译文说明
本文由 Hy4 preview 机器翻译自韩文原文,仅供参考。技术细节请以韩文原文为准。
卡顿为何发生在画面黑场区间之后
只要 VBR 编码的码率塌陷区间骗过了播放器的 ABR 判断,卡顿反而会出现在画面重新变亮之后。
先说观测到的现象
这是实际运营中的直播频道发生过的事。那是一场 4 小时的活动,按 CDN 边缘节点统计的最高带宽约为 824.47 Mbps。编码器、打包器、CDN、网络各方面都没有资源异常。但运营期间的监控指标中,却观测到只有卡顿曲线出现瞬时飙升的区间。
按顺序过了一遍检查清单,全部干净。
| 检查项 | 结果 |
|---|---|
| CDN 边缘节点 5xx、超时比例 | 无变化 |
| 源站 CPU、内存、带宽 | 余量充足 |
| 源站响应时间分布(p50 / p99) | 与平时一致 |
| 分片生成间隔、清单更新延迟 | 正常 |
| 网络区间丢包 | 无显著数值 |
| 编码器输入丢帧 | 无 |
注意:出现这种组合,就意味着分发链路没有问题。那么剩下的只有两处:内容本身,以及播放器的判断逻辑。
把时间轴叠在一起看
我把打包器输出的编码质量按时间轴提取出来,与原始视频并排放在一起。
关键有两点。
- VBR 输出码率先急剧下降,随后又急剧上升。
- 码率偏低的约 7 秒区间,与原始视频约 8 秒的黑场区间完全重合。
而且卡顿尖峰并非出现在码率下降时,而是出现在码率重新回升之后。正是这个时间差揭示了该现象的本质。
VBR 的正常行为如何变成陷阱
VBR 会根据画面复杂度分配不同的比特。画面运动多、细节多时就多用比特,画面静止或偏暗时就少用。黑场区间对编码器而言是最容易压缩的画面,因为 residual 几乎没有。于是码率会跌到谷底。
这不是缺陷,恰恰是 VBR 正常工作的证据。问题在于这一现象会在 ABR 阶梯的所有层级上同时发生。
| rendition | 目标码率 | 运动区间实测 | 黑场区间实测(估算) |
|---|---|---|---|
| 1080p | 8 Mbps | 约 8 Mbps | 1 Mbps 以下 |
| 720p | 4 Mbps | 约 4 Mbps | 1 Mbps 以下 |
| 480p | 2 Mbps | 约 2 Mbps | 1 Mbps 以下 |
| 360p | 1 Mbps | 约 1 Mbps | 1 Mbps 以下 |
参考:在黑场区间,所有画质等级的实际码率会挤到一起。如果 1080p 和 360p 都在 1 Mbps 以下,那么那一刻的阶梯就不是台阶,而是一块平地。
播放器侧的行为
ABR 逻辑大致是这样工作的。
추정 대역폭 = 방금 받은 세그먼트 크기(bit) / 다운로드에 걸린 시간(s)
if (추정 대역폭 > 상위 rendition 선언 비트레이트 x safety factor) {
상위 rendition으로 전환
}这里漏掉了一个事实:作为分子的分片大小会随内容复杂度变化。我们以一个带宽为 1 Mbps 的用户为例来计算。
[움직임 구간, 360p 시청 중]
세그먼트: 6초 x 1 Mbps = 약 0.75 MB
다운로드 시간: 0.75 MB / (1 Mbps) = 약 6초
추정 대역폭 = 1 Mbps -> 360p 유지, 정확한 판단
[암전 구간, 360p 시청 중]
세그먼트: 6초 x 0.3 Mbps = 약 0.22 MB (VBR이 비트를 덜 씀)
다운로드 시간: 0.22 MB / (1 Mbps) = 약 1.8초
추정 대역폭 = 6초 분량을 1.8초에 받았으니 약 3.3 Mbps로 계산됨
-> "네트워크가 좋아졌다" 판단
-> 720p 또는 1080p로 상향
[암전 종료, 1080p 시청 중]
세그먼트: 6초 x 8 Mbps = 약 6 MB
다운로드 시간: 6 MB / (1 Mbps) = 약 48초
6초 분량을 48초에 받는 중 => 버퍼 고갈 => 버퍼링 발생参考:用户的实际带宽从 1 Mbps 起一个字节都没变。但播放器却判断带宽变宽了 3 倍。根源不在网络,而在于这个估算式并不知道分子发生了抖动。
而且,由于「做出向上切换的决定」与「为此付出代价的时刻」之间存在时间差,卡顿总是出现在画面重新变亮之后。这正是只看指标去找原因发生时点、结果却挖错区间的原因。
那么编码侧要改什么
推荐的方向是转向 CBR 系。各选项对比如下。
| 方式 | 比特分配 | ABR 准确度 | 存储/传输效率 | 直播适配度 |
|---|---|---|---|---|
| VBR | 随复杂度自由波动 | 低(分子会抖动) | 最好 | 低 |
| capped VBR | 会波动但上限固定 | 中(下限仍会塌陷) | 好 | 中 |
| CBR | 把区间平均固定到目标值,不足则补 padding | 高 | 低(简单画面会浪费比特) | 高 |
静态画面上浪费的比特看似可惜,但在直播 ABR 中,「声明的码率与实际一致」这份保证,比节省带宽更有价值。阶梯各层级的实测码率互不重叠,正是 ABR 成立的前提条件。
注意:只改成 capped VBR 只能解决一半。制造问题的不是上限,而是下限塌陷。如果没有最小码率下限(min bitrate)或 padding,黑场区间里阶梯仍会变成平地。
播放器侧可以缓解的手段
有时无法改动编码,所以这里也整理了缓解手段。
- 估算带宽时不要只用单个分片,而是对多个分片取移动平均或调和平均。目的是让 7 秒级别的异常值无法推翻判断。
- 为向上切换增加缓冲区水位条件。即便估算带宽充足,只要缓冲区低于目标值就不升。
- 为向上切换设置冷却时间。下行立即、上行保守的非对称策略,在直播中几乎总是正确的。
- 除分片大小外,同时把清单声明的 BANDWIDTH 值作为向上判断标准的下限。只信实测数据的话,这次的案例就会原样踩中。
同一时间段一起响起的告警
顺带一提,这个区间里还有另外两类告警同时触发,但两者都属于正常行为。它们会干扰排查顺序,属于噪声,所以一并记在这里。
- 分片 404 激增:DASH MPD 的 SegmentTemplate 结构里,
$Time$值与 SegmentTimeline 的t字段相绑定。播放器按计算出的时间戳发起请求时,可能会提前请求尚未生成的时间戳,这时就会出现 404。而源站实际生成的分片请求全部以 200 记录在日志中。在 DASH 直播中,少量 404 属于正常范围。 - 403 激增:规模约为每分钟 150 次,全部来自不在 IP allowlist 中的来源。这是策略按预期生效的结果。
参考:3 个指标同时跳变,看起来像是同一个原因造成的,但实际上往往是 2 个无关的正常行为加 1 个真实问题。预先定义好每条告警的正常范围基线,是缩短故障响应时间最便宜的办法。
原理梳理
- VBR:码率随画面复杂度变化的编码方式。相对平均质量而言效率最高。
- CBR:把区间平均码率固定到目标值的编码方式。在简单画面上会浪费比特,但输出可预测。
- ABR:客户端依据观测到的下载性能选取 rendition 的方式。关键在于观测值是
세그먼트 크기 / 다운로드 시간。
压缩成一句话:ABR 测量的不是网络,而是「内容大小除以时间」。所以当内容大小因内容自身原因而抖动时,ABR 会误以为是网络发生了抖动。直播中使用 CBR 的理由不是画质一致性,而是为了不对 ABR 说谎。
小结
- 如果分发链路(CDN、源站、网络)全部正常、却只有卡顿指标跳变,就该去看内容特性和播放器的判断逻辑。
- 在原始视频约 8 秒的黑场区间里,VBR 输出码率发生了塌陷(约 7 秒),ABR 阶梯的所有层级都降到用户带宽 1 Mbps 以下,台阶变成了平地。
- 播放器把变短的下载时间误判为带宽改善,从而升到更高层级的 rendition;当画面重新变亮、1080p 恢复到 8 Mbps 的那一刻,缓冲区被耗尽。所以卡顿不出现在黑场区间,而出现在其紧随之后。
- 根本解决方法是转向 CBR。只用 capped VBR 只能管住上限,下限塌陷依然存在。
- 播放器侧的缓解办法包括:基于多分片平均的带宽估算、结合缓冲区水位条件、向上切换冷却、以及参考清单声明的码率。