Commit | Line | Data |
---|---|---|
16cca4d3 | 1 | use nihav_core::codecs::*; |
a091b968 | 2 | use nihav_core::io::byteio::read_u32be; |
16cca4d3 KS |
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; | |
d686ebc4 | 11 | const BYTEBUF_SIZE: usize = 2048; |
16cca4d3 KS |
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 | ||
f27c73df KS |
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(); | |
a091b968 KS |
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 | } | |
f27c73df KS |
381 | let ainfo = NAAudioInfo::new(hdr.srate, hdr.channels, SND_F32P_FORMAT, hdr.nsamples); |
382 | let info = NACodecInfo::new("mp3", NACodecTypeInfo::Audio(ainfo), None); | |
a091b968 | 383 | Ok(NAStream::new(StreamType::Audio, id, info, hdr.nsamples as u32, hdr.srate, duration).into_ref()) |
f27c73df KS |
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 | } | |
7f754c49 | 446 | fn bytes_left(&self) -> usize { self.buf.len() } |
f27c73df KS |
447 | } |
448 | ||
449 | pub fn get_packetiser() -> Box<dyn NAPacketiser + Send> { | |
450 | Box::new(MPAPacketiser::new()) | |
451 | } | |
452 | ||
16cca4d3 KS |
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; | |
f27c73df KS |
460 | use std::io::Read; |
461 | use nihav_core::codecs::NAPacketiser; | |
462 | ||
16cca4d3 KS |
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 | ||
886cde48 | 470 | // sample: https://samples.mplayerhq.hu/FLV/flash_video_5/i_004.flv |
16cca4d3 KS |
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 | ||
886cde48 | 481 | // sample: https://samples.mplayerhq.hu/FLV/venture_030_ivcp_001_8bit.flv |
16cca4d3 KS |
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 | ||
886cde48 | 492 | // sample: https://samples.mplayerhq.hu/FLV/flash_with_alpha/lection2-2.flv |
16cca4d3 KS |
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 | } | |
f27c73df KS |
496 | #[test] |
497 | fn test_mpa_packetiser() { | |
498 | let mut buf = [0; 16384]; | |
886cde48 | 499 | // sample from a private collection |
f27c73df KS |
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 | } | |
16cca4d3 KS |
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 ]; |