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
media / capabilities / bucket_utility.cc [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif
#include "media/capabilities/bucket_utility.h"
#include <algorithm>
#include <cmath>
#include <iterator>
#include "base/check_op.h"
namespace {
// TODO(chcunningham): Find some authoritative list of frame rates.
// Framerates in this list go way beyond typical values to account for changes
// to playback rate.
const int kFrameRateBuckets[] = {5, 10, 20, 25, 30, 40, 50, 60,
70, 80, 90, 100, 120, 150, 200, 250,
300, 350, 400, 450, 500, 550, 600, 650,
700, 750, 800, 850, 900, 950, 1000, 1500};
// A mix of width and height dimensions for common and not-so-common resolutions
// spanning 50p -> 12K.
// TODO(chcunningham): Ponder these a bit more.
const int kSizeBuckets[] = {
50, 100, 144, 240, 256, 280, 360, 426, 480, 640, 720,
854, 960, 1080, 1280, 1440, 1920, 2160, 2560, 2880, 3160, 3840,
4128, 4320, 5120, 6144, 7360, 7680, 8000, 9000, 10000, 11000, 11520};
// Pixel buckets that are used to quantize the resolution to limit the amount of
// information that is stored and exposed through the API. The pixel size
// indices are used for logging, the pixel size buckets can therefore not be
// changed unless the corresponding logging code is updated.
constexpr int kWebrtcPixelsBuckets[] = {1280 * 720, 1920 * 1080, 2560 * 1440,
3840 * 2160};
// The boundaries between buckets are calculated as the point between the two
// buckets.
constexpr int kWebrtcPixelsBoundaries[] = {
(kWebrtcPixelsBuckets[0] + kWebrtcPixelsBuckets[1]) / 2,
(kWebrtcPixelsBuckets[1] + kWebrtcPixelsBuckets[2]) / 2,
(kWebrtcPixelsBuckets[2] + kWebrtcPixelsBuckets[3]) / 2};
// Static assert to make sure that `kWebrtcPixelsBoundaries[]` is updated if new
// pixel sizes are added to kWebrtcPixelsBuckets[]`.
static_assert(std::size(kWebrtcPixelsBoundaries) + 1 ==
std::size(kWebrtcPixelsBuckets));
} // namespace
namespace media {
gfx::Size GetSizeBucket(const gfx::Size& raw_size) {
// If either dimension is less than 75% of the min size bucket, return an
// empty size. Empty |natural_size_| will signal ShouldBeReporting() to return
// false.
const double kMinSizeBucketPercent = .75;
if (raw_size.width() < kMinSizeBucketPercent * kSizeBuckets[0] ||
raw_size.height() < kMinSizeBucketPercent * kSizeBuckets[0]) {
return gfx::Size();
}
// Round width and height to first bucket >= |raw_size| dimensions. See
// explanation in header file.
const int* width_bound = std::lower_bound(
std::begin(kSizeBuckets), std::end(kSizeBuckets), raw_size.width());
const int* height_bound = std::lower_bound(
std::begin(kSizeBuckets), std::end(kSizeBuckets), raw_size.height());
// If no bucket is larger than the raw dimension, just use the last bucket.
if (width_bound == std::end(kSizeBuckets))
--width_bound;
if (height_bound == std::end(kSizeBuckets))
--height_bound;
return gfx::Size(*width_bound, *height_bound);
}
int GetFpsBucket(double raw_fps) {
int rounded_fps = std::round(raw_fps);
// Find the first bucket that is strictly > than |rounded_fps|.
const int* upper_bound =
std::upper_bound(std::begin(kFrameRateBuckets),
std::end(kFrameRateBuckets), std::round(rounded_fps));
// If no bucket is larger than |rounded_fps|, just used the last bucket;
if (upper_bound == std::end(kFrameRateBuckets))
return *(upper_bound - 1);
// Return early if its the first bucket.
if (upper_bound == std::begin(kFrameRateBuckets))
return *upper_bound;
int higher_bucket = *upper_bound;
int previous_bucket = *(upper_bound - 1);
if (std::abs(previous_bucket - rounded_fps) <
std::abs(higher_bucket - rounded_fps)) {
return previous_bucket;
}
return higher_bucket;
}
int GetWebrtcPixelsBucket(int pixels) {
return kWebrtcPixelsBuckets[GetWebrtcPixelsBucketIndex(pixels)];
}
int GetWebrtcPixelsBucketIndex(int pixels) {
const int* pixels_bucket_it =
std::lower_bound(std::begin(kWebrtcPixelsBoundaries),
std::end(kWebrtcPixelsBoundaries), pixels);
// The output from std::lower_bound is in the range [begin, end], hence the
// subtraction below is well defined.
int pixels_bucket_index =
std::distance(std::begin(kWebrtcPixelsBoundaries), pixels_bucket_it);
DCHECK_GE(pixels_bucket_index, 0);
DCHECK_LT(pixels_bucket_index,
static_cast<int>(std::size(kWebrtcPixelsBuckets)));
return pixels_bucket_index;
}
} // namespace media