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

11
#include "vp9/common/vp9_mvref_common.h"
Paul Wilkins's avatar
Paul Wilkins committed
12 13

#define MVREF_NEIGHBOURS 8
14 15 16 17 18 19 20 21 22 23 24 25 26 27
static int mb_mv_ref_search[MVREF_NEIGHBOURS][2] = {
    {0, -1}, {-1, 0}, {-1, -1}, {0, -2},
    {-2, 0}, {-1, -2}, {-2, -1}, {-2, -2}
};
static int mb_ref_distance_weight[MVREF_NEIGHBOURS] =
  { 3, 3, 2, 1, 1, 1, 1, 1 };
#if CONFIG_SUPERBLOCKS
static int sb_mv_ref_search[MVREF_NEIGHBOURS][2] = {
    {0, -1}, {-1, 0}, {1, -1}, {-1, 1},
    {-1, -1}, {0, -2}, {-2, 0}, {-1, -2}
};
static int sb_ref_distance_weight[MVREF_NEIGHBOURS] =
  { 3, 3, 2, 2, 2, 1, 1, 1 };
#endif
Paul Wilkins's avatar
Paul Wilkins committed
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
// clamp_mv
#define MV_BORDER (16 << 3) // Allow 16 pels in 1/8th pel units
static void clamp_mv(const MACROBLOCKD *xd, int_mv *mv) {

  if (mv->as_mv.col < (xd->mb_to_left_edge - MV_BORDER))
    mv->as_mv.col = xd->mb_to_left_edge - MV_BORDER;
  else if (mv->as_mv.col > xd->mb_to_right_edge + MV_BORDER)
    mv->as_mv.col = xd->mb_to_right_edge + MV_BORDER;

  if (mv->as_mv.row < (xd->mb_to_top_edge - MV_BORDER))
    mv->as_mv.row = xd->mb_to_top_edge - MV_BORDER;
  else if (mv->as_mv.row > xd->mb_to_bottom_edge + MV_BORDER)
    mv->as_mv.row = xd->mb_to_bottom_edge + MV_BORDER;
}


// Gets a best matching candidate refenence motion vector
// from the given mode info structure (if available)
Paul Wilkins's avatar
Paul Wilkins committed
46
static int get_candidate_mvref(
Paul Wilkins's avatar
Paul Wilkins committed
47 48
  const MODE_INFO *candidate_mi,
  MV_REFERENCE_FRAME ref_frame,
Paul Wilkins's avatar
Paul Wilkins committed
49 50 51 52
  MV_REFERENCE_FRAME *c_ref_frame,
  int_mv *c_mv,
  MV_REFERENCE_FRAME *c2_ref_frame,
  int_mv *c2_mv
Paul Wilkins's avatar
Paul Wilkins committed
53 54 55
) {

  int ret_val = FALSE;
Paul Wilkins's avatar
Paul Wilkins committed
56 57
  c2_mv->as_int = 0;
  *c2_ref_frame = INTRA_FRAME;
Paul Wilkins's avatar
Paul Wilkins committed
58

Paul Wilkins's avatar
Paul Wilkins committed
59
  // Target ref frame matches candidate first ref frame
Paul Wilkins's avatar
Paul Wilkins committed
60
  if (ref_frame == candidate_mi->mbmi.ref_frame) {
61
    c_mv->as_int = candidate_mi->mbmi.mv[0].as_int;
Paul Wilkins's avatar
Paul Wilkins committed
62
    *c_ref_frame = ref_frame;
Paul Wilkins's avatar
Paul Wilkins committed
63 64
    ret_val = TRUE;

Paul Wilkins's avatar
Paul Wilkins committed
65
    // Is there a second non zero vector we can use.
66
    if ((candidate_mi->mbmi.second_ref_frame > INTRA_FRAME) &&
67 68 69
        (candidate_mi->mbmi.mv[1].as_int != 0) &&
        (candidate_mi->mbmi.mv[1].as_int != c_mv->as_int)) {
      c2_mv->as_int = candidate_mi->mbmi.mv[1].as_int;
Paul Wilkins's avatar
Paul Wilkins committed
70 71 72 73
      *c2_ref_frame = candidate_mi->mbmi.second_ref_frame;
    }

  // Target ref frame matches candidate second ref frame
Paul Wilkins's avatar
Paul Wilkins committed
74
  } else if (ref_frame == candidate_mi->mbmi.second_ref_frame) {
75
    c_mv->as_int = candidate_mi->mbmi.mv[1].as_int;
Paul Wilkins's avatar
Paul Wilkins committed
76
    *c_ref_frame = ref_frame;
Paul Wilkins's avatar
Paul Wilkins committed
77 78
    ret_val = TRUE;

Paul Wilkins's avatar
Paul Wilkins committed
79
    // Is there a second non zero vector we can use.
80
    if ((candidate_mi->mbmi.ref_frame > INTRA_FRAME) &&
81 82 83
        (candidate_mi->mbmi.mv[0].as_int != 0) &&
        (candidate_mi->mbmi.mv[0].as_int != c_mv->as_int)) {
      c2_mv->as_int = candidate_mi->mbmi.mv[0].as_int;
Paul Wilkins's avatar
Paul Wilkins committed
84 85 86 87
      *c2_ref_frame = candidate_mi->mbmi.ref_frame;
    }

  // No ref frame matches so use first ref mv as first choice
88
  } else if (candidate_mi->mbmi.ref_frame > INTRA_FRAME) {
89
    c_mv->as_int = candidate_mi->mbmi.mv[0].as_int;
Paul Wilkins's avatar
Paul Wilkins committed
90
    *c_ref_frame = candidate_mi->mbmi.ref_frame;
Paul Wilkins's avatar
Paul Wilkins committed
91 92
    ret_val = TRUE;

Paul Wilkins's avatar
Paul Wilkins committed
93
    // Is there a second non zero vector we can use.
94
    if ((candidate_mi->mbmi.second_ref_frame > INTRA_FRAME) &&
95 96 97
        (candidate_mi->mbmi.mv[1].as_int != 0) &&
        (candidate_mi->mbmi.mv[1].as_int != c_mv->as_int)) {
      c2_mv->as_int = candidate_mi->mbmi.mv[1].as_int;
Paul Wilkins's avatar
Paul Wilkins committed
98 99 100 101 102
      *c2_ref_frame = candidate_mi->mbmi.second_ref_frame;
    }

  // If only the second ref mv is valid:- (Should not trigger in current code
  // base given current possible compound prediction options).
103
  } else if (candidate_mi->mbmi.second_ref_frame > INTRA_FRAME) {
104
    c_mv->as_int = candidate_mi->mbmi.mv[1].as_int;
Paul Wilkins's avatar
Paul Wilkins committed
105
    *c_ref_frame = candidate_mi->mbmi.second_ref_frame;
Paul Wilkins's avatar
Paul Wilkins committed
106 107 108 109 110 111 112 113
    ret_val = TRUE;
  }

  return ret_val;
}

// Performs mv adjustment based on reference frame and clamps the MV
// if it goes off the edge of the buffer.
Paul Wilkins's avatar
Paul Wilkins committed
114
static void scale_mv(
Paul Wilkins's avatar
Paul Wilkins committed
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
  MACROBLOCKD *xd,
  MV_REFERENCE_FRAME this_ref_frame,
  MV_REFERENCE_FRAME candidate_ref_frame,
  int_mv *candidate_mv,
  int *ref_sign_bias
) {

  if (candidate_ref_frame != this_ref_frame) {

    //int frame_distances[MAX_REF_FRAMES];
    //int last_distance = 1;
    //int gf_distance = xd->frames_since_golden;
    //int arf_distance = xd->frames_till_alt_ref_frame;

    // Sign inversion where appropriate.
    if (ref_sign_bias[candidate_ref_frame] != ref_sign_bias[this_ref_frame]) {
      candidate_mv->as_mv.row = -candidate_mv->as_mv.row;
      candidate_mv->as_mv.col = -candidate_mv->as_mv.col;
    }

    // Scale based on frame distance if the reference frames not the same.
    /*frame_distances[INTRA_FRAME] = 1;   // should never be used
    frame_distances[LAST_FRAME] = 1;
    frame_distances[GOLDEN_FRAME] =
      (xd->frames_since_golden) ? xd->frames_since_golden : 1;
    frame_distances[ALTREF_FRAME] =
      (xd->frames_till_alt_ref_frame) ? xd->frames_till_alt_ref_frame : 1;

    if (frame_distances[this_ref_frame] &&
        frame_distances[candidate_ref_frame]) {
      candidate_mv->as_mv.row =
        (short)(((int)(candidate_mv->as_mv.row) *
                 frame_distances[this_ref_frame]) /
                frame_distances[candidate_ref_frame]);

      candidate_mv->as_mv.col =
        (short)(((int)(candidate_mv->as_mv.col) *
                 frame_distances[this_ref_frame]) /
                frame_distances[candidate_ref_frame]);
    }
    */
  }

  // Clamp the MV so it does not point out of the frame buffer
  clamp_mv(xd, candidate_mv);
}

// Adds a new candidate reference vector to the list if indeed it is new.
// If it is not new then the score of the existing candidate that it matches
// is increased and the list is resorted.
Paul Wilkins's avatar
Paul Wilkins committed
165
static void addmv_and_shuffle(
Paul Wilkins's avatar
Paul Wilkins committed
166 167 168 169 170 171 172 173 174 175 176
  int_mv *mv_list,
  int *mv_scores,
  int *index,
  int_mv candidate_mv,
  int weight
) {

  int i = *index;
  int duplicate_found = FALSE;

  // Check for duplicates. If there is one increment its score.
Paul Wilkins's avatar
Paul Wilkins committed
177
  // Duplicate defined as being the same full pel vector with rounding.
Paul Wilkins's avatar
Paul Wilkins committed
178 179
  while (i > 0) {
    i--;
Paul Wilkins's avatar
Paul Wilkins committed
180

Paul Wilkins's avatar
Paul Wilkins committed
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
    if (candidate_mv.as_int == mv_list[i].as_int) {
      duplicate_found = TRUE;
      mv_scores[i] += weight;
      break;
    }
  }

  // If no duplicate was found add the new vector and give it a weight
  if (!duplicate_found) {
    mv_list[*index].as_int = candidate_mv.as_int;
    mv_scores[*index] = weight;
    i = *index;
    (*index)++;
  }

  // Reshuffle the list so that highest scoring mvs at the top.
  while (i > 0) {
    if (mv_scores[i] > mv_scores[i-1]) {
      int tmp_score = mv_scores[i-1];
      int_mv tmp_mv = mv_list[i-1];

      mv_scores[i-1] = mv_scores[i];
      mv_list[i-1] = mv_list[i];
      mv_scores[i] = tmp_score;
      mv_list[i] = tmp_mv;
      i--;
    } else
      break;
  }
}

// This function searches the neighbourhood of a given MB/SB and populates a
// list of candidate reference vectors.
//
Paul Wilkins's avatar
Paul Wilkins committed
215
void vp9_find_mv_refs(
Paul Wilkins's avatar
Paul Wilkins committed
216 217 218 219 220 221 222 223 224 225
  MACROBLOCKD *xd,
  MODE_INFO *here,
  MODE_INFO *lf_here,
  MV_REFERENCE_FRAME ref_frame,
  int_mv *mv_ref_list,
  int *ref_sign_bias
) {

  int i;
  MODE_INFO *candidate_mi;
Paul Wilkins's avatar
Paul Wilkins committed
226
  MB_MODE_INFO * mbmi = &xd->mode_info_context->mbmi;
Paul Wilkins's avatar
Paul Wilkins committed
227 228 229
  int_mv candidate_mvs[MAX_MV_REFS];
  int_mv c_refmv;
  MV_REFERENCE_FRAME c_ref_frame;
Paul Wilkins's avatar
Paul Wilkins committed
230 231
  int_mv c2_refmv;
  MV_REFERENCE_FRAME c2_ref_frame;
Paul Wilkins's avatar
Paul Wilkins committed
232 233
  int candidate_scores[MAX_MV_REFS];
  int index = 0;
234
  int split_count = 0;
Paul Wilkins's avatar
Paul Wilkins committed
235 236
  int ref_weight = 0;
  int valid_mv_ref;
237 238
  int (*mv_ref_search)[2];
  int *ref_distance_weight;
Paul Wilkins's avatar
Paul Wilkins committed
239 240 241 242 243 244

  // Blank the reference vector lists and other local structures.
  vpx_memset(mv_ref_list, 0, sizeof(int_mv) * MAX_MV_REFS);
  vpx_memset(candidate_mvs, 0, sizeof(int_mv) * MAX_MV_REFS);
  vpx_memset(candidate_scores, 0, sizeof(candidate_scores));

245 246 247 248 249 250 251 252 253 254 255 256
#if CONFIG_SUPERBLOCKS
  if (mbmi->encoded_as_sb) {
    mv_ref_search = sb_mv_ref_search;
    ref_distance_weight = sb_ref_distance_weight;
  } else {
    mv_ref_search = mb_mv_ref_search;
    ref_distance_weight = mb_ref_distance_weight;
  }
#else
  mv_ref_search = mb_mv_ref_search;
  ref_distance_weight = mb_ref_distance_weight;
#endif
Paul Wilkins's avatar
Paul Wilkins committed
257 258 259 260 261 262 263 264 265 266
  // Populate a list with candidate reference vectors from the
  // spatial neighbours.
  for (i = 0; i < 2; ++i) {
    if (((mv_ref_search[i][0] << 7) >= xd->mb_to_left_edge) &&
        ((mv_ref_search[i][1] << 7) >= xd->mb_to_top_edge)) {

      candidate_mi = here + mv_ref_search[i][0] +
                     (mv_ref_search[i][1] * xd->mode_info_stride);

      valid_mv_ref = get_candidate_mvref(candidate_mi, ref_frame,
Paul Wilkins's avatar
Paul Wilkins committed
267 268
                                         &c_ref_frame, &c_refmv,
                                         &c2_ref_frame, &c2_refmv);
Paul Wilkins's avatar
Paul Wilkins committed
269

Paul Wilkins's avatar
Paul Wilkins committed
270
      // If there is a valid MV candidate then add it to the list
Paul Wilkins's avatar
Paul Wilkins committed
271
      if (valid_mv_ref) {
Paul Wilkins's avatar
Paul Wilkins committed
272 273 274
        scale_mv(xd, ref_frame, c_ref_frame, &c_refmv, ref_sign_bias );
        ref_weight = ref_distance_weight[i] +
                     ((c_ref_frame == ref_frame) << 4);
275
        split_count += (candidate_mi->mbmi.mode == SPLITMV);
Paul Wilkins's avatar
Paul Wilkins committed
276 277 278 279 280 281 282

        addmv_and_shuffle(candidate_mvs, candidate_scores,
                          &index, c_refmv, ref_weight);

        // If there is a second valid mv then add it as well.
        if (c2_ref_frame != INTRA_FRAME) {
          scale_mv(xd, ref_frame, c2_ref_frame, &c2_refmv, ref_sign_bias );
Paul Wilkins's avatar
Paul Wilkins committed
283
          ref_weight = ref_distance_weight[i] +
Paul Wilkins's avatar
Paul Wilkins committed
284
                       ((c2_ref_frame == ref_frame) << 4);
Paul Wilkins's avatar
Paul Wilkins committed
285 286

          addmv_and_shuffle(candidate_mvs, candidate_scores,
Paul Wilkins's avatar
Paul Wilkins committed
287 288
                            &index, c2_refmv, ref_weight);
        }
Paul Wilkins's avatar
Paul Wilkins committed
289 290 291 292 293 294 295
      }
    }
  }

  // Look at the corresponding vector in the last frame
  candidate_mi = lf_here;
  valid_mv_ref = get_candidate_mvref(candidate_mi, ref_frame,
Paul Wilkins's avatar
Paul Wilkins committed
296 297 298 299
                                     &c_ref_frame, &c_refmv,
                                     &c2_ref_frame, &c2_refmv);

  // If there is a valid MV candidate then add it to the list
Paul Wilkins's avatar
Paul Wilkins committed
300 301
  if (valid_mv_ref) {
    scale_mv(xd, ref_frame, c_ref_frame, &c_refmv, ref_sign_bias );
Paul Wilkins's avatar
Paul Wilkins committed
302
    ref_weight = 2 + ((c_ref_frame == ref_frame) << 4);
Paul Wilkins's avatar
Paul Wilkins committed
303 304
    addmv_and_shuffle(candidate_mvs, candidate_scores,
                      &index, c_refmv, ref_weight);
Paul Wilkins's avatar
Paul Wilkins committed
305 306 307 308 309 310 311 312 313 314

    // If there is a second valid mv then add it as well.
    if (c2_ref_frame != INTRA_FRAME) {
      scale_mv(xd, ref_frame, c2_ref_frame, &c2_refmv, ref_sign_bias );
      ref_weight = ref_distance_weight[i] +
                   ((c2_ref_frame == ref_frame) << 4);

      addmv_and_shuffle(candidate_mvs, candidate_scores,
                        &index, c2_refmv, ref_weight);
    }
Paul Wilkins's avatar
Paul Wilkins committed
315 316 317 318
  }

  // Populate a list with candidate reference vectors from the
  // spatial neighbours.
Paul Wilkins's avatar
Paul Wilkins committed
319
  for (i = 2; (i < MVREF_NEIGHBOURS) && (index < (MAX_MV_REFS - 2)); ++i) {
Paul Wilkins's avatar
Paul Wilkins committed
320 321 322 323 324 325 326
    if (((mv_ref_search[i][0] << 7) >= xd->mb_to_left_edge) &&
        ((mv_ref_search[i][1] << 7) >= xd->mb_to_top_edge)) {

      candidate_mi = here + mv_ref_search[i][0] +
                     (mv_ref_search[i][1] * xd->mode_info_stride);

      valid_mv_ref = get_candidate_mvref(candidate_mi, ref_frame,
Paul Wilkins's avatar
Paul Wilkins committed
327 328
                                         &c_ref_frame, &c_refmv,
                                         &c2_ref_frame, &c2_refmv);
Paul Wilkins's avatar
Paul Wilkins committed
329

Paul Wilkins's avatar
Paul Wilkins committed
330
      // If there is a valid MV candidate then add it to the list
Paul Wilkins's avatar
Paul Wilkins committed
331
      if (valid_mv_ref) {
Paul Wilkins's avatar
Paul Wilkins committed
332 333 334 335 336 337 338 339 340 341
        scale_mv(xd, ref_frame, c_ref_frame, &c_refmv, ref_sign_bias );
        ref_weight = ref_distance_weight[i] +
                     ((c_ref_frame == ref_frame) << 4);

        addmv_and_shuffle(candidate_mvs, candidate_scores,
                          &index, c_refmv, ref_weight);

        // If there is a second valid mv then add it as well.
        if (c2_ref_frame != INTRA_FRAME) {
          scale_mv(xd, ref_frame, c2_ref_frame, &c2_refmv, ref_sign_bias );
Paul Wilkins's avatar
Paul Wilkins committed
342
          ref_weight = ref_distance_weight[i] +
Paul Wilkins's avatar
Paul Wilkins committed
343
                       ((c2_ref_frame == ref_frame) << 4);
Paul Wilkins's avatar
Paul Wilkins committed
344 345

          addmv_and_shuffle(candidate_mvs, candidate_scores,
Paul Wilkins's avatar
Paul Wilkins committed
346 347
                            &index, c2_refmv, ref_weight);
        }
Paul Wilkins's avatar
Paul Wilkins committed
348 349 350 351
      }
    }
  }

Paul Wilkins's avatar
Paul Wilkins committed
352 353 354 355 356
  // Make sure we are able to add 0,0
  if (index > (MAX_MV_REFS - 1)) {
    index = (MAX_MV_REFS - 1);
  }

357 358
  // Define inter mode coding context.
  // 0,0 was best
Paul Wilkins's avatar
Paul Wilkins committed
359
  if (candidate_mvs[0].as_int == 0) {
360 361
    // 0,0 is only candidate
    if (index <= 1) {
Paul Wilkins's avatar
Paul Wilkins committed
362
      mbmi->mb_mode_context[ref_frame] = 0;
363 364
    // non zero candidates candidates available
    } else if (split_count == 0) {
Paul Wilkins's avatar
Paul Wilkins committed
365 366 367 368
      mbmi->mb_mode_context[ref_frame] = 1;
    } else {
      mbmi->mb_mode_context[ref_frame] = 2;
    }
369 370 371
  // Non zero best, No Split MV cases
  } else if (split_count == 0) {
    if (candidate_scores[0] >= 32) {
Paul Wilkins's avatar
Paul Wilkins committed
372 373 374 375
      mbmi->mb_mode_context[ref_frame] = 3;
    } else {
      mbmi->mb_mode_context[ref_frame] = 4;
    }
376
  // Non zero best, some split mv
Paul Wilkins's avatar
Paul Wilkins committed
377
  } else {
378 379 380 381 382
    if (candidate_scores[0] >= 32) {
      mbmi->mb_mode_context[ref_frame] = 5;
    } else {
      mbmi->mb_mode_context[ref_frame] = 6;
    }
Paul Wilkins's avatar
Paul Wilkins committed
383 384
  }

Paul Wilkins's avatar
Paul Wilkins committed
385
  // 0,0 is always a valid reference.
386
  for (i = 0; i < index; ++i) {
Paul Wilkins's avatar
Paul Wilkins committed
387 388
    if (candidate_mvs[i].as_int == 0)
      break;
389
  }
Paul Wilkins's avatar
Paul Wilkins committed
390 391 392
  if (i == index) {
    c_refmv.as_int = 0;
    addmv_and_shuffle(candidate_mvs, candidate_scores,
Paul Wilkins's avatar
Paul Wilkins committed
393
                      &index, c_refmv, candidate_scores[3]+1 );
Paul Wilkins's avatar
Paul Wilkins committed
394 395 396 397 398
  }

  // Copy over the candidate list.
  vpx_memcpy(mv_ref_list, candidate_mvs, sizeof(candidate_mvs));
}