Commit 9ee6087f authored by Minghai Shang's avatar Minghai Shang
Browse files

[svc] Finalize first version of 2nd pass rc

Change-Id: I366850015004644c4fc7feabe27a782fdd8d8718
parent 5cf03633
......@@ -419,9 +419,52 @@ TEST_F(SvcTest, SecondPassEncode) {
fclose(stats_file);
codec_enc_.rc_twopass_stats_in = stats_buf;
const vpx_codec_err_t res =
vpx_codec_err_t res =
vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
ASSERT_EQ(VPX_CODEC_OK, res);
codec_initialized_ = true;
libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight,
codec_enc_.g_timebase.den,
codec_enc_.g_timebase.num, 0, 30);
// FRAME 0
video.Begin();
// This frame is a keyframe.
res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
video.duration(), VPX_DL_GOOD_QUALITY);
ASSERT_EQ(VPX_CODEC_OK, res);
EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_));
vpx_codec_err_t res_dec = decoder_->DecodeFrame(
static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
vpx_svc_get_frame_size(&svc_));
ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
// FRAME 1
video.Next();
// This is a P-frame.
res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
video.duration(), VPX_DL_GOOD_QUALITY);
ASSERT_EQ(VPX_CODEC_OK, res);
EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_));
res_dec = decoder_->DecodeFrame(
static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
vpx_svc_get_frame_size(&svc_));
ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
// FRAME 2
video.Next();
// This is a P-frame.
res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(),
video.duration(), VPX_DL_GOOD_QUALITY);
ASSERT_EQ(VPX_CODEC_OK, res);
EXPECT_EQ(0, vpx_svc_is_keyframe(&svc_));
res_dec = decoder_->DecodeFrame(
static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)),
vpx_svc_get_frame_size(&svc_));
ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError();
free(stats_buf.buf);
}
......
......@@ -946,104 +946,97 @@ void vp9_init_second_pass(VP9_COMP *cpi) {
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;
if (is_spatial_svc) {
layer_end = cpi->svc.number_spatial_layers;
twopass = &cpi->svc.layer_context[cpi->svc.spatial_layer_id].twopass;
}
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;
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);
}
zero_stats(&twopass->total_stats);
zero_stats(&twopass->total_left_stats);
cpi->output_framerate = oxcf->framerate;
if (!twopass->stats_in_end)
return;
// 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;
twopass->total_stats = *twopass->stats_in_end;
twopass->total_left_stats = twopass->total_stats;
// This variable monitors how far behind the second ref update is lagging.
twopass->sr_update_lag = 1;
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.
// 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;
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[cpi->svc.spatial_layer_id].target_bandwidth /
10000000.0);
} else {
vp9_new_framerate(cpi, frame_rate);
twopass->bits_left = (int64_t)(twopass->total_stats.duration *
oxcf->target_bandwidth / 10000000.0);
}
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);
}
cpi->output_framerate = oxcf->framerate;
twopass->avg_iiratio = sum_iiratio /
DOUBLE_DIVIDE_CHECK((double)twopass->total_stats.count);
// 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.
if (!is_spatial_svc) {
// We don't know the number of MBs for each layer at this point.
// So we will do it later.
twopass->kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs;
twopass->gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs;
}
reset_fpf_position(twopass, start_pos);
// 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);
}
// 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->avg_iiratio = sum_iiratio /
DOUBLE_DIVIDE_CHECK((double)twopass->total_stats.count);
start_pos = twopass->stats_in;
reset_fpf_position(twopass, start_pos);
}
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;
// 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);
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;
start_pos = twopass->stats_in;
reset_fpf_position(twopass, start_pos);
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
......@@ -1652,8 +1645,8 @@ static void define_gf_group(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
// Calculate the bits to be allocated to the group as a whole.
if (twopass->kf_group_bits > 0 && twopass->kf_group_error_left > 0) {
twopass->gf_group_bits = (int64_t)(cpi->twopass.kf_group_bits *
(gf_group_err / cpi->twopass.kf_group_error_left));
twopass->gf_group_bits = (int64_t)(twopass->kf_group_bits *
(gf_group_err / twopass->kf_group_error_left));
} else {
twopass->gf_group_bits = 0;
}
......@@ -2224,14 +2217,24 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
struct twopass_rc *const twopass = &cpi->twopass;
const int frames_left = (int)(twopass->total_stats.count -
cm->current_video_frame);
int frames_left;
FIRSTPASS_STATS this_frame;
FIRSTPASS_STATS this_frame_copy;
double this_frame_intra_error;
double this_frame_coded_error;
int target;
LAYER_CONTEXT *lc = NULL;
int is_spatial_svc = (cpi->use_svc && cpi->svc.number_temporal_layers == 1);
if (is_spatial_svc) {
lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id];
frames_left = (int)(twopass->total_stats.count -
lc->current_video_frame_in_layer);
} else {
frames_left = (int)(twopass->total_stats.count -
cm->current_video_frame);
}
if (!twopass->stats_in)
return;
......@@ -2244,9 +2247,15 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) {
vp9_clear_system_state();
if (is_spatial_svc && twopass->kf_intra_err_min == 0) {
twopass->kf_intra_err_min = KF_MB_INTRA_MIN * cpi->common.MBs;
twopass->gf_intra_err_min = GF_MB_INTRA_MIN * cpi->common.MBs;
}
if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) {
twopass->active_worst_quality = cpi->oxcf.cq_level;
} else if (cm->current_video_frame == 0) {
} else if (cm->current_video_frame == 0 ||
(is_spatial_svc && lc->current_video_frame_in_layer == 0)) {
// Special case code for first frame.
const int section_target_bandwidth = (int)(twopass->bits_left /
frames_left);
......@@ -2269,6 +2278,11 @@ void vp9_rc_get_second_pass_params(VP9_COMP *cpi) {
// Define next KF group and assign bits to it.
this_frame_copy = this_frame;
find_next_key_frame(cpi, &this_frame_copy);
// Don't place key frame in any enhancement layers in spatial svc
if (cpi->use_svc && cpi->svc.number_temporal_layers == 1 &&
cpi->svc.spatial_layer_id > 0) {
cm->frame_type = INTER_FRAME;
}
} else {
cm->frame_type = INTER_FRAME;
}
......
......@@ -1230,7 +1230,8 @@ static void init_config(struct VP9_COMP *cpi, VP9_CONFIG *oxcf) {
if ((cpi->svc.number_temporal_layers > 1 &&
cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER) ||
(cpi->svc.number_spatial_layers > 1 && cpi->pass == 2)) {
(cpi->svc.number_spatial_layers > 1 &&
cpi->oxcf.mode == MODE_SECONDPASS_BEST)) {
vp9_init_layer_context(cpi);
}
......@@ -1795,13 +1796,15 @@ VP9_COMP *vp9_create_compressor(VP9_CONFIG *oxcf) {
++stats_copy[layer_id];
}
}
vp9_init_second_pass_spatial_svc(cpi);
} else {
cpi->twopass.stats_in_start = oxcf->two_pass_stats_in.buf;
cpi->twopass.stats_in = cpi->twopass.stats_in_start;
cpi->twopass.stats_in_end = &cpi->twopass.stats_in[packets - 1];
}
vp9_init_second_pass(cpi);
vp9_init_second_pass(cpi);
}
}
vp9_set_speed_features(cpi);
......@@ -3242,6 +3245,15 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
// Don't increment frame counters if this was an altref buffer
// update not a real frame
++cm->current_video_frame;
if (cpi->use_svc) {
LAYER_CONTEXT *lc;
if (cpi->svc.number_temporal_layers > 1) {
lc = &cpi->svc.layer_context[cpi->svc.temporal_layer_id];
} else {
lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id];
}
++lc->current_video_frame_in_layer;
}
}
// restore prev_mi
......@@ -3397,6 +3409,10 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
if (!cpi)
return -1;
if (cpi->svc.number_spatial_layers > 1 && cpi->pass == 2) {
vp9_restore_layer_context(cpi);
}
vpx_usec_timer_start(&cmptimer);
cpi->source = NULL;
......@@ -3589,7 +3605,8 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
if (cpi->pass == 1 &&
(!cpi->use_svc || cpi->svc.number_temporal_layers == 1)) {
Pass1Encode(cpi, size, dest, frame_flags);
} else if (cpi->pass == 2 && !cpi->use_svc) {
} else if (cpi->pass == 2 &&
(!cpi->use_svc || cpi->svc.number_temporal_layers == 1)) {
Pass2Encode(cpi, size, dest, frame_flags);
} else if (cpi->use_svc) {
SvcEncode(cpi, size, dest, frame_flags);
......@@ -3611,8 +3628,9 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
}
// Save layer specific state.
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_save_layer_context(cpi);
}
......
......@@ -933,7 +933,7 @@ static int rc_pick_q_and_bounds_two_pass(const VP9_COMP *cpi,
active_best_quality, active_worst_quality);
if (q > *top_index) {
// Special case when we are targeting the max allowed rate.
if (cpi->rc.this_frame_target >= cpi->rc.max_frame_bandwidth)
if (rc->this_frame_target >= rc->max_frame_bandwidth)
*top_index = q;
else
q = *top_index;
......
......@@ -30,9 +30,8 @@ void vp9_init_layer_context(VP9_COMP *const cpi) {
for (layer = 0; layer < layer_end; ++layer) {
LAYER_CONTEXT *const lc = &cpi->svc.layer_context[layer];
RATE_CONTROL *const lrc = &lc->rc;
lc->current_video_frame_in_layer = 0;
lrc->avg_frame_qindex[INTER_FRAME] = q_trans[oxcf->worst_allowed_q];
lrc->last_q[INTER_FRAME] = q_trans[oxcf->worst_allowed_q];
lrc->ni_av_qi = q_trans[oxcf->worst_allowed_q];
lrc->total_actual_bits = 0;
lrc->total_target_vs_actual = 0;
......@@ -47,8 +46,12 @@ void vp9_init_layer_context(VP9_COMP *const cpi) {
if (cpi->svc.number_temporal_layers > 1) {
lc->target_bandwidth = oxcf->ts_target_bitrate[layer] * 1000;
lrc->last_q[INTER_FRAME] = q_trans[oxcf->worst_allowed_q];
} else {
lc->target_bandwidth = oxcf->ss_target_bitrate[layer] * 1000;
lrc->last_q[0] = q_trans[oxcf->best_allowed_q];
lrc->last_q[1] = q_trans[oxcf->best_allowed_q];
lrc->last_q[2] = q_trans[oxcf->best_allowed_q];
}
lrc->buffer_level = vp9_rescale((int)(oxcf->starting_buffer_level),
......@@ -105,14 +108,16 @@ void vp9_update_layer_context_change_config(VP9_COMP *const cpi,
}
}
static LAYER_CONTEXT *get_temporal_layer_context(SVC *svc) {
return &svc->layer_context[svc->temporal_layer_id];
static LAYER_CONTEXT *get_layer_context(SVC *svc) {
return svc->number_temporal_layers > 1 ?
&svc->layer_context[svc->temporal_layer_id] :
&svc->layer_context[svc->spatial_layer_id];
}
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);
LAYER_CONTEXT *const lc = get_layer_context(&cpi->svc);
RATE_CONTROL *const lrc = &lc->rc;
lc->framerate = oxcf->framerate / oxcf->ts_rate_decimator[layer];
......@@ -133,9 +138,8 @@ void vp9_update_temporal_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];
LAYER_CONTEXT *const lc = get_layer_context(&cpi->svc);
RATE_CONTROL *const lrc = &lc->rc;
lc->framerate = framerate;
......@@ -145,14 +149,28 @@ void vp9_update_spatial_layer_framerate(VP9_COMP *const cpi, double framerate) {
lrc->max_frame_bandwidth = (int)(((int64_t)lrc->av_per_frame_bandwidth *
oxcf->two_pass_vbrmax_section) / 100);
lrc->max_gf_interval = 16;
lrc->static_scene_max_gf_interval = cpi->key_frame_frequency >> 1;
if (oxcf->play_alternate && oxcf->lag_in_frames) {
if (lrc->max_gf_interval > oxcf->lag_in_frames - 1)
lrc->max_gf_interval = oxcf->lag_in_frames - 1;
if (lrc->static_scene_max_gf_interval > oxcf->lag_in_frames - 1)
lrc->static_scene_max_gf_interval = oxcf->lag_in_frames - 1;
}
if (lrc->max_gf_interval > lrc->static_scene_max_gf_interval)
lrc->max_gf_interval = lrc->static_scene_max_gf_interval;
}
void vp9_restore_layer_context(VP9_COMP *const cpi) {
LAYER_CONTEXT *const lc = get_temporal_layer_context(&cpi->svc);
LAYER_CONTEXT *const lc = get_layer_context(&cpi->svc);
const int old_frame_since_key = cpi->rc.frames_since_key;
const int old_frame_to_key = cpi->rc.frames_to_key;
cpi->rc = lc->rc;
cpi->twopass = lc->twopass;
cpi->oxcf.target_bandwidth = lc->target_bandwidth;
cpi->oxcf.starting_buffer_level = lc->starting_buffer_level;
cpi->oxcf.optimal_buffer_level = lc->optimal_buffer_level;
......@@ -160,18 +178,35 @@ void vp9_restore_layer_context(VP9_COMP *const cpi) {
cpi->output_framerate = lc->framerate;
// Reset the frames_since_key and frames_to_key counters to their values
// before the layer restore. Keep these defined for the stream (not layer).
cpi->rc.frames_since_key = old_frame_since_key;
cpi->rc.frames_to_key = old_frame_to_key;
if (cpi->svc.number_temporal_layers > 1) {
cpi->rc.frames_since_key = old_frame_since_key;
cpi->rc.frames_to_key = old_frame_to_key;
}
}
void vp9_save_layer_context(VP9_COMP *const cpi) {
const VP9_CONFIG *const oxcf = &cpi->oxcf;
LAYER_CONTEXT *const lc = get_temporal_layer_context(&cpi->svc);
LAYER_CONTEXT *const lc = get_layer_context(&cpi->svc);
lc->rc = cpi->rc;
lc->twopass = cpi->twopass;
lc->target_bandwidth = (int)oxcf->target_bandwidth;
lc->starting_buffer_level = oxcf->starting_buffer_level;
lc->optimal_buffer_level = oxcf->optimal_buffer_level;
lc->maximum_buffer_size = oxcf->maximum_buffer_size;
lc->framerate = cpi->output_framerate;
}
void vp9_init_second_pass_spatial_svc(VP9_COMP *cpi) {
int i;
for (i = 0; i < cpi->svc.number_spatial_layers; ++i) {
struct twopass_rc *const twopass = &cpi->svc.layer_context[i].twopass;
cpi->svc.spatial_layer_id = i;
vp9_init_second_pass(cpi);
twopass->total_stats.spatial_layer_id = i;
twopass->total_left_stats.spatial_layer_id = i;
}
cpi->svc.spatial_layer_id = 0;
}
......@@ -29,6 +29,7 @@ typedef struct {
int avg_frame_size;
struct twopass_rc twopass;
struct vpx_fixed_buf rc_twopass_stats_in;
unsigned int current_video_frame_in_layer;
} LAYER_CONTEXT;
typedef struct {
......@@ -36,8 +37,8 @@ typedef struct {
int temporal_layer_id;
int number_spatial_layers;
int number_temporal_layers;
// Layer context used for rate control in temporal CBR mode or spatial
// two pass mode. Defined for temporal or spatial layers for now.
// Layer context used for rate control in one pass temporal CBR mode or
// two pass spatial mode. Defined for temporal or spatial layers for now.
// Does not support temporal combined with spatial RC.
LAYER_CONTEXT layer_context[MAX(VPX_TS_MAX_LAYERS, VPX_SS_MAX_LAYERS)];
} SVC;
......@@ -66,6 +67,9 @@ void vp9_restore_layer_context(struct VP9_COMP *const cpi);
// Save the layer context after encoding the frame.
void vp9_save_layer_context(struct VP9_COMP *const cpi);
// Initialize second pass rc for spatial svc.
void vp9_init_second_pass_spatial_svc(struct VP9_COMP *cpi);
#ifdef __cplusplus
} // extern "C"
#endif
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment