rtc: Spatial layers for RTC
Make spatial layers work for RTC mode.
Added unittest and updated sample encoder.
Change-Id: I221b5f421d6c6eaf0e2c8df2a3c0faade2b0c9fc
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index 2e56077..3874904 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -393,6 +393,12 @@
// Clear down mmx registers
aom_clear_system_state();
+ if (cpi->use_svc && cpi->svc.spatial_layer_id > 0) {
+ cpi->framerate = cpi->svc.base_framerate;
+ av1_rc_update_framerate(cpi, cpi->common.width, cpi->common.height);
+ return;
+ }
+
if (source->ts_start == cpi->first_time_stamp_ever) {
this_duration = source->ts_end - source->ts_start;
step = 1;
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index c564e2e..37fff27 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -765,6 +765,8 @@
for (int i = 0; i < MAX_NUM_OPERATING_POINTS; ++i) {
aom_free(cpi->level_info[i]);
}
+
+ if (cpi->use_svc) av1_free_svc_cyclic_refresh(cpi);
}
static void save_coding_context(AV1_COMP *cpi) {
@@ -4070,7 +4072,7 @@
}
// Returns 1 if the assigned width or height was <= 0.
-static int set_size_literal(AV1_COMP *cpi, int width, int height) {
+int av1_set_size_literal(AV1_COMP *cpi, int width, int height) {
AV1_COMMON *cm = &cpi->common;
const int num_planes = av1_num_planes(cm);
check_initial_width(cpi, cm->seq_params.use_highbitdepth,
@@ -4104,7 +4106,7 @@
if (width != cm->width || height != cm->height) {
// There has been a change in the encoded frame size
- set_size_literal(cpi, width, height);
+ av1_set_size_literal(cpi, width, height);
set_mv_search_params(cpi);
// Recalculate 'all_lossless' in case super-resolution was (un)selected.
cm->all_lossless = cm->coded_lossless && !av1_superres_scaled(cm);
@@ -4415,6 +4417,12 @@
const AV1EncoderConfig *oxcf = &cpi->oxcf;
size_params_type rsz = { oxcf->width, oxcf->height, SCALE_NUMERATOR };
int resize_denom = SCALE_NUMERATOR;
+ if (oxcf->pass == 0 && cpi->use_svc &&
+ cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1) {
+ rsz.resize_width = cpi->common.width;
+ rsz.resize_height = cpi->common.height;
+ return rsz;
+ }
if (oxcf->pass == 1) return rsz;
if (cpi->resize_pending_width && cpi->resize_pending_height) {
rsz.resize_width = cpi->resize_pending_width;
@@ -6282,6 +6290,9 @@
aom_bitstream_queue_set_frame_write(cm->current_frame.frame_number * 2 +
cm->show_frame);
#endif
+ if (cpi->use_svc && cm->number_spatial_layers > 1) {
+ av1_one_pass_cbr_svc_start_layer(cpi);
+ }
// Indicates whether or not to use an adaptive quantize b rather than
// the traditional version
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index fe91842..5d4343d 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -1152,6 +1152,8 @@
int av1_set_reference_enc(AV1_COMP *cpi, int idx, YV12_BUFFER_CONFIG *sd);
+int av1_set_size_literal(AV1_COMP *cpi, int width, int height);
+
void av1_set_frame_size(AV1_COMP *cpi, int width, int height);
int av1_update_entropy(AV1_COMP *cpi, int update);
diff --git a/av1/encoder/svc_layercontext.c b/av1/encoder/svc_layercontext.c
index 3c34335..59a4f3d 100644
--- a/av1/encoder/svc_layercontext.c
+++ b/av1/encoder/svc_layercontext.c
@@ -26,6 +26,7 @@
SVC *const svc = &cpi->svc;
int mi_rows = cpi->common.mi_rows;
int mi_cols = cpi->common.mi_cols;
+ svc->base_framerate = 30.0;
for (int sl = 0; sl < svc->number_spatial_layers; ++sl) {
for (int tl = 0; tl < svc->number_temporal_layers; ++tl) {
@@ -178,6 +179,7 @@
lc->rc = cpi->rc;
lc->target_bandwidth = (int)cpi->oxcf.target_bandwidth;
lc->group_index = gf_group->index;
+ if (cpi->svc.spatial_layer_id == 0) cpi->svc.base_framerate = cpi->framerate;
// For spatial-svc, allow cyclic-refresh to be applied on the spatial layers,
// for the base temporal layer.
if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ &&
@@ -220,3 +222,29 @@
av1_update_temporal_layer_framerate(cpi);
av1_restore_layer_context(cpi);
}
+
+static void get_layer_resolution(const int width_org, const int height_org,
+ const int num, const int den, int *width_out,
+ int *height_out) {
+ int w, h;
+ if (width_out == NULL || height_out == NULL || den == 0) return;
+ w = width_org * num / den;
+ h = height_org * num / den;
+ // Make height and width even.
+ w += w % 2;
+ h += h % 2;
+ *width_out = w;
+ *height_out = h;
+}
+
+void av1_one_pass_cbr_svc_start_layer(AV1_COMP *const cpi) {
+ SVC *const svc = &cpi->svc;
+ LAYER_CONTEXT *lc = NULL;
+ int width = 0, height = 0;
+ lc = &svc->layer_context[svc->spatial_layer_id * svc->number_temporal_layers +
+ svc->temporal_layer_id];
+ get_layer_resolution(cpi->oxcf.width, cpi->oxcf.height,
+ lc->scaling_factor_num, lc->scaling_factor_den, &width,
+ &height);
+ av1_set_size_literal(cpi, width, height);
+}
diff --git a/av1/encoder/svc_layercontext.h b/av1/encoder/svc_layercontext.h
index d52677f..b018f48 100644
--- a/av1/encoder/svc_layercontext.h
+++ b/av1/encoder/svc_layercontext.h
@@ -52,6 +52,7 @@
int non_reference_frame;
int ref_idx[INTER_REFS_PER_FRAME];
int refresh[REF_FRAMES];
+ double base_framerate;
// Layer context used for rate control in one pass temporal CBR mode or
// two pass spatial mode.
LAYER_CONTEXT layer_context[AOM_MAX_LAYERS];
@@ -81,6 +82,8 @@
void av1_svc_reset_temporal_layers(struct AV1_COMP *const cpi, int is_key);
+void av1_one_pass_cbr_svc_start_layer(struct AV1_COMP *const cpi);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/examples/svc_encoder_rtc.c b/examples/svc_encoder_rtc.c
index 2e9d5fc..a5ab076 100644
--- a/examples/svc_encoder_rtc.c
+++ b/examples/svc_encoder_rtc.c
@@ -30,26 +30,26 @@
void usage_exit(void) { exit(EXIT_FAILURE); }
-static int mode_to_num_layers[5] = { 1, 2, 3, 3, 2 };
+static int mode_to_num_temporal_layers[6] = { 1, 2, 3, 3, 2, 1 };
+static int mode_to_num_spatial_layers[6] = { 1, 1, 1, 1, 1, 2 };
+static int mode_to_num_layers[6] = { 1, 2, 3, 3, 2, 2 };
// For rate control encoding stats.
struct RateControlMetrics {
// Number of input frames per layer.
int layer_input_frames[AOM_MAX_TS_LAYERS];
- // Total (cumulative) number of encoded frames per layer.
- int layer_tot_enc_frames[AOM_MAX_TS_LAYERS];
// Number of encoded non-key frames per layer.
int layer_enc_frames[AOM_MAX_TS_LAYERS];
// Framerate per layer layer (cumulative).
double layer_framerate[AOM_MAX_TS_LAYERS];
// Target average frame size per layer (per-frame-bandwidth per layer).
- double layer_pfb[AOM_MAX_TS_LAYERS];
+ double layer_pfb[AOM_MAX_LAYERS];
// Actual average frame size per layer.
- double layer_avg_frame_size[AOM_MAX_TS_LAYERS];
+ double layer_avg_frame_size[AOM_MAX_LAYERS];
// Average rate mismatch per layer (|target - actual| / target).
- double layer_avg_rate_mismatch[AOM_MAX_TS_LAYERS];
- // Actual encoding bitrate per layer (cumulative).
- double layer_encoding_bitrate[AOM_MAX_TS_LAYERS];
+ double layer_avg_rate_mismatch[AOM_MAX_LAYERS];
+ // Actual encoding bitrate per layer (cumulative across temporal layers).
+ double layer_encoding_bitrate[AOM_MAX_LAYERS];
// Average of the short-time encoder actual bitrate.
// TODO(marpan): Should we add these short-time stats for each layer?
double avg_st_encoding_bitrate;
@@ -59,7 +59,7 @@
int window_size;
// Number of window measurements.
int window_count;
- int layer_target_bitrate[AOM_MAX_TS_LAYERS];
+ int layer_target_bitrate[AOM_MAX_LAYERS];
};
static int read_frame(struct AvxInputContext *input_ctx, aom_image_t *img) {
@@ -151,6 +151,7 @@
// in the stream.
static void set_rate_control_metrics(struct RateControlMetrics *rc,
double framerate,
+ unsigned int ss_number_layers,
unsigned int ts_number_layers) {
int ts_rate_decimator[AOM_MAX_TS_LAYERS] = { 1 };
ts_rate_decimator[0] = 1;
@@ -165,23 +166,26 @@
}
// Set the layer (cumulative) framerate and the target layer (non-cumulative)
// per-frame-bandwidth, for the rate control encoding stats below.
- rc->layer_framerate[0] = framerate / ts_rate_decimator[0];
- rc->layer_pfb[0] =
- 1000.0 * rc->layer_target_bitrate[0] / rc->layer_framerate[0];
- for (unsigned int i = 0; i < ts_number_layers; ++i) {
- if (i > 0) {
- rc->layer_framerate[i] = framerate / ts_rate_decimator[i];
- rc->layer_pfb[i] =
- 1000.0 *
- (rc->layer_target_bitrate[i] - rc->layer_target_bitrate[i - 1]) /
- (rc->layer_framerate[i] - rc->layer_framerate[i - 1]);
+ for (unsigned int sl = 0; sl < ss_number_layers; ++sl) {
+ unsigned int i = sl * ts_number_layers;
+ rc->layer_framerate[0] = framerate / ts_rate_decimator[0];
+ rc->layer_pfb[i] =
+ 1000.0 * rc->layer_target_bitrate[i] / rc->layer_framerate[0];
+ for (unsigned int tl = 0; tl < ts_number_layers; ++tl) {
+ i = sl * ts_number_layers + tl;
+ if (tl > 0) {
+ rc->layer_framerate[tl] = framerate / ts_rate_decimator[tl];
+ rc->layer_pfb[i] =
+ 1000.0 *
+ (rc->layer_target_bitrate[i] - rc->layer_target_bitrate[i - 1]) /
+ (rc->layer_framerate[tl] - rc->layer_framerate[tl - 1]);
+ }
+ rc->layer_input_frames[tl] = 0;
+ rc->layer_enc_frames[tl] = 0;
+ rc->layer_encoding_bitrate[i] = 0.0;
+ rc->layer_avg_frame_size[i] = 0.0;
+ rc->layer_avg_rate_mismatch[i] = 0.0;
}
- rc->layer_input_frames[i] = 0;
- rc->layer_enc_frames[i] = 0;
- rc->layer_tot_enc_frames[i] = 0;
- rc->layer_encoding_bitrate[i] = 0.0;
- rc->layer_avg_frame_size[i] = 0.0;
- rc->layer_avg_rate_mismatch[i] = 0.0;
}
rc->window_count = 0;
rc->window_size = 15;
@@ -191,35 +195,40 @@
static void printout_rate_control_summary(struct RateControlMetrics *rc,
int frame_cnt,
+ unsigned int ss_number_layers,
unsigned int ts_number_layers) {
int tot_num_frames = 0;
double perc_fluctuation = 0.0;
printf("Total number of processed frames: %d\n\n", frame_cnt - 1);
printf("Rate control layer stats for %d layer(s):\n\n", ts_number_layers);
- for (unsigned int i = 0; i < ts_number_layers; ++i) {
- const int num_dropped =
- i > 0 ? rc->layer_input_frames[i] - rc->layer_enc_frames[i]
- : rc->layer_input_frames[i] - rc->layer_enc_frames[i] - 1;
- tot_num_frames += rc->layer_input_frames[i];
- rc->layer_encoding_bitrate[i] = 0.001 * rc->layer_framerate[i] *
- rc->layer_encoding_bitrate[i] /
- tot_num_frames;
- rc->layer_avg_frame_size[i] =
- rc->layer_avg_frame_size[i] / rc->layer_enc_frames[i];
- rc->layer_avg_rate_mismatch[i] =
- 100.0 * rc->layer_avg_rate_mismatch[i] / rc->layer_enc_frames[i];
- printf("For layer#: %d\n", i);
- printf("Bitrate (target vs actual): %d %f\n", rc->layer_target_bitrate[i],
- rc->layer_encoding_bitrate[i]);
- printf("Average frame size (target vs actual): %f %f\n", rc->layer_pfb[i],
- rc->layer_avg_frame_size[i]);
- printf("Average rate_mismatch: %f\n", rc->layer_avg_rate_mismatch[i]);
- printf(
- "Number of input frames, encoded (non-key) frames, "
- "and perc dropped frames: %d %d %f\n",
- rc->layer_input_frames[i], rc->layer_enc_frames[i],
- 100.0 * num_dropped / rc->layer_input_frames[i]);
- printf("\n");
+ for (unsigned int sl = 0; sl < ss_number_layers; ++sl) {
+ tot_num_frames = 0;
+ for (unsigned int tl = 0; tl < ts_number_layers; ++tl) {
+ unsigned int i = sl * ts_number_layers + tl;
+ const int num_dropped =
+ tl > 0 ? rc->layer_input_frames[tl] - rc->layer_enc_frames[tl]
+ : rc->layer_input_frames[tl] - rc->layer_enc_frames[tl] - 1;
+ tot_num_frames += rc->layer_input_frames[tl];
+ rc->layer_encoding_bitrate[i] = 0.001 * rc->layer_framerate[tl] *
+ rc->layer_encoding_bitrate[i] /
+ tot_num_frames;
+ rc->layer_avg_frame_size[i] =
+ rc->layer_avg_frame_size[i] / rc->layer_enc_frames[tl];
+ rc->layer_avg_rate_mismatch[i] =
+ 100.0 * rc->layer_avg_rate_mismatch[i] / rc->layer_enc_frames[tl];
+ printf("For layer#: %d %d \n", sl, tl);
+ printf("Bitrate (target vs actual): %d %f\n", rc->layer_target_bitrate[i],
+ rc->layer_encoding_bitrate[i]);
+ printf("Average frame size (target vs actual): %f %f\n", rc->layer_pfb[i],
+ rc->layer_avg_frame_size[i]);
+ printf("Average rate_mismatch: %f\n", rc->layer_avg_rate_mismatch[i]);
+ printf(
+ "Number of input frames, encoded (non-key) frames, "
+ "and perc dropped frames: %d %d %f\n",
+ rc->layer_input_frames[tl], rc->layer_enc_frames[tl],
+ 100.0 * num_dropped / rc->layer_input_frames[tl]);
+ printf("\n");
+ }
}
rc->avg_st_encoding_bitrate = rc->avg_st_encoding_bitrate / rc->window_count;
rc->variance_st_encoding_bitrate =
@@ -239,11 +248,10 @@
static int set_layer_pattern(int layering_mode, int frame_cnt,
aom_svc_layer_id_t *layer_id,
aom_svc_ref_frame_config_t *ref_frame_config,
- int *use_svc_control) {
+ int *use_svc_control, int spatial_layer_id) {
int i;
*use_svc_control = 1;
- // No spatial layers in this test.
- layer_id->spatial_layer_id = 0;
+ layer_id->spatial_layer_id = spatial_layer_id;
// Set the referende map buffer idx for the 7 references:
// LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2), GOLDEN_FRAME(3),
// BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6).
@@ -345,13 +353,29 @@
AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_REF_GF;
}
break;
+ case 5:
+ layer_id->temporal_layer_id = 0;
+ if (layer_id->spatial_layer_id == 0) {
+ // Reference LAST, update LAST. Keep LAST and GOLDEN in slots 0 and 3.
+ ref_frame_config->ref_idx[0] = 0;
+ ref_frame_config->ref_idx[3] = 3;
+ ref_frame_config->refresh[0] = 1;
+ layer_flags |= AOM_EFLAG_NO_REF_GF;
+ } else if (layer_id->spatial_layer_id == 1) {
+ // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 3
+ // and GOLDEN to slot 0. Update slot 3 (LAST).
+ ref_frame_config->ref_idx[0] = 3;
+ ref_frame_config->ref_idx[3] = 0;
+ ref_frame_config->refresh[3] = 1;
+ }
+ break;
default: assert(0); die("Error: Unsupported temporal layering mode!\n");
}
return layer_flags;
}
int main(int argc, char **argv) {
- AvxVideoWriter *outfile[AOM_MAX_TS_LAYERS] = { NULL };
+ AvxVideoWriter *outfile[AOM_MAX_LAYERS] = { NULL };
aom_codec_ctx_t codec;
aom_codec_enc_cfg_t cfg;
int frame_cnt = 0;
@@ -362,9 +386,9 @@
uint32_t error_resilient = 0;
int speed;
int frame_avail;
- int got_data;
+ int got_data = 0;
int flags = 0;
- unsigned int i;
+ unsigned i;
int pts = 0; // PTS starts at 0.
int frame_duration = 1; // 1 timebase tick per frame.
int layering_mode = 0;
@@ -420,7 +444,8 @@
die("Invalid number of arguments");
}
- ts_number_layers = mode_to_num_layers[layering_mode];
+ ts_number_layers = mode_to_num_temporal_layers[layering_mode];
+ ss_number_layers = mode_to_num_spatial_layers[layering_mode];
input_ctx.filename = argv[1];
open_input_file(&input_ctx, 0);
@@ -458,7 +483,8 @@
svc_params.layer_target_bitrate[i - 13] = rc.layer_target_bitrate[i - 13];
}
- cfg.rc_target_bitrate = svc_params.layer_target_bitrate[ts_number_layers - 1];
+ cfg.rc_target_bitrate =
+ svc_params.layer_target_bitrate[ss_number_layers * ts_number_layers - 1];
svc_params.framerate_factor[0] = 1;
if (ts_number_layers == 2) {
@@ -499,7 +525,7 @@
cfg.kf_min_dist = cfg.kf_max_dist = 3000;
framerate = cfg.g_timebase.den / cfg.g_timebase.num;
- set_rate_control_metrics(&rc, framerate, ts_number_layers);
+ set_rate_control_metrics(&rc, framerate, ss_number_layers, ts_number_layers);
if (input_ctx.file_type == FILE_TYPE_Y4M) {
if (input_ctx.width != cfg.g_w || input_ctx.height != cfg.g_h) {
@@ -513,20 +539,22 @@
}
// Open an output file for each stream.
- for (i = 0; i < ts_number_layers; ++i) {
- char file_name[PATH_MAX];
- AvxVideoInfo info;
- info.codec_fourcc = encoder->fourcc;
- info.frame_width = cfg.g_w;
- info.frame_height = cfg.g_h;
- info.time_base.numerator = cfg.g_timebase.num;
- info.time_base.denominator = cfg.g_timebase.den;
+ for (unsigned int sl = 0; sl < ss_number_layers; ++sl) {
+ for (unsigned tl = 0; tl < ts_number_layers; ++tl) {
+ i = sl * ts_number_layers + tl;
+ char file_name[PATH_MAX];
+ AvxVideoInfo info;
+ info.codec_fourcc = encoder->fourcc;
+ info.frame_width = cfg.g_w;
+ info.frame_height = cfg.g_h;
+ info.time_base.numerator = cfg.g_timebase.num;
+ info.time_base.denominator = cfg.g_timebase.den;
- snprintf(file_name, sizeof(file_name), "%s_%d.av1", argv[2], i);
- outfile[i] = aom_video_writer_open(file_name, kContainerIVF, &info);
- if (!outfile[i]) die("Failed to open %s for writing", file_name);
-
- assert(outfile[i] != NULL);
+ snprintf(file_name, sizeof(file_name), "%s_%d.av1", argv[2], i);
+ outfile[i] = aom_video_writer_open(file_name, kContainerIVF, &info);
+ if (!outfile[i]) die("Failed to open %s for writing", file_name);
+ assert(outfile[i] != NULL);
+ }
}
// Initialize codec.
@@ -540,7 +568,7 @@
svc_params.number_spatial_layers = ss_number_layers;
svc_params.number_temporal_layers = ts_number_layers;
- for (i = 0; i < ts_number_layers; ++i) {
+ for (i = 0; i < ss_number_layers * ts_number_layers; ++i) {
svc_params.max_quantizers[i] = cfg.rc_max_quantizer;
svc_params.min_quantizers[i] = cfg.rc_min_quantizer;
}
@@ -548,6 +576,16 @@
svc_params.scaling_factor_num[i] = 1;
svc_params.scaling_factor_den[i] = 1;
}
+ if (ss_number_layers == 2) {
+ svc_params.scaling_factor_num[0] = 1;
+ svc_params.scaling_factor_den[0] = 2;
+ } else if (ss_number_layers == 3) {
+ svc_params.scaling_factor_num[0] = 1;
+ svc_params.scaling_factor_den[0] = 4;
+ svc_params.scaling_factor_num[1] = 1;
+ svc_params.scaling_factor_den[1] = 2;
+ }
+
aom_codec_control(&codec, AV1E_SET_SVC_PARAMS, &svc_params);
// This controls the maximum target size of the key frame.
@@ -562,83 +600,101 @@
frame_avail = 1;
while (frame_avail || got_data) {
struct aom_usec_timer timer;
- aom_codec_iter_t iter = NULL;
- const aom_codec_cx_pkt_t *pkt;
-
- // Set the reference/update flags, layer_id, and reference_map
- // buffer index.
- flags = set_layer_pattern(layering_mode, frame_cnt, &layer_id,
- &ref_frame_config, &use_svc_control);
- aom_codec_control(&codec, AV1E_SET_SVC_LAYER_ID, &layer_id);
- if (use_svc_control)
- aom_codec_control(&codec, AV1E_SET_SVC_REF_FRAME_CONFIG,
- &ref_frame_config);
-
frame_avail = read_frame(&input_ctx, &raw);
- if (frame_avail) ++rc.layer_input_frames[layer_id.temporal_layer_id];
- aom_usec_timer_start(&timer);
- if (aom_codec_encode(&codec, frame_avail ? &raw : NULL, pts, 1, flags)) {
- die_codec(&codec, "Failed to encode frame");
- }
- aom_usec_timer_mark(&timer);
- cx_time += aom_usec_timer_elapsed(&timer);
- got_data = 0;
- while ((pkt = aom_codec_get_cx_data(&codec, &iter))) {
- got_data = 1;
- switch (pkt->kind) {
- case AOM_CODEC_CX_FRAME_PKT:
- for (i = layer_id.temporal_layer_id; i < ts_number_layers; ++i) {
- aom_video_writer_write_frame(outfile[i], pkt->data.frame.buf,
- pkt->data.frame.sz, pts);
- ++rc.layer_tot_enc_frames[i];
- rc.layer_encoding_bitrate[i] += 8.0 * pkt->data.frame.sz;
- // Keep count of rate control stats per layer (for non-key frames).
- if (i == (unsigned int)layer_id.temporal_layer_id &&
- !(pkt->data.frame.flags & AOM_FRAME_IS_KEY)) {
- rc.layer_avg_frame_size[i] += 8.0 * pkt->data.frame.sz;
- rc.layer_avg_rate_mismatch[i] +=
- fabs(8.0 * pkt->data.frame.sz - rc.layer_pfb[i]) /
- rc.layer_pfb[i];
- ++rc.layer_enc_frames[i];
+ // Loop over spatial layers.
+ for (unsigned int slx = 0; slx < ss_number_layers; slx++) {
+ aom_codec_iter_t iter = NULL;
+ const aom_codec_cx_pkt_t *pkt;
+ int layer = 0;
+
+ // Set the reference/update flags, layer_id, and reference_map
+ // buffer index.
+ flags = set_layer_pattern(layering_mode, frame_cnt, &layer_id,
+ &ref_frame_config, &use_svc_control, slx);
+ aom_codec_control(&codec, AV1E_SET_SVC_LAYER_ID, &layer_id);
+ if (use_svc_control)
+ aom_codec_control(&codec, AV1E_SET_SVC_REF_FRAME_CONFIG,
+ &ref_frame_config);
+
+ layer = slx * ts_number_layers + layer_id.temporal_layer_id;
+ if (frame_avail && slx == 0) ++rc.layer_input_frames[layer];
+
+ // Do the layer encode.
+ aom_usec_timer_start(&timer);
+ if (aom_codec_encode(&codec, frame_avail ? &raw : NULL, pts, 1, flags))
+ die_codec(&codec, "Failed to encode frame");
+ aom_usec_timer_mark(&timer);
+ cx_time += aom_usec_timer_elapsed(&timer);
+
+ got_data = 0;
+ while ((pkt = aom_codec_get_cx_data(&codec, &iter))) {
+ got_data = 1;
+ switch (pkt->kind) {
+ case AOM_CODEC_CX_FRAME_PKT:
+ for (unsigned int sl = layer_id.spatial_layer_id;
+ sl < ss_number_layers; ++sl) {
+ for (unsigned tl = layer_id.temporal_layer_id;
+ tl < ts_number_layers; ++tl) {
+ unsigned int j = sl * ts_number_layers + tl;
+ aom_video_writer_write_frame(outfile[j], pkt->data.frame.buf,
+ pkt->data.frame.sz, pts);
+
+ if (sl == (unsigned int)layer_id.spatial_layer_id)
+ rc.layer_encoding_bitrate[j] += 8.0 * pkt->data.frame.sz;
+ // Keep count of rate control stats per layer (for non-key).
+ if (tl == (unsigned int)layer_id.temporal_layer_id &&
+ sl == (unsigned int)layer_id.spatial_layer_id &&
+ !(pkt->data.frame.flags & AOM_FRAME_IS_KEY)) {
+ rc.layer_avg_frame_size[j] += 8.0 * pkt->data.frame.sz;
+ rc.layer_avg_rate_mismatch[j] +=
+ fabs(8.0 * pkt->data.frame.sz - rc.layer_pfb[j]) /
+ rc.layer_pfb[j];
+ if (slx == 0) ++rc.layer_enc_frames[tl];
+ }
+ }
}
- }
- // Update for short-time encoding bitrate states, for moving window
- // of size rc->window, shifted by rc->window / 2.
- // Ignore first window segment, due to key frame.
- if (frame_cnt > rc.window_size) {
- sum_bitrate += 0.001 * 8.0 * pkt->data.frame.sz * framerate;
- rc.window_size = (rc.window_size <= 0) ? 1 : rc.window_size;
- if (frame_cnt % rc.window_size == 0) {
- rc.window_count += 1;
- rc.avg_st_encoding_bitrate += sum_bitrate / rc.window_size;
- rc.variance_st_encoding_bitrate +=
- (sum_bitrate / rc.window_size) *
- (sum_bitrate / rc.window_size);
- sum_bitrate = 0.0;
+
+ // Update for short-time encoding bitrate states, for moving window
+ // of size rc->window, shifted by rc->window / 2.
+ // Ignore first window segment, due to key frame.
+ // For spatial layers: only do this for top/highest SL.
+ if (frame_cnt > rc.window_size && slx == ss_number_layers - 1) {
+ sum_bitrate += 0.001 * 8.0 * pkt->data.frame.sz * framerate;
+ rc.window_size = (rc.window_size <= 0) ? 1 : rc.window_size;
+ if (frame_cnt % rc.window_size == 0) {
+ rc.window_count += 1;
+ rc.avg_st_encoding_bitrate += sum_bitrate / rc.window_size;
+ rc.variance_st_encoding_bitrate +=
+ (sum_bitrate / rc.window_size) *
+ (sum_bitrate / rc.window_size);
+ sum_bitrate = 0.0;
+ }
}
- }
- // Second shifted window.
- if (frame_cnt > rc.window_size + rc.window_size / 2) {
- sum_bitrate2 += 0.001 * 8.0 * pkt->data.frame.sz * framerate;
- if (frame_cnt > 2 * rc.window_size &&
- frame_cnt % rc.window_size == 0) {
- rc.window_count += 1;
- rc.avg_st_encoding_bitrate += sum_bitrate2 / rc.window_size;
- rc.variance_st_encoding_bitrate +=
- (sum_bitrate2 / rc.window_size) *
- (sum_bitrate2 / rc.window_size);
- sum_bitrate2 = 0.0;
+ // Second shifted window.
+ if (frame_cnt > rc.window_size + rc.window_size / 2 &&
+ slx == ss_number_layers - 1) {
+ sum_bitrate2 += 0.001 * 8.0 * pkt->data.frame.sz * framerate;
+ if (frame_cnt > 2 * rc.window_size &&
+ frame_cnt % rc.window_size == 0) {
+ rc.window_count += 1;
+ rc.avg_st_encoding_bitrate += sum_bitrate2 / rc.window_size;
+ rc.variance_st_encoding_bitrate +=
+ (sum_bitrate2 / rc.window_size) *
+ (sum_bitrate2 / rc.window_size);
+ sum_bitrate2 = 0.0;
+ }
}
- }
- break;
- default: break;
+ break;
+ default: break;
+ }
}
- }
+ } // loop over spatial layers
++frame_cnt;
pts += frame_duration;
}
close_input_file(&input_ctx);
- printout_rate_control_summary(&rc, frame_cnt, ts_number_layers);
+ printout_rate_control_summary(&rc, frame_cnt, ss_number_layers,
+ ts_number_layers);
printf("\n");
printf("Frame cnt and encoding time/FPS stats for encoding: %d %f %f\n",
frame_cnt, 1000 * (float)cx_time / (double)(frame_cnt * 1000000),
@@ -647,7 +703,8 @@
if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
// Try to rewrite the output file headers with the actual frame count.
- for (i = 0; i < ts_number_layers; ++i) aom_video_writer_close(outfile[i]);
+ for (i = 0; i < ss_number_layers * ts_number_layers; ++i)
+ aom_video_writer_close(outfile[i]);
if (input_ctx.file_type != FILE_TYPE_Y4M) {
aom_img_free(&raw);
diff --git a/test/encode_test_driver.cc b/test/encode_test_driver.cc
index d06168f..226248b 100644
--- a/test/encode_test_driver.cc
+++ b/test/encode_test_driver.cc
@@ -219,65 +219,69 @@
}
#endif
+ number_spatial_layers_ = GetNumSpatialLayers();
+
bool again;
for (again = true; again; video->Next()) {
again = (video->img() != NULL);
- PreEncodeFrameHook(video);
- PreEncodeFrameHook(video, encoder.get());
- encoder->EncodeFrame(video, frame_flags_);
+ for (int sl = 0; sl < number_spatial_layers_; sl++) {
+ PreEncodeFrameHook(video);
+ PreEncodeFrameHook(video, encoder.get());
+ encoder->EncodeFrame(video, frame_flags_);
- CxDataIterator iter = encoder->GetCxData();
+ CxDataIterator iter = encoder->GetCxData();
- bool has_cxdata = false;
- bool has_dxdata = false;
- while (const aom_codec_cx_pkt_t *pkt = iter.Next()) {
- pkt = MutateEncoderOutputHook(pkt);
- again = true;
- switch (pkt->kind) {
- case AOM_CODEC_CX_FRAME_PKT:
- has_cxdata = true;
- if (decoder.get() != NULL && DoDecode()) {
- aom_codec_err_t res_dec;
- if (DoDecodeInvisible()) {
- res_dec = decoder->DecodeFrame(
- (const uint8_t *)pkt->data.frame.buf, pkt->data.frame.sz);
- } else {
- res_dec = decoder->DecodeFrame(
- (const uint8_t *)pkt->data.frame.buf +
- (pkt->data.frame.sz - pkt->data.frame.vis_frame_size),
- pkt->data.frame.vis_frame_size);
+ bool has_cxdata = false;
+ bool has_dxdata = false;
+ while (const aom_codec_cx_pkt_t *pkt = iter.Next()) {
+ pkt = MutateEncoderOutputHook(pkt);
+ again = true;
+ switch (pkt->kind) {
+ case AOM_CODEC_CX_FRAME_PKT:
+ has_cxdata = true;
+ if (decoder.get() != NULL && DoDecode()) {
+ aom_codec_err_t res_dec;
+ if (DoDecodeInvisible()) {
+ res_dec = decoder->DecodeFrame(
+ (const uint8_t *)pkt->data.frame.buf, pkt->data.frame.sz);
+ } else {
+ res_dec = decoder->DecodeFrame(
+ (const uint8_t *)pkt->data.frame.buf +
+ (pkt->data.frame.sz - pkt->data.frame.vis_frame_size),
+ pkt->data.frame.vis_frame_size);
+ }
+
+ if (!HandleDecodeResult(res_dec, decoder.get())) break;
+
+ has_dxdata = true;
}
+ ASSERT_GE(pkt->data.frame.pts, last_pts_);
+ if (sl == number_spatial_layers_) last_pts_ = pkt->data.frame.pts;
+ FramePktHook(pkt);
+ break;
- if (!HandleDecodeResult(res_dec, decoder.get())) break;
+ case AOM_CODEC_PSNR_PKT: PSNRPktHook(pkt); break;
- has_dxdata = true;
- }
- ASSERT_GE(pkt->data.frame.pts, last_pts_);
- last_pts_ = pkt->data.frame.pts;
- FramePktHook(pkt);
- break;
-
- case AOM_CODEC_PSNR_PKT: PSNRPktHook(pkt); break;
-
- default: break;
- }
- }
-
- if (has_dxdata && has_cxdata) {
- const aom_image_t *img_enc = encoder->GetPreviewFrame();
- DxDataIterator dec_iter = decoder->GetDxData();
- const aom_image_t *img_dec = dec_iter.Next();
- if (img_enc && img_dec) {
- const bool res =
- compare_img(img_enc, img_dec, NULL, NULL, NULL, NULL, NULL);
- if (!res) { // Mismatch
- MismatchHook(img_enc, img_dec);
+ default: break;
}
}
- if (img_dec) DecompressedFrameHook(*img_dec, video->pts());
- }
- if (!Continue()) break;
+
+ if (has_dxdata && has_cxdata) {
+ const aom_image_t *img_enc = encoder->GetPreviewFrame();
+ DxDataIterator dec_iter = decoder->GetDxData();
+ const aom_image_t *img_dec = dec_iter.Next();
+ if (img_enc && img_dec) {
+ const bool res =
+ compare_img(img_enc, img_dec, NULL, NULL, NULL, NULL, NULL);
+ if (!res) { // Mismatch
+ MismatchHook(img_enc, img_dec);
+ }
+ }
+ if (img_dec) DecompressedFrameHook(*img_dec, video->pts());
+ }
+ if (!Continue()) break;
+ } // Loop over spatial layers
}
EndPassHook();
diff --git a/test/encode_test_driver.h b/test/encode_test_driver.h
index 65f8944..19448c8 100644
--- a/test/encode_test_driver.h
+++ b/test/encode_test_driver.h
@@ -179,7 +179,7 @@
protected:
explicit EncoderTest(const CodecFactory *codec)
: codec_(codec), abort_(false), init_flags_(0), frame_flags_(0),
- last_pts_(0), mode_(kRealTime) {
+ last_pts_(0), mode_(kRealTime), number_spatial_layers_(1) {
// Default to 1 thread.
cfg_.g_threads = 1;
}
@@ -242,6 +242,8 @@
return AOM_CODEC_OK == res_dec;
}
+ virtual int GetNumSpatialLayers() { return 1; }
+
// Hook that can modify the encoder's output data
virtual const aom_codec_cx_pkt_t *MutateEncoderOutputHook(
const aom_codec_cx_pkt_t *pkt) {
@@ -257,6 +259,7 @@
unsigned long frame_flags_;
aom_codec_pts_t last_pts_;
TestMode mode_;
+ int number_spatial_layers_;
};
} // namespace libaom_test
diff --git a/test/svc_datarate_test.cc b/test/svc_datarate_test.cc
index 3d2c206..1a50f16 100644
--- a/test/svc_datarate_test.cc
+++ b/test/svc_datarate_test.cc
@@ -40,10 +40,14 @@
ResetModel();
}
+ virtual int GetNumSpatialLayers() { return number_spatial_layers_; }
+
virtual void ResetModel() {
DatarateTest::ResetModel();
+ layer_frame_cnt_ = 0;
number_temporal_layers_ = 1;
- for (int i = 0; i < 3; i++) {
+ number_spatial_layers_ = 1;
+ for (int i = 0; i < AOM_MAX_LAYERS; i++) {
target_layer_bitrate_[i] = 0;
effective_datarate_tl[i] = 0.0;
}
@@ -54,48 +58,48 @@
virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
::libaom_test::Encoder *encoder) {
+ int spatial_layer_id = 0;
if (video->frame() == 0) {
- if (number_temporal_layers_ > 1) {
- initialize_svc(number_temporal_layers_, &svc_params_);
- encoder->Control(AV1E_SET_SVC_PARAMS, &svc_params_);
- }
+ initialize_svc(number_temporal_layers_, number_spatial_layers_,
+ &svc_params_);
+ encoder->Control(AV1E_SET_SVC_PARAMS, &svc_params_);
}
- if (number_temporal_layers_ > 1) {
- // Set the reference/update flags, layer_id, and reference_map
- // buffer index.
- frame_flags_ =
- set_layer_pattern(video->frame(), &layer_id_, &ref_frame_config_);
- encoder->Control(AV1E_SET_SVC_LAYER_ID, &layer_id_);
- encoder->Control(AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_frame_config_);
- }
+ if (number_spatial_layers_ == 2)
+ spatial_layer_id = (layer_frame_cnt_ % 2 == 0) ? 0 : 1;
+ // Set the reference/update flags, layer_id, and reference_map
+ // buffer index.
+ frame_flags_ = set_layer_pattern(video->frame(), &layer_id_,
+ &ref_frame_config_, spatial_layer_id);
+ encoder->Control(AV1E_SET_SVC_LAYER_ID, &layer_id_);
+ encoder->Control(AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_frame_config_);
+ layer_frame_cnt_++;
DatarateTest::PreEncodeFrameHook(video, encoder);
}
virtual void FramePktHook(const aom_codec_cx_pkt_t *pkt) {
- DatarateTest::FramePktHook(pkt);
const size_t frame_size_in_bits = pkt->data.frame.sz * 8;
- if (number_temporal_layers_ > 1) {
- // Update the layer cumulative bitrate.
- for (int i = layer_id_.temporal_layer_id; i < number_temporal_layers_;
- i++)
- effective_datarate_tl[i] += 1.0 * frame_size_in_bits;
+ // Update the layer cumulative bitrate.
+ for (int i = layer_id_.temporal_layer_id; i < number_temporal_layers_;
+ i++) {
+ int layer = layer_id_.spatial_layer_id * number_temporal_layers_ + i;
+ effective_datarate_tl[layer] += 1.0 * frame_size_in_bits;
}
+ if (layer_id_.spatial_layer_id == number_spatial_layers_ - 1)
+ last_pts_ = pkt->data.frame.pts;
}
virtual void EndPassHook(void) {
- DatarateTest::EndPassHook();
- if (number_temporal_layers_ > 1) {
- for (int i = 0; i < number_temporal_layers_; i++)
- effective_datarate_tl[i] =
- (effective_datarate_tl[i] / 1000) / duration_;
+ duration_ = ((last_pts_ + 1) * timebase_);
+ for (int i = 0; i < number_temporal_layers_ * number_spatial_layers_; i++) {
+ effective_datarate_tl[i] = (effective_datarate_tl[i] / 1000) / duration_;
}
}
// Layer pattern configuration.
virtual int set_layer_pattern(int frame_cnt, aom_svc_layer_id_t *layer_id,
- aom_svc_ref_frame_config_t *ref_frame_config) {
- // No spatial layers in this test.
- layer_id->spatial_layer_id = 0;
+ aom_svc_ref_frame_config_t *ref_frame_config,
+ int spatial_layer) {
+ layer_id->spatial_layer_id = spatial_layer;
// Set the referende map buffer idx for the 7 references:
// LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2), GOLDEN_FRAME(3),
// BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6).
@@ -105,47 +109,64 @@
int layer_flags = AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 |
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_REF_BWD |
AOM_EFLAG_NO_REF_ARF2;
- // 3-layer:
- // 1 3 5 7
- // 2 6
- // 0 4 8
- if (frame_cnt % 4 == 0) {
- // Base layer.
+ if (number_temporal_layers_ == 3 && number_spatial_layers_ == 1) {
+ // 3-layer:
+ // 1 3 5 7
+ // 2 6
+ // 0 4 8
+ if (frame_cnt % 4 == 0) {
+ // Base layer.
+ layer_id->temporal_layer_id = 0;
+ // Update LAST on layer 0, reference LAST and GF.
+ ref_frame_config->refresh[0] = 1;
+ } else if ((frame_cnt - 1) % 4 == 0) {
+ layer_id->temporal_layer_id = 2;
+ // First top layer: no updates, only reference LAST (TL0).
+ layer_flags |= AOM_EFLAG_NO_REF_GF;
+ } else if ((frame_cnt - 2) % 4 == 0) {
+ layer_id->temporal_layer_id = 1;
+ // Middle layer (TL1): update LAST2, only reference LAST (TL0).
+ ref_frame_config->refresh[1] = 1;
+ layer_flags |= AOM_EFLAG_NO_REF_GF;
+ } else if ((frame_cnt - 3) % 4 == 0) {
+ layer_id->temporal_layer_id = 2;
+ // Second top layer: no updates, only reference LAST.
+ // Set buffer idx for LAST to slot 1, since that was the slot
+ // updated in previous frame. So LAST is TL1 frame.
+ ref_frame_config->ref_idx[0] = 1;
+ ref_frame_config->ref_idx[1] = 0;
+ layer_flags |= AOM_EFLAG_NO_REF_GF;
+ }
+ } else if (number_temporal_layers_ == 1 && number_spatial_layers_ == 2) {
layer_id->temporal_layer_id = 0;
- // Update LAST on layer 0, reference LAST and GF.
- ref_frame_config->refresh[0] = 1;
- } else if ((frame_cnt - 1) % 4 == 0) {
- layer_id->temporal_layer_id = 2;
- // First top layer: no updates, only reference LAST (TL0).
- layer_flags |= AOM_EFLAG_NO_REF_GF;
- } else if ((frame_cnt - 2) % 4 == 0) {
- layer_id->temporal_layer_id = 1;
- // Middle layer (TL1): update LAST2, only reference LAST (TL0).
- ref_frame_config->refresh[1] = 1;
- layer_flags |= AOM_EFLAG_NO_REF_GF;
- } else if ((frame_cnt - 3) % 4 == 0) {
- layer_id->temporal_layer_id = 2;
- // Second top layer: no updates, only reference LAST.
- // Set buffer idx for LAST to slot 1, since that was the slot
- // updated in previous frame. So LAST is TL1 frame.
- ref_frame_config->ref_idx[0] = 1;
- ref_frame_config->ref_idx[1] = 0;
- layer_flags |= AOM_EFLAG_NO_REF_GF;
+ if (layer_id->spatial_layer_id == 0) {
+ // Reference LAST, update LAST. Keep LAST and GOLDEN in slots 0 and 3.
+ ref_frame_config->ref_idx[0] = 0;
+ ref_frame_config->ref_idx[3] = 3;
+ ref_frame_config->refresh[0] = 1;
+ layer_flags |= AOM_EFLAG_NO_REF_GF;
+ } else if (layer_id->spatial_layer_id == 1) {
+ // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 3
+ // and GOLDEN to slot 0. Update slot 3 (LAST).
+ ref_frame_config->ref_idx[0] = 3;
+ ref_frame_config->ref_idx[3] = 0;
+ ref_frame_config->refresh[3] = 1;
+ }
}
return layer_flags;
}
virtual void initialize_svc(int number_temporal_layers,
+ int number_spatial_layers,
aom_svc_params *svc_params) {
- svc_params->number_spatial_layers = 1;
- svc_params->scaling_factor_num[0] = 1;
- svc_params->scaling_factor_den[0] = 1;
+ svc_params->number_spatial_layers = number_spatial_layers;
svc_params->number_temporal_layers = number_temporal_layers;
- for (int i = 0; i < number_temporal_layers; ++i) {
- svc_params->max_quantizers[i] = 56;
+ for (int i = 0; i < number_temporal_layers * number_spatial_layers; ++i) {
+ svc_params->max_quantizers[i] = 60;
svc_params->min_quantizers[i] = 2;
svc_params->layer_target_bitrate[i] = target_layer_bitrate_[i];
}
+ // Do at most 3 spatial or temporal layers here.
svc_params->framerate_factor[0] = 1;
if (number_temporal_layers == 2) {
svc_params->framerate_factor[0] = 2;
@@ -155,6 +176,21 @@
svc_params->framerate_factor[1] = 2;
svc_params->framerate_factor[2] = 1;
}
+ svc_params->scaling_factor_num[0] = 1;
+ svc_params->scaling_factor_den[0] = 1;
+ if (number_spatial_layers == 2) {
+ svc_params->scaling_factor_num[0] = 1;
+ svc_params->scaling_factor_den[0] = 2;
+ svc_params->scaling_factor_num[1] = 1;
+ svc_params->scaling_factor_den[1] = 1;
+ } else if (number_spatial_layers == 3) {
+ svc_params->scaling_factor_num[0] = 1;
+ svc_params->scaling_factor_den[0] = 4;
+ svc_params->scaling_factor_num[1] = 1;
+ svc_params->scaling_factor_den[1] = 2;
+ svc_params->scaling_factor_num[2] = 1;
+ svc_params->scaling_factor_den[2] = 1;
+ }
}
virtual void BasicRateTargetingSVC3TL1SLTest() {
@@ -178,11 +214,8 @@
target_layer_bitrate_[0] = 50 * cfg_.rc_target_bitrate / 100;
target_layer_bitrate_[1] = 70 * cfg_.rc_target_bitrate / 100;
target_layer_bitrate_[2] = cfg_.rc_target_bitrate;
- framerate_factor_[0] = 4;
- framerate_factor_[1] = 2;
- framerate_factor_[2] = 1;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
- for (int i = 0; i < number_temporal_layers_; i++) {
+ for (int i = 0; i < number_temporal_layers_ * number_spatial_layers_; i++) {
ASSERT_GE(effective_datarate_tl[i], target_layer_bitrate_[i] * 0.80)
<< " The datarate for the file is lower than target by too much!";
ASSERT_LE(effective_datarate_tl[i], target_layer_bitrate_[i] * 1.30)
@@ -190,14 +223,45 @@
}
}
+ virtual void BasicRateTargetingSVC1TL2SLTest() {
+ cfg_.rc_buf_initial_sz = 500;
+ cfg_.rc_buf_optimal_sz = 500;
+ cfg_.rc_buf_sz = 1000;
+ cfg_.rc_dropframe_thresh = 0;
+ cfg_.rc_min_quantizer = 0;
+ cfg_.rc_max_quantizer = 63;
+ cfg_.rc_end_usage = AOM_CBR;
+ cfg_.g_lag_in_frames = 0;
+ cfg_.g_usage = AOM_USAGE_REALTIME;
+ cfg_.g_error_resilient = 1;
+
+ ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352,
+ 288, 30, 1, 0, 300);
+ const int bitrate_array[2] = { 300, 600 };
+ cfg_.rc_target_bitrate = bitrate_array[GET_PARAM(4)];
+ ResetModel();
+ number_temporal_layers_ = 1;
+ number_spatial_layers_ = 2;
+ target_layer_bitrate_[0] = 2 * cfg_.rc_target_bitrate / 4;
+ target_layer_bitrate_[1] = 2 * cfg_.rc_target_bitrate / 4;
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ for (int i = 0; i < number_temporal_layers_ * number_spatial_layers_; i++) {
+ ASSERT_GE(effective_datarate_tl[i], target_layer_bitrate_[i] * 0.80)
+ << " The datarate for the file is lower than target by too much!";
+ ASSERT_LE(effective_datarate_tl[i], target_layer_bitrate_[i] * 1.35)
+ << " The datarate for the file is greater than target by too much!";
+ }
+ }
+
+ int layer_frame_cnt_;
int number_temporal_layers_;
+ int number_spatial_layers_;
// Allow for up to 3 temporal layers.
- int target_layer_bitrate_[3];
+ int target_layer_bitrate_[AOM_MAX_LAYERS];
aom_svc_params_t svc_params_;
aom_svc_ref_frame_config_t ref_frame_config_;
aom_svc_layer_id_t layer_id_;
- double effective_datarate_tl[3];
- int framerate_factor_[3];
+ double effective_datarate_tl[AOM_MAX_LAYERS];
};
// Check basic rate targeting for CBR, for 3 temporal layers.
@@ -205,6 +269,11 @@
BasicRateTargetingSVC3TL1SLTest();
}
+// Check basic rate targeting for CBR, for 2 spatial layers.
+TEST_P(DatarateTestSVC, BasicRateTargetingSVC1TL2SL) {
+ BasicRateTargetingSVC1TL2SLTest();
+}
+
AV1_INSTANTIATE_TEST_CASE(DatarateTestSVC,
::testing::Values(::libaom_test::kRealTime),
::testing::Range(7, 9),