硬件加速编解码:NVENC、QSV 与 RK3588 MPP
硬件加速编解码NVENC、QSV 与 RK3588 MPP软件编解码 CPU 占用高实时处理多路视频很吃力。硬件加速用 GPU/NPU 来编解码速度快几倍甚至几十倍CPU 占用还极低。这篇讲三种主流硬件加速方案NVIDIA NVENC/NVDEC、Intel QSV、以及 RK3588 的 MPP命令行和 SDK 用法都覆盖。大家好我是黒漂技术佬。做售货柜项目的时候一开始我用软解码跑 YOLORK3588 的 CPU 占满了还卡。后来切到 RKMPP 硬件解码CPU 占用直接降到 10% 以下同时还能跑识别算法体验完全不一样。硬件加速是嵌入式和实时视频处理的必修课。这篇把主流的硬件加速方案讲清楚重点讲 RK3588 的 MPP——毕竟做 AIoT 项目用得最多。一、硬件加速是什么软件编解码CPU 跑算法通用但慢。硬件编解码专用的硬件模块VPU/GPU/NPU来做专门的电路跑编解码速度快、功耗低、CPU 占用少。常见硬件加速方案方案厂商适用设备NVENC / NVDECNVIDIA桌面/服务器 NVIDIA 显卡QSVIntelIntel 核显VA-API开源标准AMD、Intel 显卡LinuxVideoToolboxApplemacOS / iOSMediaCodecGoogleAndroidRKMPP瑞芯微RK3588 / RK3568 等 ARM 开发板AMCodec晶晨Amlogic 芯片二、怎么确认支不支持硬件加速命令行查看支持的编码器ffmpeg-encoders|grepnvenc ffmpeg-encoders|greph264看到h264_nvenc、hevc_nvenc就说明支持 NVIDIA 硬件编码。RK3588 上ffmpeg-encoders|greprkmpp有h264_rkmpp、hevc_rkmpp就是支持。查看解码器ffmpeg-decoders|greph264看有没有h264_cuvidNVIDIA 硬解、h264_rkmppRK 硬解。三、命令行用法1. NVIDIA NVENC/NVDEC硬件编码# H.264 硬件编码ffmpeg-iinput.mp4-c:vh264_nvenc-crf23output.mp4# H.265 硬件编码ffmpeg-iinput.mp4-c:vhevc_nvenc-crf28output.mp4硬件解码 硬件编码全硬解ffmpeg-hwaccelcuda-iinput.mp4-c:vh264_nvenc-crf23output.mp4-hwaccel cuda用 CUDA 硬解码解码后数据还在 GPU 显存里直接送给 NVENC 编码不经过 CPU速度最快。NVENC 常用参数ffmpeg-iinput.mp4-c:vh264_nvenc-presetp4-rcvbr-cq23-b:v2M output.mp4-presetp1最快到 p7最慢压缩最好-rc码率控制模式vbr / cbr / cq-cq恒定质量类似软编的 CRF2. Intel QSV# 硬解 硬编ffmpeg-hwaccelqsv-iinput.mp4-c:vh264_qsv-presetmedium output.mp43. RK3588 MPP重点这是做嵌入式 AIoT 最常用的。硬件编码ffmpeg-iinput.mp4-c:vh264_rkmpp-b:v2M output.mp4硬件解码ffmpeg-hwaccelrkmpp-iinput.mp4-c:vlibx264-crf23output.mp4全硬件转码硬解 硬编ffmpeg-hwaccelrkmpp-iinput.mp4-c:vh264_rkmpp-b:v2M output.mp4解码和编码都走硬件CPU 占用极低。RTSP 硬解录制售货柜项目里我最常用的命令ffmpeg-hwaccelrkmpp-rtsp_transporttcp-irtsp://摄像头地址-c:vh264_rkmpp-b:v1M-c:acopy-fsegment-segment_time1800record/%Y%m%d_%H%M%S.mp4硬解硬编一路 1080p 30fps 录像CPU 占用不到 5%。四、硬件解码的零拷贝硬件解码出来的帧在显存/硬件内存里如果还要硬件编码或者送 NPU 推理可以不拷到 CPU 内存直接在硬件层传递这就是零拷贝。像素格式硬解出来的帧像素格式和软解不一样平台硬解像素格式NVIDIA CUDAAV_PIX_FMT_CUDARKMPPAV_PIX_FMT_DRM_PRIMEQSVAV_PIX_FMT_QSV如果要做图像处理比如送给 YOLO还是得转到 CPU 内存的 YUV 或 RGB这一步有拷贝开销。但如果只是转码硬解→硬编数据一直在硬件里速度极快。五、SDK 开发硬件解码RKMPP 硬解代码RK3588 上用硬件解码和软解代码几乎一样只是多了设置 hwaccel 的步骤。AVFormatContext*fmt_ctxNULL;AVCodecContext*dec_ctxNULL;AVBufferRef*hw_device_ctxNULL;// 1. 初始化硬件设备av_hwdevice_ctx_create(hw_device_ctx,AV_HWDEVICE_TYPE_DRM_PRIME,NULL,NULL,0);// 2. 找解码器和软解一样constAVCodec*decoderavcodec_find_decoder(AV_CODEC_ID_H264);// 3. 创建解码器上下文dec_ctxavcodec_alloc_context3(decoder);avcodec_parameters_to_context(dec_ctx,fmt_ctx-streams[video_idx]-codecpar);// 4. 绑定硬件设备dec_ctx-hw_device_ctxav_buffer_ref(hw_device_ctx);// 5. 打开解码器avcodec_open2(dec_ctx,decoder,NULL);解码流程和软解完全一样send_packet → receive_frame。拿到的 frame 的像素格式是AV_PIX_FMT_DRM_PRIME数据在硬件内存里。硬件帧转 CPU 内存如果需要处理像素数据比如送 YOLO需要把硬件帧下载到 CPUAVFrame*hw_frameav_frame_alloc();AVFrame*sw_frameav_frame_alloc();avcodec_receive_frame(dec_ctx,hw_frame);// 拿到硬件帧// 分配软件帧sw_frame-formatAV_PIX_FMT_YUV420P;sw_frame-widthhw_frame-width;sw_frame-heighthw_frame-height;av_frame_get_buffer(sw_frame,0);// 硬件帧拷贝到 CPUav_hwframe_transfer_data(sw_frame,hw_frame,0);sw_frame就是普通的 YUV 帧了可以正常处理。NVIDIA CUDA 硬解流程类似只是设备类型换成AV_HWDEVICE_TYPE_CUDAav_hwdevice_ctx_create(hw_device_ctx,AV_HWDEVICE_TYPE_CUDA,NULL,NULL,0);六、SDK 开发硬件编码和软编码也差不多编码器选硬件的就行。constAVCodec*encoderavcodec_find_encoder_by_name(h264_rkmpp);// 或者 NVIDIA: avcodec_find_encoder_by_name(h264_nvenc)AVCodecContext*enc_ctxavcodec_alloc_context3(encoder);enc_ctx-width1280;enc_ctx-height720;enc_ctx-pix_fmtAV_PIX_FMT_YUV420P;enc_ctx-time_base(AVRational){1,30};enc_ctx-bit_rate2000000;avcodec_open2(enc_ctx,encoder,NULL);编码流程和软编一样send_frame → receive_packet。全硬件编码输入也是硬件帧如果输入帧是硬件解码出来的DRM_PRIME 格式可以直接送给硬件编码器零拷贝。// hw_frame 是硬解出来的 DRM_PRIME 帧enc_ctx-pix_fmtAV_PIX_FMT_DRM_PRIME;// 编码器接受硬件帧// ...avcodec_send_frame(enc_ctx,hw_frame);// 直接送不经过 CPU硬解 → 硬编全程数据在硬件里CPU 几乎不干活。七、怎么判断用没用上硬件加速很多人以为加了参数就是硬解硬编了其实不一定。教你几个验证方法。方法 1看 CPU 占用转码的时候 CPU 占用很高比如 100%那肯定是软解。硬解硬编的话 CPU 占用应该很低个位数到十几。方法 2看 FFmpeg 输出日志加-v debug看日志里有没有硬件相关的输出ffmpeg-vdebug-hwaccelrkmpp-iinput.mp4-fnull -有rkmpp、drm相关的日志就是用上了。方法 3看像素格式代码里打印解码后的 frame-format看是不是硬件格式printf(像素格式: %s\n,av_get_pix_fmt_name(frame-format));输出drm_prime、cuda、qsv就是硬解输出yuv420p就是软解。方法 4RK3588 上看 mpp 进程cat/sys/kernel/debug/rkvenc/status或者用top看有没有 mpp_service 进程在跑。八、硬件加速的坑坑 1以为支持其实不支持不是所有 FFmpeg 编译版本都带硬件加速。很多发行版默认的 FFmpeg 是纯软件的需要自己编译带硬件支持的版本。解决ffmpeg -hwaccels查看支持的硬件加速类型。坑 2硬解不支持某些格式硬件解码器支持的格式有限比如某些老的编码格式、非主流分辨率硬解不支持就会失败或者自动回退到软解。解决加错误处理硬解失败就降级软解。坑 3像素格式不匹配硬解出来是 DRM_PRIME你直接当 YUV 读数据全错。解决检查 frame-format需要的话用av_hwframe_transfer_data转。坑 4RK3588 编码码率控制不准RKMPP 的 CBR 模式码率波动比较大尤其是场景切换的时候。解决根据实际场景调参数或者用 VBR 模式。坑 5多路硬解有数量限制RK3588 硬解最多同时几路是有限制的一般 4-8 路 1080p开多了会失败。解决控制并发路数超过的走软解或者用其他方案。九、性能对比RK3588 实测我在 RK3588 上实测的 1080p H.264 转码数据方案速度CPU 占用软解 软编libx264~8fps100%8核占满硬解 软编~15fps~60%软解 硬编~20fps~40%硬解 硬编实时 30fps10%差距非常大。做嵌入式实时视频处理硬解硬编是必须的。十、硬件加速选型建议桌面/服务器有 NVIDIA 显卡 → NVENC/NVDEC性能最强Intel CPU → QSV核显就能用性价比高AMD → VA-API嵌入式/ARMRK3588/RK3568 → RKMPPAIoT 首选树莓派 → 用 MMAL 或 V4L2性能一般其他 ARM → 看芯片厂商有没有 FFmpeg 补丁开发建议先写软解软编版本跑通逻辑再加硬件加速支持作为性能优化保留软解软编作为 fallback硬解失败自动降级不同平台用编译宏或运行时检测来切换十一、本篇小结硬件加速编解码速度快、CPU 占用低实时处理必备主流方案NVIDIA NVENC、Intel QSV、RKMPP嵌入式命令行用法-hwaccel xxx硬解-c:v xxx_xxx硬编SDK 开发多一步 hwdevice 初始化其他和软解软编差不多硬解帧是硬件像素格式DRM_PRIME/CUDA要处理像素需转 CPU硬解→硬编可以零拷贝性能最优验证方法看 CPU 占用、看像素格式、看日志坑不是所有版本都支持、格式有限制、多路有限制下一篇讲性能优化最佳实践多线程、零拷贝、管道复用、减少编码次数——让你的 FFmpeg 处理速度再上一个台阶。我是黒漂技术佬。