#![allow(dead_code)]
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum SeqLevel {
L20 = 0,
L21 = 1,
L22 = 2,
L23 = 3,
L30 = 4,
L31 = 5,
L32 = 6,
L33 = 7,
L40 = 8,
L41 = 9,
L42 = 10,
L43 = 11,
L50 = 12,
L51 = 13,
L52 = 14,
L53 = 15,
L60 = 16,
L61 = 17,
L62 = 18,
L63 = 19,
}
pub const MAX_TILE_WIDTH: u32 = 4096;
pub const MAX_TILE_AREA: u32 = 4096 * 2304;
pub const MAX_TILE_ROWS: u32 = 64;
pub const MAX_TILE_COLS: u32 = 64;
pub const MAX_TILE_COUNT: u32 = 512;
pub const NUM_REF_FRAMES: usize = 8;
pub const REFS_PER_FRAME: usize = 7;
pub const MAX_SB_SIZE: u32 = 128;
pub const MI_SIZE: u32 = 4;
pub const MAX_SEGMENTS: usize = 8;
struct LevelParams {
max_picture_size: u64, max_bitrate_mbps: u64, }
static LEVEL_PARAMS: [LevelParams; 20] = [
LevelParams { max_picture_size: 147_456, max_bitrate_mbps: 1_500 },
LevelParams { max_picture_size: 278_784, max_bitrate_mbps: 3_000 },
LevelParams { max_picture_size: 278_784, max_bitrate_mbps: 6_000 },
LevelParams { max_picture_size: 278_784, max_bitrate_mbps: 10_000 },
LevelParams { max_picture_size: 665_856, max_bitrate_mbps: 12_000 },
LevelParams { max_picture_size: 1_065_024, max_bitrate_mbps: 20_000 },
LevelParams { max_picture_size: 1_065_024, max_bitrate_mbps: 30_000 },
LevelParams { max_picture_size: 1_065_024, max_bitrate_mbps: 40_000 },
LevelParams { max_picture_size: 2_359_296, max_bitrate_mbps: 60_000 },
LevelParams { max_picture_size: 2_359_296, max_bitrate_mbps: 100_000 },
LevelParams { max_picture_size: 2_359_296, max_bitrate_mbps: 160_000 },
LevelParams { max_picture_size: 2_359_296, max_bitrate_mbps: 240_000 },
LevelParams { max_picture_size: 8_912_896, max_bitrate_mbps: 240_000 },
LevelParams { max_picture_size: 8_912_896, max_bitrate_mbps: 480_000 },
LevelParams { max_picture_size: 8_912_896, max_bitrate_mbps: 800_000 },
LevelParams { max_picture_size: 8_912_896, max_bitrate_mbps: 1_600_000 },
LevelParams { max_picture_size: 35_651_584, max_bitrate_mbps: 1_600_000 },
LevelParams { max_picture_size: 35_651_584, max_bitrate_mbps: 4_800_000 },
LevelParams { max_picture_size: 35_651_584, max_bitrate_mbps: 4_800_000 },
LevelParams { max_picture_size: 35_651_584, max_bitrate_mbps: 4_800_000 },
];
const ALL_LEVELS: [SeqLevel; 20] = [
SeqLevel::L20,
SeqLevel::L21,
SeqLevel::L22,
SeqLevel::L23,
SeqLevel::L30,
SeqLevel::L31,
SeqLevel::L32,
SeqLevel::L33,
SeqLevel::L40,
SeqLevel::L41,
SeqLevel::L42,
SeqLevel::L43,
SeqLevel::L50,
SeqLevel::L51,
SeqLevel::L52,
SeqLevel::L53,
SeqLevel::L60,
SeqLevel::L61,
SeqLevel::L62,
SeqLevel::L63,
];
impl SeqLevel {
pub fn max_picture_size(&self) -> u64 {
LEVEL_PARAMS[*self as usize].max_picture_size
}
pub fn max_bitrate(&self) -> u64 {
LEVEL_PARAMS[*self as usize].max_bitrate_mbps * 1_000_000
}
pub fn for_frame_size(width: u32, height: u32) -> SeqLevel {
let frame_area = (width as u64) * (height as u64);
for level in &ALL_LEVELS {
if level.max_picture_size() >= frame_area {
return *level;
}
}
SeqLevel::L63
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_level_for_small_frame() {
let level = SeqLevel::for_frame_size(426, 240);
assert_eq!(level, SeqLevel::L20);
}
#[test]
fn test_level_for_1080p() {
let level = SeqLevel::for_frame_size(1920, 1080);
assert_eq!(level, SeqLevel::L40);
}
#[test]
fn test_level_for_4k() {
let level = SeqLevel::for_frame_size(3840, 2160);
assert_eq!(level, SeqLevel::L50);
}
#[test]
fn test_level_for_8k() {
let level = SeqLevel::for_frame_size(7680, 4320);
assert_eq!(level, SeqLevel::L60);
}
#[test]
fn test_max_picture_size_monotonic() {
let sizes: Vec<u64> = ALL_LEVELS.iter().map(|l| l.max_picture_size()).collect();
for i in 1..sizes.len() {
assert!(
sizes[i] >= sizes[i - 1],
"level sizes not monotone at index {i}: {} < {}",
sizes[i],
sizes[i - 1]
);
}
}
#[test]
fn test_bitrate_positive() {
for level in &ALL_LEVELS {
assert!(level.max_bitrate() > 0, "bitrate should be positive for {:?}", level);
}
}
#[test]
fn test_l63_is_fallback_for_huge_frame() {
let level = SeqLevel::for_frame_size(100_000, 100_000);
assert_eq!(level, SeqLevel::L63);
}
#[test]
fn test_level_indices() {
assert_eq!(SeqLevel::L20 as u8, 0);
assert_eq!(SeqLevel::L63 as u8, 19);
assert_eq!(SeqLevel::L50 as u8, 12);
}
}