/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 | | } |