ncobmc-adapt-weight: add recon functions

Change-Id: Iebc527697548355ea2e92e2fbc2faa46f16ef0db
diff --git a/av1/common/reconinter.c b/av1/common/reconinter.c
index 5eae3be..3cfa5d2 100644
--- a/av1/common/reconinter.c
+++ b/av1/common/reconinter.c
@@ -10,6 +10,7 @@
  */
 
 #include <assert.h>
+#include <stdio.h>
 
 #include "./aom_scale_rtcd.h"
 #include "./aom_dsp_rtcd.h"
@@ -2442,7 +2443,9 @@
                                           int tmp_height[MAX_MB_PLANE],
                                           int tmp_stride[MAX_MB_PLANE]) {
   const TileInfo *const tile = &xd->tile;
+#if CONFIG_DEBUG
   BLOCK_SIZE bsize = xd->mi[0]->mbmi.sb_type;
+#endif
   int i, j, mi_step, ref;
   const int ilimit = AOMMIN(xd->n8_w, cm->mi_cols - mi_col);
   int mb_to_right_edge_base = xd->mb_to_right_edge;
@@ -2495,12 +2498,12 @@
     xd->mb_to_right_edge =
         mb_to_right_edge_base + (xd->n8_w - i - mi_step) * 64;
     mi_x = (mi_col + i) << MI_SIZE_LOG2;
-    mi_y = (mi_row << MI_SIZE_LOG2) + xd->n8_h * 4;
+    mi_y = (mi_row << MI_SIZE_LOG2) + xd->n8_h * (MI_SIZE >> 1);
 
     for (j = 0; j < MAX_MB_PLANE; ++j) {
       const struct macroblockd_plane *pd = &xd->plane[j];
       bw = (mi_step << MI_SIZE_LOG2) >> pd->subsampling_x;
-      bh = (num_4x4_blocks_high_lookup[bsize] << 1) >> pd->subsampling_y;
+      bh = (xd->n8_h << (MI_SIZE_LOG2 - 1)) >> pd->subsampling_y;
 
       if (mbmi->sb_type < BLOCK_8X8 && !CONFIG_CB4X4) {
         const PARTITION_TYPE bp = BLOCK_8X8 - mbmi->sb_type;
@@ -2551,7 +2554,9 @@
                                          int tmp_height[MAX_MB_PLANE],
                                          const int tmp_stride[MAX_MB_PLANE]) {
   const TileInfo *const tile = &xd->tile;
+#if CONFIG_DEBUG
   BLOCK_SIZE bsize = xd->mi[0]->mbmi.sb_type;
+#endif
   int i, j, mi_step, ref;
   const int ilimit = AOMMIN(xd->n8_h, cm->mi_rows - mi_row);
   int mb_to_bottom_edge_base = xd->mb_to_bottom_edge;
@@ -2560,6 +2565,8 @@
       (mi_col + xd->n8_w) % MI_SIZE == 0 || (mi_col + xd->n8_w) >= cm->mi_cols)
     return;
 
+  assert(bsize >= BLOCK_8X8);
+
   xd->mb_to_left_edge -= xd->n8_w * 32;
   for (i = 0; i < ilimit; i += mi_step) {
     int mi_row_offset = i;
@@ -2602,12 +2609,12 @@
     xd->mb_to_top_edge = -(((mi_row + i) * MI_SIZE) * 8);
     xd->mb_to_bottom_edge =
         mb_to_bottom_edge_base + (xd->n8_h - i - mi_step) * 64;
-    mi_x = (mi_col << MI_SIZE_LOG2) + xd->n8_w * 4;
+    mi_x = (mi_col << MI_SIZE_LOG2) + xd->n8_w * (MI_SIZE >> 1);
     mi_y = (mi_row + i) << MI_SIZE_LOG2;
 
     for (j = 0; j < MAX_MB_PLANE; ++j) {
       const struct macroblockd_plane *pd = &xd->plane[j];
-      bw = (num_4x4_blocks_wide_lookup[bsize] << 1) >> pd->subsampling_x;
+      bw = (xd->n8_w << (MI_SIZE_LOG2 - 1)) >> pd->subsampling_x;
       bh = (mi_step << MI_SIZE_LOG2) >> pd->subsampling_y;
 
       if (mbmi->sb_type < BLOCK_8X8 && !CONFIG_CB4X4) {
@@ -2818,6 +2825,31 @@
                        mi_col);
 }
 #endif  // CONFIG_NCOBMC
+
+#if CONFIG_NCOBMC_ADAPT_WEIGHT
+void reset_xd_boundary(MACROBLOCKD *xd, int mi_row, int bh, int mi_col, int bw,
+                       int mi_rows, int mi_cols) {
+  xd->mb_to_top_edge = -((mi_row * MI_SIZE) * 8);
+  xd->mb_to_bottom_edge = ((mi_rows - bh - mi_row) * MI_SIZE) * 8;
+  xd->mb_to_left_edge = -((mi_col * MI_SIZE) * 8);
+  xd->mb_to_right_edge = ((mi_cols - bw - mi_col) * MI_SIZE) * 8;
+}
+void set_sb_mi_boundaries(const AV1_COMMON *const cm, MACROBLOCKD *const xd,
+                          const int mi_row, const int mi_col) {
+  const BLOCK_SIZE sb = cm->sb_size;
+  const int num_mi_w = mi_size_wide[sb];
+  const int num_mi_h = mi_size_high[sb];
+
+  xd->sb_mi_bd.mi_col_begin = mi_col;
+  xd->sb_mi_bd.mi_row_begin = mi_row;
+  // points to the last mi
+  xd->sb_mi_bd.mi_col_end =
+      mi_col + num_mi_w > cm->mi_cols ? cm->mi_cols - 1 : mi_col + num_mi_w - 1;
+  xd->sb_mi_bd.mi_row_end =
+      mi_row + num_mi_h > cm->mi_rows ? cm->mi_rows - 1 : mi_row + num_mi_h - 1;
+}
+#endif
+
 #endif  // CONFIG_MOTION_VAR
 
 #if CONFIG_EXT_INTER
@@ -3370,3 +3402,715 @@
   }
 }
 #endif  // CONFIG_EXT_INTER
+#if CONFIG_NCOBMC_ADAPT_WEIGHT
+
+void alloc_ncobmc_pred_buffer(MACROBLOCKD *const xd) {
+  int i;
+  // allocate interpolated prediction buffer
+  for (i = 0; i < MAX_MB_PLANE; ++i) {
+    xd->ncobmc_pred_buf[i] = (uint8_t *)malloc(sizeof(uint8_t) * MAX_SB_SQUARE);
+    av1_zero_array(xd->ncobmc_pred_buf[i], MAX_SB_SQUARE);
+    xd->ncobmc_pred_buf_stride[i] = MAX_SB_SIZE;
+  }
+}
+
+void free_ncobmc_pred_buffer(MACROBLOCKD *const xd) {
+  for (int i = 0; i < MAX_MB_PLANE; ++i) free(xd->ncobmc_pred_buf[i]);
+}
+
+void get_pred_from_intrpl_buf(MACROBLOCKD *xd, int mi_row, int mi_col,
+                              BLOCK_SIZE bsize, int plane) {
+  uint8_t *dst = xd->plane[plane].dst.buf;
+  int ds = xd->plane[plane].dst.stride;
+  int ss_x = xd->plane[plane].subsampling_x;
+  int ss_y = xd->plane[plane].subsampling_y;
+
+  const int ip_wide = mi_size_wide[bsize] * MI_SIZE >> ss_x;
+  const int ip_high = mi_size_high[bsize] * MI_SIZE >> ss_y;
+  // relative coordinates of this MI in the superblock
+  int row_rlt = (mi_row - xd->sb_mi_bd.mi_row_begin) * MI_SIZE >> ss_y;
+  int col_rlt = (mi_col - xd->sb_mi_bd.mi_col_begin) * MI_SIZE >> ss_x;
+  int s = xd->ncobmc_pred_buf_stride[plane];
+  int r, c;
+
+  for (r = 0; r < ip_high; ++r) {
+    for (c = 0; c < ip_wide; ++c) {
+      dst[r * ds + c] =
+          xd->ncobmc_pred_buf[plane][(r + row_rlt) * s + c + col_rlt];
+    }
+  }
+}
+// scaling factors for ncobmc kernels
+#define KERNEL_SCALE_LOG 14
+
+void build_ncobmc_intrpl_pred(const AV1_COMMON *const cm, MACROBLOCKD *xd,
+                              int plane, int pxl_row, int pxl_col,
+                              BLOCK_SIZE bsize, uint8_t *preds[][MAX_MB_PLANE],
+                              int stride[MAX_MB_PLANE],  // pred buffer strides
+                              int mode) {
+  const ADAPT_OVERLAP_BLOCK ao_block = adapt_overlap_block_lookup[bsize];
+  const NCOBMC_KERNELS *const knls = &cm->ncobmc_kernels[ao_block][mode];
+  const int wide = mi_size_wide[bsize] * MI_SIZE;
+  const int high = mi_size_high[bsize] * MI_SIZE;
+  const int s = stride[plane];
+  const int ss_x = xd->plane[plane].subsampling_x;
+  const int ss_y = xd->plane[plane].subsampling_y;
+  int row_offset = (pxl_row - xd->sb_mi_bd.mi_row_begin * MI_SIZE) >> ss_y;
+  int col_offset = (pxl_col - xd->sb_mi_bd.mi_col_begin * MI_SIZE) >> ss_x;
+  int dst_stride = xd->ncobmc_pred_buf_stride[plane];
+  int dst_offset = row_offset * dst_stride + col_offset;
+
+#if CONFIG_HIGHBITDEPTH
+  const int is_hbd = (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) ? 1 : 0;
+#else
+  const int is_hbd = 0;
+#endif  // CONFIG_HIGHBITDEPTH
+
+  int r, c, k_r, k_c;
+  int64_t tmp;
+
+  for (r = 0; r < (high >> ss_x); ++r) {
+    for (c = 0; c < (wide >> ss_y); ++c) {
+      int pos = r * s + c;
+      int q_tmp;
+      uint8_t val;
+
+      // TODO(weitinglin): find out the optimal sub-sampling patterns for
+      //                   chroma
+      k_r = (r << ss_y) + ss_y;
+      k_c = (c << ss_x) + ss_x;
+      if (ss_y && k_r >= high) k_r -= 1;
+      if (ss_x && k_c >= wide) k_c -= 1;
+
+      if (!is_hbd) {
+        uint8_t *tmp_p[4];
+        int i;
+        for (i = 0; i < 4; ++i) tmp_p[i] = preds[i][plane];
+
+        tmp = (int64_t)knls->KERNEL_TL[k_r][k_c] * tmp_p[0][pos] +
+              (int64_t)knls->KERNEL_TR[k_r][k_c] * tmp_p[1][pos] +
+              (int64_t)knls->KERNEL_BL[k_r][k_c] * tmp_p[2][pos] +
+              (int64_t)knls->KERNEL_BR[k_r][k_c] * tmp_p[3][pos];
+      } else {
+        uint16_t *tmp_p[4];
+        int i;
+        for (i = 0; i < 4; ++i) tmp_p[i] = CONVERT_TO_SHORTPTR(preds[i][plane]);
+
+        tmp = (int64_t)knls->KERNEL_TL[k_r][k_c] * tmp_p[0][pos] +
+              (int64_t)knls->KERNEL_TR[k_r][k_c] * tmp_p[1][pos] +
+              (int64_t)knls->KERNEL_BL[k_r][k_c] * tmp_p[2][pos] +
+              (int64_t)knls->KERNEL_BR[k_r][k_c] * tmp_p[3][pos];
+      }
+
+      q_tmp = (tmp <= 0) ? 0 : ROUND_POWER_OF_TWO(tmp, KERNEL_SCALE_LOG);
+      val = clip_pixel(q_tmp);
+
+      xd->ncobmc_pred_buf[plane][r * dst_stride + c + dst_offset] = val;
+
+      assert(r * dst_stride + c + dst_offset < MAX_SB_SQUARE);
+    }
+  }
+}
+
+void get_pred_by_horz_neighbor(const AV1_COMMON *cm, MACROBLOCKD *xd, int bsize,
+                               int mi_row, int mi_col,
+                               uint8_t *dst_buf[MAX_MB_PLANE],
+                               int dst_stride[MAX_MB_PLANE]) {
+  const TileInfo *const tile = &xd->tile;
+  const int mb_to_bottom_edge_base = xd->mb_to_bottom_edge;
+  const int mb_to_top_edge_base = xd->mb_to_top_edge;
+  const int mb_to_left_edge_base = xd->mb_to_left_edge;
+  const int mb_to_right_edge_base = xd->mb_to_right_edge;
+  int overlappable_offset = -1;
+  const int mi_nums = AOMMIN(mi_size_high[bsize], cm->mi_rows - mi_row);
+
+  int i, j, mi_step, ref;
+
+  xd->mb_to_right_edge += mi_size_wide[bsize] * MI_SIZE * 4;
+
+  // build from left neighbors
+  for (i = 0; i < mi_nums; i += mi_step) {
+    int mi_row_offset = i;
+    int mi_col_offset = -1;
+    int mi_x, mi_y, bw, bh;
+    MODE_INFO *left_mi;
+    MB_MODE_INFO *left_mbmi, backup_mbmi;
+    BLOCK_SIZE l_bsize;
+
+    // create the original prediction if offset exceeds the boundary
+    if (mi_col == 0 || (mi_col - 1 < tile->mi_col_start)) mi_col_offset = 0;
+
+    left_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
+    left_mbmi = &left_mi->mbmi;
+    l_bsize = AOMMAX(left_mbmi->sb_type, BLOCK_8X8);
+
+    mi_step = AOMMIN(xd->n8_h, mi_size_high[l_bsize]);
+
+    // reset the mi if it is not overlappble
+    if (!is_neighbor_overlappable(left_mbmi)) {
+      // use left_mbmi->sb_type instead of l_bsize to handle
+      // sub8x8 cases
+      int search_mi_step = mi_size_high[left_mbmi->sb_type];
+      while (!is_neighbor_overlappable(left_mbmi)) {
+        mi_row_offset += search_mi_step;
+        if (mi_row_offset < mi_nums) {
+          left_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
+          left_mbmi = &left_mi->mbmi;
+          search_mi_step = mi_size_high[left_mbmi->sb_type];
+        } else {
+          if (overlappable_offset >= 0) {
+            mi_row_offset = overlappable_offset;
+          } else {
+            mi_row_offset = 0;
+            mi_col_offset = 0;
+          }
+          left_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
+          left_mbmi = &left_mi->mbmi;
+          break;
+        }
+      }
+    } else {
+      // update the available overlappable mi
+      overlappable_offset = mi_row_offset;
+    }
+
+    backup_mbmi = *left_mbmi;
+    modify_neighbor_predictor_for_obmc(left_mbmi);
+
+    for (j = 0; j < MAX_MB_PLANE; ++j) {
+      struct macroblockd_plane *const pd = &xd->plane[j];
+      setup_pred_plane(&pd->dst, l_bsize, dst_buf[j], MAX_SB_SIZE, MAX_SB_SIZE,
+                       dst_stride[j], i, 0, NULL, pd->subsampling_x,
+                       pd->subsampling_y);
+    }
+#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+    for (ref = 0; ref < 1 + (is_inter_anyref_comp_mode(left_mbmi->mode));
+         ++ref) {
+      const MV_REFERENCE_FRAME frame = has_second_ref(left_mbmi)
+                                           ? left_mbmi->ref_frame[ref]
+                                           : left_mbmi->ref_frame[0];
+#else   // !(CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF)
+    for (ref = 0; ref < 1 + has_second_ref(left_mbmi); ++ref) {
+      const MV_REFERENCE_FRAME frame = left_mbmi->ref_frame[ref];
+#endif  // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+      const RefBuffer *const ref_buf = &cm->frame_refs[frame - LAST_FRAME];
+
+      xd->block_refs[ref] = ref_buf;
+      if ((!av1_is_valid_scale(&ref_buf->sf)))
+        aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM,
+                           "Reference frame has invalid dimensions");
+      av1_setup_pre_planes(xd, ref, ref_buf->buf, mi_row + i, mi_col,
+                           &ref_buf->sf);
+    }
+    xd->mb_to_top_edge = -((mi_row + i) * MI_SIZE * 8);
+    xd->mb_to_bottom_edge =
+        mb_to_bottom_edge_base + (mi_nums - i - mi_step) * MI_SIZE * 8;
+    mi_x = mi_col << MI_SIZE_LOG2;
+    mi_y = (mi_row + i) << MI_SIZE_LOG2;
+
+    for (j = 0; j < MAX_MB_PLANE; ++j) {
+      const struct macroblockd_plane *pd = &xd->plane[j];
+      bw = mi_size_wide[bsize] << (MI_SIZE_LOG2 - 1) >> pd->subsampling_x;
+      bh = (mi_step << MI_SIZE_LOG2) >> pd->subsampling_y;
+
+      build_inter_predictors(cm, xd, j, mi_col_offset, mi_row_offset, 0, bw, bh,
+                             0, 0, bw, bh,
+#if CONFIG_SUPERTX && CONFIG_EXT_INTER
+                             0, 0,
+#endif  // CONFIG_SUPERTX && CONFIG_EXT_INTER
+                             mi_x, mi_y);
+    }
+    *left_mbmi = backup_mbmi;
+  }
+
+  // build from right neighbors
+  xd->mb_to_right_edge = mb_to_right_edge_base;
+  xd->mb_to_left_edge -= mi_size_wide[bsize] * MI_SIZE * 4;
+
+  overlappable_offset = -1;
+
+  for (i = 0; i < mi_nums; i += mi_step) {
+    int mi_row_offset = i;
+    int mi_col_offset = mi_size_wide[bsize];
+    int mi_x, mi_y, bw, bh;
+    int mi_col_shift = mi_size_wide[bsize] >> 1;
+    MODE_INFO *right_mi;
+    MB_MODE_INFO *right_mbmi, backup_mbmi;
+    BLOCK_SIZE r_bsize;
+
+    // create the original prediction if offset exceeds the boundary
+    if (mi_col + mi_col_offset > xd->sb_mi_bd.mi_col_end) mi_col_offset = 0;
+
+    right_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
+    right_mbmi = &right_mi->mbmi;
+    r_bsize = AOMMAX(right_mbmi->sb_type, BLOCK_8X8);
+
+    mi_step = AOMMIN(mi_nums, mi_size_high[r_bsize]);
+
+    if (!is_neighbor_overlappable(right_mbmi)) {
+      int search_mi_step = mi_size_high[right_mbmi->sb_type];
+      while (!is_neighbor_overlappable(right_mbmi)) {
+        mi_row_offset += search_mi_step;
+        if (mi_row_offset < mi_nums) {
+          right_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
+          right_mbmi = &right_mi->mbmi;
+          search_mi_step = mi_size_high[right_mbmi->sb_type];
+        } else {
+          if (overlappable_offset >= 0) {
+            mi_row_offset = overlappable_offset;
+          } else {
+            mi_row_offset = 0;
+            mi_col_offset = 0;
+          }
+          right_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
+          right_mbmi = &right_mi->mbmi;
+          break;
+        }
+      }
+    } else {
+      overlappable_offset = mi_row_offset;
+    }
+
+    backup_mbmi = *right_mbmi;
+    modify_neighbor_predictor_for_obmc(right_mbmi);
+
+    for (j = 0; j < MAX_MB_PLANE; ++j) {
+      struct macroblockd_plane *const pd = &xd->plane[j];
+      setup_pred_plane(&pd->dst, r_bsize, dst_buf[j], MAX_SB_SIZE, MAX_SB_SIZE,
+                       dst_stride[j], i, mi_col_shift, NULL, pd->subsampling_x,
+                       pd->subsampling_y);
+    }
+#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+    for (ref = 0; ref < 1 + (is_inter_anyref_comp_mode(right_mbmi->mode));
+         ++ref) {
+      const MV_REFERENCE_FRAME frame = has_second_ref(right_mbmi)
+                                           ? right_mbmi->ref_frame[ref]
+                                           : right_mbmi->ref_frame[0];
+#else   // !(CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF)
+    for (ref = 0; ref < 1 + has_second_ref(right_mbmi); ++ref) {
+      const MV_REFERENCE_FRAME frame = right_mbmi->ref_frame[ref];
+#endif  // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+      const RefBuffer *const ref_buf = &cm->frame_refs[frame - LAST_FRAME];
+      xd->block_refs[ref] = ref_buf;
+      if ((!av1_is_valid_scale(&ref_buf->sf)))
+        aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM,
+                           "Reference frame has invalid dimensions");
+      av1_setup_pre_planes(xd, ref, ref_buf->buf, mi_row + i,
+                           mi_col + mi_col_shift, &ref_buf->sf);
+    }
+    xd->mb_to_top_edge = -((mi_row + i) * MI_SIZE * 8);
+    xd->mb_to_bottom_edge =
+        mb_to_bottom_edge_base + (mi_nums - i - mi_step) * MI_SIZE * 8;
+    mi_x = (mi_col + mi_col_shift) << MI_SIZE_LOG2;
+    mi_y = (mi_row + i) << MI_SIZE_LOG2;
+
+    for (j = 0; j < MAX_MB_PLANE; ++j) {
+      const struct macroblockd_plane *pd = &xd->plane[j];
+      bw = mi_size_wide[bsize] << (MI_SIZE_LOG2 - 1) >> pd->subsampling_x;
+      bh = (mi_step << MI_SIZE_LOG2) >> pd->subsampling_y;
+
+      build_inter_predictors(cm, xd, j, mi_col_offset, mi_row_offset, 0, bw, bh,
+                             0, 0, bw, bh,
+#if CONFIG_SUPERTX && CONFIG_EXT_INTER
+                             0, 0,
+#endif  // CONFIG_SUPERTX && CONFIG_EXT_INTER
+                             mi_x, mi_y);
+    }
+
+    *right_mbmi = backup_mbmi;
+  }
+
+  // restore the boundaries
+  xd->mb_to_top_edge = mb_to_top_edge_base;
+  xd->mb_to_bottom_edge = mb_to_bottom_edge_base;
+  xd->mb_to_left_edge = mb_to_left_edge_base;
+  xd->mb_to_right_edge = mb_to_right_edge_base;
+}
+
+void get_pred_by_vert_neighbor(const AV1_COMMON *cm, MACROBLOCKD *xd, int bsize,
+                               int mi_row, int mi_col,
+                               uint8_t *dst_buf[MAX_MB_PLANE],
+                               int dst_stride[MAX_MB_PLANE]) {
+  const TileInfo *const tile = &xd->tile;
+  const int mb_to_bottom_edge_base = xd->mb_to_bottom_edge;
+  const int mb_to_top_edge_base = xd->mb_to_top_edge;
+  const int mb_to_left_edge_base = xd->mb_to_left_edge;
+  const int mb_to_right_edge_base = xd->mb_to_right_edge;
+  int overlappable_offset = -1;
+  const int mi_nums = AOMMIN(mi_size_wide[bsize], cm->mi_cols - mi_col);
+
+  int i, j, mi_step, ref;
+
+  xd->mb_to_bottom_edge += mi_nums * MI_SIZE * 4;
+
+  // build from above neighbors
+  for (i = 0; i < mi_nums; i += mi_step) {
+    int mi_row_offset = -1;
+    int mi_col_offset = i;
+    int mi_x, mi_y, bw, bh;
+    MODE_INFO *above_mi;
+    MB_MODE_INFO *above_mbmi, backup_mbmi;
+    BLOCK_SIZE a_bsize;
+
+    // create the original prediction if offset exceeds the boundary
+    if (mi_row <= tile->mi_row_start) mi_row_offset = 0;
+
+    above_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
+    above_mbmi = &above_mi->mbmi;
+    a_bsize = AOMMAX(above_mbmi->sb_type, BLOCK_8X8);
+
+    mi_step = AOMMIN(mi_nums, mi_size_high[a_bsize]);
+
+    // reset the mi if it is not overlappble
+    if (!is_neighbor_overlappable(above_mbmi)) {
+      int search_mi_step = mi_size_high[above_mbmi->sb_type];
+      // backward search
+      while (!is_neighbor_overlappable(above_mbmi)) {
+        mi_col_offset += search_mi_step;
+        if (mi_col_offset < mi_nums) {
+          above_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
+          above_mbmi = &above_mi->mbmi;
+          search_mi_step = mi_size_high[above_mbmi->sb_type];
+        } else {
+          if (overlappable_offset >= 0) {
+            mi_col_offset = overlappable_offset;
+          } else {
+            mi_row_offset = 0;
+            mi_col_offset = 0;
+          }
+          above_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
+          above_mbmi = &above_mi->mbmi;
+          break;
+        }
+      }
+    } else {
+      // update the available overlappable mi
+      overlappable_offset = mi_col_offset;
+    }
+
+    backup_mbmi = *above_mbmi;
+    modify_neighbor_predictor_for_obmc(above_mbmi);
+
+    for (j = 0; j < MAX_MB_PLANE; ++j) {
+      struct macroblockd_plane *const pd = &xd->plane[j];
+      setup_pred_plane(&pd->dst, a_bsize, dst_buf[j], MAX_SB_SIZE, MAX_SB_SIZE,
+                       dst_stride[j], 0, i, NULL, pd->subsampling_x,
+                       pd->subsampling_y);
+    }
+#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+    for (ref = 0; ref < 1 + (is_inter_anyref_comp_mode(above_mbmi->mode));
+         ++ref) {
+      const MV_REFERENCE_FRAME frame = has_second_ref(above_mbmi)
+                                           ? above_mbmi->ref_frame[ref]
+                                           : above_mbmi->ref_frame[0];
+#else   // !(CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF)
+    for (ref = 0; ref < 1 + has_second_ref(above_mbmi); ++ref) {
+      const MV_REFERENCE_FRAME frame = above_mbmi->ref_frame[ref];
+#endif  // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+      const RefBuffer *const ref_buf = &cm->frame_refs[frame - LAST_FRAME];
+
+      xd->block_refs[ref] = ref_buf;
+      if ((!av1_is_valid_scale(&ref_buf->sf)))
+        aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM,
+                           "Reference frame has invalid dimensions");
+      av1_setup_pre_planes(xd, ref, ref_buf->buf, mi_row, mi_col + i,
+                           &ref_buf->sf);
+    }
+
+    xd->mb_to_left_edge = -(((mi_col + i) * MI_SIZE) * 8);
+    xd->mb_to_right_edge =
+        mb_to_right_edge_base + (mi_nums - i - mi_step) * MI_SIZE * 8;
+    mi_x = (mi_col + i) << MI_SIZE_LOG2;
+    mi_y = mi_row << MI_SIZE_LOG2;
+
+    for (j = 0; j < MAX_MB_PLANE; ++j) {
+      const struct macroblockd_plane *pd = &xd->plane[j];
+
+      bh = mi_size_high[bsize] << (MI_SIZE_LOG2 - 1) >> pd->subsampling_x;
+      bw = (mi_step << MI_SIZE_LOG2) >> pd->subsampling_y;
+
+      build_inter_predictors(cm, xd, j, mi_col_offset, mi_row_offset, 0, bw, bh,
+                             0, 0, bw, bh,
+#if CONFIG_SUPERTX && CONFIG_EXT_INTER
+                             0, 0,
+#endif  // CONFIG_SUPERTX && CONFIG_EXT_INTER
+                             mi_x, mi_y);
+    }
+
+    *above_mbmi = backup_mbmi;
+  }
+
+  // build from bottom neighbors
+  xd->mb_to_bottom_edge = mb_to_bottom_edge_base;
+  xd->mb_to_top_edge -= mi_size_high[bsize] * MI_SIZE * 4;
+
+  overlappable_offset = -1;
+
+  for (i = 0; i < mi_nums; i += mi_step) {
+    int mi_row_offset = mi_size_high[bsize];
+    int mi_col_offset = i;
+    int mi_x, mi_y, bw, bh;
+    int mi_row_shift = mi_size_high[bsize] >> 1;
+    MODE_INFO *bottom_mi;
+    MB_MODE_INFO *bottom_mbmi, backup_mbmi;
+    BLOCK_SIZE b_bsize;
+
+    // create the original prediction if offset exceeds the boundary
+    if (mi_row + mi_row_offset > xd->sb_mi_bd.mi_row_end) mi_row_offset = 0;
+
+    bottom_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
+    bottom_mbmi = &bottom_mi->mbmi;
+    b_bsize = AOMMAX(bottom_mbmi->sb_type, BLOCK_8X8);
+
+    mi_step = AOMMIN(mi_nums, mi_size_high[b_bsize]);
+
+    // reset the mi if it is not overlappble
+    if (!is_neighbor_overlappable(bottom_mbmi)) {
+      int search_mi_step = mi_size_high[bottom_mbmi->sb_type];
+      while (!is_neighbor_overlappable(bottom_mbmi)) {
+        mi_col_offset += search_mi_step;
+        if (mi_col_offset < mi_nums) {
+          bottom_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
+          bottom_mbmi = &bottom_mi->mbmi;
+          search_mi_step = mi_size_high[bottom_mbmi->sb_type];
+        } else {
+          if (overlappable_offset >= 0) {
+            mi_col_offset = overlappable_offset;
+          } else {
+            mi_col_offset = 0;
+            mi_row_offset = 0;
+          }
+          bottom_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
+          bottom_mbmi = &bottom_mi->mbmi;
+          break;
+        }
+      }
+    } else {
+      // update the available overlappable mi
+      overlappable_offset = mi_col_offset;
+    }
+
+    backup_mbmi = *bottom_mbmi;
+    modify_neighbor_predictor_for_obmc(bottom_mbmi);
+
+    for (j = 0; j < MAX_MB_PLANE; ++j) {
+      struct macroblockd_plane *const pd = &xd->plane[j];
+      setup_pred_plane(&pd->dst, b_bsize, dst_buf[j], MAX_SB_SIZE, MAX_SB_SIZE,
+                       dst_stride[j], mi_row_shift, i, NULL, pd->subsampling_x,
+                       pd->subsampling_y);
+    }
+#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+    for (ref = 0; ref < 1 + (is_inter_anyref_comp_mode(bottom_mbmi->mode));
+         ++ref) {
+      const MV_REFERENCE_FRAME frame = has_second_ref(bottom_mbmi)
+                                           ? bottom_mbmi->ref_frame[ref]
+                                           : bottom_mbmi->ref_frame[0];
+#else   // !(CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF)
+    for (ref = 0; ref < 1 + has_second_ref(bottom_mbmi); ++ref) {
+      const MV_REFERENCE_FRAME frame = bottom_mbmi->ref_frame[ref];
+#endif  // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+      const RefBuffer *const ref_buf = &cm->frame_refs[frame - LAST_FRAME];
+      xd->block_refs[ref] = ref_buf;
+      if ((!av1_is_valid_scale(&ref_buf->sf)))
+        aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM,
+                           "Reference frame has invalid dimensions");
+      av1_setup_pre_planes(xd, ref, ref_buf->buf, mi_row + mi_row_shift,
+                           mi_col + i, &ref_buf->sf);
+    }
+
+    xd->mb_to_left_edge = -(((mi_col + i) * MI_SIZE) * 8);
+    xd->mb_to_right_edge =
+        mb_to_right_edge_base + (mi_nums - i - mi_step) * MI_SIZE * 8;
+    mi_x = (mi_col + i) << MI_SIZE_LOG2;
+    mi_y = (mi_row + mi_row_shift) << MI_SIZE_LOG2;
+
+    for (j = 0; j < MAX_MB_PLANE; ++j) {
+      const struct macroblockd_plane *pd = &xd->plane[j];
+
+      bh = mi_size_high[bsize] << (MI_SIZE_LOG2 - 1) >> pd->subsampling_x;
+      bw = (mi_step << MI_SIZE_LOG2) >> pd->subsampling_y;
+
+      build_inter_predictors(cm, xd, j, mi_col_offset, mi_row_offset, 0, bw, bh,
+                             0, 0, bw, bh,
+#if CONFIG_SUPERTX && CONFIG_EXT_INTER
+                             0, 0,
+#endif  // CONFIG_SUPERTX && CONFIG_EXT_INTER
+                             mi_x, mi_y);
+    }
+
+    *bottom_mbmi = backup_mbmi;
+  }
+  // restore the boundaries
+  xd->mb_to_top_edge = mb_to_top_edge_base;
+  xd->mb_to_bottom_edge = mb_to_bottom_edge_base;
+  xd->mb_to_left_edge = mb_to_left_edge_base;
+  xd->mb_to_right_edge = mb_to_right_edge_base;
+}
+
+void get_pred_by_corner_neighbor(const AV1_COMMON *cm, MACROBLOCKD *xd,
+                                 int bsize, int mi_row, int mi_col,
+                                 uint8_t *dst_buf[MAX_MB_PLANE],
+                                 int dst_stride[MAX_MB_PLANE]) {
+  const TileInfo *const tile = &xd->tile;
+  const int mb_to_bottom_edge_base = xd->mb_to_bottom_edge;
+  const int mb_to_top_edge_base = xd->mb_to_top_edge;
+  const int mb_to_left_edge_base = xd->mb_to_left_edge;
+  const int mb_to_right_edge_base = xd->mb_to_right_edge;
+  const int mi_wide = mi_size_wide[bsize];
+  const int mi_high = mi_size_high[bsize];
+
+  // location of four mi sources
+  const int mi_row_offsets[4] = { -1, -1, mi_high, mi_high };
+  const int mi_col_offsets[4] = { -1, mi_wide, -1, mi_wide };
+
+  MB_MODE_INFO backup_mbmi;
+  int mi_x, mi_y, bh, bw;
+  int i, j, ref;
+
+  assert(bsize >= BLOCK_8X8);
+
+  for (i = 0; i < 4; ++i) {
+    int mi_row_offset = mi_row_offsets[i];
+    int mi_col_offset = mi_col_offsets[i];
+    MODE_INFO *corner_mi;
+    MB_MODE_INFO *corner_mbmi;
+
+    if (mi_col + mi_col_offset < tile->mi_col_start ||
+        mi_col + mi_col_offset > xd->sb_mi_bd.mi_col_end)
+      mi_col_offset = 0;
+
+    if (mi_row + mi_row_offset < tile->mi_row_start ||
+        mi_row + mi_row_offset > xd->sb_mi_bd.mi_row_end)
+      mi_row_offset = 0;
+
+    corner_mi = xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride];
+    corner_mbmi = &corner_mi->mbmi;
+
+    // reset the mi if it is not overlappble
+    if (!is_neighbor_overlappable(corner_mbmi)) {
+      mi_row_offset = 0;
+      mi_col_offset = 0;
+      corner_mi = xd->mi[0];
+      corner_mbmi = &corner_mi->mbmi;
+    }
+
+    backup_mbmi = *corner_mbmi;
+    modify_neighbor_predictor_for_obmc(corner_mbmi);
+
+    for (j = 0; j < MAX_MB_PLANE; ++j) {
+      struct macroblockd_plane *const pd = &xd->plane[j];
+      setup_pred_plane(&pd->dst, BLOCK_8X8, dst_buf[j], MAX_SB_SIZE,
+                       MAX_SB_SIZE, dst_stride[j], (i / 2) * (mi_high >> 1),
+                       (i % 2) * (mi_wide >> 1), NULL, pd->subsampling_x,
+                       pd->subsampling_y);
+    }
+
+#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+    for (ref = 0; ref < 1 + (is_inter_anyref_comp_mode(corner_mbmi->mode));
+         ++ref) {
+      const MV_REFERENCE_FRAME frame = has_second_ref(corner_mbmi)
+                                           ? corner_mbmi->ref_frame[ref]
+                                           : corner_mbmi->ref_frame[0];
+#else
+    for (ref = 0; ref < 1 + has_second_ref(corner_mbmi); ++ref) {
+      const MV_REFERENCE_FRAME frame = corner_mbmi->ref_frame[ref];
+#endif
+      const RefBuffer *const ref_buf = &cm->frame_refs[frame - LAST_FRAME];
+      xd->block_refs[ref] = ref_buf;
+
+      if ((!av1_is_valid_scale(&ref_buf->sf)))
+        aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM,
+                           "Reference frame has invalid dimensions");
+      av1_setup_pre_planes(xd, ref, ref_buf->buf,
+                           mi_row + (i / 2) * (mi_high >> 1),
+                           mi_col + (i % 2) * (mi_wide >> 1), &ref_buf->sf);
+    }
+    // adjust mi boundaries of this block
+    xd->mb_to_bottom_edge =
+        mb_to_bottom_edge_base + (1 - (i / 2)) * mi_high * MI_SIZE * 4;
+    xd->mb_to_top_edge = mb_to_top_edge_base - (i / 2) * mi_high * MI_SIZE * 4;
+    xd->mb_to_right_edge =
+        mb_to_right_edge_base + (1 - (i % 2)) * mi_wide * MI_SIZE * 4;
+    xd->mb_to_left_edge =
+        mb_to_left_edge_base - (i % 2) * mi_wide * MI_SIZE * 4;
+
+    mi_x = (mi_col + (i % 2) * mi_wide / 2) << MI_SIZE_LOG2;
+    mi_y = (mi_row + (i / 2) * mi_high / 2) << MI_SIZE_LOG2;
+
+    for (j = 0; j < MAX_MB_PLANE; ++j) {
+      const struct macroblockd_plane *pd = &xd->plane[j];
+      bh = mi_high << MI_SIZE_LOG2 >> (pd->subsampling_x + 1);
+      bw = mi_wide << MI_SIZE_LOG2 >> (pd->subsampling_y + 1);
+      build_inter_predictors(cm, xd, j, mi_col_offset, mi_row_offset, 0, bw, bh,
+                             0, 0, bw, bh,
+#if CONFIG_SUPERTX && CONFIG_EXT_INTER
+                             0, 0,
+#endif  // CONFIG_SUPERTX && CONFIG_EXT_INTER
+                             mi_x, mi_y);
+    }
+    *corner_mbmi = backup_mbmi;
+  }
+  // restore the boundaries
+  xd->mb_to_bottom_edge = mb_to_bottom_edge_base;
+  xd->mb_to_top_edge = mb_to_top_edge_base;
+  xd->mb_to_right_edge = mb_to_right_edge_base;
+  xd->mb_to_left_edge = mb_to_left_edge_base;
+}
+
+// get the stitched extra prediction for this block
+void av1_get_ext_blk_preds(const AV1_COMMON *cm, MACROBLOCKD *xd, int bsize,
+                           int mi_row, int mi_col,
+                           uint8_t *dst_buf[][MAX_MB_PLANE],
+                           int dst_stride[MAX_MB_PLANE]) {
+  get_pred_by_corner_neighbor(cm, xd, bsize, mi_row, mi_col, dst_buf[0],
+                              dst_stride);
+  get_pred_by_vert_neighbor(cm, xd, bsize, mi_row, mi_col, dst_buf[1],
+                            dst_stride);
+  get_pred_by_horz_neighbor(cm, xd, bsize, mi_row, mi_col, dst_buf[2],
+                            dst_stride);
+}
+
+void av1_get_ori_blk_pred(const AV1_COMMON *cm, MACROBLOCKD *xd, int bsize,
+                          int mi_row, int mi_col,
+                          uint8_t *dst_buf[MAX_MB_PLANE],
+                          int dst_stride[MAX_MB_PLANE]) {
+  MODE_INFO *const mi = xd->mi[0];
+  MB_MODE_INFO *const mbmi = &mi->mbmi;
+  int mi_x = mi_col << MI_SIZE_LOG2;
+  int mi_y = mi_row << MI_SIZE_LOG2;
+  int bw = block_size_wide[bsize];
+  int bh = block_size_high[bsize];
+  int i, ref;
+
+  for (i = 0; i < MAX_MB_PLANE; ++i) {
+    struct macroblockd_plane *const pd = &xd->plane[i];
+    setup_pred_plane(&pd->dst, BLOCK_8X8, dst_buf[i], MAX_SB_SIZE, MAX_SB_SIZE,
+                     dst_stride[i], 0, 0, NULL, pd->subsampling_x,
+                     pd->subsampling_y);
+  }
+
+  for (ref = 0; ref < 1 + has_second_ref(mbmi); ++ref) {
+    const MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref];
+    const RefBuffer *const ref_buf = &cm->frame_refs[frame - LAST_FRAME];
+    xd->block_refs[ref] = ref_buf;
+
+    if (!av1_is_valid_scale(&ref_buf->sf))
+      aom_internal_error(xd->error_info, AOM_CODEC_UNSUP_BITSTREAM,
+                         "Reference frame has invalid dimensions");
+
+    av1_setup_pre_planes(xd, ref, ref_buf->buf, mi_row, mi_col, &ref_buf->sf);
+  }
+
+  for (i = 0; i < MAX_MB_PLANE; ++i) {
+    const struct macroblockd_plane *pd = &xd->plane[i];
+    build_inter_predictors(cm, xd, i, 0, 0, 0, bw >> pd->subsampling_x,
+                           bh >> pd->subsampling_y, 0, 0,
+                           bw >> pd->subsampling_x, bh >> pd->subsampling_y,
+#if CONFIG_SUPERTX && CONFIG_EXT_INTER
+                           0, 0,
+#endif  // CONFIG_SUPERTX && CONFIG_EXT_INTER
+                           mi_x, mi_y);
+  }
+}
+
+#endif
diff --git a/av1/common/reconinter.h b/av1/common/reconinter.h
index 2296460..7d6badb 100644
--- a/av1/common/reconinter.h
+++ b/av1/common/reconinter.h
@@ -873,6 +873,45 @@
     int ext_dst_stride1[3]);
 #endif  // CONFIG_EXT_INTER
 
+#if CONFIG_NCOBMC_ADAPT_WEIGHT
+#define ASSIGN_ALIGNED_PTRS(p, a, s) \
+  p[0] = a;                          \
+  p[1] = a + s;                      \
+  p[2] = a + 2 * s;
+
+#define ASSIGN_ALIGNED_PTRS_HBD(p, a, s, l) \
+  p[0] = CONVERT_TO_BYTEPTR(a);             \
+  p[1] = CONVERT_TO_BYTEPTR(a + s * l);     \
+  p[2] = CONVERT_TO_BYTEPTR(a + 2 * s * l);
+
+void alloc_ncobmc_pred_buffer(MACROBLOCKD *const xd);
+void free_ncobmc_pred_buffer(MACROBLOCKD *const xd);
+void set_sb_mi_boundaries(const AV1_COMMON *const cm, MACROBLOCKD *const xd,
+                          const int mi_row, const int mi_col);
+
+void reset_xd_boundary(MACROBLOCKD *xd, int mi_row, int bh, int mi_col, int bw,
+                       int mi_rows, int mi_cols);
+
+void get_pred_from_intrpl_buf(MACROBLOCKD *xd, int mi_row, int mi_col,
+                              BLOCK_SIZE bsize, int plane);
+
+void build_ncobmc_intrpl_pred(const AV1_COMMON *const cm, MACROBLOCKD *xd,
+                              int plane, int pxl_row, int pxl_col,
+                              BLOCK_SIZE bsize, uint8_t *preds[][MAX_MB_PLANE],
+                              int ps[MAX_MB_PLANE],  // pred buffer strides
+                              int mode);
+
+void av1_get_ext_blk_preds(const AV1_COMMON *cm, MACROBLOCKD *xd, int bsize,
+                           int mi_row, int mi_col,
+                           uint8_t *dst_buf[][MAX_MB_PLANE],
+                           int dst_stride[MAX_MB_PLANE]);
+
+void av1_get_ori_blk_pred(const AV1_COMMON *cm, MACROBLOCKD *xd, int bsize,
+                          int mi_row, int mi_col,
+                          uint8_t *dst_buf[MAX_MB_PLANE],
+                          int dst_stride[MAX_MB_PLANE]);
+#endif  // CONFIG_NCOBMC_ADAPT_WEIGHT
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif