Commit 5fa46c0b authored by Sarah Parker's avatar Sarah Parker Committed by sarahparker

Add global motion parameters to compressed header

Currently nothing is implemented to compute GM parameters, this
just adds the capability to send them in the bitstream if they
were computed. Still need to implement the reconstruction
based on the parameters in reconinter.

Change-Id: I72aea3c6a9de9f5a40f96da76c82b54a52781fe2
parent 681ba364
......@@ -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,
......
......@@ -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 {
......
......@@ -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
}
......@@ -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
......
......@@ -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;
......
......@@ -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
......
......@@ -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
......
......@@ -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;
}
}
......@@ -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_
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
}
}
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment