safesight-edge/docs/design/PRD_06_Hardware_Decoupling_Plan.md

180 lines
5.3 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.

# PRD_06 多硬件解耦计划RK3588/Atlas/Jetson
## 1. 背景与目标
当前工程深度绑定 RK3588RKNN/RGA/MPP/DMA-BUF限制了 Atlas、Jetson 等平台的接入。目标是在**不破坏现有功能**的前提下,通过接口解耦与默认实现保留现有行为,实现多硬件可插拔支持。
### 目标
- 以接口层抽象 **推理、图像处理、编解码、缓冲区** 四个核心模块。
- 默认实现保持 RK3588 行为与性能路径(零拷贝/DMA-BUF
- 逐步迁移现有节点,避免一次性大改。
### 非目标
- 不改变业务逻辑(检测/识别流程、RTSP/HLS 业务)。
- 不在本阶段引入新 UI/协议或跨平台发布流程。
## 2. 现状摘要(关键路径)
- 推理:`include/ai_scheduler.h`, `src/ai_scheduler.cpp`RKNN + DMA-BUF 输入)
- 图像处理:`plugins/preprocess/preprocess_node.cpp`RGA 或 swscale
- 编解码:`plugins/input_rtsp/*`, `plugins/input_file/*`, `plugins/publish/*`MPP + FFmpeg 混用)
- 缓冲:`include/frame/frame.h`dma_fd/planes/data_owner
## 3. 总体方案
引入四类接口与默认实现:
- **IInferBackend**:推理后端抽象(默认 RKNN
- **IImageProcessor**:图像预处理抽象(默认 RGA + swscale 兜底)
- **IDecoder / IEncoder**:编解码抽象(默认 MPP必要时 FFmpeg
- **FrameBuffer**:统一缓冲区语义与同步
所有接口通过工厂/配置注入,保持现有 JSON 配置兼容。
## 4. 实施步骤、里程碑与单元测试
### Step 1建立基础抽象与工厂
**实施内容**
- 新建 `include/hw/` 下接口定义:`i_infer_backend.h`, `i_image_processor.h`, `i_decoder.h`, `i_encoder.h`, `frame_buffer.h`
- 定义最小能力集:
- IInferBackend: `LoadModel`, `Infer`, `InferBorrowed`
- IImageProcessor: `Resize`, `CvtColor`, `Normalize`
- IDecoder/IEncoder: `Open`, `Send`, `Receive`, `Close`
- FrameBuffer: `Planes()`, `DmaFd()`, `SyncStart/End()`
- 新建工厂:`hw_factory.h/cpp`,根据配置返回默认实现
**关键里程碑**
- 接口头文件编译通过;工程无行为变化
- 工厂默认返回 RK3588 实现(空实现也可先用占位)
**单元测试GTest**
- `HwFactory_Defaults_ReturnsRk3588Impls`
- `FrameBuffer_Metadata_Preserved`dma_fd/planes 赋值一致性)
---
### Step 2推理模块解耦RKNN → IInferBackend
**实施内容**
-`AiScheduler` 包装为 `RknnInferBackend` 实现
- `ai_*` 节点依赖 `IInferBackend` 接口注入(保留默认行为)
- 保留 `InferBorrowed` 以支持零拷贝输入
**关键里程碑**
- 现有模型推理链路无回归,性能基准一致(同配置)
- RKNN 仍可多上下文并发
**单元测试GTest**
- `InferBackend_LoadModel_Smoke`(加载模型返回成功)
- `InferBackend_BorrowedInput_UsesDmaFd`(检查传入 dma_fd 路径被调用)
---
### Step 3图像预处理解耦RGA/CPU → IImageProcessor
**实施内容**
- 抽取 RGA 路径为 `RgaImageProcessor`
- 抽取 swscale 路径为 `SwscaleImageProcessor`
- `preprocess_node` 仅面向接口调用
**关键里程碑**
- `use_rga=true/false` 行为完全一致
- RGA 限流逻辑RgaGate保留
**单元测试GTest**
- `ImageProcessor_RgaVsSwscale_OutputShape`(输出尺寸一致)
- `ImageProcessor_ColorConversion_Nv12ToRgb`(像素格式转换)
---
### Step 4编解码解耦MPP/FFmpeg → IDecoder/IEncoder
**实施内容**
- `MppDecoder`, `FfmpegDecoder` 实现 `IDecoder`
- `MppEncoder`, `FfmpegEncoder` 实现 `IEncoder`
- `input_rtsp/input_file/publish/storage` 节点仅面向接口
**关键里程碑**
- RTSP 输入与 HLS 输出链路不变
- MPP 仍为默认路径FFmpeg 作为兜底/平台适配
**单元测试GTest**
- `Decoder_Open_Close_Smoke`
- `Encoder_Open_Close_Smoke`
- `Codec_Pipeline_EncodeDecode_OneFrame`(小尺寸样例帧)
---
### Step 5缓冲区抽象Frame → FrameBuffer
**实施内容**
- 新增 `FrameBuffer`,替代直接使用 `Frame` 的 dma_fd/data_owner
- `Frame` 保留为业务结构,内部持有 `FrameBuffer`
- 统一 DMA 同步接口以便多硬件适配
**关键里程碑**
- DMA-BUF 与内存缓冲区均可通过统一接口访问
- `Frame` 兼容旧字段,最小侵入替换完成
**单元测试GTest**
- `FrameBuffer_Sync_NoCrash`
- `FrameBuffer_PlaneAccess_Consistent`
---
### Step 6多硬件适配接入Atlas/Jetson
**实施内容**
- 新增 `AtlasInferBackend/AtlasImageProcessor/AtlasCodec` 实现(占位/实验性)
- 新增 `JetsonInferBackend/JetsonImageProcessor/JetsonCodec` 实现
- 通过配置切换平台实现
**关键里程碑**
- 不影响 RK3588 默认路径
- 新平台可在单机完成 smoke 测试
**单元测试GTest**
- `HwFactory_SelectsBackend_ByConfig`
- `PlatformImpls_Smoke_Construct`(构造/释放)
## 5. 风险与缓解
- **接口过宽导致迁移成本增加** → 控制最小接口集,逐步扩展
- **性能回退** → 保留 RK3588 默认实现与 DMA-BUF 快路径
- **迁移破坏现有节点** → 节点逐个替换,保持旧路径可回退
## 6. 验证与回滚
### 验证命令
```
scripts/build_host.sh
ctest --test-dir build/host --output-on-failure
```
### 回滚策略
- 以编译开关/配置切换回旧路径
- 保留 RK3588 实现作为默认后端