用Docker部署go2rtc流媒体网关:统一RTSP/WebRTC摄像头接入与低延迟播放实践
一个人在家里或工作室里折腾监控摄像头、智能家居、无人机图传、甚至是一堆树莓派自制采集设备时,最痛苦的事情其实不是设备买错,而是 协议全都不一样 。有的摄像头只出RTSP,有的只支持RTMP推流,有的走私有SDK,有的走ONVIF,还有的是USB摄像头、手机摄像头、甚至一个网页上的MJPEG流。你想把这些画面统一收进一个平台、随时用浏览器看、用手机看、或者喂给NVR录像,就得靠一个能把“多协议接入”这件事做干净的流媒体网关。go2rtc就是干这个的,而用Docker把它跑起来,几乎是目前最省心的部署方式,不用关心系统依赖、Python版本、编译环境,拉个镜像起来就能用。
这篇文章我会从方案选型开始讲起,再到Docker部署的具体配置、摄像头接入时常见的URL写法和参数细节,最后是一堆实测踩坑记录。适合正在做智能家居集成、监控系统改造、或者单纯想把家里几路摄像头视频统一管理的朋友参考,如果你还在被“这个设备只支持RTSP、那个只支持WebRTC”搞到头大,那这篇文章基本就是为你写的。
1. 为什么选go2rtc:与其他流媒体方案的对比
1.1 传统流媒体方案的根本痛点
很多第一次做摄像头接入的人,第一反应是“直接用FFmpeg转一下不就行了”。这话对了一半。FFmpeg确实是万能的转码工具,但它本质上是一个“一次性处理”的命令,你需要在后台手动维护进程、断线重连、多路并发管理、浏览器播放兼容性,这些都是额外的工作量。比如你用FFmpeg把RTSP转成HLS切片,得自己写循环脚本、处理IO错误、清理历史分片,摄像头一旦断线,进程就挂了,脚本还得重启。做一两路没问题,一旦超过五路,维护成本立刻失控。
另一类做法是上比较重的商业流媒体服务器,比如SRS、ZLMediaKit、Nginx-RTMP这类方案。这些平台功能确实强,但配置复杂度高,而且很多能力对普通玩家来说是过剩的。你只是想在内网里把几路摄像头画面统一起来、在浏览器里低延迟看,不是要做一个能扛百万并发直播的CDN。而且这类方案通常要求你先把所有输入转成统一协议,再对外分发,链路还是偏长。
这时候go2rtc就非常有意思了。它是直接用Go语言写的轻量级流媒体网关,单个二进制文件就能跑,核心卖点就是 多协议接入和多协议输出 。它原生支持RTSP、RTMP、HTTP-FLV、HLS、WebRTC、MJPEG等常见的流媒体协议,还支持直接对接ONVIF摄像头做设备自动发现,甚至可以发现自己接入Home Assistant、Frigate这些智能家居平台。它最大的价值是:你不用关心输入源是什么协议,go2rtc会帮你转成一个最适合播放端消费的输出,浏览器端可以走WebRTC看低延迟画面,手机端可以走HLS,老旧的网页可以直接用MJPEG。
1.2 go2rtc的核心能力与适用场景
go2rtc比较吸引人的一点是它不把转码作为默认手段。很多方案一遇到协议不匹配,第一反应就是“重新编码”,这是吃CPU的大户。go2rtc会尽量做“透传”,只在真正必要的时候(比如浏览器不支持H265、输入格式太特殊)才调用FFmpeg转码。这一点在实际部署中非常值钱,意味着你用一个瘦小的主机就能同时跑五六路摄像头,CPU占用率还相当低。
适用场景我总结下来有三类:
- 监控/智能家居集成场景 :手头设备比较杂,有海康、大华、TP-LINK还有不知名的小厂摄像头,协议不统一,想归拢到一套体系里。
- 低延迟远程观看场景 :在浏览器里用WebRTC看实时画面,延迟能压到一秒以内,比传统的HLS延迟从十几秒降到毫秒级体验差别非常明显。
- 边缘AI/录像联动场景 :go2rtc可以把流直接推给Frigate、Home Assistant这类平台,作为视频源接入,不用再二次转码。
如果你有这些需求中的一个,那go2rtc就是很合适的中间层。接下来进入正题,用Docker把它跑起来。
2. Docker部署整体设计与环境准备
2.1 部署前的环境要求
go2rtc对Docker宿主机的性能要求很低,毕竟它本职是“转发”而不是“转码”。我自己实测在树莓派4B这种ARM架构的小主机上跑六路H264子码流转发,CPU占用率大概在20%-30%之间(不开转码的情况下)。如果你要开FFmpeg转码,那CPU占用会明显上去,ARM板子就比较吃力了,建议起码是x86的N100、J4125这档次的低功耗主机。
宿主机安装好Docker和docker-compose插件是前提,这一步不太赘述。需要注意的一点是,如果你的宿主机是Windows,直接用Docker Desktop跑go2rtc是可以的,但 网络性能会比Linux宿主机差一些 ,尤其在多路大码流转发场景下,还是建议用Linux系统比较稳。
建议的目录结构是这样的:
/home/you/go2rtc/
├── docker-compose.yml
├── go2rtc.yaml
└── data/
└── recordings/ # 如果开启录像功能
2.2 docker-compose.yml完整配置
我贴一份自己实际在用的docker-compose配置,标记了每段的作用,方便你直接抄改:
version: "3.8"
services:
go2rtc:
image: ghcr.io/alexxito/go2rtc:latest
container_name: go2rtc
restart: unless-stopped
network_mode: host
environment:
- TZ=Asia/Shanghai
volumes:
- ./go2rtc.yaml:/config/go2rtc.yaml
- ./data:/data
ports:
# 注意:使用host网络模式时,ports配置可忽略,这里留着只是便于理解端口
- "1984:1984" # Web控制台
- "8554:8554" # RTSP入口
- "8555:8555" # WebRTC入口
- "8555:8555/udp" # WebRTC UDP端口
这里我特意用了
network_mode: host
,这是我踩过几次坑之后的选择。一开始我用bridge模式,按常规映射端口,结果WebRTC那边总是连不上,排查半天发现是WebRTC需要大范围的UDP端口做音视频传输,在bridge模式下你得手动把成百上千个UDP端口都映射出来,非常反人类。改成host模式之后,go2rtc直接复用宿主机的网络栈,WebRTC的UDP端口分配就不用管了,省心很多。
注意:如果你的宿主机是macOS,Docker Desktop对host网络模式支持有限,建议还是用bridge模式并把必要的端口映射出来,或者直接跑原生二进制,别跟网络模式死磕。
2.3 配置文件的初始化
go2rtc支持把配置写在
go2rtc.yaml
里,启动时自动加载。最开始我们可以先放一个最简配置进去,验证服务能起来:
log:
level: info
format: text
api:
listen: ":1984"
rtsp:
listen: ":8554"
webrtc:
listen: ":8555"
这个配置意思是:Web控制台监听1984端口,RTSP服务监听8554端口,WebRTC监听8555端口。填好之后启动容器:
docker compose up -d
启动后打开
http://宿主机IP:1984
,你应该能看到go2rtc的管理界面。界面上会展示当前已经配置的流、连接的客户端数量、每路流的码率等统计信息。这个管理页本身就是一个很实用的调试工具,后面排查问题基本都靠它。
3. 摄像头接入:设备发现与手动配置实操
3.1 用ONVIF自动发现摄像头
go2rtc内置了ONVIF协议的支持,可以帮你自动扫描同一网段内的摄像头设备。在管理后台左侧点击“设备”或直接在配置里加一个onvif源,它就能通过广播发现局域网里支持ONVIF标准的摄像头。海康、大华、TP-LINK这类主流品牌基本都支持ONVIF。
自动发现到设备后,go2rtc会尝试用配置的凭证去拿流地址。这里有个细节:ONVIF只是帮你找到“设备在哪”,真正拿视频流还要靠RTSP或HTTP拉流,所以摄像头上填写ONVIF用户时,建议直接用摄像头的管理员账号,免得碰到权限不足导致拉不到流。
不过说实话,ONVIF自动发现在设备不多的时候挺方便,但如果你的网络里设备太多、或者摄像头厂家对ONVIF支持不完整,自动发现出来的流地址可能不是最优的(比如抓到的是MJPEG而不是H264)。所以更靠谱的方式还是手动配置RTSP地址。
3.2 主流品牌摄像头RTSP地址写法与参数计算
手动配置RTSP地址这事,网上很多教程写得含糊,但实际就那几个套路。以最常见的海康和大华为例:
海康威视的RTSP地址通常长这样:
rtsp://用户名:密码@IP地址:554/Streaming/Channels/101
末尾的
101
含义是“通道1的主码流”,
102
是“通道1的子码流”,
201
就是“通道2的主码流”,依次类推。主码流分辨率高、码率大,适合录像和后期分析;子码流分辨率低、码率小,适合多路同时预览和手机端观看。
大华的RTSP地址语法稍有不同:
rtsp://用户名:密码@IP地址:554/cam/realmonitor?channel=1&subtype=0
其中
channel=1
表示通道1,
subtype=0
表示主码流,
subtype=1
表示子码流。
其他小厂或者杂牌摄像头的RTSP地址就五花八门了,最靠谱的办法是去摄像头的Web管理界面看“音视频/网络设置”里是否显示了流地址,或者搜索“品牌 + RTSP地址获取”。go2rtc配置里把地址写进streams段即可:
streams:
drive_cam:
- "rtsp://admin:password@192.168.1.100:554/Streaming/Channels/101"
yard_cam:
- "rtsp://admin:password@192.168.1.101:554/cam/realmonitor?channel=1&subtype=1"
这里有个参数上的学问:
用户名或密码里如果包含特殊字符,必须要做URL编码
。比如密码是
abc@123
,直接填进URL里会导致解析失败,因为
@
是URL里用来分隔用户信息和地址的保留字符。需要把
@
替换成
%40
。我见过好几个人头天晚上折腾半天接入不上,第二天发现就是密码里有个
#
没编码。这个细节很容易被忽略,但排查起来最耗时。
3.3 多路流合并与备份源配置
go2rtc的streams配置还支持一个很有用的特性:一个流名称下可以配置多个地址,用减号开头列出来。这样做的意义有两个:
- 可以配置 故障切换 ,如果第一个地址拉流失败,自动尝试第二个。
- 可以配置 同源不同清晰度 ,比如主码流断了自动切子码流,保证画面不中断。
streams:
front_door:
- "rtsp://admin:pass@192.168.1.10:554/Streaming/Channels/101"
- "rtsp://admin:pass@192.168.1.10:554/Streaming/Channels/102"
go2rtc会按顺序尝试,第一个不通就切换往下走。这个功能在摄像头偶尔重启或者网络抖动的场景下非常有价值,画面不容易直接黑掉。
4. 浏览器低延迟播放与码流策略
4.1 WebRTC播放路径的正确理解
go2rtc配置好摄像头流之后,最直接的播放验证方式就是打开管理后台,点一下流名称旁边的播放按钮,它会自动用WebRTC把画面拉到浏览器里。
WebRTC是go2rtc的招牌功能,它的意义在于:浏览器原生支持WebRTC,不需要装插件、不需要Flash(这玩意已经死了很多年了)、不需要看HLS那种10秒以上的延迟。go2rtc内部会做一层转换,把RTSP的RTP包转换成WebRTC需要的形式,然后通过UDP直接推给浏览器播放。
实际使用中,WebRTC的延迟能做到几百毫秒,体感上非常“接近实时”。如果你有远程看门口、看宝宝房、看宠物这类需求,WebRTC的体验比HLS好太多。但要注意,WebRTC依赖UDP传输,所以你如果要在公网访问,必须在路由器或防火墙上放行UDP端口。这也是我一直推荐host网络模式的原因,UDP端口管理的问题会被绕开一大半。
4.2 浏览器黑屏与H265编码问题
WebRTC播放最常见的坑,就是 画面黑屏但声音正常,或者完全没有画面也没有报错 。这种情况十有八九是摄像头输出的视频编码格式是H265(HEVC)。
浏览器对H265的支持一直很尴尬。WebRTC规范里强制要求的视频编码是VP8,H264是主流补充,H265则是“看缘分”。Chrome、Edge这些基于Chromium的浏览器官方并没有稳定的H265硬解支持(部分新版本在特定硬件下能用,但不保证)。所以如果你摄像头的编码设成H265,go2rtc做WebRTC推流时会发现“浏览器没法解码”,表现就是黑屏,或者有时候首帧要等好久。
解决方式有两个:
- 在摄像头后台把视频编码改成H264。这是最优解,成本最低,兼容性最好。
- 如果摄像头只能出H265(比如某些较新的4K机型以H265为主),那就得在go2rtc里加转码配置,让它把H265转成H264再推流。
转码配置需要在go2rtc的配置里指定FFmpeg参数:
ffmpeg:
h265_to_h264: "-analyzeduration 1000000 -probesize 1000000 -f lavfi -i anullsrc -c:v libx264 -preset ultrafast -tune zerolatency -c:a aac"
streams:
living_room:
- "rtsp://admin:pass@192.168.1.50:554/Streaming/Channels/101"
- "ffmpeg:living_room#video=h265_to_h264"
注意,转码是CPU密集型操作。我实测过把一路1080P H265主码流转成H264,在J4125上CPU占用大概增加15%-25%。所以如果你有十路摄像头要转码,还是乖乖在摄像头上改编码格式最划算,别让主机白白烧CPU。
4.3 码流选择策略:主码流还是子码流
这个问题我多说一句,因为在多路预览场景下的经验很多人写博客没提。如果你只是想在浏览器里同时看四路、六路、甚至九路画面, 强烈建议在配置里使用子码流 。子码流通常分辨率是D1或720P级别,码率只有主码流的四分之一左右,多路同时跑时网络和CPU的压力都会小很多。
具体做法就是上面提到的,在RTSP地址里控制
101/102
或者
subtype=0/1
的参数。主码流留给录像或者需要放大看细节的场景。把“实时预览走子码流、录像走主码流”这套策略做好,你会发现设备多起来了系统依然跑得很轻快。
5. 常见问题与排查技巧实录
5.1 部署与接入阶段高频问题速查表
我把自己和身边朋友踩过的高频问题整理成了表格,按现象、原因、解决办法排列,方便你直接对号入座。
| 问题现象 | 根本原因 | 解决办法 |
|---|---|---|
| Web控制台打不开 | 容器没起来或端口没映射 |
docker compose ps
查看状态,确认1984端口是否被占用
|
| 控制台能看到流,但画面一直转圈 | RTSP鉴权失败或网络不通 | 先用VLC拉流验证地址是否可用,同时检查用户名密码特殊字符URL编码 |
| 浏览器黑屏无声音 | H265编码,浏览器不支持 | 摄像头端改H264,或者配置FFmpeg转码参数 |
| WebRTC连不上 | UDP端口没放行 | 改用host网络模式,或在路由器放行WebRTC对应的UDP区间 |
| 画面卡顿严重 | 多路同时拉主码流,带宽/CPU瓶颈 | 切换到子码流,降低同时预览路数 |
| 摄像头画面每隔几秒断一次 | 摄像头侧RTSP会话超时配置过于严格 | 调整摄像头“RTSP会话超时/心跳时间”设置,或开启go2rtc的重连机制 |
| 局域网观看正常,公网无法访问 | 端口未做映射或运营商封端口 | 确认公网IP是真正的公网IP,映射1984/8554/8555,考虑DDNS加证书 |
5.2 独家避坑技巧
这里分享几个常规文档里基本不会写的坑。
第一个是
摄像头拉流不要用主码流作为默认预览源
。不止一次,有人跟我抱怨“为什么我的go2rtc画面延迟高、卡顿”,我跟他说你把URL里的
101
改成
102
或
subtype=1
,瞬间就好了。根本原因就是摄像头主码流可能是4K/8Mbps的高码流,你浏览器窗口本身显示区域就小,拉一个8Mbps的流纯属浪费带宽和CPU。
第二个是 关于Docker容器重启后的流自动恢复问题 。go2rtc默认在流断开后会按一定的退避策略重连,但如果摄像头是DHCP分配IP,重启后IP变了,配置里的旧IP就拉不到流了。所以建议在摄像头后台把IP改成静态或者用DHCP保留绑定,省得go2rtc重启后还得手动改配置。
第三个是
配置文件的修改生效时机
。go2rtc默认不会自动热加载你修改的yaml文件,改完配置后需要重启容器或者调用API重载。如果你开发调试时频繁改配置,建议用
go2rtc -config
配合外部编辑器保存时自动重启进程的方式,省去手动重启的麻烦。
第四个是关于
多平台播放时的协议选择
。浏览器端我优先用WebRTC,移动端在微信内置浏览器里WebRTC支持不理想,我就用HLS。go2rtc会自动把每个流暴露成HLS的播放地址,格式是
http://宿主机IP:1984/api/stream/{流名称}/hls
。手机端的VLC、nPlayer、甚至网页里的
<video>
标签都能直接播HLS,只是延迟会高一些。多终端多场景切换时,记住“实时低延迟选WebRTC,兼容性优先选HLS”基本够用。
5.3 与Home Assistant和Frigate的联动
最后聊一个很多玩智能家居的朋友会关心的方向。go2rtc因为原生支持Home Assistant集成,你可以在HA里直接以“camera”实体形式添加go2rtc的流,不用再走一遍
generic camera
的模板配置。Frigate也一样,它的
go2rtc
配置段可以直接指向你已经配好的流名称,让Frigate从go2rtc拉流做物体识别检测,避免多个服务同时直连摄像头导致摄像头RTSP连接数爆掉。
这个架构思路非常实用: 摄像头只允许有限的RTSP连接数,但你的AI检测、录像、网页预览、手机App可能都想同时拉流 。让go2rtc做唯一与摄像头通信的网关,其他所有消费方都从go2rtc拿流,就不会出现“摄像头拒绝连接”的尴尬。我自己的环境就是这样,摄像头只与go2rtc建立一条RTSP连接,Frigate、Home Assistant、手机App全部从go2rtc分发,跑了一两个月,稳得很。
配置上只需要在HA的configuration.yaml里加上go2rtc的自定义源,或者在Frigate的配置里指定
go2rtc
的URL,之后就能直接在HA里看到摄像头画面。这类联动我建议你把go2rtc作为一个基础服务先跑起来,后面接AI、接录像都属于水到渠成的事。
这套Docker部署go2rtc的方案我已经推荐给好几个朋友了,从智能家居玩家到工作室做监控改造的都有,反馈都是“以前要凑齐一堆工具才能干的事,现在一个容器全搞定”。如果你也在被摄像头协议不统一折磨,不妨按这篇文章的步骤跑一遍,相信我,你会回来感谢自己的。
火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。
更多推荐
所有评论(0)