use symphonia_core::errors::unsupported_error;
use symphonia_core::support_format;
use symphonia_core::audio::Channels;
use symphonia_core::codecs::{CodecParameters, CODEC_TYPE_AAC};
use symphonia_core::errors::{decode_error, seek_error, Result, SeekErrorKind};
use symphonia_core::formats::prelude::*;
use symphonia_core::io::*;
use symphonia_core::meta::{Metadata, MetadataLog};
use symphonia_core::probe::{Descriptor, Instantiate, QueryDescriptor};
use std::io::{Seek, SeekFrom};
use super::common::{map_channels, M4AType, AAC_SAMPLE_RATES, M4A_TYPES};
use log::debug;
const SAMPLES_PER_AAC_PACKET: u64 = 1024;
pub struct AdtsReader {
reader: MediaSourceStream,
tracks: Vec<Track>,
cues: Vec<Cue>,
metadata: MetadataLog,
first_frame_pos: u64,
next_packet_ts: u64,
}
impl QueryDescriptor for AdtsReader {
fn query() -> &'static [Descriptor] {
&[support_format!(
"aac",
"Audio Data Transport Stream (native AAC)",
&["aac"],
&["audio/aac"],
&[&[0xff, 0xf1]]
)]
}
fn score(_context: &[u8]) -> u8 {
255
}
}
#[derive(Debug)]
#[allow(dead_code)]
struct AdtsHeader {
profile: M4AType,
channels: Option<Channels>,
sample_rate: u32,
frame_len: usize,
}
impl AdtsHeader {
const SIZE: usize = 7;
fn sync<B: ReadBytes>(reader: &mut B) -> Result<()> {
let mut sync = 0u16;
while sync != 0xfff1 {
sync = (sync << 8) | u16::from(reader.read_u8()?);
}
Ok(())
}
fn read<B: ReadBytes>(reader: &mut B) -> Result<Self> {
AdtsHeader::sync(reader)?;
let mut buf = [0u8; 7];
reader.read_buf_exact(&mut buf[..5])?;
let mut bs = BitReaderLtr::new(&buf);
let profile = M4A_TYPES[bs.read_bits_leq32(2)? as usize + 1];
let sample_rate = match bs.read_bits_leq32(4)? as usize {
15 => return decode_error("adts: forbidden sample rate"),
13 | 14 => return decode_error("adts: reserved sample rate"),
idx => AAC_SAMPLE_RATES[idx],
};
bs.ignore_bit()?;
let channels = match bs.read_bits_leq32(3)? {
0 => None,
idx => map_channels(idx),
};
bs.ignore_bits(4)?;
let frame_len = bs.read_bits_leq32(13)? as usize;
if frame_len < AdtsHeader::SIZE {
return decode_error("adts: invalid adts frame length");
}
let _fullness = bs.read_bits_leq32(11)?;
let num_aac_frames = bs.read_bits_leq32(2)? + 1;
if num_aac_frames > 1 {
return unsupported_error("adts: only 1 aac frame per adts packet is supported");
}
Ok(AdtsHeader { profile, channels, sample_rate, frame_len: frame_len - AdtsHeader::SIZE })
}
}
impl FormatReader for AdtsReader {
fn try_new(mut source: MediaSourceStream, _options: &FormatOptions) -> Result<Self> {
let header = AdtsHeader::read(&mut source)?;
let mut params = CodecParameters::new();
params.for_codec(CODEC_TYPE_AAC).with_sample_rate(header.sample_rate);
if let Some(channels) = header.channels {
params.with_channels(channels);
}
source.seek_buffered_rev(AdtsHeader::SIZE);
let first_frame_pos = source.pos();
Ok(AdtsReader {
reader: source,
tracks: vec![Track::new(0, params)],
cues: Vec::new(),
metadata: Default::default(),
first_frame_pos,
next_packet_ts: 0,
})
}
fn next_packet(&mut self) -> Result<Packet> {
let header = AdtsHeader::read(&mut self.reader)?;
let ts = self.next_packet_ts;
self.next_packet_ts += SAMPLES_PER_AAC_PACKET;
Ok(Packet::new_from_boxed_slice(
0,
ts,
SAMPLES_PER_AAC_PACKET,
self.reader.read_boxed_slice_exact(header.frame_len)?,
))
}
fn metadata(&mut self) -> Metadata<'_> {
self.metadata.metadata()
}
fn cues(&self) -> &[Cue] {
&self.cues
}
fn tracks(&self) -> &[Track] {
&self.tracks
}
fn seek(&mut self, _mode: SeekMode, to: SeekTo) -> Result<SeekedTo> {
let required_ts = match to {
SeekTo::TimeStamp { ts, .. } => ts,
SeekTo::Time { time, .. } => {
if let Some(sample_rate) = self.tracks[0].codec_params.sample_rate {
TimeBase::new(1, sample_rate).calc_timestamp(time)
}
else {
return seek_error(SeekErrorKind::Unseekable);
}
}
};
debug!("seeking to ts={}", required_ts);
if required_ts < self.next_packet_ts {
if self.reader.is_seekable() {
let seeked_pos = self.reader.seek(SeekFrom::Start(self.first_frame_pos))?;
if seeked_pos != self.first_frame_pos {
return seek_error(SeekErrorKind::Unseekable);
}
}
else {
return seek_error(SeekErrorKind::ForwardOnly);
}
self.next_packet_ts = 0;
}
loop {
let header = AdtsHeader::read(&mut self.reader)?;
if self.next_packet_ts + SAMPLES_PER_AAC_PACKET > required_ts {
self.reader.seek_buffered_rev(AdtsHeader::SIZE);
break;
}
self.reader.ignore_bytes(header.frame_len as u64)?;
self.next_packet_ts += SAMPLES_PER_AAC_PACKET;
}
debug!(
"seeked to ts={} (delta={})",
self.next_packet_ts,
required_ts as i64 - self.next_packet_ts as i64
);
Ok(SeekedTo { track_id: 0, required_ts, actual_ts: self.next_packet_ts })
}
fn into_inner(self: Box<Self>) -> MediaSourceStream {
self.reader
}
}