00001 /*!@file Video/VideoFrame.C Handle generic video frames in a multitude of formats */ 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/VideoFrame.C $ 00035 // $Id: VideoFrame.C 12962 2010-03-06 02:13:53Z irock $ 00036 // 00037 00038 #ifndef VIDEO_VIDEOFRAME_C_DEFINED 00039 #define VIDEO_VIDEOFRAME_C_DEFINED 00040 00041 #include "Video/VideoFrame.H" 00042 00043 #include "Image/Image.H" 00044 #include "Image/Pixels.H" 00045 #include "Util/StringUtil.H" // for toLowerCase() 00046 #include "Util/log.H" 00047 #include "Util/sformat.H" 00048 #include "Video/RgbConversion.H" 00049 #include "rutz/mappedfile.h" 00050 #include "rutz/shared_ptr.h" 00051 #include "rutz/trace.h" 00052 #include "Raster/DeBayer.H" 00053 00054 #include <fcntl.h> 00055 #include <istream> 00056 #include <sys/mman.h> 00057 #include <sys/stat.h> 00058 #include <sys/types.h> 00059 #include <unistd.h> // for fsync() 00060 #include <vector> 00061 00062 // ###################################################################### 00063 namespace 00064 { 00065 void checkDataLength(const size_t actualLength, 00066 const VideoFormat mode, 00067 const Dims& dims, 00068 const bool strict) 00069 { 00070 const size_t expectedLength = getFrameSize(mode, dims); 00071 00072 if (actualLength == expectedLength) 00073 // OK, the data buffer is the right size: 00074 return; 00075 00076 //There is no way to know the jpeg's compression rate until we start 00077 //decompressing? 00078 if(mode == VIDFMT_MJPEG) return; 00079 00080 // OK, the actual buffer size doesn't match the expected buffer 00081 // size, so let's try to be helpful and guess some possible 00082 // matching widths and heights that we can suggest to the user 00083 00084 uint numer = 0, denom = 0; 00085 getBytesPerPixelForMode(mode, &numer, &denom); 00086 ASSERT(numer > 0); 00087 ASSERT(denom > 0); 00088 00089 const size_t numPix = (actualLength * denom) / numer; 00090 00091 const uint aspects[][2] = 00092 { 00093 // see http://en.wikipedia.org/wiki/Aspect_ratio_(image) for 00094 // other possible aspect ratios 00095 00096 { 4, 3 }, // standard TV 00097 { 16, 9 }, // HDTV 00098 { 1, 1 }, // square 00099 00100 // keep this terminal entry last 00101 { 0, 0 } 00102 }; 00103 00104 std::string suggestion; 00105 00106 for (size_t i = 0; aspects[i][0] > 0; ++i) 00107 { 00108 const uint aw = aspects[i][0]; 00109 const uint ah = aspects[i][1]; 00110 00111 // w*h = numPix 00112 // h = (w*ah)/aw 00113 00114 // w*(w*ah)/aw = numPix 00115 // w*(w*ah) = numPix*aw 00116 // w*w = (numPix*aw)/ah 00117 const uint wsq = (numPix*aw)/ah; 00118 00119 const uint w = uint(sqrt(double(wsq))); 00120 const uint h = (w*ah)/aw; 00121 00122 // LDEBUG("aw=%u, ah=%u, wsq=%u, w=%u, h=%u, w*w=%u, w*h=%u, numPix=%u", 00123 // aw, ah, wsq, w, h, w*w, w*h, (uint)numPix); 00124 00125 if (w*w == wsq && w*h == numPix) 00126 { 00127 if (suggestion.length() == 0) 00128 suggestion = "\n\tpossible matching frame sizes include:"; 00129 00130 suggestion += sformat("\n\t\t%ux%u (%ux%u aspect)", 00131 w, h, aw, ah); 00132 } 00133 } 00134 00135 if (actualLength < expectedLength) 00136 LFATAL("VideoFrame buffer is too small for %dx%d mode %s\n" 00137 "\t(expected %"ZU" bytes, got %"ZU" bytes)%s", 00138 dims.w(), dims.h(), convertToString(mode).c_str(), 00139 expectedLength, actualLength, suggestion.c_str()); 00140 00141 if (actualLength > expectedLength) 00142 { 00143 // NOTE: it's not necessarily a fatal error if actualLength is 00144 // larger than expectedLength; it might just mean we have some 00145 // unused space in the data buffer, though it might also mean 00146 // that the user has specified incorrect yuv dims (or perhaps 00147 // not specified them at all) 00148 const std::string msg = 00149 sformat("VideoFrame buffer is larger than expected for %dx%d mode %s\n" 00150 "\t(expected %"ZU" bytes, got %"ZU" bytes; you should\n" 00151 "\tdouble-check the width and height settings on your\n" 00152 "\tframegrabber, mpeg file, etc. or try --yuv-dims)%s", 00153 dims.w(), dims.h(), convertToString(mode).c_str(), 00154 expectedLength, actualLength, suggestion.c_str()); 00155 00156 if (strict) 00157 LFATAL("%s", msg.c_str()); 00158 else 00159 LDEBUG("%s", msg.c_str()); 00160 } 00161 } 00162 00163 template <class T> 00164 class ArrayHandleStorage : public VideoFrame::Storage 00165 { 00166 public: 00167 ArrayHandleStorage(const ArrayHandle<T>& hdl) : itsHdl(hdl) {} 00168 00169 virtual ~ArrayHandleStorage() {} 00170 00171 virtual Storage* clone() const 00172 { 00173 // copy-on-write in effect here 00174 return new ArrayHandleStorage<T>(this->itsHdl); 00175 } 00176 00177 ArrayHandle<T> itsHdl; 00178 }; 00179 00180 template <class T> 00181 class ImageStorage : public VideoFrame::Storage 00182 { 00183 public: 00184 ImageStorage(const Image<T>& img) : itsImg(img) {} 00185 00186 virtual ~ImageStorage() {} 00187 00188 virtual Storage* clone() const 00189 { 00190 // copy-on-write in effect here 00191 return new ImageStorage<T>(this->itsImg); 00192 } 00193 00194 Image<T> itsImg; 00195 }; 00196 00197 class MappedFileStorage : public VideoFrame::Storage 00198 { 00199 public: 00200 MappedFileStorage(rutz::shared_ptr<rutz::mapped_infile> f) : itsFile(f) {} 00201 00202 virtual ~MappedFileStorage() {} 00203 00204 virtual Storage* clone() const 00205 { 00206 return new MappedFileStorage(this->itsFile); 00207 } 00208 00209 rutz::shared_ptr<rutz::mapped_infile> itsFile; 00210 }; 00211 } 00212 00213 // ###################################################################### 00214 VideoFrame::Storage::~Storage() {} 00215 00216 // ###################################################################### 00217 VideoFrame::VideoFrame() 00218 : 00219 itsStorage(), 00220 itsData(0), 00221 itsDims(), 00222 itsMode(VIDFMT_AUTO), 00223 itsByteSwap(false) 00224 { 00225 GVX_TRACE(__PRETTY_FUNCTION__); 00226 } 00227 00228 // ###################################################################### 00229 VideoFrame::VideoFrame(const byte* data, const size_t length, const Dims& dims, 00230 const VideoFormat mode, const bool byteswap, 00231 const bool strictLength) 00232 : 00233 itsStorage(), // don't initialize this unless someone requests it 00234 itsData(data), 00235 itsDataLength(length), 00236 itsDims(dims), 00237 itsMode(mode), 00238 itsByteSwap(byteswap) 00239 { 00240 GVX_TRACE(__PRETTY_FUNCTION__); 00241 checkDataLength(itsDataLength, itsMode, itsDims, strictLength); 00242 } 00243 00244 00245 // ###################################################################### 00246 VideoFrame::VideoFrame(const ArrayHandle<byte>& hdl, const Dims& dims, 00247 const VideoFormat mode, const bool byteswap) 00248 : 00249 itsStorage(new ArrayHandleStorage<byte>(hdl)), 00250 itsData(hdl.get().data()), 00251 itsDataLength(hdl.get().dims().sz()), 00252 itsDims(dims), 00253 itsMode(mode), 00254 itsByteSwap(byteswap) 00255 { 00256 GVX_TRACE(__PRETTY_FUNCTION__); 00257 checkDataLength(itsDataLength, itsMode, itsDims, true); 00258 } 00259 00260 // ###################################################################### 00261 VideoFrame::VideoFrame(const Image<byte>& gray) 00262 : 00263 itsStorage(new ImageStorage<byte>(gray)), 00264 itsData(gray.getArrayPtr()), 00265 itsDataLength(gray.getSize() * sizeof(byte)), 00266 itsDims(gray.getDims()), 00267 itsMode(VIDFMT_GREY), 00268 itsByteSwap(false) 00269 { 00270 GVX_TRACE(__PRETTY_FUNCTION__); 00271 checkDataLength(itsDataLength, itsMode, itsDims, true); 00272 } 00273 00274 // ###################################################################### 00275 VideoFrame::VideoFrame(const Image<PixRGB<byte> >& rgb) 00276 : 00277 itsStorage(new ImageStorage<PixRGB<byte> >(rgb)), 00278 itsData(reinterpret_cast<const byte*>(rgb.getArrayPtr())), 00279 itsDataLength(rgb.getSize() * sizeof(PixRGB<byte>)), 00280 itsDims(rgb.getDims()), 00281 itsMode(VIDFMT_RGB24), 00282 itsByteSwap(false) 00283 { 00284 GVX_TRACE(__PRETTY_FUNCTION__); 00285 ASSERT(sizeof(PixRGB<byte>) == 3); 00286 checkDataLength(itsDataLength, itsMode, itsDims, true); 00287 } 00288 00289 // ###################################################################### 00290 VideoFrame::VideoFrame(const Image<PixVideoYUV<byte> >& yuv) 00291 : 00292 itsStorage(new ImageStorage<PixVideoYUV<byte> >(yuv)), 00293 itsData(reinterpret_cast<const byte*>(yuv.getArrayPtr())), 00294 itsDataLength(yuv.getSize() * sizeof(PixVideoYUV<byte>)), 00295 itsDims(yuv.getDims()), 00296 itsMode(VIDFMT_YUV24), 00297 itsByteSwap(false) 00298 { 00299 GVX_TRACE(__PRETTY_FUNCTION__); 00300 ASSERT(sizeof(PixVideoYUV<byte>) == 3); 00301 checkDataLength(itsDataLength, itsMode, itsDims, true); 00302 } 00303 00304 // ###################################################################### 00305 VideoFrame::~VideoFrame() 00306 { 00307 GVX_TRACE(__PRETTY_FUNCTION__); 00308 } 00309 00310 // ###################################################################### 00311 VideoFrame::VideoFrame(const VideoFrame& that) 00312 : 00313 itsStorage(that.itsStorage.get() 00314 ? that.itsStorage->clone() 00315 : 0), 00316 itsData(that.itsData), 00317 itsDataLength(that.itsDataLength), 00318 itsDims(that.itsDims), 00319 itsMode(that.itsMode), 00320 itsByteSwap(that.itsByteSwap) 00321 { 00322 GVX_TRACE(__PRETTY_FUNCTION__); 00323 } 00324 00325 // ###################################################################### 00326 VideoFrame& VideoFrame::operator=(const VideoFrame& that) 00327 { 00328 GVX_TRACE(__PRETTY_FUNCTION__); 00329 00330 itsStorage.reset(that.itsStorage.get() 00331 ? that.itsStorage->clone() 00332 : 0); 00333 itsData = that.itsData; 00334 itsDataLength = that.itsDataLength; 00335 itsDims = that.itsDims; 00336 itsMode = that.itsMode; 00337 itsByteSwap = that.itsByteSwap; 00338 00339 return *this; 00340 } 00341 00342 // ###################################################################### 00343 VideoFrame VideoFrame::fromFile(const char* fname, const Dims& dims, 00344 const VideoFormat mode, 00345 const bool byteswap, 00346 const bool strict) 00347 { 00348 rutz::shared_ptr<rutz::mapped_infile> fmap(new rutz::mapped_infile(fname)); 00349 00350 VideoFrame result; 00351 result.itsStorage.reset(new MappedFileStorage(fmap)); 00352 result.itsData = static_cast<const byte*>(fmap->memory()); 00353 result.itsDataLength = fmap->length(); 00354 result.itsDims = dims; 00355 result.itsMode = mode; 00356 result.itsByteSwap = byteswap; 00357 00358 checkDataLength(result.itsDataLength, result.itsMode, result.itsDims, 00359 strict); 00360 00361 return result; 00362 } 00363 00364 // ###################################################################### 00365 VideoFrame VideoFrame::fromStream(std::istream& strm, 00366 const Dims& dims, 00367 const VideoFormat mode, 00368 const bool byteswap, 00369 const bool fail_is_fatal) 00370 { 00371 const size_t sz = getFrameSize(mode, dims); 00372 00373 ArrayHandle<byte> data 00374 (new ArrayData<byte>(Dims(sz, 1), NO_INIT)); 00375 00376 strm.read(reinterpret_cast<char*>(data.uniq().dataw()), sz); 00377 00378 if (strm.fail()) 00379 { 00380 if (fail_is_fatal) 00381 LFATAL("error while reading data from input stream"); 00382 else 00383 return VideoFrame(); 00384 } 00385 00386 return VideoFrame(data, dims, mode, byteswap); 00387 } 00388 00389 // ###################################################################### 00390 VideoFrame VideoFrame::deepCopyOf(const VideoFrame& original) 00391 { 00392 GVX_TRACE(__PRETTY_FUNCTION__); 00393 00394 if (!original.initialized()) 00395 // original was an invalid (empty) frame, so just return another 00396 // empty frame as the result: 00397 return VideoFrame(); 00398 00399 if (original.itsStorage.get() != 0) 00400 // original already has a persistent copy of the data, so just 00401 // return a (copy-on-write) copy of that: 00402 return original; 00403 00404 // otherwise, make a fresh copy of original's data: 00405 00406 ArrayHandle<byte> newhdl 00407 (new ArrayData<byte>(Dims(original.getBufSize(), 1), 00408 original.itsData)); 00409 00410 return VideoFrame(newhdl, original.itsDims, original.itsMode, 00411 original.itsByteSwap); 00412 } 00413 00414 // ###################################################################### 00415 size_t VideoFrame::getBufSize() const 00416 { 00417 GVX_TRACE(__PRETTY_FUNCTION__); 00418 00419 const size_t expectedLength = getFrameSize(itsMode, itsDims); 00420 00421 if(expectedLength <= 0) return itsDataLength; 00422 00423 // This is a hard ASSERT, not an LFATAL, because we should have 00424 // already caught any size mismatch in the VideoFrame constructor, 00425 // so this ASSERT just serves as a double-check: 00426 ASSERT(itsDataLength >= expectedLength); 00427 00428 // NOTE: We return the expectedLength, even though itsDataLength may 00429 // be larger; that's because external clients should only count on 00430 // having expectedLength of space, and not more. 00431 00432 // Also make sure that we always return 0 if our data buffer is null 00433 // (otherwise callers would try to index into a null pointer) 00434 ASSERT(itsData != 0 || expectedLength == 0); 00435 00436 return expectedLength; 00437 } 00438 00439 // ###################################################################### 00440 namespace 00441 { 00442 void bobDeinterlace(const byte* src, const byte* const srcend, 00443 byte* dest, byte* const destend, 00444 const int height, const int stride, 00445 const bool in_bottom_field) 00446 { 00447 // NOTE: this deinterlacing code was derived from and/or inspired by 00448 // code from tvtime (http://tvtime.sourceforge.net/); original 00449 // copyright notice here: 00450 00451 /** 00452 * Copyright (c) 2001, 2002, 2003 Billy Biggs <vektor@dumbterm.net>. 00453 * 00454 * This program is free software; you can redistribute it and/or modify 00455 * it under the terms of the GNU General Public License as published by 00456 * the Free Software Foundation; either version 2, or (at your option) 00457 * any later version. 00458 * 00459 * This program is distributed in the hope that it will be useful, 00460 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00461 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00462 * GNU General Public License for more details. 00463 * 00464 * You should have received a copy of the GNU General Public License 00465 * along with this program; if not, write to the Free Software Foundation, 00466 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00467 */ 00468 00469 ASSERT(height > 0); 00470 ASSERT(stride > 0); 00471 00472 // NOTE: on x86 machines with glibc 2.3.6 and g++ 3.4.4, it looks 00473 // like std::copy is faster than memcpy, so we use that to do the 00474 // copying here: 00475 00476 #if 1 00477 # define DOCOPY(dst,src,n) std::copy((src),(src)+(n),(dst)) 00478 #else 00479 # define DOCOPY(dst,src,n) memcpy((dst),(src),(n)) 00480 #endif 00481 00482 if (in_bottom_field) 00483 { 00484 src += stride; 00485 00486 DOCOPY(dest, src, stride); 00487 00488 dest += stride; 00489 } 00490 00491 DOCOPY(dest, src, stride); 00492 00493 dest += stride; 00494 00495 const int N = (height / 2) - 1; 00496 for (int i = 0; i < N; ++i) 00497 { 00498 const byte* const src2 = src + (stride*2); 00499 00500 for (int k = 0; k < stride; ++k) 00501 dest[k] = (src[k] + src2[k]) / 2; 00502 00503 dest += stride; 00504 00505 DOCOPY(dest, src2, stride); 00506 00507 src += stride*2; 00508 dest += stride; 00509 } 00510 00511 if (!in_bottom_field) 00512 { 00513 DOCOPY(dest, src, stride); 00514 00515 src += stride*2; 00516 dest += stride; 00517 } 00518 else 00519 src += stride; 00520 00521 // consistency check: make sure we've done all our counting right: 00522 00523 if (src != srcend) 00524 LFATAL("deinterlacing consistency check failed: %d src %p-%p=%d", 00525 int(in_bottom_field), src, srcend, int(src-srcend)); 00526 00527 if (dest != destend) 00528 LFATAL("deinterlacing consistency check failed: %d dst %p-%p=%d", 00529 int(in_bottom_field), dest, destend, int(dest-destend)); 00530 } 00531 00532 #undef DOCOPY 00533 00534 } 00535 00536 // ###################################################################### 00537 VideoFrame VideoFrame::makeBobDeinterlaced(int in_bottom_field) const 00538 { 00539 GVX_TRACE(__PRETTY_FUNCTION__); 00540 00541 // Allocate a new memory area for storing the deinterlaced 00542 // frame. (Note, although it may seem expensive to allocate a new 00543 // buffer for every frame, in practice this is cheap because 00544 // ArrayData uses a caching allocator (invt_allocate(), see 00545 // Util/alloc.C) which caches commonly requested chunk sizes.) 00546 ArrayHandle<byte> hdl 00547 (new ArrayData<byte>(Dims(getFrameSize(itsMode, itsDims), 1), 00548 NO_INIT)); 00549 00550 byte* const dest = hdl.uniq().dataw(); 00551 const byte* const src = this->getBuffer(); 00552 const int w = this->getDims().w(); 00553 const int h = this->getDims().h(); 00554 const int stride = getScanlineWidth(this->getMode(), w); 00555 00556 if (stride > 0) 00557 { 00558 bobDeinterlace(src, src+h*stride, dest, dest+h*stride, 00559 h, stride, in_bottom_field); 00560 } 00561 else if (this->getMode() == VIDFMT_YUV420P) 00562 { 00563 // in this planar format, each plane is interlaced separately, 00564 // so we just deinterlace each separately as well: 00565 00566 // y plane: 00567 bobDeinterlace(src, src+w*h, dest, dest+w*h, 00568 h, w, in_bottom_field); 00569 00570 // we have to do (w+1)/2 instead of just w/2, because if 00571 // e.g. the y array has 5 pixels, then we want the u and v 00572 // arrays to have 3 pixels, not 2: 00573 const int w2 = (w+1)/2; 00574 const int h2 = (h+1)/2; 00575 00576 // u plane: 00577 bobDeinterlace(src + w*h, src + w*h + w2*h2, 00578 dest + w*h, dest + w*h + w2*h2, 00579 h2, w2, in_bottom_field); 00580 // v plane: 00581 bobDeinterlace(src + w*h + w2*h2, src + w*h + 2*w2*h2, 00582 dest + w*h + w2*h2, dest + w*h + 2*w2*h2, 00583 h2, w2, in_bottom_field); 00584 } 00585 00586 return VideoFrame(hdl, this->getDims(), this->getMode(), 00587 this->getByteSwap()); 00588 } 00589 00590 // ###################################################################### 00591 VideoFrame VideoFrame::getFlippedHoriz() const 00592 { 00593 GVX_TRACE(__PRETTY_FUNCTION__); 00594 00595 // this only works in YUV420P: 00596 if (this->getMode() != VIDFMT_YUV420P) 00597 LFATAL("Sorry, only VIDFMT_YUV420P is currently supported"); 00598 00599 // prepare a new frame: 00600 ArrayHandle<byte> hdl 00601 (new ArrayData<byte>(Dims(getFrameSize(itsMode, itsDims), 1), NO_INIT)); 00602 00603 byte* dest = hdl.uniq().dataw(); 00604 const byte* src = this->getBuffer(); 00605 const int w = this->getDims().w(); 00606 const int h = this->getDims().h(); 00607 00608 const byte *ysrc = src; 00609 const byte *usrc = ysrc + w * h; 00610 const byte *vsrc = usrc + ((w+1)/2) * ((h+1)/2); 00611 00612 // do the luminance: 00613 for (int j = 0; j < h; j ++) 00614 for (int i = 0; i < w; i ++) 00615 *dest++ = ysrc[(j+1)*w - i - 1]; 00616 00617 // do U and V: 00618 for (int j = 0; j < (h+1)/2; j ++) 00619 for (int i = 0; i < (w+1)/2; i ++) 00620 *dest++ = usrc[(j+1)*((w+1)/2) - i - 1]; 00621 00622 for (int j = 0; j < (h+1)/2; j ++) 00623 for (int i = 0; i < (w+1)/2; i ++) 00624 *dest++ = vsrc[(j+1)*((w+1)/2) - i - 1]; 00625 00626 return VideoFrame(hdl, this->getDims(), VIDFMT_YUV420P, this->getByteSwap()); 00627 } 00628 00629 // ###################################################################### 00630 namespace 00631 { 00632 std::string extensionFor(const Dims& dims, VideoFormat mode) 00633 { 00634 return sformat(".%dx%d.%s", 00635 dims.w(), dims.h(), 00636 toLowerCase(convertToString(mode)).c_str()); 00637 } 00638 00639 std::string addExtension(const char* fstem, 00640 const Dims& dims, VideoFormat mode) 00641 { 00642 const std::string ext = extensionFor(dims, mode); 00643 00644 std::string result(fstem); 00645 00646 if (result.size() < ext.size() || 00647 result.compare(result.size() - ext.size(), result.npos, 00648 ext) != 0) 00649 result += ext; 00650 00651 ASSERT(result.compare(result.size() - ext.size(), result.npos, 00652 ext) == 0); 00653 00654 return result; 00655 } 00656 } 00657 00658 // ###################################################################### 00659 std::string VideoFrame::diskDumpMmap(const char* fstem, bool flush) const 00660 { 00661 GVX_TRACE(__PRETTY_FUNCTION__); 00662 00663 const std::string fname = addExtension(fstem, itsDims, itsMode); 00664 00665 const int fd = 00666 open(fname.c_str(), 00667 O_CREAT | O_RDWR | O_TRUNC, 00668 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 00669 00670 if (fd == -1) 00671 PLFATAL("Cannot open %s for writing", fname.c_str()); 00672 00673 const size_t siz = this->getBufSize(); 00674 00675 if (siz != 0) 00676 { 00677 // seek to the desired file size and write a single byte 00678 // there, in order to force the file to be the right size 00679 lseek(fd, siz-1, SEEK_SET); 00680 int ret = write(fd, "", 1); 00681 ASSERT(ret > 0); 00682 lseek(fd, 0, SEEK_SET); 00683 00684 void* const mem = mmap(0, siz, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 00685 if (mem == MAP_FAILED) 00686 { close(fd); PLFATAL("mmap() failed for %s", fname.c_str()); } 00687 00688 memcpy(mem, this->getBuffer(), siz); 00689 00690 if (munmap(mem, siz) != 0) 00691 { close(fd); PLFATAL("munmap() failed for %s", fname.c_str()); } 00692 } 00693 00694 if (flush) 00695 fsync(fd); 00696 00697 close(fd); 00698 00699 return fname; 00700 } 00701 00702 // ###################################################################### 00703 std::string VideoFrame::diskDumpStdio(const char* fstem, bool flush) const 00704 { 00705 GVX_TRACE(__PRETTY_FUNCTION__); 00706 00707 const std::string fname = addExtension(fstem, itsDims, itsMode); 00708 00709 const int fd = 00710 open(fname.c_str(), 00711 O_CREAT | O_RDWR | O_TRUNC, 00712 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 00713 00714 if (fd == -1) 00715 PLFATAL("Cannot open %s for writing", fname.c_str()); 00716 00717 const size_t siz = this->getBufSize(); 00718 00719 if (write(fd, this->getBuffer(), siz) != ssize_t(siz)) 00720 { close(fd); PLFATAL("write() failed for %s", fname.c_str()); } 00721 00722 if (flush) 00723 fsync(fd); 00724 00725 close(fd); 00726 00727 return fname; 00728 } 00729 00730 // ###################################################################### 00731 Image<PixRGB<byte> > VideoFrame::toRgb() const 00732 { 00733 GVX_TRACE(__PRETTY_FUNCTION__); 00734 00735 if (itsData == 0) 00736 LFATAL("Eeek! I have no data!"); 00737 00738 // short names so the switch statement below fits nicely :-) 00739 00740 const byte* d = itsData; 00741 const size_t s = this->getBufSize(); 00742 const Dims m = itsDims; 00743 const bool p = itsByteSwap; 00744 00745 switch (itsMode) 00746 { 00747 case VIDFMT_GREY: return fromMono (d,s,m); 00748 case VIDFMT_RGB555: return fromRGB555 (d,s,m,p); 00749 case VIDFMT_RGB565: return fromRGB565 (d,s,m,p); 00750 case VIDFMT_RGB24: return fromRGB (d,s,m,p); 00751 case VIDFMT_RGB32: return fromARGB (d,s,m,p); 00752 case VIDFMT_YUV24: return fromVideoYUV24 (d,s,m,p); 00753 case VIDFMT_UYVY: return fromVideoYUV422 (d,s,m,p); // same as YUV422 00754 case VIDFMT_YUYV: return fromVideoYUV422 (d,s,m,!p); // same as YUV422 00755 case VIDFMT_YUV444: return fromVideoYUV444 (d,s,m,p); 00756 case VIDFMT_YUV422: return fromVideoYUV422 (d,s,m,p); 00757 case VIDFMT_YUV411: return fromVideoYUV411 (d,s,m,p); 00758 case VIDFMT_YUV420: return fromVideoYUV420P (d,s,m); // same as YUV420P? 00759 case VIDFMT_YUV410: return fromVideoYUV410P (d,s,m); // same as YUV410P? 00760 case VIDFMT_YUV444P: return fromVideoYUV444P (d,s,m); 00761 case VIDFMT_YUV422P: return fromVideoYUV422P (d,s,m); 00762 case VIDFMT_YUV411P: return fromVideoYUV411P (d,s,m); 00763 case VIDFMT_YUV420P: return fromVideoYUV420P (d,s,m); 00764 case VIDFMT_YUV410P: return fromVideoYUV410P (d,s,m); 00765 case VIDFMT_HM12: return fromVideoHM12 (d,s,m); 00766 case VIDFMT_MJPEG: return fromVideoMJPEG (d,s,m); 00767 case VIDFMT_BAYER_GB: return fromBayer(d,s,m, BAYER_GBRG); 00768 case VIDFMT_BAYER_BG: return fromBayer(d,s,m, BAYER_BGGR); 00769 case VIDFMT_BAYER_GR: return fromBayer(d,s,m, BAYER_GRBG); 00770 case VIDFMT_BAYER_RG: return fromBayer(d,s,m, BAYER_RGGB); 00771 default: 00772 LFATAL("Sorry, conversion from selected grabmode to RGB not implemented!"); 00773 } 00774 /* can't happen */ return Image< PixRGB<byte> >(); 00775 } 00776 00777 // ###################################################################### 00778 Image<PixRGB<uint16> > VideoFrame::toRgbU16() const 00779 { 00780 GVX_TRACE(__PRETTY_FUNCTION__); 00781 00782 if (itsData == 0) 00783 LFATAL("Eeek! I have no data!"); 00784 00785 // short names so the switch statement below fits nicely :-) 00786 00787 const uint16* d = (uint16*)itsData; 00788 //const unsigned short* d = (unsigned short*)itsData; 00789 const size_t s = this->getBufSize(); 00790 const Dims m = itsDims; 00791 00792 switch (itsMode) 00793 { 00794 case VIDFMT_BAYER_GB12: return fromBayerU16 (d,s,m, BAYER_GBRG12); 00795 case VIDFMT_BAYER_BG12: return fromBayerU16 (d,s,m, BAYER_BGGR12); 00796 case VIDFMT_BAYER_GR12: return fromBayerU16 (d,s,m, BAYER_GRBG12); 00797 case VIDFMT_BAYER_RG12: return fromBayerU16 (d,s,m, BAYER_RGGB12); 00798 default: 00799 LFATAL("Sorry, conversion from selected grabmode to RGB not implemented!"); 00800 } 00801 /* can't happen */ return Image< PixRGB<uint16> >(); 00802 } 00803 00804 // ###################################################################### 00805 void VideoFrame::toYuvComponents(Image<byte>& y, 00806 Image<byte>& u, 00807 Image<byte>& v) const 00808 { 00809 const byte* buf = this->getBuffer(); 00810 const Dims dims = this->getDims(); 00811 00812 switch (this->getMode()) 00813 { 00814 case VIDFMT_YUV420P: 00815 y = Image<byte>(buf, dims); 00816 u = Image<byte>(buf + dims.sz(), (dims + 1) / 2); 00817 v = Image<byte>(buf + dims.sz() + ((dims + 1) / 2).sz(), 00818 (dims + 1) / 2); 00819 break; 00820 00821 // FIXME add code here for other YUV VideoFormat modes 00822 00823 default: 00824 LFATAL("toYuvComponents() not supported for VideoFormat %s", 00825 convertToString(this->getMode()).c_str()); 00826 } 00827 } 00828 00829 // ###################################################################### 00830 /* So things look consistent in everyone's emacs... */ 00831 /* Local Variables: */ 00832 /* mode: c++ */ 00833 /* indent-tabs-mode: nil */ 00834 /* End: */ 00835 00836 #endif // VIDEO_VIDEOFRAME_C_DEFINED