diff --git a/common_video/include/video_frame.h b/common_video/include/video_frame.h index 0c145fa322..572a4e4703 100644 --- a/common_video/include/video_frame.h +++ b/common_video/include/video_frame.h @@ -36,14 +36,6 @@ class EncodedImage { void SetEncodeTime(int64_t encode_start_ms, int64_t encode_finish_ms); - // TODO(kthelgason): get rid of this struct as it only has a single member - // remaining. - struct AdaptReason { - AdaptReason() : bw_resolutions_disabled(-1) {} - int bw_resolutions_disabled; // Number of resolutions that are not sent - // due to bandwidth for this frame. - // Or -1 if information is not provided. - }; uint32_t _encodedWidth = 0; uint32_t _encodedHeight = 0; uint32_t _timeStamp = 0; @@ -57,7 +49,6 @@ class EncodedImage { VideoRotation rotation_ = kVideoRotation_0; VideoContentType content_type_ = VideoContentType::UNSPECIFIED; bool _completeFrame = false; - AdaptReason adapt_reason_; int qp_ = -1; // Quantizer value. // When an application indicates non-zero values here, it is taken as an diff --git a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc index 5d6abec76d..ad1003095a 100644 --- a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc +++ b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc @@ -254,8 +254,6 @@ TEST_F(TestVp8Impl, OnEncodedImageReportsInfo) { EXPECT_EQ(kWidth, static_cast(encoded_cb_.encoded_frame_._encodedWidth)); EXPECT_EQ(kHeight, static_cast(encoded_cb_.encoded_frame_._encodedHeight)); - EXPECT_EQ(-1, // Disabled for single stream. - encoded_cb_.encoded_frame_.adapt_reason_.bw_resolutions_disabled); } // We only test the encoder here, since the decoded frame rotation is set based diff --git a/modules/video_coding/codecs/vp8/vp8_impl.cc b/modules/video_coding/codecs/vp8/vp8_impl.cc index ffb8051efc..c52b7cde91 100644 --- a/modules/video_coding/codecs/vp8/vp8_impl.cc +++ b/modules/video_coding/codecs/vp8/vp8_impl.cc @@ -115,15 +115,6 @@ bool ValidSimulcastTemporalLayers(const VideoCodec& codec, int num_streams) { return true; } -int NumStreamsDisabled(const std::vector& streams) { - int num_disabled = 0; - for (bool stream : streams) { - if (!stream) - ++num_disabled; - } - return num_disabled; -} - bool GetGfBoostPercentageFromFieldTrialGroup(int* boost_percentage) { std::string group = webrtc::field_trial::FindFullName(kVp8GfBoostFieldTrial); if (group.empty()) @@ -874,9 +865,6 @@ void VP8EncoderImpl::PopulateCodecSpecific( int VP8EncoderImpl::GetEncodedPartitions( const TemporalLayers::FrameConfig tl_configs[], const VideoFrame& input_image) { - int bw_resolutions_disabled = - (encoders_.size() > 1) ? NumStreamsDisabled(send_stream_) : -1; - int stream_idx = static_cast(encoders_.size()) - 1; int result = WEBRTC_VIDEO_CODEC_OK; for (size_t encoder_idx = 0; encoder_idx < encoders_.size(); @@ -949,9 +937,6 @@ int VP8EncoderImpl::GetEncodedPartitions( codec_.simulcastStream[stream_idx].height; encoded_images_[encoder_idx]._encodedWidth = codec_.simulcastStream[stream_idx].width; - // Report once per frame (lowest stream always sent). - encoded_images_[encoder_idx].adapt_reason_.bw_resolutions_disabled = - (stream_idx == 0) ? bw_resolutions_disabled : -1; int qp_128 = -1; vpx_codec_control(&encoders_[encoder_idx], VP8E_GET_LAST_QUANTIZER, &qp_128); diff --git a/video/send_statistics_proxy.cc b/video/send_statistics_proxy.cc index 71c9348e3a..5325306b3c 100644 --- a/video/send_statistics_proxy.cc +++ b/video/send_statistics_proxy.cc @@ -12,8 +12,7 @@ #include #include -#include -#include +#include #include "common_types.h" // NOLINT(build/include) #include "modules/video_coding/include/video_codec_interface.h" @@ -170,7 +169,9 @@ SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer( fec_byte_counter_(clock, nullptr, true), first_rtcp_stats_time_ms_(-1), first_rtp_stats_time_ms_(-1), - start_stats_(stats) { + start_stats_(stats), + num_streams_(0), + num_pixels_highest_stream_(0) { InitializeBitrateCounters(stats); } @@ -197,7 +198,9 @@ void SendStatisticsProxy::UmaSamplesContainer::InitializeBitrateCounters( } } -void SendStatisticsProxy::UmaSamplesContainer::RemoveOld(int64_t now_ms) { +void SendStatisticsProxy::UmaSamplesContainer::RemoveOld( + int64_t now_ms, + bool* is_limited_in_resolution) { while (!encoded_frames_.empty()) { auto it = encoded_frames_.begin(); if (now_ms - it->second.send_ms < kMaxEncodedFrameWindowMs) @@ -206,14 +209,34 @@ void SendStatisticsProxy::UmaSamplesContainer::RemoveOld(int64_t now_ms) { // Use max per timestamp. sent_width_counter_.Add(it->second.max_width); sent_height_counter_.Add(it->second.max_height); + + // Check number of encoded streams per timestamp. + if (num_streams_ > it->second.max_simulcast_idx) { + *is_limited_in_resolution = false; + if (num_streams_ > 1) { + int disabled_streams = + static_cast(num_streams_ - 1 - it->second.max_simulcast_idx); + // Can be limited in resolution or framerate. + uint32_t pixels = it->second.max_width * it->second.max_height; + bool bw_limited_resolution = + disabled_streams > 0 && pixels < num_pixels_highest_stream_; + bw_limited_frame_counter_.Add(bw_limited_resolution); + if (bw_limited_resolution) { + bw_resolutions_disabled_counter_.Add(disabled_streams); + *is_limited_in_resolution = true; + } + } + } encoded_frames_.erase(it); } } bool SendStatisticsProxy::UmaSamplesContainer::InsertEncodedFrame( - const EncodedImage& encoded_frame) { + const EncodedImage& encoded_frame, + size_t simulcast_idx, + bool* is_limited_in_resolution) { int64_t now_ms = clock_->TimeInMilliseconds(); - RemoveOld(now_ms); + RemoveOld(now_ms, is_limited_in_resolution); if (encoded_frames_.size() > kMaxEncodedFrameMapSize) { encoded_frames_.clear(); } @@ -221,9 +244,10 @@ bool SendStatisticsProxy::UmaSamplesContainer::InsertEncodedFrame( auto it = encoded_frames_.find(encoded_frame._timeStamp); if (it == encoded_frames_.end()) { // First frame with this timestamp. - encoded_frames_.insert(std::make_pair( - encoded_frame._timeStamp, Frame(now_ms, encoded_frame._encodedWidth, - encoded_frame._encodedHeight))); + encoded_frames_.insert( + std::make_pair(encoded_frame._timeStamp, + Frame(now_ms, encoded_frame._encodedWidth, + encoded_frame._encodedHeight, simulcast_idx))); sent_fps_counter_.Add(1); return true; } @@ -232,6 +256,8 @@ bool SendStatisticsProxy::UmaSamplesContainer::InsertEncodedFrame( std::max(it->second.max_width, encoded_frame._encodedWidth); it->second.max_height = std::max(it->second.max_height, encoded_frame._encodedHeight); + it->second.max_simulcast_idx = + std::max(it->second.max_simulcast_idx, simulcast_idx); return false; } @@ -590,6 +616,7 @@ void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms( void SendStatisticsProxy::OnEncoderReconfigured( const VideoEncoderConfig& config, + const std::vector& streams, uint32_t preferred_bitrate_bps) { rtc::CritScope lock(&crit_); stats_.preferred_media_bitrate_bps = preferred_bitrate_bps; @@ -600,6 +627,10 @@ void SendStatisticsProxy::OnEncoderReconfigured( GetUmaPrefix(config.content_type), stats_, clock_)); content_type_ = config.content_type; } + uma_container_->encoded_frames_.clear(); + uma_container_->num_streams_ = streams.size(); + uma_container_->num_pixels_highest_stream_ = + streams.empty() ? 0 : (streams.back().width * streams.back().height); } void SendStatisticsProxy::OnEncodedFrameTimeMeasured( @@ -848,23 +879,6 @@ void SendStatisticsProxy::OnSendEncodedImage( uma_container_->key_frame_counter_.Add(encoded_image._frameType == kVideoFrameKey); - stats_.bw_limited_resolution = - encoded_image.adapt_reason_.bw_resolutions_disabled > 0 || - quality_downscales_ > 0; - - if (quality_downscales_ != -1) { - uma_container_->quality_limited_frame_counter_.Add(quality_downscales_ > 0); - if (quality_downscales_ > 0) - uma_container_->quality_downscales_counter_.Add(quality_downscales_); - } - if (encoded_image.adapt_reason_.bw_resolutions_disabled != -1) { - bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0; - uma_container_->bw_limited_frame_counter_.Add(bw_limited); - if (bw_limited) { - uma_container_->bw_resolutions_disabled_counter_.Add( - encoded_image.adapt_reason_.bw_resolutions_disabled); - } - } if (encoded_image.qp_ != -1) { if (!stats_.qp_sum) @@ -891,8 +905,23 @@ void SendStatisticsProxy::OnSendEncodedImage( } media_byte_rate_tracker_.AddSamples(encoded_image._length); - if (uma_container_->InsertEncodedFrame(encoded_image)) + + // Initialize to current since |is_limited_in_resolution| is only updated + // when an encoded frame is removed from the EncodedFrameMap. + bool is_limited_in_resolution = stats_.bw_limited_resolution; + if (uma_container_->InsertEncodedFrame(encoded_image, simulcast_idx, + &is_limited_in_resolution)) { encoded_frame_rate_tracker_.AddSamples(1); + } + + stats_.bw_limited_resolution = + is_limited_in_resolution || quality_downscales_ > 0; + + if (quality_downscales_ != -1) { + uma_container_->quality_limited_frame_counter_.Add(quality_downscales_ > 0); + if (quality_downscales_ > 0) + uma_container_->quality_downscales_counter_.Add(quality_downscales_); + } } int SendStatisticsProxy::GetSendFrameRate() const { diff --git a/video/send_statistics_proxy.h b/video/send_statistics_proxy.h index 094e78fa71..c90f88ac3d 100644 --- a/video/send_statistics_proxy.h +++ b/video/send_statistics_proxy.h @@ -81,6 +81,7 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, // Used to indicate change in content type, which may require a change in // how stats are collected and set the configured preferred media bitrate. void OnEncoderReconfigured(const VideoEncoderConfig& encoder_config, + const std::vector& streams, uint32_t preferred_bitrate_bps); // Used to update the encoder target rate. @@ -190,12 +191,19 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, } }; struct Frame { - Frame(int64_t send_ms, uint32_t width, uint32_t height) - : send_ms(send_ms), max_width(width), max_height(height) {} + Frame(int64_t send_ms, + uint32_t width, + uint32_t height, + size_t simulcast_idx) + : send_ms(send_ms), + max_width(width), + max_height(height), + max_simulcast_idx(simulcast_idx) {} const int64_t send_ms; // Time when first frame with this timestamp is sent. uint32_t max_width; // Max width with this timestamp. uint32_t max_height; // Max height with this timestamp. + size_t max_simulcast_idx; // Max simulcast index with this timestamp. }; typedef std::map EncodedFrameMap; @@ -247,8 +255,10 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, void InitializeBitrateCounters(const VideoSendStream::Stats& stats); - bool InsertEncodedFrame(const EncodedImage& encoded_frame); - void RemoveOld(int64_t now_ms); + bool InsertEncodedFrame(const EncodedImage& encoded_frame, + size_t simulcast_idx, + bool* is_limited_in_resolution); + void RemoveOld(int64_t now_ms, bool* is_limited_in_resolution); const std::string uma_prefix_; Clock* const clock_; @@ -285,6 +295,8 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, FallbackEncoderInfoDisabled fallback_info_disabled_; ReportBlockStats report_block_stats_; const VideoSendStream::Stats start_stats_; + size_t num_streams_; // Number of configured streams to encoder. + size_t num_pixels_highest_stream_; EncodedFrameMap encoded_frames_; std::map diff --git a/video/send_statistics_proxy_unittest.cc b/video/send_statistics_proxy_unittest.cc index a204a469aa..98ad5668a5 100644 --- a/video/send_statistics_proxy_unittest.cc +++ b/video/send_statistics_proxy_unittest.cc @@ -28,10 +28,12 @@ const uint32_t kFirstRtxSsrc = 18; const uint32_t kSecondRtxSsrc = 43; const uint32_t kFlexFecSsrc = 55; const int kFpsPeriodicIntervalMs = 2000; +const int kPreferredBps = 50000; const int kWidth = 640; const int kHeight = 480; const int kQpIdx0 = 21; const int kQpIdx1 = 39; +const int kRtpClockRateHz = 90000; const CodecSpecificInfo kDefaultCodecInfo = []() { CodecSpecificInfo codec_info; codec_info.codecType = kVideoCodecVP8; @@ -322,12 +324,11 @@ TEST_F(SendStatisticsProxyTest, OnEncodedFrameTimeMeasured) { TEST_F(SendStatisticsProxyTest, OnEncoderReconfiguredChangePreferredBitrate) { VideoSendStream::Stats stats = statistics_proxy_->GetStats(); EXPECT_EQ(0, stats.preferred_media_bitrate_bps); - const int kPreferredMediaBitrateBps = 50; VideoEncoderConfig config; - statistics_proxy_->OnEncoderReconfigured(config, kPreferredMediaBitrateBps); + statistics_proxy_->OnEncoderReconfigured(config, {}, kPreferredBps); stats = statistics_proxy_->GetStats(); - EXPECT_EQ(kPreferredMediaBitrateBps, stats.preferred_media_bitrate_bps); + EXPECT_EQ(kPreferredBps, stats.preferred_media_bitrate_bps); } TEST_F(SendStatisticsProxyTest, OnSendEncodedImageIncreasesFramesEncoded) { @@ -753,7 +754,7 @@ TEST_F(SendStatisticsProxyTest, AdaptChangesReportedAfterContentSwitch) { // Switch content type, real-time stats should be updated. VideoEncoderConfig config; config.content_type = VideoEncoderConfig::ContentType::kScreen; - statistics_proxy_->OnEncoderReconfigured(config, 50); + statistics_proxy_->OnEncoderReconfigured(config, {}, kPreferredBps); EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu")); EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 8)); EXPECT_EQ(0, @@ -786,12 +787,12 @@ TEST_F(SendStatisticsProxyTest, SwitchContentTypeUpdatesHistograms) { // No switch, stats should not be updated. VideoEncoderConfig config; config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo; - statistics_proxy_->OnEncoderReconfigured(config, 50); + statistics_proxy_->OnEncoderReconfigured(config, {}, kPreferredBps); EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.InputWidthInPixels")); // Switch to screenshare, real-time stats should be updated. config.content_type = VideoEncoderConfig::ContentType::kScreen; - statistics_proxy_->OnEncoderReconfigured(config, 50); + statistics_proxy_->OnEncoderReconfigured(config, {}, kPreferredBps); EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputWidthInPixels")); } @@ -1179,11 +1180,30 @@ TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_H264) { } TEST_F(SendStatisticsProxyTest, - BandwidthLimitedHistogramsNotUpdatedWhenDisabled) { + BandwidthLimitedHistogramsNotUpdatedForOneStream) { + // Configure one stream. + VideoEncoderConfig config; + config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo; + VideoStream stream1; + stream1.width = kWidth; + stream1.height = kHeight; + statistics_proxy_->OnEncoderReconfigured(config, {stream1}, kPreferredBps); + + const int64_t kMaxEncodedFrameWindowMs = 800; + const int kFps = 20; + const int kNumFramesPerWindow = kFps * kMaxEncodedFrameWindowMs / 1000; + const int kMinSamples = // Sample added when removed from EncodedFrameMap. + SendStatisticsProxy::kMinRequiredMetricsSamples + kNumFramesPerWindow; + + // Stream encoded. EncodedImage encoded_image; - // encoded_image.adapt_reason_.bw_resolutions_disabled by default: -1 - for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) + encoded_image._encodedWidth = kWidth; + encoded_image._encodedHeight = kHeight; + for (int i = 0; i < kMinSamples; ++i) { + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + encoded_image._timeStamp += (kRtpClockRateHz / kFps); statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); + } // Histograms are updated when the statistics_proxy_ is deleted. statistics_proxy_.reset(); @@ -1194,12 +1214,37 @@ TEST_F(SendStatisticsProxyTest, } TEST_F(SendStatisticsProxyTest, - BandwidthLimitedHistogramsUpdatedWhenEnabled_NoResolutionDisabled) { - const int kResolutionsDisabled = 0; + BandwidthLimitedHistogramsUpdatedForTwoStreams_NoResolutionDisabled) { + // Configure two streams. + VideoEncoderConfig config; + config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo; + VideoStream stream1; + stream1.width = kWidth / 2; + stream1.height = kHeight / 2; + VideoStream stream2; + stream2.width = kWidth; + stream2.height = kHeight; + statistics_proxy_->OnEncoderReconfigured(config, {stream1, stream2}, + kPreferredBps); + + const int64_t kMaxEncodedFrameWindowMs = 800; + const int kFps = 20; + const int kNumFramesPerWindow = kFps * kMaxEncodedFrameWindowMs / 1000; + const int kMinSamples = // Sample added when removed from EncodedFrameMap. + SendStatisticsProxy::kMinRequiredMetricsSamples + kNumFramesPerWindow; + + // Two streams encoded. EncodedImage encoded_image; - encoded_image.adapt_reason_.bw_resolutions_disabled = kResolutionsDisabled; - for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) + for (int i = 0; i < kMinSamples; ++i) { + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + encoded_image._timeStamp += (kRtpClockRateHz / kFps); + encoded_image._encodedWidth = kWidth; + encoded_image._encodedHeight = kHeight; statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); + encoded_image._encodedWidth = kWidth / 2; + encoded_image._encodedHeight = kHeight / 2; + statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); + } // Histograms are updated when the statistics_proxy_ is deleted. statistics_proxy_.reset(); @@ -1213,12 +1258,34 @@ TEST_F(SendStatisticsProxyTest, } TEST_F(SendStatisticsProxyTest, - BandwidthLimitedHistogramsUpdatedWhenEnabled_OneResolutionDisabled) { - const int kResolutionsDisabled = 1; + BandwidthLimitedHistogramsUpdatedForTwoStreams_OneResolutionDisabled) { + // Configure two streams. + VideoEncoderConfig config; + config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo; + VideoStream stream1; + stream1.width = kWidth / 2; + stream1.height = kHeight / 2; + VideoStream stream2; + stream2.width = kWidth; + stream2.height = kHeight; + statistics_proxy_->OnEncoderReconfigured(config, {stream1, stream2}, + kPreferredBps); + + const int64_t kMaxEncodedFrameWindowMs = 800; + const int kFps = 20; + const int kNumFramesPerWindow = kFps * kMaxEncodedFrameWindowMs / 1000; + const int kMinSamples = // Sample added when removed from EncodedFrameMap. + SendStatisticsProxy::kMinRequiredMetricsSamples + kNumFramesPerWindow; + + // One stream encoded. EncodedImage encoded_image; - encoded_image.adapt_reason_.bw_resolutions_disabled = kResolutionsDisabled; - for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) + encoded_image._encodedWidth = kWidth / 2; + encoded_image._encodedHeight = kHeight / 2; + for (int i = 0; i < kMinSamples; ++i) { + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + encoded_image._timeStamp += (kRtpClockRateHz / kFps); statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); + } // Histograms are updated when the statistics_proxy_ is deleted. statistics_proxy_.reset(); @@ -1226,12 +1293,11 @@ TEST_F(SendStatisticsProxyTest, "WebRTC.Video.BandwidthLimitedResolutionInPercent")); EXPECT_EQ(1, metrics::NumEvents( "WebRTC.Video.BandwidthLimitedResolutionInPercent", 100)); - // Resolutions disabled. + // One resolution disabled. EXPECT_EQ(1, metrics::NumSamples( "WebRTC.Video.BandwidthLimitedResolutionsDisabled")); - EXPECT_EQ( - 1, metrics::NumEvents("WebRTC.Video.BandwidthLimitedResolutionsDisabled", - kResolutionsDisabled)); + EXPECT_EQ(1, metrics::NumEvents( + "WebRTC.Video.BandwidthLimitedResolutionsDisabled", 1)); } TEST_F(SendStatisticsProxyTest, @@ -1300,17 +1366,58 @@ TEST_F(SendStatisticsProxyTest, TEST_F(SendStatisticsProxyTest, GetStatsReportsBandwidthLimitedResolution) { // Initially false. EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); - // No resolution scale by default. - EncodedImage encoded_image; - statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); - EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); - // Simulcast disabled resolutions - encoded_image.adapt_reason_.bw_resolutions_disabled = 1; + // Configure two streams. + VideoEncoderConfig config; + config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo; + VideoStream stream1; + stream1.width = kWidth / 2; + stream1.height = kHeight / 2; + VideoStream stream2; + stream2.width = kWidth; + stream2.height = kHeight; + statistics_proxy_->OnEncoderReconfigured(config, {stream1, stream2}, + kPreferredBps); + + const int64_t kMaxEncodedFrameWindowMs = 800; + const int kFps = 20; + const int kMinSamples = // Sample added when removed from EncodedFrameMap. + kFps * kMaxEncodedFrameWindowMs / 1000; + + // One stream encoded. + EncodedImage encoded_image; + encoded_image._encodedWidth = kWidth / 2; + encoded_image._encodedHeight = kHeight / 2; + for (int i = 0; i < kMinSamples; ++i) { + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + encoded_image._timeStamp += (kRtpClockRateHz / kFps); + statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); + EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); + } + + // First frame removed from EncodedFrameMap, stats updated. + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + ++encoded_image._timeStamp; statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution); - encoded_image.adapt_reason_.bw_resolutions_disabled = 0; + // Two streams encoded. + for (int i = 0; i < kMinSamples; ++i) { + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + encoded_image._timeStamp += (kRtpClockRateHz / kFps); + encoded_image._encodedWidth = kWidth; + encoded_image._encodedHeight = kHeight; + statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); + EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution); + encoded_image._encodedWidth = kWidth / 2; + encoded_image._encodedHeight = kHeight / 2; + statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); + EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution); + } + + // First frame with two streams removed, expect no resolution limit. + fake_clock_.AdvanceTimeMilliseconds(1000 / kFps); + encoded_image._timeStamp += (kRtpClockRateHz / kFps); statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr); EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution); @@ -1473,7 +1580,7 @@ TEST_F(SendStatisticsProxyTest, ResetsRtcpCountersOnContentChange) { // Changing content type causes histograms to be reported. VideoEncoderConfig config; config.content_type = VideoEncoderConfig::ContentType::kScreen; - statistics_proxy_->OnEncoderReconfigured(config, 50); + statistics_proxy_->OnEncoderReconfigured(config, {}, kPreferredBps); EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.NackPacketsReceivedPerMinute")); @@ -1637,7 +1744,7 @@ TEST_F(SendStatisticsProxyTest, ResetsRtpCountersOnContentChange) { // Changing content type causes histograms to be reported. VideoEncoderConfig config; config.content_type = VideoEncoderConfig::ContentType::kScreen; - statistics_proxy_->OnEncoderReconfigured(config, 50000); + statistics_proxy_->OnEncoderReconfigured(config, {}, kPreferredBps); // Interval: 3500 bytes * 4 / 2 sec = 7000 bytes / sec = 56 kbps EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.BitrateSentInKbps")); diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc index 92b8856b68..94360eb182 100644 --- a/video/video_stream_encoder.cc +++ b/video/video_stream_encoder.cc @@ -616,7 +616,7 @@ void VideoStreamEncoder::ReconfigureEncoder() { if (current_framerate == 0) current_framerate = codec.maxFramerate; stats_proxy_->OnEncoderReconfigured( - encoder_config_, + encoder_config_, streams, rate_allocator_.get() ? rate_allocator_->GetPreferredBitrateBps(current_framerate) : codec.maxBitrate);