Use arithmetic coding (cdf) to code sb filter lvl

Change-Id: I5446327378938128f27186015619a079c2845d53
diff --git a/av1/common/blockd.h b/av1/common/blockd.h
index 86fcd57..9ee553f 100644
--- a/av1/common/blockd.h
+++ b/av1/common/blockd.h
@@ -465,6 +465,9 @@
   BOUNDARY_TYPE boundary_info;
 #if CONFIG_LPF_SB
   uint8_t filt_lvl;
+  int reuse_sb_lvl;
+  int sign;
+  int delta;
 #endif
 } MB_MODE_INFO;
 
diff --git a/av1/common/entropy.c b/av1/common/entropy.c
index 3ac9c82..17a8f13 100644
--- a/av1/common/entropy.c
+++ b/av1/common/entropy.c
@@ -2313,6 +2313,11 @@
   AVERAGE_TILE_CDFS(quarter_tx_size_cdf)
 #endif
 #endif
+#if CONFIG_LPF_SB
+  AVERAGE_TILE_CDFS(lpf_reuse_cdf);
+  AVERAGE_TILE_CDFS(lpf_delta_cdf);
+  AVERAGE_TILE_CDFS(lpf_sign_cdf);
+#endif  // CONFIG_LPF_SB
 }
 
 void av1_average_tile_inter_cdfs(AV1_COMMON *cm, FRAME_CONTEXT *fc,
@@ -2381,6 +2386,11 @@
 #if CONFIG_MRC_TX
   AVERAGE_TILE_CDFS(mrc_mask_inter_cdf)
 #endif  // CONFIG_MRC_TX
+#if CONFIG_LPF_SB
+  AVERAGE_TILE_CDFS(lpf_reuse_cdf);
+  AVERAGE_TILE_CDFS(lpf_delta_cdf);
+  AVERAGE_TILE_CDFS(lpf_sign_cdf);
+#endif  // CONFIG_LPF_SB
 }
 
 #if CONFIG_PVQ
diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c
index 6ccd098..600d693 100644
--- a/av1/common/entropymode.c
+++ b/av1/common/entropymode.c
@@ -5622,6 +5622,40 @@
 };
 #endif  // CONFIG_KF_CTX
 
+#if CONFIG_LPF_SB
+static const aom_cdf_prob default_lpf_reuse_cdf[LPF_REUSE_CONTEXT][CDF_SIZE(
+    2)] = { { AOM_ICDF(8192), AOM_ICDF(32768), 0 },
+            { AOM_ICDF(4096), AOM_ICDF(32768), 0 } };
+
+static const aom_cdf_prob
+    default_lpf_delta_cdf[LPF_DELTA_CONTEXT][CDF_SIZE(DELTA_RANGE)] = {
+      { AOM_ICDF(4096), AOM_ICDF(7680), AOM_ICDF(10816), AOM_ICDF(13560),
+        AOM_ICDF(15961), AOM_ICDF(18062), AOM_ICDF(19900), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(4096), AOM_ICDF(7680), AOM_ICDF(10816), AOM_ICDF(13560),
+        AOM_ICDF(15961), AOM_ICDF(18062), AOM_ICDF(19900), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(4096), AOM_ICDF(7680), AOM_ICDF(10816), AOM_ICDF(13560),
+        AOM_ICDF(15961), AOM_ICDF(18062), AOM_ICDF(19900), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(4096), AOM_ICDF(7680), AOM_ICDF(10816), AOM_ICDF(13560),
+        AOM_ICDF(15961), AOM_ICDF(18062), AOM_ICDF(19900), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(4096), AOM_ICDF(7680), AOM_ICDF(10816), AOM_ICDF(13560),
+        AOM_ICDF(15961), AOM_ICDF(18062), AOM_ICDF(19900), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(4096), AOM_ICDF(7680), AOM_ICDF(10816), AOM_ICDF(13560),
+        AOM_ICDF(15961), AOM_ICDF(18062), AOM_ICDF(19900), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(4096), AOM_ICDF(7680), AOM_ICDF(10816), AOM_ICDF(13560),
+        AOM_ICDF(15961), AOM_ICDF(18062), AOM_ICDF(19900), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(4096), AOM_ICDF(7680), AOM_ICDF(10816), AOM_ICDF(13560),
+        AOM_ICDF(15961), AOM_ICDF(18062), AOM_ICDF(19900), AOM_ICDF(32768), 0 }
+    };
+
+static const aom_cdf_prob
+    default_lpf_sign_cdf[LPF_REUSE_CONTEXT][LPF_SIGN_CONTEXT][CDF_SIZE(2)] = {
+      { { AOM_ICDF(6554), AOM_ICDF(32768), 0 },
+        { AOM_ICDF(26214), AOM_ICDF(32768), 0 } },
+      { { AOM_ICDF(16384), AOM_ICDF(32768), 0 },
+        { AOM_ICDF(16384), AOM_ICDF(32768), 0 } }
+    };
+#endif  // CONFIG_LPF_SB
+
 static void init_mode_probs(FRAME_CONTEXT *fc) {
   av1_copy(fc->partition_prob, default_partition_probs);
   av1_copy(fc->intra_inter_prob, default_intra_inter_p);
@@ -5798,6 +5832,11 @@
 #if CONFIG_INTRABC
   av1_copy(fc->intrabc_cdf, default_intrabc_cdf);
 #endif
+#if CONFIG_LPF_SB
+  av1_copy(fc->lpf_reuse_cdf, default_lpf_reuse_cdf);
+  av1_copy(fc->lpf_delta_cdf, default_lpf_delta_cdf);
+  av1_copy(fc->lpf_sign_cdf, default_lpf_sign_cdf);
+#endif  // CONFIG_LPF_SB
 }
 
 void av1_adapt_inter_frame_probs(AV1_COMMON *cm) {
diff --git a/av1/common/entropymode.h b/av1/common/entropymode.h
index 92cd94a..e5c8f9d 100644
--- a/av1/common/entropymode.h
+++ b/av1/common/entropymode.h
@@ -405,6 +405,11 @@
   aom_cdf_prob cfl_sign_cdf[CDF_SIZE(CFL_JOINT_SIGNS)];
   aom_cdf_prob cfl_alpha_cdf[CFL_ALPHA_CONTEXTS][CDF_SIZE(CFL_ALPHABET_SIZE)];
 #endif
+#if CONFIG_LPF_SB
+  aom_cdf_prob lpf_reuse_cdf[LPF_REUSE_CONTEXT][CDF_SIZE(2)];
+  aom_cdf_prob lpf_delta_cdf[LPF_DELTA_CONTEXT][CDF_SIZE(DELTA_RANGE)];
+  aom_cdf_prob lpf_sign_cdf[LPF_REUSE_CONTEXT][LPF_SIGN_CONTEXT][CDF_SIZE(2)];
+#endif  // CONFIG_LPF_SB
 } FRAME_CONTEXT;
 
 typedef struct FRAME_COUNTS {
@@ -556,6 +561,11 @@
 #if CONFIG_FILTER_INTRA
   unsigned int filter_intra[PLANE_TYPES][2];
 #endif  // CONFIG_FILTER_INTRA
+#if CONFIG_LPF_SB
+  unsigned int lpf_reuse[LPF_REUSE_CONTEXT][2];
+  unsigned int lpf_delta[LPF_DELTA_CONTEXT][DELTA_RANGE];
+  unsigned int lpf_sign[LPF_SIGN_CONTEXT][2];
+#endif  // CONFIG_LPF_SB
 } FRAME_COUNTS;
 
 #if CONFIG_KF_CTX
diff --git a/av1/common/enums.h b/av1/common/enums.h
index aeae71c..efc79fd 100644
--- a/av1/common/enums.h
+++ b/av1/common/enums.h
@@ -92,8 +92,13 @@
 #if CONFIG_LPF_SB
 #define LPF_DELTA_BITS 3
 #define LPF_STEP 2
+#define DELTA_RANGE (1 << LPF_DELTA_BITS)
 #define MAX_LPF_OFFSET (LPF_STEP * ((1 << LPF_DELTA_BITS) - 1))
 
+#define LPF_REUSE_CONTEXT 2
+#define LPF_DELTA_CONTEXT DELTA_RANGE
+#define LPF_SIGN_CONTEXT 2
+
 // Half of maximum loop filter length (15-tap)
 #define FILT_BOUNDARY_OFFSET 8
 #define FILT_BOUNDARY_MI_OFFSET (FILT_BOUNDARY_OFFSET >> MI_SIZE_LOG2)
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index e140847..f75975f 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -2579,6 +2579,9 @@
     int filt_lvl;
     if (mi_row == 0 && mi_col == 0) {
       filt_lvl = aom_read_literal(r, 6, ACCT_STR);
+      cm->mi_grid_visible[0]->mbmi.reuse_sb_lvl = 0;
+      cm->mi_grid_visible[0]->mbmi.delta = 0;
+      cm->mi_grid_visible[0]->mbmi.sign = 0;
     } else {
       int prev_mi_row, prev_mi_col;
       if (mi_col - MAX_MIB_SIZE < 0) {
@@ -2589,22 +2592,37 @@
         prev_mi_col = mi_col - MAX_MIB_SIZE;
       }
 
-      const uint8_t prev_lvl =
-          cm->mi_grid_visible[prev_mi_row * cm->mi_stride + prev_mi_col]
-              ->mbmi.filt_lvl;
+      MB_MODE_INFO *curr_mbmi =
+          &cm->mi_grid_visible[mi_row * cm->mi_stride + mi_col]->mbmi;
+      MB_MODE_INFO *prev_mbmi =
+          &cm->mi_grid_visible[prev_mi_row * cm->mi_stride + prev_mi_col]->mbmi;
+      const uint8_t prev_lvl = prev_mbmi->filt_lvl;
 
-      const int reuse_prev_lvl = aom_read_literal(r, 1, ACCT_STR);
+      const int reuse_ctx = prev_mbmi->reuse_sb_lvl;
+      const int reuse_prev_lvl = aom_read_symbol(
+          r, xd->tile_ctx->lpf_reuse_cdf[reuse_ctx], 2, ACCT_STR);
+      curr_mbmi->reuse_sb_lvl = reuse_prev_lvl;
+
       if (reuse_prev_lvl) {
         filt_lvl = prev_lvl;
+        curr_mbmi->delta = 0;
+        curr_mbmi->sign = 0;
       } else {
-        unsigned int delta = aom_read_literal(r, LPF_DELTA_BITS, ACCT_STR);
+        const int delta_ctx = prev_mbmi->delta;
+        unsigned int delta = aom_read_symbol(
+            r, xd->tile_ctx->lpf_delta_cdf[delta_ctx], DELTA_RANGE, ACCT_STR);
+        curr_mbmi->delta = delta;
         delta *= LPF_STEP;
 
         if (delta) {
-          const int sign = aom_read_literal(r, 1, ACCT_STR);
+          const int sign_ctx = prev_mbmi->sign;
+          const int sign = aom_read_symbol(
+              r, xd->tile_ctx->lpf_sign_cdf[reuse_ctx][sign_ctx], 2, ACCT_STR);
+          curr_mbmi->sign = sign;
           filt_lvl = sign ? prev_lvl + delta : prev_lvl - delta;
         } else {
           filt_lvl = prev_lvl;
+          curr_mbmi->sign = 0;
         }
       }
     }
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index a546258..adad474 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -3153,10 +3153,10 @@
   // send filter level for each superblock (64x64)
   if (bsize == cm->sb_size) {
     if (mi_row == 0 && mi_col == 0) {
-      aom_write_literal(
-          w,
-          cm->mi_grid_visible[mi_row * cm->mi_stride + mi_col]->mbmi.filt_lvl,
-          6);
+      aom_write_literal(w, cm->mi_grid_visible[0]->mbmi.filt_lvl, 6);
+      cm->mi_grid_visible[0]->mbmi.reuse_sb_lvl = 0;
+      cm->mi_grid_visible[0]->mbmi.delta = 0;
+      cm->mi_grid_visible[0]->mbmi.sign = 0;
     } else {
       int prev_mi_row, prev_mi_col;
       if (mi_col - MAX_MIB_SIZE < 0) {
@@ -3174,13 +3174,31 @@
       const uint8_t curr_lvl = curr_mbmi->filt_lvl;
       const uint8_t prev_lvl = prev_mbmi->filt_lvl;
 
-      aom_write_literal(w, curr_lvl == prev_lvl, 1);
-      if (curr_lvl != prev_lvl) {
-        const int sign = curr_lvl > prev_lvl;
-        const unsigned int delta = abs(curr_lvl - prev_lvl) / LPF_STEP;
+      const int reuse_prev_lvl = curr_lvl == prev_lvl;
+      const int reuse_ctx = prev_mbmi->reuse_sb_lvl;
+      curr_mbmi->reuse_sb_lvl = reuse_prev_lvl;
+      aom_write_symbol(w, reuse_prev_lvl,
+                       xd->tile_ctx->lpf_reuse_cdf[reuse_ctx], 2);
 
-        aom_write_literal(w, delta, LPF_DELTA_BITS);
-        if (delta) aom_write_literal(w, sign, 1);
+      if (reuse_prev_lvl) {
+        curr_mbmi->delta = 0;
+        curr_mbmi->sign = 0;
+      } else {
+        const unsigned int delta = abs(curr_lvl - prev_lvl) / LPF_STEP;
+        const int delta_ctx = prev_mbmi->delta;
+        curr_mbmi->delta = delta;
+        aom_write_symbol(w, delta, xd->tile_ctx->lpf_delta_cdf[delta_ctx],
+                         DELTA_RANGE);
+
+        if (delta) {
+          const int sign = curr_lvl > prev_lvl;
+          const int sign_ctx = prev_mbmi->sign;
+          curr_mbmi->sign = sign;
+          aom_write_symbol(w, sign,
+                           xd->tile_ctx->lpf_sign_cdf[reuse_ctx][sign_ctx], 2);
+        } else {
+          curr_mbmi->sign = 0;
+        }
       }
     }
   }