
做直播、做监控、做视频点播说到底绕不开“视频流服务器”这个中间层。我这些年帮团队和客户搭过不少流媒体环境结论很直接商业产品能干的活儿目前主流、免费且开源的视频流服务器几乎都能干定制空间反而更大出了问题还能直接看源码定位不用干等厂商售后。这篇文章把我实际部署过的 SRS、Nginx-RTMP、MediaMTX、ZLMediaKit 这四个项目掰开讲清楚覆盖协议选型、部署过程、延迟优化和常见故障排查。适合刚接触流媒体、想给内部系统加直播能力或者想把监控摄像头画面接到 Web 端和手机端的开发者也适合已经跑通一套服务、但被延迟和兼容性问题反复折磨的老手。读完你至少能回答三个问题不同场景该选哪个开源项目RTMP、HLS、WebRTC 这些协议到底怎么取舍服务部署上去之后出了问题该从哪里下手查。我尽量不堆名词每个概念都用实际场景说明白。1. 主流开源方案的横向对比与选型思路1.1 先搞清楚“视频流服务器”到底解决什么问题很多人第一次接触流媒体容易被一堆协议名字绕晕其实核心链路非常简单一端把视频数据推上来服务端做接收、存储、转码也可以不转码和分发另一端的播放器从服务端拉流播放。视频流服务器就是中间那个承上启下的角色。它要解决的痛点有三个。第一个是兼容性推流端可能是 OBS、摄像头、手机 App播放端可能是浏览器、VLC、小程序服务端必须把不同来源、不同协议的视频统一管理起来再按播放端能接受的方式发出去。第二个是延迟和卡顿控制直播场景要求低延迟点播场景要求流畅拖动同一个服务往往要同时满足。第三个是并发稳定性人数一多带宽、内存、文件句柄都会成为瓶颈能不能扛住直接决定项目口碑。带着这三个痛点去看开源项目就不会被“功能越多越好”带偏。实际选型时先问自己三个问题视频源是什么摄像头还是软件推流播放端主要是什么浏览器、App 还是电视对延迟的容忍度是多高几秒还是几百毫秒答案不同选型结果完全不同。这也是我下面反复强调的主线。1.2 四个主流开源项目的定位差异我实际部署过的开源视频流服务器主要有四个各有各的脾气。先看一张对比表后面再逐个展开。项目核心特点最合适的场景学习成本SRS国产开源、功能全支持 RTMP/HLS/HTTP-FLV/WebRTC直播、会议、点播一体化平台中等Nginx-RTMP基于 Nginx 模块轻量、部署简单小规模直播、内部系统低MediaMTX极简配置、秒级起服务WebRTC/RTSP 桥接能力强摄像头、监控流接入 Web低ZLMediaKit高性能、支持 GB28181 国标C 底层安防监控、海量并发接入高SRS 可以说是目前开源直播服务器里综合能力最均衡的一个文档齐全、社区活跃单机就能支撑几千路并发适合做产品级服务。Nginx-RTMP 严格说不是一个独立服务器而是 Nginx 的一个模块胜在轻量适合快速验证和小规模使用但它已经很久没有大版本更新了别指望它帮你处理太复杂的业务。MediaMTX 前身叫 rtsp-simple-server名字起得特别实在它把 HTTP、RTSP、WebRTC、HLS 这些协议之间的转换做得非常顺手我用它接过大量海康、大华摄像头的 RTSP 流再以 WebRTC 方式推到浏览器里延迟低到几乎无感。ZLMediaKit 则是偏底层的重型选手安防领域大量项目用它对接 GB28181 国标设备如果你要自己写流媒体中间件它是很好的底座但二次开发成本也确实高。选型没有标准答案只有“合不合适”。小团队内部直播Nginx-RTMP 就够做产品面向客户优先 SRS监控类项目绕不开 ZLMediaKit 和 MediaMTX。2. 核心协议拆解选错协议等于埋雷2.1 RTMP、HLS、HTTP-FLV、WebRTC、SRT 各自的定位很多新手把“视频流服务器”和“RTMP”划等号这是最常见的误解。协议只是服务端对外提供的接口项目支持哪些协议、你选哪种接入方式直接决定播放延迟、兼容范围和部署复杂度。RTMP 是 Adobe 当年为 Flash 直播设计的 TCP 协议现在 Flash 已经没了但 RTMP 作为“推流入口”依然活得好好的。OBS、FFmpeg、大部分编码器都原生支持 RTMP 推流延迟在 2 到 5 秒之间。它的优点是非常成熟、穿透性好缺点是播放端没法直接播放必须由服务端转成其他格式再分发。HLS 是苹果推的 HTTP 分片方案。服务端把视频切成一个个几秒钟的小文件再用 m3u8 索引文件告诉播放器按顺序拉取。它的兼容性天下无敌浏览器、iOS、Android、各种播放器全都认识 m3u8但代价是延迟高通常 5 到 15 秒切得越细延迟越低文件数也越多。HTTP-FLV 算是国内直播圈的特产。它把 FLV 封装的数据包通过 HTTP 流式下发浏览器端用 flv.js 就能播放。延迟和 RTMP 差不多大概 2 到 5 秒但兼容性不如 HLS。它的最大好处是方便做 CDN 分发因为走的是普通 HTTP。WebRTC 是低延迟场景的终极大招。它基于 UDP建立了音视频传输的完整链路端到端延迟能压到 500 毫秒以内适合连麦、教育、远程操控这类互动场景。缺点是技术栈偏前端服务端配置稍复杂对网络质量要求也更高。SRT 则是为弱网环境设计的可靠传输协议在丢包严重的公网上依然能保持画面不花屏适合跨地域推流、卫星传输这类场景。我自己用 SRT 从外地稳定推流回中心机房的经历里同等网络条件下确实比 RTMP 稳得多。2.2 实际项目中协议怎么排布实操里我不会只依赖一种协议而是按“推流端、服务端、播放端”三段来做协议编排。推流端优先用 RTMP 或 SRT服务端统一接收后由流媒体服务器自动转出 HLS 和 HTTP-FLV 给普通播放端如果业务对延迟有硬性要求再单独开一路 WebRTC 出口。这里有个概念需要澄清服务端做的是“协议转换”不是“转码”。协议转换只改封装格式不重新编码画面CPU 压力很小转码则是把 H.264 转成 H.265 或调整分辨率非常吃 CPU。很多小项目一上来就开转码机器瞬间被打满其实大部分场景下协议转换就够了。如果播放端要覆盖微信小程序那基本只能靠 HLS因为小程序的 video 组件对 HTTP-FLV 和 RTMP 支持都很差。如果播放端是自己的 App那可以优先考虑 HTTP-FLV因为它实现简单、延迟适中。如果是 Web 端的实时监控画面直接走 WebRTC用户体验完全不在一个档次。3. 从零部署三个开源视频流服务器3.1 SRS直播场景的一站式方案SRS 安装非常省心官方提供了 Docker 镜像一条命令就能把包含 RTMP、HLS、HTTP-FLV、WebRTC 的完整服务跑起来docker run -d --name srs \ -p 1935:1935 \ -p 8080:8080 \ -p 1985:1985 \ -p 8000:8000/udp \ ossrs/srs:5端口含义要记牢1935 是 RTMP 和 SRT 的入口8080 是 HTTP 服务端口提供 HLS 和 HTTP-FLV 播放1985 是 HTTP API 端口8000 是 WebRTC 的 UDP 端口。忘了开 8000 的 UDPWebRTC 就绝对连不上这个坑我踩过不止一次。推流命令用 FFmpeg 就能测ffmpeg -re -i input.mp4 \ -c:v libx264 -preset veryfast -tune zerolatency \ -c:a aac -f flv rtmp://192.168.1.100:1935/live/stream1播放验证也很简单。HLS 地址是http://192.168.1.100:8080/live/stream1.m3u8HTTP-FLV 地址是http://192.168.1.100:8080/live/stream1.flv浏览器装个 flv.js 或直接用 VLC 打开即可。SRS 还自带了一个默认的播放器页面访问http://192.168.1.100:8080/players/就能看到这对我做项目演示帮助很大。如果需要自定义SRS 的配置文件是/usr/local/srs/conf/srs.conf容器内路径。我常用的几个关键配置项如下listen 1935; max_connections 1000; srs_log_tank console; vhost __defaultVhost__ { hls { enabled on; hls_path /data/hls; hls_fragment 2; hls_window 10; } http_remux { enabled on; mount [vhost]/[app]/[stream].flv; } rtc { enabled on; rtc_port 8000; } }hls_fragment 2表示每个 TS 切片 2 秒hls_window 10表示播放列表里保留最近 10 秒的切片。这两个值直接影响 HLS 延迟和回看长度想要更低延迟就把 fragment 调到 1但文件数会翻倍要注意磁盘压力。SRS 的优势之一就是这些参数都有中文注释对国内开发者极其友好。3.2 Nginx-RTMP轻量改造派的首选如果你的服务器上已经跑着 Nginx那加一个 RTMP 模块可能是成本最低的方案。以 Debian/Ubuntu 为例直接装模块即可apt install nginx libnginx-mod-rtmp然后在/etc/nginx/nginx.conf末尾追加一段配置rtmp { server { listen 1935; chunk_size 4096; application live { live on; record off; hls on; hls_path /var/www/hls; hls_fragment 2s; hls_playlist_length 6s; } } } http { server { listen 8080; location /hls { types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } alias /var/www/hls; add_header Cache-Control no-cache; } } }这段配置有两个关键点。第一application live是推流路径中的应用名推流地址里的“live”必须和它一致否则会被拒绝。第二HLS 切片默认写到/var/www/hls必须确保目录存在且有写权限否则服务起来之后切片生成失败播放端永远拉不到 m3u8。配置完执行nginx -t检查语法再systemctl reload nginx重载。然后同样用 FFmpeg 推流HLS 地址就是http://服务器IP:8080/hls/stream1.m3u8。整个部署过程十分钟内能搞定特别适合先验证业务可行性。不过要提醒一句Nginx-RTMP 项目维护节奏偏慢对 HTTP-FLV 和 WebRTC 的支持很弱如果业务刚起步可以拿它速成做正式产品还是建议换 SRS 这类持续迭代的项目。3.3 MediaMTX把 RTSP 摄像头接入 WebRTC 的桥安防场景最常见的需求是拉取摄像头的 RTSP 流然后让用户在网页或手机 App 上实时观看。方案很多但 MediaMTX 是我用过配置最轻、最不折腾的。到 GitHub Releases 页下载对应平台的二进制解压后目录里只有一个可执行文件和一份mediamtx.yml。默认配置就能跑默认 RTSP 端口是 8554WebRTC 和 HLS 也都现成可用。启动命令就一句./mediamtx默认情况下访问rtsp://服务器IP:8554/摄像头名会提示找不到流因为 MediaMTX 需要主动从上游拉流。在配置文件中加一段paths: cam1: source: rtsp://admin:password192.168.1.64:554/Streaming/Channels/101这里的source指向摄像头自身的 RTSP 地址cam1是对外暴露的流名称。改完重启就会得到三个可用的播放地址。HLS 是http://服务器IP:8888/cam1/index.m3u8WebRTC 播放地址是http://服务器IP:8888/cam1/webrtcRTSP 回源地址是rtsp://服务器IP:8554/cam1。我最常用的是 WebRTC 方式。在浏览器里用官方提供的 webrtc 播放器样例打开http://服务器IP:8888/cam1/webrtc这个地址对应的播放页面延迟基本在 0.5 秒以内画面拖动感很轻微。这在看门禁、看车间、看工地场景里体验非常关键比 HLS 那种至少 5 秒的延迟强太多。MediaMTX 还支持把整路流转封装后交给其他服务器比如用runOnDemand配合 FFmpeg 转推给 SRS组合起来可以搭出一套“摄像头 → MediaMTX → SRS → 全网分发”的完整链路。这种模块化组合是开源方案最大的优势每个环节选最擅长的组件。4. 常见坑位与排查实录4.1 延迟高的问题三板斧延迟高是流媒体项目里被问得最多的问题。排查顺序我建议固定下来先看播放端协议再看服务端切片参数最后看推流端的编码参数。第一板斧是确认播放端用的协议。如果播放端走的是 HLS3 到 6 秒延迟是正常现象觉得受不了就换成 HTTP-FLV 或 WebRTC。经常有人一边用 HLS 一边抱怨延迟两秒这属于拿着锤子找钉子问题不在服务端。第二板斧是检查服务端的切片时长。HLS 延迟大致等于“切片时长 × 2”再加上播放器的缓冲。把hls_fragment从 5 秒改成 2 秒延迟立刻能降下来好几秒。SRS 和 Nginx-RTMP 都支持运行时修改改完重载即可生效不用重启。第三板斧是推流端的 GOP 设置。GOP 是 H.264 编码里的关键帧间隔它同时影响延迟和兼容性。常见播放器在关键帧到达之前都不会出画面所以编码器参数里要加-g 60每 2 秒一个关键帧和-tune zerolatency零延迟编码预设。这两个参数在 FFmpeg 推流命令行里加上效果立竿见影。4.2 播放白屏、无法启动、鉴权失败的处理白屏和无法启动是最让新手崩溃的两类问题其实多数时候原因很简单。播放白屏先打开浏览器开发者工具看 Network 面板HLS 播放时如果 m3u8 请求被 CORS 拦截报错信息会非常明显。解决办法是给服务端加上Access-Control-Allow-Origin: *响应头Nginx 里加一行add_header即可。服务起不来的情况八成是端口被占用或配置语法错误。Nginx 用nginx -t检查配置SRS 启动日志里会明确打印监听失败的原因。我遇到过最隐蔽的问题是把两个项目都配置成监听 1935 端口服务轮番崩溃排查半天才发现是部署脚本里把 SRS 和 Nginx-RTMP 同时启了。鉴权失败则要从两个层面看。流媒体服务器自身的鉴权比如 SRS 的http_hooks回调配置不对会直接拒绝推流业务层的鉴权比如播放地址带 token 参数一般是签名过期或时间戳不一致。我建议调试阶段先关掉鉴权确认链路通了再加回否则叠加在一起很难定位。4.3 上线前必须做好的几件事项目能跑通和能上线是两码事我吃过亏所以列几条经验。第一所有对外服务必须走 HTTPS。浏览器里调用 getUserMedia 和 WebRTC 都要求安全上下文HTTP 环境下功能会被浏览器直接禁用这条不满足Web 端实时播放就是空谈。用 Nginx 做反向代理加证书是最常见的做法。第二WebRTC 涉及 UDP 端口很多云服务器的安全组默认不放行 UDP。部署后一定要在安全组和系统防火墙两层都确认 UDP 8000 端口可用。我见过防火墙文档写的是“放行 TCP”结果 UDP 被拦WebRTC 怎么都连不上。第三视频内容是 7×24 小时写入磁盘会持续增长HLS 切片目录必须配置定期清理策略。SRS 的hls_window会自动删除过期切片但如果自己拿 Nginx-RTMP 做 HLS就需要写一个 crontab 清理脚本否则半年后磁盘满了才被发现整个服务直接写不进去。第四日志和监控要提前接入。SRS 提供 HTTP API 可以查询在线连接数MediaMTX 也有日志输出把这些接入已有的监控系统比事后翻日志高效得多。5. 我的选型经验与后续扩展建议5.1 按团队能力和项目周期选技术栈选型这件事我现在的判断依据非常简单团队里有几个人能看懂源码、项目周期有多长、客户会不会要求二次开发。如果只是给公司内部做一个直播工具人数不超过百人Nginx-RTMP 或者 MediaMTX 足够别为了“专业”上一个自己驾驭不了的平台。如果你在做一个对外交付的产品直接选 SRS它的生态和社区让后续招人、查文档、抄配置都有保障。安防类项目没有商量余地ZLMediaKit 加相关的 GB28181 网关是绕不开的路线选它就要做好啃 C 源码和协议规范的心理准备。这套判断标准帮我在不少项目里避免了“过度选型”。有个客户原本坚持要上“某商业流媒体平台”我核算完并发和延迟需求后直接用一个 SRS 实例解决半年省下十几万授权费客户自己后来还在内部推广了这套方案。开源项目真正的价值不只是免费而是你手里始终握着掌控权。5.2 预留扩展口子别把架构做成死胡同最后一个建议给所有准备动手的人先想清楚半年后可能增加什么需求再决定今天的部署方式。常见扩展方向有这么几个一是鉴权系统SRS 和 MediaMTX 都支持对接外部 HTTP API 做推拉流鉴权建议一开始就把回调地址约定好别等上线了再补。二是多服务器分发单机扛不住的时候要么加 CDN要么用 SRS Origin Edge 集群模式这个架构最好在第一次部署时就留出域名和端口规划。三是录制回放推流的同时录制 FLV 或 MP4对直播内容留存几乎是刚需。我自己踩过最深的坑就是一开始只图快把所有流都推到一台裸 Nginx-RTMP 上后来业务量上来想加录制、想加鉴权、想加集群全都得推倒重来。后来换了 SRS这些能力本来就是内置的只是改配置的问题。如果你面前只有一条路走到黑的可能那不如先花半天时间把 SRS 这类功能完整的项目跑起来而不是从一路轻量方案里慢慢拆东墙补西墙。视频流服务器这个领域开源项目的成熟度已经远超很多人的预期。从几百人的内部直播到上万路的安防监控都有对应的免费方案能抗住。希望这篇基于实际部署经验的梳理能让你在面对一堆协议、框架和端口号的时候少走几段弯路。