xref: /aosp_15_r20/external/libaom/av1/encoder/level.c (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker  * Copyright (c) 2019, Alliance for Open Media. All rights reserved.
3*77c1e3ccSAndroid Build Coastguard Worker  *
4*77c1e3ccSAndroid Build Coastguard Worker  * This source code is subject to the terms of the BSD 2 Clause License and
5*77c1e3ccSAndroid Build Coastguard Worker  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6*77c1e3ccSAndroid Build Coastguard Worker  * was not distributed with this source code in the LICENSE file, you can
7*77c1e3ccSAndroid Build Coastguard Worker  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8*77c1e3ccSAndroid Build Coastguard Worker  * Media Patent License 1.0 was not distributed with this source code in the
9*77c1e3ccSAndroid Build Coastguard Worker  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10*77c1e3ccSAndroid Build Coastguard Worker  */
11*77c1e3ccSAndroid Build Coastguard Worker 
12*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/encoder.h"
13*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/level.h"
14*77c1e3ccSAndroid Build Coastguard Worker 
15*77c1e3ccSAndroid Build Coastguard Worker #define UNDEFINED_LEVEL                                                 \
16*77c1e3ccSAndroid Build Coastguard Worker   {                                                                     \
17*77c1e3ccSAndroid Build Coastguard Worker     .level = SEQ_LEVEL_MAX, .max_picture_size = 0, .max_h_size = 0,     \
18*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 0, .max_display_rate = 0, .max_decode_rate = 0,       \
19*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 0, .main_mbps = 0, .high_mbps = 0, .main_cr = 0, \
20*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 0, .max_tiles = 0, .max_tile_cols = 0                    \
21*77c1e3ccSAndroid Build Coastguard Worker   }
22*77c1e3ccSAndroid Build Coastguard Worker 
23*77c1e3ccSAndroid Build Coastguard Worker static const AV1LevelSpec av1_level_defs[SEQ_LEVELS] = {
24*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_2_0,
25*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 147456,
26*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 2048,
27*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 1152,
28*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 4423680L,
29*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 5529600L,
30*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 150,
31*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 1.5,
32*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 0,
33*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 2.0,
34*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 0,
35*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 8,
36*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 4 },
37*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_2_1,
38*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 278784,
39*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 2816,
40*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 1584,
41*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 8363520L,
42*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 10454400L,
43*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 150,
44*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 3.0,
45*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 0,
46*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 2.0,
47*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 0,
48*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 8,
49*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 4 },
50*77c1e3ccSAndroid Build Coastguard Worker   UNDEFINED_LEVEL,
51*77c1e3ccSAndroid Build Coastguard Worker   UNDEFINED_LEVEL,
52*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_3_0,
53*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 665856,
54*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 4352,
55*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 2448,
56*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 19975680L,
57*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 24969600L,
58*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 150,
59*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 6.0,
60*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 0,
61*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 2.0,
62*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 0,
63*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 16,
64*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 6 },
65*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_3_1,
66*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 1065024,
67*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 5504,
68*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 3096,
69*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 31950720L,
70*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 39938400L,
71*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 150,
72*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 10.0,
73*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 0,
74*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 2.0,
75*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 0,
76*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 16,
77*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 6 },
78*77c1e3ccSAndroid Build Coastguard Worker   UNDEFINED_LEVEL,
79*77c1e3ccSAndroid Build Coastguard Worker   UNDEFINED_LEVEL,
80*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_4_0,
81*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 2359296,
82*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 6144,
83*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 3456,
84*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 70778880L,
85*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 77856768L,
86*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
87*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 12.0,
88*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 30.0,
89*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 4.0,
90*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
91*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 32,
92*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 8 },
93*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_4_1,
94*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 2359296,
95*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 6144,
96*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 3456,
97*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 141557760L,
98*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 155713536L,
99*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
100*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 20.0,
101*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 50.0,
102*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 4.0,
103*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
104*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 32,
105*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 8 },
106*77c1e3ccSAndroid Build Coastguard Worker   UNDEFINED_LEVEL,
107*77c1e3ccSAndroid Build Coastguard Worker   UNDEFINED_LEVEL,
108*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_5_0,
109*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 8912896,
110*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 8192,
111*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 4352,
112*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 267386880L,
113*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 273715200L,
114*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
115*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 30.0,
116*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 100.0,
117*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 6.0,
118*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
119*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 64,
120*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 8 },
121*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_5_1,
122*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 8912896,
123*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 8192,
124*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 4352,
125*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 534773760L,
126*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 547430400L,
127*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
128*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 40.0,
129*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 160.0,
130*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
131*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
132*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 64,
133*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 8 },
134*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_5_2,
135*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 8912896,
136*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 8192,
137*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 4352,
138*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 1069547520L,
139*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 1094860800L,
140*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
141*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 60.0,
142*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 240.0,
143*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
144*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
145*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 64,
146*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 8 },
147*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_5_3,
148*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 8912896,
149*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 8192,
150*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 4352,
151*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 1069547520L,
152*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 1176502272L,
153*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
154*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 60.0,
155*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 240.0,
156*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
157*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
158*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 64,
159*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 8 },
160*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_6_0,
161*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 35651584,
162*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 16384,
163*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 8704,
164*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 1069547520L,
165*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 1176502272L,
166*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
167*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 60.0,
168*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 240.0,
169*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
170*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
171*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 128,
172*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 16 },
173*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_6_1,
174*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 35651584,
175*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 16384,
176*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 8704,
177*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 2139095040L,
178*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 2189721600L,
179*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
180*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 100.0,
181*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 480.0,
182*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
183*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
184*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 128,
185*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 16 },
186*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_6_2,
187*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 35651584,
188*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 16384,
189*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 8704,
190*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 4278190080L,
191*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 4379443200L,
192*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
193*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 160.0,
194*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 800.0,
195*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
196*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
197*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 128,
198*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 16 },
199*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_6_3,
200*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 35651584,
201*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 16384,
202*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 8704,
203*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 4278190080L,
204*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 4706009088L,
205*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
206*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 160.0,
207*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 800.0,
208*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
209*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
210*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 128,
211*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 16 },
212*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_CWG_C013
213*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_7_0,
214*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 142606336,
215*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 32768,
216*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 17408,
217*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 4278190080L,
218*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 4706009088L,
219*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
220*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 160.0,
221*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 800.0,
222*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
223*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
224*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 256,
225*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 32 },
226*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_7_1,
227*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 142606336,
228*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 32768,
229*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 17408,
230*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 8556380160L,
231*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 8758886400L,
232*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
233*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 200.0,
234*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 960.0,
235*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
236*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
237*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 256,
238*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 32 },
239*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_7_2,
240*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 142606336,
241*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 32768,
242*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 17408,
243*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 17112760320L,
244*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 17517772800L,
245*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
246*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 320.0,
247*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 1600.0,
248*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
249*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
250*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 256,
251*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 32 },
252*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_7_3,
253*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 142606336,
254*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 32768,
255*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 17408,
256*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 17112760320L,
257*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 18824036352L,
258*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
259*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 320.0,
260*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 1600.0,
261*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
262*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
263*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 256,
264*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 32 },
265*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_8_0,
266*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 530841600,
267*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 65536,
268*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 34816,
269*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 17112760320L,
270*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 18824036352L,
271*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
272*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 320.0,
273*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 1600.0,
274*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
275*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
276*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 512,
277*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 64 },
278*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_8_1,
279*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 530841600,
280*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 65536,
281*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 34816,
282*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 34225520640L,
283*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 34910031052L,
284*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
285*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 400.0,
286*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 1920.0,
287*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
288*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
289*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 512,
290*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 64 },
291*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_8_2,
292*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 530841600,
293*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 65536,
294*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 34816,
295*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 68451041280L,
296*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 69820062105L,
297*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
298*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 640.0,
299*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 3200.0,
300*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
301*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
302*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 512,
303*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 64 },
304*77c1e3ccSAndroid Build Coastguard Worker   { .level = SEQ_LEVEL_8_3,
305*77c1e3ccSAndroid Build Coastguard Worker     .max_picture_size = 530841600,
306*77c1e3ccSAndroid Build Coastguard Worker     .max_h_size = 65536,
307*77c1e3ccSAndroid Build Coastguard Worker     .max_v_size = 34816,
308*77c1e3ccSAndroid Build Coastguard Worker     .max_display_rate = 68451041280L,
309*77c1e3ccSAndroid Build Coastguard Worker     .max_decode_rate = 75296145408L,
310*77c1e3ccSAndroid Build Coastguard Worker     .max_header_rate = 300,
311*77c1e3ccSAndroid Build Coastguard Worker     .main_mbps = 640.0,
312*77c1e3ccSAndroid Build Coastguard Worker     .high_mbps = 3200.0,
313*77c1e3ccSAndroid Build Coastguard Worker     .main_cr = 8.0,
314*77c1e3ccSAndroid Build Coastguard Worker     .high_cr = 4.0,
315*77c1e3ccSAndroid Build Coastguard Worker     .max_tiles = 512,
316*77c1e3ccSAndroid Build Coastguard Worker     .max_tile_cols = 64 },
317*77c1e3ccSAndroid Build Coastguard Worker #else   // !CONFIG_CWG_C013
318*77c1e3ccSAndroid Build Coastguard Worker   UNDEFINED_LEVEL,
319*77c1e3ccSAndroid Build Coastguard Worker   UNDEFINED_LEVEL,
320*77c1e3ccSAndroid Build Coastguard Worker   UNDEFINED_LEVEL,
321*77c1e3ccSAndroid Build Coastguard Worker   UNDEFINED_LEVEL,
322*77c1e3ccSAndroid Build Coastguard Worker   UNDEFINED_LEVEL,
323*77c1e3ccSAndroid Build Coastguard Worker   UNDEFINED_LEVEL,
324*77c1e3ccSAndroid Build Coastguard Worker   UNDEFINED_LEVEL,
325*77c1e3ccSAndroid Build Coastguard Worker   UNDEFINED_LEVEL,
326*77c1e3ccSAndroid Build Coastguard Worker #endif  // CONFIG_CWG_C013
327*77c1e3ccSAndroid Build Coastguard Worker };
328*77c1e3ccSAndroid Build Coastguard Worker 
329*77c1e3ccSAndroid Build Coastguard Worker typedef enum {
330*77c1e3ccSAndroid Build Coastguard Worker   LUMA_PIC_SIZE_TOO_LARGE,
331*77c1e3ccSAndroid Build Coastguard Worker   LUMA_PIC_H_SIZE_TOO_LARGE,
332*77c1e3ccSAndroid Build Coastguard Worker   LUMA_PIC_V_SIZE_TOO_LARGE,
333*77c1e3ccSAndroid Build Coastguard Worker   LUMA_PIC_H_SIZE_TOO_SMALL,
334*77c1e3ccSAndroid Build Coastguard Worker   LUMA_PIC_V_SIZE_TOO_SMALL,
335*77c1e3ccSAndroid Build Coastguard Worker   TOO_MANY_TILE_COLUMNS,
336*77c1e3ccSAndroid Build Coastguard Worker   TOO_MANY_TILES,
337*77c1e3ccSAndroid Build Coastguard Worker   TILE_RATE_TOO_HIGH,
338*77c1e3ccSAndroid Build Coastguard Worker   TILE_TOO_LARGE,
339*77c1e3ccSAndroid Build Coastguard Worker   SUPERRES_TILE_WIDTH_TOO_LARGE,
340*77c1e3ccSAndroid Build Coastguard Worker   CROPPED_TILE_WIDTH_TOO_SMALL,
341*77c1e3ccSAndroid Build Coastguard Worker   CROPPED_TILE_HEIGHT_TOO_SMALL,
342*77c1e3ccSAndroid Build Coastguard Worker   TILE_WIDTH_INVALID,
343*77c1e3ccSAndroid Build Coastguard Worker   FRAME_HEADER_RATE_TOO_HIGH,
344*77c1e3ccSAndroid Build Coastguard Worker   DISPLAY_RATE_TOO_HIGH,
345*77c1e3ccSAndroid Build Coastguard Worker   DECODE_RATE_TOO_HIGH,
346*77c1e3ccSAndroid Build Coastguard Worker   CR_TOO_SMALL,
347*77c1e3ccSAndroid Build Coastguard Worker   TILE_SIZE_HEADER_RATE_TOO_HIGH,
348*77c1e3ccSAndroid Build Coastguard Worker   BITRATE_TOO_HIGH,
349*77c1e3ccSAndroid Build Coastguard Worker   DECODER_MODEL_FAIL,
350*77c1e3ccSAndroid Build Coastguard Worker 
351*77c1e3ccSAndroid Build Coastguard Worker   TARGET_LEVEL_FAIL_IDS,
352*77c1e3ccSAndroid Build Coastguard Worker   TARGET_LEVEL_OK,
353*77c1e3ccSAndroid Build Coastguard Worker } TARGET_LEVEL_FAIL_ID;
354*77c1e3ccSAndroid Build Coastguard Worker 
355*77c1e3ccSAndroid Build Coastguard Worker static const char *level_fail_messages[TARGET_LEVEL_FAIL_IDS] = {
356*77c1e3ccSAndroid Build Coastguard Worker   "The picture size is too large.",
357*77c1e3ccSAndroid Build Coastguard Worker   "The picture width is too large.",
358*77c1e3ccSAndroid Build Coastguard Worker   "The picture height is too large.",
359*77c1e3ccSAndroid Build Coastguard Worker   "The picture width is too small.",
360*77c1e3ccSAndroid Build Coastguard Worker   "The picture height is too small.",
361*77c1e3ccSAndroid Build Coastguard Worker   "Too many tile columns are used.",
362*77c1e3ccSAndroid Build Coastguard Worker   "Too many tiles are used.",
363*77c1e3ccSAndroid Build Coastguard Worker   "The tile rate is too high.",
364*77c1e3ccSAndroid Build Coastguard Worker   "The tile size is too large.",
365*77c1e3ccSAndroid Build Coastguard Worker   "The superres tile width is too large.",
366*77c1e3ccSAndroid Build Coastguard Worker   "The cropped tile width is less than 8.",
367*77c1e3ccSAndroid Build Coastguard Worker   "The cropped tile height is less than 8.",
368*77c1e3ccSAndroid Build Coastguard Worker   "The tile width is invalid.",
369*77c1e3ccSAndroid Build Coastguard Worker   "The frame header rate is too high.",
370*77c1e3ccSAndroid Build Coastguard Worker   "The display luma sample rate is too high.",
371*77c1e3ccSAndroid Build Coastguard Worker   "The decoded luma sample rate is too high.",
372*77c1e3ccSAndroid Build Coastguard Worker   "The compression ratio is too small.",
373*77c1e3ccSAndroid Build Coastguard Worker   "The product of max tile size and header rate is too high.",
374*77c1e3ccSAndroid Build Coastguard Worker   "The bitrate is too high.",
375*77c1e3ccSAndroid Build Coastguard Worker   "The decoder model fails.",
376*77c1e3ccSAndroid Build Coastguard Worker };
377*77c1e3ccSAndroid Build Coastguard Worker 
get_max_bitrate(const AV1LevelSpec * const level_spec,int tier,BITSTREAM_PROFILE profile)378*77c1e3ccSAndroid Build Coastguard Worker static double get_max_bitrate(const AV1LevelSpec *const level_spec, int tier,
379*77c1e3ccSAndroid Build Coastguard Worker                               BITSTREAM_PROFILE profile) {
380*77c1e3ccSAndroid Build Coastguard Worker   if (level_spec->level < SEQ_LEVEL_4_0) tier = 0;
381*77c1e3ccSAndroid Build Coastguard Worker   const double bitrate_basis =
382*77c1e3ccSAndroid Build Coastguard Worker       (tier ? level_spec->high_mbps : level_spec->main_mbps) * 1e6;
383*77c1e3ccSAndroid Build Coastguard Worker   const double bitrate_profile_factor =
384*77c1e3ccSAndroid Build Coastguard Worker       profile == PROFILE_0 ? 1.0 : (profile == PROFILE_1 ? 2.0 : 3.0);
385*77c1e3ccSAndroid Build Coastguard Worker   return bitrate_basis * bitrate_profile_factor;
386*77c1e3ccSAndroid Build Coastguard Worker }
387*77c1e3ccSAndroid Build Coastguard Worker 
av1_get_max_bitrate_for_level(AV1_LEVEL level_index,int tier,BITSTREAM_PROFILE profile)388*77c1e3ccSAndroid Build Coastguard Worker double av1_get_max_bitrate_for_level(AV1_LEVEL level_index, int tier,
389*77c1e3ccSAndroid Build Coastguard Worker                                      BITSTREAM_PROFILE profile) {
390*77c1e3ccSAndroid Build Coastguard Worker   assert(is_valid_seq_level_idx(level_index));
391*77c1e3ccSAndroid Build Coastguard Worker   return get_max_bitrate(&av1_level_defs[level_index], tier, profile);
392*77c1e3ccSAndroid Build Coastguard Worker }
393*77c1e3ccSAndroid Build Coastguard Worker 
av1_get_max_tiles_for_level(AV1_LEVEL level_index,int * const max_tiles,int * const max_tile_cols)394*77c1e3ccSAndroid Build Coastguard Worker void av1_get_max_tiles_for_level(AV1_LEVEL level_index, int *const max_tiles,
395*77c1e3ccSAndroid Build Coastguard Worker                                  int *const max_tile_cols) {
396*77c1e3ccSAndroid Build Coastguard Worker   assert(is_valid_seq_level_idx(level_index));
397*77c1e3ccSAndroid Build Coastguard Worker   const AV1LevelSpec *const level_spec = &av1_level_defs[level_index];
398*77c1e3ccSAndroid Build Coastguard Worker   *max_tiles = level_spec->max_tiles;
399*77c1e3ccSAndroid Build Coastguard Worker   *max_tile_cols = level_spec->max_tile_cols;
400*77c1e3ccSAndroid Build Coastguard Worker }
401*77c1e3ccSAndroid Build Coastguard Worker 
402*77c1e3ccSAndroid Build Coastguard Worker // We assume time t to be valid if and only if t >= 0.0.
403*77c1e3ccSAndroid Build Coastguard Worker // So INVALID_TIME can be defined as anything less than 0.
404*77c1e3ccSAndroid Build Coastguard Worker #define INVALID_TIME (-1.0)
405*77c1e3ccSAndroid Build Coastguard Worker 
406*77c1e3ccSAndroid Build Coastguard Worker // This corresponds to "free_buffer" in the spec.
release_buffer(DECODER_MODEL * const decoder_model,int idx)407*77c1e3ccSAndroid Build Coastguard Worker static void release_buffer(DECODER_MODEL *const decoder_model, int idx) {
408*77c1e3ccSAndroid Build Coastguard Worker   assert(idx >= 0 && idx < BUFFER_POOL_MAX_SIZE);
409*77c1e3ccSAndroid Build Coastguard Worker   FRAME_BUFFER *const this_buffer = &decoder_model->frame_buffer_pool[idx];
410*77c1e3ccSAndroid Build Coastguard Worker   this_buffer->decoder_ref_count = 0;
411*77c1e3ccSAndroid Build Coastguard Worker   this_buffer->player_ref_count = 0;
412*77c1e3ccSAndroid Build Coastguard Worker   this_buffer->display_index = -1;
413*77c1e3ccSAndroid Build Coastguard Worker   this_buffer->presentation_time = INVALID_TIME;
414*77c1e3ccSAndroid Build Coastguard Worker }
415*77c1e3ccSAndroid Build Coastguard Worker 
initialize_buffer_pool(DECODER_MODEL * const decoder_model)416*77c1e3ccSAndroid Build Coastguard Worker static void initialize_buffer_pool(DECODER_MODEL *const decoder_model) {
417*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < BUFFER_POOL_MAX_SIZE; ++i) {
418*77c1e3ccSAndroid Build Coastguard Worker     release_buffer(decoder_model, i);
419*77c1e3ccSAndroid Build Coastguard Worker   }
420*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < REF_FRAMES; ++i) {
421*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->vbi[i] = -1;
422*77c1e3ccSAndroid Build Coastguard Worker   }
423*77c1e3ccSAndroid Build Coastguard Worker }
424*77c1e3ccSAndroid Build Coastguard Worker 
get_free_buffer(DECODER_MODEL * const decoder_model)425*77c1e3ccSAndroid Build Coastguard Worker static int get_free_buffer(DECODER_MODEL *const decoder_model) {
426*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < BUFFER_POOL_MAX_SIZE; ++i) {
427*77c1e3ccSAndroid Build Coastguard Worker     const FRAME_BUFFER *const this_buffer =
428*77c1e3ccSAndroid Build Coastguard Worker         &decoder_model->frame_buffer_pool[i];
429*77c1e3ccSAndroid Build Coastguard Worker     if (this_buffer->decoder_ref_count == 0 &&
430*77c1e3ccSAndroid Build Coastguard Worker         this_buffer->player_ref_count == 0)
431*77c1e3ccSAndroid Build Coastguard Worker       return i;
432*77c1e3ccSAndroid Build Coastguard Worker   }
433*77c1e3ccSAndroid Build Coastguard Worker   return -1;
434*77c1e3ccSAndroid Build Coastguard Worker }
435*77c1e3ccSAndroid Build Coastguard Worker 
update_ref_buffers(DECODER_MODEL * const decoder_model,int idx,int refresh_frame_flags)436*77c1e3ccSAndroid Build Coastguard Worker static void update_ref_buffers(DECODER_MODEL *const decoder_model, int idx,
437*77c1e3ccSAndroid Build Coastguard Worker                                int refresh_frame_flags) {
438*77c1e3ccSAndroid Build Coastguard Worker   FRAME_BUFFER *const this_buffer = &decoder_model->frame_buffer_pool[idx];
439*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < REF_FRAMES; ++i) {
440*77c1e3ccSAndroid Build Coastguard Worker     if (refresh_frame_flags & (1 << i)) {
441*77c1e3ccSAndroid Build Coastguard Worker       const int pre_idx = decoder_model->vbi[i];
442*77c1e3ccSAndroid Build Coastguard Worker       if (pre_idx != -1) {
443*77c1e3ccSAndroid Build Coastguard Worker         --decoder_model->frame_buffer_pool[pre_idx].decoder_ref_count;
444*77c1e3ccSAndroid Build Coastguard Worker       }
445*77c1e3ccSAndroid Build Coastguard Worker       decoder_model->vbi[i] = idx;
446*77c1e3ccSAndroid Build Coastguard Worker       ++this_buffer->decoder_ref_count;
447*77c1e3ccSAndroid Build Coastguard Worker     }
448*77c1e3ccSAndroid Build Coastguard Worker   }
449*77c1e3ccSAndroid Build Coastguard Worker }
450*77c1e3ccSAndroid Build Coastguard Worker 
451*77c1e3ccSAndroid Build Coastguard Worker // The time (in seconds) required to decode a frame.
time_to_decode_frame(const AV1_COMMON * const cm,int64_t max_decode_rate)452*77c1e3ccSAndroid Build Coastguard Worker static double time_to_decode_frame(const AV1_COMMON *const cm,
453*77c1e3ccSAndroid Build Coastguard Worker                                    int64_t max_decode_rate) {
454*77c1e3ccSAndroid Build Coastguard Worker   if (cm->show_existing_frame) return 0.0;
455*77c1e3ccSAndroid Build Coastguard Worker 
456*77c1e3ccSAndroid Build Coastguard Worker   const FRAME_TYPE frame_type = cm->current_frame.frame_type;
457*77c1e3ccSAndroid Build Coastguard Worker   int luma_samples = 0;
458*77c1e3ccSAndroid Build Coastguard Worker   if (frame_type == KEY_FRAME || frame_type == INTRA_ONLY_FRAME) {
459*77c1e3ccSAndroid Build Coastguard Worker     luma_samples = cm->superres_upscaled_width * cm->height;
460*77c1e3ccSAndroid Build Coastguard Worker   } else {
461*77c1e3ccSAndroid Build Coastguard Worker     const int spatial_layer_dimensions_present_flag = 0;
462*77c1e3ccSAndroid Build Coastguard Worker     if (spatial_layer_dimensions_present_flag) {
463*77c1e3ccSAndroid Build Coastguard Worker       assert(0 && "Spatial layer dimensions not supported yet.");
464*77c1e3ccSAndroid Build Coastguard Worker     } else {
465*77c1e3ccSAndroid Build Coastguard Worker       const SequenceHeader *const seq_params = cm->seq_params;
466*77c1e3ccSAndroid Build Coastguard Worker       const int max_frame_width = seq_params->max_frame_width;
467*77c1e3ccSAndroid Build Coastguard Worker       const int max_frame_height = seq_params->max_frame_height;
468*77c1e3ccSAndroid Build Coastguard Worker       luma_samples = max_frame_width * max_frame_height;
469*77c1e3ccSAndroid Build Coastguard Worker     }
470*77c1e3ccSAndroid Build Coastguard Worker   }
471*77c1e3ccSAndroid Build Coastguard Worker 
472*77c1e3ccSAndroid Build Coastguard Worker   return luma_samples / (double)max_decode_rate;
473*77c1e3ccSAndroid Build Coastguard Worker }
474*77c1e3ccSAndroid Build Coastguard Worker 
475*77c1e3ccSAndroid Build Coastguard Worker // Release frame buffers that are no longer needed for decode or display.
476*77c1e3ccSAndroid Build Coastguard Worker // It corresponds to "start_decode_at_removal_time" in the spec.
release_processed_frames(DECODER_MODEL * const decoder_model,double removal_time)477*77c1e3ccSAndroid Build Coastguard Worker static void release_processed_frames(DECODER_MODEL *const decoder_model,
478*77c1e3ccSAndroid Build Coastguard Worker                                      double removal_time) {
479*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < BUFFER_POOL_MAX_SIZE; ++i) {
480*77c1e3ccSAndroid Build Coastguard Worker     FRAME_BUFFER *const this_buffer = &decoder_model->frame_buffer_pool[i];
481*77c1e3ccSAndroid Build Coastguard Worker     if (this_buffer->player_ref_count > 0) {
482*77c1e3ccSAndroid Build Coastguard Worker       if (this_buffer->presentation_time >= 0.0 &&
483*77c1e3ccSAndroid Build Coastguard Worker           this_buffer->presentation_time <= removal_time) {
484*77c1e3ccSAndroid Build Coastguard Worker         this_buffer->player_ref_count = 0;
485*77c1e3ccSAndroid Build Coastguard Worker         if (this_buffer->decoder_ref_count == 0) {
486*77c1e3ccSAndroid Build Coastguard Worker           release_buffer(decoder_model, i);
487*77c1e3ccSAndroid Build Coastguard Worker         }
488*77c1e3ccSAndroid Build Coastguard Worker       }
489*77c1e3ccSAndroid Build Coastguard Worker     }
490*77c1e3ccSAndroid Build Coastguard Worker   }
491*77c1e3ccSAndroid Build Coastguard Worker }
492*77c1e3ccSAndroid Build Coastguard Worker 
frames_in_buffer_pool(const DECODER_MODEL * const decoder_model)493*77c1e3ccSAndroid Build Coastguard Worker static int frames_in_buffer_pool(const DECODER_MODEL *const decoder_model) {
494*77c1e3ccSAndroid Build Coastguard Worker   int frames_in_pool = 0;
495*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < BUFFER_POOL_MAX_SIZE; ++i) {
496*77c1e3ccSAndroid Build Coastguard Worker     const FRAME_BUFFER *const this_buffer =
497*77c1e3ccSAndroid Build Coastguard Worker         &decoder_model->frame_buffer_pool[i];
498*77c1e3ccSAndroid Build Coastguard Worker     if (this_buffer->decoder_ref_count > 0 ||
499*77c1e3ccSAndroid Build Coastguard Worker         this_buffer->player_ref_count > 0) {
500*77c1e3ccSAndroid Build Coastguard Worker       ++frames_in_pool;
501*77c1e3ccSAndroid Build Coastguard Worker     }
502*77c1e3ccSAndroid Build Coastguard Worker   }
503*77c1e3ccSAndroid Build Coastguard Worker   return frames_in_pool;
504*77c1e3ccSAndroid Build Coastguard Worker }
505*77c1e3ccSAndroid Build Coastguard Worker 
get_presentation_time(const DECODER_MODEL * const decoder_model,int display_index)506*77c1e3ccSAndroid Build Coastguard Worker static double get_presentation_time(const DECODER_MODEL *const decoder_model,
507*77c1e3ccSAndroid Build Coastguard Worker                                     int display_index) {
508*77c1e3ccSAndroid Build Coastguard Worker   if (decoder_model->mode == SCHEDULE_MODE) {
509*77c1e3ccSAndroid Build Coastguard Worker     assert(0 && "SCHEDULE_MODE NOT SUPPORTED");
510*77c1e3ccSAndroid Build Coastguard Worker     return INVALID_TIME;
511*77c1e3ccSAndroid Build Coastguard Worker   } else {
512*77c1e3ccSAndroid Build Coastguard Worker     const double initial_presentation_delay =
513*77c1e3ccSAndroid Build Coastguard Worker         decoder_model->initial_presentation_delay;
514*77c1e3ccSAndroid Build Coastguard Worker     // Can't decide presentation time until the initial presentation delay is
515*77c1e3ccSAndroid Build Coastguard Worker     // known.
516*77c1e3ccSAndroid Build Coastguard Worker     if (initial_presentation_delay < 0.0) return INVALID_TIME;
517*77c1e3ccSAndroid Build Coastguard Worker 
518*77c1e3ccSAndroid Build Coastguard Worker     return initial_presentation_delay +
519*77c1e3ccSAndroid Build Coastguard Worker            display_index * decoder_model->num_ticks_per_picture *
520*77c1e3ccSAndroid Build Coastguard Worker                decoder_model->display_clock_tick;
521*77c1e3ccSAndroid Build Coastguard Worker   }
522*77c1e3ccSAndroid Build Coastguard Worker }
523*77c1e3ccSAndroid Build Coastguard Worker 
524*77c1e3ccSAndroid Build Coastguard Worker #define MAX_TIME 1e16
time_next_buffer_is_free(int num_decoded_frame,int decoder_buffer_delay,const FRAME_BUFFER * frame_buffer_pool,double current_time)525*77c1e3ccSAndroid Build Coastguard Worker static double time_next_buffer_is_free(int num_decoded_frame,
526*77c1e3ccSAndroid Build Coastguard Worker                                        int decoder_buffer_delay,
527*77c1e3ccSAndroid Build Coastguard Worker                                        const FRAME_BUFFER *frame_buffer_pool,
528*77c1e3ccSAndroid Build Coastguard Worker                                        double current_time) {
529*77c1e3ccSAndroid Build Coastguard Worker   if (num_decoded_frame == 0) {
530*77c1e3ccSAndroid Build Coastguard Worker     return (double)decoder_buffer_delay / 90000.0;
531*77c1e3ccSAndroid Build Coastguard Worker   }
532*77c1e3ccSAndroid Build Coastguard Worker 
533*77c1e3ccSAndroid Build Coastguard Worker   double buf_free_time = MAX_TIME;
534*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < BUFFER_POOL_MAX_SIZE; ++i) {
535*77c1e3ccSAndroid Build Coastguard Worker     const FRAME_BUFFER *const this_buffer = &frame_buffer_pool[i];
536*77c1e3ccSAndroid Build Coastguard Worker     if (this_buffer->decoder_ref_count == 0) {
537*77c1e3ccSAndroid Build Coastguard Worker       if (this_buffer->player_ref_count == 0) {
538*77c1e3ccSAndroid Build Coastguard Worker         return current_time;
539*77c1e3ccSAndroid Build Coastguard Worker       }
540*77c1e3ccSAndroid Build Coastguard Worker       const double presentation_time = this_buffer->presentation_time;
541*77c1e3ccSAndroid Build Coastguard Worker       if (presentation_time >= 0.0 && presentation_time < buf_free_time) {
542*77c1e3ccSAndroid Build Coastguard Worker         buf_free_time = presentation_time;
543*77c1e3ccSAndroid Build Coastguard Worker       }
544*77c1e3ccSAndroid Build Coastguard Worker     }
545*77c1e3ccSAndroid Build Coastguard Worker   }
546*77c1e3ccSAndroid Build Coastguard Worker   return buf_free_time < MAX_TIME ? buf_free_time : INVALID_TIME;
547*77c1e3ccSAndroid Build Coastguard Worker }
548*77c1e3ccSAndroid Build Coastguard Worker #undef MAX_TIME
549*77c1e3ccSAndroid Build Coastguard Worker 
get_removal_time(int mode,int num_decoded_frame,int decoder_buffer_delay,const FRAME_BUFFER * frame_buffer_pool,double current_time)550*77c1e3ccSAndroid Build Coastguard Worker static double get_removal_time(int mode, int num_decoded_frame,
551*77c1e3ccSAndroid Build Coastguard Worker                                int decoder_buffer_delay,
552*77c1e3ccSAndroid Build Coastguard Worker                                const FRAME_BUFFER *frame_buffer_pool,
553*77c1e3ccSAndroid Build Coastguard Worker                                double current_time) {
554*77c1e3ccSAndroid Build Coastguard Worker   if (mode == SCHEDULE_MODE) {
555*77c1e3ccSAndroid Build Coastguard Worker     assert(0 && "SCHEDULE_MODE IS NOT SUPPORTED YET");
556*77c1e3ccSAndroid Build Coastguard Worker     return INVALID_TIME;
557*77c1e3ccSAndroid Build Coastguard Worker   } else {
558*77c1e3ccSAndroid Build Coastguard Worker     return time_next_buffer_is_free(num_decoded_frame, decoder_buffer_delay,
559*77c1e3ccSAndroid Build Coastguard Worker                                     frame_buffer_pool, current_time);
560*77c1e3ccSAndroid Build Coastguard Worker   }
561*77c1e3ccSAndroid Build Coastguard Worker }
562*77c1e3ccSAndroid Build Coastguard Worker 
563*77c1e3ccSAndroid Build Coastguard Worker #if 0
564*77c1e3ccSAndroid Build Coastguard Worker // Print the status of the decoder model (for debugging).
565*77c1e3ccSAndroid Build Coastguard Worker void av1_decoder_model_print_status(const DECODER_MODEL *const decoder_model) {
566*77c1e3ccSAndroid Build Coastguard Worker   printf(
567*77c1e3ccSAndroid Build Coastguard Worker       "\n status %d, num_frame %3d, num_decoded_frame %3d, "
568*77c1e3ccSAndroid Build Coastguard Worker       "num_shown_frame %3d, current time %6.2f, frames in buffer %2d, "
569*77c1e3ccSAndroid Build Coastguard Worker       "presentation delay %6.2f, total interval %6.2f\n",
570*77c1e3ccSAndroid Build Coastguard Worker       decoder_model->status, decoder_model->num_frame,
571*77c1e3ccSAndroid Build Coastguard Worker       decoder_model->num_decoded_frame, decoder_model->num_shown_frame,
572*77c1e3ccSAndroid Build Coastguard Worker       decoder_model->current_time, frames_in_buffer_pool(decoder_model),
573*77c1e3ccSAndroid Build Coastguard Worker       decoder_model->initial_presentation_delay,
574*77c1e3ccSAndroid Build Coastguard Worker       decoder_model->dfg_interval_queue.total_interval);
575*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 10; ++i) {
576*77c1e3ccSAndroid Build Coastguard Worker     const FRAME_BUFFER *const this_buffer =
577*77c1e3ccSAndroid Build Coastguard Worker         &decoder_model->frame_buffer_pool[i];
578*77c1e3ccSAndroid Build Coastguard Worker     printf("buffer %d, decode count %d, display count %d, present time %6.4f\n",
579*77c1e3ccSAndroid Build Coastguard Worker            i, this_buffer->decoder_ref_count, this_buffer->player_ref_count,
580*77c1e3ccSAndroid Build Coastguard Worker            this_buffer->presentation_time);
581*77c1e3ccSAndroid Build Coastguard Worker   }
582*77c1e3ccSAndroid Build Coastguard Worker }
583*77c1e3ccSAndroid Build Coastguard Worker #endif
584*77c1e3ccSAndroid Build Coastguard Worker 
585*77c1e3ccSAndroid Build Coastguard Worker // op_index is the operating point index.
decoder_model_init(const AV1_COMP * const cpi,AV1_LEVEL level,int op_index,DECODER_MODEL * const decoder_model)586*77c1e3ccSAndroid Build Coastguard Worker static void decoder_model_init(const AV1_COMP *const cpi, AV1_LEVEL level,
587*77c1e3ccSAndroid Build Coastguard Worker                                int op_index,
588*77c1e3ccSAndroid Build Coastguard Worker                                DECODER_MODEL *const decoder_model) {
589*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->status = DECODER_MODEL_OK;
590*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->level = level;
591*77c1e3ccSAndroid Build Coastguard Worker 
592*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
593*77c1e3ccSAndroid Build Coastguard Worker   const SequenceHeader *const seq_params = cm->seq_params;
594*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->bit_rate = get_max_bitrate(
595*77c1e3ccSAndroid Build Coastguard Worker       av1_level_defs + level, seq_params->tier[op_index], seq_params->profile);
596*77c1e3ccSAndroid Build Coastguard Worker 
597*77c1e3ccSAndroid Build Coastguard Worker   // TODO(huisu or anyone): implement SCHEDULE_MODE.
598*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->mode = RESOURCE_MODE;
599*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->encoder_buffer_delay = 20000;
600*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->decoder_buffer_delay = 70000;
601*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->is_low_delay_mode = false;
602*77c1e3ccSAndroid Build Coastguard Worker 
603*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->first_bit_arrival_time = 0.0;
604*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->last_bit_arrival_time = 0.0;
605*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->coded_bits = 0;
606*77c1e3ccSAndroid Build Coastguard Worker 
607*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->removal_time = INVALID_TIME;
608*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->presentation_time = INVALID_TIME;
609*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->decode_samples = 0;
610*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->display_samples = 0;
611*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->max_decode_rate = 0.0;
612*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->max_display_rate = 0.0;
613*77c1e3ccSAndroid Build Coastguard Worker 
614*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->num_frame = -1;
615*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->num_decoded_frame = -1;
616*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->num_shown_frame = -1;
617*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->current_time = 0.0;
618*77c1e3ccSAndroid Build Coastguard Worker 
619*77c1e3ccSAndroid Build Coastguard Worker   initialize_buffer_pool(decoder_model);
620*77c1e3ccSAndroid Build Coastguard Worker 
621*77c1e3ccSAndroid Build Coastguard Worker   DFG_INTERVAL_QUEUE *const dfg_interval_queue =
622*77c1e3ccSAndroid Build Coastguard Worker       &decoder_model->dfg_interval_queue;
623*77c1e3ccSAndroid Build Coastguard Worker   dfg_interval_queue->total_interval = 0.0;
624*77c1e3ccSAndroid Build Coastguard Worker   dfg_interval_queue->head = 0;
625*77c1e3ccSAndroid Build Coastguard Worker   dfg_interval_queue->size = 0;
626*77c1e3ccSAndroid Build Coastguard Worker 
627*77c1e3ccSAndroid Build Coastguard Worker   if (seq_params->timing_info_present) {
628*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->num_ticks_per_picture =
629*77c1e3ccSAndroid Build Coastguard Worker         seq_params->timing_info.num_ticks_per_picture;
630*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->display_clock_tick =
631*77c1e3ccSAndroid Build Coastguard Worker         seq_params->timing_info.num_units_in_display_tick /
632*77c1e3ccSAndroid Build Coastguard Worker         seq_params->timing_info.time_scale;
633*77c1e3ccSAndroid Build Coastguard Worker   } else {
634*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->num_ticks_per_picture = 1;
635*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->display_clock_tick = 1.0 / cpi->framerate;
636*77c1e3ccSAndroid Build Coastguard Worker   }
637*77c1e3ccSAndroid Build Coastguard Worker 
638*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->initial_display_delay =
639*77c1e3ccSAndroid Build Coastguard Worker       seq_params->op_params[op_index].initial_display_delay;
640*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->initial_presentation_delay = INVALID_TIME;
641*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->decode_rate = av1_level_defs[level].max_decode_rate;
642*77c1e3ccSAndroid Build Coastguard Worker }
643*77c1e3ccSAndroid Build Coastguard Worker 
av1_decoder_model_try_smooth_buf(const AV1_COMP * const cpi,size_t coded_bits,const DECODER_MODEL * const decoder_model)644*77c1e3ccSAndroid Build Coastguard Worker DECODER_MODEL_STATUS av1_decoder_model_try_smooth_buf(
645*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMP *const cpi, size_t coded_bits,
646*77c1e3ccSAndroid Build Coastguard Worker     const DECODER_MODEL *const decoder_model) {
647*77c1e3ccSAndroid Build Coastguard Worker   DECODER_MODEL_STATUS status = DECODER_MODEL_OK;
648*77c1e3ccSAndroid Build Coastguard Worker 
649*77c1e3ccSAndroid Build Coastguard Worker   if (!decoder_model || decoder_model->status != DECODER_MODEL_OK) {
650*77c1e3ccSAndroid Build Coastguard Worker     return status;
651*77c1e3ccSAndroid Build Coastguard Worker   }
652*77c1e3ccSAndroid Build Coastguard Worker 
653*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
654*77c1e3ccSAndroid Build Coastguard Worker   const int show_existing_frame = cm->show_existing_frame;
655*77c1e3ccSAndroid Build Coastguard Worker 
656*77c1e3ccSAndroid Build Coastguard Worker   size_t cur_coded_bits = decoder_model->coded_bits + coded_bits;
657*77c1e3ccSAndroid Build Coastguard Worker   int num_decoded_frame = decoder_model->num_decoded_frame;
658*77c1e3ccSAndroid Build Coastguard Worker   if (!show_existing_frame) ++num_decoded_frame;
659*77c1e3ccSAndroid Build Coastguard Worker 
660*77c1e3ccSAndroid Build Coastguard Worker   if (show_existing_frame) {
661*77c1e3ccSAndroid Build Coastguard Worker     return status;
662*77c1e3ccSAndroid Build Coastguard Worker   } else {
663*77c1e3ccSAndroid Build Coastguard Worker     const double removal_time = get_removal_time(
664*77c1e3ccSAndroid Build Coastguard Worker         decoder_model->mode, num_decoded_frame,
665*77c1e3ccSAndroid Build Coastguard Worker         decoder_model->decoder_buffer_delay, decoder_model->frame_buffer_pool,
666*77c1e3ccSAndroid Build Coastguard Worker         decoder_model->current_time);
667*77c1e3ccSAndroid Build Coastguard Worker     if (removal_time < 0.0) {
668*77c1e3ccSAndroid Build Coastguard Worker       status = DECODE_FRAME_BUF_UNAVAILABLE;
669*77c1e3ccSAndroid Build Coastguard Worker       return status;
670*77c1e3ccSAndroid Build Coastguard Worker     }
671*77c1e3ccSAndroid Build Coastguard Worker 
672*77c1e3ccSAndroid Build Coastguard Worker     // A frame with show_existing_frame being false indicates the end of a DFG.
673*77c1e3ccSAndroid Build Coastguard Worker     // Update the bits arrival time of this DFG.
674*77c1e3ccSAndroid Build Coastguard Worker     const double buffer_delay = (decoder_model->encoder_buffer_delay +
675*77c1e3ccSAndroid Build Coastguard Worker                                  decoder_model->decoder_buffer_delay) /
676*77c1e3ccSAndroid Build Coastguard Worker                                 90000.0;
677*77c1e3ccSAndroid Build Coastguard Worker     const double latest_arrival_time = removal_time - buffer_delay;
678*77c1e3ccSAndroid Build Coastguard Worker     const double first_bit_arrival_time =
679*77c1e3ccSAndroid Build Coastguard Worker         AOMMAX(decoder_model->last_bit_arrival_time, latest_arrival_time);
680*77c1e3ccSAndroid Build Coastguard Worker     const double last_bit_arrival_time =
681*77c1e3ccSAndroid Build Coastguard Worker         first_bit_arrival_time +
682*77c1e3ccSAndroid Build Coastguard Worker         (double)cur_coded_bits / decoder_model->bit_rate;
683*77c1e3ccSAndroid Build Coastguard Worker     // Smoothing buffer underflows if the last bit arrives after the removal
684*77c1e3ccSAndroid Build Coastguard Worker     // time.
685*77c1e3ccSAndroid Build Coastguard Worker     if (last_bit_arrival_time > removal_time &&
686*77c1e3ccSAndroid Build Coastguard Worker         !decoder_model->is_low_delay_mode) {
687*77c1e3ccSAndroid Build Coastguard Worker       status = SMOOTHING_BUFFER_UNDERFLOW;
688*77c1e3ccSAndroid Build Coastguard Worker       return status;
689*77c1e3ccSAndroid Build Coastguard Worker     }
690*77c1e3ccSAndroid Build Coastguard Worker 
691*77c1e3ccSAndroid Build Coastguard Worker     // Check if the smoothing buffer overflows.
692*77c1e3ccSAndroid Build Coastguard Worker     const DFG_INTERVAL_QUEUE *const queue = &decoder_model->dfg_interval_queue;
693*77c1e3ccSAndroid Build Coastguard Worker     if (queue->size >= DFG_INTERVAL_QUEUE_SIZE) {
694*77c1e3ccSAndroid Build Coastguard Worker       assert(0);
695*77c1e3ccSAndroid Build Coastguard Worker     }
696*77c1e3ccSAndroid Build Coastguard Worker 
697*77c1e3ccSAndroid Build Coastguard Worker     double total_interval = queue->total_interval;
698*77c1e3ccSAndroid Build Coastguard Worker     int qhead = queue->head;
699*77c1e3ccSAndroid Build Coastguard Worker     int qsize = queue->size;
700*77c1e3ccSAndroid Build Coastguard Worker     // Remove the DFGs with removal time earlier than last_bit_arrival_time.
701*77c1e3ccSAndroid Build Coastguard Worker     while (queue->buf[qhead].removal_time <= last_bit_arrival_time &&
702*77c1e3ccSAndroid Build Coastguard Worker            qsize > 0) {
703*77c1e3ccSAndroid Build Coastguard Worker       if (queue->buf[qhead].removal_time - first_bit_arrival_time +
704*77c1e3ccSAndroid Build Coastguard Worker               total_interval >
705*77c1e3ccSAndroid Build Coastguard Worker           1.0) {
706*77c1e3ccSAndroid Build Coastguard Worker         status = SMOOTHING_BUFFER_OVERFLOW;
707*77c1e3ccSAndroid Build Coastguard Worker         return status;
708*77c1e3ccSAndroid Build Coastguard Worker       }
709*77c1e3ccSAndroid Build Coastguard Worker       total_interval -= queue->buf[qhead].last_bit_arrival_time -
710*77c1e3ccSAndroid Build Coastguard Worker                         queue->buf[qhead].first_bit_arrival_time;
711*77c1e3ccSAndroid Build Coastguard Worker       qhead = (qhead + 1) % DFG_INTERVAL_QUEUE_SIZE;
712*77c1e3ccSAndroid Build Coastguard Worker       --qsize;
713*77c1e3ccSAndroid Build Coastguard Worker     }
714*77c1e3ccSAndroid Build Coastguard Worker     total_interval += last_bit_arrival_time - first_bit_arrival_time;
715*77c1e3ccSAndroid Build Coastguard Worker     // The smoothing buffer can hold at most "bit_rate" bits, which is
716*77c1e3ccSAndroid Build Coastguard Worker     // equivalent to 1 second of total interval.
717*77c1e3ccSAndroid Build Coastguard Worker     if (total_interval > 1.0) {
718*77c1e3ccSAndroid Build Coastguard Worker       status = SMOOTHING_BUFFER_OVERFLOW;
719*77c1e3ccSAndroid Build Coastguard Worker       return status;
720*77c1e3ccSAndroid Build Coastguard Worker     }
721*77c1e3ccSAndroid Build Coastguard Worker 
722*77c1e3ccSAndroid Build Coastguard Worker     return status;
723*77c1e3ccSAndroid Build Coastguard Worker   }
724*77c1e3ccSAndroid Build Coastguard Worker }
725*77c1e3ccSAndroid Build Coastguard Worker 
decoder_model_process_frame(const AV1_COMP * const cpi,size_t coded_bits,DECODER_MODEL * const decoder_model)726*77c1e3ccSAndroid Build Coastguard Worker static void decoder_model_process_frame(const AV1_COMP *const cpi,
727*77c1e3ccSAndroid Build Coastguard Worker                                         size_t coded_bits,
728*77c1e3ccSAndroid Build Coastguard Worker                                         DECODER_MODEL *const decoder_model) {
729*77c1e3ccSAndroid Build Coastguard Worker   if (!decoder_model || decoder_model->status != DECODER_MODEL_OK) return;
730*77c1e3ccSAndroid Build Coastguard Worker 
731*77c1e3ccSAndroid Build Coastguard Worker   const AV1_COMMON *const cm = &cpi->common;
732*77c1e3ccSAndroid Build Coastguard Worker   const int luma_pic_size = cm->superres_upscaled_width * cm->height;
733*77c1e3ccSAndroid Build Coastguard Worker   const int show_existing_frame = cm->show_existing_frame;
734*77c1e3ccSAndroid Build Coastguard Worker   const int show_frame = cm->show_frame || show_existing_frame;
735*77c1e3ccSAndroid Build Coastguard Worker   ++decoder_model->num_frame;
736*77c1e3ccSAndroid Build Coastguard Worker   if (!show_existing_frame) ++decoder_model->num_decoded_frame;
737*77c1e3ccSAndroid Build Coastguard Worker   if (show_frame) ++decoder_model->num_shown_frame;
738*77c1e3ccSAndroid Build Coastguard Worker   decoder_model->coded_bits += coded_bits;
739*77c1e3ccSAndroid Build Coastguard Worker 
740*77c1e3ccSAndroid Build Coastguard Worker   int display_idx = -1;
741*77c1e3ccSAndroid Build Coastguard Worker   if (show_existing_frame) {
742*77c1e3ccSAndroid Build Coastguard Worker     display_idx = decoder_model->vbi[cpi->existing_fb_idx_to_show];
743*77c1e3ccSAndroid Build Coastguard Worker     if (display_idx < 0) {
744*77c1e3ccSAndroid Build Coastguard Worker       decoder_model->status = DECODE_EXISTING_FRAME_BUF_EMPTY;
745*77c1e3ccSAndroid Build Coastguard Worker       return;
746*77c1e3ccSAndroid Build Coastguard Worker     }
747*77c1e3ccSAndroid Build Coastguard Worker     if (decoder_model->frame_buffer_pool[display_idx].frame_type == KEY_FRAME) {
748*77c1e3ccSAndroid Build Coastguard Worker       update_ref_buffers(decoder_model, display_idx, 0xFF);
749*77c1e3ccSAndroid Build Coastguard Worker     }
750*77c1e3ccSAndroid Build Coastguard Worker   } else {
751*77c1e3ccSAndroid Build Coastguard Worker     const double removal_time = get_removal_time(
752*77c1e3ccSAndroid Build Coastguard Worker         decoder_model->mode, decoder_model->num_decoded_frame,
753*77c1e3ccSAndroid Build Coastguard Worker         decoder_model->decoder_buffer_delay, decoder_model->frame_buffer_pool,
754*77c1e3ccSAndroid Build Coastguard Worker         decoder_model->current_time);
755*77c1e3ccSAndroid Build Coastguard Worker     if (removal_time < 0.0) {
756*77c1e3ccSAndroid Build Coastguard Worker       decoder_model->status = DECODE_FRAME_BUF_UNAVAILABLE;
757*77c1e3ccSAndroid Build Coastguard Worker       return;
758*77c1e3ccSAndroid Build Coastguard Worker     }
759*77c1e3ccSAndroid Build Coastguard Worker 
760*77c1e3ccSAndroid Build Coastguard Worker     const int previous_decode_samples = decoder_model->decode_samples;
761*77c1e3ccSAndroid Build Coastguard Worker     const double previous_removal_time = decoder_model->removal_time;
762*77c1e3ccSAndroid Build Coastguard Worker     assert(previous_removal_time < removal_time);
763*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->removal_time = removal_time;
764*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->decode_samples = luma_pic_size;
765*77c1e3ccSAndroid Build Coastguard Worker     const double this_decode_rate =
766*77c1e3ccSAndroid Build Coastguard Worker         previous_decode_samples / (removal_time - previous_removal_time);
767*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->max_decode_rate =
768*77c1e3ccSAndroid Build Coastguard Worker         AOMMAX(decoder_model->max_decode_rate, this_decode_rate);
769*77c1e3ccSAndroid Build Coastguard Worker 
770*77c1e3ccSAndroid Build Coastguard Worker     // A frame with show_existing_frame being false indicates the end of a DFG.
771*77c1e3ccSAndroid Build Coastguard Worker     // Update the bits arrival time of this DFG.
772*77c1e3ccSAndroid Build Coastguard Worker     const double buffer_delay = (decoder_model->encoder_buffer_delay +
773*77c1e3ccSAndroid Build Coastguard Worker                                  decoder_model->decoder_buffer_delay) /
774*77c1e3ccSAndroid Build Coastguard Worker                                 90000.0;
775*77c1e3ccSAndroid Build Coastguard Worker     const double latest_arrival_time = removal_time - buffer_delay;
776*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->first_bit_arrival_time =
777*77c1e3ccSAndroid Build Coastguard Worker         AOMMAX(decoder_model->last_bit_arrival_time, latest_arrival_time);
778*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->last_bit_arrival_time =
779*77c1e3ccSAndroid Build Coastguard Worker         decoder_model->first_bit_arrival_time +
780*77c1e3ccSAndroid Build Coastguard Worker         (double)decoder_model->coded_bits / decoder_model->bit_rate;
781*77c1e3ccSAndroid Build Coastguard Worker     // Smoothing buffer underflows if the last bit arrives after the removal
782*77c1e3ccSAndroid Build Coastguard Worker     // time.
783*77c1e3ccSAndroid Build Coastguard Worker     if (decoder_model->last_bit_arrival_time > removal_time &&
784*77c1e3ccSAndroid Build Coastguard Worker         !decoder_model->is_low_delay_mode) {
785*77c1e3ccSAndroid Build Coastguard Worker       decoder_model->status = SMOOTHING_BUFFER_UNDERFLOW;
786*77c1e3ccSAndroid Build Coastguard Worker       return;
787*77c1e3ccSAndroid Build Coastguard Worker     }
788*77c1e3ccSAndroid Build Coastguard Worker     // Reset the coded bits for the next DFG.
789*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->coded_bits = 0;
790*77c1e3ccSAndroid Build Coastguard Worker 
791*77c1e3ccSAndroid Build Coastguard Worker     // Check if the smoothing buffer overflows.
792*77c1e3ccSAndroid Build Coastguard Worker     DFG_INTERVAL_QUEUE *const queue = &decoder_model->dfg_interval_queue;
793*77c1e3ccSAndroid Build Coastguard Worker     if (queue->size >= DFG_INTERVAL_QUEUE_SIZE) {
794*77c1e3ccSAndroid Build Coastguard Worker       assert(0);
795*77c1e3ccSAndroid Build Coastguard Worker     }
796*77c1e3ccSAndroid Build Coastguard Worker     const double first_bit_arrival_time = decoder_model->first_bit_arrival_time;
797*77c1e3ccSAndroid Build Coastguard Worker     const double last_bit_arrival_time = decoder_model->last_bit_arrival_time;
798*77c1e3ccSAndroid Build Coastguard Worker     // Remove the DFGs with removal time earlier than last_bit_arrival_time.
799*77c1e3ccSAndroid Build Coastguard Worker     while (queue->buf[queue->head].removal_time <= last_bit_arrival_time &&
800*77c1e3ccSAndroid Build Coastguard Worker            queue->size > 0) {
801*77c1e3ccSAndroid Build Coastguard Worker       if (queue->buf[queue->head].removal_time - first_bit_arrival_time +
802*77c1e3ccSAndroid Build Coastguard Worker               queue->total_interval >
803*77c1e3ccSAndroid Build Coastguard Worker           1.0) {
804*77c1e3ccSAndroid Build Coastguard Worker         decoder_model->status = SMOOTHING_BUFFER_OVERFLOW;
805*77c1e3ccSAndroid Build Coastguard Worker         return;
806*77c1e3ccSAndroid Build Coastguard Worker       }
807*77c1e3ccSAndroid Build Coastguard Worker       queue->total_interval -= queue->buf[queue->head].last_bit_arrival_time -
808*77c1e3ccSAndroid Build Coastguard Worker                                queue->buf[queue->head].first_bit_arrival_time;
809*77c1e3ccSAndroid Build Coastguard Worker       queue->head = (queue->head + 1) % DFG_INTERVAL_QUEUE_SIZE;
810*77c1e3ccSAndroid Build Coastguard Worker       --queue->size;
811*77c1e3ccSAndroid Build Coastguard Worker     }
812*77c1e3ccSAndroid Build Coastguard Worker     // Push current DFG into the queue.
813*77c1e3ccSAndroid Build Coastguard Worker     const int queue_index =
814*77c1e3ccSAndroid Build Coastguard Worker         (queue->head + queue->size++) % DFG_INTERVAL_QUEUE_SIZE;
815*77c1e3ccSAndroid Build Coastguard Worker     queue->buf[queue_index].first_bit_arrival_time = first_bit_arrival_time;
816*77c1e3ccSAndroid Build Coastguard Worker     queue->buf[queue_index].last_bit_arrival_time = last_bit_arrival_time;
817*77c1e3ccSAndroid Build Coastguard Worker     queue->buf[queue_index].removal_time = removal_time;
818*77c1e3ccSAndroid Build Coastguard Worker     queue->total_interval += last_bit_arrival_time - first_bit_arrival_time;
819*77c1e3ccSAndroid Build Coastguard Worker     // The smoothing buffer can hold at most "bit_rate" bits, which is
820*77c1e3ccSAndroid Build Coastguard Worker     // equivalent to 1 second of total interval.
821*77c1e3ccSAndroid Build Coastguard Worker     if (queue->total_interval > 1.0) {
822*77c1e3ccSAndroid Build Coastguard Worker       decoder_model->status = SMOOTHING_BUFFER_OVERFLOW;
823*77c1e3ccSAndroid Build Coastguard Worker       return;
824*77c1e3ccSAndroid Build Coastguard Worker     }
825*77c1e3ccSAndroid Build Coastguard Worker 
826*77c1e3ccSAndroid Build Coastguard Worker     release_processed_frames(decoder_model, removal_time);
827*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->current_time =
828*77c1e3ccSAndroid Build Coastguard Worker         removal_time + time_to_decode_frame(cm, decoder_model->decode_rate);
829*77c1e3ccSAndroid Build Coastguard Worker 
830*77c1e3ccSAndroid Build Coastguard Worker     const int cfbi = get_free_buffer(decoder_model);
831*77c1e3ccSAndroid Build Coastguard Worker     if (cfbi < 0) {
832*77c1e3ccSAndroid Build Coastguard Worker       decoder_model->status = DECODE_FRAME_BUF_UNAVAILABLE;
833*77c1e3ccSAndroid Build Coastguard Worker       return;
834*77c1e3ccSAndroid Build Coastguard Worker     }
835*77c1e3ccSAndroid Build Coastguard Worker     const CurrentFrame *const current_frame = &cm->current_frame;
836*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->frame_buffer_pool[cfbi].frame_type =
837*77c1e3ccSAndroid Build Coastguard Worker         cm->current_frame.frame_type;
838*77c1e3ccSAndroid Build Coastguard Worker     display_idx = cfbi;
839*77c1e3ccSAndroid Build Coastguard Worker     update_ref_buffers(decoder_model, cfbi, current_frame->refresh_frame_flags);
840*77c1e3ccSAndroid Build Coastguard Worker 
841*77c1e3ccSAndroid Build Coastguard Worker     if (decoder_model->initial_presentation_delay < 0.0) {
842*77c1e3ccSAndroid Build Coastguard Worker       // Display can begin after required number of frames have been buffered.
843*77c1e3ccSAndroid Build Coastguard Worker       if (frames_in_buffer_pool(decoder_model) >=
844*77c1e3ccSAndroid Build Coastguard Worker           decoder_model->initial_display_delay - 1) {
845*77c1e3ccSAndroid Build Coastguard Worker         decoder_model->initial_presentation_delay = decoder_model->current_time;
846*77c1e3ccSAndroid Build Coastguard Worker         // Update presentation time for each shown frame in the frame buffer.
847*77c1e3ccSAndroid Build Coastguard Worker         for (int i = 0; i < BUFFER_POOL_MAX_SIZE; ++i) {
848*77c1e3ccSAndroid Build Coastguard Worker           FRAME_BUFFER *const this_buffer =
849*77c1e3ccSAndroid Build Coastguard Worker               &decoder_model->frame_buffer_pool[i];
850*77c1e3ccSAndroid Build Coastguard Worker           if (this_buffer->player_ref_count == 0) continue;
851*77c1e3ccSAndroid Build Coastguard Worker           assert(this_buffer->display_index >= 0);
852*77c1e3ccSAndroid Build Coastguard Worker           this_buffer->presentation_time =
853*77c1e3ccSAndroid Build Coastguard Worker               get_presentation_time(decoder_model, this_buffer->display_index);
854*77c1e3ccSAndroid Build Coastguard Worker         }
855*77c1e3ccSAndroid Build Coastguard Worker       }
856*77c1e3ccSAndroid Build Coastguard Worker     }
857*77c1e3ccSAndroid Build Coastguard Worker   }
858*77c1e3ccSAndroid Build Coastguard Worker 
859*77c1e3ccSAndroid Build Coastguard Worker   // Display.
860*77c1e3ccSAndroid Build Coastguard Worker   if (show_frame) {
861*77c1e3ccSAndroid Build Coastguard Worker     assert(display_idx >= 0 && display_idx < BUFFER_POOL_MAX_SIZE);
862*77c1e3ccSAndroid Build Coastguard Worker     FRAME_BUFFER *const this_buffer =
863*77c1e3ccSAndroid Build Coastguard Worker         &decoder_model->frame_buffer_pool[display_idx];
864*77c1e3ccSAndroid Build Coastguard Worker     ++this_buffer->player_ref_count;
865*77c1e3ccSAndroid Build Coastguard Worker     this_buffer->display_index = decoder_model->num_shown_frame;
866*77c1e3ccSAndroid Build Coastguard Worker     const double presentation_time =
867*77c1e3ccSAndroid Build Coastguard Worker         get_presentation_time(decoder_model, this_buffer->display_index);
868*77c1e3ccSAndroid Build Coastguard Worker     this_buffer->presentation_time = presentation_time;
869*77c1e3ccSAndroid Build Coastguard Worker     if (presentation_time >= 0.0 &&
870*77c1e3ccSAndroid Build Coastguard Worker         decoder_model->current_time > presentation_time) {
871*77c1e3ccSAndroid Build Coastguard Worker       decoder_model->status = DISPLAY_FRAME_LATE;
872*77c1e3ccSAndroid Build Coastguard Worker       return;
873*77c1e3ccSAndroid Build Coastguard Worker     }
874*77c1e3ccSAndroid Build Coastguard Worker 
875*77c1e3ccSAndroid Build Coastguard Worker     const int previous_display_samples = decoder_model->display_samples;
876*77c1e3ccSAndroid Build Coastguard Worker     const double previous_presentation_time = decoder_model->presentation_time;
877*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->display_samples = luma_pic_size;
878*77c1e3ccSAndroid Build Coastguard Worker     decoder_model->presentation_time = presentation_time;
879*77c1e3ccSAndroid Build Coastguard Worker     if (presentation_time >= 0.0 && previous_presentation_time >= 0.0) {
880*77c1e3ccSAndroid Build Coastguard Worker       assert(previous_presentation_time < presentation_time);
881*77c1e3ccSAndroid Build Coastguard Worker       const double this_display_rate =
882*77c1e3ccSAndroid Build Coastguard Worker           previous_display_samples /
883*77c1e3ccSAndroid Build Coastguard Worker           (presentation_time - previous_presentation_time);
884*77c1e3ccSAndroid Build Coastguard Worker       decoder_model->max_display_rate =
885*77c1e3ccSAndroid Build Coastguard Worker           AOMMAX(decoder_model->max_display_rate, this_display_rate);
886*77c1e3ccSAndroid Build Coastguard Worker     }
887*77c1e3ccSAndroid Build Coastguard Worker   }
888*77c1e3ccSAndroid Build Coastguard Worker }
889*77c1e3ccSAndroid Build Coastguard Worker 
av1_init_level_info(AV1_COMP * cpi)890*77c1e3ccSAndroid Build Coastguard Worker void av1_init_level_info(AV1_COMP *cpi) {
891*77c1e3ccSAndroid Build Coastguard Worker   for (int op_index = 0; op_index < MAX_NUM_OPERATING_POINTS; ++op_index) {
892*77c1e3ccSAndroid Build Coastguard Worker     AV1LevelInfo *const this_level_info =
893*77c1e3ccSAndroid Build Coastguard Worker         cpi->ppi->level_params.level_info[op_index];
894*77c1e3ccSAndroid Build Coastguard Worker     if (!this_level_info) continue;
895*77c1e3ccSAndroid Build Coastguard Worker     memset(this_level_info, 0, sizeof(*this_level_info));
896*77c1e3ccSAndroid Build Coastguard Worker     AV1LevelSpec *const level_spec = &this_level_info->level_spec;
897*77c1e3ccSAndroid Build Coastguard Worker     level_spec->level = SEQ_LEVEL_MAX;
898*77c1e3ccSAndroid Build Coastguard Worker     AV1LevelStats *const level_stats = &this_level_info->level_stats;
899*77c1e3ccSAndroid Build Coastguard Worker     level_stats->min_cropped_tile_width = INT_MAX;
900*77c1e3ccSAndroid Build Coastguard Worker     level_stats->min_cropped_tile_height = INT_MAX;
901*77c1e3ccSAndroid Build Coastguard Worker     level_stats->min_frame_width = INT_MAX;
902*77c1e3ccSAndroid Build Coastguard Worker     level_stats->min_frame_height = INT_MAX;
903*77c1e3ccSAndroid Build Coastguard Worker     level_stats->tile_width_is_valid = 1;
904*77c1e3ccSAndroid Build Coastguard Worker     level_stats->min_cr = 1e8;
905*77c1e3ccSAndroid Build Coastguard Worker 
906*77c1e3ccSAndroid Build Coastguard Worker     FrameWindowBuffer *const frame_window_buffer =
907*77c1e3ccSAndroid Build Coastguard Worker         &this_level_info->frame_window_buffer;
908*77c1e3ccSAndroid Build Coastguard Worker     frame_window_buffer->num = 0;
909*77c1e3ccSAndroid Build Coastguard Worker     frame_window_buffer->start = 0;
910*77c1e3ccSAndroid Build Coastguard Worker 
911*77c1e3ccSAndroid Build Coastguard Worker     const AV1_COMMON *const cm = &cpi->common;
912*77c1e3ccSAndroid Build Coastguard Worker     const int upscaled_width = cm->superres_upscaled_width;
913*77c1e3ccSAndroid Build Coastguard Worker     const int height = cm->height;
914*77c1e3ccSAndroid Build Coastguard Worker     const int pic_size = upscaled_width * height;
915*77c1e3ccSAndroid Build Coastguard Worker     for (AV1_LEVEL level = SEQ_LEVEL_2_0; level < SEQ_LEVELS; ++level) {
916*77c1e3ccSAndroid Build Coastguard Worker       DECODER_MODEL *const this_model = &this_level_info->decoder_models[level];
917*77c1e3ccSAndroid Build Coastguard Worker       const AV1LevelSpec *const spec = &av1_level_defs[level];
918*77c1e3ccSAndroid Build Coastguard Worker       if (upscaled_width > spec->max_h_size || height > spec->max_v_size ||
919*77c1e3ccSAndroid Build Coastguard Worker           pic_size > spec->max_picture_size) {
920*77c1e3ccSAndroid Build Coastguard Worker         // Turn off decoder model for this level as the frame size already
921*77c1e3ccSAndroid Build Coastguard Worker         // exceeds level constraints.
922*77c1e3ccSAndroid Build Coastguard Worker         this_model->status = DECODER_MODEL_DISABLED;
923*77c1e3ccSAndroid Build Coastguard Worker       } else {
924*77c1e3ccSAndroid Build Coastguard Worker         decoder_model_init(cpi, level, op_index, this_model);
925*77c1e3ccSAndroid Build Coastguard Worker       }
926*77c1e3ccSAndroid Build Coastguard Worker     }
927*77c1e3ccSAndroid Build Coastguard Worker   }
928*77c1e3ccSAndroid Build Coastguard Worker }
929*77c1e3ccSAndroid Build Coastguard Worker 
get_min_cr(const AV1LevelSpec * const level_spec,int tier,int is_still_picture,int64_t decoded_sample_rate)930*77c1e3ccSAndroid Build Coastguard Worker static double get_min_cr(const AV1LevelSpec *const level_spec, int tier,
931*77c1e3ccSAndroid Build Coastguard Worker                          int is_still_picture, int64_t decoded_sample_rate) {
932*77c1e3ccSAndroid Build Coastguard Worker   if (is_still_picture) return 0.8;
933*77c1e3ccSAndroid Build Coastguard Worker   if (level_spec->level < SEQ_LEVEL_4_0) tier = 0;
934*77c1e3ccSAndroid Build Coastguard Worker   const double min_cr_basis = tier ? level_spec->high_cr : level_spec->main_cr;
935*77c1e3ccSAndroid Build Coastguard Worker   const double speed_adj =
936*77c1e3ccSAndroid Build Coastguard Worker       (double)decoded_sample_rate / level_spec->max_display_rate;
937*77c1e3ccSAndroid Build Coastguard Worker   return AOMMAX(min_cr_basis * speed_adj, 0.8);
938*77c1e3ccSAndroid Build Coastguard Worker }
939*77c1e3ccSAndroid Build Coastguard Worker 
av1_get_min_cr_for_level(AV1_LEVEL level_index,int tier,int is_still_picture)940*77c1e3ccSAndroid Build Coastguard Worker double av1_get_min_cr_for_level(AV1_LEVEL level_index, int tier,
941*77c1e3ccSAndroid Build Coastguard Worker                                 int is_still_picture) {
942*77c1e3ccSAndroid Build Coastguard Worker   assert(is_valid_seq_level_idx(level_index));
943*77c1e3ccSAndroid Build Coastguard Worker   const AV1LevelSpec *const level_spec = &av1_level_defs[level_index];
944*77c1e3ccSAndroid Build Coastguard Worker   return get_min_cr(level_spec, tier, is_still_picture,
945*77c1e3ccSAndroid Build Coastguard Worker                     level_spec->max_decode_rate);
946*77c1e3ccSAndroid Build Coastguard Worker }
947*77c1e3ccSAndroid Build Coastguard Worker 
get_temporal_parallel_params(int scalability_mode_idc,int * temporal_parallel_num,int * temporal_parallel_denom)948*77c1e3ccSAndroid Build Coastguard Worker static void get_temporal_parallel_params(int scalability_mode_idc,
949*77c1e3ccSAndroid Build Coastguard Worker                                          int *temporal_parallel_num,
950*77c1e3ccSAndroid Build Coastguard Worker                                          int *temporal_parallel_denom) {
951*77c1e3ccSAndroid Build Coastguard Worker   if (scalability_mode_idc < 0) {
952*77c1e3ccSAndroid Build Coastguard Worker     *temporal_parallel_num = 1;
953*77c1e3ccSAndroid Build Coastguard Worker     *temporal_parallel_denom = 1;
954*77c1e3ccSAndroid Build Coastguard Worker     return;
955*77c1e3ccSAndroid Build Coastguard Worker   }
956*77c1e3ccSAndroid Build Coastguard Worker 
957*77c1e3ccSAndroid Build Coastguard Worker   // TODO(huisu@): handle scalability cases.
958*77c1e3ccSAndroid Build Coastguard Worker   if (scalability_mode_idc == SCALABILITY_SS) {
959*77c1e3ccSAndroid Build Coastguard Worker     (void)scalability_mode_idc;
960*77c1e3ccSAndroid Build Coastguard Worker   } else {
961*77c1e3ccSAndroid Build Coastguard Worker     (void)scalability_mode_idc;
962*77c1e3ccSAndroid Build Coastguard Worker   }
963*77c1e3ccSAndroid Build Coastguard Worker }
964*77c1e3ccSAndroid Build Coastguard Worker 
965*77c1e3ccSAndroid Build Coastguard Worker #define MIN_CROPPED_TILE_WIDTH 8
966*77c1e3ccSAndroid Build Coastguard Worker #define MIN_CROPPED_TILE_HEIGHT 8
967*77c1e3ccSAndroid Build Coastguard Worker #define MIN_FRAME_WIDTH 16
968*77c1e3ccSAndroid Build Coastguard Worker #define MIN_FRAME_HEIGHT 16
969*77c1e3ccSAndroid Build Coastguard Worker #define MAX_TILE_SIZE_HEADER_RATE_PRODUCT 588251136
970*77c1e3ccSAndroid Build Coastguard Worker 
check_level_constraints(const AV1LevelInfo * const level_info,AV1_LEVEL level,int tier,int is_still_picture,BITSTREAM_PROFILE profile,int check_bitrate)971*77c1e3ccSAndroid Build Coastguard Worker static TARGET_LEVEL_FAIL_ID check_level_constraints(
972*77c1e3ccSAndroid Build Coastguard Worker     const AV1LevelInfo *const level_info, AV1_LEVEL level, int tier,
973*77c1e3ccSAndroid Build Coastguard Worker     int is_still_picture, BITSTREAM_PROFILE profile, int check_bitrate) {
974*77c1e3ccSAndroid Build Coastguard Worker   const DECODER_MODEL *const decoder_model = &level_info->decoder_models[level];
975*77c1e3ccSAndroid Build Coastguard Worker   const DECODER_MODEL_STATUS decoder_model_status = decoder_model->status;
976*77c1e3ccSAndroid Build Coastguard Worker   if (decoder_model_status != DECODER_MODEL_OK &&
977*77c1e3ccSAndroid Build Coastguard Worker       decoder_model_status != DECODER_MODEL_DISABLED) {
978*77c1e3ccSAndroid Build Coastguard Worker     return DECODER_MODEL_FAIL;
979*77c1e3ccSAndroid Build Coastguard Worker   }
980*77c1e3ccSAndroid Build Coastguard Worker 
981*77c1e3ccSAndroid Build Coastguard Worker   const AV1LevelSpec *const level_spec = &level_info->level_spec;
982*77c1e3ccSAndroid Build Coastguard Worker   const AV1LevelSpec *const target_level_spec = &av1_level_defs[level];
983*77c1e3ccSAndroid Build Coastguard Worker   const AV1LevelStats *const level_stats = &level_info->level_stats;
984*77c1e3ccSAndroid Build Coastguard Worker   TARGET_LEVEL_FAIL_ID fail_id = TARGET_LEVEL_OK;
985*77c1e3ccSAndroid Build Coastguard Worker   do {
986*77c1e3ccSAndroid Build Coastguard Worker     if (level_spec->max_picture_size > target_level_spec->max_picture_size) {
987*77c1e3ccSAndroid Build Coastguard Worker       fail_id = LUMA_PIC_SIZE_TOO_LARGE;
988*77c1e3ccSAndroid Build Coastguard Worker       break;
989*77c1e3ccSAndroid Build Coastguard Worker     }
990*77c1e3ccSAndroid Build Coastguard Worker 
991*77c1e3ccSAndroid Build Coastguard Worker     if (level_spec->max_h_size > target_level_spec->max_h_size) {
992*77c1e3ccSAndroid Build Coastguard Worker       fail_id = LUMA_PIC_H_SIZE_TOO_LARGE;
993*77c1e3ccSAndroid Build Coastguard Worker       break;
994*77c1e3ccSAndroid Build Coastguard Worker     }
995*77c1e3ccSAndroid Build Coastguard Worker 
996*77c1e3ccSAndroid Build Coastguard Worker     if (level_spec->max_v_size > target_level_spec->max_v_size) {
997*77c1e3ccSAndroid Build Coastguard Worker       fail_id = LUMA_PIC_V_SIZE_TOO_LARGE;
998*77c1e3ccSAndroid Build Coastguard Worker       break;
999*77c1e3ccSAndroid Build Coastguard Worker     }
1000*77c1e3ccSAndroid Build Coastguard Worker 
1001*77c1e3ccSAndroid Build Coastguard Worker     if (level_spec->max_tile_cols > target_level_spec->max_tile_cols) {
1002*77c1e3ccSAndroid Build Coastguard Worker       fail_id = TOO_MANY_TILE_COLUMNS;
1003*77c1e3ccSAndroid Build Coastguard Worker       break;
1004*77c1e3ccSAndroid Build Coastguard Worker     }
1005*77c1e3ccSAndroid Build Coastguard Worker 
1006*77c1e3ccSAndroid Build Coastguard Worker     if (level_spec->max_tiles > target_level_spec->max_tiles) {
1007*77c1e3ccSAndroid Build Coastguard Worker       fail_id = TOO_MANY_TILES;
1008*77c1e3ccSAndroid Build Coastguard Worker       break;
1009*77c1e3ccSAndroid Build Coastguard Worker     }
1010*77c1e3ccSAndroid Build Coastguard Worker 
1011*77c1e3ccSAndroid Build Coastguard Worker     if (level_spec->max_header_rate > target_level_spec->max_header_rate) {
1012*77c1e3ccSAndroid Build Coastguard Worker       fail_id = FRAME_HEADER_RATE_TOO_HIGH;
1013*77c1e3ccSAndroid Build Coastguard Worker       break;
1014*77c1e3ccSAndroid Build Coastguard Worker     }
1015*77c1e3ccSAndroid Build Coastguard Worker 
1016*77c1e3ccSAndroid Build Coastguard Worker     if (decoder_model->max_display_rate >
1017*77c1e3ccSAndroid Build Coastguard Worker         (double)target_level_spec->max_display_rate) {
1018*77c1e3ccSAndroid Build Coastguard Worker       fail_id = DISPLAY_RATE_TOO_HIGH;
1019*77c1e3ccSAndroid Build Coastguard Worker       break;
1020*77c1e3ccSAndroid Build Coastguard Worker     }
1021*77c1e3ccSAndroid Build Coastguard Worker 
1022*77c1e3ccSAndroid Build Coastguard Worker     // TODO(huisu): we are not using max decode rate calculated by the decoder
1023*77c1e3ccSAndroid Build Coastguard Worker     // model because the model in resource availability mode always returns
1024*77c1e3ccSAndroid Build Coastguard Worker     // MaxDecodeRate(as in the level definitions) as the max decode rate.
1025*77c1e3ccSAndroid Build Coastguard Worker     if (level_spec->max_decode_rate > target_level_spec->max_decode_rate) {
1026*77c1e3ccSAndroid Build Coastguard Worker       fail_id = DECODE_RATE_TOO_HIGH;
1027*77c1e3ccSAndroid Build Coastguard Worker       break;
1028*77c1e3ccSAndroid Build Coastguard Worker     }
1029*77c1e3ccSAndroid Build Coastguard Worker 
1030*77c1e3ccSAndroid Build Coastguard Worker     if (level_spec->max_tile_rate > target_level_spec->max_tiles * 120) {
1031*77c1e3ccSAndroid Build Coastguard Worker       fail_id = TILE_RATE_TOO_HIGH;
1032*77c1e3ccSAndroid Build Coastguard Worker       break;
1033*77c1e3ccSAndroid Build Coastguard Worker     }
1034*77c1e3ccSAndroid Build Coastguard Worker 
1035*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_CWG_C013
1036*77c1e3ccSAndroid Build Coastguard Worker     const int max_tile_size = (level >= SEQ_LEVEL_7_0 && level <= SEQ_LEVEL_8_3)
1037*77c1e3ccSAndroid Build Coastguard Worker                                   ? MAX_TILE_AREA_LEVEL_7_AND_ABOVE
1038*77c1e3ccSAndroid Build Coastguard Worker                                   : MAX_TILE_AREA;
1039*77c1e3ccSAndroid Build Coastguard Worker #else
1040*77c1e3ccSAndroid Build Coastguard Worker     const int max_tile_size = MAX_TILE_AREA;
1041*77c1e3ccSAndroid Build Coastguard Worker #endif
1042*77c1e3ccSAndroid Build Coastguard Worker     if (level_stats->max_tile_size > max_tile_size) {
1043*77c1e3ccSAndroid Build Coastguard Worker       fail_id = TILE_TOO_LARGE;
1044*77c1e3ccSAndroid Build Coastguard Worker       break;
1045*77c1e3ccSAndroid Build Coastguard Worker     }
1046*77c1e3ccSAndroid Build Coastguard Worker 
1047*77c1e3ccSAndroid Build Coastguard Worker     if (level_stats->max_superres_tile_width > MAX_TILE_WIDTH) {
1048*77c1e3ccSAndroid Build Coastguard Worker       fail_id = SUPERRES_TILE_WIDTH_TOO_LARGE;
1049*77c1e3ccSAndroid Build Coastguard Worker       break;
1050*77c1e3ccSAndroid Build Coastguard Worker     }
1051*77c1e3ccSAndroid Build Coastguard Worker 
1052*77c1e3ccSAndroid Build Coastguard Worker     if (level_stats->min_cropped_tile_width < MIN_CROPPED_TILE_WIDTH) {
1053*77c1e3ccSAndroid Build Coastguard Worker       fail_id = CROPPED_TILE_WIDTH_TOO_SMALL;
1054*77c1e3ccSAndroid Build Coastguard Worker       break;
1055*77c1e3ccSAndroid Build Coastguard Worker     }
1056*77c1e3ccSAndroid Build Coastguard Worker 
1057*77c1e3ccSAndroid Build Coastguard Worker     if (level_stats->min_cropped_tile_height < MIN_CROPPED_TILE_HEIGHT) {
1058*77c1e3ccSAndroid Build Coastguard Worker       fail_id = CROPPED_TILE_HEIGHT_TOO_SMALL;
1059*77c1e3ccSAndroid Build Coastguard Worker       break;
1060*77c1e3ccSAndroid Build Coastguard Worker     }
1061*77c1e3ccSAndroid Build Coastguard Worker 
1062*77c1e3ccSAndroid Build Coastguard Worker     if (level_stats->min_frame_width < MIN_FRAME_WIDTH) {
1063*77c1e3ccSAndroid Build Coastguard Worker       fail_id = LUMA_PIC_H_SIZE_TOO_SMALL;
1064*77c1e3ccSAndroid Build Coastguard Worker       break;
1065*77c1e3ccSAndroid Build Coastguard Worker     }
1066*77c1e3ccSAndroid Build Coastguard Worker 
1067*77c1e3ccSAndroid Build Coastguard Worker     if (level_stats->min_frame_height < MIN_FRAME_HEIGHT) {
1068*77c1e3ccSAndroid Build Coastguard Worker       fail_id = LUMA_PIC_V_SIZE_TOO_SMALL;
1069*77c1e3ccSAndroid Build Coastguard Worker       break;
1070*77c1e3ccSAndroid Build Coastguard Worker     }
1071*77c1e3ccSAndroid Build Coastguard Worker 
1072*77c1e3ccSAndroid Build Coastguard Worker     if (!level_stats->tile_width_is_valid) {
1073*77c1e3ccSAndroid Build Coastguard Worker       fail_id = TILE_WIDTH_INVALID;
1074*77c1e3ccSAndroid Build Coastguard Worker       break;
1075*77c1e3ccSAndroid Build Coastguard Worker     }
1076*77c1e3ccSAndroid Build Coastguard Worker 
1077*77c1e3ccSAndroid Build Coastguard Worker     const double min_cr = get_min_cr(target_level_spec, tier, is_still_picture,
1078*77c1e3ccSAndroid Build Coastguard Worker                                      level_spec->max_decode_rate);
1079*77c1e3ccSAndroid Build Coastguard Worker     if (level_stats->min_cr < min_cr) {
1080*77c1e3ccSAndroid Build Coastguard Worker       fail_id = CR_TOO_SMALL;
1081*77c1e3ccSAndroid Build Coastguard Worker       break;
1082*77c1e3ccSAndroid Build Coastguard Worker     }
1083*77c1e3ccSAndroid Build Coastguard Worker 
1084*77c1e3ccSAndroid Build Coastguard Worker     if (check_bitrate) {
1085*77c1e3ccSAndroid Build Coastguard Worker       // Check average bitrate instead of max_bitrate.
1086*77c1e3ccSAndroid Build Coastguard Worker       const double bitrate_limit =
1087*77c1e3ccSAndroid Build Coastguard Worker           get_max_bitrate(target_level_spec, tier, profile);
1088*77c1e3ccSAndroid Build Coastguard Worker       const double avg_bitrate = level_stats->total_compressed_size * 8.0 /
1089*77c1e3ccSAndroid Build Coastguard Worker                                  level_stats->total_time_encoded;
1090*77c1e3ccSAndroid Build Coastguard Worker       if (avg_bitrate > bitrate_limit) {
1091*77c1e3ccSAndroid Build Coastguard Worker         fail_id = BITRATE_TOO_HIGH;
1092*77c1e3ccSAndroid Build Coastguard Worker         break;
1093*77c1e3ccSAndroid Build Coastguard Worker       }
1094*77c1e3ccSAndroid Build Coastguard Worker     }
1095*77c1e3ccSAndroid Build Coastguard Worker 
1096*77c1e3ccSAndroid Build Coastguard Worker     if (target_level_spec->level > SEQ_LEVEL_5_1) {
1097*77c1e3ccSAndroid Build Coastguard Worker       int temporal_parallel_num;
1098*77c1e3ccSAndroid Build Coastguard Worker       int temporal_parallel_denom;
1099*77c1e3ccSAndroid Build Coastguard Worker       const int scalability_mode_idc = -1;
1100*77c1e3ccSAndroid Build Coastguard Worker       get_temporal_parallel_params(scalability_mode_idc, &temporal_parallel_num,
1101*77c1e3ccSAndroid Build Coastguard Worker                                    &temporal_parallel_denom);
1102*77c1e3ccSAndroid Build Coastguard Worker       const int val = level_stats->max_tile_size * level_spec->max_header_rate *
1103*77c1e3ccSAndroid Build Coastguard Worker                       temporal_parallel_denom / temporal_parallel_num;
1104*77c1e3ccSAndroid Build Coastguard Worker       if (val > MAX_TILE_SIZE_HEADER_RATE_PRODUCT) {
1105*77c1e3ccSAndroid Build Coastguard Worker         fail_id = TILE_SIZE_HEADER_RATE_TOO_HIGH;
1106*77c1e3ccSAndroid Build Coastguard Worker         break;
1107*77c1e3ccSAndroid Build Coastguard Worker       }
1108*77c1e3ccSAndroid Build Coastguard Worker     }
1109*77c1e3ccSAndroid Build Coastguard Worker   } while (0);
1110*77c1e3ccSAndroid Build Coastguard Worker 
1111*77c1e3ccSAndroid Build Coastguard Worker   return fail_id;
1112*77c1e3ccSAndroid Build Coastguard Worker }
1113*77c1e3ccSAndroid Build Coastguard Worker 
get_tile_stats(const AV1_COMMON * const cm,const TileDataEnc * const tile_data,int * max_tile_size,int * max_superres_tile_width,int * min_cropped_tile_width,int * min_cropped_tile_height,int * tile_width_valid)1114*77c1e3ccSAndroid Build Coastguard Worker static void get_tile_stats(const AV1_COMMON *const cm,
1115*77c1e3ccSAndroid Build Coastguard Worker                            const TileDataEnc *const tile_data,
1116*77c1e3ccSAndroid Build Coastguard Worker                            int *max_tile_size, int *max_superres_tile_width,
1117*77c1e3ccSAndroid Build Coastguard Worker                            int *min_cropped_tile_width,
1118*77c1e3ccSAndroid Build Coastguard Worker                            int *min_cropped_tile_height,
1119*77c1e3ccSAndroid Build Coastguard Worker                            int *tile_width_valid) {
1120*77c1e3ccSAndroid Build Coastguard Worker   const int tile_cols = cm->tiles.cols;
1121*77c1e3ccSAndroid Build Coastguard Worker   const int tile_rows = cm->tiles.rows;
1122*77c1e3ccSAndroid Build Coastguard Worker   const int superres_scale_denominator = cm->superres_scale_denominator;
1123*77c1e3ccSAndroid Build Coastguard Worker 
1124*77c1e3ccSAndroid Build Coastguard Worker   *max_tile_size = 0;
1125*77c1e3ccSAndroid Build Coastguard Worker   *max_superres_tile_width = 0;
1126*77c1e3ccSAndroid Build Coastguard Worker   *min_cropped_tile_width = INT_MAX;
1127*77c1e3ccSAndroid Build Coastguard Worker   *min_cropped_tile_height = INT_MAX;
1128*77c1e3ccSAndroid Build Coastguard Worker   *tile_width_valid = 1;
1129*77c1e3ccSAndroid Build Coastguard Worker 
1130*77c1e3ccSAndroid Build Coastguard Worker   for (int tile_row = 0; tile_row < tile_rows; ++tile_row) {
1131*77c1e3ccSAndroid Build Coastguard Worker     for (int tile_col = 0; tile_col < tile_cols; ++tile_col) {
1132*77c1e3ccSAndroid Build Coastguard Worker       const TileInfo *const tile_info =
1133*77c1e3ccSAndroid Build Coastguard Worker           &tile_data[tile_row * cm->tiles.cols + tile_col].tile_info;
1134*77c1e3ccSAndroid Build Coastguard Worker       const int tile_width =
1135*77c1e3ccSAndroid Build Coastguard Worker           (tile_info->mi_col_end - tile_info->mi_col_start) * MI_SIZE;
1136*77c1e3ccSAndroid Build Coastguard Worker       const int tile_height =
1137*77c1e3ccSAndroid Build Coastguard Worker           (tile_info->mi_row_end - tile_info->mi_row_start) * MI_SIZE;
1138*77c1e3ccSAndroid Build Coastguard Worker       const int tile_size = tile_width * tile_height;
1139*77c1e3ccSAndroid Build Coastguard Worker       *max_tile_size = AOMMAX(*max_tile_size, tile_size);
1140*77c1e3ccSAndroid Build Coastguard Worker 
1141*77c1e3ccSAndroid Build Coastguard Worker       const int supperres_tile_width =
1142*77c1e3ccSAndroid Build Coastguard Worker           tile_width * superres_scale_denominator / SCALE_NUMERATOR;
1143*77c1e3ccSAndroid Build Coastguard Worker       *max_superres_tile_width =
1144*77c1e3ccSAndroid Build Coastguard Worker           AOMMAX(*max_superres_tile_width, supperres_tile_width);
1145*77c1e3ccSAndroid Build Coastguard Worker 
1146*77c1e3ccSAndroid Build Coastguard Worker       const int cropped_tile_width =
1147*77c1e3ccSAndroid Build Coastguard Worker           cm->width - tile_info->mi_col_start * MI_SIZE;
1148*77c1e3ccSAndroid Build Coastguard Worker       const int cropped_tile_height =
1149*77c1e3ccSAndroid Build Coastguard Worker           cm->height - tile_info->mi_row_start * MI_SIZE;
1150*77c1e3ccSAndroid Build Coastguard Worker       *min_cropped_tile_width =
1151*77c1e3ccSAndroid Build Coastguard Worker           AOMMIN(*min_cropped_tile_width, cropped_tile_width);
1152*77c1e3ccSAndroid Build Coastguard Worker       *min_cropped_tile_height =
1153*77c1e3ccSAndroid Build Coastguard Worker           AOMMIN(*min_cropped_tile_height, cropped_tile_height);
1154*77c1e3ccSAndroid Build Coastguard Worker 
1155*77c1e3ccSAndroid Build Coastguard Worker       const int is_right_most_tile =
1156*77c1e3ccSAndroid Build Coastguard Worker           tile_info->mi_col_end == cm->mi_params.mi_cols;
1157*77c1e3ccSAndroid Build Coastguard Worker       if (!is_right_most_tile) {
1158*77c1e3ccSAndroid Build Coastguard Worker         if (av1_superres_scaled(cm))
1159*77c1e3ccSAndroid Build Coastguard Worker           *tile_width_valid &= tile_width >= 128;
1160*77c1e3ccSAndroid Build Coastguard Worker         else
1161*77c1e3ccSAndroid Build Coastguard Worker           *tile_width_valid &= tile_width >= 64;
1162*77c1e3ccSAndroid Build Coastguard Worker       }
1163*77c1e3ccSAndroid Build Coastguard Worker     }
1164*77c1e3ccSAndroid Build Coastguard Worker   }
1165*77c1e3ccSAndroid Build Coastguard Worker }
1166*77c1e3ccSAndroid Build Coastguard Worker 
store_frame_record(int64_t ts_start,int64_t ts_end,size_t encoded_size,int pic_size,int frame_header_count,int tiles,int show_frame,int show_existing_frame,FrameWindowBuffer * const buffer)1167*77c1e3ccSAndroid Build Coastguard Worker static int store_frame_record(int64_t ts_start, int64_t ts_end,
1168*77c1e3ccSAndroid Build Coastguard Worker                               size_t encoded_size, int pic_size,
1169*77c1e3ccSAndroid Build Coastguard Worker                               int frame_header_count, int tiles, int show_frame,
1170*77c1e3ccSAndroid Build Coastguard Worker                               int show_existing_frame,
1171*77c1e3ccSAndroid Build Coastguard Worker                               FrameWindowBuffer *const buffer) {
1172*77c1e3ccSAndroid Build Coastguard Worker   if (buffer->num < FRAME_WINDOW_SIZE) {
1173*77c1e3ccSAndroid Build Coastguard Worker     ++buffer->num;
1174*77c1e3ccSAndroid Build Coastguard Worker   } else {
1175*77c1e3ccSAndroid Build Coastguard Worker     buffer->start = (buffer->start + 1) % FRAME_WINDOW_SIZE;
1176*77c1e3ccSAndroid Build Coastguard Worker   }
1177*77c1e3ccSAndroid Build Coastguard Worker   const int new_idx = (buffer->start + buffer->num - 1) % FRAME_WINDOW_SIZE;
1178*77c1e3ccSAndroid Build Coastguard Worker   FrameRecord *const record = &buffer->buf[new_idx];
1179*77c1e3ccSAndroid Build Coastguard Worker   record->ts_start = ts_start;
1180*77c1e3ccSAndroid Build Coastguard Worker   record->ts_end = ts_end;
1181*77c1e3ccSAndroid Build Coastguard Worker   record->encoded_size_in_bytes = encoded_size;
1182*77c1e3ccSAndroid Build Coastguard Worker   record->pic_size = pic_size;
1183*77c1e3ccSAndroid Build Coastguard Worker   record->frame_header_count = frame_header_count;
1184*77c1e3ccSAndroid Build Coastguard Worker   record->tiles = tiles;
1185*77c1e3ccSAndroid Build Coastguard Worker   record->show_frame = show_frame;
1186*77c1e3ccSAndroid Build Coastguard Worker   record->show_existing_frame = show_existing_frame;
1187*77c1e3ccSAndroid Build Coastguard Worker 
1188*77c1e3ccSAndroid Build Coastguard Worker   return new_idx;
1189*77c1e3ccSAndroid Build Coastguard Worker }
1190*77c1e3ccSAndroid Build Coastguard Worker 
1191*77c1e3ccSAndroid Build Coastguard Worker // Count the number of frames encoded in the last "duration" ticks, in display
1192*77c1e3ccSAndroid Build Coastguard Worker // time.
count_frames(const FrameWindowBuffer * const buffer,int64_t duration)1193*77c1e3ccSAndroid Build Coastguard Worker static int count_frames(const FrameWindowBuffer *const buffer,
1194*77c1e3ccSAndroid Build Coastguard Worker                         int64_t duration) {
1195*77c1e3ccSAndroid Build Coastguard Worker   const int current_idx = (buffer->start + buffer->num - 1) % FRAME_WINDOW_SIZE;
1196*77c1e3ccSAndroid Build Coastguard Worker   // Assume current frame is shown frame.
1197*77c1e3ccSAndroid Build Coastguard Worker   assert(buffer->buf[current_idx].show_frame);
1198*77c1e3ccSAndroid Build Coastguard Worker 
1199*77c1e3ccSAndroid Build Coastguard Worker   const int64_t current_time = buffer->buf[current_idx].ts_end;
1200*77c1e3ccSAndroid Build Coastguard Worker   const int64_t time_limit = AOMMAX(current_time - duration, 0);
1201*77c1e3ccSAndroid Build Coastguard Worker   int num_frames = 1;
1202*77c1e3ccSAndroid Build Coastguard Worker   int index = current_idx - 1;
1203*77c1e3ccSAndroid Build Coastguard Worker   for (int i = buffer->num - 2; i >= 0; --i, --index, ++num_frames) {
1204*77c1e3ccSAndroid Build Coastguard Worker     if (index < 0) index = FRAME_WINDOW_SIZE - 1;
1205*77c1e3ccSAndroid Build Coastguard Worker     const FrameRecord *const record = &buffer->buf[index];
1206*77c1e3ccSAndroid Build Coastguard Worker     if (!record->show_frame) continue;
1207*77c1e3ccSAndroid Build Coastguard Worker     const int64_t ts_start = record->ts_start;
1208*77c1e3ccSAndroid Build Coastguard Worker     if (ts_start < time_limit) break;
1209*77c1e3ccSAndroid Build Coastguard Worker   }
1210*77c1e3ccSAndroid Build Coastguard Worker 
1211*77c1e3ccSAndroid Build Coastguard Worker   return num_frames;
1212*77c1e3ccSAndroid Build Coastguard Worker }
1213*77c1e3ccSAndroid Build Coastguard Worker 
1214*77c1e3ccSAndroid Build Coastguard Worker // Scan previously encoded frames and update level metrics accordingly.
scan_past_frames(const FrameWindowBuffer * const buffer,int num_frames_to_scan,AV1LevelSpec * const level_spec,AV1LevelStats * const level_stats)1215*77c1e3ccSAndroid Build Coastguard Worker static void scan_past_frames(const FrameWindowBuffer *const buffer,
1216*77c1e3ccSAndroid Build Coastguard Worker                              int num_frames_to_scan,
1217*77c1e3ccSAndroid Build Coastguard Worker                              AV1LevelSpec *const level_spec,
1218*77c1e3ccSAndroid Build Coastguard Worker                              AV1LevelStats *const level_stats) {
1219*77c1e3ccSAndroid Build Coastguard Worker   const int num_frames_in_buffer = buffer->num;
1220*77c1e3ccSAndroid Build Coastguard Worker   int index = (buffer->start + num_frames_in_buffer - 1) % FRAME_WINDOW_SIZE;
1221*77c1e3ccSAndroid Build Coastguard Worker   int frame_headers = 0;
1222*77c1e3ccSAndroid Build Coastguard Worker   int tiles = 0;
1223*77c1e3ccSAndroid Build Coastguard Worker   int64_t display_samples = 0;
1224*77c1e3ccSAndroid Build Coastguard Worker   int64_t decoded_samples = 0;
1225*77c1e3ccSAndroid Build Coastguard Worker   size_t encoded_size_in_bytes = 0;
1226*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < AOMMIN(num_frames_in_buffer, num_frames_to_scan); ++i) {
1227*77c1e3ccSAndroid Build Coastguard Worker     const FrameRecord *const record = &buffer->buf[index];
1228*77c1e3ccSAndroid Build Coastguard Worker     if (!record->show_existing_frame) {
1229*77c1e3ccSAndroid Build Coastguard Worker       frame_headers += record->frame_header_count;
1230*77c1e3ccSAndroid Build Coastguard Worker       decoded_samples += record->pic_size;
1231*77c1e3ccSAndroid Build Coastguard Worker     }
1232*77c1e3ccSAndroid Build Coastguard Worker     if (record->show_frame) {
1233*77c1e3ccSAndroid Build Coastguard Worker       display_samples += record->pic_size;
1234*77c1e3ccSAndroid Build Coastguard Worker     }
1235*77c1e3ccSAndroid Build Coastguard Worker     tiles += record->tiles;
1236*77c1e3ccSAndroid Build Coastguard Worker     encoded_size_in_bytes += record->encoded_size_in_bytes;
1237*77c1e3ccSAndroid Build Coastguard Worker     --index;
1238*77c1e3ccSAndroid Build Coastguard Worker     if (index < 0) index = FRAME_WINDOW_SIZE - 1;
1239*77c1e3ccSAndroid Build Coastguard Worker   }
1240*77c1e3ccSAndroid Build Coastguard Worker   level_spec->max_header_rate =
1241*77c1e3ccSAndroid Build Coastguard Worker       AOMMAX(level_spec->max_header_rate, frame_headers);
1242*77c1e3ccSAndroid Build Coastguard Worker   // TODO(huisu): we can now compute max display rate with the decoder model, so
1243*77c1e3ccSAndroid Build Coastguard Worker   // these couple of lines can be removed. Keep them here for a while for
1244*77c1e3ccSAndroid Build Coastguard Worker   // debugging purpose.
1245*77c1e3ccSAndroid Build Coastguard Worker   level_spec->max_display_rate =
1246*77c1e3ccSAndroid Build Coastguard Worker       AOMMAX(level_spec->max_display_rate, display_samples);
1247*77c1e3ccSAndroid Build Coastguard Worker   level_spec->max_decode_rate =
1248*77c1e3ccSAndroid Build Coastguard Worker       AOMMAX(level_spec->max_decode_rate, decoded_samples);
1249*77c1e3ccSAndroid Build Coastguard Worker   level_spec->max_tile_rate = AOMMAX(level_spec->max_tile_rate, tiles);
1250*77c1e3ccSAndroid Build Coastguard Worker   level_stats->max_bitrate =
1251*77c1e3ccSAndroid Build Coastguard Worker       AOMMAX(level_stats->max_bitrate,
1252*77c1e3ccSAndroid Build Coastguard Worker              (int)AOMMIN(encoded_size_in_bytes * 8, (size_t)INT_MAX));
1253*77c1e3ccSAndroid Build Coastguard Worker }
1254*77c1e3ccSAndroid Build Coastguard Worker 
av1_update_level_info(AV1_COMP * cpi,size_t size,int64_t ts_start,int64_t ts_end)1255*77c1e3ccSAndroid Build Coastguard Worker void av1_update_level_info(AV1_COMP *cpi, size_t size, int64_t ts_start,
1256*77c1e3ccSAndroid Build Coastguard Worker                            int64_t ts_end) {
1257*77c1e3ccSAndroid Build Coastguard Worker   AV1_COMMON *const cm = &cpi->common;
1258*77c1e3ccSAndroid Build Coastguard Worker   const AV1LevelParams *const level_params = &cpi->ppi->level_params;
1259*77c1e3ccSAndroid Build Coastguard Worker 
1260*77c1e3ccSAndroid Build Coastguard Worker   const int upscaled_width = cm->superres_upscaled_width;
1261*77c1e3ccSAndroid Build Coastguard Worker   const int width = cm->width;
1262*77c1e3ccSAndroid Build Coastguard Worker   const int height = cm->height;
1263*77c1e3ccSAndroid Build Coastguard Worker   const int tile_cols = cm->tiles.cols;
1264*77c1e3ccSAndroid Build Coastguard Worker   const int tile_rows = cm->tiles.rows;
1265*77c1e3ccSAndroid Build Coastguard Worker   const int tiles = tile_cols * tile_rows;
1266*77c1e3ccSAndroid Build Coastguard Worker   const int luma_pic_size = upscaled_width * height;
1267*77c1e3ccSAndroid Build Coastguard Worker   const int frame_header_count = cpi->frame_header_count;
1268*77c1e3ccSAndroid Build Coastguard Worker   const int show_frame = cm->show_frame;
1269*77c1e3ccSAndroid Build Coastguard Worker   const int show_existing_frame = cm->show_existing_frame;
1270*77c1e3ccSAndroid Build Coastguard Worker 
1271*77c1e3ccSAndroid Build Coastguard Worker   int max_tile_size;
1272*77c1e3ccSAndroid Build Coastguard Worker   int min_cropped_tile_width;
1273*77c1e3ccSAndroid Build Coastguard Worker   int min_cropped_tile_height;
1274*77c1e3ccSAndroid Build Coastguard Worker   int max_superres_tile_width;
1275*77c1e3ccSAndroid Build Coastguard Worker   int tile_width_is_valid;
1276*77c1e3ccSAndroid Build Coastguard Worker   get_tile_stats(cm, cpi->tile_data, &max_tile_size, &max_superres_tile_width,
1277*77c1e3ccSAndroid Build Coastguard Worker                  &min_cropped_tile_width, &min_cropped_tile_height,
1278*77c1e3ccSAndroid Build Coastguard Worker                  &tile_width_is_valid);
1279*77c1e3ccSAndroid Build Coastguard Worker 
1280*77c1e3ccSAndroid Build Coastguard Worker   const double compression_ratio = av1_get_compression_ratio(cm, size);
1281*77c1e3ccSAndroid Build Coastguard Worker 
1282*77c1e3ccSAndroid Build Coastguard Worker   const int temporal_layer_id = cm->temporal_layer_id;
1283*77c1e3ccSAndroid Build Coastguard Worker   const int spatial_layer_id = cm->spatial_layer_id;
1284*77c1e3ccSAndroid Build Coastguard Worker   const SequenceHeader *const seq_params = cm->seq_params;
1285*77c1e3ccSAndroid Build Coastguard Worker   const BITSTREAM_PROFILE profile = seq_params->profile;
1286*77c1e3ccSAndroid Build Coastguard Worker   const int is_still_picture = seq_params->still_picture;
1287*77c1e3ccSAndroid Build Coastguard Worker   // update level_stats
1288*77c1e3ccSAndroid Build Coastguard Worker   // TODO(kyslov@) fix the implementation according to buffer model
1289*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < seq_params->operating_points_cnt_minus_1 + 1; ++i) {
1290*77c1e3ccSAndroid Build Coastguard Worker     if (!is_in_operating_point(seq_params->operating_point_idc[i],
1291*77c1e3ccSAndroid Build Coastguard Worker                                temporal_layer_id, spatial_layer_id) ||
1292*77c1e3ccSAndroid Build Coastguard Worker         !((level_params->keep_level_stats >> i) & 1)) {
1293*77c1e3ccSAndroid Build Coastguard Worker       continue;
1294*77c1e3ccSAndroid Build Coastguard Worker     }
1295*77c1e3ccSAndroid Build Coastguard Worker 
1296*77c1e3ccSAndroid Build Coastguard Worker     AV1LevelInfo *const level_info = level_params->level_info[i];
1297*77c1e3ccSAndroid Build Coastguard Worker     assert(level_info != NULL);
1298*77c1e3ccSAndroid Build Coastguard Worker     AV1LevelStats *const level_stats = &level_info->level_stats;
1299*77c1e3ccSAndroid Build Coastguard Worker 
1300*77c1e3ccSAndroid Build Coastguard Worker     level_stats->max_tile_size =
1301*77c1e3ccSAndroid Build Coastguard Worker         AOMMAX(level_stats->max_tile_size, max_tile_size);
1302*77c1e3ccSAndroid Build Coastguard Worker     level_stats->max_superres_tile_width =
1303*77c1e3ccSAndroid Build Coastguard Worker         AOMMAX(level_stats->max_superres_tile_width, max_superres_tile_width);
1304*77c1e3ccSAndroid Build Coastguard Worker     level_stats->min_cropped_tile_width =
1305*77c1e3ccSAndroid Build Coastguard Worker         AOMMIN(level_stats->min_cropped_tile_width, min_cropped_tile_width);
1306*77c1e3ccSAndroid Build Coastguard Worker     level_stats->min_cropped_tile_height =
1307*77c1e3ccSAndroid Build Coastguard Worker         AOMMIN(level_stats->min_cropped_tile_height, min_cropped_tile_height);
1308*77c1e3ccSAndroid Build Coastguard Worker     level_stats->tile_width_is_valid &= tile_width_is_valid;
1309*77c1e3ccSAndroid Build Coastguard Worker     level_stats->min_frame_width = AOMMIN(level_stats->min_frame_width, width);
1310*77c1e3ccSAndroid Build Coastguard Worker     level_stats->min_frame_height =
1311*77c1e3ccSAndroid Build Coastguard Worker         AOMMIN(level_stats->min_frame_height, height);
1312*77c1e3ccSAndroid Build Coastguard Worker     level_stats->min_cr = AOMMIN(level_stats->min_cr, compression_ratio);
1313*77c1e3ccSAndroid Build Coastguard Worker     level_stats->total_compressed_size += (double)size;
1314*77c1e3ccSAndroid Build Coastguard Worker 
1315*77c1e3ccSAndroid Build Coastguard Worker     // update level_spec
1316*77c1e3ccSAndroid Build Coastguard Worker     // TODO(kyslov@) update all spec fields
1317*77c1e3ccSAndroid Build Coastguard Worker     AV1LevelSpec *const level_spec = &level_info->level_spec;
1318*77c1e3ccSAndroid Build Coastguard Worker     level_spec->max_picture_size =
1319*77c1e3ccSAndroid Build Coastguard Worker         AOMMAX(level_spec->max_picture_size, luma_pic_size);
1320*77c1e3ccSAndroid Build Coastguard Worker     level_spec->max_h_size =
1321*77c1e3ccSAndroid Build Coastguard Worker         AOMMAX(level_spec->max_h_size, cm->superres_upscaled_width);
1322*77c1e3ccSAndroid Build Coastguard Worker     level_spec->max_v_size = AOMMAX(level_spec->max_v_size, height);
1323*77c1e3ccSAndroid Build Coastguard Worker     level_spec->max_tile_cols = AOMMAX(level_spec->max_tile_cols, tile_cols);
1324*77c1e3ccSAndroid Build Coastguard Worker     level_spec->max_tiles = AOMMAX(level_spec->max_tiles, tiles);
1325*77c1e3ccSAndroid Build Coastguard Worker 
1326*77c1e3ccSAndroid Build Coastguard Worker     // Store info. of current frame into FrameWindowBuffer.
1327*77c1e3ccSAndroid Build Coastguard Worker     FrameWindowBuffer *const buffer = &level_info->frame_window_buffer;
1328*77c1e3ccSAndroid Build Coastguard Worker     store_frame_record(ts_start, ts_end, size, luma_pic_size,
1329*77c1e3ccSAndroid Build Coastguard Worker                        frame_header_count, tiles, show_frame,
1330*77c1e3ccSAndroid Build Coastguard Worker                        show_existing_frame, buffer);
1331*77c1e3ccSAndroid Build Coastguard Worker     if (show_frame) {
1332*77c1e3ccSAndroid Build Coastguard Worker       // Count the number of frames encoded in the past 1 second.
1333*77c1e3ccSAndroid Build Coastguard Worker       const int encoded_frames_in_last_second =
1334*77c1e3ccSAndroid Build Coastguard Worker           show_frame ? count_frames(buffer, TICKS_PER_SEC) : 0;
1335*77c1e3ccSAndroid Build Coastguard Worker       scan_past_frames(buffer, encoded_frames_in_last_second, level_spec,
1336*77c1e3ccSAndroid Build Coastguard Worker                        level_stats);
1337*77c1e3ccSAndroid Build Coastguard Worker       level_stats->total_time_encoded +=
1338*77c1e3ccSAndroid Build Coastguard Worker           (cpi->time_stamps.prev_ts_end - cpi->time_stamps.prev_ts_start) /
1339*77c1e3ccSAndroid Build Coastguard Worker           (double)TICKS_PER_SEC;
1340*77c1e3ccSAndroid Build Coastguard Worker     }
1341*77c1e3ccSAndroid Build Coastguard Worker 
1342*77c1e3ccSAndroid Build Coastguard Worker     DECODER_MODEL *const decoder_models = level_info->decoder_models;
1343*77c1e3ccSAndroid Build Coastguard Worker     for (AV1_LEVEL level = SEQ_LEVEL_2_0; level < SEQ_LEVELS; ++level) {
1344*77c1e3ccSAndroid Build Coastguard Worker       decoder_model_process_frame(cpi, size << 3, &decoder_models[level]);
1345*77c1e3ccSAndroid Build Coastguard Worker     }
1346*77c1e3ccSAndroid Build Coastguard Worker 
1347*77c1e3ccSAndroid Build Coastguard Worker     // Check whether target level is met.
1348*77c1e3ccSAndroid Build Coastguard Worker     const AV1_LEVEL target_level = level_params->target_seq_level_idx[i];
1349*77c1e3ccSAndroid Build Coastguard Worker     if (target_level < SEQ_LEVELS && cpi->oxcf.strict_level_conformance) {
1350*77c1e3ccSAndroid Build Coastguard Worker       assert(is_valid_seq_level_idx(target_level));
1351*77c1e3ccSAndroid Build Coastguard Worker       const int tier = seq_params->tier[i];
1352*77c1e3ccSAndroid Build Coastguard Worker       const TARGET_LEVEL_FAIL_ID fail_id = check_level_constraints(
1353*77c1e3ccSAndroid Build Coastguard Worker           level_info, target_level, tier, is_still_picture, profile, 0);
1354*77c1e3ccSAndroid Build Coastguard Worker       if (fail_id != TARGET_LEVEL_OK) {
1355*77c1e3ccSAndroid Build Coastguard Worker         const int target_level_major = 2 + (target_level >> 2);
1356*77c1e3ccSAndroid Build Coastguard Worker         const int target_level_minor = target_level & 3;
1357*77c1e3ccSAndroid Build Coastguard Worker         aom_internal_error(cm->error, AOM_CODEC_ERROR,
1358*77c1e3ccSAndroid Build Coastguard Worker                            "Failed to encode to the target level %d_%d. %s",
1359*77c1e3ccSAndroid Build Coastguard Worker                            target_level_major, target_level_minor,
1360*77c1e3ccSAndroid Build Coastguard Worker                            level_fail_messages[fail_id]);
1361*77c1e3ccSAndroid Build Coastguard Worker       }
1362*77c1e3ccSAndroid Build Coastguard Worker     }
1363*77c1e3ccSAndroid Build Coastguard Worker   }
1364*77c1e3ccSAndroid Build Coastguard Worker }
1365*77c1e3ccSAndroid Build Coastguard Worker 
av1_get_seq_level_idx(const SequenceHeader * seq_params,const AV1LevelParams * level_params,int * seq_level_idx)1366*77c1e3ccSAndroid Build Coastguard Worker aom_codec_err_t av1_get_seq_level_idx(const SequenceHeader *seq_params,
1367*77c1e3ccSAndroid Build Coastguard Worker                                       const AV1LevelParams *level_params,
1368*77c1e3ccSAndroid Build Coastguard Worker                                       int *seq_level_idx) {
1369*77c1e3ccSAndroid Build Coastguard Worker   const int is_still_picture = seq_params->still_picture;
1370*77c1e3ccSAndroid Build Coastguard Worker   const BITSTREAM_PROFILE profile = seq_params->profile;
1371*77c1e3ccSAndroid Build Coastguard Worker   for (int op = 0; op < seq_params->operating_points_cnt_minus_1 + 1; ++op) {
1372*77c1e3ccSAndroid Build Coastguard Worker     seq_level_idx[op] = (int)SEQ_LEVEL_MAX;
1373*77c1e3ccSAndroid Build Coastguard Worker     if (!((level_params->keep_level_stats >> op) & 1)) continue;
1374*77c1e3ccSAndroid Build Coastguard Worker     const int tier = seq_params->tier[op];
1375*77c1e3ccSAndroid Build Coastguard Worker     const AV1LevelInfo *const level_info = level_params->level_info[op];
1376*77c1e3ccSAndroid Build Coastguard Worker     assert(level_info != NULL);
1377*77c1e3ccSAndroid Build Coastguard Worker     for (int level = 0; level < SEQ_LEVELS; ++level) {
1378*77c1e3ccSAndroid Build Coastguard Worker       if (!is_valid_seq_level_idx(level)) continue;
1379*77c1e3ccSAndroid Build Coastguard Worker       const TARGET_LEVEL_FAIL_ID fail_id = check_level_constraints(
1380*77c1e3ccSAndroid Build Coastguard Worker           level_info, level, tier, is_still_picture, profile, 1);
1381*77c1e3ccSAndroid Build Coastguard Worker       if (fail_id == TARGET_LEVEL_OK) {
1382*77c1e3ccSAndroid Build Coastguard Worker         seq_level_idx[op] = level;
1383*77c1e3ccSAndroid Build Coastguard Worker         break;
1384*77c1e3ccSAndroid Build Coastguard Worker       }
1385*77c1e3ccSAndroid Build Coastguard Worker     }
1386*77c1e3ccSAndroid Build Coastguard Worker   }
1387*77c1e3ccSAndroid Build Coastguard Worker 
1388*77c1e3ccSAndroid Build Coastguard Worker   return AOM_CODEC_OK;
1389*77c1e3ccSAndroid Build Coastguard Worker }
1390*77c1e3ccSAndroid Build Coastguard Worker 
av1_get_target_seq_level_idx(const SequenceHeader * seq_params,const AV1LevelParams * level_params,int * target_seq_level_idx)1391*77c1e3ccSAndroid Build Coastguard Worker aom_codec_err_t av1_get_target_seq_level_idx(const SequenceHeader *seq_params,
1392*77c1e3ccSAndroid Build Coastguard Worker                                              const AV1LevelParams *level_params,
1393*77c1e3ccSAndroid Build Coastguard Worker                                              int *target_seq_level_idx) {
1394*77c1e3ccSAndroid Build Coastguard Worker   for (int op = 0; op < seq_params->operating_points_cnt_minus_1 + 1; ++op) {
1395*77c1e3ccSAndroid Build Coastguard Worker     target_seq_level_idx[op] = (int)SEQ_LEVEL_MAX;
1396*77c1e3ccSAndroid Build Coastguard Worker     if (!((level_params->keep_level_stats >> op) & 1)) continue;
1397*77c1e3ccSAndroid Build Coastguard Worker     target_seq_level_idx[op] = level_params->target_seq_level_idx[op];
1398*77c1e3ccSAndroid Build Coastguard Worker   }
1399*77c1e3ccSAndroid Build Coastguard Worker 
1400*77c1e3ccSAndroid Build Coastguard Worker   return AOM_CODEC_OK;
1401*77c1e3ccSAndroid Build Coastguard Worker }
1402