9、编解码器协商:RTCRtpCodecCapability、编解码器优先级排序、H264/VP8/VP9/AV1的SDP参数
编解码器协商,说白了就是通话双方在握手阶段互相喊话:
「我支持 H264,你支持啥?」
「我支持 VP8 和 VP9,但我更想用 VP9。」
「行,那就 VP9 吧。」
这个过程看似简单,但坑不少。我做过一个跨平台项目,Android 端默认只开了 H264,iOS 端只开了 VP8,结果两边互相等对方先开口,愣是协商了 5 秒才出画面。嗯,这就是编解码器没对齐的典型问题。
9.1 RTCRtpCodecCapability:浏览器能做什么
在 WebRTC 里,RTCRtpCodecCapability 描述的是「浏览器底层能力」。你可以通过 RTCRtpSender.getCapabilities('video') 拿到它。
举个例子,我在 Chrome 上跑了一下:
const caps = RTCRtpSender.getCapabilities('video');
console.log(caps.codecs);
返回的数组里,每个元素长这样:
{
mimeType: 'video/VP8',
clockRate: 90000,
channels: undefined,
sdpFmtpLine: undefined
}
这里要注意几点:
- mimeType:格式是
video/CODEC,比如video/H264、video/VP9。 - clockRate:视频编码器固定 90000,这是 RTP 时间戳的基准频率。
- sdpFmtpLine:这个字段很关键,它对应 SDP 里的
a=fmtp行。比如 H264 的 profile-level-id、packetization-mode 都在这里。
getCapabilities,看看浏览器到底支持哪些编码器。有一次发现某款国产浏览器居然不支持 VP9,排查了半天才发现是浏览器阉割了。
9.2 编解码器优先级排序:谁先谁后
协商时,Offer 方会把自己支持的编码器按优先级排好序。优先级高的写在 SDP 前面。
排序逻辑一般是:
- 带宽效率:同等画质下,码率越低越优先。AV1 > VP9 > H264 > VP8。
- 硬件支持:如果设备有硬件编码器,优先用硬件编码。
- 兼容性:有些老设备只支持 H264,那就得把 H264 往前放。
我做过一个视频会议项目,默认排序是 VP9 > H264 > VP8。结果发现 VP9 在低端手机上编码延迟太高,画面卡得不行。后来改成 H264 > VP9 > VP8,体验反而好了。你想想看,优先级不是越高越好,得看场景。
9.3 H264 的 SDP 参数:profile-level-id 和 packetization-mode
H264 的 SDP 参数最复杂,因为它的配置项多。典型的 a=fmtp 行长这样:
a=fmtp:96 profile-level-id=42e01f;packetization-mode=1
我来拆解一下:
- profile-level-id:6 位十六进制数,前两位是 profile,中间两位是约束,后两位是 level。比如
42e01f表示 Baseline profile、level 3.1。 - packetization-mode:0 表示单 NALU 模式,1 表示非交错模式(常用),2 表示交错模式(很少用)。
我曾经踩过一个坑:两个浏览器都支持 H264,但一个设了 packetization-mode=1,另一个没设。结果协商失败,画面一直黑屏。后来我强制在 Offer 里加上 packetization-mode=1,问题解决。
42e01f,Answer 方只能回复相同或更低的 profile/level。回复更高的会被拒绝。
9.4 VP8 的 SDP 参数:简单但别忽略
VP8 的 SDP 参数相对简单,a=fmtp 行通常只有:
a=fmtp:96 max-fr=30;max-fs=3600
- max-fr:最大帧率,单位是 1/256 帧每秒。30 表示 30fps。
- max-fs:最大帧大小,单位是宏块数。3600 对应 720p 左右。
嗯,这里要注意:VP8 的参数虽然少,但 max-fs 如果设得太小,高分辨率画面会被截断。我见过有人设成 1200,结果 720p 视频只显示了左上角一块。
9.5 VP9 的 SDP 参数:profile-id 和 scalability
VP9 比 VP8 多了 profile 的概念。SDP 里常见:
a=fmtp:96 profile-id=0
- profile-id:0 是基础版(8-bit 4:2:0),1 是 8-bit 4:2:2/4:4:4,2 是 10-bit 4:2:0,3 是 10-bit 4:2:2/4:4:4。
VP9 还支持 SVC(可伸缩编码),参数里会有 max-layers、max-temporal-layers 等。不过目前大多数 WebRTC 实现只用单层。
我个人建议:除非你明确需要 10-bit 色深,否则 VP9 用 profile-id=0 就够了。profile 越高,解码器要求越苛刻。
9.6 AV1 的 SDP 参数:新贵但参数少
AV1 是新生代编码器,SDP 参数目前很简单:
a=fmtp:96 profile=0;level=5;tier=0
- profile:0 是 Main profile,1 是 High profile。
- level:对应分辨率上限,level 5 支持 4K。
- tier:0 是 Main tier,1 是 High tier(更高码率)。
AV1 的编码复杂度高,目前硬件支持还不多。我在项目中试过软件 AV1 编码,CPU 直接飙到 90%。嗯,现阶段还是建议当备选。
9.7 核心知识图谱
下面这张图总结了编解码器协商的完整流程:
9.8 避坑指南
最后,分享几个我实际项目中遇到的坑:
- H264 的 profile 不匹配:Offer 方写
42e01f,Answer 方只支持42001f,协商失败。解决办法是 Offer 里多写几个 profile。 - VP8 的 max-fs 设太小:导致 1080p 画面被裁剪。建议设成 8192 以上。
- AV1 的 level 设太高:老设备解码器不支持 level 5,降级到 level 3 就好了。
- 编码器顺序写反:把 VP8 写在 H264 前面,结果低端设备被迫用 VP8 软件编码,CPU 爆炸。
公众号:蓝海资料掘金营,微信deep3321