From c7bedd82e4e8469e9d0163e63677188bb8b6e8cc Mon Sep 17 00:00:00 2001 From: "sayon.chen" Date: Wed, 27 May 2020 09:51:20 +0800 Subject: [PATCH] [rc_v2]: Support smart gop rate control Change-Id: Ie8cb39304af2628f3bed2cd452f164df643300da Signed-off-by: sayon.chen --- inc/mpp_rc_api.h | 7 ++ mpp/codec/inc/mpp_rc.h | 7 +- mpp/codec/mpp_enc_v2.cpp | 15 ++- mpp/codec/rc/rc_model_v2.c | 187 ++++++++++++++++++++++++++++--------- 4 files changed, 165 insertions(+), 51 deletions(-) diff --git a/inc/mpp_rc_api.h b/inc/mpp_rc_api.h index 6dd4b030..89eedf68 100644 --- a/inc/mpp_rc_api.h +++ b/inc/mpp_rc_api.h @@ -55,6 +55,11 @@ typedef enum RcMode_e { RC_MODE_BUTT, } RcMode; +typedef enum GopMode_e { + NORMAL_P, + SMART_P, +} GopMode; + /* * frame rate parameters have great effect on rate control * @@ -102,6 +107,7 @@ typedef struct RcCfg_s { RcFpsCfg fps; + GopMode gop_mode; /* I frame gop len */ RK_S32 igop; /* visual gop len */ @@ -126,6 +132,7 @@ typedef struct RcCfg_s { RK_S32 max_i_quality; RK_S32 min_i_quality; RK_S32 i_quality_delta; + RK_S32 vi_quality_delta; /* layer quality proportion */ RK_S32 layer_quality_delta[4]; diff --git a/mpp/codec/inc/mpp_rc.h b/mpp/codec/inc/mpp_rc.h index 0a78d7c9..c19f892a 100644 --- a/mpp/codec/inc/mpp_rc.h +++ b/mpp/codec/inc/mpp_rc.h @@ -98,9 +98,10 @@ typedef struct MppVirtualBuffer_s { typedef enum ENC_FRAME_TYPE_E { - INTER_P_FRAME = 0, - INTER_B_FRAME = 1, - INTRA_FRAME = 2 + INTER_P_FRAME = 0, + INTER_B_FRAME = 1, + INTRA_FRAME = 2, + INTER_VI_FRAME = 3, } ENC_FRAME_TYPE; /* diff --git a/mpp/codec/mpp_enc_v2.cpp b/mpp/codec/mpp_enc_v2.cpp index 6a3bb357..8f7b32bc 100644 --- a/mpp/codec/mpp_enc_v2.cpp +++ b/mpp/codec/mpp_enc_v2.cpp @@ -596,6 +596,8 @@ static void set_rc_cfg(RcCfg *cfg, MppEncCfgSet *cfg_set) MppEncRcCfg *rc = &cfg_set->rc; MppEncPrepCfg *prep = &cfg_set->prep; MppEncCodecCfg *codec = &cfg_set->codec; + MppEncRefCfgImpl *ref = (MppEncRefCfgImpl *)cfg_set->ref_cfg; + MppEncCpbInfo *info = &ref->cpb_info; cfg->width = prep->width; cfg->height = prep->height; @@ -628,9 +630,6 @@ static void set_rc_cfg(RcCfg *cfg, MppEncCfgSet *cfg_set) cfg->bps_min = rc->bps_min; cfg->stat_times = 3; - cfg->i_quality_delta = 0; - cfg->vgop = 0; - /* quality configure */ switch (codec->coding) { case MPP_VIDEO_CodingAVC : { @@ -669,6 +668,16 @@ static void set_rc_cfg(RcCfg *cfg, MppEncCfgSet *cfg_set) cfg->max_reencode_times = rc->max_reenc_times; + if (info->st_gop) { + cfg->vgop = info->st_gop; + if (cfg->vgop >= rc->fps_out_num / rc->fps_out_denorm && + cfg->vgop < cfg->igop ) { + cfg->gop_mode = SMART_P; + if (!cfg->vi_quality_delta) + cfg->vi_quality_delta = 2; + } + } + mpp_log("mode %s bps [%d:%d:%d] fps %s [%d/%d] -> %s [%d/%d] gop i [%d] v [%d]\n", name_of_rc_mode[cfg->mode], rc->bps_min, rc->bps_target, rc->bps_max, diff --git a/mpp/codec/rc/rc_model_v2.c b/mpp/codec/rc/rc_model_v2.c index 5d1e1384..ebf6c5ec 100644 --- a/mpp/codec/rc/rc_model_v2.c +++ b/mpp/codec/rc/rc_model_v2.c @@ -30,10 +30,10 @@ #define P_WINDOW2_LEN 8 RK_S32 max_i_delta_qp[51] = { - 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, - 0x9, 0x9, 0x8, 0x8, 0x7, 0x7, 0x6, 0x6, 0x5, 0x5, 0x5, 0x4, 0x4, 0x4, - 0x3, 0x3, 0x3, 0x3, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, - 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, + 576, 576, 512, 512, 448, 448, 384, 384, 320, 320, 320, 256, 256, 256, + 192, 192, 192, 192, 192, 128, 128, 128, 128, 128, 128, 64, 64, 64, + 64, 64, 64, 0, 0, 0, 0, 0, 0, }; RK_S32 tab_lnx[64] = { @@ -69,6 +69,9 @@ typedef struct RcModelV2Ctx_t { RK_U32 idr_sumbits; RK_U32 idr_scale; + MppDataV2 *vi_bit; + RK_U32 vi_sumbits; + RK_U32 vi_scale; MppDataV2 *p_bit; RK_U32 p_sumbits; RK_U32 p_scale; @@ -121,6 +124,10 @@ MPP_RET bits_model_deinit(RcModelV2Ctx *ctx) ctx->p_bit = NULL; } + if (ctx->vi_bit != NULL) { + mpp_data_deinit_v2(ctx->vi_bit); + ctx->vi_bit = NULL; + } if (ctx->pre_p_bit != NULL) { mpp_data_deinit_v2(ctx->pre_p_bit); ctx->pre_p_bit = NULL; @@ -130,6 +137,11 @@ MPP_RET bits_model_deinit(RcModelV2Ctx *ctx) } } + if (ctx->madi != NULL) { + mpp_data_deinit_v2(ctx->madi); + ctx->madi = NULL; + } + if (ctx->stat_rate != NULL) { mpp_data_deinit_v2(ctx->stat_rate); ctx->stat_rate = NULL; @@ -144,6 +156,51 @@ MPP_RET bits_model_deinit(RcModelV2Ctx *ctx) return MPP_OK; } +void bits_frm_init(RcModelV2Ctx *ctx) +{ + rc_dbg_func("enter %p\n", ctx); + RK_U32 gop_len = ctx->usr_cfg.igop; + RK_U32 p_bit = 0; + switch (ctx->usr_cfg.gop_mode) { + case NORMAL_P: { + ctx->i_scale = 160; + ctx->p_scale = 16; + if (gop_len <= 1) + p_bit = ctx->gop_total_bits * 16; + else + p_bit = ctx->gop_total_bits * 16 / (ctx->i_scale + ctx->p_scale * (gop_len - 1)); + mpp_data_reset_v2(ctx->p_bit, p_bit); + 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; + } break; + case SMART_P: { + RK_U32 vi_num = 0; + mpp_assert(ctx->usr_cfg.vgop > 1); + ctx->i_scale = 320; + ctx->p_scale = 16; + ctx->vi_scale = 32; + vi_num = gop_len / ctx->usr_cfg.vgop; + if (vi_num > 0) { + vi_num = vi_num - 1; + } + p_bit = ctx->gop_total_bits * 16 / (ctx->i_scale + ctx->vi_scale * vi_num + ctx->p_scale * (gop_len - vi_num)); + mpp_data_reset_v2(ctx->p_bit, p_bit); + 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; + + mpp_data_reset_v2(ctx->vi_bit, p_bit * ctx->vi_scale / 16); + ctx->vi_sumbits = 2 * p_bit * ctx->vi_scale / 16; + } break; + default: + break; + } + rc_dbg_rc("p_sumbits %d i_sumbits %d vi_sumbits %d\n", ctx->p_sumbits, ctx->i_sumbits, ctx->vi_sumbits); + rc_dbg_func("leave %p\n", ctx); +} + MPP_RET bits_model_init(RcModelV2Ctx *ctx) { RK_U32 gop_len = ctx->usr_cfg.igop; @@ -153,7 +210,6 @@ MPP_RET bits_model_init(RcModelV2Ctx *ctx) RK_U32 stat_len; RK_U32 target_bps; RK_U32 total_stat_bits; - RK_U32 p_bit = 0; rc_dbg_func("enter %p\n", ctx); @@ -199,6 +255,11 @@ MPP_RET bits_model_init(RcModelV2Ctx *ctx) return -1; } + mpp_data_init_v2(&ctx->vi_bit, I_WINDOW_LEN); + if (ctx->vi_bit == NULL) { + mpp_err("vi_bit init fail"); + return -1; + } mpp_data_init_v2(&ctx->p_bit, P_WINDOW1_LEN); if (ctx->p_bit == NULL) { mpp_err("p_bit init fail"); @@ -226,9 +287,14 @@ MPP_RET bits_model_init(RcModelV2Ctx *ctx) mpp_err("stat_bits init fail stat_len %d", stat_len); return -1; } + mpp_data_reset_v2(ctx->stat_rate, 0); - ctx->i_scale = 160; - ctx->p_scale = 16; + + mpp_data_init_v2(&ctx->madi, P_WINDOW2_LEN); + if (ctx->madi == NULL) { + mpp_err("madi init fail"); + return -1; + } total_stat_bits = stat_times * target_bps; ctx->target_bps = target_bps; @@ -241,21 +307,7 @@ MPP_RET bits_model_init(RcModelV2Ctx *ctx) ctx->usr_cfg.igop, ctx->gop_total_bits, ctx->bit_per_frame, ctx->usr_cfg.stat_times); - if (gop_len <= 1) - p_bit = ctx->gop_total_bits * 16; - else - p_bit = ctx->gop_total_bits * 16 / (ctx->i_scale + 16 * (gop_len - 1)); - - mpp_data_reset_v2(ctx->p_bit, p_bit); - - 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; - - rc_dbg_rc("p_sumbits %d i_sumbits %d\n", ctx->p_sumbits, ctx->i_sumbits); - + bits_frm_init(ctx); rc_dbg_func("leave %p\n", ctx); return MPP_OK; } @@ -296,6 +348,12 @@ MPP_RET bits_model_update(RcModelV2Ctx *ctx, RK_S32 real_bit, RK_U32 madi) ctx->p_scale = 16; } break; + case INTER_VI_FRAME: { + mpp_data_update_v2(ctx->vi_bit, real_bit); + ctx->vi_sumbits = mpp_data_sum_v2(ctx->vi_bit); + ctx->vi_scale = 80 * ctx->vi_sumbits / (2 * ctx->p_sumbits); + } break; + default: break; } @@ -311,27 +369,61 @@ MPP_RET bits_model_alloc(RcModelV2Ctx *ctx, EncRcTaskInfo *cfg) RK_S64 total_bits = ctx->gop_total_bits; RK_S32 ins_bps = mpp_data_sum_v2(ctx->stat_bits) / ctx->usr_cfg.stat_times; RK_S32 i_scale = ctx->i_scale; + RK_S32 vi_scale = ctx->vi_scale; + RK_S32 alloc_bits = 0; rc_dbg_func("enter %p\n", ctx); rc_dbg_rc("frame_type %d max_i_prop %d i_scale %d total_bits %lld\n", ctx->frame_type, max_i_prop, i_scale, total_bits); - if (ctx->frame_type == INTRA_FRAME) { - i_scale = mpp_clip(i_scale, 16, max_i_prop); - total_bits = total_bits * i_scale; - } else { - i_scale = mpp_clip(i_scale, 16, 16000); - total_bits = total_bits * 16; - } + if (ctx->usr_cfg.gop_mode == SMART_P) { + RK_U32 vi_num = 0; + mpp_assert(ctx->usr_cfg.vgop > 1); + vi_num = gop_len / ctx->usr_cfg.vgop; + if (vi_num > 0) { + vi_num = vi_num - 1; + } + switch (ctx->frame_type) { + case INTRA_FRAME: { + i_scale = mpp_clip(i_scale, 16, max_i_prop); + total_bits = total_bits * i_scale; + } break; + case INTER_P_FRAME: { + i_scale = mpp_clip(i_scale, 16, 16000); + total_bits = total_bits * 16; + } break; + case INTER_VI_FRAME: { + i_scale = mpp_clip(i_scale, 16, 16000); + total_bits = total_bits * vi_scale; + } break; + default: + break; + } + alloc_bits = total_bits / (i_scale + 16 * (gop_len - vi_num) + vi_num * vi_scale); + } else { + switch (ctx->frame_type) { + case INTRA_FRAME: { + i_scale = mpp_clip(i_scale, 16, max_i_prop); + total_bits = total_bits * i_scale; + } break; + + case INTER_P_FRAME: { + i_scale = mpp_clip(i_scale, 16, 16000); + total_bits = total_bits * 16; + } break; + default: + break; + } + if (gop_len > 1) { + alloc_bits = total_bits / (i_scale + 16 * (gop_len - 1)); + } else { + alloc_bits = total_bits / i_scale; + } + } rc_dbg_rc("i_scale %d, total_bits %lld", i_scale, total_bits); - if (gop_len > 1) { - cfg->bit_target = total_bits / (i_scale + 16 * (gop_len - 1)); - } else { - cfg->bit_target = total_bits / i_scale; - } + cfg->bit_target = alloc_bits; ctx->ins_bps = ins_bps; - rc_dbg_func("leave %p\n", ctx); return MPP_OK; } @@ -352,15 +444,12 @@ MPP_RET calc_next_i_ratio(RcModelV2Ctx *ctx) if (ctx->pre_real_bits > bits_alloc || ctx->next_i_ratio) { RK_S32 ratio = ((ctx->pre_real_bits - bits_alloc) << 8) / bits_alloc; - if (ratio >= 256) - ratio = 256; - if (ratio < -256) - ratio = ctx->next_i_ratio - 256; - else - ratio = ctx->next_i_ratio + ratio; + + ratio = mpp_clip(ratio, -256, 256); + ratio = ctx->next_i_ratio + ratio; if (ratio >= 0) { - if (ratio > (max_i_delta_qp[pre_qp] << 6)) - ratio = (max_i_delta_qp[pre_qp] << 6); + if (ratio > max_i_delta_qp[pre_qp]) + ratio = max_i_delta_qp[pre_qp]; } else { ratio = 0; } @@ -470,7 +559,7 @@ MPP_RET reenc_calc_cbr_ratio(RcModelV2Ctx *ctx, EncRcTaskInfo *cfg) if (target_bit > real_bit) bit_diff_ratio = 32 * (real_bit - target_bit) / target_bit; else - bit_diff_ratio = 32 * (real_bit - target_bit) / real_bit; + bit_diff_ratio = 48 * (real_bit - target_bit) / real_bit; idx1 = ins_bps / (target_bps >> 5); idx2 = last_ins_bps / (target_bps >> 5); @@ -712,6 +801,10 @@ MPP_RET rc_model_v2_start(void *ctx, EncRcTask *task) p->frame_type = (frm->is_intra) ? (INTRA_FRAME) : (INTER_P_FRAME); + if (frm->ref_mode == REF_TO_PREV_INTRA) { + p->frame_type = INTER_VI_FRAME; + } + /* bitrate allocation */ bits_model_alloc(p, info); @@ -867,6 +960,7 @@ MPP_RET rc_model_v2_hal_start(void *ctx, EncRcTask *task) dealt_qp = p->usr_cfg.i_quality_delta; } } + if (p->usr_cfg.i_quality_delta) { p->start_qp -= dealt_qp; } @@ -874,9 +968,12 @@ MPP_RET rc_model_v2_hal_start(void *ctx, EncRcTask *task) qp_scale = mpp_clip(qp_scale, (info->quality_min << 6), (info->quality_max << 6)); p->cur_scale_qp = qp_scale; p->start_qp = qp_scale >> 6; + if (frm->ref_mode == REF_TO_PREV_INTRA && p->usr_cfg.vi_quality_delta) { + p->start_qp -= p->usr_cfg.vi_quality_delta; + } } + rc_dbg_rc("i_quality_delta %d, vi_quality_delta %d", dealt_qp, p->usr_cfg.vi_quality_delta); } - p->start_qp = mpp_clip( p->start_qp, info->quality_min, info->quality_max); info->quality_target = p->start_qp;