blob: ea8145dd90f16d1476662b0eee58b4ea747a511e [file] [log] [blame]
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +00001/*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
kwiberg27f982b2016-03-01 11:52:33 -080011#include <memory>
12
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "api/video/i420_buffer.h"
14#include "common_video/include/video_frame.h"
15#include "modules/video_coding/utility/quality_scaler.h"
16#include "rtc_base/event.h"
17#include "rtc_base/fakeclock.h"
Niels Möllere541be72017-12-13 13:03:10 +010018#include "rtc_base/random.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "test/gmock.h"
20#include "test/gtest.h"
21#include "video/overuse_frame_detector.h"
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000022
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000023namespace webrtc {
perkjd52063f2016-09-07 06:32:18 -070024
kthelgason876222f2016-11-29 01:44:11 -080025using ::testing::InvokeWithoutArgs;
Niels Möllere541be72017-12-13 13:03:10 +010026using ::testing::_;
perkjd52063f2016-09-07 06:32:18 -070027
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000028namespace {
29 const int kWidth = 640;
30 const int kHeight = 480;
nissee0e3bdf2017-01-18 02:16:20 -080031 const int kFrameIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
32 const int kProcessTimeUs = 5 * rtc::kNumMicrosecsPerMillisec;
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000033} // namespace
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000034
sprangb1ca0732017-02-01 08:38:12 -080035class MockCpuOveruseObserver : public AdaptationObserverInterface {
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000036 public:
mflodman@webrtc.org6879c8a2013-07-23 11:35:00 +000037 MockCpuOveruseObserver() {}
38 virtual ~MockCpuOveruseObserver() {}
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000039
sprangb1ca0732017-02-01 08:38:12 -080040 MOCK_METHOD1(AdaptUp, void(AdaptReason));
41 MOCK_METHOD1(AdaptDown, void(AdaptReason));
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000042};
43
sprangb1ca0732017-02-01 08:38:12 -080044class CpuOveruseObserverImpl : public AdaptationObserverInterface {
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000045 public:
46 CpuOveruseObserverImpl() :
47 overuse_(0),
48 normaluse_(0) {}
49 virtual ~CpuOveruseObserverImpl() {}
50
sprangb1ca0732017-02-01 08:38:12 -080051 void AdaptDown(AdaptReason) { ++overuse_; }
52 void AdaptUp(AdaptReason) { ++normaluse_; }
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000053
54 int overuse_;
55 int normaluse_;
56};
57
perkjd52063f2016-09-07 06:32:18 -070058class OveruseFrameDetectorUnderTest : public OveruseFrameDetector {
59 public:
nissee0e3bdf2017-01-18 02:16:20 -080060 OveruseFrameDetectorUnderTest(const CpuOveruseOptions& options,
sprangb1ca0732017-02-01 08:38:12 -080061 AdaptationObserverInterface* overuse_observer,
perkjd52063f2016-09-07 06:32:18 -070062 CpuOveruseMetricsObserver* metrics_observer)
nissee0e3bdf2017-01-18 02:16:20 -080063 : OveruseFrameDetector(options,
perkjd52063f2016-09-07 06:32:18 -070064 overuse_observer,
perkjd52063f2016-09-07 06:32:18 -070065 metrics_observer) {}
66 ~OveruseFrameDetectorUnderTest() {}
67
68 using OveruseFrameDetector::CheckForOveruse;
69};
70
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +000071class OveruseFrameDetectorTest : public ::testing::Test,
72 public CpuOveruseMetricsObserver {
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000073 protected:
nisseef8b61e2016-04-29 06:09:15 -070074 void SetUp() override {
mflodman@webrtc.org6879c8a2013-07-23 11:35:00 +000075 observer_.reset(new MockCpuOveruseObserver());
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000076 options_.min_process_count = 0;
Peter Boström4b91bd02015-06-26 06:58:16 +020077 ReinitializeOveruseDetector();
78 }
79
80 void ReinitializeOveruseDetector() {
perkjd52063f2016-09-07 06:32:18 -070081 overuse_detector_.reset(new OveruseFrameDetectorUnderTest(
Niels Möller6b642f72017-12-08 14:11:14 +010082 options_, observer_.get(), this));
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000083 }
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000084
Peter Boströme4499152016-02-05 11:13:28 +010085 void OnEncodedFrameTimeMeasured(int encode_time_ms,
86 const CpuOveruseMetrics& metrics) override {
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +000087 metrics_ = metrics;
88 }
89
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +000090 int InitialUsage() {
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +000091 return ((options_.low_encode_usage_threshold_percent +
92 options_.high_encode_usage_threshold_percent) / 2.0f) + 0.5;
93 }
94
Peter Boströme4499152016-02-05 11:13:28 +010095 void InsertAndSendFramesWithInterval(int num_frames,
nissee0e3bdf2017-01-18 02:16:20 -080096 int interval_us,
Peter Boströme4499152016-02-05 11:13:28 +010097 int width,
98 int height,
nissee0e3bdf2017-01-18 02:16:20 -080099 int delay_us) {
Niels Möller7dc26b72017-12-06 10:27:48 +0100100 VideoFrame frame(I420Buffer::Create(width, height),
101 webrtc::kVideoRotation_0, 0);
102 uint32_t timestamp = 0;
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000103 while (num_frames-- > 0) {
Niels Möller7dc26b72017-12-06 10:27:48 +0100104 frame.set_timestamp(timestamp);
105 overuse_detector_->FrameCaptured(frame, rtc::TimeMicros());
106 clock_.AdvanceTimeMicros(delay_us);
107 overuse_detector_->FrameSent(timestamp, rtc::TimeMicros());
108 clock_.AdvanceTimeMicros(interval_us - delay_us);
109 timestamp += interval_us * 90 / 1000;
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000110 }
111 }
112
Niels Möllere541be72017-12-13 13:03:10 +0100113 void InsertAndSendFramesWithRandomInterval(int num_frames,
114 int min_interval_us,
115 int max_interval_us,
116 int width,
117 int height,
118 int delay_us) {
119 webrtc::Random random(17);
120
121 VideoFrame frame(I420Buffer::Create(width, height),
122 webrtc::kVideoRotation_0, 0);
123 uint32_t timestamp = 0;
124 while (num_frames-- > 0) {
125 frame.set_timestamp(timestamp);
126 int interval_us = random.Rand(min_interval_us, max_interval_us);
127 overuse_detector_->FrameCaptured(frame, rtc::TimeMicros());
128 clock_.AdvanceTimeMicros(delay_us);
129 overuse_detector_->FrameSent(timestamp, rtc::TimeMicros());
130
131 overuse_detector_->CheckForOveruse();
132 // Avoid turning clock backwards.
133 if (interval_us > delay_us)
134 clock_.AdvanceTimeMicros(interval_us - delay_us);
135
136 timestamp += interval_us * 90 / 1000;
137 }
138 }
139
Peter Boströme4499152016-02-05 11:13:28 +0100140 void ForceUpdate(int width, int height) {
Niels Möller7dc26b72017-12-06 10:27:48 +0100141 // Insert one frame, wait a second and then put in another to force update
142 // the usage. From the tests where these are used, adding another sample
143 // doesn't affect the expected outcome (this is mainly to check initial
144 // values and whether the overuse detector has been reset or not).
145 InsertAndSendFramesWithInterval(2, rtc::kNumMicrosecsPerSec,
146 width, height, kFrameIntervalUs);
Peter Boströme4499152016-02-05 11:13:28 +0100147 }
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000148 void TriggerOveruse(int num_times) {
nissee0e3bdf2017-01-18 02:16:20 -0800149 const int kDelayUs = 32 * rtc::kNumMicrosecsPerMillisec;
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000150 for (int i = 0; i < num_times; ++i) {
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000151 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800152 1000, kFrameIntervalUs, kWidth, kHeight, kDelayUs);
perkjd52063f2016-09-07 06:32:18 -0700153 overuse_detector_->CheckForOveruse();
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000154 }
155 }
156
Åsa Persson746210f2015-09-08 10:52:42 +0200157 void TriggerUnderuse() {
nissee0e3bdf2017-01-18 02:16:20 -0800158 const int kDelayUs1 = 5000;
159 const int kDelayUs2 = 6000;
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000160 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800161 1300, kFrameIntervalUs, kWidth, kHeight, kDelayUs1);
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000162 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800163 1, kFrameIntervalUs, kWidth, kHeight, kDelayUs2);
perkjd52063f2016-09-07 06:32:18 -0700164 overuse_detector_->CheckForOveruse();
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000165 }
166
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000167 int UsagePercent() { return metrics_.encode_usage_percent; }
asapersson@webrtc.orgab6bf4f2014-05-27 07:43:15 +0000168
sprangfda496a2017-06-15 04:21:07 -0700169 int64_t OveruseProcessingTimeLimitForFramerate(int fps) const {
170 int64_t frame_interval = rtc::kNumMicrosecsPerSec / fps;
171 int64_t max_processing_time_us =
172 (frame_interval * options_.high_encode_usage_threshold_percent) / 100;
173 return max_processing_time_us;
174 }
175
176 int64_t UnderuseProcessingTimeLimitForFramerate(int fps) const {
177 int64_t frame_interval = rtc::kNumMicrosecsPerSec / fps;
178 int64_t max_processing_time_us =
179 (frame_interval * options_.low_encode_usage_threshold_percent) / 100;
180 return max_processing_time_us;
181 }
182
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000183 CpuOveruseOptions options_;
nissee0e3bdf2017-01-18 02:16:20 -0800184 rtc::ScopedFakeClock clock_;
kwiberg27f982b2016-03-01 11:52:33 -0800185 std::unique_ptr<MockCpuOveruseObserver> observer_;
perkjd52063f2016-09-07 06:32:18 -0700186 std::unique_ptr<OveruseFrameDetectorUnderTest> overuse_detector_;
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000187 CpuOveruseMetrics metrics_;
kthelgason876222f2016-11-29 01:44:11 -0800188
sprangb1ca0732017-02-01 08:38:12 -0800189 static const auto reason_ = AdaptationObserverInterface::AdaptReason::kCpu;
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000190};
191
Åsa Persson746210f2015-09-08 10:52:42 +0200192
Åsa Persson746210f2015-09-08 10:52:42 +0200193// UsagePercent() > high_encode_usage_threshold_percent => overuse.
194// UsagePercent() < low_encode_usage_threshold_percent => underuse.
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000195TEST_F(OveruseFrameDetectorTest, TriggerOveruse) {
Åsa Persson746210f2015-09-08 10:52:42 +0200196 // usage > high => overuse
sprangb1ca0732017-02-01 08:38:12 -0800197 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000198 TriggerOveruse(options_.high_threshold_consecutive_count);
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000199}
200
201TEST_F(OveruseFrameDetectorTest, OveruseAndRecover) {
Åsa Persson746210f2015-09-08 10:52:42 +0200202 // usage > high => overuse
sprangb1ca0732017-02-01 08:38:12 -0800203 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000204 TriggerOveruse(options_.high_threshold_consecutive_count);
Åsa Persson746210f2015-09-08 10:52:42 +0200205 // usage < low => underuse
sprangb1ca0732017-02-01 08:38:12 -0800206 EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(testing::AtLeast(1));
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000207 TriggerUnderuse();
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000208}
209
asapersson@webrtc.org2881ab12014-06-12 08:46:46 +0000210TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithNoObserver) {
perkjd52063f2016-09-07 06:32:18 -0700211 overuse_detector_.reset(new OveruseFrameDetectorUnderTest(
Niels Möller6b642f72017-12-08 14:11:14 +0100212 options_, nullptr, this));
sprangb1ca0732017-02-01 08:38:12 -0800213 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000214 TriggerOveruse(options_.high_threshold_consecutive_count);
sprangb1ca0732017-02-01 08:38:12 -0800215 EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(0);
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000216 TriggerUnderuse();
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000217}
218
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000219TEST_F(OveruseFrameDetectorTest, DoubleOveruseAndRecover) {
sprangb1ca0732017-02-01 08:38:12 -0800220 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(2);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000221 TriggerOveruse(options_.high_threshold_consecutive_count);
222 TriggerOveruse(options_.high_threshold_consecutive_count);
sprangb1ca0732017-02-01 08:38:12 -0800223 EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(testing::AtLeast(1));
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000224 TriggerUnderuse();
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000225}
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000226
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000227TEST_F(OveruseFrameDetectorTest, TriggerUnderuseWithMinProcessCount) {
nissee0e3bdf2017-01-18 02:16:20 -0800228 const int kProcessIntervalUs = 5 * rtc::kNumMicrosecsPerSec;
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000229 options_.min_process_count = 1;
Peter Boström4b91bd02015-06-26 06:58:16 +0200230 CpuOveruseObserverImpl overuse_observer;
perkjd52063f2016-09-07 06:32:18 -0700231 overuse_detector_.reset(new OveruseFrameDetectorUnderTest(
Niels Möller6b642f72017-12-08 14:11:14 +0100232 options_, &overuse_observer, this));
Åsa Persson746210f2015-09-08 10:52:42 +0200233 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800234 1200, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
perkjd52063f2016-09-07 06:32:18 -0700235 overuse_detector_->CheckForOveruse();
Peter Boström4b91bd02015-06-26 06:58:16 +0200236 EXPECT_EQ(0, overuse_observer.normaluse_);
nissee0e3bdf2017-01-18 02:16:20 -0800237 clock_.AdvanceTimeMicros(kProcessIntervalUs);
perkjd52063f2016-09-07 06:32:18 -0700238 overuse_detector_->CheckForOveruse();
Peter Boström4b91bd02015-06-26 06:58:16 +0200239 EXPECT_EQ(1, overuse_observer.normaluse_);
asapersson@webrtc.orgb60346e2014-02-17 19:02:15 +0000240}
241
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000242TEST_F(OveruseFrameDetectorTest, ConstantOveruseGivesNoNormalUsage) {
sprangb1ca0732017-02-01 08:38:12 -0800243 EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(0);
244 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(64);
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100245 for (size_t i = 0; i < 64; ++i) {
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000246 TriggerOveruse(options_.high_threshold_consecutive_count);
247 }
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000248}
249
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000250TEST_F(OveruseFrameDetectorTest, ConsecutiveCountTriggersOveruse) {
sprangb1ca0732017-02-01 08:38:12 -0800251 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000252 options_.high_threshold_consecutive_count = 2;
Peter Boström4b91bd02015-06-26 06:58:16 +0200253 ReinitializeOveruseDetector();
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000254 TriggerOveruse(2);
255}
256
257TEST_F(OveruseFrameDetectorTest, IncorrectConsecutiveCountTriggersNoOveruse) {
sprangb1ca0732017-02-01 08:38:12 -0800258 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000259 options_.high_threshold_consecutive_count = 2;
Peter Boström4b91bd02015-06-26 06:58:16 +0200260 ReinitializeOveruseDetector();
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000261 TriggerOveruse(1);
262}
263
Åsa Persson746210f2015-09-08 10:52:42 +0200264TEST_F(OveruseFrameDetectorTest, ProcessingUsage) {
265 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800266 1000, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
267 EXPECT_EQ(kProcessTimeUs * 100 / kFrameIntervalUs, UsagePercent());
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000268}
269
Åsa Persson746210f2015-09-08 10:52:42 +0200270TEST_F(OveruseFrameDetectorTest, ResetAfterResolutionChange) {
Peter Boströme4499152016-02-05 11:13:28 +0100271 ForceUpdate(kWidth, kHeight);
Åsa Persson746210f2015-09-08 10:52:42 +0200272 EXPECT_EQ(InitialUsage(), UsagePercent());
273 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800274 1000, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
Åsa Persson746210f2015-09-08 10:52:42 +0200275 EXPECT_NE(InitialUsage(), UsagePercent());
Peter Boströme4499152016-02-05 11:13:28 +0100276 // Verify reset (with new width/height).
277 ForceUpdate(kWidth, kHeight + 1);
Åsa Persson746210f2015-09-08 10:52:42 +0200278 EXPECT_EQ(InitialUsage(), UsagePercent());
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000279}
280
Åsa Persson746210f2015-09-08 10:52:42 +0200281TEST_F(OveruseFrameDetectorTest, ResetAfterFrameTimeout) {
Peter Boströme4499152016-02-05 11:13:28 +0100282 ForceUpdate(kWidth, kHeight);
Åsa Persson746210f2015-09-08 10:52:42 +0200283 EXPECT_EQ(InitialUsage(), UsagePercent());
284 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800285 1000, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
Åsa Persson746210f2015-09-08 10:52:42 +0200286 EXPECT_NE(InitialUsage(), UsagePercent());
287 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800288 2, options_.frame_timeout_interval_ms *
289 rtc::kNumMicrosecsPerMillisec, kWidth, kHeight, kProcessTimeUs);
Åsa Persson746210f2015-09-08 10:52:42 +0200290 EXPECT_NE(InitialUsage(), UsagePercent());
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000291 // Verify reset.
Åsa Persson746210f2015-09-08 10:52:42 +0200292 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800293 2, (options_.frame_timeout_interval_ms + 1) *
294 rtc::kNumMicrosecsPerMillisec, kWidth, kHeight, kProcessTimeUs);
Peter Boströme4499152016-02-05 11:13:28 +0100295 ForceUpdate(kWidth, kHeight);
Åsa Persson746210f2015-09-08 10:52:42 +0200296 EXPECT_EQ(InitialUsage(), UsagePercent());
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000297}
298
Niels Möller7dc26b72017-12-06 10:27:48 +0100299TEST_F(OveruseFrameDetectorTest, MinFrameSamplesBeforeUpdating) {
300 options_.min_frame_samples = 40;
301 ReinitializeOveruseDetector();
302 InsertAndSendFramesWithInterval(
303 40, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
304 EXPECT_EQ(InitialUsage(), UsagePercent());
305 // Pass time far enough to digest all previous samples.
306 clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec);
307 InsertAndSendFramesWithInterval(1, kFrameIntervalUs, kWidth, kHeight,
308 kProcessTimeUs);
309 // The last sample has not been processed here.
310 EXPECT_EQ(InitialUsage(), UsagePercent());
311
312 // Pass time far enough to digest all previous samples, 41 in total.
313 clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec);
314 InsertAndSendFramesWithInterval(
315 1, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
316 EXPECT_NE(InitialUsage(), UsagePercent());
317}
318
Åsa Persson746210f2015-09-08 10:52:42 +0200319TEST_F(OveruseFrameDetectorTest, InitialProcessingUsage) {
Peter Boströme4499152016-02-05 11:13:28 +0100320 ForceUpdate(kWidth, kHeight);
Åsa Persson746210f2015-09-08 10:52:42 +0200321 EXPECT_EQ(InitialUsage(), UsagePercent());
asapersson@webrtc.orgb24d3352013-11-20 13:51:40 +0000322}
323
Niels Möller7dc26b72017-12-06 10:27:48 +0100324TEST_F(OveruseFrameDetectorTest, MeasuresMultipleConcurrentSamples) {
325 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_))
326 .Times(testing::AtLeast(1));
327 static const int kIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
328 static const size_t kNumFramesEncodingDelay = 3;
329 VideoFrame frame(I420Buffer::Create(kWidth, kHeight),
330 webrtc::kVideoRotation_0, 0);
331 for (size_t i = 0; i < 1000; ++i) {
332 // Unique timestamps.
333 frame.set_timestamp(static_cast<uint32_t>(i));
334 overuse_detector_->FrameCaptured(frame, rtc::TimeMicros());
335 clock_.AdvanceTimeMicros(kIntervalUs);
336 if (i > kNumFramesEncodingDelay) {
337 overuse_detector_->FrameSent(
338 static_cast<uint32_t>(i - kNumFramesEncodingDelay),
339 rtc::TimeMicros());
340 }
341 overuse_detector_->CheckForOveruse();
342 }
343}
344
345TEST_F(OveruseFrameDetectorTest, UpdatesExistingSamples) {
346 // >85% encoding time should trigger overuse.
347 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_))
348 .Times(testing::AtLeast(1));
349 static const int kIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
350 static const int kDelayUs = 30 * rtc::kNumMicrosecsPerMillisec;
351 VideoFrame frame(I420Buffer::Create(kWidth, kHeight),
352 webrtc::kVideoRotation_0, 0);
353 uint32_t timestamp = 0;
354 for (size_t i = 0; i < 1000; ++i) {
355 frame.set_timestamp(timestamp);
356 overuse_detector_->FrameCaptured(frame, rtc::TimeMicros());
357 // Encode and send first parts almost instantly.
358 clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec);
359 overuse_detector_->FrameSent(timestamp, rtc::TimeMicros());
360 // Encode heavier part, resulting in >85% usage total.
361 clock_.AdvanceTimeMicros(kDelayUs - rtc::kNumMicrosecsPerMillisec);
362 overuse_detector_->FrameSent(timestamp, rtc::TimeMicros());
363 clock_.AdvanceTimeMicros(kIntervalUs - kDelayUs);
364 timestamp += kIntervalUs * 90 / 1000;
365 overuse_detector_->CheckForOveruse();
366 }
367}
368
perkjd52063f2016-09-07 06:32:18 -0700369TEST_F(OveruseFrameDetectorTest, RunOnTqNormalUsage) {
370 rtc::TaskQueue queue("OveruseFrameDetectorTestQueue");
371
372 rtc::Event event(false, false);
373 queue.PostTask([this, &event] {
374 overuse_detector_->StartCheckForOveruse();
375 event.Set();
376 });
377 event.Wait(rtc::Event::kForever);
378
379 // Expect NormalUsage(). When called, stop the |overuse_detector_| and then
380 // set |event| to end the test.
sprangb1ca0732017-02-01 08:38:12 -0800381 EXPECT_CALL(*(observer_.get()), AdaptUp(reason_))
kthelgason876222f2016-11-29 01:44:11 -0800382 .WillOnce(InvokeWithoutArgs([this, &event] {
perkjd52063f2016-09-07 06:32:18 -0700383 overuse_detector_->StopCheckForOveruse();
384 event.Set();
385 }));
386
eladalon1cc5fc32017-08-23 04:15:18 -0700387 queue.PostTask([this] {
nissee0e3bdf2017-01-18 02:16:20 -0800388 const int kDelayUs1 = 5 * rtc::kNumMicrosecsPerMillisec;
389 const int kDelayUs2 = 6 * rtc::kNumMicrosecsPerMillisec;
390 InsertAndSendFramesWithInterval(1300, kFrameIntervalUs, kWidth, kHeight,
391 kDelayUs1);
392 InsertAndSendFramesWithInterval(1, kFrameIntervalUs, kWidth, kHeight,
393 kDelayUs2);
perkjd52063f2016-09-07 06:32:18 -0700394 });
395
396 EXPECT_TRUE(event.Wait(10000));
397}
398
Niels Möller7dc26b72017-12-06 10:27:48 +0100399TEST_F(OveruseFrameDetectorTest, MaxIntervalScalesWithFramerate) {
400 const int kCapturerMaxFrameRate = 30;
401 const int kEncodeMaxFrameRate = 20; // Maximum fps the encoder can sustain.
sprangfda496a2017-06-15 04:21:07 -0700402
Niels Möller7dc26b72017-12-06 10:27:48 +0100403 // Trigger overuse.
404 int64_t frame_interval_us = rtc::kNumMicrosecsPerSec / kCapturerMaxFrameRate;
405 // Processing time just below over use limit given kEncodeMaxFrameRate.
406 int64_t processing_time_us =
407 (98 * OveruseProcessingTimeLimitForFramerate(kEncodeMaxFrameRate)) / 100;
408 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
409 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
410 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
411 processing_time_us);
sprangfda496a2017-06-15 04:21:07 -0700412 overuse_detector_->CheckForOveruse();
413 }
Niels Möller7dc26b72017-12-06 10:27:48 +0100414
415 // Simulate frame rate reduction and normal usage.
416 frame_interval_us = rtc::kNumMicrosecsPerSec / kEncodeMaxFrameRate;
417 overuse_detector_->OnTargetFramerateUpdated(kEncodeMaxFrameRate);
418 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
419 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
420 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
421 processing_time_us);
422 overuse_detector_->CheckForOveruse();
423 }
424
425 // Reduce processing time to trigger underuse.
426 processing_time_us =
427 (98 * UnderuseProcessingTimeLimitForFramerate(kEncodeMaxFrameRate)) / 100;
428 EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(1);
429 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
430 processing_time_us);
431 overuse_detector_->CheckForOveruse();
sprangfda496a2017-06-15 04:21:07 -0700432}
433
Niels Möller7dc26b72017-12-06 10:27:48 +0100434TEST_F(OveruseFrameDetectorTest, RespectsMinFramerate) {
435 const int kMinFrameRate = 7; // Minimum fps allowed by current detector impl.
436 overuse_detector_->OnTargetFramerateUpdated(kMinFrameRate);
sprangfda496a2017-06-15 04:21:07 -0700437
Niels Möller7dc26b72017-12-06 10:27:48 +0100438 // Normal usage just at the limit.
439 int64_t frame_interval_us = rtc::kNumMicrosecsPerSec / kMinFrameRate;
440 // Processing time just below over use limit given kEncodeMaxFrameRate.
441 int64_t processing_time_us =
442 (98 * OveruseProcessingTimeLimitForFramerate(kMinFrameRate)) / 100;
443 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
444 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
445 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
446 processing_time_us);
sprangfda496a2017-06-15 04:21:07 -0700447 overuse_detector_->CheckForOveruse();
448 }
Niels Möller7dc26b72017-12-06 10:27:48 +0100449
450 // Over the limit to overuse.
451 processing_time_us =
452 (102 * OveruseProcessingTimeLimitForFramerate(kMinFrameRate)) / 100;
453 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
454 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
455 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
456 processing_time_us);
457 overuse_detector_->CheckForOveruse();
458 }
459
460 // Reduce input frame rate. Should still trigger overuse.
461 overuse_detector_->OnTargetFramerateUpdated(kMinFrameRate - 1);
462 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
463 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
464 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
465 processing_time_us);
466 overuse_detector_->CheckForOveruse();
467 }
468}
469
470TEST_F(OveruseFrameDetectorTest, LimitsMaxFrameInterval) {
471 const int kMaxFrameRate = 20;
472 overuse_detector_->OnTargetFramerateUpdated(kMaxFrameRate);
473 int64_t frame_interval_us = rtc::kNumMicrosecsPerSec / kMaxFrameRate;
474 // Maximum frame interval allowed is 35% above ideal.
475 int64_t max_frame_interval_us = (135 * frame_interval_us) / 100;
476 // Maximum processing time, without triggering overuse, allowed with the above
477 // frame interval.
478 int64_t max_processing_time_us =
479 (max_frame_interval_us * options_.high_encode_usage_threshold_percent) /
480 100;
481
482 // Processing time just below overuse limit given kMaxFrameRate.
483 int64_t processing_time_us = (98 * max_processing_time_us) / 100;
484 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
485 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
486 InsertAndSendFramesWithInterval(1200, max_frame_interval_us, kWidth,
487 kHeight, processing_time_us);
488 overuse_detector_->CheckForOveruse();
489 }
490
491 // Go above limit, trigger overuse.
492 processing_time_us = (102 * max_processing_time_us) / 100;
493 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
494 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
495 InsertAndSendFramesWithInterval(1200, max_frame_interval_us, kWidth,
496 kHeight, processing_time_us);
497 overuse_detector_->CheckForOveruse();
498 }
499
500 // Increase frame interval, should still trigger overuse.
501 max_frame_interval_us *= 2;
502 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
503 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
504 InsertAndSendFramesWithInterval(1200, max_frame_interval_us, kWidth,
505 kHeight, processing_time_us);
506 overuse_detector_->CheckForOveruse();
507 }
sprangfda496a2017-06-15 04:21:07 -0700508}
509
Niels Möllere541be72017-12-13 13:03:10 +0100510// Models screencast, with irregular arrival of frames which are heavy
511// to encode.
512TEST_F(OveruseFrameDetectorTest, NoOveruseForLargeRandomFrameInterval) {
513 // TODO(bugs.webrtc.org/8504): When new estimator is relanded,
514 // behavior is improved in this scenario, with only AdaptUp events,
515 // and estimated load closer to the true average.
516
517 // EXPECT_CALL(*(observer_.get()), AdaptDown(_)).Times(0);
518 // EXPECT_CALL(*(observer_.get()), AdaptUp(reason_))
519 // .Times(testing::AtLeast(1));
520
521 const int kNumFrames = 500;
522 const int kEncodeTimeUs = 100 * rtc::kNumMicrosecsPerMillisec;
523
524 const int kMinIntervalUs = 30 * rtc::kNumMicrosecsPerMillisec;
525 const int kMaxIntervalUs = 1000 * rtc::kNumMicrosecsPerMillisec;
526
527 const int kTargetFramerate = 5;
528
529 overuse_detector_->OnTargetFramerateUpdated(kTargetFramerate);
530
531 InsertAndSendFramesWithRandomInterval(kNumFrames,
532 kMinIntervalUs, kMaxIntervalUs,
533 kWidth, kHeight, kEncodeTimeUs);
534 // Average usage 19%. Check that estimate is in the right ball park.
535 // EXPECT_NEAR(UsagePercent(), 20, 10);
536 EXPECT_NEAR(UsagePercent(), 20, 35);
537}
538
539// Models screencast, with irregular arrival of frames, often
540// exceeding the timeout interval.
541TEST_F(OveruseFrameDetectorTest, NoOveruseForRandomFrameIntervalWithReset) {
542 // TODO(bugs.webrtc.org/8504): When new estimator is relanded,
543 // behavior is improved in this scenario, and we get AdaptUp events.
544 EXPECT_CALL(*(observer_.get()), AdaptDown(_)).Times(0);
545 // EXPECT_CALL(*(observer_.get()), AdaptUp(reason_))
546 // .Times(testing::AtLeast(1));
547
548 const int kNumFrames = 500;
549 const int kEncodeTimeUs = 100 * rtc::kNumMicrosecsPerMillisec;
550
551 const int kMinIntervalUs = 30 * rtc::kNumMicrosecsPerMillisec;
552 const int kMaxIntervalUs = 3000 * rtc::kNumMicrosecsPerMillisec;
553
554 const int kTargetFramerate = 5;
555
556 overuse_detector_->OnTargetFramerateUpdated(kTargetFramerate);
557
558 InsertAndSendFramesWithRandomInterval(kNumFrames,
559 kMinIntervalUs, kMaxIntervalUs,
560 kWidth, kHeight, kEncodeTimeUs);
561
562 // Average usage 6.6%, but since the frame_timeout_interval_ms is
563 // only 1500 ms, we often reset the estimate to the initial value.
564 // Check that estimate is in the right ball park.
565 EXPECT_GE(UsagePercent(), 1);
566 EXPECT_LE(UsagePercent(), InitialUsage() + 5);
567}
568
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000569} // namespace webrtc