Implement kBalanced degradation preference.
A balance of framerate reduction and resolution down-scaling is used on degrades. BUG=webrtc:7607 Review-Url: https://codereview.webrtc.org/2887303003 Cr-Commit-Position: refs/heads/master@{#18583}
This commit is contained in:
parent
b749e5e1f5
commit
f7e294d568
@ -73,6 +73,29 @@ uint32_t MaximumFrameSizeForBitrate(uint32_t kbps) {
|
||||
return std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
// Initial limits for kBalanced degradation preference.
|
||||
int MinFps(int pixels) {
|
||||
if (pixels <= 320 * 240) {
|
||||
return 7;
|
||||
} else if (pixels <= 480 * 270) {
|
||||
return 10;
|
||||
} else if (pixels <= 640 * 480) {
|
||||
return 15;
|
||||
} else {
|
||||
return std::numeric_limits<int>::max();
|
||||
}
|
||||
}
|
||||
|
||||
int MaxFps(int pixels) {
|
||||
if (pixels <= 320 * 240) {
|
||||
return 10;
|
||||
} else if (pixels <= 480 * 270) {
|
||||
return 15;
|
||||
} else {
|
||||
return std::numeric_limits<int>::max();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsResolutionScalingEnabled(
|
||||
VideoSendStream::DegradationPreference degradation_preference) {
|
||||
return degradation_preference ==
|
||||
@ -211,7 +234,7 @@ class ViEEncoder::VideoSourceProxy {
|
||||
// the used degradation_preference.
|
||||
switch (degradation_preference_) {
|
||||
case VideoSendStream::DegradationPreference::kBalanced:
|
||||
FALLTHROUGH();
|
||||
break;
|
||||
case VideoSendStream::DegradationPreference::kMaintainFramerate:
|
||||
wants.max_framerate_fps = std::numeric_limits<int>::max();
|
||||
break;
|
||||
@ -227,6 +250,15 @@ class ViEEncoder::VideoSourceProxy {
|
||||
return wants;
|
||||
}
|
||||
|
||||
void ResetPixelFpsCount() {
|
||||
rtc::CritScope lock(&crit_);
|
||||
sink_wants_.max_pixel_count = std::numeric_limits<int>::max();
|
||||
sink_wants_.target_pixel_count.reset();
|
||||
sink_wants_.max_framerate_fps = std::numeric_limits<int>::max();
|
||||
if (source_)
|
||||
source_->AddOrUpdateSink(vie_encoder_, sink_wants_);
|
||||
}
|
||||
|
||||
bool RequestResolutionLowerThan(int pixel_count) {
|
||||
// Called on the encoder task queue.
|
||||
rtc::CritScope lock(&crit_);
|
||||
@ -447,6 +479,15 @@ void ViEEncoder::SetSource(
|
||||
// Reset adaptation state, so that we're not tricked into thinking there's
|
||||
// an already pending request of the same type.
|
||||
last_adaptation_request_.reset();
|
||||
if (degradation_preference ==
|
||||
VideoSendStream::DegradationPreference::kBalanced ||
|
||||
degradation_preference_ ==
|
||||
VideoSendStream::DegradationPreference::kBalanced) {
|
||||
// TODO(asapersson): Consider removing |adapt_counters_| map and use one
|
||||
// AdaptCounter for all modes.
|
||||
source_proxy_->ResetPixelFpsCount();
|
||||
adapt_counters_.clear();
|
||||
}
|
||||
}
|
||||
degradation_preference_ = degradation_preference;
|
||||
bool allow_scaling = IsResolutionScalingEnabled(degradation_preference_);
|
||||
@ -803,12 +844,10 @@ void ViEEncoder::AdaptDown(AdaptReason reason) {
|
||||
last_adaptation_request_ &&
|
||||
last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptDown;
|
||||
|
||||
int max_downgrades = 0;
|
||||
switch (degradation_preference_) {
|
||||
case VideoSendStream::DegradationPreference::kBalanced:
|
||||
FALLTHROUGH();
|
||||
break;
|
||||
case VideoSendStream::DegradationPreference::kMaintainFramerate:
|
||||
max_downgrades = kMaxCpuResolutionDowngrades;
|
||||
if (downgrade_requested &&
|
||||
adaptation_request.input_pixel_count_ >=
|
||||
last_adaptation_request_->input_pixel_count_) {
|
||||
@ -818,7 +857,6 @@ void ViEEncoder::AdaptDown(AdaptReason reason) {
|
||||
}
|
||||
break;
|
||||
case VideoSendStream::DegradationPreference::kMaintainResolution:
|
||||
max_downgrades = kMaxCpuFramerateDowngrades;
|
||||
if (adaptation_request.framerate_fps_ <= 0 ||
|
||||
(downgrade_requested &&
|
||||
adaptation_request.framerate_fps_ < kMinFramerateFps)) {
|
||||
@ -836,20 +874,32 @@ void ViEEncoder::AdaptDown(AdaptReason reason) {
|
||||
}
|
||||
|
||||
if (reason == kCpu) {
|
||||
if (GetConstAdaptCounter().TotalCount(kCpu) >= max_downgrades)
|
||||
if (GetConstAdaptCounter().ResolutionCount(kCpu) >=
|
||||
kMaxCpuResolutionDowngrades ||
|
||||
GetConstAdaptCounter().FramerateCount(kCpu) >=
|
||||
kMaxCpuFramerateDowngrades) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (degradation_preference_) {
|
||||
case VideoSendStream::DegradationPreference::kBalanced:
|
||||
case VideoSendStream::DegradationPreference::kBalanced: {
|
||||
// Try scale down framerate, if lower.
|
||||
int fps = MinFps(last_frame_info_->pixel_count());
|
||||
if (source_proxy_->RestrictFramerate(fps)) {
|
||||
GetAdaptCounter().IncrementFramerate(reason);
|
||||
break;
|
||||
}
|
||||
// Scale down resolution.
|
||||
FALLTHROUGH();
|
||||
}
|
||||
case VideoSendStream::DegradationPreference::kMaintainFramerate:
|
||||
// Scale down resolution.
|
||||
if (!source_proxy_->RequestResolutionLowerThan(
|
||||
adaptation_request.input_pixel_count_)) {
|
||||
return;
|
||||
}
|
||||
GetAdaptCounter().IncrementResolution(reason, 1);
|
||||
GetAdaptCounter().IncrementResolution(reason);
|
||||
break;
|
||||
case VideoSendStream::DegradationPreference::kMaintainResolution:
|
||||
// Scale down framerate.
|
||||
@ -857,7 +907,7 @@ void ViEEncoder::AdaptDown(AdaptReason reason) {
|
||||
adaptation_request.framerate_fps_)) {
|
||||
return;
|
||||
}
|
||||
GetAdaptCounter().IncrementFramerate(reason, 1);
|
||||
GetAdaptCounter().IncrementFramerate(reason);
|
||||
break;
|
||||
case VideoSendStream::DegradationPreference::kDegradationDisabled:
|
||||
RTC_NOTREACHED();
|
||||
@ -888,29 +938,34 @@ void ViEEncoder::AdaptUp(AdaptReason reason) {
|
||||
last_adaptation_request_ &&
|
||||
last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptUp;
|
||||
|
||||
switch (degradation_preference_) {
|
||||
case VideoSendStream::DegradationPreference::kBalanced:
|
||||
FALLTHROUGH();
|
||||
case VideoSendStream::DegradationPreference::kMaintainFramerate:
|
||||
if (adapt_up_requested &&
|
||||
adaptation_request.input_pixel_count_ <=
|
||||
last_adaptation_request_->input_pixel_count_) {
|
||||
// Don't request higher resolution if the current resolution is not
|
||||
// higher than the last time we asked for the resolution to be higher.
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case VideoSendStream::DegradationPreference::kMaintainResolution:
|
||||
// TODO(sprang): Don't request higher framerate if we are already at
|
||||
// max requested fps?
|
||||
break;
|
||||
case VideoSendStream::DegradationPreference::kDegradationDisabled:
|
||||
if (degradation_preference_ ==
|
||||
VideoSendStream::DegradationPreference::kMaintainFramerate) {
|
||||
if (adapt_up_requested &&
|
||||
adaptation_request.input_pixel_count_ <=
|
||||
last_adaptation_request_->input_pixel_count_) {
|
||||
// Don't request higher resolution if the current resolution is not
|
||||
// higher than the last time we asked for the resolution to be higher.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (degradation_preference_) {
|
||||
case VideoSendStream::DegradationPreference::kBalanced:
|
||||
case VideoSendStream::DegradationPreference::kBalanced: {
|
||||
// Try scale up framerate, if higher.
|
||||
int fps = MaxFps(last_frame_info_->pixel_count());
|
||||
if (source_proxy_->IncreaseFramerate(fps)) {
|
||||
GetAdaptCounter().DecrementFramerate(reason, fps);
|
||||
// Reset framerate in case of fewer fps steps down than up.
|
||||
if (adapt_counter.FramerateCount() == 0 &&
|
||||
fps != std::numeric_limits<int>::max()) {
|
||||
LOG(LS_INFO) << "Removing framerate down-scaling setting.";
|
||||
source_proxy_->IncreaseFramerate(std::numeric_limits<int>::max());
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Scale up resolution.
|
||||
FALLTHROUGH();
|
||||
}
|
||||
case VideoSendStream::DegradationPreference::kMaintainFramerate: {
|
||||
// Scale up resolution.
|
||||
int pixel_count = adaptation_request.input_pixel_count_;
|
||||
@ -920,7 +975,7 @@ void ViEEncoder::AdaptUp(AdaptReason reason) {
|
||||
}
|
||||
if (!source_proxy_->RequestHigherResolutionThan(pixel_count))
|
||||
return;
|
||||
GetAdaptCounter().IncrementResolution(reason, -1);
|
||||
GetAdaptCounter().DecrementResolution(reason);
|
||||
break;
|
||||
}
|
||||
case VideoSendStream::DegradationPreference::kMaintainResolution: {
|
||||
@ -932,11 +987,11 @@ void ViEEncoder::AdaptUp(AdaptReason reason) {
|
||||
}
|
||||
if (!source_proxy_->RequestHigherFramerateThan(fps))
|
||||
return;
|
||||
GetAdaptCounter().IncrementFramerate(reason, -1);
|
||||
GetAdaptCounter().DecrementFramerate(reason);
|
||||
break;
|
||||
}
|
||||
case VideoSendStream::DegradationPreference::kDegradationDisabled:
|
||||
RTC_NOTREACHED();
|
||||
return;
|
||||
}
|
||||
|
||||
last_adaptation_request_.emplace(adaptation_request);
|
||||
@ -994,6 +1049,7 @@ const ViEEncoder::AdaptCounter& ViEEncoder::GetConstAdaptCounter() {
|
||||
ViEEncoder::AdaptCounter::AdaptCounter() {
|
||||
fps_counters_.resize(kScaleReasonSize);
|
||||
resolution_counters_.resize(kScaleReasonSize);
|
||||
static_assert(kScaleReasonSize == 2, "Update MoveCount.");
|
||||
}
|
||||
|
||||
ViEEncoder::AdaptCounter::~AdaptCounter() {}
|
||||
@ -1012,12 +1068,48 @@ ViEEncoder::AdaptCounts ViEEncoder::AdaptCounter::Counts(int reason) const {
|
||||
return counts;
|
||||
}
|
||||
|
||||
void ViEEncoder::AdaptCounter::IncrementFramerate(int reason, int delta) {
|
||||
fps_counters_[reason] += delta;
|
||||
void ViEEncoder::AdaptCounter::IncrementFramerate(int reason) {
|
||||
++(fps_counters_[reason]);
|
||||
}
|
||||
|
||||
void ViEEncoder::AdaptCounter::IncrementResolution(int reason, int delta) {
|
||||
resolution_counters_[reason] += delta;
|
||||
void ViEEncoder::AdaptCounter::IncrementResolution(int reason) {
|
||||
++(resolution_counters_[reason]);
|
||||
}
|
||||
|
||||
void ViEEncoder::AdaptCounter::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) % kScaleReasonSize);
|
||||
}
|
||||
--(fps_counters_[reason]);
|
||||
RTC_DCHECK_GE(fps_counters_[reason], 0);
|
||||
}
|
||||
|
||||
void ViEEncoder::AdaptCounter::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) % kScaleReasonSize);
|
||||
}
|
||||
--(resolution_counters_[reason]);
|
||||
RTC_DCHECK_GE(resolution_counters_[reason], 0);
|
||||
}
|
||||
|
||||
void ViEEncoder::AdaptCounter::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())
|
||||
std::fill(fps_counters_.begin(), fps_counters_.end(), 0);
|
||||
}
|
||||
|
||||
int ViEEncoder::AdaptCounter::FramerateCount() const {
|
||||
@ -1028,10 +1120,6 @@ int ViEEncoder::AdaptCounter::ResolutionCount() const {
|
||||
return Count(resolution_counters_);
|
||||
}
|
||||
|
||||
int ViEEncoder::AdaptCounter::TotalCount() const {
|
||||
return FramerateCount() + ResolutionCount();
|
||||
}
|
||||
|
||||
int ViEEncoder::AdaptCounter::FramerateCount(int reason) const {
|
||||
return fps_counters_[reason];
|
||||
}
|
||||
@ -1048,6 +1136,13 @@ int ViEEncoder::AdaptCounter::Count(const std::vector<int>& counters) const {
|
||||
return std::accumulate(counters.begin(), counters.end(), 0);
|
||||
}
|
||||
|
||||
void ViEEncoder::AdaptCounter::MoveCount(std::vector<int>* counters,
|
||||
int from_reason) {
|
||||
int to_reason = (from_reason + 1) % kScaleReasonSize;
|
||||
++((*counters)[to_reason]);
|
||||
--((*counters)[from_reason]);
|
||||
}
|
||||
|
||||
std::string ViEEncoder::AdaptCounter::ToString(
|
||||
const std::vector<int>& counters) const {
|
||||
std::stringstream ss;
|
||||
|
||||
@ -189,13 +189,15 @@ class ViEEncoder : public rtc::VideoSinkInterface<VideoFrame>,
|
||||
|
||||
std::string ToString() const;
|
||||
|
||||
void IncrementFramerate(int reason, int delta);
|
||||
void IncrementResolution(int reason, int delta);
|
||||
void IncrementFramerate(int reason);
|
||||
void IncrementResolution(int reason);
|
||||
void DecrementFramerate(int reason);
|
||||
void DecrementResolution(int reason);
|
||||
void DecrementFramerate(int reason, int cur_fps);
|
||||
|
||||
// Gets the total number of downgrades (for all adapt reasons).
|
||||
int FramerateCount() const;
|
||||
int ResolutionCount() const;
|
||||
int TotalCount() const;
|
||||
|
||||
// Gets the total number of downgrades for |reason|.
|
||||
int FramerateCount(int reason) const;
|
||||
@ -205,6 +207,7 @@ class ViEEncoder : public rtc::VideoSinkInterface<VideoFrame>,
|
||||
private:
|
||||
std::string ToString(const std::vector<int>& counters) const;
|
||||
int Count(const std::vector<int>& counters) const;
|
||||
void MoveCount(std::vector<int>* counters, int from_reason);
|
||||
|
||||
// Degradation counters holding number of framerate/resolution reductions
|
||||
// per adapt reason.
|
||||
|
||||
@ -311,6 +311,37 @@ class ViEEncoderTest : public ::testing::Test {
|
||||
EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
|
||||
}
|
||||
|
||||
void VerifyFpsMaxResolutionEq(const rtc::VideoSinkWants& wants1,
|
||||
const rtc::VideoSinkWants& wants2) {
|
||||
EXPECT_EQ(std::numeric_limits<int>::max(), wants1.max_framerate_fps);
|
||||
EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
|
||||
}
|
||||
|
||||
void VerifyFpsLtResolutionEq(const rtc::VideoSinkWants& wants1,
|
||||
const rtc::VideoSinkWants& wants2) {
|
||||
EXPECT_LT(wants1.max_framerate_fps, wants2.max_framerate_fps);
|
||||
EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
|
||||
}
|
||||
|
||||
void VerifyFpsGtResolutionEq(const rtc::VideoSinkWants& wants1,
|
||||
const rtc::VideoSinkWants& wants2) {
|
||||
EXPECT_GT(wants1.max_framerate_fps, wants2.max_framerate_fps);
|
||||
EXPECT_EQ(wants1.max_pixel_count, wants2.max_pixel_count);
|
||||
}
|
||||
|
||||
void VerifyFpsEqResolutionLt(const rtc::VideoSinkWants& wants1,
|
||||
const rtc::VideoSinkWants& wants2) {
|
||||
EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
|
||||
EXPECT_LT(wants1.max_pixel_count, wants2.max_pixel_count);
|
||||
EXPECT_GT(wants1.max_pixel_count, 0);
|
||||
}
|
||||
|
||||
void VerifyFpsEqResolutionGt(const rtc::VideoSinkWants& wants1,
|
||||
const rtc::VideoSinkWants& wants2) {
|
||||
EXPECT_EQ(wants1.max_framerate_fps, wants2.max_framerate_fps);
|
||||
EXPECT_GT(wants1.max_pixel_count, wants2.max_pixel_count);
|
||||
}
|
||||
|
||||
void VerifyFpsMaxResolutionLt(const rtc::VideoSinkWants& wants,
|
||||
int pixel_count) {
|
||||
EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_framerate_fps);
|
||||
@ -324,6 +355,13 @@ class ViEEncoderTest : public ::testing::Test {
|
||||
EXPECT_FALSE(wants.target_pixel_count);
|
||||
}
|
||||
|
||||
void VerifyFpsEqResolutionMax(const rtc::VideoSinkWants& wants,
|
||||
int expected_fps) {
|
||||
EXPECT_EQ(expected_fps, wants.max_framerate_fps);
|
||||
EXPECT_EQ(std::numeric_limits<int>::max(), wants.max_pixel_count);
|
||||
EXPECT_FALSE(wants.target_pixel_count);
|
||||
}
|
||||
|
||||
class TestEncoder : public test::FakeEncoder {
|
||||
public:
|
||||
TestEncoder()
|
||||
@ -808,6 +846,59 @@ TEST_F(ViEEncoderTest, SinkWantsFromOveruseDetector) {
|
||||
vie_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(ViEEncoderTest, TestMaxCpuResolutionDowngrades_BalancedMode_NoFpsLimit) {
|
||||
const int kMaxDowngrades = ViEEncoder::kMaxCpuResolutionDowngrades;
|
||||
const int kWidth = 1280;
|
||||
const int kHeight = 720;
|
||||
vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
||||
|
||||
// Enable kBalanced preference, no initial limitation.
|
||||
AdaptingFrameForwarder source;
|
||||
source.set_adaptation_enabled(true);
|
||||
vie_encoder_->SetSource(&source,
|
||||
VideoSendStream::DegradationPreference::kBalanced);
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
|
||||
// Trigger adapt down kMaxCpuDowngrades times.
|
||||
int t = 1;
|
||||
for (int i = 1; i <= kMaxDowngrades; ++i) {
|
||||
source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(t++);
|
||||
vie_encoder_->TriggerCpuOveruse();
|
||||
VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_EQ(i, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
}
|
||||
|
||||
// Trigger adapt down, max cpu downgrades reach, expect no change.
|
||||
rtc::VideoSinkWants last_wants = source.sink_wants();
|
||||
source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(t++);
|
||||
vie_encoder_->TriggerCpuOveruse();
|
||||
VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
|
||||
EXPECT_EQ(last_wants.max_pixel_count, source.sink_wants().max_pixel_count);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_EQ(kMaxDowngrades,
|
||||
stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
|
||||
// Trigger adapt up kMaxCpuDowngrades times.
|
||||
for (int i = 1; i <= kMaxDowngrades; ++i) {
|
||||
source.IncomingCapturedFrame(CreateFrame(t, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(t++);
|
||||
vie_encoder_->TriggerCpuNormalUsage();
|
||||
VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_GT(source.sink_wants().max_pixel_count, last_wants.max_pixel_count);
|
||||
EXPECT_EQ(kMaxDowngrades + i,
|
||||
stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
}
|
||||
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
|
||||
vie_encoder_->Stop();
|
||||
}
|
||||
TEST_F(ViEEncoderTest, SinkWantsStoredByDegradationPreference) {
|
||||
vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
||||
VerifyNoLimitation(video_source_.sink_wants());
|
||||
@ -1376,6 +1467,45 @@ TEST_F(ViEEncoderTest, SkipsSameAdaptDownRequest_MaintainFramerateMode) {
|
||||
vie_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(ViEEncoderTest, SkipsSameOrLargerAdaptDownRequest_BalancedMode) {
|
||||
const int kWidth = 1280;
|
||||
const int kHeight = 720;
|
||||
vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
||||
|
||||
// Enable kBalanced preference, no initial limitation.
|
||||
test::FrameForwarder source;
|
||||
vie_encoder_->SetSource(&source,
|
||||
VideoSendStream::DegradationPreference::kBalanced);
|
||||
source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(1);
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
|
||||
// Trigger adapt down, expect scaled down resolution.
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
const int kLastMaxPixelCount = source.sink_wants().max_pixel_count;
|
||||
|
||||
// Trigger adapt down for same input resolution, expect no change.
|
||||
source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(2);
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down for larger input resolution, expect no change.
|
||||
source.IncomingCapturedFrame(CreateFrame(3, kWidth + 1, kHeight + 1));
|
||||
sink_.WaitForEncodedFrame(3);
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
EXPECT_EQ(kLastMaxPixelCount, source.sink_wants().max_pixel_count);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
vie_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainFramerateMode) {
|
||||
const int kWidth = 1280;
|
||||
const int kHeight = 720;
|
||||
@ -1426,6 +1556,33 @@ TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_MaintainResolutionMode) {
|
||||
vie_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_BalancedMode) {
|
||||
const int kWidth = 1280;
|
||||
const int kHeight = 720;
|
||||
vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
||||
|
||||
// Enable kBalanced preference, no initial limitation.
|
||||
test::FrameForwarder source;
|
||||
vie_encoder_->SetSource(&source,
|
||||
VideoSendStream::DegradationPreference::kBalanced);
|
||||
|
||||
source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(kWidth, kHeight);
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect no change.
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
vie_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(ViEEncoderTest, NoChangeForInitialNormalUsage_DisabledMode) {
|
||||
const int kWidth = 1280;
|
||||
const int kHeight = 720;
|
||||
@ -1617,6 +1774,59 @@ TEST_F(ViEEncoderTest,
|
||||
vie_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(ViEEncoderTest,
|
||||
AdaptsResolutionUpAndDownTwiceForLowQuality_BalancedMode_NoFpsLimit) {
|
||||
const int kWidth = 1280;
|
||||
const int kHeight = 720;
|
||||
vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
||||
|
||||
// Enable kBalanced preference, no initial limitation.
|
||||
AdaptingFrameForwarder source;
|
||||
source.set_adaptation_enabled(true);
|
||||
vie_encoder_->SetSource(&source,
|
||||
VideoSendStream::DegradationPreference::kBalanced);
|
||||
|
||||
source.IncomingCapturedFrame(CreateFrame(1, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(kWidth, kHeight);
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect scaled down resolution.
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
source.IncomingCapturedFrame(CreateFrame(2, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(2);
|
||||
VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect no restriction.
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
source.IncomingCapturedFrame(CreateFrame(3, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(kWidth, kHeight);
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect scaled down resolution.
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
source.IncomingCapturedFrame(CreateFrame(4, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(4);
|
||||
VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect no restriction.
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
source.IncomingCapturedFrame(CreateFrame(5, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(kWidth, kHeight);
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
vie_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(ViEEncoderTest,
|
||||
AdaptsResolutionOnOveruseAndLowQuality_MaintainFramerateMode) {
|
||||
const int kWidth = 1280;
|
||||
@ -1926,6 +2136,41 @@ TEST_F(ViEEncoderTest,
|
||||
vie_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(ViEEncoderTest, ResolutionNotAdaptedForTooSmallFrame_BalancedMode) {
|
||||
const int kTooSmallWidth = 10;
|
||||
const int kTooSmallHeight = 10;
|
||||
const int kFpsLimit = 7;
|
||||
vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
||||
|
||||
// Enable kBalanced preference, no initial limitation.
|
||||
test::FrameForwarder source;
|
||||
vie_encoder_->SetSource(&source,
|
||||
VideoSendStream::DegradationPreference::kBalanced);
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
|
||||
// Trigger adapt down, expect limited framerate.
|
||||
source.IncomingCapturedFrame(CreateFrame(1, kTooSmallWidth, kTooSmallHeight));
|
||||
sink_.WaitForEncodedFrame(1);
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, too small frame, expect no change.
|
||||
source.IncomingCapturedFrame(CreateFrame(2, kTooSmallWidth, kTooSmallHeight));
|
||||
sink_.WaitForEncodedFrame(2);
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
vie_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(ViEEncoderTest, FailingInitEncodeDoesntCauseCrash) {
|
||||
fake_encoder_.ForceInitEncodeFailure(true);
|
||||
vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
||||
@ -2118,6 +2363,384 @@ TEST_F(ViEEncoderTest, DoesntAdaptDownPastMinFramerate) {
|
||||
CreateFrame(timestamp_ms, kFrameWidth, kFrameHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
}
|
||||
|
||||
vie_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(ViEEncoderTest, AdaptsResolutionAndFramerateForLowQuality_BalancedMode) {
|
||||
const int kWidth = 1280;
|
||||
const int kHeight = 720;
|
||||
const int64_t kFrameIntervalMs = 150;
|
||||
int64_t timestamp_ms = kFrameIntervalMs;
|
||||
vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
||||
|
||||
// Enable kBalanced preference, no initial limitation.
|
||||
AdaptingFrameForwarder source;
|
||||
source.set_adaptation_enabled(true);
|
||||
vie_encoder_->SetSource(&source,
|
||||
VideoSendStream::DegradationPreference::kBalanced);
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(kWidth, kHeight);
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect scaled down resolution (960x540@30fps).
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect scaled down resolution (640x360@30fps).
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect reduced fps (640x360@15fps).
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect scaled down resolution (480x270@15fps).
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(4, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Restrict bitrate, trigger adapt down, expect reduced fps (480x270@10fps).
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(5, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect scaled down resolution (320x180@10fps).
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(6, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect reduced fps (320x180@7fps).
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
|
||||
rtc::VideoSinkWants last_wants = source.sink_wants();
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, min resolution reached, expect no change.
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionEq(source.sink_wants(), last_wants);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(7, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt down, expect expect increased fps (320x180@10fps).
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(8, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect upscaled resolution (480x270@10fps).
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(9, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Increase bitrate, trigger adapt up, expect increased fps (480x270@15fps).
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsGtResolutionEq(source.sink_wants(), source.last_wants());
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(10, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect upscaled resolution (640x360@15fps).
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(11, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect increased fps (640x360@30fps).
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(12, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect upscaled resolution (960x540@30fps).
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(13, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect no restriction (1280x720fps@30fps).
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(kWidth, kHeight);
|
||||
VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect no change.
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_EQ(14, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
vie_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(ViEEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Framerate) {
|
||||
const int kWidth = 1280;
|
||||
const int kHeight = 720;
|
||||
const int64_t kFrameIntervalMs = 150;
|
||||
int64_t timestamp_ms = kFrameIntervalMs;
|
||||
vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
||||
|
||||
// Enable kBalanced preference, no initial limitation.
|
||||
AdaptingFrameForwarder source;
|
||||
source.set_adaptation_enabled(true);
|
||||
vie_encoder_->SetSource(&source,
|
||||
VideoSendStream::DegradationPreference::kBalanced);
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(kWidth, kHeight);
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger cpu adapt down, expect scaled down resolution (960x540@30fps).
|
||||
vie_encoder_->TriggerCpuOveruse();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsMaxResolutionLt(source.sink_wants(), kWidth * kHeight);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger cpu adapt down, expect scaled down resolution (640x360@30fps).
|
||||
vie_encoder_->TriggerCpuOveruse();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsMaxResolutionLt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger quality adapt down, expect reduced fps (640x360@15fps).
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsLtResolutionEq(source.sink_wants(), source.last_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger cpu adapt up, expect increased fps (640x360@30fps).
|
||||
vie_encoder_->TriggerCpuNormalUsage();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsMaxResolutionEq(source.sink_wants(), source.last_wants());
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger quality adapt up, expect upscaled resolution (960x540@30fps).
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(3, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger cpu adapt up, expect no restriction (1280x720fps@30fps).
|
||||
vie_encoder_->TriggerCpuNormalUsage();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(kWidth, kHeight);
|
||||
VerifyFpsMaxResolutionGt(source.sink_wants(), source.last_wants());
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect no change.
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_EQ(4, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
vie_encoder_->Stop();
|
||||
}
|
||||
|
||||
TEST_F(ViEEncoderTest, AdaptWithTwoReasonsAndDifferentOrder_Resolution) {
|
||||
const int kWidth = 640;
|
||||
const int kHeight = 360;
|
||||
const int kFpsLimit = 15;
|
||||
const int64_t kFrameIntervalMs = 150;
|
||||
int64_t timestamp_ms = kFrameIntervalMs;
|
||||
vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0);
|
||||
|
||||
// Enable kBalanced preference, no initial limitation.
|
||||
AdaptingFrameForwarder source;
|
||||
source.set_adaptation_enabled(true);
|
||||
vie_encoder_->SetSource(&source,
|
||||
VideoSendStream::DegradationPreference::kBalanced);
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(kWidth, kHeight);
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger cpu adapt down, expect scaled down framerate (640x360@15fps).
|
||||
vie_encoder_->TriggerCpuOveruse();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionMax(source.sink_wants(), kFpsLimit);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
EXPECT_EQ(0, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger quality adapt down, expect scaled down resolution (480x270@15fps).
|
||||
vie_encoder_->TriggerQualityLow();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionLt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger cpu adapt up, expect upscaled resolution (640x360@15fps).
|
||||
vie_encoder_->TriggerCpuNormalUsage();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyFpsEqResolutionGt(source.sink_wants(), source.last_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_TRUE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
EXPECT_EQ(1, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger quality adapt up, expect increased fps (640x360@30fps).
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
timestamp_ms += kFrameIntervalMs;
|
||||
source.IncomingCapturedFrame(CreateFrame(timestamp_ms, kWidth, kHeight));
|
||||
sink_.WaitForEncodedFrame(timestamp_ms);
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().bw_limited_framerate);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_resolution);
|
||||
EXPECT_FALSE(stats_proxy_->GetStats().cpu_limited_framerate);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
// Trigger adapt up, expect no change.
|
||||
vie_encoder_->TriggerQualityHigh();
|
||||
VerifyNoLimitation(source.sink_wants());
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_cpu_adapt_changes);
|
||||
EXPECT_EQ(2, stats_proxy_->GetStats().number_of_quality_adapt_changes);
|
||||
|
||||
vie_encoder_->Stop();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user