1use std::fmt;
2
3use crate::common::ProfileConstraint;
4use yuv::color::ChromaSampling;
5use yuv::color::Depth;
6
7#[derive(Debug)]
8pub struct LevelSelector {
9 width: u32,
11 height: u32,
12 framerate: f32,
13 tier: Tier,
14 profile: Profile,
15 min_level: Option<Level>,
16 max_level: Option<Level>,
17 max_bitrate: Option<u32>,
18}
19
20impl LevelSelector {
21 pub fn new() -> Self {
22 Self {
23 width: 1920,
25 height: 1080,
26 framerate: 30.0,
27 tier: Tier::Main,
28 profile: Profile::Main,
29 min_level: None,
31 max_level: None,
32 max_bitrate: None,
33 }
34 }
35 pub fn width(mut self, width: u32) -> Self {
36 self.width = width;
37 self
38 }
39 pub fn height(mut self, height: u32) -> Self {
40 self.height = height;
41 self
42 }
43 pub fn framerate(mut self, framerate: f32) -> Self {
44 self.framerate = framerate;
45 self
46 }
47 pub fn clamp(mut self, min: Level, max: Level) -> Self {
48 self.min_level = Some(min);
49 self.max_level = Some(max);
50 self
51 }
52 pub fn max_bitrate(mut self, max_bitrate: u32) -> Self {
53 self.max_bitrate = Some(max_bitrate);
54 self
55 }
56 pub fn tier(mut self, tier: Tier) -> Self {
57 self.tier = tier;
58 self
59 }
60 pub fn profile(mut self, profile: Profile) -> Self {
61 self.profile = profile;
62 self
63 }
64
65 pub fn select(self) -> Option<LevelSpecification> {
66 let samples = self.width * self.height;
67 let display_rate = (samples as f64 * self.framerate as f64) as u64;
68
69 for level in LEVEL_DETAILS.iter() {
70 if samples as u64 <= level.max_picture_size()
71 && display_rate <= level.max_display_rate()
72 && self.width <= level.max_width()
73 && self.height <= level.max_height()
74 && self.framerate as u32 <= level.max_header_rate()
75 {
76 let selected = match (self.max_bitrate, level.max_bit_rate(self.tier)) {
77 (Some(bitrate_constraint), Some(level_max_bitrate))
78 if level_max_bitrate >= bitrate_constraint.into() =>
79 {
80 *level
81 }
82 (None, Some(_)) => *level,
83 _ => continue,
84 };
85
86 match self.min_level {
88 Some(min) if selected.id() < min => {
89 continue;
90 }
91 _ => {}
92 }
93
94 match self.max_level {
96 Some(max) if selected.id() > max => return None,
97 _ => {}
98 }
99
100 return Some(selected);
101 }
102 }
103
104 Some(LEVEL_DETAILS[LEVEL_DETAILS.len() - 1])
105 }
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
109pub enum Profile {
110 Main,
111 High,
112 Professional,
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
116pub enum Tier {
117 Main,
118 High,
119}
120
121impl From<&Profile> for ProfileConstraint {
122 fn from(profile: &Profile) -> Self {
123 match profile {
124 Profile::Main => ProfileConstraint {
125 max_bit_depth: Depth::Depth10,
126 chroma_formats: vec![ChromaSampling::Monochrome, ChromaSampling::Cs420],
127 },
128 Profile::High => ProfileConstraint {
129 max_bit_depth: Depth::Depth10,
130 chroma_formats: vec![
131 ChromaSampling::Monochrome,
132 ChromaSampling::Cs420,
133 ChromaSampling::Cs444,
134 ],
135 },
136 Profile::Professional => ProfileConstraint {
137 max_bit_depth: Depth::Depth12,
138 chroma_formats: vec![
139 ChromaSampling::Monochrome,
140 ChromaSampling::Cs420,
141 ChromaSampling::Cs422,
142 ChromaSampling::Cs444,
143 ],
144 },
145 }
146 }
147}
148
149#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
150pub enum Level {
151 L2,
152 L2_1,
153 L3,
154 L3_1,
155 L4,
156 L4_1,
157 L5,
158 L5_1,
159 L5_2,
160 L5_3,
161 L6,
162 L6_1,
163 L6_2,
164 L6_3,
165 Reserved,
166 Max,
167}
168
169impl From<usize> for Level {
170 fn from(value: usize) -> Self {
171 match value {
172 0 => Level::L2,
173 1 => Level::L2_1,
174 4 => Level::L3,
175 5 => Level::L3_1,
176 8 => Level::L4,
177 9 => Level::L4_1,
178 12 => Level::L5,
179 13 => Level::L5_1,
180 14 => Level::L5_2,
181 15 => Level::L5_3,
182 16 => Level::L6,
183 17 => Level::L6_1,
184 18 => Level::L6_2,
185 19 => Level::L6_3,
186 24..=30 => Level::Reserved,
187 32 => Level::Max,
188 _ => Level::Max,
189 }
190 }
191}
192
193impl Level {
194 fn usize(&self) -> usize {
195 match self {
196 Level::L2 => 0,
197 Level::L2_1 => 1,
198 Level::L3 => 4,
199 Level::L3_1 => 5,
200 Level::L4 => 8,
201 Level::L4_1 => 9,
202 Level::L5 => 12,
203 Level::L5_1 => 13,
204 Level::L5_2 => 14,
205 Level::L5_3 => 15,
206 Level::L6 => 16,
207 Level::L6_1 => 17,
208 Level::L6_2 => 18,
209 Level::L6_3 => 19,
210 Level::Reserved => 24,
211 Level::Max => 32,
212 }
213 }
214}
215
216impl fmt::Display for Level {
217 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
218 let level_str = match self {
219 Level::L2 => "L2",
220 Level::L2_1 => "L2.1",
221 Level::L3 => "L3",
222 Level::L3_1 => "L3.1",
223 Level::L4 => "L4",
224 Level::L4_1 => "L4.1",
225 Level::L5 => "L5",
226 Level::L5_1 => "L5.1",
227 Level::L5_2 => "L5.2",
228 Level::L5_3 => "L5.3",
229 Level::L6 => "L6",
230 Level::L6_1 => "L6.1",
231 Level::L6_2 => "L6.2",
232 Level::L6_3 => "L6.3",
233 Level::Reserved => "Reserved",
234 Level::Max => "Max",
235 };
236 write!(f, "{}", level_str)
237 }
238}
239
240pub fn get(level: Level) -> LevelSpecification {
242 for l in LEVEL_DETAILS.iter() {
243 if l.id() == level {
244 return *l;
245 }
246 }
247 LEVEL_DETAILS[LEVEL_DETAILS.len() - 1]
248}
249
250#[derive(Debug, Clone, Copy)]
251pub struct LevelSpecification {
252 id: Level,
253 max_picture_size: u64,
254 max_horizontal: u32,
255 max_vertical: u32,
256 max_display_rate: u64,
257 max_decode_rate: u64,
258 max_header_rate: u32,
259 max_bit_rate_main: u64,
260 max_bit_rate_high: Option<u32>,
261 min_comp_basis: u32,
262 max_tiles: u32,
263 max_tile_cols: u32,
264}
265
266impl LevelSpecification {
267 pub fn id(&self) -> Level {
268 self.id
269 }
270 pub fn max_picture_size(&self) -> u64 {
271 self.max_picture_size
272 }
273 pub fn max_horizontal(&self) -> u32 {
274 self.max_horizontal
275 }
276 pub fn max_vertical(&self) -> u32 {
277 self.max_vertical
278 }
279 pub fn max_width(&self) -> u32 {
280 self.max_horizontal
281 }
282 pub fn max_height(&self) -> u32 {
283 self.max_vertical
284 }
285 pub fn max_display_rate(&self) -> u64 {
286 self.max_display_rate
287 }
288 pub fn max_decode_rate(&self) -> u64 {
289 self.max_decode_rate
290 }
291 pub fn max_header_rate(&self) -> u32 {
292 self.max_header_rate
293 }
294 pub fn max_bit_rate(&self, tier: Tier) -> Option<u64> {
295 match tier {
296 Tier::Main => Some(self.max_bit_rate_main),
297 Tier::High => self.max_bit_rate_high.map(|v| v as u64),
298 }
299 }
300 pub fn max_bit_rate_main(&self) -> u64 {
301 self.max_bit_rate_main
302 }
303 pub fn max_bit_rate_high(&self) -> Option<u32> {
304 self.max_bit_rate_high
305 }
306 pub fn min_comp_basis(&self) -> u32 {
307 self.min_comp_basis
308 }
309 pub fn max_tiles(&self) -> u32 {
310 self.max_tiles
311 }
312 pub fn max_tile_cols(&self) -> u32 {
313 self.max_tile_cols
314 }
315}
316
317pub const LEVEL_DETAILS: [LevelSpecification; 14] = [
318 LevelSpecification {
319 id: Level::L2,
320 max_picture_size: 147456,
321 max_horizontal: 1152,
322 max_vertical: 2048,
323 max_display_rate: 4423680,
324 max_decode_rate: 5529600,
325 max_header_rate: 150,
326 max_bit_rate_main: 1_500_000,
327 max_bit_rate_high: None,
328 min_comp_basis: 2,
329 max_tiles: 8,
330 max_tile_cols: 4,
331 },
332 LevelSpecification {
333 id: Level::L2_1,
334 max_picture_size: 278784,
335 max_horizontal: 1584,
336 max_vertical: 2816,
337 max_display_rate: 8363520,
338 max_decode_rate: 10454400,
339 max_header_rate: 150,
340 max_bit_rate_main: 3_000_000,
341 max_bit_rate_high: None,
342 min_comp_basis: 2,
343 max_tiles: 8,
344 max_tile_cols: 4,
345 },
346 LevelSpecification {
347 id: Level::L3,
348 max_picture_size: 665856,
349 max_horizontal: 2448,
350 max_vertical: 4352,
351 max_display_rate: 19975680,
352 max_decode_rate: 24969600,
353 max_header_rate: 150,
354 max_bit_rate_main: 6_000_000,
355 max_bit_rate_high: None,
356 min_comp_basis: 2,
357 max_tiles: 16,
358 max_tile_cols: 6,
359 },
360 LevelSpecification {
361 id: Level::L3_1,
362 max_picture_size: 1065024,
363 max_horizontal: 3096,
364 max_vertical: 5504,
365 max_display_rate: 31950720,
366 max_decode_rate: 39938400,
367 max_header_rate: 150,
368 max_bit_rate_main: 10_000_000,
369 max_bit_rate_high: None,
370 min_comp_basis: 2,
371 max_tiles: 16,
372 max_tile_cols: 6,
373 },
374 LevelSpecification {
375 id: Level::L4,
376 max_picture_size: 2359296,
377 max_horizontal: 3456,
378 max_vertical: 6144,
379 max_display_rate: 70778880,
380 max_decode_rate: 77856768,
381 max_header_rate: 300,
382 max_bit_rate_main: 12_000_000,
383 max_bit_rate_high: Some(30_000_000),
384 min_comp_basis: 4,
385 max_tiles: 32,
386 max_tile_cols: 8,
387 },
388 LevelSpecification {
389 id: Level::L4_1,
390 max_picture_size: 2359296,
391 max_horizontal: 3456,
392 max_vertical: 6144,
393 max_display_rate: 141557760,
394 max_decode_rate: 155713536,
395 max_header_rate: 300,
396 max_bit_rate_main: 20_000_000,
397 max_bit_rate_high: Some(50_000_000),
398 min_comp_basis: 4,
399 max_tiles: 32,
400 max_tile_cols: 8,
401 },
402 LevelSpecification {
403 id: Level::L5,
404 max_picture_size: 8912896,
405 max_horizontal: 4352,
406 max_vertical: 8192,
407 max_display_rate: 267386880,
408 max_decode_rate: 273715200,
409 max_header_rate: 300,
410 max_bit_rate_main: 30_000_000,
411 max_bit_rate_high: Some(100_000_000),
412 min_comp_basis: 6,
413 max_tiles: 64,
414 max_tile_cols: 8,
415 },
416 LevelSpecification {
417 id: Level::L5_1,
418 max_picture_size: 8912896,
419 max_horizontal: 4352,
420 max_vertical: 8192,
421 max_display_rate: 534773760,
422 max_decode_rate: 547430400,
423 max_header_rate: 300,
424 max_bit_rate_main: 40_000_000,
425 max_bit_rate_high: Some(160_000_000),
426 min_comp_basis: 8,
427 max_tiles: 64,
428 max_tile_cols: 8,
429 },
430 LevelSpecification {
431 id: Level::L5_2,
432 max_picture_size: 8912896,
433 max_horizontal: 4352,
434 max_vertical: 8192,
435 max_display_rate: 1069547520,
436 max_decode_rate: 1094860800,
437 max_header_rate: 300,
438 max_bit_rate_main: 60_000_000,
439 max_bit_rate_high: Some(240_000_000),
440 min_comp_basis: 8,
441 max_tiles: 64,
442 max_tile_cols: 8,
443 },
444 LevelSpecification {
445 id: Level::L5_3,
446 max_picture_size: 8912896,
447 max_horizontal: 4352,
448 max_vertical: 8192,
449 max_display_rate: 1069547520,
450 max_decode_rate: 1176502272,
451 max_header_rate: 300,
452 max_bit_rate_main: 60_000_000,
453 max_bit_rate_high: Some(240_000_000),
454 min_comp_basis: 8,
455 max_tiles: 64,
456 max_tile_cols: 8,
457 },
458 LevelSpecification {
459 id: Level::L6,
460 max_picture_size: 35651584,
461 max_horizontal: 8704,
462 max_vertical: 16384,
463 max_display_rate: 1069547520,
464 max_decode_rate: 1176502272,
465 max_header_rate: 300,
466 max_bit_rate_main: 60_000_000,
467 max_bit_rate_high: Some(240_000_000),
468 min_comp_basis: 8,
469 max_tiles: 128,
470 max_tile_cols: 16,
471 },
472 LevelSpecification {
473 id: Level::L6_1,
474 max_picture_size: 35651584,
475 max_horizontal: 8704,
476 max_vertical: 16384,
477 max_display_rate: 2139095040,
478 max_decode_rate: 2189721600,
479 max_header_rate: 300,
480 max_bit_rate_main: 100_000_000,
481 max_bit_rate_high: Some(480_000_000),
482 min_comp_basis: 8,
483 max_tiles: 128,
484 max_tile_cols: 16,
485 },
486 LevelSpecification {
487 id: Level::L6_2,
488 max_picture_size: 35651584,
489 max_horizontal: 8704,
490 max_vertical: 16384,
491 max_display_rate: 4278190080,
492 max_decode_rate: 4379443200,
493 max_header_rate: 300,
494 max_bit_rate_main: 160_000_000,
495 max_bit_rate_high: Some(800_000_000),
496 min_comp_basis: 8,
497 max_tiles: 128,
498 max_tile_cols: 16,
499 },
500 LevelSpecification {
501 id: Level::L6_3,
502 max_picture_size: 35651584,
503 max_horizontal: 8704,
504 max_vertical: 16384,
505 max_display_rate: 4278190080,
506 max_decode_rate: 4706009088,
507 max_header_rate: 300,
508 max_bit_rate_main: 160_000_000,
509 max_bit_rate_high: Some(800_000_000),
510 min_comp_basis: 8,
511 max_tiles: 128,
512 max_tile_cols: 16,
513 },
514];
515#[cfg(test)]
516mod tests {
517 #[test]
518 fn level_mult() {
519 use crate::av1::Level;
520 assert_eq!(Level::L3, Level::from(4));
521 }
522
523 #[test]
524 fn max_bitrate() {
525 use crate::av1::{self, Level, Tier};
526
527 let l = av1::get(Level::L3);
528 assert_eq!(l.max_bit_rate(Tier::Main), Some(6_000_000));
529 assert_eq!(l.max_bit_rate(Tier::High), None);
530
531 let l = av1::get(Level::L5_2);
532 assert_eq!(l.max_bit_rate(Tier::Main), Some(60_000_000));
533 assert_eq!(l.max_bit_rate(Tier::High), Some(240_000_000));
534 }
535
536 #[test]
537 fn select_base_cases() {
538 use crate::av1::{Level, LevelSelector, Profile, Tier};
539 assert_eq!(
540 LevelSelector::new()
541 .width(1920)
542 .height(1080)
543 .framerate(30.0)
544 .tier(Tier::Main)
545 .profile(Profile::Main)
546 .select()
547 .unwrap()
548 .id(),
549 Level::L4
550 );
551
552 assert_eq!(
553 LevelSelector::new()
554 .width(4380)
555 .height(1080)
556 .framerate(30.0)
557 .tier(Tier::Main)
558 .profile(Profile::Main)
559 .select()
560 .unwrap()
561 .id(),
562 Level::L6
563 );
564
565 assert_eq!(
566 LevelSelector::new()
567 .width(3840)
568 .height(2160)
569 .framerate(200.0)
570 .tier(Tier::Main)
571 .profile(Profile::Main)
572 .select()
573 .unwrap()
574 .id(),
575 Level::L6_1
576 );
577 }
578}