From 58ec6fe8c399c3f21e8e0ba368a80270581b2aa6 Mon Sep 17 00:00:00 2001 From: Paul Wilkins Date: Fri, 3 Feb 2012 13:46:18 +0000 Subject: [PATCH] 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 --- vp8/common/onyxc_int.h | 1 + vp8/common/pred_common.c | 135 ++++++++++++++------------------------ vp8/decoder/decodemv.c | 1 - vp8/encoder/bitstream.c | 113 ++++++++++++++----------------- vp8/encoder/encodeframe.c | 1 + vp8/encoder/onyx_if.c | 10 ++- vp8/encoder/onyx_int.h | 2 +- 7 files changed, 110 insertions(+), 153 deletions(-) diff --git a/vp8/common/onyxc_int.h b/vp8/common/onyxc_int.h index fd6a55801..a86635a7c 100644 --- a/vp8/common/onyxc_int.h +++ b/vp8/common/onyxc_int.h @@ -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 diff --git a/vp8/common/pred_common.c b/vp8/common/pred_common.c index e4cd037e8..bda140058 100644 --- a/vp8/common/pred_common.c +++ b/vp8/common/pred_common.c @@ -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,107 +162,68 @@ 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 - { - frame_allowed[INTRA_FRAME] = 1; - frame_allowed[LAST_FRAME] = 1; - frame_allowed[GOLDEN_FRAME] = 1; - frame_allowed[ALTREF_FRAME] = 1; - } + vpx_memcpy( ref_score, cm->ref_scores, sizeof(ref_score) ); - // 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) ) - { - pred_ref = left; - } - else if ( left_pred > above_pred ) + // 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 ) { - pred_ref = left; + ref_score[left] += 16; + if ( above_left_in_image && (left == above_left) ) + ref_score[left] += 4; } - else if ( above_pred > left_pred ) + if ( frame_allowed[above] && above_in_image ) { - pred_ref = above; + ref_score[above] += 16; + if ( above_left_in_image && (above == above_left) ) + ref_score[above] += 4; } - // If we reach this clause left_pred and above_pred must be the same - else if ( left_pred > 0 ) + + // Now choose the candidate with the highest score + for ( i = 0; i < MAX_REF_FRAMES; i++ ) { - // 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)) ) - { - pred_ref = LAST_FRAME; - } - else if ( frame_allowed[ALTREF_FRAME] && - ((left == ALTREF_FRAME) || (above == ALTREF_FRAME)) ) + if ( ref_score[i] > best_score ) { - 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; + pred_ref = i; + best_score = ref_score[i]; } } - // 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 diff --git a/vp8/decoder/decodemv.c b/vp8/decoder/decodemv.c index 432b339b1..4238e4d18 100644 --- a/vp8/decoder/decodemv.c +++ b/vp8/decoder/decodemv.c @@ -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) ); diff --git a/vp8/encoder/bitstream.c b/vp8/encoder/bitstream.c index 26f1cb487..3c0ea4c2b 100644 --- a/vp8/encoder/bitstream.c +++ b/vp8/encoder/bitstream.c @@ -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); diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c index 30352d719..2e5bd20c8 100644 --- a/vp8/encoder/encodeframe.c +++ b/vp8/encoder/encodeframe.c @@ -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 diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index 2ea41ab35..e3656e2d8 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -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 diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h index 214006cfd..cd2f25eaa 100644 --- a/vp8/encoder/onyx_int.h +++ b/vp8/encoder/onyx_int.h @@ -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]; -- 2.40.0