株洲网站建设方案咨询百度小说风云榜总榜
RKMPP+RGA硬解码
- 函数说明
- 代码如下
函数说明
-
调用video_decoder_create_v2函数初始化解码器句柄,完成一系列初始化操作
-
video_decoder_decode_v2函数将送入的h264_data数据,转成期望的数据格式,并且保存到dst_buff缓冲区
-
video_decoder_destroy_v2销毁解码器句柄,释放内存
-
这里以格式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_formatrga_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.