VideoFrame.C

Go to the documentation of this file.
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
Generated on Sun May 8 08:42:37 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3