Moonfire NVR 实战:Rust 自建 RTSP 录像系统与避坑指南
简介Moonfire NVR 是一款开源的安全摄像机网络视频录像机面向需要自建监控存储方案的开发者与运维人员。它把 IP 摄像机输出的 H.264-over-RTSP 流直接落盘视频帧以旋转目录形式保存其余元数据存入 SQLite3并能按任意时间范围动态生成 .mp4 文件由于不做解码、分析与重编码CPU 占用极低可在普通机器上同时处理六路 1080p/30fps 流。资源包共 116 个文件约 5.22MB以 48 个 Rust 源码文件为核心配合 24 个 JavaScript 前端脚本、11 个 Markdown 文档、5 个 SQL 建表脚本以及 Dockerfile、TOML 配置、proto 定义与示例视频等覆盖后端、前端、数据库与容器化部署。目前已有 1409 人学习下载。借助这套代码读者可理解 NVR 的存储分层设计、RTSP 接入流程与 Web 片段检索实现并据此搭建或二次开发自己的录像系统。1. 从一台总是掉线的摄像头说起Moonfire NVR 到底解决什么问题手里有几台 RTSP 网络摄像机的人大概率都经历过这种场景厂商自带的客户端只能在一台手机上看换台电脑就得重新装一遍想存 7×24 小时录像要么买厂商的云存储按月付费要么忍受 NAS 上那套笨重的套件。更麻烦的是一旦摄像头数量上去码流、磁盘、时间轴回放这三件事就开始互相打架。Moonfire NVR 就是冲着这个痛点来的——它是一个用 Rust 写的网络视频录像机核心职责很纯粹把 RTSP 摄像机的流拉进来切成一段段可检索的录像落到本地磁盘再通过一个轻量 Web 界面回放和导出。它适合谁适合手里有 IP 摄像头、想自己掌控录像数据、又不想被厂商生态绑死的从业者。Rust 技术栈意味着它在长时间运行下的内存占用和稳定性有先天优势不像某些脚本拼起来的方案跑几天就内存泄漏。前端是 JavaScript浏览器直接看不需要装插件。这篇笔记按「它是什么 → 怎么装怎么配 → 坑在哪 → 怎么用得更顺」的顺序拆一遍新手能照着复现熟手能直接看参数边界。2. 拆开 Moonfire NVR 的架构Rust 后端、RTSP 拉流与分段存储2.1 为什么是 Rust 分段录像这套组合先讲清楚它的工作模型不然后面配参数全是玄学。Moonfire NVR 的进程模型很简单一个常驻的 Rust 二进制内部维护若干「流stream」每个流对应一路摄像机的 RTSP 地址。它不像传统 NVR 那样把视频拼成一个大文件而是按时间切成固定时长的「录像段recording」每段独立成文件同时在 SQLite 里记一条元数据起始时间、时长、文件路径、码流参数。这种设计的好处是回放和清理都变成数据库查询。你要看某个时间点的录像先查 SQLite 找到覆盖该时间点的段再定位文件要删旧录像按时间条件删记录和文件即可不用去动一个大文件。代价是文件数量会很多磁盘的 inode 和目录遍历性能要留意后面避坑章节会讲。Rust 在这里的价值主要是两点一是内存安全长时间跑不会因为缓冲区越界崩掉二是它用了一套基于 tokio 的异步 IO多路 RTSP 并发拉流时线程开销可控。前端 JavaScript 只负责渲染时间轴和播放真正的解码交给浏览器服务端基本只做转发和存储CPU 压力比想象中小。2.2 目录结构与关键文件装完之后你会看到一个典型的数据目录理解它才能排查问题。常见布局如下路径作用备注db/SQLite 数据库存流配置、录像段元数据db/db主数据库文件备份时优先拷这个sample/或录像根目录录像段文件按流和时间组织config.toml主配置定义流、端口、存储路径二进制本体moonfire-nvr用子命令操作配置里最核心的是[[streams]]段每一路摄像机一个块。下面是一个最小可用的配置骨架字段名按常见版本习惯写具体以你拿到的版本为准# 全局设置Web 监听端口和数据库位置 bind_addresses [0.0.0.0:8080] db_dir /var/lib/moonfire-nvr/db # 每一路摄像机一个 [[streams]] [[streams]] id 1 # RTSP 地址用户名密码按实际填 url rtsp://user:pass192.168.1.10:554/stream1 # 录像保留天数超期自动清理 retain_days 14 # 单段录像时长秒太短文件多太长回放粒度粗 sample_file_duration 300逻辑说明bind_addresses决定 Web 界面从哪访问db_dir是数据库落盘位置retain_days是自动清理策略sample_file_duration控制分段粒度。参数上sample_file_duration我一般设 300 秒也就是 5 分钟一段——设成 60 秒会让文件数暴涨设成 3600 秒则回放时定位精度差拖动时间轴要等整段加载。2.3 初始化数据库与首次启动配置写完不能直接跑得先初始化数据库否则进程会因为找不到表结构退出。常见做法是分两步# 第一步初始化数据库创建表结构 moonfire-nvr init --db-dir /var/lib/moonfire-nvr/db # 第二步前台启动方便看日志 moonfire-nvr run --db-dir /var/lib/moonfire-nvr/db --config /etc/moonfire-nvr/config.toml逻辑说明init只做一次重复执行一般会报错或跳过run是常驻进程。第一次启动时重点看日志里有没有connected或stream started之类的字样如果某路流一直重连八成是 RTSP 地址或鉴权有问题。参数上--db-dir必须和配置里的db_dir一致否则会出现「配置读到了但数据库是空的」这种翻车现场。启动成功后浏览器打开http://主机IP:8080应该能看到时间轴界面。如果页面能开但时间轴空白说明 Web 服务正常、拉流没成功问题在 RTSP 那一侧不在前端。3. 把 RTSP 摄像机接进来地址、鉴权与码流选择3.1 RTSP 地址的构成与常见写法RTSP 地址是接入的第一道坎。标准格式是rtsp://用户名:密码IP:端口/路径但不同厂商的路径差异很大这是最容易踩坑的地方。常见几类路径写法主码流/stream1、/h264/ch1/main/av_stream、/cam/realmonitor?channel1subtype0子码流/stream2、/h264/ch1/sub/av_stream、/cam/realmonitor?channel1subtype1主码流清晰但码率高子码流省带宽但糊。Moonfire NVR 本身不做转码拉什么存什么所以选哪路直接决定磁盘消耗。我的习惯是录像存主码流如果带宽或磁盘吃紧再考虑子码流。3.2 用命令行先验证流能不能拉在把地址填进配置之前强烈建议先用工具验证一遍别让 NVR 去当小白鼠。常见做法是用 ffmpeg 或 ffprobe 探一下# 探测流信息不实际录像几秒后自动退出 ffprobe -rtsp_transport tcp -i rtsp://user:pass192.168.1.10:554/stream1 -show_streams # 实际拉 10 秒存成文件验证能否稳定解码 ffmpeg -rtsp_transport tcp -i rtsp://user:pass192.168.1.10:554/stream1 -t 10 -c copy test.mp4逻辑说明-rtsp_transport tcp强制走 TCP避免 UDP 丢包导致的画面花屏这是 IP 摄像头场景下的血泪经验。-show_streams会打印编码格式、分辨率、帧率确认是 H.264 还是 H.265——有些浏览器对 H.265 支持有限回放可能黑屏。-c copy表示不重新编码直接封装速度快。如果 ffprobe 都拉不到流Moonfire NVR 一定也拉不到先解决网络和鉴权别去改 NVR 配置。3.3 多路流与带宽估算接多路之前先算笔账。假设一路主码流 4 Mbps14 天保留单路每天4 Mbps ÷ 8 0.5 MB/s 0.5 MB/s × 86400 s ≈ 43 GB/天 14 天 ≈ 600 GB/路四路就是 2.4 TB 左右。这个数字决定了你磁盘要留多少余量。Moonfire NVR 不做智能编码码率是摄像机给的所以估算只能按摄像机标称值来。实际中运动画面多的场景码率会更高建议按标称值的 1.2 倍留余量。配置多路时每路一个[[streams]]块id不能重复。启动后如果某几路正常、某几路一直重连优先怀疑那几路的地址或该摄像机的并发连接数限制——有些摄像头同时只允许 12 个 RTSP 客户端你 NVR 占了一个手机 App 再连就挤掉了。4. 避坑与排查那些让录像悄悄断掉的问题4.1 时间轴有段但点开黑屏现象Web 界面时间轴上明明有录像段点进去播放却黑屏或一直转圈。原因多半是编码格式问题。摄像机用了 H.265而当前浏览器不支持或者录像段封装格式浏览器解不了。Moonfire NVR 服务端不转码浏览器拿到什么就解什么。解决把摄像机切到 H.264 主码流或者确认浏览器版本支持 H.265。用 ffprobe 看录像段文件的编码确认和预期一致。如果必须用 H.265回放时换支持它的浏览器或者接受导出后用本地播放器看。4.2 磁盘写满后录像静默停止现象某天发现最近几天的录像全没了进程还在跑日志也没明显报错。原因保留策略和磁盘容量没对上。retain_days设了 14 天但磁盘只够 7 天写满后新段写不进去旧段又没到清理时间就卡住了。有些版本在磁盘满时的日志级别不高容易被忽略。解决先按 3.3 的公式算实际容量把retain_days调到磁盘能承受的值留 15% 余量。同时监控磁盘使用率超过 85% 就告警。别指望 NVR 自己处理磁盘满这类工具普遍是「写不进去就停」不会帮你删。4.3 文件数暴涨拖慢回放现象跑了一段时间后时间轴加载变慢磁盘ls一个目录要好几秒。原因sample_file_duration设得太小比如 60 秒一天就是 1440 个文件一个月四万多个。文件系统在单目录文件数过多时性能下降明显。解决把sample_file_duration调到 300 秒甚至 600 秒减少文件数。已经产生的碎文件不用手动合并等保留期过了自动清理。如果目录已经很大清理时用按时间批量删别用通配符一次删几万个。4.4 RTSP 断流后不自动重连现象摄像头重启或网络抖动后那路流再也没恢复时间轴出现一段空白。原因部分版本的重连逻辑有退避策略如果摄像头短时间内反复断退避时间会拉长或者 TCP 连接处于半开状态进程以为还连着。解决先确认进程日志里有没有重连记录。如果长时间不恢复重启 NVR 进程是最直接的办法。长期方案是给摄像机配固定 IP、稳定的交换机端口减少物理层抖动。也可以写个外部脚本定期检查时间轴最新段的时间超过阈值就重启对应流。4.5 数据库和录像文件不同步现象手动删了录像文件但时间轴上还能看到那些段点开报 404。原因Moonfire NVR 的元数据在 SQLite 里文件系统是另一套。手动删文件绕过了数据库记录还在。解决永远通过 NVR 自己的清理机制删录像别手动rm。如果已经删了需要进数据库把对应记录清掉或者重建数据库会丢失所有元数据慎用。备份时数据库和录像文件要一起备只备一个没意义。5. 进阶用法用 SQLite 直接查录像元数据与自动化清理跑顺之后最有价值的进阶技巧是直接查它的 SQLite 数据库。Web 界面能做的事有限但数据库里什么都有写脚本做自动化清理、统计、告警都靠它。先看表结构常见的有stream、recording、sample_file几张表。查最近一小时有哪些录像段-- 查指定流在某个时间范围内的录像段 SELECT r.id, r.start_time_90k, -- 起始时间单位 90kHz r.duration_90k, -- 时长单位 90kHz sf.path -- 对应的文件路径 FROM recording r JOIN sample_file sf ON sf.recording_id r.id WHERE r.stream_id 1 AND r.start_time_90k (strftime(%s,now) - 3600) * 90000 ORDER BY r.start_time_90k DESC;逻辑说明Moonfire NVR 内部用 90kHz 时钟计数所以时间字段要乘 90000 换算成秒。strftime(%s,now)取当前 Unix 时间戳减 3600 秒就是最近一小时。这条查询能帮你确认某路流到底有没有在正常写录像——如果结果为空说明那路流断了。参数上stream_id对应配置里的id改这个值就能查不同摄像机。duration_90k除以 90000 就是这段录像的秒数可以用来统计实际录像覆盖率把一天所有段的时长加起来除以 86400就知道有没有漏录。基于这个查询可以写个巡检脚本每小时跑一次发现某路流最近 10 分钟没有新段就发告警。这比等用户发现录像没了要主动得多。我一般还会顺手统计磁盘增长速率反推retain_days设得合不合理。导出录像也是类似思路查到目标时间段的文件路径直接拷文件即可Moonfire NVR 的段文件本身就是可播放的封装格式不需要额外转码。导出后如果要合并成一个大文件用 ffmpeg 的 concat 协议按顺序拼就行。从那以后我每次接新摄像机都强制先用 ffprobe 验证流、再算磁盘容量、最后才填配置这三步少一步后面都要返工。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

AI 把维基百科搞宕机了:比「取代人类」更紧迫的问题来了

AI 把维基百科搞宕机了:比「取代人类」更紧迫的问题来了

每天5分钟,看懂AI,越看越明白,感谢关注🙏今天咱们聊聊👇 关注作者,查看更多干货 AI 把维基百科搞宕机了:比「取代人类」更紧迫的问题来了 先问你一个问题: 如果一个 AI 可以自己…

2026/10/16 18:32:11 阅读更多 →
Spring循环依赖原理:三级缓存如何保障AOP与线程安全

Spring循环依赖原理:三级缓存如何保障AOP与线程安全

1. 项目概述:这不是一道面试题,而是一次对Spring容器底层逻辑的“解剖手术”“深入源码分析Spring如何解决循环依赖”——看到这个标题,很多刚接触Spring的朋友第一反应是:“哦,又是八股文”,然后下意识点开…

2026/10/16 17:54:36 阅读更多 →
Enterprise Architect 授权机制解析与合规替代方案

Enterprise Architect 授权机制解析与合规替代方案

简介:这份资源面向软件架构师、系统分析师及UML建模学习者,提供EnterpriseArchitect的安装与使用支持,帮助解决UML2.1建模、代码工程双向转换、项目管理及数据库建模等实际需求。压缩包共5个文件,以msi安装程序为主,辅…

2026/10/15 15:38:38 阅读更多 →

最新新闻

初中物理虚拟实验教学资源包实用指南:仿真交互与课堂落地

初中物理虚拟实验教学资源包实用指南:仿真交互与课堂落地

简介:面向初中生的NB初中物理虚拟实验平台,是一套基于计算机仿真技术的互动教学资源,适合学生、教师及实验条件有限的学校使用。资源围绕力学、热学、光学、电学、声学、能量转换、简单机械等内容设计,通过模拟真实实验环境&#…

2026/10/16 20:32:59 阅读更多 →
Maya层编辑器实战:显示层/渲染层/批渲染脚本全攻略

Maya层编辑器实战:显示层/渲染层/批渲染脚本全攻略

如果你也靠Maya做场景类项目,层编辑器这个东西迟早得认真对待。我在一个做了大半年的城市场景Demo里吃过不少苦头:Outliner里的节点从几百长到两三千,角色、建筑、路灯、参考模型全部搅在一起;想临时隐藏一片屋顶,Ctrl…

2026/10/16 20:32:59 阅读更多 →
汉字笔顺动画教学系统:基于国标规范的交互式训练实践

汉字笔顺动画教学系统:基于国标规范的交互式训练实践

简介:Hanzi Writer 是一个基于 TypeScript 开发的开源汉字笔画顺序动画与练习测验 JavaScript 库,面向中文学习者、教育类应用开发者及前端技术实践者,解决汉字书写规范可视化与交互式训练缺失的问题,特别适配简繁体字教学场景。资…

2026/10/16 20:31:58 阅读更多 →
EAC抓轨实战:精确流、偏移校正与无损FLAC转换全解析

EAC抓轨实战:精确流、偏移校正与无损FLAC转换全解析

简介:EAC CD抓轨软件压缩包是一套面向音频发烧友、音乐收藏者及数字音频制作者的经典抓轨工具,专为解决CD音轨提取时易出现的读取错误、音质损耗等问题。软件采用安全抓轨机制,能最大限度保留原始声音,支持FLAC、WAV、AAC等多种编…

2026/10/16 20:31:58 阅读更多 →
蓝色立体三角形多边形PPT背景图:选图、排版与避坑指南

蓝色立体三角形多边形PPT背景图:选图、排版与避坑指南

简介:蓝色立体三角形多边形PPT背景图片zip包,定位于需要快速提升演示文稿视觉效果的PPT制作者。以三角形拼合形成的立体图形为主视觉,蓝色调契合科技、商业、创新等专业主题,能将幻灯片的平面感转为更具层次与深度的空间感&#x…

2026/10/16 20:31:58 阅读更多 →
Foxmail v7.0.1.92:安装配置、数据迁移与避坑指南

Foxmail v7.0.1.92:安装配置、数据迁移与避坑指南

简介:Foxmail v7.0.1.92官方正式版是一款面向国内个人及办公用户的电子邮件客户端,解决邮件收发管理、垃圾邮件过滤和传输安全等常见问题。其反垃圾机制可自动识别并分拣垃圾邮件,数字签名与SSL加密确保邮件真实性和保密性,还支持…

2026/10/16 20:31:58 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →