rtc: Fix setting of intra-only frame for set_ref_frame_config When setting the reference structure with SET_REF_FRAME_CONFIG: if no references are set for delta frames then that frame should be set internally to an intra-only frame. But this check was only being done if layers are used (number_temporal > 1 or number_spatial > 1) (i.e., use_svc is set). So single layer was not being checked. Fix here is to check and set to intra-only regardless of layers. Added unittest, based on: https://chromium-review.googlesource.com/c/chromium/src/+/5809671 Bug: 363016123 Change-Id: Ie9d9ce190dc407a50e592a5f8bf47c2a26779e9b
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c index 007812d..5aa38a3 100644 --- a/av1/encoder/ratectrl.c +++ b/av1/encoder/ratectrl.c
@@ -3715,23 +3715,24 @@ svc->spatial_layer_id == 0 ? 0 : svc->layer_context[svc->temporal_layer_id].is_key_frame; - // If the user is setting the reference structure with - // set_ref_frame_config and did not set any references, set the - // frame type to Intra-only. - if (cpi->ppi->rtc_ref.set_ref_frame_config) { - int no_references_set = 1; - for (int i = 0; i < INTER_REFS_PER_FRAME; i++) { - if (cpi->ppi->rtc_ref.reference[i]) { - no_references_set = 0; - break; - } + } + // If the user is setting the reference structure with + // set_ref_frame_config and did not set any references, set the + // frame type to Intra-only. + if (cpi->ppi->rtc_ref.set_ref_frame_config) { + int no_references_set = 1; + for (int i = 0; i < INTER_REFS_PER_FRAME; i++) { + if (cpi->ppi->rtc_ref.reference[i]) { + no_references_set = 0; + break; } - // Set to intra_only_frame if no references are set. - // The stream can start decoding on INTRA_ONLY_FRAME so long as the - // layer with the intra_only_frame doesn't signal a reference to a slot - // that hasn't been set yet. - if (no_references_set) *frame_type = INTRA_ONLY_FRAME; } + + // Set to intra_only_frame if no references are set. + // The stream can start decoding on INTRA_ONLY_FRAME so long as the + // layer with the intra_only_frame doesn't signal a reference to a slot + // that hasn't been set yet. + if (no_references_set) *frame_type = INTRA_ONLY_FRAME; } } if (cpi->active_map.enabled && cpi->rc.percent_blocks_inactive == 100) {
diff --git a/test/svc_datarate_test.cc b/test/svc_datarate_test.cc index 7da2160..a1b7136 100644 --- a/test/svc_datarate_test.cc +++ b/test/svc_datarate_test.cc
@@ -86,6 +86,7 @@ comp_pred_ = 0; dynamic_enable_disable_mode_ = 0; intra_only_ = 0; + intra_only_single_layer_ = false; frame_to_start_decoding_ = 0; layer_to_decode_ = 0; frame_sync_ = 0; @@ -675,9 +676,20 @@ // Always reference LAST. ref_frame_config->reference[0] = 1; if (number_temporal_layers_ == 1 && number_spatial_layers_ == 1) { + layer_id->temporal_layer_id = 0; ref_frame_config->refresh[0] = 1; if (rps_mode) ref_config_rps(ref_frame_config, frame_cnt, rps_recovery_frame); + if (intra_only_single_layer_) { + // This repros the crash in Bug: 363016123. + ref_frame_config->ref_idx[0] = 0; + ref_frame_config->ref_idx[3] = 1; + ref_frame_config->ref_idx[6] = 2; + if (frame_cnt == 1) { + for (int i = 0; i < INTER_REFS_PER_FRAME; i++) + ref_frame_config->reference[i] = 0; + } + } } if (number_temporal_layers_ == 2 && number_spatial_layers_ == 1) { // 2-temporal layer. @@ -1369,6 +1381,32 @@ } } + virtual void BasicRateTargetingSVC1TL1SLIntraOnlyTest() { + 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_error_resilient = 0; + + ::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(); + intra_only_single_layer_ = true; + number_temporal_layers_ = 1; + number_spatial_layers_ = 1; + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + ASSERT_GE(effective_datarate_tl[0], cfg_.rc_target_bitrate * 0.80) + << " The datarate for the file is lower than target by too much!"; + ASSERT_LE(effective_datarate_tl[0], cfg_.rc_target_bitrate * 1.60) + << " The datarate for the file is greater than target by too much!"; + } + virtual void BasicRateTargetingSVC1TL3SLTest() { cfg_.rc_buf_initial_sz = 500; cfg_.rc_buf_optimal_sz = 500; @@ -2442,6 +2480,7 @@ int comp_pred_; int dynamic_enable_disable_mode_; int intra_only_; + int intra_only_single_layer_; unsigned int frame_to_start_decoding_; unsigned int layer_to_decode_; unsigned int frame_sync_; @@ -2532,6 +2571,12 @@ BasicRateTargetingSVC1TL2SLIntraOnlyTest(); } +// Check basic rate targeting for CBR, for 1 spatial layers, 1 temporal, +// with Intra-only frame (frame with no references) inserted in the stream. +TEST_P(DatarateTestSVC, BasicRateTargetingSVC1TL1SLIntraOnly) { + BasicRateTargetingSVC1TL1SLIntraOnlyTest(); +} + // Check basic rate targeting for CBR, for 3 spatial layers, 1 temporal. TEST_P(DatarateTestSVC, BasicRateTargetingSVC1TL3SL) { BasicRateTargetingSVC1TL3SLTest();