保姆级教程:在ArmSoM-W3开发板上用QT+MPP搞定四路RTSP硬解码(附FFmpeg拉流代码)

发布时间:2026/6/11 8:19:32

保姆级教程:在ArmSoM-W3开发板上用QT+MPP搞定四路RTSP硬解码(附FFmpeg拉流代码) 基于RK3588的四路RTSP硬解码全流程实战从FFmpeg拉流到QT显示拿到ArmSoM-W3开发板的第一时间很多开发者都会想验证其强大的视频处理能力。四路1080P实时视频解码正是RK3588的典型应用场景之一但实际开发中常会遇到FFmpeg交叉编译困难、MPP接口调用晦涩、RGA格式转换异常等问题。本文将用最简化的代码和清晰的流程带你完整实现FFmpeg拉取RTSP流并解封装MPP硬解码YUV数据RGA图像格式转换QT多窗口渲染1. 开发环境准备1.1 硬件清单ArmSoM-W3开发板RK3588芯片支持H.264/H.265的4路RTSP源如IPC摄像头5V/4A电源适配器散热风扇持续解码建议加装1.2 软件依赖# 基础依赖库 sudo apt install build-essential cmake git # QT环境 sudo apt install qtbase5-dev qtmultimedia5-dev # FFmpeg基础库 sudo apt install libavcodec-dev libavformat-dev libswscale-dev注意建议使用ArmSoM提供的Ubuntu 20.04镜像已预装部分驱动2. FFmpeg交叉编译与拉流实现2.1 定制化编译FFmpegRK3588需要启用特定的硬件加速选项git clone https://git.ffmpeg.org/ffmpeg.git cd ffmpeg ./configure \ --enable-shared \ --enable-rkmpp \ --enable-libdrm \ --archaarch64 \ --target-oslinux make -j$(nproc) sudo make install2.2 RTSP拉流核心代码AVFormatContext *pFormatCtx avformat_alloc_context(); AVDictionary *options nullptr; av_dict_set(options, rtsp_transport, tcp, 0); // 强制TCP传输 av_dict_set(options, stimeout, 5000000, 0); // 5秒超时 const char *url rtsp://192.168.1.100/live/main; if(avformat_open_input(pFormatCtx, url, nullptr, options) 0) { qDebug() Failed to open RTSP stream; return; } AVPacket *pkt av_packet_alloc(); while(av_read_frame(pFormatCtx, pkt) 0) { if(pkt-stream_index video_stream_idx) { emit newPacket(pkt); // 通过信号传递到解码线程 } av_packet_unref(pkt); }常见问题解决花屏问题添加av_dict_set(options, fflags, nobuffer, 0)高延迟尝试av_dict_set(options, tune, zerolatency, 0)3. MPP硬解码实战3.1 MPP初始化流程MppCtx ctx nullptr; MppApi *mpi nullptr; mpp_create(ctx, mpi); mpp_init(ctx, MPP_CTX_DEC, MPP_VIDEO_CodingAVC); // H.264解码 mpp_set_prop(ctx, MPP_DEC_SET_EXT_BUF_GROUP, enable); // 启用外部缓冲 mpp_set_prop(ctx, MPP_DEC_SET_INFO_CHANGE_READY, ready_callback);3.2 解码循环实现MppPacket packet nullptr; MppFrame frame nullptr; // 将FFmpeg的AVPacket转为MPP输入 mpp_packet_init(packet, pkt-data, pkt-size); mpp_packet_set_pts(packet, pkt-pts); // 送入解码器 mpi-decode_put_packet(ctx, packet); // 获取解码结果 while(MPP_OK mpi-decode_get_frame(ctx, frame)) { if(frame) { processDecodedFrame(frame); // 处理解码后数据 mpp_frame_deinit(frame); // 释放帧 } }关键参数说明参数类型说明MPP_VIDEO_CodingAVC枚举H.264解码类型MPP_VIDEO_CodingHEVC枚举H.265解码类型MPP_DEC_SET_PARSER_SPLIT_MODE属性设置分片模式4. RGA图像处理技巧4.1 YUV420SP转RGB888#include rga/RgaApi.h rga_info_t src, dst; memset(src, 0, sizeof(rga_info_t)); memset(dst, 0, sizeof(rga_info_t)); // 配置源图像MPP输出 src.fd -1; src.virAddr yuv_data; src.mmuFlag 1; src.rotation 0; // 配置目标图像QT输入 dst.fd -1; dst.virAddr rgb_buf; dst.mmuFlag 1; // 执行转换 c_RkRgaBlit(src, dst, nullptr);4.2 常见转换模式转换类型RGA格式标识典型用途NV12转RGBRK_FORMAT_YCbCr_420_SP → RK_FORMAT_RGB_888QT直接显示缩放格式转换SRC_1080P → DST_720P画质适配旋转镜像RGA_TRANSFORM_ROT_90 FLIP_H特殊视角调整5. QT多路显示方案5.1 基于QLabel的简易实现QPixmap pixmap QPixmap::fromImage(QImage( rgb_data, width, height, QImage::Format_RGB888)); ui-label1-setPixmap(pixmap.scaled( ui-label1-size(), Qt::KeepAspectRatio));5.2 高性能OpenGL方案class VideoWidget : public QOpenGLWidget { protected: void paintGL() override { glClear(GL_COLOR_BUFFER_BIT); glDrawPixels(width, height, GL_RGB, GL_UNSIGNED_BYTE, rgb_data); } };性能对比方案CPU占用延迟适用场景QLabel15%~20%50~100ms快速原型开发OpenGL5%~8%30ms生产环境6. 项目优化建议线程模型设计单拉流线程 四解码线程 一显示线程使用QSharedPointer管理帧数据生命周期零拷贝优化// MPP与RGA共享内存 mpp_buffer_group_get_external(group, rga_buffer);动态码流适配if(av_packet-flags AV_PKT_FLAG_KEY) { mpi-reset(ctx); // 关键帧重置解码器 }实际测试中四路1080P30fps解码时RK3588的CPU占用约为40%温度控制在65℃以下。建议通过cat /sys/kernel/debug/mpp/dec_status实时监控解码状态。

相关新闻