vp9_mvref_common.c 12.5 KB
Newer Older
1

Paul Wilkins's avatar
Paul Wilkins committed
2
3
4
5
6
7
8
9
10
11
/*
 *  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.
 */

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

#define MVREF_NEIGHBOURS 8
Jim Bankoski's avatar
Jim Bankoski committed
15

16
17
18
19
20
typedef struct position {
  int row;
  int col;
} POSITION;

Jim Bankoski's avatar
Jim Bankoski committed
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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
Dmitry Kovalev's avatar
Dmitry Kovalev committed
45
  9,  // D207_PRED
Jim Bankoski's avatar
Jim Bankoski committed
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
73
74
75
76
77
78
  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
};

79
static const POSITION mv_ref_blocks[BLOCK_SIZES][MVREF_NEIGHBOURS] = {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
80
  // 4X4
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
  // 4X8
83
  {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
84
  // 8X4
85
  {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
86
  // 8X8
87
  {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
88
  // 8X16
89
  {{0, -1}, {-1, 0}, {1, -1}, {-1, -1}, {0, -2}, {-2, 0}, {-2, -1}, {-1, -2}},
90
91
  // 16X8
  {{-1, 0}, {0, -1}, {-1, 1}, {-1, -1}, {-2, 0}, {0, -2}, {-1, -2}, {-2, -1}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
92
  // 16X16
93
  {{-1, 0}, {0, -1}, {-1, 1}, {1, -1}, {-1, -1}, {-3, 0}, {0, -3}, {-3, -3}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
94
  // 16X32
95
  {{0, -1}, {-1, 0}, {2, -1}, {-1, -1}, {-1, 1}, {0, -3}, {-3, 0}, {-3, -3}},
96
97
  // 32X16
  {{-1, 0}, {0, -1}, {-1, 2}, {-1, -1}, {1, -1}, {-3, 0}, {0, -3}, {-3, -3}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
98
  // 32X32
99
  {{-1, 1}, {1, -1}, {-1, 2}, {2, -1}, {-1, -1}, {-3, 0}, {0, -3}, {-3, -3}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
100
  // 32X64
101
  {{0, -1}, {-1, 0}, {4, -1}, {-1, 2}, {-1, -1}, {0, -3}, {-3, 0}, {2, -1}},
102
103
  // 64X32
  {{-1, 0}, {0, -1}, {-1, 4}, {2, -1}, {-1, -1}, {-3, 0}, {0, -3}, {-1, 2}},
Dmitry Kovalev's avatar
Dmitry Kovalev committed
104
  // 64X64
105
  {{-1, 3}, {3, -1}, {-1, 4}, {4, -1}, {-1, -1}, {-1, 0}, {0, -1}, {-1, 6}}
106
};
Jim Bankoski's avatar
Jim Bankoski committed
107
108
109
110
111
112
113
114

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
115
// clamp_mv_ref
Jim Bankoski's avatar
Jim Bankoski committed
116
#define MV_BORDER (16 << 3)  // Allow 16 pels in 1/8th pel units
Paul Wilkins's avatar
Paul Wilkins committed
117

Dmitry Kovalev's avatar
Dmitry Kovalev committed
118
119
120
121
122
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
123
124
}

Jim Bankoski's avatar
Jim Bankoski committed
125
126
// 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.
127
static INLINE int_mv get_sub_block_mv(const MODE_INFO *candidate, int which_mv,
Jim Bankoski's avatar
Jim Bankoski committed
128
                                      int search_col, int block_idx) {
129
  return block_idx >= 0 && candidate->mbmi.sb_type < BLOCK_8X8
Jim Bankoski's avatar
Jim Bankoski committed
130
131
          ? candidate->bmi[idx_n_column_to_subblock[block_idx][search_col == 0]]
              .as_mv[which_mv]
132
          : candidate->mbmi.mv[which_mv];
Paul Wilkins's avatar
Paul Wilkins committed
133
134
}

Paul Wilkins's avatar
Paul Wilkins committed
135
136

// Performs mv sign inversion if indicated by the reference frame combination.
137
static INLINE int_mv scale_mv(const MB_MODE_INFO *mbmi, int ref,
Jim Bankoski's avatar
Jim Bankoski committed
138
139
                              const MV_REFERENCE_FRAME this_ref_frame,
                              const int *ref_sign_bias) {
140
141
142
143
  int_mv mv = mbmi->mv[ref];
  if (ref_sign_bias[mbmi->ref_frame[ref]] != ref_sign_bias[this_ref_frame]) {
    mv.as_mv.row *= -1;
    mv.as_mv.col *= -1;
Paul Wilkins's avatar
Paul Wilkins committed
144
  }
145
  return mv;
Paul Wilkins's avatar
Paul Wilkins committed
146
147
}

Jim Bankoski's avatar
Jim Bankoski committed
148
149
150
151
// 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) \
152
153
154
155
156
157
158
159
  do { \
    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); \
Jim Bankoski's avatar
Jim Bankoski committed
160
    } \
161
  } while (0)
Jim Bankoski's avatar
Jim Bankoski committed
162
163
164
165

// 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) \
166
167
168
169
170
171
172
173
174
  do { \
    if ((CANDIDATE)->ref_frame[0] != ref_frame) \
      ADD_MV_REF_LIST(scale_mv((CANDIDATE), 0, ref_frame, ref_sign_bias)); \
    if ((CANDIDATE)->ref_frame[1] != ref_frame && \
        has_second_ref(CANDIDATE) && \
        (CANDIDATE)->mv[1].as_int != (CANDIDATE)->mv[0].as_int) \
      ADD_MV_REF_LIST(scale_mv((CANDIDATE), 1, ref_frame, ref_sign_bias)); \
  } while (0)

Jim Bankoski's avatar
Jim Bankoski committed
175
176
177

// Checks that the given mi_row, mi_col and search point
// are inside the borders of the tile.
James Zern's avatar
James Zern committed
178
179
static INLINE int is_inside(const TileInfo *const tile,
                            int mi_col, int mi_row, int mi_rows,
180
181
182
183
184
                            const POSITION *mi_pos) {
  return !(mi_row + mi_pos->row < 0 ||
           mi_col + mi_pos->col < tile->mi_col_start ||
           mi_row + mi_pos->row >= mi_rows ||
           mi_col + mi_pos->col >= tile->mi_col_end);
Paul Wilkins's avatar
Paul Wilkins committed
185
}
Paul Wilkins's avatar
Paul Wilkins committed
186

Paul Wilkins's avatar
Paul Wilkins committed
187
188
// This function searches the neighbourhood of a given MB/SB
// to try and find candidate reference vectors.
189
190
static void find_mv_refs_idx(const VP9_COMMON *cm, const MACROBLOCKD *xd,
                             const TileInfo *const tile,
191
                             MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
192
                             int_mv *mv_ref_list,
193
                             int block, int mi_row, int mi_col) {
194
195
  const int *ref_sign_bias = cm->ref_frame_sign_bias;
  int i, refmv_count = 0;
196
197
  const MODE_INFO *prev_mi = cm->coding_use_prev_mi && cm->prev_mi ?
                                 xd->prev_mi_8x8[0] : NULL;
198
  const POSITION *const mv_ref_search = mv_ref_blocks[mi->mbmi.sb_type];
199
200
  const MB_MODE_INFO *const prev_mbmi = cm->coding_use_prev_mi && prev_mi ?
      &prev_mi->mbmi : NULL;
Jim Bankoski's avatar
Jim Bankoski committed
201
202
203
204
205
206
207
208
209
  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.
210
  for (i = 0; i < 2; ++i) {
211
    const POSITION *const mv_ref = &mv_ref_search[i];
James Zern's avatar
James Zern committed
212
    if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
213
214
      const MODE_INFO *const candidate_mi = xd->mi_8x8[mv_ref->col + mv_ref->row
                                                   * xd->mode_info_stride];
215
216
217
      const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
      // Keep counts for entropy encoding.
      context_counter += mode_2_counter[candidate->mode];
218
      different_ref_found = 1;
219

220
221
222
223
      if (candidate->ref_frame[0] == ref_frame)
        ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 0, mv_ref->col, block));
      else if (candidate->ref_frame[1] == ref_frame)
        ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 1, mv_ref->col, block));
Paul Wilkins's avatar
Paul Wilkins committed
224
225
    }
  }
Paul Wilkins's avatar
Paul Wilkins committed
226

Jim Bankoski's avatar
Jim Bankoski committed
227
228
229
  // 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.
230
  for (; i < MVREF_NEIGHBOURS; ++i) {
231
    const POSITION *const mv_ref = &mv_ref_search[i];
James Zern's avatar
James Zern committed
232
    if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
233
234
235
      const MB_MODE_INFO *const candidate = &xd->mi_8x8[mv_ref->col +
                                            mv_ref->row
                                            * xd->mode_info_stride]->mbmi;
236
      different_ref_found = 1;
237

238
      if (candidate->ref_frame[0] == ref_frame)
239
        ADD_MV_REF_LIST(candidate->mv[0]);
240
241
      else if (candidate->ref_frame[1] == ref_frame)
        ADD_MV_REF_LIST(candidate->mv[1]);
242
243
    }
  }
Paul Wilkins's avatar
Paul Wilkins committed
244

Jim Bankoski's avatar
Jim Bankoski committed
245
  // Check the last frame's mode and mv info.
246
247
248
249
250
  if (prev_mbmi) {
    if (prev_mbmi->ref_frame[0] == ref_frame)
      ADD_MV_REF_LIST(prev_mbmi->mv[0]);
    else if (prev_mbmi->ref_frame[1] == ref_frame)
      ADD_MV_REF_LIST(prev_mbmi->mv[1]);
Jim Bankoski's avatar
Jim Bankoski committed
251
252
253
254
255
256
  }

  // 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) {
257
    for (i = 0; i < MVREF_NEIGHBOURS; ++i) {
258
      const POSITION *mv_ref = &mv_ref_search[i];
James Zern's avatar
James Zern committed
259
      if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) {
260
261
262
        const MB_MODE_INFO *const candidate = &xd->mi_8x8[mv_ref->col +
                                                          mv_ref->row
                                              * xd->mode_info_stride]->mbmi;
263
264
265
266
267

        // If the candidate is INTRA we don't want to consider its mv.
        if (is_inter_block(candidate))
          IF_DIFF_REF_FRAME_ADD_MV(candidate);
      }
Paul Wilkins's avatar
Paul Wilkins committed
268
269
270
    }
  }

Jim Bankoski's avatar
Jim Bankoski committed
271
  // Since we still don't have a candidate we'll try the last frame.
272
273
  if (prev_mbmi && is_inter_block(prev_mbmi))
    IF_DIFF_REF_FRAME_ADD_MV(prev_mbmi);
Paul Wilkins's avatar
Paul Wilkins committed
274

Jim Bankoski's avatar
Jim Bankoski committed
275
276
 Done:

277
  mi->mbmi.mode_context[ref_frame] = counter_to_context[context_counter];
Jim Bankoski's avatar
Jim Bankoski committed
278

Paul Wilkins's avatar
Paul Wilkins committed
279
  // Clamp vectors
280
281
  for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i)
    clamp_mv_ref(&mv_ref_list[i].as_mv, xd);
Paul Wilkins's avatar
Paul Wilkins committed
282
}
283

284
285
void vp9_find_mv_refs(const VP9_COMMON *cm, const MACROBLOCKD *xd,
                                    const TileInfo *const tile,
286
                                    MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
287
288
                                    int_mv *mv_ref_list,
                                    int mi_row, int mi_col) {
289
  find_mv_refs_idx(cm, xd, tile, mi, ref_frame, mv_ref_list, -1,
290
291
292
                   mi_row, mi_col);
}

293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
static void lower_mv_precision(MV *mv, int allow_hp) {
  const int use_hp = allow_hp && vp9_use_mv_hp(mv);
  if (!use_hp) {
    if (mv->row & 1)
      mv->row += (mv->row > 0 ? -1 : 1);
    if (mv->col & 1)
      mv->col += (mv->col > 0 ? -1 : 1);
  }
}


void vp9_find_best_ref_mvs(MACROBLOCKD *xd, int allow_hp,
                           int_mv *mvlist, int_mv *nearest, int_mv *near) {
  int i;
  // Make sure all the candidates are properly clamped etc
  for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) {
    lower_mv_precision(&mvlist[i].as_mv, allow_hp);
    clamp_mv2(&mvlist[i].as_mv, xd);
  }
  *nearest = mvlist[0];
  *near = mvlist[1];
}

void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd,
                                   const TileInfo *const tile,
                                   int block, int ref, int mi_row, int mi_col,
                                   int_mv *nearest, int_mv *near) {
  int_mv mv_list[MAX_MV_REF_CANDIDATES];
  MODE_INFO *const mi = xd->mi_8x8[0];
  b_mode_info *bmi = mi->bmi;
  int n;

  assert(MAX_MV_REF_CANDIDATES == 2);

327
328
  find_mv_refs_idx(cm, xd, tile, mi, mi->mbmi.ref_frame[ref], mv_list, block,
                   mi_row, mi_col);
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363

  near->as_int = 0;
  switch (block) {
    case 0:
      nearest->as_int = mv_list[0].as_int;
      near->as_int = mv_list[1].as_int;
      break;
    case 1:
    case 2:
      nearest->as_int = bmi[0].as_mv[ref].as_int;
      for (n = 0; n < MAX_MV_REF_CANDIDATES; ++n)
        if (nearest->as_int != mv_list[n].as_int) {
          near->as_int = mv_list[n].as_int;
          break;
        }
      break;
    case 3: {
      int_mv candidates[2 + MAX_MV_REF_CANDIDATES];
      candidates[0] = bmi[1].as_mv[ref];
      candidates[1] = bmi[0].as_mv[ref];
      candidates[2] = mv_list[0];
      candidates[3] = mv_list[1];

      nearest->as_int = bmi[2].as_mv[ref].as_int;
      for (n = 0; n < 2 + MAX_MV_REF_CANDIDATES; ++n)
        if (nearest->as_int != candidates[n].as_int) {
          near->as_int = candidates[n].as_int;
          break;
        }
      break;
    }
    default:
      assert("Invalid block index.");
  }
}