From 13cf459bb2dc0811fbd4f1d5dc20865d0dbecc13 Mon Sep 17 00:00:00 2001 From: kuviman Date: Sun, 19 Feb 2023 15:05:09 +0400 Subject: [PATCH 1/3] Calculate duration for mp3s --- src/decoder/read_seek_source.rs | 22 +++++++++++++++++++--- src/decoder/symphonia.rs | 14 +++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/decoder/read_seek_source.rs b/src/decoder/read_seek_source.rs index f7f31dde..befff3ad 100644 --- a/src/decoder/read_seek_source.rs +++ b/src/decoder/read_seek_source.rs @@ -5,13 +5,29 @@ use symphonia::core::io::MediaSource; pub struct ReadSeekSource { inner: T, + byte_len: Option, +} + +// Copied from std Seek::stream_len since its unstable +fn stream_len(stream: &mut impl Seek) -> std::io::Result { + let old_pos = stream.stream_position()?; + let len = stream.seek(SeekFrom::End(0))?; + + // Avoid seeking a third time when we were already at the end of the + // stream. The branch is usually way cheaper than a seek operation. + if old_pos != len { + stream.seek(SeekFrom::Start(old_pos))?; + } + + Ok(len) } impl ReadSeekSource { /// Instantiates a new `ReadSeekSource` by taking ownership and wrapping the provided /// `Read + Seek`er. - pub fn new(inner: T) -> Self { - ReadSeekSource { inner } + pub fn new(mut inner: T) -> Self { + let byte_len = stream_len(&mut inner).ok(); + ReadSeekSource { inner, byte_len } } } @@ -21,7 +37,7 @@ impl MediaSource for ReadSeekSource { } fn byte_len(&self) -> Option { - None + self.byte_len } } diff --git a/src/decoder/symphonia.rs b/src/decoder/symphonia.rs index 649bb9df..fb640de5 100644 --- a/src/decoder/symphonia.rs +++ b/src/decoder/symphonia.rs @@ -28,6 +28,7 @@ pub struct SymphoniaDecoder { format: Box, buffer: SampleBuffer, spec: SignalSpec, + duration: Option, } impl SymphoniaDecoder { @@ -80,6 +81,16 @@ impl SymphoniaDecoder { }, )?; + // Calculate duration if possible + let mut duration = None; + if let Some(time_base) = &dbg!(&stream.codec_params).time_base { + if let Some(n_frames) = stream.codec_params.n_frames { + let time = time_base.calc_time(n_frames); + duration = + Some(Duration::from_secs(time.seconds) + Duration::from_secs_f64(time.frac)); + } + } + let mut decode_errors: usize = 0; let decoded = loop { let current_frame = probed.format.next_packet()?; @@ -107,6 +118,7 @@ impl SymphoniaDecoder { format: probed.format, buffer, spec, + duration, })); } @@ -137,7 +149,7 @@ impl Source for SymphoniaDecoder { #[inline] fn total_duration(&self) -> Option { - None + self.duration } } From 1903f38a7e3c266bd3467bb772c21fcce47bc267 Mon Sep 17 00:00:00 2001 From: kuviman Date: Sun, 19 Feb 2023 15:41:03 +0400 Subject: [PATCH 2/3] Remove dbg! --- src/decoder/symphonia.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decoder/symphonia.rs b/src/decoder/symphonia.rs index fb640de5..7ef48d5f 100644 --- a/src/decoder/symphonia.rs +++ b/src/decoder/symphonia.rs @@ -83,7 +83,7 @@ impl SymphoniaDecoder { // Calculate duration if possible let mut duration = None; - if let Some(time_base) = &dbg!(&stream.codec_params).time_base { + if let Some(time_base) = &stream.codec_params.time_base { if let Some(n_frames) = stream.codec_params.n_frames { let time = time_base.calc_time(n_frames); duration = From 74fae4359329c86f46d838a92f4467be58c5251f Mon Sep 17 00:00:00 2001 From: kuviman Date: Tue, 19 Sep 2023 17:30:18 +0400 Subject: [PATCH 3/3] Calculate ReadSeekSource byte_len lazily --- src/decoder/read_seek_source.rs | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/decoder/read_seek_source.rs b/src/decoder/read_seek_source.rs index befff3ad..828dce29 100644 --- a/src/decoder/read_seek_source.rs +++ b/src/decoder/read_seek_source.rs @@ -1,11 +1,12 @@ use std::io::{Read, Result, Seek, SeekFrom}; use std::marker::Sync; +use std::sync::{Mutex, RwLock}; use symphonia::core::io::MediaSource; pub struct ReadSeekSource { - inner: T, - byte_len: Option, + inner: Mutex, + byte_len: RwLock>>, // One option is for lazy calculation } // Copied from std Seek::stream_len since its unstable @@ -25,9 +26,11 @@ fn stream_len(stream: &mut impl Seek) -> std::io::Result { impl ReadSeekSource { /// Instantiates a new `ReadSeekSource` by taking ownership and wrapping the provided /// `Read + Seek`er. - pub fn new(mut inner: T) -> Self { - let byte_len = stream_len(&mut inner).ok(); - ReadSeekSource { inner, byte_len } + pub fn new(inner: T) -> Self { + ReadSeekSource { + inner: Mutex::new(inner), + byte_len: RwLock::new(None), + } } } @@ -37,18 +40,31 @@ impl MediaSource for ReadSeekSource { } fn byte_len(&self) -> Option { - self.byte_len + // Check if length was calculated before + let byte_len = self.byte_len.read().unwrap(); + if let Some(cached) = *byte_len { + return cached; + } + std::mem::drop(byte_len); // Release read lock + + let mut inner = self.inner.lock().unwrap(); + let calculated_stream_len = match stream_len(&mut *inner) { + Ok(len) => Some(len), + Err(_) => None, // Ignore error, cache failure + }; + *self.byte_len.write().unwrap() = Some(calculated_stream_len); + calculated_stream_len } } impl Read for ReadSeekSource { fn read(&mut self, buf: &mut [u8]) -> Result { - self.inner.read(buf) + self.inner.get_mut().unwrap().read(buf) } } impl Seek for ReadSeekSource { fn seek(&mut self, pos: SeekFrom) -> Result { - self.inner.seek(pos) + self.inner.get_mut().unwrap().seek(pos) } }