Replace AdaptCount with a single counter.
There is still a counter for the active counts for the scaling, but these will be removed at a later date. BUG=webrtc:11392 Change-Id: Ie9bcf3f744a0bbac601f0da61197f4bac1e9f879 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/169447 Reviewed-by: Åsa Persson <asapersson@webrtc.org> Reviewed-by: Henrik Boström <hbos@webrtc.org> Commit-Queue: Evan Shrubsole <eshr@google.com> Cr-Commit-Position: refs/heads/master@{#30701}
This commit is contained in:

committed by
Commit Bot

parent
d3da6b05c1
commit
33be9dfe7a
@ -504,6 +504,7 @@ if (rtc_include_tests) {
|
|||||||
"end_to_end_tests/stats_tests.cc",
|
"end_to_end_tests/stats_tests.cc",
|
||||||
"end_to_end_tests/transport_feedback_tests.cc",
|
"end_to_end_tests/transport_feedback_tests.cc",
|
||||||
"frame_encode_metadata_writer_unittest.cc",
|
"frame_encode_metadata_writer_unittest.cc",
|
||||||
|
"overuse_frame_detector_resource_adaptation_unittest.cc",
|
||||||
"overuse_frame_detector_unittest.cc",
|
"overuse_frame_detector_unittest.cc",
|
||||||
"picture_id_tests.cc",
|
"picture_id_tests.cc",
|
||||||
"quality_limitation_reason_tracker_unittest.cc",
|
"quality_limitation_reason_tracker_unittest.cc",
|
||||||
|
@ -67,8 +67,57 @@ VideoSourceRestrictions ApplyDegradationPreference(
|
|||||||
return source_restrictions;
|
return source_restrictions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns AdaptationCounters where constraints that don't apply to the
|
||||||
|
// degradation preference are cleared. This behaviour must reflect that of
|
||||||
|
// ApplyDegradationPreference for SourceRestrictions. Any changed to that
|
||||||
|
// method must also change this one.
|
||||||
|
AdaptationCounters ApplyDegradationPreference(
|
||||||
|
AdaptationCounters counters,
|
||||||
|
DegradationPreference degradation_preference) {
|
||||||
|
switch (degradation_preference) {
|
||||||
|
case DegradationPreference::BALANCED:
|
||||||
|
break;
|
||||||
|
case DegradationPreference::MAINTAIN_FRAMERATE:
|
||||||
|
counters.fps_adaptations = 0;
|
||||||
|
break;
|
||||||
|
case DegradationPreference::MAINTAIN_RESOLUTION:
|
||||||
|
counters.resolution_adaptations = 0;
|
||||||
|
break;
|
||||||
|
case DegradationPreference::DISABLED:
|
||||||
|
counters.resolution_adaptations = 0;
|
||||||
|
counters.fps_adaptations = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
RTC_NOTREACHED();
|
||||||
|
}
|
||||||
|
return counters;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
bool AdaptationCounters::operator==(const AdaptationCounters& rhs) const {
|
||||||
|
return fps_adaptations == rhs.fps_adaptations &&
|
||||||
|
resolution_adaptations == rhs.resolution_adaptations;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AdaptationCounters::operator!=(const AdaptationCounters& rhs) const {
|
||||||
|
return !(rhs == *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdaptationCounters AdaptationCounters::operator+(
|
||||||
|
const AdaptationCounters& other) const {
|
||||||
|
return AdaptationCounters(
|
||||||
|
resolution_adaptations + other.resolution_adaptations,
|
||||||
|
fps_adaptations + other.fps_adaptations);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdaptationCounters AdaptationCounters::operator-(
|
||||||
|
const AdaptationCounters& other) const {
|
||||||
|
return AdaptationCounters(
|
||||||
|
resolution_adaptations - other.resolution_adaptations,
|
||||||
|
fps_adaptations - other.fps_adaptations);
|
||||||
|
}
|
||||||
|
|
||||||
// VideoSourceRestrictor is responsible for keeping track of current
|
// VideoSourceRestrictor is responsible for keeping track of current
|
||||||
// VideoSourceRestrictions and how to modify them in response to adapting up or
|
// VideoSourceRestrictions and how to modify them in response to adapting up or
|
||||||
// down. It is not reponsible for determining when we should adapt up or down -
|
// down. It is not reponsible for determining when we should adapt up or down -
|
||||||
@ -115,8 +164,10 @@ class OveruseFrameDetectorResourceAdaptationModule::VideoSourceRestrictor {
|
|||||||
VideoSourceRestrictions source_restrictions() {
|
VideoSourceRestrictions source_restrictions() {
|
||||||
return source_restrictions_;
|
return source_restrictions_;
|
||||||
}
|
}
|
||||||
|
const AdaptationCounters& adaptation_counters() const { return adaptations_; }
|
||||||
void ClearRestrictions() {
|
void ClearRestrictions() {
|
||||||
source_restrictions_ = VideoSourceRestrictions();
|
source_restrictions_ = VideoSourceRestrictions();
|
||||||
|
adaptations_ = AdaptationCounters();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanDecreaseResolutionTo(int target_pixels, int min_pixels_per_frame) {
|
bool CanDecreaseResolutionTo(int target_pixels, int min_pixels_per_frame) {
|
||||||
@ -135,6 +186,7 @@ class OveruseFrameDetectorResourceAdaptationModule::VideoSourceRestrictor {
|
|||||||
? absl::optional<size_t>(target_pixels)
|
? absl::optional<size_t>(target_pixels)
|
||||||
: absl::nullopt);
|
: absl::nullopt);
|
||||||
source_restrictions_.set_target_pixels_per_frame(absl::nullopt);
|
source_restrictions_.set_target_pixels_per_frame(absl::nullopt);
|
||||||
|
++adaptations_.resolution_adaptations;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanIncreaseResolutionTo(int target_pixels) {
|
bool CanIncreaseResolutionTo(int target_pixels) {
|
||||||
@ -157,6 +209,8 @@ class OveruseFrameDetectorResourceAdaptationModule::VideoSourceRestrictor {
|
|||||||
max_pixels_wanted != std::numeric_limits<int>::max()
|
max_pixels_wanted != std::numeric_limits<int>::max()
|
||||||
? absl::optional<size_t>(target_pixels)
|
? absl::optional<size_t>(target_pixels)
|
||||||
: absl::nullopt);
|
: absl::nullopt);
|
||||||
|
--adaptations_.resolution_adaptations;
|
||||||
|
RTC_DCHECK_GE(adaptations_.resolution_adaptations, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanDecreaseFrameRateTo(int max_frame_rate) {
|
bool CanDecreaseFrameRateTo(int max_frame_rate) {
|
||||||
@ -173,6 +227,7 @@ class OveruseFrameDetectorResourceAdaptationModule::VideoSourceRestrictor {
|
|||||||
max_frame_rate != std::numeric_limits<int>::max()
|
max_frame_rate != std::numeric_limits<int>::max()
|
||||||
? absl::optional<double>(max_frame_rate)
|
? absl::optional<double>(max_frame_rate)
|
||||||
: absl::nullopt);
|
: absl::nullopt);
|
||||||
|
++adaptations_.fps_adaptations;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanIncreaseFrameRateTo(int max_frame_rate) {
|
bool CanIncreaseFrameRateTo(int max_frame_rate) {
|
||||||
@ -187,6 +242,8 @@ class OveruseFrameDetectorResourceAdaptationModule::VideoSourceRestrictor {
|
|||||||
max_frame_rate != std::numeric_limits<int>::max()
|
max_frame_rate != std::numeric_limits<int>::max()
|
||||||
? absl::optional<double>(max_frame_rate)
|
? absl::optional<double>(max_frame_rate)
|
||||||
: absl::nullopt);
|
: absl::nullopt);
|
||||||
|
--adaptations_.fps_adaptations;
|
||||||
|
RTC_DCHECK_GE(adaptations_.fps_adaptations, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -207,113 +264,11 @@ class OveruseFrameDetectorResourceAdaptationModule::VideoSourceRestrictor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VideoSourceRestrictions source_restrictions_;
|
VideoSourceRestrictions source_restrictions_;
|
||||||
|
AdaptationCounters adaptations_;
|
||||||
|
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(VideoSourceRestrictor);
|
RTC_DISALLOW_COPY_AND_ASSIGN(VideoSourceRestrictor);
|
||||||
};
|
};
|
||||||
|
|
||||||
class OveruseFrameDetectorResourceAdaptationModule::AdaptCounter final {
|
|
||||||
public:
|
|
||||||
AdaptCounter() {
|
|
||||||
fps_counters_.resize(AdaptationObserverInterface::kScaleReasonSize);
|
|
||||||
resolution_counters_.resize(AdaptationObserverInterface::kScaleReasonSize);
|
|
||||||
static_assert(AdaptationObserverInterface::kScaleReasonSize == 2,
|
|
||||||
"Update MoveCount.");
|
|
||||||
}
|
|
||||||
~AdaptCounter() = default;
|
|
||||||
|
|
||||||
// Get number of adaptation downscales for |reason|.
|
|
||||||
VideoStreamEncoderObserver::AdaptationSteps Counts(int reason) const {
|
|
||||||
VideoStreamEncoderObserver::AdaptationSteps counts;
|
|
||||||
counts.num_framerate_reductions = fps_counters_[reason];
|
|
||||||
counts.num_resolution_reductions = resolution_counters_[reason];
|
|
||||||
return counts;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ToString() const {
|
|
||||||
rtc::StringBuilder ss;
|
|
||||||
ss << "Downgrade counts: fps: {" << ToString(fps_counters_);
|
|
||||||
ss << "}, resolution: {" << ToString(resolution_counters_) << "}";
|
|
||||||
return ss.Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IncrementFramerate(int reason) { ++(fps_counters_[reason]); }
|
|
||||||
void IncrementResolution(int reason) { ++(resolution_counters_[reason]); }
|
|
||||||
void DecrementFramerate(int reason) {
|
|
||||||
if (fps_counters_[reason] == 0) {
|
|
||||||
// Balanced mode: Adapt up is in a different order, switch reason.
|
|
||||||
// E.g. framerate adapt down: quality (2), framerate adapt up: cpu (3).
|
|
||||||
// 1. Down resolution (cpu): res={quality:0,cpu:1}, fps={quality:0,cpu:0}
|
|
||||||
// 2. Down fps (quality): res={quality:0,cpu:1}, fps={quality:1,cpu:0}
|
|
||||||
// 3. Up fps (cpu): res={quality:1,cpu:0}, fps={quality:0,cpu:0}
|
|
||||||
// 4. Up resolution (quality):res={quality:0,cpu:0}, fps={quality:0,cpu:0}
|
|
||||||
RTC_DCHECK_GT(TotalCount(reason), 0) << "No downgrade for reason.";
|
|
||||||
RTC_DCHECK_GT(FramerateCount(), 0) << "Framerate not downgraded.";
|
|
||||||
MoveCount(&resolution_counters_, reason);
|
|
||||||
MoveCount(&fps_counters_,
|
|
||||||
(reason + 1) % AdaptationObserverInterface::kScaleReasonSize);
|
|
||||||
}
|
|
||||||
--(fps_counters_[reason]);
|
|
||||||
RTC_DCHECK_GE(fps_counters_[reason], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DecrementResolution(int reason) {
|
|
||||||
if (resolution_counters_[reason] == 0) {
|
|
||||||
// Balanced mode: Adapt up is in a different order, switch reason.
|
|
||||||
RTC_DCHECK_GT(TotalCount(reason), 0) << "No downgrade for reason.";
|
|
||||||
RTC_DCHECK_GT(ResolutionCount(), 0) << "Resolution not downgraded.";
|
|
||||||
MoveCount(&fps_counters_, reason);
|
|
||||||
MoveCount(&resolution_counters_,
|
|
||||||
(reason + 1) % AdaptationObserverInterface::kScaleReasonSize);
|
|
||||||
}
|
|
||||||
--(resolution_counters_[reason]);
|
|
||||||
RTC_DCHECK_GE(resolution_counters_[reason], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DecrementFramerate(int reason, int cur_fps) {
|
|
||||||
DecrementFramerate(reason);
|
|
||||||
// Reset if at max fps (i.e. in case of fewer steps up than down).
|
|
||||||
if (cur_fps == std::numeric_limits<int>::max())
|
|
||||||
absl::c_fill(fps_counters_, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets the total number of downgrades (for all adapt reasons).
|
|
||||||
int FramerateCount() const { return Count(fps_counters_); }
|
|
||||||
int ResolutionCount() const { return Count(resolution_counters_); }
|
|
||||||
|
|
||||||
// Gets the total number of downgrades for |reason|.
|
|
||||||
int FramerateCount(int reason) const { return fps_counters_[reason]; }
|
|
||||||
int ResolutionCount(int reason) const { return resolution_counters_[reason]; }
|
|
||||||
int TotalCount(int reason) const {
|
|
||||||
return FramerateCount(reason) + ResolutionCount(reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string ToString(const std::vector<int>& counters) const {
|
|
||||||
rtc::StringBuilder ss;
|
|
||||||
for (size_t reason = 0;
|
|
||||||
reason < AdaptationObserverInterface::kScaleReasonSize; ++reason) {
|
|
||||||
ss << (reason ? " cpu" : "quality") << ":" << counters[reason];
|
|
||||||
}
|
|
||||||
return ss.Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
int Count(const std::vector<int>& counters) const {
|
|
||||||
return absl::c_accumulate(counters, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveCount(std::vector<int>* counters, int from_reason) {
|
|
||||||
int to_reason =
|
|
||||||
(from_reason + 1) % AdaptationObserverInterface::kScaleReasonSize;
|
|
||||||
++((*counters)[to_reason]);
|
|
||||||
--((*counters)[from_reason]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Degradation counters holding number of framerate/resolution reductions
|
|
||||||
// per adapt reason.
|
|
||||||
std::vector<int> fps_counters_;
|
|
||||||
std::vector<int> resolution_counters_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class OveruseFrameDetectorResourceAdaptationModule::InitialFrameDropper {
|
class OveruseFrameDetectorResourceAdaptationModule::InitialFrameDropper {
|
||||||
public:
|
public:
|
||||||
explicit InitialFrameDropper(QualityScalerResource* quality_scaler_resource)
|
explicit InitialFrameDropper(QualityScalerResource* quality_scaler_resource)
|
||||||
@ -402,7 +357,6 @@ OveruseFrameDetectorResourceAdaptationModule::
|
|||||||
experiment_cpu_load_estimator_(experiment_cpu_load_estimator),
|
experiment_cpu_load_estimator_(experiment_cpu_load_estimator),
|
||||||
has_input_video_(false),
|
has_input_video_(false),
|
||||||
degradation_preference_(DegradationPreference::DISABLED),
|
degradation_preference_(DegradationPreference::DISABLED),
|
||||||
adapt_counters_(),
|
|
||||||
balanced_settings_(),
|
balanced_settings_(),
|
||||||
last_adaptation_request_(absl::nullopt),
|
last_adaptation_request_(absl::nullopt),
|
||||||
source_restrictor_(std::make_unique<VideoSourceRestrictor>()),
|
source_restrictor_(std::make_unique<VideoSourceRestrictor>()),
|
||||||
@ -418,10 +372,10 @@ OveruseFrameDetectorResourceAdaptationModule::
|
|||||||
quality_rampup_done_(false),
|
quality_rampup_done_(false),
|
||||||
quality_rampup_experiment_(QualityRampupExperiment::ParseSettings()),
|
quality_rampup_experiment_(QualityRampupExperiment::ParseSettings()),
|
||||||
encoder_settings_(absl::nullopt),
|
encoder_settings_(absl::nullopt),
|
||||||
encoder_stats_observer_(encoder_stats_observer) {
|
encoder_stats_observer_(encoder_stats_observer),
|
||||||
|
active_counts_() {
|
||||||
RTC_DCHECK(adaptation_listener_);
|
RTC_DCHECK(adaptation_listener_);
|
||||||
RTC_DCHECK(encoder_stats_observer_);
|
RTC_DCHECK(encoder_stats_observer_);
|
||||||
ClearAdaptCounters();
|
|
||||||
AddResource(encode_usage_resource_.get(),
|
AddResource(encode_usage_resource_.get(),
|
||||||
AdaptationObserverInterface::AdaptReason::kCpu);
|
AdaptationObserverInterface::AdaptReason::kCpu);
|
||||||
AddResource(quality_scaler_resource_.get(),
|
AddResource(quality_scaler_resource_.get(),
|
||||||
@ -488,10 +442,8 @@ void OveruseFrameDetectorResourceAdaptationModule::SetDegradationPreference(
|
|||||||
last_adaptation_request_.reset();
|
last_adaptation_request_.reset();
|
||||||
if (degradation_preference == DegradationPreference::BALANCED ||
|
if (degradation_preference == DegradationPreference::BALANCED ||
|
||||||
degradation_preference_ == DegradationPreference::BALANCED) {
|
degradation_preference_ == DegradationPreference::BALANCED) {
|
||||||
// TODO(asapersson): Consider removing |adapt_counters_| map and use one
|
|
||||||
// AdaptCounter for all modes.
|
|
||||||
source_restrictor_->ClearRestrictions();
|
source_restrictor_->ClearRestrictions();
|
||||||
ClearAdaptCounters();
|
active_counts_.fill(AdaptationCounters());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
degradation_preference_ = degradation_preference;
|
degradation_preference_ = degradation_preference;
|
||||||
@ -533,7 +485,7 @@ void OveruseFrameDetectorResourceAdaptationModule::
|
|||||||
ResetVideoSourceRestrictions() {
|
ResetVideoSourceRestrictions() {
|
||||||
last_adaptation_request_.reset();
|
last_adaptation_request_.reset();
|
||||||
source_restrictor_->ClearRestrictions();
|
source_restrictor_->ClearRestrictions();
|
||||||
ClearAdaptCounters();
|
active_counts_.fill(AdaptationCounters());
|
||||||
MaybeUpdateVideoSourceRestrictions();
|
MaybeUpdateVideoSourceRestrictions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,19 +495,17 @@ void OveruseFrameDetectorResourceAdaptationModule::OnFrame(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OveruseFrameDetectorResourceAdaptationModule::OnFrameDroppedDueToSize() {
|
void OveruseFrameDetectorResourceAdaptationModule::OnFrameDroppedDueToSize() {
|
||||||
int fps_count = GetConstAdaptCounter().FramerateCount(
|
AdaptationCounters counters_before =
|
||||||
AdaptationObserverInterface::AdaptReason::kQuality);
|
source_restrictor_->adaptation_counters();
|
||||||
int res_count = GetConstAdaptCounter().ResolutionCount(
|
|
||||||
AdaptationObserverInterface::AdaptReason::kQuality);
|
|
||||||
OnResourceOveruse(AdaptationObserverInterface::AdaptReason::kQuality);
|
OnResourceOveruse(AdaptationObserverInterface::AdaptReason::kQuality);
|
||||||
if (degradation_preference() == DegradationPreference::BALANCED &&
|
if (degradation_preference() == DegradationPreference::BALANCED &&
|
||||||
GetConstAdaptCounter().FramerateCount(
|
source_restrictor_->adaptation_counters().fps_adaptations >
|
||||||
AdaptationObserverInterface::AdaptReason::kQuality) > fps_count) {
|
counters_before.fps_adaptations) {
|
||||||
// Adapt framerate in same step as resolution.
|
// Adapt framerate in same step as resolution.
|
||||||
OnResourceOveruse(AdaptationObserverInterface::AdaptReason::kQuality);
|
OnResourceOveruse(AdaptationObserverInterface::AdaptReason::kQuality);
|
||||||
}
|
}
|
||||||
if (GetConstAdaptCounter().ResolutionCount(
|
if (source_restrictor_->adaptation_counters().resolution_adaptations >
|
||||||
AdaptationObserverInterface::AdaptReason::kQuality) > res_count) {
|
counters_before.resolution_adaptations) {
|
||||||
encoder_stats_observer_->OnInitialQualityResolutionAdaptDown();
|
encoder_stats_observer_->OnInitialQualityResolutionAdaptDown();
|
||||||
}
|
}
|
||||||
initial_frame_dropper_->OnFrameDroppedDueToSize();
|
initial_frame_dropper_->OnFrameDroppedDueToSize();
|
||||||
@ -690,7 +640,14 @@ OveruseFrameDetectorResourceAdaptationModule::GetAdaptUpTarget(
|
|||||||
if (!has_input_video_)
|
if (!has_input_video_)
|
||||||
return absl::nullopt;
|
return absl::nullopt;
|
||||||
// 1. We can't adapt up if we're already at the highest setting.
|
// 1. We can't adapt up if we're already at the highest setting.
|
||||||
int num_downgrades = GetConstAdaptCounter().TotalCount(reason);
|
// Note that this only includes counts relevant to the current degradation
|
||||||
|
// preference. e.g. we previously adapted resolution, now prefer adpating fps,
|
||||||
|
// only count the fps adaptations and not the previous resolution adaptations.
|
||||||
|
// TODO(https://crbug.com/webrtc/11394): Checking the counts for reason should
|
||||||
|
// be replaced with checking the overuse state of all resources.
|
||||||
|
int num_downgrades = ApplyDegradationPreference(active_counts_[reason],
|
||||||
|
degradation_preference_)
|
||||||
|
.Total();
|
||||||
RTC_DCHECK_GE(num_downgrades, 0);
|
RTC_DCHECK_GE(num_downgrades, 0);
|
||||||
if (num_downgrades == 0)
|
if (num_downgrades == 0)
|
||||||
return absl::nullopt;
|
return absl::nullopt;
|
||||||
@ -745,7 +702,8 @@ OveruseFrameDetectorResourceAdaptationModule::GetAdaptUpTarget(
|
|||||||
}
|
}
|
||||||
// Attempt to increase pixel count.
|
// Attempt to increase pixel count.
|
||||||
int target_pixels = input_pixels;
|
int target_pixels = input_pixels;
|
||||||
if (GetConstAdaptCounter().ResolutionCount() == 1) {
|
if (source_restrictor_->adaptation_counters().resolution_adaptations ==
|
||||||
|
1) {
|
||||||
RTC_LOG(LS_INFO) << "Removing resolution down-scaling setting.";
|
RTC_LOG(LS_INFO) << "Removing resolution down-scaling setting.";
|
||||||
target_pixels = std::numeric_limits<int>::max();
|
target_pixels = std::numeric_limits<int>::max();
|
||||||
}
|
}
|
||||||
@ -759,7 +717,7 @@ OveruseFrameDetectorResourceAdaptationModule::GetAdaptUpTarget(
|
|||||||
case DegradationPreference::MAINTAIN_RESOLUTION: {
|
case DegradationPreference::MAINTAIN_RESOLUTION: {
|
||||||
// Scale up framerate.
|
// Scale up framerate.
|
||||||
int target_fps = input_fps;
|
int target_fps = input_fps;
|
||||||
if (GetConstAdaptCounter().FramerateCount() == 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();
|
||||||
}
|
}
|
||||||
@ -777,8 +735,7 @@ absl::optional<OveruseFrameDetectorResourceAdaptationModule::AdaptationTarget>
|
|||||||
OveruseFrameDetectorResourceAdaptationModule::GetAdaptDownTarget(
|
OveruseFrameDetectorResourceAdaptationModule::GetAdaptDownTarget(
|
||||||
int input_pixels,
|
int input_pixels,
|
||||||
int input_fps,
|
int input_fps,
|
||||||
int min_pixels_per_frame,
|
int min_pixels_per_frame) const {
|
||||||
AdaptationObserverInterface::AdaptReason reason) const {
|
|
||||||
// Preconditions for being able to adapt down:
|
// Preconditions for being able to adapt down:
|
||||||
if (!has_input_video_)
|
if (!has_input_video_)
|
||||||
return absl::nullopt;
|
return absl::nullopt;
|
||||||
@ -860,22 +817,19 @@ void OveruseFrameDetectorResourceAdaptationModule::ApplyAdaptationTarget(
|
|||||||
switch (target.action) {
|
switch (target.action) {
|
||||||
case AdaptationAction::kIncreaseResolution:
|
case AdaptationAction::kIncreaseResolution:
|
||||||
source_restrictor_->IncreaseResolutionTo(target.value);
|
source_restrictor_->IncreaseResolutionTo(target.value);
|
||||||
GetAdaptCounter().DecrementResolution(reason);
|
|
||||||
return;
|
return;
|
||||||
case AdaptationAction::kDecreaseResolution:
|
case AdaptationAction::kDecreaseResolution:
|
||||||
source_restrictor_->DecreaseResolutionTo(target.value,
|
source_restrictor_->DecreaseResolutionTo(target.value,
|
||||||
min_pixels_per_frame);
|
min_pixels_per_frame);
|
||||||
GetAdaptCounter().IncrementResolution(reason);
|
|
||||||
return;
|
return;
|
||||||
case AdaptationAction::kIncreaseFrameRate:
|
case AdaptationAction::kIncreaseFrameRate:
|
||||||
source_restrictor_->IncreaseFrameRateTo(target.value);
|
source_restrictor_->IncreaseFrameRateTo(target.value);
|
||||||
GetAdaptCounter().DecrementFramerate(reason, target.value);
|
|
||||||
// TODO(https://crbug.com/webrtc/11222): Don't adapt in two steps.
|
// TODO(https://crbug.com/webrtc/11222): Don't adapt in two steps.
|
||||||
// GetAdaptUpTarget() should tell us the correct value, but BALANCED logic
|
// GetAdaptUpTarget() should tell us the correct value, but BALANCED logic
|
||||||
// in DecrementFramerate() makes it hard to predict whether this will be
|
// in DecrementFramerate() makes it hard to predict whether this will be
|
||||||
// the last step. Remove the dependency on GetConstAdaptCounter().
|
// the last step. Remove the dependency on GetConstAdaptCounter().
|
||||||
if (EffectiveDegradationPreference() == DegradationPreference::BALANCED &&
|
if (EffectiveDegradationPreference() == DegradationPreference::BALANCED &&
|
||||||
GetConstAdaptCounter().FramerateCount() == 0 &&
|
source_restrictor_->adaptation_counters().fps_adaptations == 0 &&
|
||||||
target.value != std::numeric_limits<int>::max()) {
|
target.value != std::numeric_limits<int>::max()) {
|
||||||
RTC_LOG(LS_INFO) << "Removing framerate down-scaling setting.";
|
RTC_LOG(LS_INFO) << "Removing framerate down-scaling setting.";
|
||||||
source_restrictor_->IncreaseFrameRateTo(
|
source_restrictor_->IncreaseFrameRateTo(
|
||||||
@ -884,7 +838,6 @@ void OveruseFrameDetectorResourceAdaptationModule::ApplyAdaptationTarget(
|
|||||||
return;
|
return;
|
||||||
case AdaptationAction::kDecreaseFrameRate:
|
case AdaptationAction::kDecreaseFrameRate:
|
||||||
source_restrictor_->DecreaseFrameRateTo(target.value);
|
source_restrictor_->DecreaseFrameRateTo(target.value);
|
||||||
GetAdaptCounter().IncrementFramerate(reason);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -908,7 +861,7 @@ void OveruseFrameDetectorResourceAdaptationModule::OnResourceUnderuse(
|
|||||||
MaybeUpdateVideoSourceRestrictions();
|
MaybeUpdateVideoSourceRestrictions();
|
||||||
// Stats and logging.
|
// Stats and logging.
|
||||||
UpdateAdaptationStats(reason);
|
UpdateAdaptationStats(reason);
|
||||||
RTC_LOG(LS_INFO) << GetConstAdaptCounter().ToString();
|
RTC_LOG(LS_INFO) << ActiveCountsToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceListenerResponse
|
ResourceListenerResponse
|
||||||
@ -921,7 +874,7 @@ OveruseFrameDetectorResourceAdaptationModule::OnResourceOveruse(
|
|||||||
int min_pixels_per_frame = MinPixelsPerFrame();
|
int min_pixels_per_frame = MinPixelsPerFrame();
|
||||||
// Should we adapt, if so to what target?
|
// Should we adapt, if so to what target?
|
||||||
absl::optional<AdaptationTarget> target =
|
absl::optional<AdaptationTarget> target =
|
||||||
GetAdaptDownTarget(input_pixels, input_fps, min_pixels_per_frame, reason);
|
GetAdaptDownTarget(input_pixels, input_fps, min_pixels_per_frame);
|
||||||
if (!target.has_value())
|
if (!target.has_value())
|
||||||
return ResourceListenerResponse::kNothing;
|
return ResourceListenerResponse::kNothing;
|
||||||
// Apply target.
|
// Apply target.
|
||||||
@ -933,7 +886,7 @@ OveruseFrameDetectorResourceAdaptationModule::OnResourceOveruse(
|
|||||||
MaybeUpdateVideoSourceRestrictions();
|
MaybeUpdateVideoSourceRestrictions();
|
||||||
// Stats and logging.
|
// Stats and logging.
|
||||||
UpdateAdaptationStats(reason);
|
UpdateAdaptationStats(reason);
|
||||||
RTC_LOG(LS_INFO) << GetConstAdaptCounter().ToString();
|
RTC_LOG(INFO) << ActiveCountsToString();
|
||||||
// In BALANCED, if requested FPS is higher or close to input FPS to the target
|
// In BALANCED, if requested FPS is higher or close to input FPS to the target
|
||||||
// we tell the QualityScaler to increase its frequency.
|
// we tell the QualityScaler to increase its frequency.
|
||||||
if (EffectiveDegradationPreference() == DegradationPreference::BALANCED &&
|
if (EffectiveDegradationPreference() == DegradationPreference::BALANCED &&
|
||||||
@ -1035,9 +988,74 @@ void OveruseFrameDetectorResourceAdaptationModule::
|
|||||||
encode_usage_resource_->SetTargetFrameRate(target_frame_rate);
|
encode_usage_resource_->SetTargetFrameRate(target_frame_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OveruseFrameDetectorResourceAdaptationModule::OnAdaptationCountChanged(
|
||||||
|
const AdaptationCounters& adaptation_count,
|
||||||
|
AdaptationCounters* active_count,
|
||||||
|
AdaptationCounters* other_active) {
|
||||||
|
RTC_DCHECK(active_count);
|
||||||
|
RTC_DCHECK(other_active);
|
||||||
|
const int active_total = active_count->Total();
|
||||||
|
const int other_total = other_active->Total();
|
||||||
|
const AdaptationCounters prev_total = *active_count + *other_active;
|
||||||
|
const AdaptationCounters delta = adaptation_count - prev_total;
|
||||||
|
|
||||||
|
RTC_DCHECK_EQ(
|
||||||
|
std::abs(delta.resolution_adaptations) + std::abs(delta.fps_adaptations),
|
||||||
|
1)
|
||||||
|
<< "Adaptation took more than one step!";
|
||||||
|
|
||||||
|
if (delta.resolution_adaptations > 0) {
|
||||||
|
++active_count->resolution_adaptations;
|
||||||
|
} else if (delta.resolution_adaptations < 0) {
|
||||||
|
if (active_count->resolution_adaptations == 0) {
|
||||||
|
RTC_DCHECK_GT(active_count->fps_adaptations, 0) << "No downgrades left";
|
||||||
|
RTC_DCHECK_GT(other_active->resolution_adaptations, 0)
|
||||||
|
<< "No resolution adaptation to borrow from";
|
||||||
|
// Lend an fps adaptation to other and take one resolution adaptation.
|
||||||
|
--active_count->fps_adaptations;
|
||||||
|
++other_active->fps_adaptations;
|
||||||
|
--other_active->resolution_adaptations;
|
||||||
|
} else {
|
||||||
|
--active_count->resolution_adaptations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (delta.fps_adaptations > 0) {
|
||||||
|
++active_count->fps_adaptations;
|
||||||
|
} else if (delta.fps_adaptations < 0) {
|
||||||
|
if (active_count->fps_adaptations == 0) {
|
||||||
|
RTC_DCHECK_GT(active_count->resolution_adaptations, 0)
|
||||||
|
<< "No downgrades left";
|
||||||
|
RTC_DCHECK_GT(other_active->fps_adaptations, 0)
|
||||||
|
<< "No fps adaptation to borrow from";
|
||||||
|
// Lend a resolution adaptation to other and take one fps adaptation.
|
||||||
|
--active_count->resolution_adaptations;
|
||||||
|
++other_active->resolution_adaptations;
|
||||||
|
--other_active->fps_adaptations;
|
||||||
|
} else {
|
||||||
|
--active_count->fps_adaptations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RTC_DCHECK(*active_count + *other_active == adaptation_count);
|
||||||
|
RTC_DCHECK_EQ(other_active->Total(), other_total);
|
||||||
|
RTC_DCHECK_EQ(active_count->Total(), active_total + delta.Total());
|
||||||
|
RTC_DCHECK_GE(active_count->resolution_adaptations, 0);
|
||||||
|
RTC_DCHECK_GE(active_count->fps_adaptations, 0);
|
||||||
|
RTC_DCHECK_GE(other_active->resolution_adaptations, 0);
|
||||||
|
RTC_DCHECK_GE(other_active->fps_adaptations, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(nisse): Delete, once AdaptReason and AdaptationReason are merged.
|
// TODO(nisse): Delete, once AdaptReason and AdaptationReason are merged.
|
||||||
void OveruseFrameDetectorResourceAdaptationModule::UpdateAdaptationStats(
|
void OveruseFrameDetectorResourceAdaptationModule::UpdateAdaptationStats(
|
||||||
AdaptationObserverInterface::AdaptReason reason) {
|
AdaptationObserverInterface::AdaptReason reason) {
|
||||||
|
// Update active counts
|
||||||
|
AdaptationCounters& active_count = active_counts_[reason];
|
||||||
|
AdaptationCounters& other_active = active_counts_[(reason + 1) % 2];
|
||||||
|
const AdaptationCounters total_counts =
|
||||||
|
source_restrictor_->adaptation_counters();
|
||||||
|
|
||||||
|
OnAdaptationCountChanged(total_counts, &active_count, &other_active);
|
||||||
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case AdaptationObserverInterface::AdaptReason::kCpu:
|
case AdaptationObserverInterface::AdaptReason::kCpu:
|
||||||
encoder_stats_observer_->OnAdaptationChanged(
|
encoder_stats_observer_->OnAdaptationChanged(
|
||||||
@ -1057,8 +1075,14 @@ void OveruseFrameDetectorResourceAdaptationModule::UpdateAdaptationStats(
|
|||||||
VideoStreamEncoderObserver::AdaptationSteps
|
VideoStreamEncoderObserver::AdaptationSteps
|
||||||
OveruseFrameDetectorResourceAdaptationModule::GetActiveCounts(
|
OveruseFrameDetectorResourceAdaptationModule::GetActiveCounts(
|
||||||
AdaptationObserverInterface::AdaptReason reason) {
|
AdaptationObserverInterface::AdaptReason reason) {
|
||||||
|
// TODO(https://crbug.com/webrtc/11392) Ideally this shuold be moved out of
|
||||||
|
// this class and into the encoder_stats_observer_.
|
||||||
|
const AdaptationCounters counters = active_counts_[reason];
|
||||||
|
|
||||||
VideoStreamEncoderObserver::AdaptationSteps counts =
|
VideoStreamEncoderObserver::AdaptationSteps counts =
|
||||||
GetConstAdaptCounter().Counts(reason);
|
VideoStreamEncoderObserver::AdaptationSteps();
|
||||||
|
counts.num_resolution_reductions = counters.resolution_adaptations;
|
||||||
|
counts.num_framerate_reductions = counters.fps_adaptations;
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case AdaptationObserverInterface::AdaptReason::kCpu:
|
case AdaptationObserverInterface::AdaptReason::kCpu:
|
||||||
if (!IsFramerateScalingEnabled(degradation_preference_))
|
if (!IsFramerateScalingEnabled(degradation_preference_))
|
||||||
@ -1095,30 +1119,6 @@ OveruseFrameDetectorResourceAdaptationModule::EffectiveDegradationPreference()
|
|||||||
: degradation_preference_;
|
: degradation_preference_;
|
||||||
}
|
}
|
||||||
|
|
||||||
OveruseFrameDetectorResourceAdaptationModule::AdaptCounter&
|
|
||||||
OveruseFrameDetectorResourceAdaptationModule::GetAdaptCounter() {
|
|
||||||
return adapt_counters_[degradation_preference_];
|
|
||||||
}
|
|
||||||
|
|
||||||
void OveruseFrameDetectorResourceAdaptationModule::ClearAdaptCounters() {
|
|
||||||
adapt_counters_.clear();
|
|
||||||
adapt_counters_.insert(
|
|
||||||
std::make_pair(DegradationPreference::DISABLED, AdaptCounter()));
|
|
||||||
adapt_counters_.insert(std::make_pair(
|
|
||||||
DegradationPreference::MAINTAIN_FRAMERATE, AdaptCounter()));
|
|
||||||
adapt_counters_.insert(std::make_pair(
|
|
||||||
DegradationPreference::MAINTAIN_RESOLUTION, AdaptCounter()));
|
|
||||||
adapt_counters_.insert(
|
|
||||||
std::make_pair(DegradationPreference::BALANCED, AdaptCounter()));
|
|
||||||
}
|
|
||||||
|
|
||||||
const OveruseFrameDetectorResourceAdaptationModule::AdaptCounter&
|
|
||||||
OveruseFrameDetectorResourceAdaptationModule::GetConstAdaptCounter() const {
|
|
||||||
auto it = adapt_counters_.find(degradation_preference_);
|
|
||||||
RTC_DCHECK(it != adapt_counters_.cend());
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OveruseFrameDetectorResourceAdaptationModule::CanAdaptUpResolution(
|
bool OveruseFrameDetectorResourceAdaptationModule::CanAdaptUpResolution(
|
||||||
int pixels,
|
int pixels,
|
||||||
uint32_t bitrate_bps) const {
|
uint32_t bitrate_bps) const {
|
||||||
@ -1158,15 +1158,36 @@ void OveruseFrameDetectorResourceAdaptationModule::
|
|||||||
try_quality_rampup = true;
|
try_quality_rampup = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (try_quality_rampup &&
|
// TODO(https://crbug.com/webrtc/11392): See if we can rely on the total
|
||||||
GetConstAdaptCounter().ResolutionCount(
|
// counts or the stats, and not the active counts.
|
||||||
AdaptationObserverInterface::AdaptReason::kQuality) > 0 &&
|
const AdaptationCounters& qp_counts =
|
||||||
GetConstAdaptCounter().TotalCount(
|
std::get<AdaptationObserverInterface::kQuality>(active_counts_);
|
||||||
AdaptationObserverInterface::AdaptReason::kCpu) == 0) {
|
const AdaptationCounters& cpu_counts =
|
||||||
|
std::get<AdaptationObserverInterface::kCpu>(active_counts_);
|
||||||
|
if (try_quality_rampup && qp_counts.resolution_adaptations > 0 &&
|
||||||
|
cpu_counts.Total() == 0) {
|
||||||
RTC_LOG(LS_INFO) << "Reset quality limitations.";
|
RTC_LOG(LS_INFO) << "Reset quality limitations.";
|
||||||
ResetVideoSourceRestrictions();
|
ResetVideoSourceRestrictions();
|
||||||
quality_rampup_done_ = true;
|
quality_rampup_done_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string OveruseFrameDetectorResourceAdaptationModule::ActiveCountsToString()
|
||||||
|
const {
|
||||||
|
rtc::StringBuilder ss;
|
||||||
|
|
||||||
|
ss << "Downgrade counts: fps: {";
|
||||||
|
for (size_t reason = 0; reason < active_counts_.size(); ++reason) {
|
||||||
|
ss << (reason ? " cpu" : "quality") << ":";
|
||||||
|
ss << active_counts_[reason].fps_adaptations;
|
||||||
|
}
|
||||||
|
ss << "}, resolution {";
|
||||||
|
for (size_t reason = 0; reason < active_counts_.size(); ++reason) {
|
||||||
|
ss << (reason ? " cpu" : "quality") << ":";
|
||||||
|
ss << active_counts_[reason].resolution_adaptations;
|
||||||
|
}
|
||||||
|
ss << "}";
|
||||||
|
|
||||||
|
return ss.Release();
|
||||||
|
}
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "rtc_base/experiments/balanced_degradation_settings.h"
|
#include "rtc_base/experiments/balanced_degradation_settings.h"
|
||||||
#include "rtc_base/experiments/quality_rampup_experiment.h"
|
#include "rtc_base/experiments/quality_rampup_experiment.h"
|
||||||
#include "rtc_base/experiments/quality_scaler_settings.h"
|
#include "rtc_base/experiments/quality_scaler_settings.h"
|
||||||
|
#include "rtc_base/strings/string_builder.h"
|
||||||
#include "system_wrappers/include/clock.h"
|
#include "system_wrappers/include/clock.h"
|
||||||
#include "video/encode_usage_resource.h"
|
#include "video/encode_usage_resource.h"
|
||||||
#include "video/overuse_frame_detector.h"
|
#include "video/overuse_frame_detector.h"
|
||||||
@ -37,6 +38,26 @@
|
|||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
|
// Counts the number of adaptations have resulted due to resource overuse.
|
||||||
|
// Today we can adapt resolution and fps.
|
||||||
|
struct AdaptationCounters {
|
||||||
|
AdaptationCounters() : resolution_adaptations(0), fps_adaptations(0) {}
|
||||||
|
AdaptationCounters(int resolution_adaptations, int fps_adaptations)
|
||||||
|
: resolution_adaptations(resolution_adaptations),
|
||||||
|
fps_adaptations(fps_adaptations) {}
|
||||||
|
|
||||||
|
int Total() const { return fps_adaptations + resolution_adaptations; }
|
||||||
|
|
||||||
|
bool operator==(const AdaptationCounters& rhs) const;
|
||||||
|
bool operator!=(const AdaptationCounters& rhs) const;
|
||||||
|
|
||||||
|
AdaptationCounters operator+(const AdaptationCounters& other) const;
|
||||||
|
AdaptationCounters operator-(const AdaptationCounters& other) const;
|
||||||
|
|
||||||
|
int resolution_adaptations;
|
||||||
|
int fps_adaptations;
|
||||||
|
};
|
||||||
|
|
||||||
class VideoStreamEncoder;
|
class VideoStreamEncoder;
|
||||||
|
|
||||||
// This class is used by the VideoStreamEncoder and is responsible for adapting
|
// This class is used by the VideoStreamEncoder and is responsible for adapting
|
||||||
@ -114,9 +135,20 @@ class OveruseFrameDetectorResourceAdaptationModule
|
|||||||
ResourceListenerResponse OnResourceUsageStateMeasured(
|
ResourceListenerResponse OnResourceUsageStateMeasured(
|
||||||
const Resource& resource) override;
|
const Resource& resource) override;
|
||||||
|
|
||||||
|
// For reasons of adaptation and statistics, we not only count the total
|
||||||
|
// number of adaptations, but we also count the number of adaptations per
|
||||||
|
// reason.
|
||||||
|
// This method takes the new total number of adaptations and allocates that to
|
||||||
|
// the "active" count - number of adaptations for the current reason.
|
||||||
|
// The "other" count is the number of adaptations for the other reason.
|
||||||
|
// This must be called for each adaptation step made.
|
||||||
|
static void OnAdaptationCountChanged(
|
||||||
|
const AdaptationCounters& adaptation_count,
|
||||||
|
AdaptationCounters* active_count,
|
||||||
|
AdaptationCounters* other_active);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class VideoSourceRestrictor;
|
class VideoSourceRestrictor;
|
||||||
class AdaptCounter;
|
|
||||||
class InitialFrameDropper;
|
class InitialFrameDropper;
|
||||||
|
|
||||||
enum class State { kStopped, kStarted };
|
enum class State { kStopped, kStarted };
|
||||||
@ -160,8 +192,7 @@ class OveruseFrameDetectorResourceAdaptationModule
|
|||||||
absl::optional<AdaptationTarget> GetAdaptDownTarget(
|
absl::optional<AdaptationTarget> GetAdaptDownTarget(
|
||||||
int input_pixels,
|
int input_pixels,
|
||||||
int input_fps,
|
int input_fps,
|
||||||
int min_pixels_per_frame,
|
int min_pixels_per_frame) const;
|
||||||
AdaptationObserverInterface::AdaptReason reason) const;
|
|
||||||
// Applies the |target| to |source_restrictor_|.
|
// Applies the |target| to |source_restrictor_|.
|
||||||
void ApplyAdaptationTarget(const AdaptationTarget& target,
|
void ApplyAdaptationTarget(const AdaptationTarget& target,
|
||||||
int min_pixels_per_frame,
|
int min_pixels_per_frame,
|
||||||
@ -179,8 +210,6 @@ class OveruseFrameDetectorResourceAdaptationModule
|
|||||||
int MinPixelsPerFrame() const;
|
int MinPixelsPerFrame() const;
|
||||||
VideoStreamEncoderObserver::AdaptationSteps GetActiveCounts(
|
VideoStreamEncoderObserver::AdaptationSteps GetActiveCounts(
|
||||||
AdaptationObserverInterface::AdaptReason reason);
|
AdaptationObserverInterface::AdaptReason reason);
|
||||||
void ClearAdaptCounters();
|
|
||||||
const AdaptCounter& GetConstAdaptCounter() const;
|
|
||||||
|
|
||||||
// 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
|
||||||
@ -196,7 +225,6 @@ class OveruseFrameDetectorResourceAdaptationModule
|
|||||||
|
|
||||||
void UpdateAdaptationStats(AdaptationObserverInterface::AdaptReason reason);
|
void UpdateAdaptationStats(AdaptationObserverInterface::AdaptReason reason);
|
||||||
DegradationPreference EffectiveDegradationPreference() const;
|
DegradationPreference EffectiveDegradationPreference() const;
|
||||||
AdaptCounter& GetAdaptCounter();
|
|
||||||
bool CanAdaptUpResolution(int pixels, uint32_t bitrate_bps) const;
|
bool CanAdaptUpResolution(int pixels, uint32_t bitrate_bps) 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
|
||||||
@ -207,6 +235,8 @@ class OveruseFrameDetectorResourceAdaptationModule
|
|||||||
void MaybePerformQualityRampupExperiment();
|
void MaybePerformQualityRampupExperiment();
|
||||||
void ResetVideoSourceRestrictions();
|
void ResetVideoSourceRestrictions();
|
||||||
|
|
||||||
|
std::string ActiveCountsToString() const;
|
||||||
|
|
||||||
ResourceAdaptationModuleListener* const adaptation_listener_;
|
ResourceAdaptationModuleListener* const adaptation_listener_;
|
||||||
Clock* clock_;
|
Clock* clock_;
|
||||||
State state_;
|
State state_;
|
||||||
@ -215,12 +245,6 @@ class OveruseFrameDetectorResourceAdaptationModule
|
|||||||
VideoSourceRestrictions video_source_restrictions_;
|
VideoSourceRestrictions video_source_restrictions_;
|
||||||
bool has_input_video_;
|
bool has_input_video_;
|
||||||
DegradationPreference degradation_preference_;
|
DegradationPreference degradation_preference_;
|
||||||
// Counters used for deciding if the video resolution or framerate is
|
|
||||||
// currently restricted, and if so, why, on a per degradation preference
|
|
||||||
// basis.
|
|
||||||
// TODO(sprang): Replace this with a state holding a relative overuse measure
|
|
||||||
// instead, that can be translated into suitable down-scale or fps limit.
|
|
||||||
std::map<const DegradationPreference, AdaptCounter> adapt_counters_;
|
|
||||||
const BalancedDegradationSettings balanced_settings_;
|
const BalancedDegradationSettings balanced_settings_;
|
||||||
// Stores a snapshot of the last adaptation request triggered by an AdaptUp
|
// Stores a snapshot of the last adaptation request triggered by an AdaptUp
|
||||||
// or AdaptDown signal.
|
// or AdaptDown signal.
|
||||||
@ -253,6 +277,15 @@ class OveruseFrameDetectorResourceAdaptationModule
|
|||||||
const AdaptationObserverInterface::AdaptReason reason;
|
const AdaptationObserverInterface::AdaptReason reason;
|
||||||
};
|
};
|
||||||
std::vector<ResourceAndReason> resources_;
|
std::vector<ResourceAndReason> resources_;
|
||||||
|
// One AdaptationCounter for each reason, tracking the number of times we have
|
||||||
|
// adapted for each reason. The sum of active_counts_ MUST always equal the
|
||||||
|
// total adaptation provided by the VideoSourceRestrictions.
|
||||||
|
// TODO(https://crbug.com/webrtc/11392): Move all active count logic to
|
||||||
|
// encoder_stats_observer_; Counters used for deciding if the video resolution
|
||||||
|
// or framerate is currently restricted, and if so, why, on a per degradation
|
||||||
|
// preference basis.
|
||||||
|
std::array<AdaptationCounters, AdaptationObserverInterface::kScaleReasonSize>
|
||||||
|
active_counts_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
144
video/overuse_frame_detector_resource_adaptation_unittest.cc
Normal file
144
video/overuse_frame_detector_resource_adaptation_unittest.cc
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "video/overuse_frame_detector_resource_adaptation_module.h"
|
||||||
|
|
||||||
|
#include "test/gmock.h"
|
||||||
|
#include "test/gtest.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
TEST(AdaptationCountersTest, Addition) {
|
||||||
|
AdaptationCounters a;
|
||||||
|
AdaptationCounters b(1, 2);
|
||||||
|
AdaptationCounters total = a + b;
|
||||||
|
EXPECT_EQ(1, total.resolution_adaptations);
|
||||||
|
EXPECT_EQ(2, total.fps_adaptations);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AdaptationCountersTest, Subtraction) {
|
||||||
|
AdaptationCounters a(0, 1);
|
||||||
|
AdaptationCounters b(2, 1);
|
||||||
|
AdaptationCounters diff = a - b;
|
||||||
|
EXPECT_EQ(-2, diff.resolution_adaptations);
|
||||||
|
EXPECT_EQ(0, diff.fps_adaptations);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AdaptationCountersTest, Equality) {
|
||||||
|
AdaptationCounters a(1, 2);
|
||||||
|
AdaptationCounters b(2, 1);
|
||||||
|
EXPECT_EQ(a, a);
|
||||||
|
EXPECT_NE(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AdaptationCountersTest, SelfAdditionSubtraction) {
|
||||||
|
AdaptationCounters a(1, 0);
|
||||||
|
AdaptationCounters b(0, 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(a, a + b - b);
|
||||||
|
EXPECT_EQ(a, b + a - b);
|
||||||
|
EXPECT_EQ(a, a - b + b);
|
||||||
|
EXPECT_EQ(a, b - b + a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OveruseFrameDetectorResourceAdaptationModuleTest,
|
||||||
|
FirstAdaptationDown_Fps) {
|
||||||
|
AdaptationCounters cpu;
|
||||||
|
AdaptationCounters qp;
|
||||||
|
AdaptationCounters total(0, 1);
|
||||||
|
|
||||||
|
OveruseFrameDetectorResourceAdaptationModule::OnAdaptationCountChanged(
|
||||||
|
total, &cpu, &qp);
|
||||||
|
AdaptationCounters expected_cpu(0, 1);
|
||||||
|
AdaptationCounters expected_qp;
|
||||||
|
EXPECT_EQ(expected_cpu, cpu);
|
||||||
|
EXPECT_EQ(expected_qp, qp);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OveruseFrameDetectorResourceAdaptationModuleTest,
|
||||||
|
FirstAdaptationDown_Resolution) {
|
||||||
|
AdaptationCounters cpu;
|
||||||
|
AdaptationCounters qp;
|
||||||
|
AdaptationCounters total(1, 0);
|
||||||
|
|
||||||
|
OveruseFrameDetectorResourceAdaptationModule::OnAdaptationCountChanged(
|
||||||
|
total, &cpu, &qp);
|
||||||
|
AdaptationCounters expected_cpu(1, 0);
|
||||||
|
AdaptationCounters expected_qp;
|
||||||
|
EXPECT_EQ(expected_cpu, cpu);
|
||||||
|
EXPECT_EQ(expected_qp, qp);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OveruseFrameDetectorResourceAdaptationModuleTest, LastAdaptUp_Fps) {
|
||||||
|
AdaptationCounters cpu(0, 1);
|
||||||
|
AdaptationCounters qp;
|
||||||
|
AdaptationCounters total;
|
||||||
|
|
||||||
|
OveruseFrameDetectorResourceAdaptationModule::OnAdaptationCountChanged(
|
||||||
|
total, &cpu, &qp);
|
||||||
|
AdaptationCounters expected_cpu;
|
||||||
|
AdaptationCounters expected_qp;
|
||||||
|
EXPECT_EQ(expected_cpu, cpu);
|
||||||
|
EXPECT_EQ(expected_qp, qp);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OveruseFrameDetectorResourceAdaptationModuleTest, LastAdaptUp_Resolution) {
|
||||||
|
AdaptationCounters cpu(1, 0);
|
||||||
|
AdaptationCounters qp;
|
||||||
|
AdaptationCounters total;
|
||||||
|
|
||||||
|
OveruseFrameDetectorResourceAdaptationModule::OnAdaptationCountChanged(
|
||||||
|
total, &cpu, &qp);
|
||||||
|
AdaptationCounters expected_cpu;
|
||||||
|
AdaptationCounters expected_qp;
|
||||||
|
EXPECT_EQ(expected_cpu, cpu);
|
||||||
|
EXPECT_EQ(expected_qp, qp);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OveruseFrameDetectorResourceAdaptationModuleTest,
|
||||||
|
AdaptUpWithBorrow_Resolution) {
|
||||||
|
AdaptationCounters cpu(0, 1);
|
||||||
|
AdaptationCounters qp(1, 0);
|
||||||
|
AdaptationCounters total(0, 1);
|
||||||
|
|
||||||
|
// CPU adaptation for resolution, but no
|
||||||
|
// resolution adaptation left from CPU.
|
||||||
|
// We then borrow the resolution
|
||||||
|
// adaptation from qp, and give qp the
|
||||||
|
// fps adaptation from CPU.
|
||||||
|
OveruseFrameDetectorResourceAdaptationModule::OnAdaptationCountChanged(
|
||||||
|
total, &cpu, &qp);
|
||||||
|
|
||||||
|
AdaptationCounters expected_cpu(0, 0);
|
||||||
|
AdaptationCounters expected_qp(0, 1);
|
||||||
|
EXPECT_EQ(expected_cpu, cpu);
|
||||||
|
EXPECT_EQ(expected_qp, qp);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OveruseFrameDetectorResourceAdaptationModuleTest, AdaptUpWithBorrow_Fps) {
|
||||||
|
AdaptationCounters cpu(1, 0);
|
||||||
|
AdaptationCounters qp(0, 1);
|
||||||
|
AdaptationCounters total(1, 0);
|
||||||
|
|
||||||
|
// CPU adaptation for fps, but no
|
||||||
|
// fps adaptation left from CPU. We
|
||||||
|
// then borrow the fps adaptation
|
||||||
|
// from qp, and give qp the
|
||||||
|
// resolution adaptation from CPU.
|
||||||
|
OveruseFrameDetectorResourceAdaptationModule::OnAdaptationCountChanged(
|
||||||
|
total, &cpu, &qp);
|
||||||
|
|
||||||
|
AdaptationCounters expected_cpu(0, 0);
|
||||||
|
AdaptationCounters expected_qp(1, 0);
|
||||||
|
EXPECT_EQ(expected_cpu, cpu);
|
||||||
|
EXPECT_EQ(expected_qp, qp);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
@ -2235,6 +2235,73 @@ TEST_F(VideoStreamEncoderTest,
|
|||||||
video_stream_encoder_->Stop();
|
video_stream_encoder_->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(VideoStreamEncoderTest,
|
||||||
|
StatsTracksCpuAdaptationStatsWhenSwitchingSource_Balanced) {
|
||||||
|
video_stream_encoder_->OnBitrateUpdated(
|
||||||
|
DataRate::BitsPerSec(kTargetBitrateBps),
|
||||||
|
DataRate::BitsPerSec(kTargetBitrateBps),
|
||||||
|
DataRate::BitsPerSec(kTargetBitrateBps), 0, 0, 0);
|
||||||
|
|
||||||
|
const int kWidth = 1280;
|
||||||
|
const int kHeight = 720;
|
||||||
|
int sequence = 1;
|
||||||
|
|
||||||
|
// Enable BALANCED preference, no initial limitation.
|
||||||
|
test::FrameForwarder source;
|
||||||
|
video_stream_encoder_->SetSource(&source,
|
||||||
|
webrtc::DegradationPreference::BALANCED);
|
||||||
|
source.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
|
||||||
|
WaitForEncodedFrame(sequence++);
|
||||||
|
VideoSendStream::Stats stats = stats_proxy_->GetStats();
|
||||||
|
EXPECT_FALSE(stats.cpu_limited_resolution);
|
||||||
|
EXPECT_FALSE(stats.cpu_limited_framerate);
|
||||||
|
EXPECT_EQ(0, stats.number_of_cpu_adapt_changes);
|
||||||
|
|
||||||
|
// Trigger CPU overuse, should now adapt down.
|
||||||
|
video_stream_encoder_->TriggerCpuOveruse();
|
||||||
|
source.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
|
||||||
|
WaitForEncodedFrame(sequence++);
|
||||||
|
stats = stats_proxy_->GetStats();
|
||||||
|
EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
|
||||||
|
|
||||||
|
// Set new degradation preference should clear restrictions since we changed
|
||||||
|
// from BALANCED.
|
||||||
|
video_stream_encoder_->SetSource(
|
||||||
|
&source, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
|
||||||
|
source.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
|
||||||
|
WaitForEncodedFrame(sequence++);
|
||||||
|
stats = stats_proxy_->GetStats();
|
||||||
|
EXPECT_FALSE(stats.cpu_limited_resolution);
|
||||||
|
EXPECT_FALSE(stats.cpu_limited_framerate);
|
||||||
|
EXPECT_EQ(1, stats.number_of_cpu_adapt_changes);
|
||||||
|
|
||||||
|
// Force an input frame rate to be available, or the adaptation call won't
|
||||||
|
// know what framerate to adapt from.
|
||||||
|
VideoSendStream::Stats mock_stats = stats_proxy_->GetStats();
|
||||||
|
mock_stats.input_frame_rate = 30;
|
||||||
|
stats_proxy_->SetMockStats(mock_stats);
|
||||||
|
video_stream_encoder_->TriggerCpuOveruse();
|
||||||
|
stats_proxy_->ResetMockStats();
|
||||||
|
source.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
|
||||||
|
WaitForEncodedFrame(sequence++);
|
||||||
|
|
||||||
|
// We have now adapted once.
|
||||||
|
stats = stats_proxy_->GetStats();
|
||||||
|
EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
|
||||||
|
|
||||||
|
// Back to BALANCED, should clear the restrictions again.
|
||||||
|
video_stream_encoder_->SetSource(&source,
|
||||||
|
webrtc::DegradationPreference::BALANCED);
|
||||||
|
source.IncomingCapturedFrame(CreateFrame(sequence, kWidth, kHeight));
|
||||||
|
WaitForEncodedFrame(sequence++);
|
||||||
|
stats = stats_proxy_->GetStats();
|
||||||
|
EXPECT_FALSE(stats.cpu_limited_resolution);
|
||||||
|
EXPECT_FALSE(stats.cpu_limited_framerate);
|
||||||
|
EXPECT_EQ(2, stats.number_of_cpu_adapt_changes);
|
||||||
|
|
||||||
|
video_stream_encoder_->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(VideoStreamEncoderTest,
|
TEST_F(VideoStreamEncoderTest,
|
||||||
StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
|
StatsTracksCpuAdaptationStatsWhenSwitchingSource) {
|
||||||
video_stream_encoder_->OnBitrateUpdated(
|
video_stream_encoder_->OnBitrateUpdated(
|
||||||
|
Reference in New Issue
Block a user