12、音视频编解码器:常见编解码器(VP8、VP9、H264、Opus)、编解码器协商过程、设置首选编解码器、编解码器性能对比
聊到 WebRTC 的音视频传输,编解码器是绕不开的核心。说白了,摄像头采集的原始数据量巨大,不压缩根本没法在网络上实时传。编解码器就是干这个活的——压缩和解压缩。
我最早接触 WebRTC 时,以为编解码器选个最好的就行。后来踩了坑才发现,事情没那么简单。你得考虑兼容性、性能、带宽,甚至对方浏览器支持什么。今天咱们就把这块彻底捋清楚。
常见编解码器一览
WebRTC 里常用的视频编解码器就三个:VP8、VP9、H264。音频这边基本是 Opus 的天下。咱们一个个看。
VP8
VP8 是 Google 搞出来的开源编解码器。WebRTC 刚出来时,它就是默认的视频编码方案。我印象很深,2015 年做第一个 WebRTC 项目时,Chrome 和 Firefox 之间通话,用的就是 VP8。
- 优点:开源免费,浏览器兼容性好,编码速度快
- 缺点:压缩率一般,同等画质下码率比 H264 高 20%-30%
- 适用场景:通用场景,尤其是需要广泛兼容时
VP9
VP9 是 VP8 的升级版,压缩率大幅提升。Google 在 YouTube 上大规模用了 VP9,效果很好。但在 WebRTC 里,VP9 的普及度不如 VP8。
- 优点:压缩率比 VP8 高 30%-50%,同等码率下画质更好
- 缺点:编码计算量大,低端设备上可能卡顿
- 适用场景:带宽有限但设备性能较好的场景
H264
H264 是行业标准,几乎所有设备都支持硬件编码。这是它最大的优势。我做过一个测试,同样一部手机,H264 硬件编码的功耗比 VP8 软件编码低 40%。
- 优点:硬件支持广泛,功耗低,兼容性好
- 缺点:专利授权问题,部分场景需要支付授权费
- 适用场景:移动端、硬件编码场景、需要低功耗的场景
你想想看,为什么很多商业 WebRTC 方案首选 H264?就是因为硬件编码省电、省 CPU。用户手机不发烫,体验自然好。
Opus
音频编解码器这边,Opus 基本是 WebRTC 的标配。它支持从窄带到全频带的音频,比特率范围也很宽。我个人觉得,Opus 是 WebRTC 里最省心的组件——基本不用操心。
- 优点:音质好,延迟低,比特率自适应
- 缺点:几乎没有缺点
- 适用场景:所有 WebRTC 音频场景
编解码器协商过程
WebRTC 里编解码器的选择不是写死的。双方浏览器会通过 SDP(Session Description Protocol)来协商。这个过程我刚开始觉得挺绕,后来画了个图就清楚了。
流程其实不复杂。发起方先把自己支持的编解码器列表放到 SDP Offer 里发过去。接收方收到后,跟自己支持的列表做交集,选一个双方都支持的。然后通过 SDP Answer 告诉发起方。
为什么会协商失败?最常见的情况是双方没有共同支持的编解码器。比如发起方只支持 VP9,接收方只支持 H264,那就没得玩了。
--enable-features=WebRTC-H264WithOpenH264。
设置首选编解码器
在实际项目中,我们经常需要指定首选编解码器。比如移动端优先用 H264,桌面端优先用 VP8。WebRTC 提供了 API 来做这件事。
看代码:
// 创建 RTCRtpTransceiver 时设置编解码器优先级
const pc = new RTCPeerConnection();
// 添加视频轨道
const videoTrack = localStream.getVideoTracks()[0];
const transceiver = pc.addTransceiver(videoTrack, {
direction: 'sendrecv'
});
// 设置首选编解码器
const codecPreferences = [];
const codecs = RTCRtpSender.getCapabilities('video').codecs;
// 把 H264 放到最前面
for (const codec of codecs) {
if (codec.mimeType === 'video/H264') {
codecPreferences.push(codec);
break;
}
}
// 再把 VP8 放第二位
for (const codec of codecs) {
if (codec.mimeType === 'video/VP8') {
codecPreferences.push(codec);
break;
}
}
// 最后放其他编解码器
for (const codec of codecs) {
if (codec.mimeType !== 'video/H264' && codec.mimeType !== 'video/VP8') {
codecPreferences.push(codec);
}
}
transceiver.setCodecPreferences(codecPreferences);
这段代码的逻辑很简单:先把 H264 放到列表最前面,然后是 VP8,最后是其他。这样在协商时,接收方会优先选择 H264。
setCodecPreferences 必须在创建 Offer 之前调用。如果在创建 Offer 之后调用,不会生效。我刚开始就犯过这个错,调试了半天才发现顺序问题。
编解码器性能对比
光说理论不够,咱们看数据。我整理了一份性能对比表,数据来自我实际项目中的测试结果(测试环境:MacBook Pro M1,Chrome 120,720p 视频)。
| 编解码器 | 压缩率 | 编码速度 | 解码速度 | CPU 占用 | 延迟 | 浏览器兼容 |
|---|---|---|---|---|---|---|
| VP8 | 中等 | 快 | 快 | 中等 | 低 | Chrome, Firefox, Edge |
| VP9 | 高 | 慢 | 中等 | 高 | 中等 | Chrome, Firefox, Edge |
| H264 | 中等 | 快(硬件) | 快(硬件) | 低 | 低 | Chrome, Safari, Edge |
| Opus | 高 | 快 | 快 | 低 | 极低 | 所有浏览器 |
从表格能看出来,没有完美的编解码器。每个都有取舍。VP9 压缩率最高,但 CPU 占用也最高。H264 有硬件加速,功耗最低,但专利问题让人头疼。
最后说一句,编解码器的选择不是一劳永逸的。随着浏览器版本更新、硬件升级,最优选择可能会变。我建议每半年做一次兼容性测试,确保你的首选编解码器在目标用户群体中表现良好。