Group quantization config in AV1EncoderConfig This CL groups configuration parameters related to quantization in AV1EncoderConfig into a new struct QuantizationCfg, removes redundant variables and adds relevant documentation. BUG=aomedia:2701 Change-Id: I9c55f16616155bd6e0df02b4d80c82b69f6d9a09
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c index 712a0eb..90684f0 100644 --- a/av1/av1_cx_iface.c +++ b/av1/av1_cx_iface.c
@@ -726,6 +726,8 @@ RateControlCfg *const rc_cfg = &oxcf->rc_cfg; + QuantizationCfg *const q_cfg = &oxcf->q_cfg; + const int is_vbr = cfg->rc_end_usage == AOM_VBR; oxcf->profile = cfg->g_profile; oxcf->max_threads = (int)cfg->g_threads; @@ -814,13 +816,30 @@ oxcf->enable_palette = extra_cfg->enable_palette; oxcf->disable_trellis_quant = extra_cfg->disable_trellis_quant; oxcf->allow_ref_frame_mvs = extra_cfg->enable_ref_frame_mvs; - oxcf->using_qm = extra_cfg->enable_qm; - oxcf->qm_y = extra_cfg->qm_y; - oxcf->qm_u = extra_cfg->qm_u; - oxcf->qm_v = extra_cfg->qm_v; - oxcf->qm_minlevel = extra_cfg->qm_min; - oxcf->qm_maxlevel = extra_cfg->qm_max; - oxcf->quant_b_adapt = extra_cfg->quant_b_adapt; + + // Set Quantization related configuration. + q_cfg->using_qm = extra_cfg->enable_qm; + q_cfg->qm_minlevel = extra_cfg->qm_min; + q_cfg->qm_maxlevel = extra_cfg->qm_max; + q_cfg->quant_b_adapt = extra_cfg->quant_b_adapt; + q_cfg->enable_chroma_deltaq = extra_cfg->enable_chroma_deltaq; + q_cfg->aq_mode = extra_cfg->aq_mode; + q_cfg->deltaq_mode = extra_cfg->deltaq_mode; + q_cfg->use_fixed_qp_offsets = + cfg->use_fixed_qp_offsets && (rc_cfg->mode == AOM_Q); + for (int i = 0; i < FIXED_QP_OFFSET_COUNT; ++i) { + if (q_cfg->use_fixed_qp_offsets) { + if (cfg->fixed_qp_offsets[i] >= 0) { // user-provided qp offset + q_cfg->fixed_qp_offsets[i] = convert_qp_offset( + rc_cfg->cq_level, cfg->fixed_qp_offsets[i], oxcf->bit_depth); + } else { // auto-selected qp offset + q_cfg->fixed_qp_offsets[i] = + get_modeled_qp_offset(rc_cfg->cq_level, i, oxcf->bit_depth); + } + } else { + q_cfg->fixed_qp_offsets[i] = -1.0; + } + } // Set cost update frequency configuration. oxcf->cost_upd_freq.coeff = (COST_UPDATE_TYPE)extra_cfg->coeff_cost_upd_freq; @@ -1049,12 +1068,8 @@ oxcf->enable_tpl_model = resize_cfg->resize_mode ? 0 : extra_cfg->enable_tpl_model; - oxcf->enable_chroma_deltaq = extra_cfg->enable_chroma_deltaq; - oxcf->aq_mode = extra_cfg->aq_mode; - oxcf->deltaq_mode = extra_cfg->deltaq_mode; - oxcf->deltalf_mode = - (oxcf->deltaq_mode != NO_DELTA_Q) && extra_cfg->deltalf_mode; + (q_cfg->deltaq_mode != NO_DELTA_Q) && extra_cfg->deltalf_mode; oxcf->save_as_annexb = cfg->save_as_annexb; @@ -1072,24 +1087,8 @@ sizeof(oxcf->target_seq_level_idx)); oxcf->tier_mask = extra_cfg->tier_mask; - oxcf->use_fixed_qp_offsets = - cfg->use_fixed_qp_offsets && (rc_cfg->mode == AOM_Q); oxcf->vbr_corpus_complexity_lap = extra_cfg->vbr_corpus_complexity_lap; - for (int i = 0; i < FIXED_QP_OFFSET_COUNT; ++i) { - if (oxcf->use_fixed_qp_offsets) { - if (cfg->fixed_qp_offsets[i] >= 0) { // user-provided qp offset - oxcf->fixed_qp_offsets[i] = convert_qp_offset( - rc_cfg->cq_level, cfg->fixed_qp_offsets[i], oxcf->bit_depth); - } else { // auto-selected qp offset - oxcf->fixed_qp_offsets[i] = - get_modeled_qp_offset(rc_cfg->cq_level, i, oxcf->bit_depth); - } - } else { - oxcf->fixed_qp_offsets[i] = -1.0; - } - } - return AOM_CODEC_OK; }
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c index c132019..d98fc46 100644 --- a/av1/encoder/encode_strategy.c +++ b/av1/encoder/encode_strategy.c
@@ -1184,7 +1184,7 @@ frame_params.speed = oxcf->speed; // Work out some encoding parameters specific to the pass: - if (has_no_stats_stage(cpi) && oxcf->aq_mode == CYCLIC_REFRESH_AQ) { + if (has_no_stats_stage(cpi) && oxcf->q_cfg.aq_mode == CYCLIC_REFRESH_AQ) { av1_cyclic_refresh_update_parameters(cpi); } else if (is_stat_generation_stage(cpi)) { cpi->td.mb.e_mbd.lossless[0] = is_lossless_requested(&oxcf->rc_cfg); @@ -1267,7 +1267,7 @@ cpi->td.mb.delta_qindex = 0; if (!frame_params.show_existing_frame) { - cm->quant_params.using_qmatrix = oxcf->using_qm; + cm->quant_params.using_qmatrix = oxcf->q_cfg.using_qm; #if !CONFIG_REALTIME_ONLY if (gf_cfg->lag_in_frames > 0 && !is_stat_generation_stage(cpi)) { if (cpi->gf_group.index == 1 && oxcf->enable_tpl_model) {
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c index 7331947..cfc8c20 100644 --- a/av1/encoder/encodeframe.c +++ b/av1/encoder/encodeframe.c
@@ -296,7 +296,7 @@ if (!is_frame_tpl_eligible((AV1_COMP *)cpi)) return deltaq_rdmult; if (tpl_idx >= MAX_TPL_FRAME_IDX) return deltaq_rdmult; if (cpi->superres_mode != AOM_SUPERRES_NONE) return deltaq_rdmult; - if (cpi->oxcf.aq_mode != NO_AQ) return deltaq_rdmult; + if (cpi->oxcf.q_cfg.aq_mode != NO_AQ) return deltaq_rdmult; const int bsize_base = BLOCK_16X16; const int num_mi_w = mi_size_wide[bsize_base]; @@ -579,7 +579,7 @@ // If segmentation in use if (seg->enabled) { // For in frame complexity AQ copy the segment id from the segment map. - if (cpi->oxcf.aq_mode == COMPLEXITY_AQ) { + if (cpi->oxcf.q_cfg.aq_mode == COMPLEXITY_AQ) { const uint8_t *const map = seg->update_map ? cpi->enc_seg.map : cm->last_frame_seg_map; mi_addr->segment_id = @@ -588,7 +588,7 @@ } // Else for cyclic refresh mode update the segment map, set the segment id // and then update the quantizer. - if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) { + if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ) { av1_cyclic_refresh_update_segment(cpi, mi_addr, mi_row, mi_col, bsize, ctx->rd_stats.rate, ctx->rd_stats.dist, txfm_info->skip_txfm); @@ -616,7 +616,8 @@ } } - if (cpi->oxcf.aq_mode) av1_init_plane_quantizers(cpi, x, mi_addr->segment_id); + if (cpi->oxcf.q_cfg.aq_mode) + av1_init_plane_quantizers(cpi, x, mi_addr->segment_id); if (dry_run) return; @@ -773,7 +774,7 @@ MB_MODE_INFO *mbmi; struct macroblock_plane *const p = x->plane; struct macroblockd_plane *const pd = xd->plane; - const AQ_MODE aq_mode = cpi->oxcf.aq_mode; + const AQ_MODE aq_mode = cpi->oxcf.q_cfg.aq_mode; TxfmSearchInfo *txfm_info = &x->txfm_search_info; int i; @@ -2325,7 +2326,7 @@ MB_MODE_INFO *mbmi = xd->mi[0]; struct macroblock_plane *const p = x->plane; struct macroblockd_plane *const pd = xd->plane; - const AQ_MODE aq_mode = cpi->oxcf.aq_mode; + const AQ_MODE aq_mode = cpi->oxcf.q_cfg.aq_mode; TxfmSearchInfo *txfm_info = &x->txfm_search_info; int i; #if CONFIG_COLLECT_COMPONENT_TIMING @@ -4500,7 +4501,7 @@ av1_setup_src_planes(x, cpi->source, mi_row, mi_col, num_planes, sb_size); int current_qindex = cm->quant_params.base_qindex; - if (cpi->oxcf.deltaq_mode == DELTA_Q_PERCEPTUAL) { + if (cpi->oxcf.q_cfg.deltaq_mode == DELTA_Q_PERCEPTUAL) { if (DELTA_Q_PERCEPTUAL_MODULATION == 1) { const int block_wavelet_energy_level = av1_block_wavelet_energy_level(cpi, x, sb_size); @@ -4513,7 +4514,7 @@ current_qindex = av1_compute_q_from_energy_level_deltaq_mode(cpi, block_var_level); } - } else if (cpi->oxcf.deltaq_mode == DELTA_Q_OBJECTIVE && + } else if (cpi->oxcf.q_cfg.deltaq_mode == DELTA_Q_OBJECTIVE && cpi->oxcf.enable_tpl_model) { // Setup deltaq based on tpl stats current_qindex = get_q_for_deltaq_objective(cpi, sb_size, mi_row, mi_col); @@ -4522,7 +4523,7 @@ const int delta_q_res = delta_q_info->delta_q_res; // Right now aq only works with tpl model. So if tpl is disabled, we set the // current_qindex to base_qindex. - if (cpi->oxcf.enable_tpl_model && cpi->oxcf.deltaq_mode != NO_DELTA_Q) { + if (cpi->oxcf.enable_tpl_model && cpi->oxcf.q_cfg.deltaq_mode != NO_DELTA_Q) { current_qindex = clamp(current_qindex, delta_q_res, 256 - delta_q_info->delta_q_res); } else { @@ -4762,8 +4763,8 @@ assert(IMPLIES(cpi->gf_group.size > 0, cpi->gf_group.index < cpi->gf_group.size)); const int gf_group_index = cpi->gf_group.index; - if (cpi->oxcf.enable_tpl_model && cpi->oxcf.aq_mode == NO_AQ && - cpi->oxcf.deltaq_mode == NO_DELTA_Q && gf_group_index > 0 && + if (cpi->oxcf.enable_tpl_model && cpi->oxcf.q_cfg.aq_mode == NO_AQ && + cpi->oxcf.q_cfg.deltaq_mode == NO_DELTA_Q && gf_group_index > 0 && cpi->gf_group.update_type[gf_group_index] == ARF_UPDATE) { const int dr = get_rdmult_delta(cpi, sb_size, 0, mi_row, mi_col, orig_rdmult); @@ -4982,7 +4983,7 @@ if (!is_frame_tpl_eligible(cpi)) return; if (frame_idx >= MAX_TPL_FRAME_IDX) return; if (cpi->superres_mode != AOM_SUPERRES_NONE) return; - if (cpi->oxcf.aq_mode != NO_AQ) return; + if (cpi->oxcf.q_cfg.aq_mode != NO_AQ) return; const int is_overlay = cpi->gf_group.update_type[frame_idx] == OVERLAY_UPDATE; if (is_overlay) { @@ -5803,6 +5804,7 @@ MultiThreadInfo *const mt_info = &cpi->mt_info; AV1EncRowMultiThreadInfo *const enc_row_mt = &mt_info->enc_row_mt; const AV1EncoderConfig *const oxcf = &cpi->oxcf; + const DELTAQ_MODE deltaq_mode = oxcf->q_cfg.deltaq_mode; int i; if (!cpi->sf.rt_sf.use_nonrd_pick_mode) { @@ -5914,20 +5916,20 @@ // Fix delta q resolution for the moment cm->delta_q_info.delta_q_res = 0; - if (oxcf->deltaq_mode == DELTA_Q_OBJECTIVE) + if (deltaq_mode == DELTA_Q_OBJECTIVE) cm->delta_q_info.delta_q_res = DEFAULT_DELTA_Q_RES_OBJECTIVE; - else if (oxcf->deltaq_mode == DELTA_Q_PERCEPTUAL) + else if (deltaq_mode == DELTA_Q_PERCEPTUAL) cm->delta_q_info.delta_q_res = DEFAULT_DELTA_Q_RES_PERCEPTUAL; // Set delta_q_present_flag before it is used for the first time cm->delta_q_info.delta_lf_res = DEFAULT_DELTA_LF_RES; - cm->delta_q_info.delta_q_present_flag = oxcf->deltaq_mode != NO_DELTA_Q; + cm->delta_q_info.delta_q_present_flag = deltaq_mode != NO_DELTA_Q; // Turn off cm->delta_q_info.delta_q_present_flag if objective delta_q is used // for ineligible frames. That effectively will turn off row_mt usage. // Note objective delta_q and tpl eligible frames are only altref frames // currently. if (cm->delta_q_info.delta_q_present_flag) { - if (oxcf->deltaq_mode == DELTA_Q_OBJECTIVE && !is_frame_tpl_eligible(cpi)) + if (deltaq_mode == DELTA_Q_OBJECTIVE && !is_frame_tpl_eligible(cpi)) cm->delta_q_info.delta_q_present_flag = 0; }
diff --git a/av1/encoder/encodemb.c b/av1/encoder/encodemb.c index fe774ef..9cda30e 100644 --- a/av1/encoder/encodemb.c +++ b/av1/encoder/encodemb.c
@@ -393,8 +393,8 @@ quant_idx = USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B : AV1_XFORM_QUANT_FP; av1_setup_xform(cm, x, tx_size, tx_type, &txfm_param); - av1_setup_quant(tx_size, use_trellis, quant_idx, cpi->oxcf.quant_b_adapt, - &quant_param); + av1_setup_quant(tx_size, use_trellis, quant_idx, + cpi->oxcf.q_cfg.quant_b_adapt, &quant_param); av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, tx_type, &quant_param); av1_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, &txfm_param, @@ -437,8 +437,8 @@ // again. if (p->eobs[block] == 0 && plane == 0) { #if 0 - if (args->cpi->oxcf.aq_mode == NO_AQ && - args->cpi->oxcf.deltaq_mode == NO_DELTA_Q) { + if (args->cpi->oxcf.q_cfg.aq_mode == NO_AQ && + args->cpi->oxcf.q_cfg.deltaq_mode == NO_DELTA_Q) { // TODO(jingning,angiebird,huisu@google.com): enable txk_check when // enable_optimize_b is true to detect potential RD bug. const uint8_t disable_txk_check = args->enable_optimize_b; @@ -584,7 +584,7 @@ QUANT_PARAM quant_param; av1_setup_xform(cm, x, tx_size, DCT_DCT, &txfm_param); - av1_setup_quant(tx_size, 0, AV1_XFORM_QUANT_B, cpi->oxcf.quant_b_adapt, + av1_setup_quant(tx_size, 0, AV1_XFORM_QUANT_B, cpi->oxcf.q_cfg.quant_b_adapt, &quant_param); av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, DCT_DCT, &quant_param); @@ -727,8 +727,8 @@ USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B : AV1_XFORM_QUANT_FP; av1_setup_xform(cm, x, tx_size, tx_type, &txfm_param); - av1_setup_quant(tx_size, use_trellis, quant_idx, cpi->oxcf.quant_b_adapt, - &quant_param); + av1_setup_quant(tx_size, use_trellis, quant_idx, + cpi->oxcf.q_cfg.quant_b_adapt, &quant_param); av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, tx_type, &quant_param); @@ -775,8 +775,8 @@ // again. if (*eob == 0 && plane == 0) { #if 0 - if (args->cpi->oxcf.aq_mode == NO_AQ - && args->cpi->oxcf.deltaq_mode == NO_DELTA_Q) { + if (args->cpi->oxcf.q_cfg.aq_mode == NO_AQ + && args->cpi->oxcf.q_cfg.deltaq_mode == NO_DELTA_Q) { assert(xd->tx_type_map[blk_row * xd->tx_type_map_stride + blk_col)] == DCT_DCT); }
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index e608c15..afdb991 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -2712,6 +2712,8 @@ // "cm->features.allow_intrabc" and "cpi->is_screen_content_type". static void determine_sc_tools_with_encoding(AV1_COMP *cpi, const int q_orig) { AV1_COMMON *const cm = &cpi->common; + const AV1EncoderConfig *const oxcf = &cpi->oxcf; + const QuantizationCfg *const q_cfg = &oxcf->q_cfg; // Variables to help determine if we should allow screen content tools. int projected_size_pass[3] = { 0 }; PSNR_STATS psnr[3]; @@ -2721,8 +2723,8 @@ const int allow_intrabc_orig_decision = cm->features.allow_intrabc; const int is_screen_content_type_orig_decision = cpi->is_screen_content_type; // Turn off the encoding trial for forward key frame and superres. - if (cpi->sf.rt_sf.use_nonrd_pick_mode || cpi->oxcf.kf_cfg.fwd_kf_enabled || - cpi->superres_mode != AOM_SUPERRES_NONE || cpi->oxcf.mode == REALTIME || + if (cpi->sf.rt_sf.use_nonrd_pick_mode || oxcf->kf_cfg.fwd_kf_enabled || + cpi->superres_mode != AOM_SUPERRES_NONE || oxcf->mode == REALTIME || is_screen_content_type_orig_decision || !is_key_frame) { return; } @@ -2732,7 +2734,7 @@ // for lossless coding. // Use a high q and a fixed partition to do quick encoding. const int q_for_screen_content_quick_run = - is_lossless_requested(&cpi->oxcf.rc_cfg) ? q_orig : AOMMAX(q_orig, 244); + is_lossless_requested(&oxcf->rc_cfg) ? q_orig : AOMMAX(q_orig, 244); const int partition_search_type_orig = cpi->sf.part_sf.partition_search_type; const BLOCK_SIZE fixed_partition_block_size_orig = cpi->sf.part_sf.always_this_block_size; @@ -2767,23 +2769,23 @@ for (int pass = 0; pass < 2; ++pass) { set_encoding_params_for_screen_content(cpi, pass); #if CONFIG_TUNE_VMAF - if (cpi->oxcf.tuning == AOM_TUNE_VMAF_WITH_PREPROCESSING || - cpi->oxcf.tuning == AOM_TUNE_VMAF_WITHOUT_PREPROCESSING || - cpi->oxcf.tuning == AOM_TUNE_VMAF_MAX_GAIN) { + if (oxcf->tuning == AOM_TUNE_VMAF_WITH_PREPROCESSING || + oxcf->tuning == AOM_TUNE_VMAF_WITHOUT_PREPROCESSING || + oxcf->tuning == AOM_TUNE_VMAF_MAX_GAIN) { av1_set_quantizer( - cm, cpi->oxcf.qm_minlevel, cpi->oxcf.qm_maxlevel, + cm, q_cfg->qm_minlevel, q_cfg->qm_maxlevel, av1_get_vmaf_base_qindex(cpi, q_for_screen_content_quick_run), - cpi->oxcf.enable_chroma_deltaq); + q_cfg->enable_chroma_deltaq); } else { #endif - av1_set_quantizer(cm, cpi->oxcf.qm_minlevel, cpi->oxcf.qm_maxlevel, + av1_set_quantizer(cm, q_cfg->qm_minlevel, q_cfg->qm_maxlevel, q_for_screen_content_quick_run, - cpi->oxcf.enable_chroma_deltaq); + q_cfg->enable_chroma_deltaq); #if CONFIG_TUNE_VMAF } #endif - av1_set_speed_features_qindex_dependent(cpi, cpi->oxcf.speed); - if (cpi->oxcf.deltaq_mode != NO_DELTA_Q) + av1_set_speed_features_qindex_dependent(cpi, oxcf->speed); + if (q_cfg->deltaq_mode != NO_DELTA_Q) av1_init_quantizer(&cpi->enc_quant_dequant_params, &cm->quant_params, cm->seq_params.bit_depth); @@ -2817,6 +2819,7 @@ */ static int encode_without_recode(AV1_COMP *cpi) { AV1_COMMON *const cm = &cpi->common; + const QuantizationCfg *const q_cfg = &cpi->oxcf.q_cfg; int top_index = 0, bottom_index = 0, q = 0; set_size_independent_vars(cpi); @@ -2842,10 +2845,10 @@ } if (!frame_is_intra_only(cm)) scale_references(cpi); - av1_set_quantizer(cm, cpi->oxcf.qm_minlevel, cpi->oxcf.qm_maxlevel, q, - cpi->oxcf.enable_chroma_deltaq); + av1_set_quantizer(cm, q_cfg->qm_minlevel, q_cfg->qm_maxlevel, q, + q_cfg->enable_chroma_deltaq); av1_set_speed_features_qindex_dependent(cpi, cpi->oxcf.speed); - if (cpi->oxcf.deltaq_mode != NO_DELTA_Q) + if (q_cfg->deltaq_mode != NO_DELTA_Q) av1_init_quantizer(&cpi->enc_quant_dequant_params, &cm->quant_params, cm->seq_params.bit_depth); av1_set_variance_partition_thresholds(cpi, q, 0); @@ -2857,17 +2860,17 @@ if (cpi->sf.rt_sf.overshoot_detection_cbr == FAST_DETECTION_MAXQ && cpi->rc.high_source_sad) { if (av1_encodedframe_overshoot(cpi, &q)) { - av1_set_quantizer(cm, cpi->oxcf.qm_minlevel, cpi->oxcf.qm_maxlevel, q, - cpi->oxcf.enable_chroma_deltaq); + av1_set_quantizer(cm, q_cfg->qm_minlevel, q_cfg->qm_maxlevel, q, + q_cfg->enable_chroma_deltaq); av1_set_speed_features_qindex_dependent(cpi, cpi->oxcf.speed); - if (cpi->oxcf.deltaq_mode != NO_DELTA_Q) + if (q_cfg->deltaq_mode != NO_DELTA_Q) av1_init_quantizer(&cpi->enc_quant_dequant_params, &cm->quant_params, cm->seq_params.bit_depth); av1_set_variance_partition_thresholds(cpi, q, 0); } } - if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) { + if (q_cfg->aq_mode == CYCLIC_REFRESH_AQ) { suppress_active_map(cpi); av1_cyclic_refresh_setup(cpi); apply_active_map(cpi); @@ -2897,7 +2900,7 @@ av1_encode_frame(cpi); // Update some stats from cyclic refresh. - if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && !frame_is_intra_only(cm)) + if (q_cfg->aq_mode == CYCLIC_REFRESH_AQ && !frame_is_intra_only(cm)) av1_cyclic_refresh_postencode(cpi); #if CONFIG_COLLECT_COMPONENT_TIMING @@ -2933,9 +2936,11 @@ AV1_COMMON *const cm = &cpi->common; RATE_CONTROL *const rc = &cpi->rc; GlobalMotionInfo *const gm_info = &cpi->gm_info; + const AV1EncoderConfig *const oxcf = &cpi->oxcf; + const QuantizationCfg *const q_cfg = &oxcf->q_cfg; const int allow_recode = (cpi->sf.hl_sf.recode_loop != DISALLOW_RECODE); // Must allow recode if minimum compression ratio is set. - assert(IMPLIES(cpi->oxcf.rc_cfg.min_cr > 0, allow_recode)); + assert(IMPLIES(oxcf->rc_cfg.min_cr > 0, allow_recode)); set_size_independent_vars(cpi); if (is_stat_consumption_stage_twopass(cpi) && @@ -3010,22 +3015,22 @@ scale_references(cpi); } #if CONFIG_TUNE_VMAF - if (cpi->oxcf.tuning == AOM_TUNE_VMAF_WITH_PREPROCESSING || - cpi->oxcf.tuning == AOM_TUNE_VMAF_WITHOUT_PREPROCESSING || - cpi->oxcf.tuning == AOM_TUNE_VMAF_MAX_GAIN) { - av1_set_quantizer(cm, cpi->oxcf.qm_minlevel, cpi->oxcf.qm_maxlevel, + if (oxcf->tuning == AOM_TUNE_VMAF_WITH_PREPROCESSING || + oxcf->tuning == AOM_TUNE_VMAF_WITHOUT_PREPROCESSING || + oxcf->tuning == AOM_TUNE_VMAF_MAX_GAIN) { + av1_set_quantizer(cm, q_cfg->qm_minlevel, q_cfg->qm_maxlevel, av1_get_vmaf_base_qindex(cpi, q), - cpi->oxcf.enable_chroma_deltaq); + q_cfg->enable_chroma_deltaq); } else { #endif - av1_set_quantizer(cm, cpi->oxcf.qm_minlevel, cpi->oxcf.qm_maxlevel, q, - cpi->oxcf.enable_chroma_deltaq); + av1_set_quantizer(cm, q_cfg->qm_minlevel, q_cfg->qm_maxlevel, q, + q_cfg->enable_chroma_deltaq); #if CONFIG_TUNE_VMAF } #endif - av1_set_speed_features_qindex_dependent(cpi, cpi->oxcf.speed); + av1_set_speed_features_qindex_dependent(cpi, oxcf->speed); - if (cpi->oxcf.deltaq_mode != NO_DELTA_Q) + if (q_cfg->deltaq_mode != NO_DELTA_Q) av1_init_quantizer(&cpi->enc_quant_dequant_params, &cm->quant_params, cm->seq_params.bit_depth); @@ -3044,9 +3049,9 @@ av1_setup_frame_contexts(cm); } - if (cpi->oxcf.aq_mode == VARIANCE_AQ) { + if (q_cfg->aq_mode == VARIANCE_AQ) { av1_vaq_frame_setup(cpi); - } else if (cpi->oxcf.aq_mode == COMPLEXITY_AQ) { + } else if (q_cfg->aq_mode == COMPLEXITY_AQ) { av1_setup_in_frame_q_adj(cpi); } @@ -3105,8 +3110,8 @@ // to recode. const int do_dummy_pack = (cpi->sf.hl_sf.recode_loop >= ALLOW_RECODE_KFARFGF && - cpi->oxcf.rc_cfg.mode != AOM_Q) || - cpi->oxcf.rc_cfg.min_cr > 0; + oxcf->rc_cfg.mode != AOM_Q) || + oxcf->rc_cfg.min_cr > 0; if (do_dummy_pack) { finalize_encoded_frame(cpi); int largest_tile_id = 0; // Output from bitstream: unused here
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h index 6546b87..0b6b358 100644 --- a/av1/encoder/encoder.h +++ b/av1/encoder/encoder.h
@@ -543,6 +543,31 @@ bool enable_onesided_comp; } RefFrameCfg; +typedef struct { + // List of QP offsets for: keyframe, ALTREF, and 3 levels of internal ARFs. + // If any of these values are negative, fixed offsets are disabled. + // Uses internal q range. + double fixed_qp_offsets[FIXED_QP_OFFSET_COUNT]; + // If true, encoder will use fixed QP offsets, that are either: + // - Given by the user, and stored in 'fixed_qp_offsets' array, OR + // - Picked automatically from cq_level. + int use_fixed_qp_offsets; + // Indicates the minimum flatness of the quantization matrix. + int qm_minlevel; + // Indicates the maximum flatness of the quantization matrix. + int qm_maxlevel; + // Indicates if adaptive quantize_b should be enabled. + int quant_b_adapt; + // Indicates the Adaptive Quantization mode to be used. + AQ_MODE aq_mode; + // Indicates the delta q mode to be used. + DELTAQ_MODE deltaq_mode; + // Indicates if delta quantization should be enabled in chroma planes. + bool enable_chroma_deltaq; + // Indicates if encoding with quantization matrices should be enabled. + bool using_qm; +} QuantizationCfg; + typedef struct AV1EncoderConfig { BITSTREAM_PROFILE profile; aom_bit_depth_t bit_depth; // Codec bit-depth. @@ -573,23 +598,17 @@ int drop_frames_water_mark; // controlling quality - int enable_chroma_deltaq; - AQ_MODE aq_mode; // Adaptive Quantization mode - DELTAQ_MODE deltaq_mode; int deltalf_mode; int enable_cdef; int enable_restoration; int force_video_mode; int disable_trellis_quant; - int using_qm; - int qm_y; - int qm_u; - int qm_v; - int qm_minlevel; - int qm_maxlevel; unsigned int vbr_corpus_complexity_lap; // 0 indicates corpus complexity vbr // mode is disabled + // Configuration related to Quantization. + QuantizationCfg q_cfg; + // Internal frame size scaling. ResizeCfg resize_cfg; @@ -690,7 +709,6 @@ unsigned int chroma_subsampling_x; unsigned int chroma_subsampling_y; - int quant_b_adapt; // Configuration related to frequency of cost update. CostUpdateFreq cost_upd_freq; @@ -700,14 +718,6 @@ // Bit mask to specify which tier each of the 32 possible operating points // conforms to. unsigned int tier_mask; - // If true, encoder will use fixed QP offsets, that are either: - // - Given by the user, and stored in 'fixed_qp_offsets' array, OR - // - Picked automatically from cq_level. - int use_fixed_qp_offsets; - // List of QP offsets for: keyframe, ALTREF, and 3 levels of internal ARFs. - // If any of these values are negative, fixed offsets are disabled. - // Uses internal q range. - double fixed_qp_offsets[FIXED_QP_OFFSET_COUNT]; const cfg_options_t *encoder_cfg; } AV1EncoderConfig;
diff --git a/av1/encoder/encodetxb.c b/av1/encoder/encodetxb.c index c55863e..1e86128 100644 --- a/av1/encoder/encodetxb.c +++ b/av1/encoder/encodetxb.c
@@ -1786,11 +1786,11 @@ const int rshift = (sharpness + - (cpi->oxcf.aq_mode == VARIANCE_AQ && mbmi->segment_id < 4 + (cpi->oxcf.q_cfg.aq_mode == VARIANCE_AQ && mbmi->segment_id < 4 ? 7 - mbmi->segment_id : 2) + - (cpi->oxcf.aq_mode != VARIANCE_AQ && - cpi->oxcf.deltaq_mode == DELTA_Q_PERCEPTUAL && + (cpi->oxcf.q_cfg.aq_mode != VARIANCE_AQ && + cpi->oxcf.q_cfg.deltaq_mode == DELTA_Q_PERCEPTUAL && cm->delta_q_info.delta_q_present_flag && x->sb_energy_level < 0 ? (3 - x->sb_energy_level) : 0));
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c index 6d5225b..c9128c9 100644 --- a/av1/encoder/firstpass.c +++ b/av1/encoder/firstpass.c
@@ -1093,8 +1093,9 @@ // Do not use periodic key frames. cpi->rc.frames_to_key = INT_MAX; - av1_set_quantizer(cm, cpi->oxcf.qm_minlevel, cpi->oxcf.qm_maxlevel, qindex, - cpi->oxcf.enable_chroma_deltaq); + av1_set_quantizer(cm, cpi->oxcf.q_cfg.qm_minlevel, + cpi->oxcf.q_cfg.qm_maxlevel, qindex, + cpi->oxcf.q_cfg.enable_chroma_deltaq); av1_setup_block_planes(xd, seq_params->subsampling_x, seq_params->subsampling_y, num_planes);
diff --git a/av1/encoder/nonrd_pickmode.c b/av1/encoder/nonrd_pickmode.c index 3d45e27..e97ded0 100644 --- a/av1/encoder/nonrd_pickmode.c +++ b/av1/encoder/nonrd_pickmode.c
@@ -470,7 +470,7 @@ else tx_size = TX_8X8; - if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && + if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ && cyclic_refresh_segment_id_boosted(xd->mi[0]->segment_id)) tx_size = TX_8X8; else if (tx_size > TX_16X16)
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c index dbcdd99..27abfb2 100644 --- a/av1/encoder/pass2_strategy.c +++ b/av1/encoder/pass2_strategy.c
@@ -1365,7 +1365,7 @@ const GFConfig *const gf_cfg = &oxcf->gf_cfg; int target; - if (oxcf->aq_mode == CYCLIC_REFRESH_AQ) { + if (oxcf->q_cfg.aq_mode == CYCLIC_REFRESH_AQ) { av1_cyclic_refresh_set_golden_update(cpi); } else { rc->baseline_gf_interval = rc->gf_intervals[rc->cur_gf_index];
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c index 8307750..b0edce3 100644 --- a/av1/encoder/ratectrl.c +++ b/av1/encoder/ratectrl.c
@@ -502,7 +502,7 @@ // Work out how big we would have expected the frame to be at this Q given // the current correction factor. // Stay in double to avoid int overflow when values are large - if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cpi->common.seg.enabled) { + if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ && cpi->common.seg.enabled) { projected_size_based_on_q = av1_cyclic_refresh_estimate_bits_at_q(cpi, rate_correction_factor); } else { @@ -574,7 +574,7 @@ const AV1_COMP *cpi, double correction_factor, int best_qindex, int worst_qindex) { - const int use_cyclic_refresh = cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && + const int use_cyclic_refresh = cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ && cpi->cyclic_refresh->apply_cyclic_refresh; // Find 'qindex' based on 'desired_bits_per_mb'. @@ -936,7 +936,7 @@ * * The q index offsets are fixed in the sense that they are independent of the * video content. The offsets for each pyramid level are taken from - * \c oxcf->fixed_qp_offsets array. + * \c oxcf->q_cfg.fixed_qp_offsets array. * * \ingroup rate_control * \param[in] oxcf Top level encoder configuration @@ -955,7 +955,7 @@ const GF_GROUP *const gf_group, int gf_index, int cq_level, int bit_depth) { - assert(oxcf->use_fixed_qp_offsets); + assert(oxcf->q_cfg.use_fixed_qp_offsets); assert(oxcf->rc_cfg.mode == AOM_Q); const FRAME_UPDATE_TYPE update_type = gf_group->update_type[gf_index]; @@ -977,12 +977,12 @@ return cq_level; // Directly Return worst quality allowed. } assert(offset_idx >= 0 && offset_idx < FIXED_QP_OFFSET_COUNT); - assert(oxcf->fixed_qp_offsets[offset_idx] >= 0); + assert(oxcf->q_cfg.fixed_qp_offsets[offset_idx] >= 0); // Get qindex offset, by first converting to 'q' and then back. const double q_val_orig = av1_convert_qindex_to_q(cq_level, bit_depth); const double q_val_target = - AOMMAX(q_val_orig - oxcf->fixed_qp_offsets[offset_idx], 0.0); + AOMMAX(q_val_orig - oxcf->q_cfg.fixed_qp_offsets[offset_idx], 0.0); const int delta_qindex = av1_compute_qdelta(rc, q_val_orig, q_val_target, bit_depth); return AOMMAX(cq_level + delta_qindex, 0); @@ -1028,7 +1028,7 @@ cm->superres_scale_denominator); const int bit_depth = cm->seq_params.bit_depth; - if (oxcf->use_fixed_qp_offsets) { + if (oxcf->q_cfg.use_fixed_qp_offsets) { return get_q_using_fixed_offsets(oxcf, rc, gf_group, gf_index, cq_level, bit_depth); } @@ -1510,7 +1510,7 @@ cm->superres_scale_denominator); const int bit_depth = cm->seq_params.bit_depth; - if (oxcf->use_fixed_qp_offsets) { + if (oxcf->q_cfg.use_fixed_qp_offsets) { return get_q_using_fixed_offsets(oxcf, rc, gf_group, gf_group->index, cq_level, bit_depth); } @@ -2255,7 +2255,7 @@ if ((resize_pending || rc->high_source_sad || rc->frames_till_gf_update_due == 0) && cpi->svc.temporal_layer_id == 0 && cpi->svc.spatial_layer_id == 0) { - if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) + if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ) av1_cyclic_refresh_set_golden_update(cpi); else rc->baseline_gf_interval = MAX_GF_INTERVAL;
diff --git a/av1/encoder/svc_layercontext.c b/av1/encoder/svc_layercontext.c index 81529a1..b21997f 100644 --- a/av1/encoder/svc_layercontext.c +++ b/av1/encoder/svc_layercontext.c
@@ -166,7 +166,7 @@ cpi->rc.frames_to_key = old_frame_to_key; // For spatial-svc, allow cyclic-refresh to be applied on the spatial layers, // for the base temporal layer. - if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && + if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ && svc->number_spatial_layers > 1 && svc->temporal_layer_id == 0) { CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; swap_ptr(&cr->map, &lc->map); @@ -204,7 +204,7 @@ if (svc->spatial_layer_id == 0) svc->base_framerate = cpi->framerate; // For spatial-svc, allow cyclic-refresh to be applied on the spatial layers, // for the base temporal layer. - if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && + if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ && cpi->svc.number_spatial_layers > 1 && svc->temporal_layer_id == 0) { CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; signed char *temp = lc->map;
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c index a43af38..4d4df7d 100644 --- a/av1/encoder/tpl_model.c +++ b/av1/encoder/tpl_model.c
@@ -1210,7 +1210,7 @@ if (!is_frame_tpl_eligible(cpi)) return; if (tpl_idx >= MAX_TPL_FRAME_IDX) return; if (cpi->superres_mode != AOM_SUPERRES_NONE) return; - if (cpi->oxcf.aq_mode != NO_AQ) return; + if (cpi->oxcf.q_cfg.aq_mode != NO_AQ) return; const int bsize_base = BLOCK_16X16; const int num_mi_w = mi_size_wide[bsize_base];
diff --git a/av1/encoder/tx_search.c b/av1/encoder/tx_search.c index 344d370..7b6a46e 100644 --- a/av1/encoder/tx_search.c +++ b/av1/encoder/tx_search.c
@@ -1117,7 +1117,7 @@ ? (USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B : AV1_XFORM_QUANT_FP) : AV1_XFORM_QUANT_FP, - cpi->oxcf.quant_b_adapt, &quant_param_intra); + cpi->oxcf.q_cfg.quant_b_adapt, &quant_param_intra); av1_setup_qmatrix(&cm->quant_params, xd, plane, tx_size, best_tx_type, &quant_param_intra); av1_xform_quant(x, plane, block, blk_row, blk_col, plane_bsize, @@ -1388,7 +1388,7 @@ QUANT_PARAM quant_param; TxfmParam txfm_param; av1_setup_xform(cm, x, tx_size, DCT_DCT, &txfm_param); - av1_setup_quant(tx_size, 1, AV1_XFORM_QUANT_B, cpi->oxcf.quant_b_adapt, + av1_setup_quant(tx_size, 1, AV1_XFORM_QUANT_B, cpi->oxcf.q_cfg.quant_b_adapt, &quant_param); int tx_type; // to ensure we can try ones even outside of ext_tx_set of current block @@ -1503,7 +1503,7 @@ TxfmParam txfm_param; QUANT_PARAM quant_param; av1_setup_xform(cm, x, tx_size, DCT_DCT, &txfm_param); - av1_setup_quant(tx_size, 1, AV1_XFORM_QUANT_B, cpi->oxcf.quant_b_adapt, + av1_setup_quant(tx_size, 1, AV1_XFORM_QUANT_B, cpi->oxcf.q_cfg.quant_b_adapt, &quant_param); for (int idx = 0; idx < TX_TYPES; idx++) { @@ -2264,7 +2264,7 @@ skip_trellis ? (USE_B_QUANT_NO_TRELLIS ? AV1_XFORM_QUANT_B : AV1_XFORM_QUANT_FP) : AV1_XFORM_QUANT_FP, - cpi->oxcf.quant_b_adapt, &quant_param); + cpi->oxcf.q_cfg.quant_b_adapt, &quant_param); // Iterate through all transform type candidates. for (int idx = 0; idx < TX_TYPES; ++idx) { @@ -2282,8 +2282,8 @@ av1_xform(x, plane, block, blk_row, blk_col, plane_bsize, &txfm_param); skip_trellis_based_on_satd[tx_type] = skip_trellis_opt_based_on_satd( - x, &quant_param, plane, block, tx_size, cpi->oxcf.quant_b_adapt, qstep, - txfm_params->coeff_opt_satd_threshold, skip_trellis); + x, &quant_param, plane, block, tx_size, cpi->oxcf.q_cfg.quant_b_adapt, + qstep, txfm_params->coeff_opt_satd_threshold, skip_trellis); av1_quant(x, plane, block, &txfm_param, &quant_param);
diff --git a/av1/encoder/var_based_part.c b/av1/encoder/var_based_part.c index 4b94a29..082bc31 100644 --- a/av1/encoder/var_based_part.c +++ b/av1/encoder/var_based_part.c
@@ -848,7 +848,7 @@ int variance4x4downsample[64]; const int segment_id = xd->mi[0]->segment_id; - if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled && + if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled && cyclic_refresh_segment_id_boosted(segment_id) && cpi->sf.rt_sf.use_nonrd_pick_mode) { int q = av1_get_qindex(&cm->seg, segment_id, cm->quant_params.base_qindex);