use std::io::{Cursor, Read};
use media_codec_bitstream::{BigEndian, ByteRead, ByteReader};
use media_core::{invalid_data_error, Result};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AvccExt {
pub chroma_format: u8,
pub bit_depth_luma: u8,
pub bit_depth_chroma: u8,
pub sequence_parameter_sets_ext: Vec<Vec<u8>>,
}
impl Default for AvccExt {
fn default() -> Self {
Self {
chroma_format: 1, bit_depth_luma: 8,
bit_depth_chroma: 8,
sequence_parameter_sets_ext: Vec::new(),
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Avcc {
pub configuration_version: u8,
pub avc_profile_indication: u8,
pub profile_compatibility: u8,
pub avc_level_indication: u8,
pub length_size: u8,
pub sequence_parameter_sets: Vec<Vec<u8>>,
pub picture_parameter_sets: Vec<Vec<u8>>,
pub ext: Option<AvccExt>,
}
impl Avcc {
pub fn parse(data: &[u8]) -> Result<Self> {
let cursor = Cursor::new(data);
Self::parse_from_reader(cursor)
}
pub fn parse_from_reader<R: Read>(reader: R) -> Result<Self> {
let mut reader = ByteReader::endian(reader, BigEndian);
Self::parse_from_byte_reader(&mut reader)
}
pub fn parse_from_byte_reader<R: Read>(reader: &mut ByteReader<R, BigEndian>) -> Result<Self> {
let configuration_version = reader.read::<u8>()?;
if configuration_version != 1 {
return Err(invalid_data_error!("configuration_version", configuration_version));
}
let avc_profile_indication = reader.read::<u8>()?;
let profile_compatibility = reader.read::<u8>()?;
let avc_level_indication = reader.read::<u8>()?;
let length_size_byte = reader.read::<u8>()?;
let length_size = (length_size_byte & 0b11) + 1;
if length_size != 1 && length_size != 2 && length_size != 4 {
return Err(invalid_data_error!("NAL unit length size", length_size));
}
let num_sps_byte = reader.read::<u8>()?;
let num_sps = num_sps_byte & 0b0001_1111;
let mut sequence_parameter_sets = Vec::with_capacity(num_sps as usize);
for _ in 0..num_sps {
let sps_length = reader.read::<u16>()? as usize;
let mut sps_data = vec![0u8; sps_length];
reader.read_bytes(&mut sps_data)?;
sequence_parameter_sets.push(sps_data);
}
let num_pps = reader.read::<u8>()?;
let mut picture_parameter_sets = Vec::with_capacity(num_pps as usize);
for _ in 0..num_pps {
let pps_length = reader.read::<u16>()? as usize;
let mut pps_data = vec![0u8; pps_length];
reader.read_bytes(&mut pps_data)?;
picture_parameter_sets.push(pps_data);
}
let ext = Self::try_parse_ext(reader);
Ok(Self {
configuration_version,
avc_profile_indication,
profile_compatibility,
avc_level_indication,
length_size,
sequence_parameter_sets,
picture_parameter_sets,
ext,
})
}
fn try_parse_ext<R: Read>(reader: &mut ByteReader<R, BigEndian>) -> Option<AvccExt> {
let chroma_format_byte = match reader.read::<u8>() {
Ok(b) => b,
Err(_) => return None,
};
let chroma_format = chroma_format_byte & 0b11;
let bit_depth_luma_byte = match reader.read::<u8>() {
Ok(b) => b,
Err(_) => return None,
};
let bit_depth_luma = (bit_depth_luma_byte & 0b111) + 8;
let bit_depth_chroma_byte = match reader.read::<u8>() {
Ok(b) => b,
Err(_) => return None,
};
let bit_depth_chroma = (bit_depth_chroma_byte & 0b111) + 8;
let num_sps_ext = match reader.read::<u8>() {
Ok(n) => n,
Err(_) => return None,
};
let mut sps_ext = Vec::with_capacity(num_sps_ext as usize);
for _ in 0..num_sps_ext {
let sps_ext_length = match reader.read::<u16>() {
Ok(len) => len as usize,
Err(_) => break,
};
let mut sps_ext_data = vec![0u8; sps_ext_length];
if reader.read_bytes(&mut sps_ext_data).is_err() {
break;
}
sps_ext.push(sps_ext_data);
}
Some(AvccExt {
chroma_format,
bit_depth_luma,
bit_depth_chroma,
sequence_parameter_sets_ext: sps_ext,
})
}
}