rtc: Test for dynamic temporal layers in RC

Add test coverage to external RC for SVC with
temporal layer changes (3->2->1->3) on the fly.

A few fixes in the SVC code were needed for this:
1) add set_primary_rc_buffer_sizes() and
   check_reset_rc_flag() in ctrl_set_svc_params.
   This also allows for user to do dynamic update
   with only calling AV1E_SET_SVC_PARAMS.
2) Reset the cyclic refresh parameters for layers
   whose map is NULL, now done in the function
   av1_update_layer_context_change_config().

Change-Id: I6545564a9fe14ca31030817ea74b80f421f24bcd
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index eb09f26..bf6dd82 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -27,6 +27,7 @@
 #include "av1/encoder/ethread.h"
 #include "av1/encoder/external_partition.h"
 #include "av1/encoder/firstpass.h"
+#include "av1/encoder/rc_utils.h"
 #include "av1/arg_defs.h"
 
 #include "common/args_helper.h"
@@ -3417,6 +3418,7 @@
   AV1_PRIMARY *const ppi = ctx->ppi;
   AV1_COMP *const cpi = ppi->cpi;
   AV1_COMMON *const cm = &cpi->common;
+  AV1EncoderConfig *oxcf = &cpi->oxcf;
   aom_svc_params_t *const params = va_arg(args, aom_svc_params_t *);
   int64_t target_bandwidth = 0;
   ppi->number_spatial_layers = params->number_spatial_layers;
@@ -3453,7 +3455,10 @@
       }
       av1_init_layer_context(cpi);
     }
+    oxcf->rc_cfg.target_bandwidth = target_bandwidth;
+    set_primary_rc_buffer_sizes(oxcf, cpi->ppi);
     av1_update_layer_context_change_config(cpi, target_bandwidth);
+    check_reset_rc_flag(cpi);
   }
   av1_check_fpmt_config(ctx->ppi, &ctx->ppi->cpi->oxcf);
   return AOM_CODEC_OK;
diff --git a/av1/encoder/svc_layercontext.c b/av1/encoder/svc_layercontext.c
index 919bc89..a2f6cbb 100644
--- a/av1/encoder/svc_layercontext.c
+++ b/av1/encoder/svc_layercontext.c
@@ -105,6 +105,9 @@
   int layer = 0;
   int64_t spatial_layer_target = 0;
   float bitrate_alloc = 1.0;
+  AV1_COMMON *const cm = &cpi->common;
+  const int mi_rows = cm->mi_params.mi_rows;
+  const int mi_cols = cm->mi_params.mi_cols;
   for (int sl = 0; sl < svc->number_spatial_layers; ++sl) {
     for (int tl = 0; tl < svc->number_temporal_layers; ++tl) {
       layer = LAYER_IDS_TO_IDX(sl, tl, svc->number_temporal_layers);
@@ -136,6 +139,17 @@
       lrc->rtc_external_ratectrl = rc->rtc_external_ratectrl;
       lrc->worst_quality = av1_quantizer_to_qindex(lc->max_q);
       lrc->best_quality = av1_quantizer_to_qindex(lc->min_q);
+      // Reset the cyclic refresh parameters, if needed (map is NULL).
+      // Cyclic refresh is only applied on base temporal layer.
+      if (svc->number_spatial_layers > 1 && tl == 0 && lc->map == NULL) {
+        lc->sb_index = 0;
+        lc->actual_num_seg1_blocks = 0;
+        lc->actual_num_seg2_blocks = 0;
+        lc->counter_encode_maxq_scene_change = 0;
+        if (lc->map) aom_free(lc->map);
+        CHECK_MEM_ERROR(cm, lc->map,
+                        aom_calloc(mi_rows * mi_cols, sizeof(*lc->map)));
+      }
     }
   }
 }
diff --git a/test/ratectrl_rtc_test.cc b/test/ratectrl_rtc_test.cc
index 07a4e1d..ceef487 100644
--- a/test/ratectrl_rtc_test.cc
+++ b/test/ratectrl_rtc_test.cc
@@ -37,7 +37,8 @@
  public:
   RcInterfaceTest()
       : EncoderTest(GET_PARAM(0)), aq_mode_(GET_PARAM(1)), key_interval_(3000),
-        encoder_exit_(false), layer_frame_cnt_(0) {
+        encoder_exit_(false), layer_frame_cnt_(0), superframe_cnt_(0),
+        dynamic_temporal_layers_(false) {
     memset(&svc_params_, 0, sizeof(svc_params_));
     memset(&layer_id_, 0, sizeof(layer_id_));
   }
@@ -68,9 +69,11 @@
       frame_params_.spatial_layer_id =
           layer_frame_cnt_ % rc_cfg_.ss_number_layers;
       if (rc_cfg_.ts_number_layers == 3)
-        frame_params_.temporal_layer_id = kTemporalId3Layer[video->frame() % 4];
+        frame_params_.temporal_layer_id =
+            kTemporalId3Layer[superframe_cnt_ % 4];
       else if (rc_cfg_.ts_number_layers == 2)
-        frame_params_.temporal_layer_id = kTemporalId2Layer[video->frame() % 2];
+        frame_params_.temporal_layer_id =
+            kTemporalId2Layer[superframe_cnt_ % 2];
       else
         frame_params_.temporal_layer_id = 0;
       layer_id_.spatial_layer_id = frame_params_.spatial_layer_id;
@@ -81,6 +84,25 @@
     frame_params_.frame_type =
         layer_frame_cnt_ % key_int == 0 ? aom::kKeyFrame : aom::kInterFrame;
     encoder_exit_ = video->frame() == kNumFrames;
+
+    if (dynamic_temporal_layers_) {
+      if (superframe_cnt_ == 100 && layer_id_.spatial_layer_id == 0) {
+        // Go down to 2 temporal layers.
+        SetConfigSvc(3, 2);
+        encoder->Control(AV1E_SET_SVC_PARAMS, &svc_params_);
+        rc_api_->UpdateRateControl(rc_cfg_);
+      } else if (superframe_cnt_ == 200 && layer_id_.spatial_layer_id == 0) {
+        // Go down to 1 temporal layer.
+        SetConfigSvc(3, 1);
+        encoder->Control(AV1E_SET_SVC_PARAMS, &svc_params_);
+        rc_api_->UpdateRateControl(rc_cfg_);
+      } else if (superframe_cnt_ == 300 && layer_id_.spatial_layer_id == 0) {
+        // Go back up to 3 temporal layers.
+        SetConfigSvc(3, 3);
+        encoder->Control(AV1E_SET_SVC_PARAMS, &svc_params_);
+        rc_api_->UpdateRateControl(rc_cfg_);
+      }
+    }
   }
 
   void PostEncodeFrameHook(::libaom_test::Encoder *encoder) override {
@@ -88,6 +110,8 @@
       return;
     }
     layer_frame_cnt_++;
+    if (layer_id_.spatial_layer_id == rc_cfg_.ss_number_layers - 1)
+      superframe_cnt_++;
     int qp;
     encoder->Control(AOME_GET_LAST_QUANTIZER, &qp);
     rc_api_->ComputeQP(frame_params_);
@@ -158,6 +182,20 @@
     ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
   }
 
+  void RunSvcDynamicTemporal() {
+    dynamic_temporal_layers_ = true;
+    key_interval_ = 10000;
+    SetConfigSvc(3, 3);
+    rc_api_ = aom::AV1RateControlRTC::Create(rc_cfg_);
+    frame_params_.spatial_layer_id = 0;
+    frame_params_.temporal_layer_id = 0;
+
+    ::libaom_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30,
+                                         1, 0, kNumFrames);
+
+    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+  }
+
  private:
   void SetConfig() {
     rc_cfg_.width = 640;
@@ -334,6 +372,8 @@
   aom_svc_params_t svc_params_;
   aom_svc_layer_id_t layer_id_;
   int layer_frame_cnt_;
+  int superframe_cnt_;
+  bool dynamic_temporal_layers_;
 };
 
 TEST_P(RcInterfaceTest, OneLayer) { RunOneLayer(); }
@@ -344,6 +384,8 @@
 
 TEST_P(RcInterfaceTest, SvcPeriodicKey) { RunSvcPeriodicKey(); }
 
+TEST_P(RcInterfaceTest, SvcDynamicTemporal) { RunSvcDynamicTemporal(); }
+
 AV1_INSTANTIATE_TEST_SUITE(RcInterfaceTest, ::testing::Values(0, 3));
 
 }  // namespace