Add the q_segmentation experiment

This experiment implements low-cost delta q signalling on a per-block basis
for all non-inter frame types, which would allow for more efficient AQ
which bases its decisions on temporal information.

Based on an Intel proposal from March.

Change-Id: I18e73d8b12f4caa0b165df12c58ab506271bec03
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 3dfd790..bc11ea2 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -488,7 +488,11 @@
     for (i = 0; i < MAX_SEGMENTS; i++) {
 #if CONFIG_EXT_DELTA_Q
       const int current_qindex =
+#if CONFIG_Q_SEGMENTATION
+          av1_get_qindex(&cm->seg, i, i, xd->current_qindex);
+#else
           av1_get_qindex(&cm->seg, i, xd->current_qindex);
+#endif
 #else
       const int current_qindex = xd->current_qindex;
 #endif  // CONFIG_EXT_DELTA_Q
@@ -1107,6 +1111,31 @@
   }
 }
 
+#if CONFIG_Q_SEGMENTATION
+static void setup_q_segmentation(AV1_COMMON *const cm,
+                                 struct aom_read_bit_buffer *rb) {
+  int i;
+  struct segmentation *const seg = &cm->seg;
+
+  for (i = 0; i < MAX_SEGMENTS; i++) {
+    if (segfeature_active(seg, i, SEG_LVL_ALT_Q)) {
+      seg->q_lvls = 0;
+      return;
+    }
+  }
+
+  if (!aom_rb_read_bit(rb)) return;
+
+  seg->q_lvls = decode_unsigned_max(rb, MAX_SEGMENTS);
+
+  for (i = 0; i < seg->q_lvls; i++) {
+    int val = decode_unsigned_max(rb, MAXQ);
+    val *= 1 - 2 * aom_rb_read_bit(rb);
+    seg->q_delta[i] = val;
+  }
+}
+#endif
+
 #if CONFIG_LOOP_RESTORATION
 static void decode_restoration_mode(AV1_COMMON *cm,
                                     struct aom_read_bit_buffer *rb) {
@@ -1367,7 +1396,11 @@
   // remaining are don't cares.
   const int max_segments = cm->seg.enabled ? MAX_SEGMENTS : 1;
   for (int i = 0; i < max_segments; ++i) {
+#if CONFIG_Q_SEGMENTATION
+    const int qindex = av1_get_qindex(&cm->seg, i, i, cm->base_qindex);
+#else
     const int qindex = av1_get_qindex(&cm->seg, i, cm->base_qindex);
+#endif
     cm->y_dequant_QTX[i][0] = dequant_Q3_to_QTX(
         av1_dc_quant(qindex, cm->y_dc_delta_q, cm->bit_depth), cm->bit_depth);
     cm->y_dequant_QTX[i][1] = dequant_Q3_to_QTX(
@@ -3141,6 +3174,9 @@
 #endif  // CONFIG_Q_ADAPT_PROBS
 
   setup_segmentation(cm, rb);
+#if CONFIG_Q_SEGMENTATION
+  setup_q_segmentation(cm, rb);
+#endif
 
   {
     int delta_q_allowed = 1;
@@ -3151,6 +3187,9 @@
       if (segfeature_active(seg, i, SEG_LVL_ALT_Q)) {
         segment_quantizer_active = 1;
       }
+#if CONFIG_Q_SEGMENTATION
+      if (seg->q_lvls) segment_quantizer_active = 1;
+#endif
     }
     delta_q_allowed = !segment_quantizer_active;
 #endif
@@ -3191,7 +3230,11 @@
 
   for (i = 0; i < MAX_SEGMENTS; ++i) {
     const int qindex = cm->seg.enabled
+#if CONFIG_Q_SEGMENTATION
+                           ? av1_get_qindex(&cm->seg, i, i, cm->base_qindex)
+#else
                            ? av1_get_qindex(&cm->seg, i, cm->base_qindex)
+#endif
                            : cm->base_qindex;
     xd->lossless[i] = qindex == 0 && cm->y_dc_delta_q == 0 &&
                       cm->uv_dc_delta_q == 0 && cm->uv_ac_delta_q == 0;
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index 14fd853..914c1a8 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -350,6 +350,82 @@
   return aom_read_symbol(r, segp->tree_cdf, MAX_SEGMENTS, ACCT_STR);
 }
 
+#if CONFIG_Q_SEGMENTATION
+static int neg_deinterleave(int diff, int ref, int max) {
+  if (!ref) return diff;
+  if (ref >= (max - 1)) return max - diff - 1;
+  if (2 * ref < max) {
+    if (diff <= 2 * ref) {
+      if (diff & 1)
+        return ref + ((diff + 1) >> 1);
+      else
+        return ref - (diff >> 1);
+    }
+    return diff;
+  } else {
+    if (diff <= 2 * (max - ref - 1)) {
+      if (diff & 1)
+        return ref + ((diff + 1) >> 1);
+      else
+        return ref - (diff >> 1);
+    }
+    return max - (diff + 1);
+  }
+}
+
+static int read_q_segment_id(AV1_COMMON *const cm, MACROBLOCKD *const xd,
+                             int mi_row, int mi_col, aom_reader *r) {
+  struct segmentation *const seg = &cm->seg;
+  FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
+  struct segmentation_probs *const segp = &ec_ctx->seg;
+  MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
+  int prev_ul = 0; /* Top left segment_id */
+  int prev_l = 0;  /* Current left segment_id */
+  int prev_u = 0;  /* Current top segment_id */
+
+  if (!seg->q_lvls) return 0;
+
+  MODE_INFO *const mi = cm->mi + mi_row * cm->mi_stride + mi_col;
+  int tinfo = mi->mbmi.boundary_info;
+  int above = (!(tinfo & TILE_ABOVE_BOUNDARY)) && ((mi_row - 1) >= 0);
+  int left = (!(tinfo & TILE_LEFT_BOUNDARY)) && ((mi_col - 1) >= 0);
+
+  if (above && left)
+    prev_ul =
+        get_segment_id(cm, cm->q_seg_map, BLOCK_4X4, mi_row - 1, mi_col - 1);
+
+  if (above)
+    prev_u = get_segment_id(cm, cm->q_seg_map, BLOCK_4X4, mi_row - 1, mi_col);
+
+  if (left)
+    prev_l = get_segment_id(cm, cm->q_seg_map, BLOCK_4X4, mi_row, mi_col - 1);
+
+  int cdf_num = pick_q_seg_cdf(prev_ul, prev_u, prev_l);
+  int pred = pick_q_seg_pred(prev_ul, prev_u, prev_l);
+
+  if (mbmi->skip) {
+    set_q_segment_id(cm, cm->q_seg_map, mbmi->sb_type, mi_row, mi_col, pred);
+    return 0;
+  }
+
+#if CONFIG_NEW_MULTISYMBOL
+  aom_cdf_prob *pred_cdf = segp->q_seg_cdf[cdf_num];
+  int coded_id = aom_read_symbol(r, pred_cdf, 8, ACCT_STR);
+#else
+  const aom_prob pred_cdf = segp->q_seg_cdf[cdf_num];
+  int coded_id = aom_read(r, pred_cdf, ACCT_STR);
+#endif
+
+  int segment_id = neg_deinterleave(coded_id, pred, seg->q_lvls);
+
+  assert(segment_id >= 0 && segment_id < seg->q_lvls);
+  set_q_segment_id(cm, cm->q_seg_map, mbmi->sb_type, mi_row, mi_col,
+                   segment_id);
+
+  return segment_id;
+}
+#endif
+
 static void read_tx_size_vartx(AV1_COMMON *cm, MACROBLOCKD *xd,
                                MB_MODE_INFO *mbmi, FRAME_COUNTS *counts,
                                TX_SIZE tx_size, int depth, int blk_row,
@@ -1086,6 +1162,9 @@
 
   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_Q_SEGMENTATION
+  mbmi->q_segment_id = read_q_segment_id(cm, xd, mi_row, mi_col, r);
+#endif
 
   if (cm->delta_q_present_flag) {
     xd->current_qindex =
@@ -2524,6 +2603,9 @@
 
   if (mbmi->skip_mode) {
     mbmi->skip = 1;
+#if CONFIG_Q_SEGMENTATION
+    mbmi->q_segment_id = read_q_segment_id(cm, xd, mi_row, mi_col, r);
+#endif
 
     if (cm->delta_q_present_flag) {
       xd->current_qindex = xd->prev_qindex;
@@ -2547,6 +2629,9 @@
   } else {
 #endif  // CONFIG_EXT_SKIP
     mbmi->skip = read_skip(cm, xd, mbmi->segment_id, r);
+#if CONFIG_Q_SEGMENTATION
+    mbmi->q_segment_id = read_q_segment_id(cm, xd, mi_row, mi_col, r);
+#endif
 
     if (cm->delta_q_present_flag) {
       xd->current_qindex =