Fix for VP9 K-SVC video freeze frame when send bandwidth is restricted.

Added distinction between number of configured and number of actively
encoded spatial layers and include number of actively encoded spatial
layers in ssData.  Modified layer_filtering_transport.cc test to
parse from the RTP header and use the number of actively encoded
spatial layers for filtering spatial video layers.

Bug: webrtc:9425
Change-Id: Ic9f8895ab08b0626f9bb53a75ec33d8e7eb8706e
Reviewed-on: https://webrtc-review.googlesource.com/84243
Commit-Queue: Michael Horowitz <mhoro@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23716}
diff --git a/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc b/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
index 5eb2447..c56bacf 100644
--- a/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
+++ b/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc
@@ -310,7 +310,7 @@
             encoder_->Encode(*NextInputFrame(), nullptr, nullptr));
 
   ASSERT_TRUE(WaitForEncodedFrames(&frames, &codec_specific));
-  EXPECT_EQ(codec_specific[0].codecSpecific.VP9.spatial_idx, 0);
+  EXPECT_EQ(codec_specific[0].codecSpecific.VP9.spatial_idx, kNoSpatialIdx);
   EXPECT_TRUE(codec_specific[0].codecSpecific.VP9.end_of_picture);
 }
 
diff --git a/modules/video_coding/codecs/vp9/vp9_impl.cc b/modules/video_coding/codecs/vp9/vp9_impl.cc
index 24f86aa..6fffdab 100644
--- a/modules/video_coding/codecs/vp9/vp9_impl.cc
+++ b/modules/video_coding/codecs/vp9/vp9_impl.cc
@@ -134,6 +134,12 @@
 
   config_->rc_target_bitrate = bitrate_allocation.get_sum_kbps();
 
+  num_active_spatial_layers_ = 0;
+  for (i = 0; i < num_spatial_layers_; ++i)
+    num_active_spatial_layers_ += bitrate_allocation.IsSpatialLayerUsed(i);
+  RTC_DCHECK_GT(num_active_spatial_layers_, 0);
+  RTC_DCHECK_LE(num_active_spatial_layers_, num_spatial_layers_);
+
   if (ExplicitlyConfiguredSpatialLayers()) {
     for (size_t sl_idx = 0; sl_idx < num_spatial_layers_; ++sl_idx) {
       const bool was_layer_enabled = (config_->ss_target_bitrate[sl_idx] > 0);
@@ -157,8 +163,7 @@
   } else {
     float rate_ratio[VPX_MAX_LAYERS] = {0};
     float total = 0;
-
-    for (i = 0; i < num_spatial_layers_; ++i) {
+    for (i = 0; i < num_active_spatial_layers_; ++i) {
       if (svc_params_.scaling_factor_num[i] <= 0 ||
           svc_params_.scaling_factor_den[i] <= 0) {
         RTC_LOG(LS_ERROR) << "Scaling factors not specified!";
@@ -169,7 +174,7 @@
       total += rate_ratio[i];
     }
 
-    for (i = 0; i < num_spatial_layers_; ++i) {
+    for (i = 0; i < num_active_spatial_layers_; ++i) {
       config_->ss_target_bitrate[i] = static_cast<unsigned int>(
           config_->rc_target_bitrate * rate_ratio[i] / total);
       if (num_temporal_layers_ == 1) {
@@ -645,14 +650,14 @@
   vpx_codec_control(encoder_, VP9E_GET_SVC_LAYER_ID, &layer_id);
 
   RTC_CHECK_GT(num_temporal_layers_, 0);
-  RTC_CHECK_GT(num_spatial_layers_, 0);
+  RTC_CHECK_GT(num_active_spatial_layers_, 0);
   if (num_temporal_layers_ == 1) {
     RTC_CHECK_EQ(layer_id.temporal_layer_id, 0);
     vp9_info->temporal_idx = kNoTemporalIdx;
   } else {
     vp9_info->temporal_idx = layer_id.temporal_layer_id;
   }
-  if (num_spatial_layers_ == 1) {
+  if (num_active_spatial_layers_ == 1) {
     RTC_CHECK_EQ(layer_id.spatial_layer_id, 0);
     vp9_info->spatial_idx = kNoSpatialIdx;
   } else {
@@ -686,13 +691,13 @@
       first_frame_in_picture ? false : is_inter_layer_pred_allowed;
 
   const bool is_last_layer =
-      (layer_id.spatial_layer_id + 1 == num_spatial_layers_);
+      (layer_id.spatial_layer_id + 1 == num_active_spatial_layers_);
   vp9_info->non_ref_for_inter_layer_pred =
       is_last_layer ? true : !is_inter_layer_pred_allowed;
 
   // Always populate this, so that the packetizer can properly set the marker
   // bit.
-  vp9_info->num_spatial_layers = num_spatial_layers_;
+  vp9_info->num_spatial_layers = num_active_spatial_layers_;
 
   RTC_DCHECK(!vp9_info->flexible_mode);
 
@@ -710,11 +715,9 @@
 
   vp9_info->inter_pic_predicted = (!is_key_pic && vp9_info->num_ref_pics > 0);
 
-  vp9_info->num_spatial_layers = num_spatial_layers_;
-
   if (vp9_info->ss_data_available) {
     vp9_info->spatial_layer_resolution_present = true;
-    for (size_t i = 0; i < vp9_info->num_spatial_layers; ++i) {
+    for (size_t i = 0; i < num_active_spatial_layers_; ++i) {
       vp9_info->width[i] = codec_.width * svc_params_.scaling_factor_num[i] /
                            svc_params_.scaling_factor_den[i];
       vp9_info->height[i] = codec_.height * svc_params_.scaling_factor_num[i] /
diff --git a/modules/video_coding/codecs/vp9/vp9_impl.h b/modules/video_coding/codecs/vp9/vp9_impl.h
index 53ed671..5cf09a3 100644
--- a/modules/video_coding/codecs/vp9/vp9_impl.h
+++ b/modules/video_coding/codecs/vp9/vp9_impl.h
@@ -108,7 +108,8 @@
   bool force_key_frame_;
   size_t pics_since_key_;
   uint8_t num_temporal_layers_;
-  uint8_t num_spatial_layers_;
+  uint8_t num_spatial_layers_;         // Number of configured SLs
+  uint8_t num_active_spatial_layers_;  // Number of actively encoded SLs
   bool is_svc_;
   InterLayerPredMode inter_layer_pred_;
 
diff --git a/test/layer_filtering_transport.cc b/test/layer_filtering_transport.cc
index 8073dfa..723eda8 100644
--- a/test/layer_filtering_transport.cc
+++ b/test/layer_filtering_transport.cc
@@ -145,7 +145,20 @@
           is_vp8 ? false
                  : parsed_payload.type.Video.codecHeader.VP9
                        .non_ref_for_inter_layer_pred;
-      if (selected_sl_ >= 0 && spatial_idx == selected_sl_ &&
+      // The number of spatial layers is sent in ssData, which is included only
+      // in the first packet of the first spatial layer of a key frame.
+      if (!parsed_payload.type.Video.codecHeader.VP9.inter_pic_predicted &&
+          parsed_payload.type.Video.codecHeader.VP9.beginning_of_frame == 1 &&
+          spatial_idx == 0) {
+        num_active_spatial_layers_ =
+            parsed_payload.type.Video.codecHeader.VP9.num_spatial_layers;
+      } else if (spatial_idx == kNoSpatialIdx)
+        num_active_spatial_layers_ = 1;
+      RTC_CHECK_GT(num_active_spatial_layers_, 0);
+
+      if (selected_sl_ >= 0 &&
+          spatial_idx ==
+              std::min(num_active_spatial_layers_ - 1, selected_sl_) &&
           parsed_payload.type.Video.codecHeader.VP9.end_of_frame) {
         // This layer is now the last in the superframe.
         set_marker_bit = true;
@@ -162,7 +175,9 @@
         // needed for decoding of target spatial layer.
         const bool lower_non_ref_spatial_layer =
             (selected_sl_ >= 0 && spatial_idx != kNoSpatialIdx &&
-             spatial_idx < selected_sl_ && non_ref_for_inter_layer_pred);
+             spatial_idx <
+                 std::min(num_active_spatial_layers_ - 1, selected_sl_) &&
+             non_ref_for_inter_layer_pred);
 
         if (higher_temporal_layer || higher_spatial_layer ||
             lower_non_ref_spatial_layer) {
diff --git a/test/layer_filtering_transport.h b/test/layer_filtering_transport.h
index 8835b89..bd5f2e8 100644
--- a/test/layer_filtering_transport.h
+++ b/test/layer_filtering_transport.h
@@ -73,6 +73,7 @@
   const int selected_tl_;
   const int selected_sl_;
   bool discarded_last_packet_;
+  int num_active_spatial_layers_;
   const uint32_t ssrc_to_filter_min_;
   const uint32_t ssrc_to_filter_max_;
 };