webrtc_media/io/ogg_reader/
mod.rs1#[cfg(test)]
2mod ogg_reader_test;
3
4use std::io::{Cursor, Read};
5
6use byteorder::{LittleEndian, ReadBytesExt};
7use bytes::BytesMut;
8
9use crate::error::{Error, Result};
10use crate::io::ResetFn;
11
12pub const PAGE_HEADER_TYPE_CONTINUATION_OF_STREAM: u8 = 0x00;
13pub const PAGE_HEADER_TYPE_BEGINNING_OF_STREAM: u8 = 0x02;
14pub const PAGE_HEADER_TYPE_END_OF_STREAM: u8 = 0x04;
15pub const DEFAULT_PRE_SKIP: u16 = 3840; pub const PAGE_HEADER_SIGNATURE: &[u8] = b"OggS";
17pub const ID_PAGE_SIGNATURE: &[u8] = b"OpusHead";
18pub const COMMENT_PAGE_SIGNATURE: &[u8] = b"OpusTags";
19pub const PAGE_HEADER_SIZE: usize = 27;
20pub const ID_PAGE_PAYLOAD_SIZE: usize = 19;
21
22pub struct OggReader<R: Read> {
24 reader: R,
25 bytes_read: usize,
26 checksum_table: [u32; 256],
27 do_checksum: bool,
28}
29
30pub struct OggHeader {
34 pub channel_map: u8,
35 pub channels: u8,
36 pub output_gain: u16,
37 pub pre_skip: u16,
38 pub sample_rate: u32,
39 pub version: u8,
40}
41
42pub struct OggPageHeader {
46 pub granule_position: u64,
47
48 sig: [u8; 4],
49 version: u8,
50 header_type: u8,
51 serial: u32,
52 index: u32,
53 segments_count: u8,
54}
55
56impl<R: Read> OggReader<R> {
57 pub fn new(reader: R, do_checksum: bool) -> Result<(OggReader<R>, OggHeader)> {
60 let mut r = OggReader {
61 reader,
62 bytes_read: 0,
63 checksum_table: generate_checksum_table(),
64 do_checksum,
65 };
66
67 let header = r.read_headers()?;
68
69 Ok((r, header))
70 }
71
72 fn read_headers(&mut self) -> Result<OggHeader> {
73 let (payload, page_header) = self.parse_next_page()?;
74
75 if page_header.sig != PAGE_HEADER_SIGNATURE {
76 return Err(Error::ErrBadIDPageSignature);
77 }
78
79 if page_header.header_type != PAGE_HEADER_TYPE_BEGINNING_OF_STREAM {
80 return Err(Error::ErrBadIDPageType);
81 }
82
83 if payload.len() != ID_PAGE_PAYLOAD_SIZE {
84 return Err(Error::ErrBadIDPageLength);
85 }
86
87 let s = &payload[..8];
88 if s != ID_PAGE_SIGNATURE {
89 return Err(Error::ErrBadIDPagePayloadSignature);
90 }
91
92 let mut reader = Cursor::new(&payload[8..]);
93 let version = reader.read_u8()?; let channels = reader.read_u8()?; let pre_skip = reader.read_u16::<LittleEndian>()?; let sample_rate = reader.read_u32::<LittleEndian>()?; let output_gain = reader.read_u16::<LittleEndian>()?; let channel_map = reader.read_u8()?; Ok(OggHeader {
101 channel_map,
102 channels,
103 output_gain,
104 pre_skip,
105 sample_rate,
106 version,
107 })
108 }
109
110 pub fn parse_next_page(&mut self) -> Result<(BytesMut, OggPageHeader)> {
113 let mut h = [0u8; PAGE_HEADER_SIZE];
114 self.reader.read_exact(&mut h)?;
115
116 let mut head_reader = Cursor::new(h);
117 let mut sig = [0u8; 4]; head_reader.read_exact(&mut sig)?;
119 let version = head_reader.read_u8()?; let header_type = head_reader.read_u8()?; let granule_position = head_reader.read_u64::<LittleEndian>()?; let serial = head_reader.read_u32::<LittleEndian>()?; let index = head_reader.read_u32::<LittleEndian>()?; let checksum = head_reader.read_u32::<LittleEndian>()?; let segments_count = head_reader.read_u8()?; let mut size_buffer = vec![0u8; segments_count as usize];
128 self.reader.read_exact(&mut size_buffer)?;
129
130 let mut payload_size = 0usize;
131 for s in &size_buffer {
132 payload_size += *s as usize;
133 }
134
135 let mut payload = BytesMut::with_capacity(payload_size);
136 payload.resize(payload_size, 0);
137 self.reader.read_exact(&mut payload)?;
138
139 if self.do_checksum {
140 let mut sum = 0;
141
142 for (index, v) in h.iter().enumerate() {
143 if index > 21 && index < 26 {
145 sum = self.update_checksum(0, sum);
146 continue;
147 }
148 sum = self.update_checksum(*v, sum);
149 }
150
151 for v in &size_buffer {
152 sum = self.update_checksum(*v, sum);
153 }
154 for v in &payload[..] {
155 sum = self.update_checksum(*v, sum);
156 }
157
158 if sum != checksum {
159 return Err(Error::ErrChecksumMismatch);
160 }
161 }
162
163 let page_header = OggPageHeader {
164 granule_position,
165 sig,
166 version,
167 header_type,
168 serial,
169 index,
170 segments_count,
171 };
172
173 Ok((payload, page_header))
174 }
175
176 pub fn reset_reader(&mut self, mut reset: ResetFn<R>) {
180 self.reader = reset(self.bytes_read);
181 }
182
183 fn update_checksum(&self, v: u8, sum: u32) -> u32 {
184 (sum << 8) ^ self.checksum_table[(((sum >> 24) as u8) ^ v) as usize]
185 }
186}
187
188pub(crate) fn generate_checksum_table() -> [u32; 256] {
189 let mut table = [0u32; 256];
190 const POLY: u32 = 0x04c11db7;
191
192 for (i, t) in table.iter_mut().enumerate() {
193 let mut r = (i as u32) << 24;
194 for _ in 0..8 {
195 if (r & 0x80000000) != 0 {
196 r = (r << 1) ^ POLY;
197 } else {
198 r <<= 1;
199 }
200 }
201 *t = r;
202 }
203 table
204}