1mod 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 pub frames: usize,
16 pub duration: f64,
17 pub bitrate: u32,
18 pub mpeg_version: u8,
19 pub encoder_delay: usize,
22 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}
222pub 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}