use crate::*;
pub mod esds;
pub use esds::Esds;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Mp4a {
pub audio: Audio,
pub esds: Esds,
pub btrt: Option<Btrt>,
pub taic: Option<Taic>,
}
impl Atom for Mp4a {
const KIND: FourCC = FourCC::new(b"mp4a");
fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
let audio = Audio::decode(buf)?;
let mut btrt = None;
let mut esds = None;
let mut taic = None;
while let Some(atom) = Any::decode_maybe(buf)? {
match atom {
Any::Btrt(atom) => btrt = atom.into(),
Any::Esds(atom) => esds = atom.into(),
Any::Taic(atom) => taic = atom.into(),
Any::Unknown(kind, body) if kind == WAVE => {
decode_wave(&body, &mut esds, &mut btrt)?;
}
unknown => Self::decode_unknown(&unknown)?,
}
}
Ok(Mp4a {
audio,
esds: esds.ok_or(Error::MissingBox(Esds::KIND))?,
btrt,
taic,
})
}
fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
self.audio.encode(buf)?;
self.esds.encode(buf)?;
self.btrt.encode(buf)?;
self.taic.encode(buf)?;
Ok(())
}
}
const WAVE: FourCC = FourCC::new(b"wave");
fn decode_wave(mut wave: &[u8], esds: &mut Option<Esds>, btrt: &mut Option<Btrt>) -> Result<()> {
while let Some(header) = Header::decode_maybe(&mut wave)? {
let size = match header.size {
Some(size) if size <= wave.remaining() => size,
_ => break,
};
let mut child = wave.slice(size);
if header.kind == Esds::KIND {
*esds = Some(Esds::decode_body(&mut child)?);
} else if header.kind == Btrt::KIND {
*btrt = Some(Btrt::decode_body(&mut child)?);
}
wave.advance(size);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mp4a() {
let expected = Mp4a {
audio: Audio {
data_reference_index: 1,
channel_count: 2,
sample_size: 16,
sample_rate: 48000.into(),
},
esds: Esds {
es_desc: esds::EsDescriptor {
es_id: 2,
dec_config: esds::DecoderConfig {
object_type_indication: 0x40,
stream_type: 0x05,
up_stream: 0,
buffer_size_db: Default::default(),
max_bitrate: 67695,
avg_bitrate: 67695,
dec_specific: esds::DecoderSpecific {
profile: 2,
freq_index: 4,
chan_conf: 2,
},
},
sl_config: esds::SLConfig::default(),
},
},
btrt: Some(Btrt {
buffer_size_db: 1,
max_bitrate: 2,
avg_bitrate: 3,
}),
taic: None,
};
let mut buf = Vec::new();
expected.encode(&mut buf).unwrap();
let mut buf = buf.as_ref();
let decoded = Mp4a::decode(&mut buf).unwrap();
assert_eq!(decoded, expected);
}
fn atom_box(fourcc: &[u8; 4], body: &[u8]) -> Vec<u8> {
let mut v = Vec::with_capacity(8 + body.len());
v.extend_from_slice(&((8 + body.len()) as u32).to_be_bytes());
v.extend_from_slice(fourcc);
v.extend_from_slice(body);
v
}
#[test]
fn test_mp4a_quicktime_wave() {
let audio = Audio {
data_reference_index: 1,
channel_count: 2,
sample_size: 16,
sample_rate: 48000.into(),
};
let esds = Esds {
es_desc: esds::EsDescriptor {
es_id: 2,
dec_config: esds::DecoderConfig {
object_type_indication: 0x40,
stream_type: 0x05,
up_stream: 0,
buffer_size_db: Default::default(),
max_bitrate: 67695,
avg_bitrate: 67695,
dec_specific: esds::DecoderSpecific {
profile: 2,
freq_index: 4,
chan_conf: 2,
},
},
sl_config: esds::SLConfig::default(),
},
};
let btrt = Btrt {
buffer_size_db: 1,
max_bitrate: 2,
avg_bitrate: 3,
};
let mut audio_bytes = Vec::new();
audio.encode(&mut audio_bytes).unwrap();
let mut esds_box = Vec::new();
esds.encode(&mut esds_box).unwrap();
let mut btrt_box = Vec::new();
btrt.encode(&mut btrt_box).unwrap();
let mut wave_body = Vec::new();
wave_body.extend_from_slice(&atom_box(b"frma", b"mp4a"));
wave_body.extend_from_slice(&atom_box(b"mp4a", &[0, 0, 0, 0]));
wave_body.extend_from_slice(&esds_box);
wave_body.extend_from_slice(&btrt_box);
wave_body.extend_from_slice(&[0, 0, 0, 8, 0, 0, 0, 0]);
let mut mp4a_body = audio_bytes;
mp4a_body.extend_from_slice(&atom_box(b"wave", &wave_body));
let mp4a = atom_box(b"mp4a", &mp4a_body);
let mut buf = mp4a.as_slice();
let decoded = Mp4a::decode(&mut buf).unwrap();
assert_eq!(decoded.audio, audio);
assert_eq!(decoded.esds, esds);
assert_eq!(decoded.btrt, Some(btrt));
}
#[test]
fn test_mp4a_with_taic() {
let expected = Mp4a {
audio: Audio {
data_reference_index: 1,
channel_count: 2,
sample_size: 16,
sample_rate: 48000.into(),
},
esds: Esds {
es_desc: esds::EsDescriptor {
es_id: 2,
dec_config: esds::DecoderConfig {
object_type_indication: 0x40,
stream_type: 0x05,
up_stream: 0,
buffer_size_db: Default::default(),
max_bitrate: 67695,
avg_bitrate: 67695,
dec_specific: esds::DecoderSpecific {
profile: 2,
freq_index: 4,
chan_conf: 2,
},
},
sl_config: esds::SLConfig::default(),
},
},
btrt: None,
taic: Some(Taic {
time_uncertainty: 1,
clock_resolution: 2,
clock_drift_rate: 4,
clock_type: ClockType::CanSync,
}),
};
let mut buf = Vec::new();
expected.encode(&mut buf).unwrap();
let mut buf = buf.as_ref();
let decoded = Mp4a::decode(&mut buf).unwrap();
assert_eq!(decoded, expected);
}
}