v4l2使用技巧

V4L2  V4L 有较大的改动,并已成为 2.6 的标准接口,函盖 video/ dvb /FM… ,多数驱动都在向 V4l2 迁移 V4L2 采用流水线的方式,操作更简单直观。 一般来说,需要用到的函数就是 open()  close()  ioctl () 

 

      推荐的参考资源:

      (1) Video for Linux Two API Specification---Revision 2.6.32

      http:// linuxtv.org/downloads/video4linux/API/V4L2_API/spec-single/v4l2.html

      (2) capture.c 官方示例程序

 

      说明:强烈建议阅读这两个参考资源!!!如果是初次接触,建议可以先浏览一下第一个参考文档,但是capture.c程序一定要仔细的看一下,至少得先让它能够跑起来(正常运行情况下,在终端下会不断的输出一个 ".")。

      下面的讲解,都将是基于capture.c程序。但是,capture.c程序有一点点小的不足,后面的内容中会介绍到,在末尾,会附上我稍微修改过的一个版本。

 

      对照capture.c程序,值得我们注意的主要是以下几点:  

(1)3  I/O 方式

      (1.1)read/write,直接使用 read  write 函数进行读写。这种方式最简单,但是这种方式会在 用户空间和内核空间不断拷贝数据 ,同时在用户空间和内核空间占用  大量内存, 效率不高。

     (1.2)mmap ,把硬件设备 里的内存映射 到位于用户空间的应用程序中的内存地址上, 直接处理设备内存,这是一种有效的 方式。

      (1.3) userptr ,内存由用户空间的应用程序分配,并把地址传递到内核中的驱动程序, 然后由 v4l2 驱动程序直接将数据填充到用户空间的内存中。

 

       第一种方式效率是最低的,后面两种方法都能提高执行的效率,但是对于mmap 方式,文档中有这样一句描述 --Remember the buffers are allocated in physical memory, as opposed to virtual memory which can be swapped out to disk. Applications should free the buffers as soon as possible with the munmap () function .(使用mmap方法的时候,buffers相当于是在内核空间中分 配的,这种情况下,这些buffer是不能被交换到虚拟内存中,虽然这种方法不怎么影响读写效率,但是它一直占用着内核空间中的内存,当系统的内存有限的 时候,如果同时运行有大量的进程,则对系统的整体性能会有一定的影响。如果对于这里描述的这些概念还不是很清楚的话,没事,先记住下面给出的结论就行了, 以后再详细的去了解)。

       所以,对于 I/O 方法的选择,推荐的顺序是 userptr  mmap  read-write 

 

(2) 当使用 mmap  userptr 方式的时候,有一个环形缓冲队列的概念,这个队列中,有 n  buffer ,驱动程序采集到的视频帧数据,就是存储在每个 buffer 中。

      在每次用 VIDIOC_DQBUF 取出一个 buffer ,并且处理完数据后,一定要用 VIDIOC_QBUF 将这个 buffer 再次放回到环形缓冲队列中。

      环形缓冲队列,也使得这两种 I/O 方式的效率高于直接 read/write 

 

 

( 3 ) 采集视频的分辨率

       (3.1) Cropping ,裁剪 ( 并非所有的摄像头都支持裁剪功能 )

       (3.2) Scaling ,缩放

 

      下面有个参考图片,注意图片中的 4 个矩形:

v4l2裁剪示意图

 

红色 —bounds ,是 最大的能捕捉到的图像 范围。这个是摄像头本身的硬件属性,比如摄像头CCD的分辨率。

蓝色  defrect ,是 我们的设备能够得到的最大的 范围。要区别于红色的部分,这是在CCD分辨率的基础上,我们的系统通过驱动软件能够获得的最大的分辨率。defrect和bounds可能会有小的差别,也可能是重合的。

绿色 —crop ,是我们希望裁剪的部分 ( 区别裁剪和缩放 ) 。也就是我我们希望获取CCD中的某个矩形部分。

紫色  fmt ,伸缩,这一部分是我们最终获得的图像的大小。在使用 VIDIOC_S_FMT 时,驱动程序会计算出图像帧数据的大小,并且返回给我们。 ( 后面还会提到这个 )

 

       如果硬件设备不支持 crop ,则相当于就是直接在 defrect 矩形上面设置大小。可以简单的理解为直接设置期望的视频分辨率。普通的摄像头,通常都不支持crop,在capture.c程序中也能看到对crop的处理方式--如果有crop功能,则crop,否则就跳过,直接使用VIDIOC_S_FMT。

   

(4) capture.c 程序中的 process_image 函数。

       capture.c 程序主要是用来演示怎样使用 v4l2 接口,并没有对采集到的视频帧数据做任何实际的处理,仅仅用process_image 函数表示了处理图像的代码位置。

       process_image 函数只有一个参数,就是存储视频帧的内存的地址指针,但是在真正的应用中,通常还需要知道该指针指向的数据的大小。

       因此可以修改函数,改成 void process_image ( const void * p, int len ) ,但是每次调用 process_image的时候,第 2 个参数该传递什么值?

 

考虑到程序中对 buffer 的定义

  struct buffer {

  void * start;

  size_t length};

 

       如果将 buffer.length 作为第 2 个参数传递到修改后的 process_image 函数中,这样做是不正确的。process_image 需要的第二个参数应该是每帧图像的大小,仔细阅读代码后会发现, buffer.length 并不一定就等于图像帧的大小。 (buffer 的大小,还需要考虑其他的一些因素,比如内存对齐等 )。

   

(5) 图像帧的大小和图像的格式  

       首先要明确一点, RGB  YUV 只是两种很笼统的划分方法,还需要知道具体的封装方式,才有办法计算出视频帧数据的实际大小。

      对于YUV而言, YUV 格式通常有两大类:打包( packed )格式和平面( planar )格式。前者将 YUV 分量存放在同一个数组中,通常是几个相邻的像素组成一个宏像素( macro-pixel );而后者使用三个数组分开存放 YUV 三个分量,就像是一个三维平面一样。

       以h.263为例, H.263 编码算法要求图象被编码为一个亮度信号和两个色差成分( Y  Cb  Cr ),可以记为YCbCr  亮度的取样结构都是 dx  象素每行, dy 行每幅图象。 两个色差成分的取样都是 dx/2 个象素每行, dy /2行每幅 图象。如下图。

h.263采样示意图


      H.263编码算法 要求的这种图象格式对应到 v4l2 里面,就是 V4L2_PIX_FMT_YUV420  (YUV  YCbCr YVU  YCrCb ) 

      V4L2_PIX_FMT_YUV420是一种平坦存储格式,也就是说,在内存中,先存储所有的 Y 值,然后是所有的 Cb 值,最后才是 Cr 值。

      假设有一个 V 4L2_PIX_FMT_ Y UV 420 格式的图像,分辨率是 × 4 像素,那么该图像帧在内存中存储形式就是

  V4L2_PIX_FMT_YUV420 格式的内存示意图

 

 

       根据前面的描述,可以看出一个公式,当使用 V4L2_PIX_FMT_YUV420 格式采集图像的时候,如果图像的宽度为width ,高度为 height ,那么图像占用的内存的大小就是 imagesize = width height * 3 / 2。

 

       前面提到过, 使用 VIDIOC_S_FMT 时,驱动程序会计算出图像帧数据的大小,并且返回给 我们。当 width = 640  height = 480 的时候,根据公式, imagesize = 640 * 480 * 3 / 2 = 460800 

      同样设置的时候,返回的 fmt.fmt.pix.sizeimage 也是 460800 

 

      如果是使用其他的格式,都可以根据各种格式的定义来计算它们实际占用的内存的大小以及他们在内 存中的存储方式。

      建议将 Video for Linux Two API Specification 作为手册,里面对视频格式的介绍比较全面。

                                                                                                                                                    

 (6)下面给出修改过的capture.c代码,只改动了一点点

  1. #include <stdio.h>   
  2. #include <stdlib.h>   
  3. #include <string.h>   
  4. #include <assert.h>   
  5. #include <getopt.h>             /* getopt_long() */   
  6. #include <fcntl.h>              /* low-level i/o */   
  7. #include <unistd.h>   
  8. #include <errno.h>   
  9. #include <malloc.h>   
  10. #include <sys/stat.h>   
  11. #include <sys/types.h>   
  12. #include <sys/time.h>   
  13. #include <sys/mman.h>   
  14. #include <sys/ioctl.h>   
  15. #include <asm/types.h>          /* for videodev2.h */   
  16. #include <linux/videodev2.h>   
  17. #define CLEAR(x) memset (&(x), 0, sizeof (x))   
  18. typedef   enum  {  
  19.     IO_METHOD_READ, IO_METHOD_MMAP, IO_METHOD_USERPTR,  
  20. } io_method;  
  21. struct  buffer {  
  22.     void  * start;  
  23.     size_t  length; //buffer's length is different from cap_image_size   
  24. };  
  25. static   char  * dev_name = NULL;  
  26. static  io_method io = IO_METHOD_MMAP; //IO_METHOD_READ;//IO_METHOD_MMAP;   
  27. static   int  fd = -1;  
  28. struct  buffer * buffers = NULL;  
  29. static  unsigned  int  n_buffers = 0;  
  30. static   FILE  * outf = 0;  
  31. static  unsigned  int  cap_image_size = 0; //to keep the real image size!!   
  32. //   
  33. static   void  errno_exit( const   char  * s) {  
  34.     fprintf(stderr, "%s error %d, %s/n" , s, errno, strerror(errno));  
  35.     exit(EXIT_FAILURE);  
  36. }  
  37. static   int  xioctl( int  fd,  int  request,  void  * arg) {  
  38.     int  r;  
  39.     do   
  40.         r = ioctl(fd, request, arg);  
  41.     while  (-1 == r && EINTR == errno);  
  42.     return  r;  
  43. }  
  44. static   void  process_image( const   void  * p,  int  len) {  
  45.     //  static char[115200] Outbuff ;   
  46.     fputc('.' , stdout);  
  47.     if  (len > 0) {  
  48.         fputc('.' , stdout);  
  49.         fwrite(p, 1, len, outf);  
  50.     }  
  51.     fflush(stdout);  
  52. }  
  53. static   int  read_frame( void ) {  
  54.     struct  v4l2_buffer buf;  
  55.     unsigned int  i;  
  56.     switch  (io) {  
  57.     case  IO_METHOD_READ:  
  58.         if  (-1 == read(fd, buffers[0].start, buffers[0].length)) {  
  59.             switch  (errno) {  
  60.             case  EAGAIN:  
  61.                 return  0;  
  62.             case  EIO:  
  63.                 /* Could ignore EIO, see spec. */   
  64.                 /* fall through */   
  65.             default :  
  66.                 errno_exit("read" );  
  67.             }  
  68.         }  
  69.         //      printf("length = %d/r", buffers[0].length);   
  70.         //      process_image(buffers[0].start, buffers[0].length);   
  71.         printf("image_size = %d,/t IO_METHOD_READ buffer.length=%d/r" ,  
  72.                 cap_image_size, buffers[0].length);  
  73.         process_image(buffers[0].start, cap_image_size);  
  74.         break ;  
  75.     case  IO_METHOD_MMAP:  
  76.         CLEAR (buf);  
  77.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  78.         buf.memory = V4L2_MEMORY_MMAP;  
  79.         if  (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {  
  80.             switch  (errno) {  
  81.             case  EAGAIN:  
  82.                 return  0;  
  83.             case  EIO:  
  84.                 /* Could ignore EIO, see spec. */   
  85.                 /* fall through */   
  86.             default :  
  87.                 errno_exit("VIDIOC_DQBUF" );  
  88.             }  
  89.         }  
  90.         assert(buf.index < n_buffers);  
  91.         //      printf("length = %d/r", buffers[buf.index].length);   
  92.         //      process_image(buffers[buf.index].start, buffers[buf.index].length);   
  93.         printf("image_size = %d,/t IO_METHOD_MMAP buffer.length=%d/r" ,  
  94.                 cap_image_size, buffers[0].length);  
  95.         process_image(buffers[0].start, cap_image_size);  
  96.         if  (-1 == xioctl(fd, VIDIOC_QBUF, &buf))  
  97.             errno_exit("VIDIOC_QBUF" );  
  98.         break ;  
  99.     case  IO_METHOD_USERPTR:  
  100.         CLEAR (buf);  
  101.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  102.         buf.memory = V4L2_MEMORY_USERPTR;  
  103.         if  (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {  
  104.             switch  (errno) {  
  105.             case  EAGAIN:  
  106.                 return  0;  
  107.             case  EIO:  
  108.                 /* Could ignore EIO, see spec. */   
  109.                 /* fall through */   
  110.             default :  
  111.                 errno_exit("VIDIOC_DQBUF" );  
  112.             }  
  113.         }  
  114.         for  (i = 0; i < n_buffers; ++i)  
  115.             if  (buf.m.userptr == (unsigned  long ) buffers[i].start && buf.length  
  116.                     == buffers[i].length)  
  117.                 break ;  
  118.         assert(i < n_buffers);  
  119.         //      printf("length = %d/r", buffers[i].length);   
  120.         //      process_image((void *) buf.m.userptr, buffers[i].length);   
  121.         printf("image_size = %d,/t IO_METHOD_USERPTR buffer.length=%d/r" ,  
  122.                 cap_image_size, buffers[0].length);  
  123.         process_image(buffers[0].start, cap_image_size);  
  124.         if  (-1 == xioctl(fd, VIDIOC_QBUF, &buf))  
  125.             errno_exit("VIDIOC_QBUF" );  
  126.         break ;  
  127.     }  
  128.     return  1;  
  129. }  
  130. static   void  mainloop( void ) {  
  131.     unsigned int  count;  
  132.     count = 100;  
  133.     while  (count-- > 0) {  
  134.         for  (;;) {  
  135.             fd_set fds;  
  136.             struct  timeval tv;  
  137.             int  r;  
  138.             FD_ZERO(&fds);  
  139.             FD_SET(fd, &fds);  
  140.             /* Timeout. */   
  141.             tv.tv_sec = 2;  
  142.             tv.tv_usec = 0;  
  143.             r = select(fd + 1, &fds, NULL, NULL, &tv);  
  144.             if  (-1 == r) {  
  145.                 if  (EINTR == errno)  
  146.                     continue ;  
  147.                 errno_exit("select" );  
  148.             }  
  149.             if  (0 == r) {  
  150.                 fprintf(stderr, "select timeout/n" );  
  151.                 exit(EXIT_FAILURE);  
  152.             }  
  153.             if  (read_frame())  
  154.                 break ;  
  155.             /* EAGAIN - continue select loop. */   
  156.         }  
  157.     }  
  158. }  
  159. static   void  stop_capturing( void ) {  
  160.     enum  v4l2_buf_type type;  
  161.     switch  (io) {  
  162.     case  IO_METHOD_READ:  
  163.         /* Nothing to do. */   
  164.         break ;  
  165.     case  IO_METHOD_MMAP:  
  166.     case  IO_METHOD_USERPTR:  
  167.         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  168.         if  (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))  
  169.             errno_exit("VIDIOC_STREAMOFF" );  
  170.         break ;  
  171.     }  
  172. }  
  173. static   void  start_capturing( void ) {  
  174.     unsigned int  i;  
  175.     enum  v4l2_buf_type type;  
  176.     switch  (io) {  
  177.     case  IO_METHOD_READ:  
  178.         /* Nothing to do. */   
  179.         break ;  
  180.     case  IO_METHOD_MMAP:  
  181.         for  (i = 0; i < n_buffers; ++i) {  
  182.             struct  v4l2_buffer buf;  
  183.             CLEAR (buf);  
  184.             buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  185.             buf.memory = V4L2_MEMORY_MMAP;  
  186.             buf.index = i;  
  187.             if  (-1 == xioctl(fd, VIDIOC_QBUF, &buf))  
  188.                 errno_exit("VIDIOC_QBUF" );  
  189.         }  
  190.         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  191.         if  (-1 == xioctl(fd, VIDIOC_STREAMON, &type))  
  192.             errno_exit("VIDIOC_STREAMON" );  
  193.         break ;  
  194.     case  IO_METHOD_USERPTR:  
  195.         for  (i = 0; i < n_buffers; ++i) {  
  196.             struct  v4l2_buffer buf;  
  197.             CLEAR (buf);  
  198.             buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  199.             buf.memory = V4L2_MEMORY_USERPTR;  
  200.             buf.index = i;  
  201.             buf.m.userptr = (unsigned long ) buffers[i].start;  
  202.             buf.length = buffers[i].length;  
  203.             if  (-1 == xioctl(fd, VIDIOC_QBUF, &buf))  
  204.                 errno_exit("VIDIOC_QBUF" );  
  205.         }  
  206.         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  207.         if  (-1 == xioctl(fd, VIDIOC_STREAMON, &type))  
  208.             errno_exit("VIDIOC_STREAMON" );  
  209.         break ;  
  210.     }  
  211. }  
  212. static   void  uninit_device( void ) {  
  213.     unsigned int  i;  
  214.     switch  (io) {  
  215.     case  IO_METHOD_READ:  
  216.         free(buffers[0].start);  
  217.         break ;  
  218.     case  IO_METHOD_MMAP:  
  219.         for  (i = 0; i < n_buffers; ++i)  
  220.             if  (-1 == munmap(buffers[i].start, buffers[i].length))  
  221.                 errno_exit("munmap" );  
  222.         break ;  
  223.     case  IO_METHOD_USERPTR:  
  224.         for  (i = 0; i < n_buffers; ++i)  
  225.             free(buffers[i].start);  
  226.         break ;  
  227.     }  
  228.     free(buffers);  
  229. }  
  230. static   void  init_read(unsigned  int  buffer_size) {  
  231.     buffers = calloc(1, sizeof (*buffers));  
  232.     if  (!buffers) {  
  233.         fprintf(stderr, "Out of memory/n" );  
  234.         exit(EXIT_FAILURE);  
  235.     }  
  236.     buffers[0].length = buffer_size;  
  237.     buffers[0].start = malloc(buffer_size);  
  238.     if  (!buffers[0].start) {  
  239.         fprintf(stderr, "Out of memory/n" );  
  240.         exit(EXIT_FAILURE);  
  241.     }  
  242. }  
  243. static   void  init_mmap( void ) {  
  244.     struct  v4l2_requestbuffers req;  
  245.     CLEAR (req);  
  246.     req.count = 4;  
  247.     req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  248.     req.memory = V4L2_MEMORY_MMAP;  
  249.     if  (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {  
  250.         if  (EINVAL == errno) {  
  251.             fprintf(stderr, "%s does not support "   
  252.                 "memory mapping/n" , dev_name);  
  253.             exit(EXIT_FAILURE);  
  254.         } else  {  
  255.             errno_exit("VIDIOC_REQBUFS" );  
  256.         }  
  257.     }  
  258.     if  (req.count < 2) {  
  259.         fprintf(stderr, "Insufficient buffer memory on %s/n" , dev_name);  
  260.         exit(EXIT_FAILURE);  
  261.     }  
  262.     buffers = calloc(req.count, sizeof (*buffers));  
  263.     if  (!buffers) {  
  264.         fprintf(stderr, "Out of memory/n" );  
  265.         exit(EXIT_FAILURE);  
  266.     }  
  267.     for  (n_buffers = 0; n_buffers < req.count; ++n_buffers) {  
  268.         struct  v4l2_buffer buf;  
  269.         CLEAR (buf);  
  270.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  271.         buf.memory = V4L2_MEMORY_MMAP;  
  272.         buf.index = n_buffers;  
  273.         if  (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))  
  274.             errno_exit("VIDIOC_QUERYBUF" );  
  275.         buffers[n_buffers].length = buf.length;  
  276.         buffers[n_buffers].start = mmap(NULL /* start anywhere */ , buf.length,  
  277.                 PROT_READ | PROT_WRITE /* required */ ,  
  278.                 MAP_SHARED /* recommended */ , fd, buf.m.offset);  
  279.         if  (MAP_FAILED == buffers[n_buffers].start)  
  280.             errno_exit("mmap" );  
  281.     }  
  282. }  
  283. static   void  init_userp(unsigned  int  buffer_size) {  
  284.     struct  v4l2_requestbuffers req;  
  285.     unsigned int  page_size;  
  286.     page_size = getpagesize();  
  287.     buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1);  
  288.     CLEAR (req);  
  289.     req.count = 4;  
  290.     req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  291.     req.memory = V4L2_MEMORY_USERPTR;  
  292.     if  (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {  
  293.         if  (EINVAL == errno) {  
  294.             fprintf(stderr, "%s does not support "   
  295.                 "user pointer i/o/n" , dev_name);  
  296.             exit(EXIT_FAILURE);  
  297.         } else  {  
  298.             errno_exit("VIDIOC_REQBUFS" );  
  299.         }  
  300.     }  
  301.     buffers = calloc(4, sizeof (*buffers));  
  302.     if  (!buffers) {  
  303.         fprintf(stderr, "Out of memory/n" );  
  304.         exit(EXIT_FAILURE);  
  305.     }  
  306.     for  (n_buffers = 0; n_buffers < 4; ++n_buffers) {  
  307.         buffers[n_buffers].length = buffer_size;  
  308.         buffers[n_buffers].start = memalign(/* boundary */ page_size,  
  309.                 buffer_size);  
  310.         if  (!buffers[n_buffers].start) {  
  311.             fprintf(stderr, "Out of memory/n" );  
  312.             exit(EXIT_FAILURE);  
  313.         }  
  314.     }  
  315. }  
  316. static   void  init_device( void ) {  
  317.     struct  v4l2_capability cap;  
  318.     struct  v4l2_cropcap cropcap;  
  319.     struct  v4l2_crop crop;  
  320.     struct  v4l2_format fmt;  
  321.     unsigned int  min;  
  322.     if  (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {  
  323.         if  (EINVAL == errno) {  
  324.             fprintf(stderr, "%s is no V4L2 device/n" , dev_name);  
  325.             exit(EXIT_FAILURE);  
  326.         } else  {  
  327.             errno_exit("VIDIOC_QUERYCAP" );  
  328.         }  
  329.     }  
  330.     if  (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {  
  331.         fprintf(stderr, "%s is no video capture device/n" , dev_name);  
  332.         exit(EXIT_FAILURE);  
  333.     }  
  334.     switch  (io) {  
  335.     case  IO_METHOD_READ:  
  336.         if  (!(cap.capabilities & V4L2_CAP_READWRITE)) {  
  337.             fprintf(stderr, "%s does not support read i/o/n" , dev_name);  
  338.             exit(EXIT_FAILURE);  
  339.         }  
  340.         break ;  
  341.     case  IO_METHOD_MMAP:  
  342.     case  IO_METHOD_USERPTR:  
  343.         if  (!(cap.capabilities & V4L2_CAP_STREAMING)) {  
  344.             fprintf(stderr, "%s does not support streaming i/o/n" , dev_name);  
  345.             exit(EXIT_FAILURE);  
  346.         }  
  347.         break ;  
  348.     }  
  349.     //not all capture support crop!!!!!!!   
  350.     /* Select video input, video standard and tune here. */   
  351.     printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n" );  
  352.     CLEAR (cropcap);  
  353.     cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  354.     if  (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {  
  355.         crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  356. #ifndef CROP_BY_JACK   
  357.         crop.c = cropcap.defrect; /* reset to default */   
  358. #else   
  359.         crop.c.left = cropcap.defrect.left;  
  360.         crop.c.top = cropcap.defrect.top;  
  361.         crop.c.width = 352;  
  362.         crop.c.height = 288;  
  363. #endif   
  364.         printf("----->has ability to crop!!/n" );  
  365.         printf("cropcap.defrect = (%d, %d, %d, %d)/n" , cropcap.defrect.left,  
  366.                 cropcap.defrect.top, cropcap.defrect.width,  
  367.                 cropcap.defrect.height);  
  368.         if  (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {  
  369.             switch  (errno) {  
  370.             case  EINVAL:  
  371.                 /* Cropping not supported. */   
  372.                 break ;  
  373.             default :  
  374.                 /* Errors ignored. */   
  375.                 break ;  
  376.             }  
  377.             printf("-----!!but crop to (%d, %d, %d, %d) Failed!!/n" ,  
  378.                     crop.c.left, crop.c.top, crop.c.width, crop.c.height);  
  379.         } else  {  
  380.             printf("----->sussess crop to (%d, %d, %d, %d)/n" , crop.c.left,  
  381.                     crop.c.top, crop.c.width, crop.c.height);  
  382.         }  
  383.     } else  {  
  384.         /* Errors ignored. */   
  385.         printf("!! has no ability to crop!!/n" );  
  386.     }  
  387.     printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n" );  
  388.     printf("/n" );  
  389.     crop finished!   
  390.     //set the format   
  391.     CLEAR (fmt);  
  392.     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  393.     fmt.fmt.pix.width = 640;  
  394.     fmt.fmt.pix.height = 480;  
  395.     //V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV420 — Planar formats with 1/2 horizontal and vertical chroma resolution, also known as YUV 4:2:0  
  396.     //V4L2_PIX_FMT_YUYV — Packed format with 1/2 horizontal chroma resolution, also known as YUV 4:2:2  
  397.     fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_YUV420;//V4L2_PIX_FMT_YUYV;   
  398.     fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;  
  399.     {  
  400.         printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n" );  
  401.         printf("=====will set fmt to (%d, %d)--" , fmt.fmt.pix.width,  
  402.                 fmt.fmt.pix.height);  
  403.         if  (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {  
  404.             printf("V4L2_PIX_FMT_YUYV/n" );  
  405.         } else   if  (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {  
  406.             printf("V4L2_PIX_FMT_YUV420/n" );  
  407.         } else   if  (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) {  
  408.             printf("V4L2_PIX_FMT_NV12/n" );  
  409.         }  
  410.     }  
  411.     if  (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))  
  412.         errno_exit("VIDIOC_S_FMT" );  
  413.     {  
  414.         printf("=====after set fmt/n" );  
  415.         printf("    fmt.fmt.pix.width = %d/n" , fmt.fmt.pix.width);  
  416.         printf("    fmt.fmt.pix.height = %d/n" , fmt.fmt.pix.height);  
  417.         printf("    fmt.fmt.pix.sizeimage = %d/n" , fmt.fmt.pix.sizeimage);  
  418.         cap_image_size = fmt.fmt.pix.sizeimage;  
  419.         printf("    fmt.fmt.pix.bytesperline = %d/n" , fmt.fmt.pix.bytesperline);  
  420.         printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n" );  
  421.         printf("/n" );  
  422.     }  
  423.     cap_image_size = fmt.fmt.pix.sizeimage;  
  424.     /* Note VIDIOC_S_FMT may change width and height. */   
  425.     printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n" );  
  426.     /* Buggy driver paranoia. */   
  427.     min = fmt.fmt.pix.width * 2;  
  428.     if  (fmt.fmt.pix.bytesperline < min)  
  429.         fmt.fmt.pix.bytesperline = min;  
  430.     min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;  
  431.     if  (fmt.fmt.pix.sizeimage < min)  
  432.         fmt.fmt.pix.sizeimage = min;  
  433.     printf("After Buggy driver paranoia/n" );  
  434.     printf("    >>fmt.fmt.pix.sizeimage = %d/n" , fmt.fmt.pix.sizeimage);  
  435.     printf("    >>fmt.fmt.pix.bytesperline = %d/n" , fmt.fmt.pix.bytesperline);  
  436.     printf("-#-#-#-#-#-#-#-#-#-#-#-#-#-/n" );  
  437.     printf("/n" );  
  438.     switch  (io) {  
  439.     case  IO_METHOD_READ:  
  440.         init_read(fmt.fmt.pix.sizeimage);  
  441.         break ;  
  442.     case  IO_METHOD_MMAP:  
  443.         init_mmap();  
  444.         break ;  
  445.     case  IO_METHOD_USERPTR:  
  446.         init_userp(fmt.fmt.pix.sizeimage);  
  447.         break ;  
  448.     }  
  449. }  
  450. static   void  close_device( void ) {  
  451.     if  (-1 == close(fd))  
  452.         errno_exit("close" );  
  453.     fd = -1;  
  454. }  
  455. static   void  open_device( void ) {  
  456.     struct  stat st;  
  457.     if  (-1 == stat(dev_name, &st)) {  
  458.         fprintf(stderr, "Cannot identify '%s': %d, %s/n" , dev_name, errno,  
  459.                 strerror(errno));  
  460.         exit(EXIT_FAILURE);  
  461.     }  
  462.     if  (!S_ISCHR(st.st_mode)) {  
  463.         fprintf(stderr, "%s is no device/n" , dev_name);  
  464.         exit(EXIT_FAILURE);  
  465.     }  
  466.     fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);  
  467.     if  (-1 == fd) {  
  468.         fprintf(stderr, "Cannot open '%s': %d, %s/n" , dev_name, errno,  
  469.                 strerror(errno));  
  470.         exit(EXIT_FAILURE);  
  471.     }  
  472. }  
  473. static   void  usage( FILE  * fp,  int  argc,  char  ** argv) {  
  474.     fprintf(fp, "Usage: %s [options]/n/n"   
  475.         "Options:/n"   
  476.         "-d | --device name   Video device name [/dev/video0]/n"   
  477.         "-h | --help          Print this message/n"   
  478.         "-m | --mmap          Use memory mapped buffers/n"   
  479.         "-r | --read          Use read() calls/n"   
  480.         "-u | --userp         Use application allocated buffers/n"   
  481.         "" , argv[0]);  
  482. }  
  483. static   const   char  short_options[] =  "d:hmru" ;  
  484. static   const   struct  option long_options[] = { {  "device" , required_argument,  
  485.         NULL, 'd'  }, {  "help" , no_argument, NULL,  'h'  }, {  "mmap" , no_argument,  
  486.         NULL, 'm'  }, {  "read" , no_argument, NULL,  'r'  }, {  "userp" ,  
  487.         no_argument, NULL, 'u'  }, { 0, 0, 0, 0 } };  
  488. int  main( int  argc,  char  ** argv) {  
  489.     dev_name = "/dev/video0" ;  
  490.     outf = fopen("out.yuv"  "wb" );  
  491.     for  (;;) {  
  492.         int  index;  
  493.         int  c;  
  494.         c = getopt_long(argc, argv, short_options, long_options, &index);  
  495.         if  (-1 == c)  
  496.             break ;  
  497.         switch  (c) {  
  498.         case  0:  /* getopt_long() flag */   
  499.             break ;  
  500.         case   'd' :  
  501.             dev_name = optarg;  
  502.             break ;  
  503.         case   'h' :  
  504.             usage(stdout, argc, argv);  
  505.             exit(EXIT_SUCCESS);  
  506.         case   'm' :  
  507.             io = IO_METHOD_MMAP;  
  508.             break ;  
  509.         case   'r' :  
  510.             io = IO_METHOD_READ;  
  511.             break ;  
  512.         case   'u' :  
  513.             io = IO_METHOD_USERPTR;  
  514.             break ;  
  515.         default :  
  516.             usage(stderr, argc, argv);  
  517.             exit(EXIT_FAILURE);  
  518.         }  
  519.     }  
  520.     open_device();  
  521.     init_device();  
  522.     start_capturing();  
  523.     mainloop();  
  524.     printf("/n" );  
  525.     stop_capturing();  
  526.     fclose(outf);  
  527.     uninit_device();  
  528.     close_device();  
  529.     exit(EXIT_SUCCESS);  
  530.     return  0;  
  531. }  

 

(7)最后还想多说两句,capture.c只是一个示例程序,仅仅是演示怎样使用v4l2中最基本的接口。尤其是在main函数中的那几个函数调用,表明了在使用v4l2时的最基本的一个流程,包括open_device,init_device,start_capturing,mainloop,stop_capturing,uninit_device,close_device。在写程序的时候,可以充分的利用这几个基本模块,把他们分散在不同的代码位置上,灵活的调用,有兴趣的可以看一下gstreamer中v4l2src的源代码或者其他的大型程序的相关部分。

    总之一句话,capture.c仅仅是一个演示程序,不要局限于它的代码结构,要灵活的使用。


转自:http://blog.csdn.net/jack0106/article/details/5644381

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
V4L2Video for Linux Two)是Linux系统中用于视频设备驱动程序的API,可以用于控制相机设备并访问其图像数据。使用V4L2 API可以实现相机的初始化、数据采集、参数设置等功能。以下是使用V4L2 API的基本步骤: 1. 打开设备:使用`open()`函数打开相机设备文件,获取文件描述符。 2. 查询设备能力:使用`ioctl()`函数和`VIDIOC_QUERYCAP`参数查询相机设备的能力,例如支持的视频格式、帧率等。 3. 配置设备参数:使用`ioctl()`函数和`VIDIOC_S_FMT`参数设置相机设备的视频格式、分辨率、帧率等参数。 4. 分配内存缓冲区:使用`ioctl()`函数和`VIDIOC_REQBUFS`参数请求分配内存缓冲区,用于存储相机采集到的图像数据。可以使用`mmap()`函数映射内存缓冲区到用户空间。 5. 启动数据流:使用`ioctl()`函数和`VIDIOC_STREAMON`参数启动数据流,让相机开始采集图像数据。 6. 读取数据:使用`read()`函数读取相机采集到的图像数据,或者使用`select()`函数和`poll()`函数等IO多路复用函数实现异步读取。 7. 处理数据:使用图像处理算法对相机采集到的图像数据进行处理。 8. 停止数据流:使用`ioctl()`函数和`VIDIOC_STREAMOFF`参数停止数据流,停止相机的采集。 9. 释放内存缓冲区:使用`ioctl()`函数和`VIDIOC_REQBUFS`参数释放分配的内存缓冲区。 10. 关闭设备:使用`close()`函数关闭相机设备文件。 以上是使用V4L2 API的基本步骤,具体的实现方法和使用细节可以参考V4L2 API的文档和示例代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值