一、已知V4L2的概念
V4L2(Video for Linux 2)是Linux内核中处理视频设备的标准驱动框架。它为应用程序提供了一套统一的API,使得开发者可以用相同的代码逻辑来操作不同厂商、不同类型的摄像头。
V4L2不只是个"软件库",它的核心价值在于对复杂硬件流水线的抽象。从SoC收到CSI数据开始,可以清晰地看到它是如何一步步将物理信号,转化为应用程序能直接使用的图像数据的。
二、到底V4L2对于工程开发意味着什么
V4L2是设计范式(Design Pattern)和接口契约(Interface Contract),而不同SoC厂商在这个契约下,给出了完全不同的硬件实现(Implementation)和私有扩展(Private Extension)。"
正因为有这个差异存在,嵌入式Linux视频开发最难的部分往往不是学V4L2,而是吃透某一家SoC厂商的V4L2"魔改"手册。
对于开发者,V4L2的魅力在于,无论底层硬件如何复杂,用户空间的操作流程都是标准化的。
-
打开设备 :
open("/dev/video0", O_RDWR)。 -
查询能力 :
ioctl(fd, VIDIOC_QUERYCAP, &cap),确认设备支持视频捕获。 -
设置格式 :
ioctl(fd, VIDIOC_S_FMT, &fmt),告诉驱动需要什么分辨率和像素格式(如V4L2_PIX_FMT_NV12)。 -
申请缓冲区 :
ioctl(fd, VIDIOC_REQBUFS, &reqbuf),在内核空间申请用于存放图像数据的缓冲区。 -
映射缓冲区 :
mmap(),将内核空间的缓冲区映射到应用程序的虚拟地址空间,以便直接访问。 -
缓冲区入队 :
ioctl(fd, VIDIOC_QBUF, &buf),将空缓冲区放入驱动等待队列。 -
启动视频流 :
ioctl(fd, VIDIOC_STREAMON, &type),硬件开始工作,图像数据开始填充缓冲区。 -
循环取帧:
-
使用
select()或poll()等待缓冲区有数据。 -
ioctl(fd, VIDIOC_DQBUF, &buf),取出一个填满数据的缓冲区。 -
处理图像数据(例如,保存为文件或送去显示)。
-
ioctl(fd, VIDIOC_QBUF, &buf),将处理完的缓冲区再次入队,以接收新数据。
-
-
停止视频流 :
ioctl(fd, VIDIOC_STREAMOFF, &type)。 -
关闭设备 :
close(fd)。
三、下面举高通的实例
高通在 Linux 内核中实现 V4L2 的核心是 CamSS (Camera Subsystem) 驱动。它完整地实现了 V4L2、Media Controller 和 V4L2 subdev 接口,将复杂的相机硬件流水线,抽象为一个个标准的、可供用户空间程序控制的 V4L2 子设备(subdev)。
(1)CamSS 驱动:硬件模块的 V4L2 的抽象
CamSS 驱动将相机子系统中的每个硬件模块都封装成一个标准的 v4l2_subdev 内核对象。以高通骁龙8x16/8x96系列为例,主要包含以下子设备:
-
CSIPHY (CSI 物理层) 子设备 :处理 MIPI CSI-2 接收器的物理层协议。每个物理的 CSIPHY 模块对应一个子设备。
-
CSID (CSI 解码器) 子设备 :处理 MIPI CSI-2 接收器的协议层和应用层。它能解码来自任何 CSIPHY 的数据流,并包含测试图像生成器 (TG)。
-
ISPIF (ISP 接口) 子设备:负责将数据从 CSID 路由到 VFE 模块的输入端。
-
VFE (视频前端) 子设备:包含实际的 ISP 图像处理硬件流水线。它有两种接口:
-
PIX (Pixel) 接口:将数据送入完整的 ISP 处理流水线。
-
RDI (Raw Dump Interface) 接口 :绕过 ISP 处理,直接原始转储 (raw dump) 数据到内存,用于调试或特殊需求。每个 RDI 端口都有独立的
/dev/video节点。
-
(2)完整的数据流示例:从 MIPI 数据到应用层的实现
下面以一个典型的场景为例,完整展示数据如何从 MIPI 接口流转到应用层:
-
物理信号接收:图像传感器通过 MIPI CSI-2 接口将图像数据发送给 SoC。
-
CamSS 驱动接管:
-
CSIPHY子设备接收并处理 MIPI 信号的物理层。 -
CSID子设备解码数据流。
-
-
数据路由与处理:
-
ISPIF子设备 将数据从CSID路由到VFE的对应输入接口。 -
VFE子设备 的 PIX 接口 对数据进行 ISP 处理(如去马赛克、降噪等),或通过 RDI 接口进行原始数据转储。
-
-
数据输出到内存 :
VFE通过 AXI 总线接口将处理后的数据写入系统内存(DDR)。 -
应用层获取 :用户空间的应用程序(如 CamX)通过标准的 V4L2 接口(如
read或mmap+VIDIOC_DQBUF),从对应的/dev/videoX节点读取内存中的图像数据