Commit 4864ab21 authored by Marco Paniconi's avatar Marco Paniconi
Browse files

Layer based rate control for CBR mode.

This patch adds a buffer-based rate control for temporal layers,
under CBR mode.

Added vpx_temporal_scalable_patters.c encoder for testing temporal
layers, for both vp9 and vp8 (replaces the old vp8_scalable_patterns).

Updated datarate unittest with tests for temporal layer rate-targeting.

Change-Id: I8900a854288b9354d9c697cfeb0243a9fd6790b1
parent 9602ed88
...@@ -54,9 +54,6 @@ vpxenc.SRCS += third_party/libmkv/EbmlWriter.h ...@@ -54,9 +54,6 @@ vpxenc.SRCS += third_party/libmkv/EbmlWriter.h
vpxenc.SRCS += $(LIBYUV_SRCS) vpxenc.SRCS += $(LIBYUV_SRCS)
vpxenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1 vpxenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1
vpxenc.DESCRIPTION = Full featured encoder vpxenc.DESCRIPTION = Full featured encoder
UTILS-$(CONFIG_VP8_ENCODER) += vp8_scalable_patterns.c
vp8_scalable_patterns.GUID = 0D6A210B-F482-4D6F-8570-4A9C01ACC88C
vp8_scalable_patterns.DESCRIPTION = Temporal Scalability Encoder
UTILS-$(CONFIG_VP9_ENCODER) += vp9_spatial_scalable_encoder.c UTILS-$(CONFIG_VP9_ENCODER) += vp9_spatial_scalable_encoder.c
vp9_spatial_scalable_encoder.SRCS += args.c args.h vp9_spatial_scalable_encoder.SRCS += args.c args.h
vp9_spatial_scalable_encoder.SRCS += ivfenc.c ivfenc.h vp9_spatial_scalable_encoder.SRCS += ivfenc.c ivfenc.h
...@@ -73,6 +70,11 @@ endif ...@@ -73,6 +70,11 @@ endif
#example_xma.GUID = A955FC4A-73F1-44F7-135E-30D84D32F022 #example_xma.GUID = A955FC4A-73F1-44F7-135E-30D84D32F022
#example_xma.DESCRIPTION = External Memory Allocation mode usage #example_xma.DESCRIPTION = External Memory Allocation mode usage
EXAMPLES-$(CONFIG_ENCODERS) += vpx_temporal_scalable_patterns.c
vpx_temporal_scalable_patterns.SRCS += ivfenc.c ivfenc.h
vpx_temporal_scalable_patterns.SRCS += tools_common.c tools_common.h
vpx_temporal_scalable_patterns.GUID = B18C08F2-A439-4502-A78E-849BE3D60947
vpx_temporal_scalable_patterns.DESCRIPTION = Temporal Scalability Encoder
EXAMPLES-$(CONFIG_VP8_DECODER) += simple_decoder.c EXAMPLES-$(CONFIG_VP8_DECODER) += simple_decoder.c
simple_decoder.GUID = D3BBF1E9-2427-450D-BBFF-B2843C1D44CC simple_decoder.GUID = D3BBF1E9-2427-450D-BBFF-B2843C1D44CC
simple_decoder.SRCS += ivfdec.h ivfdec.c simple_decoder.SRCS += ivfdec.h ivfdec.c
......
This diff is collapsed.
...@@ -200,21 +200,102 @@ class DatarateTestVP9 : public ::libvpx_test::EncoderTest, ...@@ -200,21 +200,102 @@ class DatarateTestVP9 : public ::libvpx_test::EncoderTest,
frame_number_ = 0; frame_number_ = 0;
first_drop_ = 0; first_drop_ = 0;
num_drops_ = 0; num_drops_ = 0;
bits_total_ = 0; // For testing up to 3 layers.
duration_ = 0.0; for (int i = 0; i < 3; ++i) {
bits_total_[i] = 0;
}
}
//
// Frame flags and layer id for temporal layers.
//
// For two layers, test pattern is:
// 1 3
// 0 2 .....
// For three layers, test pattern is:
// 1 3 5 7
// 2 6
// 0 4 ....
// LAST is always update on base/layer 0, GOLDEN is updated on layer 1.
// For this 3 layer example, the 2nd enhancement layer (layer 2) does not
// update any reference frames.
int SetFrameFlags(int frame_num, int num_temp_layers) {
int frame_flags = 0;
if (num_temp_layers == 2) {
if (frame_num % 2 == 0) {
// Layer 0: predict from L and ARF, update L.
frame_flags = VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF;
} else {
// Layer 1: predict from L, G and ARF, and update G.
frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_UPD_ENTROPY;
}
} else if (num_temp_layers == 3) {
if (frame_num % 4 == 0) {
// Layer 0: predict from L and ARF; update L.
frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_REF_GF;
} else if ((frame_num - 2) % 4 == 0) {
// Layer 1: predict from L, G, ARF; update G.
frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST;
} else if ((frame_num - 1) % 2 == 0) {
// Layer 2: predict from L, G, ARF; update none.
frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
VP8_EFLAG_NO_UPD_LAST;
}
}
return frame_flags;
}
int SetLayerId(int frame_num, int num_temp_layers) {
int layer_id = 0;
if (num_temp_layers == 2) {
if (frame_num % 2 == 0) {
layer_id = 0;
} else {
layer_id = 1;
}
} else if (num_temp_layers == 3) {
if (frame_num % 4 == 0) {
layer_id = 0;
} else if ((frame_num - 2) % 4 == 0) {
layer_id = 1;
} else if ((frame_num - 1) % 2 == 0) {
layer_id = 2;
}
}
return layer_id;
} }
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video, virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) { ::libvpx_test::Encoder *encoder) {
if (video->frame() == 1) { if (video->frame() == 1) {
encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_); encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_);
} }
if (cfg_.ts_number_layers > 1) {
if (video->frame() == 1) {
encoder->Control(VP9E_SET_SVC, 1);
}
vpx_svc_layer_id_t layer_id = {0, 0};
layer_id.spatial_layer_id = 0;
frame_flags_ = SetFrameFlags(video->frame(), cfg_.ts_number_layers);
layer_id.temporal_layer_id = SetLayerId(video->frame(),
cfg_.ts_number_layers);
if (video->frame() > 0) {
encoder->Control(VP9E_SET_SVC_LAYER_ID, &layer_id);
}
}
const vpx_rational_t tb = video->timebase(); const vpx_rational_t tb = video->timebase();
timebase_ = static_cast<double>(tb.num) / tb.den; timebase_ = static_cast<double>(tb.num) / tb.den;
duration_ = 0; duration_ = 0;
} }
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) { virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
int layer = SetLayerId(frame_number_, cfg_.ts_number_layers);
// Time since last timestamp = duration. // Time since last timestamp = duration.
vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_; vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_;
...@@ -227,7 +308,12 @@ class DatarateTestVP9 : public ::libvpx_test::EncoderTest, ...@@ -227,7 +308,12 @@ class DatarateTestVP9 : public ::libvpx_test::EncoderTest,
<< pkt->data.frame.pts; << pkt->data.frame.pts;
const size_t frame_size_in_bits = pkt->data.frame.sz * 8; const size_t frame_size_in_bits = pkt->data.frame.sz * 8;
bits_total_ += frame_size_in_bits;
// Update the total encoded bits. For temporal layers, update the cumulative
// encoded bits per layer.
for (int i = layer; i < static_cast<int>(cfg_.ts_number_layers); ++i) {
bits_total_[i] += frame_size_in_bits;
}
// If first drop not set and we have a drop set it to this time. // If first drop not set and we have a drop set it to this time.
if (!first_drop_ && duration > 1) if (!first_drop_ && duration > 1)
...@@ -244,19 +330,22 @@ class DatarateTestVP9 : public ::libvpx_test::EncoderTest, ...@@ -244,19 +330,22 @@ class DatarateTestVP9 : public ::libvpx_test::EncoderTest,
} }
virtual void EndPassHook(void) { virtual void EndPassHook(void) {
if (bits_total_) { for (int layer = 0; layer < static_cast<int>(cfg_.ts_number_layers);
++layer) {
duration_ = (last_pts_ + 1) * timebase_; duration_ = (last_pts_ + 1) * timebase_;
// Effective file datarate: if (bits_total_[layer]) {
effective_datarate_ = ((bits_total_) / 1000.0) / duration_; // Effective file datarate:
effective_datarate_[layer] = (bits_total_[layer] / 1000.0) / duration_;
}
} }
} }
vpx_codec_pts_t last_pts_; vpx_codec_pts_t last_pts_;
double timebase_; double timebase_;
int frame_number_; int frame_number_;
int64_t bits_total_; int64_t bits_total_[3];
double duration_; double duration_;
double effective_datarate_; double effective_datarate_[3];
int set_cpu_used_; int set_cpu_used_;
int64_t bits_in_buffer_model_; int64_t bits_in_buffer_model_;
vpx_codec_pts_t first_drop_; vpx_codec_pts_t first_drop_;
...@@ -272,6 +361,7 @@ TEST_P(DatarateTestVP9, BasicRateTargeting) { ...@@ -272,6 +361,7 @@ TEST_P(DatarateTestVP9, BasicRateTargeting) {
cfg_.rc_min_quantizer = 0; cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63; cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR; cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 140); 30, 1, 0, 140);
...@@ -279,12 +369,10 @@ TEST_P(DatarateTestVP9, BasicRateTargeting) { ...@@ -279,12 +369,10 @@ TEST_P(DatarateTestVP9, BasicRateTargeting) {
cfg_.rc_target_bitrate = i; cfg_.rc_target_bitrate = i;
ResetModel(); ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(static_cast<double>(cfg_.rc_target_bitrate), ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85)
effective_datarate_ * 0.85) << " The datarate for the file is lower than target by too much!";
<< " The datarate for the file exceeds the target by too much!"; ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15)
ASSERT_LE(static_cast<double>(cfg_.rc_target_bitrate), << " The datarate for the file is greater than target by too much!";
effective_datarate_ * 1.15)
<< " The datarate for the file missed the target!";
} }
} }
...@@ -309,10 +397,10 @@ TEST_P(DatarateTestVP9, BasicRateTargeting444) { ...@@ -309,10 +397,10 @@ TEST_P(DatarateTestVP9, BasicRateTargeting444) {
ResetModel(); ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(static_cast<double>(cfg_.rc_target_bitrate), ASSERT_GE(static_cast<double>(cfg_.rc_target_bitrate),
effective_datarate_ * 0.85) effective_datarate_[0] * 0.85)
<< " The datarate for the file exceeds the target by too much!"; << " The datarate for the file exceeds the target by too much!";
ASSERT_LE(static_cast<double>(cfg_.rc_target_bitrate), ASSERT_LE(static_cast<double>(cfg_.rc_target_bitrate),
effective_datarate_ * 1.15) effective_datarate_[0] * 1.15)
<< " The datarate for the file missed the target!" << " The datarate for the file missed the target!"
<< cfg_.rc_target_bitrate << " "<< effective_datarate_; << cfg_.rc_target_bitrate << " "<< effective_datarate_;
} }
...@@ -334,6 +422,7 @@ TEST_P(DatarateTestVP9, ChangingDropFrameThresh) { ...@@ -334,6 +422,7 @@ TEST_P(DatarateTestVP9, ChangingDropFrameThresh) {
cfg_.rc_max_quantizer = 50; cfg_.rc_max_quantizer = 50;
cfg_.rc_end_usage = VPX_CBR; cfg_.rc_end_usage = VPX_CBR;
cfg_.rc_target_bitrate = 200; cfg_.rc_target_bitrate = 200;
cfg_.g_lag_in_frames = 0;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 140); 30, 1, 0, 140);
...@@ -345,10 +434,10 @@ TEST_P(DatarateTestVP9, ChangingDropFrameThresh) { ...@@ -345,10 +434,10 @@ TEST_P(DatarateTestVP9, ChangingDropFrameThresh) {
cfg_.rc_dropframe_thresh = i; cfg_.rc_dropframe_thresh = i;
ResetModel(); ResetModel();
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(effective_datarate_, cfg_.rc_target_bitrate * 0.85) ASSERT_GE(effective_datarate_[0], cfg_.rc_target_bitrate * 0.85)
<< " The datarate for the file is lower than target by too much!"; << " The datarate for the file is lower than target by too much!";
ASSERT_LE(effective_datarate_, cfg_.rc_target_bitrate * 1.15) ASSERT_LE(effective_datarate_[0], cfg_.rc_target_bitrate * 1.15)
<< " The datarate for the file is greater than target by too much!"; << " The datarate for the file is greater than target by too much!";
ASSERT_LE(first_drop_, last_drop) ASSERT_LE(first_drop_, last_drop)
<< " The first dropped frame for drop_thresh " << i << " The first dropped frame for drop_thresh " << i
<< " > first dropped frame for drop_thresh " << " > first dropped frame for drop_thresh "
...@@ -362,6 +451,81 @@ TEST_P(DatarateTestVP9, ChangingDropFrameThresh) { ...@@ -362,6 +451,81 @@ TEST_P(DatarateTestVP9, ChangingDropFrameThresh) {
} }
} }
// Check basic rate targeting for 2 temporal layers.
TEST_P(DatarateTestVP9, BasicRateTargeting2TemporalLayers) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_dropframe_thresh = 1;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
// 2 Temporal layers, no spatial layers: Framerate decimation (2, 1).
cfg_.ss_number_layers = 1;
cfg_.ts_number_layers = 2;
cfg_.ts_rate_decimator[0] = 2;
cfg_.ts_rate_decimator[1] = 1;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200);
for (int i = 200; i <= 800; i += 200) {
cfg_.rc_target_bitrate = i;
ResetModel();
// 60-40 bitrate allocation for 2 temporal layers.
cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.85)
<< " The datarate for the file is lower than target by too much, "
"for layer: " << j;
ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.15)
<< " The datarate for the file is greater than target by too much, "
"for layer: " << j;
}
}
}
// Check basic rate targeting for 3 temporal layers.
TEST_P(DatarateTestVP9, BasicRateTargeting3TemporalLayers) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_dropframe_thresh = 1;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
// 3 Temporal layers, no spatial layers: Framerate decimation (4, 2, 1).
cfg_.ss_number_layers = 1;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200);
for (int i = 200; i <= 800; i += 200) {
cfg_.rc_target_bitrate = i;
ResetModel();
// 40-20-40 bitrate allocation for 3 temporal layers.
cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.85)
<< " The datarate for the file is lower than target by too much, "
"for layer: " << j;
ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.15)
<< " The datarate for the file is greater than target by too much, "
"for layer: " << j;
}
}
}
VP8_INSTANTIATE_TEST_CASE(DatarateTest, ALL_TEST_MODES); VP8_INSTANTIATE_TEST_CASE(DatarateTest, ALL_TEST_MODES);
VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9, VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9,
::testing::Values(::libvpx_test::kOnePassGood), ::testing::Values(::libvpx_test::kOnePassGood),
......
...@@ -123,6 +123,11 @@ class Encoder { ...@@ -123,6 +123,11 @@ class Encoder {
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
} }
void Control(int ctrl_id, struct vpx_svc_layer_id *arg) {
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}
void set_deadline(unsigned long deadline) { void set_deadline(unsigned long deadline) {
deadline_ = deadline; deadline_ = deadline;
} }
......
This diff is collapsed.
...@@ -147,8 +147,12 @@ extern "C" { ...@@ -147,8 +147,12 @@ extern "C" {
// END DATARATE CONTROL OPTIONS // END DATARATE CONTROL OPTIONS
// ---------------------------------------------------------------- // ----------------------------------------------------------------
// Spatial scalability // Spatial and temporal scalability.
int ss_number_layers; int ss_number_layers; // Number of spatial layers.
int ts_number_layers; // Number of temporal layers.
// Bitrate allocation (CBR mode) and framerate factor, for temporal layers.
int ts_target_bitrate[VPX_TS_MAX_LAYERS];
int ts_rate_decimator[VPX_TS_MAX_LAYERS];
// these parameters aren't to be used in final build don't use!!! // these parameters aren't to be used in final build don't use!!!
int play_alternate; int play_alternate;
......
...@@ -1144,6 +1144,109 @@ static int64_t rescale(int val, int64_t num, int denom) { ...@@ -1144,6 +1144,109 @@ static int64_t rescale(int val, int64_t num, int denom) {
return (llval * llnum / llden); return (llval * llnum / llden);
} }
// Initialize layer context data from init_config().
static void init_layer_context(VP9_COMP *const cpi) {
const VP9_CONFIG *const oxcf = &cpi->oxcf;
int temporal_layer = 0;
cpi->svc.spatial_layer_id = 0;
cpi->svc.temporal_layer_id = 0;
for (temporal_layer = 0; temporal_layer < cpi->svc.number_temporal_layers;
++temporal_layer) {
LAYER_CONTEXT *const lc = &cpi->svc.layer_context[temporal_layer];
RATE_CONTROL *const lrc = &lc->rc;
lrc->active_worst_quality = q_trans[oxcf->worst_allowed_q];
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 = lrc->active_worst_quality;
lrc->total_actual_bits = 0;
lrc->total_target_vs_actual = 0;
lrc->ni_tot_qi = 0;
lrc->tot_q = 0.0;
lrc->ni_frames = 0;
lrc->rate_correction_factor = 1.0;
lrc->key_frame_rate_correction_factor = 1.0;
lc->target_bandwidth = oxcf->ts_target_bitrate[temporal_layer] *
1000;
lrc->buffer_level = rescale((int)(oxcf->starting_buffer_level),
lc->target_bandwidth, 1000);
lrc->bits_off_target = lrc->buffer_level;
}
}
// Update the layer context from a change_config() call.
static void update_layer_context_change_config(VP9_COMP *const cpi,
const int target_bandwidth) {
const VP9_CONFIG *const oxcf = &cpi->oxcf;
const RATE_CONTROL *const rc = &cpi->rc;
int temporal_layer = 0;
float bitrate_alloc = 1.0;
for (temporal_layer = 0; temporal_layer < cpi->svc.number_temporal_layers;
++temporal_layer) {
LAYER_CONTEXT *const lc = &cpi->svc.layer_context[temporal_layer];
RATE_CONTROL *const lrc = &lc->rc;
lc->target_bandwidth = oxcf->ts_target_bitrate[temporal_layer] * 1000;
bitrate_alloc = (float)lc->target_bandwidth / (float)target_bandwidth;
// Update buffer-related quantities.
lc->starting_buffer_level = oxcf->starting_buffer_level * bitrate_alloc;
lc->optimal_buffer_level = oxcf->optimal_buffer_level * bitrate_alloc;
lc->maximum_buffer_size = oxcf->maximum_buffer_size * bitrate_alloc;
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[temporal_layer];
lrc->av_per_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
lrc->max_frame_bandwidth = rc->max_frame_bandwidth;
// Update qp-related quantities.
lrc->worst_quality = rc->worst_quality;
lrc->best_quality = rc->best_quality;
lrc->active_worst_quality = rc->active_worst_quality;
}
}
// Prior to encoding the frame, update framerate-related quantities
// for the current layer.
static void update_layer_framerate(VP9_COMP *const cpi) {
int temporal_layer = cpi->svc.temporal_layer_id;
LAYER_CONTEXT *const lc = &cpi->svc.layer_context[temporal_layer];
RATE_CONTROL *const lrc = &lc->rc;
lc->framerate = cpi->oxcf.framerate /
cpi->oxcf.ts_rate_decimator[temporal_layer];
lrc->av_per_frame_bandwidth = (int)(lc->target_bandwidth /
lc->framerate);
lrc->max_frame_bandwidth = cpi->rc.max_frame_bandwidth;
}
// Prior to encoding the frame, set the layer context, for the current layer
// to be encoded, to the cpi struct.
static void restore_layer_context(VP9_COMP *const cpi) {
int temporal_layer = cpi->svc.temporal_layer_id;
LAYER_CONTEXT *lc = &cpi->svc.layer_context[temporal_layer];
int frame_since_key = cpi->rc.frames_since_key;
int frame_to_key = cpi->rc.frames_to_key;
cpi->rc = lc->rc;
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;
cpi->oxcf.maximum_buffer_size = lc->maximum_buffer_size;
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 = frame_since_key;
cpi->rc.frames_to_key = frame_to_key;
}
// Save the layer context after encoding the frame.
static void save_layer_context(VP9_COMP *const cpi) {
int temporal_layer = cpi->svc.temporal_layer_id;
LAYER_CONTEXT *lc = &cpi->svc.layer_context[temporal_layer];
lc->rc = cpi->rc;
lc->target_bandwidth = cpi->oxcf.target_bandwidth;
lc->starting_buffer_level = cpi->oxcf.starting_buffer_level;
lc->optimal_buffer_level = cpi->oxcf.optimal_buffer_level;
lc->maximum_buffer_size = cpi->oxcf.maximum_buffer_size;
lc->framerate = cpi->output_framerate;
}
static void set_tile_limits(VP9_COMP *cpi) { static void set_tile_limits(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common; VP9_COMMON *const cm = &cpi->common;
...@@ -1170,6 +1273,16 @@ static void init_config(VP9_PTR ptr, VP9_CONFIG *oxcf) { ...@@ -1170,6 +1273,16 @@ static void init_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
cm->subsampling_y = 0; cm->subsampling_y = 0;
vp9_alloc_compressor_data(cpi); vp9_alloc_compressor_data(cpi);
// Spatial scalability.
cpi->svc.number_spatial_layers = oxcf->ss_number_layers;
// 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) {
init_layer_context(cpi);
}
// change includes all joint functionality // change includes all joint functionality
vp9_change_config(ptr, oxcf); vp9_change_config(ptr, oxcf);
...@@ -1210,9 +1323,6 @@ static void init_config(VP9_PTR ptr, VP9_CONFIG *oxcf) { ...@@ -1210,9 +1323,6 @@ static void init_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
cpi->gld_fb_idx = 1; cpi->gld_fb_idx = 1;
cpi->alt_fb_idx = 2; cpi->alt_fb_idx = 2;
cpi->current_layer = 0;
cpi->use_svc = 0;
set_tile_limits(cpi); set_tile_limits(cpi);
cpi->fixed_divide[0] = 0; cpi->fixed_divide[0] = 0;
...@@ -1220,7 +1330,6 @@ static void init_config(VP9_PTR ptr, VP9_CONFIG *oxcf) { ...@@ -1220,7 +1330,6 @@ static void init_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
cpi->fixed_divide[i] = 0x80000 / i; cpi->fixed_divide[i] = 0x80000 / i;
} }
void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) { void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
VP9_COMP *cpi = (VP9_COMP *)(ptr); VP9_COMP *cpi = (VP9_COMP *)(ptr);
VP9_COMMON *const cm = &cpi->common; VP9_COMMON *const cm = &cpi->common;
...@@ -1312,10 +1421,10 @@ void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) { ...@@ -1312,10 +1421,10 @@ void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
cpi->oxcf.target_bandwidth, 1000); cpi->oxcf.target_bandwidth, 1000);
// Under a configuration change, where maximum_buffer_size may change, // Under a configuration change, where maximum_buffer_size may change,
// keep buffer level clipped to the maximum allowed buffer size. // keep buffer level clipped to the maximum allowed buffer size.
if (cpi->rc.bits_off_target > cpi->oxcf.maximum_buffer_size) { cpi->rc.bits_off_target = MIN(cpi->rc.bits_off_target,
cpi->rc.bits_off_target = cpi->oxcf.maximum_buffer_size; cpi->oxcf.maximum_buffer_size);
cpi->rc.buffer_level = cpi->rc.bits_off_target; cpi->rc.buffer_level = MIN(cpi->rc.buffer_level,
} cpi->oxcf.maximum_buffer_size);
// Set up frame rate and related parameters rate control values. // Set up frame rate and related parameters rate control values.
vp9_new_framerate(cpi, cpi->oxcf.framerate); vp9_new_framerate(cpi, cpi->oxcf.framerate);
...@@ -1350,6 +1459,11 @@ void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) { ...@@ -1350,6 +1459,11 @@ void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) {
} }
update_frame_size(cpi); update_frame_size(cpi);