[Adaptation] Adapt up requires previous underuse
The problem is that a resource that signals Underuse would be able to trigger an adapt up when it was never limited in the past. This means that an underused resource would be able to negate the adaptations made for an overused one. For example, consider a fast CPU on a bad link. The QP for the image is high but the CPU is underused. Without requiring previous underuse, everytime the QP would signal overuse and trigger an adpatation down, the CPU would signal underuse and trigger an adaptation up. This works today as we want by using the active counts in the VideoStreamEncoderResourceManager. This change makes it a normal behaviour independant of active counts. The problem with active counts is that is only works with 2 resources. When resources are injectable it no longer works as expected. Bug: webrtc:11522, webrtc:11523 Change-Id: I140636ce206d74e00a6b6f8558162bb8afffda1c Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/174482 Commit-Queue: Evan Shrubsole <eshr@google.com> Reviewed-by: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/master@{#31181}
This commit is contained in:

committed by
Commit Bot

parent
ab866a2ccb
commit
0dcb470cfe
@ -29,7 +29,7 @@ ResourceAdaptationProcessor::ResourceAdaptationProcessor(
|
||||
last_reported_source_restrictions_(),
|
||||
processing_in_progress_(false) {}
|
||||
|
||||
ResourceAdaptationProcessor::~ResourceAdaptationProcessor() {}
|
||||
ResourceAdaptationProcessor::~ResourceAdaptationProcessor() = default;
|
||||
|
||||
DegradationPreference ResourceAdaptationProcessor::degradation_preference()
|
||||
const {
|
||||
@ -85,22 +85,26 @@ void ResourceAdaptationProcessor::MaybeUpdateEffectiveDegradationPreference() {
|
||||
|
||||
void ResourceAdaptationProcessor::ResetVideoSourceRestrictions() {
|
||||
stream_adapter_->ClearRestrictions();
|
||||
adaptations_counts_by_resource_.clear();
|
||||
MaybeUpdateVideoSourceRestrictions(nullptr);
|
||||
}
|
||||
|
||||
void ResourceAdaptationProcessor::MaybeUpdateVideoSourceRestrictions(
|
||||
const Resource* reason) {
|
||||
VideoSourceRestrictions new_soure_restrictions =
|
||||
VideoSourceRestrictions new_source_restrictions =
|
||||
FilterRestrictionsByDegradationPreference(
|
||||
stream_adapter_->source_restrictions(),
|
||||
effective_degradation_preference_);
|
||||
if (last_reported_source_restrictions_ != new_soure_restrictions) {
|
||||
last_reported_source_restrictions_ = std::move(new_soure_restrictions);
|
||||
if (last_reported_source_restrictions_ != new_source_restrictions) {
|
||||
last_reported_source_restrictions_ = std::move(new_source_restrictions);
|
||||
for (auto* adaptation_listener : adaptation_listeners_) {
|
||||
adaptation_listener->OnVideoSourceRestrictionsUpdated(
|
||||
last_reported_source_restrictions_,
|
||||
stream_adapter_->adaptation_counters(), reason);
|
||||
}
|
||||
if (reason) {
|
||||
UpdateResourceDegradationCounts(reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,6 +146,10 @@ void ResourceAdaptationProcessor::OnResourceUnderuse(
|
||||
processing_in_progress_ = false;
|
||||
return;
|
||||
}
|
||||
if (!IsResourceAllowedToAdaptUp(&reason_resource)) {
|
||||
processing_in_progress_ = false;
|
||||
return;
|
||||
}
|
||||
// Update video input states and encoder settings for accurate adaptation.
|
||||
stream_adapter_->SetInput(input_state);
|
||||
// How can this stream be adapted up?
|
||||
@ -202,8 +210,9 @@ void ResourceAdaptationProcessor::OnResourceOveruse(
|
||||
stream_adapter_->SetInput(input_state);
|
||||
// How can this stream be adapted up?
|
||||
Adaptation adaptation = stream_adapter_->GetAdaptationDown();
|
||||
if (adaptation.min_pixel_limit_reached())
|
||||
if (adaptation.min_pixel_limit_reached()) {
|
||||
encoder_stats_observer_->OnMinPixelLimitReached();
|
||||
}
|
||||
if (adaptation.status() != Adaptation::Status::kValid) {
|
||||
processing_in_progress_ = false;
|
||||
return;
|
||||
@ -242,4 +251,25 @@ void ResourceAdaptationProcessor::TriggerAdaptationDueToFrameDroppedDueToSize(
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceAdaptationProcessor::UpdateResourceDegradationCounts(
|
||||
const Resource* resource) {
|
||||
RTC_DCHECK(resource);
|
||||
int delta = stream_adapter_->adaptation_counters().Total();
|
||||
for (const auto& adaptations : adaptations_counts_by_resource_) {
|
||||
delta -= adaptations.second;
|
||||
}
|
||||
|
||||
// Default value is 0, inserts the value if missing.
|
||||
adaptations_counts_by_resource_[resource] += delta;
|
||||
RTC_DCHECK_GE(adaptations_counts_by_resource_[resource], 0);
|
||||
}
|
||||
|
||||
bool ResourceAdaptationProcessor::IsResourceAllowedToAdaptUp(
|
||||
const Resource* resource) const {
|
||||
RTC_DCHECK(resource);
|
||||
const auto& adaptations = adaptations_counts_by_resource_.find(resource);
|
||||
return adaptations != adaptations_counts_by_resource_.end() &&
|
||||
adaptations->second > 0;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -11,6 +11,7 @@
|
||||
#ifndef CALL_ADAPTATION_RESOURCE_ADAPTATION_PROCESSOR_H_
|
||||
#define CALL_ADAPTATION_RESOURCE_ADAPTATION_PROCESSOR_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@ -76,12 +77,24 @@ class ResourceAdaptationProcessor : public ResourceAdaptationProcessorInterface,
|
||||
// If the filtered source restrictions are different than
|
||||
// |last_reported_source_restrictions_|, inform the listeners.
|
||||
void MaybeUpdateVideoSourceRestrictions(const Resource* reason);
|
||||
// Updates the number of times the resource has degraded based on the latest
|
||||
// degradation applied.
|
||||
void UpdateResourceDegradationCounts(const Resource* resource);
|
||||
// Returns true if a Resource has been overused in the pass and is responsible
|
||||
// for creating a VideoSourceRestriction. The current algorithm counts the
|
||||
// number of times the resource caused an adaptation and allows adapting up
|
||||
// if that number is non-zero. This is consistent with how adaptation has
|
||||
// traditionally been handled.
|
||||
// TODO(crbug.com/webrtc/11553) Change this algorithm to look at the resources
|
||||
// restrictions rather than just the counters.
|
||||
bool IsResourceAllowedToAdaptUp(const Resource* resource) const;
|
||||
|
||||
// Input and output.
|
||||
VideoStreamInputStateProvider* const input_state_provider_;
|
||||
VideoStreamEncoderObserver* const encoder_stats_observer_;
|
||||
std::vector<ResourceAdaptationProcessorListener*> adaptation_listeners_;
|
||||
std::vector<Resource*> resources_;
|
||||
std::map<const Resource*, int> adaptations_counts_by_resource_;
|
||||
// Adaptation strategy settings.
|
||||
DegradationPreference degradation_preference_;
|
||||
DegradationPreference effective_degradation_preference_;
|
||||
|
@ -69,10 +69,12 @@ class ResourceAdaptationProcessorTest : public ::testing::Test {
|
||||
: frame_rate_provider_(),
|
||||
input_state_provider_(&frame_rate_provider_),
|
||||
resource_("FakeResource"),
|
||||
other_resource_("OtherFakeResource"),
|
||||
processor_(&input_state_provider_,
|
||||
/*encoder_stats_observer=*/&frame_rate_provider_) {
|
||||
processor_.AddAdaptationListener(&processor_listener_);
|
||||
processor_.AddResource(&resource_);
|
||||
processor_.AddResource(&other_resource_);
|
||||
}
|
||||
~ResourceAdaptationProcessorTest() override {
|
||||
processor_.StopResourceAdaptation();
|
||||
@ -96,6 +98,7 @@ class ResourceAdaptationProcessorTest : public ::testing::Test {
|
||||
FakeFrameRateProvider frame_rate_provider_;
|
||||
VideoStreamInputStateProvider input_state_provider_;
|
||||
FakeResource resource_;
|
||||
FakeResource other_resource_;
|
||||
ResourceAdaptationProcessor processor_;
|
||||
ResourceAdaptationProcessorListenerForTesting processor_listener_;
|
||||
};
|
||||
@ -226,6 +229,74 @@ TEST_F(ResourceAdaptationProcessorTest, ResourcesCanPreventAdaptingUp) {
|
||||
EXPECT_EQ(1u, processor_listener_.restrictions_updated_count());
|
||||
}
|
||||
|
||||
TEST_F(ResourceAdaptationProcessorTest,
|
||||
ResourcesCanNotAdaptUpIfNeverAdaptedDown) {
|
||||
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());
|
||||
|
||||
// Other resource signals under-use
|
||||
other_resource_.set_usage_state(ResourceUsageState::kUnderuse);
|
||||
EXPECT_EQ(1u, processor_listener_.restrictions_updated_count());
|
||||
}
|
||||
|
||||
TEST_F(ResourceAdaptationProcessorTest,
|
||||
ResourcesCanNotAdaptUpIfNotAdaptedDownAfterReset) {
|
||||
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());
|
||||
|
||||
processor_.ResetVideoSourceRestrictions();
|
||||
EXPECT_EQ(0, processor_listener_.adaptation_counters().Total());
|
||||
other_resource_.set_usage_state(ResourceUsageState::kOveruse);
|
||||
EXPECT_EQ(1, processor_listener_.adaptation_counters().Total());
|
||||
RestrictSource(processor_listener_.restrictions());
|
||||
|
||||
// resource_ did not overuse after we reset the restrictions, so adapt up
|
||||
// should be disallowed.
|
||||
resource_.set_usage_state(ResourceUsageState::kUnderuse);
|
||||
EXPECT_EQ(1, processor_listener_.adaptation_counters().Total());
|
||||
}
|
||||
|
||||
TEST_F(ResourceAdaptationProcessorTest,
|
||||
MultipleResourcesCanTriggerMultipleAdaptations) {
|
||||
processor_.SetDegradationPreference(
|
||||
DegradationPreference::MAINTAIN_FRAMERATE);
|
||||
processor_.StartResourceAdaptation();
|
||||
SetInputStates(true, kDefaultFrameRate, kDefaultFrameSize);
|
||||
resource_.set_usage_state(ResourceUsageState::kOveruse);
|
||||
EXPECT_EQ(1, processor_listener_.adaptation_counters().Total());
|
||||
RestrictSource(processor_listener_.restrictions());
|
||||
other_resource_.set_usage_state(ResourceUsageState::kOveruse);
|
||||
EXPECT_EQ(2, processor_listener_.adaptation_counters().Total());
|
||||
RestrictSource(processor_listener_.restrictions());
|
||||
other_resource_.set_usage_state(ResourceUsageState::kOveruse);
|
||||
EXPECT_EQ(3, processor_listener_.adaptation_counters().Total());
|
||||
RestrictSource(processor_listener_.restrictions());
|
||||
|
||||
resource_.set_usage_state(ResourceUsageState::kUnderuse);
|
||||
EXPECT_EQ(2, processor_listener_.adaptation_counters().Total());
|
||||
RestrictSource(processor_listener_.restrictions());
|
||||
// Does not trigger adaptation since resource has no adaptations left.
|
||||
resource_.set_usage_state(ResourceUsageState::kUnderuse);
|
||||
EXPECT_EQ(2, processor_listener_.adaptation_counters().Total());
|
||||
RestrictSource(processor_listener_.restrictions());
|
||||
|
||||
other_resource_.set_usage_state(ResourceUsageState::kUnderuse);
|
||||
EXPECT_EQ(1, processor_listener_.adaptation_counters().Total());
|
||||
RestrictSource(processor_listener_.restrictions());
|
||||
other_resource_.set_usage_state(ResourceUsageState::kUnderuse);
|
||||
EXPECT_EQ(0, processor_listener_.adaptation_counters().Total());
|
||||
RestrictSource(processor_listener_.restrictions());
|
||||
}
|
||||
|
||||
TEST_F(ResourceAdaptationProcessorTest, AdaptingTriggersOnAdaptationApplied) {
|
||||
processor_.SetDegradationPreference(
|
||||
DegradationPreference::MAINTAIN_FRAMERATE);
|
||||
|
Reference in New Issue
Block a user