1*103e46e4SHarish Mahendrakar // Copyright (c) 2016 The WebM project authors. All Rights Reserved.
2*103e46e4SHarish Mahendrakar //
3*103e46e4SHarish Mahendrakar // Use of this source code is governed by a BSD-style license
4*103e46e4SHarish Mahendrakar // that can be found in the LICENSE file in the root of the source
5*103e46e4SHarish Mahendrakar // tree. An additional intellectual property rights grant can be found
6*103e46e4SHarish Mahendrakar // in the file PATENTS. All contributing project authors may
7*103e46e4SHarish Mahendrakar // be found in the AUTHORS file in the root of the source tree.
8*103e46e4SHarish Mahendrakar #include "common/vp9_level_stats.h"
9*103e46e4SHarish Mahendrakar
10*103e46e4SHarish Mahendrakar #include <inttypes.h>
11*103e46e4SHarish Mahendrakar
12*103e46e4SHarish Mahendrakar #include <limits>
13*103e46e4SHarish Mahendrakar #include <utility>
14*103e46e4SHarish Mahendrakar
15*103e46e4SHarish Mahendrakar #include "common/webm_constants.h"
16*103e46e4SHarish Mahendrakar
17*103e46e4SHarish Mahendrakar namespace vp9_parser {
18*103e46e4SHarish Mahendrakar
19*103e46e4SHarish Mahendrakar const Vp9LevelRow Vp9LevelStats::Vp9LevelTable[kNumVp9Levels] = {
20*103e46e4SHarish Mahendrakar {LEVEL_1, 829440, 36864, 512, 200, 400, 2, 1, 4, 8},
21*103e46e4SHarish Mahendrakar {LEVEL_1_1, 2764800, 73728, 768, 800, 1000, 2, 1, 4, 8},
22*103e46e4SHarish Mahendrakar {LEVEL_2, 4608000, 122880, 960, 1800, 1500, 2, 1, 4, 8},
23*103e46e4SHarish Mahendrakar {LEVEL_2_1, 9216000, 245760, 1344, 3600, 2800, 2, 2, 4, 8},
24*103e46e4SHarish Mahendrakar {LEVEL_3, 20736000, 552960, 2048, 7200, 6000, 2, 4, 4, 8},
25*103e46e4SHarish Mahendrakar {LEVEL_3_1, 36864000, 983040, 2752, 12000, 10000, 2, 4, 4, 8},
26*103e46e4SHarish Mahendrakar {LEVEL_4, 83558400, 2228224, 4160, 18000, 16000, 4, 4, 4, 8},
27*103e46e4SHarish Mahendrakar {LEVEL_4_1, 160432128, 2228224, 4160, 30000, 18000, 4, 4, 5, 6},
28*103e46e4SHarish Mahendrakar {LEVEL_5, 311951360, 8912896, 8384, 60000, 36000, 6, 8, 6, 4},
29*103e46e4SHarish Mahendrakar {LEVEL_5_1, 588251136, 8912896, 8384, 120000, 46000, 8, 8, 10, 4},
30*103e46e4SHarish Mahendrakar // CPB Size = 0 for levels 5_2 to 6_2
31*103e46e4SHarish Mahendrakar {LEVEL_5_2, 1176502272, 8912896, 8384, 180000, 0, 8, 8, 10, 4},
32*103e46e4SHarish Mahendrakar {LEVEL_6, 1176502272, 35651584, 16832, 180000, 0, 8, 16, 10, 4},
33*103e46e4SHarish Mahendrakar {LEVEL_6_1, 2353004544, 35651584, 16832, 240000, 0, 8, 16, 10, 4},
34*103e46e4SHarish Mahendrakar {LEVEL_6_2, 4706009088, 35651584, 16832, 480000, 0, 8, 16, 10, 4}};
35*103e46e4SHarish Mahendrakar
AddFrame(const Vp9HeaderParser & parser,int64_t time_ns)36*103e46e4SHarish Mahendrakar void Vp9LevelStats::AddFrame(const Vp9HeaderParser& parser, int64_t time_ns) {
37*103e46e4SHarish Mahendrakar ++frames;
38*103e46e4SHarish Mahendrakar if (start_ns_ == -1)
39*103e46e4SHarish Mahendrakar start_ns_ = time_ns;
40*103e46e4SHarish Mahendrakar end_ns_ = time_ns;
41*103e46e4SHarish Mahendrakar
42*103e46e4SHarish Mahendrakar const int width = parser.width();
43*103e46e4SHarish Mahendrakar const int height = parser.height();
44*103e46e4SHarish Mahendrakar const int64_t luma_picture_size = width * height;
45*103e46e4SHarish Mahendrakar const int64_t luma_picture_breadth = (width > height) ? width : height;
46*103e46e4SHarish Mahendrakar if (luma_picture_size > max_luma_picture_size_)
47*103e46e4SHarish Mahendrakar max_luma_picture_size_ = luma_picture_size;
48*103e46e4SHarish Mahendrakar if (luma_picture_breadth > max_luma_picture_breadth_)
49*103e46e4SHarish Mahendrakar max_luma_picture_breadth_ = luma_picture_breadth;
50*103e46e4SHarish Mahendrakar
51*103e46e4SHarish Mahendrakar total_compressed_size_ += parser.frame_size();
52*103e46e4SHarish Mahendrakar
53*103e46e4SHarish Mahendrakar while (!luma_window_.empty() &&
54*103e46e4SHarish Mahendrakar luma_window_.front().first <
55*103e46e4SHarish Mahendrakar (time_ns - (libwebm::kNanosecondsPerSecondi - 1))) {
56*103e46e4SHarish Mahendrakar current_luma_size_ -= luma_window_.front().second;
57*103e46e4SHarish Mahendrakar luma_window_.pop();
58*103e46e4SHarish Mahendrakar }
59*103e46e4SHarish Mahendrakar current_luma_size_ += luma_picture_size;
60*103e46e4SHarish Mahendrakar luma_window_.push(std::make_pair(time_ns, luma_picture_size));
61*103e46e4SHarish Mahendrakar if (current_luma_size_ > max_luma_size_) {
62*103e46e4SHarish Mahendrakar max_luma_size_ = current_luma_size_;
63*103e46e4SHarish Mahendrakar max_luma_end_ns_ = luma_window_.back().first;
64*103e46e4SHarish Mahendrakar }
65*103e46e4SHarish Mahendrakar
66*103e46e4SHarish Mahendrakar // Record CPB stats.
67*103e46e4SHarish Mahendrakar // Remove all frames that are less than window size.
68*103e46e4SHarish Mahendrakar while (cpb_window_.size() > 3) {
69*103e46e4SHarish Mahendrakar current_cpb_size_ -= cpb_window_.front().second;
70*103e46e4SHarish Mahendrakar cpb_window_.pop();
71*103e46e4SHarish Mahendrakar }
72*103e46e4SHarish Mahendrakar cpb_window_.push(std::make_pair(time_ns, parser.frame_size()));
73*103e46e4SHarish Mahendrakar
74*103e46e4SHarish Mahendrakar current_cpb_size_ += parser.frame_size();
75*103e46e4SHarish Mahendrakar if (current_cpb_size_ > max_cpb_size_) {
76*103e46e4SHarish Mahendrakar max_cpb_size_ = current_cpb_size_;
77*103e46e4SHarish Mahendrakar max_cpb_start_ns_ = cpb_window_.front().first;
78*103e46e4SHarish Mahendrakar max_cpb_end_ns_ = cpb_window_.back().first;
79*103e46e4SHarish Mahendrakar }
80*103e46e4SHarish Mahendrakar
81*103e46e4SHarish Mahendrakar if (max_cpb_window_size_ < static_cast<int64_t>(cpb_window_.size())) {
82*103e46e4SHarish Mahendrakar max_cpb_window_size_ = cpb_window_.size();
83*103e46e4SHarish Mahendrakar max_cpb_window_end_ns_ = time_ns;
84*103e46e4SHarish Mahendrakar }
85*103e46e4SHarish Mahendrakar
86*103e46e4SHarish Mahendrakar // Record altref stats.
87*103e46e4SHarish Mahendrakar if (parser.altref()) {
88*103e46e4SHarish Mahendrakar const int delta_altref = frames_since_last_altref;
89*103e46e4SHarish Mahendrakar if (first_altref) {
90*103e46e4SHarish Mahendrakar first_altref = false;
91*103e46e4SHarish Mahendrakar } else if (delta_altref < minimum_altref_distance) {
92*103e46e4SHarish Mahendrakar minimum_altref_distance = delta_altref;
93*103e46e4SHarish Mahendrakar min_altref_end_ns = time_ns;
94*103e46e4SHarish Mahendrakar }
95*103e46e4SHarish Mahendrakar frames_since_last_altref = 0;
96*103e46e4SHarish Mahendrakar } else {
97*103e46e4SHarish Mahendrakar ++frames_since_last_altref;
98*103e46e4SHarish Mahendrakar ++displayed_frames;
99*103e46e4SHarish Mahendrakar // TODO(fgalligan): Add support for other color formats. Currently assuming
100*103e46e4SHarish Mahendrakar // 420.
101*103e46e4SHarish Mahendrakar total_uncompressed_bits_ +=
102*103e46e4SHarish Mahendrakar (luma_picture_size * parser.bit_depth() * 3) / 2;
103*103e46e4SHarish Mahendrakar }
104*103e46e4SHarish Mahendrakar
105*103e46e4SHarish Mahendrakar // Count max reference frames.
106*103e46e4SHarish Mahendrakar if (parser.key() == 1) {
107*103e46e4SHarish Mahendrakar frames_refreshed_ = 0;
108*103e46e4SHarish Mahendrakar } else {
109*103e46e4SHarish Mahendrakar frames_refreshed_ |= parser.refresh_frame_flags();
110*103e46e4SHarish Mahendrakar
111*103e46e4SHarish Mahendrakar int ref_frame_count = frames_refreshed_ & 1;
112*103e46e4SHarish Mahendrakar for (int i = 1; i < kMaxVp9RefFrames; ++i) {
113*103e46e4SHarish Mahendrakar ref_frame_count += (frames_refreshed_ >> i) & 1;
114*103e46e4SHarish Mahendrakar }
115*103e46e4SHarish Mahendrakar
116*103e46e4SHarish Mahendrakar if (ref_frame_count > max_frames_refreshed_)
117*103e46e4SHarish Mahendrakar max_frames_refreshed_ = ref_frame_count;
118*103e46e4SHarish Mahendrakar }
119*103e46e4SHarish Mahendrakar
120*103e46e4SHarish Mahendrakar // Count max tiles.
121*103e46e4SHarish Mahendrakar const int tiles = parser.column_tiles();
122*103e46e4SHarish Mahendrakar if (tiles > max_column_tiles_)
123*103e46e4SHarish Mahendrakar max_column_tiles_ = tiles;
124*103e46e4SHarish Mahendrakar }
125*103e46e4SHarish Mahendrakar
GetLevel() const126*103e46e4SHarish Mahendrakar Vp9Level Vp9LevelStats::GetLevel() const {
127*103e46e4SHarish Mahendrakar const int64_t max_luma_sample_rate = GetMaxLumaSampleRate();
128*103e46e4SHarish Mahendrakar const int64_t max_luma_picture_size = GetMaxLumaPictureSize();
129*103e46e4SHarish Mahendrakar const int64_t max_luma_picture_breadth = GetMaxLumaPictureBreadth();
130*103e46e4SHarish Mahendrakar const double average_bitrate = GetAverageBitRate();
131*103e46e4SHarish Mahendrakar const double max_cpb_size = GetMaxCpbSize();
132*103e46e4SHarish Mahendrakar const double compression_ratio = GetCompressionRatio();
133*103e46e4SHarish Mahendrakar const int max_column_tiles = GetMaxColumnTiles();
134*103e46e4SHarish Mahendrakar const int min_altref_distance = GetMinimumAltrefDistance();
135*103e46e4SHarish Mahendrakar const int max_ref_frames = GetMaxReferenceFrames();
136*103e46e4SHarish Mahendrakar
137*103e46e4SHarish Mahendrakar int level_index = 0;
138*103e46e4SHarish Mahendrakar Vp9Level max_level = LEVEL_UNKNOWN;
139*103e46e4SHarish Mahendrakar const double grace_multiplier =
140*103e46e4SHarish Mahendrakar max_luma_sample_rate_grace_percent_ / 100.0 + 1.0;
141*103e46e4SHarish Mahendrakar for (int i = 0; i < kNumVp9Levels; ++i) {
142*103e46e4SHarish Mahendrakar if (max_luma_sample_rate <=
143*103e46e4SHarish Mahendrakar Vp9LevelTable[i].max_luma_sample_rate * grace_multiplier) {
144*103e46e4SHarish Mahendrakar if (max_level < Vp9LevelTable[i].level) {
145*103e46e4SHarish Mahendrakar max_level = Vp9LevelTable[i].level;
146*103e46e4SHarish Mahendrakar level_index = i;
147*103e46e4SHarish Mahendrakar }
148*103e46e4SHarish Mahendrakar break;
149*103e46e4SHarish Mahendrakar }
150*103e46e4SHarish Mahendrakar }
151*103e46e4SHarish Mahendrakar for (int i = 0; i < kNumVp9Levels; ++i) {
152*103e46e4SHarish Mahendrakar if (max_luma_picture_size <= Vp9LevelTable[i].max_luma_picture_size) {
153*103e46e4SHarish Mahendrakar if (max_level < Vp9LevelTable[i].level) {
154*103e46e4SHarish Mahendrakar max_level = Vp9LevelTable[i].level;
155*103e46e4SHarish Mahendrakar level_index = i;
156*103e46e4SHarish Mahendrakar }
157*103e46e4SHarish Mahendrakar break;
158*103e46e4SHarish Mahendrakar }
159*103e46e4SHarish Mahendrakar }
160*103e46e4SHarish Mahendrakar for (int i = 0; i < kNumVp9Levels; ++i) {
161*103e46e4SHarish Mahendrakar if (max_luma_picture_breadth <= Vp9LevelTable[i].max_luma_picture_breadth) {
162*103e46e4SHarish Mahendrakar if (max_level < Vp9LevelTable[i].level) {
163*103e46e4SHarish Mahendrakar max_level = Vp9LevelTable[i].level;
164*103e46e4SHarish Mahendrakar level_index = i;
165*103e46e4SHarish Mahendrakar }
166*103e46e4SHarish Mahendrakar break;
167*103e46e4SHarish Mahendrakar }
168*103e46e4SHarish Mahendrakar }
169*103e46e4SHarish Mahendrakar for (int i = 0; i < kNumVp9Levels; ++i) {
170*103e46e4SHarish Mahendrakar if (average_bitrate <= Vp9LevelTable[i].average_bitrate) {
171*103e46e4SHarish Mahendrakar if (max_level < Vp9LevelTable[i].level) {
172*103e46e4SHarish Mahendrakar max_level = Vp9LevelTable[i].level;
173*103e46e4SHarish Mahendrakar level_index = i;
174*103e46e4SHarish Mahendrakar }
175*103e46e4SHarish Mahendrakar break;
176*103e46e4SHarish Mahendrakar }
177*103e46e4SHarish Mahendrakar }
178*103e46e4SHarish Mahendrakar for (int i = 0; i < kNumVp9Levels; ++i) {
179*103e46e4SHarish Mahendrakar // Only check CPB size for levels that are defined.
180*103e46e4SHarish Mahendrakar if (Vp9LevelTable[i].max_cpb_size > 0 &&
181*103e46e4SHarish Mahendrakar max_cpb_size <= Vp9LevelTable[i].max_cpb_size) {
182*103e46e4SHarish Mahendrakar if (max_level < Vp9LevelTable[i].level) {
183*103e46e4SHarish Mahendrakar max_level = Vp9LevelTable[i].level;
184*103e46e4SHarish Mahendrakar level_index = i;
185*103e46e4SHarish Mahendrakar }
186*103e46e4SHarish Mahendrakar break;
187*103e46e4SHarish Mahendrakar }
188*103e46e4SHarish Mahendrakar }
189*103e46e4SHarish Mahendrakar for (int i = 0; i < kNumVp9Levels; ++i) {
190*103e46e4SHarish Mahendrakar if (max_column_tiles <= Vp9LevelTable[i].max_tiles) {
191*103e46e4SHarish Mahendrakar if (max_level < Vp9LevelTable[i].level) {
192*103e46e4SHarish Mahendrakar max_level = Vp9LevelTable[i].level;
193*103e46e4SHarish Mahendrakar level_index = i;
194*103e46e4SHarish Mahendrakar }
195*103e46e4SHarish Mahendrakar break;
196*103e46e4SHarish Mahendrakar }
197*103e46e4SHarish Mahendrakar }
198*103e46e4SHarish Mahendrakar
199*103e46e4SHarish Mahendrakar for (int i = 0; i < kNumVp9Levels; ++i) {
200*103e46e4SHarish Mahendrakar if (max_ref_frames <= Vp9LevelTable[i].max_ref_frames) {
201*103e46e4SHarish Mahendrakar if (max_level < Vp9LevelTable[i].level) {
202*103e46e4SHarish Mahendrakar max_level = Vp9LevelTable[i].level;
203*103e46e4SHarish Mahendrakar level_index = i;
204*103e46e4SHarish Mahendrakar }
205*103e46e4SHarish Mahendrakar break;
206*103e46e4SHarish Mahendrakar }
207*103e46e4SHarish Mahendrakar }
208*103e46e4SHarish Mahendrakar
209*103e46e4SHarish Mahendrakar // Check if the current level meets the minimum altref distance requirement.
210*103e46e4SHarish Mahendrakar // If not, set to unknown level as we can't move up a level as the minimum
211*103e46e4SHarish Mahendrakar // altref distance get farther apart and we can't move down a level as we are
212*103e46e4SHarish Mahendrakar // already at the minimum level for all the other requirements.
213*103e46e4SHarish Mahendrakar if (min_altref_distance < Vp9LevelTable[level_index].min_altref_distance)
214*103e46e4SHarish Mahendrakar max_level = LEVEL_UNKNOWN;
215*103e46e4SHarish Mahendrakar
216*103e46e4SHarish Mahendrakar // The minimum compression ratio has the same behavior as minimum altref
217*103e46e4SHarish Mahendrakar // distance.
218*103e46e4SHarish Mahendrakar if (compression_ratio < Vp9LevelTable[level_index].compression_ratio)
219*103e46e4SHarish Mahendrakar max_level = LEVEL_UNKNOWN;
220*103e46e4SHarish Mahendrakar return max_level;
221*103e46e4SHarish Mahendrakar }
222*103e46e4SHarish Mahendrakar
GetMaxLumaSampleRate() const223*103e46e4SHarish Mahendrakar int64_t Vp9LevelStats::GetMaxLumaSampleRate() const { return max_luma_size_; }
224*103e46e4SHarish Mahendrakar
GetMaxLumaPictureSize() const225*103e46e4SHarish Mahendrakar int64_t Vp9LevelStats::GetMaxLumaPictureSize() const {
226*103e46e4SHarish Mahendrakar return max_luma_picture_size_;
227*103e46e4SHarish Mahendrakar }
228*103e46e4SHarish Mahendrakar
GetMaxLumaPictureBreadth() const229*103e46e4SHarish Mahendrakar int64_t Vp9LevelStats::GetMaxLumaPictureBreadth() const {
230*103e46e4SHarish Mahendrakar return max_luma_picture_breadth_;
231*103e46e4SHarish Mahendrakar }
232*103e46e4SHarish Mahendrakar
GetAverageBitRate() const233*103e46e4SHarish Mahendrakar double Vp9LevelStats::GetAverageBitRate() const {
234*103e46e4SHarish Mahendrakar const int64_t frame_duration_ns = end_ns_ - start_ns_;
235*103e46e4SHarish Mahendrakar double duration_seconds =
236*103e46e4SHarish Mahendrakar ((duration_ns_ == -1) ? frame_duration_ns : duration_ns_) /
237*103e46e4SHarish Mahendrakar libwebm::kNanosecondsPerSecond;
238*103e46e4SHarish Mahendrakar if (estimate_last_frame_duration_ &&
239*103e46e4SHarish Mahendrakar (duration_ns_ == -1 || duration_ns_ <= frame_duration_ns)) {
240*103e46e4SHarish Mahendrakar const double sec_per_frame = frame_duration_ns /
241*103e46e4SHarish Mahendrakar libwebm::kNanosecondsPerSecond /
242*103e46e4SHarish Mahendrakar (displayed_frames - 1);
243*103e46e4SHarish Mahendrakar duration_seconds += sec_per_frame;
244*103e46e4SHarish Mahendrakar }
245*103e46e4SHarish Mahendrakar
246*103e46e4SHarish Mahendrakar return total_compressed_size_ / duration_seconds / 125.0;
247*103e46e4SHarish Mahendrakar }
248*103e46e4SHarish Mahendrakar
GetMaxCpbSize() const249*103e46e4SHarish Mahendrakar double Vp9LevelStats::GetMaxCpbSize() const { return max_cpb_size_ / 125.0; }
250*103e46e4SHarish Mahendrakar
GetCompressionRatio() const251*103e46e4SHarish Mahendrakar double Vp9LevelStats::GetCompressionRatio() const {
252*103e46e4SHarish Mahendrakar return total_uncompressed_bits_ /
253*103e46e4SHarish Mahendrakar static_cast<double>(total_compressed_size_ * 8);
254*103e46e4SHarish Mahendrakar }
255*103e46e4SHarish Mahendrakar
GetMaxColumnTiles() const256*103e46e4SHarish Mahendrakar int Vp9LevelStats::GetMaxColumnTiles() const { return max_column_tiles_; }
257*103e46e4SHarish Mahendrakar
GetMinimumAltrefDistance() const258*103e46e4SHarish Mahendrakar int Vp9LevelStats::GetMinimumAltrefDistance() const {
259*103e46e4SHarish Mahendrakar if (minimum_altref_distance != std::numeric_limits<int>::max())
260*103e46e4SHarish Mahendrakar return minimum_altref_distance;
261*103e46e4SHarish Mahendrakar else
262*103e46e4SHarish Mahendrakar return -1;
263*103e46e4SHarish Mahendrakar }
264*103e46e4SHarish Mahendrakar
GetMaxReferenceFrames() const265*103e46e4SHarish Mahendrakar int Vp9LevelStats::GetMaxReferenceFrames() const {
266*103e46e4SHarish Mahendrakar return max_frames_refreshed_;
267*103e46e4SHarish Mahendrakar }
268*103e46e4SHarish Mahendrakar
269*103e46e4SHarish Mahendrakar } // namespace vp9_parser
270