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();