直播架构 / 流媒体协议
直播系统整体架构
推流端(采集 -> 编码 -> 封包 -> 推流)
推流端是整个直播链路的起点,负责将现实世界的音视频信号转换为可在网络上传输的数据流。推流端包含以下核心环节:
采集(Capture)
采集阶段从硬件设备获取原始音视频数据。视频采集源包括摄像头、屏幕录制、摄像机采集卡等;音频采集源包括麦克风、混音器输出、系统音频等。采集后的数据为未经压缩的原始格式,视频为 YUV/RGB 帧序列,音频为 PCM 采样数据。
视频采集: 摄像头 -> YUV/RGB 原始帧 (分辨率 1080p/720p/480p 等)
音频采集: 麦克风 -> PCM 原始采样 (采样率 44100/48000 Hz)编码(Encode)
原始音视频数据体积巨大(例如 1080p@30fps 的 YUV 视频码率约 1.5 Gbps),必须经过压缩编码才能通过网络传输。编码阶段使用视频编码器和音频编码器对原始数据进行压缩。
- 视频编码:H.264(AVC)是目前最通用的直播编码格式,H.265(HEVC)和 AV1 提供更高压缩率但解码兼容性较低。编码器通过帧内预测、帧间预测、变换量化、熵编码等技术消除空间和时间冗余。
- 音频编码:AAC 是直播中最常用的音频编码格式,Opus 在低延迟场景表现出色,MP3 已较少用于直播场景。
编码器输出的码率、帧率、GOP(Group of Pictures)长度直接影响直播质量和延迟。
视频编码示例(FFmpeg):
ffmpeg -i input.mp4 -c:v libx264 -preset veryfast -b:v 2500k -g 60 -c:a aac -b:a 128k output.flv封包(Mux/Packetize)
编码后的 ES(Elementary Stream,基本流)需要按照特定协议格式进行封装,添加必要的元信息(时间戳、帧类型、序列头等),形成可传输的媒体容器格式。常见的直播封装格式包括 FLV、TS、fMP4 等。封装阶段会生成 PTS(显示时间戳)和 DTS(解码时间戳),用于播放端的同步渲染。
推流(Push/Publish)
封装后的数据通过推流协议发送到流媒体服务器。推流协议负责将媒体数据可靠或实时地传输到服务端,并支持流发布认证、元数据传递等功能。
采集 -> 编码 -> 封包 -> 推流
[摄像头] -> [H.264] -> [FLV/TS] -> [RTMP/SRT]分发端(源站 -> 转码 -> CDN -> 边缘节点)
分发端负责将推流端推送的直播流高效、可靠地分发到全球各地的观众。分发端架构通常采用多层分层设计。
源站(Origin Server)
源站是直播流的第一站,负责接收推流端的上行流。源站提供流媒体接入能力,对推流进行认证鉴权,并将流转换为多种格式供下游拉取。源站通常部署在核心数据中心,具备大带宽接入能力。
转码(Transcoding)
转码服务将源站接收的原始流实时转换为多种码率和分辨率的副本,用于自适应码率分发。转码包括:
- 多码率转码:将一路源流转为 1080p(高码率)、720p(中码率)、480p(低码率)、360p(流畅)等多路输出。
- 格式转换:将 RTMP 流转换为 HLS(TS/fMP4)、DASH 等拉流格式。
- 自定义处理:添加水印、裁剪画面、调整帧率等。
CDN(Content Delivery Network)
CDN 是直播分发的核心基础设施,通过遍布全球的边缘节点就近服务观众。直播 CDN 包括:
- 中心节点:汇聚源站数据,作为区域回源的总入口。
- 区域节点:覆盖大区域(如华东、华北),缓存热点内容,减少回源压力。
- 边缘节点:部署在用户附近的接入点,直接响应播放请求,提供低延迟拉流。
推流端 -> 源站 -> 转码集群 -> CDN 中心节点 -> CDN 区域节点 -> CDN 边缘节点 -> 播放端缓存策略
直播 CDN 采用分片级缓存策略。对于 HLS/DASH 等分片协议,CDN 按 .ts 或 .m4s 分片粒度进行缓存和回源;对于 HTTP-FLV,CDN 基于 GOP 边界进行缓存拼接,支持时间戳修正。
播放端(拉流 -> 解封装 -> 解码 -> 渲染)
播放端是直播链路的终点,负责从 CDN 或源站拉取媒体流并呈现给观众。
拉流(Pull)
播放器根据 URL 选择对应的拉流协议从 CDN 边缘节点获取媒体数据。播放器首先下载索引文件(如 M3U8、MPD),解析出媒体分片列表,然后按顺序请求分片数据。对于 HTTP-FLV 协议,播放器直接建立 HTTP 长连接获取持续的 FLV 流。
解封装(Demux)
播放器将获取到的媒体容器数据分解为独立的视频 ES、音频 ES 和元数据。解封装阶段根据容器格式(TS、fMP4、FLV)选择对应的解复用器,提取编码帧和时间戳信息。
解码(Decode)
使用硬件或软件解码器将压缩的视频 ES 和音频 ES 解码为原始 YUV/RGB 帧和 PCM 采样。现代播放器优先使用硬件解码(如 MediaCodec、VideoToolbox、VAAPI)以降低功耗和 CPU 占用。解码后得到无压缩的原始帧序列。
渲染(Render)
将解码后的视频帧按照 PTS 时间戳同步渲染到显示设备上,同时将音频数据发送到音频输出设备。渲染阶段需要处理音画同步(A/V Sync)、帧率适配、缓冲控制等逻辑。
拉流 -> 解封装 -> 解码 -> 渲染
[HLS/FLV] -> [FLV/TS Demux] -> [H.264 Decode] -> [OpenGL/Surface 渲染]直播链路端到端拓扑图
┌─────────────────┐
│ 播放端 (观众 A) │
│ HLS/FLV/DASH │
└────────┬────────┘
│
┌──────────────┐ ┌──────────────────┐ ┌─────────────────────┐ ┌──────┴──────┐
│ 推流端 │ │ │ │ │ │ CDN 边缘 │
│ ┌────┐ ┌───┐ │ │ 流媒体源站 │ │ 转码集群 │ │ 节点 1 │
│ │采集 │ │编码│ │ │ │ │ │ │ │
│ └────┘ └───┘ │ RTMP│ ┌────────────┐ │ │ ┌─────┐ ┌───────┐ │ └──────┬──────┘
│ ┌────┐ ┌───┐ │ ────┼─┤ 推流接入 │ │─────┼─┤1080p│ │HLS Pack│ │ │
│ │封包 │ │推流│ │ SRT │ │ 鉴权/分发 │ │ │ │720p │ │DASH │ │ │
│ └────┘ └───┘ │ │ └────────────┘ │ │ │480p │ │FLV │ │ ┌──────┴──────┐
└──────────────┘ │ ┌────────────┐ │ │ └─────┘ └───────┘ │ │ CDN 边缘 │
│ │ 录制/时移 │ │ │ │ │ 节点 2 │
│ └────────────┘ │ └─────────────────────┘ │ │
└──────────────────┘ └──────┬──────┘
│
┌────────┴────────┐
│ 播放端 (观众 B) │
│ HLS/FLV/DASH │
└─────────────────┘推流协议
RTMP(Real-Time Messaging Protocol)
RTMP 是 Adobe 开发的基于 TCP 的实时消息传输协议,自 2000 年代初起成为直播推流的事实标准。尽管 Adobe 在 2020 年停止支持 Flash,但 RTMP 在推流场景中仍被广泛使用。
协议握手
RTMP 握手是客户端与服务端建立连接后的第一个交互过程,包含三个往返阶段:
客户端 服务端
│ │
│──── C0 (版本 0x03) ────────────────────│
│──── C1 (1536 字节随机数据) ────────────│
│ │
│◄─── S0 (版本 0x03) ────────────────────│
│◄─── S1 (1536 字节随机数据) ────────────│
│ │
│──── C2 (回显 S1 数据) ─────────────────│
│ │
│◄─── S2 (回显 C1 数据) ─────────────────│
│ │
│──── 建立连接 (connect) ────────────────│
│◄─── 窗口确认/设置带宽 ─────────────────│
│◄─── 连接成功 (_result) ───────────────│
│──── 创建流 (createStream) ─────────────│
│◄─── 流ID (_result) ───────────────────│
│──── 发布 (publish) ───────────────────│
│◄─── 发布成功 (onStatus) ──────────────│
│ │
│──── 推送音视频数据 ────────────────────│握手完成后,客户端和服务端通过 RTMP Chunk Stream 进行消息交换。
AMF 编码
RTMP 使用 Action Message Format(AMF)进行协议级数据编码,包括 AMF0 和 AMF3 两种版本。
- AMF0:使用类型标记 + 数据的编码方式,支持 Number(0x00)、Boolean(0x01)、String(0x02)、Object(0x03)、Null(0x05)、Array(0x0A)等类型。
- AMF3:在 AMF0 基础上增加了引用机制和更紧凑的编码。
AMF0 String 编码示例:
0x02 // 类型标记: String
0x00 0x0A // 字符串长度: 10 字节
0x72 0x74 0x6D 0x70 0x3A 0x70 0x6C 0x61 0x79 // "rtmp:play"
AMF0 Object 编码示例:
0x03 // 类型标记: Object
0x00 0x04 0x6E 0x61 0x6D 0x65 // key: "name"
0x02 0x00 0x05 0x76 0x61 0x6C 0x75 0x65 // value: "value"
0x00 0x00 0x09 // 对象结束标记Chunk 分块
RTMP Chunk Stream 是 RTMP 的传输层,将大消息拆分为更小的 Chunk 进行传输,支持流复用和优先级控制。
Chunk Header 有以下四种类型:
| 类型 | 字段包含 | 头部大小 | 说明 |
|---|---|---|---|
| Type 0 | timestamp, msg_length, msg_type_id, msg_stream_id | 11 字节 | 完整头部,用于 Chunk 起始或时间戳变化 |
| Type 1 | timestamp_delta, msg_length, msg_type_id | 7 字节 | 省略 msg_stream_id,延续前一个 Chunk 的流 ID |
| Type 2 | timestamp_delta | 3 字节 | 仅携带时间戳增量 |
| Type 3 | 无 | 0 字节 | 完全复用前一个 Chunk 的头部信息 |
Chunk 基本格式:
┌────────┬──────────┬─────────────┬────────────┐
│基本头部 │ 消息头部 │ 扩展时间戳 │ Chunk 数据 │
│1-3 字节 │ 0/3/7/11 │ 0/4 字节 │ 变长 │
│ │ 字节 │ │ │
└────────┴──────────┴─────────────┴────────────┘
基本头部:
┌──────┬──────┬───────────────┐
│ fmt │ cs │ chunk body │
│ 2bit │ 6bit │ (可选扩展) │
└──────┴──────┴───────────────┘
fmt: Chunk 类型 (0-3)
cs: Chunk Stream ID (2-63 直接编码, 64-65599 扩展编码)
Type 0 头部:
┌─────────┬───────────┬───────────┬──────────────┐
│Timestamp│Msg Length │Msg Type ID│ Msg Stream ID│
│ 3 字节 │ 3 字节 │ 1 字节 │ 4 字节 │
└─────────┴───────────┴───────────┴──────────────┘Chunk 分块机制的优点:
- 大消息(如视频帧)被拆分为多个 Chunk,避免阻塞小消息(如音频帧、控制消息)。
- Type 3 Chunk 仅 1 字节头部,有效降低连续帧的传输开销。
- 支持 Chunk Stream ID 复用,同一流上的多个消息交错传输。
推送流程
1. TCP 三次握手建立连接 (1935 端口)
2. RTMP 握手 (C0/C1 -> S0/S1 -> C2/S2)
3. 协议层连接 (connect 命令)
- 传入应用名 (app) 和实例类型 (type)
4. 创建流 (createStream 命令)
- 服务端分配流 ID
5. 发布流 (publish 命令)
- 传入流名称和发布类型 (live/record/append)
6. 推送音视频数据
- 发送音频数据消息 (Type ID = 8)
- 发送视频数据消息 (Type ID = 9)
- 发送元数据消息 (Type ID = 18, 包含 onMetaData)
7. 断开连接 (FCUnpublish / deleteStream)RTMP 推送数据流示例 (十六进制):
// 视频关键帧 (Type 0 Chunk)
03 00 00 00 00 1E 00 09 01 00 00 00
// 以上: fmt=0, cs=3, timestamp=0, length=30, type=video, stream=1
// 后续帧 (Type 3 Chunk) - 仅基本头部
C3 [26 字节视频数据]
// 音频帧
02 00 00 2D 00 01 00 08 01 00 00 00
// fmt=0, cs=2, timestamp=45, length=1, type=audio, stream=1
[1 字节音频数据]元数据(onMetaData)
推流端在推送音视频数据之前,需要通过 @setDataFrame 发送元数据,包含音视频编码参数:
onMetaData:
{
width: 1920,
height: 1080,
videodatarate: 2500,
framerate: 30,
videocodecid: 7, // AVC/H.264
audiodatarate: 128,
audiosamplerate: 44100,
audiosamplesize: 16,
stereo: true,
audiocodecid: 10, // AAC
encoder: "Lavf58.76.100",
duration: 0 // 直播流时长为 0
}SRT(Secure Reliable Transport)
SRT 是 Haivision 开发的基于 UDP 的可靠传输协议,专为不稳定的网络环境下的实时视频传输设计。SRT 在 2017 年开源并被广泛应用于远程制作和直播推流。
协议基础
SRT 运行在 UDP 之上,通过内置的 ARQ(自动重传请求)机制实现可靠传输,同时保持低延迟。SRT 支持点对点传输,无需中间服务器中转。
OSI 模型对比:
TCP: 应用层 -> RTMP/HTTP -> TCP -> IP
SRT: 应用层 -> 音视频数据 -> SRT -> UDP -> IPARQ 丢包重传
SRT 的核心特性是基于接收端反馈的丢包重传机制:
- 发送端为每个数据包分配递增的序列号。
- 接收端定期发送 ACK(确认)和 NAK(丢包报告)反馈。
- 发送端收到 NAK 后立即重传丢失的数据包。
- 接收端对乱序到达的数据包进行重排序。
发送端 接收端
│ │
│──── Packet N (Seq=1001) ──────────────│ (正常接收,发送 ACK)
│──── Packet N+1 (Seq=1002) ────────────X (丢失)
│──── Packet N+2 (Seq=1003) ────────────│ (正常接收)
│ │
│◄─── ACK(1002) ────────────────────────│ (接收端确认已收到 1002 之前的数据)
│◄─── NAK(1002) ────────────────────────│ (接收端报告 1002 丢失)
│ │
│──── 重传 Packet N+1 (Seq=1002) ───────│
│ │SRT 可配置延迟参数(latency)控制重传的时间窗口。如果数据包超出延迟窗口仍未收到,则直接跳过,确保实时性。
时间戳
SRT 使用发送端时钟生成时间戳,接收端通过时间戳实现播放同步。SRT 时间戳基于微秒精度,与 RTP 时间戳不同,SRT 时间戳直接反映发送时刻。
SRT 支持两种时间戳模式:
- 发送端时间戳模式(默认):数据包携带发送端生成的绝对时间戳。
- 接收端时间戳模式:接收端在接收到数据包时追加本地时间戳。
加密
SRT 内置 AES 加密支持,提供三种安全模式:
- 无加密:明文传输。
- AES-128:128 位密钥加密。
- AES-256:256 位密钥加密。
加密密钥通过带外方式协商,SRT 握手阶段使用密钥推导函数生成会话密钥。
SRT 握手流程:
客户端 服务端
│ │
│──── 握手请求 (Handshake Request) ──────│
│ (SRT 版本、加密配置、延迟参数、流ID) │
│◄─── 握手响应 (Handshake Response) ─────│
│ (SRT 版本、加密配置、延迟参数) │
│──── 握手确认 (Handshake Confirm) ──────│
│ │
│──── 开始传输媒体数据 ──────────────────│
│ (TS: 接收端时间戳模式) │
│◄─── ACK / NAK ────────────────────────│SRT 使用 streamid 参数进行推流路径标识:
推流链接示例:
srt://live.example.com:10080?streamid=#!::r=live/test,u=username,p=password参数说明:r 为流名称路径,u 和 p 为认证凭据。
SRT 推流配置
FFmpeg SRT 推流示例:
ffmpeg -i input.mp4 -c:v libx264 -preset veryfast -b:v 2500k \
-c:a aac -b:a 128k -f mpegts \
"srt://origin.example.com:10080?streamid=#!::r=live/stream1,m=publish"
FFmpeg SRT 拉流示例:
ffmpeg -i "srt://origin.example.com:10080?streamid=#!::r=live/stream1,m=request" \
-c copy output.mp4
SRT 关键参数:
- lat=120: 延迟窗口 120ms(默认 120ms,不稳定的网络可调大至 500-1000ms)
- maxbw=5000000: 最大带宽 5Mbps(0 表示自适应估算)
- passphrase: AES 加密密码
- pbkeylen: 密钥长度(16-AES128, 24-AES192, 32-AES256)RTMPS(RTMP + TLS)
RTMPS 是 RTMP 在 TLS 加密传输通道上的安全变体。本质上是 RTMP over TLS,将 RTMP 协议内容的明文传输替换为 TLS 加密传输。
协议特性
- 推流端口:通常使用 443 端口(与 HTTPS 相同),可通过防火墙。
- 加密方式:TLS 1.2/1.3,与 HTTPS 采用相同的证书体系。
- 握手流程:TCP 建立连接后先进行 TLS 握手,再执行标准 RTMP 握手。
- 适用场景:对推流内容安全性要求高的场景,如付费直播、企业内部直播。
RTMPS 连接建立:
TCP 连接 (443 端口)
│
├── TLS 握手
│ ├── ClientHello
│ ├── ServerHello + Certificate
│ ├── 密钥交换
│ └── ChangeCipherSpec + Finished
│
└── RTMP 握手 (加密通道内)
├── C0/C1 -> S0/S1 -> C2/S2
├── connect
├── createStream
├── publish
└── 音视频数据 (加密传输)与 RTMP 的对比
| 特性 | RTMP | RTMPS |
|---|---|---|
| 传输层 | TCP | TCP + TLS |
| 默认端口 | 1935 | 443 |
| 加密 | 无 | AES/TLS 加密 |
| 防火墙友好 | 较差(非标准端口) | 好(HTTPS 端口) |
| 性能开销 | 低 | 较高(TLS 握手 + 加解密) |
| 推流工具支持 | OBS、FFmpeg 完整支持 | OBS、FFmpeg 支持 |
WHIP(WebRTC-HTTP Ingestion Protocol)
WHIP 是 IETF 制定的基于 WebRTC 的标准化推流协议,旨在替代 RTMP 提供低延迟、高兼容性的推流方案。WHIP 已被多个主流平台(如 Cloudflare、Twitch、YouTube)采纳。
协议基础
WHIP 使用 HTTP 作为信令传输通道,通过 WebRTC(SRTP/SCTP)传输媒体数据。WHIP 的关键设计目标:
- 简化 WebRTC 推流的信令交互,使用 HTTP POST 代替复杂的 WebSocket/SIP 信令。
- 利用 WebRTC 的 ICE(交互式连接建立)机制实现 NAT 穿越。
- 支持 STUN/TURN 中继,适应复杂网络环境。
WHIP 推流建立流程:
推流端 服务端 (WHIP Endpoint)
│ │
│──── POST /whip/endpoint ──────────────────│
│ Content-Type: application/sdp │
│ Body: [Offer SDP - 推流端支持的编解码] │
│ │
│◄─── 201 Created ──────────────────────────│
│ Content-Type: application/sdp │
│ Body: [Answer SDP - 服务端选择的参数] │
│ Location: /whip/session/abc123 │
│ ETag: "session-id" │
│ │
│──── ICE 连接建立 (STUN/TURN) ──────────────│
│──── DTLS 握手 ────────────────────────────│
│──── SRTP/SCTP 媒体通道 ───────────────────│
│ │
│──── DELETE /whip/session/abc123 ──────────│
│ (推流结束时删除会话) │Offer SDP 示例
v=0
o=- 1234567890 1234567890 IN IP4 0.0.0.0
s=WHIP Live Stream
t=0 0
a=group:BUNDLE 0 1
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98
c=IN IP4 0.0.0.0
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=42e01f
a=rtpmap:97 VP8/90000
a=rtpmap:98 AV1/90000
a=mid:0
a=sendonly
m=audio 9 UDP/TLS/RTP/SAVPF 99 100
c=IN IP4 0.0.0.0
a=rtpmap:99 OPUS/48000/2
a=rtpmap:100 PCMU/8000
a=mid:1
a=sendonlyWHIP 与 WebRTC 的关系
WHIP 不是一个新的传输协议,而是对 WebRTC 推流信令过程的简化封装。WHIP 使用 WebRTC 的以下核心技术:
- ICE(Interactive Connectivity Establishment):NAT 穿越和连接建立。
- DTLS-SRTP:媒体加密传输(与 HTTPS 同等级安全)。
- RTP/RTCP:实时媒体传输和质量反馈。
- SDP(Session Description Protocol):媒体参数协商。
WHIP 优势
- 超低延迟:端到端延迟可控制在 500ms 以内(RTMP 通常 2-5 秒)。
- 浏览器原生支持:无需插件或额外软件,浏览器即可推流。
- 防火墙友好:使用 HTTPS 443 端口和 HTTP 信令。
- NAT 穿透:ICE 框架自动处理复杂网络环境。
推流协议对比
| 特性 | RTMP | SRT | RTMPS | WHIP |
|---|---|---|---|---|
| 传输层 | TCP | UDP | TCP + TLS | UDP (SRTP) |
| 默认端口 | 1935 | 10080 | 443 | 443 (HTTP) |
| 端到端延迟 | 2-5 秒 | 0.5-2 秒 | 2-5 秒 | 0.2-1 秒 |
| 加密 | 不支持 | AES 可选 | TLS 加密 | DTLS-SRTP |
| 抗丢包能力 | 差(TCP 队头阻塞) | 好(ARQ 重传) | 差(TCP 队头阻塞) | 好(FEC+NACK) |
| NAT 穿越 | 需反向代理 | 需中介 | 需反向代理 | 原生支持(ICE) |
| 浏览器支持 | 不支持 | 不支持 | 不支持 | 原生支持 |
| FFmpeg/OBS 支持 | 完整支持 | 完整支持 | 完整支持 | 逐步支持 |
| 协议复杂度 | 中 | 中 | 中 | 高(WebRTC 栈) |
| 生态成熟度 | 最成熟 | 成熟 | 成熟 | 快速发展中 |
| 适用场景 | 传统推流、CDN 上行 | 弱网环境、远程制作 | 安全推流、企业内部 | 低延迟直播、互动直播 |
| 编码器支持 | H.264/H.265 | 任意编码 | H.264/H.265 | H.264/VP8/AV1/Opus |
| 传输单位 | FLV Tag | TS 包 | FLV Tag | RTP 包 |
拉流协议
HLS(HTTP Live Streaming)
HLS 是 Apple 提出的基于 HTTP 的自适应码率流媒体传输协议,是目前最广泛使用的直播拉流协议。HLS 将直播流切分为一系列连续的 HTTP 文件片段,通过索引文件(M3U8)进行管理。
M3U8 索引文件
HLS 使用 M3U8 播放列表文件描述可用的媒体分片和码率信息。M3U8 基于 M3U 格式扩展,使用 UTF-8 编码。
主播放列表(Master Playlist):
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-INDEPENDENT-SEGMENTS
# 高码率流 - 1080p
#EXT-X-STREAM-INF:BANDWIDTH=3500000,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2"
index_1080p.m3u8
# 中码率流 - 720p
#EXT-X-STREAM-INF:BANDWIDTH=2000000,RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2"
index_720p.m3u8
# 低码率流 - 480p
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=854x480,CODECS="avc1.64001e,mp4a.40.2"
index_480p.m3u8
# 音频流
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",NAME="Chinese",DEFAULT=YES,URI="audio_ch.m3u8"媒体播放列表:
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:1682912345
#EXT-X-DISCONTINUITY-SEQUENCE:0
#EXT-X-PROGRAM-DATE-TIME:2026-07-12T10:00:00.000Z
#EXT-X-MAP:URI="init.mp4"
#EXTINF:6.000,
segment_1682912345.m4s
#EXTINF:6.000,
segment_1682912346.m4s
#EXTINF:4.000,
segment_1682912347.m4s
#EXT-X-KEY:METHOD=AES-128,URI="key.bin",IV=0x1234567890abcdef
#EXTINF:6.000,
segment_1682912348.m4s
#EXT-X-ENDLIST媒体播放列表关键标签说明:
| 标签 | 说明 |
|---|---|
#EXT-X-TARGETDURATION | 单个分片的最大时长(秒),播放器据此设置缓冲策略 |
#EXT-X-MEDIA-SEQUENCE | 当前列表第一个分片的序列号,实现分片淘汰和持续更新 |
#EXT-X-DISCONTINUITY | 标记音视频流参数发生不连续变化(如编码参数变更) |
#EXT-X-KEY | 指定分片解密方法和密钥获取地址 |
#EXT-X-MAP | 用于 fMP4 格式,指向初始化片段(包含 ftyp+moov) |
#EXTINF | 分片持续时间,格式为 #EXTINF:<duration>,<title> |
#EXT-X-ENDLIST | 标记列表结束,仅 VoD(点播)场景存在,直播场景不存在此标签 |
TS 分片与 CMAP 分片
HLS 最初使用 MPEG-2 Transport Stream(TS)作为分片容器格式,后引入 fMP4(Fragmented MP4)作为 CMAF(Common Media Application Format)标准容器。
TS 格式:
- 每个分片为独立的
.ts文件,包含完整的音视频数据。 - 分片起始位置包含 PAT(Program Association Table)和 PMT(Program Map Table)用于解复用。
- 每个 TS 包固定 188 字节,包含 4 字节头部和负载数据。
fMP4 格式:
- 分片由初始化片段(Init Segment,
.mp4)和媒体片段(Media Segment,.m4s)组成。 - 初始化片段包含 ftyp(文件类型)和 moov(元数据)box,描述编码参数。
- 媒体片段包含 moof(电影片段)和 mdat(媒体数据)box。
- 相比 TS,fMP4 解码开销更小,兼容性更广。
TS 分片格式:
┌─────────────────────────────────────┐
│ .ts 文件 (6 秒) │
├─────────────────────────────────────┤
│ PAT (PID=0x0000) │
│ └─ PMT PID = 0x1000 │
├─────────────────────────────────────┤
│ PMT (PID=0x1000) │
│ ├─ 视频 PID = 0x0100 (H.264) │
│ ├─ 音频 PID = 0x0101 (AAC) │
│ └─ PCR PID = 0x0100 │
├─────────────────────────────────────┤
│ PES 包 (PID=0x0100, H.264 视频帧) │
│ └─ 188 字节 TS 包序列 │
├─────────────────────────────────────┤
│ PES 包 (PID=0x0101, AAC 音频帧) │
│ └─ 188 字节 TS 包序列 │
└─────────────────────────────────────┘
fMP4 分片格式:
初始化片段 (init.mp4):
┌──────────┬──────────┐
│ ftyp │ moov │
│ 文件类型 │ 编解码参数 │
└──────────┴──────────┘
媒体片段 (segment_N.m4s):
┌──────────┬──────────┬──────────┬──────────┐
│ moof │ mdat │ moof │ mdat │
│ 片段元数据│ 视频帧 │ 片段元数据│ 音频帧 │
└──────────┴──────────┴──────────┴──────────┘HLS 与其他技术的对比
| 特性 | HLS + TS | HLS + fMP4 (CMAF) |
|---|---|---|
| 容器格式 | MPEG-TS | Fragmented MP4 |
| 文件扩展名 | .ts | .m4s + .mp4 (init) |
| 解码复杂度 | 较高(需要 PSI 解析) | 较低(box 结构清晰) |
| 兼容性 | 所有支持 HLS 的设备 | iOS 10+、现代浏览器 |
| 加密支持 | AES-128 / SAMPLE-AES | AES-128 / SAMPLE-AES |
| 分片 overhead | 较高(PES 头部 + TS 头部) | 较低(box 结构紧凑) |
| 多协议复用 | 无法复用 | 可同时用于 HLS 和 DASH |
直播 HLS 的分片更新机制
HLS 服务端持续生成新的媒体分片,并更新 M3U8 播放列表。播放器定期重新请求 M3U8 以获取新的分片列表。
时间轴:
分片: [1] [2] [3] [4] [5] [6] [7] [8] ...
└─── 当前列表 ───┘
(包含分片 1-4)
时间推移 -->
分片: [1] [2] [3] [4] [5] [6] [7] [8] ...
└─── 更新后的列表 ───┘
(包含分片 5-8)播放器通过将 #EXT-X-MEDIA-SEQUENCE 的值与本地已下载的分片序列号对比,判断哪些是新分片。
FLV(HTTP-FLV)
HTTP-FLV 是一种通过 HTTP 长连接持续传输 FLV 格式数据的拉流方案。它将传统的 RTMP 协议中的 FLV 数据封装在 HTTP 响应体中,利用 HTTP 的广泛兼容性实现准实时的低延迟直播。
协议原理
- 播放器向 CDN/源站发起标准的 HTTP GET 请求。
- 服务端返回 HTTP 200 OK,Content-Type 设置为
video/x-flv。 - 服务端持续以 Chunked Transfer Encoding 方式写入 FLV 数据。
- 播放器在 HTTP 连接上持续读取 FLV Tag,实时解码渲染。
- 连接保持开启,直到播放器主动断开或直播结束。
HTTP-FLV 响应:
HTTP/1.1 200 OK
Content-Type: video/x-flv
Transfer-Encoding: chunked
Access-Control-Allow-Origin: *
Cache-Control: no-cache
Connection: keep-alive
[FLV 二进制数据流]
├── FLV Header (9 字节)
│ ├── Signature: "FLV" (0x46 0x4C 0x56)
│ ├── Version: 1 (0x01)
│ ├── Flags: 5 (0x05, 有音频 + 有视频)
│ └── HeaderOffset: 9 (0x00000009)
├── PreviousTagSize0: 0 (4 字节)
├── Script Tag (onMetaData)
├── PreviousTagSize1 (4 字节)
├── Audio Tag (AAC Sequence Header)
├── PreviousTagSize2 (4 字节)
├── Video Tag (AVC Sequence Header)
├── PreviousTagSize3 (4 字节)
├── Video Tag (关键帧数据)
├── PreviousTagSize4 (4 字节)
├── Audio Tag (AAC 音频帧)
├── PreviousTagSize5 (4 字节)
├── Video Tag (P 帧数据)
├── ...FLV Tag 格式
FLV Tag 结构:
┌────────────┬───────────┬───────────┬────────────┐
│ Tag Type │ Data Size │ Timestamp │ Stream ID │
│ 1 字节 │ 3 字节 │ 4 字节 │ 3 字节 │
└────────────┴───────────┴───────────┴────────────┘
┌─────────────────────────────────────┐
│ Tag Data (变长) │
├─────────────────────────────────────┤
│ Previous Tag Size (4 字节) │
└─────────────────────────────────────┘
Tag Type:
8 - 音频 (Audio)
9 - 视频 (Video)
18 - 脚本数据 (Script Data)
视频 Tag Data (Type=9):
┌──────────┬──────────────────────────┐
│ FrameType│ CodecID │
│ 4 bit │ 4 bit │
├──────────┴──────────────────────────┤
│ AVCPacketType (1 byte, H.264 专用) │
│ 0 = AVC Sequence Header │
│ 1 = AVC NALU │
│ 2 = AVC End of Sequence │
├────────────────────────────────────┤
│ CompositionTime (3 bytes, 仅 H.264) │
├────────────────────────────────────┤
│ Video Data (NALU / Sequence Header) │
└────────────────────────────────────┘
音频 Tag Data (Type=8):
┌──────────┬─────────┬─────────────┐
│ SoundFmt │ Rate │ Size/Type │
│ 4 bit │ 2 bit │ 2 bit │
├──────────┴─────────┴─────────────┤
│ AACPacketType (1 byte, AAC 专用) │
│ 0 = AAC Sequence Header │
│ 1 = AAC Raw │
├──────────────────────────────────┤
│ Audio Data (AAC Raw / Header) │
└──────────────────────────────────┘HTTP-FLV 延迟分析
HTTP-FLV 的延迟主要由以下因素决定:
- 传输延迟:HTTP 长连接传输,毫秒级。
- CDN 缓存延迟:CDN 节点基于 GOP 边界缓存,端到端延迟约 2-5 秒。
- 播放器缓冲:播放器需要缓冲 1-2 个 GOP 用于抗抖动。
- 整体延迟:典型配置下 2-5 秒,优化后可降低至 1-2 秒。
适用场景
- 实时监控:对延迟要求较高(1-3 秒)的监控场景。
- 互动直播:教育直播、电商直播等需要较低延迟的场景。
- 移动端直播:FLV 在移动端解码兼容性良好。
DASH(Dynamic Adaptive Streaming over HTTP)
DASH 是 MPEG(ISO/IEC 23009)制定的基于 HTTP 的自适应码率流媒体标准。DASH 与 HLS 功能类似,但采用 XML 格式的 MPD(Media Presentation Description)清单和 fMP4 分片。
MPD 清单
DASH 使用 MPD 文件描述媒体流的元数据、分片信息、码率、分辨率等。MPD 基于 XML 格式,支持多种描述模式。
<?xml version="1.0" encoding="UTF-8"?>
<MPD
xmlns="urn:mpeg:dash:schema:mpd:2011"
profiles="urn:mpeg:dash:profile:isoff-live:2011"
type="dynamic"
availabilityStartTime="2026-07-12T10:00:00Z"
publishTime="2026-07-12T10:05:00Z"
minimumUpdatePeriod="PT2S"
timeShiftBufferDepth="PT1H"
minBufferTime="PT4S">
<Period id="1" start="PT0S">
<AdaptationSet mimeType="video/mp4" contentType="video"
width="1920" height="1080" frameRate="30"
segmentAlignment="true" startWithSAP="1">
<Representation id="v1" bandwidth="3500000"
codecs="avc1.640028">
<SegmentTemplate
timescale="90000"
duration="540000"
startNumber="0"
initialization="init-v1.mp4"
media="seg-v1-$Number$.m4s"/>
</Representation>
<Representation id="v2" bandwidth="2000000"
codecs="avc1.64001f">
<SegmentTemplate
timescale="90000"
duration="540000"
startNumber="0"
initialization="init-v2.mp4"
media="seg-v2-$Number$.m4s"/>
</Representation>
<Representation id="v3" bandwidth="1000000"
codecs="avc1.64001e">
<SegmentTemplate
timescale="90000"
duration="540000"
startNumber="0"
initialization="init-v3.mp4"
media="seg-v3-$Number$.m4s"/>
</Representation>
</AdaptationSet>
<AdaptationSet mimeType="audio/mp4" contentType="audio">
<Representation id="a1" bandwidth="128000"
codecs="mp4a.40.2">
<SegmentTemplate
timescale="44100"
duration="264600"
startNumber="0"
initialization="init-a1.mp4"
media="seg-a1-$Number$.m4s"/>
</Representation>
</AdaptationSet>
</Period>
</MPD>MPD 关键属性
| 属性 | 说明 |
|---|---|
type | static 表示点播,dynamic 表示直播 |
availabilityStartTime | 直播流的起始可用时间 |
publishTime | MPD 的发布时间,用于判断更新 |
minimumUpdatePeriod | MPD 更新周期(直播时不断更新) |
timeShiftBufferDepth | 时移回看的缓冲区深度,例如 PT1H 支持回看 1 小时 |
minBufferTime | 播放器最小缓冲时间 |
SegmentTemplate | 分片 URL 模板,支持 $Number$ 和 $Time$ 变量 |
Segment 分片
DASH 标准支持多种分片寻址方式:
- Segment Template:基于模板生成分片 URL,使用
$Number$(序列号)或$Time$(时间戳)变量。 - Segment Timeline:显式列出每个分片的时间和持续时间。
- Segment Base + Segment List:通过
SegmentURL元素直接列出所有分片 URL。
分片寻址模式示例:
1. Template (模板模式):
media="seg-v1-$Number$.m4s"
-> seg-v1-0.m4s, seg-v1-1.m4s, seg-v1-2.m4s
2. Timeline (时间线模式):
<SegmentTimeline>
<S t="0" d="540000" r="2"/> <!-- 从 0 开始,时长 540000 单位,重复 2 次 -->
<S t="1620000" d="540000"/> <!-- 从 1620000 开始,时长 540000 -->
</SegmentTimeline>
3. Base URL (直接列出):
<SegmentList>
<SegmentURL media="seg1.m4s"/>
<SegmentURL media="seg2.m4s"/>
</SegmentList>自适应码率
DASH 的 AdaptationSet 包含多个 Representation,每个 Representation 代表一个码率/分辨率版本。播放器根据网络条件动态选择不同的 Representation。
<AdaptationSet>
<!-- 高码率: 1080p, 3.5 Mbps -->
<Representation bandwidth="3500000" width="1920" height="1080" .../>
<!-- 中码率: 720p, 2.0 Mbps -->
<Representation bandwidth="2000000" width="1280" height="720" .../>
<!-- 低码率: 480p, 1.0 Mbps -->
<Representation bandwidth="1000000" width="854" height="480" .../>
<!-- 流畅: 360p, 0.5 Mbps -->
<Representation bandwidth="500000" width="640" height="360" .../>
</AdaptationSet>HLS vs FLV vs DASH 对比
| 特性 | HLS | HTTP-FLV | DASH |
|---|---|---|---|
| 标准制定者 | Apple | Adobe/社区实践 | MPEG |
| 清单格式 | M3U8 (文本) | 无清单 | MPD (XML) |
| 分片容器 | TS / fMP4 (CMAF) | FLV (流式) | fMP4 / MPEG-TS |
| 传输方式 | HTTP 分片请求 | HTTP 长连接流式 | HTTP 分片请求 |
| 默认延迟 | 6-30 秒 | 2-5 秒 | 6-30 秒 |
| 低延迟优化 | LL-HLS: 2-5 秒 | 不可优化(依赖 GOP) | LL-DASH: 2-5 秒 |
| 自适应码率 | 原生支持 | 不支持(需多路切换) | 原生支持 |
| 苹果生态 | 原生支持(iOS/macOS) | 不支持 | 有限支持 |
| Android 生态 | 支持 | 支持 | 支持 |
| Web 浏览器 | MSE 支持 | MSE + FLV 插件 | MSE 原生支持 |
| 防火墙穿透 | 好(HTTP 80/443) | 好(HTTP 80/443) | 好(HTTP 80/443) |
| 加密支持 | AES-128 / SAMPLE-AES | 依赖 HTTPS | AES-128 / SAMPLE-AES |
| 录制/时移 | 简单(分片持久化) | 困难(需转码) | 简单(分片持久化) |
| CDN 缓存友好 | 很好(静态分片缓存) | 较差(长连接维护成本高) | 很好(静态分片缓存) |
| 浏览器 MSE 支持 | 原生支持 | 需 flv.js 等 JS 解封装 | 原生支持(MediaSource) |
| 行业应用 | 点播/直播/电视 | 低延迟直播 | 多平台自适应分发 |
协议选择建议:
- 苹果生态全覆盖:HLS(TS 或 fMP4)。
- 低延迟互动直播:HTTP-FLV 或 LL-HLS。
- 跨平台自适应分发:HLS(CMAF)或 DASH。
- 需要统一交付:HLS + fMP4(CMAF)可同时服务 HLS 和 DASH 客户端。
- 监控/推流场景:HTTP-FLV,延迟低且实现简单。
CDN 分发
CDN 架构
CDN(Content Delivery Network)是直播分发的基础设施,通过在全球各地部署缓存节点,将直播流从源站就近分发给观众,有效降低回源压力和播放延迟。
分层架构
┌────────────────┐
│ 中心源站 │
│ (Origin) │
│ 直播服务器 │
└────────┬───────┘
│
┌─────────────┼─────────────┐
│ │ │
┌─────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐
│ 区域节点 A │ │ 区域节点 B │ │ 区域节点 C │
│ (华南) │ │ (华东) │ │ (华北) │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
┌─────────┼───────┐ ┌───┼───────┐ ┌───┼─────────┐
│ │ │ │ │ │ │ │ │
┌─────┴──┐ ┌────┴──┐ ┌─┴─┐ │ ┌─┴──┐ ┌─┴┐ │ ┌──┴──┐ ┌──┴──┐
│边缘节点1│ │边缘节点2│ │...│ │ │... │ │ │ │ │ ... │ │ ... │
│ (广州) │ │ (深圳) │ │ │ │ │ │ │ │ │ │ │ │ │
└───┬────┘ └───┬───┘ └───┘ │ └────┘ └───┘ │ └─────┘ └─────┘
│ │ │ │
┌───┴───┐ ┌───┴───┐ │ │
│播放器 1│ │播放器 2│ │ │
└───────┘ └───────┘ │ │
┌────┴────┐ ┌────┴────┐
│播放器 3 │ │播放器 4 │
└─────────┘ └─────────┘各层职责
- 中心源站:接收推流端上行流,提供转码和格式封装能力,是分发的唯一数据来源。
- 区域节点:缓存区域内热门直播流,减少跨区域回源流量。区域节点之间通常不互通。
- 边缘节点:直接服务终端观众,从区域节点或中心源站回源。边缘节点是最接近用户的层级。
缓存策略
直播 CDN 的缓存策略与点播 CDN 有显著差异:
- 分片粒度缓存:对于 HLS/DASH,CDN 按
.ts、.m4s分片粒度缓存,分片生成后即可缓存。 - GOP 级缓存:对于 HTTP-FLV,CDN 基于 GOP(Group of Pictures)边界缓存和转发。CDN 需要将 FLV 流按照 GOP 边界切分为缓存单元。
- 时间戳修正:CDN 边缘节点在转发 FLV 流时,需要对时间戳进行修正,确保连续性和递增性。
- 预缓存:对于热门直播流,CDN 提前从源站拉取分片到边缘节点,减少首次播放等待时间。