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