[mpp_dec]: Add post-process path to mpp_dec

1. Unify the hal thread output process to mpp_dec_put_frame
2. Add vproc path for field source.
3. Reserve one more buffer when deinterlace is enabled.
4. Default enable for normal mpp path but disable on vpuapi path for the
reason that rk_ffplayer has done deinterlace process internally.

Change-Id: I02e7cece844fde01c2d249dafe6f7ce6a325593f
Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
This commit is contained in:
Herman Chen
2018-05-10 18:15:50 +08:00
parent 3f57e7bda0
commit 44f0ee0353
6 changed files with 169 additions and 94 deletions

View File

@@ -98,6 +98,7 @@ typedef enum {
MPP_DEC_SET_OUTPUT_FORMAT,
MPP_DEC_SET_DISABLE_ERROR, /* When set it will disable sw/hw error (H.264 / H.265) */
MPP_DEC_SET_IMMEDIATE_OUT,
MPP_DEC_SET_ENABLE_DEINTERLACE, /* MPP enable deinterlace by default. Vpuapi can disable it */
MPP_DEC_CMD_END,
MPP_ENC_CMD_BASE = CMD_MODULE_CODEC | CMD_CTX_ID_ENC,

View File

@@ -42,9 +42,11 @@ struct MppDec_t {
RK_U32 parser_internal_pts;
RK_U32 disable_error;
RK_U32 use_preset_time_order;
RK_U32 enable_deinterlace;
// dec parser thread runtime resource context
MppPacket mpp_pkt_in;
void *mpp;
void *vproc;
};
typedef struct {

View File

@@ -29,6 +29,8 @@
#include "mpp_packet_impl.h"
#include "mpp_frame_impl.h"
#include "mpp_dec_vproc.h"
typedef union PaserTaskWait_u {
RK_U32 val;
struct {
@@ -38,6 +40,7 @@ typedef union PaserTaskWait_u {
RK_U32 prev_task : 1;
RK_U32 info_change : 1;
RK_U32 dec_pic_buf : 1;
RK_U32 dec_slot_idx : 1;
RK_U32 dis_que_full : 1;
};
} PaserTaskWait;
@@ -104,7 +107,8 @@ static MPP_RET check_task_wait(MppDec *dec, DecTask *task)
(task->wait.prev_task &&
!hal_task_check_empty(dec->tasks, TASK_PROC_DONE)) ||
task->wait.info_change ||
task->wait.dec_pic_buf)
task->wait.dec_pic_buf ||
task->wait.dec_slot_idx)
return MPP_NOK;
return MPP_OK;
@@ -148,6 +152,8 @@ static RK_U32 reset_dec_task(Mpp *mpp, DecTask *task)
task_dec->valid = 0;
mpp_parser_reset(dec->parser);
mpp_hal_reset(dec->hal);
if (dec->vproc)
dec_vproc_reset(dec->vproc);
dec->reset_flag = 0;
if (task->wait.info_change) {
mpp_log("reset add info change status\n");
@@ -194,74 +200,117 @@ static RK_U32 reset_dec_task(Mpp *mpp, DecTask *task)
return MPP_OK;
}
static void mpp_put_frame(Mpp *mpp, MppFrame frame)
/* Overall mpp_dec output frame function */
static void mpp_dec_put_frame(Mpp *mpp, RK_S32 index, HalDecTaskFlag flags)
{
mpp_list *list = mpp->mFrames;
MppDec *dec = mpp->mDec;
MppBufSlots slots = dec->frame_slots;
MppFrame frame = NULL;
RK_U32 eos = flags.eos;
RK_U32 change = flags.info_change;
RK_U32 error = flags.had_error;
RK_U32 refer = flags.used_for_ref;
if (index >= 0) {
mpp_buf_slot_get_prop(slots, index, SLOT_FRAME_PTR, &frame);
if (mpp_frame_get_mode(frame) && dec->enable_deinterlace &&
NULL == dec->vproc) {
dec_vproc_init(&dec->vproc, mpp);
dec_vproc_start(dec->vproc);
}
} else {
// when post-process is needed and eos without slot index case
// we need to create a slot index for it
mpp_assert(eos);
mpp_assert(!change);
if (dec->vproc) {
mpp_buf_slot_get_unused(slots, &index);
mpp_buf_slot_default_info(slots, index, &frame);
mpp_buf_slot_set_flag(slots, index, SLOT_CODEC_READY);
} else {
mpp_frame_init(&frame);
index = 0;
}
mpp_frame_set_eos(frame, eos);
}
mpp_assert(index >= 0);
mpp_assert(frame);
list->lock();
if (mpp->mDec->disable_error) {
mpp_frame_set_errinfo(frame, 0);
mpp_frame_set_discard(frame, 0);
}
list->add_at_tail(&frame, sizeof(frame));
if (change) {
/* NOTE: Set codec ready here for dequeue/enqueue */
mpp_buf_slot_set_flag(slots, index, SLOT_CODEC_READY);
} else {
if (dec->use_preset_time_order) {
MppPacket pkt = NULL;
mpp->mTimeStamps->pull(&pkt, sizeof(pkt));
if (pkt) {
mpp_frame_set_dts(frame, mpp_packet_get_dts(pkt));
mpp_frame_set_pts(frame, mpp_packet_get_pts(pkt));
mpp_packet_deinit(&pkt);
} else
mpp_err_f("pull out packet error.\n");
}
}
mpp_frame_set_info_change(frame, change);
if (eos) {
mpp_frame_set_eos(frame, 1);
if (error) {
if (refer)
mpp_frame_set_errinfo(frame, 1);
else
mpp_frame_set_discard(frame, 1);
}
mpp->mTimeStamps->flush();
}
if (dec->vproc) {
mpp_buf_slot_set_flag(slots, index, SLOT_QUEUE_USE);
mpp_buf_slot_enqueue(slots, index, QUEUE_DEINTERLACE);
dec_vproc_signal(dec->vproc);
} else {
// direct output -> copy a new MppFrame and output
mpp_list *list = mpp->mFrames;
MppFrame out = NULL;
mpp_frame_init(&out);
mpp_frame_copy(out, frame);
if (mpp_debug & MPP_DBG_PTS)
mpp_log("output frame pts %lld\n", mpp_frame_get_pts(frame));
mpp_log("output frame pts %lld\n", mpp_frame_get_pts(out));
list->lock();
list->add_at_tail(&out, sizeof(out));
mpp->mFramePutCount++;
list->signal();
list->unlock();
}
static void mpp_put_frame_eos(Mpp *mpp, HalDecTaskFlag flags)
{
MppFrame info_frame = NULL;
mpp_frame_init(&info_frame);
mpp_assert(NULL == mpp_frame_get_buffer(info_frame));
mpp_frame_set_eos(info_frame, 1);
if (flags.had_error) {
if (flags.used_for_ref)
mpp_frame_set_errinfo(info_frame, 1);
else
mpp_frame_set_discard(info_frame, 1);
}
mpp_put_frame((Mpp*)mpp, info_frame);
if (mpp->mDec->use_preset_time_order) {
mpp->mTimeStamps->flush();
}
return;
}
static void mpp_dec_push_display(Mpp *mpp, RK_U32 flag)
static void mpp_dec_push_display(Mpp *mpp, HalDecTaskFlag flags)
{
RK_S32 index = -1;
MppDec *dec = mpp->mDec;
MppBufSlots frame_slots = dec->frame_slots;
RK_U32 eos = flags.eos;
HalDecTaskFlag tmp = flags;
tmp.eos = 0;
mpp->mThreadHal->lock(THREAD_OUTPUT);
while (MPP_OK == mpp_buf_slot_dequeue(frame_slots, &index, QUEUE_DISPLAY)) {
MppFrame frame = NULL;
mpp_buf_slot_get_prop(frame_slots, index, SLOT_FRAME, &frame);
/* deal with current frame */
if (flag && mpp_slots_is_empty(frame_slots, QUEUE_DISPLAY))
mpp_frame_set_eos(frame, 1);
if (dec->use_preset_time_order) {
MppPacket pkt_out = NULL;
mpp->mTimeStamps->pull(&pkt_out, sizeof(pkt_out));
if (pkt_out) {
mpp_frame_set_dts(frame, mpp_packet_get_dts(pkt_out));
mpp_frame_set_pts(frame, mpp_packet_get_pts(pkt_out));
mpp_packet_deinit(&pkt_out);
} else
mpp_err_f("pull out packet error.\n");
}
if (!dec->reset_flag)
mpp_put_frame(mpp, frame);
else
mpp_frame_deinit(&frame);
if (eos && mpp_slots_is_empty(frame_slots, QUEUE_DISPLAY))
tmp.eos = 1;
mpp_dec_put_frame(mpp, index, tmp);
mpp_buf_slot_clr_flag(frame_slots, index, SLOT_QUEUE_USE);
}
mpp->mThreadHal->unlock(THREAD_OUTPUT);
@@ -450,11 +499,19 @@ static MPP_RET try_proc_dec_task(Mpp *mpp, DecTask *task)
/* 7.2 look for a unused hardware buffer for output */
if (mpp->mFrameGroup) {
task->wait.dec_pic_buf = (mpp_buffer_group_unused(mpp->mFrameGroup) < 1);
RK_S32 unused = mpp_buffer_group_unused(mpp->mFrameGroup);
// NOTE: When dec post-process is enabled reserve 2 buffer for it.
task->wait.dec_pic_buf = (dec->vproc) ? (unused < 3) : (unused < 1);
if (task->wait.dec_pic_buf)
return MPP_ERR_BUFFER_FULL;
}
/* 7.3 wait for a unused slot index for decoder parse operation */
task->wait.dec_slot_idx = (mpp_slots_get_unused_count(frame_slots)) ? (0) : (1);
if (task->wait.dec_slot_idx)
return MPP_ERR_BUFFER_FULL;
/*
* 8. send packet data to parser
*
@@ -661,16 +718,9 @@ void *mpp_dec_hal_thread(void *data)
* MppFrame without any image data for info change.
*/
if (task_dec->flags.info_change) {
MppFrame info_frame = NULL;
mpp_dec_flush(dec);
mpp_dec_push_display(mpp, 0);
mpp_buf_slot_get_prop(frame_slots, task_dec->output, SLOT_FRAME,
&info_frame);
mpp_assert(info_frame);
mpp_assert(NULL == mpp_frame_get_buffer(info_frame));
mpp_frame_set_info_change(info_frame, 1);
mpp_frame_set_errinfo(info_frame, 0);
mpp_put_frame(mpp, info_frame);
mpp_dec_push_display(mpp, task_dec->flags);
mpp_dec_put_frame(mpp, task_dec->output, task_dec->flags);
hal_task_hnd_set_status(task, TASK_IDLE);
task = NULL;
@@ -684,8 +734,15 @@ void *mpp_dec_hal_thread(void *data)
* all frames have decoded.
*/
if (task_dec->flags.eos && !task_dec->valid) {
mpp_dec_push_display(mpp, 0);
mpp_put_frame_eos(mpp, task_dec->flags);
mpp_dec_push_display(mpp, task_dec->flags);
/*
* Use -1 as invalid buffer slot index.
* Reason: the last task maybe is a empty task with eos flag
* only but this task may go through vproc process also. We need
* create a buffer slot index for it.
*/
mpp_dec_put_frame(mpp, -1, task_dec->flags);
hal_task_hnd_set_status(task, TASK_IDLE);
mpp->mThreadCodec->signal();
task = NULL;
@@ -703,21 +760,12 @@ void *mpp_dec_hal_thread(void *data)
mpp_buf_slot_clr_flag(packet_slots, task_dec->input,
SLOT_HAL_INPUT);
/*
* TODO: Locking the parser thread will prevent it fetching a
* new task. I wish there will be a better way here.
*/
parser->lock();
hal_task_hnd_set_status(task, TASK_PROC_DONE);
task = NULL;
if (dec->parser_fast_mode) {
hal_task_get_hnd(tasks, TASK_PROC_DONE, &task);
if (task) {
hal_task_hnd_set_status(task, TASK_IDLE);
}
}
hal_task_hnd_set_status(task, (dec->parser_fast_mode) ?
(TASK_IDLE) : (TASK_PROC_DONE));
mpp->mThreadCodec->signal();
parser->unlock();
task = NULL;
mpp_buf_slot_clr_flag(frame_slots, task_dec->output, SLOT_HAL_OUTPUT);
for (RK_U32 i = 0; i < MPP_ARRAY_ELEMS(task_dec->refer); i++) {
@@ -727,7 +775,7 @@ void *mpp_dec_hal_thread(void *data)
}
if (task_dec->flags.eos)
mpp_dec_flush(dec);
mpp_dec_push_display(mpp, task_dec->flags.eos);
mpp_dec_push_display(mpp, task_dec->flags);
}
}
@@ -1015,6 +1063,7 @@ MPP_RET mpp_dec_init(MppDec **dec, MppDecCfg *cfg)
p->parser_need_split = cfg->need_split;
p->parser_fast_mode = cfg->fast_mode;
p->parser_internal_pts = cfg->internal_pts;
p->enable_deinterlace = 1;
*dec = p;
return MPP_OK;
} while (0);
@@ -1040,6 +1089,11 @@ MPP_RET mpp_dec_deinit(MppDec *dec)
dec->hal = NULL;
}
if (dec->vproc) {
dec_vproc_deinit(dec->vproc);
dec->vproc = NULL;
}
if (dec->frame_slots) {
mpp_buf_slot_deinit(dec->frame_slots);
dec->frame_slots = NULL;
@@ -1083,12 +1137,7 @@ MPP_RET mpp_dec_flush(MppDec *dec)
MPP_RET mpp_dec_notify(void *ctx, void *info)
{
MppDec *dec = (MppDec *)ctx;
MppFrame info_frame = NULL;
mpp_frame_init(&info_frame);
mpp_assert(NULL == mpp_frame_get_buffer(info_frame));
mpp_frame_set_eos(info_frame, 1);
mpp_put_frame((Mpp*)dec->mpp, info_frame);
(void)ctx;
(void)info;
return MPP_OK;
}
@@ -1125,6 +1174,9 @@ MPP_RET mpp_dec_control(MppDec *dec, MpiCmd cmd, void *param)
case MPP_DEC_SET_PRESENT_TIME_ORDER: {
dec->use_preset_time_order = (param) ? (*((RK_U32 *)param)) : (1);
} break;
case MPP_DEC_SET_ENABLE_DEINTERLACE: {
dec->enable_deinterlace = (param) ? (*((RK_U32 *)param)) : (1);
} break;
default : {
} break;
}

View File

@@ -482,13 +482,11 @@ RK_S32 VpuApiLegacy::init(VpuCodecContext *ctx, RK_U8 *extraData, RK_U32 extra_s
ctx->extradata = mpp_packet_get_data(pkt);
}
pkt = NULL;
}
} else { /* MPP_CTX_DEC */
vpug.CodecType = ctx->codecType;
vpug.ImgWidth = ctx->width;
vpug.ImgHeight = ctx->height;
if (MPP_CTX_DEC == type)
init_frame_info(ctx, mpp_ctx, mpi, &vpug);
if (extraData != NULL) {
@@ -497,6 +495,13 @@ RK_S32 VpuApiLegacy::init(VpuCodecContext *ctx, RK_U8 *extraData, RK_U32 extra_s
mpi->decode_put_packet(mpp_ctx, pkt);
mpp_packet_deinit(&pkt);
}
RK_U32 flag = 0;
ret = mpi->control(mpp_ctx, MPP_DEC_SET_ENABLE_DEINTERLACE, &flag);
if (ret)
mpp_err_f("disable mpp deinterlace failed ret %d\n", ret);
}
init_ok = 1;
vpu_api_dbg_func("leave\n");
@@ -1388,6 +1393,9 @@ RK_S32 VpuApiLegacy::control(VpuCodecContext *ctx, VPU_API_CMD cmd, void *param)
MpiCmd mpicmd = MPI_CMD_BUTT;
switch (cmd) {
case VPU_API_ENABLE_DEINTERLACE : {
mpicmd = MPP_DEC_SET_ENABLE_DEINTERLACE;
} break;
case VPU_API_ENC_SETCFG : {
MppCodingType coding = (MppCodingType)ctx->videoCoding;

View File

@@ -771,7 +771,8 @@ MPP_RET Mpp::control_dec(MpiCmd cmd, MppParam param)
case MPP_DEC_SET_OUTPUT_FORMAT:
case MPP_DEC_SET_DISABLE_ERROR:
case MPP_DEC_SET_PRESENT_TIME_ORDER:
case MPP_DEC_SET_IMMEDIATE_OUT: {
case MPP_DEC_SET_IMMEDIATE_OUT:
case MPP_DEC_SET_ENABLE_DEINTERLACE: {
ret = mpp_dec_control(mDec, cmd, param);
}
default : {

View File

@@ -38,11 +38,14 @@
#define VPROC_DBG_FUNCTION (0x00000001)
#define VPROC_DBG_STATUS (0x00000002)
#define VPROC_DBG_RESET (0x00000004)
#define vproc_dbg_func(fmt, ...) \
vproc_dbg_f(VPROC_DBG_FUNCTION, fmt, ## __VA_ARGS__);
#define vproc_dbg_status(fmt, ...) \
vproc_dbg_f(VPROC_DBG_FUNCTION, fmt, ## __VA_ARGS__);
vproc_dbg_f(VPROC_DBG_STATUS, fmt, ## __VA_ARGS__);
#define vproc_dbg_reset(fmt, ...) \
vproc_dbg_f(VPROC_DBG_RESET, fmt, ## __VA_ARGS__);
RK_U32 vproc_debug = 0;
@@ -120,8 +123,10 @@ static void dec_vproc_reset_queue(MppDecVprocCtxImpl *ctx)
RK_S32 index = -1;
MPP_RET ret = MPP_OK;
vproc_dbg_reset("reset start\n");
dec_vproc_clr_prev(ctx);
vproc_dbg_reset("reset loop start\n");
// on reset just return all index
do {
ret = mpp_buf_slot_dequeue(slots, &index, QUEUE_DEINTERLACE);
@@ -139,10 +144,13 @@ static void dec_vproc_reset_queue(MppDecVprocCtxImpl *ctx)
} while (ret == MPP_OK);
mpp_assert(ctx->count == 0);
vproc_dbg_reset("reset loop done\n");
thd->lock(THREAD_CONTROL);
ctx->reset = 0;
vproc_dbg_reset("reset signal\n");
thd->signal(THREAD_CONTROL);
thd->unlock(THREAD_CONTROL);
vproc_dbg_reset("reset done\n");
}
static void dec_vproc_set_img_fmt(IepImg *img, MppFrame frm)
@@ -500,14 +508,17 @@ MPP_RET dec_vproc_reset(MppDecVprocCtx ctx)
MppDecVprocCtxImpl *p = (MppDecVprocCtxImpl *)ctx;
if (p->thd) {
// wait reset finished
p->thd->lock(THREAD_CONTROL);
p->thd->lock();
p->reset = 1;
p->thd->signal();
p->thd->unlock();
// wait reset finished
p->thd->lock(THREAD_CONTROL);
vproc_dbg_reset("reset contorl wait\n");
p->thd->wait(THREAD_CONTROL);
vproc_dbg_reset("reset contorl done\n");
p->thd->unlock(THREAD_CONTROL);
mpp_assert(p->reset == 0);