/* * Copyright 2016 Rockchip Electronics Co. LTD * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define MODULE_TAG "rc_model_v2_smt" #include #include #include "mpp_env.h" #include "mpp_mem.h" #include "mpp_common.h" #include "rc_base.h" #include "rc_debug.h" #include "rc_model_v2_smt.h" #include "mpp_rc.h" #define MAD_THDI 20 #define LIMIT_QP_MORE_MOVE 30 #define ENOUGH_QP 33 #define LOW_QP 34 #define LOW_QP_level0 34 #define LOW_QP_level1 34 #define LOW_LOW_QP 38 #define LOW_PRE_DIFF_BIT_USE -20000 extern RK_S32 tab_lnx[64]; typedef struct RcModelV2SmtCtx_t { RcCfg usr_cfg; EncRcTaskInfo hal_cfg; RK_U32 frame_type; RK_U32 last_frame_type; RK_S64 gop_total_bits; RK_U32 bit_per_frame; MppDataV2 *i_bit; RK_U32 i_sumbits; RK_U32 i_scale; MppDataV2 *idr_bit; RK_U32 idr_sumbits; RK_U32 idr_scale; MppDataV2 *p_bit; RK_U32 p_sumbits; RK_U32 p_scale; MppDataV2 *pre_p_bit; RK_S32 target_bps; RK_S32 pre_target_bits; RK_S32 pre_real_bits; RK_S32 frm_bits_thr; RK_S32 ins_bps; RK_S32 last_inst_bps; RK_U32 water_level_thr; MppDataV2 *stat_bits; MppDataV2 *stat_rate; RK_S32 stat_watl_thrd; RK_S32 stat_watl; RK_S32 stat_last_watl; RK_S32 next_i_ratio; // scale 64 RK_S32 next_ratio; // scale 64 RK_S32 pre_i_qp; RK_S32 pre_p_qp; RK_S32 scale_qp; // scale 64 MppDataV2 *means_qp; RK_S64 frm_num; RK_S32 reenc_cnt; RK_S32 codec_type; // 264: 0 ; 265: 1 RK_S32 qp_min; RK_S32 qp_max; RK_S32 qp_step; MppEncGopMode gop_mode; RK_S32 window_len; RK_S32 intra_to_inter_rate; RK_S32 acc_intra_bits_in_fps; RK_S32 acc_inter_bits_in_fps; RK_S32 acc_total_bits; RK_S64 acc_total_count; RK_S64 acc_intra_count; RK_S64 acc_inter_count; RK_S32 last_fps_bits; RK_S32 pre_gop_left_bit; MppData *qp_p; MppData *sse_p; MppData *intra; MppData *inter; MppData *gop_bits; MppData *intra_percent; MppPIDCtx pid_fps; RK_S32 bps_target_low_rate; RK_S32 bps_target_high_rate; RK_S32 bits_target_low_rate; RK_S32 bits_target_high_rate; RK_S32 bits_per_pic_low_rate; RK_S32 bits_per_intra_low_rate; RK_S32 bits_per_inter_low_rate; RK_S32 bits_per_pic_high_rate; RK_S32 bits_per_intra_high_rate; RK_S32 bits_per_inter_high_rate; RK_S32 pre_diff_bit_low_rate; RK_S32 pre_diff_bit_high_rate; RK_S32 gop_min; MppPIDCtx pid_intra_low_rate; MppPIDCtx pid_intra_high_rate; MppPIDCtx pid_inter_low_rate; MppPIDCtx pid_inter_high_rate; RK_S32 bits_one_gop[1000]; RK_S32 bits_one_gop_use_flag; RK_S32 bits_one_gop_sum; RK_S32 delta_bits_per_frame; RK_S32 frame_cnt_in_gop; RK_S32 bits_target_use; RK_S32 qp_out; RK_S32 qp_prev_out; RK_S32 qp_preavg; RK_S32 intra_prerealbit; RK_S32 intra_preqp; RK_S32 intra_presse; RK_S32 intra_premadi; RK_U32 st_madi; } RcModelV2SmtCtx; typedef struct InfoList_t { RK_U16 flag; // 1 - valid 0 - unvaild RK_U16 up_left[2]; // 0 - y idx 1 - x idx RK_U16 down_right[2]; // 0 - y idx 1 - x idx } InfoList; typedef struct RoiInfo_t { RK_U16 flag; // 1 - valid 0 - unvaild RK_U16 is_move; // 1 - is motion 0 - is motionless RK_U16 up_left[2]; // 0 - y idx 1 - x idx RK_U16 down_right[2]; // 0 - y idx 1 - x idx } RoiInfo; static RK_U32 cal_mv_info(InfoList* info) { RK_S32 k, i, j; RK_S32 mb_sta_x, mb_sta_y; RK_S32 mb_end_x, mb_end_y; RK_U32 move_num = 0; if (info == NULL) return 0; for (k = 0; k < 4096; k++) { if (info[k].flag == 0) break; mb_sta_y = info[k].up_left[0] / 16; mb_sta_x = info[k].up_left[1] / 16; mb_end_y = info[k].down_right[0] / 16; mb_end_x = info[k].down_right[1] / 16; for (j = mb_sta_y; j <= mb_end_y; j++) { for (i = mb_sta_x; i <= mb_end_x; i++) { move_num++; } } } return move_num; } MPP_RET bits_model_smt_deinit(RcModelV2SmtCtx *ctx) { rc_dbg_func("enter %p\n", ctx); if (ctx->qp_p) { mpp_data_deinit(ctx->qp_p); ctx->qp_p = NULL; } if (ctx->sse_p) { mpp_data_deinit(ctx->sse_p); ctx->sse_p = NULL; } if (ctx->intra) { mpp_data_deinit(ctx->intra); ctx->intra = NULL; } if (ctx->inter) { mpp_data_deinit(ctx->inter); ctx->inter = NULL; } if (ctx->gop_bits) { mpp_data_deinit(ctx->gop_bits); ctx->gop_bits = NULL; } if (ctx->intra_percent) { mpp_data_deinit(ctx->intra_percent); ctx->intra_percent = NULL; } if (ctx->i_bit != NULL) { mpp_data_deinit_v2(ctx->i_bit); ctx->i_bit = NULL; } if (ctx->p_bit != NULL) { mpp_data_deinit_v2(ctx->p_bit); ctx->p_bit = NULL; } if (ctx->pre_p_bit != NULL) { mpp_data_deinit_v2(ctx->pre_p_bit); ctx->pre_p_bit = NULL; } if (ctx->stat_rate != NULL) { mpp_data_deinit_v2(ctx->stat_rate); ctx->stat_rate = NULL; } if (ctx->stat_bits != NULL) { mpp_data_deinit_v2(ctx->stat_bits); ctx->stat_bits = NULL; } rc_dbg_func("leave %p\n", ctx); return MPP_OK; } MPP_RET bits_model_smt_init(RcModelV2SmtCtx *ctx) { RK_S32 gop_len = ctx->usr_cfg.igop; RcFpsCfg *fps = &ctx->usr_cfg.fps; rc_dbg_func("enter %p\n", ctx); ctx->frm_num = 0; // smt ctx->frame_cnt_in_gop = 0; ctx->bits_one_gop_use_flag = 0; ctx->gop_min = gop_len; ctx->qp_min = 18; ctx->qp_max = 51; ctx->qp_step = 4; if (gop_len < fps->fps_out_num) ctx->window_len = fps->fps_out_num; else ctx->window_len = gop_len; if (ctx->window_len < 10) ctx->window_len = 10; if (ctx->window_len > fps->fps_out_num) ctx->window_len = fps->fps_out_num; if (ctx->intra) mpp_data_deinit(ctx->intra); mpp_data_init(&ctx->intra, gop_len); if (ctx->inter) mpp_data_deinit(ctx->inter); mpp_data_init(&ctx->inter, fps->fps_out_num); /* need test */ if (ctx->gop_bits) mpp_data_deinit(ctx->gop_bits); mpp_data_init(&ctx->gop_bits, gop_len); if (ctx->intra_percent) mpp_data_deinit(ctx->intra_percent); mpp_data_init(&ctx->intra_percent, gop_len); mpp_pid_reset(&ctx->pid_fps); mpp_pid_reset(&ctx->pid_intra_low_rate); mpp_pid_reset(&ctx->pid_intra_high_rate); mpp_pid_reset(&ctx->pid_inter_low_rate); mpp_pid_reset(&ctx->pid_inter_high_rate); mpp_pid_set_param(&ctx->pid_fps, 4, 6, 0, 100, ctx->window_len); mpp_pid_set_param(&ctx->pid_intra_low_rate, 4, 6, 0, 100, ctx->window_len); mpp_pid_set_param(&ctx->pid_intra_high_rate, 4, 6, 0, 100, ctx->window_len); mpp_pid_set_param(&ctx->pid_inter_low_rate, 4, 6, 0, 100, ctx->window_len); mpp_pid_set_param(&ctx->pid_inter_high_rate, 4, 6, 0, 100, ctx->window_len); ctx->bps_target_low_rate = ctx->usr_cfg.bps_min; ctx->bps_target_high_rate = ctx->usr_cfg.bps_max; ctx->bits_per_pic_low_rate = axb_div_c(ctx->bps_target_low_rate, fps->fps_out_denorm, fps->fps_out_num); ctx->bits_per_pic_high_rate = axb_div_c(ctx->bps_target_high_rate, fps->fps_out_denorm, fps->fps_out_num); ctx->acc_intra_bits_in_fps = 0; ctx->acc_inter_bits_in_fps = 0; ctx->acc_total_bits = 0; ctx->acc_intra_count = 0; ctx->acc_inter_count = 0; ctx->last_fps_bits = 0; RK_S32 avg_low_rate = ctx->bits_per_pic_low_rate; RK_S32 avg_high_rate = ctx->bits_per_pic_high_rate; if (gop_len == 0) { ctx->gop_mode = MPP_GOP_ALL_INTER; ctx->bits_per_inter_low_rate = avg_low_rate; ctx->bits_per_intra_low_rate = avg_low_rate * 10; ctx->bits_per_inter_high_rate = avg_high_rate; ctx->bits_per_intra_high_rate = avg_high_rate * 10; } else if (gop_len == 1) { ctx->gop_mode = MPP_GOP_ALL_INTRA; ctx->bits_per_inter_low_rate = 0; ctx->bits_per_intra_low_rate = avg_low_rate; ctx->bits_per_inter_high_rate = 0; ctx->bits_per_intra_high_rate = avg_high_rate; ctx->intra_to_inter_rate = 0; } else if (gop_len < ctx->window_len) { ctx->gop_mode = MPP_GOP_SMALL; ctx->intra_to_inter_rate = gop_len + 1; ctx->bits_per_inter_low_rate = avg_low_rate / 2; ctx->bits_per_intra_low_rate = ctx->bits_per_inter_low_rate * ctx->intra_to_inter_rate; ctx->bits_per_inter_high_rate = avg_high_rate / 2; ctx->bits_per_intra_high_rate = ctx->bits_per_inter_high_rate * ctx->intra_to_inter_rate; } else { ctx->gop_mode = MPP_GOP_LARGE; ctx->intra_to_inter_rate = gop_len + 1; ctx->bits_per_intra_low_rate = ctx->bits_per_pic_low_rate * (2.0 * log((float)gop_len)); ctx->bits_per_inter_low_rate = ctx->bits_per_pic_low_rate; ctx->bits_per_inter_low_rate -= ctx->bits_per_intra_low_rate / (fps->fps_out_num - 1); ctx->bits_per_intra_high_rate = ctx->bits_per_pic_high_rate * (2.0 * log((float)gop_len)); ctx->bits_per_inter_high_rate = ctx->bits_per_pic_high_rate; ctx->bits_per_inter_high_rate -= ctx->bits_per_intra_high_rate / (fps->fps_out_num - 1); } rc_dbg_func("leave %p\n", ctx); return MPP_OK; } MPP_RET bits_model_update_smt(RcModelV2SmtCtx *ctx, RK_S32 real_bit) { rc_dbg_func("enter %p\n", ctx); // smt RK_S32 gop_len = ctx->usr_cfg.igop; RcFpsCfg *fps = &ctx->usr_cfg.fps; ctx->pre_diff_bit_low_rate = ctx->bits_target_low_rate - real_bit; ctx->pre_diff_bit_high_rate = ctx->bits_target_high_rate - real_bit; ctx->bits_one_gop[ctx->frame_cnt_in_gop % 1000] = real_bit; ctx->frame_cnt_in_gop++; if (ctx->frame_cnt_in_gop == gop_len) { ctx->frame_cnt_in_gop = 0; ctx->bits_one_gop_use_flag = 1; ctx->bits_one_gop_sum = 0; RK_S32 i = 0; RK_S32 gop_len_save = gop_len; if (gop_len > 1000) { gop_len_save = 1000; } for (i = 0; i < gop_len_save; i++) ctx->bits_one_gop_sum += ctx->bits_one_gop[i]; ctx->delta_bits_per_frame = ctx->bps_target_high_rate / (fps->fps_out_num) - ctx->bits_one_gop_sum / gop_len_save; } if (ctx->frame_type == INTRA_FRAME) { ctx->acc_intra_count++; ctx->acc_intra_bits_in_fps += real_bit; mpp_data_update(ctx->intra, real_bit); mpp_data_update(ctx->gop_bits, real_bit); mpp_pid_update(&ctx->pid_intra_low_rate, real_bit - ctx->bits_target_low_rate); mpp_pid_update(&ctx->pid_intra_high_rate, real_bit - ctx->bits_target_high_rate); } else { ctx->acc_inter_count++; ctx->acc_inter_bits_in_fps += real_bit; mpp_data_update(ctx->inter, real_bit); mpp_data_update(ctx->gop_bits, real_bit); mpp_pid_update(&ctx->pid_inter_low_rate, real_bit - ctx->bits_target_low_rate); mpp_pid_update(&ctx->pid_inter_high_rate, real_bit - ctx->bits_target_high_rate); } ctx->acc_total_count++; ctx->last_fps_bits += real_bit; /* new fps start */ if ((ctx->acc_intra_count + ctx->acc_inter_count) % fps->fps_out_num == 0) { RK_S32 bps_target_temp = (ctx->bps_target_low_rate + ctx->bps_target_high_rate) / 2; if (bps_target_temp > (ctx->last_fps_bits * 2 / 3)) mpp_pid_update(&ctx->pid_fps, bps_target_temp - ctx->last_fps_bits); else { bps_target_temp = ctx->bps_target_low_rate * 0.4 + ctx->bps_target_high_rate * 0.6; mpp_pid_update(&ctx->pid_fps, bps_target_temp - ctx->last_fps_bits); } ctx->acc_intra_bits_in_fps = 0; ctx->acc_inter_bits_in_fps = 0; ctx->last_fps_bits = 0; } /* new frame start */ ctx->qp_prev_out = ctx->qp_out; rc_dbg_func("leave %p\n", ctx); return MPP_OK; } MPP_RET reenc_calc_cbr_ratio_smt(RcModelV2SmtCtx *ctx, EncRcTaskInfo *cfg) { RK_S32 stat_time = ctx->usr_cfg.stats_time; RK_S32 last_ins_bps = mpp_data_sum_v2(ctx->stat_bits) / stat_time; RK_S32 ins_bps = (last_ins_bps * stat_time - mpp_data_get_pre_val_v2(ctx->stat_bits, -1) + cfg->bit_real) / stat_time; RK_S32 real_bit = cfg->bit_real; RK_S32 target_bit = cfg->bit_target; RK_S32 target_bps = ctx->target_bps; RK_S32 water_level = 0; RK_S32 idx1, idx2; RK_S32 i_flag = 0; RK_S32 bit_diff_ratio, ins_ratio, bps_ratio, wl_ratio; rc_dbg_func("enter %p\n", ctx); i_flag = (ctx->frame_type == INTRA_FRAME); if (real_bit + ctx->stat_watl > ctx->stat_watl_thrd) water_level = ctx->stat_watl_thrd - ctx->bit_per_frame; else water_level = real_bit + ctx->stat_watl_thrd - ctx->bit_per_frame; if (water_level < ctx->stat_last_watl) { water_level = ctx->stat_last_watl; } 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; idx1 = ins_bps / (target_bps >> 5); idx2 = last_ins_bps / (target_bps >> 5); idx1 = mpp_clip(idx1, 0, 63); idx2 = mpp_clip(idx2, 0, 63); ins_ratio = tab_lnx[idx1] - tab_lnx[idx2]; bps_ratio = 96 * (ins_bps - target_bps) / target_bps; wl_ratio = 32 * (water_level - (ctx->water_level_thr >> 3)) / (ctx->water_level_thr >> 3); if (last_ins_bps < ins_bps && target_bps != last_ins_bps) { ins_ratio = 6 * ins_ratio; ins_ratio = mpp_clip(ins_ratio, -192, 256); } else { if (i_flag) { ins_ratio = 3 * ins_ratio; ins_ratio = mpp_clip(ins_ratio, -192, 256); } else { ins_ratio = 0; } } if (bit_diff_ratio >= 256) bit_diff_ratio = 256; if (bps_ratio >= 32) bps_ratio = 32; if (wl_ratio >= 32) wl_ratio = 32; if (bit_diff_ratio < -128) ins_ratio = ins_ratio - 128; else ins_ratio = ins_ratio + bit_diff_ratio; if (bps_ratio < -32) ins_ratio = ins_ratio - 32; else ins_ratio = ins_ratio + bps_ratio; if (wl_ratio < -32) wl_ratio = ins_ratio - 32; else wl_ratio = ins_ratio + wl_ratio; ctx->next_ratio = wl_ratio; rc_dbg_func("leave %p\n", ctx); return MPP_OK; } MPP_RET reenc_calc_vbr_ratio_smt(RcModelV2SmtCtx *ctx, EncRcTaskInfo *cfg) { RK_S32 stat_time = ctx->usr_cfg.stats_time; RK_S32 last_ins_bps = mpp_data_sum_v2(ctx->stat_bits) / stat_time; RK_S32 ins_bps = (last_ins_bps * stat_time - mpp_data_get_pre_val_v2(ctx->stat_bits, -1) + cfg->bit_real) / stat_time; RK_S32 bps_change = ctx->target_bps; RK_S32 max_bps_target = ctx->usr_cfg.bps_max; RK_S32 real_bit = cfg->bit_real; RK_S32 target_bit = cfg->bit_target; RK_S32 idx1, idx2; RK_S32 bit_diff_ratio, ins_ratio, bps_ratio; rc_dbg_func("enter %p\n", ctx); 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; idx1 = ins_bps / (max_bps_target >> 5); idx2 = last_ins_bps / (max_bps_target >> 5); idx1 = mpp_clip(idx1, 0, 63); idx2 = mpp_clip(idx2, 0, 63); if (last_ins_bps < ins_bps && bps_change < ins_bps) { ins_ratio = 6 * (tab_lnx[idx1] - tab_lnx[idx2]); ins_ratio = mpp_clip(ins_ratio, -192, 256); } else { ins_ratio = 0; } bps_ratio = 96 * (ins_bps - bps_change) / bps_change; if (bit_diff_ratio >= 256) bit_diff_ratio = 256; if (bps_ratio >= 32) bps_ratio = 32; if (bit_diff_ratio < -128) ins_ratio = ins_ratio - 128; else ins_ratio = bit_diff_ratio + ins_ratio; if (bps_ratio < -32) ins_ratio = ins_ratio - 32; else ins_ratio = ins_ratio + bps_ratio; ctx->next_ratio = ins_ratio; rc_dbg_func("leave %p\n", ctx); return MPP_OK; } MPP_RET check_re_enc_smt(RcModelV2SmtCtx *ctx, EncRcTaskInfo *cfg) { return MPP_OK; RK_S32 frame_type = ctx->frame_type; RK_S32 i_flag = 0; RK_S32 big_flag = 0; RK_S32 stat_time = ctx->usr_cfg.stats_time; RK_S32 last_ins_bps = mpp_data_sum_v2(ctx->stat_bits) / stat_time; RK_S32 ins_bps = (last_ins_bps * stat_time - mpp_data_get_pre_val_v2(ctx->stat_bits, -1) + cfg->bit_real) / stat_time; RK_S32 target_bps; RK_S32 flag1 = 0; RK_S32 flag2 = 0; rc_dbg_func("enter %p\n", ctx); if (ctx->usr_cfg.mode == RC_CBR) target_bps = ctx->usr_cfg.bps_target; else target_bps = ctx->usr_cfg.bps_max; if (ctx->reenc_cnt >= ctx->usr_cfg.max_reencode_times) { return MPP_OK; } i_flag = (frame_type == INTRA_FRAME); if (!i_flag && cfg->bit_real > 3 * cfg->bit_target) { big_flag = 1; } if (i_flag && cfg->bit_real > 3 * cfg->bit_target / 2) { big_flag = 1; } if (ctx->usr_cfg.mode == RC_CBR) { flag1 = target_bps / 20 < ins_bps - last_ins_bps; if (target_bps + target_bps / 10 < ins_bps || target_bps - target_bps / 10 > ins_bps) { flag2 = 1; } } else { flag1 = target_bps - (target_bps >> 3) < ins_bps; flag2 = target_bps / 20 < ins_bps - last_ins_bps; } if (!(big_flag && flag1 && flag2)) { return MPP_OK; } rc_dbg_func("leave %p\n", ctx); return MPP_OK; } MPP_RET rc_model_v2_smt_h265_init(void *ctx, RcCfg *cfg) { RcModelV2SmtCtx *p = (RcModelV2SmtCtx*)ctx; rc_dbg_func("enter %p\n", ctx); p->codec_type = 1; memcpy(&p->usr_cfg, cfg, sizeof(RcCfg)); bits_model_smt_init(p); rc_dbg_func("leave %p\n", ctx); return MPP_OK; } MPP_RET rc_model_v2_smt_h264_init(void *ctx, RcCfg *cfg) { RcModelV2SmtCtx *p = (RcModelV2SmtCtx*)ctx; rc_dbg_func("enter %p\n", ctx); p->codec_type = 0; memcpy(&p->usr_cfg, cfg, sizeof(RcCfg)); bits_model_smt_init(p); rc_dbg_func("leave %p\n", ctx); return MPP_OK; } MPP_RET rc_model_v2_smt_deinit(void *ctx) { RcModelV2SmtCtx *p = (RcModelV2SmtCtx *)ctx; rc_dbg_func("enter %p\n", ctx); bits_model_smt_deinit(p); rc_dbg_func("leave %p\n", ctx); return MPP_OK; } MPP_RET rc_model_v2_smt_start(void *ctx, EncRcTask *task) { RcModelV2SmtCtx *p = (RcModelV2SmtCtx*)ctx; EncFrmStatus *frm = &task->frm; EncRcTaskInfo *info = &task->info; RcFpsCfg *fps = &p->usr_cfg.fps; RK_U32 md_ctu_cnt = 0; void *ptr = NULL; if (frm->reencode) return MPP_OK; if (mpp_frame_has_meta(task->frame)) { MppMeta meta = mpp_frame_get_meta(task->frame); mpp_meta_get_ptr(meta, KEY_MV_LIST, &ptr); } md_ctu_cnt = cal_mv_info(ptr); if (frm->is_intra) { p->frame_type = INTRA_FRAME; p->acc_total_count = 0; p->acc_intra_bits_in_fps = 0; } else { p->frame_type = INTER_P_FRAME; } switch (p->gop_mode) { case MPP_GOP_ALL_INTER : { if (p->frame_type == INTRA_FRAME) { p->bits_target_low_rate = p->bits_per_intra_low_rate; p->bits_target_high_rate = p->bits_per_intra_high_rate; } else { p->bits_target_low_rate = p->bits_per_inter_low_rate - mpp_pid_calc(&p->pid_inter_low_rate); p->bits_target_high_rate = p->bits_per_inter_high_rate - mpp_pid_calc(&p->pid_inter_high_rate); } } break; case MPP_GOP_ALL_INTRA : { p->bits_target_low_rate = p->bits_per_intra_low_rate - mpp_pid_calc(&p->pid_intra_low_rate); p->bits_target_high_rate = p->bits_per_intra_high_rate - mpp_pid_calc(&p->pid_intra_high_rate); } break; default : { if (p->frame_type == INTRA_FRAME) { //float intra_percent = 0.0; RK_S32 diff_bit = mpp_pid_calc(&p->pid_fps); /* only affected by last gop */ p->pre_gop_left_bit = p->pid_fps.i - diff_bit; mpp_pid_reset(&p->pid_fps); if (p->acc_intra_count) { p->bits_target_low_rate = (p->bits_per_intra_low_rate + diff_bit); p->bits_target_high_rate = (p->bits_per_intra_high_rate + diff_bit); } else { p->bits_target_low_rate = p->bits_per_intra_low_rate - mpp_pid_calc(&p->pid_intra_low_rate); p->bits_target_high_rate = p->bits_per_intra_high_rate - mpp_pid_calc(&p->pid_intra_high_rate); } } else { if (p->last_frame_type == INTRA_FRAME) { RK_S32 diff_bit = mpp_pid_calc(&p->pid_fps); /* * case - inter frame after intra frame * update inter target bits with compensation of previous intra frame */ RK_S32 bits_prev_intra = mpp_data_avg(p->intra, 1, 1, 1); p->bits_per_inter_low_rate = (p->bps_target_low_rate * (p->gop_min * 1.0 / fps->fps_out_num) - bits_prev_intra + diff_bit + p->pre_gop_left_bit) / (p->gop_min - 1); p->bits_target_low_rate = p->bits_per_inter_low_rate; p->bits_per_inter_high_rate = (p->bps_target_high_rate * (p->gop_min * 1.0 / fps->fps_out_num) - bits_prev_intra + diff_bit + p->pre_gop_left_bit) / (p->gop_min - 1); p->bits_target_high_rate = p->bits_per_inter_high_rate; } else { RK_S32 diff_bit_low_rate = mpp_pid_calc(&p->pid_inter_low_rate); p->bits_target_low_rate = p->bits_per_inter_low_rate - diff_bit_low_rate; if (p->bits_target_low_rate > p->bits_per_pic_low_rate * 2) { p->bits_target_low_rate = 2 * p->bits_per_pic_low_rate; p->pid_inter_low_rate.i = p->pid_inter_low_rate.i / 2; } RK_S32 diff_bit_high_rate = mpp_pid_calc(&p->pid_inter_high_rate); p->bits_target_high_rate = p->bits_per_inter_high_rate - diff_bit_high_rate; if (p->bits_target_high_rate > p->bits_per_pic_high_rate * 2) { p->bits_target_high_rate = 2 * p->bits_per_pic_high_rate; p->pid_inter_high_rate.i = p->pid_inter_high_rate.i / 2; } } } } break; } if (NULL == p->qp_p) mpp_data_init(&p->qp_p, MPP_MIN(p->gop_min, 15)); if (NULL == p->sse_p) mpp_data_init(&p->sse_p, MPP_MIN(p->gop_min, 15)); RK_S32 madi = p->hal_cfg.madi; if (p->frm_num == 0) { RK_S32 bits_target_use = 0; bits_target_use = (p->bits_target_high_rate - p->bits_target_low_rate) * 1 * 0.5 + p->bits_target_low_rate; p->bits_target_use = bits_target_use; bits_target_use = bits_target_use * ((1920 * 1080 * 1000) / (p->usr_cfg.width * p->usr_cfg.height)) / 1000; p->qp_out = 95 - 10.0 * log((float)(bits_target_use / 1000)); if (p->qp_out < 27) { p->qp_out = 27; } p->qp_out = mpp_clip(p->qp_out, p->qp_min, p->qp_max); p->qp_preavg = 0; } if (p->frame_type == INTRA_FRAME) { if (p->frm_num > 0) { p->qp_out = mpp_data_avg(p->qp_p, -1, 1, 1) - 3; RK_S32 sse = mpp_data_avg(p->sse_p, 1, 1, 1) + 1; RK_S32 bit_target_use = (p->bits_target_low_rate + p->bits_target_high_rate) / 2; RK_S32 qp_add = 0; if (bit_target_use < 100) bit_target_use = 100; if (sse < p->intra_presse) { if (bit_target_use <= p->intra_prerealbit) { p->qp_out = p->intra_preqp; } else { if (madi >= MAD_THDI) { p->qp_out = p->intra_preqp - 1; } else { if (p->intra_preqp - p->qp_out >= 4) { p->qp_out = p->intra_preqp - (madi <= 12 ? 4 : 3); } } } } else if (sse > p->intra_presse && p->qp_out < p->intra_preqp) { if (p->intra_preqp - p->qp_out >= 3) p->qp_out = p->intra_preqp - 2; } else { RK_S32 ratio = (RK_S32)((float)sse / (float)p->intra_presse + 0.5); if (ratio <= 2) { p->qp_out = p->intra_preqp; } else if (ratio <= 4) { p->qp_out = mpp_clip(p->qp_out, p->intra_preqp - 1, p->intra_preqp + 1); } else { p->qp_out = mpp_clip(p->qp_out, p->intra_preqp - 2, p->intra_preqp + 2); } } if (p->qp_prev_out < 25) { qp_add = 4; } else if (p->qp_prev_out < 27) { qp_add = 2; } else if (p->qp_prev_out < 29) { qp_add = 1; } p->qp_out = mpp_clip(p->qp_out, p->qp_prev_out - 4, p->qp_prev_out + qp_add); p->bits_target_use = (p->bits_target_low_rate + p->bits_target_high_rate) / 2; if (p->bits_target_use < 100) p->bits_target_use = 100; } } else { p->bits_target_use = (p->bits_target_low_rate + p->bits_target_high_rate) / 2; p->qp_out = p->qp_preavg; if (p->last_frame_type == INTRA_FRAME) { RK_S32 qp_add = 0; if (p->qp_prev_out < 25) { qp_add = 2; } else if (p->qp_prev_out < 29) { qp_add = 1; } p->qp_out = mpp_clip(p->qp_out, p->qp_prev_out + qp_add, p->qp_prev_out + 4 + qp_add); p->bits_target_use = (p->bits_target_low_rate + p->bits_target_high_rate) / 2; if (p->bits_target_use < 100) p->bits_target_use = 100; } else { MppFrame frame = task->frame; RK_S32 width = mpp_frame_get_width(frame); RK_S32 height = mpp_frame_get_height(frame); float coef = (float)md_ctu_cnt / (MPP_ALIGN(width, 16) / 16 * MPP_ALIGN(height, 16) / 16); float coef2 = 0.5; if (coef >= 0.7) coef2 = 1.0; else if (coef >= 0.3) // 0.7~0.3 --> 1.0~0.5 coef2 = 0.5 + (coef - 0.3) * (1.0 - 0.5) / (0.7 - 0.3); else // 0.3~0.0 --> 0.5~0.0 coef2 = 0.0 + coef * (0.5 - 0.0) / (0.3 - 0.0); RK_S32 bits_target_use = p->bits_target_low_rate; // bits_target_high_rate RK_S32 pre_diff_bit_use = p->pre_diff_bit_low_rate; // pre_diff_bit_high_rate bits_target_use = (p->bits_target_high_rate - p->bits_target_low_rate) * 1 * coef2 + p->bits_target_low_rate; pre_diff_bit_use = (p->pre_diff_bit_high_rate - p->pre_diff_bit_low_rate) * 1 * coef2 + p->pre_diff_bit_low_rate; if (bits_target_use < 100) bits_target_use = 100; p->bits_target_use = bits_target_use; if (abs(pre_diff_bit_use) <= bits_target_use * 3 / 100) { p->qp_out = p->qp_prev_out - 1; } else if (pre_diff_bit_use > bits_target_use * 3 / 100) { if (pre_diff_bit_use >= bits_target_use) { p->qp_out = (p->qp_out >= 30 && madi < MAD_THDI) ? p->qp_prev_out - 4 : p->qp_prev_out - 3; } else if (pre_diff_bit_use >= bits_target_use * 1 / 4) { p->qp_out = (p->qp_out >= 30 && madi < MAD_THDI) ? p->qp_prev_out - 3 : p->qp_prev_out - 2; } else if (pre_diff_bit_use > bits_target_use * 1 / 10) { p->qp_out = (madi < MAD_THDI) ? p->qp_prev_out - 2 : p->qp_prev_out - 1; } else { p->qp_out = p->qp_prev_out - 1; } } else { pre_diff_bit_use = abs(pre_diff_bit_use); RK_S32 weight = (madi < MAD_THDI ? 1 : 3); if (pre_diff_bit_use >= 2 * weight * bits_target_use) { p->qp_out = p->qp_prev_out + 3 ; } else if (pre_diff_bit_use >= bits_target_use * 2 * weight / 3) { p->qp_out = p->qp_prev_out + 2 ; } else if (pre_diff_bit_use > bits_target_use * weight / 5) { p->qp_out = p->qp_prev_out + 1; } else { p->qp_out = p->qp_prev_out; } } p->qp_out = mpp_clip(p->qp_out, p->qp_min, p->qp_max); pre_diff_bit_use = (p->pre_diff_bit_high_rate - p->pre_diff_bit_low_rate) * 1 * coef2 + p->pre_diff_bit_low_rate; RK_S32 low_pre_diff_bit_use = LOW_PRE_DIFF_BIT_USE; low_pre_diff_bit_use = (p->bps_target_low_rate + p->bps_target_high_rate) / 2 / fps->fps_out_num; low_pre_diff_bit_use = -low_pre_diff_bit_use / 5; RK_S32 frame_low_qp; if (p->codec_type == 1) { if (madi >= MAD_THDI) frame_low_qp = LOW_QP_level1; else frame_low_qp = LOW_QP_level0; } else { frame_low_qp = LOW_QP; } if (p->qp_out > frame_low_qp) { if (pre_diff_bit_use <= 2 * low_pre_diff_bit_use) coef2 += 0.5; else if (pre_diff_bit_use <= low_pre_diff_bit_use) coef2 += 0.2; else coef2 += 0.1; if (coef2 >= 1.0) coef2 = 1.0; if (p->qp_out > LOW_LOW_QP) coef2 = 1.0; if (coef2 == 1.0 && p->qp_prev_out > frame_low_qp) { float delta_coef = 0; if (p->bits_one_gop_use_flag == 1 && p->delta_bits_per_frame > 0) { delta_coef = ((float)p->delta_bits_per_frame) / ((float)p->bits_per_inter_high_rate - p->bits_per_inter_low_rate); if (delta_coef >= 0.5) delta_coef = 0.5; else if (delta_coef >= 0.3) delta_coef = 0.3; if (p->qp_prev_out > (frame_low_qp + 1)) delta_coef += 0.1; coef2 += delta_coef; } } bits_target_use = (p->bits_target_high_rate - p->bits_target_low_rate) * 1 * coef2 + p->bits_target_low_rate; pre_diff_bit_use = (p->pre_diff_bit_high_rate - p->pre_diff_bit_low_rate) * 1 * coef2 + p->pre_diff_bit_low_rate; if (bits_target_use < 100) bits_target_use = 100; p->bits_target_use = bits_target_use; if (abs(pre_diff_bit_use) <= bits_target_use * 3 / 100) { p->qp_out = p->qp_prev_out ; } else if (pre_diff_bit_use > bits_target_use * 3 / 100) { if (pre_diff_bit_use >= bits_target_use) { p->qp_out = (p->qp_out >= 30 && madi < MAD_THDI) ? p->qp_prev_out - 3 : p->qp_prev_out - 2; } else if (pre_diff_bit_use >= bits_target_use * 1 / 4) { p->qp_out = (p->qp_out >= 30 && madi < MAD_THDI) ? p->qp_prev_out - 2 : p->qp_prev_out - 1; } else if (pre_diff_bit_use > bits_target_use * 1 / 10) { p->qp_out = (madi < MAD_THDI) ? p->qp_prev_out - 1 : p->qp_prev_out; } else { p->qp_out = p->qp_prev_out; } } else { pre_diff_bit_use = abs(pre_diff_bit_use); RK_S32 weight = (madi < MAD_THDI ? 0 : 2); if (pre_diff_bit_use >= 2 * weight * bits_target_use) { p->qp_out = p->qp_prev_out + 1 ; } else if (pre_diff_bit_use >= bits_target_use * 2 * weight / 3) { p->qp_out = p->qp_prev_out + 1 ; } else if (pre_diff_bit_use > bits_target_use * weight / 5) { p->qp_out = p->qp_prev_out; } else { p->qp_out = p->qp_prev_out; } } p->qp_out = mpp_clip(p->qp_out, p->qp_min, p->qp_max); } if (p->qp_out < LIMIT_QP_MORE_MOVE && coef >= 0.2) p->qp_out = LIMIT_QP_MORE_MOVE; } } if (p->frm_num >= 1) { p->qp_out = mpp_clip(p->qp_out, p->qp_prev_out - 3, p->qp_prev_out + p->qp_step); } info->bit_target = p->bits_target_use; info->quality_target = p->qp_out; info->quality_max = p->usr_cfg.max_quality; info->quality_min = p->usr_cfg.min_quality; p->frm_num++; p->reenc_cnt = 0; rc_dbg_func("leave %p\n", ctx); return MPP_OK; } MPP_RET rc_model_v2_smt_check_reenc(void *ctx, EncRcTask *task) { RcModelV2SmtCtx *p = (RcModelV2SmtCtx *)ctx; EncRcTaskInfo *cfg = (EncRcTaskInfo *)&task->info; EncFrmStatus *frm = &task->frm; RcCfg *usr_cfg = &p->usr_cfg; rc_dbg_func("enter ctx %p cfg %p\n", ctx, cfg); frm->reencode = 0; if ((usr_cfg->mode == RC_FIXQP) || (task->force.force_flag & ENC_RC_FORCE_QP)) return MPP_OK; if (check_re_enc_smt(p, cfg)) { if (p->usr_cfg.mode == RC_CBR) { reenc_calc_cbr_ratio_smt(p, cfg); } else { reenc_calc_vbr_ratio_smt(p, cfg); } if (p->next_ratio != 0 && cfg->quality_target < cfg->quality_max) { p->reenc_cnt++; frm->reencode = 1; } } rc_dbg_func("leave %p\n", ctx); return MPP_OK; } MPP_RET rc_model_v2_smt_end(void *ctx, EncRcTask *task) { RcModelV2SmtCtx *p = (RcModelV2SmtCtx *)ctx; EncRcTaskInfo *cfg = (EncRcTaskInfo *)&task->info; MppFrame frame = task->frame; RK_S32 width = mpp_frame_get_width(frame); RK_S32 height = mpp_frame_get_height(frame); RK_S32 bit_real = cfg->bit_real; RK_S32 madi = cfg->madi; RK_S32 cu64_num = (MPP_ALIGN(width, 64) / 64 * MPP_ALIGN(height, 64) / 64) ; RK_U64 sse_dat = cfg->madp * cu64_num; RK_U32 qp_sum; double avg_qp = 0.0; RK_S32 avg_sse = 1; rc_dbg_func("enter ctx %p cfg %p\n", ctx, cfg); if (p->codec_type == 1) qp_sum = cfg->quality_real / 64; // 265 else qp_sum = cfg->quality_real / 16; // 264 avg_qp = qp_sum; avg_sse = (RK_S32)sqrt((double)(sse_dat)); p->qp_preavg = (RK_S32)(avg_qp + 0.5); if (p->frame_type == INTER_P_FRAME) { if (madi >= MAD_THDI) { avg_qp = p->qp_out; } } if (p->frame_type == INTER_P_FRAME || p->gop_mode == MPP_GOP_ALL_INTRA) { mpp_data_update(p->qp_p, avg_qp); mpp_data_update(p->sse_p, avg_sse); } else { p->intra_preqp = p->qp_out; p->intra_presse = avg_sse; p->intra_premadi = madi; p->intra_prerealbit = bit_real; } p->st_madi = cfg->madi; rc_dbg_rc("bits_mode_update real_bit %d", bit_real); bits_model_update_smt(p, bit_real); p->pre_target_bits = cfg->bit_target; p->pre_real_bits = bit_real; p->qp_prev_out = p->qp_out; p->last_inst_bps = p->ins_bps; p->last_frame_type = p->frame_type; rc_dbg_func("leave %p\n", ctx); return MPP_OK; } MPP_RET rc_model_v2_smt_hal_start(void *ctx, EncRcTask *task) { rc_dbg_func("smt_hal_start enter ctx %p task %p\n", ctx, task); return MPP_OK; } MPP_RET rc_model_v2_smt_hal_end(void *ctx, EncRcTask *task) { rc_dbg_func("smt_hal_end enter ctx %p task %p\n", ctx, task); rc_dbg_func("leave %p\n", ctx); return MPP_OK; } const RcImplApi smt_h264e = { "smart", MPP_VIDEO_CodingAVC, sizeof(RcModelV2SmtCtx), rc_model_v2_smt_h264_init, rc_model_v2_smt_deinit, NULL, rc_model_v2_smt_check_reenc, rc_model_v2_smt_start, rc_model_v2_smt_end, rc_model_v2_smt_hal_start, rc_model_v2_smt_hal_end, }; const RcImplApi smt_h265e = { "smart", MPP_VIDEO_CodingHEVC, sizeof(RcModelV2SmtCtx), rc_model_v2_smt_h265_init, rc_model_v2_smt_deinit, NULL, rc_model_v2_smt_check_reenc, rc_model_v2_smt_start, rc_model_v2_smt_end, rc_model_v2_smt_hal_start, rc_model_v2_smt_hal_end, };