blob: 48cf9f9a56dbdca13afe97d61b25bac2f176b218 [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 <array>
namespace media {
// Number of samples we need before we'll trust the estimate. All samples must
// end up in the same bucket, else we won't report an FPS for the window.
// kMaxSamples is the maximum that we'll need, if we think that things are
// unstable. kMinSamples is the minimum that we'll need to establish a
// baseline fps optimistically.
static constexpr int kMaxSamples = 15;
static constexpr int kMinSamples = 3;
// Size (in FPS) of our buckets, which take on integral multiples of
// |BucketSize|. Observed frame rates are rounded to the nearest bucket, so
// that 1.75 and 1.25 might both end up in bucket 2.
static constexpr int BucketSize = 1;
namespace {
// Convert |duration| into an FPS bucket.
int ToBucket(base::TimeDelta duration) {
return static_cast<int>(((1.0 / duration.InSecondsF()) + (BucketSize / 2.0)) /
BucketSize) *
BucketSize;
}
} // namespace
FrameRateEstimator::FrameRateEstimator()
: duration_(kMaxSamples), required_samples_(kMinSamples) {}
FrameRateEstimator::~FrameRateEstimator() = default;
void FrameRateEstimator::AddSample(base::TimeDelta frame_duration) {
duration_.AddSample(frame_duration);
// See if the duration averages have enough samples. If not, then we can't
// do anything else yet.
if (duration_.count() < required_samples_)
return;
// Make sure that the entire window is in the same bucket.
auto extremes = duration_.GetMinAndMax();
// See if the current sample is too far from the bucketed average.
int bucketed_fps_min = ToBucket(extremes.first);
int bucketed_fps_max = ToBucket(extremes.second);
if (bucketed_fps_min != bucketed_fps_max) {
// There's no current bucket until the entire window agrees. Use the
// maximum window size since we don't like disagreement.
most_recent_bucket_.reset();
required_samples_ = kMaxSamples;
return;
}
most_recent_bucket_ = bucketed_fps_min;
}
absl::optional<int> FrameRateEstimator::ComputeFPS() {
return most_recent_bucket_;
}
void FrameRateEstimator::Reset() {
duration_.Reset();
most_recent_bucket_.reset();
required_samples_ = kMinSamples;
}
int FrameRateEstimator::GetRequiredSamplesForTesting() const {
return required_samples_;
}
int FrameRateEstimator::GetMinSamplesForTesting() const {
return kMinSamples;
}
int FrameRateEstimator::GetMaxSamplesForTesting() const {
return kMaxSamples;
}
} // namespace media