From 76feb965d3340cfe38a06ee017ff02e4a493cecf Mon Sep 17 00:00:00 2001 From: Yaowu Xu Date: Tue, 6 Dec 2011 12:03:42 -0800 Subject: [PATCH] made vp8_mode_context adaptive vp8_mode_contexts[] is an entropy table used to code inter mode choices. It was a fixed constant table. This commit made the entropy context adaptive. Tests on derf set showed very good consistent gains on all metrics: avg psnr .47%, overall psnr .46% and ssim .40%. http://www.corp.google.com/~yaowu/no_crawl/newModeContext.html Change-Id: Ia62b14485c948e2b74586118619c5eb2068b43b2 --- vp8/common/alloccommon.c | 7 +++ vp8/common/entropymode.c | 100 +++++++++++++++++++++++++++++++++++++++ vp8/common/findnearmv.c | 10 ++-- vp8/common/findnearmv.h | 3 +- vp8/common/modecont.c | 2 +- vp8/common/modecont.h | 2 +- vp8/common/onyxc_int.h | 7 +++ vp8/decoder/decodemv.c | 6 ++- vp8/decoder/decodframe.c | 29 +++++++++++- vp8/encoder/bitstream.c | 31 +++++++++++- vp8/encoder/mcomp.c | 32 +++---------- vp8/encoder/pickinter.c | 5 +- vp8/encoder/ratectrl.c | 3 ++ vp8/encoder/rdopt.c | 12 +++-- 14 files changed, 204 insertions(+), 45 deletions(-) diff --git a/vp8/common/alloccommon.c b/vp8/common/alloccommon.c index 61bb31777..0c7a9ef8d 100644 --- a/vp8/common/alloccommon.c +++ b/vp8/common/alloccommon.c @@ -190,6 +190,13 @@ void vp8_create_common(VP8_COMMON *oci) vp8_machine_specific_config(oci); vp8_init_mbmode_probs(oci); +#if CONFIG_NEWNEAR + vp8_init_mv_ref_counts(oci); +#endif + vpx_memcpy( oci->vp8_mode_contexts, + default_vp8_mode_contexts, + sizeof(default_vp8_mode_contexts)); + vp8_default_bmode_probs(oci->fc.bmode_prob); oci->mb_no_coeff_skip = 1; diff --git a/vp8/common/entropymode.c b/vp8/common/entropymode.c index 8b9934461..15fbc41b6 100644 --- a/vp8/common/entropymode.c +++ b/vp8/common/entropymode.c @@ -385,3 +385,103 @@ void vp8_entropy_mode_init() vp8_tokens_from_tree(vp8_small_mvencodings, vp8_small_mvtree); } + +#if CONFIG_NEWNEAR +void vp8_init_mv_ref_counts(VP8_COMMON *pc) +{ + vpx_memset(pc->mv_ref_ct, 0, sizeof(pc->mv_ref_ct)); +} + +void vp8_accum_mv_refs(VP8_COMMON *pc, + MB_PREDICTION_MODE m, + const int ct[4]) +{ + if (m == ZEROMV) + { + ++pc->mv_ref_ct [ct[0]] [0] [0]; + } + else + { + ++pc->mv_ref_ct [ct[0]] [0] [1]; + if (m == NEARESTMV) + { + ++pc->mv_ref_ct [ct[1]] [1] [0]; + } + else + { + ++pc->mv_ref_ct [ct[1]] [1] [1]; + if (m == NEARMV) + { + ++pc->mv_ref_ct [ct[2]] [2] [0]; + } + else + { + ++pc->mv_ref_ct [ct[2]] [2] [1]; + if (m == NEWMV) + { + ++pc->mv_ref_ct [ct[3]] [3] [0]; + } + else + { + ++pc->mv_ref_ct [ct[3]] [3] [1]; + } + } + } + } +} + +void vp8_update_mode_context(VP8_COMMON *pc) +{ + int i, j; + for (j = 0; j < 6; j++) + { + for (i = 0; i < 4; i++) + { + int this_prob; + int count; + // context probs + count = pc->mv_ref_ct[j][i][0] + pc->mv_ref_ct[j][i][1]; + if (count) + this_prob = 256 * pc->mv_ref_ct[j][i][0] / count; + else + this_prob = 128; + if (this_prob == 0) + this_prob = 1; + if (this_prob == 256) + this_prob = 255; + + pc->mode_context[j][i] = this_prob; + } + } +} +#include "vp8/common/modecont.h" +void print_mode_contexts(VP8_COMMON *pc) +{ + int j, i; + for(j=0; j<6; j++) + { + for (i = 0; i < 4; i++) + { + printf( "%4d ", pc->vp8_mode_contexts[j][i]); + } + printf("\n"); + } +} +void print_mv_ref_cts(VP8_COMMON *pc) +{ + int j, i; + for(j=0; j<6; j++) + { + for (i = 0; i < 4; i++) + { + printf("(%4d:%4d) ", + pc->mv_ref_ct[j][i][0], + pc->mv_ref_ct[j][i][1]); + } + printf("\n"); + } +} + + +#endif + diff --git a/vp8/common/findnearmv.c b/vp8/common/findnearmv.c index 23a28a7bd..aace856b1 100644 --- a/vp8/common/findnearmv.c +++ b/vp8/common/findnearmv.c @@ -278,14 +278,14 @@ void vp8_find_near_mvs } #endif -vp8_prob *vp8_mv_ref_probs( +vp8_prob *vp8_mv_ref_probs(VP8_COMMON *pc, vp8_prob p[VP8_MVREFS-1], const int near_mv_ref_ct[4] ) { - p[0] = vp8_mode_contexts [near_mv_ref_ct[0]] [0]; - p[1] = vp8_mode_contexts [near_mv_ref_ct[1]] [1]; - p[2] = vp8_mode_contexts [near_mv_ref_ct[2]] [2]; - p[3] = vp8_mode_contexts [near_mv_ref_ct[3]] [3]; + p[0] = pc->vp8_mode_contexts [near_mv_ref_ct[0]] [0]; + p[1] = pc->vp8_mode_contexts [near_mv_ref_ct[1]] [1]; + p[2] = pc->vp8_mode_contexts [near_mv_ref_ct[2]] [2]; + p[3] = pc->vp8_mode_contexts [near_mv_ref_ct[3]] [3]; return p; } diff --git a/vp8/common/findnearmv.h b/vp8/common/findnearmv.h index b07a54b5c..b26f9873b 100644 --- a/vp8/common/findnearmv.h +++ b/vp8/common/findnearmv.h @@ -16,6 +16,7 @@ #include "blockd.h" #include "modecont.h" #include "treecoder.h" +#include "onyxc_int.h" static void mv_bias(int refmb_ref_frame_sign_bias, int refframe, int_mv *mvp, const int *ref_frame_sign_bias) @@ -84,7 +85,7 @@ void vp8_find_near_mvs int *ref_frame_sign_bias ); -vp8_prob *vp8_mv_ref_probs( +vp8_prob *vp8_mv_ref_probs(VP8_COMMON *pc, vp8_prob p[VP8_MVREFS-1], const int near_mv_ref_ct[4] ); diff --git a/vp8/common/modecont.c b/vp8/common/modecont.c index 86a74bc0f..d7491f241 100644 --- a/vp8/common/modecont.c +++ b/vp8/common/modecont.c @@ -11,7 +11,7 @@ #include "entropy.h" -const int vp8_mode_contexts[6][4] = +const int default_vp8_mode_contexts[6][4] = { { /* 0 */ diff --git a/vp8/common/modecont.h b/vp8/common/modecont.h index 24db88295..476ae3fa9 100644 --- a/vp8/common/modecont.h +++ b/vp8/common/modecont.h @@ -12,6 +12,6 @@ #ifndef __INC_MODECONT_H #define __INC_MODECONT_H -extern const int vp8_mode_contexts[6][4]; +extern const int default_vp8_mode_contexts[6][4]; #endif diff --git a/vp8/common/onyxc_int.h b/vp8/common/onyxc_int.h index 08fc79501..04f8507d6 100644 --- a/vp8/common/onyxc_int.h +++ b/vp8/common/onyxc_int.h @@ -218,6 +218,13 @@ typedef struct VP8Common FRAME_CONTEXT lfc; /* last frame entropy */ FRAME_CONTEXT fc; /* this frame entropy */ +#if CONFIG_NEWNEAR + int mv_ref_ct[6][4][2]; + int mode_context[6][4]; +#endif + + int vp8_mode_contexts[6][4]; + unsigned int current_video_frame; int near_boffset[3]; diff --git a/vp8/decoder/decodemv.c b/vp8/decoder/decodemv.c index 8934b62a8..75d47dc18 100644 --- a/vp8/decoder/decodemv.c +++ b/vp8/decoder/decodemv.c @@ -548,7 +548,7 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, #endif &nearest, &nearby, &best_mv, rct, mbmi->ref_frame, pbi->common.ref_frame_sign_bias); - vp8_mv_ref_probs(mv_ref_p, rct); + vp8_mv_ref_probs(&pbi->common, mv_ref_p, rct); //#if CONFIG_SEGFEATURES // Is the segment level mode feature enabled for this segment @@ -560,6 +560,10 @@ static void read_mb_modes_mv(VP8D_COMP *pbi, MODE_INFO *mi, MB_MODE_INFO *mbmi, else { mbmi->mode = read_mv_ref(bc, mv_ref_p); + +#if CONFIG_NEWNEAR + vp8_accum_mv_refs(&pbi->common, mbmi->mode, rct); +#endif } mbmi->uv_mode = DC_PRED; diff --git a/vp8/decoder/decodframe.c b/vp8/decoder/decodframe.c index 2ad5d1b87..b9fefa94e 100644 --- a/vp8/decoder/decodframe.c +++ b/vp8/decoder/decodframe.c @@ -27,6 +27,7 @@ #include "decodemv.h" #include "vp8/common/extend.h" +#include "vp8/common/modecont.h" #if CONFIG_ERROR_CONCEALMENT #include "error_concealment.h" #endif @@ -862,7 +863,9 @@ static void init_frame(VP8D_COMP *pbi) vpx_memcpy(&pc->lfc, &pc->fc, sizeof(pc->fc)); vpx_memcpy(&pc->lfc_a, &pc->fc, sizeof(pc->fc)); #endif - +#if CONFIG_NEWNEAR + vp8_init_mv_ref_counts(&pbi->common); +#endif } else { @@ -1364,8 +1367,30 @@ int vp8_decode_frame(VP8D_COMP *pbi) /* Read the mb_no_coeff_skip flag */ pc->mb_no_coeff_skip = (int)vp8_read_bit(bc); - vp8_decode_mode_mvs(pbi); +#if CONFIG_NEWNEAR + if(!pbi->common.refresh_alt_ref_frame) + { + vp8_update_mode_context(&pbi->common); + vpx_memcpy( pc->vp8_mode_contexts, + pbi->common.mode_context, + sizeof(pbi->common.mode_context)); + + if(0) //pbi->common.current_video_frame<2) + { + printf("mv_ref_ct on frame %d:\n", + pbi->common.current_video_frame); + print_mv_ref_cts(&pbi->common); + + printf("mode_contexts on frame %d:\n", + pbi->common.current_video_frame); + print_mode_contexts(); + } + + + } +#endif + #if CONFIG_ERROR_CONCEALMENT if (pbi->ec_active && diff --git a/vp8/encoder/bitstream.c b/vp8/encoder/bitstream.c index 43182b10d..955cc3133 100644 --- a/vp8/encoder/bitstream.c +++ b/vp8/encoder/bitstream.c @@ -1156,18 +1156,20 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi) else { int_mv best_mv; + int ct[4]; + vp8_prob mv_ref_p [VP8_MVREFS-1]; { int_mv n1, n2; - int ct[4]; vp8_find_near_mvs(xd, m, #if CONFIG_NEWNEAR prev_m, #endif &n1, &n2, &best_mv, ct, rf, cpi->common.ref_frame_sign_bias); - vp8_mv_ref_probs(mv_ref_p, ct); + vp8_mv_ref_probs(&cpi->common, mv_ref_p, ct); + #ifdef ENTROPY_STATS accum_mv_refs(mode, ct); @@ -1183,6 +1185,9 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi) if ( !segfeature_active( xd, segment_id, SEG_LVL_MODE ) ) { write_mv_ref(w, mode, mv_ref_p); +#if CONFIG_NEWNEAR + vp8_accum_mv_refs(&cpi->common, mode, ct); +#endif } { @@ -2326,6 +2331,28 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size) { pack_inter_mode_mvs(cpi); +#if CONFIG_NEWNEAR + if(!cpi->common.refresh_alt_ref_frame) + { + vp8_update_mode_context(&cpi->common); + vpx_memcpy( pc->vp8_mode_contexts, + cpi->common.mode_context, + sizeof(cpi->common.mode_context)); + + if(0) //(cpi->common.current_video_frame<2) + { + + printf("mv_ref_ct on frame %d:\n", + cpi->common.current_video_frame); + print_mv_ref_cts(&cpi->common); + + printf("mode_contexts on frame %d:\n", + cpi->common.current_video_frame); + print_mode_contexts(); + } + } +#endif + #ifdef ENTROPY_STATS active_section = 1; #endif diff --git a/vp8/encoder/mcomp.c b/vp8/encoder/mcomp.c index aebcfce70..b23abffad 100644 --- a/vp8/encoder/mcomp.c +++ b/vp8/encoder/mcomp.c @@ -1852,41 +1852,28 @@ int vp8_refining_search_sadx4(MACROBLOCK *x, BLOCK *b, BLOCKD *d, return INT_MAX; } + + #ifdef ENTROPY_STATS void print_mode_context(void) { - FILE *f = fopen("modecont.c", "w"); + FILE *f = fopen("modecont.c", "a"); int i, j; fprintf(f, "#include \"entropy.h\"\n"); - fprintf(f, "const int vp8_mode_contexts[6][4] =\n"); + fprintf(f, "const int vp8_mode_contexts[6][4] ="); fprintf(f, "{\n"); - for (j = 0; j < 6; j++) { - fprintf(f, " { // %d \n", j); + fprintf(f, " {/* %d */ ", j); fprintf(f, " "); - for (i = 0; i < 4; i++) { - int overal_prob; int this_prob; - int count; // = mv_ref_ct[j][i][0]+mv_ref_ct[j][i][1]; - - // Overall probs - count = mv_mode_cts[i][0] + mv_mode_cts[i][1]; - - if (count) - overal_prob = 256 * mv_mode_cts[i][0] / count; - else - overal_prob = 128; - - if (overal_prob == 0) - overal_prob = 1; + int count; // context probs count = mv_ref_ct[j][i][0] + mv_ref_ct[j][i][1]; - if (count) this_prob = 256 * mv_ref_ct[j][i][0] / count; else @@ -1894,12 +1881,8 @@ void print_mode_context(void) if (this_prob == 0) this_prob = 1; - fprintf(f, "%5d, ", this_prob); - //fprintf(f,"%5d, %5d, %8d,", this_prob, overal_prob, (this_prob << 10)/overal_prob); - //fprintf(f,"%8d, ", (this_prob << 10)/overal_prob); } - fprintf(f, " },\n"); } @@ -1908,7 +1891,6 @@ void print_mode_context(void) } /* MV ref count ENTROPY_STATS stats code */ -#ifdef ENTROPY_STATS void init_mv_ref_counts() { vpx_memset(mv_ref_ct, 0, sizeof(mv_ref_ct)); @@ -1964,4 +1946,4 @@ void accum_mv_refs(MB_PREDICTION_MODE m, const int ct[4]) #endif/* END MV ref count ENTROPY_STATS stats code */ -#endif + diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c index 4b622d8bf..19ab4d434 100644 --- a/vp8/encoder/pickinter.c +++ b/vp8/encoder/pickinter.c @@ -47,7 +47,8 @@ extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES]; extern const MV_REFERENCE_FRAME vp8_second_ref_frame_order[MAX_MODES]; extern unsigned int (*vp8_get4x4sse_cs)(unsigned char *src_ptr, int source_stride, unsigned char *ref_ptr, int recon_stride); -extern int vp8_cost_mv_ref(MB_PREDICTION_MODE m, const int near_mv_ref_ct[4]); +extern int vp8_cost_mv_ref(VP8_COMMON *pc, + MB_PREDICTION_MODE m, const int near_mv_ref_ct[4]); int vp8_skip_fractional_mv_step(MACROBLOCK *mb, BLOCK *b, BLOCKD *d, @@ -811,7 +812,7 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, ((mode_mv[this_mode].as_mv.col >> 3) < x->mv_col_min) || ((mode_mv[this_mode].as_mv.col >> 3) > x->mv_col_max)) continue; - rate2 += vp8_cost_mv_ref(this_mode, mdcounts); + rate2 += vp8_cost_mv_ref(&cpi->common, this_mode, mdcounts); x->e_mbd.mode_info_context->mbmi.mv.as_int = mode_mv[this_mode].as_int; diff --git a/vp8/encoder/ratectrl.c b/vp8/encoder/ratectrl.c index d510ad958..d4ca381ae 100644 --- a/vp8/encoder/ratectrl.c +++ b/vp8/encoder/ratectrl.c @@ -267,6 +267,9 @@ void vp8_setup_key_frame(VP8_COMP *cpi) vpx_memcpy(&cpi->common.lfc_a, &cpi->common.fc, sizeof(cpi->common.fc)); #endif +#if CONFIG_NEWNEAR + vp8_init_mv_ref_counts(&cpi->common); +#endif } #if CONFIG_MULCONTEXT void vp8_setup_inter_frame(VP8_COMP *cpi) diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c index 00055f9f1..f4a44baa7 100644 --- a/vp8/encoder/rdopt.c +++ b/vp8/encoder/rdopt.c @@ -1142,11 +1142,13 @@ static void rd_pick_intra_mbuv_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate, int x->e_mbd.mode_info_context->mbmi.uv_mode = mode_selected; } -int vp8_cost_mv_ref(MB_PREDICTION_MODE m, const int near_mv_ref_ct[4]) +int vp8_cost_mv_ref(VP8_COMMON *pc, + MB_PREDICTION_MODE m, + const int near_mv_ref_ct[4]) { vp8_prob p [VP8_MVREFS-1]; assert(NEARESTMV <= m && m <= SPLITMV); - vp8_mv_ref_probs(p, near_mv_ref_ct); + vp8_mv_ref_probs(pc, p, near_mv_ref_ct); return vp8_cost_token(vp8_mv_ref_tree, p, vp8_mv_ref_encoding_array - NEARESTMV + m); } @@ -1362,7 +1364,7 @@ static void rd_check_segment(VP8_COMP *cpi, MACROBLOCK *x, // Segmentation method overheads rate = vp8_cost_token(vp8_mbsplit_tree, vp8_mbsplit_probs, vp8_mbsplit_encodings + segmentation); - rate += vp8_cost_mv_ref(SPLITMV, bsi->mdcounts); + rate += vp8_cost_mv_ref(&cpi->common, SPLITMV, bsi->mdcounts); this_segment_rd += RDCOST(x->rdmult, x->rddiv, rate, 0); br += rate; @@ -2613,7 +2615,7 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int //intermodecost[mode_index] = vp8_cost_mv_ref(this_mode, mdcounts); // Experimental debug code // Add in the Mv/mode cost - rate2 += vp8_cost_mv_ref(this_mode, mdcounts); + rate2 += vp8_cost_mv_ref(&cpi->common, this_mode, mdcounts); // Y cost and distortion macro_block_yrd(x, &rate_y, &distortion, IF_RTCD(&cpi->rtcd.encodemb)); @@ -2674,7 +2676,7 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int } /* Add in the Mv/mode cost */ - rate2 += vp8_cost_mv_ref(this_mode, mdcounts); + rate2 += vp8_cost_mv_ref(&cpi->common,this_mode, mdcounts); vp8_clamp_mv2(&x->e_mbd.mode_info_context->mbmi.mv, xd); vp8_clamp_mv2(&x->e_mbd.mode_info_context->mbmi.second_mv, xd); -- 2.50.1