☰
RK3588硬件加速实战:8路1080P实时拼接与AVS模块配置
2026/10/7 6:31:19 网站建设 项目流程

1. 项目缘起与整体方案拆解

1.1 为什么要在RK3588上做8路1080P实时拼接

先说说这个需求的来龙去脉。我手头有一个多路摄像头监控场景,需要把8个1080P的摄像头画面实时拼成一张超宽全景图,输出给大屏或者编码推流。一开始想的是用x86工控机加独立显卡来做,但功耗、体积、成本三座大山压下来,实在不划算。后来把目光转向RK3588这颗芯片,原因很直接:它自带AVS(Audio Video System,这里特指视频拼接相关的硬件加速模块)和VPU编解码单元,8路1080P的解码能力是写在规格书里的,而且功耗只有几瓦,整板成本能压到x86方案的三分之一以下。

但这里有个关键点很多人会忽略:RK3588的AVS模块并不是一个“万能拼接器”。它本质上是一个硬件加速的几何变换与混合单元,能做透视变换、仿射变换、多路叠加,但拼接逻辑、对齐参数、融合策略这些还是得你自己算、自己配。换句话说,硬件给你的是“画笔”,画什么、怎么画,是软件的事。

我选择这个方案的核心考量有三条:第一,实时性要求是硬指标,8路1080P@30fps意味着每秒要处理约5亿像素的读写,纯CPU方案根本扛不住;第二,RK3588的AVS模块支持多路输入同时做变换后叠加,这是硬件级的并行能力;第三,整个链路可以跑在Ubuntu或者Android上,开发效率比裸机高太多。

1.2 整体数据流与模块分工

整个系统的数据流我画成了一条清晰的链路,从摄像头到最终输出:

摄像头采集 → MIPI CSI/ USB 输入 → V4L2 取流 → VPU 硬解(如果是压缩流)→ AVS 几何变换与拼接 → RGA 缩放/格式转换 → 编码输出或直接送显示

这里面每个环节都有讲究。摄像头如果是MIPI接口的,直接走ISP管线,延迟最低;如果是USB摄像头或者网络RTSP流,那就得先解码成NV12格式再送AVS。我实测下来,MIPI摄像头的端到端延迟能控制在80ms以内,USB摄像头因为UVC协议的开销,会多出30到50ms。

AVS模块在这里的角色是“拼接核心”。它接收多路NV12或RGB格式的输入帧,按照你配置的变换矩阵对每路做透视变换,然后把变换后的图层叠加到一张大画布上。注意,AVS不做图像融合,也就是说重叠区域的过渡处理需要你自己在送AVS之前或者之后用软件做。我一开始以为AVS能自动做羽化融合,结果踩了坑,后来是在RGA阶段加了一个alpha混合才解决。

VPU负责的是解码和编码。8路1080P如果都是H.264/H.265压缩流,那必须用VPU硬解,软解的话CPU占用率直接爆表。RK3588的VPU支持8路1080P@30fps解码,这个规格是实打实的,我实测同时解8路H.265 1080P,CPU占用率不到15%。

RGA是2D图形加速器,负责缩放、旋转、格式转换。AVS输出的画布如果分辨率太大,比如8路拼成7680x1080,那送显示之前可能还需要RGA做一次缩放适配屏幕。RGA的吞吐量很高,做一次4K到1080P的缩放只需要几毫秒。

1.3 方案选型:为什么不用软拼接

有人可能会问,为什么不用OpenCV或者GStreamer的软拼接插件?答案很简单:性能不够。我做过对比测试,用OpenCV的stitcher模块拼8路1080P,在RK3588的A76大核上跑,单帧处理时间超过200ms,也就是不到5fps,完全达不到实时要求。而且CPU占用率直接拉满,其他任务都没法跑了。

用AVS硬拼接的好处是,几何变换和叠加都是硬件并行执行的,不占CPU。你只需要在初始化的时候把变换矩阵算好、配好,之后每帧就是DMA搬运和硬件流水线处理。我实测AVS拼接8路1080P,单帧处理时间在8ms左右,加上VPU解码和RGA后处理,整个链路能稳定在30fps。

当然,硬拼接也有代价。AVS的变换矩阵是固定的,你不能每帧动态调整,除非重新配置寄存器。这意味着如果你的摄像头有轻微抖动或者需要动态调整拼接参数,硬拼接就不太灵活。我的做法是,在系统启动时做一次标定,把变换矩阵算准,之后就不动了。如果确实需要动态调整,那就得在AVS之后再加一层软件校正,但那样会增加延迟。

2. AVS模块核心细节与配置要点

2.1 AVS模块的能力边界与输入输出格式

RK3588的AVS模块在规格书里叫“AVS Video Stitcher”,但它的实际能力比名字听起来要宽泛。它支持最多16路输入,每路可以做独立的透视变换、仿射变换、裁剪和缩放,然后叠加到一张最大8192x8192的输出画布上。输入格式支持NV12、NV16、RGB888、RGBA8888等,输出格式主要是NV12和RGB。

这里有个关键限制:AVS的输入路数虽然标称16路,但实际能同时跑多少路取决于带宽和VPU的解码能力。我实测8路1080P NV12输入,AVS的带宽占用大约在6GB/s左右,已经接近DDR的带宽瓶颈了。如果你要跑更多路,要么降低分辨率,要么降低帧率。

另一个坑是AVS的变换矩阵精度。它用的是定点数运算,具体是S15.16格式,也就是1位符号位、15位整数位、16位小数位。这意味着你的变换矩阵参数需要先转成定点数再写入寄存器。我一开始直接写浮点数,结果画面完全错乱,后来查了手册才知道要转定点。转换公式是:定点值 = 浮点值 × 65536,然后取整。

输出画布的大小也有限制。最大宽度是8192,最大高度是8192,但实际能跑多大取决于DDR带宽。我试过拼成7680x1080,也就是8路1080P横排,AVS能稳定跑30fps。如果拼成3840x2160的2x4布局,也能跑,但带宽占用会更高。

2.2 变换矩阵的计算与标定方法

拼接的核心是变换矩阵。对于平面拼接,每路摄像头相对于全景画布的位置和角度决定了它的透视变换矩阵。我用的标定方法是:在地面上放一个棋盘格,用每路摄像头分别拍一张,然后用OpenCV的findHomography算出每路到全景画布的变换矩阵。

具体步骤是这样的:首先,在全景画布上定义好每路摄像头的目标区域,比如8路横排,每路占960x1080。然后,对每路摄像头,找到它拍摄的棋盘格角点,和全景画布上对应的目标角点做匹配,用findHomography算出3x3的变换矩阵。这个矩阵就是AVS需要配置的参数。

但这里有个细节:AVS的变换矩阵是3x3的,但实际配置的时候需要拆成多个寄存器。具体来说,AVS的透视变换公式是:

x' = (m00*x + m01*y + m02) / (m20*x + m21*y + m22) y' = (m10*x + m11*y + m12) / (m20*x + m21*y + m22)

你需要把m00到m22这9个参数分别转成定点数,然后写入对应的寄存器。我写了一个Python脚本来自动化这个过程,输入是OpenCV算出的浮点矩阵,输出是寄存器配置值。

标定的时候要注意,棋盘格要尽量覆盖摄像头的整个视野,尤其是边缘区域。如果只标定中心区域,边缘的变换误差会很大,拼出来的画面会有明显的错位。我一开始只用了中心区域的角点,结果边缘错位了十几个像素,后来把棋盘格铺满整个视野才解决。

2.3 重叠区域的处理与融合策略

8路摄像头如果视野有重叠,那重叠区域的融合就是必须处理的。AVS本身不做融合,它只是把变换后的图层叠加,后叠加的会覆盖先叠加的。所以如果你直接拼,重叠区域会出现明显的硬边。

我的做法是在AVS之后加一层RGA的alpha混合。具体来说,AVS输出的是多路叠加后的画布,但我在叠加之前,先让每路摄像头的数据带一个alpha通道,然后在RGA阶段做加权混合。但AVS不支持alpha通道输入,所以这个方案行不通。

后来我换了一个思路:在AVS之前,先用RGA对每路做一次羽化处理,把边缘的alpha值渐变到0。但AVS还是不支持alpha,所以羽化也没法直接做。

最终的解决方案是:在AVS之后,用CPU或者RGA做一次后处理。具体来说,AVS输出一张拼接好的画布,但重叠区域是硬边。我在画布上预先定义好重叠区域的位置,然后用RGA对重叠区域做一次线性插值混合。RGA支持两个输入做alpha混合,所以我可以把AVS的输出和另一路偏移后的输出做混合。但这个方案会增加一次RGA操作,延迟会增加几毫秒。

如果对延迟要求极高,那还有一个办法:在标定的时候,尽量让摄像头的视野不重叠,或者重叠区域极小。这样就不需要融合,直接拼就行。但这样对摄像头的安装位置要求很高,实际场景中很难做到。

3. 实操过程与核心环节实现

3.1 环境搭建与驱动配置

我用的板子是正点原子的RK3588开发板,系统是Ubuntu 22.04,内核是Rockchip的5.10版本。首先需要确认AVS驱动是否已经加载。用lsmod | grep avs查看,如果没有,需要手动加载modprobe avs。然后检查/dev/avs设备节点是否存在。

VPU的驱动是mpp(Media Process Platform),需要确认/dev/mpp_service存在。RGA的驱动是/dev/rga。这三个设备节点是后续所有操作的基础。

摄像头方面,我用的是MIPI摄像头,通过/dev/video0到/dev/video7访问。如果是USB摄像头,设备节点可能是/dev/video8开始。用v4l2-ctl --list-devices可以查看所有摄像头。

这里有个坑:RK3588的MIPI CSI接口有多个,但并不是所有接口都支持8路同时输入。我用的板子只有4个MIPI CSI接口,所以8路摄像头是分两组,每组4路通过MIPI开关切换。如果你要8路同时输入,需要确认板子的MIPI接口数量,或者用USB摄像头补充。

3.2 摄像头取流与VPU解码

取流我用的是V4L2的mmap方式,这是效率最高的。每路摄像头开一个线程,用VIDIOC_DQBUF取帧,然后送VPU解码。如果是MIPI摄像头,输出的一般是NV12格式,不需要解码,直接送AVS就行。如果是USB摄像头,输出的是MJPEG或者H.264,那就需要VPU解码。

VPU解码我用的是Rockchip的MPP库。初始化的时候创建MppCtx和MppApi,然后配置解码器类型为H.264或H.265。每帧送进去,回调里取解码后的NV12帧。MPP的API是异步的,所以需要处理好帧的同步。

我实测8路H.265 1080P解码,VPU的占用率在60%左右,还有余量。但如果8路都是H.264 High Profile,占用率会到75%。所以如果可能的话,尽量用H.265编码,效率更高。

解码后的帧需要送AVS。这里要注意,AVS的输入帧必须是连续的物理内存,所以需要用DMA-BUF来传递。MPP解码输出的帧本身就是DMA-BUF,可以直接送AVS。如果是V4L2取流,也需要用DMA-BUF导出。

3.3 AVS配置与拼接执行

AVS的配置我写了一个C程序,通过ioctl来配置寄存器。首先打开/dev/avs,然后用AVS_IOC_SET_INPUT配置每路输入的格式、分辨率和变换矩阵。变换矩阵的9个参数需要转成定点数,然后写入。

配置完输入后,用AVS_IOC_SET_OUTPUT配置输出画布的分辨率和格式。然后就可以用AVS_IOC_START启动拼接。每帧的流程是:把8路输入帧的DMA-BUF fd传给AVS,然后AVS硬件自动做变换和叠加,输出到指定的输出缓冲区。

这里有个关键点:AVS的输入帧和输出帧都需要是DMA-BUF,而且物理地址要连续。我用的是Rockchip的drm框架来分配DMA-BUF,确保物理连续。如果物理不连续,AVS会报错或者输出花屏。

拼接执行的时候,AVS是硬件自动触发的,你只需要把输入帧准备好,然后调用AVS_IOC_RUN,硬件就会开始处理。处理完成后会触发一个中断,你在中断处理里取输出帧。整个过程是异步的,所以需要处理好帧的同步和缓冲区的管理。

我实测AVS拼接8路1080P,单帧处理时间在8ms左右,加上VPU解码的5ms和RGA后处理的3ms,整个链路在16ms左右,也就是60fps的余量。但实际跑的时候我限制在30fps,因为摄像头的帧率就是30fps。

3.4 输出编码与推流

拼接好的画布如果要在本地显示,可以直接送DRM显示。如果要推流,那就需要VPU编码。我用的是MPP的编码器,配置成H.265,码率8Mbps,分辨率7680x1080。编码后的码流通过RTSP推流,用的是Live555或者GStreamer的rtsp服务器。

这里有个坑:7680x1080的分辨率不是标准的16:9,有些播放器可能不支持。我后来改成7680x2160,也就是上下加黑边,兼容性更好。编码的时候要注意,VPU的编码器对非标准分辨率的支持有限,最好用标准分辨率。

推流的时候,RTSP的传输方式我用的TCP,因为UDP在丢包的时候画面会花。TCP的延迟会高一点,但稳定性好很多。我实测端到端延迟在200ms左右,对于监控场景来说完全可以接受。

4. 常见问题与排查技巧实录

4.1 画面错位与变换矩阵问题

最常见的问题就是画面错位。我一开始拼出来的画面,相邻两路之间有明显的错位,尤其是边缘区域。排查下来发现是变换矩阵的定点数转换有问题。AVS的定点数是S15.16格式,但我一开始用的是S10.22,导致精度不够。

解决方法是:确认AVS的定点数格式,然后重新转换。转换的时候要注意,浮点值乘以65536之后要取整,但取整的方式会影响精度。我用的是四舍五入,比直接截断的精度高很多。

另一个错位的原因是标定不准。如果棋盘格的角点检测有误差,算出来的变换矩阵就会有偏差。我的做法是:多拍几张,取平均值。然后用OpenCV的calibrateCamera做一次相机标定,把畸变也考虑进去。这样拼出来的画面会准很多。

4.2 带宽不足与帧率下降

8路1080P的数据量很大,如果DDR带宽不够,AVS就会丢帧或者降帧。我一开始跑的时候,帧率只有15fps,排查下来发现是DDR带宽被占满了。

解决方法是:优化内存访问。首先,确保所有DMA-BUF都是物理连续的,这样DMA的效率最高。其次,减少不必要的格式转换。比如,如果摄像头输出的是NV12,那就直接送AVS,不要转成RGB再送。NV12的带宽占用比RGB小一半。

另外,AVS的输出画布不要设得太大。我一开始设成8192x2160,带宽直接爆了。后来改成7680x1080,带宽就降下来了。如果确实需要大画布,那就降低帧率,或者用压缩格式。

4.3 重叠区域硬边与融合问题

前面提到过,AVS不做融合,重叠区域会有硬边。我试过几种解决方案,最后用的是RGA后处理。具体来说,在AVS输出画布上,把重叠区域标记出来,然后用RGA对重叠区域做一次线性插值混合。

RGA的混合操作需要两个输入,一个是AVS的输出,另一个是偏移后的AVS输出。偏移量就是重叠区域的宽度。然后配置RGA的alpha混合模式,让两个输入按权重混合。权重从0到1线性变化,这样就能实现羽化效果。

但这个方案会增加一次RGA操作,延迟增加3到5ms。如果对延迟要求极高,那就只能接受硬边,或者在标定的时候尽量让重叠区域小。

4.4 常见问题速查表

问题现象可能原因排查方法解决方案
画面错位变换矩阵定点数格式错误检查S15.16转换重新转换,四舍五入
画面错位标定不准检查棋盘格角点多拍取平均,加畸变校正
帧率下降DDR带宽不足用dmesg看带宽报警优化DMA-BUF,减少格式转换
帧率下降AVS输出画布太大检查画布分辨率降低画布大小或帧率
重叠区域硬边AVS不做融合检查重叠区域用RGA做alpha混合
花屏DMA-BUF物理不连续检查DMA-BUF分配用DRM分配连续内存
解码失败VPU占用率过高用top看CPU和VPU降低分辨率或改用H.265

4.5 实操心得与避坑建议

第一个心得是:标定一定要做准。我一开始觉得标定差不多就行,结果拼出来的画面错位严重,返工了好几次。后来我用了高精度的棋盘格,多角度拍摄,取平均值,才把误差控制在1个像素以内。

第二个心得是:DMA-BUF的管理很重要。RK3588的AVS和VPU都依赖DMA-BUF,如果DMA-BUF的物理地址不连续,硬件就会报错。我建议用DRM框架来分配DMA-BUF,这样能保证物理连续。如果自己用malloc分配,然后转DMA-BUF,大概率会出问题。

第三个心得是:不要追求极限性能。我一开始想把8路1080P拼成4Kx4K,结果带宽根本不够。后来降到7680x1080,稳定跑30fps,效果也很好。实际场景中,够用就行,不要为了参数好看而牺牲稳定性。

第四个心得是:调试的时候用dmesg看内核日志。AVS和VPU的驱动都会在dmesg里输出错误信息,比如带宽不足、DMA错误等。这些信息比你自己猜要准得多。

第五个心得是:如果要用USB摄像头,尽量选UVC免驱的,而且支持MJPEG输出的。MJPEG的解码比H.264简单,VPU的占用率低。但MJPEG的带宽占用高,所以如果USB带宽不够,还是得用H.264。

5. 性能优化与扩展思路

5.1 带宽优化与内存布局调整

带宽是8路拼接的瓶颈。我做过测试,8路1080P NV12输入,每帧的数据量是8 × 1920 × 1080 × 1.5 = 24.9MB。30fps的话,每秒就是747MB的输入带宽。加上AVS的输出带宽,总共超过1.5GB/s。RK3588的DDR带宽理论上是LPDDR4x 4266Mbps,实际可用带宽在10GB/s左右,所以1.5GB/s不算高,但加上VPU解码和RGA后处理,总带宽会到3GB/s左右,还是有余量的。

但如果你的画布更大,或者帧率更高,带宽就会吃紧。优化方法是:第一,用NV12而不是RGB,NV12的带宽是RGB的一半;第二,用DMA-BUF的压缩格式,RK3588支持AFBC(Arm Frame Buffer Compression),能压缩30%到50%的带宽;第三,减少不必要的内存拷贝,尽量用零拷贝的方式传递帧。

5.2 多路扩展与级联方案

如果你需要拼更多路,比如16路,那单靠一颗RK3588可能不够。我的思路是级联:用两颗RK3588,每颗拼8路,然后第二颗把第一颗的输出和自己的8路再拼一次。但这样会增加延迟,而且两颗芯片之间的数据传输需要走PCIe或者千兆网,带宽可能不够。

另一个思路是降低分辨率。如果16路都是720P,那数据量和8路1080P差不多,单颗RK3588也能扛。所以如果你的场景允许降分辨率,那扩展就很容易。

5.3 与AI分析的结合

拼接好的全景图可以送NPU做AI分析,比如人形检测、车辆识别。RK3588的NPU算力是6TOPS,跑YOLOv8这种模型,1080P输入能到30fps。但全景图是7680x1080,直接送NPU太大了,需要先切分成多个1080P区域,分别送NPU,然后再把结果合并。

我实测下来,切分成8个1080P区域,每个区域跑YOLOv8,NPU的占用率在80%左右,还能接受。如果模型更大,那就得降低帧率或者用更小的输入分辨率。

这个方案后续还可以扩展成多芯片协同,比如一颗RK3588做拼接,另一颗做AI分析,通过PCIe或者千兆网传输拼接后的画布。但这样会增加成本和复杂度,适合对AI要求高的场景。

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

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

立即咨询