use crate::engine::adts::ADTS_SAMPLE_RATES_HZ;
use crate::engine::enc_frame::LcEncoder;
use crate::engine::swb::LONG_WINDOW_LEN as FRAME;
use crate::error::{AacError, Result};
use crate::options::{EncodeContainer, EncodeOptions};
pub struct EncodedFrame<'a> {
pub samples: usize,
pub au: &'a [u8],
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EncodeInfo {
pub sample_rate: u32,
pub channels: usize,
pub aac_frames: u64,
pub samples: u64,
pub bytes: u64,
}
pub struct Encoder {
enc: LcEncoder,
sample_rate: u32,
channels: usize,
pending: [Vec<f32>; 2],
pending_len: usize,
scratch: Vec<u8>,
samples: u64,
aac_frames: u64,
bytes: u64,
}
impl Encoder {
pub fn new(sample_rate: u32, channels: usize, opts: &EncodeOptions) -> Result<Self> {
if !ADTS_SAMPLE_RATES_HZ.contains(&sample_rate) {
return Err(AacError::encode(format!(
"encode: unsupported sample rate {sample_rate}Hz (not in the AAC table)"
)));
}
if !(1..=2).contains(&channels) {
return Err(AacError::encode(format!(
"encode: channels must be 1 or 2, got {channels}"
)));
}
if opts.bitrate_bps == 0 {
return Err(AacError::encode("encode: bitrate must be > 0"));
}
if opts.container != EncodeContainer::Adts {
return Err(AacError::encode(
"encode: M4A/ISOBMFF needs finish-time sizes; use encode_with",
));
}
Ok(Self {
enc: LcEncoder::new(sample_rate, channels, opts.bitrate_bps)?
.with_lookahead(opts.lookahead),
sample_rate,
channels,
pending: [Vec::new(), Vec::new()],
pending_len: 0,
scratch: Vec::new(),
samples: 0,
aac_frames: 0,
bytes: 0,
})
}
pub fn feed<F>(&mut self, planes: &[&[f32]], on_frame: F) -> Result<usize>
where
F: FnMut(EncodedFrame<'_>) -> Result<()>,
{
if planes.len() != self.channels {
return Err(AacError::encode(format!(
"encode: expected {} channel plane(s), got {}",
self.channels,
planes.len()
)));
}
let n = planes.first().map_or(0, |p| p.len());
if planes.iter().any(|p| p.len() != n) {
return Err(AacError::encode("encode: channel planes differ in length"));
}
if planes.iter().any(|p| p.iter().any(|x| !x.is_finite())) {
return Err(AacError::encode("encode: non-finite sample"));
}
let mut cb = on_frame;
let mut scratch = std::mem::take(&mut self.scratch);
let mut off = 0usize;
while self.pending_len + (n - off) >= FRAME {
let take = FRAME - self.pending_len;
let mut bufs = [[0.0f32; FRAME]; 2];
for (ch, buf) in bufs.iter_mut().enumerate().take(self.channels) {
buf[..self.pending_len].copy_from_slice(&self.pending[ch][..self.pending_len]);
buf[self.pending_len..].copy_from_slice(&planes[ch][off..off + take]);
}
self.emit(&bufs, FRAME, &mut scratch, &mut cb)?;
off += take;
self.pending_len = 0;
}
self.scratch = scratch;
if off < n {
if self.pending_len == 0 {
for (ch, plane) in planes.iter().enumerate() {
self.pending[ch].clear();
self.pending[ch].extend_from_slice(&plane[off..]);
}
self.pending_len = n - off;
} else {
for (ch, plane) in planes.iter().enumerate() {
self.pending[ch].extend_from_slice(&plane[off..]);
}
self.pending_len += n - off;
}
}
self.samples += n as u64;
Ok(n)
}
pub fn finish<F>(mut self, on_frame: F) -> Result<EncodeInfo>
where
F: FnMut(EncodedFrame<'_>) -> Result<()>,
{
if self.samples == 0 {
return Err(AacError::encode("encode: empty input"));
}
let mut cb = on_frame;
let mut scratch = std::mem::take(&mut self.scratch);
if self.pending_len > 0 {
let tail = self.pending_len;
let mut bufs = [[0.0f32; FRAME]; 2];
for (ch, buf) in bufs.iter_mut().enumerate().take(self.channels) {
buf[..tail].copy_from_slice(&self.pending[ch][..tail]);
}
if self.enc.lookahead_enabled() {
let planes: Vec<&[f32]> = bufs[..self.channels].iter().map(|b| &b[..]).collect();
if let Some(au) = self.enc.push_frame(&planes)? {
self.deliver(&au, FRAME, &mut scratch, &mut cb)?;
}
if let Some(au) = self.enc.flush()? {
self.deliver(&au, tail, &mut scratch, &mut cb)?;
}
} else {
self.emit(&bufs, tail, &mut scratch, &mut cb)?;
}
} else if self.enc.lookahead_enabled()
&& let Some(au) = self.enc.flush()?
{
self.deliver(&au, FRAME, &mut scratch, &mut cb)?;
}
self.scratch = scratch;
Ok(EncodeInfo {
sample_rate: self.sample_rate,
channels: self.channels,
aac_frames: self.aac_frames,
samples: self.samples,
bytes: self.bytes,
})
}
fn emit<F>(
&mut self,
bufs: &[[f32; FRAME]; 2],
samples: usize,
scratch: &mut Vec<u8>,
cb: &mut F,
) -> Result<()>
where
F: FnMut(EncodedFrame<'_>) -> Result<()>,
{
let planes: Vec<&[f32]> = bufs[..self.channels].iter().map(|b| &b[..]).collect();
if self.enc.lookahead_enabled() {
if let Some(au) = self.enc.push_frame(&planes)? {
self.deliver(&au, samples, scratch, cb)?;
}
return Ok(());
}
let au = self.enc.encode_frame(&planes)?;
self.deliver(&au, samples, scratch, cb)
}
fn deliver<F>(
&mut self,
au: &[u8],
samples: usize,
scratch: &mut Vec<u8>,
cb: &mut F,
) -> Result<()>
where
F: FnMut(EncodedFrame<'_>) -> Result<()>,
{
scratch.clear();
crate::encode::adts_frame_into(au, self.enc.fs_index(), self.channels, scratch);
cb(EncodedFrame {
samples,
au: scratch,
})?;
self.aac_frames += 1;
self.bytes += scratch.len() as u64;
Ok(())
}
}
#[cfg(test)]
#[path = "enc_stream_tests.rs"]
mod enc_stream_tests;