旧电脑也能跑NetSurveillance DVR:开源自建监控录像系统指南
简介面向Windows平台IE浏览器的NetSurveillance DVR插件是一套通过网络远程访问监控设备的轻量级解决方案主要针对安防工程人员、运维人员和二次开发者。资源包共61个文件、约1.07MB核心构成包括ActiveX控件、H.264解码播放库、多语言语言包、界面皮肤图片及设备配置文件dll文件承担解码与通信ocx控件提供浏览器交互接口lang资源支持多语言界面切换jpg/bmp负责按钮与面板皮肤ini/xml保存设备、回放和云台等参数整体结构清晰便于按需调用。插件内置PTZ云台控制、通道切换、回放面板与安装脚本可快速部署到IE环境并接入监控网络也方便开发者在自有系统中集成摄像头预览与控制能力。压缩包内按控件、语言、皮肤、配置等类别组织文件便于对照学习或进行模块级替换。目前已有1051人学习下载适合需要理解DVR插件组成、进行界面汉化或二次开发的工程师参考。1. 一台旧电脑就能跑的 NetSurveillance DVR从录像盒子到开源自建店里装了 8 个摄像头买台品牌 DVR 要两千多云存储年费又是大几百画质还被平台二次压缩。NetSurveillance 字面上是网络视频监控配上 DVRDigital Video Recorder这个载体就是一套能接入 IP Camera、能本地存储、能 Web 回放、能按事件检索的录像系统。我自己给仓库做了一套核心只花了一个旧电脑加一块 4TB 硬盘的成本。这套方案适合小店主、仓库管理、弱电集成工程师以及任何被商用录像机授权费和私有协议绑住的人。2. 搭建最小可用系统硬件底线与一套 Docker Compose先说结论别为了省 500 块钱去买二手工控机专用主板也不建议在树莓派上硬扛 4 路 1080p 录像。按我踩过的坑一套稳定的 NetSurveillance DVR 硬件选型有明确底线同时软件栈选型直接决定你未来三个月是在装环境还是在看录像。2.1 硬件底线 CPU、内存、硬盘与网卡的取舍NetSurveillance DVR 的核心负载是两件事把 RTSP 视频流解码出来再把解码后的画面按帧交给检测器或编码器。4 路 1080p 同时做检测和录像CPU 占用大头在 FFmpeg 的解码和重编码上。我的实际经验是CPU 用 i3-4130 以上内存 8GB 起系统盘单独上一块 64GB SSD录像盘用 4TB 紫盘或企业盘。Intel 核显的 Quick SyncQSV硬件转码能把 CPU 占用压到软解的 1/3 左右所以选 CPU 时优先看核心显卡型号而不是只看主频。硬盘是整个 DVR 里最不能省的部分。7x24 小时连续写入普通家用盘跑两三个月就开始冒坏道。监控紫盘WD Purple / 希捷 SkyHawk至少能撑三年以上。还有人问我能不能把录像存在 NAS 上可以但你要额外处理 NFS/SMB 的并发性能和断线重连问题——刚上手不要碰。我一般把录像目录直接挂载到本机物理盘系统盘和录像盘分开Docker 数据也放系统盘。这样系统崩了录像还在。网络上千兆交换机是底线并且一定要确认网线协商到了千兆。等到了第 5 章你会看到我至少有一半的卡顿排查是在看 ethtool 协商速率。2.2 软件栈选型为什么选 Frigate 而不是 ZoneMinder老牌开源监控方案 ZoneMinder 功能全但它的录像文件管理非常笨重Web 界面停留在上一个时代。新项目我基本不推荐。Frigate 是更现代的 NetSurveillance 后端录像直接分段写 MP4Web 回放流畅自带基于 OpenVINO / Coral TPU 的 AI 目标检测而且整个项目 Docker 化升级和回滚都很干净。对比项ZoneMinderFrigate录像管理按事件存片文件多且碎按时间分段 MP4循环覆盖策略清晰AI 检测运动检测为主误报多支持 OpenVINO/Coral可识别行人车辆界面体验老式 Web 控制台功能多但难看现代 Web UI支持时间轴拖拽回放维护成本依赖多PHP/MySQL迁移费劲Docker 单容器配置是 YAML硬件加速配置繁琐预设了 Intel QSV / VAAPI 加速参数Frigate 的定位是 NVRNetwork Video Recorder但现在的安防场景里 DVR 和 NVR 边界已经模糊输入源是网络摄像头输出是本地硬盘录像。所以我说的 NetSurveillance DVR指的就是这一套基于开源 NVR 的完整录像系统。Frigate 对摄像头的要求是有 RTSP 主码流和子码流后面接入摄像头的时候我会细讲。2.3 用 Docker Compose 一步拉起 DVR 服务我习惯把整个 DVR 服务放在/opt/frigate目录下用 Docker Compose 管理。下面的docker-compose.yml是我在 Intel 核显平台上稳定跑了一年多的版本services: frigate: image: ghcr.io/blakeblackshear/frigate:stable container_name: frigate restart: unless-stopped privileged: true devices: - /dev/dri/renderD128:/dev/dri/renderD128 volumes: - /etc/localtime:/etc/localtime:ro - /opt/frigate/config:/config - /media/recordings:/media/frigate ports: - 8971:8971 # Web 管理界面 - 8554:8554 # 内置 RTSP 服务供客户端拉流 - 8555:8555 # WebRTC 实时预览 environment: - FRIGATE_RTSP_PASSWORDcustom_password - LIBVA_DRIVER_NAMEiHD启动命令很简单在/opt/frigate目录下执行sudo docker compose up -d然后等 30 秒左右浏览器打开http://DVR主机IP:8971就能看到登录页。几个关键点/dev/dri/renderD128映射是让容器访问 Intel 核显的 VAAPI 能力LIBVA_DRIVER_NAMEiHD指定 Intel 核显驱动privileged: true是为了让容器能读取摄像头时间戳和系统时钟Frigate 官方文档也建议这样但注意这台机器不要放公网。没有 Intel 核显的机器可以删掉devices和LIBVA_DRIVER_NAME两行系统会退回到 CPU 软解4 路 1080p 也能跑就是 CPU 占用会到 80% 以上。启动后先别急着接摄像头直接看日志验证服务是否正常cd /opt/frigate sudo docker compose logs -f --tail 50能刷出Starting Frigate和Camera start up相关日志就说明服务起来了。这一步走通后面的摄像头接入只是在 YAML 里加几行的问题。3. 三个必调参数编码、存储与录像计划很多 NetSurveillance 新手翻车不是摄像头没接对而是参数没有概念地乱填分辨率拉满、码率选最大、录像保留 30 天结果硬盘三天就满回放时画面全是马赛克。这一章我给出一套可以直接抄的参数设定以及背后的计算逻辑。3.1 编码参数H.264 还是 H.265码率控制与 GOP 怎么设摄像头端编码我几乎只用 H.264不用 H.265。说来话长H.265 确实省一半存储但在 FFmpeg 的开源解码链路里兼容性参差不齐而且 Web 回放时浏览器对 H.265 的硬件解码支持到现在都是玄学。为了录像稳定和回放不折腾H.264 是当前 NetSurveillance DVR 最不容易翻车的选择。码率控制一定要设CBR固定码率不要用 VBR。VBR 在大范围运动场景下码率会突然飙到设定值的 3-5 倍造成的直接影响就是网络瞬断、画面花屏。下面是我给摄像头设的基准参数主码流1080P15fpsH.264CBR 上限 4Mbps子码流720P5fpsH.264CBR 上限 1MbpsI 帧间隔GOP30即 2 倍帧率I 帧间隔这里容易被忽略。FFmpeg 在-ss快速定位录像时靠的是跳到最近的 I 帧再解码。GOP 越大定位越慢、越不准。30 这个值在存储压力和 seek 精度之间比较均衡。帧率 15fps 对监控足够但如果你的场景是车道或者体育场馆这类快速移动画面要提到 25fps否则画面拖影严重。3.2 存储容量算账一张 4TB 硬盘能录多久先记住一个换算公式单路每小时占用 码率Mbps÷ 8 × 3600 ÷ 1024GB。比如 4Mbps4 ÷ 8 0.5MB/s0.5 × 3600 1800MB/h约 1.76GB/h。一天 42.2GB4TB 硬盘实际可用约 3.6TB单路就能录 85 天。下面是常见码率的参考表单路码率每小时占用每天占用4TB 单路可录时长1.5 Mbps0.66 GB15.8 GB约 227 天2 Mbps0.86 GB20.6 GB约 174 天4 Mbps1.76 GB42.2 GB约 85 天8 Mbps3.52 GB84.5 GB约 42 天注意这是单路独占一块 4TB 盘的数字。实际场景是多路共享比如 4 路 × 4Mbps 168GB/天4TB 盘能录 21 天。如果要求录 30 天要么降低到 3Mbps要么加一块硬盘。这套计算方式在 Frigate 里还要考虑事件录像的额外占用。我的建议是连续录像用 4Mbps 主码流事件录像共享同一份主码流数据不需要重复计算。真正会多占存储的是检测分辨率也就是子码流1Mbps 一天才 10GB 左右可以忽略。3.3 录像计划连续录像与事件录像的组合打法Frigate 的录像策略用 YAML 配置核心是区分record连续录和events按事件录。我的配置长这样mqtt: enabled: false cameras: shop_entrance: ffmpeg: inputs: - path: rtsp://admin:password10.0.0.64:554/Streaming/Channels/102 roles: - detect - path: rtsp://admin:password10.0.0.64:554/Streaming/Channels/101 roles: - record detect: width: 640 height: 360 fps: 5 record: enabled: true retain: days: 7 events: pre_capture: 5 post_capture: 5 retain: default: 30 mode: motion逻辑说明第一个输入走子码流只承担检测任务640×360 的分辨率足够 AI 识别行人和车辆第二个输入走主码流负责录制高清画面。检测和录像用不同的流能把 CPU 占用降一半以上——这是 Frigate 里的标准做法。retain.days: 7表示普通录像保留 7 天events.retain.default: 30表示带事件标记的片段保留 30 天pre_capture: 5和post_capture: 5表示事件触发前后各多录 5 秒避免人刚好走出画面的尴尬。mode: motion这里有个隐蔽坑Frigate 会用检测结果把连续录像切出事件片段motion模式会把光线变化、飞虫、树叶晃动都算成事件长期运行会导致事件片段占满磁盘。我一般配合 AI 检测器后改成active_objects只保留真正有行人或车辆的片段事件存储能省一半以上。这个配置项在接完摄像头后可以随时调整不用重启容器Frigate 会自动热加载。4. 接入摄像头与客户端ONVIF 发现与 RTSP 拉流的落地细节摄像头接入是最容易劝退新手的一步不同品牌的 RTSP 路径格式不一样ONVIF 端口也五花八门。我的工作流是先用 ONVIF 的 WS-Discovery 协议自动发现设备拿到设备的服务地址再逐个验证 RTSP 拉流路径最后统一写进 Frigate 配置。4.1 局域网内用 WS-Discovery 脚本自动发现摄像头ONVIF 规范的设备都会监听 UDP 3702 端口响应多播探测请求。不需要装任何品牌工具一个 Python 脚本就能把网段里的摄像头挖出来import socket probe_msg ?xml version1.0 encodingUTF-8? e:Envelope xmlns:ehttp://www.w3.org/2003/05/soap-envelope xmlns:whttp://schemas.xmlsoap.org/ws/2004/08/addressing xmlns:dhttp://schemas.xmlsoap.org/ws/2005/04/discovery xmlns:dnhttp://www.onvif.org/ver10/network/wsdl e:Header w:MessageIDuuid:net-surveillance-dvr/w:MessageID w:Tourn:schemas-xmlsoap-org:ws:2005:04:discovery/w:To w:Actionhttp://schemas.xmlsoap.org/ws/2005/04/discovery/Probe/w:Action /e:Header e:Body d:Probe d:Typesdn:NetworkVideoTransmitter/d:Types /d:Probe /e:Body /e:Envelope sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind((, 3702)) sock.settimeout(10) sock.sendto(probe_msg.encode(), (239.255.255.250, 3702)) while True: try: data, addr sock.recvfrom(65535) print(f发现设备: {addr[0]}) # 这里可以进一步解析 XAddr 来获取 RTSP 地址 print(data.decode(utf-8, errorsignore)[:1500]) except socket.timeout: print(扫描结束) break这段脚本的核心是多播地址239.255.255.250:3702这是 ONVIF WS-Discovery 的标准地址。脚本跑完会把所有支持 ONVIF 的网络摄像头 IP 列出来。注意如果摄像头在别的网段脚本可能发现不了需要先确认本机和摄像头在同一局域网内。拿到 IP 后我一般会再用curl访问摄像头的 HTTP 配置端口确认品牌标识方便后面拼 RTSP 路径。这一步比盲目在网上搜索某个杂牌摄像头的路径靠谱得多。4.2 RTSP 拉流 URL 的常见格式与路径表不同品牌摄像头 RTSP 路径差异很大但主流厂牌的格式基本固定。下面是公开的标准路径格式可以直接套用品牌主码流 RTSP子码流 RTSP海康 Hikvisionrtsp://user:passip:554/Streaming/Channels/101rtsp://user:passip:554/Streaming/Channels/102大华 Dahuartsp://user:passip:554/cam/realmonitor?channel1subtype0rtsp://user:passip:554/cam/realmonitor?channel1subtype1宇视 Univiewrtsp://user:passip:554/unicast/c4s1/livertsp://user:passip:554/unicast/c5s1/liveTP-LINKrtsp://user:passip:554/stream1rtsp://user:passip:554/stream2密码里如果包含、:等特殊字符需要做 URL 编码比如admin:test123要写成admin:test%40123。不然 RTSP 解析会从最后一个开始分割直接导致认证失败。我在这上面翻过一次车花了一个小时排查日志才发现是密码里的没转义。验证路径是否正确不需要先写进 Frigate。用 FFmpeg 直接拉一帧看最直观ffprobe -rtsp_transport tcp -i rtsp://admin:pass10.0.0.64:554/Streaming/Channels/101 \ -show_streams -format json -loglevel error | head -50-rtsp_transport tcp是关键很多摄像头默认用 UDP 传输 RTSP但 UDP 在弱网环境丢包严重。强制 TCP 后网络抖动时的恢复速度快很多。如果 ffprobe 能输出 video stream 信息说明路径和认证都对。4.3 给 Frigate 添加摄像头从验证到写配置把验证过的 RTSP 路径填回/opt/frigate/config/config.ymlFrigate 会自动重载配置。我会在cameras下为每个摄像头建一个独立节点命名规则用位置方位方便后续检索事件cameras: shop_entrance: ffmpeg: inputs: - path: rtsp://admin:pass10.0.0.64:554/Streaming/Channels/102 roles: - detect - path: rtsp://admin:pass10.0.0.64:554/Streaming/Channels/101 roles: - record record: enabled: true保存后等 10 秒Frigate 会热加载配置。如果摄像头里的用户没有 ONVIF 权限Frigate 也能纯靠 RTSP 拉流只是没法通过 ONVIF 控制云台等功能。测试时发现画面出不来第一反应是看日志docker compose exec frigate cat /tmp/frigate.log | grep -i error | tail -20日志里的关键错误有三类401 Unauthorized是密码或认证方式不对Connection refused是端口不通Received any packet from the stream is less than expected是码流参数和检测设置不匹配解决方向是把detect的分辨率帧率调到和子码流一致。5. 避坑指南NetSurveillance DVR 最常见的 5 个翻车点跑运维时90% 的问题不是配置不会写而是设备和服务在特定环境下的小脾气。下面是 5 个我真实遇到过的故障按现象 → 原因 → 解决拆开写你在自己的 DVR 上大概率也会碰到。5.1 摄像头掉线但网络通并发连接数超限现象Frigate 日志出现Cannot connect to camera但ping 摄像头IP完全通Web 管理页面也能登录。重启摄像头后恢复过几小时又掉线。原因摄像头自带 RTSP 并发连接数上限多数家用摄像头默认只允许 4-8 路。如果你同时开着 VLC 预览、手机 App 观看再加 Frigate 的 detect 和 record 两路拉流连接数就爆了。摄像头会拒绝新连接但 Web 管理页面走 HTTP 是另一套逻辑所以网络通给了人错觉。解决把并发上限调高或者约束没必要的实时预览。我在摄像头管理页把 RTSP 最大连接数从 4 调到 16顺手把 VLC 偶尔开的预览关掉问题就消失了。如果你的摄像头不支持调整连接数那就只能减少拉流端Frigate 只开一路主码流做 record用子码流做 detect不要同时在多个页面看实时画面。5.2 画面卡顿与花屏VBR 码率失控现象平时画面正常傍晚或者人流量大的时候画面开始马赛克、卡顿影响持续几分钟后自行恢复。单独测一路时一切正常。原因摄像头设置为 VBR 码率控制时在大范围运动场景下比如卷帘门升起、多人进出码率会瞬间飙到设定值的 3-5 倍。如果交换机或网线质量不佳突发流量会直接导致丢包和花屏。解决把摄像头编码改成 CBR主码流上限锁死。同时要检查网线协商速率ethtool eth0 | grep Speed如果显示100Mb/s而不是1000Mb/s基本可以断定是网线或水晶头问题直接换线。这两个动作下去花屏基本会绝迹。5.3 录像文件损坏最后一段总是放不出现象回放时最后一个时间段的录像文件播放器报错或者画面卡在最后几秒无法继续。损坏的往往正好是断电停机那一段。原因MP4 的文件结构决定了它必须在文件末尾或通过moov) 记录完整的索引信息。FFmpeg 边录边写的分段 MP4 如果碰到断电、容器强制停止最后一段文件没有正常 finalize索引不完整自然就坏了。解决把 Fridge 的分段时长控制短一点我一般让录像文件按segment大小切单个文件在 20-30 秒左右。这样断电最多丢最后一段 30 秒录像风险可接受。已经损坏的文件用 FFmpeg 可以尝试修复ffmpeg -i corrupt.mp4 -c copy -movflags faststart repaired.mp4-c copy不做重编码速度快逻辑是把损坏文件的moov元数据重新整理到文件头部。修复后文件就能正常拖动时间轴了。注意这招对文件完全没写入索引比如 0 字节的情况无效那种只能放弃。5.4 时间轴错乱NTP 没同步带来的回放灾难现象录像回放的时间轴和实际时间对不上事件检索出来的片段时间戳差了几个小时甚至显示 1970 年。原因摄像头和 DVR 主机的系统时间不同步。摄像头自带 RTC 电池时间会越走越偏DVR 主机如果没配置 NTP也会漂移。Frigate 的事件时间戳依赖摄像头流里的时间源头错事件时间必然错。解决DVR 主机必须同步 NTP。Ubuntu 上直接sudo apt install chrony -y sudo systemctl enable --now chrony chronyc sources -v然后到每台摄像头管理页把 NTP 服务器填成 DVR 主机的 IP同步周期改成 1 小时。摄像头和主机都指向同一时间源时间轴就不会乱。我这里强调一句别依赖摄像头自动校时很多杂牌摄像头的 NTP 实现就是个空壳子。5.5 硬盘提前写满事件保留策略没生效现象设置了retain.days: 7但运行 3 天磁盘就满了事件文件占据了大量空间。原因Frigate 的事件保留策略mode: motion会把所有有像素变化的片段都算作事件。夜晚的灯光变化、雨滴打在镜头上、飞虫飞过都会被保留 30 天。我遇到过一套系统一天的正常录像只有 60GB但事件片段占了 120GB。解决把事件保留模式改成active_objectsrecord: events: retain: default: 30 mode: active_objects改完后 Frigate 只会把检测到行人、车辆等具体目标的片段作为事件保留。存量事件的话直接在 Web 界面的事件列表里全选删除即可不影响连续录像的历史记录。这个配置改完不需要重启Frigate 会热加载。不过要注意active_objects依赖检测器正常工作如果没接 AI 检测器事件可能被过滤得一个都不剩那就还是用motion吧。6. 进阶录像快速检索与断流自愈的两个实用技巧系统跑顺之后我的下一步习惯是把两个日常刚需打磨到顺手一是想找某段录像时不用对着时间轴一点一点拖二是服务或者摄像头掉线时能自动恢复。6.1 用 FFmpeg 在大录像文件中秒定位关键片段Frigate 的录像默认按时间分段但在大时间跨度上回放还是要靠拖动时间轴。如果我要快速截取某个事件前后 30 秒的画面比如今天下午 3 点 15 分有人进入仓库我直接用 FFmpeg 从事件 API 拿到时间戳然后定位导出ffmpeg -ss 15:15:00 -i /media/frigate/recordings/2025/06/17/15/15/00.mp4 \ -t 30 -c copy -an clip.mp4关键在-ss放在-i之前。FFmpeg 会基于关键帧快速 seek 到指定时间点再开始输出速度非常快。如果放在-i后面它会从头解码该文件的所有帧直到到达指定时间一个几小时的视频能等到你怀疑人生。-c copy表示只复制编码数据不重编码秒级完成。-an去掉音轨。这个命令同样适用于从任何品牌的 DVR 录像文件里截取片段是我平时最常用的后悔药。6.2 崩溃自动拉起一个 watchdog 脚本加 systemd 定时器Docker 的restart: unless-stopped只能处理守护进程崩溃但 Frigate 内部可能出现异常状态比如检测进程挂掉但容器还活着或者摄像头长时间拉流导致内存泄漏。我用一个 watchdog 脚本兜底每 5 分钟检查一次容器状态和录像目录增长不对就重启容器。#!/bin/bash # /usr/local/bin/frigate-watchdog.sh # 检查容器是否在运行不在就拉起检查录像目录是否在增长停滞则重启 CONTAINERfrigate RECORD_DIR/media/recordings if ! docker ps --format {{.Names}} | grep -q ^${CONTAINER}$; then cd /opt/frigate docker compose up -d exit 0 fi SIZE_BEFORE$(du -sb $RECORD_DIR 2/dev/null | cut -f1) sleep 60 SIZE_AFTER$(du -sb $RECORD_DIR 2/dev/null | cut -f1) if [ $SIZE_AFTER -le $SIZE_BEFORE ]; then docker restart $CONTAINER fi脚本逻辑分两段第一段判断容器是否存在没有就直接拉起第二段用 60 秒内录像目录的字节数变化判断服务是否在正常写录如果完全停止增长说明内部卡死重启容器。把脚本放进 crontab*/5 * * * * /usr/local/bin/frigate-watchdog.sh这套机制上线后我基本不用再担心半夜摄像头掉线导致的无人值守黑匣子状态。故障恢复不是靠人工盯而是靠自动兜底。我现在的习惯是任何新部署的 NetSurveillance DVR 站点开机第一件事就是把 NTP 校时、watchdog 脚本、事件保留策略这三样配置好。前 30 天把系统调到零干预后面才能睡安稳觉。希望这些落地的参数和坑能帮你少走我走过的那几圈弯路一台旧电脑加一块监控盘完全能把商用 DVR 该干的活稳稳接住。本文还有配套的精品资源点击获取