V4L2框架基础:核心数据结构与Pipeline概念
做摄像头驱动开发,V4L2是绕不开的坎。我刚开始接触R-Car平台时,也被这套框架搞得晕头转向。说白了,V4L2就是Linux内核给视频设备定的一套标准接口。你只要按它的规矩来,上层应用就能用统一的open/ioctl去操作摄像头,不用管底层是MIPI还是USB。
这一章,我带你拆解V4L2最核心的几个概念。理解了它们,后面调试驱动时你才知道问题出在哪。
2.1 核心数据结构:video_device 与 v4l2_device
先看两个最重要的结构体。一个是代表“视频设备节点”的,一个是代表“整个硬件设备”的。
2.1.1 video_device
video_device 对应 /dev/videoX 这个设备节点。用户空间打开它,就能发ioctl、取数据。它的定义在 include/media/v4l2-dev.h 里。
struct video_device {
const struct v4l2_file_operations *fops;
struct v4l2_ioctl_ops *ioctl_ops;
struct device dev;
struct v4l2_device *v4l2_dev;
unsigned long flags;
int index;
// ... 其他字段
};
我个人习惯重点关注这几个字段:
- fops:文件操作函数集,open/release/read/write/poll 都在这里。
- ioctl_ops:ioctl 操作函数集,后面会细讲。
- v4l2_dev:指向父设备,也就是 v4l2_device。
- index:设备编号,决定是 /dev/video0 还是 /dev/video1。
2.1.2 v4l2_device
v4l2_device 代表一个完整的视频硬件设备。它可能包含多个 subdev(子设备),比如一个摄像头模组里有 sensor、ISP、串行器等。定义在 include/media/v4l2-device.h。
struct v4l2_device {
struct device *dev;
struct list_head subdevs;
spinlock_t lock;
char name[V4L2_DEVICE_NAME_SIZE];
// ...
};
关键点:
- subdevs:链表,挂载所有子设备。
- dev:指向 platform_device 或 i2c_client 的 device 结构。
- name:设备名,调试时很有用。
| 结构体 | 作用 | 对应用户空间 |
|---|---|---|
| video_device | 代表 /dev/videoX 节点 | open/ioctl/mmap |
| v4l2_device | 代表整个硬件设备 | 无直接对应 |
2.2 ioctl调用流程:从用户态到硬件
你写个应用程序调用 ioctl(fd, VIDIOC_S_FMT, &fmt),内核里到底发生了什么?我画个图你就明白了。
流程其实不复杂。关键是 v4l2_ioctl 这个核心分发函数。它会根据你传入的 cmd(比如 VIDIOC_S_FMT),去 video_device->ioctl_ops 里找到对应的回调函数。
避坑指南:我曾经在实现 VIDIOC_S_FMT 时,忘了检查用户传入的格式是否合法。结果上层传了个 1920x1080 的格式,但 sensor 只支持 1280x720。驱动直接写寄存器,sensor 就罢工了。后来我加了个格式校验表,才搞定。
2.3 subdev与pipeline概念
现代摄像头模组不是单一设备。一个典型的 R-Car 摄像头通路是这样的:
- sensor:采集图像,输出 RAW 数据。
- 串行器/解串器:把 MIPI CSI-2 信号转成并行。
- ISP:图像信号处理,做去噪、白平衡等。
- 视频采集控制器:把数据写入内存。
每个硬件模块都是一个 subdev(子设备)。它们通过 pipeline(管道)串联起来,数据才能从 sensor 流到内存。
2.3.1 subdev 结构
struct v4l2_subdev {
struct v4l2_device *v4l2_dev;
struct media_entity entity;
const struct v4l2_subdev_ops *ops;
struct v4l2_subdev_pad_config *config;
char name[V4L2_SUBDEV_NAME_SIZE];
// ...
};
每个 subdev 有自己的 pad(端口)。pad 分两种:
- 源端(source pad):数据从这里出去。
- 接收端(sink pad):数据从这里进来。
比如 sensor 只有一个 source pad,ISP 有一个 sink pad 和一个 source pad。
2.3.2 pipeline 的建立
pipeline 是通过 media controller 框架来建立的。你想想看,应用层要配置一条通路,得先知道 sensor 连到哪个 ISP,ISP 又连到哪个视频采集控制器。
在 R-Car 平台上,我通常这样建立 pipeline:
- 枚举所有 subdev,找到 sensor 和视频采集控制器。
- 通过 media controller 的 ioctl(MEDIA_IOC_ENUM_LINKS)查看连接关系。
- 调用 MEDIA_IOC_SETUP_LINK 建立连接。
- 最后通过 VIDIOC_SUBDEV_S_FMT 配置每个 subdev 的格式。
2.4 小结
这一章我们聊了 V4L2 的三个核心概念:
- video_device:用户空间看到的 /dev/videoX。
- v4l2_device:整个硬件设备的抽象。
- subdev 与 pipeline:模块化硬件和它们之间的数据通路。