creek_decode_symphonia/
lib.rs

1#![warn(rust_2018_idioms)]
2#![warn(rust_2021_compatibility)]
3#![warn(clippy::missing_panics_doc)]
4#![warn(clippy::clone_on_ref_ptr)]
5#![deny(trivial_numeric_casts)]
6#![forbid(unsafe_code)]
7
8use std::fs::File;
9use std::path::PathBuf;
10
11use symphonia::core::audio::AudioBuffer;
12use symphonia::core::codecs::{CodecParameters, Decoder as SymphDecoder, DecoderOptions};
13use symphonia::core::errors::Error;
14use symphonia::core::formats::{FormatOptions, FormatReader, SeekMode, SeekTo};
15use symphonia::core::io::MediaSourceStream;
16use symphonia::core::meta::{Metadata, MetadataOptions, MetadataRevision};
17use symphonia::core::probe::Hint;
18
19use creek_core::{DataBlock, Decoder, FileInfo};
20
21mod error;
22pub use error::OpenError;
23
24pub struct SymphoniaDecoder {
25    reader: Box<dyn FormatReader>,
26    decoder: Box<dyn SymphDecoder>,
27
28    decode_buffer: AudioBuffer<f32>,
29    decode_buffer_len: usize,
30    curr_decode_buffer_frame: usize,
31
32    num_frames: usize,
33    sample_rate: Option<u32>,
34    block_size: usize,
35
36    playhead_frame: usize,
37    reset_decode_buffer: bool,
38    seek_diff: usize,
39}
40
41impl Decoder for SymphoniaDecoder {
42    type T = f32;
43    type FileParams = SymphoniaDecoderInfo;
44    type OpenError = OpenError;
45    type FatalError = Error;
46    type AdditionalOpts = ();
47
48    const DEFAULT_BLOCK_SIZE: usize = 16384;
49    const DEFAULT_NUM_CACHE_BLOCKS: usize = 0;
50    const DEFAULT_NUM_LOOK_AHEAD_BLOCKS: usize = 8;
51
52    fn new(
53        file: PathBuf,
54        start_frame: usize,
55        block_size: usize,
56        _additional_opts: Self::AdditionalOpts,
57    ) -> Result<(Self, FileInfo<Self::FileParams>), Self::OpenError> {
58        // Create a hint to help the format registry guess what format reader is appropriate.
59        let mut hint = Hint::new();
60
61        // Provide the file extension as a hint.
62        if let Some(extension) = file.extension() {
63            if let Some(extension_str) = extension.to_str() {
64                hint.with_extension(extension_str);
65            }
66        }
67
68        let source = Box::new(File::open(file)?);
69
70        // Create the media source stream using the boxed media source from above.
71        let mss = MediaSourceStream::new(source, Default::default());
72
73        // Use the default options for metadata and format readers.
74        let format_opts: FormatOptions = Default::default();
75        let metadata_opts: MetadataOptions = Default::default();
76
77        let probed =
78            symphonia::default::get_probe().format(&hint, mss, &format_opts, &metadata_opts)?;
79
80        let mut reader = probed.format;
81
82        let decoder_opts = DecoderOptions {
83            ..Default::default()
84        };
85
86        let params = {
87            // Get the default stream.
88            let stream = reader.default_track().ok_or(OpenError::NoDefaultTrack)?;
89
90            stream.codec_params.clone()
91        };
92        let num_frames = params.n_frames.ok_or(OpenError::NoNumFrames)? as usize;
93        let sample_rate = params.sample_rate;
94
95        // Seek the reader to the requested position.
96        if start_frame != 0 {
97            reader.seek(
98                SeekMode::Accurate,
99                SeekTo::Time {
100                    time: frame_to_symphonia_time(start_frame as u64, sample_rate.unwrap_or(44100)),
101                    track_id: None,
102                },
103            )?;
104        }
105
106        // Create a decoder for the stream.
107        let mut decoder = symphonia::default::get_codecs().make(&params, &decoder_opts)?;
108        debug_assert_eq!(params.n_frames, decoder.codec_params().n_frames);
109        debug_assert_eq!(params.sample_rate, decoder.codec_params().sample_rate);
110        debug_assert_eq!(params.channels, decoder.codec_params().channels);
111
112        // The stream/decoder might not always provide the actual numbers
113        // of channels (MP4/AAC/ALAC). In this case the number of channels
114        // will be obtained from the signal spec of the first decoded packet.
115        let mut channels = params.channels;
116
117        // Decode the first packet to get the signal specification.
118        let (decode_buffer, decode_buffer_len) = loop {
119            match decoder.decode(&reader.next_packet()?) {
120                Ok(decoded) => {
121                    // Get the buffer spec.
122                    let spec = *decoded.spec();
123                    if let Some(channels) = channels {
124                        assert_eq!(channels, spec.channels);
125                    } else {
126                        log::debug!(
127                            "Assuming {num_channels} channel(s) according to the first decoded packet",
128                            num_channels = spec.channels.count()
129                        );
130                        channels = Some(spec.channels);
131                    }
132
133                    let len = decoded.frames();
134                    let capacity = decoded.capacity();
135
136                    let mut decode_buffer: AudioBuffer<f32> =
137                        AudioBuffer::new(capacity as u64, spec);
138
139                    decoded.convert(&mut decode_buffer);
140
141                    break (decode_buffer, len);
142                }
143                Err(Error::DecodeError(err)) => {
144                    // Decode errors are not fatal.
145                    log::warn!("{err}");
146                    // Continue by decoding the next packet.
147                    continue;
148                }
149                Err(e) => {
150                    // Errors other than decode errors are fatal.
151                    return Err(e.into());
152                }
153            }
154        };
155
156        let metadata = reader.metadata().skip_to_latest().cloned();
157        let info = SymphoniaDecoderInfo {
158            codec_params: params,
159            metadata,
160        };
161        let num_channels = (channels.ok_or(OpenError::NoNumChannels)?).count();
162
163        let file_info = FileInfo {
164            params: info,
165            num_frames,
166            num_channels: num_channels as u16,
167            sample_rate,
168        };
169        Ok((
170            Self {
171                reader,
172                decoder,
173
174                decode_buffer,
175                decode_buffer_len,
176                curr_decode_buffer_frame: 0,
177
178                num_frames,
179                sample_rate,
180                block_size,
181
182                playhead_frame: start_frame,
183                reset_decode_buffer: false,
184                seek_diff: 0,
185            },
186            file_info,
187        ))
188    }
189
190    fn seek(&mut self, frame: usize) -> Result<(), Self::FatalError> {
191        if frame >= self.num_frames {
192            // Do nothing if out of range.
193            self.playhead_frame = self.num_frames;
194
195            return Ok(());
196        }
197
198        self.playhead_frame = frame;
199
200        match self.reader.seek(
201            SeekMode::Accurate,
202            SeekTo::Time {
203                time: frame_to_symphonia_time(
204                    self.playhead_frame as u64,
205                    self.sample_rate.unwrap_or(44100),
206                ),
207                track_id: None,
208            },
209        ) {
210            Ok(res) => {
211                // this is always correct for `SeekMode::Accurate`, it may not be for `SeekMode::Coarse`
212                debug_assert!(res.required_ts >= res.actual_ts);
213
214                self.seek_diff = (res.required_ts - res.actual_ts) as usize;
215            }
216            Err(e) => {
217                return Err(e);
218            }
219        }
220
221        self.reset_decode_buffer = true;
222        self.curr_decode_buffer_frame = 0;
223
224        /*
225        let decoder_opts = DecoderOptions {
226            verify: false,
227            ..Default::default()
228        };
229
230        self.decoder.close();
231        self.decoder = symphonia::default::get_codecs()
232            .make(self.decoder.codec_params(), &decoder_opts)?;
233            */
234
235        Ok(())
236    }
237
238    fn decode(&mut self, data_block: &mut DataBlock<Self::T>) -> Result<(), Self::FatalError> {
239        if self.playhead_frame >= self.num_frames {
240            // Do nothing if reached the end of the file.
241            return Ok(());
242        }
243
244        let mut reached_end_of_file = false;
245
246        let mut block_start_frame = 0;
247        while block_start_frame < self.block_size {
248            let num_frames_to_cpy = if self.reset_decode_buffer {
249                // Get new data first.
250                self.reset_decode_buffer = false;
251                0
252            } else {
253                // Find the maximum amount of frames that can be copied.
254                (self.block_size - block_start_frame)
255                    .min(self.decode_buffer_len - self.curr_decode_buffer_frame)
256            };
257
258            if num_frames_to_cpy != 0 {
259                let src_planes = self.decode_buffer.planes();
260                let src_channels = src_planes.planes();
261
262                for (dst_ch, src_ch) in data_block.block.iter_mut().zip(src_channels) {
263                    let src_ch_part = &src_ch[self.curr_decode_buffer_frame
264                        ..self.curr_decode_buffer_frame + num_frames_to_cpy];
265                    dst_ch.extend_from_slice(src_ch_part);
266                }
267
268                block_start_frame += num_frames_to_cpy;
269
270                self.curr_decode_buffer_frame += num_frames_to_cpy;
271                if self.curr_decode_buffer_frame >= self.decode_buffer_len {
272                    self.reset_decode_buffer = true;
273                }
274            } else {
275                // Decode the next packet.
276
277                loop {
278                    match self.reader.next_packet() {
279                        Ok(packet) => {
280                            match self.decoder.decode(&packet) {
281                                Ok(decoded) => {
282                                    self.decode_buffer_len = decoded.frames();
283                                    if self.seek_diff < self.decode_buffer_len {
284                                        let capacity = decoded.capacity();
285                                        if self.decode_buffer.capacity() < capacity {
286                                            self.decode_buffer =
287                                                AudioBuffer::new(capacity as u64, *decoded.spec());
288                                        }
289                                        decoded.convert(&mut self.decode_buffer);
290                                        self.curr_decode_buffer_frame = self.seek_diff;
291                                        self.seek_diff = 0;
292                                        break;
293                                    } else {
294                                        self.seek_diff -= self.decode_buffer_len;
295                                    }
296                                }
297                                Err(Error::DecodeError(err)) => {
298                                    // Decode errors are not fatal.
299                                    log::warn!("{err}");
300                                    // Continue by decoding the next packet.
301                                    continue;
302                                }
303                                Err(e) => {
304                                    // Errors other than decode errors are fatal.
305                                    return Err(e);
306                                }
307                            }
308                        }
309                        Err(e) => {
310                            if let Error::IoError(io_error) = &e {
311                                if io_error.kind() == std::io::ErrorKind::UnexpectedEof {
312                                    // End of file, stop decoding.
313                                    reached_end_of_file = true;
314                                    block_start_frame = self.block_size;
315                                    break;
316                                } else {
317                                    return Err(e);
318                                }
319                            } else {
320                                return Err(e);
321                            }
322                        }
323                    }
324                }
325            }
326        }
327
328        if reached_end_of_file {
329            self.playhead_frame = self.num_frames;
330        } else {
331            self.playhead_frame += self.block_size;
332        }
333
334        Ok(())
335    }
336
337    fn current_frame(&self) -> usize {
338        self.playhead_frame
339    }
340}
341
342impl Drop for SymphoniaDecoder {
343    fn drop(&mut self) {
344        let _ = self.decoder.finalize();
345    }
346}
347
348impl SymphoniaDecoder {
349    /// Symphonia does metadata oddly. This is more for raw access.
350    ///
351    /// See [`Metadata`](https://docs.rs/symphonia-core/0.5.2/symphonia_core/meta/struct.Metadata.html).
352    pub fn get_metadata_raw(&mut self) -> Metadata<'_> {
353        self.reader.metadata()
354    }
355
356    /// Get the latest entry in the metadata.
357    pub fn get_metadata(&mut self) -> Option<MetadataRevision> {
358        let mut md = self.reader.metadata();
359        md.skip_to_latest().cloned()
360    }
361}
362
363#[derive(Debug, Clone)]
364pub struct SymphoniaDecoderInfo {
365    pub codec_params: CodecParameters,
366    pub metadata: Option<MetadataRevision>,
367}
368
369fn frame_to_symphonia_time(frame: u64, sample_rate: u32) -> symphonia::core::units::Time {
370    // Doing it this way is more accurate for large inputs than just using f64s.
371    let seconds = frame / u64::from(sample_rate);
372    let fract_frames = frame % u64::from(sample_rate);
373    let frac = fract_frames as f64 / f64::from(sample_rate);
374
375    // TODO: Ask the maintainer of Symphonia to add an option to seek to an
376    // exact frame.
377    symphonia::core::units::Time { seconds, frac }
378}
379
380#[cfg(test)]
381mod tests {
382    use super::*;
383    use float_cmp::*;
384
385    #[test]
386    fn decoder_new() {
387        let files = vec![
388            //  file | num_channels | num_frames | sample_rate
389            ("../test_files/wav_u8_mono.wav", 1, 1323000, Some(44100)),
390            ("../test_files/wav_i16_mono.wav", 1, 1323000, Some(44100)),
391            ("../test_files/wav_i24_mono.wav", 1, 1323000, Some(44100)),
392            ("../test_files/wav_i32_mono.wav", 1, 1323000, Some(44100)),
393            ("../test_files/wav_f32_mono.wav", 1, 1323000, Some(44100)),
394            ("../test_files/wav_i24_stereo.wav", 2, 1323000, Some(44100)),
395            //"../test_files/ogg_mono.ogg",
396            //"../test_files/ogg_stereo.ogg",
397            //"../test_files/mp3_constant_mono.mp3",
398            //"../test_files/mp3_constant_stereo.mp3",
399            //"../test_files/mp3_variable_mono.mp3",
400            //"../test_files/mp3_variable_stereo.mp3",
401        ];
402
403        for file in files {
404            dbg!(file.0);
405            let decoder =
406                SymphoniaDecoder::new(file.0.into(), 0, SymphoniaDecoder::DEFAULT_BLOCK_SIZE, ());
407            match decoder {
408                Ok((_, file_info)) => {
409                    assert_eq!(file_info.num_channels, file.1);
410                    assert_eq!(file_info.num_frames, file.2);
411                    //assert_eq!(file_info.sample_rate, file.3);
412                }
413                Err(e) => {
414                    panic!("{}", e);
415                }
416            }
417        }
418    }
419
420    #[test]
421    fn decode_first_frame() {
422        let block_size = 10;
423
424        let decoder =
425            SymphoniaDecoder::new("../test_files/wav_u8_mono.wav".into(), 0, block_size, ());
426
427        let (mut decoder, file_info) = decoder.unwrap();
428
429        let mut data_block = DataBlock::new(1, block_size);
430        data_block.clear();
431        decoder.decode(&mut data_block).unwrap();
432
433        let samples = &mut data_block.block[0];
434        assert_eq!(samples.len(), block_size);
435
436        let first_frame = [
437            0.0, 0.046875, 0.09375, 0.1484375, 0.1953125, 0.2421875, 0.2890625, 0.3359375,
438            0.3828125, 0.421875,
439        ];
440
441        for i in 0..samples.len() {
442            assert!(approx_eq!(f32, first_frame[i], samples[i], ulps = 2));
443        }
444
445        let second_frame = [
446            0.46875, 0.5078125, 0.5390625, 0.578125, 0.609375, 0.640625, 0.671875, 0.6953125,
447            0.71875, 0.7421875,
448        ];
449
450        data_block.clear();
451        decoder.decode(&mut data_block).unwrap();
452
453        let samples = &mut data_block.block[0];
454        for i in 0..samples.len() {
455            assert_approx_eq!(f32, second_frame[i], samples[i], ulps = 2);
456        }
457
458        let last_frame = [
459            -0.0859375, -0.09375, -0.1015625, -0.1015625, -0.1015625, -0.09375, -0.0859375,
460            -0.078125, -0.0625, -0.046875,
461        ];
462
463        // Seek to last frame
464        decoder.seek(file_info.num_frames - 1 - block_size).unwrap();
465
466        data_block.clear();
467        decoder.decode(&mut data_block).unwrap();
468
469        let samples = &mut data_block.block[0];
470        for i in 0..samples.len() {
471            assert_approx_eq!(f32, last_frame[i], samples[i], ulps = 2);
472        }
473
474        assert_eq!(decoder.playhead_frame, file_info.num_frames - 1);
475    }
476}