RK3568 MIPI 摄像头驱动的 V4L2 多平面视频格式解析
在嵌入式 Linux 系统中,摄像头的视频采集通常通过 V4L2(Video4Linux2)接口完成。不同的摄像头驱动会支持不同的像素格式,这些格式直接影响到应用是否能够正常解析、显示或编码视频数据。
本文基于实际在 RK3568 平台 MIPI 摄像头下运行 v4l2-ctl --list-formats
的输出,详细解析每种格式的含义和用途,并解释单平面与多平面模式的区别。
1. 获取格式列表
在系统中,我们运行:
v4l2-ctl --device=/dev/video18 --list-formats
输出为:
ioctl: VIDIOC_ENUM_FMTType: Video Capture Multiplanar[0]: 'UYVY' (UYVY 4:2:2)[1]: '422P' (Planar YUV 4:2:2)[2]: 'NV16' (Y/CbCr 4:2:2)[3]: 'NV61' (Y/CrCb 4:2:2)[4]: 'YM16' (Planar YUV 4:2:2 (N-C))[5]: 'NV21' (Y/CrCb 4:2:0)[6]: 'NV12' (Y/CbCr 4:2:0)[7]: 'NM21' (Y/CrCb 4:2:0 (N-C))[8]: 'NM12' (Y/CbCr 4:2:0 (N-C))[9]: 'YU12' (Planar YUV 4:2:0)[10]: 'YM24' (Planar YUV 4:4:4 (N-C))
第一行 Type: Video Capture Multiplanar
说明:
- 这是 多平面(multi-planar) 模式的设备
- 每帧图像数据会分成多个 plane(如 NV12 有两个 plane:Y 和 UV)
- 和单平面设备相比,API 调用时使用
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
2. 格式逐一解析
[0] UYVY (UYVY 4:2:2)
- 排列方式:交错存储(Packed)
- 每两个像素共享一对 U/V 分量,格式为:U0, Y0, V0, Y1
- 常用于视频采集和回放,带宽占用比 RGB 高,但颜色分量压缩了一半
[1] 422P (Planar YUV 4:2:2)
- 排列方式:平面式(每个分量存放在不同内存区域)
- 4:2:2 意味着水平色度采样减半
- 通常用于视频编解码器输入输出,有利于硬件做快速访问
[2] NV16 (Y/CbCr 4:2:2)
- 排列方式:半平面 (semi-planar)
- Plane 0: 所有 Y 分量(亮度)
- Plane 1: 交错的 CbCr(色度),水平采样比为 4:2:2
- 适合硬件加速视频处理
[3] NV61 (Y/CrCb 4:2:2)
- 与 NV16 类似,但第二 plane 中的色度顺序颠倒为 CrCb
- 某些视频编解码器或 ISP 的内部格式
[4] YM16 (Planar YUV 4:2:2 (N-C))
- “N-C”= Non-Contiguous(非连续内存)
- 三个平面分别存 Y、U、V,水平色度采样减半
- Non-Contiguous 意味着每个 plane 独立分配内存,不一定连续
[5] NV21 (Y/CrCb 4:2:0)
- 半平面格式,Y 独立,色度采样为垂直和水平都减半
- 第二 plane 存储交错的 CrCb,与 NV12 色度分量顺序不同
- 常见于 Android Camera HAL
[6] NV12 (Y/CbCr 4:2:0)
- 半平面格式,Y 在 plane0,交错的 CbCr 在 plane1
- 色度采样为 4:2:0(水平、垂直都减半)
- 注意:此处 NV12 是多平面版本(
V4L2_PIX_FMT_NV12M
),并非单平面 NV12 - 应用需用
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
来访问
[7] NM21 (Y/CrCb 4:2:0 (N-C))
- NV21 的 Non-Contiguous(非连续内存)版本
- 在某些 ISP 分配策略下更易优化内存带宽
[8] NM12 (Y/CbCr 4:2:0 (N-C))
- NV12 的 Non-Contiguous 版本
- 两个 plane 分离且不连续存储
[9] YU12 (Planar YUV 4:2:0)
- Y、U、V 三个 plane
- 经典的 I420 格式,用于编解码标准中(如 H.264 / VP8)
[10] YM24 (Planar YUV 4:4:4 (N-C))
- 每像素都有完整的 Y、U、V 信息
- 不做色度采样压缩,色彩信息最完整,带宽需求也最高
- Non-Contiguous 存储方式
3. 单平面 vs 多平面 NV12
- 单平面 NV12:亮度 + 色度交错的两个 plane 在一个缓冲区里
- 多平面 NV12:亮度 plane0 和色度 plane1 分成两个缓冲区独立管理
- 在 V4L2 API 调用上,单平面用
VIDIOC_REQBUFS
时type = V4L2_BUF_TYPE_VIDEO_CAPTURE
多平面则用V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
并处理struct v4l2_plane
4. 应用开发注意事项
- 必须匹配驱动输出的采集类型
- 多平面格式必须用
VIDEO_CAPTURE_MPLANE
- 多平面格式必须用
- 色度顺序敏感
- NV12 与 NV21 的 UV 分量顺序不同,颜色会偏差
- Non-Contiguous 内存
- 某些应用假设 plane 在内存中连续,这在 N-C 格式中不成立
- RK3568 MIPI 摄像头驱动暴露的是 多平面格式集合,包括 NV12M、NM12、NV21M、NM21 等
- GStreamer 等现代多媒体框架可透明适配多平面格式
- 旧版 V4L2 应用若只支持单平面 NV12,会报“不支持”
- 要在应用中使用这些格式,需要根据实际驱动类型调整缓冲区申请和数据解析逻辑
NV12 内存布局对比图
============================================================
NV12 单平面格式 (V4L2_PIX_FMT_NV12, Video Capture 单平面)
============================================================[Plane0+Plane1 放在同一个连续 buffer 中]
------------------------------------------------------------
| Y0 | Y1 | Y2 | ... | Y(Width*Height -1) | --> 亮度(Y)数据
------------------------------------------------------------
| Cb0 | Cr0 | Cb1 | Cr1 | ... | Cb/Cr(Width*Height/2 -1) | --> 色度(CbCr交错)数据
------------------------------------------------------------
(总大小 = Y分量大小 + UV分量大小)特点:
- 一个缓冲区里顺序存储亮度和色度
- V4L2 应用用 struct v4l2_buffer,无 planes[]
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE============================================================
NV12 多平面格式 (V4L2_PIX_FMT_NV12M, Video Capture Multiplanar)
============================================================[Plane0 和 Plane1 分开存储在两个缓冲区/plane 中]
------------------------------------------------------------
Plane0: 亮度(Y)数据
| Y0 | Y1 | Y2 | ... | Y(Width*Height -1) |
------------------------------------------------------------Plane1: 色度(CbCr交错)数据
| Cb0 | Cr0 | Cb1 | Cr1 | ... | Cb/Cr(Width*Height/2 -1) |
------------------------------------------------------------特点:
- 多平面 API,每个 plane 独立分配内存
- V4L2 应用使用 struct v4l2_buffer 内 planes[] 数组访问
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
- plane[0].length = 宽 x 高
- plane[1].length = 宽 x 高 / 2
- 可以是 Contiguous(连续)或 N-C(非连续内存)
图形化的直观示意
单平面 NV12:
+----------------- 整个内存缓冲区 ------------------+
| Y 分量 (亮度) Width*Height 字节 |
+---------------------------------------------------+
| Cb / Cr 交错的色度分量 Width*Height/2 字节 |
+---------------------------------------------------+
多平面 NV12:
Plane 0 (亮度Y)
+--------------------+
| Y 数据 (W*H 字节) |
+--------------------+Plane 1 (色度UV交错)
+--------------------+
| Cb/Cr 数据 (W*H/2) |
+--------------------+
应用开发要点
- 单平面 →
V4L2_BUF_TYPE_VIDEO_CAPTURE
,数据一次性取出,解析时按大小拆分成 Y 和 UV 两段 - 多平面 →
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
,取两个 plane 分别处理 - 如果驱动只支持多平面 NV12,而应用只写了单平面 NV12 解析代码,就会不兼容 → 这正是你测试中应用报“不支持 NV12”的原因。
📌引用:
在 RK3568 + MIPI 摄像头的驱动实现中,由于硬件 ISP 输出采用多平面 NV12(NV12M),需要在应用端匹配使用
VIDEO_CAPTURE_MPLANE
类型,并通过struct v4l2_buffer
的 planes[] 分别读取 Y plane 和 UV plane。
如果应用只支持单平面 NV12,必须增加单平面兼容路径或在驱动端做格式转换,否则会出现“不支持 NV12”的提示。