diff options
author | Henrik Boström <hbos@webrtc.org> | 2020-04-29 16:46:30 +0200 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-04-29 15:59:14 +0000 |
commit | 722fa4d50924ba35bd5bf76283222c43af23cdab (patch) | |
tree | 1dc9df71498230a874c824403bce31a81e90bc21 | |
parent | bb826c9142e370574335a0529d45cd4a6b3a0c19 (diff) | |
download | webrtc-722fa4d50924ba35bd5bf76283222c43af23cdab.tar.gz |
[Adaptation] Misc tests for processor, input provider and restrictions.
This CL adds miscellaneous unit tests for the
ResourceAdaptationProcessor, the VideoSourceRestrictions comparators and
the VideoStreamInputStateProvider.
Bug: webrtc:11172
Change-Id: If95f69644aaf2b43e3b19d5729bedef0b438c77b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/174101
Reviewed-by: Evan Shrubsole <eshr@google.com>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#31147}
-rw-r--r-- | call/adaptation/BUILD.gn | 7 | ||||
-rw-r--r-- | call/adaptation/resource_adaptation_processor_unittest.cc | 257 | ||||
-rw-r--r-- | call/adaptation/test/fake_frame_rate_provider.cc | 27 | ||||
-rw-r--r-- | call/adaptation/test/fake_frame_rate_provider.h | 57 | ||||
-rw-r--r-- | call/adaptation/test/fake_resource.cc | 29 | ||||
-rw-r--r-- | call/adaptation/test/fake_resource.h | 13 | ||||
-rw-r--r-- | call/adaptation/video_source_restrictions_unittest.cc | 73 | ||||
-rw-r--r-- | call/adaptation/video_stream_adapter.cc | 7 | ||||
-rw-r--r-- | call/adaptation/video_stream_input_state.cc | 10 | ||||
-rw-r--r-- | call/adaptation/video_stream_input_state.h | 6 | ||||
-rw-r--r-- | call/adaptation/video_stream_input_state_provider.cc | 3 | ||||
-rw-r--r-- | call/adaptation/video_stream_input_state_provider_unittest.cc | 53 | ||||
-rw-r--r-- | video/adaptation/quality_scaler_resource.cc | 4 | ||||
-rw-r--r-- | video/adaptation/video_stream_encoder_resource_manager.h | 3 |
14 files changed, 531 insertions, 18 deletions
diff --git a/call/adaptation/BUILD.gn b/call/adaptation/BUILD.gn index 94656cf0a9..deac3156d6 100644 --- a/call/adaptation/BUILD.gn +++ b/call/adaptation/BUILD.gn @@ -47,8 +47,11 @@ if (rtc_include_tests) { testonly = true sources = [ + "resource_adaptation_processor_unittest.cc", "resource_unittest.cc", + "video_source_restrictions_unittest.cc", "video_stream_adapter_unittest.cc", + "video_stream_input_state_provider_unittest.cc", ] deps = [ ":resource_adaptation", @@ -68,12 +71,16 @@ if (rtc_include_tests) { testonly = true sources = [ + "test/fake_frame_rate_provider.cc", + "test/fake_frame_rate_provider.h", "test/fake_resource.cc", "test/fake_resource.h", ] deps = [ ":resource_adaptation", + "../../api/video:video_stream_encoder", "../../rtc_base:rtc_base_approved", + "../../test:test_support", ] } } diff --git a/call/adaptation/resource_adaptation_processor_unittest.cc b/call/adaptation/resource_adaptation_processor_unittest.cc new file mode 100644 index 0000000000..2e26dbec72 --- /dev/null +++ b/call/adaptation/resource_adaptation_processor_unittest.cc @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "call/adaptation/resource_adaptation_processor.h" + +#include "api/video/video_adaptation_counters.h" +#include "call/adaptation/resource.h" +#include "call/adaptation/resource_adaptation_processor_interface.h" +#include "call/adaptation/test/fake_frame_rate_provider.h" +#include "call/adaptation/test/fake_resource.h" +#include "call/adaptation/video_source_restrictions.h" +#include "call/adaptation/video_stream_input_state_provider.h" +#include "test/gtest.h" + +namespace webrtc { + +namespace { + +const int kDefaultFrameRate = 30; +const int kDefaultFrameSize = 1280 * 720; + +class ResourceAdaptationProcessorListenerForTesting + : public ResourceAdaptationProcessorListener { + public: + ResourceAdaptationProcessorListenerForTesting() + : restrictions_updated_count_(0), + restrictions_(), + adaptation_counters_(), + reason_(nullptr) {} + ~ResourceAdaptationProcessorListenerForTesting() override {} + + size_t restrictions_updated_count() const { + return restrictions_updated_count_; + } + const VideoSourceRestrictions& restrictions() const { return restrictions_; } + const VideoAdaptationCounters& adaptation_counters() const { + return adaptation_counters_; + } + const Resource* reason() const { return reason_; } + + // ResourceAdaptationProcessorListener implementation. + void OnVideoSourceRestrictionsUpdated( + VideoSourceRestrictions restrictions, + const VideoAdaptationCounters& adaptation_counters, + const Resource* reason) override { + ++restrictions_updated_count_; + restrictions_ = restrictions; + adaptation_counters_ = adaptation_counters; + reason_ = reason; + } + + private: + size_t restrictions_updated_count_; + VideoSourceRestrictions restrictions_; + VideoAdaptationCounters adaptation_counters_; + const Resource* reason_; +}; + +class ResourceAdaptationProcessorTest : public ::testing::Test { + public: + ResourceAdaptationProcessorTest() + : frame_rate_provider_(), + input_state_provider_(&frame_rate_provider_), + resource_("FakeResource"), + processor_(&input_state_provider_, + /*encoder_stats_observer=*/&frame_rate_provider_) { + processor_.AddAdaptationListener(&processor_listener_); + processor_.AddResource(&resource_); + } + ~ResourceAdaptationProcessorTest() override { + processor_.StopResourceAdaptation(); + } + + void SetInputStates(bool has_input, int fps, int frame_size) { + input_state_provider_.OnHasInputChanged(has_input); + frame_rate_provider_.set_fps(fps); + input_state_provider_.OnFrameSizeObserved(frame_size); + } + + void RestrictSource(VideoSourceRestrictions restrictions) { + SetInputStates( + true, restrictions.max_frame_rate().value_or(kDefaultFrameRate), + restrictions.target_pixels_per_frame().has_value() + ? restrictions.target_pixels_per_frame().value() + : restrictions.max_pixels_per_frame().value_or(kDefaultFrameSize)); + } + + protected: + FakeFrameRateProvider frame_rate_provider_; + VideoStreamInputStateProvider input_state_provider_; + FakeResource resource_; + ResourceAdaptationProcessor processor_; + ResourceAdaptationProcessorListenerForTesting processor_listener_; +}; + +} // namespace + +TEST_F(ResourceAdaptationProcessorTest, DisabledByDefault) { + EXPECT_EQ(DegradationPreference::DISABLED, + processor_.degradation_preference()); + EXPECT_EQ(DegradationPreference::DISABLED, + processor_.effective_degradation_preference()); + SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); + processor_.StartResourceAdaptation(); + // Adaptation does not happen when disabled. + resource_.set_usage_state(ResourceUsageState::kOveruse); + EXPECT_EQ(0u, processor_listener_.restrictions_updated_count()); +} + +TEST_F(ResourceAdaptationProcessorTest, InsufficientInput) { + processor_.SetDegradationPreference( + DegradationPreference::MAINTAIN_FRAMERATE); + processor_.StartResourceAdaptation(); + // Adaptation does not happen if input is insufficient. + // When frame size is missing (OnFrameSizeObserved not called yet). + input_state_provider_.OnHasInputChanged(true); + resource_.set_usage_state(ResourceUsageState::kOveruse); + EXPECT_EQ(0u, processor_listener_.restrictions_updated_count()); + // When "has input" is missing. + SetInputStates(false, kDefaultFrameRate, kDefaultFrameSize); + resource_.set_usage_state(ResourceUsageState::kOveruse); + EXPECT_EQ(0u, processor_listener_.restrictions_updated_count()); + // Note: frame rate cannot be missing, if unset it is 0. +} + +// These tests verify that restrictions are applied, but not exactly how much +// the source is restricted. This ensures that the VideoStreamAdapter is wired +// up correctly but not exactly how the VideoStreamAdapter generates +// restrictions. For that, see video_stream_adapter_unittest.cc. +TEST_F(ResourceAdaptationProcessorTest, + OveruseTriggersRestrictingResolutionInMaintainFrameRate) { + processor_.SetDegradationPreference( + DegradationPreference::MAINTAIN_FRAMERATE); + processor_.StartResourceAdaptation(); + SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); + resource_.set_usage_state(ResourceUsageState::kOveruse); + EXPECT_EQ(1u, processor_listener_.restrictions_updated_count()); + EXPECT_TRUE( + processor_listener_.restrictions().max_pixels_per_frame().has_value()); +} + +TEST_F(ResourceAdaptationProcessorTest, + OveruseTriggersRestrictingFrameRateInMaintainResolution) { + processor_.SetDegradationPreference( + DegradationPreference::MAINTAIN_RESOLUTION); + processor_.StartResourceAdaptation(); + SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); + resource_.set_usage_state(ResourceUsageState::kOveruse); + EXPECT_EQ(1u, processor_listener_.restrictions_updated_count()); + EXPECT_TRUE(processor_listener_.restrictions().max_frame_rate().has_value()); +} + +TEST_F(ResourceAdaptationProcessorTest, + OveruseTriggersRestrictingFrameRateAndResolutionInBalanced) { + processor_.SetDegradationPreference(DegradationPreference::BALANCED); + processor_.StartResourceAdaptation(); + SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); + // Adapting multiple times eventually resticts both frame rate and resolution. + // Exactly many times we need to adapt depends on BalancedDegradationSettings, + // VideoStreamAdapter and default input states. This test requires it to be + // achieved within 4 adaptations. + for (size_t i = 0; i < 4; ++i) { + resource_.set_usage_state(ResourceUsageState::kOveruse); + EXPECT_EQ(i + 1, processor_listener_.restrictions_updated_count()); + RestrictSource(processor_listener_.restrictions()); + } + EXPECT_TRUE( + processor_listener_.restrictions().max_pixels_per_frame().has_value()); + EXPECT_TRUE(processor_listener_.restrictions().max_frame_rate().has_value()); +} + +TEST_F(ResourceAdaptationProcessorTest, AwaitingPreviousAdaptation) { + processor_.SetDegradationPreference( + DegradationPreference::MAINTAIN_FRAMERATE); + processor_.StartResourceAdaptation(); + SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); + resource_.set_usage_state(ResourceUsageState::kOveruse); + EXPECT_EQ(1u, processor_listener_.restrictions_updated_count()); + // If we don't restrict the source then adaptation will not happen again due + // to "awaiting previous adaptation". This prevents "double-adapt". + resource_.set_usage_state(ResourceUsageState::kOveruse); + EXPECT_EQ(1u, processor_listener_.restrictions_updated_count()); +} + +TEST_F(ResourceAdaptationProcessorTest, CannotAdaptUpWhenUnrestricted) { + processor_.SetDegradationPreference( + DegradationPreference::MAINTAIN_FRAMERATE); + processor_.StartResourceAdaptation(); + SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); + resource_.set_usage_state(ResourceUsageState::kUnderuse); + EXPECT_EQ(0u, processor_listener_.restrictions_updated_count()); +} + +TEST_F(ResourceAdaptationProcessorTest, UnderuseTakesUsBackToUnrestricted) { + processor_.SetDegradationPreference( + DegradationPreference::MAINTAIN_FRAMERATE); + processor_.StartResourceAdaptation(); + SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); + resource_.set_usage_state(ResourceUsageState::kOveruse); + EXPECT_EQ(1u, processor_listener_.restrictions_updated_count()); + RestrictSource(processor_listener_.restrictions()); + resource_.set_usage_state(ResourceUsageState::kUnderuse); + EXPECT_EQ(2u, processor_listener_.restrictions_updated_count()); + EXPECT_EQ(VideoSourceRestrictions(), processor_listener_.restrictions()); +} + +TEST_F(ResourceAdaptationProcessorTest, ResourcesCanPreventAdaptingUp) { + processor_.SetDegradationPreference( + DegradationPreference::MAINTAIN_FRAMERATE); + processor_.StartResourceAdaptation(); + SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); + // Adapt down so that we can adapt up. + resource_.set_usage_state(ResourceUsageState::kOveruse); + EXPECT_EQ(1u, processor_listener_.restrictions_updated_count()); + RestrictSource(processor_listener_.restrictions()); + // Adapting up is prevented. + resource_.set_is_adaptation_up_allowed(false); + resource_.set_usage_state(ResourceUsageState::kUnderuse); + EXPECT_EQ(1u, processor_listener_.restrictions_updated_count()); +} + +TEST_F(ResourceAdaptationProcessorTest, AdaptingTriggersOnAdaptationApplied) { + processor_.SetDegradationPreference( + DegradationPreference::MAINTAIN_FRAMERATE); + processor_.StartResourceAdaptation(); + SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); + resource_.set_usage_state(ResourceUsageState::kOveruse); + EXPECT_EQ(1u, resource_.num_adaptations_applied()); +} + +TEST_F(ResourceAdaptationProcessorTest, AdaptingClearsResourceUsageState) { + processor_.SetDegradationPreference( + DegradationPreference::MAINTAIN_FRAMERATE); + processor_.StartResourceAdaptation(); + SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize); + resource_.set_usage_state(ResourceUsageState::kOveruse); + EXPECT_EQ(1u, processor_listener_.restrictions_updated_count()); + EXPECT_FALSE(resource_.usage_state().has_value()); +} + +TEST_F(ResourceAdaptationProcessorTest, + FailingAdaptingAlsoClearsResourceUsageState) { + processor_.SetDegradationPreference(DegradationPreference::DISABLED); + processor_.StartResourceAdaptation(); + resource_.set_usage_state(ResourceUsageState::kOveruse); + EXPECT_EQ(0u, processor_listener_.restrictions_updated_count()); + EXPECT_FALSE(resource_.usage_state().has_value()); +} + +} // namespace webrtc diff --git a/call/adaptation/test/fake_frame_rate_provider.cc b/call/adaptation/test/fake_frame_rate_provider.cc new file mode 100644 index 0000000000..65fee6a7ba --- /dev/null +++ b/call/adaptation/test/fake_frame_rate_provider.cc @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "call/adaptation/test/fake_frame_rate_provider.h" + +#include "test/gmock.h" + +using ::testing::Return; + +namespace webrtc { + +FakeFrameRateProvider::FakeFrameRateProvider() { + set_fps(0); +} + +void FakeFrameRateProvider::set_fps(int fps) { + EXPECT_CALL(*this, GetInputFrameRate()).WillRepeatedly(Return(fps)); +} + +} // namespace webrtc diff --git a/call/adaptation/test/fake_frame_rate_provider.h b/call/adaptation/test/fake_frame_rate_provider.h new file mode 100644 index 0000000000..a08e162321 --- /dev/null +++ b/call/adaptation/test/fake_frame_rate_provider.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef CALL_ADAPTATION_TEST_FAKE_FRAME_RATE_PROVIDER_H_ +#define CALL_ADAPTATION_TEST_FAKE_FRAME_RATE_PROVIDER_H_ + +#include <string> +#include <vector> + +#include "api/video/video_stream_encoder_observer.h" +#include "test/gmock.h" + +namespace webrtc { + +class MockVideoStreamEncoderObserver : public VideoStreamEncoderObserver { + public: + MOCK_METHOD2(OnEncodedFrameTimeMeasured, void(int, int)); + MOCK_METHOD2(OnIncomingFrame, void(int, int)); + MOCK_METHOD2(OnSendEncodedImage, + void(const EncodedImage&, const CodecSpecificInfo*)); + MOCK_METHOD1(OnEncoderImplementationChanged, void(const std::string&)); + MOCK_METHOD1(OnFrameDropped, void(DropReason)); + MOCK_METHOD2(OnEncoderReconfigured, + void(const VideoEncoderConfig&, + const std::vector<VideoStream>&)); + MOCK_METHOD3(OnAdaptationChanged, + void(VideoAdaptationReason, + const VideoAdaptationCounters&, + const VideoAdaptationCounters&)); + MOCK_METHOD0(ClearAdaptationStats, void()); + MOCK_METHOD2(UpdateAdaptationSettings, + void(AdaptationSettings, AdaptationSettings)); + MOCK_METHOD0(OnMinPixelLimitReached, void()); + MOCK_METHOD0(OnInitialQualityResolutionAdaptDown, void()); + MOCK_METHOD1(OnSuspendChange, void(bool)); + MOCK_METHOD2(OnBitrateAllocationUpdated, + void(const VideoCodec&, const VideoBitrateAllocation&)); + MOCK_METHOD1(OnEncoderInternalScalerUpdate, void(bool)); + MOCK_CONST_METHOD0(GetInputFrameRate, int()); +}; + +class FakeFrameRateProvider : public MockVideoStreamEncoderObserver { + public: + FakeFrameRateProvider(); + void set_fps(int fps); +}; + +} // namespace webrtc + +#endif // CALL_ADAPTATION_TEST_FAKE_FRAME_RATE_PROVIDER_H_ diff --git a/call/adaptation/test/fake_resource.cc b/call/adaptation/test/fake_resource.cc index dc2d8c5df9..bd7ad5431f 100644 --- a/call/adaptation/test/fake_resource.cc +++ b/call/adaptation/test/fake_resource.cc @@ -15,7 +15,10 @@ namespace webrtc { FakeResource::FakeResource(std::string name) - : Resource(), name_(std::move(name)) {} + : Resource(), + name_(std::move(name)), + is_adaptation_up_allowed_(true), + num_adaptations_applied_(0) {} FakeResource::~FakeResource() {} @@ -23,4 +26,28 @@ void FakeResource::set_usage_state(ResourceUsageState usage_state) { OnResourceUsageStateMeasured(usage_state); } +void FakeResource::set_is_adaptation_up_allowed(bool is_adaptation_up_allowed) { + is_adaptation_up_allowed_ = is_adaptation_up_allowed; +} + +size_t FakeResource::num_adaptations_applied() const { + return num_adaptations_applied_; +} + +bool FakeResource::IsAdaptationUpAllowed( + const VideoStreamInputState& input_state, + const VideoSourceRestrictions& restrictions_before, + const VideoSourceRestrictions& restrictions_after, + const Resource& reason_resource) const { + return is_adaptation_up_allowed_; +} + +void FakeResource::OnAdaptationApplied( + const VideoStreamInputState& input_state, + const VideoSourceRestrictions& restrictions_before, + const VideoSourceRestrictions& restrictions_after, + const Resource& reason_resource) { + ++num_adaptations_applied_; +} + } // namespace webrtc diff --git a/call/adaptation/test/fake_resource.h b/call/adaptation/test/fake_resource.h index 2e1dc1b550..0d9b1f46bb 100644 --- a/call/adaptation/test/fake_resource.h +++ b/call/adaptation/test/fake_resource.h @@ -24,11 +24,24 @@ class FakeResource : public Resource { ~FakeResource() override; void set_usage_state(ResourceUsageState usage_state); + void set_is_adaptation_up_allowed(bool is_adaptation_up_allowed); + size_t num_adaptations_applied() const; + // Resource implementation. std::string name() const override { return name_; } + bool IsAdaptationUpAllowed(const VideoStreamInputState& input_state, + const VideoSourceRestrictions& restrictions_before, + const VideoSourceRestrictions& restrictions_after, + const Resource& reason_resource) const override; + void OnAdaptationApplied(const VideoStreamInputState& input_state, + const VideoSourceRestrictions& restrictions_before, + const VideoSourceRestrictions& restrictions_after, + const Resource& reason_resource) override; private: const std::string name_; + bool is_adaptation_up_allowed_; + size_t num_adaptations_applied_; }; } // namespace webrtc diff --git a/call/adaptation/video_source_restrictions_unittest.cc b/call/adaptation/video_source_restrictions_unittest.cc new file mode 100644 index 0000000000..eeb4b1d7fd --- /dev/null +++ b/call/adaptation/video_source_restrictions_unittest.cc @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "call/adaptation/video_source_restrictions.h" + +#include "test/gtest.h" + +namespace webrtc { + +namespace { + +VideoSourceRestrictions RestrictionsFromMaxPixelsPerFrame( + size_t max_pixels_per_frame) { + return VideoSourceRestrictions(max_pixels_per_frame, absl::nullopt, + absl::nullopt); +} + +VideoSourceRestrictions RestrictionsFromMaxFrameRate(double max_frame_rate) { + return VideoSourceRestrictions(absl::nullopt, absl::nullopt, max_frame_rate); +} + +} // namespace + +TEST(VideoSourceRestrictionsTest, DidIncreaseResolution) { + // smaller restrictions -> larger restrictions + EXPECT_TRUE(DidIncreaseResolution(RestrictionsFromMaxPixelsPerFrame(10), + RestrictionsFromMaxPixelsPerFrame(11))); + // unrestricted -> restricted + EXPECT_FALSE(DidIncreaseResolution(VideoSourceRestrictions(), + RestrictionsFromMaxPixelsPerFrame(10))); + // restricted -> unrestricted + EXPECT_TRUE(DidIncreaseResolution(RestrictionsFromMaxPixelsPerFrame(10), + VideoSourceRestrictions())); + // restricted -> equally restricted + EXPECT_FALSE(DidIncreaseResolution(RestrictionsFromMaxPixelsPerFrame(10), + RestrictionsFromMaxPixelsPerFrame(10))); + // unrestricted -> unrestricted + EXPECT_FALSE(DidIncreaseResolution(VideoSourceRestrictions(), + VideoSourceRestrictions())); + // larger restrictions -> smaller restrictions + EXPECT_FALSE(DidIncreaseResolution(RestrictionsFromMaxPixelsPerFrame(10), + RestrictionsFromMaxPixelsPerFrame(9))); +} + +TEST(VideoSourceRestrictionsTest, DidDecreaseFrameRate) { + // samller restrictions -> larger restrictions + EXPECT_FALSE(DidDecreaseFrameRate(RestrictionsFromMaxFrameRate(10), + RestrictionsFromMaxFrameRate(11))); + // unrestricted -> restricted + EXPECT_TRUE(DidDecreaseFrameRate(VideoSourceRestrictions(), + RestrictionsFromMaxFrameRate(10))); + // restricted -> unrestricted + EXPECT_FALSE(DidDecreaseFrameRate(RestrictionsFromMaxFrameRate(10), + VideoSourceRestrictions())); + // restricted -> equally restricted + EXPECT_FALSE(DidDecreaseFrameRate(RestrictionsFromMaxFrameRate(10), + RestrictionsFromMaxFrameRate(10))); + // unrestricted -> unrestricted + EXPECT_FALSE(DidDecreaseFrameRate(VideoSourceRestrictions(), + VideoSourceRestrictions())); + // larger restrictions -> samller restrictions + EXPECT_TRUE(DidDecreaseFrameRate(RestrictionsFromMaxFrameRate(10), + RestrictionsFromMaxFrameRate(9))); +} + +} // namespace webrtc diff --git a/call/adaptation/video_stream_adapter.cc b/call/adaptation/video_stream_adapter.cc index 62330e945f..b224e3e4d2 100644 --- a/call/adaptation/video_stream_adapter.cc +++ b/call/adaptation/video_stream_adapter.cc @@ -433,7 +433,7 @@ Adaptation VideoStreamAdapter::GetAdaptationUp() const { } case DegradationPreference::MAINTAIN_RESOLUTION: { // Scale up framerate. - int target_fps = input_state_.frames_per_second().value(); + int target_fps = input_state_.frames_per_second(); if (source_restrictor_->adaptation_counters().fps_adaptations == 1) { RTC_LOG(LS_INFO) << "Removing framerate down-scaling setting."; target_fps = std::numeric_limits<int>::max(); @@ -505,8 +505,7 @@ Adaptation VideoStreamAdapter::GetAdaptationDown() const { min_pixel_limit_reached); } case DegradationPreference::MAINTAIN_RESOLUTION: { - int target_fps = - GetLowerFrameRateThan(input_state_.frames_per_second().value()); + int target_fps = GetLowerFrameRateThan(input_state_.frames_per_second()); if (!source_restrictor_->CanDecreaseFrameRateTo(target_fps)) { return Adaptation(adaptation_validation_id_, Adaptation::Status::kLimitReached); @@ -542,7 +541,7 @@ void VideoStreamAdapter::ApplyAdaptation(const Adaptation& adaptation) { // adapting again before this adaptation has had an effect. last_adaptation_request_.emplace(AdaptationRequest{ input_state_.frame_size_pixels().value(), - input_state_.frames_per_second().value(), + input_state_.frames_per_second(), AdaptationRequest::GetModeFromAdaptationAction(adaptation.step().type)}); // Adapt! source_restrictor_->ApplyAdaptationStep(adaptation.step(), diff --git a/call/adaptation/video_stream_input_state.cc b/call/adaptation/video_stream_input_state.cc index 1827334b21..dc3315e6d0 100644 --- a/call/adaptation/video_stream_input_state.cc +++ b/call/adaptation/video_stream_input_state.cc @@ -17,7 +17,7 @@ namespace webrtc { VideoStreamInputState::VideoStreamInputState() : has_input_(false), frame_size_pixels_(absl::nullopt), - frames_per_second_(absl::nullopt), + frames_per_second_(0), video_codec_type_(VideoCodecType::kVideoCodecGeneric), min_pixels_per_frame_(kDefaultMinPixelsPerFrame) {} @@ -30,8 +30,7 @@ void VideoStreamInputState::set_frame_size_pixels( frame_size_pixels_ = frame_size_pixels; } -void VideoStreamInputState::set_frames_per_second( - absl::optional<int> frames_per_second) { +void VideoStreamInputState::set_frames_per_second(int frames_per_second) { frames_per_second_ = frames_per_second; } @@ -52,7 +51,7 @@ absl::optional<int> VideoStreamInputState::frame_size_pixels() const { return frame_size_pixels_; } -absl::optional<int> VideoStreamInputState::frames_per_second() const { +int VideoStreamInputState::frames_per_second() const { return frames_per_second_; } @@ -65,8 +64,7 @@ int VideoStreamInputState::min_pixels_per_frame() const { } bool VideoStreamInputState::HasInputFrameSizeAndFramesPerSecond() const { - return has_input_ && frame_size_pixels_.has_value() && - frames_per_second_.has_value(); + return has_input_ && frame_size_pixels_.has_value(); } } // namespace webrtc diff --git a/call/adaptation/video_stream_input_state.h b/call/adaptation/video_stream_input_state.h index ef80405e75..af0d7c78e9 100644 --- a/call/adaptation/video_stream_input_state.h +++ b/call/adaptation/video_stream_input_state.h @@ -24,13 +24,13 @@ class VideoStreamInputState { void set_has_input(bool has_input); void set_frame_size_pixels(absl::optional<int> frame_size_pixels); - void set_frames_per_second(absl::optional<int> frames_per_second); + void set_frames_per_second(int frames_per_second); void set_video_codec_type(VideoCodecType video_codec_type); void set_min_pixels_per_frame(int min_pixels_per_frame); bool has_input() const; absl::optional<int> frame_size_pixels() const; - absl::optional<int> frames_per_second() const; + int frames_per_second() const; VideoCodecType video_codec_type() const; int min_pixels_per_frame() const; @@ -39,7 +39,7 @@ class VideoStreamInputState { private: bool has_input_; absl::optional<int> frame_size_pixels_; - absl::optional<int> frames_per_second_; + int frames_per_second_; VideoCodecType video_codec_type_; int min_pixels_per_frame_; }; diff --git a/call/adaptation/video_stream_input_state_provider.cc b/call/adaptation/video_stream_input_state_provider.cc index 2548a4802b..eac30bbfac 100644 --- a/call/adaptation/video_stream_input_state_provider.cc +++ b/call/adaptation/video_stream_input_state_provider.cc @@ -40,8 +40,7 @@ VideoStreamInputState VideoStreamInputStateProvider::InputState() { // GetInputFrameRate() is thread-safe. int input_fps = frame_rate_provider_->GetInputFrameRate(); rtc::CritScope lock(&crit_); - input_state_.set_frames_per_second( - input_fps >= 0 ? absl::optional<int>(input_fps) : absl::nullopt); + input_state_.set_frames_per_second(input_fps); return input_state_; } diff --git a/call/adaptation/video_stream_input_state_provider_unittest.cc b/call/adaptation/video_stream_input_state_provider_unittest.cc new file mode 100644 index 0000000000..49c662c581 --- /dev/null +++ b/call/adaptation/video_stream_input_state_provider_unittest.cc @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "call/adaptation/video_stream_input_state_provider.h" + +#include <utility> + +#include "api/video_codecs/video_encoder.h" +#include "call/adaptation/encoder_settings.h" +#include "call/adaptation/test/fake_frame_rate_provider.h" +#include "test/gtest.h" + +namespace webrtc { + +TEST(VideoStreamInputStateProviderTest, DefaultValues) { + FakeFrameRateProvider frame_rate_provider; + VideoStreamInputStateProvider input_state_provider(&frame_rate_provider); + VideoStreamInputState input_state = input_state_provider.InputState(); + EXPECT_EQ(false, input_state.has_input()); + EXPECT_EQ(absl::nullopt, input_state.frame_size_pixels()); + EXPECT_EQ(0, input_state.frames_per_second()); + EXPECT_EQ(VideoCodecType::kVideoCodecGeneric, input_state.video_codec_type()); + EXPECT_EQ(kDefaultMinPixelsPerFrame, input_state.min_pixels_per_frame()); +} + +TEST(VideoStreamInputStateProviderTest, ValuesSet) { + FakeFrameRateProvider frame_rate_provider; + VideoStreamInputStateProvider input_state_provider(&frame_rate_provider); + input_state_provider.OnHasInputChanged(true); + input_state_provider.OnFrameSizeObserved(42); + frame_rate_provider.set_fps(123); + VideoEncoder::EncoderInfo encoder_info; + encoder_info.scaling_settings.min_pixels_per_frame = 1337; + VideoEncoderConfig encoder_config; + encoder_config.codec_type = VideoCodecType::kVideoCodecVP9; + input_state_provider.OnEncoderSettingsChanged(EncoderSettings( + std::move(encoder_info), std::move(encoder_config), VideoCodec())); + VideoStreamInputState input_state = input_state_provider.InputState(); + EXPECT_EQ(true, input_state.has_input()); + EXPECT_EQ(42, input_state.frame_size_pixels()); + EXPECT_EQ(123, input_state.frames_per_second()); + EXPECT_EQ(VideoCodecType::kVideoCodecVP9, input_state.video_codec_type()); + EXPECT_EQ(1337, input_state.min_pixels_per_frame()); +} + +} // namespace webrtc diff --git a/video/adaptation/quality_scaler_resource.cc b/video/adaptation/quality_scaler_resource.cc index 4369baa092..3f32fa2ce6 100644 --- a/video/adaptation/quality_scaler_resource.cc +++ b/video/adaptation/quality_scaler_resource.cc @@ -116,8 +116,8 @@ void QualityScalerResource::OnAdaptationApplied( DidDecreaseFrameRate(restrictions_before, restrictions_after)) { absl::optional<int> min_diff = BalancedDegradationSettings().MinFpsDiff( input_state.frame_size_pixels().value()); - if (min_diff && input_state.frames_per_second().value() > 0) { - int fps_diff = input_state.frames_per_second().value() - + if (min_diff && input_state.frames_per_second() > 0) { + int fps_diff = input_state.frames_per_second() - restrictions_after.max_frame_rate().value(); if (fps_diff < min_diff.value()) { clear_qp_samples = false; diff --git a/video/adaptation/video_stream_encoder_resource_manager.h b/video/adaptation/video_stream_encoder_resource_manager.h index 740865baba..61b1506627 100644 --- a/video/adaptation/video_stream_encoder_resource_manager.h +++ b/video/adaptation/video_stream_encoder_resource_manager.h @@ -164,6 +164,9 @@ class VideoStreamEncoderResourceManager void ResetActiveCounts(); std::string ActiveCountsToString() const; + // TODO(hbos): Consider moving all of the manager's resources into separate + // files for testability. + // Does not trigger adaptations, only prevents adapting up based on // |active_counts_|. class PreventAdaptUpDueToActiveCounts final : public Resource { |