RK3399硬件支持V4L2编码器需确认内核启用CONFIG_VIDEO_ROCKCHIP_VPU、生成/dev/videoX(如video10)且capabilities含V4L2_CAP_VIDEO_ENCODER;输入须为NV12/YUV420对齐格式,输出为H.264,控制参数需通过VIDIOC_S_CTRL设置标准MPEG控件,严格遵循M2M双平面buffer管理流程。

确认硬件是否真正支持 V4L2 的编码器设备节点
很多嵌入式平台(如 Rockchip RK3399、NXP i.MX8MQ、Allwinner H6)虽然标称“支持 H.264 编码”,但实际需检查内核是否启用了对应 V4L2 encoder 驱动,并生成了 /dev/videoX 类型为 V4L2_CAP_VIDEO_M2M_MPLANE 或 V4L2_CAP_VIDEO_ENCODER 的设备。仅靠 /dev/video0(通常是摄像头输入)无法做编码。
实操建议:
- 运行
v4l2-ctl --list-devices,找带 “encoder”、“codec” 或 “vpu” 字样的设备,例如:rk-vpu-enc (platform: ff9a0000.rkvenc): [/dev/video10] - 用
v4l2-ctl -d /dev/video10 --all确认其Capabilities包含Video Encoder,且Device Caps显示0x04200002(即含V4L2_CAP_VIDEO_ENCODER) - 检查内核配置:必须启用
CONFIG_VIDEO_ROCKCHIP_VPU(RK)、CONFIG_VIDEO_IMX_MEDIA(i.MX)等,且未禁用CONFIG_V4L2_MEM2MEM_DEV - 常见错误现象:打开
/dev/video10成功,但ioctl(fd, VIDIOC_G_FMT, &fmt)返回EINVAL—— 很可能是驱动未正确绑定或格式不支持
设置正确的 capture/output plane 格式与 buffer 类型
V4L2 编码器是 memory-to-memory(M2M)设备,必须同时配置 output plane(原始 YUV 输入)和 capture plane(H.264 bitstream 输出),二者格式不能随意匹配。硬编码器对输入格式极其敏感,比如 RK3399 的 rkvenc 仅接受 V4L2_PIX_FMT_NV12 或 V4L2_PIX_FMT_YUV420,且 stride 对齐要求严格(如 128 字节边界)。
实操建议:
- output plane(输入)设为
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,使用V4L2_PIX_FMT_NV12;capture plane(输出)设为V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,使用V4L2_PIX_FMT_H264 - 调用
VIDIOC_S_FMT前,先用VIDIOC_TRY_FMT测试,尤其注意fmt.fmt.pix_mp.plane_fmt[0].sizeimage和stride是否被驱动修正 —— 硬件常会放大 width/height 到对齐值(如 64×32) - 务必使用
V4L2_MEMORY_MMAP(不推荐 USERPTR),因为多数嵌入式 VPU 驱动只实现 mmap 接口;分配 buffer 时按plane_fmt[i].sizeimage而非原始分辨率粗略计算 - 若出现编码帧全黑或解码失败,大概率是 YUV 数据未按驱动要求的 stride 填充(例如每行末尾缺 padding),可用
ffmpeg -f v4l2 -i /dev/video10 -vframes 1 test.h264快速验证设备输出是否有效
控制编码参数需通过 V4L2_CID_MPEG_* 控制 ID,而非自定义结构体
硬件编码器不接受用户传入 x264_param_t 或类似结构,所有码率、GOP、profile、level 等必须通过 VIDIOC_S_CTRL 设置标准 V4L2 control ID。不同 SoC 支持的 control 子集差异大:i.MX8MQ 支持 V4L2_CID_MPEG_VIDEO_BITRATE_MODE,而 RK3399 还需额外设 V4L2_CID_MPEG_VIDEO_ROCKCHIP_GOP 才能生效 GOP。
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
实操建议:
- 先用
v4l2-ctl -d /dev/video10 --list-ctrls-mpeg查看实际支持的 control 列表;缺失关键项(如 bitrate)说明驱动版本过旧或未启用对应功能 - 必须设置的最小集合通常包括:
V4L2_CID_MPEG_VIDEO_BITRATE、V4L2_CID_MPEG_VIDEO_BITRATE_PEAK、V4L2_CID_MPEG_VIDEO_GOP_SIZE、V4L2_CID_MPEG_VIDEO_H264_PROFILE(设为V4L2_MPEG_VIDEO_H264_PROFILE_MAIN)、V4L2_CID_MPEG_VIDEO_H264_LEVEL - 注意 control 值范围:例如
V4L2_CID_MPEG_VIDEO_BITRATE单位是 bit/s(不是 kbit/s),设 2000000 表示 2 Mbps;设超限会静默失败或触发EINVAL - 某些平台(如 Allwinner)需在 streamon 前一次性设完所有 control,中途修改部分参数可能不生效甚至导致设备 hang 住
同步模型必须严格遵循 M2M 的 request/requeue 流程,避免 buffer 混乱
硬编码器内部有独立 DMA 引擎,output/capture plane 的 buffer 生命周期完全由驱动管理。用户不能自行 memcpy 后立刻 qbuf,也不能在 capture plane 尚未 DQBUF 出数据时反复 QBUF output plane —— 这会导致硬件 FIFO 溢出、丢帧或 kernel panic。
实操建议:
- 典型流程是:output plane
qbuf→ capture planeqbuf→poll()等待POLLIN | POLLOUT→ 分别dqbuf两个 plane → 处理 H.264 数据 → 再次qbuf回去 - 务必检查
struct v4l2_buffer中的index和bytesused:capture plane 的bytesused是真实编码长度,可能远小于length;output plane 的bytesused应等于整帧 YUV 大小,否则驱动可能拒绝编码 - 不要假设 buffer 顺序:即使只开 4 个 buffer,
dqbuf返回的 index 也可能是乱序;用数组索引管理 buffer,而非队列顺序 - 最容易被忽略的是 EOS(End of Stream)处理:发送空 buffer(
bytesused = 0)到 output plane 后,capture plane 会输出剩余 SPS/PPS/SEI,此时必须继续dqbuf直到返回EAGAIN,否则残留 bitstream 丢失
驱动对齐要求、control 支持度、buffer 生命周期这三处,任一没踩准都会让编码器静默失败 —— 错误往往不报 errno,只表现为无输出或卡死。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










