rtc-svc: Add (3 spatial, 3 temporal) layers Update sample encoder and SVC datarate tests. Change-Id: I27036a7422ac2c0449b4eb715459d74af1fea790
diff --git a/examples/svc_encoder_rtc.c b/examples/svc_encoder_rtc.c index d77fa99..ea87af1 100644 --- a/examples/svc_encoder_rtc.c +++ b/examples/svc_encoder_rtc.c
@@ -30,9 +30,9 @@ void usage_exit(void) { exit(EXIT_FAILURE); } -static int mode_to_num_temporal_layers[7] = { 1, 2, 3, 3, 2, 1, 1 }; -static int mode_to_num_spatial_layers[7] = { 1, 1, 1, 1, 1, 2, 3 }; -static int mode_to_num_layers[7] = { 1, 2, 3, 3, 2, 2, 3 }; +static int mode_to_num_temporal_layers[8] = { 1, 2, 3, 3, 2, 1, 1, 3 }; +static int mode_to_num_spatial_layers[8] = { 1, 1, 1, 1, 1, 2, 3, 3 }; +static int mode_to_num_layers[8] = { 1, 2, 3, 3, 2, 2, 3, 9 }; // For rate control encoding stats. struct RateControlMetrics { @@ -245,7 +245,7 @@ } // Layer pattern configuration. -static int set_layer_pattern(int layering_mode, int frame_cnt, +static int set_layer_pattern(int layering_mode, int superframe_cnt, aom_svc_layer_id_t *layer_id, aom_svc_ref_frame_config_t *ref_frame_config, int *use_svc_control, int spatial_layer_id) { @@ -268,10 +268,10 @@ ref_frame_config->refresh[0] = 1; break; case 1: - // 2-layer. + // 2-temporal layer. // 1 3 5 // 0 2 4 - if (frame_cnt % 2 == 0) { + if (superframe_cnt % 2 == 0) { layer_id->temporal_layer_id = 0; // Update LAST on layer 0, reference LAST and GF. ref_frame_config->refresh[0] = 1; @@ -282,25 +282,25 @@ } break; case 2: - // 3-layer: + // 3-temporal layer: // 1 3 5 7 // 2 6 // 0 4 8 - if (frame_cnt % 4 == 0) { + if (superframe_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) { + } else if ((superframe_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) { + } else if ((superframe_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) { + } else if ((superframe_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 @@ -311,38 +311,39 @@ } break; case 3: - // 3-layer: but middle layer updates GF, so 2nd TL2 will only - // reference GF (not LAST). Other frames only reference LAST. + // 3-temporal layer: but middle layer updates GF, so 2nd TL2 will + // only reference GF (not LAST). Other frames only reference LAST. // 1 3 5 7 // 2 6 // 0 4 8 - if (frame_cnt % 4 == 0) { + if (superframe_cnt % 4 == 0) { // Base layer. layer_id->temporal_layer_id = 0; // Update LAST on layer 0, only reference LAST. ref_frame_config->refresh[0] = 1; layer_flags |= AOM_EFLAG_NO_REF_GF; - } else if ((frame_cnt - 1) % 4 == 0) { + } else if ((superframe_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) { + } else if ((superframe_cnt - 2) % 4 == 0) { layer_id->temporal_layer_id = 1; // Middle layer (TL1): update GF, only reference LAST (TL0). ref_frame_config->refresh[3] = 1; layer_flags |= AOM_EFLAG_NO_REF_GF; - } else if ((frame_cnt - 3) % 4 == 0) { + } else if ((superframe_cnt - 3) % 4 == 0) { layer_id->temporal_layer_id = 2; // Second top layer: no updates, only reference GF. layer_flags |= AOM_EFLAG_NO_REF_LAST; } break; case 4: - // 2-layer with the old update flags, not with the new SVC control. + // 2-temporla layer with the old update flags, not with the new + // SVC control. *use_svc_control = 0; // 1 3 5 // 0 2 4 - if (frame_cnt % 2 == 0) { + if (superframe_cnt % 2 == 0) { layer_id->temporal_layer_id = 0; // Update LAST on layer 0, reference LAST and GF. layer_flags |= AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF; @@ -399,6 +400,124 @@ ref_frame_config->refresh[2] = 1; } break; + case 7: + // 3 spatial and 3 temporal layer. + if (superframe_cnt % 4 == 0) { + // Base temporal layer. + layer_id->temporal_layer_id = 0; + if (layer_id->spatial_layer_id == 0) { + // Reference LAST, update LAST. + // Set all buffer_idx to 0. + for (i = 0; i < INTER_REFS_PER_FRAME; i++) + ref_frame_config->ref_idx[i] = 0; + 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 1, + // GOLDEN (and all other refs) to slot 0. + // Update slot 1 (LAST). + for (i = 0; i < INTER_REFS_PER_FRAME; i++) + ref_frame_config->ref_idx[i] = 0; + ref_frame_config->ref_idx[0] = 1; + ref_frame_config->refresh[1] = 1; + } else if (layer_id->spatial_layer_id == 2) { + // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 2, + // GOLDEN (and all other refs) to slot 1. + // Update slot 2 (LAST). + for (i = 0; i < INTER_REFS_PER_FRAME; i++) + ref_frame_config->ref_idx[i] = 1; + ref_frame_config->ref_idx[0] = 2; + ref_frame_config->refresh[2] = 1; + } + } else if ((superframe_cnt - 1) % 4 == 0) { + // First top temporal enhancement layer. + layer_id->temporal_layer_id = 2; + if (layer_id->spatial_layer_id == 0) { + // Reference LAST (slot 0). + // Set GOLDEN to slot 3 and update slot 3. + // Set all other buffer_idx to slot 0. + for (i = 0; i < INTER_REFS_PER_FRAME; i++) + ref_frame_config->ref_idx[i] = 0; + ref_frame_config->ref_idx[3] = 3; + ref_frame_config->refresh[3] = 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 1, + // GOLDEN (and all other refs) to slot 3. + // Set LAST2 to slot 4 and Update slot 4. + for (i = 0; i < INTER_REFS_PER_FRAME; i++) + ref_frame_config->ref_idx[i] = 3; + ref_frame_config->ref_idx[0] = 1; + ref_frame_config->ref_idx[1] = 4; + ref_frame_config->refresh[4] = 1; + } else if (layer_id->spatial_layer_id == 2) { + // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 2, + // GOLDEN (and all other refs) to slot 4. + // No update. + for (i = 0; i < INTER_REFS_PER_FRAME; i++) + ref_frame_config->ref_idx[i] = 4; + ref_frame_config->ref_idx[0] = 2; + } + } else if ((superframe_cnt - 2) % 4 == 0) { + // Middle temporal enhancement layer. + layer_id->temporal_layer_id = 1; + if (layer_id->spatial_layer_id == 0) { + // Reference LAST. + // Set all buffer_idx to 0. + // Set GOLDEN to slot 3 and update slot 3. + for (i = 0; i < INTER_REFS_PER_FRAME; i++) + ref_frame_config->ref_idx[i] = 0; + ref_frame_config->ref_idx[3] = 3; + ref_frame_config->refresh[3] = 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 1, + // GOLDEN (and all other refs) to slot 3. + // Set LAST2 to slot and Update slot 4. + for (i = 0; i < INTER_REFS_PER_FRAME; i++) + ref_frame_config->ref_idx[i] = 3; + ref_frame_config->ref_idx[0] = 1; + ref_frame_config->ref_idx[2] = 4; + ref_frame_config->refresh[4] = 1; + } else if (layer_id->spatial_layer_id == 2) { + // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 2, + // GOLDEN (and all other refs) to slot 4. + // Set LAST2 to slot 5 and update slot 5. + for (i = 0; i < INTER_REFS_PER_FRAME; i++) + ref_frame_config->ref_idx[i] = 4; + ref_frame_config->ref_idx[0] = 2; + ref_frame_config->ref_idx[2] = 5; + ref_frame_config->refresh[5] = 1; + } + } else if ((superframe_cnt - 3) % 4 == 0) { + // Second top temporal enhancement layer. + layer_id->temporal_layer_id = 2; + if (layer_id->spatial_layer_id == 0) { + // Set LAST to slot 3 and reference LAST. + // Set all other buffer_idx to 0. + for (i = 0; i < INTER_REFS_PER_FRAME; i++) + ref_frame_config->ref_idx[i] = 0; + ref_frame_config->ref_idx[0] = 3; + ref_frame_config->refresh[3] = 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 4, + // GOLDEN to slot 3, and update slot 4. + for (i = 0; i < INTER_REFS_PER_FRAME; i++) + ref_frame_config->ref_idx[i] = 0; + ref_frame_config->ref_idx[0] = 4; + ref_frame_config->ref_idx[3] = 3; + ref_frame_config->refresh[4] = 1; + } else if (layer_id->spatial_layer_id == 2) { + // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 5, + // GOLDEN to slot 4. No update. + for (i = 0; i < INTER_REFS_PER_FRAME; i++) + ref_frame_config->ref_idx[i] = 0; + ref_frame_config->ref_idx[3] = 4; + ref_frame_config->ref_idx[0] = 5; + } + } + break; default: assert(0); die("Error: Unsupported temporal layering mode!\n"); } return layer_flags; @@ -668,7 +787,6 @@ 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).
diff --git a/test/svc_datarate_test.cc b/test/svc_datarate_test.cc index a6d3b3d..9ea2aad 100644 --- a/test/svc_datarate_test.cc +++ b/test/svc_datarate_test.cc
@@ -45,6 +45,7 @@ virtual void ResetModel() { DatarateTest::ResetModel(); layer_frame_cnt_ = 0; + superframe_cnt_ = 0; number_temporal_layers_ = 1; number_spatial_layers_ = 1; for (int i = 0; i < AOM_MAX_LAYERS; i++) { @@ -89,8 +90,10 @@ 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) + if (layer_id_.spatial_layer_id == number_spatial_layers_ - 1) { last_pts_ = pkt->data.frame.pts; + superframe_cnt_++; + } } virtual void EndPassHook(void) { @@ -184,6 +187,111 @@ ref_frame_config->ref_idx[0] = 2; ref_frame_config->refresh[2] = 1; } + } else if (number_temporal_layers_ == 3 && number_spatial_layers_ == 3) { + // 3 spatial and 3 temporal layer. + if (superframe_cnt_ % 4 == 0) { + // Base temporal layer. + layer_id->temporal_layer_id = 0; + if (layer_id->spatial_layer_id == 0) { + // Reference LAST, update LAST. + // Set all buffer_idx to 0. + for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0; + 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 1, + // GOLDEN (and all other refs) to slot 0. + // Update slot 1 (LAST). + for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0; + ref_frame_config->ref_idx[0] = 1; + ref_frame_config->refresh[1] = 1; + } else if (layer_id->spatial_layer_id == 2) { + // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 2, + // GOLDEN (and all other refs) to slot 1. + // Update slot 2 (LAST). + for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 1; + ref_frame_config->ref_idx[0] = 2; + ref_frame_config->refresh[2] = 1; + } + } else if ((superframe_cnt_ - 1) % 4 == 0) { + // First top temporal enhancement layer. + layer_id->temporal_layer_id = 2; + if (layer_id->spatial_layer_id == 0) { + // Reference LAST (slot 0). + // Set GOLDEN to slot 3 and update slot 3. + // Set all other buffer_idx to slot 0. + for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0; + ref_frame_config->ref_idx[3] = 3; + ref_frame_config->refresh[3] = 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 1, + // GOLDEN (and all other refs) to slot 3. + // Set LAST2 to slot 4 and Update slot 4. + for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 3; + ref_frame_config->ref_idx[0] = 1; + ref_frame_config->ref_idx[1] = 4; + ref_frame_config->refresh[4] = 1; + } else if (layer_id->spatial_layer_id == 2) { + // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 2, + // GOLDEN (and all other refs) to slot 4. + // No update. + for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 4; + ref_frame_config->ref_idx[0] = 2; + } + } else if ((superframe_cnt_ - 2) % 4 == 0) { + // Middle temporal enhancement layer. + layer_id->temporal_layer_id = 1; + if (layer_id->spatial_layer_id == 0) { + // Reference LAST. + // Set all buffer_idx to 0. + // Set GOLDEN to slot 3 and update slot 3. + for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0; + ref_frame_config->ref_idx[3] = 3; + ref_frame_config->refresh[3] = 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 1, + // GOLDEN (and all other refs) to slot 3. + // Set LAST2 to slot and Update slot 4. + for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 3; + ref_frame_config->ref_idx[0] = 1; + ref_frame_config->ref_idx[2] = 4; + ref_frame_config->refresh[4] = 1; + } else if (layer_id->spatial_layer_id == 2) { + // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 2, + // GOLDEN (and all other refs) to slot 4. + // Set LAST2 to slot 5 and update slot 5. + for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 4; + ref_frame_config->ref_idx[0] = 2; + ref_frame_config->ref_idx[2] = 5; + ref_frame_config->refresh[5] = 1; + } + } else if ((superframe_cnt_ - 3) % 4 == 0) { + // Second top temporal enhancement layer. + layer_id->temporal_layer_id = 2; + if (layer_id->spatial_layer_id == 0) { + // Set LAST to slot 3 and reference LAST. + // Set all other buffer_idx to 0. + for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0; + ref_frame_config->ref_idx[0] = 3; + ref_frame_config->refresh[3] = 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 4, + // GOLDEN to slot 3, and update slot 4. + for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0; + ref_frame_config->ref_idx[0] = 4; + ref_frame_config->ref_idx[3] = 3; + ref_frame_config->refresh[4] = 1; + } else if (layer_id->spatial_layer_id == 2) { + // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 5, + // GOLDEN to slot 4. No update. + for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0; + ref_frame_config->ref_idx[3] = 4; + ref_frame_config->ref_idx[0] = 5; + } + } } return layer_flags; } @@ -316,7 +424,51 @@ } } + virtual void BasicRateTargetingSVC3TL3SLTest() { + 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] = { 600, 1200 }; + cfg_.rc_target_bitrate = bitrate_array[GET_PARAM(4)]; + ResetModel(); + number_temporal_layers_ = 3; + number_spatial_layers_ = 3; + // SL0 + const int bitrate_sl0 = 1 * cfg_.rc_target_bitrate / 8; + target_layer_bitrate_[0] = 50 * bitrate_sl0 / 100; + target_layer_bitrate_[1] = 70 * bitrate_sl0 / 100; + target_layer_bitrate_[2] = bitrate_sl0; + // SL1 + const int bitrate_sl1 = 3 * cfg_.rc_target_bitrate / 8; + target_layer_bitrate_[3] = 50 * bitrate_sl1 / 100; + target_layer_bitrate_[4] = 70 * bitrate_sl1 / 100; + target_layer_bitrate_[5] = bitrate_sl1; + // SL2 + const int bitrate_sl2 = 4 * cfg_.rc_target_bitrate / 8; + target_layer_bitrate_[6] = 50 * bitrate_sl2 / 100; + target_layer_bitrate_[7] = 70 * bitrate_sl2 / 100; + target_layer_bitrate_[8] = bitrate_sl2; + 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.38) + << " The datarate for the file is greater than target by too much!"; + } + } + int layer_frame_cnt_; + int superframe_cnt_; int number_temporal_layers_; int number_spatial_layers_; // Allow for up to 3 temporal layers. @@ -342,6 +494,11 @@ BasicRateTargetingSVC1TL3SLTest(); } +// Check basic rate targeting for CBR, for 3 spatial, 3 temporal layers. +TEST_P(DatarateTestSVC, BasicRateTargetingSVC3TL3SL) { + BasicRateTargetingSVC3TL3SLTest(); +} + AV1_INSTANTIATE_TEST_CASE(DatarateTestSVC, ::testing::Values(::libaom_test::kRealTime), ::testing::Range(7, 9),