diff --git a/inc/mpp_rc_api.h b/inc/mpp_rc_api.h index 71e845d1..c7368af5 100644 --- a/inc/mpp_rc_api.h +++ b/inc/mpp_rc_api.h @@ -153,6 +153,10 @@ typedef struct RcCfg_s { RK_S32 min_i_quality; RK_S32 i_quality_delta; RK_S32 vi_quality_delta; + RK_S32 fqp_min_i; + RK_S32 fqp_min_p; + RK_S32 fqp_max_i; + RK_S32 fqp_max_p; /* layer quality proportion */ RK_S32 layer_quality_delta[4]; @@ -180,6 +184,7 @@ typedef struct RcCfg_s { RcDebreathCfg debreath_cfg; RcHierQPCfg hier_qp_cfg; RK_U32 refresh_len; + RK_S32 scene_mode; } RcCfg; /* diff --git a/inc/rk_venc_cmd.h b/inc/rk_venc_cmd.h index a133730d..9f5fe2ff 100644 --- a/inc/rk_venc_cmd.h +++ b/inc/rk_venc_cmd.h @@ -238,6 +238,7 @@ typedef enum MppEncRcCfgChange_e { MPP_ENC_RC_CFG_CHANGE_ST_TIME = (1 << 26), MPP_ENC_RC_CFG_CHANGE_REFRESH = (1 << 27), MPP_ENC_RC_CFG_CHANGE_GOP_REF_CFG = (1 << 28), + MPP_ENC_RC_CFG_CHANGE_FQP = (1 << 29), MPP_ENC_RC_CFG_CHANGE_ALL = (0xFFFFFFFF), } MppEncRcCfgChange; @@ -405,6 +406,10 @@ typedef struct MppEncRcCfg_t { RK_S32 qp_max_step; /* delta qp between each two P frame */ RK_S32 qp_delta_ip; /* delta qp between I and P */ RK_S32 qp_delta_vi; /* delta qp between vi and P */ + RK_S32 fqp_min_i; + RK_S32 fqp_min_p; + RK_S32 fqp_max_i; + RK_S32 fqp_max_p; RK_S32 hier_qp_en; RK_S32 hier_qp_delta[4]; diff --git a/mpp/base/mpp_enc_cfg.cpp b/mpp/base/mpp_enc_cfg.cpp index 0cb99cc3..c5ad1b39 100644 --- a/mpp/base/mpp_enc_cfg.cpp +++ b/mpp/base/mpp_enc_cfg.cpp @@ -166,6 +166,10 @@ public: 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) \ + ENTRY(rc, fqp_min_i, S32, RK_S32, MPP_ENC_RC_CFG_CHANGE_FQP, rc, fqp_min_i) \ + ENTRY(rc, fqp_min_p, S32, RK_S32, MPP_ENC_RC_CFG_CHANGE_FQP, rc, fqp_min_p) \ + ENTRY(rc, fqp_max_i, S32, RK_S32, MPP_ENC_RC_CFG_CHANGE_FQP, rc, fqp_max_i) \ + ENTRY(rc, fqp_max_p, S32, RK_S32, MPP_ENC_RC_CFG_CHANGE_FQP, rc, fqp_max_p) \ /* 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/codec/enc/h264/h264e_api_v2.c b/mpp/codec/enc/h264/h264e_api_v2.c index 78e06254..4fd0ccba 100644 --- a/mpp/codec/enc/h264/h264e_api_v2.c +++ b/mpp/codec/enc/h264/h264e_api_v2.c @@ -180,6 +180,10 @@ static void init_h264e_cfg_set(MppEncCfgSet *cfg, MppClientType type) rc_cfg->qp_max_i = 0; rc_cfg->qp_min_i = 0; rc_cfg->qp_delta_ip = 2; + rc_cfg->fqp_min_i = 10; + rc_cfg->fqp_min_p = 10; + rc_cfg->fqp_max_i = 51; + rc_cfg->fqp_max_p = 51; } static void h264e_add_syntax(H264eCtx *ctx, H264eSyntaxType type, void *p) diff --git a/mpp/codec/enc/h265/h265e_api.c b/mpp/codec/enc/h265/h265e_api.c index cb5a1c27..5aeaff32 100644 --- a/mpp/codec/enc/h265/h265e_api.c +++ b/mpp/codec/enc/h265/h265e_api.c @@ -110,6 +110,7 @@ static MPP_RET h265e_init(void *ctx, EncImplCfg *ctrlCfg) h265->merge_cfg.max_mrg_cnd = 2; h265->merge_cfg.merge_left_flag = 1; h265->merge_cfg.merge_up_flag = 1; + p->cfg->tune.scene_mode = MPP_ENC_SCENE_MODE_DEFAULT; /* * default prep: @@ -163,6 +164,10 @@ static MPP_RET h265e_init(void *ctx, EncImplCfg *ctrlCfg) rc_cfg->qp_min_i = 15; rc_cfg->qp_delta_ip = 4; rc_cfg->qp_delta_vi = 2; + rc_cfg->fqp_min_i = 10; + rc_cfg->fqp_min_p = 10; + rc_cfg->fqp_max_i = 51; + rc_cfg->fqp_max_p = 51; INIT_LIST_HEAD(&p->rc_list); diff --git a/mpp/codec/mpp_enc_impl.cpp b/mpp/codec/mpp_enc_impl.cpp index f4552703..6d90c7a8 100644 --- a/mpp/codec/mpp_enc_impl.cpp +++ b/mpp/codec/mpp_enc_impl.cpp @@ -653,6 +653,13 @@ MPP_RET mpp_enc_proc_rc_cfg(MppCodingType coding, MppEncRcCfg *dst, MppEncRcCfg if (change & MPP_ENC_RC_CFG_CHANGE_QP_VI) dst->qp_delta_vi = src->qp_delta_vi; + if (change & MPP_ENC_RC_CFG_CHANGE_FQP) { + dst->fqp_min_i = src->fqp_min_i; + dst->fqp_min_p = src->fqp_min_p; + dst->fqp_max_i = src->fqp_max_i; + dst->fqp_max_p = src->fqp_max_p; + } + if (change & MPP_ENC_RC_CFG_CHANGE_HIER_QP) { dst->hier_qp_en = src->hier_qp_en; memcpy(dst->hier_qp_delta, src->hier_qp_delta, sizeof(src->hier_qp_delta)); @@ -1217,10 +1224,15 @@ static void set_rc_cfg(RcCfg *cfg, MppEncCfgSet *cfg_set) cfg->max_i_bit_prop = rc->max_i_prop; cfg->min_i_bit_prop = rc->min_i_prop; cfg->init_ip_ratio = rc->init_ip_ratio; + cfg->fqp_min_p = rc->fqp_min_p; + cfg->fqp_min_i = rc->fqp_min_i; + cfg->fqp_max_p = rc->fqp_max_p; + cfg->fqp_max_i = rc->fqp_max_i; cfg->bps_target = rc->bps_target; cfg->bps_max = rc->bps_max; cfg->bps_min = rc->bps_min; + cfg->scene_mode = cfg_set->tune.scene_mode; cfg->hier_qp_cfg.hier_qp_en = rc->hier_qp_en; memcpy(cfg->hier_qp_cfg.hier_frame_num, rc->hier_frame_num, sizeof(rc->hier_frame_num)); diff --git a/mpp/codec/rc/rc_model_v2.c b/mpp/codec/rc/rc_model_v2.c index 2bf2d352..04cf6ea4 100644 --- a/mpp/codec/rc/rc_model_v2.c +++ b/mpp/codec/rc/rc_model_v2.c @@ -1524,7 +1524,10 @@ MPP_RET rc_model_v2_hal_start(void *ctx, EncRcTask *task) } } - p->start_qp = mpp_clip(p->start_qp, info->quality_min, info->quality_max); + if (frm->is_intra) + p->start_qp = mpp_clip(p->start_qp, usr_cfg->fqp_min_i, usr_cfg->fqp_max_i); + else + p->start_qp = mpp_clip(p->start_qp, usr_cfg->fqp_min_p, usr_cfg->fqp_max_p); info->quality_target = p->start_qp; rc_dbg_rc("bitrate [%d : %d : %d] -> [%d : %d : %d]\n", diff --git a/test/mpi_enc_test.c b/test/mpi_enc_test.c index a3a2f5ea..faadaaa7 100644 --- a/test/mpi_enc_test.c +++ b/test/mpi_enc_test.c @@ -33,6 +33,7 @@ #include "mpi_enc_utils.h" #include "camera_source.h" #include "mpp_enc_roi_utils.h" +#include "mpp_rc_api.h" typedef struct { // base flow context @@ -116,6 +117,7 @@ typedef struct { RK_S32 gop_mode; RK_S32 gop_len; RK_S32 vi_len; + RK_S32 scene_mode; RK_S64 first_frm; RK_S64 first_pkt; @@ -175,6 +177,7 @@ MPP_RET test_ctx_init(MpiEncMultiCtxInfo *info) p->fps_out_flex = cmd->fps_out_flex; p->fps_out_den = cmd->fps_out_den; p->fps_out_num = cmd->fps_out_num; + p->scene_mode = cmd->scene_mode; p->mdinfo_size = (MPP_VIDEO_CodingHEVC == cmd->type) ? (MPP_ALIGN(p->hor_stride, 32) >> 5) * (MPP_ALIGN(p->ver_stride, 32) >> 5) * 16 : @@ -311,6 +314,8 @@ MPP_RET test_mpp_enc_cfg_setup(MpiEncMultiCtxInfo *info) if (!p->bps) p->bps = p->width * p->height / 8 * (p->fps_out_num / p->fps_out_den); + mpp_enc_cfg_set_s32(cfg, "tune:scene_mode", p->scene_mode); + mpp_enc_cfg_set_s32(cfg, "prep:width", p->width); mpp_enc_cfg_set_s32(cfg, "prep:height", p->height); mpp_enc_cfg_set_s32(cfg, "prep:hor_stride", p->hor_stride); @@ -370,6 +375,10 @@ MPP_RET test_mpp_enc_cfg_setup(MpiEncMultiCtxInfo *info) mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", fix_qp); mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", fix_qp); mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 0); + mpp_enc_cfg_set_s32(cfg, "rc:fqp_min_i", fix_qp); + mpp_enc_cfg_set_s32(cfg, "rc:fqp_max_i", fix_qp); + mpp_enc_cfg_set_s32(cfg, "rc:fqp_min_p", fix_qp); + mpp_enc_cfg_set_s32(cfg, "rc:fqp_max_p", fix_qp); } break; case MPP_ENC_RC_MODE_CBR : case MPP_ENC_RC_MODE_VBR : @@ -380,6 +389,10 @@ MPP_RET test_mpp_enc_cfg_setup(MpiEncMultiCtxInfo *info) mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", cmd->qp_max_i ? cmd->qp_max_i : 51); mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", cmd->qp_min_i ? cmd->qp_min_i : 10); mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 2); + mpp_enc_cfg_set_s32(cfg, "rc:fqp_min_i", cmd->fqp_min_i ? cmd->fqp_min_i : 10); + mpp_enc_cfg_set_s32(cfg, "rc:fqp_max_i", cmd->fqp_max_i ? cmd->fqp_max_i : 51); + mpp_enc_cfg_set_s32(cfg, "rc:fqp_min_p", cmd->fqp_min_p ? cmd->fqp_min_p : 10); + mpp_enc_cfg_set_s32(cfg, "rc:fqp_max_p", cmd->fqp_max_p ? cmd->fqp_max_p : 51); } break; default : { mpp_err_f("unsupport encoder rc mode %d\n", p->rc_mode); diff --git a/utils/mpi_enc_utils.c b/utils/mpi_enc_utils.c index 98ed14f7..548b677e 100644 --- a/utils/mpi_enc_utils.c +++ b/utils/mpi_enc_utils.c @@ -375,6 +375,22 @@ RK_S32 mpi_enc_opt_qc(void *ctx, const char *next) return 0; } +RK_S32 mpi_enc_opt_fqc(void *ctx, const char *next) +{ + MpiEncTestArgs *cmd = (MpiEncTestArgs *)ctx; + RK_S32 cnt = 0; + + if (next) { + cnt = sscanf(next, "%d:%d:%d:%d", &cmd->fqp_min_i, &cmd->fqp_max_i, + &cmd->fqp_min_p, &cmd->fqp_max_p); + if (cnt) + return 1; + } + + mpp_err("invalid frame quality control usage -fqc min_i:max_i:min_p:max_p\n"); + return 0; +} + RK_S32 mpi_enc_opt_s(void *ctx, const char *next) { MpiEncTestArgs *cmd = (MpiEncTestArgs *)ctx; @@ -457,6 +473,19 @@ RK_S32 mpi_enc_opt_slt(void *ctx, const char *next) return 0; } +RK_S32 mpi_enc_opt_sm(void *ctx, const char *next) +{ + MpiEncTestArgs *cmd = (MpiEncTestArgs *)ctx; + + if (next) { + cmd->scene_mode = atoi(next); + return 1; + } + + mpp_err("invalid scene mode\n"); + return 0; +} + RK_S32 mpi_enc_opt_help(void *ctx, const char *next) { (void)ctx; @@ -480,11 +509,13 @@ static MppOptInfo enc_opts[] = { {"bps", "bps target:min:max", "set tareget:min:max bps", mpi_enc_opt_bps}, {"fps", "in/output fps", "set input and output frame rate", mpi_enc_opt_fps}, {"qc", "quality control", "set qp_init:min:max:min_i:max_i", mpi_enc_opt_qc}, + {"fqc", "frm quality control", "set fqp min_i:max_i:min_p:max_p", mpi_enc_opt_fqc}, {"s", "instance_nb", "number of instances", mpi_enc_opt_s}, {"v", "trace option", "q - quiet f - show fps", mpi_enc_opt_v}, {"l", "loop count", "loop encoding times for each frame", mpi_enc_opt_l}, {"ini", "ini file", "encoder extra ini config file", mpi_enc_opt_ini}, {"slt", "slt file", "slt verify data file", mpi_enc_opt_slt}, + {"sm", "scene mode", "scene_mode, 0:default 1:ipc", mpi_enc_opt_sm}, }; static RK_U32 enc_opt_cnt = MPP_ARRAY_ELEMS(enc_opts); diff --git a/utils/mpi_enc_utils.h b/utils/mpi_enc_utils.h index 50c59208..baa133b2 100644 --- a/utils/mpi_enc_utils.h +++ b/utils/mpi_enc_utils.h @@ -63,11 +63,20 @@ typedef struct MpiEncTestArgs_t { RK_S32 qp_min_i; RK_S32 qp_max_i; + /* -fqc */ + RK_S32 fqp_min_i; + RK_S32 fqp_min_p; + RK_S32 fqp_max_i; + RK_S32 fqp_max_p; + /* -g gop mode */ RK_S32 gop_mode; RK_S32 gop_len; RK_S32 vi_len; + /* -sm scene_mode */ + RK_S32 scene_mode; + /* -v q runtime log disable flag */ RK_U32 quiet; /* -v f runtime fps log flag */