4. 目标码率测试:固定码率下编码输出实际码率与设定码率的偏差测量、误差容忍度
4.1 参数含义
目标码率 (target bitrate) 是 MediaCodec 编码器配置中通过 KEY_BIT_RATE 设置的期望输出码率,单位通常为 bps。固定码率 (Constant Bitrate, CBR) 模式下,编码器应尽量使输出流瞬时码率维持在目标值附近,实际码率与设定码率之间的偏差反映编码器的码率控制精度。
- 设定码率(Set Bitrate):应用层通过 MediaFormat 指定的值。
- 实际码率(Actual Bitrate):编码器输出码流在特定时间窗口内的平均比特率。
- 偏差率:
(实际码率 − 设定码率) / 设定码率 × 100%。 - 误差容忍度:工程上允许的偏差范围,通常为 ±5%~±15%。
4.2 测试条件
| 条件项 | 推荐值 / 说明 |
|---|---|
| 编码器 | MediaCodec 音视频编码器(如 AVC / HEVC / AAC) |
| 码率模式 | BITRATE_MODE_CBR(固定码率) |
| 输入源 | 静态测试序列(单色屏、渐变图、运动场景)至少 10 秒 |
| 帧率 | 30 fps / 60 fps,与编码配置一致 |
| 分辨率 | 720p / 1080p / 4K |
| 测试时长 | ≥ 30 秒(保证稳定窗口) |
| 芯片/平台 | 记录硬件型号与驱动版本 |
⚠ 提示:CBR 模式下,奇数次 GOP 边界可能因帧类型切换出现短时码率尖峰,测量窗口应避开前 2 秒。
4.3 仪器/工具配置
- 设备端:Android 手机/平板(API 21+)
- 抓取工具:
adb shell am start …+ 自定义测试 App 或命令行工具 - 码流分析:
ffprobe/BitrateViewer/Elecard StreamEye - 脚本语言:Python 3 +
subprocess自动化
# 使用 ffprobe 提取码流平均码率
ffprobe -v error -select_streams v:0 -show_entries stream=bit_rate \
-of default=noprint_wrappers=1 output.mp4
# 逐帧码率分析(基于文件大小)
ffprobe -v error -show_frames -select_streams v:0 -print_format json output.mp4 \
| python3 parse_frame_bitrate.py
4.4 测量步骤
- 配置 MediaCodec:设置
KEY_BIT_RATE、BITRATE_MODE_CBR、帧率、I 帧间隔等; - 编码并保存:将测试序列编码为 MP4 或 raw H.264/HEVC 文件;
- 提取实际码率:用
ffprobe或自定义解析工具读取码流总时长与文件大小,计算实际码率; - 记录瞬时波动:按帧或 GOP 粒度统计瞬时码率,绘制波动曲线;
- 重复多轮:至少 3 轮,取平均值。
4.5 数据判断 & 记录表格
| 设定码率 (kbps) | 实际码率 (kbps) | 偏差率 | 是否合格 (±10%) |
|---|---|---|---|
| 1000 | 985 | -1.5% | ✅ 通过 |
| 2000 | 2180 | +9.0% | ✅ 通过 |
| 4000 | 4480 | +12.0% | ❌ 超限 |
| 8000 | 7600 | -5.0% | ✅ 通过 |
关键指标:平均偏差率 ≤ ±10%,最大瞬时偏差 ≤ ±20%(1 秒滑动窗口)。
4.6 误差分析
导致偏差的主要原因:
- 码率控制算法精度:不同芯片厂商对 CBR 实现不同,高通/MTK/三星差异明显;
- 场景复杂度剧烈变化:黑白画面→运动纹理导致码率瞬间超调;
- GOP 结构:I 帧占比大时平均码率偏高;
- 帧填充策略:部分编码器在静帧时通过时域缩放填充浪费码率。
‼ 排除干扰:确认 MediaCodec 配置中未开启
BITRATE_MODE_VBR 或 BITRATE_MODE_CQ;检查 KEY_MAX_BIT_RATE 是否限制过高。
4.7 调参策略
- 微调目标码率:若实测偏低,小幅上调设定值(如 +5%);
- 缩小 I 帧间隔:降低
KEY_I_FRAME_INTERVAL可减少 I 帧比例波动; - 使用
KEY_QUALITY:部分编码器支持 Quality 级别微调码率控制; - 限制最大码率:设置
KEY_MAX_BIT_RATE ≈ 1.2 × KEY_BIT_RATE防止尖峰。
MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, height);
format.setInteger(MediaFormat.KEY_BIT_RATE, 2_000_000);
format.setInteger(MediaFormat.KEY_BITRATE_MODE, MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR);
format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2);
// 可选:设置最大码率略高于目标
format.setInteger(MediaFormat.KEY_MAX_BIT_RATE, 2_400_000);
4.8 验收阈值
| 场景 | 平均偏差 | 最大瞬时偏差(1s 窗口) | 标准 |
|---|---|---|---|
| 普通视频通话 | ≤ ±15% | ≤ ±25% | 可接受 |
| 直播推流 | ≤ ±10% | ≤ ±20% | 推荐 |
| 离线编码(文件存档) | ≤ ±5% | ≤ ±10% | 严格 |
💡 工程建议:在 App 内部集成一段 5 秒自检流程,编码完成后回调偏差检查,若超出阈值则弹窗提示或自动重试。