use oxideav_core::bits::{BitReader, BitWriter};
use crate::asc::AacResilienceFlags;
use crate::gain_control_data::GainControlData;
use crate::ics_info::{IcsInfo, WindowSequence};
use crate::pulse_data::PulseData;
use crate::scale_factor_data::{ErScaleFactorData, ScaleFactorData};
use crate::section_data::SectionData;
use crate::swb_offset::FrameFamily;
use crate::tns_data::TnsData;
use crate::{Error, Result};
pub const GLOBAL_GAIN_BITS: u32 = 8;
pub const AOT_AAC_SSR: u8 = 3;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IcsBody {
pub global_gain: u8,
pub ics_info: Option<IcsInfo>,
pub section_data: SectionData,
pub scale_factor_data: ScaleFactorData,
pub pulse_data_present: bool,
pub pulse_data: Option<PulseData>,
pub tns_data_present: bool,
pub tns_data: Option<TnsData>,
pub gain_control_data_present: bool,
pub gain_control_data: Option<GainControlData>,
pub spectral_data_bit_offset: u64,
pub er_scale_factor_data: Option<ErScaleFactorData>,
pub reordered_spectral_lengths: Option<(u16, u8)>,
}
impl IcsBody {
pub fn parse(
reader: &mut BitReader<'_>,
audio_object_type: u8,
sampling_frequency_index: u8,
scale_flag: bool,
) -> Result<Self> {
Self::parse_family(
reader,
FrameFamily::Lc1024,
audio_object_type,
sampling_frequency_index,
scale_flag,
)
}
pub fn parse_family(
reader: &mut BitReader<'_>,
family: FrameFamily,
audio_object_type: u8,
sampling_frequency_index: u8,
scale_flag: bool,
) -> Result<Self> {
Self::parse_inner(
reader,
family,
audio_object_type,
sampling_frequency_index,
false,
scale_flag,
)
}
pub fn parse_with_ics_info(
reader: &mut BitReader<'_>,
ics_info: &IcsInfo,
audio_object_type: u8,
scale_flag: bool,
) -> Result<Self> {
if scale_flag {
return Err(Error::NotImplemented);
}
let start = reader.bit_position();
let global_gain = read_u8(reader, GLOBAL_GAIN_BITS)?;
let section_data = SectionData::parse(
reader,
ics_info.window_sequence,
ics_info.num_window_groups,
ics_info.max_sfb,
)?;
let scale_factor_data = ScaleFactorData::parse(reader, §ion_data.sfb_cb)?;
let tools = parse_tools(reader, ics_info, audio_object_type, start)?;
Ok(IcsBody {
global_gain,
ics_info: None,
section_data,
scale_factor_data,
pulse_data_present: tools.pulse_data_present,
pulse_data: tools.pulse_data,
tns_data_present: tools.tns_data_present,
tns_data: tools.tns_data,
gain_control_data_present: tools.gain_control_data_present,
gain_control_data: tools.gain_control_data,
spectral_data_bit_offset: tools.spectral_data_bit_offset,
er_scale_factor_data: None,
reordered_spectral_lengths: None,
})
}
fn parse_inner(
reader: &mut BitReader<'_>,
family: FrameFamily,
audio_object_type: u8,
sampling_frequency_index: u8,
common_window: bool,
scale_flag: bool,
) -> Result<Self> {
if scale_flag {
return Err(Error::NotImplemented);
}
let start = reader.bit_position();
let global_gain = read_u8(reader, GLOBAL_GAIN_BITS)?;
let ics_info = IcsInfo::parse_family(
reader,
family,
audio_object_type,
sampling_frequency_index,
common_window,
)?;
let section_data = SectionData::parse(
reader,
ics_info.window_sequence,
ics_info.num_window_groups,
ics_info.max_sfb,
)?;
let scale_factor_data = ScaleFactorData::parse(reader, §ion_data.sfb_cb)?;
let tools = parse_tools(reader, &ics_info, audio_object_type, start)?;
Ok(IcsBody {
global_gain,
ics_info: Some(ics_info),
section_data,
scale_factor_data,
pulse_data_present: tools.pulse_data_present,
pulse_data: tools.pulse_data,
tns_data_present: tools.tns_data_present,
tns_data: tools.tns_data,
gain_control_data_present: tools.gain_control_data_present,
gain_control_data: tools.gain_control_data,
spectral_data_bit_offset: tools.spectral_data_bit_offset,
er_scale_factor_data: None,
reordered_spectral_lengths: None,
})
}
pub fn parse_er(
reader: &mut BitReader<'_>,
audio_object_type: u8,
sampling_frequency_index: u8,
scale_flag: bool,
resilience: AacResilienceFlags,
) -> Result<Self> {
Self::parse_er_family(
reader,
FrameFamily::Lc1024,
audio_object_type,
sampling_frequency_index,
scale_flag,
resilience,
)
}
pub fn parse_er_family(
reader: &mut BitReader<'_>,
family: FrameFamily,
audio_object_type: u8,
sampling_frequency_index: u8,
scale_flag: bool,
resilience: AacResilienceFlags,
) -> Result<Self> {
if scale_flag {
return Err(Error::NotImplemented);
}
let start = reader.bit_position();
let global_gain = read_u8(reader, GLOBAL_GAIN_BITS)?;
let ics_info = IcsInfo::parse_family(
reader,
family,
audio_object_type,
sampling_frequency_index,
false,
)?;
let mut body = Self::finish_er_shared(
reader,
global_gain,
&ics_info,
audio_object_type,
resilience,
start,
)?;
body.ics_info = Some(ics_info);
Ok(body)
}
pub fn parse_with_ics_info_er(
reader: &mut BitReader<'_>,
ics_info: &IcsInfo,
audio_object_type: u8,
scale_flag: bool,
resilience: AacResilienceFlags,
) -> Result<Self> {
if scale_flag {
return Err(Error::NotImplemented);
}
let start = reader.bit_position();
let global_gain = read_u8(reader, GLOBAL_GAIN_BITS)?;
Self::finish_er_shared(
reader,
global_gain,
ics_info,
audio_object_type,
resilience,
start,
)
}
fn finish_er_shared(
reader: &mut BitReader<'_>,
global_gain: u8,
ics_info: &IcsInfo,
audio_object_type: u8,
resilience: AacResilienceFlags,
start: u64,
) -> Result<Self> {
let section_data = if resilience.section_data {
SectionData::parse_er(
reader,
ics_info.window_sequence,
ics_info.num_window_groups,
ics_info.max_sfb,
)?
} else {
SectionData::parse(
reader,
ics_info.window_sequence,
ics_info.num_window_groups,
ics_info.max_sfb,
)?
};
let (scale_factor_data, er_scale_factor_data) = if resilience.scalefactor_data {
let er =
ErScaleFactorData::parse(reader, §ion_data.sfb_cb, ics_info.window_sequence)?;
(er.data.clone(), Some(er))
} else {
(ScaleFactorData::parse(reader, §ion_data.sfb_cb)?, None)
};
let tools = parse_tools(reader, ics_info, audio_object_type, start)?;
let reordered_spectral_lengths = if resilience.spectral_data {
let len_reordered = reader.read_u32(14).map_err(|_| Error::UnexpectedEnd)? as u16;
let len_longest = reader.read_u32(6).map_err(|_| Error::UnexpectedEnd)? as u8;
Some((len_reordered, len_longest))
} else {
None
};
let spectral_data_bit_offset = reader.bit_position() - start;
Ok(IcsBody {
global_gain,
ics_info: None,
section_data,
scale_factor_data,
pulse_data_present: tools.pulse_data_present,
pulse_data: tools.pulse_data,
tns_data_present: tools.tns_data_present,
tns_data: tools.tns_data,
gain_control_data_present: tools.gain_control_data_present,
gain_control_data: tools.gain_control_data,
spectral_data_bit_offset,
er_scale_factor_data,
reordered_spectral_lengths,
})
}
pub fn parse_scale(
reader: &mut BitReader<'_>,
ics_info: &IcsInfo,
resilience: AacResilienceFlags,
) -> Result<Self> {
let start = reader.bit_position();
let global_gain = read_u8(reader, GLOBAL_GAIN_BITS)?;
let section_data = if resilience.section_data {
SectionData::parse_er(
reader,
ics_info.window_sequence,
ics_info.num_window_groups,
ics_info.max_sfb,
)?
} else {
SectionData::parse(
reader,
ics_info.window_sequence,
ics_info.num_window_groups,
ics_info.max_sfb,
)?
};
let (scale_factor_data, er_scale_factor_data) = if resilience.scalefactor_data {
let er =
ErScaleFactorData::parse(reader, §ion_data.sfb_cb, ics_info.window_sequence)?;
(er.data.clone(), Some(er))
} else {
(ScaleFactorData::parse(reader, §ion_data.sfb_cb)?, None)
};
let reordered_spectral_lengths = if resilience.spectral_data {
let len_reordered = reader.read_u32(14).map_err(|_| Error::UnexpectedEnd)? as u16;
let len_longest = reader.read_u32(6).map_err(|_| Error::UnexpectedEnd)? as u8;
Some((len_reordered, len_longest))
} else {
None
};
let spectral_data_bit_offset = reader.bit_position() - start;
Ok(IcsBody {
global_gain,
ics_info: None,
section_data,
scale_factor_data,
pulse_data_present: false,
pulse_data: None,
tns_data_present: false,
tns_data: None,
gain_control_data_present: false,
gain_control_data: None,
spectral_data_bit_offset,
er_scale_factor_data,
reordered_spectral_lengths,
})
}
pub fn write_scale(
&self,
writer: &mut BitWriter,
ics_info: &IcsInfo,
resilience: AacResilienceFlags,
) -> Result<()> {
writer.write_u32(u32::from(self.global_gain), GLOBAL_GAIN_BITS);
if resilience.section_data {
self.section_data
.write_er(writer, ics_info.window_sequence, ics_info.max_sfb)?;
} else {
self.section_data
.write(writer, ics_info.window_sequence, ics_info.max_sfb)?;
}
if resilience.scalefactor_data {
let er = self
.er_scale_factor_data
.as_ref()
.ok_or(Error::ElementDecodeInvalid)?;
er.write(writer, &self.section_data.sfb_cb, ics_info.window_sequence)?;
} else {
self.scale_factor_data
.write(writer, &self.section_data.sfb_cb)?;
}
if resilience.spectral_data {
let (len_reordered, len_longest) = self
.reordered_spectral_lengths
.ok_or(Error::ElementDecodeInvalid)?;
writer.write_u32(u32::from(len_reordered), 14);
writer.write_u32(u32::from(len_longest), 6);
}
Ok(())
}
pub fn write(
&self,
writer: &mut BitWriter,
audio_object_type: u8,
sampling_frequency_index: u8,
scale_flag: bool,
) -> Result<()> {
if scale_flag {
return Err(Error::NotImplemented);
}
let ics_info = self.ics_info.as_ref().ok_or(Error::IcsInfoEncodeInvalid)?;
writer.write_u32(u32::from(self.global_gain), GLOBAL_GAIN_BITS);
ics_info.write(writer, audio_object_type, sampling_frequency_index, false)?;
self.section_data
.write(writer, ics_info.window_sequence, ics_info.max_sfb)?;
self.scale_factor_data
.write(writer, &self.section_data.sfb_cb)?;
self.write_tools(writer, ics_info, audio_object_type)
}
pub fn write_with_ics_info(
&self,
writer: &mut BitWriter,
ics_info: &IcsInfo,
audio_object_type: u8,
scale_flag: bool,
) -> Result<()> {
if scale_flag {
return Err(Error::NotImplemented);
}
writer.write_u32(u32::from(self.global_gain), GLOBAL_GAIN_BITS);
self.section_data
.write(writer, ics_info.window_sequence, ics_info.max_sfb)?;
self.scale_factor_data
.write(writer, &self.section_data.sfb_cb)?;
self.write_tools(writer, ics_info, audio_object_type)
}
fn write_tools(
&self,
writer: &mut BitWriter,
ics_info: &IcsInfo,
audio_object_type: u8,
) -> Result<()> {
writer.write_bit(self.pulse_data_present);
if self.pulse_data_present {
if ics_info.window_sequence == WindowSequence::EightShort {
return Err(Error::PulseDataEncodeInvalid);
}
let pd = self
.pulse_data
.as_ref()
.ok_or(Error::PulseDataEncodeInvalid)?;
pd.write(writer)?;
} else if self.pulse_data.is_some() {
return Err(Error::PulseDataEncodeInvalid);
}
writer.write_bit(self.tns_data_present);
if self.tns_data_present {
let td = self.tns_data.as_ref().ok_or(Error::TnsDataEncodeInvalid)?;
td.write_family(writer, ics_info.family, ics_info.window_sequence)?;
} else if self.tns_data.is_some() {
return Err(Error::TnsDataEncodeInvalid);
}
writer.write_bit(self.gain_control_data_present);
if self.gain_control_data_present {
if audio_object_type != AOT_AAC_SSR {
return Err(Error::GainControlDataEncodeInvalid);
}
let gc = self
.gain_control_data
.as_ref()
.ok_or(Error::GainControlDataEncodeInvalid)?;
gc.write(writer, ics_info.window_sequence)?;
} else if self.gain_control_data.is_some() {
return Err(Error::GainControlDataEncodeInvalid);
}
Ok(())
}
}
fn read_u8(reader: &mut BitReader<'_>, bits: u32) -> Result<u8> {
Ok(reader.read_u32(bits).map_err(|_| Error::UnexpectedEnd)? as u8)
}
struct ToolDispatch {
pulse_data_present: bool,
pulse_data: Option<PulseData>,
tns_data_present: bool,
tns_data: Option<TnsData>,
gain_control_data_present: bool,
gain_control_data: Option<GainControlData>,
spectral_data_bit_offset: u64,
}
fn parse_tools(
reader: &mut BitReader<'_>,
ics_info: &IcsInfo,
_audio_object_type: u8,
start: u64,
) -> Result<ToolDispatch> {
let pulse_data_present = reader.read_bit().map_err(|_| Error::UnexpectedEnd)?;
let pulse_data = if pulse_data_present {
if ics_info.window_sequence == WindowSequence::EightShort {
return Err(Error::PulseDataEncodeInvalid);
}
Some(PulseData::parse(reader)?)
} else {
None
};
let tns_data_present = reader.read_bit().map_err(|_| Error::UnexpectedEnd)?;
let tns_data = if tns_data_present {
Some(TnsData::parse_family(
reader,
ics_info.family,
ics_info.window_sequence,
)?)
} else {
None
};
let gain_control_data_present = reader.read_bit().map_err(|_| Error::UnexpectedEnd)?;
let gain_control_data = if gain_control_data_present {
Some(GainControlData::parse(reader, ics_info.window_sequence)?)
} else {
None
};
let spectral_data_bit_offset = reader.bit_position() - start;
Ok(ToolDispatch {
pulse_data_present,
pulse_data,
tns_data_present,
tns_data,
gain_control_data_present,
gain_control_data,
spectral_data_bit_offset,
})
}