tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

motion_search_facade.c (44474B)


      1 /*
      2 * Copyright (c) 2020, Alliance for Open Media. All rights reserved.
      3 *
      4 * This source code is subject to the terms of the BSD 2 Clause License and
      5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
      6 * was not distributed with this source code in the LICENSE file, you can
      7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
      8 * Media Patent License 1.0 was not distributed with this source code in the
      9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
     10 */
     11 
     12 #include "av1/common/reconinter.h"
     13 
     14 #include "av1/encoder/encodemv.h"
     15 #include "av1/encoder/encoder.h"
     16 #include "av1/encoder/interp_search.h"
     17 #include "av1/encoder/mcomp.h"
     18 #include "av1/encoder/motion_search_facade.h"
     19 #include "av1/encoder/partition_strategy.h"
     20 #include "av1/encoder/reconinter_enc.h"
     21 #include "av1/encoder/tpl_model.h"
     22 #include "av1/encoder/tx_search.h"
     23 
     24 #define RIGHT_SHIFT_MV(x) (((x) + 3 + ((x) >= 0)) >> 3)
     25 
     26 typedef struct {
     27  int_mv fmv;
     28  int weight;
     29 } cand_mv_t;
     30 
     31 static int compare_weight(const void *a, const void *b) {
     32  const int diff = ((cand_mv_t *)a)->weight - ((cand_mv_t *)b)->weight;
     33  if (diff < 0)
     34    return 1;
     35  else if (diff > 0)
     36    return -1;
     37  return 0;
     38 }
     39 
     40 // Allow more mesh searches for screen content type on the ARF.
     41 static int use_fine_search_interval(const AV1_COMP *const cpi) {
     42  return cpi->is_screen_content_type &&
     43         cpi->ppi->gf_group.update_type[cpi->gf_frame_index] == ARF_UPDATE &&
     44         cpi->oxcf.speed <= 2;
     45 }
     46 
     47 // Iterate through the tpl and collect the mvs to be used as candidates
     48 static inline void get_mv_candidate_from_tpl(const AV1_COMP *const cpi,
     49                                             const MACROBLOCK *x,
     50                                             BLOCK_SIZE bsize, int ref,
     51                                             cand_mv_t *cand, int *cand_count,
     52                                             int *total_cand_weight) {
     53  const SuperBlockEnc *sb_enc = &x->sb_enc;
     54  if (!sb_enc->tpl_data_count) {
     55    return;
     56  }
     57 
     58  const AV1_COMMON *cm = &cpi->common;
     59  const MACROBLOCKD *xd = &x->e_mbd;
     60  const int mi_row = xd->mi_row;
     61  const int mi_col = xd->mi_col;
     62 
     63  const BLOCK_SIZE tpl_bsize =
     64      convert_length_to_bsize(cpi->ppi->tpl_data.tpl_bsize_1d);
     65  const int tplw = mi_size_wide[tpl_bsize];
     66  const int tplh = mi_size_high[tpl_bsize];
     67  const int nw = mi_size_wide[bsize] / tplw;
     68  const int nh = mi_size_high[bsize] / tplh;
     69 
     70  if (nw >= 1 && nh >= 1) {
     71    const int of_h = mi_row % mi_size_high[cm->seq_params->sb_size];
     72    const int of_w = mi_col % mi_size_wide[cm->seq_params->sb_size];
     73    const int start = of_h / tplh * sb_enc->tpl_stride + of_w / tplw;
     74    int valid = 1;
     75 
     76    // Assign large weight to start_mv, so it is always tested.
     77    cand[0].weight = nw * nh;
     78 
     79    for (int k = 0; k < nh; k++) {
     80      for (int l = 0; l < nw; l++) {
     81        const int_mv mv =
     82            sb_enc
     83                ->tpl_mv[start + k * sb_enc->tpl_stride + l][ref - LAST_FRAME];
     84        if (mv.as_int == INVALID_MV) {
     85          valid = 0;
     86          break;
     87        }
     88 
     89        const FULLPEL_MV fmv = { GET_MV_RAWPEL(mv.as_mv.row),
     90                                 GET_MV_RAWPEL(mv.as_mv.col) };
     91        int unique = 1;
     92        for (int m = 0; m < *cand_count; m++) {
     93          if (RIGHT_SHIFT_MV(fmv.row) ==
     94                  RIGHT_SHIFT_MV(cand[m].fmv.as_fullmv.row) &&
     95              RIGHT_SHIFT_MV(fmv.col) ==
     96                  RIGHT_SHIFT_MV(cand[m].fmv.as_fullmv.col)) {
     97            unique = 0;
     98            cand[m].weight++;
     99            break;
    100          }
    101        }
    102 
    103        if (unique) {
    104          cand[*cand_count].fmv.as_fullmv = fmv;
    105          cand[*cand_count].weight = 1;
    106          (*cand_count)++;
    107        }
    108      }
    109      if (!valid) break;
    110    }
    111 
    112    if (valid) {
    113      *total_cand_weight = 2 * nh * nw;
    114      if (*cand_count > 2)
    115        qsort(cand, *cand_count, sizeof(cand[0]), &compare_weight);
    116    }
    117  }
    118 }
    119 
    120 void av1_single_motion_search(const AV1_COMP *const cpi, MACROBLOCK *x,
    121                              BLOCK_SIZE bsize, int ref_idx, int *rate_mv,
    122                              int search_range, inter_mode_info *mode_info,
    123                              int_mv *best_mv,
    124                              struct HandleInterModeArgs *const args) {
    125  MACROBLOCKD *xd = &x->e_mbd;
    126  const AV1_COMMON *cm = &cpi->common;
    127  const MotionVectorSearchParams *mv_search_params = &cpi->mv_search_params;
    128  const int num_planes = av1_num_planes(cm);
    129  MB_MODE_INFO *mbmi = xd->mi[0];
    130  struct buf_2d backup_yv12[MAX_MB_PLANE] = { { 0, 0, 0, 0, 0 } };
    131  int bestsme = INT_MAX;
    132  const int ref = mbmi->ref_frame[ref_idx];
    133  const YV12_BUFFER_CONFIG *scaled_ref_frame =
    134      av1_get_scaled_ref_frame(cpi, ref);
    135  const int mi_row = xd->mi_row;
    136  const int mi_col = xd->mi_col;
    137  const MvCosts *mv_costs = x->mv_costs;
    138 
    139  if (scaled_ref_frame) {
    140    // Swap out the reference frame for a version that's been scaled to
    141    // match the resolution of the current frame, allowing the existing
    142    // full-pixel motion search code to be used without additional
    143    // modifications.
    144    for (int i = 0; i < num_planes; i++) {
    145      backup_yv12[i] = xd->plane[i].pre[ref_idx];
    146    }
    147    av1_setup_pre_planes(xd, ref_idx, scaled_ref_frame, mi_row, mi_col, NULL,
    148                         num_planes);
    149  }
    150 
    151  // Work out the size of the first step in the mv step search.
    152  // 0 here is maximum length first step. 1 is AOMMAX >> 1 etc.
    153  int step_param;
    154  if (cpi->sf.mv_sf.auto_mv_step_size && cm->show_frame) {
    155    // Take the weighted average of the step_params based on the last frame's
    156    // max mv magnitude and that based on the best ref mvs of the current
    157    // block for the given reference.
    158    step_param = (av1_init_search_range(x->max_mv_context[ref]) +
    159                  mv_search_params->mv_step_param) /
    160                 2;
    161  } else {
    162    step_param = mv_search_params->mv_step_param;
    163  }
    164 
    165  const MV ref_mv = av1_get_ref_mv(x, ref_idx).as_mv;
    166  FULLPEL_MV start_mv;
    167  if (mbmi->motion_mode != SIMPLE_TRANSLATION)
    168    start_mv = get_fullmv_from_mv(&mbmi->mv[0].as_mv);
    169  else
    170    start_mv = get_fullmv_from_mv(&ref_mv);
    171 
    172  // cand stores start_mv and all possible MVs in a SB.
    173  cand_mv_t cand[MAX_TPL_BLK_IN_SB * MAX_TPL_BLK_IN_SB + 1];
    174  av1_zero(cand);
    175  cand[0].fmv.as_fullmv = start_mv;
    176  int cnt = 1;
    177  int total_weight = 0;
    178 
    179  if (!cpi->sf.mv_sf.full_pixel_search_level &&
    180      mbmi->motion_mode == SIMPLE_TRANSLATION) {
    181    get_mv_candidate_from_tpl(cpi, x, bsize, ref, cand, &cnt, &total_weight);
    182  }
    183 
    184  const int cand_cnt = AOMMIN(2, cnt);
    185  // TODO(any): Test the speed feature for OBMC_CAUSAL mode.
    186  if (cpi->sf.mv_sf.skip_fullpel_search_using_startmv &&
    187      mbmi->motion_mode == SIMPLE_TRANSLATION) {
    188    const int stack_size = args->start_mv_cnt;
    189    for (int cand_idx = 0; cand_idx < cand_cnt; cand_idx++) {
    190      int_mv *fmv_cand = &cand[cand_idx].fmv;
    191      int skip_cand_mv = 0;
    192 
    193      // Check difference between mvs in the stack and candidate mv.
    194      for (int stack_idx = 0; stack_idx < stack_size; stack_idx++) {
    195        const uint8_t this_ref_mv_idx = args->ref_mv_idx_stack[stack_idx];
    196        const FULLPEL_MV *fmv_stack = &args->start_mv_stack[stack_idx];
    197        const int this_newmv_valid =
    198            args->single_newmv_valid[this_ref_mv_idx][ref];
    199        const int row_diff = abs(fmv_stack->row - fmv_cand->as_fullmv.row);
    200        const int col_diff = abs(fmv_stack->col - fmv_cand->as_fullmv.col);
    201 
    202        if (!this_newmv_valid) continue;
    203 
    204        if (cpi->sf.mv_sf.skip_fullpel_search_using_startmv >= 2) {
    205          // Prunes the current start_mv candidate, if the absolute mv
    206          // difference of both row and column are <= 1.
    207          if (row_diff <= 1 && col_diff <= 1) {
    208            skip_cand_mv = 1;
    209            break;
    210          }
    211        } else if (cpi->sf.mv_sf.skip_fullpel_search_using_startmv >= 1) {
    212          // Prunes the current start_mv candidate, if the sum of the absolute
    213          // mv difference of row and column is <= 1.
    214          if (row_diff + col_diff <= 1) {
    215            skip_cand_mv = 1;
    216            break;
    217          }
    218        }
    219      }
    220      if (skip_cand_mv) {
    221        // Ensure atleast one full-pel motion search is not pruned.
    222        assert(mbmi->ref_mv_idx != 0);
    223        // Mark the candidate mv as invalid so that motion search gets skipped.
    224        cand[cand_idx].fmv.as_int = INVALID_MV;
    225      } else {
    226        // Store start_mv candidate and corresponding ref_mv_idx of full-pel
    227        // search in the mv stack (except last ref_mv_idx).
    228        if (mbmi->ref_mv_idx != MAX_REF_MV_SEARCH - 1) {
    229          assert(args->start_mv_cnt < (MAX_REF_MV_SEARCH - 1) * 2);
    230          args->start_mv_stack[args->start_mv_cnt] = fmv_cand->as_fullmv;
    231          args->ref_mv_idx_stack[args->start_mv_cnt] = mbmi->ref_mv_idx;
    232          args->start_mv_cnt++;
    233        }
    234      }
    235    }
    236  }
    237 
    238  // Hot fix for asan complaints when resize mode is on. When resize mode is on,
    239  // the stride of the reference frame can be different from indicated by
    240  // MotionVectorSearchParams::search_site_cfg. When this happens, we need to
    241  // readjust the stride.
    242  const MV_SPEED_FEATURES *mv_sf = &cpi->sf.mv_sf;
    243  const SEARCH_METHODS search_method =
    244      av1_get_default_mv_search_method(x, mv_sf, bsize);
    245  const search_site_config *src_search_site_cfg =
    246      av1_get_search_site_config(cpi, x, search_method);
    247 
    248  // Further reduce the search range.
    249  if (search_range < INT_MAX) {
    250    const search_site_config *search_site_cfg =
    251        &src_search_site_cfg[search_method_lookup[search_method]];
    252    // Max step_param is search_site_cfg->num_search_steps.
    253    if (search_range < 1) {
    254      step_param = search_site_cfg->num_search_steps;
    255    } else {
    256      while (search_site_cfg->radius[search_site_cfg->num_search_steps -
    257                                     step_param - 1] > (search_range << 1) &&
    258             search_site_cfg->num_search_steps - step_param - 1 > 0)
    259        step_param++;
    260    }
    261  }
    262 
    263  int cost_list[5];
    264  FULLPEL_MV_STATS best_mv_stats;
    265  int_mv second_best_mv;
    266  best_mv->as_int = second_best_mv.as_int = INVALID_MV;
    267 
    268  // Allow more mesh searches for screen content type on the ARF.
    269  const int fine_search_interval = use_fine_search_interval(cpi);
    270  FULLPEL_MOTION_SEARCH_PARAMS full_ms_params;
    271 
    272  switch (mbmi->motion_mode) {
    273    case SIMPLE_TRANSLATION: {
    274      // Perform a search with the top 2 candidates
    275      int sum_weight = 0;
    276      for (int m = 0; m < cand_cnt; m++) {
    277        int_mv smv = cand[m].fmv;
    278        FULLPEL_MV this_best_mv, this_second_best_mv;
    279        FULLPEL_MV_STATS this_mv_stats;
    280 
    281        if (smv.as_int == INVALID_MV) continue;
    282 
    283        av1_make_default_fullpel_ms_params(
    284            &full_ms_params, cpi, x, bsize, &ref_mv, smv.as_fullmv,
    285            src_search_site_cfg, search_method, fine_search_interval);
    286 
    287        const int thissme =
    288            av1_full_pixel_search(smv.as_fullmv, &full_ms_params, step_param,
    289                                  cond_cost_list(cpi, cost_list), &this_best_mv,
    290                                  &this_mv_stats, &this_second_best_mv);
    291 
    292        if (thissme < bestsme) {
    293          bestsme = thissme;
    294          best_mv->as_fullmv = this_best_mv;
    295          best_mv_stats = this_mv_stats;
    296          second_best_mv.as_fullmv = this_second_best_mv;
    297        }
    298 
    299        sum_weight += cand[m].weight;
    300        if (4 * sum_weight > 3 * total_weight) break;
    301      }
    302    } break;
    303    case OBMC_CAUSAL:
    304      av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize,
    305                                         &ref_mv, start_mv, src_search_site_cfg,
    306                                         search_method, fine_search_interval);
    307 
    308      bestsme = av1_obmc_full_pixel_search(start_mv, &full_ms_params,
    309                                           step_param, &best_mv->as_fullmv);
    310      break;
    311    default: assert(0 && "Invalid motion mode!\n");
    312  }
    313  if (best_mv->as_int == INVALID_MV) return;
    314 
    315  if (scaled_ref_frame) {
    316    // Swap back the original buffers for subpel motion search.
    317    for (int i = 0; i < num_planes; i++) {
    318      xd->plane[i].pre[ref_idx] = backup_yv12[i];
    319    }
    320  }
    321 
    322  // Terminate search with the current ref_idx based on fullpel mv, rate cost,
    323  // and other know cost.
    324  if (cpi->sf.inter_sf.skip_newmv_in_drl >= 2 &&
    325      mbmi->motion_mode == SIMPLE_TRANSLATION &&
    326      best_mv->as_int != INVALID_MV) {
    327    int_mv this_mv;
    328    this_mv.as_mv = get_mv_from_fullmv(&best_mv->as_fullmv);
    329    const int ref_mv_idx = mbmi->ref_mv_idx;
    330    const int this_mv_rate =
    331        av1_mv_bit_cost(&this_mv.as_mv, &ref_mv, mv_costs->nmv_joint_cost,
    332                        mv_costs->mv_cost_stack, MV_COST_WEIGHT);
    333    mode_info[ref_mv_idx].full_search_mv.as_int = this_mv.as_int;
    334    mode_info[ref_mv_idx].full_mv_rate = this_mv_rate;
    335    mode_info[ref_mv_idx].full_mv_bestsme = bestsme;
    336 
    337    for (int prev_ref_idx = 0; prev_ref_idx < ref_mv_idx; ++prev_ref_idx) {
    338      // Check if the motion search result same as previous results
    339      if (this_mv.as_int == mode_info[prev_ref_idx].full_search_mv.as_int) {
    340        // Compare the rate cost
    341        const int prev_rate_cost = mode_info[prev_ref_idx].full_mv_rate +
    342                                   mode_info[prev_ref_idx].drl_cost;
    343        const int this_rate_cost =
    344            this_mv_rate + mode_info[ref_mv_idx].drl_cost;
    345 
    346        if (prev_rate_cost <= this_rate_cost) {
    347          // If the current rate_cost is worse than the previous rate_cost, then
    348          // we terminate the search. Since av1_single_motion_search is only
    349          // called by handle_new_mv in SIMPLE_TRANSLATION mode, we set the
    350          // best_mv to INVALID mv to signal that we wish to terminate search
    351          // for the current mode.
    352          best_mv->as_int = INVALID_MV;
    353          return;
    354        }
    355      }
    356 
    357      // Terminate the evaluation of current ref_mv_idx based on bestsme and
    358      // drl_cost.
    359      const int psme = mode_info[prev_ref_idx].full_mv_bestsme;
    360      if (psme == INT_MAX) continue;
    361      const int thr =
    362          cpi->sf.inter_sf.skip_newmv_in_drl == 3 ? (psme + (psme >> 2)) : psme;
    363      if (cpi->sf.inter_sf.skip_newmv_in_drl >= 3 &&
    364          mode_info[ref_mv_idx].full_mv_bestsme > thr &&
    365          mode_info[prev_ref_idx].drl_cost < mode_info[ref_mv_idx].drl_cost) {
    366        best_mv->as_int = INVALID_MV;
    367        return;
    368      }
    369    }
    370  }
    371 
    372  if (cpi->common.features.cur_frame_force_integer_mv) {
    373    convert_fullmv_to_mv(best_mv);
    374  }
    375 
    376  const int use_fractional_mv =
    377      bestsme < INT_MAX && cpi->common.features.cur_frame_force_integer_mv == 0;
    378  int best_mv_rate = 0;
    379  int mv_rate_calculated = 0;
    380  if (use_fractional_mv) {
    381    int_mv fractional_ms_list[3];
    382    av1_set_fractional_mv(fractional_ms_list);
    383    int dis; /* TODO: use dis in distortion calculation later. */
    384 
    385    SUBPEL_MOTION_SEARCH_PARAMS ms_params;
    386    av1_make_default_subpel_ms_params(&ms_params, cpi, x, bsize, &ref_mv,
    387                                      cost_list);
    388    MV subpel_start_mv = get_mv_from_fullmv(&best_mv->as_fullmv);
    389    assert(av1_is_subpelmv_in_range(&ms_params.mv_limits, subpel_start_mv));
    390 
    391    switch (mbmi->motion_mode) {
    392      case SIMPLE_TRANSLATION:
    393        if (mv_sf->use_accurate_subpel_search) {
    394          const int try_second = second_best_mv.as_int != INVALID_MV &&
    395                                 second_best_mv.as_int != best_mv->as_int &&
    396                                 (mv_sf->disable_second_mv <= 1);
    397          const int best_mv_var = mv_search_params->find_fractional_mv_step(
    398              xd, cm, &ms_params, subpel_start_mv, &best_mv_stats,
    399              &best_mv->as_mv, &dis, &x->pred_sse[ref], fractional_ms_list);
    400 
    401          if (try_second) {
    402            struct macroblockd_plane *p = xd->plane;
    403            const BUFFER_SET orig_dst = {
    404              { p[0].dst.buf, p[1].dst.buf, p[2].dst.buf },
    405              { p[0].dst.stride, p[1].dst.stride, p[2].dst.stride },
    406            };
    407            int64_t rd = INT64_MAX;
    408            if (!mv_sf->disable_second_mv) {
    409              // Calculate actual rd cost.
    410              mbmi->mv[0].as_mv = best_mv->as_mv;
    411              av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst,
    412                                            bsize, 0, 0);
    413              av1_subtract_plane(x, bsize, 0);
    414              RD_STATS this_rd_stats;
    415              av1_init_rd_stats(&this_rd_stats);
    416              av1_estimate_txfm_yrd(cpi, x, &this_rd_stats, INT64_MAX, bsize,
    417                                    max_txsize_rect_lookup[bsize]);
    418              int this_mv_rate = av1_mv_bit_cost(
    419                  &best_mv->as_mv, &ref_mv, mv_costs->nmv_joint_cost,
    420                  mv_costs->mv_cost_stack, MV_COST_WEIGHT);
    421              rd = RDCOST(x->rdmult, this_mv_rate + this_rd_stats.rate,
    422                          this_rd_stats.dist);
    423            }
    424 
    425            MV this_best_mv;
    426            subpel_start_mv = get_mv_from_fullmv(&second_best_mv.as_fullmv);
    427            if (av1_is_subpelmv_in_range(&ms_params.mv_limits,
    428                                         subpel_start_mv)) {
    429              unsigned int sse;
    430              const int this_var = mv_search_params->find_fractional_mv_step(
    431                  xd, cm, &ms_params, subpel_start_mv, NULL, &this_best_mv,
    432                  &dis, &sse, fractional_ms_list);
    433 
    434              if (!mv_sf->disable_second_mv) {
    435                // If cpi->sf.mv_sf.disable_second_mv is 0, use actual rd cost
    436                // to choose the better MV.
    437                mbmi->mv[0].as_mv = this_best_mv;
    438                av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst,
    439                                              bsize, 0, 0);
    440                av1_subtract_plane(x, bsize, 0);
    441                RD_STATS tmp_rd_stats;
    442                av1_init_rd_stats(&tmp_rd_stats);
    443                av1_estimate_txfm_yrd(cpi, x, &tmp_rd_stats, INT64_MAX, bsize,
    444                                      max_txsize_rect_lookup[bsize]);
    445                int tmp_mv_rate = av1_mv_bit_cost(
    446                    &this_best_mv, &ref_mv, mv_costs->nmv_joint_cost,
    447                    mv_costs->mv_cost_stack, MV_COST_WEIGHT);
    448                int64_t tmp_rd =
    449                    RDCOST(x->rdmult, tmp_rd_stats.rate + tmp_mv_rate,
    450                           tmp_rd_stats.dist);
    451                if (tmp_rd < rd) {
    452                  best_mv->as_mv = this_best_mv;
    453                  x->pred_sse[ref] = sse;
    454                }
    455              } else {
    456                // If cpi->sf.mv_sf.disable_second_mv = 1, use var to decide the
    457                // best MV.
    458                if (this_var < best_mv_var) {
    459                  best_mv->as_mv = this_best_mv;
    460                  x->pred_sse[ref] = sse;
    461                }
    462              }
    463            }
    464          }
    465        } else {
    466          mv_search_params->find_fractional_mv_step(
    467              xd, cm, &ms_params, subpel_start_mv, &best_mv_stats,
    468              &best_mv->as_mv, &dis, &x->pred_sse[ref], NULL);
    469        }
    470        break;
    471      case OBMC_CAUSAL:
    472        av1_find_best_obmc_sub_pixel_tree_up(
    473            xd, cm, &ms_params, subpel_start_mv, NULL, &best_mv->as_mv, &dis,
    474            &x->pred_sse[ref], NULL);
    475        break;
    476      default: assert(0 && "Invalid motion mode!\n");
    477    }
    478 
    479    // Terminate search with the current ref_idx based on subpel mv and rate
    480    // cost.
    481    if (cpi->sf.inter_sf.skip_newmv_in_drl >= 1 && args != NULL &&
    482        mbmi->motion_mode == SIMPLE_TRANSLATION &&
    483        best_mv->as_int != INVALID_MV) {
    484      const int ref_mv_idx = mbmi->ref_mv_idx;
    485      best_mv_rate =
    486          av1_mv_bit_cost(&best_mv->as_mv, &ref_mv, mv_costs->nmv_joint_cost,
    487                          mv_costs->mv_cost_stack, MV_COST_WEIGHT);
    488      mv_rate_calculated = 1;
    489 
    490      for (int prev_ref_idx = 0; prev_ref_idx < ref_mv_idx; ++prev_ref_idx) {
    491        if (!args->single_newmv_valid[prev_ref_idx][ref]) continue;
    492        // Check if the motion vectors are the same.
    493        if (best_mv->as_int == args->single_newmv[prev_ref_idx][ref].as_int) {
    494          // Skip this evaluation if the previous one is skipped.
    495          if (mode_info[prev_ref_idx].skip) {
    496            mode_info[ref_mv_idx].skip = 1;
    497            break;
    498          }
    499          // Compare the rate cost that we current know.
    500          const int prev_rate_cost =
    501              args->single_newmv_rate[prev_ref_idx][ref] +
    502              mode_info[prev_ref_idx].drl_cost;
    503          const int this_rate_cost =
    504              best_mv_rate + mode_info[ref_mv_idx].drl_cost;
    505 
    506          if (prev_rate_cost <= this_rate_cost) {
    507            // If the current rate_cost is worse than the previous rate_cost,
    508            // then we terminate the search for this ref_mv_idx.
    509            mode_info[ref_mv_idx].skip = 1;
    510            break;
    511          }
    512        }
    513      }
    514    }
    515  }
    516 
    517  if (mv_rate_calculated) {
    518    *rate_mv = best_mv_rate;
    519  } else {
    520    *rate_mv =
    521        av1_mv_bit_cost(&best_mv->as_mv, &ref_mv, mv_costs->nmv_joint_cost,
    522                        mv_costs->mv_cost_stack, MV_COST_WEIGHT);
    523  }
    524 }
    525 
    526 int av1_joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x,
    527                            BLOCK_SIZE bsize, int_mv *cur_mv,
    528                            const uint8_t *mask, int mask_stride, int *rate_mv,
    529                            int allow_second_mv, int joint_me_num_refine_iter) {
    530  const AV1_COMMON *const cm = &cpi->common;
    531  const int num_planes = av1_num_planes(cm);
    532  const int pw = block_size_wide[bsize];
    533  const int ph = block_size_high[bsize];
    534  const int plane = 0;
    535  MACROBLOCKD *xd = &x->e_mbd;
    536  MB_MODE_INFO *mbmi = xd->mi[0];
    537  // This function should only ever be called for compound modes
    538  assert(has_second_ref(mbmi));
    539  const int_mv init_mv[2] = { cur_mv[0], cur_mv[1] };
    540  const int refs[2] = { mbmi->ref_frame[0], mbmi->ref_frame[1] };
    541  const MvCosts *mv_costs = x->mv_costs;
    542  int_mv ref_mv[2];
    543  int ite, ref;
    544 
    545  // Get the prediction block from the 'other' reference frame.
    546  const int_interpfilters interp_filters =
    547      av1_broadcast_interp_filter(EIGHTTAP_REGULAR);
    548 
    549  InterPredParams inter_pred_params;
    550  const int mi_row = xd->mi_row;
    551  const int mi_col = xd->mi_col;
    552 
    553  // Do joint motion search in compound mode to get more accurate mv.
    554  struct buf_2d backup_yv12[2][MAX_MB_PLANE];
    555  int last_besterr[2] = { INT_MAX, INT_MAX };
    556  const YV12_BUFFER_CONFIG *const scaled_ref_frame[2] = {
    557    av1_get_scaled_ref_frame(cpi, refs[0]),
    558    av1_get_scaled_ref_frame(cpi, refs[1])
    559  };
    560 
    561  // Prediction buffer from second frame.
    562  DECLARE_ALIGNED(16, uint8_t, second_pred16[MAX_SB_SQUARE * sizeof(uint16_t)]);
    563  uint8_t *second_pred = get_buf_by_bd(xd, second_pred16);
    564 
    565  int_mv best_mv, second_best_mv;
    566 
    567  // Allow joint search multiple times iteratively for each reference frame
    568  // and break out of the search loop if it couldn't find a better mv.
    569  for (ite = 0; ite < (2 * joint_me_num_refine_iter); ite++) {
    570    struct buf_2d ref_yv12[2];
    571    int bestsme = INT_MAX;
    572    int id = ite % 2;  // Even iterations search in the first reference frame,
    573                       // odd iterations search in the second. The predictor
    574                       // found for the 'other' reference frame is factored in.
    575    if (ite >= 2 && cur_mv[!id].as_int == init_mv[!id].as_int) {
    576      if (cur_mv[id].as_int == init_mv[id].as_int) {
    577        break;
    578      } else {
    579        int_mv cur_int_mv, init_int_mv;
    580        cur_int_mv.as_mv.col = cur_mv[id].as_mv.col >> 3;
    581        cur_int_mv.as_mv.row = cur_mv[id].as_mv.row >> 3;
    582        init_int_mv.as_mv.row = init_mv[id].as_mv.row >> 3;
    583        init_int_mv.as_mv.col = init_mv[id].as_mv.col >> 3;
    584        if (cur_int_mv.as_int == init_int_mv.as_int) {
    585          break;
    586        }
    587      }
    588    }
    589    for (ref = 0; ref < 2; ++ref) {
    590      ref_mv[ref] = av1_get_ref_mv(x, ref);
    591      // Swap out the reference frame for a version that's been scaled to
    592      // match the resolution of the current frame, allowing the existing
    593      // motion search code to be used without additional modifications.
    594      if (scaled_ref_frame[ref]) {
    595        int i;
    596        for (i = 0; i < num_planes; i++)
    597          backup_yv12[ref][i] = xd->plane[i].pre[ref];
    598        av1_setup_pre_planes(xd, ref, scaled_ref_frame[ref], mi_row, mi_col,
    599                             NULL, num_planes);
    600      }
    601    }
    602 
    603    assert(IMPLIES(scaled_ref_frame[0] != NULL,
    604                   cm->width == scaled_ref_frame[0]->y_crop_width &&
    605                       cm->height == scaled_ref_frame[0]->y_crop_height));
    606    assert(IMPLIES(scaled_ref_frame[1] != NULL,
    607                   cm->width == scaled_ref_frame[1]->y_crop_width &&
    608                       cm->height == scaled_ref_frame[1]->y_crop_height));
    609 
    610    // Initialize based on (possibly scaled) prediction buffers.
    611    ref_yv12[0] = xd->plane[plane].pre[0];
    612    ref_yv12[1] = xd->plane[plane].pre[1];
    613 
    614    av1_init_inter_params(&inter_pred_params, pw, ph, mi_row * MI_SIZE,
    615                          mi_col * MI_SIZE, 0, 0, xd->bd, is_cur_buf_hbd(xd), 0,
    616                          &cm->sf_identity, &ref_yv12[!id], interp_filters);
    617    inter_pred_params.conv_params = get_conv_params(0, 0, xd->bd);
    618 
    619    // Since we have scaled the reference frames to match the size of the
    620    // current frame we must use a unit scaling factor during mode selection.
    621    av1_enc_build_one_inter_predictor(second_pred, pw, &cur_mv[!id].as_mv,
    622                                      &inter_pred_params);
    623 
    624    // Do full-pixel compound motion search on the current reference frame.
    625    if (id) xd->plane[plane].pre[0] = ref_yv12[id];
    626 
    627    // Make motion search params
    628    FULLPEL_MOTION_SEARCH_PARAMS full_ms_params;
    629    FULLPEL_MV_STATS best_mv_stats;
    630    const MV_SPEED_FEATURES *mv_sf = &cpi->sf.mv_sf;
    631    const SEARCH_METHODS search_method =
    632        av1_get_default_mv_search_method(x, mv_sf, bsize);
    633    const search_site_config *src_search_sites =
    634        av1_get_search_site_config(cpi, x, search_method);
    635    // Use the mv result from the single mode as mv predictor.
    636    const FULLPEL_MV start_fullmv = get_fullmv_from_mv(&cur_mv[id].as_mv);
    637    av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize,
    638                                       &ref_mv[id].as_mv, start_fullmv,
    639                                       src_search_sites, search_method,
    640                                       /*fine_search_interval=*/0);
    641 
    642    av1_set_ms_compound_refs(&full_ms_params.ms_buffers, second_pred, mask,
    643                             mask_stride, id);
    644 
    645    // Small-range full-pixel motion search.
    646    if (!mv_sf->disable_extensive_joint_motion_search &&
    647        mbmi->interinter_comp.type != COMPOUND_WEDGE) {
    648      bestsme = av1_full_pixel_search(start_fullmv, &full_ms_params, 5, NULL,
    649                                      &best_mv.as_fullmv, &best_mv_stats,
    650                                      &second_best_mv.as_fullmv);
    651    } else {
    652      bestsme = av1_refining_search_8p_c(&full_ms_params, start_fullmv,
    653                                         &best_mv.as_fullmv);
    654      second_best_mv = best_mv;
    655    }
    656 
    657    const int try_second = second_best_mv.as_int != INVALID_MV &&
    658                           second_best_mv.as_int != best_mv.as_int &&
    659                           allow_second_mv;
    660 
    661    // Restore the pointer to the first (possibly scaled) prediction buffer.
    662    if (id) xd->plane[plane].pre[0] = ref_yv12[0];
    663 
    664    for (ref = 0; ref < 2; ++ref) {
    665      if (scaled_ref_frame[ref]) {
    666        // Swap back the original buffers for subpel motion search.
    667        for (int i = 0; i < num_planes; i++) {
    668          xd->plane[i].pre[ref] = backup_yv12[ref][i];
    669        }
    670        // Re-initialize based on unscaled prediction buffers.
    671        ref_yv12[ref] = xd->plane[plane].pre[ref];
    672      }
    673    }
    674 
    675    // Do sub-pixel compound motion search on the current reference frame.
    676    if (id) xd->plane[plane].pre[0] = ref_yv12[id];
    677 
    678    if (cpi->common.features.cur_frame_force_integer_mv) {
    679      convert_fullmv_to_mv(&best_mv);
    680    }
    681    if (bestsme < INT_MAX &&
    682        cpi->common.features.cur_frame_force_integer_mv == 0) {
    683      int dis; /* TODO: use dis in distortion calculation later. */
    684      unsigned int sse;
    685      SUBPEL_MOTION_SEARCH_PARAMS ms_params;
    686      av1_make_default_subpel_ms_params(&ms_params, cpi, x, bsize,
    687                                        &ref_mv[id].as_mv, NULL);
    688      av1_set_ms_compound_refs(&ms_params.var_params.ms_buffers, second_pred,
    689                               mask, mask_stride, id);
    690      ms_params.forced_stop = EIGHTH_PEL;
    691      MV start_mv = get_mv_from_fullmv(&best_mv.as_fullmv);
    692      assert(av1_is_subpelmv_in_range(&ms_params.mv_limits, start_mv));
    693      bestsme = cpi->mv_search_params.find_fractional_mv_step(
    694          xd, cm, &ms_params, start_mv, NULL, &best_mv.as_mv, &dis, &sse, NULL);
    695 
    696      if (try_second) {
    697        MV this_best_mv;
    698        MV subpel_start_mv = get_mv_from_fullmv(&second_best_mv.as_fullmv);
    699        if (av1_is_subpelmv_in_range(&ms_params.mv_limits, subpel_start_mv)) {
    700          const int thissme = cpi->mv_search_params.find_fractional_mv_step(
    701              xd, cm, &ms_params, subpel_start_mv, NULL, &this_best_mv, &dis,
    702              &sse, NULL);
    703          if (thissme < bestsme) {
    704            best_mv.as_mv = this_best_mv;
    705            bestsme = thissme;
    706          }
    707        }
    708      }
    709    }
    710 
    711    // Restore the pointer to the first prediction buffer.
    712    if (id) xd->plane[plane].pre[0] = ref_yv12[0];
    713    if (bestsme < last_besterr[id]) {
    714      cur_mv[id] = best_mv;
    715      last_besterr[id] = bestsme;
    716    } else {
    717      break;
    718    }
    719  }
    720 
    721  *rate_mv = 0;
    722 
    723  for (ref = 0; ref < 2; ++ref) {
    724    const int_mv curr_ref_mv = av1_get_ref_mv(x, ref);
    725    *rate_mv += av1_mv_bit_cost(&cur_mv[ref].as_mv, &curr_ref_mv.as_mv,
    726                                mv_costs->nmv_joint_cost,
    727                                mv_costs->mv_cost_stack, MV_COST_WEIGHT);
    728  }
    729 
    730  return AOMMIN(last_besterr[0], last_besterr[1]);
    731 }
    732 
    733 // Search for the best mv for one component of a compound,
    734 // given that the other component is fixed.
    735 int av1_compound_single_motion_search(const AV1_COMP *cpi, MACROBLOCK *x,
    736                                      BLOCK_SIZE bsize, MV *this_mv,
    737                                      const uint8_t *second_pred,
    738                                      const uint8_t *mask, int mask_stride,
    739                                      int *rate_mv, int ref_idx) {
    740  const AV1_COMMON *const cm = &cpi->common;
    741  const int num_planes = av1_num_planes(cm);
    742  MACROBLOCKD *xd = &x->e_mbd;
    743  MB_MODE_INFO *mbmi = xd->mi[0];
    744  const int ref = mbmi->ref_frame[ref_idx];
    745  const int_mv ref_mv = av1_get_ref_mv(x, ref_idx);
    746  struct macroblockd_plane *const pd = &xd->plane[0];
    747  const MvCosts *mv_costs = x->mv_costs;
    748 
    749  struct buf_2d backup_yv12[MAX_MB_PLANE];
    750  const YV12_BUFFER_CONFIG *const scaled_ref_frame =
    751      av1_get_scaled_ref_frame(cpi, ref);
    752 
    753  // Check that this is either an interinter or an interintra block
    754  assert(has_second_ref(mbmi) || (ref_idx == 0 && is_interintra_mode(mbmi)));
    755 
    756  // Store the first prediction buffer.
    757  struct buf_2d orig_yv12;
    758  if (ref_idx) {
    759    orig_yv12 = pd->pre[0];
    760    pd->pre[0] = pd->pre[ref_idx];
    761  }
    762 
    763  if (scaled_ref_frame) {
    764    // Swap out the reference frame for a version that's been scaled to
    765    // match the resolution of the current frame, allowing the existing
    766    // full-pixel motion search code to be used without additional
    767    // modifications.
    768    for (int i = 0; i < num_planes; i++) {
    769      backup_yv12[i] = xd->plane[i].pre[ref_idx];
    770    }
    771    const int mi_row = xd->mi_row;
    772    const int mi_col = xd->mi_col;
    773    // The index below needs to be 0 instead of ref_idx since we assume the
    774    // 0th slot to be used for subsequent searches. Note that the ref_idx
    775    // reference buffer has been copied to the 0th slot in the code above.
    776    // Now we need to swap the reference frame for the 0th slot.
    777    av1_setup_pre_planes(xd, 0, scaled_ref_frame, mi_row, mi_col, NULL,
    778                         num_planes);
    779  }
    780 
    781  int bestsme = INT_MAX;
    782  int_mv best_mv;
    783 
    784  // Make motion search params
    785  FULLPEL_MOTION_SEARCH_PARAMS full_ms_params;
    786  FULLPEL_MV_STATS best_mv_stats;
    787  const SEARCH_METHODS search_method =
    788      av1_get_default_mv_search_method(x, &cpi->sf.mv_sf, bsize);
    789  const search_site_config *src_search_sites =
    790      av1_get_search_site_config(cpi, x, search_method);
    791  // Use the mv result from the single mode as mv predictor.
    792  const FULLPEL_MV start_fullmv = get_fullmv_from_mv(this_mv);
    793  av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize,
    794                                     &ref_mv.as_mv, start_fullmv,
    795                                     src_search_sites, search_method,
    796                                     /*fine_search_interval=*/0);
    797 
    798  av1_set_ms_compound_refs(&full_ms_params.ms_buffers, second_pred, mask,
    799                           mask_stride, ref_idx);
    800 
    801  // Small-range full-pixel motion search.
    802  bestsme = av1_full_pixel_search(start_fullmv, &full_ms_params, 5, NULL,
    803                                  &best_mv.as_fullmv, &best_mv_stats, NULL);
    804 
    805  if (scaled_ref_frame) {
    806    // Swap back the original buffers for subpel motion search for the 0th slot.
    807    for (int i = 0; i < num_planes; i++) {
    808      xd->plane[i].pre[0] = backup_yv12[i];
    809    }
    810  }
    811 
    812  if (cpi->common.features.cur_frame_force_integer_mv) {
    813    convert_fullmv_to_mv(&best_mv);
    814  }
    815  const int use_fractional_mv =
    816      bestsme < INT_MAX && cpi->common.features.cur_frame_force_integer_mv == 0;
    817  if (use_fractional_mv) {
    818    int dis; /* TODO: use dis in distortion calculation later. */
    819    unsigned int sse;
    820    SUBPEL_MOTION_SEARCH_PARAMS ms_params;
    821    av1_make_default_subpel_ms_params(&ms_params, cpi, x, bsize, &ref_mv.as_mv,
    822                                      NULL);
    823    av1_set_ms_compound_refs(&ms_params.var_params.ms_buffers, second_pred,
    824                             mask, mask_stride, ref_idx);
    825    ms_params.forced_stop = EIGHTH_PEL;
    826    MV start_mv = get_mv_from_fullmv(&best_mv.as_fullmv);
    827    assert(av1_is_subpelmv_in_range(&ms_params.mv_limits, start_mv));
    828    bestsme = cpi->mv_search_params.find_fractional_mv_step(
    829        xd, cm, &ms_params, start_mv, &best_mv_stats, &best_mv.as_mv, &dis,
    830        &sse, NULL);
    831  }
    832 
    833  // Restore the pointer to the first unscaled prediction buffer.
    834  if (ref_idx) pd->pre[0] = orig_yv12;
    835 
    836  if (bestsme < INT_MAX) *this_mv = best_mv.as_mv;
    837 
    838  *rate_mv = 0;
    839 
    840  *rate_mv += av1_mv_bit_cost(this_mv, &ref_mv.as_mv, mv_costs->nmv_joint_cost,
    841                              mv_costs->mv_cost_stack, MV_COST_WEIGHT);
    842  return bestsme;
    843 }
    844 
    845 static inline void build_second_inter_pred(const AV1_COMP *cpi, MACROBLOCK *x,
    846                                           BLOCK_SIZE bsize, const MV *other_mv,
    847                                           int ref_idx, uint8_t *second_pred) {
    848  const AV1_COMMON *const cm = &cpi->common;
    849  const int pw = block_size_wide[bsize];
    850  const int ph = block_size_high[bsize];
    851  MACROBLOCKD *xd = &x->e_mbd;
    852  MB_MODE_INFO *mbmi = xd->mi[0];
    853  struct macroblockd_plane *const pd = &xd->plane[0];
    854  const int mi_row = xd->mi_row;
    855  const int mi_col = xd->mi_col;
    856  const int p_col = ((mi_col * MI_SIZE) >> pd->subsampling_x);
    857  const int p_row = ((mi_row * MI_SIZE) >> pd->subsampling_y);
    858 
    859  // This function should only ever be called for compound modes
    860  assert(has_second_ref(mbmi));
    861 
    862  const int plane = 0;
    863  struct buf_2d ref_yv12 = xd->plane[plane].pre[!ref_idx];
    864 
    865  struct scale_factors sf;
    866  av1_setup_scale_factors_for_frame(&sf, ref_yv12.width, ref_yv12.height,
    867                                    cm->width, cm->height);
    868 
    869  InterPredParams inter_pred_params;
    870 
    871  av1_init_inter_params(&inter_pred_params, pw, ph, p_row, p_col,
    872                        pd->subsampling_x, pd->subsampling_y, xd->bd,
    873                        is_cur_buf_hbd(xd), 0, &sf, &ref_yv12,
    874                        mbmi->interp_filters);
    875  inter_pred_params.conv_params = get_conv_params(0, plane, xd->bd);
    876 
    877  // Get the prediction block from the 'other' reference frame.
    878  av1_enc_build_one_inter_predictor(second_pred, pw, other_mv,
    879                                    &inter_pred_params);
    880 }
    881 
    882 // Wrapper for av1_compound_single_motion_search, for the common case
    883 // where the second prediction is also an inter mode.
    884 static int compound_single_motion_search_interinter(
    885    const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, int_mv *cur_mv,
    886    const uint8_t *mask, int mask_stride, int *rate_mv, int ref_idx) {
    887  MACROBLOCKD *xd = &x->e_mbd;
    888  // This function should only ever be called for compound modes
    889  assert(has_second_ref(xd->mi[0]));
    890 
    891  // Prediction buffer from second frame.
    892  DECLARE_ALIGNED(16, uint16_t, second_pred_alloc_16[MAX_SB_SQUARE]);
    893  uint8_t *second_pred;
    894  if (is_cur_buf_hbd(xd))
    895    second_pred = CONVERT_TO_BYTEPTR(second_pred_alloc_16);
    896  else
    897    second_pred = (uint8_t *)second_pred_alloc_16;
    898 
    899  MV *this_mv = &cur_mv[ref_idx].as_mv;
    900  const MV *other_mv = &cur_mv[!ref_idx].as_mv;
    901  build_second_inter_pred(cpi, x, bsize, other_mv, ref_idx, second_pred);
    902  return av1_compound_single_motion_search(cpi, x, bsize, this_mv, second_pred,
    903                                           mask, mask_stride, rate_mv, ref_idx);
    904 }
    905 
    906 static inline void do_masked_motion_search_indexed(
    907    const AV1_COMP *const cpi, MACROBLOCK *x, const int_mv *const cur_mv,
    908    const INTERINTER_COMPOUND_DATA *const comp_data, BLOCK_SIZE bsize,
    909    int_mv *tmp_mv, int *rate_mv, int which) {
    910  // NOTE: which values: 0 - 0 only, 1 - 1 only, 2 - both
    911  MACROBLOCKD *xd = &x->e_mbd;
    912  MB_MODE_INFO *mbmi = xd->mi[0];
    913  BLOCK_SIZE sb_type = mbmi->bsize;
    914  const uint8_t *mask;
    915  const int mask_stride = block_size_wide[bsize];
    916 
    917  mask = av1_get_compound_type_mask(comp_data, sb_type);
    918 
    919  tmp_mv[0].as_int = cur_mv[0].as_int;
    920  tmp_mv[1].as_int = cur_mv[1].as_int;
    921  if (which == 0 || which == 1) {
    922    compound_single_motion_search_interinter(cpi, x, bsize, tmp_mv, mask,
    923                                             mask_stride, rate_mv, which);
    924  } else if (which == 2) {
    925    const int joint_me_num_refine_iter =
    926        cpi->sf.inter_sf.enable_fast_compound_mode_search == 2
    927            ? REDUCED_JOINT_ME_REFINE_ITER
    928            : NUM_JOINT_ME_REFINE_ITER;
    929    av1_joint_motion_search(cpi, x, bsize, tmp_mv, mask, mask_stride, rate_mv,
    930                            !cpi->sf.mv_sf.disable_second_mv,
    931                            joint_me_num_refine_iter);
    932  }
    933 }
    934 
    935 int av1_interinter_compound_motion_search(const AV1_COMP *const cpi,
    936                                          MACROBLOCK *x,
    937                                          const int_mv *const cur_mv,
    938                                          const BLOCK_SIZE bsize,
    939                                          const PREDICTION_MODE this_mode) {
    940  MACROBLOCKD *const xd = &x->e_mbd;
    941  MB_MODE_INFO *const mbmi = xd->mi[0];
    942  int_mv tmp_mv[2];
    943  int tmp_rate_mv = 0;
    944  // TODO(jingning): The average compound mode has proper SAD and variance
    945  // functions implemented, and is triggerd by setting the mask pointer as
    946  // Null. Need to further implement those for frame distance weighted mode.
    947  mbmi->interinter_comp.seg_mask =
    948      mbmi->interinter_comp.type == COMPOUND_AVERAGE ? NULL : xd->seg_mask;
    949  const INTERINTER_COMPOUND_DATA *compound_data = &mbmi->interinter_comp;
    950 
    951  if (this_mode == NEW_NEWMV) {
    952    do_masked_motion_search_indexed(cpi, x, cur_mv, compound_data, bsize,
    953                                    tmp_mv, &tmp_rate_mv, 2);
    954    mbmi->mv[0].as_int = tmp_mv[0].as_int;
    955    mbmi->mv[1].as_int = tmp_mv[1].as_int;
    956  } else if (this_mode >= NEAREST_NEWMV && this_mode <= NEW_NEARMV) {
    957    // which = 1 if this_mode == NEAREST_NEWMV || this_mode == NEAR_NEWMV
    958    // which = 0 if this_mode == NEW_NEARESTMV || this_mode == NEW_NEARMV
    959    int which = (NEWMV == compound_ref1_mode(this_mode));
    960    do_masked_motion_search_indexed(cpi, x, cur_mv, compound_data, bsize,
    961                                    tmp_mv, &tmp_rate_mv, which);
    962    mbmi->mv[which].as_int = tmp_mv[which].as_int;
    963  }
    964  return tmp_rate_mv;
    965 }
    966 
    967 int_mv av1_simple_motion_search_sse_var(AV1_COMP *const cpi, MACROBLOCK *x,
    968                                        int mi_row, int mi_col,
    969                                        BLOCK_SIZE bsize, int ref,
    970                                        FULLPEL_MV start_mv, int num_planes,
    971                                        int use_subpixel, unsigned int *sse,
    972                                        unsigned int *var) {
    973  assert(num_planes == 1 &&
    974         "Currently simple_motion_search only supports luma plane");
    975  assert(!frame_is_intra_only(&cpi->common) &&
    976         "Simple motion search only enabled for non-key frames");
    977  AV1_COMMON *const cm = &cpi->common;
    978  MACROBLOCKD *xd = &x->e_mbd;
    979 
    980  set_offsets_for_motion_search(cpi, x, mi_row, mi_col, bsize);
    981 
    982  MB_MODE_INFO *mbmi = xd->mi[0];
    983  mbmi->bsize = bsize;
    984  mbmi->ref_frame[0] = ref;
    985  mbmi->ref_frame[1] = NONE_FRAME;
    986  mbmi->motion_mode = SIMPLE_TRANSLATION;
    987  mbmi->interp_filters = av1_broadcast_interp_filter(EIGHTTAP_REGULAR);
    988 
    989  const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_yv12_buf(cm, ref);
    990  const YV12_BUFFER_CONFIG *scaled_ref_frame =
    991      av1_get_scaled_ref_frame(cpi, ref);
    992  struct buf_2d backup_yv12;
    993  // ref_mv is used to calculate the cost of the motion vector
    994  const MV ref_mv = kZeroMv;
    995  const int step_param =
    996      AOMMIN(cpi->mv_search_params.mv_step_param +
    997                 cpi->sf.part_sf.simple_motion_search_reduce_search_steps,
    998             MAX_MVSEARCH_STEPS - 2);
    999  int cost_list[5];
   1000  const int ref_idx = 0;
   1001  int bestsme;
   1002  int_mv best_mv;
   1003  FULLPEL_MV_STATS best_mv_stats;
   1004 
   1005  av1_setup_pre_planes(xd, ref_idx, yv12, mi_row, mi_col,
   1006                       get_ref_scale_factors(cm, ref), num_planes);
   1007  set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
   1008  if (scaled_ref_frame) {
   1009    backup_yv12 = xd->plane[AOM_PLANE_Y].pre[ref_idx];
   1010    av1_setup_pre_planes(xd, ref_idx, scaled_ref_frame, mi_row, mi_col, NULL,
   1011                         num_planes);
   1012  }
   1013 
   1014  // Allow more mesh searches for screen content type on the ARF.
   1015  const int fine_search_interval = use_fine_search_interval(cpi);
   1016  FULLPEL_MOTION_SEARCH_PARAMS full_ms_params;
   1017  const MV_SPEED_FEATURES *mv_sf = &cpi->sf.mv_sf;
   1018  const SEARCH_METHODS search_method =
   1019      av1_get_default_mv_search_method(x, mv_sf, bsize);
   1020  const search_site_config *src_search_sites =
   1021      av1_get_search_site_config(cpi, x, search_method);
   1022  av1_make_default_fullpel_ms_params(&full_ms_params, cpi, x, bsize, &ref_mv,
   1023                                     start_mv, src_search_sites, search_method,
   1024                                     fine_search_interval);
   1025 
   1026  bestsme = av1_full_pixel_search(start_mv, &full_ms_params, step_param,
   1027                                  cond_cost_list(cpi, cost_list),
   1028                                  &best_mv.as_fullmv, &best_mv_stats, NULL);
   1029 
   1030  const int use_subpel_search =
   1031      bestsme < INT_MAX && !cpi->common.features.cur_frame_force_integer_mv &&
   1032      use_subpixel &&
   1033      (cpi->sf.mv_sf.simple_motion_subpel_force_stop != FULL_PEL);
   1034  if (scaled_ref_frame) {
   1035    xd->plane[AOM_PLANE_Y].pre[ref_idx] = backup_yv12;
   1036  }
   1037  if (use_subpel_search) {
   1038    int not_used = 0;
   1039 
   1040    SUBPEL_MOTION_SEARCH_PARAMS ms_params;
   1041    av1_make_default_subpel_ms_params(&ms_params, cpi, x, bsize, &ref_mv,
   1042                                      cost_list);
   1043    // TODO(yunqing): integrate this into av1_make_default_subpel_ms_params().
   1044    ms_params.forced_stop = mv_sf->simple_motion_subpel_force_stop;
   1045 
   1046    MV subpel_start_mv = get_mv_from_fullmv(&best_mv.as_fullmv);
   1047    assert(av1_is_subpelmv_in_range(&ms_params.mv_limits, subpel_start_mv));
   1048 
   1049    cpi->mv_search_params.find_fractional_mv_step(
   1050        xd, cm, &ms_params, subpel_start_mv, &best_mv_stats, &best_mv.as_mv,
   1051        &not_used, &x->pred_sse[ref], NULL);
   1052 
   1053    mbmi->mv[0] = best_mv;
   1054 
   1055    // Get a copy of the prediction output
   1056    av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize,
   1057                                  AOM_PLANE_Y, AOM_PLANE_Y);
   1058    *var = cpi->ppi->fn_ptr[bsize].vf(
   1059        x->plane[0].src.buf, x->plane[0].src.stride, xd->plane[0].dst.buf,
   1060        xd->plane[0].dst.stride, sse);
   1061  } else {
   1062    // Manually convert from units of pixel to 1/8-pixels if we are not doing
   1063    // subpel search
   1064    convert_fullmv_to_mv(&best_mv);
   1065    *var = best_mv_stats.distortion;
   1066    *sse = best_mv_stats.sse;
   1067  }
   1068 
   1069  return best_mv;
   1070 }