use crate::engine::adts::AdtsHeader;
use crate::error::Result;
use crate::isomp4::sniff_is_isobmff;
use crate::options::{ChannelMode, DecodeOptions};
use crate::stream::{decode_streaming, decode_streaming_mono_into};
#[derive(Debug, Clone)]
pub struct DecodedAac {
pub sample_rate: u32,
pub channels: Vec<Vec<f32>>,
}
#[inline]
pub fn decode(data: &[u8]) -> Result<DecodedAac> {
decode_with(data, &DecodeOptions::speech())
}
#[inline]
pub fn decode_bytes(data: &[u8]) -> Result<DecodedAac> {
decode(data)
}
pub fn read(path: impl AsRef<std::path::Path>) -> Result<DecodedAac> {
decode(&std::fs::read(path)?)
}
pub fn read_with(path: impl AsRef<std::path::Path>, opts: &DecodeOptions) -> Result<DecodedAac> {
decode_with(&std::fs::read(path)?, opts)
}
pub fn decode_with(data: &[u8], opts: &DecodeOptions) -> Result<DecodedAac> {
let est_frames = adts_frame_estimate(data);
if matches!(opts.channel_mode, ChannelMode::Mono) && !sniff_is_isobmff(data) {
let mut track: Vec<f32> = Vec::new();
let info = decode_streaming_mono_into(data, opts, est_frames, &mut track)?;
return Ok(DecodedAac {
sample_rate: info.sample_rate,
channels: vec![track],
});
}
let mut tracks: Vec<Vec<f32>> = Vec::new();
let info = decode_streaming(data, opts, |f| {
if tracks.is_empty() {
tracks.resize_with(f.planar.len(), Vec::new);
if let Some(frames) = est_frames {
let per = (frames * f.samples).min(opts.max_frames(f.sample_rate));
for t in &mut tracks {
t.reserve(per);
}
}
}
for (dst, src) in tracks.iter_mut().zip(f.planar.iter()) {
dst.extend_from_slice(src);
}
Ok(())
})?;
Ok(DecodedAac {
sample_rate: info.sample_rate,
channels: tracks,
})
}
fn adts_frame_estimate(data: &[u8]) -> Option<usize> {
let mut pos = 0usize;
let mut frames = 0usize;
while let Ok((hdr, _)) = AdtsHeader::parse(&data[pos..]) {
let len = usize::from(hdr.aac_frame_length);
if len == 0 || pos + len > data.len() {
break;
}
pos += len;
frames += 1;
}
(frames > 0).then_some(frames)
}