334 lines
11 KiB
C++
Executable File
334 lines
11 KiB
C++
Executable File
#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=%ld dts=%ld ",
|
|
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;
|
|
} |