11 KiB
11 KiB
总体思路
- 每个阶段都交付一个可运行的“小产品”(而不是一堆库)
- 优先把 RK3588 的硬件链路打通(解码 → 前处理 → NPU → 编码)
- 从 最简单的“转码网关” 一步步进化到 “智能分析+报警+录像”
建议整体 roadmap ≈ 7~8 个迭代:
- Sprint 0:环境&硬件打底
- Sprint 1:最小可用媒体服务器(纯转码网关)
- Sprint 2:插件框架 + DAG 图 & 队列打通
- Sprint 3:AI 推理链路(preprocess + ai_yolo + OSD)
- Sprint 4:报警 + 录像插件,打通完整“安防通道”
- Sprint 5:配置系统(templates/instances)+ 热更新 + Drain
- Sprint 6:监控指标 + Web 控制台基础
- Sprint 7:多路性能调优 + 长稳测试
下面每个 Sprint 我都给一个目标 / 核心任务 / 关键里程碑。
Sprint 0:环境准备 & 板子打通(已完成)
目标: 所有开发人员都能在本地和 RK3588 板子上编译、部署、跑官方 demo。
核心任务:
- 建工程骨架:
- 建 Git 仓库 + 基础目录结构(
src/,include/,plugins/,cmake/等) - CMake + Ninja 构建脚本
- 建 Git 仓库 + 基础目录结构(
- 搭建交叉编译环境:
- 配置
aarch64-linux-gnu-gcc - 能在 x86 上编译并在 RK3588 板子上运行“hello world”
- 配置
- 验证 RK 官方 SDK:
- 跑 MPP 解码 demo(本地 H264 文件 → 屏幕或 /dev/null)
- 跑 RKNN demo(官方示例图片 → 得到推理结果)
- CI 基础:
- 至少有一个自动构建(例如 push 后自动编译)
关键里程碑:
- ✅ 在 RK3588 板子上成功运行:
- 一个 MPP 解码 demo
- 一个 RKNN 推理 demo
- ✅
media-server空壳程序(打印版本号)能从 CI 输出产物并部署到板子上运行
Sprint 1:最小可用媒体服务器(纯转码网关)
目标: 实现一个最小可用产品:
从 RTSP 拉流 → 解码 → 编码 → 再推 RTSP/HLS
还没有 AI、报警、录像,只是转码网关。
核心任务:
- 定义最初版
Frame结构(至少包含:宽高、格式、 pts、dma_fd) - 实现最简单的线性 pipeline(先不用 DAG):
input_rtsp插件:- 拉 RTSP 流,断线重连
- 用 MPP 解码为 NV12/YUV
publish插件:- 用 MPP VENC 编码 H264/H265
- 启动简单 RTSP server 或 HLS 输出
- 初版线程模型:
- 1 个拉流/解码线程
- 1 个编码/推流线程
- 中间通过 SPSC 队列传
shared_ptr<Frame>
- 配置文件:
- 简单 JSON,只支持一条通道,如:
{ "graphs": [ { "name": "cam1", "nodes": [...], "edges": [...] } ] }
- 简单 JSON,只支持一条通道,如:
关键里程碑:
- ✅ 在 RK3588 板子上:
- 从外部摄像头 / NVR 拉一路 RTSP
- 在本机 8554 端口重新发布 RTSP(或 8080 HLS)
- VLC / ffplay 打开
rtsp://board_ip:8554/live/cam1能稳定观看
- ✅ 初始版本
Frame+ 队列已经固定下来,后面不会大改接口
Sprint 2:插件框架 + DAG 图 & 队列体系
目标: 从「硬编码 pipeline」升级为「插件 + DAG 驱动」,让架构进入你 PRD 描述的形态。
核心任务:
- 定义
INode接口(含 Init/Start/Process/UpdateConfig/Drain/Stop) - 完成插件加载系统:
.so动态加载(dlopen)REGISTER_NODE宏 +GetNodeType/GetAbiVersion
- 实现 GraphMgr:
- 支持从 JSON 读取
graphs[nodes + edges] - 根据 type 创建节点、连接 edges
- 每条 edge 对应一个 SPSC 队列
- 支持从 JSON 读取
- 多分支 DAG 支持:
- 允许一个节点连接多个下游,GraphMgr 为每条边创建独立队列
- 把 Sprint1 的 input/publish 改造成插件形式,跑在 DAG 上:
- Graph:
input_rtsp -> publish
- Graph:
关键里程碑:
- ✅ 支持通过 JSON 配置任意组合节点(至少:
in→pub、in→pre→pub两种) - ✅ 节点以
.so的形式存在,可以单独编译、加载/卸载 - ✅ 框架已支持一对多分支(即使当前下游还只有一个,这点结构上要打好)
Sprint 3:AI 链路打通(preprocess + ai_yolo + OSD)
目标: 打通一条完整的 AI 视觉链路:
拉流 → 前处理 → YOLO 推理(RKNN) → 叠框 OSD → 推流
核心任务:
- 完整定义
Detection/DetectionResult/ 扩展版Frame结构(含det) - 实现
preprocess插件:- RGA 缩放(例如 1080p → 640×640)
- NV12 → RGB/BGR 格式转换
- 实现
AiScheduler:- 提供提交/回调接口
- 内部管理 RKNN 上下文和 NPU 资源
- 暂时可只支持单路/单 batch,先打通功能
- 实现
ai_yolo插件:- 加载
.rknn模型 - 调用
AiScheduler做推理 - 将输出写入
Frame::det
- 加载
- 实现
osd插件:- 根据
Frame::det在原图上画框/标签 - 输出 NV12/YUV 帧(可以软绘+回写,也可以用 RGA)
- 根据
- 在 JSON 中构建一条完整 AI pipeline:
input_rtsp -> preprocess -> ai_yolo -> osd -> publish
关键里程碑:
- ✅ 在板子上:
- 拉一条实际摄像头画面
- web/RTSP 观看输出画面时,能看到实时的检测框
- ✅ 基础性能满足:
- 单路 1080p 流畅运行(不明显掉帧)
- CPU/NPU 占用在可接受范围内(不超出预期天花板)
Sprint 4:报警 + 录像插件(完成一条“安防通道”)
目标: 在 AI 结果基础上,增加 报警逻辑 + 录像,形成完整“安防产品”的基本形态。
核心任务:
- 实现
alarm插件:- 支持按规则配置:object 类型、ROI、最小持续时间、时间段(类似你 PRD 里的
rules) - 支持 HTTP/MQTT 等方式发报警(先做 HTTP)
- 支持按规则配置:object 类型、ROI、最小持续时间、时间段(类似你 PRD 里的
- 实现
storage插件:- 支持 continuous 模式(持续录像,分段保存)
- 文件切片(
segment_sec) - 先不做 event 模式,后续可以扩展 pre/post-event 缓冲
- 在 DAG 上实现典型拓扑:
ai_yolo → alarm(分支 1)ai_yolo → osd → storage(分支 2)osd → publish(分支 3)
- 简单报警可视化:
- HTTP 回调到一个简单日志服务,或直接打印到日志,先验证链路
关键里程碑:
- ✅ 配置一个规则:例如“白天有人进入 ROI 区域触发报警”
- ✅ 摄像头对准测试区域:
- 屏幕上能看到检测框
- 有人进 ROI 时,后台收到 HTTP 报警请求(或日志输出)
- 同时有录像文件被写入(在
/rec/cam1下能找到)
Sprint 5:配置系统完善 + 模板/实例 + 热更新 & Drain
目标: 从“能跑”升级到“好配、好改”:
实现 templates/instances、节点 enable/override、热更新、Drain/Stop 正常运转。
核心任务:
-
(P0,热更新前置)Stop/Drain 语义对齐 & 线程/资源可回收:
Drain():不再接收新输入/不再产生新任务,仅负责把内部缓冲“处理完/落盘/发送完”Stop():在Drain()之后调用,必须保证内部线程退出并 join、句柄/资源释放,可幂等- 至少覆盖 alarm:HttpAction/ClipAction 等动作线程 Stop 后可回收,避免多次热更新/重建图堆线程
-
完善配置结构:
global、templates、instances、graphs- 节点通用字段(
enable,role,queue)
-
模板 + 实例展开逻辑:
- 支持
${placeholder}替换 - 支持实例级
override(开启/关闭某节点、覆盖某些参数)
- 支持
-
实现
UpdateConfig:- 对一部分节点(alarm/publish/storage)支持参数热更新
-
实现图的热更新流程:
- inotify 监控 config
- 构建新图 → 校验 → 若成功则原子切换
- 对旧节点按顺序调用
Drain()→Stop() - 失败则回滚旧配置
-
对 "enable=false" 节点的处理:
- 构图时直接忽略该节点和相关 edges
- 或者实现旁路逻辑(看你最终选哪种,在代码里统一)
关键里程碑:
-
✅ 连续热更新/重建图 N 次后:
- action/node 线程数不随次数增长(至少 alarm 的 http/clip 线程不会残留)
Drain/Stop无死锁,Stop 后资源可回收
-
✅ 不重启进程的前提下:
- 通过修改 config,把某一路的
ai_yolo.enable改为 false → 该通道立即变成纯转码网关 - 再改回 true,恢复智能分析
- 通过修改 config,把某一路的
-
✅ 热更新时:
- 流“几乎不断”(允许 1 秒内小抖动)
- 没有崩溃 / 明显内存泄漏 / 死锁
Sprint 6:监控指标 + Web 控制台基础
目标: 增加可观测性,让系统变成“可视化可管理”的产品,而不是黑盒程序。
核心任务:
- 指标采集模块:
- 节点级:input/output fps、queue 长度、drop 数、error 数、平均处理时长
- 图级:总 fps、报警数、当前推流客户端数
- HTTP API:
GET /api/graphsGET /api/graphs/{name}GET /api/nodes/{id}/metrics- (可选)
POST /api/nodes/{id}/config调用UpdateConfig
- Web 控制台(Vue)第一版:
- 简单展示通道列表、节点状态、关键指标
- 不必太花哨,能看到“通道是否绿”、“fps 大概多少”即可
- 日志查看:
- 提供简单接口/页面看到最近日志(或直接解析 log 文件)
关键里程碑:
- ✅ 打开 Web 页面:
- 能看到所有通道,以及每个通道的状态(Running/Stopped/Error)
- 能看到某通道底下的节点链条(in→pre→ai→osd→alarm/storage/publish)
- 能看到每个节点的大致 fps & 队列深度
- ✅ 模拟异常(例如关闭摄像头):
- Web 页面能看到该通道出现错误/掉线状态,日志中有清晰错误信息
Sprint 7:多路性能调优 + 长稳测试
目标: 把系统从 demo 提升到「能上生产」的水平:多路、低延迟、长时间稳定。
核心任务:
- 多路场景压测:
- 逐步从 2 路 → 4 路 → 8 路 → 16 路(根据目标)
- 观察 CPU、NPU、内存占用和延迟
- 性能调优点:
- 队列策略(
drop_oldestvsblock) - OSD 放在 RGA/CPU 侧的性能权衡
- AiScheduler 模式(是否可以 batch、是否减少多线程抢 NPU)
- 绑核策略(input/ai/stroage/publish 分布在大/小核)
- 队列策略(
- 长稳测试:
- 7×24 小时连续跑,统计:
- 内存占用曲线
- CPU/NPU 曲线
- 崩溃/重启次数
- 7×24 小时连续跑,统计:
- 回归测试:
- 关键功能场景(报警、录像、推流、热更新)跑完一遍
关键里程碑:
- ✅ 在目标多路场景(例如 8×1080p)下:
- 系统端到端延迟满足 PRD 要求
- CPU/NPU 占用在目标范围内(如 CPU <30%,NPU >90%)
- ✅ 连续运行 7×24 小时:
- 无崩溃 / 无明显内存泄漏(内存曲线稳定)
- 所有通道仍在正常推流/录制/报警