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);