v4l.cpp
Go to the documentation of this file.
00001 /* This file is part of the Pangolin Project,
00002  * http://github.com/stevenlovegrove/Pangolin
00003  * Copyright (c) 2011 Steven Lovegrove
00004  *
00005  * adapted from V4L2 video capture example
00006  *
00007  * Permission is hereby granted, free of charge, to any person
00008  * obtaining a copy of this software and associated documentation
00009  * files (the "Software"), to deal in the Software without
00010  * restriction, including without limitation the rights to use,
00011  * copy, modify, merge, publish, distribute, sublicense, and/or sell
00012  * copies of the Software, and to permit persons to whom the
00013  * Software is furnished to do so, subject to the following
00014  * conditions:
00015  *
00016  * The above copyright notice and this permission notice shall be
00017  * included in all copies or substantial portions of the Software.
00018  *
00019  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00020  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
00021  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00022  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
00023  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
00024  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00025  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00026  * OTHER DEALINGS IN THE SOFTWARE.
00027  */
00028 
00029 #include "v4l.h"
00030 
00031 #include <iostream>
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <assert.h>
00036 
00037 #include <fcntl.h>
00038 #include <unistd.h>
00039 #include <errno.h>
00040 #include <malloc.h>
00041 #include <sys/stat.h>
00042 #include <sys/types.h>
00043 #include <sys/time.h>
00044 #include <sys/mman.h>
00045 #include <sys/ioctl.h>
00046 
00047 #define CLEAR(x) memset (&(x), 0, sizeof (x))
00048 
00049 using namespace std;
00050 
00051 namespace pangolin
00052 {
00053 
00054 static int xioctl(int fd, int request, void* arg)
00055 {
00056     int r;
00057     do r = ioctl (fd, request, arg);
00058     while (-1 == r && EINTR == errno);
00059     return r;
00060 }
00061 
00062 V4lVideo::V4lVideo(const char* dev_name, io_method io)
00063     : io(io), fd(-1), buffers(0), n_buffers(0), running(false)
00064 {
00065     open_device(dev_name);
00066     init_device(dev_name,640,480,30);
00067     Start();
00068 }
00069 
00070 V4lVideo::~V4lVideo()
00071 {
00072     if(running)
00073     {
00074         Stop();
00075     }
00076 
00077     uninit_device();
00078     close_device();
00079 }
00080 
00081 unsigned V4lVideo::Width() const
00082 {
00083     return width;
00084 }
00085 
00086 unsigned V4lVideo::Height() const
00087 {
00088     return height;
00089 }
00090 
00091 size_t V4lVideo::SizeBytes() const
00092 {
00093     return image_size;
00094 }
00095 
00096 std::string V4lVideo::PixFormat() const
00097 {
00098     // TODO: compute properly
00099     return "YUYV422";
00100 }
00101 
00102 bool V4lVideo::GrabNext( unsigned char* image, bool wait )
00103 {
00104     for (;;)
00105     {
00106         fd_set fds;
00107         struct timeval tv;
00108         int r;
00109 
00110         FD_ZERO (&fds);
00111         FD_SET (fd, &fds);
00112 
00113         /* Timeout. */
00114         tv.tv_sec = 2;
00115         tv.tv_usec = 0;
00116 
00117         r = select (fd + 1, &fds, NULL, NULL, &tv);
00118 
00119         if (-1 == r)
00120         {
00121             if (EINTR == errno)
00122                 continue;
00123 
00124             throw VideoException ("select", strerror(errno));
00125         }
00126 
00127         if (0 == r)
00128         {
00129             throw VideoException("select Timeout", strerror(errno));
00130         }
00131 
00132         if (ReadFrame(image))
00133             break;
00134 
00135         /* EAGAIN - continue select loop. */
00136     }
00137     return true;
00138 }
00139 
00140 bool V4lVideo::GrabNewest( unsigned char* image, bool wait )
00141 {
00142     // TODO: Implement
00143     return GrabNext(image,wait);
00144 }
00145 
00146 int V4lVideo::ReadFrame(unsigned char* image)
00147 {
00148     struct v4l2_buffer buf;
00149     unsigned int i;
00150 
00151     switch (io)
00152     {
00153     case IO_METHOD_READ:
00154         if (-1 == read (fd, buffers[0].start, buffers[0].length))
00155         {
00156             switch (errno)
00157             {
00158             case EAGAIN:
00159                 return 0;
00160 
00161             case EIO:
00162                 /* Could ignore EIO, see spec. */
00163 
00164                 /* fall through */
00165 
00166             default:
00167                 throw VideoException("read", strerror(errno));
00168             }
00169         }
00170 
00171 //            process_image(buffers[0].start);
00172         memcpy(image,buffers[0].start,buffers[0].length);
00173 
00174         break;
00175 
00176     case IO_METHOD_MMAP:
00177         CLEAR (buf);
00178 
00179         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00180         buf.memory = V4L2_MEMORY_MMAP;
00181 
00182         if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf))
00183         {
00184             switch (errno)
00185             {
00186             case EAGAIN:
00187                 return 0;
00188 
00189             case EIO:
00190                 /* Could ignore EIO, see spec. */
00191 
00192                 /* fall through */
00193 
00194             default:
00195                 throw VideoException("VIDIOC_DQBUF", strerror(errno));
00196             }
00197         }
00198 
00199         assert (buf.index < n_buffers);
00200 
00201 //            process_image (buffers[buf.index].start);
00202         memcpy(image,buffers[buf.index].start,buffers[buf.index].length);
00203 
00204 
00205         if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00206             throw VideoException("VIDIOC_QBUF", strerror(errno));
00207 
00208         break;
00209 
00210     case IO_METHOD_USERPTR:
00211         CLEAR (buf);
00212 
00213         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00214         buf.memory = V4L2_MEMORY_USERPTR;
00215 
00216         if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf))
00217         {
00218             switch (errno)
00219             {
00220             case EAGAIN:
00221                 return 0;
00222 
00223             case EIO:
00224                 /* Could ignore EIO, see spec. */
00225 
00226                 /* fall through */
00227 
00228             default:
00229                 throw VideoException("VIDIOC_DQBUF", strerror(errno));
00230             }
00231         }
00232 
00233         for (i = 0; i < n_buffers; ++i)
00234             if (buf.m.userptr == (unsigned long) buffers[i].start
00235                     && buf.length == buffers[i].length)
00236                 break;
00237 
00238         assert (i < n_buffers);
00239 
00240 //            process_image ((void *) buf.m.userptr);
00241         memcpy(image,(void *)buf.m.userptr,buf.length);
00242 
00243 
00244         if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00245             throw VideoException("VIDIOC_QBUF", strerror(errno));
00246 
00247         break;
00248     }
00249 
00250     return 1;
00251 }
00252 
00253 void V4lVideo::Stop()
00254 {
00255     enum v4l2_buf_type type;
00256 
00257     switch (io)
00258     {
00259     case IO_METHOD_READ:
00260         /* Nothing to do. */
00261         break;
00262 
00263     case IO_METHOD_MMAP:
00264     case IO_METHOD_USERPTR:
00265         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00266 
00267         if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type))
00268             throw VideoException("VIDIOC_STREAMOFF", strerror(errno));
00269 
00270         break;
00271     }
00272 
00273     running = false;
00274 }
00275 
00276 void V4lVideo::Start()
00277 {
00278     unsigned int i;
00279     enum v4l2_buf_type type;
00280 
00281     switch (io)
00282     {
00283     case IO_METHOD_READ:
00284         /* Nothing to do. */
00285         break;
00286 
00287     case IO_METHOD_MMAP:
00288         for (i = 0; i < n_buffers; ++i)
00289         {
00290             struct v4l2_buffer buf;
00291 
00292             CLEAR (buf);
00293 
00294             buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00295             buf.memory      = V4L2_MEMORY_MMAP;
00296             buf.index       = i;
00297 
00298             if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00299                 throw VideoException("VIDIOC_QBUF", strerror(errno));
00300         }
00301 
00302         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00303 
00304         if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
00305             throw VideoException("VIDIOC_STREAMON", strerror(errno));
00306 
00307         break;
00308 
00309     case IO_METHOD_USERPTR:
00310         for (i = 0; i < n_buffers; ++i)
00311         {
00312             struct v4l2_buffer buf;
00313 
00314             CLEAR (buf);
00315 
00316             buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00317             buf.memory      = V4L2_MEMORY_USERPTR;
00318             buf.index       = i;
00319             buf.m.userptr   = (unsigned long) buffers[i].start;
00320             buf.length      = buffers[i].length;
00321 
00322             if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00323                 throw VideoException("VIDIOC_QBUF", strerror(errno));
00324         }
00325 
00326         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00327 
00328         if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
00329             throw VideoException ("VIDIOC_STREAMON", strerror(errno));
00330 
00331         break;
00332     }
00333 
00334     running = true;
00335 }
00336 
00337 void V4lVideo::uninit_device()
00338 {
00339     unsigned int i;
00340 
00341     switch (io)
00342     {
00343     case IO_METHOD_READ:
00344         free (buffers[0].start);
00345         break;
00346 
00347     case IO_METHOD_MMAP:
00348         for (i = 0; i < n_buffers; ++i)
00349             if (-1 == munmap (buffers[i].start, buffers[i].length))
00350                 throw VideoException ("munmap");
00351         break;
00352 
00353     case IO_METHOD_USERPTR:
00354         for (i = 0; i < n_buffers; ++i)
00355             free (buffers[i].start);
00356         break;
00357     }
00358 
00359     free (buffers);
00360 }
00361 
00362 void V4lVideo::init_read(unsigned int buffer_size)
00363 {
00364     buffers = (buffer*)calloc (1, sizeof (buffer));
00365 
00366     if (!buffers)
00367     {
00368         throw VideoException("Out of memory\n");
00369     }
00370 
00371     buffers[0].length = buffer_size;
00372     buffers[0].start = malloc (buffer_size);
00373 
00374     if (!buffers[0].start)
00375     {
00376         throw VideoException("Out of memory\n");
00377     }
00378 }
00379 
00380 void V4lVideo::init_mmap(const char* dev_name)
00381 {
00382     struct v4l2_requestbuffers req;
00383 
00384     CLEAR (req);
00385 
00386     req.count               = 4;
00387     req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00388     req.memory              = V4L2_MEMORY_MMAP;
00389 
00390     if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req))
00391     {
00392         if (EINVAL == errno)
00393         {
00394             throw VideoException("does not support memory mapping", strerror(errno));
00395         }
00396         else
00397         {
00398             throw VideoException ("VIDIOC_REQBUFS", strerror(errno));
00399         }
00400     }
00401 
00402     if (req.count < 2)
00403     {
00404         throw VideoException("Insufficient buffer memory");
00405     }
00406 
00407     buffers = (buffer*)calloc(req.count, sizeof(buffer));
00408 
00409     if (!buffers)
00410     {
00411         throw VideoException( "Out of memory\n");
00412     }
00413 
00414     for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
00415     {
00416         struct v4l2_buffer buf;
00417 
00418         CLEAR (buf);
00419 
00420         buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00421         buf.memory      = V4L2_MEMORY_MMAP;
00422         buf.index       = n_buffers;
00423 
00424         if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf))
00425             throw VideoException ("VIDIOC_QUERYBUF", strerror(errno));
00426 
00427         buffers[n_buffers].length = buf.length;
00428         buffers[n_buffers].start =
00429             mmap (NULL /* start anywhere */,
00430                   buf.length,
00431                   PROT_READ | PROT_WRITE /* required */,
00432                   MAP_SHARED /* recommended */,
00433                   fd, buf.m.offset);
00434 
00435         if (MAP_FAILED == buffers[n_buffers].start)
00436             throw VideoException ("mmap");
00437     }
00438 }
00439 
00440 void V4lVideo::init_userp(const char* dev_name, unsigned int buffer_size)
00441 {
00442     struct v4l2_requestbuffers req;
00443     unsigned int page_size;
00444 
00445     page_size = getpagesize ();
00446     buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1);
00447 
00448     CLEAR (req);
00449 
00450     req.count               = 4;
00451     req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00452     req.memory              = V4L2_MEMORY_USERPTR;
00453 
00454     if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req))
00455     {
00456         if (EINVAL == errno)
00457         {
00458             throw VideoException( "Does not support user pointer i/o", strerror(errno));
00459         }
00460         else
00461         {
00462             throw VideoException ("VIDIOC_REQBUFS", strerror(errno));
00463         }
00464     }
00465 
00466     buffers = (buffer*)calloc(4, sizeof(buffer));
00467 
00468     if (!buffers)
00469     {
00470         throw VideoException( "Out of memory\n");
00471     }
00472 
00473     for (n_buffers = 0; n_buffers < 4; ++n_buffers)
00474     {
00475         buffers[n_buffers].length = buffer_size;
00476         buffers[n_buffers].start = memalign (/* boundary */ page_size,
00477                                    buffer_size);
00478 
00479         if (!buffers[n_buffers].start)
00480         {
00481             throw VideoException( "Out of memory\n");
00482         }
00483     }
00484 }
00485 
00486 void V4lVideo::init_device(const char* dev_name, unsigned iwidth, unsigned iheight, unsigned ifps, unsigned v4l_format, v4l2_field field)
00487 {
00488     struct v4l2_capability cap;
00489     struct v4l2_cropcap cropcap;
00490     struct v4l2_crop crop;
00491     struct v4l2_format fmt;
00492     struct v4l2_streamparm strm;
00493 
00494     unsigned int min;
00495 
00496     if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap))
00497     {
00498         if (EINVAL == errno)
00499         {
00500             throw VideoException("Not a V4L2 device", strerror(errno));
00501         }
00502         else
00503         {
00504             throw VideoException ("VIDIOC_QUERYCAP", strerror(errno));
00505         }
00506     }
00507 
00508     if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
00509     {
00510         throw VideoException("Not a video capture device");
00511     }
00512 
00513     switch (io)
00514     {
00515     case IO_METHOD_READ:
00516         if (!(cap.capabilities & V4L2_CAP_READWRITE))
00517         {
00518             throw VideoException("Does not support read i/o");
00519         }
00520 
00521         break;
00522 
00523     case IO_METHOD_MMAP:
00524     case IO_METHOD_USERPTR:
00525         if (!(cap.capabilities & V4L2_CAP_STREAMING))
00526         {
00527             throw VideoException("Does not support streaming i/o");
00528         }
00529 
00530         break;
00531     }
00532 
00533 
00534     /* Select video input, video standard and tune here. */
00535 
00536     CLEAR (cropcap);
00537 
00538     cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00539 
00540     if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap))
00541     {
00542         crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00543         crop.c = cropcap.defrect; /* reset to default */
00544 
00545         if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop))
00546         {
00547             switch (errno)
00548             {
00549             case EINVAL:
00550                 /* Cropping not supported. */
00551                 break;
00552             default:
00553                 /* Errors ignored. */
00554                 break;
00555             }
00556         }
00557     }
00558     else
00559     {
00560         /* Errors ignored. */
00561     }
00562 
00563 //        {
00564 //            v4l2_frmivalenum fie;
00565 //            CLEAR(fie);
00566 //            fie.width = iwidth;
00567 //            fie.height = iheight;
00568 //            fie.pixel_format = v4l_format;
00569 
00570 //            while(1)
00571 //            {
00572 
00573 //                if (-1 == xioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &fie))
00574 //                    throw VideoException("VIDIOC_ENUM_FRAMEINTERVALS", strerror(errno));
00575 
00576 //                cout << fie.type << endl;
00577 //                cout << fie.discrete.numerator << endl;
00578 //                cout << fie.discrete.denominator << endl << endl;
00579 //                fie.index++;
00580 //            }
00581 //        }
00582 
00583 
00584     CLEAR (fmt);
00585 
00586     fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00587     fmt.fmt.pix.width       = iwidth;
00588     fmt.fmt.pix.height      = iheight;
00589     fmt.fmt.pix.pixelformat = v4l_format;
00590     fmt.fmt.pix.field       = field;
00591 
00592     if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt))
00593         throw VideoException("VIDIOC_S_FMT", strerror(errno));
00594 
00595     /* Buggy driver paranoia. */
00596     min = fmt.fmt.pix.width * 2;
00597     if (fmt.fmt.pix.bytesperline < min)
00598         fmt.fmt.pix.bytesperline = min;
00599     min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
00600     if (fmt.fmt.pix.sizeimage < min)
00601         fmt.fmt.pix.sizeimage = min;
00602 
00603     /* Note VIDIOC_S_FMT may change width and height. */
00604     width = fmt.fmt.pix.width;
00605     height = fmt.fmt.pix.height;
00606     image_size = fmt.fmt.pix.sizeimage;
00607 
00608 
00609     CLEAR(strm);
00610     strm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00611     strm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
00612     strm.parm.capture.timeperframe.numerator = 1;
00613     strm.parm.capture.timeperframe.denominator = ifps;
00614 
00615     if (-1 == xioctl (fd, VIDIOC_S_PARM, &fmt))
00616         throw VideoException("VIDIOC_S_PARM", strerror(errno));
00617 
00618     fps = (float)strm.parm.capture.timeperframe.denominator / strm.parm.capture.timeperframe.numerator;
00619 
00620     switch (io)
00621     {
00622     case IO_METHOD_READ:
00623         init_read (fmt.fmt.pix.sizeimage);
00624         break;
00625 
00626     case IO_METHOD_MMAP:
00627         init_mmap (dev_name );
00628         break;
00629 
00630     case IO_METHOD_USERPTR:
00631         init_userp (dev_name, fmt.fmt.pix.sizeimage);
00632         break;
00633     }
00634 }
00635 
00636 void V4lVideo::close_device()
00637 {
00638     if (-1 == close (fd))
00639         throw VideoException("close");
00640 
00641     fd = -1;
00642 }
00643 
00644 void V4lVideo::open_device(const char* dev_name)
00645 {
00646     struct stat st;
00647 
00648     if (-1 == stat (dev_name, &st))
00649     {
00650         throw VideoException("Cannot stat device", strerror(errno));
00651     }
00652 
00653     if (!S_ISCHR (st.st_mode))
00654     {
00655         throw VideoException("Not device");
00656     }
00657 
00658     fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
00659 
00660     if (-1 == fd)
00661     {
00662         throw VideoException("Cannot open device");
00663     }
00664 }
00665 
00666 }
00667 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines


pangolin_wrapper
Author(s): Todor Stoyanov
autogenerated on Wed Feb 13 2013 14:03:25