You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
334 lines
11 KiB
334 lines
11 KiB
#include <stdio.h> |
|
#include <sys/time.h> |
|
|
|
#include "mpp_decoder.h" |
|
#include <unistd.h> |
|
#include <pthread.h> |
|
#include <sys/syscall.h> |
|
|
|
#define LOGD printf |
|
// #define LOGD |
|
|
|
static unsigned long GetCurrentTimeMS() { |
|
struct timeval tv; |
|
gettimeofday(&tv, NULL); |
|
return tv.tv_sec*1000+tv.tv_usec/1000; |
|
} |
|
|
|
MppDecoder::MppDecoder() |
|
{ |
|
|
|
} |
|
|
|
MppDecoder::~MppDecoder() { |
|
if (loop_data.packet) { |
|
mpp_packet_deinit(&loop_data.packet); |
|
loop_data.packet = NULL; |
|
} |
|
if (frame) { |
|
mpp_frame_deinit(&frame); |
|
frame = NULL; |
|
} |
|
if (mpp_ctx) { |
|
mpp_destroy(mpp_ctx); |
|
mpp_ctx = NULL; |
|
} |
|
|
|
if (loop_data.frm_grp) { |
|
mpp_buffer_group_put(loop_data.frm_grp); |
|
loop_data.frm_grp = NULL; |
|
} |
|
} |
|
|
|
int MppDecoder::Init(int video_type, int fps, void* userdata) |
|
{ |
|
MPP_RET ret = MPP_OK; |
|
this->userdata = userdata; |
|
this->fps = fps; |
|
this->last_frame_time_ms = 0; |
|
if(video_type == 264) { |
|
mpp_type = MPP_VIDEO_CodingAVC; |
|
} else if (video_type == 265) { |
|
mpp_type =MPP_VIDEO_CodingHEVC; |
|
} else { |
|
LOGD("unsupport video_type %d", video_type); |
|
return -1; |
|
} |
|
LOGD("mpi_dec_test start "); |
|
memset(&loop_data, 0, sizeof(loop_data)); |
|
LOGD("mpi_dec_test decoder test start mpp_type %d ", mpp_type); |
|
|
|
MppDecCfg cfg = NULL; |
|
|
|
MppCtx mpp_ctx = NULL; |
|
ret = mpp_create(&mpp_ctx, &mpp_mpi); |
|
if (MPP_OK != ret) { |
|
LOGD("mpp_create failed "); |
|
return 0; |
|
} |
|
|
|
ret = mpp_init(mpp_ctx, MPP_CTX_DEC, mpp_type); |
|
if (ret) { |
|
LOGD("%p mpp_init failed ", mpp_ctx); |
|
return -1; |
|
} |
|
|
|
mpp_dec_cfg_init(&cfg); |
|
|
|
/* get default config from decoder context */ |
|
ret = mpp_mpi->control(mpp_ctx, MPP_DEC_GET_CFG, cfg); |
|
if (ret) { |
|
LOGD("%p failed to get decoder cfg ret %d ", mpp_ctx, ret); |
|
return -1; |
|
} |
|
|
|
/* |
|
* split_parse is to enable mpp internal frame spliter when the input |
|
* packet is not aplited into frames. |
|
*/ |
|
ret = mpp_dec_cfg_set_u32(cfg, "base:split_parse", need_split); |
|
if (ret) { |
|
LOGD("%p failed to set split_parse ret %d ", mpp_ctx, ret); |
|
return -1; |
|
} |
|
|
|
ret = mpp_mpi->control(mpp_ctx, MPP_DEC_SET_CFG, cfg); |
|
if (ret) { |
|
LOGD("%p failed to set cfg %p ret %d ", mpp_ctx, cfg, ret); |
|
return -1; |
|
} |
|
|
|
mpp_dec_cfg_deinit(cfg); |
|
|
|
loop_data.ctx = mpp_ctx; |
|
loop_data.mpi = mpp_mpi; |
|
loop_data.eos = 0; |
|
loop_data.packet_size = packet_size; |
|
loop_data.frame = 0; |
|
loop_data.frame_count = 0; |
|
return 1; |
|
} |
|
|
|
int MppDecoder::Reset() { |
|
if (mpp_mpi != NULL) { |
|
mpp_mpi->reset(mpp_ctx); |
|
} |
|
return 0; |
|
} |
|
|
|
int MppDecoder::Decode(uint8_t* pkt_data, int pkt_size, int pkt_eos) |
|
{ |
|
MpiDecLoopData *data=&loop_data; |
|
RK_U32 pkt_done = 0; |
|
RK_U32 err_info = 0; |
|
MPP_RET ret = MPP_OK; |
|
MppCtx ctx = data->ctx; |
|
MppApi *mpi = data->mpi; |
|
|
|
size_t read_size = 0; |
|
size_t packet_size = data->packet_size; |
|
|
|
LOGD("receive packet size=%d ", pkt_size); |
|
|
|
if (packet == NULL) { |
|
ret = mpp_packet_init(&packet, NULL, 0); |
|
} |
|
|
|
/////////////////////////////////////////////// |
|
// ret = mpp_packet_init(&packet, frame_data, frame_size); |
|
mpp_packet_set_data(packet, pkt_data); |
|
mpp_packet_set_size(packet, pkt_size); |
|
mpp_packet_set_pos(packet, pkt_data); |
|
mpp_packet_set_length(packet, pkt_size); |
|
// setup eos flag |
|
if (pkt_eos) |
|
mpp_packet_set_eos(packet); |
|
do { |
|
|
|
RK_S32 times = 5; |
|
// send the packet first if packet is not done |
|
if (!pkt_done) { |
|
ret = mpi->decode_put_packet(ctx, packet); |
|
if (MPP_OK == ret) |
|
pkt_done = 1; |
|
} |
|
// then get all available frame and release |
|
do { |
|
RK_S32 get_frm = 0; |
|
RK_U32 frm_eos = 0; |
|
|
|
try_again: |
|
ret = mpi->decode_get_frame(ctx, &frame); |
|
if (MPP_ERR_TIMEOUT == ret) { |
|
if (times > 0) { |
|
times--; |
|
usleep(2000); |
|
goto try_again; |
|
} |
|
LOGD("decode_get_frame failed too much time "); |
|
} |
|
|
|
if (MPP_OK != ret) { |
|
LOGD("decode_get_frame failed ret %d ", ret); |
|
break; |
|
} |
|
|
|
if (frame) { |
|
RK_U32 hor_stride = mpp_frame_get_hor_stride(frame); |
|
RK_U32 ver_stride = mpp_frame_get_ver_stride(frame); |
|
RK_U32 hor_width = mpp_frame_get_width(frame); |
|
RK_U32 ver_height = mpp_frame_get_height(frame); |
|
RK_U32 buf_size = mpp_frame_get_buf_size(frame); |
|
RK_S64 pts = mpp_frame_get_pts(frame); |
|
RK_S64 dts = mpp_frame_get_dts(frame); |
|
|
|
LOGD("decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d pts=%lld dts=%lld ", |
|
hor_width, ver_height, hor_stride, ver_stride, buf_size, pts, dts); |
|
|
|
if (mpp_frame_get_info_change(frame)) { |
|
|
|
LOGD("decode_get_frame get info changed found "); |
|
// ret = mpp_buffer_group_get_internal(&data->frm_grp, MPP_BUFFER_TYPE_DRM); |
|
// if (ret) { |
|
// LOGD("get mpp buffer group failed ret %d ", ret); |
|
// break; |
|
// } |
|
// mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp); |
|
// mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL); |
|
if (NULL == data->frm_grp) { |
|
/* If buffer group is not set create one and limit it */ |
|
ret = mpp_buffer_group_get_internal(&data->frm_grp, MPP_BUFFER_TYPE_DRM); |
|
if (ret) { |
|
LOGD("%p get mpp buffer group failed ret %d ", ctx, ret); |
|
break; |
|
} |
|
|
|
/* Set buffer to mpp decoder */ |
|
ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp); |
|
if (ret) { |
|
LOGD("%p set buffer group failed ret %d ", ctx, ret); |
|
break; |
|
} |
|
} else { |
|
/* If old buffer group exist clear it */ |
|
ret = mpp_buffer_group_clear(data->frm_grp); |
|
if (ret) { |
|
LOGD("%p clear buffer group failed ret %d ", ctx, ret); |
|
break; |
|
} |
|
} |
|
|
|
/* Use limit config to limit buffer count to 24 with buf_size */ |
|
ret = mpp_buffer_group_limit_config(data->frm_grp, buf_size, 24); |
|
if (ret) { |
|
LOGD("%p limit buffer group failed ret %d ", ctx, ret); |
|
break; |
|
} |
|
|
|
/* |
|
* All buffer group config done. Set info change ready to let |
|
* decoder continue decoding |
|
*/ |
|
ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL); |
|
if (ret) { |
|
LOGD("%p info change ready failed ret %d ", ctx, ret); |
|
break; |
|
} |
|
|
|
this->last_frame_time_ms = GetCurrentTimeMS(); |
|
} else { |
|
err_info = mpp_frame_get_errinfo(frame) | mpp_frame_get_discard(frame); |
|
if (err_info) { |
|
LOGD("decoder_get_frame get err info:%d discard:%d. ", |
|
mpp_frame_get_errinfo(frame), mpp_frame_get_discard(frame)); |
|
} |
|
data->frame_count++; |
|
struct timeval tv; |
|
gettimeofday(&tv, NULL); |
|
LOGD("get one frame %ld ", (tv.tv_sec * 1000 + tv.tv_usec/1000)); |
|
// mpp_frame_get_width(frame); |
|
// char *input_data =(char *) mpp_buffer_get_ptr(mpp_frame_get_buffer(frame)); |
|
if (callback != nullptr) { |
|
MppFrameFormat format = mpp_frame_get_fmt(frame); |
|
char *data_vir =(char *) mpp_buffer_get_ptr(mpp_frame_get_buffer(frame)); |
|
int fd = mpp_buffer_get_fd(mpp_frame_get_buffer(frame)); |
|
LOGD("data_vir=%p fd=%d ", data_vir, fd); |
|
callback(this->userdata, hor_stride, ver_stride, hor_width, ver_height, format, fd, data_vir); |
|
} |
|
unsigned long cur_time_ms = GetCurrentTimeMS(); |
|
long time_gap = 1000/this->fps - (cur_time_ms - this->last_frame_time_ms); |
|
LOGD("time_gap=%ld", time_gap); |
|
if (time_gap > 0) { |
|
usleep(time_gap * 1000); |
|
} |
|
this->last_frame_time_ms = GetCurrentTimeMS(); |
|
} |
|
frm_eos = mpp_frame_get_eos(frame); |
|
|
|
ret = mpp_frame_deinit(&frame); |
|
frame = NULL; |
|
|
|
// if(frame_pre!=NULL) |
|
// { |
|
// mpp_frame_deinit(&frame_pre); |
|
// } |
|
// &frame_pre=&frame; |
|
|
|
get_frm = 1; |
|
} |
|
|
|
// try get runtime frame memory usage |
|
if (data->frm_grp) { |
|
size_t usage = mpp_buffer_group_usage(data->frm_grp); |
|
if (usage > data->max_usage) |
|
data->max_usage = usage; |
|
} |
|
|
|
// if last packet is send but last frame is not found continue |
|
if (pkt_eos && pkt_done && !frm_eos) { |
|
usleep(1*1000); |
|
continue; |
|
} |
|
|
|
if (frm_eos) { |
|
LOGD("found last frame "); |
|
break; |
|
} |
|
|
|
if (data->frame_num > 0 && data->frame_count >= data->frame_num) { |
|
data->eos = 1; |
|
break; |
|
} |
|
|
|
if (get_frm) |
|
continue; |
|
break; |
|
} while (1); |
|
|
|
if (data->frame_num > 0 && data->frame_count >= data->frame_num) { |
|
data->eos = 1; |
|
LOGD("reach max frame number %d ", data->frame_count); |
|
break; |
|
} |
|
|
|
if (pkt_done) |
|
break; |
|
|
|
/* |
|
* why sleep here: |
|
* mpi->decode_put_packet will failed when packet in internal queue is |
|
* full,waiting the package is consumed .Usually hardware decode one |
|
* frame which resolution is 1080p needs 2 ms,so here we sleep 3ms |
|
* * is enough. |
|
*/ |
|
usleep(3*1000); |
|
} while (1); |
|
mpp_packet_deinit(&packet); |
|
|
|
return ret; |
|
} |
|
|
|
int MppDecoder::SetCallback(MppDecoderFrameCallback callback) { |
|
this->callback = callback; |
|
return 0; |
|
} |