Split delta_lf from delta_q mode and refactor

Splits delta_lf mode from delta q mode as a separate
control and command line option. Also, makes space
for a new delta q mode based on prediction efficiency
along with the existing mode based on spatial perceptual
characteristics.

Change-Id: I594e5665ae00a0c683f5340fe0469e49241ebab3
diff --git a/aom/aomcx.h b/aom/aomcx.h
index 2c4309a..2cf4ad7 100644
--- a/aom/aomcx.h
+++ b/aom/aomcx.h
@@ -990,16 +990,23 @@
 
   /*!\brief Codec control function to set the delta q mode
    *
-   * AV1 has a segment based feature that allows encoder to adaptively change
-   * quantization parameter for each segment within a frame to improve the
-   * subjective quality. the delta q mode is added on top of segment based
-   * feature, and allows control per 64x64 q and lf delta.This control makes
-   * encoder operate in one of the several DELTA_Q_modes supported.
+   * AV1 supports a delta q mode feature, that allows modulating q per
+   * superblock. This control makes encoder operate in one of several
+   * DELTA_Q_modes supported:
+   * 0: Not Supported
+   * 1: Use modulation to maximize objective quality
+   * 2: Use modulation to maximize perceptual quality
    *
    * By default, encoder operates with DELTAQ_Mode 0(deltaq signaling off).
    */
   AV1E_SET_DELTAQ_MODE,
 
+  /*!\brief Codec control function to turn on/off loopfilter modulation
+   * when delta q modulation is enabled. Note AV1 only supports loopfilter
+   * modulation when delta q modulation is enabled as well.
+   */
+  AV1E_SET_DELTALF_MODE,
+
   /*!\brief Codec control function to set the single tile decoding mode to 0 or
    * 1.
    *
@@ -1406,6 +1413,9 @@
 AOM_CTRL_USE_TYPE(AV1E_SET_DELTAQ_MODE, unsigned int)
 #define AOM_CTRL_AV1E_SET_DELTAQ_MODE
 
+AOM_CTRL_USE_TYPE(AV1E_SET_DELTALF_MODE, unsigned int)
+#define AOM_CTRL_AV1E_SET_DELTALF_MODE
+
 AOM_CTRL_USE_TYPE(AV1E_SET_FRAME_PERIODIC_BOOST, unsigned int)
 #define AOM_CTRL_AV1E_SET_FRAME_PERIODIC_BOOST
 
diff --git a/apps/aomenc.c b/apps/aomenc.c
index 3663dff..cfbf8e2 100644
--- a/apps/aomenc.c
+++ b/apps/aomenc.c
@@ -629,9 +629,12 @@
     NULL, "aq-mode", 1,
     "Adaptive quantization mode (0: off (default), 1: variance 2: complexity, "
     "3: cyclic refresh)");
-static const arg_def_t deltaq_mode = ARG_DEF(
-    NULL, "deltaq-mode", 1,
-    "Delta qindex mode (0: off (default), 1: deltaq 2: deltaq + deltalf)");
+static const arg_def_t deltaq_mode =
+    ARG_DEF(NULL, "deltaq-mode", 1,
+            "Delta qindex mode (0: off (default), 1: deltaq pred efficiency, "
+            "2: deltaq perceptual)");
+static const arg_def_t deltalf_mode = ARG_DEF(
+    NULL, "delta-lf-mode", 1, "Enable delta-lf-mode (0: off (default), 1: on)");
 static const arg_def_t frame_periodic_boost =
     ARG_DEF(NULL, "frame-boost", 1,
             "Enable frame periodic boost (0: off (default), 1: on)");
@@ -840,6 +843,7 @@
                                        &error_resilient_mode,
                                        &aq_mode,
                                        &deltaq_mode,
+                                       &deltalf_mode,
                                        &frame_periodic_boost,
                                        &noise_sens,
                                        &tune_content,
@@ -939,6 +943,7 @@
                                         AV1E_SET_ERROR_RESILIENT_MODE,
                                         AV1E_SET_AQ_MODE,
                                         AV1E_SET_DELTAQ_MODE,
+                                        AV1E_SET_DELTALF_MODE,
                                         AV1E_SET_FRAME_PERIODIC_BOOST,
                                         AV1E_SET_NOISE_SENSITIVITY,
                                         AV1E_SET_TUNE_CONTENT,
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index e9a9b82..398d672 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -72,6 +72,7 @@
   int enable_dual_filter;
   AQ_MODE aq_mode;
   DELTAQ_MODE deltaq_mode;
+  int deltalf_mode;
   unsigned int frame_periodic_boost;
   aom_bit_depth_t bit_depth;
   aom_tune_content content;
@@ -186,6 +187,7 @@
   1,                            // enable dual filter
   NO_AQ,                        // aq_mode
   NO_DELTA_Q,                   // deltaq_mode
+  0,                            // delta lf mode
   0,                            // frame_periodic_delta_q
   AOM_BITS_8,                   // Bit depth
   AOM_CONTENT_DEFAULT,          // content
@@ -324,7 +326,8 @@
   RANGE_CHECK_HI(cfg, rc_min_quantizer, cfg->rc_max_quantizer);
   RANGE_CHECK_BOOL(extra_cfg, lossless);
   RANGE_CHECK_HI(extra_cfg, aq_mode, AQ_MODE_COUNT - 1);
-  RANGE_CHECK_HI(extra_cfg, deltaq_mode, DELTAQ_MODE_COUNT - 1);
+  RANGE_CHECK_HI(extra_cfg, deltaq_mode, DELTA_Q_MODE_COUNT - 1);
+  RANGE_CHECK_HI(extra_cfg, deltalf_mode, 1);
   RANGE_CHECK_HI(extra_cfg, frame_periodic_boost, 1);
   RANGE_CHECK_HI(cfg, g_usage, 1);
   RANGE_CHECK_HI(cfg, g_threads, MAX_NUM_THREADS);
@@ -683,9 +686,6 @@
     }
   }
 
-  oxcf->enable_tpl_model =
-      extra_cfg->enable_tpl_model && (oxcf->superres_mode == SUPERRES_NONE);
-
   oxcf->maximum_buffer_size_ms = is_vbr ? 240000 : cfg->rc_buf_sz;
   oxcf->starting_buffer_level_ms = is_vbr ? 60000 : cfg->rc_buf_initial_sz;
   oxcf->optimal_buffer_level_ms = is_vbr ? 60000 : cfg->rc_buf_optimal_sz;
@@ -833,8 +833,23 @@
     oxcf->timing_info_present = 0;
   }
 
+  oxcf->enable_tpl_model =
+      extra_cfg->enable_tpl_model && (oxcf->superres_mode == SUPERRES_NONE);
+
   oxcf->aq_mode = extra_cfg->aq_mode;
   oxcf->deltaq_mode = extra_cfg->deltaq_mode;
+  // Turn on tpl model for deltaq_mode == DELTA_Q_OBJECTIVE and no
+  // superres. If superres is being used on the other hand, turn
+  // delta_q off.
+  if (oxcf->deltaq_mode == DELTA_Q_OBJECTIVE) {
+    if (oxcf->superres_mode == SUPERRES_NONE)
+      oxcf->enable_tpl_model = 1;
+    else
+      oxcf->deltaq_mode = NO_DELTA_Q;
+  }
+
+  oxcf->deltalf_mode =
+      (oxcf->deltaq_mode != NO_DELTA_Q) && extra_cfg->deltalf_mode;
 
   oxcf->save_as_annexb = cfg->save_as_annexb;
 
@@ -1507,6 +1522,13 @@
   return update_extra_cfg(ctx, &extra_cfg);
 }
 
+static aom_codec_err_t ctrl_set_deltalf_mode(aom_codec_alg_priv_t *ctx,
+                                             va_list args) {
+  struct av1_extracfg extra_cfg = ctx->extra_cfg;
+  extra_cfg.deltalf_mode = CAST(AV1E_SET_DELTALF_MODE, args);
+  return update_extra_cfg(ctx, &extra_cfg);
+}
+
 static aom_codec_err_t ctrl_set_min_gf_interval(aom_codec_alg_priv_t *ctx,
                                                 va_list args) {
   struct av1_extracfg extra_cfg = ctx->extra_cfg;
@@ -2231,6 +2253,7 @@
   { AV1E_SET_COEFF_COST_UPD_FREQ, ctrl_set_coeff_cost_upd_freq },
   { AV1E_SET_MODE_COST_UPD_FREQ, ctrl_set_mode_cost_upd_freq },
   { AV1E_SET_DELTAQ_MODE, ctrl_set_deltaq_mode },
+  { AV1E_SET_DELTALF_MODE, ctrl_set_deltalf_mode },
   { AV1E_SET_FRAME_PERIODIC_BOOST, ctrl_set_frame_periodic_boost },
   { AV1E_SET_TUNE_CONTENT, ctrl_set_tune_content },
   { AV1E_SET_CDF_UPDATE_MODE, ctrl_set_cdf_update_mode },
diff --git a/av1/encoder/aq_variance.c b/av1/encoder/aq_variance.c
index d572948..9b58363 100644
--- a/av1/encoder/aq_variance.c
+++ b/av1/encoder/aq_variance.c
@@ -185,7 +185,7 @@
   int rate_level;
   const AV1_COMMON *const cm = &cpi->common;
 
-  if (DELTAQ_MODULATION == 1) {
+  if (DELTA_Q_PERCEPTUAL_MODULATION == 1) {
     ENERGY_IN_BOUNDS(block_var_level);
     rate_level = SEGMENT_ID(block_var_level);
   } else {
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index f079d90..61e1d2b 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -634,7 +634,7 @@
     x->rdmult = x->cb_rdmult;
   }
 
-  if (deltaq_mode > 0) x->rdmult = set_deltaq_rdmult(cpi, xd);
+  if (deltaq_mode != NO_DELTA_Q) x->rdmult = set_deltaq_rdmult(cpi, xd);
 
   // Find best coding mode & reconstruct the MB so it is available
   // as a predictor for MBs that follow in the SB
@@ -1486,7 +1486,7 @@
   mbmi->partition = partition;
   update_state(cpi, tile_data, td, ctx, mi_row, mi_col, bsize, dry_run);
   if (cpi->oxcf.enable_tpl_model && cpi->oxcf.aq_mode == NO_AQ &&
-      cpi->oxcf.deltaq_mode == 0) {
+      cpi->oxcf.deltaq_mode == NO_DELTA_Q) {
     x->rdmult = x->cb_rdmult;
   }
 
@@ -4250,7 +4250,7 @@
   av1_setup_src_planes(x, cpi->source, mi_row, mi_col, num_planes, sb_size);
 
   int offset_qindex;
-  if (DELTAQ_MODULATION == 1) {
+  if (DELTA_Q_PERCEPTUAL_MODULATION == 1) {
     const int block_wavelet_energy_level =
         av1_block_wavelet_energy_level(cpi, x, sb_size);
     x->sb_energy_level = block_wavelet_energy_level;
@@ -4275,7 +4275,7 @@
   set_offsets(cpi, tile_info, x, mi_row, mi_col, sb_size);
   xd->mi[0]->current_qindex = current_qindex;
   av1_init_plane_quantizers(cpi, x, xd->mi[0]->segment_id);
-  if (cpi->oxcf.deltaq_mode == DELTA_Q_LF) {
+  if (cpi->oxcf.deltaq_mode != NO_DELTA_Q && cpi->oxcf.deltalf_mode) {
     const int lfmask = ~(delta_q_info->delta_lf_res - 1);
     const int delta_lf_from_base =
         ((offset_qindex / 2 + delta_q_info->delta_lf_res / 2) & lfmask);
@@ -4707,7 +4707,7 @@
       const int orig_rdmult = cpi->rd.RDMULT;
       x->cb_rdmult = orig_rdmult;
       if (cpi->twopass.gf_group.index > 0 && cpi->oxcf.enable_tpl_model &&
-          cpi->oxcf.aq_mode == NO_AQ && cpi->oxcf.deltaq_mode == 0) {
+          cpi->oxcf.aq_mode == NO_AQ && cpi->oxcf.deltaq_mode == NO_DELTA_Q) {
         const int dr =
             get_rdmult_delta(cpi, BLOCK_128X128, mi_row, mi_col, orig_rdmult);
 
@@ -5332,7 +5332,8 @@
   // 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 = cpi->oxcf.deltaq_mode != NO_DELTA_Q;
-  cm->delta_q_info.delta_lf_present_flag = cpi->oxcf.deltaq_mode == DELTA_Q_LF;
+  cm->delta_q_info.delta_lf_present_flag =
+      cpi->oxcf.deltaq_mode != NO_DELTA_Q && cpi->oxcf.deltalf_mode;
   cm->delta_q_info.delta_lf_multi = DEFAULT_DELTA_LF_MULTI;
   // update delta_q_present_flag and delta_lf_present_flag based on
   // base_qindex
diff --git a/av1/encoder/encodeframe.h b/av1/encoder/encodeframe.h
index 3b1730d..e4c4841 100644
--- a/av1/encoder/encodeframe.h
+++ b/av1/encoder/encodeframe.h
@@ -20,7 +20,9 @@
 extern "C" {
 #endif
 
-#define DELTAQ_MODULATION 1  // 0: variance based, 1: wavelet AC energy based
+#define DELTA_Q_PERCEPTUAL_MODULATION \
+  1  // 0: variance based
+     // 1: wavelet AC energy based
 
 struct macroblock;
 struct yv12_buffer_config;
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index bf02394..edb9507 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -110,9 +110,9 @@
 } UENUM1BYTE(AQ_MODE);
 enum {
   NO_DELTA_Q = 0,
-  DELTA_Q_ONLY = 1,
-  DELTA_Q_LF = 2,
-  DELTAQ_MODE_COUNT  // This should always be the last member of the enum
+  DELTA_Q_OBJECTIVE = 1,   // Modulation to improve objective quality
+  DELTA_Q_PERCEPTUAL = 2,  // Modulation to improve perceptual quality
+  DELTA_Q_MODE_COUNT       // This should always be the last member of the enum
 } UENUM1BYTE(DELTAQ_MODE);
 
 enum {
@@ -237,6 +237,7 @@
   int cq_level;
   AQ_MODE aq_mode;  // Adaptive Quantization mode
   DELTAQ_MODE deltaq_mode;
+  int deltalf_mode;
   int enable_cdef;
   int enable_restoration;
   int enable_obmc;
diff --git a/av1/encoder/encodetxb.c b/av1/encoder/encodetxb.c
index 37f4bb9..ee30e63 100644
--- a/av1/encoder/encodetxb.c
+++ b/av1/encoder/encodetxb.c
@@ -1690,15 +1690,15 @@
   const LV_MAP_EOB_COST *txb_eob_costs =
       &x->eob_costs[eob_multi_size][plane_type];
 
-  const int rshift =
-      (sharpness +
-       (cpi->oxcf.aq_mode == VARIANCE_AQ && mbmi->segment_id < 4
-            ? 7 - mbmi->segment_id
-            : 2) +
-       (cpi->oxcf.aq_mode != VARIANCE_AQ &&
-                cpi->oxcf.deltaq_mode > NO_DELTA_Q && x->sb_energy_level < 0
-            ? (3 - x->sb_energy_level)
-            : 0));
+  const int rshift = (sharpness +
+                      (cpi->oxcf.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 &&
+                               x->sb_energy_level < 0
+                           ? (3 - x->sb_energy_level)
+                           : 0));
   const int64_t rdmult =
       (((int64_t)x->rdmult *
         (plane_rd_mult[is_inter][plane_type] << (2 * (xd->bd - 8)))) +
diff --git a/av1/encoder/picklpf.c b/av1/encoder/picklpf.c
index aca089c..bc222f1 100644
--- a/av1/encoder/picklpf.c
+++ b/av1/encoder/picklpf.c
@@ -57,7 +57,7 @@
   if (plane == 0 && dir == 0) filter_level[1] = cm->lf.filter_level[1];
   if (plane == 0 && dir == 1) filter_level[0] = cm->lf.filter_level[0];
 
-  // set base filters for use of get_filter_level when in DELTA_Q_LF mode
+  // set base filters for use of get_filter_level when in DELTA_LF mode
   switch (plane) {
     case 0:
       cm->lf.filter_level[0] = filter_level[0];