[h264d]: Support 3D MVC decoding

Only support stereo high profile MVC. Frames with the same POC of two
views will be output in turn. The base view will be output at first.

Change-Id: I534e07bd079dc31d1a1e9178b81dfb21ffec8f60
Signed-off-by: Johnson Ding <johnson.ding@rock-chips.com>
This commit is contained in:
Johnson Ding
2022-10-14 21:04:31 +08:00
committed by Herman Chen
parent 5136d85679
commit 0923f061ad
7 changed files with 113 additions and 36 deletions

View File

@@ -131,21 +131,22 @@ static MPP_RET free_vid_ctx(H264dVideoCtx_t *p_Vid)
INP_CHECK(ret, !p_Vid);
for (i = 0; i < MAXSPS; i++) {
MPP_FREE(p_Vid->spsSet[i]);
if (p_Vid->subspsSet[i])
recycle_subsps(p_Vid->subspsSet[i]);
}
for (i = 0; i < MAXSPS; i++) {
MPP_FREE(p_Vid->spsSet[i]);
MPP_FREE(p_Vid->subspsSet[i]);
}
for (i = 0; i < MAXPPS; i++) {
for (i = 0; i < MAXPPS; i++)
MPP_FREE(p_Vid->ppsSet[i]);
}
for (i = 0; i < MAX_NUM_DPB_LAYERS; i++) {
free_dpb(p_Vid->p_Dpb_layer[i]);
MPP_FREE(p_Vid->p_Dpb_layer[i]);
}
free_storable_picture(p_Vid->p_Dec, p_Vid->dec_pic);
if (p_Vid->pic_st) {
mpp_mem_pool_deinit(p_Vid->pic_st);
p_Vid->pic_st = NULL;
@@ -290,6 +291,8 @@ static MPP_RET h264d_flush_dpb_eos(H264_DecCtx_t *p_Dec)
// layer_id == 1
FUN_CHECK(ret = flush_dpb(p_Dec->p_Vid->p_Dpb_layer[1], 1));
FUN_CHECK(ret = init_dpb(p_Dec->p_Vid, p_Dec->p_Vid->p_Dpb_layer[1], 2));
p_Dec->p_Vid->p_Dpb_layer[0]->size = MPP_MIN(p_Dec->p_Vid->p_Dpb_layer[1]->size, MAX_DPB_SIZE / 2);
p_Dec->p_Vid->dpb_size[0] = p_Dec->p_Vid->p_Dpb_layer[0]->size;
}
flush_dpb_buf_slot(p_Dec);
@@ -394,6 +397,8 @@ MPP_RET h264d_reset(void *decoder)
// layer_id == 1
FUN_CHECK(ret = flush_dpb(p_Dec->p_Vid->p_Dpb_layer[1], 1));
FUN_CHECK(ret = init_dpb(p_Dec->p_Vid, p_Dec->p_Vid->p_Dpb_layer[1], 2));
p_Dec->p_Vid->p_Dpb_layer[0]->size = MPP_MIN(p_Dec->p_Vid->p_Dpb_layer[1]->size, MAX_DPB_SIZE / 2);
p_Dec->p_Vid->dpb_size[0] = p_Dec->p_Vid->p_Dpb_layer[0]->size;
}
flush_dpb_buf_slot(p_Dec);
//!< reset input parameter
@@ -651,9 +656,10 @@ MPP_RET h264d_callback(void *decoder, void *errinfo)
mpp_frame_set_discard(mframe, MPP_FRAME_ERR_UNKNOW);
}
}
H264D_DBG(H264D_DBG_CALLBACK, "[CALLBACK] g_no=%d, out_idx=%d, dpberr=%d, harderr=%d, ref_flag=%d, errinfo=%d, discard=%d\n",
H264D_DBG(H264D_DBG_CALLBACK, "[CALLBACK] g_no=%d, out_idx=%d, dpberr=%d, harderr=%d, ref_flag=%d, errinfo=%d, discard=%d, poc=%d, view_id=%d\n",
p_Dec->p_Vid->g_framecnt, task_dec->output, task_err, ctx->hard_err, task_dec->flags.used_for_ref,
mpp_frame_get_errinfo(mframe), mpp_frame_get_discard(mframe));
mpp_frame_get_errinfo(mframe), mpp_frame_get_discard(mframe),
mpp_frame_get_poc(mframe), mpp_frame_get_viewid(mframe));
}
}

View File

@@ -853,16 +853,6 @@ static void write_picture(H264_StorePic_t *p, H264dVideoCtx_t *p_Vid)
|| p->mem_malloc_type == Mem_BotOnly)
&& p->structure == FRAME && p_mark->out_flag) {
mpp_buf_slot_get_prop(p_Vid->p_Dec->frame_slots, p_mark->slot_idx, SLOT_FRAME_PTR, &mframe);
mpp_frame_set_poc(mframe, p->poc);
p_mark->poc = p->poc;
p_mark->pts = mpp_frame_get_pts(mframe);
mpp_frame_set_viewid(mframe, p->layer_id);
//if (p->layer_id == 1) {
// mpp_frame_set_discard(frame, 1);
//}
//else {
// mpp_frame_set_discard(frame, 1);
//}
//!< discard unpaired
if (p->mem_malloc_type == Mem_TopOnly || p->mem_malloc_type == Mem_BotOnly) {
@@ -881,10 +871,67 @@ static void write_picture(H264_StorePic_t *p, H264dVideoCtx_t *p_Vid)
mpp_frame_set_discard(mframe, MPP_FRAME_ERR_UNKNOW);
}
}
mpp_buf_slot_set_flag(p_Vid->p_Dec->frame_slots, p_mark->slot_idx, SLOT_QUEUE_USE);
if (p_Vid->p_Dec->mvc_valid && !p_Vid->p_Inp->mvc_disable) {
//muti_view_output(p_Vid->p_Dec->frame_slots, p_mark, p_Vid);
if (p_Vid->p_Dec->mvc_valid) {
H264_DpbMark_t *match_mark = NULL;
H264_DpbMark_t *out_mark_list[2] = {NULL, NULL};
RK_U32 i = 0;
RK_S32 match_flag = 0;
RK_U32 is_base_view = p_mark->pic->layer_id == 0 ? 1 : 0;
// find pic with the same poc at base view
for (i = 0; i < MAX_MARK_SIZE; i++) {
match_mark = &p_Vid->p_Dec->dpb_mark[i];
if (!match_mark || !match_mark->pic || !match_mark->out_flag || match_mark->slot_idx < 0)
continue;
if (match_mark->pic->layer_id != p_mark->pic->layer_id) {
if (match_mark->pic->poc < p_mark->pic->poc) {
match_flag = 1;
break;
} else if (match_mark->pic->poc == p_mark->pic->poc) {
match_flag = 2;
break;
} else {
match_flag = 0;
}
}
}
if (!match_flag) {
H264D_DBG(H264D_DBG_DPB_INFO, "no other view matched with current view_id %d, poc %d",
p_mark->pic->layer_id, p_mark->pic->poc);
out_mark_list[0] = p_mark;
} else if (match_flag == 1) {
H264D_DBG(H264D_DBG_DPB_INFO, "find match view at %d, slot_idx %d, view_id %d, poc %d",
i, match_mark->slot_idx, match_mark->pic->layer_id, match_mark->pic->poc);
out_mark_list[0] = match_mark;
out_mark_list[1] = p_mark;
} else if (match_flag == 2) {
H264D_DBG(H264D_DBG_DPB_INFO, "find match view at %d, slot_idx %d, view_id %d, poc %d",
i, match_mark->slot_idx, match_mark->pic->layer_id, match_mark->pic->poc);
if (is_base_view) {
out_mark_list[0] = p_mark;
out_mark_list[1] = match_mark;
} else {
out_mark_list[0] = match_mark;
out_mark_list[1] = p_mark;
}
}
for (i = 0; i < 2; i++) {
if (out_mark_list[i]) {
mpp_buf_slot_set_flag(p_Vid->p_Dec->frame_slots, out_mark_list[i]->slot_idx, SLOT_QUEUE_USE);
mpp_buf_slot_enqueue(p_Vid->p_Dec->frame_slots, out_mark_list[i]->slot_idx, QUEUE_DISPLAY);
out_mark_list[i]->out_flag = 0;
p_Vid->p_Dec->last_frame_slot_idx = out_mark_list[i]->slot_idx;
}
}
} else {
H264D_DBG(H264D_DBG_DPB_INFO, "display frame view_id %d slot_idx %d poc %d",
p_mark->pic->layer_id, p_mark->slot_idx, p_mark->pic->poc);
mpp_buf_slot_set_flag(p_Vid->p_Dec->frame_slots, p_mark->slot_idx, SLOT_QUEUE_USE);
mpp_buf_slot_enqueue(p_Vid->p_Dec->frame_slots, p_mark->slot_idx, QUEUE_DISPLAY);
p_Vid->p_Dec->last_frame_slot_idx = p_mark->slot_idx;
p_mark->out_flag = 0;
@@ -907,6 +954,7 @@ static MPP_RET write_unpaired_field(H264dVideoCtx_t *p_Vid, H264_FrameStore_t *f
FUN_CHECK(ret = dpb_combine_field_yuv(p_Vid, fs, 0));
fs->frame->view_id = fs->view_id;
fs->frame->mem_malloc_type = Mem_TopOnly;
H264D_WARNNING("write frame, line %d", __LINE__);
write_picture(fs->frame, p_Vid);
}
@@ -926,6 +974,7 @@ static MPP_RET write_unpaired_field(H264dVideoCtx_t *p_Vid, H264_FrameStore_t *f
FUN_CHECK(ret = dpb_combine_field_yuv(p_Vid, fs, 0));
fs->frame->view_id = fs->view_id;
fs->frame->mem_malloc_type = Mem_BotOnly;
H264D_WARNNING("write frame, line %d", __LINE__);
write_picture(fs->frame, p_Vid);
}
fs->is_used = 3;
@@ -968,6 +1017,7 @@ static MPP_RET write_stored_frame(H264dVideoCtx_t *p_Vid, H264_DpbBuf_t *p_Dpb,
fs->top_field = NULL;
fs->bottom_field = NULL;
} else {
H264D_WARNNING("write frame, line %d", __LINE__);
write_picture(fs->frame, p_Vid);
}
p_Dpb->last_output_poc = fs->poc;
@@ -989,6 +1039,7 @@ static MPP_RET output_one_frame_from_dpb(H264_DpbBuf_t *p_Dpb)
//!< find smallest POC
if (get_smallest_poc(p_Dpb, &poc, &pos)) {
//!< JVT-P072 ends
H264D_WARNNING("write_stored_frame, line %d", __LINE__);
FUN_CHECK(ret = write_stored_frame(p_Vid, p_Dpb, p_Dpb->fs[pos]));
//!< free frame store and move empty store to end of buffer
if (!is_used_for_reference(p_Dpb->fs[pos])) {
@@ -1195,6 +1246,7 @@ static MPP_RET direct_output(H264dVideoCtx_t *p_Vid, H264_DpbBuf_t *p_Dpb, H264_
if (p->structure == FRAME) {
//!< we have a frame (or complementary field pair), so output it directly
FUN_CHECK(ret = flush_direct_output(p_Vid));
H264D_WARNNING("write frame, line %d", __LINE__);
write_picture(p, p_Vid);
p_Dpb->last_output_poc = p->poc;
free_storable_picture(p_Vid->p_Dec, p);
@@ -1230,6 +1282,7 @@ static MPP_RET direct_output(H264dVideoCtx_t *p_Vid, H264_DpbBuf_t *p_Dpb, H264_
//!< we have both fields, so output them
FUN_CHECK(ret = dpb_combine_field_yuv(p_Vid, &p_Vid->out_buffer, 0));
p_Vid->out_buffer.frame->view_id = p_Vid->out_buffer.view_id;
H264D_WARNNING("write frame, line %d", __LINE__);
write_picture(p_Vid->out_buffer.frame, p_Vid);
free_storable_picture(p_Vid->p_Dec, p_Vid->out_buffer.frame);
p_Vid->out_buffer.frame = NULL;
@@ -1271,6 +1324,7 @@ static MPP_RET scan_dpb_output(H264_DpbBuf_t *p_Dpb, H264_StorePic_t *p)
if ((p_Dpb->last_output_poc > INT_MIN) && (abs(poc_inc) & 0x1))
p_Dpb->poc_interval = 1;
if ((min_poc - p_Dpb->last_output_poc) <= p_Dpb->poc_interval) {
H264D_WARNNING("write_stored_frame, line %d", __LINE__);
FUN_CHECK(ret = write_stored_frame(p_Dpb->p_Vid, p_Dpb, p_Dpb->fs[min_pos]));
} else {
break;
@@ -1357,6 +1411,8 @@ MPP_RET store_picture_in_dpb(H264_DpbBuf_t *p_Dpb, H264_StorePic_t *p)
}
while (!remove_unused_frame_from_dpb(p_Dpb));
//!< when full output one frame
H264D_DBG(H264D_DBG_DPB_INFO, "before out, dpb[%d] used_size %d, size %d",
p_Dpb->layer_id, p_Dpb->used_size, p_Dpb->size);
while (p_Dpb->used_size >= p_Dpb->size) {
RK_S32 min_poc = 0, min_pos = 0;
RK_S32 find_flag = 0;
@@ -1374,6 +1430,7 @@ MPP_RET store_picture_in_dpb(H264_DpbBuf_t *p_Dpb, H264_StorePic_t *p)
//min_pos = 0;
unmark_for_reference(p_Vid->p_Dec, p_Dpb->fs[min_pos]);
if (!p_Dpb->fs[min_pos]->is_output) {
H264D_WARNNING("write_stored_frame, line %d", __LINE__);
FUN_CHECK(ret = write_stored_frame(p_Vid, p_Dpb, p_Dpb->fs[min_pos]));
}
FUN_CHECK(ret = remove_frame_from_dpb(p_Dpb, min_pos));
@@ -1381,6 +1438,8 @@ MPP_RET store_picture_in_dpb(H264_DpbBuf_t *p_Dpb, H264_StorePic_t *p)
}
FUN_CHECK(ret = output_one_frame_from_dpb(p_Dpb));
}
H264D_DBG(H264D_DBG_DPB_INFO, "after out, dpb[%d] used_size %d, size %d",
p_Dpb->layer_id, p_Dpb->used_size, p_Dpb->size);
//!< store current decoder picture at end of dpb
FUN_CHECK(ret = insert_picture_in_dpb(p_Vid, p_Dpb->fs[p_Dpb->used_size], p, 0));
if (p->structure != FRAME) {
@@ -1393,7 +1452,8 @@ MPP_RET store_picture_in_dpb(H264_DpbBuf_t *p_Dpb, H264_StorePic_t *p)
p_Dpb->used_size++;
H264D_DBG(H264D_DBG_DPB_INFO, "[DPB_size] p_Dpb->used_size=%d", p_Dpb->used_size);
scan_dpb_output(p_Dpb, p);
if (!p_Vid->p_Dec->mvc_valid)
scan_dpb_output(p_Dpb, p);
update_ref_list(p_Dpb);
update_ltref_list(p_Dpb);
@@ -1443,7 +1503,7 @@ void free_dpb(H264_DpbBuf_t *p_Dpb)
H264dVideoCtx_t *p_Vid = p_Dpb->p_Vid;
if (p_Dpb->fs) {
for (i = 0; i < p_Dpb->size; i++) {
for (i = 0; i < p_Dpb->allocated_size; i++) {
free_frame_store(p_Vid->p_Dec, p_Dpb->fs[i]);
p_Dpb->fs[i] = NULL;
}
@@ -1753,6 +1813,7 @@ MPP_RET init_dpb(H264dVideoCtx_t *p_Vid, H264_DpbBuf_t *p_Dpb, RK_S32 type) //
}
dpb_size = getDpbSize(p_Vid, active_sps);
p_Dpb->size = MPP_MAX(1, dpb_size);
p_Dpb->allocated_size = p_Dpb->size;
p_Dpb->num_ref_frames = active_sps->max_num_ref_frames;
if (active_sps->max_dec_frame_buffering < active_sps->max_num_ref_frames) {
H264D_WARNNING("DPB size at specified level is smaller than reference frames");
@@ -1822,6 +1883,8 @@ MPP_RET flush_dpb(H264_DpbBuf_t *p_Dpb, RK_S32 type)
if (!p_Dpb->init_done) {
goto __RETURN;
}
H264D_DBG(H264D_DBG_DPB_INFO, "dpb layer %d, used_size %d",
p_Dpb->layer_id, p_Dpb->used_size);
//!< mark all frames unused
for (i = 0; i < p_Dpb->used_size; i++) {
if (p_Dpb->fs[i] && p_Dpb->p_Vid) {

View File

@@ -265,8 +265,6 @@ typedef struct h264_dpb_mark_t {
RK_U8 mark_idx;
MppFrame mframe;
RK_S32 slot_idx;
RK_S32 poc;
RK_S64 pts;
struct h264_store_pic_t *pic;
} H264_DpbMark_t;
@@ -389,6 +387,7 @@ typedef struct h264_frame_store_t {
typedef struct h264_dpb_buf_t {
RK_U32 size;
RK_U32 used_size;
RK_U32 allocated_size;
RK_U32 ref_frames_in_buffer;
RK_U32 ltref_frames_in_buffer;
RK_U32 used_size_il;

View File

@@ -545,6 +545,9 @@ static MPP_RET dpb_mark_malloc(H264dVideoCtx_t *p_Vid, H264_StorePic_t *dec_pic)
impl->colorspace = MPP_FRAME_SPC_UNSPECIFIED;
}
}
impl->poc = dec_pic->poc;
impl->viewid = dec_pic->layer_id;
mpp_buf_slot_set_prop(p_Dec->frame_slots, cur_mark->slot_idx, SLOT_FRAME, p_Dec->curframe);
mpp_buf_slot_get_prop(p_Dec->frame_slots, cur_mark->slot_idx, SLOT_FRAME_PTR, &cur_mark->mframe);
}
@@ -1110,7 +1113,7 @@ static MPP_RET init_lists_p_slice_mvc(H264_SLICE_t *currSlice)
MEM_CHECK(ret, currSlice->fs_listinterview0);
list0idx = currSlice->listXsizeP[0];
if (currSlice->structure == FRAME) {
FUN_CHECK(ret = append_interview_list(p_Vid->p_Dpb_layer[1], 0, 0,
FUN_CHECK(ret = append_interview_list(p_Vid->p_Dpb_layer[1], currSlice->structure, 0,
currSlice->fs_listinterview0, &currSlice->listinterviewidx0, currPOC, curr_layer_id, anchor_pic_flag));
for (i = 0; i < (RK_U32)currSlice->listinterviewidx0; i++) {
currSlice->listP[0][list0idx++] = currSlice->fs_listinterview0[i]->frame;
@@ -1279,9 +1282,9 @@ static MPP_RET init_lists_b_slice_mvc(H264_SLICE_t *currSlice)
MEM_CHECK(ret, currSlice->fs_listinterview0 && currSlice->fs_listinterview1);
list0idx = currSlice->listXsizeB[0];
if (currSlice->structure == FRAME) {
FUN_CHECK(ret = append_interview_list(p_Vid->p_Dpb_layer[1], 0, 0,
FUN_CHECK(ret = append_interview_list(p_Vid->p_Dpb_layer[1], currSlice->structure, 0,
currSlice->fs_listinterview0, &currSlice->listinterviewidx0, currPOC, curr_layer_id, anchor_pic_flag));
FUN_CHECK(ret = append_interview_list(p_Vid->p_Dpb_layer[1], 0, 1,
FUN_CHECK(ret = append_interview_list(p_Vid->p_Dpb_layer[1], currSlice->structure, 1,
currSlice->fs_listinterview1, &currSlice->listinterviewidx1, currPOC, curr_layer_id, anchor_pic_flag));
for (i = 0; i < (RK_U32)currSlice->listinterviewidx0; i++) {
@@ -1927,14 +1930,15 @@ static MPP_RET check_refer_dpb_buf_slots(H264_SLICE_t *currSlice)
mpp_buf_slot_get_prop(p_Dec->frame_slots, p_mark->slot_idx, SLOT_FRAME_PTR, &mframe);
mbuffer = mframe ? mpp_frame_get_buffer(mframe) : NULL;
fd = mbuffer ? mpp_buffer_get_fd(mbuffer) : 0xFF;
H264D_DBG(H264D_DBG_DPB_INFO, "[DPB_MARK_INFO] slot_idx=%d, top_used=%d, bot_used=%d, out_flag=%d, fd=0x%02x",
p_mark->slot_idx, p_mark->top_used, p_mark->bot_used, p_mark->out_flag, fd);
H264D_DBG(H264D_DBG_DPB_INFO, "[DPB_MARK_INFO] slot_idx=%d, top_used=%d, bot_used=%d, out_flag=%d, fd=0x%02x, poc=%d, view_id=%d",
p_mark->slot_idx, p_mark->top_used, p_mark->bot_used,
p_mark->out_flag, fd, p_mark->pic->poc, p_mark->pic->layer_id);
}
}
}
H264D_DBG(H264D_DBG_DPB_INFO, "[DPB_MARK_INFO] ---------- cur_slot=%d --------------------", p_Dec->in_task->output);
if (dpb_used > currSlice->p_Dpb->size + 2) {
if (dpb_used > MPP_MIN(p_Dec->p_Vid->dpb_size[0] + p_Dec->p_Vid->dpb_size[1], 16) + 2) {
H264D_ERR("[h264d_reset_error]");
h264d_reset((void *)p_Dec);
return MPP_NOK;

View File

@@ -79,12 +79,13 @@ static void reset_slice(H264dVideoCtx_t *p_Vid)
memset(currSlice, 0, sizeof(H264_SLICE_t));
//-- re-init parameters
currSlice->view_id = -1;
currSlice->p_Vid = p_Vid;
currSlice->p_Dec = p_Vid->p_Dec;
currSlice->p_Cur = p_Vid->p_Cur;
currSlice->p_Inp = p_Vid->p_Inp;
currSlice->p_Vid = p_Vid;
currSlice->p_Dec = p_Vid->p_Dec;
currSlice->p_Cur = p_Vid->p_Cur;
currSlice->p_Inp = p_Vid->p_Inp;
currSlice->active_sps = p_Vid->active_sps;
currSlice->active_pps = p_Vid->active_pps;
currSlice->active_subsps = p_Vid->active_subsps;
//--- reset listP listB
for (i = 0; i < MAX_NUM_DPB_LAYERS; i++) {
currSlice->listP[i] = p_Vid->p_Cur->listP[i];
@@ -420,6 +421,7 @@ static MPP_RET judge_is_new_frame(H264dCurCtx_t *p_Cur, H264dCurStream_t *p_strm
&& (p_strm->nalu_type == H264_NALU_TYPE_SEI
|| p_strm->nalu_type == H264_NALU_TYPE_SPS
|| p_strm->nalu_type == H264_NALU_TYPE_PPS
|| p_strm->nalu_type == H264_NALU_TYPE_SUB_SPS
|| p_strm->nalu_type == H264_NALU_TYPE_AUD
/*|| p_strm->nalu_type == H264_NALU_TYPE_PREFIX*/)) { // prefix may insert in slices of one frame
if (p_Cur->p_Dec->have_slice_data) {

View File

@@ -234,8 +234,7 @@ static void init_slice_parmeters(H264_SLICE_t *currSlice)
H264_Nalu_t *cur_nalu = &currSlice->p_Cur->nalu;
//--- init slice syntax
currSlice->idr_flag = ((cur_nalu->nalu_type == H264_NALU_TYPE_IDR)
|| (currSlice->mvcExt.valid && !currSlice->mvcExt.non_idr_flag));
currSlice->idr_flag = cur_nalu->nalu_type == H264_NALU_TYPE_IDR;
currSlice->nal_reference_idc = cur_nalu->nal_reference_idc;
//!< set ref flag and dpb error flag
{

View File

@@ -580,6 +580,10 @@ MPP_RET activate_sps(H264dVideoCtx_t *p_Vid, H264_SPS_t *sps, H264_subSPS_t *sub
//!< init frame slots, store frame buffer size
p_Vid->dpb_size[1] = p_Vid->p_Dpb_layer[1]->size;
p_Vid->spspps_update = 1;
if (p_Vid->p_Dec->mvc_valid && p_Vid->p_Dpb_layer[1]->size > 0) {
p_Vid->p_Dpb_layer[0]->size = MPP_MIN(p_Vid->p_Dpb_layer[1]->size, MAX_DPB_SIZE / 2);
p_Vid->dpb_size[0] = p_Vid->p_Dpb_layer[0]->size;
}
}
VAL_CHECK(ret, p_Vid->dpb_size[1] > 0);
} else { //!< layer_id == 0