mod frame;
mod huffman;
mod id3;
mod imdct;
mod stereo;
mod synthesis;
pub use frame::{ChannelMode, Emphasis, FrameHeader, Layer, MpegVersion};
pub use id3::{Id3Tag, Id3Version};
use crate::{AudioDecoder, AudioError, AudioFrame, AudioResult, ChannelLayout};
use bytes::Bytes;
use huffman::HuffmanDecoder;
use imdct::Imdct;
use oximedia_core::{CodecId, Rational, SampleFormat, Timestamp};
use stereo::StereoProcessor;
use synthesis::SynthesisFilter;
pub struct Mp3Decoder {
state: DecoderState,
imdct: Imdct,
synthesis: SynthesisFilter,
stereo: StereoProcessor,
buffer: Vec<u8>,
decode_buffer: DecodeBuffer,
current_header: Option<FrameHeader>,
sample_count: u64,
id3_tag: Option<Id3Tag>,
skip_id3: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum DecoderState {
Sync,
Ready,
Eof,
}
struct DecodeBuffer {
spectral: [[[f32; 576]; 2]; 2],
pcm: [[f32; 1152]; 2],
}
impl Default for DecodeBuffer {
fn default() -> Self {
Self {
spectral: [[[0.0; 576]; 2]; 2],
pcm: [[0.0; 1152]; 2],
}
}
}
impl Default for Mp3Decoder {
fn default() -> Self {
Self::new()
}
}
impl Mp3Decoder {
#[must_use]
pub fn new() -> Self {
Self {
state: DecoderState::Sync,
imdct: Imdct::new(),
synthesis: SynthesisFilter::new(),
stereo: StereoProcessor::new(),
buffer: Vec::new(),
decode_buffer: DecodeBuffer::default(),
current_header: None,
sample_count: 0,
id3_tag: None,
skip_id3: true,
}
}
pub fn set_parse_id3(&mut self, enable: bool) {
self.skip_id3 = !enable;
}
#[must_use]
pub const fn id3_tag(&self) -> Option<&Id3Tag> {
self.id3_tag.as_ref()
}
fn find_next_frame(&mut self) -> AudioResult<Option<FrameHeader>> {
if !self.skip_id3 && self.buffer.len() >= 10 && &self.buffer[0..3] == b"ID3" {
let tag_size = Id3Tag::get_tag_size(&self.buffer)?;
if self.buffer.len() >= tag_size {
if let Ok((tag, _)) = Id3Tag::parse_v2(&self.buffer) {
self.id3_tag = Some(tag);
}
self.buffer.drain(0..tag_size);
}
}
let sync_pos = match frame::find_sync(&self.buffer) {
Some(pos) => pos,
None => {
if self.buffer.len() > 1 {
self.buffer.drain(0..self.buffer.len() - 1);
}
return Ok(None);
}
};
if sync_pos > 0 {
self.buffer.drain(0..sync_pos);
}
if self.buffer.len() < 4 {
return Ok(None);
}
match FrameHeader::parse(&self.buffer[0..4]) {
Ok(header) => {
if let Some(ref prev_header) = self.current_header {
if !frame::is_compatible(prev_header, &header) {
self.buffer.drain(0..1);
return Ok(None);
}
}
Ok(Some(header))
}
Err(_) => {
self.buffer.drain(0..1);
Ok(None)
}
}
}
fn decode_layer3(&mut self, header: &FrameHeader, data: &[u8]) -> AudioResult<()> {
let mut decoder = HuffmanDecoder::new(data);
let side_info_size = match (header.version, header.channels()) {
(MpegVersion::Mpeg1, 1) => 17,
(MpegVersion::Mpeg1, _) => 32,
(_, 1) => 9,
_ => 17,
};
decoder.skip_bits(side_info_size * 8)?;
let granules = match header.version {
MpegVersion::Mpeg1 => 2,
_ => 1,
};
for gr in 0..granules {
for ch in 0..header.channels() {
self.decode_granule(&mut decoder, header, gr, ch)?;
}
}
if header.channels() == 2 {
for gr in 0..granules {
let mut left = self.decode_buffer.spectral[0][gr];
let mut right = self.decode_buffer.spectral[1][gr];
self.stereo.process(&mut left, &mut right, header.mode);
self.decode_buffer.spectral[0][gr] = left;
self.decode_buffer.spectral[1][gr] = right;
}
}
for ch in 0..header.channels() {
let mut offset = 0;
for gr in 0..granules {
let spectral = &self.decode_buffer.spectral[ch][gr];
let pcm = &mut self.decode_buffer.pcm[ch][offset..];
let mut imdct_out = [0.0f32; 36];
for sb in 0..32 {
let sb_samples = &spectral[sb * 18..(sb + 1) * 18];
self.imdct.imdct36(sb_samples, &mut imdct_out, ch);
let mut synth_out = [0.0f32; 32];
self.synthesis.synthesize(&imdct_out, ch, &mut synth_out);
for (i, &sample) in synth_out.iter().enumerate() {
if offset + i < pcm.len() {
pcm[i] = sample;
}
}
}
offset += header.samples;
}
}
Ok(())
}
fn decode_granule(
&mut self,
decoder: &mut HuffmanDecoder<'_>,
header: &FrameHeader,
granule: usize,
channel: usize,
) -> AudioResult<()> {
let spectral = &mut self.decode_buffer.spectral[channel][granule];
let mut pos = 0;
while pos < 576 && decoder.bit_position() < decoder.data.len() * 8 {
let table = if pos < 192 { 1 } else { 0 };
let linbits = huffman::get_linbits(table);
match decoder.decode(table, linbits) {
Ok(pair) => {
if pos < 576 {
spectral[pos] = f32::from(pair.x);
pos += 1;
}
if pos < 576 {
spectral[pos] = f32::from(pair.y);
pos += 1;
}
}
Err(_) => break,
}
}
Self::requantize(spectral, header);
Ok(())
}
fn requantize(spectral: &mut [f32], _header: &FrameHeader) {
const SCALE: f32 = 1.0 / 32768.0;
for sample in spectral.iter_mut() {
*sample *= SCALE;
*sample = sample.clamp(-1.0, 1.0);
}
}
fn decode_layer2(&mut self, _header: &FrameHeader, _data: &[u8]) -> AudioResult<()> {
Ok(())
}
fn decode_layer1(&mut self, _header: &FrameHeader, _data: &[u8]) -> AudioResult<()> {
Ok(())
}
fn create_audio_frame(&mut self, header: &FrameHeader) -> AudioResult<AudioFrame> {
let channels = header.channels();
let samples_per_channel = header.samples;
let mut output = Vec::with_capacity(samples_per_channel * channels * 4);
for i in 0..samples_per_channel {
for ch in 0..channels {
let sample = self.decode_buffer.pcm[ch][i];
output.extend_from_slice(&sample.to_le_bytes());
}
}
let channel_layout = if channels == 1 {
ChannelLayout::Mono
} else {
ChannelLayout::Stereo
};
let timebase = Rational::new(1, i64::from(header.sample_rate));
let timestamp = Timestamp::new(self.sample_count as i64, timebase);
self.sample_count += samples_per_channel as u64;
Ok(AudioFrame {
format: SampleFormat::F32,
sample_rate: header.sample_rate,
channels: channel_layout,
samples: crate::AudioBuffer::Interleaved(Bytes::from(output)),
timestamp,
})
}
}
impl AudioDecoder for Mp3Decoder {
fn codec(&self) -> CodecId {
CodecId::Mp3
}
fn send_packet(&mut self, data: &[u8], _pts: i64) -> AudioResult<()> {
if self.state == DecoderState::Eof {
return Err(AudioError::Eof);
}
self.buffer.extend_from_slice(data);
self.state = DecoderState::Ready;
Ok(())
}
fn receive_frame(&mut self) -> AudioResult<Option<AudioFrame>> {
if self.state == DecoderState::Eof {
return Ok(None);
}
let header = match self.find_next_frame()? {
Some(h) => h,
None => return Err(AudioError::NeedMoreData),
};
if self.buffer.len() < header.frame_size {
return Err(AudioError::NeedMoreData);
}
let frame_data = self.buffer[4..header.frame_size].to_vec();
match header.layer {
Layer::III => {
self.decode_layer3(&header, &frame_data)?;
}
Layer::II => {
self.decode_layer2(&header, &frame_data)?;
}
Layer::I => {
self.decode_layer1(&header, &frame_data)?;
}
}
self.buffer.drain(0..header.frame_size);
self.current_header = Some(header.clone());
let frame = self.create_audio_frame(&header)?;
Ok(Some(frame))
}
fn flush(&mut self) -> AudioResult<()> {
self.buffer.clear();
self.imdct.reset();
self.synthesis.reset();
self.stereo.reset();
self.current_header = None;
Ok(())
}
fn reset(&mut self) {
self.state = DecoderState::Sync;
self.buffer.clear();
self.decode_buffer = DecodeBuffer::default();
self.imdct.reset();
self.synthesis.reset();
self.stereo.reset();
self.current_header = None;
self.sample_count = 0;
self.id3_tag = None;
}
fn output_format(&self) -> Option<SampleFormat> {
Some(SampleFormat::F32)
}
fn sample_rate(&self) -> Option<u32> {
self.current_header.as_ref().map(|h| h.sample_rate)
}
fn channel_layout(&self) -> Option<ChannelLayout> {
self.current_header.as_ref().map(|h| {
if h.channels() == 1 {
ChannelLayout::Mono
} else {
ChannelLayout::Stereo
}
})
}
}
pub struct Mp3FrameIterator<'a> {
data: &'a [u8],
offset: usize,
}
impl<'a> Mp3FrameIterator<'a> {
#[must_use]
pub const fn new(data: &'a [u8]) -> Self {
Self { data, offset: 0 }
}
}
impl<'a> Iterator for Mp3FrameIterator<'a> {
type Item = AudioResult<(FrameHeader, &'a [u8])>;
fn next(&mut self) -> Option<Self::Item> {
if self.offset >= self.data.len() {
return None;
}
let sync_pos = match frame::find_sync(&self.data[self.offset..]) {
Some(pos) => self.offset + pos,
None => return None,
};
self.offset = sync_pos;
if self.offset + 4 > self.data.len() {
return None;
}
let header = match FrameHeader::parse(&self.data[self.offset..self.offset + 4]) {
Ok(h) => h,
Err(e) => {
self.offset += 1;
return Some(Err(e));
}
};
if self.offset + header.frame_size > self.data.len() {
return None;
}
let frame_data = &self.data[self.offset..self.offset + header.frame_size];
self.offset += header.frame_size;
Some(Ok((header, frame_data)))
}
}
#[must_use]
pub fn calculate_average_bitrate(frames: &[(FrameHeader, &[u8])]) -> u32 {
if frames.is_empty() {
return 0;
}
let total_bits: u64 = frames.iter().map(|(h, _)| u64::from(h.bitrate)).sum();
#[allow(clippy::cast_possible_truncation)]
let result = (total_bits / frames.len() as u64) as u32;
result
}
#[must_use]
pub fn is_vbr(frames: &[(FrameHeader, &[u8])]) -> bool {
if frames.len() < 2 {
return false;
}
let first_bitrate = frames[0].0.bitrate;
frames.iter().any(|(h, _)| h.bitrate != first_bitrate)
}