00001 /*!@file Devices/V4Lgrabber.C Interface with a video4linux 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/V4Lgrabber.C $ 00035 // $Id: V4Lgrabber.C 10794 2009-02-08 06:21:09Z itti $ 00036 // 00037 00038 #ifdef HAVE_LINUX_VIDEODEV_H 00039 00040 #include "Devices/V4Lgrabber.H" 00041 00042 #include "Component/OptionManager.H" // for option alias requests 00043 #include "Devices/DeviceOpts.H" 00044 #include "Image/ColorOps.H" 00045 #include "Raster/GenericFrame.H" 00046 #include "Util/Assert.H" 00047 #include "Util/log.H" 00048 #include "Video/VideoFrame.H" 00049 00050 #include <cerrno> 00051 #include <fcntl.h> 00052 #include <sys/ioctl.h> 00053 #include <sys/mman.h> 00054 #include <sys/stat.h> 00055 #include <unistd.h> 00056 00057 //! for id-logging; see log.H: 00058 #define MYLOGID itsFd 00059 00060 namespace 00061 { 00062 //! A V4L palette entry 00063 struct V4LPalette 00064 { 00065 int pal; //!< palette 00066 int depth; //!< depth 00067 const char* name; //!< name of palette e.g. "rgb24" 00068 VideoFormat vidformat; //!< Frame grabber mode 00069 }; 00070 00071 //! array of all known palettes 00072 //! high preference modes have lower indices 00073 struct V4LPalette palettes[12] = 00074 { 00075 { VIDEO_PALETTE_RGB24, 24, "bgr24", VIDFMT_RGB24 }, 00076 { VIDEO_PALETTE_RGB24 | 0x80, 24, "rgb24", VIDFMT_RGB24 }, 00077 { VIDEO_PALETTE_RGB32, 32, "bgr32", VIDFMT_RGB32 }, 00078 { VIDEO_PALETTE_RGB32 | 0x80, 32, "rgb32", VIDFMT_RGB32 }, 00079 { VIDEO_PALETTE_YUYV, 24, "yuyv 16bpp", VIDFMT_YUYV }, 00080 { VIDEO_PALETTE_YUV422, 24, "yuv422 16bpp", VIDFMT_YUV422 }, 00081 { VIDEO_PALETTE_RGB565, 16, "rgb565", VIDFMT_RGB565 }, 00082 { VIDEO_PALETTE_RGB555, 15, "rgb555", VIDFMT_RGB555 }, 00083 { VIDEO_PALETTE_YUV420, 24, "yuv420 12bpp", VIDFMT_YUV420 }, 00084 { VIDEO_PALETTE_YUV420P, 24, "yuv420 planar 12bpp", VIDFMT_YUV420P }, 00085 { VIDEO_PALETTE_GREY, 8, "grayscale 8bpp", VIDFMT_GREY }, 00086 { -1, -1, 0, VideoFormat(-1) } 00087 }; 00088 00089 int ioctl_nointr(int d, int req, void* mem) 00090 { 00091 int result = 0; 00092 do { result = ioctl(d, req, mem); } 00093 while ((result < 0) && (errno == EINTR)); 00094 return result; 00095 } 00096 } 00097 00098 // ###################################################################### 00099 V4Lgrabber::V4Lgrabber(OptionManager& mgr, const std::string& descrName, 00100 const std::string& tagName, 00101 const ParamFlag flags) : 00102 FrameIstream(mgr, descrName, tagName), 00103 // NOTE that contrary to the common case, we may give (by default 00104 // value of 'flags') USE_MY_VAL here when we construct the 00105 // OModelParam objects; that means that we push our values into the 00106 // ModelManager as the new default values, rather than having our 00107 // param take its value from the ModelManager's default 00108 itsDevName(&OPT_FrameGrabberDevice, this, "/dev/video0", flags), // V4l device 00109 itsChannel(&OPT_FrameGrabberChannel, this, 1, flags), // composite input 00110 itsDims(&OPT_FrameGrabberDims, this, Dims(320, 240), flags), 00111 itsGrabMode(&OPT_FrameGrabberMode, this, VIDFMT_RGB24, flags), // 24-bit rgb grabbing 00112 itsByteSwap(&OPT_FrameGrabberByteSwap, this, true, flags), // use byte-swapping 00113 itsBrightness(&OPT_FrameGrabberBrightness, this, 32768, flags | ALLOW_ONLINE_CHANGES), 00114 itsHue(&OPT_FrameGrabberHue, this, 32768, flags | ALLOW_ONLINE_CHANGES), 00115 itsColour(&OPT_FrameGrabberColour, this, 32768, flags | ALLOW_ONLINE_CHANGES), 00116 itsContrast(&OPT_FrameGrabberContrast, this, 32768, flags | ALLOW_ONLINE_CHANGES), 00117 itsWhiteness(&OPT_FrameGrabberWhiteness, this, 32768, flags | ALLOW_ONLINE_CHANGES), 00118 itsStreamingMode(&OPT_FrameGrabberStreaming, this), 00119 itsFd(-1), 00120 itsMmapBuf(NULL), 00121 itsReadBuf(), 00122 itsTotalBufSize(0), 00123 itsNumBufFrames(0), 00124 itsCurrentFrame(0), 00125 itsGrabbing(NULL), 00126 itsFrameTime(SimTime::ZERO()), 00127 itsListener(), 00128 itsStreamStarted(false) 00129 { 00130 // request a bunch of camera aliases which work with V4L: 00131 mgr.requestOptionAlias(&OPT_ALIAScamBttv); 00132 } 00133 00134 // ###################################################################### 00135 void V4Lgrabber::start1() 00136 { 00137 itsFd = open(itsDevName.getVal().c_str(), O_RDWR | O_NONBLOCK); 00138 if (itsFd == -1) PLFATAL("Cannot open V4L device %s", 00139 itsDevName.getVal().c_str()); 00140 00141 // get frame grabber capabilities: 00142 struct video_capability vc; 00143 if (ioctl_nointr(itsFd, VIDIOCGCAP, &vc) < 0) 00144 IDPLFATAL("Cannot get V4L device capabilities"); 00145 IDLINFO("FrameGrabber board name is: %s", vc.name); 00146 IDLINFO("maxwidth = %d, maxheight = %d", vc.maxwidth, vc.maxheight); 00147 if (itsDims.getVal().w() > vc.maxwidth || 00148 itsDims.getVal().h() > vc.maxheight) 00149 IDLFATAL("Requested grab size %dx%d too large", 00150 itsDims.getVal().w(), itsDims.getVal().h()); 00151 00152 // select input channel & norm: 00153 struct video_channel vch; 00154 vch.channel = itsChannel.getVal(); 00155 if (ioctl_nointr(itsFd, VIDIOCGCHAN, &vch) < 0) 00156 IDPLERROR("Cannot get V4L device channel information"); 00157 vch.norm = VIDEO_MODE_NTSC; // set NTSC norm 00158 vch.type = VIDEO_TYPE_CAMERA; // camera input 00159 IDLINFO("Channel %d is '%s' [norm %d]", 00160 vch.channel, vch.name, vch.norm); 00161 if (ioctl_nointr(itsFd, VIDIOCSCHAN, &vch) < 0) 00162 IDPLERROR("Cannot set V4L device channel information"); 00163 00164 switch (vch.norm) 00165 { 00166 case VIDEO_MODE_PAL: 00167 itsFrameTime = SimTime::HERTZ(25.0); 00168 break; 00169 00170 case VIDEO_MODE_NTSC: 00171 itsFrameTime = SimTime::HERTZ(29.97); 00172 break; 00173 00174 case VIDEO_MODE_SECAM: 00175 itsFrameTime = SimTime::HERTZ(25.0); 00176 break; 00177 00178 default: 00179 itsFrameTime = SimTime::ZERO(); 00180 break; 00181 } 00182 00183 // get specs of video buffer: 00184 struct video_mbuf vmb; 00185 if (ioctl_nointr(itsFd, VIDIOCGMBUF, &vmb) < 0) 00186 IDPLFATAL("Cannot get V4L device buffer"); 00187 00188 IDLINFO("video Mbuf: 0x%x bytes, %d frames", vmb.size, vmb.frames); 00189 for (int i = 0; i < vmb.frames; ++i) 00190 IDLINFO("buffer offset[%d] = %d", i, vmb.offsets[i]); 00191 00192 // get the picture properties 00193 struct video_picture vp; 00194 if (ioctl_nointr(itsFd, VIDIOCGPICT, &vp) != 0) 00195 IDPLFATAL("ioctl(VIDIOCSPICT) get picture properties failed"); 00196 00197 // get ready for capture, for all frames in buffer: 00198 switch (itsGrabMode.getVal()) { 00199 case VIDFMT_GREY: itsVmmInfo.format = VIDEO_PALETTE_GREY; break; 00200 case VIDFMT_RAW: itsVmmInfo.format = VIDEO_PALETTE_RAW; break; 00201 case VIDFMT_RGB555: itsVmmInfo.format = VIDEO_PALETTE_RGB555; break; 00202 case VIDFMT_RGB565: itsVmmInfo.format = VIDEO_PALETTE_RGB565; break; 00203 case VIDFMT_RGB24: itsVmmInfo.format = VIDEO_PALETTE_RGB24; break; 00204 case VIDFMT_RGB32: itsVmmInfo.format = VIDEO_PALETTE_RGB32; break; 00205 case VIDFMT_YUYV: itsVmmInfo.format = VIDEO_PALETTE_YUYV; break; 00206 case VIDFMT_UYVY: itsVmmInfo.format = VIDEO_PALETTE_UYVY; break; 00207 case VIDFMT_YUV422: itsVmmInfo.format = VIDEO_PALETTE_YUV422; break; 00208 case VIDFMT_YUV411: itsVmmInfo.format = VIDEO_PALETTE_YUV411; break; 00209 case VIDFMT_YUV420: itsVmmInfo.format = VIDEO_PALETTE_YUV420; break; 00210 case VIDFMT_YUV422P: itsVmmInfo.format = VIDEO_PALETTE_YUV422P; break; 00211 case VIDFMT_YUV411P: itsVmmInfo.format = VIDEO_PALETTE_YUV411P; break; 00212 case VIDFMT_YUV420P: itsVmmInfo.format = VIDEO_PALETTE_YUV420P; break; 00213 case VIDFMT_YUV410P: itsVmmInfo.format = VIDEO_PALETTE_YUV410P; break; 00214 case VIDFMT_AUTO: 00215 // Auto selection of grab mode: 00216 struct V4LPalette* pal; 00217 LINFO("Probing for supported palettes:"); 00218 00219 #define CHECK_PALETTE(p) \ 00220 { \ 00221 vp.palette = p; \ 00222 vp.depth = 32; \ 00223 ioctl_nointr(itsFd, VIDIOCSPICT, &vp);\ 00224 ioctl_nointr(itsFd, VIDIOCGPICT, &vp);\ 00225 if (vp.palette == p) \ 00226 LINFO(" %-22s supported", #p); \ 00227 else \ 00228 LINFO(" %-22s NOT supported", #p); \ 00229 } 00230 00231 CHECK_PALETTE(VIDEO_PALETTE_GREY); 00232 CHECK_PALETTE(VIDEO_PALETTE_HI240); 00233 CHECK_PALETTE(VIDEO_PALETTE_RGB565); 00234 CHECK_PALETTE(VIDEO_PALETTE_RGB24); 00235 CHECK_PALETTE(VIDEO_PALETTE_RGB32); 00236 CHECK_PALETTE(VIDEO_PALETTE_RGB555); 00237 CHECK_PALETTE(VIDEO_PALETTE_YUV422); 00238 CHECK_PALETTE(VIDEO_PALETTE_YUYV); 00239 CHECK_PALETTE(VIDEO_PALETTE_UYVY); 00240 CHECK_PALETTE(VIDEO_PALETTE_YUV420); 00241 CHECK_PALETTE(VIDEO_PALETTE_YUV411); 00242 CHECK_PALETTE(VIDEO_PALETTE_RAW); 00243 CHECK_PALETTE(VIDEO_PALETTE_YUV422P); 00244 CHECK_PALETTE(VIDEO_PALETTE_YUV411P); 00245 CHECK_PALETTE(VIDEO_PALETTE_YUV420P); 00246 CHECK_PALETTE(VIDEO_PALETTE_YUV410P); 00247 00248 #undef CHECK_PALETTE 00249 00250 // Brutal, loop through all available modes 00251 for (pal = &palettes[0]; pal->pal >= 0; ++pal) 00252 { 00253 vp.palette = pal->pal; 00254 vp.depth = pal->depth; 00255 ioctl_nointr(itsFd, VIDIOCSPICT, &vp); 00256 ioctl_nointr(itsFd, VIDIOCGPICT, &vp); 00257 if (vp.palette == pal->pal) 00258 { 00259 LINFO(" Using palette \"%s\" with depth %u", 00260 pal->name, vp.depth); 00261 // hack 00262 itsGrabMode.setVal(pal->vidformat); 00263 itsVmmInfo.format = vp.palette; 00264 break; 00265 } 00266 else 00267 LINFO(" Palette \"%s\" not supported", pal->name); 00268 } 00269 00270 if (pal->pal < 0) 00271 IDLFATAL("Auto palette selection failed - try setting manually."); 00272 break; 00273 default: 00274 LFATAL("Unsupported grab mode"); 00275 } 00276 00277 // get ready to grab frames, starting with buffer/frame 0: 00278 itsNumBufFrames = vmb.frames; 00279 itsTotalBufSize = vmb.size; 00280 itsCurrentFrame = 0; 00281 itsGrabbing = new bool[itsNumBufFrames]; 00282 for (int i = 0; i < itsNumBufFrames; ++i) itsGrabbing[i] = false; 00283 itsVmmInfo.width = itsDims.getVal().w(); 00284 itsVmmInfo.height = itsDims.getVal().h(); 00285 itsVmmInfo.frame = 0; 00286 00287 // decide on mmap'ed or read() access: 00288 if (ioctl_nointr(itsFd, VIDIOCGMBUF, &vmb) != -1) 00289 { 00290 IDLINFO("Using mmap'ed image capture"); 00291 // setup mmap'ed access to the video buffer: 00292 itsMmapBuf = 00293 static_cast<byte*>(mmap((void*)0, vmb.size, 00294 PROT_READ|PROT_WRITE, 00295 MAP_SHARED, itsFd, 0)); 00296 00297 if (itsMmapBuf == MAP_FAILED) 00298 IDPLFATAL("mmap failed"); 00299 00300 itsReadBuf = Image<byte>(); 00301 } 00302 else 00303 { 00304 IDLINFO("Using read() image capture"); 00305 itsMmapBuf = NULL; 00306 00307 itsReadBuf = Image<byte>(getFrameSize(itsGrabMode.getVal(), 00308 itsDims.getVal()), 00309 1, NO_INIT); 00310 } 00311 00312 // set picture properties 00313 vp.brightness = itsBrightness.getVal(); 00314 vp.hue = itsHue.getVal(); 00315 vp.colour = itsColour.getVal(); 00316 vp.contrast = itsContrast.getVal(); 00317 vp.whiteness = itsWhiteness.getVal(); 00318 vp.palette = itsVmmInfo.format; 00319 LINFO("bright=%u hue=%u color=%u contrast=%u white=%u depth=%u palette=%u", 00320 vp.brightness, vp.hue, vp.colour, vp.contrast, 00321 vp.whiteness, vp.depth, vp.palette); 00322 if (ioctl_nointr(itsFd, VIDIOCSPICT, &vp) != 0) 00323 IDPLERROR("ioctl(VIDIOCSPICT) set picture properties failed"); 00324 } 00325 00326 // ###################################################################### 00327 void V4Lgrabber::stop2() 00328 { 00329 if (itsMmapBuf) { munmap(itsMmapBuf, itsTotalBufSize); itsMmapBuf = NULL; } 00330 if (itsFd >= 0) { close(itsFd); itsFd = -1; } 00331 if (itsGrabbing) { delete [] itsGrabbing; itsGrabbing = NULL; } 00332 itsReadBuf = Image<byte>(); 00333 itsStreamStarted = false; 00334 } 00335 00336 // ###################################################################### 00337 V4Lgrabber::~V4Lgrabber() 00338 { } 00339 00340 // ###################################################################### 00341 void V4Lgrabber::setListener(rutz::shared_ptr<FrameListener> listener) 00342 { 00343 itsListener = listener; 00344 } 00345 00346 // ###################################################################### 00347 void V4Lgrabber::startStream() 00348 { 00349 // reset itsStreamStarted so that we wait for any pending frames to 00350 // be grabbed, then start fresh grabbing requests: 00351 itsStreamStarted = false; 00352 00353 this->restartStream(); 00354 } 00355 00356 // ###################################################################### 00357 SimTime V4Lgrabber::getNaturalFrameTime() const 00358 { 00359 return itsFrameTime; 00360 } 00361 00362 // ###################################################################### 00363 GenericFrameSpec V4Lgrabber::peekFrameSpec() 00364 { 00365 GenericFrameSpec result; 00366 00367 result.nativeType = GenericFrame::VIDEO; 00368 result.videoFormat = itsGrabMode.getVal(); 00369 result.videoByteSwap = itsByteSwap.getVal(); 00370 result.dims = itsDims.getVal(); 00371 result.floatFlags = 0; 00372 00373 return result; 00374 } 00375 00376 // ###################################################################### 00377 GenericFrame V4Lgrabber::readFrame() 00378 { 00379 const GenericFrame frame = 00380 itsStreamingMode.getVal() 00381 ? GenericFrame(this->grabRaw()) 00382 : GenericFrame(this->grabSingleRaw()); 00383 00384 if (itsListener.get() != 0) 00385 itsListener->onRawFrame(frame); 00386 00387 return frame; 00388 } 00389 00390 // ###################################################################### 00391 VideoFrame V4Lgrabber::grabRaw() 00392 { 00393 byte* result = 0; 00394 if (itsMmapBuf) // mmap interface 00395 { 00396 this->restartStream(); 00397 00398 result = itsMmapBuf + itsCurrentFrame * (itsTotalBufSize / itsNumBufFrames); 00399 00400 // are we already grabbing buffer 'itsCurrentFrame'? otherwise, 00401 // start the grab now: 00402 if (itsGrabbing[itsCurrentFrame] == false) 00403 { 00404 itsVmmInfo.frame = itsCurrentFrame; 00405 itsGrabbing[itsCurrentFrame] = true; 00406 if (ioctl_nointr(itsFd, VIDIOCMCAPTURE, &itsVmmInfo) < 0) 00407 IDPLFATAL("VIDIOCMCAPTURE (frame %d)", itsCurrentFrame); 00408 } 00409 00410 // wait until buffer 'itsCurrentFrame' has been fully captured: 00411 if (ioctl_nointr(itsFd, VIDIOCSYNC, &itsCurrentFrame) < 0) 00412 IDPLFATAL("VIDIOCSYNC (frame %d)", itsCurrentFrame); 00413 itsGrabbing[itsCurrentFrame] = false; 00414 00415 // get ready for capture of that frame again (for later): 00416 itsVmmInfo.frame = itsCurrentFrame; 00417 itsGrabbing[itsCurrentFrame] = true; 00418 if (ioctl_nointr(itsFd, VIDIOCMCAPTURE, &itsVmmInfo) < 0) 00419 IDPLFATAL("VIDIOCMCAPTURE (frame %d)", itsCurrentFrame); 00420 } 00421 else // read() interface 00422 { 00423 ASSERT(itsReadBuf.initialized()); 00424 const ssize_t nbytes = 00425 read(itsFd, itsReadBuf.getArrayPtr(), itsReadBuf.getSize()); 00426 if (nbytes < 0) 00427 IDPLFATAL("read() failed"); 00428 PLDEBUG("got %zd bytes", nbytes); 00429 result = itsReadBuf.getArrayPtr(); 00430 } 00431 00432 // switch to another frame: 00433 ++itsCurrentFrame; 00434 if (itsCurrentFrame >= itsNumBufFrames) itsCurrentFrame = 0; 00435 00436 // return pointer to last-grabbed frame. You have a bit of time to 00437 // get a hold of the data but beware that an order to capture that 00438 // buffer has already been issued, so as soon as the grabber gets to 00439 // it, it will overwrite this buffer with a new frame: 00440 ASSERT(result != 0); 00441 VideoFrame frame(result, (itsTotalBufSize / itsNumBufFrames), 00442 itsDims.getVal(), 00443 itsGrabMode.getVal(), itsByteSwap.getVal(), 00444 /* strictLength = */ false); 00445 00446 return frame; 00447 } 00448 00449 // ###################################################################### 00450 void V4Lgrabber::paramChanged(ModelParamBase* const param, 00451 const bool valueChanged, 00452 ParamClient::ChangeStatus* status) 00453 { 00454 00455 FrameIstream::paramChanged(param, valueChanged, status); 00456 00457 // set picture properties 00458 if (valueChanged) 00459 { 00460 //FIXME 00461 /*struct video_picture vp; 00462 vp.brightness = itsBrightness.getVal(); 00463 vp.hue = itsHue.getVal(); 00464 vp.colour = itsColour.getVal(); 00465 vp.contrast = itsContrast.getVal(); 00466 vp.whiteness = itsWhiteness.getVal(); 00467 vp.palette = itsVmmInfo.format; 00468 LINFO("bright=%u hue=%u color=%u contrast=%u white=%u depth=%u palette=%u", 00469 vp.brightness, vp.hue, vp.colour, vp.contrast, 00470 vp.whiteness, vp.depth, vp.palette); 00471 if (ioctl_nointr(itsFd, VIDIOCSPICT, &vp) != 0) 00472 { 00473 LERROR("ioctl(VIDIOCSPICT) set picture properties failed"); 00474 *status = ParamClient::CHANGE_REJECTED; 00475 }*/ 00476 } 00477 00478 00479 00480 } 00481 00482 00483 // ###################################################################### 00484 VideoFrame V4Lgrabber::grabSingleRaw() 00485 { 00486 byte* result = 0; 00487 if (itsMmapBuf) // mmap interface 00488 { 00489 itsCurrentFrame = 0; 00490 result = itsMmapBuf; 00491 00492 // are we already grabbing buffer 'itsCurrentFrame'? otherwise, 00493 // start the grab now: 00494 if (itsGrabbing[itsCurrentFrame] == false) 00495 { 00496 itsVmmInfo.frame = itsCurrentFrame; 00497 itsGrabbing[itsCurrentFrame] = true; 00498 if (ioctl_nointr(itsFd, VIDIOCMCAPTURE, &itsVmmInfo) < 0) 00499 IDPLFATAL("VIDIOCMCAPTURE (frame %d)", itsCurrentFrame); 00500 } 00501 00502 // wait until grab is complete: 00503 if (ioctl_nointr(itsFd, VIDIOCSYNC, &itsCurrentFrame) < 0) 00504 IDPLFATAL("VIDIOCSYNC (frame %d)", itsCurrentFrame); 00505 itsGrabbing[itsCurrentFrame] = false; 00506 } 00507 else // read() interface 00508 { 00509 ASSERT(itsReadBuf.initialized()); 00510 const ssize_t nbytes = 00511 read(itsFd, itsReadBuf.getArrayPtr(), itsReadBuf.getSize()); 00512 if (nbytes < 0) 00513 IDPLFATAL("read() failed (frame %d)", itsCurrentFrame); 00514 PLDEBUG("got %zd bytes", nbytes); 00515 result = itsReadBuf.getArrayPtr(); 00516 } 00517 00518 // return grabbed & converted frame: 00519 VideoFrame frame(result, (itsTotalBufSize / itsNumBufFrames), 00520 itsDims.getVal(), 00521 itsGrabMode.getVal(), itsByteSwap.getVal(), 00522 /* strictLength = */ false); 00523 00524 return frame; 00525 } 00526 00527 // ###################################################################### 00528 void V4Lgrabber::restartStream() 00529 { 00530 if (itsStreamingMode.getVal() 00531 && itsMmapBuf 00532 && !itsStreamStarted) 00533 { 00534 for (int i = 0; i < itsNumBufFrames; ++i) 00535 { 00536 // are we already grabbing buffer i? if so, wait for grab 00537 // to finished if we've requested resync (if we don't do 00538 // this, then the first few frames after a restart will be 00539 // wrong -- they'll come too quickly and they'll be too old, 00540 // since the v4l driver doesn't grab new frames into buffers 00541 // until the old frames have been retrieved): 00542 if (itsGrabbing[i] == true) 00543 { 00544 if (ioctl_nointr(itsFd, VIDIOCSYNC, &i) < 0) 00545 IDPLFATAL("VIDIOCSYNC (frame %d)", i); 00546 LINFO("flushed buffer %d", i); 00547 itsGrabbing[i] = false; 00548 } 00549 } 00550 00551 for (int i = 0; i < itsNumBufFrames; ++i) 00552 { 00553 // now start a fresh grab for buffer i: 00554 itsVmmInfo.frame = i; itsGrabbing[i] = true; 00555 if (ioctl_nointr(itsFd, VIDIOCMCAPTURE, &itsVmmInfo) < 0) 00556 IDPLFATAL("VIDIOCMCAPTURE (frame %d)", i); 00557 } 00558 00559 itsCurrentFrame = 0; 00560 00561 itsStreamStarted = true; 00562 } 00563 } 00564 00565 #endif // HAVE_LINUX_VIDEODEV_H 00566 00567 // ###################################################################### 00568 /* So things look consistent in everyone's emacs... */ 00569 /* Local Variables: */ 00570 /* indent-tabs-mode: nil */ 00571 /* End: */