mod ac3;
mod amr;
mod audio;
mod av01;
mod btrt;
mod camm;
mod ccst;
mod chnl;
mod colr;
mod eac3;
mod evte;
mod fiel;
mod flac;
mod ftab;
mod h264;
mod hevc;
mod jpeg;
mod mebx;
mod metadata;
mod mett;
mod metx;
mod mp3;
mod mp4a;
mod opus;
mod pasp;
mod pcm;
mod plaintext;
mod spatial;
mod st3d;
mod sv3d;
mod taic;
mod tx3g;
mod uncv;
mod urim;
mod vexu;
mod visual;
mod vp9;
mod wvtt;
pub use ac3::*;
pub use amr::*;
pub use audio::*;
pub use av01::*;
pub use btrt::*;
pub use camm::*;
pub use ccst::*;
pub use chnl::*;
pub use colr::*;
pub use eac3::*;
pub use evte::*;
pub use fiel::*;
pub use flac::*;
pub use ftab::*;
pub use h264::*;
pub use hevc::*;
pub use jpeg::*;
pub use mebx::*;
pub use metadata::*;
pub use mett::*;
pub use metx::*;
pub use mp3::*;
pub use mp4a::*;
pub use opus::*;
pub use pasp::*;
pub use pcm::*;
pub use plaintext::*;
pub use spatial::*;
pub use st3d::*;
pub use sv3d::*;
pub use taic::*;
pub use tx3g::*;
pub use uncv::*;
pub use urim::*;
pub use vexu::*;
pub use visual::*;
pub use vp9::*;
pub use wvtt::*;
use crate::*;
use derive_more::From;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Stsd {
pub codecs: Vec<Codec>,
}
#[derive(Debug, Clone, PartialEq, Eq, From)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub enum Codec {
Avc1(Avc1),
Avc3(Avc3),
Jpeg(Jpeg),
Hev1(Hev1),
Hvc1(Hvc1),
Vp08(Vp08),
Vp09(Vp09),
Av01(Av01),
Mp4a(Mp4a),
Mp3(Mp3),
Tx3g(Tx3g),
Opus(Opus),
Uncv(Uncv),
Flac(Flac),
Ac3(Ac3),
Eac3(Eac3),
Ipcm(Ipcm),
Fpcm(Fpcm),
Sowt(Sowt),
Twos(Twos),
Lpcm(Lpcm),
In24(In24),
In32(In32),
Fl32(Fl32),
Fl64(Fl64),
S16l(S16l),
Wvtt(Wvtt),
Samr(Samr),
Mett(Mett),
Metx(Metx),
Urim(Urim),
Camm(Camm),
Evte(Evte),
Mebx(Mebx),
Unknown(FourCC, Vec<u8>),
}
impl Codec {
pub fn visual(&self) -> Option<&Visual> {
Some(match self {
Self::Avc1(avc1) => &avc1.visual,
Self::Avc3(avc3) => &avc3.visual,
Self::Jpeg(jpeg) => &jpeg.visual,
Self::Hev1(hev1) => &hev1.visual,
Self::Hvc1(hvc1) => &hvc1.visual,
Self::Vp08(vp08) => &vp08.visual,
Self::Vp09(vp09) => &vp09.visual,
Self::Av01(av01) => &av01.visual,
Self::Uncv(uncv) => &uncv.visual,
_ => return None,
})
}
pub fn audio(&self) -> Option<&Audio> {
Some(match self {
Self::Mp4a(mp4a) => &mp4a.audio,
Self::Mp3(mp3) => &mp3.audio,
Self::Opus(opus) => &opus.audio,
Self::Flac(flac) => &flac.audio,
Self::Ac3(ac3) => &ac3.audio,
Self::Eac3(eac3) => &eac3.audio,
Self::Ipcm(pcm) => &pcm.audio,
Self::Fpcm(pcm) => &pcm.audio,
Self::Sowt(pcm) => &pcm.audio,
Self::Twos(pcm) => &pcm.audio,
Self::Lpcm(pcm) => &pcm.audio,
Self::In24(pcm) => &pcm.audio,
Self::In32(pcm) => &pcm.audio,
Self::Fl32(pcm) => &pcm.audio,
Self::Fl64(pcm) => &pcm.audio,
Self::S16l(pcm) => &pcm.audio,
_ => return None,
})
}
pub fn metadata(&self) -> Option<&MetaData> {
Some(match self {
Self::Mett(mett) => &mett.metadata,
Self::Metx(metx) => &metx.metadata,
Self::Urim(urim) => &urim.metadata,
Self::Camm(camm) => &camm.metadata,
Self::Evte(evte) => &evte.metadata,
Self::Mebx(mebx) => &mebx.metadata,
_ => return None,
})
}
}
impl Decode for Codec {
fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
let atom = Any::decode(buf)?;
Ok(match atom {
Any::Avc1(atom) => atom.into(),
Any::Avc3(atom) => atom.into(),
Any::Jpeg(atom) => atom.into(),
Any::Hev1(atom) => atom.into(),
Any::Hvc1(atom) => atom.into(),
Any::Vp08(atom) => atom.into(),
Any::Vp09(atom) => atom.into(),
Any::Mp4a(atom) => atom.into(),
Any::Mp3(atom) => atom.into(),
Any::Tx3g(atom) => atom.into(),
Any::Av01(atom) => atom.into(),
Any::Opus(atom) => atom.into(),
Any::Uncv(atom) => atom.into(),
Any::Flac(atom) => atom.into(),
Any::Ac3(atom) => atom.into(),
Any::Eac3(atom) => atom.into(),
Any::Ipcm(atom) => atom.into(),
Any::Fpcm(atom) => atom.into(),
Any::Sowt(atom) => atom.into(),
Any::Twos(atom) => atom.into(),
Any::Lpcm(atom) => atom.into(),
Any::In24(atom) => atom.into(),
Any::In32(atom) => atom.into(),
Any::Fl32(atom) => atom.into(),
Any::Fl64(atom) => atom.into(),
Any::S16l(atom) => atom.into(),
Any::Wvtt(atom) => atom.into(),
Any::Samr(atom) => atom.into(),
Any::Mett(atom) => atom.into(),
Any::Metx(atom) => atom.into(),
Any::Urim(atom) => atom.into(),
Any::Camm(atom) => atom.into(),
Any::Evte(atom) => atom.into(),
Any::Mebx(atom) => atom.into(),
Any::Unknown(four_cc, body) => Self::Unknown(four_cc, body),
unknown => {
crate::decode_unknown(&unknown, Stsd::KIND)?;
let kind = unknown.kind();
let mut encoded = Vec::new();
unknown.encode(&mut encoded)?;
Self::Unknown(kind, encoded.split_off(8))
}
})
}
}
impl Encode for Codec {
fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
match self {
Self::Unknown(..) => Err(Error::UnknownCodec),
Self::Avc1(atom) => atom.encode(buf),
Self::Avc3(atom) => atom.encode(buf),
Self::Jpeg(atom) => atom.encode(buf),
Self::Hev1(atom) => atom.encode(buf),
Self::Hvc1(atom) => atom.encode(buf),
Self::Vp08(atom) => atom.encode(buf),
Self::Vp09(atom) => atom.encode(buf),
Self::Mp4a(atom) => atom.encode(buf),
Self::Mp3(atom) => atom.encode(buf),
Self::Tx3g(atom) => atom.encode(buf),
Self::Av01(atom) => atom.encode(buf),
Self::Opus(atom) => atom.encode(buf),
Self::Uncv(atom) => atom.encode(buf),
Self::Flac(atom) => atom.encode(buf),
Self::Ac3(atom) => atom.encode(buf),
Self::Eac3(atom) => atom.encode(buf),
Self::Ipcm(atom) => atom.encode(buf),
Self::Fpcm(atom) => atom.encode(buf),
Self::Sowt(atom) => atom.encode(buf),
Self::Twos(atom) => atom.encode(buf),
Self::Lpcm(atom) => atom.encode(buf),
Self::In24(atom) => atom.encode(buf),
Self::In32(atom) => atom.encode(buf),
Self::Fl32(atom) => atom.encode(buf),
Self::Fl64(atom) => atom.encode(buf),
Self::S16l(atom) => atom.encode(buf),
Self::Wvtt(atom) => atom.encode(buf),
Self::Samr(atom) => atom.encode(buf),
Self::Mett(atom) => atom.encode(buf),
Self::Metx(atom) => atom.encode(buf),
Self::Urim(atom) => atom.encode(buf),
Self::Camm(atom) => atom.encode(buf),
Self::Evte(atom) => atom.encode(buf),
Self::Mebx(atom) => atom.encode(buf),
}
}
}
impl AtomExt for Stsd {
type Ext = ();
const KIND_EXT: FourCC = FourCC::new(b"stsd");
fn decode_body_ext<B: Buf>(buf: &mut B, _ext: ()) -> Result<Self> {
let codec_count = u32::decode(buf)?;
let mut codecs = Vec::new();
for _ in 0..codec_count {
let codec = Codec::decode(buf)?;
codecs.push(codec);
}
Ok(Stsd { codecs })
}
fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<()> {
(self.codecs.len() as u32).encode(buf)?;
for codec in &self.codecs {
codec.encode(buf)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_codec_visual() {
let visual = Visual {
width: 640,
height: 480,
..Default::default()
};
let codec = Codec::from(Jpeg {
visual: visual.clone(),
..Default::default()
});
assert_eq!(codec.visual(), Some(&visual));
assert_eq!(codec.audio(), None);
assert_eq!(codec.metadata(), None);
}
#[test]
fn test_codec_audio() {
let audio = Audio {
data_reference_index: 1,
channel_count: 2,
sample_size: 16,
sample_rate: 44100.into(),
};
let codec = Codec::from(Mp3 {
audio: audio.clone(),
});
assert_eq!(codec.audio(), Some(&audio));
assert_eq!(codec.visual(), None);
}
#[test]
fn test_codec_metadata() {
let metadata = MetaData {
data_reference_index: 3,
};
let codec = Codec::from(Camm {
metadata: metadata.clone(),
});
assert_eq!(codec.metadata(), Some(&metadata));
assert_eq!(codec.visual(), None);
assert_eq!(codec.audio(), None);
}
#[test]
fn test_codec_neither() {
for codec in [
Codec::from(Tx3g::default()),
Codec::Unknown(FourCC::new(b"dvh9"), vec![]),
] {
assert_eq!(codec.visual(), None);
assert_eq!(codec.audio(), None);
assert_eq!(codec.metadata(), None);
}
}
#[cfg(not(feature = "strict"))]
mod not_strict {
use super::*;
#[test]
fn unknown_codec_parses() {
let input = b"\0\0\0\x1cstsd\0\0\0\0\0\0\0\x01\0\0\0\x0cdvh9\x01\x02\x03\x04";
let mut buf = input.as_slice();
let stsd = Stsd::decode(&mut buf).unwrap();
assert_eq!(
stsd.codecs,
vec![Codec::Unknown(FourCC::new(b"dvh9"), vec![1, 2, 3, 4])]
);
}
#[test]
fn unknown_codec_not_emitted() {
let stsd = Stsd {
codecs: vec![Codec::Unknown(FourCC::new(b"dvh9"), vec![1, 2, 3, 4])],
};
assert_eq!(
stsd.codecs,
vec![Codec::Unknown(FourCC::new(b"dvh9"), vec![1, 2, 3, 4])]
);
let mut output = Vec::new();
assert!(matches!(
stsd.encode(&mut output),
Err(crate::Error::UnknownCodec)
));
}
}
}