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 协议选择决策流程

说了这么多,到底怎么选?我画了一张决策流程图,你可以按自己的场景走一遍。

推流协议选择决策流程 推流协议选择决策流程 开始选择协议 延迟要求 < 3 秒? 是 否 网络丢包 > 2%? (上行稳定性) 是 否 推荐 SRT 抗丢包,低延迟 推荐 RTMP 低延迟,生态成熟 需要 ABR 或 CDN 分发? 是 否 推荐 HLS 兼容性好,ABR 成熟 推荐 SRT 低延迟,灵活部署 决策说明 • 延迟 < 3 秒且网络好 → RTMP(简单直接) • 延迟 < 3 秒且网络差 → SRT(抗丢包) • 延迟 > 3 秒且需要 CDN → HLS(最省心) • 延迟 > 3 秒且自建分发 → SRT(可控性强) • 连麦/互动场景 → 优先 SRT 或 WebRTC • 纯录制/回放 → HLS(天然支持)

4.6 协议切换的实战建议

如果你已经在用 RTMP 但卡顿严重,别急着全盘换协议。我建议你先做两件事:

  1. 测一下上行丢包率:用 ping -c 100 -s 1400 your-server 测一下,丢包超过 2% 就考虑换 SRT。
  2. 检查时间戳:RTMP 卡顿有时不是协议的问题,而是编码器打的时间戳不均匀。用 Wireshark 抓包看看帧间隔是否稳定。

如果确认要换协议,我建议分步走:先在一路测试流上切到 SRT,跑一周看看效果。没问题了再全量切换。别在生产环境上直接换,你想想看,万一出问题,观众端全卡住,那画面太美我不敢看。

小技巧:SRT 和 RTMP 可以同时推流。编码器输出两路,一路 RTMP 给 CDN,一路 SRT 给备用服务器。主路挂了自动切备用,观众端几乎无感。我在一个电商直播项目中就是这么做的,效果很好。

最后说一句,协议只是工具,不是银弹。选对了协议能解决 80% 的卡顿问题,但剩下的 20% 还得靠编码参数、网络优化和播放器策略来补。别指望换个协议就万事大吉,该调的参数一个都不能少。