From f703f98757f6a767749b92dc327ac87c69df1605 Mon Sep 17 00:00:00 2001 From: Jim Bankoski Date: Sat, 3 Aug 2013 19:51:56 -0700 Subject: [PATCH] reworked find_mv_ref This is an attempt at rewriting vp9_find_mv_refs_idx. I believe that it gains about 1-2% decode speed Change-Id: Ia5359c94ce9bb43b32652890e605e9a385485c1b --- vp9/common/vp9_mvref_common.c | 433 +++++++++++++++++----------------- vp9/common/vp9_mvref_common.h | 11 +- 2 files changed, 228 insertions(+), 216 deletions(-) diff --git a/vp9/common/vp9_mvref_common.c b/vp9/common/vp9_mvref_common.c index 64baac613..3b72f41c2 100644 --- a/vp9/common/vp9_mvref_common.c +++ b/vp9/common/vp9_mvref_common.c @@ -11,6 +11,65 @@ #include "vp9/common/vp9_mvref_common.h" #define MVREF_NEIGHBOURS 8 + +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 +}; + static const int mv_ref_blocks[BLOCK_SIZE_TYPES][MVREF_NEIGHBOURS][2] = { // SB4X4 {{0, -1}, {-1, 0}, {-1, -1}, {0, -2}, {-2, 0}, {-1, -2}, {-2, -1}, {-2, -2}}, @@ -39,6 +98,14 @@ static const int mv_ref_blocks[BLOCK_SIZE_TYPES][MVREF_NEIGHBOURS][2] = { // SB64X64 {{3, -1}, {-1, 3}, {4, -1}, {-1, 4}, {-1, -1}, {0, -1}, {-1, 0}, {6, -1}} }; + +static const int idx_n_column_to_subblock[4][2] = { + {1, 2}, + {1, 3}, + {3, 2}, + {3, 3} +}; + // clamp_mv_ref #define MV_BORDER (16 << 3) // Allow 16 pels in 1/8th pel units @@ -49,250 +116,194 @@ static void clamp_mv_ref(const MACROBLOCKD *xd, int_mv *mv) { xd->mb_to_bottom_edge + MV_BORDER); } -// Gets a candidate reference motion vector from the given mode info -// structure if one exists that matches the given reference frame. -static int get_matching_candidate(const MODE_INFO *candidate_mi, - MV_REFERENCE_FRAME ref_frame, - int_mv *c_mv, int block_idx) { - if (ref_frame == candidate_mi->mbmi.ref_frame[0]) { - if (block_idx >= 0 && candidate_mi->mbmi.sb_type < BLOCK_SIZE_SB8X8) - c_mv->as_int = candidate_mi->bmi[block_idx].as_mv[0].as_int; - else - c_mv->as_int = candidate_mi->mbmi.mv[0].as_int; - } else if (ref_frame == candidate_mi->mbmi.ref_frame[1]) { - if (block_idx >= 0 && candidate_mi->mbmi.sb_type < BLOCK_SIZE_SB8X8) - c_mv->as_int = candidate_mi->bmi[block_idx].as_mv[1].as_int; - else - c_mv->as_int = candidate_mi->mbmi.mv[1].as_int; - } else { - return 0; - } - - return 1; -} - -// Gets candidate reference motion vector(s) from the given mode info -// structure if they exists and do NOT match the given reference frame. -static void get_non_matching_candidates(const MODE_INFO *candidate_mi, - MV_REFERENCE_FRAME ref_frame, - MV_REFERENCE_FRAME *c_ref_frame, - int_mv *c_mv, - MV_REFERENCE_FRAME *c2_ref_frame, - int_mv *c2_mv) { - - c_mv->as_int = 0; - c2_mv->as_int = 0; - *c_ref_frame = INTRA_FRAME; - *c2_ref_frame = INTRA_FRAME; - - // If first candidate not valid neither will be. - if (candidate_mi->mbmi.ref_frame[0] > INTRA_FRAME) { - // First candidate - if (candidate_mi->mbmi.ref_frame[0] != ref_frame) { - *c_ref_frame = candidate_mi->mbmi.ref_frame[0]; - c_mv->as_int = candidate_mi->mbmi.mv[0].as_int; - } - - // Second candidate - if ((candidate_mi->mbmi.ref_frame[1] > INTRA_FRAME) && - (candidate_mi->mbmi.ref_frame[1] != ref_frame) && - (candidate_mi->mbmi.mv[1].as_int != candidate_mi->mbmi.mv[0].as_int)) { - *c2_ref_frame = candidate_mi->mbmi.ref_frame[1]; - c2_mv->as_int = candidate_mi->mbmi.mv[1].as_int; - } - } +// 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) { + return (check_sub_blocks && candidate->mbmi.sb_type < BLOCK_SIZE_SB8X8 + ? candidate->bmi[idx_n_column_to_subblock[block_idx][search_col == 0]] + .as_mv[which_mv] + : candidate->mbmi.mv[which_mv]); } // Performs mv sign inversion if indicated by the reference frame combination. -static void scale_mv(MV_REFERENCE_FRAME this_ref_frame, - MV_REFERENCE_FRAME candidate_ref_frame, - int_mv *candidate_mv, int *ref_sign_bias) { +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]; // 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; + 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; } + return return_mv; } -// Add a candidate mv. -// Discard if it has already been seen. -static void add_candidate_mv(int_mv *mv_list, int *mv_scores, - int *candidate_count, int_mv candidate_mv, - int weight) { - if (*candidate_count == 0) { - mv_list[0].as_int = candidate_mv.as_int; - mv_scores[0] = weight; - *candidate_count += 1; - } else if ((*candidate_count == 1) && - (candidate_mv.as_int != mv_list[0].as_int)) { - mv_list[1].as_int = candidate_mv.as_int; - mv_scores[1] = weight; - *candidate_count += 1; +// 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); \ } + +// 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. +static INLINE int is_inside(const int mi_col, const int mi_row, + const int cur_tile_mi_col_start, + const int cur_tile_mi_col_end, const int mi_rows, + const int (*mv_ref_search)[2], int idx) { + int mi_search_col; + const int mi_search_row = mi_row + mv_ref_search[idx][1];; + + // 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. + if (mi_search_row < 0) + return 0; + + mi_search_col = mi_col + mv_ref_search[idx][0]; + if (mi_search_col < cur_tile_mi_col_start) + return 0; + + return 1; } // This function searches the neighbourhood of a given MB/SB // to try and find candidate reference vectors. -// void vp9_find_mv_refs_idx(VP9_COMMON *cm, MACROBLOCKD *xd, MODE_INFO *here, - MODE_INFO *lf_here, MV_REFERENCE_FRAME ref_frame, - int_mv *mv_ref_list, int *ref_sign_bias, - int block_idx, int mi_row, int mi_col) { - int i; - MODE_INFO *candidate_mi; - MB_MODE_INFO *mbmi = &here->mbmi; - int_mv c_refmv; - int_mv c2_refmv; - MV_REFERENCE_FRAME c_ref_frame; - MV_REFERENCE_FRAME c2_ref_frame; - int candidate_scores[MAX_MV_REF_CANDIDATES] = { 0 }; + 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; int refmv_count = 0; const int (*mv_ref_search)[2] = mv_ref_blocks[mbmi->sb_type]; - const int mi_stride = cm->mode_info_stride; - int intra_count = 0; - int zero_count = 0; - int newmv_count = 0; - int x_idx = 0, y_idx = 0; - - // Blank the reference vector lists and other local structures. - vpx_memset(mv_ref_list, 0, sizeof(int_mv) * MAX_MV_REF_CANDIDATES); - - if (mbmi->sb_type < BLOCK_SIZE_SB8X8) { - x_idx = block_idx & 1; - y_idx = block_idx >> 1; - } - - // We first scan for candidate vectors that match the current reference frame - // Look at nearest neigbours - for (i = 0; i < 2; ++i) { - const int mi_search_col = mi_col + mv_ref_search[i][0]; - const int mi_search_row = mi_row + mv_ref_search[i][1]; - if ((mi_search_col >= cm->cur_tile_mi_col_start) && - (mi_search_col < cm->cur_tile_mi_col_end) && - (mi_search_row >= 0) && (mi_search_row < cm->mi_rows)) { - int b; - - candidate_mi = here + mv_ref_search[i][0] + - mi_stride * mv_ref_search[i][1]; - - if (block_idx >= 0) { - if (mv_ref_search[i][0]) - b = 1 + y_idx * 2; - else - b = 2 + x_idx; - } else { - b = -1; + 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) { + if (!is_inside(mi_col, mi_row, cm->cur_tile_mi_col_start, + cm->cur_tile_mi_col_end, cm->mi_rows, mv_ref_search, idx)) + continue; + + candidate = here + mv_ref_search[idx][0] + + mv_ref_search[idx][1] * xd->mode_info_stride; + + // 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, + mv_ref_search[idx][0], block_idx)); + 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, + mv_ref_search[idx][0], block_idx)); } - if (get_matching_candidate(candidate_mi, ref_frame, &c_refmv, b)) - add_candidate_mv(mv_ref_list, candidate_scores, &refmv_count, c_refmv, - 16); - - // Count number of neihgbours coded intra and zeromv - intra_count += is_intra_mode(candidate_mi->mbmi.mode); - zero_count += (candidate_mi->mbmi.mode == ZEROMV); - newmv_count += (candidate_mi->mbmi.mode >= NEWMV); } } - // More distant neigbours - for (i = 2; (i < MVREF_NEIGHBOURS) && - (refmv_count < MAX_MV_REF_CANDIDATES); ++i) { - const int mi_search_col = mi_col + mv_ref_search[i][0]; - const int mi_search_row = mi_row + mv_ref_search[i][1]; - if (mi_search_col >= cm->cur_tile_mi_col_start && - mi_search_col < cm->cur_tile_mi_col_end && - mi_search_row >= 0 && - mi_search_row < cm->mi_rows) { - candidate_mi = here + mv_ref_search[i][0] + - mi_stride * mv_ref_search[i][1]; - - if (get_matching_candidate(candidate_mi, ref_frame, &c_refmv, -1)) - add_candidate_mv(mv_ref_list, candidate_scores, &refmv_count, c_refmv, - 16); - } - } + // 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) { + if (!is_inside(mi_col, mi_row, cm->cur_tile_mi_col_start, + cm->cur_tile_mi_col_end, cm->mi_rows, mv_ref_search, idx)) + continue; - // Look in the last frame if it exists - if (lf_here && (refmv_count < MAX_MV_REF_CANDIDATES)) { - candidate_mi = lf_here; - if (get_matching_candidate(candidate_mi, ref_frame, &c_refmv, -1)) - add_candidate_mv(mv_ref_list, candidate_scores, &refmv_count, c_refmv, - 16); - } - - // If we have not found enough candidates consider ones where the - // reference frame does not match. Break out when we have - // MAX_MV_REF_CANDIDATES candidates. - // Look first at spatial neighbours - for (i = 0; (i < MVREF_NEIGHBOURS) && - (refmv_count < MAX_MV_REF_CANDIDATES); ++i) { - const int mi_search_col = mi_col + mv_ref_search[i][0]; - const int mi_search_row = mi_row + mv_ref_search[i][1]; - if (mi_search_col >= cm->cur_tile_mi_col_start && - mi_search_col < cm->cur_tile_mi_col_end && - mi_search_row >= 0 && - mi_search_row < cm->mi_rows) { - candidate_mi = here + mv_ref_search[i][0] + - mi_stride * mv_ref_search[i][1]; - - get_non_matching_candidates(candidate_mi, ref_frame, - &c_ref_frame, &c_refmv, - &c2_ref_frame, &c2_refmv); - - if (c_ref_frame != INTRA_FRAME) { - scale_mv(ref_frame, c_ref_frame, &c_refmv, ref_sign_bias); - add_candidate_mv(mv_ref_list, candidate_scores, - &refmv_count, c_refmv, 1); - } + candidate = here + mv_ref_search[idx][0] + + mv_ref_search[idx][1] * xd->mode_info_stride; - if (c2_ref_frame != INTRA_FRAME) { - scale_mv(ref_frame, c2_ref_frame, &c2_refmv, ref_sign_bias); - add_candidate_mv(mv_ref_list, candidate_scores, - &refmv_count, c2_refmv, 1); + 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]); } } } - // Look at the last frame if it exists - if (lf_here && (refmv_count < MAX_MV_REF_CANDIDATES)) { - candidate_mi = lf_here; - get_non_matching_candidates(candidate_mi, ref_frame, - &c_ref_frame, &c_refmv, - &c2_ref_frame, &c2_refmv); - - if (c_ref_frame != INTRA_FRAME) { - scale_mv(ref_frame, c_ref_frame, &c_refmv, ref_sign_bias); - add_candidate_mv(mv_ref_list, candidate_scores, - &refmv_count, c_refmv, 1); + // 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]); } + } + + // 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) { + if (!is_inside(mi_col, mi_row, cm->cur_tile_mi_col_start, + cm->cur_tile_mi_col_end, cm->mi_rows, mv_ref_search, idx)) + continue; - if (c2_ref_frame != INTRA_FRAME) { - scale_mv(ref_frame, c2_ref_frame, &c2_refmv, ref_sign_bias); - add_candidate_mv(mv_ref_list, candidate_scores, - &refmv_count, c2_refmv, 1); + candidate = here + mv_ref_search[idx][0] + + mv_ref_search[idx][1] * xd->mode_info_stride; + + // If the candidate is INTRA we don't want to consider its mv. + if (candidate->mbmi.ref_frame[0] == INTRA_FRAME) + continue; + + IF_DIFF_REF_FRAME_ADD_MV(candidate); } } - if (!intra_count) { - if (!newmv_count) { - // 0 = both zero mv - // 1 = one zero mv + one a predicted mv - // 2 = two predicted mvs - mbmi->mb_mode_context[ref_frame] = 2 - zero_count; - } else { - // 3 = one predicted/zero and one new mv - // 4 = two new mvs - mbmi->mb_mode_context[ref_frame] = 2 + newmv_count; - } - } else { - // 5 = one intra neighbour + x - // 6 = two intra neighbours - mbmi->mb_mode_context[ref_frame] = 4 + intra_count; + // Since we still don't have a candidate we'll try the last frame. + if (lf_here != NULL && lf_here->mbmi.ref_frame[0] != INTRA_FRAME) { + IF_DIFF_REF_FRAME_ADD_MV(lf_here); } + Done: + + mbmi->mb_mode_context[ref_frame] = counter_to_context[context_counter]; + // Clamp vectors - for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) - clamp_mv_ref(xd, &mv_ref_list[i]); + for (idx = 0; idx < MAX_MV_REF_CANDIDATES; ++idx) { + clamp_mv_ref(xd, &mv_ref_list[idx]); + } } + +#undef ADD_MV_REF_LIST +#undef IF_DIFF_REF_FRAME_ADD_MV diff --git a/vp9/common/vp9_mvref_common.h b/vp9/common/vp9_mvref_common.h index c32a8bf2c..c5f89eb57 100644 --- a/vp9/common/vp9_mvref_common.h +++ b/vp9/common/vp9_mvref_common.h @@ -17,12 +17,13 @@ void vp9_find_mv_refs_idx(VP9_COMMON *cm, MACROBLOCKD *xd, MODE_INFO *here, - MODE_INFO *lf_here, - MV_REFERENCE_FRAME ref_frame, + const MODE_INFO *lf_here, + const MV_REFERENCE_FRAME ref_frame, int_mv *mv_ref_list, - int *ref_sign_bias, - int block_idx, - int mi_row, int mi_col); + const int *ref_sign_bias, + const int block_idx, + const int mi_row, + const int mi_col); static INLINE void vp9_find_mv_refs(VP9_COMMON *cm, MACROBLOCKD *xd, -- 2.40.0