4. 推流协议选择:RTMP vs SRT vs WebRTC
推流卡顿,很多时候不是带宽不够,也不是编码器不行,而是协议选错了。我见过太多团队,一卡顿就砸钱升级服务器,结果问题出在协议本身。今天咱们就把 RTMP、SRT、WebRTC 这三兄弟掰开揉碎,看看它们到底差在哪。
4.1 三款协议的核心差异
先看一张对比表,心里有个底:
| 特性 | RTMP | SRT | WebRTC |
|---|---|---|---|
| 传输层 | TCP | UDP + 自定义重传 | UDP + ICE/SRTP |
| 延迟典型值 | 3-10 秒 | 0.5-2 秒 | 0.1-0.5 秒 |
| 抗丢包能力 | 弱(TCP 队头阻塞) | 强(ARQ + FEC) | 中(FEC + NACK) |
| 防火墙穿透 | 差(依赖 1935 端口) | 中(可配置端口) | 强(ICE/STUN/TURN) |
| 适用场景 | 传统直播、CDN 分发 | 弱网推流、远程制作 | 实时互动、视频会议 |
说白了,RTMP 是「老黄牛」,稳但慢;SRT 是「越野车」,路况差也能跑;WebRTC 是「跑车」,快但挑路。
4.2 协议对卡顿的影响机制
4.2.1 RTMP 的队头阻塞
RTMP 跑在 TCP 上。TCP 有个毛病:一个包丢了,后面的包都得等着重传。这在直播里很要命。你想想看,视频帧是连续的,一个关键帧丢了,后面几十帧都解不出来。
我在项目中遇到过,某客户用 RTMP 推 4K 流,网络抖动 5% 就开始卡。后来抓包一看,TCP 窗口一直在 0 和满之间来回跳。这就是典型的队头阻塞。
4.2.2 SRT 的智能重传
SRT 用 UDP,但加了自定义的可靠传输。它有个「丢包重传 + 前向纠错」的组合拳。丢包少的时候用重传,丢包多的时候用 FEC 直接恢复。
我个人习惯在 SRT 里把 latency 参数设成 1000ms。为什么?因为 SRT 的延迟参数其实是「容忍等待时间」。设太短,重传来不及;设太长,延迟又上去了。1000ms 是个平衡点。
# SRT 推流示例(FFmpeg)
ffmpeg -i input.mp4 \
-c:v libx264 -preset ultrafast -tune zerolatency \
-f mpegts 'srt://push.example.com:10080?latency=1000&maxbw=5000000&pbkeylen=16&passphrase=yourkey'
maxbw 参数建议设为实际带宽的 80%。设太高会导致 UDP 丢包激增,设太低又浪费带宽。我一般先用 iperf 测一下链路带宽,再反推这个值。
4.2.3 WebRTC 的实时博弈
WebRTC 追求的是「毫秒级延迟」。它用 UDP 传音视频,用 FEC 和 NACK 处理丢包。但有个问题:FEC 会占用额外带宽,NACK 又会引入延迟。
我记得有一次做远程手术示教,要求延迟低于 200ms。WebRTC 默认配置下,丢包 2% 就开始花屏。后来我把 googCpuOveruseDetection 关掉,手动调了码率分配,才稳住。
// WebRTC 码率控制示例(JavaScript)
const pc = new RTCPeerConnection({
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
});
// 设置视频编码器参数
const params = {
minBitrate: 1000000, // 1 Mbps
maxBitrate: 4000000, // 4 Mbps
initialBitrate: 2000000 // 2 Mbps
};
// 通过 SDP 注入参数
const sdp = pc.localDescription.sdp;
const modifiedSdp = sdp.replace(
/(a=fmtp:\d+ .*)/g,
'$1;x-google-min-bitrate=' + params.minBitrate +
';x-google-max-bitrate=' + params.maxBitrate +
';x-google-start-bitrate=' + params.initialBitrate
);
pc.setLocalDescription({ type: pc.localDescription.type, sdp: modifiedSdp });
4.3 低延迟协议的最佳实践
选协议不是非黑即白。我总结了一套「场景匹配法」:
- 传统直播(延迟容忍 5 秒以上):用 RTMP + CDN。成本低,生态成熟。
- 弱网推流(丢包率 > 5%):用 SRT。我曾在 20% 丢包率的卫星链路上推 1080p,SRT 依然能跑。
- 实时互动(延迟 < 1 秒):用 WebRTC。但要做好带宽预估和码率自适应。
- 混合场景:推流用 SRT,分发用 WebRTC。比如远程制作,现场用 SRT 推回机房,再转 WebRTC 给观众。
下面这张图是我自己画的协议选择流程,帮你快速决策:
4.4 实战中的协议调优
选对协议只是第一步。调优才是见功夫的地方。
4.4.1 RTMP 调优三板斧
- 增大发送缓冲区:
rtmp_buffer_size 10000(单位 KB),避免 TCP 发送窗口满。 - 关闭 Nagle 算法:
tcp_nodelay 1,减少小包延迟。 - 使用 GOP 对齐:固定关键帧间隔,方便播放器快速恢复。
4.4.2 SRT 参数调优清单
| 参数 | 推荐值 | 说明 |
|---|---|---|
latency |
1000-2000 ms | 网络抖动越大,值越大 |
maxbw |
带宽的 80% | 避免 UDP 风暴 |
pbkeylen |
16 | 加密强度,16 字节够用 |
passphrase |
自定义 | 必设,防止盗推 |
4.4.3 WebRTC 的「降级」策略
WebRTC 默认配置偏保守。如果你需要更低延迟,可以尝试:
- 关闭 Simulcast:只推单流,减少编码开销。
- 降低分辨率:从 1080p 降到 720p,码率省一半。
- 使用 VP9:同等画质下码率比 H.264 低 30%,但编码器负载高。
getCapabilities() 检测设备能力,再动态选择编码器。否则,有些手机推 1080p 直接过热降频,卡成幻灯片。
嗯,协议这块就聊到这。记住一句话:没有最好的协议,只有最合适的场景。下次遇到卡顿,先别急着调码率,看看协议选对了没。