From: Paul Wilkins Date: Thu, 24 Jan 2013 12:52:13 +0000 (+0000) Subject: Mvref speedup X-Git-Tag: v1.3.0~1151^2~234 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fcb4a25cd54396bb9ec646515820b47f79b22d75;p=libvpx Mvref speedup Quality / decode speed trade off changes. Simpler insert method without sort. Quality impact small. Change-Id: Id0c0941bc508d985405abd06a13ffe7489170b62 --- diff --git a/vp9/common/vp9_mvref_common.c b/vp9/common/vp9_mvref_common.c index 8d4980f08..f22d9bec1 100644 --- a/vp9/common/vp9_mvref_common.c +++ b/vp9/common/vp9_mvref_common.c @@ -24,9 +24,9 @@ static int sb_mv_ref_search[MVREF_NEIGHBOURS][2] = { static int sb_ref_distance_weight[MVREF_NEIGHBOURS] = { 3, 3, 2, 2, 2, 1, 1, 1 }; -// clamp_mv +// clamp_mv_ref #define MV_BORDER (16 << 3) // Allow 16 pels in 1/8th pel units -static void clamp_mv(const MACROBLOCKD *xd, int_mv *mv) { +static void clamp_mv_ref(const MACROBLOCKD *xd, int_mv *mv) { if (mv->as_mv.col < (xd->mb_to_left_edge - MV_BORDER)) mv->as_mv.col = xd->mb_to_left_edge - MV_BORDER; @@ -85,18 +85,17 @@ static void get_non_matching_candidates( // Second candidate if ((candidate_mi->mbmi.second_ref_frame > INTRA_FRAME) && - (candidate_mi->mbmi.second_ref_frame != ref_frame)) { // && - // (candidate_mi->mbmi.mv[1].as_int != 0) && - // (candidate_mi->mbmi.mv[1].as_int != - // candidate_mi->mbmi.mv[0].as_int)) { + (candidate_mi->mbmi.second_ref_frame != ref_frame) && + (candidate_mi->mbmi.mv[1].as_int != + candidate_mi->mbmi.mv[0].as_int)) { *c2_ref_frame = candidate_mi->mbmi.second_ref_frame; c2_mv->as_int = candidate_mi->mbmi.mv[1].as_int; } } } -// Performs mv adjustment based on reference frame and clamps the MV -// if it goes off the edge of the buffer. + +// Performs mv sign inversion if indicated by the reference frame combination. static void scale_mv( MACROBLOCKD *xd, MV_REFERENCE_FRAME this_ref_frame, @@ -104,54 +103,55 @@ static void scale_mv( int_mv *candidate_mv, int *ref_sign_bias ) { - - if (candidate_ref_frame != this_ref_frame) { - - //int frame_distances[MAX_REF_FRAMES]; - //int last_distance = 1; - //int gf_distance = xd->frames_since_golden; - //int arf_distance = xd->frames_till_alt_ref_frame; - - // 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; - } - - // Scale based on frame distance if the reference frames not the same. - /*frame_distances[INTRA_FRAME] = 1; // should never be used - frame_distances[LAST_FRAME] = 1; - frame_distances[GOLDEN_FRAME] = - (xd->frames_since_golden) ? xd->frames_since_golden : 1; - frame_distances[ALTREF_FRAME] = - (xd->frames_till_alt_ref_frame) ? xd->frames_till_alt_ref_frame : 1; - - if (frame_distances[this_ref_frame] && - frame_distances[candidate_ref_frame]) { - candidate_mv->as_mv.row = - (short)(((int)(candidate_mv->as_mv.row) * - frame_distances[this_ref_frame]) / - frame_distances[candidate_ref_frame]); - - candidate_mv->as_mv.col = - (short)(((int)(candidate_mv->as_mv.col) * - frame_distances[this_ref_frame]) / - frame_distances[candidate_ref_frame]); - } - */ + // int frame_distances[MAX_REF_FRAMES]; + // int last_distance = 1; + // int gf_distance = xd->frames_since_golden; + // int arf_distance = xd->frames_till_alt_ref_frame; + + // 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; } - // Clamp the MV so it does not point out of the frame buffer - clamp_mv(xd, candidate_mv); + /* + // Scale based on frame distance if the reference frames not the same. + frame_distances[INTRA_FRAME] = 1; // should never be used + frame_distances[LAST_FRAME] = 1; + frame_distances[GOLDEN_FRAME] = + (xd->frames_since_golden) ? xd->frames_si nce_golden : 1; + frame_distances[ALTREF_FRAME] = + (xd->frames_till_alt_ref_frame) ? xd->frames_till_alt_ref_frame : 1; + + if (frame_distances[this_ref_frame] && + frame_distances[candidate_ref_frame]) { + candidate_mv->as_mv.row = + (short)(((int)(candidate_mv->as_mv.row) * + frame_distances[this_ref_frame]) / + frame_distances[candidate_ref_frame]); + + candidate_mv->as_mv.col = + (short)(((int)(candidate_mv->as_mv.col) * + frame_distances[this_ref_frame]) / + frame_distances[candidate_ref_frame]); + } + */ } -// Adds a new candidate reference vector to the list if indeed it is new. -// If it is not new then the score of the existing candidate that it matches -// is increased and the list is resorted. +/* +// Adds a new candidate reference vector to the sorted list. +// If it is a repeat the weight of the existing entry is increased +// and the order of the list is resorted. +// This method of add plus sort has been deprecated for now as there is a +// further sort of the best candidates in vp9_find_best_ref_mvs() and the +// incremental benefit of both is small. If the decision is made to remove +// the sort in vp9_find_best_ref_mvs() for performance reasons then it may be +// worth re-instating some sort of list reordering by weight here. +// static void addmv_and_shuffle( int_mv *mv_list, int *mv_scores, - int *index, + int *refmv_count, int_mv candidate_mv, int weight ) { @@ -162,11 +162,11 @@ static void addmv_and_shuffle( // Check for duplicates. If there is one increase its score. // We only compare vs the current top candidates. - insert_point = (*index < (MAX_MV_REF_CANDIDATES - 1)) - ? *index : (MAX_MV_REF_CANDIDATES - 1); + insert_point = (*refmv_count < (MAX_MV_REF_CANDIDATES - 1)) + ? *refmv_count : (MAX_MV_REF_CANDIDATES - 1); i = insert_point; - if (*index > i) + if (*refmv_count > i) i++; while (i > 0) { i--; @@ -184,7 +184,7 @@ static void addmv_and_shuffle( mv_scores[insert_point] = weight; i = insert_point; } - (*index)++; + (*refmv_count)++; } // Reshuffle the list so that highest scoring mvs at the top. @@ -202,6 +202,42 @@ static void addmv_and_shuffle( break; } } +*/ + +// Adds a new candidate reference vector to the list. +// The mv is thrown out if it is already in the list. +// Unlike the addmv_and_shuffle() this does not reorder the list +// but assumes that candidates are added in the order most likely to +// match distance and reference frame bias. +static void add_candidate_mv( + int_mv *mv_list, + int *mv_scores, + int *candidate_count, + int_mv candidate_mv, + int weight +) { + int i; + int insert_point; + + // Make sure we dont insert off the end of the list + insert_point = (*candidate_count < (MAX_MV_REF_CANDIDATES - 1)) + ? *candidate_count : (MAX_MV_REF_CANDIDATES - 1); + + // Look for duplicates + for (i = 0; i <= insert_point; ++i) { + if (candidate_mv.as_int == mv_list[i].as_int) + break; + } + + // Add the candidate. If the list is already full it is only desirable that + // it should overwrite if it has a higher weight than the last entry. + if ((i >= insert_point) && + (weight > mv_scores[insert_point])) { + mv_list[insert_point].as_int = candidate_mv.as_int; + mv_scores[insert_point] = weight; + *candidate_count += (*candidate_count < MAX_MV_REF_CANDIDATES); + } +} // This function searches the neighbourhood of a given MB/SB and populates a // list of candidate reference vectors. @@ -224,10 +260,11 @@ void vp9_find_mv_refs( MV_REFERENCE_FRAME c_ref_frame; MV_REFERENCE_FRAME c2_ref_frame; int candidate_scores[MAX_MV_REF_CANDIDATES]; - int index = 0; + int refmv_count = 0; int split_count = 0; int (*mv_ref_search)[2]; int *ref_distance_weight; + int zero_seen = FALSE; // Blank the reference vector lists and other local structures. vpx_memset(mv_ref_list, 0, sizeof(int_mv) * MAX_MV_REF_CANDIDATES); @@ -252,9 +289,8 @@ void vp9_find_mv_refs( (mv_ref_search[i][1] * xd->mode_info_stride); if (get_matching_candidate(candidate_mi, ref_frame, &c_refmv)) { - clamp_mv(xd, &c_refmv); - addmv_and_shuffle(candidate_mvs, candidate_scores, - &index, c_refmv, ref_distance_weight[i] + 16); + add_candidate_mv(candidate_mvs, candidate_scores, + &refmv_count, c_refmv, ref_distance_weight[i] + 16); } split_count += (candidate_mi->mbmi.mode == SPLITMV); } @@ -263,23 +299,21 @@ void vp9_find_mv_refs( if (lf_here) { candidate_mi = lf_here; if (get_matching_candidate(candidate_mi, ref_frame, &c_refmv)) { - clamp_mv(xd, &c_refmv); - addmv_and_shuffle(candidate_mvs, candidate_scores, - &index, c_refmv, 18); + add_candidate_mv(candidate_mvs, candidate_scores, + &refmv_count, c_refmv, 18); } } // More distant neigbours for (i = 2; (i < MVREF_NEIGHBOURS) && - (index < (MAX_MV_REF_CANDIDATES - 1)); ++i) { + (refmv_count < (MAX_MV_REF_CANDIDATES - 1)); ++i) { if (((mv_ref_search[i][0] << 7) >= xd->mb_to_left_edge) && ((mv_ref_search[i][1] << 7) >= xd->mb_to_top_edge)) { candidate_mi = here + mv_ref_search[i][0] + (mv_ref_search[i][1] * xd->mode_info_stride); if (get_matching_candidate(candidate_mi, ref_frame, &c_refmv)) { - clamp_mv(xd, &c_refmv); - addmv_and_shuffle(candidate_mvs, candidate_scores, - &index, c_refmv, ref_distance_weight[i] + 16); + add_candidate_mv(candidate_mvs, candidate_scores, + &refmv_count, c_refmv, ref_distance_weight[i] + 16); } } } @@ -288,7 +322,7 @@ void vp9_find_mv_refs( // reference frame does not match. Break out when we have // MAX_MV_REF_CANDIDATES candidates. // Look first at spatial neighbours - if (index < (MAX_MV_REF_CANDIDATES - 1)) { + if (refmv_count < (MAX_MV_REF_CANDIDATES - 1)) { for (i = 0; i < MVREF_NEIGHBOURS; ++i) { if (((mv_ref_search[i][0] << 7) >= xd->mb_to_left_edge) && ((mv_ref_search[i][1] << 7) >= xd->mb_to_top_edge)) { @@ -302,24 +336,24 @@ void vp9_find_mv_refs( if (c_ref_frame != INTRA_FRAME) { scale_mv(xd, ref_frame, c_ref_frame, &c_refmv, ref_sign_bias); - addmv_and_shuffle(candidate_mvs, candidate_scores, - &index, c_refmv, ref_distance_weight[i]); + add_candidate_mv(candidate_mvs, candidate_scores, + &refmv_count, c_refmv, ref_distance_weight[i]); } if (c2_ref_frame != INTRA_FRAME) { scale_mv(xd, ref_frame, c2_ref_frame, &c2_refmv, ref_sign_bias); - addmv_and_shuffle(candidate_mvs, candidate_scores, - &index, c2_refmv, ref_distance_weight[i]); + add_candidate_mv(candidate_mvs, candidate_scores, + &refmv_count, c2_refmv, ref_distance_weight[i]); } } - if (index >= (MAX_MV_REF_CANDIDATES - 1)) { + if (refmv_count >= (MAX_MV_REF_CANDIDATES - 1)) { break; } } } // Look at the last frame if it exists - if (index < (MAX_MV_REF_CANDIDATES - 1) && lf_here) { + if (refmv_count < (MAX_MV_REF_CANDIDATES - 1) && lf_here) { candidate_mi = lf_here; get_non_matching_candidates(candidate_mi, ref_frame, &c_ref_frame, &c_refmv, @@ -327,14 +361,14 @@ void vp9_find_mv_refs( if (c_ref_frame != INTRA_FRAME) { scale_mv(xd, ref_frame, c_ref_frame, &c_refmv, ref_sign_bias); - addmv_and_shuffle(candidate_mvs, candidate_scores, - &index, c_refmv, 2); + add_candidate_mv(candidate_mvs, candidate_scores, + &refmv_count, c_refmv, 2); } if (c2_ref_frame != INTRA_FRAME) { scale_mv(xd, ref_frame, c2_ref_frame, &c2_refmv, ref_sign_bias); - addmv_and_shuffle(candidate_mvs, candidate_scores, - &index, c2_refmv, 2); + add_candidate_mv(candidate_mvs, candidate_scores, + &refmv_count, c2_refmv, 2); } } @@ -342,7 +376,7 @@ void vp9_find_mv_refs( // 0,0 was best if (candidate_mvs[0].as_int == 0) { // 0,0 is only candidate - if (index <= 1) { + if (refmv_count <= 1) { mbmi->mb_mode_context[ref_frame] = 0; // non zero candidates candidates available } else if (split_count == 0) { @@ -352,26 +386,30 @@ void vp9_find_mv_refs( } // Non zero best, No Split MV cases } else if (split_count == 0) { - if (candidate_scores[0] >= 32) { + if (candidate_scores[0] >= 16) { mbmi->mb_mode_context[ref_frame] = 3; } else { mbmi->mb_mode_context[ref_frame] = 4; } // Non zero best, some split mv } else { - if (candidate_scores[0] >= 32) { + if (candidate_scores[0] >= 16) { mbmi->mb_mode_context[ref_frame] = 5; } else { mbmi->mb_mode_context[ref_frame] = 6; } } - // 0,0 is always a valid reference. + // Scan for 0,0 case and clamp non zero choices for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) { - if (candidate_mvs[i].as_int == 0) - break; + if (candidate_mvs[i].as_int == 0) { + zero_seen = TRUE; + } else { + clamp_mv_ref(xd, &candidate_mvs[i]); + } } - if (i == MAX_MV_REF_CANDIDATES) { + // 0,0 is always a valid reference. Add it if not already seen. + if (!zero_seen) { candidate_mvs[MAX_MV_REF_CANDIDATES-1].as_int = 0; }