最近对摄影尤其感兴趣,因此对于Linux下的摄像头是如何工作的同样产生了浓厚的兴趣。想要去探寻一下摄像头底层的工作原理。如果感兴趣的话一起来和博主进行接下来的揭秘吧!
一、摄像头基础概念
在一切开始之前,我们需要先对摄像头的各种基础概念有一个了解,相当于打下基础,以防后面面对这些词汇时产生局促不安哈哈。
1.1 摄像头硬件基础
摄像头的工作原理其实是将采集的光信号转化为电信号,然后将转换成的电信号做各种处理,最终输出图像数据,完整流程如下图所示:

- 镜头:收集光线,负责光信号的采集
- 传感器:主要负责光信号向电信号的转化
- ISP:主要将采集到的信号进行处理工作,比如白平衡、降噪、曝光等工作,是最终输出图像数据的重要一环
1.2 图像基础知识
了解了摄像头的工作流程之后,我们需要对输出的图像格式有一个基本了解,这涉及到后续的接口参数设置,因此了解这方面的内容也是很有必要的。
- 像素
我们可以把一张图像想象成由很多点构成的,而这个点其实就被称作像素,是图像的最小单元。
- 分辨率
分辨率描述了一张图像由多少个像素点构成。我们常听到的”1080P”,其实就是描述了一张图片的宽由1920个像素点,高由1080个像素点构成。可以想象,构成图像的像素点越多,成像质量就越细腻。
- 帧率 (FPS)
摄像头通过高速采集图像来构成一段视频流,而描述视频流流畅度的直接参数就是帧率,即摄像头每秒可以采集多少张图片。
- 图像格式
我们熟知的图像格式有RGB格式以及YUV格式,这个参数直接影响到图像的存储方式。
RGB格式:每个像素点由红(R)、绿(G)、蓝(B)组成。这种格式适合在电脑上显示,但由于数据量大(一个像素点需要多位数据描述),不太适合嵌入式这种资源受限的设备进行存储。
YUV格式:为了解决RGB数据量大的问题,YUV格式应运而生。它将亮度信息(Y)与色度信息(U/V)分离,可以压缩颜色信息,数据量小,适合传输和存储。
二、Linux下的摄像头
2.1 Linux一切皆文件
在Linux中我们熟知的一句话叫做”一切皆文件“。摄像头在Linux中也以文件的形式呈现:
/dev/video0 # 第一个摄像头
/dev/video1 # 第二个摄像头
对摄像头的操作本质上也是对文件的操作:打开——读取——关闭。但摄像头文件有其特殊性——内容是动态产生的:
摄像头 → 拍一张 → 得到一帧图像
→ 再拍一张 → 得到另一帧图像
→ 一直拍 → 得到视频流
因此我们不能用普通的read/write接口进行操作,而需要使用ioctl接口——Linux中专门用来和设备”对话”的接口:

2.2 V4L2——Linux视频统一标准
而说到操作这个摄像头文件,在Linux中,规范了一个类似于协议的东西——V4L2 (Video for Linux 2)。它是Linux系统的摄像头统一标准,无论什么型号的摄像头,都用同一套文件操作流程控制。
反应到真实代码中就如下面的伪代码流程所示:
// 1. 打开摄像头
fd = open("/dev/video0", ...);
// 2. 设置参数
struct v4l2_format fmt;
fmt.width = 1920; // 分辨率:1920x1080
fmt.height = 1080;
fmt.pixelformat = V4L2_PIX_FMT_NV12; // 格式:NV12
ioctl(fd, VIDIOC_S_FMT, &fmt);
// 3. 申请缓冲区
struct v4l2_requestbuffers req;
req.count = 4;
ioctl(fd, VIDIOC_REQBUFS, &req);
// 4. 开始工作
ioctl(fd, VIDIOC_STREAMON);
// 5. 循环取数据
while(1) {
ioctl(fd, VIDIOC_DQBUF, &buf); // 取出已填满的缓冲区
process_image(buf); // 处理图像数据
ioctl(fd, VIDIOC_QBUF, &buf); // 将缓冲区重新入队
}
// 6. 结束
ioctl(fd, VIDIOC_STREAMOFF);
close(fd);
可以看到其实他这个规范就是要求了我们ioctl该如何去控制这个摄像头文件。
2.2 v4l2-ctl——V4L2命令行工具
Linux中封装了V4L2操作的命令行工具——v4l2-ctl。这个工具内部封装了ioctl对于摄像头文件的各种操作,可以帮助我们进行摄像头最基本的调试:
例如:
v4l2-ctl --list-devices #列出所有 V4L2 设备,查询摄像头支持哪些分辨率、像素格式、帧率等
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=NV12 #设置/dev/video0设备的参数信息
v4l2-ctl --stream-mmap --stream-count=10 --stream-to=test.raw #采集一帧图像
这个工具方便了我们对于摄像头的一个调试工作。
三、摄像头应用框架——Rockit
3.1 为什么需要应用框架?
在对摄像头做应用逻辑开发时,我们会有各种操作需求:视频流获取、视频保存、视频流显示等。这些操作本质上都是遵循V4L2规范对摄像头文件进行操作。但是,正如我们前面看到的,仅仅获取一帧图像就需要:设置格式、申请内存、映射、入队、开始流、循环取帧等一系列复杂操作。
这些操作的难度较高,同时有很多细节需要处理,大大降低了开发效率。于是,瑞芯微厂商按照V4L2的规范封装了一系列接口,这个接口的统称就叫做——Rockit。
有了这个架构之后我们的操作复杂度大大降低,还是同一个应用需求,比如想要获取一帧图像数据:
RK_MPI_VI_GetChnFrame(pipe, chn, &frame, timeout);//只需要调用这一个接口即可完成
// 内部帮你做了:
// - 维护V4L2文件描述符
// - 管理缓冲区队列
// - 处理VIDIOC_DQBUF
// - 错误重试
// - 超时控制
3.2 一个常见疑问
其实我不知道大家在看到这里有没有这么一个疑问产生:明明Linux内部已经封装完成了v4l2-ctl命令,通过这个命令也可以实现视频流的采集,那么我们在应用程序中直接下面这种操作不就可以了:
//执行v4l2-ctl命令
system("v4l2-ctl -d /dev/video0 --stream-mmap --stream-count=1 --stream-to=/tmp/frame.raw");
//读取采集文件/tmp/frame.raw
read_frame_from_file();
其实这确实是一种获取视频数据的方法,但通过查阅资料发现,这对于性能角度来说是灾难性的:
- 在执行system内部会通过fork创建新的进程,大大浪费了系统资源
- 进程切换、文件读写会导致延迟
- 每次都要重新申请/释放缓冲区
- 并且还会出现画面伪影的现象。
而使用标准的框架,在提高开发效率的同时也大大提高系统性能,如下面这种操作:
RK_MPI_SYS_Init(); // 初始化一次
while(1) {
// 直接获取帧(内部已经是优化好的缓冲区循环)
RK_MPI_VI_GetChnFrame(pipe, chn, &frame, 1000);
// ADAS处理
process_adas(frame);
// 释放帧(放回缓冲区循环)
RK_MPI_VI_ReleaseChnFrame(pipe, chn, &frame);
}
- 高性能:一次初始化,持续运行
- 低延迟:内存直接操作,没有进程创建/文件读写
- 硬件加速:Rockit内部调用硬件模块,CPU负载低
所以综上来看,v4l2-ctl这个命令的定位只是一个在调试阶段的工具,并不能用作实际项目的开发。
讲到这里我们对于rockit框架有了一个基本的了解,他就是为了提高我们的开发效率而产生的。我们通过调用他内部的各种接口,从而实现了摄像头的一个应用开发。
四、Rockit四层框架
在rockit框架中,把摄像头的应用开发分了四个核心层次:
- VI (Video Input) – 视频输入
这一层的应用在于我们刚刚讨论了半天的图像帧获取的需求,所以它负责的一个职责就是:从摄像头获取原始图像数据
- VO (Video Output) – 视频输出
这一层的关键在于视频的输出,比如把采集到的视频放在哪显示。如果我们有一个需求是想要把摄象头采集的内容在一个屏幕显示出来,那必然就需要用到这一层的API
- VENC (Video Encoder) – 视频编码
将YUV数据压缩成H.264/H.265的职责
- VPSS (Video Process Sub-System) – 视频处理
这一层主要是对于采集到的图像做各种操作,比如缩小、旋转等等…
这四个层之间的关系:

这些预制件(VI/VO/VENC/VPSS)就是Rockit框架的核心组件,它们负责和底层的V4L2、驱动、硬件打交道,然后提供到我们的只是一些简单接口。
- 如果需要录像:VI → VPSS(可选) → VENC → 文件
- 如果需要显示:VI → VPSS → VO → 屏幕
- 如果需要同时录像和显示:VI → VPSS(一分二) → VENC 和 VO
五、总结
这篇文章,我们梳理了从摄像头硬件基础,到Linux V4L2标准,再到Rockit应用框架的完整的一个体系:
- 摄像头硬件:理解光线→传感器→ISP的基本流程
- 图像基础:掌握分辨率、帧率、YUV/RGB等核心概念
- Linux V4L2:了解”一切皆文件”的设计哲学,以及V4L2作为视频统一标准的重要性
- v4l2-ctl:掌握这个调试工具的正确使用场景
- Rockit框架:理解为什么需要应用框架,以及VI/VPSS/VENC/VO四个核心组件的职责
Rockit框架的核心价值在于:它将复杂的V4L2底层操作封装成易用的API,同时充分利用硬件加速能力,让开发者能够专注于业务逻辑的实现。
在接下来的文章我将对于Rockit内部API做详细解释,欢迎大家来和我进行技术交流!



😊😊