Repository: pdeljanov/Symphonia (language: rust)

Issue:
MediaSource without a static life time
So I want to use a media source that depends on an external life time `'a`:
```rs
// My media source implementation:
struct DatasetMediaSource<'a> {
    r: hdf5::ByteReader<'a>, // Implements io::Read and io::Seek, but does not have a static life time
    size: u64,
}
impl<'a> DatasetMediaSource<'a> {
    fn new(ds: &'a hdf5::Dataset) -> Result<DatasetMediaSource<'a>> {
        Ok(DatasetMediaSource {
            r: ds.as_byte_reader()?,
            size: ds.size() as u64,
        })
    }
}
impl<'a> Read for DatasetMediaSource<'a> {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        self.r.read(buf)
    }
}
impl<'a> Seek for DatasetMediaSource<'a> {
    fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
        self.r.seek(pos)
    }
}
impl<'a> MediaSource for DatasetMediaSource<'a> {
    fn is_seekable(&self) -> bool {
        true
    }

    fn byte_len(&self) -> Option<u64> {
        Some(self.size)
    }
}
```
However, MediaSourceStream requires a static life time:
```rs
// media_source_stream.rs
pub struct MediaSourceStream {
    /// The source reader.
    inner: Box<dyn MediaSource>, // same as: Box<dyn MediaSource + 'static>
   /// ...
```
Resulting in the error
```rs
let source = Box::new(DatasetMediaSource::new(&ds)?); // type: Box<dyn MediaSource + 'a>
                                              ^^^ borrowed value does not live long enough
```

Does someone have an idea, if I can use such a MediaSource?


Discussion / hints:

Fix patch:
diff --git a/symphonia-bundle-flac/src/demuxer.rs b/symphonia-bundle-flac/src/demuxer.rs
index 82b533d4..77e4ad41 100644
--- a/symphonia-bundle-flac/src/demuxer.rs
+++ b/symphonia-bundle-flac/src/demuxer.rs
@@ -35,8 +35,8 @@ const FLAC_FORMAT_INFO: FormatInfo = FormatInfo {
 };
 
 /// Free Lossless Audio Codec (FLAC) native frame reader.
-pub struct FlacReader {
-    reader: MediaSourceStream,
+pub struct FlacReader<'s> {
+    reader: MediaSourceStream<'s>,
     metadata: MetadataLog,
     tracks: Vec<Track>,
     cues: Vec<Cue>,
@@ -45,9 +45,9 @@ pub struct FlacReader {
     parser: PacketParser,
 }
 
-impl FlacReader {
+impl<'s> FlacReader<'s> {
     /// Reads all the metadata blocks, returning a fully populated `FlacReader`.
-    fn init_with_metadata(source: MediaSourceStream, options: FormatOptions) -> Result<Self> {
+    fn init_with_metadata(source: MediaSourceStream<'s>, options: FormatOptions) -> Result<Self> {
         let mut metadata_builder = MetadataBuilder::new();
 
         let mut reader = source;
@@ -140,18 +140,18 @@ impl FlacReader {
     }
 }
 
-impl Probeable for FlacReader {
+impl Probeable for FlacReader<'_> {
     fn probe_descriptor() -> &'static [ProbeDescriptor] {
-        &[support_format!(FLAC_FORMAT_INFO, &["flac"], &["audio/flac"], &[b"fLaC"])]
+        &[support_format!(FlacReader<'_>, FLAC_FORMAT_INFO, &["flac"], &["audio/flac"], &[b"fLaC"])]
     }
 
-    fn score(_src: ScopedStream<&mut MediaSourceStream>) -> Result<Score> {
+    fn score(_src: ScopedStream<&mut MediaSourceStream<'_>>) -> Result<Score> {
         Ok(Score::Supported(255))
     }
 }
 
-impl FormatReader for FlacReader {
-    fn try_new(mut source: MediaSourceStream, options: FormatOptions) -> Result<Self> {
+impl<'s> BuildFormatReader<'s> for FlacReader<'s> {
+    fn try_new(mut source: MediaSourceStream<'s>, options: FormatOptions) -> Result<Self> {
         // Read the first 4 bytes of the stream. Ideally this will be the FLAC stream marker.
         let marker = source.read_quad_bytes()?;
 
@@ -172,7 +172,9 @@ impl FormatReader for FlacReader {
 
         Ok(flac)
     }
+}
 
+impl FormatReader for FlacReader<'_> {
     fn format_info(&self) -> &FormatInfo {
         &FLAC_FORMAT_INFO
     }
@@ -337,7 +339,10 @@ impl FormatReader for FlacReader {
         Ok(SeekedTo { track_id: 0, actual_ts: packet.ts, required_ts: ts })
     }
 
-    fn into_inner(self: Box<Self>) -> MediaSourceStream {
+    fn into_inner<'s>(self: Box<Self>) -> MediaSourceStream<'s>
+    where
+        Self: 's,
+    {
         self.reader
     }
 }
diff --git a/symphonia-bundle-mp3/src/demuxer.rs b/symphonia-bundle-mp3/src/demuxer.rs
index c60b86ee..c2b19efb 100644
--- a/symphonia-bundle-mp3/src/demuxer.rs
+++ b/symphonia-bundle-mp3/src/demuxer.rs
@@ -43,8 +43,8 @@ const MP3_FORMAT_INFO: FormatInfo = FormatInfo {
 /// MPEG1 and MPEG2 audio elementary stream reader.
 ///
 /// `MpaReader` implements a demuxer for the MPEG1 and MPEG2 audio elementary stream.
-pub struct MpaReader {
-    reader: MediaSourceStream,
+pub struct MpaReader<'s> {
+    reader: MediaSourceStream<'s>,
     tracks: Vec<Track>,
     cues: Vec<Cue>,
     metadata: MetadataLog,
@@ -53,11 +53,12 @@ pub struct MpaReader {
     next_packet_ts: u64,
 }
 
-impl Probeable for MpaReader {
+impl Probeable for MpaReader<'_> {
     fn probe_descriptor() -> &'static [ProbeDescriptor] {
         &[
             // Layer 1
             support_format!(
+                MpaReader<'_>,
                 MP1_FORMAT_INFO,
                 &["mp1"],
                 &["audio/mpeg", "audio/mp1"],
@@ -72,6 +73,7 @@ impl Probeable for MpaReader {
             ),
             // Layer 2
             support_format!(
+                MpaReader<'_>,
                 MP2_FORMAT_INFO,
                 &["mp2"],
                 &["audio/mpeg", "audio/mp2"],
@@ -86,6 +88,7 @@ impl Probeable for MpaReader {
             ),
             // Layer 3
             support_format!(
+                MpaReader<'_>,
                 MP3_FORMAT_INFO,
                 &["mp3"],
                 &["audio/mpeg", "audio/mp3"],
@@ -101,7 +104,7 @@ impl Probeable for MpaReader {
         ]
     }
 
-    fn score(mut src: ScopedStream<&mut MediaSourceStream>) -> Result<Score> {
+    fn score(mut src: ScopedStream<&mut MediaSourceStream<'_>>) -> Result<Score> {
         // Read the sync word for the first (assumed) MPEG frame and try to parse it into a header.
         let sync1 = header::read_frame_header_word_no_sync(&mut src)?;
         let hdr1 = header::parse_frame_header(sync1)?;
@@ -132,8 +135,8 @@ impl Probeable for MpaReader {
     }
 }
 
-impl FormatReader for MpaReader {
-    fn try_new(mut source: MediaSourceStream, options: FormatOptions) -> Result<Self> {
+impl<'s> BuildFormatReader<'s> for MpaReader<'s> {
+    fn try_new(mut source: MediaSourceStream<'s>, options: FormatOptions) -> Result<Self> {
         // Try to read the first MPEG frame.
         let (header, packet) = read_mpeg_frame_strict(&mut source)?;
 
@@ -208,7 +211,9 @@ impl FormatReader for MpaReader {
             next_packet_ts: 0,
         })
     }
+}
 
+impl FormatReader for MpaReader<'_> {
     fn format_info(&self) -> &FormatInfo {
         match self.tracks[0].codec_params.codec {
             CODEC_TYPE_MP1 => &MP1_FORMAT_INFO,
@@ -467,12 +472,15 @@ impl FormatReader for MpaReader {
         Ok(SeekedTo { track_id: 0, required_ts: required_ts - delay, actual_ts })
     }
 
-    fn into_inner(self: Box<Self>) -> MediaSourceStream {
+    fn into_inner<'s>(self: Box<Self>) -> MediaSourceStream<'s>
+    where
+        Self: 's,
+    {
         self.reader
     }
 }
 
-impl MpaReader {
+impl MpaReader<'_> {
     /// Seeks the media source stream to a byte position roughly where the packet with the required
     /// timestamp should be located.
     fn preseek_coarse(&mut self, required_ts: u64, duration: Option<u64>) -> Result<()> {
@@ -542,7 +550,7 @@ impl MpaReader {
 }
 
 /// Reads a MPEG frame and returns the header and buffer.
-fn read_mpeg_frame(reader: &mut MediaSourceStream) -> Result<(FrameHeader, Vec<u8>)> {
+fn read_mpeg_frame(reader: &mut MediaSourceStream<'_>) -> Result<(FrameHeader, Vec<u8>)> {
     let (header, header_word) = loop {
         // Sync to the next frame header.
         let sync = header::sync_frame(reader)?;
@@ -567,7 +575,7 @@ fn read_mpeg_frame(reader: &mut MediaSourceStream) -> Result<(FrameHeader, Vec<u
 }
 
 /// Reads a MPEG frame and checks if the next frame begins after the packet.
-fn read_mpeg_frame_strict(reader: &mut MediaSourceStream) -> Result<(FrameHeader, Vec<u8>)> {
+fn read_mpeg_frame_strict(reader: &mut MediaSourceStream<'_>) -> Result<(FrameHeader, Vec<u8>)> {
     loop {
         // Read the next MPEG frame.
         let (header, packet) = read_mpeg_frame(reader)?;
@@ -640,7 +648,7 @@ fn read_main_data_begin<B: ReadBytes>(reader: &mut B, header: &FrameHeader) -> R
 }
 
 /// Estimates the total number of MPEG frames in the media source stream.
-fn estimate_num_mpeg_frames(reader: &mut MediaSourceStream) -> Option<u64> {
+fn estimate_num_mpeg_frames(reader: &mut MediaSourceStream<'_>) -> Option<u64> {
     const MAX_FRAMES: u32 = 16;
     const MAX_LEN: usize = 16 * 1024;
 
diff --git a/symphonia-bundle-mp3/src/lib.rs b/symphonia-bundle-mp3/src/lib.rs
index def350db..7b8f9b83 100644
--- a/symphonia-bundle-mp3/src/lib.rs
+++ b/symphonia-bundle-mp3/src/lib.rs
@@ -49,4 +49,4 @@ pub use demuxer::MpaReader;
 pub type Mp3Decoder = MpaDecoder;
 
 #[deprecated = "use `symphonia_bundle_mp3::MpaReader` instead"]
-pub type Mp3Reader = MpaReader;
+pub type Mp3Reader<'s> = MpaReader<'s>;
diff --git a/symphonia-check/src/main.rs b/symphonia-check/src/main.rs
index 22145438..6b00920f 100644
--- a/symphonia-check/src/main.rs
+++ b/symphonia-check/src/main.rs
@@ -152,7 +152,10 @@ struct DecoderInstance {
 }
 
 impl DecoderInstance {
-    fn try_open(mss: MediaSourceStream, fmt_opts: FormatOptions) -> Result<DecoderInstance> {
+    fn try_open(
+        mss: MediaSourceStream<'static>,
+        fmt_opts: FormatOptions,
+    ) -> Result<DecoderInstance> {
         // Use the default options for metadata and format readers, and the decoder.
         let meta_opts: MetadataOptions = Default::default();
         let dec_opts: DecoderOptions = Default::default();
diff --git a/symphonia-codec-aac/src/adts.rs b/symphonia-codec-aac/src/adts.rs
index c4620a0f..7e7d4a39 100644
--- a/symphonia-codec-aac/src/adts.rs
+++ b/symphonia-codec-aac/src/adts.rs
@@ -33,8 +33,8 @@ const ADTS_FORMAT_INFO: FormatInfo = FormatInfo {
 /// Audio Data Transport Stream (ADTS) format reader.
 ///
 /// `AdtsReader` implements a demuxer for ADTS (AAC native frames).
-pub struct AdtsReader {
-    reader: MediaSourceStream,
+pub struct AdtsReader<'s> {
+    reader: MediaSourceStream<'s>,
     tracks: Vec<Track>,
     cues: Vec<Cue>,
     metadata: MetadataLog,
@@ -42,9 +42,10 @@ pub struct AdtsReader {
     next_packet_ts: u64,
 }
 
-impl Probeable for AdtsReader {
+impl Probeable for AdtsReader<'_> {
     fn probe_descriptor() -> &'static [ProbeDescriptor] {
         &[support_format!(
+            AdtsReader<'_>,
             ADTS_FORMAT_INFO,
             &["aac"],
             &["audio/aac"],
@@ -57,7 +58,7 @@ impl Probeable for AdtsReader {
         )]
     }
 
-    fn score(mut src: ScopedStream<&mut MediaSourceStream>) -> Result<Score> {
+    fn score(mut src: ScopedStream<&mut MediaSourceStream<'_>>) -> Result<Score> {
         // Read the first (assumed) ADTS header.
         let hdr1 = AdtsHeader::read_no_resync(&mut src)?;
 
@@ -211,8 +212,8 @@ impl AdtsHeader {
     }
 }
 
-impl FormatReader for AdtsReader {
-    fn try_new(mut source: MediaSourceStream, options: FormatOptions) -> Result<Self> {
+impl<'s> BuildFormatReader<'s> for AdtsReader<'s> {
+    fn try_new(mut source: MediaSourceStream<'s>, options: FormatOptions) -> Result<Self> {
         let header = AdtsHeader::read(&mut source)?;
 
         // Rewind back to the start of the frame.
@@ -246,7 +247,9 @@ impl FormatReader for AdtsReader {
             next_packet_ts: 0,
         })
     }
+}
 
+impl FormatReader for AdtsReader<'_> {
     fn format_info(&self) -> &FormatInfo {
         &ADTS_FORMAT_INFO
     }
@@ -369,12 +372,15 @@ impl FormatReader for AdtsReader {
         Ok(SeekedTo { track_id: 0, required_ts, actual_ts: self.next_packet_ts })
     }
 
-    fn into_inner(self: Box<Self>) -> MediaSourceStream {
+    fn into_inner<'s>(self: Box<Self>) -> MediaSourceStream<'s>
+    where
+        Self: 's,
+    {
         self.reader
     }
 }
 
-fn approximate_frame_count(mut source: &mut MediaSourceStream) -> Result<Option<u64>> {
+fn approximate_frame_count(mut source: &mut MediaSourceStream<'_>) -> Result<Option<u64>> {
     let original_pos = source.pos();
     let total_len = match source.byte_len() {
         Some(len) => len - original_pos,
diff --git a/symphonia-core/src/formats.rs b/symphonia-core/src/formats.rs
index 7451d086..51164270 100644
--- a/symphonia-core/src/formats.rs
+++ b/symphonia-core/src/formats.rs
@@ -22,8 +22,8 @@ pub mod prelude {
     pub use crate::units::{Duration, TimeBase, TimeStamp};
 
     pub use super::{
-        Cue, FormatInfo, FormatOptions, FormatReader, FormatType, Packet, SeekMode, SeekTo,
-        SeekedTo, Track,
+        BuildFormatReader, Cue, FormatInfo, FormatOptions, FormatReader, FormatType, Packet,
+        SeekMode, SeekTo, SeekedTo, Track,
     };
 }
 
@@ -213,6 +213,13 @@ impl Track {
     }
 }
 
+pub trait BuildFormatReader<'s>: FormatReader + Sized {
+    /// Attempt to instantiate a `FormatReader` using the provided `FormatOptions` and
+    /// `MediaSourceStream`. The reader will probe the container to verify format support, determine
+    /// the number of tracks, and read any initial metadata.
+    fn try_new(source: MediaSourceStream<'s>, options: FormatOptions) -> Result<Self>;
+}
+
 /// A `FormatReader` is a container demuxer. It provides methods to probe a media container for
 /// information and access the tracks encapsulated in the container.
 ///
@@ -230,13 +237,6 @@ impl Track {
 /// filtering. Seeking will invalidate the state of any `Decoder` processing packets from the
 /// `FormatReader` and should be reset after a successful seek operation.
 pub trait FormatReader: Send + Sync {
-    /// Attempt to instantiate a `FormatReader` using the provided `FormatOptions` and
-    /// `MediaSourceStream`. The reader will probe the container to verify format support, determine
-    /// the number of tracks, and read any initial metadata.
-    fn try_new(source: MediaSourceStream, options: FormatOptions) -> Result<Self>
-    where
-        Self: Sized;
-
     /// Get basic information about the container format.
     fn format_info(&self) -> &FormatInfo;
 
@@ -280,7 +280,9 @@ pub trait FormatReader: Send + Sync {
     fn next_packet(&mut self) -> Result<Option<Packet>>;
 
     /// Destroys the `FormatReader` and returns the underlying media source stream
-    fn into_inner(self: Box<Self>) -> MediaSourceStream;
+    fn into_inner<'s>(self: Box<Self>) -> MediaSourceStream<'s>
+    where
+        Self: 's;
 }
 
 /// A `Packet` contains a discrete amount of encoded data for a single codec bitstream. The exact
diff --git a/symphonia-core/src/io/media_source_stream.rs b/symphonia-core/src/io/media_source_stream.rs
index 0251e79a..d508968e 100644
--- a/symphonia-core/src/io/media_source_stream.rs
+++ b/symphonia-core/src/io/media_source_stream.rs
@@ -49,9 +49,9 @@ impl Default for MediaSourceStreamOptions {
 /// length buffer cache. By default, the buffer caches allows backtracking by up-to the minimum of
 /// either `buffer_len - 32kB` or the total number of bytes read since instantiation or the last
 /// buffer cache invalidation. Note that regular a `seek()` will invalidate the buffer cache.
-pub struct MediaSourceStream {
+pub struct MediaSourceStream<'s> {
     /// The source reader.
-    inner: Box<dyn MediaSource>,
+    inner: Box<dyn MediaSource + 's>,
     /// The ring buffer.
     ring: Box<[u8]>,
     /// The ring buffer's wrap-around mask.
@@ -69,11 +69,11 @@ pub struct MediaSourceStream {
     rel_pos: u64,
 }
 
-impl MediaSourceStream {
+impl<'s> MediaSourceStream<'s> {
     const MIN_BLOCK_LEN: usize = 1 * 1024;
     const MAX_BLOCK_LEN: usize = 32 * 1024;
 
-    pub fn new(source: Box<dyn MediaSource>, options: MediaSourceStreamOptions) -> Self {
+    pub fn new(source: Box<dyn MediaSource + 's>, options: MediaSourceStreamOptions) -> Self {
         // The buffer length must be a power of 2, and > the maximum read block length.
         assert!(options.buffer_len.count_ones() == 1);
         assert!(options.buffer_len > Self::MAX_BLOCK_LEN);
@@ -174,7 +174,7 @@ impl MediaSourceStream {
     }
 }
 
-impl MediaSource for MediaSourceStream {
+impl MediaSource for MediaSourceStream<'_> {
     #[inline]
     fn is_seekable(&self) -> bool {
         self.inner.is_seekable()
@@ -186,7 +186,7 @@ impl MediaSource for MediaSourceStream {
     }
 }
 
-impl io::Read for MediaSourceStream {
+impl io::Read for MediaSourceStream<'_> {
     fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
         let read_len = buf.len();
 
@@ -213,7 +213,7 @@ impl io::Read for MediaSourceStream {
     }
 }
 
-impl io::Seek for MediaSourceStream {
+impl io::Seek for MediaSourceStream<'_> {
     fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
         // The current position of the underlying reader is ahead of the current position of the
         // MediaSourceStream by how ever many bytes have not been read from the read-ahead buffer
@@ -234,7 +234,7 @@ impl io::Seek for MediaSourceStream {
     }
 }
 
-impl ReadBytes for MediaSourceStream {
+impl ReadBytes for MediaSourceStream<'_> {
     #[inline(always)]
     fn read_byte(&mut self) -> io::Result<u8> {
         // This function, read_byte, is inlined for performance. To reduce code bloat, place the
@@ -375,7 +375,7 @@ impl ReadBytes for MediaSourceStream {
     }
 }
 
-impl SeekBuffered for MediaSourceStream {
+impl SeekBuffered for MediaSourceStream<'_> {
     fn ensure_seekback_buffer(&mut self, len: usize) {
         let ring_len = self.ring.len();
 
diff --git a/symphonia-core/src/probe.rs b/symphonia-core/src/probe.rs
index 1ae3c390..4692fb26 100644
--- a/symphonia-core/src/probe.rs
+++ b/symphonia-core/src/probe.rs
@@ -93,7 +93,8 @@ pub enum ProbeCandidate {
         /// A basic description about the container format.
         info: FormatInfo,
         /// A factory function to create an instance of the format reader.
-        factory: fn(MediaSourceStream, FormatOptions) -> Result<Box<dyn FormatReader>>,
+        factory:
+            for<'s> fn(MediaSourceStream<'s>, FormatOptions) -> Result<Box<dyn FormatReader + 's>>,
     },
     Metadata {
         /// A basic description about the metadata format.
@@ -115,7 +116,7 @@ pub struct ProbeDescriptor {
     pub markers: &'static [&'static [u8]],
     /// A function to assign a likelyhood score that the media source, readable with scoped access
     /// via. the provided stream, is the start of a metadate or container format
-    pub score: fn(ScopedStream<&mut MediaSourceStream>) -> Result<Score>,
+    pub score: fn(ScopedStream<&mut MediaSourceStream<'_>>) -> Result<Score>,
     /// If the probe descriptor matches the byte stream, then the probe candidate describes the
     /// metadata or container format reader, and provides a factory function to instantiate it.
     pub candidate: ProbeCandidate,
@@ -144,7 +145,7 @@ pub trait Probeable {
     /// If an error is returned, errors other than [`Error::IoError`] (excluding the unexpected EOF
     /// kind) are treated as if [`Score::Unsupported`] was returned. All other IO errors abort
     /// the probe operation.
-    fn score(src: ScopedStream<&mut MediaSourceStream>) -> Result<Score>;
+    fn score(src: ScopedStream<&mut MediaSourceStream<'_>>) -> Result<Score>;
 }
 
 /// A `Hint` provides additional information and context when probing a media source stream.
@@ -346,13 +347,13 @@ impl Probe {
     /// Searches the provided `MediaSourceStream` for a container format. Any metadata that is read
     /// during the search will be queued and attached to the `FormatReader` instance once a
     /// container format is found.
-    pub fn format(
+    pub fn format<'s>(
         &self,
         hint: &Hint,
-        mut mss: MediaSourceStream,
+        mut mss: MediaSourceStream<'s>,
         mut fmt_opts: FormatOptions,
         meta_opts: MetadataOptions,
-    ) -> Result<Box<dyn FormatReader>> {
+    ) -> Result<Box<dyn FormatReader + 's>> {
         // Loop over all elements in the stream until a container format is found.
         loop {
             match self.next(&mut mss, hint)? {
@@ -470,7 +471,7 @@ fn warn_junk_bytes(pos: u64, init_pos: u64) {
 /// Convenience macro for declaring a probe `ProbeDescriptor` for a `FormatReader`.
 #[macro_export]
 macro_rules! support_format {
-    ($info:expr, $exts:expr, $mimes:expr, $markers:expr) => {
+    ($typ:ty, $info:expr, $exts:expr, $mimes:expr, $markers:expr) => {
         symphonia_core::probe::ProbeDescriptor {
             extensions: $exts,
             mime_types: $mimes,
@@ -478,7 +479,7 @@ macro_rules! support_format {
             score: Self::score,
             candidate: symphonia_core::probe::ProbeCandidate::Format {
                 info: $info,
-                factory: |src, opts| Ok(Box::new(Self::try_new(src, opts)?)),
+                factory: |src, opts| Ok(Box::new(<$typ>::try_new(src, opts)?)),
             },
         }
     };
diff --git a/symphonia-format-caf/src/chunks.rs b/symphonia-format-caf/src/chunks.rs
index 80274b8e..fc2764a1 100644
--- a/symphonia-format-caf/src/chunks.rs
+++ b/symphonia-format-caf/src/chunks.rs
@@ -79,7 +79,7 @@ impl Chunk {
     /// The first chunk read will be the AudioDescription chunk. Once it's been read, the caller
     /// should pass it in to subsequent read calls.
     pub fn read(
-        reader: &mut MediaSourceStream,
+        reader: &mut MediaSourceStream<'_>,
         audio_description: &Option<AudioDescription>,
     ) -> Result<Option<Self>> {
         let chunk_type = reader.read_quad_bytes()?;
@@ -140,7 +140,7 @@ pub struct AudioDescription {
 }
 
 impl AudioDescription {
-    pub fn read(reader: &mut MediaSourceStream, chunk_size: i64) -> Result<Self> {
+    pub fn read(reader: &mut MediaSourceStream<'_>, chunk_size: i64) -> Result<Self> {
         if chunk_size != 32 {
             return invalid_chunk_size_error("Audio Description", chunk_size);
         }
@@ -236,7 +236,7 @@ pub struct AudioData {
 }
 
 impl AudioData {
-    pub fn read(reader: &mut MediaSourceStream, chunk_size: i64) -> Result<Self> {
+    pub fn read(reader: &mut MediaSourceStream<'_>, chunk_size: i64) -> Result<Self> {
         let edit_count_offset = size_of::<u32>() as i64;
 
         if chunk_size != -1 && chunk_size < edit_count_offset {
@@ -275,7 +275,7 @@ pub enum AudioDescriptionFormatId {
 }
 
 impl AudioDescriptionFormatId {
-    pub fn read(reader: &mut MediaSourceStream) -> Result<Self> {
+    pub fn read(reader: &mut MediaSourceStream<'_>) -> Result<Self> {
         use AudioDescriptionFormatId::*;
 
         let format_id = reader.read_quad_bytes()?;
@@ -328,7 +328,7 @@ pub struct ChannelLayout {
 }
 
 impl ChannelLayout {
-    pub fn read(reader: &mut MediaSourceStream, chunk_size: i64) -> Result<Self> {
+    pub fn read(reader: &mut MediaSourceStream<'_>, chunk_size: i64) -> Result<Self> {
         if chunk_size < 12 {
             return invalid_chunk_size_error("Channel Layout", chunk_size);
         }
@@ -436,7 +436,7 @@ pub struct ChannelDescription {
 }
 
 impl ChannelDescription {
-    pub fn read(reader: &mut MediaSourceStream) -> Result<Self> {
+    pub fn read(reader: &mut MediaSourceStream<'_>) -> Result<Self> {
         Ok(Self {
             channel_label: reader.read_be_u32()?,
             channel_flags: reader.read_be_u32()?,
@@ -454,7 +454,7 @@ pub struct PacketTable {
 
 impl PacketTable {
     pub fn read(
-        reader: &mut MediaSourceStream,
+        reader: &mut MediaSourceStream<'_>,
         desc: &Option<AudioDescription>,
         chunk_size: i64,
     ) -> Result<Self> {
@@ -583,7 +583,7 @@ fn invalid_chunk_size_error<T>(chunk_type: &str, chunk_size: i64) -> Result<T> {
     decode_error("caf: invalid chunk size")
 }
 
-fn read_variable_length_integer(reader: &mut MediaSourceStream) -> Result<u64> {
+fn read_variable_length_integer(reader: &mut MediaSourceStream<'_>) -> Result<u64> {
     let mut result = 0;
 
     for _ in 0..9 {
diff --git a/symphonia-format-caf/src/demuxer.rs b/symphonia-format-caf/src/demuxer.rs
index 8fc8c216..911bda27 100644
--- a/symphonia-format-caf/src/demuxer.rs
+++ b/symphonia-format-caf/src/demuxer.rs
@@ -28,8 +28,8 @@ const CAF_FORMAT_INFO: FormatInfo =
 /// Core Audio Format (CAF) format reader.
 ///
 /// `CafReader` implements a demuxer for Core Audio Format containers.
-pub struct CafReader {
-    reader: MediaSourceStream,
+pub struct CafReader<'s> {
+    reader: MediaSourceStream<'s>,
     tracks: Vec<Track>,
     cues: Vec<Cue>,
     metadata: MetadataLog,
@@ -44,18 +44,18 @@ enum PacketInfo {
     Compressed { packets: Vec<CafPacket>, current_packet_index: usize },
 }
 
-impl Probeable for CafReader {
+impl Probeable for CafReader<'_> {
     fn probe_descriptor() -> &'static [ProbeDescriptor] {
-        &[support_format!(CAF_FORMAT_INFO, &["caf"], &["audio/x-caf"], &[b"caff"])]
+        &[support_format!(CafReader<'_>, CAF_FORMAT_INFO, &["caf"], &["audio/x-caf"], &[b"caff"])]
     }
 
-    fn score(_src: ScopedStream<&mut MediaSourceStream>) -> Result<Score> {
+    fn score(_src: ScopedStream<&mut MediaSourceStream<'_>>) -> Result<Score> {
         Ok(Score::Supported(255))
     }
 }
 
-impl FormatReader for CafReader {
-    fn try_new(source: MediaSourceStream, options: FormatOptions) -> Result<Self> {
+impl<'s> BuildFormatReader<'s> for CafReader<'s> {
+    fn try_new(source: MediaSourceStream<'s>, options: FormatOptions) -> Result<Self> {
         let mut reader = Self {
             reader: source,
             tracks: vec![],
@@ -73,7 +73,9 @@ impl FormatReader for CafReader {
 
         Ok(reader)
     }
+}
 
+impl FormatReader for CafReader<'_> {
     fn format_info(&self) -> &FormatInfo {
         &CAF_FORMAT_INFO
     }
@@ -241,12 +243,15 @@ impl FormatReader for CafReader {
         }
     }
 
-    fn into_inner(self: Box<Self>) -> MediaSourceStream {
+    fn into_inner<'s>(self: Box<Self>) -> MediaSourceStream<'s>
+    where
+        Self: 's,
+    {
         self.reader
     }
 }
 
-impl CafReader {
+impl CafReader<'_> {
     fn time_base(&self) -> Option<TimeBase> {
         self.tracks.first().and_then(|track| {
             track.codec_params.sample_rate.map(|sample_rate| TimeBase::new(1, sample_rate))
diff --git a/symphonia-format-isomp4/src/demuxer.rs b/symphonia-format-isomp4/src/demuxer.rs
index 6987db13..f08bcb4d 100644
--- a/symphonia-format-isomp4/src/demuxer.rs
+++ b/symphonia-format-isomp4/src/demuxer.rs
@@ -89,8 +89,8 @@ struct SampleDataInfo {
 /// ISO Base Media File Format (MP4, M4A, MOV, etc.) demultiplexer.
 ///
 /// `IsoMp4Reader` implements a demuxer for the ISO Base Media File Format.
-pub struct IsoMp4Reader {
-    iter: AtomIterator<MediaSourceStream>,
+pub struct IsoMp4Reader<'s> {
+    iter: AtomIterator<MediaSourceStream<'s>>,
     tracks: Vec<Track>,
     cues: Vec<Cue>,
     metadata: MetadataLog,
@@ -102,7 +102,7 @@ pub struct IsoMp4Reader {
     moov: Arc<MoovAtom>,
 }
 
-impl IsoMp4Reader {
+impl IsoMp4Reader<'_> {
     /// Idempotently gets information regarding the next sample of the media stream. This function
     /// selects the next sample with the lowest timestamp of all tracks.
     fn next_sample_info(&self) -> Result<Option<NextSampleInfo>> {
@@ -320,9 +320,10 @@ impl IsoMp4Reader {
     }
 }
 
-impl Probeable for IsoMp4Reader {
+impl Probeable for IsoMp4Reader<'_> {
     fn probe_descriptor() -> &'static [ProbeDescriptor] {
         &[support_format!(
+            IsoMp4Reader<'_>,
             ISOMP4_FORMAT_INFO,
             &["mp4", "m4a", "m4p", "m4b", "m4r", "m4v", "mov"],
             &["video/mp4", "audio/m4a"],
@@ -330,13 +331,13 @@ impl Probeable for IsoMp4Reader {
         )]
     }
 
-    fn score(_src: ScopedStream<&mut MediaSourceStream>) -> Result<Score> {
+    fn score(_src: ScopedStream<&mut MediaSourceStream<'_>>) -> Result<Score> {
         Ok(Score::Supported(255))
     }
 }
 
-impl FormatReader for IsoMp4Reader {
-    fn try_new(mut mss: MediaSourceStream, options: FormatOptions) -> Result<Self> {
+impl<'s> BuildFormatReader<'s> for IsoMp4Reader<'s> {
+    fn try_new(mut mss: MediaSourceStream<'s>, options: FormatOptions) -> Result<Self> {
         // To get to beginning of the atom.
         mss.seek_buffered_rel(-4);
 
@@ -504,7 +505,9 @@ impl FormatReader for IsoMp4Reader {
             moov,
         })
     }
+}
 
+impl FormatReader for IsoMp4Reader<'_> {
     fn format_info(&self) -> &FormatInfo {
         &ISOMP4_FORMAT_INFO
     }
@@ -617,7 +620,10 @@ impl FormatReader for IsoMp4Reader {
         }
     }
 
-    fn into_inner(self: Box<Self>) -> MediaSourceStream {
+    fn into_inner<'s>(self: Box<Self>) -> MediaSourceStream<'s>
+    where
+        Self: 's,
+    {
         self.iter.into_inner()
     }
 }
diff --git a/symphonia-format-mkv/src/demuxer.rs b/symphonia-format-mkv/src/demuxer.rs
index 9ce75074..31f11b11 100644
--- a/symphonia-format-mkv/src/demuxer.rs
+++ b/symphonia-format-mkv/src/demuxer.rs
@@ -49,9 +49,9 @@ pub struct TrackState {
 /// Matroska (MKV) and WebM demultiplexer.
 ///
 /// `MkvReader` implements a demuxer for the Matroska and WebM formats.
-pub struct MkvReader {
+pub struct MkvReader<'s> {
     /// Iterator over EBML element headers
-    iter: ElementIterator<MediaSourceStream>,
+    iter: ElementIterator<MediaSourceStream<'s>>,
     tracks: Vec<Track>,
     track_states: HashMap<u32, TrackState>,
     current_cluster: Option<ClusterState>,
@@ -138,7 +138,7 @@ fn flac_extra_data_from_codec_private(codec_private: &[u8]) -> Result<Box<[u8]>>
     }
 }
 
-impl MkvReader {
+impl MkvReader<'_> {
     fn seek_track_by_ts_forward(&mut self, track_id: u32, ts: u64) -> Result<SeekedTo> {
         let actual_ts = 'out: loop {
             // Skip frames from the buffer until the given timestamp
@@ -314,8 +314,8 @@ impl MkvReader {
     }
 }
 
-impl FormatReader for MkvReader {
-    fn try_new(mut reader: MediaSourceStream, options: FormatOptions) -> Result<Self>
+impl<'s> BuildFormatReader<'s> for MkvReader<'s> {
+    fn try_new(mut reader: MediaSourceStream<'s>, options: FormatOptions) -> Result<Self>
     where
         Self: Sized,
     {
@@ -527,7 +527,9 @@ impl FormatReader for MkvReader {
             clusters,
         })
     }
+}
 
+impl FormatReader for MkvReader<'_> {
     fn format_info(&self) -> &FormatInfo {
         &MKV_FORMAT_INFO
     }
@@ -588,14 +590,18 @@ impl FormatReader for MkvReader {
         }
     }
 
-    fn into_inner(self: Box<Self>) -> MediaSourceStream {
+    fn into_inner<'s>(self: Box<Self>) -> MediaSourceStream<'s>
+    where
+        Self: 's,
+    {
         self.iter.into_inner()
     }
 }
 
-impl Probeable for MkvReader {
+impl Probeable for MkvReader<'_> {
     fn probe_descriptor() -> &'static [ProbeDescriptor] {
         &[support_format!(
+            MkvReader<'_>,
             MKV_FORMAT_INFO,
             &["webm", "mkv"],
             &["video/webm", "video/x-matroska"],
@@ -603,7 +609,7 @@ impl Probeable for MkvReader {
         )]
     }
 
-    fn score(_src: ScopedStream<&mut MediaSourceStream>) -> Result<Score> {
+    fn score(_src: ScopedStream<&mut MediaSourceStream<'_>>) -> Result<Score> {
         Ok(Score::Supported(255))
     }
 }
diff --git a/symphonia-format-ogg/src/demuxer.rs b/symphonia-format-ogg/src/demuxer.rs
index b748442a..fef0f95f 100644
--- a/symphonia-format-ogg/src/demuxer.rs
+++ b/symphonia-format-ogg/src/demuxer.rs
@@ -30,8 +30,8 @@ const OGG_FORMAT_INFO: FormatInfo =
 /// OGG demultiplexer.
 ///
 /// `OggReader` implements a demuxer for Xiph's OGG container format.
-pub struct OggReader {
-    reader: MediaSourceStream,
+pub struct OggReader<'s> {
+    reader: MediaSourceStream<'s>,
     tracks: Vec<Track>,
     cues: Vec<Cue>,
     metadata: MetadataLog,
@@ -46,7 +46,7 @@ pub struct OggReader {
     phys_byte_range_end: Option<u64>,
 }
 
-impl OggReader {
+impl OggReader<'_> {
     fn read_page(&mut self) -> Result<()> {
         // Try reading pages until a page is successfully read, or an IO error.
         loop {
@@ -375,9 +375,10 @@ impl OggReader {
     }
 }
 
-impl Probeable for OggReader {
+impl Probeable for OggReader<'_> {
     fn probe_descriptor() -> &'static [ProbeDescriptor] {
         &[support_format!(
+            OggReader<'_>,
             OGG_FORMAT_INFO,
             &["ogg", "ogv", "oga", "ogx", "ogm", "spx", "opus"],
             &["video/ogg", "audio/ogg", "application/ogg"],
@@ -385,13 +386,13 @@ impl Probeable for OggReader {
         )]
     }
 
-    fn score(_src: ScopedStream<&mut MediaSourceStream>) -> Result<Score> {
+    fn score(_src: ScopedStream<&mut MediaSourceStream<'_>>) -> Result<Score> {
         Ok(Score::Supported(255))
     }
 }
 
-impl FormatReader for OggReader {
-    fn try_new(mut source: MediaSourceStream, options: FormatOptions) -> Result<Self> {
+impl<'s> BuildFormatReader<'s> for OggReader<'s> {
+    fn try_new(mut source: MediaSourceStream<'s>, options: FormatOptions) -> Result<Self> {
         // A seekback buffer equal to the maximum OGG page size is required for this reader.
         source.ensure_seekback_buffer(OGG_PAGE_MAX_SIZE);
 
@@ -417,7 +418,9 @@ impl FormatReader for OggReader {
 
         Ok(ogg)
     }
+}
 
+impl FormatReader for OggReader<'_> {
     fn format_info(&self) -> &FormatInfo {
         &OGG_FORMAT_INFO
     }
@@ -520,7 +523,10 @@ impl FormatReader for OggReader {
         self.do_seek(serial, required_ts)
     }
 
-    fn into_inner(self: Box<Self>) -> MediaSourceStream {
+    fn into_inner<'s>(self: Box<Self>) -> MediaSourceStream<'s>
+    where
+        Self: 's,
+    {
         self.reader
     }
 }
diff --git a/symphonia-format-ogg/src/physical.rs b/symphonia-format-ogg/src/physical.rs
index dc921740..de639e54 100644
--- a/symphonia-format-ogg/src/physical.rs
+++ b/symphonia-format-ogg/src/physical.rs
@@ -16,7 +16,7 @@ use super::page::*;
 use log::debug;
 
 pub fn probe_stream_start(
-    reader: &mut MediaSourceStream,
+    reader: &mut MediaSourceStream<'_>,
     pages: &mut PageReader,
     streams: &mut BTreeMap<u32, LogicalStream>,
 ) {
@@ -66,7 +66,7 @@ pub fn probe_stream_start(
 }
 
 pub fn probe_stream_end(
-    reader: &mut MediaSourceStream,
+    reader: &mut MediaSourceStream<'_>,
     pages: &mut PageReader,
     streams: &mut BTreeMap<u32, LogicalStream>,
     byte_range_start: u64,
@@ -142,7 +142,7 @@ pub fn probe_stream_end(
 }
 
 fn scan_stream_end(
-    reader: &mut MediaSourceStream,
+    reader: &mut MediaSourceStream<'_>,
     pages: &mut PageReader,
     streams: &mut BTreeMap<u32, LogicalStream>,
     byte_range_end: u64,
diff --git a/symphonia-format-riff/src/aiff/chunks.rs b/symphonia-format-riff/src/aiff/chunks.rs
index 873aea58..bdf06438 100644
--- a/symphonia-format-riff/src/aiff/chunks.rs
+++ b/symphonia-format-riff/src/aiff/chunks.rs
@@ -200,16 +200,16 @@ impl fmt::Display for CommonChunk {
 }
 
 pub trait CommonChunkParser {
-    fn parse_aiff(self, source: &mut MediaSourceStream) -> Result<CommonChunk>;
-    fn parse_aifc(self, source: &mut MediaSourceStream) -> Result<CommonChunk>;
+    fn parse_aiff(self, source: &mut MediaSourceStream<'_>) -> Result<CommonChunk>;
+    fn parse_aifc(self, source: &mut MediaSourceStream<'_>) -> Result<CommonChunk>;
 }
 
 impl CommonChunkParser for ChunkParser<CommonChunk> {
-    fn parse_aiff(self, source: &mut MediaSourceStream) -> Result<CommonChunk> {
+    fn parse_aiff(self, source: &mut MediaSourceStream<'_>) -> Result<CommonChunk> {
         self.parse(source)
     }
 
-    fn parse_aifc(self, source: &mut MediaSourceStream) -> Result<CommonChunk> {
+    fn parse_aifc(self, source: &mut MediaSourceStream<'_>) -> Result<CommonChunk> {
         let n_channels = source.read_be_i16()?;
         let n_sample_frames = source.read_be_u32()?;
         let sample_size = source.read_be_i16()?;
diff --git a/symphonia-format-riff/src/aiff/mod.rs b/symphonia-format-riff/src/aiff/mod.rs
index 1db46e17..7e409132 100644
--- a/symphonia-format-riff/src/aiff/mod.rs
+++ b/symphonia-format-riff/src/aiff/mod.rs
@@ -40,8 +40,8 @@ const AIFF_FORMAT_INFO: FormatInfo = FormatInfo {
 /// Audio Interchange File Format (AIFF) format reader.
 ///
 /// `AiffReader` implements a demuxer for the AIFF container format.
-pub struct AiffReader {
-    reader: MediaSourceStream,
+pub struct AiffReader<'s> {
+    reader: MediaSourceStream<'s>,
     tracks: Vec<Track>,
     cues: Vec<Cue>,
     metadata: MetadataLog,
@@ -50,11 +50,12 @@ pub struct AiffReader {
     data_end_pos: u64,
 }
 
-impl Probeable for AiffReader {
+impl Probeable for AiffReader<'_> {
     fn probe_descriptor() -> &'static [ProbeDescriptor] {
         &[
             // AIFF RIFF form
             support_format!(
+                AiffReader<'_>,
                 AIFF_FORMAT_INFO,
                 &["aiff", "aif", "aifc"],
                 &["audio/aiff", "audio/x-aiff", " sound/aiff", "audio/x-pn-aiff"],
@@ -63,13 +64,13 @@ impl Probeable for AiffReader {
         ]
     }
 
-    fn score(_src: ScopedStream<&mut MediaSourceStream>) -> Result<Score> {
+    fn score(_src: ScopedStream<&mut MediaSourceStream<'_>>) -> Result<Score> {
         Ok(Score::Supported(255))
     }
 }
 
-impl FormatReader for AiffReader {
-    fn try_new(mut source: MediaSourceStream, options: FormatOptions) -> Result<Self> {
+impl<'s> BuildFormatReader<'s> for AiffReader<'s> {
+    fn try_new(mut source: MediaSourceStream<'s>, options: FormatOptions) -> Result<Self> {
         // The FORM marker should be present.
         let marker = source.read_quad_bytes()?;
         if marker != AIFF_STREAM_MARKER {
@@ -141,7 +142,9 @@ impl FormatReader for AiffReader {
             }
         }
     }
+}
 
+impl FormatReader for AiffReader<'_> {
     fn format_info(&self) -> &FormatInfo {
         &AIFF_FORMAT_INFO
     }
@@ -234,7 +237,10 @@ impl FormatReader for AiffReader {
         Ok(SeekedTo { track_id: 0, actual_ts, required_ts: ts })
     }
 
-    fn into_inner(self: Box<Self>) -> MediaSourceStream {
+    fn into_inner<'s>(self: Box<Self>) -> MediaSourceStream<'s>
+    where
+        Self: 's,
+    {
         self.reader
     }
 }
diff --git a/symphonia-format-riff/src/common.rs b/symphonia-format-riff/src/common.rs
index 0d4e095e..6ab76a9c 100644
--- a/symphonia-format-riff/src/common.rs
+++ b/symphonia-format-riff/src/common.rs
@@ -262,7 +262,7 @@ impl PacketInfo {
 }
 
 pub fn next_packet(
-    reader: &mut MediaSourceStream,
+    reader: &mut MediaSourceStream<'_>,
     packet_info: &PacketInfo,
     tracks: &[Track],
     data_start_pos: u64,
diff --git a/symphonia-format-riff/src/wave/chunks.rs b/symphonia-format-riff/src/wave/chunks.rs
index 40e72fae..4af409e9 100644
--- a/symphonia-format-riff/src/wave/chunks.rs
+++ b/symphonia-format-riff/src/wave/chunks.rs
@@ -617,7 +617,7 @@ pub fn append_fact_params(codec_params: &mut CodecParameters, fact: &FactChunk)
     codec_params.with_n_frames(u64::from(fact.n_frames));
 }
 
-pub fn read_info_chunk(source: &mut MediaSourceStream, len: u32) -> Result<MetadataRevision> {
+pub fn read_info_chunk(source: &mut MediaSourceStream<'_>, len: u32) -> Result<MetadataRevision> {
     let mut info_list = ChunksReader::<RiffInfoListChunks>::new(len, ByteOrder::LittleEndian);
 
     let mut metadata_builder = MetadataBuilder::new();
diff --git a/symphonia-format-riff/src/wave/mod.rs b/symphonia-format-riff/src/wave/mod.rs
index 7b25a315..ea59f963 100644
--- a/symphonia-format-riff/src/wave/mod.rs
+++ b/symphonia-format-riff/src/wave/mod.rs
@@ -38,8 +38,8 @@ const WAVE_FORMAT_INFO: FormatInfo = FormatInfo {
 /// Waveform Audio File Format (WAV) format reader.
 ///
 /// `WavReader` implements a demuxer for the WAVE container format.
-pub struct WavReader {
-    reader: MediaSourceStream,
+pub struct WavReader<'s> {
+    reader: MediaSourceStream<'s>,
     tracks: Vec<Track>,
     cues: Vec<Cue>,
     metadata: MetadataLog,
@@ -48,11 +48,12 @@ pub struct WavReader {
     data_end_pos: u64,
 }
 
-impl Probeable for WavReader {
+impl Probeable for WavReader<'_> {
     fn probe_descriptor() -> &'static [ProbeDescriptor] {
         &[
             // WAVE RIFF form
             support_format!(
+                WavReader<'_>,
                 WAVE_FORMAT_INFO,
                 &["wav", "wave"],
                 &["audio/vnd.wave", "audio/x-wav", "audio/wav", "audio/wave"],
@@ -61,7 +62,7 @@ impl Probeable for WavReader {
         ]
     }
 
-    fn score(mut src: ScopedStream<&mut MediaSourceStream>) -> Result<Score> {
+    fn score(mut src: ScopedStream<&mut MediaSourceStream<'_>>) -> Result<Score> {
         // Perform simple scoring by testing that the RIFF stream marker and RIFF form are both
         // valid for WAVE.
         let riff_marker = src.read_quad_bytes()?;
@@ -76,8 +77,8 @@ impl Probeable for WavReader {
     }
 }
 
-impl FormatReader for WavReader {
-    fn try_new(mut source: MediaSourceStream, options: FormatOptions) -> Result<Self> {
+impl<'s> BuildFormatReader<'s> for WavReader<'s> {
+    fn try_new(mut source: MediaSourceStream<'s>, options: FormatOptions) -> Result<Self> {
         // The RIFF marker should be present.
         let marker = source.read_quad_bytes()?;
 
@@ -168,7 +169,9 @@ impl FormatReader for WavReader {
             }
         }
     }
+}
 
+impl FormatReader for WavReader<'_> {
     fn format_info(&self) -> &FormatInfo {
         &WAVE_FORMAT_INFO
     }
@@ -261,7 +264,10 @@ impl FormatReader for WavReader {
         Ok(SeekedTo { track_id: 0, actual_ts, required_ts: ts })
     }
 
-    fn into_inner(self: Box<Self>) -> MediaSourceStream {
+    fn into_inner<'s>(self: Box<Self>) -> MediaSourceStream<'s>
+    where
+        Self: 's,
+    {
         self.reader
     }
 }
diff --git a/symphonia-metadata/src/id3v2/mod.rs b/symphonia-metadata/src/id3v2/mod.rs
index ad41b73e..6bdb85c8 100644
--- a/symphonia-metadata/src/id3v2/mod.rs
+++ b/symphonia-metadata/src/id3v2/mod.rs
@@ -410,7 +410,7 @@ impl Probeable for Id3v2Reader {
         &[support_metadata!(ID3V2_METADATA_INFO, &[], &[], &[b"ID3"])]
     }
 
-    fn score(_src: ScopedStream<&mut MediaSourceStream>) -> Result<Score> {
+    fn score(_src: ScopedStream<&mut MediaSourceStream<'_>>) -> Result<Score> {
         Ok(Score::Supported(255))
     }
 }
@@ -424,7 +424,7 @@ impl MetadataReader for Id3v2Reader {
         &ID3V2_METADATA_INFO
     }
 
-    fn read_all(&mut self, reader: &mut MediaSourceStream) -> Result<MetadataRevision> {
+    fn read_all(&mut self, reader: &mut MediaSourceStream<'_>) -> Result<MetadataRevision> {
         let mut builder = MetadataBuilder::new();
         read_id3v2(reader, &mut builder)?;
         Ok(builder.metadata())
diff --git a/symphonia/src/lib.rs b/symphonia/src/lib.rs
index 4a20bd30..a13182d3 100644
--- a/symphonia/src/lib.rs
+++ b/symphonia/src/lib.rs
@@ -187,7 +187,7 @@ pub mod default {
 
         #[deprecated = "use `default::formats::MpaReader` instead"]
         #[cfg(any(feature = "mp1", feature = "mp2", feature = "mp3"))]
-        pub type Mp3Reader = MpaReader;
+        pub type Mp3Reader<'s> = MpaReader<'s>;
     }
 
     use lazy_static::lazy_static;
@@ -269,31 +269,31 @@ pub mod default {
 
         // Formats
         #[cfg(feature = "aac")]
-        probe.register_all::<formats::AdtsReader>();
+        probe.register_all::<formats::AdtsReader<'_>>();
 
         #[cfg(feature = "caf")]
-        probe.register_all::<formats::CafReader>();
+        probe.register_all::<formats::CafReader<'_>>();
 
         #[cfg(feature = "flac")]
-        probe.register_all::<formats::FlacReader>();
+        probe.register_all::<formats::FlacReader<'_>>();
 
         #[cfg(feature = "isomp4")]
-        probe.register_all::<formats::IsoMp4Reader>();
+        probe.register_all::<formats::IsoMp4Reader<'_>>();
 
         #[cfg(any(feature = "mp1", feature = "mp2", feature = "mp3"))]
-        probe.register_all::<formats::MpaReader>();
+        probe.register_all::<formats::MpaReader<'_>>();
 
         #[cfg(feature = "aiff")]
-        probe.register_all::<formats::AiffReader>();
+        probe.register_all::<formats::AiffReader<'_>>();
 
         #[cfg(feature = "wav")]
-        probe.register_all::<formats::WavReader>();
+        probe.register_all::<formats::WavReader<'_>>();
 
         #[cfg(feature = "ogg")]
-        probe.register_all::<formats::OggReader>();
+        probe.register_all::<formats::OggReader<'_>>();
 
         #[cfg(feature = "mkv")]
-        probe.register_all::<formats::MkvReader>();
+        probe.register_all::<formats::MkvReader<'_>>();
 
         // Metadata
         probe.register_all::<Id3v2Reader>();


Test patch:
diff --git a/symphonia-codec-aac/tests/tests.rs b/symphonia-codec-aac/tests/tests.rs
index 863dea88..e45292f0 100644
--- a/symphonia-codec-aac/tests/tests.rs
+++ b/symphonia-codec-aac/tests/tests.rs
@@ -1,7 +1,7 @@
 use symphonia_codec_aac::{AacDecoder, AdtsReader};
 use symphonia_core::codecs::{CodecParameters, Decoder, DecoderOptions, CODEC_TYPE_AAC};
 use symphonia_core::errors;
-use symphonia_core::formats::FormatReader;
+use symphonia_core::formats::{BuildFormatReader, FormatReader};
 use symphonia_core::io::MediaSourceStream;
 
 fn test_decode(data: Vec<u8>) -> symphonia_core::errors::Result<()> {