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 5eb2447342..c56bacf377 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 @@ TEST_F(TestVp9Impl, EndOfPicture) { 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 24f86aae98..6fffdabb73 100644 --- a/modules/video_coding/codecs/vp9/vp9_impl.cc +++ b/modules/video_coding/codecs/vp9/vp9_impl.cc @@ -134,6 +134,12 @@ bool VP9EncoderImpl::SetSvcRates( 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 @@ bool VP9EncoderImpl::SetSvcRates( } 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 @@ bool VP9EncoderImpl::SetSvcRates( 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( config_->rc_target_bitrate * rate_ratio[i] / total); if (num_temporal_layers_ == 1) { @@ -645,14 +650,14 @@ void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, 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 @@ void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, 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 @@ void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, 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 53ed671768..5cf09a3645 100644 --- a/modules/video_coding/codecs/vp9/vp9_impl.h +++ b/modules/video_coding/codecs/vp9/vp9_impl.h @@ -108,7 +108,8 @@ class VP9EncoderImpl : public VP9Encoder { 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 8073dfa8ed..723eda8903 100644 --- a/test/layer_filtering_transport.cc +++ b/test/layer_filtering_transport.cc @@ -145,7 +145,20 @@ bool LayerFilteringTransport::SendRtp(const uint8_t* packet, 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 @@ bool LayerFilteringTransport::SendRtp(const uint8_t* packet, // 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 8835b89463..bd5f2e8ab9 100644 --- a/test/layer_filtering_transport.h +++ b/test/layer_filtering_transport.h @@ -73,6 +73,7 @@ class LayerFilteringTransport : public test::DirectTransport { 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_; };