Coverage Report

Created: 2026-08-01 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/symphonia/symphonia-bundle-mp3/src/decoder.rs
Line
Count
Source
1
// Symphonia
2
// Copyright (c) 2019-2026 The Project Symphonia Developers.
3
//
4
// This Source Code Form is subject to the terms of the Mozilla Public
5
// License, v. 2.0. If a copy of the MPL was not distributed with this
6
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
8
use symphonia_core::audio::{AsGenericAudioBufferRef, Audio, AudioBuffer, GenericAudioBufferRef};
9
use symphonia_core::codecs::CodecInfo;
10
use symphonia_core::codecs::audio::{
11
    AudioCodecId, AudioCodecParameters, AudioDecoder, AudioDecoderOptions, FinalizeResult,
12
};
13
use symphonia_core::codecs::registry::{RegisterableAudioDecoder, SupportedAudioCodec};
14
use symphonia_core::errors::{Result, decode_error, unsupported_error};
15
use symphonia_core::io::FiniteStream;
16
use symphonia_core::packet::PacketRef;
17
use symphonia_core::support_audio_codec;
18
19
#[cfg(feature = "mp1")]
20
use symphonia_core::codecs::audio::well_known::CODEC_ID_MP1;
21
#[cfg(feature = "mp2")]
22
use symphonia_core::codecs::audio::well_known::CODEC_ID_MP2;
23
#[cfg(feature = "mp3")]
24
use symphonia_core::codecs::audio::well_known::CODEC_ID_MP3;
25
26
use super::{common::*, header};
27
28
#[cfg(feature = "mp1")]
29
use crate::layer1;
30
#[cfg(feature = "mp2")]
31
use crate::layer2;
32
#[cfg(feature = "mp3")]
33
use crate::layer3;
34
35
enum State {
36
    #[cfg(feature = "mp1")]
37
    Layer1(layer1::Layer1),
38
    #[cfg(feature = "mp2")]
39
    Layer2(layer2::Layer2),
40
    #[cfg(feature = "mp3")]
41
    Layer3(Box<layer3::Layer3>),
42
}
43
44
impl State {
45
3.63k
    fn new(codec: AudioCodecId) -> Self {
46
3.63k
        match codec {
47
            #[cfg(feature = "mp1")]
48
494
            CODEC_ID_MP1 => State::Layer1(layer1::Layer1::new()),
49
            #[cfg(feature = "mp2")]
50
582
            CODEC_ID_MP2 => State::Layer2(layer2::Layer2::new()),
51
            #[cfg(feature = "mp3")]
52
2.55k
            CODEC_ID_MP3 => State::Layer3(Box::new(layer3::Layer3::new())),
53
0
            _ => unreachable!(),
54
        }
55
3.63k
    }
56
}
57
58
/// MPEG1 and MPEG2 audio layer 1, 2, and 3 decoder.
59
pub struct MpaDecoder {
60
    opts: AudioDecoderOptions,
61
    params: AudioCodecParameters,
62
    state: State,
63
    buf: AudioBuffer<f32>,
64
}
65
66
impl MpaDecoder {
67
3.63k
    pub fn try_new(params: &AudioCodecParameters, opts: &AudioDecoderOptions) -> Result<Self> {
68
        // This decoder only supports MP1, MP2, and MP3.
69
3.63k
        match params.codec {
70
            #[cfg(feature = "mp1")]
71
494
            CODEC_ID_MP1 => (),
72
            #[cfg(feature = "mp2")]
73
582
            CODEC_ID_MP2 => (),
74
            #[cfg(feature = "mp3")]
75
2.55k
            CODEC_ID_MP3 => (),
76
0
            _ => return unsupported_error("mpa: invalid codec"),
77
        }
78
79
        // Create decoder state.
80
3.63k
        let state = State::new(params.codec);
81
82
3.63k
        Ok(MpaDecoder { opts: *opts, params: params.clone(), state, buf: Default::default() })
83
3.63k
    }
84
85
99.1k
    fn decode_inner(&mut self, packet: &PacketRef<'_>) -> Result<()> {
86
99.1k
        let mut reader = packet.as_buf_reader();
87
88
99.1k
        let header = header::read_frame_header(&mut reader)?;
89
90
        // The packet should be the size stated in the header.
91
99.0k
        if header.frame_size != reader.bytes_available() as usize {
92
98
            return decode_error("mpa: invalid packet length");
93
98.9k
        }
94
95
        // The audio buffer can only be created after the first frame is decoded.
96
98.9k
        if self.buf.is_unused() {
97
3.37k
            self.buf = AudioBuffer::new(header.spec(), 1152);
98
3.37k
        }
99
        else {
100
            // Ensure the packet contains an audio frame with the same signal specification as the
101
            // buffer.
102
            //
103
            // TODO: Is it worth it to support changing signal specifications?
104
95.5k
            if self.buf.spec() != &header.spec() {
105
17.9k
                return decode_error("mpa: invalid audio buffer signal spec for packet");
106
77.5k
            }
107
        }
108
109
        // Clear the audio buffer.
110
80.9k
        self.buf.clear();
111
112
        // Choose the decode step based on the MPEG layer and the current codec ID.
113
3.53k
        match &mut self.state {
114
            #[cfg(feature = "mp1")]
115
3.53k
            State::Layer1(layer) if header.layer == MpegLayer::Layer1 => {
116
3.32k
                layer.decode(&mut reader, &header, &mut self.buf)?;
117
            }
118
            #[cfg(feature = "mp2")]
119
11.5k
            State::Layer2(layer) if header.layer == MpegLayer::Layer2 => {
120
10.7k
                layer.decode(&mut reader, &header, &mut self.buf)?;
121
            }
122
            #[cfg(feature = "mp3")]
123
65.8k
            State::Layer3(layer) if header.layer == MpegLayer::Layer3 => {
124
51.8k
                layer.decode(&mut reader, &header, &mut self.buf)?;
125
            }
126
15.0k
            _ => return decode_error("mpa: invalid mpeg audio layer"),
127
        }
128
129
        // Trim gaps.
130
22.8k
        if self.opts.gapless {
131
22.8k
            self.buf.trim(packet.trim_start.get() as usize, packet.trim_end.get() as usize);
132
22.8k
        }
133
134
22.8k
        Ok(())
135
99.1k
    }
136
}
137
138
impl AudioDecoder for MpaDecoder {
139
0
    fn codec_info(&self) -> &CodecInfo {
140
        // Return the codec that's in-use.
141
0
        &Self::supported_codecs()
142
0
            .iter()
143
0
            .find(|desc| desc.id == self.params.codec)
144
0
            .expect("codec registered in supported_codecs")
145
            .info
146
0
    }
147
148
0
    fn codec_params(&self) -> &AudioCodecParameters {
149
0
        &self.params
150
0
    }
151
152
0
    fn reset(&mut self) {
153
        // Fully reset the decoder state.
154
0
        self.state = State::new(self.params.codec);
155
0
    }
156
157
99.1k
    fn decode_ref(&mut self, packet: &PacketRef<'_>) -> Result<GenericAudioBufferRef<'_>> {
158
99.1k
        if let Err(e) = self.decode_inner(packet) {
159
76.3k
            self.buf.clear();
160
76.3k
            Err(e)
161
        }
162
        else {
163
22.8k
            Ok(self.buf.as_generic_audio_buffer_ref())
164
        }
165
99.1k
    }
166
167
0
    fn finalize(&mut self) -> FinalizeResult {
168
0
        Default::default()
169
0
    }
170
171
0
    fn last_decoded(&self) -> GenericAudioBufferRef<'_> {
172
0
        self.buf.as_generic_audio_buffer_ref()
173
0
    }
174
}
175
176
impl RegisterableAudioDecoder for MpaDecoder {
177
3.63k
    fn try_registry_new(
178
3.63k
        params: &AudioCodecParameters,
179
3.63k
        opts: &AudioDecoderOptions,
180
3.63k
    ) -> Result<Box<dyn AudioDecoder>>
181
3.63k
    where
182
3.63k
        Self: Sized,
183
    {
184
3.63k
        Ok(Box::new(MpaDecoder::try_new(params, opts)?))
185
3.63k
    }
186
187
1.37k
    fn supported_codecs() -> &'static [SupportedAudioCodec] {
188
1.37k
        &[
189
1.37k
            #[cfg(feature = "mp1")]
190
1.37k
            support_audio_codec!(CODEC_ID_MP1, "mp1", "MPEG Audio Layer 1"),
191
1.37k
            #[cfg(feature = "mp2")]
192
1.37k
            support_audio_codec!(CODEC_ID_MP2, "mp2", "MPEG Audio Layer 2"),
193
1.37k
            #[cfg(feature = "mp3")]
194
1.37k
            support_audio_codec!(CODEC_ID_MP3, "mp3", "MPEG Audio Layer 3"),
195
1.37k
        ]
196
1.37k
    }
197
}