diff options
author | Marco Paniconi <marpan@google.com> | 2013-12-17 15:45:30 -0800 |
---|---|---|
committer | Marco Paniconi <marpan@google.com> | 2013-12-18 09:24:24 -0800 |
commit | 1b8b8b0d0df9ac6f0a50db73d20231ecb7529666 (patch) | |
tree | c6bff1ad5d4e34e7f0f1f44a00004ea222a2e230 /vp9/encoder | |
parent | d2f49407830de9dbc466f03fcdc90d379a3c0269 (diff) | |
download | libvpx-1b8b8b0d0df9ac6f0a50db73d20231ecb7529666.tar libvpx-1b8b8b0d0df9ac6f0a50db73d20231ecb7529666.tar.gz libvpx-1b8b8b0d0df9ac6f0a50db73d20231ecb7529666.tar.bz2 libvpx-1b8b8b0d0df9ac6f0a50db73d20231ecb7529666.zip |
Updates for 1-pass CBR rate control.
Adjustments based on buffer level, frame dropper.
Change-Id: Iaa85b570493526a60c4b9fb7ded4c0226b1b3a33
Diffstat (limited to 'vp9/encoder')
-rw-r--r-- | vp9/encoder/vp9_onyx_if.c | 19 | ||||
-rw-r--r-- | vp9/encoder/vp9_onyx_int.h | 6 | ||||
-rw-r--r-- | vp9/encoder/vp9_ratectrl.c | 202 | ||||
-rw-r--r-- | vp9/encoder/vp9_ratectrl.h | 6 |
4 files changed, 200 insertions, 33 deletions
diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c index 5bbd42bea..daf44658d 100644 --- a/vp9/encoder/vp9_onyx_if.c +++ b/vp9/encoder/vp9_onyx_if.c @@ -2987,6 +2987,20 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, configure_static_seg_features(cpi); } + // For 1 pass CBR, check if we are dropping this frame. + // Never drop on key frame. + if (cpi->pass == 0 && + cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER && + cm->frame_type != KEY_FRAME) { + if (vp9_drop_frame(cpi)) { + // Update buffer level with zero size, update frame counters, and return. + vp9_update_buffer_level(cpi, 0); + cm->current_video_frame++; + cpi->rc.frames_since_key++; + return; + } + } + vp9_clear_system_state(); vp9_zero(cpi->rd_tx_select_threshes); @@ -3587,6 +3601,11 @@ int vp9_get_compressed_data(VP9_PTR ptr, unsigned int *frame_flags, if (cm->refresh_frame_context) cm->frame_contexts[cm->frame_context_idx] = cm->fc; + // Frame was dropped, release scaled references. + if (*size == 0) { + release_scaled_references(cpi); + } + if (*size > 0) { // if its a dropped frame honor the requests on subsequent frames cpi->droppable = !frame_is_reference(cpi); diff --git a/vp9/encoder/vp9_onyx_int.h b/vp9/encoder/vp9_onyx_int.h index 2d7cd01f4..13ce1cc24 100644 --- a/vp9/encoder/vp9_onyx_int.h +++ b/vp9/encoder/vp9_onyx_int.h @@ -331,6 +331,9 @@ typedef struct { int buffer_level; int bits_off_target; + int decimation_factor; + int decimation_count; + int rolling_target_bits; int rolling_actual_bits; @@ -480,9 +483,6 @@ typedef struct VP9_COMP { int static_mb_pct; // % forced skip mbs by segmentation int seg0_progress, seg0_idx, seg0_cnt; - int decimation_factor; - int decimation_count; - // for real time encoding int speed; int compressor_speed; diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index 9ea0c3ddf..ca7d6c64c 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -222,6 +222,31 @@ static void calc_iframe_target_size(VP9_COMP *cpi) { // New Two pass RC target = cpi->rc.per_frame_bandwidth; + // For 1-pass. + if (cpi->pass == 0) { + if (cpi->common.current_video_frame == 0) { + target = cpi->oxcf.starting_buffer_level / 2; + } else { + // TODO(marpan): Add in adjustment based on Q. + // If this keyframe was forced, use a more recent Q estimate. + // int Q = (cpi->common.frame_flags & FRAMEFLAGS_KEY) ? + // cpi->rc.avg_frame_qindex : cpi->rc.ni_av_qi; + int initial_boost = 32; + // Boost depends somewhat on frame rate. + int kf_boost = MAX(initial_boost, (int)(2 * cpi->output_framerate - 16)); + // Adjustment up based on q: need to fix. + // kf_boost = kf_boost * kfboost_qadjust(Q) / 100; + // Frame separation adjustment (down). + if (cpi->rc.frames_since_key < cpi->output_framerate / 2) { + kf_boost = (int)(kf_boost * cpi->rc.frames_since_key / + (cpi->output_framerate / 2)); + } + kf_boost = (kf_boost < 16) ? 16 : kf_boost; + target = ((16 + kf_boost) * cpi->rc.per_frame_bandwidth) >> 4; + } + cpi->rc.active_worst_quality = cpi->rc.worst_quality; + } + if (cpi->oxcf.rc_max_intra_bitrate_pct) { int max_rate = cpi->rc.per_frame_bandwidth * cpi->oxcf.rc_max_intra_bitrate_pct / 100; @@ -242,18 +267,154 @@ static void calc_gf_params(VP9_COMP *cpi) { cpi->rc.frames_till_gf_update_due = cpi->rc.baseline_gf_interval; } +// Update the buffer level: leaky bucket model. +void vp9_update_buffer_level(VP9_COMP *const cpi, int encoded_frame_size) { + VP9_COMMON *const cm = &cpi->common; + // Non-viewable frames are a special case and are treated as pure overhead. + if (!cm->show_frame) { + cpi->rc.bits_off_target -= encoded_frame_size; + } else { + cpi->rc.bits_off_target += cpi->rc.av_per_frame_bandwidth - + encoded_frame_size; + } + // Clip the buffer level to the maximum specified buffer size. + if (cpi->rc.bits_off_target > cpi->oxcf.maximum_buffer_size) { + cpi->rc.bits_off_target = cpi->oxcf.maximum_buffer_size; + } + cpi->rc.buffer_level = cpi->rc.bits_off_target; +} + +int vp9_drop_frame(VP9_COMP *const cpi) { + if (!cpi->oxcf.drop_frames_water_mark) { + return 0; + } else { + if (cpi->rc.buffer_level < 0) { + // Always drop if buffer is below 0. + return 1; + } else { + // If buffer is below drop_mark, for now just drop every other frame + // (starting with the next frame) until it increases back over drop_mark. + int drop_mark = (int)(cpi->oxcf.drop_frames_water_mark * + cpi->oxcf.optimal_buffer_level / 100); + if ((cpi->rc.buffer_level > drop_mark) && + (cpi->rc.decimation_factor > 0)) { + --cpi->rc.decimation_factor; + } else if (cpi->rc.buffer_level <= drop_mark && + cpi->rc.decimation_factor == 0) { + cpi->rc.decimation_factor = 1; + } + if (cpi->rc.decimation_factor > 0) { + if (cpi->rc.decimation_count > 0) { + --cpi->rc.decimation_count; + return 1; + } else { + cpi->rc.decimation_count = cpi->rc.decimation_factor; + return 0; + } + } else { + cpi->rc.decimation_count = 0; + return 0; + } + } + } +} + +// Adjust active_worst_quality level based on buffer level. +static int adjust_active_worst_quality_from_buffer_level(const VP9_COMP *cpi) { + // Adjust active_worst_quality: If buffer is above the optimal/target level, + // bring active_worst_quality down depending on fullness over buffer. + // If buffer is below the optimal level, let the active_worst_quality go from + // ambient Q (at buffer = optimal level) to worst_quality level + // (at buffer = critical level). + int active_worst_quality = cpi->rc.active_worst_quality; + // Maximum limit for down adjustment, ~20%. + int max_adjustment_down = active_worst_quality / 5; + // Buffer level below which we push active_worst to worst_quality. + int critical_level = cpi->oxcf.optimal_buffer_level >> 2; + int adjustment = 0; + int buff_lvl_step = 0; + if (cpi->rc.buffer_level > cpi->oxcf.optimal_buffer_level) { + // Adjust down. + if (max_adjustment_down) { + buff_lvl_step = (int)((cpi->oxcf.maximum_buffer_size - + cpi->oxcf.optimal_buffer_level) / max_adjustment_down); + if (buff_lvl_step) { + adjustment = (int)((cpi->rc.buffer_level - + cpi->oxcf.optimal_buffer_level) / buff_lvl_step); + } + active_worst_quality -= adjustment; + } + } else if (cpi->rc.buffer_level > critical_level) { + // Adjust up from ambient Q. + if (critical_level) { + buff_lvl_step = (cpi->oxcf.optimal_buffer_level - critical_level); + if (buff_lvl_step) { + adjustment = + (cpi->rc.worst_quality - cpi->rc.avg_frame_qindex[INTER_FRAME]) * + (cpi->oxcf.optimal_buffer_level - cpi->rc.buffer_level) / + buff_lvl_step; + } + active_worst_quality = cpi->rc.avg_frame_qindex[INTER_FRAME] + adjustment; + } + } else { + // Set to worst_quality if buffer is below critical level. + active_worst_quality = cpi->rc.worst_quality; + } + return active_worst_quality; +} + +// Adjust target frame size with respect to the buffering constraints: +static int target_size_from_buffer_level(const VP9_COMP *cpi) { + int this_frame_target = cpi->rc.this_frame_target; + int percent_low = 0; + int percent_high = 0; + int one_percent_bits = (int)(1 + cpi->oxcf.optimal_buffer_level / 100); + if (cpi->rc.buffer_level < cpi->oxcf.optimal_buffer_level) { + percent_low = (int)((cpi->oxcf.optimal_buffer_level - cpi->rc.buffer_level) + / one_percent_bits); + if (percent_low > cpi->oxcf.under_shoot_pct) { + percent_low = cpi->oxcf.under_shoot_pct; + } else if (percent_low < 0) { + percent_low = 0; + } + // Lower the target bandwidth for this frame. + this_frame_target -= (this_frame_target * percent_low) / 200; + } else if (cpi->rc.buffer_level > cpi->oxcf.optimal_buffer_level) { + percent_high = (int)((cpi->rc.buffer_level - cpi->oxcf.optimal_buffer_level) + / one_percent_bits); + if (percent_high > cpi->oxcf.over_shoot_pct) { + percent_high = cpi->oxcf.over_shoot_pct; + } else if (percent_high < 0) { + percent_high = 0; + } + // Increase the target bandwidth for this frame. + this_frame_target += (this_frame_target * percent_high) / 200; + } + return this_frame_target; +} -static void calc_pframe_target_size(VP9_COMP *cpi) { - const int min_frame_target = MAX(cpi->rc.min_frame_bandwidth, - cpi->rc.av_per_frame_bandwidth >> 5); +static void calc_pframe_target_size(VP9_COMP *const cpi) { + int min_frame_target = MAX(cpi->rc.min_frame_bandwidth, + cpi->rc.av_per_frame_bandwidth >> 5); if (cpi->refresh_alt_ref_frame) { // Special alt reference frame case // Per frame bit target for the alt ref frame cpi->rc.per_frame_bandwidth = cpi->twopass.gf_bits; cpi->rc.this_frame_target = cpi->rc.per_frame_bandwidth; } else { - // Normal frames (gf,and inter) + // Normal frames (gf and inter). cpi->rc.this_frame_target = cpi->rc.per_frame_bandwidth; + // Set target frame size based on buffer level, for 1 pass CBR. + if (cpi->pass == 0 && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) { + // Need to decide how low min_frame_target should be for 1-pass CBR. + // For now, use: cpi->rc.av_per_frame_bandwidth / 16: + min_frame_target = MAX(cpi->rc.av_per_frame_bandwidth >> 4, + FRAME_OVERHEAD_BITS); + cpi->rc.this_frame_target = target_size_from_buffer_level(cpi); + // Adjust qp-max based on buffer level. + cpi->rc.active_worst_quality = + adjust_active_worst_quality_from_buffer_level(cpi); + } } // Check that the total sum of adjustments is not above the maximum allowed. @@ -262,11 +423,13 @@ static void calc_pframe_target_size(VP9_COMP *cpi) { // not capable of recovering all the extra bits we have spent in the KF or GF, // then the remainder will have to be recovered over a longer time span via // other buffer / rate control mechanisms. - if (cpi->rc.this_frame_target < min_frame_target) + if (cpi->rc.this_frame_target < min_frame_target) { cpi->rc.this_frame_target = min_frame_target; + } // Adjust target frame size for Golden Frames: - if (cpi->rc.frames_till_gf_update_due == 0) { + if (cpi->rc.frames_till_gf_update_due == 0 && + !(cpi->pass == 0 && cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER)) { cpi->refresh_golden_frame = 1; calc_gf_params(cpi); // If we are using alternate ref instead of gf then do not apply the boost @@ -608,17 +771,8 @@ int vp9_rc_pick_q_and_adjust_q_bounds(const VP9_COMP *cpi, } else if ((cm->frame_type == KEY_FRAME) && cpi->rc.this_key_frame_forced) { q = cpi->rc.last_boosted_qindex; } else { - // Determine initial Q to try. - if (cpi->pass == 0) { - // 1-pass: for now, use per-frame-bw for target size of frame, scaled - // by |x| for key frame. - int scale = (cm->frame_type == KEY_FRAME) ? 5 : 1; - q = vp9_rc_regulate_q(cpi, scale * cpi->rc.av_per_frame_bandwidth, - active_best_quality, active_worst_quality); - } else { - q = vp9_rc_regulate_q(cpi, cpi->rc.this_frame_target, - active_best_quality, active_worst_quality); - } + q = vp9_rc_regulate_q(cpi, cpi->rc.this_frame_target, + active_best_quality, active_worst_quality); if (q > *top_index) q = *top_index; } @@ -741,17 +895,7 @@ void vp9_rc_postencode_update(VP9_COMP *cpi, uint64_t bytes_used) { cpi->rc.last_boosted_qindex = cm->base_qindex; } - // Update the buffer level variable. - // Non-viewable frames are a special case and are treated as pure overhead. - if (!cm->show_frame) - cpi->rc.bits_off_target -= cpi->rc.projected_frame_size; - else - cpi->rc.bits_off_target += cpi->rc.av_per_frame_bandwidth - - cpi->rc.projected_frame_size; - - // Clip the buffer level at the maximum buffer size - if (cpi->rc.bits_off_target > cpi->oxcf.maximum_buffer_size) - cpi->rc.bits_off_target = cpi->oxcf.maximum_buffer_size; + vp9_update_buffer_level(cpi, cpi->rc.projected_frame_size); // Rolling monitors of whether we are over or underspending used to help // regulate min and Max Q in two pass. @@ -777,8 +921,6 @@ void vp9_rc_postencode_update(VP9_COMP *cpi, uint64_t bytes_used) { cpi->rc.total_target_vs_actual += (cpi->rc.this_frame_target - cpi->rc.projected_frame_size); - cpi->rc.buffer_level = cpi->rc.bits_off_target; - #ifndef DISABLE_RC_LONG_TERM_MEM // Update bits left to the kf and gf groups to account for overshoot or // undershoot on these frames diff --git a/vp9/encoder/vp9_ratectrl.h b/vp9/encoder/vp9_ratectrl.h index 8113a056c..82935578c 100644 --- a/vp9/encoder/vp9_ratectrl.h +++ b/vp9/encoder/vp9_ratectrl.h @@ -61,4 +61,10 @@ int vp9_rc_bits_per_mb(FRAME_TYPE frame_type, int qindex, void vp9_twopass_postencode_update(VP9_COMP *cpi, uint64_t bytes_used); +// Decide if we should drop this frame: For 1-pass CBR. +int vp9_drop_frame(VP9_COMP *cpi); + +// Update the buffer level. +void vp9_update_buffer_level(VP9_COMP *cpi, int encoded_frame_size); + #endif // VP9_ENCODER_VP9_RATECTRL_H_ |