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
media / base / frame_rate_estimator.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 <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()
: min_max_duration_(kMaxSamples), required_samples_(kMinSamples) {}
FrameRateEstimator::~FrameRateEstimator() = default;
void FrameRateEstimator::AddSample(base::TimeDelta frame_duration) {
min_max_duration_.AddSample(frame_duration);
// See if the duration averages have enough samples. If not, then we can't
// do anything else yet.
if (min_max_duration_.Count() <
static_cast<unsigned int>(required_samples_)) {
return;
}
// Make sure that the entire window is in the same bucket.
int bucketed_fps_min = ToBucket(min_max_duration_.Min());
int bucketed_fps_max = ToBucket(min_max_duration_.Max());
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;
}
std::optional<int> FrameRateEstimator::ComputeFPS() {
return most_recent_bucket_;
}
void FrameRateEstimator::Reset() {
min_max_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