【rockchip】使用RKMPP+RGA解码H264并转换数据格式输出

RKMPP+RGA硬解码

函数说明

  1. 调用video_decoder_create_v2函数初始化解码器句柄,完成一系列初始化操作

  2. video_decoder_decode_v2函数将送入的h264_data数据,转成期望的数据格式,并且保存到dst_buff缓冲区

  3. video_decoder_destroy_v2销毁解码器句柄,释放内存

  4. 这里以格式BGRA8888为例,dst_buff缓冲区大小至少要dst_w * dst_h * 4,参考RK官方demo代码:mpi_dec_test.c

代码如下

#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <rockchip/rk_mpi.h>
#include <rga/RgaApi.h>


#define VDEC_VO_TAG         "vdec_vo.c"



typedef struct{
	// MPP 和 RGA 全局上下文
	MppCtx mpp_ctx;
	MppApi *mpi;
	MppPacket packet;
	MppDecCfg cfg;
	MppBufferGroup group;
	struct _dst_info {
		int w;
		int h;
		int format;
		int bbp;
	}dst_info;
	int start;
}VDEC_VO_PARAMS;

int video_decoder_get_frame_v2(void* handle, uint8_t* dst_buff, int size)
{
	VDEC_VO_PARAMS* vdec_vo_handle = (VDEC_VO_PARAMS*)handle;
	if (vdec_vo_handle == NULL) return -1;

	int ret = -1;
	int retry_times = 2;
	MppFrame mpp_frame;
try_again:
    ret = vdec_vo_handle->mpi->decode_get_frame(vdec_vo_handle->mpp_ctx, &mpp_frame);
    if (MPP_OK != ret || !mpp_frame) {
        if (retry_times > 0) {
            retry_times--;
            msleep(2);
            goto try_again;
        }
        log_Error(VDEC_VO_TAG, "%p decode_get_frame failed too much time\n", vdec_vo_handle->mpp_ctx);
    }
    if (ret) {
        log_Error(VDEC_VO_TAG, "%p decode_get_frame failed ret %d\n", vdec_vo_handle->mpp_ctx, ret);
        return -1;
    }
	//log_Debug(VDEC_VO_TAG, "%s, mpp_frame=%d, ret=%d\n", __func__, mpp_frame != NULL, ret);
	if (mpp_frame != NULL) {
		RK_U32 src_width = mpp_frame_get_width(mpp_frame);
        RK_U32 src_height = mpp_frame_get_height(mpp_frame);
        RK_U32 src_hor_stride = mpp_frame_get_hor_stride(mpp_frame);
        RK_U32 src_ver_stride = mpp_frame_get_ver_stride(mpp_frame);
		RK_U32 buf_size = mpp_frame_get_buf_size(mpp_frame);
		MppFrameFormat fmt = mpp_frame_get_fmt(mpp_frame);
		RK_U32 err_info = mpp_frame_get_errinfo(mpp_frame);
        RK_U32 discard = mpp_frame_get_discard(mpp_frame);
		RK_U32 frm_oes = mpp_frame_get_discard(mpp_frame);
		//log_Debug(VDEC_VO_TAG, "%s, Frame format: %d, err_info=%d, discard=%d, frm_oes=%d\n", __func__, fmt, err_info, discard, frm_oes);
		if (mpp_frame_get_info_change(mpp_frame)) {
            log_Debug(VDEC_VO_TAG, "%p decode_get_frame get info changed found\n", vdec_vo_handle->mpp_ctx);
            log_Debug(VDEC_VO_TAG, "%p decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d",
                      vdec_vo_handle->mpp_ctx, src_width, src_height, src_hor_stride, src_ver_stride, buf_size);
			
            if (NULL == vdec_vo_handle->group) {
                /* If buffer group is not set create one and limit it */
                ret = mpp_buffer_group_get_internal(&vdec_vo_handle->group, MPP_BUFFER_TYPE_ION);
                if (ret) {
                    log_Error(VDEC_VO_TAG, "%p get mpp buffer group failed ret %d\n", vdec_vo_handle->mpp_ctx, ret);
                }

                /* Set buffer to mpp decoder */
                ret = vdec_vo_handle->mpi->control(vdec_vo_handle->mpp_ctx, MPP_DEC_SET_EXT_BUF_GROUP, vdec_vo_handle->group);
                if (ret) {
                    log_Error(VDEC_VO_TAG, "%p set buffer group failed ret %d\n", vdec_vo_handle->mpp_ctx, ret);
                }
            } else {
                /* If old buffer group exist clear it */
                ret = mpp_buffer_group_clear(vdec_vo_handle->group);
                if (ret) {
                    log_Error(VDEC_VO_TAG, "%p clear buffer group failed ret %d\n", vdec_vo_handle->mpp_ctx, ret);
                }
            }

            /* Use limit config to limit buffer count to 24 with buf_size */
            ret = mpp_buffer_group_limit_config(vdec_vo_handle->group, buf_size, 24);
            if (ret) {
                log_Error(VDEC_VO_TAG, "%p limit buffer group failed ret %d\n", vdec_vo_handle->mpp_ctx, ret);
            }

            /*
             * All buffer group config done. Set info change ready to let
             * decoder continue decoding
             */
            ret = vdec_vo_handle->mpi->control(vdec_vo_handle->mpp_ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
            if (ret) {
                log_Error(VDEC_VO_TAG, "%p info change ready failed ret %d\n", vdec_vo_handle->mpp_ctx, ret);
            }
		}else {
			// 获取解码后的 YUV 数据
	        void *yuv_buffer = mpp_frame_get_buffer(mpp_frame);
	        int fd = mpp_buffer_get_fd(yuv_buffer);
	        // RGA 转换:NV12 → dst_format
	        rga_info_t src = {0,};
			src.fd = fd;
			src.mmuFlag = 1;
	        rga_set_rect(&src.rect, 0,0,src_width,src_height,src_hor_stride,src_ver_stride, RK_FORMAT_YCbCr_420_SP);
			rga_info_t dst = {0,};
			dst.fd = -1;
			dst.mmuFlag = 1;
			dst.virAddr = dst_buff,
	        rga_set_rect(&dst.rect, 0,0,vdec_vo_handle->dst_info.w,vdec_vo_handle->dst_info.h,vdec_vo_handle->dst_info.w,
	        	vdec_vo_handle->dst_info.h, vdec_vo_handle->dst_info.format);
	       	ret = c_RkRgaBlit(&src, &dst, NULL);
	        if (ret == 0) {
	        } else {
				log_Error(VDEC_VO_TAG, "c_RkRgaBlit failed ret = %d\n", ret);
			}
			ret = 1;
		}
		mpp_frame_deinit(&mpp_frame);
		return ret;
	}
	return 0;
}


void* video_decoder_create_v2(int disp_w, int disp_h, const char* dst_format)
{
	VDEC_VO_PARAMS* vdec_vo_handle = (VDEC_VO_PARAMS*)calloc(1, sizeof(VDEC_VO_PARAMS));
    if(vdec_vo_handle != NULL)
    {
    	int ret = 0;
		ret = mpp_create(&vdec_vo_handle->mpp_ctx, &vdec_vo_handle->mpi);
		if(ret) {
			log_Error(VDEC_VO_TAG, "mpp_create failed! ret=%d\n", ret);
			free(vdec_vo_handle);
			return NULL;
		}
		MppParam param      = NULL;
		RK_U32 need_split   = 1;
		MpiCmd mpi_cmd = MPP_DEC_SET_PARSER_SPLIT_MODE;
	    param = &need_split;
	    ret = vdec_vo_handle->mpi->control(vdec_vo_handle->mpp_ctx, mpi_cmd, param);
	    if (MPP_OK != ret) {
	        log_Error(VDEC_VO_TAG, "%p mpi->control failed\n", vdec_vo_handle->mpp_ctx);
			mpp_destroy(vdec_vo_handle->mpp_ctx);
	        return NULL;
	    }
		//ret = vdec_vo_handle->mpi->control(vdec_vo_handle->mpp_ctx, MPP_DEC_SET_ENABLE_DEINTERLACE, (MppParam)0);
		ret = mpp_init(vdec_vo_handle->mpp_ctx, MPP_CTX_DEC, MPP_VIDEO_CodingAVC);
		if (ret) {
			log_Error(VDEC_VO_TAG, "mpp_init failed! ret=%d\n", ret);
			mpp_destroy(vdec_vo_handle->mpp_ctx);
			free(vdec_vo_handle);
			return NULL;
		}

		mpp_dec_cfg_init(&vdec_vo_handle->cfg);

	    /*
	     * split_parse is to enable mpp internal frame spliter when the input
	     * packet is not aplited into frames.
	     */
	    ret = mpp_dec_cfg_set_u32(vdec_vo_handle->cfg, "base:split_parse", need_split);
	    if (ret) {
	        log_Error(VDEC_VO_TAG, "%p failed to set split_parse ret %d\n", vdec_vo_handle->mpp_ctx, ret);
	    }
	    ret = vdec_vo_handle->mpi->control(vdec_vo_handle->mpp_ctx, MPP_DEC_SET_CFG, vdec_vo_handle->cfg);
	    if (ret) {
	        log_Error(VDEC_VO_TAG, "%p failed to set cfg %p ret %d\n", vdec_vo_handle->mpp_ctx, vdec_vo_handle->cfg, ret);
    	}
        ret = mpp_packet_init(&vdec_vo_handle->packet, NULL, 0);
		vdec_vo_handle->dst_info.w = disp_w;
		vdec_vo_handle->dst_info.h = disp_h;
		if (str_eq(dst_format, "BGRA")) {
			vdec_vo_handle->dst_info.format = RK_FORMAT_BGRA_8888;
		} else {
			log_Error(VDEC_VO_TAG, "not support format:%s\n", dst_format);
			video_decoder_destroy_v2();
			return NULL;
		}
    }
    log_Info(VDEC_VO_TAG, "%s, vdec_vo_handle:0x%p successfully!\n", __func__, vdec_vo_handle);
     // 初始化 RGA (程序初始化全局只需要创建一次即可)
    c_RkRgaInit();
    return vdec_vo_handle;
}

int video_decoder_decode_v2(void* handle, uint8_t* h264_data, int h264_size, int is_key_frame, uint8_t* dst_buff, int dst_size)
{
	VDEC_VO_PARAMS* vdec_vo_handle = (VDEC_VO_PARAMS*)handle;
	if (vdec_vo_handle != NULL) {
		// 这里保证先得到H264关键帧,其实也可以不需要,RKMPP内部自己会解析判断
		if (is_key_frame) {vdec_vo_handle->start = 1;}
		if (!vdec_vo_handle->start) {return -1;}
		int ret = 0;
		// 复用 packet,仅更新数据
	    mpp_packet_set_data(vdec_vo_handle->packet, h264_data);
	    mpp_packet_set_size(vdec_vo_handle->packet, h264_size);
		mpp_packet_set_pos(vdec_vo_handle->packet, h264_data);
    	mpp_packet_set_length(vdec_vo_handle->packet, h264_size);
		if (is_key_frame) {
			//log_Debug(VDEC_VO_TAG, "%s, is_key_frame\n", __func__);
			//mpp_packet_set_extra_data(vdec_vo_handle->packet);
		}
		/*MppDecQueryCfg query = {0};
		query.query_flag = MPP_DEC_QUERY_ALL;
		vdec_vo_handle->mpi->control(vdec_vo_handle->mpp_ctx, MPP_DEC_QUERY, &query);
		log_Debug(VDEC_VO_TAG, "%s, dec_in_pkt_cnt=%d, dec_hw_run_cnt=%d, dec_out_frm_cnt=%d, rt_bps=%d, rt_fps=%d, rt_status=%d, rt_wait=%d\n", 
	          __func__, query.dec_in_pkt_cnt, query.dec_hw_run_cnt, query.dec_out_frm_cnt, 
	          query.rt_bps, query.rt_fps, query.rt_status, query.rt_wait);*/
	    // 发送给解码器
	    ret = vdec_vo_handle->mpi->decode_put_packet(vdec_vo_handle->mpp_ctx, vdec_vo_handle->packet);
		if (ret) {
		    log_Error(VDEC_VO_TAG, "decode_put_packet failed! ret=%d\n", ret);
		}
		// 送入数据后就可以立即获取解码后的数据了
		video_decoder_get_frame_v2(handle, dst_buff, size);
		return ret;
	}
	return -1;
}

void video_decoder_destroy_v2(void* handle)
{
    VDEC_VO_PARAMS* vdec_vo_handle = (VDEC_VO_PARAMS*)handle;
    if(vdec_vo_handle != NULL){
        int ret = 0;
        // 释放资源(循环外!)
	    if (vdec_vo_handle->packet != NULL) {
	        mpp_packet_deinit(&vdec_vo_handle->packet);
	        vdec_vo_handle->packet = NULL;
	    }
		if (vdec_vo_handle->group != NULL) {
		    mpp_buffer_group_put(vdec_vo_handle->group);
		    vdec_vo_handle->group = NULL;
		}
		if (vdec_vo_handle->cfg != NULL) {
	        mpp_dec_cfg_deinit(vdec_vo_handle->cfg);
	        vdec_vo_handle->cfg = NULL;
	    }
    	mpp_destroy(vdec_vo_handle->mpp_ctx);
        free(vdec_vo_handle);
    }
}

No pains, no gains.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值