From 0ee683acf33712257afbfb439df77fb0c2db588f Mon Sep 17 00:00:00 2001 From: Hongjin Li Date: Mon, 9 May 2022 17:51:47 +0800 Subject: [PATCH] [enc_gdr]: Platform supports intra refresh Add parameters required for intra refresh Add rate control corresponding to intra refresh Change-Id: I6dbaf70e3c50cd0debf909ded9fb5c4f30df26ec Signed-off-by: Hongjin Li --- inc/mpp_rc_api.h | 1 + inc/mpp_rc_defs.h | 12 +++++++- inc/rk_venc_cmd.h | 6 ++++ inc/rk_venc_rc.h | 6 ++++ mpp/base/inc/mpp_enc_cfg_impl.h | 2 ++ mpp/base/inc/mpp_enc_refs.h | 1 + mpp/base/mpp_enc_cfg.cpp | 3 ++ mpp/base/mpp_enc_refs.cpp | 54 +++++++++++++++++++++++++++++++-- mpp/codec/mpp_enc_impl.cpp | 41 ++++++++++++++++++++++++- mpp/codec/rc/rc_ctx.h | 3 ++ mpp/codec/rc/rc_model_v2.c | 48 +++++++++++++++++++++++++++-- 11 files changed, 169 insertions(+), 8 deletions(-) diff --git a/inc/mpp_rc_api.h b/inc/mpp_rc_api.h index 4374227e..71e845d1 100644 --- a/inc/mpp_rc_api.h +++ b/inc/mpp_rc_api.h @@ -179,6 +179,7 @@ typedef struct RcCfg_s { RcSuperframeCfg super_cfg; RcDebreathCfg debreath_cfg; RcHierQPCfg hier_qp_cfg; + RK_U32 refresh_len; } RcCfg; /* diff --git a/inc/mpp_rc_defs.h b/inc/mpp_rc_defs.h index 06a55e05..b61fafd1 100644 --- a/inc/mpp_rc_defs.h +++ b/inc/mpp_rc_defs.h @@ -26,6 +26,7 @@ typedef enum EncFrmType_e { INTER_B_FRAME = 1, INTRA_FRAME = 2, INTER_VI_FRAME = 3, + INTRA_RFH_FRAME = 4, } EncFrmType; /* @@ -131,7 +132,16 @@ typedef union EncFrmStatus_u { * When true currnet frame is force to encoded as software skip frame */ RK_U32 force_pskip : 1; - RK_U32 reserved1 : 3; + + /* + * Current frame is intra refresh frame + */ + RK_U32 is_i_refresh : 1; + /* + * Current frame needs add recovery point prefix + */ + RK_U32 is_i_recovery : 1; + RK_U32 reserved1 : 1; /* reencode times */ RK_U32 reencode_times : 8; diff --git a/inc/rk_venc_cmd.h b/inc/rk_venc_cmd.h index 89821ef4..76581998 100644 --- a/inc/rk_venc_cmd.h +++ b/inc/rk_venc_cmd.h @@ -236,6 +236,7 @@ typedef enum MppEncRcCfgChange_e { MPP_ENC_RC_CFG_CHANGE_DEBREATH = (1 << 24), MPP_ENC_RC_CFG_CHANGE_HIER_QP = (1 << 25), MPP_ENC_RC_CFG_CHANGE_ST_TIME = (1 << 26), + MPP_ENC_RC_CFG_CHANGE_REFRESH = (1 << 27), MPP_ENC_RC_CFG_CHANGE_ALL = (0xFFFFFFFF), } MppEncRcCfgChange; @@ -406,6 +407,11 @@ typedef struct MppEncRcCfg_t { RK_S32 hier_qp_en; RK_S32 hier_qp_delta[4]; RK_S32 hier_frame_num[4]; + + RK_U32 refresh_en; + MppEncRcRefreshMode refresh_mode; + RK_U32 refresh_num; + RK_S32 refresh_length; } MppEncRcCfg; diff --git a/inc/rk_venc_rc.h b/inc/rk_venc_rc.h index e2996dfb..b03289c1 100644 --- a/inc/rk_venc_rc.h +++ b/inc/rk_venc_rc.h @@ -57,4 +57,10 @@ typedef enum MppEncRcGopMode_e { MPP_ENC_RC_GOP_MODE_BUTT, } MppEncRcGopMode; +typedef enum MppEncRcIntraRefreshMode_e { + MPP_ENC_RC_INTRA_REFRESH_ROW = 0, + MPP_ENC_RC_INTRA_REFRESH_COL, + MPP_ENC_RC_INTRA_REFRESH_BUTT +} MppEncRcRefreshMode; + #endif /*__RK_VENC_RC_H__*/ diff --git a/mpp/base/inc/mpp_enc_cfg_impl.h b/mpp/base/inc/mpp_enc_cfg_impl.h index 6d371e3f..472e4518 100644 --- a/mpp/base/inc/mpp_enc_cfg_impl.h +++ b/mpp/base/inc/mpp_enc_cfg_impl.h @@ -20,6 +20,8 @@ #include "mpp_trie.h" #include "mpp_enc_cfg.h" +extern RK_U8 uuid_refresh_cfg[16]; + typedef struct MppEncCfgImpl_t { RK_S32 size; MppEncCfgSet cfg; diff --git a/mpp/base/inc/mpp_enc_refs.h b/mpp/base/inc/mpp_enc_refs.h index 2e8e8a11..ca9de1b4 100644 --- a/mpp/base/inc/mpp_enc_refs.h +++ b/mpp/base/inc/mpp_enc_refs.h @@ -61,6 +61,7 @@ MPP_RET mpp_enc_refs_deinit(MppEncRefs *refs); MPP_RET mpp_enc_refs_set_cfg(MppEncRefs refs, MppEncRefCfg ref_cfg); MPP_RET mpp_enc_refs_set_usr_cfg(MppEncRefs refs, MppEncRefFrmUsrCfg *force); MPP_RET mpp_enc_refs_set_rc_igop(MppEncRefs refs, RK_S32 igop); +MPP_RET mpp_enc_refs_set_refresh_length(MppEncRefs refs, RK_S32 len); /* return hdr need update or not */ RK_S32 mpp_enc_refs_update_hdr(MppEncRefs refs); diff --git a/mpp/base/mpp_enc_cfg.cpp b/mpp/base/mpp_enc_cfg.cpp index 480446dc..dbcaf942 100644 --- a/mpp/base/mpp_enc_cfg.cpp +++ b/mpp/base/mpp_enc_cfg.cpp @@ -162,6 +162,9 @@ public: ENTRY(rc, hier_qp_delta, St, RK_S32 *, MPP_ENC_RC_CFG_CHANGE_HIER_QP, rc, hier_qp_delta) \ ENTRY(rc, hier_frame_num, St, RK_S32 *, MPP_ENC_RC_CFG_CHANGE_HIER_QP, rc, hier_frame_num) \ ENTRY(rc, stats_time, S32, RK_S32, MPP_ENC_RC_CFG_CHANGE_ST_TIME, rc, stats_time) \ + ENTRY(rc, refresh_en, U32, RK_U32, MPP_ENC_RC_CFG_CHANGE_REFRESH, rc, refresh_en) \ + ENTRY(rc, refresh_mode, U32, MppEncRcRefreshMode, MPP_ENC_RC_CFG_CHANGE_REFRESH, rc, refresh_mode) \ + ENTRY(rc, refresh_num, U32, RK_U32, MPP_ENC_RC_CFG_CHANGE_REFRESH, rc, refresh_num) \ /* prep config */ \ ENTRY(prep, width, S32, RK_S32, MPP_ENC_PREP_CFG_CHANGE_INPUT, prep, width) \ ENTRY(prep, height, S32, RK_S32, MPP_ENC_PREP_CFG_CHANGE_INPUT, prep, height) \ diff --git a/mpp/base/mpp_enc_refs.cpp b/mpp/base/mpp_enc_refs.cpp index 60780a34..6a96be72 100644 --- a/mpp/base/mpp_enc_refs.cpp +++ b/mpp/base/mpp_enc_refs.cpp @@ -104,6 +104,7 @@ typedef struct MppEncRefsImpl_t { MppEncRefCfgImpl *ref_cfg; MppEncRefFrmUsrCfg usr_cfg; RK_S32 igop; + RK_U32 refresh_length; RK_S32 hdr_need_update; @@ -318,6 +319,22 @@ static void set_st_cfg_to_frm(EncFrmStatus *frm, RK_S32 seq_idx, dump_frm(frm); } +static MPP_RET set_frm_refresh_flag(EncFrmStatus *frm, MppEncRefsImpl *p) +{ + MPP_RET ret = MPP_OK; + + if (!frm || !p) + return ret = MPP_ERR_NULL_PTR; + + if (p->refresh_length) { + frm->is_i_refresh = ((frm->seq_idx % p->igop) < p->refresh_length) && p->cpb.seq_cnt > 1; + frm->is_i_recovery = !(frm->seq_idx % p->igop) && p->cpb.seq_cnt > 1; + } else + frm->is_i_refresh = 0; + + return ret; +} + static void set_lt_cfg_to_frm(EncFrmStatus *frm, RefsCnt *lt_cfg) { frm->is_non_ref = 0; @@ -339,7 +356,7 @@ static EncFrmStatus *get_ref_from_cpb(EncVirtualCpb *cpb, EncFrmStatus *frm) MppEncRefMode ref_mode = frm->ref_mode; RK_S32 ref_arg = frm->ref_arg; - if (frm->is_intra) + if (frm->is_idr) return NULL; EncFrmStatus *ref = NULL; @@ -592,6 +609,7 @@ MPP_RET mpp_enc_refs_dryrun(MppEncRefs refs) while (repeat-- > 0) { /* step 1. updated by st_cfg */ set_st_cfg_to_frm(&frm, seq_idx++, st_cfg); + set_frm_refresh_flag(&frm, p); /* step 2. updated by lt_cfg */ RefsCnt *lt_cfg = &cpb->lt_cnter[0]; @@ -694,6 +712,30 @@ MPP_RET mpp_enc_refs_set_rc_igop(MppEncRefs refs, RK_S32 igop) return MPP_OK; } +MPP_RET mpp_enc_refs_set_refresh_length(MppEncRefs refs, RK_S32 len) +{ + MPP_RET ret = MPP_OK; + if (NULL == refs) { + mpp_err_f("invalid NULL input refs\n"); + return MPP_ERR_VALUE; + } + + enc_refs_dbg_func("enter %p\n", refs); + + MppEncRefsImpl *p = (MppEncRefsImpl *)refs; + + if (len < p->igop) { + p->refresh_length = len; + } else { + p->refresh_length = p->igop; + ret = MPP_ERR_VALUE; + goto RET; + } + enc_refs_dbg_func("leave %p\n", refs); +RET: + return ret; +} + RK_S32 mpp_enc_refs_update_hdr(MppEncRefs refs) { if (NULL == refs) { @@ -764,12 +806,17 @@ MPP_RET mpp_enc_refs_get_cpb(MppEncRefs refs, EncCpbStatus *status) if (p->changed & ENC_REFS_IGOP_CHANGED) cleanup_cpb = 1; - if (p->igop && cpb->seq_idx >= p->igop) - cleanup_cpb = 1; + if (p->igop && (cpb->seq_idx >= p->igop)) { + if (p->refresh_length) { + p->cpb.seq_cnt = cpb->seq_idx / p->igop + 1; + } else + cleanup_cpb = 1; + } if (usr_cfg->force_flag & ENC_FORCE_IDR) { usr_cfg->force_flag &= (~ENC_FORCE_IDR); cleanup_cpb = 1; + p->cpb.seq_cnt = 0; } if (cleanup_cpb) { @@ -787,6 +834,7 @@ MPP_RET mpp_enc_refs_get_cpb(MppEncRefs refs, EncCpbStatus *status) st_cfg = &cfg->st_cfg[cpb->st_cfg_pos]; /* step 2. updated by st_cfg */ set_st_cfg_to_frm(frm, cpb->seq_idx++, st_cfg); + set_frm_refresh_flag(frm, p); lt_cfg = p->cpb.lt_cnter; diff --git a/mpp/codec/mpp_enc_impl.cpp b/mpp/codec/mpp_enc_impl.cpp index 955cfdb4..b16d1068 100644 --- a/mpp/codec/mpp_enc_impl.cpp +++ b/mpp/codec/mpp_enc_impl.cpp @@ -77,6 +77,11 @@ static RK_U8 uuid_debug_info[16] = { 0xa9, 0x06, 0xae, 0x29, 0x94, 0x11, 0xcd, 0x9a }; +RK_U8 uuid_refresh_cfg[16] = { + 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, + 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x00, 0x00 +}; + static void reset_hal_enc_task(HalEncTask *task) { memset(task, 0, sizeof(*task)); @@ -562,8 +567,16 @@ MPP_RET mpp_enc_proc_rc_cfg(MppCodingType coding, MppEncRcCfg *dst, MppEncRcCfg dst->fps_out_denorm = src->fps_out_denorm; } - if (change & MPP_ENC_RC_CFG_CHANGE_GOP) + if (change & MPP_ENC_RC_CFG_CHANGE_GOP) { + /* + * If GOP is changed smaller, disable Intra-Refresh + * and User level should reconfig Intra-Refresh + */ + if (dst->gop < src->gop && dst->refresh_en) { + dst->refresh_en = 0; + } dst->gop = src->gop; + } if (change & MPP_ENC_RC_CFG_CHANGE_MAX_REENC) dst->max_reenc_times = src->max_reenc_times; @@ -643,6 +656,17 @@ MPP_RET mpp_enc_proc_rc_cfg(MppCodingType coding, MppEncRcCfg *dst, MppEncRcCfg if (change & MPP_ENC_RC_CFG_CHANGE_ST_TIME) dst->stats_time = src->stats_time; + if (change & MPP_ENC_RC_CFG_CHANGE_REFRESH) { + if (dst->debreath_en) { + mpp_err_f("Turn off Debreath first."); + ret = MPP_ERR_VALUE; + } + dst->refresh_en = src->refresh_en; + dst->refresh_mode = src->refresh_mode; + // Make sure refresh_num is legal + dst->refresh_num = src->refresh_num; + } + // parameter checking if (dst->rc_mode >= MPP_ENC_RC_MODE_BUTT) { mpp_err("invalid rc mode %d should be RC_MODE_VBR or RC_MODE_CBR\n", @@ -1041,6 +1065,9 @@ MPP_RET mpp_enc_proc_cfg(MppEncImpl *enc, MpiCmd cmd, void *param) if (check_rc_gop_update(cmd, &enc->cfg)) mpp_enc_refs_set_rc_igop(enc->refs, enc->cfg.rc.gop); + if (enc->cfg.rc.refresh_en) + mpp_enc_refs_set_refresh_length(enc->refs, enc->cfg.rc.refresh_length); + if (check_hal_info_update(cmd)) enc->hal_info_updated = 0; @@ -1213,6 +1240,8 @@ static void set_rc_cfg(RcCfg *cfg, MppEncCfgSet *cfg_set) cfg->debreath_cfg.enable = rc->debreath_en; cfg->debreath_cfg.strength = rc->debre_strength; + cfg->refresh_len = rc->refresh_length; + if (info->st_gop) { cfg->vgop = info->st_gop; if (cfg->vgop >= rc->fps_out_num / rc->fps_out_denorm && @@ -1514,6 +1543,16 @@ static MPP_RET mpp_enc_normal(Mpp *mpp, EncAsyncTaskInfo *task) hal_task->length += length; } + if (!frm->is_idr && frm->is_i_recovery && enc->cfg.rc.refresh_en) { + RK_S32 length = 0; + + enc_impl_add_prefix(impl, packet, &length, uuid_refresh_cfg, + &enc->cfg.rc.refresh_length, 0); + + hal_task->sei_length += length; + hal_task->length += length; + } + if (mpp_frame_has_meta(frame)) { update_user_datas(impl, packet, frame, hal_task); } diff --git a/mpp/codec/rc/rc_ctx.h b/mpp/codec/rc/rc_ctx.h index c4264c33..727f8121 100644 --- a/mpp/codec/rc/rc_ctx.h +++ b/mpp/codec/rc/rc_ctx.h @@ -40,12 +40,15 @@ typedef struct RcModelV2Ctx_t { MppDataV2 *vi_bit; RK_U32 vi_sumbits; RK_U32 vi_scale; + RK_U32 i_refresh_scale; MppDataV2 *p_bit; RK_U32 p_sumbits; + RK_U32 i_refresh_sumbits; RK_U32 p_scale; MppDataV2 *pre_p_bit; MppDataV2 *pre_i_bit; + MppDataV2 *i_refresh_bit; MppDataV2 *pre_i_mean_qp; MppDataV2 *madi; MppDataV2 *madp; diff --git a/mpp/codec/rc/rc_model_v2.c b/mpp/codec/rc/rc_model_v2.c index 04215bf1..b20152af 100644 --- a/mpp/codec/rc/rc_model_v2.c +++ b/mpp/codec/rc/rc_model_v2.c @@ -202,6 +202,14 @@ MPP_RET bits_model_param_init(RcModelV2Ctx *ctx) mpp_err("gop_bits init fail gop_len %d", gop_len); return MPP_ERR_MALLOC; } + + if (ctx->usr_cfg.refresh_len) { + mpp_data_init_v2(&ctx->i_refresh_bit, ctx->usr_cfg.refresh_len, 0); + if (ctx->i_refresh_bit == NULL) { + mpp_err("i_refresh_bit init fail refresh_len %d", ctx->usr_cfg.refresh_len); + return MPP_ERR_MALLOC; + } + } return MPP_OK; } @@ -210,6 +218,7 @@ void bits_frm_init(RcModelV2Ctx *ctx) RcCfg *usr_cfg = &ctx->usr_cfg; RK_U32 gop_len = usr_cfg->igop; RK_U32 p_bit = 0; + RK_U32 refresh_bit = 0; rc_dbg_func("enter %p\n", ctx); @@ -225,6 +234,13 @@ void bits_frm_init(RcModelV2Ctx *ctx) ctx->p_sumbits = 5 * p_bit; mpp_data_reset_v2(ctx->i_bit, p_bit * ctx->i_scale / 16); ctx->i_sumbits = 2 * p_bit * ctx->i_scale / 16; + if (usr_cfg->refresh_len) { + ctx->i_refresh_scale = ctx->i_scale / usr_cfg->refresh_len + ctx->p_scale; + refresh_bit = ctx->gop_total_bits * 16 / (ctx->i_refresh_scale * usr_cfg->refresh_len + + ctx->p_scale * (gop_len - usr_cfg->refresh_len)); + mpp_data_reset_v2(ctx->i_refresh_bit, refresh_bit); + ctx->i_refresh_sumbits = usr_cfg->refresh_len * refresh_bit; + } } break; case SMART_P: { RK_U32 vi_num = 0; @@ -329,6 +345,13 @@ MPP_RET bits_model_preset(RcModelV2Ctx *ctx, EncRcTaskInfo *info) /* NOTE: vi_scale may be set to zero. So we should limit the range */ ctx->vi_scale = mpp_clip(ctx->vi_scale, 16, 320); } break; + case INTRA_RFH_FRAME: { + mpp_data_update_v2(ctx->i_refresh_bit, preset_bit); + mpp_data_update_v2(ctx->madi, info->madi); + ctx->i_refresh_sumbits = mpp_data_sum_v2(ctx->i_refresh_bit); + ctx->i_refresh_scale = 80 * ctx->i_refresh_sumbits / (usr_cfg->refresh_len * ctx->p_sumbits); + ctx->i_refresh_scale = mpp_clip(ctx->i_refresh_scale, 16, 64); + } break; default : { } break; } @@ -384,6 +407,13 @@ MPP_RET bits_model_update(RcModelV2Ctx *ctx, EncRcTaskInfo *cfg) /* NOTE: vi_scale may be set to zero. So we should limit the range */ ctx->vi_scale = mpp_clip(ctx->vi_scale, 16, 320); } break; + case INTRA_RFH_FRAME: { + mpp_data_update_v2(ctx->i_refresh_bit, real_bit); + mpp_data_update_v2(ctx->madi, madi); + ctx->i_refresh_sumbits = mpp_data_sum_v2(ctx->i_refresh_bit); + ctx->i_refresh_scale = 80 * ctx->i_refresh_sumbits / (usr_cfg->refresh_len * ctx->p_sumbits); + ctx->i_refresh_scale = mpp_clip(ctx->i_refresh_scale, 16, 64); + } break; default : { } break; } @@ -426,7 +456,6 @@ MPP_RET bits_model_alloc(RcModelV2Ctx *ctx, EncRcTaskInfo *cfg, RK_S64 total_bit super_bit_thr = usr_cfg->super_cfg.super_i_thd; } } break; - case INTER_P_FRAME: { i_scale = mpp_clip(i_scale, 16, max_i_prop); total_bits = total_bits * 16; @@ -462,11 +491,21 @@ MPP_RET bits_model_alloc(RcModelV2Ctx *ctx, EncRcTaskInfo *cfg, RK_S64 total_bit i_scale = mpp_clip(i_scale, 16, max_i_prop); total_bits = total_bits * 16; } break; + case INTRA_RFH_FRAME: { + i_scale = mpp_clip(i_scale, 16, max_i_prop); + total_bits = total_bits * ctx->i_refresh_scale; + rc_dbg_rc("ctx->i_refresh_scale = %d", ctx->i_refresh_scale); + } break; default: break; } if (gop_len > 1) { - alloc_bits = total_bits / (i_scale + 16 * (gop_len - 1)); + if (!usr_cfg->refresh_len || cfg->frame_type == INTRA_FRAME) + alloc_bits = total_bits / (i_scale + 16 * (gop_len - 1)); + else + alloc_bits = total_bits / + (ctx->i_refresh_scale * usr_cfg->refresh_len + + 16 * (gop_len - usr_cfg->refresh_len)); } else { alloc_bits = total_bits / i_scale; } @@ -1289,6 +1328,9 @@ MPP_RET rc_model_v2_start(void *ctx, EncRcTask *task) if (frm->ref_mode == REF_TO_PREV_INTRA) info->frame_type = INTER_VI_FRAME; + if (frm->is_i_refresh) + info->frame_type = INTRA_RFH_FRAME; + p->next_ratio = 0; if (p->last_frame_type == INTRA_FRAME) { calc_next_i_ratio(p); @@ -1426,7 +1468,7 @@ MPP_RET rc_model_v2_hal_start(void *ctx, EncRcTask *task) RK_S32 qp_scale = p->cur_scale_qp + p->next_ratio; RK_S32 start_qp = 0; - if (frm->is_intra) { + if (frm->is_intra && !frm->is_i_refresh) { RK_S32 i_quality_delta = usr_cfg->i_quality_delta; qp_scale = mpp_clip(qp_scale, (info->quality_min << 6), (info->quality_max << 6));