Skip to main content

audiobox/mp3/
mod.rs

1//! MPEG-1/2/2.5 Layer III decoding, probing and MPEG-1 CBR encoding.
2mod decoder;
3mod encoder;
4mod tables;
5mod transform;
6use crate::{Audio, DecodeOptions, EncodeOptions, Error, Result};
7pub(crate) use decoder::{DECODER_DELAY, FLUSH, Mp3State, decode, main_data_begin, payload_len};
8pub(crate) use encoder::encode;
9
10#[derive(Clone, Copy, Debug)]
11pub struct Mp3Info {
12    pub sample_rate: u32,
13    pub channels: usize,
14    /// Coded MPEG audio frames, excluding the Info frame; not PCM sample frames.
15    pub frames: usize,
16    pub duration: f64,
17    pub bitrate: u32,
18    pub mpeg_version: u8,
19    /// Encoder priming in source-sample frames (528 for audiobox exports).
20    /// An MPEG decoder adds its own delay; FFmpeg's Layer III delay is 529.
21    pub encoder_delay: usize,
22    /// End padding in the gapless convention, including the decoder-delay credit.
23    /// Exact PCM length is coded frames * samples per MPEG frame - delay - padding.
24    pub encoder_padding: usize,
25}
26#[derive(Clone, Copy, Debug)]
27pub(crate) struct Header {
28    pub version: u8,
29    pub rate: u32,
30    pub channels: usize,
31    pub length: usize,
32    pub side: usize,
33    pub crc: usize,
34    pub mode: u8,
35    pub extension: u8,
36    pub bitrate: u32,
37}
38pub(super) const BITRATES: [u32; 16] = [
39    0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0,
40];
41pub(crate) fn header(bytes: &[u8], at: usize) -> Option<Header> {
42    let b = bytes.get(at..at.checked_add(4)?)?;
43    if b[0] != 255 || b[1] & 224 != 224 || b[1] & 6 != 2 {
44        return None;
45    }
46    let version = match (b[1] >> 3) & 3 {
47        3 => 1,
48        2 => 2,
49        0 => 25,
50        _ => return None,
51    };
52    let index = (b[2] >> 4) as usize;
53    let rate_index = ((b[2] >> 2) & 3) as usize;
54    if index == 0 || index == 15 || rate_index == 3 {
55        return None;
56    }
57    let rate = [44100, 48000, 32000][rate_index]
58        / if version == 1 {
59            1
60        } else if version == 2 {
61            2
62        } else {
63            4
64        };
65    let bitrate = if version == 1 {
66        BITRATES[index]
67    } else {
68        [
69            0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0,
70        ][index]
71    };
72    let mode = b[3] >> 6;
73    let channels = if mode == 3 { 1 } else { 2 };
74    let length = (if version == 1 { 144 } else { 72 }) * bitrate as usize * 1000 / rate as usize
75        + ((b[2] >> 1) & 1) as usize;
76    let side = if version == 1 {
77        if channels == 1 { 17 } else { 32 }
78    } else if channels == 1 {
79        9
80    } else {
81        17
82    };
83    let crc = if b[1] & 1 == 0 { 2 } else { 0 };
84    if length < 4 + side + crc {
85        return None;
86    }
87    Some(Header {
88        version,
89        rate,
90        channels,
91        length,
92        side,
93        crc,
94        mode,
95        extension: (b[3] >> 4) & 3,
96        bitrate,
97    })
98}
99pub(crate) fn tag_size(bytes: &[u8]) -> usize {
100    if !bytes.starts_with(b"ID3") || bytes.len() < 10 {
101        return 0;
102    }
103    10 + ((bytes[6] as usize & 127) << 21)
104        + ((bytes[7] as usize & 127) << 14)
105        + ((bytes[8] as usize & 127) << 7)
106        + (bytes[9] as usize & 127)
107        + if bytes[5] & 16 != 0 { 10 } else { 0 }
108}
109pub(crate) fn find(bytes: &[u8], start: usize) -> Option<(usize, Header)> {
110    for i in start..bytes.len().saturating_sub(3) {
111        if let Some(h) = header(bytes, i) {
112            if i + h.length > bytes.len() {
113                continue;
114            }
115            if i + h.length + 4 <= bytes.len()
116                && bytes.get(i + h.length..i + h.length + 3) != Some(b"TAG")
117            {
118                let next = header(bytes, i + h.length);
119                if next.is_none_or(|n| n.rate != h.rate || n.version != h.version) {
120                    continue;
121                }
122            }
123            return Some((i, h));
124        }
125    }
126    None
127}
128pub(crate) fn has_frame(bytes: &[u8]) -> bool {
129    find(&bytes[..bytes.len().min(8192)], 0).is_some()
130}
131#[derive(Clone, Copy, Default)]
132pub(crate) struct Vbr {
133    pub frames: usize,
134    pub delay: usize,
135    pub padding: usize,
136}
137pub(crate) fn vbr(bytes: &[u8], at: usize, h: Header) -> Result<Option<Vbr>> {
138    let start = at + 4 + h.crc + h.side;
139    let end = at + h.length;
140    let read = |p: usize| -> Result<u32> {
141        Ok(u32::from_be_bytes(
142            bytes
143                .get(p..p + 4)
144                .filter(|_| p + 4 <= end)
145                .ok_or_else(|| Error::decode("Truncated Xing tag"))?
146                .try_into()
147                .unwrap(),
148        ))
149    };
150    if bytes.get(start..start + 4) == Some(b"Xing") || bytes.get(start..start + 4) == Some(b"Info")
151    {
152        let flags = read(start + 4)?;
153        let mut p = start + 8;
154        let mut info = Vbr::default();
155        if flags & 1 != 0 {
156            info.frames = read(p)? as usize;
157            p += 4;
158        }
159        if flags & 2 != 0 {
160            read(p)?;
161            p += 4;
162        }
163        if flags & 4 != 0 {
164            p += 100;
165        }
166        if flags & 8 != 0 {
167            p += 4;
168        }
169        if p + 24 <= end && bytes[p..p + 9].iter().all(|&c| (32..=126).contains(&c)) {
170            let d = (bytes[p + 21] as usize) << 4 | (bytes[p + 22] as usize) >> 4;
171            let pad = ((bytes[p + 22] as usize & 15) << 8) | bytes[p + 23] as usize;
172            if d <= 2304 && pad <= 3456 {
173                info.delay = d;
174                info.padding = pad;
175            }
176        }
177        Ok(Some(info))
178    } else if bytes.get(at + 36..at + 40) == Some(b"VBRI") {
179        Ok(Some(Vbr {
180            frames: read(at + 50)? as usize,
181            ..Default::default()
182        }))
183    } else {
184        Ok(None)
185    }
186}
187pub fn probe_mp3(bytes: &[u8]) -> Result<Mp3Info> {
188    let (at, h) =
189        find(bytes, tag_size(bytes)).ok_or_else(|| Error::decode("No MPEG Layer III frame"))?;
190    let tag = vbr(bytes, at, h)?;
191    let mut pos = at;
192    let mut count = 0usize;
193    let mut size = 0;
194    while let Some(h2) = header(bytes, pos) {
195        if h2.rate != h.rate || h2.channels != h.channels || pos + h2.length > bytes.len() {
196            break;
197        }
198        size += h2.length;
199        count += 1;
200        pos += h2.length;
201    }
202    let audio_frames = count.saturating_sub(usize::from(tag.is_some()));
203    let tag = tag.unwrap_or_default();
204    let samples = audio_frames * if h.version == 1 { 1152 } else { 576 };
205    let samples = samples.saturating_sub(tag.delay + tag.padding);
206    let duration = samples as f64 / h.rate as f64;
207    Ok(Mp3Info {
208        sample_rate: h.rate,
209        channels: h.channels,
210        frames: audio_frames,
211        duration,
212        bitrate: if duration > 0.0 {
213            (size as f64 * 8.0 / duration).round() as u32
214        } else {
215            h.bitrate * 1000
216        },
217        mpeg_version: h.version,
218        encoder_delay: tag.delay,
219        encoder_padding: tag.padding,
220    })
221}
222/// Decode MP3 using the default safety limits.
223pub fn decode_mp3(bytes: &[u8]) -> Result<Audio> {
224    decode(bytes, &DecodeOptions::default())
225}
226pub fn encode_mp3(audio: &Audio, options: &EncodeOptions) -> Result<Vec<u8>> {
227    crate::metadata::validate_options(options, crate::AudioFormat::Mp3)?;
228    encode(audio, options)
229}