• MPP-解码示例


    提取出编码的代码后,现在提取解码例程,供以后需要的时候使用。

    完整的解码代码如下,做了一些改动,指令参数全部去除,输入H264数据,解码后的数据保存在本地,官方示例解码后的数据是YUV_420sp和YUV_422sp格式,这里将其改为了YUV_420p格式。

    #if defined(_WIN32)
    #include "vld.h"
    #endif
    
    #define MODULE_TAG "mpi_dec_test"
    
    #include <string.h>
    
    #include "utils.h"
    #include "rk_mpi.h"
    #include "mpp_log.h"
    #include "mpp_mem.h"
    #include "mpp_env.h"
    #include "mpp_time.h"
    #include "mpp_common.h"
    
    #include "mpp_frame.h"
    #include "mpp_buffer_impl.h"
    #include "mpp_frame_impl.h"
    
    #define MPI_DEC_STREAM_SIZE         (SZ_4K)
    #define MPI_DEC_LOOP_COUNT          4
    #define MAX_FILE_NAME_LENGTH        256
    	
    typedef struct 
    {
        MppCtx          ctx;
        MppApi          *mpi;
        RK_U32          eos;
        char            *buf;
    
        MppBufferGroup  frm_grp;
        MppBufferGroup  pkt_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;
    
    typedef struct 
    {
        char            file_input[MAX_FILE_NAME_LENGTH];
        char            file_output[MAX_FILE_NAME_LENGTH];
        MppCodingType   type;
        MppFrameFormat  format;
        RK_U32          width;
        RK_U32          height;
        RK_U32          debug;
    
        RK_U32          have_input;
        RK_U32          have_output;
    
        RK_U32          simple;
        RK_S32          timeout;
        RK_S32          frame_num;
        size_t          max_usage;
    } MpiDecTestCmd;
    
    size_t mpp_frame_get_buf_size(const MppFrame s)
    {
        check_is_mpp_frame((MppFrameImpl*)s); 
        return ((MppFrameImpl*)s)->buf_size; 
    }
    
    void dump_mpp_frame_to_file(MppFrame frame, FILE *fp)
    {
        RK_U32 width    = 0;
        RK_U32 height   = 0;
        RK_U32 h_stride = 0;
        RK_U32 v_stride = 0;
    	
        MppBuffer buffer    = NULL;
        RK_U8 *base = NULL;
    
        width    = mpp_frame_get_width(frame);
        height   = mpp_frame_get_height(frame);
        h_stride = mpp_frame_get_hor_stride(frame);
        v_stride = mpp_frame_get_ver_stride(frame);
        buffer   = mpp_frame_get_buffer(frame);
    	
        base = (RK_U8 *)mpp_buffer_get_ptr(buffer);
        RK_U32 buf_size = mpp_frame_get_buf_size(frame);
        size_t base_length = mpp_buffer_get_size(buffer);
        mpp_log("base_length = %d
    ",base_length);
    
        RK_U32 i;
        RK_U8 *base_y = base;
        RK_U8 *base_c = base + h_stride * v_stride;
    	
    	//保存为YUV420sp格式
        /*for (i = 0; i < height; i++, base_y += h_stride) 
        {
            fwrite(base_y, 1, width, fp);
        }
        for (i = 0; i < height / 2; i++, base_c += h_stride)
        {
            fwrite(base_c, 1, width, fp);
        }*/
    
    	//保存为YUV420p格式
        for(i = 0; i < height; i++, base_y += h_stride)
        {
            fwrite(base_y, 1, width, fp);
        }
        for(i = 0; i < height * width / 2; i+=2)
    	{
    	    fwrite((base_c + i), 1, 1, fp);
        }
        for(i = 1; i < height * width / 2; i+=2)
    	{
    	    fwrite((base_c + i), 1, 1, fp);
        }
    }
    
    size_t mpp_buffer_group_usage(MppBufferGroup group)
    {
        if (NULL == group) 
        {
            mpp_err_f("input invalid group %p
    ", group);
            return MPP_BUFFER_MODE_BUTT;
        }
    
        MppBufferGroupImpl *p = (MppBufferGroupImpl *)group;
        return p->usage;
    }
    
    static int decode_simple(MpiDecLoopData *data)
    {
        RK_U32 pkt_done = 0;
        RK_U32 pkt_eos  = 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)) 
        {
            mpp_log("found last packet
    ");
            data->eos = pkt_eos = 1;
        }
        
        mpp_packet_write(packet, 0, buf, read_size);
        mpp_packet_set_pos(packet, buf);
        mpp_packet_set_length(packet, read_size);
    
        if (pkt_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);								
    
                        mpp_log("decode_get_frame get info changed found
    ");
                        mpp_log("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) 
    						{
                                mpp_err("get mpp buffer group failed ret %d
    ", ret);
                                break;
                            }							
                            ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp);
                            if (ret) 
    						{
                                mpp_err("set buffer group failed ret %d
    ", ret);
                                break;
                            }
                        } 
    					else 
    					{                      
                            ret = mpp_buffer_group_clear(data->frm_grp);
                            if (ret)
    						{
                                mpp_err("clear buffer group failed ret %d
    ", ret);
                                break;
                            }
                        }
                        
                        ret = mpp_buffer_group_limit_config(data->frm_grp, buf_size, 24);
                        if (ret) 
    					{
                            mpp_err("limit buffer group failed ret %d
    ", ret);
                            break;
                        }                   
                        ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
                        if (ret) 
    					{
                            mpp_err("info change ready failed ret %d
    ", ret);
                            break;
                        }
                    }
    				else 
    				{
                        err_info = mpp_frame_get_errinfo(frame) | mpp_frame_get_discard(frame);
                        if (err_info) 
    					{
                            mpp_log("decoder_get_frame get err info:%d discard:%d.
    ", mpp_frame_get_errinfo(frame), mpp_frame_get_discard(frame));
                        }
                        data->frame_count++;
                        mpp_log("decode_get_frame get frame %d
    ", data->frame_count);
                        if (data->fp_output && !err_info)
    					{
                            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 (pkt_eos && pkt_done && !frm_eos) 
    			{
                    msleep(10);
                    continue;
                }
                if (frm_eos) 
    			{
                    mpp_log("found last frame
    ");
                    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;
                mpp_log("reach max frame number %d
    ", data->frame_count);
                break;
            }
            if (pkt_done)
    		{
                break;
    		}
        } while (1);
    
        return ret;
    }
    
    int mpi_dec_test_decode(MpiDecTestCmd *cmd)
    {
        MPP_RET ret         = MPP_OK;
        size_t file_size    = 0;
    
        MppCtx ctx          = NULL;
        MppApi *mpi         = NULL;
    
        MppPacket packet    = NULL;
        MppFrame  frame     = NULL;
    
        MpiCmd mpi_cmd      = MPP_CMD_BASE;
        MppParam param      = NULL;
        RK_U32 need_split   = 1;
    
        RK_U32 width        = cmd->width;
        RK_U32 height       = cmd->height;
        MppCodingType type  = cmd->type;
    
        char *buf           = NULL;
        size_t packet_size  = MPI_DEC_STREAM_SIZE;
        MppBuffer pkt_buf   = NULL;
        MppBuffer frm_buf   = NULL;
    
        MpiDecLoopData data;
    
        mpp_log("mpi_dec_test start
    ");
        memset(&data, 0, sizeof(data));
    
        data.fp_input = fopen("test.h264", "rb");
        if (NULL == data.fp_input) 
        {
            mpp_err("failed to open input file %s
    ", cmd->file_input);
            goto MPP_TEST_OUT;
        }
    	
        fseek(data.fp_input, 0L, SEEK_END);
        file_size = ftell(data.fp_input);
        rewind(data.fp_input);
        mpp_log("input file size %ld
    ", file_size);
    
        data.fp_output = fopen("output.yuv", "w+b");
    
        if (cmd->simple) 
        {
            buf = mpp_malloc(char, packet_size);
    
            ret = mpp_packet_init(&packet, buf, packet_size);
        } 
        mpp_log("mpi_dec_test decoder test start w %d h %d type %d
    ", width, height, type);
    
        ret = mpp_create(&ctx, &mpi);
    
        mpi_cmd = MPP_DEC_SET_PARSER_SPLIT_MODE;
        param = &need_split;
    	
        ret = mpi->control(ctx, mpi_cmd, param);
        if (MPP_OK != ret) 
        {
            mpp_err("mpi->control failed
    ");
            goto MPP_TEST_OUT;
        }
    
        ret = mpp_init(ctx, MPP_CTX_DEC, type);
        if (MPP_OK != ret) 
        {
            mpp_err("mpp_init failed
    ");
            goto MPP_TEST_OUT;
        }
    	
        mpp_log("packet_size = %d
    ", packet_size);
    
        data.ctx            = ctx;
        data.mpi            = mpi;
        data.eos            = 0;
        data.buf            = buf;
        data.packet         = packet;
        data.packet_size    = packet_size;
        data.frame          = frame;
        data.frame_count    = 0;
        data.frame_num      = cmd->frame_num;
        mpp_log("data.packet_size = %d
    ", data.packet_size);
    
        if (cmd->simple) 
        {
            while (!data.eos) 
    		{
                decode_simple(&data);
    			mpp_log("data.eos = %d
    ", data.eos);
            }
        } 
    
        cmd->max_usage = data.max_usage;
        ret = mpi->reset(ctx);
        if (MPP_OK != ret) 
        {
            mpp_err("mpi->reset failed
    ");
            goto MPP_TEST_OUT;
        }
    
    MPP_TEST_OUT:
        if (packet) 
        {
            mpp_packet_deinit(&packet);
            packet = NULL;
        }
    
        if (frame) 
        {
            mpp_frame_deinit(&frame);
            frame = NULL;
        }
    
        if (ctx) 
        {
            mpp_destroy(ctx);
            ctx = NULL;
        }
    
        if (cmd->simple) 
        {
            if (buf) 
    		{
                mpp_free(buf);
                buf = NULL;
            }
        } 
    
        if (data.pkt_grp) 
        {
            mpp_buffer_group_put(data.pkt_grp);
            data.pkt_grp = 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;
        MpiDecTestCmd  cmd_ctx;
        MpiDecTestCmd* cmd = &cmd_ctx;
    	
        cmd->simple = 1;
        cmd->type = 7;
        cmd->width = 640;
        cmd->height = 480;
    	
        ret = mpi_dec_test_decode(cmd);
    	
        return ret;
    }

    具体分析:

    1、MPI接口的结构和使用,可以参考上篇内容,解码与编码基本一致。

    2、解码器接口

    decode_put_packet:

    MPP_RET decode_put_packet(MppCtx ctx,MppPacket packet)

    ctx:MPP解码器实例;

    packet:待输入的码流数据;

    输入码流的方式:分帧与不分帧。裸码流输入有两种,一种是按帧分段的数据,每一个输入给decode_put_packet函数的数据包都包含完整的一帧,不多也不少。在这种情况下,MPP可以直接按包处理码流。另一种是按长度读取数据,无法判断一个包的数据是否为完整的一帧,需要MPP内部进行分帧处理。在进行这种形式的输入时,需要在mpp_init前,通过control接口的MPP_DEC_SET_PARSER_SPLIT_MODE命令,打开need_split标志。分帧方式效率高,但需要在输入码流前进行解析与分帧,不分帧方式使用简单,效率会受影响。官方解码示例采用的是不分帧方式,因此上述代码也是不分帧方式。

    decode_get_frame:

    MPP_RET decode_get_frame(MppCtx ctx,MppFrame *frame)

    ctx:MPP解码器实例;

    frame:用于MppFrame实例的指针;

    完整的解码过程是上面两个函数的结合。

  • 相关阅读:
    css
    博客目录
    macOS下psql客户端中文乱码问题
    PostgreSQL dblink的使用
    error: RPC failed; curl 56 LibreSSL SSL_read: SSL_ERROR_SYSCALL, errno 60
    mac中环境变量配置
    PostgreSQL Copy 命令
    Linux下rz命令和sz命令使用方法
    Tmux 使用教程
    create_time和update_time自动填写
  • 原文地址:https://www.cnblogs.com/xue0708/p/10152855.html
Copyright © 2020-2023  润新知