• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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