V4L2grabber.C

Go to the documentation of this file.
00001 /*!@file Devices/V4L2grabber.C Interface with a video4linux2 frame grabber */
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/Devices/V4L2grabber.C $
00035 // $Id: V4L2grabber.C 14753 2011-04-27 23:11:33Z itti $
00036 //
00037 
00038 #ifdef HAVE_LINUX_VIDEODEV2_H
00039 
00040 #include "Devices/V4L2grabber.H"
00041 
00042 #include "Component/OptionManager.H" // for option alias requests
00043 #include "Component/ModelOptionDef.H"
00044 #include "Devices/DeviceOpts.H"
00045 #include "Image/ColorOps.H"
00046 #include "Raster/GenericFrame.H"
00047 #include "Util/Assert.H"
00048 #include "Util/log.H"
00049 #include "Util/sformat.H"
00050 #include "Video/VideoFrame.H"
00051 
00052 #include <cerrno>
00053 #include <fcntl.h>
00054 #include <sys/ioctl.h>
00055 #include <sys/mman.h>
00056 #include <sys/stat.h>
00057 #include <unistd.h>
00058 
00059 //! for id-logging; see log.H:
00060 #define MYLOGID itsFd
00061 
00062 namespace
00063 {
00064   struct V4L2Palette
00065   {
00066     VideoFormat vidformat;
00067     uint32 v4l2format; // V4L2_PIX_FMT_...
00068   };
00069 
00070   const V4L2Palette v4l2tab[VIDFMT_AUTO] =
00071     {
00072       { VIDFMT_GREY    , V4L2_PIX_FMT_GREY },
00073       { VIDFMT_RGB555  , V4L2_PIX_FMT_RGB555 },
00074       { VIDFMT_RGB565  , V4L2_PIX_FMT_RGB565 },
00075       { VIDFMT_RGB24   , V4L2_PIX_FMT_BGR24 },
00076       { VIDFMT_RGB32   , V4L2_PIX_FMT_BGR32 },
00077       { VIDFMT_YUYV    , V4L2_PIX_FMT_YUYV },
00078       { VIDFMT_UYVY    , V4L2_PIX_FMT_UYVY },
00079       { VIDFMT_YUV422  , V4L2_PIX_FMT_UYVY },
00080       { VIDFMT_YUV411  , V4L2_PIX_FMT_Y41P },
00081       { VIDFMT_YUV420  , V4L2_PIX_FMT_YUV420 },
00082       { VIDFMT_YUV410  , V4L2_PIX_FMT_YUV410 },
00083       { VIDFMT_YUV422P , V4L2_PIX_FMT_YUV422P },
00084       { VIDFMT_YUV411P , V4L2_PIX_FMT_YUV411P },
00085       { VIDFMT_YUV420P , V4L2_PIX_FMT_YUV420 },
00086       { VIDFMT_YUV410P , V4L2_PIX_FMT_YUV410 },
00087       { VIDFMT_MJPEG   , V4L2_PIX_FMT_MJPEG },
00088       { VIDFMT_HM12    , V4L2_PIX_FMT_HM12 }
00089     };
00090 
00091   //! Mapping between our VideoFormat and V4L2 pixfmt:
00092   // See Video/VideoFormat.H
00093   uint32 VideoFormat_to_V4L2Format(const VideoFormat vidformat)
00094   {
00095     for (size_t i = 0; i < sizeof(v4l2tab) / sizeof(v4l2tab[0]); ++i)
00096       if (vidformat == v4l2tab[i].vidformat)
00097         return v4l2tab[i].v4l2format;
00098 
00099     // not found
00100     return 0xffffffff;
00101   }
00102 
00103   VideoFormat V4L2Format_to_VideoFormat(const uint32 v4l2format)
00104   {
00105     for (size_t i = 0; i < sizeof(v4l2tab) / sizeof(v4l2tab[0]); ++i)
00106       if (v4l2format == v4l2tab[i].v4l2format)
00107         return v4l2tab[i].vidformat;
00108 
00109     // not found
00110     return VIDFMT_AUTO;
00111   }
00112 
00113   int ioctl_nointr(int d, int req, void* mem)
00114   {
00115     int result = 0;
00116     do { result = ioctl(d, req, mem); }
00117     while ((result < 0) && (errno == EINTR));
00118     return result;
00119   }
00120 
00121   // mapping of V4L2 controls to our command-line options:
00122   struct ControlMapping {
00123     uint v4l2;
00124     const ModelOptionDef *opt;
00125   };
00126 
00127   // see here for definitions: http://v4l2spec.bytesex.org/spec/x542.htm
00128   ControlMapping controlmapping[] = {
00129     // standard controls, in V4L2_CID_USER_CLASS
00130     { V4L2_CID_BRIGHTNESS, &OPT_FrameGrabberBrightness },
00131     { V4L2_CID_CONTRAST, &OPT_FrameGrabberContrast },
00132     { V4L2_CID_SATURATION, &OPT_FrameGrabberSaturation },
00133     { V4L2_CID_HUE, &OPT_FrameGrabberHue },
00134     { V4L2_CID_AUDIO_VOLUME, &OPT_FrameGrabberAudioVolume },
00135     { V4L2_CID_AUDIO_BALANCE, &OPT_FrameGrabberAudioBalance },
00136     { V4L2_CID_AUDIO_BASS, &OPT_FrameGrabberAudioBass },
00137     { V4L2_CID_AUDIO_TREBLE, &OPT_FrameGrabberAudioTreble },
00138     { V4L2_CID_AUDIO_MUTE, &OPT_FrameGrabberAudioMute },
00139     { V4L2_CID_AUDIO_LOUDNESS, &OPT_FrameGrabberAudioLoudness },
00140     { V4L2_CID_AUTO_WHITE_BALANCE, &OPT_FrameGrabberWhiteBalTempAuto }, // ??
00141     { V4L2_CID_DO_WHITE_BALANCE, &OPT_FrameGrabberDoWhiteBal },
00142     { V4L2_CID_RED_BALANCE, &OPT_FrameGrabberWhiteBalBU }, //?
00143     { V4L2_CID_BLUE_BALANCE, &OPT_FrameGrabberWhiteBalRV }, //?
00144     { V4L2_CID_GAMMA, &OPT_FrameGrabberGamma },
00145     { V4L2_CID_EXPOSURE, &OPT_FrameGrabberExposure },
00146     { V4L2_CID_AUTOGAIN, &OPT_FrameGrabberAutoGain },
00147     { V4L2_CID_GAIN, &OPT_FrameGrabberGain },
00148     { V4L2_CID_HFLIP, &OPT_FrameGrabberHFlip },
00149     { V4L2_CID_VFLIP, &OPT_FrameGrabberVFlip },
00150     { V4L2_CID_POWER_LINE_FREQUENCY, &OPT_FrameGrabberPowerLineFreq },
00151     { V4L2_CID_HUE_AUTO, &OPT_FrameGrabberHueAuto },
00152     { V4L2_CID_WHITE_BALANCE_TEMPERATURE, &OPT_FrameGrabberWhiteBalTemp },
00153     { V4L2_CID_SHARPNESS, &OPT_FrameGrabberSharpness },
00154     { V4L2_CID_BACKLIGHT_COMPENSATION, &OPT_FrameGrabberBacklightComp },
00155     { V4L2_CID_CHROMA_AGC, NULL }, //FIXME
00156     { V4L2_CID_COLOR_KILLER, NULL }, //FIXME
00157 
00158 #ifdef V4L2_CID_COLORFX
00159     { V4L2_CID_COLORFX, NULL }, //FIXME
00160 #endif
00161 
00162 #ifdef V4L2_CID_AUTOBRIGHTNESS
00163     { V4L2_CID_AUTOBRIGHTNESS, NULL }, //FIXME
00164 #endif
00165 
00166 #ifdef V4L2_CID_BAND_STOP_FILTER
00167     { V4L2_CID_BAND_STOP_FILTER, NULL }, //FIXME
00168 #endif
00169 
00170     // extended controls in V4L2_CID_CAMERA_CLASS
00171     { V4L2_CID_EXPOSURE_AUTO, &OPT_FrameGrabberExposureMode },
00172     { V4L2_CID_EXPOSURE_ABSOLUTE, &OPT_FrameGrabberExposureAbs },
00173     { V4L2_CID_EXPOSURE_AUTO_PRIORITY, &OPT_FrameGrabberExposureAutoPri },
00174     { V4L2_CID_PAN_RELATIVE, NULL }, //FIXME
00175     { V4L2_CID_TILT_RELATIVE, NULL }, //FIXME
00176     { V4L2_CID_PAN_RESET, NULL }, //FIXME
00177     { V4L2_CID_TILT_RESET, NULL }, //FIXME
00178     { V4L2_CID_PAN_ABSOLUTE, NULL }, //FIXME
00179     { V4L2_CID_TILT_ABSOLUTE, NULL }, //FIXME
00180     { V4L2_CID_FOCUS_ABSOLUTE, &OPT_FrameGrabberFocus },
00181     { V4L2_CID_FOCUS_RELATIVE, NULL }, //FIXME
00182     { V4L2_CID_FOCUS_AUTO, &OPT_FrameGrabberFocusAuto },
00183     { V4L2_CID_ZOOM_ABSOLUTE, &OPT_FrameGrabberZoom },
00184     { V4L2_CID_ZOOM_RELATIVE, NULL }, //FIXME
00185     { V4L2_CID_ZOOM_CONTINUOUS, NULL }, //FIXME
00186     { V4L2_CID_PRIVACY, NULL }, //FIXME
00187 
00188     { -1, NULL } // keep this as the last entry
00189   };
00190 
00191 } // namespace
00192 
00193 // ######################################################################
00194 V4L2grabber::V4L2grabber(OptionManager& mgr, const std::string& descrName,
00195                          const std::string& tagName, const ParamFlag flags) :
00196   FrameIstream(mgr, descrName, tagName),
00197   // NOTE that contrary to the common case, we may give (by default
00198   // value of 'flags') USE_MY_VAL here when we construct the
00199   // OModelParam objects; that means that we push our values into the
00200   // ModelManager as the new default values, rather than having our
00201   // param take its value from the ModelManager's default
00202   itsDevName(&OPT_FrameGrabberDevice, this, "/dev/video0", flags),
00203   itsChannel(&OPT_FrameGrabberChannel, this, 1, flags | ALLOW_ONLINE_CHANGES),
00204   itsDims(&OPT_FrameGrabberDims, this, Dims(320, 240), flags),
00205   itsGrabMode(&OPT_FrameGrabberMode, this, VIDFMT_RGB24, flags),
00206   itsByteSwap(&OPT_FrameGrabberByteSwap, this, true, flags),
00207   itsStreamingMode(&OPT_FrameGrabberStreaming, this),
00208   itsNbuf(&OPT_FrameGrabberNbuf, this, 4, flags),
00209   itsFd(-1),
00210   itsMmapBuf(NULL),
00211   itsMmapBufSize(NULL),
00212   itsReadBuf(),
00213   itsCurrentFrame(0),
00214   itsGrabbing(NULL),
00215   itsFrameTime(SimTime::ZERO()),
00216   itsListener(),
00217   itsStreamStarted(false),
00218   itsCanMMap(false),
00219   itsCanRW(false),
00220   itsOptionFlags(flags)
00221 {
00222   openDevice();
00223 
00224   // request a bunch of camera aliases which work with V4L2:
00225   mgr.requestOptionAlias(&OPT_ALIAScamBttv);
00226   mgr.requestOptionAlias(&OPT_ALIAScamMacbook);
00227   mgr.requestOptionAlias(&OPT_ALIAScamLifeCam);
00228   mgr.requestOptionAlias(&OPT_ALIAScamLifeCamManual);
00229   mgr.requestOptionAlias(&OPT_ALIAScamHPpremAF);
00230   mgr.requestOptionAlias(&OPT_ALIAScamHPpremAFmanual);
00231   mgr.requestOptionAlias(&OPT_ALIAScamC910);
00232   mgr.requestOptionAlias(&OPT_ALIAScamC910manual);
00233   mgr.requestOptionAlias(&OPT_ALIAScamC910turntable);
00234 }
00235 
00236 // ######################################################################
00237 void V4L2grabber::openDevice()
00238 {
00239   if (itsFd != -1) closeDevice();
00240 
00241   itsFd = open(itsDevName.getVal().c_str(), O_RDWR);
00242   // since we will be called upon construction of the grabber with whichever default device name, do not LFATAL here if
00243   // the device does not open. We may be called again with a different device name if that name is changed at the
00244   // command line. In the end, during start1() we will check that the final selected device did open and that it has the
00245   // right capabilities (itsCanRW or itsCanMMap at the minimum):
00246   if (itsFd == -1) { PLERROR("Failed to open V4L2 device %s", itsDevName.getVal().c_str()); return; }
00247 
00248   LINFO("Opened V4L2 device named: %s", itsDevName.getVal().c_str());
00249 
00250   // get frame grabber capabilities:
00251   struct v4l2_capability vc; itsCanRW = false; itsCanMMap = false;
00252   if (ioctl_nointr(itsFd, VIDIOC_QUERYCAP, &vc) < 0) IDPLFATAL("Cannot get V4L2 device capabilities");
00253   IDLINFO("V4L2 kernel driver: %s", vc.driver);
00254   IDLINFO("FrameGrabber board name is: %s", vc.card);
00255   IDLINFO("FrameGrabber board bus info: %s", vc.bus_info);
00256 
00257   // note: these defs from /usr/include/linux/videodev2.h as of kernel 2.6.32, some may not be defined in older kernels
00258   // and should then be commented out:
00259   if (vc.capabilities & V4L2_CAP_VIDEO_CAPTURE) IDLINFO("    > Supports video capture");
00260   else IDLFATAL("Not a video capture device.");
00261   if (vc.capabilities & V4L2_CAP_VIDEO_OUTPUT) IDLINFO("    > Supports video output");
00262   if (vc.capabilities & V4L2_CAP_VIDEO_OVERLAY) IDLINFO("    > Supports video overlay");
00263   if (vc.capabilities & V4L2_CAP_VBI_CAPTURE) IDLINFO("    > Supports raw VBI capture");
00264   if (vc.capabilities & V4L2_CAP_VBI_OUTPUT) IDLINFO("    > Supports raw VBI output");
00265   if (vc.capabilities & V4L2_CAP_SLICED_VBI_CAPTURE) IDLINFO("    > Supports sliced VBI capture");
00266   if (vc.capabilities & V4L2_CAP_SLICED_VBI_OUTPUT) IDLINFO("    > Supports sliced VBI_OUTPUT");
00267   if (vc.capabilities & V4L2_CAP_RDS_CAPTURE) IDLINFO("    > Supports RDS capture");
00268   if (vc.capabilities & V4L2_CAP_VIDEO_OUTPUT_OVERLAY) IDLINFO("    > Supports video output overlay");
00269   if (vc.capabilities & V4L2_CAP_HW_FREQ_SEEK) IDLINFO("    > Supports hardware frequency seek");
00270 #ifdef V4L2_CAP_RDS_OUTPUT
00271   if (vc.capabilities & V4L2_CAP_RDS_OUTPUT) IDLINFO("    > Supports RDS output");
00272 #endif
00273   if (vc.capabilities & V4L2_CAP_TUNER) IDLINFO("    > Has an RF tuner and/or modulator");
00274   if (vc.capabilities & V4L2_CAP_AUDIO) IDLINFO("    > Supports audio input and/or output");
00275   if (vc.capabilities & V4L2_CAP_RADIO) IDLINFO("    > Supports radio");
00276 #ifdef V4L2_CAP_MODULATOR
00277   if (vc.capabilities & V4L2_CAP_MODULATOR) IDLINFO("    > Supports a modulator");
00278 #endif
00279 
00280   if (vc.capabilities & V4L2_CAP_READWRITE) { IDLINFO("    > Supports read/write I/O method"); itsCanRW = true; }
00281   else itsCanRW = false;
00282   if (vc.capabilities & V4L2_CAP_ASYNCIO) IDLINFO("    > Supports asynchronous I/O method");
00283   if (vc.capabilities & V4L2_CAP_STREAMING) { IDLINFO("    > Supports streaming I/O (MMAP) method"); itsCanMMap=true; }
00284   else itsCanMMap = false;
00285 
00286   // List available controls and their current settings. First try to do this using the new method, for devices that
00287   // support the new extended controls API. If that fails we will fall back to the older method for standard controls:
00288   struct v4l2_queryctrl ctrl; memset(&ctrl, 0, sizeof(ctrl)); ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
00289 
00290   if (ioctl_nointr(itsFd, VIDIOC_QUERYCTRL, &ctrl) == 0) {
00291     IDLINFO("    > Supports Extended Controls API");
00292     do {
00293       // add a command-line option for the control, and describe it:
00294       addControl(ctrl);
00295 
00296       // get ready to query the next control:
00297       ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
00298     } while (ioctl_nointr(itsFd, VIDIOC_QUERYCTRL, &ctrl) == 0);
00299 
00300     // on some cameras (e.g., Microsoft LifeCam), we just got all the controls and we are done. On others, more controls
00301     // are available by excplicitly setting the class (e.g., HP Premium AF). So let's try that too, addControl() will
00302     // need to make sure we don't try to add a control twice:
00303     memset(&ctrl, 0, sizeof(ctrl)); ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_CLASS_MPEG;
00304     if (ioctl_nointr(itsFd, VIDIOC_QUERYCTRL, &ctrl) == 0)
00305       do { addControl(ctrl); ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; }
00306       while (ioctl_nointr(itsFd, VIDIOC_QUERYCTRL, &ctrl) == 0);
00307 
00308     memset(&ctrl, 0, sizeof(ctrl)); ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_CLASS_CAMERA;
00309     if (ioctl_nointr(itsFd, VIDIOC_QUERYCTRL, &ctrl) == 0)
00310       do { addControl(ctrl); ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; }
00311       while (ioctl_nointr(itsFd, VIDIOC_QUERYCTRL, &ctrl) == 0);
00312 
00313 #ifdef V4L2_CTRL_CLASS_FM_TX
00314     memset(&ctrl, 0, sizeof(ctrl)); ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_CLASS_FM_TX;
00315     if (ioctl_nointr(itsFd, VIDIOC_QUERYCTRL, &ctrl) == 0)
00316       do { addControl(ctrl); ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; }
00317       while (ioctl_nointr(itsFd, VIDIOC_QUERYCTRL, &ctrl) == 0);
00318 #endif
00319 
00320   } else {
00321     IDLINFO("    > Does not support Extended Controls API");
00322     memset(&ctrl, 0, sizeof(ctrl));
00323 
00324     for (ctrl.id = V4L2_CID_BASE; ctrl.id < V4L2_CID_LASTP1; ++ctrl.id)
00325       if (ioctl_nointr(itsFd, VIDIOC_QUERYCTRL, &ctrl) == 0)
00326         addControl(ctrl);  // add a command-line option for the control, and describe it:
00327 
00328     for (ctrl.id = V4L2_CID_PRIVATE_BASE; ; ++ctrl.id)
00329       if (ioctl_nointr(itsFd, VIDIOC_QUERYCTRL, &ctrl) == 0)
00330         addControl(ctrl);  // add a command-line option for the control, and describe it:
00331       else break;
00332   }
00333 }
00334 
00335 // ######################################################################
00336 void V4L2grabber::addControl(const struct v4l2_queryctrl& ctrl)
00337 {
00338   // make sure we have not already added the control. This is because on some cameras the enumeration of extended
00339   // controls is broken, see comments in openDevice():
00340   for (size_t i = 0; i < itsControls.size(); ++i) if (itsControls[i]->cid == ctrl.id) return;
00341 
00342   std::string info = "CONTROL: "; std::vector<std::string> infomenu;
00343 
00344   // find a command-line option for this control:
00345   int ii = 0; const ModelOptionDef *option = NULL;
00346   while (controlmapping[ii].v4l2)
00347     if (controlmapping[ii].v4l2 == ctrl.id) { option = controlmapping[ii].opt; break; } else ++ ii;
00348 
00349   // display some info about this control:
00350   switch(ctrl.type)
00351     {
00352     case V4L2_CTRL_TYPE_INTEGER:
00353       info += sformat("%s [int] Def=%d, Rng=[%d ..(%d).. %d]",
00354                       ctrl.name, ctrl.default_value, ctrl.minimum, ctrl.step, ctrl.maximum);
00355       if (option) {
00356         rutz::shared_ptr<V4L2grabberControl<int> >
00357           param(new V4L2grabberControl<int>(option, this, ctrl.default_value, itsOptionFlags, ctrl.id, ctrl.type));
00358         itsControls.push_back(param);
00359         getManager().requestOption(param->param, true); // always use my val (the default) so change is not rejected
00360         info += " (use --" + std::string(option->longoptname) + "=<int>)";
00361       } else info = "UNSUPPORTED " + info;
00362 
00363       break;
00364 
00365     case V4L2_CTRL_TYPE_BOOLEAN:
00366       info += sformat("%s [boolean] Def=%s", ctrl.name, ctrl.default_value ? "true" : "false");
00367       if (option) {
00368         rutz::shared_ptr<V4L2grabberControl<bool> >
00369           param(new V4L2grabberControl<bool>(option, this, ctrl.default_value, itsOptionFlags, ctrl.id, ctrl.type));
00370         itsControls.push_back(param);
00371         getManager().requestOption(param->param, true);
00372         info += " (use --" + std::string(option->longoptname) + "=<bool>)";
00373       } else info = "UNSUPPORTED " + info;
00374 
00375       break;
00376 
00377     case V4L2_CTRL_TYPE_MENU:
00378       info += sformat("%s [menu] Def=%d", ctrl.name, ctrl.default_value);
00379       {
00380         // enumerate the menu items:
00381         struct v4l2_querymenu querymenu; memset(&querymenu, 0, sizeof(querymenu));
00382         querymenu.id = ctrl.id;
00383 
00384         for (querymenu.index = ctrl.minimum; int(querymenu.index) <= ctrl.maximum; ++querymenu.index) {
00385           if (ioctl_nointr(itsFd, VIDIOC_QUERYMENU, &querymenu) == 0)
00386             infomenu.push_back(sformat("CONTROL:            - %d = %s", querymenu.index, querymenu.name));
00387           else IDPLERROR("VIDIOC_QUERYMENU");
00388         }
00389       }
00390 
00391       if (option) {
00392         rutz::shared_ptr<V4L2grabberControl<int> >
00393           param(new V4L2grabberControl<int>(option, this, ctrl.default_value, itsOptionFlags, ctrl.id, ctrl.type));
00394         itsControls.push_back(param);
00395         getManager().requestOption(param->param, true);
00396         info += " (use --" + std::string(option->longoptname) + "=<int>)";
00397       } else info = "UNSUPPORTED " + info;
00398 
00399       break;
00400 
00401     case V4L2_CTRL_TYPE_BUTTON:
00402       info += sformat("%s [button]", ctrl.name);
00403 
00404       if (option) {
00405         rutz::shared_ptr<V4L2grabberControl<bool> >
00406           param(new V4L2grabberControl<bool>(option, this, ctrl.default_value, itsOptionFlags, ctrl.id, ctrl.type));
00407         itsControls.push_back(param);
00408         getManager().requestOption(param->param, true);
00409         info += " (use --" + std::string(option->longoptname) + "=<bool>)";
00410       } else info = "UNSUPPORTED " + info;
00411 
00412       break;
00413 
00414     case V4L2_CTRL_TYPE_INTEGER64:
00415       info += sformat("%s [int64]", ctrl.name);
00416 
00417       if (option) {
00418         rutz::shared_ptr<V4L2grabberControl<int64> >
00419           param(new V4L2grabberControl<int64>(option, this, ctrl.default_value, itsOptionFlags, ctrl.id, ctrl.type));
00420         itsControls.push_back(param);
00421         getManager().requestOption(param->param, true);
00422         info += " (use --" + std::string(option->longoptname) + "=<int64>)";
00423       } else info = "UNSUPPORTED " + info;
00424 
00425       break;
00426 
00427     case V4L2_CTRL_TYPE_CTRL_CLASS: // Note: this should never happen
00428       info += sformat("%s [control class]", ctrl.name);
00429       break;
00430 
00431 #ifdef V4L2_CTRL_TYPE_STRING
00432     case V4L2_CTRL_TYPE_STRING:
00433       info += sformat("%s [string]", ctrl.name);
00434 
00435       if (option) {
00436         rutz::shared_ptr<V4L2grabberControl<std::string> >
00437           param(new V4L2grabberControl<std::string>(option, this, "", itsOptionFlags, ctrl.id, ctrl.type));
00438         itsControls.push_back(param);
00439         getManager().requestOption(param->param, true);
00440         info += " (use --" + std::string(option->longoptname) + "=<string>)";
00441       } else info = "UNSUPPORTED " + info;
00442 
00443       break;
00444 #endif
00445 
00446     default:
00447       info += sformat("%s [unknown control 0x%x]", ctrl.name, ctrl.id);
00448       break;
00449     }
00450 
00451   std::vector<std::string> infoflags;
00452   if (ctrl.flags & V4L2_CTRL_FLAG_DISABLED) infoflags.push_back("DISABLED");
00453   if (ctrl.flags & V4L2_CTRL_FLAG_GRABBED) infoflags.push_back("GRABBED");
00454   if (ctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) infoflags.push_back("READONLY");
00455   if (ctrl.flags & V4L2_CTRL_FLAG_UPDATE) infoflags.push_back("UPDATE");
00456   if (ctrl.flags & V4L2_CTRL_FLAG_INACTIVE) infoflags.push_back("INACTIVE");
00457   if (ctrl.flags & V4L2_CTRL_FLAG_SLIDER) infoflags.push_back("SLIDER");
00458 
00459   if (infoflags.size() > 0) {
00460     info += " (" + infoflags[0];
00461     for (size_t ii = 1; ii < infoflags.size(); ++ii) info += ", " + infoflags[ii];
00462     info += ")";
00463   }
00464 
00465   // print the info:
00466   IDLINFO("%s", info.c_str());
00467   for (size_t ii = 0; ii < infomenu.size(); ++ii) IDLINFO("%s", infomenu[ii].c_str());
00468 
00469   // now set the value. If it is an extended control, we will change it using the extended control interface. Note that
00470   // here, some settings may fail, e.g., setting the manual focus value when autofocus is on. So we are going to be very
00471   // quiet about errors and just show everything at the LDEBUG level:
00472   if (V4L2_CTRL_ID2CLASS(ctrl.id) != V4L2_CTRL_CLASS_USER) {
00473     struct v4l2_ext_controls extctrls; memset(&extctrls, 0, sizeof(extctrls));
00474     extctrls.count = 1; extctrls.ctrl_class = V4L2_CTRL_ID2CLASS(ctrl.id);
00475 
00476     struct v4l2_ext_control xc; memset(&xc, 0, sizeof(xc)); extctrls.controls = &xc;
00477 
00478     xc.id = ctrl.id; xc.value = ctrl.default_value;
00479 
00480     if (ioctl_nointr(itsFd, VIDIOC_S_EXT_CTRLS, &extctrls) == -1)
00481       IDPLDEBUG("NOTE: Failed to set '%s' to %d (VIDIOC_S_EXT_CTRLS)", ctrl.name, ctrl.default_value);
00482     else IDLDEBUG("Suceesfully set control '%s' to value %d", ctrl.name, ctrl.default_value);
00483   } else {
00484     // old-style interface:
00485     struct v4l2_control c; memset(&c, 0, sizeof(c));
00486     c.id = ctrl.id; c.value = ctrl.default_value;
00487 
00488     if (ioctl_nointr(itsFd, VIDIOC_S_CTRL, &c) == -1)
00489       IDPLDEBUG("NOTE: Failed to set '%s' to %d (VIDIOC_S_EXT_CTRLS)", ctrl.name, ctrl.default_value);
00490     else IDLDEBUG("Successfully set control '%s' to value %d", ctrl.name, ctrl.default_value);
00491   }
00492 }
00493 
00494 // ######################################################################
00495 void V4L2grabber::closeDevice()
00496 {
00497   if (itsStreamStarted)
00498     {
00499       enum v4l2_buf_type typ = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00500       if (ioctl_nointr(itsFd, VIDIOC_STREAMOFF, &typ)) IDPLERROR("VIDIOC_STREAMOFF");
00501       itsStreamStarted = false;
00502     }
00503 
00504   if (itsMmapBuf)
00505     {
00506       for (int i = 0; i < itsNbuf.getVal(); i ++) munmap(itsMmapBuf[i], itsMmapBufSize[i]);
00507       delete [] itsMmapBuf; itsMmapBuf = NULL;
00508       delete [] itsMmapBufSize; itsMmapBufSize = NULL;
00509     }
00510 
00511   if (itsFd >= 0) { close(itsFd); itsFd = -1; }
00512   if (itsGrabbing) { delete [] itsGrabbing; itsGrabbing = NULL; }
00513   itsReadBuf = Image<byte>();
00514   itsStreamStarted = false;
00515 }
00516 
00517 // ######################################################################
00518 void V4L2grabber::start1()
00519 {
00520   if (itsFd == -1) openDevice();
00521 
00522   if (itsCanMMap == false && itsCanRW == false) IDLFATAL("No known frame grabbing method supported by hardware");
00523 
00524   // list available channels:
00525   for (int i = 0; ; i++)
00526     {
00527       struct v4l2_input inp; memset(&inp, 0, sizeof(inp)); inp.index = i;
00528       if (ioctl_nointr(itsFd, VIDIOC_ENUMINPUT, &inp) != 0) break;
00529       IDLINFO("Video input %d is '%s'", i, inp.name);
00530     }
00531 
00532   // select desired channel:
00533   int channel = itsChannel.getVal();
00534   if (ioctl_nointr(itsFd, VIDIOC_S_INPUT, &channel) < 0) IDPLERROR("Cannot select video input %d", itsChannel.getVal());
00535   else IDLINFO("Selected video input %d", itsChannel.getVal());
00536 
00537   // Reset cropping parameters and get resolution capabilities. NOTE: just open()'ing the device does not reset it,
00538   // according to the unix toolchain philosophy. Hence, although here we do not provide support for cropping, we still
00539   // need to ensure that it is properly reset:
00540   struct v4l2_cropcap cropcap;
00541   memset (&cropcap, 0, sizeof(cropcap));
00542   cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00543   if (ioctl_nointr(itsFd, VIDIOC_CROPCAP, &cropcap) == -1) IDPLERROR("Failed to get cropping capabilities -- IGNORED.");
00544   else {
00545     IDLINFO("Video capture bounds: (%d, %d) -> (%d, %d)", cropcap.bounds.left, cropcap.bounds.top,
00546             cropcap.bounds.left + cropcap.bounds.width - 1, cropcap.bounds.top + cropcap.bounds.height - 1);
00547     IDLINFO("Video default capture rectangle: (%d, %d) -> (%d, %d)", cropcap.defrect.left, cropcap.defrect.top,
00548             cropcap.defrect.left + cropcap.defrect.width - 1, cropcap.defrect.top + cropcap.defrect.height - 1);
00549   }
00550 
00551   struct v4l2_crop crop; memset (&crop, 0, sizeof(crop));
00552   crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; crop.c = cropcap.defrect;
00553   if (ioctl_nointr(itsFd, VIDIOC_S_CROP, &crop) == -1) IDPLERROR("Failed to reset cropping settings -- IGNORED.");
00554 
00555   // list available video formats and see which ones would work with the requested resolution:
00556   struct v4l2_format fmt; memset(&fmt, 0, sizeof(fmt));
00557   fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00558   fmt.fmt.pix.width = itsDims.getVal().w();
00559   fmt.fmt.pix.height = itsDims.getVal().h();
00560   fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
00561   int fmt_to_use = -1; // in case user selected "auto" format
00562 
00563   for (int i = 0; ; ++ i) {
00564     struct v4l2_fmtdesc fdesc; memset(&fdesc, 0, sizeof(fdesc));
00565     fdesc.index = i; fdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00566     if (ioctl_nointr(itsFd, VIDIOC_ENUM_FMT, &fdesc) != 0) break;
00567 
00568     const VideoFormat f = V4L2Format_to_VideoFormat(fdesc.pixelformat);
00569 
00570     // try to see whether that would work with our given image dims:
00571     fmt.fmt.pix.pixelformat = fdesc.pixelformat;
00572     bool worked = false;
00573     if (ioctl_nointr(itsFd, VIDIOC_TRY_FMT, &fmt) == 0) {
00574       worked = true; if (fmt_to_use == -1) fmt_to_use = fdesc.pixelformat;
00575     }
00576     IDLINFO("Video Format: Use '%s' for '%s (Fourcc: %c%c%c%c)'%s%s",
00577             f == VIDFMT_AUTO ?
00578             "????" : convertToString(f).c_str(),
00579             fdesc.description,
00580             ((char*)(&fdesc.pixelformat))[0],
00581             ((char*)(&fdesc.pixelformat))[1],
00582             ((char*)(&fdesc.pixelformat))[2],
00583             ((char*)(&fdesc.pixelformat))[3],
00584             fdesc.flags & V4L2_FMT_FLAG_COMPRESSED ? " (COMPRESSED)" : "",
00585             worked ? " [OK]" : " [FAILED TO SET]");
00586   }
00587 
00588   // Get the frame time, according to current video standard:
00589   struct v4l2_streamparm sparm; memset(&sparm, 0, sizeof(sparm));
00590   sparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00591   if (ioctl_nointr(itsFd, VIDIOC_G_PARM, &sparm) == -1) {
00592     IDPLERROR("Cannot get video standard params - ASSUMING NTSC");
00593     itsFrameTime = SimTime::HERTZ(29.97);
00594   }
00595   else itsFrameTime = SimTime::SECS(float(sparm.parm.capture.timeperframe.numerator) /
00596                                     float(sparm.parm.capture.timeperframe.denominator));
00597   IDLINFO("Capture at %.2f fps", itsFrameTime.hertz());
00598 
00599   // try to select a video mode and image format:
00600   if (itsGrabMode.getVal() == VIDFMT_AUTO) {
00601     if (fmt_to_use == -1) IDLFATAL("Could not find a working video mode for given resolution.");
00602     fmt.fmt.pix.pixelformat = fmt_to_use;
00603   } else fmt.fmt.pix.pixelformat = VideoFormat_to_V4L2Format(itsGrabMode.getVal());
00604 
00605   if (ioctl_nointr(itsFd, VIDIOC_S_FMT, &fmt) == -1)
00606     IDPLFATAL("Cannot set requested video mode/resolution %s [%dx%d], probably unsupported by hardware.",
00607               convertToString(itsGrabMode.getVal()).c_str(), itsDims.getVal().w(), itsDims.getVal().h());
00608 
00609   if (ioctl_nointr(itsFd, VIDIOC_G_FMT, &fmt) == 0)
00610     IDLINFO("Video mode/resolution set to %s [%dx%d]", convertToString(itsGrabMode.getVal()).c_str(),
00611             fmt.fmt.pix.width, fmt.fmt.pix.height);
00612 
00613   if (int(fmt.fmt.pix.width) != itsDims.getVal().w() || int(fmt.fmt.pix.height) != itsDims.getVal().h())
00614     IDLFATAL("Hardware suggests changing input dims to %dx%d instead of requested %dx%d",
00615              fmt.fmt.pix.width, fmt.fmt.pix.height, itsDims.getVal().w(), itsDims.getVal().h());
00616 
00617   // if MMAP is supported, allocate a mmap'ed buffer:
00618   if (itsCanMMap) {
00619     IDLINFO("Using mmap'ed image capture with %d buffers", itsNbuf.getVal());
00620     struct v4l2_requestbuffers req; memset(&req, 0, sizeof(req));
00621     req.count = itsNbuf.getVal();
00622     req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00623     req.memory = V4L2_MEMORY_MMAP;
00624 
00625     if (ioctl_nointr(itsFd, VIDIOC_REQBUFS, &req) == -1)
00626       IDPLFATAL("Cannot allocate %d mmap'ed video frame buffers", itsNbuf.getVal());
00627     if (int(req.count) != itsNbuf.getVal())
00628       IDLFATAL("Hardware can only support %d video frame buffers (vs. %d requested)", req.count, itsNbuf.getVal());
00629 
00630     itsMmapBuf = new byte*[req.count];
00631     itsMmapBufSize = new int[req.count];
00632 
00633     for (uint i = 0; i < req.count; ++i) {
00634       struct v4l2_buffer buf; memset(&buf, 0, sizeof(buf));
00635       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00636       buf.memory = V4L2_MEMORY_MMAP;
00637       buf.index = i;
00638 
00639       if (ioctl_nointr(itsFd, VIDIOC_QUERYBUF, &buf) == -1) IDPLFATAL("Could not query for MMAP buffer");
00640 
00641       itsMmapBufSize[i] = buf.length;
00642       itsMmapBuf[i] = static_cast<byte*>(mmap(NULL, buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, itsFd, buf.m.offset));
00643 
00644       if (itsMmapBuf[i] == MAP_FAILED) IDPLFATAL("Error MMAP'ing video buffer number %d", i);
00645     }
00646 
00647     // we don't need the read() buffer:
00648     itsReadBuf = Image<byte>();
00649   } else {
00650     // get ready for read() access method:
00651     IDLINFO("Using read() image capture");
00652     itsReadBuf = Image<byte>(getFrameSize(itsGrabMode.getVal(), itsDims.getVal()), 1, NO_INIT);
00653     itsMmapBuf = NULL;
00654     itsMmapBufSize = NULL;
00655   }
00656 
00657   // get ready to grab frames, starting with buffer/frame 0:
00658   IDLDEBUG("Using %d grab buffers", itsNbuf.getVal());
00659   itsCurrentFrame = 0;
00660   itsGrabbing = new bool[itsNbuf.getVal()];
00661   for (int i = 0; i < itsNbuf.getVal(); ++i) itsGrabbing[i] = false;
00662 }
00663 
00664 // ######################################################################
00665 void V4L2grabber::stop2()
00666 {
00667   closeDevice();
00668 }
00669 
00670 // ######################################################################
00671 V4L2grabber::~V4L2grabber()
00672 {  }
00673 
00674 // ######################################################################
00675 void V4L2grabber::setListener(rutz::shared_ptr<FrameListener> listener)
00676 { itsListener = listener; }
00677 
00678 // ######################################################################
00679 void V4L2grabber::paramChanged(ModelParamBase* const param, const bool valueChanged,
00680                                ParamClient::ChangeStatus* status)
00681 {
00682   // re-open the device if its name was changed:
00683   if (valueChanged && param == &itsDevName) {
00684     if (started()) IDLFATAL("Cannot change device while started");
00685     closeDevice(); openDevice();
00686   }
00687 
00688   if (valueChanged && param == &itsChannel) {
00689     int channel = itsChannel.getVal();
00690     if (ioctl_nointr(itsFd, VIDIOC_S_INPUT, &channel) < 0)
00691       IDPLERROR("Cannot select video input %d", itsChannel.getVal());
00692     else
00693       IDLINFO("Selected video input %d", itsChannel.getVal());
00694   }
00695 
00696   // is that one of our camera controls?
00697   if (valueChanged)
00698     for (size_t i = 0; i < itsControls.size(); ++i) {
00699       int val = 0; const char *name = NULL;
00700 
00701       // match the param and get its value:
00702       switch(itsControls[i]->ctype) {
00703       case V4L2_CTRL_TYPE_INTEGER:
00704         {
00705           const V4L2grabberControl<int>& c = dynamic_cast<V4L2grabberControl<int>&>(*itsControls[i]);
00706           const OModelParam<int>& p = c.param;
00707           if (param == &p) { val = p.getVal(); name = p.getOptionDef()->longoptname; }
00708         }
00709         break;
00710       case V4L2_CTRL_TYPE_BOOLEAN:
00711         {
00712           const V4L2grabberControl<bool>& c = dynamic_cast<V4L2grabberControl<bool>&>(*itsControls[i]);
00713           const OModelParam<bool>& p = c.param;
00714           if (param == &p) { val = p.getVal(); name = p.getOptionDef()->longoptname; }
00715         }
00716         break;
00717       case V4L2_CTRL_TYPE_MENU:
00718         {
00719           const V4L2grabberControl<int>& c = dynamic_cast<V4L2grabberControl<int>&>(*itsControls[i]);
00720           const OModelParam<int>& p = c.param;
00721           if (param == &p) { val = p.getVal(); name = p.getOptionDef()->longoptname; }
00722         }
00723         break;
00724       case V4L2_CTRL_TYPE_BUTTON:
00725         {
00726           const V4L2grabberControl<bool>& c = dynamic_cast<V4L2grabberControl<bool>&>(*itsControls[i]);
00727           const OModelParam<bool>& p = c.param;
00728           if (param == &p) { val = p.getVal(); name = p.getOptionDef()->longoptname; }
00729         }
00730         break;
00731       case V4L2_CTRL_TYPE_INTEGER64:
00732         {
00733           const V4L2grabberControl<int64>& c = dynamic_cast<V4L2grabberControl<int64>&>(*itsControls[i]);
00734           const OModelParam<int64>& p = c.param;
00735           if (param == &p) { val = static_cast<int>(p.getVal()); name = p.getOptionDef()->longoptname; }
00736         }
00737         break;
00738 
00739 #ifdef V4L2_CTRL_TYPE_STRING
00740       case V4L2_CTRL_TYPE_STRING:
00741         {
00742           const V4L2grabberControl<std::string>& c = dynamic_cast<V4L2grabberControl<std::string>&>(*itsControls[i]);
00743           const OModelParam<std::string>& p = c.param;
00744           if (param == &p) IDLFATAL("Changing value of string control not yet supported");
00745         }
00746         break;
00747 #endif
00748       default: IDLFATAL("Changing value of control of type 0x%x not supported", itsControls[i]->ctype); break;
00749       }
00750 
00751       if (name) {
00752         // ok, we got the param. If it is extended, we will change it using the extended control interface:
00753         if (V4L2_CTRL_ID2CLASS(itsControls[i]->cid) != V4L2_CTRL_CLASS_USER) {
00754           struct v4l2_ext_controls extctrls; memset(&extctrls, 0, sizeof(extctrls));
00755           extctrls.count = 1; // we'll set one extended control at a time
00756           extctrls.ctrl_class = V4L2_CTRL_ID2CLASS(itsControls[i]->cid);
00757 
00758           struct v4l2_ext_control xctrl; memset(&xctrl, 0, sizeof(xctrl));
00759           extctrls.controls = &xctrl; // our one extended control to set
00760 
00761           xctrl.id = itsControls[i]->cid;
00762           xctrl.value = val;
00763 
00764           if (ioctl_nointr(itsFd, VIDIOC_S_EXT_CTRLS, &extctrls) == -1) {
00765             IDPLERROR("NOTE: Failed to set --%s to %d (VIDIOC_S_EXT_CTRLS)", name, val);
00766             //*status = ParamClient::CHANGE_REJECTED;
00767           } else IDLDEBUG("Changed control --%s to value %d", name, val);
00768         } else {
00769           // old-style interface:
00770           struct v4l2_control ctrl; memset(&ctrl, 0, sizeof(ctrl));
00771           ctrl.id = itsControls[i]->cid;
00772           ctrl.value = val;
00773 
00774           if (ioctl_nointr(itsFd, VIDIOC_S_CTRL, &ctrl) == -1) {
00775             IDPLERROR("NOTE: Failed to set --%s to %d (VIDIOC_S_EXT_CTRLS)", name, val);
00776             //*status = ParamClient::CHANGE_REJECTED;
00777           } else IDLDEBUG("Changed control --%s to value %d", name, val);
00778         }
00779       }
00780     }
00781 
00782   FrameIstream::paramChanged(param, valueChanged, status);
00783 }
00784 
00785 // ######################################################################
00786 void V4L2grabber::startStream()
00787 {
00788   // reset itsStreamStarted so that we wait for any pending frames to
00789   // be grabbed, then start fresh grabbing requests:
00790   itsStreamStarted = false;
00791 
00792   this->restartStream();
00793 }
00794 
00795 // ######################################################################
00796 SimTime V4L2grabber::getNaturalFrameTime() const
00797 {
00798   return itsFrameTime;
00799 }
00800 
00801 // ######################################################################
00802 GenericFrameSpec V4L2grabber::peekFrameSpec()
00803 {
00804   GenericFrameSpec result;
00805 
00806   result.nativeType = GenericFrame::VIDEO;
00807   result.videoFormat = itsGrabMode.getVal();
00808   result.videoByteSwap = itsByteSwap.getVal();
00809   result.dims = itsDims.getVal();
00810   result.floatFlags = 0;
00811 
00812   return result;
00813 }
00814 
00815 // ######################################################################
00816 GenericFrame V4L2grabber::readFrame()
00817 {
00818   const GenericFrame frame =
00819     itsStreamingMode.getVal()
00820     ? GenericFrame(this->grabRaw())
00821     : GenericFrame(this->grabSingleRaw());
00822 
00823   if (itsListener.get() != 0)
00824     itsListener->onRawFrame(frame);
00825 
00826   return frame;
00827 }
00828 
00829 // ######################################################################
00830 VideoFrame V4L2grabber::grabRaw()
00831 {
00832   byte* result = 0; int siz = 0;
00833   if (itsMmapBuf) // mmap interface
00834     {
00835       this->restartStream();
00836       result = itsMmapBuf[itsCurrentFrame];
00837       siz = itsMmapBufSize[itsCurrentFrame];
00838       struct v4l2_buffer buf;
00839       memset(&buf, 0, sizeof(buf));
00840       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00841       buf.memory = V4L2_MEMORY_MMAP;
00842       buf.index = itsCurrentFrame;
00843 
00844       // are we already grabbing buffer 'itsCurrentFrame'? otherwise,
00845       // start the grab now:
00846       if (itsGrabbing[itsCurrentFrame] == false)
00847         {
00848           if (ioctl_nointr(itsFd, VIDIOC_QBUF, &buf))
00849             IDPLFATAL("VIDIOC_QBUF (frame %d)", itsCurrentFrame);
00850           itsGrabbing[itsCurrentFrame] = true;
00851         }
00852 
00853       // wait until buffer 'itsCurrentFrame' has been fully captured:
00854       if (ioctl_nointr(itsFd, VIDIOC_DQBUF, &buf) == -1)
00855         IDPLFATAL("VIDIOC_DQBUF (frame %d)", itsCurrentFrame);
00856       itsGrabbing[itsCurrentFrame] = false;
00857 
00858       // get ready for capture of that frame again (for later):
00859       itsGrabbing[itsCurrentFrame] = true;
00860       if (ioctl_nointr(itsFd, VIDIOC_QBUF, &buf) < 0)
00861         IDPLFATAL("VIDIOC_QBUF (frame %d)", itsCurrentFrame);
00862     }
00863   else // read() interface
00864     {
00865       ASSERT(itsReadBuf.initialized());
00866       const ssize_t nbytes =
00867         read(itsFd, itsReadBuf.getArrayPtr(), itsReadBuf.getSize());
00868       if (nbytes < 0) IDPLFATAL("read() failed (frame %d)", itsCurrentFrame);
00869       IDLDEBUG("Got %zd bytes", nbytes);
00870       result = itsReadBuf.getArrayPtr();
00871       siz = nbytes;
00872     }
00873 
00874   // switch to another frame:
00875   ++itsCurrentFrame;
00876   if (itsCurrentFrame >= itsNbuf.getVal()) itsCurrentFrame = 0;
00877 
00878   // return pointer to last-grabbed frame. You have a bit of time to
00879   // get a hold of the data but beware that an order to capture that
00880   // buffer has already been issued, so as soon as the grabber gets to
00881   // it, it will overwrite this buffer with a new frame:
00882   ASSERT(result != 0);
00883   VideoFrame frame(result, siz, itsDims.getVal(),
00884                    itsGrabMode.getVal(), itsByteSwap.getVal(),
00885                    /* strictLength = */ false);
00886   return frame;
00887 }
00888 
00889 // ######################################################################
00890 VideoFrame V4L2grabber::grabSingleRaw()
00891 {
00892   byte* result = 0; int siz = 0;
00893   if (itsMmapBuf) // mmap interface
00894     {
00895       itsCurrentFrame = 0;
00896       result = itsMmapBuf[itsCurrentFrame];
00897       siz = itsMmapBufSize[itsCurrentFrame];
00898       struct v4l2_buffer buf;
00899       memset(&buf, 0, sizeof(buf));
00900       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00901       buf.memory = V4L2_MEMORY_MMAP;
00902       buf.index = itsCurrentFrame;
00903 
00904       // are we already grabbing buffer 'itsCurrentFrame'? otherwise,
00905       // start the grab now:
00906       if (itsGrabbing[itsCurrentFrame] == false)
00907         {
00908           if (ioctl_nointr(itsFd, VIDIOC_QBUF, &buf))
00909             IDPLFATAL("VIDIOC_QBUF (frame %d)", itsCurrentFrame);
00910           itsGrabbing[itsCurrentFrame] = true;
00911         }
00912 
00913       // wait until buffer 'itsCurrentFrame' has been fully captured:
00914       if (ioctl_nointr(itsFd, VIDIOC_DQBUF, &buf) == -1)
00915         IDPLFATAL("VIDIOC_DQBUF (frame %d)", itsCurrentFrame);
00916       itsGrabbing[itsCurrentFrame] = false;
00917     }
00918   else // read() interface
00919     {
00920       ASSERT(itsReadBuf.initialized());
00921       const ssize_t nbytes =
00922         read(itsFd, itsReadBuf.getArrayPtr(), itsReadBuf.getSize());
00923       if (nbytes < 0) IDPLFATAL("read() failed (frame %d)", itsCurrentFrame);
00924       IDLDEBUG("Got %zd bytes", nbytes);
00925       result = itsReadBuf.getArrayPtr();
00926       siz = nbytes;
00927     }
00928 
00929   // return grabbed & converted frame:
00930   VideoFrame frame(result, siz, itsDims.getVal(),
00931                    itsGrabMode.getVal(), itsByteSwap.getVal(),
00932                    /* strictLength = */ false);
00933   return frame;
00934 }
00935 
00936 // ######################################################################
00937 void V4L2grabber::restartStream()
00938 {
00939   if (itsStreamingMode.getVal()
00940       && itsMmapBuf
00941       && !itsStreamStarted)
00942     {
00943       struct v4l2_buffer buf;
00944       memset(&buf, 0, sizeof(buf));
00945 
00946       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00947       buf.memory = V4L2_MEMORY_MMAP;
00948 
00949       for (int i = 0; i < itsNbuf.getVal(); ++i)
00950         if (itsGrabbing[i] == true)
00951           {
00952             // are we already grabbing buffer i?  if so, wait for grab
00953             // to finished if we've requested resync (if we don't do
00954             // this, then the first few frames after a restart will be
00955             // wrong -- they'll come too quickly and they'll be too old,
00956             // since the v4l driver doesn't grab new frames into buffers
00957             // until the old frames have been retrieved):
00958             buf.index = i;
00959             if (ioctl_nointr(itsFd, VIDIOC_DQBUF, &buf) == -1)
00960               IDPLFATAL("VIDIOC_DQBUF (frame %d)", i);
00961             itsGrabbing[i] = false;
00962           }
00963 
00964       for (int i = 0; i < itsNbuf.getVal(); ++i)
00965         {
00966           // now start a fresh grab for buffer i:
00967           buf.index = i;
00968           if (ioctl_nointr(itsFd, VIDIOC_QBUF, &buf))
00969             IDPLFATAL("VIDIOC_QBUF (frame %d)", i);
00970           itsGrabbing[i] = true;
00971         }
00972 
00973       // tell grabber to stream:
00974       enum v4l2_buf_type typ = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00975       if (ioctl_nointr(itsFd, VIDIOC_STREAMON, &typ))
00976         PLFATAL("VIDIOC_STREAMON");
00977 
00978       itsCurrentFrame = 0;
00979       itsStreamStarted = true;
00980     }
00981 }
00982 
00983 #endif // HAVE_LINUX_VIDEODEV2_H
00984 
00985 // ######################################################################
00986 /* So things look consistent in everyone's emacs... */
00987 /* Local Variables: */
00988 /* indent-tabs-mode: nil */
00989 /* End: */
Generated on Sun May 8 08:40:38 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3