V4L2 框架分析 [魏东山视频学习笔记
最编程
2024-04-22 19:04:11
...
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,找到之后再往对应的结构体进行填充
原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/12546925.html
推荐阅读