ref: 5cf036336830b564abf129d6f69a46d56cf8ae03
parent: e27bcc2451855d08bf2b86028de9e090ee513929
author: Minghai Shang <[email protected]>
date: Thu Mar 27 11:46:32 EDT 2014
[svc] Initialization of 2nd pass rc for svc two pass rc Change-Id: If67ed8721f258883e41bab18f5c456505de68785
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -257,13 +257,22 @@
// harder frames.
static double calculate_modified_err(const VP9_COMP *cpi,
const FIRSTPASS_STATS *this_frame) {
- const struct twopass_rc *const twopass = &cpi->twopass;
- const FIRSTPASS_STATS *const stats = &twopass->total_stats;
- const double av_err = stats->ssim_weighted_pred_err / stats->count;
- double modified_error = av_err * pow(this_frame->ssim_weighted_pred_err /
- DOUBLE_DIVIDE_CHECK(av_err),
- cpi->oxcf.two_pass_vbrbias / 100.0);
+ const struct twopass_rc *twopass = &cpi->twopass;
+ const FIRSTPASS_STATS *stats;
+ double av_err;
+ double modified_error;
+ if (cpi->svc.number_spatial_layers > 1 &&
+ cpi->svc.number_temporal_layers == 1) {
+ twopass = &cpi->svc.layer_context[cpi->svc.spatial_layer_id].twopass;
+ }
+
+ stats = &twopass->total_stats;
+ av_err = stats->ssim_weighted_pred_err / stats->count;
+ modified_error = av_err * pow(this_frame->ssim_weighted_pred_err /
+ DOUBLE_DIVIDE_CHECK(av_err),
+ cpi->oxcf.two_pass_vbrbias / 100.0);
+
return fclamp(modified_error,
twopass->modified_error_min, twopass->modified_error_max);
}
@@ -933,80 +942,108 @@
void vp9_init_second_pass(VP9_COMP *cpi) {
FIRSTPASS_STATS this_frame;
const FIRSTPASS_STATS *start_pos;
- struct twopass_rc *const twopass = &cpi->twopass;
+ struct twopass_rc *twopass = &cpi->twopass;
const VP9_CONFIG *const oxcf = &cpi->oxcf;
+ const int is_spatial_svc = (cpi->svc.number_spatial_layers > 1) &&
+ (cpi->svc.number_temporal_layers == 1);
+ int layer = 0;
+ int layer_end = 1;
+ double frame_rate;
- zero_stats(&twopass->total_stats);
- zero_stats(&twopass->total_left_stats);
+ if (is_spatial_svc) {
+ layer_end = cpi->svc.number_spatial_layers;
+ }
- if (!twopass->stats_in_end)
- return;
+ for (layer = 0; layer < layer_end; ++layer) {
+ if (is_spatial_svc) {
+ twopass = &cpi->svc.layer_context[layer].twopass;
+ cpi->svc.spatial_layer_id = layer;
+ }
+ zero_stats(&twopass->total_stats);
+ zero_stats(&twopass->total_left_stats);
+ twopass->total_stats.spatial_layer_id = layer;
+ twopass->total_left_stats.spatial_layer_id = layer;
- twopass->total_stats = *twopass->stats_in_end;
- twopass->total_left_stats = twopass->total_stats;
+ if (!twopass->stats_in_end)
+ continue;
- // Each frame can have a different duration, as the frame rate in the source
- // isn't guaranteed to be constant. The frame rate prior to the first frame
- // encoded in the second pass is a guess. However, the sum duration is not.
- // It is calculated based on the actual durations of all frames from the
- // first pass.
- vp9_new_framerate(cpi, 10000000.0 * twopass->total_stats.count /
- twopass->total_stats.duration);
+ twopass->total_stats = *twopass->stats_in_end;
+ twopass->total_left_stats = twopass->total_stats;
- cpi->output_framerate = oxcf->framerate;
- twopass->bits_left = (int64_t)(twopass->total_stats.duration *
- oxcf->target_bandwidth / 10000000.0);
+ frame_rate = 10000000.0 * twopass->total_stats.count /
+ twopass->total_stats.duration;
+ // Each frame can have a different duration, as the frame rate in the source
+ // isn't guaranteed to be constant. The frame rate prior to the first frame
+ // encoded in the second pass is a guess. However, the sum duration is not.
+ // It is calculated based on the actual durations of all frames from the
+ // first pass.
+ if (layer == 0) {
+ vp9_new_framerate(cpi, frame_rate);
+ }
+ if (is_spatial_svc) {
+ vp9_update_spatial_layer_framerate(cpi, frame_rate);
+ twopass->bits_left = (int64_t)(twopass->total_stats.duration *
+ cpi->svc.layer_context[layer].target_bandwidth /
+ 10000000.0);
+ } else {
+ twopass->bits_left = (int64_t)(twopass->total_stats.duration *
+ oxcf->target_bandwidth / 10000000.0);
+ }
- // Calculate a minimum intra value to be used in determining the IIratio
- // scores used in the second pass. We have this minimum to make sure
- // that clips that are static but "low complexity" in the intra domain
- // are still boosted appropriately for KF/GF/ARF.
- twopass->kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs;
- twopass->gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs;
+ cpi->output_framerate = oxcf->framerate;
- // This variable monitors how far behind the second ref update is lagging.
- twopass->sr_update_lag = 1;
+ // Calculate a minimum intra value to be used in determining the IIratio
+ // scores used in the second pass. We have this minimum to make sure
+ // that clips that are static but "low complexity" in the intra domain
+ // are still boosted appropriately for KF/GF/ARF.
+ twopass->kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs;
+ twopass->gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs;
- // Scan the first pass file and calculate an average Intra / Inter error score
- // ratio for the sequence.
- {
- double sum_iiratio = 0.0;
- start_pos = twopass->stats_in;
+ // This variable monitors how far behind the second ref update is lagging.
+ twopass->sr_update_lag = 1;
- while (input_stats(twopass, &this_frame) != EOF) {
- const double iiratio = this_frame.intra_error /
- DOUBLE_DIVIDE_CHECK(this_frame.coded_error);
- sum_iiratio += fclamp(iiratio, 1.0, 20.0);
- }
+ // Scan the first pass file and calculate an average Intra / Inter error
+ // score ratio for the sequence.
+ {
+ double sum_iiratio = 0.0;
+ start_pos = twopass->stats_in;
- twopass->avg_iiratio = sum_iiratio /
- DOUBLE_DIVIDE_CHECK((double)twopass->total_stats.count);
+ while (input_stats(twopass, &this_frame) != EOF) {
+ const double iiratio = this_frame.intra_error /
+ DOUBLE_DIVIDE_CHECK(this_frame.coded_error);
+ sum_iiratio += fclamp(iiratio, 1.0, 20.0);
+ }
- reset_fpf_position(twopass, start_pos);
- }
+ twopass->avg_iiratio = sum_iiratio /
+ DOUBLE_DIVIDE_CHECK((double)twopass->total_stats.count);
- // Scan the first pass file and calculate a modified total error based upon
- // the bias/power function used to allocate bits.
- {
- double av_error = twopass->total_stats.ssim_weighted_pred_err /
- DOUBLE_DIVIDE_CHECK(twopass->total_stats.count);
+ reset_fpf_position(twopass, start_pos);
+ }
- start_pos = twopass->stats_in;
+ // Scan the first pass file and calculate a modified total error based upon
+ // the bias/power function used to allocate bits.
+ {
+ double av_error = twopass->total_stats.ssim_weighted_pred_err /
+ DOUBLE_DIVIDE_CHECK(twopass->total_stats.count);
- twopass->modified_error_total = 0.0;
- twopass->modified_error_min =
- (av_error * oxcf->two_pass_vbrmin_section) / 100;
- twopass->modified_error_max =
- (av_error * oxcf->two_pass_vbrmax_section) / 100;
+ start_pos = twopass->stats_in;
- while (input_stats(twopass, &this_frame) != EOF) {
- twopass->modified_error_total +=
- calculate_modified_err(cpi, &this_frame);
- }
- twopass->modified_error_left = twopass->modified_error_total;
+ twopass->modified_error_total = 0.0;
+ twopass->modified_error_min =
+ (av_error * oxcf->two_pass_vbrmin_section) / 100;
+ twopass->modified_error_max =
+ (av_error * oxcf->two_pass_vbrmax_section) / 100;
- reset_fpf_position(twopass, start_pos);
+ while (input_stats(twopass, &this_frame) != EOF) {
+ twopass->modified_error_total +=
+ calculate_modified_err(cpi, &this_frame);
+ }
+ twopass->modified_error_left = twopass->modified_error_total;
+
+ reset_fpf_position(twopass, start_pos);
+ }
}
+ cpi->svc.spatial_layer_id = 0;
}
// This function gives an estimate of how badly we believe the prediction
--- a/vp9/encoder/vp9_onyx_if.c
+++ b/vp9/encoder/vp9_onyx_if.c
@@ -1228,8 +1228,9 @@
// Temporal scalability.
cpi->svc.number_temporal_layers = oxcf->ts_number_layers;
- if (cpi->svc.number_temporal_layers > 1 &&
- cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+ if ((cpi->svc.number_temporal_layers > 1 &&
+ cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) ||
+ (cpi->svc.number_spatial_layers > 1 && cpi->pass == 2)) {
vp9_init_layer_context(cpi);
}
@@ -1387,8 +1388,9 @@
}
update_frame_size(cpi);
- if (cpi->svc.number_temporal_layers > 1 &&
- cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
+ if ((cpi->svc.number_temporal_layers > 1 &&
+ cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) ||
+ (cpi->svc.number_spatial_layers > 1 && cpi->pass == 2)) {
vp9_update_layer_context_change_config(cpi,
(int)cpi->oxcf.target_bandwidth);
}
@@ -3527,7 +3529,7 @@
if (cpi->svc.number_temporal_layers > 1 &&
cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) {
- vp9_update_layer_framerate(cpi);
+ vp9_update_temporal_layer_framerate(cpi);
vp9_restore_layer_context(cpi);
}
--- a/vp9/encoder/vp9_svc_layercontext.c
+++ b/vp9/encoder/vp9_svc_layercontext.c
@@ -16,10 +16,18 @@
void vp9_init_layer_context(VP9_COMP *const cpi) {
const VP9_CONFIG *const oxcf = &cpi->oxcf;
int layer;
+ int layer_end;
cpi->svc.spatial_layer_id = 0;
cpi->svc.temporal_layer_id = 0;
- for (layer = 0; layer < cpi->svc.number_temporal_layers; ++layer) {
+
+ if (cpi->svc.number_temporal_layers > 1) {
+ layer_end = cpi->svc.number_temporal_layers;
+ } else {
+ layer_end = cpi->svc.number_spatial_layers;
+ }
+
+ for (layer = 0; layer < layer_end; ++layer) {
LAYER_CONTEXT *const lc = &cpi->svc.layer_context[layer];
RATE_CONTROL *const lrc = &lc->rc;
@@ -36,7 +44,13 @@
lrc->decimation_factor = 0;
lrc->rate_correction_factor = 1.0;
lrc->key_frame_rate_correction_factor = 1.0;
- lc->target_bandwidth = oxcf->ts_target_bitrate[layer] * 1000;
+
+ if (cpi->svc.number_temporal_layers > 1) {
+ lc->target_bandwidth = oxcf->ts_target_bitrate[layer] * 1000;
+ } else {
+ lc->target_bandwidth = oxcf->ss_target_bitrate[layer] * 1000;
+ }
+
lrc->buffer_level = vp9_rescale((int)(oxcf->starting_buffer_level),
lc->target_bandwidth, 1000);
lrc->bits_off_target = lrc->buffer_level;
@@ -49,12 +63,24 @@
const VP9_CONFIG *const oxcf = &cpi->oxcf;
const RATE_CONTROL *const rc = &cpi->rc;
int layer;
+ int layer_end;
float bitrate_alloc = 1.0;
- for (layer = 0; layer < cpi->svc.number_temporal_layers; ++layer) {
+ if (cpi->svc.number_temporal_layers > 1) {
+ layer_end = cpi->svc.number_temporal_layers;
+ } else {
+ layer_end = cpi->svc.number_spatial_layers;
+ }
+
+ for (layer = 0; layer < layer_end; ++layer) {
LAYER_CONTEXT *const lc = &cpi->svc.layer_context[layer];
RATE_CONTROL *const lrc = &lc->rc;
- lc->target_bandwidth = oxcf->ts_target_bitrate[layer] * 1000;
+
+ if (cpi->svc.number_temporal_layers > 1) {
+ lc->target_bandwidth = oxcf->ts_target_bitrate[layer] * 1000;
+ } else {
+ lc->target_bandwidth = oxcf->ss_target_bitrate[layer] * 1000;
+ }
bitrate_alloc = (float)lc->target_bandwidth / target_bandwidth;
// Update buffer-related quantities.
lc->starting_buffer_level =
@@ -66,7 +92,11 @@
lrc->bits_off_target = MIN(lrc->bits_off_target, lc->maximum_buffer_size);
lrc->buffer_level = MIN(lrc->buffer_level, lc->maximum_buffer_size);
// Update framerate-related quantities.
- lc->framerate = oxcf->framerate / oxcf->ts_rate_decimator[layer];
+ if (cpi->svc.number_temporal_layers > 1) {
+ lc->framerate = oxcf->framerate / oxcf->ts_rate_decimator[layer];
+ } else {
+ lc->framerate = oxcf->framerate;
+ }
lrc->av_per_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
lrc->max_frame_bandwidth = rc->max_frame_bandwidth;
// Update qp-related quantities.
@@ -79,7 +109,7 @@
return &svc->layer_context[svc->temporal_layer_id];
}
-void vp9_update_layer_framerate(VP9_COMP *const cpi) {
+void vp9_update_temporal_layer_framerate(VP9_COMP *const cpi) {
const int layer = cpi->svc.temporal_layer_id;
const VP9_CONFIG *const oxcf = &cpi->oxcf;
LAYER_CONTEXT *const lc = get_temporal_layer_context(&cpi->svc);
@@ -100,6 +130,21 @@
(int)((lc->target_bandwidth - prev_layer_target_bandwidth) /
(lc->framerate - prev_layer_framerate));
}
+}
+
+void vp9_update_spatial_layer_framerate(VP9_COMP *const cpi, double framerate) {
+ int layer = cpi->svc.spatial_layer_id;
+ const VP9_CONFIG *const oxcf = &cpi->oxcf;
+ LAYER_CONTEXT *const lc = &cpi->svc.layer_context[layer];
+ RATE_CONTROL *const lrc = &lc->rc;
+
+ lc->framerate = framerate;
+ lrc->av_per_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
+ lrc->min_frame_bandwidth = (int)(lrc->av_per_frame_bandwidth *
+ oxcf->two_pass_vbrmin_section / 100);
+ lrc->max_frame_bandwidth = (int)(((int64_t)lrc->av_per_frame_bandwidth *
+ oxcf->two_pass_vbrmax_section) / 100);
+ lrc->max_gf_interval = 16;
}
void vp9_restore_layer_context(VP9_COMP *const cpi) {
--- a/vp9/encoder/vp9_svc_layercontext.h
+++ b/vp9/encoder/vp9_svc_layercontext.h
@@ -52,8 +52,12 @@
const int target_bandwidth);
// Prior to encoding the frame, update framerate-related quantities
-// for the current layer.
-void vp9_update_layer_framerate(struct VP9_COMP *const cpi);
+// for the current temporal layer.
+void vp9_update_temporal_layer_framerate(struct VP9_COMP *const cpi);
+
+// Update framerate-related quantities for the current spatial layer.
+void vp9_update_spatial_layer_framerate(struct VP9_COMP *const cpi,
+ double framerate);
// Prior to encoding the frame, set the layer context, for the current layer
// to be encoded, to the cpi struct.