第三阶段应用层——2.1 视频监控—V4L2框架的简单分析

视频监控—V4L2框架的简单分析


一、概述

1、V4L2

    V4L,其全称是Ⅴideo4 Linux(即 Video for Linux),是 Linux内核中关于视频设备的API接口,涉及开关视频设备,以及从该类设备采集并处理相关的音、视频信息

    现在 Linux内核中用的是V4L2,即 Video4 Linux2(即 Video for Linux Two),其是修改V4L相关Bug后的一个升级版,始于 Linux2.5内核。

    V4L2的主设备号是81次设备号为0~255。这些次设备号里又分为多类设备视频设备、 Radio(收音机)设备、 Teletext on VBI等。因此V4L2设备对应的文件节点有:/dev/videoX、/dev/vbix、/dev/ radioX

2、UVC

    UVC全称为USB Video Class,即:USB视频类,是一种为USB视频捕获设备定义的协议标准,在不需要安装任何的驱动程序下即插即用,包括摄像头、数字摄影机、模拟视频转换器、电视卡及静态视频相机。

二、从UVC设备文件反推V4L2框架

备注

  • 涉及文件:uvc_driver.c、v4l2-dev.c、v4l2-ctrls.c、v4l2-iocl.c、vivi.c
  • 下面的分析为个人看法,肯定有所不足,望各位提出宝贵修改意见

1、uvc_driver

  • uvc_driver结构体:
    从图中可以看出uvc_driver采用platform平台机制进行管理,其中比较关键的函数就是.probe
    在这里插入图片描述
  • uvc_probe():
    在这个函数中主要进行如下设置,其中我们会看到
    一个比较显眼的函数v4l2_device_register(),这个函数并不是实际意义上的v4l2_device注册函数(可以理解为v4l2_device_init(),进行一些相关初始化工作),但是是后面介绍到的V4L2框架的一员
    后面的uvc_register_chains()比较关键
    在这里插入图片描述
  • uvc_register_chains()函数
    1、可以看到,在uvc_register_chains()函数中,遍历链表,调用video_register_device()注册uvc设备
    2、video_register_device()函数中遍历对uvc设备进行绑定、初始化与注册
    在这里插入图片描述
  • uvc_register_video()函数
    在这个函数中uvc_device真正进行分配video_device_alloc()和注册结构体video_register_device()相关操作
    在这里插入图片描述

2、v4l2_device结构体

  • video_device_alloc()函数
    调用kzalloc分配video_device结构体大小的内存空间
    在这里插入图片描述
  • video_register_device()函数
    通过源码追踪可以发现最终调用的是__video_register_device()函数
    __video_register_device()函数中进行六个步骤的设置主要实现注册的是如下三个操作
    cdev_alloc()vdev->cdev->ops = &v4l2_fops;cdev_add()三个操作
    在这里插入图片描述

3、初步总结uvc_device设置

通过上述分析,可以得到uvc_device驱动建立步骤如下图:
注意:

  • v4l2_device_register()video_device_alloc()video_register_device()其函数实现是在v4l2-dev.c件中
  • cdev_alloc()cdev_add()是在char_dev.c中实现的。
  • vdev->cdev->ops = &v4l2_fopsv4l2-dev.c文件与具体的uvc-driver.c联系起来。
    在这里插入图片描述
    通过追踪v4l2_fops结构体可以知道,file_operation结构体的定义是在v4l2-dev.c文件中实现
    在这里插入图片描述

4、V4L2的初步框架

  1. 对于uvc设备类,其属于字符驱动的一种,所以最终会调用cdev_alloc()cdev_add()对该设备类进行注册
  2. 对于内核空间中的V4L2框架,大致分为:具体的设备类、V4L2核心层v4l2-dev.c、字符设备驱动程序
  3. 具体的设备与内核中的设备类匹配上时,会调用其.probe函数建立联系
  4. .probe函数中实现与V4L2接口的注册与连接
  5. V4L2核心层v4l2-dev.c对该设备进行字符设备的注册
  6. 上述操作完成后,用户空间就可以通过open、read、write、ioctl的函数,操作具体的设备
    在这里插入图片描述

三、用户空间通过V4L2核心如何操作具体的uvc设备

用户空间往V4L2核心层看去,需要先分析v4l2-dev.c核心层

1、v4l2_fops结构体

v4l2-dev.c文件中,发现了驱动的关键结构体file_operations,在这个文件中,实现了具体的操作函数,供上层应用调用,下面v4l2_ioctl为例子进行分析
在这里插入图片描述

2、v4l2_ioctl()函数

对于完全的函数就不作展示了,留意其比较关键的函数

if (video_is_registered(vdev))
			ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);

中的vdev->fops->unlocked_ioctl(filp, cmd, arg)vdev->fops uvc设备类注册时最终调用__video_register_device()vdev->cdev->ops = &v4l2_fops对应起来了。

vdev->fops->unlocked_ioctl(filp, cmd, arg)最终对调用具体设备的.ioctl函数,对于内核中,有一个虚拟视频驱动程序vivi.c,对它来进一步分析
在这里插入图片描述

3、vivi_fops结构体

vivi.c文件中,发现了驱动的关键结构体file_operations,其中的.unlocked_ioctl函数就是实际调用的函数。

vdev->fops->unlocked_ioctl(filp, cmd, arg)
	---> vivi_fops->video_ioctl2()

在这里插入图片描述

4、video_ioctl2()函数

通过源码追踪,可以找到实际的操作函数为video_usercopy(),最后进入到__video_do_ioctl(),进行获得、设置某些属性

在这里插入图片描述

5、vivi.c的部分属性在哪里设置

对于一个设备,在编写驱动时,会在驱动程序中设定一些必须的属性,来对此设备进行必要的初始化工作
通过追踪vivi_init()函数,找到了部分属性设置在vivi_creat_instance()函数中:

vivi.c中使用的是v4l2_ctrl_new_std()v4l2_ctrl_new_custom()来设置属性与控制项,当然还有其他的设置函数,这里不一一赘述了。
在这里插入图片描述

6、以vivi.c的video_ioctl2为例,初步总结

  • 总源码追踪过程:
    在这里插入图片描述

画图理解与总结:
用户空间执行相关open、read、ioctl.....函数

  1. 由于为字符设备,会先调用字符设备驱动程序,在字符设备驱动找到对应v4l2接口
  2. 在V4L2核心层中,调用对应的open、read、ioctl.....函数,通过函数指针找到具体的设备的函数
  3. 具体设备对应的open、read、ioctl.....函数进行硬件的相关操作
    在这里插入图片描述

四、总结

V4L2整体的框架如下:
下图分析的是带有platform平台机制下的V4L2框架分析,若设备本身不采用platform平台机制管理,则不需要xxx_driver.c部分
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42813232/article/details/107436720