Further change to mv reference search.
This experimental change reorders the search so that all possible references that match the target reference frame are tested first and these in order of distance from the current block. These will usually be the highest scoring candidates. If we do not find enough good candidates this way we try non matching cases. These will usually be lower scoring candidates. The change in order together with breakouts when we have found enough candidates should reduce the computational cost and especially reduce the number of sort operations. Quality Results: Std Hd +0.228%, Hd +0.074%, YT +0.046%, derf +0.137% This effect is probably due to the fact that more distant weak candidates are now less likely to get "promoted" over near candidates even if they are repeated. Change-Id: Iec37e77d88a48ad0ee1f315b14327a95d63f81f6
This commit is contained in:
parent
df7ce5a711
commit
c6ba3a3d85
@ -25,6 +25,7 @@ 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 };
|
||||
#endif
|
||||
|
||||
// clamp_mv
|
||||
#define MV_BORDER (16 << 3) // Allow 16 pels in 1/8th pel units
|
||||
static void clamp_mv(const MACROBLOCKD *xd, int_mv *mv) {
|
||||
@ -40,10 +41,29 @@ static void clamp_mv(const MACROBLOCKD *xd, int_mv *mv) {
|
||||
mv->as_mv.row = xd->mb_to_bottom_edge + MV_BORDER;
|
||||
}
|
||||
|
||||
// Gets a candidate refenence 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 ret_val = TRUE;
|
||||
|
||||
// Gets a best matching candidate refenence motion vector
|
||||
// from the given mode info structure (if available)
|
||||
static int get_candidate_mvref(
|
||||
if (ref_frame == candidate_mi->mbmi.ref_frame) {
|
||||
c_mv->as_int = candidate_mi->mbmi.mv[0].as_int;
|
||||
} else if (ref_frame == candidate_mi->mbmi.second_ref_frame) {
|
||||
c_mv->as_int = candidate_mi->mbmi.mv[1].as_int;
|
||||
} else {
|
||||
ret_val = FALSE;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
// Gets candidate refenence 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,
|
||||
@ -52,61 +72,29 @@ static int get_candidate_mvref(
|
||||
int_mv *c2_mv
|
||||
) {
|
||||
|
||||
int ret_val = FALSE;
|
||||
c_mv->as_int = 0;
|
||||
c2_mv->as_int = 0;
|
||||
*c_ref_frame = INTRA_FRAME;
|
||||
*c2_ref_frame = INTRA_FRAME;
|
||||
|
||||
// Target ref frame matches candidate first ref frame
|
||||
if (ref_frame == candidate_mi->mbmi.ref_frame) {
|
||||
c_mv->as_int = candidate_mi->mbmi.mv[0].as_int;
|
||||
*c_ref_frame = ref_frame;
|
||||
ret_val = TRUE;
|
||||
// If first candidate not valid neither will be.
|
||||
if (candidate_mi->mbmi.ref_frame > INTRA_FRAME) {
|
||||
// First candidate
|
||||
if (candidate_mi->mbmi.ref_frame != ref_frame) {
|
||||
*c_ref_frame = candidate_mi->mbmi.ref_frame;
|
||||
c_mv->as_int = candidate_mi->mbmi.mv[0].as_int;
|
||||
}
|
||||
|
||||
// Is there a second non zero vector we can use.
|
||||
// Second candidate
|
||||
if ((candidate_mi->mbmi.second_ref_frame > INTRA_FRAME) &&
|
||||
(candidate_mi->mbmi.mv[1].as_int != 0) &&
|
||||
(candidate_mi->mbmi.mv[1].as_int != c_mv->as_int)) {
|
||||
c2_mv->as_int = candidate_mi->mbmi.mv[1].as_int;
|
||||
(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)) {
|
||||
*c2_ref_frame = candidate_mi->mbmi.second_ref_frame;
|
||||
}
|
||||
|
||||
// Target ref frame matches candidate second ref frame
|
||||
} else if (ref_frame == candidate_mi->mbmi.second_ref_frame) {
|
||||
c_mv->as_int = candidate_mi->mbmi.mv[1].as_int;
|
||||
*c_ref_frame = ref_frame;
|
||||
ret_val = TRUE;
|
||||
|
||||
// Is there a second non zero vector we can use.
|
||||
if ((candidate_mi->mbmi.ref_frame > INTRA_FRAME) &&
|
||||
(candidate_mi->mbmi.mv[0].as_int != 0) &&
|
||||
(candidate_mi->mbmi.mv[0].as_int != c_mv->as_int)) {
|
||||
c2_mv->as_int = candidate_mi->mbmi.mv[0].as_int;
|
||||
*c2_ref_frame = candidate_mi->mbmi.ref_frame;
|
||||
}
|
||||
|
||||
// No ref frame matches so use first ref mv as first choice
|
||||
} else if (candidate_mi->mbmi.ref_frame > INTRA_FRAME) {
|
||||
c_mv->as_int = candidate_mi->mbmi.mv[0].as_int;
|
||||
*c_ref_frame = candidate_mi->mbmi.ref_frame;
|
||||
ret_val = TRUE;
|
||||
|
||||
// Is there a second non zero vector we can use.
|
||||
if ((candidate_mi->mbmi.second_ref_frame > INTRA_FRAME) &&
|
||||
(candidate_mi->mbmi.mv[1].as_int != 0) &&
|
||||
(candidate_mi->mbmi.mv[1].as_int != c_mv->as_int)) {
|
||||
c2_mv->as_int = candidate_mi->mbmi.mv[1].as_int;
|
||||
*c2_ref_frame = candidate_mi->mbmi.second_ref_frame;
|
||||
}
|
||||
|
||||
// If only the second ref mv is valid:- (Should not trigger in current code
|
||||
// base given current possible compound prediction options).
|
||||
} else if (candidate_mi->mbmi.second_ref_frame > INTRA_FRAME) {
|
||||
c_mv->as_int = candidate_mi->mbmi.mv[1].as_int;
|
||||
*c_ref_frame = candidate_mi->mbmi.second_ref_frame;
|
||||
ret_val = TRUE;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
// Performs mv adjustment based on reference frame and clamps the MV
|
||||
@ -240,8 +228,6 @@ void vp9_find_mv_refs(
|
||||
int candidate_scores[MAX_MV_REF_CANDIDATES];
|
||||
int index = 0;
|
||||
int split_count = 0;
|
||||
int ref_weight = 0;
|
||||
int valid_mv_ref;
|
||||
int (*mv_ref_search)[2];
|
||||
int *ref_distance_weight;
|
||||
|
||||
@ -262,8 +248,9 @@ void vp9_find_mv_refs(
|
||||
mv_ref_search = mb_mv_ref_search;
|
||||
ref_distance_weight = mb_ref_distance_weight;
|
||||
#endif
|
||||
// Populate a list with candidate reference vectors from the
|
||||
// spatial neighbours.
|
||||
|
||||
// We first scan for candidate vectors that match the current reference frame
|
||||
// Look at nearest neigbours
|
||||
for (i = 0; i < 2; ++i) {
|
||||
if (((mv_ref_search[i][0] << 7) >= xd->mb_to_left_edge) &&
|
||||
((mv_ref_search[i][1] << 7) >= xd->mb_to_top_edge)) {
|
||||
@ -271,89 +258,88 @@ void vp9_find_mv_refs(
|
||||
candidate_mi = here + mv_ref_search[i][0] +
|
||||
(mv_ref_search[i][1] * xd->mode_info_stride);
|
||||
|
||||
valid_mv_ref = get_candidate_mvref(candidate_mi, ref_frame,
|
||||
&c_ref_frame, &c_refmv,
|
||||
&c2_ref_frame, &c2_refmv);
|
||||
|
||||
// If there is a valid MV candidate then add it to the list
|
||||
if (valid_mv_ref) {
|
||||
scale_mv(xd, ref_frame, c_ref_frame, &c_refmv, ref_sign_bias );
|
||||
ref_weight = ref_distance_weight[i] +
|
||||
((c_ref_frame == ref_frame) << 4);
|
||||
split_count += (candidate_mi->mbmi.mode == SPLITMV);
|
||||
|
||||
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_weight);
|
||||
|
||||
// If there is a second valid mv then add it as well.
|
||||
if (c2_ref_frame > INTRA_FRAME) {
|
||||
scale_mv(xd, ref_frame, c2_ref_frame, &c2_refmv, ref_sign_bias );
|
||||
ref_weight = ref_distance_weight[i] +
|
||||
((c2_ref_frame == ref_frame) << 4);
|
||||
|
||||
addmv_and_shuffle(candidate_mvs, candidate_scores,
|
||||
&index, c2_refmv, ref_weight);
|
||||
}
|
||||
&index, c_refmv, ref_distance_weight[i] + 16);
|
||||
}
|
||||
split_count += (candidate_mi->mbmi.mode == SPLITMV);
|
||||
}
|
||||
}
|
||||
|
||||
// Look at the corresponding vector in the last frame
|
||||
// Look in the last frame
|
||||
candidate_mi = lf_here;
|
||||
valid_mv_ref = get_candidate_mvref(candidate_mi, ref_frame,
|
||||
&c_ref_frame, &c_refmv,
|
||||
&c2_ref_frame, &c2_refmv);
|
||||
|
||||
// If there is a valid MV candidate then add it to the list
|
||||
if (valid_mv_ref) {
|
||||
scale_mv(xd, ref_frame, c_ref_frame, &c_refmv, ref_sign_bias );
|
||||
ref_weight = 2 + ((c_ref_frame == ref_frame) << 4);
|
||||
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_weight);
|
||||
|
||||
// If there is a second valid mv then add it as well.
|
||||
if (c2_ref_frame > INTRA_FRAME) {
|
||||
scale_mv(xd, ref_frame, c2_ref_frame, &c2_refmv, ref_sign_bias );
|
||||
ref_weight = ref_distance_weight[i] +
|
||||
((c2_ref_frame == ref_frame) << 4);
|
||||
|
||||
addmv_and_shuffle(candidate_mvs, candidate_scores,
|
||||
&index, c2_refmv, ref_weight);
|
||||
}
|
||||
&index, c_refmv, 18);
|
||||
}
|
||||
|
||||
// Populate a list with candidate reference vectors from the
|
||||
// spatial neighbours.
|
||||
for (i = 2; (i < MVREF_NEIGHBOURS) && (index < (MAX_MV_REFS - 2)); ++i) {
|
||||
// More distant neigbours
|
||||
for (i = 2; (i < MVREF_NEIGHBOURS) &&
|
||||
(index < (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);
|
||||
|
||||
valid_mv_ref = get_candidate_mvref(candidate_mi, ref_frame,
|
||||
&c_ref_frame, &c_refmv,
|
||||
&c2_ref_frame, &c2_refmv);
|
||||
|
||||
// If there is a valid MV candidate then add it to the list
|
||||
if (valid_mv_ref) {
|
||||
scale_mv(xd, ref_frame, c_ref_frame, &c_refmv, ref_sign_bias );
|
||||
ref_weight = ref_distance_weight[i] +
|
||||
((c_ref_frame == ref_frame) << 4);
|
||||
|
||||
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_weight);
|
||||
&index, c_refmv, ref_distance_weight[i] + 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there is a second valid mv then add it as well.
|
||||
if (c2_ref_frame > INTRA_FRAME) {
|
||||
scale_mv(xd, ref_frame, c2_ref_frame, &c2_refmv, ref_sign_bias );
|
||||
ref_weight = ref_distance_weight[i] +
|
||||
((c2_ref_frame == ref_frame) << 4);
|
||||
// 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
|
||||
if (index < (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)) {
|
||||
|
||||
candidate_mi = here + mv_ref_search[i][0] +
|
||||
(mv_ref_search[i][1] * xd->mode_info_stride);
|
||||
|
||||
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(xd, ref_frame, c_ref_frame, &c_refmv, ref_sign_bias);
|
||||
addmv_and_shuffle(candidate_mvs, candidate_scores,
|
||||
&index, c2_refmv, ref_weight);
|
||||
&index, 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]);
|
||||
}
|
||||
}
|
||||
|
||||
if (index >= (MAX_MV_REF_CANDIDATES - 1)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Look at the last frame
|
||||
if (index < (MAX_MV_REF_CANDIDATES - 1)) {
|
||||
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(xd, ref_frame, c_ref_frame, &c_refmv, ref_sign_bias);
|
||||
addmv_and_shuffle(candidate_mvs, candidate_scores,
|
||||
&index, 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user