V4L2框架分析【韦东山视频学习笔记】

v4l2的基本框架如下:

 1     app: open read write ioctrl
 2     ------------------------------------------------------------
 3     核心层  主要提供一套标准的接口供上层调用:
 4     v4l2-dev.c--->
 5         static const struct file_operations v4l2_fops = {
 6             .owner = THIS_MODULE,
 7             .read = v4l2_read,
 8             .write = v4l2_write,
 9             .open = v4l2_open,
10             .get_unmapped_area = v4l2_get_unmapped_area,
11             .mmap = v4l2_mmap,
12             .unlocked_ioctl = v4l2_ioctl,
13         #ifdef CONFIG_COMPAT
14             .compat_ioctl = v4l2_compat_ioctl32,
15         #endif
16             .release = v4l2_release,
17             .poll = v4l2_poll,
18             .llseek = no_llseek,
19         };
20 
21 
22 
23     -------------------------------------------------------------
24     硬件相关:
25                     |---v4l2_device_register  --->重点
26                     |
27     Uvc_driver.c ---|---uvc_register_chains
28                     |        uvc_register_terms
29                     |            uvc_register_video
30                     |                video_device_alloc --->重点
31                     |                    video_register_device ---> 重点

下面以vivi.c为例分析相关的调用流程

vivi_init的主要流程:

 1 vivi_init
 2         vivi_create_instance
 3             v4l2_device_register ---> 注册这个结构体:struct v4l2_device
 4 
 5             dev->fmt = &formats[0];  设置图片的格式
 6             v4l2_ctrl_handler_init   设置一些属性
 7             dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
 8             V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
 9             dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
10             V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
11             dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
12             V4L2_CID_CONTRAST, 0, 255, 1, 16);
13             dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
14             V4L2_CID_SATURATION, 0, 255, 1, 127);
15             dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
16             V4L2_CID_HUE, -128, 127, 1, 0);
17             dev->autogain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
18             V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
19             dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
20             V4L2_CID_GAIN, 0, 255, 1, 100);
21             dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
22             dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
23             dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
24             dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
25             dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
26             dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
27             dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL);
28 
29         vfd = video_device_alloc();   //主要是注册这个结构体;video_device
30         *vfd = vivi_template;//
31         vfd->v4l2_dev = &dev->v4l2_dev;
32 
33         ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
34             __video_register_device
35                 vdev->cdev->ops = &v4l2_fops;
36                 vdev->cdev->owner = owner;
37                 ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
38                 if (ret < 0) {
39                         printk(KERN_ERR "%s: cdev_add failed\n", __func__);
40                         kfree(vdev->cdev);
41                         vdev->cdev = NULL;
42                         goto cleanup;
43                 }
44 
45                 video_device[vdev->minor] = vdev;  //通过这个数组进行关联
46 
47                 if (vdev->v4l2_dev) {  // 跟之前vivi.c设置vfd->v4l2_dev = &dev->v4l2_dev; 相互关联
48                     if (vdev->v4l2_dev->dev)
49                         vdev->parent = vdev->v4l2_dev->dev;
50                     if (vdev->ctrl_handler == NULL)
51                         vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
52                     /* If the prio state pointer is NULL, then use the v4l2_device
53                        prio state. */
54                     if (vdev->prio == NULL)
55                 }
56 
57 
58         static const struct v4l2_file_operations vivi_fops = {
59             .owner        = THIS_MODULE,
60             .open           = v4l2_fh_open,
61             .release        = vivi_close,
62             .read           = vivi_read,
63             .poll        = vivi_poll,
64             .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
65             .mmap           = vivi_mmap,
66         };
67 
68 
69         static struct video_device vivi_template = {
70             .name        = "vivi",
71             .fops           = &vivi_fops,
72             .ioctl_ops     = &vivi_ioctl_ops,
73             .release    = video_device_release,
74         
75             .tvnorms              = V4L2_STD_525_60,
76             .current_norm         = V4L2_STD_NTSC_M,
77         };

open的流程:

 1 open的流程:
 2     app: open("/dev/video0",....)
 3     --------------------------------
 4     open:
 5         v4l2_fops.open
 6             vdev = video_devdata(filp);
 7                 video_device[iminor(file->f_path.dentry->d_inode)] //    __video_register_device 将vivi.v注册的video_device结构体放在这个数组存储
 8                 vdev->fops->open  调到vivi.c设置的fops,这里很关键也很精彩,大家领悟一下
 9                     vivi_template
10                         v4l2_fh_open

read的流程:

1 read的流程:
2         v4l2_fops.read
3             struct video_device *vdev = video_devdata(filp);
4             vdev->fops->read

ioctrl的流程:

 1     app:可以通过ioctl来设置获取亮度等信息,驱动程序谁来接收和管理这些信息
 2     v4l2_ctrl来设置这些信息
 3     v4l2_ctrl_handler来管理
 4 
 5     ioctl的流程:
 6     v4l2_fops.v4l2_ioctl
 7         struct video_device *vdev = video_devdata(filp);
 8             vdev->fops->unlocked_ioctl(filp, cmd, arg);
 9                 vivi_fops.video_ioctl2
10                     video_usercopy(file, cmd, arg, __video_do_ioctl); // 传递一个回调函数进去    __video_do_ioctl
11                         struct video_device *vfd = video_devdata(file);
12                         //根据APP传入的cmd来获得、设置"某些属性"
13                         switch (cmd) {
14                                                     
15                         }
16 
17 
18     或者通过v4l2_ctrl来获取
19     针对ctrl_handler相关的设置代码
20     vivi_create_instance
21         v4l2_ctrl_handler_init(hdl, 11);
22         v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
       ...
23 dev->v4l2_dev.ctrl_handler = hdl; 跟vdev关联 24 video_register_device 25 __video_register_device 26 if (vdev->ctrl_handler == NULL) 27 vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler; 28 29 __video_do_ioctl 30 case VIDIOC_QUERYCTRL: 31 if (vfh && vfh->ctrl_handler) 32 ret = v4l2_queryctrl(vfh->ctrl_handler, p); 33 ref = find_ref(hdl, id); //根据ID找到对应的v4l2_ctrl,找到之后再往对应的结构体进行填充

猜你喜欢

转载自www.cnblogs.com/zzb-Dream-90Time/p/12546925.html