vp9-svc: Add layer bitrate targeting to SVC datarate tests.

Modify and update the SVC datarate unittests to verify the
rate targeting for each spatial-temporal layer.
The current tests were only verifying the rate targeting
of the full SVC stream, not individual layers.
Also re-enabled a test that was disabled.

This is a stronger verification of the layered rate control
for SVC for 1 pass CBR encoding.

Added PostEncodeFrameHook, needed to get the layer_id and
update the layer buffer level.

Change-Id: I9fd54ad474686b20a6de3250d587e2cec194a56f
This commit is contained in:
Marco 2017-12-14 16:35:33 -08:00
parent a2127236ae
commit 9ca9c12dbd
3 changed files with 200 additions and 66 deletions

View File

@ -1216,16 +1216,17 @@ class DatarateOnePassCbrSvc
} }
virtual void ResetModel() { virtual void ResetModel() {
last_pts_ = 0; last_pts_ = 0;
bits_in_buffer_model_ = cfg_.rc_target_bitrate * cfg_.rc_buf_initial_sz;
frame_number_ = 0;
first_drop_ = 0;
bits_total_ = 0;
duration_ = 0.0; duration_ = 0.0;
mismatch_psnr_ = 0.0; mismatch_psnr_ = 0.0;
mismatch_nframes_ = 0; mismatch_nframes_ = 0;
denoiser_on_ = 0; denoiser_on_ = 0;
tune_content_ = 0; tune_content_ = 0;
base_speed_setting_ = 5; base_speed_setting_ = 5;
spatial_layer_id_ = 0;
temporal_layer_id_ = 0;
memset(bits_in_buffer_model_, 0, sizeof(bits_in_buffer_model_));
memset(bits_total_, 0, sizeof(bits_total_));
memset(layer_target_avg_bandwidth_, 0, sizeof(layer_target_avg_bandwidth_));
} }
virtual void BeginPassHook(unsigned int /*pass*/) {} virtual void BeginPassHook(unsigned int /*pass*/) {}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video, virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
@ -1256,30 +1257,94 @@ class DatarateOnePassCbrSvc
timebase_ = static_cast<double>(tb.num) / tb.den; timebase_ = static_cast<double>(tb.num) / tb.den;
duration_ = 0; duration_ = 0;
} }
virtual void PostEncodeFrameHook(::libvpx_test::Encoder *encoder) {
vpx_svc_layer_id_t layer_id;
encoder->Control(VP9E_GET_SVC_LAYER_ID, &layer_id);
spatial_layer_id_ = layer_id.spatial_layer_id;
temporal_layer_id_ = layer_id.temporal_layer_id;
// Update buffer with per-layer target frame bandwidth, this is done
// for every frame passed to the encoder (encoded or dropped).
// For temporal layers, update the cumulative buffer level.
for (int sl = 0; sl < number_spatial_layers_; ++sl) {
for (int tl = temporal_layer_id_; tl < number_temporal_layers_; ++tl) {
const int layer = sl * number_temporal_layers_ + tl;
bits_in_buffer_model_[layer] +=
static_cast<int64_t>(layer_target_avg_bandwidth_[layer]);
}
}
}
vpx_codec_err_t parse_superframe_index(const uint8_t *data, size_t data_sz,
uint32_t sizes[8], int *count) {
uint8_t marker;
marker = *(data + data_sz - 1);
*count = 0;
if ((marker & 0xe0) == 0xc0) {
const uint32_t frames = (marker & 0x7) + 1;
const uint32_t mag = ((marker >> 3) & 0x3) + 1;
const size_t index_sz = 2 + mag * frames;
// This chunk is marked as having a superframe index but doesn't have
// enough data for it, thus it's an invalid superframe index.
if (data_sz < index_sz) return VPX_CODEC_CORRUPT_FRAME;
{
const uint8_t marker2 = *(data + data_sz - index_sz);
// This chunk is marked as having a superframe index but doesn't have
// the matching marker byte at the front of the index therefore it's an
// invalid chunk.
if (marker != marker2) return VPX_CODEC_CORRUPT_FRAME;
}
{
uint32_t i, j;
const uint8_t *x = &data[data_sz - index_sz + 1];
for (i = 0; i < frames; ++i) {
uint32_t this_sz = 0;
for (j = 0; j < mag; ++j) this_sz |= (*x++) << (j * 8);
sizes[i] = this_sz;
}
*count = frames;
}
}
return VPX_CODEC_OK;
}
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) { virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_; uint32_t sizes[8] = { 0 };
if (last_pts_ == 0) duration = 1; int count = 0;
bits_in_buffer_model_ += static_cast<int64_t>( last_pts_ = pkt->data.frame.pts;
duration * timebase_ * cfg_.rc_target_bitrate * 1000);
const bool key_frame = const bool key_frame =
(pkt->data.frame.flags & VPX_FRAME_IS_KEY) ? true : false; (pkt->data.frame.flags & VPX_FRAME_IS_KEY) ? true : false;
if (!key_frame) { parse_superframe_index(static_cast<const uint8_t *>(pkt->data.frame.buf),
ASSERT_GE(bits_in_buffer_model_, 0) pkt->data.frame.sz, sizes, &count);
<< "Buffer Underrun at frame " << pkt->data.frame.pts; ASSERT_EQ(count, number_spatial_layers_);
for (int sl = 0; sl < number_spatial_layers_; ++sl) {
sizes[sl] = sizes[sl] << 3;
// Update the total encoded bits per layer.
// For temporal layers, update the cumulative encoded bits per layer.
for (int tl = temporal_layer_id_; tl < number_temporal_layers_; ++tl) {
const int layer = sl * number_temporal_layers_ + tl;
bits_total_[layer] += static_cast<int64_t>(sizes[sl]);
// Update the per-layer buffer level with the encoded frame size.
bits_in_buffer_model_[layer] -= static_cast<int64_t>(sizes[sl]);
// There should be no buffer underrun, except on the base
// temporal layer, since there may be key frames there.
if (!key_frame && tl > 0) {
ASSERT_GE(bits_in_buffer_model_[layer], 0)
<< "Buffer Underrun at frame " << pkt->data.frame.pts;
}
}
} }
const size_t frame_size_in_bits = pkt->data.frame.sz * 8;
bits_in_buffer_model_ -= static_cast<int64_t>(frame_size_in_bits);
bits_total_ += frame_size_in_bits;
if (!first_drop_ && duration > 1) first_drop_ = last_pts_ + 1;
last_pts_ = pkt->data.frame.pts;
bits_in_last_frame_ = frame_size_in_bits;
++frame_number_;
} }
virtual void EndPassHook(void) { virtual void EndPassHook(void) {
if (bits_total_) { for (int sl = 0; sl < number_spatial_layers_; ++sl) {
const double file_size_in_kb = bits_total_ / 1000.; // bits per kilobit for (int tl = 0; tl < number_temporal_layers_; ++tl) {
duration_ = (last_pts_ + 1) * timebase_; const int layer = sl * number_temporal_layers_ + tl;
file_datarate_ = file_size_in_kb / duration_; const double file_size_in_kb = bits_total_[layer] / 1000.;
duration_ = (last_pts_ + 1) * timebase_;
file_datarate_[layer] = file_size_in_kb / duration_;
}
} }
} }
@ -1292,13 +1357,11 @@ class DatarateOnePassCbrSvc
unsigned int GetMismatchFrames() { return mismatch_nframes_; } unsigned int GetMismatchFrames() { return mismatch_nframes_; }
vpx_codec_pts_t last_pts_; vpx_codec_pts_t last_pts_;
int64_t bits_in_buffer_model_; int64_t bits_in_buffer_model_[VPX_MAX_LAYERS];
double timebase_; double timebase_;
int frame_number_; int64_t bits_total_[VPX_MAX_LAYERS];
vpx_codec_pts_t first_drop_;
int64_t bits_total_;
double duration_; double duration_;
double file_datarate_; double file_datarate_[VPX_MAX_LAYERS];
size_t bits_in_last_frame_; size_t bits_in_last_frame_;
vpx_svc_extra_cfg_t svc_params_; vpx_svc_extra_cfg_t svc_params_;
int speed_setting_; int speed_setting_;
@ -1307,14 +1370,22 @@ class DatarateOnePassCbrSvc
int denoiser_on_; int denoiser_on_;
int tune_content_; int tune_content_;
int base_speed_setting_; int base_speed_setting_;
int spatial_layer_id_;
int temporal_layer_id_;
int number_spatial_layers_;
int number_temporal_layers_;
int layer_target_avg_bandwidth_[VPX_MAX_LAYERS];
}; };
static void assign_layer_bitrates(vpx_codec_enc_cfg_t *const enc_cfg, static void assign_layer_bitrates(vpx_codec_enc_cfg_t *const enc_cfg,
const vpx_svc_extra_cfg_t *svc_params, const vpx_svc_extra_cfg_t *svc_params,
int spatial_layers, int temporal_layers, int spatial_layers, int temporal_layers,
int temporal_layering_mode) { int temporal_layering_mode,
int *layer_target_avg_bandwidth,
int64_t *bits_in_buffer_model) {
int sl, spatial_layer_target; int sl, spatial_layer_target;
float total = 0; float total = 0;
float alloc_ratio[VPX_MAX_LAYERS] = { 0 }; float alloc_ratio[VPX_MAX_LAYERS] = { 0 };
float framerate = 30.0;
for (sl = 0; sl < spatial_layers; ++sl) { for (sl = 0; sl < spatial_layers; ++sl) {
if (svc_params->scaling_factor_den[sl] > 0) { if (svc_params->scaling_factor_den[sl] > 0) {
alloc_ratio[sl] = (float)(svc_params->scaling_factor_num[sl] * 1.0 / alloc_ratio[sl] = (float)(svc_params->scaling_factor_num[sl] * 1.0 /
@ -1334,8 +1405,41 @@ static void assign_layer_bitrates(vpx_codec_enc_cfg_t *const enc_cfg,
} else if (temporal_layering_mode == 2) { } else if (temporal_layering_mode == 2) {
enc_cfg->layer_target_bitrate[index] = spatial_layer_target * 2 / 3; enc_cfg->layer_target_bitrate[index] = spatial_layer_target * 2 / 3;
enc_cfg->layer_target_bitrate[index + 1] = spatial_layer_target; enc_cfg->layer_target_bitrate[index + 1] = spatial_layer_target;
} else if (temporal_layering_mode <= 1) {
enc_cfg->layer_target_bitrate[index] = spatial_layer_target;
} }
} }
for (sl = 0; sl < spatial_layers; ++sl) {
for (int tl = 0; tl < temporal_layers; ++tl) {
const int layer = sl * temporal_layers + tl;
float layer_framerate = framerate;
if (temporal_layers == 2 && tl == 0) layer_framerate = framerate / 2;
if (temporal_layers == 3 && tl == 0) layer_framerate = framerate / 4;
if (temporal_layers == 3 && tl == 1) layer_framerate = framerate / 2;
layer_target_avg_bandwidth[layer] = static_cast<int>(
enc_cfg->layer_target_bitrate[layer] * 1000.0 / layer_framerate);
bits_in_buffer_model[layer] =
enc_cfg->layer_target_bitrate[layer] * enc_cfg->rc_buf_initial_sz;
}
}
}
static void CheckLayerRateTargeting(vpx_codec_enc_cfg_t *const cfg,
int number_spatial_layers,
int number_temporal_layers,
double *file_datarate,
double thresh_overshoot,
double thresh_undershoot) {
for (int sl = 0; sl < number_spatial_layers; ++sl)
for (int tl = 0; tl < number_temporal_layers; ++tl) {
const int layer = sl * number_temporal_layers + tl;
ASSERT_GE(cfg->layer_target_bitrate[layer],
file_datarate[layer] * thresh_overshoot)
<< " The datarate for the file exceeds the target by too much!";
ASSERT_LE(cfg->layer_target_bitrate[layer],
file_datarate[layer] * thresh_undershoot)
<< " The datarate for the file is lower than the target by too much!";
}
} }
// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and 1 // Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and 1
@ -1361,14 +1465,19 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SL1TLScreenContent1) {
svc_params_.scaling_factor_den[1] = 288; svc_params_.scaling_factor_den[1] = 288;
cfg_.rc_dropframe_thresh = 10; cfg_.rc_dropframe_thresh = 10;
cfg_.kf_max_dist = 9999; cfg_.kf_max_dist = 9999;
number_spatial_layers_ = cfg_.ss_number_layers;
number_temporal_layers_ = cfg_.ts_number_layers;
::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60); ::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
cfg_.rc_target_bitrate = 500; cfg_.rc_target_bitrate = 500;
ResetModel(); ResetModel();
tune_content_ = 1; tune_content_ = 1;
base_speed_setting_ = speed_setting_; base_speed_setting_ = speed_setting_;
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode); cfg_.ts_number_layers, cfg_.temporal_layering_mode,
layer_target_avg_bandwidth_, bits_in_buffer_model_);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
number_temporal_layers_, file_datarate_, 0.78, 1.15);
EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames()); EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
} }
@ -1396,6 +1505,8 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SL3TL) {
svc_params_.scaling_factor_den[1] = 288; svc_params_.scaling_factor_den[1] = 288;
cfg_.rc_dropframe_thresh = 0; cfg_.rc_dropframe_thresh = 0;
cfg_.kf_max_dist = 9999; cfg_.kf_max_dist = 9999;
number_spatial_layers_ = cfg_.ss_number_layers;
number_temporal_layers_ = cfg_.ts_number_layers;
::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1, ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
0, 400); 0, 400);
// TODO(marpan): Check that effective_datarate for each layer hits the // TODO(marpan): Check that effective_datarate for each layer hits the
@ -1404,12 +1515,12 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SL3TL) {
cfg_.rc_target_bitrate = i; cfg_.rc_target_bitrate = i;
ResetModel(); ResetModel();
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode); cfg_.ts_number_layers, cfg_.temporal_layering_mode,
layer_target_avg_bandwidth_, bits_in_buffer_model_);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.78) CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
<< " The datarate for the file exceeds the target by too much!"; number_temporal_layers_, file_datarate_, 0.78,
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15) 1.15);
<< " The datarate for the file is lower than the target by too much!";
#if CONFIG_VP9_DECODER #if CONFIG_VP9_DECODER
// Number of temporal layers > 1, so half of the frames in this SVC pattern // Number of temporal layers > 1, so half of the frames in this SVC pattern
// will be non-reference frame and hence encoder will avoid loopfilter. // will be non-reference frame and hence encoder will avoid loopfilter.
@ -1444,6 +1555,8 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SL3TLDenoiserOn) {
svc_params_.scaling_factor_den[1] = 288; svc_params_.scaling_factor_den[1] = 288;
cfg_.rc_dropframe_thresh = 0; cfg_.rc_dropframe_thresh = 0;
cfg_.kf_max_dist = 9999; cfg_.kf_max_dist = 9999;
number_spatial_layers_ = cfg_.ss_number_layers;
number_temporal_layers_ = cfg_.ts_number_layers;
::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1, ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
0, 400); 0, 400);
// TODO(marpan): Check that effective_datarate for each layer hits the // TODO(marpan): Check that effective_datarate for each layer hits the
@ -1456,12 +1569,12 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SL3TLDenoiserOn) {
ResetModel(); ResetModel();
denoiser_on_ = noise_sen; denoiser_on_ = noise_sen;
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode); cfg_.ts_number_layers, cfg_.temporal_layering_mode,
layer_target_avg_bandwidth_, bits_in_buffer_model_);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.78) CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
<< " The datarate for the file exceeds the target by too much!"; number_temporal_layers_, file_datarate_, 0.78,
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15) 1.15);
<< " The datarate for the file is lower than the target by too much!";
#if CONFIG_VP9_DECODER #if CONFIG_VP9_DECODER
// Number of temporal layers > 1, so half of the frames in this SVC // Number of temporal layers > 1, so half of the frames in this SVC
// pattern // pattern
@ -1476,7 +1589,7 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SL3TLDenoiserOn) {
// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and 3 // Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and 3
// temporal layers. Run CIF clip with 1 thread, and few short key frame periods. // temporal layers. Run CIF clip with 1 thread, and few short key frame periods.
TEST_P(DatarateOnePassCbrSvc, DISABLED_OnePassCbrSvc2SL3TLSmallKf) { TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SL3TLSmallKf) {
cfg_.rc_buf_initial_sz = 500; cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500; cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000; cfg_.rc_buf_sz = 1000;
@ -1498,6 +1611,8 @@ TEST_P(DatarateOnePassCbrSvc, DISABLED_OnePassCbrSvc2SL3TLSmallKf) {
svc_params_.scaling_factor_den[1] = 288; svc_params_.scaling_factor_den[1] = 288;
cfg_.rc_dropframe_thresh = 10; cfg_.rc_dropframe_thresh = 10;
cfg_.rc_target_bitrate = 400; cfg_.rc_target_bitrate = 400;
number_spatial_layers_ = cfg_.ss_number_layers;
number_temporal_layers_ = cfg_.ts_number_layers;
::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1, ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
0, 400); 0, 400);
// For this 3 temporal layer case, pattern repeats every 4 frames, so choose // For this 3 temporal layer case, pattern repeats every 4 frames, so choose
@ -1506,12 +1621,12 @@ TEST_P(DatarateOnePassCbrSvc, DISABLED_OnePassCbrSvc2SL3TLSmallKf) {
cfg_.kf_max_dist = j; cfg_.kf_max_dist = j;
ResetModel(); ResetModel();
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode); cfg_.ts_number_layers, cfg_.temporal_layering_mode,
layer_target_avg_bandwidth_, bits_in_buffer_model_);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.80) CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
<< " The datarate for the file exceeds the target by too much!"; number_temporal_layers_, file_datarate_, 0.78,
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15) 1.15);
<< " The datarate for the file is lower than the target by too much!";
} }
} }
@ -1539,16 +1654,17 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SL3TL4Threads) {
svc_params_.scaling_factor_den[1] = 288; svc_params_.scaling_factor_den[1] = 288;
cfg_.rc_dropframe_thresh = 0; cfg_.rc_dropframe_thresh = 0;
cfg_.kf_max_dist = 9999; cfg_.kf_max_dist = 9999;
number_spatial_layers_ = cfg_.ss_number_layers;
number_temporal_layers_ = cfg_.ts_number_layers;
::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60); ::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
cfg_.rc_target_bitrate = 800; cfg_.rc_target_bitrate = 800;
ResetModel(); ResetModel();
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode); cfg_.ts_number_layers, cfg_.temporal_layering_mode,
layer_target_avg_bandwidth_, bits_in_buffer_model_);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.78) CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
<< " The datarate for the file exceeds the target by too much!"; number_temporal_layers_, file_datarate_, 0.78, 1.15);
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15)
<< " The datarate for the file is lower than the target by too much!";
#if CONFIG_VP9_DECODER #if CONFIG_VP9_DECODER
// Number of temporal layers > 1, so half of the frames in this SVC pattern // Number of temporal layers > 1, so half of the frames in this SVC pattern
// will be non-reference frame and hence encoder will avoid loopfilter. // will be non-reference frame and hence encoder will avoid loopfilter.
@ -1584,17 +1700,18 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SL3TL) {
svc_params_.scaling_factor_den[2] = 288; svc_params_.scaling_factor_den[2] = 288;
cfg_.rc_dropframe_thresh = 0; cfg_.rc_dropframe_thresh = 0;
cfg_.kf_max_dist = 9999; cfg_.kf_max_dist = 9999;
number_spatial_layers_ = cfg_.ss_number_layers;
number_temporal_layers_ = cfg_.ts_number_layers;
::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1, ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
0, 400); 0, 400);
cfg_.rc_target_bitrate = 800; cfg_.rc_target_bitrate = 800;
ResetModel(); ResetModel();
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode); cfg_.ts_number_layers, cfg_.temporal_layering_mode,
layer_target_avg_bandwidth_, bits_in_buffer_model_);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.78) CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
<< " The datarate for the file exceeds the target by too much!"; number_temporal_layers_, file_datarate_, 0.78, 1.15);
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.22)
<< " The datarate for the file is lower than the target by too much!";
#if CONFIG_VP9_DECODER #if CONFIG_VP9_DECODER
// Number of temporal layers > 1, so half of the frames in this SVC pattern // Number of temporal layers > 1, so half of the frames in this SVC pattern
// will be non-reference frame and hence encoder will avoid loopfilter. // will be non-reference frame and hence encoder will avoid loopfilter.
@ -1630,6 +1747,8 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SL3TLSmallKf) {
svc_params_.scaling_factor_den[2] = 288; svc_params_.scaling_factor_den[2] = 288;
cfg_.rc_dropframe_thresh = 10; cfg_.rc_dropframe_thresh = 10;
cfg_.rc_target_bitrate = 800; cfg_.rc_target_bitrate = 800;
number_spatial_layers_ = cfg_.ss_number_layers;
number_temporal_layers_ = cfg_.ts_number_layers;
::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1, ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
0, 400); 0, 400);
// For this 3 temporal layer case, pattern repeats every 4 frames, so choose // For this 3 temporal layer case, pattern repeats every 4 frames, so choose
@ -1638,12 +1757,12 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SL3TLSmallKf) {
cfg_.kf_max_dist = j; cfg_.kf_max_dist = j;
ResetModel(); ResetModel();
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode); cfg_.ts_number_layers, cfg_.temporal_layering_mode,
layer_target_avg_bandwidth_, bits_in_buffer_model_);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.80) CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
<< " The datarate for the file exceeds the target by too much!"; number_temporal_layers_, file_datarate_, 0.78,
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.30) 1.15);
<< " The datarate for the file is lower than the target by too much!";
} }
} }
@ -1673,16 +1792,17 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc3SL3TL4threads) {
svc_params_.scaling_factor_den[2] = 288; svc_params_.scaling_factor_den[2] = 288;
cfg_.rc_dropframe_thresh = 0; cfg_.rc_dropframe_thresh = 0;
cfg_.kf_max_dist = 9999; cfg_.kf_max_dist = 9999;
number_spatial_layers_ = cfg_.ss_number_layers;
number_temporal_layers_ = cfg_.ts_number_layers;
::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60); ::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
cfg_.rc_target_bitrate = 800; cfg_.rc_target_bitrate = 800;
ResetModel(); ResetModel();
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers, assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode); cfg_.ts_number_layers, cfg_.temporal_layering_mode,
layer_target_avg_bandwidth_, bits_in_buffer_model_);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, file_datarate_ * 0.78) CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
<< " The datarate for the file exceeds the target by too much!"; number_temporal_layers_, file_datarate_, 0.78, 1.15);
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.22)
<< " The datarate for the file is lower than the target by too much!";
#if CONFIG_VP9_DECODER #if CONFIG_VP9_DECODER
// Number of temporal layers > 1, so half of the frames in this SVC pattern // Number of temporal layers > 1, so half of the frames in this SVC pattern
// will be non-reference frame and hence encoder will avoid loopfilter. // will be non-reference frame and hence encoder will avoid loopfilter.
@ -1720,9 +1840,19 @@ TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc2SL1TL5x5MultipleRuns) {
cfg_.layer_target_bitrate[0] = 300; cfg_.layer_target_bitrate[0] = 300;
cfg_.layer_target_bitrate[1] = 1400; cfg_.layer_target_bitrate[1] = 1400;
cfg_.rc_target_bitrate = 1700; cfg_.rc_target_bitrate = 1700;
::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60); number_spatial_layers_ = cfg_.ss_number_layers;
number_temporal_layers_ = cfg_.ts_number_layers;
ResetModel(); ResetModel();
layer_target_avg_bandwidth_[0] = cfg_.layer_target_bitrate[0] * 1000 / 30;
bits_in_buffer_model_[0] =
cfg_.layer_target_bitrate[0] * cfg_.rc_buf_initial_sz;
layer_target_avg_bandwidth_[1] = cfg_.layer_target_bitrate[1] * 1000 / 30;
bits_in_buffer_model_[1] =
cfg_.layer_target_bitrate[1] * cfg_.rc_buf_initial_sz;
::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
CheckLayerRateTargeting(&cfg_, number_spatial_layers_,
number_temporal_layers_, file_datarate_, 0.78, 1.15);
EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames()); EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
} }

View File

@ -201,6 +201,8 @@ void EncoderTest::RunLoop(VideoSource *video) {
PreEncodeFrameHook(video, encoder.get()); PreEncodeFrameHook(video, encoder.get());
encoder->EncodeFrame(video, frame_flags_); encoder->EncodeFrame(video, frame_flags_);
PostEncodeFrameHook(encoder.get());
CxDataIterator iter = encoder->GetCxData(); CxDataIterator iter = encoder->GetCxData();
bool has_cxdata = false; bool has_cxdata = false;

View File

@ -219,6 +219,8 @@ class EncoderTest {
virtual void PreEncodeFrameHook(VideoSource * /*video*/, virtual void PreEncodeFrameHook(VideoSource * /*video*/,
Encoder * /*encoder*/) {} Encoder * /*encoder*/) {}
virtual void PostEncodeFrameHook(Encoder * /*encoder*/) {}
// Hook to be called on every compressed data packet. // Hook to be called on every compressed data packet.
virtual void FramePktHook(const vpx_codec_cx_pkt_t * /*pkt*/) {} virtual void FramePktHook(const vpx_codec_cx_pkt_t * /*pkt*/) {}