音视频编解码基础
RTMP 面试速成
一、30 秒版本(先给结论)
RTMP 是 Adobe(前身 Macromedia)设计的应用层流媒体协议,基于 TCP,默认端口 1935。它把音视频、元数据、控制命令切成带时间戳的消息,再拆成小的 Chunk 多路复用传输。连接先 C0/C1/C2 握手,再用 AMF 编码的命令(connect、createStream、publish/play)建立流,之后传输和 FLV tag 格式一致的音视频数据。
它延迟低(约 1~3 秒),主要用在推流端(OBS → CDN)。浏览器播放因为 Flash 淘汰,现在多用 HTTP-FLV、HLS 或 WebRTC。
后面是每个点的展开,让你被追问时答得下去。
二、协议全貌
1. 基本定位
- 传输层:TCP,所以可靠、有序,但存在队头阻塞,网络差时延迟会累积。
- 变种:
- RTMPS:RTMP over TLS
- RTMPE:Adobe 私有加密(不推荐)
- RTMPT:HTTP 隧道
- RTMFP:基于 UDP,和 RTMP 基本不是一回事
- 负载格式:音视频 payload 基本等同于 FLV tag body。所以 RTMP 和 HTTP-FLV 能很容易互转,这是个高频考点。
2. 握手(Handshake)
1 | Client Server |
- C0/S0:1 字节,版本号(3)。
- C1/S1:1536 字节 = 时间戳(4)+ 零(4)+ 随机数(1528)。
- C2/S2:分别是对 S1/C1 的回显。
- 区分简单握手和复杂握手。复杂握手在随机数里嵌入 HMAC-SHA256 摘要做校验,Flash Player 和部分 CDN 会要求。多数推流工具能自动适配。
3. Chunk(最核心,必考)
消息(Message)太大会阻塞别的消息,所以拆成 Chunk 传输。默认 chunk size = 128 字节,可用 Set Chunk Size 修改,实际常设 4096 或更大以减少头开销。
Chunk 结构:
1 | | Basic Header | Message Header | Extended Timestamp | Chunk Data | |
- Basic Header(1~3 字节):高 2 位是
fmt,低 6 位是 **chunk stream id(csid)**。csid 为 0 或 1 表示用 2 或 3 字节扩展 csid。 - Message Header 按 fmt 分 4 种,体现了”头部压缩”思想:
| fmt | 头长度 | 内容 | 典型场景 |
|---|---|---|---|
| 0 | 11 字节 | 绝对时间戳(3)+ 消息长度(3)+ 类型 ID(1)+ stream ID(4,小端) | 流的第一个消息 |
| 1 | 7 字节 | 时间戳差值 + 长度 + 类型 ID | 同一流,长度/类型变了 |
| 2 | 3 字节 | 仅时间戳差值 | 长度、类型都不变(如固定帧长音频) |
| 3 | 0 字节 | 全部沿用上一个 | 同一消息的后续 chunk |
- Extended Timestamp:时间戳 ≥ 0xFFFFFF 时,用 4 字节扩展。
- 为什么要分 Chunk? 多路复用(音频、视频、命令交织)、避免大 I 帧阻塞小的音频包或控制消息、头部压缩。
4. 消息类型(Message Type ID)
| ID | 含义 |
|---|---|
| 1 | Set Chunk Size |
| 2 | Abort Message |
| 3 | Acknowledgement |
| 4 | User Control Message(StreamBegin、PingRequest/Response 等) |
| 5 | Window Acknowledgement Size |
| 6 | Set Peer Bandwidth |
| 8 | 音频 |
| 9 | 视频 |
| 18 | 数据消息(AMF0,如 onMetaData) |
| 20 | 命令消息(AMF0) |
| 17 / 15 | AMF3 的命令 / 数据 |
ID 1~6 是协议控制消息,走 chunk stream id 2,message stream id 为 0。
5. AMF(命令的编码方式)
命令、元数据都用 AMF0(或 AMF3)序列化。常见 AMF0 类型:Number(0x00,8 字节 double)、Boolean(0x01)、String(0x02,2 字节长度前缀)、Object(0x03,以 00 00 09 结尾)、Null(0x05)、ECMA Array(0x08)。
命令消息的格式是:命令名(String)+ 事务 ID(Number)+ 命令对象(Object/Null)+ 参数。
6. 推流完整流程(面试时能画出来就很加分)
1 | 握手完成 |
拉流(play)类似:connect → createStream → play,服务端回 StreamBegin、NetStream.Play.Start,然后下发 metadata 和音视频数据。
7. 音视频 payload(和 FLV 一致)
视频(type 9):
- 第 1 字节:高 4 位 FrameType(1 = 关键帧,2 = 非关键帧),低 4 位 CodecID(7 = H.264)
- 第 2 字节:AVCPacketType(0 = Sequence Header,1 = NALU,2 = 序列结束)
- 3 字节 CompositionTime(CTS),PTS = DTS + CTS。RTMP 头里的时间戳是 DTS。
- 后面是 NALU,格式是 AVCC(4 字节长度前缀),不是 Annex-B 的 start code。
- Sequence Header 里是
AVCDecoderConfigurationRecord(含 SPS/PPS),播放端必须先拿到它才能解码。
音频(type 8):
- 第 1 字节:SoundFormat(10 = AAC)+ 采样率 + 位深 + 声道
- 第 2 字节:AACPacketType(0 = AudioSpecificConfig,1 = 原始 AAC 帧)
补充:原版 RTMP/FLV 只支持 H.264 等老编码。Enhanced RTMP(社区推动的扩展,用 FourCC 标识)加入了 HEVC、AV1、VP9 的支持,面试提一句说明你了解现状。
8. 流控
Window Acknowledgement Size:接收方每收到这么多字节,要回一个 Acknowledgement。Set Peer Bandwidth 用来限制对端发送速率,有 Hard / Soft / Dynamic 三种限制类型。
三、对比类问题
| RTMP | HTTP-FLV | HLS | WebRTC | |
|---|---|---|---|---|
| 传输 | TCP | HTTP 长连接 | HTTP 分片 | UDP(SRTP) |
| 延迟 | 约 1~3s | 约 1~3s | 5 |
<500ms |
| 浏览器 | 不支持 | 靠 MSE(flv.js) | 原生/MSE | 原生 |
| CDN 友好 | 一般 | 好 | 最好 | 较差 |
| 典型用途 | 推流 | 播放 | 播放、兼容 | 连麦、超低延迟 |
要点:RTMP 和 HTTP-FLV 的数据内容一样,区别在于传输层,所以 CDN 常见做法是 “RTMP 推流 + HTTP-FLV / HLS 分发”。
四、高频追问和答法
- 为什么延迟会越来越大? TCP 在弱网下重传和拥塞控制会堆积数据。服务端或播放器可以做追帧(加速播放或丢帧追赶),服务端也可以在发送缓冲堆积时**丢帧(优先丢非关键帧,或整个 GOP)**。
- 怎么做到秒开? 服务端缓存 Sequence Header + 最近一个 GOP,新观众连上先收这些,马上能出画面。GOP 越长,秒开越难。
- 时间戳怎么处理? 头里是毫秒级 DTS,且会溢出到 32 位(约 49 天)。要处理时间戳回绕、跳变,拉流端和转封装时必须校正。
- 推流失败怎么排查? 看顺序:网络和 1935 端口 → 握手是否成功 → connect 是否被拒(app 名、鉴权) → publish 的 stream key 是否正确或被占用 → 服务端回的 onStatus 错误码。
- RTMP 的缺点? TCP 队头阻塞、延迟下限受限、无原生浏览器支持、编码支持老旧(靠 Enhanced RTMP 补)、没有内置 FEC 或自适应码率。替代方案有 SRT、WebRTC(WHIP 推流)。
五、2 分钟面试回答模板
RTMP 是基于 TCP 的应用层流媒体协议,默认 1935 端口。
连接过程:先 C0/C1/C2 三次握手,然后通过 AMF 编码的命令消息依次做 connect、createStream、publish 或 play 来建立流。
传输方式:数据按消息传输,消息再拆成 Chunk,默认 128 字节,可调整。Chunk 头有 4 种格式,可以压缩重复字段,同时支持音视频和控制消息多路复用,避免大帧阻塞。
载荷:音视频消息的格式和 FLV tag 一致,H.264 要先发 Sequence Header(SPS/PPS),再发 AVCC 格式的 NALU,时间戳是毫秒级 DTS,PTS 靠 CompositionTime 计算。
应用场景:延迟大约 1~3 秒,现在主要用于推流,播放端因为浏览器不支持,通常转成 HTTP-FLV、HLS 或 WebRTC。缺点是 TCP 弱网下延迟会累积。
如果你简历里有直播播放器、拉流或解码相关的项目,可以在最后接一句”我在项目里处理过 xx(比如 Sequence Header 缺失导致花屏、时间戳跳变、延迟追赶)”,这比背协议更能打动面试官。
六、建议的下一步
最好亲手抓一次包:用 OBS 推流到本地 nginx-rtmp(或 SRS),用 Wireshark 过滤 rtmpt 看握手、chunk 头、connect 命令,印象会比背诵深得多。需要的话,我可以接着出一组模拟面试题,你来答,我来点评。
回显(echo)就是:把对方发来的数据原样(或基本原样)再发回给对方。
在 RTMP 握手里怎么回显
1 | Client Server |
注意是交叉对应:
- S2 回显的是客户端发来的 C1
- C2 回显的是服务端发来的 S1
回显具体回了什么
以 C2 为例(S2 同理),1536 字节的结构是:
| 字段 | 长度 | 内容 |
|---|---|---|
| time | 4 字节 | 抄 S1 里的时间戳 |
| time2 | 4 字节 | 收到 S1 时自己的时间戳 |
| random echo | 1528 字节 | 抄 S1 里的随机数 |
所以严格来说,大部分内容是原样抄回去,中间有 4 字节是填自己收到包的时间。我前面说”回显”是简化说法,面试时说”基本是原样返回对方的数据”就够了。简单握手里很多实现就是直接把整个包拷贝回去。
为什么要回显
- 确认对方收到了:你发的随机数,对方原样返回,说明链路双向通了,对方也确实读到了你的包。
- 验证对方的身份和有效性:随机数对得上,说明对方不是乱发数据的。
- 可以测往返时延:对方回的 time 是你当初发的时间戳,time2 是它收到的时间,据此能估算 RTT。
这里的回显只是握手确认,不是安全机制。真正带校验的是复杂握手里的 HMAC-SHA256 摘要。
HTTP-FLV / HLS / RTSP 面试速成
一、先记住它们的定位
| 协议 | 一句话 |
|---|---|
| HTTP-FLV | 把 RTMP 里的那份 FLV 数据,改用 HTTP 长连接持续下发。内容和 RTMP 一样,只是传输方式不同 |
| HLS | 把直播流切成几秒一个的小文件,用 m3u8 索引,播放器像下载文件一样轮流拉取。延迟高,兼容性和 CDN 友好度最好 |
| RTSP | 一个控制协议(像遥控器),只负责建立会话和播放控制。真正的音视频由 RTP/RTCP 传输。安防摄像头的标配 |
二、HTTP-FLV
30 秒版本
HTTP-FLV 是把 FLV 格式的音视频流通过 HTTP 长连接持续下发的方案。响应不带 Content-Length,使用 chunked 传输,服务器一直往连接里写 FLV tag。它的数据和 RTMP 同源,所以 CDN 通常”RTMP 推流,HTTP-FLV 分发”。延迟约 1~3 秒,浏览器端靠 MSE 解封装播放,比如 flv.js。
1. 先搞懂 FLV 容器格式(必考)
1 | FLV Header (9 字节) |
- FLV Header:
'F' 'L' 'V'+ 版本(1)+ 标志位(0x05 表示有音频和视频)+ 头长度(9)。 - Tag Header 共 11 字节:
| 字段 | 长度 | 说明 |
|---|---|---|
| TagType | 1 | 8 音频,9 视频,18 脚本数据(onMetaData) |
| DataSize | 3 | tag body 长度 |
| Timestamp | 3 | 低 24 位,毫秒 |
| TimestampExtended | 1 | 时间戳高 8 位 |
| StreamID | 3 | 恒为 0 |
- PreviousTagSize(4 字节)= 11 + DataSize,用于从后往前解析文件。直播里用不上,但格式要求带上。
- Tag Body 的内容和上次讲的 RTMP 音视频 payload 完全一致(视频的 FrameType/CodecID/AVCPacketType/CTS + AVCC NALU,音频的 AAC 两种包类型)。
2. RTMP 怎么转 HTTP-FLV
RTMP 消息类型 8/9/18 的 payload 直接就是 FLV tag body。服务器只需要:
- 先发 FLV Header + PreviousTagSize0
- 发 onMetaData 脚本 tag、音视频 Sequence Header
- (为了秒开)发缓存的最近一个 GOP
- 之后每收到一个 RTMP 音视频消息,套上 11 字节 tag header,再补上 PreviousTagSize,写入 HTTP 响应
3. HTTP 层
Content-Type: video/x-flv,Transfer-Encoding: chunked,没有 Content-Length,连接保持不断。- 注意:这里的 HTTP chunked 和 RTMP 的 Chunk 不是一回事,面试别混。
4. 播放端
浏览器不能直接播 FLV,flv.js 之类的库做的是:fetch + ReadableStream 读取流 → 在 JS 里解析 FLV → 转封装成 fMP4 → 喂给 MSE(Media Source Extensions) 的 SourceBuffer。所以浏览器要能解码 H.264/AAC,并支持 MSE。桌面端播放器(ffmpeg、mpv 等)则直接支持 FLV over HTTP。
优缺点
- 优点:延迟低;走 HTTP/HTTPS(80/443),穿防火墙、对 CDN 友好;实现简单。
- 缺点:仍是 TCP,有队头阻塞,弱网延迟会累积;浏览器依赖 MSE;没有原生自适应码率;原版 FLV 编码支持老旧(靠 Enhanced FLV 扩展 HEVC/AV1)。
三、HLS
30 秒版本
HLS 是 Apple 提出的基于 HTTP 的自适应流媒体协议。服务器把流按关键帧切成几秒一个的分片(TS 或 fMP4),用 m3u8 播放列表索引。直播时播放列表是滑动窗口,播放器不断刷新列表、下载新分片。它天然支持多码率切换,兼容性和 CDN 缓存效果最好,但传统延迟在 10
30 秒,LL-HLS 可降到 25 秒左右。
1. 整体结构
1 | Master Playlist (多码率入口) |
Master Playlist(多码率清单):
1 | #EXTM3U |
Media Playlist(直播):
1 | #EXTM3U |
关键标签:
| 标签 | 含义 |
|---|---|
#EXT-X-TARGETDURATION |
分片最大时长(秒,整数) |
#EXT-X-MEDIA-SEQUENCE |
列表中第一个分片的序号,窗口滑动时递增 |
#EXTINF |
下一个分片的时长 |
#EXT-X-ENDLIST |
表示流结束(点播有,直播没有) |
#EXT-X-DISCONTINUITY |
编码参数或时间戳不连续(如换流、广告插入) |
#EXT-X-KEY |
加密信息(AES-128 等) |
#EXT-X-MAP |
fMP4 的初始化段(init segment) |
2. 分片格式
- MPEG-TS:固定 188 字节包,有 PAT/PMT 表描述节目,音视频打包成 PES。老方案,兼容性极好。
- fMP4(CMAF):较新(协议版本 7 起),开销更小,可与 DASH 共用一套分片,HEVC 也只能走 fMP4。
3. 直播工作流程
- 推流端(通常 RTMP)→ 服务器
- 服务器按关键帧切片,所以 GOP 必须和分片对齐(例如 GOP 2 秒,分片 6 秒就是 3 个 GOP)
- 每切好一片,更新 m3u8,删掉最老的分片(滑动窗口)
- 播放器下载 m3u8 → 下载分片 → 解码播放,并按分片时长周期性刷新 m3u8
4. 为什么延迟高
规范建议播放器直播时不要从距列表末尾不足 3 个 TargetDuration 的位置开始播放。所以延迟的下限大约是 3 × 分片时长,再加上切片、CDN 传播和播放器缓冲。分片 6 秒,延迟就是 18 秒起步。降延迟的办法是缩短分片和 GOP,但分片越小,请求数越多,CDN 压力越大。
5. LL-HLS(低延迟 HLS)
核心思想是不等整个分片切完就开始发:
- Partial Segment(
#EXT-X-PART):分片再细分成几百毫秒的小块,生成后就能被请求。 - Blocking Playlist Reload:播放器请求带上期望的
_HLS_msn/_HLS_part,服务器挂起请求,直到该片段可用才响应,不用频繁轮询。 - Preload Hint(
#EXT-X-PRELOAD-HINT):提前告知下一个小块的地址,播放器可预先发请求。
延迟约 2~5 秒。
优缺点
- 优点:纯 HTTP,CDN 缓存友好、可扩展性最强;iOS/Safari/Android 原生支持;天然多码率自适应;支持 DRM(FairPlay)。
- 缺点:延迟高;分片和列表带来额外存储与请求开销;低延迟版本实现复杂。
四、RTSP
30 秒版本
RTSP 是一个应用层的流媒体控制协议,文本格式,语法类似 HTTP,默认端口 554。它负责会话的建立和播放控制(OPTIONS、DESCRIBE、SETUP、PLAY、TEARDOWN 等),会话描述用 SDP,真正的音视频数据由 RTP 承载,RTCP 做质量反馈和音视频同步。传输可以走 UDP,也可以通过 TCP 交织(interleaved)复用在同一条连接上。常用于 IP 摄像头和安防监控,延迟可以做到很低,但浏览器不支持。
1. 核心方法
| 方法 | 作用 |
|---|---|
| OPTIONS | 询问服务器支持哪些方法 |
| DESCRIBE | 获取媒体描述(返回 SDP) |
| SETUP | 为每条轨道(音频、视频)协商传输方式,建立会话 |
| PLAY | 开始播放 |
| PAUSE | 暂停 |
| TEARDOWN | 结束会话 |
| ANNOUNCE / RECORD | 推流方向(把流发给服务器) |
| GET_PARAMETER | 常用作保活心跳 |
2. 典型交互流程
1 | C→S: OPTIONS rtsp://host/live RTSP/1.0 |
- 每个请求带 CSeq(序列号),会话靠 Session 头标识。
- 有会话超时(默认约 60 秒),需要心跳保活。
- 认证支持 Basic 和 Digest(返回 401 后重发带认证头的请求)。
3. SDP:会话描述
1 | m=video 0 RTP/AVP 96 |
SDP 告诉客户端有几路媒体、什么编码、时钟频率、各轨道的控制 URL。H.264 的 SPS/PPS 常放在 sprop-parameter-sets 里,所以 RTSP 不像 RTMP 那样靠 Sequence Header 包带参数集。
4. 数据传输方式(重点)
| 方式 | 特点 |
|---|---|
| RTP over UDP | 延迟最低;偶发丢包会花屏;穿 NAT/防火墙麻烦。RTP 用偶数端口,RTCP 用相邻奇数端口 |
| RTP over TCP(interleaved) | RTP 数据复用在 RTSP 的 TCP 连接里,可靠、穿防火墙容易,代价是有队头阻塞 |
| RTSP over HTTP 隧道 | 穿透严格网络 |
交织模式下,数据格式是:'$'(0x24) + channel(1 字节) + length(2 字节) + RTP/RTCP 包。通道号 0/1 通常对应视频的 RTP/RTCP,2/3 对应音频。
5. RTP 和 RTCP
RTP 头(固定 12 字节):版本(2 位)、P、X、CC、M(Marker)、PT(负载类型)、序列号(16 位)、时间戳(32 位)、SSRC。
- 序列号:接收端用来检测丢包和乱序。
- 时间戳:是媒体时钟,不是毫秒。视频固定 90 kHz,音频等于采样率。
- M 位:视频中通常标记一帧的最后一个包。
H.264 的 RTP 封装(RFC 6184):
- Single NAL:一个 NALU 一个包(小 NALU,如 SPS/PPS)
- STAP-A:多个小 NALU 聚合成一个包
- FU-A:大 NALU(如 I 帧)按 MTU(约 1400 字节)分片,接收端重组
RTCP:SR/RR 报告丢包率和抖动;SR 里带 NTP 时间 ↔ RTP 时间戳的对应关系,接收端靠它做音视频同步(音频和视频的 RTP 时钟不同,不经 RTCP 对齐无法同步)。
优缺点
- 优点:延迟低(UDP 下可到几百毫秒);标准化,摄像头和 NVR 普遍支持(ONVIF 生态);控制能力强(暂停、倍速、定位)。
- 缺点:浏览器不支持;UDP 穿 NAT 难;不适合大规模 CDN 分发;不同厂商实现差异大,兼容坑多。
RTSP 和 RTMP 的本质区别
- RTMP:控制和数据混在一条 TCP 连接里,协议自带 Chunk 复用。
- RTSP:控制通道和数据通道分离(控制走 TCP,数据通常走 UDP RTP)。
- 时间戳也不同:RTMP 是毫秒级 DTS,RTSP/RTP 是媒体时钟(90 kHz),需要 RTCP 才能映射到绝对时间。
五、四个协议总对比
| RTMP | HTTP-FLV | HLS | RTSP/RTP | |
|---|---|---|---|---|
| 层级 | 应用层,完整协议 | HTTP + FLV 容器 | HTTP + 分片 | 控制协议 + RTP 数据 |
| 传输 | TCP | TCP(HTTP) | TCP(HTTP) | UDP 或 TCP 交织 |
| 延迟 | 1~3s | 1~3s | 传统 10 |
0.1~1s |
| 浏览器 | 不支持 | MSE(flv.js) | 原生/MSE | 不支持 |
| CDN 友好 | 一般 | 好 | 最好 | 差 |
| 自适应码率 | 无 | 无 | 有 | 无 |
| 典型场景 | 推流 | 直播播放 | 兼容性播放、点播 | 摄像头、监控 |
一个典型的直播链路:
1 | OBS ──RTMP──→ 源站(SRS/nginx-rtmp)──→ HTTP-FLV(Web/App 播放) |
六、高频追问
- HTTP-FLV 和 RTMP 的区别? 数据格式同源(都是 FLV tag body),RTMP 是私有协议自带 Chunk 复用和命令交互;HTTP-FLV 就是 HTTP 响应里持续写 FLV。HTTP-FLV 更容易过防火墙、走 CDN,也方便做鉴权和统计。
- 为什么直播推流用 RTMP,播放却不用? RTMP 只能靠 Flash 在浏览器播放,Flash 淘汰后没有原生支持;推流端(OBS、编码器)实现成熟,所以推流继续沿用。
- HLS 怎么降延迟? 缩短分片和 GOP;改用 fMP4 + LL-HLS(Partial Segment + 阻塞刷新);播放器缩小缓冲、调整起播位置。代价是请求量增加。
- RTSP 为什么经常花屏? UDP 丢包导致 NALU 分片(FU-A)不完整,解码出错,直到下一个关键帧才恢复。解决:改 TCP 交织传输,或接收端检测序列号缺口后丢弃整帧并等待 I 帧。
- RTSP 的 SDP 里没有 SPS/PPS 怎么办? 部分摄像头会在码流中周期性插入 SPS/PPS(随 I 帧发送),解码器要从码流里解析,不能只依赖 SDP。
- HLS 的分片为什么必须从关键帧开始? 每个分片要能独立解码,播放器可能从任意分片起播或切换码率,不以 IDR 开头就花屏;多码率时各档位的分片边界还要对齐,才能无缝切换。
七、建议
如果你的项目里拉过 B 站这类直播流,面试时可以主动讲你实际接触到的协议(FLV 流还是 HLS 分片)、遇到过的问题(起播黑屏、时间戳跳变、断流重连),这比背协议细节更有说服力。
动手验证的话,可以用 ffprobe/ffplay 分别拉 HTTP-FLV、HLS、RTSP 流,再配合 Wireshark 看报文,印象会很深。
需要的话,我可以把 RTMP / HTTP-FLV / HLS / RTSP / WebRTC 合在一起出一套模拟面试题,你先答,我再逐题点评。
是的,HTTP-FLV 通常用 HTTP/1.1 的 Transfer-Encoding: chunked,但它和 RTMP 的 Chunk 名字相同,作用完全不同。 先把这几个”分片”分到不同层级,就不会混了。
一、HTTP chunked 是什么
HTTP 响应的长度未知(直播永远不结束),所以不能写 Content-Length。HTTP/1.1 的解决办法是分块编码,每块的格式是:
1 | <十六进制长度>\r\n |
要点:
- 它只是传输层的”定界”手段,告诉客户端”这一块有多长,流还没结束”。
- 块边界和 FLV tag 边界没有任何关系。一个 FLV tag 可能跨多个 HTTP 块,一个块里也可能有好几个 tag。客户端的 HTTP 库会先拆掉 chunked 封装,应用层(比如 flv.js 用
fetch的ReadableStream)拿到的只是一条连续的字节流,自己按 FLV 格式解析。 - 不是必须用 chunked:HTTP/1.0 风格的”不带长度,服务器关闭连接表示结束”也可以。HTTP/2、HTTP/3 里根本没有 chunked 编码,数据靠 DATA 帧传输,流式下发照样成立。
二、和 RTMP Chunk 的区别
| HTTP chunked | RTMP Chunk | |
|---|---|---|
| 层级 | HTTP 传输编码 | RTMP 应用层协议自己的格式 |
| 目的 | 在不知道总长度时定界 | 多路复用,让大消息不阻塞小消息 |
| 多路复用 | 没有,一个响应就是一条串行字节流 | 有,不同 csid 的 chunk 可以交织发送 |
| 头部 | 只有长度 | fmt 0/1/2/3 四种头,压缩重复字段 |
| 是否理解内容 | 完全不理解数据是什么 | 知道消息类型、流 ID、时间戳 |
| 块大小 | 由服务器随意决定 | 默认 128 字节,可用 Set Chunk Size 协商 |
| 与媒体边界的关系 | 无关 | 一个 Message 拆成多个 Chunk,接收端按 csid 重组回完整 Message |
核心区别:RTMP 的 Chunk 是为了让音频、视频、控制命令在同一条 TCP 连接里穿插传输(比如一个几百 KB 的 I 帧拆开发,中间可以插入音频包),HTTP chunked 只是一条流的长度标记,不存在交织。
HTTP-FLV 能做到的”音视频同时下发”,靠的是 FLV 容器本身把音视频 tag 按时间顺序串行排好,而不是靠多路复用。所以它的音视频 tag 必须在服务器端就按时间戳顺序交错写入,而 RTMP 是由 chunk stream id 区分。
三、这几个协议里的”分片”各是哪一层
可以把所谓”分片”分成三个层面:
| 层面 | 谁在做 | 粒度 | 目的 |
|---|---|---|---|
| ① 传输/定界 | HTTP chunked、RTMP Chunk、TCP 分段 | 字节~KB | 在字节流上划分边界、复用 |
| ② 媒体打包 | RTP 的 FU-A、TS 的 188 字节包 | 约 188 B~1.4 KB | 适配网络 MTU、便于丢包恢复 |
| ③ 内容切片 | HLS 的 TS/fMP4 分片、LL-HLS 的 Part | 秒级 / 百毫秒级 | 让每个文件可独立下载、缓存、解码 |
逐个协议对照:
| 协议 | 分片方式 | 边界是否有媒体语义 | 丢包/出错时 |
|---|---|---|---|
| RTMP | Message → Chunk(默认 128 B) | 无。Chunk 只是搬运单位 | 跑在 TCP 上,由 TCP 重传,应用层不处理丢包 |
| HTTP-FLV | 无自己的分片,一条持续 HTTP 响应,底层可能是 HTTP chunked | 无。边界靠 FLV tag 自己的长度字段 | 同样由 TCP 重传 |
| HLS | 按关键帧切成多秒的文件,每片可独立解码 | 有,必须从 IDR 开始,片间边界对齐 | 某个分片下载失败可重试或换码率,影响限于这一片 |
| RTSP/RTP | 一帧按 MTU 拆成多个 RTP 包(FU-A),用序列号标识 | 有部分语义:M 位标记帧尾,时间戳相同的包属于同一帧 | UDP 丢包由接收端用序列号检测,只能丢弃整帧并等下一个关键帧 |
四、一个容易混淆的点:RTMP Chunk 不是为了适配 MTU
RTMP 的 Chunk 大小(128 B 或 4096 B)和网络 MTU 没关系,TCP 层会自己再分段。拆 Chunk 是为了应用层的公平调度和头部压缩。而 RTP 的 FU-A 分片才是专门按 MTU 来切的,因为 UDP 没有分段重组能力,IP 层分片还会放大丢包影响。
五、面试回答模板
HTTP-FLV 用的 chunked 是 HTTP/1.1 的传输编码,用来在响应长度未知时定界,和 FLV 的 tag 边界无关,客户端拿到的是连续字节流;HTTP/2 以后甚至没有 chunked。RTMP 的 Chunk 是协议自己的应用层机制,把 Message 拆成小块,不同 chunk stream 可以交织,解决大帧阻塞小包的问题,并通过 fmt 0~3 压缩头部。HLS 的分片是内容层面的切片,按关键帧切成几秒的独立文件。RTP 的分片是按 MTU 把一帧拆成多个包,靠序列号检测丢包。四者层级和目的都不同。

