V4L2学习记录【转】

简介:

转自:http://blog.chinaunix.net/uid-30254565-id-5637600.html

    1. 4L2学习记录
    2.                                                                                                                                    这个还没有分析完,先在这放着,防止电脑坏掉丢了,以后再完善
    3. V4L2的全称是video for linux two。

    4. V4L2 驱动核心
    5. V4L2 驱动源码在 drivers/media/video目录下,主要核心代码有:
    6. v4l2-dev.//linux版本2视频捕捉接口,主要结构体 video_device 的注册 
    7. v4l2-common.//在Linux操作系统体系采用低级别的操作一套设备structures/vectors的通用视频设备接口。 
    8. v4l2-device.//V4L2的设备支持。注册v4l2_device。
    9. v4l22-ioctl.//处理V4L2的ioctl命令的一个通用的框架。 
    10. v4l2-subdev.//v4l2子设备 
    11. v4l2-mem2mem.//内存到内存为Linux和videobuf视频设备的框架。设备的辅助函数,使用其源和目的地videobuf缓冲区。 

    12. 直接来看驱动源码的话,还是对驱动的框架没有一个感性的认识,尤其这个V4L2的框架非常复杂,我们先从内核源码中提供的虚拟视频驱动程序vivi.c来分析。内核版本3.4.2。

    13. 虚拟视频驱动程序vivi.c源码分析
    14. 16年1月18日09:35:42
    15. (1)分析一个程序从它的init入口函数开始分析:
    16. static int __init vivi_init(void

    17.     const struct font_desc *font = find_font("VGA8x16")
    18.     int ret = 0, i

    19.     if (font =NULL
    20.         printk(KERN_ERR "vivi: could not find font\n")
    21.         return -ENODEV
    22.     
    23.     font8x16 = font->data

    24.     if (n_devs <= 0
    25.         n_devs = 1

    26.     for (= 0; i < n_devs; i++
    27.         ret = vivi_create_instance(i)
    28.         if (ret
    29.             /If some instantiations succeeded, keep driver *
    30.             if (i
    31.                 ret = 0
    32.             break
    33.         
    34.     

    35.     if (ret < 0
    36.         printk(KERN_ERR "vivi: error %d while loading driver\n", ret)
    37.         return ret
    38.     

    39.     printk(KERN_INFO "Video Technology Magazine Virtual Video " 
    40.             "Capture Board ver %s successfully loaded.\n"
    41.             VIVI_VERSION)
    42.  
    43.     /* n_devs will reflect the actual number of allocated devices *
    44.     n_devs = i

    45.     return ret


    46. static void __exit vivi_exit(void

    47.     vivi_release()


    48. module_init(vivi_init)
    49. module_exit(vivi_exit);

    50. 其中n_devs的定义在前面,如下所示:
    51. static unsigned n_devs = 1
    52. module_param(n_devs, uint, 0644)
    53. MODULE_PARM_DESC(n_devs"number of video devices to create");
    54. 写的很清楚了, n_devs表示想要创建的 video devices个数。
    55. 去掉其他的判断语句,发现重要的函数只有一个vivi_create_instance(i)函数,我们下面就来分析这个函数。
    56. (2)vivi_create_instance(i)函数:
    57. static int __init vivi_create_instance(int inst

    58.     struct vivi_dev *dev
    59.     struct video_device *vfd
    60.     struct v4l2_ctrl_handler *hdl
    61.     struct vb2_queue *q
    62.     int ret

    63.     dev = kzalloc(sizeof(*dev), GFP_KERNEL)
    64.     if (!dev
    65.         return -ENOMEM

    66.     snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name)
    67.             "%s-%03d", VIVI_MODULE_NAME, inst)
    68.     ret = v4l2_device_register(NULL&dev->v4l2_dev)
    69.     if (ret
    70.         goto free_dev

    71.     dev->fmt &formats[0]
    72.     dev->width = 640
    73.     dev->height = 480
    74.     hdl &dev->ctrl_handler
    75.     v4l2_ctrl_handler_init(hdl, 11)
    76.     dev->volume = v4l2_ctrl_new_std(hdl&vivi_ctrl_ops
    77.             V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200)
    78.     dev->brightness = v4l2_ctrl_new_std(hdl&vivi_ctrl_ops
    79.             V4L2_CID_BRIGHTNESS, 0, 255, 1, 127)
    80.     dev->contrast = v4l2_ctrl_new_std(hdl&vivi_ctrl_ops
    81.             V4L2_CID_CONTRAST, 0, 255, 1, 16)
    82.     dev->saturation = v4l2_ctrl_new_std(hdl&vivi_ctrl_ops
    83.             V4L2_CID_SATURATION, 0, 255, 1, 127)
    84.     dev->hue = v4l2_ctrl_new_std(hdl&vivi_ctrl_ops
    85.             V4L2_CID_HUE-128, 127, 1, 0)
    86.     dev->autogain = v4l2_ctrl_new_std(hdl&vivi_ctrl_ops
    87.             V4L2_CID_AUTOGAIN, 0, 1, 1, 1)
    88.     dev->gain = v4l2_ctrl_new_std(hdl&vivi_ctrl_ops
    89.             V4L2_CID_GAIN, 0, 255, 1, 100)
    90.     dev->button = v4l2_ctrl_new_custom(hdl&vivi_ctrl_buttonNULL)
    91.     dev->int32 = v4l2_ctrl_new_custom(hdl&vivi_ctrl_int32NULL)
    92.     dev->int64 = v4l2_ctrl_new_custom(hdl&vivi_ctrl_int64NULL)
    93.     dev->boolean = v4l2_ctrl_new_custom(hdl&vivi_ctrl_booleanNULL)
    94.     dev->menu = v4l2_ctrl_new_custom(hdl&vivi_ctrl_menuNULL)
    95.     dev->string = v4l2_ctrl_new_custom(hdl&vivi_ctrl_stringNULL)
    96.     dev->bitmask = v4l2_ctrl_new_custom(hdl&vivi_ctrl_bitmaskNULL)
    97.     if (hdl->error
    98.         ret = hdl->error
    99.         goto unreg_dev
    100.     
    101.     v4l2_ctrl_auto_cluster(2&dev->autogain, 0true)
    102.     dev->v4l2_dev.ctrl_handler = hdl

    103.     /* initialize locks *
    104.     spin_lock_init(&dev->slock)

    105.     /* initialize queue *
    106.     q &dev->vb_vidq
    107.     memset(q, 0, sizeof(dev->vb_vidq))
    108.     q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE
    109.     q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ
    110.     q->drv_priv = dev
    111.     q->buf_struct_size = sizeof(struct vivi_buffer)
    112.     q->ops &vivi_video_qops
    113.     q->mem_ops &vb2_vmalloc_memops

    114.     vb2_queue_init(q)

    115.     mutex_init(&dev->mutex)

    116.     /* init video dma queues *
    117.     INIT_LIST_HEAD(&dev->vidq.active)
    118.     init_waitqueue_head(&dev->vidq.wq)

    119.     ret -ENOMEM
    120.     vfd = video_device_alloc()
    121.     if (!vfd
    122.         goto unreg_dev

    123.     *vfd = vivi_template
    124.     vfd->debug = debug
    125.     vfd->v4l2_dev &dev->v4l2_dev
    126.     set_bit(V4L2_FL_USE_FH_PRIO&vfd->flags)

    127.     /
    128.      * Provide a mutex to v4l2 core. It will be used to protect 
    129.      * all fops and v4l2 ioctls
    130.      *
    131.     vfd->lock &dev->mutex

    132.     ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr)
    133.     if (ret < 0
    134.         goto rel_vdev

    135.     video_set_drvdata(vfd, dev)

    136.     /Now that everything is finelet's add it to device list *
    137.     list_add_tail(&dev->vivi_devlist&vivi_devlist)

    138.     if (video_nr !-1
    139.         video_nr++

    140.     dev->vfd = vfd
    141.     v4l2_info(&dev->v4l2_dev"V4L2 device registered as %s\n"
    142.          video_device_node_name(vfd))
    143.     return 0

    144. rel_vdev
    145.     video_device_release(vfd)
    146. unreg_dev
    147.     v4l2_ctrl_handler_free(hdl)
    148.     v4l2_device_unregister(&dev->v4l2_dev)
    149. free_dev
    150.     kfree(dev)
    151.     return ret
    152. }

    153. 1. 函数首先为struct vivi_dev *dev;分配内存,然后将dev->v4l2_dev.name的名字设置为“vivi-i”的形式,然后调用 v4l2_device_register这个函数来注册dev->v4l2_dev这个结构体,结构体v4l2_device如下所示,看它的名字就叫V4L2设备,它肯定就是V4L2设备的核心结构体:
    154. struct v4l2_device 
    155.     /* dev->driver_data points to this struct
    156.      Note: dev might be NULL if there is no parent device 
    157.      as is the case with e.g. ISA devices*
    158.     struct device *dev
    159. #if defined(CONFIG_MEDIA_CONTROLLER
    160.     struct media_device *mdev
    161. #endif 
    162.     /* used to keep track of the registered subdevs *
    163.     struct list_head subdevs
    164.     /* lock this struct; can be used by the driver as well if this 
    165.      struct is embedded into a larger struct*
    166.     spinlock_t lock
    167.     /* unique device name, by default the driver name + bus ID *
    168.     char name[V4L2_DEVICE_NAME_SIZE]
    169.     /* notify callback called by some sub-devices*
    170.     void (*notify)(struct v4l2_subdev *sd
    171.             unsigned int notification, void *arg)
    172.     /* The control handler. May be NULL*
    173.     struct v4l2_ctrl_handler *ctrl_handler
    174.     /* Device's priority state *
    175.     struct v4l2_prio_state prio
    176.     /* BKL replacement mutex. Temporary solution only*
    177.     struct mutex ioctl_lock
    178.     /* Keep track of the references to this struct*
    179.     struct kref ref
    180.     /* Release function that is called when the ref count goes to 0*
    181.     void (*release)(struct v4l2_device *v4l2_dev)
    182. };

    183. 可以看到这个结构体里面包含一个device父设备成员,一个subdevs子设备链表头,一个自旋锁,一个notify函数指针,v4l2_ctrl_handler控制句柄,prio优先级,ref引用计数,还有一个release函数指针。暂时先不对这个结构体进行具体的分析,在以后分析V4L2框架的时候再分析。
    184. 2. 它通过v4l2_device_register(NULL&dev->v4l2_dev);函数来完成对结构体的注册,可以看出在”vivi.c”中,它的父设备为NULL, v4l2_device_register这个函数在v4l2-device.c中:
    185. int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev

    186.     if (v4l2_dev =NULL
    187.         return -EINVAL

    188.     INIT_LIST_HEAD(&v4l2_dev->subdevs)
    189.     spin_lock_init(&v4l2_dev->lock)
    190.     mutex_init(&v4l2_dev->ioctl_lock)
    191.     v4l2_prio_init(&v4l2_dev->prio)
    192.     kref_init(&v4l2_dev->ref)
    193.     get_device(dev)
    194.     v4l2_dev->dev = dev
    195.     if (dev =NULL
    196.         /If dev =NULLthen name must be filled in by the caller *
    197.         WARN_ON(!v4l2_dev->name[0])
    198.         return 0
    199.     

    200.     /Set name to driver name + device name if it is empty*
    201.     if (!v4l2_dev->name[0]
    202.         snprintf(v4l2_dev->name, sizeof(v4l2_dev->name)"%s %s"
    203.             dev->driver->name, dev_name(dev))
    204.     if (!dev_get_drvdata(dev)
    205.         dev_set_drvdata(dev, v4l2_dev)
    206.     return 0

    207. EXPORT_SYMBOL_GPL(v4l2_device_register);

    208. 这个函数完成了子设备链表的初始化,自旋锁,互斥量,优先级,引用计数的初始化,其他并没有做太多工作。

    209. 3. 继续回到vivi_create_instance(i)函数中进行分析,下一句话:dev->fmt &formats[0]
    210. 通过向前搜索发现,vivi.c维持着一个 formats数组,它表示vivi.c支持的数据格式。关于视频的格式我们在V4L2框架中介绍,通过这行代码,我们知道了vivi.c所支持的格式为 V4L2_PIX_FMT_YUYV。
    211. struct vivi_fmt 
    212.     char *name
    213.     u32 fourcc/* v4l2 format id *
    214.     int depth
    215. }

    216. static struct vivi_fmt formats[
    217.     
    218.         .name "4:2:2, packed, YUYV"
    219.         .fourcc = V4L2_PIX_FMT_YUYV
    220.         .depth = 16
    221.     }
    222.     
    223.         .name "4:2:2, packed, UYVY"
    224.         .fourcc = V4L2_PIX_FMT_UYVY
    225.         .depth = 16
    226.     }
    227.     
    228.         .name "RGB565 (LE)"
    229.         .fourcc = V4L2_PIX_FMT_RGB565/* gggbbbbb rrrrrggg *
    230.         .depth = 16
    231.     }
    232.     
    233.         .name "RGB565 (BE)"
    234.         .fourcc = V4L2_PIX_FMT_RGB565X/* rrrrrggg gggbbbbb *
    235.         .depth = 16
    236.     }
    237.     
    238.         .name "RGB555 (LE)"
    239.         .fourcc = V4L2_PIX_FMT_RGB555/* gggbbbbb arrrrrgg *
    240.         .depth = 16
    241.     }
    242.     
    243.         .name "RGB555 (BE)"
    244.         .fourcc = V4L2_PIX_FMT_RGB555X/* arrrrrgg gggbbbbb *
    245.         .depth = 16
    246.     }
    247. };

    248. 4.继续在vivi_create_instance(i)函数中分析 :
    249.     hdl &dev->ctrl_handler
    250.     v4l2_ctrl_handler_init(hdl, 11);
    251. v4l2_ctrl_handler结构体在v4l2-ctrls.h中定义,如下所示:
    252. struct v4l2_ctrl_handler 
    253.     struct mutex lock
    254.     struct list_head ctrls
    255.     struct list_head ctrl_refs
    256.     struct v4l2_ctrl_ref *cached
    257.     struct v4l2_ctrl_ref **buckets
    258.     u16 nr_of_buckets
    259.     int error
    260. };
    261. v4l2_ctrl_handler是用于保存子设备控制方法集的结构体,对于视频设备这些ctrls包括设置亮度、饱和度、对比度和 清晰度等,用链表的方式来保存ctrls,可以通过v4l2_ctrl_new_std函数向链表添加ctrls。在下面的代码中用到了这个函数。
    262. /* Initialize the handler *
    263. int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl
    264.              unsigned nr_of_controls_hint

    265.     mutex_init(&hdl->lock)
    266.     INIT_LIST_HEAD(&hdl->ctrls)
    267.     INIT_LIST_HEAD(&hdl->ctrl_refs)
    268.     hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8
    269.     hdl->buckets = kcalloc(hdl->nr_of_buckets, sizeof(hdl->buckets[0])
    270.              GFP_KERNEL)
    271.     hdl->error = hdl->buckets ? 0 -ENOMEM
    272.     return hdl->error

    273. EXPORT_SYMBOL(v4l2_ctrl_handler_init)

    274. 通过nr_of_controls_hint变量的大小,计算出nr_of_buckets,并为 buckets申请空间,并将申请结果保存在error变量中。 

    275. 5. 继续在vivi_create_instance(i)函数中分析,继续设置dev结构体中的其他一些参数,对volume,brightness,contrast, saturation等参数设置的时候,调用了 v4l2_ctrl_new_std这个函数,以及对button, int32, menu,bitmask等参数的设置,调用了v4l2_ctrl_new_custom这个函数,一看就知道这两个函数是V4L2框架所提供的接口函数。
    276. struct v4l2_ctrl *v4l2_ctrl_new_std(structv4l2_ctrl_handler *hdl, conststruct v4l2_ctrl_ops *ops, u32id, s32 min, s32 max,u32 step, s32 def
    277. hdl是初始化好的v4l2_ctrl_handler结构体
    278. ops是v4l2_ctrl_ops结构体,包含ctrls的具体实现
    279. id是通过IOCTL的arg参数传过来的指令,定义在v4l2-controls.h文件
    280. min、max用来定义某操作对象的范围。如
    281. v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS,-208, 127, 1, 0)
    282. 用户空间可以通过ioctl的VIDIOC_S_CTRL指令调用到v4l2_ctrl_handler,id透过arg参数传递。
    283. 通过几个函数来完成对视频中亮度,饱和度等的设置。

    284. 6. 然后是缓冲区队列的操作,设置vb2_queue队列q的一些参数,最主要的是下面两个参数:
    285.     q->ops &vivi_video_qops
    286.     q->mem_ops &vb2_vmalloc_memops;
    287. 可以看到:q->ops &vivi_video_qops;中vivi_video_qops是需要vivi.c实现的一个操作函数集,它在vivi.c中定义如下:
    288. static struct vb2_ops vivi_video_qops 
    289.     .queue_setup        = queue_setup
    290.     .buf_init        = buffer_init
    291.     .buf_prepare        = buffer_prepare
    292.     .buf_finish        = buffer_finish
    293.     .buf_cleanup        = buffer_cleanup
    294.     .buf_queue        = buffer_queue
    295.     .start_streaming    = start_streaming
    296.     .stop_streaming        = stop_streaming
    297.     .wait_prepare        = vivi_unlock
    298.     .wait_finish        = vivi_lock
    299. };

    300. 这几个函数是需要我们写驱动程序的时候自己实现的函数。
    301. 其中 vb2_ops结构体在videobuf2-core.h中定义,如下所示:
    302. struct vb2_ops 
    303.     int (*queue_setup)(struct vb2_queue *qconst struct v4l2_format *fmt
    304.              unsigned int *num_buffers, unsigned int *num_planes
    305.              unsigned int sizes[], void *alloc_ctxs[])

    306.     void (*wait_prepare)(struct vb2_queue *q)
    307.     void (*wait_finish)(struct vb2_queue *q)

    308.     int (*buf_init)(struct vb2_buffer *vb)
    309.     int (*buf_prepare)(struct vb2_buffer *vb)
    310.     int (*buf_finish)(struct vb2_buffer *vb)
    311.     void (*buf_cleanup)(struct vb2_buffer *vb)

    312.     int (*start_streaming)(struct vb2_queue *q, unsigned int count)
    313.     int (*stop_streaming)(struct vb2_queue *q)

    314.     void (*buf_queue)(struct vb2_buffer *vb)
    315. };

    316. 对于 vb2_vmalloc_memops结构体,它在videobuf2-vmalloc.c中定义,如下所示:
    317. const struct vb2_mem_ops vb2_vmalloc_memops 
    318.     .alloc        = vb2_vmalloc_alloc
    319.     .put        = vb2_vmalloc_put
    320.     .get_userptr    = vb2_vmalloc_get_userptr
    321.     .put_userptr    = vb2_vmalloc_put_userptr
    322.     .vaddr        = vb2_vmalloc_vaddr
    323.     .mmap        = vb2_vmalloc_mmap
    324.     .num_users    = vb2_vmalloc_num_users
    325. }
    326. EXPORT_SYMBOL_GPL(vb2_vmalloc_memops);

    327. 看它的名字是vb2开头的,这几个函数应该都是系统为我们提供好的函数,通过查看源码发现,它确实存在于videobuf2-vmalloc.c中。
    328. 然后调用vb2_queue_init(q);函数来初始化它,vb2_queue_init(q)函数如下所示:
    329. /*
    330.  * vb2_queue_init(- initialize a videobuf2 queue 
    331.  * @q:        videobuf2 queue; this structure should be allocated in driver 
    332.  
    333.  * The vb2_queue structure should be allocated by the driver. The driver is 
    334.  * responsible of clearing it's content and setting initial values for some 
    335.  * required entries before calling this function
    336.  * q->ops, q->mem_ops, q->type and q->io_modes are mandatory. Please refer 
    337.  to the struct vb2_queue description in include/media/videobuf2-core.
    338.  for more information
    339.  *
    340. int vb2_queue_init(struct vb2_queue *q

    341.     BUG_ON(!q)
    342.     BUG_ON(!q->ops)
    343.     BUG_ON(!q->mem_ops)
    344.     BUG_ON(!q->type)
    345.     BUG_ON(!q->io_modes)

    346.     BUG_ON(!q->ops->queue_setup)
    347.     BUG_ON(!q->ops->buf_queue)

    348.     INIT_LIST_HEAD(&q->queued_list)
    349.     INIT_LIST_HEAD(&q->done_list)
    350.     spin_lock_init(&q->done_lock)
    351.     init_waitqueue_head(&q->done_wq)

    352.     if (q->buf_struct_size == 0
    353.         q->buf_struct_size = sizeof(struct vb2_buffer)

    354.     return 0

    355. EXPORT_SYMBOL_GPL(vb2_queue_init);

    356. 它只是完成了一些检查判断的语句,进行了一些链表,自旋锁等的初始化。

    357. 7/* init video dma queues *
    358.     INIT_LIST_HEAD(&dev->vidq.active)
    359.     init_waitqueue_head(&dev->vidq.wq);

    360. 8.下面是对video_device的操作,它算是这个函数中核心的操作:
    361. struct video_device *vfd;
    362. vfd = video_device_alloc();
    363. *vfd = vivi_template;
    364. ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
    365. video_set_drvdata(vfd, dev)

    366. 8.1先来看这个video_device结构体,它在v4l2-dev.h中定义,显示如下:
    367. struct video_device 

    368.     /* device ops *
    369.     const struct v4l2_file_operations *fops
    370.     /* sysfs *
    371.     struct device dev;        /* v4l device *
    372.     struct cdev *cdev;        /* character device *
    373.     /Set either parent or v4l2_dev if your driver uses v4l2_device *
    374.     struct device *parent;        /* device parent *
    375.     struct v4l2_device *v4l2_dev;    /* v4l2_device parent *
    376.     /* Control handler associated with this device node. May be NULL*
    377.     struct v4l2_ctrl_handler *ctrl_handler
    378.     /* Priority stateIf NULLthen v4l2_dev->prio will be used*
    379.     struct v4l2_prio_state *prio
    380.     /* device info *
    381.     char name[32]
    382.     int vfl_type
    383.     /'minoris set to -if the registration failed *
    384.     int minor
    385.     u16 num
    386.     /* use bitops to set/clear/test flags *
    387.     unsigned long flags
    388.     /* attribute to differentiate multiple indices on one physical device *
    389.     int index
    390.     /* V4L2 file handles *
    391.     spinlock_t        fh_lock/* Lock for all v4l2_fhs *
    392.     struct list_head    fh_list/* List of struct v4l2_fh *
    393.     int debug;            /* Activates debug level*
    394.     /* Video standard vars *
    395.     v4l2_std_id tvnorms;        /* Supported tv norms *
    396.     v4l2_std_id current_norm;    /* Current tvnorm *
    397.     /* callbacks *
    398.     void (*release)(struct video_device *vdev)
    399.     /* ioctl callbacks *
    400.     const struct v4l2_ioctl_ops *ioctl_ops
    401.     /* serialization lock *
    402.     struct mutex *lock
    403. };

    404. 根据注释应该能大致了解各个成员的意义。后面有这个函数的一些初始化和注册函数,里面肯定有对这个结构体成员的设置初始化等,所以我们在后面再具体分析这些成员。

    405. 8.2 下面来看video_device_alloc函数。它在v4l2-dev.c中定义:
    406. struct video_device *video_device_alloc(void

    407.     return kzalloc(sizeof(struct video_device), GFP_KERNEL)

    408. EXPORT_SYMBOL(video_device_alloc);

    409. 只是分配了一段内存,然后将它置为0,并没有对video_device结构体里面的成员进行设置。

    410. 8.3 然后vivi.c中下一句是*vfd = vivi_template;在vivi.c中搜索发现,它在前面定义:
    411. static struct video_device vivi_template 
    412.     .name        "vivi"
    413.     .fops &vivi_fops
    414.     .ioctl_ops     &vivi_ioctl_ops
    415.     .release    = video_device_release

    416.     .tvnorms = V4L2_STD_525_60
    417.     .current_norm = V4L2_STD_NTSC_M
    418. };

    419. 对比video_device结构体中的成员,可以确定就是在这进行赋值的。它只是对其中某些成员进行了赋。

    420. 8.3.1 video_device结构体中首先是.fops &vivi_fops,在vivi.c中搜索如下所示:
    421. static const struct v4l2_file_operations vivi_fops 
    422.     .owner        = THIS_MODULE
    423.     .open = v4l2_fh_open
    424.     .release = vivi_close
    425.     .read = vivi_read
    426.     .poll        = vivi_poll
    427.     .unlocked_ioctl = video_ioctl2/* V4L2 ioctl handler *
    428.     .mmap = vivi_mmap
    429. };

    430. 先来看这几个函数的名字,其中open函数和unlocked_ioctl函数的名字与其他的不同,直觉告诉我,他俩是系统提供的,其他的函数名字都是vivi开头的,应该是这个文件里面实现的函数,我们在vivi.c中搜索就可以找到,但是我们暂时先不具体分析这几个函数。

    431. 8.3.2 video_device结构体中第二个是.ioctl_ops &vivi_ioctl_ops,看名字也是在vivi.c中定义的:
    432. static const struct v4l2_ioctl_ops vivi_ioctl_ops 
    433.     .vidioc_querycap = vidioc_querycap
    434.     .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap
    435.     .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap
    436.     .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap
    437.     .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap
    438.     .vidioc_reqbufs = vidioc_reqbufs
    439.     .vidioc_querybuf = vidioc_querybuf
    440.     .vidioc_qbuf = vidioc_qbuf
    441.     .vidioc_dqbuf = vidioc_dqbuf
    442.     .vidioc_s_std = vidioc_s_std
    443.     .vidioc_enum_input = vidioc_enum_input
    444.     .vidioc_g_input = vidioc_g_input
    445.     .vidioc_s_input = vidioc_s_input
    446.     .vidioc_streamon = vidioc_streamon
    447.     .vidioc_streamoff = vidioc_streamoff
    448.     .vidioc_log_status = v4l2_ctrl_log_status
    449.     .vidioc_subscribe_event = v4l2_ctrl_subscribe_event
    450.     .vidioc_unsubscribe_event = v4l2_event_unsubscribe
    451. };

    452. 可以看到,这是一大堆的ioctl调用,大致可分为以下几类:
    453. 查询性能query capability的:vidioc_querycap;
    454. 对format的一些操作: vidioc_enum_fmt_vid_cap, vidioc_g_fmt_vid_cap, vidioc_try_fmt_vid_cap, vidioc_s_fmt_vid_cap;
    455. 对缓冲区的一些操作: vidioc_reqbufs, vidioc_querybuf, vidioc_qbuf, vidioc_dqbuf;
    456. 对标准standard的操作: vidioc_s_std;
    457. 对输入input的操作: vidioc_enum_input, vidioc_g_input, vidioc_s_input;
    458. 对流stream的操作: vidioc_streamon, vidioc_streamoff;
    459. 以上几个ioctl调用都是需要我们自己实现的,后面3个ioctl的名字是v4l2开头的,应该是系统里面实现好的函数,搜索可以发现在v4l2-ctrls.c和v4l2-event.c中定义。 

    460. 8.3.3 video_device结构体中第三个是.release = video_device_release,它在v4l2-dev.c中定义,如下所示:
    461. void video_device_release(struct video_device *vdev

    462.     kfree(vdev)

    463. EXPORT_SYMBOL(video_device_release);

    464. 8.3.4 video_device结构体中第四,五个是:
    465.     .tvnorms = V4L2_STD_525_60
    466.     .current_norm = V4L2_STD_NTSC_M
    467. 通过看video_device结构体中的注释,
    468.     /* Video standard vars *
    469.     v4l2_std_id tvnorms;        /* Supported tv norms *
    470.     v4l2_std_id current_norm;    /* Current tvnorm *
    471. 是指支持的tv制式以及当前的tv制式。

    472. 8.3.5 分析完了vivi_template中的成员,也即video_device结构体中的成员,还是有点迷惑的,在
    473. video_device结构体中,有一个struct v4l2_file_operations成员,这个成员又包含一个unlocked_ioctl,同时video_device结构体中还有一个struct v4l2_ioctl_ops成员,怎么有两个ioctl成员函数啊?先大致分析一些,struct v4l2_file_operations vivi_fops中.unlocked_ioctl = video_ioctl2,这个video_ioctl2在v4l2-ioctl.c中:
    474. long video_ioctl2(struct file *file
    475.      unsigned int cmd, unsigned long arg

    476.     return video_usercopy(file, cmd, arg, __video_do_ioctl)

    477. EXPORT_SYMBOL(video_ioctl2);
    478. 它又调用了__video_do_ioctl函数,也在v4l2-ioctl.c中,这个__video_do_ioctl函数是一个大的switch,case语句,根据不同的case,调用不同的函数,以 VIDIOC_QUERYCAP为例:
    479. struct video_device *vfd = video_devdata(file);
    480. const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
    481. case VIDIOC_QUERYCAP:
    482. ret = ops->vidioc_querycap(file, fh, cap);
    483. 用在vivi.c这个例子中就是: vfd这个结构体就是vivi_template, ops就是vivi_template中的ioctl_ops成员,也就是vivi_ioctl_ops,对于 VIDIOC_QUERYCAP宏,真正调用的是vivi_ioctl_ops中的.vidioc_querycap成员,也即我们在vivi.c中自己实现的
    484. static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap)函数。有点绕,我已晕@_@!~~
    485. 咱们在后面再具体分析。

    486. 8.4 继续在vivi_create_instance中分析:
    487.     vfd->debug = debug
    488.     vfd->v4l2_dev &dev->v4l2_dev
    489. 注意这个语句,从这里可以看出在注册video_device之前必须先注册了v4l2_device。
    490.     set_bit(V4L2_FL_USE_FH_PRIO&vfd->flags);
    491.     vfd->lock &dev->mutex;
    492. 进行了一些设置,然后就是大boss了:
    493. ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
    494. 它在v4l2-dev.h中定义,如下所示:
    495. static inline int __must_check video_register_device_no_warn
    496.         struct video_device *vdevint typeint nr

    497.     return __video_register_device(vdev, type, nr, 0, vdev->fops->owner)
    498. }
    499. __video_register_device在v4l2-dev.c中定义:(就直接在代码中注释了)
    500. /*
    501.  *    __video_register_device - register video4linux devices 
    502.  *    @vdev: video device structure we want to register 
    503.  *    @type: type of device to register 
    504.  *    @nr: which device node number (=/dev/video0, 1 =/dev/video1..
    505.  -== first free
    506.  *    @warn_if_nr_in_use: warn if the desired device node number 
    507.  *     was already in use and another number was chosen instead
    508.  *    @owner: module that owns the video device node 
    509.  
    510.  *    The registration code assigns minor numbers and device node numbers 
    511.  *    based on the requested type and registers the new device node with 
    512.  *    the kernel
    513.  
    514.  *    This function assumes that struct video_device was zeroed when it 
    515.  *    was allocated and does not contain any stale date
    516.  
    517.  *    An error is returned if no free minor or device node number could be 
    518.  *    foundor if the registration of the device node failed
    519.  
    520.  *    Zero is returned on success
    521.  
    522.  *    Valid types are 
    523.  
    524.  *    %VFL_TYPE_GRABBER - A frame grabber 
    525.  
    526.  *    %VFL_TYPE_VBI - Vertical blank data (undecoded
    527.  
    528.  *    %VFL_TYPE_RADIO - A radio card 
    529.  
    530.  *    %VFL_TYPE_SUBDEV - A subdevice 
    531.  */
    532. int __video_register_device(struct video_device *vdevint typeint nr
    533.         int warn_if_nr_in_use, struct module *owner

    534.     int i = 0
    535.     int ret
    536.     int minor_offset = 0
    537.     int minor_cnt = VIDEO_NUM_DEVICES
    538.     const char *name_base

    539.     /* A minor value of -1 marks this video device as never 
    540.      having been registered *
    541.     vdev->minor -1

    542.     /* the release callback MUST be present *
    543.     if (WARN_ON(!vdev->release)
    544.         return -EINVAL
    545. /* 如果没有提供这个release函数的话,就直接返回错误,它就在vivi_template中提供了。 */
    546.     /* v4l2_fh support *
    547.     spin_lock_init(&vdev->fh_lock)
    548.     INIT_LIST_HEAD(&vdev->fh_list)

    549.     /* Part 1: check device type *
    550.     switch (type
    551.     case VFL_TYPE_GRABBER
    552.         name_base "video"
    553.         break
    554.     case VFL_TYPE_VBI
    555.         name_base "vbi"
    556.         break
    557.     case VFL_TYPE_RADIO
    558.         name_base "radio"
    559.         break
    560.     case VFL_TYPE_SUBDEV
    561.         name_base "v4l-subdev"
    562.         break
    563.     default
    564.         printk(KERN_ERR "%s called with unknown type: %d\n"
    565.          __func__, type)
    566.         return -EINVAL
    567.     
    568. /* 根据传进来的type参数,确定设备在/dev目录下看到的名字 */
    569.     vdev->vfl_type = type
    570.     vdev->cdev NULL
    571.     if (vdev->v4l2_dev
    572.         if (vdev->v4l2_dev->dev
    573.             vdev->parent = vdev->v4l2_dev->dev
    574.         if (vdev->ctrl_handler =NULL
    575.             vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler
    576.         /If the prio state pointer is NULLthen use the v4l2_device 
    577.          prio state*
    578.         if (vdev->prio =NULL
    579.             vdev->prio &vdev->v4l2_dev->prio
    580.     
    581. /* 进行vdev中父设备和ctrl处理函数的初始化。*/
    582.     /* Part 2: find a free minor, device node number and device index*
    583. #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES 
    584.     /* Keep the ranges for the first four types for historical 
    585.      * reasons
    586.      * Newer devices (not yet in place) should use the range 
    587.      * of 128-191 and just pick the first free minor there 
    588.      (new style)*
    589.     switch (type
    590.     case VFL_TYPE_GRABBER
    591.         minor_offset = 0
    592.         minor_cnt = 64
    593.         break
    594.     case VFL_TYPE_RADIO
    595.         minor_offset = 64
    596.         minor_cnt = 64
    597.         break
    598.     case VFL_TYPE_VBI
    599.         minor_offset = 224
    600.         minor_cnt = 32
    601.         break
    602.     default
    603.         minor_offset = 128
    604.         minor_cnt = 64
    605.         break
    606.     
    607. #endif 

    608.     /* Pick a device node number *
    609.     mutex_lock(&videodev_lock)
    610.     nr = devnode_find(vdev, nr =-? 0 : nr, minor_cnt)
    611.     if (nr == minor_cnt
    612.         nr = devnode_find(vdev, 0, minor_cnt)
    613.     if (nr == minor_cnt
    614.         printk(KERN_ERR "could not get a free device node number\n")
    615.         mutex_unlock(&videodev_lock)
    616.         return -ENFILE
    617.     
    618. #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES 
    619.     /* 1-on-1 mapping of device node number to minor number *
    620.     i = nr
    621. #else 
    622.     /* The device node number and minor numbers are independent, so 
    623.      we just find the first free minor number*
    624.     for (= 0; i < VIDEO_NUM_DEVICES; i++
    625.         if (video_device[i=NULL
    626.             break
    627.     if (== VIDEO_NUM_DEVICES
    628.         mutex_unlock(&videodev_lock)
    629.         printk(KERN_ERR "could not get a free minor\n")
    630.         return -ENFILE
    631.     
    632. #endif 
    633.     vdev->minor = i + minor_offset
    634.     vdev->num = nr
    635.     devnode_set(vdev)

    636.     /* Should not happen since we thought this minor was free *
    637.     WARN_ON(video_device[vdev->minor!NULL)
    638.     vdev->index = get_index(vdev)
    639.     mutex_unlock(&videodev_lock)
    640. /* 上面的part2就是确定设备的次设备号 */
    641.     /* Part 3: Initialize the character device *
    642.     vdev->cdev = cdev_alloc()
    643.     if (vdev->cdev =NULL
    644.         ret -ENOMEM
    645.         goto cleanup
    646.     
    647. /* 在这进行设备的注册,用cdev_alloc函数,从这我们就可以看出来,它是一个普通的字符设备驱动,然后设置它的一些参数。怎么就是字符设备驱动了???这个在后面的v4l2框架中再说。 */
    648.     vdev->cdev->ops &v4l2_fops
    649. /* cdev结构体里面的ops指向了v4l2_fops这个结构体,这个v4l2_fops结构体也是在v4l2-dev.c这个文件中。又一个file_operations操作函数集,在vivi.c中有一个v4l2_file_operations vivi_fops,他俩又是什么关系呢? */
    650.     vdev->cdev->owner = owner
    651.     ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1)
    652.     if (ret < 0
    653.         printk(KERN_ERR "%s: cdev_add failed\n", __func__)
    654.         kfree(vdev->cdev)
    655.         vdev->cdev NULL
    656.         goto cleanup
    657.     


    658.     /* Part 4: register the device with sysfs *
    659.     vdev->dev.class &video_class
    660.     vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor)
    661.     if (vdev->parent
    662.         vdev->dev.parent = vdev->parent
    663.     dev_set_name(&vdev->dev"%s%d", name_base, vdev->num)
    664.     ret = device_register(&vdev->dev)
    665.     if (ret < 0
    666.         printk(KERN_ERR "%s: device_register failed\n", __func__)
    667.         goto cleanup
    668.     
    669.     /* Register the release callback that will be called when the last 
    670.      reference to the device goes away*
    671.     vdev->dev.release = v4l2_device_release

    672.     if (nr !-&& nr != vdev->num && warn_if_nr_in_use
    673.         printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__
    674.             name_base, nr, video_device_node_name(vdev))

    675.     /* Increase v4l2_device refcount *
    676.     if (vdev->v4l2_dev
    677.         v4l2_device_get(vdev->v4l2_dev)
    678. /* 在sysfs中创建类,在类下创建设备结点 */

    679. #if defined(CONFIG_MEDIA_CONTROLLER
    680.     /* Part 5: Register the entity*
    681.     if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &
    682.      vdev->vfl_type != VFL_TYPE_SUBDEV
    683.         vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L
    684.         vdev->entity.name = vdev->name
    685.         vdev->entity.info.v4l.major = VIDEO_MAJOR
    686.         vdev->entity.info.v4l.minor = vdev->minor
    687.         ret = media_device_register_entity(vdev->v4l2_dev->mdev
    688.             &vdev->entity)
    689.         if (ret < 0
    690.             printk(KERN_WARNING 
    691.              "%s: media_device_register_entity failed\n"
    692.              __func__)
    693.     
    694. #endif 
    695. /* 创建实体entity,这一步并不是必须的,需要配置了CONFIG_MEDIA_CONTROLLER选项后才会执行这一步,在这一步里面有一个media_entity实体结构体,在后面再分析它。 */
    696.     /* Part 6: Activate this minor. The char device can now be used*
    697.     set_bit(V4L2_FL_REGISTERED&vdev->flags)
    698. /* 设置标志位 */
    699.     mutex_lock(&videodev_lock)
    700.     video_device[vdev->minor= vdev
    701. /* 将设置好的video_device结构体vdev按照次设备号保存到video_device数组中。这个数组是在前面static struct video_device*video_device[VIDEO_NUM_DEVICES];定义的。 */
    702.     mutex_unlock(&videodev_lock)

    703.     return 0

    704. cleanup
    705.     mutex_lock(&videodev_lock)
    706.     if (vdev->cdev
    707.         cdev_del(vdev->cdev)
    708.     devnode_clear(vdev)
    709.     mutex_unlock(&videodev_lock)
    710.     /* Mark this video device as never having been registered*
    711.     vdev->minor -1
    712.     return ret

    713. EXPORT_SYMBOL(__video_register_device);

    714. 8.5 注册完video_device结构体后继续在vivi_create_instance中执行:
    715. video_set_drvdata(vfd, dev);
    716. /* 将vivi_dev dev添加到video_device vfd中,为什么要这样做呢?是为了以后字符设备驱动接口的使用。*/
    717. list_add_tail(&dev->vivi_devlist&vivi_devlist);
    718. /* 添加到device list链表中 */
    719. if (video_nr !-1
    720.     video_nr++
    721. /* 用于计数 */
    722. dev->vfd = vfd;
    723. /* 关联video_device 和vivi_dev。 */

    724. (三)到这里我们就分析完了vivi_init和vivi_create_instance函数,vivi.c中剩下的代码,基本就是以下3个结构体的具体实现代码我们暂时先不分析。
    725. static struct video_device vivi_template 
    726.     .name        "vivi"
    727.     .fops &vivi_fops
    728.     .ioctl_ops     &vivi_ioctl_ops
    729.     .release    = video_device_release
    730.     .tvnorms = V4L2_STD_525_60
    731.     .current_norm = V4L2_STD_NTSC_M
    732. };

    733. static const struct v4l2_ioctl_ops vivi_ioctl_ops 
    734.     .vidioc_querycap = vidioc_querycap
    735.     .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap
    736.     .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap
    737.     .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap
    738.     .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap
    739.     .vidioc_reqbufs = vidioc_reqbufs
    740.     .vidioc_querybuf = vidioc_querybuf
    741.     .vidioc_qbuf = vidioc_qbuf
    742.     .vidioc_dqbuf = vidioc_dqbuf
    743.     .vidioc_s_std = vidioc_s_std
    744.     .vidioc_enum_input = vidioc_enum_input
    745.     .vidioc_g_input = vidioc_g_input
    746.     .vidioc_s_input = vidioc_s_input
    747.     .vidioc_streamon = vidioc_streamon
    748.     .vidioc_streamoff = vidioc_streamoff
    749.     .vidioc_log_status = v4l2_ctrl_log_status
    750.     .vidioc_subscribe_event = v4l2_ctrl_subscribe_event
    751.     .vidioc_unsubscribe_event = v4l2_event_unsubscribe
    752. };

    753. static const struct v4l2_file_operations vivi_fops 
    754.     .owner        = THIS_MODULE
    755.     .open = v4l2_fh_open
    756.     .release = vivi_close
    757.     .read = vivi_read
    758.     .poll        = vivi_poll
    759.     .unlocked_ioctl = video_ioctl2/* V4L2 ioctl handler *
    760.     .mmap = vivi_mmap
    761. };
    762. 我们首先分析这个vivi.c的目的是为了先大致看一些v4l2驱动的代码,留一些疑问,以后分析v4l2的代码框架及一些概念的时候,还会以这个vivi.c为例子来说明。等到分析完大致的框架以后,我们再来继续仔细分析vivi.c中那些具体代码的实现。

    763. V4L2框架分析
    764. 16年1月18日19:12:43
    765. (一)概述
    766. Video4Linux2是Linux内核中关于视频设备的内核驱动框架,为上层的访问底层的视频设备提供了统一的接口。凡是内核中的子系统都有抽象底层硬件的差异,为上层提供统一的接口和提取出公共代码避免代码冗余等好处。 
    767. V4L2支持三类设备:GRABBER视频输入输出设备、VBI设备和RADIO设备(其实还支持更多类型的设备,暂不讨论),分别会在/dev目录下产生videoX、radioX和vbiX设备节点。我们常见的视频输入设备主要是摄像头,也是本文主要分析对象。下图V4L2在Linux系统中的结构图
    768.  
    769. Linux系统中视频输入设备主要包括以下四个部分
    770. (1)字符设备驱动程序核心:V4L2本身就是一个字符设备,具有字符设备所有的特性,暴露接口给用户空间
    771. (2)V4L2驱动核心:主要是构建一个内核中标准视频设备驱动的框架,为视频操作提供统一的接口函数
    772. (3)平台V4L2设备驱动:在V4L2框架下,根据平台自身的特性实现与平台相关的V4L2驱动部分,包括注册 video_device和v4l2_dev。 
    773. (4)具体的sensor驱动:主要上电、提供工作时钟、视频图像裁剪、流IO开启等,实现各种设备控制方法供上层调用并 注册v4l2_subdev 。

    774. V4L2的核心源码位于drivers/media/video中,在4.4版本的内核中位于drivers/media/v4l2-core,源码以实现的功能可以划分为四类
    775. 核心模块实现:由v4l2-dev.c实现,主要作用申请字符主设备号、注册class和提供video_device注册注销和file_operations等相关函数
    776. V4L2框架:由v4l2-device.c、v4l2-subdev.c、v4l2-fh.c、v4l2-ctrls.c等文件实现,构建V4L2框架
    777. Videobuf管理:由videobuf2-core.c、videobuf2-dma-contig.c、videobuf2-dma-sg.c、videobuf2-memops.c、 videobuf2-vmalloc.c、v4l2-mem2mem.c等文件实现,完成videobuffer的分配、管理和注销。 
    778. ioctl框架:由v4l2-ioctl.c文件实现,构建V4L2 ioctl的框架。
    779. (二)V4L2框架 
    780. 结构体v4l2_device、video_device、v4l2_subdev和v4l2_fh是搭建框架的主要元素。下图是V4L2框架的结构 图

    781. 从上图可以看出V4L2框架是一个标准的树形结构,v4l2_device充当了父设备,通过链表把所有注册到其下的子设备管理起来,这些设备可以是GRABBER、VBI或RADIO。v4l2_subdev是子设备,v4l2_subdev结构体包含了对设备操作的ops和ctrls,这部分代码和硬件相关,需要驱动工程师根据硬件实现,像摄像头设备需要实现控制上下电、读取ID、饱和度、对比度和视频数据流打开关闭的接口函数。video_device用于创建子设备节点,把操作设备的接口暴露给用户空间。V4l2_fh是每个子设备的文件句柄,在打开设备节点文件时设置,方便上层索引到v4l2_ctrl_handler,v4l2_ctrl_handler管理设备的ctrls,这些ctrls(摄像头设备)包括调节饱和度、对比度和白平衡等。

    782. (三)v4l2_device结构体
    783. v4l2_device在v4l2框架中充当所有v4l2_subdev的父设备,管理着注册在其下的子设备。 它在v4l2-device.h中定义,如下所示:
    784. struct v4l2_device 
    785.     /* dev->driver_data points to this struct
    786.      Note: dev might be NULL if there is no parent device 
    787.      as is the case with e.g. ISA devices*
    788.     struct device *dev
    789.     /* used to keep track of the registered subdevs *
    790.     struct list_head subdevs//它所管理的子设备链表头
    791.     /* lock this struct; can be used by the driver as well if this 
    792.      struct is embedded into a larger struct*
    793.     spinlock_t lock
    794.     /* unique device name, by default the driver name + bus ID *
    795.     char name[V4L2_DEVICE_NAME_SIZE]//device名字
    796.     /* notify callback called by some sub-devices*
    797.     void (*notify)(struct v4l2_subdev *sd
    798.             unsigned int notification, void *arg)
    799.     /* The control handler. May be NULL*
    800.     struct v4l2_ctrl_handler *ctrl_handler//控制接口
    801.     /* Device's priority state *
    802.     struct v4l2_prio_state prio//设备优先级状态
    803.     /* BKL replacement mutex. Temporary solution only*
    804.     struct mutex ioctl_lock
    805.     /* Keep track of the references to this struct*
    806.     struct kref ref//引用计数
    807.     /* Release function that is called when the ref count goes to 0*
    808.     void (*release)(struct v4l2_device *v4l2_dev)
    809. }
    810. 可以看出v4l2_device的主要作用是管理注册在其下的子设备,方便系统查找引用到。 
    811. V4l2_device的注册和注销
    812. int v4l2_device_register(struct device*dev, struct v4l2_device *v4l2_dev
    813. static void v4l2_device_release(struct kref *ref
    814. 暂时不对这两个函数进行具体分析,再后面会详细分析这个c文件。

    815. (四)V4l2_subdev 
    816. V4l2_subdev代表子设备,包含了子设备的相关属性和操作。先来看下结构体原型,在v4l2-subdev.h中:
    817. struct v4l2_subdev 
    818. #if defined(CONFIG_MEDIA_CONTROLLER
    819.     struct media_entity entity
    820. #endif 
    821.     struct list_head list
    822.     struct module *owner
    823.     u32 flags
    824.     struct v4l2_device *v4l2_dev//指向它的父设备
    825.     const struct v4l2_subdev_ops *ops//提供一些控制v4l2设备的接口 
    826.     /* Never call these internal ops from within a *
    827.     const struct v4l2_subdev_internal_ops *internal_ops//向V4L2框架提供的接口函数 
    828.     /* The control handler of this subdev. May be NULL*
    829.     struct v4l2_ctrl_handler *ctrl_handler//subdev控制接口 
    830.     /* name must be unique *
    831.     char name[V4L2_SUBDEV_NAME_SIZE]//subdev名字
    832.     /* can be used to group similar subdevs, value is driver-specific *
    833.     u32 grp_id
    834.     /* pointer to private data *
    835.     void *dev_priv
    836.     void *host_priv
    837.     /* subdev device node *
    838.     struct video_device *devnode
    839. };

    840. 每个子设备驱动都需要实现一个v4l2_subdev结构体,v4l2_subdev可以内嵌到其它结构体中,也可以独立使用。结构体中包含了对子设备操作的成员v4l2_subdev_ops和v4l2_subdev_internal_ops。 
    841. v4l2_subdev_ops结构体原型如下
    842. struct v4l2_subdev_ops 
    843.     const struct v4l2_subdev_core_ops    *core
    844.     const struct v4l2_subdev_tuner_ops    *tuner
    845.     const struct v4l2_subdev_audio_ops    *audio
    846.     const struct v4l2_subdev_video_ops    *video
    847.     const struct v4l2_subdev_vbi_ops    *vbi
    848.     const struct v4l2_subdev_ir_ops        *ir
    849.     const struct v4l2_subdev_sensor_ops    *sensor
    850.     const struct v4l2_subdev_pad_ops    *pad
    851. };
    852. 视频设备通常需要实现core和video成员,这两个ops中的操作都是可选的,但是对于视频流设备 
    853. video->s_stream(开启或关闭流IO)必须要实现。 
    854. v4l2_subdev_internal_ops结构体原型如下
    855. struct v4l2_subdev_internal_ops 
    856.     int (*registered)(struct v4l2_subdev *sd)
    857.     void (*unregistered)(struct v4l2_subdev *sd)
    858.     int (*open)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
    859.     int (*close)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
    860. };
    861. v4l2_subdev_internal_ops是向V4L2框架提供的接口,只能被V4L2框架层调用。在注册或打开子设备时,进行一些辅助性操作。

    862. subdev的注册和注销 
    863. 当我们把v4l2_subdev需要实现的成员都已经实现,就可以调用以下函数把子设备注册到V4L2核心层
    864. int v4l2_device_register_subdev(struct v4l2_device*v4l2_dev, struct v4l2_subdev *sd
    865. 当卸载子设备时,可以调用以下函数进行注销
    866. void v4l2_device_unregister_subdev(struct v4l2_subdev*sd


    867. (五)video_device 
    868. 1. video_device结构体用于在/dev目录下生成设备节点文件,把操作设备的接口暴露给用户空间。所以这个结构体是我们操作的重点,它直接与用户空间相联系。
    869. struct video_device 

    870. #if defined(CONFIG_MEDIA_CONTROLLER
    871.     struct media_entity entity
    872. #endif 
    873.     /* device ops *
    874.     const struct v4l2_file_operations *fops//V4L2设备操作函数集合 
    875.     /* sysfs *
    876.     struct device dev;        /* v4l device *
    877.     struct cdev *cdev;        /* character device *
    878.     /Set either parent or v4l2_dev if your driver uses v4l2_device *
    879.     struct device *parent;        /* device parent *
    880.     struct v4l2_device *v4l2_dev;    /* v4l2_device parent *
    881.     /* Control handler associated with this device node. May be NULL*
    882.     struct v4l2_ctrl_handler *ctrl_handler
    883.     /* Priority stateIf NULLthen v4l2_dev->prio will be used*
    884.     struct v4l2_prio_state *prio
    885.     /* device info *
    886.     char name[32]
    887.     int vfl_type
    888.     /'minoris set to -if the registration failed *
    889.     int minor
    890.     u16 num
    891.     /* use bitops to set/clear/test flags *
    892.     unsigned long flags
    893.     /* attribute to differentiate multiple indices on one physical device *
    894.     int index
    895.     /* V4L2 file handles *
    896.     spinlock_t        fh_lock/* Lock for all v4l2_fhs *
    897.     struct list_head    fh_list/* List of struct v4l2_fh *
    898.     int debug;            /* Activates debug level*
    899.     /* Video standard vars *
    900.     v4l2_std_id tvnorms;        /* Supported tv norms *
    901.     v4l2_std_id current_norm;    /* Current tvnorm *
    902.     /* callbacks *
    903.     void (*release)(struct video_device *vdev)
    904.     /* ioctl callbacks *
    905.     const struct v4l2_ioctl_ops *ioctl_ops/*ioctl回调函数集,提供                                     * file_operations中的ioctl调用 *
    906.     /* serialization lock *
    907.     struct mutex *lock
    908. };

    909. 2. video_device结构体的name字段是这类设备的名字,它将出现在内核日志和 sysfs中出现。这个名字 通常与驱动名称相同。

    910. 3. vfl_type字段可以是下列5个值之一,他们在v4l2-dev.h中定义:
    911. #define VFL_TYPE_GRABBER    0 
    912. #define VFL_TYPE_VBI        1 
    913. #define VFL_TYPE_RADIO        2 
    914. #define VFL_TYPE_SUBDEV        3 
    915. #define VFL_TYPE_MAX        4
    916. 4. V4L2驱动还要初始化的一个字段是 minor,它是你想要的子设备号。通常这个值都设为-1,这样会让video4linux子系统在注册时自动分配一个空的子设备号。

    917. 5. 在video_device结构体中,一共包含三组不同的函数指针集。
    918. 5.1第一个函数指针集只包含一个函数,就是
    919. void (*release)(struct video_device *vdev);
    920. 这个函数通常只包含一个简单的kfree调用,V4L2驱动框架中v4l2-dev.c中帮我们实现了video_device_release,一般让这个函数指向video_device_release即可。
    921. 5.2 第二个函数指针集是const struct v4l2_file_operations *fops; 它与file_operations结构体大致相同,在前面我们就说了,V4L2框架它就是一个字符设备驱动,怎么体现呢?以这个vivi.c为例:
    922. 首先,它作为一个字符设备驱动,肯定有对应的file_operations结构,它就在v4l2-dev.c中定义了:
    923. static const struct file_operations v4l2_fops 
    924.     .owner = THIS_MODULE
    925.     .read = v4l2_read
    926.     .write = v4l2_write
    927.     .open = v4l2_open
    928.     .get_unmapped_area = v4l2_get_unmapped_area
    929.     .mmap = v4l2_mmap
    930.     .unlocked_ioctl = v4l2_ioctl
    931.     .release = v4l2_release
    932.     .poll = v4l2_poll
    933.     .llseek = no_llseek
    934. };
    935. 然后,在vivi.c中,我们注册申请video_device vivi_template的时候,需要提供对应的v4l2_file_operations vivi_fops,如下所示:
    936. static struct video_device vivi_template 
    937.     .name        "vivi"
    938.     .fops &vivi_fops
    939.     .ioctl_ops     &vivi_ioctl_ops
    940.     .release    = video_device_release
    941.     .tvnorms = V4L2_STD_525_60
    942.     .current_norm = V4L2_STD_NTSC_M
    943. };

    944. static const struct v4l2_file_operations vivi_fops 
    945.     .owner        = THIS_MODULE
    946.     .open = v4l2_fh_open
    947.     .release = vivi_close
    948.     .read = vivi_read
    949.     .poll        = vivi_poll
    950.     .unlocked_ioctl = video_ioctl2/* V4L2 ioctl handler *
    951.     .mmap = vivi_mmap
    952. };
    953. 以read为例,应用程序在调用read的时候,对应到驱动file_operations v4l2_fops中的v4l2_read函数,在函数里面通过ret =vdev->fops->read(filp, buf, sz, off);最后调用到我们在vivi.c中申请注册的video_device vivi_template 结构体里面的fops->read函数,即vivi_read函数。即V4L2框架只是提供了一个中转站的效果。再看vivi_read函数里面,
    954. return vb2_read(&dev->vb_vidq, data, count, ppos, file->f_flags & O_NONBLOCK);
    955. 它又调用了videobuf2-core.c中的vb2_read函数。确实说明了v4l2框架的中转作用。
    956. 这样相似的函数有read, write, poll, mmap, realease等,比较特别的是ioctl函数,在后面分析它。他们都是应用程序调用,通过V4L2框架中转到对应的驱动程序中,然后驱动程序根据不同的调用,选择调用videobuf或ioctl中的函数。
    957. 5.3 第三个函数指针集是const struct v4l2_ioctl_ops *ioctl_ops;在vivi.c中就是
    958. static const struct v4l2_ioctl_ops vivi_ioctl_ops 
    959.     .vidioc_querycap = vidioc_querycap
    960.     .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap
    961.     .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap
    962.     .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap
    963.     .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap
    964.     .vidioc_reqbufs = vidioc_reqbufs
    965.     .vidioc_querybuf = vidioc_querybuf
    966.     .vidioc_qbuf = vidioc_qbuf
    967.     .vidioc_dqbuf = vidioc_dqbuf
    968.     .vidioc_s_std = vidioc_s_std
    969.     .vidioc_enum_input = vidioc_enum_input
    970.     .vidioc_g_input = vidioc_g_input
    971.     .vidioc_s_input = vidioc_s_input
    972.     .vidioc_streamon = vidioc_streamon
    973.     .vidioc_streamoff = vidioc_streamoff
    974.     .vidioc_log_status = v4l2_ctrl_log_status
    975.     .vidioc_subscribe_event = v4l2_ctrl_subscribe_event
    976.     .vidioc_unsubscribe_event = v4l2_event_unsubscribe
    977. };
    978. 这个ioctl更麻烦,首先作为字符设备驱动,当应用程序调用ioctl的时候,就调用到了file_operations v4l2_fops中的.unlocked_ioctl = v4l2_ioctl,这个v4l2_ioctl同样通过ret = vdev->fops->ioctl(filp, cmd, arg);就调用到了vivi.c中申请注册的video_device vivi_template结构体里面的fops->ioctl函数,即v4l2_file_operations vivi_fops里面的 video_ioctl2函数,这个video_ioctl2函数又调用__video_do_ioctl函数(以上两个函数都在v4l2-ioctl.c中),根据不同的cmd宏,以VIDIOC_QUERYCAP为例,通过
    979. ret = ops->vidioc_querycap(file, fh, cap);
    980. 其中struct video_device *vfd = video_devdata(file)
    981.     const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
    982. 可以看出,__video_do_ioctl函数又调用了video_device vivi_template 结构体里面的.ioctl_ops &vivi_ioctl_ops,然后根据宏的名字来选择struct v4l2_ioctl_ops vivi_ioctl_ops中对应的函数,即vidioc_querycap函数。
    983. 这些调用太麻烦了,我决定在后面画一张图表来表示这些调用关系。
    984. 5.4 video_device分配和释放,用于分配和释放video_device结构体
    985. struct video_device *video_device_alloc(void
    986. void video_device_release(struct video_device *vdev
    987. video_device注册和注销,实现video_device结构体的相关成员后,就可以调用下面的接口进行注册
    988. static inline int __must_check video_register_device(struct video_device *vdev
    989. inttypeint nr
    990. void video_unregister_device(struct video_device*vdev)
    991. vdev:需要注册和注销的video_device
    992. type:设备类型,包括VFL_TYPE_GRABBER、VFL_TYPE_VBI、VFL_TYPE_RADIO和VFL_TYPE_SUBDEV。 
    993. nr:设备节点名编号,/dev/video[nr]

    994. (六)v4l2_fh 
    995. v4l2_fh是用来保存子设备的特有操作方法,也就是下面要分析到的v4l2_ctrl_handler,内核提供一组v4l2_fh的操作方法,通常在打开设备节点时进行v4l2_fh注册。 
    996. 初始化v4l2_fh,添加v4l2_ctrl_handler到v4l2_fh
    997. void v4l2_fh_init(struct v4l2_fh *fh, structvideo_device *vdev
    998. 添加v4l2_fh到video_device,方便核心层调用到
    999. void v4l2_fh_add(struct v4l2_fh *fh)

    1000. (七)v4l2_ctrl_handler 
    1001. v4l2_ctrl_handler是用于保存子设备控制方法集的结构体,对于视频设备这些ctrls包括设置亮度、饱和度、对比度和 清晰度等,用链表的方式来保存ctrls,可以通过v4l2_ctrl_new_std函数向链表添加ctrls。 
    1002. struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl
    1003. const struct v4l2_ctrl_ops *ops, u32 id, s32 min, s32 max, u32 step, s32 def
    1004. hdl是初始化好的v4l2_ctrl_handler结构体
    1005. ops是v4l2_ctrl_ops结构体,包含ctrls的具体实现
    1006. id是通过IOCTL的arg参数传过来的指令,定义在v4l2-controls.h文件
    1007. min、max用来定义某操作对象的范围。如
    1008. v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS,-208, 127, 1, 0)
    1009. 用户空间可以通过ioctl的VIDIOC_S_CTRL指令调用到v4l2_ctrl_handler,id透过arg参数传递。

    1010. (八)ioctl框架 
    1011. 你可能观察到用户空间对V4L2设备的操作基本都是ioctl来实现的,V4L2设备都有大量可操作的功能(配置寄存器),所以V4L2的ioctl也是十分庞大的。它是一个怎样的框架,是怎么实现的呢
    1012. ioctl函数在v4l2-ioctl.h中定义,一共包含79个回调函数,如果在这列举的话,就会显得太冗长了,我们会在下面用到的部分再列举,现显示部分如下所示:
    1013. struct v4l2_ioctl_ops 
    1014.     /* ioctl callbacks *

    1015.     /* VIDIOC_QUERYCAP handler *
    1016.     int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap)

    1017.     /* Priority handling *
    1018.     int (*vidioc_g_priority(struct file *file, void *fh
    1019.                  enum v4l2_priority *p)
    1020.     int (*vidioc_s_priority(struct file *file, void *fh
    1021.                  enum v4l2_priority p)
    1022. ......................................
    1023.     /For other private ioctls *
    1024.     long (*vidioc_default)     (struct file *file, void *fh
    1025.                     bool valid_prioint cmd, void *arg)
    1026. };

    1027. 8.1 驱动要实现的第一个回调函数可能就是:
    1028. /* VIDIOC_QUERYCAP handler *
    1029.     int (*vidioc_querycap)(struct file *file, void *priv, struct v4l2_capability *cap);
    1030. 这个函数处理 VIDIOC_QUERYCAP 的 ioctl(), 只是简单问问“你是谁?你能干什么?”实现它是 V4L2 驱动的责任。和所有其他V4L2回调函数一样,这个函数中的参数 priv 是 file->private_data 域的内容,通 常的做法是在 open()的时候把它指向驱动中表示设备的内部结构体。
    1031. 驱动应该负责填充cap结构并且返回“0或负的错误码”值。如果成功返回,则V4L2层会负责把回复拷 贝到用户空间。
    1032. struct v4l2_capability定义在videodev2.h中,如下所示:
    1033. /*
    1034.   * struct v4l2_capability - Describes V4L2 device caps returned by                                         VIDIOC_QUERYCAP 
    1035.   
    1036.   * @driver:     name of the driver module (e.g"bttv"
    1037.   * @card:     name of the card (e.g"Hauppauge WinTV"
    1038.   * @bus_info:     name of the bus (e.g"PCI:" + pci_name(pci_dev
    1039.   * @version:     KERNEL_VERSION 
    1040.   * @capabilities: capabilities of the physical device as a whole 
    1041.   * @device_caps: capabilities accessed via this particular device (node
    1042.   * @reserved:     reserved fields for future extensions 
    1043.   *
    1044. struct v4l2_capability 
    1045.     __u8    driver[16]//driver的名字
    1046.     __u8    card[32]//设备的硬件描述信息
    1047.     __u8    bus_info[32]
    1048.     __u32 version//内核版本号
    1049.     __u32    capabilities
    1050.     __u32    device_caps
    1051.     __u32    reserved[3]
    1052. }
    1053. 对于bus_info 成员,驱动程序一般用strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));来填充。
    1054. capabilities 成员是一个位掩码用来描述驱动能做的不同事情,也在videodev2.h中定义
    1055. /* Values for 'capabilities' field *
    1056. #define V4L2_CAP_VIDEO_CAPTURE        0x00000001 /Is a video capture device *
    1057. #define V4L2_CAP_VIDEO_OUTPUT        0x00000002 /Is a video output device *
    1058. #define V4L2_CAP_VIDEO_OVERLAY        0x00000004 /* Can do video overlay *
    1059. #define V4L2_CAP_VBI_CAPTURE        0x00000010 /Is a raw VBI capture device *
    1060. #define V4L2_CAP_VBI_OUTPUT        0x00000020 /Is a raw VBI output device *
    1061. #define V4L2_CAP_SLICED_VBI_CAPTURE    0x00000040 /Is a sliced VBI capture device *
    1062. #define V4L2_CAP_SLICED_VBI_OUTPUT    0x00000080 /Is a sliced VBI output device *
    1063. #define V4L2_CAP_RDS_CAPTURE        0x00000100 /* RDS data capture *
    1064. #define V4L2_CAP_VIDEO_OUTPUT_OVERLAY    0x00000200 /* Can do video output overlay *
    1065. #define V4L2_CAP_HW_FREQ_SEEK        0x00000400 /* Can do hardware frequency seek *
    1066. #define V4L2_CAP_RDS_OUTPUT        0x00000800 /Is an RDS encoder */

    1067. /Is a video capture device that supports multiplanar formats *
    1068. #define V4L2_CAP_VIDEO_CAPTURE_MPLANE    0x00001000 
    1069. /Is a video output device that supports multiplanar formats *
    1070. #define V4L2_CAP_VIDEO_OUTPUT_MPLANE    0x00002000 

    1071. #define V4L2_CAP_TUNER            0x00010000 /* has a tuner *
    1072. #define V4L2_CAP_AUDIO            0x00020000 /* has audio support *
    1073. #define V4L2_CAP_RADIO            0x00040000 /is a radio device *
    1074. #define V4L2_CAP_MODULATOR        0x00080000 /* has a modulator *

    1075. #define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls *
    1076. #define V4L2_CAP_ASYNCIO 0x02000000 /* async I/*
    1077. #define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls *

    1078. #define V4L2_CAP_DEVICE_CAPS 0x80000000 /* sets device capabilities field */
    1079. 下面我们来看看vivi.c中对它的实现:
    1080. static int vidioc_querycap(struct file *file, void *priv
    1081.                     struct v4l2_capability *cap

    1082.     struct vivi_dev *dev = video_drvdata(file)

    1083.     strcpy(cap->driver"vivi")
    1084.     strcpy(cap->card"vivi")
    1085.     strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info))
    1086.     cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING 
    1087.              V4L2_CAP_READWRITE
    1088.     cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS
    1089.     return 0
    1090. }
    1091. 它就是完成上述我们所说的事情。

    1092. 8.2 输入和输出
    1093. 8.2.1 综述
    1094.     在很多情况下,视频适配器并不能提供很多的输入输出选项。比如摄像头控制器,可能只是提供摄像 头信号输入,而没什么别的功能;然而,在一些其他的情况下,事情就变得复杂了。一个电视卡板上不同 的接口可能对应不同的输入。他甚至可能拥有可独立发挥功能的多路调谐器。有时,那些输入会有不同的 特性,有些调谐器可以支持比其他的更广泛的视频标准。对于输出来说,也有同样的问题。 很明显,一个应用若想有效地利用视频适配器,它必须有能力找到可用的输入和输出,而且他必须能 找到他想操作的那一个。为此,Video4Linux2 API提供三种不同的ioctl()调用来处理输入,相应地有三个来 处理输出。如下所示:
    1095.     int (*vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
    1096.     int (*vidioc_s_std(struct file *file, void *fh, v4l2_std_id *norm)
    1097.     int (*vidioc_querystd(struct file *file, void *fh, v4l2_std_id *a);

    1098.     /* Input handling *
    1099.     int (*vidioc_enum_input)(struct file *file, void *fh, struct v4l2_input *inp)
    1100.     int (*vidioc_g_input(struct file *file, void *fh, unsigned int *i)
    1101.     int (*vidioc_s_input(struct file *file, void *fh, unsigned int i)

    1102.     /* Output handling *
    1103.     int (*vidioc_enum_output(struct file *file, void *fh, struct v4l2_output *a)
    1104.     int (*vidioc_g_output(struct file *file, void *fh, unsigned int *i)
    1105.     int (*vidioc_s_output(struct file *file, void *fh, unsigned int i);
    1106. 对于用户空间而言,V4L2提供一个ioctl()命令(VIDIOC_ENUMSTD),它允许应用查询设备实现了哪 些标准。驱动却无需直接回答查询,而是将video_device 结构体的tvnorm字段设置为它所支持的所有标准。
    1107. 然后V4L2层会向应用回复所支持的标准。VIDIOC_G_STD命令可以用来查询现在哪种标准是激活的,它 也是在V4L2层通过返回video_device结构体的current_norm字段来处理的。驱动程序应在启动时,初始化 current_norm来反映现实情况。 当某个应用想要申请某个特定标准时,会发出一个 VIDIOC_S_STD 调用,该调用传到驱动时通过调用int (*vidioc_s_std(struct file *file, void *fh,v4l2_std_id *norm); 回调函数来实现,来看vivi.c中,
    1108. static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i

    1109.     return 0
    1110. }
    1111. 它就什么都没做,因为在设置video_device结构体的时候设置了:
    1112. static struct video_device vivi_template 
    1113.     .name        "vivi"
    1114.     .fops &vivi_fops
    1115.     .ioctl_ops     &vivi_ioctl_ops
    1116.     .release    = video_device_release

    1117.     .tvnorms = V4L2_STD_525_60
    1118.     .current_norm = V4L2_STD_NTSC_M
    1119. };
    1120. 下面就简单说一些视频标准,这些标准描述的是视频如何为传输 而进行格式化---分辨率、帧率等。 现在世界上使用的 标准主要有三个:NTSC(主要是北美使用)、PAL(主要是欧洲、非洲和中国)和 SECAM(法、俄和非洲部分地 区)。 
    1121. V4L2 使用v4l2_std_id 来代表视频标准,它是一个64位的掩码。每个标准变种在掩码中就是一位。所 
    1122. 以 “标准”NTSC 的定义为V4L2_STD_NTSC_M, 值为 0x1000 ; 而日本的变种就是V4L2_STD_NTSC_M_JP(0x2000)。如果一个设备可以处理所有NTSC变种,它就可以设为V4L2_STD_NTSC,它将所有相关位置位。它同样在videodev2.h中定义:
    1123. /
    1124.  * A N A L O G V I D E O S T A N D A R D 
    1125.  *

    1126. typedef __u64 v4l2_std_id
    1127.  
    1128. /* one bit for each *
    1129. #define V4L2_STD_PAL_B ((v4l2_std_id)0x00000001
    1130. #define V4L2_STD_PAL_B1 ((v4l2_std_id)0x00000002
    1131. #define V4L2_STD_PAL_G ((v4l2_std_id)0x00000004
    1132. #define V4L2_STD_PAL_H ((v4l2_std_id)0x00000008
    1133. #define V4L2_STD_PAL_I ((v4l2_std_id)0x00000010
    1134. #define V4L2_STD_PAL_D ((v4l2_std_id)0x00000020
    1135. #define V4L2_STD_PAL_D1 ((v4l2_std_id)0x00000040
    1136. #define V4L2_STD_PAL_K ((v4l2_std_id)0x00000080

    1137. #define V4L2_STD_PAL_M ((v4l2_std_id)0x00000100
    1138. #define V4L2_STD_PAL_N ((v4l2_std_id)0x00000200
    1139. #define V4L2_STD_PAL_Nc ((v4l2_std_id)0x00000400
    1140. #define V4L2_STD_PAL_60 ((v4l2_std_id)0x00000800

    1141. #define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000)    /* BTSC *
    1142. #define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000)    /* EIA-*
    1143. #define V4L2_STD_NTSC_443 ((v4l2_std_id)0x00004000
    1144. #define V4L2_STD_NTSC_M_KR ((v4l2_std_id)0x00008000)    /* FM A2 *

    1145. #define V4L2_STD_SECAM_B ((v4l2_std_id)0x00010000
    1146. #define V4L2_STD_SECAM_D ((v4l2_std_id)0x00020000
    1147. #define V4L2_STD_SECAM_G ((v4l2_std_id)0x00040000
    1148. #define V4L2_STD_SECAM_H ((v4l2_std_id)0x00080000
    1149. #define V4L2_STD_SECAM_K ((v4l2_std_id)0x00100000
    1150. #define V4L2_STD_SECAM_K1 ((v4l2_std_id)0x00200000
    1151. #define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000
    1152. #define V4L2_STD_SECAM_LC ((v4l2_std_id)0x00800000

    1153. /* ATSC/HDTV *
    1154. #define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000
    1155. #define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000

    1156. /
    1157.  "Common" NTSC/- It should be noticed that V4L2_STD_NTSC_443 is 
    1158.  * Missing here
    1159.  *
    1160. #define V4L2_STD_NTSC (V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_M_KR)

    1161. 8.2.2 输入
    1162. 视频捕获的应用首先要通过 VIDIOC_ENUMINPUT 命令来枚举所有可用的输入。在V4L2层,这个调 
    1163. 用会转换成调用驱动中对应的回调函数
    1164. int (*vidioc_enum_input)(struct file *file, void *priv, struct v4l2_input *inp)
    1165. 在这个调用中,file 对应要打开的视频设备。priv是驱动的私有字段。inp字段是传递的真正 信息
    1166. 先来看看这个v4l2_input结构体,它在videodev2.h中定义:
    1167. struct v4l2_input 
    1168.     __u32     index;        /* Which input *
    1169.     __u8     name[32];        /* Label *
    1170.     __u32     type;        /* Type of input *
    1171.     __u32     audioset;        /* Associated audios (bitfield*
    1172.     __u32 tuner/* Associated tuner *
    1173.     v4l2_std_id std
    1174.     __u32     status
    1175.     __u32     capabilities
    1176.     __u32     reserved[3]
    1177. };
    1178. index:是应用关注的输入索引号; 这是惟一一个用户空间设定的字段。驱动要分配索引号给输入,从0开始,依次增加。想要知道所有可用的输入,应用会调用 VIDIOC_ENUMINPUT,索引号从0开始,并开始递增。一旦驱动返回-EINVAL,应用就知道:输入己经枚举完了。只要有输入,输入索引号0就一定存在。
    1179. name:是输入的名字,由驱动确定。
    1180. type:输入类型,只有两个值可选 : V4L2_INPUT_TYPE_TUNER 和 V4L2_INPUT_TYPE_CAMERA。
    1181. status:给出输入状态,其中设置的每一位都代表一个问题,比如说掉电,无信号等问题,定义如下:
    1182. #define V4L2_IN_ST_NO_POWER 0x00000001 /* Attached device is off *
    1183. #define V4L2_IN_ST_NO_SIGNAL 0x00000002 
    1184. #define V4L2_IN_ST_NO_COLOR 0x00000004 
    1185. std:描述设备支持哪个或哪些视频标准。就是上面咱们所说的视频标准。
    1186. 来看看vivi.c中是怎么实现这个函数的: 
    1187. /* only one input in this sample driver *
    1188. static int vidioc_enum_input(struct file *file, void *priv
    1189.                 struct v4l2_input *inp

    1190.     if (inp->index >= NUM_INPUTS
    1191.         return -EINVAL

    1192.     inp->type = V4L2_INPUT_TYPE_CAMERA
    1193.     inp->std = V4L2_STD_525_60
    1194.     sprintf(inp->name"Camera %u", inp->index)
    1195.     return 0
    1196. }

    1197. 当应用想改变当前输入时,驱动会收到一个对回调函数 vidioc_s_input()的调用。
    1198. int (*vidioc_s_input(struct file *file, void *priv, unsigned int index)
    1199. index与上面提到的相同,它用来确定哪个输入是想要的 ,驱动要对硬件操作,选择指定输 
    1200. 入并返回 0。也有可能要返回-EINVAL(索引号不正确) 或-EIO(硬件故障)。即使只有一路输入,驱动也要实 现这个回调函数。
    1201. 还有另一个回调函数,指示哪一个输入处在激活状态
    1202. int (*vidioc_g_input(struct file *file, void *priv, unsigned int *index)
    1203. 这里驱动把*index 值设为当前激活输入的索引号。
    1204. 看看vivi.c中对这两个函数的实现:
    1205. static int vidioc_g_input(struct file *file, void *priv, unsigned int *i

    1206.     struct vivi_dev *dev = video_drvdata(file)

    1207.     *= dev->input
    1208.     return 0


    1209. static int vidioc_s_input(struct file *file, void *priv, unsigned int i

    1210.     struct vivi_dev *dev = video_drvdata(file)

    1211.     if (>= NUM_INPUTS
    1212.         return -EINVAL

    1213.     if (== dev->input
    1214.         return 0

    1215.     dev->input = i
    1216.     precalculate_bars(dev)
    1217.     precalculate_line(dev)
    1218.     return 0
    1219. }

    1220. 8.2.3 输出
    1221. 枚举和选择输出的过程与输入十分相似。 
    1222. 输出枚举的回调函数是这样的
    1223. int (*vidioc_enumoutput(struct file *file, void *private_data, struct v4l2_output *output)
    1224. 其中v4l2_output结构体如下所示:
    1225. struct v4l2_output 
    1226.     __u32     index;        /* Which output *
    1227.     __u8     name[32];        /* Label *
    1228.     __u32     type;        /* Type of output *
    1229.     __u32     audioset;        /* Associated audios (bitfield*
    1230.     __u32     modulator/* Associated modulator *
    1231.     v4l2_std_id std
    1232.     __u32     capabilities
    1233.     __u32     reserved[3]
    1234. };
    1235. index:相关输出索引号,工作方式与输入的索引号相同。
    1236. type:输出类型,支持的类型如下:
    1237. /* Values for the 'type' field */
    1238. #define V4L2_OUTPUT_TYPE_MODULATOR         1 //用于模拟电视调制器 
    1239. #define V4L2_OUTPUT_TYPE_ANALOG            2 //用于基本模拟视频输出 
    1240. #define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY     3 //用于模拟 VGA 覆盖设备 
    1241. audioset:能与视频协同工作的音频集。 
    1242. modulator:与此设备相关的调制器(仅对类型为 V4L2_OUTPUT_TYPE_MODULATOR 的设 备而言)
    1243. std:描述设备支持哪个或哪些视频标准。就是上面咱们所说的视频标准。
    1244. capabilities flags:
    1245. #define V4L2_OUT_CAP_PRESETS         0x00000001 /* Supports S_DV_PRESET *
    1246. #define V4L2_OUT_CAP_CUSTOM_TIMINGS     0x00000002 /* Supports S_DV_TIMINGS *
    1247. #define V4L2_OUT_CAP_STD         0x00000004 /* Supports S_STD */
    1248. 也有用于获得和设定现行输出设置的回调函数
    1249. int (*vidioc_g_output(struct file *file, void *fh, unsigned int *i)
    1250. int (*vidioc_s_output(struct file *file, void *fh, unsigned int i);
    1251. 有了这些函数之后,V4L2 应用就可以知道有哪些输入和输入,并在它们间进行选择。

    1252. 8.3 颜色与格式 
    1253. 应用在视频设备可以工作之前,它必须与驱动达成一致,知道视频数据是何种格式。这种协商将是一 
    1254. 个非常复杂的过程,其原因有二
    1255. 1、 视频硬件所支持的视频格各不相同。 
    1256. 2、 在内核的格式转换是令人难以接受的。 
    1257. 所以应用要找出一种硬件支持的格式,并做出一种大家都可以接受的配置。 这篇文章将会讲述格式的 
    1258. 基本描述方式,下篇文章则会讲述 V4L2 驱动与应用协商格式时所实现的 API。

    1259. 8.3.1 色域 
    1260. 色域从广义上来讲,就是系统在描述色彩时所使用的坐标系。V4L2 规范中定义了好几个,但只有两个 
    1261. 的使用最为广泛。它们是:
    1262. ● V4L2_COLORSPACE_SRGB 
    1263. 多数开发者所熟悉的[red、green、blue]数组就包含在这个色域中。它为每一种颜色提供了一个简单的 
    1264. 强度值,把它们混合在一起,从而产生了丰富的颜色。表示 RGB 值的方法有很多,我们在下面将会介绍。 这个色域也包含 YUV 和 YCbCr 的表示方法,这个表示方法最早是为了早期的彩色电视信号可以在黑 白电视中的播放,所以 Y(或“亮度” )值只是一个简单的亮度值,单独显示时可以产生灰度图像。U 和 V (或 Cb 和 Cr)色度值描述的是色彩中蓝色和红色的分量。绿色可以通过从亮度中减去这些分量而得到。 
    1265. YUV 和 RGB 之间的转换并不那么直接,但是我们有一些公式可用。 
    1266. 注意:YUV 和 YCbCr 并非完全一样,虽然有时他们的名字会替代使用。 
    1267. ● V4L2_COLORSPACE_SMPTE170M 
    1268. 这个是 NTSC 或 PAL 等电视信号的模拟色彩表示方法,电视调谐器通常产生的色域都属于这个色域。 还存在很多其他的色域,他们多数都是电视相关标准的变种。

    1269. 8.3.2 密集存储和平面存储
    1270. 如上所述,像素值是以数组的方式表示的,通常由 RGB 或 YUV 值组成。要把这数组组织成图像,通 常有两种常用的方法。 
    1271. ● Packed 格式把一个像素的所有分量值连续存放在一起。 
    1272. ● Planar 格式把每一个分量单独存储成一个阵列。例如在 YUV 格式中,所有 Y 值都连续地一起存 储在一个阵列中,U 值存储在另一个中,V 值存在第三个中。这些平面常常都存储在一个缓冲区 中,但并不一定非要这样。 
    1273. 紧密型存储方式可能使用更为广泛,特别是 RGB 格式,但这两种存储方式都可以由硬件产生并由应用 程序请求。如果设备可以产生紧密型和平面型两种,那么驱动就要让两种都在用户空间可见。

    1274. 8.3.3 四字符码 (four Charactor Code : FourCC )
    1275. V4L2 API 中表示色彩格式采用的是广受好评的四字符码(fourcc)机制。这些编码都是 32 位的值,由四 
    1276. 个 ASCII 码产生。 如此一来, 它就有一个优点就是, 易于传递, 对人可读。 例如, 当一个色彩格式读作“RGB4” 就没有必要去查表了。 
    1277. 注意
    1278. 四字符码在很多不同的配置中都会使用, 有些还是早于linux。 Mplayer 内部使用它们, 然而, fourcc 只是说明一种编码机制,并不说明使用何种编码。Mplayer有一个转换函数,用于在它自己的fourcc码和v4l2 用的fourcc码之间做出转换。

    1279. 8.3.4 RGB 格式:(videodev2.h中) 
    1280. /* RGB formats *
    1281. #define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R''G''B''1'/* 8 RGB-3-3-*
    1282. #define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R''4''4''4'/* 16 xxxxrrrr ggggbbbb *
    1283. #define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R''G''B''O'/* 16 RGB-5-5-*
    1284. #define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R''G''B''P'/* 16 RGB-5-6-*
    1285. #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R''G''B''Q'/* 16 RGB-5-5-5 BE *
    1286. #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R''G''B''R'/* 16 RGB-5-6-5 BE *
    1287. #define V4L2_PIX_FMT_BGR666 v4l2_fourcc('B''G''R''H'/* 18 BGR-6-6-6     *
    1288. #define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B''G''R''3'/* 24 BGR-8-8-*
    1289. #define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R''G''B''3'/* 24 RGB-8-8-*
    1290. #define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B''G''R''4'/* 32 BGR-8-8-8-*
    1291. #define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R''G''B''4'/* 32 RGB-8-8-8-*/

    1292. 8.3.5 YUV 格式(videodev2.h中) 
    1293. /* Luminance+Chrominance formats *
    1294. #define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y''V''U''9'/* 9 YVU 4:1:*
    1295. #define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y''V''1''2'/* 12 YVU 4:2:*
    1296. #define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y''U''Y''V'/* 16 YUV 4:2:*
    1297. #define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y''Y''U''V'/* 16 YUV 4:2:*
    1298. #define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y''V''Y''U'/* 16 YVU 4:2:*
    1299. #define V4L2_PIX_FMT_UYVY v4l2_fourcc('U''Y''V''Y'/* 16 YUV 4:2:*
    1300. #define V4L2_PIX_FMT_VYUY v4l2_fourcc('V''Y''U''Y'/* 16 YUV 4:2:*
    1301. #define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4''2''2''P'/* 16 YVU422 planar *
    1302. #define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4''1''1''P'/* 16 YVU411 planar *
    1303. #define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y''4''1''P'/* 12 YUV 4:1:*
    1304. #define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y''4''4''4'/* 16 xxxxyyyy uuuuvvvv *
    1305. #define V4L2_PIX_FMT_YUV555 v4l2_fourcc('Y''U''V''O'/* 16 YUV-5-5-*
    1306. #define V4L2_PIX_FMT_YUV565 v4l2_fourcc('Y''U''V''P'/* 16 YUV-5-6-*
    1307. #define V4L2_PIX_FMT_YUV32 v4l2_fourcc('Y''U''V''4'/* 32 YUV-8-8-8-*
    1308. #define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y''U''V''9'/* 9 YUV 4:1:*
    1309. #define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y''U''1''2'/* 12 YUV 4:2:*
    1310. #define V4L2_PIX_FMT_HI240 v4l2_fourcc('H''I''2''4'/* 8 8-bit color *
    1311. #define V4L2_PIX_FMT_HM12 v4l2_fourcc('H''M''1''2'/* 8 YUV 4:2:0 16x16 macroblocks *
    1312. #define V4L2_PIX_FMT_M420 v4l2_fourcc('M''4''2''0'/* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */

    1313. 8.3.6其他格式
    1314. /* compressed formats *
    1315. #define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M''J''P''G'/* Motion-JPEG *
    1316. #define V4L2_PIX_FMT_JPEG v4l2_fourcc('J''P''E''G'/* JFIF JPEG */
    1317. 等等。。。。。。
    1318. 8.3.7 格式描述符,struct v4l2_pix_format,它在videodev2.h中定义:
    1319. struct v4l2_pix_format 
    1320.     __u32     width
    1321.     __u32            height
    1322.     __u32            pixelformat
    1323.     enum v4l2_field     field
    1324.     __u32     bytesperline;    /for padding, zero if unused *
    1325.     __u32         sizeimage
    1326.     enum v4l2_colorspace    colorspace
    1327.     __u32            priv;        /private data, depends on pixelformat *
    1328. };
    1329. width:图像宽度,以像素为单位
    1330. height:图像高度,以像素为单位
    1331. pixelformat:描述图像格式的四字符码 
    1332. field:很多图像源会使数据交错——先传输奇数行,然后是偶数行。真正的摄像 头设备是不会做数据交错的。 V4L2 API允许应用使用多种交错方式。常用的值为 V4L2_FIELD_NONE (非交错)、 V4l2_FIELD_TOP (仅顶部交错)或 V4L2_FIELD_ANY (忽略)。具体的值可以去查看 enum v4l2_field的值,在这就不一一列举了。
    1333. bytesperline:相临扫描行之间的字节数,这包括各种设备可能会加入的填充字节。
    1334. sizeimage:存储图像所需的缓冲区的大小。 
    1335. colorspace:使用的色域。同样可以查看 enum v4l2_colorspace的值:
    1336. enum v4l2_colorspace 
    1337.     V4L2_COLORSPACE_SMPTE170M = 1
    1338.     V4L2_COLORSPACE_SMPTE240M = 2
    1339.     V4L2_COLORSPACE_REC709 = 3
    1340.     V4L2_COLORSPACE_BT878 = 4
    1341.     V4L2_COLORSPACE_470_SYSTEM_M = 5
    1342.     V4L2_COLORSPACE_470_SYSTEM_BG = 6
    1343.     V4L2_COLORSPACE_JPEG = 7
    1344.     V4L2_COLORSPACE_SRGB = 8
    1345. }

    1346. 至此,对于视频数据缓冲区的描述就算完成了,驱动程序需要和应用程序协商,以使硬件设备支持的图像格式能够满足应用程序的使用。下面再来讲驱动程序和应用程序协商的过程。

    1347. 8.4 格式协商 
    1348. 在存储器中表示图像的方法有很多种。 市场几乎找不到可以处理所有V4L2所理解的视频格式的设备。驱动不应支持底层硬件不理解的视频格式。实际上在内核中进行格式转换是令人难以接受的。 所以驱动必须能让应用选择一个硬件可以支持的格式。

    1349. 8.4.1 第一步就是简单的允许应用查询所支持的格式。VIDIOC_ENUM_FMT ioctl()就是为此目的而提供的。 在驱动内部,这个调用会转化为如下的回调函数(如果查询的是视频捕获设备 )。
    1350. int (*vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
    1351. 这个回调函数要求视频捕获设备描述其支持的格式,应用会传入一个v4l2_fmtdesc结构体:
    1352. struct v4l2_fmtdesc 
    1353.     __u32         index/* Format number *
    1354.     enum v4l2_buf_type type/* buffer type *
    1355.     __u32 flags
    1356.     __u8         description[32]/* Description string *
    1357.     __u32         pixelformat/* Format fourcc *
    1358.     __u32         reserved[4]
    1359. };

    1360. 应用会设置index和type成员
    1361. index:用来确定格式的一个简单整型数;与其他 V4L2 所使用的索引一样,这个也是从 0 开始递 增,至最大允许值为止。应用可以通过一直递增索引值直到返回-EINVAL 的方式枚举所有支持的 格式。 
    1362. type:描述的是数据流类型,对于视频捕获设备(摄像头)来说就V4L2_BUF_TYPE_VIDEO_CAPTURE。

    1363. 如果index对就某个支持的格式,驱动应该填写结构体的其他成员
    1364. flags:只定义了一个值,即 V4L2_FMT_FLAG_COMPRESSED,表示一个压缩的视频格式。 
    1365. description:一般来说可以是对这个格式的一种简短的字符串描述。
    1366. pixelformat:描述视频表现方式的四字符码。

    1367. 对于上述这个回调函数,它其实针对的是视频捕获设备,只有当 type 值为V4L2_BUF_TYPE_VIDEO_CAPTURE 时才会调用,这是一个回调函数集, 对于其他不同的设备,会根据不同的type值调用不同的回调函数。下面列举如下:
    1368. /* VIDIOC_ENUM_FMT handlers *
    1369. int (*vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
    1370. int (*vidioc_enum_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_fmtdesc *f)
    1371. int (*vidioc_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *f)
    1372. int (*vidioc_enum_fmt_vid_cap_mplane)(struct file *file, void *fh, struct v4l2_fmtdesc *f)
    1373. int (*vidioc_enum_fmt_vid_out_mplane)(struct file *file, void *fh, struct v4l2_fmtdesc *f)
    1374. int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh, struct v4l2_fmtdesc *f)

    1375. 来看看vivi.c中对于这个回调函数的实现:
    1376. static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv
    1377.                     struct v4l2_fmtdesc *f

    1378.     struct vivi_fmt *fmt

    1379.     if (f->index >= ARRAY_SIZE(formats)
    1380.         return -EINVAL

    1381.     fmt &formats[f->index]

    1382.     strlcpy(f->description, fmt->name, sizeof(f->description))
    1383.     f->pixelformat = fmt->fourcc
    1384.     return 0
    1385. }

    1386. 8.4.2 应用程序可以通过调用 VIDIOC_G_FMT 知道硬件现在的配置。 这种情况下传递的参数是一个v4l2_format 结构体
    1387. struct v4l2_format 
    1388.     enum v4l2_buf_type type
    1389.     union 
    1390.         struct v4l2_pix_format        pix/* V4L2_BUF_TYPE_VIDEO_CAPTURE *
    1391.         struct v4l2_pix_format_mplane    pix_mp/* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE *
    1392.         struct v4l2_window        win/* V4L2_BUF_TYPE_VIDEO_OVERLAY *
    1393.         struct v4l2_vbi_format        vbi/* V4L2_BUF_TYPE_VBI_CAPTURE *
    1394.         struct v4l2_sliced_vbi_format    sliced/* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE *
    1395.         __u8    raw_data[200]/* user-defined *
    1396.     } fmt
    1397. };
    1398. 对于视频捕获(和输出)设备,联合体中pix成员是我们关注的重点。这是我们在上面见过的v4l2_pix_format结构体,驱动应该用现在的硬件设置填充那个结构体并且返回。
    1399. 来看看vivi.c中对于这个回调函数的实现:
    1400. static int vidioc_g_fmt_vid_cap(struct file *file, void *priv
    1401.                     struct v4l2_format *f

    1402.     struct vivi_dev *dev = video_drvdata(file)

    1403.     f->fmt.pix.width = dev->width
    1404.     f->fmt.pix.height = dev->height
    1405.     f->fmt.pix.field = dev->field
    1406.     f->fmt.pix.pixelformat = dev->fmt->fourcc
    1407.     f->fmt.pix.bytesperline (f->fmt.pix.width * dev->fmt->depth>> 3
    1408.     f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline
    1409.     if (dev->fmt->fourcc == V4L2_PIX_FMT_YUYV |
    1410.      dev->fmt->fourcc == V4L2_PIX_FMT_UYVY
    1411.         f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M
    1412.     else 
    1413.         f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB
    1414.     return 0


    1415. 8.4.3多数应用都想最终对硬件进行配置以使其为应用提供一种合适的格式。改变视频格式有两个函数接口
    1416. 一个是 VIDIOC_TRY_FMT 调用,它在 V4L2 驱动中转化为下面的回调函数
    1417. int (*vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f);
    1418. 要处理这个调用,驱动会查看请求的视频格式,然后断定硬件是否支持这个格式。如果应用请求的格 式是不被支持的,就会返回-EINVAL。例如,描述了一个不支持格的 fourcc 编码或者请求了一个隔行扫描 的视频,而设备只支持逐行扫描的就会失败。在另一方面,驱动可以调整 size 字段,以与硬件支持的图像 大小相适应。通常的做法是尽量将大小调小。所以一个只能处理 VGA 分辨率的设备驱动会根据情况相应地 调整 width 和 height 参数而成功返回。v4l2_format结构体会在调用后复制给用户空间,驱动应该更新这个 结构体以反映改变的参数,这样应用才可以知道它真正得到是什么。 
    1419. VIDIOC_TRY_FMT这个处理对于驱动来说是可选的,但不推荐忽略这个功能。如果提供了的话,这 个函数可以在任何时候调用,甚至时设备正在工作的时候。它不可以对实质上的硬件参数做任何改变,只 是让应用知道都可以做什么的一种方式。

    1420. 如果应用要真正的改变硬件的格式,它使用 VIDIOC_S_FMT 调用,它以下面的方式到达驱动
    1421. int (*vidioc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f);
    1422. 与 VIDIOC_TRY_FMT 不同,这个回调是不能随时调用的。如果硬件正在工作或己经开辟了流缓冲区 (后面的文章将介绍),改变格式会带来无尽的麻烦。想想会发生什么?比如,一个新的格式比现在使的缓冲 区大的时候。所以驱动总是要保证硬件是空闲的,否则就对请求返回失败(-EBUSY)。 
    1423. 格式的改变应该是原子的——它要么改变所有的参数以实现请求,要么一个也不改变。同样,驱动在 必要时是可以改变图像大小的。
    1424. 还是来看看vivi.c中对于这两个回调函数的实现:
    1425. static int vidioc_try_fmt_vid_cap(struct file *file, void *priv
    1426.             struct v4l2_format *f

    1427.     struct vivi_dev *dev = video_drvdata(file)
    1428.     struct vivi_fmt *fmt
    1429.     enum v4l2_field field

    1430.     fmt = get_format(f)
    1431.     if (!fmt
    1432.         dprintk(dev, 1"Fourcc format (0x%08x) invalid.\n"
    1433.             f->fmt.pix.pixelformat)
    1434.         return -EINVAL
    1435.     

    1436.     field = f->fmt.pix.field

    1437.     if (field == V4L2_FIELD_ANY
    1438.         field = V4L2_FIELD_INTERLACED
    1439.     else if (V4L2_FIELD_INTERLACED != field
    1440.         dprintk(dev, 1"Field type invalid.\n")
    1441.         return -EINVAL
    1442.     

    1443.     f->fmt.pix.field = field
    1444.     v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2
    1445.              &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0)
    1446.     f->fmt.pix.bytesperline 
    1447.         (f->fmt.pix.width * fmt->depth>> 3
    1448.     f->fmt.pix.sizeimage 
    1449.         f->fmt.pix.height * f->fmt.pix.bytesperline
    1450.     if (fmt->fourcc == V4L2_PIX_FMT_YUYV |
    1451.      fmt->fourcc == V4L2_PIX_FMT_UYVY
    1452.         f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M
    1453.     else 
    1454.         f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB
    1455.     return 0


    1456. static int vidioc_s_fmt_vid_cap(struct file *file, void *priv
    1457.                     struct v4l2_format *f

    1458.     struct vivi_dev *dev = video_drvdata(file)
    1459.     struct vb2_queue *&dev->vb_vidq

    1460.     int ret = vidioc_try_fmt_vid_cap(file, priv, f)
    1461.     if (ret < 0
    1462.         return ret

    1463.     if (vb2_is_streaming(q)
    1464.         dprintk(dev, 1"%s device busy\n", __func__)
    1465.         return -EBUSY
    1466.     

    1467.     dev->fmt = get_format(f)
    1468.     dev->width = f->fmt.pix.width
    1469.     dev->height = f->fmt.pix.height
    1470.     dev->field = f->fmt.pix.field

    1471.     return 0
    1472. }

    1473. 8.5 IO访问 
    1474. V4L2支持三种不同IO访问方式(内核中还支持了其它的访问方式,暂不讨论)
    1475. (1)read和write,是基本帧IO访问方式,通过read读取每一帧数据,数据需要在内核和用户之间拷贝,这种方式访问速度可能会非常慢
    1476. (2)内存映射缓冲区(V4L2_MEMORY_MMAP),是在内核空间开辟缓冲区,应用通过mmap()系统调用映射到用户地址空间。这些缓冲区可以是大而连续DMA缓冲区、通过vmalloc()创建的虚拟缓冲区,或者直接在设备的IO内存中开辟的缓冲区(如果硬件支持)
    1477. (3)用户空间缓冲区(V4L2_MEMORY_USERPTR),是用户空间的应用中开辟缓冲区,用户与内核空间之间交换缓冲区指针。很明显,在这种情况下是不需要mmap()调用的,但驱动为有效的支持用户空间缓冲区,其工作将也会更困难。 

    1478. read和write方式属于帧IO访问方式,每一帧都要通过IO操作,需要用户和内核之间数据拷贝,而后两种是流IO访问方式,不需要内存拷贝,访问速度比较快。内存映射缓冲区访问方式是比较常用的方式。 

    1479. 对于其他两种IO访问方式,我们暂时不探讨,因为写到这,我已经腰酸背痛腿抽筋了!_!

    1480. 8.6 流IO方式
    1481. 关于流IO的方式,内核中有一个更高层次的API,它能够帮助驱动作者完成流驱动。当底层设备可以支持分散/聚集I/O的时候,这一层(称为 video-buf)可以使工作变得容易。关于video-buf API我们将在后面讨论。
    1482. 支持流 I/O 的驱动应通过在 vidioc_querycap()方法中设置 V4L2_CAP_STREAMING 标签通知应用。注意:我们无法描述支持哪种缓冲区,那是后话。

    1483. 8.6.1 v4l2_buffer 结构体 
    1484. 当使用流 I/O 时,帧以v4l2_buffer的格式在应用和驱动之间传输。 
    1485. 首先大家要知道一个缓冲区可以有三种基本状态
    1486. (1)在驱动的传入队列中。如果驱动不用它做什么有用事的话,应用就可以把缓冲区放在这个队列里。对于一个视频捕获设备,传入队列中的缓冲区是空的,等待驱动向其中填入视频数据;对于输出设备来讲,这些缓冲区是要设备发送的帧数据。 
    1487. (2)在驱动的传出队列中。这些缓冲区已由驱动处理过,正等待应用来认领。对于捕获设备而言,传出缓冲区内是新的帧数据;对输出设备而言,这个缓冲区是空的。 
    1488. (3)不在上述两个队列里。在这种状态时,缓冲区由用户空间拥有,驱动无法访问。这是应用可对缓冲区进行操作的唯一时间。我们称其为用户空间状态。 
    1489. 将这些状态和他们之间传输的操作放在一起,如下图所示


    1490. 其实缓冲区的三种状态是以驱动为中心的,可以理解为传入队列为要给驱动处理的缓冲区,传出队列为驱动处理完毕的缓冲区,而第三种状态是脱离驱动控制的缓冲区。 
    1491. 他们操作的缓冲区核心就是这个v4l2_buffer结构体,它在videodev2.h中定义:
    1492. struct v4l2_buffer 
    1493.     __u32            index
    1494.     enum v4l2_buf_type type
    1495.     __u32            bytesused
    1496.     __u32            flags
    1497.     enum v4l2_field        field
    1498.     struct timeval        timestamp
    1499.     struct v4l2_timecode    timecode
    1500.     __u32            sequence

    1501.     /* memory location *
    1502.     enum v4l2_memory memory
    1503.     union 
    1504.         __u32 offset
    1505.         unsigned long userptr
    1506.         struct v4l2_plane *planes
    1507.     } m
    1508.     __u32            length
    1509.     __u32            input
    1510.     __u32            reserved
    1511. };
    1512. index:是鉴别缓冲区的序号,它只在内存映射缓冲区中使用。与其它可以在V4L2接口中枚举的对象一样,内存映射缓冲区的index 从0开始,依次递增。 
    1513. type:描述的是缓冲区类型,通常是V4L2_BUF_TYPE_VIDEO_CAPTURE 或V4L2_BUF_TYPE_VIDEO_OUTPUT。它是一个枚举值,具体可以自己查看。 
    1514. 缓冲区的大小由length给定,单位为byte。缓冲区中的图像数据大小可以在 bytesused 成员中找到。显 然,bytesused<=length。对于捕获设备而言,驱动会设置 bytesused; 对输出设备而言,应用必须设置这个成员。
    1515. flags:代表缓冲区的状态,如下所示:
    1516. /* Flags for 'flags' field *
    1517. #define V4L2_BUF_FLAG_MAPPED    0x0001 /* 缓冲区己映射到用户空间。它只应用于内存映射缓冲区 *
    1518. #define V4L2_BUF_FLAG_QUEUED    0x0002    /* 缓冲区在驱动的传入队列。 *
    1519. #define V4L2_BUF_FLAG_DONE    0x0004    /* 缓冲区在驱动的传出队列 *
    1520. #define V4L2_BUF_FLAG_KEYFRAME    0x0008    /* 缓冲区包含一个关键帧,它在压缩流中是                                    * 非常有用的。 *
    1521. #define V4L2_BUF_FLAG_PFRAME    0x0010    /* 应用于压缩流中,代表的是预测帧 *
    1522. #define V4L2_BUF_FLAG_BFRAME    0x0020    /* 应用于压缩流中,代表的是差分帧 *

    1523. /* Buffer is ready, but the data contained within is corrupted*
    1524. #define V4L2_BUF_FLAG_ERROR    0x0040 
    1525. #define V4L2_BUF_FLAG_TIMECODE    0x0100    /* timecode 字段有效 *
    1526. #define V4L2_BUF_FLAG_INPUT 0x0200 /* input 字段有效 *
    1527. #define V4L2_BUF_FLAG_PREPARED    0x0400    /* 缓冲区准备好进入队列 */

    1528. field :描述存在缓冲区中的图像属于哪一个域,它也是一个枚举值。 
    1529. timestamp(时间戳):对于输入设备来说,代表帧捕获的时间。对输出设备来说,在没有到达时间戳所代表的时间前,驱动不可以把帧发送出去,时间戳为0代表越快越好。驱动会把时间戳设为帧的第一个字节传送到设备的时间,或者说是驱动所能达到的最接近的时间。 
    1530. timecode:可以用来存放时间编码,对于视频编辑类应用是非常有用的。 
    1531. sequence:驱动对传过设备的帧维护了一个递增的计数; 每一帧传送时,它都会在sequence成员中存入当前序号。 对于输入设备来讲,应用可以观察这一成员来检测帧。 
    1532. memory:表示缓冲是内存映射缓冲区还是用户空间缓冲区。如果是 V4L2_MEMORY_MMAP方式,m.offset是内核空间图像数据存放的开始地址,会传递给mmap函数作为一个偏移, 通过mmap映射返回一个缓冲区指针p,p+byteused是图像数据在进程的虚拟地址空间所占区域;如果是用户指针缓冲区的方式,可以获取的图像数据开始地址的指针m.userptr,userptr是一个用户空间的指针,userptr+byteused便是所占的虚拟地址空间,应用可以直接访问。 
    1533. input:可以用来快速切换捕获设备的输入——如果设备支持帧间的快速切换。

    1534. /* 以下几个函数是参考Tekkaman Ninja 整理的V4L2 驱动编写指南写的,在实际中对于这几个宏的ioctl回调函数已经转移到videobuf2-core.c里面,通过调用vb2_xxx函数来实现了,但是它对于缓冲区的操作过程还是非常重要的,同时希望能够了解更多的底层知识,为后面写videobuf2做准备。 */

    1535. 8.6.2 申请缓冲区
    1536. 当流应用已经完成了基本设置,它将转去执行组织I/O缓冲区的任务。第一步就是使用 VIDIOC_REQBUFS ioctl()来建立一组缓冲区,它由V4L2转换成对驱动vidioc_reqbufs()方法的调用。 
    1537. int (*vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *buf);
    1538. 其中v4l2_requestbuffers结构体在videodev2.h中定义,如下所示:
    1539. struct v4l2_requestbuffers 
    1540.     __u32            count
    1541.     enum v4l2_buf_type type
    1542.     enum v4l2_memory memory
    1543.     __u32            reserved[2]
    1544. };
    1545. count:是期望使用的缓冲区数目。
    1546. type:它是一个枚举值,部分如下所示:
    1547. enum v4l2_buf_type 
    1548.     V4L2_BUF_TYPE_VIDEO_CAPTURE = 1
    1549.     V4L2_BUF_TYPE_VIDEO_OUTPUT = 2
    1550.     V4L2_BUF_TYPE_VIDEO_OVERLAY = 3
    1551.     V4L2_BUF_TYPE_VBI_CAPTURE = 4,
    1552.     ...........
    1553. };
    1554. memory:它也是一个枚举值,如下所示:
    1555. enum v4l2_memory 
    1556.     V4L2_MEMORY_MMAP = 1
    1557.     V4L2_MEMORY_USERPTR = 2
    1558.     V4L2_MEMORY_OVERLAY = 3
    1559. };
    1560. 如果应用想要使用内存映射缓冲区,它会把memory字段置为V4L2_MEMORY_MMAP,count置为期望使用的缓冲区数。如果驱动不支持内存映射,它应返回-EINVAL。否则它将在内部开辟请求的缓冲区并返回0。返回后,应用就会认为缓冲区是存在的,所以任何可能失败的操作都应在这个阶段处理 (比如说内存申请)。 

    1561. 注意:驱动并不一定要开辟与请求数目一样的缓冲区。在多数情况下,只有最小缓冲区数是有意义的。 
    1562. 如果应用请求的比这个最小值小,它可能得到比实际申请的多一些。 
    1563. 应用可以通过设置 count 字段为 0 的方式来释放掉所有已存在的缓冲区。在这种情况下, 驱动必须在释放缓冲前停止所有的 DMA 操作,否则会发生非常严重问题。如果缓冲区已映射到用户空间,则释放缓冲区是不可能的。
    1564. 相反,如果使用用户空间缓冲区,则有意义的字段只有缓冲区的type以及仅 V4L2_MEMORY_USERPTR 这个可用的 memory 字段。应用无须指定它想用的缓冲区的数目。因为内存是在用户空间开辟的,驱动无须操心。如果驱动支持用户空间缓冲区,它只须注意应用会使用这一特性, 返回0就可以了,否则返回-EINVAL。

    1565. VIDIOC_REQBUFS 命令是应用得知驱动所支持的流 I/O 缓冲区类型的唯一方法。

    1566. 8.6.3 将缓冲区映射到用户空间 
    1567. 如果使用用户空间缓存,在应用向传入队列放置缓冲区之前,驱动看不到任何缓冲区的相关调用。内存映射缓冲区需要更多的设置。应用通常会查看每一个开辟的缓冲区,并将其映射到自己的地址空间。第一步是 VIDIOC_QUERYBUF命令,它将转换成驱动中的vidioc_querybuf()方法
    1568. int (*vidioc_querybuf)(struct file *file, void *priv, struct v4l2_buffer *buf);

    1569. 进入此方法时, buf字段中要设置的字段有type(在缓冲区开辟时, 它将被检查是否与给定的类型相符) 和 index,它们可以确定一个特定的缓冲区。驱动要保证index有意义,并添充 buf中的其余字段。通常来说,驱动内部存储着一个v4l2_buffer 结构体数组, 所以vidioc_querybuf()方法的核心只是对这个v4l2_buffer结构体进行赋值。

    1570. 应用访问内存映射缓冲区的唯一方法就是将其映射到它们自己的地址空间,所以 vidioc_querybuf()调用后面通常会跟着一个驱动的 mmap()方法---要记住,这个方法指针是存储在相关设备的video_device 结构体中fops 字段中的。设备如何处理 mmap()依赖于内核中缓冲区是如何设置的。 
    1571. 当用户空间映射缓冲区时, 驱动应在相关的 v4l2_buffer 结构体中调置 V4L2_BUF_FLAG_MAPPED 标 签。它也必须在 open()和 close()中设定 VMA 操作,这样它才能跟踪映射了缓冲区的进程数。只要缓冲区在任何地方被映射了,它就不能在内核中释放。如果一个或多个缓冲区的映射计数为0,驱动就应该停止正 在进行的 I/O 操作,因为没有进程需要它。 

    1572. 8.6.4 流IO
    1573. 到现为止,我们己经看了很多设置,却没有传输过一帧的数据,我们离这步己经很近了,但在此之前还有一个步骤要做。当应用通过 VIDIOC_REQBUFS 获得了缓冲区后,那个缓冲区处于用户空间状态。如果他们是用户空间缓冲区,他们甚至还不存在。在应用开始流I/O之前,它必须至少将一个缓冲区放到驱动传入队列中。对于输出设备,那些缓冲区当然还要先填完有效的视频帧数据。 
    1574. 要把一个缓冲区放进传入队列,应用首先要发出一个VIDIOC_QBUF ioctl()调用, V4L2会将其映射为对驱动vidioc_qbuf()方法的调用。 
    1575. int (*vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf);

    1576. 对于内存映射缓冲而言,还是只有 buf 的 type 和 index 成员有效。驱动只能进行一些显式的检查(type 和index 是否有效、缓冲区是否在驱动队列中、缓冲区已映射等),把缓冲区放进传入队列里(设置 
    1577. V4L2_BUF_FLAG_QUEUED标签),并返回。

    1578. 一旦流 I/O 开始,驱动就要从它的传入队列里获取缓冲区,让设备更快地实现转送请求,然后把缓冲区移动到传出队列。转输开始时,缓冲区标签也要相应调整。像序号和时间戳这样的字段必需在这个时候填充。最后,应用会在传出队列中认领缓冲区,让它变回为用户态。这是 VIDIOC_DQBUF 的工作,它最终变为如下调用
    1579. int (*vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf);

    1580. 这里,驱动会从传出队列中移除第一个缓冲区,把相关的信息存入 buf。通常,传出队列是空的,这个调用会处于阻塞状态直到有缓冲区可用。然而V4L2是用来处理非阻塞I/O的,所以如果视频设备是以O_NONBLOCK 方式打开的,在队列为空的情况下驱动就该返回-EAGAIN。当然,这个要求也暗示驱动必须为流I/O支持poll()

    1581. 8.6.5 打开/关闭流
    1582. 剩下最后的一个步骤实际上就是告诉设备开始流 I/O 操作。 完成这个任务的 Video4Linux2 驱动方法是:
    1583. int (*vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
    1584. int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i);
    1585. 对 vidioc_streamon()的调用应该在检查类型有意义之后才让设备开始工作。如果需要的话,驱动可以请求等传入队列中有一定数目的缓冲区后再开始流传输。

    1586. 当应用关闭时,它应发出一个 vidioc_streamoff()调用,此调用要停止设备。驱动还应从传入和传出队列 中移除所有的缓冲区,使它们都处于用户空间状态。当然,驱动必须意识到:应用可能在没有停止流传输的情况下关闭设备。 

    1587. (九)控制




    1588. (十)linux内核v4l2框架中videobuf2分析
    1589. 16年1月19日20:44:18

    1590. 1. 首先在vivi.c中,在vivi_init函数的vivi_create_instance中,对于缓冲区队列的操作有以下的代码:
    1591.     struct vb2_queue *q;
    1592.     /* initialize queue *
    1593.     q &dev->vb_vidq
    1594.     memset(q, 0, sizeof(dev->vb_vidq))
    1595.     q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE
    1596.     q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ
    1597.     q->drv_priv = dev
    1598.     q->buf_struct_size = sizeof(struct vivi_buffer)
    1599.     q->ops &vivi_video_qops
    1600.     q->mem_ops &vb2_vmalloc_memops

    1601.     vb2_queue_init(q);

    1602. 它对struct vb2_queue结构体进行了设置,然后调用vb2_queue_init()函数进行初始化,那么就先来分析这个vb2_queue结构体。

    1603. 2.vb2_queue结构体在videobuf2-core.h中定义,如下所示(对于结构体的注释,我也放在下面了):
    1604. /*
    1605.  * struct vb2_queue - a videobuf queue 
    1606.  
    1607.  * @type:    queue type (see V4L2_BUF_TYPE_in linux/videodev2.
    1608.  * @io_modes:    supported io methods (see vb2_io_modes enum
    1609.  * @io_flags:    additional io flags (see vb2_fileio_flags enum
    1610.  * @ops:    driver-specific callbacks 
    1611.  * @mem_ops:    memory allocator specific callbacks 
    1612.  * @drv_priv:    driver private data 
    1613.  * @buf_struct_size: size of the driver-specific buffer structure
    1614.  *        "0" indicates the driver doesn't want to use a custom buffer 
    1615.  *        structure type, so sizeof(struct vb2_buffer) will is used 
    1616.  
    1617.  * @memory:    current memory type used 
    1618.  * @bufs:    videobuf buffer structures 
    1619.  * @num_buffers: number of allocated/used buffers 
    1620.  * @queued_list: list of buffers currently queued from userspace 
    1621.  * @queued_count: number of buffers owned by the driver 
    1622.  * @done_list:    list of buffers ready to be dequeued to userspace 
    1623.  * @done_lock:    lock to protect done_list list 
    1624.  * @done_wq: waitqueue for processes waiting for buffers ready to be dequeued 
    1625.  * @alloc_ctx:    memory type/allocator-specific contexts for each plane 
    1626.  * @streaming:    current streaming state 
    1627.  * @fileio:    file io emulator internal data, used only if emulator is active 
    1628.  */
    1629. struct vb2_queue 
    1630.     enum v4l2_buf_type        type
    1631.     unsigned int            io_modes
    1632.     unsigned int            io_flags
    1633.     const struct vb2_ops        *ops
    1634.     const struct vb2_mem_ops    *mem_ops
    1635.     void                *drv_priv
    1636.     unsigned int            buf_struct_size
    1637. /private: internal use only *
    1638.     enum v4l2_memory        memory
    1639.     struct vb2_buffer        *bufs[VIDEO_MAX_FRAME]//代表每个buffer (后面分析)
    1640.     unsigned int            num_buffers//分配的buffer个数 
    1641.     struct list_head        queued_list
    1642.     atomic_t            queued_count
    1643.     struct list_head        done_list
    1644.     spinlock_t            done_lock
    1645.     wait_queue_head_t        done_wq
    1646.     void                *alloc_ctx[VIDEO_MAX_PLANES]
    1647.     unsigned int            plane_sizes[VIDEO_MAX_PLANES]
    1648.     unsigned int            streaming:1
    1649.     struct vb2_fileio_data        *fileio
    1650. };
    1651. type:缓冲区的类型,与v4l2_buf_type这个枚举值相同,为下面其中的一项:
    1652. enum v4l2_buf_type 
    1653.     V4L2_BUF_TYPE_VIDEO_CAPTURE = 1
    1654.     V4L2_BUF_TYPE_VIDEO_OUTPUT = 2
    1655.     V4L2_BUF_TYPE_VIDEO_OVERLAY = 3
    1656.     V4L2_BUF_TYPE_VBI_CAPTURE = 4
    1657.     V4L2_BUF_TYPE_VBI_OUTPUT = 5
    1658.     V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6
    1659.     V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7
    1660.     V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8
    1661.     V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9
    1662.     V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE = 10
    1663.     V4L2_BUF_TYPE_PRIVATE = 0x80
    1664. };
    1665. io_modes:访问IO的方式,与enum vb2_io_modes相同,如下所示:
    1666. *
    1667.  * enum vb2_io_modes - queue access methods 
    1668.  * @VB2_MMAP:        driver supports MMAP with streaming API 
    1669.  * @VB2_USERPTR:    driver supports USERPTR with streaming API 
    1670.  * @VB2_READ:        driver supports read() style access 
    1671.  * @VB2_WRITE:        driver supports write() style access 
    1672.  *
    1673. enum vb2_io_modes 
    1674.     VB2_MMAP    (<< 0)
    1675.     VB2_USERPTR    (<< 1)
    1676.     VB2_READ    (<< 2)
    1677.     VB2_WRITE    (<< 3)
    1678. };
    1679. ops:buffer队列操作函数集合 
    1680. mem_ops:buffer memory操作集合 
    1681. vb2_queue代表一个videobuffer队列,vb2_buffer是这个队列中的成员,vb2_mem_ops是缓冲内存的操作函数集,vb2_ops用来管理队列。根据vivi.c中的设置,它都对这两个函数集设置了初始值,那么下面我们就来看看这两个函数集。

    1682. 2.1 vb2_mem_ops 包含了内存映射缓冲区、用户空间缓冲区的内存操作方法
    1683. struct vb2_mem_ops 
    1684.     void        *(*alloc)(void *alloc_ctx, unsigned long size)
    1685.     void        (*put)(void *buf_priv)
    1686.     void        *(*get_userptr)(void *alloc_ctx, unsigned long vaddr
    1687.                     unsigned long sizeint write)
    1688.     void        (*put_userptr)(void *buf_priv)
    1689.     void        *(*vaddr)(void *buf_priv)
    1690.     void        *(*cookie)(void *buf_priv)
    1691.     unsigned int    (*num_users)(void *buf_priv)
    1692.     int        (*mmap)(void *buf_priv, struct vm_area_struct *vma)
    1693. };

    1694. 通过在vivi.c中使用这个结构体,我们发现这几个函数都是直接调用内核中实现好的函数。它提供了三种类型的视频缓存区操作方法:连续的DMA缓冲区、集散的DMA缓冲区以及vmalloc创建的缓冲区,分别由 videobuf2-dma-contig.c、videobuf2-dma-sg.c和videobuf-vmalloc.c文件实现,可以根据实际情况来使用。
    1695. vivi.c中,q->mem_ops &vb2_vmalloc_memops;它使用vmalloc的方式创建缓冲区,搜索发现vb2_vmalloc_memops在videobuf2-vmalloc.c中定义,如下所示:
    1696. const struct vb2_mem_ops vb2_vmalloc_memops 
    1697.     .alloc        = vb2_vmalloc_alloc
    1698.     .put        = vb2_vmalloc_put
    1699.     .get_userptr    = vb2_vmalloc_get_userptr
    1700.     .put_userptr    = vb2_vmalloc_put_userptr
    1701.     .vaddr        = vb2_vmalloc_vaddr
    1702.     .mmap        = vb2_vmalloc_mmap
    1703.     .num_users    = vb2_vmalloc_num_users
    1704. }
    1705. EXPORT_SYMBOL_GPL(vb2_vmalloc_memops);
    1706. 这几个函数暂时先不具体分析他们的代码。

    1707. 2.2 vb2_ops是用来管理buffer队列的函数集合,包括队列和缓冲区初始化:
    1708. struct vb2_ops 
    1709.     int (*queue_setup)(struct vb2_queue *qconst struct v4l2_format *fmt
    1710.              unsigned int *num_buffers, unsigned int *num_planes
    1711.              unsigned int sizes[], void *alloc_ctxs[])
    1712.     void (*wait_prepare)(struct vb2_queue *q)
    1713.     void (*wait_finish)(struct vb2_queue *q)
    1714.     int (*buf_init)(struct vb2_buffer *vb)
    1715.     int (*buf_prepare)(struct vb2_buffer *vb)
    1716.     int (*buf_finish)(struct vb2_buffer *vb)
    1717.     void (*buf_cleanup)(struct vb2_buffer *vb)
    1718.     int (*start_streaming)(struct vb2_queue *q, unsigned int count)
    1719.     int (*stop_streaming)(struct vb2_queue *q)
    1720.     void (*buf_queue)(struct vb2_buffer *vb)
    1721. };
    1722. vivi.c中q->ops &vivi_video_qops;这几个函数是需要我们自己实现的,如下所示:
    1723. static struct vb2_ops vivi_video_qops 
    1724.     .queue_setup        = queue_setup//队列初始化
    1725.     //对buffer的操作 
    1726.     .buf_init        = buffer_init
    1727.     .buf_prepare        = buffer_prepare
    1728.     .buf_finish        = buffer_finish
    1729.     .buf_cleanup        = buffer_cleanup
    1730.     //把vb传递给驱动 
    1731.     .buf_queue        = buffer_queue
    1732.     // 开始/停止视频流 
    1733.     .start_streaming    = start_streaming
    1734.     .stop_streaming        = stop_streaming
    1735.     //释放和获取设备操作锁 
    1736.     .wait_prepare        = vivi_unlock
    1737.     .wait_finish        = vivi_lock
    1738. };

    1739. 3. 在vb2_queue中有一个struct vb2_buffer    *bufs[VIDEO_MAX_FRAME]
    1740. 其中这个vb2_buffer是缓存队列的基本单位,内嵌在其中的v4l2_buffer是核心成员。当开始流IO时,帧以v4l2_buffer的格式在应用和驱动之间传输。
    1741. struct vb2_buffer 
    1742.     struct v4l2_buffer    v4l2_buf
    1743.     struct v4l2_plane    v4l2_planes[VIDEO_MAX_PLANES]
    1744.     struct vb2_queue    *vb2_queue