🎬 第一章 音视频及流媒体播放原理
📄 一句话概括

五个协议不是一个东西的五个版本,是五个位置上的不同工具。 RTMP 管推、HLS 管分发、RTSP 管监控、HTTP-FLV 补延迟、WebRTC 管互动——认位置比背参数有用。

📝 本节和前面几节的关系

上一节讲了传输方式的三种复制模式与两种时间属性,这一节把它们落到具体协议上。 看这一节要带着一个问题:不背端口号,只问「它解决了哪一段的问题,代价是什么」。 协议细节在 🎬 流媒体直播原理及应用 里讲得更深。

一、先分清它站在哪一层

最容易混的地方是把不同层的协议拿来比较:RTMP 是「应用层协议」, HLS 是「一套基于 HTTP 的封装约定」, RTP 是「传输音视频的载荷格式」——它们本来就不在同一个平面上。

协议 底层 默认端口 主要用途
RTMP TCP 1935 推流入口
RTSP TCP 或 UDP 554 监控点播、摄像机
HLS HTTP 80/443 大规模分发
HTTP-FLV HTTP 80/443 低延迟分发
WebRTC UDP 动态 双向互动

看「底层」这一列最有信息量:走 TCP 的怕丢包(一丢就等重传),走 UDP 的怕乱序(要靠自己排), 走 HTTP 的好处是能穿过一切防火墙、能被 CDN 缓存。

二、RTMP:曾经的王者,今天的入口

RTMP 是 Adobe 为 Flash 设计的,跑在 TCP 上,封装 FLV,默认 1935 端口。

它的历史地位来自一个事实:当年几乎所有浏览器都装了 Flash, 所以 RTMP 是唯一能「在网页里看实时流」的方案。Flash 一退役,这条路的终点就定了。

但 RTMP 没有死,它换了个位置活下来:今天它主要做「推流入口」——OBS、编码器、 手机 App 推给服务器,几乎都用它。

为什么推流还用它: 协议简单、实现成熟,所有编码器都支持。 TCP 保证不丢,推流这一段带宽通常够,不怕重传。 延迟一到三秒,对「推」这个方向足够了。

它不适合做播放的原因也很明确:TCP 的队头阻塞——一个包丢了,后面所有包都得等它重传, 观众看到的是整体卡住。而 UDP 系协议丢掉一个包只是糊一下。

三、RTSP:监控行业的老标准

RTSP 更像「遥控器」,它本身不传音视频——它负责「播放/暂停/快进/设置参数」这些命令, 真正的数据由 RTP 传、由 RTCP 做质量反馈。

这个分工让它在监控与IPTV里活得很好:摄像机是「服务器」,客户端发 RTSP 命令, 数据走 RTP(通常 UDP)。它的延迟能做到半秒到两秒,比 HLS 低一个数量级。

它的麻烦在于「穿透」:用 UDP 时常常过不了 NAT 与防火墙,改成 TCP 又损失了低延迟的优势。 所以同一台摄像机,局域网里流畅、外网就卡,这是 RTSP 最常见的抱怨。

今天的现实是:新装的监控大量转向「RTSP 转 WebRTC」或「RTSP 转 HLS」,因为浏览器不再支持插件, RTSP 没法直接播。RTSP 保住了「设备侧接口」的位置,丢掉了「播放侧」的位置。

四、HLS:把直播变成一堆文件

HLS 的思路非常不一样:它不传流,它传文件。 发送端把流切成几秒一个的 TS 片段,再写一个播放列表(m3u8)说明顺序。 播放器按列表逐个下载、逐个播放。

这个设计带来三个巨大的好处: 它只是 HTTP,能穿过任何防火墙,能被任何 CDN 缓存。 天然支持多码率——列表里可以同时列 360p、720p、1080p,播放器自己挑。 切片是独立可解的,所以拖动、回看、断点续播都变得简单。

代价就是延迟:播放器至少要先拿到一个完整片段才能播, 常规配置下延迟就是「三倍切片时长」——切片 6 秒,延迟 18 秒左右。

所以「低延迟 HLS」做的全是同一件事:把切片切短。切片缩到 1 秒,延迟能压到 3 秒以内, 但请求数翻六倍,CDN 的日志与回源压力跟着涨——这就是它的天花板。

五、HTTP-FLV 与 WebRTC:两头补位

HTTP-FLV 是「用 HTTP 传一个不结束的 FLV」:服务器一直往响应里写数据,客户端一直读。 延迟一到三秒,和 RTMP 一样。

它的价值在于「既低延迟又能穿墙」:因为走 HTTP,能过防火墙、能挂 CDN,比 RTMP 好部署。 代价是它需要长连接,CDN 的并发连接数压力比 HLS 大得多。

WebRTC 是另一个极端:它天生为「双向、超低延迟」设计。基于 UDP、走 SRTP 加密, 延迟能压到几百毫秒甚至更低。

它的成本在「连接建立」:要交换 SDP、要打洞(ICE/STUN/TURN),要处理各种 NAT 类型。 所以它不适合「一万个人看同一个直播」——每个观众都要单独建立连接,服务器得为每条连接维持状态。

今天的主流架构是「混合」:推流用 RTMP 或 SRT 进服务器,服务器转成多种格式, 普通观众走 HLS 或 HTTP-FLV,需要连麦的少数人走 WebRTC。

六、怎么选:问三个问题

不用背表,问三个问题就够了:

第一问:延迟要求是多少? 秒级以上 → HLS,最省事、最便宜。 一到三秒 → HTTP-FLV 或 RTMP 系。 亚秒级 → WebRTC 或 SRT。

第二问:规模有多大? 十万级并发 → 必须能挂 CDN,只能选 HTTP 系。 几十人互动 → WebRTC 的连接受不了太多,得靠 SFU 帮转。

第三问:要不要互动? 只看 → 单向协议足够。 要连麦、要远程控制 → 必须双向,只能 WebRTC。

三问的答案常常互相打架,那就是工程的取舍点:既要超低延迟又要十万并发, 今天的答案是「大部分走 HLS、少数走 WebRTC」的两套并行。

七、动手 Demo:五个协议,各自解决哪一段

这段列五个协议的定位与延迟量级,再真查本机支持哪些封装格式。 最后那张表的意义是「提醒自己别把格式名当协议名」。

rows = ((u"RTMP", u"TCP", u"1935", u"FLV", u"1~3 秒"),
        (u"RTSP", u"TCP/UDP", u"554", u"RTP", u"0.5~2 秒"),
        (u"HLS", u"HTTP", u"80/443", u"TS 或 fMP4", u"6~30 秒"),
        (u"HTTP-FLV", u"HTTP", u"80/443", u"FLV", u"1~3 秒"),
        (u"WebRTC", u"UDP", u"动态", u"SRTP", u"0.1~0.5 秒"))

fmts = av.formats_available      # 这是「容器名」集合,不是协议表
for name in (u"flv", u"mpegts", u"hls", u"rtsp", u"rtmp"):
    T([name, u"在" if name in fmts else u"不在", u""], [0, 0, 0])

实跑输出:

--------------------------------------------------------------------
五个协议,各自解决哪一段
--------------------------------------------------------------------
**流媒体协议不是一个东西的五个版本,而是五个位置上的不同工具。**

  协议         传输         端口        封装           延迟量级
  -------------------------------------------------------------------
  RTMP         TCP          1935        FLV            1~3 秒
  RTSP         TCP/UDP     554         RTP            0.5~2 秒
  HLS          HTTP         80/443     TS 或 fMP4     6~30 秒
  HTTP-FLV     HTTP         80/443     FLV            1~3 秒
  WebRTC       UDP          动态        SRTP           0.1~0.5 秒

**延迟差在哪**:HLS 是把流切成几秒一个的切片文件,播放器下一片之前要等它生成完。
  切片短一点延迟就低一点,但请求数上去了,CDN 的日志与开销跟着涨。
  **这就是「低延迟 HLS」要解决的矛盾:切片越短越好,但越短越贵。**

**RTMP 延迟不高,为什么不做播放?** 因为它跑在 TCP 上,丢包会整体卡住等重传;
而且浏览器早就不支持了(Flash 退役)。它今天的定位是**推流入口**,不是分发出口。

**本机 PyAV 自查,哪些封装能用**:

  名字       在不在     说明
  --------------------------------------------------
  flv        在         RTMP 与 HTTP-FLV 的封装
  mpegts     在         HLS 切片与数字电视的封装
  hls        在         HLS 的输出格式
  rtsp       在         RTSP 的封装
  rtmp       不在       RTMP 的封装

**注意这张表查的是「容器/格式名」,不是协议名。**
**协议能不能通,只有真开一次才知道**——32 课踩过这个坑:`rtmp` 不在表里,
可 `av.open` 照样返回成功,写第一包也不报错,冲空包才炸。

最后一行 rtmp 不在,这一行值得单独说。它不代表「本机不能 RTMP」——它只说明 rtmp 这个名字不在「封装格式」的表里。

32 课在这里踩过一个坑,值得原样搬过来:当时真去开了一次 rtmp://,av.open 立刻返回成功、 写第一个包也不报错, 冲空包的时候才炸——「能打开」不等于「能工作」,协议类的判断只能靠真发一次数据。

所以这张表正确的读法是: 它在告诉你「哪些容器的读写是本机编译进来的」,而不是「哪些协议能用」。判协议要另做一次阴性对照:拿一个肯定不存在的地址去开,看报错是否不同。

30 秒实验

  1. 用浏览器开发者工具打开任意一个视频网站,看它请求的是 m3u8 还是 flv。
  2. 看播放器源码里有没有 #EXT-X-TARGETDURATION,那个值就是切片时长。
  3. 想一想:为什么监控摄像头偏爱 RTSP,而直播平台偏爱 HLS?

常见误区

  1. 以为 HLS 延迟高是因为「技术落后」。 延迟高是它的设计前提——用延迟换穿透性、可缓存、可拖动。
  2. 把 RTMP 当成「过时的协议」。 它丢掉了播放,但保住了推流,今天绝大多数直播的入口还是它。
  3. 以为 WebRTC 能替代一切。 它的连接成本随观众数线性增长,大规模单向分发用它非常不划算。
自测三问(点开对答案) 1. HLS 的延迟为什么大约是切片时长的三倍? —— 要等一个片段生成完、再下载下来、再缓冲一个,三段加起来大致是三个切片时长。 2. RTSP 里 RTSP、RTP、RTCP 各管什么? —— RTSP 管命令(播放、暂停、设置参数),RTP 管数据,RTCP 管质量反馈。 3. 为什么推流用 RTMP 而不直接用 HLS? —— 推流要的是「实时把数据送上去」,RTMP 是一路持续连接,延迟一两秒; HLS 要先切片再发布,推流侧用它会平白多出几秒延迟。

协议定了「怎么送」,但观众最终看到的是播放器画出来的画面。下一节拆开播放器, 看一条数据从进来到上屏要过几道手。

相关笔记