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