1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140

media / base / frame_rate_estimator_unittest.cc [blame]

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/base/frame_rate_estimator.h"

#include <tuple>

#include "testing/gtest/include/gtest/gtest.h"

namespace media {

using FpsPair = std::tuple<int, int>;

class FrameRateEstimatorTest : public testing::TestWithParam<FpsPair> {
 public:
  void ProvideSamples(base::TimeDelta duration, int count) {
    while (count--)
      estimator_.AddSample(duration);
  }

  void ProvideSample(base::TimeDelta duration) {
    estimator_.AddSample(duration);
  }

  int low_fps() const { return std::get<0>(GetParam()); }
  int high_fps() const { return std::get<1>(GetParam()); }

  base::TimeDelta duration(int fps) { return base::Seconds(1.0 / fps); }

  FrameRateEstimator estimator_;
};

TEST_P(FrameRateEstimatorTest, NoEstimateInitially) {
  // Asking for an estimate with no samples is okay, though it shouldn't return
  // an estimate.
  EXPECT_FALSE(estimator_.ComputeFPS());
}

TEST_P(FrameRateEstimatorTest, AverageConvergesThenReset) {
  // Verify that the estimate is provided after the required samples are reached
  // and that Reset() clears it.

  // The initial sample requirement should allow quick convergence.
  EXPECT_EQ(estimator_.GetRequiredSamplesForTesting(),
            estimator_.GetMinSamplesForTesting());

  // Make sure that it doesn't converge before the required sample count.
  ProvideSamples(duration(low_fps()),
                 estimator_.GetRequiredSamplesForTesting() - 1);
  EXPECT_FALSE(estimator_.ComputeFPS());
  ProvideSample(duration(low_fps()));
  EXPECT_EQ(*estimator_.ComputeFPS(), low_fps());

  estimator_.Reset();
  EXPECT_FALSE(estimator_.ComputeFPS());
  ProvideSamples(duration(low_fps()),
                 estimator_.GetRequiredSamplesForTesting() - 1);
  EXPECT_FALSE(estimator_.ComputeFPS());
}

TEST_P(FrameRateEstimatorTest, DurationJitterIsFine) {
  // A little jitter doesn't change anything.
  ProvideSamples(duration(low_fps()),
                 estimator_.GetRequiredSamplesForTesting());

  // Compute a jitter that's not big enough to move it out of its bucket.  We
  // use +1 so it works either above or below (below has more room).  2.0 would
  // be fine ideally, but we make it a bit smaller than that just to prevent
  // floating point weirdness.
  auto jitter = (duration(low_fps()) - duration(low_fps() + 1)) / 2.1;
  for (int i = 0; i < estimator_.GetRequiredSamplesForTesting(); i++) {
    ProvideSample(duration(low_fps()) + jitter);
    EXPECT_EQ(*estimator_.ComputeFPS(), low_fps());
  }

  for (int i = 0; i < estimator_.GetRequiredSamplesForTesting(); i++) {
    ProvideSample(duration(low_fps()) - jitter);
    EXPECT_EQ(*estimator_.ComputeFPS(), low_fps());
  }
}

TEST_P(FrameRateEstimatorTest, AverageDoesntSkew) {
  // Changing frame rates shouldn't skew between them.  It should stop providing
  // estimates temporarily.
  ProvideSamples(duration(low_fps()),
                 estimator_.GetRequiredSamplesForTesting());
  EXPECT_EQ(*estimator_.ComputeFPS(), low_fps());

  ProvideSample(duration(high_fps()));
  EXPECT_FALSE(estimator_.ComputeFPS());
  // We should now require more samples one we destabilized.
  EXPECT_EQ(estimator_.GetRequiredSamplesForTesting(),
            estimator_.GetMaxSamplesForTesting());
  ProvideSamples(duration(high_fps()),
                 estimator_.GetRequiredSamplesForTesting() - 2);
  EXPECT_FALSE(estimator_.ComputeFPS());
  ProvideSample(duration(high_fps()));
  EXPECT_EQ(*estimator_.ComputeFPS(), high_fps());
}

TEST_P(FrameRateEstimatorTest, ResetAllowsFastConvergence) {
  // If we're in slow-convergence mode, Reset() should allow fast convergence.

  // Get into slow convergence mode by providing a non-uniform window.
  ProvideSamples(duration(low_fps()), estimator_.GetMinSamplesForTesting() - 1);
  ProvideSamples(duration(high_fps()), 1);
  EXPECT_EQ(estimator_.GetRequiredSamplesForTesting(),
            estimator_.GetMaxSamplesForTesting());

  // See if Reset() gets us back to fast convergence.
  estimator_.Reset();
  EXPECT_EQ(estimator_.GetRequiredSamplesForTesting(),
            estimator_.GetMinSamplesForTesting());
}

// Instantiate tests for lots of common frame rates.
INSTANTIATE_TEST_SUITE_P(All,
                         FrameRateEstimatorTest,
                         testing::Values(FpsPair(24, 30),
                                         FpsPair(24, 60),
                                         FpsPair(24, 90),
                                         FpsPair(24, 120),
                                         FpsPair(24, 240),

                                         FpsPair(30, 60),
                                         FpsPair(30, 90),
                                         FpsPair(30, 120),
                                         FpsPair(30, 240),

                                         FpsPair(60, 90),
                                         FpsPair(60, 120),
                                         FpsPair(60, 240),

                                         FpsPair(90, 120),
                                         FpsPair(90, 240),

                                         FpsPair(120, 240)));

}  // namespace media