用 MediaMTX 搭建低延迟直播:从 SRT 推流到 WebRTC 播放的完整指南
【免费下载链接】mediamtxReady-to-use Media-over-QUIC / SRT / WebRTC / RTSP / RTMP / LL-HLS / MPEG-TS / RTP live media server and media proxy that allows to read, publish, proxy, record and playback real-time video and audio streams.项目地址: https://gitcode.com/GitHub_Trending/me/mediamtx
推一路线路测试码流到观众屏幕,走 HLS 是 3 到 10 秒,走 RTMP 也要 1 到 3 秒。对娱乐直播来说尚可忍受,但对游戏直播,观众看到技能释放时操作已经完成,体验直接崩掉。延迟问题的根源不在网络带宽,而在协议本身的分段缓冲机制——而破局的办法,是用支持WebRTC的流媒体服务器把播放端延迟压到亚秒级。
MediaMTX是一个开箱即用的零依赖实时流媒体服务器,同时内置 WebRTC、SRT、RTSP、RTMP、LL-HLS 等协议栈,可以把一路推流转成任意协议播放,并支持录制与回放。
一条流如何同时喂饱四种播放器
MediaMTX 的核心心智模型很朴素:所有流都挂在一个叫path(路径)的对象上,path 由一个path manager统一管理。
- 一个 path 只有一个推流者(publisher),可以是 RTSP/RTMP/WebRTC/SRT 客户端,也可以是被配置拉流的外部源
- 任意多个观众可以用任意受支持的协议读同一条流
- 服务器内部只做remux(协议转换、不重编码),所以 CPU 开销极低,单进程即可撑起多路并发
也就是说,推流者用 SRT 进来,浏览器观众用 WebRTC 看,移动端用 LL-HLS 看,VLC 用 RTSP 看——它们读的是同一条流。数据流向就是:推流客户端 → path → 各协议 server → 观众,完整说明见架构文档。
关键技术决策
为什么用 SRT 推流
SRT(Secure Reliable Transport)是基于 UDP 的可靠传输协议,用应用层重传对抗丢包,典型端到端延迟在 100ms 量级,远低于 TCP 系的 RTSP/RTMP。对游戏场景更重要的是它天然适配 OBS 这类推流端。MediaMTX 的 SRT server 默认开启,监听 UDP:8890,streamid 同时支持m=publish,r=live这种标准语法(部分硬件只认它),细节见SRT 特性文档:
srt: true srtAddress: :8890为什么用 WebRTC 播放
WebRTC 在浏览器里无需插件,媒体走 SRTP 直连,观众端延迟通常在几十毫秒到 100ms 出头。MediaMTX 的 WebRTC 握手走 HTTP(:8889),媒体走独立的 UDP/ICE 监听(默认:8189),四层连通方案按优先级排列:静态 UDP 端口 → 静态 TCP 端口 → STUN 打洞 → TURN 中继。局域网或端口放通的内网机器,默认配置就够了;公网部署时把公网 IP 写进webrtcAdditionalHosts即可:
webrtc: true webrtcAddress: :8889 webrtcLocalUDPAddress: :8189 webrtcAdditionalHosts: [1.2.3.4]为什么留一个 LL-HLS 兜底
部分移动端场景(尤其是 iOS 系统播放器)只能走 HLS。MediaMTX 的 HLS 默认就是lowLatency变体,hlsPartDuration: 200ms,把 LL-HLS 的 part 粒度压到 200 毫秒,配合 CDN 分发时延迟能到 2 秒左右——不是最优,但足够覆盖 WebRTC 触达不了的终端。
从安装到出画面的最小配置
MediaMTX 是单个可执行文件,Docker 启动最快。注意 WebRTC 的 UDP 端口8189和 SRT 的8890都要用/udp映射,漏掉 8189 是新手最常见的失败点:
docker run --rm -it \ -p 8554:8554 -p 8888:8888 -p 8889:8889 \ -p 8189:8189/udp -p 8890:8890/udp \ bluenviron/mediamtx:1启动后日志会逐行列出各 server 的监听状态。默认配置(仓库根目录的mediamtx.yml,共 800 余行注释)里authMethod: internal且user: any放行匿名读写,局域网实验直接可用;上生产前至少要改成按 path 限制权限,完整参数以配置文件参考为准。
推流端用 FFmpeg 生成测试源,走 SRT 标准 streamid 语法推入live路径:
ffmpeg -re -f lavfi -i testsrc=duration=30 -f lavfi -i sine=duration=30 \ -c:v libx264 -preset ultrafast -c:a aac \ -f srt "srt://127.0.0.1:8890?streamid=#!::m=publish,r=live"验证闭环只需要两条命令。第一条确认流真的进了服务器(跨协议读取成功):
ffprobe -v error -show_entries stream=codec_name rtsp://127.0.0.1:8554/live # 预期输出:h264 与 aac 两行 codec_name第二条确认 LL-HLS 播放列表已生成:
curl -s http://127.0.0.1:8888/live/index.m3u8 | head # 预期输出:#EXTM3U 开头的播放列表浏览器打开http://服务器IP:8889,MediaMTX 自带 WebRTC 查看页,填入流地址即可出画面——从推流到出画面,这条链路通常不到 1 秒。
两个文档不会重点提醒的坑
⚠️ 第一个坑在编码器上:浏览器用 WebRTC 播 H265 基本全军覆没(仅 Windows 版 Chrome 在特定 GPU 下支持),而含B 帧的 H264 同样不被 WebRTC 规范接纳——服务端转不动浏览器的编码限制,唯一解法是推流端改用 H264 baseline profile + Opus 重新编码,WebRTC 特性文档 里给了现成的 FFmpeg 转码参数。如果你的推流设备固定输出 B 帧 H264,观众端大概率是黑屏而非报错,这点非常隐蔽。
第二个坑在网络层:Docker 部署时如果只映射了8889忘了8189/udp,握手 HTTP 200、页面正常加载、但画面永远转圈——因为 ICE 媒体通道根本建立不起来。排查顺序建议照文档的四层方案走:先确认 UDP 8189 放通,再开webrtcLocalTCPAddress: :8189走 TCP 兜底(代价是拥塞时延迟递增),最后才上 STUN/TURN。
另外录制是默认关闭的(record: false),开启后recordPath默认按%path与时间戳落盘 fMP4 分段,单段 1 小时,适合比赛回放,详见录制文档。
延伸方向
- 大规模并发时把主服务器的 path 通过
forward推到边缘 MediaMTX 节点,或反向用source拉流做读副本,见转发文档 - 用
:9998的 Prometheus metrics 端点接 Grafana,盯每路的 reader 数与 CPU 占用 - 探索 MoQ(Media over QUIC)协议栈,它基于 HTTP3/WebTransport,是比 WebRTC 更轻的下一代低延迟方案,仓库已内置完整实现
【免费下载链接】mediamtxReady-to-use Media-over-QUIC / SRT / WebRTC / RTSP / RTMP / LL-HLS / MPEG-TS / RTP live media server and media proxy that allows to read, publish, proxy, record and playback real-time video and audio streams.项目地址: https://gitcode.com/GitHub_Trending/me/mediamtx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考