从四路 4K 硬解成功,到完整推理的困局

写在前面

最近一直在做一个看起来很简单、实际上非常容易误判的事情:把四路 4K 视频送进 RK3588,完成硬件解码、目标检测、叠框、H.264 编码,再分别推回 SRS。

阶段中出现过两个看似矛盾的结果:

  • 四路 4K H.264 硬解已经成功,而且可以实时跑到 30 FPS;
  • 四路 4K 完整推理却不能稳定做到“每路高频检测 + 每路 30 FPS 输出”。

这两个结论并不矛盾。前者证明的是 RKVDEC/FFmpeg 硬解链路的能力,后者考验的是整台板卡上解码、内存、RGA、NPU、MPP 编码和网络输出的总资源预算。

本文记录这个过程,也解释为什么“4K 硬解成功”不能直接推导出“四路 4K 完整推理实时通过”。

一、之前的 4K 硬解确实成功了

1. 最初的测试目标很单纯

最初测试并没有把检测和编码放进来,测试链路是:

Windows 本地 4K 视频
        ↓
SRS RTMP
        ↓
板端 FFmpeg + h264_rkmpp
        ↓
null sink

板端使用的命令明确把 h264_rkmpp 放在输入端,输出只是 wrapped_avframe,不再做后续 MPP 编码。这样做的目的,是单独回答一个问题:

RK3588 上能不能同时把四路 3840×2160 H.264 RTMP 实时解码出来?

2. 中间还排查出一个网络问题

早期四路测试表现很差,输入 speed 只有 0.8~0.9 倍实时。最初怀疑过:

  • RKVDEC 是否只启用了一颗核心;
  • FFmpeg 是否选错了解码器;
  • SRS 是否没有实时输出;
  • 多路 RTMP 是否有丢包;
  • 板端是否存在 TCP 接收队列积压。

最后确认的主要原因是 SRS 所在 Windows 主机的物理网卡只协商到了 100 Mbps。四路源视频大约 40 Mbps/路,四路聚合已经接近或超过物理链路上限。

恢复千兆链路后,点到点 TCP 测试达到约 787 Mbps,网络瓶颈被排除。

3. 四路纯硬解验收结果

在千兆链路和正确的 decoder 参数下,四路硬解测试结果如下:

  • 输入:四路 3840×2160 H.264 RTMP;
  • 解码器:h264_rkmpp
  • 输出:wrapped_avframe,不做检测和编码;
  • 测试时间:约 60 秒;
  • 四路最终 speed:约 1.02–1.05x
  • 每路完成约 1770~1800 帧;
  • 未出现软件解码回退;
  • 未出现 MPP 解码错误。

所以这件事可以明确下结论:

四路 4K H.264 硬解本身已经通过实时门槛。

这不是模拟结果,也不是单路结果,而是 Windows 本地源 → SRS → 板端四路 h264_rkmpp 的实际拓扑验证。

二、为什么完整推理又变成了另一个问题

完整业务链路不是“解码结束就完事”,而是:

4K H.264
  ↓
h264_rkmpp 硬解
  ↓
NV12 / DMA-BUF
  ↓
RGA 颜色转换、缩放和 letterbox
  ↓
RKNN YOLOv8s INT8 推理
  ↓
CPU 输出获取、DFL 解码、NMS
  ↓
SharedDetections / 跟踪
  ↓
MPP 4K H.264 编码
  ↓
RTMP 推流 + MQTT

纯硬解测试只消耗了解码和网络输入资源;完整推理还额外增加了:

  • 四路 4K NV12 buffer 的分配、同步和 DMA 访问;
  • RGA 预处理;
  • RKNN NPU 计算;
  • 输出 tensor 获取和 CPU 后处理;
  • 四路 MPP H.264 编码;
  • 四路 RTMP 输出。

因此,纯硬解实时通过,只能证明“解码器有能力”,不能证明“整条流水线还有足够余量”。

三、完整推理阶段做了哪些修改

1. 让硬解帧进入 RGA、RKNN 和 MPP

以前的推理路径更多是围绕 CPU 帧和 V4L2 帧设计的,4K 硬解后得到的 MPP DMA-BUF 不能简单当成普通 raw_data 使用。

这次做了几项适配:

  • InferThread 同时支持 CPU NV12/YUYV 和 MPP DMA-BUF;
  • RGA 处理使用实际 buffer 的 stride;
  • CPU fallback 也按 stride 读取 NV12;
  • 访问 MPP buffer 前进行只读同步;
  • TilingTask 的 NV12 crop 同样适配 DMA-BUF 和 stride;
  • 保留 frame ID、PTS 和时间戳,保证检测结果能够和视频帧对齐。

单路板端运行时已经明确打印:

Resolution: 3840x2160
Decoder: h264_rkmpp
Format: nv12

并且后续出现 RKNN 推理、MPP 编码、RTMP 输出和 MQTT 连接日志。单路 4K 完整链路分别完成了 60 秒和 180 秒稳定性测试,输入、编码和输出约 30 FPS,编码/推流失败计数为 0。

2. 从多个 RKNN context 改成一个全局 NPU executor

最初的四路完整推理路径是每个 pipeline 各自创建 RKNN context,并都绑定三颗 NPU 核心。结果是四个 context 同时争用同一组 NPU 资源。

实测表现是:

  • 单路 NPU 阶段约 27 ms;
  • 四路并发时部分时段升到 50 ms;
  • 压力进一步增加后,部分时段达到 85–88 ms;
  • 视频输出随之出现明显卡顿。

因此新增了全局 Scheduler:

  • 一个共享 RKNN context;
  • 一个 all-core NPU executor;
  • 一个 scheduler worker 串行执行推理事务;
  • 每路一个 latest-frame mailbox;
  • 旧帧被覆盖,不允许队列无限堆积;
  • 统计 NPU 平均值、P95、busy ratio、queue wait 和每路实际 FPS。

这个修改解决的是 NPU context 争用,不是让 NPU 变成了更快的硬件。

3. 增加全局节流和固定相位

早期的 global_target_fps 只是配置校验,并没有真正限制全局发车间隔。现在增加了实际的全局节流和相位错峰:

四路 4 FPS:
channel 1: 0 ms
channel 2: 62 ms
channel 3: 125 ms
channel 4: 187 ms

调度器会按照绝对时间轴发车;如果某次执行已经错过下一个周期,就跳过过期周期,而不是连续追赶。这可以减少瞬时 RGA、NPU、内存和 MPP 资源争用。

需要特别说明:错峰不会增加每路检测频率。每路仍然是 4 FPS,就意味着检测框每 250 ms 才得到一次新测量。

四、单路、双路、四路分别是什么结果

单路:有余量

单路 4K 不主动跳帧时:

  • 完整推理平均约 40.9 ms;
  • NPU 阶段约 27 ms;
  • 实际完整推理能力约 24 FPS;
  • 视频编码和 RTMP 输出约 30 FPS。

另一个单路候选设置了 infer_every_n_frames=4,这代表每 4 个输入帧才推理一次,不是每秒 4 次。30 FPS 输入下理论约 7.5 FPS,180 秒实测约 6.8~7 FPS。

双路:每路 7 FPS 可以稳定

双路全局 Scheduler 测试使用每路目标 7 FPS:

  • 实际约 6.9~7.0 FPS/路;
  • 全局约 14 FPS;
  • 两路视频输出约 30 FPS/路;
  • enc_drop=0
  • out_drop=0
  • write_fail=0

这说明在当前板端资源下,双路每路 7 FPS 是可行的容量档位。

四路目标 7 FPS:预算超载

四路每路目标 7 FPS,总目标是 28 FPS。实测结果:

  • 每路实际约 4.8~5.3 FPS;
  • NPU 平均约 31.5~33.9 ms;
  • busy_ratio=0.98–0.99
  • 结果视频有效窗口约 28.6~29.5 FPS,部分窗口约 27 FPS;
  • 没有 RKNN 执行失败、编码失败或 RTMP 写失败。

这说明系统不是“跑不起来”,而是已经没有足够资源满足原来的预算。

四路目标 5 FPS:稍微缓解,但还不够

把每路目标降为 5 FPS、全局预算设为 21 FPS 后:

  • 每路实际约 4.7~5.0 FPS;
  • busy_ratio=0.92–0.97
  • 大部分视频窗口接近 30 FPS;
  • 仍有部分窗口降到约 27 FPS。

这说明降低 NPU 调度预算有帮助,但四路 4K 解码、内存搬运和 MPP 编码的总压力仍然存在。

四路目标 4 FPS:视频稳了,但框不顺

加入全局 16 FPS 节流和固定相位后,四路 4 FPS 测试得到:

  • 每路实际约 4.0 FPS;
  • busy_ratio 降到约 0.72~0.76;
  • 四路视频输出约 29.8~30.2 FPS;
  • 最后 10 秒 SRS 帧增量约 298/301/301/302;
  • 所有编码和推流失败计数为 0。

从视频链路角度,这个结果是成功的;从检测框体验角度,它不合格。因为当前跟踪器主要做保持和 EMA 平滑,没有在检测间隔内持续预测框的位置,所以移动目标会表现为:

框停留一段时间 → 更新一次 → 再停留 → 再跳一次

用户已经明确不接受每路 4 FPS 的检测刷新率,因此这个配置只保留为容量基线,不进入最终配置。

五、当前真正卡住的地方

1. NPU 是单次推理的主要计算开销

单路 NPU 约 27 ms,是一次推理事务中最大的单项计算阶段。四路共享后,NPU 平均仍在 30~34 ms,P95 约 34~39 ms。

但四路问题不能只看 rknn_run(),因为完整 executor 还包括 RGA、cache sync、outputs_get 和后处理。

2. 四路 4K 媒体链路总量超过安全余量

稳定窗口中可以观察到:

  • MPP 解码接收通常约 12~15 ms/帧;
  • RGA/NV12 预处理约 3 ms/帧;
  • MPP 4K 编码约 25~27 ms/帧;
  • 多路 DMA buffer、内存带宽和硬件模块调度继续叠加。

这就是为什么 target=5 已经降低了 NPU 压力,部分输出窗口仍然只有约 27 FPS:瓶颈已经不是纯 NPU,而是完整 4K 媒体链路的总吞吐。

3. Queue wait 是后果,不是根因

Scheduler 中的 queue_wait_p95 在四路 4 FPS 时仍约 50~105 ms。这代表最新提交的帧需要等待全局 slot 和通道相位,不代表编码或推流丢帧。

latest mailbox 的策略是:宁可覆盖旧推理帧,也不让延迟无限增加。所以 mailbox_replaced 较高是预期行为;但它不会把 4 FPS 检测框变成 30 FPS 连续运动。

4. 网络问题已经不是当前主因

100 Mbps 物理链路的问题已经通过恢复千兆协商解决。四路纯 h264_rkmpp 硬解已经证明输入网络和硬解能力都可以达到实时。

当前更应该关注的是板端多路解码、NV12/DMA 内存、RGA、NPU 和 MPP 编码之间的资源竞争。

六、下一步怎么走

现在不能继续把“四路 4K 完整推理”简单理解成一个 FPS 数字。至少要同时满足三个条件:

  1. 每路检测刷新率达到可接受水平,不能停在 4 FPS;
  2. 四路视频输出稳定约 30 FPS;
  3. 不能依靠持续堆积队列来换取表面上的检测频率。

下一轮最合理的实验是重新测试带全局节流和固定相位的:

每路 target_infer_fps = 5
全局 global_target_fps = 20
相位 = 0 / 50 / 100 / 150 ms

之前的 target=5 测试是在全局节流和固定相位实现之前完成的,不能直接作为新调度器的最终结论。

如果 target=5 仍然让检测框出现明显跳变,那么继续把四路目标推到 6~7 FPS 很可能重新压垮媒体链路。更合理的方向是:让 NPU 以 5 FPS 左右负责检测校正,再在两次检测之间增加低成本的帧间运动跟踪或位置插值,使框可以按视频帧率连续移动。

总结

目前可以非常明确地说:

  • 四路 4K h264_rkmpp 硬解已经成功;
  • 单路 4K 完整推理已经成功;
  • 双路 4K 每路约 7 FPS 检测已经成功;
  • 四路 4K 完整流水线已经完成功能闭环;
  • 四路目标 7 FPS 资源超载;
  • 四路目标 5 FPS 尚需在新调度器上重新公平验证;
  • 四路目标 4 FPS 能保护视频输出,但检测框体验不被接受。

这不是“硬解成功后突然失败”,而是测试目标从“能不能解码”升级成了“整条 4K 业务链路能不能在资源预算内稳定工作”。前一个问题已经解决,后一个问题等待有经验的大佬解惑,

posted @ 2026-08-01 13:08  rambos1996  阅读(3)  评论(0)    收藏  举报