Changed how coefficient probability table is updated

Added a frame level flag to indicate if coef probabilities are updated
at all for the frame.

During the experimental work with 8x8 transform, it is discovered that
even in the case of no probability is ever update, cost of transmitting
"no update" for each of probabilities can run up to become a significant
overhead cost. A single bit to indicate no-update for all coef probs
is therefore helpful, which is also demonstrated by the test results:

1. On Cif set:
http://www.corp.google.com/~yaowu/no_crawl/t8x8/cif_t8x8_updprob.html
(avg psnr: .14%, glb psnr: .14% SSIM: .13%)

2. On HD set:
http://www.corp.google.com/~yaowu/no_crawl/t8x8/HD_t8x8_updprob.html
(avg psnr: .02%  glb psnr: .01% SSIM: .02%)
It should be noted that the gain on HD is smaller because the average bit
rate is much higher in contrast to the overhead bit cost.

Change-Id: I46db270e693ee8799fef34a14d8260868ce4cd16
This commit is contained in:
Yaowu Xu 2012-02-06 15:10:13 -08:00 committed by Paul Wilkins
parent 21108d800c
commit 2d1ead342c
2 changed files with 185 additions and 77 deletions

View File

@ -1399,13 +1399,14 @@ int vp8_decode_frame(VP8D_COMP *pbi)
{
pbi->independent_partitions = 1;
if(vp8_read_bit(bc))
{
/* read coef probability tree */
for (i = 0; i < BLOCK_TYPES; i++)
for (j = 0; j < COEF_BANDS; j++)
for (k = 0; k < PREV_COEF_CONTEXTS; k++)
for (l = 0; l < ENTROPY_NODES; l++)
{
vp8_prob *const p = pc->fc.coef_probs [i][j][k] + l;
if (vp8_read(bc, vp8_coef_update_probs [i][j][k][l]))
@ -1415,14 +1416,13 @@ int vp8_decode_frame(VP8D_COMP *pbi)
}
if (k > 0 && *p != pc->fc.coef_probs[i][j][k-1][l])
pbi->independent_partitions = 0;
}
}
}
#if CONFIG_T8X8
if(pbi->common.txfm_mode == ALLOW_8X8)
if(pbi->common.txfm_mode == ALLOW_8X8 && vp8_read_bit(bc))
{
// read coef probability tree
for (i = 0; i < BLOCK_TYPES; i++)
for (j = 0; j < COEF_BANDS; j++)
for (k = 0; k < PREV_COEF_CONTEXTS; k++)

View File

@ -2210,14 +2210,13 @@ static void update_coef_probs(VP8_COMP *cpi)
{
int i = 0;
vp8_writer *const w = & cpi->bc;
int savings = 0;
int update = 0;
vp8_clear_system_state(); //__asm emms;
/* dry run to see if there is any udpate at all needed */
do
{
int j = 0;
do
{
int k = 0;
@ -2235,7 +2234,6 @@ static void update_coef_probs(VP8_COMP *cpi)
const vp8_prob oldp = cpi->common.fc.coef_probs[i][j]
[k][t];
const vp8_prob upd = vp8_coef_update_probs[i][j][k][t];
prev_coef_savings[t] +=
prob_update_savings(ct, oldp, newp, upd);
}
@ -2246,29 +2244,22 @@ static void update_coef_probs(VP8_COMP *cpi)
{
//note: use result from vp8_estimate_entropy_savings, so no need to call vp8_tree_probs_from_distribution here.
/* at every context */
/* calc probs and branch cts for this frame only */
//vp8_prob new_p [ENTROPY_NODES];
//unsigned int branch_ct [ENTROPY_NODES] [2];
int t = 0; /* token/prob index */
//vp8_tree_probs_from_distribution(
// MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree,
// new_p, branch_ct, (unsigned int *)cpi->coef_counts [i][j][k],
// 256, 1
// );
do
{
const vp8_prob newp = cpi->frame_coef_probs [i][j][k][t];
vp8_prob *Pold = cpi->common.fc.coef_probs [i][j][k] + t;
const vp8_prob upd = vp8_coef_update_probs [i][j][k][t];
int s = prev_coef_savings[t];
int u = 0;
if (!(cpi->oxcf.error_resilient_mode &
VPX_ERROR_RESILIENT_PARTITIONS))
{
@ -2276,10 +2267,8 @@ static void update_coef_probs(VP8_COMP *cpi)
cpi->frame_branch_ct [i][j][k][t],
*Pold, newp, upd);
}
if (s > 0)
u = 1;
/* Force updates on key frames if the new is different,
* so that we can be sure we end up with equal probabilities
* over the prev coef contexts.
@ -2288,60 +2277,51 @@ static void update_coef_probs(VP8_COMP *cpi)
VPX_ERROR_RESILIENT_PARTITIONS) &&
cpi->common.frame_type == KEY_FRAME && newp != *Pold)
u = 1;
vp8_write(w, u, upd);
#ifdef ENTROPY_STATS
++ tree_update_hist [i][j][k][t] [u];
#endif
if (u)
{
/* send/use new probability */
*Pold = newp;
vp8_write_literal(w, newp, 8);
savings += s;
}
update += u;
}
while (++t < ENTROPY_NODES);
/* Accum token counts for generation of default statistics */
#ifdef ENTROPY_STATS
t = 0;
do
{
context_counters [i][j][k][t] += cpi->coef_counts [i][j][k][t];
}
while (++t < MAX_ENTROPY_TOKENS);
#endif
}
while (++k < PREV_COEF_CONTEXTS);
}
while (++j < COEF_BANDS);
}
while (++i < BLOCK_TYPES);
#if CONFIG_T8X8
/* do not do this if not evena allowed */
if(cpi->common.txfm_mode == ALLOW_8X8)
/* Is coef updated at all */
if(update==0)
{
i = 0;
vp8_write_bit(w, 0);
}
else
{
vp8_write_bit(w, 1);
i=0;
do
{
int j = 0;
do
{
int k = 0;
int prev_coef_savings[ENTROPY_NODES] = {0};
if (cpi->oxcf.error_resilient_mode & VPX_ERROR_RESILIENT_PARTITIONS)
{
for (k = 0; k < PREV_COEF_CONTEXTS; ++k)
{
int t; /* token/prob index */
for (t = 0; t < ENTROPY_NODES; ++t)
{
const unsigned int *ct = cpi->frame_branch_ct [i][j]
[k][t];
const vp8_prob newp = cpi->frame_coef_probs[i][j][k][t];
const vp8_prob oldp = cpi->common.fc.coef_probs[i][j]
[k][t];
const vp8_prob upd = vp8_coef_update_probs[i][j][k][t];
prev_coef_savings[t] +=
prob_update_savings(ct, oldp, newp, upd);
}
}
k = 0;
}
do
{
//note: use result from vp8_estimate_entropy_savings, so no need to call vp8_tree_probs_from_distribution here.
@ -2350,51 +2330,109 @@ static void update_coef_probs(VP8_COMP *cpi)
/* calc probs and branch cts for this frame only */
//vp8_prob new_p [ENTROPY_NODES];
//unsigned int branch_ct [ENTROPY_NODES] [2];
int t = 0; /* token/prob index */
//vp8_tree_probs_from_distribution(
// MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree,
// new_p, branch_ct, (unsigned int *)cpi->coef_counts [i][j][k],
// 256, 1
// );
do
{
const vp8_prob newp = cpi->frame_coef_probs [i][j][k][t];
vp8_prob *Pold = cpi->common.fc.coef_probs [i][j][k] + t;
const vp8_prob upd = vp8_coef_update_probs [i][j][k][t];
int s = prev_coef_savings[t];
int u = 0;
if (!(cpi->oxcf.error_resilient_mode &
VPX_ERROR_RESILIENT_PARTITIONS))
{
s = prob_update_savings(
cpi->frame_branch_ct [i][j][k][t],
*Pold, newp, upd);
}
if (s > 0)
u = 1;
/* Force updates on key frames if the new is different,
* so that we can be sure we end up with equal probabilities
* over the prev coef contexts.
*/
if ((cpi->oxcf.error_resilient_mode &
VPX_ERROR_RESILIENT_PARTITIONS) &&
cpi->common.frame_type == KEY_FRAME && newp != *Pold)
u = 1;
vp8_write(w, u, upd);
#ifdef ENTROPY_STATS
++ tree_update_hist [i][j][k][t] [u];
#endif
if (u)
{
/* send/use new probability */
*Pold = newp;
vp8_write_literal(w, newp, 8);
}
}
while (++t < ENTROPY_NODES);
/* Accum token counts for generation of default statistics */
#ifdef ENTROPY_STATS
t = 0;
do
{
context_counters [i][j][k][t] += cpi->coef_counts [i][j][k][t];
}
while (++t < MAX_ENTROPY_TOKENS);
#endif
}
while (++k < PREV_COEF_CONTEXTS);
}
while (++j < COEF_BANDS);
}
while (++i < BLOCK_TYPES);
}
#if CONFIG_T8X8
/* do not do this if not evena allowed */
if(cpi->common.txfm_mode == ALLOW_8X8)
{
update = 1;
/* dry run to see if update is necessary */
i = 0;
do
{
int j = 0;
do
{
int k = 0;
do
{
//note: use result from vp8_estimate_entropy_savings, so no need to call vp8_tree_probs_from_distribution here.
/* at every context */
/* calc probs and branch cts for this frame only */
//vp8_prob new_p [ENTROPY_NODES];
//unsigned int branch_ct [ENTROPY_NODES] [2];
int t = 0; /* token/prob index */
//vp8_tree_probs_from_distribution(
// MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree,
// new_p, branch_ct, (unsigned int *)cpi->coef_counts [i][j][k],
// 256, 1
// );
do
{
const unsigned int *ct = cpi->frame_branch_ct_8x8 [i][j][k][t];
const vp8_prob newp = cpi->frame_coef_probs_8x8 [i][j][k][t];
vp8_prob *Pold = cpi->common.fc.coef_probs_8x8 [i][j][k] + t;
const vp8_prob old = *Pold;
const vp8_prob upd = vp8_coef_update_probs_8x8 [i][j][k][t];
const int old_b = vp8_cost_branch(ct, old);
const int new_b = vp8_cost_branch(ct, newp);
const int update_b = 8 +
((vp8_cost_one(upd) - vp8_cost_zero(upd)) >> 8);
const int s = old_b - new_b - update_b;
const int u = s > 0 ? 1 : 0;
vp8_write(w, u, upd);
#ifdef ENTROPY_STATS
++ tree_update_hist_8x8 [i][j][k][t] [u];
#endif
if (u)
{
/* send/use new probability */
*Pold = newp;
vp8_write_literal(w, newp, 8);
savings += s;
}
update += u;
}
while (++t < MAX_ENTROPY_TOKENS - 1);
@ -2415,6 +2453,76 @@ static void update_coef_probs(VP8_COMP *cpi)
while (++j < COEF_BANDS);
}
while (++i < BLOCK_TYPES);
if(update == 0)
{
vp8_write_bit(w, 0);
}
else
{
vp8_write_bit(w, 1);
i = 0;
do
{
int j = 0;
do
{
int k = 0;
do
{
//note: use result from vp8_estimate_entropy_savings, so no need to call vp8_tree_probs_from_distribution here.
/* at every context */
/* calc probs and branch cts for this frame only */
//vp8_prob new_p [ENTROPY_NODES];
//unsigned int branch_ct [ENTROPY_NODES] [2];
int t = 0; /* token/prob index */
//vp8_tree_probs_from_distribution(
// MAX_ENTROPY_TOKENS, vp8_coef_encodings, vp8_coef_tree,
// new_p, branch_ct, (unsigned int *)cpi->coef_counts [i][j][k],
// 256, 1
// );
do
{
const unsigned int *ct = cpi->frame_branch_ct_8x8 [i][j][k][t];
const vp8_prob newp = cpi->frame_coef_probs_8x8 [i][j][k][t];
vp8_prob *Pold = cpi->common.fc.coef_probs_8x8 [i][j][k] + t;
const vp8_prob old = *Pold;
const vp8_prob upd = vp8_coef_update_probs_8x8 [i][j][k][t];
const int old_b = vp8_cost_branch(ct, old);
const int new_b = vp8_cost_branch(ct, newp);
const int update_b = 8 +
((vp8_cost_one(upd) - vp8_cost_zero(upd)) >> 8);
const int s = old_b - new_b - update_b;
const int u = s > 0 ? 1 : 0;
vp8_write(w, u, upd);
#ifdef ENTROPY_STATS
++ tree_update_hist_8x8 [i][j][k][t] [u];
#endif
if (u)
{
/* send/use new probability */
*Pold = newp;
vp8_write_literal(w, newp, 8);
}
}
while (++t < MAX_ENTROPY_TOKENS - 1);
/* Accum token counts for generation of default statistics */
#ifdef ENTROPY_STATS
t = 0;
do
{
context_counters_8x8 [i][j][k][t] += cpi->coef_counts_8x8 [i][j][k][t];
}
while (++t < MAX_ENTROPY_TOKENS);
#endif
}
while (++k < PREV_COEF_CONTEXTS);
}
while (++j < COEF_BANDS);
}
while (++i < BLOCK_TYPES);
}
}
#endif