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

1use crate::*;
2
3ext! {
4    name: PcmC,
5    versions: [0],
6    flags: {}
7}
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct PcmC {
12    pub big_endian: bool,
13    pub sample_size: u8,
14}
15
16impl AtomExt for PcmC {
17    const KIND_EXT: FourCC = FourCC::new(b"pcmC");
18
19    type Ext = PcmCExt;
20
21    fn decode_body_ext<B: Buf>(buf: &mut B, _ext: PcmCExt) -> Result<Self> {
22        let format_flags = u8::decode(buf)?;
23        let sample_size = u8::decode(buf)?;
24
25        Ok(Self {
26            big_endian: format_flags == 0,
27            sample_size,
28        })
29    }
30
31    fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<PcmCExt> {
32        let mut format_flags = 0u8;
33        if !self.big_endian {
34            format_flags = 1u8;
35        }
36
37        format_flags.encode(buf)?;
38        self.sample_size.encode(buf)?;
39
40        Ok(PcmCExt {
41            version: PcmCVersion::V0,
42        })
43    }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
48pub struct Pcm {
49    pub fourcc: FourCC,
50    pub audio: Audio,
51    pub pcmc: PcmC,
52    pub chnl: Option<Chnl>,
53    pub btrt: Option<Btrt>,
54}
55
56impl Pcm {
57    fn encode_fields<B: BufMut>(
58        audio: &Audio,
59        pcmc: &PcmC,
60        chnl: Option<&Chnl>,
61        btrt: Option<&Btrt>,
62        buf: &mut B,
63    ) -> Result<()> {
64        audio.encode(buf)?;
65        pcmc.encode(buf)?;
66
67        if let Some(chnl) = chnl {
68            chnl.encode(buf)?;
69        }
70
71        if let Some(btrt) = btrt {
72            btrt.encode(buf)?;
73        }
74
75        Ok(())
76    }
77
78    pub fn decode_with_fourcc<B: Buf>(fourcc: FourCC, buf: &mut B) -> Result<Self> {
79        let audio = Audio::decode(buf)?;
80
81        let mut chnl = None;
82        let mut pcmc = None;
83        let mut btrt = None;
84
85        while buf.remaining() > 0 {
86            let header = match Header::decode_maybe(buf)? {
87                Some(h) => h,
88                None => break,
89            };
90
91            let size = header.size.unwrap_or(buf.remaining());
92            if size > buf.remaining() {
93                break;
94            }
95
96            let mut limited = buf.slice(size);
97
98            if header.kind == Chnl::KIND {
99                // Decode channel layout by using the channel count
100                // information. We cannot rely on the decode_body
101                // implementation of Atom for channel layout box.
102                chnl = Some(Chnl::decode_body_with_channel_count(
103                    &mut limited,
104                    audio.channel_count,
105                )?);
106            } else {
107                match Any::decode_atom(&header, &mut limited)? {
108                    Any::PcmC(atom) => pcmc = Some(atom),
109                    Any::Btrt(atom) => btrt = Some(atom),
110                    atom => crate::decode_unknown(&atom, fourcc)?,
111                }
112            }
113
114            buf.advance(size);
115        }
116
117        Ok(Self {
118            fourcc,
119            audio,
120            pcmc: pcmc.ok_or(Error::MissingBox(PcmC::KIND))?,
121            chnl,
122            btrt,
123        })
124    }
125
126    pub fn encode_with_fourcc<B: BufMut>(&self, buf: &mut B) -> Result<()> {
127        Self::encode_fields(
128            &self.audio,
129            &self.pcmc,
130            self.chnl.as_ref(),
131            self.btrt.as_ref(),
132            buf,
133        )
134    }
135}
136
137macro_rules! define_pcm_sample_entry {
138    ($name:ident, $fourcc:expr) => {
139        #[derive(Debug, Clone, PartialEq, Eq)]
140        #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
141        pub struct $name {
142            pub audio: Audio,
143            pub pcmc: PcmC,
144            pub chnl: Option<Chnl>,
145            pub btrt: Option<Btrt>,
146        }
147
148        impl Atom for $name {
149            const KIND: FourCC = FourCC::new($fourcc);
150
151            fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
152                let entry = Pcm::decode_with_fourcc(Self::KIND, buf)?;
153                Ok(Self {
154                    audio: entry.audio,
155                    pcmc: entry.pcmc,
156                    chnl: entry.chnl,
157                    btrt: entry.btrt,
158                })
159            }
160
161            fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
162                Pcm::encode_fields(
163                    &self.audio,
164                    &self.pcmc,
165                    self.chnl.as_ref(),
166                    self.btrt.as_ref(),
167                    buf,
168                )
169            }
170        }
171    };
172}
173
174define_pcm_sample_entry!(Sowt, b"sowt");
175define_pcm_sample_entry!(Twos, b"twos");
176define_pcm_sample_entry!(Lpcm, b"lpcm");
177define_pcm_sample_entry!(Ipcm, b"ipcm");
178define_pcm_sample_entry!(Fpcm, b"fpcm");
179define_pcm_sample_entry!(In24, b"in24");
180define_pcm_sample_entry!(In32, b"in32");
181define_pcm_sample_entry!(Fl32, b"fl32");
182define_pcm_sample_entry!(Fl64, b"fl64");
183define_pcm_sample_entry!(S16l, b"s16l");
184
185#[cfg(test)]
186mod tests {
187    use super::*;
188
189    #[test]
190    fn test_pcmc_encode_decode() {
191        let pcmc = PcmC {
192            big_endian: true,
193            sample_size: 16,
194        };
195
196        let mut buf = Vec::new();
197        pcmc.encode(&mut buf).unwrap();
198
199        let decoded = PcmC::decode(&mut &buf[..]).unwrap();
200        assert_eq!(pcmc, decoded);
201    }
202
203    #[test]
204    fn test_pcm_encode_decode() {
205        let pcmc = PcmC {
206            big_endian: false,
207            sample_size: 16,
208        };
209        let chnl = Chnl {
210            channel_structure: Some(ChannelStructure::DefinedLayout {
211                layout: 2, // Stereo
212                omitted_channels_map: Some(0),
213                channel_order_definition: None,
214            }),
215            object_count: None,
216            format_ordering: None,
217            base_channel_count: None,
218        };
219        let pcm = Pcm {
220            fourcc: FourCC::new(b"fpcm"),
221            audio: Audio {
222                data_reference_index: 1,
223                channel_count: 2,
224                sample_size: 16,
225                sample_rate: 48000.into(),
226            },
227            pcmc,
228            chnl: Some(chnl),
229            btrt: None,
230        };
231
232        let mut buf = Vec::new();
233        pcm.encode_with_fourcc(&mut buf).unwrap();
234
235        let decoded = Pcm::decode_with_fourcc(FourCC::new(b"fpcm"), &mut &buf[..]).unwrap();
236        assert_eq!(pcm, decoded);
237    }
238
239    #[test]
240    fn test_pcm_encode_decode_with_both_channel_and_object() {
241        let pcmc = PcmC {
242            big_endian: true,
243            sample_size: 16,
244        };
245        let chnl = Chnl {
246            channel_structure: Some(ChannelStructure::DefinedLayout {
247                layout: 2, // Stereo
248                omitted_channels_map: Some(0),
249                channel_order_definition: None,
250            }),
251            object_count: Some(2),
252            format_ordering: None,
253            base_channel_count: None,
254        };
255        let pcm = Pcm {
256            fourcc: FourCC::new(b"ipcm"),
257            audio: Audio {
258                data_reference_index: 1,
259                channel_count: 2,
260                sample_size: 16,
261                sample_rate: 48000.into(),
262            },
263            pcmc,
264            chnl: Some(chnl),
265            btrt: None,
266        };
267
268        let mut buf = Vec::new();
269        pcm.encode_with_fourcc(&mut buf).unwrap();
270
271        let decoded = Pcm::decode_with_fourcc(FourCC::new(b"ipcm"), &mut &buf[..]).unwrap();
272        assert_eq!(pcm, decoded);
273    }
274
275    #[test]
276    fn test_pcm_encode_decode_with_both_channel_and_object_explicit_position() {
277        let pcmc = PcmC {
278            big_endian: true,
279            sample_size: 16,
280        };
281        let chnl = Chnl {
282            channel_structure: Some(ChannelStructure::ExplicitPositions {
283                positions: vec![
284                    SpeakerPosition::Standard(AudioChannelPosition::FrontLeft),
285                    SpeakerPosition::Standard(AudioChannelPosition::FrontRight),
286                ],
287            }),
288            object_count: Some(2),
289            format_ordering: None,
290            base_channel_count: None,
291        };
292        let pcm = Pcm {
293            fourcc: FourCC::new(b"fpcm"),
294            audio: Audio {
295                data_reference_index: 1,
296                channel_count: 2,
297                sample_size: 16,
298                sample_rate: 48000.into(),
299            },
300            pcmc,
301            chnl: Some(chnl),
302            btrt: Some(Btrt {
303                buffer_size_db: 6,
304                max_bitrate: 2_304_096,
305                avg_bitrate: 2_304_000,
306            }),
307        };
308
309        let mut buf = Vec::new();
310        pcm.encode_with_fourcc(&mut buf).unwrap();
311
312        let decoded = Pcm::decode_with_fourcc(FourCC::new(b"fpcm"), &mut &buf[..]).unwrap();
313        assert_eq!(pcm, decoded);
314    }
315
316    #[test]
317    fn test_pcm_encode_decode_with_chnl_explicit_positions() {
318        let pcmc = PcmC {
319            big_endian: true,
320            sample_size: 16,
321        };
322        let chnl = Chnl {
323            channel_structure: Some(ChannelStructure::ExplicitPositions {
324                positions: vec![
325                    SpeakerPosition::Standard(AudioChannelPosition::FrontLeft),
326                    SpeakerPosition::Standard(AudioChannelPosition::FrontRight),
327                ],
328            }),
329            object_count: None,
330            format_ordering: None,
331            base_channel_count: None,
332        };
333        let pcm = Pcm {
334            fourcc: FourCC::new(b"fpcm"),
335            audio: Audio {
336                data_reference_index: 1,
337                channel_count: 2,
338                sample_size: 16,
339                sample_rate: 48000.into(),
340            },
341            pcmc,
342            chnl: Some(chnl),
343            btrt: None,
344        };
345
346        let mut buf = Vec::new();
347        pcm.encode_with_fourcc(&mut buf).unwrap();
348
349        let decoded = Pcm::decode_with_fourcc(FourCC::new(b"fpcm"), &mut &buf[..]).unwrap();
350        assert_eq!(pcm, decoded);
351    }
352
353    #[test]
354    fn test_pcm_encode_decode_with_chnl_explicit_speaker_position() {
355        let pcmc = PcmC {
356            big_endian: true,
357            sample_size: 16,
358        };
359        let chnl = Chnl {
360            channel_structure: Some(ChannelStructure::ExplicitPositions {
361                positions: vec![
362                    SpeakerPosition::Standard(AudioChannelPosition::FrontLeft),
363                    SpeakerPosition::Explicit(ExplicitSpeakerPosition {
364                        azimuth: 45,
365                        elevation: 10,
366                    }),
367                ],
368            }),
369            object_count: None,
370            format_ordering: None,
371            base_channel_count: None,
372        };
373        let pcm = Pcm {
374            fourcc: FourCC::new(b"fpcm"),
375            audio: Audio {
376                data_reference_index: 1,
377                channel_count: 2,
378                sample_size: 16,
379                sample_rate: 48000.into(),
380            },
381            pcmc,
382            chnl: Some(chnl),
383            btrt: None,
384        };
385
386        let mut buf = Vec::new();
387        pcm.encode_with_fourcc(&mut buf).unwrap();
388
389        let decoded = Pcm::decode_with_fourcc(FourCC::new(b"fpcm"), &mut &buf[..]).unwrap();
390        assert_eq!(pcm, decoded);
391    }
392
393    #[test]
394    fn test_pcm_v1_chnl() {
395        let pcmc = PcmC {
396            big_endian: false,
397            sample_size: 24,
398        };
399        let chnl = Chnl {
400            channel_structure: Some(ChannelStructure::ExplicitPositions {
401                positions: vec![
402                    SpeakerPosition::Standard(AudioChannelPosition::FrontLeft),
403                    SpeakerPosition::Standard(AudioChannelPosition::FrontRight),
404                ],
405            }),
406            object_count: Some(1),
407            format_ordering: Some(1),
408            base_channel_count: Some(3),
409        };
410        let pcm = Lpcm {
411            audio: Audio {
412                data_reference_index: 1,
413                channel_count: 2,
414                sample_size: 24,
415                sample_rate: 48000.into(),
416            },
417            pcmc,
418            chnl: Some(chnl),
419            btrt: None,
420        };
421
422        let mut buf = Vec::new();
423        pcm.encode(&mut buf).unwrap();
424
425        let decoded = Lpcm::decode(&mut &buf[..]).unwrap();
426        assert_eq!(pcm, decoded);
427    }
428
429    const ENCODED_IPCM: &[u8] = &[
430        0x00, 0x00, 0x00, 0x5c, 0x69, 0x70, 0x63, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
431        0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x18, 0x00, 0x00,
432        0x00, 0x00, 0xbb, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x70, 0x63, 0x6d, 0x43, 0x00,
433        0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x16, 0x63, 0x68, 0x6e, 0x6c, 0x00, 0x00,
434        0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
435        0x14, 0x62, 0x74, 0x72, 0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x23, 0x28, 0x60, 0x00, 0x23,
436        0x28, 0x00,
437    ];
438
439    fn decoded_ipcm() -> Ipcm {
440        Ipcm {
441            audio: Audio {
442                data_reference_index: 1,
443                channel_count: 2,
444                sample_size: 24,
445                sample_rate: FixedPoint::new(48000, 0),
446            },
447            pcmc: PcmC {
448                big_endian: true,
449                sample_size: 24,
450            },
451            chnl: Some(Chnl {
452                channel_structure: Some(ChannelStructure::DefinedLayout {
453                    layout: 2,
454                    omitted_channels_map: Some(0),
455                    channel_order_definition: None,
456                }),
457                object_count: None,
458                format_ordering: None,
459                base_channel_count: None,
460            }),
461            btrt: Some(Btrt {
462                buffer_size_db: 6,
463                max_bitrate: 2_304_096,
464                avg_bitrate: 2_304_000,
465            }),
466        }
467    }
468
469    #[test]
470    fn test_ipcm_decode() {
471        let buf = &mut std::io::Cursor::new(ENCODED_IPCM);
472        let ipcm = Ipcm::decode(buf).expect("failed to decode ipcm");
473        assert_eq!(ipcm, decoded_ipcm());
474    }
475
476    #[test]
477    fn test_ipcm_encode() {
478        let ipcm = decoded_ipcm();
479        let mut buf = Vec::new();
480        ipcm.encode(&mut buf).unwrap();
481        assert_eq!(buf.as_slice(), ENCODED_IPCM);
482    }
483}