Skip to main content
 首页 » 操作系统

Linux中V4L2分析

2022年07月19日30soundcode

一、vivi.c分析

1、vivi.c是Linux中虚拟的v4l2驱动,使用它来学习v4l2驱动架构

 1.vivi驱动涉及文件:

            vivi.c                        驱动的具体实现

            v4l2-common.c

            V4L2-dev.c            video_register_device(struct video_device *vdev...);

            V4L2-device.c       v4l2_device_register(struct device *dev,struct v4l2_device *v4l2_device);

            videobuf_core.c

            videobuf_vmalloc.c

2.主要关注以下几个结构体:

             struct video_device   视频类设备的基类,另外字符设备驱动的基类为cdev,所有的操作都是围绕cdev结构体

             struct v4l2_file_operations   包含vivi_read,vivi_open等函数具体实现。在系统调用的时候,会首先调用cdev的file_operations的v4l2_read,v4l2_open等函数,在这些函数中会使用struct file中的video_device来调用vivi_read等函数具体去实现。

             struct v4l2_ioctl_ops            ioctl操作的函数的具体实现

             struct V4l2_device

             struct videobuf_buffer           视频数据缓冲区,对应一帧视频,里面包含视频的大小等信息

             struct videobuf_queue          视频缓冲区队列

        以上几个结构体可能不会被单独使用,一般都被包含在某个更大的对象结构中,比如video_device和v4l2_device都包含在vivi_dev中,而vivi_dev被包含在viv_fh中,videobuf_buffer被包含在vivi_buffer中。

这个struct file_opertions v4l2_fops是字符设备给上层提供的系统调用,这里的函数最终调用的还是struct v4l2_file_operations (vivi_fops)的实现,可以查看v4l2_open的实现。videobuf_queue_ops中实现了缓冲队列的一些操作,buffer_setup,buffer_prepare,buffer_queue,buffer_release等,但是这些申请的缓冲队列都是在内核空间,在vivi_mmap函数中videobuf_mmap_mapper(struct videobuf_queue *q,struct vm_area_struct *vma);将缓冲队列映射到vm_area_struct虚拟地址

3.分析程序流程:

在vivi.c文件中

vivi_create_instance()

      v4l2_device_register()

      给video_device vdev对象赋值v4l2_file_operations和v4l2_ioctl_ops等

      video_device_register()

          初始化video_device对象vdev

          初始化video_device中的cdev结构体

                      cdev_add()注册字符设备

          初始化video_device中struct device结构体

                     device_register()在/dev/目录下创建设备节点

  v4l2_dev.c文件里file_operations中的v4l2_ioctl最终调用的还是vivi.c文件里v4l2_file_operations中的video_ioctl2函数,但是这里的video_ioctl2不像vivi_open,vivi_read等是具体的实现,video_ioctl2具体的实现已经单独拿出来放到v4l2_ioctl.c文件中了,所以video_ioctl2最终调用的是v4l2_ioctl.c文件中的__video_do_ioctl(file,cmd,arg)函数,而__video_do_ioctl(file,cmd,arg)函数又回过来调用vivi_ioctl中vivi_ioctl_ops中的函数。

 二、V4L2架构分析

  v4l2向上为应用程序提供了统一的调用接口,向下为设备驱动程序提供了统一的V4L2框架;Linux中V4L2驱动的视频设备(如摄像头、视频采集卡)的设备文件为/dev/videoX,主设备号81,对于视频设备次设备号为0-63(是字符设备),Radio设备为64-127,Teltext设备为192-223,VBI设备是224-255,V4L2驱动的视频设备在用户空间通过ioctl()控制,还可以进行mmap()映射。

要想了解 V4l2 有几个重要的文档是必须要读的:

1、源码Documentation/video4linux目录下的V4L2-framework.txtvideobuf

2、V4L2的官方API文档V4L2 API Specification

3、源码drivers/media/video目录下的sample程序vivi.c(虚拟视频驱动程序,此代码模拟一个真正的视频设备V4L2 API)。

V4l2可以支持多种设备,它可以有以下几种接口:

1. 视频采集接口(video capture interface):这种应用的设备可以是高频头或者摄像头.V4L2的最初设计就是应用于这种功能的.

2. 视频输出接口(video output interface):可以驱动计算机的外围视频图像设备--像可以输出电视信号格式的设备.

3. 直接传输视频接口(video overlay interface):它的主要工作是把从视频采集设备采集过来的信号直接输出到输出设备之上,而不用经过系统的CPU.

4. 视频间隔消隐信号接口(VBI interface):它可以使应用可以访问传输消隐期的视频信号.

5. 收音机接口(radio interface):可用来处理从AM或FM高频头设备接收来的音频流.

V4L2 驱动核心

V4L2 的驱动源码在drivers/media/video目录下,主要核心代码有:

v4l2-dev.c                  //linux版本2视频捕捉接口,主要结构体 video_device 的注册 
v4l2-common.c               //在Linux操作系统体系采用低级别的操作一套设备structures/vectors的通用视频设备接口。 
                            //此文件将替换videodev.c的文件配备常规的内核分配。 
v4l2-device.c               //V4L2的设备支持。注册v4l2_device 
v4l22-ioctl.c               //处理V4L2的ioctl命令的一个通用的框架。 
v4l2-subdev.c               //v4l2子设备 
v4l2-mem2mem.c              //内存到内存为Linux和videobuf视频设备的框架。设备的辅助函数,使用其源和目的地videobuf缓冲区。 
 
头文件linux/videodev2.h、media/v4l2-common.h、media/v4l2-device.h、media/v4l2-ioctl.h、media/v4l2-dev.h、media/v4l2-ioctl.h等。

 来源:http://zjbintsystem.blog.51cto.com/964211/464729       http://www.rosoo.net/a/201001/8382.html   (此二者类似)

Video4linux2一般操作流程(视频设备):
1. 打开设备文件。 int fd=open(”/dev/video0″,O_RDWR);
2. 取得设备的capability,看看设备具有什么功能,比如是否具有视频输入等。VIDIOC_QUERYCAP,struct v4l2_capability
3. 选择视频输入,一个视频设备可以有多个视频输入。VIDIOC_S_INPUT,struct v4l2_input
4. 设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。
VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format
5. 向驱动申请帧缓冲,一般不超过5个。struct v4l2_requestbuffers
6. 将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。
7. 将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer
8. 开始视频的采集。VIDIOC_STREAMON
9. 出队列以取得已采集数据的帧缓冲,取得原始采集数据。VIDIOC_DQBUF
10. 将缓冲重新入队列尾,这样可以循环采集。VIDIOC_QBUF
11. 停止视频的采集。VIDIOC_STREAMOFF
12. 关闭视频设备。close(fd);
常用的结构体(参见linux-2.6.18_pro500/include/linux/include/linux/videodev2.h):
struct v4l2_requestbuffers reqbufs;//向驱动申请帧缓冲的请求,里面包含申请的个数
struct v4l2_capability cap;//这个设备的功能,比如是否是视频输入设备
struct v4l2_input input; //视频输入
struct v4l2_standard std;//视频的制式,比如PAL,NTSC
struct v4l2_format fmt;//帧的格式,比如宽度,高度等
struct v4l2_buffer buf;//代表驱动中的一帧
v4l2_std_id stdid;//视频制式,例如:V4L2_STD_PAL
struct v4l2_queryctrl query;//查询的控制
struct v4l2_control control;//具体控制的值

  open(CAPTURE_DEVICE, O_RDWR | O_NONBLOCK, 0))关于阻塞模式和非阻塞模式,应用程序能够使用阻塞模式或非阻塞模式打开视频设备,如果使用非阻塞模式调用视频设备,即使尚未捕获到信息,驱动依旧会把缓存(DQBUFF)里的东西返回给应用程序。

参考:http://blog.csdn.net/luckywang1103/article/details/17406029

关于如何创建设备节点的:用户空间的udev会根据device_create创建相应的设备节点;这里只是简单说说我的理解class_create与class_register功能上类似,只是class_register需要分配struct class对象内存并初始化。自动创建设备节点class_create与device_create或者class_register,device_register,用户空间的udev会根据device_create创建相应的设备节点

 linux中class_create和class_register说明:http://www.cnblogs.com/skywang12345/archive/2013/05/15/driver_class.html  (未看

v4l2驱动架构解析与开发引导: http://www.360doc.com/content/13/1010/16/7775902_320343471.shtml


本文参考链接:https://www.cnblogs.com/hellokitty2/p/7444700.html