协议按传输层分成两派:UDP 派(RTSP/WebRTC)追低延迟,TCP/HTTP 派(RTMP/HLS/HTTP-FLV)追穿透与并发。没有最好的,只有代价你付得起的那一个。
1.2.2 把四层拆开了,这一节看第 ④ 层(会话层)上有哪些选手。后面第 2~6 章会一个一个拆开讲——这里先给一张全局地图,别到后面迷路。
一、按传输层分两派
所有流媒体协议,第一刀按「跑在 UDP 还是 TCP 上」切开。
UDP 派:RTSP(RTP over UDP)、WebRTC、SRT。 优点是丢了就丢了、不等重传,所以延迟最低; 缺点是要自己处理丢包、乱序、拥塞,而且防火墙讨厌 UDP。 TCP/HTTP 派:RTMP、HLS、HTTP-FLV、DASH。 优点是走 80/443,任何网络都能过; 缺点是一个包丢了全队等——队头阻塞。
这个分野决定了很多事: 监控、视频会议用 UDP 派,因为延迟是第一位的; 直播、点播用 HTTP 派,因为要过 CDN、要扛并发。
二、五个主流协议各自的来路
① RTSP(1998):RealNetworks 与 Netscape 一起搞的,像「遥控器」——PLAY、PAUSE、TEARDOWN 都是命令。 真正传数据的是 RTP/RTCP。监控行业至今是它的天下。 ② RTMP(2002):Flash 时代的产物,跑在 1935 端口的 TCP 长连接上。 Flash 死了它却没死——因为「推流」这块它太成熟,OBS、FFmpeg 都默认推 RTMP。 ③ HLS(2009):苹果为 iPhone 不支持 Flash 而造。把流切成几秒的 ts 文件,用 m3u8 当播放列表,全部走普通 HTTP GET。延迟高,但 CDN 天生就吃这一套。 ④ HTTP-FLV(2010 年代):中国公司搞出来的折中——把 FLV 的 Tag 一个接一个写进 HTTP 响应体,不封口,一直流。既走了 80 端口,又不用切片,延迟能压到 1 秒内。 ⑤ WebRTC(2011):Google 开源,目标是浏览器之间直接通话,延迟 200 毫秒以内。 代价是没有中心服务器时穿透困难,大并发要靠 SFU 转发。
三、延迟 vs 并发:HLS 用延迟换并发
为什么 HLS 慢却赢了点播市场?因为它的「慢」换来了三件事:
① 每个请求都是普通 GET:CDN 不用懂流媒体,会缓存静态文件就够了。 ② 天然可水平扩容:一片 ts 可以被一万个人同时下载,CDN 边缘节点各存一份。 ③ 天然自适应:m3u8 里可以列多档码率,播放器按网速自己挑——这就是「清晰度自动切换」的实现方式。
代价就是延迟:观众永远在播「已经切完的那一片」。 片长 6 秒,首屏就至少 6 秒;片长 2 秒,首屏 2 秒。 LL-HLS(低延迟 HLS)用「部分片段」把延迟压到 1 秒内,但复杂度上去了。
反过来,WebRTC 的延迟能到 200 毫秒,但一个房间几十人就到顶——因为它要为每个观众单独维护一条实时连接。
四、怎么选:四个问题定下来
选型不用背表,问四个问题:
① 延迟要求多少? <500 毫秒只能 WebRTC;1~3 秒 RTMP/HTTP-FLV;3 秒以上可以 HLS。 ② 观众多少? 上万必须走 HTTP 派 + CDN;几十人的连麦可以 WebRTC。 ③ 终端是什么? 浏览器只认 HLS(Safari 原生)和 HTTP-FLV(要 flv.js);机顶盒、监控摄像机往往只认 RTSP。 ④ 要不要录制、回看? 要的话 HLS 天然就是「一堆文件」,切片直接存下来就是回放。
实际系统往往是组合:主播 RTMP 推流 → 服务端转出 HLS + HTTP-FLV → 观众按终端挑。第 10~12 章的 Nginx、SRS、ZLMediaKit 干的就是这个「一转多」的活。
五、动手 Demo:真切一段 HLS,看它的时间粒度
HLS 的延迟下限是「片长」决定的,所以先真切一段,看片长怎么变成一个硬约束。 5 秒素材、片长设 2 秒,看它切出几片、播放列表长什么样。
import io, os, tempfile, av
d = tempfile.mkdtemp(prefix="hls_")
ml = os.path.join(d, "index.m3u8")
out = av.open(ml, "w", format="hls", options={"hls_time": "2"})
st = out.add_stream("libx264", rate=25)
st.width, st.height, st.pix_fmt = 320, 240, "yuv420p"
st.options = {"crf": "30", "preset": "veryfast", "g": "25"}
for i in range(125): # 5 秒 @25fps
f = av.VideoFrame(320, 240, "yuv420p")
for p in range(3):
f.planes[p].update(bytes([(i * 3 + p * 50) % 256]) * f.planes[p].buffer_size)
f.pts = i
for pk in st.encode(f):
out.mux(pk)
for pk in st.encode(None):
out.mux(pk)
out.close()
segs = sorted(x for x in os.listdir(d) if x.endswith(".ts"))
print("切片数 %d:%s" % (len(segs), segs))
for line in io.open(ml, encoding="utf-8"):
line = line.strip()
if line.startswith(("#EXTINF", "#EXT-X-TARGETDURATION")) or line.endswith(".ts"):
print(" |", line)
实跑输出:
--------------------------------------------------------------------
四种常见协议——首屏延迟是【攒出来】的
--------------------------------------------------------------------
① 真切一段 HLS,看它的时间粒度
**HLS 不是「一整个文件」,而是一堆几秒长的小文件加一张播放列表。下面真切一段。**
**5 秒素材(125 帧 @25fps),片长设 2 秒,切出 3 个 ts。**
**播放列表里的 #EXTINF 就是每片的时长:2.000000、2.000000、1.000000**
② 四种协议的延迟构成
**下表是按各协议的真实机制算的,假设 RTT = 30 毫秒、片长 2 秒、播放器缓冲 1 片。**
协议 建连 RTT 额外缓冲 典型首屏 常见用途
-------------------------------------------------------------------------------------
RTSP(RTP over UDP) 2 0.10 秒 0.16 秒 实时对讲、监控
RTMP(TCP 长连接) 1 0.30 秒 0.33 秒 主播推流
HLS(切片) 1 2.00 秒 2.03 秒 点播、大并发分发
HTTP-FLV(流式 HTTP) 1 0.30 秒 0.33 秒 低延迟网页直播
**HLS 的 2 秒不是「技术不行」,是它故意的。**
**切片让每个请求都是普通 HTTP GET。**
**于是 CDN 能缓存、能水平扩容——用延迟换并发能力。**
③ 一张表看清取舍
协议 传输层 延迟 穿透性 代价
-------------------------------------------------------------------------
RTSP UDP 为主 最低 差(要开端口) 防火墙不友好
RTMP TCP 低 中(1935 常封) 浏览器要 Flash
HLS TCP/HTTP 高 最好(走 443) 延迟 2 秒起
HTTP-FLV TCP/HTTP 低 好(走 80) 要长连接不缓存
**选协议从来不是选「最好的」,是选「哪一项代价你付得起」。**
**监控选 RTSP,推流选 RTMP,大并发点播选 HLS,网页低延迟选 FLV。**
5 秒素材按 2 秒切,切出三片——最后一片往往不足 2 秒。
播放列表里 #EXT-X-TARGETDURATION 记的是最大片长。
这个数字就是观众首屏延迟的地板——播放器必须等一整片到齐才能开始。
想更快,只有两条路:把片切短(延迟降、请求数涨),或者换一个不切片的协议。
30 秒实验
- 把
hls_time改成1再跑,看切片数怎么变——延迟减半,但请求数翻倍,服务端压力也翻倍。 - 把
hls_time改成10,看 5 秒素材能不能切出片来。 - 用记事本打开
index.m3u8,你会发现它就是个纯文本,没有任何二进制——这就是它能被 CDN 缓存的原因。
常见误区
- 「HLS 是苹果的标准,只有苹果能用」——错。HLS 早就是 RFC 8216,安卓、浏览器、机顶盒全都支持。
- 「RTMP 已经淘汰了」——推流端没有。OBS、FFmpeg、各大云厂商的推流地址至今都是 rtmp://。
- 「延迟越低越好」——低延迟要付出「更容易卡」的代价。录播回看用 HLS,连麦用 WebRTC,别一刀切。
自测三问(点开对答案)
1. HLS 为什么能走 CDN,而 WebRTC 很难? —— **HLS 的每个请求都是普通 HTTP GET,拿到的是静态文件;WebRTC 是端到端的实时连接,CDN 没法缓存。** 2. HTTP-FLV 为什么既低延迟又能过防火墙? —— **它把 FLV 的 Tag 连续写进一个不封口的 HTTP 响应,走了 80 端口又不切片。** 3. 一个系统要同时支持网页、手机、机顶盒,协议该怎么搭? —— **推流统一 RTMP,服务端转出 HLS(网页/手机)和 RTSP(机顶盒/监控),按终端下发。**- ☐ (本节完,下一节 1.3.1 视频直播原理与流程)