From: Jingning Han Date: Wed, 2 Dec 2015 18:59:01 +0000 (-0800) Subject: Re-design motion compensated prediction mode entropy coding system X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1dc18077b8f7fa1aedc2deefe7079a3c64b952e6;p=libvpx Re-design motion compensated prediction mode entropy coding system This commit re-works the entropy coding scheme of the motion compensated prediction modes. It allows more flexible hyperplane partition for precise classification. Change-Id: Iba5035c76691946cf1386b6c495e399c3d9c8fc5 --- diff --git a/vp10/common/blockd.h b/vp10/common/blockd.h index f632836b3..8858d573f 100644 --- a/vp10/common/blockd.h +++ b/vp10/common/blockd.h @@ -133,8 +133,8 @@ typedef struct { int8_t angle_delta[2]; #endif // CONFIG_EXT_INTRA - // TODO(slavarnway): Delete and use bmi[3].as_mv[] instead. int_mv mv[2]; + int_mv pred_mv[2]; } MB_MODE_INFO; typedef struct MODE_INFO { diff --git a/vp10/common/entropymode.c b/vp10/common/entropymode.c index 4cc92496d..9f2c1108f 100644 --- a/vp10/common/entropymode.c +++ b/vp10/common/entropymode.c @@ -171,6 +171,20 @@ static const vpx_prob default_partition_probs[PARTITION_CONTEXTS] { 10, 7, 6 }, // a/l both split }; +#if CONFIG_REF_MV +static const vpx_prob default_newmv_prob[NEWMV_MODE_CONTEXTS] = { + 230, 190, 150, 110, 70, 30, +}; + +static const vpx_prob default_zeromv_prob[ZEROMV_MODE_CONTEXTS] = { + 192, 64, +}; + +static const vpx_prob default_refmv_prob[REFMV_MODE_CONTEXTS] = { + 180, 230, 128 +}; +#endif + static const vpx_prob default_inter_mode_probs[INTER_MODE_CONTEXTS] [INTER_MODES - 1] = { {2, 173, 34}, // 0 = both zero mv @@ -1184,6 +1198,11 @@ static void init_mode_probs(FRAME_CONTEXT *fc) { vp10_copy(fc->txfm_partition_prob, default_txfm_partition_probs); #endif vp10_copy(fc->skip_probs, default_skip_probs); +#if CONFIG_REF_MV + vp10_copy(fc->newmv_prob, default_newmv_prob); + vp10_copy(fc->zeromv_prob, default_zeromv_prob); + vp10_copy(fc->refmv_prob, default_refmv_prob); +#endif vp10_copy(fc->inter_mode_probs, default_inter_mode_probs); #if CONFIG_EXT_TX vp10_copy(fc->inter_ext_tx_prob, default_inter_ext_tx_prob); @@ -1232,9 +1251,21 @@ void vp10_adapt_inter_frame_probs(VP10_COMMON *cm) { fc->single_ref_prob[i][j] = mode_mv_merge_probs( pre_fc->single_ref_prob[i][j], counts->single_ref[i][j]); +#if CONFIG_REF_MV + for (i = 0; i < NEWMV_MODE_CONTEXTS; ++i) + fc->newmv_prob[i] = mode_mv_merge_probs(pre_fc->newmv_prob[i], + counts->newmv_mode[i]); + for (i = 0; i < ZEROMV_MODE_CONTEXTS; ++i) + fc->zeromv_prob[i] = mode_mv_merge_probs(pre_fc->zeromv_prob[i], + counts->zeromv_mode[i]); + for (i = 0; i < REFMV_MODE_CONTEXTS; ++i) + fc->refmv_prob[i] = mode_mv_merge_probs(pre_fc->refmv_prob[i], + counts->refmv_mode[i]); +#else for (i = 0; i < INTER_MODE_CONTEXTS; i++) vpx_tree_merge_probs(vp10_inter_mode_tree, pre_fc->inter_mode_probs[i], counts->inter_mode[i], fc->inter_mode_probs[i]); +#endif for (i = 0; i < BLOCK_SIZE_GROUPS; i++) vpx_tree_merge_probs(vp10_intra_mode_tree, pre_fc->y_mode_prob[i], diff --git a/vp10/common/entropymode.h b/vp10/common/entropymode.h index 52c3630fc..1cc583846 100644 --- a/vp10/common/entropymode.h +++ b/vp10/common/entropymode.h @@ -60,6 +60,13 @@ typedef struct frame_contexts { vp10_coeff_probs_model coef_probs[TX_SIZES][PLANE_TYPES]; vpx_prob switchable_interp_prob[SWITCHABLE_FILTER_CONTEXTS] [SWITCHABLE_FILTERS - 1]; + +#if CONFIG_REF_MV + vpx_prob newmv_prob[NEWMV_MODE_CONTEXTS]; + vpx_prob zeromv_prob[ZEROMV_MODE_CONTEXTS]; + vpx_prob refmv_prob[REFMV_MODE_CONTEXTS]; +#endif + vpx_prob inter_mode_probs[INTER_MODE_CONTEXTS][INTER_MODES - 1]; vpx_prob intra_inter_prob[INTRA_INTER_CONTEXTS]; vpx_prob comp_inter_prob[COMP_INTER_CONTEXTS]; @@ -93,6 +100,12 @@ typedef struct FRAME_COUNTS { [COEF_BANDS][COEFF_CONTEXTS]; unsigned int switchable_interp[SWITCHABLE_FILTER_CONTEXTS] [SWITCHABLE_FILTERS]; +#if CONFIG_REF_MV + unsigned int newmv_mode[NEWMV_MODE_CONTEXTS][2]; + unsigned int zeromv_mode[ZEROMV_MODE_CONTEXTS][2]; + unsigned int refmv_mode[REFMV_MODE_CONTEXTS][2]; +#endif + unsigned int inter_mode[INTER_MODE_CONTEXTS][INTER_MODES]; unsigned int intra_inter[INTRA_INTER_CONTEXTS][2]; unsigned int comp_inter[COMP_INTER_CONTEXTS][2]; diff --git a/vp10/common/enums.h b/vp10/common/enums.h index 593ff7fcf..b59531e4d 100644 --- a/vp10/common/enums.h +++ b/vp10/common/enums.h @@ -202,6 +202,19 @@ typedef enum { #define INTER_MODES (1 + NEWMV - NEARESTMV) #define SKIP_CONTEXTS 3 + +#if CONFIG_REF_MV +#define NEWMV_MODE_CONTEXTS 6 +#define ZEROMV_MODE_CONTEXTS 2 +#define REFMV_MODE_CONTEXTS 3 + +#define ZEROMV_OFFSET 3 +#define REFMV_OFFSET 4 + +#define NEWMV_CTX_MASK ((1 << ZEROMV_OFFSET) - 1) +#define ZEROMV_CTX_MASK ((1 << (REFMV_OFFSET - ZEROMV_OFFSET)) - 1) +#endif + #define INTER_MODE_CONTEXTS 7 /* Segment Feature Masks */ diff --git a/vp10/common/mvref_common.c b/vp10/common/mvref_common.c index aa134b4b3..074bc1600 100644 --- a/vp10/common/mvref_common.c +++ b/vp10/common/mvref_common.c @@ -12,14 +12,15 @@ #include "vp10/common/mvref_common.h" #if CONFIG_REF_MV -static void scan_row_mbmi(const VP10_COMMON *cm, const MACROBLOCKD *xd, - const int mi_row, const int mi_col, int block, - const MV_REFERENCE_FRAME ref_frame, - int row_offset, - CANDIDATE_MV *ref_mv_stack, - uint8_t *refmv_count) { +static uint8_t scan_row_mbmi(const VP10_COMMON *cm, const MACROBLOCKD *xd, + const int mi_row, const int mi_col, int block, + const MV_REFERENCE_FRAME ref_frame, + int row_offset, + CANDIDATE_MV *ref_mv_stack, + uint8_t *refmv_count) { const TileInfo *const tile = &xd->tile; int i; + uint8_t newmv_count = 0; for (i = 0; i < xd->n8_w && *refmv_count < MAX_REF_MV_STACK_SIZE;) { POSITION mi_pos; @@ -51,6 +52,9 @@ static void scan_row_mbmi(const VP10_COMMON *cm, const MACROBLOCKD *xd, ref_mv_stack[index].this_mv = this_refmv; ref_mv_stack[index].weight = weight; ++(*refmv_count); + + if (candidate->mode == NEWMV) + ++newmv_count; } } } @@ -59,16 +63,19 @@ static void scan_row_mbmi(const VP10_COMMON *cm, const MACROBLOCKD *xd, ++i; } } + + return newmv_count; } -static void scan_col_mbmi(const VP10_COMMON *cm, const MACROBLOCKD *xd, - const int mi_row, const int mi_col, int block, - const MV_REFERENCE_FRAME ref_frame, - int col_offset, - CANDIDATE_MV *ref_mv_stack, - uint8_t *refmv_count) { +static uint8_t scan_col_mbmi(const VP10_COMMON *cm, const MACROBLOCKD *xd, + const int mi_row, const int mi_col, int block, + const MV_REFERENCE_FRAME ref_frame, + int col_offset, + CANDIDATE_MV *ref_mv_stack, + uint8_t *refmv_count) { const TileInfo *const tile = &xd->tile; int i; + uint8_t newmv_count = 0; for (i = 0; i < xd->n8_h && *refmv_count < MAX_REF_MV_STACK_SIZE;) { POSITION mi_pos; @@ -99,25 +106,30 @@ static void scan_col_mbmi(const VP10_COMMON *cm, const MACROBLOCKD *xd, ref_mv_stack[index].this_mv = this_refmv; ref_mv_stack[index].weight = weight; ++(*refmv_count); + + if (candidate->mode == NEWMV) + ++newmv_count; } } } - i += len; } else { ++i; } } + + return newmv_count; } -static void scan_blk_mbmi(const VP10_COMMON *cm, const MACROBLOCKD *xd, - const int mi_row, const int mi_col, int block, - const MV_REFERENCE_FRAME ref_frame, - int row_offset, int col_offset, - CANDIDATE_MV *ref_mv_stack, - uint8_t *refmv_count) { +static uint8_t scan_blk_mbmi(const VP10_COMMON *cm, const MACROBLOCKD *xd, + const int mi_row, const int mi_col, int block, + const MV_REFERENCE_FRAME ref_frame, + int row_offset, int col_offset, + CANDIDATE_MV *ref_mv_stack, + uint8_t *refmv_count) { const TileInfo *const tile = &xd->tile; POSITION mi_pos; + uint8_t newmv_count = 0; mi_pos.row = row_offset; mi_pos.col = col_offset; @@ -146,6 +158,9 @@ static void scan_blk_mbmi(const VP10_COMMON *cm, const MACROBLOCKD *xd, ref_mv_stack[index].this_mv = this_refmv; ref_mv_stack[index].weight = weight; ++(*refmv_count); + + if (candidate->mode == NEWMV) + ++newmv_count; } if (candidate_mi->mbmi.sb_type < BLOCK_8X8 && block >= 0) { @@ -169,6 +184,7 @@ static void scan_blk_mbmi(const VP10_COMMON *cm, const MACROBLOCKD *xd, } } } // Analyze a single 8x8 block motion information. + return newmv_count; } static int has_top_right(const MACROBLOCKD *xd, @@ -215,55 +231,102 @@ static void setup_ref_mv_list(const VP10_COMMON *cm, const MACROBLOCKD *xd, int block, int mi_row, int mi_col, uint8_t *mode_context) { int idx, nearest_refmv_count = 0; + uint8_t newmv_count = 0; CANDIDATE_MV tmp_mv; int len, nr_len; - const MV_REF *const prev_frame_mvs = cm->use_prev_frame_mvs ? + const MV_REF *const prev_frame_mvs_base = cm->use_prev_frame_mvs ? cm->prev_frame->mvs + mi_row * cm->mi_cols + mi_col : NULL; int bs = VPXMAX(xd->n8_w, xd->n8_h); int has_tr = has_top_right(xd, mi_row, mi_col, bs); - (void) mode_context; - *refmv_count = 0; // Scan the first above row mode info. - scan_row_mbmi(cm, xd, mi_row, mi_col, block, ref_frame, - -1, ref_mv_stack, refmv_count); + newmv_count = scan_row_mbmi(cm, xd, mi_row, mi_col, block, ref_frame, + -1, ref_mv_stack, refmv_count); // Scan the first left column mode info. - scan_col_mbmi(cm, xd, mi_row, mi_col, block, ref_frame, - -1, ref_mv_stack, refmv_count); + newmv_count += scan_col_mbmi(cm, xd, mi_row, mi_col, block, ref_frame, + -1, ref_mv_stack, refmv_count); // Check top-right boundary if (has_tr) - scan_blk_mbmi(cm, xd, mi_row, mi_col, block, ref_frame, - -1, 1, ref_mv_stack, refmv_count); + newmv_count += scan_blk_mbmi(cm, xd, mi_row, mi_col, block, ref_frame, + -1, 1, ref_mv_stack, refmv_count); nearest_refmv_count = *refmv_count; - if (prev_frame_mvs && cm->show_frame && cm->last_show_frame) { - int ref; - for (ref = 0; ref < 2; ++ref) { - if (prev_frame_mvs->ref_frame[ref] == ref_frame) { - for (idx = 0; idx < nearest_refmv_count; ++idx) - if (prev_frame_mvs->mv[ref].as_int == - ref_mv_stack[idx].this_mv.as_int) - break; + mode_context[ref_frame] = 0; + switch (nearest_refmv_count) { + case 0: + mode_context[ref_frame] = 0; + break; - if (idx == nearest_refmv_count && - nearest_refmv_count < MAX_REF_MV_STACK_SIZE) { - ref_mv_stack[idx].this_mv.as_int = prev_frame_mvs->mv[ref].as_int; - ref_mv_stack[idx].weight = 1; - ++(*refmv_count); - ++nearest_refmv_count; + case 1: + mode_context[ref_frame] = (newmv_count > 0) ? 1 : 2; + mode_context[ref_frame] += (1 << REFMV_OFFSET); + break; + + case 2: + default: + if (newmv_count >= 2) + mode_context[ref_frame] = 3; + else if (newmv_count == 1) + mode_context[ref_frame] = 4; + else + mode_context[ref_frame] = 5; + mode_context[ref_frame] += (2 << REFMV_OFFSET); + break; + } + + if (prev_frame_mvs_base && cm->show_frame && cm->last_show_frame) { + int ref; + int blk_row, blk_col; + + for (blk_row = 0; blk_row < xd->n8_h; ++blk_row) { + for (blk_col = 0; blk_col < xd->n8_w; ++blk_col) { + const MV_REF *prev_frame_mvs = + prev_frame_mvs_base + blk_row * cm->mi_cols + blk_col; + + POSITION mi_pos; + mi_pos.row = blk_row; + mi_pos.col = blk_col; + + if (!is_inside(&xd->tile, mi_col, mi_row, cm->mi_rows, &mi_pos)) + continue; + + for (ref = 0; ref < 2; ++ref) { + if (prev_frame_mvs->ref_frame[ref] == ref_frame) { + for (idx = 0; idx < *refmv_count; ++idx) + if (prev_frame_mvs->mv[ref].as_int == + ref_mv_stack[idx].this_mv.as_int) + break; + + if (idx < *refmv_count) + ref_mv_stack[idx].weight += 1; + + if (idx == *refmv_count && + *refmv_count < MAX_REF_MV_STACK_SIZE) { + ref_mv_stack[idx].this_mv.as_int = prev_frame_mvs->mv[ref].as_int; + ref_mv_stack[idx].weight = 1; + ++(*refmv_count); + + if (abs(ref_mv_stack[idx].this_mv.as_mv.row) >= 8 || + abs(ref_mv_stack[idx].this_mv.as_mv.col) >= 8) + mode_context[ref_frame] |= (1 << ZEROMV_OFFSET); + } + } } } } } + if (*refmv_count == nearest_refmv_count) + mode_context[ref_frame] |= (1 << ZEROMV_OFFSET); + // Analyze the top-left corner block mode info. // scan_blk_mbmi(cm, xd, mi_row, mi_col, block, ref_frame, // -1, -1, ref_mv_stack, refmv_count); @@ -519,7 +582,6 @@ void vp10_append_sub8x8_mvs_for_idx(VP10_COMMON *cm, MACROBLOCKD *xd, find_mv_refs_idx(cm, xd, mi, mi->mbmi.ref_frame[ref], mv_list, block, mi_row, mi_col, NULL, NULL, NULL); - #if CONFIG_REF_MV scan_blk_mbmi(cm, xd, mi_row, mi_col, block, mi->mbmi.ref_frame[ref], -1, 0, ref_mv_stack, &ref_mv_count); diff --git a/vp10/common/thread_common.c b/vp10/common/thread_common.c index b504649f6..d2fbccd90 100644 --- a/vp10/common/thread_common.c +++ b/vp10/common/thread_common.c @@ -366,6 +366,20 @@ void vp10_accumulate_frame_counts(VP10_COMMON *cm, FRAME_COUNTS *counts, for (j = 0; j < SWITCHABLE_FILTERS; j++) cm->counts.switchable_interp[i][j] += counts->switchable_interp[i][j]; +#if CONFIG_REF_MV + for (i = 0; i < NEWMV_MODE_CONTEXTS; ++i) + for (j = 0; j < 2; ++j) + cm->counts.newmv_mode[i][j] += counts->newmv_mode[i][j]; + + for (i = 0; i < ZEROMV_MODE_CONTEXTS; ++i) + for (j = 0; j < 2; ++j) + cm->counts.zeromv_mode[i][j] += counts->zeromv_mode[i][j]; + + for (i = 0; i < REFMV_MODE_CONTEXTS; ++i) + for (j = 0; j < 2; ++j) + cm->counts.refmv_mode[i][j] += counts->refmv_mode[i][j]; +#endif + for (i = 0; i < INTER_MODE_CONTEXTS; i++) for (j = 0; j < INTER_MODES; j++) cm->counts.inter_mode[i][j] += counts->inter_mode[i][j]; diff --git a/vp10/decoder/decodeframe.c b/vp10/decoder/decodeframe.c index 5a00bc474..ced0b868b 100644 --- a/vp10/decoder/decodeframe.c +++ b/vp10/decoder/decodeframe.c @@ -124,10 +124,20 @@ static void read_switchable_interp_probs(FRAME_CONTEXT *fc, vpx_reader *r) { } static void read_inter_mode_probs(FRAME_CONTEXT *fc, vpx_reader *r) { - int i, j; + int i; +#if CONFIG_REF_MV + for (i = 0; i < NEWMV_MODE_CONTEXTS; ++i) + vp10_diff_update_prob(r, &fc->newmv_prob[i]); + for (i = 0; i < ZEROMV_MODE_CONTEXTS; ++i) + vp10_diff_update_prob(r, &fc->zeromv_prob[i]); + for (i = 0; i < REFMV_MODE_CONTEXTS; ++i) + vp10_diff_update_prob(r, &fc->refmv_prob[i]); +#else + int j; for (i = 0; i < INTER_MODE_CONTEXTS; ++i) for (j = 0; j < INTER_MODES - 1; ++j) vp10_diff_update_prob(r, &fc->inter_mode_probs[i][j]); +#endif } static REFERENCE_MODE read_frame_reference_mode(const VP10_COMMON *cm, diff --git a/vp10/decoder/decodemv.c b/vp10/decoder/decodemv.c index fc0989126..abb2217d0 100644 --- a/vp10/decoder/decodemv.c +++ b/vp10/decoder/decodemv.c @@ -63,7 +63,49 @@ static PREDICTION_MODE read_intra_mode_uv(VP10_COMMON *cm, MACROBLOCKD *xd, } static PREDICTION_MODE read_inter_mode(VP10_COMMON *cm, MACROBLOCKD *xd, - vpx_reader *r, int ctx) { + vpx_reader *r, uint8_t ctx) { +#if CONFIG_REF_MV + FRAME_COUNTS *counts = xd->counts; + uint8_t mode_ctx = ctx & NEWMV_CTX_MASK; + vpx_prob mode_prob = cm->fc->newmv_prob[mode_ctx]; + + if (vpx_read(r, mode_prob) == 0) { + if (counts) + ++counts->newmv_mode[mode_ctx][0]; + return NEWMV; + } + if (counts) + ++counts->newmv_mode[mode_ctx][1]; + + mode_ctx = (ctx >> ZEROMV_OFFSET) & ZEROMV_CTX_MASK; + + if (mode_ctx > 1) + assert(0); + + mode_prob = cm->fc->zeromv_prob[mode_ctx]; + if (vpx_read(r, mode_prob) == 0) { + if (counts) + ++counts->zeromv_mode[mode_ctx][0]; + return ZEROMV; + } + if (counts) + ++counts->zeromv_mode[mode_ctx][1]; + + mode_ctx = (ctx >> REFMV_OFFSET); + mode_prob = cm->fc->refmv_prob[mode_ctx]; + if (vpx_read(r, mode_prob) == 0) { + if (counts) + ++counts->refmv_mode[mode_ctx][0]; + return NEARESTMV; + } else { + if (counts) + ++counts->refmv_mode[mode_ctx][1]; + return NEARMV; + } + + // Invalid prediction mode. + assert(0); +#else const int mode = vpx_read_tree(r, vp10_inter_mode_tree, cm->fc->inter_mode_probs[ctx]); FRAME_COUNTS *counts = xd->counts; @@ -71,6 +113,7 @@ static PREDICTION_MODE read_inter_mode(VP10_COMMON *cm, MACROBLOCKD *xd, ++counts->inter_mode[ctx][mode]; return NEARESTMV + mode; +#endif } static int read_segment_id(vpx_reader *r, diff --git a/vp10/encoder/bitstream.c b/vp10/encoder/bitstream.c index b60fd96e3..2bac77dcb 100644 --- a/vp10/encoder/bitstream.c +++ b/vp10/encoder/bitstream.c @@ -47,8 +47,10 @@ static const struct vp10_token switchable_interp_encodings[SWITCHABLE_FILTERS] = #endif // CONFIG_EXT_INTERP && SWITCHABLE_FILTERS == 4 static const struct vp10_token partition_encodings[PARTITION_TYPES] = {{0, 1}, {2, 2}, {6, 3}, {7, 3}}; +#if !CONFIG_REF_MV static const struct vp10_token inter_mode_encodings[INTER_MODES] = {{2, 2}, {6, 3}, {0, 1}, {7, 3}}; +#endif static const struct vp10_token palette_size_encodings[] = { {0, 1}, {2, 2}, {6, 3}, {14, 4}, {30, 5}, {62, 6}, {63, 6}, }; @@ -99,11 +101,31 @@ static void write_intra_mode(vpx_writer *w, PREDICTION_MODE mode, vp10_write_token(w, vp10_intra_mode_tree, probs, &intra_mode_encodings[mode]); } -static void write_inter_mode(vpx_writer *w, PREDICTION_MODE mode, - const vpx_prob *probs) { +static void write_inter_mode(VP10_COMMON *cm, + vpx_writer *w, PREDICTION_MODE mode, + const uint8_t mode_ctx) { +#if CONFIG_REF_MV + const uint8_t newmv_ctx = mode_ctx & NEWMV_CTX_MASK; + const vpx_prob newmv_prob = cm->fc->newmv_prob[newmv_ctx]; + vpx_write(w, mode != NEWMV, newmv_prob); + + if (mode != NEWMV) { + const uint8_t zeromv_ctx = (mode_ctx >> ZEROMV_OFFSET) & ZEROMV_CTX_MASK; + const vpx_prob zeromv_prob = cm->fc->zeromv_prob[zeromv_ctx]; + vpx_write(w, mode != ZEROMV, zeromv_prob); + + if (mode != ZEROMV) { + const uint8_t refmv_ctx = (mode_ctx >> REFMV_OFFSET); + const vpx_prob refmv_prob = cm->fc->refmv_prob[refmv_ctx]; + vpx_write(w, mode != NEARESTMV, refmv_prob); + } + } +#else + const vpx_prob *const inter_probs = cm->fc->inter_mode_probs[mode_ctx]; assert(is_inter_mode(mode)); - vp10_write_token(w, vp10_inter_mode_tree, probs, + vp10_write_token(w, vp10_inter_mode_tree, inter_probs, &inter_mode_encodings[INTER_OFFSET(mode)]); +#endif } static void encode_unsigned_max(struct vpx_write_bit_buffer *wb, @@ -215,6 +237,22 @@ static void write_selected_tx_size(const VP10_COMMON *cm, } } +#if CONFIG_REF_MV +static void update_inter_mode_probs(VP10_COMMON *cm, vpx_writer *w, + FRAME_COUNTS *counts) { + int i; + for (i = 0; i < NEWMV_MODE_CONTEXTS; ++i) + vp10_cond_prob_diff_update(w, &cm->fc->newmv_prob[i], + counts->newmv_mode[i]); + for (i = 0; i < ZEROMV_MODE_CONTEXTS; ++i) + vp10_cond_prob_diff_update(w, &cm->fc->zeromv_prob[i], + counts->zeromv_mode[i]); + for (i = 0; i < REFMV_MODE_CONTEXTS; ++i) + vp10_cond_prob_diff_update(w, &cm->fc->refmv_prob[i], + counts->refmv_mode[i]); +} +#endif + static int write_skip(const VP10_COMMON *cm, const MACROBLOCKD *xd, int segment_id, const MODE_INFO *mi, vpx_writer *w) { if (segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP)) { @@ -677,13 +715,12 @@ static void pack_inter_mode_mvs(VP10_COMP *cpi, const MODE_INFO *mi, #endif // CONFIG_EXT_INTRA } else { const int mode_ctx = mbmi_ext->mode_context[mbmi->ref_frame[0]]; - const vpx_prob *const inter_probs = cm->fc->inter_mode_probs[mode_ctx]; write_ref_frames(cm, xd, w); // If segment skip is not enabled code the mode. if (!segfeature_active(seg, segment_id, SEG_LVL_SKIP)) { if (bsize >= BLOCK_8X8) { - write_inter_mode(w, mode, inter_probs); + write_inter_mode(cm, w, mode, mode_ctx); } } @@ -699,7 +736,7 @@ static void pack_inter_mode_mvs(VP10_COMP *cpi, const MODE_INFO *mi, for (idx = 0; idx < 2; idx += num_4x4_w) { const int j = idy * 2 + idx; const PREDICTION_MODE b_mode = mi->bmi[j].as_mode; - write_inter_mode(w, b_mode, inter_probs); + write_inter_mode(cm, w, b_mode, mode_ctx); if (b_mode == NEWMV) { for (ref = 0; ref < 1 + is_compound; ++ref) vp10_encode_mv(cpi, w, &mi->bmi[j].as_mv[ref].as_mv, @@ -1749,9 +1786,13 @@ static size_t write_compressed_header(VP10_COMP *cpi, uint8_t *data) { prob_diff_update(vp10_intra_mode_tree, cm->kf_y_prob[i][j], counts->kf_y_mode[i][j], INTRA_MODES, &header_bc); } else { +#if CONFIG_REF_MV + update_inter_mode_probs(cm, &header_bc, counts); +#else for (i = 0; i < INTER_MODE_CONTEXTS; ++i) prob_diff_update(vp10_inter_mode_tree, cm->fc->inter_mode_probs[i], counts->inter_mode[i], INTER_MODES, &header_bc); +#endif if (cm->interp_filter == SWITCHABLE) update_switchable_interp_probs(cm, &header_bc, counts); diff --git a/vp10/encoder/encodeframe.c b/vp10/encoder/encodeframe.c index c57b224b7..34eac8912 100644 --- a/vp10/encoder/encodeframe.c +++ b/vp10/encoder/encodeframe.c @@ -1257,6 +1257,29 @@ static void rd_pick_sb_modes(VP10_COMP *cpi, ctx->dist = rd_cost->dist; } +#if CONFIG_REF_MV +static void update_inter_mode_stats(FRAME_COUNTS *counts, + PREDICTION_MODE mode, + uint8_t mode_context) { + uint8_t mode_ctx = mode_context & NEWMV_CTX_MASK; + if (mode == NEWMV) { + ++counts->newmv_mode[mode_ctx][0]; + return; + } else { + ++counts->newmv_mode[mode_ctx][1]; + mode_ctx = (mode_context >> ZEROMV_OFFSET) & ZEROMV_CTX_MASK; + if (mode == ZEROMV) { + ++counts->zeromv_mode[mode_ctx][0]; + return; + } else { + ++counts->zeromv_mode[mode_ctx][1]; + mode_ctx = (mode_context >> REFMV_OFFSET); + ++counts->refmv_mode[mode_ctx][mode != NEARESTMV]; + } + } +} +#endif + static void update_stats(VP10_COMMON *cm, ThreadData *td) { const MACROBLOCK *x = &td->mb; const MACROBLOCKD *const xd = &x->e_mbd; @@ -1335,7 +1358,11 @@ static void update_stats(VP10_COMMON *cm, ThreadData *td) { const int mode_ctx = mbmi_ext->mode_context[mbmi->ref_frame[0]]; if (bsize >= BLOCK_8X8) { const PREDICTION_MODE mode = mbmi->mode; +#if CONFIG_REF_MV + update_inter_mode_stats(counts, mode, mode_ctx); +#else ++counts->inter_mode[mode_ctx][INTER_OFFSET(mode)]; +#endif } else { const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize]; const int num_4x4_h = num_4x4_blocks_high_lookup[bsize]; @@ -1344,7 +1371,11 @@ static void update_stats(VP10_COMMON *cm, ThreadData *td) { for (idx = 0; idx < 2; idx += num_4x4_w) { const int j = idy * 2 + idx; const PREDICTION_MODE b_mode = mi->bmi[j].as_mode; +#if CONFIG_REF_MV + update_inter_mode_stats(counts, b_mode, mode_ctx); +#else ++counts->inter_mode[mode_ctx][INTER_OFFSET(b_mode)]; +#endif } } } diff --git a/vp10/encoder/encoder.h b/vp10/encoder/encoder.h index 7b380005f..7a879e2a3 100644 --- a/vp10/encoder/encoder.h +++ b/vp10/encoder/encoder.h @@ -466,6 +466,12 @@ typedef struct VP10_COMP { search_site_config ss_cfg; int mbmode_cost[INTRA_MODES]; +#if CONFIG_REF_MV + int newmv_mode_cost[NEWMV_MODE_CONTEXTS][2]; + int zeromv_mode_cost[ZEROMV_MODE_CONTEXTS][2]; + int refmv_mode_cost[REFMV_MODE_CONTEXTS][2]; +#endif + unsigned int inter_mode_cost[INTER_MODE_CONTEXTS][INTER_MODES]; int intra_uv_mode_cost[INTRA_MODES][INTRA_MODES]; int y_mode_costs[INTRA_MODES][INTRA_MODES][INTRA_MODES]; diff --git a/vp10/encoder/rd.c b/vp10/encoder/rd.c index 34606be55..6d6f13b60 100644 --- a/vp10/encoder/rd.c +++ b/vp10/encoder/rd.c @@ -338,10 +338,26 @@ void vp10_initialize_rd_consts(VP10_COMP *cpi) { cm->allow_high_precision_mv ? x->nmvcost_hp : x->nmvcost, &cm->fc->nmvc, cm->allow_high_precision_mv); +#if CONFIG_REF_MV + for (i = 0; i < NEWMV_MODE_CONTEXTS; ++i) { + cpi->newmv_mode_cost[i][0] = vp10_cost_bit(cm->fc->newmv_prob[i], 0); + cpi->newmv_mode_cost[i][1] = vp10_cost_bit(cm->fc->newmv_prob[i], 1); + } + + for (i = 0; i < ZEROMV_MODE_CONTEXTS; ++i) { + cpi->zeromv_mode_cost[i][0] = vp10_cost_bit(cm->fc->zeromv_prob[i], 0); + cpi->zeromv_mode_cost[i][1] = vp10_cost_bit(cm->fc->zeromv_prob[i], 1); + } + for (i = 0; i < REFMV_MODE_CONTEXTS; ++i) { + cpi->refmv_mode_cost[i][0] = vp10_cost_bit(cm->fc->refmv_prob[i], 0); + cpi->refmv_mode_cost[i][1] = vp10_cost_bit(cm->fc->refmv_prob[i], 1); + } +#else for (i = 0; i < INTER_MODE_CONTEXTS; ++i) vp10_cost_tokens((int *)cpi->inter_mode_cost[i], cm->fc->inter_mode_probs[i], vp10_inter_mode_tree); +#endif } } diff --git a/vp10/encoder/rdopt.c b/vp10/encoder/rdopt.c index 1e5b128c7..813e13e0b 100644 --- a/vp10/encoder/rdopt.c +++ b/vp10/encoder/rdopt.c @@ -3025,9 +3025,33 @@ static void choose_intra_uv_mode(VP10_COMP *cpi, MACROBLOCK *const x, } static int cost_mv_ref(const VP10_COMP *cpi, PREDICTION_MODE mode, - int mode_context) { + uint8_t mode_context) { +#if CONFIG_REF_MV + int mode_cost = 0; + uint8_t mode_ctx = mode_context & NEWMV_CTX_MASK; + + assert(is_inter_mode(mode)); + + if (mode == NEWMV) { + mode_cost = cpi->newmv_mode_cost[mode_ctx][0]; + return mode_cost; + } else { + mode_cost = cpi->newmv_mode_cost[mode_ctx][1]; + mode_ctx = (mode_context >> ZEROMV_OFFSET) & ZEROMV_CTX_MASK; + if (mode == ZEROMV) { + mode_cost += cpi->zeromv_mode_cost[mode_ctx][0]; + return mode_cost; + } else { + mode_cost += cpi->zeromv_mode_cost[mode_ctx][1]; + mode_ctx = (mode_context >> REFMV_OFFSET); + mode_cost += cpi->refmv_mode_cost[mode_ctx][mode != NEARESTMV]; + return mode_cost; + } + } +#else assert(is_inter_mode(mode)); return cpi->inter_mode_cost[mode_context][INTER_OFFSET(mode)]; +#endif } static int set_and_cost_bmi_mvs(VP10_COMP *cpi, MACROBLOCK *x, MACROBLOCKD *xd,