现在的位置: 首页 > 综合 > 正文

v4l2驱动浅析

2013年08月23日 ⁄ 综合 ⁄ 共 6884字 ⁄ 字号 评论关闭
选自《v4l2研究进展》 作者lapset
简介:本文所附代码是根据v4l2官方文档以及demo(capture.c)修改而来,纯粹为学习交流之用,请勿使用在商用场合。
地址:由于官方网的域名有敏感词汇,所以请google一下。
一 ,操作流程简单看
 
 
 
二 模块概要分析
 
以下是所附代码所涉及到的全局变量,摆出来只是参考,具体修改的话请自行安排。
  1. #define CLEAR(x) memset (&(x), 0, sizeof (x))
  2. typedef enum {
  3. #ifdef IO_READ
  4.         IO_METHOD_READ,
  5. #endif
  6. #ifdef IO_MMAP
  7.         IO_METHOD_MMAP,
  8. #endif
  9. #ifdef IO_USERPTR
  10.         IO_METHOD_USERPTR,
  11. #endif
  12. } io_method;
  13. struct buffer {
  14.         void * start;
  15.         size_t length;
  16. };
  17. static io_method io = IO_METHOD_MMAP;
  18. static int fd = -1;
  19. struct buffer * buffers = NULL;
  20. static unsigned int n_buffers = 0;
  21. // global settings
  22. static unsigned int width = 640;
  23. static unsigned int height = 480;
  24. static unsigned char jpegQuality = 70;
  25. static char* jpegFilename = NULL;
  26. static char* deviceName = "/dev/video0";
1,deviceOpen
   主要就是打开你的设备文件,一般情况下就是,/dev/vedio0 取决于你的设备数量。前面提到的stat这个结构体主要是记录了文件的基本信息。通过这一点来校验文件的打开权限。
 
2,deviceInit
   这个模块稍微复杂些,它主要是使用了v4l2中定义的4种相关的数据结构。以下列出每种结构的具体属性。
  

  1. struct v4l2_cropcap {
  2. enum v4l2_buf_type type;
  3.        struct v4l2_rect bounds;
  4. struct v4l2_rect defrect;
  5. struct v4l2_fract pixelaspect;
  6. };
  7. struct v4l2_crop {
  8. enum v4l2_buf_type type;
  9. struct v4l2_rect c;
  10. };
  11. struct v4l2_capability {
  12. __u8 driver[16]; /* i.e. "bttv" */
  13. __u8 card[32]; /* i.e. "Hauppauge WinTV"
    */
  14. __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev)
    */
  15. __u32 version; /* should use KERNEL_VERSION() */
  16. __u32 capabilities; /* Device capabilities */
  17. __u32 reserved[4];
  18. };
  19. struct v4l2_format {
  20. enum v4l2_buf_type type;
  21. union {
  22. struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
  23. struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
  24. struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */
  25. struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
  26. __u8 raw_data[200]; /* user-defined */
  27. } fmt;
  28. };
这里不得不提醒一点,通常usb摄像头驱动,都会提供3种不同的数据传输方式,1,read IO 2,mmap内存映射 3,USERPTR(这一种是测试方法,具体可以去查询)
本文暂且只讨论常见的操作方法,即mmap内存映射方式.
通过一段时间的学习,才知道为什么只支持mmap,其实是我们所用的去架构是基于uvc.在uvc架构中,是不支持read/write io mode 以及用户扩展模式。
 
 
 
 
  1. static void deviceInit(void)
  2. {
  3.   struct v4l2_capability cap;
  4.   struct v4l2_cropcap cropcap; 
  5.   struct v4l2_crop crop;
  6.   struct v4l2_format fmt;
  7.   unsigned int min;
  8.   if (-== xioctl(fd, VIDIOC_QUERYCAP, &cap)) { //get
    the capab info about
  9.     if (EINVAL == errno) {
  10.       fprintf(stderr, "%s
    is no V4L2 device\n"
    ,deviceName);
  11.       exit(EXIT_FAILURE);
  12.     } else {
  13.       errno_exit("VIDIOC_QUERYCAP");
  14.     }
  15.   }
  16.   if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { //check
    is it support capture mode ?
  17.     fprintf(stderr, "%s
    is no video capture device\n"
    ,deviceName);
  18.     exit(EXIT_FAILURE);
  19.   }
  20.   
  21.      if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
  22.         fprintf(stderr, "%s
    does not support streaming i/o\n"
    ,deviceName);
  23.         exit(EXIT_FAILURE);
  24.       }
  25.   /* Select video input, video standard and tune here. */
  26.   CLEAR(cropcap);// init -0    it is a
    initialize func about set 0 to parameter   
  27.   cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  28.   if (== xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
  29.     crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  30.     crop.= cropcap.defrect; /*
    reset to default */
  31.     if (-== xioctl(fd, VIDIOC_S_CROP, &crop)) {
  32.       switch (errno) {
  33.         case EINVAL:
  34.           /* Cropping not supported. */
  35.           break;
  36.         default:
  37.           /* Errors ignored. */
  38.           break;
  39.       }
  40.     }
  41.   } else {
  42.   
  43.   }
  44.   CLEAR (fmt); 
  45.   // v4l2_format
  46.   fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;        //mode is capture 
  47.   fmt.fmt.pix.width = width;                   
     //define pixee width
  48.   fmt.fmt.pix.height = height;                  
    //define pixel height
  49.   fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;  
    //define pixel format
  50.   fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;       
  51.   if (-== xioctl(fd, VIDIOC_S_FMT, &fmt))      
    //set fmt 
  52.     errno_exit("VIDIOC_S_FMT");
  53.   /* Note VIDIOC_S_FMT may change width and height. */
  54.   if (width != fmt.fmt.pix.width) {
  55.     width = fmt.fmt.pix.width;
  56.     fprintf(stderr,"Image
    width set to %i by device %s.\n"
    ,width,deviceName);
  57.   }
  58.   if (height != fmt.fmt.pix.height) {
  59.     height = fmt.fmt.pix.height;
  60.     fprintf(stderr,"Image
    height set to %i by device %s.\n"
    ,height,deviceName);
  61.   }
  62.   /* Buggy driver paranoia. */
  63.   min = fmt.fmt.pix.width * 2;
  64.   if (fmt.fmt.pix.bytesperline < min)
  65.     fmt.fmt.pix.bytesperline = min;
  66.   min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
  67.   if (fmt.fmt.pix.sizeimage < min)
  68.     fmt.fmt.pix.sizeimage = min;
  69.    
  70.   //this function is important to init mmap pre_work
  71.   mmapInit();
  72. }
 
可以看到上面主要是初始化工作,具体的参数意义,请参看v4l2的specification 。
 
  1. static void mmapInit(void)
  2. {
  3.   struct v4l2_requestbuffers req;//apply for frame buffer
  4.   CLEAR (req);
  5.   req.count = 4;
  6.   req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  7.   req.memory = V4L2_MEMORY_MMAP;
  8.   if (-== xioctl(fd, VIDIOC_REQBUFS, &req)) {
  9.     if (EINVAL == errno) {
  10.       fprintf(stderr, "%s
    does not support memory mapping\n"
    , deviceName);
  11.       exit(EXIT_FAILURE);
  12.     } else {
  13.       errno_exit("VIDIOC_REQBUFS");
  14.     }
  15.   }
  16.   if (req.count < 2) {
  17.     fprintf(stderr, "Insufficient
    buffer memory on %s\n"
    , deviceName);
  18.     exit(EXIT_FAILURE);
  19.   }
  20.   buffers = calloc(req.count, sizeof(*buffers));
  21.   if (!buffers) {
  22.     fprintf(stderr, "Out
    of memory\n"
    );
  23.     exit(EXIT_FAILURE);
  24.   }
  25.   for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
  26.     struct v4l2_buffer buf;
  27.     CLEAR (buf);
  28.     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  29.     buf.memory = V4L2_MEMORY_MMAP;
  30.     buf.index = n_buffers;
  31.     if (-== xioctl(fd, VIDIOC_QUERYBUF, &buf))
  32.       errno_exit("VIDIOC_QUERYBUF");
  33.     buffers[n_buffers].length = buf.length;
  34.     buffers[n_buffers].start =
  35.     mmap (NULL /* start anywhere */, buf.length, PROT_READ | PROT_WRITE /*
    required */
    , MAP_SHARED /* recommended */, fd, buf.m.offset);
  36.     if (MAP_FAILED == buffers[n_buffers].start)
  37.       errno_exit("mmap");
  38.   }
  39. }
 
 
3,capture_start
初始化以后就可以进行正题了,就是所谓的capture data.不过在此之前,应该打开数据流通道,重点在于最后那个ioctl函数的参数:VIDIOC_STREAMON
 
  1. static void captureStart(void) //grap
    after initialize
  2. {
  3.   unsigned int i;
  4.   enum v4l2_buf_type type; //page-68
  5.  #ifdef IO_MMAP
  6.     
  7.       for (= 0; i < n_buffers; ++i) {
  8.         struct v4l2_buffer buf;
  9.         CLEAR (buf);
  10.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  11.         buf.memory = V4L2_MEMORY_MMAP;
  12.         buf.index = i;
  13.         if (-== xioctl(fd, VIDIOC_QBUF, &buf))
  14.           errno_exit("VIDIOC_QBUF");
  15.       }
  16.       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  17.       if (-== xioctl(fd, VIDIOC_STREAMON, &type))
  18.         errno_exit("VIDIOC_STREAMON");
  19.        #endif
上面出现的两个结构体的分别定义如下:
 
  1. enum v4l2_buf_type {
  2.     V4L2_BUF_TYPE_VIDEO_CAPTURE = 1,
  3.     V4L2_BUF_TYPE_VIDEO_OUTPUT = 2,
  4.     V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
  5.     V4L2_BUF_TYPE_VBI_CAPTURE = 4,
  6.     V4L2_BUF_TYPE_VBI_OUTPUT = 5,
  7.     V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6,
  8.     V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7,
  9. #if 1
  10.     /* Experimental */
  11.     V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
  12. #endif
  13.     V4L2_BUF_TYPE_PRIVATE = 0x80,
  14. };
  1. struct v4l2_buffer {
  2.     __u32            index;
  3.     enum v4l2_buf_type type;
  4.     __u32            bytesused;
  5.     __u32            flags;
  6.     enum v4l2_field        field;
  7.     struct timeval        timestamp;
  8.     struct v4l2_timecode    timecode;
  9.     __u32            sequence;
  10.     /* memory location */
  11.     enum v4l2_memory memory;
  12.     union {
  13.         __u32 offset;
  14.         unsigned long userptr;

抱歉!评论已关闭.