videograb.C

00001 /*!@file AppPsycho/videograb.C grab frames and save them to disk */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00005 // 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: Laurent Itti <itti@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppGUI/videograb.C $
00035 // $Id: videograb.C 9816 2008-06-17 01:42:47Z ilab24 $
00036 //
00037 
00038 #include "Component/ModelManager.H"
00039 #include "Devices/FrameGrabberConfigurator.H"
00040 #include "Image/DrawOps.H"
00041 #include "Image/Image.H"
00042 #include "Image/Image.H"
00043 #include "Image/ImageCache.H"
00044 #include "Image/Pixels.H"
00045 #include "GUI/SDLdisplay.H"
00046 #include "GUI/GUIOpts.H"
00047 #include "Raster/Raster.H"
00048 #include "Transport/FrameIstream.H"
00049 #include "Util/Timer.H"
00050 #include "Util/log.H"
00051 #include "Util/sformat.H"
00052 #include "Video/RgbConversion.H" // for toVideoYUV422()
00053 
00054 #include <pthread.h>
00055 
00056 //! number of frames over which frame rate is computed
00057 #define NAVG 20
00058 
00059 //! Maximum number of frames in queue
00060 #define MAXQLEN 1000
00061 
00062 pthread_mutex_t qmutex;
00063 ImageCache< PixRGB<byte> > cache;
00064 std::vector<std::string> base;
00065 
00066 static void* saveframes(void *)
00067 {
00068   uint fnb = 0;
00069   while(1) {
00070     Image< PixRGB<byte> > ima; bool havemore = false;
00071 
00072     // do we have images ready to go?
00073     pthread_mutex_lock(&qmutex);
00074     if (cache.size()) ima = cache.pop_front();
00075     if (cache.size()) havemore = true;
00076     pthread_mutex_unlock(&qmutex);
00077 
00078     // if we got an image, save it:
00079     if (ima.initialized())
00080       {
00081         // we save each frame to a different base in a rolling manner:
00082         const char *b = base[fnb % base.size()].c_str();
00083         Raster::WriteRGB(ima, sformat("%s%06u.ppm", b, fnb++));
00084       }
00085 
00086     if (havemore == false) usleep(1000);
00087   }
00088   return NULL;
00089 }
00090 
00091 
00092 /*! This simple executable grabs video frames through the video4linux
00093   driver (see V4Lgrabber.H) or the IEEE1394 (firewire) grabber (see
00094   IEEE1394grabber.H). Selection of the grabber type is made via the
00095   --fg-type=XX command-line option. Frames are pushed into a queue and
00096   a second thread then tries to empty the queue as quickly as possible
00097   by writing the frames to disk. In testing, PPM format actually gave
00098   better frame rates than PNG, so that's what is used.  Press <SPACE>
00099   to start grabbing and <SPACE> again to stop. */
00100 static int submain(const int argc, char** argv)
00101 {
00102   // instantiate a model manager:
00103   ModelManager manager("Frame Grabber");
00104 
00105   // Instantiate our various ModelComponents:
00106   nub::soft_ref<FrameGrabberConfigurator>
00107     gbc(new FrameGrabberConfigurator(manager));
00108   manager.addSubComponent(gbc);
00109 
00110   nub::soft_ref<SDLdisplay> d(new SDLdisplay(manager));
00111   manager.addSubComponent(d);
00112 
00113   manager.setOptionValString(&OPT_SDLdisplayPriority, "0");
00114 
00115   // Parse command-line:
00116   if (manager.parseCommandLine(argc, argv, "<basename> ... <basename>",
00117                                1, -1) == false)
00118     return(1);
00119 
00120   // do post-command-line configs:
00121   nub::soft_ref<FrameIstream> gb = gbc->getFrameGrabber();
00122   if (gb.isInvalid())
00123     LFATAL("You need to select a frame grabber type via the "
00124            "--fg-type=XX command-line option for this program "
00125            "to be useful");
00126 
00127   // get the basename:
00128   for (uint i = 0; i < manager.numExtraArgs(); i ++)
00129     base.push_back(manager.getExtraArg(i));
00130 
00131   // let's get all our ModelComponent instances started:
00132   manager.start();
00133 
00134   // get ready for main loop:
00135   Timer tim; uint64 t[NAVG]; int frame = 0;
00136   d->clearScreen(PixRGB<byte>(128)); bool doit = true;
00137 
00138   int iw = gb->getWidth(), ih = gb->getHeight();
00139   int dw = d->getDims().w(), dh = d->getDims().h();
00140   if (iw > dw || ih > dh)
00141     {
00142       LERROR("Grab frame size must be smaller than display size");
00143       doit = false;
00144     }
00145 
00146   int ovlyoff = (dw - iw) / 2 + dw * ((dh - ih) / 2);
00147   int ovluvoff = (dw - iw) / 4 + dw * ((dh - ih) / 8);
00148   int ystride = (dw - iw), uvstride = (dw - iw) / 2;
00149   bool saving = false; float frate = 0.0f;
00150   pthread_t saver;
00151   pthread_create(&saver, NULL, &saveframes, (void *)NULL);
00152 
00153   // create an overlay:
00154   d->createYUVoverlay(SDL_YV12_OVERLAY);
00155 
00156   // get the frame grabber to start streaming:
00157   gb->startStream();
00158 
00159   // main loop:
00160   while(doit) {
00161     tim.reset();
00162 
00163     // grab a frame:
00164     Image< PixRGB<byte> > ima = gb->readRGB();
00165 
00166     // to measure display time:
00167     uint64 t0 = tim.get();
00168 
00169     // if saving, push image into queue:
00170     if (saving)
00171       {
00172         pthread_mutex_lock(&qmutex);
00173         cache.push_back(ima);
00174         pthread_mutex_unlock(&qmutex);
00175         const std::string msg = sformat(" %.1ffps [%04d] ", frate, cache.size());
00176         writeText(ima, Point2D<int>(0, 0), msg.c_str(), PixRGB<byte>(255), PixRGB<byte>(0));
00177       }
00178     else // tell user we are ready to save
00179       {
00180         const std::string msg = sformat(" [SPC] to save [%04d] ", cache.size());
00181         writeText(ima, Point2D<int>(0, 0), msg.c_str(), PixRGB<byte>(255), PixRGB<byte>(0));
00182       }
00183 
00184     // show the frame:
00185     SDL_Overlay* ovl = d->lockYUVoverlay();
00186     toVideoYUV422(ima, ovl->pixels[0] + ovlyoff,
00187                   ovl->pixels[2] + ovluvoff,
00188                   ovl->pixels[1] + ovluvoff,
00189              ystride, uvstride, uvstride);
00190     d->unlockYUVoverlay();
00191     d->displayYUVoverlay(-1, SDLdisplay::NO_WAIT);
00192 
00193     // check for space bar pressed; note: will abort us violently if
00194     // ESC is pressed instead:
00195     if (d->checkForKey() == ' ') saving = ! saving;
00196 
00197     t[frame % NAVG] = tim.get();
00198     t0 = t[frame % NAVG] - t0;
00199     if (t0 > 20000ULL) LINFO("Display took %lluus", t0);
00200 
00201     // compute and show framerate over the last NAVG frames:
00202     if (frame % NAVG == 0 && frame > 0)
00203       {
00204         uint64 avg = 0ULL; for (int i = 0; i < NAVG; i ++) avg += t[i];
00205         frate = 1000.0F / float(avg) * float(NAVG);
00206       }
00207     frame ++;
00208   }
00209 
00210   // stop all our ModelComponents
00211   d->destroyYUVoverlay();
00212   manager.stop();
00213 
00214   // all done!
00215   return 0;
00216 }
00217 
00218 extern "C" int main(const int argc, char** argv)
00219 {
00220   try
00221     {
00222       return submain(argc, argv);
00223     }
00224   catch (...)
00225     {
00226       REPORT_CURRENT_EXCEPTION;
00227     }
00228 
00229   return 1;
00230 }
00231 
00232 // ######################################################################
00233 /* So things look consistent in everyone's emacs... */
00234 /* Local Variables: */
00235 /* indent-tabs-mode: nil */
00236 /* End: */
Generated on Sun May 8 08:40:07 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3