From cf561bad1d027da0b28b4cd75036942e97d4fef7 Mon Sep 17 00:00:00 2001 From: Paul Wilkins Date: Wed, 11 Jan 2012 14:05:57 +0000 Subject: [PATCH] Rate control on static scenes plus Y2dc delta Q fix. A problem can arise on static clips with force key frames where attempts to avoid popping lead to a progressive reduction in key frame Q that ultimately may lead to unexpected overspend against the rate target. The changes in this patch help to insure that in such clips the quality of the key frames across the clip is more uniform (rather than starting bad and getting better - especially at low target rates). This patch also includes a fix that removes a delta on the Y2DC when the baseline q index < 4 as this is no longer needed. There is also a fix to try and prevent repeat single step Q adjustment in the recode loop leading to lots of recodes, especially where the use of forced skips as part of segmentation has made the impact of Q on the number of bits generated much smaller. Patch 2: Amend "last_boosted_qindex" calculation for arf overlay frames. Change-Id: Ia1feeb79ed8ed014e4239994fcf5e58e68fd9459 --- vp8/encoder/firstpass.c | 24 ++++++++++--- vp8/encoder/mbgraph.c | 8 +++-- vp8/encoder/onyx_if.c | 79 ++++++++++++++++++++++++++++++++--------- vp8/encoder/onyx_int.h | 7 ++-- vp8/encoder/quantize.c | 26 ++++---------- vp8/encoder/ratectrl.c | 10 +++++- 6 files changed, 106 insertions(+), 48 deletions(-) diff --git a/vp8/encoder/firstpass.c b/vp8/encoder/firstpass.c index 901404617..19ae70684 100644 --- a/vp8/encoder/firstpass.c +++ b/vp8/encoder/firstpass.c @@ -3032,10 +3032,26 @@ static void find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame) // We do three calculations for kf size. // The first is based on the error score for the whole kf group. - // The second (optionaly) on the key frames own error if this is smaller than the average for the group. - // The final one insures that the frame receives at least the allocation it would have received based on its own error score vs the error score remaining - - allocation_chunks = ((cpi->twopass.frames_to_key - 1) * 100) + kf_boost; // cpi->twopass.frames_to_key-1 because key frame itself is taken care of by kf_boost + // The second (optionaly) on the key frames own error if this is + // smaller than the average for the group. + // The final one insures that the frame receives at least the + // allocation it would have received based on its own error score vs + // the error score remaining + // Special case if the sequence appears almost totaly static + // as measured by the decay accumulator. In this case we want to + // spend almost all of the bits on the key frame. + // cpi->twopass.frames_to_key-1 because key frame itself is taken + // care of by kf_boost. + if ( decay_accumulator >= 0.99 ) + { + allocation_chunks = + ((cpi->twopass.frames_to_key - 1) * 10) + kf_boost; + } + else + { + allocation_chunks = + ((cpi->twopass.frames_to_key - 1) * 100) + kf_boost; + } // Normalize Altboost and allocations chunck down to prevent overflow while (kf_boost > 1000) diff --git a/vp8/encoder/mbgraph.c b/vp8/encoder/mbgraph.c index ad40c9e33..4f9ba125b 100644 --- a/vp8/encoder/mbgraph.c +++ b/vp8/encoder/mbgraph.c @@ -477,12 +477,16 @@ void separate_arf_mbs //if ( ncnt[1] && (ncnt[0] / ncnt[1] < 10) ) if ( 1 ) { - cpi->mbgraph_use_arf_segmentation = ncnt[1]; + // Note % of blocks that are marked as static + cpi->static_mb_pct = + (ncnt[1] * 100) / cm->MBs; + vp8_enable_segmentation((VP8_PTR) cpi); } else { - cpi->mbgraph_use_arf_segmentation = 0; + cpi->static_mb_pct = 0; + vp8_disable_segmentation((VP8_PTR) cpi); } diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index b60d996a8..25b56691d 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -492,6 +492,7 @@ static void init_seg_features(VP8_COMP *cpi) vpx_memset( cpi->segmentation_map, 0, (cm->mb_rows * cm->mb_cols)); xd->update_mb_segmentation_map = 0; xd->update_mb_segmentation_data = 0; + cpi->static_mb_pct = 0; // Disable segmentation vp8_disable_segmentation((VP8_PTR)cpi); @@ -507,6 +508,7 @@ static void init_seg_features(VP8_COMP *cpi) vpx_memset( cpi->segmentation_map, 0, (cm->mb_rows * cm->mb_cols)); xd->update_mb_segmentation_map = 0; xd->update_mb_segmentation_data = 0; + cpi->static_mb_pct = 0; // Disable segmentation and individual segment features by default vp8_disable_segmentation((VP8_PTR)cpi); @@ -557,7 +559,7 @@ static void init_seg_features(VP8_COMP *cpi) set_segdata( xd, 1, SEG_LVL_ALT_LF, -2 ); enable_segfeature(xd, 1, SEG_LVL_ALT_LF); - if ( high_q ) + if ( high_q || (cpi->static_mb_pct == 100) ) { set_segref(xd, 1, ALTREF_FRAME); enable_segfeature(xd, 1, SEG_LVL_REF_FRAME); @@ -1973,6 +1975,8 @@ static void init_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cpi->total_actual_bits = 0; cpi->total_target_vs_actual = 0; + cpi->static_mb_pct = 0; + #if VP8_TEMPORAL_ALT_REF { int i; @@ -2233,6 +2237,7 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) { cpi->last_q[0] = cpi->oxcf.fixed_q; cpi->last_q[1] = cpi->oxcf.fixed_q; + cpi->last_boosted_qindex = cpi->oxcf.fixed_q; } cpi->Speed = cpi->oxcf.cpu_used; @@ -2694,6 +2699,9 @@ void vp8_remove_compressor(VP8_PTR *ptr) fprintf(f, "%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%8.0f\n", dr, cpi->total / cpi->count, total_psnr, cpi->totalp / cpi->count, total_psnr2, total_ssim, total_encode_time); +// fprintf(f, "%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%8.0f %10ld\n", +// dr, cpi->total / cpi->count, total_psnr, cpi->totalp / cpi->count, total_psnr2, total_ssim, +// total_encode_time, cpi->tot_recode_hits); } if (cpi->b_calculate_ssimg) @@ -2702,6 +2710,9 @@ void vp8_remove_compressor(VP8_PTR *ptr) fprintf(f, "%7.3f\t%6.4f\t%6.4f\t%6.4f\t%6.4f\t%8.0f\n", dr, cpi->total_ssimg_y / cpi->count, cpi->total_ssimg_u / cpi->count, cpi->total_ssimg_v / cpi->count, cpi->total_ssimg_all / cpi->count, total_encode_time); +// fprintf(f, "%7.3f\t%6.4f\t%6.4f\t%6.4f\t%6.4f\t%8.0f %10ld\n", dr, +// cpi->total_ssimg_y / cpi->count, cpi->total_ssimg_u / cpi->count, +// cpi->total_ssimg_v / cpi->count, cpi->total_ssimg_all / cpi->count, total_encode_time, cpi->tot_recode_hits); } fclose(f); @@ -4134,10 +4145,15 @@ static void encode_frame_to_data_rate // based on the ambient Q to reduce the risk of popping if ( cpi->this_key_frame_forced ) { - if ( cpi->active_best_quality > cpi->avg_frame_qindex * 7/8) - cpi->active_best_quality = cpi->avg_frame_qindex * 7/8; - else if ( cpi->active_best_quality < cpi->avg_frame_qindex >> 2 ) - cpi->active_best_quality = cpi->avg_frame_qindex >> 2; + int delta_qindex; + int qindex = cpi->last_boosted_qindex; + + delta_qindex = compute_qdelta( cpi, qindex, + (qindex * 0.75) ); + + cpi->active_best_quality = qindex + delta_qindex; + if (cpi->active_best_quality < cpi->best_quality) + cpi->active_best_quality = cpi->best_quality; } } // One pass more conservative @@ -4248,8 +4264,16 @@ static void encode_frame_to_data_rate if ( cpi->active_worst_quality < cpi->active_best_quality ) cpi->active_worst_quality = cpi->active_best_quality; - // Determine initial Q to try - Q = vp8_regulate_q(cpi, cpi->this_frame_target); + // Specuial case code to try and match quality with forced key frames + if ( (cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced ) + { + Q = cpi->last_boosted_qindex; + } + else + { + // Determine initial Q to try + Q = vp8_regulate_q(cpi, cpi->this_frame_target); + } last_zbin_oq = cpi->zbin_over_quant; // Set highest allowed value for Zbin over quant @@ -4527,23 +4551,32 @@ static void encode_frame_to_data_rate &cm->yv12_fb[cm->new_fb_idx], IF_RTCD(&cpi->rtcd.variance)); + int high_err_target = cpi->ambient_err; + int low_err_target = ((cpi->ambient_err * 3) >> 2); + // The key frame is not good enough - if ( kf_err > ((cpi->ambient_err * 7) >> 3) ) + if ( (kf_err > high_err_target) && + (cpi->projected_frame_size <= frame_over_shoot_limit) ) { // Lower q_high q_high = (Q > q_low) ? (Q - 1) : q_low; // Adjust Q - Q = (q_high + q_low) >> 1; + Q = (Q * high_err_target) / kf_err; + if ( Q < ((q_high + q_low) >> 1)) + Q = (q_high + q_low) >> 1; } // The key frame is much better than the previous frame - else if ( kf_err < (cpi->ambient_err >> 1) ) + else if ( (kf_err < low_err_target) && + (cpi->projected_frame_size >= frame_under_shoot_limit) ) { // Raise q_low q_low = (Q < q_high) ? (Q + 1) : q_high; // Adjust Q - Q = (q_high + q_low + 1) >> 1; + Q = (Q * low_err_target) / kf_err; + if ( Q > ((q_high + q_low + 1) >> 1)) + Q = (q_high + q_low + 1) >> 1; } // Clamp Q to upper and lower limits: @@ -4569,14 +4602,12 @@ static void encode_frame_to_data_rate // Frame is too large if (cpi->projected_frame_size > cpi->this_frame_target) { - //if ( cpi->zbin_over_quant == 0 ) q_low = (Q < q_high) ? (Q + 1) : q_high; // Raise Qlow as to at least the current value if (cpi->zbin_over_quant > 0) // If we are using over quant do the same for zbin_oq_low zbin_oq_low = (cpi->zbin_over_quant < zbin_oq_high) ? (cpi->zbin_over_quant + 1) : zbin_oq_high; - //if ( undershoot_seen || (Q == MAXQ) ) - if (undershoot_seen) + if ( undershoot_seen || (loop_count > 1) ) { // Update rate_correction_factor unless cpi->active_worst_quality has changed. if (!active_worst_qchanged) @@ -4619,7 +4650,7 @@ static void encode_frame_to_data_rate else // else lower zbin_oq_high zbin_oq_high = (cpi->zbin_over_quant > zbin_oq_low) ? (cpi->zbin_over_quant - 1) : zbin_oq_low; - if (overshoot_seen) + if ( overshoot_seen || (loop_count > 1) ) { // Update rate_correction_factor unless cpi->active_worst_quality has changed. if (!active_worst_qchanged) @@ -4845,6 +4876,20 @@ static void encode_frame_to_data_rate cpi->last_q[cm->frame_type] = cm->base_qindex; + // Keep record of last boosted (KF/KF/ARF) Q value. + // If the current frame is coded at a lower Q then we also update it. + // If all mbs in this group are skipped only update if the Q value is + // better than that already stored. + // This is used to help set quality in forced key frames to reduce popping + if ( (cm->base_qindex < cpi->last_boosted_qindex) || + ( (cpi->static_mb_pct < 100) && + ( (cm->frame_type == KEY_FRAME) || + cm->refresh_alt_ref_frame || + (cm->refresh_golden_frame && !cpi->is_src_frame_alt_ref) ) ) ) + { + cpi->last_boosted_qindex = cm->base_qindex; + } + if (cm->frame_type == KEY_FRAME) { vp8_adjust_key_frame_context(cpi); @@ -4991,7 +5036,7 @@ static void encode_frame_to_data_rate if (cpi->twopass.total_left_stats->coded_error != 0.0) fprintf(f, "%10d %10d %10d %10d %10d %10d %10d" - "%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f" + "%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f" "%6d %5d %5d %5d %8d %8.2f %10d %10.3f" "%10.3f %8d\n", cpi->common.current_video_frame, cpi->this_frame_target, @@ -5023,7 +5068,7 @@ static void encode_frame_to_data_rate cpi->tot_recode_hits); else fprintf(f, "%10d %10d %10d %10d %10d %10d %10d" - "%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f" + "%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f" "%6d %5d %5d %5d %8d %8.2f %10d %10.3f" "%8d\n", cpi->common.current_video_frame, diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h index f47a46408..002f30a97 100644 --- a/vp8/encoder/onyx_int.h +++ b/vp8/encoder/onyx_int.h @@ -383,6 +383,7 @@ typedef struct VP8_COMP int this_frame_target; int projected_frame_size; int last_q[2]; // Separate values for Intra/Inter + int last_boosted_qindex; // Last boosted GF/KF/ARF q double rate_correction_factor; double key_frame_rate_correction_factor; @@ -483,11 +484,7 @@ typedef struct VP8_COMP #endif MBGRAPH_FRAME_STATS mbgraph_stats[MAX_LAG_BUFFERS]; int mbgraph_n_frames; // number of frames filled in the above - int mbgraph_use_arf_segmentation; // set if part of an ARF is considered to be a - // poor predictor, and thus coeffs are skipped - // or coded at a higher Q using MB-segmentation - // this value is the number of MBs that are - // poor predictors (> 0 and < common.MBs) + int static_mb_pct; // % forced skip mbs by segmentation int decimation_factor; int decimation_count; diff --git a/vp8/encoder/quantize.c b/vp8/encoder/quantize.c index 68b10cc4c..d7316f74e 100644 --- a/vp8/encoder/quantize.c +++ b/vp8/encoder/quantize.c @@ -1271,30 +1271,18 @@ void vp8cx_frame_init_quantizer(VP8_COMP *cpi) void vp8_set_quantizer(struct VP8_COMP *cpi, int Q) { VP8_COMMON *cm = &cpi->common; - int update = 0; - int new_delta_q; - cm->base_qindex = Q; - - /* if any of the delta_q values are changing update flag has to be set */ - /* currently only y2dc_delta_q may change */ + // if any of the delta_q values are changing update flag will + // have to be set. cm->y1dc_delta_q = 0; cm->y2ac_delta_q = 0; cm->uvdc_delta_q = 0; cm->uvac_delta_q = 0; + cm->y2dc_delta_q = 0; - if (Q < 4) - { - new_delta_q = 4-Q; - } - else - new_delta_q = 0; - - update |= cm->y2dc_delta_q != new_delta_q; - cm->y2dc_delta_q = new_delta_q; - - /* quantizer has to be reinitialized for any delta_q changes */ - if(update) - vp8cx_init_quantizer(cpi); + // quantizer has to be reinitialized if any delta_q changes. + // As there are not any here for now this is inactive code. + //if(update) + // vp8cx_init_quantizer(cpi); } diff --git a/vp8/encoder/ratectrl.c b/vp8/encoder/ratectrl.c index d2e680f89..fd3f8d7b2 100644 --- a/vp8/encoder/ratectrl.c +++ b/vp8/encoder/ratectrl.c @@ -24,7 +24,7 @@ #include "encodemv.h" -#define MIN_BPB_FACTOR 0.01 +#define MIN_BPB_FACTOR 0.005 #define MAX_BPB_FACTOR 50 extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES]; @@ -1477,6 +1477,14 @@ void vp8_compute_frame_size_bounds(VP8_COMP *cpi, int *frame_under_shoot_limit, } } } + + // For very small rate targets where the fractional adjustment + // (eg * 7/8) may be tiny make sure there is at least a minimum + // range. + *frame_over_shoot_limit += 200; + *frame_under_shoot_limit -= 200; + if ( *frame_under_shoot_limit < 0 ) + *frame_under_shoot_limit = 0; } }