4. 推流协议选择:RTMP / HLS / SRT
推流卡顿和音画不同步,很多时候不是编码器的问题,而是你选错了传输协议。我见过不少团队,花了两周调编码参数,结果换了个协议就全好了。说白了,协议决定了数据怎么走、走多快、丢了怎么办。选对了,事半功倍;选错了,后面全是坑。
4.1 三大主流协议的核心差异
目前直播推流用得最多的就是 RTMP、HLS 和 SRT。它们的设计目标完全不同,适用场景也各有侧重。我整理了一张对比表,你可以快速定位自己的场景该用哪个。
| 特性 | RTMP | HLS | SRT |
|---|---|---|---|
| 传输层 | TCP | HTTP (TCP) | UDP |
| 延迟 | 1-3 秒 | 6-30 秒(LL-HLS 可到 2-4 秒) | 0.5-2 秒 |
| 丢包处理 | TCP 重传,易卡顿 | 切片重试,缓冲大 | ARQ + FEC,抗丢包强 |
| 防火墙友好 | 一般(需开放 1935) | 极好(80/443) | 较好(可配端口) |
| 推流端复杂度 | 低 | 中(需切片器) | 中(需库支持) |
| 音视频同步 | 依赖时间戳 | 依赖切片边界 | 内置时钟同步 |
核心结论:低延迟选 SRT,兼容性选 HLS,传统生态选 RTMP。没有万能协议,只有最适合你网络环境的协议。
4.2 RTMP:老牌协议,但坑不少
RTMP 是 Adobe 当年为 Flash 设计的协议,现在虽然 Flash 没了,但 RTMP 作为推流协议依然活着。很多 CDN 和编码器默认就支持它。
它的优点是简单。推流端连上服务器,把 FLV 数据包一帧一帧发过去就行。延迟能做到 1-3 秒,互动性还不错。
但问题也很明显——它跑在 TCP 上。你想想看,TCP 为了保证可靠,丢包就重传。一旦网络抖动,重传的数据会堵住后面的帧。我在项目中遇到过,推流端上行丢包率超过 2%,画面就开始一卡一卡的,音频也跟着断断续续。
避坑指南:我曾经在弱网环境下用 RTMP 推 1080p 流,结果卡得完全没法看。后来把分辨率降到 720p,码率从 6Mbps 砍到 3Mbps,才勉强稳住。RTMP 对上行带宽的稳定性要求很高,别只看带宽峰值。
RTMP 的音视频同步依赖发送端的时间戳。如果编码器打的时间戳不准,或者网络延迟导致帧到达顺序错乱,同步就会出问题。我建议你在推流端用 monotonic clock 打时间戳,别用系统 wall clock,避免 NTP 调整导致时间戳跳变。
4.3 HLS:苹果的切片方案
HLS 最初是苹果为点播设计的,后来被广泛用于直播。它的核心思路是把直播流切成一个个小文件(通常是 2-6 秒的 TS 或 fMP4 片段),然后通过 m3u8 索引文件让播放器按顺序拉取。
HLS 最大的优势是兼容性。它跑在 HTTP 上,防火墙基本不拦。而且切片天然支持自适应码率(ABR),播放器可以根据带宽自动切换不同码率的流。
但延迟是硬伤。传统 HLS 有 3 个切片的缓冲,加上切片本身的时长,延迟轻松到 10-30 秒。后来苹果推出了 Low-Latency HLS(LL-HLS),通过部分切片和预加载提示把延迟压到了 2-4 秒,但需要播放器和 CDN 都支持。
我的经验:如果你做的是大型活动直播,观众端不要求实时互动,HLS 是最省心的选择。CDN 支持好,回放也天然可用。但如果你要做连麦或互动,HLS 的延迟会让你抓狂。
HLS 的音视频同步问题通常出现在切片边界。如果切片器切的时候,音频帧和视频帧不在同一个时间点,播放器就可能出现短暂的音画错位。我建议你把切片时长设成 GOP 时长的整数倍,比如 GOP 是 2 秒,切片就设 2 秒或 4 秒,这样每个切片都从一个关键帧开始,同步问题会少很多。
4.4 SRT:新时代的 UDP 方案
SRT(Secure Reliable Transport)是 Haivision 开源的传输协议,专门为弱网环境设计。它跑在 UDP 上,但通过 ARQ(自动重传请求)和 FEC(前向纠错)来保证可靠性。
我最早接触 SRT 是在一次跨国直播项目中。推流端在东南亚,服务器在美国,中间跨了半个地球。用 RTMP 推,延迟 5 秒但卡顿频繁;换成 SRT 后,延迟降到 1.5 秒,卡顿基本消失。说实话,那次之后我就成了 SRT 的忠实用户。
SRT 的核心优势有两个:
- 抗丢包:通过 ARQ 选择性重传丢失的包,而不是像 TCP 那样重传所有后续包。丢包率 10% 以内都能保持流畅。
- 内置时钟同步:SRT 协议自带时间戳同步机制,推流端和接收端的时钟偏差会被自动校正。这对音视频同步帮助很大。
关键参数:SRT 的 latency 参数控制接收端缓冲大小。设得太小,网络抖动时容易卡顿;设得太大,延迟就上去了。我一般从 120ms 开始调,根据实际网络情况增减。
SRT 的配置示例:
# 推流端(FFmpeg + SRT)
ffmpeg -i input.mp4 \
-c:v libx264 -preset veryfast -b:v 3000k \
-c:a aac -b:a 128k \
-f mpegts 'srt://your-server:7000?mode=caller&latency=200&maxbw=5000'
注意 mode=caller 表示推流端主动连接,接收端用 mode=listener。SRT 的端口可以自定义,不像 RTMP 必须用 1935。
4.5 协议选择决策流程
说了这么多,到底怎么选?我画了一张决策流程图,你可以按自己的场景走一遍。
4.6 协议切换的实战建议
如果你已经在用 RTMP 但卡顿严重,别急着全盘换协议。我建议你先做两件事:
- 测一下上行丢包率:用
ping -c 100 -s 1400 your-server测一下,丢包超过 2% 就考虑换 SRT。 - 检查时间戳:RTMP 卡顿有时不是协议的问题,而是编码器打的时间戳不均匀。用 Wireshark 抓包看看帧间隔是否稳定。
如果确认要换协议,我建议分步走:先在一路测试流上切到 SRT,跑一周看看效果。没问题了再全量切换。别在生产环境上直接换,你想想看,万一出问题,观众端全卡住,那画面太美我不敢看。
小技巧:SRT 和 RTMP 可以同时推流。编码器输出两路,一路 RTMP 给 CDN,一路 SRT 给备用服务器。主路挂了自动切备用,观众端几乎无感。我在一个电商直播项目中就是这么做的,效果很好。
最后说一句,协议只是工具,不是银弹。选对了协议能解决 80% 的卡顿问题,但剩下的 20% 还得靠编码参数、网络优化和播放器策略来补。别指望换个协议就万事大吉,该调的参数一个都不能少。