恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Moonfire NVR 实战:Rust 自建 RTSP 录像系统与 SQLite 索引
首页
资讯中心
/
Moonfire NVR 实战:Rust 自建 RTSP 录像系统与 SQLite 索引
Moonfire NVR 实战:Rust 自建 RTSP 录像系统与 SQLite 索引
发布时间:2026/10/15 15:51:23
简介Moonfire NVR 是一套面向安防监控场景的开源网络视频录像机方案适合具备一定 Rust 与后端基础、希望自建 IP 摄像机存储系统的开发者与运维人员。它把来自 IP 摄像机的 H.264-over-RTSP 流直接落盘视频帧以旋转目录形式保存其余元数据存入 SQLite3并能按任意时间范围动态拼装出 .mp4 文件由于不做解码、分析与重编码CPU 占用极低可在普通机器上同时处理六路 1080p/30fps 流。资源包共 116 个文件约 5.22MB以 48 个 rs 源码、24 个 js 前端脚本、11 个 md 文档为主另含 sql 建表脚本、toml/json 配置、Dockerfile 与 docker 相关文件、proto 定义及少量 png、css、html 等静态资源覆盖服务端、Web 界面与容器化部署的完整结构。目前已有 1409 人学习下载读者可借此理解 NVR 的存储设计、时间范围检索与前端片段列表实现并作为二次开发或私有化部署的起点。1. Moonfire NVR 到底解决什么问题从一台家用摄像机的录像焦虑说起很多人第一次接触 Moonfire NVR是因为家里或小型办公场所装了几路网络摄像机厂商自带的云存储要么按月收费要么画质被压缩得看不清车牌本地 NVR 盒子又是个封闭黑匣子硬盘满了不会告诉你想导出某一段录像得在菜单里点十几层。Moonfire NVR 就是冲着这个场景来的它是一个用 Rust 写的网络视频录像机把 RTSP 摄像机的视频流拉下来切成一段段可检索的录像存到本地磁盘再通过一个轻量 Web 界面回放和导出。它不依赖任何云服务录像文件就是普通的 MP4 分片加一个 SQLite 索引库你随时能拿ffmpeg或文件管理器直接翻。适合谁适合愿意自己维护一台常开小主机迷你主机、旧笔记本、NAS 都行、有几路到十几路摄像机、对隐私和长期存储成本敏感的人。它不追求企业级集群和花哨 AI 分析核心就三件事稳定拉流、可靠落盘、快速回放。把这三件事做扎实比堆功能更值钱。2. 拆开 Moonfire NVR 的录像链路从 RTSP 拉流到 SQLite 索引2.1 为什么选 Rust SQLite 分片 MP4 这套组合先讲选型理由不然你照着装完也不知道它为什么这么设计。Moonfire NVR 用 Rust 写核心动机是长时间运行的稳定性——录像服务一跑就是几个月C 里一个野指针或内存泄漏就能让进程半夜挂掉Rust 的所有权模型在编译期挡掉大部分这类问题。存储层选 SQLite 而不是 PostgreSQL是因为单机场景下 SQLite 的零配置、单文件、崩溃恢复能力足够好索引库就一个.db文件备份直接拷走。录像格式选分片 MP4 而不是一个大文件是为了避免「录到一半断电整个文件损坏」的经典翻车每段录像独立成文件默认按时间或大小切分坏一段只丢一段。这三者组合起来形成一条「拉流 → 编码封装 → 落盘 → 建索引」的流水线每一环都可单独排查。2.2 最小可跑通的部署步骤与命令下面这套流程是我在 Debian/Ubuntu 系小主机上反复用过的先装依赖再编译最后初始化数据库。注意 Moonfire NVR 需要 Rust 工具链和 FFmpeg 的开发库缺一个都会在编译阶段报错。# 1. 安装系统依赖FFmpeg 开发库、SQLite、构建工具 sudo apt update sudo apt install -y build-essential pkg-config libavcodec-dev libavformat-dev \ libavutil-dev libavfilter-dev libavdevice-dev libswscale-dev libswresample-dev \ libsqlite3-dev libssl-dev # 2. 安装 Rust 工具链如果已有可跳过 curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh source $HOME/.cargo/env # 3. 获取源码并编译 release 版本 git clone https://github.com/scottlamb/moonfire-nvr.git cd moonfire-nvr cargo build --release # 4. 初始化配置目录与数据库 mkdir -p ~/moonfire/config ~/moonfire/db ~/moonfire/recordings ./target/release/moonfire-nvr init --db-dir ~/moonfire/db逻辑说明前三步是环境准备libav*-dev这一串是 FFmpeg 各模块的开发头文件Moonfire NVR 靠它们做解封装和转封装cargo build --release编译出优化后的二进制debug 版本跑录像会明显吃 CPU。第四步init会在指定目录生成空的 SQLite 数据库和默认配置骨架。参数说明--db-dir指向索引库所在目录建议和录像文件目录分开放在不同磁盘或分区避免索引写入和录像写入互相抢 IO。编译时间在四核小主机上大约几分钟到十几分钟取决于机器性能。2.3 配置摄像机与录像参数的关键字段初始化完成后配置文件里最需要你动手的是摄像机来源和录像保留策略。常见做法是在配置中为每路摄像机指定 RTSP 地址、传输协议和期望的流类型。下面是一段配置片段字段名以实际版本为准这里展示结构和含义。# 摄像机定义每路一个 [[cameras]] 块 [[cameras]] name front-door # 逻辑名称回放界面显示用 streams [ { url rtsp://user:pass192.168.1.10:554/stream1, proto tcp } ] # 录像保留策略按天数和磁盘占用双重限制 [retention] max_age_days 30 # 超过 30 天的录像自动清理 max_used_percent 85 # 磁盘占用超过 85% 开始删最旧的逻辑说明proto tcp是血泪经验UDP 在丢包网络下容易出现花屏和花帧TCP 虽然延迟略高但录像完整性更好。max_age_days和max_used_percent两个条件谁先触发谁生效双保险防止磁盘被写满导致服务崩溃。参数说明RTSP 地址里的stream1通常是主码流清晰度高但码率大如果小主机性能吃紧可以改用子码流地址降低解码压力。改完配置后需要重启服务或触发重载具体命令看你的部署方式。3. 把录像存明白磁盘规划、保留策略与回放导出3.1 磁盘怎么分区才不容易翻车录像服务最怕的不是软件崩是磁盘写满。我的习惯是把系统盘和录像盘彻底分开系统盘放数据库和配置录像盘单独一块大容量机械盘或 SSD。原因很简单录像写入是持续的顺序写数据库是随机小写混在一起会互相拖慢。如果只有一块盘至少给录像目录单独挂一个分区并开启文件系统的保留空间。另外机械盘做录像存储性价比高但要注意它的持续写入速度——单路 1080p 主码流大约 2~4 Mbps十路就是 20~40 Mbps普通机械盘完全扛得住瓶颈往往在网络和 CPU 解码上不在磁盘。3.2 保留策略的参数怎么调保留策略直接决定你能回看多久。max_age_days设太小出了事想查一周前的录像发现已经被删设太大磁盘很快满。我的经验是先算一笔账单路 1080p 按 3 Mbps 估算一天约 32 GB十路一天约 320 GB一块 4 TB 盘大约能存 12 天。所以如果你要保留 30 天要么加盘要么降码率或只录运动触发。max_used_percent建议留 10%~15% 余量不要设到 95%因为文件系统本身需要空间写满会导致服务异常。这两个参数配合使用比只设一个更稳。3.3 回放与导出的实际操作回放走 Web 界面浏览器打开服务监听地址即可按时间轴拖动定位。导出某段录像时界面会调用后端把对应分片合并成一个可下载文件。如果你不想走界面也可以直接去录像目录按时间戳找分片文件用 FFmpeg 合并# 把某段时间的多个 MP4 分片合并成一个文件 # 先生成文件列表注意路径按实际录像目录替换 ls ~/moonfire/recordings/front-door/2024/06/01/*.mp4 | sort /tmp/list.txt # 用 concat 协议无损合并 ffmpeg -f concat -safe 0 -i /tmp/list.txt -c copy /tmp/export.mp4逻辑说明-c copy表示不重新编码直接复制流速度快且无损-safe 0允许列表里出现绝对路径。参数说明分片文件按时间排序很重要sort保证顺序正确否则合并出来时间轴会乱。如果分片之间编码参数不一致-c copy可能失败这时才需要重新编码但会慢很多。4. 避坑与排查Moonfire NVR 部署中最容易踩的五个坑4.1 坑一编译时报 FFmpeg 库找不到现象cargo build过程中报libavcodec not found或链接错误。原因系统只装了 FFmpeg 可执行程序没装开发库或者pkg-config找不到.pc文件。解决确认装了libav*-dev系列包用pkg-config --libs libavcodec测试能否输出链接参数如果自定义路径安装了 FFmpeg需要设置PKG_CONFIG_PATH指向对应的pkgconfig目录。4.2 坑二摄像机连不上或频繁断流现象日志里反复出现 RTSP 连接超时或 401 未授权。原因地址、端口、用户名密码错误或者摄像机限制了并发连接数。解决先用ffplay或ffprobe单独测试 RTSP 地址能否拉流排除摄像机侧问题确认协议用 TCP检查摄像机是否达到最大连接数有些设备默认只允许一两个客户端。4.3 坑三录像有画面但时间戳错乱现象回放时时间轴跳跃或者录像时长和实际不符。原因摄像机时间未同步或者分片切分参数与关键帧间隔不匹配。解决给摄像机和录像主机都配置 NTP 时间同步检查摄像机的关键帧间隔GOP建议设为帧率的 1~2 倍太长会导致分片切分点找不到关键帧。4.4 坑四磁盘写满导致服务停止现象服务突然不录像日志报磁盘空间不足。原因保留策略没生效或设置过松。解决检查max_used_percent是否设置确认清理任务在运行临时手动删除最旧的分片目录释放空间再调整策略。后悔药是提前监控磁盘用简单的定时脚本在占用超阈值时告警。4.5 坑五Web 界面能打开但看不到录像现象界面正常时间轴上没有录像段。原因数据库索引和实际录像文件不一致常见于手动删过文件或迁移过目录。解决不要手动删录像文件要走服务提供的清理机制如果已经不一致需要重建索引或按文档做数据库修复操作前先备份.db文件。5. 进阶技巧用脚本做健康检查与录像完整性验证部署稳定之后真正让你省心的是自动化检查。我一般会写一个定时脚本做三件事检查服务进程是否存活、检查最近是否有新录像写入、检查磁盘余量。下面是一个 bash 示例配合 cron 每小时跑一次。#!/usr/bin/env bash # moonfire_check.sh - 每小时健康检查 set -euo pipefail REC_DIR$HOME/moonfire/recordings DB_DIR$HOME/moonfire/db ALERT_LOG$HOME/moonfire/alert.log # 1. 检查进程 if ! pgrep -f moonfire-nvr run /dev/null; then echo $(date) CRITICAL: moonfire-nvr 进程不存在 $ALERT_LOG fi # 2. 检查最近 10 分钟内是否有新录像文件 RECENT$(find $REC_DIR -name *.mp4 -mmin -10 | wc -l) if [ $RECENT -eq 0 ]; then echo $(date) WARN: 最近 10 分钟无新录像 $ALERT_LOG fi # 3. 检查磁盘余量低于 15% 告警 USED$(df --outputpcent $REC_DIR | tail -1 | tr -d %) if [ $USED -gt 85 ]; then echo $(date) WARN: 录像盘占用 ${USED}% $ALERT_LOG fi逻辑说明第一段用pgrep判断进程进程没了说明服务挂了第二段用find -mmin -10统计最近十分钟内修改过的 MP4 文件数量为零说明拉流或写入出了问题第三段用df取占用百分比超过 85% 告警。参数说明-mmin -10的时间窗口按你的分片时长调整如果分片是 5 分钟一段窗口设 10 分钟比较合理。这个脚本不负责自动重启只负责记录因为盲目重启可能掩盖根因。验证录像完整性还有一个技巧定期随机抽一个分片用ffprobe检查能否正常解析能解析说明文件没损坏。# 随机抽一个分片做完整性检查 SAMPLE$(find ~/moonfire/recordings -name *.mp4 | shuf -n 1) ffprobe -v error -show_entries formatduration -of defaultnw1 $SAMPLE如果ffprobe报错或时长异常说明这个分片可能损坏需要检查磁盘健康或写入过程是否被中断。我自己踩过的最大坑就是早期没做磁盘监控盘满了服务静默停止等发现时已经丢了两天录像。从那以后健康检查脚本成了标配宁可多一条告警日志也不要事后拍大腿。希望帮到你。本文还有配套的精品资源点击获取