ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FFmpeg推流实战:用smart_rtmpd快速搭建轻量RTMP直播服务

FFmpeg推流实战:用smart_rtmpd快速搭建轻量RTMP直播服务 最近在调试移动端直播链路时我把 FFmpeg 推流的目标服务器换成了 smart_rtmpd。之前一直用 SRS 和 Nginx-RTMP功能没得挑但每次想在笔记本上快速验证一条推流命令总得先折腾一轮配置。smart_rtmpd 最大的特点就是轻解压即可运行本地几秒钟就能把 RTMP 服务拉起来然后把 FFmpeg 的推流地址指过去就能干活。这篇笔记就记录我从服务器部署、推流命令、延迟排查到踩坑处理的完整过程适合正在做直播开发、想用 FFmpeg 快速联调推流的朋友参考。1. 为什么我在直播联调时把默认RTMP服务器换成了smart_rtmpd先说结论我不是说 SRS 或 Nginx-RTMP 不好而是这两者在“联调场景”下有点重。SRS 要了解配置项、信令流程Nginx-RTMP 要折腾 nginx.conf 和模块编译如果只是测一条ffmpeg -re -i xxx.flv rtmp://...这些前置成本显得多余。smart_rtmpd 属于典型的“开箱即用型”直播服务器我把它当成 RTMP 协议的“回显设备”你推什么它接什么然后你再从同一个地址拉出来看效果。1.1 smart_rtmpd 和 SRS、Nginx-RTMP 的定位差异在项目里我做过一个简单对比整理成表格如下对比项smart_rtmpdSRSNginx-RTMP部署难度低下载即用中需要配置和启动中要编译或装额外模块适合场景本地开发、命令验证、小规模内网测试生产环境、大规模直播、复杂分发传统RTMP模块、与Nginx集成配置复杂度基本免配置配置项多、能力全面依赖Nginx上下文日志可读性直观适合看推流成功与否详细但信息量大和Nginx日志风格一致如果你只是需要“有个 RTMP 服务能收流”smart_rtmpd 能省不少事如果要承载成千上万的拉流用户还是老老实实上 SRS 那一类生产级服务器。1.2 FFmpeg、smart_rtmpd、播放器三者之间的推流链路这条链路并不复杂但很多人一遇到延迟就开始无脑调命令其实是因为没把链路拆开。推流链路大致是采集/文件读取 → FFmpeg 编码封装 → RTMP 推送 → smart_rtmpd 接收 → 播放器 RTMP 拉流 → 解码渲染延迟可能出现在“FFmpeg 编码器侧”“服务器分发侧”“播放器缓冲侧”并不总是推流端的错。后面我会专门写一节排查方法。2. 十分钟把 smart_rtmpd 部署起来下载、启动、验证一条龙这一节我按实际操作顺序写Windows 和 Linux 都适用。2.1 下载和解压从项目发布页下载对应操作系统的压缩包Windows 下解压到任意目录即可Linux 下我习惯放到/opt/smart_rtmpd/下。需要注意安装路径尽量不要有中文和空格否则程序加载相对配置文件或日志文件时可能因为路径解析问题启动失败。我第一次放在带空格的目录里启动就报找不到配置路径改成纯英文路径后一切正常。解压后目录里一般有主程序、配置文件和文档。不同版本主程序命名可能不同如果没有特殊说明直接运行目录下的可执行文件。2.2 启动服务并确认端口监听Windows 下在 cmd 里执行主程序名Linux 下执行./smart_rtmpd正常启动后日志会打印监听地址。RTMP 默认端口是 1935。我建议启动后用 netstat 或 ss 确认端口真的在监听Linuxss -lntp | grep 1935Windowsnetstat -ano | findstr 1935这一步能快速区分“服务没起来”和“服务起来但端口没监听”。如果端口没起来先看配置文件的端口项是不是被改了再看是不是被防火墙挡了。2.3 修改监听端口和局域网访问按需修改配置文件里的端口项比如改成 19350listen 19350;改完重启进程再执行一次ss -lntp确认。这里有一个很多人忽略的细节如果你只是本机测试RTMP 地址写127.0.0.1就够了如果要让手机或另一台电脑推流/拉流服务器必须监听 0.0.0.0 而不是 127.0.0.1否则局域网设备根本连不上。做局域网访问时还需要在系统防火墙里放行对应端口。开发环境下可以先保证本机访问正常再进行局域网放行避免把你的测试环境完全暴露在公网。2.4 用 ffprobe 验证服务在不在“响应”服务有没有起来不一定非得看日志。我有个习惯在推送前先用 ffprobe 探一下地址ffprobe rtmp://127.0.0.1:1935/live/test如果服务在运行但当前没有推流FFprobe 会报错但报错内容通常是“超时”或“找不到流”这说明服务在响应请求。如果直接报“Connection refused”那说明服务没跑起来或端口不对。这个办法比对着日志猜端口快很多。3. FFmpeg 推流前必须搞明白的封装和编码要求这一节是我在整个测试过程中收获最大的一部分因为绝大多数推流失败其实不是 smart_rtmpd 的问题而是 FFmpeg 封装格式和编码格式不匹配。3.1 为什么 RTMP 推流必须加-f flv很多 MP4 文件直接用 FFmpeg 推送时报错或者推上去了播放器黑屏。原因在于 RTMP 协议传输的内容是 FLV 流不是裸 MP4。FFmpeg 里输出格式用-f flv明确指定等于告诉 muxer“把数据封装成 FLV 再发送”。ffmpeg -re -i input.mp4 -c copy -f flv rtmp://127.0.0.1:1935/live/test-f flv这个参数放在输出文件也就是 RTMP 地址前面。虽然 FFmpeg 有时会根据rtmp://前缀自动判断 muxer但显式写出来更稳也方便后发现封装问题。3.2 FLV 容器和编码格式的兼容关系FLV 容器对视频编码的支持很有限最常见的是 H.264音频最常见的是 AAC。如果你用 HEVCH.265视频源直接-c copy推流时大概率会报错或者服务器能接收但播放器花屏、黑屏。所以遇到推不上服务器的文件第一时间用 ffprobe 看编码格式ffprobe -show_streams input.mp4看到codec_namehevc或codec_namevp9这类字段就别想着-c copy了老老实实转码成 H.264ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -c:a aac -f flv rtmp://127.0.0.1:1935/live/test3.3-re参数为什么对文件推流那么重要没有-re时FFmpeg 会以“能读多快就读多快”的方式读取本地文件一条一分钟的视频可能一秒钟就读完并推完。这在点播场景没问题但在直播场景是错误的因为直播需要按时间轴实时推送。-re的作用就是让 FFmpeg 按文件原帧率读取输入模拟出实时的效果。所以只要输入是本地文件推流必须加-re如果输入是摄像头这类已经实时产生数据的设备则不要加-re否则可能出现采集速度跟不上、时间戳错乱的问题。4. 三套最常用的 FFmpeg 推流命令本地文件、摄像头、循环垫片4.1 本地视频文件推流这是我最常用的联调方式没有之一。源文件是 H.264 AAC 时用-c copy不转码、不消耗 CPUffmpeg -re -i input.mp4 -c:v copy -c:a copy -f flv rtmp://127.0.0.1:1935/live/test如果源文件编码格式不兼容就用重编码方案ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -tune zerolatency -b:v 2000k -c:a aac -b:a 128k -ar 44100 -ac 2 -f flv rtmp://127.0.0.1:1935/live/test其中-b:v 2000k是视频码率具体值取决于测试目的。我一般先用 2Mbps 做基准再逐步往上顶看服务器和网络能不能扛住。-ar 44100 -ac 2是音频采样率和声道部分播放器对音频参数比较敏感显式指定能避免“有画面没声音”。4.2 摄像头采集推流Windows 下要先用 dshow 枚举设备名ffmpeg -list_devices true -f dshow -i dummy然后根据列出的设备名推流ffmpeg -f dshow -i videoUSB Camera -s 1280x720 -r 25 -c:v libx264 -preset veryfast -tune zerolatency -c:a aac -f flv rtmp://127.0.0.1:1935/live/test没有麦克风时去掉音频输出参数ffmpeg -f dshow -i videoUSB Camera -s 1280x720 -r 25 -c:v libx264 -preset veryfast -tune zerolatency -an -f flv rtmp://127.0.0.1:1935/live/testLinux 下的写法类似设备节点一般是/dev/video0ffmpeg -f v4l2 -framerate 25 -video_size 1280x720 -i /dev/video0 -c:v libx264 -preset veryfast -tune zerolatency -an -f flv rtmp://127.0.0.1:1935/live/test我特别提醒一句Windows 的摄像头名称里有中文或空格时video这里别写错很容易翻车。宁可先列出设备再复制粘贴设备名也不要手敲。4.3 循环推流当备用信号源直播项目里经常遇到一个场景主信号源断了不能让播放端直接黑屏要用一段宣传片循环兜底。这时用-stream_loop -1ffmpeg -re -stream_loop -1 -i placeholder.mp4 -c:v copy -c:a copy -f flv rtmp://127.0.0.1:1935/live/backup-stream_loop -1表示无限循环读取输入文件它属于输入参数必须放在-i前面。这里的-c copy在编码格式满足条件时效率最高循环推流跑几天都不太占 CPU。5. 推流到 smart_rtmpd 延迟高按这个顺序排查这是我在测试中花时间最多的地方。很多人一看到“延迟”就把锅甩给服务器实际上延迟往往是三层因素叠加出来的。5.1 延迟到底出在哪一个环节先把链路拆开看环节常见延迟来源容易判断程度FFmpeg 编码x264 编码缓冲、GOP大小、preset中网络传输TCP 拥塞、上行带宽不足低smart_rtmpd 服务端关键帧间隔、连接缓冲中播放器渲染播放器自带缓冲、音视频对齐高我以前遇到过一例FFmpeg 侧参数已经调到极致延迟还是 3 秒起步。排查到最后发现是播放器默认缓冲了 2 秒加上 GOP 是 5 秒首屏慢和画面延迟自然都来了。5.2 编码器侧三个最有效的低延迟参数第一个是-preset veryfast。x264 的 preset 决定编码速度和压缩率的取舍preset 越快编码耗时越短丢帧和缓冲的可能性越小。追求极致延迟可以-preset ultrafast但画质和码率代价更大建议从 veryfast 起步。第二个是-tune zerolatency。它会针对低延迟场景优化 x264 内部参数关闭一些引入额外延迟的特性适合交互式直播和视频通话。第三个是-g。它决定关键帧间隔-g 50在 25fps 下就是每 2 秒一个关键帧。RTMP 播放器连接服务器后通常要等下一个关键帧才能出画面所以 GOP 太长首屏就会明显变慢。建议联调时设为 1~2 秒也就是帧率等于多少-g就设多少的 1~2 倍。示例命令ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -tune zerolatency -g 50 -keyint_min 50 -b:v 2000k -maxrate 2200k -bufsize 2200k -c:a aac -f flv rtmp://127.0.0.1:1935/live/test-maxrate和-bufsize控制码率波动幅度防止编码器在画面复杂时突然冲出过高码率挤爆上行带宽导致播放器缓冲。用这两个参数把码率收紧在设定附近延迟会更稳定。5.3 smart_rtmpd 服务端和播放器怎么配合服务器一般不会自作主张给你加上大缓冲但播放器为了追求流畅往往会做“缓冲自愈”。所以我在测量延迟时强烈建议先用命令行播放器排除播放器缓冲干扰ffplay -fflags nobuffer -flags low_delay -framedrop rtmp://127.0.0.1:1935/live/test三个参数的含义-fflags nobuffer关闭播放器缓冲数据到了就播放-flags low_delay告诉解码器走低延迟模式-framedrop解码不过来时直接丢帧避免音频等视频。如果这个命令播放出来的画面比之前肉眼可见更“实时”说明延迟大头在播放器缓冲而不是 smart_rtmpd。5.4 一种笨但靠谱的延时测量方法不引入复杂工具的前提下最简单的方法是把手机秒表放在摄像头前推流后通过 ffplay 拉流对比播放画面里的秒表读数和真实手机秒表读数差值就是近似端到端延迟。实际操作时我会推一个测试画面然后同时打开手机秒表和 ffplay对着画面拍一张照读取两个数字的差值。同一时间多测几次取中间值比凭感觉判断延迟要靠谱得多。6. 我在 smart_rtmpd 实测中踩过的坑以及对应处理6.1 连接被拒绝服务是不是真在监听我遇到过一次推流报Connection refused当时下意识以为是服务器挂了。排查下来是我把端口改成了 19350但推流命令里忘写端口默认还是连 1935。这类问题只要记住一条原则就能避免改完端口URL 里必须显式带端口例如rtmp://127.0.0.1:19350/live/test6.2 黑屏但有声音十有八九是编码格式问题有段时间我拿一个 HEVC 测试片源推流结果播放器有声音但黑屏smart_rtmpd 日志里看不到推流异常。用 ffprobe 一看视频编码是 HEVCF LV 容器里这个编码兼容性很差。改成 H.264 转码输出后画面立刻正常。遇到黑屏先别研究服务器按顺序查三件事源编码是否 H.264、GOP 是否太长、播放器是否支持。尤其不能拿一个 VVC 或 AV1 的片子跑-c copy然后怪服务器黑屏。6.3 长时间循环推流后音画不同步本地文件-re循环推流几个小时后我拉流发现视频比音频越来越慢。原因主要是 FFmpeg 读文件和编码两个环节的时间戳漂移。实际处理方法是循环推流不要加-stream_loop -1和-re一起跑太久更稳妥的做法是外层用脚本循环重启推流进程每次重启都能重新对齐时间戳。脚本大概长这样#!/bin/sh while true; do ffmpeg -re -stream_loop -1 -i placeholder.mp4 -c:v copy -c:a copy -f flv rtmp://127.0.0.1:1935/live/test sleep 5 done如果来源是摄像头时间戳漂移更明显可以在输入侧加上-use_wallclock_as_timestamps 1这个参数会以系统时钟作为时间戳基准避免采集设备漂移导致音画不同步。6.4 USB 摄像头掉线导致推流中断测试 USB 摄像头时运行二十多分钟后 FFmpeg 进程直接退出错误信息指向采集设备超时。这不是 smart_rtmpd 的问题而是 USB 摄像头在长时间高码率采集下不稳。我加了一个缓冲参数ffmpeg -rtbufsize 100M -f dshow -i videoUSB Camera ...-rtbufsize提高实时采集缓冲区能在采集设备短暂卡顿时避免 FFmpeg 丢流退出。还可以顺带降低采集分辨率从 1080p 降到 720p长时间跑稳定性会明显提升。6.5 局域网无线设备推流时卡顿和断流手机或笔记本通过 Wi-Fi 推流偶尔出现度数卡顿。检查 smart_rtmpd 日志看不出异常反而是 Wi-Fi 上行带宽被占满。我的经验是局域网无线推流要控制码率720p 建议控制在 2.5Mbps 以内1080p 至少准备 5Mbps 的干净上行带宽否则视频画面的动态变化一大就会出现推流端堵包、播放端疯狂缓冲的情况。提示推流遇到问题先别急着怀疑 smart_rtmpd按这个顺序排查用 ffprobe 看源编码 → 确认输出加了-f flv→ 确认 URL 端口正确 → 用 ffplay 低延迟参数拉流 → 再回头调编码参数。我在实际项目里养成的习惯是所有推流命令先写进一个 shell 脚本或 bat 文件固定好-f flv的位置然后再跑。这样既能快速恢复推流也方便日后换服务器地址时改一处就行。希望这篇笔记对正在折腾 RTMP 推流的你有帮助。
返回列表