Skip to main content

mp4_atom/moov/trak/mdia/minf/stbl/stsd/
eac3.rs

1use crate::*;
2
3// See ETSI TS 102 366 V1.4.1 (2017-09) for details of AC-3 and EAC-3
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7pub struct Eac3 {
8    pub audio: Audio,
9    pub dec3: Ec3SpecificBox,
10}
11
12impl Atom for Eac3 {
13    const KIND: FourCC = FourCC::new(b"ec-3");
14
15    fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
16        let audio = Audio::decode(buf)?;
17
18        let mut dec3 = None;
19
20        while let Some(atom) = Any::decode_maybe(buf)? {
21            match atom {
22                Any::Ec3SpecificBox(atom) => dec3 = atom.into(),
23                unknown => Self::decode_unknown(&unknown)?,
24            }
25        }
26        skip_trailing_padding(buf);
27
28        Ok(Self {
29            audio,
30            dec3: dec3.ok_or(Error::MissingBox(Ec3SpecificBox::KIND))?,
31        })
32    }
33
34    fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
35        self.audio.encode(buf)?;
36        self.dec3.encode(buf)?;
37        Ok(())
38    }
39}
40
41// EAC-3 specific data
42#[derive(Debug, Clone, PartialEq, Eq)]
43#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
44pub struct Ec3IndependentSubstream {
45    pub fscod: u8,
46    pub bsid: u8,
47    pub asvc: bool,
48    pub bsmod: u8,
49    pub acmod: u8,
50    pub lfeon: bool,
51    pub num_dep_sub: u8,
52    pub chan_loc: Option<u16>,
53}
54
55#[derive(Debug, Clone, PartialEq, Eq)]
56#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
57pub struct Ec3SpecificBox {
58    pub data_rate: u16,
59    pub substreams: Vec<Ec3IndependentSubstream>,
60}
61
62impl Atom for Ec3SpecificBox {
63    const KIND: FourCC = FourCC::new(b"dec3");
64
65    fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
66        let header = u16::decode(buf)?;
67        let data_rate = header >> 3;
68        let num_ind_sub = header & 0b111;
69        let mut substreams = Vec::with_capacity(num_ind_sub as usize + 1);
70        for _ in 0..num_ind_sub + 1 {
71            let b0 = u8::decode(buf)?;
72            let fscod = b0 >> 6;
73            let bsid = (b0 >> 1) & 0b11111;
74            // ignore low bit - reserved
75            let b1 = u8::decode(buf)?;
76            let asvc = (b1 & 0x80) == 0x80;
77            let bsmod = (b1 >> 4) & 0b111;
78            let acmod = (b1 >> 1) & 0b111;
79            let lfeon = (b1 & 0b1) == 0b1;
80            let b2 = u8::decode(buf)?;
81            // ignore next three bits
82            let num_dep_sub = (b2 >> 1) & 0b1111;
83            if num_dep_sub > 0 {
84                let b3 = u8::decode(buf)? as u16;
85                let chan_loc = ((b2 as u16 & 0x01) << 8) | b3;
86                substreams.push(Ec3IndependentSubstream {
87                    fscod,
88                    bsid,
89                    asvc,
90                    bsmod,
91                    acmod,
92                    lfeon,
93                    num_dep_sub,
94                    chan_loc: Some(chan_loc),
95                });
96            } else {
97                // ignore last bit in b2
98                substreams.push(Ec3IndependentSubstream {
99                    fscod,
100                    bsid,
101                    asvc,
102                    bsmod,
103                    acmod,
104                    lfeon,
105                    num_dep_sub,
106                    chan_loc: None,
107                });
108            }
109        }
110
111        // reserved bits may follow
112        buf.advance(buf.remaining());
113        Ok(Self {
114            data_rate,
115            substreams,
116        })
117    }
118
119    fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
120        let header = self.data_rate << 3 | self.substreams.len().saturating_sub(1) as u16;
121        header.encode(buf)?;
122        for substream in &self.substreams {
123            // low bit is reserved = 0
124            let b = (substream.fscod << 6) | (substream.bsid << 1);
125            b.encode(buf)?;
126            let b = (if substream.asvc { 0x80 } else { 0x00 })
127                | (substream.bsmod << 4)
128                | (substream.acmod << 1)
129                | (if substream.lfeon { 0x01 } else { 0x00 });
130            b.encode(buf)?;
131            if substream.num_dep_sub > 0 {
132                let b: u16 =
133                    ((substream.num_dep_sub as u16) << 9) | (substream.chan_loc.unwrap_or(0u16));
134                b.encode(buf)?;
135            } else {
136                // high and low bits are reserved = 0
137                let b = substream.num_dep_sub << 1;
138                b.encode(buf)?;
139            }
140        }
141        Ok(())
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148
149    // EAC-3 metadata block only
150    const ENCODED_EAC3: &[u8] = &[
151        0x00, 0x00, 0x00, 0x31, 0x65, 0x63, 0x2d, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, 0x00,
153        0x00, 0x00, 0xac, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x64, 0x65, 0x63, 0x33, 0x5f,
154        0xc0, 0x60, 0x04, 0x00,
155    ];
156
157    #[test]
158    fn test_eac3_decode() {
159        let buf: &mut std::io::Cursor<&[u8]> = &mut std::io::Cursor::new(ENCODED_EAC3);
160
161        let eac3 = Eac3::decode(buf).expect("failed to decode eac-3");
162
163        assert_eq!(
164            eac3,
165            Eac3 {
166                audio: Audio {
167                    data_reference_index: 1,
168                    channel_count: 2,
169                    sample_size: 16,
170                    sample_rate: 44100.into()
171                },
172                dec3: Ec3SpecificBox {
173                    data_rate: 3064,
174                    substreams: vec![Ec3IndependentSubstream {
175                        fscod: 1,
176                        bsid: 16,
177                        asvc: false,
178                        bsmod: 0,
179                        acmod: 2,
180                        lfeon: false,
181                        num_dep_sub: 0,
182                        chan_loc: None
183                    }]
184                }
185            }
186        );
187    }
188
189    #[test]
190    fn test_eac3_encode() {
191        let eac3 = Eac3 {
192            audio: Audio {
193                data_reference_index: 1,
194                channel_count: 2,
195                sample_size: 16,
196                sample_rate: 44100.into(),
197            },
198            dec3: Ec3SpecificBox {
199                data_rate: 3064,
200                substreams: vec![Ec3IndependentSubstream {
201                    fscod: 1,
202                    bsid: 16,
203                    asvc: false,
204                    bsmod: 0,
205                    acmod: 2,
206                    lfeon: false,
207                    num_dep_sub: 0,
208                    chan_loc: None,
209                }],
210            },
211        };
212
213        let mut buf = Vec::new();
214        eac3.encode(&mut buf).unwrap();
215
216        assert_eq!(buf.as_slice(), ENCODED_EAC3);
217    }
218
219    #[test]
220    fn test_eac3_with_dependent_substreams() {
221        // Test case with dependent substreams (num_dep_sub > 0)
222        let eac3 = Eac3 {
223            audio: Audio {
224                data_reference_index: 1,
225                channel_count: 6,
226                sample_size: 16,
227                sample_rate: 48000.into(),
228            },
229            dec3: Ec3SpecificBox {
230                data_rate: 768,
231                substreams: vec![Ec3IndependentSubstream {
232                    fscod: 0, // 48 kHz
233                    bsid: 16,
234                    asvc: true,
235                    bsmod: 1,
236                    acmod: 7, // 3/2 (L, C, R, Ls, Rs)
237                    lfeon: true,
238                    num_dep_sub: 2,
239                    chan_loc: Some(0x1FF),
240                }],
241            },
242        };
243
244        // Encode
245        let mut buf = Vec::new();
246        eac3.encode(&mut buf).unwrap();
247
248        // Decode and verify round-trip
249        let mut cursor = std::io::Cursor::new(&buf);
250        let decoded = Eac3::decode(&mut cursor).expect("failed to decode eac-3");
251
252        assert_eq!(decoded, eac3);
253        assert_eq!(decoded.dec3.substreams[0].chan_loc, Some(0x1FF));
254    }
255
256    #[test]
257    fn test_eac3_multiple_substreams() {
258        // Test case with multiple independent substreams
259        let eac3 = Eac3 {
260            audio: Audio {
261                data_reference_index: 1,
262                channel_count: 8,
263                sample_size: 16,
264                sample_rate: 48000.into(),
265            },
266            dec3: Ec3SpecificBox {
267                data_rate: 1536,
268                substreams: vec![
269                    Ec3IndependentSubstream {
270                        fscod: 0, // 48 kHz
271                        bsid: 16,
272                        asvc: false,
273                        bsmod: 0,
274                        acmod: 7, // 3/2
275                        lfeon: true,
276                        num_dep_sub: 0,
277                        chan_loc: None,
278                    },
279                    Ec3IndependentSubstream {
280                        fscod: 0, // 48 kHz
281                        bsid: 16,
282                        asvc: false,
283                        bsmod: 0,
284                        acmod: 2, // 2/0 (L, R)
285                        lfeon: false,
286                        num_dep_sub: 0,
287                        chan_loc: None,
288                    },
289                ],
290            },
291        };
292
293        // Encode
294        let mut buf = Vec::new();
295        eac3.encode(&mut buf).unwrap();
296
297        // Decode and verify round-trip
298        let mut cursor = std::io::Cursor::new(&buf);
299        let decoded = Eac3::decode(&mut cursor).expect("failed to decode eac-3");
300
301        assert_eq!(decoded, eac3);
302        assert_eq!(decoded.dec3.substreams.len(), 2);
303    }
304
305    #[test]
306    fn test_eac3_with_reserved_bits() {
307        // Test case with reserved bits following the substream data
308        // This simulates a dec3 box with extra padding/reserved bits at the end
309        let encoded_with_reserved: &[u8] = &[
310            0x00, 0x00, 0x00, 0x33, 0x65, 0x63, 0x2d, 0x33, // ec-3 atom header (size=51)
311            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // audio sample entry
312            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // audio sample entry
313            0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, // audio sample entry
314            0xac, 0x44, 0x00, 0x00, // audio sample entry
315            0x00, 0x00, 0x00, 0x0f, 0x64, 0x65, 0x63, 0x33, // dec3 header (size 15 bytes)
316            0x5f, 0xc0, // header: data_rate=3064, num_ind_sub=0
317            0x60, 0x04, 0x00, // substream data
318            0xAB, 0xCD, // extra reserved bits (2 bytes)
319        ];
320
321        let mut cursor = std::io::Cursor::new(encoded_with_reserved);
322        let decoded = Eac3::decode(&mut cursor).expect("failed to decode eac-3 with reserved bits");
323
324        // Should decode successfully and ignore the reserved bits
325        assert_eq!(
326            decoded,
327            Eac3 {
328                audio: Audio {
329                    data_reference_index: 1,
330                    channel_count: 2,
331                    sample_size: 16,
332                    sample_rate: 44100.into()
333                },
334                dec3: Ec3SpecificBox {
335                    data_rate: 3064,
336                    substreams: vec![Ec3IndependentSubstream {
337                        fscod: 1,
338                        bsid: 16,
339                        asvc: false,
340                        bsmod: 0,
341                        acmod: 2,
342                        lfeon: false,
343                        num_dep_sub: 0,
344                        chan_loc: None
345                    }]
346                }
347            }
348        );
349    }
350}