blob: 2ba25e6ab5d7e6615647ac968985d166173d91ce [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// 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