scuffle_mp4/boxes/types/
mp4a.rs1use 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)]
14pub 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}