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              return 0;
00425 
00426             /* fall through */
00427 
00428           default:
00429             errno_exit ("VIDIOC_DQBUF error");
00430         }
00431       }
00432 
00433       assert (buf.index < n_buffers);
00434 
00435       return process_image (buffers[buf.index].start,buffers[buf.index].length );
00436 
00437       // get ready for capture of that frame again (for later):
00438       if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00439         errno_exit ("VIDIOC_QBUF");
00440 
00441       break;
00442 
00443     case IO_METHOD_USERPTR:
00444       CLEAR (buf);
00445 
00446       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00447       buf.memory = V4L2_MEMORY_USERPTR;
00448 
00449       if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) {
00450         switch (errno) {
00451           case EAGAIN:
00452             return 0;
00453 
00454           case EIO:
00455             /* Could ignore EIO, see spec. */
00456 
00457             /* fall through */
00458 
00459           default:
00460             errno_exit ("VIDIOC_DQBUF");
00461         }
00462       }
00463 
00464       for (i = 0; i < n_buffers; ++i)
00465         if (buf.m.userptr == (unsigned long) buffers[i].start
00466             && buf.length == buffers[i].length)
00467           break;
00468 
00469       assert (i < n_buffers);
00470 
00471       return process_image ((void *) buf.m.userptr, 0);
00472 
00473       if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00474         errno_exit ("VIDIOC_QBUF");
00475 
00476       break;
00477   }
00478 
00479   return NULL;
00480 }
00481 void mainloop(void)
00482 {
00483   unsigned int count;
00484 
00485   count = 100;
00486 
00487   while (count-- > 0) {
00488     for (;;) {
00489       fd_set fds;
00490       struct timeval tv;
00491       int r;
00492 
00493       FD_ZERO (&fds);
00494       FD_SET (fd, &fds);
00495 
00496       /* Timeout. */
00497       tv.tv_sec = 2;
00498       tv.tv_usec = 0;
00499 
00500       r = select (fd + 1, &fds, NULL, NULL, &tv);
00501 
00502       if (-1 == r) {
00503         if (EINTR == errno)
00504           continue;
00505 
00506         errno_exit ("select");
00507       }
00508 
00509       if (0 == r) {
00510         fprintf (stderr, "select timeout\n");
00511         exit (EXIT_FAILURE);
00512       }
00513 
00514       if (read_frame ())
00515         break;
00516 
00517       /* EAGAIN - continue select loop. */
00518     }
00519   }
00520 }
00521 
00522 void stop_capturing(void)
00523 {
00524   enum v4l2_buf_type type;
00525 
00526   switch (io) {
00527     case IO_METHOD_READ:
00528       /* Nothing to do. */
00529       break;
00530 
00531     case IO_METHOD_MMAP:
00532     case IO_METHOD_USERPTR:
00533       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00534 
00535       if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type))
00536         errno_exit ("VIDIOC_STREAMOFF");
00537 
00538       break;
00539   }
00540 }
00541 
00542 void start_capturing(void)
00543 {
00544   unsigned int i;
00545   enum v4l2_buf_type type;
00546 
00547   currentFrame = new frame;
00548   currentFrame->data = new unsigned char[width*height*3];
00549   currentFrame->width = width;
00550   currentFrame->height = height;
00551   currentFrame->pixType=0;
00552 
00553 
00554   switch (io) {
00555     case IO_METHOD_READ:
00556       /* Nothing to do. */
00557       break;
00558 
00559     case IO_METHOD_MMAP:
00560       for (i = 0; i < n_buffers; ++i) {
00561         struct v4l2_buffer buf;
00562 
00563         CLEAR (buf);
00564 
00565         buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00566         buf.memory      = V4L2_MEMORY_MMAP;
00567         buf.index       = i;
00568 
00569         if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00570           errno_exit ("VIDIOC_QBUF");
00571       }
00572 
00573       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00574 
00575       if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
00576         errno_exit ("VIDIOC_STREAMON");
00577 
00578       break;
00579 
00580     case IO_METHOD_USERPTR:
00581       for (i = 0; i < n_buffers; ++i) {
00582         struct v4l2_buffer buf;
00583 
00584         CLEAR (buf);
00585 
00586         buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00587         buf.memory      = V4L2_MEMORY_USERPTR;
00588         buf.index       = i;
00589         buf.m.userptr   = (unsigned long) buffers[i].start;
00590         buf.length      = buffers[i].length;
00591 
00592         if (-1 == xioctl (fd, VIDIOC_QBUF, &buf))
00593           errno_exit ("VIDIOC_QBUF");
00594       }
00595 
00596       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00597 
00598       if (-1 == xioctl (fd, VIDIOC_STREAMON, &type))
00599         errno_exit ("VIDIOC_STREAMON");
00600 
00601       break;
00602   }
00603 }
00604 
00605 void uninit_device(void)
00606 {
00607   unsigned int i;
00608 
00609   switch (io) {
00610     case IO_METHOD_READ:
00611       free (buffers[0].start);
00612       break;
00613 
00614     case IO_METHOD_MMAP:
00615       for (i = 0; i < n_buffers; ++i)
00616         if (-1 == munmap (buffers[i].start, buffers[i].length))
00617           errno_exit ("munmap");
00618       break;
00619 
00620     case IO_METHOD_USERPTR:
00621       for (i = 0; i < n_buffers; ++i)
00622         free (buffers[i].start);
00623       break;
00624   }
00625 
00626   if (currentFrame != NULL)
00627     if (currentFrame->data != NULL)
00628       free(currentFrame->data);
00629     free(currentFrame);
00630 
00631   free (buffers);
00632 }
00633 
00634 void init_read(unsigned int buffer_size)
00635 {
00636   buffers = (struct buffer*)calloc (1, sizeof (*buffers));
00637 
00638   if (!buffers) {
00639     fprintf (stderr, "Out of memory\n");
00640     exit (EXIT_FAILURE);
00641   }
00642 
00643   buffers[0].length = buffer_size;
00644   buffers[0].start = malloc (buffer_size);
00645 
00646   if (!buffers[0].start) {
00647     fprintf (stderr, "Out of memory\n");
00648     exit (EXIT_FAILURE);
00649   }
00650 }
00651 
00652 void init_mmap(void)
00653 {
00654   struct v4l2_requestbuffers req;
00655 
00656   CLEAR (req);
00657 
00658   req.count               = 1;
00659   req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00660   req.memory              = V4L2_MEMORY_MMAP;
00661 
00662   if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
00663     if (EINVAL == errno) {
00664       fprintf (stderr, "%s does not support "
00665           "memory mapping\n", dev_name);
00666       exit (EXIT_FAILURE);
00667     } else {
00668       errno_exit ("VIDIOC_REQBUFS");
00669     }
00670   }
00671 
00672   if (req.count < 2) {
00673     fprintf (stderr, "Insufficient buffer memory on %s\n",
00674         dev_name);
00675     exit (EXIT_FAILURE);
00676   }
00677 
00678   buffers = (struct buffer*)calloc (req.count, sizeof (*buffers));
00679 
00680   if (!buffers) {
00681     fprintf (stderr, "Out of memory\n");
00682     exit (EXIT_FAILURE);
00683   }
00684 
00685   for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
00686     struct v4l2_buffer buf;
00687 
00688     CLEAR (buf);
00689 
00690     buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00691     buf.memory      = V4L2_MEMORY_MMAP;
00692     buf.index       = n_buffers;
00693 
00694     if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf))
00695       errno_exit ("VIDIOC_QUERYBUF");
00696 
00697     buffers[n_buffers].length = buf.length;
00698     buffers[n_buffers].start =
00699       mmap (NULL /* start anywhere */,
00700           buf.length,
00701           PROT_READ | PROT_WRITE /* required */,
00702           MAP_SHARED /* recommended */,
00703           fd, buf.m.offset);
00704 
00705     if (MAP_FAILED == buffers[n_buffers].start)
00706       errno_exit ("mmap");
00707   }
00708 }
00709 
00710 void init_userp(unsigned int buffer_size)
00711 {
00712   struct v4l2_requestbuffers req;
00713 
00714   CLEAR (req);
00715 
00716   req.count               = 4;
00717   req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00718   req.memory              = V4L2_MEMORY_USERPTR;
00719 
00720   if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) {
00721     if (EINVAL == errno) {
00722       fprintf (stderr, "%s does not support "
00723           "user pointer i/o\n", dev_name);
00724       exit (EXIT_FAILURE);
00725     } else {
00726       errno_exit ("VIDIOC_REQBUFS");
00727     }
00728   }
00729 
00730   buffers = (struct buffer*)calloc (4, sizeof (*buffers));
00731 
00732   if (!buffers) {
00733     fprintf (stderr, "Out of memory\n");
00734     exit (EXIT_FAILURE);
00735   }
00736 
00737   for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
00738     buffers[n_buffers].length = buffer_size;
00739     buffers[n_buffers].start = malloc (buffer_size);
00740 
00741     if (!buffers[n_buffers].start) {
00742       fprintf (stderr, "Out of memory\n");
00743       exit (EXIT_FAILURE);
00744     }
00745   }
00746 }
00747 
00748 void init_device(int pix_fmt)
00749 {
00750   struct v4l2_capability cap;
00751   struct v4l2_cropcap cropcap;
00752   struct v4l2_crop crop;
00753   struct v4l2_format fmt;
00754   unsigned int min;
00755 
00756   colorspace_init();
00757 
00758   printf("Settting to pixformat %i\n", pix_fmt);
00759   if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) {
00760     if (EINVAL == errno) {
00761       fprintf (stderr, "%s is no V4L2 device\n",
00762           dev_name);
00763       exit (EXIT_FAILURE);
00764     } else {
00765       errno_exit ("VIDIOC_QUERYCAP");
00766     }
00767   }
00768 
00769   printf("V4L2 kernel driver: %s\n", cap.driver);
00770   printf("FrameGrabber board name is: %s\n", cap.card);
00771   printf("FrameGrabber board bus info: %s\n", cap.bus_info);
00772   if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
00773     printf("    > Supports video capture\n");
00774   else printf("Not a video capture device.\n");
00775   if (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)
00776     printf("    > Supports video output\n");
00777   if (cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
00778     printf("    > Supports video overlay\n");
00779   if (cap.capabilities & V4L2_CAP_VBI_CAPTURE)
00780     printf("    > Supports raw VBI capture\n");
00781   if (cap.capabilities & V4L2_CAP_VBI_OUTPUT)
00782     printf("    > Supports raw VBI output\n");
00783 
00784   // NOTE: older versions of V4L2 don't know about sliced VBI:
00785 #ifdef V4L2_CAP_SLICED_VBI_CAPTURE
00786   if (cap.capabilities & V4L2_CAP_SLICED_VBI_CAPTURE)
00787     printf("    > Supports sliced VBI capture\n");
00788 #endif
00789 #ifdef V4L2_CAP_SLICED_VBI_OUTPUT
00790   if (cap.capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
00791     printf("    > Supports sliced VBI_OUTPUT\n");
00792 #endif
00793   if (cap.capabilities & V4L2_CAP_RDS_CAPTURE)
00794     printf("    > Supports RDS capture\n");
00795   if (cap.capabilities & V4L2_CAP_TUNER)
00796     printf("    > Has an RF tuner and/or modulator\n");
00797   if (cap.capabilities & V4L2_CAP_AUDIO)
00798     printf("    > Supports audio input and/or output\n");
00799   if (cap.capabilities & V4L2_CAP_READWRITE)
00800      printf("    > Supports read/write I/O method\n");
00801   if (cap.capabilities & V4L2_CAP_ASYNCIO)
00802     printf("    > Supports asynchronous I/O method\n");
00803   if (cap.capabilities & V4L2_CAP_STREAMING)
00804      printf("    > Supports streaming I/O (MMAP) method\n");
00805 
00806   ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00807 
00808   // List available controls and their current settings:
00809   struct v4l2_queryctrl ctrl;
00810   int cid;
00811   for (cid = V4L2_CID_BASE; cid < V4L2_CID_LASTP1; cid ++)
00812     {
00813       memset(&ctrl, 0, sizeof(ctrl));
00814       ctrl.id = cid;
00815 
00816       // is that control supported?
00817       if (xioctl(fd, VIDIOC_QUERYCTRL, &ctrl) == 0 &&
00818           ctrl.type != 0)
00819         {
00820           // first of all, if we have a ModelParam for it, let's
00821           // attempt to set the current value:
00822           struct v4l2_control control; control.id = cid;
00823           switch(cid)
00824             {
00825             case V4L2_CID_BRIGHTNESS:
00826               control.value = 64;
00827               if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00828                 printf("Failed to set brightness to %d (VIDIOC_S_CTRL)\n",
00829                         control.value);
00830               break;
00831             case V4L2_CID_CONTRAST:
00832               control.value = 0;
00833               if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00834                 printf("Failed to set contrast to %d (VIDIOC_S_CTRL)\n",
00835                         control.value);
00836               break;
00837             case V4L2_CID_WHITENESS: // NOTE this is = V4L2_CID_GAMMA
00838               // NOTE: bttv driver supports saturation but not whiteness
00839               // NOTE: macbook supports gamma
00840               /*control.value = 50;
00841               if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00842                 printf("Failed to set whiteness to %d (VIDIOC_S_CTRL)\n",
00843                         control.value);*/
00844               break;
00845             case V4L2_CID_SATURATION:
00846               control.value = 0;
00847               if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00848                 printf("Failed to set saturation to %d (VIDIOC_S_CTRL)\n",
00849                         control.value);
00850               break;
00851             case V4L2_CID_HUE:
00852               control.value = 32768;
00853               if (xioctl(fd, VIDIOC_S_CTRL, &control) == -1)
00854                 printf("Failed to set hue to %d (VIDIOC_S_CTRL)\n",
00855                         control.value);
00856               break;
00857 
00858             default: break; // Ignore other controls
00859             }
00860 
00861           // ok, now get the current value, silently ignoring errors:
00862           int val = -1;
00863           if (xioctl(fd, VIDIOC_G_CTRL, &control) == 0)
00864             val = control.value;
00865 
00866           switch(ctrl.type)
00867             {
00868             case V4L2_CTRL_TYPE_INTEGER:
00869               printf("CONTROL: %s=%d (Def=%d, Rng=[%d .. %d])%s\n",
00870                       ctrl.name, val, ctrl.default_value,
00871                       ctrl.minimum, ctrl.maximum,
00872                       ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00873                       " (DISABLED)" : "");
00874               break;
00875 
00876             case V4L2_CTRL_TYPE_BOOLEAN:
00877               printf("CONTROL: %s=%s (Def=%s)%s\n",
00878                       ctrl.name, val ? "true" : "false",
00879                       ctrl.default_value ? "true" : "false",
00880                       ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00881                       " (DISABLED)" : "");
00882               break;
00883 
00884             case V4L2_CTRL_TYPE_MENU:
00885               printf("CONTROL: %s=[menu type not yet implemented]%s\n",
00886                       ctrl.name,
00887                       ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00888                       " (DISABLED)" : "");
00889               break;
00890             case V4L2_CTRL_TYPE_BUTTON:
00891               printf("CONTROL: %s=[button]%s\n",
00892                       ctrl.name,
00893                       ctrl.flags & V4L2_CTRL_FLAG_DISABLED ?
00894                       " (DISABLED)" : "");
00895               break;
00896 
00897             default: break;
00898             }
00899         }
00900     }
00901 
00902   // list available channels:
00903   int i;
00904   for (i = 0; ; i++)
00905     {
00906       struct v4l2_input inp;
00907       memset(&inp, 0, sizeof(inp));
00908       inp.index = i;
00909       if (xioctl(fd, VIDIOC_ENUMINPUT, &inp) != 0) break;
00910       printf("Video input %d is '%s'\n", i, inp.name);
00911     }
00912 
00913 
00914 
00915   ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
00916 
00917   if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
00918     fprintf (stderr, "%s is no video capture device\n",
00919         dev_name);
00920     exit (EXIT_FAILURE);
00921   }
00922 
00923   switch (io) {
00924     case IO_METHOD_READ:
00925       if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
00926         fprintf (stderr, "%s does not support read i/o\n",
00927             dev_name);
00928         exit (EXIT_FAILURE);
00929       }
00930 
00931       break;
00932 
00933     case IO_METHOD_MMAP:
00934     case IO_METHOD_USERPTR:
00935       if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
00936         fprintf (stderr, "%s does not support streaming i/o\n",
00937             dev_name);
00938         exit (EXIT_FAILURE);
00939       }
00940 
00941       break;
00942   }
00943 
00944 
00945   /* Select video input, video standard and tune here. */
00946   int channel = 0;
00947   if (xioctl(fd, VIDIOC_S_INPUT, &channel) < 0)
00948     printf("Cannot select video input %d\n", channel);
00949   else
00950     printf("Selected video input %d\n", channel);
00951 
00952 
00953 
00954   // Reset cropping parameters and get resolution capabilities. NOTE:
00955   // just open()'ing the device does not reset it, according to the
00956   // unix toolchain philosophy. Hence, although here we do not provide
00957   // support for cropping, we still need to ensure that it is properly
00958   // reset:
00959   CLEAR (cropcap);
00960   cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00961 
00962   if (0 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) {
00963     printf("Video capture bounds: (%d, %d) -> (%d, %d)\n",
00964         cropcap.bounds.left, cropcap.bounds.top,
00965         cropcap.bounds.left + cropcap.bounds.width - 1,
00966         cropcap.bounds.top + cropcap.bounds.height - 1);
00967     printf("Video default capture rectangle: (%d, %d) -> (%d, %d)\n",
00968         cropcap.defrect.left, cropcap.defrect.top,
00969         cropcap.defrect.left + cropcap.defrect.width - 1,
00970         cropcap.defrect.top + cropcap.defrect.height - 1);
00971 
00972   } else {
00973     printf("Failed to get cropping capabilities -- IGNORED.\n");
00974   }
00975 
00976   memset (&crop, 0, sizeof(crop));
00977   crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00978   crop.c = cropcap.defrect;
00979   if (xioctl(fd, VIDIOC_S_CROP, &crop) == -1)
00980     printf("Failed to reset cropping settings -- IGNORED.\n");
00981 
00982 
00983 
00984   // list available video formats and see which ones would work with
00985   // the requested resolution:
00986   CLEAR (fmt);
00987   fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00988   fmt.fmt.pix.width = width;
00989   fmt.fmt.pix.height = height;
00990   fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
00991   int fmt_to_use = -1; // in case user selected "auto" format
00992 
00993   for (i = 0; ; i ++)
00994   {
00995     struct v4l2_fmtdesc fdesc;
00996     memset(&fdesc, 0, sizeof(fdesc));
00997     fdesc.index = i;
00998     fdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00999     if (xioctl(fd, VIDIOC_ENUM_FMT, &fdesc) != 0) break;
01000     unsigned int f;
01001     for (f = 0; f < (unsigned int)IROBOT_VIDFMT_AUTO; f ++)
01002       if (v4l2format[f] == fdesc.pixelformat) break;
01003 
01004     // try to see whether that would work with our given image dims:
01005     fmt.fmt.pix.pixelformat = fdesc.pixelformat;
01006     int worked = 0;
01007     if (xioctl(fd, VIDIOC_TRY_FMT, &fmt) == 0)
01008     {
01009       worked = 1;
01010       if (fmt_to_use == -1) fmt_to_use = fdesc.pixelformat;
01011     }
01012     printf("Video Format: Use '%i' for '%s (Fourcc: %c%c%c%c)'%s%s\n",
01013         f == IROBOT_VIDFMT_AUTO ?  -1 : f,
01014         fdesc.description,
01015         ((char*)(&fdesc.pixelformat))[0],
01016         ((char*)(&fdesc.pixelformat))[1],
01017         ((char*)(&fdesc.pixelformat))[2],
01018         ((char*)(&fdesc.pixelformat))[3],
01019         fdesc.flags & V4L2_FMT_FLAG_COMPRESSED ? " (COMPRESSED)" : "",
01020         worked ? " [OK]" : " [FAILED TO SET]");
01021   }
01022   printf("Using format %i\n", fmt_to_use);
01023 
01024   // Get the frame time, according to current video standard:
01025   struct v4l2_streamparm sparm;
01026   memset(&sparm, 0, sizeof(sparm));
01027   sparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01028   if (xioctl(fd, VIDIOC_G_PARM, &sparm) == -1)
01029     {
01030       printf("Cannot get video standard params - ASSUMING NTSC\n");
01031     }
01032   else
01033     printf("Capture at %.2f fps\n",
01034         (float)sparm.parm.capture.timeperframe.numerator/
01035         (float)sparm.parm.capture.timeperframe.denominator);
01036 
01037   //fmt.fmt.pix.pixelformat = fmt_to_use;
01038   fmt.fmt.pix.pixelformat = v4l2format[11];
01039 
01040   if (xioctl(fd, VIDIOC_S_FMT, &fmt) == -1)
01041     printf("Cannot set requested video mode/resolution %i [%dx%d], probably unsupported by hardware.",
01042               fmt_to_use, width, height);
01043 
01044   if (xioctl(fd, VIDIOC_G_FMT, &fmt) == 0)
01045     printf("Video mode/resolution set to %i [%dx%d]\n",
01046         fmt_to_use,
01047         fmt.fmt.pix.width,  fmt.fmt.pix.height);
01048 
01049   if ((int)fmt.fmt.pix.width != width ||
01050       (int)fmt.fmt.pix.height != height)
01051     printf("Hardware suggests changing input dims to %dx%d instead of "
01052         "requested %dx%d\n",
01053         fmt.fmt.pix.width, fmt.fmt.pix.height,
01054         width, height);
01055 
01056   width = fmt.fmt.pix.width;
01057   height = fmt.fmt.pix.height;
01058 
01059 
01060   /* Note VIDIOC_S_FMT may change width and height. */
01061 
01062   switch (io) {
01063     case IO_METHOD_READ:
01064       init_read (fmt.fmt.pix.sizeimage);
01065       break;
01066 
01067     case IO_METHOD_MMAP:
01068       printf("Using MMap\n");
01069       init_mmap ();
01070       break;
01071 
01072     case IO_METHOD_USERPTR:
01073       init_userp (fmt.fmt.pix.sizeimage);
01074       break;
01075   }
01076 }
01077 
01078 void close_device(void)
01079 {
01080   if (-1 == close (fd))
01081     errno_exit ("close");
01082 
01083   fd = -1;
01084 }
01085 
01086 void open_device(void)
01087 {
01088   struct stat st;
01089 
01090   if (-1 == stat (dev_name, &st)) {
01091     fprintf (stderr, "Cannot identify '%s': %d, %s\n",
01092         dev_name, errno, strerror (errno));
01093     exit (EXIT_FAILURE);
01094   }
01095 
01096   if (!S_ISCHR (st.st_mode)) {
01097     fprintf (stderr, "%s is no device\n", dev_name);
01098     exit (EXIT_FAILURE);
01099   }
01100 
01101   fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
01102 
01103   if (-1 == fd) {
01104     fprintf (stderr, "Cannot open '%s': %d, %s\n",
01105         dev_name, errno, strerror (errno));
01106     exit (EXIT_FAILURE);
01107   }
01108 }
Generated on Sun May 8 08:41:21 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3