use crate::error::Result;
use crate::macros::decode_err;
use crate::mp4::{AudioObjectType, SAMPLE_RATES};
use crate::mpeg::MpegVersion;
use crate::probe::ParsingMode;
use std::io::{Read, Seek, SeekFrom};
pub(super) const HEADER_MASK: u32 = 0xFFFF_FFE0;
#[derive(Copy, Clone)]
pub(crate) struct ADTSHeader {
pub(crate) version: MpegVersion,
pub(crate) audio_object_ty: AudioObjectType,
pub(crate) sample_rate: u32,
pub(crate) channels: u8,
pub(crate) copyright: bool,
pub(crate) original: bool,
pub(crate) len: u16,
pub(crate) bitrate: u32,
pub(crate) bytes: [u8; 7],
pub(crate) has_crc: bool,
}
impl ADTSHeader {
pub(super) fn read<R>(reader: &mut R, _parse_mode: ParsingMode) -> Result<Option<Self>>
where
R: Read + Seek,
{
let mut needs_crc_skip = false;
let mut header = [0; 7];
reader.read_exact(&mut header)?;
let byte2 = header[1];
let version = match (byte2 >> 3) & 0b1 {
0 => MpegVersion::V4,
1 => MpegVersion::V2,
_ => unreachable!(),
};
if byte2 & 0b1 == 0 {
needs_crc_skip = true;
}
let byte3 = header[2];
let audio_object_ty = match ((byte3 >> 6) & 0b11) + 1 {
1 => AudioObjectType::AacMain,
2 => AudioObjectType::AacLowComplexity,
3 => AudioObjectType::AacScalableSampleRate,
4 => AudioObjectType::AacLongTermPrediction,
_ => unreachable!(),
};
let sample_rate_idx = (byte3 >> 2) & 0b1111;
if sample_rate_idx == 15 {
decode_err!(@BAIL AAC, "File contains an invalid sample frequency index");
}
let sample_rate = SAMPLE_RATES[sample_rate_idx as usize];
let byte4 = header[3];
let channel_configuration = ((byte3 & 0b1) << 2) | ((byte4 >> 6) & 0b11);
let original = (byte4 >> 5) & 0b1 == 1;
let copyright = (byte4 >> 4) & 0b1 == 1;
let byte5 = header[4];
let byte6 = header[5];
let len = (u16::from(byte4 & 0b11) << 11) | u16::from(byte5) << 3 | u16::from(byte6) >> 5;
let bitrate = ((u32::from(len) * sample_rate / 1024) * 8) / 1024;
if needs_crc_skip {
reader.seek(SeekFrom::Current(2))?;
}
Ok(Some(ADTSHeader {
version,
audio_object_ty,
sample_rate,
channels: channel_configuration,
copyright,
original,
len,
bitrate,
bytes: header,
has_crc: needs_crc_skip,
}))
}
}