vp9 svc: Add tests for sync on 2nd & 3rd spatial layers.

Change-Id: I4d8b6d114d9a407f5bb879ab059a66425976f1df
diff --git a/test/encode_test_driver.cc b/test/encode_test_driver.cc
index 005a4b9..22e3f05 100644
--- a/test/encode_test_driver.cc
+++ b/test/encode_test_driver.cc
@@ -128,6 +128,8 @@
   bool match = (img1->fmt == img2->fmt) && (img1->cs == img2->cs) &&
                (img1->d_w == img2->d_w) && (img1->d_h == img2->d_h);
 
+  if (!match) return false;
+
   const unsigned int width_y = img1->d_w;
   const unsigned int height_y = img1->d_h;
   unsigned int i;
diff --git a/test/svc_end_to_end_test.cc b/test/svc_end_to_end_test.cc
index d742469..d4c1a5c 100644
--- a/test/svc_end_to_end_test.cc
+++ b/test/svc_end_to_end_test.cc
@@ -26,9 +26,11 @@
  public:
   SyncFrameOnePassCbrSvc()
       : OnePassCbrSvc(GET_PARAM(0)), current_video_frame_(0),
-        frame_to_start_decode_(0), mismatch_nframes_(0), num_nonref_frames_(0),
-        inter_layer_pred_mode_(GET_PARAM(1)) {
+        frame_to_start_decode_(0), frame_to_sync_(0), mismatch_nframes_(0),
+        num_nonref_frames_(0), inter_layer_pred_mode_(GET_PARAM(1)),
+        decode_to_layer_before_sync_(-1), decode_to_layer_after_sync_(-1) {
     SetMode(::libvpx_test::kRealTime);
+    memset(&svc_layer_sync_, 0, sizeof(svc_layer_sync_));
   }
 
  protected:
@@ -39,6 +41,32 @@
     speed_setting_ = 7;
   }
 
+  void Set2SpatialLayerConfig() {
+    SetConfig();
+    cfg_.ss_number_layers = 2;
+    cfg_.ts_number_layers = 3;
+    svc_params_.scaling_factor_num[0] = 144;
+    svc_params_.scaling_factor_den[0] = 288;
+    svc_params_.scaling_factor_num[1] = 288;
+    svc_params_.scaling_factor_den[1] = 288;
+    number_spatial_layers_ = cfg_.ss_number_layers;
+    number_temporal_layers_ = cfg_.ts_number_layers;
+  }
+
+  void Set3SpatialLayerConfig() {
+    SetConfig();
+    cfg_.ss_number_layers = 3;
+    cfg_.ts_number_layers = 3;
+    svc_params_.scaling_factor_num[0] = 72;
+    svc_params_.scaling_factor_den[0] = 288;
+    svc_params_.scaling_factor_num[1] = 144;
+    svc_params_.scaling_factor_den[1] = 288;
+    svc_params_.scaling_factor_num[2] = 288;
+    svc_params_.scaling_factor_den[2] = 288;
+    number_spatial_layers_ = cfg_.ss_number_layers;
+    number_temporal_layers_ = cfg_.ts_number_layers;
+  }
+
   virtual bool DoDecode() const {
     return current_video_frame_ >= frame_to_start_decode_;
   }
@@ -49,16 +77,26 @@
     PreEncodeFrameHookSetup(video, encoder);
     if (video->frame() == 0)
       encoder->Control(VP9E_SET_SVC_INTER_LAYER_PRED, inter_layer_pred_mode_);
-    if (video->frame() == frame_to_start_decode_) {
-      vpx_svc_spatial_layer_sync_t svc_layer_sync;
-      for (size_t i = 0; i < cfg_.ss_number_layers; i++)
-        svc_layer_sync.spatial_layer_sync[i] = 0;
-      svc_layer_sync.base_layer_intra_only = 0;
-      svc_layer_sync.spatial_layer_sync[0] = 1;
-      encoder->Control(VP9E_SET_SVC_SPATIAL_LAYER_SYNC, &svc_layer_sync);
+    if (video->frame() == frame_to_sync_) {
+      encoder->Control(VP9E_SET_SVC_SPATIAL_LAYER_SYNC, &svc_layer_sync_);
     }
   }
 
+#if CONFIG_VP9_DECODER
+  virtual void PreDecodeFrameHook(::libvpx_test::VideoSource *video,
+                                  ::libvpx_test::Decoder *decoder) {
+    if (video->frame() < frame_to_sync_) {
+      if (decode_to_layer_before_sync_ >= 0)
+        decoder->Control(VP9_DECODE_SVC_SPATIAL_LAYER,
+                         decode_to_layer_before_sync_);
+    } else {
+      if (decode_to_layer_after_sync_ >= 0)
+        decoder->Control(VP9_DECODE_SVC_SPATIAL_LAYER,
+                         decode_to_layer_after_sync_);
+    }
+  }
+#endif
+
   virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
     // Keep track of number of non-reference frames, needed for mismatch check.
     // Non-reference frames are top spatial and temporal layer frames,
@@ -66,51 +104,90 @@
     if (temporal_layer_id_ == number_temporal_layers_ - 1 &&
         temporal_layer_id_ > 0 &&
         pkt->data.frame.spatial_layer_encoded[number_spatial_layers_ - 1] &&
-        current_video_frame_ >= frame_to_start_decode_)
+        current_video_frame_ >= frame_to_sync_)
       num_nonref_frames_++;
   }
 
   virtual void MismatchHook(const vpx_image_t * /*img1*/,
                             const vpx_image_t * /*img2*/) {
-    ++mismatch_nframes_;
+    if (current_video_frame_ >= frame_to_sync_) ++mismatch_nframes_;
   }
 
   unsigned int GetMismatchFrames() const { return mismatch_nframes_; }
 
   unsigned int current_video_frame_;
   unsigned int frame_to_start_decode_;
+  unsigned int frame_to_sync_;
   unsigned int mismatch_nframes_;
   unsigned int num_nonref_frames_;
   int inter_layer_pred_mode_;
+  int decode_to_layer_before_sync_;
+  int decode_to_layer_after_sync_;
+  vpx_svc_spatial_layer_sync_t svc_layer_sync_;
+
+ private:
+  void SetConfig() {
+    cfg_.rc_buf_initial_sz = 500;
+    cfg_.rc_buf_optimal_sz = 500;
+    cfg_.rc_buf_sz = 1000;
+    cfg_.rc_min_quantizer = 0;
+    cfg_.rc_max_quantizer = 63;
+    cfg_.rc_end_usage = VPX_CBR;
+    cfg_.g_lag_in_frames = 0;
+    cfg_.g_error_resilient = 1;
+    cfg_.g_threads = 1;
+    cfg_.rc_dropframe_thresh = 30;
+    cfg_.kf_max_dist = 9999;
+    cfg_.ts_rate_decimator[0] = 4;
+    cfg_.ts_rate_decimator[1] = 2;
+    cfg_.ts_rate_decimator[2] = 1;
+    cfg_.temporal_layering_mode = 3;
+  }
 };
 
-// Test for sync layer for 1 pass CBR SVC: 2 spatial layers and
+// Test for sync layer for 1 pass CBR SVC: 3 spatial layers and
 // 3 temporal layers. Only start decoding on the sync layer.
-TEST_P(SyncFrameOnePassCbrSvc, OnePassCbrSvc2SL3TLSyncFrame) {
-  cfg_.rc_buf_initial_sz = 500;
-  cfg_.rc_buf_optimal_sz = 500;
-  cfg_.rc_buf_sz = 1000;
-  cfg_.rc_min_quantizer = 0;
-  cfg_.rc_max_quantizer = 63;
-  cfg_.rc_end_usage = VPX_CBR;
-  cfg_.g_lag_in_frames = 0;
-  cfg_.ss_number_layers = 2;
-  cfg_.ts_number_layers = 3;
-  cfg_.ts_rate_decimator[0] = 4;
-  cfg_.ts_rate_decimator[1] = 2;
-  cfg_.ts_rate_decimator[2] = 1;
-  cfg_.g_error_resilient = 1;
-  cfg_.g_threads = 1;
-  cfg_.temporal_layering_mode = 3;
-  svc_params_.scaling_factor_num[0] = 144;
-  svc_params_.scaling_factor_den[0] = 288;
-  svc_params_.scaling_factor_num[1] = 288;
-  svc_params_.scaling_factor_den[1] = 288;
-  cfg_.rc_dropframe_thresh = 30;
-  cfg_.kf_max_dist = 9999;
-  number_spatial_layers_ = cfg_.ss_number_layers;
-  number_temporal_layers_ = cfg_.ts_number_layers;
-  frame_to_start_decode_ = 100;
+// Full sync: insert key frame on base layer.
+TEST_P(SyncFrameOnePassCbrSvc, OnePassCbrSvc3SL3TLSyncFrameFull) {
+  Set3SpatialLayerConfig();
+  // Sync is on base layer so the frame to sync and the frame to start decoding
+  // is the same.
+  frame_to_start_decode_ = 20;
+  frame_to_sync_ = 20;
+  decode_to_layer_before_sync_ = -1;
+  decode_to_layer_after_sync_ = 2;
+
+  // Set up svc layer sync structure.
+  svc_layer_sync_.base_layer_intra_only = 0;
+  svc_layer_sync_.spatial_layer_sync[0] = 1;
+
+  ::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
+
+  cfg_.rc_target_bitrate = 600;
+  AssignLayerBitrates();
+  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+#if CONFIG_VP9_DECODER
+  // The non-reference frames are expected to be mismatched frames as the
+  // encoder will avoid loopfilter on these frames.
+  EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
+#endif
+}
+
+// Test for sync layer for 1 pass CBR SVC: 2 spatial layers and
+// 3 temporal layers. Decoding QVGA before sync frame and decode up to
+// VGA on and after sync.
+TEST_P(SyncFrameOnePassCbrSvc, OnePassCbrSvc2SL3TLSyncFrameVGA) {
+  Set2SpatialLayerConfig();
+  frame_to_start_decode_ = 0;
+  frame_to_sync_ = 100;
+  decode_to_layer_before_sync_ = 0;
+  decode_to_layer_after_sync_ = 1;
+
+  // Set up svc layer sync structure.
+  svc_layer_sync_.base_layer_intra_only = 0;
+  svc_layer_sync_.spatial_layer_sync[0] = 0;
+  svc_layer_sync_.spatial_layer_sync[1] = 1;
+
   ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
                                        0, 400);
   cfg_.rc_target_bitrate = 400;
@@ -123,6 +200,60 @@
 #endif
 }
 
+// Test for sync layer for 1 pass CBR SVC: 3 spatial layers and
+// 3 temporal layers. Decoding QVGA and VGA before sync frame and decode up to
+// HD on and after sync.
+TEST_P(SyncFrameOnePassCbrSvc, OnePassCbrSvc3SL3TLSyncFrameHD) {
+  Set3SpatialLayerConfig();
+  frame_to_start_decode_ = 0;
+  frame_to_sync_ = 20;
+  decode_to_layer_before_sync_ = 1;
+  decode_to_layer_after_sync_ = 2;
+
+  // Set up svc layer sync structure.
+  svc_layer_sync_.base_layer_intra_only = 0;
+  svc_layer_sync_.spatial_layer_sync[0] = 0;
+  svc_layer_sync_.spatial_layer_sync[1] = 0;
+  svc_layer_sync_.spatial_layer_sync[2] = 1;
+
+  ::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
+  cfg_.rc_target_bitrate = 600;
+  AssignLayerBitrates();
+  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+#if CONFIG_VP9_DECODER
+  // The non-reference frames are expected to be mismatched frames as the
+  // encoder will avoid loopfilter on these frames.
+  EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
+#endif
+}
+
+// Test for sync layer for 1 pass CBR SVC: 3 spatial layers and
+// 3 temporal layers. Decoding QVGA before sync frame and decode up to
+// HD on and after sync.
+TEST_P(SyncFrameOnePassCbrSvc, OnePassCbrSvc3SL3TLSyncFrameVGAHD) {
+  Set3SpatialLayerConfig();
+  frame_to_start_decode_ = 0;
+  frame_to_sync_ = 20;
+  decode_to_layer_before_sync_ = 0;
+  decode_to_layer_after_sync_ = 2;
+
+  // Set up svc layer sync structure.
+  svc_layer_sync_.base_layer_intra_only = 0;
+  svc_layer_sync_.spatial_layer_sync[0] = 0;
+  svc_layer_sync_.spatial_layer_sync[1] = 1;
+  svc_layer_sync_.spatial_layer_sync[2] = 1;
+
+  ::libvpx_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
+  cfg_.rc_target_bitrate = 600;
+  AssignLayerBitrates();
+  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+#if CONFIG_VP9_DECODER
+  // The non-reference frames are expected to be mismatched frames as the
+  // encoder will avoid loopfilter on these frames.
+  EXPECT_EQ(num_nonref_frames_, GetMismatchFrames());
+#endif
+}
+
 VP9_INSTANTIATE_TEST_CASE(SyncFrameOnePassCbrSvc, ::testing::Range(0, 3));
 
 }  // namespace