很多玩智能家居、搞监控工程或者自己折腾NAS的朋友,应该都遇到过这种尴尬:手里好几个摄像头,牌子还不一样,海康的、大华的、杂牌的,接入协议五花八门,有的走RTSP,有的走RTMP,还有的只给你个私有SDK。看个实时画面,要么装各自家的APP,要么在电脑上装一堆厂商客户端,烦得要死。我自己就为这事折腾过好几个晚上,直到用上了go2rtc,配合Docker一把梭,才算是把“摄像头自由”这事儿给彻底办了。这篇文章,我就把自己的部署过程、踩过的坑、还有怎么把它跟Home Assistant、VLC这些生态串起来的经验,一次性写给兄弟们。
1. 为什么选 go2rtc:不只是“又一个流媒体网关”
先说个前提,市面上面向摄像头的流媒体中间件不少,像ZoneMinder、Frigate、Scrypted,甚至有些NVR方案也能干这活。但在“多协议接入”这块,go2rtc确实有它独到的设计思路。
1.1 go2rtc 到底解决什么问题
简单理解,go2rtc是一个用Go语言写的轻量级流媒体网关,它不负责录制和AI识别(那是NVR和Frigate的活),它只专注干一件事:把各路来源的流,统一成你能方便消费的格式,再分发给多方去用。
你可以把它当成一个“流媒体翻译官”。摄像头说RTSP,浏览器要WebRTC,你的手机APP要HLS,Home Assistant要MJPEG,正常情况你得各写各的拉流代码。有了go2rtc,你只需要告诉它“RTSP源在哪”,它自己就能搞定协议转换,把H.264/H.265视频流和AAC/G.711音频流,按需转成WebRTC、HLS、MJPEG、RTMP等格式输出。
这玩意儿最吸引我的点有三个:
- 极致轻量:Go编译的单一二进制文件,内存占用几十MB级别,哪怕放在树莓派或者软路由这种弱鸡设备上,也毫无压力。
- 协议兼容之王:它不只是RTSP中转,还内置了针对海康、大华等厂商SDK的适配(通过ffmpeg调用),以及ONVIF协议的自动发现。很多冷门摄像头型号,只要支持ONVIF,go2rtc基本能直接识别取流。
- WebRTC低延迟输出:对于本地局域网内的监控预览,通过WebRTC协议,延迟能压到几百毫秒以内,这在操作云台或者人脸识别联动时,体验是质的飞跃。
1.2 Docker 部署的核心优势
go2rtc官方提供了二进制文件直接运行,但我还是强烈推荐用Docker方式部署。
最直接的原因是**“零依赖”**。go2rtc虽然是个静态编译的二进制,但如果你需要用到它内置的FFmpeg转码功能(比如把无法直接解析的私有格式转成RTSP,或者做H.265转H.264),官方镜像里会封装好一个可用的FFmpeg,如果你裸装,还得自己解决FFmpeg的版本兼容和PATH环境变量问题,麻烦。
另外Docker的版本管理也舒服。go2rtc更新迭代很快,有时候修一个厂商SDK的兼容bug,可能一两天就发一个新版本。用Docker镜像,我在Portainer或者命令行里换个latest标签,docker-compose pull && docker-compose up -d一下就升级完了,不想用了回滚也方便,不会在宿主机上留下一堆乱七八糟的库文件。
2. 部署前的准备工作
动手敲命令之前,先得把账算清楚。虽然Docker部署基本是傻瓜式,但有几个前置条件不准备好,后面排查起来会极其痛苦。
2.1 硬件选型:不是所有设备都能硬解
go2rtc本身不挑硬件,跑在树莓派3B+上也能稳如老狗。但这里有个隐形的大坑:WebRTC低延迟播放的“硬件加速”。
如果只是局域网内两三个人看画面,纯CPU软解也没有任何问题。但你要是接了4路以上1080P的摄像头,还想在手机或者平板上通过WebRTC或者HLS看流畅画面,建议还是找一台带Intel Quick Sync(核显)或者NVIDIA GPU的设备。go2rtc的FFmpeg转码模块是支持硬件加速的,能大幅降低CPU占用。
我自己用的是N100的小主机,平时CPU占用率被go2rtc吃掉的可以忽略不计。如果你打算在群晖NAS上跑,也得确认下你的NAS是否支持容器化(大部分主流都支持了),以及硬解相关驱动是否已经加载。
2.2 网络规划:固定IP是底线
摄像头和NVR主机这一层,一定要用固定的局域网IP。DHCP分配的IP一旦变了,go2rtc配置里的RTSP地址就全失效了,画面一断,排查会让你崩溃。
同时,要确保跑go2rtc的这台主机能直接访问摄像头。这听起来像废话,但很多人会把摄像头挂在POE交换机上,NVR也接同一个POE交换机,而go2rtc跑在主路由或另一台服务器上,这时候就要看下VLAN隔离的设置了,没有路由,自然拉不到流。
2.3 端口规划
go2rtc默认监听1984端口。这个端口用于Web界面和API请求。如果要在公网或者跨VLAN访问,记得防火墙放行1984端口。
WebRTC牵扯到的UDP端口较广(通常默认50000到50100),需要同时放行,不然会导致能扫码出画面,但实际播放黑屏或者要等很久。
3. Docker Compose 部署全过程
这块我直接给你能“抄作业”的配置,省得照着官方文档绕。
3.1 编写 docker-compose.yml
我用的是docker-compose方式管理,比单条docker run更清晰。目录结构大概是:
~/docker/go2rtc/ ├── docker-compose.yml ├── go2rtc.yaml └── data/docker-compose.yml内容如下,亲测可用:
version: "3.8" services: go2rtc: image: alexxit/go2rtc:latest container_name: go2rtc network_mode: host restart: unless-stopped environment: - TZ=Asia/Shanghai volumes: - ./go2rtc.yaml:/config/go2rtc.yaml - ./data:/tmp注意几个关键点是**network_mode: host**。这个非常关键!
go2rtc支持的RTSP、RTSP over TCP、WebRTC等协议,需要创建很多动态的UDP和TCP连接端口,用桥接模式映射端口会非常痛苦。host模式直接就共享宿主机网络栈了,一台设备不需要做NAT映射,视频流吞吐性能损耗也最小。
data目录挂在容器的/tmp是给snapshot等功能用,保存临时截图,不是必须的,但建议加上。
3.2 配置 go2rtc.yaml(核心重点)
这个配置文件是整个平台的心脏,格式是YAML。先放我的一份通用配置:
log: level: info # 调试期间可以改成 debug api: listen: ":1984" webrtc: listen: ":8555" ice_servers: - urls: [ "stun:stun.l.google.com:19302" ] ffmpeg: bin: ffmpeg hardware: "vaapi" # 如果你的CPU不支持VAAPI,可以注释掉或者改成 "cuda" streams: living_room: - "ffmpeg:rtsp://admin:password@192.168.1.108:554/h265/ch1/main/av_stream#video=copy#audio=copy" bedroom: - "rtsp://admin:password@192.168.1.109:554/Streaming/Channels/101" doorbell: - "onvif://admin:password@192.168.1.110"配置内容不复杂,但每一项都值得细细说,下面拆解下。
streams 域详解
streams就是你要映射的通道。键是你给这个流起的名字,值是一个列表,表示该流可以通过哪些方式获取。
直接RTSP取流:
bedroom: - "rtsp://admin:password@192.168.1.109:554/Streaming/Channels/101"这是最朴素的方式,直接把摄像头的RTSP地址交给go2rtc,go2rtc内部做代理转发。注意,这里URL里的特殊字符最好做一下URL编码,比如密码中如果有
@或:,可能会解析错位。通过ffmpeg转换取流:
living_room: - "ffmpeg:rtsp://admin:password@192.168.1.108:554/h265/ch1/main/av_stream#video=copy#audio=copy"很多海康新固件的子码流格式是H.265编码,如果你网页端无法直接解H.265,可以迁就一下,用
ffmpeg:前缀让go2rtc去调内置FFmpeg拉流。后面的#video=copy指的是视频编码流不变(ch1是主码流,这里对着主码流直接copy就行),#audio=copy表示音频编码流也不变。这套思路和播放器的硬件解码原理一致,降低了延迟,也不损失清晰度。如果遇到各种无法直接打开的厂商私有格式,也可以直接落这一招。
ONVIF自动发现:
doorbell: - "onvif://admin:password@192.168.1.110"go2rtc对ONVIF支持得不错。只要你摄像头开启了ONVIF协议,它就能自动探测出视频流地址,不用你去翻厂商文档找RTSP路径。
3.3 启动并验证服务
配置写好后,在docker-compose文件目录下执行:
docker-compose up -d docker logs -f go2rtc打开浏览器访问http://<你的IP>:1984,如果能看到go2rtc自带的Web界面,并且在界面左侧能看到你配置的living_room、bedroom这些通道,点击右侧的画面能正常预览,恭喜,第一步走通了。
4. 核心玩法进阶:不止是“看个画面”
仅仅是能在网页上看摄像头,还不至于让我花这么大力气。go2rtc最诱人的地方在于和周边生态的联动。
4.1 API 接口与代码对接
go2rtc暴露了一套RESTful API,操作起来极顺滑。
比如获取当前所有流的信息,一条curl命令就行:
curl http://127.0.0.1:1984/api/streams返回结果是JSON格式,状态一目了然。
真正玩出花的是api/webrtc接口。当你想在自己的前端页面里快速播放摄像头画面时,不需要引入一大堆JS SDK,直接用WebRTC原生能力去拉go2rtc的流就行。go2rtc官方文档里把这套信的策源地讲得很细。简单说,你的网页代码只要从/api/webrtc?src=<stream_name>获取SDP,然后走传统WebRTC握手,就能实现亚秒级延迟的播放,这体验比HLS的5秒延迟强太多了。
4.2 从 VLC 到网页播放
VLC拉go2rtc的流也非常方便。在VLC里选择“打开网络串流”,填Go2RTC的HTTP接口地址即可:
http://<你的IP>:1984/api/webrtc?src=bedroom甚至你还可以使用RTSP模式:
rtsp://<你的IP>:8554/bedroom这里的8554端口是go2rtc内置的RTSP服务端口(通过rtsp配置项可以修改,默认我在配置里没开,如果需要备注,可以加一行rtsp: "8554")。
4.3 接入 Home Assistant
如果你是Home Assistant玩家,go2rtc的集成体验几乎是官方级的。在HA的配置里添加一个camera实体,指向go2rtc的流地址即可,不需要额外安装怪异的插件。
更骚的操作是,利用go2rtc的WebRTC组件直接给HA的卡片用。这样你在手机上打开HA面板,监控画面几乎是零延迟的。配合人脸识别或者人体传感器,响应速度会舒服不少。
5. 视频流原理与问题排查
做流媒体这行,光会配还不算完,还是要懂点底层原理,否则出了问题就是两眼一抹黑。
5.1 推流和拉流模式
go2rtc里一条流有几种状态:
tracks:表示已经拿到了的音视频轨。producers:当前活动的流生产者。consumers:当前正在消费这条流的客户端。
它这个设计很巧妙。比如一个RTSP源,2个浏览器看,通过go2rtc对外只维持一个到摄像头的连接。内部做分发,对摄像头友好,不会把摄像头连接数打满。
5.2 常见问题速查表
我踩过的坑还挺典型的,顺便整理个表格给大家避雷:
| 症状 | 可能原因 | 处理方法 |
|---|---|---|
| 网页画面一直转圈黑屏 | 摄像头H.265编码,浏览器不支持硬解 | 在WebRTC播放器中勾选“通过FFmpeg转码”,或者在流路径中加#video=copy并启动软/硬解转码(在go2rtc里可以将视频转成H.264) |
| 延迟爆炸(十几秒以上) | 默认拉的是子码流或RTSP over TCP的缓存问题 | 检查摄像头主码流是否用的H.265/HEVC且清晰度高,如果只是看预览,配置一条子码流,或者切换RTSP transport为UDP |
| WebRTC连接不稳定,频繁断开 | UDP端口未放行,或者STUN配置错误 | 确保容器/防火墙放行UDP 50000-50100,确保ICE server可以连通公网(局域网内建议直接用IP) |
| 通过FFmpeg转码后CPU占用100% | 没开硬件加速 | 在ffmpeg模块中配置hardware: "vaapi"或"cuda",并确保Docker启动时映射了设备(devices:/dev/dri:/dev/dri) |
| 摄像头的音频和视频画面不同步 | RTSP协议抓流时的缓存策略导致 | 在go2rtc配置中为流加#audio=copy,让音频轨道直接复用源数据,不同步情况会改善。如果还不行,尝试降低前端的缓冲设置 |
5.3 抓包排查三板斧
排查的时候,先看go2rtc的日志,然后把日志级别调成debug,直接看它打印的SDP信息和RTSP状态码,很多问题就清楚了。
如果涉及摄像头本身的问题,可以在宿主机上用ffprobe或者curl直接测试一下摄像头的RTSP地址是否可通。注意不要用ffmpeg去探测过于频繁,部分摄像头有连接数限制,试探太多会给锁IP。
6. 与 Docker 生态的“梦幻联动”
go2rtc用处太多了,经常和别的服务串起来用,比单一功能价值翻倍。
6.1 联动 Frigate 做检测
Frigate会从go2rtc这里拉流,供检测模块使用。你可以直接在Frigate配置里指向go2rtc的流地址,这样既可以平时在Web UI看低延迟实时流,又能让Frigate随时抓帧做目标识别。好处是Frigate不用自己维护一堆摄像头连接,都交给go2rtc去管理。
6.2 联动 OBS 推流
如果你想在家里搭建一个简单的“家庭直播间”或者做一个“慢直播”页面,调用go2rtc的WebRTC接口,OBS通过浏览器源拉过来,再走自有RTMP推到平台,链路非常顺滑。
6.3 结合 Node-RED 做自动化
Node-RED接onvif或RTSP很酸爽,但监控流本身不好在流程里直接处理。用go2rtc做中间层,Node-RED只负责API调用(get snapshot)和决策,画面表现交给go2rtc,分工清晰效率高。
7. 最后聊点实在的:几点心得
折腾了这么久,有几点感受特别深。
- 别迷信最新版本,稳定版更重要。go2rtc的Dev分支新功能多,但偶尔也会冒出来一些breaking change。我生产环境一直固定在某个稳定版本,等确认没问题再升级。
- 配置文件写注释是个好习惯。go2rtc的yaml格式比较宽泛,但对缩进和特殊符号还是敏感的,如果你的密码或者路径里带
#或&,建议用引号包裹起来。 - 其实这玩意儿的Web界面自带一个功能,叫
snapshot,可以实时抓帧,这对做监控联动或者生成缩略图非常有用。直接浏览器访问/api/frame?src=<stream_name>就能返回一张JPEG图,毫秒级响应,比你自己用ffmpeg去抓要省事太多。
希望这篇经验贴能帮兄弟们少走点弯路。流媒体这东西入门容易折腾精难,但我们图的不就是那种“一屏看尽所有摄像头”的舒坦劲儿吗。去搞个Docker跑起来试试看吧,你会有惊喜的。