Audio & Video 进阶 25m
Low-Latency HLS 新特性
What's new in Low-Latency HLS
2020年6月24日
一句话判断
如果你在构建直播系统,这场 Session 汇总了 Low-Latency HLS 在 2020 年的全部更新——从 Partial Segments 到 Blocking Playlist Reload,一套组合拳将端到端延迟压到 3 秒以内。
这场 Session 讲了什么
这场 Session 是 WWDC 2020 关于 Low-Latency HLS 的总览性演讲。Apple 在 2019 年提出了 Low-Latency HLS 的概念,2020 年则是将这些规范落地为可用技术的关键一年。演讲者从传统 HLS 的延迟问题讲起——标准 HLS 的端到端延迟通常在 15-30 秒,主要因为播放器需要下载完整的 segment(通常 6 秒)才能开始播放。
Low-Latency HLS 的核心思路是将完整的 segment 进一步拆分为更小的 partial segment(通常 0.5-1 秒),播放器可以在 partial segment 级别就开始解码播放,而不必等待完整 segment。配合 Blocking Playlist Reload 和 Preload Hints 两个机制,播放器可以在服务器有新数据时立即获取,而不是轮询等待。
Session 还介绍了 Low-Latency HLS 对 CDN 的友好设计。通过 Delta Playlist Updates,服务器只需要发送 playlist 的增量变化,而不是完整的 playlist 文件,这大幅减少了 CDN 的带宽消耗。广告插入(Ad Insertion)也有了新的方案,在低延迟场景下实现更无缝的广告切换。
值得深挖的点
- 端到端延迟的组成部分:延迟不只是播放器的问题——从编码器到 CDN 到客户端,每一环都在加延迟。Apple 给出的目标是 encoder delay + segment duration + CDN propagation + client buffer < 3 秒。这意味着你需要从整个链路角度去优化,不能只盯着播放器端。
- CDN 兼容性的现实:Low-Latency HLS 的很多新特性(如 Blocking Playlist Reload)依赖 CDN 支持 HTTP/2 的长连接和推送。如果你的 CDN 不支持这些特性,一些优化效果会打折扣。选择 CDN 时需要特别关注其对 Low-Latency HLS 的支持程度。
代码片段
# Low-Latency HLS Playlist 示例
# #EXTM3U
# #EXT-X-TARGETDURATION:6
# #EXT-X-PART-INF:PART-TARGET=1.0
# #EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=3.0
#
# #EXT-X-PART:DURATION=1.0,URI="segment1_part0.mp4"
# #EXT-X-PART:DURATION=1.0,URI="segment1_part1.mp4"
# #EXT-X-PART:DURATION=0.75,URI="segment1_part2.mp4"
# #EXTINF:6.0,
# segment1.mp4
# 使用 mediastreamsegmenter 生成 Low-Latency HLS 流
mediastreamsegmenter \
--segment-duration 6 \
--partial-segment-duration 1 \
--delete-ext-old-clips 30 \
--output-directory /hls/live/ \
--master-playlist-name master.m3u8 \
--file /dev/stdin
// 使用 AVPlayer 播放 Low-Latency HLS 流
import AVFoundation
let url = URL(string: "https://example.com/live/master.m3u8")!
let playerItem = AVPlayerItem(url: url)
// 配置低延迟播放偏好
playerItem.preferredForwardBufferDuration = 1.0
let player = AVPlayer(playerItem: playerItem)
player.play()
// 监听延迟指标
player.addPeriodicTimeObserver(
forInterval: CMTime(seconds: 1, preferredTimescale: 1),
queue: .main
) { time in
// 计算当前延迟
if let currentDate = playerItem.currentDate() {
let latency = Date().timeIntervalSince(currentDate)
print("当前延迟: \(latency) 秒")
}
}
最佳实践
- Partial segment duration 设为 1 秒是延迟和性能的最佳平衡点,不要为了追求更低延迟而设得太小
PART-HOLD-BACK至少设为 partial segment duration 的 3 倍,确保播放器有足够的缓冲- 直播场景下优先使用 fMP4 容器而非 MPEG-TS,前者支持更精确的 partial segment 切分
- 部署前用 mediastreamvalidator 全面验证流的合规性,特别是 Low-Latency 特有的标签
- CDN 缓存策略需要为 partial segment 设置更短的 TTL,避免播放器拿到过期数据
还有什么值得关注
- Low-Latency HLS 的规范已经提交为 RFC 草案,正在走向标准化
- 这一系列还有三场深度 Session:Blocking Preload Hints、Playlist Delta Updates、Blocking Playlist Reload
- 搭配 “Improve stream authoring with HLS Tools” 一起看,可以掌握完整的 Low-Latency HLS 工具链
WWDC 2020