Line data Source code
1 : /*
2 : * Copyright (c) 2016, 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 : #ifndef AV1_COMMON_MVREF_COMMON_H_
12 : #define AV1_COMMON_MVREF_COMMON_H_
13 :
14 : #include "av1/common/onyxc_int.h"
15 : #include "av1/common/blockd.h"
16 :
17 : #ifdef __cplusplus
18 : extern "C" {
19 : #endif
20 :
21 : #define MVREF_NEIGHBOURS 9
22 :
23 : typedef struct position {
24 : int row;
25 : int col;
26 : } POSITION;
27 :
28 : typedef enum {
29 : BOTH_ZERO = 0,
30 : ZERO_PLUS_PREDICTED = 1,
31 : BOTH_PREDICTED = 2,
32 : NEW_PLUS_NON_INTRA = 3,
33 : BOTH_NEW = 4,
34 : INTRA_PLUS_NON_INTRA = 5,
35 : BOTH_INTRA = 6,
36 : INVALID_CASE = 9
37 : } motion_vector_context;
38 :
39 : // This is used to figure out a context for the ref blocks. The code flattens
40 : // an array that would have 3 possible counts (0, 1 & 2) for 3 choices by
41 : // adding 9 for each intra block, 3 for each zero mv and 1 for each new
42 : // motion vector. This single number is then converted into a context
43 : // with a single lookup ( counter_to_context ).
44 : static const int mode_2_counter[] = {
45 : 9, // DC_PRED
46 : 9, // V_PRED
47 : 9, // H_PRED
48 : 9, // D45_PRED
49 : 9, // D135_PRED
50 : 9, // D117_PRED
51 : 9, // D153_PRED
52 : 9, // D207_PRED
53 : 9, // D63_PRED
54 : #if CONFIG_ALT_INTRA
55 : 9, // SMOOTH_PRED
56 : #if CONFIG_SMOOTH_HV
57 : 9, // SMOOTH_V_PRED
58 : 9, // SMOOTH_H_PRED
59 : #endif // CONFIG_SMOOTH_HV
60 : #endif // CONFIG_ALT_INTRA
61 : 9, // TM_PRED
62 : 0, // NEARESTMV
63 : 0, // NEARMV
64 : 3, // ZEROMV
65 : 1, // NEWMV
66 : #if CONFIG_EXT_INTER
67 : #if CONFIG_COMPOUND_SINGLEREF
68 : 0, // SR_NEAREST_NEARMV
69 : 1, // SR_NEAREST_NEWMV
70 : 1, // SR_NEAR_NEWMV
71 : 3, // SR_ZERO_NEWMV
72 : 1, // SR_NEW_NEWMV
73 : #endif // CONFIG_COMPOUND_SINGLEREF
74 : 0, // NEAREST_NEARESTMV
75 : 0, // NEAR_NEARMV
76 : 1, // NEAREST_NEWMV
77 : 1, // NEW_NEARESTMV
78 : 1, // NEAR_NEWMV
79 : 1, // NEW_NEARMV
80 : 3, // ZERO_ZEROMV
81 : 1, // NEW_NEWMV
82 : #endif // CONFIG_EXT_INTER
83 : };
84 :
85 : // There are 3^3 different combinations of 3 counts that can be either 0,1 or
86 : // 2. However the actual count can never be greater than 2 so the highest
87 : // counter we need is 18. 9 is an invalid counter that's never used.
88 : static const int counter_to_context[19] = {
89 : BOTH_PREDICTED, // 0
90 : NEW_PLUS_NON_INTRA, // 1
91 : BOTH_NEW, // 2
92 : ZERO_PLUS_PREDICTED, // 3
93 : NEW_PLUS_NON_INTRA, // 4
94 : INVALID_CASE, // 5
95 : BOTH_ZERO, // 6
96 : INVALID_CASE, // 7
97 : INVALID_CASE, // 8
98 : INTRA_PLUS_NON_INTRA, // 9
99 : INTRA_PLUS_NON_INTRA, // 10
100 : INVALID_CASE, // 11
101 : INTRA_PLUS_NON_INTRA, // 12
102 : INVALID_CASE, // 13
103 : INVALID_CASE, // 14
104 : INVALID_CASE, // 15
105 : INVALID_CASE, // 16
106 : INVALID_CASE, // 17
107 : BOTH_INTRA // 18
108 : };
109 :
110 : static const int idx_n_column_to_subblock[4][2] = {
111 : { 1, 2 }, { 1, 3 }, { 3, 2 }, { 3, 3 }
112 : };
113 :
114 : // clamp_mv_ref
115 : #if CONFIG_EXT_PARTITION
116 : #define MV_BORDER (16 << 3) // Allow 16 pels in 1/8th pel units
117 : #else
118 : #define MV_BORDER (8 << 3) // Allow 8 pels in 1/8th pel units
119 : #endif // CONFIG_EXT_PARTITION
120 :
121 0 : static INLINE void clamp_mv_ref(MV *mv, int bw, int bh, const MACROBLOCKD *xd) {
122 0 : clamp_mv(mv, xd->mb_to_left_edge - bw * 8 - MV_BORDER,
123 0 : xd->mb_to_right_edge + bw * 8 + MV_BORDER,
124 0 : xd->mb_to_top_edge - bh * 8 - MV_BORDER,
125 0 : xd->mb_to_bottom_edge + bh * 8 + MV_BORDER);
126 0 : }
127 :
128 : // This function returns either the appropriate sub block or block's mv
129 : // on whether the block_size < 8x8 and we have check_sub_blocks set.
130 0 : static INLINE int_mv get_sub_block_mv(const MODE_INFO *candidate, int which_mv,
131 : int search_col, int block_idx) {
132 : (void)search_col;
133 : (void)block_idx;
134 0 : return candidate->mbmi.mv[which_mv];
135 : }
136 :
137 0 : static INLINE int_mv get_sub_block_pred_mv(const MODE_INFO *candidate,
138 : int which_mv, int search_col,
139 : int block_idx) {
140 : (void)search_col;
141 : (void)block_idx;
142 0 : return candidate->mbmi.mv[which_mv];
143 : }
144 :
145 : // Performs mv sign inversion if indicated by the reference frame combination.
146 0 : static INLINE int_mv scale_mv(const MB_MODE_INFO *mbmi, int ref,
147 : const MV_REFERENCE_FRAME this_ref_frame,
148 : const int *ref_sign_bias) {
149 0 : int_mv mv = mbmi->mv[ref];
150 0 : if (ref_sign_bias[mbmi->ref_frame[ref]] != ref_sign_bias[this_ref_frame]) {
151 0 : mv.as_mv.row *= -1;
152 0 : mv.as_mv.col *= -1;
153 : }
154 0 : return mv;
155 : }
156 :
157 : #define CLIP_IN_ADD(mv, bw, bh, xd) clamp_mv_ref(mv, bw, bh, xd)
158 :
159 : // This macro is used to add a motion vector mv_ref list if it isn't
160 : // already in the list. If it's the second motion vector it will also
161 : // skip all additional processing and jump to done!
162 : #define ADD_MV_REF_LIST(mv, refmv_count, mv_ref_list, bw, bh, xd, Done) \
163 : do { \
164 : (mv_ref_list)[(refmv_count)] = (mv); \
165 : CLIP_IN_ADD(&(mv_ref_list)[(refmv_count)].as_mv, (bw), (bh), (xd)); \
166 : if (refmv_count && (mv_ref_list)[1].as_int != (mv_ref_list)[0].as_int) { \
167 : (refmv_count) = 2; \
168 : goto Done; \
169 : } \
170 : (refmv_count) = 1; \
171 : } while (0)
172 :
173 : // If either reference frame is different, not INTRA, and they
174 : // are different from each other scale and add the mv to our list.
175 : #define IF_DIFF_REF_FRAME_ADD_MV(mbmi, ref_frame, ref_sign_bias, refmv_count, \
176 : mv_ref_list, bw, bh, xd, Done) \
177 : do { \
178 : if (is_inter_block(mbmi)) { \
179 : if ((mbmi)->ref_frame[0] != ref_frame) \
180 : ADD_MV_REF_LIST(scale_mv((mbmi), 0, ref_frame, ref_sign_bias), \
181 : refmv_count, mv_ref_list, bw, bh, xd, Done); \
182 : if (has_second_ref(mbmi) && (mbmi)->ref_frame[1] != ref_frame) \
183 : ADD_MV_REF_LIST(scale_mv((mbmi), 1, ref_frame, ref_sign_bias), \
184 : refmv_count, mv_ref_list, bw, bh, xd, Done); \
185 : } \
186 : } while (0)
187 :
188 : // Checks that the given mi_row, mi_col and search point
189 : // are inside the borders of the tile.
190 0 : static INLINE int is_inside(const TileInfo *const tile, int mi_col, int mi_row,
191 : int mi_rows, const AV1_COMMON *cm,
192 : const POSITION *mi_pos) {
193 : #if CONFIG_DEPENDENT_HORZTILES
194 : const int dependent_horz_tile_flag = cm->dependent_horz_tiles;
195 : #else
196 0 : const int dependent_horz_tile_flag = 0;
197 : (void)cm;
198 : #endif
199 : #if CONFIG_TILE_GROUPS
200 0 : if (dependent_horz_tile_flag && !tile->tg_horz_boundary) {
201 : #else
202 : if (dependent_horz_tile_flag) {
203 : #endif
204 0 : return !(mi_row + mi_pos->row < 0 ||
205 0 : mi_col + mi_pos->col < tile->mi_col_start ||
206 0 : mi_row + mi_pos->row >= mi_rows ||
207 0 : mi_col + mi_pos->col >= tile->mi_col_end);
208 : } else {
209 0 : return !(mi_row + mi_pos->row < tile->mi_row_start ||
210 0 : mi_col + mi_pos->col < tile->mi_col_start ||
211 0 : mi_row + mi_pos->row >= tile->mi_row_end ||
212 0 : mi_col + mi_pos->col >= tile->mi_col_end);
213 : }
214 : }
215 :
216 0 : static INLINE void lower_mv_precision(MV *mv, int allow_hp) {
217 0 : if (!allow_hp) {
218 0 : if (mv->row & 1) mv->row += (mv->row > 0 ? -1 : 1);
219 0 : if (mv->col & 1) mv->col += (mv->col > 0 ? -1 : 1);
220 : }
221 0 : }
222 :
223 0 : static INLINE uint8_t av1_get_pred_diff_ctx(const int_mv pred_mv,
224 : const int_mv this_mv) {
225 0 : if (abs(this_mv.as_mv.row - pred_mv.as_mv.row) <= 4 &&
226 0 : abs(this_mv.as_mv.col - pred_mv.as_mv.col) <= 4)
227 0 : return 2;
228 : else
229 0 : return 1;
230 : }
231 :
232 0 : static INLINE int av1_nmv_ctx(const uint8_t ref_mv_count,
233 : const CANDIDATE_MV *ref_mv_stack, int ref,
234 : int ref_mv_idx) {
235 0 : if (ref_mv_stack[ref_mv_idx].weight >= REF_CAT_LEVEL && ref_mv_count > 0)
236 0 : return ref_mv_stack[ref_mv_idx].pred_diff[ref];
237 :
238 0 : return 0;
239 : }
240 :
241 0 : static INLINE int8_t av1_ref_frame_type(const MV_REFERENCE_FRAME *const rf) {
242 0 : if (rf[1] > INTRA_FRAME) {
243 0 : return TOTAL_REFS_PER_FRAME + FWD_RF_OFFSET(rf[0]) +
244 0 : BWD_RF_OFFSET(rf[1]) * FWD_REFS;
245 : }
246 :
247 0 : return rf[0];
248 : }
249 :
250 : // clang-format off
251 : static MV_REFERENCE_FRAME ref_frame_map[COMP_REFS][2] = {
252 : #if CONFIG_EXT_REFS
253 : { LAST_FRAME, BWDREF_FRAME }, { LAST2_FRAME, BWDREF_FRAME },
254 : { LAST3_FRAME, BWDREF_FRAME }, { GOLDEN_FRAME, BWDREF_FRAME },
255 :
256 : { LAST_FRAME, ALTREF_FRAME }, { LAST2_FRAME, ALTREF_FRAME },
257 : { LAST3_FRAME, ALTREF_FRAME }, { GOLDEN_FRAME, ALTREF_FRAME }
258 : #else
259 : { LAST_FRAME, ALTREF_FRAME }, { GOLDEN_FRAME, ALTREF_FRAME }
260 : #endif
261 : };
262 : // clang-format on
263 :
264 0 : static INLINE void av1_set_ref_frame(MV_REFERENCE_FRAME *rf,
265 : int8_t ref_frame_type) {
266 0 : if (ref_frame_type >= TOTAL_REFS_PER_FRAME) {
267 0 : rf[0] = ref_frame_map[ref_frame_type - TOTAL_REFS_PER_FRAME][0];
268 0 : rf[1] = ref_frame_map[ref_frame_type - TOTAL_REFS_PER_FRAME][1];
269 : } else {
270 0 : rf[0] = ref_frame_type;
271 0 : rf[1] = NONE_FRAME;
272 : #if CONFIG_INTRABC
273 : assert(ref_frame_type > NONE_FRAME);
274 : #else
275 0 : assert(ref_frame_type > INTRA_FRAME);
276 : #endif
277 0 : assert(ref_frame_type < TOTAL_REFS_PER_FRAME);
278 : }
279 0 : }
280 :
281 0 : static INLINE int16_t av1_mode_context_analyzer(
282 : const int16_t *const mode_context, const MV_REFERENCE_FRAME *const rf,
283 : BLOCK_SIZE bsize, int block) {
284 0 : int16_t mode_ctx = 0;
285 0 : int8_t ref_frame_type = av1_ref_frame_type(rf);
286 :
287 0 : if (block >= 0) {
288 0 : mode_ctx = mode_context[rf[0]] & 0x00ff;
289 : #if !CONFIG_CB4X4
290 : if (block > 0 && bsize < BLOCK_8X8 && bsize > BLOCK_4X4)
291 : mode_ctx |= (1 << SKIP_NEARESTMV_SUB8X8_OFFSET);
292 : #else
293 : (void)block;
294 : (void)bsize;
295 : #endif
296 :
297 0 : return mode_ctx;
298 : }
299 :
300 0 : return mode_context[ref_frame_type];
301 : }
302 :
303 0 : static INLINE uint8_t av1_drl_ctx(const CANDIDATE_MV *ref_mv_stack,
304 : int ref_idx) {
305 0 : if (ref_mv_stack[ref_idx].weight >= REF_CAT_LEVEL &&
306 0 : ref_mv_stack[ref_idx + 1].weight >= REF_CAT_LEVEL)
307 0 : return 0;
308 :
309 0 : if (ref_mv_stack[ref_idx].weight >= REF_CAT_LEVEL &&
310 0 : ref_mv_stack[ref_idx + 1].weight < REF_CAT_LEVEL)
311 0 : return 2;
312 :
313 0 : if (ref_mv_stack[ref_idx].weight < REF_CAT_LEVEL &&
314 0 : ref_mv_stack[ref_idx + 1].weight < REF_CAT_LEVEL)
315 0 : return 3;
316 :
317 0 : return 0;
318 : }
319 :
320 : typedef void (*find_mv_refs_sync)(void *const data, int mi_row);
321 : void av1_find_mv_refs(const AV1_COMMON *cm, const MACROBLOCKD *xd,
322 : MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
323 : uint8_t *ref_mv_count, CANDIDATE_MV *ref_mv_stack,
324 : #if CONFIG_EXT_INTER
325 : int16_t *compound_mode_context,
326 : #endif // CONFIG_EXT_INTER
327 : int_mv *mv_ref_list, int mi_row, int mi_col,
328 : find_mv_refs_sync sync, void *const data,
329 : int16_t *mode_context);
330 :
331 : // check a list of motion vectors by sad score using a number rows of pixels
332 : // above and a number cols of pixels in the left to select the one with best
333 : // score to use as ref motion vector
334 : void av1_find_best_ref_mvs(int allow_hp, int_mv *mvlist, int_mv *nearest_mv,
335 : int_mv *near_mv);
336 :
337 : void av1_append_sub8x8_mvs_for_idx(const AV1_COMMON *cm, MACROBLOCKD *xd,
338 : int block, int ref, int mi_row, int mi_col,
339 : CANDIDATE_MV *ref_mv_stack,
340 : uint8_t *ref_mv_count,
341 : #if CONFIG_EXT_INTER
342 : int_mv *mv_list,
343 : #endif // CONFIG_EXT_INTER
344 : int_mv *nearest_mv, int_mv *near_mv);
345 :
346 : #if CONFIG_EXT_INTER
347 : // This function keeps a mode count for a given MB/SB
348 : void av1_update_mv_context(const AV1_COMMON *cm, const MACROBLOCKD *xd,
349 : MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
350 : int_mv *mv_ref_list, int block, int mi_row,
351 : int mi_col, int16_t *mode_context);
352 : #endif // CONFIG_EXT_INTER
353 :
354 : #if CONFIG_WARPED_MOTION
355 : int findSamples(const AV1_COMMON *cm, MACROBLOCKD *xd, int mi_row, int mi_col,
356 : int *pts, int *pts_inref);
357 : #endif // CONFIG_WARPED_MOTION
358 :
359 : #if CONFIG_INTRABC
360 : static INLINE void av1_find_ref_dv(int_mv *ref_dv, int mi_row, int mi_col) {
361 : // TODO(aconverse@google.com): Handle tiles and such
362 : (void)mi_col;
363 : if (mi_row < MAX_MIB_SIZE) {
364 : ref_dv->as_mv.row = 0;
365 : ref_dv->as_mv.col = -MI_SIZE * MAX_MIB_SIZE;
366 : } else {
367 : ref_dv->as_mv.row = -MI_SIZE * MAX_MIB_SIZE;
368 : ref_dv->as_mv.col = 0;
369 : }
370 : }
371 :
372 : static INLINE int is_dv_valid(const MV dv, const TileInfo *const tile,
373 : int mi_row, int mi_col, BLOCK_SIZE bsize) {
374 : const int bw = block_size_wide[bsize];
375 : const int bh = block_size_high[bsize];
376 : const int SCALE_PX_TO_MV = 8;
377 : // Disallow subpixel for now
378 : // SUBPEL_MASK is not the correct scale
379 : if ((dv.row & (SCALE_PX_TO_MV - 1) || dv.col & (SCALE_PX_TO_MV - 1)))
380 : return 0;
381 : // Is the source top-left inside the current tile?
382 : const int src_top_edge = mi_row * MI_SIZE * SCALE_PX_TO_MV + dv.row;
383 : const int tile_top_edge = tile->mi_row_start * MI_SIZE * SCALE_PX_TO_MV;
384 : if (src_top_edge < tile_top_edge) return 0;
385 : const int src_left_edge = mi_col * MI_SIZE * SCALE_PX_TO_MV + dv.col;
386 : const int tile_left_edge = tile->mi_col_start * MI_SIZE * SCALE_PX_TO_MV;
387 : if (src_left_edge < tile_left_edge) return 0;
388 : // Is the bottom right inside the current tile?
389 : const int src_bottom_edge = (mi_row * MI_SIZE + bh) * SCALE_PX_TO_MV + dv.row;
390 : const int tile_bottom_edge = tile->mi_row_end * MI_SIZE * SCALE_PX_TO_MV;
391 : if (src_bottom_edge > tile_bottom_edge) return 0;
392 : const int src_right_edge = (mi_col * MI_SIZE + bw) * SCALE_PX_TO_MV + dv.col;
393 : const int tile_right_edge = tile->mi_col_end * MI_SIZE * SCALE_PX_TO_MV;
394 : if (src_right_edge > tile_right_edge) return 0;
395 : // Is the bottom right within an already coded SB?
396 : const int active_sb_top_edge =
397 : (mi_row & ~MAX_MIB_MASK) * MI_SIZE * SCALE_PX_TO_MV;
398 : const int active_sb_bottom_edge =
399 : ((mi_row & ~MAX_MIB_MASK) + MAX_MIB_SIZE) * MI_SIZE * SCALE_PX_TO_MV;
400 : const int active_sb_left_edge =
401 : (mi_col & ~MAX_MIB_MASK) * MI_SIZE * SCALE_PX_TO_MV;
402 : if (src_bottom_edge > active_sb_bottom_edge) return 0;
403 : if (src_bottom_edge > active_sb_top_edge &&
404 : src_right_edge > active_sb_left_edge)
405 : return 0;
406 : return 1;
407 : }
408 : #endif // CONFIG_INTRABC
409 :
410 : #ifdef __cplusplus
411 : } // extern "C"
412 : #endif
413 :
414 : #endif // AV1_COMMON_MVREF_COMMON_H_
|