Modified prediction behavior for reference frame.

Trial of a modified prediction function that ranks each possible
reference frame based on a combination of local usage and
frame level probability. The code is a bit cleaner and simpler.

In direct comparison with old unpredicted method with segment level
coding turned off for mode,ref & EOB the prediction gives a gain on derf
of around 0.4%. There is some further gain from bug fixes over earlier code.

With segment coding on the prediction method is slightly -ve on some very
easy clips (at low rates) due to slightly higher overheads, but better on harder
clips. Overall neutral on derf in direct comparison on latest code base, but
compared to earlier code without bug fixes about +0.7% overall psnr
+0.3% SSIM.

Change-Id: I5b8474658b208134d352d24f6517f25795490789
This commit is contained in:
Paul Wilkins 2012-02-03 13:46:18 +00:00
parent f0459549a6
commit 58ec6fe8c3
7 changed files with 112 additions and 155 deletions

View File

@ -236,6 +236,7 @@ typedef struct VP8Common
#if CONFIG_COMPRED
// Context probabilities for reference frame prediction
unsigned char ref_scores[MAX_REF_FRAMES];
vp8_prob ref_pred_probs[PREDICTION_PROBS];
vp8_prob mod_refprobs[MAX_REF_FRAMES][PREDICTION_PROBS];
#endif

View File

@ -155,10 +155,6 @@ MV_REFERENCE_FRAME get_pred_ref( VP8_COMMON *const cm,
{
MODE_INFO *m = xd->mode_info_context;
unsigned char left_pred;
unsigned char above_pred;
unsigned char frame_allowed[MAX_REF_FRAMES];
MV_REFERENCE_FRAME left;
MV_REFERENCE_FRAME above;
MV_REFERENCE_FRAME above_left;
@ -166,106 +162,67 @@ MV_REFERENCE_FRAME get_pred_ref( VP8_COMMON *const cm,
int segment_id = xd->mode_info_context->mbmi.segment_id;
int seg_ref_active;
int i;
unsigned char frame_allowed[MAX_REF_FRAMES] = {1,1,1,1};
unsigned char ref_score[MAX_REF_FRAMES];
unsigned char best_score = 0;
unsigned char left_in_image;
unsigned char above_in_image;
unsigned char above_left_in_image;
// Is segment coding ennabled
seg_ref_active = segfeature_active( xd, segment_id, SEG_LVL_REF_FRAME );
// Reference frame used by neighbours
left = (m - 1)->mbmi.ref_frame;
above = (m - cm->mode_info_stride)->mbmi.ref_frame;
above_left = (m - 1 - cm->mode_info_stride)->mbmi.ref_frame;
// Reference frame prediction status of immediate neigbours.
// This can only be set if the mb is "in image"
left_pred = (m - 1)->mbmi.ref_predicted;
above_pred = (m - cm->mode_info_stride)->mbmi.ref_predicted;
// Special case treatment if segment coding is enabled.
// Dont allow prediction of a reference frame that the segment
// does not allow
if ( seg_ref_active )
{
frame_allowed[INTRA_FRAME] =
check_segref( xd, segment_id, INTRA_FRAME );
frame_allowed[LAST_FRAME] =
check_segref( xd, segment_id, LAST_FRAME );
frame_allowed[GOLDEN_FRAME] =
check_segref( xd, segment_id, GOLDEN_FRAME );
frame_allowed[ALTREF_FRAME] =
check_segref( xd, segment_id, ALTREF_FRAME );
for ( i = 0; i < MAX_REF_FRAMES; i++ )
{
frame_allowed[i] =
check_segref( xd, segment_id, i );
// Score set to 0 if ref frame not allowed
ref_score[i] = cm->ref_scores[i] * frame_allowed[i];
}
}
else
vpx_memcpy( ref_score, cm->ref_scores, sizeof(ref_score) );
// Reference frames used by neighbours
left = (m - 1)->mbmi.ref_frame;
above = (m - cm->mode_info_stride)->mbmi.ref_frame;
above_left = (m - 1 - cm->mode_info_stride)->mbmi.ref_frame;
// Are neighbours in image
left_in_image = (m - 1)->mbmi.mb_in_image;
above_in_image = (m - cm->mode_info_stride)->mbmi.mb_in_image;
above_left_in_image = (m - 1 - cm->mode_info_stride)->mbmi.mb_in_image;
// Adjust scores for candidate reference frames based on neigbours
if ( frame_allowed[left] && left_in_image )
{
frame_allowed[INTRA_FRAME] = 1;
frame_allowed[LAST_FRAME] = 1;
frame_allowed[GOLDEN_FRAME] = 1;
frame_allowed[ALTREF_FRAME] = 1;
ref_score[left] += 16;
if ( above_left_in_image && (left == above_left) )
ref_score[left] += 4;
}
if ( frame_allowed[above] && above_in_image )
{
ref_score[above] += 16;
if ( above_left_in_image && (above == above_left) )
ref_score[above] += 4;
}
// Dont predict if not allowed
left_pred = left_pred * frame_allowed[left];
above_pred = above_pred * frame_allowed[above];
// Boost prediction scores of above / left if they are predicted and match
// the above left.
if ( left_pred )
left_pred += (left == above_left);
if ( above_pred )
above_pred += (above == above_left);
// Only consider "in image" mbs as giving valid prediction.
if ( (left == above) && frame_allowed[left] &&
((m - 1)->mbmi.mb_in_image ||
(m - cm->mode_info_stride)->mbmi.mb_in_image) )
// Now choose the candidate with the highest score
for ( i = 0; i < MAX_REF_FRAMES; i++ )
{
pred_ref = left;
}
else if ( left_pred > above_pred )
{
pred_ref = left;
}
else if ( above_pred > left_pred )
{
pred_ref = above;
}
// If we reach this clause left_pred and above_pred must be the same
else if ( left_pred > 0 )
{
// Choose from above or left.
// For now this is based on a fixed preference order.
// Last,Altref,Golden
if ( frame_allowed[LAST_FRAME] &&
((left == LAST_FRAME) || (above == LAST_FRAME)) )
if ( ref_score[i] > best_score )
{
pred_ref = LAST_FRAME;
pred_ref = i;
best_score = ref_score[i];
}
else if ( frame_allowed[ALTREF_FRAME] &&
((left == ALTREF_FRAME) || (above == ALTREF_FRAME)) )
{
pred_ref = ALTREF_FRAME;
}
else if ( frame_allowed[GOLDEN_FRAME] &&
((left == GOLDEN_FRAME) || (above == GOLDEN_FRAME)) )
{
pred_ref = GOLDEN_FRAME;
}
else
{
pred_ref = INTRA_FRAME;
}
}
// No prediction case.. choose in fixed order from allowed options
// TBD could order based onf frequency.
else
{
if ( frame_allowed[LAST_FRAME] )
pred_ref = LAST_FRAME;
else if ( frame_allowed[ALTREF_FRAME] )
pred_ref = ALTREF_FRAME;
else if ( frame_allowed[GOLDEN_FRAME] )
pred_ref = GOLDEN_FRAME;
else
pred_ref = INTRA_FRAME;
}
return pred_ref;
@ -357,5 +314,13 @@ void compute_mod_refprobs( VP8_COMMON *const cm )
norm_cnt[3] = 0;
calc_ref_probs( norm_cnt, cm->mod_refprobs[ALTREF_FRAME] );
cm->mod_refprobs[ALTREF_FRAME][2] = 0; // This branch implicit
// Score the reference frames based on overal frequency.
// These scores contribute to the prediction choices.
// Max score 17 min 1
cm->ref_scores[INTRA_FRAME] = 1 + (intra_count * 16 / 255);
cm->ref_scores[LAST_FRAME] = 1 + (last_count * 16 / 255);
cm->ref_scores[GOLDEN_FRAME] = 1 + (gf_count * 16 / 255);
cm->ref_scores[ALTREF_FRAME] = 1 + (arf_count * 16 / 255);
}
#endif

View File

@ -292,7 +292,6 @@ static MV_REFERENCE_FRAME read_ref_frame( VP8D_COMP *pbi,
// else decode the explicitly coded value
else
{
//vp8_prob * mod_refprobs = cm->mod_refprobs[pred_ref];
vp8_prob mod_refprobs[PREDICTION_PROBS];
vpx_memcpy( mod_refprobs,
cm->mod_refprobs[pred_ref], sizeof(mod_refprobs) );

View File

@ -869,21 +869,24 @@ static void encode_ref_frame( vp8_writer *const w,
// Values used in prediction model coding
unsigned char prediction_flag;
vp8_prob pred_prob;
MV_REFERENCE_FRAME pred_rf;
// Get the context probability the prediction flag
pred_prob = get_pred_prob( cm, xd, PRED_REF );
// Code the prediction flag
prediction_flag = get_pred_flag( xd, PRED_REF );
// Get the predicted value.
pred_rf = get_pred_ref( cm, xd );
// Did the chosen reference frame match its predicted value.
prediction_flag =
( xd->mode_info_context->mbmi.ref_frame == pred_rf );
set_pred_flag( xd, PRED_REF, prediction_flag );
vp8_write( w, prediction_flag, pred_prob );
// If not predicted correctly then code value explicitly
if ( !prediction_flag )
{
// Get the predicted value so that it can be excluded.
MV_REFERENCE_FRAME pred_rf = get_pred_ref( cm, xd );
//vp8_prob * mod_refprobs = cm->mod_refprobs[pred_rf];
vp8_prob mod_refprobs[PREDICTION_PROBS];
vpx_memcpy( mod_refprobs,
@ -997,6 +1000,42 @@ static void encode_ref_frame( vp8_writer *const w,
#endif
}
// Update the probabilities used to encode reference frame data
static void update_ref_probs( VP8_COMP *const cpi )
{
VP8_COMMON *const cm = & cpi->common;
const int *const rfct = cpi->count_mb_ref_frame_usage;
const int rf_intra = rfct[INTRA_FRAME];
const int rf_inter = rfct[LAST_FRAME] +
rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME];
//#if CONFIG_SEGFEATURES
cm->prob_intra_coded = (rf_intra + rf_inter)
? rf_intra * 255 / (rf_intra + rf_inter) : 1;
if (!cm->prob_intra_coded)
cm->prob_intra_coded = 1;
cm->prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128;
if (!cm->prob_last_coded)
cm->prob_last_coded = 1;
cm->prob_gf_coded = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME])
? (rfct[GOLDEN_FRAME] * 255) /
(rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128;
if (!cm->prob_gf_coded)
cm->prob_gf_coded = 1;
#if CONFIG_COMPRED
// Compute a modified set of probabilities to use when prediction of the
// reference frame fails
compute_mod_refprobs( cm );
#endif
}
#if CONFIG_SUPERBLOCKS
static void pack_inter_mode_mvs(VP8_COMP *const cpi)
{
@ -1010,9 +1049,6 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
#endif
int pred_context;
const int *const rfct = cpi->count_mb_ref_frame_usage;
const int rf_intra = rfct[INTRA_FRAME];
const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME];
MODE_INFO *m = pc->mi;
#if CONFIG_NEWNEAR
MODE_INFO *prev_m = pc->prev_mi;
@ -1036,31 +1072,8 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
cpi->mb.partition_info = cpi->mb.pi;
// Calculate the probabilities to be used to code the reference frame
// based on actual useage this frame
//#if CONFIG_SEGFEATURES
pc->prob_intra_coded = (rf_intra + rf_inter)
? rf_intra * 255 / (rf_intra + rf_inter) : 1;
if (!pc->prob_intra_coded)
pc->prob_intra_coded = 1;
pc->prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128;
if (!pc->prob_last_coded)
pc->prob_last_coded = 1;
pc->prob_gf_coded = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME])
? (rfct[GOLDEN_FRAME] * 255) / (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128;
if (!pc->prob_gf_coded)
pc->prob_gf_coded = 1;
#if CONFIG_COMPRED
// Compute a modified set of probabilities to use when prediction of the
// reference frame fails
compute_mod_refprobs( pc );
#endif
// Update the probabilities used to encode reference frame data
update_ref_probs( cpi );
#ifdef ENTROPY_STATS
active_section = 1;
@ -1425,9 +1438,6 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
#endif
int pred_context;
const int *const rfct = cpi->count_mb_ref_frame_usage;
const int rf_intra = rfct[INTRA_FRAME];
const int rf_inter = rfct[LAST_FRAME] + rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME];
MODE_INFO *m = pc->mi;
#if CONFIG_NEWNEAR
@ -1448,31 +1458,8 @@ static void pack_inter_mode_mvs(VP8_COMP *const cpi)
cpi->mb.partition_info = cpi->mb.pi;
// Calculate the probabilities to be used to code the reference frame
// based on actual useage this frame
//#if CONFIG_SEGFEATURES
pc->prob_intra_coded = (rf_intra + rf_inter)
? rf_intra * 255 / (rf_intra + rf_inter) : 1;
if (!pc->prob_intra_coded)
pc->prob_intra_coded = 1;
pc->prob_last_coded = rf_inter ? (rfct[LAST_FRAME] * 255) / rf_inter : 128;
if (!pc->prob_last_coded)
pc->prob_last_coded = 1;
pc->prob_gf_coded = (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME])
? (rfct[GOLDEN_FRAME] * 255) / (rfct[GOLDEN_FRAME] + rfct[ALTREF_FRAME]) : 128;
if (!pc->prob_gf_coded)
pc->prob_gf_coded = 1;
#if CONFIG_COMPRED
// Compute a modified set of probabilities to use when prediction of the
// reference frame fails
compute_mod_refprobs( pc );
#endif
// Update the probabilities used to encode reference frame data
update_ref_probs( cpi );
#ifdef ENTROPY_STATS
active_section = 1;
@ -2825,7 +2812,7 @@ void vp8_pack_bitstream(VP8_COMP *cpi, unsigned char *dest, unsigned long *size)
{
for (i = 0; i < PREDICTION_PROBS; i++)
{
if ( cpi->ref_probs_update[i] )
if ( cpi->ref_pred_probs_update[i] )
{
vp8_write_bit(bc, 1);
vp8_write_literal(bc, pc->ref_pred_probs[i], 8);

View File

@ -1982,6 +1982,7 @@ int vp8cx_encode_inter_macroblock
ref_pred_flag = ( (xd->mode_info_context->mbmi.ref_frame ==
get_pred_ref( cm, xd )) );
set_pred_flag( xd, PRED_REF, ref_pred_flag );
#endif
// If we have just a single reference frame coded for a segment then

View File

@ -3418,6 +3418,7 @@ static void update_golden_frame_stats(VP8_COMP *cpi)
}
#if !CONFIG_COMPRED
//#if 1
// This function updates the reference frame probability estimates that
// will be used during mode selection
static void update_rd_ref_frame_probs(VP8_COMP *cpi)
@ -3899,7 +3900,9 @@ static void update_refpred_stats( VP8_COMP *cpi )
cm->ref_pred_probs[0] = 120;
cm->ref_pred_probs[1] = 80;
cm->ref_pred_probs[2] = 40;
vpx_memset(cpi->ref_probs_update, 0, sizeof(cpi->ref_probs_update) );
vpx_memset(cpi->ref_pred_probs_update, 0,
sizeof(cpi->ref_pred_probs_update) );
}
else
{
@ -3988,11 +3991,11 @@ static void update_refpred_stats( VP8_COMP *cpi )
// Cost saving must be >= 8 bits (2048 in these units)
if ( (old_cost - new_cost) >= 2048 )
{
cpi->ref_probs_update[i] = 1;
cpi->ref_pred_probs_update[i] = 1;
cm->ref_pred_probs[i] = new_pred_probs[i];
}
else
cpi->ref_probs_update[i] = 0;
cpi->ref_pred_probs_update[i] = 0;
}
}
@ -4156,6 +4159,7 @@ static void encode_frame_to_data_rate
#endif
#if !CONFIG_COMPRED
//#if 1
update_rd_ref_frame_probs(cpi);
#endif

View File

@ -519,7 +519,7 @@ typedef struct VP8_COMP
int last_frame_percent_intra;
int ref_frame_flags;
unsigned char ref_probs_update[PREDICTION_PROBS];
unsigned char ref_pred_probs_update[PREDICTION_PROBS];
SPEED_FEATURES sf;
int error_bins[1024];