| 1 | use nihav_core::codecs::*; |
| 2 | use nihav_core::io::byteio::read_u32be; |
| 3 | use nihav_core::io::bitreader::*; |
| 4 | use nihav_codec_support::dsp::qmf::QMF; |
| 5 | |
| 6 | mod mp3data; |
| 7 | mod mp3code; |
| 8 | use mp3code::*; |
| 9 | |
| 10 | const SAMPLES: usize = 1152; |
| 11 | const BYTEBUF_SIZE: usize = 2048; |
| 12 | |
| 13 | #[allow(clippy::large_enum_variant)] |
| 14 | enum LayerData { |
| 15 | MP1, |
| 16 | MP2, |
| 17 | MP3(MP3Data), |
| 18 | } |
| 19 | |
| 20 | impl LayerData { |
| 21 | fn layer_id(&self) -> u8 { |
| 22 | match *self { |
| 23 | LayerData::MP1 => 0, |
| 24 | LayerData::MP2 => 1, |
| 25 | LayerData::MP3(_) => 2, |
| 26 | } |
| 27 | } |
| 28 | fn reset(&mut self) { |
| 29 | match self { |
| 30 | LayerData::MP1 => {}, |
| 31 | LayerData::MP2 => {}, |
| 32 | LayerData::MP3(ref mut data) => data.reset(), |
| 33 | }; |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | struct MPADecoder { |
| 38 | info: NACodecInfoRef, |
| 39 | smap: NAChannelMap, |
| 40 | mmap: NAChannelMap, |
| 41 | qmf: [QMF; 2], |
| 42 | srate: u32, |
| 43 | channels: u8, |
| 44 | sf_idx: usize, |
| 45 | |
| 46 | bytebuf: Vec<u8>, |
| 47 | coeffs: [[f32; SAMPLES]; 2], |
| 48 | out: [[[f32; 32]; 36]; 2], |
| 49 | ctx: LayerData, |
| 50 | } |
| 51 | |
| 52 | impl MPADecoder { |
| 53 | fn new(layer: u8) -> Self { |
| 54 | let ctx = match layer { |
| 55 | 0 => LayerData::MP1, |
| 56 | 1 => LayerData::MP2, |
| 57 | 2 => LayerData::MP3(MP3Data::new()), |
| 58 | _ => unreachable!(), |
| 59 | }; |
| 60 | Self { |
| 61 | info: NACodecInfo::new_dummy(), |
| 62 | smap: NAChannelMap::from_ms_mapping(3), |
| 63 | mmap: NAChannelMap::from_ms_mapping(4), |
| 64 | qmf: [QMF::new(), QMF::new()], |
| 65 | srate: 0, |
| 66 | channels: 0, |
| 67 | sf_idx: 0, |
| 68 | ctx, |
| 69 | |
| 70 | bytebuf: Vec::with_capacity(BYTEBUF_SIZE), |
| 71 | coeffs: [[0.0; SAMPLES]; 2], |
| 72 | out: [[[0.0; 32]; 36]; 2], |
| 73 | } |
| 74 | } |
| 75 | fn read_mp3_side_data(&mut self, br: &mut BitReader, src: &[u8], mono: bool) -> DecoderResult<()> { |
| 76 | if let LayerData::MP3(ref mut ctx) = self.ctx { |
| 77 | let channels = if mono { 1 } else { 2 }; |
| 78 | ctx.mpeg1 = self.sf_idx < 3; |
| 79 | ctx.sf_idx = self.sf_idx; |
| 80 | ctx.read_mp3_side_data(br, channels)?; |
| 81 | let hdr_size = (br.tell() / 8) as usize; |
| 82 | let add_len = src.len() - hdr_size; |
| 83 | if self.bytebuf.len() + add_len > BYTEBUF_SIZE { |
| 84 | self.bytebuf.drain(..self.bytebuf.len() + add_len - BYTEBUF_SIZE); |
| 85 | } |
| 86 | let underrun = self.bytebuf.len() < ctx.main_data_end; |
| 87 | let del_len = if !underrun { self.bytebuf.len() - ctx.main_data_end } else { 0 }; |
| 88 | self.bytebuf.extend_from_slice(&src[hdr_size..]); |
| 89 | self.bytebuf.drain(..del_len); |
| 90 | if underrun { |
| 91 | return Err(DecoderError::MissingReference); |
| 92 | } |
| 93 | |
| 94 | Ok(()) |
| 95 | } else { |
| 96 | Err(DecoderError::Bug) |
| 97 | } |
| 98 | } |
| 99 | fn decode_layer3(&mut self, channels: usize, mode_ext: u8) -> DecoderResult<bool> { |
| 100 | if let LayerData::MP3(ref mut ctx) = self.ctx { |
| 101 | let mut br = BitReader::new(&self.bytebuf, BitReaderMode::BE); |
| 102 | if ctx.mpeg1 { |
| 103 | ctx.decode_mpeg1_layer3(&mut br, &mut self.coeffs, channels)?; |
| 104 | } else { |
| 105 | ctx.decode_mpeg2_layer3(&mut br, &mut self.coeffs, channels, mode_ext)?; |
| 106 | } |
| 107 | let used_data = (br.tell() + 7) / 8; |
| 108 | self.bytebuf.drain(..used_data); |
| 109 | |
| 110 | Ok(true) |
| 111 | } else { |
| 112 | Err(DecoderError::Bug) |
| 113 | } |
| 114 | } |
| 115 | fn synth_layer3(&mut self, mode: u8, mode_ext: u8) { |
| 116 | if let LayerData::MP3(ref mut ctx) = self.ctx { |
| 117 | ctx.synth(&mut self.coeffs, &mut self.out, mode, mode_ext); |
| 118 | } |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | fn apply_ms(ch0: &mut [f32], ch1: &mut [f32]) { |
| 123 | for (l, r) in ch0.iter_mut().zip(ch1) { |
| 124 | let ll = (*l + *r) * std::f32::consts::FRAC_1_SQRT_2; |
| 125 | let rr = (*l - *r) * std::f32::consts::FRAC_1_SQRT_2; |
| 126 | *l = ll; |
| 127 | *r = rr; |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | impl NADecoder for MPADecoder { |
| 132 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { |
| 133 | if let NACodecTypeInfo::Audio(_ainfo) = info.get_properties() { |
| 134 | self.info = info.clone(); |
| 135 | Ok(()) |
| 136 | } else { |
| 137 | Err(DecoderError::InvalidData) |
| 138 | } |
| 139 | } |
| 140 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { |
| 141 | let info = pkt.get_stream().get_info(); |
| 142 | if let NACodecTypeInfo::Audio(_) = info.get_properties() { |
| 143 | let src = pkt.get_buffer(); |
| 144 | |
| 145 | let mut br = BitReader::new(src.as_slice(), BitReaderMode::BE); |
| 146 | |
| 147 | let syncword = br.read(11)?; |
| 148 | validate!(syncword == 0x7FF); |
| 149 | let id = br.read(2)?; |
| 150 | validate!(id != 1); |
| 151 | let layer = (br.read(2)? ^ 3) as u8; |
| 152 | validate!(layer != 3); |
| 153 | let protection = br.read_bool()?; |
| 154 | let bitrate_index = br.read(4)? as usize; |
| 155 | validate!(bitrate_index < 15); |
| 156 | if bitrate_index == 0 { |
| 157 | //todo freeform eventually |
| 158 | unimplemented!(); |
| 159 | } |
| 160 | let mut sf_idx = br.read(2)? as usize; |
| 161 | validate!(sf_idx != 3); |
| 162 | let padding = br.read_bool()?; |
| 163 | let _private = br.read_bool()?; |
| 164 | let mode = br.read(2)? as u8; |
| 165 | let mode_extension = br.read(2)? as u8; |
| 166 | let _copyright = br.read_bool()?; |
| 167 | let _original = br.read_bool()?; |
| 168 | let _emphasis = br.read(2)?; |
| 169 | if !protection { |
| 170 | let _crc_check = br.read(16)?; |
| 171 | } |
| 172 | validate!(layer == self.ctx.layer_id()); |
| 173 | match id { |
| 174 | 0 => sf_idx += 6, |
| 175 | 2 => sf_idx += 3, |
| 176 | _ => {}, |
| 177 | }; |
| 178 | let mpeg1 = id == 3; |
| 179 | let srate = SAMPLING_RATE[sf_idx]; |
| 180 | if self.srate == 0 { |
| 181 | self.srate = srate; |
| 182 | } |
| 183 | validate!(srate == self.srate); |
| 184 | let channels = if mode == 3 { 1 } else { 2 }; |
| 185 | if self.channels == 0 { |
| 186 | self.channels = channels; |
| 187 | } |
| 188 | if channels != self.channels { |
| 189 | self.flush(); |
| 190 | } |
| 191 | let bitrate = BITRATE[if mpeg1 { 0 } else { 1 }][layer as usize][bitrate_index]; |
| 192 | let frame_size = match layer { |
| 193 | 0 => { |
| 194 | ((SAMPLES / 3 / 8 * 1000 * (bitrate as usize) / (srate as usize)) & !3) + if padding { 4 } else { 0 } |
| 195 | }, |
| 196 | 2 if !mpeg1 => { |
| 197 | SAMPLES / 2 / 8 * 1000 * (bitrate as usize) / (srate as usize) + if padding { 1 } else { 0 } |
| 198 | }, |
| 199 | _ => { |
| 200 | SAMPLES / 8 * 1000 * (bitrate as usize) / (srate as usize) + if padding { 1 } else { 0 } |
| 201 | }, |
| 202 | }; |
| 203 | validate!(src.len() >= frame_size); |
| 204 | self.sf_idx = sf_idx; |
| 205 | |
| 206 | let nsamples = if mpeg1 { SAMPLES } else { SAMPLES / 2 }; |
| 207 | |
| 208 | let ainfo = NAAudioInfo::new(srate, channels, SND_F32P_FORMAT, nsamples); |
| 209 | let chmap = if channels == 1 { self.mmap.clone() } else { self.smap.clone() }; |
| 210 | |
| 211 | let mut abuf = alloc_audio_buffer(ainfo, nsamples, chmap)?; |
| 212 | let mut adata = abuf.get_abuf_f32().unwrap(); |
| 213 | let off = if channels == 1 { adata.get_length() } else { adata.get_stride() }; |
| 214 | let buf = adata.get_data_mut().unwrap(); |
| 215 | let (ch0, ch1) = buf.split_at_mut(off); |
| 216 | |
| 217 | match layer { |
| 218 | 0 => unimplemented!(), |
| 219 | 1 => unimplemented!(), |
| 220 | _ => { |
| 221 | let ret = self.read_mp3_side_data(&mut br, &src[..frame_size], channels == 1); |
| 222 | match ret { |
| 223 | Err(DecoderError::MissingReference) => { |
| 224 | abuf.truncate_audio(0); |
| 225 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), abuf); |
| 226 | frm.set_duration(Some(0)); |
| 227 | return Ok(frm.into_ref()); |
| 228 | }, |
| 229 | Err(err) => return Err(err), |
| 230 | Ok(()) => {}, |
| 231 | }; |
| 232 | let has_data = self.decode_layer3(channels as usize, mode_extension)?; |
| 233 | if !has_data { |
| 234 | let frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None); |
| 235 | return Ok(frm.into_ref()); |
| 236 | } |
| 237 | self.synth_layer3(mode, mode_extension); |
| 238 | for (dst, src) in ch0.chunks_exact_mut(32).zip(self.out[0].iter_mut()) { |
| 239 | self.qmf[0].synth(src, dst); |
| 240 | } |
| 241 | if channels == 2 { |
| 242 | for (dst, src) in ch1.chunks_mut(32).zip(self.out[1].iter_mut()) { |
| 243 | self.qmf[1].synth(src, dst); |
| 244 | } |
| 245 | } |
| 246 | }, |
| 247 | }; |
| 248 | |
| 249 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), abuf); |
| 250 | frm.set_duration(Some(nsamples as u64)); |
| 251 | frm.set_keyframe(true); |
| 252 | Ok(frm.into_ref()) |
| 253 | } else { |
| 254 | Err(DecoderError::Bug) |
| 255 | } |
| 256 | } |
| 257 | fn flush(&mut self) { |
| 258 | for qmf in self.qmf.iter_mut() { |
| 259 | *qmf = QMF::new(); |
| 260 | } |
| 261 | self.bytebuf.clear(); |
| 262 | self.ctx.reset(); |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | impl NAOptionHandler for MPADecoder { |
| 267 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } |
| 268 | fn set_options(&mut self, _options: &[NAOption]) { } |
| 269 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } |
| 270 | } |
| 271 | |
| 272 | pub fn get_decoder_mp3() -> Box<dyn NADecoder + Send> { |
| 273 | Box::new(MPADecoder::new(2)) |
| 274 | } |
| 275 | |
| 276 | #[derive(Clone,Copy,Debug)] |
| 277 | struct MPAHeader { |
| 278 | layer: u8, |
| 279 | srate: u32, |
| 280 | channels: u8, |
| 281 | frame_size: usize, |
| 282 | nsamples: usize, |
| 283 | } |
| 284 | |
| 285 | impl PartialEq for MPAHeader { |
| 286 | fn eq(&self, other: &Self) -> bool { |
| 287 | self.layer == other.layer && |
| 288 | self.srate == other.srate && |
| 289 | self.channels == other.channels |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | #[derive(Default)] |
| 294 | struct MPAPacketiser { |
| 295 | buf: Vec<u8>, |
| 296 | hdr: Option<MPAHeader>, |
| 297 | } |
| 298 | |
| 299 | impl MPAPacketiser { |
| 300 | fn new() -> Self { Self::default() } |
| 301 | fn parse_header(&self, off: usize) -> DecoderResult<MPAHeader> { |
| 302 | if self.buf.len() < off + 4 { return Err(DecoderError::ShortData); } |
| 303 | |
| 304 | let mut br = BitReader::new(&self.buf[off..], BitReaderMode::BE); |
| 305 | |
| 306 | let syncword = br.read(11)?; |
| 307 | validate!(syncword == 0x7FF); |
| 308 | let id = br.read(2)?; |
| 309 | validate!(id != 1); |
| 310 | let layer = (br.read(2)? ^ 3) as u8; |
| 311 | validate!(layer != 3); |
| 312 | let _protection = br.read_bool()?; |
| 313 | let bitrate_index = br.read(4)? as usize; |
| 314 | validate!(bitrate_index < 15); |
| 315 | if bitrate_index == 0 { |
| 316 | //todo freeform eventually |
| 317 | unimplemented!(); |
| 318 | } |
| 319 | let mut sf_idx = br.read(2)? as usize; |
| 320 | validate!(sf_idx != 3); |
| 321 | let padding = br.read_bool()?; |
| 322 | let _private = br.read_bool()?; |
| 323 | let mode = br.read(2)? as u8; |
| 324 | |
| 325 | match id { |
| 326 | 0 => sf_idx += 6, |
| 327 | 2 => sf_idx += 3, |
| 328 | _ => {}, |
| 329 | }; |
| 330 | let mpeg1 = id == 3; |
| 331 | let srate = SAMPLING_RATE[sf_idx]; |
| 332 | let channels = if mode == 3 { 1 } else { 2 }; |
| 333 | let bitrate = BITRATE[if mpeg1 { 0 } else { 1 }][layer as usize][bitrate_index]; |
| 334 | let frame_size = match layer { |
| 335 | 0 => { |
| 336 | ((SAMPLES / 3 / 8 * 1000 * (bitrate as usize) / (srate as usize)) & !3) + if padding { 4 } else { 0 } |
| 337 | }, |
| 338 | 2 if !mpeg1 => { |
| 339 | SAMPLES / 2 / 8 * 1000 * (bitrate as usize) / (srate as usize) + if padding { 1 } else { 0 } |
| 340 | }, |
| 341 | _ => { |
| 342 | SAMPLES / 8 * 1000 * (bitrate as usize) / (srate as usize) + if padding { 1 } else { 0 } |
| 343 | }, |
| 344 | }; |
| 345 | let nsamples = if mpeg1 { SAMPLES } else { SAMPLES / 2 }; |
| 346 | |
| 347 | Ok(MPAHeader{ layer, srate, channels, frame_size, nsamples }) |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | impl NAPacketiser for MPAPacketiser { |
| 352 | fn add_data(&mut self, src: &[u8]) -> bool { |
| 353 | self.buf.extend_from_slice(src); |
| 354 | self.buf.len() < 4096 |
| 355 | } |
| 356 | fn parse_stream(&mut self, id: u32) -> DecoderResult<NAStreamRef> { |
| 357 | if self.hdr.is_none() { |
| 358 | if self.buf.len() < 4 { |
| 359 | return Err(DecoderError::ShortData); |
| 360 | } |
| 361 | let hdr = self.parse_header(0)?; |
| 362 | self.hdr = Some(hdr); |
| 363 | } |
| 364 | let hdr = self.hdr.unwrap(); |
| 365 | let mut duration = 0; |
| 366 | if hdr.layer == 2 { // check for Xing/LAME info |
| 367 | let mpeg1 = hdr.srate >= 32000; |
| 368 | let offset = match (mpeg1, hdr.channels) { |
| 369 | (true, 1) => 24, |
| 370 | (true, _) => 36, |
| 371 | (false, 1) => 13, |
| 372 | (false, _) => 21, |
| 373 | }; |
| 374 | if self.buf.len() >= offset + 12 && (&self.buf[offset..][..4] == b"Xing" || &self.buf[offset..][..4] == b"Info") { |
| 375 | let flags = read_u32be(&self.buf[offset + 4..]).unwrap_or(0); |
| 376 | if (flags & 1) != 0 { |
| 377 | duration = u64::from(read_u32be(&self.buf[offset + 8..]).unwrap_or(0)); |
| 378 | } |
| 379 | } |
| 380 | } |
| 381 | let ainfo = NAAudioInfo::new(hdr.srate, hdr.channels, SND_F32P_FORMAT, hdr.nsamples); |
| 382 | let info = NACodecInfo::new("mp3", NACodecTypeInfo::Audio(ainfo), None); |
| 383 | Ok(NAStream::new(StreamType::Audio, id, info, hdr.nsamples as u32, hdr.srate, duration).into_ref()) |
| 384 | } |
| 385 | fn skip_junk(&mut self) -> DecoderResult<usize> { |
| 386 | if self.buf.len() <= 2 { |
| 387 | return Ok(0); |
| 388 | } |
| 389 | let mut off = 0; |
| 390 | let mut hdr = u16::from(self.buf[0]) * 256 + u16::from(self.buf[1]); |
| 391 | let mut iter = self.buf[2..].iter(); |
| 392 | loop { |
| 393 | if (hdr & 0xFFE0) != 0xFFE0 { |
| 394 | let ret = self.parse_header(off); |
| 395 | match ret { |
| 396 | Ok(hdr) => { |
| 397 | if self.hdr.is_none() { |
| 398 | self.hdr = Some(hdr); |
| 399 | } |
| 400 | if self.hdr.unwrap() != hdr { // header is valid but mismatches |
| 401 | self.buf.drain(..off + 1); |
| 402 | return Err(DecoderError::InvalidData); |
| 403 | } |
| 404 | break; |
| 405 | }, |
| 406 | Err(err) => { |
| 407 | self.buf.drain(..off + 1); |
| 408 | return Err(err); |
| 409 | }, |
| 410 | }; |
| 411 | } |
| 412 | off += 1; |
| 413 | if let Some(&b) = iter.next() { |
| 414 | hdr = (hdr << 8) | u16::from(b); |
| 415 | } else { |
| 416 | break; |
| 417 | } |
| 418 | } |
| 419 | self.buf.drain(..off); |
| 420 | Ok(off) |
| 421 | } |
| 422 | fn get_packet(&mut self, stream: NAStreamRef) -> DecoderResult<Option<NAPacket>> { |
| 423 | if self.buf.len() < 4 { |
| 424 | return Err(DecoderError::ShortData); |
| 425 | } |
| 426 | let hdr = self.parse_header(0)?; |
| 427 | if self.hdr.is_none() { |
| 428 | self.hdr = Some(hdr); |
| 429 | } |
| 430 | if self.hdr.unwrap() != hdr { |
| 431 | return Err(DecoderError::InvalidData); |
| 432 | } |
| 433 | if hdr.frame_size <= self.buf.len() { |
| 434 | let mut data = Vec::with_capacity(hdr.frame_size); |
| 435 | data.extend_from_slice(&self.buf[..hdr.frame_size]); |
| 436 | self.buf.drain(..hdr.frame_size); |
| 437 | let ts = NATimeInfo::new(None, None, Some(1), hdr.nsamples as u32, hdr.srate); |
| 438 | Ok(Some(NAPacket::new(stream, ts, true, data))) |
| 439 | } else { |
| 440 | Ok(None) |
| 441 | } |
| 442 | } |
| 443 | fn reset(&mut self) { |
| 444 | self.buf.clear(); |
| 445 | } |
| 446 | fn bytes_left(&self) -> usize { self.buf.len() } |
| 447 | } |
| 448 | |
| 449 | pub fn get_packetiser() -> Box<dyn NAPacketiser + Send> { |
| 450 | Box::new(MPAPacketiser::new()) |
| 451 | } |
| 452 | |
| 453 | #[cfg(test)] |
| 454 | mod test { |
| 455 | use nihav_core::codecs::RegisteredDecoders; |
| 456 | use nihav_core::demuxers::RegisteredDemuxers; |
| 457 | use nihav_codec_support::test::dec_video::test_decode_audio; |
| 458 | use crate::mpeg_register_all_decoders; |
| 459 | use nihav_flash::flash_register_all_demuxers; |
| 460 | use std::io::Read; |
| 461 | use nihav_core::codecs::NAPacketiser; |
| 462 | |
| 463 | #[test] |
| 464 | fn test_mpeg1_layer3_mono() { |
| 465 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 466 | flash_register_all_demuxers(&mut dmx_reg); |
| 467 | let mut dec_reg = RegisteredDecoders::new(); |
| 468 | mpeg_register_all_decoders(&mut dec_reg); |
| 469 | |
| 470 | // sample: https://samples.mplayerhq.hu/FLV/flash_video_5/i_004.flv |
| 471 | let file = "assets/Flash/i_004.flv"; |
| 472 | test_decode_audio("flv", file, Some(6000), None/*Some("mp3_1")*/, &dmx_reg, &dec_reg); |
| 473 | } |
| 474 | #[test] |
| 475 | fn test_mpeg1_layer3_stereo() { |
| 476 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 477 | flash_register_all_demuxers(&mut dmx_reg); |
| 478 | let mut dec_reg = RegisteredDecoders::new(); |
| 479 | mpeg_register_all_decoders(&mut dec_reg); |
| 480 | |
| 481 | // sample: https://samples.mplayerhq.hu/FLV/venture_030_ivcp_001_8bit.flv |
| 482 | let file = "assets/Flash/venture_030_ivcp_001_8bit.flv"; |
| 483 | test_decode_audio("flv", file, Some(7200), None/*Some("mp3_2")*/, &dmx_reg, &dec_reg); |
| 484 | } |
| 485 | #[test] |
| 486 | fn test_mpeg2_layer3() { |
| 487 | let mut dmx_reg = RegisteredDemuxers::new(); |
| 488 | flash_register_all_demuxers(&mut dmx_reg); |
| 489 | let mut dec_reg = RegisteredDecoders::new(); |
| 490 | mpeg_register_all_decoders(&mut dec_reg); |
| 491 | |
| 492 | // sample: https://samples.mplayerhq.hu/FLV/flash_with_alpha/lection2-2.flv |
| 493 | let file = "assets/Flash/lection2-2.flv"; |
| 494 | test_decode_audio("flv", file, Some(6000), None/*Some("mp3_3")*/, &dmx_reg, &dec_reg); |
| 495 | } |
| 496 | #[test] |
| 497 | fn test_mpa_packetiser() { |
| 498 | let mut buf = [0; 16384]; |
| 499 | // sample from a private collection |
| 500 | let mut file = std::fs::File::open("assets/MPEG/1.mp3").unwrap(); |
| 501 | |
| 502 | let mut pkts = super::MPAPacketiser::new(); |
| 503 | file.read_exact(&mut buf).unwrap(); |
| 504 | pkts.add_data(&buf); |
| 505 | let stream = pkts.parse_stream(0).unwrap(); |
| 506 | let mut frame_sizes = Vec::with_capacity(15); |
| 507 | while let Some(pkt) = pkts.get_packet(stream.clone()).unwrap() { |
| 508 | let frame_size = pkt.get_buffer().len(); |
| 509 | println!("pkt size {}", frame_size); |
| 510 | frame_sizes.push(frame_size); |
| 511 | } |
| 512 | assert_eq!(&frame_sizes, &[1044, 1044, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1044, 1045, 1045, 1045]); |
| 513 | } |
| 514 | } |
| 515 | |
| 516 | const BITRATE: [[[u32; 15]; 3]; 2] = [ |
| 517 | [ |
| 518 | [ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 ], |
| 519 | [ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 ], |
| 520 | [ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 ] |
| 521 | ], [ |
| 522 | [ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256 ], |
| 523 | [ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 ], |
| 524 | [ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 ] |
| 525 | ] |
| 526 | ]; |
| 527 | |
| 528 | const SAMPLING_RATE: [u32; 9] = [ 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000 ]; |