OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include <memory> | 11 #include <memory> |
12 | 12 |
13 #include "webrtc/base/event.h" | 13 #include "webrtc/base/event.h" |
14 #include "webrtc/system_wrappers/include/clock.h" | 14 #include "webrtc/system_wrappers/include/clock.h" |
15 #include "webrtc/test/gmock.h" | 15 #include "webrtc/test/gmock.h" |
16 #include "webrtc/test/gtest.h" | 16 #include "webrtc/test/gtest.h" |
17 #include "webrtc/video/overuse_frame_detector.h" | 17 #include "webrtc/video/overuse_frame_detector.h" |
18 #include "webrtc/video_frame.h" | 18 #include "webrtc/video_frame.h" |
| 19 #include "webrtc/modules/video_coding/utility/quality_scaler.h" |
19 | 20 |
20 namespace webrtc { | 21 namespace webrtc { |
21 | 22 |
22 using ::testing::Invoke; | 23 using ::testing::InvokeWithoutArgs; |
23 | 24 |
24 namespace { | 25 namespace { |
25 const int kWidth = 640; | 26 const int kWidth = 640; |
26 const int kHeight = 480; | 27 const int kHeight = 480; |
27 const int kFrameInterval33ms = 33; | 28 const int kFrameInterval33ms = 33; |
28 const int kProcessIntervalMs = 5000; | 29 const int kProcessIntervalMs = 5000; |
29 const int kProcessTime5ms = 5; | 30 const int kProcessTime5ms = 5; |
30 } // namespace | 31 } // namespace |
31 | 32 |
32 class MockCpuOveruseObserver : public CpuOveruseObserver { | 33 class MockCpuOveruseObserver : public ScalingObserverInterface { |
33 public: | 34 public: |
34 MockCpuOveruseObserver() {} | 35 MockCpuOveruseObserver() {} |
35 virtual ~MockCpuOveruseObserver() {} | 36 virtual ~MockCpuOveruseObserver() {} |
36 | 37 |
37 MOCK_METHOD0(OveruseDetected, void()); | 38 MOCK_METHOD1(ScaleUp, void(ScaleReason)); |
38 MOCK_METHOD0(NormalUsage, void()); | 39 MOCK_METHOD1(ScaleDown, void(ScaleReason)); |
39 }; | 40 }; |
40 | 41 |
41 class CpuOveruseObserverImpl : public CpuOveruseObserver { | 42 class CpuOveruseObserverImpl : public ScalingObserverInterface { |
42 public: | 43 public: |
43 CpuOveruseObserverImpl() : | 44 CpuOveruseObserverImpl() : |
44 overuse_(0), | 45 overuse_(0), |
45 normaluse_(0) {} | 46 normaluse_(0) {} |
46 virtual ~CpuOveruseObserverImpl() {} | 47 virtual ~CpuOveruseObserverImpl() {} |
47 | 48 |
48 void OveruseDetected() { ++overuse_; } | 49 void ScaleDown(ScaleReason) { ++overuse_; } |
49 void NormalUsage() { ++normaluse_; } | 50 void ScaleUp(ScaleReason) { ++normaluse_; } |
50 | 51 |
51 int overuse_; | 52 int overuse_; |
52 int normaluse_; | 53 int normaluse_; |
53 }; | 54 }; |
54 | 55 |
55 class OveruseFrameDetectorUnderTest : public OveruseFrameDetector { | 56 class OveruseFrameDetectorUnderTest : public OveruseFrameDetector { |
56 public: | 57 public: |
57 OveruseFrameDetectorUnderTest(Clock* clock, | 58 OveruseFrameDetectorUnderTest(Clock* clock, |
58 const CpuOveruseOptions& options, | 59 const CpuOveruseOptions& options, |
59 CpuOveruseObserver* overuse_observer, | 60 ScalingObserverInterface* overuse_observer, |
60 EncodedFrameObserver* encoder_timing, | 61 EncodedFrameObserver* encoder_timing, |
61 CpuOveruseMetricsObserver* metrics_observer) | 62 CpuOveruseMetricsObserver* metrics_observer) |
62 : OveruseFrameDetector(clock, | 63 : OveruseFrameDetector(clock, |
63 options, | 64 options, |
64 overuse_observer, | 65 overuse_observer, |
65 encoder_timing, | 66 encoder_timing, |
66 metrics_observer) {} | 67 metrics_observer) {} |
67 ~OveruseFrameDetectorUnderTest() {} | 68 ~OveruseFrameDetectorUnderTest() {} |
68 | 69 |
69 using OveruseFrameDetector::CheckForOveruse; | 70 using OveruseFrameDetector::CheckForOveruse; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 overuse_detector_->CheckForOveruse(); | 139 overuse_detector_->CheckForOveruse(); |
139 } | 140 } |
140 | 141 |
141 int UsagePercent() { return metrics_.encode_usage_percent; } | 142 int UsagePercent() { return metrics_.encode_usage_percent; } |
142 | 143 |
143 CpuOveruseOptions options_; | 144 CpuOveruseOptions options_; |
144 std::unique_ptr<SimulatedClock> clock_; | 145 std::unique_ptr<SimulatedClock> clock_; |
145 std::unique_ptr<MockCpuOveruseObserver> observer_; | 146 std::unique_ptr<MockCpuOveruseObserver> observer_; |
146 std::unique_ptr<OveruseFrameDetectorUnderTest> overuse_detector_; | 147 std::unique_ptr<OveruseFrameDetectorUnderTest> overuse_detector_; |
147 CpuOveruseMetrics metrics_; | 148 CpuOveruseMetrics metrics_; |
| 149 |
| 150 static const auto reason_ = ScalingObserverInterface::ScaleReason::kCpu; |
148 }; | 151 }; |
149 | 152 |
150 | 153 |
151 // UsagePercent() > high_encode_usage_threshold_percent => overuse. | 154 // UsagePercent() > high_encode_usage_threshold_percent => overuse. |
152 // UsagePercent() < low_encode_usage_threshold_percent => underuse. | 155 // UsagePercent() < low_encode_usage_threshold_percent => underuse. |
153 TEST_F(OveruseFrameDetectorTest, TriggerOveruse) { | 156 TEST_F(OveruseFrameDetectorTest, TriggerOveruse) { |
154 // usage > high => overuse | 157 // usage > high => overuse |
155 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); | 158 EXPECT_CALL(*(observer_.get()), ScaleDown(reason_)).Times(1); |
156 TriggerOveruse(options_.high_threshold_consecutive_count); | 159 TriggerOveruse(options_.high_threshold_consecutive_count); |
157 } | 160 } |
158 | 161 |
159 TEST_F(OveruseFrameDetectorTest, OveruseAndRecover) { | 162 TEST_F(OveruseFrameDetectorTest, OveruseAndRecover) { |
160 // usage > high => overuse | 163 // usage > high => overuse |
161 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); | 164 EXPECT_CALL(*(observer_.get()), ScaleDown(reason_)).Times(1); |
162 TriggerOveruse(options_.high_threshold_consecutive_count); | 165 TriggerOveruse(options_.high_threshold_consecutive_count); |
163 // usage < low => underuse | 166 // usage < low => underuse |
164 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1)); | 167 EXPECT_CALL(*(observer_.get()), ScaleUp(reason_)).Times(testing::AtLeast(1)); |
165 TriggerUnderuse(); | 168 TriggerUnderuse(); |
166 } | 169 } |
167 | 170 |
168 TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithNoObserver) { | 171 TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithNoObserver) { |
169 overuse_detector_.reset(new OveruseFrameDetectorUnderTest( | 172 overuse_detector_.reset(new OveruseFrameDetectorUnderTest( |
170 clock_.get(), options_, nullptr, nullptr, this)); | 173 clock_.get(), options_, nullptr, nullptr, this)); |
171 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0); | 174 EXPECT_CALL(*(observer_.get()), ScaleDown(reason_)).Times(0); |
172 TriggerOveruse(options_.high_threshold_consecutive_count); | 175 TriggerOveruse(options_.high_threshold_consecutive_count); |
173 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); | 176 EXPECT_CALL(*(observer_.get()), ScaleUp(reason_)).Times(0); |
174 TriggerUnderuse(); | 177 TriggerUnderuse(); |
175 } | 178 } |
176 | 179 |
177 TEST_F(OveruseFrameDetectorTest, DoubleOveruseAndRecover) { | 180 TEST_F(OveruseFrameDetectorTest, DoubleOveruseAndRecover) { |
178 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(2); | 181 EXPECT_CALL(*(observer_.get()), ScaleDown(reason_)).Times(2); |
179 TriggerOveruse(options_.high_threshold_consecutive_count); | 182 TriggerOveruse(options_.high_threshold_consecutive_count); |
180 TriggerOveruse(options_.high_threshold_consecutive_count); | 183 TriggerOveruse(options_.high_threshold_consecutive_count); |
181 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1)); | 184 EXPECT_CALL(*(observer_.get()), ScaleUp(reason_)).Times(testing::AtLeast(1)); |
182 TriggerUnderuse(); | 185 TriggerUnderuse(); |
183 } | 186 } |
184 | 187 |
185 TEST_F(OveruseFrameDetectorTest, TriggerUnderuseWithMinProcessCount) { | 188 TEST_F(OveruseFrameDetectorTest, TriggerUnderuseWithMinProcessCount) { |
186 options_.min_process_count = 1; | 189 options_.min_process_count = 1; |
187 CpuOveruseObserverImpl overuse_observer; | 190 CpuOveruseObserverImpl overuse_observer; |
188 overuse_detector_.reset(new OveruseFrameDetectorUnderTest( | 191 overuse_detector_.reset(new OveruseFrameDetectorUnderTest( |
189 clock_.get(), options_, &overuse_observer, nullptr, this)); | 192 clock_.get(), options_, &overuse_observer, nullptr, this)); |
190 InsertAndSendFramesWithInterval( | 193 InsertAndSendFramesWithInterval( |
191 1200, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms); | 194 1200, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms); |
192 overuse_detector_->CheckForOveruse(); | 195 overuse_detector_->CheckForOveruse(); |
193 EXPECT_EQ(0, overuse_observer.normaluse_); | 196 EXPECT_EQ(0, overuse_observer.normaluse_); |
194 clock_->AdvanceTimeMilliseconds(kProcessIntervalMs); | 197 clock_->AdvanceTimeMilliseconds(kProcessIntervalMs); |
195 overuse_detector_->CheckForOveruse(); | 198 overuse_detector_->CheckForOveruse(); |
196 EXPECT_EQ(1, overuse_observer.normaluse_); | 199 EXPECT_EQ(1, overuse_observer.normaluse_); |
197 } | 200 } |
198 | 201 |
199 TEST_F(OveruseFrameDetectorTest, ConstantOveruseGivesNoNormalUsage) { | 202 TEST_F(OveruseFrameDetectorTest, ConstantOveruseGivesNoNormalUsage) { |
200 EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(0); | 203 EXPECT_CALL(*(observer_.get()), ScaleUp(reason_)).Times(0); |
201 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(64); | 204 EXPECT_CALL(*(observer_.get()), ScaleDown(reason_)).Times(64); |
202 for (size_t i = 0; i < 64; ++i) { | 205 for (size_t i = 0; i < 64; ++i) { |
203 TriggerOveruse(options_.high_threshold_consecutive_count); | 206 TriggerOveruse(options_.high_threshold_consecutive_count); |
204 } | 207 } |
205 } | 208 } |
206 | 209 |
207 TEST_F(OveruseFrameDetectorTest, ConsecutiveCountTriggersOveruse) { | 210 TEST_F(OveruseFrameDetectorTest, ConsecutiveCountTriggersOveruse) { |
208 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1); | 211 EXPECT_CALL(*(observer_.get()), ScaleDown(reason_)).Times(1); |
209 options_.high_threshold_consecutive_count = 2; | 212 options_.high_threshold_consecutive_count = 2; |
210 ReinitializeOveruseDetector(); | 213 ReinitializeOveruseDetector(); |
211 TriggerOveruse(2); | 214 TriggerOveruse(2); |
212 } | 215 } |
213 | 216 |
214 TEST_F(OveruseFrameDetectorTest, IncorrectConsecutiveCountTriggersNoOveruse) { | 217 TEST_F(OveruseFrameDetectorTest, IncorrectConsecutiveCountTriggersNoOveruse) { |
215 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(0); | 218 EXPECT_CALL(*(observer_.get()), ScaleDown(reason_)).Times(0); |
216 options_.high_threshold_consecutive_count = 2; | 219 options_.high_threshold_consecutive_count = 2; |
217 ReinitializeOveruseDetector(); | 220 ReinitializeOveruseDetector(); |
218 TriggerOveruse(1); | 221 TriggerOveruse(1); |
219 } | 222 } |
220 | 223 |
221 TEST_F(OveruseFrameDetectorTest, ProcessingUsage) { | 224 TEST_F(OveruseFrameDetectorTest, ProcessingUsage) { |
222 InsertAndSendFramesWithInterval( | 225 InsertAndSendFramesWithInterval( |
223 1000, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms); | 226 1000, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms); |
224 EXPECT_EQ(kProcessTime5ms * 100 / kFrameInterval33ms, UsagePercent()); | 227 EXPECT_EQ(kProcessTime5ms * 100 / kFrameInterval33ms, UsagePercent()); |
225 } | 228 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
271 1, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms); | 274 1, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms); |
272 EXPECT_NE(InitialUsage(), UsagePercent()); | 275 EXPECT_NE(InitialUsage(), UsagePercent()); |
273 } | 276 } |
274 | 277 |
275 TEST_F(OveruseFrameDetectorTest, InitialProcessingUsage) { | 278 TEST_F(OveruseFrameDetectorTest, InitialProcessingUsage) { |
276 ForceUpdate(kWidth, kHeight); | 279 ForceUpdate(kWidth, kHeight); |
277 EXPECT_EQ(InitialUsage(), UsagePercent()); | 280 EXPECT_EQ(InitialUsage(), UsagePercent()); |
278 } | 281 } |
279 | 282 |
280 TEST_F(OveruseFrameDetectorTest, MeasuresMultipleConcurrentSamples) { | 283 TEST_F(OveruseFrameDetectorTest, MeasuresMultipleConcurrentSamples) { |
281 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(testing::AtLeast(1)); | 284 EXPECT_CALL(*(observer_.get()), ScaleDown(reason_)) |
| 285 .Times(testing::AtLeast(1)); |
282 static const int kIntervalMs = 33; | 286 static const int kIntervalMs = 33; |
283 static const size_t kNumFramesEncodingDelay = 3; | 287 static const size_t kNumFramesEncodingDelay = 3; |
284 VideoFrame frame(I420Buffer::Create(kWidth, kHeight), | 288 VideoFrame frame(I420Buffer::Create(kWidth, kHeight), |
285 webrtc::kVideoRotation_0, 0); | 289 webrtc::kVideoRotation_0, 0); |
286 for (size_t i = 0; i < 1000; ++i) { | 290 for (size_t i = 0; i < 1000; ++i) { |
287 // Unique timestamps. | 291 // Unique timestamps. |
288 frame.set_timestamp(static_cast<uint32_t>(i)); | 292 frame.set_timestamp(static_cast<uint32_t>(i)); |
289 overuse_detector_->FrameCaptured(frame, clock_->TimeInMilliseconds()); | 293 overuse_detector_->FrameCaptured(frame, clock_->TimeInMilliseconds()); |
290 clock_->AdvanceTimeMilliseconds(kIntervalMs); | 294 clock_->AdvanceTimeMilliseconds(kIntervalMs); |
291 if (i > kNumFramesEncodingDelay) { | 295 if (i > kNumFramesEncodingDelay) { |
292 overuse_detector_->FrameSent( | 296 overuse_detector_->FrameSent( |
293 static_cast<uint32_t>(i - kNumFramesEncodingDelay), | 297 static_cast<uint32_t>(i - kNumFramesEncodingDelay), |
294 clock_->TimeInMilliseconds()); | 298 clock_->TimeInMilliseconds()); |
295 } | 299 } |
296 overuse_detector_->CheckForOveruse(); | 300 overuse_detector_->CheckForOveruse(); |
297 } | 301 } |
298 } | 302 } |
299 | 303 |
300 TEST_F(OveruseFrameDetectorTest, UpdatesExistingSamples) { | 304 TEST_F(OveruseFrameDetectorTest, UpdatesExistingSamples) { |
301 // >85% encoding time should trigger overuse. | 305 // >85% encoding time should trigger overuse. |
302 EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(testing::AtLeast(1)); | 306 EXPECT_CALL(*(observer_.get()), ScaleDown(reason_)) |
| 307 .Times(testing::AtLeast(1)); |
303 static const int kIntervalMs = 33; | 308 static const int kIntervalMs = 33; |
304 static const int kDelayMs = 30; | 309 static const int kDelayMs = 30; |
305 VideoFrame frame(I420Buffer::Create(kWidth, kHeight), | 310 VideoFrame frame(I420Buffer::Create(kWidth, kHeight), |
306 webrtc::kVideoRotation_0, 0); | 311 webrtc::kVideoRotation_0, 0); |
307 uint32_t timestamp = 0; | 312 uint32_t timestamp = 0; |
308 for (size_t i = 0; i < 1000; ++i) { | 313 for (size_t i = 0; i < 1000; ++i) { |
309 frame.set_timestamp(timestamp); | 314 frame.set_timestamp(timestamp); |
310 overuse_detector_->FrameCaptured(frame, clock_->TimeInMilliseconds()); | 315 overuse_detector_->FrameCaptured(frame, clock_->TimeInMilliseconds()); |
311 // Encode and send first parts almost instantly. | 316 // Encode and send first parts almost instantly. |
312 clock_->AdvanceTimeMilliseconds(1); | 317 clock_->AdvanceTimeMilliseconds(1); |
(...skipping 12 matching lines...) Expand all Loading... |
325 | 330 |
326 rtc::Event event(false, false); | 331 rtc::Event event(false, false); |
327 queue.PostTask([this, &event] { | 332 queue.PostTask([this, &event] { |
328 overuse_detector_->StartCheckForOveruse(); | 333 overuse_detector_->StartCheckForOveruse(); |
329 event.Set(); | 334 event.Set(); |
330 }); | 335 }); |
331 event.Wait(rtc::Event::kForever); | 336 event.Wait(rtc::Event::kForever); |
332 | 337 |
333 // Expect NormalUsage(). When called, stop the |overuse_detector_| and then | 338 // Expect NormalUsage(). When called, stop the |overuse_detector_| and then |
334 // set |event| to end the test. | 339 // set |event| to end the test. |
335 EXPECT_CALL(*(observer_.get()), NormalUsage()) | 340 EXPECT_CALL(*(observer_.get()), ScaleUp(reason_)) |
336 .WillOnce(Invoke([this, &event] { | 341 .WillOnce(InvokeWithoutArgs([this, &event] { |
337 overuse_detector_->StopCheckForOveruse(); | 342 overuse_detector_->StopCheckForOveruse(); |
338 event.Set(); | 343 event.Set(); |
339 })); | 344 })); |
340 | 345 |
341 queue.PostTask([this, &event] { | 346 queue.PostTask([this, &event] { |
342 const int kDelayMs1 = 5; | 347 const int kDelayMs1 = 5; |
343 const int kDelayMs2 = 6; | 348 const int kDelayMs2 = 6; |
344 InsertAndSendFramesWithInterval(1300, kFrameInterval33ms, kWidth, kHeight, | 349 InsertAndSendFramesWithInterval(1300, kFrameInterval33ms, kWidth, kHeight, |
345 kDelayMs1); | 350 kDelayMs1); |
346 InsertAndSendFramesWithInterval(1, kFrameInterval33ms, kWidth, kHeight, | 351 InsertAndSendFramesWithInterval(1, kFrameInterval33ms, kWidth, kHeight, |
347 kDelayMs2); | 352 kDelayMs2); |
348 }); | 353 }); |
349 | 354 |
350 EXPECT_TRUE(event.Wait(10000)); | 355 EXPECT_TRUE(event.Wait(10000)); |
351 } | 356 } |
352 | 357 |
353 } // namespace webrtc | 358 } // namespace webrtc |
OLD | NEW |