summaryrefslogtreecommitdiff
path: root/vp9/encoder/vp9_ratectrl.c
diff options
context:
space:
mode:
authorMarco Paniconi <marpan@google.com>2013-12-17 15:45:30 -0800
committerMarco Paniconi <marpan@google.com>2013-12-18 09:24:24 -0800
commit1b8b8b0d0df9ac6f0a50db73d20231ecb7529666 (patch)
treec6bff1ad5d4e34e7f0f1f44a00004ea222a2e230 /vp9/encoder/vp9_ratectrl.c
parentd2f49407830de9dbc466f03fcdc90d379a3c0269 (diff)
downloadlibvpx-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/vp9_ratectrl.c')
-rw-r--r--vp9/encoder/vp9_ratectrl.c202
1 files changed, 172 insertions, 30 deletions
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