use super::bits::{BitReader, BitWriter};
use super::error::{Error, Result};
pub const ADTS_SYNCWORD: u16 = 0x0FFF;
pub const ADTS_HEADER_BYTES_NO_CRC: usize = 7;
pub const ADTS_HEADER_BYTES_WITH_CRC: usize = 9;
pub const ADTS_SAMPLE_RATES_HZ: [u32; 13] = [
96_000, 88_200, 64_000, 48_000, 44_100, 32_000, 24_000, 22_050, 16_000, 12_000, 11_025, 8_000,
7_350,
];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AdtsHeader {
pub mpeg_version_mpeg2: bool,
pub protection_absent: bool,
pub profile: u8,
pub sampling_frequency_index: u8,
pub channel_configuration: u8,
pub aac_frame_length: u16,
pub adts_buffer_fullness: u16,
pub number_of_raw_data_blocks_in_frame: u8,
}
impl AdtsHeader {
pub fn parse(data: &[u8]) -> Result<(Self, usize)> {
if data.len() < ADTS_HEADER_BYTES_NO_CRC {
return Err(Error::UnexpectedEnd);
}
let mut br = BitReader::new(data);
let sync = br.read(12)? as u16;
if sync != ADTS_SYNCWORD {
return Err(Error::AdtsSyncNotFound);
}
let mpeg_version_mpeg2 = br.read_bit()?;
let layer = br.read(2)?;
if layer != 0 {
return Err(Error::AdtsLayerNonZero);
}
let protection_absent = br.read_bit()?;
let profile = br.read(2)? as u8;
let sampling_frequency_index = br.read(4)? as u8;
if sampling_frequency_index >= 13 {
return Err(Error::AdtsReservedSampleRateIndex);
}
let _private_bit = br.read_bit()?;
let channel_configuration = br.read(3)? as u8;
let _original_copy = br.read_bit()?;
let _home = br.read_bit()?;
let _copyright_identification_bit = br.read_bit()?;
let _copyright_identification_start = br.read_bit()?;
let aac_frame_length = br.read(13)? as u16;
let adts_buffer_fullness = br.read(11)? as u16;
let number_of_raw_data_blocks_in_frame = br.read(2)? as u8 + 1;
let payload_offset = payload_offset(protection_absent, number_of_raw_data_blocks_in_frame);
if (aac_frame_length as usize) < payload_offset {
return Err(Error::AdtsFrameLengthTooSmall);
}
if data.len() < payload_offset {
return Err(Error::UnexpectedEnd);
}
Ok((
AdtsHeader {
mpeg_version_mpeg2,
protection_absent,
profile,
sampling_frequency_index,
channel_configuration,
aac_frame_length,
adts_buffer_fullness,
number_of_raw_data_blocks_in_frame,
},
payload_offset,
))
}
#[must_use]
pub fn sample_rate(&self) -> u32 {
ADTS_SAMPLE_RATES_HZ
.get(self.sampling_frequency_index as usize)
.copied()
.unwrap_or(0)
}
#[must_use]
pub fn audio_object_type(&self) -> u8 {
self.profile + 1
}
#[must_use]
pub fn write(&self) -> [u8; ADTS_HEADER_BYTES_NO_CRC] {
let mut w = BitWriter::new();
w.write(u32::from(ADTS_SYNCWORD), 12);
w.write_bit(self.mpeg_version_mpeg2);
w.write(0, 2); w.write_bit(true); w.write(u32::from(self.profile), 2);
w.write(u32::from(self.sampling_frequency_index), 4);
w.write_bit(false); w.write(u32::from(self.channel_configuration), 3);
w.write(0, 4); w.write(u32::from(self.aac_frame_length), 13);
w.write(u32::from(self.adts_buffer_fullness), 11);
w.write(
u32::from(self.number_of_raw_data_blocks_in_frame.saturating_sub(1)),
2,
);
let bytes = w.finish();
let mut out = [0u8; ADTS_HEADER_BYTES_NO_CRC];
out.copy_from_slice(&bytes);
out
}
}
#[must_use]
pub fn payload_offset(protection_absent: bool, n_rdb: u8) -> usize {
if protection_absent {
ADTS_HEADER_BYTES_NO_CRC
} else if n_rdb <= 1 {
ADTS_HEADER_BYTES_WITH_CRC
} else {
ADTS_HEADER_BYTES_NO_CRC + 2 * usize::from(n_rdb)
}
}
#[cfg(test)]
#[path = "adts_tests.rs"]
mod adts_tests;