[svc] Initialization of 2nd pass rc for svc two pass rc
Change-Id: If67ed8721f258883e41bab18f5c456505de68785
This commit is contained in:
Родитель
e27bcc2451
Коммит
5cf0363368
|
@ -257,12 +257,21 @@ static void avg_stats(FIRSTPASS_STATS *section) {
|
|||
// 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 @@ extern void vp9_new_framerate(VP9_COMP *cpi, double framerate);
|
|||
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 (!twopass->stats_in_end)
|
||||
return;
|
||||
|
||||
twopass->total_stats = *twopass->stats_in_end;
|
||||
twopass->total_left_stats = twopass->total_stats;
|
||||
|
||||
// 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);
|
||||
|
||||
cpi->output_framerate = oxcf->framerate;
|
||||
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;
|
||||
|
||||
// This variable monitors how far behind the second ref update is lagging.
|
||||
twopass->sr_update_lag = 1;
|
||||
|
||||
// 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
twopass->avg_iiratio = sum_iiratio /
|
||||
DOUBLE_DIVIDE_CHECK((double)twopass->total_stats.count);
|
||||
|
||||
reset_fpf_position(twopass, start_pos);
|
||||
if (is_spatial_svc) {
|
||||
layer_end = cpi->svc.number_spatial_layers;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
start_pos = twopass->stats_in;
|
||||
|
||||
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;
|
||||
|
||||
while (input_stats(twopass, &this_frame) != EOF) {
|
||||
twopass->modified_error_total +=
|
||||
calculate_modified_err(cpi, &this_frame);
|
||||
for (layer = 0; layer < layer_end; ++layer) {
|
||||
if (is_spatial_svc) {
|
||||
twopass = &cpi->svc.layer_context[layer].twopass;
|
||||
cpi->svc.spatial_layer_id = layer;
|
||||
}
|
||||
twopass->modified_error_left = twopass->modified_error_total;
|
||||
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;
|
||||
|
||||
reset_fpf_position(twopass, start_pos);
|
||||
if (!twopass->stats_in_end)
|
||||
continue;
|
||||
|
||||
twopass->total_stats = *twopass->stats_in_end;
|
||||
twopass->total_left_stats = twopass->total_stats;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
cpi->output_framerate = oxcf->framerate;
|
||||
|
||||
// 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;
|
||||
|
||||
// This variable monitors how far behind the second ref update is lagging.
|
||||
twopass->sr_update_lag = 1;
|
||||
|
||||
// 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
twopass->avg_iiratio = sum_iiratio /
|
||||
DOUBLE_DIVIDE_CHECK((double)twopass->total_stats.count);
|
||||
|
||||
reset_fpf_position(twopass, start_pos);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
start_pos = twopass->stats_in;
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
|
|
|
@ -1228,8 +1228,9 @@ static void init_config(struct VP9_COMP *cpi, VP9_CONFIG *oxcf) {
|
|||
// 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 @@ void vp9_change_config(struct VP9_COMP *cpi, const VP9_CONFIG *oxcf) {
|
|||
}
|
||||
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 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 @@ void vp9_init_layer_context(VP9_COMP *const cpi) {
|
|||
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 @@ void vp9_update_layer_context_change_config(VP9_COMP *const cpi,
|
|||
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 @@ void vp9_update_layer_context_change_config(VP9_COMP *const cpi,
|
|||
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 @@ static LAYER_CONTEXT *get_temporal_layer_context(SVC *svc) {
|
|||
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);
|
||||
|
@ -102,6 +132,21 @@ void vp9_update_layer_framerate(VP9_COMP *const cpi) {
|
|||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
LAYER_CONTEXT *const lc = get_temporal_layer_context(&cpi->svc);
|
||||
const int old_frame_since_key = cpi->rc.frames_since_key;
|
||||
|
|
|
@ -52,8 +52,12 @@ void vp9_update_layer_context_change_config(struct VP9_COMP *const cpi,
|
|||
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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче