Skip to main content

mp4/mp4box/
mp4a.rs

1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
2use serde::Serialize;
3use std::io::{Read, Seek, Write};
4
5use crate::mp4box::*;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
8pub struct Mp4aBox {
9    pub data_reference_index: u16,
10    pub channelcount: u16,
11    pub samplesize: u16,
12
13    #[serde(with = "value_u32")]
14    pub samplerate: FixedPointU16,
15    pub esds: Option<EsdsBox>,
16}
17
18impl Default for Mp4aBox {
19    fn default() -> Self {
20        Self {
21            data_reference_index: 0,
22            channelcount: 2,
23            samplesize: 16,
24            samplerate: FixedPointU16::new(48000),
25            esds: Some(EsdsBox::default()),
26        }
27    }
28}
29
30impl Mp4aBox {
31    pub fn new(config: &AacConfig) -> Self {
32        Self {
33            data_reference_index: 1,
34            channelcount: config.chan_conf as u16,
35            samplesize: 16,
36            samplerate: FixedPointU16::new(config.freq_index.freq() as u16),
37            esds: Some(EsdsBox::new(config)),
38        }
39    }
40
41    pub fn get_type(&self) -> BoxType {
42        BoxType::Mp4aBox
43    }
44
45    pub fn get_size(&self) -> u64 {
46        let mut size = HEADER_SIZE + 8 + 20;
47        if let Some(ref esds) = self.esds {
48            size += esds.box_size();
49        }
50        size
51    }
52}
53
54impl Mp4Box for Mp4aBox {
55    fn box_type(&self) -> BoxType {
56        self.get_type()
57    }
58
59    fn box_size(&self) -> u64 {
60        self.get_size()
61    }
62
63    fn to_json(&self) -> Result<String> {
64        Ok(serde_json::to_string(&self).unwrap())
65    }
66
67    fn summary(&self) -> Result<String> {
68        let s = format!(
69            "channel_count={} sample_size={} sample_rate={}",
70            self.channelcount,
71            self.samplesize,
72            self.samplerate.value()
73        );
74        Ok(s)
75    }
76}
77
78impl<R: Read + Seek> ReadBox<&mut R> for Mp4aBox {
79    fn read_box(reader: &mut R, size: u64) -> Result<Self> {
80        let start = box_start(reader)?;
81
82        reader.read_u32::<BigEndian>()?; // reserved
83        reader.read_u16::<BigEndian>()?; // reserved
84        let data_reference_index = reader.read_u16::<BigEndian>()?;
85        let version = reader.read_u16::<BigEndian>()?;
86        reader.read_u16::<BigEndian>()?; // reserved
87        reader.read_u32::<BigEndian>()?; // reserved
88        let channelcount = reader.read_u16::<BigEndian>()?;
89        let samplesize = reader.read_u16::<BigEndian>()?;
90        reader.read_u32::<BigEndian>()?; // pre-defined, reserved
91        let samplerate = FixedPointU16::new_raw(reader.read_u32::<BigEndian>()?);
92
93        if version == 1 {
94            // Skip QTFF
95            reader.read_u64::<BigEndian>()?;
96            reader.read_u64::<BigEndian>()?;
97        }
98
99        // Find esds in mp4a or wave
100        let mut esds = None;
101        let end = start + size;
102        loop {
103            let current = reader.stream_position()?;
104            if current >= end {
105                break;
106            }
107            let header = BoxHeader::read(reader)?;
108            let BoxHeader { name, size: s } = header;
109            if s > size {
110                return Err(Error::InvalidData(
111                    "mp4a box contains a box with a larger size than it",
112                ));
113            }
114            if name == BoxType::EsdsBox {
115                esds = Some(EsdsBox::read_box(reader, s)?);
116                break;
117            } else if name == BoxType::WaveBox {
118                // Typically contains frma, mp4a, esds, and a terminator atom
119            } else {
120                // Skip boxes
121                let skip_to = current + s;
122                skip_bytes_to(reader, skip_to)?;
123            }
124        }
125
126        skip_bytes_to(reader, end)?;
127
128        Ok(Mp4aBox {
129            data_reference_index,
130            channelcount,
131            samplesize,
132            samplerate,
133            esds,
134        })
135    }
136}
137
138impl<W: Write> WriteBox<&mut W> for Mp4aBox {
139    fn write_box(&self, writer: &mut W) -> Result<u64> {
140        let size = self.box_size();
141        BoxHeader::new(self.box_type(), size).write(writer)?;
142
143        writer.write_u32::<BigEndian>(0)?; // reserved
144        writer.write_u16::<BigEndian>(0)?; // reserved
145        writer.write_u16::<BigEndian>(self.data_reference_index)?;
146
147        writer.write_u64::<BigEndian>(0)?; // reserved
148        writer.write_u16::<BigEndian>(self.channelcount)?;
149        writer.write_u16::<BigEndian>(self.samplesize)?;
150        writer.write_u32::<BigEndian>(0)?; // reserved
151        writer.write_u32::<BigEndian>(self.samplerate.raw_value())?;
152
153        if let Some(ref esds) = self.esds {
154            esds.write_box(writer)?;
155        }
156
157        Ok(size)
158    }
159}
160
161#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
162pub struct EsdsBox {
163    pub version: u8,
164    pub flags: u32,
165    pub es_desc: ESDescriptor,
166}
167
168impl EsdsBox {
169    pub fn new(config: &AacConfig) -> Self {
170        Self {
171            version: 0,
172            flags: 0,
173            es_desc: ESDescriptor::new(config),
174        }
175    }
176}
177
178impl Mp4Box for EsdsBox {
179    fn box_type(&self) -> BoxType {
180        BoxType::EsdsBox
181    }
182
183    fn box_size(&self) -> u64 {
184        HEADER_SIZE
185            + HEADER_EXT_SIZE
186            + 1
187            + size_of_length(ESDescriptor::desc_size()) as u64
188            + ESDescriptor::desc_size() as u64
189    }
190
191    fn to_json(&self) -> Result<String> {
192        Ok(serde_json::to_string(&self).unwrap())
193    }
194
195    fn summary(&self) -> Result<String> {
196        Ok(String::new())
197    }
198}
199
200impl<R: Read + Seek> ReadBox<&mut R> for EsdsBox {
201    fn read_box(reader: &mut R, size: u64) -> Result<Self> {
202        let start = box_start(reader)?;
203
204        let (version, flags) = read_box_header_ext(reader)?;
205
206        let mut es_desc = None;
207
208        let mut current = reader.stream_position()?;
209        let end = start + size;
210        while current < end {
211            let (desc_tag, desc_size) = read_desc(reader)?;
212            match desc_tag {
213                0x03 => {
214                    es_desc = Some(ESDescriptor::read_desc(reader, desc_size)?);
215                }
216                _ => break,
217            }
218            current = reader.stream_position()?;
219        }
220
221        if es_desc.is_none() {
222            return Err(Error::InvalidData("ESDescriptor not found"));
223        }
224
225        skip_bytes_to(reader, start + size)?;
226
227        Ok(EsdsBox {
228            version,
229            flags,
230            es_desc: es_desc.unwrap(),
231        })
232    }
233}
234
235impl<W: Write> WriteBox<&mut W> for EsdsBox {
236    fn write_box(&self, writer: &mut W) -> Result<u64> {
237        let size = self.box_size();
238        BoxHeader::new(self.box_type(), size).write(writer)?;
239
240        write_box_header_ext(writer, self.version, self.flags)?;
241
242        self.es_desc.write_desc(writer)?;
243
244        Ok(size)
245    }
246}
247
248trait Descriptor: Sized {
249    fn desc_tag() -> u8;
250    fn desc_size() -> u32;
251}
252
253trait ReadDesc<T>: Sized {
254    fn read_desc(_: T, size: u32) -> Result<Self>;
255}
256
257trait WriteDesc<T>: Sized {
258    fn write_desc(&self, _: T) -> Result<u32>;
259}
260
261fn read_desc<R: Read>(reader: &mut R) -> Result<(u8, u32)> {
262    let tag = reader.read_u8()?;
263
264    let mut size: u32 = 0;
265    for _ in 0..4 {
266        let b = reader.read_u8()?;
267        size = (size << 7) | (b & 0x7F) as u32;
268        if b & 0x80 == 0 {
269            break;
270        }
271    }
272
273    Ok((tag, size))
274}
275
276fn size_of_length(size: u32) -> u32 {
277    match size {
278        0x0..=0x7F => 1,
279        0x80..=0x3FFF => 2,
280        0x4000..=0x1FFFFF => 3,
281        _ => 4,
282    }
283}
284
285fn write_desc<W: Write>(writer: &mut W, tag: u8, size: u32) -> Result<u64> {
286    writer.write_u8(tag)?;
287
288    if size as u64 > std::u32::MAX as u64 {
289        return Err(Error::InvalidData("invalid descriptor length range"));
290    }
291
292    let nbytes = size_of_length(size);
293
294    for i in 0..nbytes {
295        let mut b = (size >> ((nbytes - i - 1) * 7)) as u8 & 0x7F;
296        if i < nbytes - 1 {
297            b |= 0x80;
298        }
299        writer.write_u8(b)?;
300    }
301
302    Ok(1 + nbytes as u64)
303}
304
305#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
306pub struct ESDescriptor {
307    pub es_id: u16,
308
309    pub dec_config: DecoderConfigDescriptor,
310    pub sl_config: SLConfigDescriptor,
311}
312
313impl ESDescriptor {
314    pub fn new(config: &AacConfig) -> Self {
315        Self {
316            es_id: 1,
317            dec_config: DecoderConfigDescriptor::new(config),
318            sl_config: SLConfigDescriptor::new(),
319        }
320    }
321}
322
323impl Descriptor for ESDescriptor {
324    fn desc_tag() -> u8 {
325        0x03
326    }
327
328    fn desc_size() -> u32 {
329        3 + 1
330            + size_of_length(DecoderConfigDescriptor::desc_size())
331            + DecoderConfigDescriptor::desc_size()
332            + 1
333            + size_of_length(SLConfigDescriptor::desc_size())
334            + SLConfigDescriptor::desc_size()
335    }
336}
337
338impl<R: Read + Seek> ReadDesc<&mut R> for ESDescriptor {
339    fn read_desc(reader: &mut R, size: u32) -> Result<Self> {
340        let start = reader.stream_position()?;
341
342        let es_id = reader.read_u16::<BigEndian>()?;
343        reader.read_u8()?; // XXX flags must be 0
344
345        let mut dec_config = None;
346        let mut sl_config = None;
347
348        let mut current = reader.stream_position()?;
349        let end = start + size as u64;
350        while current < end {
351            let (desc_tag, desc_size) = read_desc(reader)?;
352            match desc_tag {
353                0x04 => {
354                    dec_config = Some(DecoderConfigDescriptor::read_desc(reader, desc_size)?);
355                }
356                0x06 => {
357                    sl_config = Some(SLConfigDescriptor::read_desc(reader, desc_size)?);
358                }
359                _ => {
360                    skip_bytes(reader, desc_size as u64)?;
361                }
362            }
363            current = reader.stream_position()?;
364        }
365
366        Ok(ESDescriptor {
367            es_id,
368            dec_config: dec_config.unwrap_or_default(),
369            sl_config: sl_config.unwrap_or_default(),
370        })
371    }
372}
373
374impl<W: Write> WriteDesc<&mut W> for ESDescriptor {
375    fn write_desc(&self, writer: &mut W) -> Result<u32> {
376        let size = Self::desc_size();
377        write_desc(writer, Self::desc_tag(), size)?;
378
379        writer.write_u16::<BigEndian>(self.es_id)?;
380        writer.write_u8(0)?;
381
382        self.dec_config.write_desc(writer)?;
383        self.sl_config.write_desc(writer)?;
384
385        Ok(size)
386    }
387}
388
389#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
390pub struct DecoderConfigDescriptor {
391    pub object_type_indication: u8,
392    pub stream_type: u8,
393    pub up_stream: u8,
394    pub buffer_size_db: u32,
395    pub max_bitrate: u32,
396    pub avg_bitrate: u32,
397
398    pub dec_specific: DecoderSpecificDescriptor,
399}
400
401impl DecoderConfigDescriptor {
402    pub fn new(config: &AacConfig) -> Self {
403        Self {
404            object_type_indication: 0x40, // XXX AAC
405            stream_type: 0x05,            // XXX Audio
406            up_stream: 0,
407            buffer_size_db: 0,
408            max_bitrate: config.bitrate, // XXX
409            avg_bitrate: config.bitrate,
410            dec_specific: DecoderSpecificDescriptor::new(config),
411        }
412    }
413}
414
415impl Descriptor for DecoderConfigDescriptor {
416    fn desc_tag() -> u8 {
417        0x04
418    }
419
420    fn desc_size() -> u32 {
421        13 + 1
422            + size_of_length(DecoderSpecificDescriptor::desc_size())
423            + DecoderSpecificDescriptor::desc_size()
424    }
425}
426
427impl<R: Read + Seek> ReadDesc<&mut R> for DecoderConfigDescriptor {
428    fn read_desc(reader: &mut R, size: u32) -> Result<Self> {
429        let start = reader.stream_position()?;
430
431        let object_type_indication = reader.read_u8()?;
432        let byte_a = reader.read_u8()?;
433        let stream_type = (byte_a & 0xFC) >> 2;
434        let up_stream = byte_a & 0x02;
435        let buffer_size_db = reader.read_u24::<BigEndian>()?;
436        let max_bitrate = reader.read_u32::<BigEndian>()?;
437        let avg_bitrate = reader.read_u32::<BigEndian>()?;
438
439        let mut dec_specific = None;
440
441        let mut current = reader.stream_position()?;
442        let end = start + size as u64;
443        while current < end {
444            let (desc_tag, desc_size) = read_desc(reader)?;
445            match desc_tag {
446                0x05 => {
447                    dec_specific = Some(DecoderSpecificDescriptor::read_desc(reader, desc_size)?);
448                }
449                _ => {
450                    skip_bytes(reader, desc_size as u64)?;
451                }
452            }
453            current = reader.stream_position()?;
454        }
455
456        Ok(DecoderConfigDescriptor {
457            object_type_indication,
458            stream_type,
459            up_stream,
460            buffer_size_db,
461            max_bitrate,
462            avg_bitrate,
463            dec_specific: dec_specific.unwrap_or_default(),
464        })
465    }
466}
467
468impl<W: Write> WriteDesc<&mut W> for DecoderConfigDescriptor {
469    fn write_desc(&self, writer: &mut W) -> Result<u32> {
470        let size = Self::desc_size();
471        write_desc(writer, Self::desc_tag(), size)?;
472
473        writer.write_u8(self.object_type_indication)?;
474        writer.write_u8((self.stream_type << 2) + (self.up_stream & 0x02) + 1)?; // 1 reserved
475        writer.write_u24::<BigEndian>(self.buffer_size_db)?;
476        writer.write_u32::<BigEndian>(self.max_bitrate)?;
477        writer.write_u32::<BigEndian>(self.avg_bitrate)?;
478
479        self.dec_specific.write_desc(writer)?;
480
481        Ok(size)
482    }
483}
484
485#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
486pub struct DecoderSpecificDescriptor {
487    pub profile: u8,
488    pub freq_index: u8,
489    pub chan_conf: u8,
490}
491
492impl DecoderSpecificDescriptor {
493    pub fn new(config: &AacConfig) -> Self {
494        Self {
495            profile: config.profile as u8,
496            freq_index: config.freq_index as u8,
497            chan_conf: config.chan_conf as u8,
498        }
499    }
500}
501
502impl Descriptor for DecoderSpecificDescriptor {
503    fn desc_tag() -> u8 {
504        0x05
505    }
506
507    fn desc_size() -> u32 {
508        2
509    }
510}
511
512fn get_audio_object_type(byte_a: u8, byte_b: u8) -> u8 {
513    let mut profile = byte_a >> 3;
514    if profile == 31 {
515        profile = 32 + ((byte_a & 7) | (byte_b >> 5));
516    }
517
518    profile
519}
520
521fn get_chan_conf<R: Read + Seek>(
522    reader: &mut R,
523    byte_b: u8,
524    freq_index: u8,
525    extended_profile: bool,
526) -> Result<u8> {
527    let chan_conf;
528    if freq_index == 15 {
529        // Skip the 24 bit sample rate
530        let sample_rate = reader.read_u24::<BigEndian>()?;
531        chan_conf = ((sample_rate >> 4) & 0x0F) as u8;
532    } else if extended_profile {
533        let byte_c = reader.read_u8()?;
534        chan_conf = (byte_b & 1) | (byte_c & 0xE0);
535    } else {
536        chan_conf = (byte_b >> 3) & 0x0F;
537    }
538
539    Ok(chan_conf)
540}
541
542impl<R: Read + Seek> ReadDesc<&mut R> for DecoderSpecificDescriptor {
543    fn read_desc(reader: &mut R, _size: u32) -> Result<Self> {
544        let byte_a = reader.read_u8()?;
545        let byte_b = reader.read_u8()?;
546        let profile = get_audio_object_type(byte_a, byte_b);
547        let freq_index;
548        let chan_conf;
549        if profile > 31 {
550            freq_index = (byte_b >> 1) & 0x0F;
551            chan_conf = get_chan_conf(reader, byte_b, freq_index, true)?;
552        } else {
553            freq_index = ((byte_a & 0x07) << 1) + (byte_b >> 7);
554            chan_conf = get_chan_conf(reader, byte_b, freq_index, false)?;
555        }
556
557        Ok(DecoderSpecificDescriptor {
558            profile,
559            freq_index,
560            chan_conf,
561        })
562    }
563}
564
565impl<W: Write> WriteDesc<&mut W> for DecoderSpecificDescriptor {
566    fn write_desc(&self, writer: &mut W) -> Result<u32> {
567        let size = Self::desc_size();
568        write_desc(writer, Self::desc_tag(), size)?;
569
570        writer.write_u8((self.profile << 3) + (self.freq_index >> 1))?;
571        writer.write_u8((self.freq_index << 7) + (self.chan_conf << 3))?;
572
573        Ok(size)
574    }
575}
576
577#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
578pub struct SLConfigDescriptor {}
579
580impl SLConfigDescriptor {
581    pub fn new() -> Self {
582        SLConfigDescriptor {}
583    }
584}
585
586impl Descriptor for SLConfigDescriptor {
587    fn desc_tag() -> u8 {
588        0x06
589    }
590
591    fn desc_size() -> u32 {
592        1
593    }
594}
595
596impl<R: Read + Seek> ReadDesc<&mut R> for SLConfigDescriptor {
597    fn read_desc(reader: &mut R, _size: u32) -> Result<Self> {
598        reader.read_u8()?; // pre-defined
599
600        Ok(SLConfigDescriptor {})
601    }
602}
603
604impl<W: Write> WriteDesc<&mut W> for SLConfigDescriptor {
605    fn write_desc(&self, writer: &mut W) -> Result<u32> {
606        let size = Self::desc_size();
607        write_desc(writer, Self::desc_tag(), size)?;
608
609        writer.write_u8(2)?; // pre-defined
610        Ok(size)
611    }
612}
613
614#[cfg(test)]
615mod tests {
616    use super::*;
617    use crate::mp4box::BoxHeader;
618    use std::io::Cursor;
619
620    #[test]
621    fn test_mp4a() {
622        let src_box = Mp4aBox {
623            data_reference_index: 1,
624            channelcount: 2,
625            samplesize: 16,
626            samplerate: FixedPointU16::new(48000),
627            esds: Some(EsdsBox {
628                version: 0,
629                flags: 0,
630                es_desc: ESDescriptor {
631                    es_id: 2,
632                    dec_config: DecoderConfigDescriptor {
633                        object_type_indication: 0x40,
634                        stream_type: 0x05,
635                        up_stream: 0,
636                        buffer_size_db: 0,
637                        max_bitrate: 67695,
638                        avg_bitrate: 67695,
639                        dec_specific: DecoderSpecificDescriptor {
640                            profile: 2,
641                            freq_index: 3,
642                            chan_conf: 1,
643                        },
644                    },
645                    sl_config: SLConfigDescriptor::default(),
646                },
647            }),
648        };
649        let mut buf = Vec::new();
650        src_box.write_box(&mut buf).unwrap();
651        assert_eq!(buf.len(), src_box.box_size() as usize);
652
653        let mut reader = Cursor::new(&buf);
654        let header = BoxHeader::read(&mut reader).unwrap();
655        assert_eq!(header.name, BoxType::Mp4aBox);
656        assert_eq!(src_box.box_size(), header.size);
657
658        let dst_box = Mp4aBox::read_box(&mut reader, header.size).unwrap();
659        assert_eq!(src_box, dst_box);
660    }
661
662    #[test]
663    fn test_mp4a_no_esds() {
664        let src_box = Mp4aBox {
665            data_reference_index: 1,
666            channelcount: 2,
667            samplesize: 16,
668            samplerate: FixedPointU16::new(48000),
669            esds: None,
670        };
671        let mut buf = Vec::new();
672        src_box.write_box(&mut buf).unwrap();
673        assert_eq!(buf.len(), src_box.box_size() as usize);
674
675        let mut reader = Cursor::new(&buf);
676        let header = BoxHeader::read(&mut reader).unwrap();
677        assert_eq!(header.name, BoxType::Mp4aBox);
678        assert_eq!(src_box.box_size(), header.size);
679
680        let dst_box = Mp4aBox::read_box(&mut reader, header.size).unwrap();
681        assert_eq!(src_box, dst_box);
682    }
683}