blob: 0f3dd8643e3c89a8a7673c534031eaed5d6cd073 [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"
18#include "test/gmock.h"
19#include "test/gtest.h"
20#include "video/overuse_frame_detector.h"
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000021
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000022namespace webrtc {
perkjd52063f2016-09-07 06:32:18 -070023
kthelgason876222f2016-11-29 01:44:11 -080024using ::testing::InvokeWithoutArgs;
perkjd52063f2016-09-07 06:32:18 -070025
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000026namespace {
27 const int kWidth = 640;
28 const int kHeight = 480;
nissee0e3bdf2017-01-18 02:16:20 -080029 const int kFrameIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
30 const int kProcessTimeUs = 5 * rtc::kNumMicrosecsPerMillisec;
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000031} // namespace
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000032
sprangb1ca0732017-02-01 08:38:12 -080033class MockCpuOveruseObserver : public AdaptationObserverInterface {
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000034 public:
mflodman@webrtc.org6879c8a2013-07-23 11:35:00 +000035 MockCpuOveruseObserver() {}
36 virtual ~MockCpuOveruseObserver() {}
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000037
sprangb1ca0732017-02-01 08:38:12 -080038 MOCK_METHOD1(AdaptUp, void(AdaptReason));
39 MOCK_METHOD1(AdaptDown, void(AdaptReason));
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000040};
41
sprangb1ca0732017-02-01 08:38:12 -080042class CpuOveruseObserverImpl : public AdaptationObserverInterface {
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000043 public:
44 CpuOveruseObserverImpl() :
45 overuse_(0),
46 normaluse_(0) {}
47 virtual ~CpuOveruseObserverImpl() {}
48
sprangb1ca0732017-02-01 08:38:12 -080049 void AdaptDown(AdaptReason) { ++overuse_; }
50 void AdaptUp(AdaptReason) { ++normaluse_; }
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000051
52 int overuse_;
53 int normaluse_;
54};
55
perkjd52063f2016-09-07 06:32:18 -070056class OveruseFrameDetectorUnderTest : public OveruseFrameDetector {
57 public:
nissee0e3bdf2017-01-18 02:16:20 -080058 OveruseFrameDetectorUnderTest(const CpuOveruseOptions& options,
sprangb1ca0732017-02-01 08:38:12 -080059 AdaptationObserverInterface* overuse_observer,
perkjd52063f2016-09-07 06:32:18 -070060 EncodedFrameObserver* encoder_timing,
61 CpuOveruseMetricsObserver* metrics_observer)
nissee0e3bdf2017-01-18 02:16:20 -080062 : OveruseFrameDetector(options,
perkjd52063f2016-09-07 06:32:18 -070063 overuse_observer,
64 encoder_timing,
65 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(
nissee0e3bdf2017-01-18 02:16:20 -080082 options_, observer_.get(), nullptr, 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) {
nissef122a852016-10-04 23:27:30 -0700100 VideoFrame frame(I420Buffer::Create(width, height),
101 webrtc::kVideoRotation_0, 0);
Peter Boströme4499152016-02-05 11:13:28 +0100102 uint32_t timestamp = 0;
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000103 while (num_frames-- > 0) {
Peter Boströme4499152016-02-05 11:13:28 +0100104 frame.set_timestamp(timestamp);
nissee0e3bdf2017-01-18 02:16:20 -0800105 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
Peter Boströme4499152016-02-05 11:13:28 +0100113 void ForceUpdate(int width, int height) {
114 // Insert one frame, wait a second and then put in another to force update
115 // the usage. From the tests where these are used, adding another sample
116 // doesn't affect the expected outcome (this is mainly to check initial
117 // values and whether the overuse detector has been reset or not).
nissee0e3bdf2017-01-18 02:16:20 -0800118 InsertAndSendFramesWithInterval(2, rtc::kNumMicrosecsPerSec,
119 width, height, kFrameIntervalUs);
Peter Boströme4499152016-02-05 11:13:28 +0100120 }
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000121 void TriggerOveruse(int num_times) {
nissee0e3bdf2017-01-18 02:16:20 -0800122 const int kDelayUs = 32 * rtc::kNumMicrosecsPerMillisec;
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000123 for (int i = 0; i < num_times; ++i) {
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000124 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800125 1000, kFrameIntervalUs, kWidth, kHeight, kDelayUs);
perkjd52063f2016-09-07 06:32:18 -0700126 overuse_detector_->CheckForOveruse();
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000127 }
128 }
129
Åsa Persson746210f2015-09-08 10:52:42 +0200130 void TriggerUnderuse() {
nissee0e3bdf2017-01-18 02:16:20 -0800131 const int kDelayUs1 = 5000;
132 const int kDelayUs2 = 6000;
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000133 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800134 1300, kFrameIntervalUs, kWidth, kHeight, kDelayUs1);
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000135 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800136 1, kFrameIntervalUs, kWidth, kHeight, kDelayUs2);
perkjd52063f2016-09-07 06:32:18 -0700137 overuse_detector_->CheckForOveruse();
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000138 }
139
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000140 int UsagePercent() { return metrics_.encode_usage_percent; }
asapersson@webrtc.orgab6bf4f2014-05-27 07:43:15 +0000141
sprangfda496a2017-06-15 04:21:07 -0700142 int64_t OveruseProcessingTimeLimitForFramerate(int fps) const {
143 int64_t frame_interval = rtc::kNumMicrosecsPerSec / fps;
144 int64_t max_processing_time_us =
145 (frame_interval * options_.high_encode_usage_threshold_percent) / 100;
146 return max_processing_time_us;
147 }
148
149 int64_t UnderuseProcessingTimeLimitForFramerate(int fps) const {
150 int64_t frame_interval = rtc::kNumMicrosecsPerSec / fps;
151 int64_t max_processing_time_us =
152 (frame_interval * options_.low_encode_usage_threshold_percent) / 100;
153 return max_processing_time_us;
154 }
155
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000156 CpuOveruseOptions options_;
nissee0e3bdf2017-01-18 02:16:20 -0800157 rtc::ScopedFakeClock clock_;
kwiberg27f982b2016-03-01 11:52:33 -0800158 std::unique_ptr<MockCpuOveruseObserver> observer_;
perkjd52063f2016-09-07 06:32:18 -0700159 std::unique_ptr<OveruseFrameDetectorUnderTest> overuse_detector_;
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000160 CpuOveruseMetrics metrics_;
kthelgason876222f2016-11-29 01:44:11 -0800161
sprangb1ca0732017-02-01 08:38:12 -0800162 static const auto reason_ = AdaptationObserverInterface::AdaptReason::kCpu;
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000163};
164
Åsa Persson746210f2015-09-08 10:52:42 +0200165
Åsa Persson746210f2015-09-08 10:52:42 +0200166// UsagePercent() > high_encode_usage_threshold_percent => overuse.
167// UsagePercent() < low_encode_usage_threshold_percent => underuse.
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000168TEST_F(OveruseFrameDetectorTest, TriggerOveruse) {
Åsa Persson746210f2015-09-08 10:52:42 +0200169 // usage > high => overuse
sprangb1ca0732017-02-01 08:38:12 -0800170 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000171 TriggerOveruse(options_.high_threshold_consecutive_count);
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000172}
173
174TEST_F(OveruseFrameDetectorTest, OveruseAndRecover) {
Åsa Persson746210f2015-09-08 10:52:42 +0200175 // usage > high => overuse
sprangb1ca0732017-02-01 08:38:12 -0800176 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000177 TriggerOveruse(options_.high_threshold_consecutive_count);
Åsa Persson746210f2015-09-08 10:52:42 +0200178 // usage < low => underuse
sprangb1ca0732017-02-01 08:38:12 -0800179 EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(testing::AtLeast(1));
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000180 TriggerUnderuse();
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000181}
182
asapersson@webrtc.org2881ab12014-06-12 08:46:46 +0000183TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithNoObserver) {
perkjd52063f2016-09-07 06:32:18 -0700184 overuse_detector_.reset(new OveruseFrameDetectorUnderTest(
nissee0e3bdf2017-01-18 02:16:20 -0800185 options_, nullptr, nullptr, this));
sprangb1ca0732017-02-01 08:38:12 -0800186 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000187 TriggerOveruse(options_.high_threshold_consecutive_count);
sprangb1ca0732017-02-01 08:38:12 -0800188 EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(0);
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000189 TriggerUnderuse();
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000190}
191
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000192TEST_F(OveruseFrameDetectorTest, DoubleOveruseAndRecover) {
sprangb1ca0732017-02-01 08:38:12 -0800193 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(2);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000194 TriggerOveruse(options_.high_threshold_consecutive_count);
195 TriggerOveruse(options_.high_threshold_consecutive_count);
sprangb1ca0732017-02-01 08:38:12 -0800196 EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(testing::AtLeast(1));
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000197 TriggerUnderuse();
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000198}
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000199
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000200TEST_F(OveruseFrameDetectorTest, TriggerUnderuseWithMinProcessCount) {
nissee0e3bdf2017-01-18 02:16:20 -0800201 const int kProcessIntervalUs = 5 * rtc::kNumMicrosecsPerSec;
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000202 options_.min_process_count = 1;
Peter Boström4b91bd02015-06-26 06:58:16 +0200203 CpuOveruseObserverImpl overuse_observer;
perkjd52063f2016-09-07 06:32:18 -0700204 overuse_detector_.reset(new OveruseFrameDetectorUnderTest(
nissee0e3bdf2017-01-18 02:16:20 -0800205 options_, &overuse_observer, nullptr, this));
Åsa Persson746210f2015-09-08 10:52:42 +0200206 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800207 1200, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
perkjd52063f2016-09-07 06:32:18 -0700208 overuse_detector_->CheckForOveruse();
Peter Boström4b91bd02015-06-26 06:58:16 +0200209 EXPECT_EQ(0, overuse_observer.normaluse_);
nissee0e3bdf2017-01-18 02:16:20 -0800210 clock_.AdvanceTimeMicros(kProcessIntervalUs);
perkjd52063f2016-09-07 06:32:18 -0700211 overuse_detector_->CheckForOveruse();
Peter Boström4b91bd02015-06-26 06:58:16 +0200212 EXPECT_EQ(1, overuse_observer.normaluse_);
asapersson@webrtc.orgb60346e2014-02-17 19:02:15 +0000213}
214
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000215TEST_F(OveruseFrameDetectorTest, ConstantOveruseGivesNoNormalUsage) {
sprangb1ca0732017-02-01 08:38:12 -0800216 EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(0);
217 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(64);
kjellander@webrtc.org0fcaf992015-11-26 15:24:52 +0100218 for (size_t i = 0; i < 64; ++i) {
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000219 TriggerOveruse(options_.high_threshold_consecutive_count);
220 }
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000221}
222
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000223TEST_F(OveruseFrameDetectorTest, ConsecutiveCountTriggersOveruse) {
sprangb1ca0732017-02-01 08:38:12 -0800224 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000225 options_.high_threshold_consecutive_count = 2;
Peter Boström4b91bd02015-06-26 06:58:16 +0200226 ReinitializeOveruseDetector();
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000227 TriggerOveruse(2);
228}
229
230TEST_F(OveruseFrameDetectorTest, IncorrectConsecutiveCountTriggersNoOveruse) {
sprangb1ca0732017-02-01 08:38:12 -0800231 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000232 options_.high_threshold_consecutive_count = 2;
Peter Boström4b91bd02015-06-26 06:58:16 +0200233 ReinitializeOveruseDetector();
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000234 TriggerOveruse(1);
235}
236
Åsa Persson746210f2015-09-08 10:52:42 +0200237TEST_F(OveruseFrameDetectorTest, ProcessingUsage) {
238 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800239 1000, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
240 EXPECT_EQ(kProcessTimeUs * 100 / kFrameIntervalUs, UsagePercent());
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000241}
242
Åsa Persson746210f2015-09-08 10:52:42 +0200243TEST_F(OveruseFrameDetectorTest, ResetAfterResolutionChange) {
Peter Boströme4499152016-02-05 11:13:28 +0100244 ForceUpdate(kWidth, kHeight);
Åsa Persson746210f2015-09-08 10:52:42 +0200245 EXPECT_EQ(InitialUsage(), UsagePercent());
246 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800247 1000, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
Åsa Persson746210f2015-09-08 10:52:42 +0200248 EXPECT_NE(InitialUsage(), UsagePercent());
Peter Boströme4499152016-02-05 11:13:28 +0100249 // Verify reset (with new width/height).
250 ForceUpdate(kWidth, kHeight + 1);
Åsa Persson746210f2015-09-08 10:52:42 +0200251 EXPECT_EQ(InitialUsage(), UsagePercent());
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000252}
253
Åsa Persson746210f2015-09-08 10:52:42 +0200254TEST_F(OveruseFrameDetectorTest, ResetAfterFrameTimeout) {
Peter Boströme4499152016-02-05 11:13:28 +0100255 ForceUpdate(kWidth, kHeight);
Åsa Persson746210f2015-09-08 10:52:42 +0200256 EXPECT_EQ(InitialUsage(), UsagePercent());
257 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800258 1000, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
Åsa Persson746210f2015-09-08 10:52:42 +0200259 EXPECT_NE(InitialUsage(), UsagePercent());
260 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800261 2, options_.frame_timeout_interval_ms *
262 rtc::kNumMicrosecsPerMillisec, kWidth, kHeight, kProcessTimeUs);
Åsa Persson746210f2015-09-08 10:52:42 +0200263 EXPECT_NE(InitialUsage(), UsagePercent());
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000264 // Verify reset.
Åsa Persson746210f2015-09-08 10:52:42 +0200265 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800266 2, (options_.frame_timeout_interval_ms + 1) *
267 rtc::kNumMicrosecsPerMillisec, kWidth, kHeight, kProcessTimeUs);
Peter Boströme4499152016-02-05 11:13:28 +0100268 ForceUpdate(kWidth, kHeight);
Åsa Persson746210f2015-09-08 10:52:42 +0200269 EXPECT_EQ(InitialUsage(), UsagePercent());
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000270}
271
Åsa Persson746210f2015-09-08 10:52:42 +0200272TEST_F(OveruseFrameDetectorTest, MinFrameSamplesBeforeUpdating) {
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000273 options_.min_frame_samples = 40;
Peter Boström4b91bd02015-06-26 06:58:16 +0200274 ReinitializeOveruseDetector();
Åsa Persson746210f2015-09-08 10:52:42 +0200275 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800276 40, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
Åsa Persson746210f2015-09-08 10:52:42 +0200277 EXPECT_EQ(InitialUsage(), UsagePercent());
Peter Boströme4499152016-02-05 11:13:28 +0100278 // Pass time far enough to digest all previous samples.
nissee0e3bdf2017-01-18 02:16:20 -0800279 clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec);
280 InsertAndSendFramesWithInterval(1, kFrameIntervalUs, kWidth, kHeight,
281 kProcessTimeUs);
Peter Boströme4499152016-02-05 11:13:28 +0100282 // The last sample has not been processed here.
283 EXPECT_EQ(InitialUsage(), UsagePercent());
284
285 // Pass time far enough to digest all previous samples, 41 in total.
nissee0e3bdf2017-01-18 02:16:20 -0800286 clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerSec);
Åsa Persson746210f2015-09-08 10:52:42 +0200287 InsertAndSendFramesWithInterval(
nissee0e3bdf2017-01-18 02:16:20 -0800288 1, kFrameIntervalUs, kWidth, kHeight, kProcessTimeUs);
Åsa Persson746210f2015-09-08 10:52:42 +0200289 EXPECT_NE(InitialUsage(), UsagePercent());
290}
291
292TEST_F(OveruseFrameDetectorTest, InitialProcessingUsage) {
Peter Boströme4499152016-02-05 11:13:28 +0100293 ForceUpdate(kWidth, kHeight);
Åsa Persson746210f2015-09-08 10:52:42 +0200294 EXPECT_EQ(InitialUsage(), UsagePercent());
asapersson@webrtc.orgb24d3352013-11-20 13:51:40 +0000295}
296
Peter Boströme4499152016-02-05 11:13:28 +0100297TEST_F(OveruseFrameDetectorTest, MeasuresMultipleConcurrentSamples) {
sprangb1ca0732017-02-01 08:38:12 -0800298 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_))
kthelgason876222f2016-11-29 01:44:11 -0800299 .Times(testing::AtLeast(1));
nissee0e3bdf2017-01-18 02:16:20 -0800300 static const int kIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
Peter Boströme4499152016-02-05 11:13:28 +0100301 static const size_t kNumFramesEncodingDelay = 3;
nissef122a852016-10-04 23:27:30 -0700302 VideoFrame frame(I420Buffer::Create(kWidth, kHeight),
303 webrtc::kVideoRotation_0, 0);
Peter Boströme4499152016-02-05 11:13:28 +0100304 for (size_t i = 0; i < 1000; ++i) {
305 // Unique timestamps.
306 frame.set_timestamp(static_cast<uint32_t>(i));
nissee0e3bdf2017-01-18 02:16:20 -0800307 overuse_detector_->FrameCaptured(frame, rtc::TimeMicros());
308 clock_.AdvanceTimeMicros(kIntervalUs);
Peter Boströme4499152016-02-05 11:13:28 +0100309 if (i > kNumFramesEncodingDelay) {
310 overuse_detector_->FrameSent(
perkjd52063f2016-09-07 06:32:18 -0700311 static_cast<uint32_t>(i - kNumFramesEncodingDelay),
nissee0e3bdf2017-01-18 02:16:20 -0800312 rtc::TimeMicros());
Peter Boströme4499152016-02-05 11:13:28 +0100313 }
perkjd52063f2016-09-07 06:32:18 -0700314 overuse_detector_->CheckForOveruse();
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000315 }
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000316}
317
Peter Boströme4499152016-02-05 11:13:28 +0100318TEST_F(OveruseFrameDetectorTest, UpdatesExistingSamples) {
319 // >85% encoding time should trigger overuse.
sprangb1ca0732017-02-01 08:38:12 -0800320 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_))
kthelgason876222f2016-11-29 01:44:11 -0800321 .Times(testing::AtLeast(1));
nissee0e3bdf2017-01-18 02:16:20 -0800322 static const int kIntervalUs = 33 * rtc::kNumMicrosecsPerMillisec;
323 static const int kDelayUs = 30 * rtc::kNumMicrosecsPerMillisec;
nissef122a852016-10-04 23:27:30 -0700324 VideoFrame frame(I420Buffer::Create(kWidth, kHeight),
325 webrtc::kVideoRotation_0, 0);
Peter Boströme4499152016-02-05 11:13:28 +0100326 uint32_t timestamp = 0;
327 for (size_t i = 0; i < 1000; ++i) {
328 frame.set_timestamp(timestamp);
nissee0e3bdf2017-01-18 02:16:20 -0800329 overuse_detector_->FrameCaptured(frame, rtc::TimeMicros());
Peter Boströme4499152016-02-05 11:13:28 +0100330 // Encode and send first parts almost instantly.
nissee0e3bdf2017-01-18 02:16:20 -0800331 clock_.AdvanceTimeMicros(rtc::kNumMicrosecsPerMillisec);
332 overuse_detector_->FrameSent(timestamp, rtc::TimeMicros());
Peter Boströme4499152016-02-05 11:13:28 +0100333 // Encode heavier part, resulting in >85% usage total.
nissee0e3bdf2017-01-18 02:16:20 -0800334 clock_.AdvanceTimeMicros(kDelayUs - rtc::kNumMicrosecsPerMillisec);
335 overuse_detector_->FrameSent(timestamp, rtc::TimeMicros());
336 clock_.AdvanceTimeMicros(kIntervalUs - kDelayUs);
337 timestamp += kIntervalUs * 90 / 1000;
perkjd52063f2016-09-07 06:32:18 -0700338 overuse_detector_->CheckForOveruse();
Peter Boströme4499152016-02-05 11:13:28 +0100339 }
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000340}
341
perkjd52063f2016-09-07 06:32:18 -0700342TEST_F(OveruseFrameDetectorTest, RunOnTqNormalUsage) {
343 rtc::TaskQueue queue("OveruseFrameDetectorTestQueue");
344
345 rtc::Event event(false, false);
346 queue.PostTask([this, &event] {
347 overuse_detector_->StartCheckForOveruse();
348 event.Set();
349 });
350 event.Wait(rtc::Event::kForever);
351
352 // Expect NormalUsage(). When called, stop the |overuse_detector_| and then
353 // set |event| to end the test.
sprangb1ca0732017-02-01 08:38:12 -0800354 EXPECT_CALL(*(observer_.get()), AdaptUp(reason_))
kthelgason876222f2016-11-29 01:44:11 -0800355 .WillOnce(InvokeWithoutArgs([this, &event] {
perkjd52063f2016-09-07 06:32:18 -0700356 overuse_detector_->StopCheckForOveruse();
357 event.Set();
358 }));
359
eladalon1cc5fc32017-08-23 04:15:18 -0700360 queue.PostTask([this] {
nissee0e3bdf2017-01-18 02:16:20 -0800361 const int kDelayUs1 = 5 * rtc::kNumMicrosecsPerMillisec;
362 const int kDelayUs2 = 6 * rtc::kNumMicrosecsPerMillisec;
363 InsertAndSendFramesWithInterval(1300, kFrameIntervalUs, kWidth, kHeight,
364 kDelayUs1);
365 InsertAndSendFramesWithInterval(1, kFrameIntervalUs, kWidth, kHeight,
366 kDelayUs2);
perkjd52063f2016-09-07 06:32:18 -0700367 });
368
369 EXPECT_TRUE(event.Wait(10000));
370}
371
sprangfda496a2017-06-15 04:21:07 -0700372TEST_F(OveruseFrameDetectorTest, MaxIntervalScalesWithFramerate) {
373 const int kCapturerMaxFrameRate = 30;
374 const int kEncodeMaxFrameRate = 20; // Maximum fps the encoder can sustain.
375
376 // Trigger overuse.
377 int64_t frame_interval_us = rtc::kNumMicrosecsPerSec / kCapturerMaxFrameRate;
378 // Processing time just below over use limit given kEncodeMaxFrameRate.
379 int64_t processing_time_us =
380 (98 * OveruseProcessingTimeLimitForFramerate(kEncodeMaxFrameRate)) / 100;
381 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
382 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
383 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
384 processing_time_us);
385 overuse_detector_->CheckForOveruse();
386 }
387
388 // Simulate frame rate reduction and normal usage.
389 frame_interval_us = rtc::kNumMicrosecsPerSec / kEncodeMaxFrameRate;
390 overuse_detector_->OnTargetFramerateUpdated(kEncodeMaxFrameRate);
391 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
392 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
393 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
394 processing_time_us);
395 overuse_detector_->CheckForOveruse();
396 }
397
398 // Reduce processing time to trigger underuse.
399 processing_time_us =
400 (98 * UnderuseProcessingTimeLimitForFramerate(kEncodeMaxFrameRate)) / 100;
401 EXPECT_CALL(*(observer_.get()), AdaptUp(reason_)).Times(1);
402 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
403 processing_time_us);
404 overuse_detector_->CheckForOveruse();
405}
406
407TEST_F(OveruseFrameDetectorTest, RespectsMinFramerate) {
408 const int kMinFrameRate = 7; // Minimum fps allowed by current detector impl.
409 overuse_detector_->OnTargetFramerateUpdated(kMinFrameRate);
410
411 // Normal usage just at the limit.
412 int64_t frame_interval_us = rtc::kNumMicrosecsPerSec / kMinFrameRate;
413 // Processing time just below over use limit given kEncodeMaxFrameRate.
414 int64_t processing_time_us =
415 (98 * OveruseProcessingTimeLimitForFramerate(kMinFrameRate)) / 100;
416 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
417 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
418 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
419 processing_time_us);
420 overuse_detector_->CheckForOveruse();
421 }
422
423 // Over the limit to overuse.
424 processing_time_us =
425 (102 * OveruseProcessingTimeLimitForFramerate(kMinFrameRate)) / 100;
426 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
427 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
428 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
429 processing_time_us);
430 overuse_detector_->CheckForOveruse();
431 }
432
433 // Reduce input frame rate. Should still trigger overuse.
434 overuse_detector_->OnTargetFramerateUpdated(kMinFrameRate - 1);
435 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
436 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
437 InsertAndSendFramesWithInterval(1200, frame_interval_us, kWidth, kHeight,
438 processing_time_us);
439 overuse_detector_->CheckForOveruse();
440 }
441}
442
443TEST_F(OveruseFrameDetectorTest, LimitsMaxFrameInterval) {
444 const int kMaxFrameRate = 20;
445 overuse_detector_->OnTargetFramerateUpdated(kMaxFrameRate);
446 int64_t frame_interval_us = rtc::kNumMicrosecsPerSec / kMaxFrameRate;
447 // Maximum frame interval allowed is 35% above ideal.
448 int64_t max_frame_interval_us = (135 * frame_interval_us) / 100;
449 // Maximum processing time, without triggering overuse, allowed with the above
450 // frame interval.
451 int64_t max_processing_time_us =
452 (max_frame_interval_us * options_.high_encode_usage_threshold_percent) /
453 100;
454
455 // Processing time just below overuse limit given kMaxFrameRate.
456 int64_t processing_time_us = (98 * max_processing_time_us) / 100;
457 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(0);
458 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
459 InsertAndSendFramesWithInterval(1200, max_frame_interval_us, kWidth,
460 kHeight, processing_time_us);
461 overuse_detector_->CheckForOveruse();
462 }
463
464 // Go above limit, trigger overuse.
465 processing_time_us = (102 * max_processing_time_us) / 100;
466 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
467 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
468 InsertAndSendFramesWithInterval(1200, max_frame_interval_us, kWidth,
469 kHeight, processing_time_us);
470 overuse_detector_->CheckForOveruse();
471 }
472
473 // Increase frame interval, should still trigger overuse.
474 max_frame_interval_us *= 2;
475 EXPECT_CALL(*(observer_.get()), AdaptDown(reason_)).Times(1);
476 for (int i = 0; i < options_.high_threshold_consecutive_count; ++i) {
477 InsertAndSendFramesWithInterval(1200, max_frame_interval_us, kWidth,
478 kHeight, processing_time_us);
479 overuse_detector_->CheckForOveruse();
480 }
481}
482
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000483} // namespace webrtc