pixelflux/recorder/
ogg.rs1use std::collections::VecDeque;
14use std::io::{self, Read};
15
16pub struct OpusHead {
19 pub channels: u8,
20 pub pre_skip: u16,
21 pub input_sample_rate: u32,
22 pub output_gain: i16,
23 pub mapping_family: u8,
24 pub mapping: Vec<u8>,
25}
26
27pub fn parse_opus_head(packet: &[u8]) -> Option<OpusHead> {
28 if packet.len() < 19 || &packet[..8] != b"OpusHead" {
29 return None;
30 }
31 let mapping_family = packet[18];
32 let channels = packet[9];
33 let mapping = if mapping_family == 0 {
34 Vec::new()
35 } else {
36 packet.get(19..21 + channels as usize)?.to_vec()
37 };
38 Some(OpusHead {
39 channels,
40 pre_skip: u16::from_le_bytes([packet[10], packet[11]]),
41 input_sample_rate: u32::from_le_bytes(packet[12..16].try_into().ok()?),
42 output_gain: i16::from_le_bytes([packet[16], packet[17]]),
43 mapping_family,
44 mapping,
45 })
46}
47
48pub struct PageReader<R: Read> {
50 inner: R,
51 carry: Vec<u8>,
53 pending: VecDeque<(Vec<u8>, Option<u64>)>,
54}
55
56impl<R: Read> PageReader<R> {
57 pub fn new(inner: R) -> Self {
58 Self {
59 inner,
60 carry: Vec::new(),
61 pending: VecDeque::new(),
62 }
63 }
64
65 pub fn inner_mut(&mut self) -> &mut R {
66 &mut self.inner
67 }
68
69 pub fn next_packet(&mut self) -> io::Result<Option<(Vec<u8>, Option<u64>)>> {
72 while self.pending.is_empty() {
73 if !self.read_page()? {
74 return Ok(None);
75 }
76 }
77 Ok(self.pending.pop_front())
78 }
79
80 fn read_exact_or_end(&mut self, buf: &mut [u8]) -> io::Result<bool> {
81 let mut filled = 0;
82 while filled < buf.len() {
83 match self.inner.read(&mut buf[filled..]) {
84 Ok(0) => return Ok(false),
85 Ok(n) => filled += n,
86 Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
87 Err(e) => return Err(e),
88 }
89 }
90 Ok(true)
91 }
92
93 fn read_page(&mut self) -> io::Result<bool> {
94 let mut header = [0u8; 27];
95 if !self.read_exact_or_end(&mut header)? {
96 return Ok(false);
97 }
98 if &header[..4] != b"OggS" {
99 return Err(io::Error::new(
100 io::ErrorKind::InvalidData,
101 "not an Ogg page",
102 ));
103 }
104 let granule = u64::from_le_bytes(header[6..14].try_into().unwrap());
105 let mut lacing = vec![0u8; header[26] as usize];
106 if !self.read_exact_or_end(&mut lacing)? {
107 return Ok(false);
108 }
109 let mut body = vec![0u8; lacing.iter().map(|&l| l as usize).sum()];
110 if !self.read_exact_or_end(&mut body)? {
111 return Ok(false);
112 }
113 let mut at = 0;
114 let mut completed: Vec<Vec<u8>> = Vec::new();
115 for &lace in &lacing {
116 self.carry.extend_from_slice(&body[at..at + lace as usize]);
117 at += lace as usize;
118 if lace < 255 {
119 completed.push(std::mem::take(&mut self.carry));
120 }
121 }
122 let last = completed.len().saturating_sub(1);
123 for (i, packet) in completed.into_iter().enumerate() {
124 self.pending
125 .push_back((packet, (i == last).then_some(granule)));
126 }
127 Ok(true)
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 fn page(granule: u64, packets: &[&[u8]], continued_tail: bool) -> Vec<u8> {
136 let mut lacing = Vec::new();
137 let mut body = Vec::new();
138 for (i, p) in packets.iter().enumerate() {
139 lacing.extend(std::iter::repeat_n(255u8, p.len() / 255));
140 if !(continued_tail && i == packets.len() - 1) {
141 lacing.push((p.len() % 255) as u8);
142 }
143 body.extend_from_slice(p);
144 }
145 let mut out = b"OggS\0\0".to_vec();
146 out.extend_from_slice(&granule.to_le_bytes());
147 out.extend_from_slice(&[0u8; 12]);
148 out.push(lacing.len() as u8);
149 out.extend_from_slice(&lacing);
150 out.extend_from_slice(&body);
151 out
152 }
153
154 #[test]
157 fn packets_and_granules() {
158 let mut head = b"OpusHead".to_vec();
159 head.extend_from_slice(&[1, 2, 0x38, 0x01, 0x80, 0xbb, 0, 0, 0, 0, 0]);
160 let long = vec![7u8; 510];
161 let mut stream = page(0, &[&head], false);
162 stream.extend(page(1920, &[b"aa", b"bbb"], false));
163 stream.extend(page(2880, &[&long], true));
164 stream.extend(page(3840, &[&[8u8; 0][..]], false));
165 let mut reader = PageReader::new(&stream[..]);
166 let (first, g0) = reader.next_packet().unwrap().unwrap();
167 let parsed = parse_opus_head(&first).expect("head");
168 assert_eq!(
169 (
170 parsed.channels,
171 parsed.pre_skip,
172 parsed.input_sample_rate,
173 parsed.mapping_family
174 ),
175 (2, 312, 48000, 0)
176 );
177 assert_eq!(g0, Some(0));
178 assert_eq!(
179 reader.next_packet().unwrap().unwrap(),
180 (b"aa".to_vec(), None)
181 );
182 assert_eq!(
183 reader.next_packet().unwrap().unwrap(),
184 (b"bbb".to_vec(), Some(1920))
185 );
186 assert_eq!(reader.next_packet().unwrap().unwrap(), (long, Some(3840)));
187 assert!(reader.next_packet().unwrap().is_none());
188 }
189}