| 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 |