Linux V4l2子系统分析1(基于Linux6.6)---系统概述
一、Linux V4L2(Video for Linux 2)子系统框架概述
V4L2(Video for Linux 2)是 Linux 内核中用于视频设备驱动程序的 API。它提供了一种标准的接口,使得应用程序能够访问视频捕获、播放、以及视频设备控制功能。V4L2 支持多种视频设备,包括摄像头、电视卡、视频捕捉卡等。V4L2 是 Linux 上视频设备的核心组成部分,尤其是对 UVC(USB Video Class)设备、数字视频设备等的支持。
1.1、V4L2 子系统的组成
V4L2 子系统在 Linux 内核中提供了从硬件到应用程序之间的标准化接口。它的核心组成包括以下几个部分:
-
V4L2 核心(Core)
- V4L2 核心是整个子系统的基础,提供了与视频设备的管理和控制有关的 API。
- 负责管理设备节点、驱动程序与用户空间的交互,以及与视频设备的控制、数据流、缓冲区管理等。
-
视频设备驱动(Device Drivers)
- 每个硬件设备都需要一个驱动程序来支持 V4L2 接口。驱动程序为设备提供具体的功能实现,例如视频捕获、视频播放、控制设置等。
- 驱动程序通过实现 V4L2 定义的接口与 V4L2 核心进行交互,处理视频设备的操作。
-
V4L2 用户空间接口
- 用户空间通过标准的文件操作(如
open()
、read()
、write()
等)来与 V4L2 设备进行交互。 - 应用程序可以使用
ioctl()
系统调用来进行设备控制、配置参数、获取视频流数据等操作。
- 用户空间通过标准的文件操作(如
-
V4L2 API 接口
- 提供给用户空间程序访问和控制视频设备的标准接口。
- 包括各种函数和数据结构,如
v4l2_capability
、v4l2_format
、v4l2_buffer
等,定义了设备的能力、格式设置、缓冲区管理等。
1.2、V4L2 核心组件
-
视频设备类(Video Device Class)
- V4L2 定义了一个
video_device
结构体,表示一个视频设备。它包含设备的基本信息、能力、格式支持、输入输出方式等。 - 每个视频设备都会有一个与之对应的
video_device
结构,驱动程序可以通过该结构来向用户空间提供设备信息。
- V4L2 定义了一个
-
IOCTL 接口
- V4L2 提供了一套丰富的 IOCTL 操作,允许用户空间与内核之间进行各种控制命令的交互。
- 通过
ioctl()
,应用程序可以控制视频设备的各种属性(如分辨率、帧率、亮度、对比度等)以及数据流的配置(如捕获模式、输出模式等)。
-
缓冲区管理(Buffer Management)
- 视频捕获设备通常需要缓冲区来存储图像数据,V4L2 通过缓冲区队列管理机制来处理数据的传输。
- V4L2 支持两种缓冲区管理模式:内存映射缓冲区(MMAP) 和 用户指针缓冲区(User Pointer)。
- 这些缓冲区通常使用队列进行管理,可以通过
VIDIOC_QBUF
和VIDIOC_DQBUF
等 IOCTL 来进行缓冲区的排队和出队操作。
-
视频流(Video Streaming)
- V4L2 支持视频流的传输,允许通过设备获取视频帧或者向设备提供视频帧。这些视频流可以通过捕获、回放等方式进行处理。
- V4L2 规定了帧缓冲和流的格式,以确保视频流的正确性。
-
多路复用与异步(Select and Poll)
- V4L2 还支持
select()
和poll()
等系统调用,用于实现异步操作,允许应用程序在等待视频设备数据时进行事件监听。 - 通过这些机制,应用程序可以在多个设备上同时等待数据的到达,处理异步的输入输出。
- V4L2 还支持
1.3、V4L2 关键数据结构
-
v4l2_capability
- 描述了视频设备的能力信息,如支持的功能、设备类型(捕获、回放等)以及 API 版本。
-
struct v4l2_capability { __u8 driver[16]; __u8 card[32]; __u8 bus_info[32]; __u32 version; __u32 capability; __u32 device_caps; __u32 reserved[4]; };
-
v4l2_format
- 用于设置或获取视频流的格式信息,如像素格式、图像宽度、高度等。
-
struct v4l2_format { __u32 type; union { struct v4l2_pix_format pix; struct v4l2_vbi_format vbi; struct v4l2_sliced_vbi_cap sliced; } fmt; };
-
v4l2_buffer
- 表示一个视频缓冲区,包含缓冲区的地址、大小、状态等信息。
-
struct v4l2_buffer { __u32 index; __u32 type; __u32 bytesused; __u32 flags; __u32 field; __u32 timestamp; struct v4l2_timecode timecode; __u32 sequence; __u32 memory; union { __u32 offset; unsigned long userptr; struct v4l2_plane *planes; } m; };
-
v4l2_input
- 用于表示视频输入端口(例如摄像头的不同输入源)。
-
struct v4l2_input { __u32 index; __u8 name[32]; __u32 type; __u32 audioset; __u32 capabilities; __u32 reserved[4]; };
1.4、V4L2 子系统的工作流程
-
设备初始化
- 驱动程序在初始化时,会注册设备并为其提供
video_device
结构,该结构包含了设备的信息和能力。 - 驱动程序需要实现一些关键的接口,如打开、关闭、读写、IOCTL 操作等。
- 驱动程序在初始化时,会注册设备并为其提供
-
设备操作
- 用户空间程序可以通过标准的文件操作接口打开设备,并使用 IOCTL 命令进行设备控制、设置格式、获取流数据等。
- 数据传输一般使用缓冲区队列,通过
VIDIOC_QBUF
和VIDIOC_DQBUF
控制缓冲区的入队和出队。
-
异步处理
- 应用程序可以使用
select()
或poll()
等异步机制,等待数据的到来或设备的响应。
- 应用程序可以使用
-
清理与释放
- 当设备不再使用时,应用程序会通过
close()
关闭设备并释放资源,驱动程序也会相应地释放与设备相关的资源。
- 当设备不再使用时,应用程序会通过
1.5、V4L2 的常见应用
- 摄像头应用:通过 V4L2 驱动和 API,应用程序可以访问和控制电脑或嵌入式设备上的摄像头,进行视频捕获。
- 视频会议系统:通过 V4L2,视频会议软件可以捕捉视频流并进行显示或传输。
- 视频监控:V4L2 可以用来管理和操作视频监控设备,处理实时视频流。
- 视频流媒体:支持从视频源采集视频流,并通过 V4L2 播放或转码。
二、系统框架图
如下即为v4l2子系统框架,针对v4l2子系统而言,其主要通过字符设备节点与应用层交互:
- 通过字符设备文件,应用程序可通过字符设备文件完成与具体v4l2 device的通信;
而在v4l2子系统内部,则主要包括如下几方面的内容:
- video_device结构体用于创建v4l2 device对应的字符设备节点,该数据结构包含了指向v4l2-dev的指针、字符设备指针(struct cdev类型)、字符设备文件相关的操作接口指针、v4l2 control handler、v4l2_fh;
- v4l2_dev则是对一个v4l2_dev的抽象,该v4l2_dev管理该device下所有的子设备(即v4l2_subdev),若该v4l2_dev没有子设备,则v4l2_dev的作用应该不大,基本上针对没有子设备的v4l2,借助video_device操作,即可完成针对该v4l2_dev的访问操作(通过字符设备的读、写、ioctl接口即可);
- V4l2_subdev则代表一个v4l2 dev的子设备,针对一个v4l2 dev,可以完成各种任务操作,但通常他们负责音视频复用和编解码。如网络摄像头的子设备通常是传感器和摄像头控制器。 针对v4l2_subdev则提供了该子设备的操作接口等信息,可实现与子设备的通信操作;
- V4l2_fh则对应一个已打开的v4l2_dev字符设备file,可以理解为该打开字符设备file的handler,一般为该字符设备文件的私有v4l2_dev变量;通过v4l2_fh,可以使用v4l2子系统提供的v4l2 control handler以及v4l2 event相关机制;
- V4l2 event机制主要实现将v4l2 dev的触发事件发送给应用程序,主要借助poll 、wait机制实现。
- v4l2_ctrl_handler是v4l2设备控制方法集的结构体,可通过字符设备文件提供的ioctl接口访问对应的方法
- videobuff用于v4l2的buff操作,针对v4l2 device,主要有三种IO访问方法(read/write)、内存映射缓冲区(内核驱动申请缓存并mmap至应用层)、USERPTR(应用层负责分配内存空间,通过指针的形式传递给V4L2子系统驱动,V4L2 device driver会把捕获的内容保存至指针所指的空间)