一、SVC 到底是什么?
SVC,全称 Scalable Video Coding,可伸缩视频编码。说白了,就是一段视频流里,藏着多个“版本”的视频。
你想想看,传统编码(比如 AVC/H.264)是一锤子买卖——编码器输出一个码流,解码器要么全收,要么全丢。但 SVC 不一样,它把视频拆成一层基础层(Base Layer)和若干增强层(Enhancement Layer)。
基础层是最低质量的版本,能独立解码。增强层则依赖基础层,加上去之后,分辨率更高、帧率更流畅、画质更清晰。
我刚开始接触 SVC 时,总觉得这玩意儿有点“浪费带宽”。后来在项目中遇到一个真实场景:用户网络从 4G 掉到 3G,画面直接卡成幻灯片。换成 SVC 之后,服务器只需要丢弃增强层,基础层还能流畅播放。嗯,从那以后,我对 SVC 的看法彻底变了。
二、三种可伸缩维度
SVC 支持三个维度的伸缩,我习惯叫它们“三板斧”:
1. 时间可伸缩(Temporal Scalability)
控制帧率。比如基础层是 15fps,加上第一层增强层到 30fps,再加一层到 60fps。
实现方式是通过预测结构——基础层用 I/P 帧,增强层用 B 帧。丢掉 B 帧,帧率就降下来了。
我在项目中遇到过一个问题:用户反馈视频“一卡一卡的”,排查后发现是时间层切得太狠,直接从 60fps 掉到 7.5fps。后来我建议限制最低帧率不低于 15fps,体验就好多了。
2. 空间可伸缩(Spatial Scalability)
控制分辨率。基础层是 360p,增强层可以到 720p,再往上到 1080p。
编码时,增强层会参考基础层重建后的图像做预测,这样能省不少码率。解码时,如果只收基础层,就输出低分辨率画面。
3. 质量可伸缩(Quality Scalability)
也叫 SNR 可伸缩。控制画质(PSNR/码率)。基础层用较粗的量化步长,增强层用更细的量化步长来补偿残差。
说白了,基础层画面有点“糊”,加上增强层之后,细节就出来了。网络差时只传基础层,虽然糊但能看;网络好时全传,画面清晰。
| 维度 | 控制对象 | 典型分层 | 我常用的场景 |
|---|---|---|---|
| 时间 | 帧率 | 15/30/60 fps | 屏幕共享、低运动场景 |
| 空间 | 分辨率 | 360p/720p/1080p | 多人会议、大屏显示 |
| 质量 | 画质/码率 | 200kbps/500kbps/1Mbps | 弱网环境、移动端 |
三、WebRTC 对 SVC 的支持
WebRTC 原生支持 SVC,但有个前提——你得用 VP9 编码器。H.264 的 SVC 扩展(Annex G)虽然标准上有,但浏览器基本没实现。
具体来说,WebRTC 通过 RTCRtpSender.setParameters() 来配置 SVC 的层级。核心参数是 scalabilityMode。
// 配置 VP9 SVC:时间 3 层 + 空间 2 层
const sender = pc.getSenders()[0];
const params = sender.getParameters();
params.encodings = [{
scalabilityMode: 'L3T3',
// L3 = 3 个空间层,T3 = 3 个时间层
}];
await sender.setParameters(params);
常见的 scalabilityMode 取值:
'L1T2':1 个空间层,2 个时间层(15/30fps)'L1T3':1 个空间层,3 个时间层(7.5/15/30fps)'L2T2':2 个空间层(360p/720p),2 个时间层'L3T3':3 个空间层,3 个时间层(全功能)
四、SVC 在 QoS 中的应用
QoS(服务质量)说白了就是:在网络波动时,如何让用户感觉不到卡顿。SVC 在这里扮演了关键角色。
4.1 自适应码率(ABR)
传统 ABR 是编码器重新编码,切换码率。但重新编码有延迟,而且画面会“闪一下”。
用 SVC 之后,服务器或 SFU 只需要决定“丢哪些包”。比如网络变差,SFU 直接丢弃增强层的数据包,只转发基础层。这个过程是零延迟的,画面也不会闪。
我做过一个对比测试:传统 ABR 切换码率需要 500ms-1s,而 SVC 丢层只需要一个 RTT(约 50-100ms)。用户体验差距非常明显。
4.2 接收端决策
WebRTC 的接收端可以通过 RTCRtpReceiver.getParameters() 查看当前收到的 SVC 层级。如果发现丢包率上升,可以主动请求发送端降低层级。
// 接收端检测到丢包,请求降级
const receiver = pc.getReceivers()[0];
const stats = await receiver.getStats();
let packetLoss = 0;
stats.forEach(stat => {
if (stat.type === 'inbound-rtp') {
packetLoss = stat.packetsLost / stat.packetsReceived;
}
});
if (packetLoss > 0.05) { // 丢包率超过 5%
// 通过 RTCP 反馈或信令,通知发送端降低 SVC 层级
sendDowngradeRequest('L1T2'); // 降到 2 层时间
}
4.3 SFU 的智能转发
在多人会议中,SFU(选择性转发单元)可以利用 SVC 做“按需转发”。
比如一个 4 人会议,当前发言人的画面用全质量(L3T3),其他 3 人用低质量(L1T2)。这样总带宽只有全质量方案的 40% 左右。
我记得有一次做 50 人大课堂,如果不做 SVC 分层,服务器带宽直接打满。用了 SVC 之后,服务器只转发基础层给非活跃用户,带宽节省了 70% 以上。
五、SVC 的局限性
说了这么多好处,也得泼点冷水。SVC 不是银弹。
- 编码开销:VP9 SVC 的编码复杂度比 VP8 高 2-3 倍。低端 CPU 上编码会卡顿。
- 码率冗余:SVC 的总码率比同等质量的单层编码高 10%-20%。因为增强层需要额外信息。
- 浏览器支持:目前只有 Chrome/Edge 支持 VP9 SVC,Safari 和 Firefox 还在观望。
六、一张图看懂 SVC 原理
下面这张 SVG 图,展示了 SVC 的三维可伸缩结构。你可以看到基础层在最底层,增强层一层层往上叠。
从这张图可以看得很清楚:基础层是“保底”的,增强层是“锦上添花”的。网络越差,丢的层越多,但画面不会断。
七、总结
SVC 是 WebRTC QoS 工具箱里的一把利器。它让视频流有了“弹性”,能根据网络状况自动伸缩。虽然编码开销和浏览器兼容性还有待改善,但在 Chrome 生态下,它已经是生产环境可用的成熟方案。
我个人习惯在项目中这样用:
- 移动端:只用时间可伸缩(L1T3),避免解码压力
- 桌面端:时间+质量可伸缩(L1T3 + 质量层)
- 大课/直播:空间+时间可伸缩(L2T2),配合 SFU 做按需转发
下一节我们会深入 Simulcast 方案,看看它和 SVC 的异同。但那是后话了,先把 SVC 吃透再说。