1use crate::mp4::{CodecConfig, PcmConfig};
2
3use super::demux::Demux;
4use crate::media::{Error, Result};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7enum Kind {
8 U8,
9 S8,
10 S16,
11 S24,
12 S32,
13 F32,
14 F64,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub struct Pcm {
19 kind: Kind,
20 big_endian: bool,
21 channels: u16,
22 rate: u32,
23}
24
25impl Pcm {
26 pub fn new(
27 bits: u16,
28 float: bool,
29 signed: bool,
30 big_endian: bool,
31 channels: u64,
32 rate: f64,
33 ) -> Result<Pcm> {
34 let kind = match (float, bits) {
35 (false, 8) if !signed => Kind::U8,
36 (false, 8) => Kind::S8,
37 (false, 16) => Kind::S16,
38 (false, 24) => Kind::S24,
39 (false, 32) => Kind::S32,
40 (true, 32) => Kind::F32,
41 (true, 64) => Kind::F64,
42 _ => {
43 let form = match (float, signed) {
44 (true, _) => "float",
45 (false, true) => "signed",
46 (false, false) => "unsigned",
47 };
48 return Err(Error::Unsupported(format!("{form} {bits}-bit PCM")));
49 }
50 };
51 if !(1..=64).contains(&channels) {
52 return Err(Error::Invalid(format!("PCM with {channels} channels")));
53 }
54 if !rate.is_finite() || !(1000.0..=768_000.0).contains(&rate) {
55 return Err(Error::Invalid(format!("PCM at {rate} Hz")));
56 }
57 Ok(Pcm {
58 kind,
59 big_endian,
60 channels: channels as u16,
61 rate: rate.round() as u32,
62 })
63 }
64
65 pub fn from_mp4(p: &PcmConfig) -> Result<Pcm> {
66 Pcm::new(
67 p.bits,
68 p.float,
69 p.signed,
70 p.big_endian,
71 p.channels as u64,
72 p.sample_rate,
73 )
74 }
75
76 fn width(&self) -> usize {
77 match self.kind {
78 Kind::U8 | Kind::S8 => 1,
79 Kind::S16 => 2,
80 Kind::S24 => 3,
81 Kind::S32 | Kind::F32 => 4,
82 Kind::F64 => 8,
83 }
84 }
85
86 pub fn decode(&self, data: &[u8], out: &mut Vec<f32>) -> Result<()> {
87 let w = self.width();
88 let frame = w * self.channels as usize;
89 if !data.len().is_multiple_of(frame) {
90 return Err(Error::Invalid(format!(
91 "a PCM packet of {} bytes, not whole {frame}-byte frames",
92 data.len()
93 )));
94 }
95 out.clear();
96 out.reserve(data.len() / w);
97 let be = self.big_endian;
98 match self.kind {
99 Kind::U8 => out.extend(data.iter().map(|&b| (b as f32 - 128.0) / 128.0)),
100 Kind::S8 => out.extend(data.iter().map(|&b| b as i8 as f32 / 128.0)),
101 Kind::S16 => out.extend(data.chunks_exact(2).map(|c| {
102 let v = [c[0], c[1]];
103 let s = if be {
104 i16::from_be_bytes(v)
105 } else {
106 i16::from_le_bytes(v)
107 };
108 s as f32 / 32768.0
109 })),
110 Kind::S24 => out.extend(data.chunks_exact(3).map(|c| {
111 let v = if be {
112 [c[0], c[1], c[2], 0]
113 } else {
114 [c[2], c[1], c[0], 0]
115 };
116 (i32::from_be_bytes(v) >> 8) as f32 / 8_388_608.0
117 })),
118 Kind::S32 => out.extend(data.chunks_exact(4).map(|c| {
119 let v = [c[0], c[1], c[2], c[3]];
120 let s = if be {
121 i32::from_be_bytes(v)
122 } else {
123 i32::from_le_bytes(v)
124 };
125 s as f32 / 2_147_483_648.0
126 })),
127 Kind::F32 => out.extend(data.chunks_exact(4).map(|c| {
128 let v = [c[0], c[1], c[2], c[3]];
129 if be {
130 f32::from_be_bytes(v)
131 } else {
132 f32::from_le_bytes(v)
133 }
134 })),
135 Kind::F64 => out.extend(data.chunks_exact(8).map(|c| {
136 let v = [c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]];
137 (if be {
138 f64::from_be_bytes(v)
139 } else {
140 f64::from_le_bytes(v)
141 }) as f32
142 })),
143 }
144 Ok(())
145 }
146}
147
148pub enum Sound {
149 Aac(Box<crate::aac::Decoder>),
150 #[cfg(feature = "ac3")]
151 Ac3(Box<crate::ac3::Decoder>),
152 #[cfg(feature = "opus")]
153 Opus(Box<crate::opus::Decoder>),
154 #[cfg(feature = "mp3")]
155 Mp3(Box<crate::mp3::Decoder>),
156 Pcm(Pcm),
157}
158
159fn unsupported(name: &str) -> Error {
160 Error::Unsupported(format!(
161 "our audio decoders read AAC, AC-3, E-AC-3, Opus, MP3 and PCM, not {}",
162 if name.is_empty() {
163 "this track's codec"
164 } else {
165 name
166 }
167 ))
168}
169
170fn mkv_pcm(t: &crate::mkv::Track) -> Result<Pcm> {
171 let a = t.audio.clone().unwrap_or_default();
172 let (float, big_endian) = match t.codec_id.as_str() {
173 "A_PCM/INT/LIT" => (false, false),
174 "A_PCM/INT/BIG" => (false, true),
175 "A_PCM/FLOAT/IEEE" => (true, false),
176 id => return Err(unsupported(id)),
177 };
178 let bits = a.bit_depth.unwrap_or(if float { 32 } else { 16 });
179 let bits = u16::try_from(bits).map_err(|_| Error::Invalid(format!("{bits}-bit PCM")))?;
180 Pcm::new(
181 bits,
182 float,
183 bits != 8,
184 big_endian,
185 a.channels,
186 a.sampling_frequency,
187 )
188}
189
190#[cfg(feature = "opus")]
191fn dops(e: &crate::mp4::SampleEntry) -> Option<&[u8]> {
192 let extra = match e.audio.as_ref().map_or(0, |a| a.qt_version) {
193 1 => 16,
194 2 => 36,
195 _ => 0,
196 };
197 let mut rest = e.raw.get(28 + extra..)?;
198 while rest.len() >= 8 {
199 let size = u32::from_be_bytes(rest.get(..4)?.try_into().ok()?) as usize;
200 if size < 8 || size > rest.len() {
201 return None;
202 }
203 if rest.get(4..8)? == b"dOps" {
204 return rest.get(8..size);
205 }
206 rest = rest.get(size..)?;
207 }
208 None
209}
210
211impl Sound {
212 #[cfg(feature = "mp3")]
213 fn mp3(rate: f64, channels: u64) -> Sound {
214 let rate = if (1.0..=768_000.0).contains(&rate) {
215 rate.round() as u32
216 } else {
217 0
218 };
219 Sound::Mp3(Box::new(crate::mp3::Decoder::with_format(
220 rate,
221 channels.min(2) as u16,
222 )))
223 }
224
225 pub fn open(d: &Demux, track: usize) -> Result<Sound> {
226 match d {
227 Demux::Mp4(r) => {
228 let t = r
229 .tracks
230 .get(track)
231 .ok_or_else(|| Error::Invalid(format!("no track {track}")))?;
232 let Some(e) = t.entry() else {
233 return Err(unsupported(""));
234 };
235 match &e.codec {
236 CodecConfig::Aac(_) => {
237 let asc = t.extradata().ok_or_else(|| {
238 Error::Invalid("AAC track without a config".to_string())
239 })?;
240 Ok(Sound::Aac(Box::new(crate::aac::Decoder::new(&asc)?)))
241 }
242 CodecConfig::Pcm(p) => Ok(Sound::Pcm(Pcm::from_mp4(p)?)),
243 #[cfg(feature = "ac3")]
244 CodecConfig::Other(f) if &f.0 == b"ac-3" || &f.0 == b"ec-3" => {
245 Ok(Sound::Ac3(Box::new(crate::ac3::Decoder::new(
246 t.sample_rate(),
247 t.channels() as u16,
248 ))))
249 }
250 #[cfg(feature = "mp3")]
251 CodecConfig::Mp3 => {
252 let a = e.audio.clone().unwrap_or_default();
253 Ok(Sound::mp3(a.sample_rate, a.channels as u64))
254 }
255 #[cfg(feature = "opus")]
256 CodecConfig::Other(f) if &f.0 == b"Opus" => {
257 let head = dops(e).ok_or_else(|| {
258 Error::Invalid("Opus track without a dOps box".to_string())
259 })?;
260 let head = crate::opus::OpusHead::from_dops(head)?;
261 Ok(Sound::Opus(Box::new(crate::opus::Decoder::from_head(
262 head, 48000,
263 )?)))
264 }
265 other => Err(unsupported(&other.name())),
266 }
267 }
268 Demux::Mkv(r) => {
269 let t = r
270 .tracks
271 .get(track)
272 .ok_or_else(|| Error::Invalid(format!("no track {track}")))?;
273 match t.codec_name() {
274 "aac" => {
275 let asc = t.extradata().ok_or_else(|| {
276 Error::Invalid("AAC track without a config".to_string())
277 })?;
278 Ok(Sound::Aac(Box::new(crate::aac::Decoder::new(&asc)?)))
279 }
280 #[cfg(feature = "opus")]
281 "opus" => Ok(Sound::Opus(Box::new(crate::opus::Decoder::new(
282 &t.codec_private,
283 )?))),
284 "pcm" => Ok(Sound::Pcm(mkv_pcm(t)?)),
285 #[cfg(feature = "ac3")]
286 "ac3" | "eac3" => Ok(Sound::Ac3(Box::new(crate::ac3::Decoder::new(
287 t.sample_rate(),
288 t.channels() as u16,
289 )))),
290 #[cfg(feature = "mp3")]
291 "mp3" | "mp2" | "mp1" => {
292 let a = t.audio.clone().unwrap_or_default();
293 Ok(Sound::mp3(a.sampling_frequency, a.channels))
294 }
295 name => Err(unsupported(name)),
296 }
297 }
298 }
299 }
300
301 pub fn rate(&self) -> u32 {
302 match self {
303 Sound::Aac(d) => d.rate(),
304 #[cfg(feature = "ac3")]
305 Sound::Ac3(d) => d.rate(),
306 #[cfg(feature = "opus")]
307 Sound::Opus(d) => d.sample_rate(),
308 #[cfg(feature = "mp3")]
309 Sound::Mp3(d) => d.rate(),
310 Sound::Pcm(p) => p.rate,
311 }
312 }
313
314 pub fn channels(&self) -> u16 {
315 match self {
316 Sound::Aac(d) => d.channels(),
317 #[cfg(feature = "ac3")]
318 Sound::Ac3(d) => d.channels(),
319 #[cfg(feature = "opus")]
320 Sound::Opus(d) => d.channels() as u16,
321 #[cfg(feature = "mp3")]
322 Sound::Mp3(d) => d.channels(),
323 Sound::Pcm(p) => p.channels,
324 }
325 }
326
327 pub fn pcm_frames(&self, bytes: u32) -> Option<u64> {
328 match self {
329 Sound::Pcm(p) => Some(bytes as u64 / (p.width() * p.channels as usize).max(1) as u64),
330 Sound::Aac(_) => None,
331 #[cfg(feature = "ac3")]
332 Sound::Ac3(_) => None,
333 #[cfg(feature = "opus")]
334 Sound::Opus(_) => None,
335 #[cfg(feature = "mp3")]
336 Sound::Mp3(_) => None,
337 }
338 }
339
340 pub fn pre_roll(&self) -> f64 {
341 match self {
342 #[cfg(feature = "opus")]
343 Sound::Opus(_) => 0.08,
344 #[cfg(feature = "ac3")]
345 Sound::Ac3(d) => 1536.0 / d.rate().max(1) as f64,
346 #[cfg(feature = "mp3")]
347 Sound::Mp3(_) => 0.2,
348 Sound::Aac(_) | Sound::Pcm(_) => 0.0,
349 }
350 }
351
352 pub fn decode(&mut self, data: &[u8], out: &mut Vec<f32>) -> Result<u16> {
353 match self {
354 Sound::Aac(d) => {
355 let b = d.decode_frame(data)?;
356 *out = b.samples;
357 Ok(b.channels)
358 }
359 #[cfg(feature = "opus")]
360 Sound::Opus(d) => {
361 out.clear();
362 d.decode_into(Some(data), out)?;
363 Ok(d.channels() as u16)
364 }
365 #[cfg(feature = "ac3")]
366 Sound::Ac3(d) => {
367 d.decode_into(data, out)?;
368 Ok(d.channels())
369 }
370 #[cfg(feature = "mp3")]
371 Sound::Mp3(d) => {
372 d.decode_packet(data, out)?;
373 Ok(d.channels())
374 }
375 Sound::Pcm(p) => {
376 p.decode(data, out)?;
377 Ok(p.channels)
378 }
379 }
380 }
381}