☰
Detile解块优化:NV12 BL转ARGB下放硬件,解码+CSC从18.1ms降到3.5ms
2026/10/30 2:26:48 网站建设 项目流程

一 背景回顾

上篇结尾说解码的 13.85ms 另有隐情,这篇填坑。

13.85ms 里真解码只有 0.5ms,解块(Detile,block-linear->pitch-linear)占了约 13.3ms。

Block-Linear(BL,块线性)和Pitch-Linear(PL,行线性/扫描线)是图像数据两种内存布局,之所以同时存在,根本原因在于图像处理(GPU/渲染/采样)与图像传输(显示输出/DMA/连续内存读写)在硬件缓存(Cache)命中率与总线吞吐效率上的矛盾。通常,GPU 中图像处理用 BL 布局而 CPU/显示用 PL 布局。

二 方案选择

端侧多个硬件模块支持解块,之前考虑用 GPU 解块,但是 GPU 的引入会使代码复杂,而且有“杀鸡用牛刀”的感觉:解块是固定套路的搬运活,不值得占用 GPU。最终选择片上专用硬件模块做 NV12 BL→ARGB 转换。原则就是:能下放给专用硬件的,就别让通用算力干。

新的 pipeline 如下:

图1:手关键点检测处理流程

三 调试过程遇到的坑

3.1 多平面格式跨硬件拷贝的 plane offset 陷阱

前期做视频解码后的 NV12 BL 上屏验证过程中,遇到问题:屏幕虽然能显示动画,但画面错位。

这是典型的 Y 数据对,UV 数据不对的症状。查看代码,我直接用 memcpy 把 decoder 后的 buffer 送到显示 buffer,但事实上 decoder buffer 的大小和显示 buffer 不一样:解码:[Y data][UV data],显示:[Y data][16KB pad][UV data]

根因:不同硬件模块对 NV12/NV21/I420 的 plane offset 假设不一致!这个坑在 Qualcomm UBWC、ARM AFBC 等都会遇到。

3.2 Cache 的两面性

  1. memcpy 慢了 40x:在做解码到显示 buffer 拷贝时,因为没有设置解码 buffer 的 cache enable,导致 profile 时候发现 memcpy 拷贝一帧(3.4MB)需要 5.6ms,这远慢于 CPU 内存拷贝的正常水平,调试发现是解码 buffer 属性没有 cache enable。
  2. 显示黑屏:视频解码成功,显示也没有错误,但是屏幕黑屏,无任何显示。调试发现 cache line 有数据,但内存中没有。

根因:同一个参数(cpuCache),在不同方向,表现出不同的行为:读设置错:“慢”;写设置错:“黑”。

3.3 方法论:渐进式验证

调试过程中,还有其他问题,不具体描述。实现的时候遵循纯色填充→单引擎工作→多引擎级联。

  1. 纯色填充:验证显示支持 ARGB/NV12 PL 等格式。
  2. 单引擎工作:分别验证解码/硬件颜色空间转换/显示等各硬件引擎能工作。
  3. 整个处理流程级联起来

嵌入式 GPU/VPU 等调试挂死就要重启,直接端到端联调成本极高!

四 实验结果

优化前后对比:

阶段优化前耗时(ms)优化后耗时(ms)
视频解码13.850.97
颜色空间转换(NV12->RGB)4.230.81
去Alpha planeN/A1.6
手掌模型预处理1.481.44
手掌检测推理0.710.70
手掌检测后处理0.040.04
关键点模型预处理3.453.42
关键点检测1.171.15
关键点后处理1.91.88
显示提交4.154.15(沿用之前测试数据)
总耗时30.9816.16

NOTE:受显示硬件 30Hz 限制,实际可观测帧率上限为 30fps;换 60Hz 显示硬件后预计可达 60fps。

硬件模块颜色空间转换输出的是 ARGB,比模型要的 RGB 多一个 Alpha 通道,得剥掉(1.6ms)——即便如此总账还是赚的。优化后,视频解码+颜色空间转换+去 Alpha plane=3.5ms!

dump 第 100 帧如下:

图2:第100帧手关键点检测结果

图左上角 OSD 消息显示帧率 81FPS 是没有上屏的结果。

五 心得总结

到此,MediaPipe 端侧移植和优化做阶段性总结:

  • 第一篇:移植不在翻译代码,在胶水代码
  • 第二篇:瓶颈不在模型,在等屏幕
  • 本篇:瓶颈不在解码,在解块

回头看,端侧模型优化就是不断把活儿交还给合适的硬件,

往前看,摄像头接入整个 pipeline,真正做到“实时看世界”!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询