When a resource is removed from the ResourceAdaptationProcessor, and the resource is the most limited resource, we reset the current adaptation to the next most limited resource level. In the case that this resource is the only adapted resource then we reset all adaptations. Bug: webrtc:11636 Change-Id: I29acc5a3934f42f00db79b3bb2171156b1313937 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/176406 Commit-Queue: Evan Shrubsole <eshr@google.com> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Reviewed-by: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/master@{#31520}
576 lines
22 KiB
C++
576 lines
22 KiB
C++
/*
|
|
* Copyright 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 "call/adaptation/video_stream_adapter.h"
|
|
|
|
#include <algorithm>
|
|
#include <limits>
|
|
#include <utility>
|
|
|
|
#include "absl/types/optional.h"
|
|
#include "api/video/video_adaptation_reason.h"
|
|
#include "api/video_codecs/video_encoder.h"
|
|
#include "rtc_base/constructor_magic.h"
|
|
#include "rtc_base/logging.h"
|
|
#include "rtc_base/numerics/safe_conversions.h"
|
|
|
|
namespace webrtc {
|
|
|
|
const int kMinFrameRateFps = 2;
|
|
|
|
namespace {
|
|
|
|
// Generate suggested higher and lower frame rates and resolutions, to be
|
|
// applied to the VideoSourceRestrictor. These are used in "maintain-resolution"
|
|
// and "maintain-framerate". The "balanced" degradation preference also makes
|
|
// use of BalancedDegradationPreference when generating suggestions. The
|
|
// VideoSourceRestrictor decidedes whether or not a proposed adaptation is
|
|
// valid.
|
|
|
|
// For frame rate, the steps we take are 2/3 (down) and 3/2 (up).
|
|
int GetLowerFrameRateThan(int fps) {
|
|
RTC_DCHECK(fps != std::numeric_limits<int>::max());
|
|
return (fps * 2) / 3;
|
|
}
|
|
// TODO(hbos): Use absl::optional<> instead?
|
|
int GetHigherFrameRateThan(int fps) {
|
|
return fps != std::numeric_limits<int>::max()
|
|
? (fps * 3) / 2
|
|
: std::numeric_limits<int>::max();
|
|
}
|
|
|
|
// For resolution, the steps we take are 3/5 (down) and 5/3 (up).
|
|
// Notice the asymmetry of which restriction property is set depending on if
|
|
// we are adapting up or down:
|
|
// - VideoSourceRestrictor::DecreaseResolution() sets the max_pixels_per_frame()
|
|
// to the desired target and target_pixels_per_frame() to null.
|
|
// - VideoSourceRestrictor::IncreaseResolutionTo() sets the
|
|
// target_pixels_per_frame() to the desired target, and max_pixels_per_frame()
|
|
// is set according to VideoSourceRestrictor::GetIncreasedMaxPixelsWanted().
|
|
int GetLowerResolutionThan(int pixel_count) {
|
|
RTC_DCHECK(pixel_count != std::numeric_limits<int>::max());
|
|
return (pixel_count * 3) / 5;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
VideoSourceRestrictions FilterRestrictionsByDegradationPreference(
|
|
VideoSourceRestrictions source_restrictions,
|
|
DegradationPreference degradation_preference) {
|
|
switch (degradation_preference) {
|
|
case DegradationPreference::BALANCED:
|
|
break;
|
|
case DegradationPreference::MAINTAIN_FRAMERATE:
|
|
source_restrictions.set_max_frame_rate(absl::nullopt);
|
|
break;
|
|
case DegradationPreference::MAINTAIN_RESOLUTION:
|
|
source_restrictions.set_max_pixels_per_frame(absl::nullopt);
|
|
source_restrictions.set_target_pixels_per_frame(absl::nullopt);
|
|
break;
|
|
case DegradationPreference::DISABLED:
|
|
source_restrictions.set_max_pixels_per_frame(absl::nullopt);
|
|
source_restrictions.set_target_pixels_per_frame(absl::nullopt);
|
|
source_restrictions.set_max_frame_rate(absl::nullopt);
|
|
}
|
|
return source_restrictions;
|
|
}
|
|
|
|
VideoAdaptationCounters FilterVideoAdaptationCountersByDegradationPreference(
|
|
VideoAdaptationCounters 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;
|
|
}
|
|
|
|
// TODO(hbos): Use absl::optional<> instead?
|
|
int GetHigherResolutionThan(int pixel_count) {
|
|
return pixel_count != std::numeric_limits<int>::max()
|
|
? (pixel_count * 5) / 3
|
|
: std::numeric_limits<int>::max();
|
|
}
|
|
|
|
// static
|
|
const char* Adaptation::StatusToString(Adaptation::Status status) {
|
|
switch (status) {
|
|
case Adaptation::Status::kValid:
|
|
return "kValid";
|
|
case Adaptation::Status::kLimitReached:
|
|
return "kLimitReached";
|
|
case Adaptation::Status::kAwaitingPreviousAdaptation:
|
|
return "kAwaitingPreviousAdaptation";
|
|
}
|
|
}
|
|
|
|
Adaptation::Step::Step(StepType type, int target) : type(type), target(target) {
|
|
RTC_DCHECK_NE(type, Adaptation::StepType::kForce);
|
|
}
|
|
|
|
Adaptation::Step::Step(VideoSourceRestrictions restrictions,
|
|
VideoAdaptationCounters counters)
|
|
: type(Adaptation::StepType::kForce),
|
|
restrictions(restrictions),
|
|
counters(counters) {}
|
|
|
|
Adaptation::Adaptation(int validation_id, Step step)
|
|
: validation_id_(validation_id),
|
|
status_(Status::kValid),
|
|
step_(std::move(step)),
|
|
min_pixel_limit_reached_(false) {}
|
|
|
|
Adaptation::Adaptation(int validation_id,
|
|
Step step,
|
|
bool min_pixel_limit_reached)
|
|
: validation_id_(validation_id),
|
|
status_(Status::kValid),
|
|
step_(std::move(step)),
|
|
min_pixel_limit_reached_(min_pixel_limit_reached) {}
|
|
|
|
Adaptation::Adaptation(int validation_id, Status invalid_status)
|
|
: validation_id_(validation_id),
|
|
status_(invalid_status),
|
|
step_(absl::nullopt),
|
|
min_pixel_limit_reached_(false) {
|
|
RTC_DCHECK_NE(status_, Status::kValid);
|
|
}
|
|
|
|
Adaptation::Adaptation(int validation_id,
|
|
Status invalid_status,
|
|
bool min_pixel_limit_reached)
|
|
: validation_id_(validation_id),
|
|
status_(invalid_status),
|
|
step_(absl::nullopt),
|
|
min_pixel_limit_reached_(min_pixel_limit_reached) {
|
|
RTC_DCHECK_NE(status_, Status::kValid);
|
|
}
|
|
|
|
Adaptation::Status Adaptation::status() const {
|
|
return status_;
|
|
}
|
|
|
|
bool Adaptation::min_pixel_limit_reached() const {
|
|
return min_pixel_limit_reached_;
|
|
}
|
|
|
|
const Adaptation::Step& Adaptation::step() const {
|
|
RTC_DCHECK_EQ(status_, Status::kValid);
|
|
return step_.value();
|
|
}
|
|
|
|
// VideoSourceRestrictor is responsible for keeping track of current
|
|
// VideoSourceRestrictions.
|
|
class VideoStreamAdapter::VideoSourceRestrictor {
|
|
public:
|
|
VideoSourceRestrictor() {}
|
|
|
|
VideoSourceRestrictions source_restrictions() const {
|
|
return source_restrictions_;
|
|
}
|
|
const VideoAdaptationCounters& adaptation_counters() const {
|
|
return adaptations_;
|
|
}
|
|
void ClearRestrictions() {
|
|
source_restrictions_ = VideoSourceRestrictions();
|
|
adaptations_ = VideoAdaptationCounters();
|
|
}
|
|
|
|
void ForceRestrictions(const VideoSourceRestrictions& restrictions,
|
|
const VideoAdaptationCounters& counters) {
|
|
source_restrictions_ = restrictions;
|
|
adaptations_ = counters;
|
|
}
|
|
|
|
void set_min_pixels_per_frame(int min_pixels_per_frame) {
|
|
min_pixels_per_frame_ = min_pixels_per_frame;
|
|
}
|
|
|
|
int min_pixels_per_frame() const { return min_pixels_per_frame_; }
|
|
|
|
bool CanDecreaseResolutionTo(int target_pixels) const {
|
|
int max_pixels_per_frame = rtc::dchecked_cast<int>(
|
|
source_restrictions_.max_pixels_per_frame().value_or(
|
|
std::numeric_limits<int>::max()));
|
|
return target_pixels < max_pixels_per_frame &&
|
|
target_pixels >= min_pixels_per_frame_;
|
|
}
|
|
|
|
bool CanIncreaseResolutionTo(int target_pixels) const {
|
|
int max_pixels_wanted = GetIncreasedMaxPixelsWanted(target_pixels);
|
|
int max_pixels_per_frame = rtc::dchecked_cast<int>(
|
|
source_restrictions_.max_pixels_per_frame().value_or(
|
|
std::numeric_limits<int>::max()));
|
|
return max_pixels_wanted > max_pixels_per_frame;
|
|
}
|
|
|
|
bool CanDecreaseFrameRateTo(int max_frame_rate) const {
|
|
const int fps_wanted = std::max(kMinFrameRateFps, max_frame_rate);
|
|
return fps_wanted < rtc::dchecked_cast<int>(
|
|
source_restrictions_.max_frame_rate().value_or(
|
|
std::numeric_limits<int>::max()));
|
|
}
|
|
|
|
bool CanIncreaseFrameRateTo(int max_frame_rate) const {
|
|
return max_frame_rate > rtc::dchecked_cast<int>(
|
|
source_restrictions_.max_frame_rate().value_or(
|
|
std::numeric_limits<int>::max()));
|
|
}
|
|
|
|
void ApplyAdaptationStep(const Adaptation::Step& step,
|
|
DegradationPreference degradation_preference) {
|
|
switch (step.type) {
|
|
case Adaptation::StepType::kIncreaseResolution:
|
|
RTC_DCHECK(step.target);
|
|
IncreaseResolutionTo(step.target.value());
|
|
break;
|
|
case Adaptation::StepType::kDecreaseResolution:
|
|
RTC_DCHECK(step.target);
|
|
DecreaseResolutionTo(step.target.value());
|
|
break;
|
|
case Adaptation::StepType::kIncreaseFrameRate:
|
|
RTC_DCHECK(step.target);
|
|
IncreaseFrameRateTo(step.target.value());
|
|
// TODO(https://crbug.com/webrtc/11222): Don't adapt in two steps.
|
|
// GetAdaptationUp() should tell us the correct value, but BALANCED
|
|
// logic in DecrementFramerate() makes it hard to predict whether this
|
|
// will be the last step. Remove the dependency on
|
|
// adaptation_counters().
|
|
if (degradation_preference == DegradationPreference::BALANCED &&
|
|
adaptation_counters().fps_adaptations == 0 &&
|
|
step.target != std::numeric_limits<int>::max()) {
|
|
RTC_LOG(LS_INFO) << "Removing framerate down-scaling setting.";
|
|
IncreaseFrameRateTo(std::numeric_limits<int>::max());
|
|
}
|
|
break;
|
|
case Adaptation::StepType::kDecreaseFrameRate:
|
|
RTC_DCHECK(step.target);
|
|
DecreaseFrameRateTo(step.target.value());
|
|
break;
|
|
case Adaptation::StepType::kForce:
|
|
RTC_DCHECK(step.restrictions);
|
|
RTC_DCHECK(step.counters);
|
|
ForceRestrictions(step.restrictions.value(), step.counters.value());
|
|
break;
|
|
}
|
|
}
|
|
|
|
private:
|
|
static int GetIncreasedMaxPixelsWanted(int target_pixels) {
|
|
if (target_pixels == std::numeric_limits<int>::max())
|
|
return std::numeric_limits<int>::max();
|
|
// When we decrease resolution, we go down to at most 3/5 of current pixels.
|
|
// Thus to increase resolution, we need 3/5 to get back to where we started.
|
|
// When going up, the desired max_pixels_per_frame() has to be significantly
|
|
// higher than the target because the source's native resolutions might not
|
|
// match the target. We pick 12/5 of the target.
|
|
//
|
|
// (This value was historically 4 times the old target, which is (3/5)*4 of
|
|
// the new target - or 12/5 - assuming the target is adjusted according to
|
|
// the above steps.)
|
|
RTC_DCHECK(target_pixels != std::numeric_limits<int>::max());
|
|
return (target_pixels * 12) / 5;
|
|
}
|
|
|
|
void DecreaseResolutionTo(int target_pixels) {
|
|
RTC_DCHECK(CanDecreaseResolutionTo(target_pixels));
|
|
RTC_LOG(LS_INFO) << "Scaling down resolution, max pixels: "
|
|
<< target_pixels;
|
|
source_restrictions_.set_max_pixels_per_frame(
|
|
target_pixels != std::numeric_limits<int>::max()
|
|
? absl::optional<size_t>(target_pixels)
|
|
: absl::nullopt);
|
|
source_restrictions_.set_target_pixels_per_frame(absl::nullopt);
|
|
++adaptations_.resolution_adaptations;
|
|
}
|
|
|
|
void IncreaseResolutionTo(int target_pixels) {
|
|
RTC_DCHECK(CanIncreaseResolutionTo(target_pixels));
|
|
int max_pixels_wanted = GetIncreasedMaxPixelsWanted(target_pixels);
|
|
RTC_LOG(LS_INFO) << "Scaling up resolution, max pixels: "
|
|
<< max_pixels_wanted;
|
|
source_restrictions_.set_max_pixels_per_frame(
|
|
max_pixels_wanted != std::numeric_limits<int>::max()
|
|
? absl::optional<size_t>(max_pixels_wanted)
|
|
: absl::nullopt);
|
|
source_restrictions_.set_target_pixels_per_frame(
|
|
max_pixels_wanted != std::numeric_limits<int>::max()
|
|
? absl::optional<size_t>(target_pixels)
|
|
: absl::nullopt);
|
|
--adaptations_.resolution_adaptations;
|
|
RTC_DCHECK_GE(adaptations_.resolution_adaptations, 0);
|
|
}
|
|
|
|
void DecreaseFrameRateTo(int max_frame_rate) {
|
|
RTC_DCHECK(CanDecreaseFrameRateTo(max_frame_rate));
|
|
max_frame_rate = std::max(kMinFrameRateFps, max_frame_rate);
|
|
RTC_LOG(LS_INFO) << "Scaling down framerate: " << max_frame_rate;
|
|
source_restrictions_.set_max_frame_rate(
|
|
max_frame_rate != std::numeric_limits<int>::max()
|
|
? absl::optional<double>(max_frame_rate)
|
|
: absl::nullopt);
|
|
++adaptations_.fps_adaptations;
|
|
}
|
|
|
|
void IncreaseFrameRateTo(int max_frame_rate) {
|
|
RTC_DCHECK(CanIncreaseFrameRateTo(max_frame_rate));
|
|
RTC_LOG(LS_INFO) << "Scaling up framerate: " << max_frame_rate;
|
|
source_restrictions_.set_max_frame_rate(
|
|
max_frame_rate != std::numeric_limits<int>::max()
|
|
? absl::optional<double>(max_frame_rate)
|
|
: absl::nullopt);
|
|
--adaptations_.fps_adaptations;
|
|
RTC_DCHECK_GE(adaptations_.fps_adaptations, 0);
|
|
}
|
|
|
|
// Needed by CanDecreaseResolutionTo().
|
|
int min_pixels_per_frame_ = 0;
|
|
// Current State.
|
|
VideoSourceRestrictions source_restrictions_;
|
|
VideoAdaptationCounters adaptations_;
|
|
};
|
|
|
|
VideoStreamAdapter::VideoStreamAdapter()
|
|
: source_restrictor_(std::make_unique<VideoSourceRestrictor>()),
|
|
balanced_settings_(),
|
|
adaptation_validation_id_(0),
|
|
degradation_preference_(DegradationPreference::DISABLED),
|
|
input_state_(),
|
|
last_adaptation_request_(absl::nullopt) {}
|
|
|
|
VideoStreamAdapter::~VideoStreamAdapter() {}
|
|
|
|
VideoSourceRestrictions VideoStreamAdapter::source_restrictions() const {
|
|
return source_restrictor_->source_restrictions();
|
|
}
|
|
|
|
const VideoAdaptationCounters& VideoStreamAdapter::adaptation_counters() const {
|
|
return source_restrictor_->adaptation_counters();
|
|
}
|
|
|
|
void VideoStreamAdapter::ClearRestrictions() {
|
|
// Invalidate any previously returned Adaptation.
|
|
++adaptation_validation_id_;
|
|
source_restrictor_->ClearRestrictions();
|
|
last_adaptation_request_.reset();
|
|
}
|
|
|
|
void VideoStreamAdapter::SetDegradationPreference(
|
|
DegradationPreference degradation_preference) {
|
|
if (degradation_preference_ == degradation_preference)
|
|
return;
|
|
// Invalidate any previously returned Adaptation.
|
|
++adaptation_validation_id_;
|
|
if (degradation_preference == DegradationPreference::BALANCED ||
|
|
degradation_preference_ == DegradationPreference::BALANCED) {
|
|
ClearRestrictions();
|
|
}
|
|
degradation_preference_ = degradation_preference;
|
|
}
|
|
|
|
void VideoStreamAdapter::SetInput(VideoStreamInputState input_state) {
|
|
// Invalidate any previously returned Adaptation.
|
|
++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_NE(degradation_preference_, DegradationPreference::DISABLED);
|
|
RTC_DCHECK(input_state_.HasInputFrameSizeAndFramesPerSecond());
|
|
// Don't adapt if we're awaiting a previous adaptation to have an effect.
|
|
bool last_request_increased_resolution =
|
|
last_adaptation_request_ && last_adaptation_request_->step_type_ ==
|
|
Adaptation::StepType::kIncreaseResolution;
|
|
if (last_request_increased_resolution &&
|
|
degradation_preference_ == DegradationPreference::MAINTAIN_FRAMERATE &&
|
|
input_state_.frame_size_pixels().value() <=
|
|
last_adaptation_request_->input_pixel_count_) {
|
|
return Adaptation(adaptation_validation_id_,
|
|
Adaptation::Status::kAwaitingPreviousAdaptation);
|
|
}
|
|
|
|
// Maybe propose targets based on degradation preference.
|
|
switch (degradation_preference_) {
|
|
case DegradationPreference::BALANCED: {
|
|
// Attempt to increase target frame rate.
|
|
int target_fps =
|
|
balanced_settings_.MaxFps(input_state_.video_codec_type(),
|
|
input_state_.frame_size_pixels().value());
|
|
if (source_restrictor_->CanIncreaseFrameRateTo(target_fps)) {
|
|
return Adaptation(
|
|
adaptation_validation_id_,
|
|
Adaptation::Step(Adaptation::StepType::kIncreaseFrameRate,
|
|
target_fps));
|
|
}
|
|
// Scale up resolution.
|
|
ABSL_FALLTHROUGH_INTENDED;
|
|
}
|
|
case DegradationPreference::MAINTAIN_FRAMERATE: {
|
|
// Attempt to increase pixel count.
|
|
int target_pixels = input_state_.frame_size_pixels().value();
|
|
if (source_restrictor_->adaptation_counters().resolution_adaptations ==
|
|
1) {
|
|
RTC_LOG(LS_INFO) << "Removing resolution down-scaling setting.";
|
|
target_pixels = std::numeric_limits<int>::max();
|
|
}
|
|
target_pixels = GetHigherResolutionThan(target_pixels);
|
|
if (!source_restrictor_->CanIncreaseResolutionTo(target_pixels)) {
|
|
return Adaptation(adaptation_validation_id_,
|
|
Adaptation::Status::kLimitReached);
|
|
}
|
|
return Adaptation(
|
|
adaptation_validation_id_,
|
|
Adaptation::Step(Adaptation::StepType::kIncreaseResolution,
|
|
target_pixels));
|
|
}
|
|
case DegradationPreference::MAINTAIN_RESOLUTION: {
|
|
// Scale up framerate.
|
|
int target_fps = input_state_.frames_per_second();
|
|
if (source_restrictor_->adaptation_counters().fps_adaptations == 1) {
|
|
RTC_LOG(LS_INFO) << "Removing framerate down-scaling setting.";
|
|
target_fps = std::numeric_limits<int>::max();
|
|
}
|
|
target_fps = GetHigherFrameRateThan(target_fps);
|
|
if (!source_restrictor_->CanIncreaseFrameRateTo(target_fps)) {
|
|
return Adaptation(adaptation_validation_id_,
|
|
Adaptation::Status::kLimitReached);
|
|
}
|
|
return Adaptation(
|
|
adaptation_validation_id_,
|
|
Adaptation::Step(Adaptation::StepType::kIncreaseFrameRate,
|
|
target_fps));
|
|
}
|
|
case DegradationPreference::DISABLED:
|
|
RTC_NOTREACHED();
|
|
return Adaptation(adaptation_validation_id_,
|
|
Adaptation::Status::kLimitReached);
|
|
}
|
|
}
|
|
|
|
Adaptation VideoStreamAdapter::GetAdaptationDown() const {
|
|
RTC_DCHECK_NE(degradation_preference_, DegradationPreference::DISABLED);
|
|
RTC_DCHECK(input_state_.HasInputFrameSizeAndFramesPerSecond());
|
|
// Don't adapt if we're awaiting a previous adaptation to have an effect or
|
|
// if we switched degradation preference.
|
|
bool last_request_decreased_resolution =
|
|
last_adaptation_request_ && last_adaptation_request_->step_type_ ==
|
|
Adaptation::StepType::kDecreaseResolution;
|
|
if (last_request_decreased_resolution &&
|
|
degradation_preference_ == DegradationPreference::MAINTAIN_FRAMERATE &&
|
|
input_state_.frame_size_pixels().value() >=
|
|
last_adaptation_request_->input_pixel_count_) {
|
|
return Adaptation(adaptation_validation_id_,
|
|
Adaptation::Status::kAwaitingPreviousAdaptation);
|
|
}
|
|
|
|
// Maybe propose targets based on degradation preference.
|
|
switch (degradation_preference_) {
|
|
case DegradationPreference::BALANCED: {
|
|
// Try scale down framerate, if lower.
|
|
int target_fps =
|
|
balanced_settings_.MinFps(input_state_.video_codec_type(),
|
|
input_state_.frame_size_pixels().value());
|
|
if (source_restrictor_->CanDecreaseFrameRateTo(target_fps)) {
|
|
return Adaptation(
|
|
adaptation_validation_id_,
|
|
Adaptation::Step(Adaptation::StepType::kDecreaseFrameRate,
|
|
target_fps));
|
|
}
|
|
// Scale down resolution.
|
|
ABSL_FALLTHROUGH_INTENDED;
|
|
}
|
|
case DegradationPreference::MAINTAIN_FRAMERATE: {
|
|
// Scale down resolution.
|
|
int target_pixels =
|
|
GetLowerResolutionThan(input_state_.frame_size_pixels().value());
|
|
bool min_pixel_limit_reached =
|
|
target_pixels < source_restrictor_->min_pixels_per_frame();
|
|
if (!source_restrictor_->CanDecreaseResolutionTo(target_pixels)) {
|
|
return Adaptation(adaptation_validation_id_,
|
|
Adaptation::Status::kLimitReached,
|
|
min_pixel_limit_reached);
|
|
}
|
|
return Adaptation(
|
|
adaptation_validation_id_,
|
|
Adaptation::Step(Adaptation::StepType::kDecreaseResolution,
|
|
target_pixels),
|
|
min_pixel_limit_reached);
|
|
}
|
|
case DegradationPreference::MAINTAIN_RESOLUTION: {
|
|
int target_fps = GetLowerFrameRateThan(input_state_.frames_per_second());
|
|
if (!source_restrictor_->CanDecreaseFrameRateTo(target_fps)) {
|
|
return Adaptation(adaptation_validation_id_,
|
|
Adaptation::Status::kLimitReached);
|
|
}
|
|
return Adaptation(
|
|
adaptation_validation_id_,
|
|
Adaptation::Step(Adaptation::StepType::kDecreaseFrameRate,
|
|
target_fps));
|
|
}
|
|
case DegradationPreference::DISABLED:
|
|
RTC_NOTREACHED();
|
|
return Adaptation(adaptation_validation_id_,
|
|
Adaptation::Status::kLimitReached);
|
|
}
|
|
}
|
|
|
|
VideoStreamAdapter::RestrictionsWithCounters
|
|
VideoStreamAdapter::PeekNextRestrictions(const Adaptation& adaptation) const {
|
|
RTC_DCHECK_EQ(adaptation.validation_id_, adaptation_validation_id_);
|
|
RTC_LOG(LS_INFO) << "PeekNextRestrictions called";
|
|
if (adaptation.status() != Adaptation::Status::kValid)
|
|
return {source_restrictor_->source_restrictions(),
|
|
source_restrictor_->adaptation_counters()};
|
|
VideoSourceRestrictor restrictor_copy = *source_restrictor_;
|
|
restrictor_copy.ApplyAdaptationStep(adaptation.step(),
|
|
degradation_preference_);
|
|
return {restrictor_copy.source_restrictions(),
|
|
restrictor_copy.adaptation_counters()};
|
|
}
|
|
|
|
void VideoStreamAdapter::ApplyAdaptation(const Adaptation& adaptation) {
|
|
RTC_DCHECK_EQ(adaptation.validation_id_, adaptation_validation_id_);
|
|
RTC_LOG(LS_INFO) << "ApplyAdaptation called";
|
|
if (adaptation.status() != Adaptation::Status::kValid)
|
|
return;
|
|
// Remember the input pixels and fps of this adaptation. Used to avoid
|
|
// adapting again before this adaptation has had an effect.
|
|
last_adaptation_request_.emplace(AdaptationRequest{
|
|
input_state_.frame_size_pixels().value(),
|
|
input_state_.frames_per_second(), adaptation.step().type});
|
|
// Adapt!
|
|
source_restrictor_->ApplyAdaptationStep(adaptation.step(),
|
|
degradation_preference_);
|
|
}
|
|
|
|
Adaptation VideoStreamAdapter::GetAdaptationTo(
|
|
const VideoAdaptationCounters& counters,
|
|
const VideoSourceRestrictions& restrictions) const {
|
|
// Adapts up/down from the current levels so counters are equal.
|
|
return Adaptation(adaptation_validation_id_,
|
|
Adaptation::Step(restrictions, counters));
|
|
}
|
|
|
|
} // namespace webrtc
|