use crate::bitreader::BitReader;
use crate::error::DecodeError;
use crate::fmt::{BitDepth, ChromaFormat};
#[derive(Debug, Clone)]
pub(crate) struct Sps {
pub(crate) chroma_idc: u8,
pub(crate) chroma: ChromaFormat,
pub(crate) separate_color_plane: bool,
pub(crate) width: u32,
pub(crate) height: u32,
pub(crate) crop_left: u32,
pub(crate) crop_right: u32,
pub(crate) crop_top: u32,
pub(crate) crop_bottom: u32,
pub(crate) bit_depth_luma: u8,
pub(crate) bit_depth_chroma: u8,
pub(crate) log2_ctb: u32,
pub(crate) log2_min_cb: u32,
pub(crate) log2_min_tb: u32,
pub(crate) log2_max_tb: u32,
pub(crate) max_transform_hierarchy_intra: u32,
pub(crate) _max_transform_hierarchy_inter: u32,
pub(crate) _scaling_list_enabled: bool,
pub(crate) _amp_enabled: bool,
pub(crate) sao_enabled: bool,
pub(crate) _pcm_enabled: bool,
pub(crate) _pcm_bit_depth_luma: u8,
pub(crate) _pcm_bit_depth_chroma: u8,
pub(crate) _log2_min_pcm_cb: u32,
pub(crate) _log2_max_pcm_cb: u32,
pub(crate) _pcm_loop_filter_disabled: bool,
pub(crate) strong_intra_smoothing: bool,
pub(crate) video_full_range: bool,
pub(crate) color_primaries: u8, pub(crate) transfer_characteristics: u8, pub(crate) matrix_coefficients: u8, }
#[derive(Debug, Clone)]
pub(crate) struct Pps {
pub(crate) dependent_slice_segments_enabled: bool,
pub(crate) output_flag_present: bool,
pub(crate) num_extra_slice_header_bits: u32,
pub(crate) sign_data_hiding_enabled: bool,
pub(crate) _cabac_init_present: bool,
pub(crate) init_qp: i32,
pub(crate) _constrained_intra_pred: bool,
pub(crate) transform_skip_enabled: bool,
pub(crate) cu_qp_delta_enabled: bool,
pub(crate) diff_cu_qp_delta_depth: u32,
pub(crate) cb_qp_offset: i32,
pub(crate) cr_qp_offset: i32,
pub(crate) slice_chroma_qp_offsets_present: bool,
pub(crate) _weighted_pred: bool,
pub(crate) _weighted_bipred: bool,
pub(crate) transquant_bypass_enabled: bool,
pub(crate) tiles_enabled: bool,
pub(crate) entropy_coding_sync_enabled: bool,
pub(crate) loop_filter_across_slices: bool,
pub(crate) _deblocking_filter_control_present: bool,
pub(crate) deblocking_filter_override_enabled: bool,
pub(crate) deblocking_filter_disabled: bool,
pub(crate) beta_offset_div2: i32,
pub(crate) tc_offset_div2: i32,
pub(crate) _scaling_list_data_present: bool,
pub(crate) _lists_modification_present: bool,
pub(crate) _log2_parallel_merge_level: u32,
pub(crate) slice_segment_header_extension_present: bool,
}
impl Sps {
pub(crate) fn bit_depth(&self) -> Result<BitDepth, DecodeError> {
match self.bit_depth_luma {
8 => Ok(BitDepth::Eight),
10 => Ok(BitDepth::Ten),
12 => Ok(BitDepth::Twelve),
n => Err(DecodeError::UnsupportedBitDepth(n)),
}
}
}
fn e(s: &'static str) -> DecodeError {
DecodeError::ParamSet(s.into())
}
fn parse_ptl(r: &mut BitReader, max_sub_layers_minus1: u32) -> Result<(), DecodeError> {
r.read_bits(8).map_err(|_| e("ptl profile byte"))?; r.read_bits(32).map_err(|_| e("ptl compat"))?; r.read_bits(32).map_err(|_| e("ptl constraint hi"))?; r.read_bits(16).map_err(|_| e("ptl constraint lo"))?;
r.read_bits(8).map_err(|_| e("ptl level"))?;
let n = max_sub_layers_minus1 as usize;
let mut prof = vec![false; n];
let mut lvl = vec![false; n];
for i in 0..n {
prof[i] = r.read_flag().map_err(|_| e("sub prof flag"))?;
lvl[i] = r.read_flag().map_err(|_| e("sub lvl flag"))?;
}
if n > 0 {
for _ in n..8 {
r.read_bits(2).map_err(|_| e("ptl reserved"))?;
}
}
for i in 0..n {
if prof[i] {
r.read_bits(8)?;
r.read_bits(32)?;
r.read_bits(32)?;
r.read_bits(16)?;
}
if lvl[i] {
r.read_bits(8)?;
}
}
Ok(())
}
fn skip_scaling_list_data(r: &mut BitReader) -> Result<(), DecodeError> {
for size_id in 0..4 {
let mut matrix_id = 0;
while matrix_id < 6 {
let pred_mode_flag = r
.read_flag()
.map_err(|_| e("scaling_list_pred_mode_flag"))?;
if !pred_mode_flag {
r.read_ue()
.map_err(|_| e("scaling_list_pred_matrix_id_delta"))?;
} else {
let coef_num = std::cmp::min(64, 1 << (4 + (size_id << 1)));
if size_id > 1 {
r.read_se().map_err(|_| e("scaling_list_dc_coef"))?;
}
for _ in 0..coef_num {
r.read_se().map_err(|_| e("scaling_list_delta_coef"))?;
}
}
matrix_id += if size_id == 3 { 3 } else { 1 };
}
}
Ok(())
}
fn parse_st_rps(
r: &mut BitReader,
idx: usize,
num_sets: usize,
num_delta_pocs: &mut Vec<u32>,
) -> Result<(), DecodeError> {
let mut inter_pred = false;
if idx != 0 {
inter_pred = r.read_flag().map_err(|_| e("inter_ref_pic_set_pred"))?;
}
if inter_pred {
if idx == num_sets {
r.read_ue().map_err(|_| e("delta_idx_minus1"))?;
}
r.read_bit().map_err(|_| e("delta_rps_sign"))?;
r.read_ue().map_err(|_| e("abs_delta_rps_minus1"))?;
let ref_idx = idx - 1; let n = num_delta_pocs.get(ref_idx).copied().unwrap_or(0);
let mut count = 0u32;
for _ in 0..=n {
let used = r.read_flag().map_err(|_| e("used_by_curr_pic"))?;
if !used {
let use_delta = r.read_flag().map_err(|_| e("use_delta_flag"))?;
if use_delta {
count += 1;
}
} else {
count += 1;
}
}
num_delta_pocs.push(count);
} else {
let num_neg = r.read_ue().map_err(|_| e("num_negative_pics"))?;
let num_pos = r.read_ue().map_err(|_| e("num_positive_pics"))?;
for _ in 0..num_neg {
r.read_ue().map_err(|_| e("delta_poc_s0"))?;
r.read_bit().map_err(|_| e("used_by_curr_s0"))?;
}
for _ in 0..num_pos {
r.read_ue().map_err(|_| e("delta_poc_s1"))?;
r.read_bit().map_err(|_| e("used_by_curr_s1"))?;
}
num_delta_pocs.push(num_neg + num_pos);
}
Ok(())
}
pub(crate) fn parse_sps(rbsp: &[u8]) -> Result<Sps, DecodeError> {
let mut r = BitReader::new(rbsp);
r.read_bits(4).map_err(|_| e("sps_vps_id"))?;
let max_sub_layers_minus1 = r.read_bits(3).map_err(|_| e("max_sub_layers"))?;
r.read_bit().map_err(|_| e("temporal_id_nesting"))?;
parse_ptl(&mut r, max_sub_layers_minus1)?;
let _sps_id = r.read_ue().map_err(|_| e("sps_id"))?;
let chroma_idc = r.read_ue().map_err(|_| e("chroma_idc"))? as u8;
let separate_color_plane = if chroma_idc == 3 {
r.read_flag().map_err(|_| e("separate_color_plane"))?
} else {
false
};
let width = r.read_ue().map_err(|_| e("pic_width"))?;
let height = r.read_ue().map_err(|_| e("pic_height"))?;
let (mut crop_left, mut crop_right, mut crop_top, mut crop_bottom) = (0, 0, 0, 0);
if r.read_flag().map_err(|_| e("conf_win"))? {
crop_left = r.read_ue().map_err(|_| e("cw_left"))?;
crop_right = r.read_ue().map_err(|_| e("cw_right"))?;
crop_top = r.read_ue().map_err(|_| e("cw_top"))?;
crop_bottom = r.read_ue().map_err(|_| e("cw_bottom"))?;
}
let bit_depth_luma = r.read_ue().map_err(|_| e("bd_luma"))? as u8 + 8;
let bit_depth_chroma = r.read_ue().map_err(|_| e("bd_chroma"))? as u8 + 8;
let log2_max_poc = r.read_ue().map_err(|_| e("log2_max_poc"))? + 4;
let _ = log2_max_poc;
let sub_layer_ordering = r.read_flag().map_err(|_| e("sub_layer_ordering"))?;
let start = if sub_layer_ordering {
0
} else {
max_sub_layers_minus1
};
for _ in start..=max_sub_layers_minus1 {
r.read_ue().map_err(|_| e("max_dec_pic_buffering"))?;
r.read_ue().map_err(|_| e("num_reorder_pics"))?;
r.read_ue().map_err(|_| e("max_latency"))?;
}
let log2_min_cb = r.read_ue().map_err(|_| e("log2_min_cb"))? + 3;
let log2_diff_max_min_cb = r.read_ue().map_err(|_| e("log2_diff_max_min_cb"))?;
let log2_ctb = log2_min_cb + log2_diff_max_min_cb;
let log2_min_tb = r.read_ue().map_err(|_| e("log2_min_tb"))? + 2;
let log2_diff_max_min_tb = r.read_ue().map_err(|_| e("log2_diff_max_min_tb"))?;
let log2_max_tb = log2_min_tb + log2_diff_max_min_tb;
let max_transform_hierarchy_inter = r.read_ue().map_err(|_| e("mth_inter"))?;
let max_transform_hierarchy_intra = r.read_ue().map_err(|_| e("mth_intra"))?;
let scaling_list_enabled = r.read_flag().map_err(|_| e("scaling_list_enabled"))?;
if scaling_list_enabled {
let present = r.read_flag().map_err(|_| e("sps_scaling_list_present"))?;
if present {
skip_scaling_list_data(&mut r)?;
}
}
let amp_enabled = r.read_flag().map_err(|_| e("amp"))?;
let sao_enabled = r.read_flag().map_err(|_| e("sao"))?;
let pcm_enabled = r.read_flag().map_err(|_| e("pcm"))?;
let mut pcm_bit_depth_luma = 0;
let mut pcm_bit_depth_chroma = 0;
let mut log2_min_pcm_cb = 0;
let mut log2_max_pcm_cb = 0;
let mut pcm_loop_filter_disabled = false;
if pcm_enabled {
pcm_bit_depth_luma = r.read_bits(4).map_err(|_| e("pcm_bd_luma"))? as u8 + 1;
pcm_bit_depth_chroma = r.read_bits(4).map_err(|_| e("pcm_bd_chroma"))? as u8 + 1;
log2_min_pcm_cb = r.read_ue().map_err(|_| e("log2_min_pcm"))? + 3;
let diff = r.read_ue().map_err(|_| e("log2_diff_pcm"))?;
log2_max_pcm_cb = log2_min_pcm_cb + diff;
pcm_loop_filter_disabled = r.read_flag().map_err(|_| e("pcm_loop_filter"))?;
}
let num_st_rps = r.read_ue().map_err(|_| e("num_short_term_rps"))? as usize;
let mut num_delta_pocs = Vec::with_capacity(num_st_rps);
for i in 0..num_st_rps {
parse_st_rps(&mut r, i, num_st_rps, &mut num_delta_pocs)?;
}
let long_term_present = r.read_flag().map_err(|_| e("long_term_present"))?;
if long_term_present {
let num_lt = r.read_ue().map_err(|_| e("num_long_term"))? as usize;
for _ in 0..num_lt {
r.read_bits(log2_max_poc).map_err(|_| e("lt_ref_poc"))?;
r.read_bit().map_err(|_| e("used_by_curr_lt"))?;
}
}
let _temporal_mvp = r.read_flag().map_err(|_| e("temporal_mvp"))?;
let strong_intra_smoothing = r.read_flag().map_err(|_| e("strong_intra_smoothing"))?;
let mut video_full_range = false;
let mut color_primaries = 2u8; let mut transfer_characteristics = 2u8; let mut matrix_coefficients = 2u8; if r.read_flag().map_err(|_| e("vui_present"))? {
if r.read_flag().map_err(|_| e("ar_present"))? {
let ar_idc = r.read_bits(8).map_err(|_| e("ar_idc"))?;
if ar_idc == 255 {
r.read_bits(16).map_err(|_| e("sar_w"))?;
r.read_bits(16).map_err(|_| e("sar_h"))?;
}
}
if r.read_flag().map_err(|_| e("overscan_present"))? {
r.read_flag().map_err(|_| e("overscan"))?;
}
if r.read_flag().map_err(|_| e("vst_present"))? {
r.read_bits(3).map_err(|_| e("video_format"))?; video_full_range = r.read_flag().map_err(|_| e("full_range"))?;
if r.read_flag().map_err(|_| e("color_desc"))? {
color_primaries = r.read_bits(8).map_err(|_| e("color_primaries"))? as u8;
transfer_characteristics = r.read_bits(8).map_err(|_| e("transfer_char"))? as u8;
matrix_coefficients = r.read_bits(8).map_err(|_| e("matrix_coeff"))? as u8;
}
}
}
let chroma = match chroma_idc {
0 => ChromaFormat::Monochrome,
1 => ChromaFormat::Yuv420,
2 => ChromaFormat::Yuv422,
3 => ChromaFormat::Yuv444,
n => return Err(DecodeError::UnsupportedChroma(n)),
};
Ok(Sps {
chroma_idc,
chroma,
separate_color_plane,
width,
height,
crop_left,
crop_right,
crop_top,
crop_bottom,
bit_depth_luma,
bit_depth_chroma,
log2_ctb,
log2_min_cb,
log2_min_tb,
log2_max_tb,
max_transform_hierarchy_intra,
_max_transform_hierarchy_inter: max_transform_hierarchy_inter,
_scaling_list_enabled: scaling_list_enabled,
_amp_enabled: amp_enabled,
sao_enabled,
_pcm_enabled: pcm_enabled,
_pcm_bit_depth_luma: pcm_bit_depth_luma,
_pcm_bit_depth_chroma: pcm_bit_depth_chroma,
_log2_min_pcm_cb: log2_min_pcm_cb,
_log2_max_pcm_cb: log2_max_pcm_cb,
_pcm_loop_filter_disabled: pcm_loop_filter_disabled,
strong_intra_smoothing,
video_full_range,
color_primaries,
transfer_characteristics,
matrix_coefficients,
})
}
pub(crate) fn parse_pps(rbsp: &[u8]) -> Result<Pps, DecodeError> {
let mut r = BitReader::new(rbsp);
let _pps_id = r.read_ue().map_err(|_| e("pps_id"))?;
let _sps_id = r.read_ue().map_err(|_| e("pps_sps_id"))?;
let dependent_slice_segments_enabled = r.read_flag().map_err(|_| e("dep_slices"))?;
let output_flag_present = r.read_flag().map_err(|_| e("output_flag_present"))?;
let num_extra_slice_header_bits = r.read_bits(3).map_err(|_| e("extra_hdr_bits"))?;
let sign_data_hiding_enabled = r.read_flag().map_err(|_| e("sign_hiding"))?;
let cabac_init_present = r.read_flag().map_err(|_| e("cabac_init"))?;
let _nref0 = r.read_ue().map_err(|_| e("nref0"))?;
let _nref1 = r.read_ue().map_err(|_| e("nref1"))?;
let init_qp = 26 + r.read_se().map_err(|_| e("init_qp"))?;
let constrained_intra_pred = r.read_flag().map_err(|_| e("constrained_intra"))?;
let transform_skip_enabled = r.read_flag().map_err(|_| e("transform_skip"))?;
let cu_qp_delta_enabled = r.read_flag().map_err(|_| e("cu_qp_delta"))?;
let diff_cu_qp_delta_depth = if cu_qp_delta_enabled {
r.read_ue().map_err(|_| e("diff_cu_qp_delta_depth"))?
} else {
0
};
let cb_qp_offset = r.read_se().map_err(|_| e("cb_qp_offset"))?;
let cr_qp_offset = r.read_se().map_err(|_| e("cr_qp_offset"))?;
let slice_chroma_qp_offsets_present = r.read_flag().map_err(|_| e("slice_chroma_qp"))?;
let weighted_pred = r.read_flag().map_err(|_| e("weighted_pred"))?;
let weighted_bipred = r.read_flag().map_err(|_| e("weighted_bipred"))?;
let transquant_bypass_enabled = r.read_flag().map_err(|_| e("transquant_bypass"))?;
let tiles_enabled = r.read_flag().map_err(|_| e("tiles"))?;
let entropy_coding_sync_enabled = r.read_flag().map_err(|_| e("entropy_sync"))?;
if tiles_enabled {
let cols = r.read_ue().map_err(|_| e("num_tile_cols"))?;
let rows = r.read_ue().map_err(|_| e("num_tile_rows"))?;
let uniform = r.read_flag().map_err(|_| e("uniform_spacing"))?;
if !uniform {
for _ in 0..cols {
r.read_ue().map_err(|_| e("col_width"))?;
}
for _ in 0..rows {
r.read_ue().map_err(|_| e("row_height"))?;
}
}
r.read_flag().map_err(|_| e("loop_filter_across_tiles"))?;
}
let loop_filter_across_slices = r.read_flag().map_err(|_| e("loop_filter_across_slices"))?;
let deblocking_filter_control_present = r.read_flag().map_err(|_| e("deblock_control"))?;
let mut deblocking_filter_override_enabled = false;
let mut deblocking_filter_disabled = false;
let mut beta_offset_div2 = 0;
let mut tc_offset_div2 = 0;
if deblocking_filter_control_present {
deblocking_filter_override_enabled = r.read_flag().map_err(|_| e("deblock_override"))?;
deblocking_filter_disabled = r.read_flag().map_err(|_| e("deblock_disabled"))?;
if !deblocking_filter_disabled {
beta_offset_div2 = r.read_se().map_err(|_| e("beta_offset"))?;
tc_offset_div2 = r.read_se().map_err(|_| e("tc_offset"))?;
}
}
let scaling_list_data_present = r.read_flag().map_err(|_| e("pps_scaling_list_present"))?;
if scaling_list_data_present {
skip_scaling_list_data(&mut r)?;
}
let lists_modification_present = r.read_flag().map_err(|_| e("lists_modification"))?;
let log2_parallel_merge_level = r.read_ue().map_err(|_| e("log2_parallel_merge"))? + 2;
let slice_segment_header_extension_present = r.read_flag().map_err(|_| e("slice_hdr_ext"))?;
Ok(Pps {
dependent_slice_segments_enabled,
output_flag_present,
num_extra_slice_header_bits,
sign_data_hiding_enabled,
_cabac_init_present: cabac_init_present,
init_qp,
_constrained_intra_pred: constrained_intra_pred,
transform_skip_enabled,
cu_qp_delta_enabled,
diff_cu_qp_delta_depth,
cb_qp_offset,
cr_qp_offset,
slice_chroma_qp_offsets_present,
_weighted_pred: weighted_pred,
_weighted_bipred: weighted_bipred,
transquant_bypass_enabled,
tiles_enabled,
entropy_coding_sync_enabled,
loop_filter_across_slices,
_deblocking_filter_control_present: deblocking_filter_control_present,
deblocking_filter_override_enabled,
deblocking_filter_disabled,
beta_offset_div2,
tc_offset_div2,
_scaling_list_data_present: scaling_list_data_present,
_lists_modification_present: lists_modification_present,
_log2_parallel_merge_level: log2_parallel_merge_level,
slice_segment_header_extension_present,
})
}
pub(crate) fn parse_hvcc_full(hvcc: &[u8]) -> Result<(Sps, Pps), DecodeError> {
if hvcc.len() < 23 {
return Err(DecodeError::ParamSet("hvcC too short".into()));
}
let num_arrays = hvcc[22] as usize;
let mut pos = 23usize;
let mut sps_rbsp = None;
let mut pps_rbsp = None;
for _ in 0..num_arrays {
if pos + 3 > hvcc.len() {
break;
}
let nal_type = hvcc[pos] & 0x3f;
pos += 1;
let count = u16::from_be_bytes([hvcc[pos], hvcc[pos + 1]]) as usize;
pos += 2;
for _ in 0..count {
if pos + 2 > hvcc.len() {
break;
}
let nlen = u16::from_be_bytes([hvcc[pos], hvcc[pos + 1]]) as usize;
pos += 2;
if pos + nlen > hvcc.len() {
break;
}
let nalu = &hvcc[pos..pos + nlen];
pos += nlen;
if nalu.len() < 2 {
continue;
}
let rbsp = crate::bitreader::unescape_rbsp(&nalu[2..]);
match nal_type {
33 => sps_rbsp = Some(rbsp),
34 => pps_rbsp = Some(rbsp),
_ => {}
}
}
}
let sps = parse_sps(&sps_rbsp.ok_or_else(|| e("no SPS"))?)?;
let pps = parse_pps(&pps_rbsp.ok_or_else(|| e("no PPS"))?)?;
Ok((sps, pps))
}