From 2ae91fbef0da3d4f677b15342e7d0e18598f5ada Mon Sep 17 00:00:00 2001 From: Paul Wilkins Date: Thu, 10 Mar 2011 16:11:39 +0000 Subject: [PATCH] 1 Pass CQ and VBR bug fixes Issue 291 highlighted the fact that CQ mode was not working as expected in 1 pass mode, This commit fixes that specific problem but in so doing I also uncovered an overflow issue in the VBR code for 1 pass and some data values not being correctly initialized. For some clips (particularly short clips), the resulting improvement is dramatic. Change-Id: Ieefd6c6e4776eb8f1b0550dbfdfb72f86b33c960 --- vp8/encoder/onyx_if.c | 62 +++++++++++++++++++++++++++------------- vp8/encoder/ratectrl.c | 77 ++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 98 insertions(+), 41 deletions(-) diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index 797e18b..9b49f2d 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -1516,9 +1516,15 @@ void vp8_init_config(VP8_PTR ptr, VP8_CONFIG *oxcf) else cpi->oxcf = *oxcf; + // change includes all joint functionality + vp8_change_config(ptr, oxcf); - // Convert target bandwidth from Kbit/s to Bit/s - cpi->oxcf.target_bandwidth *= 1000; + // Initialize active best and worst q and average q values. + cpi->active_worst_quality = cpi->oxcf.worst_allowed_q; + cpi->active_best_quality = cpi->oxcf.best_allowed_q; + cpi->avg_frame_qindex = cpi->oxcf.worst_allowed_q; + + // Initialise the starting buffer levels cpi->oxcf.starting_buffer_level = rescale(cpi->oxcf.starting_buffer_level, cpi->oxcf.target_bandwidth, 1000); @@ -1526,10 +1532,6 @@ void vp8_init_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cpi->buffer_level = cpi->oxcf.starting_buffer_level; cpi->bits_off_target = cpi->oxcf.starting_buffer_level; - cpi->active_worst_quality = cpi->oxcf.worst_allowed_q; - cpi->active_best_quality = cpi->oxcf.best_allowed_q; - cpi->avg_frame_qindex = cpi->oxcf.worst_allowed_q; - cpi->rolling_target_bits = cpi->av_per_frame_bandwidth; cpi->rolling_actual_bits = cpi->av_per_frame_bandwidth; cpi->long_rolling_target_bits = cpi->av_per_frame_bandwidth; @@ -1538,9 +1540,6 @@ void vp8_init_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cpi->total_actual_bits = 0; cpi->total_target_vs_actual = 0; - // change includes all joint functionality - vp8_change_config(ptr, oxcf); - #if VP8_TEMPORAL_ALT_REF cpi->use_weighted_temporal_filter = 0; @@ -1668,7 +1667,8 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) } - cpi->baseline_gf_interval = cpi->oxcf.alt_freq ? cpi->oxcf.alt_freq : DEFAULT_GF_INTERVAL; + cpi->baseline_gf_interval = + cpi->oxcf.alt_freq ? cpi->oxcf.alt_freq : DEFAULT_GF_INTERVAL; cpi->ref_frame_flags = VP8_ALT_FLAG | VP8_GOLD_FLAG | VP8_LAST_FLAG; @@ -1679,7 +1679,8 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cm->refresh_entropy_probs = 1; if (cpi->oxcf.token_partitions >= 0 && cpi->oxcf.token_partitions <= 3) - cm->multi_token_partition = (TOKEN_PARTITION) cpi->oxcf.token_partitions; + cm->multi_token_partition = + (TOKEN_PARTITION) cpi->oxcf.token_partitions; setup_features(cpi); @@ -1700,12 +1701,12 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cpi->oxcf.starting_buffer_level = 60000; cpi->oxcf.optimal_buffer_level = 60000; cpi->oxcf.maximum_buffer_size = 240000; - } // Convert target bandwidth from Kbit/s to Bit/s cpi->oxcf.target_bandwidth *= 1000; + // Set or reset optimal and maximum buffer levels. if (cpi->oxcf.optimal_buffer_level == 0) cpi->oxcf.optimal_buffer_level = cpi->oxcf.target_bandwidth / 8; else @@ -1720,7 +1721,10 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) rescale(cpi->oxcf.maximum_buffer_size, cpi->oxcf.target_bandwidth, 1000); + // Set up frame rate and related parameters rate control values. vp8_new_frame_rate(cpi, cpi->oxcf.frame_rate); + + // Set absolute upper and lower quality limits cpi->worst_quality = cpi->oxcf.worst_allowed_q; cpi->best_quality = cpi->oxcf.best_allowed_q; @@ -1749,9 +1753,9 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cpi->cq_target_quality = cpi->oxcf.cq_level; // Only allow dropped frames in buffered mode - cpi->drop_frames_allowed = cpi->oxcf.allow_df && cpi->buffered_mode; + cpi->drop_frames_allowed = cpi->oxcf.allow_df && cpi->buffered_mode; - cm->filter_type = (LOOPFILTERTYPE) cpi->filter_type; + cm->filter_type = (LOOPFILTERTYPE) cpi->filter_type; if (!cm->use_bilinear_mc_filter) cm->mcomp_filter_type = SIXTAP; @@ -1766,7 +1770,8 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cm->horiz_scale = cpi->horiz_scale; cm->vert_scale = cpi->vert_scale ; - cpi->intra_frame_target = (4 * (cm->Width + cm->Height) / 15) * 1000; // As per VP8 + // As per VP8 + cpi->intra_frame_target = (4 * (cm->Width + cm->Height) / 15) * 1000; // VP8 sharpness level mapping 0-7 (vs 0-10 in general VPx dialogs) if (cpi->oxcf.Sharpness > 7) @@ -1787,8 +1792,10 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf) cm->Height = (vs - 1 + cpi->oxcf.Height * vr) / vs; } - if (((cm->Width + 15) & 0xfffffff0) != cm->yv12_fb[cm->lst_fb_idx].y_width || - ((cm->Height + 15) & 0xfffffff0) != cm->yv12_fb[cm->lst_fb_idx].y_height || + if (((cm->Width + 15) & 0xfffffff0) != + cm->yv12_fb[cm->lst_fb_idx].y_width || + ((cm->Height + 15) & 0xfffffff0) != + cm->yv12_fb[cm->lst_fb_idx].y_height || cm->yv12_fb[cm->lst_fb_idx].y_width == 0) { alloc_raw_frame_buffers(cpi); @@ -3637,11 +3644,12 @@ static void encode_frame_to_data_rate } } - // If CBR and the buffer is as full then it is reasonable to allow higher quality on the frames - // to prevent bits just going to waste. + // If CBR and the buffer is as full then it is reasonable to allow + // higher quality on the frames to prevent bits just going to waste. if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) { - // Note that the use of >= here elliminates the risk of a devide by 0 error in the else if clause + // Note that the use of >= here elliminates the risk of a devide + // by 0 error in the else if clause if (cpi->buffer_level >= cpi->oxcf.maximum_buffer_size) cpi->active_best_quality = cpi->best_quality; @@ -3654,6 +3662,20 @@ static void encode_frame_to_data_rate } } } + // Make sure constrained quality mode limits are adhered to for the first + // few frames of one pass encodes + else if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) + { + if ( (cm->frame_type == KEY_FRAME) || + cm->refresh_golden_frame || cpi->common.refresh_alt_ref_frame ) + { + cpi->active_best_quality = cpi->best_quality; + } + else if (cpi->active_best_quality < cpi->cq_target_quality) + { + cpi->active_best_quality = cpi->cq_target_quality; + } + } // Clip the active best and worst quality values to limits if (cpi->active_worst_quality > cpi->worst_quality) diff --git a/vp8/encoder/ratectrl.c b/vp8/encoder/ratectrl.c index bfffe43..9797f5f 100644 --- a/vp8/encoder/ratectrl.c +++ b/vp8/encoder/ratectrl.c @@ -842,7 +842,8 @@ void vp8_calc_pframe_target_size(VP8_COMP *cpi) { int one_percent_bits = 1 + cpi->oxcf.optimal_buffer_level / 100; - if ((cpi->buffer_level < cpi->oxcf.optimal_buffer_level) || (cpi->bits_off_target < cpi->oxcf.optimal_buffer_level)) + if ((cpi->buffer_level < cpi->oxcf.optimal_buffer_level) || + (cpi->bits_off_target < cpi->oxcf.optimal_buffer_level)) { int percent_low = 0; @@ -851,9 +852,12 @@ void vp8_calc_pframe_target_size(VP8_COMP *cpi) // If we are are below the optimal buffer fullness level and adherence // to buffering contraints is important to the end useage then adjust // the per frame target. - if ((cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) && (cpi->buffer_level < cpi->oxcf.optimal_buffer_level)) + if ((cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) && + (cpi->buffer_level < cpi->oxcf.optimal_buffer_level)) { - percent_low = (cpi->oxcf.optimal_buffer_level - cpi->buffer_level) / one_percent_bits; + percent_low = + (cpi->oxcf.optimal_buffer_level - cpi->buffer_level) / + one_percent_bits; if (percent_low > 100) percent_low = 100; @@ -864,7 +868,8 @@ void vp8_calc_pframe_target_size(VP8_COMP *cpi) else if (cpi->bits_off_target < 0) { // Adjust per frame data target downwards to compensate. - percent_low = (int)(100 * -cpi->bits_off_target / (cpi->total_byte_count * 8)); + percent_low = (int)(100 * -cpi->bits_off_target / + (cpi->total_byte_count * 8)); if (percent_low > 100) percent_low = 100; @@ -873,39 +878,60 @@ void vp8_calc_pframe_target_size(VP8_COMP *cpi) } // lower the target bandwidth for this frame. - cpi->this_frame_target = (cpi->this_frame_target * (100 - (percent_low / 2))) / 100; + cpi->this_frame_target = + (cpi->this_frame_target * (100 - (percent_low / 2))) / 100; - // Are we using allowing control of active_worst_allowed_q according to buffer level. + // Are we using allowing control of active_worst_allowed_q + // according to buffer level. if (cpi->auto_worst_q) { int critical_buffer_level; - // For streaming applications the most important factor is cpi->buffer_level as this takes - // into account the specified short term buffering constraints. However, hitting the long - // term clip data rate target is also important. + // For streaming applications the most important factor is + // cpi->buffer_level as this takes into account the + // specified short term buffering constraints. However, + // hitting the long term clip data rate target is also + // important. if (cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) { - // Take the smaller of cpi->buffer_level and cpi->bits_off_target - critical_buffer_level = (cpi->buffer_level < cpi->bits_off_target) ? cpi->buffer_level : cpi->bits_off_target; + // Take the smaller of cpi->buffer_level and + // cpi->bits_off_target + critical_buffer_level = + (cpi->buffer_level < cpi->bits_off_target) + ? cpi->buffer_level : cpi->bits_off_target; } - // For local file playback short term buffering contraints are less of an issue + // For local file playback short term buffering contraints + // are less of an issue else { - // Consider only how we are doing for the clip as a whole + // Consider only how we are doing for the clip as a + // whole critical_buffer_level = cpi->bits_off_target; } - // Set the active worst quality based upon the selected buffer fullness number. + // Set the active worst quality based upon the selected + // buffer fullness number. if (critical_buffer_level < cpi->oxcf.optimal_buffer_level) { - if (critical_buffer_level > (cpi->oxcf.optimal_buffer_level / 4)) + if ( critical_buffer_level > + (cpi->oxcf.optimal_buffer_level >> 2) ) { - int qadjustment_range = cpi->worst_quality - cpi->ni_av_qi; - int above_base = (critical_buffer_level - (cpi->oxcf.optimal_buffer_level / 4)); - - // Step active worst quality down from cpi->ni_av_qi when (critical_buffer_level == cpi->optimal_buffer_level) - // to cpi->oxcf.worst_allowed_q when (critical_buffer_level == cpi->optimal_buffer_level/4) - cpi->active_worst_quality = cpi->worst_quality - ((qadjustment_range * above_base) / (cpi->oxcf.optimal_buffer_level * 3 / 4)); + INT64 qadjustment_range = + cpi->worst_quality - cpi->ni_av_qi; + INT64 above_base = + (critical_buffer_level - + (cpi->oxcf.optimal_buffer_level >> 2)); + + // Step active worst quality down from + // cpi->ni_av_qi when (critical_buffer_level == + // cpi->optimal_buffer_level) to + // cpi->worst_quality when + // (critical_buffer_level == + // cpi->optimal_buffer_level >> 2) + cpi->active_worst_quality = + cpi->worst_quality - + ((qadjustment_range * above_base) / + (cpi->oxcf.optimal_buffer_level*3>>2)); } else { @@ -965,6 +991,15 @@ void vp8_calc_pframe_target_size(VP8_COMP *cpi) // Set the active worst quality cpi->active_worst_quality = cpi->worst_quality; } + + // Special trap for constrained quality mode + // "active_worst_quality" may never drop below cq level + // for any frame type. + if ( cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY && + cpi->active_worst_quality < cpi->cq_target_quality) + { + cpi->active_worst_quality = cpi->cq_target_quality; + } } // Test to see if we have to drop a frame -- 2.7.4