ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Windows下用Nginx搭建RTMP视频流服务实战指南

Windows下用Nginx搭建RTMP视频流服务实战指南 最近在给一个展厅做互动大屏的实时画面分发源端是一台 Windows 主机的桌面画面要同时送到大厅里几块屏幕上。我的第一反应就是搭一套 RTMP 视频流服务而 Windows 环境里最顺手的组合仍然是 Nginx 加上 nginx-rtmp-module。这篇文章就把我这次实际搭建、验证、排坑的完整过程写出来从下载哪个包、怎么改配置到 OBS 怎么推、VLC 怎么拉再到局域网内联调时最容易翻车的几个点全部贴着实战讲。准备在 Windows 上做推拉流中转、给 Unity 或 C# 项目接视频流、把摄像头画面分发给多台终端的朋友可以直接照这个流程走。1. 先想清楚 RTMP 服务是干什么的别一上来就装1.1 RTMP 协议原理与“推-拉”角色RTMP 是 Adobe 在 Flash 时代推出的实时消息传输协议基于 TCP 长连接默认端口 1935。它有非常清晰的推流端、服务器、播放端三角色源端把音视频流推送publish到服务器播放端再从服务器拉取play同一路流。它本质上是“单一产生端多路消费端”的分发模型。举一个能瞬间理解的例子RTMP 服务器就像电视台的总控机房前方记者OBS、摄像头把画面实时传回总控总控再决定把这路信号送给家里所有电视机VLC、播放器、Unity 视频纹理。不需要每个客户端都直连前端摄像机而是各自连总控这样摄像机端只需要推一路流效率高管理也集中。虽然在浏览器里直接播放 RTMP 已经不太好使但因为延迟低、推流端生态成熟在局域网大屏、摄像头接入、直播采集场景里依然是主力协议。Nginx 的 rtmp 模块已经稳定运行很多年所以我做内网视频分发首先会想到它。1.2 主流方案对比为什么选 Nginx 而不是 SRS、MediaMTX搭建流媒体服务常见的软件有 SRS、MediaMTX、Red5、nginx-rtmp-module。我直接给一个对照表方便大家根据自己的情况判断方案跨平台协议支持配置复杂度适合场景Nginx rtmpWindows / LinuxRTMP、HLS、HTTP-FLV低快速搭推拉流中转中小规模分发SRSLinux 为主RTMP、SRT、WebRTC、HLS高大规模直播集群、复杂业务MediaMTX全平台RTSP、RTMP、WebRTC、SRT 等低多协议转换、AI 项目集成Red5全平台RTMP、HLS高Java 生态、自研播放器我选 Nginx 不是因为它在所有维度上最强而是因为在 Windows 上“够用且可控”。很多项目其实只有几路流、几个客户端用 SRS 要学一整套配置体系用 MediaMTX 倒也不是不行但 Nginx rtmp 模块几乎是人人都能上手的那一档一个配置文件搞定推流、拉流、录制、转推、HLS 输出而且包体只有几 MB拷贝到任何一台 Windows 机器上就能跑。它还自带一个短板必须说清楚不支持 WebRTC 协议对多路高码率并发流的承载能力也不如 SRS。你的需求如果只是“几路到几十路、单机几千并发以内”它完全够用一旦要上百路或者涉及 WebRTC 低延迟通话那就要换方案了。1.3 这个服务到底能用在哪些场景这次展厅项目的实际需求是一台 Windows 工作站采集桌面画面通过 RTMP 推到 Nginx展厅三块大屏分别用播放器拉流。这类场景经常出现在展厅、门店的多屏联动一块屏幕采集其他屏幕同步播放摄像头 RTSP 转 RTMP 后统一分发下游播放端不再关心摄像头品牌Unity 里用 VideoPlayer 播放流媒体给 HUD、视频墙、互动装置提供画面教育培训、会议画面的内网直播备份如果你在 Unity 里做视频墙渲染或者用 C# 接海康摄像头的画面这套服务可以帮你把“多路海康 RTSP 流”先收敛成“一路 RTMP 流”再统一分发给不同的终端。这样每一台终端都不需要单独装解码 SDK播放链路会清爽很多。2. Windows 环境准备下载、解压、启动一条龙2.1 带 rtmp 模块的 Nginx 包怎么选这一步最容易踩坑我建议的做法是不自己编译源码直接下载已经编译好的稳定版。GitHub 上很多开源项目会把 nginx rtmp 打包成 Windows 发布版本这些包通常已经内置了 nginx-rtmp-module有的还带了 http-flv 模块。选版本时有三个原则优先选 nginx-rtmp-module 版本为 1.2.1 或更新的包老版本有一些非致命但比较烦人的 bug。优先选和 Nginx 主版本匹配的稳定版别用太新的开发版Windows 下的表现不一定稳定。下载后先看一眼根目录里有没有 conf/nginx.conf、nginx.exe、logs 这三个基本结构缺少任何一个都说明包不完整。这里还要强调一个老生常谈的误区不要把 Nginx 官方 Windows 版和带 rtmp 模块的第三方编译包混淆。官方 nginx.exe 默认不带 rtmp 指令直接往配置里写rtmp {}块执行nginx -t时会报unknown directive rtmp。所以下载之前一定要确认包里到底有没有 rtmp 模块。2.2 目录规范纯英文、短路径、避开权限坑Windows 上跑 Nginx 有一个很常见的坑中文路径。如果你把 Nginx 解压到D:\视频服务\nginx后续推流时某些播放器和推流软件在 URL 拼接上会出现字符编码问题日志里也容易出现乱码。我一般固定在D:\nginx-rtmp这种纯英文目录下。另一个坑是权限。程序如果解压在C:\Program Files这一类受保护目录启动时会因为权限不足导致无法写入 logs 目录表现为双击 exe 闪退或者nginx -t执行正常但进程起不来。解决办法是直接放在普通用户目录或 D 盘根目录没必要为了跑一个 Nginx 去开管理员权限更不建议养成“所有程序都右键管理员运行”的习惯。目录结构准备好后检查一下是否有 logs 文件夹。如果手动删掉过 logsNginx 启动时会因为找不到目录直接报错这类问题在网上的提问里出现过很多次。2.3 启动与基础检查命令启动方式很简单打开命令行切到 Nginx 目录cd /d D:\nginx-rtmp start nginx.exestart是关键它会新开一个窗口把 nginx 跑在后台。直接执行nginx.exe也不是不行但窗口会一直挂在前台不小心按到 Ctrl C 进程就断了。启动之前最好先做一次配置语法检查nginx.exe -t如果输出syntax is ok再执行start nginx.exe。停止服务用nginx -s stop重新加载配置用nginx -s reload。这里我有一个实测经验要分享改了rtmp{}块内部的关键参数后-s reload经常不生效表现为配置改了但推流行为没变化。最稳妥的流程是先nginx -s stop再start nginx.exe重新启动。后面第 5 章会细说为什么。3. nginx.conf 配置逐项拆解推流地址、录制、转推、HLS 一次讲透3.1 最小可用的 rtmp 配置模板拿到包之后打开的 conf/nginx.conf重点关注两个块http{}和rtmp{}。http 块负责管理后台页面和 HLS 切片服务rtmp 块负责 RTMP 推拉流服务。一个最小可用的配置模板如下我建议直接参考这份来改worker_processes 1; events { worker_connections 1024; } rtmp { server { listen 1935; chunk_size 4096; application live { live on; record off; allow publish 127.0.0.1; deny publish all; allow play all; } } } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } } }这里面每个参数都不白给。listen 1935指定 RTMP 服务端口chunk_size 4096是数据块大小一般保持默认即可。application live相当于定义一个应用名它决定了推流地址里的路径部分。live on开启直播模式record off关闭录制。关键是allow publish和deny publish这两行。它表示只允许本机推流局域网内其他电脑想推流会被拒绝。如果只是为了本机测试这样写最安全如果想局域网内多台设备都能推流可以把允许范围改成网段写法比如allow publish 192.168.1.0/24;。很多新手在这里翻车配了allow publish 127.0.0.1然后在另一台电脑上用 OBS 推流服务器却一直拒绝连接。这不是网络问题是权限规则把非本机的推流请求挡掉了。3.2 推流地址的语义application、stream name 怎么规划RTMP 地址的格式一般是rtmp://IP:端口/application/stream_name举个例子rtmp://192.168.1.10:1935/live/room1这里/live就是配置里的application liveroom1是流的名字。OBS 设置里通常分成两栏服务器地址填rtmp://192.168.1.10:1935/live串流密钥填room1。服务器自动把两部分拼成完整地址。在实际项目里我习惯用业务含义来命名 application 和 stream。一路展厅大屏推流用live/screen_01一路摄像头画面用live/cam_west这样在后续日志和播放端定位问题时一目了然。不要用test、aaaa这种没有辨识度的名字否则流一多就完全乱了。流的名称同时会受到推流软件和服务端的双重校验它本质上不是安全鉴权但没有对外暴露内网 IP 和合法流名确实能降低被乱推流的概率。如果部署到公网必须走 3.3 节的 on_publish 鉴权。3.3 record 录制、push 转推、on_publish 鉴权这几个高级参数怎么配RTMP 模块除了转发还有几个非常实用的附加功能我重点说三个。直播录制把record off换成下面的配置每一路推上来的流都会被录制为 FLV 文件。record all; record_path D:/nginx-rtmp/rec; record_unique on;record_unique on会保证每条流生成不同文件避免被覆盖。注意 Windows 路径要用D:/nginx-rtmp/rec这种正斜杠写法反斜杠在配置解析里会被当成转义字符这是 Windows 上非常容易踩的 Api。多路转推push如果希望把 Nginx 收到的流再推到另一台服务器例如同时分发到公网 CDN可以加一行push指令。application live { live on; push rtmp://目标服务器/live/stream_name; }它会在任意客户端推流到当前 application 时自动向目标发起推流相当于做了一个级联中转。实测下来 push 指令最好写在 application 内部配合pull指令可以实现双向转发适合总部-分支机构的级联场景。on_publish 鉴权nginx-rtmp 原生不带推流密码但提供了回调机制。推流开始时会请求一个 HTTP 接口接口返回 2xx 才允许推流。application live { live on; on_publish http://127.0.0.1:8080/auth; }后端接口接收请求后检查name流名和addr客户端地址等参数决定是否放行。这个功能在部署到公网时几乎是必须的否则任何知道地址的人都能往你的服务器推流。局域网内测试可以先不开但心里要清楚它存在。3.4 HLS 输出与 HTTP-FLV 扩展让浏览器和 Unity 也能播RTMP 协议在浏览器里现在已经很难直接播放如果要给 Web 页面或移动端看最好同时开启 HLS 输出。配置方式是在 rtmp 的 application 里加 HLS 参数再在 http 块里加一个 location 用于访问.m3u8文件。rtmp { server { application live { live on; hls on; hls_path D:/nginx-rtmp/hls; hls_fragment 2s; hls_playlist_length 6s; } } } http { server { location /hls { types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } alias D:/nginx-rtmp/hls; add_header Cache-Control no-cache; } } }这样播放端可以用http://IP/hls/stream_name.m3u8拉流。HLS 的切片时长非常影响延迟hls_fragment 2意味着每 2 秒切一个 ts 文件播放端延迟大约为切片时长加播放器缓存实测在 4 到 8 秒左右。需要更低延迟就用 RTMP 或 HTTP-FLVHLS 从来就不是低延迟方案。如果要给网页用 flv.js 做低延迟播放可以配置 HTTP-FLV。前提是下载的 Nginx 包必须带 http-flv 模块否则会报unknown directive flv_live。配置方式是在 http 块里加location /live { flv_live on; chunked_transfer_encoding on; add_header Access-Control-Allow-Origin *; }播放地址变成http://IP/live?applivestreamstream_name用 flv.js 就能在浏览器里实现 1 到 3 秒的低延迟播放。这个配置属于进阶玩法按需使用。4. 全链路推拉流实操验收OBS、ffmpeg、VLC 一个都不能少4.1 OBS 推流视频编码、码率、关键帧这几个参数千万别乱调OBS 是 PC 端最常用的推流软件配置路径在“设置 - 直播”。服务器填rtmp://你的IP:1935/live串流密钥填一个自己定义的流名比如test。最影响实际效果的是“输出”这一栏。我建议打开输出模式的高级选项重点调整几个参数视频编码器硬件编码或 x264 都可以实测在 Windows 上硬件编码占用低x264 画质更稳视频码率1080p 建议 4000 到 8000 Kbps画质和带宽要平衡关键帧间隔建议 2 秒这个参数直接影响播放端出画速度音频编码器AAC码率 128 或 192这里我要单独强调关键帧间隔。播放器解码时必须等到 I 帧才能开始显示画面如果关键帧间隔设了 10 秒播放器可能会等很久才出图像观感就是黑屏或者长时间加载。2 秒是比较均衡的数值既不会让文件体积膨胀太厉害也能让新加入的播放端快速出画。音频方面如果投影内容不需要声音仍然建议保留一路 AAC 静音轨很多播放器没有音频轨时会表现异常比如 VLC 部分版本会出现“无法播放”的提示。这个坑我在项目里遇到过后来在 OBS 里加了一路静音麦克风就解决了。4.2 用 ffmpeg 生成测试流不依赖摄像头也能验证不是每个人都有摄像头随时可以推流所以我习惯用 ffmpeg 生成一路测试视频源快速验证整套链路。ffmpeg 在 Windows 上可以直接下载官方编译包放进系统 PATH 后在任何目录执行。推一路实验室测试画面ffmpeg -re -f lavfi -i testsrc2size1280x720:rate30 -c:v libx264 -preset veryfast -tune zerolatency -c:a aac -f flv rtmp://127.0.0.1:1935/live/test如果想把 Windows 桌面实时抓取并推流ffmpeg -f gdigrab -framerate 30 -i desktop -c:v libx264 -preset veryfast -tune zerolatency -c:a aac -f flv rtmp://127.0.0.1:1935/live/desktop-re参数表示按源文件正常速率读取否则 ffmpeg 会尽可能快地推流导致服务器端接收节奏异常。-tune zerolatency对直播非常重要它会降低编码器缓冲延迟从而减少播放端的延迟。-f lavfi -i testsrc2是 ffmpeg 内置的测试画面生成器不需要额外视频文件就能工作。实测下来这套命令在 Windows 上很稳定。唯一要注意的是如果机器上没有音频设备-c:a aac可能报错此时可以去掉音频参数直接推纯视频流。4.3 VLC 和 ffplay 拉流验证链路通不通就看这一步推流成功后需要在播放端验证。最简单的就是 VLC打开“媒体 - 打开网络串流”输入rtmp://127.0.0.1:1935/live/test点击播放。如果配置正确几秒后就能看到画面。用 ffplay 也可以ffplay rtmp://127.0.0.1:1935/live/test本机验证通过后再拿另一台局域网电脑测试。这时需要把地址里的127.0.0.1换成服务器的局域网 IP比如rtmp://192.168.1.10:1935/live/test。如果另一台机器连不上不要急着怀疑配置优先检查 Windows 防火墙是否放行了 TCP 1935 端口。这一步的操作放到第 5 章详细说但记住局域网联调时防火墙放行是优先级最高的一步。5. 常见问题与排查技巧实录这些坑我基本都踩过5.1 端口占用导致 Nginx 启动失败现象执行start nginx.exe后进程闪退或者nginx -t正常但访问 1935 端口没反应。排查步骤是先确认端口被谁占用了netstat -ano | findstr :1935如果输出里有监听记录记下最后一列的 PID去任务管理器里找到对应进程结束掉或者直接把 Nginx 的监听端口改成 19350 这种不常用端口。很多网监、安全软件会默认占用一些端口改端口是最省事的做法不要跟系统抢。另一种情况是之前已经启动过 Nginx再次启动时端口被自己占住此时执行nginx -s stop后再启动即可。Windows 下 Nginx 进程名是nginx.exe如果任务管理器里能看到多个 nginx 进程不要随手全删先停掉再清理残留。5.2 OBS 推流提示 connect timed out 或 connect failed这是局域网联调中最高频的问题。我看到过一个误区Nginx 配置没问题、OBS 设置也对了但推流就是超时原因十有八九是防火墙没放行。打开“控制面板 - Windows Defender 防火墙 - 高级设置”在“入站规则”里新建一条规则选择端口协议选 TCP端口填 1935然后允许连接。创建后要确认当前网络配置文件是“专用”还是“公用”如果 Nginx 所在机器当前网络类型是“公用”而你创建的规则只应用到“专用”规则就不会生效。这一点非常隐蔽很多人明明加了规则仍然连不上就是因为没匹配当前网络类型。还有一种情况是把服务器地址填成了localhost或127.0.0.1另一台机器访问时当然无效。OBS 里填的地址必须以实际局域网 IP 为准不确定就执行ipconfig看一下本机 IPv4 地址。5.3 播放黑屏、花屏、卡顿如果推流和拉流连接都成功但画面出不来或者很卡问题基本集中在编码参数上。黑屏最常见的原因是关键帧间隔设置过长。播放器必须等到一个完整的关键帧才能开始显示画面关键帧间隔 10 秒时播放端可能要黑屏好几秒甚至更久。把 OBS 里的关键帧间隔改成 2 秒是最直接的解决办法。卡顿通常由码率引起。局域网内千兆带宽下10 Mbps 以下都没什么问题但如果是无线网络或跨公网传输码率过大就会缓冲卡顿。遇到卡顿先降低推流码率同时检查是不是服务器所在机器的网卡负载过高。我做过一个项目Nginx 跑在一台低配 Windows 工控机上单路 1080p 推流没问题三路同时推就频繁卡顿最后把每路码率从 8 Mbps 降到 5 Mbps 才稳定。花屏多半是流数据损坏常见于 UDP 丢包或者推流端编码器不稳定。解决思路是优先用 TCP 传输局域网内不要为了追求极低延迟去做激进的重传关闭稳定优先。5.4 配置改了但行为没变化该怎么看日志修改 nginx.conf 后执行nginx -s reload有时候推流行为没变化比如明明改了 application 名称OBS 旧地址居然还能用。这大概率是-s reload对 rtmp 模块的配置没有完全生效老配置还留在进程中。我实测下来最可靠的流程是nginx -s stop start nginx.exe不要嫌麻烦Windows 下 Nginx 进程启停都很快几秒就能完成比纠结 reload 是否生效省心得多。至于日志logs/error.log 是整个排查过程中的第一入口。推流失败、播放失败、权限拒绝都会在这里留下记录。看到connection closed时先检查网络是否中断看到no application is configured for ...时说明地址里的 application 名字和服务端配置不一致看到permission denied时优先检查防火墙和 publish 权限规则。我之前排查一个几分钟断流一次的问题最后就是靠 error.log 里反复出现的connection reset by peer定位到交换机端口做了空闲超时切断属于网络层问题而不是 Nginx 配置问题。5.5 局域网内能 ping 通但打不开流常见原因速查现象可能原因处理方式推流超时防火墙未放行 TCP 1935添加入站规则匹配当前网络类型其他电脑连不上地址用了 127.0.0.1换成服务器局域网 IPv4 地址播放黑屏关键帧间隔过长OBS 关键帧设为 2 秒播放卡顿码率过高或无线网络降低码率换有线连接配置修改不生效reload 未加载 rtmp 配置stop 后重新 startunknown directive rtmpNginx 包不带 rtmp 模块下载带模块的编译包本机测试正常局域网失败防火墙规则只适用于专用网络调整网络类型或规则范围6. 扩展应用场景与最后的个人体会6.1 对接 Unity、C# 和海康摄像头流的思路如果你和我一样最终目的是给 Unity 客户端或者 C# 程序提供视频流这套 Nginx 服务会变成一个很好的“统一接入层”。拿 Unity 举例Unity 的 VideoPlayer 原生不支持 RTMP 直连但支持通过 HTTP 播放 HLS 流。所以你只要在 Nginx 里开启 HLS 输出Unity 客户端直接输入http://IP/hls/stream_name.m3u8就能播放。如果项目里必须用 RTMP可以引入第三方库比如 FFmpeg 插件来拉流但开发量会大不少。海康摄像头的接入方式通常是先拉 RTSP 流再用 ffmpeg 转成 RTMP 推到 Nginx。命令类似ffmpeg -rtsp_transport tcp -i rtsp://用户名:密码摄像头IP:554/Streaming/Channels/101 -c:v copy -c:a aac -f flv rtmp://127.0.0.1:1935/live/cam01这样下游播放端只需要面对一个标准的 RTMP 地址不用关心海康的私有 SDK也不用在每一个客户端单独处理 RTSP 鉴权和协议差异。推拉流模型让“多路采集、多端消费”变成一个很清爽的架构。6.2 内网服务的边界与安全注意点这套方案在局域网内非常舒服但真要放到公网或者云服务器上有几个边界必须心里有数。第一默认配置没有鉴权任何知道地址的人都能推流和拉流。公网部署前至少开启 on_publish 鉴权并配合防火墙只放行可信 IP。第二RTMP 推流对上行带宽有硬性要求一路 1080p 大约要占 4 到 6 Mbps 上行带宽。云服务器带宽是按照流量计费的如果多路长时间推流费用不能忽略。第三Nginx rtmp 不是高并发设计单机几十路还能扛上百路建议换 SRS 或者做集群分流。我记得自己第一次搭这套服务时卡在下载了官方 Nginx 却配不出 rtmp 那一步后来换了带模块的编译包又卡在防火墙放行。这些坑不是从文档里能直接找到的都是实测踩出来的。如果你按这篇流程走一遍局域网推拉流链路基本就能通后面要做的只是按业务情况去调命名、调码率、加鉴权。希望这篇能帮你少走点弯路。
返回列表