RK-MPP硬件编解码库介绍和使用

一、下载RK-MPP硬件编解码库

        下载链接:https://github.com/rockchip-linux/mpp

二、RK-MPP库介绍

        1、资料来源:MPP 开发参考.pdf

        2、MPP说明

        MPP(Media Process Platform )是rk提供的一款硬件编解码库,为用户空间屏蔽了复杂的底层操作,通过MPP提供了一组MPI接口,用户通过MPI接口来实现媒体处理

        MPP提供的功能包括:

         视频解码

         H.265 / H.264 / H.263 / VP9 / VP8 / MPEG-4 / MPEG-2 / MPEG-1 / VC1 / MJPEG

         视频编码

         H.264 / VP8 / MJPEG

         视频处理

         视频拷贝,缩放,色彩空间转换,场视频解交织(Deinterlace)

        3、mpp系统框架

        4、MPP库的MPI接口介绍 

                

         5、MPI数据结构说明

        MppMem 为 C 库 malloc 内存的封装。

        MppBuffer 为硬件用的 dmabuf 内存的封装。

        MppPacket 为一维缓存封装,可以从 MppMem 和 MppBuffer 生成,表示码流数据。

        MppFrame 为二维帧数据封装,可以从 MppMem 和 MppBuffer 生成,表示图像数据。

        使用 MppPacket 和 MppFrame 就可以简单有效的完成一般的视频编解码工作。

        以视频解码为例,码流输入端把地址和大小赋值给 MppPacket,通过 put_packet 接口输入,在输出端通过 get_frame 接口得到输入图像 MppFrame,即可完成最简单的视频解码过程。

        6、解码流程示例

 5b73bb9aa28df76f3bf30ebae310b6aa.png

三、RK-MPP库工具介绍与使用

        1、MPP测试工具说明

        MPP 提供了一些单元测试用的工具程序,这种程序可以对软硬件平台以及 MPP 库本身进行测试

        mpp_info_test

        用于读取和打印 MPP 库的版本信息,在反馈问题时,可以把打印出来信息附上。

        mpp_buffer_test

        用于测试内核的内存分配器是否正常。

        mpp_mem_test

        用于测试 C 库的内存分配器是否正常。

        mpp_runtime_test

        用于测试一些软硬件运行时环境是否正常。

        mpp_platform_test

        用于读取和测试芯片平台信息是否正常

        2、交叉编译MPP库

        unzip mpp-develop.zip && cd mpp-developab473bb6d94757e60efd3320e93de993.png

        cd build/linux/aarch64(根据平台选择) && vim arm.linux.cross.cmake(看下是否是对应平台的交叉编译工具)

d30f998ff1f057414c83d0c01f1ddb24.png        3、./arm.linux.cross.cmake && make,编译之后,动态库在mpp目录下,测试工具在test目录下 

fa4ae183ac5c5c0a27e05b517d026e35.png

45692a1ce3d6dd24d5f885740cd56925.png

        4、将工具和动态库push到rk的平台上(一般rk的平台都已经自带MPP动态库了),以解码为例执行./mpi_dec_test -t 7 -i /sdcard/tennis200.h264 -n 10

        -t 7 表示是 H.264 码流, -i 表示输入文件, -n 10 表示解码 10 帧,如果一切正常,会得到如下的结果:

四、仿照mpi_dec_test.c 写一个最简单的解码demo 

#include <string.h>
#include "rk_mpi.h"
#include "mpp_mem.h"
#include "mpp_env.h"
#include "mpp_time.h"
#include "mpp_common.h"
#include "mpi_dec_utils.h"
#include "utils.h"

typedef struct 
{
    MppCtx          ctx;
    MppApi          *mpi;
    RK_U32          eos;
    char            *buf;
 
    MppBufferGroup  frm_grp;
    MppPacket       packet;
    size_t          packet_size;
    MppFrame        frame;
 
    FILE            *fp_input;
    FILE            *fp_output;
    RK_S32          frame_count;
    RK_S32          frame_num;
    size_t          max_usage;
} MpiDecLoopData;

static int decode_simple(MpiDecLoopData *data)
{
    RK_U32 pkt_done = 0;
    RK_U32 err_info = 0;
	
    MPP_RET ret = MPP_OK;
    MppCtx ctx  = data->ctx;
    MppApi *mpi = data->mpi;
    char   *buf = data->buf;
	
    MppPacket packet = data->packet;
    MppFrame  frame  = NULL;
	
    size_t read_size = fread(buf, 1, data->packet_size, data->fp_input);
	
    if (read_size != data->packet_size || feof(data->fp_input)) {
        printf("found last packet\n");
        data->eos = 1;
    }
    
    mpp_packet_write(packet, 0, buf, read_size);
    mpp_packet_set_pos(packet, buf);
    mpp_packet_set_length(packet, read_size);
 
    if (data->eos){
        mpp_packet_set_eos(packet);
    }
 
    do {
        if (!pkt_done) {
            ret = mpi->decode_put_packet(ctx, packet);
            if (MPP_OK == ret){
                pkt_done = 1;
			}
        }

        do {
            RK_S32 get_frm = 0;
            RK_U32 frm_eos = 0;
            ret = mpi->decode_get_frame(ctx, &frame);
    
            if (frame) {
                if (mpp_frame_get_info_change(frame)){
                    RK_U32 width = mpp_frame_get_width(frame);
                    RK_U32 height = mpp_frame_get_height(frame);
                    RK_U32 hor_stride = mpp_frame_get_hor_stride(frame);
                    RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
                    RK_U32 buf_size = mpp_frame_get_buf_size(frame);								
                    printf("decode_get_frame get info changed found\n");
                    printf("decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d", width, height, hor_stride, ver_stride, buf_size);        
 
                    if (NULL == data->frm_grp) {                       
                        ret = mpp_buffer_group_get_internal(&data->frm_grp, MPP_BUFFER_TYPE_ION);
                        if (ret) {
                            printf("get mpp buffer group failed ret %d\n", ret);
                            break;
                        }							
                        ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp);
                        if (ret) {
                            printf("set buffer group failed ret %d\n", ret);
                            break;
                        }
                    } else {                      
                        ret = mpp_buffer_group_clear(data->frm_grp);
                        if (ret){
                            printf("clear buffer group failed ret %d\n", ret);
                            break;
                        }
                    }
                    
                    ret = mpp_buffer_group_limit_config(data->frm_grp, buf_size, 24);
                    if (ret) {
                        printf("limit buffer group failed ret %d\n", ret);
                        break;
                    }                   
                    ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
                    if (ret) {
                        printf("info change ready failed ret %d\n", ret);
                        break;
                    }
                }else{
                    err_info = mpp_frame_get_errinfo(frame) | mpp_frame_get_discard(frame);
                    if (err_info) {
                        printf("decoder_get_frame get err info:%d discard:%d.\n", mpp_frame_get_errinfo(frame), mpp_frame_get_discard(frame));
                    }
                    data->frame_count++;
                    printf("decode_get_frame get frame %d\n", data->frame_count);
                    if ( (!err_info) && (data->frame_count==data->frame_num)){
                        dump_mpp_frame_to_file(frame, data->fp_output);
					}
				}
                frm_eos = mpp_frame_get_eos(frame);
                mpp_frame_deinit(&frame);
                frame = NULL;
                get_frm = 1;
			}
           
            if (data->frm_grp) {
                size_t usage = mpp_buffer_group_usage(data->frm_grp);
                if (usage > data->max_usage){
                    data->max_usage = usage;
				}	
            }
         
            if (data->eos && pkt_done && !frm_eos) {
                msleep(10);
                continue;
            }
            if (frm_eos) {
                printf("found last frame\n");
                break;
            }
            if (data->frame_num && data->frame_count >= data->frame_num) {
                data->eos = 1;
                break;
            }
            if (get_frm){
                continue;
			}
            break;
        } while (1);
 
        if (data->frame_num && data->frame_count >= data->frame_num){
            data->eos = 1;
            printf("reach max frame number %d\n", data->frame_count);
            break;
        }
        if (pkt_done){
            break;
		}
		
		
    } while (1);
 
    return ret;
}
 
int mpi_dec_test_decode(char **argv)
{
    MPP_RET ret         = MPP_OK;
    size_t file_size 	= 0;

    MppParam param      = NULL;
    RK_U32 need_split   = 1;
 
    MpiDecLoopData data;
    memset(&data, 0, sizeof(data));
	
    data.eos            = 0;
    data.packet_size    = MPI_DEC_STREAM_SIZE;
    data.frame_count    = 0;
	data.frame_num		= 1;

    data.fp_input = fopen(argv[1], "rb");
	data.fp_output = fopen(argv[2], "w+");
    if ( (NULL == data.fp_input) || (NULL == data.fp_output) ) {
        printf("failed to open input/output file \n");
        goto MPP_TEST_OUT;
    }

	
    data.buf = mpp_malloc(char, data.packet_size);
    ret = mpp_packet_init(&data.packet, data.buf, data.packet_size);
	if(MPP_OK != ret){
		printf("mpp_packet_init error\n");
		goto MPP_TEST_OUT;
	}
	
	
    ret = mpp_create(&data.ctx, &data.mpi);
	if(MPP_OK != ret){
		printf("mpp_create error\n");
		goto MPP_TEST_OUT;
	}

	ret = mpp_init(data.ctx, MPP_CTX_DEC, MPP_VIDEO_CodingAVC);
    if (MPP_OK != ret) 
    {
        printf("mpp_init failed\n");
        goto MPP_TEST_OUT;
    }
 
    param = &need_split;
	
    ret = data.mpi->control(data.ctx, MPP_DEC_SET_PARSER_SPLIT_MODE, param);
    if (MPP_OK != ret) {
        printf("mpi->control failed\n");
        goto MPP_TEST_OUT;
    }
 
	fseek(data.fp_input, 0L, SEEK_END);
	file_size = ftell(data.fp_input);
    rewind(data.fp_input);
    printf("input file size %ld\n", file_size);
 
    while (!data.eos) 
	{
        decode_simple(&data);
    }

    ret = data.mpi->reset(data.ctx);
    if (MPP_OK != ret) 
    {
        printf("mpi->reset failed\n");
        goto MPP_TEST_OUT;
    }
 
MPP_TEST_OUT:
    if (data.packet) {
        mpp_packet_deinit(&data.packet);
        data.packet = NULL;
    }
 
    if (data.ctx) {
        mpp_destroy(data.ctx);
        data.ctx = NULL;
    }
 
    if (data.buf) {
        mpp_free(data.buf);
        data.buf = NULL;
    }
 
    if (data.frm_grp) {
        mpp_buffer_group_put(data.frm_grp);
        data.frm_grp = NULL;
    }
 
    if (data.fp_output){
        fclose(data.fp_output);
        data.fp_output = NULL;
    }
 
    if (data.fp_input) {
        fclose(data.fp_input);
        data.fp_input = NULL;
    }
 
    return ret;
}
 
int main(int argc, char **argv)
{
    RK_S32 ret = 0;

	if(argc != 3 ){
		printf("please input options\n");
		return -1;
	}
	
    ret = mpi_dec_test_decode(argv);
	
    return ret;
}

五、测试MPP解码H264,解码输出格式为YUV420SP

<think>好的,我现在需要帮助用户找到关于RK3576芯片使用MPP进行交叉编译的方法或教程。用户提到了之前的几个引用,涉及RK3588、RK3568等芯片的编译步骤,可能需要参考这些现有的方法来推断RK3576的步骤。 首先,用户提供的引用[1][3]提到了从GitHub下载MPP库,解压后进入build/linux/aarch64目录,并执行脚本生成Makefile。这可能是一个通用的流程,适用于不同型号的Rockchip芯片,包括RK3576。因此,我可以推测RK3576可能也遵循类似的步骤,只是可能需要调整编译配置或路径。 引用[2]是关于FFMPEG交叉编译的,其中提到了配置CMake参数,设置安装路径链接器选项。这可能对MPP的交叉编译也有参考价值,比如需要指定交叉编译工具链安装目录。 引用[4]提到了Qt交叉编译时使用预编译的qmake生成Makefile,这可能意味着在交叉编译MPP时也需要配置正确的工具链路径环境变量。 接下来,我需要将这些步骤整合,并假设RK3576的交叉编译流程与其他Rockchip芯片类似。可能需要确认官方是否有针对RK3576的特定文档或配置,但用户目前没有提供,所以基于现有信息进行推断。 可能的步骤包括:下载MPP源码,配置交叉编译环境(如aarch64-linux-gnu工具链),运行配置脚本生成Makefile,执行make安装。需要特别注意工具链的路径是否正确,以及可能的依赖项安装,如libx265等。 另外,用户可能需要调整CMake参数,例如指定目标架构为RK3576,但如果没有具体信息,可以沿用通用的aarch64配置。如果遇到问题,可能需要检查日志或参考其他Rockchip芯片的解决方案。 最后,生成相关问题需要考虑用户可能遇到的后续问题,比如环境配置、依赖项处理或编译错误解决,以及如何验证编译后的库是否可用。</think>根据Rockchip芯片交叉编译的通用流程,结合RK3576的架构特性,整理MPP交叉编译步骤如下: ### RK3576 MPP交叉编译步骤 1. **获取MPP源码** 从官方仓库下载并解压: ```bash git clone https://github.com/rockchip-linux/mpp cd mpp && git checkout stable # 建议选择稳定分支 ``` 引用[1]提到从GitHub下载源码是基础操作[^1]。 2. **配置交叉编译环境** 安装aarch64工具链: ```bash sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu ``` 设置环境变量(需根据实际路径调整): ```bash export CROSS_COMPILE=aarch64-linux-gnu- export CC=aarch64-linux-gnu-gcc export CXX=aarch64-linux-gnu-g++ ``` 3. **生成编译配置** 进入目标平台目录并执行配置脚本: ```bash cd build/linux/aarch64/ ./make-Makefiles.bash -DCMAKE_INSTALL_PREFIX=/opt/rk3576_mpp_install ``` 引用[3]显示执行`make-Makefiles.bash`是关键步骤[^3]。 4. **编译与安装** ```bash make -j$(nproc) # 多线程编译加速 sudo make install # 安装到指定目录 ``` 生成的库文件将保存在`/opt/rk3576_mpp_install`目录下。 5. **验证编译结果** 通过`file`命令检查动态库架构: ```bash file /opt/rk3576_mpp_install/lib/librockchip_mpp.so ``` 应输出`ELF 64-bit LSB shared object, ARM aarch64`。 ### 常见问题处理 - **依赖缺失**:编译前需安装`libdrm`等依赖项: ```bash sudo apt-get install libdrm-dev ``` - **CMake参数调整**:若需启用特定功能(如H.265硬解码),参考引用[2]中类似方法添加`-DENABLE_AVCODEC=ON`等参数[^2]。 ### 应用部署 交叉编译完成后,将`/opt/rk3576_mpp_install`目录拷贝至RK3576开发板,并在应用程序中通过`-I``-L`指定头文件与库路径[^4]。
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值