OrangePi3588Media/Plan.md
2025-12-29 16:07:13 +08:00

297 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
## 总体思路
- 每个阶段都交付一个**可运行的“小产品”**(而不是一堆库)
- 优先把 **RK3588 的硬件链路打通**(解码 → 前处理 → NPU → 编码)
-**最简单的“转码网关”** 一步步进化到 **“智能分析+报警+录像”**
建议整体 roadmap ≈ 7~8 个迭代:
1. Sprint 0环境&硬件打底
2. Sprint 1最小可用媒体服务器纯转码网关
3. Sprint 2插件框架 + DAG 图 & 队列打通
4. Sprint 3AI 推理链路preprocess + ai_yolo + OSD
5. Sprint 4报警 + 录像插件,打通完整“安防通道”
6. Sprint 5配置系统templates/instances+ 热更新 + Drain
7. Sprint 6监控指标 + Web 控制台基础
8. Sprint 7多路性能调优 + 长稳测试
下面每个 Sprint 我都给一个**目标 / 核心任务 / 关键里程碑**。
---
## Sprint 0环境准备 & 板子打通(已完成)
**目标:** 所有开发人员都能在本地和 RK3588 板子上编译、部署、跑官方 demo。
**核心任务:**
- 建工程骨架:
- 建 Git 仓库 + 基础目录结构(`src/`, `include/`, `plugins/`, `cmake/` 等)
- CMake + Ninja 构建脚本
- 搭建交叉编译环境:
- 配置 `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只支持一条通道
```json
{
"graphs": [
{
"name": "cam1",
"nodes": [...],
"edges": [...]
}
]
}
```
**关键里程碑:**
- ✅ 在 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 队列
- 多分支 DAG 支持:
- 允许一个节点连接多个下游GraphMgr 为每条边创建独立队列
- 把 Sprint1 的 input/publish 改造成插件形式,跑在 DAG 上:
- Graph`input_rtsp -> publish`
**关键里程碑:**
- ✅ 支持通过 JSON 配置任意组合节点(至少:`in→pub`、`in→pre→pub` 两种)
- ✅ 节点以 `.so` 的形式存在,可以单独编译、加载/卸载
- ✅ 框架已支持一对多分支(即使当前下游还只有一个,这点结构上要打好)
---
## Sprint 3AI 链路打通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
- 实现 `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、句柄/资源释放,可幂等
- 至少覆盖 alarmHttpAction/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恢复智能分析
- ✅ 热更新时:
- 流“几乎不断”(允许 1 秒内小抖动)
- 没有崩溃 / 明显内存泄漏 / 死锁
---
## Sprint 6监控指标 + Web 控制台基础
**目标:** 增加可观测性,让系统变成“可视化可管理”的产品,而不是黑盒程序。
**核心任务:**
- 指标采集模块:
- 节点级input/output fps、queue 长度、drop 数、error 数、平均处理时长
- 图级:总 fps、报警数、当前推流客户端数
- HTTP API
- `GET /api/graphs`
- `GET /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_oldest` vs `block`
- OSD 放在 RGA/CPU 侧的性能权衡
- AiScheduler 模式(是否可以 batch、是否减少多线程抢 NPU
- 绑核策略input/ai/stroage/publish 分布在大/小核)
- 长稳测试:
- 7×24 小时连续跑,统计:
- 内存占用曲线
- CPU/NPU 曲线
- 崩溃/重启次数
- 回归测试:
- 关键功能场景(报警、录像、推流、热更新)跑完一遍
**关键里程碑:**
- ✅ 在目标多路场景(例如 8×1080p
- 系统端到端延迟满足 PRD 要求
- CPU/NPU 占用在目标范围内(如 CPU <30%NPU >90%
- ✅ 连续运行 7×24 小时:
- 无崩溃 / 无明显内存泄漏(内存曲线稳定)
- 所有通道仍在正常推流/录制/报警
---