每次遇到监控摄像头或者视频会议系统的RTSP流接入需求时,前端开发同学都会露出痛苦面具。这个诞生于1998年的老古董协议,在现代Web环境中就像个不合群的怪老头——浏览器压根不认它,移动端支持也参差不齐。我去年给某园区做智慧安防平台时,就经历过在Chrome里反复调试RTSP流的绝望,最终发现这根本就是条死胡同。
传统解决方案通常要经过RTMP中转或者用FFmpeg转码,就像为了喝杯咖啡先种咖啡树一样折腾。直到发现RTSPtoWeb这个神器,它相当于给RTSP流装了协议转换器,能实时输出HLS、WebSocket、WebRTC这些现代Web标准协议。最让我惊喜的是它用Go语言编写,资源占用比传统FFmpeg方案低60%以上,在树莓派上都能稳定跑起来。
先准备个docker-compose.yml文件,比搭积木还简单:
yaml复制version: "3"
services:
rtsp-web:
image: ghcr.io/deepch/rtsptoweb:latest
ports:
- "8083:8083" # Web访问端口
- "5541:5541" # RTSP服务端口
volumes:
- ./config:/config # 挂载配置文件
restart: unless-stopped
启动命令简单到令人发指:
bash复制docker-compose up -d
config.json里藏着所有魔法:
json复制{
"server": {
"http_port": ":8083",
"ice_servers": ["stun:stun.l.google.com:19302"]
},
"streams": {
"hls": {
"channels": {
"camera1": {
"url": "rtsp://admin:password@192.168.1.100:554/live",
"on_demand": false
}
}
}
}
}
重点参数说明:
on_demand:true时按需启动流(省资源),false时持续转码audio:是否保留音频轨道(监控场景常设为false)status:0自动启动,1手动启动测试地址:
code复制http://服务器IP:8083/stream/hls/channel/camera1/hls/live/index.m3u8
前端播放代码示例:
html复制<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<video id="video" controls></video>
<script>
const video = document.getElementById('video');
if(Hls.isSupported()) {
const hls = new Hls();
hls.loadSource('你的m3u8地址');
hls.attachMedia(video);
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = '你的m3u8地址'; // Safari原生支持
}
</script>
实测数据:
测试地址:
code复制ws://服务器IP:8083/stream/hls/channel/camera1/mse?uuid=test
核心代码逻辑:
javascript复制const video = document.querySelector('video');
const mse = new MediaSource();
video.src = URL.createObjectURL(mse);
mse.addEventListener('sourceopen', () => {
const ws = new WebSocket(wsUrl);
ws.binaryType = "arraybuffer";
ws.onmessage = (event) => {
const data = new Uint8Array(event.data);
if(data[0] === 9) { // 元数据包
const codecInfo = new TextDecoder().decode(data.slice(1));
sourceBuffer = mse.addSourceBuffer(`video/mp4; codecs="${codecInfo}"`);
} else { // 视频数据包
sourceBuffer.appendBuffer(event.data);
}
};
});
实测表现:
调用地址:
code复制http://服务器IP:8083/stream/hls/channel/camera1/webrtc
完整实现方案:
javascript复制const pc = new RTCPeerConnection({
iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
});
pc.ontrack = (event) => {
document.getElementById('video').srcObject = event.streams[0];
};
fetch('/webrtc/offer', {
method: 'POST',
body: JSON.stringify({
sid: 'camera1',
offer: await pc.createOffer()
})
}).then(async res => {
await pc.setLocalDescription(await res.json());
});
性能表现:
流无法启动
docker logs -f rtsp-webHLS播放卡顿
hls_segment参数(默认2秒)hls_list_size缓冲片段数量WebRTC黑屏
在config.json的channel配置中添加:
json复制"video_select": {
"width": 1280,
"height": 720,
"fps": 15
},
"transcode": {
"video_bitrate": 1500,
"audio_bitrate": 128
}
内存优化技巧:
on_demand: truehls_fragment 1dockerfile复制environment:
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=compute,video,utility
在某智慧工地项目中,我们这样设计架构:
性能数据对比:
| 协议类型 | 平均延迟 | 带宽占用 | 适用场景 |
|---|---|---|---|
| HLS | 10s | 1.5Mbps | 监控回看 |
| WebSocket | 2s | 2Mbps | 实时预览 |
| WebRTC | 0.5s | 3Mbps | 双向通信 |
特别提醒:WebRTC在弱网环境下表现优异,但需要配合TURN服务器使用。我们在新疆某项目测试时,3G网络下仍能保持1秒内的延迟,而HLS已经完全卡死。