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
This commit is contained in:
Yaowu Xu 2011-12-06 12:03:42 -08:00
Родитель b1823a7dd2
Коммит 76feb965d3
14 изменённых файлов: 204 добавлений и 45 удалений

Просмотреть файл

@ -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;

Просмотреть файл

@ -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

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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]
);

Просмотреть файл

@ -11,7 +11,7 @@
#include "entropy.h"
const int vp8_mode_contexts[6][4] =
const int default_vp8_mode_contexts[6][4] =
{
{
/* 0 */

Просмотреть файл

@ -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

Просмотреть файл

@ -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];

Просмотреть файл

@ -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;

Просмотреть файл

@ -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 &&

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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;

Просмотреть файл

@ -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)

Просмотреть файл

@ -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);