|
Urbi SDK Remote for C++
2.7.3
|
00001 /* 00002 * Copyright (C) 2006-2011, Gostai S.A.S. 00003 * 00004 * This software is provided "as is" without warranty of any kind, 00005 * either expressed or implied, including but not limited to the 00006 * implied warranties of fitness for a particular purpose. 00007 * 00008 * See the LICENSE file for more information. 00009 */ 00010 00011 #include <libport/cstdlib> 00012 #include <libport/debug.hh> 00013 #include <libport/cstdio> 00014 #include <libport/format.hh> 00015 00016 #include <urbi/uconversion.hh> 00017 00018 GD_CATEGORY(Urbi.Convert); 00019 00020 #ifndef NO_IMAGE_CONVERSION 00021 # include <csetjmp> 00022 00023 // It would be nice to use jpeg/jpeglib.h, but this file includes 00024 // jconfig.h, unqualified, which we might pick-up on the host. So 00025 // don't take gratuitous chances. 00026 # include <jpeglib.h> 00027 00028 namespace urbi 00029 { 00030 00031 namespace 00032 { 00033 void* 00034 read_jpeg(const char* jpgbuffer, size_t jpgbuffer_size, 00035 bool RGB, size_t& output_size, size_t& w, size_t& h); 00036 00037 int 00038 write_jpeg(const byte* src, size_t w, size_t h, bool ycrcb, 00039 byte* dst, size_t& sz, int quality); 00040 00041 inline byte clamp(int v) 00042 { 00043 return (v < 0 ? 0 00044 : 255 < v ? 255 00045 : v); 00046 } 00047 00048 inline byte clamp(float v) 00049 { 00050 return (v < 0 ? 0 00051 : 255 < v ? 255 00052 : (byte) v); 00053 } 00054 } // namespace 00055 00056 int 00057 convertRGBtoYCbCr(const byte* in, size_t bufferSize, 00058 byte* out) 00059 { 00060 for (size_t i = 0; i < bufferSize - 2; i += 3) 00061 { 00062 float r = in[i]; 00063 float g = in[i + 1]; 00064 float b = in[i + 2]; 00065 /* 00066 Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16 00067 Cr = V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128 00068 Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128 00069 */ 00070 out[i] = clamp( 0.257f * r + 0.504f * g + 0.098f * b + 16.0f); 00071 out[i + 1] = clamp(-0.148f * r - 0.291f * g + 0.439f * b + 128.0f); 00072 out[i + 2] = clamp( 0.439f * r - 0.368f * g - 0.071f * b + 128.0f); 00073 } 00074 return 1; 00075 } 00076 00077 int 00078 convertYCrCbtoYCbCr(const byte* in, size_t bufferSize, 00079 byte* out) 00080 { 00081 for (size_t i = 0; i < bufferSize - 2; i += 3) 00082 { 00083 byte tmp; // If source == destination 00084 out[i] = in[i]; 00085 tmp = in[i + 1]; 00086 out[i + 1] = in[i + 2]; 00087 out[i + 2] = tmp; 00088 } 00089 return 1; 00090 } 00091 00092 00093 int 00094 convertYCbCrtoRGB(const byte* in, size_t bufferSize, 00095 byte* out) 00096 { 00097 // http://en.wikipedia.org/wiki/YUV#Converting_between_Y.27UV_and_RGB 00098 for (size_t i = 0; i < bufferSize - 2; i += 3) 00099 { 00100 int c = in[i]-16; 00101 int c298 = c * 298; 00102 int d = in[i+1] - 128; 00103 int e = in[i+2] - 128; 00104 out[i] = clamp((c298 + 409*e + 128) >> 8); 00105 out[i+1] = clamp((c298 + 100*d - 20*e + 128) >> 8); 00106 out[i+2] = clamp((c298 + 516*d + 128) >> 8); 00107 /* Float version, 5 times slower on p4. 00108 float y = in[i]; 00109 float cb = in[i + 1]; 00110 float cr = in[i + 2]; 00111 out[i] = clamp(1.164 * (y - 16) + 1.596 * (cr - 128)); 00112 out[i + 1] = clamp(1.164 * (y - 16) - 0.813 * (cr - 128) - 00113 0.392 * (cb - 128)); 00114 out[i + 2] = clamp(1.164 * (y - 16) + 2.017 * (cb - 128)); 00115 */ 00116 } 00117 return 1; 00118 } 00119 00120 00139 static 00140 int 00141 convert_jpeg_to(const byte* source, size_t sourcelen, 00142 UImageFormat dest_format, 00143 byte** dest, size_t& size, size_t& w, size_t& h) 00144 { 00145 passert(dest_format, 00146 dest_format == IMAGE_RGB || dest_format == IMAGE_YCbCr); 00147 if (!dest) 00148 return 0; 00149 00150 size_t sz; 00151 void *destination = read_jpeg((const char*) source, sourcelen, 00152 dest_format == IMAGE_RGB, sz, w, h); 00153 if (!destination) 00154 { 00155 size = 0; 00156 return 0; 00157 } 00158 if (!*dest) 00159 { 00160 *dest = (byte*) destination; 00161 size = sz; 00162 return 1; 00163 } 00164 size_t cplen = std::min(sz, size); 00165 memcpy(*dest, destination, cplen); 00166 free(destination); 00167 size = sz; 00168 return 1; 00169 } 00170 00171 int 00172 convertJPEGtoYCrCb(const byte* source, size_t sourcelen, 00173 byte** dest, size_t& size, size_t& w, size_t& h) 00174 { 00175 return convert_jpeg_to(source, sourcelen, 00176 IMAGE_YCbCr, dest, size, w, h); 00177 } 00178 00179 int 00180 convertJPEGtoRGB(const byte* source, size_t sourcelen, 00181 byte** dest, size_t& size, size_t& w, size_t& h) 00182 { 00183 return convert_jpeg_to(source, sourcelen, 00184 IMAGE_RGB, dest, size, w, h); 00185 } 00186 00187 00188 int 00189 convertRGBtoJPEG(const byte* source, 00190 size_t w, size_t h, byte* dest, 00191 size_t& size, int quality) 00192 { 00193 return write_jpeg(source, w, h, false, dest, size, quality); 00194 } 00195 00196 00197 int 00198 convertYCrCbtoJPEG(const byte* source, 00199 size_t w, size_t h, byte* dest, 00200 size_t& size, int quality) 00201 { 00202 return write_jpeg(source, w, h, true, dest, size, quality); 00203 } 00204 00205 int 00206 convertRGBtoGrey8_601(const byte* in, size_t bufferSize, 00207 byte* out) 00208 { 00209 for (size_t j = 0, i = 0; i < bufferSize - 2; i += 3, j++) 00210 { 00211 float r = in[i]; 00212 float g = in[i + 1]; 00213 float b = in[i + 2]; 00214 out[j] = clamp( 0.299f * r + 0.587f * g + 0.114f * b); 00215 } 00216 return 1; 00217 } 00218 00219 struct mem_source_mgr 00220 { 00221 struct jpeg_source_mgr pub; 00222 JOCTET eoi[2]; 00223 }; 00224 00225 00226 namespace 00227 { 00228 void init_source(j_decompress_ptr) 00229 { 00230 } 00231 00232 boolean fill_input_buffer(j_decompress_ptr cinfo) 00233 { 00234 mem_source_mgr *src = (mem_source_mgr *) cinfo->src; 00235 if (src->pub.bytes_in_buffer != 0) 00236 return TRUE; 00237 src->eoi[0] = 0xFF; 00238 src->eoi[1] = JPEG_EOI; 00239 src->pub.bytes_in_buffer = 2; 00240 src->pub.next_input_byte = src->eoi; 00241 return TRUE; 00242 } 00243 00244 void term_source(j_decompress_ptr) 00245 { 00246 } 00247 00248 void skip_input_data(j_decompress_ptr cinfo, long num_bytes) 00249 { 00250 mem_source_mgr* src = (mem_source_mgr*) cinfo->src; 00251 if (num_bytes <= 0) 00252 return; 00253 if (static_cast<unsigned long> (num_bytes) > src->pub.bytes_in_buffer) 00254 num_bytes = src->pub.bytes_in_buffer; 00255 src->pub.bytes_in_buffer -= num_bytes; 00256 src->pub.next_input_byte += num_bytes; 00257 } 00258 00259 } // namespace 00260 00261 struct urbi_jpeg_error_mgr 00262 { 00263 struct jpeg_error_mgr pub; /* "public" fields */ 00264 jmp_buf setjmp_buffer; /* for return to caller */ 00265 }; 00266 00267 METHODDEF(void) 00268 urbi_jpeg_error_exit (j_common_ptr cinfo) 00269 { 00270 /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ 00271 urbi_jpeg_error_mgr * myerr = ( urbi_jpeg_error_mgr *) cinfo->err; 00272 00273 /* Always display the message. */ 00274 /* We could postpone this until after returning, if we chose. */ 00275 (*cinfo->err->output_message) (cinfo); 00276 00277 /* Return control to the setjmp point */ 00278 longjmp(myerr->setjmp_buffer, 1); 00279 } 00280 00281 00282 struct mem_destination_mgr 00283 { 00284 struct jpeg_destination_mgr pub; 00285 }; 00286 00287 static void init_destination(j_compress_ptr) 00288 { 00289 } 00290 00291 static boolean empty_output_buffer(j_compress_ptr) 00292 { 00293 return FALSE; 00294 } 00295 00296 static void term_destination(j_compress_ptr) 00297 { 00298 } 00299 00300 namespace 00301 { 00302 int 00303 write_jpeg(const byte* src, size_t w, size_t h, bool ycrcb, 00304 byte* dst, size_t& sz, int quality) 00305 { 00306 struct jpeg_compress_struct cinfo; 00307 struct jpeg_error_mgr jerr; 00308 00309 int row_stride; /* physical row width in image buffer */ 00310 00311 cinfo.err = jpeg_std_error(&jerr); 00312 jpeg_create_compress(&cinfo); 00313 mem_destination_mgr *dest = (struct mem_destination_mgr *) 00314 (*cinfo.mem->alloc_small) ((j_common_ptr) & cinfo, JPOOL_PERMANENT, 00315 sizeof (mem_destination_mgr)); 00316 00317 cinfo.dest = (jpeg_destination_mgr*)dest; 00318 dest->pub.init_destination=&init_destination; 00319 dest->pub.empty_output_buffer = &empty_output_buffer; 00320 dest->pub.term_destination = term_destination; 00321 dest->pub.free_in_buffer = sz; 00322 dest->pub.next_output_byte = dst; 00323 cinfo.image_width = w; 00324 cinfo.image_height = h; 00325 cinfo.input_components = 3; // # of color components per pixel. 00326 /* colorspace of input image */ 00327 cinfo.in_color_space = ycrcb ? JCS_YCbCr : JCS_RGB; 00328 00329 jpeg_set_defaults(&cinfo); 00330 00331 jpeg_set_quality(&cinfo, 00332 quality, TRUE /* limit to baseline-JPEG values */); 00333 00334 jpeg_start_compress(&cinfo, TRUE); 00335 00336 row_stride = w * 3; /* JSAMPLEs per row in image_buffer */ 00337 00338 while (cinfo.next_scanline < cinfo.image_height) 00339 { 00340 /* pointer to JSAMPLE row[s] */ 00341 const JSAMPLE* row = 00342 (const JSAMPLE*) &src[cinfo.next_scanline * row_stride]; 00343 jpeg_write_scanlines(&cinfo, const_cast<JSAMPLE**>(&row), 1); 00344 } 00345 00346 jpeg_finish_compress(&cinfo); 00347 sz -= dest->pub.free_in_buffer ; 00348 jpeg_destroy_compress(&cinfo); 00349 00350 return sz; 00351 } 00352 00355 void *read_jpeg(const char* jpgbuffer, size_t jpgbuffer_size, bool RGB, 00356 size_t& output_size, size_t& w, size_t& h) 00357 { 00358 struct jpeg_decompress_struct cinfo; 00359 struct urbi_jpeg_error_mgr jerr; 00360 cinfo.err = jpeg_std_error(&jerr.pub); 00361 jerr.pub.error_exit = urbi_jpeg_error_exit; 00362 if (setjmp(jerr.setjmp_buffer)) 00363 { 00364 /* If we get here, the JPEG code has signaled an error. We 00365 * need to clean up the JPEG object, close the input file, and 00366 * return. 00367 */ 00368 jpeg_destroy_decompress(&cinfo); 00369 GD_ERROR("JPEG error!"); 00370 return 0; 00371 } 00372 jpeg_create_decompress(&cinfo); 00373 mem_source_mgr *source = (struct mem_source_mgr *) 00374 (*cinfo.mem->alloc_small) ((j_common_ptr) & cinfo, JPOOL_PERMANENT, 00375 sizeof (mem_source_mgr)); 00376 00377 cinfo.src = (jpeg_source_mgr *) source; 00378 source->pub.skip_input_data = skip_input_data; 00379 source->pub.term_source = term_source; 00380 source->pub.init_source = init_source; 00381 source->pub.fill_input_buffer = fill_input_buffer; 00382 source->pub.resync_to_restart = jpeg_resync_to_restart; 00383 source->pub.bytes_in_buffer = jpgbuffer_size; 00384 source->pub.next_input_byte = (JOCTET *) jpgbuffer; 00385 cinfo.out_color_space = (RGB ? JCS_RGB : JCS_YCbCr); 00386 jpeg_read_header(&cinfo, TRUE); 00387 cinfo.out_color_space = (RGB ? JCS_RGB : JCS_YCbCr); 00388 jpeg_start_decompress(&cinfo); 00389 w = cinfo.output_width; 00390 h = cinfo.output_height; 00391 output_size = 00392 cinfo.output_width * cinfo.output_components * cinfo.output_height; 00393 void *buffer = malloc(output_size); 00394 00395 while (cinfo.output_scanline < cinfo.output_height) 00396 { 00397 /* jpeg_read_scanlines expects an array of pointers to scanlines. 00398 * Here the array is only one element long, but you could ask for 00399 * more than one scanline at a time if that's more convenient. 00400 */ 00401 JSAMPLE* row = 00402 (JSAMPLE *) &((char*) buffer)[cinfo.output_scanline 00403 * cinfo.output_components 00404 * cinfo.output_width]; 00405 jpeg_read_scanlines(&cinfo, &row, 1); 00406 } 00407 jpeg_finish_decompress(&cinfo); 00408 jpeg_destroy_decompress(&cinfo); 00409 00410 return buffer; 00411 } 00412 00413 00414 00415 //scale putting (scx, scy) at the center of destination image 00416 void scaleColorImage(byte* src, int sw, int sh, 00417 int scx, int scy, byte* dst, 00418 int dw, int dh, float sx, float sy) 00419 { 00420 for (int x = 0; x < dw; ++x) 00421 for (int y = 0; y < dh; ++y) 00422 { 00423 //find the corresponding point in source image 00424 float fsrcx = (float) (x-dw/2) / sx + (float) scx; 00425 float fsrcy = (float) (y-dh/2) / sy + (float) scy; 00426 int srcx = (int) fsrcx; 00427 int srcy = (int) fsrcy; 00428 if (srcx <= 0 || srcx >= sw - 1 || srcy <= 0 || srcy >= sh - 1) 00429 memset(dst + (x + y * dw) * 3, 0, 3); 00430 else //do the bilinear interpolation 00431 { 00432 float xfactor = fsrcx - (float) srcx; 00433 float yfactor = fsrcy - (float) srcy; 00434 for (int color = 0; color < 3; ++color) 00435 { 00436 float up = (float) src[(srcx + srcy * sw) * 3 + color] 00437 * (1.0 - xfactor) 00438 + (float) src[(srcx + 1 + srcy * sw) * 3 + color] * xfactor; 00439 float down = (float) src[(srcx + (srcy + 1) * sw) * 3 + color] 00440 * (1.0 - xfactor) 00441 + (float) src[(srcx + 1 + (srcy + 1) * sw) * 3 + color] 00442 * xfactor; 00443 float result = up * (1.0 - yfactor) + down * yfactor; 00444 dst[(x + y * dw) * 3 + color] = (byte) result; 00445 } 00446 } 00447 } 00448 } 00449 00450 } // anonymous namespace 00451 00452 int convert(const UImage& src, UImage& dest) 00453 { 00454 enum FormatKind 00455 { 00456 RGB, 00457 YUV, 00458 COMPRESSED, 00459 UNSET 00460 }; 00461 //step 1: uncompress source, to have raw uncompressed rgb or ycbcr 00462 bool allocated = false; // true if data must be freed 00463 00464 // uncompressed data. 00465 byte* data = 0; 00466 size_t w, h; 00467 size_t usz; 00468 // Effective format of the source in 'data'. 00469 FormatKind format = UNSET; 00470 // Format we need the source in 00471 FormatKind targetformat = UNSET; 00472 00473 switch (dest.imageFormat) 00474 { 00475 case IMAGE_RGB: 00476 case IMAGE_PPM: 00477 case IMAGE_GREY8: 00478 targetformat = RGB; 00479 break; 00480 case IMAGE_YCbCr: 00481 case IMAGE_NV12: 00482 case IMAGE_YUV411_PLANAR: 00483 case IMAGE_YUV420_PLANAR: 00484 targetformat = YUV; 00485 break; 00486 case IMAGE_JPEG: 00487 targetformat = COMPRESSED; 00488 break; 00489 default: 00490 GD_FERROR("Image conversion to format %s is not implemented", 00491 dest.format_string()); 00492 return 0; 00493 } 00494 unsigned p = 0; 00495 int c = 0; 00496 00497 // Avoid using src fields because JPEG file format embedded these 00498 // information in the data buffer. 00499 if (src.imageFormat != IMAGE_JPEG) 00500 { 00501 w = src.width; 00502 h = src.height; 00503 usz = w * h * 3; 00504 } 00505 00506 switch (src.imageFormat) 00507 { 00508 case IMAGE_YCbCr: 00509 format = YUV; 00510 data = src.data; 00511 break; 00512 case IMAGE_RGB: 00513 format = RGB; 00514 data = src.data; 00515 break; 00516 case IMAGE_PPM: 00517 format = RGB; 00518 //locate header end 00519 p = 0; 00520 c = 0; 00521 while (c < 3 && p < src.size) 00522 if (src.data[p++] == '\n') 00523 ++c; 00524 data = src.data + p; 00525 break; 00526 case IMAGE_JPEG: 00527 // this image is allocated by the function convertJPEG* function. 00528 // w, h and usz are defined by these functions calls. 00529 allocated = true; 00530 if (targetformat == RGB) 00531 { 00532 convertJPEGtoRGB((byte*) src.data, src.size, 00533 (byte**) &data, usz, 00534 w, h); 00535 format = RGB; 00536 } 00537 else 00538 { 00539 convertJPEGtoYCrCb((byte*) src.data, src.size, 00540 (byte**) &data, usz, 00541 w, h); 00542 format = YUV; 00543 } 00544 break; 00545 case IMAGE_YUV422: 00546 format = YUV; 00547 data = (byte*)malloc(src.width * src.height * 3); 00548 allocated = true; 00549 for (unsigned i=0; i< src.width*src.height; i+=2) 00550 { 00551 data[i*3] = src.data[i*2]; 00552 data[i*3 + 1] = src.data[i*2+1]; 00553 data[i*3 + 2] = src.data[i*2+3]; 00554 data[(i+1)*3] = src.data[i*2+2]; 00555 data[(i+1)*3 + 1] = src.data[i*2+1]; 00556 data[(i+1)*3 + 2] = src.data[i*2+3]; 00557 } 00558 break; 00559 case IMAGE_YUV411_PLANAR: 00560 { 00561 format = YUV; 00562 data = (byte*)malloc(src.width * src.height * 3); 00563 allocated = true; 00564 unsigned char* cy = src.data; 00565 unsigned char* u = cy + w*h; 00566 unsigned char* v = u + w*h/4; 00567 int w = src.width; 00568 int h = src.height; 00569 for (int x=0; x<w;++x) 00570 for (int y=0; y<h; ++y) 00571 { 00572 data[(x+y*w)*3+0] = cy[x+y*w]; 00573 data[(x+y*w)*3+1] = u[x/4 + y*w/4]; 00574 data[(x+y*w)*3+2] = v[x/4 + y*w/4]; 00575 } 00576 } 00577 break; 00578 case IMAGE_YUV420_PLANAR: 00579 { 00580 format = YUV; 00581 data = (byte*)malloc(src.width * src.height * 3); 00582 allocated = true; 00583 unsigned char* cy = src.data; 00584 unsigned char* u = cy + w*h; 00585 unsigned char* v = u + w*h/4; 00586 int w = src.width; 00587 int h = src.height; 00588 for (int x=0; x<w;++x) 00589 for (int y=0; y<h; ++y) 00590 { 00591 data[(x+y*w)*3+0] = cy[x+y*w]; 00592 data[(x+y*w)*3+1] = u[x/2 + (y>>1)*w/2]; 00593 data[(x+y*w)*3+2] = v[x/2 + (y>>1)*w/2]; 00594 } 00595 } 00596 break; 00597 case IMAGE_NV12: 00598 { 00599 format = YUV; 00600 data = (byte*)malloc(src.width * src.height * 3); 00601 allocated = true; 00602 unsigned char* cy = src.data; 00603 unsigned char* uv = src.data + w*h; 00604 for (unsigned int x=0; x<w;++x) 00605 for (unsigned int y=0; y<h; ++y) 00606 { 00607 data[(x+y*w)*3+0] = cy[x+y*w]; 00608 data[(x+y*w)*3+1] = uv[((x>>1) + (((y>>1)*w)>>1))*2]; 00609 data[(x+y*w)*3+2] = uv[((x>>1) + (((y>>1)*w)>>1))*2 + 1]; 00610 } 00611 } 00612 break; 00613 case IMAGE_GREY8: 00614 format = YUV; 00615 data = (byte*)malloc(src.width * src.height * 3); 00616 allocated = true; 00617 memset(data, 127, src.width * src.height * 3); 00618 for (unsigned i=0; i< src.width*src.height; ++i) 00619 data[i*3] = src.data[i]; 00620 break; 00621 case IMAGE_GREY4: 00622 format = YUV; 00623 data = (byte*)malloc(src.width * src.height * 3); 00624 allocated = true; 00625 memset(data, 127, src.width * src.height * 3); 00626 for (unsigned i=0; i< src.width*src.height; i+=2) 00627 { 00628 data[i*3] = src.data[i/2] & 0xF0; 00629 data[(i+1)*3] = (src.data[i/2] & 0x0F) << 4; 00630 } 00631 break; 00632 case IMAGE_UNKNOWN: 00633 break; 00634 } 00635 00636 if (dest.width == 0) 00637 dest.width = w; 00638 if (dest.height == 0) 00639 dest.height = h; 00640 00641 //now resize if target size is different 00642 if (w != dest.width || h != dest.height) 00643 { 00644 void* scaled = malloc(dest.width * dest.height * 3); 00645 scaleColorImage(data, w, h, w/2, h/2, 00646 (byte*) scaled, dest.width, dest.height, 00647 (float) dest.width / (float) w, 00648 (float) dest.height / (float) h); 00649 if (allocated) 00650 free(data); 00651 data = (byte*)scaled; 00652 allocated = true; 00653 } 00654 // Then factor YUV<->RGB conversion if necessary 00655 if ((format == RGB && targetformat == YUV) 00656 || (format == YUV && targetformat == RGB)) 00657 { 00658 byte* src = data; 00659 if (!allocated) 00660 { 00661 allocated = true; 00662 data = (byte*)malloc(dest.width * dest.height * 3); 00663 } 00664 if (format == RGB) 00665 convertRGBtoYCbCr(src, dest.width * dest.height * 3, data); 00666 else 00667 convertYCbCrtoRGB(src, dest.width * dest.height * 3, data); 00668 format = targetformat; 00669 } 00670 //then convert to destination format 00671 dest.size = dest.width * dest.height * 3 + 20; 00672 if (dest.imageFormat == IMAGE_GREY8) 00673 dest.size = dest.width * dest.height + 20; 00674 dest.data = static_cast<byte*> (realloc(dest.data, dest.size)); 00675 size_t dsz = dest.size; 00676 switch (dest.imageFormat) 00677 { 00678 case IMAGE_RGB: 00679 memcpy(dest.data, data, dest.width * dest.height * 3); 00680 break; 00681 case IMAGE_GREY8: 00682 assert(format == 0); 00683 convertRGBtoGrey8_601((byte*) data, 00684 dest.width * dest.height * 3, (byte*) dest.data); 00685 break; 00686 case IMAGE_YCbCr: 00687 memcpy(dest.data, data, dest.width * dest.height * 3); 00688 break; 00689 case IMAGE_PPM: 00690 strcpy((char*) dest.data, 00691 libport::format("P6\n%s %s\n255\n", 00692 dest.width, dest.height).c_str()); 00693 memcpy(dest.data + strlen((char*) dest.data), 00694 data, dest.width * dest.height * 3); 00695 break; 00696 case IMAGE_JPEG: 00697 if (format == YUV) 00698 convertYCrCbtoJPEG((byte*) data, 00699 dest.width ,dest.height, 00700 (byte*) dest.data, dsz, 80); 00701 else 00702 convertRGBtoJPEG((byte*) data, 00703 dest.width , dest.height, 00704 (byte*) dest.data, dsz, 80); 00705 dest.size = dsz; 00706 break; 00707 case IMAGE_YUV411_PLANAR: 00708 { 00709 unsigned int plane = dest.width * dest.height; 00710 for (unsigned int i=0; i<plane;++i) 00711 dest.data[i] = data[i*3]; 00712 for (unsigned int y=0; y<dest.height; y++) 00713 for (unsigned int x=0; x<dest.width; x+=4) 00714 { 00715 dest.data[plane + x/4 + y*dest.width/4] 00716 = data[(x+y*dest.width)*3+1]; 00717 dest.data[plane+plane/4 + x/4 + y*dest.width/4] 00718 = data[(x+y*dest.width)*3+2]; 00719 } 00720 break; 00721 } 00722 case IMAGE_YUV420_PLANAR: 00723 { 00724 unsigned int plane = dest.width * dest.height; 00725 for (unsigned int i=0; i<plane;++i) 00726 dest.data[i] = data[i*3]; 00727 for (unsigned int y=0; y<dest.height/2; y++) 00728 for (unsigned int x=0; x<dest.width/2; x++) 00729 { 00730 dest.data[plane + x +y*dest.width/2] 00731 = data[(x*2+y*2*dest.width)*3+1]; 00732 dest.data[plane + plane/4 + x +y*dest.width/2] 00733 = data[(x*2+y*2*dest.width)*3+2]; 00734 } 00735 break; 00736 } 00737 case IMAGE_NV12: 00738 { 00739 unsigned int planeS = dest.width * dest.height; 00740 // y plane 00741 for (unsigned int p=0; p<planeS; ++p) 00742 dest.data[p] = data[p*3]; 00743 // crcb interleaved plane 00744 for (unsigned int y=0; y<dest.height; y+=2) 00745 for (unsigned int x=0; x<dest.width; x+=2) 00746 { 00747 dest.data[planeS + x + y*dest.width/2] 00748 = data[(x+y*dest.width)*3+1]; 00749 dest.data[planeS + x + y*dest.width/2 +1 ] 00750 = data[(x+y*dest.width)*3+2]; 00751 } 00752 dest.size = planeS * 3 / 2; 00753 } 00754 break; 00755 default: 00756 GD_FERROR("Image conversion to format %s is not implemented", 00757 dest.format_string()); 00758 } 00759 if (allocated) 00760 free(data); 00761 return 1; 00762 } 00763 00764 } // namespace urbi 00765 00766 #endif // !NO_IMAGE_CONVERSION 00767 00768 namespace urbi 00769 { 00770 static 00771 void 00772 dup(unsigned short* dst, const unsigned short* src, size_t count) 00773 { 00774 unsigned int* idst = (unsigned int*)dst; 00775 const unsigned short* end = src + count; 00776 while (src != end) 00777 { 00778 *(idst++) = (unsigned int)(*src) << 16 | (unsigned int)(*src); 00779 src++; 00780 } 00781 } 00782 00783 00784 static 00785 void 00786 dup(byte* dst, const byte* src, size_t count) 00787 { 00788 unsigned short* idst = (unsigned short*)dst; 00789 const byte* end = src + count; 00790 while (src != end) 00791 { 00792 *(idst++) = (unsigned short)(*src) << 8 | (unsigned short)(*src); 00793 src++; 00794 } 00795 } 00796 00797 template<typename D> void 00798 pud(D* dst, const D* src, int count) 00799 { 00800 for (int i=0; i<count/2; i++) 00801 dst[i] = src[i*2]; 00802 } 00803 00804 template<class S, class D> 00805 void copy(const S* src, D* dst, 00806 int sc, int dc, int sr, int dr, 00807 size_t count, bool sf, bool df) 00808 { 00809 long shift = 8 * (sizeof (S) - sizeof (D)); 00810 if (!shift && sc == dc && sr == dr && sf==df) 00811 { 00812 memcpy(dst, src, sizeof(S)*sc*count); 00813 return; 00814 } 00815 for (size_t i = 0; i < count; ++i) 00816 { 00817 float soffset = (float)i * ((float)sr / (float)dr); 00818 int so = (int)soffset; 00819 float factor = soffset - (float)so; 00820 S s1, s2; 00821 s1 = src[so * sc]; 00822 if (i != count - 1) 00823 s2 = src[(so + 1) * sc]; 00824 else 00825 s2 = s1; //nothing to interpolate with 00826 if (!sf) 00827 { 00828 s1 = s1 ^ (1<<(sizeof (S)*8-1)); 00829 s2 = s2 ^ (1<<(sizeof (S)*8-1)); 00830 } 00831 int v1 = (int) ((float)(s1)*(1.0-factor) + (float)(s2)*factor); 00832 int v2; 00833 if (sc==1) 00834 v2 = v1; 00835 else 00836 { 00837 s1 = src[so*sc+1]; 00838 if (i != count - 1) 00839 s2 = src[(so+1)*sc+1]; 00840 else 00841 s2 = s1; //nothing to interpolate with 00842 if (!sf) 00843 { 00844 s1 = s1 ^ (1<<(sizeof (S)*8-1)); 00845 s2 = s2 ^ (1<<(sizeof (S)*8-1)); 00846 } 00847 v2 = (int) ((float)(s1)*(1.0-factor) + (float)(s2)*factor); 00848 } 00849 D d1, d2; 00850 if (shift>=0) 00851 { 00852 d1 = (D)(v1 >>shift); 00853 d2 = (D)(v2 >>shift); 00854 } 00855 else 00856 { 00857 d1 = (D)(v1) * (1 << -shift); 00858 d2 = (D)(v2) * (1 << -shift); 00859 } 00860 if (!df) 00861 { 00862 d1 = d1 ^ (1<<(sizeof (D)*8-1)); 00863 d2 = d2 ^ (1<<(sizeof (D)*8-1)); 00864 } 00865 if (dc==2) 00866 { 00867 dst[i*2] = d1; 00868 dst[i*2+1] = d2; 00869 } 00870 else 00871 dst[i] = (D) (((int)d1+(int)d2) /2); 00872 } 00873 } 00874 00875 int 00876 convert (const USound &source, USound &dest) 00877 { 00878 if ((source.soundFormat != SOUND_RAW 00879 && source.soundFormat != SOUND_WAV) 00880 || (dest.soundFormat != SOUND_RAW 00881 && dest.soundFormat != SOUND_WAV)) 00882 return 1; //conversion not handled yet 00883 /* phase one: calculate required buffer size, set destination unspecified 00884 * fields */ 00885 size_t schannels, srate, ssampleSize; 00886 USoundSampleFormat ssampleFormat; 00887 if (source.soundFormat == SOUND_WAV) 00888 { 00889 wavheader * wh = (wavheader *)source.data; 00890 schannels = wh->channels; 00891 srate = wh->freqechant; 00892 ssampleSize = wh->bitperchannel; 00893 ssampleFormat = (ssampleSize>8)?SAMPLE_SIGNED:SAMPLE_UNSIGNED; 00894 } 00895 else 00896 { 00897 schannels = source.channels; 00898 srate = source.rate; 00899 ssampleSize = source.sampleSize; 00900 ssampleFormat = source.sampleFormat; 00901 } 00902 if (!dest.channels) 00903 dest.channels = schannels; 00904 if (!dest.rate) 00905 dest.rate = srate; 00906 if (!dest.sampleSize) 00907 dest.sampleSize = ssampleSize; 00908 if (!(int)dest.sampleFormat) 00909 dest.sampleFormat = ssampleFormat; 00910 if (dest.soundFormat == SOUND_WAV) 00911 dest.sampleFormat = dest.sampleSize > 8 ? SAMPLE_SIGNED 00912 : SAMPLE_UNSIGNED; 00913 // That's a big one! 00914 unsigned destSize = 00915 ((long long)(source.size 00916 - ((source.soundFormat == SOUND_WAV)?44:0)) 00917 * (long long)dest.channels 00918 * (long long)dest.rate 00919 * (long long)(dest.sampleSize/8)) 00920 / ((long long)schannels 00921 *(long long)srate 00922 *(long long)(ssampleSize/8)); 00923 if (dest.soundFormat == SOUND_WAV) 00924 destSize += sizeof (wavheader); 00925 if (dest.size<destSize) 00926 dest.data = static_cast<char*> (realloc (dest.data, destSize)); 00927 dest.size = destSize; 00928 //write destination header if appropriate 00929 if (dest.soundFormat == SOUND_WAV) 00930 { 00931 wavheader* wh = (wavheader*) dest.data; 00932 memcpy(wh->riff, "RIFF", 4); 00933 wh->length = dest.size - 8; 00934 memcpy(wh->wave, "WAVE", 4); 00935 memcpy(wh->fmt, "fmt ", 4); 00936 wh->lnginfo = 16; 00937 wh->one = 1; 00938 wh->channels = dest.channels; 00939 wh->freqechant = dest.rate; 00940 wh->bytespersec = dest.rate * dest.channels * (dest.sampleSize/8); 00941 wh->bytesperechant = (dest.sampleSize/8)*dest.channels; 00942 wh->bitperchannel = dest.sampleSize; 00943 memcpy(wh->data, "data", 4); 00944 wh->datalength = destSize - sizeof (wavheader); 00945 } 00946 00947 //do the conversion and write to dest.data 00948 char* sbuffer = source.data; 00949 if (source.soundFormat == SOUND_WAV) 00950 sbuffer += sizeof (wavheader); 00951 char* dbuffer = dest.data; 00952 if (dest.soundFormat == SOUND_WAV) 00953 dbuffer += sizeof (wavheader); 00954 int elementCount = dest.size - (dest.soundFormat == SOUND_WAV ? 00955 sizeof (wavheader) : 0); 00956 elementCount /= (dest.channels * (dest.sampleSize / 8)); 00957 switch (ssampleSize * 1000 + dest.sampleSize) 00958 { 00959 case 8008: 00960 if (srate == dest.rate && schannels == 1 && dest.channels == 2) 00961 dup((byte*)dbuffer, (byte*)sbuffer, elementCount); 00962 else if (srate == dest.rate && schannels == 2 && dest.channels == 1) 00963 pud(dbuffer, sbuffer, elementCount); 00964 else 00965 copy(dbuffer, sbuffer, schannels, dest.channels, srate, dest.rate, 00966 elementCount, ssampleFormat==SAMPLE_SIGNED, dest.sampleFormat == 00967 SAMPLE_SIGNED); 00968 break; 00969 case 16008: 00970 copy((short*)sbuffer, dbuffer, schannels, dest.channels, srate, 00971 dest.rate, elementCount, ssampleFormat==SAMPLE_SIGNED, 00972 dest.sampleFormat == SAMPLE_SIGNED); 00973 break; 00974 case 16016: // Data is short, but convertions needs an unsigned short. 00975 if (srate == dest.rate && schannels == 1 && dest.channels == 2) 00976 dup((unsigned short*)dbuffer, 00977 (unsigned short*)sbuffer, 00978 elementCount); 00979 else if (srate == dest.rate && schannels == 2 && dest.channels == 1) 00980 pud((unsigned short*)dbuffer, 00981 (unsigned short*)sbuffer, 00982 elementCount); 00983 else 00984 copy((short*)sbuffer, (short*)dbuffer, schannels, dest.channels, 00985 srate, dest.rate, elementCount, ssampleFormat==SAMPLE_SIGNED, 00986 dest.sampleFormat == SAMPLE_SIGNED); 00987 break; 00988 case 8016: 00989 copy((char*)sbuffer, (short*)dbuffer, schannels, dest.channels, 00990 srate, dest.rate, elementCount, ssampleFormat==SAMPLE_SIGNED, 00991 dest.sampleFormat == SAMPLE_SIGNED); 00992 break; 00993 } 00994 return 0; 00995 } 00996 00997 } // namespace urbi