vpr_audio_analyzer/analyzer/
mod.rs1mod 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}