LOOPFILTER_LEVEL: add flexibility for EXT_DELTA_Q

When experiment LOOPFILTER_LEVEL is on, there're four base filter levels
for each frame. This patch enables one to use one delta or four deltas
to update corresponding filter levels for each superblock in
EXT_DELTA_Q.

1 bit per frame is sent through bitstream to select one or four deltas.
Now, we hard code to use one delta.

Change-Id: I9c61a035064fa81878b0575ad21664e2b22a6a45
diff --git a/av1/common/av1_loopfilter.c b/av1/common/av1_loopfilter.c
index a3c3527..7eb0f8c 100644
--- a/av1/common/av1_loopfilter.c
+++ b/av1/common/av1_loopfilter.c
@@ -651,8 +651,13 @@
 #endif  // CONFIG_SUPERTX
   if (cm->delta_lf_present_flag) {
 #if CONFIG_LOOPFILTER_LEVEL
-    const int delta_lf_idx = delta_lf_id_lut[plane][dir_idx];
-    const int delta_lf = mbmi->curr_delta_lf[delta_lf_idx];
+    int delta_lf;
+    if (cm->delta_lf_multi) {
+      const int delta_lf_idx = delta_lf_id_lut[plane][dir_idx];
+      delta_lf = mbmi->curr_delta_lf[delta_lf_idx];
+    } else {
+      delta_lf = mbmi->current_delta_lf_from_base;
+    }
     int lvl_seg =
         clamp(delta_lf + cm->lf.filter_level[dir_idx], 0, MAX_LOOP_FILTER);
 #else
diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c
index fecafe7..c10a3d3 100644
--- a/av1/common/entropymode.c
+++ b/av1/common/entropymode.c
@@ -1684,23 +1684,23 @@
 };
 #if CONFIG_EXT_DELTA_Q
 #if CONFIG_LOOPFILTER_LEVEL
-static const aom_prob default_delta_lf_probs[FRAME_LF_COUNT][DELTA_LF_PROBS] = {
-  { 220, 220, 220 }, { 220, 220, 220 }, { 220, 220, 220 }, { 220, 220, 220 }
-};
+static const aom_prob
+    default_delta_lf_multi_probs[FRAME_LF_COUNT][DELTA_LF_PROBS] = {
+      { 220, 220, 220 }, { 220, 220, 220 }, { 220, 220, 220 }, { 220, 220, 220 }
+    };
 static const aom_cdf_prob
-    default_delta_lf_cdf[FRAME_LF_COUNT][CDF_SIZE(DELTA_LF_PROBS + 1)] = {
+    default_delta_lf_multi_cdf[FRAME_LF_COUNT][CDF_SIZE(DELTA_LF_PROBS + 1)] = {
       { AOM_ICDF(28160), AOM_ICDF(32120), AOM_ICDF(32677), AOM_ICDF(32768), 0 },
       { AOM_ICDF(28160), AOM_ICDF(32120), AOM_ICDF(32677), AOM_ICDF(32768), 0 },
       { AOM_ICDF(28160), AOM_ICDF(32120), AOM_ICDF(32677), AOM_ICDF(32768), 0 },
       { AOM_ICDF(28160), AOM_ICDF(32120), AOM_ICDF(32677), AOM_ICDF(32768), 0 }
     };
-#else
+#endif  // CONFIG_LOOPFILTER_LEVEL
 static const aom_prob default_delta_lf_probs[DELTA_LF_PROBS] = { 220, 220,
                                                                  220 };
 static const aom_cdf_prob default_delta_lf_cdf[CDF_SIZE(DELTA_LF_PROBS + 1)] = {
   AOM_ICDF(28160), AOM_ICDF(32120), AOM_ICDF(32677), AOM_ICDF(32768), 0
 };
-#endif  // CONFIG_LOOPFILTER_LEVEL
 #endif
 
 /* clang-format off */
@@ -5720,6 +5720,9 @@
 #if CONFIG_EXT_DELTA_Q
   av1_copy(fc->delta_lf_prob, default_delta_lf_probs);
   av1_copy(fc->delta_lf_cdf, default_delta_lf_cdf);
+#if CONFIG_LOOPFILTER_LEVEL
+  av1_copy(fc->delta_lf_multi_cdf, default_delta_lf_multi_cdf);
+#endif  // CONFIG_LOOPFILTER_LEVEL
 #endif
 #if CONFIG_CFL
   av1_copy(fc->cfl_sign_cdf, default_cfl_sign_cdf);
@@ -5952,13 +5955,12 @@
 #if CONFIG_LOOPFILTER_LEVEL
   for (i = 0; i < FRAME_LF_COUNT; ++i)
     for (int j = 0; j < DELTA_LF_PROBS; ++j)
-      fc->delta_lf_prob[i][j] = mode_mv_merge_probs(pre_fc->delta_lf_prob[i][j],
-                                                    counts->delta_lf[i][j]);
-#else
+      fc->delta_lf_multi_prob[i][j] = mode_mv_merge_probs(
+          pre_fc->delta_lf_multi_prob[i][j], counts->delta_lf_multi[i][j]);
+#endif  // CONFIG_LOOPFILTER_LEVEL
   for (i = 0; i < DELTA_LF_PROBS; ++i)
     fc->delta_lf_prob[i] =
         mode_mv_merge_probs(pre_fc->delta_lf_prob[i], counts->delta_lf[i]);
-#endif  // CONFIG_LOOPFILTER_LEVEL
 #endif  // CONFIG_EXT_DELTA_Q
 #if CONFIG_EXT_INTRA
 #if CONFIG_INTRA_INTERP
diff --git a/av1/common/entropymode.h b/av1/common/entropymode.h
index 56ce9b2..fbebf15 100644
--- a/av1/common/entropymode.h
+++ b/av1/common/entropymode.h
@@ -361,10 +361,9 @@
   aom_cdf_prob delta_q_cdf[CDF_SIZE(DELTA_Q_PROBS + 1)];
 #if CONFIG_EXT_DELTA_Q
 #if CONFIG_LOOPFILTER_LEVEL
-  aom_cdf_prob delta_lf_cdf[FRAME_LF_COUNT][CDF_SIZE(DELTA_LF_PROBS + 1)];
-#else
-  aom_cdf_prob delta_lf_cdf[CDF_SIZE(DELTA_LF_PROBS + 1)];
+  aom_cdf_prob delta_lf_multi_cdf[FRAME_LF_COUNT][CDF_SIZE(DELTA_LF_PROBS + 1)];
 #endif  // CONFIG_LOOPFILTER_LEVEL
+  aom_cdf_prob delta_lf_cdf[CDF_SIZE(DELTA_LF_PROBS + 1)];
 #endif
 #if CONFIG_EXT_TX
   aom_cdf_prob intra_ext_tx_cdf[EXT_TX_SETS_INTRA][EXT_TX_SIZES][INTRA_MODES]
@@ -381,10 +380,9 @@
   aom_prob delta_q_prob[DELTA_Q_PROBS];
 #if CONFIG_EXT_DELTA_Q
 #if CONFIG_LOOPFILTER_LEVEL
-  aom_prob delta_lf_prob[FRAME_LF_COUNT][DELTA_LF_PROBS];
-#else
-  aom_prob delta_lf_prob[DELTA_LF_PROBS];
+  aom_prob delta_lf_multi_prob[FRAME_LF_COUNT][DELTA_LF_PROBS];
 #endif  // CONFIG_LOOPFILTER_LEVEL
+  aom_prob delta_lf_prob[DELTA_LF_PROBS];
 #endif
 #if CONFIG_PVQ
   // TODO(any): If PVQ is enabled, most of coefficient related cdf,
@@ -516,10 +514,9 @@
   unsigned int delta_q[DELTA_Q_PROBS][2];
 #if CONFIG_EXT_DELTA_Q
 #if CONFIG_LOOPFILTER_LEVEL
-  unsigned int delta_lf[FRAME_LF_COUNT][DELTA_LF_PROBS][2];
-#else
-  unsigned int delta_lf[DELTA_LF_PROBS][2];
+  unsigned int delta_lf_multi[FRAME_LF_COUNT][DELTA_LF_PROBS][2];
 #endif  // CONFIG_LOOPFILTER_LEVEL
+  unsigned int delta_lf[DELTA_LF_PROBS][2];
 #endif
 #if CONFIG_EXT_TX && CONFIG_RECT_TX
   unsigned int tx_size_implied[TX_SIZES][TX_SIZES];
diff --git a/av1/common/enums.h b/av1/common/enums.h
index 6648138..c40bbd8 100644
--- a/av1/common/enums.h
+++ b/av1/common/enums.h
@@ -86,6 +86,7 @@
 // 4 frame filter levels: y plane vertical, y plane horizontal,
 // u plane, and v plane
 #define FRAME_LF_COUNT 4
+#define DEFAULT_DELTA_LF_MULTI 0
 #endif  // CONFIG_LOOPFILTER_LEVEL
 
 #if CONFIG_LPF_SB
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index 3dbadc7..d42d414 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -513,6 +513,12 @@
   int delta_lf_present_flag;
   // Resolution of delta lf level
   int delta_lf_res;
+#if CONFIG_LOOPFILTER_LEVEL
+  // This is a flag for number of deltas of loop filter level
+  // 0: use 1 delta, for y_vertical, y_horizontal, u, and v
+  // 1: use separate deltas for each filter level
+  int delta_lf_multi;
+#endif  // CONFIG_LOOPFILTER_LEVEL
 #endif
   int num_tg;
 #if CONFIG_REFERENCE_BUFFER
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index a363352..4cb3178 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -5048,6 +5048,9 @@
 #if CONFIG_EXT_DELTA_Q
     cm->delta_lf_res = 1;
     cm->delta_lf_present_flag = 0;
+#if CONFIG_LOOPFILTER_LEVEL
+    cm->delta_lf_multi = 0;
+#endif  // CONFIG_LOOPFILTER_LEVEL
 #endif
     if (segment_quantizer_active == 0 && cm->base_qindex > 0) {
       cm->delta_q_present_flag = aom_rb_read_bit(rb);
@@ -5061,12 +5064,13 @@
       assert(!segment_quantizer_active);
       cm->delta_lf_present_flag = aom_rb_read_bit(rb);
       if (cm->delta_lf_present_flag) {
+        xd->prev_delta_lf_from_base = 0;
+        cm->delta_lf_res = 1 << aom_rb_read_literal(rb, 2);
 #if CONFIG_LOOPFILTER_LEVEL
+        cm->delta_lf_multi = aom_rb_read_bit(rb);
         for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id)
           xd->prev_delta_lf[lf_id] = 0;
 #endif  // CONFIG_LOOPFILTER_LEVEL
-        xd->prev_delta_lf_from_base = 0;
-        cm->delta_lf_res = 1 << aom_rb_read_literal(rb, 2);
       }
 #endif  // CONFIG_EXT_DELTA_Q
     }
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index 7f6e88d..53795b4 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -96,8 +96,14 @@
 
   if ((bsize != BLOCK_64X64 || mbmi->skip == 0) && read_delta_lf_flag) {
 #if CONFIG_LOOPFILTER_LEVEL
-    abs = aom_read_symbol(r, ec_ctx->delta_lf_cdf[lf_id], DELTA_LF_PROBS + 1,
-                          ACCT_STR);
+    if (cm->delta_lf_multi) {
+      assert(lf_id >= 0 && lf_id < FRAME_LF_COUNT);
+      abs = aom_read_symbol(r, ec_ctx->delta_lf_multi_cdf[lf_id],
+                            DELTA_LF_PROBS + 1, ACCT_STR);
+    } else {
+      abs = aom_read_symbol(r, ec_ctx->delta_lf_cdf, DELTA_LF_PROBS + 1,
+                            ACCT_STR);
+    }
 #else
     abs =
         aom_read_symbol(r, ec_ctx->delta_lf_cdf, DELTA_LF_PROBS + 1, ACCT_STR);
@@ -105,8 +111,13 @@
     smallval = (abs < DELTA_LF_SMALL);
     if (counts) {
 #if CONFIG_LOOPFILTER_LEVEL
-      for (i = 0; i < abs; ++i) counts->delta_lf[lf_id][i][1]++;
-      if (smallval) counts->delta_lf[lf_id][abs][0]++;
+      if (cm->delta_lf_multi) {
+        for (i = 0; i < abs; ++i) counts->delta_lf_multi[lf_id][i][1]++;
+        if (smallval) counts->delta_lf_multi[lf_id][abs][0]++;
+      } else {
+        for (i = 0; i < abs; ++i) counts->delta_lf[i][1]++;
+        if (smallval) counts->delta_lf[abs][0]++;
+      }
 #else
       for (i = 0; i < abs; ++i) counts->delta_lf[i][1]++;
       if (smallval) counts->delta_lf[abs][0]++;
@@ -1115,12 +1126,20 @@
 #if CONFIG_EXT_DELTA_Q
     if (cm->delta_lf_present_flag) {
 #if CONFIG_LOOPFILTER_LEVEL
-      for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
-        mbmi->curr_delta_lf[lf_id] = xd->curr_delta_lf[lf_id] =
-            xd->prev_delta_lf[lf_id] +
-            read_delta_lflevel(cm, xd, r, lf_id, mbmi, mi_col, mi_row) *
+      if (cm->delta_lf_multi) {
+        for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
+          mbmi->curr_delta_lf[lf_id] = xd->curr_delta_lf[lf_id] =
+              xd->prev_delta_lf[lf_id] +
+              read_delta_lflevel(cm, xd, r, lf_id, mbmi, mi_col, mi_row) *
+                  cm->delta_lf_res;
+          xd->prev_delta_lf[lf_id] = xd->curr_delta_lf[lf_id];
+        }
+      } else {
+        mbmi->current_delta_lf_from_base = xd->current_delta_lf_from_base =
+            xd->prev_delta_lf_from_base +
+            read_delta_lflevel(cm, xd, r, -1, mbmi, mi_col, mi_row) *
                 cm->delta_lf_res;
-        xd->prev_delta_lf[lf_id] = xd->curr_delta_lf[lf_id];
+        xd->prev_delta_lf_from_base = xd->current_delta_lf_from_base;
       }
 #else
       mbmi->current_delta_lf_from_base = xd->current_delta_lf_from_base =
@@ -2876,12 +2895,20 @@
 #if CONFIG_EXT_DELTA_Q
     if (cm->delta_lf_present_flag) {
 #if CONFIG_LOOPFILTER_LEVEL
-      for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
-        mbmi->curr_delta_lf[lf_id] = xd->curr_delta_lf[lf_id] =
-            xd->prev_delta_lf[lf_id] +
-            read_delta_lflevel(cm, xd, r, lf_id, mbmi, mi_col, mi_row) *
+      if (cm->delta_lf_multi) {
+        for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
+          mbmi->curr_delta_lf[lf_id] = xd->curr_delta_lf[lf_id] =
+              xd->prev_delta_lf[lf_id] +
+              read_delta_lflevel(cm, xd, r, lf_id, mbmi, mi_col, mi_row) *
+                  cm->delta_lf_res;
+          xd->prev_delta_lf[lf_id] = xd->curr_delta_lf[lf_id];
+        }
+      } else {
+        mbmi->current_delta_lf_from_base = xd->current_delta_lf_from_base =
+            xd->prev_delta_lf_from_base +
+            read_delta_lflevel(cm, xd, r, -1, mbmi, mi_col, mi_row) *
                 cm->delta_lf_res;
-        xd->prev_delta_lf[lf_id] = xd->curr_delta_lf[lf_id];
+        xd->prev_delta_lf_from_base = xd->current_delta_lf_from_base;
       }
 #else
       mbmi->current_delta_lf_from_base = xd->current_delta_lf_from_base =
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 37bfdfb..0662273 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -541,8 +541,14 @@
   (void)cm;
 
 #if CONFIG_LOOPFILTER_LEVEL
-  aom_write_symbol(w, AOMMIN(abs, DELTA_LF_SMALL), ec_ctx->delta_lf_cdf[lf_id],
-                   DELTA_LF_PROBS + 1);
+  if (cm->delta_lf_multi) {
+    assert(lf_id >= 0 && lf_id < FRAME_LF_COUNT);
+    aom_write_symbol(w, AOMMIN(abs, DELTA_LF_SMALL),
+                     ec_ctx->delta_lf_multi_cdf[lf_id], DELTA_LF_PROBS + 1);
+  } else {
+    aom_write_symbol(w, AOMMIN(abs, DELTA_LF_SMALL), ec_ctx->delta_lf_cdf,
+                     DELTA_LF_PROBS + 1);
+  }
 #else
   aom_write_symbol(w, AOMMIN(abs, DELTA_LF_SMALL), ec_ctx->delta_lf_cdf,
                    DELTA_LF_PROBS + 1);
@@ -1724,12 +1730,20 @@
 #if CONFIG_EXT_DELTA_Q
 #if CONFIG_LOOPFILTER_LEVEL
       if (cm->delta_lf_present_flag) {
-        for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
+        if (cm->delta_lf_multi) {
+          for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
+            int reduced_delta_lflevel =
+                (mbmi->curr_delta_lf[lf_id] - xd->prev_delta_lf[lf_id]) /
+                cm->delta_lf_res;
+            write_delta_lflevel(cm, xd, lf_id, reduced_delta_lflevel, w);
+            xd->prev_delta_lf[lf_id] = mbmi->curr_delta_lf[lf_id];
+          }
+        } else {
           int reduced_delta_lflevel =
-              (mbmi->curr_delta_lf[lf_id] - xd->prev_delta_lf[lf_id]) /
+              (mbmi->current_delta_lf_from_base - xd->prev_delta_lf_from_base) /
               cm->delta_lf_res;
-          write_delta_lflevel(cm, xd, lf_id, reduced_delta_lflevel, w);
-          xd->prev_delta_lf[lf_id] = mbmi->curr_delta_lf[lf_id];
+          write_delta_lflevel(cm, xd, -1, reduced_delta_lflevel, w);
+          xd->prev_delta_lf_from_base = mbmi->current_delta_lf_from_base;
         }
       }
 #else
@@ -2119,12 +2133,20 @@
 #if CONFIG_EXT_DELTA_Q
 #if CONFIG_LOOPFILTER_LEVEL
       if (cm->delta_lf_present_flag) {
-        for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
+        if (cm->delta_lf_multi) {
+          for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
+            int reduced_delta_lflevel =
+                (mbmi->curr_delta_lf[lf_id] - xd->prev_delta_lf[lf_id]) /
+                cm->delta_lf_res;
+            write_delta_lflevel(cm, xd, lf_id, reduced_delta_lflevel, w);
+            xd->prev_delta_lf[lf_id] = mbmi->curr_delta_lf[lf_id];
+          }
+        } else {
           int reduced_delta_lflevel =
-              (mbmi->curr_delta_lf[lf_id] - xd->prev_delta_lf[lf_id]) /
+              (mbmi->current_delta_lf_from_base - xd->prev_delta_lf_from_base) /
               cm->delta_lf_res;
-          write_delta_lflevel(cm, xd, lf_id, reduced_delta_lflevel, w);
-          xd->prev_delta_lf[lf_id] = mbmi->curr_delta_lf[lf_id];
+          write_delta_lflevel(cm, xd, -1, reduced_delta_lflevel, w);
+          xd->prev_delta_lf_from_base = mbmi->current_delta_lf_from_base;
         }
       }
 #else
@@ -4757,11 +4779,12 @@
         aom_wb_write_bit(wb, cm->delta_lf_present_flag);
         if (cm->delta_lf_present_flag) {
           aom_wb_write_literal(wb, OD_ILOG_NZ(cm->delta_lf_res) - 1, 2);
+          xd->prev_delta_lf_from_base = 0;
 #if CONFIG_LOOPFILTER_LEVEL
+          aom_wb_write_bit(wb, cm->delta_lf_multi);
           for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id)
             xd->prev_delta_lf[lf_id] = 0;
 #endif  // CONFIG_LOOPFILTER_LEVEL
-          xd->prev_delta_lf_from_base = 0;
         }
 #endif  // CONFIG_EXT_DELTA_Q
       }
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index 9ae8b49..51d1c72 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -1624,19 +1624,31 @@
 #if CONFIG_EXT_DELTA_Q
 #if CONFIG_LOOPFILTER_LEVEL
     if (cm->delta_lf_present_flag) {
-      for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
+      if (cm->delta_lf_multi) {
+        for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
+          const int delta_lf =
+              (mbmi->curr_delta_lf[lf_id] - xd->prev_delta_lf[lf_id]) /
+              cm->delta_lf_res;
+          const int abs_delta_lf = abs(delta_lf);
+          for (i = 0; i < AOMMIN(abs_delta_lf, DELTA_LF_SMALL); ++i) {
+            td->counts->delta_lf_multi[lf_id][i][1]++;
+          }
+          if (abs_delta_lf < DELTA_LF_SMALL)
+            td->counts->delta_lf_multi[lf_id][abs_delta_lf][0]++;
+          xd->prev_delta_lf[lf_id] = mbmi->curr_delta_lf[lf_id];
+        }
+      } else {
         const int delta_lf =
-            (mbmi->curr_delta_lf[lf_id] - xd->prev_delta_lf[lf_id]) /
+            (mbmi->current_delta_lf_from_base - xd->prev_delta_lf_from_base) /
             cm->delta_lf_res;
         const int abs_delta_lf = abs(delta_lf);
         for (i = 0; i < AOMMIN(abs_delta_lf, DELTA_LF_SMALL); ++i) {
-          td->counts->delta_lf[lf_id][i][1]++;
+          td->counts->delta_lf[i][1]++;
         }
         if (abs_delta_lf < DELTA_LF_SMALL)
-          td->counts->delta_lf[lf_id][abs_delta_lf][0]++;
-        xd->prev_delta_lf[lf_id] = mbmi->curr_delta_lf[lf_id];
+          td->counts->delta_lf[abs_delta_lf][0]++;
+        xd->prev_delta_lf_from_base = mbmi->current_delta_lf_from_base;
       }
-      xd->prev_delta_lf_from_base = mbmi->current_delta_lf_from_base;
     }
 #else
     if (cm->delta_lf_present_flag) {
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index e008c54..cc2d580 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -5552,6 +5552,9 @@
 #if CONFIG_EXT_DELTA_Q
   cm->delta_q_present_flag = cpi->oxcf.deltaq_mode != NO_DELTA_Q;
   cm->delta_lf_present_flag = cpi->oxcf.deltaq_mode == DELTA_Q_LF;
+#if CONFIG_LOOPFILTER_LEVEL
+  cm->delta_lf_multi = DEFAULT_DELTA_LF_MULTI;
+#endif  // CONFIG_LOOPFILTER_LEVEL
 #endif
 
   if (cpi->sf.recode_loop == DISALLOW_RECODE) {