1 /*
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
11 #include "webrtc/video/overuse_frame_detector.h"
12
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 #include "webrtc/base/scoped_ptr.h"
17 #include "webrtc/system_wrappers/include/clock.h"
18
19 namespace webrtc {
20 namespace {
21 const int kWidth = 640;
22 const int kHeight = 480;
23 const int kFrameInterval33ms = 33;
24 const int kProcessIntervalMs = 5000;
25 const int kProcessTime5ms = 5;
26 } // namespace
27
28 class MockCpuOveruseObserver : public CpuOveruseObserver {
29 public:
MockCpuOveruseObserver()30 MockCpuOveruseObserver() {}
~MockCpuOveruseObserver()31 virtual ~MockCpuOveruseObserver() {}
32
33 MOCK_METHOD0(OveruseDetected, void());
34 MOCK_METHOD0(NormalUsage, void());
35 };
36
37 class CpuOveruseObserverImpl : public CpuOveruseObserver {
38 public:
CpuOveruseObserverImpl()39 CpuOveruseObserverImpl() :
40 overuse_(0),
41 normaluse_(0) {}
~CpuOveruseObserverImpl()42 virtual ~CpuOveruseObserverImpl() {}
43
OveruseDetected()44 void OveruseDetected() { ++overuse_; }
NormalUsage()45 void NormalUsage() { ++normaluse_; }
46
47 int overuse_;
48 int normaluse_;
49 };
50
51 class OveruseFrameDetectorTest : public ::testing::Test,
52 public CpuOveruseMetricsObserver {
53 protected:
SetUp()54 virtual void SetUp() {
55 clock_.reset(new SimulatedClock(1234));
56 observer_.reset(new MockCpuOveruseObserver());
57 options_.min_process_count = 0;
58 ReinitializeOveruseDetector();
59 }
60
ReinitializeOveruseDetector()61 void ReinitializeOveruseDetector() {
62 overuse_detector_.reset(new OveruseFrameDetector(clock_.get(), options_,
63 observer_.get(), this));
64 }
65
CpuOveruseMetricsUpdated(const CpuOveruseMetrics & metrics)66 void CpuOveruseMetricsUpdated(const CpuOveruseMetrics& metrics) override {
67 metrics_ = metrics;
68 }
69
InitialUsage()70 int InitialUsage() {
71 return ((options_.low_encode_usage_threshold_percent +
72 options_.high_encode_usage_threshold_percent) / 2.0f) + 0.5;
73 }
74
InsertAndSendFramesWithInterval(int num_frames,int interval_ms,int width,int height,int delay_ms)75 void InsertAndSendFramesWithInterval(
76 int num_frames, int interval_ms, int width, int height, int delay_ms) {
77 while (num_frames-- > 0) {
78 int64_t capture_time_ms = clock_->TimeInMilliseconds();
79 overuse_detector_->FrameCaptured(width, height, capture_time_ms);
80 clock_->AdvanceTimeMilliseconds(delay_ms);
81 overuse_detector_->FrameSent(capture_time_ms);
82 clock_->AdvanceTimeMilliseconds(interval_ms - delay_ms);
83 }
84 }
85
TriggerOveruse(int num_times)86 void TriggerOveruse(int num_times) {
87 const int kDelayMs = 32;
88 for (int i = 0; i < num_times; ++i) {
89 InsertAndSendFramesWithInterval(
90 1000, kFrameInterval33ms, kWidth, kHeight, kDelayMs);
91 overuse_detector_->Process();
92 }
93 }
94
TriggerUnderuse()95 void TriggerUnderuse() {
96 const int kDelayMs1 = 5;
97 const int kDelayMs2 = 6;
98 InsertAndSendFramesWithInterval(
99 1300, kFrameInterval33ms, kWidth, kHeight, kDelayMs1);
100 InsertAndSendFramesWithInterval(
101 1, kFrameInterval33ms, kWidth, kHeight, kDelayMs2);
102 overuse_detector_->Process();
103 }
104
UsagePercent()105 int UsagePercent() { return metrics_.encode_usage_percent; }
106
107 CpuOveruseOptions options_;
108 rtc::scoped_ptr<SimulatedClock> clock_;
109 rtc::scoped_ptr<MockCpuOveruseObserver> observer_;
110 rtc::scoped_ptr<OveruseFrameDetector> overuse_detector_;
111 CpuOveruseMetrics metrics_;
112 };
113
114
115 // UsagePercent() > high_encode_usage_threshold_percent => overuse.
116 // UsagePercent() < low_encode_usage_threshold_percent => underuse.
TEST_F(OveruseFrameDetectorTest,TriggerOveruse)117 TEST_F(OveruseFrameDetectorTest, TriggerOveruse) {
118 // usage > high => overuse
119 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
120 TriggerOveruse(options_.high_threshold_consecutive_count);
121 }
122
TEST_F(OveruseFrameDetectorTest,OveruseAndRecover)123 TEST_F(OveruseFrameDetectorTest, OveruseAndRecover) {
124 // usage > high => overuse
125 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
126 TriggerOveruse(options_.high_threshold_consecutive_count);
127 // usage < low => underuse
128 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1));
129 TriggerUnderuse();
130 }
131
TEST_F(OveruseFrameDetectorTest,OveruseAndRecoverWithNoObserver)132 TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithNoObserver) {
133 overuse_detector_.reset(
134 new OveruseFrameDetector(clock_.get(), options_, nullptr, this));
135 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0);
136 TriggerOveruse(options_.high_threshold_consecutive_count);
137 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0);
138 TriggerUnderuse();
139 }
140
TEST_F(OveruseFrameDetectorTest,DoubleOveruseAndRecover)141 TEST_F(OveruseFrameDetectorTest, DoubleOveruseAndRecover) {
142 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(2);
143 TriggerOveruse(options_.high_threshold_consecutive_count);
144 TriggerOveruse(options_.high_threshold_consecutive_count);
145 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1));
146 TriggerUnderuse();
147 }
148
TEST_F(OveruseFrameDetectorTest,TriggerUnderuseWithMinProcessCount)149 TEST_F(OveruseFrameDetectorTest, TriggerUnderuseWithMinProcessCount) {
150 options_.min_process_count = 1;
151 CpuOveruseObserverImpl overuse_observer;
152 overuse_detector_.reset(new OveruseFrameDetector(clock_.get(), options_,
153 &overuse_observer, this));
154 InsertAndSendFramesWithInterval(
155 1200, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms);
156 overuse_detector_->Process();
157 EXPECT_EQ(0, overuse_observer.normaluse_);
158 clock_->AdvanceTimeMilliseconds(kProcessIntervalMs);
159 overuse_detector_->Process();
160 EXPECT_EQ(1, overuse_observer.normaluse_);
161 }
162
TEST_F(OveruseFrameDetectorTest,ConstantOveruseGivesNoNormalUsage)163 TEST_F(OveruseFrameDetectorTest, ConstantOveruseGivesNoNormalUsage) {
164 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0);
165 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(64);
166 for (size_t i = 0; i < 64; ++i) {
167 TriggerOveruse(options_.high_threshold_consecutive_count);
168 }
169 }
170
TEST_F(OveruseFrameDetectorTest,ConsecutiveCountTriggersOveruse)171 TEST_F(OveruseFrameDetectorTest, ConsecutiveCountTriggersOveruse) {
172 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
173 options_.high_threshold_consecutive_count = 2;
174 ReinitializeOveruseDetector();
175 TriggerOveruse(2);
176 }
177
TEST_F(OveruseFrameDetectorTest,IncorrectConsecutiveCountTriggersNoOveruse)178 TEST_F(OveruseFrameDetectorTest, IncorrectConsecutiveCountTriggersNoOveruse) {
179 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0);
180 options_.high_threshold_consecutive_count = 2;
181 ReinitializeOveruseDetector();
182 TriggerOveruse(1);
183 }
184
TEST_F(OveruseFrameDetectorTest,ProcessingUsage)185 TEST_F(OveruseFrameDetectorTest, ProcessingUsage) {
186 InsertAndSendFramesWithInterval(
187 1000, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms);
188 EXPECT_EQ(kProcessTime5ms * 100 / kFrameInterval33ms, UsagePercent());
189 }
190
TEST_F(OveruseFrameDetectorTest,ResetAfterResolutionChange)191 TEST_F(OveruseFrameDetectorTest, ResetAfterResolutionChange) {
192 EXPECT_EQ(InitialUsage(), UsagePercent());
193 InsertAndSendFramesWithInterval(
194 1000, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms);
195 EXPECT_NE(InitialUsage(), UsagePercent());
196 // Verify reset.
197 InsertAndSendFramesWithInterval(
198 1, kFrameInterval33ms, kWidth, kHeight + 1, kProcessTime5ms);
199 EXPECT_EQ(InitialUsage(), UsagePercent());
200 }
201
TEST_F(OveruseFrameDetectorTest,ResetAfterFrameTimeout)202 TEST_F(OveruseFrameDetectorTest, ResetAfterFrameTimeout) {
203 EXPECT_EQ(InitialUsage(), UsagePercent());
204 InsertAndSendFramesWithInterval(
205 1000, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms);
206 EXPECT_NE(InitialUsage(), UsagePercent());
207 InsertAndSendFramesWithInterval(
208 2, options_.frame_timeout_interval_ms, kWidth, kHeight, kProcessTime5ms);
209 EXPECT_NE(InitialUsage(), UsagePercent());
210 // Verify reset.
211 InsertAndSendFramesWithInterval(
212 2, options_.frame_timeout_interval_ms + 1, kWidth, kHeight,
213 kProcessTime5ms);
214 EXPECT_EQ(InitialUsage(), UsagePercent());
215 }
216
TEST_F(OveruseFrameDetectorTest,MinFrameSamplesBeforeUpdating)217 TEST_F(OveruseFrameDetectorTest, MinFrameSamplesBeforeUpdating) {
218 options_.min_frame_samples = 40;
219 ReinitializeOveruseDetector();
220 InsertAndSendFramesWithInterval(
221 40, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms);
222 EXPECT_EQ(InitialUsage(), UsagePercent());
223 InsertAndSendFramesWithInterval(
224 1, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms);
225 EXPECT_NE(InitialUsage(), UsagePercent());
226 }
227
TEST_F(OveruseFrameDetectorTest,InitialProcessingUsage)228 TEST_F(OveruseFrameDetectorTest, InitialProcessingUsage) {
229 EXPECT_EQ(InitialUsage(), UsagePercent());
230 }
231
TEST_F(OveruseFrameDetectorTest,FrameDelay_OneFrame)232 TEST_F(OveruseFrameDetectorTest, FrameDelay_OneFrame) {
233 const int kProcessingTimeMs = 100;
234 overuse_detector_->FrameCaptured(kWidth, kHeight, 33);
235 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs);
236 EXPECT_EQ(-1, overuse_detector_->LastProcessingTimeMs());
237 overuse_detector_->FrameSent(33);
238 EXPECT_EQ(kProcessingTimeMs, overuse_detector_->LastProcessingTimeMs());
239 EXPECT_EQ(0, overuse_detector_->FramesInQueue());
240 }
241
TEST_F(OveruseFrameDetectorTest,FrameDelay_TwoFrames)242 TEST_F(OveruseFrameDetectorTest, FrameDelay_TwoFrames) {
243 const int kProcessingTimeMs1 = 100;
244 const int kProcessingTimeMs2 = 50;
245 const int kTimeBetweenFramesMs = 200;
246 overuse_detector_->FrameCaptured(kWidth, kHeight, 33);
247 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs1);
248 overuse_detector_->FrameSent(33);
249 EXPECT_EQ(kProcessingTimeMs1, overuse_detector_->LastProcessingTimeMs());
250 clock_->AdvanceTimeMilliseconds(kTimeBetweenFramesMs);
251 overuse_detector_->FrameCaptured(kWidth, kHeight, 66);
252 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs2);
253 overuse_detector_->FrameSent(66);
254 EXPECT_EQ(kProcessingTimeMs2, overuse_detector_->LastProcessingTimeMs());
255 }
256
TEST_F(OveruseFrameDetectorTest,FrameDelay_MaxQueueSize)257 TEST_F(OveruseFrameDetectorTest, FrameDelay_MaxQueueSize) {
258 const int kMaxQueueSize = 91;
259 for (int i = 0; i < kMaxQueueSize * 2; ++i) {
260 overuse_detector_->FrameCaptured(kWidth, kHeight, i);
261 }
262 EXPECT_EQ(kMaxQueueSize, overuse_detector_->FramesInQueue());
263 }
264
TEST_F(OveruseFrameDetectorTest,FrameDelay_NonProcessedFramesRemoved)265 TEST_F(OveruseFrameDetectorTest, FrameDelay_NonProcessedFramesRemoved) {
266 const int kProcessingTimeMs = 100;
267 overuse_detector_->FrameCaptured(kWidth, kHeight, 33);
268 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs);
269 overuse_detector_->FrameCaptured(kWidth, kHeight, 35);
270 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs);
271 overuse_detector_->FrameCaptured(kWidth, kHeight, 66);
272 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs);
273 overuse_detector_->FrameCaptured(kWidth, kHeight, 99);
274 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs);
275 EXPECT_EQ(-1, overuse_detector_->LastProcessingTimeMs());
276 EXPECT_EQ(4, overuse_detector_->FramesInQueue());
277 overuse_detector_->FrameSent(66);
278 // Frame 33, 35 removed, 66 processed, 99 not processed.
279 EXPECT_EQ(2 * kProcessingTimeMs, overuse_detector_->LastProcessingTimeMs());
280 EXPECT_EQ(1, overuse_detector_->FramesInQueue());
281 overuse_detector_->FrameSent(99);
282 EXPECT_EQ(kProcessingTimeMs, overuse_detector_->LastProcessingTimeMs());
283 EXPECT_EQ(0, overuse_detector_->FramesInQueue());
284 }
285
TEST_F(OveruseFrameDetectorTest,FrameDelay_ResetClearsFrames)286 TEST_F(OveruseFrameDetectorTest, FrameDelay_ResetClearsFrames) {
287 const int kProcessingTimeMs = 100;
288 overuse_detector_->FrameCaptured(kWidth, kHeight, 33);
289 EXPECT_EQ(1, overuse_detector_->FramesInQueue());
290 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs);
291 // Verify reset (resolution changed).
292 overuse_detector_->FrameCaptured(kWidth, kHeight + 1, 66);
293 EXPECT_EQ(1, overuse_detector_->FramesInQueue());
294 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs);
295 overuse_detector_->FrameSent(66);
296 EXPECT_EQ(kProcessingTimeMs, overuse_detector_->LastProcessingTimeMs());
297 EXPECT_EQ(0, overuse_detector_->FramesInQueue());
298 }
299
TEST_F(OveruseFrameDetectorTest,FrameDelay_NonMatchingSendFrameIgnored)300 TEST_F(OveruseFrameDetectorTest, FrameDelay_NonMatchingSendFrameIgnored) {
301 const int kProcessingTimeMs = 100;
302 overuse_detector_->FrameCaptured(kWidth, kHeight, 33);
303 clock_->AdvanceTimeMilliseconds(kProcessingTimeMs);
304 overuse_detector_->FrameSent(34);
305 EXPECT_EQ(-1, overuse_detector_->LastProcessingTimeMs());
306 overuse_detector_->FrameSent(33);
307 EXPECT_EQ(kProcessingTimeMs, overuse_detector_->LastProcessingTimeMs());
308 }
309
310 } // namespace webrtc
311