# PRD_06 多硬件解耦计划(RK3588/Atlas/Jetson) ## 1. 背景与目标 当前工程深度绑定 RK3588(RKNN/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 实现作为默认后端