资讯详情

资讯详情

RK3576硬件编解码实战:FFmpeg集成MPP,多路视频性能优化指南

最近在调RK3576的流媒体项目主控板上同时要接四路1080p摄像头其中一路还要实时做本地编码保存。刚开始图省事直接用CPU软解软编结果编解码进程一开CPU占用直接飙到70%以上中间业务逻辑稍微复杂一点系统就开始肉眼可见地卡顿。后来费了点功夫把FFmpeg切到Rockchip MPP硬件编解码通道上同样的负载CPU占用直接压到10%以内这个差距不是一点半点。这篇文章不是放一堆官方文档截图而是把我从编译FFmpeg到多场景实测的完整过程记录下来重点说清楚RK3576上硬件编解码的接入方式、参数怎么调、多路场景下有哪些坑以及和软解软编的性能差距到底有多大。如果你正在用RK3576做视频接入、RTSP推流、本地录像或者播放器相关的项目这篇文章应该能帮你省下不少试错的时间。1. RK3576的编解码家底先搞清楚硬件上有什么很多人在RK3576上做视频处理上来就搜FFmpeg命令结果发现同样的命令在别的板子上能硬解换到自己板子上就报错。这是因为没搞清楚一个最底层的问题硬件上到底有哪些编解码单元以及它们以什么方式暴露给上层。1.1 解码能力比想象中宽但驱动才是瓶颈RK3576用的Rockchip自研VPU方案也就是常说的Video Processing Unit集成了不少常见的视频格式解编码能力。就我手头这块板子的实际表现来看H.265、H.264、VP9、AV1这些主流格式都能解视频输出能力覆盖到4K级别日常的监控和播放需求绰绰有余。编码侧主要是H.264和H.265这也是目前RTSP推流和本地存储最常用的两种格式。但注意硬件有能力和系统能用起来是两回事。RK3576上必须依赖Rockchip MPPMedia Process Platform用户态库以及内核对VPU节点的正确枚举。如果你拿到的是精简版内核裁剪掉了相关驱动或者设备树里没配置对应节点那FFmpeg就算编译支持了MPP也会在打开设备时报类似Invalid argument或者Cant open video device的错误。我建议拿到板子后先做一件事查看/dev下有哪些video节点和media节点。ls /dev/video* /dev/media* 2/dev/null正常能看到类似/dev/video0、/dev/video1这样的节点再执行v4l2-ctl --list-devices 2/dev/null如果节点都能正常枚举说明驱动层基本没问题。否则先不要折腾FFmpeg优先去查内核配置和设备树这是很多“硬解打不开”问题的真正根源。1.2 MP通路和V4L2通路怎么选Rockchip平台上FFmpeg调用硬件编解码有两条主要通路一条是通过Rockchip MPP插件FFmpeg编译选项里对应--enable-rkmpp解码器名类似h264_rkmpp、hevc_rkmpp编码器名类似h264_rkmpp、hevc_rkmpp。另一条通路是通过内核V4L2请求API编译选项对应--enable-v4l2-request相关解码器带v4l2后缀。这条新内核更倾向但工具链要求高用起来也没MPP那套直接。我做项目时优先选MPP通道原因很简单Rockchip官方对MPP的支持一直在持续更新FFmpeg里rkmpp插件的成熟度也比较高接入成本和调试成本都更低。V4L2通道适合需要统管多种平台硬件的场景如果只是固定在RK3576上做产品直接用MPP通路是效率最高的选择。2. 编译一个能硬编硬解的FFmpeg关键配置与踩坑如果你只是用系统自带的FFmpeg大概率发现ffmpeg -decoders里没有rkmpp相关条目因为默认发行版不会把Rockchip私有库编进去。所以第一步就是自己编译。2.1 交叉编译环境与依赖准备RK3576跑Linux通常是在X86主机上做交叉编译。先准备好Rockchip提供的交叉编译工具链同时编译安装rockchip-mpp源码库。FFmpeg需要依赖MPP的库文件和头文件所以编译前要确认环境变量PKG_CONFIG_PATH能定位到MPP的pc文件。export PKG_CONFIG_PATH/opt/rk3576/sysroot/usr/lib/pkgconfig:$PKG_CONFIG_PATH export CC/opt/rk3576/bin/aarch64-rockchip-linux-gnu-gcc这个过程不难但很容易踩一个坑如果编译出来的FFmpeg在板子上运行时报找不到librockchip_mpp.so说明没有把MPP库同步到板子的/usr/lib下或者没有设置LD_LIBRARY_PATH。2.2 configure参数里最容易漏掉的两个开关FFmpeg配置时最核心的两个参数是--enable-rkmpp --enable-ffmpeg第二个参数看起来有点奇怪但它会联动开启MPP的编解码buffer管理逻辑。如果你只开了--enable-rkmpp而漏了后面那个编译时可能不会立刻报错但运行时解码帧经常会出现花屏或frame无法正常释放的问题。我第一次就是只开了rkmpp结果调试了整整一个下午最后对照官方构建脚本才发现漏了--enable-ffmpeg。完整配置命令参考如下具体路径根据你自己的目录调整./configure \ --archaarch64 \ --cross-prefixaarch64-rockchip-linux-gnu- \ --enable-cross-compile \ --target-oslinux \ --sysroot/opt/rk3576/sysroot \ --enable-rkmpp \ --enable-ffmpeg \ --enable-version3 \ --enable-gpl \ --enable-nonfree \ --enable-shared \ --disable-static我没有开启太多的第三方编解码库因为项目只需要硬解和硬编软解码器用FFmpeg自带的基本就够。你如果还要处理音频转码可以再酌情加--enable-libopus、--enable-libmp3lame这些。2.3 编译完怎么验证是真的硬解编译安装完成后先在板子上跑两个命令确认插件已经生效ffmpeg -decoders | grep rkmpp ffmpeg -encoders | grep rkmpp如果能看到h264_rkmpp、hevc_rkmpp、h264_rkmpp、hevc_rkmpp这些条目说明编译没问题。接下来拿一段H.265的视频文件做硬解测试ffmpeg -hwaccel rkmpp -c:v hevc_rkmpp -i test.hevc -f null -观察输出日志里有没有Using hardware decoding或者类似提示同时看板子CPU占用。硬解成功的情况下CPU占用率应该明显低于软解。注意如果只加-hwaccel rkmpp但解码器还是hevc实际上走的还是软解必须同时指定解码器为带rkmpp后缀的名字或者用-hwaccel rkmpp -c:v hevc手动指定不同的FFmpeg版本对自动选择硬解解码器的策略有所差别最稳妥的方式是显式指定。3. 解码链路优化从能播放到多路稳定能硬解只是第一步。真正让项目跑起来的是多路场景下的稳定性尤其是你让FFmpeg同时处理多路输入时线程模型和buffer参数直接决定了系统的表现。3.1 基础硬解命令与原理解释单路硬解H.265的命令我一般这样写ffmpeg -hwaccel rkmpp \ -c:v hevc_rkmpp \ -i input.hevc \ -c:v copy \ output.mp4这里有两层逻辑要理解-hwaccel rkmpp是告诉FFmpeg打开硬件加速框架-c:v hevc_rkmpp是解码器本身。很多人以为加了第一个参数就自动硬解其实不完全对。硬件加速框架负责申请设备上下文和buffer类型真正的帧解码还是由解码器完成的。如果只加-hwaccel rkmpp不指定解码器FFmpeg会按普通软解解码器来解硬解加速就名存实亡了。而且MPP的buffer管理比较特殊解码后的帧通常是DRM或dma-buf类型如果后面的滤镜不支持这种格式会多一次拷贝或直接报错。遇到Invalid argument时先查一下前后滤镜和编码器是否都在MPP体系内不要在中间塞一个只支持软件帧的滤镜。3.2 多路并发时的几个关键调整多路监控场景四路1080p是很常见的需求。四路同时硬解时我一开始直接起了四个FFmpeg进程结果VPU资源占用非常高偶尔还出现丢帧。后来改成单进程内用多线程或分路处理稳定性明显提升。RK3576的VPU支持多个通道并发但通道数有限而且每个通道需要固定的硬件上下文。如果你用多进程方式每个进程都去初始化一份MPP上下文底层会重复申请硬件资源容易碰到资源竞争。我的做法是用FFmpeg的filter_complex把多路输入交给一个进程统一调度或者直接基于Libavcodec写一个轻量级的多路解码循环不再每次解码都重建上下文。另外解码线程数不用多。硬解的瓶颈在VPU不在CPU线程开-threads 1就够了。开多了线程反而增加调度开销CPU占用不降反升。3.3 低延迟模式的参数选择如果你的场景是实时预览比如摄像头画面要低延迟显示那需要关注两个参数-fflags nobuffer和-flags low_delay。ffmpeg -fflags nobuffer -flags low_delay \ -hwaccel rkmpp -c:v hevc_rkmpp \ -i rtsp://your_camera/stream \ -f sdl -不过这里有个容易误解的地方解码延迟和网络传输延迟是两回事。nobuffer主要减少输入缓冲的延迟让数据尽快进入解码器low_delay减少解码器的延迟处理。但它们不会降低网络传输本身的延迟如果前端摄像头到板子这段网络已经有几百毫秒延迟这两个参数也救不回来。实际调试中我用-fflags nobuffer -flags low_delay配合RTSP over TCP从摄像头画面变化到屏幕显示延迟大约能控制在200到300毫秒。拉流协议建议优先RTSP over TCPUDP虽然更省带宽但在有丢包的网络里会产生解码卡顿反而让低延迟失去意义。4. 硬件编码调优码控、GOP与延迟的平衡RK3576的硬编码器其实很成熟但前提是你得理解它的码控特点。硬编码器和x264这类软编码器不一样它的码控算法更依赖硬件模块参数给不对出来的画质和码率会和预期差很多。4.1 一条能直接用的硬编码命令单路硬编码推流命令我项目里用的基础版是这样的ffmpeg -hwaccel rkmpp -c:v hevc_rkmpp \ -i input.hevc \ -c:v h264_rkmpp \ -b:v 2M \ -maxrate 2M \ -bufsize 4M \ -g 50 \ -r 25 \ -f rtsp rtsp://your_server/live/stream这条命令把H.265解码后重新硬编码成H.264推流。-b:v设目标码率-maxrate设峰值-g设GOP大小。对于25fps的视频-g 50意味着2秒一个关键帧比较适合弱网下的推流画面切换时最多等2秒就能恢复清晰。4.2 CBR和VBR怎么选硬编码器的码控模式通常分为CBR和VBR两种。CBR模式下码率波动小适合网络带宽稳定的RTSP推流VBR模式下码率会根据画面复杂度浮动同等平均码率下画质更好但峰值会高不少。在MPP编码器里通过-b:v和-maxrate的配合来实现近似CBR或VBRCBR-b:v 2M -maxrate 2M -bufsize 4MVBR-b:v 2M -maxrate 4M -bufsize 6MCBR的好处是带宽可控码率曲线平稳监控场景或者运营商带宽受限的场景推荐这个。VBR更适合本地录像因为存储空间有一定余量而且画面明暗变化大的场景VBR能明显保留更多暗部细节。我这里给组对比数据是同一段1080p视频在RK3576上用不同码控模式实测的参数组合平均码率峰值瞬时码率同码率下主观画质CBR 2M2.0Mbps2.1Mbps一般运动场景有块状模糊VBR 2M max 4M2.1Mbps3.8Mbps明显更好暗部细节更完整VBR 4M max 8M4.2Mbps7.5Mbps很好基本无可见块效应如果你的实际场景对画质要求高但带宽够VBR通常比CBR更值得选。4.3 GOP和编码延迟的微妙关系GOP太大关键帧间隔长同码率下画质会好一些因为码率预算可以更多地分配给普通帧。但在流媒体场景里过大GOP会让客户端切入直播流时等待很久才能等到关键帧。GOP太小比如设成1所有帧都是关键帧画质最稳但码率会翻几倍不推荐。经验值视频会议或低延迟场景用-g 25到-g 50比较合适监控录像存储场景可以适当加大到-g 100。我自己做过测试25fps视频场景下GOP从50改到100同码率下平均画质能提升3%左右但客户端拉流首帧时间大约增加0.5到1秒。执行层怎么选取决于你的业务更在乎实时性还是画质。硬编码延迟还有一个隐形因素MPP编码器内部存在帧排队。如果输入源是连续解码的摄像头帧建议保持输入帧率和编码帧率一致并开启-vsync 0或-fps_mode passthrough避免FFmpeg自动做帧率转换因为多余的帧率转换既增加延迟还会消耗CPU。5. 多场景实测监控接入、RTSP推流、本地回放的性能对比数据是最有说服力的。这次实测我把整个方案放到了三种典型场景里统一使用Linux系统、内核开启VPU驱动、FFmpeg版本为自编译的rkmpp版本。CPU占用数据通过top读取统计的是整个FFmpeg相关进程的平均占用率。5.1 多路监控接入软解和硬解完全是两种体验场景四路1080p H.265摄像头实时接入每路码率约2Mbps接入后需要实时预览和存储。软解方案四路FFmpeg进程各自软解CPU占用直接干到82%到90%之间系统整体变卡网络处理也有轻微丢包。硬解方案在同一个平台测试四路全部通过rkmpp硬解CPU占用只有9%到13%系统完全流畅剩余CPU还可以继续跑OpenCV检测或业务逻辑。方案CPU占用内存占用丢帧情况能否同时跑业务软解四路1080p82%-90%680MB偶尔丢帧很吃力MPP硬解四路1080p9%-13%510MB无丢帧完全没问题这里内存下降没有CPU那么夸张原因是VPU解码后需要分配帧buffer给业务层访问这部分内存省不掉。但CPU资源释放带来的收益是巨大的这也是为什么多路监控项目一定要用硬解的原因。5.2 RTSP推流软编码和硬编码的实际差距场景一路1080p摄像头画面解码后硬编码H.264推送到RTSP服务器目标码率2Mbps25fps。软编码用的是FFmpeg内置的libx264preset设置为veryfast硬编码用h264_rkmpp。两者对比结果让我比较意外的是硬编码在CPU占用上的优势太明显了但画质上并没有因为硬件编而明显缩水。编码方式CPU占用平均码率主观画质libx264 veryfast38%-45%2.0Mbps较好暗部轻微噪声h264_rkmpp5%-8%2.1Mbps较好暗部细节保留不错从数据看硬编码已经完全可以用在推流场景里。唯一需要注意的是硬编码器对极端低码率的容忍度不如x264如果非要压到500kbps以下硬编码会出现明显的块状模糊这时候还得考虑适当提升码率或者切换GOP策略。5.3 本地4K录像回放硬解的优势更明显场景播放一段4K H.265本地视频文件时长3分钟要求流畅播放。软解4K H.265对于RK3576的压力不小CPU占用大约在70%左右帧率勉强到30fps画面偶尔有卡顿。硬解模式下CPU占用降到18%帧率稳定满帧60fps播放非常丝滑。播放模式CPU占用帧率画面表现软解4K H.26570%28-32fps偶尔卡顿MPP硬解4K H.26518%58-61fps稳定流畅如果你要做一个RK3576平台的本地播放器这组数据很直观解码能力不做硬解4K体验基本不可能合格。5.4 综合对比后的几个直接结论三组测试下来我可以直接给出几个结论解码场景硬解是必选项不是可选项。多路监控和4K播放软解在RK3576上基本承载不了业务逻辑。编码场景硬编完全可以替代软编。特别是单路1080p推流画质差距很小CPU节省却非常可观。CPU释放出来的算力是额外收益。我后来在硬解硬编的基础上还跑了轻量级的移动侦测算法整机CPU占用控制在30%以内这在软解方案里是完全不敢想的。6. 实操中容易被坑的细节与后续扩展最后这部分把我在项目里遇到过的坑集中整理一下这些内容官方文档里基本没有但不处理就会反复消耗你的时间。6.1 RGA和NV12颜色格式的适配问题MPP解码输出的默认格式通常是NV12如果你的叠加模块或编码输入需要RGBA格式需要经过一次转换。RK3576上有专门的RGARaster Graphic Acceleration硬件加速模块可以在FFmpeg里通过hwupload_cuda类似的思路但Rockchip这边更多是调用librga或MPP内部的格式转换能力。我在做人脸检测框叠加时因为输出格式不统一画面上出现了严重的颜色偏色排查到最后才发现是解码输出的色域是BT.709而叠加模块默认按BT.601处理。解决办法是统一色域矩阵或者在FFmpeg里显式加-color_primaries bt709 -color_trc bt709 -colorspace bt709。别小看这几个参数不显式指定时FFmpeg默认会采用BT.601而硬件解码输出往往是BT.709颜色就容易飘。6.2 设备树配置对编解码的隐性影响RK3576的设备树如果不配置VPU和RGA节点系统大概率枚举不到video节点。有一个很容易遇到的问题设备树配置了节点但MMU相关属性没开硬解小分辨率视频没问题一旦上到4K分辨率系统直接报内存错误。使用MPP硬解涉及连续物理内存和iommu映射设备树里通常需要确认iommus属性是否正确引用。这个排查起来很隐蔽因为小分辨率视频能跑通会让你以为硬件没问题。我的建议是全链路测一遍从1080p到4K的素材一旦出现内存类报错先把设备树里iommu和内存配置对齐官方SDK。6.3 多路并发时用多进程还是多线程这个前面提到过这里再系统地记录一下优劣对比。多进程方案实现简单进程隔离安全但每进程都初始化MPP上下文资源占用大且VPU通道竞争严重。多线程或单进程多路复用方案占用资源小稳定性好但代码复杂度高需要自己处理输入源调度和buffer生命周期。方案实现难度资源占用稳定性适用场景多进程低高一般功能验证、快速原型单进程多路复用高低高产品化、长期稳定运行我最终在项目里选择单进程多路复用架构虽然前期编码时间多了几天但后期稳定性省了很多维护成本。6.4 后续可以从哪些方向继续深挖这个方案稳定跑起来之后还有很多可以继续深挖的点多路4K解码能力边界测试。RK3576标称的能力和实际可用的能力之间还有距离我目前只验证到四路1080p如果你要做8路甚至16路接入需要仔细测试VPU通道数的上限和内存带宽瓶颈。AV1硬解的实际效果。RK3576支持AV1解码这对在线播放场景很有价值流媒体平台已经开始大量使用AV1硬解AV1能进一步降低带宽成本。结合NPU做智能分析。RK3576自带NPU解码后输出NV12可以零拷贝送到NPU做推理这样整个视频接入到智能分析的链路都不会占用太多CPU是做一个智能监控网关的理想架构。我在实际使用中还有一个比较深的体会硬件编解码调通只是开始真正决定项目能不能交付的是格式、颜色、分辨率、内存这些细节的匹配。建议你拿到RK3576第一周先不要急着写业务逻辑把所有编解码链路、格式转换链路、颜色属性全部验证一遍做一份自己平台的参数表。后面做任何功能时照着参数表配置能省下大量排查问题的时间。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →