Fix some minor issues in global motion code
* Fix a check which was supposed to be "is model type IDENTITY or
TRANSLATION?" but was actually written as "is model type not ROTZOOM?"
* Track ref_frame_error for the best warp model found, and use this when
deciding whether to use that model. We were accidentally using the
ref_frame_error for the last model considered instead.
* Also strengthen some checks on when to skip models, in cases where
they definitely won't be useful.
None of these change the encoder output currently - we currently only
consider one model per ref frame, of type ROTZOOM - but this helps
future-proof things so that we can more accurately evaluate multiple
models or use AFFINE type models in the future.
Change-Id: Ieb7edd200ab99dcc2ba98e42b46c79166c260f79
diff --git a/av1/encoder/ethread.c b/av1/encoder/ethread.c
index ba93299..08e773f 100644
--- a/av1/encoder/ethread.c
+++ b/av1/encoder/ethread.c
@@ -2278,7 +2278,7 @@
// INVALID/TRANSLATION/IDENTITY, skip the evaluation of global motion w.r.t
// the remaining ref frames in that direction.
if (cpi->sf.gm_sf.prune_ref_frame_for_gm_search &&
- cpi->common.global_motion[ref_buf_idx].wmtype != ROTZOOM)
+ cpi->common.global_motion[ref_buf_idx].wmtype <= TRANSLATION)
job_info->early_exit[cur_dir] = 1;
#if CONFIG_MULTITHREAD
diff --git a/av1/encoder/global_motion_facade.c b/av1/encoder/global_motion_facade.c
index 7a3acb1..448215a 100644
--- a/av1/encoder/global_motion_facade.c
+++ b/av1/encoder/global_motion_facade.c
@@ -101,66 +101,66 @@
int num_refinements = cpi->sf.gm_sf.num_refinement_steps;
for (model = ROTZOOM; model < GLOBAL_TRANS_TYPES_ENC; ++model) {
- int64_t best_warp_error = INT64_MAX;
-
if (!aom_compute_global_motion(model, cpi->source, ref_buf[frame],
bit_depth, global_motion_method,
motion_models, RANSAC_NUM_MOTIONS)) {
continue;
}
- int64_t ref_frame_error = 0;
+ int64_t best_ref_frame_error = 0;
+ int64_t best_warp_error = INT64_MAX;
for (i = 0; i < RANSAC_NUM_MOTIONS; ++i) {
if (motion_models[i].num_inliers == 0) continue;
params_this_motion = motion_models[i].params;
av1_convert_model_to_params(params_this_motion, &tmp_wm_params);
- // Work around a bug in the AV1 specification
+ // Skip models that we won't use (IDENTITY or TRANSLATION)
+ //
+ // For IDENTITY type models, we don't need to evaluate anything because
+ // all the following logic is effectively comparing the estimated model
+ // to an identity model.
//
// For TRANSLATION type global motion models, gm_get_motion_vector() gives
// the wrong motion vector (see comments in that function for details).
// As translation-type models do not give much gain, we can avoid this bug
// by never choosing a TRANSLATION type model
- if (tmp_wm_params.wmtype == TRANSLATION) {
- continue;
- }
+ if (tmp_wm_params.wmtype <= TRANSLATION) continue;
- if (tmp_wm_params.wmtype != IDENTITY) {
- av1_compute_feature_segmentation_map(
- segment_map, segment_map_w, segment_map_h, motion_models[i].inliers,
- motion_models[i].num_inliers);
+ av1_compute_feature_segmentation_map(
+ segment_map, segment_map_w, segment_map_h, motion_models[i].inliers,
+ motion_models[i].num_inliers);
- ref_frame_error = av1_segmented_frame_error(
- is_cur_buf_hbd(xd), xd->bd, ref_buf[frame]->y_buffer,
- ref_buf[frame]->y_stride, cpi->source->y_buffer, src_width,
- src_height, src_stride, segment_map, segment_map_w);
+ int64_t ref_frame_error = av1_segmented_frame_error(
+ is_cur_buf_hbd(xd), xd->bd, ref_buf[frame]->y_buffer,
+ ref_buf[frame]->y_stride, cpi->source->y_buffer, src_width,
+ src_height, src_stride, segment_map, segment_map_w);
- const int64_t erroradv_threshold =
- calc_erroradv_threshold(ref_frame_error);
+ if (ref_frame_error == 0) continue;
- const int64_t warp_error = av1_refine_integerized_param(
- &tmp_wm_params, tmp_wm_params.wmtype, is_cur_buf_hbd(xd), xd->bd,
- ref_buf[frame]->y_buffer, ref_buf[frame]->y_crop_width,
- ref_buf[frame]->y_crop_height, ref_buf[frame]->y_stride,
- cpi->source->y_buffer, src_width, src_height, src_stride,
- num_refinements, best_warp_error, segment_map, segment_map_w,
- erroradv_threshold);
+ const int64_t erroradv_threshold =
+ calc_erroradv_threshold(ref_frame_error);
- // av1_refine_integerized_param() can return a TRANSLATION type model
- // even if its input is some other type, so we have to skip those too
- if (tmp_wm_params.wmtype == TRANSLATION) {
- continue;
- }
+ const int64_t warp_error = av1_refine_integerized_param(
+ &tmp_wm_params, tmp_wm_params.wmtype, is_cur_buf_hbd(xd), xd->bd,
+ ref_buf[frame]->y_buffer, ref_buf[frame]->y_crop_width,
+ ref_buf[frame]->y_crop_height, ref_buf[frame]->y_stride,
+ cpi->source->y_buffer, src_width, src_height, src_stride,
+ num_refinements, best_warp_error, segment_map, segment_map_w,
+ erroradv_threshold);
- if (warp_error < best_warp_error) {
- best_warp_error = warp_error;
- // Save the wm_params modified by
- // av1_refine_integerized_param() rather than motion index to
- // avoid rerunning refine() below.
- memcpy(&(cm->global_motion[frame]), &tmp_wm_params,
- sizeof(WarpedMotionParams));
- }
+ // av1_refine_integerized_param() can return a simpler model type than
+ // its input, so re-check model type here
+ if (tmp_wm_params.wmtype <= TRANSLATION) continue;
+
+ if (warp_error < best_warp_error) {
+ best_ref_frame_error = ref_frame_error;
+ best_warp_error = warp_error;
+ // Save the wm_params modified by
+ // av1_refine_integerized_param() rather than motion index to
+ // avoid rerunning refine() below.
+ memcpy(&(cm->global_motion[frame]), &tmp_wm_params,
+ sizeof(WarpedMotionParams));
}
}
assert(cm->global_motion[frame].wmtype <= AFFINE);
@@ -183,12 +183,15 @@
if (cm->global_motion[frame].wmtype == IDENTITY) continue;
- if (ref_frame_error == 0) continue;
+ // Once we get here, best_ref_frame_error must be > 0. This is because
+ // of the logic above, which skips over any models which have
+ // ref_frame_error == 0
+ assert(best_ref_frame_error > 0);
// If the best error advantage found doesn't meet the threshold for
// this motion type, revert to IDENTITY.
if (!av1_is_enough_erroradvantage(
- (double)best_warp_error / ref_frame_error,
+ (double)best_warp_error / best_ref_frame_error,
gm_get_params_cost(&cm->global_motion[frame], ref_params,
cm->features.allow_high_precision_mv))) {
cm->global_motion[frame] = default_warp_params;
@@ -231,7 +234,7 @@
// INVALID/TRANSLATION/IDENTITY, skip the evaluation of global motion w.r.t
// the remaining ref frames in that direction.
if (cpi->sf.gm_sf.prune_ref_frame_for_gm_search &&
- cm->global_motion[ref_frame].wmtype != ROTZOOM)
+ cm->global_motion[ref_frame].wmtype <= TRANSLATION)
break;
}
}