Add option to pick QP offsets using base qindex

* Command-line opion '--use-fixed-qp-offsets=2' can be used to enable this mode.When the mode is enabled, the qOffset factors are not fixed and for each temporal level are computed based on the base qindex level.

Change-Id: Ia7d411d765054396969becf75482488a2b3c3584
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index fd56eba..9c3c69f 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -650,7 +650,11 @@
   }
 
   if (cfg->rc_end_usage == AOM_Q) {
+#if CONFIG_QBASED_QP_OFFSET
+    RANGE_CHECK_HI(cfg, use_fixed_qp_offsets, 2);
+#else
     RANGE_CHECK_HI(cfg, use_fixed_qp_offsets, 1);
+#endif  // CONFIG_QBASED_QP_OFFSET
     for (int i = 0; i < FIXED_QP_OFFSET_COUNT; ++i) {
       RANGE_CHECK_HI(cfg, fixed_qp_offsets[i], 255);
     }
@@ -946,13 +950,49 @@
   return (base_q_val - new_q_val);
 }
 
+#if CONFIG_QBASED_QP_OFFSET
+static double get_modeled_qp_offset(int qp, int level, int bit_depth,
+                                    int q_based_qp_offsets) {
+#else
 static double get_modeled_qp_offset(int qp, int level, int bit_depth) {
+#endif  // CONFIG_QBASED_QP_OFFSET
   // 76% for keyframe was derived empirically.
   // 60% similar to rc_pick_q_and_bounds_one_pass_vbr() for Q mode ARF.
   // Rest derived similar to rc_pick_q_and_bounds_two_pass()
   static const int percents[FIXED_QP_OFFSET_COUNT] = { 76, 60, 30, 15, 8, 4 };
   const double q_val = av1_convert_qindex_to_q(qp, bit_depth);
+
+#if CONFIG_QBASED_QP_OFFSET
+  double factor = percents[level];
+  if (q_based_qp_offsets) {
+    // At higher end of QP the slope of quant step-size grows exponentially,
+    // captured by qp_threshold.
+#if CONFIG_EXTQUANT
+    const int max_q = (bit_depth == AOM_BITS_8)
+                          ? MAXQ_8_BITS
+                          : (bit_depth == AOM_BITS_10) ? MAXQ_10_BITS : MAXQ;
+#else
+    const int max_q = MAXQ;
+#endif  // CONFIG_EXTQUANT
+
+    const int qp_threshold = (max_q * 7) / 10;
+    if (qp < qp_threshold) {
+      factor = AOMMIN((cbrt(q_val * 4) / 8) * 100, 76);
+      if (level == 1) {
+        factor = (factor * 7) / 8;
+      } else if (level == 2) {
+        factor = factor / 2;
+      } else if (level == 3) {
+        factor = factor / 4;
+      } else if (level == 4) {
+        factor = factor / 8;
+      }
+    }
+  }
+  return q_val * factor / 100;
+#else
   return q_val * percents[level] / 100;
+#endif  // CONFIG_QBASED_QP_OFFSET
 }
 
 // update_config parameter is used to indicate whether extra command line
@@ -1141,14 +1181,23 @@
   q_cfg->deltaq_mode = extra_cfg->deltaq_mode;
   q_cfg->use_fixed_qp_offsets =
       cfg->use_fixed_qp_offsets && (rc_cfg->mode == AOM_Q);
+#if CONFIG_QBASED_QP_OFFSET
+  q_cfg->q_based_qp_offsets = (q_cfg->use_fixed_qp_offsets == 2) ? 1 : 0;
+#endif  // CONFIG_QBASED_QP_OFFSET
+
   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->qp, cfg->fixed_qp_offsets[i], tool_cfg->bit_depth);
       } else {  // auto-selected qp offset
+#if CONFIG_QBASED_QP_OFFSET
+        q_cfg->fixed_qp_offsets[i] = get_modeled_qp_offset(
+            rc_cfg->qp, i, tool_cfg->bit_depth, q_cfg->q_based_qp_offsets);
+#else
         q_cfg->fixed_qp_offsets[i] =
             get_modeled_qp_offset(rc_cfg->qp, i, tool_cfg->bit_depth);
+#endif  // CONFIG_QBASED_QP_OFFSET
       }
     } else {
       q_cfg->fixed_qp_offsets[i] = -1.0;
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 2ae07ea..903c8d7 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -695,10 +695,22 @@
   // List of QP offsets for: keyframe, ALTREF, and 3 levels of internal ARFs.
   // If any of these values are negative, fixed offsets are disabled.
   double fixed_qp_offsets[FIXED_QP_OFFSET_COUNT];
-  // If true, encoder will use fixed QP offsets, that are either:
+  // If the value is 0 (default), encoder may not use fixed QP offsets.
+  // If the value is 1, encoder will use fixed QP offsets, that are
+  // either:
   // - Given by the user, and stored in 'fixed_qp_offsets' array, OR
-  // - Picked automatically from qp.
+  // - Picked automatically from qp using a fixed factor.
+  // If the value is 2, encoder will use fixed QP offsets that are :
+  // - Derived from qp and has variable factors across Temporal levels as a fn.
+  // of q-step.
+  // TODO(krapaka): extend the derivation of factors also based on operating
+  // configuration such as random access and low-delay.
   int use_fixed_qp_offsets;
+#if CONFIG_QBASED_QP_OFFSET
+  // It true, the offset factor depends on the QP value
+  // else fixed value is used.
+  int q_based_qp_offsets;
+#endif  // CONFIG_QBASED_QP_OFFSET
   // Indicates the minimum flatness of the quantization matrix.
   int qm_minlevel;
   // Indicates the maximum flatness of the quantization matrix.
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index eb95ae2..e3d5fe6 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -1069,7 +1069,12 @@
                                      const RATE_CONTROL *const rc,
                                      const GF_GROUP *const gf_group,
                                      int gf_index, int qp, int bit_depth) {
+#if CONFIG_QBASED_QP_OFFSET
+  assert(oxcf->q_cfg.use_fixed_qp_offsets == 1 ||
+         oxcf->q_cfg.use_fixed_qp_offsets == 2);
+#else
   assert(oxcf->q_cfg.use_fixed_qp_offsets);
+#endif  // CONFIG_QBASED_QP_OFFSET
   assert(oxcf->rc_cfg.mode == AOM_Q);
   const FRAME_UPDATE_TYPE update_type = gf_group->update_type[gf_index];
 
diff --git a/build/cmake/aom_config_defaults.cmake b/build/cmake/aom_config_defaults.cmake
index c7a149b..0336cf7 100644
--- a/build/cmake/aom_config_defaults.cmake
+++ b/build/cmake/aom_config_defaults.cmake
@@ -160,6 +160,8 @@
 set_aom_config_var(CONFIG_TMVP_IMPROVEMENT 1 "Enable TMVP improvement")
 set_aom_config_var(
   CONFIG_CCSO 1 "AV2 experiment flag to enable cross component sample offset.")
+set_aom_config_var(CONFIG_QBASED_QP_OFFSET 0
+                   "AV2 experiment flag to adjust q_offset based on QP.")
 #
 # Variables in this section control optional features of the build system.
 #