Support for delta-q at superblock level

Change-Id: I4128af44776d1f361bddc1fdffb75ed2224dbfa5
diff --git a/aomenc.c b/aomenc.c
index 3f9a87d..3b34ed8 100644
--- a/aomenc.c
+++ b/aomenc.c
@@ -392,10 +392,17 @@
     ARG_DEF(NULL, "frame-parallel", 1,
             "Enable frame parallel decodability features "
             "(0: false (default), 1: true)");
+#if CONFIG_DELTA_Q
+static const arg_def_t aq_mode = ARG_DEF(
+    NULL, "aq-mode", 1,
+    "Adaptive quantization mode (0: off (default), 1: variance 2: complexity, "
+    "3: cyclic refresh)");
+#else
 static const arg_def_t aq_mode = ARG_DEF(
     NULL, "aq-mode", 1,
     "Adaptive quantization mode (0: off (default), 1: variance 2: complexity, "
     "3: cyclic refresh, 4: equator360)");
+#endif
 static const arg_def_t frame_periodic_boost =
     ARG_DEF(NULL, "frame-boost", 1,
             "Enable frame periodic boost (0: off (default), 1: on)");
diff --git a/av1/common/blockd.h b/av1/common/blockd.h
index cc990ea..3ff4943 100644
--- a/av1/common/blockd.h
+++ b/av1/common/blockd.h
@@ -246,6 +246,9 @@
 #endif  // CONFIG_NEW_QUANT
   /* deringing gain *per-superblock* */
   int8_t dering_gain;
+#if CONFIG_DELTA_Q
+  int current_q_index;
+#endif
 } MB_MODE_INFO;
 
 typedef struct MODE_INFO {
@@ -401,6 +404,11 @@
 #if CONFIG_GLOBAL_MOTION
   Global_Motion_Params *global_motion;
 #endif  // CONFIG_GLOBAL_MOTION
+#if CONFIG_DELTA_Q
+  int prev_qindex;
+  int delta_qindex;
+  int current_qindex;
+#endif
 } MACROBLOCKD;
 
 static INLINE BLOCK_SIZE get_subsize(BLOCK_SIZE bsize,
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index cf8d7b4..525680f 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -395,6 +395,9 @@
 #if CONFIG_DERING
   int dering_level;
 #endif
+#if CONFIG_DELTA_Q
+  int delta_q_present_flag;
+#endif
 } AV1_COMMON;
 
 // TODO(hkuang): Don't need to lock the whole pool after implementing atomic
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index e4f2ee7..e3c7698 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -1209,6 +1209,26 @@
   }
 #endif  // CONFIG_SUPERTX
 
+#if CONFIG_DELTA_Q
+  if (cm->delta_q_present_flag) {
+    int i;
+    for (i = 0; i < MAX_SEGMENTS; i++) {
+      xd->plane[0].seg_dequant[i][0] =
+          av1_dc_quant(xd->current_qindex, cm->y_dc_delta_q, cm->bit_depth);
+      xd->plane[0].seg_dequant[i][1] =
+          av1_ac_quant(xd->current_qindex, 0, cm->bit_depth);
+      xd->plane[1].seg_dequant[i][0] =
+          av1_dc_quant(xd->current_qindex, cm->uv_dc_delta_q, cm->bit_depth);
+      xd->plane[1].seg_dequant[i][1] =
+          av1_ac_quant(xd->current_qindex, cm->uv_ac_delta_q, cm->bit_depth);
+      xd->plane[2].seg_dequant[i][0] =
+          av1_dc_quant(xd->current_qindex, cm->uv_dc_delta_q, cm->bit_depth);
+      xd->plane[2].seg_dequant[i][1] =
+          av1_ac_quant(xd->current_qindex, cm->uv_ac_delta_q, cm->bit_depth);
+    }
+  }
+#endif
+
   if (mbmi->skip) {
     dec_reset_skip_context(xd);
   }
@@ -3485,6 +3505,27 @@
 
   setup_segmentation(cm, rb);
 
+#if CONFIG_DELTA_Q
+  {
+    struct segmentation *const seg = &cm->seg;
+    int segment_quantizer_active = 0;
+    for (i = 0; i < MAX_SEGMENTS; i++) {
+      if (segfeature_active(seg, i, SEG_LVL_ALT_Q)) {
+        segment_quantizer_active = 1;
+      }
+    }
+
+    if (segment_quantizer_active == 0) {
+      cm->delta_q_present_flag = aom_rb_read_bit(rb);
+    } else {
+      cm->delta_q_present_flag = 0;
+    }
+    if (cm->delta_q_present_flag) {
+      xd->prev_qindex = cm->base_qindex;
+    }
+  }
+#endif
+
   for (i = 0; i < MAX_SEGMENTS; ++i) {
     const int qindex = cm->seg.enabled
                            ? av1_get_qindex(&cm->seg, i, cm->base_qindex)
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index 66056c0..37bc0f4 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -598,6 +598,38 @@
 
   mbmi->segment_id = read_intra_segment_id(cm, xd, mi_offset, x_mis, y_mis, r);
   mbmi->skip = read_skip(cm, xd, mbmi->segment_id, r);
+
+#if CONFIG_DELTA_Q
+  if (cm->delta_q_present_flag) {
+    int b_col = mi_col & 7;
+    int b_row = mi_row & 7;
+    int read_delta_q_flag = (b_col == 0 && b_row == 0);
+    if ((bsize != BLOCK_64X64 || mbmi->skip == 0) && read_delta_q_flag) {
+      int sign, abs, tmp, delta_qindex;
+
+      abs = 0;
+      tmp = aom_read_bit(r, ACCT_STR);
+      while (tmp == 0 && abs < 2) {
+        tmp = aom_read_bit(r, ACCT_STR);
+        abs++;
+      }
+      if (tmp == 0) {
+        abs = aom_read_literal(r, 6, ACCT_STR);
+      }
+
+      if (abs) {
+        sign = aom_read_bit(r, ACCT_STR);
+      } else {
+        sign = 1;
+      }
+
+      delta_qindex = sign ? -abs : abs;
+      xd->current_qindex = xd->prev_qindex + delta_qindex;
+      xd->prev_qindex = xd->current_qindex;
+    }
+  }
+#endif
+
   mbmi->tx_size = read_tx_size_intra(cm, xd, r);
   mbmi->ref_frame[0] = INTRA_FRAME;
   mbmi->ref_frame[1] = NONE;
@@ -1655,6 +1687,35 @@
   if (!supertx_enabled) {
 #endif  // CONFIG_SUPERTX
     mbmi->skip = read_skip(cm, xd, mbmi->segment_id, r);
+#if CONFIG_DELTA_Q
+    if (cm->delta_q_present_flag) {
+      BLOCK_SIZE bsize = mbmi->sb_type;
+      int b_col = mi_col & 7;
+      int b_row = mi_row & 7;
+      int read_delta_q_flag = (b_col == 0 && b_row == 0);
+      if ((bsize != BLOCK_64X64 || mbmi->skip == 0) && read_delta_q_flag) {
+        int sign, abs, tmp, delta_qindex;
+
+        abs = 0;
+        tmp = aom_read_bit(r, ACCT_STR);
+        while (tmp == 0 && abs < 2) {
+          tmp = aom_read_bit(r, ACCT_STR);
+          abs++;
+        }
+        if (tmp == 0) {
+          abs = aom_read_literal(r, 6, ACCT_STR);
+        }
+        if (abs) {
+          sign = aom_read_bit(r, ACCT_STR);
+        } else {
+          sign = 1;
+        }
+        delta_qindex = sign ? -abs : abs;
+        xd->current_qindex = xd->prev_qindex + delta_qindex;
+        xd->prev_qindex = xd->current_qindex;
+      }
+    }
+#endif
     inter_block = read_is_inter_block(cm, xd, mbmi->segment_id, r);
 
 #if CONFIG_VAR_TX
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index b7cbc00..fe6ffe7 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -488,6 +488,22 @@
   }
 }
 
+#if CONFIG_DELTA_Q
+static void write_delta_qindex(int delta_qindex, aom_writer *w) {
+  int sign = delta_qindex < 0;
+  int abs = sign ? -delta_qindex : delta_qindex;
+  if (abs < 3) {
+    aom_write_literal(w, 1, abs + 1);
+  } else {
+    aom_write_literal(w, 0, 3);
+    aom_write_literal(w, abs, 6);
+  }
+  if (abs > 0) {
+    aom_write_bit(w, sign);
+  }
+}
+#endif
+
 static void update_skip_probs(AV1_COMMON *cm, aom_writer *w,
                               FRAME_COUNTS *counts) {
   int k;
@@ -1069,8 +1085,14 @@
 #if !CONFIG_REF_MV
   const nmv_context *nmvc = &cm->fc->nmvc;
 #endif
+
+#if CONFIG_DELTA_Q
+  MACROBLOCK *const x = &cpi->td.mb;
+  MACROBLOCKD *const xd = &x->e_mbd;
+#else
   const MACROBLOCK *x = &cpi->td.mb;
   const MACROBLOCKD *xd = &x->e_mbd;
+#endif
   const struct segmentation *const seg = &cm->seg;
   const struct segmentation_probs *const segp = &cm->fc->seg;
   const MB_MODE_INFO *const mbmi = &mi->mbmi;
@@ -1102,6 +1124,18 @@
 #else
   skip = write_skip(cm, xd, segment_id, mi, w);
 #endif  // CONFIG_SUPERTX
+#if CONFIG_DELTA_Q
+  if (cm->delta_q_present_flag) {
+    int mi_row = (-xd->mb_to_top_edge) >> 6;
+    int mi_col = (-xd->mb_to_left_edge) >> 6;
+    int super_block_upper_left = ((mi_row & 7) == 0) && ((mi_col & 7) == 0);
+    if ((bsize != BLOCK_64X64 || skip == 0) && super_block_upper_left) {
+      int delta_qindex = mbmi->current_q_index - xd->prev_qindex;
+      write_delta_qindex(delta_qindex, w);
+      xd->prev_qindex = mbmi->current_q_index;
+    }
+  }
+#endif
 
 #if CONFIG_SUPERTX
   if (!supertx_enabled)
@@ -1503,8 +1537,14 @@
   }
 }
 
+#if CONFIG_DELTA_Q
+static void write_mb_modes_kf(const AV1_COMMON *cm, MACROBLOCKD *xd,
+                              MODE_INFO **mi_8x8, aom_writer *w) {
+  int skip;
+#else
 static void write_mb_modes_kf(const AV1_COMMON *cm, const MACROBLOCKD *xd,
                               MODE_INFO **mi_8x8, aom_writer *w) {
+#endif
   const struct segmentation *const seg = &cm->seg;
   const struct segmentation_probs *const segp = &cm->fc->seg;
   const MODE_INFO *const mi = mi_8x8[0];
@@ -1515,7 +1555,21 @@
 
   if (seg->update_map) write_segment_id(w, seg, segp, mbmi->segment_id);
 
+#if CONFIG_DELTA_Q
+  skip = write_skip(cm, xd, mbmi->segment_id, mi, w);
+  if (cm->delta_q_present_flag) {
+    int mi_row = (-xd->mb_to_top_edge) >> 6;
+    int mi_col = (-xd->mb_to_left_edge) >> 6;
+    int super_block_upper_left = ((mi_row & 7) == 0) && ((mi_col & 7) == 0);
+    if ((bsize != BLOCK_64X64 || skip == 0) && super_block_upper_left) {
+      int delta_qindex = mbmi->current_q_index - xd->prev_qindex;
+      write_delta_qindex(delta_qindex, w);
+      xd->prev_qindex = mbmi->current_q_index;
+    }
+  }
+#else
   write_skip(cm, xd, mbmi->segment_id, mi, w);
+#endif
 
   if (bsize >= BLOCK_8X8 && cm->tx_mode == TX_MODE_SELECT &&
       !xd->lossless[mbmi->segment_id])
@@ -2000,8 +2054,12 @@
   const int mi_col_start = tile->mi_col_start;
   const int mi_col_end = tile->mi_col_end;
   int mi_row, mi_col;
-
   av1_zero_above_context(cm, mi_col_start, mi_col_end);
+#if CONFIG_DELTA_Q
+  if (cpi->common.delta_q_present_flag) {
+    xd->prev_qindex = cpi->common.base_qindex;
+  }
+#endif
 
   for (mi_row = mi_row_start; mi_row < mi_row_end; mi_row += cm->mib_size) {
     av1_zero_left_context(xd);
@@ -3337,6 +3395,26 @@
 #endif  // CONFIG_LOOP_RESTORATION
   encode_quantization(cm, wb);
   encode_segmentation(cm, xd, wb);
+#if CONFIG_DELTA_Q
+  {
+    int i;
+    struct segmentation *const seg = &cm->seg;
+    int segment_quantizer_active = 0;
+    for (i = 0; i < MAX_SEGMENTS; i++) {
+      if (segfeature_active(seg, i, SEG_LVL_ALT_Q)) {
+        segment_quantizer_active = 1;
+      }
+    }
+    if (segment_quantizer_active == 0) {
+      cm->delta_q_present_flag = cpi->oxcf.aq_mode == DELTA_AQ;
+      aom_wb_write_bit(wb, cm->delta_q_present_flag);
+      if (cm->delta_q_present_flag) {
+        xd->prev_qindex = cm->base_qindex;
+      }
+    }
+  }
+#endif
+
   if (!cm->seg.enabled && xd->lossless[0])
     cm->tx_mode = ONLY_4X4;
   else
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index 004ad68..dce26dd 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -1114,8 +1114,13 @@
         xd->mi[x_idx + y * mis] = mi_addr;
       }
 
+#if CONFIG_DELTA_Q
+  if (cpi->oxcf.aq_mode > NO_AQ && cpi->oxcf.aq_mode < DELTA_AQ)
+    av1_init_plane_quantizers(cpi, x);
+#else
   if (cpi->oxcf.aq_mode)
     av1_init_plane_quantizers(cpi, x, xd->mi[0]->mbmi.segment_id);
+#endif
 
   if (is_inter_block(mbmi) && mbmi->sb_type < BLOCK_8X8) {
     mbmi->mv[0].as_int = mi->bmi[3].as_mv[0].as_int;
@@ -4188,6 +4193,22 @@
       seg_skip = segfeature_active(seg, segment_id, SEG_LVL_SKIP);
     }
 
+#if CONFIG_DELTA_Q
+    if (cpi->oxcf.aq_mode == DELTA_AQ) {
+      int sb_row = mi_row >> 3;
+      int sb_col = mi_col >> 3;
+      int sb_stride = (cm->width + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2;
+      int index = ((sb_row * sb_stride + sb_col + 8) & 31) - 16;
+      int offset_qindex = index < 0 ? -index - 8 : index - 8;
+      int current_qindex = clamp(cm->base_qindex + offset_qindex, 1, 255);
+      xd->delta_qindex = current_qindex - cm->base_qindex;
+      set_offsets(cpi, tile_info, x, mi_row, mi_col, BLOCK_64X64);
+      xd->mi[0]->mbmi.current_q_index = current_qindex;
+      xd->mi[0]->mbmi.segment_id = 0;
+      av1_init_plane_quantizers(cpi, x);
+    }
+#endif
+
     x->source_variance = UINT_MAX;
     if (sf->partition_search_type == FIXED_PARTITION || seg_skip) {
       BLOCK_SIZE bsize;
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index e2046ec..b55481b 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -133,6 +133,9 @@
   VARIANCE_AQ = 1,
   COMPLEXITY_AQ = 2,
   CYCLIC_REFRESH_AQ = 3,
+#if CONFIG_DELTA_Q
+  DELTA_AQ = 4,
+#endif
   AQ_MODE_COUNT  // This should always be the last member of the enum
 } AQ_MODE;
 
diff --git a/av1/encoder/quantize.c b/av1/encoder/quantize.c
index 554a38b..db2fdb8 100644
--- a/av1/encoder/quantize.c
+++ b/av1/encoder/quantize.c
@@ -1219,7 +1219,15 @@
   const AV1_COMMON *const cm = &cpi->common;
   MACROBLOCKD *const xd = &x->e_mbd;
   const QUANTS *const quants = &cpi->quants;
+
+#if CONFIG_DELTA_Q
+  int current_q_index = cpi->oxcf.aq_mode == DELTA_AQ
+                            ? cm->base_qindex + xd->delta_qindex
+                            : cm->base_qindex;
+  const int qindex = av1_get_qindex(&cm->seg, segment_id, current_q_index);
+#else
   const int qindex = av1_get_qindex(&cm->seg, segment_id, cm->base_qindex);
+#endif
   const int rdmult = av1_compute_rd_mult(cpi, qindex + cm->y_dc_delta_q);
   int i;
 #if CONFIG_AOM_QM
diff --git a/configure b/configure
index 4e9a52c..c396632 100755
--- a/configure
+++ b/configure
@@ -285,6 +285,7 @@
     daala_ec
     cb4x4
     frame_size
+    delta_q
 "
 CONFIG_LIST="
     dependency_tracking