use crate::engine::bits::BitReader;
use crate::engine::raw_data_block::IdSynEle;
use crate::engine::sbr_element::SbrElement;
use crate::engine::sbr_header::SbrHeader;
use crate::engine::{Error, Result};
pub const SBR_CRC_BITS: u32 = 10;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SbrExtensionData {
pub crc: Option<u16>,
pub header_present: bool,
pub header: SbrHeader,
pub element: SbrElement,
pub num_sbr_bits: u64,
}
impl SbrExtensionData {
pub fn parse(
reader: &mut BitReader<'_>,
id_aac: IdSynEle,
crc_flag: bool,
fs_sbr: u32,
cnt: Option<u32>,
prev_header: Option<SbrHeader>,
) -> Result<Self> {
let start = reader.bit_position();
let crc = if crc_flag {
Some(read(reader, SBR_CRC_BITS)? as u16)
} else {
None
};
let header_present = read_flag(reader)?;
let header = if header_present {
SbrHeader::parse(reader)?
} else {
prev_header.ok_or(Error::SbrFreqBandInvalid)?
};
let bands = header.derive_bands(fs_sbr)?;
let element = match id_aac {
IdSynEle::Sce => SbrElement::parse_single(reader, &bands, header.amp_res)?,
IdSynEle::Cpe => SbrElement::parse_pair(reader, &bands, header.amp_res)?,
_ => return Err(Error::SbrFreqBandInvalid),
};
let num_sbr_bits = reader.bit_position() - start;
if let Some(cnt) = cnt {
let total = u64::from(cnt) * 8;
let consumed = num_sbr_bits + 4; if total < consumed {
return Err(Error::SbrFreqBandInvalid);
}
let align = (total - consumed) % 8;
if align > 0 {
read(reader, align as u32)?;
}
}
Ok(SbrExtensionData {
crc,
header_present,
header,
element,
num_sbr_bits,
})
}
}
#[inline]
fn read(reader: &mut BitReader<'_>, n: u32) -> Result<u32> {
reader.read_u32(n).map_err(|_| Error::SbrFreqBandInvalid)
}
#[inline]
fn read_flag(reader: &mut BitReader<'_>) -> Result<bool> {
reader.read_bit().map_err(|_| Error::SbrFreqBandInvalid)
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used, clippy::expect_used)]
use super::*;
use crate::engine::bits::BitWriter;
use crate::engine::sbr_freq_bands::HiLoTables;
use crate::engine::sbr_grid::FrameClass;
use crate::engine::sbr_huffman::{SbrHuffContext, env_tables, noise_tables};
const FS_SBR: u32 = 88_200;
fn write_header(w: &mut BitWriter, amp_res: bool) {
w.write_bit(amp_res); w.write_u32(5, 4); w.write_u32(0, 4); w.write_u32(1, 3); w.write_u32(0, 2); w.write_bit(true); w.write_bit(false); w.write_u32(0, 2); w.write_bit(false); w.write_u32(2, 2); }
fn header_bands() -> HiLoTables {
let mut w = BitWriter::new();
write_header(&mut w, false);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let h = SbrHeader::parse(&mut r).unwrap();
h.derive_bands(FS_SBR).unwrap()
}
fn push_code(w: &mut BitWriter, table: &[(u8, u32)], idx: usize) {
let (len, code) = table[idx];
w.write_u32(code, len as u32);
}
fn write_minimal_sce(w: &mut BitWriter, bands: &HiLoTables) {
let n_high = bands.n_high();
let n_q = bands.n_q();
w.write_bit(false); w.write_u32(FrameClass::FixFix.to_bits(), 2);
w.write_u32(0, 2); w.write_bit(true); w.write_bit(false); w.write_bit(false); for _ in 0..n_q {
w.write_u32(1, 2); }
let (_, (f_huff, f_lav)) = env_tables(SbrHuffContext {
coupling: false,
ch: false,
amp_res: false,
});
w.write_u32(33, 7); for i in 1..n_high {
push_code(w, f_huff, (i + f_lav as usize) % f_huff.len());
}
let (_, (nf, nfl)) = noise_tables(SbrHuffContext {
coupling: false,
ch: false,
amp_res: false,
});
w.write_u32(10, 5); for i in 1..n_q {
push_code(w, nf, (i + nfl as usize) % nf.len());
}
w.write_bit(false); w.write_bit(false); }
#[test]
fn parses_header_plus_single_channel() {
let bands = header_bands();
let mut w = BitWriter::new();
w.write_bit(true); write_header(&mut w, true);
write_minimal_sce(&mut w, &bands);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let sbr =
SbrExtensionData::parse(&mut r, IdSynEle::Sce, false, FS_SBR, None, None).unwrap();
assert!(sbr.header_present);
assert!(sbr.crc.is_none());
assert_eq!(sbr.header.start_freq, 5);
assert_eq!(sbr.header.freq_scale, 0);
assert!(!sbr.element.coupling);
assert_eq!(sbr.element.channels.len(), 1);
assert_eq!(sbr.element.channels[0].envelope.data[0][0], 33);
assert_eq!(sbr.element.channels[0].noise.data[0][0], 10);
}
#[test]
fn crc_flag_reads_ten_bit_field() {
let bands = header_bands();
let mut w = BitWriter::new();
w.write_u32(0x2A5, SBR_CRC_BITS); w.write_bit(true); write_header(&mut w, true);
write_minimal_sce(&mut w, &bands);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let sbr = SbrExtensionData::parse(&mut r, IdSynEle::Sce, true, FS_SBR, None, None).unwrap();
assert_eq!(sbr.crc, Some(0x2A5));
assert!(sbr.header_present);
}
#[test]
fn header_reuse_when_flag_clear() {
let bands = header_bands();
let prev = {
let mut w = BitWriter::new();
write_header(&mut w, true);
let bytes = w.finish();
SbrHeader::parse(&mut BitReader::new(&bytes)).unwrap()
};
let mut w = BitWriter::new();
w.write_bit(false); write_minimal_sce(&mut w, &bands);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let sbr = SbrExtensionData::parse(&mut r, IdSynEle::Sce, false, FS_SBR, None, Some(prev))
.unwrap();
assert!(!sbr.header_present);
assert_eq!(sbr.header, prev);
assert_eq!(sbr.element.channels.len(), 1);
}
#[test]
fn header_clear_without_prior_is_error() {
let mut w = BitWriter::new();
w.write_bit(false); let bytes = w.finish();
let mut r = BitReader::new(&bytes);
assert!(matches!(
SbrExtensionData::parse(&mut r, IdSynEle::Sce, false, FS_SBR, None, None),
Err(Error::SbrFreqBandInvalid)
));
}
#[test]
fn non_channel_id_aac_is_rejected() {
let mut w = BitWriter::new();
w.write_bit(true);
write_header(&mut w, true);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
assert!(matches!(
SbrExtensionData::parse(&mut r, IdSynEle::Lfe, false, FS_SBR, None, None),
Err(Error::SbrFreqBandInvalid)
));
}
#[test]
fn fill_bits_consumed_when_cnt_given() {
let bands = header_bands();
let mut w = BitWriter::new();
w.write_bit(true);
write_header(&mut w, true);
write_minimal_sce(&mut w, &bands);
let mut body = w.finish();
let cnt = (body.len() + 2) as u32;
body.extend_from_slice(&[0u8, 0u8]);
let mut r = BitReader::new(&body);
let before = r.bit_position();
let sbr =
SbrExtensionData::parse(&mut r, IdSynEle::Sce, false, FS_SBR, Some(cnt), None).unwrap();
let consumed = r.bit_position() - before;
assert_eq!((consumed + 4) % 8, 0);
assert_eq!(sbr.element.channels.len(), 1);
}
}