1use crate::bitreader::BitReader;
12use crate::crc::{crc8, crc16};
13use crate::frame::ChannelAssignment;
14use crate::metadata::{SEEKPOINT_PLACEHOLDER, SeekPoint};
15
16pub struct DecodedFrames {
18 pub interleaved: Vec<i32>,
20 pub channels: u32,
21 pub bits_per_sample: u32,
22 pub sample_rate: u32,
23}
24
25pub fn decode_frames(data: &[u8]) -> Option<DecodedFrames> {
30 let mut br = BitReader::new(data);
31 let mut interleaved = Vec::new();
32 let mut channels = 0u32;
33 let mut bits_per_sample = 0u32;
34 let mut sample_rate = 0u32;
35
36 while br.byte_pos() < data.len() {
37 let frame = decode_frame(&mut br, data)?;
38 channels = frame.channels;
39 bits_per_sample = frame.bits_per_sample;
40 sample_rate = frame.sample_rate;
41 for i in 0..frame.blocksize {
42 for ch in &frame.samples {
43 interleaved.push(ch[i]);
44 }
45 }
46 }
47
48 Some(DecodedFrames {
49 interleaved,
50 channels,
51 bits_per_sample,
52 sample_rate,
53 })
54}
55
56pub struct DecodedStream {
58 pub interleaved: Vec<i32>,
59 pub channels: u32,
60 pub bits_per_sample: u32,
61 pub sample_rate: u32,
62 pub total_samples: u64,
63 pub md5: [u8; 16],
65 pub md5_ok: bool,
68 pub seek_points: Vec<SeekPoint>,
71}
72
73pub fn decode(data: &[u8]) -> Option<DecodedStream> {
78 let mut br = BitReader::new(data);
79 let (info, seek_points) = parse_header(&mut br)?;
80
81 let mut interleaved = Vec::new();
82 while br.byte_pos() < data.len() {
83 let frame = decode_frame(&mut br, data)?;
84 for i in 0..frame.blocksize {
85 for ch in &frame.samples {
86 interleaved.push(ch[i]);
87 }
88 }
89 }
90 if info.total_samples > 0 {
92 interleaved.truncate(info.total_samples as usize * info.channels as usize);
93 }
94
95 let md5_ok = info.md5 == [0u8; 16] || {
96 let computed =
97 crate::md5::audio_md5(&interleaved, info.bits_per_sample.div_ceil(8) as usize);
98 computed == info.md5
99 };
100
101 Some(DecodedStream {
102 interleaved,
103 channels: info.channels,
104 bits_per_sample: info.bits_per_sample,
105 sample_rate: info.sample_rate,
106 total_samples: info.total_samples,
107 md5: info.md5,
108 md5_ok,
109 seek_points,
110 })
111}
112
113fn parse_header(br: &mut BitReader) -> Option<(StreamInfo, Vec<SeekPoint>)> {
116 if br.read_raw_u32(32)? != 0x664c_6143 {
117 return None; }
119 let mut info: Option<StreamInfo> = None;
120 let mut seek_points: Vec<SeekPoint> = Vec::new();
121 loop {
122 let is_last = br.read_raw_u32(1)? == 1;
123 let block_type = br.read_raw_u32(7)?;
124 let length = br.read_raw_u32(24)? as usize;
125 if block_type == 0 {
126 let _min_bs = br.read_raw_u32(16)?;
128 let _max_bs = br.read_raw_u32(16)?;
129 let _min_fs = br.read_raw_u32(24)?;
130 let _max_fs = br.read_raw_u32(24)?;
131 let sample_rate = br.read_raw_u32(20)?;
132 let channels = br.read_raw_u32(3)? + 1;
133 let bits_per_sample = br.read_raw_u32(5)? + 1;
134 let total_samples = br.read_raw_u64(36)?;
135 let mut md5 = [0u8; 16];
136 for b in &mut md5 {
137 *b = br.read_raw_u32(8)? as u8;
138 }
139 info = Some(StreamInfo {
140 sample_rate,
141 channels,
142 bits_per_sample,
143 total_samples,
144 md5,
145 });
146 } else if block_type == 3 {
147 let n = length / 18;
149 seek_points = Vec::with_capacity(n);
150 for _ in 0..n {
151 let sample_number = br.read_raw_u64(64)?;
152 let stream_offset = br.read_raw_u64(64)?;
153 let frame_samples = br.read_raw_u32(16)?;
154 seek_points.push(SeekPoint {
155 sample_number,
156 stream_offset,
157 frame_samples,
158 });
159 }
160 br.skip_bytes(length - n * 18)?;
162 } else {
163 br.skip_bytes(length)?;
164 }
165 if is_last {
166 break;
167 }
168 }
169 Some((info?, seek_points))
170}
171
172pub struct SeekResult {
175 pub interleaved: Vec<i32>,
177 pub first_sample: u64,
179 pub channels: u32,
180 pub bits_per_sample: u32,
181 pub sample_rate: u32,
182}
183
184fn seek_start(seek_points: &[SeekPoint], target: u64) -> (u64, u64) {
189 let mut best = (0u64, 0u64);
190 for p in seek_points {
191 if p.sample_number != SEEKPOINT_PLACEHOLDER
192 && p.sample_number <= target
193 && p.sample_number >= best.0
194 {
195 best = (p.sample_number, p.stream_offset);
196 }
197 }
198 best
199}
200
201pub fn decode_seek(data: &[u8], target_sample: u64) -> Option<SeekResult> {
207 let mut br = BitReader::new(data);
208 let (info, seek_points) = parse_header(&mut br)?;
209 if info.total_samples != 0 && target_sample >= info.total_samples {
210 return None;
211 }
212 let audio_offset = br.byte_pos();
213
214 let (start_sample, start_offset) = seek_start(&seek_points, target_sample);
215 let start_byte = audio_offset.checked_add(start_offset as usize)?;
216 let frames = data.get(start_byte..)?;
217
218 let mut fbr = BitReader::new(frames);
219 let mut current = start_sample;
220 let mut interleaved = Vec::new();
221 while fbr.byte_pos() < frames.len() {
222 let frame = decode_frame(&mut fbr, frames)?;
223 let frame_end = current + frame.blocksize as u64;
224 if frame_end > target_sample {
226 let skip = target_sample.saturating_sub(current) as usize;
227 for i in skip..frame.blocksize {
228 for ch in &frame.samples {
229 interleaved.push(ch[i]);
230 }
231 }
232 }
233 current = frame_end;
234 }
235 if info.total_samples != 0 {
236 let want = (info.total_samples - target_sample) as usize * info.channels as usize;
237 interleaved.truncate(want);
238 }
239
240 Some(SeekResult {
241 interleaved,
242 first_sample: target_sample,
243 channels: info.channels,
244 bits_per_sample: info.bits_per_sample,
245 sample_rate: info.sample_rate,
246 })
247}
248
249pub fn decode_ogg(data: &[u8]) -> Option<DecodedStream> {
256 let packets = crate::ogg::read_packets(data)?;
257 let bos = packets.first()?;
258 if bos.len() < 13 + 38 || bos[0] != 0x7F || &bos[1..5] != b"FLAC" || &bos[9..13] != b"fLaC" {
260 return None;
261 }
262 let mut sbr = BitReader::new(&bos[13..]);
263 let _is_last = sbr.read_raw_u32(1)?;
264 if sbr.read_raw_u32(7)? != 0 {
265 return None; }
267 let _len = sbr.read_raw_u32(24)?;
268 let _min_bs = sbr.read_raw_u32(16)?;
269 let _max_bs = sbr.read_raw_u32(16)?;
270 let _min_fs = sbr.read_raw_u32(24)?;
271 let _max_fs = sbr.read_raw_u32(24)?;
272 let sample_rate = sbr.read_raw_u32(20)?;
273 let channels = sbr.read_raw_u32(3)? + 1;
274 let bits_per_sample = sbr.read_raw_u32(5)? + 1;
275 let total_samples = sbr.read_raw_u64(36)?;
276 let mut md5 = [0u8; 16];
277 for b in &mut md5 {
278 *b = sbr.read_raw_u32(8)? as u8;
279 }
280
281 let mut frame_bytes = Vec::new();
284 if let Some(idx) = packets[1..].iter().position(|p| p.first() == Some(&0xFF)) {
285 for p in &packets[1 + idx..] {
286 frame_bytes.extend_from_slice(p);
287 }
288 }
289 let decoded = decode_frames(&frame_bytes)?;
290 let mut interleaved = decoded.interleaved;
291 if total_samples > 0 {
292 interleaved.truncate(total_samples as usize * channels as usize);
293 }
294 let md5_ok = md5 == [0u8; 16] || {
295 crate::md5::audio_md5(&interleaved, bits_per_sample.div_ceil(8) as usize) == md5
296 };
297
298 Some(DecodedStream {
299 interleaved,
300 channels,
301 bits_per_sample,
302 sample_rate,
303 total_samples,
304 md5,
305 md5_ok,
306 seek_points: Vec::new(),
307 })
308}
309
310struct StreamInfo {
311 sample_rate: u32,
312 channels: u32,
313 bits_per_sample: u32,
314 total_samples: u64,
315 md5: [u8; 16],
316}
317
318struct Frame {
319 blocksize: usize,
320 channels: u32,
321 bits_per_sample: u32,
322 sample_rate: u32,
323 samples: Vec<Vec<i32>>,
325}
326
327fn decode_frame(br: &mut BitReader, data: &[u8]) -> Option<Frame> {
328 let frame_start = br.byte_pos();
329
330 if br.read_raw_u32(14)? != 0x3ffe {
332 return None; }
334 let _reserved = br.read_raw_u32(1)?;
335 let blocking_strategy = br.read_raw_u32(1)?; let bs_code = br.read_raw_u32(4)?;
337 let sr_code = br.read_raw_u32(4)?;
338 let ca_code = br.read_raw_u32(4)?;
339 let bps_code = br.read_raw_u32(3)?;
340 let _reserved2 = br.read_raw_u32(1)?;
341 if blocking_strategy == 0 {
346 let _frame_number = br.read_utf8_u32()?;
347 } else {
348 let _sample_number = br.read_utf8_u64()?;
349 }
350
351 let blocksize = match bs_code {
352 1 => 192,
353 2 => 576,
354 3 => 1152,
355 4 => 2304,
356 5 => 4608,
357 6 => br.read_raw_u32(8)? as usize + 1,
358 7 => br.read_raw_u32(16)? as usize + 1,
359 8 => 256,
360 9 => 512,
361 10 => 1024,
362 11 => 2048,
363 12 => 4096,
364 13 => 8192,
365 14 => 16384,
366 15 => 32768,
367 _ => return None, };
369 let sample_rate = match sr_code {
370 1 => 88200,
371 2 => 176400,
372 3 => 192000,
373 4 => 8000,
374 5 => 16000,
375 6 => 22050,
376 7 => 24000,
377 8 => 32000,
378 9 => 44100,
379 10 => 48000,
380 11 => 96000,
381 12 => br.read_raw_u32(8)? * 1000,
382 13 => br.read_raw_u32(16)?,
383 14 => br.read_raw_u32(16)? * 10,
384 _ => 0, };
386 let bits_per_sample = match bps_code {
387 1 => 8,
388 2 => 12,
389 4 => 16,
390 5 => 20,
391 6 => 24,
392 7 => 32,
393 _ => return None, };
395 let (assignment, channels) = match ca_code {
396 0..=7 => (ChannelAssignment::Independent, ca_code + 1),
397 8 => (ChannelAssignment::LeftSide, 2),
398 9 => (ChannelAssignment::RightSide, 2),
399 10 => (ChannelAssignment::MidSide, 2),
400 _ => return None,
401 };
402
403 let computed_crc8 = crc8(br.bytes_since(frame_start));
405 if br.read_raw_u32(8)? as u8 != computed_crc8 {
406 return None;
407 }
408
409 let mut chans: Vec<Vec<i64>> = Vec::with_capacity(channels as usize);
411 for ch in 0..channels {
412 let side = matches!(
413 (assignment, ch),
414 (ChannelAssignment::LeftSide, 1)
415 | (ChannelAssignment::RightSide, 0)
416 | (ChannelAssignment::MidSide, 1)
417 );
418 let channel_bps = bits_per_sample + u32::from(side);
419 chans.push(decode_subframe(br, blocksize, channel_bps)?);
420 }
421
422 br.align_to_byte();
424 let computed_crc16 = crc16(br.bytes_since(frame_start));
425 if br.read_raw_u32(16)? as u16 != computed_crc16 {
426 return None;
427 }
428 let _ = data; Some(Frame {
431 blocksize,
432 channels,
433 bits_per_sample,
434 sample_rate,
435 samples: undecorrelate(assignment, &chans, blocksize),
436 })
437}
438
439fn decode_subframe(br: &mut BitReader, blocksize: usize, channel_bps: u32) -> Option<Vec<i64>> {
441 let header = br.read_raw_u32(8)?;
442 let wasted = if header & 1 == 1 {
443 br.read_unary()? + 1
444 } else {
445 0
446 };
447 let type6 = (header >> 1) & 0x3f;
448 let subframe_bps = channel_bps - wasted;
449
450 let mut data = vec![0i64; blocksize];
451 if type6 == 0 {
452 let v = br.read_signed(subframe_bps)?;
454 data.fill(v);
455 } else if type6 == 1 {
456 for d in data.iter_mut() {
458 *d = br.read_signed(subframe_bps)?;
459 }
460 } else if type6 & 0x20 != 0 {
461 let order = ((type6 & 0x1f) + 1) as usize;
463 for d in data.iter_mut().take(order) {
464 *d = br.read_signed(subframe_bps)?;
465 }
466 let precision = br.read_raw_u32(4)? + 1;
467 let shift = sign_extend5(br.read_raw_u32(5)?);
468 let mut qlp = vec![0i32; order];
469 for c in qlp.iter_mut() {
470 *c = br.read_signed(precision)? as i32;
471 }
472 let residual = decode_residual(br, blocksize, order)?;
473 for i in order..blocksize {
474 let mut sum = 0i64;
475 for (j, &c) in qlp.iter().enumerate() {
476 sum += c as i64 * data[i - 1 - j];
477 }
478 data[i] = residual[i - order] as i64 + (sum >> shift);
479 }
480 } else if type6 & 0x08 != 0 {
481 let order = (type6 & 0x07) as usize;
483 for d in data.iter_mut().take(order) {
484 *d = br.read_signed(subframe_bps)?;
485 }
486 let residual = decode_residual(br, blocksize, order)?;
487 for i in order..blocksize {
488 let r = residual[i - order] as i64;
489 data[i] = match order {
490 0 => r,
491 1 => r + data[i - 1],
492 2 => r + 2 * data[i - 1] - data[i - 2],
493 3 => r + 3 * data[i - 1] - 3 * data[i - 2] + data[i - 3],
494 _ => r + 4 * data[i - 1] - 6 * data[i - 2] + 4 * data[i - 3] - data[i - 4],
495 };
496 }
497 } else {
498 return None; }
500
501 if wasted > 0 {
502 for d in data.iter_mut() {
503 *d <<= wasted;
504 }
505 }
506 Some(data)
507}
508
509fn decode_residual(br: &mut BitReader, blocksize: usize, order: usize) -> Option<Vec<i32>> {
511 let is_rice2 = br.read_raw_u32(2)? == 1;
512 let param_len = if is_rice2 { 5 } else { 4 };
513 let escape = if is_rice2 { 31 } else { 15 };
514 let partition_order = br.read_raw_u32(4)?;
515 let partitions = 1usize << partition_order;
516
517 let mut residual = vec![0i32; blocksize - order];
518 let mut idx = 0usize;
519 for p in 0..partitions {
520 let count = if p == 0 {
521 (blocksize >> partition_order) - order
522 } else {
523 blocksize >> partition_order
524 };
525 let param = br.read_raw_u32(param_len)?;
526 if param == escape {
527 let raw_bits = br.read_raw_u32(5)?;
530 for r in &mut residual[idx..idx + count] {
531 *r = br.read_signed(raw_bits)? as i32;
532 }
533 } else {
534 br.read_rice_signed_block(&mut residual[idx..idx + count], param)?;
535 }
536 idx += count;
537 }
538 Some(residual)
539}
540
541fn undecorrelate(
543 assignment: ChannelAssignment,
544 chans: &[Vec<i64>],
545 blocksize: usize,
546) -> Vec<Vec<i32>> {
547 match assignment {
548 ChannelAssignment::Independent => chans
549 .iter()
550 .map(|c| c.iter().map(|&s| s as i32).collect())
551 .collect(),
552 ChannelAssignment::LeftSide => {
553 let (l, s) = (&chans[0], &chans[1]);
555 let left: Vec<i32> = l.iter().map(|&v| v as i32).collect();
556 let right: Vec<i32> = (0..blocksize).map(|i| (l[i] - s[i]) as i32).collect();
557 vec![left, right]
558 }
559 ChannelAssignment::RightSide => {
560 let (s, r) = (&chans[0], &chans[1]);
562 let left: Vec<i32> = (0..blocksize).map(|i| (r[i] + s[i]) as i32).collect();
563 let right: Vec<i32> = r.iter().map(|&v| v as i32).collect();
564 vec![left, right]
565 }
566 ChannelAssignment::MidSide => {
567 let (m, s) = (&chans[0], &chans[1]);
570 let mut left = vec![0i32; blocksize];
571 let mut right = vec![0i32; blocksize];
572 for i in 0..blocksize {
573 let side = s[i];
574 let mid2 = (m[i] << 1) | (side & 1);
575 left[i] = ((mid2 + side) >> 1) as i32;
576 right[i] = ((mid2 - side) >> 1) as i32;
577 }
578 vec![left, right]
579 }
580 }
581}
582
583fn sign_extend5(v: u32) -> i32 {
585 ((v << 27) as i32) >> 27
586}
587
588#[cfg(test)]
589mod tests {
590 use super::{decode, decode_frames, decode_ogg, decode_seek};
591 use crate::bitwriter::BitWriter;
592 use crate::encoder::{encode, encode_frames, encode_ogg, preset};
593 use crate::metadata::{LIBFLAC_VENDOR_STRING, MetadataBlock, spaced_seek_points};
594
595 fn gen_pcm(seed: u32, n: usize, bps: u32, channels: u32) -> Vec<i32> {
597 let mut st = seed.wrapping_mul(2_654_435_761).wrapping_add(1);
598 let mut rng = || {
599 st ^= st << 13;
600 st ^= st >> 17;
601 st ^= st << 5;
602 st
603 };
604 let maxv = ((1i64 << (bps - 1)) - 1) as f64;
605 let minv = -(1i64 << (bps - 1)) as f64;
606 let scale = (1u64 << (bps - 1)) as f64 / 32768.0;
607 let f1 = 0.008 + (rng() >> 22) as f64 / 2.0e6;
608 let f2 = 0.05 + (rng() >> 22) as f64 / 1.0e6;
609 let a1 = (1500.0 + (rng() >> 19) as f64 / 8.0e3) * scale;
610 let a2 = (400.0 + (rng() >> 20) as f64 / 1.0e4) * scale;
611 let noise = 250.0 * scale;
612 let mut out = Vec::with_capacity(n * channels as usize);
613 for i in 0..n {
614 for c in 0..channels {
615 let p = c as f64 * 0.35;
616 let v = a1 * (f1 * i as f64 + p).sin()
617 + a2 * (f2 * i as f64 + p).sin()
618 + noise * ((rng() >> 16) as u16 as i16 as f64 / 32768.0);
619 out.push(v.round().clamp(minv, maxv) as i32);
620 }
621 }
622 out
623 }
624
625 #[test]
626 fn round_trip_all_depths_levels() {
627 let bs = 2048u32;
628 for &bps in &[8u32, 12, 16, 20, 24, 32] {
629 for &ch in &[1u32, 2] {
630 for level in [0u32, 2, 5, 8] {
631 for seed in 1..=3u32 {
632 let n = bs as usize + (seed as usize * 173) % 1500;
634 let pcm = gen_pcm(seed, n, bps, ch);
635 let frames = encode_frames(&pcm, ch, bps, 44_100, bs, &preset(level));
636 let dec = decode_frames(&frames).expect("decode failed (CRC/format)");
637 assert_eq!(dec.channels, ch);
638 assert_eq!(dec.bits_per_sample, bps);
639 assert_eq!(dec.sample_rate, 44_100);
640 assert_eq!(
641 dec.interleaved, pcm,
642 "round-trip mismatch [bps {bps} ch {ch} level {level} seed {seed}]"
643 );
644 }
645 }
646 }
647 }
648 }
649
650 #[test]
651 fn full_stream_round_trip_with_md5() {
652 use crate::encoder::encode;
653 use crate::metadata::{LIBFLAC_VENDOR_STRING, MetadataBlock};
654 let bs = 2048u32;
655 for &bps in &[8u32, 16, 24, 32] {
656 for level in [0u32, 8] {
657 let pcm = gen_pcm(9, bs as usize + 555, bps, 2);
658 let stream = encode(
660 &pcm,
661 2,
662 bps,
663 44_100,
664 bs,
665 &preset(level),
666 true,
667 &[MetadataBlock::VorbisComment(LIBFLAC_VENDOR_STRING)],
668 );
669 let dec = decode(&stream).expect("decode full stream");
670 assert_eq!(dec.interleaved, pcm, "[bps {bps} level {level}] PCM");
671 assert_eq!(dec.total_samples, (pcm.len() / 2) as u64);
672 assert!(dec.md5_ok, "[bps {bps} level {level}] MD5 mismatch");
673 }
674 }
675 }
676
677 #[test]
678 fn round_trip_edge_signals() {
679 let bs = 2048u32;
680 for &bps in &[16u32, 24, 32] {
681 let maxv = ((1i64 << (bps - 1)) - 1) as i32;
682 let minv = -(1i64 << (bps - 1)) as i32;
683 let cases: &[(&str, Vec<i32>)] = &[
684 ("silence", vec![0i32; bs as usize * 2 + 50]), ("dc", vec![1234 << 3; bs as usize + 10]), ("full_pos", vec![maxv; bs as usize + 7]),
687 ("full_neg", vec![minv; bs as usize + 7]),
688 ("tiny", vec![5, -5, 5]), ];
690 for &(name, ref mono) in cases {
691 let stereo: Vec<i32> = mono.iter().flat_map(|&v| [v, v]).collect();
693 for level in [0u32, 8] {
694 let frames = encode_frames(&stereo, 2, bps, 44_100, bs, &preset(level));
695 let dec = decode_frames(&frames).expect("decode failed");
696 assert_eq!(dec.interleaved, stereo, "[{name} bps {bps} level {level}]");
697 }
698 }
699 }
700 }
701
702 #[test]
707 fn seek_lands_on_exact_sample() {
708 let bs = 2048u32;
709 let ch = 2u32;
710 for &bps in &[16u32, 24] {
711 let n = bs as usize * 5 + 777; let total = n as u64;
713 let pcm = gen_pcm(5, n, bps, ch);
714 let with_seektable = spaced_seek_points(10, total);
715 let targets = [
716 0u64,
717 1,
718 bs as u64 - 1,
719 bs as u64,
720 bs as u64 + 5,
721 bs as u64 * 3 + 100,
722 total - bs as u64,
723 total - 10,
724 total - 1,
725 ];
726 for seektable in [with_seektable.as_slice(), &[]] {
728 let blocks = [
729 MetadataBlock::VorbisComment(LIBFLAC_VENDOR_STRING),
730 MetadataBlock::Seektable(seektable),
731 ];
732 let nblocks = if seektable.is_empty() {
733 &blocks[..1]
734 } else {
735 &blocks[..]
736 };
737 let stream = encode(&pcm, ch, bps, 44_100, bs, &preset(8), true, nblocks);
738 for &target in &targets {
739 let r = decode_seek(&stream, target).expect("seek");
740 assert_eq!(r.first_sample, target);
741 assert_eq!(r.channels, ch);
742 assert_eq!(r.bits_per_sample, bps);
743 let expected = &pcm[target as usize * ch as usize..];
744 assert_eq!(
745 r.interleaved,
746 expected,
747 "[bps {bps} seektable {}] seek to {target}",
748 !seektable.is_empty()
749 );
750 }
751 assert!(decode_seek(&stream, total).is_none());
753 }
754 }
755 }
756
757 #[test]
763 fn decodes_variable_block_size_frame() {
764 let mut bw = BitWriter::new();
765 bw.write_raw_u32(0x3FFE, 14); bw.write_raw_u32(0, 1); bw.write_raw_u32(1, 1); bw.write_raw_u32(6, 4); bw.write_raw_u32(9, 4); bw.write_raw_u32(0, 4); bw.write_raw_u32(4, 3); bw.write_raw_u32(0, 1); bw.write_utf8_u64(0x123456); bw.write_raw_u32(4 - 1, 8); let header_crc = bw.crc8(); bw.write_raw_u32(header_crc as u32, 8);
777 bw.write_raw_u32(0x00, 8);
779 bw.write_raw_u32(1000, 16);
780 let frame_crc = bw.crc16(); bw.write_raw_u32(frame_crc as u32, 16);
782 let frame = bw.as_bytes().to_vec();
783
784 let dec = decode_frames(&frame).expect("decode variable-block-size frame");
785 assert_eq!(dec.channels, 1);
786 assert_eq!(dec.bits_per_sample, 16);
787 assert_eq!(dec.sample_rate, 44_100);
788 assert_eq!(dec.interleaved, vec![1000i32; 4]);
789 }
790
791 #[test]
796 fn ogg_round_trip() {
797 for &bps in &[8u32, 16, 20, 24, 32] {
798 for level in [0u32, 5, 8] {
799 let pcm = gen_pcm(7, 12_000 + bps as usize * 13, bps, 2);
801 let ogg = encode_ogg(
802 &pcm,
803 2,
804 bps,
805 44_100,
806 4096,
807 &preset(level),
808 true,
809 &[MetadataBlock::VorbisComment(LIBFLAC_VENDOR_STRING)],
810 0x55AA_1234,
811 );
812 let dec = decode_ogg(&ogg).expect("decode_ogg");
813 assert_eq!(
814 dec.interleaved, pcm,
815 "[bps {bps} level {level}] ogg round-trip"
816 );
817 assert!(dec.md5_ok, "[bps {bps} level {level}] ogg MD5");
818 assert_eq!(dec.total_samples, (pcm.len() / 2) as u64);
819 }
820 }
821 }
822}