Add global motion experiment to rdopt
This patch completes the global motion experiment
implementation. It modifies the format of the motion
parameters to use the mv union to facilitate faster
copying and checks for parameters equal to 0 that occur
frequently in rdopt. The rd decisions for the global motion experiment
have also been added to rdopt.
Change-Id: Idfb9f0c6d23e538221763881099c5a2a3891f5a9
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 305a672..f5a4858 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -3195,29 +3195,29 @@
switch (gmtype) {
case GLOBAL_ZERO: break;
case GLOBAL_AFFINE:
- av1_write_primitive_symmetric(
- w, params->motion_params.wmmat[4] >> GM_ALPHA_PREC_DIFF,
- GM_ABS_ALPHA_BITS);
- av1_write_primitive_symmetric(
- w, (params->motion_params.wmmat[5] >> GM_ALPHA_PREC_DIFF) -
+ aom_write_primitive_symmetric(
+ w, (params->motion_params.wmmat[2].as_mv.row >> GM_ALPHA_PREC_DIFF) -
(1 << GM_ALPHA_PREC_BITS),
GM_ABS_ALPHA_BITS);
+ aom_write_primitive_symmetric(
+ w, (params->motion_params.wmmat[2].as_mv.col >> GM_ALPHA_PREC_DIFF),
+ GM_ABS_ALPHA_BITS);
// fallthrough intended
case GLOBAL_ROTZOOM:
aom_write_primitive_symmetric(
- w, (params->motion_params.wmmat[2] >> GM_ALPHA_PREC_DIFF) -
- (1 << GM_ALPHA_PREC_BITS),
+ w, (params->motion_params.wmmat[1].as_mv.row >> GM_ALPHA_PREC_DIFF),
GM_ABS_ALPHA_BITS);
aom_write_primitive_symmetric(
- w, params->motion_params.wmmat[3] >> GM_ALPHA_PREC_DIFF,
+ w, (params->motion_params.wmmat[1].as_mv.col >> GM_ALPHA_PREC_DIFF) -
+ (1 << GM_ALPHA_PREC_BITS),
GM_ABS_ALPHA_BITS);
// fallthrough intended
case GLOBAL_TRANSLATION:
aom_write_primitive_symmetric(
- w, params->motion_params.wmmat[0] >> GM_TRANS_PREC_DIFF,
+ w, (params->motion_params.wmmat[0].as_mv.row >> GM_TRANS_PREC_DIFF),
GM_ABS_TRANS_BITS);
aom_write_primitive_symmetric(
- w, params->motion_params.wmmat[1] >> GM_TRANS_PREC_DIFF,
+ w, (params->motion_params.wmmat[0].as_mv.col >> GM_TRANS_PREC_DIFF),
GM_ABS_TRANS_BITS);
break;
default: assert(0);
@@ -3233,6 +3233,14 @@
}
write_global_motion_params(&cm->global_motion[frame],
cm->fc->global_motion_types_prob, w);
+ /*
+ printf("Enc Ref %d [%d] (used %d): %d %d %d %d\n",
+ frame, cm->current_video_frame, cpi->global_motion_used[frame],
+ cm->global_motion[frame].motion_params.wmmat[0].as_mv.row,
+ cm->global_motion[frame].motion_params.wmmat[0].as_mv.col,
+ cm->global_motion[frame].motion_params.wmmat[1].as_mv.row,
+ cm->global_motion[frame].motion_params.wmmat[1].as_mv.col);
+ */
}
}
#endif
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index a7183f9..d510b19 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -40,6 +40,7 @@
#include "av1/encoder/cost.h"
#endif
#if CONFIG_GLOBAL_MOTION
+#include "av1/common/warped_motion.h"
#include "av1/encoder/global_motion.h"
#endif
#include "av1/encoder/encodeframe.h"
@@ -4401,37 +4402,30 @@
#if CONFIG_GLOBAL_MOTION
#define MIN_TRANS_THRESH 8
#define GLOBAL_MOTION_ADVANTAGE_THRESH 0.60
-#define GLOBAL_MOTION_MODEL ROTZOOM
+#define GLOBAL_MOTION_MODEL TRANSLATION
static void convert_to_params(double *H, TransformationType type,
- Global_Motion_Params *model) {
+ int16_t *model) {
int i;
int alpha_present = 0;
int n_params = n_trans_model_params[type];
- model->motion_params.wmmat[0] =
- (int)floor(H[0] * (1 << GM_TRANS_PREC_BITS) + 0.5);
- model->motion_params.wmmat[1] =
- (int)floor(H[1] * (1 << GM_TRANS_PREC_BITS) + 0.5);
- model->motion_params.wmmat[0] =
- clamp(model->motion_params.wmmat[0], GM_TRANS_MIN, GM_TRANS_MAX) *
- GM_TRANS_DECODE_FACTOR;
- model->motion_params.wmmat[1] =
- clamp(model->motion_params.wmmat[1], GM_TRANS_MIN, GM_TRANS_MAX) *
- GM_TRANS_DECODE_FACTOR;
+ model[0] = (int16_t)floor(H[0] * (1 << GM_TRANS_PREC_BITS) + 0.5);
+ model[1] = (int16_t)floor(H[1] * (1 << GM_TRANS_PREC_BITS) + 0.5);
+ model[0] = (int16_t)clamp(model[0], GM_TRANS_MIN, GM_TRANS_MAX) *
+ GM_TRANS_DECODE_FACTOR;
+ model[1] = (int16_t)clamp(model[1], GM_TRANS_MIN, GM_TRANS_MAX) *
+ GM_TRANS_DECODE_FACTOR;
for (i = 2; i < n_params; ++i) {
- model->motion_params.wmmat[i] =
- (int)floor(H[i] * (1 << GM_ALPHA_PREC_BITS) + 0.5);
- model->motion_params.wmmat[i] =
- clamp(model->motion_params.wmmat[i], GM_ALPHA_MIN, GM_ALPHA_MAX) *
- GM_ALPHA_DECODE_FACTOR;
- alpha_present |= (model->motion_params.wmmat[i] != 0);
+ model[i] = (int16_t)floor(H[i] * (1 << GM_ALPHA_PREC_BITS) + 0.5);
+ model[i] = (int16_t)clamp(model[i], GM_ALPHA_MIN, GM_ALPHA_MAX) *
+ GM_ALPHA_DECODE_FACTOR;
+ alpha_present |= (model[i] != 0);
}
if (!alpha_present) {
- if (abs(model->motion_params.wmmat[0]) < MIN_TRANS_THRESH &&
- abs(model->motion_params.wmmat[1]) < MIN_TRANS_THRESH) {
- model->motion_params.wmmat[0] = 0;
- model->motion_params.wmmat[1] = 0;
+ if (abs(model[0]) < MIN_TRANS_THRESH && abs(model[1]) < MIN_TRANS_THRESH) {
+ model[0] = 0;
+ model[1] = 0;
}
}
}
@@ -4439,7 +4433,8 @@
static void convert_model_to_params(double *H, TransformationType type,
Global_Motion_Params *model) {
// TODO(sarahparker) implement for homography
- if (type > HOMOGRAPHY) convert_to_params(H, type, model);
+ if (type > HOMOGRAPHY)
+ convert_to_params(H, type, (int16_t *)model->motion_params.wmmat);
model->gmtype = get_gmtype(model);
model->motion_params.wmtype = gm_to_trans_type(model->gmtype);
}
diff --git a/av1/encoder/ransac.c b/av1/encoder/ransac.c
index 0beaab8..a3072bc 100644
--- a/av1/encoder/ransac.c
+++ b/av1/encoder/ransac.c
@@ -469,7 +469,8 @@
}
av1_integerize_model(H, type, &wm);
- projectpoints(wm.wmmat, corners1_int, image1_coord, npoints, 2, 2, 0, 0);
+ projectpoints((int16_t *)wm.wmmat, corners1_int, image1_coord, npoints, 2,
+ 2, 0, 0);
for (i = 0; i < npoints; ++i) {
double dx =
@@ -610,12 +611,12 @@
Ha[6] = Ha[7] = 0;
Ha[8] = 1;
denormalizeHomography(Ha, T1, T2);
- H[0] = Ha[2];
- H[1] = Ha[5];
- H[2] = Ha[0];
- H[3] = Ha[1];
- H[4] = Ha[3];
- H[5] = Ha[4];
+ H[0] = Ha[5];
+ H[1] = Ha[2];
+ H[2] = Ha[1];
+ H[3] = Ha[0];
+ H[4] = Ha[4];
+ H[5] = Ha[3];
}
static void denormalizeRotZoom(double *H, double *T1, double *T2) {
@@ -629,10 +630,10 @@
Ha[6] = Ha[7] = 0;
Ha[8] = 1;
denormalizeHomography(Ha, T1, T2);
- H[0] = Ha[2];
- H[1] = Ha[5];
- H[2] = Ha[0];
- H[3] = Ha[1];
+ H[0] = Ha[5];
+ H[1] = Ha[2];
+ H[2] = Ha[1];
+ H[3] = Ha[0];
}
static void denormalizeTranslation(double *H, double *T1, double *T2) {
@@ -646,8 +647,8 @@
Ha[6] = Ha[7] = 0;
Ha[8] = 1;
denormalizeHomography(Ha, T1, T2);
- H[0] = Ha[2];
- H[1] = Ha[5];
+ H[0] = Ha[5];
+ H[1] = Ha[2];
}
static int is_collinear3(double *p1, double *p2, double *p3) {
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index bd93746..e3941cb 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -4068,6 +4068,31 @@
#endif
}
+#if CONFIG_GLOBAL_MOTION
+static int get_gmbitcost(const Global_Motion_Params *gm,
+ const aom_prob *probs) {
+ int gmtype_cost[GLOBAL_MOTION_TYPES];
+ int bits;
+ av1_cost_tokens(gmtype_cost, probs, av1_global_motion_types_tree);
+ if (gm->motion_params.wmmat[2].as_int) {
+ bits = (GM_ABS_TRANS_BITS + 1) * 2 + 4 * GM_ABS_ALPHA_BITS + 4;
+ } else if (gm->motion_params.wmmat[1].as_int) {
+ bits = (GM_ABS_TRANS_BITS + 1) * 2 + 2 * GM_ABS_ALPHA_BITS + 2;
+ } else {
+ bits =
+ (gm->motion_params.wmmat[0].as_int ? ((GM_ABS_TRANS_BITS + 1) * 2) : 0);
+ }
+ return (bits << AV1_PROB_COST_SHIFT) + gmtype_cost[gm->gmtype];
+}
+
+#define GLOBAL_MOTION_RATE(ref) \
+ (cpi->global_motion_used[ref] >= 2 \
+ ? 0 \
+ : get_gmbitcost(&cm->global_motion[(ref)], \
+ cm->fc->global_motion_types_prob) / \
+ 2);
+#endif // CONFIG_GLOBAL_MOTION
+
static int set_and_cost_bmi_mvs(
AV1_COMP *cpi, MACROBLOCK *x, MACROBLOCKD *xd, int i, PREDICTION_MODE mode,
int_mv this_mv[2], int_mv frame_mv[MB_MODE_COUNT][TOTAL_REFS_PER_FRAME],
@@ -4076,6 +4101,9 @@
int_mv compound_seg_newmvs[2],
#endif // CONFIG_EXT_INTER
int_mv *best_ref_mv[2], const int *mvjcost, int *mvcost[2]) {
+#if CONFIG_GLOBAL_MOTION
+ const AV1_COMMON *cm = &cpi->common;
+#endif // CONFIG_GLOBAL_MOTION
MODE_INFO *const mic = xd->mi[0];
const MB_MODE_INFO *const mbmi = &mic->mbmi;
const MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
@@ -4127,8 +4155,21 @@
this_mv[1].as_int = frame_mv[mode][mbmi->ref_frame[1]].as_int;
break;
case ZEROMV:
+#if CONFIG_GLOBAL_MOTION
+ this_mv[0].as_int = cpi->common.global_motion[mbmi->ref_frame[0]]
+ .motion_params.wmmat[0]
+ .as_int;
+ thismvcost += GLOBAL_MOTION_RATE(mbmi->ref_frame[0]);
+ if (is_compound) {
+ this_mv[1].as_int = cpi->common.global_motion[mbmi->ref_frame[1]]
+ .motion_params.wmmat[0]
+ .as_int;
+ thismvcost += GLOBAL_MOTION_RATE(mbmi->ref_frame[1]);
+ }
+#else // CONFIG_GLOBAL_MOTION
this_mv[0].as_int = 0;
if (is_compound) this_mv[1].as_int = 0;
+#endif // CONFIG_GLOBAL_MOTION
break;
#if CONFIG_EXT_INTER
case NEW_NEWMV:
@@ -4837,7 +4878,12 @@
av1_update_mv_context(xd, mi, frame, mv_ref_list, i, mi_row, mi_col,
NULL);
#endif // CONFIG_EXT_INTER
+#if CONFIG_GLOBAL_MOTION
+ frame_mv[ZEROMV][frame].as_int =
+ cm->global_motion[frame].motion_params.wmmat[0].as_int;
+#else // CONFIG_GLOBAL_MOTION
frame_mv[ZEROMV][frame].as_int = 0;
+#endif // CONFIG_GLOBAL_MOTION
av1_append_sub8x8_mvs_for_idx(cm, xd, i, ref, mi_row, mi_col,
#if CONFIG_REF_MV
ref_mv_stack[ref], &ref_mv_count[ref],
@@ -4973,12 +5019,19 @@
#endif // CONFIG_EXT_INTER
#endif // CONFIG_REF_MV
- if (!check_best_zero_mv(cpi, mbmi_ext->mode_context,
+#if CONFIG_GLOBAL_MOTION
+ if (get_gmtype(&cm->global_motion[mbmi->ref_frame[0]]) == GLOBAL_ZERO &&
+ (!has_second_rf ||
+ get_gmtype(&cm->global_motion[mbmi->ref_frame[1]]) == GLOBAL_ZERO))
+#endif // CONFIG_GLOBAL_MOTION
+
+ if (!check_best_zero_mv(cpi, mbmi_ext->mode_context,
#if CONFIG_REF_MV && CONFIG_EXT_INTER
- mbmi_ext->compound_mode_context,
+ mbmi_ext->compound_mode_context,
#endif // CONFIG_REF_MV && CONFIG_EXT_INTER
- frame_mv, this_mode, mbmi->ref_frame, bsize, i))
- continue;
+ frame_mv, this_mode, mbmi->ref_frame, bsize,
+ i))
+ continue;
memcpy(orig_pre, pd->pre, sizeof(orig_pre));
memcpy(bsi->rdstat[i][mode_idx].ta, t_above,
@@ -7638,6 +7691,12 @@
*rate_uv = 0;
*skippable = 1;
}
+#if CONFIG_GLOBAL_MOTION
+ if (this_mode == ZEROMV) {
+ *rate2 += GLOBAL_MOTION_RATE(mbmi->ref_frame[0]);
+ if (is_comp_pred) *rate2 += GLOBAL_MOTION_RATE(mbmi->ref_frame[1]);
+ }
+#endif // CONFIG_GLOBAL_MOTION
#if CONFIG_OBMC || CONFIG_WARPED_MOTION
tmp_rd = RDCOST(x->rdmult, x->rddiv, *rate2, *distortion);
@@ -8274,7 +8333,12 @@
frame_mv[NEARESTMV], frame_mv[NEARMV], yv12_mb);
}
frame_mv[NEWMV][ref_frame].as_int = INVALID_MV;
+#if CONFIG_GLOBAL_MOTION
+ frame_mv[ZEROMV][ref_frame].as_int =
+ cm->global_motion[ref_frame].motion_params.wmmat[0].as_int;
+#else // CONFIG_GLOBAL_MOTION
frame_mv[ZEROMV][ref_frame].as_int = 0;
+#endif // CONFIG_GLOBAL_MOTION
#if CONFIG_EXT_INTER
frame_mv[NEWFROMNEARMV][ref_frame].as_int = INVALID_MV;
frame_mv[NEW_NEWMV][ref_frame].as_int = INVALID_MV;
@@ -8351,6 +8415,7 @@
// an unfiltered alternative. We allow near/nearest as well
// because they may result in zero-zero MVs but be cheaper.
if (cpi->rc.is_src_frame_alt_ref && (cpi->oxcf.arnr_max_frames == 0)) {
+ int_mv zeromv;
ref_frame_skip_mask[0] = (1 << LAST_FRAME) |
#if CONFIG_EXT_REFS
(1 << LAST2_FRAME) | (1 << LAST3_FRAME) |
@@ -8361,18 +8426,24 @@
// TODO(zoeliu): To further explore whether following needs to be done for
// BWDREF_FRAME as well.
mode_skip_mask[ALTREF_FRAME] = ~INTER_NEAREST_NEAR_ZERO;
- if (frame_mv[NEARMV][ALTREF_FRAME].as_int != 0)
+#if CONFIG_GLOBAL_MOTION
+ zeromv.as_int =
+ cm->global_motion[ALTREF_FRAME].motion_params.wmmat[0].as_int;
+#else
+ zeromv.as_int = 0;
+#endif // CONFIG_GLOBAL_MOTION
+ if (frame_mv[NEARMV][ALTREF_FRAME].as_int != zeromv.as_int)
mode_skip_mask[ALTREF_FRAME] |= (1 << NEARMV);
- if (frame_mv[NEARESTMV][ALTREF_FRAME].as_int != 0)
+ if (frame_mv[NEARESTMV][ALTREF_FRAME].as_int != zeromv.as_int)
mode_skip_mask[ALTREF_FRAME] |= (1 << NEARESTMV);
#if CONFIG_EXT_INTER
- if (frame_mv[NEAREST_NEARESTMV][ALTREF_FRAME].as_int != 0)
+ if (frame_mv[NEAREST_NEARESTMV][ALTREF_FRAME].as_int != zeromv.as_int)
mode_skip_mask[ALTREF_FRAME] |= (1 << NEAREST_NEARESTMV);
- if (frame_mv[NEAREST_NEARMV][ALTREF_FRAME].as_int != 0)
+ if (frame_mv[NEAREST_NEARMV][ALTREF_FRAME].as_int != zeromv.as_int)
mode_skip_mask[ALTREF_FRAME] |= (1 << NEAREST_NEARMV);
- if (frame_mv[NEAR_NEARESTMV][ALTREF_FRAME].as_int != 0)
+ if (frame_mv[NEAR_NEARESTMV][ALTREF_FRAME].as_int != zeromv.as_int)
mode_skip_mask[ALTREF_FRAME] |= (1 << NEAR_NEARESTMV);
- if (frame_mv[NEAR_NEARMV][ALTREF_FRAME].as_int != 0)
+ if (frame_mv[NEAR_NEARMV][ALTREF_FRAME].as_int != zeromv.as_int)
mode_skip_mask[ALTREF_FRAME] |= (1 << NEAR_NEARMV);
#endif // CONFIG_EXT_INTER
}
@@ -8580,7 +8651,14 @@
if (conditional_skipintra(this_mode, best_intra_mode)) continue;
}
}
+#if CONFIG_GLOBAL_MOTION
+ } else if (get_gmtype(&cm->global_motion[ref_frame]) == GLOBAL_ZERO &&
+ (!comp_pred ||
+ get_gmtype(&cm->global_motion[second_ref_frame]) ==
+ GLOBAL_ZERO)) {
+#else // CONFIG_GLOBAL_MOTION
} else {
+#endif // CONFIG_GLOBAL_MOTION
const MV_REFERENCE_FRAME ref_frames[2] = { ref_frame, second_ref_frame };
if (!check_best_zero_mv(cpi, mbmi_ext->mode_context,
#if CONFIG_REF_MV && CONFIG_EXT_INTER
@@ -9426,8 +9504,18 @@
const MV_REFERENCE_FRAME refs[2] = { best_mbmode.ref_frame[0],
best_mbmode.ref_frame[1] };
int comp_pred_mode = refs[1] > INTRA_FRAME;
+ int_mv zeromv[2];
#if CONFIG_REF_MV
const uint8_t rf_type = av1_ref_frame_type(best_mbmode.ref_frame);
+#endif // CONFIG_REF_MV
+#if CONFIG_GLOBAL_MOTION
+ zeromv[0].as_int = cm->global_motion[refs[0]].motion_params.wmmat[0].as_int;
+ zeromv[1].as_int = cm->global_motion[refs[1]].motion_params.wmmat[0].as_int;
+#else
+ zeromv[0].as_int = 0;
+ zeromv[1].as_int = 0;
+#endif // CONFIG_GLOBAL_MOTION
+#if CONFIG_REF_MV
if (!comp_pred_mode) {
int i;
int ref_set = (mbmi_ext->ref_mv_count[rf_type] >= 2)
@@ -9444,7 +9532,7 @@
if (frame_mv[NEARESTMV][refs[0]].as_int == best_mbmode.mv[0].as_int)
best_mbmode.mode = NEARESTMV;
- else if (best_mbmode.mv[0].as_int == 0)
+ else if (best_mbmode.mv[0].as_int == zeromv[0].as_int)
best_mbmode.mode = ZEROMV;
} else {
int_mv nearestmv[2];
@@ -9500,7 +9588,8 @@
best_mbmode.mode = ZERO_ZEROMV;
#else
best_mbmode.mode = NEARESTMV;
- else if (best_mbmode.mv[0].as_int == 0 && best_mbmode.mv[1].as_int == 0)
+ else if (best_mbmode.mv[0].as_int == zeromv[0].as_int &&
+ best_mbmode.mv[1].as_int == zeromv[1].as_int)
best_mbmode.mode = ZEROMV;
#endif // CONFIG_EXT_INTER
}
@@ -9519,8 +9608,9 @@
best_mbmode.mv[1].as_int) ||
!comp_pred_mode))
best_mbmode.mode = NEARMV;
- else if (best_mbmode.mv[0].as_int == 0 &&
- ((comp_pred_mode && best_mbmode.mv[1].as_int == 0) ||
+ else if (best_mbmode.mv[0].as_int == zeromv[0].as_int &&
+ ((comp_pred_mode &&
+ best_mbmode.mv[1].as_int == zeromv[1].as_int) ||
!comp_pred_mode))
best_mbmode.mode = ZEROMV;
#if CONFIG_EXT_INTER
@@ -9692,7 +9782,13 @@
mbmi->uv_mode = DC_PRED;
mbmi->ref_frame[0] = LAST_FRAME;
mbmi->ref_frame[1] = NONE;
+#if CONFIG_GLOBAL_MOTION
+ mbmi->mv[0].as_int =
+ cm->global_motion[mbmi->ref_frame[0]].motion_params.wmmat[0].as_int;
+#else // CONFIG_GLOBAL_MOTION
mbmi->mv[0].as_int = 0;
+#endif // CONFIG_GLOBAL_MOTION
+
#if CONFIG_REF_MV
mbmi->ref_mv_idx = 0;
mbmi->pred_mv[0].as_int = 0;