V4l2相关
一、V4L2框架概述
V4L2(Video for Linux 2)是Linux内核中专门为视频设备设计的驱动框架,它为应用程序提供了一套统一的操作接口来控制摄像头、视频采集卡等设备。在Linux系统中,V4L2设备通常表现为/dev/videoX设备节点。
1.1 为什么需要V4L2框架?
现代视频设备通常非常复杂,一个设备可能包含多个IC(集成电路),导出多个设备节点,还可能同时创建DVB、ALSA、FB、I2C等非V4L2设备。此外,视频设备还需要处理音频/视频的复用、编码/解码等复杂功能,这些功能通常通过I2C等总线连接到主桥驱动器,这类设备被称为"子设备"(sub-device)。
在V4L2框架出现之前,所有驱动都需要自己完成设备实例的设置和子设备的连接,这项工作相当复杂,很多驱动都没有正确实现。V4L2框架的诞生就是为了提供所有驱动都需要的基本构建块,使通用代码可以被复用。
1.2 框架架构图
设备实例(device instances)
|
+--子设备实例(sub-device instances)
|
\--V4L2设备节点(V4L2 device nodes)
|
\--文件句柄实例(filehandle instances)
二、核心数据结构
V4L2框架主要包含以下四个核心数据结构:
| 数据结构 | 作用 | 对应层级 |
|---|---|---|
v4l2_device | 代表整个设备实例,是所有子设备的容器 | 设备实例层 |
v4l2_subdev | 代表子设备(如传感器、ISP、解码器等) | 子设备层 |
video_device | 创建V4L2设备节点,负责与用户空间交互 | 设备节点层 |
v4l2_fh | 跟踪每个文件句柄的私有数据 | 文件句柄层 |
2.1 v4l2_device
v4l2_device是每个设备实例的核心结构体,它代表一个完整的视频设备。
主要功能:
- 作为所有子设备的容器,管理该设备下的所有
v4l2_subdev - 提供与媒体框架(
media framework)的可选集成 - 提供引用计数机制,支持热插拔设备
注册与注销:
// 注册设备实例
int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
// 注销设备实例
void v4l2_device_unregister(struct v4l2_device *v4l2_dev);
// 热插拔设备断开连接时调用
void v4l2_device_disconnect(struct v4l2_device *v4l2_dev);
引用计数管理:
void v4l2_device_get(struct v4l2_device *v4l2_dev); // 增加引用计数
int v4l2_device_put(struct v4l2_device *v4l2_dev); // 减少引用计数
引用计数初始值为1。当调用video_register_device时增加,设备节点释放时减少。当计数归零时,会调用release()回调进行清理。
2.2 v4l2_subdev
v4l2_subdev用于抽象子设备,如摄像头传感器、ISP(图像信号处理器)、视频解码器等。
子设备操作函数集:
struct v4l2_subdev_core_ops {
int (*g_chip_ident)(struct v4l2_subdev *sd, ...);
int (*log_status)(struct v4l2_subdev *sd);
int (*init)(struct v4l2_subdev *sd, u32 val);
// ...
};
struct v4l2_subdev_video_ops {
// 视频相关操作
};
struct v4l2_subdev_audio_ops {
// 音频相关操作
};
struct v4l2_subdev_ops {
const struct v4l2_subdev_core_ops *core;
const struct v4l2_subdev_tuner_ops *tuner;
const struct v4l2_subdev_audio_ops *audio;
const struct v4l2_subdev_video_ops *video;
};
调用子设备操作:
// 使用宏调用更安全(会自动进行NULL检查)
err = v4l2_subdev_call(subdev, core, g_chip_ident, &chip);
// 调用所有子设备的某个操作
v4l2_device_call_all(dev, 0, core, log_status);
2.3 video_device
video_device用于创建V4L2设备节点(如/dev/video0),提供用户空间访问接口。
核心字段:
v4l2_file_operations *fops:文件操作函数集v4l2_ioctl_ops *ioctl_ops:ioctl操作函数集vb2_queue *queue:videobuf2缓冲区队列
2.4 v4l2_fh
v4l2_fh用于管理每个文件句柄的私有数据,并实现优先级处理。
使用方式:
struct my_fh {
int blah;
struct v4l2_fh fh;
};
int my_open(struct file *file) {
struct my_fh *my_fh = kzalloc(sizeof(*my_fh), GFP_KERNEL);
v4l2_fh_init(&my_fh->fh, vfd);
file->private_data = &my_fh->fh;
v4l2_fh_add(&my_fh->fh);
return 0;
}
三、媒体框架(Media Framework)集成
当硬件需要支持复杂的数据流通路(如ISP中可选择不同的图像处理路径)时,V4L2框架可以与媒体框架结合使用。
3.1 核心概念
| 概念 | 描述 |
|---|---|
media_device | 管理所有媒体实体 |
media_entity | 代表一个硬件模块(如CSI、CCDC、Resizer等) |
media_pad | 实体的端口(source或sink) |
media_link | 连接两个pad,定义数据流方向 |
media_pipeline | 由多个entity组成的数据通路 |
3.2 硬件拓扑示例
以OMAP3 ISP为例,典型的硬件结构包括:
CSI:摄像头接口,接收图像数据CCDC:视频处理前端,处理图像数据Preview/Resizer:视频处理后端,提供预览和尺寸调整H3A/HIST:静态统计模块,支持3A算法
这些模块通过media framework连接成灵活的数据通路,可以根据运行时需求动态选择路径。
四、Videobuf2缓冲区管理
videobuf2是V4L2框架中的缓冲区管理模块,负责用户空间和驱动之间的视频数据传输。
4.1 核心组件
vb2_queue(缓冲区队列)
├── vb2_buffer[](缓冲区数组)
├── queued_list(待处理队列)
├── done_list(已完成队列)
├── vb2_ops(驱动实现的队列操作)
├── vb2_buf_ops(缓冲区操作)
└── vb2_mem_ops(内存分配操作)
4.2 三种内存模型
| 类型 | 描述 | 适用场景 |
|---|---|---|
MMAP | 内存映射方式,内核分配缓冲区并映射到用户空间 | 连续视频数据采集(最常用) |
read/write | 直接读取方式,数据从内核拷贝到用户空间 | 静态图片采集 |
USERPTR | 用户指针方式,用户空间分配缓冲区 | 特殊应用场景 |
五、应用层开发流程
使用V4L2进行视频采集的典型步骤:
text
1. 打开设备节点
↓
2. 查询设备能力(VIDIOC_QUERYCAP)
↓
3. 设置视频格式(VIDIOC_S_FMT)
↓
4. 申请缓冲区(VIDIOC_REQBUFS)
↓
5. 查询并映射缓冲区(VIDIOC_QUERYBUF + mmap)
↓
6. 缓冲区入队(VIDIOC_QBUF)
↓
7. 开始视频流(VIDIOC_STREAMON)
↓
8. 循环:出队(VIDIOC_DQBUF)→ 处理数据 → 入队(VIDIOC_QBUF)
↓
9. 停止视频流(VIDIOC_STREAMOFF)
↓
10. 释放资源(munmap + close)
六、总结
V4L2框架通过分层设计解决了复杂视频设备的驱动开发问题:
v4l2_device:顶层容器,管理整个设备v4l2_subdev:子设备抽象,支持模块化驱动开发video_device:用户空间接口,提供标准访问方式Media Framework:处理复杂数据通路,支持动态pipeline配置Videobuf2:高效缓冲区管理,支持多种内存模型
这种架构使得驱动开发者可以专注于硬件相关的实现细节,而通用功能由框架提供,大大简化了V4L2驱动的开发工作
1万+



被折叠的 条评论
为什么被折叠?



