1 2/* 3 * Copyright (c) 2012 The WebM project authors. All Rights Reserved. 4 * 5 * Use of this source code is governed by a BSD-style license 6 * that can be found in the LICENSE file in the root of the source 7 * tree. An additional intellectual property rights grant can be found 8 * in the file PATENTS. All contributing project authors may 9 * be found in the AUTHORS file in the root of the source tree. 10 */ 11 12#include "vp9/common/vp9_mvref_common.h" 13 14#define MVREF_NEIGHBOURS 8 15 16typedef struct position { 17 int row; 18 int col; 19} POSITION; 20 21typedef enum { 22 BOTH_ZERO = 0, 23 ZERO_PLUS_PREDICTED = 1, 24 BOTH_PREDICTED = 2, 25 NEW_PLUS_NON_INTRA = 3, 26 BOTH_NEW = 4, 27 INTRA_PLUS_NON_INTRA = 5, 28 BOTH_INTRA = 6, 29 INVALID_CASE = 9 30} motion_vector_context; 31 32// This is used to figure out a context for the ref blocks. The code flattens 33// an array that would have 3 possible counts (0, 1 & 2) for 3 choices by 34// adding 9 for each intra block, 3 for each zero mv and 1 for each new 35// motion vector. This single number is then converted into a context 36// with a single lookup ( counter_to_context ). 37static const int mode_2_counter[MB_MODE_COUNT] = { 38 9, // DC_PRED 39 9, // V_PRED 40 9, // H_PRED 41 9, // D45_PRED 42 9, // D135_PRED 43 9, // D117_PRED 44 9, // D153_PRED 45 9, // D207_PRED 46 9, // D63_PRED 47 9, // TM_PRED 48 0, // NEARESTMV 49 0, // NEARMV 50 3, // ZEROMV 51 1, // NEWMV 52}; 53 54// There are 3^3 different combinations of 3 counts that can be either 0,1 or 55// 2. However the actual count can never be greater than 2 so the highest 56// counter we need is 18. 9 is an invalid counter that's never used. 57static const int counter_to_context[19] = { 58 BOTH_PREDICTED, // 0 59 NEW_PLUS_NON_INTRA, // 1 60 BOTH_NEW, // 2 61 ZERO_PLUS_PREDICTED, // 3 62 NEW_PLUS_NON_INTRA, // 4 63 INVALID_CASE, // 5 64 BOTH_ZERO, // 6 65 INVALID_CASE, // 7 66 INVALID_CASE, // 8 67 INTRA_PLUS_NON_INTRA, // 9 68 INTRA_PLUS_NON_INTRA, // 10 69 INVALID_CASE, // 11 70 INTRA_PLUS_NON_INTRA, // 12 71 INVALID_CASE, // 13 72 INVALID_CASE, // 14 73 INVALID_CASE, // 15 74 INVALID_CASE, // 16 75 INVALID_CASE, // 17 76 BOTH_INTRA // 18 77}; 78 79static const POSITION mv_ref_blocks[BLOCK_SIZES][MVREF_NEIGHBOURS] = { 80 // 4X4 81 {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}}, 82 // 4X8 83 {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}}, 84 // 8X4 85 {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}}, 86 // 8X8 87 {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}}, 88 // 8X16 89 {{0, -1}, {-1, 0}, {1, -1}, {-1, -1}, {0, -2}, {-2, 0}, {-2, -1}, {-1, -2}}, 90 // 16X8 91 {{-1, 0}, {0, -1}, {-1, 1}, {-1, -1}, {-2, 0}, {0, -2}, {-1, -2}, {-2, -1}}, 92 // 16X16 93 {{-1, 0}, {0, -1}, {-1, 1}, {1, -1}, {-1, -1}, {-3, 0}, {0, -3}, {-3, -3}}, 94 // 16X32 95 {{0, -1}, {-1, 0}, {2, -1}, {-1, -1}, {-1, 1}, {0, -3}, {-3, 0}, {-3, -3}}, 96 // 32X16 97 {{-1, 0}, {0, -1}, {-1, 2}, {-1, -1}, {1, -1}, {-3, 0}, {0, -3}, {-3, -3}}, 98 // 32X32 99 {{-1, 1}, {1, -1}, {-1, 2}, {2, -1}, {-1, -1}, {-3, 0}, {0, -3}, {-3, -3}}, 100 // 32X64 101 {{0, -1}, {-1, 0}, {4, -1}, {-1, 2}, {-1, -1}, {0, -3}, {-3, 0}, {2, -1}}, 102 // 64X32 103 {{-1, 0}, {0, -1}, {-1, 4}, {2, -1}, {-1, -1}, {-3, 0}, {0, -3}, {-1, 2}}, 104 // 64X64 105 {{-1, 3}, {3, -1}, {-1, 4}, {4, -1}, {-1, -1}, {-1, 0}, {0, -1}, {-1, 6}} 106}; 107 108static const int idx_n_column_to_subblock[4][2] = { 109 {1, 2}, 110 {1, 3}, 111 {3, 2}, 112 {3, 3} 113}; 114 115// clamp_mv_ref 116#define MV_BORDER (16 << 3) // Allow 16 pels in 1/8th pel units 117 118static void clamp_mv_ref(MV *mv, const MACROBLOCKD *xd) { 119 clamp_mv(mv, xd->mb_to_left_edge - MV_BORDER, 120 xd->mb_to_right_edge + MV_BORDER, 121 xd->mb_to_top_edge - MV_BORDER, 122 xd->mb_to_bottom_edge + MV_BORDER); 123} 124 125// This function returns either the appropriate sub block or block's mv 126// on whether the block_size < 8x8 and we have check_sub_blocks set. 127static INLINE int_mv get_sub_block_mv(const MODE_INFO *candidate, int which_mv, 128 int search_col, int block_idx) { 129 return block_idx >= 0 && candidate->mbmi.sb_type < BLOCK_8X8 130 ? candidate->bmi[idx_n_column_to_subblock[block_idx][search_col == 0]] 131 .as_mv[which_mv] 132 : candidate->mbmi.mv[which_mv]; 133} 134 135 136// Performs mv sign inversion if indicated by the reference frame combination. 137static INLINE int_mv scale_mv(const MB_MODE_INFO *mbmi, int ref, 138 const MV_REFERENCE_FRAME this_ref_frame, 139 const int *ref_sign_bias) { 140 int_mv mv = mbmi->mv[ref]; 141 if (ref_sign_bias[mbmi->ref_frame[ref]] != ref_sign_bias[this_ref_frame]) { 142 mv.as_mv.row *= -1; 143 mv.as_mv.col *= -1; 144 } 145 return mv; 146} 147 148// This macro is used to add a motion vector mv_ref list if it isn't 149// already in the list. If it's the second motion vector it will also 150// skip all additional processing and jump to done! 151#define ADD_MV_REF_LIST(mv) \ 152 do { \ 153 if (refmv_count) { \ 154 if ((mv).as_int != mv_ref_list[0].as_int) { \ 155 mv_ref_list[refmv_count] = (mv); \ 156 goto Done; \ 157 } \ 158 } else { \ 159 mv_ref_list[refmv_count++] = (mv); \ 160 } \ 161 } while (0) 162 163// If either reference frame is different, not INTRA, and they 164// are different from each other scale and add the mv to our list. 165#define IF_DIFF_REF_FRAME_ADD_MV(mbmi) \ 166 do { \ 167 if (is_inter_block(mbmi)) { \ 168 if ((mbmi)->ref_frame[0] != ref_frame) \ 169 ADD_MV_REF_LIST(scale_mv((mbmi), 0, ref_frame, ref_sign_bias)); \ 170 if (has_second_ref(mbmi) && \ 171 (mbmi)->ref_frame[1] != ref_frame && \ 172 (mbmi)->mv[1].as_int != (mbmi)->mv[0].as_int) \ 173 ADD_MV_REF_LIST(scale_mv((mbmi), 1, ref_frame, ref_sign_bias)); \ 174 } \ 175 } while (0) 176 177 178// Checks that the given mi_row, mi_col and search point 179// are inside the borders of the tile. 180static INLINE int is_inside(const TileInfo *const tile, 181 int mi_col, int mi_row, int mi_rows, 182 const POSITION *mi_pos) { 183 return !(mi_row + mi_pos->row < 0 || 184 mi_col + mi_pos->col < tile->mi_col_start || 185 mi_row + mi_pos->row >= mi_rows || 186 mi_col + mi_pos->col >= tile->mi_col_end); 187} 188 189// This function searches the neighbourhood of a given MB/SB 190// to try and find candidate reference vectors. 191static void find_mv_refs_idx(const VP9_COMMON *cm, const MACROBLOCKD *xd, 192 const TileInfo *const tile, 193 MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame, 194 int_mv *mv_ref_list, 195 int block, int mi_row, int mi_col) { 196 const int *ref_sign_bias = cm->ref_frame_sign_bias; 197 int i, refmv_count = 0; 198 const MODE_INFO *prev_mi = cm->prev_mi 199 ? cm->prev_mi_grid_visible[mi_row * xd->mi_stride + mi_col] 200 : NULL; 201 const MB_MODE_INFO *const prev_mbmi = prev_mi ? &prev_mi->mbmi : NULL; 202 203 204 const POSITION *const mv_ref_search = mv_ref_blocks[mi->mbmi.sb_type]; 205 206 int different_ref_found = 0; 207 int context_counter = 0; 208 209 // Blank the reference vector list 210 vpx_memset(mv_ref_list, 0, sizeof(*mv_ref_list) * MAX_MV_REF_CANDIDATES); 211 212 // The nearest 2 blocks are treated differently 213 // if the size < 8x8 we get the mv from the bmi substructure, 214 // and we also need to keep a mode count. 215 for (i = 0; i < 2; ++i) { 216 const POSITION *const mv_ref = &mv_ref_search[i]; 217 if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) { 218 const MODE_INFO *const candidate_mi = xd->mi[mv_ref->col + mv_ref->row * 219 xd->mi_stride]; 220 const MB_MODE_INFO *const candidate = &candidate_mi->mbmi; 221 // Keep counts for entropy encoding. 222 context_counter += mode_2_counter[candidate->mode]; 223 different_ref_found = 1; 224 225 if (candidate->ref_frame[0] == ref_frame) 226 ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 0, mv_ref->col, block)); 227 else if (candidate->ref_frame[1] == ref_frame) 228 ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 1, mv_ref->col, block)); 229 } 230 } 231 232 // Check the rest of the neighbors in much the same way 233 // as before except we don't need to keep track of sub blocks or 234 // mode counts. 235 for (; i < MVREF_NEIGHBOURS; ++i) { 236 const POSITION *const mv_ref = &mv_ref_search[i]; 237 if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) { 238 const MB_MODE_INFO *const candidate = &xd->mi[mv_ref->col + mv_ref->row * 239 xd->mi_stride]->mbmi; 240 different_ref_found = 1; 241 242 if (candidate->ref_frame[0] == ref_frame) 243 ADD_MV_REF_LIST(candidate->mv[0]); 244 else if (candidate->ref_frame[1] == ref_frame) 245 ADD_MV_REF_LIST(candidate->mv[1]); 246 } 247 } 248 249 // Check the last frame's mode and mv info. 250 if (prev_mbmi) { 251 if (prev_mbmi->ref_frame[0] == ref_frame) 252 ADD_MV_REF_LIST(prev_mbmi->mv[0]); 253 else if (prev_mbmi->ref_frame[1] == ref_frame) 254 ADD_MV_REF_LIST(prev_mbmi->mv[1]); 255 } 256 257 // Since we couldn't find 2 mvs from the same reference frame 258 // go back through the neighbors and find motion vectors from 259 // different reference frames. 260 if (different_ref_found) { 261 for (i = 0; i < MVREF_NEIGHBOURS; ++i) { 262 const POSITION *mv_ref = &mv_ref_search[i]; 263 if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) { 264 const MB_MODE_INFO *const candidate = &xd->mi[mv_ref->col + mv_ref->row 265 * xd->mi_stride]->mbmi; 266 267 // If the candidate is INTRA we don't want to consider its mv. 268 IF_DIFF_REF_FRAME_ADD_MV(candidate); 269 } 270 } 271 } 272 273 // Since we still don't have a candidate we'll try the last frame. 274 if (prev_mbmi) 275 IF_DIFF_REF_FRAME_ADD_MV(prev_mbmi); 276 277 Done: 278 279 mi->mbmi.mode_context[ref_frame] = counter_to_context[context_counter]; 280 281 // Clamp vectors 282 for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) 283 clamp_mv_ref(&mv_ref_list[i].as_mv, xd); 284} 285 286void vp9_find_mv_refs(const VP9_COMMON *cm, const MACROBLOCKD *xd, 287 const TileInfo *const tile, 288 MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame, 289 int_mv *mv_ref_list, 290 int mi_row, int mi_col) { 291 find_mv_refs_idx(cm, xd, tile, mi, ref_frame, mv_ref_list, -1, 292 mi_row, mi_col); 293} 294 295static void lower_mv_precision(MV *mv, int allow_hp) { 296 const int use_hp = allow_hp && vp9_use_mv_hp(mv); 297 if (!use_hp) { 298 if (mv->row & 1) 299 mv->row += (mv->row > 0 ? -1 : 1); 300 if (mv->col & 1) 301 mv->col += (mv->col > 0 ? -1 : 1); 302 } 303} 304 305 306void vp9_find_best_ref_mvs(MACROBLOCKD *xd, int allow_hp, 307 int_mv *mvlist, int_mv *nearest, int_mv *near) { 308 int i; 309 // Make sure all the candidates are properly clamped etc 310 for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) { 311 lower_mv_precision(&mvlist[i].as_mv, allow_hp); 312 clamp_mv2(&mvlist[i].as_mv, xd); 313 } 314 *nearest = mvlist[0]; 315 *near = mvlist[1]; 316} 317 318void vp9_append_sub8x8_mvs_for_idx(VP9_COMMON *cm, MACROBLOCKD *xd, 319 const TileInfo *const tile, 320 int block, int ref, int mi_row, int mi_col, 321 int_mv *nearest, int_mv *near) { 322 int_mv mv_list[MAX_MV_REF_CANDIDATES]; 323 MODE_INFO *const mi = xd->mi[0]; 324 b_mode_info *bmi = mi->bmi; 325 int n; 326 327 assert(MAX_MV_REF_CANDIDATES == 2); 328 329 find_mv_refs_idx(cm, xd, tile, mi, mi->mbmi.ref_frame[ref], mv_list, block, 330 mi_row, mi_col); 331 332 near->as_int = 0; 333 switch (block) { 334 case 0: 335 nearest->as_int = mv_list[0].as_int; 336 near->as_int = mv_list[1].as_int; 337 break; 338 case 1: 339 case 2: 340 nearest->as_int = bmi[0].as_mv[ref].as_int; 341 for (n = 0; n < MAX_MV_REF_CANDIDATES; ++n) 342 if (nearest->as_int != mv_list[n].as_int) { 343 near->as_int = mv_list[n].as_int; 344 break; 345 } 346 break; 347 case 3: { 348 int_mv candidates[2 + MAX_MV_REF_CANDIDATES]; 349 candidates[0] = bmi[1].as_mv[ref]; 350 candidates[1] = bmi[0].as_mv[ref]; 351 candidates[2] = mv_list[0]; 352 candidates[3] = mv_list[1]; 353 354 nearest->as_int = bmi[2].as_mv[ref].as_int; 355 for (n = 0; n < 2 + MAX_MV_REF_CANDIDATES; ++n) 356 if (nearest->as_int != candidates[n].as_int) { 357 near->as_int = candidates[n].as_int; 358 break; 359 } 360 break; 361 } 362 default: 363 assert("Invalid block index."); 364 } 365} 366