diff --git a/vp10/common/blockd.h b/vp10/common/blockd.h index 6314e0510afa0fb00d9aa19873d968b315e06fec..4c46cbb718c5c96f8c2042e10fb613d95055118a 100644 --- a/vp10/common/blockd.h +++ b/vp10/common/blockd.h @@ -388,6 +388,9 @@ typedef struct macroblockd { int corrupted; struct vpx_internal_error_info *error_info; +#if CONFIG_GLOBAL_MOTION + Global_Motion_Params *global_motion; +#endif // CONFIG_GLOBAL_MOTION } MACROBLOCKD; static INLINE BLOCK_SIZE get_subsize(BLOCK_SIZE bsize, diff --git a/vp10/common/entropymode.h b/vp10/common/entropymode.h index 71e79d90dce0093c24e513c03600000b7a352f69..a898038a839aed223a56c89654169f3294daf912 100644 --- a/vp10/common/entropymode.h +++ b/vp10/common/entropymode.h @@ -118,6 +118,9 @@ typedef struct frame_contexts { vpx_prob ext_intra_probs[PLANE_TYPES]; vpx_prob intra_filter_probs[INTRA_FILTERS + 1][INTRA_FILTERS - 1]; #endif // CONFIG_EXT_INTRA +#if CONFIG_GLOBAL_MOTION + vpx_prob global_motion_types_prob[GLOBAL_MOTION_TYPES - 1]; +#endif // CONFIG_GLOBAL_MOTION } FRAME_CONTEXT; typedef struct FRAME_COUNTS { diff --git a/vp10/common/entropymv.c b/vp10/common/entropymv.c index 87c64219f062a1fb31da9d68aeeb236e1a35f48e..ae6209d00b3fa6d52eebc4289e2e9cbb3d461b12 100644 --- a/vp10/common/entropymv.c +++ b/vp10/common/entropymv.c @@ -120,6 +120,17 @@ static const uint8_t log_in_base_2[] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10 }; +#if CONFIG_GLOBAL_MOTION +const vpx_tree_index vp10_global_motion_types_tree + [TREE_SIZE(GLOBAL_MOTION_TYPES)] = { + -GLOBAL_ZERO, 2, + -GLOBAL_TRANSLATION, -GLOBAL_ROTZOOM +}; + +static const vpx_prob default_global_motion_types_prob + [GLOBAL_MOTION_TYPES - 1] = {224, 128}; +#endif // CONFIG_GLOBAL_MOTION + static INLINE int mv_class_base(MV_CLASS_TYPE c) { return c ? CLASS0_SIZE << (c + 2) : 0; } @@ -277,4 +288,7 @@ void vp10_init_mv_probs(VP10_COMMON *cm) { #else cm->fc->nmvc = default_nmv_context; #endif +#if CONFIG_GLOBAL_MOTION + vp10_copy(cm->fc->global_motion_types_prob, default_global_motion_types_prob); +#endif // CONFIG_GLOBAL_MOTION } diff --git a/vp10/common/entropymv.h b/vp10/common/entropymv.h index f8ade34d5740f0a8b6533bb3fab1c36d62f60802..af69a2daa53440ed90240889e835ea7f1da76b68 100644 --- a/vp10/common/entropymv.h +++ b/vp10/common/entropymv.h @@ -132,6 +132,11 @@ typedef struct { void vp10_inc_mv(const MV *mv, nmv_context_counts *mvctx, const int usehp); +#if CONFIG_GLOBAL_MOTION +extern const vpx_tree_index vp10_global_motion_types_tree + [TREE_SIZE(GLOBAL_MOTION_TYPES)]; +#endif // CONFIG_GLOBAL_MOTION + #ifdef __cplusplus } // extern "C" #endif diff --git a/vp10/common/mv.h b/vp10/common/mv.h index 8b9348bcadb6f0e0d13d6113c241c7a2edc23404..255a7243cf2860cc5387a9f3c9f97aede8b3f643 100644 --- a/vp10/common/mv.h +++ b/vp10/common/mv.h @@ -13,6 +13,9 @@ #include "vp10/common/common.h" #include "vpx_dsp/vpx_filter.h" +#if CONFIG_GLOBAL_MOTION +#include "vp10/common/warped_motion.h" +#endif // CONFIG_GLOBAL_MOTION #ifdef __cplusplus extern "C" { @@ -33,6 +36,64 @@ typedef struct mv32 { int32_t col; } MV32; +#if CONFIG_GLOBAL_MOTION +// ALPHA here refers to parameters a and b in rotzoom model: +// | a b| +// |-b a| +// +// Anything ending in PREC_BITS is the number of bits of precision +// to maintain when converting from double to integer. +// +// The ABS parameters are used to create an upper and lower bound +// for each parameter. In other words, after a parameter is integerized +// it is clamped between -(1 << ABS_XXX_BITS) and (1 << ABS_XXX_BITS) +// +// XXX_PREC_DIFF and XXX_DECODE_FACTOR are computed once here to +// prevent repetetive computation on the decoder side. These are +// to allow the global motion parameters to be encoded in a lower +// precision than the warped model precision. This means that they +// need to be changed to warped precision when they are decoded. +// +// XX_MIN, XX_MAX are also computed to avoid repeated computation + +#define GM_TRANS_PREC_BITS 3 +#define GM_TRANS_PREC_DIFF (WARPEDMODEL_PREC_BITS - GM_TRANS_PREC_BITS) +#define GM_TRANS_DECODE_FACTOR (1 << GM_TRANS_PREC_DIFF) + +#define GM_ALPHA_PREC_BITS 5 +#define GM_ALPHA_PREC_DIFF (WARPEDMODEL_PREC_BITS - GM_ALPHA_PREC_BITS) +#define GM_ALPHA_DECODE_FACTOR (1 << GM_ALPHA_PREC_DIFF) + +#define GM_ABS_ALPHA_BITS 5 +#define GM_ABS_TRANS_BITS 5 + +#define GM_TRANS_MAX (1 << GM_ABS_TRANS_BITS) +#define GM_ALPHA_MAX (1 << GM_ABS_ALPHA_BITS) +#define GM_TRANS_MIN -GM_TRANS_MAX +#define GM_ALPHA_MIN -GM_ALPHA_MAX + +typedef enum { + GLOBAL_ZERO = 0, + GLOBAL_TRANSLATION = 1, + GLOBAL_ROTZOOM = 2, + GLOBAL_MOTION_TYPES +} GLOBAL_MOTION_TYPE; + +typedef struct { + GLOBAL_MOTION_TYPE gmtype; + WarpedMotionParams motion_params; +} Global_Motion_Params; + +static INLINE GLOBAL_MOTION_TYPE get_gmtype(const Global_Motion_Params *gm) { + if (gm->motion_params.wmmat[2] == 0 && gm->motion_params.wmmat[3] == 0) { + return ((gm->motion_params.wmmat[0] | gm->motion_params.wmmat[1]) ? + GLOBAL_TRANSLATION : GLOBAL_ZERO); + } else { + return GLOBAL_ROTZOOM; + } +} +#endif // CONFIG_GLOBAL_MOTION + #if CONFIG_REF_MV typedef struct candidate_mv { int_mv this_mv; diff --git a/vp10/common/onyxc_int.h b/vp10/common/onyxc_int.h index b2d65b5f9c9ad471ea5147ddaf99115df4e4a60c..37f7631c7ed963180dbf7aeefb0e99930e14c7aa 100644 --- a/vp10/common/onyxc_int.h +++ b/vp10/common/onyxc_int.h @@ -350,6 +350,9 @@ typedef struct VP10Common { // - this is intentionally not placed in FRAME_CONTEXT since it's reset upon // each keyframe and not used afterwards vpx_prob kf_y_prob[INTRA_MODES][INTRA_MODES][INTRA_MODES - 1]; +#if CONFIG_GLOBAL_MOTION + Global_Motion_Params global_motion[MAX_REF_FRAMES]; +#endif BLOCK_SIZE sb_size; // Size of the superblock used for this frame int mib_size; // Size of the superblock in units of MI blocks diff --git a/vp10/decoder/decodeframe.c b/vp10/decoder/decodeframe.c index d4c7d5efa84fe64b867b3351c0e2832b700cd2c3..66b44a36bdfa58ab6065d97307fe2a1ffe543c85 100644 --- a/vp10/decoder/decodeframe.c +++ b/vp10/decoder/decodeframe.c @@ -3443,6 +3443,55 @@ static void read_supertx_probs(FRAME_CONTEXT *fc, vp10_reader *r) { } #endif // CONFIG_SUPERTX +#if CONFIG_GLOBAL_MOTION +static void read_global_motion_params(Global_Motion_Params *params, + vpx_prob *probs, + vp10_reader *r) { + GLOBAL_MOTION_TYPE gmtype = vp10_read_tree(r, vp10_global_motion_types_tree, + probs); + params->gmtype = gmtype; + switch (gmtype) { + case GLOBAL_ZERO: + break; + case GLOBAL_TRANSLATION: + params->motion_params.wmtype = TRANSLATION; + params->motion_params.wmmat[0] = + vp10_read_primitive_symmetric(r, GM_ABS_TRANS_BITS) * + GM_TRANS_DECODE_FACTOR; + params->motion_params.wmmat[1] = + vp10_read_primitive_symmetric(r, GM_ABS_TRANS_BITS) * + GM_TRANS_DECODE_FACTOR; + break; + case GLOBAL_ROTZOOM: + params->motion_params.wmtype = ROTZOOM; + params->motion_params.wmmat[2] = + vp10_read_primitive_symmetric(r, GM_ABS_TRANS_BITS) * + GM_TRANS_DECODE_FACTOR; + params->motion_params.wmmat[3] = + vp10_read_primitive_symmetric(r, GM_ABS_TRANS_BITS) * + GM_TRANS_DECODE_FACTOR; + params->motion_params.wmmat[0] = + (vp10_read_primitive_symmetric(r, GM_ABS_ALPHA_BITS) * + GM_ALPHA_DECODE_FACTOR) + (1 << WARPEDMODEL_PREC_BITS); + params->motion_params.wmmat[1] = + vp10_read_primitive_symmetric(r, GM_ABS_ALPHA_BITS) * + GM_ALPHA_DECODE_FACTOR; + break; + default: + assert(0); + } +} + +static void read_global_motion(VP10_COMMON *cm, vp10_reader *r) { + int frame; + memset(cm->global_motion, 0, sizeof(cm->global_motion)); + for (frame = LAST_FRAME; frame <= ALTREF_FRAME; ++frame) { + read_global_motion_params( + &cm->global_motion[frame], cm->fc->global_motion_types_prob, r); + } +} +#endif // CONFIG_GLOBAL_MOTION + static int read_compressed_header(VP10Decoder *pbi, const uint8_t *data, size_t partition_size) { VP10_COMMON *const cm = &pbi->common; @@ -3585,6 +3634,9 @@ static int read_compressed_header(VP10Decoder *pbi, const uint8_t *data, if (!xd->lossless[0]) read_supertx_probs(fc, &r); #endif +#if CONFIG_GLOBAL_MOTION + read_global_motion(cm, &r); +#endif // CONFIG_GLOBAL_MOTION } return vp10_reader_has_error(&r); @@ -3714,6 +3766,9 @@ void vp10_decode_frame(VP10Decoder *pbi, init_read_bit_buffer(pbi, &rb, data, data_end, clear_data)); YV12_BUFFER_CONFIG *const new_fb = get_frame_new_buffer(cm); xd->cur_buf = new_fb; +#if CONFIG_GLOBAL_MOTION + xd->global_motion = cm->global_motion; +#endif // CONFIG_GLOBAL_MOTION if (!first_partition_size) { // showing a frame directly diff --git a/vp10/decoder/dsubexp.c b/vp10/decoder/dsubexp.c index 4d53e12c7340d4535e55b16f54e3c0944732e338..49695cc929d8807feefab0ee70209f5d9ec3e439 100644 --- a/vp10/decoder/dsubexp.c +++ b/vp10/decoder/dsubexp.c @@ -74,3 +74,13 @@ void vp10_diff_update_prob(vp10_reader *r, vpx_prob* p) { *p = (vpx_prob)inv_remap_prob(delp, *p); } } + +int vp10_read_primitive_symmetric(vp10_reader *r, unsigned int mag_bits) { + if (vp10_read_bit(r)) { + int s = vp10_read_bit(r); + int x = vp10_read_literal(r, mag_bits) + 1; + return (s > 0 ? -x : x); + } else { + return 0; + } +} diff --git a/vp10/decoder/dsubexp.h b/vp10/decoder/dsubexp.h index c05ec6e9f490e5b6524bbe56e62f744db852ef40..eaccf1fb26620b3071d68865044a1de2067d8423 100644 --- a/vp10/decoder/dsubexp.h +++ b/vp10/decoder/dsubexp.h @@ -24,4 +24,9 @@ void vp10_diff_update_prob(vp10_reader *r, vpx_prob* p); } // extern "C" #endif +// mag_bits is number of bits for magnitude. The alphabet is of size +// 2 * 2^mag_bits + 1, symmetric around 0, where one bit is used to +// indicate 0 or non-zero, mag_bits bits are used to indicate magnitide +// and 1 more bit for the sign if non-zero. +int vp10_read_primitive_symmetric(vp10_reader *r, unsigned int mag_bits); #endif // VP10_DECODER_DSUBEXP_H_ diff --git a/vp10/encoder/bitstream.c b/vp10/encoder/bitstream.c index 3999c94609023a9deb369e403d4c01197a314214..9743367b17befdc203a87e7b3ffac4762587f92a 100644 --- a/vp10/encoder/bitstream.c +++ b/vp10/encoder/bitstream.c @@ -111,6 +111,9 @@ static struct vp10_token ext_tx_intra_encodings[EXT_TX_SETS_INTRA][TX_TYPES]; #else static struct vp10_token ext_tx_encodings[TX_TYPES]; #endif // CONFIG_EXT_TX +#if CONFIG_GLOBAL_MOTION +static struct vp10_token global_motion_types_encodings[GLOBAL_MOTION_TYPES]; +#endif // CONFIG_GLOBAL_MOTION #if CONFIG_EXT_INTRA static struct vp10_token intra_filter_encodings[INTRA_FILTERS]; #endif // CONFIG_EXT_INTRA @@ -142,6 +145,10 @@ void vp10_encode_token_init(void) { #if CONFIG_OBMC || CONFIG_WARPED_MOTION vp10_tokens_from_tree(motvar_encodings, vp10_motvar_tree); #endif // CONFIG_OBMC || CONFIG_WARPED_MOTION +#if CONFIG_GLOBAL_MOTION + vp10_tokens_from_tree(global_motion_types_encodings, + vp10_global_motion_types_tree); +#endif // CONFIG_GLOBAL_MOTION } static void write_intra_mode(vp10_writer *w, PREDICTION_MODE mode, @@ -3181,6 +3188,50 @@ static void write_uncompressed_header(VP10_COMP *cpi, write_tile_info(cm, wb); } +#if CONFIG_GLOBAL_MOTION +static void write_global_motion_params(Global_Motion_Params *params, + vpx_prob *probs, + vp10_writer *w) { + GLOBAL_MOTION_TYPE gmtype = get_gmtype(params); + vp10_write_token(w, vp10_global_motion_types_tree, probs, + &global_motion_types_encodings[gmtype]); + switch (gmtype) { + case GLOBAL_ZERO: + break; + case GLOBAL_TRANSLATION: + vp10_write_primitive_symmetric(w, params->motion_params.wmmat[0], + GM_ABS_TRANS_BITS); + vp10_write_primitive_symmetric(w, params->motion_params.wmmat[1], + GM_ABS_TRANS_BITS); + break; + case GLOBAL_ROTZOOM: + vp10_write_primitive_symmetric(w, params->motion_params.wmmat[0], + GM_ABS_TRANS_BITS); + vp10_write_primitive_symmetric(w, params->motion_params.wmmat[1], + GM_ABS_TRANS_BITS); + vp10_write_primitive_symmetric(w, params->motion_params.wmmat[2], + GM_ABS_ALPHA_BITS); + vp10_write_primitive_symmetric(w, params->motion_params.wmmat[3], + GM_ABS_ALPHA_BITS); + break; + default: + assert(0); + } +} + +static void write_global_motion(VP10_COMP *cpi, vp10_writer *w) { + VP10_COMMON *const cm = &cpi->common; + int frame; + for (frame = LAST_FRAME; frame <= ALTREF_FRAME; ++frame) { + if (!cpi->global_motion_used[frame]) { + memset(&cm->global_motion[frame], 0, + sizeof(*cm->global_motion)); + } + write_global_motion_params( + &cm->global_motion[frame], cm->fc->global_motion_types_prob, w); + } +} +#endif static uint32_t write_compressed_header(VP10_COMP *cpi, uint8_t *data) { VP10_COMMON *const cm = &cpi->common; @@ -3349,7 +3400,9 @@ static uint32_t write_compressed_header(VP10_COMP *cpi, uint8_t *data) { update_supertx_probs(cm, header_bc); #endif // CONFIG_SUPERTX } - +#if CONFIG_GLOBAL_MOTION + write_global_motion(cpi, header_bc); +#endif // CONFIG_GLOBAL_MOTION #if CONFIG_ANS ans_write_init(&header_ans, data); buf_ans_flush(header_bc, &header_ans); diff --git a/vp10/encoder/encodeframe.c b/vp10/encoder/encodeframe.c index 3119acf2842ca53ecdce37b3a016fdd9640e2ed8..b91615bf3e03b05966f4409153f35364d535af01 100644 --- a/vp10/encoder/encodeframe.c +++ b/vp10/encoder/encodeframe.c @@ -4536,6 +4536,78 @@ static int input_fpmb_stats(FIRSTPASS_MB_STATS *firstpass_mb_stats, } #endif +#if CONFIG_GLOBAL_MOTION +#define MIN_TRANS_THRESH 8 + +static void convert_translation_to_params( + double *H, Global_Motion_Params *model) { + 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); + 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; + } else { + model->motion_params.wmmat[0] = + clamp(model->motion_params.wmmat[0], + GM_TRANS_MIN, GM_TRANS_MAX); + model->motion_params.wmmat[1] = + clamp(model->motion_params.wmmat[1], + GM_TRANS_MIN, GM_TRANS_MAX); + } +} + +static void convert_rotzoom_to_params(double *H, Global_Motion_Params *model) { + 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); + model->motion_params.wmmat[1] = + clamp(model->motion_params.wmmat[1], + GM_TRANS_MIN, GM_TRANS_MAX); + + model->motion_params.wmmat[2] = (int) floor(H[2] * + (1 << GM_ALPHA_PREC_BITS) + 0.5) - + (1 << GM_ALPHA_PREC_BITS); + model->motion_params.wmmat[3] = (int) floor(H[3] * + (1 << GM_ALPHA_PREC_BITS) + 0.5); + + model->motion_params.wmmat[2] = clamp(model->motion_params.wmmat[2], + GM_ALPHA_MIN, GM_ALPHA_MAX); + model->motion_params.wmmat[3] = clamp(model->motion_params.wmmat[3], + GM_ALPHA_MIN, GM_ALPHA_MAX); + + if (model->motion_params.wmmat[2] == 0 && + model->motion_params.wmmat[3] == 0) { + 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; + } + } +} + +static void convert_model_to_params(double *H, TransformationType type, + Global_Motion_Params *model) { + switch (type) { + case ROTZOOM: + convert_rotzoom_to_params(H, model); + break; + case TRANSLATION: + convert_translation_to_params(H, model); + break; + default: + break; + } + model->gmtype = get_gmtype(model); +} +#endif // CONFIG_GLOBAL_MOTION + static void encode_frame_internal(VP10_COMP *cpi) { ThreadData *const td = &cpi->td; MACROBLOCK *const x = &td->mb; @@ -4556,6 +4628,18 @@ static void encode_frame_internal(VP10_COMP *cpi) { rdc->m_search_count = 0; // Count of motion search hits. rdc->ex_search_count = 0; // Exhaustive mesh search hits. +#if CONFIG_GLOBAL_MOTION + // TODO(sarahparker) this is a placeholder for gm computation + vpx_clear_system_state(); + vp10_zero(cpi->global_motion_used); + if (cpi->common.frame_type == INTER_FRAME && cpi->Source) { + int frame; + double H[9] = {0, 0, 0, 0, 0, 0, 0, 0, 1}; + for (frame = LAST_FRAME; frame <= ALTREF_FRAME; ++frame) + convert_model_to_params(H, ROTZOOM, &cm->global_motion[frame]); + } +#endif // CONFIG_GLOBAL_MOTION + for (i = 0; i < MAX_SEGMENTS; ++i) { const int qindex = cm->seg.enabled ? vp10_get_qindex(&cm->seg, i, cm->base_qindex) : cm->base_qindex; @@ -4569,7 +4653,6 @@ static void encode_frame_internal(VP10_COMP *cpi) { x->optimize = 0; cm->tx_mode = select_tx_mode(cpi, xd); - vp10_frame_init_quantizer(cpi); vp10_initialize_rd_consts(cpi); diff --git a/vp10/encoder/encoder.h b/vp10/encoder/encoder.h index d7c62b2588c59d5899c6ca44b809f8cebbe76384..5b07c39517de0eb0e9a7a7c753867e1265027dc3 100644 --- a/vp10/encoder/encoder.h +++ b/vp10/encoder/encoder.h @@ -615,6 +615,9 @@ typedef struct VP10_COMP { int refresh_frame_mask; int existing_fb_idx_to_show; #endif // CONFIG_EXT_REFS +#if CONFIG_GLOBAL_MOTION + int global_motion_used[MAX_REF_FRAMES]; +#endif } VP10_COMP; void vp10_initialize_enc(void); diff --git a/vp10/encoder/subexp.c b/vp10/encoder/subexp.c index 4aaffae7952d472363012a90af0d482c7b899c5c..3a2e09f2fec2a54a4e274a86854c54219602755c 100644 --- a/vp10/encoder/subexp.c +++ b/vp10/encoder/subexp.c @@ -286,3 +286,16 @@ int vp10_cond_prob_diff_update_savings(vpx_prob *oldp, upd); return savings; } + +void vp10_write_primitive_symmetric(vp10_writer *w, int word, + unsigned int abs_bits) { + if (word == 0) { + vp10_write_bit(w, 0); + } else { + const int x = abs(word); + const int s = word < 0; + vp10_write_bit(w, 1); + vp10_write_bit(w, s); + vp10_write_literal(w, x - 1, abs_bits); + } +} diff --git a/vp10/encoder/subexp.h b/vp10/encoder/subexp.h index 756b499e538d8e0187b390298d0ba9cee746fdcc..dbd48ff62e80f90159b3ffa5200672ac6390688c 100644 --- a/vp10/encoder/subexp.h +++ b/vp10/encoder/subexp.h @@ -50,6 +50,13 @@ int vp10_prob_update_search_model_subframe(unsigned int ct[ENTROPY_NODES] int stepsize, int n); #endif // CONFIG_ENTROPY +// +// mag_bits is number of bits for magnitude. The alphabet is of size +// 2 * 2^mag_bits + 1, symmetric around 0, where one bit is used to +// indicate 0 or non-zero, mag_bits bits are used to indicate magnitide +// and 1 more bit for the sign if non-zero. +void vp10_write_primitive_symmetric(vp10_writer *w, int word, + unsigned int mag_bits); #ifdef __cplusplus } // extern "C" #endif