Add new compound modes using single reference

The hookup with the encoder-decoder pipeline will be in the following
CLs. This is under the experiment of compound-singleref, with ext-
inter enabled.

Change-Id: I6523a1a6525539eb7c6aa6c5e11724a694e8bf6c
diff --git a/av1/common/blockd.h b/av1/common/blockd.h
index 8f7761e..86a068e 100644
--- a/av1/common/blockd.h
+++ b/av1/common/blockd.h
@@ -119,7 +119,11 @@
 static INLINE int is_inter_singleref_mode(PREDICTION_MODE mode) {
   return mode >= NEARESTMV && mode <= NEWMV;
 }
-
+#if CONFIG_COMPOUND_SINGLEREF
+static INLINE int is_inter_singleref_comp_mode(PREDICTION_MODE mode) {
+  return mode >= SR_NEAREST_NEARMV && mode <= SR_NEW_NEWMV;
+}
+#endif  // CONFIG_COMPOUND_SINGLEREF
 static INLINE int is_inter_compound_mode(PREDICTION_MODE mode) {
   return mode >= NEAREST_NEARESTMV && mode <= NEW_NEWMV;
 }
@@ -143,16 +147,23 @@
     MB_MODE_COUNT,  // NEARMV
     MB_MODE_COUNT,  // ZEROMV
     MB_MODE_COUNT,  // NEWMV
-    NEARESTMV,      // NEAREST_NEARESTMV
-    NEARESTMV,      // NEAREST_NEARMV
-    NEARMV,         // NEAR_NEARESTMV
-    NEARMV,         // NEAR_NEARMV
-    NEARESTMV,      // NEAREST_NEWMV
-    NEWMV,          // NEW_NEARESTMV
-    NEARMV,         // NEAR_NEWMV
-    NEWMV,          // NEW_NEARMV
-    ZEROMV,         // ZERO_ZEROMV
-    NEWMV,          // NEW_NEWMV
+#if CONFIG_COMPOUND_SINGLEREF
+    NEARESTMV,  // SR_NEAREST_NEARMV
+    NEARESTMV,  // SR_NEAREST_NEWMV
+    NEARMV,     // SR_NEAR_NEWMV
+    ZEROMV,     // SR_ZERO_NEWMV
+    NEWMV,      // SR_NEW_NEWMV
+#endif          // CONFIG_COMPOUND_SINGLEREF
+    NEARESTMV,  // NEAREST_NEARESTMV
+    NEARESTMV,  // NEAREST_NEARMV
+    NEARMV,     // NEAR_NEARESTMV
+    NEARMV,     // NEAR_NEARMV
+    NEARESTMV,  // NEAREST_NEWMV
+    NEWMV,      // NEW_NEARESTMV
+    NEARMV,     // NEAR_NEWMV
+    NEWMV,      // NEW_NEARMV
+    ZEROMV,     // ZERO_ZEROMV
+    NEWMV,      // NEW_NEWMV
   };
   assert(is_inter_compound_mode(mode));
   return lut[mode];
@@ -177,16 +188,23 @@
     MB_MODE_COUNT,  // NEARMV
     MB_MODE_COUNT,  // ZEROMV
     MB_MODE_COUNT,  // NEWMV
-    NEARESTMV,      // NEAREST_NEARESTMV
-    NEARMV,         // NEAREST_NEARMV
-    NEARESTMV,      // NEAR_NEARESTMV
-    NEARMV,         // NEAR_NEARMV
-    NEWMV,          // NEAREST_NEWMV
-    NEARESTMV,      // NEW_NEARESTMV
-    NEWMV,          // NEAR_NEWMV
-    NEARMV,         // NEW_NEARMV
-    ZEROMV,         // ZERO_ZEROMV
-    NEWMV,          // NEW_NEWMV
+#if CONFIG_COMPOUND_SINGLEREF
+    NEARMV,     // SR_NEAREST_NEARMV
+    NEWMV,      // SR_NEAREST_NEWMV
+    NEWMV,      // SR_NEAR_NEWMV
+    NEWMV,      // SR_ZERO_NEWMV
+    NEWMV,      // SR_NEW_NEWMV
+#endif          // CONFIG_COMPOUND_SINGLEREF
+    NEARESTMV,  // NEAREST_NEARESTMV
+    NEARMV,     // NEAREST_NEARMV
+    NEARESTMV,  // NEAR_NEARESTMV
+    NEARMV,     // NEAR_NEARMV
+    NEWMV,      // NEAREST_NEWMV
+    NEARESTMV,  // NEW_NEARESTMV
+    NEWMV,      // NEAR_NEWMV
+    NEARMV,     // NEW_NEARMV
+    ZEROMV,     // ZERO_ZEROMV
+    NEWMV,      // NEW_NEWMV
   };
   assert(is_inter_compound_mode(mode));
   return lut[mode];
diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c
index d3568d6..0fcf762 100644
--- a/av1/common/entropymode.c
+++ b/av1/common/entropymode.c
@@ -772,6 +772,21 @@
       { 25, 29, 50, 192, 64, 192, 128, 180, 180 },   // 6 = two intra neighbours
     };
 
+#if CONFIG_COMPOUND_SINGLEREF
+// TODO(zoeliu): Default values to be further adjusted based on the collected
+//               stats.
+static const aom_prob default_inter_singleref_comp_mode_probs
+    [INTER_MODE_CONTEXTS][INTER_SINGLEREF_COMP_MODES - 1] = {
+      { 2, 173, 68, 180 },   // 0 = both zero mv
+      { 7, 145, 160, 180 },  // 1 = 1 zero + 1 predicted
+      { 7, 166, 126, 180 },  // 2 = two predicted mvs
+      { 7, 94, 132, 180 },   // 3 = 1 pred/zero, 1 new
+      { 8, 64, 64, 180 },    // 4 = two new mvs
+      { 17, 81, 52, 180 },   // 5 = one intra neighbour
+      { 25, 29, 50, 180 },   // 6 = two intra neighbours
+    };
+#endif  // CONFIG_COMPOUND_SINGLEREF
+
 #if CONFIG_COMPOUND_SEGMENT && CONFIG_WEDGE
 static const aom_prob
     default_compound_type_probs[BLOCK_SIZES][COMPOUND_TYPES - 1] = {
@@ -992,6 +1007,17 @@
   -INTER_COMPOUND_OFFSET(NEAR_NEWMV), -INTER_COMPOUND_OFFSET(NEW_NEARMV)
 };
 
+#if CONFIG_COMPOUND_SINGLEREF
+const aom_tree_index av1_inter_singleref_comp_mode_tree
+    [TREE_SIZE(INTER_SINGLEREF_COMP_MODES)] = {
+  -INTER_SINGLEREF_COMP_OFFSET(SR_ZERO_NEWMV), 2,
+  -INTER_SINGLEREF_COMP_OFFSET(SR_NEAREST_NEARMV), 4,
+  6, -INTER_SINGLEREF_COMP_OFFSET(SR_NEW_NEWMV),
+  -INTER_SINGLEREF_COMP_OFFSET(SR_NEAREST_NEWMV),
+  -INTER_SINGLEREF_COMP_OFFSET(SR_NEAR_NEWMV)
+};
+#endif  // CONFIG_COMPOUND_SINGLEREF
+
 #if CONFIG_COMPOUND_SEGMENT && CONFIG_WEDGE
 const aom_tree_index av1_compound_type_tree[TREE_SIZE(COMPOUND_TYPES)] = {
   -COMPOUND_AVERAGE, 2, -COMPOUND_WEDGE, -COMPOUND_SEG
@@ -1066,6 +1092,14 @@
 #endif  // CONFIG_EXT_REFS
 };
 
+#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+// TODO(zoeliu): Default values to be further adjusted based on the collected
+//               stats.
+static const aom_prob default_comp_inter_mode_p[COMP_INTER_MODE_CONTEXTS] = {
+  41, 119, 187, 225
+};
+#endif  // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+
 #if CONFIG_PALETTE
 
 // Tree to code palette size (number of colors in a palette) and the
@@ -3226,6 +3260,9 @@
   av1_copy(fc->comp_bwdref_prob, default_comp_bwdref_p);
 #endif  // CONFIG_EXT_REFS
   av1_copy(fc->single_ref_prob, default_single_ref_p);
+#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+  av1_copy(fc->comp_inter_mode_prob, default_comp_inter_mode_p);
+#endif  // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
   av1_copy(fc->tx_size_probs, default_tx_size_prob);
 #if CONFIG_VAR_TX
   av1_copy(fc->txfm_partition_prob, default_txfm_partition_probs);
@@ -3246,6 +3283,10 @@
 #endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
 #if CONFIG_EXT_INTER
   av1_copy(fc->inter_compound_mode_probs, default_inter_compound_mode_probs);
+#if CONFIG_COMPOUND_SINGLEREF
+  av1_copy(fc->inter_singleref_comp_mode_probs,
+           default_inter_singleref_comp_mode_probs);
+#endif  // CONFIG_COMPOUND_SINGLEREF
   av1_copy(fc->compound_type_prob, default_compound_type_probs);
   av1_copy(fc->interintra_prob, default_interintra_prob);
   av1_copy(fc->interintra_mode_prob, default_interintra_mode_prob);
@@ -3420,6 +3461,7 @@
   for (i = 0; i < INTRA_INTER_CONTEXTS; i++)
     fc->intra_inter_prob[i] = av1_mode_mv_merge_probs(
         pre_fc->intra_inter_prob[i], counts->intra_inter[i]);
+
   for (i = 0; i < COMP_INTER_CONTEXTS; i++)
     fc->comp_inter_prob[i] = av1_mode_mv_merge_probs(pre_fc->comp_inter_prob[i],
                                                      counts->comp_inter[i]);
@@ -3445,6 +3487,13 @@
       fc->single_ref_prob[i][j] = av1_mode_mv_merge_probs(
           pre_fc->single_ref_prob[i][j], counts->single_ref[i][j]);
 
+#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+  for (i = 0; i < COMP_INTER_MODE_CONTEXTS; i++)
+    fc->comp_inter_mode_prob[i] = av1_mode_mv_merge_probs(
+        pre_fc->comp_inter_mode_prob[i], counts->comp_inter_mode[i]);
+
+#endif  // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+
 #if CONFIG_REF_MV
   for (i = 0; i < NEWMV_MODE_CONTEXTS; ++i)
     fc->newmv_prob[i] =
@@ -3490,6 +3539,13 @@
     aom_tree_merge_probs(
         av1_inter_compound_mode_tree, pre_fc->inter_compound_mode_probs[i],
         counts->inter_compound_mode[i], fc->inter_compound_mode_probs[i]);
+#if CONFIG_COMPOUND_SINGLEREF
+  for (i = 0; i < INTER_MODE_CONTEXTS; i++)
+    aom_tree_merge_probs(av1_inter_singleref_comp_mode_tree,
+                         pre_fc->inter_singleref_comp_mode_probs[i],
+                         counts->inter_singleref_comp_mode[i],
+                         fc->inter_singleref_comp_mode_probs[i]);
+#endif  // CONFIG_COMPOUND_SINGLEREF
   for (i = 0; i < BLOCK_SIZE_GROUPS; ++i) {
     if (is_interintra_allowed_bsize_group(i))
       fc->interintra_prob[i] = av1_mode_mv_merge_probs(
diff --git a/av1/common/entropymode.h b/av1/common/entropymode.h
index 71be25f..9c3a78d 100644
--- a/av1/common/entropymode.h
+++ b/av1/common/entropymode.h
@@ -34,6 +34,9 @@
 
 #define INTER_OFFSET(mode) ((mode)-NEARESTMV)
 #if CONFIG_EXT_INTER
+#if CONFIG_COMPOUND_SINGLEREF
+#define INTER_SINGLEREF_COMP_OFFSET(mode) ((mode)-SR_NEAREST_NEARMV)
+#endif  // CONFIG_COMPOUND_SINGLEREF
 #define INTER_COMPOUND_OFFSET(mode) ((mode)-NEAREST_NEARESTMV)
 #endif  // CONFIG_EXT_INTER
 
@@ -193,6 +196,10 @@
 #if CONFIG_EXT_INTER
   aom_prob inter_compound_mode_probs[INTER_MODE_CONTEXTS]
                                     [INTER_COMPOUND_MODES - 1];
+#if CONFIG_COMPOUND_SINGLEREF
+  aom_prob inter_singleref_comp_mode_probs[INTER_MODE_CONTEXTS]
+                                          [INTER_SINGLEREF_COMP_MODES - 1];
+#endif  // CONFIG_COMPOUND_SINGLEREF
   aom_prob compound_type_prob[BLOCK_SIZES][COMPOUND_TYPES - 1];
   aom_prob interintra_prob[BLOCK_SIZE_GROUPS];
   aom_prob interintra_mode_prob[BLOCK_SIZE_GROUPS][INTERINTRA_MODES - 1];
@@ -213,6 +220,9 @@
 #else
   aom_prob comp_ref_prob[REF_CONTEXTS][COMP_REFS - 1];
 #endif  // CONFIG_EXT_REFS
+#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+  aom_prob comp_inter_mode_prob[COMP_INTER_MODE_CONTEXTS];
+#endif  // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
   aom_prob tx_size_probs[MAX_TX_DEPTH][TX_SIZE_CONTEXTS][MAX_TX_DEPTH];
 #if CONFIG_VAR_TX
   aom_prob txfm_partition_prob[TXFM_PARTITION_CONTEXTS];
@@ -360,6 +370,10 @@
   unsigned int inter_mode[INTER_MODE_CONTEXTS][INTER_MODES];
 #if CONFIG_EXT_INTER
   unsigned int inter_compound_mode[INTER_MODE_CONTEXTS][INTER_COMPOUND_MODES];
+#if CONFIG_COMPOUND_SINGLEREF
+  unsigned int inter_singleref_comp_mode[INTER_MODE_CONTEXTS]
+                                        [INTER_SINGLEREF_COMP_MODES];
+#endif  // CONFIG_COMPOUND_SINGLEREF
   unsigned int interintra[BLOCK_SIZE_GROUPS][2];
   unsigned int interintra_mode[BLOCK_SIZE_GROUPS][INTERINTRA_MODES];
   unsigned int wedge_interintra[BLOCK_SIZES][2];
@@ -380,6 +394,9 @@
 #else
   unsigned int comp_ref[REF_CONTEXTS][COMP_REFS - 1][2];
 #endif  // CONFIG_EXT_REFS
+#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+  unsigned int comp_inter_mode[COMP_INTER_MODE_CONTEXTS][2];
+#endif  // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
   // TODO(any): tx_size_totals is only used by the encoder to decide whether
   // to use forward updates for the coeff probs, and as such it does not really
   // belong into this structure.
@@ -475,6 +492,10 @@
     av1_interintra_mode_tree[TREE_SIZE(INTERINTRA_MODES)];
 extern const aom_tree_index
     av1_inter_compound_mode_tree[TREE_SIZE(INTER_COMPOUND_MODES)];
+#if CONFIG_COMPOUND_SINGLEREF
+extern const aom_tree_index
+    av1_inter_singleref_comp_mode_tree[TREE_SIZE(INTER_SINGLEREF_COMP_MODES)];
+#endif  // CONFIG_COMPOUND_SINGLEREF
 extern const aom_tree_index av1_compound_type_tree[TREE_SIZE(COMPOUND_TYPES)];
 #endif  // CONFIG_EXT_INTER
 extern const aom_tree_index av1_partition_tree[TREE_SIZE(PARTITION_TYPES)];
diff --git a/av1/common/enums.h b/av1/common/enums.h
index b684eb0..6f00635 100644
--- a/av1/common/enums.h
+++ b/av1/common/enums.h
@@ -321,6 +321,15 @@
   ZEROMV,
   NEWMV,
 #if CONFIG_EXT_INTER
+#if CONFIG_COMPOUND_SINGLEREF
+  // Single ref compound modes
+  SR_NEAREST_NEARMV,
+  SR_NEAREST_NEWMV,
+  SR_NEAR_NEWMV,
+  SR_ZERO_NEWMV,
+  SR_NEW_NEWMV,
+#endif  // CONFIG_COMPOUND_SINGLEREF
+  // Compound ref compound modes
   NEAREST_NEARESTMV,
   NEAREST_NEARMV,
   NEAR_NEARESTMV,
@@ -401,6 +410,10 @@
 #define INTER_MODES (1 + NEWMV - NEARESTMV)
 
 #if CONFIG_EXT_INTER
+#if CONFIG_COMPOUND_SINGLEREF
+#define INTER_SINGLEREF_COMP_MODES (1 + SR_NEW_NEWMV - SR_NEAREST_NEARMV)
+#endif  // CONFIG_COMPOUND_SINGLEREF
+
 #define INTER_COMPOUND_MODES (1 + NEW_NEWMV - NEAREST_NEARESTMV)
 #endif  // CONFIG_EXT_INTER
 
@@ -454,6 +467,9 @@
 #define INTRA_INTER_CONTEXTS 4
 #define COMP_INTER_CONTEXTS 5
 #define REF_CONTEXTS 5
+#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+#define COMP_INTER_MODE_CONTEXTS 4
+#endif  // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
 
 #if CONFIG_VAR_TX
 #define TXFM_PARTITION_CONTEXTS ((TX_SIZES - TX_8X8) * 6 - 2)
diff --git a/av1/common/mvref_common.h b/av1/common/mvref_common.h
index 7c1161d..01f74b7 100644
--- a/av1/common/mvref_common.h
+++ b/av1/common/mvref_common.h
@@ -64,6 +64,13 @@
   3,    // ZEROMV
   1,    // NEWMV
 #if CONFIG_EXT_INTER
+#if CONFIG_COMPOUND_SINGLEREF
+  0,    // SR_NEAREST_NEARMV
+  1,    // SR_NEAREST_NEWMV
+  1,    // SR_NEAR_NEWMV
+  3,    // SR_ZERO_NEWMV
+  1,    // SR_NEW_NEWMV
+#endif  // CONFIG_COMPOUND_SINGLEREF
   0,    // NEAREST_NEARESTMV
   0,    // NEAREST_NEARMV
   0,    // NEAR_NEARESTMV
diff --git a/av1/common/pred_common.c b/av1/common/pred_common.c
index f8041f8..e139e14 100644
--- a/av1/common/pred_common.c
+++ b/av1/common/pred_common.c
@@ -177,6 +177,35 @@
   }
 }
 
+#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+// The compound/single mode info data structure has one element border above and
+// to the left of the entries corresponding to real macroblocks.
+// The prediction flags in these dummy entries are initialized to 0.
+// 0 - single/single
+// 1 - single/--, --/single, --/--
+// 2 - single/comp, comp/single
+// 3 - comp/comp, comp/--, --/comp
+int av1_get_inter_mode_context(const MACROBLOCKD *xd) {
+  const MB_MODE_INFO *const above_mbmi = xd->above_mbmi;
+  const MB_MODE_INFO *const left_mbmi = xd->left_mbmi;
+  const int has_above = xd->up_available;
+  const int has_left = xd->left_available;
+
+  if (has_above && has_left) {  // both edges available (0/2/3)
+    const int above_inter_comp_mode = is_inter_compound_mode(above_mbmi->mode);
+    const int left_inter_comp_mode = is_inter_compound_mode(left_mbmi->mode);
+    return (above_inter_comp_mode && left_inter_comp_mode)
+               ? 3
+               : (above_inter_comp_mode || left_inter_comp_mode) * 2;
+  } else if (has_above || has_left) {  // one edge available (1/3)
+    const MB_MODE_INFO *const edge_mbmi = has_above ? above_mbmi : left_mbmi;
+    return is_inter_compound_mode(edge_mbmi->mode) ? 3 : 1;
+  } else {  // no edge available (1)
+    return 1;
+  }
+}
+#endif  // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+
 #if CONFIG_EXT_REFS
 #define CHECK_BACKWARD_REFS(ref_frame) \
   (((ref_frame) >= BWDREF_FRAME) && ((ref_frame) <= ALTREF_FRAME))
diff --git a/av1/common/pred_common.h b/av1/common/pred_common.h
index 7825f3c..e16ad70 100644
--- a/av1/common/pred_common.h
+++ b/av1/common/pred_common.h
@@ -168,6 +168,15 @@
 }
 #endif  // CONFIG_EXT_REFS
 
+#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+int av1_get_inter_mode_context(const MACROBLOCKD *xd);
+
+static INLINE aom_prob av1_get_inter_mode_prob(const AV1_COMMON *cm,
+                                               const MACROBLOCKD *xd) {
+  return cm->fc->comp_inter_mode_prob[av1_get_inter_mode_context(xd)];
+}
+#endif  // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+
 // Returns a context number for the given MB prediction signal
 // The mode info data structure has a one element border above and to the
 // left of the entries corresponding to real blocks.