use crate::asc::AudioSpecificConfig;
use crate::crc;
use crate::{Error, Result};
use oxideav_core::bits::BitReader;
pub const AUDIO_SYNC_STREAM_SYNCWORD: u32 = 0x2B7;
pub const EP_AUDIO_SYNC_STREAM_SYNCWORD: u32 = 0x4DE1;
pub const MAX_AUDIO_MUX_LENGTH_BYTES: u32 = (1 << 13) - 1;
const MAX_PROGRAM_INDEX: u32 = 15;
const MAX_LAYER_INDEX: u32 = 7;
const MAX_STREAM_COUNT: usize = 16;
#[derive(Debug, Clone)]
pub struct LayerConfig {
pub prog: u8,
pub lay: u8,
pub stream_id: u8,
pub asc: Option<AudioSpecificConfig>,
pub effective_asc: AudioSpecificConfig,
pub frame_length_type: u8,
pub latm_buffer_fullness: Option<u8>,
pub core_frame_offset: Option<u8>,
pub frame_length: Option<u16>,
}
impl LayerConfig {
pub fn fixed_payload_bits(&self) -> Option<u32> {
if self.frame_length_type == 1 {
self.frame_length
.map(|fl| (u32::from(fl) + 20).saturating_mul(8))
} else {
None
}
}
}
#[derive(Debug, Clone)]
pub struct StreamMuxConfig {
pub audio_mux_version: u8,
pub audio_mux_version_a: u8,
pub tara_buffer_fullness: Option<u32>,
pub all_streams_same_time_framing: bool,
pub num_sub_frames: u8,
pub num_program: u8,
pub num_layer: Vec<u8>,
pub layers: Vec<LayerConfig>,
pub other_data_present: bool,
pub other_data_len_bits: u32,
pub crc_check_present: bool,
pub crc_check_sum: Option<u8>,
}
impl StreamMuxConfig {
pub fn stream_id(&self, prog: u8, lay: u8) -> Option<u8> {
self.layers
.iter()
.find(|l| l.prog == prog && l.lay == lay)
.map(|l| l.stream_id)
}
pub fn layer(&self, stream_id: u8) -> Option<&LayerConfig> {
self.layers.iter().find(|l| l.stream_id == stream_id)
}
pub fn parse(reader: &mut BitReader<'_>, data: &[u8]) -> Result<Self> {
let start_bit = reader.bit_position();
let audio_mux_version = read_u8(reader, 1)?;
let audio_mux_version_a = if audio_mux_version == 1 {
read_u8(reader, 1)?
} else {
0
};
if audio_mux_version_a != 0 {
return Err(Error::LatmAudioMuxVersionAReserved);
}
let tara_buffer_fullness = if audio_mux_version == 1 {
Some(latm_get_value(reader)?)
} else {
None
};
let all_streams_same_time_framing = read_bit(reader)?;
let num_sub_frames = read_u8(reader, 6)?;
let num_program = read_u8(reader, 4)?;
if u32::from(num_program) > MAX_PROGRAM_INDEX {
return Err(Error::LatmConfigOutOfRange);
}
let mut num_layer: Vec<u8> = Vec::with_capacity(usize::from(num_program) + 1);
let mut layers: Vec<LayerConfig> = Vec::new();
let mut last_asc: Option<AudioSpecificConfig> = None;
let mut stream_cnt: u32 = 0;
for prog in 0..=u32::from(num_program) {
let n_layer = read_u8(reader, 3)?;
if u32::from(n_layer) > MAX_LAYER_INDEX {
return Err(Error::LatmConfigOutOfRange);
}
num_layer.push(n_layer);
for lay in 0..=u32::from(n_layer) {
if stream_cnt as usize >= MAX_STREAM_COUNT {
return Err(Error::LatmConfigOutOfRange);
}
let stream_id = stream_cnt as u8;
stream_cnt += 1;
let use_same_config = if prog == 0 && lay == 0 {
false
} else {
read_bit(reader)?
};
let asc = if use_same_config {
None
} else if audio_mux_version == 0 {
let asc = AudioSpecificConfig::parse_bits(reader, start_bit)?;
Some(asc)
} else {
let asc_len = latm_get_value(reader)?;
let asc_start = reader.bit_position();
let asc = AudioSpecificConfig::parse_bits_bounded(
reader,
asc_start,
u64::from(asc_len),
)?;
let consumed = reader.bit_position().saturating_sub(asc_start);
let fill = u64::from(asc_len).saturating_sub(consumed);
if fill > 0 {
skip_bits(reader, fill)?;
}
Some(asc)
};
let effective_asc = if let Some(a) = &asc {
last_asc = Some(a.clone());
a.clone()
} else {
last_asc.clone().ok_or(Error::LatmNoPreviousMuxConfig)?
};
let frame_length_type = read_u8(reader, 3)?;
let mut latm_buffer_fullness = None;
let mut core_frame_offset = None;
let mut frame_length = None;
match frame_length_type {
0 => {
latm_buffer_fullness = Some(read_u8(reader, 8)?);
if !all_streams_same_time_framing {
let this_aot = effective_asc.aot;
let prev_aot = layers.last().map(|l| l.effective_asc.aot);
let pairs = (this_aot == 6 || this_aot == 20)
&& matches!(prev_aot, Some(8) | Some(24));
if pairs {
core_frame_offset = Some(read_u8(reader, 6)?);
}
}
}
1 => {
frame_length = Some(read_u16(reader, 9)?);
}
other => {
return Err(Error::LatmUnsupportedFrameLengthType(other));
}
}
layers.push(LayerConfig {
prog: prog as u8,
lay: lay as u8,
stream_id,
asc,
effective_asc,
frame_length_type,
latm_buffer_fullness,
core_frame_offset,
frame_length,
});
}
}
let other_data_present = read_bit(reader)?;
let other_data_len_bits = if other_data_present {
if audio_mux_version == 1 {
latm_get_value(reader)?
} else {
let mut acc: u32 = 0;
loop {
acc = acc.wrapping_mul(256);
let esc = read_bit(reader)?;
let tmp = read_u8(reader, 8)?;
acc = acc.wrapping_add(u32::from(tmp));
if !esc {
break;
}
}
acc
}
} else {
0
};
let crc_end_bit = reader.bit_position();
let crc_check_present = read_bit(reader)?;
let crc_check_sum = if crc_check_present {
let sum = read_u8(reader, 8)?;
let prefix = read_back_bits(data, start_bit, crc_end_bit)?;
let expected = crc::stream_mux_config_crc(&prefix);
if expected != sum {
return Err(Error::LatmCrcMismatch);
}
Some(sum)
} else {
None
};
Ok(StreamMuxConfig {
audio_mux_version,
audio_mux_version_a,
tara_buffer_fullness,
all_streams_same_time_framing,
num_sub_frames,
num_program,
num_layer,
layers,
other_data_present,
other_data_len_bits,
crc_check_present,
crc_check_sum,
})
}
}
const MAX_NUM_CHUNK_INDEX: u32 = 15;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MuxPayload {
pub sub_frame: u8,
pub prog: u8,
pub lay: u8,
pub stream_id: u8,
pub data: Vec<u8>,
}
#[derive(Debug, Clone, Copy)]
struct SlotLength {
prog: u8,
lay: u8,
stream_id: u8,
bits: u32,
}
#[derive(Debug, Clone)]
pub struct AudioMuxElement {
pub use_same_stream_mux: bool,
pub config: StreamMuxConfig,
pub payloads: Vec<MuxPayload>,
}
impl AudioMuxElement {
pub fn parse(
reader: &mut BitReader<'_>,
data: &[u8],
mux_config_present: bool,
prev_config: Option<&StreamMuxConfig>,
) -> Result<Self> {
let (use_same_stream_mux, config) = if mux_config_present {
let use_same = read_bit(reader)?;
if use_same {
let cfg = prev_config.cloned().ok_or(Error::LatmNoPreviousMuxConfig)?;
(true, cfg)
} else {
(false, StreamMuxConfig::parse(reader, data)?)
}
} else {
let cfg = prev_config.cloned().ok_or(Error::LatmNoPreviousMuxConfig)?;
(false, cfg)
};
if config.audio_mux_version_a != 0 {
return Err(Error::LatmAudioMuxVersionAReserved);
}
let mut payloads = Vec::new();
for sub_frame in 0..=u32::from(config.num_sub_frames) {
let slots = payload_length_info(reader, &config)?;
payload_mux(reader, &config, sub_frame as u8, &slots, &mut payloads)?;
}
if config.other_data_present {
skip_bits(reader, u64::from(config.other_data_len_bits))?;
}
reader.align_to_byte();
Ok(AudioMuxElement {
use_same_stream_mux,
config,
payloads,
})
}
}
fn payload_length_info(
reader: &mut BitReader<'_>,
config: &StreamMuxConfig,
) -> Result<Vec<SlotLength>> {
let mut slots = Vec::new();
if config.all_streams_same_time_framing {
for prog in 0..=u32::from(config.num_program) {
let n_layer = config.num_layer[prog as usize];
for lay in 0..=u32::from(n_layer) {
let stream_id = config
.stream_id(prog as u8, lay as u8)
.ok_or(Error::LatmConfigOutOfRange)?;
let layer = config.layer(stream_id).ok_or(Error::LatmConfigOutOfRange)?;
let bits = slot_bits(reader, layer)?;
slots.push(SlotLength {
prog: prog as u8,
lay: lay as u8,
stream_id,
bits,
});
}
}
} else {
let num_chunk = read_u8(reader, 4)?;
if u32::from(num_chunk) > MAX_NUM_CHUNK_INDEX {
return Err(Error::LatmConfigOutOfRange);
}
for _ in 0..=u32::from(num_chunk) {
let stream_indx = read_u8(reader, 4)?;
let layer = config
.layer(stream_indx)
.ok_or(Error::LatmConfigOutOfRange)?;
let prog = layer.prog;
let lay = layer.lay;
let stream_id = layer.stream_id;
let frame_length_type = layer.frame_length_type;
let bits = slot_bits(reader, layer)?;
if frame_length_type == 0 {
let _au_end_flag = read_bit(reader)?;
}
slots.push(SlotLength {
prog,
lay,
stream_id,
bits,
});
}
}
Ok(slots)
}
fn slot_bits(reader: &mut BitReader<'_>, layer: &LayerConfig) -> Result<u32> {
match layer.frame_length_type {
0 => {
let mut bytes: u32 = 0;
loop {
let tmp = read_u8(reader, 8)?;
bytes = bytes.wrapping_add(u32::from(tmp));
if tmp != 255 {
break;
}
}
Ok(bytes.saturating_mul(8))
}
1 => layer
.fixed_payload_bits()
.ok_or(Error::LatmConfigOutOfRange),
other => Err(Error::LatmUnsupportedFrameLengthType(other)),
}
}
fn payload_mux(
reader: &mut BitReader<'_>,
config: &StreamMuxConfig,
sub_frame: u8,
slots: &[SlotLength],
out: &mut Vec<MuxPayload>,
) -> Result<()> {
let _ = config;
for slot in slots {
let data = read_payload_bytes(reader, slot.bits)?;
out.push(MuxPayload {
sub_frame,
prog: slot.prog,
lay: slot.lay,
stream_id: slot.stream_id,
data,
});
}
Ok(())
}
fn read_payload_bytes(reader: &mut BitReader<'_>, bits: u32) -> Result<Vec<u8>> {
if bits % 8 == 0 && reader.is_byte_aligned() {
let n = (bits / 8) as usize;
return reader.read_bytes(n).map_err(|_| Error::UnexpectedEnd);
}
let full = bits / 8;
let rem = bits % 8;
let mut out = Vec::with_capacity((full + u32::from(rem != 0)) as usize);
for _ in 0..full {
out.push(read_u8(reader, 8)?);
}
if rem > 0 {
let v = read_u8(reader, rem)?;
out.push(v << (8 - rem));
}
Ok(out)
}
pub fn latm_get_value(reader: &mut BitReader<'_>) -> Result<u32> {
let bytes_for_value = read_u8(reader, 2)?;
let mut value: u32 = 0;
for _ in 0..=u32::from(bytes_for_value) {
value = value.wrapping_mul(256);
let byte = read_u8(reader, 8)?;
value = value.wrapping_add(u32::from(byte));
}
Ok(value)
}
#[derive(Debug, Clone)]
pub struct LoasFrame {
pub audio_mux_length_bytes: u16,
pub element: AudioMuxElement,
pub frame_counter: Option<u8>,
pub offset: usize,
pub next_offset: usize,
}
#[derive(Debug)]
pub struct AudioSyncStream<'a> {
data: &'a [u8],
pos: usize,
prev_config: Option<StreamMuxConfig>,
}
impl<'a> AudioSyncStream<'a> {
pub fn new(data: &'a [u8]) -> Self {
AudioSyncStream {
data,
pos: 0,
prev_config: None,
}
}
pub fn next_frame(&mut self) -> Result<Option<LoasFrame>> {
let Some(sync_off) = self.find_syncword(AUDIO_SYNC_STREAM_SYNCWORD, 11) else {
self.pos = self.data.len();
return Ok(None);
};
let mut reader = BitReader::new(&self.data[sync_off..]);
reader.skip(11).map_err(|_| Error::LoasSyncInvalid)?;
let audio_mux_length_bytes =
reader.read_u32(13).map_err(|_| Error::LoasSyncInvalid)? as u16;
debug_assert_eq!(reader.bit_position(), 24);
let element_byte_start = sync_off + 3;
let element_byte_end = element_byte_start + usize::from(audio_mux_length_bytes);
if element_byte_end > self.data.len() {
return Err(Error::LoasSyncInvalid);
}
let element_bytes = &self.data[element_byte_start..element_byte_end];
let mut elem_reader = BitReader::new(element_bytes);
let element = AudioMuxElement::parse(
&mut elem_reader,
element_bytes,
true,
self.prev_config.as_ref(),
)?;
self.prev_config = Some(element.config.clone());
self.pos = element_byte_end;
Ok(Some(LoasFrame {
audio_mux_length_bytes,
element,
frame_counter: None,
offset: sync_off,
next_offset: element_byte_end,
}))
}
fn find_syncword(&self, syncword: u32, n: u32) -> Option<usize> {
let bytes_needed = n.div_ceil(8) as usize;
let mut off = self.pos;
while off + bytes_needed <= self.data.len() {
let mut r = BitReader::new(&self.data[off..]);
if let Ok(v) = r.read_u32(n) {
if v == syncword {
return Some(off);
}
}
off += 1;
}
None
}
}
impl Iterator for AudioSyncStream<'_> {
type Item = Result<LoasFrame>;
fn next(&mut self) -> Option<Self::Item> {
match self.next_frame() {
Ok(Some(frame)) => Some(Ok(frame)),
Ok(None) => None,
Err(e) => {
self.pos = self.data.len();
Some(Err(e))
}
}
}
}
#[derive(Debug, Clone)]
pub struct EpAudioSyncHeader {
pub future_use: u8,
pub audio_mux_length_bytes: u16,
pub frame_counter: u8,
pub header_parity: u32,
pub offset: usize,
pub body_offset: usize,
}
impl EpAudioSyncHeader {
pub fn parse(data: &[u8], pos: usize) -> Result<Option<Self>> {
let walker = AudioSyncStream {
data,
pos,
prev_config: None,
};
let Some(sync_off) = walker.find_syncword(EP_AUDIO_SYNC_STREAM_SYNCWORD, 16) else {
return Ok(None);
};
let mut reader = BitReader::new(&data[sync_off..]);
reader.skip(16).map_err(|_| Error::LoasSyncInvalid)?; let future_use = read_u8(&mut reader, 4)?;
let audio_mux_length_bytes = read_u16(&mut reader, 13)?;
let frame_counter = read_u8(&mut reader, 5)?;
let header_parity = reader.read_u32(18).map_err(|_| Error::UnexpectedEnd)?;
debug_assert_eq!(reader.bit_position(), 56);
Ok(Some(EpAudioSyncHeader {
future_use,
audio_mux_length_bytes,
frame_counter,
header_parity,
offset: sync_off,
body_offset: sync_off + 7,
}))
}
}
const EP_SYNC_BCH_GEN: u32 = (1 << 17)
| (1 << 16)
| (1 << 15)
| (1 << 9)
| (1 << 7)
| (1 << 6)
| (1 << 3)
| (1 << 2)
| (1 << 1)
| 1;
pub fn ep_sync_header_parity(audio_mux_length_bytes: u16, frame_counter: u8) -> u32 {
let msg: u32 =
(u32::from(audio_mux_length_bytes & 0x1FFF) << 5) | u32::from(frame_counter & 0x1F);
let mut reg: u32 = 0;
let top = 1u32 << 17;
let feed = |reg: &mut u32, bit: bool| {
let high = *reg & top != 0;
*reg = (*reg << 1) & 0x3FFFF;
if high {
*reg ^= EP_SYNC_BCH_GEN;
}
if bit {
*reg ^= 1;
}
};
for i in (0..18).rev() {
feed(&mut reg, msg & (1 << i) != 0);
}
for _ in 0..18 {
let high = reg & top != 0;
reg = (reg << 1) & 0x3FFFF;
if high {
reg ^= EP_SYNC_BCH_GEN;
}
}
reg
}
impl EpAudioSyncHeader {
pub fn parity_ok(&self) -> bool {
ep_sync_header_parity(self.audio_mux_length_bytes, self.frame_counter) == self.header_parity
}
}
#[derive(Debug, Default)]
pub struct EpMuxState {
pub ep_config: Option<crate::ep_config::ErrorProtectionSpecificConfig>,
pub prev_config: Option<StreamMuxConfig>,
}
#[derive(Debug)]
pub struct EpMuxElement {
pub use_previous_mux_config: bool,
pub element: AudioMuxElement,
}
impl EpMuxElement {
pub fn parse(data: &[u8], state: &mut EpMuxState) -> Result<Self> {
let mut reader = BitReader::new(data);
let b0 = read_bit(&mut reader)?;
let b1 = read_bit(&mut reader)?;
let b2 = read_bit(&mut reader)?;
let use_prev = (u8::from(b0) + u8::from(b1) + u8::from(b2)) >= 2;
if !use_prev {
let mut len_bits_field = [false; 10];
for b in len_bits_field.iter_mut() {
*b = read_bit(&mut reader)?;
}
let mut parity = [false; 11];
for b in parity.iter_mut() {
*b = read_bit(&mut reader)?;
}
let corrected = crate::ep_fec::header_fec_decode(&len_bits_field, &parity)?;
let mut cfg_len = 0usize;
for &b in &corrected {
cfg_len = (cfg_len << 1) | usize::from(b);
}
let cfg_start = reader.bit_position();
let epsc = crate::ep_config::ErrorProtectionSpecificConfig::parse(&mut reader)?;
let consumed = (reader.bit_position() - cfg_start) as usize;
if cfg_len != consumed && cfg_len != consumed.div_ceil(8) {
return Err(Error::EpFrameInvalid);
}
let cfg_bits = read_back_bits(data, cfg_start, cfg_start + consumed as u64)?;
let parity_len = crate::ep_fec::HeaderFec::for_len(consumed)?.parity_bits(consumed)?;
let mut cfg_parity = Vec::with_capacity(parity_len);
for _ in 0..parity_len {
cfg_parity.push(read_bit(&mut reader)?);
}
let corrected_cfg = crate::ep_fec::header_fec_decode(&cfg_bits, &cfg_parity)?;
if corrected_cfg != cfg_bits {
let mut bytes = vec![0u8; corrected_cfg.len().div_ceil(8)];
for (i, &b) in corrected_cfg.iter().enumerate() {
if b {
bytes[i / 8] |= 0x80 >> (i % 8);
}
}
let mut r2 = BitReader::new(&bytes);
state.ep_config = Some(crate::ep_config::ErrorProtectionSpecificConfig::parse(
&mut r2,
)?);
} else {
state.ep_config = Some(epsc);
}
}
reader.align_to_byte();
let epsc = state.ep_config.clone().ok_or(Error::EpFrameInvalid)?;
let codec = crate::ep_frame::EpFrameCodec::new(epsc)?;
let body = crate::ep_frame::read_remaining_bytes(&mut reader, data.len())?;
let frame = codec.decode(&body)?;
let mut au_bits: Vec<bool> = Vec::new();
for c in &frame.classes {
au_bits.extend_from_slice(c);
}
let mut au_bytes = vec![0u8; au_bits.len().div_ceil(8)];
for (i, &b) in au_bits.iter().enumerate() {
if b {
au_bytes[i / 8] |= 0x80 >> (i % 8);
}
}
let mut au_reader = BitReader::new(&au_bytes);
let element =
AudioMuxElement::parse(&mut au_reader, &au_bytes, true, state.prev_config.as_ref())?;
state.prev_config = Some(element.config.clone());
Ok(EpMuxElement {
use_previous_mux_config: use_prev,
element,
})
}
}
fn read_u8(reader: &mut BitReader<'_>, n: u32) -> Result<u8> {
Ok(reader.read_u32(n).map_err(|_| Error::UnexpectedEnd)? as u8)
}
fn read_u16(reader: &mut BitReader<'_>, n: u32) -> Result<u16> {
Ok(reader.read_u32(n).map_err(|_| Error::UnexpectedEnd)? as u16)
}
fn read_bit(reader: &mut BitReader<'_>) -> Result<bool> {
reader.read_bit().map_err(|_| Error::UnexpectedEnd)
}
fn skip_bits(reader: &mut BitReader<'_>, n: u64) -> Result<()> {
let mut remaining = n;
while remaining > 0 {
let chunk = remaining.min(u64::from(u32::MAX)) as u32;
reader.skip(chunk).map_err(|_| Error::UnexpectedEnd)?;
remaining -= u64::from(chunk);
}
Ok(())
}
fn read_back_bits(data: &[u8], from_bit: u64, to_bit: u64) -> Result<Vec<bool>> {
debug_assert!(to_bit >= from_bit);
let count = (to_bit - from_bit) as usize;
let mut scratch = BitReader::new(data);
skip_bits(&mut scratch, from_bit)?;
let mut out = Vec::with_capacity(count);
for _ in 0..count {
out.push(scratch.read_bit().map_err(|_| Error::UnexpectedEnd)?);
}
Ok(out)
}
use std::collections::HashMap;
use crate::decode::{DecodedFrame, StreamDecoder};
#[derive(Debug, Default)]
pub struct LoasDecoder {
streams: HashMap<u8, StreamDecoder>,
scalable: HashMap<u8, crate::scalable::ScalableDecoder>,
scalable_pending: HashMap<u8, Vec<Vec<u8>>>,
sbr_downsampled: bool,
sbr_low_power: bool,
}
impl LoasDecoder {
#[must_use]
pub fn new() -> Self {
LoasDecoder::default()
}
pub fn set_sbr_downsampled(&mut self, downsampled: bool) {
self.sbr_downsampled = downsampled;
}
pub fn set_sbr_low_power(&mut self, low_power: bool) {
self.sbr_low_power = low_power;
}
pub fn decode_all(&mut self, data: &[u8]) -> Result<Vec<DecodedFrame>> {
let mut out = Vec::new();
let mut walker = AudioSyncStream::new(data);
while let Some(frame) = walker.next_frame()? {
for payload in &frame.element.payloads {
let config = &frame.element.config;
let layer = config
.layer(payload.stream_id)
.ok_or(Error::LatmConfigOutOfRange)?;
if layer.effective_asc.aot == 6 || layer.effective_asc.aot == 20 {
if let Some(decoded) = self.push_scalable_payload(config, payload)? {
out.push(decoded);
}
continue;
}
let decoded = self.decode_payload(config, payload)?;
out.push(decoded);
}
}
Ok(out)
}
pub fn push_scalable_payload(
&mut self,
config: &StreamMuxConfig,
payload: &MuxPayload,
) -> Result<Option<DecodedFrame>> {
let layer = config
.layer(payload.stream_id)
.ok_or(Error::LatmConfigOutOfRange)?;
let prog = layer.prog;
let n_layers = usize::from(
*config
.num_layer
.get(usize::from(prog))
.ok_or(Error::LatmConfigOutOfRange)?,
) + 1;
let pending = self.scalable_pending.entry(prog).or_default();
if usize::from(layer.lay) != pending.len() {
self.scalable_pending.remove(&prog);
return Err(Error::ScalableInvalid);
}
pending.push(payload.data.clone());
if pending.len() < n_layers {
return Ok(None);
}
let payloads = self.scalable_pending.remove(&prog).unwrap_or_default();
let mut ascs: Vec<&crate::asc::AudioSpecificConfig> = Vec::with_capacity(n_layers);
for lay in 0..n_layers {
let sid = config
.stream_id(prog, lay as u8)
.ok_or(Error::LatmConfigOutOfRange)?;
let lc = config.layer(sid).ok_or(Error::LatmConfigOutOfRange)?;
ascs.push(&lc.effective_asc);
}
let cfg = crate::scalable::ScalableConfig::from_layer_ascs(&ascs)?;
let rebuild = !matches!(self.scalable.get(&prog), Some(d) if d.config() == &cfg);
if rebuild {
self.scalable
.insert(prog, crate::scalable::ScalableDecoder::new(cfg)?);
}
let dec = self.scalable.get_mut(&prog).expect("just inserted");
let refs: Vec<&[u8]> = payloads.iter().map(Vec::as_slice).collect();
dec.decode_frame(&refs).map(Some)
}
pub fn decode_all_ep(&mut self, data: &[u8]) -> Result<Vec<DecodedFrame>> {
let mut out = Vec::new();
let mut ep_state = EpMuxState::default();
let mut pos = 0usize;
while let Some(header) = EpAudioSyncHeader::parse(data, pos)? {
if !header.parity_ok() {
return Err(Error::EpFrameInvalid);
}
let body_end = header
.body_offset
.checked_add(usize::from(header.audio_mux_length_bytes))
.ok_or(Error::UnexpectedEnd)?;
if body_end > data.len() {
return Err(Error::UnexpectedEnd);
}
let mux = EpMuxElement::parse(&data[header.body_offset..body_end], &mut ep_state)?;
for payload in &mux.element.payloads {
let config = &mux.element.config;
let layer = config
.layer(payload.stream_id)
.ok_or(Error::LatmConfigOutOfRange)?;
if layer.effective_asc.aot == 6 || layer.effective_asc.aot == 20 {
if let Some(decoded) = self.push_scalable_payload(config, payload)? {
out.push(decoded);
}
continue;
}
out.push(self.decode_payload(config, payload)?);
}
pos = body_end;
}
Ok(out)
}
pub fn decode_payload(
&mut self,
config: &StreamMuxConfig,
payload: &MuxPayload,
) -> Result<DecodedFrame> {
let layer = config
.layer(payload.stream_id)
.ok_or(Error::LatmConfigOutOfRange)?;
let asc = &layer.effective_asc;
if asc.aot == 6 || asc.aot == 20 {
let sample_rate = asc.sample_rate;
return Ok(self
.push_scalable_payload(config, payload)?
.unwrap_or(DecodedFrame {
pcm: Vec::new(),
channels: 0,
sample_rate,
}));
}
let family = crate::swb_offset::FrameFamily::from_aot_and_flag(
asc.aot,
asc.ga_body.frame_length == crate::asc::FrameLength::Long960,
);
let dec = self.streams.entry(payload.stream_id).or_insert_with({
let force_down = self.sbr_downsampled;
let force_lp = self.sbr_low_power;
move || {
let mut d = StreamDecoder::new();
d.set_sbr_downsampled(force_down);
d.set_sbr_low_power(force_lp);
d.set_frame_family(family);
d
}
});
if dec.frame_family() != family {
let mut d = StreamDecoder::new();
d.set_sbr_downsampled(self.sbr_downsampled);
d.set_sbr_low_power(self.sbr_low_power);
d.set_frame_family(family);
*dec = d;
}
if asc.sbr_present && asc.extension_sample_rate == Some(asc.sample_rate) {
dec.set_sbr_downsampled(true);
}
if asc.channel_configuration == 0 {
if let Some(pce) = &asc.ga_body.pce {
dec.set_program_config(pce.clone());
}
}
if asc.aot == 17 || asc.aot == 19 || asc.aot == 23 {
let resilience = asc
.ga_body
.extension_body
.as_ref()
.and_then(|ext| ext.resilience)
.unwrap_or_default();
return dec.decode_er_raw_data_block(
asc.aot,
asc.sampling_frequency_index,
asc.sample_rate,
asc.channel_configuration,
resilience,
&payload.data,
);
}
dec.decode_raw_data_block(
asc.aot,
asc.sampling_frequency_index,
asc.sample_rate,
asc.channel_configuration,
1,
&payload.data,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use oxideav_core::bits::BitWriter;
const AAC_LC_ASC: [u8; 2] = [0x12, 0x10];
fn write_aac_lc_asc(w: &mut BitWriter) {
w.write_u32(u32::from(u16::from_be_bytes(AAC_LC_ASC)), 16);
}
#[test]
fn latm_get_value_single_byte() {
let mut w = BitWriter::new();
w.write_u32(0, 2); w.write_u32(0xFF, 8);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
assert_eq!(latm_get_value(&mut r).unwrap(), 0xFF);
}
#[test]
fn latm_get_value_multi_byte() {
let mut w = BitWriter::new();
w.write_u32(2, 2);
w.write_u32(0x01, 8);
w.write_u32(0x02, 8);
w.write_u32(0x03, 8);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
assert_eq!(latm_get_value(&mut r).unwrap(), 0x01_02_03);
}
fn build_min_smc() -> Vec<u8> {
let mut w = BitWriter::new();
w.write_bit(false); w.write_bit(true); w.write_u32(0, 6); w.write_u32(0, 4); w.write_u32(0, 3); write_aac_lc_asc(&mut w);
w.write_u32(0, 3); w.write_u32(0xFF, 8); w.write_bit(false); w.write_bit(false); w.finish()
}
#[test]
fn stream_mux_config_minimal_aac_lc() {
let bytes = build_min_smc();
let mut r = BitReader::new(&bytes);
let smc = StreamMuxConfig::parse(&mut r, &bytes).unwrap();
assert_eq!(smc.audio_mux_version, 0);
assert_eq!(smc.audio_mux_version_a, 0);
assert!(smc.all_streams_same_time_framing);
assert_eq!(smc.num_sub_frames, 0);
assert_eq!(smc.num_program, 0);
assert_eq!(smc.num_layer, vec![0]);
assert_eq!(smc.layers.len(), 1);
let lay = &smc.layers[0];
assert_eq!(lay.stream_id, 0);
assert_eq!(lay.frame_length_type, 0);
assert_eq!(lay.latm_buffer_fullness, Some(0xFF));
assert_eq!(lay.effective_asc.aot, 2);
assert_eq!(lay.effective_asc.sampling_frequency_index, 4);
assert_eq!(lay.effective_asc.channel_configuration, 2);
assert!(!smc.other_data_present);
assert!(!smc.crc_check_present);
assert_eq!(smc.stream_id(0, 0), Some(0));
}
fn push_bits(out: &mut Vec<bool>, v: u32, n: u32) {
for i in (0..n).rev() {
out.push((v >> i) & 1 == 1);
}
}
#[test]
fn stream_mux_config_with_valid_crc() {
let mut prefix: Vec<bool> = Vec::new();
push_bits(&mut prefix, 0, 1); push_bits(&mut prefix, 1, 1); push_bits(&mut prefix, 0, 6); push_bits(&mut prefix, 0, 4); push_bits(&mut prefix, 0, 3); push_bits(&mut prefix, u32::from(u16::from_be_bytes(AAC_LC_ASC)), 16);
push_bits(&mut prefix, 0, 3); push_bits(&mut prefix, 0xFF, 8); push_bits(&mut prefix, 0, 1); let sum = crc::stream_mux_config_crc(&prefix);
let mut w = BitWriter::new();
for &b in &prefix {
w.write_bit(b);
}
w.write_bit(true); w.write_u32(u32::from(sum), 8); let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let smc = StreamMuxConfig::parse(&mut r, &bytes).unwrap();
assert!(smc.crc_check_present);
assert_eq!(smc.crc_check_sum, Some(sum));
}
#[test]
fn stream_mux_config_bad_crc_rejected() {
let mut w = BitWriter::new();
w.write_bit(false);
w.write_bit(true);
w.write_u32(0, 6);
w.write_u32(0, 4);
w.write_u32(0, 3);
write_aac_lc_asc(&mut w);
w.write_u32(0, 3);
w.write_u32(0xFF, 8);
w.write_bit(false);
w.write_bit(true); w.write_u32(0x00, 8); let bytes = w.finish();
let mut r = BitReader::new(&bytes);
assert!(matches!(
StreamMuxConfig::parse(&mut r, &bytes),
Err(Error::LatmCrcMismatch)
));
}
#[test]
fn stream_mux_config_two_layers_use_same_config() {
let mut w = BitWriter::new();
w.write_bit(false); w.write_bit(true); w.write_u32(0, 6); w.write_u32(0, 4); w.write_u32(1, 3); write_aac_lc_asc(&mut w);
w.write_u32(0, 3); w.write_u32(0xFF, 8); w.write_bit(true); w.write_u32(0, 3); w.write_u32(0xFF, 8); w.write_bit(false); w.write_bit(false); let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let smc = StreamMuxConfig::parse(&mut r, &bytes).unwrap();
assert_eq!(smc.layers.len(), 2);
assert!(smc.layers[0].asc.is_some());
assert!(smc.layers[1].asc.is_none());
assert_eq!(
smc.layers[1].effective_asc.aot,
smc.layers[0].effective_asc.aot
);
assert_eq!(smc.stream_id(0, 1), Some(1));
}
#[test]
fn stream_mux_config_unsupported_frame_length_type() {
let mut w = BitWriter::new();
w.write_bit(false);
w.write_bit(true);
w.write_u32(0, 6);
w.write_u32(0, 4);
w.write_u32(0, 3);
write_aac_lc_asc(&mut w);
w.write_u32(3, 3); let bytes = w.finish();
let mut r = BitReader::new(&bytes);
assert!(matches!(
StreamMuxConfig::parse(&mut r, &bytes),
Err(Error::LatmUnsupportedFrameLengthType(3))
));
}
#[test]
fn stream_mux_config_version1_reserved_a_rejected() {
let mut w = BitWriter::new();
w.write_bit(true); w.write_bit(true); let bytes = w.finish();
let mut r = BitReader::new(&bytes);
assert!(matches!(
StreamMuxConfig::parse(&mut r, &bytes),
Err(Error::LatmAudioMuxVersionAReserved)
));
}
#[test]
fn stream_mux_config_frame_length_type1_fixed_bits() {
let mut w = BitWriter::new();
w.write_bit(false);
w.write_bit(true);
w.write_u32(0, 6);
w.write_u32(0, 4);
w.write_u32(0, 3);
write_aac_lc_asc(&mut w);
w.write_u32(1, 3); w.write_u32(100, 9); w.write_bit(false); w.write_bit(false); let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let smc = StreamMuxConfig::parse(&mut r, &bytes).unwrap();
let lay = &smc.layers[0];
assert_eq!(lay.frame_length_type, 1);
assert_eq!(lay.frame_length, Some(100));
assert_eq!(lay.fixed_payload_bits(), Some((100 + 20) * 8));
}
fn write_min_smc_into(w: &mut BitWriter) {
w.write_bit(false); w.write_bit(true); w.write_u32(0, 6); w.write_u32(0, 4); w.write_u32(0, 3); write_aac_lc_asc(w);
w.write_u32(0, 3); w.write_u32(0xFF, 8); w.write_bit(false); w.write_bit(false); }
#[test]
fn audio_mux_element_in_band_single_payload() {
let payload: [u8; 4] = [0xDE, 0xAD, 0xBE, 0xEF];
let mut w = BitWriter::new();
w.write_bit(false); write_min_smc_into(&mut w);
w.write_u32(4, 8);
for &b in &payload {
w.write_byte(b);
}
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let ame = AudioMuxElement::parse(&mut r, &bytes, true, None).unwrap();
assert!(!ame.use_same_stream_mux);
assert_eq!(ame.payloads.len(), 1);
let p = &ame.payloads[0];
assert_eq!(p.sub_frame, 0);
assert_eq!(p.prog, 0);
assert_eq!(p.lay, 0);
assert_eq!(p.stream_id, 0);
assert_eq!(p.data, payload.to_vec());
}
#[test]
fn audio_mux_element_escape_length() {
let len = 258usize;
let payload: Vec<u8> = (0..len).map(|i| (i & 0xFF) as u8).collect();
let mut w = BitWriter::new();
w.write_bit(false); write_min_smc_into(&mut w);
w.write_u32(255, 8); w.write_u32(3, 8); for &b in &payload {
w.write_byte(b);
}
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let ame = AudioMuxElement::parse(&mut r, &bytes, true, None).unwrap();
assert_eq!(ame.payloads.len(), 1);
assert_eq!(ame.payloads[0].data, payload);
}
#[test]
fn audio_mux_element_use_same_stream_mux_inherits() {
let mut w0 = BitWriter::new();
w0.write_bit(false); write_min_smc_into(&mut w0);
w0.write_u32(2, 8); w0.write_byte(0x11);
w0.write_byte(0x22);
let bytes0 = w0.finish();
let mut r0 = BitReader::new(&bytes0);
let first = AudioMuxElement::parse(&mut r0, &bytes0, true, None).unwrap();
let mut w1 = BitWriter::new();
w1.write_bit(true); w1.write_u32(3, 8); w1.write_byte(0xAA);
w1.write_byte(0xBB);
w1.write_byte(0xCC);
let bytes1 = w1.finish();
let mut r1 = BitReader::new(&bytes1);
let second = AudioMuxElement::parse(&mut r1, &bytes1, true, Some(&first.config)).unwrap();
assert!(second.use_same_stream_mux);
assert_eq!(second.payloads.len(), 1);
assert_eq!(second.payloads[0].data, vec![0xAA, 0xBB, 0xCC]);
}
#[test]
fn audio_mux_element_use_same_without_prev_rejected() {
let mut w = BitWriter::new();
w.write_bit(true); let bytes = w.finish();
let mut r = BitReader::new(&bytes);
assert!(matches!(
AudioMuxElement::parse(&mut r, &bytes, true, None),
Err(Error::LatmNoPreviousMuxConfig)
));
}
#[test]
fn audio_mux_element_multiple_subframes() {
let mut w = BitWriter::new();
w.write_bit(false); w.write_bit(false); w.write_bit(true); w.write_u32(1, 6); w.write_u32(0, 4); w.write_u32(0, 3); write_aac_lc_asc(&mut w);
w.write_u32(0, 3); w.write_u32(0xFF, 8); w.write_bit(false); w.write_bit(false); w.write_u32(2, 8);
w.write_byte(0x01);
w.write_byte(0x02);
w.write_u32(1, 8);
w.write_byte(0x03);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let ame = AudioMuxElement::parse(&mut r, &bytes, true, None).unwrap();
assert_eq!(ame.payloads.len(), 2);
assert_eq!(ame.payloads[0].sub_frame, 0);
assert_eq!(ame.payloads[0].data, vec![0x01, 0x02]);
assert_eq!(ame.payloads[1].sub_frame, 1);
assert_eq!(ame.payloads[1].data, vec![0x03]);
}
fn build_min_audio_mux_element(payload: &[u8]) -> Vec<u8> {
let mut w = BitWriter::new();
w.write_bit(false); write_min_smc_into(&mut w);
assert!(payload.len() < 255);
w.write_u32(payload.len() as u32, 8);
for &b in payload {
w.write_byte(b);
}
w.finish()
}
#[test]
fn audio_sync_stream_single_frame() {
let payload: [u8; 5] = [0x21, 0x00, 0x03, 0x40, 0x80];
let body = build_min_audio_mux_element(&payload);
let mut w = BitWriter::new();
w.write_u32(AUDIO_SYNC_STREAM_SYNCWORD, 11);
w.write_u32(body.len() as u32, 13);
w.write_bytes(&body);
let stream = w.finish();
let mut walker = AudioSyncStream::new(&stream);
let frame = walker.next_frame().unwrap().unwrap();
assert_eq!(frame.offset, 0);
assert_eq!(usize::from(frame.audio_mux_length_bytes), body.len());
assert_eq!(frame.element.payloads.len(), 1);
assert_eq!(frame.element.payloads[0].data, payload.to_vec());
assert!(walker.next_frame().unwrap().is_none());
}
#[test]
fn audio_sync_stream_skips_leading_garbage() {
let payload: [u8; 2] = [0xAB, 0xCD];
let body = build_min_audio_mux_element(&payload);
let mut w = BitWriter::new();
w.write_u32(AUDIO_SYNC_STREAM_SYNCWORD, 11);
w.write_u32(body.len() as u32, 13);
w.write_bytes(&body);
let frame_bytes = w.finish();
let mut stream = vec![0x00, 0xAA, 0x55];
stream.extend_from_slice(&frame_bytes);
let mut walker = AudioSyncStream::new(&stream);
let frame = walker.next_frame().unwrap().unwrap();
assert_eq!(frame.offset, 3);
assert_eq!(frame.element.payloads[0].data, payload.to_vec());
}
#[test]
fn audio_sync_stream_two_frames_via_iterator() {
let p0: [u8; 2] = [0x10, 0x20];
let p1: [u8; 3] = [0x30, 0x40, 0x50];
let build = |payload: &[u8]| {
let body = build_min_audio_mux_element(payload);
let mut w = BitWriter::new();
w.write_u32(AUDIO_SYNC_STREAM_SYNCWORD, 11);
w.write_u32(body.len() as u32, 13);
w.write_bytes(&body);
w.finish()
};
let mut stream = build(&p0);
let body1 = {
let mut w = BitWriter::new();
w.write_bit(true); w.write_u32(p1.len() as u32, 8); for &b in &p1 {
w.write_byte(b);
}
w.finish()
};
let mut w1 = BitWriter::new();
w1.write_u32(AUDIO_SYNC_STREAM_SYNCWORD, 11);
w1.write_u32(body1.len() as u32, 13);
w1.write_bytes(&body1);
stream.extend_from_slice(&w1.finish());
let frames: Vec<_> = AudioSyncStream::new(&stream)
.collect::<Result<Vec<_>>>()
.unwrap();
assert_eq!(frames.len(), 2);
assert_eq!(frames[0].element.payloads[0].data, p0.to_vec());
assert_eq!(frames[1].element.payloads[0].data, p1.to_vec());
assert!(frames[1].element.use_same_stream_mux);
}
#[test]
fn audio_sync_stream_truncated_body_rejected() {
let payload: [u8; 4] = [0x01, 0x02, 0x03, 0x04];
let body = build_min_audio_mux_element(&payload);
let mut w = BitWriter::new();
w.write_u32(AUDIO_SYNC_STREAM_SYNCWORD, 11);
w.write_u32((body.len() + 10) as u32, 13);
w.write_bytes(&body);
let stream = w.finish();
let mut walker = AudioSyncStream::new(&stream);
assert!(matches!(walker.next_frame(), Err(Error::LoasSyncInvalid)));
}
#[test]
fn ep_audio_sync_header_parse() {
let mut w = BitWriter::new();
w.write_u32(EP_AUDIO_SYNC_STREAM_SYNCWORD, 16);
w.write_u32(0x5, 4);
w.write_u32(100, 13);
w.write_u32(7, 5);
w.write_u32(0x12345, 18);
w.write_bytes(&[0xAA, 0xBB]);
let stream = w.finish();
let hdr = EpAudioSyncHeader::parse(&stream, 0).unwrap().unwrap();
assert_eq!(hdr.offset, 0);
assert_eq!(hdr.future_use, 0x5);
assert_eq!(hdr.audio_mux_length_bytes, 100);
assert_eq!(hdr.frame_counter, 7);
assert_eq!(hdr.header_parity, 0x12345);
assert_eq!(hdr.body_offset, 7);
}
#[test]
fn ep_audio_sync_header_not_found() {
let stream = [0x00u8, 0x11, 0x22, 0x33];
assert!(EpAudioSyncHeader::parse(&stream, 0).unwrap().is_none());
}
}