1. 问题背景与现象分析
在RV1126B芯片平台上进行视频编码开发时,遇到了一个颇为棘手的帧率控制问题。这款芯片的编码能力上限为4K@45fps,换算成1080P分辨率时理论最大帧率约为180fps。我们当前的视频处理链路设计如下:
code复制VI(视频输入模块,1080P@120fps输出) → VENC(视频编码模块,分为VENC0和VENC1两个通道)
实际需求是:
- VENC0通道输出1080P@120fps
- VENC1通道输出1080P@30fps
但通过cat /proc/vcodec/enc/venc_info命令查看实际编码参数时,发现两个通道的输出帧率都被锁定在88fps左右,完全不符合预期。从调试信息可以看到:
bash复制--------venc chn attr 2----------
ID| VeStr| SrcFr| TarFr| Timeref| PixFmt|RealFps*10|rotation|mirror
0| y| 120| 120| 7d6cc75| YUV420SP| 882| 180| N
-------venc chn attr 2----------
ID| VeStr| SrcFr| TarFr| Timeref| PixFmt|RealFps*10|rotation|mirror
1| y| 30| 30| 7d6e4d7| YUV420SP| 882| 180| N
关键现象:无论设置目标帧率为120fps还是30fps,实际输出都是88fps(RealFps*10=882表示88.2fps)
2. 问题根因探究
2.1 芯片编码能力限制
RV1126B的编码器采用硬编码设计,其处理能力存在物理上限:
- 最大支持4K@45fps
- 换算为1080P分辨率时,理论最大帧率≈180fps(4K像素量是1080P的4倍)
这个限制意味着:
- 单路1080P编码最高可达180fps
- 多路编码时,总帧率不能超过180fps
2.2 VENC模块的工作机制
通过分析Rockchip的VENC驱动代码,发现其帧率控制存在以下特点:
- 输入帧率继承:VENC各通道的输入帧率默认继承自VI模块的输出帧率(120fps)
- 帧率控制层级:
- 第一级:全局编码能力限制(芯片级)
- 第二级:通道间帧率分配(驱动级)
- 第三级:单个通道的帧率控制(应用级)
2.3 问题本质
当两个VENC通道都直接从VI继承120fps输入时:
- 系统检测到总需求帧率=120+120=240fps > 180fps上限
- 驱动自动进行帧率均衡,将各通道输出限制在≈88fps
- 这种均衡行为导致设置的30fps目标完全失效
3. 解决方案与实现细节
3.1 关键配置修改
正确的配置方式应该是明确指定各通道的输入/输出帧率关系。对于需要降帧的VENC1通道,需要显式设置:
c复制stAttr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;
stAttr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 30; // 目标输出30fps
stAttr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;
stAttr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 120; // 输入帧率120fps
这种配置明确告知编码器:
- 输入帧率是120fps
- 需要做4:1的帧丢弃(120→30)
- 不参与全局帧率均衡计算
3.2 参数详解
| 参数名 | 类型 | 说明 |
|---|---|---|
| fr32DstFrameRateNum | uint32_t | 目标帧率的分子 |
| fr32DstFrameRateDen | uint32_t | 目标帧率的分母 |
| u32SrcFrameRateNum | uint32_t | 输入帧率的分子 |
| u32SrcFrameRateDen | uint32_t | 输入帧率的分母 |
注:实际帧率 = Num / Den。通常Den设为1,直接用Num表示帧率值。
3.3 配置生效原理
这种配置方式之所以有效,是因为:
- 驱动会根据u32SrcFrameRateNum值计算实际需要的处理能力
- VENC1通道的计算量=120fps(而非30fps)
- 系统总需求=120(VENC0) + 120(VENC1) = 240fps
- 虽然仍超限,但通过帧丢弃VENC1实际只输出30fps
- 最终实际处理量=120 + 30=150fps < 180fps上限
4. 完整实现示例
4.1 VENC通道初始化代码
c复制// VENC0通道配置(保持120fps)
VENC_CHN_ATTR_S stAttr0;
memset(&stAttr0, 0, sizeof(stAttr0));
stAttr0.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
stAttr0.stRcAttr.stH264Cbr.u32BitRate = 4000000; // 4Mbps
stAttr0.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;
stAttr0.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 120;
stAttr0.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;
stAttr0.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 120;
// VENC1通道配置(120fps输入→30fps输出)
VENC_CHN_ATTR_S stAttr1;
memset(&stAttr1, 0, sizeof(stAttr1));
stAttr1.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
stAttr1.stRcAttr.stH264Cbr.u32BitRate = 2000000; // 2Mbps
stAttr1.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;
stAttr1.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 30;
stAttr1.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;
stAttr1.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 120;
// 创建编码通道
RK_MPI_VENC_CreateChn(0, &stAttr0);
RK_MPI_VENC_CreateChn(1, &stAttr1);
4.2 绑定VI到VENC
c复制// VI配置(输出120fps)
VI_CHN_ATTR_S vi_attr;
memset(&vi_attr, 0, sizeof(vi_attr));
vi_attr.u32Width = 1920;
vi_attr.u32Height = 1080;
vi_attr.stFrameRate.f32DstFrameRate = 120;
vi_attr.stFrameRate.f32SrcFrameRate = 120;
// 创建VI通道
RK_MPI_VI_CreateChn(0, &vi_attr);
// 绑定VI到两个VENC通道
RK_MPI_SYS_Bind(RK_ID_VI, 0, RK_ID_VENC, 0);
RK_MPI_SYS_Bind(RK_ID_VI, 0, RK_ID_VENC, 1);
5. 调试技巧与注意事项
5.1 关键调试命令
-
实时查看编码状态:
bash复制cat /proc/vcodec/enc/venc_info -
查看VI帧率:
bash复制cat /proc/vi/vi_info -
查看系统负载:
bash复制cat /proc/loadavg
5.2 常见问题排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 实际帧率低于设置值 | 1. 芯片算力超限 2. 输入帧率不足 |
1. 检查总帧率需求 2. 确认VI输出帧率 |
| 画面卡顿 | 帧丢弃不均匀 | 调整stH264Cbr.u32Gop参数 |
| 编码延迟高 | 缓冲区设置不当 | 调整stH264Cbr.u32BufSize |
5.3 性能优化建议
-
合理分配码率:
- 高帧率通道分配更高码率(如VENC0给4Mbps)
- 低帧率通道可适当降低码率(如VENC1给2Mbps)
-
关键帧间隔:
c复制stAttr.stRcAttr.stH264Cbr.u32Gop = 120; // 建议设为帧率的整数倍 -
多通道优先级:
c复制stAttr.stVencAttr.u32Priority = 1; // 0-3,数值越高优先级越高
6. 经验总结
在RV1126B这类资源受限的平台上实现多路差异化帧率编码,需要特别注意以下几点:
-
显式声明输入帧率:即使做帧率转换,也要正确设置u32SrcFrameRateNum,让驱动准确计算负载
-
全局视野:计算所有通道的总帧率需求,确保不超过芯片能力上限
-
监控实际输出:通过/proc接口实时验证配置效果,避免仅依赖API返回值
-
动态调整:根据实际负载情况,可以运行时调整帧率和码率:
c复制
RK_MPI_VENC_SetRcParam(chn, &stRcParam);
这个案例也反映出,在嵌入式视频处理系统中,理解硬件限制和驱动行为往往比单纯调用API更重要。通过正确配置帧率转换参数,我们最终实现了VENC0@120fps和VENC1@30fps的稳定输出,满足了项目需求。