V4L2 子系统
V4L2(Video for Linux 2)是 Linux 内核中用于视频采集、输出和处理的标准子系统。
什么是 V4L2
V4L2 是 Linux 下视频设备的统一接口框架,向上为用户空间提供统一的 ioctl 接口,向下对接各类视频硬件驱动(Camera、TV Tuner、Codec 等)。
用户空间
↓ (open / ioctl / mmap / read)
V4L2 核心 (videobuf2 等)
↓
具体硬件驱动 (Sensor / ISP / MIPI CSI 等)
↓
硬件设备节点
V4L2 设备通常以 /dev/videoX 的形式存在:
bash
ls -la /dev/video*| 设备号 | 用途 |
|---|---|
| /dev/video0 | 通常是第一个视频采集设备 |
| /dev/video1 | 可能是第二个设备或同一设备的另一个节点 |
| /dev/media0 | Media Controller 设备 |
| /dev/v4l-subdevX | V4L2 子设备节点 |
常用 ioctl 命令
查询设备能力
c
struct v4l2_capability cap;
ioctl(fd, VIDIOC_QUERYCAP, &cap);关键字段:
cap.driver— 驱动名称cap.card— 设备名称cap.bus_info— 总线信息cap.capabilities— 设备能力标志
枚举支持的格式
c
struct v4l2_fmtdesc fmt_desc;
fmt_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt_desc.index = 0;
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt_desc) == 0) {
printf("Format: %s\n", fmt_desc.description);
fmt_desc.index++;
}设置视频格式
c
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 1920;
fmt.fmt.pix.height = 1080;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_NONE;
ioctl(fd, VIDIOC_S_FMT, &fmt);常用像素格式:
V4L2_PIX_FMT_YUYV— YUYV422 格式V4L2_PIX_FMT_NV12— NV12 格式(Y 平面 + UV 交错平面)V4L2_PIX_FMT_MJPEG— MJPEG 格式V4L2_PIX_FMT_H264— H.264 格式
缓冲管理方式
V4L2 支持多种缓冲管理方式:
1. READ 模式(最简单)
直接使用 read() 读取帧数据。
c
read(fd, buffer, buffer_size);- 优点:简单
- 缺点:有数据拷贝,性能低
2. MMAP 模式(最常用)
将内核缓冲区映射到用户空间,零拷贝。
c
// 请求缓冲
struct v4l2_requestbuffers req;
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ioctl(fd, VIDIOC_REQBUFS, &req);
// 映射每帧缓冲
for (int i = 0; i < req.count; i++) {
struct v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
ioctl(fd, VIDIOC_QUERYBUF, &buf);
buffers[i] = mmap(NULL, buf.length, PROT_READ, MAP_SHARED, fd, buf.m.offset);
}- 优点:零拷贝,性能高
- 缺点:编程稍复杂
3. USERPTR 模式
用户空间自己分配缓冲,传递指针给内核。
- 优点:缓冲管理灵活
- 缺点:需要内核和用户空间之间的内存一致性处理
4. DMABUF 模式
通过 DMA-BUF 在不同硬件模块间共享缓冲(如 V4L2 → MPP → RGA 零拷贝流水线)。
- 优点:硬件间零拷贝,性能最高
- 缺点:编程最复杂
采集流程(MMAP 模式)
1. open 设备
2. VIDIOC_QUERYCAP 查询能力
3. VIDIOC_S_FMT 设置格式
4. VIDIOC_REQBUFS 请求缓冲
5. VIDIOC_QUERYBUF 查询缓冲 + mmap 映射
6. VIDIOC_QBUF 将缓冲入队
7. VIDIOC_STREAMON 启动流
8. VIDIOC_DQBUF 取出一帧处理
9. VIDIOC_QBUF 重新入队
... 循环 8-9 ...
10. VIDIOC_STREAMOFF 停止流
11. munmap 释放映射
12. close 关闭设备v4l2-ctl 常用命令
shellbash
# 列出设备信息
v4l2-ctl -d /dev/video0 --all
# 列出支持的格式
v4l2-ctl -d /dev/video0 --list-formats-ext
# 设置格式
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1920,height=1080,pixelformat=YUYV
# 抓取一帧保存
v4l2-ctl -d /dev/video0 --stream-mmap --stream-count=1 --stream-to=output.yuv
# 查看控件列表
v4l2-ctl -d /dev/video0 --list-ctrls
# 设置曝光
v4l2-ctl -d /dev/video0 --set-ctrl=exposure=1000常见问题
DQBUF 超时
VIDIOC_DQBUF 阻塞返回 ETIMEDOUT,常见原因:
- Sensor 未正常输出数据(电源、时钟、复位)
- MIPI CSI 链路未建立
- 设备树配置错误
- ISP 未正确配置
→ 详见 Debug 记录:VIDIOC_DQBUF Timeout
帧数据不对
- 像素格式不匹配
- stride/对齐问题
- 分辨率设置错误
相关实验
参考资料
- Linux Kernel V4L2 文档
- v4l2-ctl man page
