ARTICLE DETAIL

资讯详情

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

webrtc-streamer实战:基于WebRTC的RTSP低延迟播放方案

webrtc-streamer实战:基于WebRTC的RTSP低延迟播放方案 简介webrtc-streamer-v0.8.1-dirty-Windows-AMD64-Release是WebRTC流媒体服务器的Windows 64位预编译版旨在解决实时音视频服务部署繁琐的问题适合需要快速搭建WebRTC网关的开发者、运维人员以及想通过实际项目学习WebRTC的零基础体验者和中级进阶开发者。压缩包共94个文件仅7.29MB核心可执行程序可直接运行23个html页面、29个js脚本和5个css文件构成前端控制台与演示界面6个woff和6个svg等字体图标资源支撑页面样式json配置便于调整流媒体参数wasm和tfjs模型如posenet、coco-ssd自带AI视觉示例md和license文档说明使用与授权。目前已有846人学习下载。解压后通过浏览器访问管理页面即可查看实时视频流无需手动编译和复杂依赖既适合在Windows环境验证摄像头/屏幕推流、多端低延迟通信也有助于理解信令交换、ICE候选收集及STUN/TURN协调机制。项目目录分层清晰能帮助使用者快速定位前端、后端与模型资源便于在此基础上做二次开发。1. 为什么需要 webrtc-streamer低延迟播放的痛点做监控摄像头或者 IP Camera 接入的时候大家应该都遇到过同一个尴尬场景摄像头明明支持 RTSP 协议浏览器却没法直接播放。Chrome 和 Firefox 早就放弃了原生 RTSP 支持Safari 虽然有点特殊但实战中基本指望不上。于是传统的方案就是推 RTMP 流再用 Flash 播放——但 Flash 已经彻底退场了这条路直接焊死。剩下的选择就是 HLS。把 RTSP 转成 HLS用 hls.js 或者原生 video 标签播放。这个方案兼容性确实好什么浏览器都能跑但延迟让人抓狂。我曾经测过一台海康摄像头从画面实际发生的事情到浏览器里面看到延迟轻松超过 5 秒钟甚至 8 秒以上都算正常。对于门铃呼叫、安防告警这种场景你总不能让用户在门口站 5 秒钟等视频出来。而 WebRTC 在这种场景下几乎是唯一合理的答案端到端延迟可以做到 300 毫秒以内。webrtc-streamer 就是干这个的。它是一个轻量级的 WebRTC 网关运行在服务器上从摄像头拉取 RTSP 流然后通过 WebRTC 协议推送给浏览器。浏览器端只需要写很短的 JavaScript 代码不需要安装任何插件也不用 Flash就能看到实时画面。这个项目是开源的用 C 写成底层基于 GStreamer 做媒体处理在 GitHub 上常年保持活跃是国内外做低延迟 Web 监控方案时经常被拿来做标杆的开源项目。这篇文章我会从原理、部署到前端集成完整跑一遍 webrtc-streamer 的实战流程包括我在部署过程中踩过的坑和调优参数。想做低延迟直播、IPC 接入、可视门铃或者 Home Assistant 智能家居集成的朋友这份内容应该能帮你省下不少时间。2. 核心架构与工作原理2.1 webrtc-streamer 在链路中扮演什么角色先搞清楚整个数据流的走向。摄像头是 RTSP 服务端浏览器是 WebRTC 客户端webrtc-streamer 夹在中间扮演的是一个“翻译官”的角色。浏览器和 webrtc-streamer 之间通过 WebSocket 交换信令信息比如 SDP 和 ICE candidate。协商完成之后媒体数据直接通过 UDP 或者 TCP 传输走的是标准的 SRTP 协议所以画面是加密传输的不用担心局域网内被劫持的问题。webrtc-streamer 内部用 GStreamer 把 RTSP 流解封装、解码如果需要的话、重新编码成 VP8 或者 H.264再封装进 WebRTC 的 RTP 包里。这个架构最 nice 的一点是WebRTC 会话是点对点直连的。webrtc-streamer 只负责“撬开”摄像头和浏览器之间的通路真正传数据的路径上它只是一个中继不参与媒体数据的深度加工。相比把所有流量都拉回服务器再转发的传统方案这种模式对服务器的带宽和 CPU 压力都小得多。2.2 为什么选择 GStreamer 而不是 FFmpegwebrtc-streamer 底层用的是 GStreamer 而不是大家更熟悉的 FFmpeg这一点很多人会好奇。我的理解是GStreamer 的优势在于它的 pipeline 架构非常灵活可以像搭积木一样把解码、编码、封装、传输各个模块组合起来而且对 WebRTC 协议栈的支持是原生级别的不需要自己再去封装一层 RTP 推流逻辑。另外一个实际的好处是GStreamer 的插件生态对硬件解码有很好的支持。在某些嵌入式的设备上比如 Jetson Nano 或者树莓派如果你用的是 GStreamer 的硬件加速插件可以把 CPU 占用压得非常低。这一点在跑多路摄像头的时候会非常有用我在第 5 节会专门讲 CPU 调优。2.3 H264 与 VP8 编码的取舍webrtc-streamer 在把 RTSP 流推给浏览器之前可以选择保持原来的 H.264 编码直接透传也可以转成 VP8。我强烈建议优先保持 H.264原因有两个大部分现代摄像头出厂就是 H.264 或者 H.265 编码直接透传意味着 webrtc-streamer 不需要做转码CPU 开销几乎可以忽略。浏览器端的 WebRTC 对 H.264 的支持已经非常成熟Chrome、Firefox、Safari 都能硬件解码 H.264又省了一层软解的开销。转码成 VP8 只在一种情况下有意义当源摄像头是 H.265HEVC编码的时候。因为目前主流浏览器对 WebRTC 传输 H.265 的支持还不够好所以这时候需要 webrtc-streamer 把 H.265 软解出来再重新编码成 H.264 或 VP8。这个场景要多留意 CPU 占用尤其是 4K 摄像头软解加软编码能把服务器的 CPU 直接打满。我建议直接把摄像头改成 H.264 输出省心得多。3. 部署与启动从二进制到 Docker3.1 获取编译好的二进制包webrtc-streamer 的 GitHub Releases 页面提供了 Windows、Linux、macOS 的预编译二进制包。如果你只是想快速验证直接下载对应平台的文件解压就能跑。Linux 环境下要注意动态库依赖。我在一台 CentOS 7 服务器上遇到过启动时报错libwebrtc.so找不到的情况这是因为发布包依赖的系统库版本和系统自带的版本对不上。我的建议是直接用源码编译过程中让 CMake 自己把依赖拉全这样兼容性是最好的。# 编译依赖安装Ubuntu/Debian sudo apt-get install -y cmake libglib2.0-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev libjsoncpp-dev libwebsockets-dev # 下载源码并编译 git clone https://github.com/ThingSpeak/webrtc-streamer.git cd webrtc-streamer cmake -DCMAKE_BUILD_TYPERelease . make -j$(nproc)编译过程会比较长主要是 webrtc 库本身就很庞大耐心等即可。如果你不想等也可以尝试用 Docker 镜像只需要一条命令docker run -d --network host \ --name webrtc-streamer \ registry:8000/webrtc-streamer:latest \ -s 127.0.0.1:80提示Docker 模式建议加--network host启用主机网络。因为 WebRTC 需要大量的 UDP 端口转发容器网络模式下端口映射配置比较繁琐直接用 host 模式最省事。3.2 启动参数详解webrtc-streamer 的启动参数不算多但每个都很关键。下面是我的常用启动命令./webrtc-streamer -s 0.0.0.0:8000 -p 20000-20100参数说明参数含义我的建议-s指定 HTTP/WebSocket 监听地址和端口默认是 8000局域网用0.0.0.0公网部署务必用 HTTPS-pWebRTC 媒体传输的 UDP 端口范围默认全是随机端口手动指定便于防火墙放行-f同时允许的最大会话数默认 16多路摄像头按需调大-q启动时自动连接的 RTSP 地址列表可预先配置免去前端传 URL-o允许的跨域来源CORS多前端部署时很有用补充一个细节-s参数指定的端口前面是 HTTP 服务同时也是 WebSocket 服务的入口。浏览器脚本里用的是ws://或者wss://连接到这个端口。3.3 HTTPS 与 WebRTC 的硬性要求这是我部署时踩过最大的坑之一。Chrome 从某个老版本开始强制要求 WebRTC 只在安全上下文Secure Context中可用。所谓安全上下文要么是localhost要么是 HTTPS 页面。如果你是通过http://访问的页面WebRTC 的getUserMedia和RTCPeerConnection都会被浏览器直接禁用控制台会报错然后视频区域一片黑。所以公网部署时务必在前面加一层 Nginx/Caddy 反代把 HTTP 升级成 HTTPS。如果你只是为了局域网测试可以临时在 Chrome 里输入chrome://flags/#unsafely-treat-insecure-origin-as-secure把http://你的IP:8000加入白名单这样才能跑通。证书我用的是 Caddy 自动申请的 Lets Encrypt 证书配置非常简单。Nginx 反代的时候需要把 WebSocket 的升级头也一并代理过去location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_http_version 1.1; }4. 前端接入三种典型模式的实战4.1 WebRTC 模式真正的低延迟webrtc-streamer 在前端暴露的 API 非常简单核心就是一个webRtcStreamer类。下面是我在项目里实际用过的完整示例// 引入核心库 require(./assets/webrtcstreamer.js); // 创建实例参数是 WebSocket 地址 const webRtcStreamer new webRtcStreamer(ws:// window.location.hostname :8000); // 开始播放指定 RTSP 流 webRtcStreamer.connect( rtsp://admin:password192.168.1.100:554/Streaming/Channels/101, null, null, video ); // 页面卸载时断开连接 window.onbeforeunload () { webRtcStreamer.disconnect(); };HTML 部分也非常简单div stylebackground:#000;width:640px;height:360px; video idvideo autoplay muted playsinline/video /divconnect方法的第一个参数是 RTSP URL第二个参数是音频开关第三个是视频参数第四个是 video 元素的 id。实际跑起来画面延迟体感上几乎就是实时的我家门口有人按门铃手机屏幕上能看到对方抬头看摄像头的瞬间这在以前用 HLS 的方案里是根本不敢想的。4.2 MSE 模式兼容性的兜底方案有时候你会遇到一些环境不支持 WebRTC或者摄像头本身的带宽不足以支撑 WebRTC 的码率要求。webrtc-streamer 也提供了一个基于 MSEMedia Source Extensions的 HLS 模拟播放模式。前端改成调用webRtcStreamer的mseConnect方法即可webRtcStreamer.mseConnect( rtsp://admin:password192.168.1.100:554/Streaming/Channels/101, video );这个模式走的是 WebSocket 拉流webrtc-streamer 把媒体数据封装成 Fragment 推给浏览器浏览器的video元素通过 MSE 解码播放。它的延迟会比 WebRTC 模式高一些但胜在兼容性极好而且服务器压力更小。我一般把它作为微信内置浏览器等 WebRTC 支持不佳场景的降级方案。4.3 录制视频和抓帧webrtc-streamer 还提供了一些额外的 HTTP API可以当作简单的录像方案来用。比如请求# 抓取当前视频帧 curl -X POST http://127.0.0.1:8000/api/takePicture \ -H Content-Type: application/json \ -d {url:rtsp://admin:password192.168.1.100:554/Streaming/Channels/101,file:/tmp/snapshot.jpg}这个能力在安防告警时非常实用。比如探测到移动侦测事件后后台自动抓一帧图再推送通知用户整个过程不到 1 秒。WebRTC 模式因为建立连接本身有一定开销用 HTTP API 抓帧反而是最快的实测 RTSP 源 200 毫秒左右就能返回一张 JPG。5. 常见问题速查与排障心得5.1 视频黑屏但 WebSocket 连接正常这个是最常见的现象现象是页面能连上 WebSocket但 video 元素一直黑屏。大概率是 STUN/TURN 配置问题。WebRTC 协商时浏览器和 webrtc-streamer 需要交换 ICE candidate。如果两边处于不同网段或者有 NAT就需要 STUN 服务器帮忙获取公网地址极端情况下还要 TURN 服务器中继流量。webrtc-streamer 的信令阶段你可以在浏览器控制台观察candidate的输出。如果发现 candidate 全部是host类型没有srflx或relay类型那就是 NAT 穿透没成功。解决方法是在启动时加-t stun:stun.l.google.com:19302指定 STUN 服务器./webrtc-streamer -s 0.0.0.0:8000 -p 20000-20100 -t stun:stun.l.google.com:19302注意局域网内部署一般不需要 STUN直接在控制台看 candidate 里有没有内网 IP 即可。公网部署才需要重点关注穿透问题。5.2 CPU 占用居高不下如果你发现 webrtc-streamer 进程 CPU 超过 100%先排除是不是在转码。用top -H -p PID看线程占用如果v4l2或x264enc相关线程特别吃资源那基本可以断定是 H.265 转 H.264 导致的。解决方案是去摄像头管理后台把视频编码改成 H.264子码流也一并改掉。另外一个优化点是把子码流当作视频源。很多 IPC 摄像头有主码流和子码流两个通道主码流是 4K/1080P 高清子码流是 640x360 流畅。如果你的业务场景不需要极高清画面直接用子码流地址CPU 占用会直线下降。5.3 延迟突然变大而且不稳定WebRTC 的延迟优势依赖的是实时传输但网络拥塞时 webrtc-streamer 内置的拥塞控制算法会根据丢包率调整编码码率画面会降到马赛克级别延迟也会上升。这时候最优先检查的是 Wi-Fi 信号强度和网线链路质量。我实测过在一条丢包率 5% 的 Wi-Fi 链路上WebRTC 延迟从 200 毫秒飙到 1.5 秒而且发烫。排查的时候用ping -f连续打几百个包看丢包率这个比什么工具都直观。5.4 摄像头兼容性清单webrtc-streamer 对海康威视、大华、宇视、TP-LINK 摄像头的支持都挺不错但有个细节要注意老款摄像头默认开启的是“私有协议优先”RTSP 可能没启用。请务必确认摄像头支持标准的 RTSP 协议并且防火墙放行了 554 端口。如果 RTSP 地址测试不通过可以用 VLC 播放器先验证一下地址是否正确排除摄像头端的问题再找 webrtc-streamer 的原因。6. 进阶玩法多路并发与智能家居集成6.1 同时播放多路摄像头webrtc-streamer 支持一个页面里同时拉起多路流。前端创建多个webRtcStreamer实例每个实例对应一个 video 元素即可。实测单路 1080P H.264 硬解的情况下webrtc-streamer 的 CPU 占用大约是 10% 到 15%一台 4 核 8G 的服务器跑 8 路并发没什么压力。带宽方面要注意一路 1080P H.264 的 WebRTC 码率通常在 2Mbps 到 4Mbps 之间8 路就意味着 32Mbps 的上行带宽。如果服务器带宽不够可以把摄像头的子码流作为播放源码率能压到 500Kbps 以下。6.2 接入 Home Assistant如果你在玩 Home Assistantwebrtc-streamer 是一个非常好用的摄像头接入方案。在configuration.yaml里配置 FFmpeg 摄像头源用 webrtc-streamer 作为流代理就能在 HA 的 Lovelace 卡片里实时预览摄像头画面。我的个人方案是用 Docker 启动 webrtc-streamer然后 HA 通过rtsp_to_webrtc组件进行关联。实际体验下来延迟在 300 毫秒左右按门铃的时候手机 App 推送点开就能看到实时画面再也不怕外卖小哥在门口傻等了。6.3 和其他流媒体服务配合使用webrtc-streamer 并不只能接 RTSP只要 GStreamer 支持的网络流协议它都能尝试接入。比如 RTMP、HTTP-FLV、甚至是 HLS 源都可以当作输入。这意味着你可以把直播服务器如 SRS、MediaMTX上的流再通过 webrtc-streamer 转成 WebRTC 分发。这种“RTMP 收流 WebRTC 分发”的组合模式在低延迟直播场景下非常有价值能够兼顾推流端的兼容性和播放端的低延迟体验。举个例子我用 MediaMTX 接收无人机通过 RTMP 推上来的画面再用 webrtc-streamer 转成 WebRTC 给地面站看延迟比原来的 HLS 方案低了整整一个量级。写在最后的几点经验跑了这么久的 webrtc-streamer我最想强调的一点是先确定你的延迟目标再决定要不要上 WebRTC。如果 2 到 3 秒的延迟可以接受HLS 方案更简单、兼容性更好但如果你的场景是通话、安防告警、体育直播WebRTC 的体验完全不是传统方案能比的。另外webrtc-streamer 这个项目本身维护节奏不算特别快遇到问题优先去看它仓库的 issue很多坑别人早就踩过了。如果你的摄像头型号比较少见建议先在 VLC 里把 RTSP 流跑通再上 webrtc-streamer能省掉一半的排查时间。最后再分享一个小技巧-f参数控制最大会话数默认 16 在大多数场景够用但如果你在页面上反复刷新、频繁重连老会话可能没有及时释放等到会话数打满时新连接会被直接拒绝。遇到这种情况先等几秒再刷新或者调大-f的值就不会有体验上的割裂感了。本文还有配套的精品资源点击获取
返回列表