[Adaptation] Report AdaptationCounters OnVideoSourceRestrictionsUpdated.

This CL is part of the Call-Level Adaptation Processing design doc:
https://docs.google.com/document/d/1ZyC26yOCknrrcYa839ZWLxD6o6Gig5A3lVTh4E41074/edit?usp=sharing

By pushing VideoAdaptationCounters updates on VideoSourceRestrictions
changes, alongside the Resource* that triggered the adaptation, we are
able to update |active_counts_| without an explicit dependency on the
VideoStreamAdapter. This allows a future CL to split up "processor"
logic from "video stream encoder resource and active counts" logic,
which will ultimately be necessary in order to do processing on a
"processing queue" and encoder and stats logic on the "encoder queue".

If the restrictions got cleared by an API call
(ResetVideoSourceRestrictions() or SetDegradationPreference()) we pass
null as the "reason_resource". This allows is to clear the
active_counts_, and the code that invokes
OnVideoSourceRestrictionsUpdated() does not have to be aware of
active_counts_ (needed to split the processor module in two).

Bug: webrtc:11172
Change-Id: Icab6d5121c0ebd27d2a00f1bffc8191f8f05f562
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/173000
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Evan Shrubsole <eshr@google.com>
Cr-Commit-Position: refs/heads/master@{#31103}
This commit is contained in:
Henrik Boström
2020-04-17 15:31:48 +02:00
committed by Commit Bot
parent 00032698ac
commit d2930c6c2b
8 changed files with 78 additions and 56 deletions

View File

@ -13,6 +13,7 @@
#include "absl/types/optional.h" #include "absl/types/optional.h"
#include "api/rtp_parameters.h" #include "api/rtp_parameters.h"
#include "api/video/video_adaptation_counters.h"
#include "api/video/video_frame.h" #include "api/video/video_frame.h"
#include "call/adaptation/encoder_settings.h" #include "call/adaptation/encoder_settings.h"
#include "call/adaptation/resource.h" #include "call/adaptation/resource.h"
@ -26,8 +27,13 @@ class ResourceAdaptationProcessorListener {
public: public:
virtual ~ResourceAdaptationProcessorListener(); virtual ~ResourceAdaptationProcessorListener();
// The |restrictions| are filtered by degradation preference but not the
// |adaptation_counters|, which are currently only reported for legacy stats
// calculation purposes.
virtual void OnVideoSourceRestrictionsUpdated( virtual void OnVideoSourceRestrictionsUpdated(
VideoSourceRestrictions restrictions) = 0; VideoSourceRestrictions restrictions,
const VideoAdaptationCounters& adaptation_counters,
const Resource* reason) = 0;
}; };
// Responsible for reconfiguring encoded streams based on resource consumption, // Responsible for reconfiguring encoded streams based on resource consumption,

View File

@ -361,22 +361,17 @@ void VideoStreamAdapter::ClearRestrictions() {
last_adaptation_request_.reset(); last_adaptation_request_.reset();
} }
VideoStreamAdapter::SetDegradationPreferenceResult void VideoStreamAdapter::SetDegradationPreference(
VideoStreamAdapter::SetDegradationPreference(
DegradationPreference degradation_preference) { DegradationPreference degradation_preference) {
if (degradation_preference_ == degradation_preference) if (degradation_preference_ == degradation_preference)
return SetDegradationPreferenceResult::kRestrictionsNotCleared; return;
// Invalidate any previously returned Adaptation. // Invalidate any previously returned Adaptation.
++adaptation_validation_id_; ++adaptation_validation_id_;
bool did_clear = false;
if (degradation_preference == DegradationPreference::BALANCED || if (degradation_preference == DegradationPreference::BALANCED ||
degradation_preference_ == DegradationPreference::BALANCED) { degradation_preference_ == DegradationPreference::BALANCED) {
ClearRestrictions(); ClearRestrictions();
did_clear = true;
} }
degradation_preference_ = degradation_preference; degradation_preference_ = degradation_preference;
return did_clear ? SetDegradationPreferenceResult::kRestrictionsCleared
: SetDegradationPreferenceResult::kRestrictionsNotCleared;
} }
void VideoStreamAdapter::SetInput(VideoStreamInputState input_state) { void VideoStreamAdapter::SetInput(VideoStreamInputState input_state) {

View File

@ -109,11 +109,6 @@ 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:
enum class SetDegradationPreferenceResult {
kRestrictionsNotCleared,
kRestrictionsCleared,
};
VideoStreamAdapter(); VideoStreamAdapter();
~VideoStreamAdapter(); ~VideoStreamAdapter();
@ -129,8 +124,7 @@ class VideoStreamAdapter {
// TODO(hbos): Setting the degradation preference should not clear // TODO(hbos): Setting the degradation preference should not clear
// 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.
SetDegradationPreferenceResult SetDegradationPreference( void SetDegradationPreference(DegradationPreference degradation_preference);
DegradationPreference degradation_preference);
// The adaptaiton logic depends on these inputs. // The adaptaiton logic depends on these inputs.
void SetInput(VideoStreamInputState input_state); void SetInput(VideoStreamInputState input_state);

View File

@ -588,18 +588,13 @@ TEST(VideoStreamAdapterTest, PeekNextRestrictions) {
TEST(VideoStreamAdapterTest, TEST(VideoStreamAdapterTest,
SetDegradationPreferenceToOrFromBalancedClearsRestrictions) { SetDegradationPreferenceToOrFromBalancedClearsRestrictions) {
VideoStreamAdapter adapter; VideoStreamAdapter adapter;
EXPECT_EQ(VideoStreamAdapter::SetDegradationPreferenceResult:: adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
kRestrictionsNotCleared,
adapter.SetDegradationPreference(
DegradationPreference::MAINTAIN_FRAMERATE));
adapter.SetInput(InputState(1280 * 720, 30, kDefaultMinPixelsPerFrame)); adapter.SetInput(InputState(1280 * 720, 30, kDefaultMinPixelsPerFrame));
adapter.ApplyAdaptation(adapter.GetAdaptationDown()); adapter.ApplyAdaptation(adapter.GetAdaptationDown());
EXPECT_NE(VideoSourceRestrictions(), adapter.source_restrictions()); EXPECT_NE(VideoSourceRestrictions(), adapter.source_restrictions());
EXPECT_NE(0, adapter.adaptation_counters().Total()); EXPECT_NE(0, adapter.adaptation_counters().Total());
// Changing from non-balanced to balanced clears the restrictions. // Changing from non-balanced to balanced clears the restrictions.
EXPECT_EQ( adapter.SetDegradationPreference(DegradationPreference::BALANCED);
VideoStreamAdapter::SetDegradationPreferenceResult::kRestrictionsCleared,
adapter.SetDegradationPreference(DegradationPreference::BALANCED));
EXPECT_EQ(VideoSourceRestrictions(), adapter.source_restrictions()); EXPECT_EQ(VideoSourceRestrictions(), adapter.source_restrictions());
EXPECT_EQ(0, adapter.adaptation_counters().Total()); EXPECT_EQ(0, adapter.adaptation_counters().Total());
// Apply adaptation again. // Apply adaptation again.
@ -607,10 +602,7 @@ TEST(VideoStreamAdapterTest,
EXPECT_NE(VideoSourceRestrictions(), adapter.source_restrictions()); EXPECT_NE(VideoSourceRestrictions(), adapter.source_restrictions());
EXPECT_NE(0, adapter.adaptation_counters().Total()); EXPECT_NE(0, adapter.adaptation_counters().Total());
// Changing from balanced to non-balanced clears the restrictions. // Changing from balanced to non-balanced clears the restrictions.
EXPECT_EQ( adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
VideoStreamAdapter::SetDegradationPreferenceResult::kRestrictionsCleared,
adapter.SetDegradationPreference(
DegradationPreference::MAINTAIN_RESOLUTION));
EXPECT_EQ(VideoSourceRestrictions(), adapter.source_restrictions()); EXPECT_EQ(VideoSourceRestrictions(), adapter.source_restrictions());
EXPECT_EQ(0, adapter.adaptation_counters().Total()); EXPECT_EQ(0, adapter.adaptation_counters().Total());
} }

View File

@ -11,6 +11,7 @@
#include "video/adaptation/resource_adaptation_processor.h" #include "video/adaptation/resource_adaptation_processor.h"
#include <algorithm> #include <algorithm>
#include <cmath>
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <string> #include <string>
@ -323,6 +324,7 @@ void ResourceAdaptationProcessor::AddResource(Resource* resource,
void ResourceAdaptationProcessor::SetDegradationPreference( void ResourceAdaptationProcessor::SetDegradationPreference(
DegradationPreference degradation_preference) { DegradationPreference degradation_preference) {
degradation_preference_ = degradation_preference; degradation_preference_ = degradation_preference;
UpdateStatsAdaptationSettings();
MaybeUpdateEffectiveDegradationPreference(); MaybeUpdateEffectiveDegradationPreference();
} }
@ -358,9 +360,7 @@ void ResourceAdaptationProcessor::SetEncoderRates(
void ResourceAdaptationProcessor::ResetVideoSourceRestrictions() { void ResourceAdaptationProcessor::ResetVideoSourceRestrictions() {
stream_adapter_->ClearRestrictions(); stream_adapter_->ClearRestrictions();
ResetActiveCounts(); MaybeUpdateVideoSourceRestrictions(nullptr);
encoder_stats_observer_->ClearAdaptationStats();
MaybeUpdateVideoSourceRestrictions();
} }
void ResourceAdaptationProcessor::OnFrameDroppedDueToSize() { void ResourceAdaptationProcessor::OnFrameDroppedDueToSize() {
@ -533,10 +533,7 @@ void ResourceAdaptationProcessor::OnResourceUnderuse(
stream_adapter_->ApplyAdaptation(adaptation); stream_adapter_->ApplyAdaptation(adaptation);
// Update VideoSourceRestrictions based on adaptation. This also informs the // Update VideoSourceRestrictions based on adaptation. This also informs the
// |adaptation_listener_|. // |adaptation_listener_|.
MaybeUpdateVideoSourceRestrictions(); MaybeUpdateVideoSourceRestrictions(&reason_resource);
// Stats and logging.
UpdateAdaptationStats(GetReasonFromResource(reason_resource));
RTC_LOG(LS_INFO) << ActiveCountsToString();
} }
ResourceListenerResponse ResourceAdaptationProcessor::OnResourceOveruse( ResourceListenerResponse ResourceAdaptationProcessor::OnResourceOveruse(
@ -562,10 +559,7 @@ ResourceListenerResponse ResourceAdaptationProcessor::OnResourceOveruse(
stream_adapter_->ApplyAdaptation(adaptation); stream_adapter_->ApplyAdaptation(adaptation);
// Update VideoSourceRestrictions based on adaptation. This also informs the // Update VideoSourceRestrictions based on adaptation. This also informs the
// |adaptation_listener_|. // |adaptation_listener_|.
MaybeUpdateVideoSourceRestrictions(); MaybeUpdateVideoSourceRestrictions(&reason_resource);
// Stats and logging.
UpdateAdaptationStats(GetReasonFromResource(reason_resource));
RTC_LOG(INFO) << ActiveCountsToString();
return response; return response;
} }
@ -604,28 +598,59 @@ void ResourceAdaptationProcessor::MaybeUpdateEffectiveDegradationPreference() {
degradation_preference_ == DegradationPreference::BALANCED) degradation_preference_ == DegradationPreference::BALANCED)
? DegradationPreference::MAINTAIN_RESOLUTION ? DegradationPreference::MAINTAIN_RESOLUTION
: degradation_preference_; : degradation_preference_;
if (stream_adapter_->SetDegradationPreference( stream_adapter_->SetDegradationPreference(effective_degradation_preference_);
effective_degradation_preference_) == MaybeUpdateVideoSourceRestrictions(nullptr);
VideoStreamAdapter::SetDegradationPreferenceResult::
kRestrictionsCleared) {
ResetActiveCounts();
encoder_stats_observer_->ClearAdaptationStats();
}
MaybeUpdateVideoSourceRestrictions();
} }
void ResourceAdaptationProcessor::MaybeUpdateVideoSourceRestrictions() { void ResourceAdaptationProcessor::MaybeUpdateVideoSourceRestrictions(
const Resource* reason_resource) {
VideoSourceRestrictions new_restrictions = VideoSourceRestrictions new_restrictions =
FilterRestrictionsByDegradationPreference( FilterRestrictionsByDegradationPreference(
stream_adapter_->source_restrictions(), degradation_preference_); stream_adapter_->source_restrictions(), degradation_preference_);
if (video_source_restrictions_ != new_restrictions) { if (video_source_restrictions_ != new_restrictions) {
video_source_restrictions_ = std::move(new_restrictions); video_source_restrictions_ = std::move(new_restrictions);
// TODO(https://crbug.com/webrtc/11172): Support multiple listeners and
// loop through them here instead of calling two hardcoded listeners (|this|
// and |adaptation_listener_|).
OnVideoSourceRestrictionsUpdated(video_source_restrictions_,
stream_adapter_->adaptation_counters(),
reason_resource);
adaptation_listener_->OnVideoSourceRestrictionsUpdated( adaptation_listener_->OnVideoSourceRestrictionsUpdated(
video_source_restrictions_); video_source_restrictions_, stream_adapter_->adaptation_counters(),
MaybeUpdateTargetFrameRate(); reason_resource);
} }
} }
void ResourceAdaptationProcessor::OnVideoSourceRestrictionsUpdated(
VideoSourceRestrictions restrictions,
const VideoAdaptationCounters& adaptation_counters,
const Resource* reason) {
VideoAdaptationCounters previous_adaptation_counters =
active_counts_[VideoAdaptationReason::kQuality] +
active_counts_[VideoAdaptationReason::kCpu];
int adaptation_counters_total_abs_diff = std::abs(
adaptation_counters.Total() - previous_adaptation_counters.Total());
if (reason) {
// A resource signal triggered this adaptation. The adaptation counters have
// to be updated every time the adaptation counter is incremented or
// decremented due to a resource.
RTC_DCHECK_EQ(adaptation_counters_total_abs_diff, 1);
VideoAdaptationReason reason_type = GetReasonFromResource(*reason);
UpdateAdaptationStats(adaptation_counters, reason_type);
} else if (adaptation_counters.Total() == 0) {
// Adaptation was manually reset - clear the per-reason counters too.
ResetActiveCounts();
encoder_stats_observer_->ClearAdaptationStats();
} else {
// If a reason did not increase or decrease the Total() by 1 and the
// restrictions were not just reset, the adaptation counters MUST not have
// been modified and there is nothing to do stats-wise.
RTC_DCHECK_EQ(adaptation_counters_total_abs_diff, 0);
}
RTC_LOG(LS_INFO) << ActiveCountsToString();
MaybeUpdateTargetFrameRate();
}
void ResourceAdaptationProcessor::MaybeUpdateTargetFrameRate() { void ResourceAdaptationProcessor::MaybeUpdateTargetFrameRate() {
absl::optional<double> codec_max_frame_rate = absl::optional<double> codec_max_frame_rate =
encoder_settings_.has_value() encoder_settings_.has_value()
@ -710,12 +735,11 @@ void ResourceAdaptationProcessor::OnAdaptationCountChanged(
} }
void ResourceAdaptationProcessor::UpdateAdaptationStats( void ResourceAdaptationProcessor::UpdateAdaptationStats(
const VideoAdaptationCounters& total_counts,
VideoAdaptationReason reason) { VideoAdaptationReason reason) {
// Update active counts // Update active counts
VideoAdaptationCounters& active_count = active_counts_[reason]; VideoAdaptationCounters& active_count = active_counts_[reason];
VideoAdaptationCounters& other_active = active_counts_[OtherReason(reason)]; VideoAdaptationCounters& other_active = active_counts_[OtherReason(reason)];
const VideoAdaptationCounters total_counts =
stream_adapter_->adaptation_counters();
OnAdaptationCountChanged(total_counts, &active_count, &other_active); OnAdaptationCountChanged(total_counts, &active_count, &other_active);

View File

@ -59,7 +59,8 @@ extern const int kDefaultInputPixelsHeight;
// indirectly in video_stream_encoder_unittest.cc and other tests exercising // indirectly in video_stream_encoder_unittest.cc and other tests exercising
// VideoStreamEncoder. // VideoStreamEncoder.
class ResourceAdaptationProcessor : public ResourceAdaptationProcessorInterface, class ResourceAdaptationProcessor : public ResourceAdaptationProcessorInterface,
public ResourceListener { public ResourceListener,
public ResourceAdaptationProcessorListener {
public: public:
// The processor can be constructed on any sequence, but must be initialized // The processor can be constructed on any sequence, but must be initialized
// and used on a single sequence, e.g. the encoder queue. // and used on a single sequence, e.g. the encoder queue.
@ -83,7 +84,7 @@ class ResourceAdaptationProcessor : public ResourceAdaptationProcessorInterface,
void StartResourceAdaptation( void StartResourceAdaptation(
ResourceAdaptationProcessorListener* adaptation_listener) override; ResourceAdaptationProcessorListener* adaptation_listener) override;
void StopResourceAdaptation() override; void StopResourceAdaptation() override;
// Uses a default AdaptReason of kCpu. // Uses a default VideoAdaptationReason of kCpu.
void AddResource(Resource* resource) override; void AddResource(Resource* resource) override;
void AddResource(Resource* resource, VideoAdaptationReason reason); void AddResource(Resource* resource, VideoAdaptationReason reason);
void SetDegradationPreference( void SetDegradationPreference(
@ -116,6 +117,11 @@ class ResourceAdaptationProcessor : public ResourceAdaptationProcessorInterface,
ResourceListenerResponse OnResourceUsageStateMeasured( ResourceListenerResponse OnResourceUsageStateMeasured(
const Resource& resource) override; const Resource& resource) override;
void OnVideoSourceRestrictionsUpdated(
VideoSourceRestrictions restrictions,
const VideoAdaptationCounters& adaptation_counters,
const Resource* reason) override;
// For reasons of adaptation and statistics, we not only count the total // For reasons of adaptation and statistics, we not only count the total
// number of adaptations, but we also count the number of adaptations per // number of adaptations, but we also count the number of adaptations per
// reason. // reason.
@ -157,7 +163,7 @@ class ResourceAdaptationProcessor : public ResourceAdaptationProcessorInterface,
// Makes |video_source_restrictions_| up-to-date and informs the // Makes |video_source_restrictions_| up-to-date and informs the
// |adaptation_listener_| if restrictions are changed, allowing the listener // |adaptation_listener_| if restrictions are changed, allowing the listener
// to reconfigure the source accordingly. // to reconfigure the source accordingly.
void MaybeUpdateVideoSourceRestrictions(); void MaybeUpdateVideoSourceRestrictions(const Resource* reason_resource);
// Calculates an up-to-date value of the target frame rate and informs the // Calculates an up-to-date value of the target frame rate and informs the
// |encode_usage_resource_| of the new value. // |encode_usage_resource_| of the new value.
void MaybeUpdateTargetFrameRate(); void MaybeUpdateTargetFrameRate();
@ -166,7 +172,8 @@ class ResourceAdaptationProcessor : public ResourceAdaptationProcessorInterface,
void UpdateQualityScalerSettings( void UpdateQualityScalerSettings(
absl::optional<VideoEncoder::QpThresholds> qp_thresholds); absl::optional<VideoEncoder::QpThresholds> qp_thresholds);
void UpdateAdaptationStats(VideoAdaptationReason reason); void UpdateAdaptationStats(const VideoAdaptationCounters& total_counts,
VideoAdaptationReason reason);
void UpdateStatsAdaptationSettings() const; void UpdateStatsAdaptationSettings() const;
// Checks to see if we should execute the quality rampup experiment. The // Checks to see if we should execute the quality rampup experiment. The

View File

@ -1657,7 +1657,9 @@ bool VideoStreamEncoder::DropDueToSize(uint32_t pixel_count) const {
} }
void VideoStreamEncoder::OnVideoSourceRestrictionsUpdated( void VideoStreamEncoder::OnVideoSourceRestrictionsUpdated(
VideoSourceRestrictions restrictions) { VideoSourceRestrictions restrictions,
const VideoAdaptationCounters& adaptation_counters,
const Resource* reason) {
RTC_DCHECK_RUN_ON(&encoder_queue_); RTC_DCHECK_RUN_ON(&encoder_queue_);
video_source_sink_controller_->SetRestrictions(std::move(restrictions)); video_source_sink_controller_->SetRestrictions(std::move(restrictions));
video_source_sink_controller_->PushSourceSinkSettings(); video_source_sink_controller_->PushSourceSinkSettings();

View File

@ -108,7 +108,9 @@ class VideoStreamEncoder : public VideoStreamEncoderInterface,
rtc::TaskQueue* encoder_queue() { return &encoder_queue_; } rtc::TaskQueue* encoder_queue() { return &encoder_queue_; }
void OnVideoSourceRestrictionsUpdated( void OnVideoSourceRestrictionsUpdated(
VideoSourceRestrictions restrictions) override; VideoSourceRestrictions restrictions,
const VideoAdaptationCounters& adaptation_counters,
const Resource* reason) override;
// Used for injected test resources. // Used for injected test resources.
// TODO(eshr): Move all adaptation tests out of VideoStreamEncoder tests. // TODO(eshr): Move all adaptation tests out of VideoStreamEncoder tests.