diff --git a/test/fake_encoder.cc b/test/fake_encoder.cc index 10b25a4598..4ff092691e 100644 --- a/test/fake_encoder.cc +++ b/test/fake_encoder.cc @@ -151,6 +151,7 @@ int32_t FakeEncoder::Encode(const VideoFrame& input_image, if (qp) encoded.qp_ = *qp; encoded.SetSimulcastIndex(i); + encoded.SetTemporalIndex(frame_info.layers[i].temporal_id); CodecSpecificInfo codec_specific = EncodeHook(encoded, buffer); if (callback->OnEncodedImage(encoded, &codec_specific).error != diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc index 250edc16b3..3f958de241 100644 --- a/video/video_stream_encoder.cc +++ b/video/video_stream_encoder.cc @@ -2168,7 +2168,10 @@ EncodedImageCallback::Result VideoStreamEncoder::OnEncodedImage( image_copy.ClearEncodedData(); int temporal_index = 0; - if (codec_specific_info) { + if (encoded_image.TemporalIndex()) { + // Give precedence to the metadata on EncodedImage, if available. + temporal_index = *encoded_image.TemporalIndex(); + } else if (codec_specific_info) { if (codec_specific_info->codecType == kVideoCodecVP9) { temporal_index = codec_specific_info->codecSpecific.VP9.temporal_idx; } else if (codec_specific_info->codecType == kVideoCodecVP8) { @@ -2412,8 +2415,8 @@ void VideoStreamEncoder::RunPostEncode(const EncodedImage& encoded_image, // TODO(https://crbug.com/webrtc/14891): If we want to support a mix of // simulcast and SVC we'll also need to consider the case where we have both // simulcast and spatial indices. - int stream_index = encoded_image.SpatialIndex().value_or( - encoded_image.SimulcastIndex().value_or(0)); + int stream_index = std::max(encoded_image.SimulcastIndex().value_or(0), + encoded_image.SpatialIndex().value_or(0)); bitrate_adjuster_->OnEncodedFrame(frame_size, stream_index, temporal_index); } } diff --git a/video/video_stream_encoder_unittest.cc b/video/video_stream_encoder_unittest.cc index df620cf5c0..f41a51e0d0 100644 --- a/video/video_stream_encoder_unittest.cc +++ b/video/video_stream_encoder_unittest.cc @@ -76,6 +76,7 @@ #include "test/video_encoder_proxy_factory.h" #include "video/config/encoder_stream_factory.h" #include "video/config/video_encoder_config.h" +#include "video/encoder_bitrate_adjuster.h" #include "video/frame_cadence_adapter.h" #include "video/send_statistics_proxy.h" @@ -2583,6 +2584,58 @@ TEST_F(VideoStreamEncoderTest, video_stream_encoder_->Stop(); } +TEST_F(VideoStreamEncoderTest, CorrectlyAdjustsAv1Bitrate) { + ResetEncoder("AV1", /*num_streams*/ 2, /*num_temporal_layers=*/2, + /*num_spatial_layers=*/1, /*screenshare*/ false, + kDefaultFramerate, + VideoStreamEncoder::BitrateAllocationCallbackType:: + kVideoLayersAllocation); + + // Let link allocation and stable bitrate be 2x the target bitrate. + video_stream_encoder_->OnBitrateUpdatedAndWaitForManagedResources( + kTargetBitrate, 2 * kTargetBitrate, 2 * kTargetBitrate, 0, 0, 0); + + video_source_.IncomingCapturedFrame( + CreateFrame(CurrentTimeMs(), codec_width_, codec_height_)); + WaitForEncodedFrame(CurrentTimeMs()); + + // Before enough data has been gathered, some default pushback is applied. + VideoEncoder::RateControlParameters rate_settings = + *fake_encoder_.GetAndResetLastRateControlSettings(); + // Allow 5% diff from target bitrate. + const double allowed_error_bps = + rate_settings.target_bitrate.get_sum_bps() * 0.05; + EXPECT_NEAR(rate_settings.bitrate.get_sum_bps(), + rate_settings.target_bitrate.get_sum_bps() / + EncoderBitrateAdjuster::kDefaultUtilizationFactor, + allowed_error_bps); + + // Insert frames until bitrate adjuster is saturated. + const TimeDelta runtime = + TimeDelta::Millis(EncoderBitrateAdjuster::kWindowSizeMs); + const Timestamp start_time = clock()->CurrentTime(); + while (clock()->CurrentTime() - start_time < runtime) { + video_source_.IncomingCapturedFrame( + CreateFrame(CurrentTimeMs(), codec_width_, codec_height_)); + WaitForEncodedFrame(CurrentTimeMs()); + } + + // Make sure rate has been reallocated. + video_stream_encoder_->OnBitrateUpdatedAndWaitForManagedResources( + kTargetBitrate - DataRate::BitsPerSec(500), 2 * kTargetBitrate, + 2 * kTargetBitrate, 0, 0, 0); + video_source_.IncomingCapturedFrame( + CreateFrame(CurrentTimeMs(), codec_width_, codec_height_)); + WaitForEncodedFrame(CurrentTimeMs()); + + // Pushback should no longer happen. + rate_settings = *fake_encoder_.GetAndResetLastRateControlSettings(); + EXPECT_NEAR(rate_settings.bitrate.get_sum_bps(), + rate_settings.target_bitrate.get_sum_bps(), allowed_error_bps); + + video_stream_encoder_->Stop(); +} + class ResolutionAlignmentTest : public VideoStreamEncoderTest, public ::testing::WithParamInterface<