scuffle_mp4/boxes/types/
mp4a.rs

1use std::io;
2
3use bytes::{Buf, Bytes};
4
5use super::btrt::Btrt;
6use super::esds::Esds;
7use super::stsd::{AudioSampleEntry, SampleEntry};
8use crate::boxes::DynBox;
9use crate::boxes::header::BoxHeader;
10use crate::boxes::traits::BoxType;
11use crate::codec::AudioCodec;
12
13#[derive(Debug, Clone, PartialEq)]
14/// AAC Audio Sample Entry
15/// ISO/IEC 14496-14:2020(E) - 6.7
16pub struct Mp4a {
17    pub header: BoxHeader,
18    pub audio_sample_entry: SampleEntry<AudioSampleEntry>,
19    pub esds: Esds,
20    pub btrt: Option<Btrt>,
21    pub unknown: Vec<DynBox>,
22}
23
24impl Mp4a {
25    pub fn new(audio_sample_entry: SampleEntry<AudioSampleEntry>, esds: Esds, btrt: Option<Btrt>) -> Self {
26        Self {
27            header: BoxHeader::new(Self::NAME),
28            audio_sample_entry,
29            esds,
30            btrt,
31            unknown: Vec::new(),
32        }
33    }
34
35    #[allow(clippy::useless_asref)]
36    pub fn codec(&self) -> io::Result<AudioCodec> {
37        let info = self
38            .esds
39            .es_descriptor
40            .decoder_config
41            .as_ref()
42            .and_then(|c| c.decoder_specific_info.as_ref().map(|c| c.data.clone()))
43            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "Missing decoder specific info"))?;
44        let aac_config = scuffle_aac::PartialAudioSpecificConfig::parse(&info)?;
45
46        Ok(AudioCodec::Aac {
47            object_type: aac_config.audio_object_type,
48        })
49    }
50}
51
52impl BoxType for Mp4a {
53    const NAME: [u8; 4] = *b"mp4a";
54
55    fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
56        let mut reader = io::Cursor::new(data);
57
58        let audio_sample_entry = SampleEntry::<AudioSampleEntry>::demux(&mut reader)?;
59        let mut btrt = None;
60        let mut esds = None;
61        let mut unknown = Vec::new();
62
63        while reader.has_remaining() {
64            let dyn_box = DynBox::demux(&mut reader)?;
65            match dyn_box {
66                DynBox::Btrt(btrt_box) => {
67                    btrt = Some(*btrt_box);
68                }
69                DynBox::Esds(esds_box) => {
70                    esds = Some(*esds_box);
71                }
72                _ => {
73                    unknown.push(dyn_box);
74                }
75            }
76        }
77
78        let esds = esds.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "Missing esds box"))?;
79
80        Ok(Self {
81            header,
82            audio_sample_entry,
83            esds,
84            btrt,
85            unknown,
86        })
87    }
88
89    fn primitive_size(&self) -> u64 {
90        self.audio_sample_entry.size()
91            + self.btrt.as_ref().map(|b| b.size()).unwrap_or(0)
92            + self.esds.size()
93            + self.unknown.iter().map(|b| b.size()).sum::<u64>()
94    }
95
96    fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
97        self.audio_sample_entry.mux(writer)?;
98        self.esds.mux(writer)?;
99        if let Some(btrt) = &self.btrt {
100            btrt.mux(writer)?;
101        }
102        for unknown in &self.unknown {
103            unknown.mux(writer)?;
104        }
105        Ok(())
106    }
107}