Chapter 4: C++ 推理流水线工程

Chapter 4: Engineering a Production-Grade C++ Inference Pipeline

Project AttributeDetails
Project NameHelmsman — C++ Inference Pipeline
PhaseMR2 Phase-3 + Phase-5
Date2026-04-11 ~ 2026-04-18
Key PersonnelPotter White

1. Core Question

2. Architecture: NVI Pattern

|TensorData| B[InferenceEngine]
B -->|vector<TensorData>| C[Backend]

subgraph Frontend
    A1[Input Source] --> A2[Decoder]
    A2 --> A3[Color Convert]
    A3 --> A4[Preprocess]
end

subgraph InferenceEngine
    B1[Inject States] --> B2[Quantize]
    B2 --> B3[NPU Execute]
    B3 --> B4[Dequantize]
end

subgraph Backend
    C1[Postprocess] --> C2[Composite]
end

设计原则:
- Preprocessor 只负责空间变换(resize, letterbox)
- Engine 负责精度变换(normalize, quantize, dequantize)
- Backend 负责数据提取 + 合成输出
- 三者正交,互不依赖
-->

### **3. Frontend: 4 Sub-Stages**

<!-- 填入:4 个子阶段的说明(参考 PKB _DASHBOARD.md 附录 B §2):
1. Stage 01 Input Source:FFmpegInputSource,读取视频 packet
2. Stage 02 Decoder:MppFrameDecoder,硬件解码 H.264/H.265
3. Stage 03 Color Convert:RgaNv12ToBgr,RGA 硬件 NV12→BGR
4. Stage 04 Preprocess:resize + letterbox → TensorData(float32 [0,255])
-->

### **4. InferenceEngine: NVI + Factory Pattern**

<!-- 填入:
- NVI(Non-Virtual Interface)模式:Infer() 公开入口 → 注入状态 → DoInfer() 纯虚钩子 → 捕获状态
- 工厂模式:make_engine() 根据 INFERENCE_BACKEND 配置创建不同引擎
- 三路引擎:onnx | rknn-zerocopy | rknn-non-zerocopy

关键设计决策:为什么 Normalize + Quantize 放在 Engine 里?

| 引擎 | 输入量化方式 | 输出反量化方式 |
|------|------------|--------------|
| RKNN Zero-Copy | 手动:(pixel-127.5)/127.5/scale+zp 写入 DMA | 手动:(val-zp)*scale 从 DMA 读出 |
| RKNN Non-Zero-Copy | rknn_inputs_set(pass_through=0) | rknn_outputs_get(want_float=1) |
| ONNX Runtime | 模型内嵌 QDQ 节点 | 模型内嵌 QDQ 节点 |

如果把 normalize 放到 Preprocessor 里,换引擎就要改 Preprocessor → 违反"换引擎只需重新编译"的设计目标。
-->

### **5. Multi-Model Support: MODNet + RVM**

<!-- 填入:
- MODNet:1-in/1-out,无状态
- RVM:5-in/6-out,有递归状态(r1i~r4i 注入/捕获)
- 设计:在旁边加新路,不改旧路(RecurrentStateManager)
- 参考 PKB summarize-MR2-G0 Q4
-->

### **6. Pipeline Modes: Sync → Double Buffer → Worker Thread**

<!-- 填入:三种模式的演进:
1. 同步模式:read → preprocess → infer → backend(串行)
2. 双 buffer 流水线:std::async 预取第 N+1 帧 decode+preprocess 与第 N 帧推理并行
3. 持久 Worker Thread:SingleSlotChannel<T> + 持久 worker thread 替换 std::async-per-frame,零线程创建开销

参考 PKB log-MR2-P5-video-pipeline.md Block 5.2 + 5.4
-->

### **7. Reusable Assets**

<!-- 填入:表格

| 资产 | 说明 |
|------|------|
| NVI InferenceEngine 基类 | 可扩展到任意模型 |
| 工厂模式 + 三路引擎 | 换引擎只需重新编译 |
| RecurrentStateManager | RVM 递归状态管理 |
| SingleSlotChannel<T> | 生产者-消费者通道,零锁开销 |
| ScopedTimer + StageAccumulator | 层级计时系统 |

-->