资讯动态

RTMP转WebRTC测试环境搭建:从SRS配置到ffmpeg推流与播放验证

发布时间:2026/9/8 6:14:10 来源:尧图企业网站定制
在做 RTMP 转 WebRTC 测试环境时大部分卡顿并不在“转换”本身而是出在“这条链路涉及的不止一个协议”。摄像头、编码器、OBS 这类采集端最常输出 RTMP而浏览器要实时低延迟播放WebRTC 几乎是当前唯一不需要装插件、又能把延迟压到几百毫秒的方案。问题是 RTMP 基于 TCP 长连接传输 FLV 封装WebRTC 基于 UDP、SRTP 和 ICE 协商两种协议从信令到媒体封装都不通用服务端必须做协议转换。这篇文章就以搭建一套本机可运行的 rtmp2webrtc 测试环境为主线从协议差异讲起给出可复现的编译启动步骤、ffmpeg 推流命令、WebRTC 浏览器播放验证、以及推流端、服务端、播放端三段式排查方法。文章末尾会补充生产化时需要补齐的鉴权、加密、监控和备份能力方便你从测试环境平滑过渡到真实业务。1. 先理解为什么 RTMP 不能直接在浏览器播放而 WebRTC 可以1.1 RTMP 的技术定位与限制RTMPReal-Time Messaging Protocol是 Adobe 提出的流媒体协议早期配合 Flash Player 在网页直播中大量使用。它基于 TCP 建立长连接传输的是 FLV 格式的音视频数据和元数据。RTMP 到今天仍然在推流端占据重要位置原因是几乎所有采集端设备、硬件编码器和 OBS 都内置了 RTMP 推流能力存量系统里大量摄像头和直播软件都输出 RTMP 流。但浏览器原生环境早已不再支持 Flash也没有内置 RTMP 客户端。虽然可以借助 VLC、ffplay 等桌面播放器拉取 RTMP但 Web 页面里想做无插件播放RTMP 这条路基本走不通。即使使用 HTTP-FLV 或 HLS 做降级延迟也会明显高于实时通信场景。因此 RTMP 更适合作为“上行推流协议”而不是“浏览器播放协议”。1.2 WebRTC 的实时能力来源WebRTCWeb Real-Time Communication是浏览器内置的实时通信能力标准由 W3C 和 IETF 推动。它默认使用 UDP 传输音视频媒体配合 SRTP 加密、ICE 连接协商、NACK 丢包重传和 Jitter Buffer 抖动缓冲可以在弱网下尽可能保持低延迟常用场景是视频通话和视频会议延迟可以做到几百毫秒。浏览器原生支持 WebRTC不需要安装插件不需要额外运行时这就是它适合作为实时播放端的原因。你要在网页里看监控、看直播、看低延迟视频WebRTC 都是首选方案。1.3 rtmp2webrtc 转换的本质不只是换协议把 RTMP 转成 WebRTC不是改一个 URL 后缀那么简单。服务端需要同时处理三件事媒体格式转换RTMP 里是 FLV 封装WebRTC 里是 RTP 封装。服务端要把 FLV 解封装重新打包成 RTP 流并且保证 H.264 的 SPS/PPS 和音频配置信息不丢失。信令协商WebRTC 播放器必须先通过信令交换 SDP 和 ICE 候选才能建立 PeerConnection。RTMP 是连上 TCP 后直接推流没有这一套协商过程。传输方式变化RTMP 是 TCP 长连接WebRTC 是 DTLS/SRTP over UDP两者的拥塞控制、重传机制和码率自适应策略都不一样。所以测试环境的真正任务不是验证推流能不能推上去也不是验证 URL 能不能访问而是验证“RTMP 推流 - 服务端转换 - 浏览器 WebRTC 播放”这条完整链路是否通、延迟是否可接受、长时间运行是否稳定。2. 测试环境的方案选型先选对工具再动手2.1 常见方案的能力差异做 rtmp2webrtc 转换社区里常见方案有 SRS、Janus、nginx-rtmp-module 和 MediaSoup但它们的能力差异非常大。先看对比表方案接收 RTMP 推流WebRTC 播放信令复杂度适用阶段SRS原生支持原生支持较低自带 HTTP API 和播放器学习、测试、生产均可Janus Gateway需要额外插件接入原生支持较高需要维护插件和信令二次开发能力强的团队nginx-rtmp-module原生支持不支持无法直接完成 rtmp2webrtc只适合 RTMP 播发场景MediaSoup不直接收 RTMP原生支持较高需要自己接入转流组件音视频通话场景从测试环境角度看SRS 是最短路径一个进程同时支持 RTMP 推流接收和 WebRTC 播放发布配置最少信令交互最直接。使用 nginx-rtmp-module 虽然能快速搭出 RTMP 服务但它本身没有 WebRTC 能力后续还要引入额外的转换服务测试链路会变长不适合作为 rtmp2webrtc 的首选。2.2 测试环境的目标测试环境只解决三个问题协议转换是否可行、延迟是否可接受、常见故障如何排查。你不需要在测试阶段就完成鉴权、集群、录制、回放和监控但要了解这些能力在生产环境是必须的。学习环境里可以把防火墙关掉、用 IP 直接访问、用 HTTP 明文拉流。生产环境则必须启用 HTTPS/WSS、增加鉴权、配置日志落盘和监控告警并考虑服务崩溃后的恢复机制。测试环境的价值在于用最低成本提前暴露协议链路上的问题而不是模拟完整生产规模。2.3 版本确认是第一步搭建之前要确认 SRS 版本。SRS 从 4.0 版本开始才提供完整的 WebRTC 发布和播放能力早期 3.x 版本不支持或支持不完整。下载源码前要先到官方仓库查看当前 release 分支不要直接克隆默认主干就当稳定版来用。本文以 SRS 4.0 版本为例具体到你的环境时以下载到的发布版本文档为准。3. 搭建 SRS 测试环境并验证基础服务3.1 环境准备SRS 是 C 项目需要编译安装。建议使用 CentOS 7.9 或 Ubuntu 20.04 的云主机或虚拟机内存不低于 2GB磁盘可用空间不低于 5GB。同时确保 gcc、g、make、pkg-config 等基础编译工具已经安装。Ubuntu/Debian 系统执行sudo apt update sudo apt install -y gcc g make pkg-config python3CentOS/RHEL 系统执行sudo yum install -y gcc gcc-c make pkgconfig python3这里安装 python3 是因为 SRS 的构建脚本和部分工具脚本依赖 Python。如果你的系统已经装过可以跳过。3.2 下载、编译和启动 SRS建议克隆官方仓库并切换到 release 分支。以 4.0 系列为例git clone https://github.com/ossrs/srs.git cd srs/trunk git branch -a git checkout 4.0release如果嫌克隆仓库太慢也可以下载对应版本的 tar 包解压。进入srs/trunk目录后执行./configure --full make -j$(nproc)--full会启用完整的编解码和协议支持包括 WebRTC 相关依赖。如果服务器内存较小-j$(nproc)可能导致编译内存不足可以改成-j2或-j1。编译成功后启动服务./objs/srs -c conf/srs.conf查看进程是否启动ps -ef | grep srs正常情况下控制台会输出类似下面的日志SRS ctrlc to stop SRS init ok3.3 验证 SRS 服务是否正常SRS 启动后会监听三个主要端口1935RTMP 推流和拉流端口1985HTTP API 端口用于查询流信息、调用管理接口8080HTTP 静态服务端口提供默认播放器页面打开浏览器访问http://服务器IP:8080/players/能看到 SRS 自带的播放器页面说明 HTTP 静态服务正常。再访问http://服务器IP:1985/api/v1/versions如果返回包含版本信息的 JSON说明 HTTP API 正常。这个接口后面排查流状态时会经常用到。注意如果服务器有防火墙需要放行 TCP 1935、TCP 1985、TCP 8080 和 UDP 8000 端口。UDP 8000 是 WebRTC 媒体传输端口很多人测试 WebRTC 失败都是因为只放行了 TCP 端口却忘了 UDP 端口。4. 用 ffmpeg 构建 RTMP 推流源4.1 安装 ffmpegSRS 本身不生成视频源测试时需要一个推流端。ffmpeg 是最常用的工具既能生成测试画面也能读取摄像头或本地视频文件推流。Ubuntu/Debian 系统执行sudo apt install -y ffmpegCentOS/RHEL 系统如果默认源没有 ffmpeg可以先安装 EPEL 源再安装 ffmpeg或者通过源码编译。测试环境也可以使用 Docker 镜像jrottenberg/ffmpeg避免依赖冲突。安装完成后验证ffmpeg -version4.2 用测试图源推流如果没有摄像头也没有现成视频文件可以直接用 ffmpeg 的 lavfi 生成彩色测试画面和正弦波音频ffmpeg -re -f lavfi -i testsrc2size1280x720:rate25 \ -f lavfi -i sinefrequency440:sample_rate44100 \ -vcodec libx264 -preset veryfast -tune zerolatency \ -acodec aac -shortest \ -f flv rtmp://127.0.0.1:1935/live/test逐项看这条命令的作用-re按实时速率读取输入避免瞬间推完导致 SRS 看到的流是断断续续的。-f lavfi -i testsrc2size1280x720:rate25生成 1280x720、25 帧每秒的测试画面。-f lavfi -i sinefrequency440:sample_rate44100生成 440Hz 正弦波音频。-vcodec libx264 -preset veryfast -tune zerolatency使用 H.264 编码zerolatency模式降低编码延迟。-acodec aac音频使用 AAC 编码。-shortest当输入源之一结束后输出同时结束。-f flv rtmp://127.0.0.1:1935/live/test以 FLV 封装推送到 SRS 的 RTMP 地址。4.3 用摄像头或本地文件推流如果测试环境有摄像头Linux 下可以使用 V4L2 设备ffmpeg -f v4l2 -i /dev/video0 \ -c:v libx264 -preset veryfast -tune zerolatency \ -f flv rtmp://127.0.0.1:1935/live/cameramacOS 上设备名是avfoundationWindows 上设备名是dshow参数略有不同。测试时优先使用测试图源因为它不依赖具体硬件驱动可以在任何机器上复现。也可以用本地视频文件循环推流ffmpeg -re -stream_loop -1 -i local.mp4 \ -c:v libx264 -preset veryfast -tune zerolatency \ -c:a aac -f flv rtmp://127.0.0.1:1935/live/test4.4 验证推流是否成功推流命令执行后注意观察 ffmpeg 日志。正常推流时日志里会出现稳定的fps、bitrate和muxing overhead数值。如果看到错误关键字比如Connection refused、Broken pipe、Permission denied说明推流链路有问题需要进入第 6 章的排查流程。在另一个终端执行ffprobe rtmp://127.0.0.1:1935/live/test如果能输出视频流和音频流的编码信息说明 RTMP 服务端已经能正常接收并分发推流。到这里RTMP 推流段验证通过。5. 用 WebRTC 播放并验证 rtmp2webrtc 是否打通5.1 确认 SRS 的 WebRTC 播放配置SRS 4.0 默认配置中已经包含了rtc_server模块但为了保险起见打开conf/srs.conf确认以下配置存在rtc_server { enabled on; listen 8000; } http_api { enabled on; listen 1985; } http_server { enabled on; listen 8080; }修改配置后重启 SRS./objs/srs -c conf/srs.confWebRTC 播放地址格式和 RTMP 完全不同。RTMP 播放地址是rtmp://服务器IP:1935/live/testWebRTC 播放地址是webrtc://服务器IP:8080/live/test注意这里不是 1935 端口而是 HTTP API 的 1985 或 HTTP Server 的 8080 端口具体取决于 SRS 版本对 WebRTC 协议 URL 的解释。实际测试中SRS 自带播放器会帮你完成 URL 解析手动填写时最容易犯的错就是把端口写成 1935。5.2 使用 SRS 自带播放器验证浏览器访问http://服务器IP:8080/players/在播放器地址栏填入webrtc://服务器IP:8080/live/test点击播放。如果画面正常显示说明 RTMP 推流已经被服务端转换为 WebRTC 播放整条链路已经打通。如果画面黑屏但浏览器控制台没有明显报错优先检查推流端的视频编码。WebRTC 播放要求视频编码是 H.264音频是 AAC 或 Opus。如果推流时使用了其他编码比如 VP8、VP9 或 MP3 音频WebRTC 播放端可能无法正常解码。5.3 独立播放页面的最小实现SRS 自带播放器适合快速验证但实际项目通常需要把播放器嵌入自己的页面。以原生 WebRTC API 为例播放流程抽象出来是创建RTCPeerConnection。添加recvonly的transceiver告诉服务端“我只接收不推流”。创建 Offer调用setLocalDescription。把 Offer 通过 HTTP 请求发送给 SRS WebRTC 播放接口。拿到 Answer 后调用setRemoteDescription触发媒体流转发。把收到的媒体流赋给video标签。核心代码示意如下video idplayer autoplay controls width640 height360/video script const pc new RTCPeerConnection(); const video document.getElementById(player); pc.addTransceiver(video, { direction: recvonly }); pc.addTransceiver(audio, { direction: recvonly }); pc.ontrack (event) { video.srcObject event.streams[0]; }; const offer await pc.createOffer(); await pc.setLocalDescription(offer); const response await fetch(http://服务器IP:1985/rtc/v1/play/, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ api: http://服务器IP:1985/rtc/v1/play/, clientip: null, sdp: pc.localDescription.sdp, streamurl: webrtc://服务器IP:8080/live/test }) }); const data await response.json(); await pc.setRemoteDescription({ type: answer, sdp: data.sdp }); /script这段代码用于说明最小流程实际项目中不同 SRS 版本的 HTTP API 字段名和路径可能有差异建议直接使用 SRS 官方提供的 WebRTC Player SDK或者以当前版本的 HTTP API 文档为准。自己写播放器时重点是理解 SDP 和 ICE 的交换过程不要每次从头造轮子。5.4 验证标准通过播放器看到画面后还要做三个验证画面完整性画面没有大面积花屏、绿屏音频没有明显电流声。延迟表现用手机拍摄推流端画面对比浏览器播放画面的时间差。RTMP 转 WebRTC 场景下网络正常时延迟通常可以控制在 1 秒以内。长时间稳定性持续播放 30 分钟以上观察是否出现卡死、画面停住、内存持续上涨、音画不同步等问题。注意不要只验证程序能启动还要验证输入、输出、异常分支和日志是否符合预期。ffmpeg推流正常不代表WebRTC播放正常WebRTC播放正常也不代表长时间运行稳定。6. 链路排查从推流端、服务端到播放端6.1 推流端问题排查rtmp2webrtc 测试里最常出现的现象是ffmpeg 推流失败SRS 里查不到流WebRTC 播放器自然没有画面。检查顺序如下检查推流地址是否写错。rtmp://127.0.0.1:1935/live/test里的live是应用名test是流名中间不能漏掉/live/。检查 SRS 是否在运行。执行ps -ef | grep srs。检查端口连通性。执行telnet 127.0.0.1 1935如果连接被拒绝说明 SRS 没监听或者防火墙拦截。检查 ffmpeg 日志。遇到Connection refused时说明没有服务监听该端口遇到Broken pipe时说明推流过程中连接被服务端断开需要回看 SRS 日志。如果是远程服务器需要确认云安全组和操作系统防火墙都放行了对应端口。很多测试环境的推流问题都是云安全组开了但操作系统 firewall 没开或者反过来。6.2 服务端问题排查推流成功但 WebRTC 播放失败时问题很可能在服务端转换环节。SRS 默认把日志输出到控制台。如果使用后台启动方式看不到日志可以停掉进程后前台运行./objs/srs -c conf/srs.conf观察日志关键字。正常推流时会出现类似下面的日志rtmp: stream live/test codec ok rtmp: serve client ok如果推流 URL 里的流名和播放 URL 里的流名不一致SRS 日志里会出现rtmp: stream not found这时要检查推流端和播放端使用的 app name 和 stream name 是否完全一致。另一个常用排查接口是流信息查询curl http://127.0.0.1:1985/api/v1/streams/返回的 JSON 里如果包含live/test说明服务端已经记录该流。如果流列表为空说明推流端到服务端的链路还没有打通。6.3 播放端问题排查WebRTC 播放失败时浏览器控制台和chrome://webrtc-internals是主要排查入口。白屏或控制台报错先看RTCPeerConnection是否建立成功ICE 状态是否变成connected。黑屏但音频正常视频编码不是 H.264或推流时没有正确携带 SPS/PPS。无法连接确认 UDP 8000 端口是否可达WebRTC 媒体传输默认走 UDP。rtc_server配置里的listen端口要和防火墙放行端口一致。浏览器提示不安全WebRTC 在非 localhost 环境下要求 HTTPS 页面。测试时可以使用http://localhost访问局域网 IP 访问则需要配置 HTTPS 证书或者暂时用浏览器的高级选项忽略安全提示但不建议在生产环境这么做。查看chrome://webrtc-internals时重点看ICE Connection State、Selected candidate pair和Inbound RTP统计。如果 ICE 一直卡在checking通常是 UDP 端口不通或者 NAT 穿透失败如果Inbound RTP的packetsLost持续上升说明网络丢包严重需要降低推流码率。6.4 OpenCV 打开 RTMP 失败怎么排查做视频测试时经常还会遇到另一个独立问题OpenCV 用cv2.VideoCapture打开 RTMP 地址失败。这个问题虽然不属于 rtmp2webrtc 核心链路但在同一个测试环境里很常见一并说明。OpenCV 打开 RTMP 依赖 FFmpeg 后端。第一步是确认当前 OpenCV 是否编译了 FFmpegimport cv2 print(cv2.getBuildInformation())在输出信息中找到Video I/O一节查看FFMPEG是否为YES。如果是NO说明当前 OpenCV 根本不带 FFmpeg 后端需要安装带 FFmpeg 的 OpenCV 版本或者使用opencv-python之外的发行版。确认后端没问题后先用 ffplay 验证 RTMP 地址本身是否可拉ffplay rtmp://127.0.0.1:1935/live/test如果 ffplay 能播放而 OpenCV 打不开通常是因为 OpenCV 在打开网络流时没有设置超时网络抖动会导致长时间阻塞。可以在代码里显式设置超时参数import cv2 cap cv2.VideoCapture(rtmp://127.0.0.1:1935/live/test, cv2.CAP_FFMPEG) cap.set(cv2.CAP_PROP_OPEN_TIMEOUT_MSEC, 3000) cap.set(cv2.CAP_PROP_READ_TIMEOUT_MSEC, 3000) ret, frame cap.read() if not ret: print(failed to read frame) else: print(frame shape:, frame.shape) cap.release()RTMP 地址里不要出现中文路径、空格和特殊字符否则 FFmpeg 解析 URL 时会失败。如果推流端码率过高OpenCV 在低配机器上拉流解码会占用大量 CPU导致read()返回慢或直接超时可以尝试推流端降低分辨率或者降低码率。7. 测试环境高频问题与处理速查表7.1 高频问题表下面把 rtmp2webrtc 测试链路中出现频率最高的问题整理成速查表方便实际排错时对照使用。问题现象常见原因检查方式处理建议ffmpeg 连接 1935 端口失败SRS 未启动或防火墙拦截telnet IP 1935ps -ef | grep srs启动 SRS放行 TCP 1935WebRTC 无法播放UDP 8000 未放行或rtc_server未开启nc -u IP 8000查看 SRS 日志开启rtc_server放行 UDP 8000播放地址写成 1935 端口混淆 RTMP 和 WebRTC 地址格式检查播放 URL 端口WebRTC 播放地址使用 8080 或 1985 端口画面黑屏但音频正常视频编码不是 H.264ffprobe rtmp://...查看编码推流端强制使用 H.264浏览器提示页面不安全非 localhost 页面使用 WebRTC查看地址栏协议配置 HTTPS 或使用 localhost 访问OpenCV 打不开 RTMPOpenCV 编译时未启用 FFmpeg 后端cv2.getBuildInformation()查看FFMPEG字段安装带 FFmpeg 的 OpenCV 版本长时间播放内存上涨播放器未释放 PeerConnection 或日志堆积观察播放页内存和 SRS 进程 RSS使用官方 SDK释放页面资源升级 SRS 版本延迟明显偏高推流端未开启低延迟模式查看 ffmpeg 日志中的 GOP 大小增加-tune zerolatency降低 GOP size7.2 排查顺序建议在测试环境里遇到问题建议严格按照“推流端 - 服务端 - 播放端”的顺序排查不要跳跃。推流端优先看是否真的推上去了最简单的方式是看 SRS 流列表curl http://127.0.0.1:1985/api/v1/streams/流列表有记录说明推流端到服务端正常问题在播放端或转换环节。流列表为空说明问题在推流端或服务端接收环节不要先去调播放器。服务端优先看 SRS 日志和三个端口是否正常监听netstat -tunlp | grep -E 1935|1985|8080|8000播放端优先用 SRS 自带播放器验证因为它已经处理好 SDP 交换细节。如果自带播放器能播放而自己的页面不能播放说明问题出在页面代码的 SDP 交换流程而不是服务端。8. 从测试环境走向生产环境还差哪些能力8.1 协议与安全方面的差距测试环境里使用明文 HTTP 和webrtc://地址没有问题但生产环境面向真实用户时浏览器对 WebRTC 有强制安全要求。非 localhost 页面必须使用 HTTPS/WSS否则getUserMedia和 WebRTC 相关 API 会被浏览器拦截。同时要增加鉴权。SRS 支持通过 HTTP 回调对接自己的鉴权服务比如推流时校验 token、播放时校验签名。如果直接裸奔线上任何人知道 RTMP 或 WebRTC 播放地址就能拉流这是生产环境最常见的安全隐患。还需要考虑防盗链。播放地址可以加入过期时间签名服务端校验签名通过后才允许播放避免地址被复制后长期有效。8.2 可运维性方面的差距测试环境直接前台运行 SRS日志全部打到控制台。生产环境必须做到日志落盘并按天轮转方便回看历史问题。使用 systemd 或容器编排守护进程进程崩溃后自动拉起。配置外置化通过环境变量或配置中心管理端口、密钥和回调地址。接入监控告警至少采集进程存活状态、推流数量、播放数量、CPU 和内存使用率。上线前可以清理测试用的默认端口避免 1935、1985、8080 这种默认端口直接暴露到公网降低被扫描和探测的风险。8.3 质量与回退方案生产环境不能只提供 WebRTC 一种播放方式。仍有大量播放器、老版本浏览器和特定场景无法使用 WebRTC因此建议保留 HLS 或 HTTP-FLV 作为回退方案。SRS 可以同时输出 RTMP、HTTP-FLV、HLS 和 WebRTC测试环境里已经验证了 WebRTC 链路生产环境只需要启用 HLS 配置并覆盖不通协议的播放器场景。延迟和码率也需要在推流端控制。推流端 GOP 不宜过大建议 1 到 2 秒一个关键帧码率上限要根据上行带宽和播放端下行带宽设置避免弱网下 WebRTC 播放端持续丢包。8.4 发布检查清单从测试环境转到生产环境前至少完成以下检查推流和播放地址是否区分了测试环境和生产环境。是否已经配置 HTTPS/WSS 证书。是否启用了推流鉴权和播放鉴权。是否放行了生产环境的 TCP 端口和 UDP 媒体端口。是否配置了日志落盘、进程守护和监控告警。是否保留了 HLS 或 HTTP-FLV 回退播放方案。是否测试了长时间运行下的内存和连接数。8.5 测试环境与生产环境的差距关注点测试环境生产环境网络本机或内网弱网干扰小公网、跨运营商、移动网络安全明文 HTTP无鉴权HTTPS/WSStoken 鉴权防盗链监控人工看控制台日志日志采集、指标监控、告警通知容灾进程重启即可多实例、自动重启、故障转移配置写死在 conf 文件外置化、版本管理、灰度发布这里最需要理解的一点是rtmp2webrtc 真正要验证的不只是“能播”而是延迟、稳定性、编码兼容性和弱网表现。测试环境把最小链路跑通后再去补生产化能力可以避免把大量时间浪费在还没确认可行的协议转换上。对本 topic 的新手来说最有价值的练习路径是先在本地用 SRS 和 ffmpeg 跑通最小闭环再分别模拟推流断开、服务重启、播放器刷新三种故障观察 SRS 日志和浏览器 WebRTC 统计会如何变化。经历过这几轮排障之后再接手带鉴权和集群的生产环境思路会清晰很多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价