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
This commit is contained in:
Sarah Parker
2016-08-16 14:57:37 -07:00
parent 9c323bc272
commit e529986568
9 changed files with 298 additions and 151 deletions

View File

@@ -3195,29 +3195,29 @@ static void write_global_motion_params(Global_Motion_Params *params,
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 @@ static void write_global_motion(AV1_COMP *cpi, aom_writer *w) {
}
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

View File

@@ -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 @@ static int input_fpmb_stats(FIRSTPASS_MB_STATS *firstpass_mb_stats,
#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_to_params(double *H, TransformationType type,
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);
}

View File

@@ -469,7 +469,8 @@ int ransac_(double *matched_points, int npoints, int *number_of_inliers,
}
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 @@ static void denormalizeAffine(double *H, double *T1, double *T2) {
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 @@ static void denormalizeRotZoom(double *H, double *T1, double *T2) {
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 @@ static void denormalizeTranslation(double *H, double *T1, double *T2) {
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) {

View File

@@ -4068,6 +4068,31 @@ static int cost_mv_ref(const AV1_COMP *cpi, PREDICTION_MODE mode,
#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 @@ static int set_and_cost_bmi_mvs(
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 @@ static int set_and_cost_bmi_mvs(
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 @@ static int64_t rd_pick_best_sub8x8_mode(
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 @@ static int64_t rd_pick_best_sub8x8_mode(
#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 @@ static int64_t handle_inter_mode(
*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 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data,
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 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data,
// 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 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data,
// 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 @@ void av1_rd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data,
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 @@ PALETTE_EXIT:
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 @@ PALETTE_EXIT:
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 @@ PALETTE_EXIT:
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 @@ PALETTE_EXIT:
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 @@ void av1_rd_pick_inter_mode_sb_seg_skip(AV1_COMP *cpi, TileDataEnc *tile_data,
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;