RK3588 MPP解码句柄泄露问题记录

1. 问题背景

最近在用瑞芯微3588开发板做一个视频处理的项目,前两天拷机发生了闪退,弹出的问题是“打开文件过多”,经过初步排查定位到是MPP硬解码部分出的问题。

我的MPP解码部分主要用来读取网络相机rtsp流,主要参考了一个github项目GitHub - MUZLATAN/ffmpeg_rtsp_mpp: ffmpeg 拉取rtsp h264流, 使用mpp解码, 目前在firefly 板子上跑通了

 我将它封装成C++类的形式,方便使用。最开始使用是没有问题的,但是在我加了一个相机异常处理机制的时候,就出现了“打开文件过多”的问题。这个相机异常处理机制主要是解决相机未连接、断电重连的时候,软件依然正常运行,而且在相机重连之后可以重新读取画面,而软件不需要重启。

我的解决办法是,如果检测到无法从相机获取数据了,就调用析构函数释放掉解码器(我封装的那个类),然后重新实例化解码类尝试连接相机。那个项目里,获取相机数据采用的是ffmpeg的av_read_frame然后用mpp调用硬件进行解码。

if (av_read_frame(pFormatCtx, av_packet) < 0) //从相机获取数据
    {
        printf("av_read_frame get packet failed!");
        return -1;
    }

 在我尝试多次插拔相机之后,软件就出现了文章开头的问题:打开文件过多。

2. 问题现象及分析

问题现象主要分为两种,一种是相机一直连接或者一直不连接,这样软件不会出现问题;第二种是相机时而连接,时而不连接,就会导致“文件打开过多”。

经过查阅,得知rk3588开发板的每个进程最多能打开1024个文件

利用lsof指令实时监控软件打开的文件数

lsof -p 进程号 | wc -l

发现打开的文件数量确实在一直上涨,而且也确实发生在插拔相机的时候。但是现在并不清楚到底泄露了什么资源,可以进一步查看进程具体打开了哪些文件

查看软件打开的文件:

ls -l /proc/进程id/fd

 可以看出来,每次插拔相机都导致一个mpp_service和若干个dmabuf增加,也就是泄露。

所以,原因应该也很明显了,就是解码器释放的时候没有完全释放掉资源,下面就需要排查代码了。

3. 问题解决

启动人眼搜索大法,一行行排查代码,看到疑似申请了资源的代码都详细查看一下

最后定位到两个函数:

 第一个函数mpp_create会申请mpp services,是导致mpp_services泄露的根源;

第二个函数mpp_buffer_group_get会申请缓冲区暂存解码出来的图像。

在两个函数头文件声明的地方,也都发现了相应的释放函数:

添加到析构函数中,问题解决~

4. 总结

这么想来,RAII真是福音,修改后的代码已放到这儿了

MPP解码icon-default.png?t=N5F7https://download.youkuaiyun.com/download/a1367666195/87925718?spm=1001.2014.3001.5503

<think> 我们正在讨论RK3588 MPP框架下进行MJPEG解码的相关内容。根据用户提供的引用资料,我们可以总结以下关键点: 1. 引用[1]和[3]提到了官方解码demo `mpi_dec_test`,这是一个用于演示MPP解码流程的示例程序。 2. 引用[3]明确指出MppCodingType中`MPP_VIDEO_CodingMJPEG`对应MJPEG编解码格式。 3. 引用[4]详细说明了MPP解码的分帧处理,特别是通过`MPP_DEC_SET_PARSER_SPLIT_MODE`设置按帧输入码流。 因此,使用RK3588 MPP进行MJPEG解码的核心步骤应包括: - 初始化MPP上下文 - 设置解码器类型为`MPP_VIDEO_CodingMJPEG` - 配置分帧模式(对于MJPEG流可能需要) - 输入MJPEG数据包并获取解码后的帧 具体实现可参考`mpi_dec_test`示例,以下是关键步骤的伪代码: ```c // 创建MPP上下文 MppCtx ctx; MppApi *mpi; mpp_create(&ctx, &mpi); // 初始化解码MppCodingType coding = MPP_VIDEO_CodingMJPEG; mpi->init(ctx, MPP_CTX_DEC, coding); // 设置分帧模式(按帧输入) RK_U32 split_mode = 1; // 1表示按帧输入 mpi->control(ctx, MPP_DEC_SET_PARSER_SPLIT_MODE, &split_mode); // 输入数据循环 while (有数据输入) { // 获取空数据包 MppPacket packet; mpp_packet_init(&packet, data, size); // 解码数据包 mpi->decode_put_packet(ctx, packet); // 获取解码MppFrame frame; if (mpi->decode_get_frame(ctx, &frame) == MPP_OK) { if (frame) { // 处理解码后的帧(如保存为YUV等) // ... mpp_frame_deinit(&frame); // 释放帧 } } mpp_packet_deinit(&packet); // 释放数据包 } ``` 注意事项: 1. MJPEG是静态图像压缩标准,解码时将得到独立的帧序列。 2. 输入数据格式需符合JPEG标准,通常以完整的JPEG图像为单位输入。 3. 输出帧格式通常为YUV420SP,可通过`mpp_frame_get_fmt(frame)`获取具体格式。 技术资料可参考: - Rockchip MPP开发文档(需向Rockchip申请) - `mpi_dec_test`源码(位于RK3588 SDK的`mpp/test`目录) - `/usr/local/include/rockchip/`下的头文件(引用[2]) 相关问题: 1. 如何配置RK3588 MPP以支持MJPEG编码? 2. MPP解码MJPEG时如何设置输出图像格式? 3. RK3588的MJPEG硬件解码支持哪些分辨率? </think> 基于提供的引用资料,以下是RK3588 MPP实现MJPEG解码的技术要点和使用方法: ### 一、MJPEG解码核心流程 1. **初始化解码器** ```c MppCtx ctx; MppApi *mpi; mpp_create(&ctx, &mpi); // 创建MPP上下文 mpi->init(ctx, MPP_CTX_DEC, MPP_VIDEO_CodingMJPEG); // 指定MJPEG格式[^3] ``` 2. **配置分帧模式**(关键步骤) ```c RK_U32 need_split = 1; // 启用分帧模式 mpi->control(ctx, MPP_DEC_SET_PARSER_SPLIT_MODE, &need_split); // 按帧输入码流[^4] ``` 3. **数据输入与解码** ```c MppPacket packet; mpp_packet_init(&packet, input_data, data_size); // 输入JPEG数据 mpi->decode_put_packet(ctx, packet); // 提交解码 MppFrame frame; while (MPP_OK == mpi->decode_get_frame(ctx, &frame)) { if (frame) { // 获取解码后的YUV数据 void *buf = mpp_frame_get_buffer(frame); // 处理解码帧... } } ``` ### 二、关键技术要点 1. **编码格式指定** 必须设置`MppCodingType`为`MPP_VIDEO_CodingMJPEG`[^3],这是MJPEG解码的标识符。 2. **分帧处理** - 对于MJPEG等图像编码,需通过`MPP_DEC_SET_PARSER_SPLIT_MODE`强制分帧 - 参数`need_split=1`确保按完整帧处理[^4] - 规避错误:若未启用分帧,可能返回`MPP_ERR_STREAM`错误 3. **数据流要求** - 输入数据必须包含完整的JPEG帧头 (`0xFFD8`开头)和帧尾(`0xFFD9`) - 建议单次提交一帧完整JPEG数据(典型应用于摄像头抓拍场景) ### 三、开发资源 1. **头文件路径** ```bash /usr/local/include/rockchip/mpp_frame.h # 帧操作API /usr/local/include/rockchip/mpp_packet.h # 数据包操作[^2] ``` 2. **官方参考实现** - `mpi_dec_test`示例程序(位于SDK的`mpp/test`目录)[^1] - 编译命令:`cmake -DHAVE_JPEGDEC=ON` 启用JPEG解码支持 3. **硬件平台验证** - 推荐使用ArmSoM-W3开发板进行测试[^1] - 输出验证:可通过`v4l2-ctl`工具抓取YUV数据帧 ### 四、常见问题解决方案 1. **解码失败排查** - 检查`mpp_init()`前是否设置分帧模式 - 验证输入数据是否包含完整JPEG帧 - 使用`mpp_log.h`输出解码状态[^2] 2. **性能优化** - 启用硬件加速:确认内核启用`VDPU_S`驱动 - 零拷贝优化:通过`mpp_buffer.h`的`MPP_BUFFER_TYPE_ION`直接访问物理内存 > 注:完整实现参考Rockchip官方SDK中的`mpi_dec_test.c`,重点关注`dec_decode()`函数流程[^1][^3]。 --- ###
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值