use crate::budgets::{BudgetExceeded, BudgetKind};
use crate::engine::asc::AudioSpecificConfig;
use crate::engine::decode::StreamDecoder;
use crate::engine::error::Error as EngineError;
use crate::engine::latm::MuxCfg;
use crate::error::{AacError, Result};
use crate::isomp4::sniff_is_isobmff;
use crate::options::{ChannelMode, DecodeOptions};
mod adts_gap;
mod au;
mod fmp4;
mod frame;
mod m4a;
mod m4a_pos;
mod m4a_seek;
mod pump;
mod read;
pub use frame::{Frame, StreamInfo};
pub use m4a_pos::{M4aSeek, preroll_aus};
pub use m4a_seek::decode_seek_streaming;
pub use read::decode_read_streaming;
enum Container {
Unknown,
Adts,
Latm,
Au,
Fmp4,
}
pub struct Decoder {
opts: DecodeOptions,
buf: Vec<u8>,
pos: usize,
abs_base: u64,
container: Container,
dec: Box<StreamDecoder>,
mux: Option<MuxCfg>,
au: Option<AudioSpecificConfig>,
fmp4: fmp4::Fmp4Push,
gap: adts_gap::AdtsGap,
mono_scratch: Vec<f32>,
locked: Option<(u32, usize)>,
max_samples: usize,
aac_frames: u64,
samples_decoded: u64,
samples_out: u64,
emitted: u64,
sink_frame_samples: usize,
life: Life,
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Life {
Open,
Finished,
Failed,
}
impl Decoder {
pub fn new(opts: DecodeOptions) -> Self {
let mut dec = StreamDecoder::new();
dec.mix_down_mono = matches!(opts.channel_mode, ChannelMode::Mono);
Self {
opts,
buf: Vec::new(),
pos: 0,
abs_base: 0,
container: Container::Unknown,
dec,
mux: None,
au: None,
fmp4: fmp4::Fmp4Push::default(),
gap: adts_gap::AdtsGap::default(),
mono_scratch: Vec::new(),
locked: None,
max_samples: 0,
aac_frames: 0,
samples_decoded: 0,
samples_out: 0,
emitted: 0,
sink_frame_samples: 0,
life: Life::Open,
}
}
fn ensure_open(&self) -> Result<()> {
match self.life {
Life::Open => Ok(()),
Life::Finished => Err(AacError::Lifecycle {
state: crate::LifecycleState::Finished,
}),
Life::Failed => Err(AacError::Lifecycle {
state: crate::LifecycleState::Failed,
}),
}
}
fn fail<T>(&mut self, e: AacError) -> Result<T> {
let e = e.with_truncated_at(self.pos as u64);
self.life = Life::Failed;
Err(e)
}
#[must_use]
pub fn frames(&self) -> u64 {
self.aac_frames
}
#[must_use]
pub fn samples(&self) -> u64 {
self.samples_out
}
#[must_use]
pub fn is_failed(&self) -> bool {
self.life == Life::Failed
}
#[must_use]
pub fn is_finished(&self) -> bool {
self.life == Life::Finished
}
pub fn reset(&mut self) {
self.dec.reset();
self.buf.clear();
self.pos = 0;
self.abs_base = 0;
self.container = Container::Unknown;
self.mux = None;
self.au = None;
self.fmp4.reset();
self.gap = adts_gap::AdtsGap::default();
self.mono_scratch.clear();
self.locked = None;
self.max_samples = 0;
self.aac_frames = 0;
self.samples_decoded = 0;
self.samples_out = 0;
self.emitted = 0;
self.sink_frame_samples = 0;
self.life = Life::Open;
}
#[cfg(test)]
pub(crate) fn test_pcm_cap(&self) -> usize {
self.dec.pcm_l.capacity()
}
#[cfg(test)]
pub(crate) fn test_buf_cap(&self) -> usize {
self.buf.capacity()
}
pub fn feed<F>(&mut self, bytes: &[u8], on_frame: F) -> Result<usize>
where
F: FnMut(Frame<'_>) -> Result<()>,
{
self.ensure_open()?;
self.opts.validate()?;
let mut cb = on_frame;
let mut off = 0usize;
while off < bytes.len() {
let cap = self.feed_cap();
let mut buf = std::mem::take(&mut self.buf);
self.compact(&mut buf);
let used = buf.len();
if used >= cap {
let res = self.pump(&buf, None, None, &mut cb, false);
if res.is_ok() {
self.compact(&mut buf);
}
self.buf = buf;
if let Err(e) = res {
return self.fail(e);
}
if self.buf.len() >= cap {
return self.fail(AacError::from(BudgetExceeded {
kind: BudgetKind::Input,
observed: self.buf.len() as u64,
max: self.opts.memory.max_buffered_input_bytes,
}));
}
continue;
}
let n = (bytes.len() - off).min(cap - used);
buf.extend_from_slice(&bytes[off..off + n]);
off += n;
let res = self.pump(&buf, None, None, &mut cb, false);
if res.is_ok() {
self.compact(&mut buf);
}
self.buf = buf;
if let Err(e) = res {
return self.fail(e);
}
}
Ok(bytes.len())
}
fn feed_cap(&self) -> usize {
let base = usize::try_from(self.opts.memory.max_buffered_input_bytes)
.unwrap_or(usize::MAX)
.max(1);
if matches!(self.container, Container::Fmp4) {
let meta = usize::try_from(self.opts.memory.max_metadata_bytes)
.unwrap_or(usize::MAX)
.max(1);
base.max(meta)
} else {
base
}
}
fn compact(&mut self, buf: &mut Vec<u8>) {
if self.pos == 0 {
return;
}
self.abs_base += self.pos as u64;
if self.pos >= buf.len() {
buf.clear();
self.pos = 0;
return;
}
buf.drain(..self.pos);
self.pos = 0;
}
pub fn finish<F>(&mut self, on_frame: F) -> Result<StreamInfo>
where
F: FnMut(Frame<'_>) -> Result<()>,
{
self.ensure_open()?;
self.opts.validate()?;
let buf = std::mem::take(&mut self.buf);
let mut cb = on_frame;
if let Err(e) = self.pump(&buf, None, None, &mut cb, true) {
return self.fail(e);
}
match self.tallies() {
Ok(info) => {
self.life = Life::Finished;
Ok(info)
}
Err(e) => self.fail(e),
}
}
fn tallies(&self) -> Result<StreamInfo> {
if self.emitted == 0 {
return Err(match self.container {
Container::Latm => AacError::from(EngineError::LoasSyncInvalid),
_ => AacError::NotAac,
});
}
let (sample_rate, channels) = self.locked.unwrap_or((0, 0));
let (priming, remainder) = match self.container {
Container::Fmp4 => self.fmp4_trim(),
Container::Adts => self.gap.report(self.samples_decoded),
_ => (None, None),
};
Ok(StreamInfo {
sample_rate,
core_rate: self.dec.last_core_rate(),
channels,
layout: self.dec.last_meta().layout,
aac_frames: self.aac_frames,
samples: self.samples_out,
priming,
remainder,
})
}
}
pub fn decode_streaming<F>(data: &[u8], opts: &DecodeOptions, on_frame: F) -> Result<StreamInfo>
where
F: FnMut(Frame<'_>) -> Result<()>,
{
opts.validate()?;
opts.memory.check_input_finite(data.len() as u64)?;
if sniff_is_isobmff(data) {
return m4a::stream_m4a(data, opts, on_frame);
}
Decoder::new(opts.clone()).decode_slice(data, on_frame)
}
pub(crate) fn decode_streaming_mono_into(
data: &[u8],
opts: &DecodeOptions,
est_frames: Option<usize>,
dst: &mut Vec<f32>,
) -> Result<StreamInfo> {
opts.validate()?;
opts.memory.check_input_finite(data.len() as u64)?;
Decoder::new(opts.clone()).decode_slice_mono(data, est_frames, dst)
}