Chapter 4: Engineering a Production-Grade C++ Inference Pipeline
| Project Attribute | Details |
|---|
| Project Name | Helmsman — C++ Inference Pipeline |
| Phase | MR2 Phase-3 + Phase-5 |
| Date | 2026-04-11 ~ 2026-04-18 |
| Key Personnel | Potter 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 | 层级计时系统 |
-->