rtc-svc: Add example for 3 spatial layers.

Add (3SL, 1TL) case to sample encoder and unittest.

Change-Id: I66ba12b3c9357e136aca5782b0edf7f060de39b8
diff --git a/examples/svc_encoder_rtc.c b/examples/svc_encoder_rtc.c
index a5ab076..d77fa99 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[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 };
+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 };
 
 // For rate control encoding stats.
 struct RateControlMetrics {
@@ -354,19 +354,49 @@
       }
       break;
     case 5:
+      // 2 spatial layers, 1 temporal.
       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;
+        // Reference LAST, update LAST.
         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;
+        // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1
+        // and GOLDEN to slot 0. Update slot 1 (LAST).
+        ref_frame_config->ref_idx[0] = 1;
         ref_frame_config->ref_idx[3] = 0;
-        ref_frame_config->refresh[3] = 1;
+        ref_frame_config->refresh[1] = 1;
+      }
+      break;
+    case 6:
+      // 3 spatial layers, 1 temporal.
+      // Note for this case, we set the buffer idx for all references to be
+      // either LAST or GOLDEN, which are always valid references, since decoder
+      // will check if any of the 7 references is valid scale in
+      // valid_ref_frame_size().
+      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
+        // and 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
+        // and 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;
       }
       break;
     default: assert(0); die("Error: Unsupported temporal layering mode!\n");
diff --git a/test/svc_datarate_test.cc b/test/svc_datarate_test.cc
index 1a50f16..a6d3b3d 100644
--- a/test/svc_datarate_test.cc
+++ b/test/svc_datarate_test.cc
@@ -64,8 +64,13 @@
                      &svc_params_);
       encoder->Control(AV1E_SET_SVC_PARAMS, &svc_params_);
     }
-    if (number_spatial_layers_ == 2)
+    if (number_spatial_layers_ == 2) {
       spatial_layer_id = (layer_frame_cnt_ % 2 == 0) ? 0 : 1;
+    } else if (number_spatial_layers_ == 3) {
+      spatial_layer_id = (layer_frame_cnt_ % 3 == 0)
+                             ? 0
+                             : ((layer_frame_cnt_ - 1) % 3 == 0) ? 1 : 2;
+    }
     // Set the reference/update flags, layer_id, and reference_map
     // buffer index.
     frame_flags_ = set_layer_pattern(video->frame(), &layer_id_,
@@ -152,6 +157,33 @@
         ref_frame_config->ref_idx[3] = 0;
         ref_frame_config->refresh[3] = 1;
       }
+    } else if (number_temporal_layers_ == 1 && number_spatial_layers_ == 3) {
+      // 3 spatial layers, 1 temporal.
+      // Note for this case , we set the buffer idx for all references to be
+      // either LAST or GOLDEN, which are always valid references, since decoder
+      // will check if any of the 7 references is valid scale in
+      // valid_ref_frame_size().
+      layer_id->temporal_layer_id = 0;
+      if (layer_id->spatial_layer_id == 0) {
+        // Reference LAST, update 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->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
+        // and 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
+        // and 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;
+      }
     }
     return layer_flags;
   }
@@ -253,6 +285,37 @@
     }
   }
 
+  virtual void BasicRateTargetingSVC1TL3SLTest() {
+    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] = { 500, 1000 };
+    cfg_.rc_target_bitrate = bitrate_array[GET_PARAM(4)];
+    ResetModel();
+    number_temporal_layers_ = 1;
+    number_spatial_layers_ = 3;
+    target_layer_bitrate_[0] = 1 * cfg_.rc_target_bitrate / 8;
+    target_layer_bitrate_[1] = 3 * cfg_.rc_target_bitrate / 8;
+    target_layer_bitrate_[2] = 4 * cfg_.rc_target_bitrate / 8;
+    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 number_temporal_layers_;
   int number_spatial_layers_;
@@ -264,16 +327,21 @@
   double effective_datarate_tl[AOM_MAX_LAYERS];
 };
 
-// Check basic rate targeting for CBR, for 3 temporal layers.
+// Check basic rate targeting for CBR, for 3 temporal layers, 1 spatial.
 TEST_P(DatarateTestSVC, BasicRateTargetingSVC3TL1SL) {
   BasicRateTargetingSVC3TL1SLTest();
 }
 
-// Check basic rate targeting for CBR, for 2 spatial layers.
+// Check basic rate targeting for CBR, for 2 spatial layers, 1 temporal.
 TEST_P(DatarateTestSVC, BasicRateTargetingSVC1TL2SL) {
   BasicRateTargetingSVC1TL2SLTest();
 }
 
+// Check basic rate targeting for CBR, for 3 spatial layers, 1 temporal.
+TEST_P(DatarateTestSVC, BasicRateTargetingSVC1TL3SL) {
+  BasicRateTargetingSVC1TL3SLTest();
+}
+
 AV1_INSTANTIATE_TEST_CASE(DatarateTestSVC,
                           ::testing::Values(::libaom_test::kRealTime),
                           ::testing::Range(7, 9),