00001 /*!@file Video/VideoFormatCoercion.C */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Rob Peters <rjpeters at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Video/VideoFormatCoercion.C $ 00035 // $Id: VideoFormatCoercion.C 9271 2008-02-15 17:59:27Z rjpeters $ 00036 // 00037 00038 #ifndef VIDEO_VIDEOFORMATCOERCION_C_DEFINED 00039 #define VIDEO_VIDEOFORMATCOERCION_C_DEFINED 00040 00041 #include "Video/VideoFormatCoercion.H" 00042 00043 #include "Image/Image.H" 00044 #include "Image/Pixels.H" 00045 #include "Util/log.H" 00046 #include "Util/sformat.H" 00047 #include "Video/VideoFrame.H" 00048 #include "Video/RgbConversion.H" 00049 00050 // ###################################################################### 00051 static void checkBufferLength(const size_t actual, const size_t expected) 00052 { 00053 if (actual < expected) 00054 LFATAL("input buffer is too short (got %"ZU", expected %"ZU")", 00055 actual, expected); 00056 00057 if (actual > expected) 00058 LINFO("input buffer is longer than expected (got %"ZU", expected %"ZU")\n" 00059 "(this is not a fatal error, but make sure the width and height are correct)", 00060 actual, expected); 00061 } 00062 00063 // ###################################################################### 00064 // ###################################################################### 00065 // conversions to RGB24 00066 // ###################################################################### 00067 // ###################################################################### 00068 00069 // ###################################################################### 00070 VideoFrame RGB_to_RGB24(const byte* sptr, const size_t length, 00071 const Dims& dims, const bool byteswap) 00072 { 00073 return VideoFrame(fromRGB(sptr, length, dims, byteswap)); 00074 } 00075 00076 // ###################################################################### 00077 VideoFrame ARGB_to_RGB24(const byte* sptr, const size_t length, 00078 const Dims& dims, const bool byteswap) 00079 { 00080 return VideoFrame(fromARGB(sptr, length, dims, byteswap)); 00081 } 00082 00083 // ###################################################################### 00084 VideoFrame RGB555_to_RGB24(const byte* sptr, const size_t length, 00085 const Dims& dims, const bool byteswap) 00086 { 00087 return VideoFrame(fromRGB555(sptr, length, dims, byteswap)); 00088 } 00089 00090 // ###################################################################### 00091 VideoFrame RGB565_to_RGB24(const byte* sptr, const size_t length, 00092 const Dims& dims, const bool byteswap) 00093 { 00094 return VideoFrame(fromRGB565(sptr, length, dims, byteswap)); 00095 } 00096 00097 // ###################################################################### 00098 VideoFrame YUV24_to_RGB24(const byte* sptr, const size_t length, 00099 const Dims& dims, const bool byteswap) 00100 { 00101 return VideoFrame(fromVideoYUV24(sptr, length, dims, byteswap)); 00102 } 00103 00104 // ###################################################################### 00105 VideoFrame YUV444_to_RGB24(const byte* sptr, const size_t length, 00106 const Dims& dims, const bool byteswap) 00107 { 00108 return VideoFrame(fromVideoYUV444(sptr, length, dims, byteswap)); 00109 } 00110 00111 // ###################################################################### 00112 VideoFrame YUYV_to_RGB24(const byte* sptr, const size_t length, 00113 const Dims& dims, const bool byteswap) 00114 { 00115 return VideoFrame(fromVideoYUV422(sptr, length, dims, !byteswap)); 00116 } 00117 00118 // ###################################################################### 00119 VideoFrame YUV422_to_RGB24(const byte* sptr, const size_t length, 00120 const Dims& dims, const bool byteswap) 00121 { 00122 return VideoFrame(fromVideoYUV422(sptr, length, dims, byteswap)); 00123 } 00124 00125 // ###################################################################### 00126 VideoFrame YUV411_to_RGB24(const byte* sptr, const size_t length, 00127 const Dims& dims, const bool byteswap) 00128 { 00129 return VideoFrame(fromVideoYUV411(sptr, length, dims, byteswap)); 00130 } 00131 00132 // ###################################################################### 00133 VideoFrame YUV444P_to_RGB24(const byte* sptr, const size_t length, 00134 const Dims& dims, const bool byteswap) 00135 { 00136 return VideoFrame(fromVideoYUV444P(sptr, length, dims)); 00137 } 00138 00139 // ###################################################################### 00140 VideoFrame YUV422P_to_RGB24(const byte* sptr, const size_t length, 00141 const Dims& dims, const bool byteswap) 00142 { 00143 return VideoFrame(fromVideoYUV422P(sptr, length, dims)); 00144 } 00145 00146 // ###################################################################### 00147 VideoFrame YUV411P_to_RGB24(const byte* sptr, const size_t length, 00148 const Dims& dims, const bool byteswap) 00149 { 00150 return VideoFrame(fromVideoYUV411P(sptr, length, dims)); 00151 } 00152 00153 // ###################################################################### 00154 VideoFrame YUV420P_to_RGB24(const byte* sptr, const size_t length, 00155 const Dims& dims, const bool byteswap) 00156 { 00157 return VideoFrame(fromVideoYUV420P(sptr, length, dims)); 00158 } 00159 00160 // ###################################################################### 00161 VideoFrame YUV410P_to_RGB24(const byte* sptr, const size_t length, 00162 const Dims& dims, const bool byteswap) 00163 { 00164 return VideoFrame(fromVideoYUV410P(sptr, length, dims)); 00165 } 00166 00167 // ###################################################################### 00168 VideoFrame GREY_to_RGB24(const byte* sptr, const size_t length, 00169 const Dims& dims, const bool byteswap) 00170 { 00171 return VideoFrame(fromMono(sptr, length, dims)); 00172 } 00173 00174 00175 00176 00177 // ###################################################################### 00178 // ###################################################################### 00179 // conversions from RGB24 00180 // ###################################################################### 00181 // ###################################################################### 00182 00183 // ###################################################################### 00184 VideoFrame RGB24_to_GREY(const byte* sptr, const size_t length, 00185 const Dims& dims, const bool byteswap) 00186 { 00187 checkBufferLength(length, dims.sz() * 3); 00188 00189 Image<byte> dst(dims, NO_INIT); 00190 00191 Image<byte>::iterator dptr = dst.beginw(); 00192 Image<byte>::iterator stop = dst.endw(); 00193 00194 while (dptr != stop) 00195 { 00196 // byteswap does not matter here since (R+G+B)/3 == (B+G+R)/3 00197 *dptr++ = byte(0.5 + (sptr[0] + sptr[1] + sptr[2]) / 3.0); 00198 sptr += 3; 00199 } 00200 00201 return VideoFrame(dst); 00202 } 00203 00204 // ###################################################################### 00205 VideoFrame RGB24_to_RGB555(const byte* sptr, const size_t length, 00206 const Dims& dims, const bool byteswap) 00207 { 00208 checkBufferLength(length, dims.sz() * 3); 00209 00210 ArrayHandle<byte> dst(new ArrayData<byte>(Dims(dims.sz() * 2, 1), NO_INIT)); 00211 byte* dptr = dst.uniq().dataw(); 00212 byte* stop = dst.uniq().endw(); 00213 00214 if (byteswap) 00215 while (dptr != stop) 00216 { 00217 // data stored as: 1 ignored bit, 5-bit R, 5-bit G, 5-bit B 00218 const int r = sptr[2]; 00219 const int g = sptr[1]; 00220 const int b = sptr[0]; 00221 00222 const uint16 val = ((r >> 3) << 10) + ((g >> 3) << 5) + (b >> 3); 00223 // big-endian: 00224 *dptr++ = (val & 0xff00) >> 8; 00225 *dptr++ = (val & 0x00ff); 00226 sptr += 3; 00227 } 00228 else 00229 while (dptr != stop) 00230 { 00231 // data stored as: 1 ignored bit, 5-bit R, 5-bit G, 5-bit B 00232 const int r = sptr[0]; 00233 const int g = sptr[1]; 00234 const int b = sptr[2]; 00235 00236 const uint16 val = ((r >> 3) << 10) + ((g >> 3) << 5) + (b >> 3); 00237 // big-endian: 00238 *dptr++ = (val & 0xff00) >> 8; 00239 *dptr++ = (val & 0x00ff); 00240 sptr += 3; 00241 } 00242 00243 return VideoFrame(dst, dims, VIDFMT_RGB555, false); 00244 } 00245 00246 // ###################################################################### 00247 VideoFrame RGB24_to_RGB565(const byte* sptr, const size_t length, 00248 const Dims& dims, const bool byteswap) 00249 { 00250 checkBufferLength(length, dims.sz() * 3); 00251 00252 ArrayHandle<byte> dst(new ArrayData<byte>(Dims(dims.sz() * 2, 1), NO_INIT)); 00253 byte* dptr = dst.uniq().dataw(); 00254 byte* stop = dst.uniq().endw(); 00255 00256 if (byteswap) 00257 while (dptr != stop) 00258 { 00259 // data stored as: 5-bit R, 6-bit G, 5-bit B 00260 const int r = sptr[2]; 00261 const int g = sptr[1]; 00262 const int b = sptr[0]; 00263 00264 const uint16 val = ((r >> 3) << 11) + ((g >> 2) << 5) + (b >> 3); 00265 // big-endian: 00266 *dptr++ = (val & 0xff00) >> 8; 00267 *dptr++ = (val & 0x00ff); 00268 sptr += 3; 00269 } 00270 else 00271 while (dptr != stop) 00272 { 00273 // data stored as: 5-bit R, 6-bit G, 5-bit B 00274 const int r = sptr[0]; 00275 const int g = sptr[1]; 00276 const int b = sptr[2]; 00277 00278 const uint16 val = ((r >> 3) << 11) + ((g >> 2) << 5) + (b >> 3); 00279 // big-endian: 00280 *dptr++ = (val & 0xff00) >> 8; 00281 *dptr++ = (val & 0x00ff); 00282 sptr += 3; 00283 } 00284 00285 return VideoFrame(dst, dims, VIDFMT_RGB565, false); 00286 } 00287 00288 // ###################################################################### 00289 VideoFrame RGB24_to_RGB32(const byte* sptr, const size_t length, 00290 const Dims& dims, const bool byteswap) 00291 { 00292 checkBufferLength(length, dims.sz() * 3); 00293 00294 ArrayHandle<byte> dst(new ArrayData<byte>(Dims(dims.sz() * 4, 1), NO_INIT)); 00295 byte* dptr = dst.uniq().dataw(); 00296 byte* stop = dst.uniq().endw(); 00297 00298 if (byteswap) 00299 while (dptr != stop) 00300 { 00301 *dptr++ = 0; 00302 *dptr++ = sptr[2]; 00303 *dptr++ = sptr[1]; 00304 *dptr++ = sptr[0]; 00305 sptr += 3; 00306 } 00307 else 00308 while (dptr != stop) 00309 { 00310 *dptr++ = 0; 00311 *dptr++ = sptr[0]; 00312 *dptr++ = sptr[1]; 00313 *dptr++ = sptr[2]; 00314 sptr += 3; 00315 } 00316 00317 return VideoFrame(dst, dims, VIDFMT_RGB32, false); 00318 } 00319 00320 // ###################################################################### 00321 // ###################################################################### 00322 // conversions to YUV24 00323 // ###################################################################### 00324 // ###################################################################### 00325 00326 // ###################################################################### 00327 VideoFrame GREY_to_YUV24(const byte* sptr, const size_t length, 00328 const Dims& dims, const bool byteswap) 00329 { 00330 const int sz = dims.sz(); 00331 00332 checkBufferLength(length, sz); 00333 00334 Image<PixVideoYUV<byte> > dst(dims, NO_INIT); 00335 Image<PixVideoYUV<byte> >::iterator dptr = dst.beginw(); 00336 00337 for (int i = 0; i < sz; ++i) 00338 *dptr++ = PixVideoYUV<byte>(PixRGB<double>(sptr[i], sptr[i], sptr[i])); 00339 00340 ASSERT(dptr == dst.endw()); 00341 00342 return VideoFrame(dst); 00343 } 00344 00345 // ###################################################################### 00346 VideoFrame RGB24_to_YUV24(const byte* sptr, const size_t length, 00347 const Dims& dims, const bool byteswap) 00348 { 00349 const int sz = dims.sz() * 3; 00350 00351 checkBufferLength(length, sz); 00352 00353 Image<PixVideoYUV<byte> > dst(dims, NO_INIT); 00354 Image<PixVideoYUV<byte> >::iterator dptr = dst.beginw(); 00355 00356 if (byteswap) 00357 for (int i = 0; i < sz; i += 3) 00358 *dptr++ = PixVideoYUV<byte>(PixRGB<double>(sptr[i+2], sptr[i+1], sptr[i])); 00359 else 00360 for (int i = 0; i < sz; i += 3) 00361 *dptr++ = PixVideoYUV<byte>(PixRGB<double>(sptr[i], sptr[i+1], sptr[i+2])); 00362 00363 ASSERT(dptr == dst.endw()); 00364 00365 return VideoFrame(dst); 00366 } 00367 00368 // ###################################################################### 00369 VideoFrame RGB32_to_YUV24(const byte* sptr, const size_t length, 00370 const Dims& dims, const bool byteswap) 00371 { 00372 const int sz = dims.sz() * 4; 00373 00374 checkBufferLength(length, sz); 00375 00376 Image<PixVideoYUV<byte> > dst(dims, NO_INIT); 00377 Image<PixVideoYUV<byte> >::iterator dptr = dst.beginw(); 00378 00379 if (byteswap) 00380 for (int i = 0; i < sz; i += 4) 00381 *dptr++ = PixVideoYUV<byte>(PixRGB<double>(sptr[i+2], sptr[i+1], sptr[i])); 00382 else 00383 for (int i = 0; i < sz; i += 4) 00384 *dptr++ = PixVideoYUV<byte>(PixRGB<double>(sptr[i+1], sptr[i+2], sptr[i+3])); 00385 00386 ASSERT(dptr == dst.endw()); 00387 00388 return VideoFrame(dst); 00389 } 00390 00391 // ###################################################################### 00392 VideoFrame YUV444_to_YUV24(const byte* sptr, const size_t length, 00393 const Dims& dims, const bool byteswap) 00394 { 00395 const int sz = dims.sz() * 3; 00396 00397 checkBufferLength(length, sz); 00398 00399 Image<PixVideoYUV<byte> > dst(dims, NO_INIT); 00400 Image<PixVideoYUV<byte> >::iterator dptr = dst.beginw(); 00401 00402 if (byteswap) 00403 for (int i = 0; i < sz; i += 6) 00404 { 00405 // data stored as: y0, u0, u1, v0, v1, y1 00406 *dptr++ = PixVideoYUV<byte>(PixRGB<double>(sptr[i], sptr[i+1], sptr[i+3])); 00407 *dptr++ = PixVideoYUV<byte>(PixRGB<double>(sptr[i+5], sptr[i+2], sptr[i+4])); 00408 } 00409 else 00410 for (int i = 0; i < sz; i += 6) 00411 { 00412 // data stored as: u0, y0, v0, u1, y1, v1 00413 *dptr++ = PixVideoYUV<byte>(PixRGB<double>(sptr[i+1], sptr[i+0], sptr[i+2])); 00414 *dptr++ = PixVideoYUV<byte>(PixRGB<double>(sptr[i+4], sptr[i+3], sptr[i+5])); 00415 } 00416 00417 ASSERT(dptr == dst.endw()); 00418 00419 return VideoFrame(dst); 00420 } 00421 00422 // ###################################################################### 00423 VideoFrame YUYV_to_YUV24(const byte* sptr, const size_t length, 00424 const Dims& dims, const bool byteswap) 00425 { 00426 const int sz = dims.sz() * 2; 00427 00428 checkBufferLength(length, sz); 00429 00430 Image<PixVideoYUV<byte> > dst(dims, NO_INIT); 00431 Image<PixVideoYUV<byte> >::iterator dptr = dst.beginw(); 00432 Image<PixVideoYUV<byte> >::iterator stop = dst.endw(); 00433 00434 if (byteswap) 00435 while (dptr != stop) 00436 { 00437 // data stored as: u, y0, v, y1 00438 *dptr++ = PixVideoYUV<byte>(sptr[1], sptr[0], sptr[2]); 00439 *dptr++ = PixVideoYUV<byte>(sptr[3], sptr[0], sptr[2]); 00440 sptr += 4; 00441 } 00442 else 00443 while (dptr != stop) 00444 { 00445 // data stored as: y0, u, y1, v 00446 *dptr++ = PixVideoYUV<byte>(sptr[0], sptr[1], sptr[3]); 00447 *dptr++ = PixVideoYUV<byte>(sptr[2], sptr[1], sptr[3]); 00448 sptr += 4; 00449 } 00450 00451 return VideoFrame(dst); 00452 } 00453 00454 // ###################################################################### 00455 VideoFrame YUV422_to_YUV24(const byte* sptr, const size_t length, 00456 const Dims& dims, const bool byteswap) 00457 { 00458 return YUYV_to_YUV24(sptr, length, dims, !byteswap); 00459 } 00460 00461 // ###################################################################### 00462 VideoFrame YUV411_to_YUV24(const byte* sptr, const size_t length, 00463 const Dims& dims, const bool byteswap) 00464 { 00465 checkBufferLength(length, dims.sz() * 3 / 2); 00466 00467 Image<PixVideoYUV<byte> > dst(dims, NO_INIT); 00468 Image<PixVideoYUV<byte> >::iterator dptr = dst.beginw(); 00469 Image<PixVideoYUV<byte> >::iterator stop = dst.endw(); 00470 00471 if (byteswap) 00472 while (dptr != stop) 00473 { 00474 // data stored as: y0, u, v, y1, y3, y2 00475 *dptr++ = PixVideoYUV<byte>(sptr[0], sptr[1], sptr[2]); 00476 *dptr++ = PixVideoYUV<byte>(sptr[3], sptr[1], sptr[2]); 00477 *dptr++ = PixVideoYUV<byte>(sptr[5], sptr[1], sptr[2]); 00478 *dptr++ = PixVideoYUV<byte>(sptr[4], sptr[1], sptr[2]); 00479 sptr += 6; 00480 } 00481 else 00482 while (dptr != stop) 00483 { 00484 // data stored as: u, y0, y1, v, y2, y3 00485 *dptr++ = PixVideoYUV<byte>(sptr[1], sptr[0], sptr[3]); 00486 *dptr++ = PixVideoYUV<byte>(sptr[2], sptr[0], sptr[3]); 00487 *dptr++ = PixVideoYUV<byte>(sptr[4], sptr[0], sptr[3]); 00488 *dptr++ = PixVideoYUV<byte>(sptr[5], sptr[0], sptr[3]); 00489 sptr += 6; 00490 } 00491 00492 return VideoFrame(dst); 00493 } 00494 00495 // ###################################################################### 00496 VideoFrame YUV444P_to_YUV24(const byte* sptr, const size_t length, 00497 const Dims& dims, const bool byteswap) 00498 { 00499 checkBufferLength(length, dims.sz() * 3); 00500 00501 Image<PixVideoYUV<byte> > dst(dims, NO_INIT); 00502 Image<PixVideoYUV<byte> >::iterator dptr = dst.beginw(); 00503 Image<PixVideoYUV<byte> >::iterator stop = dst.endw(); 00504 00505 const byte* yptr = sptr; 00506 const byte* uptr = yptr + dims.sz(); 00507 const byte* vptr = uptr + dims.sz(); 00508 00509 if (byteswap) 00510 std::swap(uptr, vptr); 00511 00512 while (dptr != stop) 00513 *dptr++ = PixVideoYUV<byte>(*yptr++, *uptr++, *vptr++); 00514 00515 return VideoFrame(dst); 00516 } 00517 00518 // ###################################################################### 00519 VideoFrame YUV422P_to_YUV24(const byte* sptr, const size_t length, 00520 const Dims& dims, const bool byteswap) 00521 { 00522 const int w = dims.w(); 00523 const int h = dims.h(); 00524 00525 checkBufferLength(length, dims.sz() + 2*(w/2)*h); 00526 00527 Image<PixVideoYUV<byte> > dst(dims, NO_INIT); 00528 Image<PixVideoYUV<byte> >::iterator dptr = dst.beginw(); 00529 00530 const byte* yptr = sptr; 00531 const byte* uptr = yptr + w * h; 00532 const byte* vptr = uptr + (w/2) * h; 00533 00534 if (byteswap) 00535 std::swap(uptr, vptr); 00536 00537 for (int j = 0; j < h; ++j) 00538 for (int i = 0; i < w; i += 2) 00539 { 00540 // we have 2 luminance pixels per chroma pair 00541 00542 const byte yf1 = *yptr++; 00543 const byte yf2 = *yptr++; 00544 const byte uf = *uptr++; 00545 const byte vf = *vptr++; 00546 00547 *dptr++ = PixVideoYUV<byte>(yf1, uf, vf); 00548 *dptr++ = PixVideoYUV<byte>(yf2, uf, vf); 00549 } 00550 ASSERT(dptr == dst.endw()); 00551 00552 return VideoFrame(dst); 00553 } 00554 00555 // ###################################################################### 00556 VideoFrame YUV411P_to_YUV24(const byte* sptr, const size_t length, 00557 const Dims& dims, const bool byteswap) 00558 { 00559 const int w = dims.w(); 00560 const int h = dims.h(); 00561 00562 checkBufferLength(length, dims.sz() + 2*(w/4)*h); 00563 00564 Image<PixVideoYUV<byte> > dst(dims, NO_INIT); 00565 Image<PixVideoYUV<byte> >::iterator dptr = dst.beginw(); 00566 00567 const byte* yptr = sptr; 00568 const byte* uptr = yptr + w * h; 00569 const byte* vptr = uptr + (w/4) * h; 00570 00571 if (byteswap) 00572 std::swap(uptr, vptr); 00573 00574 for (int j = 0; j < h; ++j) 00575 for (int i = 0; i < w; i += 4) 00576 { 00577 // we have a 4 luminance pixels per chroma pair 00578 const byte uf = *uptr++; 00579 const byte vf = *vptr++; 00580 00581 *dptr++ = PixVideoYUV<byte>(*yptr++, uf, vf); 00582 *dptr++ = PixVideoYUV<byte>(*yptr++, uf, vf); 00583 *dptr++ = PixVideoYUV<byte>(*yptr++, uf, vf); 00584 *dptr++ = PixVideoYUV<byte>(*yptr++, uf, vf); 00585 } 00586 ASSERT(dptr == dst.endw()); 00587 00588 return VideoFrame(dst); 00589 } 00590 00591 // ###################################################################### 00592 VideoFrame YUV420P_to_YUV24(const byte* sptr, const size_t length, 00593 const Dims& dims, const bool byteswap) 00594 { 00595 00596 const int w = dims.w(); 00597 const int h = dims.h(); 00598 // we have to do (w+1)/2 instead of just w/2, because if e.g. the y 00599 // array has 5 pixels, then we want the u and v arrays to have 3 00600 // pixels, not 2: 00601 const int w2 = (w+1)/2; 00602 const int h2 = (h+1)/2; 00603 00604 checkBufferLength(length, dims.sz() + 2*w2*h2); 00605 00606 Image<PixVideoYUV<byte> > dst(dims, NO_INIT); 00607 Image<PixVideoYUV<byte> >::iterator dptr = dst.beginw(); 00608 00609 const byte* yptr = sptr; 00610 const byte* uptr = yptr + w * h; 00611 const byte* vptr = uptr + w2 * h2; 00612 00613 if (byteswap) 00614 std::swap(uptr, vptr); 00615 00616 for (int j = 0; j < h; j += 2) 00617 { 00618 for (int i = 0; i < w; i += 2) 00619 { 00620 const byte u = *uptr++; 00621 const byte v = *vptr++; 00622 // we have a 2x2 luminance block per chroma pair 00623 dptr[0] = PixVideoYUV<byte>(yptr[0], u, v); 00624 dptr[1] = PixVideoYUV<byte>(yptr[1], u, v); 00625 dptr[w] = PixVideoYUV<byte>(yptr[w], u, v); 00626 dptr[w+1] = PixVideoYUV<byte>(yptr[w+1], u, v); 00627 00628 dptr += 2; 00629 yptr += 2; 00630 } 00631 dptr += w; 00632 yptr += w; 00633 } 00634 ASSERT(dptr == dst.endw()); 00635 00636 return VideoFrame(dst); 00637 } 00638 00639 // ###################################################################### 00640 VideoFrame YUV410P_to_YUV24(const byte* sptr, const size_t length, 00641 const Dims& dims, const bool byteswap) 00642 { 00643 const int w = dims.w(); 00644 const int h = dims.h(); 00645 const int w2 = w * 2; 00646 const int w3 = w * 3; 00647 00648 checkBufferLength(length, dims.sz() * 9 / 8); 00649 00650 Image<PixVideoYUV<byte> > dst(dims, NO_INIT); 00651 Image<PixVideoYUV<byte> >::iterator dptr = dst.beginw(); 00652 00653 const byte* yptr = sptr; 00654 const byte* uptr = yptr + w * h; 00655 const byte* vptr = uptr + (w/4) * (h/4); 00656 00657 for (int j = 0; j < h; j += 4) 00658 { 00659 for (int i = 0; i < w; i += 4) 00660 { 00661 const byte u = *uptr++; 00662 const byte v = *vptr++; 00663 00664 // we have a 4x4 luminance block per chroma pair 00665 dptr[0] = PixVideoYUV<byte>(*yptr, u, v); 00666 dptr[1] = PixVideoYUV<byte>(yptr[1], u, v); 00667 dptr[2] = PixVideoYUV<byte>(yptr[2], u, v); 00668 dptr[3] = PixVideoYUV<byte>(yptr[3], u, v); 00669 00670 dptr[w] = PixVideoYUV<byte>(yptr[w], u, v); 00671 dptr[w+1] = PixVideoYUV<byte>(yptr[w+1], u, v); 00672 dptr[w+2] = PixVideoYUV<byte>(yptr[w+2], u, v); 00673 dptr[w+3] = PixVideoYUV<byte>(yptr[w+3], u, v); 00674 00675 dptr[w2] = PixVideoYUV<byte>(yptr[w2], u, v); 00676 dptr[w2+1] = PixVideoYUV<byte>(yptr[w2+1], u, v); 00677 dptr[w2+2] = PixVideoYUV<byte>(yptr[w2+2], u, v); 00678 dptr[w2+3] = PixVideoYUV<byte>(yptr[w2+3], u, v); 00679 00680 dptr[w3] = PixVideoYUV<byte>(yptr[w3], u, v); 00681 dptr[w3+1] = PixVideoYUV<byte>(yptr[w3+1], u, v); 00682 dptr[w3+2] = PixVideoYUV<byte>(yptr[w3+2], u, v); 00683 dptr[w3+3] = PixVideoYUV<byte>(yptr[w3+3], u, v); 00684 00685 dptr += 4; 00686 yptr += 4; 00687 } 00688 dptr += w3; 00689 yptr += w3; 00690 } 00691 ASSERT(dptr == dst.endw()); 00692 00693 return VideoFrame(dst); 00694 } 00695 00696 // ###################################################################### 00697 // ###################################################################### 00698 // conversions from YUV24 00699 // ###################################################################### 00700 // ###################################################################### 00701 00702 // ###################################################################### 00703 VideoFrame YUV24_to_YUV444(const byte* sptr, const size_t length, 00704 const Dims& dims, const bool byteswap) 00705 { 00706 checkBufferLength(length, dims.sz() * 3); 00707 00708 ArrayHandle<byte> dst(new ArrayData<byte>(Dims(dims.sz() * 3, 1), NO_INIT)); 00709 byte* dptr = dst.uniq().dataw(); 00710 byte* stop = dst.uniq().endw(); 00711 00712 // output data stored as: u0, y0, v0, u1, y1, v1 00713 00714 if (byteswap) 00715 while (dptr != stop) 00716 { 00717 // input data stored as: y0, v0, u0, y1, v1, u1 00718 dptr[0] = sptr[2]; 00719 dptr[1] = sptr[0]; 00720 dptr[2] = sptr[1]; 00721 dptr[3] = sptr[5]; 00722 dptr[4] = sptr[3]; 00723 dptr[5] = sptr[4]; 00724 00725 dptr += 6; 00726 sptr += 6; 00727 } 00728 else 00729 while (dptr != stop) 00730 { 00731 // input data stored as: y0, u0, v0, y1, u1, v1 00732 dptr[0] = sptr[1]; 00733 dptr[1] = sptr[0]; 00734 dptr[2] = sptr[2]; 00735 dptr[3] = sptr[4]; 00736 dptr[4] = sptr[3]; 00737 dptr[5] = sptr[5]; 00738 00739 dptr += 6; 00740 sptr += 6; 00741 } 00742 00743 return VideoFrame(dst, dims, VIDFMT_YUV444, false); 00744 } 00745 00746 // ###################################################################### 00747 VideoFrame YUV24_to_YUYV(const byte* sptr, const size_t length, 00748 const Dims& dims, const bool byteswap) 00749 { 00750 checkBufferLength(length, dims.sz() * 3); 00751 00752 ASSERT(dims.w() % 2 == 0); 00753 00754 ArrayHandle<byte> dst(new ArrayData<byte>(Dims(dims.sz() * 2, 1), NO_INIT)); 00755 byte* dptr = dst.uniq().dataw(); 00756 byte* stop = dst.uniq().endw(); 00757 00758 // output data stored as: y0, u, y1, v 00759 00760 if (byteswap) 00761 while (dptr != stop) 00762 { 00763 // input data stored as: y0, v0, u0, y1, v1, u1 00764 dptr[0] = sptr[0]; 00765 dptr[1] = byte((sptr[2] + sptr[5])/2.0 + 0.5); 00766 dptr[2] = sptr[3]; 00767 dptr[3] = byte((sptr[1] + sptr[4])/2.0 + 0.5); 00768 00769 dptr += 4; 00770 sptr += 6; 00771 } 00772 else 00773 while (dptr != stop) 00774 { 00775 // input data stored as: y0, u0, v0, y1, u1, v1 00776 dptr[0] = sptr[0]; 00777 dptr[1] = byte((sptr[1] + sptr[4])/2.0 + 0.5); 00778 dptr[2] = sptr[3]; 00779 dptr[3] = byte((sptr[2] + sptr[5])/2.0 + 0.5); 00780 00781 dptr += 4; 00782 sptr += 6; 00783 } 00784 00785 return VideoFrame(dst, dims, VIDFMT_YUYV, false); 00786 } 00787 00788 // ###################################################################### 00789 ArrayHandle<byte> YUV24_to_UYVYx(const byte* sptr, const size_t length, 00790 const Dims& dims, const bool byteswap) 00791 { 00792 checkBufferLength(length, dims.sz() * 3); 00793 00794 ASSERT(dims.w() % 2 == 0); 00795 00796 ArrayHandle<byte> dst(new ArrayData<byte>(Dims(dims.sz() * 2, 1), NO_INIT)); 00797 byte* dptr = dst.uniq().dataw(); 00798 byte* stop = dst.uniq().endw(); 00799 00800 // output data stored as: u, y0, v, y1 00801 00802 if (byteswap) 00803 while (dptr != stop) 00804 { 00805 // input data stored as: y0, v0, u0, y1, v1, u1 00806 dptr[0] = byte((sptr[2] + sptr[5])/2.0 + 0.5); 00807 dptr[1] = sptr[0]; 00808 dptr[2] = byte((sptr[1] + sptr[4])/2.0 + 0.5); 00809 dptr[3] = sptr[3]; 00810 00811 dptr += 4; 00812 sptr += 6; 00813 } 00814 else 00815 while (dptr != stop) 00816 { 00817 // input data stored as: y0, u0, v0, y1, u1, v1 00818 dptr[0] = byte((sptr[1] + sptr[4])/2.0 + 0.5); 00819 dptr[1] = sptr[0]; 00820 dptr[2] = byte((sptr[2] + sptr[5])/2.0 + 0.5); 00821 dptr[3] = sptr[3]; 00822 00823 dptr += 4; 00824 sptr += 6; 00825 } 00826 00827 return dst; 00828 } 00829 00830 // ###################################################################### 00831 VideoFrame YUV24_to_UYVY(const byte* sptr, const size_t length, 00832 const Dims& dims, const bool byteswap) 00833 { 00834 return VideoFrame(YUV24_to_UYVYx(sptr, length, dims, byteswap), 00835 dims, VIDFMT_UYVY, false); 00836 } 00837 00838 // ###################################################################### 00839 VideoFrame YUV24_to_YUV422(const byte* sptr, const size_t length, 00840 const Dims& dims, const bool byteswap) 00841 { 00842 return VideoFrame(YUV24_to_UYVYx(sptr, length, dims, byteswap), 00843 dims, VIDFMT_YUV422, false); 00844 } 00845 00846 // ###################################################################### 00847 VideoFrame YUV24_to_YUV411(const byte* sptr, const size_t length, 00848 const Dims& dims, const bool byteswap) 00849 { 00850 checkBufferLength(length, dims.sz() * 3); 00851 00852 ASSERT(dims.w() % 4 == 0); 00853 00854 ArrayHandle<byte> dst(new ArrayData<byte>(Dims(dims.sz() * 3 / 2, 1), NO_INIT)); 00855 byte* dptr = dst.uniq().dataw(); 00856 byte* stop = dst.uniq().endw(); 00857 00858 // output data stored as: u, y0, y1, v, y2, y3 00859 00860 if (byteswap) 00861 while (dptr != stop) 00862 { 00863 // input data stored as: y0, v0, u0, y1, v1, u1, y2, v2, y2, y3, v3, u3 00864 dptr[0] = byte((sptr[2] + sptr[5] + sptr[8] + sptr[11])/4.0 + 0.5); 00865 dptr[1] = sptr[0]; 00866 dptr[2] = sptr[3]; 00867 dptr[3] = byte((sptr[1] + sptr[4] + sptr[7] + sptr[10])/4.0 + 0.5); 00868 dptr[4] = sptr[6]; 00869 dptr[5] = sptr[9]; 00870 00871 dptr += 6; 00872 sptr += 12; 00873 } 00874 else 00875 while (dptr != stop) 00876 { 00877 // input data stored as: y0, u0, v0, y1, u1, v1, y2, u2, v2, y3, u3, v3 00878 dptr[0] = byte((sptr[1] + sptr[4] + sptr[7] + sptr[10])/4.0 + 0.5); 00879 dptr[1] = sptr[0]; 00880 dptr[2] = sptr[3]; 00881 dptr[3] = byte((sptr[2] + sptr[5] + sptr[8] + sptr[11])/4.0 + 0.5); 00882 dptr[4] = sptr[6]; 00883 dptr[5] = sptr[9]; 00884 00885 dptr += 6; 00886 sptr += 12; 00887 } 00888 00889 return VideoFrame(dst, dims, VIDFMT_YUV411, false); 00890 } 00891 00892 // ###################################################################### 00893 VideoFrame YUV24_to_YUV444P(const byte* sptr, const size_t length, 00894 const Dims& dims, const bool byteswap) 00895 { 00896 checkBufferLength(length, dims.sz() * 3); 00897 00898 ArrayHandle<byte> dst(new ArrayData<byte>(Dims(dims.sz() * 3, 1), NO_INIT)); 00899 byte* yptr = dst.uniq().dataw(); 00900 byte* uptr = yptr + dims.sz(); 00901 byte* vptr = uptr + dims.sz(); 00902 00903 if (byteswap) 00904 std::swap(uptr, vptr); 00905 00906 const byte* sstop = sptr + length; 00907 00908 while (sptr != sstop) 00909 { 00910 *yptr++ = *sptr++; 00911 *uptr++ = *sptr++; 00912 *vptr++ = *sptr++; 00913 } 00914 00915 return VideoFrame(dst, dims, VIDFMT_YUV444P, false); 00916 } 00917 00918 // ###################################################################### 00919 VideoFrame YUV24_to_YUV422P(const byte* sptr, const size_t length, 00920 const Dims& dims, const bool byteswap) 00921 { 00922 checkBufferLength(length, dims.sz() * 3); 00923 00924 ASSERT(dims.w() % 2 == 0); 00925 00926 const int w = dims.w(); 00927 const int h = dims.h(); 00928 00929 ArrayHandle<byte> dst(new ArrayData<byte>(Dims(dims.sz() + 2 * (w/2)*h, 1), NO_INIT)); 00930 byte* yptr = dst.uniq().dataw(); 00931 byte* uptr = yptr + w * h; 00932 byte* vptr = uptr + (w/2) * h; 00933 00934 if (byteswap) 00935 std::swap(uptr, vptr); 00936 00937 const byte* sstop = sptr + length; 00938 00939 while (sptr != sstop) 00940 { 00941 *yptr++ = sptr[0]; 00942 *yptr++ = sptr[3]; 00943 *uptr++ = byte((sptr[1]+sptr[4])/2.0 + 0.5); 00944 *vptr++ = byte((sptr[2]+sptr[5])/2.0 + 0.5); 00945 sptr += 6; 00946 } 00947 00948 return VideoFrame(dst, dims, VIDFMT_YUV422P, false); 00949 } 00950 00951 // ###################################################################### 00952 VideoFrame YUV24_to_YUV411P(const byte* sptr, const size_t length, 00953 const Dims& dims, const bool byteswap) 00954 { 00955 checkBufferLength(length, dims.sz() * 3); 00956 00957 ASSERT(dims.w() % 4 == 0); 00958 00959 const int w = dims.w(); 00960 const int h = dims.h(); 00961 00962 ArrayHandle<byte> dst(new ArrayData<byte>(Dims(dims.sz() + 2 * (w/4)*h, 1), NO_INIT)); 00963 byte* yptr = dst.uniq().dataw(); 00964 byte* uptr = yptr + w * h; 00965 byte* vptr = uptr + (w/4) * h; 00966 00967 if (byteswap) 00968 std::swap(uptr, vptr); 00969 00970 const byte* sstop = sptr + length; 00971 00972 while (sptr != sstop) 00973 { 00974 *yptr++ = sptr[0]; 00975 *yptr++ = sptr[3]; 00976 *yptr++ = sptr[6]; 00977 *yptr++ = sptr[9]; 00978 *uptr++ = byte((sptr[1]+sptr[4]+sptr[7]+sptr[10])/4.0 + 0.5); 00979 *vptr++ = byte((sptr[2]+sptr[5]+sptr[8]+sptr[11])/4.0 + 0.5); 00980 sptr += 12; 00981 } 00982 00983 return VideoFrame(dst, dims, VIDFMT_YUV411P, false); 00984 } 00985 00986 // ###################################################################### 00987 VideoFrame YUV24_to_YUV420P(const byte* sptr, const size_t length, 00988 const Dims& dims, const bool byteswap) 00989 { 00990 checkBufferLength(length, dims.sz() * 3); 00991 00992 ASSERT(dims.w() % 2 == 0); 00993 ASSERT(dims.h() % 2 == 0); 00994 00995 const int w = dims.w(); 00996 const int h = dims.h(); 00997 00998 const int w2 = (w+1)/2; 00999 const int h2 = (h+1)/2; 01000 01001 ArrayHandle<byte> dst(new ArrayData<byte>(Dims(dims.sz() + 2*w2*h2, 1), NO_INIT)); 01002 byte* yptr = dst.uniq().dataw(); 01003 byte* uptr = yptr + w * h; 01004 byte* vptr = uptr + w2 * h2; 01005 01006 if (byteswap) 01007 std::swap(uptr, vptr); 01008 01009 const byte* sstop = sptr + length; 01010 01011 for (int j = 0; j < h; j += 2) 01012 { 01013 for (int i = 0; i < w; i += 2) 01014 { 01015 yptr[0] = sptr[0]; 01016 yptr[1] = sptr[3]; 01017 yptr[w] = sptr[3*w]; 01018 yptr[w+1] = sptr[3*w+3]; 01019 *uptr++ = byte((sptr[1] + sptr[4] + sptr[3*w+1] + sptr[3*w+4])/4.0 + 0.5); 01020 *vptr++ = byte((sptr[2] + sptr[5] + sptr[3*w+2] + sptr[3*w+5])/4.0 + 0.5); 01021 01022 yptr += 2; 01023 sptr += 6; 01024 } 01025 01026 yptr += w; 01027 sptr += 3*w; 01028 } 01029 01030 ASSERT(sptr == sstop); 01031 01032 return VideoFrame(dst, dims, VIDFMT_YUV420P, false); 01033 } 01034 01035 // ###################################################################### 01036 VideoFrame YUV24_to_YUV410P(const byte* sptr, const size_t length, 01037 const Dims& dims, const bool byteswap) 01038 { 01039 checkBufferLength(length, dims.sz() * 3); 01040 01041 ASSERT(dims.w() % 4 == 0); 01042 ASSERT(dims.h() % 4 == 0); 01043 01044 const int w = dims.w(); 01045 const int h = dims.h(); 01046 01047 ArrayHandle<byte> dst(new ArrayData<byte>(Dims(dims.sz() * 9 / 8, 1), NO_INIT)); 01048 byte* yptr = dst.uniq().dataw(); 01049 byte* uptr = yptr + w * h; 01050 byte* vptr = uptr + (w/4) * (h/4); 01051 01052 if (byteswap) 01053 std::swap(uptr, vptr); 01054 01055 const byte* sstop = sptr + length; 01056 01057 for (int j = 0; j < h; j += 4) 01058 { 01059 for (int i = 0; i < w; i += 4) 01060 { 01061 yptr[0] = sptr[0]; 01062 yptr[1] = sptr[3]; 01063 yptr[2] = sptr[6]; 01064 yptr[3] = sptr[9]; 01065 yptr[w] = sptr[3*w]; 01066 yptr[w+1] = sptr[3*w+3]; 01067 yptr[w+2] = sptr[3*w+6]; 01068 yptr[w+3] = sptr[3*w+9]; 01069 yptr[2*w] = sptr[6*w]; 01070 yptr[2*w+1] = sptr[6*w+3]; 01071 yptr[2*w+2] = sptr[6*w+6]; 01072 yptr[2*w+3] = sptr[6*w+9]; 01073 yptr[3*w] = sptr[9*w]; 01074 yptr[3*w+1] = sptr[9*w+3]; 01075 yptr[3*w+2] = sptr[9*w+6]; 01076 yptr[3*w+3] = sptr[9*w+9]; 01077 01078 *uptr++ = byte((sptr[1] + sptr[4] + sptr[7] + sptr[10] + 01079 sptr[3*w+1] + sptr[3*w+4] + sptr[3*w+7] + sptr[3*w+10] + 01080 sptr[6*w+1] + sptr[6*w+4] + sptr[6*w+7] + sptr[6*w+10] + 01081 sptr[9*w+1] + sptr[9*w+4] + sptr[9*w+7] + sptr[9*w+10]) 01082 / 16.0 + 0.5); 01083 *vptr++ = byte((sptr[2] + sptr[5] + sptr[8] + sptr[11] + 01084 sptr[3*w+2] + sptr[3*w+5] + sptr[3*w+8] + sptr[3*w+11] + 01085 sptr[6*w+2] + sptr[6*w+5] + sptr[6*w+8] + sptr[6*w+11] + 01086 sptr[9*w+2] + sptr[9*w+5] + sptr[9*w+8] + sptr[9*w+11]) 01087 / 16.0 + 0.5); 01088 01089 yptr += 4; 01090 sptr += 12; 01091 } 01092 01093 yptr += 3*w; 01094 sptr += 9*w; 01095 } 01096 01097 ASSERT(sptr == sstop); 01098 01099 return VideoFrame(dst, dims, VIDFMT_YUV410P, false); 01100 } 01101 01102 // ###################################################################### 01103 // ###################################################################### 01104 // VideoFormatConverter 01105 // ###################################################################### 01106 // ###################################################################### 01107 01108 // ###################################################################### 01109 VideoFormatConverter::VideoFormatConverter(VideoFormatConverter::Func* f, 01110 unsigned int w, 01111 VideoFormat s, VideoFormat d, 01112 const char* fn) 01113 : func(f), weight(w), src(s), dst(d), fname(fn) 01114 {} 01115 01116 // ###################################################################### 01117 VideoFrame VideoFormatConverter::apply(const VideoFrame& in) const 01118 { 01119 if (func == NULL) 01120 LFATAL("oops! this is an invalid VideoFormatConverter"); 01121 01122 if (in.getMode() != this->src) 01123 LFATAL("oops! src frame is %s, but converter (%s) expects %s", 01124 convertToString(in.getMode()).c_str(), 01125 this->fname.c_str(), 01126 convertToString(this->src).c_str()); 01127 01128 const VideoFrame result = 01129 (*this->func)(in.getBuffer(), in.getBufSize(), 01130 in.getDims(), in.getByteSwap()); 01131 01132 ASSERT(result.getMode() == this->dst); 01133 01134 return result; 01135 } 01136 01137 01138 // ###################################################################### 01139 // ###################################################################### 01140 // VideoFormatCoercion 01141 // ###################################################################### 01142 // ###################################################################### 01143 01144 // ###################################################################### 01145 VideoFormatCoercion::VideoFormatCoercion() 01146 {} 01147 01148 // ###################################################################### 01149 VideoFormatCoercion::VideoFormatCoercion(unsigned int w, 01150 VideoFormat s, VideoFormat d, 01151 VideoFormatConverter::Func* f, 01152 const char* fname) 01153 { 01154 if (f != NULL) 01155 nodes.push_back(VideoFormatConverter(f, w, s, d, fname)); 01156 } 01157 01158 // ###################################################################### 01159 std::string VideoFormatCoercion::describe() const 01160 { 01161 if (nodes.empty()) 01162 return std::string("nil"); 01163 01164 unsigned int w = 0; 01165 for (size_t i = 0; i < nodes.size(); ++i) 01166 w += nodes[i].weight; 01167 01168 std::string result = sformat("%s -> %s [wt=%u] (", 01169 convertToString(nodes.front().src).c_str(), 01170 convertToString(nodes.back().dst).c_str(), 01171 w); 01172 01173 for (size_t i = 0; i < nodes.size(); ++i) 01174 { 01175 result += sformat("%s [wt=%u]", 01176 nodes[i].fname.c_str(), nodes[i].weight); 01177 01178 if (i+1 < nodes.size()) 01179 result += "; "; 01180 } 01181 01182 result += ")"; 01183 return result; 01184 } 01185 01186 // ###################################################################### 01187 VideoFrame VideoFormatCoercion::apply(const VideoFrame& src) const 01188 { 01189 if (nodes.size() == 0) 01190 LFATAL("oops! this is an invalid VideoFormat converter"); 01191 01192 VideoFrame result = src; 01193 for (size_t i = 0; i < nodes.size(); ++i) 01194 result = nodes[i].apply(result); 01195 01196 return result; 01197 } 01198 01199 01200 // ###################################################################### 01201 // ###################################################################### 01202 // conversion table 01203 // ###################################################################### 01204 // ###################################################################### 01205 01206 static VideoFormatCoercion pathtab[VIDFMT_AUTO+1][VIDFMT_AUTO+1]; 01207 01208 static const unsigned int PRECISION_PENALTY = 100; // loss of pixel bit depth (e.g. rgb24->rgb565) 01209 static const unsigned int RESOLUTION_PENALTY = 10000; // loss of spatial resolution (e.g. yuv24 -> yuv411) 01210 static const unsigned int COLORSPACE_PENALTY = 1000000; // lossy colorspace conversion (e.g. rgb->yuv) 01211 static const unsigned int COLORDIMENSION_PENALTY = 100000000; // reduction in the number of color planes (e.g., rgb->grey) 01212 01213 static void initDirectConversions(VideoFormatCoercion table[VIDFMT_AUTO+1][VIDFMT_AUTO+1]) 01214 { 01215 #define CONVERT(vf1, vf2, wt, f) \ 01216 table[vf1][vf2] = VideoFormatCoercion(wt, vf1, vf2, f, #f) 01217 01218 // conversions to RGB24 01219 CONVERT(VIDFMT_GREY, VIDFMT_RGB24, 1, &GREY_to_RGB24); 01220 CONVERT(VIDFMT_RGB555, VIDFMT_RGB24, 1, &RGB555_to_RGB24); 01221 CONVERT(VIDFMT_RGB565, VIDFMT_RGB24, 1, &RGB565_to_RGB24); 01222 CONVERT(VIDFMT_RGB32, VIDFMT_RGB24, 1, &ARGB_to_RGB24); 01223 CONVERT(VIDFMT_YUYV, VIDFMT_RGB24, 1+COLORSPACE_PENALTY, &YUYV_to_RGB24); 01224 CONVERT(VIDFMT_UYVY, VIDFMT_RGB24, 1+COLORSPACE_PENALTY, &YUV422_to_RGB24); 01225 CONVERT(VIDFMT_YUV444, VIDFMT_RGB24, 1+COLORSPACE_PENALTY, &YUV444_to_RGB24); 01226 CONVERT(VIDFMT_YUV422, VIDFMT_RGB24, 1+COLORSPACE_PENALTY, &YUV422_to_RGB24); 01227 CONVERT(VIDFMT_YUV411, VIDFMT_RGB24, 1+COLORSPACE_PENALTY, &YUV411_to_RGB24); 01228 //CONVERT(VIDFMT_YUV420, VIDFMT_RGB24, 1+COLORSPACE_PENALTY, NULL); /* not implemented: what is YUV420? */ 01229 //CONVERT(VIDFMT_YUV410, VIDFMT_RGB24, 1+COLORSPACE_PENALTY, NULL); /* not implemented: what is YUV410? */ 01230 CONVERT(VIDFMT_YUV444P, VIDFMT_RGB24, 1+COLORSPACE_PENALTY, &YUV444P_to_RGB24); 01231 CONVERT(VIDFMT_YUV422P, VIDFMT_RGB24, 1+COLORSPACE_PENALTY, &YUV422P_to_RGB24); 01232 CONVERT(VIDFMT_YUV411P, VIDFMT_RGB24, 1+COLORSPACE_PENALTY, &YUV411P_to_RGB24); 01233 CONVERT(VIDFMT_YUV420P, VIDFMT_RGB24, 1+COLORSPACE_PENALTY, &YUV420P_to_RGB24); 01234 CONVERT(VIDFMT_YUV410P, VIDFMT_RGB24, 1+COLORSPACE_PENALTY, &YUV410P_to_RGB24); 01235 01236 // conversions from RGB24 01237 CONVERT(VIDFMT_RGB24, VIDFMT_GREY, 1+COLORDIMENSION_PENALTY, &RGB24_to_GREY); 01238 CONVERT(VIDFMT_RGB24, VIDFMT_RGB555, 1+PRECISION_PENALTY, &RGB24_to_RGB555); 01239 CONVERT(VIDFMT_RGB24, VIDFMT_RGB565, 1+PRECISION_PENALTY, &RGB24_to_RGB565); 01240 CONVERT(VIDFMT_RGB24, VIDFMT_RGB32, 1, &RGB24_to_RGB32); 01241 CONVERT(VIDFMT_RGB24, VIDFMT_YUV24, 1+COLORSPACE_PENALTY, &RGB24_to_YUV24); 01242 //CONVERT(VIDFMT_RGB24, VIDFMT_YUYV, 1+COLORSPACE_PENALTY+RESOLUTION_PENALTY, NULL); /* could be implemented in the future */ 01243 //CONVERT(VIDFMT_RGB24, VIDFMT_UYVY, 1+COLORSPACE_PENALTY+RESOLUTION_PENALTY, NULL); /* could be implemented in the future */ 01244 //CONVERT(VIDFMT_RGB24, VIDFMT_YUV444, 1+COLORSPACE_PENALTY, NULL); /* could be implemented in the future */ 01245 //CONVERT(VIDFMT_RGB24, VIDFMT_YUV422, 1+COLORSPACE_PENALTY+RESOLUTION_PENALTY, NULL); /* could be implemented in the future */ 01246 //CONVERT(VIDFMT_RGB24, VIDFMT_YUV411, 1+COLORSPACE_PENALTY+RESOLUTION_PENALTY, NULL); /* could be implemented in the future */ 01247 //CONVERT(VIDFMT_RGB24, VIDFMT_YUV420, 1+COLORSPACE_PENALTY+RESOLUTION_PENALTY, NULL); /* not implemented: what is YUV420? */ 01248 //CONVERT(VIDFMT_RGB24, VIDFMT_YUV410, 1+COLORSPACE_PENALTY+RESOLUTION_PENALTY, NULL); /* not implemented: what is YUV410? */ 01249 //CONVERT(VIDFMT_RGB24, VIDFMT_YUV444P, 1+COLORSPACE_PENALTY, NULL); /* could be implemented in the future */ 01250 //CONVERT(VIDFMT_RGB24, VIDFMT_YUV422P, 1+COLORSPACE_PENALTY+RESOLUTION_PENALTY, NULL); /* could be implemented in the future */ 01251 //CONVERT(VIDFMT_RGB24, VIDFMT_YUV411P, 1+COLORSPACE_PENALTY+RESOLUTION_PENALTY, NULL); /* could be implemented in the future */ 01252 //CONVERT(VIDFMT_RGB24, VIDFMT_YUV420P, 1+COLORSPACE_PENALTY+RESOLUTION_PENALTY, NULL); /* could be implemented in the future */ 01253 //CONVERT(VIDFMT_RGB24, VIDFMT_YUV410P, 1+COLORSPACE_PENALTY+RESOLUTION_PENALTY, NULL); /* could be implemented in the future */ 01254 01255 // conversions to YUV24 01256 CONVERT(VIDFMT_GREY, VIDFMT_YUV24, 1+COLORSPACE_PENALTY, &GREY_to_YUV24); 01257 //CONVERT(VIDFMT_RGB555, VIDFMT_YUV24, 1+COLORSPACE_PENALTY, NULL); /* could be implemented in the future */ 01258 //CONVERT(VIDFMT_RGB565, VIDFMT_YUV24, 1+COLORSPACE_PENALTY, NULL); /* could be implemented in the future */ 01259 CONVERT(VIDFMT_RGB24, VIDFMT_YUV24, 1+COLORSPACE_PENALTY, &RGB24_to_YUV24); 01260 CONVERT(VIDFMT_RGB32, VIDFMT_YUV24, 1+COLORSPACE_PENALTY, &RGB32_to_YUV24); 01261 CONVERT(VIDFMT_YUYV, VIDFMT_YUV24, 1, &YUYV_to_YUV24); 01262 CONVERT(VIDFMT_UYVY, VIDFMT_YUV24, 1, &YUV422_to_YUV24); 01263 CONVERT(VIDFMT_YUV444, VIDFMT_YUV24, 1, &YUV444_to_YUV24); 01264 CONVERT(VIDFMT_YUV422, VIDFMT_YUV24, 1, &YUV422_to_YUV24); 01265 CONVERT(VIDFMT_YUV411, VIDFMT_YUV24, 1, &YUV411_to_YUV24); 01266 //CONVERT(VIDFMT_YUV420, VIDFMT_YUV24, 1, NULL); /* not implemented: what is YUV420? */ 01267 //CONVERT(VIDFMT_YUV410, VIDFMT_YUV24, 1, NULL); /* not implemented: what is YUV410? */ 01268 CONVERT(VIDFMT_YUV444P, VIDFMT_YUV24, 1, &YUV444P_to_YUV24); 01269 CONVERT(VIDFMT_YUV422P, VIDFMT_YUV24, 1, &YUV422P_to_YUV24); 01270 CONVERT(VIDFMT_YUV411P, VIDFMT_YUV24, 1, &YUV411P_to_YUV24); 01271 CONVERT(VIDFMT_YUV420P, VIDFMT_YUV24, 1, &YUV420P_to_YUV24); 01272 CONVERT(VIDFMT_YUV410P, VIDFMT_YUV24, 1, &YUV410P_to_YUV24); 01273 01274 // conversions from YUV24 01275 //CONVERT(VIDFMT_YUV24, VIDFMT_GREY, 1+COLORSPACE_PENALTY, NULL); /* could be implemented in the future */ 01276 //CONVERT(VIDFMT_YUV24, VIDFMT_RGB555, 1+COLORSPACE_PENALTY+PRECISION_PENALTY, NULL); /* could be implemented in the future */ 01277 //CONVERT(VIDFMT_YUV24, VIDFMT_RGB565, 1+COLORSPACE_PENALTY+PRECISION_PENALTY, NULL); /* could be implemented in the future */ 01278 CONVERT(VIDFMT_YUV24, VIDFMT_RGB24, 1+COLORSPACE_PENALTY, &YUV24_to_RGB24); 01279 //CONVERT(VIDFMT_YUV24, VIDFMT_RGB32, 1+COLORSPACE_PENALTY, NULL); /* could be implemented in the future */ 01280 CONVERT(VIDFMT_YUV24, VIDFMT_YUYV, 1+RESOLUTION_PENALTY, &YUV24_to_YUYV); 01281 CONVERT(VIDFMT_YUV24, VIDFMT_UYVY, 1+RESOLUTION_PENALTY, &YUV24_to_UYVY); 01282 CONVERT(VIDFMT_YUV24, VIDFMT_YUV444, 1, &YUV24_to_YUV444); 01283 CONVERT(VIDFMT_YUV24, VIDFMT_YUV422, 1+RESOLUTION_PENALTY, &YUV24_to_YUV422); 01284 CONVERT(VIDFMT_YUV24, VIDFMT_YUV411, 1+RESOLUTION_PENALTY, &YUV24_to_YUV411); 01285 //CONVERT(VIDFMT_YUV24, VIDFMT_YUV420, 1+RESOLUTION_PENALTY, NULL); /* could be implemented in the future */ 01286 //CONVERT(VIDFMT_YUV24, VIDFMT_YUV410, 1+RESOLUTION_PENALTY, NULL); /* could be implemented in the future */ 01287 CONVERT(VIDFMT_YUV24, VIDFMT_YUV444P, 1, &YUV24_to_YUV444P); 01288 CONVERT(VIDFMT_YUV24, VIDFMT_YUV422P, 1+RESOLUTION_PENALTY, &YUV24_to_YUV422P); 01289 CONVERT(VIDFMT_YUV24, VIDFMT_YUV411P, 1+RESOLUTION_PENALTY, &YUV24_to_YUV411P); 01290 CONVERT(VIDFMT_YUV24, VIDFMT_YUV420P, 1+RESOLUTION_PENALTY, &YUV24_to_YUV420P); 01291 CONVERT(VIDFMT_YUV24, VIDFMT_YUV410P, 1+RESOLUTION_PENALTY, &YUV24_to_YUV410P); 01292 01293 #undef CONVERT 01294 } 01295 01296 namespace 01297 { 01298 struct Heap 01299 { 01300 int deletemin() 01301 { 01302 ASSERT(!h.empty()); 01303 01304 unsigned int best = h[0].second; 01305 size_t bestpos = 0; 01306 01307 for (size_t i = 1; i < h.size(); ++i) 01308 if (h[i].second < best) 01309 { 01310 best = h[i].second; 01311 bestpos = i; 01312 } 01313 01314 int result = h[bestpos].first; 01315 h.erase(h.begin() + bestpos); 01316 return result; 01317 } 01318 01319 void decreasekey(int v, unsigned int dist) 01320 { 01321 for (size_t i = 0; i < h.size(); ++i) 01322 if (h[i].first == v) 01323 { 01324 h[i].second = dist; 01325 return; 01326 } 01327 } 01328 01329 std::vector<std::pair<int, unsigned int> > h; 01330 }; 01331 } 01332 01333 void initIndirectConversions(VideoFormatCoercion table[VIDFMT_AUTO+1][VIDFMT_AUTO+1]) 01334 { 01335 // Dijkstra's shortest-path algorithm to find the optimal sequence 01336 // of atomic conversions to achieve an arbitrary coercion 01337 01338 for (int src = 0; src <= VIDFMT_AUTO; ++src) 01339 { 01340 unsigned int dist[VIDFMT_AUTO+1]; 01341 int prev[VIDFMT_AUTO+1]; 01342 01343 for (int u = 0; u <= VIDFMT_AUTO; ++u) 01344 { 01345 dist[u] = std::numeric_limits<unsigned int>::max(); 01346 prev[u] = -1; 01347 } 01348 dist[src] = 0; 01349 01350 Heap H; 01351 for (int u = 0; u <= VIDFMT_AUTO; ++u) 01352 if (u == src) 01353 H.h.push_back(std::make_pair(u, 0)); 01354 else if (table[src][u].isDirect()) 01355 H.h.push_back(std::make_pair(u, table[src][u].nodes[0].weight)); 01356 else 01357 H.h.push_back(std::make_pair(u, std::numeric_limits<unsigned int>::max())); 01358 01359 while (!H.h.empty()) 01360 { 01361 const int u = H.deletemin(); 01362 for (int v = 0; v <= VIDFMT_AUTO; ++v) 01363 { 01364 if (table[u][v].nodes.size() != 1) 01365 continue; 01366 01367 if (double(dist[v]) > double(dist[u]) + double(table[u][v].nodes[0].weight)) 01368 { 01369 dist[v] = dist[u] + table[u][v].nodes[0].weight; 01370 prev[v] = u; 01371 01372 H.decreasekey(v, dist[v]); 01373 } 01374 } 01375 } 01376 01377 for (int u = 0; u <= VIDFMT_AUTO; ++u) 01378 { 01379 if (u != src && prev[u] != -1) 01380 { 01381 VideoFormatCoercion p; 01382 int v = u; 01383 while (v != src) 01384 { 01385 ASSERT(table[prev[v]][v].isDirect()); 01386 p.nodes.push_front(table[prev[v]][v].nodes[0]); 01387 v = prev[v]; 01388 } 01389 01390 table[src][u] = p; 01391 } 01392 } 01393 } 01394 } 01395 01396 // ###################################################################### 01397 const VideoFormatCoercion& findConverter(const VideoFormat srcformat, 01398 const VideoFormat dstformat) 01399 { 01400 static bool inited = false; 01401 if (!inited) 01402 { 01403 initDirectConversions(pathtab); 01404 initIndirectConversions(pathtab); 01405 inited = true; 01406 } 01407 01408 ASSERT(srcformat >= 0); 01409 ASSERT(srcformat <= VIDFMT_AUTO); 01410 ASSERT(dstformat >= 0); 01411 ASSERT(dstformat <= VIDFMT_AUTO); 01412 01413 return pathtab[srcformat][dstformat]; 01414 } 01415 01416 // ###################################################################### 01417 VideoFrame coerceVideoFormat(const VideoFrame& src, 01418 const VideoFormat dstformat) 01419 { 01420 if (src.getMode() == dstformat) 01421 return src; 01422 01423 const VideoFormatCoercion& c = findConverter(src.getMode(), dstformat); 01424 01425 return c.apply(src); 01426 } 01427 01428 // ###################################################################### 01429 void printCoercionTable() 01430 { 01431 for (size_t n = 7; n-- > 0; ) 01432 { 01433 std::string line = sformat("%7s ", ""); 01434 01435 for (int i = 0; i <= VIDFMT_AUTO; ++i) 01436 { 01437 const std::string m = convertToString(VideoFormat(i)); 01438 if (n < m.size()) 01439 line += sformat(" %c", m[m.size() - 1 - n]); 01440 else 01441 line += " "; 01442 } 01443 01444 LINFO("%s", line.c_str()); 01445 } 01446 01447 { 01448 std::string line = sformat("%7s ", ""); 01449 for (int i = 0; i <= VIDFMT_AUTO; ++i) 01450 line += " -"; 01451 01452 LINFO("%s", line.c_str()); 01453 } 01454 01455 for (int i = 0; i <= VIDFMT_AUTO; ++i) 01456 { 01457 std::string line = 01458 sformat("%7s|", convertToString(VideoFormat(i)).c_str()); 01459 for (int j = 0; j <= VIDFMT_AUTO; ++j) 01460 if (i == j) 01461 line += " 0"; 01462 else 01463 { 01464 const VideoFormatCoercion& c = 01465 findConverter(VideoFormat(i), VideoFormat(j)); 01466 if (c.nodes.empty()) 01467 line += " ."; 01468 else 01469 line += sformat(" %d", int(c.nodes.size())); 01470 } 01471 01472 LINFO("%s", line.c_str()); 01473 } 01474 } 01475 01476 // ###################################################################### 01477 /* So things look consistent in everyone's emacs... */ 01478 /* Local Variables: */ 01479 /* mode: c++ */ 01480 /* indent-tabs-mode: nil */ 01481 /* End: */ 01482 01483 #endif // VIDEO_VIDEOFORMATCOERCION_C_DEFINED