[Adaptation] Remove QualityScalerResource when disabled.

Bug: webrtc:11843
Change-Id: I2d3e40356c266f189db0242f3c7590e6d83e4456
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/181369
Commit-Queue: Evan Shrubsole <eshr@google.com>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#31924}
diff --git a/call/adaptation/resource_adaptation_processor.cc b/call/adaptation/resource_adaptation_processor.cc
index b988479..c164292 100644
--- a/call/adaptation/resource_adaptation_processor.cc
+++ b/call/adaptation/resource_adaptation_processor.cc
@@ -132,6 +132,7 @@
     resources_.push_back(resource);
   }
   resource->SetResourceListener(resource_listener_delegate_);
+  RTC_LOG(INFO) << "Registered resource \"" << resource->Name() << "\".";
 }
 
 std::vector<rtc::scoped_refptr<Resource>>
diff --git a/video/adaptation/quality_scaler_resource.cc b/video/adaptation/quality_scaler_resource.cc
index ff8f171..c438488 100644
--- a/video/adaptation/quality_scaler_resource.cc
+++ b/video/adaptation/quality_scaler_resource.cc
@@ -12,6 +12,7 @@
 
 #include <utility>
 
+#include "rtc_base/checks.h"
 #include "rtc_base/experiments/balanced_degradation_settings.h"
 #include "rtc_base/ref_counted_object.h"
 #include "rtc_base/task_utils/to_queued_task.h"
@@ -19,27 +20,14 @@
 
 namespace webrtc {
 
-namespace {
-
-const int64_t kUnderuseDueToDisabledCooldownMs = 1000;
-
-}  // namespace
-
 // static
-rtc::scoped_refptr<QualityScalerResource> QualityScalerResource::Create(
-    DegradationPreferenceProvider* degradation_preference_provider) {
-  return new rtc::RefCountedObject<QualityScalerResource>(
-      degradation_preference_provider);
+rtc::scoped_refptr<QualityScalerResource> QualityScalerResource::Create() {
+  return new rtc::RefCountedObject<QualityScalerResource>();
 }
 
-QualityScalerResource::QualityScalerResource(
-    DegradationPreferenceProvider* degradation_preference_provider)
+QualityScalerResource::QualityScalerResource()
     : VideoStreamEncoderResource("QualityScalerResource"),
-      quality_scaler_(nullptr),
-      last_underuse_due_to_disabled_timestamp_ms_(absl::nullopt),
-      degradation_preference_provider_(degradation_preference_provider) {
-  RTC_CHECK(degradation_preference_provider_);
-}
+      quality_scaler_(nullptr) {}
 
 QualityScalerResource::~QualityScalerResource() {
   RTC_DCHECK(!quality_scaler_);
@@ -60,6 +48,7 @@
 
 void QualityScalerResource::StopCheckForOveruse() {
   RTC_DCHECK_RUN_ON(encoder_queue());
+  RTC_DCHECK(is_started());
   // Ensure we have no pending callbacks. This makes it safe to destroy the
   // QualityScaler and even task queues with tasks in-flight.
   quality_scaler_.reset();
@@ -83,21 +72,6 @@
   RTC_DCHECK_RUN_ON(encoder_queue());
   if (quality_scaler_ && encoded_image.qp_ >= 0) {
     quality_scaler_->ReportQp(encoded_image.qp_, time_sent_in_us);
-  } else if (!quality_scaler_) {
-    // Reference counting guarantees that this object is still alive by the time
-    // the task is executed.
-    // TODO(webrtc:11553): this is a workaround to ensure that all quality
-    // scaler imposed limitations are removed once qualty scaler is disabled
-    // mid call.
-    // Instead it should be done at a higher layer in the same way for all
-    // resources.
-    int64_t timestamp_ms = rtc::TimeMillis();
-    if (!last_underuse_due_to_disabled_timestamp_ms_.has_value() ||
-        timestamp_ms - last_underuse_due_to_disabled_timestamp_ms_.value() >=
-            kUnderuseDueToDisabledCooldownMs) {
-      last_underuse_due_to_disabled_timestamp_ms_ = timestamp_ms;
-      OnResourceUsageStateMeasured(ResourceUsageState::kUnderuse);
-    }
   }
 }
 
diff --git a/video/adaptation/quality_scaler_resource.h b/video/adaptation/quality_scaler_resource.h
index 27c2555..06c22ca 100644
--- a/video/adaptation/quality_scaler_resource.h
+++ b/video/adaptation/quality_scaler_resource.h
@@ -32,18 +32,15 @@
 class QualityScalerResource : public VideoStreamEncoderResource,
                               public QualityScalerQpUsageHandlerInterface {
  public:
-  static rtc::scoped_refptr<QualityScalerResource> Create(
-      DegradationPreferenceProvider* degradation_preference_provider);
+  static rtc::scoped_refptr<QualityScalerResource> Create();
 
-  explicit QualityScalerResource(
-      DegradationPreferenceProvider* degradation_preference_provider);
+  QualityScalerResource();
   ~QualityScalerResource() override;
 
   bool is_started() const;
 
   void StartCheckForOveruse(VideoEncoder::QpThresholds qp_thresholds);
   void StopCheckForOveruse();
-
   void SetQpThresholds(VideoEncoder::QpThresholds qp_thresholds);
   bool QpFastFilterLow();
   void OnEncodeCompleted(const EncodedImage& encoded_image,
@@ -55,15 +52,8 @@
   void OnReportQpUsageLow() override;
 
  private:
-  // Members accessed on the encoder queue.
   std::unique_ptr<QualityScaler> quality_scaler_
       RTC_GUARDED_BY(encoder_queue());
-  // The timestamp of the last time we reported underuse because this resource
-  // was disabled in order to prevent getting stuck with QP adaptations. Used to
-  // make sure underuse reporting is not too spammy.
-  absl::optional<int64_t> last_underuse_due_to_disabled_timestamp_ms_
-      RTC_GUARDED_BY(encoder_queue());
-  DegradationPreferenceProvider* const degradation_preference_provider_;
 };
 
 }  // namespace webrtc
diff --git a/video/adaptation/quality_scaler_resource_unittest.cc b/video/adaptation/quality_scaler_resource_unittest.cc
index 1560521..1a3175a 100644
--- a/video/adaptation/quality_scaler_resource_unittest.cc
+++ b/video/adaptation/quality_scaler_resource_unittest.cc
@@ -41,17 +41,13 @@
 class QualityScalerResourceTest : public ::testing::Test {
  public:
   QualityScalerResourceTest()
-      : quality_scaler_resource_(
-            QualityScalerResource::Create(&degradation_preference_provider_)) {
+      : quality_scaler_resource_(QualityScalerResource::Create()) {
     quality_scaler_resource_->RegisterEncoderTaskQueue(
         TaskQueueBase::Current());
     quality_scaler_resource_->SetResourceListener(&fake_resource_listener_);
-    quality_scaler_resource_->StartCheckForOveruse(
-        VideoEncoder::QpThresholds());
   }
 
   ~QualityScalerResourceTest() override {
-    quality_scaler_resource_->StopCheckForOveruse();
     quality_scaler_resource_->SetResourceListener(nullptr);
   }
 
diff --git a/video/adaptation/video_stream_encoder_resource_manager.cc b/video/adaptation/video_stream_encoder_resource_manager.cc
index 16c8b3d..47bd1b4 100644
--- a/video/adaptation/video_stream_encoder_resource_manager.cc
+++ b/video/adaptation/video_stream_encoder_resource_manager.cc
@@ -22,11 +22,15 @@
 #include "api/video/video_adaptation_reason.h"
 #include "api/video/video_source_interface.h"
 #include "call/adaptation/video_source_restrictions.h"
+#include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/numerics/safe_conversions.h"
 #include "rtc_base/ref_counted_object.h"
 #include "rtc_base/strings/string_builder.h"
+#include "rtc_base/synchronization/sequence_checker.h"
+#include "rtc_base/task_utils/to_queued_task.h"
 #include "rtc_base/time_utils.h"
+#include "video/adaptation/quality_scaler_resource.h"
 
 namespace webrtc {
 
@@ -82,7 +86,6 @@
 
   void SetTargetBitrate(DataRate target_bitrate, int64_t now_ms) {
     if (set_start_bitrate_ > DataRate::Zero() && !has_seen_first_bwe_drop_ &&
-        quality_scaler_resource_->is_started() &&
         quality_scaler_settings_.InitialBitrateIntervalMs() &&
         quality_scaler_settings_.InitialBitrateFactor()) {
       int64_t diff_ms = now_ms - set_start_bitrate_time_ms_;
@@ -273,8 +276,7 @@
           degradation_preference_provider_)),
       encode_usage_resource_(
           EncodeUsageResource::Create(std::move(overuse_detector))),
-      quality_scaler_resource_(
-          QualityScalerResource::Create(degradation_preference_provider_)),
+      quality_scaler_resource_(QualityScalerResource::Create()),
       encoder_queue_(nullptr),
       resource_adaptation_queue_(nullptr),
       input_state_provider_(input_state_provider),
@@ -293,12 +295,10 @@
       encoder_settings_(absl::nullopt) {
   RTC_CHECK(degradation_preference_provider_);
   RTC_CHECK(encoder_stats_observer_);
-  MapResourceToReason(encode_usage_resource_, VideoAdaptationReason::kCpu);
-  MapResourceToReason(quality_scaler_resource_,
-                      VideoAdaptationReason::kQuality);
 }
 
-VideoStreamEncoderResourceManager::~VideoStreamEncoderResourceManager() {}
+VideoStreamEncoderResourceManager::~VideoStreamEncoderResourceManager() =
+    default;
 
 void VideoStreamEncoderResourceManager::Initialize(
     rtc::TaskQueue* encoder_queue,
@@ -341,37 +341,49 @@
   RTC_DCHECK(encoder_settings_.has_value());
   if (encode_usage_resource_->is_started()) {
     encode_usage_resource_->StopCheckForOveruse();
+  } else {
+    // If the resource has not yet started then it needs to be added.
+    AddResource(encode_usage_resource_, VideoAdaptationReason::kCpu);
   }
   encode_usage_resource_->StartCheckForOveruse(GetCpuOveruseOptions());
 }
 
 void VideoStreamEncoderResourceManager::StopManagedResources() {
   RTC_DCHECK_RUN_ON(encoder_queue_);
-  encode_usage_resource_->StopCheckForOveruse();
-  quality_scaler_resource_->StopCheckForOveruse();
+  RTC_DCHECK(adaptation_processor_);
+  if (encode_usage_resource_->is_started()) {
+    encode_usage_resource_->StopCheckForOveruse();
+    RemoveResource(encode_usage_resource_);
+  }
+  if (quality_scaler_resource_->is_started()) {
+    quality_scaler_resource_->StopCheckForOveruse();
+    RemoveResource(quality_scaler_resource_);
+  }
 }
 
-void VideoStreamEncoderResourceManager::MapResourceToReason(
+void VideoStreamEncoderResourceManager::AddResource(
     rtc::scoped_refptr<Resource> resource,
     VideoAdaptationReason reason) {
   MutexLock lock(&resource_lock_);
   RTC_DCHECK(resource);
-  RTC_DCHECK(absl::c_find_if(resources_,
-                             [resource](const ResourceAndReason& r) {
-                               return r.resource == resource;
-                             }) == resources_.end())
-      << "Resource " << resource->Name() << " already was inserted";
-  resources_.emplace_back(resource, reason);
+  bool inserted;
+  std::tie(std::ignore, inserted) = resources_.emplace(resource, reason);
+  RTC_DCHECK(inserted) << "Resurce " << resource->Name()
+                       << " already was inserted";
+  adaptation_processor_->AddResource(resource);
 }
 
-std::vector<rtc::scoped_refptr<Resource>>
-VideoStreamEncoderResourceManager::MappedResources() const {
-  MutexLock lock(&resource_lock_);
-  std::vector<rtc::scoped_refptr<Resource>> resources;
-  for (auto const& resource_and_reason : resources_) {
-    resources.push_back(resource_and_reason.resource);
+void VideoStreamEncoderResourceManager::RemoveResource(
+    rtc::scoped_refptr<Resource> resource) {
+  {
+    MutexLock lock(&resource_lock_);
+    RTC_DCHECK(resource);
+    const auto& it = resources_.find(resource);
+    RTC_DCHECK(it != resources_.end())
+        << "Resource \"" << resource->Name() << "\" not found.";
+    resources_.erase(it);
   }
-  return resources;
+  adaptation_processor_->RemoveResource(resource);
 }
 
 std::vector<AdaptationConstraint*>
@@ -379,12 +391,6 @@
   return {bitrate_constraint_, balanced_constraint_};
 }
 
-rtc::scoped_refptr<QualityScalerResource>
-VideoStreamEncoderResourceManager::quality_scaler_resource_for_testing() {
-  MutexLock lock(&resource_lock_);
-  return quality_scaler_resource_;
-}
-
 void VideoStreamEncoderResourceManager::SetEncoderSettings(
     EncoderSettings encoder_settings) {
   RTC_DCHECK_RUN_ON(encoder_queue_);
@@ -468,7 +474,6 @@
       encoded_image.capture_time_ms_ * rtc::kNumMicrosecsPerMillisec;
   encode_usage_resource_->OnEncodeCompleted(
       timestamp, time_sent_in_us, capture_time_us, encode_duration_us);
-  // Inform |quality_scaler_resource_| of the encode completed event.
   quality_scaler_resource_->OnEncodeCompleted(encoded_image, time_sent_in_us);
 }
 
@@ -486,7 +491,7 @@
 void VideoStreamEncoderResourceManager::OnMaybeEncodeFrame() {
   RTC_DCHECK_RUN_ON(encoder_queue_);
   initial_frame_dropper_->OnMaybeEncodeFrame();
-  if (quality_rampup_experiment_) {
+  if (quality_rampup_experiment_ && quality_scaler_resource_->is_started()) {
     DataRate bandwidth = encoder_rates_.has_value()
                              ? encoder_rates_->bandwidth_allocation
                              : DataRate::Zero();
@@ -502,10 +507,15 @@
     absl::optional<VideoEncoder::QpThresholds> qp_thresholds) {
   RTC_DCHECK_RUN_ON(encoder_queue_);
   if (qp_thresholds.has_value()) {
+    if (quality_scaler_resource_->is_started()) {
+      quality_scaler_resource_->SetQpThresholds(qp_thresholds.value());
+    } else {
+      quality_scaler_resource_->StartCheckForOveruse(qp_thresholds.value());
+      AddResource(quality_scaler_resource_, VideoAdaptationReason::kQuality);
+    }
+  } else if (quality_scaler_resource_->is_started()) {
     quality_scaler_resource_->StopCheckForOveruse();
-    quality_scaler_resource_->StartCheckForOveruse(qp_thresholds.value());
-  } else {
-    quality_scaler_resource_->StopCheckForOveruse();
+    RemoveResource(quality_scaler_resource_);
   }
   initial_frame_dropper_->OnQualityScalerSettingsUpdated();
 }
@@ -555,13 +565,10 @@
 VideoAdaptationReason VideoStreamEncoderResourceManager::GetReasonFromResource(
     rtc::scoped_refptr<Resource> resource) const {
   MutexLock lock(&resource_lock_);
-  const auto& registered_resource =
-      absl::c_find_if(resources_, [&resource](const ResourceAndReason& r) {
-        return r.resource == resource;
-      });
+  const auto& registered_resource = resources_.find(resource);
   RTC_DCHECK(registered_resource != resources_.end())
       << resource->Name() << " not found.";
-  return registered_resource->reason;
+  return registered_resource->second;
 }
 
 // TODO(pbos): Lower these thresholds (to closer to 100%) when we handle
diff --git a/video/adaptation/video_stream_encoder_resource_manager.h b/video/adaptation/video_stream_encoder_resource_manager.h
index 10d0e66..e7a45d9 100644
--- a/video/adaptation/video_stream_encoder_resource_manager.h
+++ b/video/adaptation/video_stream_encoder_resource_manager.h
@@ -40,6 +40,7 @@
 #include "rtc_base/strings/string_builder.h"
 #include "rtc_base/synchronization/mutex.h"
 #include "rtc_base/task_queue.h"
+#include "rtc_base/thread_annotations.h"
 #include "system_wrappers/include/clock.h"
 #include "video/adaptation/encode_usage_resource.h"
 #include "video/adaptation/overuse_frame_detector.h"
@@ -115,12 +116,10 @@
 
   // Resources need to be mapped to an AdaptReason (kCpu or kQuality) in order
   // to update legacy getStats().
-  void MapResourceToReason(rtc::scoped_refptr<Resource> resource,
-                           VideoAdaptationReason reason);
-  std::vector<rtc::scoped_refptr<Resource>> MappedResources() const;
+  void AddResource(rtc::scoped_refptr<Resource> resource,
+                   VideoAdaptationReason reason);
+  void RemoveResource(rtc::scoped_refptr<Resource> resource);
   std::vector<AdaptationConstraint*> AdaptationConstraints() const;
-  rtc::scoped_refptr<QualityScalerResource>
-  quality_scaler_resource_for_testing();
   // If true, the VideoStreamEncoder should eexecute its logic to maybe drop
   // frames baseed on size and bitrate.
   bool DropInitialFrames() const;
@@ -237,8 +236,7 @@
   rtc::TaskQueue* resource_adaptation_queue_;
   VideoStreamInputStateProvider* const input_state_provider_
       RTC_GUARDED_BY(encoder_queue_);
-  ResourceAdaptationProcessorInterface* adaptation_processor_
-      RTC_GUARDED_BY(resource_adaptation_queue_);
+  ResourceAdaptationProcessorInterface* adaptation_processor_;
   VideoStreamAdapter* stream_adapter_
       RTC_GUARDED_BY(resource_adaptation_queue_);
   // Thread-safe.
@@ -263,19 +261,11 @@
   absl::optional<EncoderSettings> encoder_settings_
       RTC_GUARDED_BY(encoder_queue_);
 
+  mutable Mutex resource_lock_;
   // Ties a resource to a reason for statistical reporting. This AdaptReason is
   // also used by this module to make decisions about how to adapt up/down.
-  struct ResourceAndReason {
-    ResourceAndReason(rtc::scoped_refptr<Resource> resource,
-                      VideoAdaptationReason reason)
-        : resource(resource), reason(reason) {}
-    virtual ~ResourceAndReason() = default;
-
-    const rtc::scoped_refptr<Resource> resource;
-    const VideoAdaptationReason reason;
-  };
-  mutable Mutex resource_lock_;
-  std::vector<ResourceAndReason> resources_ RTC_GUARDED_BY(&resource_lock_);
+  std::map<rtc::scoped_refptr<Resource>, VideoAdaptationReason> resources_
+      RTC_GUARDED_BY(&resource_lock_);
 };
 
 }  // namespace webrtc
diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc
index e64e1e9..323c9fb 100644
--- a/video/video_stream_encoder.cc
+++ b/video/video_stream_encoder.cc
@@ -34,6 +34,7 @@
 #include "rtc_base/arraysize.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/constructor_magic.h"
+#include "rtc_base/event.h"
 #include "rtc_base/experiments/alr_experiment.h"
 #include "rtc_base/experiments/rate_control_settings.h"
 #include "rtc_base/location.h"
@@ -386,9 +387,6 @@
 
     // Add the stream resource manager's resources to the processor.
     adaptation_constraints_ = stream_resource_manager_.AdaptationConstraints();
-    for (auto& resource : stream_resource_manager_.MappedResources()) {
-      resource_adaptation_processor_->AddResource(resource);
-    }
     for (auto* constraint : adaptation_constraints_) {
       video_stream_adapter_->AddAdaptationConstraint(constraint);
     }
@@ -407,11 +405,19 @@
   RTC_DCHECK_RUN_ON(&thread_checker_);
   video_source_sink_controller_.SetSource(nullptr);
 
-  if (resource_adaptation_processor_) {
-    for (auto& resource : stream_resource_manager_.MappedResources()) {
-      resource_adaptation_processor_->RemoveResource(resource);
-    }
-  }
+  encoder_queue_.PostTask([this] {
+    RTC_DCHECK_RUN_ON(&encoder_queue_);
+    stream_resource_manager_.StopManagedResources();
+    ShutdownResourceAdaptationQueue();
+    rate_allocator_ = nullptr;
+    bitrate_observer_ = nullptr;
+    ReleaseEncoder();
+    shutdown_event_.Set();
+  });
+  shutdown_event_.Wait(rtc::Event::kForever);
+}
+
+void VideoStreamEncoder::ShutdownResourceAdaptationQueue() {
   rtc::Event shutdown_adaptation_processor_event;
   resource_adaptation_queue_.PostTask([this,
                                        &shutdown_adaptation_processor_event] {
@@ -423,6 +429,10 @@
       for (auto* constraint : adaptation_constraints_) {
         video_stream_adapter_->RemoveAdaptationConstraint(constraint);
       }
+      for (auto& resource : additional_resources_) {
+        stream_resource_manager_.RemoveResource(resource);
+      }
+      additional_resources_.clear();
       video_stream_adapter_->RemoveRestrictionsListener(this);
       video_stream_adapter_->RemoveRestrictionsListener(
           &stream_resource_manager_);
@@ -435,15 +445,6 @@
     shutdown_adaptation_processor_event.Set();
   });
   shutdown_adaptation_processor_event.Wait(rtc::Event::kForever);
-  encoder_queue_.PostTask([this] {
-    RTC_DCHECK_RUN_ON(&encoder_queue_);
-    stream_resource_manager_.StopManagedResources();
-    rate_allocator_ = nullptr;
-    bitrate_observer_ = nullptr;
-    ReleaseEncoder();
-    shutdown_event_.Set();
-  });
-  shutdown_event_.Wait(rtc::Event::kForever);
 }
 
 void VideoStreamEncoder::SetBitrateAllocationObserver(
@@ -474,11 +475,10 @@
   // TODO(hbos): Make the manager map any unknown resources to kCpu and get rid
   // of this MapResourceToReason() call.
   rtc::Event map_resource_event;
-  encoder_queue_.PostTask([this, resource, &map_resource_event] {
-    RTC_DCHECK_RUN_ON(&encoder_queue_);
-    stream_resource_manager_.MapResourceToReason(resource,
-                                                 VideoAdaptationReason::kCpu);
-    resource_adaptation_processor_->AddResource(resource);
+  resource_adaptation_queue_.PostTask([this, resource, &map_resource_event] {
+    RTC_DCHECK_RUN_ON(&resource_adaptation_queue_);
+    additional_resources_.push_back(resource);
+    stream_resource_manager_.AddResource(resource, VideoAdaptationReason::kCpu);
     map_resource_event.Set();
   });
   map_resource_event.Wait(rtc::Event::kForever);
@@ -837,10 +837,6 @@
   }
 
   if (pending_encoder_creation_) {
-    // TODO(hbos): Stopping and restarting for backwards compatibility reasons.
-    // We may be able to change this to "EnsureStarted()" if it took care of
-    // reconfiguring the QualityScaler as well. (ConfigureQualityScaler() is
-    // invoked later in this method.)
     stream_resource_manager_.EnsureEncodeUsageResourceStarted();
     pending_encoder_creation_ = false;
   }
@@ -2084,12 +2080,13 @@
     rtc::scoped_refptr<Resource> resource,
     VideoAdaptationReason reason) {
   rtc::Event map_resource_event;
-  encoder_queue_.PostTask([this, resource, reason, &map_resource_event] {
-    RTC_DCHECK_RUN_ON(&encoder_queue_);
-    stream_resource_manager_.MapResourceToReason(resource, reason);
-    resource_adaptation_processor_->AddResource(resource);
-    map_resource_event.Set();
-  });
+  resource_adaptation_queue_.PostTask(
+      [this, resource, reason, &map_resource_event] {
+        RTC_DCHECK_RUN_ON(&resource_adaptation_queue_);
+        additional_resources_.push_back(resource);
+        stream_resource_manager_.AddResource(resource, reason);
+        map_resource_event.Set();
+      });
   map_resource_event.Wait(rtc::Event::kForever);
 }
 
@@ -2110,12 +2107,6 @@
   event.Wait(rtc::Event::kForever);
 }
 
-rtc::scoped_refptr<QualityScalerResource>
-VideoStreamEncoder::quality_scaler_resource_for_testing() {
-  RTC_DCHECK_RUN_ON(&encoder_queue_);
-  return stream_resource_manager_.quality_scaler_resource_for_testing();
-}
-
 void VideoStreamEncoder::AddRestrictionsListenerForTesting(
     VideoSourceRestrictionsListener* restrictions_listener) {
   rtc::Event event;
diff --git a/video/video_stream_encoder.h b/video/video_stream_encoder.h
index 5761896..c8ef1fe 100644
--- a/video/video_stream_encoder.h
+++ b/video/video_stream_encoder.h
@@ -40,6 +40,7 @@
 #include "rtc_base/rate_statistics.h"
 #include "rtc_base/synchronization/sequence_checker.h"
 #include "rtc_base/task_queue.h"
+#include "rtc_base/thread_annotations.h"
 #include "rtc_base/thread_checker.h"
 #include "system_wrappers/include/clock.h"
 #include "video/adaptation/video_stream_encoder_resource_manager.h"
@@ -128,9 +129,6 @@
                                 VideoAdaptationReason reason);
   void InjectAdaptationConstraint(AdaptationConstraint* adaptation_constraint);
 
-  rtc::scoped_refptr<QualityScalerResource>
-  quality_scaler_resource_for_testing();
-
   void AddRestrictionsListenerForTesting(
       VideoSourceRestrictionsListener* restrictions_listener);
   void RemoveRestrictionsListenerForTesting(
@@ -214,6 +212,8 @@
                      DataSize frame_size);
   bool HasInternalSource() const RTC_RUN_ON(&encoder_queue_);
   void ReleaseEncoder() RTC_RUN_ON(&encoder_queue_);
+  // After calling this function |resource_adaptation_processor_| will be null.
+  void ShutdownResourceAdaptationQueue();
 
   void CheckForAnimatedContent(const VideoFrame& frame,
                                int64_t time_when_posted_in_ms)
@@ -429,6 +429,8 @@
   // tied to the VideoStreamEncoder (which is destroyed off the encoder queue)
   // and its resource list is accessible from any thread.
   VideoStreamEncoderResourceManager stream_resource_manager_;
+  std::vector<rtc::scoped_refptr<Resource>> additional_resources_
+      RTC_GUARDED_BY(&resource_adaptation_queue_);
   // Carries out the VideoSourceRestrictions provided by the
   // ResourceAdaptationProcessor, i.e. reconfigures the source of video frames
   // to provide us with different resolution or frame rate.
diff --git a/video/video_stream_encoder_unittest.cc b/video/video_stream_encoder_unittest.cc
index 3007a69..c0719d4 100644
--- a/video/video_stream_encoder_unittest.cc
+++ b/video/video_stream_encoder_unittest.cc
@@ -4212,6 +4212,55 @@
 }
 
 TEST_F(VideoStreamEncoderTest,
+       QualityScalerAdaptationsRemovedWhenQualityScalingDisabled) {
+  AdaptingFrameForwarder source;
+  source.set_adaptation_enabled(true);
+  video_stream_encoder_->SetSource(&source,
+                                   DegradationPreference::MAINTAIN_FRAMERATE);
+  video_stream_encoder_->OnBitrateUpdatedAndWaitForManagedResources(
+      DataRate::BitsPerSec(kTargetBitrateBps),
+      DataRate::BitsPerSec(kTargetBitrateBps),
+      DataRate::BitsPerSec(kTargetBitrateBps), 0, 0, 0);
+  fake_encoder_.SetQp(kQpHigh + 1);
+  const int kWidth = 1280;
+  const int kHeight = 720;
+  const int64_t kFrameIntervalMs = 100;
+  int64_t timestamp_ms = kFrameIntervalMs;
+  for (size_t i = 1; i <= 100; i++) {
+    timestamp_ms += kFrameIntervalMs;
+    source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
+    WaitForEncodedFrame(timestamp_ms);
+  }
+  // Wait for QualityScaler, which will wait for 2000*2.5 ms until checking QP
+  // for the first time.
+  // TODO(eshr): We should avoid these waits by using threads with simulated
+  // time.
+  EXPECT_TRUE_WAIT(stats_proxy_->GetStats().bw_limited_resolution,
+                   2000 * 2.5 * 2);
+  timestamp_ms += kFrameIntervalMs;
+  source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
+  WaitForEncodedFrame(timestamp_ms);
+  video_stream_encoder_->WaitUntilTaskQueueIsIdle();
+  video_stream_encoder_->WaitUntilAdaptationTaskQueueIsIdle();
+  EXPECT_THAT(source.sink_wants(), WantsMaxPixels(Lt(kWidth * kHeight)));
+  EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
+
+  // Disable Quality scaling by turning off scaler on the encoder and
+  // reconfiguring.
+  fake_encoder_.SetQualityScaling(false);
+  video_stream_encoder_->ConfigureEncoder(video_encoder_config_.Copy(),
+                                          kMaxPayloadLength);
+  video_stream_encoder_->WaitUntilTaskQueueIsIdle();
+  video_stream_encoder_->WaitUntilAdaptationTaskQueueIsIdle();
+  // Since we turned off the quality scaler, the adaptations made by it are
+  // removed.
+  EXPECT_THAT(source.sink_wants(), ResolutionMax());
+  EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
+
+  video_stream_encoder_->Stop();
+}
+
+TEST_F(VideoStreamEncoderTest,
        ResolutionNotAdaptedForTooSmallFrame_MaintainFramerateMode) {
   const int kTooSmallWidth = 10;
   const int kTooSmallHeight = 10;