JNT_COMP: 1. Init version of experiment JNT_COMP

Enable to assign distance based weight for joint compound prediction.

(w0, w1) are weights for two predictors of different distance to
current frame.

Use 4 bit precision for quantized distance weight. e.g.
the prediction is generated as

value = (w0 * p0 + w1 * p1) >> n
w0 + w1 = (1 << n), n = 4;

Change-Id: Ib0ff0c41c82b9ebb033f498e90c18a03d18969e4
diff --git a/av1/common/common_data.h b/av1/common/common_data.h
index f487bb8..f862d63 100644
--- a/av1/common/common_data.h
+++ b/av1/common/common_data.h
@@ -1933,6 +1933,14 @@
 #define EOB_THRESHOLD_NUM 2
 #endif
 
+#if CONFIG_JNT_COMP
+static const double quant_dist_category[4] = { 1.5, 2.5, 3.5, 255 };
+static const int quant_dist_lookup_table[2][4][2] = {
+  { { 8, 8 }, { 11, 5 }, { 12, 4 }, { 13, 3 } },
+  { { 8, 8 }, { 5, 11 }, { 4, 12 }, { 3, 13 } },
+};
+#endif  // CONFIG_JNT_COMP
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/av1/common/convolve.c b/av1/common/convolve.c
index 5476f59..1aa08a4 100644
--- a/av1/common/convolve.c
+++ b/av1/common/convolve.c
@@ -361,10 +361,27 @@
         sum += y_filter[k] * src_vert[(y - fo_vert + k) * im_stride + x];
       }
       CONV_BUF_TYPE res = ROUND_POWER_OF_TWO(sum, conv_params->round_1);
+#if CONFIG_JNT_COMP
+      if (conv_params->bck_offset == -1) {
+        if (conv_params->do_average)
+          dst[y * dst_stride + x] += res;
+        else
+          dst[y * dst_stride + x] = res;
+      } else {
+        if (conv_params->do_average == 0) {
+          dst[y * dst_stride + x] = res * conv_params->fwd_offset;
+        } else {
+          dst[y * dst_stride + x] += res * conv_params->bck_offset;
+
+          dst[y * dst_stride + x] >>= (DIST_PRECISION_BITS - 1);
+        }
+      }
+#else
       if (conv_params->do_average)
         dst[y * dst_stride + x] += res;
       else
         dst[y * dst_stride + x] = res;
+#endif  // CONFIG_JNT_COMP
     }
   }
 }
@@ -419,10 +436,27 @@
         sum += y_filter[k] * src_y[(k - fo_vert) * im_stride];
       }
       CONV_BUF_TYPE res = ROUND_POWER_OF_TWO(sum, conv_params->round_1);
+#if CONFIG_JNT_COMP
+      if (conv_params->bck_offset == -1) {
+        if (conv_params->do_average)
+          dst[y * dst_stride + x] += res;
+        else
+          dst[y * dst_stride + x] = res;
+      } else {
+        if (conv_params->do_average == 0) {
+          dst[y * dst_stride + x] = res * conv_params->fwd_offset;
+        } else {
+          dst[y * dst_stride + x] += res * conv_params->bck_offset;
+
+          dst[y * dst_stride + x] >>= (DIST_PRECISION_BITS - 1);
+        }
+      }
+#else
       if (conv_params->do_average)
         dst[y * dst_stride + x] += res;
       else
         dst[y * dst_stride + x] = res;
+#endif  // CONFIG_JNT_COMP
     }
     src_vert++;
   }
@@ -481,10 +515,27 @@
       CONV_BUF_TYPE res = ROUND_POWER_OF_TWO(sum, conv_params->round_1) -
                           ((1 << (offset_bits - conv_params->round_1)) +
                            (1 << (offset_bits - conv_params->round_1 - 1)));
+#if CONFIG_JNT_COMP
+      if (conv_params->fwd_offset == -1) {
+        if (conv_params->do_average)
+          dst[y * dst_stride + x] += res;
+        else
+          dst[y * dst_stride + x] = res;
+      } else {
+        if (conv_params->do_average) {
+          dst[y * dst_stride + x] += res * conv_params->bck_offset;
+
+          dst[y * dst_stride + x] >>= (DIST_PRECISION_BITS - 1);
+        } else {
+          dst[y * dst_stride + x] = res * conv_params->fwd_offset;
+        }
+      }
+#else
       if (conv_params->do_average)
         dst[y * dst_stride + x] += res;
       else
         dst[y * dst_stride + x] = res;
+#endif  // CONFIG_JNT_COMP
     }
   }
 }
@@ -545,10 +596,27 @@
       CONV_BUF_TYPE res = ROUND_POWER_OF_TWO(sum, conv_params->round_1) -
                           ((1 << (offset_bits - conv_params->round_1)) +
                            (1 << (offset_bits - conv_params->round_1 - 1)));
+#if CONFIG_JNT_COMP
+      if (conv_params->fwd_offset == -1) {
+        if (conv_params->do_average)
+          dst[y * dst_stride + x] += res;
+        else
+          dst[y * dst_stride + x] = res;
+      } else {
+        if (conv_params->do_average) {
+          dst[y * dst_stride + x] += res * conv_params->bck_offset;
+
+          dst[y * dst_stride + x] >>= (DIST_PRECISION_BITS - 1);
+        } else {
+          dst[y * dst_stride + x] = res * conv_params->fwd_offset;
+        }
+      }
+#else
       if (conv_params->do_average)
         dst[y * dst_stride + x] += res;
       else
         dst[y * dst_stride + x] = res;
+#endif  // CONFIG_JNT_COMP
     }
     src_vert++;
   }
@@ -584,7 +652,19 @@
     transpose_int32(tr_dst, tr_dst_stride, conv_params->dst,
                     conv_params->dst_stride, w, h);
 
-    // horizontal and vertical parameters are swapped because of the transpose
+// horizontal and vertical parameters are swapped because of the transpose
+#if CONFIG_JNT_COMP
+    if (scaled)
+      av1_convolve_2d_scale_c(tr_src + fo_horiz * tr_src_stride + fo_vert,
+                              tr_src_stride, tr_dst, tr_dst_stride, h, w,
+                              &filter_params_y, &filter_params_x, subpel_y_q4,
+                              y_step_q4, subpel_x_q4, x_step_q4, conv_params);
+    else
+      av1_convolve_2d_c(tr_src + fo_horiz * tr_src_stride + fo_vert,
+                        tr_src_stride, tr_dst, tr_dst_stride, h, w,
+                        &filter_params_y, &filter_params_x, subpel_y_q4,
+                        subpel_x_q4, conv_params);
+#else
     if (scaled)
       av1_convolve_2d_scale(tr_src + fo_horiz * tr_src_stride + fo_vert,
                             tr_src_stride, tr_dst, tr_dst_stride, h, w,
@@ -595,9 +675,22 @@
                       tr_src_stride, tr_dst, tr_dst_stride, h, w,
                       &filter_params_y, &filter_params_x, subpel_y_q4,
                       subpel_x_q4, conv_params);
+#endif  // CONFIG_JNT_COMP
     transpose_int32(conv_params->dst, conv_params->dst_stride, tr_dst,
                     tr_dst_stride, h, w);
   } else {
+#if CONFIG_JNT_COMP
+    if (scaled)
+      av1_convolve_2d_scale_c(src, src_stride, conv_params->dst,
+                              conv_params->dst_stride, w, h, &filter_params_x,
+                              &filter_params_y, subpel_x_q4, x_step_q4,
+                              subpel_y_q4, y_step_q4, conv_params);
+    else
+      av1_convolve_2d_c(src, src_stride, conv_params->dst,
+                        conv_params->dst_stride, w, h, &filter_params_x,
+                        &filter_params_y, subpel_x_q4, subpel_y_q4,
+                        conv_params);
+#else
     if (scaled)
       av1_convolve_2d_scale(src, src_stride, conv_params->dst,
                             conv_params->dst_stride, w, h, &filter_params_x,
@@ -607,6 +700,7 @@
       av1_convolve_2d(src, src_stride, conv_params->dst,
                       conv_params->dst_stride, w, h, &filter_params_x,
                       &filter_params_y, subpel_x_q4, subpel_y_q4, conv_params);
+#endif  // CONFIG_JNT_COMP
   }
 }
 
diff --git a/av1/common/convolve.h b/av1/common/convolve.h
index c43f649..61f290a 100644
--- a/av1/common/convolve.h
+++ b/av1/common/convolve.h
@@ -35,6 +35,10 @@
   int round_1;
   int plane;
   int do_post_rounding;
+#if CONFIG_JNT_COMP
+  int fwd_offset;
+  int bck_offset;
+#endif
 } ConvolveParams;
 
 static INLINE ConvolveParams get_conv_params(int ref, int do_average,
diff --git a/av1/common/enums.h b/av1/common/enums.h
index 91f1f16..5e2e815 100644
--- a/av1/common/enums.h
+++ b/av1/common/enums.h
@@ -103,6 +103,16 @@
 #define USE_LOOP_FILTER_SUPERBLOCK 1
 #endif  // CONFIG_LPF_SB
 
+#if CONFIG_JNT_COMP
+typedef enum COMPOUND_DIST_WEIGHT_MODE {
+  DIST,
+} COMPOUND_DIST_WEIGHT_MODE;
+
+#define COMPOUND_WEIGHT_MODE DIST
+#define DIST_PRECISION_BITS 4
+#define DIST_PRECISION (1 << DIST_PRECISION_BITS)  // 16
+#endif                                             // CONFIG_JNT_COMP
+
 // Bitstream profiles indicated by 2-3 bits in the uncompressed header.
 // 00: Profile 0.  8-bit 4:2:0 only.
 // 10: Profile 1.  8-bit 4:4:4, 4:2:2, and 4:4:0.
diff --git a/av1/common/reconinter.c b/av1/common/reconinter.c
index 5eba691..30e1d72 100644
--- a/av1/common/reconinter.c
+++ b/av1/common/reconinter.c
@@ -1104,6 +1104,60 @@
   int subpel_y;
 } SubpelParams;
 
+#if CONFIG_JNT_COMP
+static void jnt_comp_weight_assign(const AV1_COMMON *cm,
+                                   const MB_MODE_INFO *mbmi,
+                                   ConvolveParams *conv_params,
+                                   int is_compound) {
+  if (is_compound) {
+    int bck_idx = cm->frame_refs[mbmi->ref_frame[0] - LAST_FRAME].idx;
+    int fwd_idx = cm->frame_refs[mbmi->ref_frame[1] - LAST_FRAME].idx;
+    int bck_frame_index = 0, fwd_frame_index = 0;
+    int cur_frame_index = cm->cur_frame->cur_frame_offset;
+
+    if (bck_idx >= 0) {
+      bck_frame_index = cm->buffer_pool->frame_bufs[bck_idx].cur_frame_offset;
+    }
+
+    if (fwd_idx >= 0) {
+      fwd_frame_index = cm->buffer_pool->frame_bufs[fwd_idx].cur_frame_offset;
+    }
+
+    conv_params->bck_offset = abs(cur_frame_index - bck_frame_index);
+    conv_params->fwd_offset = abs(fwd_frame_index - cur_frame_index);
+
+    const double fwd = abs(fwd_frame_index - cur_frame_index);
+    const double bck = abs(cur_frame_index - bck_frame_index);
+    int order;
+    double ratio;
+
+    if (COMPOUND_WEIGHT_MODE == DIST) {
+      if (fwd > bck) {
+        ratio = (bck != 0) ? fwd / bck : 5.0;
+        order = 0;
+      } else {
+        ratio = (fwd != 0) ? bck / fwd : 5.0;
+        order = 1;
+      }
+      int quant_dist_idx;
+      for (quant_dist_idx = 0; quant_dist_idx < 4; ++quant_dist_idx) {
+        if (ratio < quant_dist_category[quant_dist_idx]) break;
+      }
+      conv_params->fwd_offset =
+          quant_dist_lookup_table[0][quant_dist_idx][order];
+      conv_params->bck_offset =
+          quant_dist_lookup_table[0][quant_dist_idx][1 - order];
+    } else {
+      conv_params->fwd_offset = (DIST_PRECISION >> 1);
+      conv_params->bck_offset = (DIST_PRECISION >> 1);
+    }
+  } else {
+    conv_params->bck_offset = -1;
+    conv_params->fwd_offset = -1;
+  }
+}
+#endif  // CONFIG_JNT_COMP
+
 static INLINE void build_inter_predictors(
     const AV1_COMMON *cm, MACROBLOCKD *xd, int plane,
 #if CONFIG_MOTION_VAR
@@ -1194,6 +1248,10 @@
 #else
         ConvolveParams conv_params = get_conv_params(0, 0, plane);
 #endif
+#if CONFIG_JNT_COMP
+        conv_params.fwd_offset = -1;
+        conv_params.bck_offset = -1;
+#endif  // CONFIG_JNT_COMP
         struct buf_2d *const dst_buf = &pd->dst;
         x = x_base + idx;
         y = y_base + idy;
@@ -1425,6 +1483,10 @@
 #if CONFIG_CONVOLVE_ROUND
     ConvolveParams conv_params =
         get_conv_params_no_round(ref, ref, plane, tmp_dst, MAX_SB_SIZE);
+#if CONFIG_JNT_COMP
+    jnt_comp_weight_assign(cm, &mi->mbmi, &conv_params, is_compound);
+#endif  // CONFIG_JNT_COMP
+
 #else
     ConvolveParams conv_params = get_conv_params(ref, ref, plane);
 #endif  // CONFIG_CONVOLVE_ROUND