跳到主要内容基于 SRS 与 WebRTC 的 RTSP 多路摄像头低延迟监控方案 | 极客日志C++大前端
基于 SRS 与 WebRTC 的 RTSP 多路摄像头低延迟监控方案
文章介绍了在车载监控场景下,实现多路 RTSP 视频低延迟(<500ms)播放的解决方案。通过 SRS 流媒体服务器将 RTSP/H.264 流转封装为 WebRTC/H.264,结合浏览器原生解码与 Qt 桌面端硬解优化(VA-API),解决了多路并发下的 CPU 占用与延迟问题。最终实现了 i7-7700 上 6 路 1080p 视频低负载稳定运行。
橘子海0 浏览 本文记录了在摄像头 RTSP 流视频多路实时监控项目中,落地的一套「多路 RTSP 低延迟播放」方案的全过程:从选型、编码、到 Web/桌面端播放与硬解优化。
一、需求现状
现场有一个远程监控端,需要同时监控多台车载设备的摄像头画面,每台设备约 6 路摄像头,摄像头输出 RTSP(视频 H.264;部分摄像头型号还有音频)。由于是车载实时摄像头,关键的不是能播,而是多路、低延迟(由于在现场操作需要实时反馈,所以需要 1 秒以内)、低 CPU 占用,因此核心需求可以总结成四点:
- 多路并发:同屏 6+ 路播放,最多一个监控端同时播放 12 路视频;
- 低延迟:操作链路希望接近实时(目标 < 500ms 级);
- 桌面端:需要有编码控制能力,最好 Qt 桌面程序;
性能与稳定性:客户端需要稳定走 GPU 硬解,否则多路全走 CPU 软解解码会被拖死;部署/运维复杂度:比如要更换视频流接入的时候要足够方便,最好能配置后一键部署;二、技术选型
HLS
HLS 的核心思路是把连续视频切成一段段 TS 分片(segment),服务器创建并动态更新一个 .m3u8 播放列表文件,这个文件里记录了所有 .ts 视频切片的文件名、顺序、时长等信息,客户端按 m3u8 索引列表去拉分片播放。它的优点是兼容性很好,所有现代浏览器和操作系统都原生支持,适合普通直播、点播和 CDN 分发。
在一个 TS 分片没有播完并同步到 m3u8 之前,客户端是无法看到最新画面的。这天生决定了 HLS 的实时性不高,一般在 3 秒以上,加上各个链路的延迟和缓冲,总延迟轻松到达 10 秒左右,这对于实时监控是完全不可接受的。
HTTP-FLV
HTTP-FLV 通常是服务器将音视频数据用 FLV(Flash Video)格式进行封装,通过客户端和服务端建立的 HTTP 长连接流式传输到播放器上,延迟在 1-3s,可以满足一定的实时性需求。缺点是需要前端引入 flv.js 之类的 JS 库在 JS 层对 FLV 流解封装成 H.264、音频等数据,尤其在多路并发时,CPU 占用会比较高,且浏览器对 FLV 的支持不如 HLS/WebRTC 原生。
海康 WebSDK 的 WebSocket
海康的 WebSDK 提供了基于 WebSocket 的视频流传输能力,延迟可以做到 1 秒以内,适合海康设备的接入,但我看有些老一些的海康设备可能不支持 WebSocket,而且 WebSDK 要求 Chrome 版本不低于 91,如果你的摄像头都支持 WebSocket 且能保证浏览器的 chromium 内核版本在 91+,那么这个方式也是可行的。
WebRTC
WebRTC(Web Real-Time Communication)是目前实时音视频通信的主流技术,现代浏览器(Chrome, Firefox, Safari 等)都原生支持 WebRTC 协议栈,无需安装插件,实时性通常能做到 500ms 左右,非常适合对实时性要求高的监控场景。WebRTC 的设计目标就是实时通话与互动,浏览器对其实现非常成熟。对于 H.264 等常见编码格式,浏览器能直接调用 GPU 进行硬件加速解码,显著降低 CPU 占用。
三、核心实践:通过 SRS 将 RTSP + H.264 视频流转封装为 WebRTC + H.264
我最终使用 SRS(Simple Realtime Server)开源流媒体服务器,一直在稳定维护,也有不少用到生产级环境的案例,文档有中文,部署也比较简单,直接 docker 拉一个镜像然后一行命令就能启动,另外它自带视频流录制功能,后期做录制也方便。
在远程监控服务器上用 Docker 部署 SRS,把摄像头 RTSP 拉到本机后,再以 WebRTC 的方式提供给前端播放。
这里要强调一个关键点:尽量做转封装(Remux),避免转码(Transcode),摄像头已经输出 RTSP 包着的 H.264 服务器只需要转协议成 WebRTC 包着 H.264 即可,不需要重新编码,转码会带来很大的 CPU 负担和延迟。
整体思路:摄像头推流 RTSP(H.264) ,经过 SRS ingest 拉流并通过 rtmp_to_rtc 转封装为 WebRTC(H.264) ,前端浏览器用 <video> 播放。
3.1 SRS 核心配置解析
SRS 的配置文件 srs.conf 是核心。下面用一个最小配置片段:
listen 1935
enabled on
listen 8000
candidate $CANDIDATE
}
http_server {
enabled on
listen 8080
dir ./objs/nginx/html
crossdomain on
}
vhost __defaultVhost__ {
rtc {
enabled on
rtmp_to_rtc on
nack on
twcc on
}
ingest camera_RIG001_0 {
enabled on
input {
type stream
url rtsp://admin:[email protected]:554/Streaming/Channels/101
}
ffmpeg ./objs/ffmpeg/bin/ffmpeg
engine {
enabled on
perfile {
rtsp_transport tcp
fflags nobuffer
flags low_delay
probesize 32
analyzeduration 0
max_delay 0
}
vcodec copy
acodec copy
output rtmp://127.0.0.1:[port]/live/camera_RIG001_0?vhost=[vhost]
}
}
}
3.2 Docker 一键配置
由于现场设备的 IP 和摄像头数量可能会变化,手动修改 srs.conf 比较繁琐且容易出错。我做了一套自动化配置流程:
- 配置文件:提供一个 JSON 文件,维护用户摄像头的 IP/Port 列表。
- 生成脚本:读取摄像头列表,生成
srs.conf,并在上一部配置变更时更新文件。
- 自动重启:检测到配置变更后,执行
docker restart srs 让配置生效。
docker pull registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5
docker tag registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5 ossrs/srs:5
docker run -d --name srs \
--restart=always \
-p 1935:1935 \
-p 1985:1985 \
-p 8080:8080 \
-p 8000:8000/udp \
-e CANDIDATE="127.0.0.1" \
-v ~/hello/config/srs_latest.conf:/usr/local/srs/conf/srs.conf \
ossrs/srs:5 \
./objs/srs -c conf/srs.conf
1935/tcp:RTMP(SRS 内部回环推流也会用到)
1985/tcp:HTTP API
8080/tcp:HTTP Server(SRS 自带的控制台页面)
8000/udp:WebRTC(RTC Server)
我实际工程里会把改摄像头配置 -> 生成 srs.conf -> 重启容器 这套动作做成一键脚本,避免手工改配置带来的维护成本,规范一点可以弄个网页让用户维护摄像头配置。
四、前端落地
1. Web 端播放
由于浏览器对 WebRTC 原生支持比较好,标准 HTML5 <video> 可以直接接住 WebRTC 流播放,我在前端页面里直接用 <video> 标签播放 SRS 输出的 WebRTC 流,让浏览器原生解码器(通常能自动走 H.264 硬解)解码,前端不需要引入其他第三方库,CPU 占用也更可控。
前端的静态资源服务器可以是 Nginx,也可以是其它轻量方案,比如 SRS 自带的 HTTP Server 就可以直接用来托管前端页面,或者 nodejs、python 都行。
2. 桌面化(Qt / QWebEngine)
QT 官方包里带的 QWebEngine 因为专利原因是不包含 H.264 编解码能力的,需要下载源码自行编译并增加 -webengine-proprietary-codecs 编译指令启用专有编解码器支持,才能让 QWebEngineView 的 Chromium 内核支持 H.264 编码。
另外注意让内置浏览器的视频解码尽可能走 VA-API 等硬解路径,可以在 QWebEngineView 里打开 chrome://gpu 看一下最下面的 Video Acceleration Information 有没有 H.264 硬解支持。我增加的 QT 环境变量如下:
qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--enable-features=VaapiVideoDecoder,VaapiVideoEncoder,VaapiIgnoreDriverChecks,VaapiVideoDecodeLinuxGL --ignore-gpu-blocklist --enable-gpu-rasterization --in-process-gpu --disable-features=UseChromeOSDirectVideoDecoder --limit-fps=20 --num-raster-threads=4 ");
优化项:SmartH264
注意在摄像头的配置中,将摄像头的 H.264 编码参数调优为 SmartH264,可以让摄像头在画面静止时降低码率(在画面不怎么动的情况下可以最大降低 90% 码流),减少网络带宽占用,同时在画面有变化时提升码率和帧率,保证画面质量。这样在多路并发时,可以显著降低整体的网络和解码压力。
优化项:硬解验证与驱动选择
在使用 intel 集显的 i7-7700 测试时,通过指定集显使用特定的 VA-API 硬件加速驱动 export LIBVA_DRIVER_NAME=iHD,强制开启 VA-API 硬解:
如果 intel_gpu_top 命令 Engine 的 Video 不为 0,则说明硬解成功,事实证明如果可以成功开启 GPU 硬解,那么即使使用集显,CPU 负载也能保持较低水平。如果使用 AMD/NVIDIA 显卡,需要参考对应的 VA-API 驱动文档,确保硬解被正确启用。
五、总结
通过 SRS 将 RTSP + H.264 视频流转封装为 WebRTC + H.264,并在前端浏览器和 Qt 桌面应用中播放,成功实现了多路低延迟的实时视频监控需求。我这边在实际测试中,i7-7700 的 CPU 上使用集显 GPU 播放 6 路 1080p H.264 流,CPU 总占用保持在 20% 左右,延迟控制在 300-500ms 之间。
SRS Getting Started
Qt WebEngine H.264 Feature
微信扫一扫,关注极客日志
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown 转 HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
- HTML 转 Markdown
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
- JSON 压缩
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
- JSON美化和格式化
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online