findnearmv.c 9.79 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
/*
2
 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
John Koleszar's avatar
John Koleszar committed
3
 *
4
 *  Use of this source code is governed by a BSD-style license
5 6
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
7
 *  in the file PATENTS.  All contributing project authors may
8
 *  be found in the AUTHORS file in the root of the source tree.
John Koleszar's avatar
John Koleszar committed
9 10 11 12
 */


#include "findnearmv.h"
Christian Duvivier's avatar
Christian Duvivier committed
13
#include "vp8/encoder/variance.h"
14
#include <limits.h>
John Koleszar's avatar
John Koleszar committed
15

16
const unsigned char vp8_mbsplit_offset[4][16] = {
John Koleszar's avatar
John Koleszar committed
17 18 19 20
  { 0,  8,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0},
  { 0,  2,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0},
  { 0,  2,  8, 10,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0},
  { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15}
21 22
};

23
static void lower_mv_precision(int_mv *mv, int usehp)
24
{
25 26 27 28 29 30 31 32 33 34
#if CONFIG_NEWMVENTROPY
  if (!usehp || !vp8_use_nmv_hp(&mv->as_mv)) {
#else
  if (!usehp) {
#endif
    if (mv->as_mv.row & 1)
      mv->as_mv.row += (mv->as_mv.row > 0 ? -1 : 1);
    if (mv->as_mv.col & 1)
      mv->as_mv.col += (mv->as_mv.col > 0 ? -1 : 1);
  }
35 36
}

John Koleszar's avatar
John Koleszar committed
37 38 39
/* Predict motion vectors using those from already-decoded nearby blocks.
   Note that we only consider one 4x4 subblock from each candidate 16x16
   macroblock.   */
40

John Koleszar's avatar
John Koleszar committed
41 42
void vp8_find_near_mvs
(
John Koleszar's avatar
John Koleszar committed
43 44 45 46 47 48 49 50
  MACROBLOCKD *xd,
  const MODE_INFO *here,
  const MODE_INFO *lf_here,
  int_mv *nearest,
  int_mv *nearby,
  int_mv *best_mv,
  int cnt[4],
  int refframe,
51
  int *ref_frame_sign_bias) {
John Koleszar's avatar
John Koleszar committed
52 53 54 55 56 57 58 59 60
  const MODE_INFO *above = here - xd->mode_info_stride;
  const MODE_INFO *left = here - 1;
  const MODE_INFO *aboveleft = above - 1;
  const MODE_INFO *third = NULL;
  int_mv            near_mvs[4];
  int_mv           *mv = near_mvs;
  int             *cntx = cnt;
  enum {CNT_INTRA, CNT_NEAREST, CNT_NEAR, CNT_SPLITMV};

61 62 63 64
#if CONFIG_NEWBESTREFMV
  int_mv          *ref_mv = xd->ref_mv;
#endif

John Koleszar's avatar
John Koleszar committed
65 66 67
  /* Zero accumulators */
  mv[0].as_int = mv[1].as_int = mv[2].as_int = 0;
  cnt[0] = cnt[1] = cnt[2] = cnt[3] = 0;
68 69 70 71 72 73
#if CONFIG_NEWBESTREFMV
  ref_mv[0].as_int = ref_mv[1].as_int
                   = ref_mv[2].as_int
                   = ref_mv[3].as_int
                   = 0;
#endif
John Koleszar's avatar
John Koleszar committed
74 75 76

  /* Process above */
  if (above->mbmi.ref_frame != INTRA_FRAME) {
77
    if (above->mbmi.mv[0].as_int) {
78
      ++ mv;
79
      mv->as_int = above->mbmi.mv[0].as_int;
John Koleszar's avatar
John Koleszar committed
80 81
      mv_bias(ref_frame_sign_bias[above->mbmi.ref_frame],
              refframe, mv, ref_frame_sign_bias);
82 83 84
#if CONFIG_NEWBESTREFMV
      ref_mv[0].as_int = mv->as_int;
#endif
John Koleszar's avatar
John Koleszar committed
85
      ++cntx;
86
    }
John Koleszar's avatar
John Koleszar committed
87 88 89 90 91
    *cntx += 2;
  }

  /* Process left */
  if (left->mbmi.ref_frame != INTRA_FRAME) {
92
    if (left->mbmi.mv[0].as_int) {
John Koleszar's avatar
John Koleszar committed
93
      int_mv this_mv;
94
      this_mv.as_int = left->mbmi.mv[0].as_int;
John Koleszar's avatar
John Koleszar committed
95 96
      mv_bias(ref_frame_sign_bias[left->mbmi.ref_frame],
              refframe, &this_mv, ref_frame_sign_bias);
97 98 99
#if CONFIG_NEWBESTREFMV
      ref_mv[1].as_int = this_mv.as_int;
#endif
John Koleszar's avatar
John Koleszar committed
100
      if (this_mv.as_int != mv->as_int) {
101 102 103
        ++ mv;
        mv->as_int = this_mv.as_int;
        ++ cntx;
John Koleszar's avatar
John Koleszar committed
104 105 106 107 108 109 110 111
      }
      *cntx += 2;
    } else
      cnt[CNT_INTRA] += 2;
  }
  /* Process above left or the one from last frame */
  if (aboveleft->mbmi.ref_frame != INTRA_FRAME ||
      (lf_here->mbmi.ref_frame == LAST_FRAME && refframe == LAST_FRAME)) {
112
    if (aboveleft->mbmi.mv[0].as_int) {
John Koleszar's avatar
John Koleszar committed
113
      third = aboveleft;
114
#if CONFIG_NEWBESTREFMV
115
      ref_mv[2].as_int = aboveleft->mbmi.mv[0].as_int;
116 117 118
      mv_bias(ref_frame_sign_bias[aboveleft->mbmi.ref_frame],
              refframe, (ref_mv+2), ref_frame_sign_bias);
#endif
119
    } else if (lf_here->mbmi.mv[0].as_int) {
John Koleszar's avatar
John Koleszar committed
120
      third = lf_here;
121
    }
122
#if CONFIG_NEWBESTREFMV
123 124
    if (lf_here->mbmi.mv[0].as_int) {
      ref_mv[3].as_int = lf_here->mbmi.mv[0].as_int;
125 126 127 128
      mv_bias(ref_frame_sign_bias[lf_here->mbmi.ref_frame],
              refframe, (ref_mv+3), ref_frame_sign_bias);
    }
#endif
John Koleszar's avatar
John Koleszar committed
129 130
    if (third) {
      int_mv this_mv;
131
      this_mv.as_int = third->mbmi.mv[0].as_int;
John Koleszar's avatar
John Koleszar committed
132 133 134 135
      mv_bias(ref_frame_sign_bias[third->mbmi.ref_frame],
              refframe, &this_mv, ref_frame_sign_bias);

      if (this_mv.as_int != mv->as_int) {
136 137 138
        ++ mv;
        mv->as_int = this_mv.as_int;
        ++ cntx;
John Koleszar's avatar
John Koleszar committed
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
      }
      *cntx += 1;
    } else
      cnt[CNT_INTRA] += 1;
  }

  /* If we have three distinct MV's ... */
  if (cnt[CNT_SPLITMV]) {
    /* See if the third MV can be merged with NEAREST */
    if (mv->as_int == near_mvs[CNT_NEAREST].as_int)
      cnt[CNT_NEAREST] += 1;
  }

  cnt[CNT_SPLITMV] = ((above->mbmi.mode == SPLITMV)
                      + (left->mbmi.mode == SPLITMV)) * 2
                     + (
                       lf_here->mbmi.mode == SPLITMV ||
156 157
                       aboveleft->mbmi.mode == SPLITMV);

John Koleszar's avatar
John Koleszar committed
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
  /* Swap near and nearest if necessary */
  if (cnt[CNT_NEAR] > cnt[CNT_NEAREST]) {
    int tmp;
    tmp = cnt[CNT_NEAREST];
    cnt[CNT_NEAREST] = cnt[CNT_NEAR];
    cnt[CNT_NEAR] = tmp;
    tmp = near_mvs[CNT_NEAREST].as_int;
    near_mvs[CNT_NEAREST].as_int = near_mvs[CNT_NEAR].as_int;
    near_mvs[CNT_NEAR].as_int = tmp;
  }

  /* Use near_mvs[0] to store the "best" MV */
  if (cnt[CNT_NEAREST] >= cnt[CNT_INTRA])
    near_mvs[CNT_INTRA] = near_mvs[CNT_NEAREST];

  /* Set up return values */
  best_mv->as_int = near_mvs[0].as_int;
  nearest->as_int = near_mvs[CNT_NEAREST].as_int;
  nearby->as_int = near_mvs[CNT_NEAR].as_int;

  /* Make sure that the 1/8th bits of the Mvs are zero if high_precision
   * is not being used, by truncating the last bit towards 0
   */
181 182 183
  lower_mv_precision(best_mv, xd->allow_high_precision_mv);
  lower_mv_precision(nearest, xd->allow_high_precision_mv);
  lower_mv_precision(nearby, xd->allow_high_precision_mv);
184

John Koleszar's avatar
John Koleszar committed
185 186 187 188
  // TODO: move clamp outside findnearmv
  vp8_clamp_mv2(nearest, xd);
  vp8_clamp_mv2(nearby, xd);
  vp8_clamp_mv2(best_mv, xd);
189 190
}

Yaowu Xu's avatar
Yaowu Xu committed
191
vp8_prob *vp8_mv_ref_probs(VP8_COMMON *pc,
John Koleszar's avatar
John Koleszar committed
192 193 194 195 196 197 198
                           vp8_prob p[VP8_MVREFS - 1], const int near_mv_ref_ct[4]
                          ) {
  p[0] = pc->fc.vp8_mode_contexts [near_mv_ref_ct[0]] [0];
  p[1] = pc->fc.vp8_mode_contexts [near_mv_ref_ct[1]] [1];
  p[2] = pc->fc.vp8_mode_contexts [near_mv_ref_ct[2]] [2];
  p[3] = pc->fc.vp8_mode_contexts [near_mv_ref_ct[3]] [3];
  return p;
John Koleszar's avatar
John Koleszar committed
199
}
200 201 202 203 204 205

#if CONFIG_NEWBESTREFMV
/* check a list of motion vectors by sad score using a number rows of pixels
 * above and a number cols of pixels in the left to select the one with best
 * score to use as ref motion vector
 */
Paul Wilkins's avatar
Paul Wilkins committed
206 207 208 209

void vp8_find_best_ref_mvs(MACROBLOCKD *xd,
                           unsigned char *ref_y_buffer,
                           int ref_y_stride,
Paul Wilkins's avatar
Paul Wilkins committed
210
                           int_mv *mvlist,
Paul Wilkins's avatar
Paul Wilkins committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
                           int_mv *best_mv,
                           int_mv *nearest,
                           int_mv *near) {
  int i, j;
  unsigned char *above_src;
  unsigned char *left_src;
  unsigned char *above_ref;
  unsigned char *left_ref;
  int sad;
  int sad_scores[MAX_MV_REFS];
  int_mv sorted_mvs[MAX_MV_REFS];
  int zero_seen = FALSE;

  // Default all to 0,0 if nothing else available
  best_mv->as_int = nearest->as_int = near->as_int = 0;
  vpx_memset(sorted_mvs, 0, sizeof(sorted_mvs));

  above_src = xd->dst.y_buffer - xd->dst.y_stride * 2;
  left_src  = xd->dst.y_buffer - 2;
  above_ref = ref_y_buffer - ref_y_stride * 2;
  left_ref  = ref_y_buffer - 2;

Paul Wilkins's avatar
Paul Wilkins committed
233 234 235
  //for(i = 0; i < MAX_MV_REFS; ++i) {
  // Limit search to the predicted best 4
  for(i = 0; i < 4; ++i) {
Paul Wilkins's avatar
Paul Wilkins committed
236 237 238 239
    int_mv this_mv;
    int offset=0;
    int row_offset, col_offset;

Paul Wilkins's avatar
Paul Wilkins committed
240
    this_mv.as_int = mvlist[i].as_int;
Paul Wilkins's avatar
Paul Wilkins committed
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304

    // If we see a 0,0 vector for a second time we have reached the end of
    // the list of valid candidate vectors.
    if (!this_mv.as_int)
      if (zero_seen)
        break;
      else
        zero_seen = TRUE;

    vp8_clamp_mv(&this_mv,
                 xd->mb_to_left_edge - LEFT_TOP_MARGIN + 16,
                 xd->mb_to_right_edge + RIGHT_BOTTOM_MARGIN,
                 xd->mb_to_top_edge - LEFT_TOP_MARGIN + 16,
                 xd->mb_to_bottom_edge + RIGHT_BOTTOM_MARGIN);

    row_offset = (this_mv.as_mv.row > 0) ?
      ((this_mv.as_mv.row + 3) >> 3):((this_mv.as_mv.row + 4) >> 3);
    col_offset = (this_mv.as_mv.col > 0) ?
      ((this_mv.as_mv.col + 3) >> 3):((this_mv.as_mv.col + 4) >> 3);
    offset = ref_y_stride * row_offset + col_offset;

    sad = vp8_sad16x2_c(above_src, xd->dst.y_stride,
                        above_ref + offset, ref_y_stride, INT_MAX);

    sad += vp8_sad2x16_c(left_src, xd->dst.y_stride,
                         left_ref + offset, ref_y_stride, INT_MAX);

    // Add the entry to our list and then resort the list on score.
    sad_scores[i] = sad;
    sorted_mvs[i].as_int = this_mv.as_int;
    j = i;
    while (j > 0) {
      if (sad_scores[j] < sad_scores[j-1]) {
        sad_scores[j] = sad_scores[j-1];
        sorted_mvs[j].as_int = sorted_mvs[j-1].as_int;
        sad_scores[j-1] = sad;
        sorted_mvs[j-1].as_int = this_mv.as_int;
        j--;
      } else
        break;
    }
  }


  // Set the best mv to the first entry in the sorted list
  best_mv->as_int = sorted_mvs[0].as_int;

  // Provided that there are non zero vectors available there will not
  // be more than one 0,0 entry in the sorted list.
  // The best ref mv is always set to the first entry (which gave the best
  // results. The nearest is set to the first non zero vector if available and
  // near to the second non zero vector if avaialable.
  // We do not use 0,0 as a nearest or near as 0,0 has its own mode.
  if ( sorted_mvs[0].as_int ) {
    nearest->as_int = sorted_mvs[0].as_int;
    if ( sorted_mvs[1].as_int )
      near->as_int = sorted_mvs[1].as_int;
    else
      near->as_int = sorted_mvs[2].as_int;
  } else {
      nearest->as_int = sorted_mvs[1].as_int;
      near->as_int = sorted_mvs[2].as_int;
  }

Paul Wilkins's avatar
Paul Wilkins committed
305 306
  // Copy back the re-ordered mv list
  vpx_memcpy(mvlist, sorted_mvs, sizeof(sorted_mvs));
307
  lower_mv_precision(best_mv, xd->allow_high_precision_mv);
Paul Wilkins's avatar
Paul Wilkins committed
308 309 310 311 312

  vp8_clamp_mv2(best_mv, xd);
}

#endif  // CONFIG_NEWBESTREFMV