capture.cc

00001 /*
00002  *  V4L2 video capture example
00003  *
00004  *  This program can be used and distributed without restrictions.
00005  */
00006 
00007 #include <stdio.h>
00008 
00009 #include "capture.h"
00010 
00011 int RGB_Y_tab[256];
00012 int B_U_tab[256];
00013 int G_U_tab[256];
00014 int G_V_tab[256];
00015 int R_V_tab[256];
00016 const int BITS_OUT = 16;
00017 char*           dev_name        = "/dev/video0";
00018 io_method       io              = IO_METHOD_MMAP;
00019 //io_method     io              = IO_METHOD_READ;
00020 int              fd              = -1;
00021 buffer*         buffers         = NULL;
00022 unsigned int     n_buffers       = 0;
00023 //int width = 160, height = 120;
00024 int width = 320, height = 240;
00025 frame* currentFrame = NULL;
00026 
00027 void errno_exit(const char *s)
00028 {
00029   printf ("%s error %d, %s\n",
00030       s, errno, strerror (errno));
00031   exit (0);
00032 }
00033 
00034 int xioctl(int fd, int request, void *arg)
00035 {
00036   int r;
00037 
00038   do r = ioctl (fd, request, arg);
00039   while (-1 == r && EINTR == errno);
00040 
00041   return r;
00042 }
00043 
00044 void colorspace_init()
00045 {
00046   const int VIDEOYUV_Y_OFFSET  = 16;
00047   const int VIDEOYUV_Y_RANGE   = 219; // Y range = [16,235]
00048   const int VIDEOYUV_UV_OFFSET = 128;
00049   const int VIDEOYUV_UV_RANGE  = 224; // UV range = [16,240]
00050 
00051   const double JPEGYUV_RGB_Y =  1.0;
00052   const double JPEGYUV_R_V   =  1.402;
00053   const double JPEGYUV_G_U   = -0.34414;
00054   const double JPEGYUV_G_V   = -0.71414;
00055   const double JPEGYUV_B_U   =  1.772;
00056 
00057   const double VIDEOYUV_RGB_Y = JPEGYUV_RGB_Y * (255.0/VIDEOYUV_Y_RANGE);
00058   const double VIDEOYUV_R_V   = JPEGYUV_R_V   * (255.0/VIDEOYUV_UV_RANGE);
00059   const double VIDEOYUV_G_U   = JPEGYUV_G_U   * (255.0/VIDEOYUV_UV_RANGE);
00060   const double VIDEOYUV_G_V   = JPEGYUV_G_V   * (255.0/VIDEOYUV_UV_RANGE);
00061   const double VIDEOYUV_B_U   = JPEGYUV_B_U   * (255.0/VIDEOYUV_UV_RANGE);
00062 
00063 
00064   // so that we get proper rounding in fixed-point integer arithmetic:
00065   const int half =
00066     BITS_OUT > 0
00067     ? 1<<(BITS_OUT-1)
00068     : 0;
00069 
00070   const int scale = 1<<BITS_OUT;
00071 
00072   int i;
00073   for (i = 0; i < 256; i++)
00074   {
00075     const int y  = i-VIDEOYUV_Y_OFFSET;
00076     const int uv = i-VIDEOYUV_UV_OFFSET;
00077 
00078     RGB_Y_tab[i] = half+(int)(0.5 + y  * VIDEOYUV_RGB_Y * scale);
00079     R_V_tab[i]   =      (int)(0.5 + uv * VIDEOYUV_R_V   * scale);
00080     // FIXME should probably have -0.5 instead of +0.5 here and
00081     // flip the sign of G_U_tab and G_V_tab:
00082     G_U_tab[i]   =      (int)(0.5 - uv * VIDEOYUV_G_U   * scale);
00083     G_V_tab[i]   =      (int)(0.5 - uv * VIDEOYUV_G_V   * scale);
00084     B_U_tab[i]   =      (int)(0.5 + uv * VIDEOYUV_B_U   * scale);
00085   }
00086 }
00087 
00088 
00089 void yuv422_to_rgb24_c(unsigned char* dst,
00090                        const int w, const int h,
00091                        const unsigned char* yuv422ptr,
00092                        const int byteswap)
00093 {
00094   int i, j;
00095   if (byteswap)
00096     for (j = 0; j < h; ++j)
00097       for (i = 0; i < w; i += 2)
00098         {
00099           // we have 2 luminance pixels per chroma pair
00100 
00101           const unsigned char y1 = yuv422ptr[0];
00102           const unsigned char u = yuv422ptr[1];
00103           const unsigned char y2 = yuv422ptr[2];
00104           const unsigned char v = yuv422ptr[3];
00105 
00106           yuv422ptr += 4;
00107 
00108           const int r_v = R_V_tab[v];
00109           const int g_uv = - G_U_tab[u] - G_V_tab[v];
00110           const int b_u = B_U_tab[u];
00111 
00112           // first luminance pixel:
00113           const int rgb_y1 = RGB_Y_tab[y1];
00114 
00115           *dst++ = (rgb_y1 + r_v) >> BITS_OUT;
00116           *dst++ = (rgb_y1 + g_uv) >> BITS_OUT;
00117           *dst++ = (rgb_y1 + b_u) >> BITS_OUT;
00118 
00119           // second luminance pixel:
00120           const int rgb_y2 = RGB_Y_tab[y2];
00121 
00122           *dst++ = (rgb_y2 + r_v) >> BITS_OUT;
00123           *dst++ = (rgb_y2 + g_uv) >> BITS_OUT;
00124           *dst++ = (rgb_y2 + b_u) >> BITS_OUT;
00125         }
00126 
00127   else // no unsigned charswap
00128     for ( j = 0; j < h; ++j)
00129       for ( i = 0; i < w; i += 2)
00130         {
00131           // we have 2 luminance pixels per chroma pair
00132 
00133           const unsigned char y1 = yuv422ptr[1];
00134           const unsigned char u = yuv422ptr[0];
00135           const unsigned char y2 = yuv422ptr[3];
00136           const unsigned char v = yuv422ptr[2];
00137 
00138           yuv422ptr += 4;
00139 
00140           const int r_v = R_V_tab[v];
00141           const int g_uv = - G_U_tab[u] - G_V_tab[v];
00142           const int b_u = B_U_tab[u];
00143 
00144           // first luminance pixel:
00145           const int rgb_y1 = RGB_Y_tab[y1];
00146 
00147           *dst++ = (rgb_y1 + r_v) >> BITS_OUT;
00148           *dst++ = (rgb_y1 + g_uv) >> BITS_OUT;
00149           *dst++ = (rgb_y1 + b_u) >> BITS_OUT;
00150 
00151           // second luminance pixel:
00152           const int rgb_y2 = RGB_Y_tab[y2];
00153 
00154           *dst++ = (rgb_y2 + r_v) >> BITS_OUT;
00155           *dst++ = (rgb_y2 + g_uv) >> BITS_OUT;
00156           *dst++ = (rgb_y2 + b_u) >> BITS_OUT;
00157         }
00158 }
00159 
00160 unsigned char clamp(int d)
00161 {
00162   int r = d;
00163   if (r > 255) r = 255;
00164   if (r < 0) r = 0;
00165 
00166   return r;
00167 }
00168 
00169 void yv12_to_rgb24_c(unsigned char* dst,
00170                      int dst_stride,
00171                      const unsigned char* y_src,
00172                      const unsigned char* u_src,
00173                      const unsigned char* v_src,
00174                      int y_stride,
00175                      int uv_stride,
00176                      int width,
00177                      int height)
00178 {
00179 
00180   if (width & 1)
00181     printf("width must be even\n");
00182 
00183   if (height & 1)
00184     printf("height must be even\n");
00185 
00186   const int dst_dif = 6 * dst_stride - 3 * width;
00187   int y_dif = 2 * y_stride - width;
00188 
00189   unsigned char* dst2 = dst + 3 * dst_stride;
00190   const unsigned char* y_src2 = y_src + y_stride;
00191 
00192   if (height < 0) {                     /* flip image? */
00193     height = -height;
00194     y_src += (height - 1) * y_stride;
00195     y_src2 = y_src - y_stride;
00196     u_src += (height / 2 - 1) * uv_stride;
00197     v_src += (height / 2 - 1) * uv_stride;
00198     y_dif = -width - 2 * y_stride;
00199     uv_stride = -uv_stride;
00200   }
00201 
00202   int x,y;
00203   for (y = height / 2; y; y--) {
00204     for (x = 0; x < width / 2; x++) {
00205       const int u = u_src[x];
00206       const int v = v_src[x];
00207 
00208       const int r_v = R_V_tab[v];
00209       const int g_uv = - G_U_tab[u] - G_V_tab[v];
00210       const int b_u = B_U_tab[u];
00211 
00212       {
00213         const int rgb_y = RGB_Y_tab[*y_src];
00214         const int r = (rgb_y + r_v) >> BITS_OUT;
00215         const int g = (rgb_y + g_uv) >> BITS_OUT;
00216         const int b = (rgb_y + b_u) >> BITS_OUT;
00217         dst[0] = clamp(r);
00218         dst[1] = clamp(g);
00219         dst[2] = clamp(b);
00220         y_src++;
00221       }
00222       {
00223         const int rgb_y = RGB_Y_tab[*y_src];
00224         const int r = (rgb_y + r_v) >> BITS_OUT;
00225         const int g = (rgb_y + g_uv) >> BITS_OUT;
00226         const int b = (rgb_y + b_u) >> BITS_OUT;
00227         dst[3] = clamp(r);
00228         dst[4] = clamp(g);
00229         dst[5] = clamp(b);
00230         y_src++;
00231       }
00232       {
00233         const int rgb_y = RGB_Y_tab[*y_src2];
00234         const int r = (rgb_y + r_v) >> BITS_OUT;
00235         const int g = (rgb_y + g_uv) >> BITS_OUT;
00236         const int b = (rgb_y + b_u) >> BITS_OUT;
00237         dst2[0] = clamp(r);
00238         dst2[1] = clamp(g);
00239         dst2[2] = clamp(b);
00240         y_src2++;
00241       }
00242       {
00243         const int rgb_y = RGB_Y_tab[*y_src2];
00244         const int r = (rgb_y + r_v) >> BITS_OUT;
00245         const int g = (rgb_y + g_uv) >> BITS_OUT;
00246         const int b = (rgb_y + b_u) >> BITS_OUT;
00247         dst2[3] = clamp(r);
00248         dst2[4] = clamp(g);
00249         dst2[5] = clamp(b);
00250         y_src2++;
00251       }
00252 
00253       dst += 6;
00254       dst2 += 6;
00255     }
00256 
00257     dst += dst_dif;
00258     dst2 += dst_dif;
00259 
00260     y_src += y_dif;
00261     y_src2 += y_dif;
00262 
00263     u_src += uv_stride;
00264     v_src += uv_stride;
00265   }
00266 }
00267 
00268 frame* process_image(const void *p, const int len)
00269 {
00270 
00271   const int w2 = (width+1)/2;
00272   const int h2 = (height+1)/2;
00273 
00274   yv12_to_rgb24_c(currentFrame->data,
00275                   width, // dst_stride ,
00276                   (const unsigned char*)p,
00277                   (const unsigned char*)p + width*height,
00278                   (const unsigned char*)p + width*height + w2*h2,
00279                   width, // y_stride ,
00280                   w2, // uv_stride ,
00281                   width, // image width ,
00282                   height); // image height
00283 
00284   return currentFrame;
00285 }
00286 
00287 int read_frame(void)
00288 {
00289   struct v4l2_buffer buf;
00290   unsigned int i;
00291 
00292   switch (io) {
00293     case IO_METHOD_READ:
00294       if (-1 == (i = read (fd, buffers[0].start, buffers[0].length))) {
00295         switch (errno) {
00296           case EAGAIN:
00297             return 0;
00298 
00299           case EIO:
00300             /* Could ignore EIO, see spec. */
00301 
00302             /* fall through */
00303 
00304           default:
00305             errno_exit ("read");
00306         }
00307       }
00308 
00309       process_image (buffers[0].start, buffers[0].length);
00310 
00311       break;
00312 
00313     case IO_METHOD_MMAP:
00314       CLEAR (buf);
00315 
00316       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00317       buf.memory = V4L2_MEMORY_MMAP;
00318 
00319       // wait until buffer 'itsCurrentFrame' has been fully captured:
00320       if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
00321         switch (errno) {
00322           case EAGAIN:
00323             return 0;
00324 
00325           case EIO:
00326             /* Could ignore EIO, see spec. */
00327 
00328             /* fall through */
00329 
00330           default:
00331             errno_exit ("VIDIOC_DQBUF");
00332         }
00333       }
00334 
00335       assert (buf.index < n_buffers);
00336 
00337       process_image (buffers[buf.index].start,buffers[buf.index].length );
00338 
00339       // get ready for capture of that frame again (for later):
00340       if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00341         errno_exit ("VIDIOC_QBUF");
00342 
00343       break;
00344 
00345     case IO_METHOD_USERPTR:
00346       CLEAR (buf);
00347 
00348       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00349       buf.memory = V4L2_MEMORY_USERPTR;
00350 
00351       if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
00352         switch (errno) {
00353           case EAGAIN:
00354             return 0;
00355 
00356           case EIO:
00357             /* Could ignore EIO, see spec. */
00358 
00359             /* fall through */
00360 
00361           default:
00362             errno_exit ("VIDIOC_DQBUF");
00363         }
00364       }
00365 
00366       for (i = 0; i < n_buffers; ++i)
00367         if (buf.m.userptr == (unsigned long) buffers[i].start
00368             && buf.length == buffers[i].length)
00369           break;
00370 
00371       assert (i < n_buffers);
00372 
00373       process_image ((void *) buf.m.userptr, 0);
00374 
00375       if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00376         errno_exit ("VIDIOC_QBUF");
00377 
00378       break;
00379   }
00380 
00381   return 1;
00382 }
00383 
00384 frame* get_frame(void)
00385 {
00386   struct v4l2_buffer buf;
00387   unsigned int i;
00388 
00389   switch (io) {
00390     case IO_METHOD_READ:
00391       if (-1 == (i = read (fd, buffers[0].start, buffers[0].length))) {
00392         switch (errno) {
00393           case EAGAIN:
00394             return 0;
00395 
00396           case EIO:
00397             /* Could ignore EIO, see spec. */
00398 
00399             /* fall through */
00400 
00401           default:
00402             errno_exit ("read");
00403         }
00404       }
00405 
00406       return process_image (buffers[0].start, buffers[0].length);
00407 
00408       break;
00409 
00410     case IO_METHOD_MMAP:
00411       CLEAR (buf);
00412 
00413       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00414       buf.memory = V4L2_MEMORY_MMAP;
00415 
00416       // wait until buffer 'itsCurrentFrame' has been fully captured:
00417       if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
00418         switch (errno) {
00419           case EAGAIN:
00420             return 0;
00421 
00422           case EIO:
00423             /* Could ignore EIO, see spec. */
00424 
00425             /* fall through */
00426 
00427           default:
00428             errno_exit ("VIDIOC_DQBUF");
00429         }
00430       }
00431 
00432       assert (buf.index < n_buffers);
00433 
00434       return process_image (buffers[buf.index].start,buffers[buf.index].length );
00435 
00436       // get ready for capture of that frame again (for later):
00437       if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00438         errno_exit ("VIDIOC_QBUF");
00439 
00440       break;
00441 
00442     case IO_METHOD_USERPTR:
00443       CLEAR (buf);
00444 
00445       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00446       buf.memory = V4L2_MEMORY_USERPTR;
00447 
00448       if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
00449         switch (errno) {
00450           case EAGAIN:
00451             return 0;
00452 
00453           case EIO:
00454             /* Could ignore EIO, see spec. */
00455 
00456             /* fall through */
00457 
00458           default:
00459             errno_exit ("VIDIOC_DQBUF");
00460         }
00461       }
00462 
00463       for (i = 0; i < n_buffers; ++i)
00464         if (buf.m.userptr == (unsigned long) buffers[i].start
00465             && buf.length == buffers[i].length)
00466           break;
00467 
00468       assert (i < n_buffers);
00469 
00470       return process_image ((void *) buf.m.userptr, 0);
00471 
00472       if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00473         errno_exit ("VIDIOC_QBUF");
00474 
00475       break;
00476   }
00477 
00478   return NULL;
00479 }
00480 
00481 
00482 void mainloop(void)
00483 {
00484   unsigned int count;
00485 
00486   count = 100;
00487 
00488   while (count-- > 0) {
00489     for (;;) {
00490       fd_set fds;
00491       struct timeval tv;
00492       int r;
00493 
00494       FD_ZERO (&fds);
00495       FD_SET (fd, &fds);
00496 
00497       /* Timeout. */
00498       tv.tv_sec = 2;
00499       tv.tv_usec = 0;
00500 
00501       r = select (fd + 1, &fds, NULL, NULL, &tv);
00502 
00503       if (-1 == r) {
00504         if (EINTR == errno)
00505           continue;
00506 
00507         errno_exit ("select");
00508       }
00509 
00510       if (0 == r) {
00511         fprintf (stderr, "select timeout\n");
00512         exit (EXIT_FAILURE);
00513       }
00514 
00515       if (read_frame ())
00516         break;
00517 
00518       /* EAGAIN - continue select loop. */
00519     }
00520   }
00521 }
00522 
00523 void stop_capturing(void)
00524 {
00525   enum v4l2_buf_type type;
00526 
00527   switch (io) {
00528     case IO_METHOD_READ:
00529       /* Nothing to do. */
00530       break;
00531 
00532     case IO_METHOD_MMAP:
00533     case IO_METHOD_USERPTR:
00534       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00535 
00536       if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type))
00537         errno_exit ("VIDIOC_STREAMOFF");
00538 
00539       break;
00540   }
00541 }
00542 
00543 void start_capturing(void)
00544 {
00545   unsigned int i;
00546   enum v4l2_buf_type type;
00547 
00548   currentFrame = new frame;
00549   currentFrame->data = new unsigned char[width*height*3];
00550   currentFrame->width = width;
00551   currentFrame->height = height;
00552   currentFrame->pixType=0;
00553 
00554 
00555   switch (io) {
00556     case IO_METHOD_READ:
00557       /* Nothing to do. */
00558       break;
00559 
00560     case IO_METHOD_MMAP:
00561       for (i = 0; i < n_buffers; ++i) {
00562         struct v4l2_buffer buf;
00563 
00564         CLEAR (buf);
00565 
00566         buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00567         buf.memory      = V4L2_MEMORY_MMAP;
00568         buf.index       = i;
00569 
00570         if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00571           errno_exit ("VIDIOC_QBUF");
00572       }
00573 
00574       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00575 
00576       if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
00577         errno_exit ("VIDIOC_STREAMON");
00578 
00579       break;
00580 
00581     case IO_METHOD_USERPTR:
00582       for (i = 0; i < n_buffers; ++i) {
00583         struct v4l2_buffer buf;
00584 
00585         CLEAR (buf);
00586 
00587         buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00588         buf.memory      = V4L2_MEMORY_USERPTR;
00589         buf.index       = i;
00590         buf.m.userptr   = (unsigned long) buffers[i].start;
00591         buf.length      = buffers[i].length;
00592 
00593         if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00594           errno_exit ("VIDIOC_QBUF");
00595       }
00596 
00597       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00598 
00599       if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
00600         errno_exit ("VIDIOC_STREAMON");
00601 
00602       break;
00603   }
00604 }
00605 
00606 void uninit_device(void)
00607 {
00608   unsigned int i;
00609 
00610   switch (io) {
00611     case IO_METHOD_READ:
00612       free (buffers[0].start);
00613       break;
00614 
00615     case IO_METHOD_MMAP:
00616       for (i = 0; i < n_buffers; ++i)
00617         if (-1 == munmap (buffers[i].start, buffers[i].length))
00618           errno_exit ("munmap");
00619       break;
00620 
00621     case IO_METHOD_USERPTR:
00622       for (i = 0; i < n_buffers; ++i)
00623         free (buffers[i].start);
00624       break;
00625   }
00626 
00627   if (currentFrame != NULL)
00628     if (currentFrame->data != NULL)
00629       free(currentFrame->data);
00630     free(currentFrame);
00631 
00632   free (buffers);
00633 }
00634 
00635 void init_read(unsigned int buffer_size)
00636 {
00637   buffers = (struct buffer*)calloc (1, sizeof (*buffers));
00638 
00639   if (!buffers) {
00640     fprintf (stderr, "Out of memory\n");
00641     exit (EXIT_FAILURE);
00642   }
00643 
00644   buffers[0].length = buffer_size;
00645   buffers[0].start = malloc (buffer_size);
00646 
00647   if (!buffers[0].start) {
00648     fprintf (stderr, "Out of memory\n");
00649     exit (EXIT_FAILURE);
00650   }
00651 }
00652 
00653 void init_mmap(void)
00654 {
00655   struct v4l2_requestbuffers req;
00656 
00657   CLEAR (req);
00658 
00659   req.count               = 1;
00660   req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00661   req.memory              = V4L2_MEMORY_MMAP;
00662 
00663   if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
00664     if (EINVAL == errno) {
00665       fprintf (stderr, "%s does not support "
00666           "memory mapping\n", dev_name);
00667       exit (EXIT_FAILURE);
00668     } else {
00669       errno_exit ("VIDIOC_REQBUFS");
00670     }
00671   }
00672 
00673   if (req.count < 2) {
00674     fprintf (stderr, "Insufficient buffer memory on %s\n",
00675         dev_name);
00676     exit (EXIT_FAILURE);
00677   }
00678 
00679   buffers = (struct buffer*)calloc (req.count, sizeof (*buffers));
00680 
00681   if (!buffers) {
00682     fprintf (stderr, "Out of memory\n");
00683     exit (EXIT_FAILURE);
00684   }
00685 
00686   for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
00687     struct v4l2_buffer buf;
00688 
00689     CLEAR (buf);
00690 
00691     buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00692     buf.memory      = V4L2_MEMORY_MMAP;
00693     buf.index       = n_buffers;
00694 
00695     if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf))
00696       errno_exit ("VIDIOC_QUERYBUF");
00697 
00698     buffers[n_buffers].length = buf.length;
00699     buffers[n_buffers].start =
00700       mmap (NULL /* start anywhere */,
00701           buf.length,
00702           PROT_READ | PROT_WRITE /* required */,
00703           MAP_SHARED /* recommended */,
00704           fd, buf.m.offset);
00705 
00706     if (MAP_FAILED == buffers[n_buffers].start)
00707       errno_exit ("mmap");
00708   }
00709 }
00710 
00711 void init_userp(unsigned int buffer_size)
00712 {
00713   struct v4l2_requestbuffers req;
00714 
00715   CLEAR (req);
00716 
00717   req.count               = 4;
00718   req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00719   req.memory              = V4L2_MEMORY_USERPTR;
00720 
00721   if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
00722     if (EINVAL == errno) {
00723       fprintf (stderr, "%s does not support "
00724           "user pointer i/o\n", dev_name);
00725       exit (EXIT_FAILURE);
00726     } else {
00727       errno_exit ("VIDIOC_REQBUFS");
00728     }
00729   }
00730 
00731   buffers = (struct buffer*)calloc (4, sizeof (*buffers));
00732 
00733   if (!buffers) {
00734     fprintf (stderr, "Out of memory\n");
00735     exit (EXIT_FAILURE);
00736   }
00737 
00738   for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
00739     buffers[n_buffers].length = buffer_size;
00740     buffers[n_buffers].start = malloc (buffer_size);
00741 
00742     if (!buffers[n_buffers].start) {
00743       fprintf (stderr, "Out of memory\n");
00744       exit (EXIT_FAILURE);
00745     }
00746   }
00747 }
00748 
00749 void init_device(int pix_fmt)
00750 {
00751   struct v4l2_capability cap;
00752   struct v4l2_cropcap cropcap;
00753   struct v4l2_crop crop;
00754   struct v4l2_format fmt;
00755   unsigned int min;
00756 
00757   colorspace_init();
00758 
00759   printf("Settting to pixformat %i\n", pix_fmt);
00760   if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) {
00761     if (EINVAL == errno) {
00762       fprintf (stderr, "%s is no V4L2 device\n",
00763           dev_name);
00764       exit (EXIT_FAILURE);
00765     } else {
00766       errno_exit ("VIDIOC_QUERYCAP");
00767     }
00768   }
00769 
00770   printf("V4L2 kernel driver: %s\n", cap.driver);
00771   printf("FrameGrabber board name is: %s\n", cap.card);
00772   printf("FrameGrabber board bus info: %s\n", cap.bus_info);
00773   if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
00774     printf("    > Supports video capture\n");
00775   else printf("Not a video capture device.\n");
00776   if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)
00777     printf("    > Supports video output\n");
00778   if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
00779     printf("    > Supports video overlay\n");
00780   if (cap.capabilities & V4L2_CAP_VBI_CAPTURE)
00781     printf("    > Supports raw VBI capture\n");
00782   if (cap.capabilities & V4L2_CAP_VBI_OUTPUT)
00783     printf("    > Supports raw VBI output\n");
00784 
00785   // NOTE: older versions of V4L2 don't know about sliced VBI:
00786 #ifdef V4L2_CAP_SLICED_VBI_CAPTURE
00787   if (cap.capabilities & V4L2_CAP_SLICED_VBI_CAPTURE)
00788     printf("    > Supports sliced VBI capture\n");
00789 #endif
00790 #ifdef V4L2_CAP_SLICED_VBI_OUTPUT
00791   if (cap.capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
00792     printf("    > Supports sliced VBI_OUTPUT\n");
00793 #endif
00794   if (cap.capabilities & V4L2_CAP_RDS_CAPTURE)
00795     printf("    > Supports RDS capture\n");
00796   if (cap.capabilities & V4L2_CAP_TUNER)
00797     printf("    > Has an RF tuner and/or modulator\n");
00798   if (cap.capabilities & V4L2_CAP_AUDIO)
00799     printf("    > Supports audio input and/or output\n");
00800   if (cap.capabilities & V4L2_CAP_READWRITE)
00801      printf("    > Supports read/write I/O method\n");
00802   if (cap.capabilities & V4L2_CAP_ASYNCIO)
00803     printf("    > Supports asynchronous I/O method\n");
00804   if (cap.capabilities & V4L2_CAP_STREAMING)
00805      printf("    > Supports streaming I/O (MMAP) method\n");
00806 
00807   ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00808 
00809   // List available controls and their current settings:
00810   struct v4l2_queryctrl ctrl;
00811   int cid;
00812   for (cid = V4L2_CID_BASE; cid < V4L2_CID_LASTP1; cid ++)
00813     {
00814       memset(&ctrl, 0, sizeof(ctrl));
00815       ctrl.id = cid;
00816 
00817       // is that control supported?
00818       if (xioctl(fd, VIDIOC_QUERYCTRL, &ctrl) == 0 &&
00819           ctrl.type != 0)
00820         {
00821           // first of all, if we have a ModelParam for it, let's
00822           // attempt to set the current value:
00823           struct v4l2_control control; control.id = cid;
00824           switch(cid)
00825             {
00826             case V4L2_CID_BRIGHTNESS:
00827               control.value = 127;
00828               if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00829                 printf("Failed to set brightness to %d (VIDIOC_S_CTRL)\n",
00830                         control.value);
00831               break;
00832             case V4L2_CID_CONTRAST:
00833               control.value = 32;
00834               if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00835                 printf("Failed to set contrast to %d (VIDIOC_S_CTRL)\n",
00836                         control.value);
00837               break;
00838             case V4L2_CID_WHITENESS: // NOTE this is = V4L2_CID_GAMMA
00839               // NOTE: bttv driver supports saturation but not whiteness
00840               // NOTE: macbook supports gamma
00841               /*control.value = 50;
00842               if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00843                 printf("Failed to set whiteness to %d (VIDIOC_S_CTRL)\n",
00844                         control.value);*/
00845               break;
00846             case V4L2_CID_SATURATION:
00847               control.value = 39;
00848               if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00849                 printf("Failed to set saturation to %d (VIDIOC_S_CTRL)\n",
00850                         control.value);
00851               break;
00852             case V4L2_CID_HUE:
00853               control.value = 32768;
00854               if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00855                 printf("Failed to set hue to %d (VIDIOC_S_CTRL)\n",
00856                         control.value);
00857               break;
00858 
00859             default: break; // Ignore other controls
00860             }
00861 
00862           // ok, now get the current value, silently ignoring errors:
00863           int val = -1;
00864           if (xioctl(fd, VIDIOC_G_CTRL, &control) == 0)
00865             val = control.value;
00866 
00867           switch(ctrl.type)
00868             {
00869             case V4L2_CTRL_TYPE_INTEGER:
00870               printf("CONTROL: %s=%d (Def=%d, Rng=[%d .. %d])%s\n",
00871                       ctrl.name, val, ctrl.default_value,
00872                       ctrl.minimum, ctrl.maximum,
00873                       ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00874                       " (DISABLED)" : "");
00875               break;
00876 
00877             case V4L2_CTRL_TYPE_BOOLEAN:
00878               printf("CONTROL: %s=%s (Def=%s)%s\n",
00879                       ctrl.name, val ? "true" : "false",
00880                       ctrl.default_value ? "true" : "false",
00881                       ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00882                       " (DISABLED)" : "");
00883               break;
00884 
00885             case V4L2_CTRL_TYPE_MENU:
00886               printf("CONTROL: %s=[menu type not yet implemented]%s\n",
00887                       ctrl.name,
00888                       ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00889                       " (DISABLED)" : "");
00890               break;
00891             case V4L2_CTRL_TYPE_BUTTON:
00892               printf("CONTROL: %s=[button]%s\n",
00893                       ctrl.name,
00894                       ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00895                       " (DISABLED)" : "");
00896               break;
00897 
00898             default: break;
00899             }
00900         }
00901     }
00902 
00903   // list available channels:
00904   int i;
00905   for (i = 0; ; i++)
00906     {
00907       struct v4l2_input inp;
00908       memset(&inp, 0, sizeof(inp));
00909       inp.index = i;
00910       if (xioctl(fd, VIDIOC_ENUMINPUT, &inp) != 0) break;
00911       printf("Video input %d is '%s'\n", i, inp.name);
00912     }
00913 
00914 
00915 
00916   ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00917 
00918   if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
00919     fprintf (stderr, "%s is no video capture device\n",
00920         dev_name);
00921     exit (EXIT_FAILURE);
00922   }
00923 
00924   switch (io) {
00925     case IO_METHOD_READ:
00926       if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
00927         fprintf (stderr, "%s does not support read i/o\n",
00928             dev_name);
00929         exit (EXIT_FAILURE);
00930       }
00931 
00932       break;
00933 
00934     case IO_METHOD_MMAP:
00935     case IO_METHOD_USERPTR:
00936       if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
00937         fprintf (stderr, "%s does not support streaming i/o\n",
00938             dev_name);
00939         exit (EXIT_FAILURE);
00940       }
00941 
00942       break;
00943   }
00944 
00945 
00946   /* Select video input, video standard and tune here. */
00947   int channel = 0;
00948   if (xioctl(fd, VIDIOC_S_INPUT, &channel) < 0)
00949     printf("Cannot select video input %d\n", channel);
00950   else
00951     printf("Selected video input %d\n", channel);
00952 
00953 
00954 
00955   // Reset cropping parameters and get resolution capabilities. NOTE:
00956   // just open()'ing the device does not reset it, according to the
00957   // unix toolchain philosophy. Hence, although here we do not provide
00958   // support for cropping, we still need to ensure that it is properly
00959   // reset:
00960   CLEAR (cropcap);
00961   cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00962 
00963   if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
00964     printf("Video capture bounds: (%d, %d) -> (%d, %d)\n",
00965         cropcap.bounds.left, cropcap.bounds.top,
00966         cropcap.bounds.left + cropcap.bounds.width - 1,
00967         cropcap.bounds.top + cropcap.bounds.height - 1);
00968     printf("Video default capture rectangle: (%d, %d) -> (%d, %d)\n",
00969         cropcap.defrect.left, cropcap.defrect.top,
00970         cropcap.defrect.left + cropcap.defrect.width - 1,
00971         cropcap.defrect.top + cropcap.defrect.height - 1);
00972 
00973   } else {
00974     printf("Failed to get cropping capabilities -- IGNORED.\n");
00975   }
00976 
00977   memset (&crop, 0, sizeof(crop));
00978   crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00979   crop.c = cropcap.defrect;
00980   if (xioctl(fd, VIDIOC_S_CROP, &crop) == -1)
00981     printf("Failed to reset cropping settings -- IGNORED.\n");
00982 
00983 
00984 
00985   // list available video formats and see which ones would work with
00986   // the requested resolution:
00987   CLEAR (fmt);
00988   fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00989   fmt.fmt.pix.width = width;
00990   fmt.fmt.pix.height = height;
00991   fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
00992   int fmt_to_use = -1; // in case user selected "auto" format
00993 
00994   for (i = 0; ; i ++)
00995   {
00996     struct v4l2_fmtdesc fdesc;
00997     memset(&fdesc, 0, sizeof(fdesc));
00998     fdesc.index = i;
00999     fdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01000     if (xioctl(fd, VIDIOC_ENUM_FMT, &fdesc) != 0) break;
01001     unsigned int f;
01002     for (f = 0; f < (unsigned int)SALGLASSES_VIDFMT_AUTO; f ++)
01003       if (v4l2format[f] == fdesc.pixelformat) break;
01004 
01005     // try to see whether that would work with our given image dims:
01006     fmt.fmt.pix.pixelformat = fdesc.pixelformat;
01007     int worked = 0;
01008     if (xioctl(fd, VIDIOC_TRY_FMT, &fmt) == 0)
01009     {
01010       worked = 1;
01011       if (fmt_to_use == -1) fmt_to_use = fdesc.pixelformat;
01012     }
01013     printf("Video Format: Use '%i' for '%s (Fourcc: %c%c%c%c)'%s%s\n",
01014         f == SALGLASSES_VIDFMT_AUTO ?  -1 : f,
01015         fdesc.description,
01016         ((char*)(&fdesc.pixelformat))[0],
01017         ((char*)(&fdesc.pixelformat))[1],
01018         ((char*)(&fdesc.pixelformat))[2],
01019         ((char*)(&fdesc.pixelformat))[3],
01020         fdesc.flags & V4L2_FMT_FLAG_COMPRESSED ? " (COMPRESSED)" : "",
01021         worked ? " [OK]" : " [FAILED TO SET]");
01022   }
01023   printf("Using format %i\n", fmt_to_use);
01024 
01025   // Get the frame time, according to current video standard:
01026   struct v4l2_streamparm sparm;
01027   memset(&sparm, 0, sizeof(sparm));
01028   sparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01029   if (xioctl(fd, VIDIOC_G_PARM, &sparm) == -1)
01030     {
01031       printf("Cannot get video standard params - ASSUMING NTSC\n");
01032     }
01033   else
01034     printf("Capture at %.2f fps\n",
01035         (float)sparm.parm.capture.timeperframe.numerator/
01036         (float)sparm.parm.capture.timeperframe.denominator);
01037 
01038   //fmt.fmt.pix.pixelformat = fmt_to_use;
01039   fmt.fmt.pix.pixelformat = v4l2format[11];
01040 
01041   if (xioctl(fd, VIDIOC_S_FMT, &fmt) == -1)
01042     printf("Cannot set requested video mode/resolution %i [%dx%d], probably unsupported by hardware.",
01043               fmt_to_use, width, height);
01044 
01045   if (xioctl(fd, VIDIOC_G_FMT, &fmt) == 0)
01046     printf("Video mode/resolution set to %i [%dx%d]\n",
01047         fmt_to_use,
01048         fmt.fmt.pix.width,  fmt.fmt.pix.height);
01049 
01050   if ((int)fmt.fmt.pix.width != width ||
01051       (int)fmt.fmt.pix.height != height)
01052     printf("Hardware suggests changing input dims to %dx%d instead of "
01053         "requested %dx%d\n",
01054         fmt.fmt.pix.width, fmt.fmt.pix.height,
01055         width, height);
01056 
01057   width = fmt.fmt.pix.width;
01058   height = fmt.fmt.pix.height;
01059 
01060 
01061   /* Note VIDIOC_S_FMT may change width and height. */
01062 
01063   switch (io) {
01064     case IO_METHOD_READ:
01065       init_read (fmt.fmt.pix.sizeimage);
01066       break;
01067 
01068     case IO_METHOD_MMAP:
01069       printf("Using MMap\n");
01070       init_mmap ();
01071       break;
01072 
01073     case IO_METHOD_USERPTR:
01074       init_userp (fmt.fmt.pix.sizeimage);
01075       break;
01076   }
01077 }
01078 
01079 void close_device(void)
01080 {
01081   if (-1 == close (fd))
01082     errno_exit ("close");
01083 
01084   fd = -1;
01085 }
01086 
01087 void open_device(void)
01088 {
01089   struct stat st;
01090 
01091   if (-1 == stat (dev_name, &st)) {
01092     fprintf (stderr, "Cannot identify '%s': %d, %s\n",
01093         dev_name, errno, strerror (errno));
01094     exit (EXIT_FAILURE);
01095   }
01096 
01097   if (!S_ISCHR (st.st_mode)) {
01098     fprintf (stderr, "%s is no device\n", dev_name);
01099     exit (EXIT_FAILURE);
01100   }
01101 
01102   fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
01103 
01104   if (-1 == fd) {
01105     fprintf (stderr, "Cannot open '%s': %d, %s\n",
01106         dev_name, errno, strerror (errno));
01107     exit (EXIT_FAILURE);
01108   }
01109 }
Generated on Sun May 8 08:41:21 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3