流媒体协议

本页目录

流媒体系统把连续采集的音视频编码、传输并按时间播放。协议选择先区分两段链路:采集端到媒体服务的 ingest/contribution,以及媒体服务到观众的 distribution。前者可能用 SRT,后者用 HLS;不能把它们当作只能选一个的竞争方案。

采集、回传与播放分发可以使用不同协议 采集与编码 摄像机 / 屏幕 媒体服务 转码 / 打包 观众播放 下载 / 解码 / 显示 回传:RTMP(S) / SRT 等 从采集端到媒体服务 分发:HLS / DASH / WebRTC 按互动与终端要求选择 SRT 回传 + HLS 分发可以共存;一段链路低延迟,不保证整条链路低延迟。
场景主要约束对应关注点
点播起播、搜索跳转、画质与成本媒体分段、缓存、ABR
单向直播距离现场多远、能否稳定播放发布速度、live edge、缓冲
双向互动对话与操作反馈是否及时双向路径、拥塞控制、播放期限
跨公网回传画面完整性与丢包恢复重传窗口、带宽余量、接收延迟

这些是测量维度,不是固定延迟排名。相同协议在不同编码器、缓冲与网络条件下,可以得到完全不同的端到端时延。

三种时间:起播、直播延迟与缓冲

起播时间从用户发起播放到第一帧显示;玻璃到玻璃延迟从真实场景采集到观众显示;缓冲水位是播放器已经拿到但尚未播放的可用媒体时长。点播可以在很短时间起播并保留较深缓冲,不能把“缓冲十秒”写成“点播晚了十秒”。

直播延迟可能包含采集编码、回传、分段发布等待、清单发现、下载、播放器安全距离与显示。若某一阶段按段等待,段长会影响它,但总延迟不恒等于 segment 时长 × 缓冲段数。计算时还要避免把同一份 hold-back 与缓冲重复计入。

例如明确划分后的阶段分别为 0.1、0.2、0.5、0.1、0.2、1.0、0.1 秒,总计 2.2 秒。即使把发布等待缩短到 0.1 秒,其他阶段不变也仍有 1.8 秒;不能只看到 100 ms part 就宣称系统实现 100 ms 延迟。

ABR:从下载时间推演缓冲变化

服务端提供不同码率和分辨率的表示,客户端依据吞吐、缓冲、设备解码能力等选择。为了顺利切换,媒体时间线、随机访问点和编码约束需要配合;“段编号相同”本身不能保证无缝切档。

播放器边下载边消耗缓冲:码率高于吞吐会逐段亏空 2 s 媒体片段 4 Mbit/s 下载 4 s 链路吞吐 2 Mbit/s 缓冲 6 → 4 s 2 s 媒体片段 2 Mbit/s 下载 2 s 链路吞吐 2 Mbit/s 缓冲 6 → 6 s 上例忽略请求与解码开销;实际 ABR 还应留裕量,不能把平均吞吐全用满。

假设每段长 2 秒,编码码率 4 Mbit/s,则该段约 8 Mbit;链路实际可用吞吐 2 Mbit/s,下载需要 4 秒。这四秒里播放器消耗四秒旧内容,仅补回两秒新内容,净亏两秒缓冲。

from fractions import Fraction as F

def next_buffer(buffer, duration, bitrate, throughput):
    download = duration * bitrate / throughput
    stall = max(F(0), download - buffer)
    return max(F(0), buffer - download) + duration, stall

buffer = F(6)
trace = []
for _ in range(3):
    buffer, stall = next_buffer(buffer, F(2), F(4), F(2))
    trace.append((buffer, stall))
assert trace == [(4, 0), (2, 0), (2, 2)]
assert next_buffer(F(6), F(2), F(2), F(2)) == (6, 0)
# 2 Mbit/s 估计吞吐、0.8安全系数,在这组候选中选1.4档。
ladder = [F('0.8'), F('1.4'), F('2.8'), F(5)]
assert max(rate for rate in ladder if rate <= F(2) * F('0.8')) == F('1.4')
print('逐段缓冲亏空、卡顿与保守选档模型通过')

这是恒定段码率、无请求开销的教学模型。真实 VBR 段大小会变化,吞吐估算也会受采样窗口、缓存命中、连接启动以及低延迟内容尚未产出等因素影响。不能断言 on-off 下载永远高估或永远低估带宽。dash.js 吞吐计算

基于吞吐与基于缓冲的规则可结合,实际播放器还会考虑放弃过慢请求、掉帧和频繁切换。画面卡顿也可能来自源站缺段、时间戳不连续或终端解码不足,并非几乎都由 ABR 算法造成。dash.js ABR

下载一段补两秒,为什么缓冲反而减少?

默认条件连续下载三段,缓冲从6到4到2,第三次出现2秒卡顿。途中降码率会改变未来下载耗时,但不会改写已经发生的卡顿。这样才能把一次算式变成可追踪的累积过程。

正在呈现知识画面
下载一段补两秒,为什么缓冲反而减少?

下载期间旧内容持续播放。下载耗时超过剩余缓冲就卡顿,新段完成后才补回其媒体时长。

HLS:清单负责描述,媒体段负责内容

HLS 使用 UTF-8 播放清单,支持 MPEG-TS、fragmented MP4 等媒体形式,不能限定为 .ts。多变体清单列出可选表示;媒体清单描述具体媒体段。播放器也可以直接打开单一媒体清单,不必所有播放都先经过多变体层。HLS RFC 8216

下面是一个完整的短 fMP4 点播媒体清单示例;媒体文件需由兼容编码/打包器生成,这段文本本身不产生视频。

#EXTM3U
#EXT-X-VERSION:7
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MAP:URI="init.mp4"
#EXTINF:2.000,
seg-000.m4s
#EXTINF:2.000,
seg-001.m4s
#EXT-X-ENDLIST

EXT-X-MAP 指定初始化部分;EXTINF 表示该段时长。TARGETDURATION 的约束是段 EXTINF 时长按规范四舍五入后的整数不得超过它,不应把它笼统解释为所有段的精确长度。媒体序号标识播放清单中的段序列,不保证不同变体的同一序号能脱离时间戳直接互换。

清单类型/状态更新规则与结果
VOD内容固定,完整点播
EVENT可向尾部追加,保留此前条目
滑动直播新段追加,旧段可移出窗口
ENDLIST不再添加媒体段;也可以出现在已结束的 EVENT/直播

低延迟 HLS:部分段、阻塞重载与预告配合

LL-HLS 让完整 segment 尚未结束时,已经生成的 partial segment 就能被发现和下载。阻塞播放清单重载允许客户端带 _HLS_msn / _HLS_part 请求未来进度,服务端等所需内容可用后返回,减少重复获取旧清单的等待。Apple LL-HLS

PRELOAD-HINT 提前告知可能需要的资源或范围,客户端可以先发请求;它不是“该资源现在已经完整存在”的保证,计划也可能改变。SERVER-CONTROL 宣告所支持能力,PART-INF 描述部分段时长参数;这些约定还需要源站、CDN 和播放器共同支持。Apple 阻塞重载讲解

缓存如果忽略 delivery directives,或代理一直缓冲响应到完整 segment 结束,源站即使快速发布也可能失去低延迟收益。更小的 part 增加请求和调度开销,缓冲更浅又降低抗抖动能力,因此 part 越小并不总是越好。

DASH 与 CMAF:表示、时间线和可共享媒体

DASH 的 MPD 使用 Period、AdaptationSet 和 Representation 组织媒体,SegmentTemplate 可以按编号或时间定位分段。timescale=90000、duration=180000 表示每段两秒;timescale 不是帧率。

动态 MPD 的时间模型涉及可用性起点、客户端时钟、时间移动窗口和播放延迟,minBufferTime 也不是“播放器必须固定缓冲这个秒数”的简单开关。DASH-IF 时间模型

低延迟 DASH 可以在一个 segment 尚在生成时增量传输 CMAF chunks。HTTP/1.1 可以采用 chunked transfer coding,HTTP/2/3 则按各自的数据帧传递,不能把 HTTP/1.1 的 chunked 编码列为所有 LL-DASH 的必要条件。DASH-IF 低延迟指南

CMAF 规范媒体组织与约束,不是另一种视频 codec。HLS 与 DASH 在 codec、轨道、分段边界及加密配置兼容时,可以复用媒体对象而使用不同清单;不符合这些条件时仍可能有多个包版本。“用了 CMAF 就一定缓存减半”忽略了实际封装与终端需求。

CDN:分发副本与源站负载的两本账

若一万名观众各看 3 Mbit/s,边缘到观众约需 30 Gbit/s 媒体吞吐;高缓存命中率可以减少回源,却不会让这一万份观众传输消失。假设二十个边缘各为同一档内容回源一份持续媒体,理想媒体回源约 60 Mbit/s,还未算其他档位、请求、预热与失败重试。

已完成且 URL 不复用的媒体段适合较长缓存;不断变化的直播清单需要及时更新。鉴权参数若让每个用户形成不同 cache key,会降低共享命中;忽略鉴权又可能越权。设计时要让边缘完成授权,并明确哪些内容可以共享,而不是简单给所有 URL 添加长 cache TTL。

RTMP(S) 与 SRT:回传侧的不同工具

RTMP 通过可靠字节流承载控制及媒体消息,其 chunk stream 用于消息分块和交错,不是 HLS 媒体 segment。RTMPS 增加 TLS 保护。Flash 浏览器播放退出历史,并不等于 RTMP 无法用于任何播放或现代回传;Enhanced RTMP 继续扩展编解码器与多轨能力,具体要看两端支持。Enhanced RTMP

SRT 使用 UDP 上的传输机制,实时模式通过丢包反馈/重传与时间戳交付缓冲兼顾恢复和及时性。SRTO_RCVLATENCY 与对端要求参与确定接收延迟约束;它们不是摄像机到显示屏总时延。数据即使早到,也可能按交付计划等待。SRT 延迟机制

提高延迟预算可以给重传更多机会,不能修复持续带宽不足。若编码 8 Mbit/s 而链路长期只有 6 Mbit/s,单纯加大缓冲只会推迟失败;重传还要额外占用带宽。Caller、Listener、Rendezvous 是建立连接的角色/方式,不是任何 NAT 都可穿越的保证。

互动与游戏串流:期限来自整条反馈路径

WebRTC 适合需要双向反馈的实时媒体,媒体服务器可以按订阅和层级分发;它与 HTTP 分段分发也可在同一平台中转换组合。不能把所有 WebRTC 连接固定描述为直连或同一种拥塞算法。

Sunshine/Moonlight 等游戏串流还包含输入回传、游戏逻辑与渲染、编码、下行、解码和显示,评估的是操作到画面的完整闭环。60 fps 只说明理想帧间隔约 16.7 ms,不证明整个闭环必须在一帧内完成,更不能断言任何重传都必然无用。FEC、重传、丢帧和帧节奏要在实际播放期限内权衡。

内容加密与播放授权

HTTPS 保护客户端到服务的传输;HLS AES-128 等方式保护媒体对象;DRM 还包括许可证和播放权限体系。三者不是同一个开关。使用 SAMPLE-AES 并不能单靠标签确定所有终端都会支持某个 DRM,密钥格式、加密模式与播放器能力都需匹配。

密钥 URL 可以下载不等于业务已经完成授权,URL 签名过期也不会抹除用户已经得到的内容。排查黑屏时应区分清单失败、媒体失败、初始化/codec 不支持和许可证失败,避免把所有问题归于网速。

选择方案时,用可复现指标描述需求:首次显示耗时、现场到播放延迟、卡顿比、画质变化、端点资源和单位观众传输成本。保留网络与编码条件后,测量才可以支持下一轮调整。