decoders: implement minimp3-based MP3 decoder

Closes #36.
This commit is contained in:
Erin Moon 2018-05-26 18:33:37 -05:00
parent c5725b8a37
commit 5c54078126
2 changed files with 110 additions and 7 deletions

View file

@ -9,6 +9,8 @@ use Source;
#[cfg(feature = "flac")]
mod flac;
#[cfg(feature = "mp3")]
mod mp3;
#[cfg(feature = "vorbis")]
mod vorbis;
#[cfg(feature = "wav")]
@ -17,15 +19,15 @@ mod wav;
/// Source of audio samples from decoding a file.
///
/// Supports WAV, Vorbis and Flac.
#[cfg(any(feature = "wav", feature = "flac", feature = "vorbis"))]
#[cfg(any(feature = "wav", feature = "flac", feature = "vorbis", feature = "mp3"))]
pub struct Decoder<R>(DecoderImpl<R>)
where
R: Read + Seek;
#[cfg(not(any(feature = "wav", feature = "flac", feature = "vorbis")))]
#[cfg(not(any(feature = "wav", feature = "flac", feature = "vorbis", feature = "mp3")))]
pub struct Decoder<R>(::std::marker::PhantomData<R>);
#[cfg(any(feature = "wav", feature = "flac", feature = "vorbis"))]
#[cfg(any(feature = "wav", feature = "flac", feature = "vorbis", feature = "mp3"))]
enum DecoderImpl<R>
where
R: Read + Seek,
@ -36,6 +38,8 @@ where
Vorbis(vorbis::VorbisDecoder<R>),
#[cfg(feature = "flac")]
Flac(flac::FlacDecoder<R>),
#[cfg(feature = "mp3")]
Mp3(mp3::Mp3Decoder<R>),
}
impl<R> Decoder<R>
@ -71,11 +75,19 @@ where
},
};
#[cfg(feature = "mp3")]
let data = match mp3::Mp3Decoder::new(data) {
Err(data) => data,
Ok(decoder) => {
return Ok(Decoder(DecoderImpl::Mp3(decoder)));
},
};
Err(DecoderError::UnrecognizedFormat)
}
}
#[cfg(not(any(feature = "wav", feature = "flac", feature = "vorbis")))]
#[cfg(not(any(feature = "wav", feature = "flac", feature = "vorbis", feature = "mp3")))]
impl<R> Iterator for Decoder<R>
where
R: Read + Seek,
@ -87,7 +99,7 @@ where
}
}
#[cfg(any(feature = "wav", feature = "flac", feature = "vorbis"))]
#[cfg(any(feature = "wav", feature = "flac", feature = "vorbis", feature = "mp3"))]
impl<R> Iterator for Decoder<R>
where
R: Read + Seek,
@ -103,6 +115,8 @@ where
DecoderImpl::Vorbis(ref mut source) => source.next(),
#[cfg(feature = "flac")]
DecoderImpl::Flac(ref mut source) => source.next(),
#[cfg(feature = "mp3")]
DecoderImpl::Mp3(ref mut source) => source.next(),
}
}
@ -115,11 +129,13 @@ where
DecoderImpl::Vorbis(ref source) => source.size_hint(),
#[cfg(feature = "flac")]
DecoderImpl::Flac(ref source) => source.size_hint(),
#[cfg(feature = "mp3")]
DecoderImpl::Mp3(ref source) => source.size_hint(),
}
}
}
#[cfg(not(any(feature = "wav", feature = "flac", feature = "vorbis")))]
#[cfg(not(any(feature = "wav", feature = "flac", feature = "vorbis", feature = "mp3")))]
impl<R> Source for Decoder<R>
where
R: Read + Seek,
@ -138,7 +154,7 @@ where
}
}
#[cfg(any(feature = "wav", feature = "flac", feature = "vorbis"))]
#[cfg(any(feature = "wav", feature = "flac", feature = "vorbis", feature = "mp3"))]
impl<R> Source for Decoder<R>
where
R: Read + Seek,
@ -152,6 +168,8 @@ where
DecoderImpl::Vorbis(ref source) => source.current_frame_len(),
#[cfg(feature = "flac")]
DecoderImpl::Flac(ref source) => source.current_frame_len(),
#[cfg(feature = "mp3")]
DecoderImpl::Mp3(ref source) => source.current_frame_len(),
}
}
@ -164,6 +182,8 @@ where
DecoderImpl::Vorbis(ref source) => source.channels(),
#[cfg(feature = "flac")]
DecoderImpl::Flac(ref source) => source.channels(),
#[cfg(feature = "mp3")]
DecoderImpl::Mp3(ref source) => source.channels(),
}
}
@ -176,6 +196,8 @@ where
DecoderImpl::Vorbis(ref source) => source.sample_rate(),
#[cfg(feature = "flac")]
DecoderImpl::Flac(ref source) => source.sample_rate(),
#[cfg(feature = "mp3")]
DecoderImpl::Mp3(ref source) => source.sample_rate(),
}
}
@ -188,6 +210,8 @@ where
DecoderImpl::Vorbis(ref source) => source.total_duration(),
#[cfg(feature = "flac")]
DecoderImpl::Flac(ref source) => source.total_duration(),
#[cfg(feature = "mp3")]
DecoderImpl::Mp3(ref source) => source.total_duration(),
}
}
}

79
src/decoder/mp3.rs Normal file
View file

@ -0,0 +1,79 @@
use std::io::{Read, Seek};
use std::time::Duration;
use Source;
use minimp3::{Decoder, Frame};
pub struct Mp3Decoder<R>
where
R: Read + Seek,
{
decoder: Decoder<R>,
current_frame: Frame,
current_frame_offset: usize,
}
impl<R> Mp3Decoder<R>
where
R: Read + Seek,
{
pub fn new(data: R) -> Result<Self, ()> {
let mut decoder = Decoder::new(data);
let current_frame = decoder.next_frame().map_err(|_| ())?;
Ok(Mp3Decoder {
decoder,
current_frame,
current_frame_offset: 0,
})
}
}
impl<R> Source for Mp3Decoder<R>
where
R: Read + Seek
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
Some(self.current_frame.data.len())
}
#[inline]
fn channels(&self) -> u16 {
self.current_frame.channels as _
}
#[inline]
fn sample_rate(&self) -> u32 {
self.current_frame.sample_rate as _
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
None
}
}
impl<R> Iterator for Mp3Decoder<R>
where
R: Read + Seek
{
type Item = i16;
#[inline]
fn next(&mut self) -> Option<i16> {
if self.current_frame_offset == self.current_frame.data.len() {
self.current_frame_offset = 0;
match self.decoder.next_frame() {
Ok(frame) => self.current_frame = frame,
_ => return None,
}
}
let v = self.current_frame.data[self.current_frame_offset];
self.current_frame_offset += 1;
return Some(v);
}
}