一、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。

编码时,增强层会参考基础层重建后的图像做预测,这样能省不少码率。解码时,如果只收基础层,就输出低分辨率画面。

避坑指南:空间可伸缩的编码复杂度较高,移动端设备解码时容易发热。我曾经在 Android 低端机上测试,解码 720p 的 SVC 流,CPU 占用直接飙到 80%。建议在移动端只启用时间+质量可伸缩。

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 个时间层(全功能)
注意:不是所有浏览器都支持所有模式。Chrome 目前只支持 L1T2 和 L1T3,L2T2 以上需要开启实验性标志。我建议在生产环境中先用 L1T3,兼容性最好。

四、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 还在观望。
我的建议:如果目标用户 80% 以上是 Chrome,大胆用 SVC。如果 Safari 用户多,还是老老实实用 Simulcast( simulcast 是另一种多流方案,后面章节会讲)。

六、一张图看懂 SVC 原理

下面这张 SVG 图,展示了 SVC 的三维可伸缩结构。你可以看到基础层在最底层,增强层一层层往上叠。

SVC 三维可伸缩结构 基础层 (Base Layer) - 360p / 15fps / 低质量 增强层 1 (Enhancement Layer 1) - 720p / 30fps / 中等质量 增强层 2 (Enhancement Layer 2) - 1080p / 60fps / 高质量 质量 时间/空间 时间可伸缩 空间可伸缩 质量可伸缩 网络差 → 只传基础层 网络中等 → 基础层 + 增强层1 网络好 → 全传

从这张图可以看得很清楚:基础层是“保底”的,增强层是“锦上添花”的。网络越差,丢的层越多,但画面不会断。

七、总结

SVC 是 WebRTC QoS 工具箱里的一把利器。它让视频流有了“弹性”,能根据网络状况自动伸缩。虽然编码开销和浏览器兼容性还有待改善,但在 Chrome 生态下,它已经是生产环境可用的成熟方案。

我个人习惯在项目中这样用:

  • 移动端:只用时间可伸缩(L1T3),避免解码压力
  • 桌面端:时间+质量可伸缩(L1T3 + 质量层)
  • 大课/直播:空间+时间可伸缩(L2T2),配合 SFU 做按需转发

下一节我们会深入 Simulcast 方案,看看它和 SVC 的异同。但那是后话了,先把 SVC 吃透再说。


公众号:蓝海资料掘金营,微信deep3321