10、视频编解码:H264与VP8/VP9编码器选择、硬件编码与软件编码、编解码参数配置
视频编解码这块,说实在的,是WebRTC视频会议App里最核心也最头疼的部分。我做了这么多年Android开发,每次遇到编解码问题,都得折腾好一阵子。今天咱们就把这块彻底聊透。
10.1 编码器三兄弟:H264、VP8、VP9
WebRTC默认支持三种视频编码器:H264、VP8和VP9。你可能会问,为什么要有这么多?其实每个都有它的脾气。
| 编码器 | 专利情况 | 压缩效率 | 硬件支持 | 适用场景 |
|---|---|---|---|---|
| H264 | 需专利授权 | 中等 | 几乎所有设备 | 通用兼容 |
| VP8 | 开源免费 | 略低于H264 | 部分设备 | WebRTC默认 |
| VP9 | 开源免费 | 比H264高30% | 较新设备 | 高画质低码率 |
H264 是行业老大哥。几乎所有Android手机都有硬件编码器支持。我在项目中遇到过一个问题:某款华为手机用VP8编码时发热严重,换成H264立马正常。这就是硬件加速的威力。
VP8 是WebRTC的亲儿子。当年Google推WebRTC时,为了避开H264的专利坑,搞了VP8。说实话,VP8的压缩效率比H264差那么一丢丢,但胜在免费。如果你做的是纯WebRTC通信,VP8是最稳妥的选择。
VP9 是后起之秀。压缩效率比H264高30%左右,同样的画质,码率更低。但问题是,硬件支持不够广。我记得2019年做的一个项目,在小米8上跑VP9硬编,结果直接崩溃——因为那款芯片不支持VP9硬件编码。
我的建议:
- 兼容性优先 → 选H264
- 开源项目 → 选VP8
- 追求画质且目标设备较新 → 选VP9
10.2 硬件编码 vs 软件编码
这个选择题,说白了就是「用专用芯片」还是「用CPU硬算」的区别。
硬件编码:手机里有专门的视频编码芯片。它干这活又快又省电。我测试过,硬件编码的功耗只有软件编码的1/5左右。但缺点也很明显——灵活性差,参数可调范围小。
软件编码:完全靠CPU计算。好处是灵活,你想怎么调参数都行。坏处是——发热、耗电、卡顿。我曾经在小米6上测试软件编码720P视频,5分钟后手机烫得能煎鸡蛋。
实战经验:
在Android平台上,我建议优先使用硬件编码。只有当硬件编码不支持你需要的参数时,才回退到软件编码。比如你要编码4K视频,但硬件不支持,那就只能软件编码了。
怎么判断设备是否支持硬件编码?用MediaCodec的CodecCapabilities来查:
// 检查是否支持H264硬件编码
MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
for (MediaCodecInfo codecInfo : codecList.getCodecInfos()) {
if (codecInfo.isEncoder() &&
codecInfo.getName().contains("h264") &&
!codecInfo.getName().contains("sw")) {
// 找到硬件编码器
Log.d("Codec", "硬件编码器: " + codecInfo.getName());
}
}
注意看那个 !codecInfo.getName().contains("sw") 的判断。软件编码器的名字里通常带「sw」或「software」字样,硬件编码器带「hw」或「omx」。
我曾经踩过的坑:
有些设备上,MediaCodecList会返回多个同名编码器。比如「OMX.google.h264.encoder」和「OMX.qcom.video.encoder.avc」。前者是软件编码,后者是高通硬件编码。一定要选对!
10.3 编解码参数配置
参数配置这块,我见过太多人乱调了。其实核心参数就那么几个,调好了视频质量蹭蹭往上涨。
10.3.1 关键参数一览
| 参数 | 说明 | 推荐值 |
|---|---|---|
| 比特率 | 每秒传输的数据量 | 500-2000 kbps |
| 帧率 | 每秒显示的帧数 | 15-30 fps |
| 分辨率 | 视频的宽高 | 640x480 或 1280x720 |
| I帧间隔 | 关键帧出现的频率 | 2-5秒 |
| 码率控制模式 | CBR/VBR/CRF | CBR(视频会议) |
比特率 是最重要的参数。设得太低,画面糊成马赛克;设得太高,网络扛不住。视频会议场景,720P视频我一般设1500kbps左右。
帧率 不是越高越好。30fps已经够流畅了,再高只会浪费带宽。而且帧率越高,编码压力越大,手机发热越严重。
I帧间隔 这个参数容易被忽略。I帧是关键帧,解码时必须从I帧开始。如果I帧间隔太长,加入会议的人要等好几秒才能看到画面。我一般设2秒一个I帧。
10.3.2 代码配置示例
在WebRTC中配置编码参数,通常通过PeerConnection的RtpParameters来实现:
// 创建视频编码配置
VideoEncoderConfig config = new VideoEncoderConfig();
config.codecName = "H264";
config.initialBitrate = 1500; // kbps
config.maxBitrate = 2000;
config.minBitrate = 500;
config.maxFramerate = 30;
// 设置到PeerConnection
RtpParameters parameters = new RtpParameters();
parameters.encoders = new ArrayList<>();
parameters.encoders.add(config);
// 应用配置
peerConnection.setVideoEncoderConfig(config);
如果是直接操作MediaCodec,配置会更细一些:
MediaFormat format = MediaFormat.createVideoFormat("video/avc", 1280, 720);
format.setInteger(MediaFormat.KEY_BIT_RATE, 1500000); // 1.5 Mbps
format.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2); // 2秒一个I帧
format.setInteger(MediaFormat.KEY_BITRATE_MODE,
MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR);
// 配置编码器
MediaCodec encoder = MediaCodec.createEncoderByType("video/avc");
encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
小技巧:
码率控制模式选CBR(恒定比特率)还是VBR(可变比特率)?视频会议场景我强烈推荐CBR。因为VBR在画面静止时码率很低,但画面一运动码率飙升,容易导致网络抖动。CBR虽然牺牲了一点画质,但网络更稳定。
10.4 编码器选择流程图
下面这张图是我自己总结的编码器选择逻辑,每次做项目都拿出来看看:
这张图的核心逻辑是:先检测硬件编码支持情况,再根据需求选编码器。如果硬件不支持,就回退到软件编码。嗯,这里要注意,软件编码首选VP8,因为它是WebRTC原生支持的。
10.5 避坑指南
最后分享几个我踩过的坑,希望能帮你少走弯路:
- 编码器名字别写错:H264的MIME类型是"video/avc",不是"video/h264"。我见过有人写错,结果MediaCodec创建失败。
- I帧间隔别设太大:我曾经设了10秒,结果用户加入会议后要等10秒才能看到画面,直接被投诉。
- 码率别设太低:720P视频码率低于800kbps,画面就会明显模糊。我一般不低于1000kbps。
- 别忘了检测编码器能力:有些设备虽然支持H264,但不支持1080P编码。一定要用CodecCapabilities检测。
我曾经犯过的错:
有一次在三星S8上测试,硬件编码H264 1080P 30fps,结果画面每隔几秒就卡一下。查了半天,发现是码率设了3000kbps,但S8的硬件编码器最大只支持2000kbps。后来用CodecCapabilities查了一下,乖乖设回2000kbps,问题解决。
编解码这块,说白了就是「硬件优先,软件兜底,参数调优」。你只要记住这个原则,大部分问题都能搞定。
公众号:蓝海资料掘金营,微信deep3321