vp9_mvref_common.c 10.3 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
Jim Bankoski's avatar
Jim Bankoski committed
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72

typedef enum {
  BOTH_ZERO = 0,
  ZERO_PLUS_PREDICTED = 1,
  BOTH_PREDICTED = 2,
  NEW_PLUS_NON_INTRA = 3,
  BOTH_NEW = 4,
  INTRA_PLUS_NON_INTRA = 5,
  BOTH_INTRA = 6,
  INVALID_CASE = 9
} motion_vector_context;

// This is used to figure out a context for the ref blocks. The code flattens
// an array that would have 3 possible counts (0, 1 & 2) for 3 choices by
// adding 9 for each intra block, 3 for each zero mv and 1 for each new
// motion vector. This single number is then converted into a context
// with a single lookup ( counter_to_context ).
static const int mode_2_counter[MB_MODE_COUNT] = {
  9,  // DC_PRED
  9,  // V_PRED
  9,  // H_PRED
  9,  // D45_PRED
  9,  // D135_PRED
  9,  // D117_PRED
  9,  // D153_PRED
  9,  // D27_PRED
  9,  // D63_PRED
  9,  // TM_PRED
  0,  // NEARESTMV
  0,  // NEARMV
  3,  // ZEROMV
  1,  // NEWMV
};

// There are 3^3 different combinations of 3 counts that can be either 0,1 or
// 2. However the actual count can never be greater than 2 so the highest
// counter we need is 18. 9 is an invalid counter that's never used.
static const int counter_to_context[19] = {
  BOTH_PREDICTED,  // 0
  NEW_PLUS_NON_INTRA,  // 1
  BOTH_NEW,  // 2
  ZERO_PLUS_PREDICTED,  // 3
  NEW_PLUS_NON_INTRA,  // 4
  INVALID_CASE,  // 5
  BOTH_ZERO,  // 6
  INVALID_CASE,  // 7
  INVALID_CASE,  // 8
  INTRA_PLUS_NON_INTRA,  // 9
  INTRA_PLUS_NON_INTRA,  // 10
  INVALID_CASE,  // 11
  INTRA_PLUS_NON_INTRA,  // 12
  INVALID_CASE,  // 13
  INVALID_CASE,  // 14
  INVALID_CASE,  // 15
  INVALID_CASE,  // 16
  INVALID_CASE,  // 17
  BOTH_INTRA  // 18
};

73
static const MV mv_ref_blocks[BLOCK_SIZES][MVREF_NEIGHBOURS] = {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
74
  // 4X4
75
  {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
76
  // 4X8
77
  {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
78
  // 8X4
79
  {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
80
  // 8X8
81
  {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
82
  // 8X16
83
  {{0, -1}, {-1, 0}, {1, -1}, {-1, -1}, {0, -2}, {-2, 0}, {-2, -1}, {-1, -2}},
84 85
  // 16X8
  {{-1, 0}, {0, -1}, {-1, 1}, {-1, -1}, {-2, 0}, {0, -2}, {-1, -2}, {-2, -1}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
86
  // 16X16
87
  {{-1, 0}, {0, -1}, {-1, 1}, {1, -1}, {-1, -1}, {-3, 0}, {0, -3}, {-3, -3}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
88
  // 16X32
89
  {{0, -1}, {-1, 0}, {2, -1}, {-1, -1}, {-1, 1}, {0, -3}, {-3, 0}, {-3, -3}},
90 91
  // 32X16
  {{-1, 0}, {0, -1}, {-1, 2}, {-1, -1}, {1, -1}, {-3, 0}, {0, -3}, {-3, -3}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
92
  // 32X32
93
  {{-1, 1}, {1, -1}, {-1, 2}, {2, -1}, {-1, -1}, {-3, 0}, {0, -3}, {-3, -3}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
94
  // 32X64
95
  {{0, -1}, {-1, 0}, {4, -1}, {-1, 2}, {-1, -1}, {0, -3}, {-3, 0}, {2, -1}},
96 97
  // 64X32
  {{-1, 0}, {0, -1}, {-1, 4}, {2, -1}, {-1, -1}, {-3, 0}, {0, -3}, {-1, 2}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
98
  // 64X64
99
  {{-1, 3}, {3, -1}, {-1, 4}, {4, -1}, {-1, -1}, {-1, 0}, {0, -1}, {-1, 6}}
100
};
Jim Bankoski's avatar
Jim Bankoski committed
101 102 103 104 105 106 107 108

static const int idx_n_column_to_subblock[4][2] = {
  {1, 2},
  {1, 3},
  {3, 2},
  {3, 3}
};

Paul Wilkins's avatar
Paul Wilkins committed
109
// clamp_mv_ref
Paul Wilkins's avatar
Paul Wilkins committed
110 111
#define MV_BORDER (16 << 3) // Allow 16 pels in 1/8th pel units

Dmitry Kovalev's avatar
Dmitry Kovalev committed
112 113 114 115 116
static void clamp_mv_ref(MV *mv, const MACROBLOCKD *xd) {
  clamp_mv(mv, xd->mb_to_left_edge - MV_BORDER,
               xd->mb_to_right_edge + MV_BORDER,
               xd->mb_to_top_edge - MV_BORDER,
               xd->mb_to_bottom_edge + MV_BORDER);
Paul Wilkins's avatar
Paul Wilkins committed
117 118
}

Jim Bankoski's avatar
Jim Bankoski committed
119 120 121 122 123
// This function returns either the appropriate sub block or block's mv
// on whether the block_size < 8x8 and we have check_sub_blocks set.
static INLINE int_mv get_sub_block_mv(const MODE_INFO *candidate,
                                      int check_sub_blocks, int which_mv,
                                      int search_col, int block_idx) {
124
  return (check_sub_blocks && candidate->mbmi.sb_type < BLOCK_8X8
Jim Bankoski's avatar
Jim Bankoski committed
125 126 127
          ? candidate->bmi[idx_n_column_to_subblock[block_idx][search_col == 0]]
              .as_mv[which_mv]
          : candidate->mbmi.mv[which_mv]);
Paul Wilkins's avatar
Paul Wilkins committed
128 129
}

Paul Wilkins's avatar
Paul Wilkins committed
130 131

// Performs mv sign inversion if indicated by the reference frame combination.
Jim Bankoski's avatar
Jim Bankoski committed
132 133 134 135
static INLINE int_mv scale_mv(const MODE_INFO *candidate, const int which_mv,
                              const MV_REFERENCE_FRAME this_ref_frame,
                              const int *ref_sign_bias) {
  int_mv return_mv = candidate->mbmi.mv[which_mv];
Paul Wilkins's avatar
Paul Wilkins committed
136 137

  // Sign inversion where appropriate.
Jim Bankoski's avatar
Jim Bankoski committed
138 139 140 141
  if (ref_sign_bias[candidate->mbmi.ref_frame[which_mv]] !=
      ref_sign_bias[this_ref_frame]) {
    return_mv.as_mv.row *= -1;
    return_mv.as_mv.col *= -1;
Paul Wilkins's avatar
Paul Wilkins committed
142
  }
Jim Bankoski's avatar
Jim Bankoski committed
143
  return return_mv;
Paul Wilkins's avatar
Paul Wilkins committed
144 145
}

Jim Bankoski's avatar
Jim Bankoski committed
146 147 148 149 150 151 152 153 154 155 156
// This macro is used to add a motion vector mv_ref list if it isn't
// already in the list.  If it's the second motion vector it will also
// skip all additional processing and jump to done!
#define ADD_MV_REF_LIST(MV) \
  if (refmv_count) { \
    if ((MV).as_int != mv_ref_list[0].as_int) { \
      mv_ref_list[refmv_count] = (MV); \
      goto Done; \
    } \
  } else { \
    mv_ref_list[refmv_count++] = (MV); \
Paul Wilkins's avatar
Paul Wilkins committed
157
  }
Jim Bankoski's avatar
Jim Bankoski committed
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172

// If either reference frame is different, not INTRA, and they
// are different from each other scale and add the mv to our list.
#define IF_DIFF_REF_FRAME_ADD_MV(CANDIDATE) \
  if ((CANDIDATE)->mbmi.ref_frame[0] != ref_frame) { \
    ADD_MV_REF_LIST(scale_mv((CANDIDATE), 0, ref_frame, ref_sign_bias)); \
  } \
  if ((CANDIDATE)->mbmi.ref_frame[1] != ref_frame && \
      (CANDIDATE)->mbmi.ref_frame[1] > INTRA_FRAME && \
      (CANDIDATE)->mbmi.mv[1].as_int != (CANDIDATE)->mbmi.mv[0].as_int) { \
    ADD_MV_REF_LIST(scale_mv((CANDIDATE), 1, ref_frame, ref_sign_bias)); \
  }

// Checks that the given mi_row, mi_col and search point
// are inside the borders of the tile.
Dmitry Kovalev's avatar
Dmitry Kovalev committed
173
static INLINE int is_inside(int mi_col, int mi_row, int cur_tile_mi_col_start,
174
                            const MV *mv_ref) {
Jim Bankoski's avatar
Jim Bankoski committed
175 176 177
  // Check that the candidate is within the border.  We only need to check
  // the left side because all the positive right side ones are for blocks that
  // are large enough to support the + value they have within their border.
178 179
  return !(mi_row + mv_ref->row < 0 ||
           mi_col + mv_ref->col < cur_tile_mi_col_start);
Paul Wilkins's avatar
Paul Wilkins committed
180
}
Paul Wilkins's avatar
Paul Wilkins committed
181

Paul Wilkins's avatar
Paul Wilkins committed
182 183
// This function searches the neighbourhood of a given MB/SB
// to try and find candidate reference vectors.
Ronald S. Bultje's avatar
Ronald S. Bultje committed
184
void vp9_find_mv_refs_idx(VP9_COMMON *cm, MACROBLOCKD *xd, MODE_INFO *here,
Jim Bankoski's avatar
Jim Bankoski committed
185 186 187 188 189 190 191
                          const MODE_INFO *lf_here,
                          const MV_REFERENCE_FRAME ref_frame,
                          int_mv *mv_ref_list, const int *ref_sign_bias,
                          const int block_idx,
                          const int mi_row, const int mi_col) {
  int idx;
  MB_MODE_INFO *mbmi = &xd->mode_info_context->mbmi;
Paul Wilkins's avatar
Paul Wilkins committed
192
  int refmv_count = 0;
193
  const MV *mv_ref_search = mv_ref_blocks[mbmi->sb_type];
Jim Bankoski's avatar
Jim Bankoski committed
194 195 196 197 198 199 200 201 202 203 204 205
  const MODE_INFO *candidate;
  const int check_sub_blocks = block_idx >= 0;
  int different_ref_found = 0;
  int context_counter = 0;

  // Blank the reference vector list
  vpx_memset(mv_ref_list, 0, sizeof(*mv_ref_list) * MAX_MV_REF_CANDIDATES);

  // The nearest 2 blocks are treated differently
  // if the size < 8x8 we get the mv from the bmi substructure,
  // and we also need to keep a mode count.
  for (idx = 0; idx < 2; ++idx) {
206
    const MV *mv_ref = &mv_ref_search[idx];
Dmitry Kovalev's avatar
Dmitry Kovalev committed
207 208

    if (!is_inside(mi_col, mi_row, cm->cur_tile_mi_col_start, mv_ref))
Jim Bankoski's avatar
Jim Bankoski committed
209 210
      continue;

211
    candidate = here + mv_ref->col + mv_ref->row * xd->mode_info_stride;
Jim Bankoski's avatar
Jim Bankoski committed
212 213 214 215 216 217 218

    // Keep counts for entropy encoding.
    context_counter += mode_2_counter[candidate->mbmi.mode];

    // Check if the candidate comes from the same reference frame.
    if (candidate->mbmi.ref_frame[0] == ref_frame) {
      ADD_MV_REF_LIST(get_sub_block_mv(candidate, check_sub_blocks, 0,
219
                                       mv_ref->col, block_idx));
Jim Bankoski's avatar
Jim Bankoski committed
220 221 222 223 224 225
      different_ref_found = candidate->mbmi.ref_frame[1] != ref_frame;
    } else {
      different_ref_found = 1;
      if (candidate->mbmi.ref_frame[1] == ref_frame) {
        // Add second motion vector if it has the same ref_frame.
        ADD_MV_REF_LIST(get_sub_block_mv(candidate, check_sub_blocks, 1,
226
                                         mv_ref->col, block_idx));
Ronald S. Bultje's avatar
Ronald S. Bultje committed
227
      }
Paul Wilkins's avatar
Paul Wilkins committed
228 229
    }
  }
Paul Wilkins's avatar
Paul Wilkins committed
230

Jim Bankoski's avatar
Jim Bankoski committed
231 232 233 234
  // Check the rest of the neighbors in much the same way
  // as before except we don't need to keep track of sub blocks or
  // mode counts.
  for (; idx < MVREF_NEIGHBOURS; ++idx) {
235
    const MV *mv_ref = &mv_ref_search[idx];
Dmitry Kovalev's avatar
Dmitry Kovalev committed
236
    if (!is_inside(mi_col, mi_row, cm->cur_tile_mi_col_start, mv_ref))
Jim Bankoski's avatar
Jim Bankoski committed
237
      continue;
Paul Wilkins's avatar
Paul Wilkins committed
238

239
    candidate = here + mv_ref->col + mv_ref->row * xd->mode_info_stride;
240

Jim Bankoski's avatar
Jim Bankoski committed
241 242 243 244 245 246 247
    if (candidate->mbmi.ref_frame[0] == ref_frame) {
      ADD_MV_REF_LIST(candidate->mbmi.mv[0]);
      different_ref_found = candidate->mbmi.ref_frame[1] != ref_frame;
    } else {
      different_ref_found = 1;
      if (candidate->mbmi.ref_frame[1] == ref_frame) {
        ADD_MV_REF_LIST(candidate->mbmi.mv[1]);
248 249 250
      }
    }
  }
Paul Wilkins's avatar
Paul Wilkins committed
251

Jim Bankoski's avatar
Jim Bankoski committed
252 253 254 255 256 257
  // Check the last frame's mode and mv info.
  if (lf_here != NULL) {
    if (lf_here->mbmi.ref_frame[0] == ref_frame) {
      ADD_MV_REF_LIST(lf_here->mbmi.mv[0]);
    } else if (lf_here->mbmi.ref_frame[1] == ref_frame) {
      ADD_MV_REF_LIST(lf_here->mbmi.mv[1]);
258
    }
Jim Bankoski's avatar
Jim Bankoski committed
259 260 261 262 263 264 265
  }

  // Since we couldn't find 2 mvs from the same reference frame
  // go back through the neighbors and find motion vectors from
  // different reference frames.
  if (different_ref_found) {
    for (idx = 0; idx < MVREF_NEIGHBOURS; ++idx) {
266
      const MV *mv_ref = &mv_ref_search[idx];
Dmitry Kovalev's avatar
Dmitry Kovalev committed
267
      if (!is_inside(mi_col, mi_row, cm->cur_tile_mi_col_start, mv_ref))
Jim Bankoski's avatar
Jim Bankoski committed
268
        continue;
269

270
      candidate = here + mv_ref->col + mv_ref->row * xd->mode_info_stride;
Jim Bankoski's avatar
Jim Bankoski committed
271 272

      // If the candidate is INTRA we don't want to consider its mv.
Dmitry Kovalev's avatar
Dmitry Kovalev committed
273
      if (!is_inter_block(&candidate->mbmi))
Jim Bankoski's avatar
Jim Bankoski committed
274 275 276
        continue;

      IF_DIFF_REF_FRAME_ADD_MV(candidate);
Paul Wilkins's avatar
Paul Wilkins committed
277 278 279
    }
  }

Jim Bankoski's avatar
Jim Bankoski committed
280
  // Since we still don't have a candidate we'll try the last frame.
Dmitry Kovalev's avatar
Dmitry Kovalev committed
281
  if (lf_here != NULL && is_inter_block(&lf_here->mbmi)) {
Jim Bankoski's avatar
Jim Bankoski committed
282
    IF_DIFF_REF_FRAME_ADD_MV(lf_here);
Paul Wilkins's avatar
Paul Wilkins committed
283 284
  }

Jim Bankoski's avatar
Jim Bankoski committed
285 286 287 288
 Done:

  mbmi->mb_mode_context[ref_frame] = counter_to_context[context_counter];

Paul Wilkins's avatar
Paul Wilkins committed
289
  // Clamp vectors
Dmitry Kovalev's avatar
Dmitry Kovalev committed
290 291
  for (idx = 0; idx < MAX_MV_REF_CANDIDATES; ++idx)
    clamp_mv_ref(&mv_ref_list[idx].as_mv, xd);
Paul Wilkins's avatar
Paul Wilkins committed
292
}
Jim Bankoski's avatar
Jim Bankoski committed
293 294 295

#undef ADD_MV_REF_LIST
#undef IF_DIFF_REF_FRAME_ADD_MV