VOD 深度剖析(六):自适应码率——播放器如何自动切换清晰度
深入解析 ABR 的底层原理:基于吞吐量、基于缓冲区(BBA)、BOLA、MPC 以及 Pensieve 算法。并给出码率阶梯与短视频场景的实用工程建议。
本文是 VOD 流媒体深度剖析 系列的第六篇。
为什么 ABR 很重要
想象一下你在地铁里追剧,网络在 4G、弱 4G 和 5G 之间反复波动:
- 如果 App 锁定在 1080p → 每次信号变弱都会卡顿、转圈缓冲。
- 如果 App 锁定在 360p → 即便有 5G 可用,画面依然模糊不清。
理想状态是:App 根据网络状况自动调整清晰度,让你观看时不被打断。这就是 ABR(自适应码率,Adaptive Bitrate)。
ABR 决策循环
After downloading each segment, the player asks itself:
┌──────────────────────────┐
│ How fast did the last │
│ segment download? │
│ How much buffer remains? │
│ What's my bandwidth │
│ estimate? │
│ Can the device handle │
│ the current tier? │
└──────────────────────────┘
│
▼
┌──────────┐
│ Pick next │
│ tier │
└──────────┘
│
▼
Download next segment
这个循环每 1–4 秒运行一次(在每个分片下载完成后触发)。
关键信号:近期吞吐量、缓冲区水位(已预下载内容的秒数)、当前码率,以及清单(manifest)中提供的可选码率阶梯。
策略 1:基于吞吐量(Throughput-Based)
最直观的做法:
Estimated bandwidth = average download speed of recent N segments
Next tier bitrate ≈ estimated bandwidth × 0.8 (20% safety margin)
举例:近期速度为 5 Mbps → 5 × 0.8 = 4 Mbps → 从 [360p(0.5) / 720p(2.5) / 1080p(5) / 4K(15)] 中挑选 ≤ 4 Mbps 的最高档 → 720p。
优点:简单直观。
缺点:HTTP/TCP 的吞吐量测量本身噪声很大(慢启动、队头阻塞、TLS 握手),会导致清晰度频繁震荡——“一会儿清晰、一会儿模糊”。
应用场景:早期 hls.js 的 bandwidthFraction 策略。
策略 2:基于缓冲区(BBA)
另一种思路:完全忽略吞吐量,只看缓冲区水位。
Buffer < 10s → download lowest tier (prevent stalling)
Buffer 10-30s → download mid tier
Buffer > 30s → download highest tier (plenty of runway)
Bitrate tier
▲
Max │ ┌────────
│ ╱
Mid │ ┌───╱
│ ╱
Min │────────────┘
└─────────────────────────► Buffer (seconds)
0 10s 30s 60s
由 Huang 等人(斯坦福 / Netflix)在 2014 年 SIGCOMM 论文 A Buffer-Based Approach to Rate Adaptation 中提出。
优点:不受吞吐量噪声影响,清晰度稳定(切换更少)。
缺点:启动阶段过于激进地降低清晰度(此时缓冲区初始为空);且无法充分利用可用带宽。
策略 3:BOLA(Lyapunov 优化)
BOLA = Buffer Occupancy based Lyapunov Algorithm(基于缓冲区占用的 Lyapunov 算法)
由 Spiteri、Urgaonkar 和 Sitaraman 于 2016 年 INFOCOM 发表。是 dash.js 的默认算法之一。
核心思想
BOLA 将 ABR 建模为一个多目标优化问题:
maximize: average_quality - V × (stall_penalty + switching_penalty)
V 是一个权衡参数:V 越大越保守(优先避免卡顿);V 越小越激进(优先追求清晰度)。
作者借助 Lyapunov 优化理论证明:仅依据当前缓冲区水位就能做出接近最优的决策。
简化伪代码
def bola_select_bitrate(buffer_level, bitrates, V):
best_bitrate = None
best_score = float('-inf')
for r in bitrates:
utility = log(r) # Diminishing returns on quality
score = buffer_level * utility - V * r
if score > best_score:
best_score = score
best_bitrate = r
return best_bitrate
工程实践
dash.js 会动态地将 BOLA 与吞吐量规则结合:启动阶段(缓冲区较低)使用基于吞吐量的策略,一旦缓冲区健康后切换到 BOLA。
策略 4:MPC(模型预测控制)
由 Yin、Jindal、Sekar 和 Sinopoli 于 2015 年 SIGCOMM 发表。
思想
不再逐个分片做决策,而是预测未来带宽并联合优化接下来的 K 个分片:
Currently at segment n.
Predict bandwidth for the next 5 segments: T1, T2, T3, T4, T5.
Try all bitrate combinations and pick the one that maximizes:
(total quality - stall penalty - switching penalty)
带宽预测通常采用调和平均数(相比算术平均数对慢速样本更敏感)或 EWMA(指数加权移动平均)。
优点:比 BOLA 更聪明(会向前看)。缺点:计算量略大;一旦预测出错就是垃圾进、垃圾出(garbage in, garbage out)。
策略 5:Pensieve(AI 驱动的 ABR)
由 Mao、Netravali 和 Alizadeh(MIT)于 2017 年 SIGCOMM 发表。
思想
用强化学习(A3C)训练一个神经网络来做 ABR 决策。
输入特征:过去 K 秒的吞吐量、当前缓冲区、上一次的码率、剩余分片数、可选码率阶梯。
输出:下一个分片选用哪个码率档位。
训练方式:在真实 / 合成的网络轨迹上模拟数百万次会话,直到网络学到最优策略。
在特定测试集上表现优于 BOLA 和 MPC,但也有局限:对未见过的网络模式泛化能力不确定、可解释性低,且需要持续的在线微调。
头部公司(Netflix、YouTube)已在内部构建了类似的基于学习的 ABR。对绝大多数平台而言,BOLA 或 MPC 已经绰绰有余。
业界实际怎么做
- Netflix:客户端采用类 BBA 策略 + 服务端提示(“CDN 负载较高,请降级”)+ 基于 VMAF 优化的码率阶梯。
- YouTube:自研算法,纳入观看时长预测;辅以大量 A/B 测试。
- 其他所有人:使用开源播放器(hls.js、Shaka Player、ExoPlayer)的默认 ABR,再做参数调优。
短视频:ABR 的特殊考量
竖屏短视频与长视频 VOD 在几个关键点上存在差异:
- 首帧时间(TTFF)至关重要——如果用户在划动后 300ms 内看不到画面,就会划走。
- 单集时长短(60–90 秒):ABR 可能还没来得及提升清晰度,这一集就已经播完了。
- 多集预加载:App 可能在后台提前下载 N+1、N+2 集的分片。
常见调整
- 降低启动档位(加快首播速度)
- 放慢向上切换的速度(避免刚启动就卡顿)
- 以低清晰度预加载(为后台下载节省带宽)
- 当前正在播放的这一集给高清晰度(前台优先)
常见的 ABR 问题与工程建议
为什么播放中途清晰度会突然下降?
通常是:带宽测量值骤降(蜂窝信号变化、路由器信道切换)、CDN 边缘节点异常,或设备因过热而降频。
为什么在良好的 Wi-Fi 下还卡在低清晰度?
启动策略过于保守、吞吐量历史被旧的慢速样本污染,或者清单里根本没有高码率档位(转码时没有生成 1080p)。
为什么清晰度一直来回震荡?
码率阶梯的相邻档位太接近,算法对吞吐量噪声过于敏感。解决办法:让相邻档位间隔约 1.5×、增加切换惩罚项,或从基于吞吐量的策略切换到 BOLA。
最重要的 ABR 配置不是算法,而是码率阶梯。
糟糕的阶梯会让任何算法都失效。设计原则:
- 相邻档位在码率上应相差 1.5–2 倍(太接近 = 切换毫无意义;太远 = 跳变突兀)
- 最低档位必须足够低,以覆盖 2G / 弱 3G 用户
- 最高档位不应浪费带宽(在手机上,8 Mbps 的 1080p 与 5 Mbps 看起来几乎没有区别)
逐标题编码(Per-title encoding) 会为每个片源定制最优的码率阶梯。
关键要点
- ABR = 自适应码率。每个分片下载后,播放器决定下一个分片下载哪个档位。
- 五种经典策略:
- 基于吞吐量:简单但噪声大
- 基于缓冲区(BBA):稳定但保守
- BOLA:接近最优、经过生产验证(dash.js 默认)
- MPC:会向前看,更聪明但依赖预测
- Pensieve:AI 驱动,被头部公司采用
- 码率阶梯比算法更重要。
- 短视频的 ABR 必须针对 TTFF 和预加载做调优。
- 档位间隔约 1.5–2 倍,最低档足够低,最高档合理。
上一篇: 第五篇:流媒体协议
下一篇: 第七篇:CDN 分发
参考资料
- RFC 8216: HTTP Live Streaming — IETF
- hls.js — GitHub
- Shaka Player — Google / GitHub