
做视觉项目的人,十有八九都被视频流这件事折腾过:摄像头在现场,AI 推理在服务器,客户端在浏览器,三方各说各话------RTSP、RTMP、HLS、WebRTC、GB28181 协议栈一堆,延迟从 200 ms 到 5 秒不等,动不动还要处理"拉到流但解不出来""能播但延迟 2 秒""多路流互相抢端口"。
工业现场最常见的一种业务长这样:从摄像头拉实时流 → AI 服务做目标检测 / 打标 → 把带框的视频重新推出去 → 客户端在网页上看打标后的画面。这条链路里,你不需要专业的直播流媒体服务器,不需要Nginx-RTMP 那种要编译源码的老古董,也不需要SRS 那种为千万级直播设计的重型方案。你只需要一个单二进制、解压即用、支持RTSP/RTMP/HLS/WebRTC 互转的小工具------MediaMTX。
这篇文章基于一套实际跑通的部署实录,讲清楚用MediaMTX v1.11.3 + FFmpeg搭这套流服务器的完整过程:安装、配置、多实例、推流、拉流验证、低延迟播放、OpenCV接流、常见坑排查。
一、先看清楚这套架构:流服务器在中间干什么

AI 视觉场景下的流中转架构:源 → MediaMTX → AI 处理 → 回推 → 客户端
很多人第一次接触会疑惑:摄像头本身不就是 RTSP 流吗,为什么中间还要架一个流服务器?因为在 AI 业务里,流服务器承担三个角色:
|---------|--------------------------------------------|--------------------------|
| 角色 | 解决什么问题 | 没有它会怎样 |
| 流中转/解耦 | 摄像头只推一路到 MediaMTX,AI 服务和客户端各自从 MediaMTX 拉流 | 每个客户端都直连摄像头,摄像头并发连接数打满就崩 |
| 协议转换 | 对外支持 RTSP/RTMP/HLS/WebRTC 多种协议 | 浏览器不能直接播 RTSP,必须自己转协议 |
| AI 打标回传 | AI 服务处理完画面,把带检测框的视频再推回 MediaMTX 新路径 | 客户端只能看原始画面,看不到 AI 结果 |
典型的业务流是这样的:
1.现场摄像头(或 FFmpeg 模拟的视频文件)把流推到 MediaMTX 的mystream路径;
2.AI 后端从mystream拉流,逐帧做检测/分割,画框打标;
3.AI 后端把打标后的画面编码后,推到 MediaMTX 的annotated路径;
4.客户端(浏览器/播放器)从annotated拉流观看。
|-------------------------------------------------------------------------------------------------------------------------------------------------------|
| 为什么选 MediaMTX 而不是 SRS 或 nginx-rtmp?MediaMTX 是 Go 写的单二进制,没有依赖,下载解压就能跑;默认配置就支持 RTSP、RTMP、HLS、WebRTC 互转;一个实例配置文件里可以声明多条 path;内存占用几十 MB,适合边缘工控机这种资源紧张的环境。 |
二、安装与启动:三步搞定,零依赖
MediaMTX 是单二进制发行包,Linux x86_64 上安装流程如下:
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| bash安装 MediaMTX v1.11.3wget https://github.com/bluenviron/mediamtx/releases/latest/download/mediamtx_linux_amd64.tar.gz tar -xvf mediamtx_linux_amd64.tar.gz ./mediamtx |
解压后目录里核心文件就两个:可执行文件mediamtx和配置文件mediamtx.yml。直接执行./mediamtx,它会默认加载同目录下的mediamtx.yml,监听默认端口:
|-----------|-----------------|---------------|
| 协议 | 默认端口 | 用途 |
| RTSP | 8554 | 推流/拉流主入口 |
| RTMP | 1935 | RTMP 推流拉流 |
| HLS | 8888 | 浏览器 HLS 播放 |
| WebRTC | 8889 / UDP 8189 | 低延迟 WebRTC 播放 |
| gRPC 健康检查 | 9000 | 服务监控 |
后台常驻用 nohup:
|-------------------------------------------------------------------------------------|
| bash后台启动# 用默认配置启动 nohup ./mediamtx & # 指定配置文件启动 nohup ./mediamtx ./mediamtx.yml & |
验证进程和端口:
|----------------------------------------------------------------|
| bash进程与端口检查ps aux | grep mediamtx netstat -tulnp | grep 8554 |
三、配置文件: paths 是核心, source 决定主动拉流
MediaMTX 的配置文件mediamtx.yml里,最关键的是paths段。每一个 path 就是一路流的命名空间。两种模式要分清:
|------------------|-------------------------------------------------|-----------------------|
| 模式 | 行为 | 适用场景 |
| 被动接收(pull 模式的反面) | 等推流方主动推上来,没人推就空着 | 摄像头/FFmpeg 主动推流到服务器 |
| 主动拉流(source 配置) | MediaMTX 启动后自动从 source 指定的 URL 拉流,没有流数据也会一直监听重试 | 摄像头固定 RTSP 地址,服务器主动去取 |
在mediamtx.yml里配置一条主动拉流的路径:
|------------------------------------------------------------------------------------------------------------------------------------------------------|
| yaml mediamtx.yml 关键片段<p>paths: mystream: source: rtsp://admin:password@192.168.1.100:554/Streaming/Channels/101 annotated: # 这条路径等 AI 服务推回来</p> |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 两个必须改的坑:第一,RTSP 端口 8554 必须在配置里显式启用 ,否则 web 端/AI 服务推流到rtsp://server:8554/mystream会被拒绝;**第二,多实例部署时**rtpAddress 必须配偶数 ,这是 MediaMTX 内部 RTP 端口段的硬约束,配成奇数启动会报错。 |
四、多实例部署:一个实例只管一路流

多实例部署:每路流独立进程、独立端口
很多人第一次部署会踩一个坑:以为在一个mediamtx.yml里写多条 path 就能跑多路流。技术上没错,但实际生产里 MediaMTX 一个实例同时处理多路流时,一旦某一路流异常(比如摄像头断流、码率突变),可能影响整个进程。更稳的做法是:一路流起一个独立的 mediamtx 实例,每个实例用不同的配置文件和不同的端口段。
|------|---------|---------------|-------------------|-----------|
| 实例 | RTSP 端口 | RTP 端口段(偶数起始) | 配置文件 | 业务用途 |
| 实例 1 | 8554 | 8000--8001 | mediamtx_cam1.yml | 1 号摄像头原始流 |
| 实例 2 | 8556 | 8002--8003 | mediamtx_cam2.yml | 2 号摄像头原始流 |
| 实例 3 | 8558 | 8004--8005 | mediamtx_anno.yml | AI 打标回传流 |
每个配置文件复制一份后改三个值:rtspAddress端口、rtpAddress偶数起始、paths里的业务路径。端口不能重复,否则启动时报"address already in use"。启动脚本思路:
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| bash多实例启动示例nohup ./mediamtx ./mediamtx_cam1.yml > cam1.log 2>&1 & nohup ./mediamtx ./mediamtx_cam2.yml > cam2.log 2>&1 & nohup ./mediamtx ./mediamtx_anno.yml > anno.log 2>&1 & # 检查 ps aux | grep mediamtx netstat -tulnp | grep -E '855468' |
五、 FFmpeg 推流:用本地文件模拟摄像头
调试阶段没有真实摄像头,最方便的方式是用 FFmpeg 把一个本地 MP4 文件"按实时帧率"推到 MediaMTX。这和真实摄像头推流在协议上没有区别,AI 服务端完全感知不到差别。
|---------------------------------------------------------------------------------------------------|
| bash UDP 推流(默认)ffmpeg -re -i input.mp4 -c:v copy -c:a copy -f rtsp rtsp://localhost:8554/mystream |
参数解释:
|--------------|--------------------------------------|
| 参数 | 作用 |
| -re | 按输入文件的原始帧率读取,不要一秒钟把文件推完;模拟实时摄像头的关键参数 |
| -i input.mp4 | 输入文件,也可以替换成摄像头设备/dev/video0或 RTSP 源 |
| -c:v copy | 视频流直接拷贝,不重新编码。CPU 占用几乎为零,延迟最低 |
| -c:a copy | 音频流同样直接拷贝;纯视频场景可省略 |
| -f rtsp | 输出格式为 RTSP |
企业网/跨网段环境下 RTSP 走 UDP 经常被防火墙拦,要显式切 TCP:
|-------------------------------------------------------------------------------------------------------------------------|
| bash TCP 推流(跨网/防火墙友好)ffmpeg -re -i 1.mpg -c:v copy -f rtsp -rtsp_transport tcp rtsp://localhost:6001/examDetStream_6001 |
|-------------------------------------------------------------------------------------------------------------------------------------------|
| 最常见的报错:推流没反应、卡住、401 或 404。90% 的原因是 MediaMTX 没起来,或者 8554 端口没在配置里启用。先跑ps aux | grep mediamtx和netstat -tulnp | grep 8554确认进程和端口,再怀疑推流命令本身。 |
六、验证流是否可用: ffprobe 与抓帧
推上去之后,不要急着写代码,先用命令行工具验证流是通的、编码参数是对的。
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| bash用 ffprobe 检查流ffprobe -hide_banner -rtsp_transport tcp -i "rtsp://localhost:8554/mystream" ffprobe -hide_banner -rtsp_transport tcp -i "rtsp://localhost:6001/faceStream_6001" |
正常输出会显示:输入格式 RTSP、时长、视频流编码(H.264/H.265)、分辨率、帧率、音频编码。如果这里报错,后面 OpenCV、AI 服务端一定也接不上。
抓一张快照验证画面内容:
|-----------------------------------------------------------------------------------------------|
| bash抓一帧 JPEGffmpeg -i "rtsp://localhost:6001/faceStream_6001" -frames:v 1 -q:v 2 snapshot.jpg |
-frames:v 1表示只抓一帧视频,-q:v 2是 JPEG 质量(2 是高质量,范围 2--31)。这个命令在做视觉项目时极常用------排查"画面里到底是什么"时,比开播放器快得多。
七、低延迟播放: GStreamer vs FFplay

三种拉流方案的延迟差异
RTSP 流在普通播放器(VLC、PotPlayer)里默认有 2--5 秒缓冲,做 AI 调试时根本没法看。要低延迟预览,有两个命令行工具:
|-----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|-----------------------------|
| 工具 | 命令 | 延迟水平 | 特点 |
| GStreamer | gst-launch-1.0 -v rtspsrc location="rtsp://..." latency=0 ! application/x-rtp,media=video ! queue max-size-buffers=0 ! decodebin ! videoconvert ! ximagesink | 100--300 ms | 零缓冲、最低延迟,但依赖 GStreamer 全套插件 |
| FFplay | ffplay -rtsp_transport tcp -fflags nobuffer -flags low_delay -framedrop "rtsp://..." | 300--800 ms | FFmpeg 自带,无需额外插件,参数少 |
| VLC 默认 | 直接打开 rtsp:// 链接 | 2--5 s | 兼容性最好,但延迟大,只适合非实时场景 |
GStreamer 那条命令里的关键参数:latency=0告诉 rtspsrc 不要缓冲;max-size-buffers=0让 queue 不攒帧;decodebin自动识别编码并解码;ximagesink在 X 窗口直接显示。这套组合是 Linux 上看 RTSP 流延迟最低的命令行方案。
八、 OpenCV 拉流:三种方案的延迟真相
AI 服务端最常见的写法是用 OpenCV cv2.VideoCapture("rtsp://...")读帧。但很多人不知道,OpenCV 默认的 FFmpeg 后端拉 RTSP 流会有 2 秒左右的缓冲,做实时检测时画面是"慢动作"的。三种方案的实际差异:
|------------------------|------------------------------------------------------------------|-------------|------------|-----------------|
| 方案 | 实现方式 | 典型延迟 | CPU/资源 | 适用场景 |
| OpenCV 默认后端 | cv2.VideoCapture(url),依赖系统 FFmpeg | 1.5--2.5 s | 低 | 非实时、离线分析、快速原型 |
| OpenCV + GStreamer 后端 | 编译 OpenCV 时开启 WITH_GSTREAMER,用 GStreamer 管道字符串作为 VideoCapture 参数 | 200--500 ms | 中 | 实时检测、边缘盒子、对延迟敏感 |
| OpenCV + FFmpeg API 硬解 | 自己写 FFmpeg API 代码,启用硬件解码(NVDEC/VAAPI)、丢帧策略、低延迟标志 | 80--200 ms | 中低(GPU 硬解) | 多路并发、超低延迟、生产级 |
要拿到 GStreamer 后端,编译 OpenCV 时必须打开-DWITH_GSTREAMER=ON,并且系统装好 GStreamer 全套插件(gstreamer1.0-plugins-base/good/bad/ugly、libgstreamer1.0-dev)。否则 OpenCV 编译时会自动跳过 GStreamer 后端,运行时又退回 FFmpeg 默认缓冲。
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| python OpenCV 用 GStreamer 管道拉流(示例)<p>import cv2pipe = ( 'rtspsrc location="rtsp://localhost:8554/mystream" latency=0 ! ' 'queue max-size-buffers=0 ! ' 'decodebin ! videoconvert ! appsink drop=true')cap = cv2.VideoCapture(pipe, cv2.CAP_GSTREAMER)while True: ok, frame = cap.read() if not ok: break # 推理、画框、推流回 annotated 路径</p> |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 如果业务对延迟要求是"必须在 200 ms 以内",GStreamer 后端也不够,得直接用 FFmpeg API 写:avformat_open_input + avformat_find_stream_info,显式设置AVDictionary里的rtsp_transport=tcp、stimeout=3000000,解码时用AVCodecContext配硬解,并在读取循环里做"丢旧帧只留最新帧"。这是生产级 RTSP 拉流的标准做法。 |
九、常见问题排查
|---------------------------|-----------------------------------------------------|------------------------------------------|
| 现象 | 排查命令/方向 | 常见原因 |
| ffmpeg 推流没反应/卡住 | ps aux | grep mediamtx;netstat -tulnp | grep 8554 | Mediamtx 没启动;8554 端口未监听;防火墙拦截 |
| 端口被占用报错 | netstat -tulnp | grep <端口> | 多实例端口重复;上次进程没退干净 |
| 启动报错 rtpAddress 非法 | 检查配置文件里 rtpAddress 值 | 端口写成了奇数,必须配偶数 |
| ffprobe 能连上但报错 | 看 stderr 里的具体错误 | 流没推上来;路径名拼写错误;认证不对 |
| OpenCV 拉流延迟 2 秒 | cv2.getBackendName()看后端 | 用了默认 FFmpeg 后端,需切 GStreamer 或 FFmpeg API |
| GStreamer 管道报错 no element | gst-inspect-1.0 rtspsrc | 缺 gst 插件;OpenCV 没编译 GStreamer 支持 |
| ffplay 花屏/卡顿 | 加-rtsp_transport tcp | UDP 丢包,切 TCP 稳定 |
| 浏览器打不开流 | 访问http://server:8888/mystream | 用 HLS/WebRTC 端口,不是 RTSP 8554 |
十、 总结
MediaMTX + FFmpeg 这套组合,本质是一个"小而美"的流中转方案:单二进制、零依赖、几十 MB 内存、RTSP/RTMP/HLS/WebRTC 全协议互转,特别适合边缘工控机、AI 推理服务器、小规模视觉项目。它不适合的场景也很清楚------万级并发直播、亚 100 毫秒级超低延迟多人互动、复杂的鉴权和转码集群,那是 SRS、Nginx-RTMP、商业 CDN 的地盘。