简介webrtc-streamer 是面向实时音视频开发者的开源流媒体服务器项目可在 Windows 平台搭建 WebRTC 流传输服务适用于在线会议、远程教育、协同办公等场景需要读者具备 WebRTC 基本原理与网络通信基础。本资源为 v0.8.1 版本的 Windows AMD64 预编译包共 94 个文件压缩包约 7.29MB内含可执行程序、配置与说明文档以及大量 js、html、css 前端页面与 woff、svg、eot 等字体图标资源另含 wasm、json 及 tfjs、posenet、coco-ssd、blazeface、deeplab、body-pix 等模型文件覆盖信令交互、媒体传输与前端演示模块。已有 856 人学习下载。通过该包可快速运行流媒体服务结合对等连接、ICE、STUN/TURN 与数据通道等机制帮助读者理解多用户流媒体中继与混音流程并借助内置示例页面调试连接、排查网络问题为二次开发与性能优化提供可运行的基础环境。1. webrtc-streamer把 RTSP 摄像头搬进浏览器为什么你总是卡在最后一公里手头有一台 RTSP 网络摄像头想直接在浏览器里看画面不装插件、不转码、不折腾流媒体服务器——这是很多做安防、做工业视觉、做远程巡检的开发者都会遇到的场景。webrtc-streamer 就是冲着这个需求来的它是一个轻量的 C 服务把 RTSP、V4L2、屏幕捕获等视频源转成 WebRTC 流浏览器端用几行 JavaScript 就能拉起来。听起来很美好但真正动手的人会发现编译能过、服务能起、页面能开画面就是不出来或者出来了延迟高得离谱。问题往往不在 webrtc-streamer 本身而在你对 WebRTC 信令、ICE 候选、编解码协商这几层的理解是否到位。这篇笔记面向的是已经能跑通基础 demo、但卡在“能用”和“好用”之间的工程师我会把选型理由、最小可复现步骤、参数调优和几个血泪踩坑点拆开讲清楚。2. webrtc-streamer 的定位与最小可跑通路径2.1 它到底解决了什么问题不解决什么问题webrtc-streamer 的核心价值是“协议桥接”一边用 FFmpeg 或 GStreamer 拉 RTSP/V4L2 流另一边用 libwebrtc 把视频帧封装成 WebRTC 的 RTP 包通过内置的 HTTP 信令服务与浏览器完成 SDP 交换。它不负责摄像头发现、不负责录像存储、不负责多路大规模分发。常见做法是把它当成一个“单路或少量路数的边缘转码节点”部署在离摄像头近的机器上浏览器直连这个节点。选它的理由通常有三条第一浏览器原生支持 WebRTC不需要额外插件第二延迟可以压到 200ms 以内比 HLS 的几秒延迟好太多第三部署简单一个二进制加一个 HTML 页面就能跑。但要注意它不适合做几十路以上的中心化分发那种场景需要 SFU 集群webrtc-streamer 本身不是为这个设计的。2.2 从源码编译到服务启动的完整命令我一般会在 Ubuntu 20.04 或 22.04 上做首次验证依赖装全再编译能避开大部分玄学问题。# 安装基础依赖libwebrtc 的编译依赖较多一次装齐 sudo apt update sudo apt install -y cmake g git pkg-config libssl-dev libsrtp2-dev \ libavcodec-dev libavformat-dev libavutil-dev libswscale-dev \ libv4l-dev libasound2-dev libpulse-dev # 拉取源码注意用 --recursive 拉子模块 git clone --recursive https://github.com/xxx/webrtc-streamer.git cd webrtc-streamer # 创建构建目录Release 模式编译Debug 模式在嵌入式设备上会非常慢 mkdir build cd build cmake .. -DCMAKE_BUILD_TYPERelease make -j$(nproc) # 编译完成后二进制在 build 目录下直接启动 ./webrtc-streamer -H 0.0.0.0:8000启动后浏览器打开http://你的IP:8000/webrtcstreamer.html?videortsp://user:pass192.168.1.10:554/stream1就能看到画面。这里有几个参数必须说清楚-H指定 HTTP 信令服务的监听地址和端口默认是 8000video参数是 URL 编码后的 RTSP 地址如果密码里有特殊字符一定要先做 URL 编码否则解析会失败。-j可以指定 ICE 使用的 STUN/TURN 服务器配置文件局域网内直连可以不加跨网段就必须配。2.3 浏览器端最小 HTML 与信令流程服务端跑起来后前端只需要一个 video 标签和一段 JS。webrtc-streamer 自带了一个webrtcstreamer.js封装但理解底层信令对排查问题很有帮助。!DOCTYPE html html head meta charsetutf-8 titleRTSP over WebRTC/title /head body video idvideo autoplay muted playsinline/video script srcwebrtcstreamer.js/script script // 初始化 WebRtcStreamer 对象第一个参数是 video 元素 id // 第二个参数是信令服务地址第三个参数是 ICE 配置 var webRtcServer new WebRtcStreamer(video, location.protocol // location.hostname :8000, null); // 调用 connect传入 RTSP 地址和音频开关 webRtcServer.connect(rtsp://user:pass192.168.1.10:554/stream1, null, stun:stun.l.google.com:19302); /script /body /html这段代码的逻辑是WebRtcStreamer构造函数会向信令服务发一个 POST 请求携带 offer SDP服务端返回 answer SDP 和 ICE 候选浏览器拿到后完成 PeerConnection 建立。connect的第三个参数是 ICE 服务器局域网内可以传null但如果你在 Docker 里跑或者跨网段必须配 STUN否则 ICE 候选收集不全连接会一直卡在 checking 状态。3. 参数调优延迟、分辨率与 CPU 占用的三角平衡3.1 影响延迟的三个关键参数webrtc-streamer 的延迟主要来自三块FFmpeg 解码缓冲、libwebrtc 的 jitter buffer、以及编码器的 GOP 长度。默认配置下延迟通常在 300ms 到 800ms 之间要压到 200ms 以内需要动这几个参数。第一个是-o参数用来指定输出选项。比如-o video_codecH264强制使用 H264避免 VP8 软编带来的额外延迟。第二个是-c参数指定视频捕获的帧率默认是 30如果摄像头本身只支持 25设 30 反而会引入抖动。第三个是-n参数指定不启用音频音频的 jitter buffer 通常比视频大关掉能省 50ms 左右。# 一个低延迟的启动示例 ./webrtc-streamer -H 0.0.0.0:8000 \ -o video_codecH264 \ -c 25 \ -n \ -j ./ice.jsonice.json里配置 STUN 和 TURN格式如下{ iceServers: [ { urls: stun:stun.example.com:3478 }, { urls: turn:turn.example.com:3478, username: user, credential: pass } ] }注意TURN 服务器在对称 NAT 环境下是必须的但会引入额外一跳延迟局域网内优先用 STUN 直连。3.2 分辨率与码率的匹配关系很多人把摄像头设成 1080p然后发现浏览器端画面糊、卡顿以为是 webrtc-streamer 的问题其实是码率没跟上。WebRTC 默认的初始码率是 300kbps 左右会根据网络状况动态调整但调整有滞后。对于 1080p25fps建议起始码率不低于 2Mbps720p 不低于 1Mbps。可以在启动时通过-o传入bitrate参数./webrtc-streamer -H 0.0.0.0:8000 \ -o video_codecH264,bitrate2000 \ -c 25这里的bitrate单位是 kbps。如果摄像头支持双码流建议用子码流做 WebRTC 预览主码流留给录像这样 CPU 和带宽都省。3.3 CPU 占用的实测对比我在一台 4 核 ARM 设备上做过对比720p25fpsH264 硬解CPU 占用约 35%1080p25fpsH264 硬解CPU 占用约 60%如果强制 VP8 软编1080p 直接飙到 90% 以上画面开始丢帧。所以选型时如果设备没有 H264 硬编硬解优先把分辨率降到 720p或者换用支持硬编的摄像头。分辨率编码CPU 占用延迟720p25H264 硬解35%180ms1080p25H264 硬解60%220ms1080p25VP8 软编90%400ms这张表是实测均值不同设备会有浮动但趋势是一致的硬解是低延迟低占用的前提。4. 避坑与排查那些让你怀疑人生的瞬间4.1 画面黑屏但信令显示 connected现象浏览器控制台看到 PeerConnection 状态是 connected但 video 元素一直是黑屏。原因通常是 SDP 协商时视频编码格式不匹配比如摄像头输出 H265而浏览器只支持 H264/VP8/VP9。解决方法是强制 webrtc-streamer 转码为 H264启动时加-o video_codecH264或者在摄像头端把编码改成 H264。4.2 延迟越跑越大重启后恢复现象刚启动时延迟 200ms跑几个小时后延迟涨到 2 秒以上。原因是 libwebrtc 的 jitter buffer 在丢包时会累积而 webrtc-streamer 默认没有开启丢包重传的快速恢复。解决方法是在启动参数里加-o rtcp_feedbacknack让接收端能请求重传关键包同时检查网络是否有持续丢包。4.3 Docker 里跑浏览器连不上现象webrtc-streamer 在 Docker 容器里启动端口映射也做了但浏览器一直卡在 connecting。原因是 WebRTC 的 ICE 候选里包含容器内网 IP浏览器无法路由到。解决方法是用--network host模式启动容器或者在 ice.json 里显式指定公网 IP 的 STUN/TURN并加-o ice_transport_policyrelay强制走 TURN 中继。4.4 多路并发时服务崩溃现象同时拉 4 路以上 RTSPwebrtc-streamer 进程内存暴涨然后被 OOM kill。原因是每路 WebRTC 连接都会创建独立的 PeerConnection 和解码线程默认线程池不够用。解决方法是在启动时加-t 8增加工作线程数同时限制单进程的路数超过 4 路建议起多个实例做负载均衡。4.5 音频回声和杂音现象开启音频后浏览器端听到严重回声。原因是摄像头麦克风和浏览器扬声器形成了声学回路。解决方法是在前端connect时把音频关掉或者启用浏览器的echoCancellation约束。如果必须双向音频建议在服务端加 WebAudio 的 AEC 处理但 webrtc-streamer 本身不提供这个能力需要自己扩展。5. 进阶用 ICE 配置和 SDP 裁剪把延迟再压 50ms前面讲的都是常规调优如果你想把延迟压到极致有两个进阶技巧值得试。第一个是手动裁剪 SDP去掉所有不用的音频和冗余编解码器只保留 H264 和必要的 RTCP 反馈。webrtc-streamer 支持通过-o sdp_override...传入自定义 SDP 片段但更稳妥的做法是在前端拿到 offer 后用 JavaScript 过滤掉maudio行和 VP8/VP9 的rtpmap行再发给服务端。这样能减少协商时间也能避免浏览器选到软编。第二个是调整 ICE 的候选收集策略。默认情况下libwebrtc 会收集 host、srflx、relay 三类候选收集过程有超时等待。局域网内如果确定直连可以在 ice.json 里只配一个 STUN并且在前端创建 PeerConnection 时设置iceCandidatePoolSize: 0减少预收集的候选数量。实测这样能省 30 到 50ms 的连接建立时间。// 前端裁剪 SDP 的示例只保留 H264 function filterSDP(sdp) { var lines sdp.split(\r\n); var result []; var inVideo false; for (var i 0; i lines.length; i) { var line lines[i]; if (line.startsWith(maudio)) { inVideo false; continue; } if (line.startsWith(mvideo)) { inVideo true; result.push(line); continue; } if (inVideo line.startsWith(artpmap) !line.includes(H264)) { continue; } if (inVideo line.startsWith(afmtp) !line.includes(H264)) { continue; } result.push(line); } return result.join(\r\n); }这段代码的逻辑是遍历 SDP 每一行遇到maudio就跳过后续音频相关行遇到mvideo开始保留但过滤掉非 H264 的rtpmap和fmtp行。注意裁剪后要同步调整mvideo行里的 payload type 列表否则协商会失败。这个操作有风险建议先在测试环境验证。最后说一个我自己的习惯每次调完参数不要只看画面流畅度一定要打开浏览器的chrome://webrtc-internals看framesDecoded、packetsLost、jitterBufferDelay这三个指标。画面会骗人指标不会。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?