如果你手里同时有海康、大华、宇视或者某个杂牌 IPC 摄像头,大概率体验过这种割裂感:每台设备都有自己的 App,每个品牌都要注册账号、绑定设备,想在一台电脑上同时看所有画面,要么同时开三四个客户端,要么去折腾一台昂贵的 NVR。我去年给家里装了 4 个不同品牌的摄像头后,被这件事反复折磨,最后靠 go2rtc 彻底解决了。

go2rtc 是一个用 Go 写的轻量级流媒体平台,核心能力是把 RTSP、RTMP、ONVIF、HLS 这类五花八门的协议统一接管,再以 WebRTC、MSE、HLS 等方式输出到浏览器或下游系统。配合 Docker 部署,从拉镜像到三路摄像头画面同时出现在浏览器里,我实测十分钟左右就能搞定。这篇文章就讲讲我的部署过程、配置思路,以及踩过的几个有代表性的坑,给准备入门的同学一条可以直接"抄作业"的路线。

1. 三个摄像头三种 App:多协议割裂把我逼到换方案

1.1 go2rtc 到底是个什么角色

先说个容易混淆的点:go2rtc 不是 NVR(网络硬盘录像机),它不做长时间录像存储,它的定位更像是一个"流媒体交换机"或者叫"代理网关"。

从名字也能看出来,go2rtc 的初始目标是把各种来源的流(Source)转成浏览器能直接播放的 WebRTC 流。但发展到现在,它已经变成了一个支持多协议中转的多面手:

  • 输入侧支持 RTSP、RTMP、HLS、HTTP-FLV、SRT、ONVIF、MJPEG,甚至一些特定品牌摄像头的私有协议。
  • 输出侧支持 WebRTC、MSE、HLS、RTSP、RTMP、MJPEG、HTTP-FLV。

打个比方,你家的摄像头就是各种说着不同方言的人(H.264、H.265、MJPEG),go2rtc 相当于一个同声传译,把所有人的话翻译成你能听懂的普通话(浏览器直接播放的视频流),而且这个翻译过程非常轻量,不做额外的画面处理,纯粹是"搬运+转封装"。

我见过不少人在论坛里问"go2rtc 和 ffmpeg 有什么区别",简单解释:ffmpeg 是一个瑞士军刀,什么都干,但要你自己搭命令行、处理复杂的分支逻辑;go2rtc 则把"拉流-转码-推流"这条链路封装成了声明式配置,大多数场景下你不用写一条 ffmpeg 命令,写几行 YAML 就行。

1.2 和 Zoneminder、MotionEye 相比,我为什么留它

在决定 go2rtc 之前,我其实试过另外几套方案,这里说说我的真实感受。

第一套是 Zoneminder。功能确实重型,支持运动检测、录像回放、多用户权限管理,但对新手非常不友好,配置页面密密麻麻,光是把摄像头加进去就要理解一堆"Monitor/Storage/Source"的概念。我折腾了一个周末,摄像头画面终于出来了,但浏览器播放延迟三四秒,而且系统资源占用居高不下。Zoneminder 适合有专门服务器、愿意花时间深入研究的人,不适合我这种"只想快速看到画面"的场景。

第二套是 MotionEye。它比 Zoneminder 轻量很多,界面也漂亮,基于 Python 开发,Docker 安装很简便。但它对流媒体协议的支持相对单一,WebRTC 这种低延迟方案是没有的,默认走 MJPEG 或 HLS,延迟依然在 1 到 3 秒左右。作为轻量监控界面够用,但如果你想拿它做实时操作(比如云台控制、实时预览),体验会打折扣。

第三套才是 go2rtc。它的优势在我看来非常聚焦:

  • 单二进制文件,资源占用极低
  • Web UI 配置界面简单,设备状态一目了然
  • 原生支持 WebRTC,延迟能压到 0.2 到 0.5 秒
  • 能和 Home Assistant 无缝集成
  • 配置完全声明式,全部写在 go2rtc.yaml 里

我最后把 go2rtc 作为"取流汇聚层"使用,Zoneminder 和 MotionEye 就不再折腾了。它在我的架构里承担的是"统一接入所有摄像头,并向浏览器和 HA 提供低延迟流"这个核心职责。

1.3 一个配置文件干完所有事

go2rtc 的配置逻辑非常朴素,核心就一个 YAML 文件。你不需要理解复杂的状态机,也不需要记住大量的集群概念,所有流都用 streams 关键字定义。

streams:
  camera_living:
    - rtsp://admin:password@192.168.1.64:554/Streaming/Channels/101
  camera_yard:
    - rtsp://admin:password@192.168.1.65:554/cam/realmonitor?channel=1&subtype=0

写完之后,Web UI 上会自动出现两个可点击的画面入口,浏览器点开就能看。这种"写配置—刷新页面—看画面"的反馈链路,是我认为 go2rtc 最吸引人的地方。

2. Docker 部署细节:镜像选择、端口映射与配置挂载

2.1 官方镜像与版本选择

go2rtc 官方提供了 Docker 镜像,仓库名是 alexxit/go2rtc 。我见过有些人从第三方镜像源拉,其实没必要,官方镜像一直维护得很勤快,直接拉最新版就行。

docker pull alexxit/go2rtc:latest

如果你对版本敏感,可以锁定具体的 tag 而不是用 latest,比如 alexxit/go2rtc:1.9.7 。我个人在家庭环境直接用 latest,因为 go2rtc 的版本迭代很快,新版本往往会修复一些摄像头兼容性问题,追新反而省事。当然,生产环境我还是建议锁版本,避免更新到某个不兼容的版本导致业务中断。

镜像大小方面,go2rtc 的镜像只有几十 MB,比一堆包含完整 ffmpeg 静态编译的媒体服务器镜像要小得多,拉取速度非常快。

2.2 docker run 和 docker compose 两种方式实测

先给最直接的 docker run 命令:

docker run -d --name go2rtc \
  -p 1984:1984 \
  -p 8554:8554 \
  -v $PWD/go2rtc.yaml:/config/go2rtc.yaml \
  --restart unless-stopped \
  alexxit/go2rtc:latest

简单解释下每个参数:

  • -d :后台运行。
  • --name go2rtc :容器命名,方便后续管理。
  • -p 1984:1984 :Web 管理界面端口,浏览器访问 http://宿主机IP:1984 就能看到 UI。
  • -p 8554:8554 :RTSP 服务端口,go2rtc 对外提供 RTSP 分发能力时使用。
  • -v $PWD/go2rtc.yaml:/config/go2rtc.yaml :把当前目录下的配置文件挂载到容器内。注意,路径一定要正确,我第一次部署时挂载错了目录,容器一直用默认的空配置启动,页面里啥都没有。
  • --restart unless-stopped :开机自启、异常退出自动重启,这个对长期运行的流媒体服务很关键。

如果你更习惯用 Docker Compose 管理,下面是对应的 docker-compose.yml :

version: "3.8"

services:
  go2rtc:
    image: alexxit/go2rtc:latest
    container_name: go2rtc
    restart: unless-stopped
    ports:
      - "1984:1984"
      - "8554:8554"
    volumes:
      - ./go2rtc.yaml:/config/go2rtc.yaml
    environment:
      - TZ=Asia/Shanghai

这里加了一个 TZ 环境变量,设置时区。如果你后续要给流加时间水印或者做录像分段,时区不对会导致时间显示完全错乱。

2.3 端口和网络模式的选择逻辑

go2rtc 默认主要监听两个端口:1984 和 8554。1984 是 Web UI 和 HTTP 播放端口,8554 是 RTSP 服务端口。如果你还需要接收 RTMP 推流或者走 SRT 协议,那就得额外把 1935、8888、8555 等端口也映射出来。

这里有一个关键选择:用桥接网络还是 host 网络模式。

我最初用的是标准的桥接模式(也就是上面 docker run 的写法,通过 -p 映射端口)。这个模式在大多数场景下都能正常工作,特别是你只需要通过 IP 地址直连摄像头 RTSP 流时。

但如果你要用 ONVIF 自动发现功能,强烈建议改用 host 网络模式。原因是 ONVIF 的设备发现依赖 UDP 组播,而 Docker 的 bridge 网络默认对组播支持不佳,摄像头发到局域网组播地址的响应包,容器里的 go2rtc 根本收不到。

host 模式的 compose 写法:

version: "3.8"

services:
  go2rtc:
    image: alexxit/go2rtc:latest
    container_name: go2rtc
    restart: unless-stopped
    network_mode: host
    volumes:
      - ./go2rtc.yaml:/config/go2rtc.yaml

host 模式下不需要写 ports 映射,因为容器直接使用宿主机网络栈,监听的是宿主机端口。这种方式的优点是组播、UPnP 等局域网发现协议都能正常工作,缺点是端口冲突由你自己负责,比如宿主机已经占用了 1984 端口就会有问题。

我的建议是:如果你的摄像头品牌和型号已知,直接在配置文件里写 RTSP 地址,用桥接模式就够了,简单干净;如果你买的是一堆杂牌摄像头,不知道 RTSP 取流路径是什么,想靠 ONVIF 自动发现,那还是用 host 模式省心。

3. 摄像头接进来:RTSP 直连与 ONVIF 两种接入方式

3.1 各品牌 RTSP 取流地址格式汇总

接入摄像头第一道坎,就是搞清楚各家的 RTSP 取流地址。不同的厂商、不同的型号,取流路径格式差异很大。我把自己试过的几类典型格式整理成表,大家可以直接参考:

品牌 主码流 RTSP 地址 子码流 RTSP 地址
海康威视 rtsp://用户名:密码@IP:554/Streaming/Channels/101 rtsp://用户名:密码@IP:554/Streaming/Channels/102
大华 rtsp://用户名:密码@IP:554/cam/realmonitor?channel=1&subtype=0 rtsp://用户名:密码@IP:554/cam/realmonitor?channel=1&subtype=1
宇视 rtsp://用户名:密码@IP:554/unicast/c1/s0/live rtsp://用户名:密码@IP:554/unicast/c1/s1/live
TP-Link rtsp://用户名:密码@IP:554/stream1 rtsp://用户名:密码@IP:554/stream2

这里有个概念要理解:主码流和子码流。

主码流的分辨率高(通常是 1080p 或 4K),码流大,适合录像存档和全屏查看;子码流分辨率低(通常是 720p 甚至 CIF),码流小,适合多画面预览和手机流量环境。在 go2rtc 里,我通常会为同一台摄像头配置两个入口,一个叫 xxx_main ,一个叫 xxx_sub ,需要低延迟实时预览时用子码流,需要看细节时切换主码流。

不建议所有场景都直接拉主码流。如果你有 4 到 8 路摄像头全部走主码流,局域网带宽和 go2rtc 的内存压力都会明显上升。

3.2 在 go2rtc.yaml 里定义多个摄像头

下面是我的一个实际配置文件片段,包含三台不同品牌的摄像头:

streams:
  hik_living_main:
    - rtsp://admin:MyPass123@192.168.1.64:554/Streaming/Channels/101
  hik_living_sub:
    - rtsp://admin:MyPass123@192.168.1.64:554/Streaming/Channels/102

  dahua_yard_main:
    - rtsp://admin:Pass2024@192.168.1.65:554/cam/realmonitor?channel=1&subtype=0

  unv_gate_sub:
    - rtsp://admin:GatePass@192.168.1.66:554/unicast/c1/s1/live

写完保存后,重启容器让配置生效:

docker restart go2rtc

接着浏览器打开 http://宿主机IP:1984 ,左侧菜单栏就能看到你这几个流的名字。点进去,它会自动用最优的方式开始播放。

这里有个小技巧:如果发现某个流无法播放,先看 Web UI 对应流名称旁边的状态指示灯。如果是红色,说明 go2rtc 拉流失败了,这时把鼠标悬停在流名称上可以看到报错信息,比如"unauthorized"(用户名密码错误)、"connection refused"(摄像头端口不通)或者"timeout"(摄像头无响应)。这些报错信息比你在浏览器控制台里瞎猜有用得多。

3.3 ONVIF 自动发现与接入

如果你的摄像头支持 ONVIF 协议(现在绝大多数 IPC 都支持),go2rtc 还能通过 ONVIF 协议自动解析出摄像头的 RTSP 地址。

配置方式也很简单:

streams:
  unkown_camera:
    - onvif://admin:MyPass123@192.168.1.100:80

这里的 192.168.1.100:80 是摄像头的 HTTP 管理端口,不是 RTSP 端口。go2rtc 会通过 ONVIF 协议向摄像头发起设备探测,自动获取到它的 RTSP 取流地址并开始拉流。

这个功能在什么场景下特别有用?就是你买了一个杂牌摄像头,说明书丢了,用扫描工具扫到了 IP,却不知道 RTSP 路径的时候。直接用 ONVIF 方式让 go2rtc 自己去"问"摄像头要地址,省去你翻手册的时间。

另外,go2rtc 的 Web UI 里还集成了一个"扫描局域网 ONVIF 设备"的功能。进到 Web UI 的配置页面,它会自动发现局域网内支持 ONVIF 的设备列表,你只需要输入设备的用户名密码就能快速添加。这个功能在 host 网络模式下使用效果最好,原因上一章说过,组播包在 bridge 模式下容易丢失。

3.4 无法通过 ONVIF 自动发现时的兜底方案

ONVIF 自动发现虽然方便,但也不是万能的。有些厂商为了"系统安全",把 ONVIF 功能在默认固件里关闭了,或者只开放给自家 App 使用。碰到这种情况,我通常先用 nmap 扫一下摄像头 IP 的常见端口:

nmap -p 80,554,8000,8899 192.168.1.100

看 554 (RTSP)和 80 (HTTP)端口是否开放。如果 554 开了,直接搜该品牌的 RTSP 取流路径;如果只有 80 开了,那试试 ONVIF 方式;如果连 80 都没开,只能把摄像头恢复出厂设置,用厂商默认端口再试。

这招虽然不是百分之百有效,但能快速排除"摄像头压根没开 RTSP 功能"这个可能。

4. 浏览器里看实时画面:WebRTC、MSE、HLS 三种链路怎么选

4.1 延迟和兼容性对比

go2rtc 最让我惊艳的部分,不是它能把 RTSP 流转成别的协议,而是它提供的低延迟播放链路。下面是拿同一台海康摄像头实测得到的三种播放方式的延迟表现:

播放方式 平均延迟 浏览器兼容性 适用场景
WebRTC 0.2~0.5 秒 Chrome、Edge、Firefox、Safari 都支持 实时预览、云台控制、需要"所见即所得"的场景
MSE 1~3 秒 Chrome、Edge、Firefox、Safari 都支持 普通监控画面查看
HLS 5~10 秒 全平台,包括 iOS Safari 兼容性优先、延迟不敏感的场景

我第一次在 go2rtc 的 Web UI 里点开摄像头,画面几乎是"即点即出"的,心里确实震了一下。因为在这之前,我用的 MotionEye 走 HLS 播放,点开画面之后还要转圈两三秒,拖动窗口时画面还会卡顿。WebRTC 的体验完全不同,点开就出画面,拖动浏览器窗口几乎没有撕裂感。

WebRTC 为什么能这么低延迟?简单说,它用 UDP 传输视频数据,跳过了 TCP 的拥塞控制和重传逻辑,而且采用 P2P 的架构思路,服务端只负责转发必要的数据包。UDP 丢包确实会导致画面短暂花屏,但在局域网环境下,丢包率极低,WebRTC 的低延迟优势可以完全发挥。

4.2 go2rtc 怎么自动选择播放链路

你可能会问:既然 WebRTC 这么好,是不是所有场景都强制用 WebRTC?

其实不用你操心,go2rtc 在浏览器里做了一套自动降级机制。当你在 Web UI 点击一个流时,go2rtc 的 Web 页面 JavaScript 会按照下面这个优先级尝试:

  1. 优先尝试 WebRTC,如果浏览器和网络环境支持。
  2. WebRTC 连接失败(比如 WebRTC 需要的 UDP 端口被防火墙挡了),自动降级到 MSE。
  3. MSE 也不行(比如流编码格式是 MKV 封装且浏览器不认),最终退到 HLS。

这套自动降级的逻辑做得很成熟,用户基本无感。因为 go2rtc 会在同一个 HTTP 端口上同时提供 WebRTC、MSE 和 HLS 的访问入口,浏览器段脚本会根据握手结果自己决定用哪条路。

另外,MSE 和 HLS 的区别也值得一提。MSE(Media Source Extensions)是浏览器提供的一个 JavaScript API,go2rtc 把 RTSP 流转成 fMP4 片段通过 HTTP 推给浏览器,延迟比 HLS 低不少;HLS 则是把流切成一个个 TS 文件,通过 m3u8 索引文件播放,切片和加载都天然引入延迟。iOS 的 Safari 对 MSE 支持有限,所以在 iPhone 上访问时,go2rtc 往往会自动落到 HLS,这一点在移动端监控场景要留意。

4.3 在 Web UI 里一次看多路画面

go2rtc 的 Web UI 支持多路画面同时打开,这个功能很实用。

点击 UI 左上角的"+"号,把需要的流一个个添加进去,它就会以网格布局同时渲染多个播放器。我在部署 4 个摄像头之后,就是靠这个功能实现了"一张屏看全屋"。

但有一点需要注意:多路同时播放时,每一路默认都走 WebRTC,每一路都要占用一份 UDP 端口和网络资源。如果局域网带宽不够,建议在 UI 里把部分摄像头切换成 MSE 或 HLS,牺牲一点延迟,换取整体流畅度。

5. 折腾过程中的典型坑位:编码格式、URL 转义与网络模式

5.1 H.265 编码导致浏览器黑屏

这是我遇到的最大一个坑,也是用 go2rtc 接摄像头最容易踩的问题。

现在的摄像头,尤其是海康和大华的新款,默认主码流编码可能是 H.265(HEVC)。H.265 比 H.264 在同等画质下码率更低、存储更省,但对于浏览器播放来说是个麻烦。

Chrome 和 Firefox 对 H.265 的支持一直不完整,Chrome 在不少平台上只支持硬件解码的 H.265,如果硬件不支持,就会直接黑屏或者报错。Safari 对 H.265 支持得倒是很全面,但你不能要求全家都用 iPhone 看监控吧。

我当时的现象是:画面能出声音(如果有音频的话),但视频区域纯黑,右上角有报错日志。后来我把摄像头主码流的编码格式从 H.265 改成 H.264,问题立刻消失。

解决方案有三个,按推荐程度排序:

  1. 在摄像头后台管理界面,把视频编码改为 H.264。这个最彻底,浏览器兼容性最好,缺点是会增大一点存储占用。
  2. 在 go2rtc 里对指定流启用转码,把 H.265 转成 H.264。这需要给 go2rtc 额外配置 ffmpeg,缺点是转码吃 CPU,低功耗设备上跑不动。
  3. 保持 H.265 不管它,强制在支持 H.265 的浏览器上播放,比如 Safari 或者开启了硬件解码的 Edge。

我现在的做法是:主码流保持 H.264,因为我要在浏览器和 Home Assistant 里看;子码流如果摄像头支持 H.265,我就让它保持,反正子码流大部分时候只是为了多画面预览,清晰度要求不高。

转码配置可以参考下面这样(前提是你手动指定了 ffmpeg 路径):

streams:
  camera_h265_main:
    - rtsp://admin:password@192.168.1.64:554/Streaming/Channels/101
    - ffmpeg:camera_h265_main#video=h264#hardware

这条配置的意思是:先从 camera_h265_main 拉流,然后用 ffmpeg 把视频转成 H.264。 #hardware 表示优先尝试硬件转码(Intel Quick Sync 或者 NVIDIA NVENC),能大幅降低 CPU 占用。实际部署时,需要确认你的 ffmpeg 编译版本支持对应的硬件加速库。

5.2 密码里的特殊字符把取流地址干废了

第二个坑来自密码中的特殊字符。

我有一台摄像头的密码是 Pass@123 ,它在摄像头后台里工作正常,但当我把它写进 go2rtc.yaml 时:

streams:
  camera_1:
    - rtsp://admin:Pass@123@192.168.1.64:554/Streaming/Channels/101

结果发现 go2rtc 一直报认证失败。原因很好理解——URL 解析器把第一个 @ 后面的内容当成了主机地址,实际解析到的主机是 123@192.168.1.64 ,这自然连不上。

解决办法是进行 URL 编码。在 RTSP 串里,以下字符需要特别注意:

字符 URL 编码
@ %40
: %3A
/ %2F
# %23
? %3F
& %26

所以正确的写法是:

streams:
  camera_1:
    - rtsp://admin:Pass%40123@192.168.1.64:554/Streaming/Channels/101

更省心的做法是:给摄像头单独建一个"仅供流媒体访问"的低权限账号,密码里只包含字母和数字,避免一切转义烦恼。我在管理海康设备时,会在用户管理里新建一个 stream 用户,密码设成 stream2024 ,把取流权限给它就够了,这样即使 go2rtc 配置泄露,也不至于让攻击者拿到摄像头的管理员权限。

5.3 Docker 网络模式选错,连不上摄像头

我在文章开头提到过桥接模式和 host 模式的差异。这里再补充一个典型的"选错网络模式"的排查案例。

有一次我把 go2rtc 部署在一台跑着很多容器的服务器上,为了方便端口管理,用了默认的 bridge 模式。之后访问 go2rtc 的 Web UI 正常,但添加摄像头之后一直拉流失败,报错是 "connect timeout"。

排查到最后发现,那台服务器上还有其他容器占用了大量内网 IP,Docker 的 bridge 网关与局域网段之间存在路由冲突,导致容器内发出的到摄像头 IP 的数据包被错误地路由到了 Docker 虚拟网卡上,而不是走宿主机局域网网卡。

这种情况排查起来很隐蔽,因为你在宿主机上用 ping 、 curl 都正常,但容器里就是连不通。我的建议是:

  • 如果 go2rtc 只是单一服务,直接上 host 网络模式,省去端口映射和 NAT 的问题。
  • 如果你必须在 bridge 模式下跑,注意看 Docker 的 bip (bridge IP 网段)配置,尽量选一个偏离内网网段的子网,比如 Docker 默认的 172.17.0.0/16 和家里的 192.168.1.0/24 不会冲突,但如果你改过 Docker 网段,就要小心了。

5.4 画面卡顿:子码流和主码流的实战取舍

还有一个很常见的卡顿问题,和网络带宽关系不大,纯粹是选择错误。

我最初把所有摄像头都配置成主码流接入,结果在 Web UI 里同时看四路画面时,画面会周期性卡顿。一开始我以为是 CPU 不够,后来用 docker stats 一看,go2rtc 的 CPU 占用不到 15%,内存也正常。

后来查了 cam 的实时码率才发现:四路 1080p 主码流的码率加起来接近 15 Mbps,而我的无线链路实际稳定吞吐只有 10 Mbps 左右。问题出在无线 AP 上。

解决方式很简单:把多画面预览的流从主码流切换到子码流。1080p 主码流改成 720p 子码流之后,四路总码率降到 3 Mbps 左右,画面立刻流畅了。

最终我的配置模式是:

  • Web UI 默认使用子码流,保证多路预览不卡。
  • 需要看细节的时候,在 UI 里手动切换到主码流入口。

6. 更进一步:Home Assistant 集成、推流分发与资源控制

6.1 和 Home Assistant 的无缝对接

如果你用 Home Assistant(以下简称 HA),go2rtc 的价值会翻倍。

go2rtc 的作者 AlexxIT 本身就是 HA 的知名集成作者,二者兼容性做得非常好。在 HA 里通过侧边栏添加 go2rtc 集成,填入 go2rtc 的 IP 和端口,HA 就能直接发现 go2rtc 里配置的所有摄像头流。

之后你可以把 go2rtc 里的流当成普通 camera 实体用:

camera:
  - platform: generic
    name: LivingRoom
    still_image_url: http://192.168.1.10:1984/api/frame?src=hik_living_sub
    stream_source: http://192.168.1.10:1984/api/stream?src=hik_living_sub

这样 HA 的仪表盘里就能实时显示摄像头画面,而且延迟非常低。配合 HA 的自动化,可以实现有人移动时把对应摄像头的画面推送到电视或手机上。

go2rtc 作为 HA 官方推荐的 stream 替代组件,一个重要原因是它天然支持 WebRTC,HA 自带的 stream 组件在某些平台上无法低延迟播放 H.265 流,而 go2rtc 可以在中间做协议转换和转封装。

6.2 把 go2rtc 的流推送到第三方平台

go2rtc 不仅能"拉",还能"推"。比如你希望把某一路摄像头的画面推送到云端直播平台,只需要在流配置后面追加一个 RTMP 推流地址:

streams:
  camera_hik:
    - rtsp://admin:password@192.168.1.64:554/Streaming/Channels/101
    - rtmp://your-rtmp-server.com/live/cam1

go2rtc 会一边从摄像头拉流,一边把同一路流转推到 RTMP 服务器。这个功能在做"公共场所视频监控分享"或者"跨区域视频汇聚"时非常实用。

需要注意的是,推流到外网平台时,你的上行带宽是瓶颈。1080p 主码流推流至少需要 4 Mbps 上行,如果带宽不够,还是推子码流吧。

6.3 资源占用与长期运行观察

最后说一下很多人关心的资源占用问题。

go2rtc 本身非常轻量。在我的测试机上(一台 N5105 软路由),同时跑 4 路 1080p 子码流和 2 路主码流,不做转码时,go2rtc 的 CPU 占用率稳定在 5% 到 10%,内存占用约 120 MB。这个负载对大多数软路由和小主机来说毫无压力。

如果启用了 H.265 转 H.264 的转码,CPU 占用会显著上升,具体取决于分辨率和帧率。在我的 N5105 上,单路 1080p 的 H.265 转 H.264 大约要吃 30% 左右的 CPU,如果你有 4 路以上的转码需求,建议考虑带 Intel Quick Sync 的 CPU,或者干脆在摄像头端把编码格式改成 H.264。

长期运行方面,我用 go2rtc 连续跑了三个多月,容器内存有缓慢增长的趋势,但没有出现明显的泄漏或者崩溃。Docker 自带的内存限制选项可以加上一层保护:

services:
  go2rtc:
    image: alexxit/go2rtc:latest
    mem_limit: 512m
    restart: unless-stopped

如果容器因为内存超限被杀掉,Docker 会自动重启,保证服务可用性。

6.4 我现在的完整配置模板

分享一个我现在还在用的完整配置模板,供大家参考:

log:
  level: info

streams:
  hik_living_main:
    - rtsp://stream:stream2024@192.168.1.64:554/Streaming/Channels/101
  hik_living_sub:
    - rtsp://stream:stream2024@192.168.1.64:554/Streaming/Channels/102
  dahua_yard_main:
    - rtsp://stream:stream2024@192.168.1.65:554/cam/realmonitor?channel=1&subtype=0
  unv_gate_sub:
    - rtsp://stream:stream2024@192.168.1.66:554/unicast/c1/s1/live

  all_cameras:
    - hik_living_sub
    - dahua_yard_main
    - unv_gate_sub

最后这个 all_cameras 很有意思,它不是一个实际的摄像头,而是把多路流组合成一个新的流,在 Web UI 里点开它,go2rtc 会自动以多画面模式呈现所有子流。这样一个入口就能集中展示所有画面,比我手动逐个添加方便多了。

如果你也想搭建一套统一的多品牌摄像头监控系统,go2rtc 绝对值得你花一个下午试试。我个人实际用下来的体会是:它把"接入摄像头"这个原本繁琐的过程压缩到了"写几行 YAML",而且 Web UI 自带的排错信息也相当直观,真的推荐自己上手跑一遍,比看我文章有用得多。

Logo

邀请您加入社区

更多推荐