vpr_audio_analyzer/analyzer/
mod.rs

1mod test;
2
3use std::{fs::File, io::Cursor, path::Path};
4
5use symphonia::core::{
6    errors::Result,
7    formats::{FormatOptions, Track},
8    io::{MediaSource, MediaSourceStream},
9    meta::{MetadataOptions, Tag},
10    probe::{Hint, ProbeResult},
11};
12
13#[derive(Debug)]
14pub struct Metadata {
15    pub tags: Vec<Tag>,
16    pub duration: Option<f64>,
17}
18
19pub trait TrackDuration {
20    fn duration(&self) -> Option<f64>;
21}
22
23impl TrackDuration for Track {
24    fn duration(&self) -> Option<f64> {
25        let params = &self.codec_params;
26        match params.n_frames {
27            Some(n_frames) => match params.time_base {
28                Some(time_base) => {
29                    let time = time_base.calc_time(n_frames);
30                    Some(time.seconds as f64 + time.frac)
31                }
32                None => None,
33            },
34            None => None,
35        }
36    }
37}
38
39pub struct VprAnalyzer {
40    probed: ProbeResult,
41}
42
43impl VprAnalyzer {
44    fn probe(
45        source: Box<dyn MediaSource>,
46        hint: Hint,
47        format_opts: FormatOptions,
48        metadata_opts: MetadataOptions,
49    ) -> Result<ProbeResult> {
50        let mss = MediaSourceStream::new(source, Default::default());
51        symphonia::default::get_probe().format(&hint, mss, &format_opts, &metadata_opts)
52    }
53
54    fn tags(&mut self) -> Vec<Tag> {
55        if let Some(metadata_rev) = self.probed.format.metadata().current() {
56            return metadata_rev.tags().to_vec();
57        } else if let Some(metadata_rev) = self
58            .probed
59            .metadata
60            .get()
61            .as_ref()
62            .and_then(|m| m.current())
63        {
64            return metadata_rev.tags().to_vec();
65        }
66
67        vec![]
68    }
69
70    pub fn duration(&self) -> Option<f64> {
71        let first_track = self.probed.format.tracks().first();
72
73        match first_track {
74            Some(track) => track.duration(),
75            None => None,
76        }
77    }
78
79    pub fn metadata(&mut self) -> Metadata {
80        let tags = self.tags();
81        let duration = self.duration();
82        Metadata { tags, duration }
83    }
84
85    pub fn try_from_path(path: &Path) -> Result<VprAnalyzer> {
86        let mut hint = Hint::new();
87        if let Some(extension) = path.extension() {
88            if let Some(extension) = extension.to_str() {
89                hint.with_extension(extension);
90            }
91        }
92
93        let source = Box::new(File::open(path)?);
94        let probed = VprAnalyzer::probe(source, hint, Default::default(), Default::default())?;
95        Ok(VprAnalyzer { probed })
96    }
97
98    pub fn try_from_file(file: File) -> Result<VprAnalyzer> {
99        let hint = Hint::new();
100        let source = Box::new(file);
101        let probed = VprAnalyzer::probe(source, hint, Default::default(), Default::default())?;
102        Ok(VprAnalyzer { probed })
103    }
104
105    pub fn try_from_buffer(buffer: Vec<u8>) -> Result<VprAnalyzer> {
106        let hint = Hint::new();
107        let source = Box::new(Cursor::new(buffer));
108        let probed = VprAnalyzer::probe(source, hint, Default::default(), Default::default())?;
109        Ok(VprAnalyzer { probed })
110    }
111}