Repository navigation
Expand file tree
/
Copy pathtests.rs
More file actions
181 lines (170 loc) · 6.41 KB
/
Copy pathtests.rs
File metadata and controls
181 lines (170 loc) · 6.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//! Synthetic Ogg streams: a small page writer (RFC 3533) and Opus-like packets.
use super::*;
/// Write one page holding `segments` (lacing already computed by `lace`).
fn page(out: &mut Vec<u8>, flags: u8, granule: i64, serial: u32, seq: u32, lacing: &[u8], body: &[u8]) {
let start = out.len();
out.extend_from_slice(b"OggS");
out.push(0);
out.push(flags);
out.extend_from_slice(&granule.to_le_bytes());
out.extend_from_slice(&serial.to_le_bytes());
out.extend_from_slice(&seq.to_le_bytes());
out.extend_from_slice(&[0; 4]);
out.push(lacing.len() as u8);
out.extend_from_slice(lacing);
out.extend_from_slice(body);
let crc = crc32(&out[start..]);
out[start + 22..start + 26].copy_from_slice(&crc.to_le_bytes());
}
fn lace(packets: &[&[u8]], last_continues: bool) -> (Vec<u8>, Vec<u8>) {
let mut l = Vec::new();
let mut b = Vec::new();
for (i, p) in packets.iter().enumerate() {
let mut n = p.len();
while n >= 255 {
l.push(255);
n -= 255;
}
if !(last_continues && i + 1 == packets.len()) {
l.push(n as u8);
}
b.extend_from_slice(p);
}
(l, b)
}
fn opus_head(pre_skip: u16) -> Vec<u8> {
let mut h = b"OpusHead".to_vec();
h.push(1);
h.push(2);
h.extend_from_slice(&pre_skip.to_le_bytes());
h.extend_from_slice(&48_000u32.to_le_bytes());
h.extend_from_slice(&0i16.to_le_bytes());
h.push(0);
h
}
/// A CELT 20 ms packet (960 samples): TOC config 31, code 0.
fn pkt(i: usize, len: usize) -> Vec<u8> {
let mut p = vec![0xF8];
p.extend((0..len.saturating_sub(1)).map(|k| (i * 7 + k) as u8));
p
}
/// Header pages, then pages of 3 packets each; the last page's granule trims `trim` samples.
fn opus_file(npk: usize, pre_skip: u16, trim: i64) -> Vec<u8> {
let mut f = Vec::new();
let head = opus_head(pre_skip);
let (l, b) = lace(&[&head], false);
page(&mut f, 0x02, 0, 9, 0, &l, &b);
let tags = b"OpusTags\x00\x00\x00\x00\x00\x00\x00\x00".to_vec();
let (l, b) = lace(&[&tags], false);
page(&mut f, 0, 0, 9, 1, &l, &b);
let pkts: Vec<Vec<u8>> = (0..npk).map(|i| pkt(i, 40 + i % 5)).collect();
let mut done = 0;
for (seq, chunk) in (2..).zip(pkts.chunks(3)) {
done += chunk.len();
let last = done == npk;
let mut g = done as i64 * 960;
if last {
g -= trim;
}
let refs: Vec<&[u8]> = chunk.iter().map(Vec::as_slice).collect();
let (l, b) = lace(&refs, false);
page(&mut f, if last { 0x04 } else { 0 }, g, 9, seq, &l, &b);
}
f
}
#[test]
fn crc_matches_known_value() {
// CRC-32/CKSUM parameters without its final XOR (check value 0x765E7680 ^ 0xFFFFFFFF)
assert_eq!(crc32(b"123456789"), 0x89A1_897F);
assert_eq!(crc32(b""), 0);
assert_ne!(crc32(b"OggS"), crc32(b"OggT"));
}
#[test]
fn opus_pages_packets_and_timing() {
let f = opus_file(10, 312, 500);
assert!(sniff(&f));
let o = open(&f).unwrap();
assert!(o.warnings.is_empty(), "{:?}", o.warnings);
let s = o.stream_of(Codec::Opus).unwrap();
let st = &o.streams[s];
assert_eq!(st.headers.len(), 2);
assert_eq!(st.packets.len(), 10);
assert!(st.saw_eos);
assert_eq!(o.read_packet(&f, s, 4).unwrap(), pkt(4, 44));
let t = OpusTiming::of(st, 312);
assert_eq!(t.durations, vec![960; 10]);
assert_eq!(t.starts[0], -312);
assert_eq!(t.starts[9], 9 * 960 - 312);
// end trimming: the last page granule is 500 short
assert_eq!(t.total, 10 * 960 - 500 - 312);
}
#[test]
fn packets_spanning_pages() {
let mut f = Vec::new();
let head = opus_head(0);
let (l, b) = lace(&[&head], false);
page(&mut f, 0x02, 0, 1, 0, &l, &b);
let (l, b) = lace(&[b"OpusTags"], false);
page(&mut f, 0, 0, 1, 1, &l, &b);
let big = pkt(0, 700);
// first 510 bytes on one page (two 255 lacing values, packet continues), rest on the next
let (l, b) = (vec![255, 255], big[..510].to_vec());
page(&mut f, 0, -1, 1, 2, &l, &b);
let rest = &big[510..];
let small = pkt(1, 30);
let (l, b) = lace(&[rest, &small], false);
page(&mut f, 0x01 | 0x04, 1920, 1, 3, &l, &b);
let o = open(&f).unwrap();
let st = &o.streams[0];
assert_eq!(st.packets.len(), 2);
assert_eq!(st.packets[0].parts.len(), 2);
assert_eq!(o.read_packet(&f, 0, 0).unwrap(), big);
assert_eq!(o.read_packet(&f, 0, 1).unwrap(), small);
let t = OpusTiming::of(st, 0);
assert_eq!(t.starts, vec![0, 960]);
assert_eq!(t.total, 1920);
}
#[test]
fn corrupt_pages_are_skipped_and_truncation_is_safe() {
let f = opus_file(12, 312, 0);
// flip a byte inside the third data page's body: that page fails its CRC and is dropped
let mut g = f.clone();
let third = g.windows(4).enumerate().filter(|(_, w)| *w == b"OggS").map(|(i, _)| i).nth(4).unwrap();
g[third + 40] ^= 0xFF;
let o = open(&g).unwrap();
assert!(o.warnings.iter().any(|w| w.contains("CRC")), "{:?}", o.warnings);
assert_eq!(o.streams[0].packets.len(), 9);
let t = OpusTiming::of(&o.streams[0], 312);
// the granules after the gap put the later packets at their true positions
assert_eq!(*t.starts.last().unwrap(), 11 * 960 - 312);
for cut in 0..f.len() {
if let Ok(o) = open(&f[..cut].to_vec()) {
for st in &o.streams {
let t = OpusTiming::of(st, 312);
assert_eq!(t.starts.len(), st.packets.len());
}
}
}
let mut seed = 99u64;
for _ in 0..300 {
let mut g = f.clone();
seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
let at = (seed >> 33) as usize % g.len();
g[at] = (seed >> 20) as u8;
if let Ok(o) = open(&g) {
for st in &o.streams {
let _ = OpusTiming::of(st, 312);
}
}
}
assert!(matches!(open(&b"not ogg at all, no capture pattern".to_vec()), Err(Error::NotOgg)));
}
#[test]
fn opus_toc_durations() {
assert_eq!(opus_packet_samples([0x00, 0], 10), Some(480)); // SILK NB 10 ms
assert_eq!(opus_packet_samples([0x18, 0], 10), Some(2880)); // SILK NB 60 ms
assert_eq!(opus_packet_samples([0x78 | 1, 0], 10), Some(1920)); // hybrid 20 ms × 2
assert_eq!(opus_packet_samples([0x80 | 3, 6], 10), Some(720)); // CELT 2.5 ms × 6
assert_eq!(opus_packet_samples([0xF8 | 3, 7], 10), None); // 140 ms: invalid
assert_eq!(opus_packet_samples([0xF8, 0], 0), None);
}