#![allow(unused)]
#![allow(bad_style)]
use crate::{Error, Result};
use bitreader::BitReader;
use std::num::{NonZeroU8, NonZeroU32};
#[derive(Debug, Clone)]
struct Header {
obu_size: usize,
is_sequence_header: bool,
}
fn get_byte(data: &mut &[u8]) -> Result<u8> {
let (&b, rest) = (*data).split_first().ok_or(Error::UnexpectedEOF)?;
*data = rest;
Ok(b)
}
const INTRA_FRAME: usize = 0;
const LAST_FRAME: usize = 1;
const LAST2_FRAME: usize = 2;
const LAST3_FRAME: usize = 3;
const GOLDEN_FRAME: usize = 4;
const BWDREF_FRAME: usize = 5;
const ALTREF2_FRAME: usize = 6;
const ALTREF_FRAME: usize = 7;
pub(crate) fn parse_obu(mut data: &[u8]) -> Result<SequenceHeaderObu> {
while !data.is_empty() {
let h = obu_header(&mut data)?;
let mut remaining_data = data.get(..h.obu_size).ok_or(Error::UnexpectedEOF)?;
data = &data[h.obu_size..];
if h.is_sequence_header {
return SequenceHeaderObu::read(remaining_data);
}
}
Err(Error::UnexpectedEOF)
}
impl SequenceHeaderObu {
fn read(data: &[u8]) -> Result<Self> {
let mut b = BitReader::new(data);
let mut enable_superres = false;
let mut enable_cdef = false;
let mut enable_restoration = false;
let seq_profile = b.read_u8(3)?;
if seq_profile > 2 {
return Err(Error::InvalidData("seq_profile"));
}
let still_picture = b.read_bool()?;
let reduced_still_picture_header = b.read_bool()?;
let decoder_model_info_present_flag = false;
if reduced_still_picture_header {
let timing_info_present_flag = 0;
let initial_display_delay_present_flag = 0;
let operating_points_cnt_minus_1 = 0;
let operating_point_idc = 0; let seq_level_idx = b.read_u8(5)?;
let seq_tier = 0; let decoder_model_present_for_this_op = 0; let initial_display_delay_present_for_this_op = 0; } else {
let timing_info_present_flag = b.read_bool()?;
if timing_info_present_flag {
return Err(Error::Unsupported("timing_info_present_flag"));
}
let initial_display_delay_present_flag = b.read_bool()?;
let operating_points_cnt = 1 + b.read_u8(5)?;
for _ in 0..operating_points_cnt {
let operating_point_idc = b.read_u16(12)?;
let seq_level_idx = b.read_u8(5)?;
let seq_tier = if seq_level_idx > 7 { b.read_bool()? } else { false };
let decoder_model_present_for_this_op = if decoder_model_info_present_flag {
b.read_bool()?;
return Err(Error::Unsupported("decoder_model_info_present_flag"));
} else {
false
};
if initial_display_delay_present_flag {
let initial_display_delay_present_for_this_op = b.read_bool()?;
if initial_display_delay_present_for_this_op {
let initial_display_delay = 1 + b.read_u8(4)?;
}
}
}
}
let frame_width_bits = 1 + b.read_u8(4)?;
let frame_height_bits = 1 + b.read_u8(4)?;
let frame_width_bits = NonZeroU8::new(frame_width_bits).ok_or(Error::InvalidData("overflow"))?;
let frame_height_bits = NonZeroU8::new(frame_height_bits).ok_or(Error::InvalidData("overflow"))?;
let max_frame_width = 1 + b.read_u32(frame_width_bits.get())?;
let max_frame_height = 1 + b.read_u32(frame_height_bits.get())?;
let max_frame_width = NonZeroU32::new(max_frame_width).ok_or(Error::InvalidData("overflow"))?;
let max_frame_height = NonZeroU32::new(max_frame_height).ok_or(Error::InvalidData("overflow"))?;
let frame_id_numbers_present_flag = if reduced_still_picture_header { false } else { b.read_bool()? };
let delta_frame_id_length = if frame_id_numbers_present_flag { 2 + b.read_u8(4)? } else { 0 };
let additional_frame_id_length = if frame_id_numbers_present_flag { 1 + b.read_u8(3)? } else { 0 };
let use_128x128_superblock = b.read_bool()?;
let enable_filter_intra = b.read_bool()?;
let enable_intra_edge_filter = b.read_bool()?;
let mut enable_interintra_compound = false;
let mut enable_masked_compound = false;
let mut enable_warped_motion = false;
let mut enable_dual_filter = false;
let mut enable_jnt_comp = false;
let mut enable_ref_frame_mvs = false;
let mut seq_force_screen_content_tools = SELECT_SCREEN_CONTENT_TOOLS;
let mut seq_force_integer_mv = SELECT_INTEGER_MV;
let mut order_hint_bits = 0;
let mut enable_order_hint = false;
if !reduced_still_picture_header {
enable_interintra_compound = b.read_bool()?;
enable_masked_compound = b.read_bool()?;
enable_warped_motion = b.read_bool()?;
enable_dual_filter = b.read_bool()?;
enable_order_hint = b.read_bool()?;
if enable_order_hint {
enable_jnt_comp = b.read_bool()?;
enable_ref_frame_mvs = b.read_bool()?;
}
let seq_choose_screen_content_tools = b.read_bool()?;
if !seq_choose_screen_content_tools {
seq_force_screen_content_tools = b.read_u8(1)?;
}
if seq_force_screen_content_tools > 0 {
let seq_choose_integer_mv = b.read_bool()?;
if !seq_choose_integer_mv {
seq_force_integer_mv = b.read_u8(1)?;
}
}
if enable_order_hint {
order_hint_bits = 1 + b.read_u8(3)?;
}
}
let enable_superres = b.read_bool()?;
let enable_cdef = b.read_bool()?;
let enable_restoration = b.read_bool()?;
let color = color_config(&mut b, seq_profile)?;
let film_grain_params_present = b.read_bool()?;
Ok(Self {
color,
seq_profile,
still_picture,
reduced_still_picture_header,
max_frame_width,
max_frame_height,
enable_superres,
enable_cdef,
enable_restoration,
frame_id_numbers_present_flag,
delta_frame_id_length,
additional_frame_id_length,
film_grain_params_present,
decoder_model_info_present_flag,
seq_force_screen_content_tools,
seq_force_integer_mv,
order_hint_bits,
enable_order_hint,
use_128x128_superblock,
enable_interintra_compound,
enable_masked_compound,
enable_warped_motion,
enable_dual_filter,
enable_jnt_comp,
enable_ref_frame_mvs,
})
}
}
#[derive(Debug, Clone)]
#[allow(clippy::struct_excessive_bools)]
pub(crate) struct SequenceHeaderObu {
pub color: ColorConfig,
pub seq_profile: u8,
pub still_picture: bool,
pub reduced_still_picture_header: bool,
pub max_frame_width: NonZeroU32,
pub max_frame_height: NonZeroU32,
pub enable_superres: bool,
pub enable_cdef: bool,
pub enable_restoration: bool,
pub frame_id_numbers_present_flag: bool,
pub delta_frame_id_length: u8,
pub additional_frame_id_length: u8,
pub film_grain_params_present: bool,
pub decoder_model_info_present_flag: bool,
pub seq_force_screen_content_tools: u8,
pub seq_force_integer_mv: u8,
pub order_hint_bits: u8,
pub enable_order_hint: bool,
pub use_128x128_superblock: bool,
pub enable_interintra_compound: bool,
pub enable_masked_compound: bool,
pub enable_warped_motion: bool,
pub enable_dual_filter: bool,
pub enable_jnt_comp: bool,
pub enable_ref_frame_mvs: bool,
}
#[derive(Debug, Clone)]
pub(crate) struct ColorConfig {
pub chroma_subsampling: (bool, bool),
pub chroma_sample_position: u8,
pub separate_uv_delta_q: bool,
pub color_range: u8,
pub bit_depth: u8,
pub monochrome: bool,
pub color_primaries: u8,
pub transfer_characteristics: u8,
pub matrix_coefficients: u8,
}
fn color_config(b: &mut BitReader, seq_profile: u8) -> Result<ColorConfig> {
let high_bitdepth = b.read_bool()?;
let bit_depth = if seq_profile == 2 && high_bitdepth {
let twelve_bit = b.read_bool()?;
if twelve_bit {
12
} else {
10
}
} else { if high_bitdepth {
10
} else {
8
}
};
let monochrome = if seq_profile == 1 { false } else { b.read_bool()? };
let num_planes = if monochrome { 1 } else { 3 };
let color_description_present_flag = b.read_bool()?;
let mut color_primaries = 2;
let mut transfer_characteristics = 2;
let matrix_coefficients = if color_description_present_flag {
color_primaries = b.read_u8(8)?;
transfer_characteristics = b.read_u8(8)?;
b.read_u8(8)?
} else {
2
};
let chroma_subsampling;
let chroma_sample_position;
let separate_uv_delta_q;
let color_range;
if monochrome {
color_range = b.read_u8(1)?;
chroma_subsampling = (false, false);
chroma_sample_position = 0;
separate_uv_delta_q = false;
} else if color_primaries == 1 && transfer_characteristics == 13 && matrix_coefficients == 0
{
color_range = 1;
chroma_subsampling = (false, false);
chroma_sample_position = 0;
separate_uv_delta_q = false;
} else {
color_range = b.read_u8(1)?;
if seq_profile == 0 {
chroma_subsampling = (true, true);
} else if seq_profile == 1 {
chroma_subsampling = (false, false);
} else if bit_depth == 12 {
let x = b.read_bool()?;
chroma_subsampling = if x {
(x, b.read_bool()?)
} else {
(false, false)
}
} else {
chroma_subsampling = (true, false);
}
debug_assert!(!monochrome);
chroma_sample_position = if chroma_subsampling.0 && chroma_subsampling.1 { b.read_u8(2)? } else { 0 };
separate_uv_delta_q = b.read_bool()?;
}
Ok(ColorConfig {
chroma_subsampling,
chroma_sample_position,
separate_uv_delta_q,
color_range,
bit_depth,
monochrome,
color_primaries,
transfer_characteristics,
matrix_coefficients,
})
}
fn obu_header(data: &mut &[u8]) -> Result<Header> {
let mut b = get_byte(data)?;
if 0 != b & 0b1000_0000 {
return Err(Error::InvalidData("not obu"));
}
let is_sequence_header = 1 == (b >> 3);
let obu_extension_flag = 0 != (b & 0b100);
let obu_has_size_field = 0 != (b & 0b010);
if obu_extension_flag {
let mut b = get_byte(data)?;
}
let obu_size = if obu_has_size_field {
leb128::read::unsigned(data)
.map_err(|_| Error::InvalidData("leb"))?
.try_into()
.map_err(|_| Error::UnexpectedEOF)?
} else {
data.len()
};
Ok(Header { obu_size, is_sequence_header })
}
const REFS_PER_FRAME: usize = 7; const TOTAL_REFS_PER_FRAME: usize = 8; const BLOCK_SIZE_GROUPS: usize = 4; const BLOCK_SIZES: usize = 22; const BLOCK_INVALID: usize = 22; const MAX_SB_SIZE: usize = 128; const MI_SIZE: usize = 4; const MI_SIZE_LOG2: usize = 2; const MAX_TILE_WIDTH: usize = 4096; const MAX_TILE_AREA: usize = 4096; const MAX_TILE_ROWS: usize = 64; const MAX_TILE_COLS: usize = 64; const INTRABC_DELAY_PIXELS: usize = 256; const INTRABC_DELAY_SB64: usize = 4; const NUM_REF_FRAMES: usize = 8; const REF_CONTEXTS: usize = 3; const MAX_SEGMENTS: usize = 8; const SEGMENT_ID_CONTEXTS: usize = 3; const SEG_LVL_ALT_Q: usize = 0; const SEG_LVL_ALT_LF_Y_V: usize = 1; const SEG_LVL_REF_FRAME: usize = 5; const SEG_LVL_SKIP: usize = 6; const SEG_LVL_GLOBALMV: usize = 7; const SEG_LVL_MAX: usize = 8; const PLANE_TYPES: usize = 2; const TX_SIZE_CONTEXTS: usize = 3; const INTERP_FILTERS: usize = 3; const INTERP_FILTER_CONTEXTS: usize = 16; const SKIP_MODE_CONTEXTS: usize = 3; const SKIP_CONTEXTS: usize = 3; const PARTITION_CONTEXTS: usize = 4; const TX_SIZES: usize = 5; const TX_SIZES_ALL: usize = 19; const TX_MODES: usize = 3; const DCT_DCT: usize = 0; const ADST_DCT: usize = 1; const DCT_ADST: usize = 2; const ADST_ADST: usize = 3; const FLIPADST_DCT: usize = 4; const DCT_FLIPADST: usize = 5; const FLIPADST_FLIPADST: usize = 6; const ADST_FLIPADST: usize = 7; const FLIPADST_ADST: usize = 8; const IDTX: usize = 9; const V_DCT: usize = 10; const H_DCT: usize = 11; const V_ADST: usize = 12; const H_ADST: usize = 13; const V_FLIPADST: usize = 14; const H_FLIPADST: usize = 15; const TX_TYPES: usize = 16; const MB_MODE_COUNT: usize = 17; const INTRA_MODES: usize = 13; const UV_INTRA_MODES_CFL_NOT_ALLOWED: usize = 13; const UV_INTRA_MODES_CFL_ALLOWED: usize = 14; const COMPOUND_MODES: usize = 8; const COMPOUND_MODE_CONTEXTS: usize = 8; const COMP_NEWMV_CTXS: usize = 5; const NEW_MV_CONTEXTS: usize = 6; const ZERO_MV_CONTEXTS: usize = 2; const REF_MV_CONTEXTS: usize = 6; const DRL_MODE_CONTEXTS: usize = 3; const MV_CONTEXTS: usize = 2; const MV_INTRABC_CONTEXT: usize = 1; const MV_JOINTS: usize = 4; const MV_CLASSES: usize = 11; const CLASS0_SIZE: usize = 2; const MV_OFFSET_BITS: usize = 10; const MAX_LOOP_FILTER: usize = 63; const REF_SCALE_SHIFT: usize = 14; const SUBPEL_BITS: usize = 4; const SUBPEL_MASK: usize = 15; const SCALE_SUBPEL_BITS: usize = 10; const MV_BORDER: usize = 128; const PALETTE_COLOR_CONTEXTS: usize = 5; const PALETTE_MAX_COLOR_CONTEXT_HASH: usize = 8; const PALETTE_BLOCK_SIZE_CONTEXTS: usize = 7; const PALETTE_Y_MODE_CONTEXTS: usize = 3; const PALETTE_UV_MODE_CONTEXTS: usize = 2; const PALETTE_SIZES: usize = 7; const PALETTE_COLORS: usize = 8; const PALETTE_NUM_NEIGHBORS: usize = 3; const DELTA_Q_SMALL: usize = 3; const DELTA_LF_SMALL: usize = 3; const QM_TOTAL_SIZE: usize = 3344; const MAX_ANGLE_DELTA: usize = 3; const DIRECTIONAL_MODES: usize = 8; const ANGLE_STEP: usize = 3; const TX_SET_TYPES_INTRA: usize = 3; const TX_SET_TYPES_INTER: usize = 4; const WARPEDMODEL_PREC_BITS: usize = 16; const IDENTITY: usize = 0; const TRANSLATION: usize = 1; const ROTZOOM: usize = 2; const AFFINE: usize = 3; const GM_ABS_TRANS_BITS: usize = 12; const GM_ABS_TRANS_ONLY_BITS: usize = 9; const GM_ABS_ALPHA_BITS: usize = 12; const DIV_LUT_PREC_BITS: usize = 14; const DIV_LUT_BITS: usize = 8; const DIV_LUT_NUM: usize = 257; const MOTION_MODES: usize = 3; const SIMPLE: usize = 0; const OBMC: usize = 1; const LOCALWARP: usize = 2; const LEAST_SQUARES_SAMPLES_MAX: usize = 8; const LS_MV_MAX: usize = 256; const WARPEDMODEL_TRANS_CLAMP: usize = 1; const WARPEDMODEL_NONDIAGAFFINE_CLAMP: usize = 1; const WARPEDPIXEL_PREC_SHIFTS: usize = 1; const WARPEDDIFF_PREC_BITS: usize = 10; const GM_ALPHA_PREC_BITS: usize = 15; const GM_TRANS_PREC_BITS: usize = 6; const GM_TRANS_ONLY_PREC_BITS: usize = 3; const INTERINTRA_MODES: usize = 4; const MASK_MASTER_SIZE: usize = 64; const SEGMENT_ID_PREDICTED_CONTEXTS: usize = 3; const IS_INTER_CONTEXTS: usize = 4; const FWD_REFS: usize = 4; const BWD_REFS: usize = 3; const SINGLE_REFS: usize = 7; const UNIDIR_COMP_REFS: usize = 4; const COMPOUND_TYPES: usize = 2; const CFL_JOINT_SIGNS: usize = 8; const CFL_ALPHABET_SIZE: usize = 16; const COMP_INTER_CONTEXTS: usize = 5; const COMP_REF_TYPE_CONTEXTS: usize = 5; const CFL_ALPHA_CONTEXTS: usize = 6; const INTRA_MODE_CONTEXTS: usize = 5; const COMP_GROUP_IDX_CONTEXTS: usize = 6; const COMPOUND_IDX_CONTEXTS: usize = 6; const INTRA_EDGE_KERNELS: usize = 3; const INTRA_EDGE_TAPS: usize = 5; const FRAME_LF_COUNT: usize = 4; const MAX_VARTX_DEPTH: usize = 2; const TXFM_PARTITION_CONTEXTS: usize = 21; const REF_CAT_LEVEL: usize = 640; const MAX_REF_MV_STACK_SIZE: usize = 8; const MFMV_STACK_SIZE: usize = 3; const MAX_TX_DEPTH: usize = 2; const WEDGE_TYPES: usize = 16; const FILTER_BITS: usize = 7; const WIENER_COEFFS: usize = 3; const SGRPROJ_PARAMS_BITS: usize = 4; const SGRPROJ_PRJ_SUBEXP_K: usize = 4; const SGRPROJ_PRJ_BITS: usize = 7; const SGRPROJ_RST_BITS: usize = 4; const SGRPROJ_MTABLE_BITS: usize = 20; const SGRPROJ_RECIP_BITS: usize = 12; const SGRPROJ_SGR_BITS: usize = 8; const EC_PROB_SHIFT: usize = 6; const EC_MIN_PROB: usize = 4; const SELECT_SCREEN_CONTENT_TOOLS: u8 = 2; const SELECT_INTEGER_MV: u8 = 2; const RESTORATION_TILESIZE_MAX: usize = 256; const MAX_FRAME_DISTANCE: usize = 31; const MAX_OFFSET_WIDTH: usize = 8; const MAX_OFFSET_HEIGHT: usize = 0; const WARP_PARAM_REDUCE_BITS: usize = 6; const NUM_BASE_LEVELS: usize = 2; const COEFF_BASE_RANGE: usize = 12; const BR_CDF_SIZE: usize = 4; const SIG_COEF_CONTEXTS_EOB: usize = 4; const SIG_COEF_CONTEXTS_2D: usize = 26; const SIG_COEF_CONTEXTS: usize = 42; const SIG_REF_DIFF_OFFSET_NUM: usize = 5; const SUPERRES_NUM: usize = 8; const SUPERRES_DENOM_MIN: usize = 9; const SUPERRES_DENOM_BITS: usize = 3; const SUPERRES_FILTER_BITS: usize = 6; const SUPERRES_FILTER_SHIFTS: usize = 1; const SUPERRES_FILTER_TAPS: usize = 8; const SUPERRES_FILTER_OFFSET: usize = 3; const SUPERRES_SCALE_BITS: usize = 14; const SUPERRES_SCALE_MASK: usize = (1 << 14) - 1; const SUPERRES_EXTRA_BITS: usize = 8; const TXB_SKIP_CONTEXTS: usize = 13; const EOB_COEF_CONTEXTS: usize = 9; const DC_SIGN_CONTEXTS: usize = 3; const LEVEL_CONTEXTS: usize = 21; const TX_CLASS_2D: usize = 0; const TX_CLASS_HORIZ: usize = 1; const TX_CLASS_VERT: usize = 2; const REFMVS_LIMIT: usize = (1 << 12) - 1; const INTRA_FILTER_SCALE_BITS: usize = 4; const INTRA_FILTER_MODES: usize = 5; const COEFF_CDF_Q_CTXS: usize = 4; const PRIMARY_REF_NONE: usize = 7; const BUFFER_POOL_MAX_SIZE: usize = 10;