MediaMTX 是一个流媒体服务器:一个 57336320 字节的 exe,起来之后开放 RTSP、RTMP 和 HLS 这几套端口,谁推流进来都能收,谁想看都能拉。

它替掉的是那种「装个 Nginx 配 RTMP 模块,再装 ffmpeg 转码,再写个 HLS 切片脚本」的活。这里一条命令起来,不用配置文件也能跑,需要定制的部分写在 yml 里。

为了验证它到底能不能搬流,我造了一段 20 秒的 720p 测试视频,从 ffmpeg 推进去,再用 ffmpeg 从另一边录出来,中间的耗时和体积都记了下来。

一个 exe 开七个端口

启动瞬间日志里打出一排监听记录,每行一个协议。这份日志本身就是它的能力清单,七个端口一次全开,不需要挑。

协议端口用它干什么
RTSP8554摄像头和 ffmpeg 推流最常用
RTMP1935OBS 直接往里推
HLS8888浏览器播放,切 ts 分片
WebRTC8889延迟最低的一路,走 UDP
SRT8890弱网传输,抗丢包
MoQ8892HTTP/3 上的新媒体协议
API9997HTTP 接口,查流状态改配置
MediaMTX v1.21.3 启动日志:RTSP 8554 / RTMP 1935 / HLS 8888 / WebRTC 8889 / SRT 8890 / MoQ 8892 / API 9997 七个监听,下面是推流与拉流会话记录

装的过程只有解压

官方 zip 28734316 字节,里面三个文件:mediamtx.exe、mediamtx.yml 和一份 LICENSE。解压 0.31 秒完事,没有安装向导,不写注册表。

文件字节作用
官方 zip28734316三个文件打成一个包
mediamtx.exe57336320主程序,Go 单文件
mediamtx.yml38940默认配置,注释比配置多
LICENSE1062MIT

exe 57336320 字节是 Go 编译出来的单文件,双击就能跑。配置默认从同目录的 mediamtx.yml 读,不在就报错退出,这点和大部分绿色软件不一样。

它不做转码,只搬流

推流进来什么样,拉出去就是什么样。H.264 进来还是 H.264,码率一点不变。要转码得自己再接一路 ffmpeg 处理,它这边只负责把流分发出去。

这个设计决定了它的开销很低。同样一路 720p 的流,转码要吃掉几个核,搬流几乎不占 CPU,机器差也能扛。

装之前有三行配置要改

API 默认是关的

# mediamtx.yml 第 147 行
api: false
# Address of the TCP/HTTP listener.
apiAddress: :9997

这一段就是默认值。不改它,9997 端口根本不会开,任何查询接口都返回连接失败。

我第一轮就是被这个绊住的:服务起来了,日志里 RTSP、RTMP 和 HLS 都有监听记录,唯独没有 API 那行。改成 api: true 之后才出现 [API] started with listener on 127.0.0.1:9997。

监听地址默认是整个网卡

默认值是 :8554 这种写法,意思是所有网卡都听。放在内网机器上没问题。

挂到公网就等于把推流口敞开,谁都能往里灌东西。

测试时我把七个地址全改成 127.0.0.1 开头,只给这台机器用。要对外提供服务的场景,得配合防火墙只放行特定来源。

端口占用要提前看

七个端口里 8888 最容易撞。不少开发工具拿它当默认端口,起来之前先 netstat -ano | findstr 8888 看一眼。

撞了不会报得很清楚,日志里是一行 address already in use 然后整进程退出。改 yml 里对应的那一行再起。

推流进来:0.53 秒看到流

用 ffmpeg 把测试视频按原速推过去,命令里 -re 是关键,不加它会用最快速度灌进去,时间对不上。

ffmpeg -re -i test20.mp4 -c copy -f rtsp -rtsp_transport tcp \
  rtsp://127.0.0.1:8554/live

推上去之后查 API,从按下回车到流状态变成 ready 是 0.53 秒。API 那一次查询往返 3.0 毫秒。

环节数值说明
测试源4089702字节,20 秒 720p 25 帧 1500k
推流到 ready0.53秒
API 查询3.0毫秒
轨道数2条,H264 加 MPEG-4 Audio

它认两种轨道

API 返回的 tracks 就两项:H264 和 MPEG-4 Audio。视频只认 H.264,音频只认 AAC。

H.265 推上去会被直接拒绝,得先在推流端转一次再送进来。

这条限制影响选摄像头。不少新设备默认 H.265,图的是同画质省一半带宽,接进来之前要先把它调成 H.264。

三种进法,本次只验证了 RTSP

推流口开了三个:RTSP 8554、RTMP 1935、SRT 8890。OBS 默认走 RTMP,摄像头和 ffmpeg 走 RTSP,弱网环境走 SRT。

本次全程用 RTSP,命令里加了 -rtsp_transport tcp。不加这个参数,ffmpeg 默认先用 UDP,UDP 在丢包时会花屏,TCP 更稳但延迟略高。RTMP 和 SRT 这两条路没有验证,不写结论。

推流口典型客户端本次是否验证
RTSP 8554ffmpeg、摄像头验证,0.53 秒变 ready
RTMP 1935OBS未验证
SRT 8890弱网推流器未验证

包太大它会自己拆

日志里出现过一行 RTP packets are too big (1460 > 1440), remuxing them into smaller ones。1500k 码率的 720p,关键帧一刀下去超过 MTU,它自己拆包重封。

这一步是自动的,不影响播放,但每拆一次多一次拷贝。推流端把关键帧间隔调大、码率降一点,这行日志就少了。

拉流出去:10 秒录到 1.39 MB

另一边用 ffmpeg 当客户端,从 RTSP 拉 10 秒写进 mp4。这条链路就是「抓直播」的实际做法,直播源换成摄像头或平台地址也是同一套命令。

ffmpeg -rtsp_transport tcp -i rtsp://127.0.0.1:8554/live \
  -t 10 -c copy rec10.mp4

结果:耗时 10.42 秒,产出 1389877 字节。10 秒的 720p 落在 1.39 MB,换算下来约 1.11 Mbps,跟推流端设的 1500k 基本吻合。

项目数值
录制时长10.42 秒
产物体积1389877 字节
视频轨489 KiB
音频轨117 KiB
封装开销0.715019%
折算每小时500 MB
折算每天12 GB
ffmpeg 从 RTSP 拉流录制 10 秒的过程:帧计数到 67,输出 mp4 489 KiB 视频加 117 KiB 音频,封装开销 0.715019%

录多长由 -t 决定

-t 10 是墙钟时间,不是帧数。想按体积控制就换成 -fs 100M,想一直录到手动停就干脆不写这个参数。

不写 -t 的时候它会一直跟着流写,直播中断才结束。定时录制要自己在外层加计划任务,它不自带这个功能。

录下来的文件能直接播

rec10.mp4 是标准 mp4 封装,1389877 字节里有 489 KiB 视频和 117 KiB 音频,剩下的封装开销占 0.715019%。播放器打开就能看,不用再处理。

这也是 -c copy 的价值:不重新编码,写进去的就是收到的原始帧,画质一点不掉,CPU 也不动。代价是封装格式得选对,要 flv 就写 -f flv,要分段就写 -f segment。

服务端一断,录制端立刻报错

我在测试脚本末尾把服务进程杀了,录制端的画面立刻变成一片红:Failed reading RTSP data: Error number -10054,接着是 Error submitting a packet to the muxer: Broken pipe,最后 Task finished with error code: -32。

这说明录制的可靠性完全压在服务端上。真实场景里要防这个,得让 ffmpeg 带重连参数,或者在录制脚本里写一个「断了就重连」的循环。

浏览器这条路没走通

HLS 的地址是 http://127.0.0.1:8888/live/index.m3u8,用无头 Chrome 打开播放页,页面加载 6.1 秒,但 video 元素的 videoWidth 和 videoHeight 都是 0。

同一时刻日志一直在刷 [HLS] session closed: no stream is available on path 'live'。原因在时序:HLS 要先由请求触发建 muxer,再切出第一个分片,这中间有三四秒是空的,我请求得太早。

播放方式本次结果原因
RTSP 拉流成功,10.42 秒录 1389877 字节ffmpeg 直接解码
HLS 页面video 尺寸 0请求早于首个分片生成
WebRTC未验证无头浏览器拿不到摄像头栈

HLS 要等 muxer 起来

日志的时间线是:请求进来先报 no stream is available,几秒后才有 muxer live created 和 is converting into HLS, 2 tracks。等到这行出现,m3u8 就能拿到了。

要做页面播放,前端得带重试,别一次失败就当流挂了。它自己那个播放页也是靠轮询,不是一打开就出画面。

性能:启动 0.58 秒,API 0.5 毫秒

从进程启动到 API 能应答是 0.58 秒。之后连续查五次流列表,延迟 0.9 / 0.6 / 0.5 / 0.6 / 0.6 毫秒,稳定在半毫秒附近。

指标数值
API 就绪0.58 秒
API 延迟0.5 到 0.9 毫秒
推流到可用0.53 秒
10 秒录制10.42 秒
内存占用没测,不作为结论

搬运模式下 CPU 几乎不动,瓶颈全在网络和磁盘。10.42 秒录 10 秒的流,多出来的 0.42 秒是建立连接和写文件尾的开销。

几个真踩过的报错

症状原因处理
API 端口连不上yml 里 api: false改成 true 再重启
进程起来就退端口被占用netstat 查占用,改 yml 端口
找不到配置文件不在 exe 同目录用绝对路径传第二个参数
推 H.265 被拒只支持 H.264推流端先转码
m3u8 返回 404首个分片还没生成等 muxer 建好再请求
录制端 Broken pipe服务端断开录制脚本加重连

第一条和最后一条最容易浪费时间。前者看起来像网络问题,其实是配置没开;后者看起来像 ffmpeg 的错,实际是上游没了。

什么场景值得上

你的情况结论
多路摄像头汇到一个出口合适,一个进程全收
把一路流转成 RTSP 和 HLS 两套给不同端合适,推一次到处能用
要做录制存档能用,但要自己写录制循环
要转码、要加水印不合适,它不碰画面
要账号体系和权限不合适,认证得自己加在前面

要判断它适不适合,先算两笔账。第一笔是带宽:一路 720p 按 1500k 算,十路并发下行就是 15 Mbps,家里宽带扛不住,得上行专线或者内网分发。

第二笔是磁盘。按刚测的比例,连录一小时就是半 GB 量级,一天不断写要十来个 GB。要长期存档得配轮转删除,或者只录关键时段。

它的定位是管道,不是平台。上游谁推、下游谁看它不关心,中间这一段的协议转换和分发归它管。

单机跑几路 720p 完全够用。要扛几十路,得考虑带宽和磁盘写入,以及把录制拆到另一台机器上。