use oxideav_core::bits::{BitReader, BitWriter};
use crate::{Error, Result};
pub const EXTENSION_TYPE_BITS: u32 = 4;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExtensionType {
Fill,
FillData,
DynamicRange,
SbrData,
SbrDataCrc,
}
impl ExtensionType {
pub fn from_bits(value: u8) -> Result<Self> {
match value {
0b0000 => Ok(ExtensionType::Fill),
0b0001 => Ok(ExtensionType::FillData),
0b1011 => Ok(ExtensionType::DynamicRange),
0b1101 | 0b1110 => Err(Error::UnsupportedExtensionSbr(value)),
other if other <= 0x0f => Err(Error::UnsupportedExtensionType(other)),
_ => Err(Error::UnsupportedExtensionType(value)),
}
}
pub fn from_bits_allow_sbr(value: u8) -> Result<Self> {
match value {
0b0000 => Ok(ExtensionType::Fill),
0b0001 => Ok(ExtensionType::FillData),
0b1011 => Ok(ExtensionType::DynamicRange),
0b1101 => Ok(ExtensionType::SbrData),
0b1110 => Ok(ExtensionType::SbrDataCrc),
other => Err(Error::UnsupportedExtensionType(other)),
}
}
pub fn as_u8(self) -> u8 {
match self {
ExtensionType::Fill => 0b0000,
ExtensionType::FillData => 0b0001,
ExtensionType::DynamicRange => 0b1011,
ExtensionType::SbrData => 0b1101,
ExtensionType::SbrDataCrc => 0b1110,
}
}
}
pub const FILL_DATA_BYTE: u8 = 0b1010_0101;
pub const FILL_DATA_NIBBLE: u8 = 0b0000;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExtensionPayload {
Fill {
cnt: u32,
other_bits: Vec<u8>,
},
FillData {
cnt: u32,
},
DynamicRange(DynamicRangeInfo),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExtensionPayloadOrSbr {
Payload(ExtensionPayload),
Sbr(Box<crate::sbr_extension::SbrExtensionData>),
SbrPreHeader {
crc: Option<u16>,
crc_region: Option<(u64, u64)>,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DynamicRangeInfo {
pub pce_tag: Option<PceTagFields>,
pub excluded_channels: Option<ExcludedChannels>,
pub drc_bands: Option<DrcBands>,
pub prog_ref_level: Option<ProgRefLevelFields>,
pub bands: Vec<DrcBandRecord>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PceTagFields {
pub pce_instance_tag: u8,
pub reserved: u8,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExcludedChannels {
pub exclude_mask: Vec<bool>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DrcBands {
pub band_incr: u8,
pub reserved: u8,
pub band_top: Vec<u8>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ProgRefLevelFields {
pub level: u8,
pub reserved: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DrcBandRecord {
pub dyn_rng_sgn: bool,
pub dyn_rng_ctl: u8,
}
impl ExtensionPayload {
pub fn parse(reader: &mut BitReader<'_>, cnt: u32) -> Result<Self> {
if cnt == 0 {
return Err(Error::ExtensionPayloadInvalid);
}
let raw = read_u8(reader, EXTENSION_TYPE_BITS)?;
let ty = ExtensionType::from_bits(raw)?;
match ty {
ExtensionType::Fill => parse_fill(reader, cnt),
ExtensionType::FillData => parse_fill_data(reader, cnt),
ExtensionType::DynamicRange => parse_dynamic_range(reader, cnt),
ExtensionType::SbrData | ExtensionType::SbrDataCrc => unreachable!(),
}
}
pub fn parse_with_sbr(
reader: &mut BitReader<'_>,
cnt: u32,
id_aac: crate::raw_data_block::IdSynEle,
fs_sbr: u32,
prev_header: Option<crate::sbr_header::SbrHeader>,
) -> Result<ExtensionPayloadOrSbr> {
if cnt == 0 {
return Err(Error::ExtensionPayloadInvalid);
}
let nibble_start = reader.bit_position();
let raw = read_u8(reader, EXTENSION_TYPE_BITS)?;
let ty = ExtensionType::from_bits_allow_sbr(raw)?;
match ty {
ExtensionType::Fill => Ok(ExtensionPayloadOrSbr::Payload(parse_fill(reader, cnt)?)),
ExtensionType::FillData => Ok(ExtensionPayloadOrSbr::Payload(parse_fill_data(
reader, cnt,
)?)),
ExtensionType::DynamicRange => Ok(ExtensionPayloadOrSbr::Payload(parse_dynamic_range(
reader, cnt,
)?)),
ExtensionType::SbrData | ExtensionType::SbrDataCrc => {
let crc_flag = ty == ExtensionType::SbrDataCrc;
if prev_header.is_none() {
let crc = if crc_flag {
Some(reader.read_u32(10).map_err(|_| Error::UnexpectedEnd)? as u16)
} else {
None
};
let region_start = reader.bit_position();
let header_flag = reader.read_bit().map_err(|_| Error::UnexpectedEnd)?;
if !header_flag {
let end = nibble_start + u64::from(cnt) * 8;
let mut pos = reader.bit_position();
while pos < end {
let step = (end - pos).min(32) as u32;
reader.read_u32(step).map_err(|_| Error::UnexpectedEnd)?;
pos += u64::from(step);
}
return Ok(ExtensionPayloadOrSbr::SbrPreHeader {
crc,
crc_region: crc.map(|_| (region_start, end)),
});
}
let sbr = crate::sbr_extension::SbrExtensionData::parse_after_prefix(
reader,
id_aac,
crc,
nibble_start,
fs_sbr,
Some(cnt),
None,
)?;
return Ok(ExtensionPayloadOrSbr::Sbr(Box::new(sbr)));
}
let sbr = crate::sbr_extension::SbrExtensionData::parse(
reader,
id_aac,
crc_flag,
fs_sbr,
Some(cnt),
prev_header,
)?;
Ok(ExtensionPayloadOrSbr::Sbr(Box::new(sbr)))
}
}
}
pub fn write(&self, writer: &mut BitWriter) -> Result<u32> {
match self {
ExtensionPayload::Fill { cnt, other_bits } => write_fill(writer, *cnt, other_bits),
ExtensionPayload::FillData { cnt } => write_fill_data(writer, *cnt),
ExtensionPayload::DynamicRange(drc) => write_dynamic_range(writer, drc),
}
}
pub fn byte_length(&self) -> u32 {
match self {
ExtensionPayload::Fill { cnt, .. } => *cnt,
ExtensionPayload::FillData { cnt } => *cnt,
ExtensionPayload::DynamicRange(drc) => drc.byte_length(),
}
}
}
impl DynamicRangeInfo {
pub fn byte_length(&self) -> u32 {
let mut n: u32 = 1;
if self.pce_tag.is_some() {
n += 1;
}
if let Some(ex) = &self.excluded_channels {
n += excluded_group_count(ex.exclude_mask.len()) as u32;
}
if let Some(b) = &self.drc_bands {
n += 1 + b.band_top.len() as u32;
}
if self.prog_ref_level.is_some() {
n += 1;
}
n += self.bands.len() as u32;
n
}
pub fn num_bands(&self) -> usize {
self.bands.len()
}
}
fn parse_fill(reader: &mut BitReader<'_>, cnt: u32) -> Result<ExtensionPayload> {
let body_bits = 8u32
.checked_mul(cnt.saturating_sub(1))
.ok_or(Error::ExtensionPayloadInvalid)?
.checked_add(4)
.ok_or(Error::ExtensionPayloadInvalid)?;
let other_bits = read_packed_bits(reader, body_bits)?;
Ok(ExtensionPayload::Fill { cnt, other_bits })
}
fn write_fill(writer: &mut BitWriter, cnt: u32, other_bits: &[u8]) -> Result<u32> {
if cnt == 0 {
return Err(Error::ExtensionPayloadInvalid);
}
let body_bits = 8u32
.checked_mul(cnt.saturating_sub(1))
.ok_or(Error::ExtensionPayloadInvalid)?
.checked_add(4)
.ok_or(Error::ExtensionPayloadInvalid)?;
let expected_bytes = (body_bits as usize).div_ceil(8);
if other_bits.len() != expected_bytes {
return Err(Error::ExtensionPayloadInvalid);
}
writer.write_u32(ExtensionType::Fill.as_u8() as u32, EXTENSION_TYPE_BITS);
write_packed_bits(writer, other_bits, body_bits)?;
Ok(cnt)
}
fn parse_fill_data(reader: &mut BitReader<'_>, cnt: u32) -> Result<ExtensionPayload> {
let nibble = read_u8(reader, 4)?;
if nibble != FILL_DATA_NIBBLE {
return Err(Error::ExtensionPayloadInvalid);
}
let body_bytes = cnt.saturating_sub(1) as usize;
for _ in 0..body_bytes {
let b = read_u8(reader, 8)?;
if b != FILL_DATA_BYTE {
return Err(Error::ExtensionPayloadInvalid);
}
}
Ok(ExtensionPayload::FillData { cnt })
}
fn write_fill_data(writer: &mut BitWriter, cnt: u32) -> Result<u32> {
if cnt == 0 {
return Err(Error::ExtensionPayloadInvalid);
}
writer.write_u32(ExtensionType::FillData.as_u8() as u32, EXTENSION_TYPE_BITS);
writer.write_u32(FILL_DATA_NIBBLE as u32, 4);
let body_bytes = cnt.saturating_sub(1) as usize;
for _ in 0..body_bytes {
writer.write_u32(FILL_DATA_BYTE as u32, 8);
}
Ok(cnt)
}
fn parse_dynamic_range(reader: &mut BitReader<'_>, cnt: u32) -> Result<ExtensionPayload> {
let pce_tag_present = read_bit(reader)?;
let pce_tag = if pce_tag_present {
let pce_instance_tag = read_u8(reader, 4)?;
let reserved = read_u8(reader, 4)?;
Some(PceTagFields {
pce_instance_tag,
reserved,
})
} else {
None
};
let excluded_chns_present = read_bit(reader)?;
let excluded_channels = if excluded_chns_present {
Some(parse_excluded_channels(reader)?)
} else {
None
};
let drc_bands_present = read_bit(reader)?;
let drc_bands = if drc_bands_present {
let band_incr = read_u8(reader, 4)?;
let reserved = read_u8(reader, 4)?;
let num_bands = 1usize + band_incr as usize;
let mut band_top = Vec::with_capacity(num_bands);
for _ in 0..num_bands {
band_top.push(read_u8(reader, 8)?);
}
Some(DrcBands {
band_incr,
reserved,
band_top,
})
} else {
None
};
let prog_ref_level_present = read_bit(reader)?;
let prog_ref_level = if prog_ref_level_present {
let level = read_u8(reader, 7)?;
let reserved = read_bit(reader)?;
Some(ProgRefLevelFields { level, reserved })
} else {
None
};
let num_bands = drc_bands
.as_ref()
.map(|b| 1 + b.band_incr as usize)
.unwrap_or(1);
let mut bands = Vec::with_capacity(num_bands);
for _ in 0..num_bands {
let dyn_rng_sgn = read_bit(reader)?;
let dyn_rng_ctl = read_u8(reader, 7)?;
bands.push(DrcBandRecord {
dyn_rng_sgn,
dyn_rng_ctl,
});
}
let drc = DynamicRangeInfo {
pce_tag,
excluded_channels,
drc_bands,
prog_ref_level,
bands,
};
if drc.byte_length() != cnt {
return Err(Error::ExtensionPayloadInvalid);
}
Ok(ExtensionPayload::DynamicRange(drc))
}
fn write_dynamic_range(writer: &mut BitWriter, drc: &DynamicRangeInfo) -> Result<u32> {
if let Some(p) = &drc.pce_tag {
if p.pce_instance_tag > 0x0f || p.reserved > 0x0f {
return Err(Error::ExtensionPayloadInvalid);
}
}
if let Some(b) = &drc.drc_bands {
if b.band_incr > 0x0f || b.reserved > 0x0f {
return Err(Error::ExtensionPayloadInvalid);
}
if b.band_top.len() != 1 + b.band_incr as usize {
return Err(Error::ExtensionPayloadInvalid);
}
}
if let Some(p) = &drc.prog_ref_level {
if p.level > 0x7f {
return Err(Error::ExtensionPayloadInvalid);
}
}
let expected_bands = drc
.drc_bands
.as_ref()
.map(|b| 1 + b.band_incr as usize)
.unwrap_or(1);
if drc.bands.len() != expected_bands {
return Err(Error::ExtensionPayloadInvalid);
}
for r in &drc.bands {
if r.dyn_rng_ctl > 0x7f {
return Err(Error::ExtensionPayloadInvalid);
}
}
writer.write_u32(
ExtensionType::DynamicRange.as_u8() as u32,
EXTENSION_TYPE_BITS,
);
writer.write_bit(drc.pce_tag.is_some());
if let Some(p) = &drc.pce_tag {
writer.write_u32(p.pce_instance_tag as u32, 4);
writer.write_u32(p.reserved as u32, 4);
}
writer.write_bit(drc.excluded_channels.is_some());
if let Some(ex) = &drc.excluded_channels {
write_excluded_channels(writer, ex)?;
}
writer.write_bit(drc.drc_bands.is_some());
if let Some(b) = &drc.drc_bands {
writer.write_u32(b.band_incr as u32, 4);
writer.write_u32(b.reserved as u32, 4);
for &top in &b.band_top {
writer.write_u32(top as u32, 8);
}
}
writer.write_bit(drc.prog_ref_level.is_some());
if let Some(p) = &drc.prog_ref_level {
writer.write_u32(p.level as u32, 7);
writer.write_bit(p.reserved);
}
for r in &drc.bands {
writer.write_bit(r.dyn_rng_sgn);
writer.write_u32(r.dyn_rng_ctl as u32, 7);
}
Ok(drc.byte_length())
}
fn parse_excluded_channels(reader: &mut BitReader<'_>) -> Result<ExcludedChannels> {
let mut exclude_mask = Vec::new();
loop {
for _ in 0..7 {
exclude_mask.push(read_bit(reader)?);
}
let cont = read_bit(reader)?;
if !cont {
break;
}
}
Ok(ExcludedChannels { exclude_mask })
}
fn write_excluded_channels(writer: &mut BitWriter, ex: &ExcludedChannels) -> Result<()> {
if ex.exclude_mask.is_empty() || ex.exclude_mask.len() % 7 != 0 {
return Err(Error::ExtensionPayloadInvalid);
}
let groups = ex.exclude_mask.len() / 7;
for g in 0..groups {
for i in 0..7 {
writer.write_bit(ex.exclude_mask[g * 7 + i]);
}
let last = g + 1 == groups;
writer.write_bit(!last);
}
Ok(())
}
pub fn excluded_group_count(exclude_mask_len: usize) -> usize {
exclude_mask_len.div_ceil(7)
}
fn read_packed_bits(reader: &mut BitReader<'_>, n_bits: u32) -> Result<Vec<u8>> {
let n_bytes = (n_bits as usize).div_ceil(8);
let mut out = vec![0u8; n_bytes];
let mut remaining = n_bits;
let mut idx = 0;
while remaining >= 8 {
out[idx] = read_u8(reader, 8)?;
idx += 1;
remaining -= 8;
}
if remaining > 0 {
let partial = read_u8(reader, remaining)?;
out[idx] = partial << (8 - remaining);
}
Ok(out)
}
fn write_packed_bits(writer: &mut BitWriter, bytes: &[u8], n_bits: u32) -> Result<()> {
let mut remaining = n_bits;
let mut idx = 0;
while remaining >= 8 {
writer.write_u32(bytes[idx] as u32, 8);
idx += 1;
remaining -= 8;
}
if remaining > 0 {
let partial = bytes[idx] >> (8 - remaining);
writer.write_u32(partial as u32, remaining);
}
Ok(())
}
fn read_u8(reader: &mut BitReader<'_>, n: u32) -> Result<u8> {
debug_assert!(n <= 8);
Ok(reader.read_u32(n).map_err(|_| Error::UnexpectedEnd)? as u8)
}
fn read_bit(reader: &mut BitReader<'_>) -> Result<bool> {
reader.read_bit().map_err(|_| Error::UnexpectedEnd)
}