Home | History | Annotate | Download | only in video
      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:
     30   MockCpuOveruseObserver() {}
     31   virtual ~MockCpuOveruseObserver() {}
     32 
     33   MOCK_METHOD0(OveruseDetected, void());
     34   MOCK_METHOD0(NormalUsage, void());
     35 };
     36 
     37 class CpuOveruseObserverImpl : public CpuOveruseObserver {
     38  public:
     39   CpuOveruseObserverImpl() :
     40     overuse_(0),
     41     normaluse_(0) {}
     42   virtual ~CpuOveruseObserverImpl() {}
     43 
     44   void OveruseDetected() { ++overuse_; }
     45   void NormalUsage() { ++normaluse_; }
     46 
     47   int overuse_;
     48   int normaluse_;
     49 };
     50 
     51 class OveruseFrameDetectorTest : public ::testing::Test,
     52                                  public CpuOveruseMetricsObserver {
     53  protected:
     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 
     61   void ReinitializeOveruseDetector() {
     62     overuse_detector_.reset(new OveruseFrameDetector(clock_.get(), options_,
     63                                                      observer_.get(), this));
     64   }
     65 
     66   void CpuOveruseMetricsUpdated(const CpuOveruseMetrics& metrics) override {
     67     metrics_ = metrics;
     68   }
     69 
     70   int InitialUsage() {
     71     return ((options_.low_encode_usage_threshold_percent +
     72              options_.high_encode_usage_threshold_percent) / 2.0f) + 0.5;
     73   }
     74 
     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 
     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 
     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 
    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.
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    185 TEST_F(OveruseFrameDetectorTest, ProcessingUsage) {
    186   InsertAndSendFramesWithInterval(
    187       1000, kFrameInterval33ms, kWidth, kHeight, kProcessTime5ms);
    188   EXPECT_EQ(kProcessTime5ms * 100 / kFrameInterval33ms, UsagePercent());
    189 }
    190 
    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 
    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 
    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 
    228 TEST_F(OveruseFrameDetectorTest, InitialProcessingUsage) {
    229   EXPECT_EQ(InitialUsage(), UsagePercent());
    230 }
    231 
    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 
    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 
    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 
    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 
    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 
    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