[Adaptation] Move input state into VideoStreamAdapter

Bug: webrtc:11700
Change-Id: I81a060b914f91f6724f13a9b672234c9c4a65fae
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/177104
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Evan Shrubsole <eshr@google.com>
Cr-Commit-Position: refs/heads/master@{#31616}
This commit is contained in:
Evan Shrubsole
2020-07-02 14:42:09 +02:00
committed by Commit Bot
parent ec0af26ff8
commit 34b1a42de8
9 changed files with 474 additions and 448 deletions

View File

@ -68,13 +68,11 @@ ResourceAdaptationProcessor::MitigationResultAndLogMessage::
: result(result), message(std::move(message)) {} : result(result), message(std::move(message)) {}
ResourceAdaptationProcessor::ResourceAdaptationProcessor( ResourceAdaptationProcessor::ResourceAdaptationProcessor(
VideoStreamInputStateProvider* input_state_provider,
VideoStreamEncoderObserver* encoder_stats_observer, VideoStreamEncoderObserver* encoder_stats_observer,
VideoStreamAdapter* stream_adapter) VideoStreamAdapter* stream_adapter)
: resource_adaptation_queue_(nullptr), : resource_adaptation_queue_(nullptr),
resource_listener_delegate_( resource_listener_delegate_(
new rtc::RefCountedObject<ResourceListenerDelegate>(this)), new rtc::RefCountedObject<ResourceListenerDelegate>(this)),
input_state_provider_(input_state_provider),
encoder_stats_observer_(encoder_stats_observer), encoder_stats_observer_(encoder_stats_observer),
resources_(), resources_(),
degradation_preference_(DegradationPreference::DISABLED), degradation_preference_(DegradationPreference::DISABLED),
@ -279,15 +277,6 @@ void ResourceAdaptationProcessor::OnResourceUsageStateMeasured(
} }
} }
bool ResourceAdaptationProcessor::HasSufficientInputForAdaptation(
const VideoStreamInputState& input_state) const {
RTC_DCHECK_RUN_ON(resource_adaptation_queue_);
return input_state.HasInputFrameSizeAndFramesPerSecond() &&
(effective_degradation_preference_ !=
DegradationPreference::MAINTAIN_RESOLUTION ||
input_state.frames_per_second() >= kMinFrameRateFps);
}
ResourceAdaptationProcessor::MitigationResultAndLogMessage ResourceAdaptationProcessor::MitigationResultAndLogMessage
ResourceAdaptationProcessor::OnResourceUnderuse( ResourceAdaptationProcessor::OnResourceUnderuse(
rtc::scoped_refptr<Resource> reason_resource) { rtc::scoped_refptr<Resource> reason_resource) {
@ -300,15 +289,6 @@ ResourceAdaptationProcessor::OnResourceUnderuse(
MitigationResult::kDisabled, MitigationResult::kDisabled,
"Not adapting up because DegradationPreference is disabled"); "Not adapting up because DegradationPreference is disabled");
} }
VideoStreamInputState input_state = input_state_provider_->InputState();
if (!HasSufficientInputForAdaptation(input_state)) {
processing_in_progress_ = false;
return MitigationResultAndLogMessage(
MitigationResult::kInsufficientInput,
"Not adapting up because input is insufficient");
}
// Update video input states and encoder settings for accurate adaptation.
stream_adapter_->SetInput(input_state);
// How can this stream be adapted up? // How can this stream be adapted up?
Adaptation adaptation = stream_adapter_->GetAdaptationUp(); Adaptation adaptation = stream_adapter_->GetAdaptationUp();
if (adaptation.status() != Adaptation::Status::kValid) { if (adaptation.status() != Adaptation::Status::kValid) {
@ -331,8 +311,8 @@ ResourceAdaptationProcessor::OnResourceUnderuse(
FindMostLimitedResources(); FindMostLimitedResources();
for (const auto* constraint : adaptation_constraints_) { for (const auto* constraint : adaptation_constraints_) {
if (!constraint->IsAdaptationUpAllowed(input_state, restrictions_before, if (!constraint->IsAdaptationUpAllowed(
restrictions_after, adaptation.input_state(), restrictions_before, restrictions_after,
reason_resource)) { reason_resource)) {
processing_in_progress_ = false; processing_in_progress_ = false;
rtc::StringBuilder message; rtc::StringBuilder message;
@ -375,7 +355,8 @@ ResourceAdaptationProcessor::OnResourceUnderuse(
stream_adapter_->ApplyAdaptation(adaptation, reason_resource); stream_adapter_->ApplyAdaptation(adaptation, reason_resource);
for (auto* adaptation_listener : adaptation_listeners_) { for (auto* adaptation_listener : adaptation_listeners_) {
adaptation_listener->OnAdaptationApplied( adaptation_listener->OnAdaptationApplied(
input_state, restrictions_before, restrictions_after, reason_resource); adaptation.input_state(), restrictions_before, restrictions_after,
reason_resource);
} }
processing_in_progress_ = false; processing_in_progress_ = false;
rtc::StringBuilder message; rtc::StringBuilder message;
@ -397,15 +378,6 @@ ResourceAdaptationProcessor::OnResourceOveruse(
MitigationResult::kDisabled, MitigationResult::kDisabled,
"Not adapting down because DegradationPreference is disabled"); "Not adapting down because DegradationPreference is disabled");
} }
VideoStreamInputState input_state = input_state_provider_->InputState();
if (!HasSufficientInputForAdaptation(input_state)) {
processing_in_progress_ = false;
return MitigationResultAndLogMessage(
MitigationResult::kInsufficientInput,
"Not adapting down because input is insufficient");
}
// Update video input states and encoder settings for accurate adaptation.
stream_adapter_->SetInput(input_state);
// How can this stream be adapted up? // How can this stream be adapted up?
Adaptation adaptation = stream_adapter_->GetAdaptationDown(); Adaptation adaptation = stream_adapter_->GetAdaptationDown();
if (adaptation.min_pixel_limit_reached()) { if (adaptation.min_pixel_limit_reached()) {
@ -429,7 +401,8 @@ ResourceAdaptationProcessor::OnResourceOveruse(
stream_adapter_->ApplyAdaptation(adaptation, reason_resource); stream_adapter_->ApplyAdaptation(adaptation, reason_resource);
for (auto* adaptation_listener : adaptation_listeners_) { for (auto* adaptation_listener : adaptation_listeners_) {
adaptation_listener->OnAdaptationApplied( adaptation_listener->OnAdaptationApplied(
input_state, restrictions_before, restrictions_after, reason_resource); adaptation.input_state(), restrictions_before, restrictions_after,
reason_resource);
} }
processing_in_progress_ = false; processing_in_progress_ = false;
rtc::StringBuilder message; rtc::StringBuilder message;
@ -527,10 +500,9 @@ void ResourceAdaptationProcessor::
most_limited.adaptation_counters, most_limited.restrictions); most_limited.adaptation_counters, most_limited.restrictions);
RTC_DCHECK_EQ(adapt_to.status(), Adaptation::Status::kValid); RTC_DCHECK_EQ(adapt_to.status(), Adaptation::Status::kValid);
stream_adapter_->ApplyAdaptation(adapt_to, nullptr); stream_adapter_->ApplyAdaptation(adapt_to, nullptr);
auto input_state = input_state_provider_->InputState();
for (auto* adaptation_listener : adaptation_listeners_) { for (auto* adaptation_listener : adaptation_listeners_) {
adaptation_listener->OnAdaptationApplied( adaptation_listener->OnAdaptationApplied(
input_state, removed_limitations.restrictions, adapt_to.input_state(), removed_limitations.restrictions,
most_limited.restrictions, nullptr); most_limited.restrictions, nullptr);
} }

View File

@ -55,7 +55,6 @@ class ResourceAdaptationProcessor : public ResourceAdaptationProcessorInterface,
public ResourceListener { public ResourceListener {
public: public:
ResourceAdaptationProcessor( ResourceAdaptationProcessor(
VideoStreamInputStateProvider* input_state_provider,
VideoStreamEncoderObserver* encoder_stats_observer, VideoStreamEncoderObserver* encoder_stats_observer,
VideoStreamAdapter* video_stream_adapter); VideoStreamAdapter* video_stream_adapter);
~ResourceAdaptationProcessor() override; ~ResourceAdaptationProcessor() override;
@ -105,9 +104,6 @@ class ResourceAdaptationProcessor : public ResourceAdaptationProcessorInterface,
rtc::scoped_refptr<Resource> reason_resource) override; rtc::scoped_refptr<Resource> reason_resource) override;
private: private:
bool HasSufficientInputForAdaptation(
const VideoStreamInputState& input_state) const;
// If resource usage measurements happens off the adaptation task queue, this // If resource usage measurements happens off the adaptation task queue, this
// class takes care of posting the measurement for the processor to handle it // class takes care of posting the measurement for the processor to handle it
// on the adaptation task queue. // on the adaptation task queue.
@ -131,7 +127,6 @@ class ResourceAdaptationProcessor : public ResourceAdaptationProcessorInterface,
enum class MitigationResult { enum class MitigationResult {
kDisabled, kDisabled,
kInsufficientInput,
kNotMostLimitedResource, kNotMostLimitedResource,
kSharedMostLimitedResource, kSharedMostLimitedResource,
kRejectedByAdapter, kRejectedByAdapter,
@ -179,8 +174,6 @@ class ResourceAdaptationProcessor : public ResourceAdaptationProcessorInterface,
TaskQueueBase* resource_adaptation_queue_; TaskQueueBase* resource_adaptation_queue_;
rtc::scoped_refptr<ResourceListenerDelegate> resource_listener_delegate_; rtc::scoped_refptr<ResourceListenerDelegate> resource_listener_delegate_;
// Input and output. // Input and output.
VideoStreamInputStateProvider* const input_state_provider_
RTC_GUARDED_BY(resource_adaptation_queue_);
VideoStreamEncoderObserver* const encoder_stats_observer_ VideoStreamEncoderObserver* const encoder_stats_observer_
RTC_GUARDED_BY(resource_adaptation_queue_); RTC_GUARDED_BY(resource_adaptation_queue_);
std::vector<ResourceLimitationsListener*> resource_limitations_listeners_ std::vector<ResourceLimitationsListener*> resource_limitations_listeners_

View File

@ -92,9 +92,9 @@ class ResourceAdaptationProcessorTest : public ::testing::Test {
other_resource_(FakeResource::Create("OtherFakeResource")), other_resource_(FakeResource::Create("OtherFakeResource")),
adaptation_constraint_("FakeAdaptationConstraint"), adaptation_constraint_("FakeAdaptationConstraint"),
adaptation_listener_(), adaptation_listener_(),
video_stream_adapter_(std::make_unique<VideoStreamAdapter>()), video_stream_adapter_(
std::make_unique<VideoStreamAdapter>(&input_state_provider_)),
processor_(std::make_unique<ResourceAdaptationProcessor>( processor_(std::make_unique<ResourceAdaptationProcessor>(
&input_state_provider_,
/*encoder_stats_observer=*/&frame_rate_provider_, /*encoder_stats_observer=*/&frame_rate_provider_,
video_stream_adapter_.get())) { video_stream_adapter_.get())) {
processor_->SetResourceAdaptationQueue(TaskQueueBase::Current()); processor_->SetResourceAdaptationQueue(TaskQueueBase::Current());

View File

@ -100,6 +100,8 @@ const char* Adaptation::StatusToString(Adaptation::Status status) {
return "kLimitReached"; return "kLimitReached";
case Adaptation::Status::kAwaitingPreviousAdaptation: case Adaptation::Status::kAwaitingPreviousAdaptation:
return "kAwaitingPreviousAdaptation"; return "kAwaitingPreviousAdaptation";
case Status::kInsufficientInput:
return "kInsufficientInput";
} }
} }
@ -113,35 +115,45 @@ Adaptation::Step::Step(VideoSourceRestrictions restrictions,
restrictions(restrictions), restrictions(restrictions),
counters(counters) {} counters(counters) {}
Adaptation::Adaptation(int validation_id, Step step) Adaptation::Adaptation(int validation_id,
Step step,
VideoStreamInputState input_state)
: validation_id_(validation_id), : validation_id_(validation_id),
status_(Status::kValid), status_(Status::kValid),
step_(std::move(step)), step_(std::move(step)),
min_pixel_limit_reached_(false) {} min_pixel_limit_reached_(false),
input_state_(input_state) {}
Adaptation::Adaptation(int validation_id, Adaptation::Adaptation(int validation_id,
Step step, Step step,
VideoStreamInputState input_state,
bool min_pixel_limit_reached) bool min_pixel_limit_reached)
: validation_id_(validation_id), : validation_id_(validation_id),
status_(Status::kValid), status_(Status::kValid),
step_(std::move(step)), step_(std::move(step)),
min_pixel_limit_reached_(min_pixel_limit_reached) {} min_pixel_limit_reached_(min_pixel_limit_reached),
input_state_(input_state) {}
Adaptation::Adaptation(int validation_id, Status invalid_status) Adaptation::Adaptation(int validation_id,
Status invalid_status,
VideoStreamInputState input_state)
: validation_id_(validation_id), : validation_id_(validation_id),
status_(invalid_status), status_(invalid_status),
step_(absl::nullopt), step_(absl::nullopt),
min_pixel_limit_reached_(false) { min_pixel_limit_reached_(false),
input_state_(input_state) {
RTC_DCHECK_NE(status_, Status::kValid); RTC_DCHECK_NE(status_, Status::kValid);
} }
Adaptation::Adaptation(int validation_id, Adaptation::Adaptation(int validation_id,
Status invalid_status, Status invalid_status,
VideoStreamInputState input_state,
bool min_pixel_limit_reached) bool min_pixel_limit_reached)
: validation_id_(validation_id), : validation_id_(validation_id),
status_(invalid_status), status_(invalid_status),
step_(absl::nullopt), step_(absl::nullopt),
min_pixel_limit_reached_(min_pixel_limit_reached) { min_pixel_limit_reached_(min_pixel_limit_reached),
input_state_(input_state) {
RTC_DCHECK_NE(status_, Status::kValid); RTC_DCHECK_NE(status_, Status::kValid);
} }
@ -157,6 +169,9 @@ const Adaptation::Step& Adaptation::step() const {
RTC_DCHECK_EQ(status_, Status::kValid); RTC_DCHECK_EQ(status_, Status::kValid);
return step_.value(); return step_.value();
} }
const VideoStreamInputState& Adaptation::input_state() const {
return input_state_;
}
// VideoSourceRestrictor is responsible for keeping track of current // VideoSourceRestrictor is responsible for keeping track of current
// VideoSourceRestrictions. // VideoSourceRestrictions.
@ -329,12 +344,13 @@ class VideoStreamAdapter::VideoSourceRestrictor {
VideoAdaptationCounters adaptations_; VideoAdaptationCounters adaptations_;
}; };
VideoStreamAdapter::VideoStreamAdapter() VideoStreamAdapter::VideoStreamAdapter(
VideoStreamInputStateProvider* input_state_provider)
: source_restrictor_(std::make_unique<VideoSourceRestrictor>()), : source_restrictor_(std::make_unique<VideoSourceRestrictor>()),
input_state_provider_(input_state_provider),
balanced_settings_(), balanced_settings_(),
adaptation_validation_id_(0), adaptation_validation_id_(0),
degradation_preference_(DegradationPreference::DISABLED), degradation_preference_(DegradationPreference::DISABLED),
input_state_(),
last_adaptation_request_(absl::nullopt), last_adaptation_request_(absl::nullopt),
last_video_source_restrictions_() { last_video_source_restrictions_() {
sequence_checker_.Detach(); sequence_checker_.Detach();
@ -399,29 +415,28 @@ void VideoStreamAdapter::SetDegradationPreference(
} }
} }
void VideoStreamAdapter::SetInput(VideoStreamInputState input_state) { Adaptation VideoStreamAdapter::GetAdaptationUp() {
// Invalidate any previously returned Adaptation.
RTC_DCHECK_RUN_ON(&sequence_checker_);
++adaptation_validation_id_;
input_state_ = input_state;
source_restrictor_->set_min_pixels_per_frame(
input_state_.min_pixels_per_frame());
}
Adaptation VideoStreamAdapter::GetAdaptationUp() const {
RTC_DCHECK_RUN_ON(&sequence_checker_); RTC_DCHECK_RUN_ON(&sequence_checker_);
RTC_DCHECK_NE(degradation_preference_, DegradationPreference::DISABLED); RTC_DCHECK_NE(degradation_preference_, DegradationPreference::DISABLED);
RTC_DCHECK(input_state_.HasInputFrameSizeAndFramesPerSecond()); VideoStreamInputState input_state = input_state_provider_->InputState();
++adaptation_validation_id_;
if (!HasSufficientInputForAdaptation(input_state)) {
return Adaptation(adaptation_validation_id_,
Adaptation::Status::kInsufficientInput, input_state);
}
source_restrictor_->set_min_pixels_per_frame(
input_state.min_pixels_per_frame());
// Don't adapt if we're awaiting a previous adaptation to have an effect. // Don't adapt if we're awaiting a previous adaptation to have an effect.
bool last_request_increased_resolution = bool last_request_increased_resolution =
last_adaptation_request_ && last_adaptation_request_->step_type_ == last_adaptation_request_ && last_adaptation_request_->step_type_ ==
Adaptation::StepType::kIncreaseResolution; Adaptation::StepType::kIncreaseResolution;
if (last_request_increased_resolution && if (last_request_increased_resolution &&
degradation_preference_ == DegradationPreference::MAINTAIN_FRAMERATE && degradation_preference_ == DegradationPreference::MAINTAIN_FRAMERATE &&
input_state_.frame_size_pixels().value() <= input_state.frame_size_pixels().value() <=
last_adaptation_request_->input_pixel_count_) { last_adaptation_request_->input_pixel_count_) {
return Adaptation(adaptation_validation_id_, return Adaptation(adaptation_validation_id_,
Adaptation::Status::kAwaitingPreviousAdaptation); Adaptation::Status::kAwaitingPreviousAdaptation,
input_state);
} }
// Maybe propose targets based on degradation preference. // Maybe propose targets based on degradation preference.
@ -429,20 +444,21 @@ Adaptation VideoStreamAdapter::GetAdaptationUp() const {
case DegradationPreference::BALANCED: { case DegradationPreference::BALANCED: {
// Attempt to increase target frame rate. // Attempt to increase target frame rate.
int target_fps = int target_fps =
balanced_settings_.MaxFps(input_state_.video_codec_type(), balanced_settings_.MaxFps(input_state.video_codec_type(),
input_state_.frame_size_pixels().value()); input_state.frame_size_pixels().value());
if (source_restrictor_->CanIncreaseFrameRateTo(target_fps)) { if (source_restrictor_->CanIncreaseFrameRateTo(target_fps)) {
return Adaptation( return Adaptation(
adaptation_validation_id_, adaptation_validation_id_,
Adaptation::Step(Adaptation::StepType::kIncreaseFrameRate, Adaptation::Step(Adaptation::StepType::kIncreaseFrameRate,
target_fps)); target_fps),
input_state);
} }
// Scale up resolution. // Scale up resolution.
ABSL_FALLTHROUGH_INTENDED; ABSL_FALLTHROUGH_INTENDED;
} }
case DegradationPreference::MAINTAIN_FRAMERATE: { case DegradationPreference::MAINTAIN_FRAMERATE: {
// Attempt to increase pixel count. // Attempt to increase pixel count.
int target_pixels = input_state_.frame_size_pixels().value(); int target_pixels = input_state.frame_size_pixels().value();
if (source_restrictor_->adaptation_counters().resolution_adaptations == if (source_restrictor_->adaptation_counters().resolution_adaptations ==
1) { 1) {
RTC_LOG(LS_INFO) << "Removing resolution down-scaling setting."; RTC_LOG(LS_INFO) << "Removing resolution down-scaling setting.";
@ -451,16 +467,17 @@ Adaptation VideoStreamAdapter::GetAdaptationUp() const {
target_pixels = GetHigherResolutionThan(target_pixels); target_pixels = GetHigherResolutionThan(target_pixels);
if (!source_restrictor_->CanIncreaseResolutionTo(target_pixels)) { if (!source_restrictor_->CanIncreaseResolutionTo(target_pixels)) {
return Adaptation(adaptation_validation_id_, return Adaptation(adaptation_validation_id_,
Adaptation::Status::kLimitReached); Adaptation::Status::kLimitReached, input_state);
} }
return Adaptation( return Adaptation(
adaptation_validation_id_, adaptation_validation_id_,
Adaptation::Step(Adaptation::StepType::kIncreaseResolution, Adaptation::Step(Adaptation::StepType::kIncreaseResolution,
target_pixels)); target_pixels),
input_state);
} }
case DegradationPreference::MAINTAIN_RESOLUTION: { case DegradationPreference::MAINTAIN_RESOLUTION: {
// Scale up framerate. // Scale up framerate.
int target_fps = input_state_.frames_per_second(); int target_fps = input_state.frames_per_second();
if (source_restrictor_->adaptation_counters().fps_adaptations == 1) { if (source_restrictor_->adaptation_counters().fps_adaptations == 1) {
RTC_LOG(LS_INFO) << "Removing framerate down-scaling setting."; RTC_LOG(LS_INFO) << "Removing framerate down-scaling setting.";
target_fps = std::numeric_limits<int>::max(); target_fps = std::numeric_limits<int>::max();
@ -468,24 +485,32 @@ Adaptation VideoStreamAdapter::GetAdaptationUp() const {
target_fps = GetHigherFrameRateThan(target_fps); target_fps = GetHigherFrameRateThan(target_fps);
if (!source_restrictor_->CanIncreaseFrameRateTo(target_fps)) { if (!source_restrictor_->CanIncreaseFrameRateTo(target_fps)) {
return Adaptation(adaptation_validation_id_, return Adaptation(adaptation_validation_id_,
Adaptation::Status::kLimitReached); Adaptation::Status::kLimitReached, input_state);
} }
return Adaptation( return Adaptation(
adaptation_validation_id_, adaptation_validation_id_,
Adaptation::Step(Adaptation::StepType::kIncreaseFrameRate, Adaptation::Step(Adaptation::StepType::kIncreaseFrameRate,
target_fps)); target_fps),
input_state);
} }
case DegradationPreference::DISABLED: case DegradationPreference::DISABLED:
RTC_NOTREACHED(); RTC_NOTREACHED();
return Adaptation(adaptation_validation_id_, return Adaptation(adaptation_validation_id_,
Adaptation::Status::kLimitReached); Adaptation::Status::kLimitReached, input_state);
} }
} }
Adaptation VideoStreamAdapter::GetAdaptationDown() const { Adaptation VideoStreamAdapter::GetAdaptationDown() {
RTC_DCHECK_RUN_ON(&sequence_checker_); RTC_DCHECK_RUN_ON(&sequence_checker_);
RTC_DCHECK_NE(degradation_preference_, DegradationPreference::DISABLED); RTC_DCHECK_NE(degradation_preference_, DegradationPreference::DISABLED);
RTC_DCHECK(input_state_.HasInputFrameSizeAndFramesPerSecond()); VideoStreamInputState input_state = input_state_provider_->InputState();
++adaptation_validation_id_;
if (!HasSufficientInputForAdaptation(input_state)) {
return Adaptation(adaptation_validation_id_,
Adaptation::Status::kInsufficientInput, input_state);
}
source_restrictor_->set_min_pixels_per_frame(
input_state.min_pixels_per_frame());
// Don't adapt if we're awaiting a previous adaptation to have an effect or // Don't adapt if we're awaiting a previous adaptation to have an effect or
// if we switched degradation preference. // if we switched degradation preference.
bool last_request_decreased_resolution = bool last_request_decreased_resolution =
@ -493,10 +518,11 @@ Adaptation VideoStreamAdapter::GetAdaptationDown() const {
Adaptation::StepType::kDecreaseResolution; Adaptation::StepType::kDecreaseResolution;
if (last_request_decreased_resolution && if (last_request_decreased_resolution &&
degradation_preference_ == DegradationPreference::MAINTAIN_FRAMERATE && degradation_preference_ == DegradationPreference::MAINTAIN_FRAMERATE &&
input_state_.frame_size_pixels().value() >= input_state.frame_size_pixels().value() >=
last_adaptation_request_->input_pixel_count_) { last_adaptation_request_->input_pixel_count_) {
return Adaptation(adaptation_validation_id_, return Adaptation(adaptation_validation_id_,
Adaptation::Status::kAwaitingPreviousAdaptation); Adaptation::Status::kAwaitingPreviousAdaptation,
input_state);
} }
// Maybe propose targets based on degradation preference. // Maybe propose targets based on degradation preference.
@ -504,13 +530,14 @@ Adaptation VideoStreamAdapter::GetAdaptationDown() const {
case DegradationPreference::BALANCED: { case DegradationPreference::BALANCED: {
// Try scale down framerate, if lower. // Try scale down framerate, if lower.
int target_fps = int target_fps =
balanced_settings_.MinFps(input_state_.video_codec_type(), balanced_settings_.MinFps(input_state.video_codec_type(),
input_state_.frame_size_pixels().value()); input_state.frame_size_pixels().value());
if (source_restrictor_->CanDecreaseFrameRateTo(target_fps)) { if (source_restrictor_->CanDecreaseFrameRateTo(target_fps)) {
return Adaptation( return Adaptation(
adaptation_validation_id_, adaptation_validation_id_,
Adaptation::Step(Adaptation::StepType::kDecreaseFrameRate, Adaptation::Step(Adaptation::StepType::kDecreaseFrameRate,
target_fps)); target_fps),
input_state);
} }
// Scale down resolution. // Scale down resolution.
ABSL_FALLTHROUGH_INTENDED; ABSL_FALLTHROUGH_INTENDED;
@ -518,35 +545,36 @@ Adaptation VideoStreamAdapter::GetAdaptationDown() const {
case DegradationPreference::MAINTAIN_FRAMERATE: { case DegradationPreference::MAINTAIN_FRAMERATE: {
// Scale down resolution. // Scale down resolution.
int target_pixels = int target_pixels =
GetLowerResolutionThan(input_state_.frame_size_pixels().value()); GetLowerResolutionThan(input_state.frame_size_pixels().value());
bool min_pixel_limit_reached = bool min_pixel_limit_reached =
target_pixels < source_restrictor_->min_pixels_per_frame(); target_pixels < source_restrictor_->min_pixels_per_frame();
if (!source_restrictor_->CanDecreaseResolutionTo(target_pixels)) { if (!source_restrictor_->CanDecreaseResolutionTo(target_pixels)) {
return Adaptation(adaptation_validation_id_, return Adaptation(adaptation_validation_id_,
Adaptation::Status::kLimitReached, Adaptation::Status::kLimitReached, input_state,
min_pixel_limit_reached); min_pixel_limit_reached);
} }
return Adaptation( return Adaptation(
adaptation_validation_id_, adaptation_validation_id_,
Adaptation::Step(Adaptation::StepType::kDecreaseResolution, Adaptation::Step(Adaptation::StepType::kDecreaseResolution,
target_pixels), target_pixels),
min_pixel_limit_reached); input_state, min_pixel_limit_reached);
} }
case DegradationPreference::MAINTAIN_RESOLUTION: { case DegradationPreference::MAINTAIN_RESOLUTION: {
int target_fps = GetLowerFrameRateThan(input_state_.frames_per_second()); int target_fps = GetLowerFrameRateThan(input_state.frames_per_second());
if (!source_restrictor_->CanDecreaseFrameRateTo(target_fps)) { if (!source_restrictor_->CanDecreaseFrameRateTo(target_fps)) {
return Adaptation(adaptation_validation_id_, return Adaptation(adaptation_validation_id_,
Adaptation::Status::kLimitReached); Adaptation::Status::kLimitReached, input_state);
} }
return Adaptation( return Adaptation(
adaptation_validation_id_, adaptation_validation_id_,
Adaptation::Step(Adaptation::StepType::kDecreaseFrameRate, Adaptation::Step(Adaptation::StepType::kDecreaseFrameRate,
target_fps)); target_fps),
input_state);
} }
case DegradationPreference::DISABLED: case DegradationPreference::DISABLED:
RTC_NOTREACHED(); RTC_NOTREACHED();
return Adaptation(adaptation_validation_id_, return Adaptation(adaptation_validation_id_,
Adaptation::Status::kLimitReached); Adaptation::Status::kLimitReached, input_state);
} }
} }
@ -577,8 +605,8 @@ void VideoStreamAdapter::ApplyAdaptation(
// Remember the input pixels and fps of this adaptation. Used to avoid // Remember the input pixels and fps of this adaptation. Used to avoid
// adapting again before this adaptation has had an effect. // adapting again before this adaptation has had an effect.
last_adaptation_request_.emplace(AdaptationRequest{ last_adaptation_request_.emplace(AdaptationRequest{
input_state_.frame_size_pixels().value(), adaptation.input_state_.frame_size_pixels().value(),
input_state_.frames_per_second(), adaptation.step().type}); adaptation.input_state_.frames_per_second(), adaptation.step().type});
// Adapt! // Adapt!
source_restrictor_->ApplyAdaptationStep(adaptation.step(), source_restrictor_->ApplyAdaptationStep(adaptation.step(),
degradation_preference_); degradation_preference_);
@ -587,11 +615,12 @@ void VideoStreamAdapter::ApplyAdaptation(
Adaptation VideoStreamAdapter::GetAdaptationTo( Adaptation VideoStreamAdapter::GetAdaptationTo(
const VideoAdaptationCounters& counters, const VideoAdaptationCounters& counters,
const VideoSourceRestrictions& restrictions) const { const VideoSourceRestrictions& restrictions) {
// Adapts up/down from the current levels so counters are equal. // Adapts up/down from the current levels so counters are equal.
RTC_DCHECK_RUN_ON(&sequence_checker_); RTC_DCHECK_RUN_ON(&sequence_checker_);
VideoStreamInputState input_state = input_state_provider_->InputState();
return Adaptation(adaptation_validation_id_, return Adaptation(adaptation_validation_id_,
Adaptation::Step(restrictions, counters)); Adaptation::Step(restrictions, counters), input_state);
} }
void VideoStreamAdapter::BroadcastVideoRestrictionsUpdate( void VideoStreamAdapter::BroadcastVideoRestrictionsUpdate(
@ -611,4 +640,12 @@ void VideoStreamAdapter::BroadcastVideoRestrictionsUpdate(
last_filtered_restrictions_ = filtered; last_filtered_restrictions_ = filtered;
} }
bool VideoStreamAdapter::HasSufficientInputForAdaptation(
const VideoStreamInputState& input_state) const {
return input_state.HasInputFrameSizeAndFramesPerSecond() &&
(degradation_preference_ !=
DegradationPreference::MAINTAIN_RESOLUTION ||
input_state.frames_per_second() >= kMinFrameRateFps);
}
} // namespace webrtc } // namespace webrtc

View File

@ -20,6 +20,7 @@
#include "api/video/video_adaptation_counters.h" #include "api/video/video_adaptation_counters.h"
#include "call/adaptation/video_source_restrictions.h" #include "call/adaptation/video_source_restrictions.h"
#include "call/adaptation/video_stream_input_state.h" #include "call/adaptation/video_stream_input_state.h"
#include "call/adaptation/video_stream_input_state_provider.h"
#include "modules/video_coding/utility/quality_scaler.h" #include "modules/video_coding/utility/quality_scaler.h"
#include "rtc_base/experiments/balanced_degradation_settings.h" #include "rtc_base/experiments/balanced_degradation_settings.h"
@ -67,6 +68,8 @@ class Adaptation final {
// adaptation has not yet been reflected in the input resolution or frame // adaptation has not yet been reflected in the input resolution or frame
// rate; adaptation is refused to avoid "double-adapting". // rate; adaptation is refused to avoid "double-adapting".
kAwaitingPreviousAdaptation, kAwaitingPreviousAdaptation,
// Not enough input.
kInsufficientInput,
}; };
static const char* StatusToString(Status status); static const char* StatusToString(Status status);
@ -77,6 +80,8 @@ class Adaptation final {
// Used for stats reporting. // Used for stats reporting.
bool min_pixel_limit_reached() const; bool min_pixel_limit_reached() const;
const VideoStreamInputState& input_state() const;
private: private:
// The adapter needs to know about step type and step target in order to // The adapter needs to know about step type and step target in order to
// construct and perform an Adaptation, which is a detail we do not want to // construct and perform an Adaptation, which is a detail we do not want to
@ -107,12 +112,18 @@ class Adaptation final {
}; };
// Constructs with a valid adaptation Step. Status is kValid. // Constructs with a valid adaptation Step. Status is kValid.
Adaptation(int validation_id, Step step); Adaptation(int validation_id, Step step, VideoStreamInputState input_state);
Adaptation(int validation_id, Step step, bool min_pixel_limit_reached); Adaptation(int validation_id,
Step step,
VideoStreamInputState input_state,
bool min_pixel_limit_reached);
// Constructor when adaptation is not valid. Status MUST NOT be kValid. // Constructor when adaptation is not valid. Status MUST NOT be kValid.
Adaptation(int validation_id, Status invalid_status);
Adaptation(int validation_id, Adaptation(int validation_id,
Status invalid_status, Status invalid_status,
VideoStreamInputState input_state);
Adaptation(int validation_id,
Status invalid_status,
VideoStreamInputState input_state,
bool min_pixel_limit_reached); bool min_pixel_limit_reached);
const Step& step() const; // Only callable if |status_| is kValid. const Step& step() const; // Only callable if |status_| is kValid.
@ -124,6 +135,8 @@ class Adaptation final {
const Status status_; const Status status_;
const absl::optional<Step> step_; // Only present if |status_| is kValid. const absl::optional<Step> step_; // Only present if |status_| is kValid.
const bool min_pixel_limit_reached_; const bool min_pixel_limit_reached_;
// Input state when adaptation was made.
const VideoStreamInputState input_state_;
}; };
// Owns the VideoSourceRestriction for a single stream and is responsible for // Owns the VideoSourceRestriction for a single stream and is responsible for
@ -134,7 +147,8 @@ class Adaptation final {
// 3. Modify the stream's restrictions in one of the valid ways. // 3. Modify the stream's restrictions in one of the valid ways.
class VideoStreamAdapter { class VideoStreamAdapter {
public: public:
VideoStreamAdapter(); explicit VideoStreamAdapter(
VideoStreamInputStateProvider* input_state_provider);
~VideoStreamAdapter(); ~VideoStreamAdapter();
VideoSourceRestrictions source_restrictions() const; VideoSourceRestrictions source_restrictions() const;
@ -150,15 +164,13 @@ class VideoStreamAdapter {
// restrictions! This is not defined in the spec and is unexpected, there is a // restrictions! This is not defined in the spec and is unexpected, there is a
// tiny risk that people would discover and rely on this behavior. // tiny risk that people would discover and rely on this behavior.
void SetDegradationPreference(DegradationPreference degradation_preference); void SetDegradationPreference(DegradationPreference degradation_preference);
// The adaptaiton logic depends on these inputs.
void SetInput(VideoStreamInputState input_state);
// Returns an adaptation that we are guaranteed to be able to apply, or a // Returns an adaptation that we are guaranteed to be able to apply, or a
// status code indicating the reason why we cannot adapt. // status code indicating the reason why we cannot adapt.
Adaptation GetAdaptationUp() const; Adaptation GetAdaptationUp();
Adaptation GetAdaptationDown() const; Adaptation GetAdaptationDown();
Adaptation GetAdaptationTo(const VideoAdaptationCounters& counters, Adaptation GetAdaptationTo(const VideoAdaptationCounters& counters,
const VideoSourceRestrictions& restrictions) const; const VideoSourceRestrictions& restrictions);
struct RestrictionsWithCounters { struct RestrictionsWithCounters {
VideoSourceRestrictions restrictions; VideoSourceRestrictions restrictions;
@ -192,6 +204,9 @@ class VideoStreamAdapter {
void BroadcastVideoRestrictionsUpdate( void BroadcastVideoRestrictionsUpdate(
const rtc::scoped_refptr<Resource>& resource); const rtc::scoped_refptr<Resource>& resource);
bool HasSufficientInputForAdaptation(const VideoStreamInputState& input_state)
const RTC_RUN_ON(&sequence_checker_);
// The input frame rate and resolution at the time of an adaptation in the // The input frame rate and resolution at the time of an adaptation in the
// direction described by |mode_| (up or down). // direction described by |mode_| (up or down).
// TODO(https://crbug.com/webrtc/11393): Can this be renamed? Can this be // TODO(https://crbug.com/webrtc/11393): Can this be renamed? Can this be
@ -209,6 +224,9 @@ class VideoStreamAdapter {
// Owner and modifier of the VideoSourceRestriction of this stream adaptor. // Owner and modifier of the VideoSourceRestriction of this stream adaptor.
const std::unique_ptr<VideoSourceRestrictor> source_restrictor_ const std::unique_ptr<VideoSourceRestrictor> source_restrictor_
RTC_GUARDED_BY(&sequence_checker_); RTC_GUARDED_BY(&sequence_checker_);
// Gets the input state which is the basis of all adaptations.
// Thread safe.
VideoStreamInputStateProvider* input_state_provider_;
// Decides the next adaptation target in DegradationPreference::BALANCED. // Decides the next adaptation target in DegradationPreference::BALANCED.
const BalancedDegradationSettings balanced_settings_; const BalancedDegradationSettings balanced_settings_;
// To guard against applying adaptations that have become invalidated, an // To guard against applying adaptations that have become invalidated, an
@ -219,7 +237,6 @@ class VideoStreamAdapter {
// https://w3c.github.io/mst-content-hint/#dom-rtcdegradationpreference // https://w3c.github.io/mst-content-hint/#dom-rtcdegradationpreference
DegradationPreference degradation_preference_ DegradationPreference degradation_preference_
RTC_GUARDED_BY(&sequence_checker_); RTC_GUARDED_BY(&sequence_checker_);
VideoStreamInputState input_state_ RTC_GUARDED_BY(&sequence_checker_);
// The input frame rate, resolution and adaptation direction of the last // The input frame rate, resolution and adaptation direction of the last
// ApplyAdaptationTarget(). Used to avoid adapting twice if a recent // ApplyAdaptationTarget(). Used to avoid adapting twice if a recent
// adaptation has not had an effect on the input frame rate or resolution yet. // adaptation has not had an effect on the input frame rate or resolution yet.

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,8 @@ VideoStreamInputStateProvider::VideoStreamInputStateProvider(
VideoStreamEncoderObserver* frame_rate_provider) VideoStreamEncoderObserver* frame_rate_provider)
: frame_rate_provider_(frame_rate_provider) {} : frame_rate_provider_(frame_rate_provider) {}
VideoStreamInputStateProvider::~VideoStreamInputStateProvider() {}
void VideoStreamInputStateProvider::OnHasInputChanged(bool has_input) { void VideoStreamInputStateProvider::OnHasInputChanged(bool has_input) {
rtc::CritScope lock(&crit_); rtc::CritScope lock(&crit_);
input_state_.set_has_input(has_input); input_state_.set_has_input(has_input);

View File

@ -22,12 +22,13 @@ class VideoStreamInputStateProvider {
public: public:
VideoStreamInputStateProvider( VideoStreamInputStateProvider(
VideoStreamEncoderObserver* frame_rate_provider); VideoStreamEncoderObserver* frame_rate_provider);
virtual ~VideoStreamInputStateProvider();
void OnHasInputChanged(bool has_input); void OnHasInputChanged(bool has_input);
void OnFrameSizeObserved(int frame_size_pixels); void OnFrameSizeObserved(int frame_size_pixels);
void OnEncoderSettingsChanged(EncoderSettings encoder_settings); void OnEncoderSettingsChanged(EncoderSettings encoder_settings);
VideoStreamInputState InputState(); virtual VideoStreamInputState InputState();
private: private:
mutable rtc::CriticalSection crit_; mutable rtc::CriticalSection crit_;

View File

@ -256,10 +256,10 @@ VideoStreamEncoder::VideoStreamEncoder(
ParseAutomatincAnimationDetectionFieldTrial()), ParseAutomatincAnimationDetectionFieldTrial()),
encoder_switch_requested_(false), encoder_switch_requested_(false),
input_state_provider_(encoder_stats_observer), input_state_provider_(encoder_stats_observer),
video_stream_adapter_(std::make_unique<VideoStreamAdapter>()), video_stream_adapter_(
std::make_unique<VideoStreamAdapter>(&input_state_provider_)),
resource_adaptation_processor_( resource_adaptation_processor_(
std::make_unique<ResourceAdaptationProcessor>( std::make_unique<ResourceAdaptationProcessor>(
&input_state_provider_,
encoder_stats_observer, encoder_stats_observer,
video_stream_adapter_.get())), video_stream_adapter_.get())),
adaptation_constraints_(), adaptation_constraints_(),