3. V4L2框架基础:Video for Linux 2架构、设备节点、ioctl调用流程
V4L2(Video for Linux 2)是Linux内核中视频设备驱动的标准框架,也是RK3588多Camera开发中用户空间与内核驱动交互的核心桥梁。理解V4L2的架构层次、设备节点映射以及ioctl调用流程,是编写稳定、高效的Camera应用和驱动的基础。
3.1 V4L2整体架构
V4L2采用分层设计,从上到下依次为:用户空间应用程序、V4L2设备节点、V4L2核心框架、V4L2子设备驱动以及具体的硬件设备。这种分层结构使得应用层代码与硬件解耦,驱动开发者只需关注子设备层面的实现。
架构要点: V4L2核心框架负责管理设备节点、ioctl分发、buffer队列调度;子设备驱动(如Sensor、CSI、ISP)通过v4l2_subdev接口注册到核心框架。
3.2 设备节点类型与映射
在RK3588平台上,V4L2设备节点主要分为两类:主设备节点和子设备节点。主设备节点用于视频数据流和常规控制,子设备节点用于配置Sensor、ISP等硬件模块。
| 设备节点 | 主设备号 | 次设备号范围 | 典型用途 |
|---|---|---|---|
/dev/video0 ~ /dev/video63 |
81 | 0 ~ 63 | 视频数据捕获/输出(主设备) |
/dev/v4l-subdev0 ~ /dev/v4l-subdev31 |
81 | 64 ~ 95 | 子设备控制(Sensor、ISP、CSI) |
/dev/media0 ~ /dev/media31 |
81 | 96 ~ 127 | Media Controller拓扑管理 |
RK3588实践提示: 多Camera场景下,每个物理Camera Sensor通常对应一个子设备节点(如
/dev/v4l-subdev0),而经过ISP处理后的视频流则通过主设备节点(如/dev/video0)输出。使用ls -l /dev/video* /dev/v4l-subdev*可查看当前系统设备节点映射。
3.3 ioctl调用流程详解
ioctl是V4L2框架中用户空间与内核驱动通信的核心机制。一次典型的ioctl调用涉及用户空间、V4L2核心框架、驱动三层处理。以VIDIOC_S_FMT(设置格式)为例,完整调用流程如下:
- 用户空间发起: 应用程序调用
ioctl(fd, VIDIOC_S_FMT, &fmt),其中fd为/dev/videoX的文件描述符。 - V4L2核心分发: 内核中的
video_ioctl2函数根据命令号查找对应的v4l2_ioctl_ops回调表。 - 驱动层处理: 调用驱动注册的
vidioc_s_fmt回调函数,驱动在此处验证参数并配置硬件寄存器。 - 结果返回: 驱动返回0表示成功,负值表示错误码(如
-EINVAL),最终传递回用户空间。
3.4 关键ioctl命令分类
V4L2定义了丰富的ioctl命令,按功能可分为以下几类。在RK3588多Camera开发中,以下命令使用频率最高:
| 分类 | 命令宏 | 功能描述 | 使用场景 |
|---|---|---|---|
| 格式协商 | VIDIOC_ENUM_FMT |
枚举支持的像素格式 | 查询Sensor/ISP支持的格式列表 |
VIDIOC_S_FMT / VIDIOC_G_FMT |
设置/获取当前格式 | 配置分辨率、像素格式、帧率 | |
| Buffer管理 | VIDIOC_REQBUFS |
请求分配Buffer | 申请视频数据缓冲区 |
VIDIOC_QBUF / VIDIOC_DQBUF |
入队/出队Buffer | 数据流循环处理 | |
| 流控制 | VIDIOC_STREAMON |
启动视频流 | 开始采集/输出 |
VIDIOC_STREAMOFF |
停止视频流 | 停止采集/输出 | |
| 子设备控制 | VIDIOC_SUBDEV_S_FMT |
设置子设备格式 | 配置Sensor输出尺寸、ISP输入格式 |
3.5 驱动侧ioctl回调注册
在驱动开发中,通过填充 v4l2_ioctl_ops 结构体来注册ioctl回调。以下是一个典型的Sensor驱动回调注册片段:
static const struct v4l2_ioctl_ops sensor_ioctl_ops = {
.vidioc_querycap = sensor_querycap,
.vidioc_enum_fmt_vid_cap = sensor_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = sensor_g_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = sensor_s_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = sensor_try_fmt_vid_cap,
.vidioc_reqbufs = sensor_reqbufs,
.vidioc_querybuf = sensor_querybuf,
.vidioc_qbuf = sensor_qbuf,
.vidioc_dqbuf = sensor_dqbuf,
.vidioc_streamon = sensor_streamon,
.vidioc_streamoff = sensor_streamoff,
};
static struct video_device sensor_vdev = {
.ioctl_ops = &sensor_ioctl_ops,
.release = video_device_release_empty,
.vfl_dir = VFL_DIR_RX,
};
常见错误: 驱动中未正确实现
vidioc_try_fmt 回调,导致用户空间调用 VIDIOC_S_FMT 时参数校验失败,返回 -EINVAL。务必在 try_fmt 中修正不支持的参数(如对齐到硬件要求的步长)。
3.6 Media Controller与Pipeline控制
RK3588平台的多Camera系统通常使用Media Controller框架来管理复杂的pipeline拓扑。通过 /dev/media0 节点,应用程序可以:
- 枚举pipeline中的实体(Entity):Sensor、CSI、ISP等。
- 设置数据链路(Link):使能或禁用实体之间的连接。
- 配置Pad格式:设置每个实体输入/输出端的格式。
典型的Media Controller配置流程如下:
- 打开
/dev/media0,调用MEDIA_IOC_ENUM_ENTITIES获取所有实体信息。 - 调用
MEDIA_IOC_ENUM_LINKS获取实体间的连接关系。 - 调用
MEDIA_IOC_SETUP_LINK使能从Sensor到CSI再到ISP的数据链路。 - 通过子设备节点配置每个实体的格式,最后通过主设备节点启动视频流。
RK3588实践: 在RK3588 SDK中,
rkisp 驱动模块集成了ISP子设备,通过Media Controller与CSI和Sensor子设备连接。使用 media-ctl 工具可以快速查看和配置pipeline:media-ctl -d /dev/media0 -p。