1#![allow(dead_code)]
2
3use std::{io::{self, Read, Write, Cursor, ErrorKind}, mem, fmt::{self, Debug, Formatter}};
4
5#[derive(Debug, Clone, Copy, PartialEq)]
6pub enum OggPacketType {
7 Continuation = 0,
9
10 BeginOfStream = 2,
12
13 EndOfStream = 4,
15}
16
17#[derive(Debug, Clone)]
19pub struct OggPacket {
20 pub version: u8,
22
23 pub packet_type: OggPacketType,
27
28 pub granule_position: u64,
31
32 pub stream_id: u32,
34
35 pub packet_index: u32,
37
38 pub checksum: u32,
40
41 pub segment_table: Vec<u8>,
43
44 pub data: Vec<u8>,
46}
47
48impl OggPacket {
49 pub fn new(stream_id: u32, packet_type: OggPacketType, packet_index: u32) -> Self {
51 Self {
52 version: 0,
53 packet_type,
54 granule_position: 0,
55 stream_id,
56 packet_index,
57 checksum: 0,
58 segment_table: Vec::new(),
59 data: Vec::new(),
60 }
61 }
62
63 pub fn write(&mut self, data: &[u8]) -> usize {
65 let mut written = 0usize;
66 let mut to_write = data.len();
67 if to_write == 0 {
68 return 0;
69 }
70 while self.segment_table.len() < 255 {
71 if to_write >= 255 {
72 let new_pos = written + 255;
73 self.segment_table.push(255);
74 self.data.extend(data[written..new_pos].to_vec());
75 written = new_pos;
76 to_write -= 255;
77 } else {
78 if to_write == 0 {
79 break;
80 }
81 let new_pos = written + to_write;
82 self.segment_table.push(to_write as u8);
83 self.data.extend(data[written..new_pos].to_vec());
84 written = new_pos;
85 break;
86 }
87 }
88 written
89 }
90
91 pub fn clear(&mut self) {
93 self.segment_table = Vec::new();
94 self.data = Vec::new();
95 }
96
97 pub fn get_segments(&self) -> Vec<Vec<u8>> {
99 let mut ret = Vec::<Vec<u8>>::with_capacity(self.segment_table.len());
100 let mut pos = 0usize;
101 self.segment_table.iter().for_each(|&size|{
102 let next_pos = pos + size as usize;
103 ret.push(self.data[pos..next_pos].to_vec());
104 pos = next_pos;
105 });
106 ret
107 }
108
109 pub fn get_inner_data_size(&self) -> usize {
111 self.segment_table.iter().map(|&s|s as usize).sum()
112 }
113
114 pub fn get_inner_data(&self) -> Vec<u8> {
116 self.get_segments().into_iter().flatten().collect()
117 }
118
119 pub fn into_inner(self) -> Vec<u8> {
121 self.get_inner_data()
122 }
123
124 pub fn crc(mut crc: u32, data: &[u8]) -> u32 {
126 type CrcTableType = [u32; 256];
127 fn ogg_generate_crc_table() -> CrcTableType {
128 use std::mem::MaybeUninit;
129 #[allow(invalid_value)]
130 #[allow(clippy::uninit_assumed_init)]
131 let mut crc_lookup: CrcTableType = unsafe{MaybeUninit::uninit().assume_init()};
132 (0..256).for_each(|i|{
133 let mut r: u32 = i << 24;
134 for _ in 0..8 {
135 r = (r << 1) ^ (-(((r >> 31) & 1) as i32) as u32 & 0x04c11db7);
136 }
137 crc_lookup[i as usize] = r;
138 });
139 crc_lookup
140 }
141
142 use std::sync::OnceLock;
143 static OGG_CRC_TABLE: OnceLock<CrcTableType> = OnceLock::<CrcTableType>::new();
144 let crc_lookup = OGG_CRC_TABLE.get_or_init(ogg_generate_crc_table);
145
146 for b in data {
147 crc = (crc << 8) ^ crc_lookup[(*b as u32 ^ (crc >> 24)) as usize];
148 }
149
150 crc
151 }
152
153 pub fn get_checksum(ogg_packet: &[u8]) -> io::Result<u32> {
154 if ogg_packet.len() < 27 {
155 Err(io::Error::new(ErrorKind::InvalidData, format!("The given packet is too small: {} < 27", ogg_packet.len())))
156 } else {
157 let mut field_cleared = ogg_packet.to_vec();
158 field_cleared[22..26].copy_from_slice(&[0u8; 4]);
159 Ok(Self::crc(0, &field_cleared))
160 }
161 }
162
163 pub fn fill_checksum_field(ogg_packet: &mut [u8]) -> io::Result<()> {
165 let checksum = Self::get_checksum(ogg_packet)?;
166 ogg_packet[22..26].copy_from_slice(&checksum.to_le_bytes());
167 Ok(())
168 }
169
170 pub fn into_bytes(self) -> Vec<u8> {
172 let mut ret: Vec<u8> = [
173 b"OggS" as &[u8],
174 &[self.version],
175 &[self.packet_type as u8],
176 &self.granule_position.to_le_bytes() as &[u8],
177 &self.stream_id.to_le_bytes() as &[u8],
178 &self.packet_index.to_le_bytes() as &[u8],
179 &0u32.to_le_bytes() as &[u8],
180 &[self.segment_table.len() as u8],
181 &self.segment_table,
182 &self.data,
183 ].into_iter().flatten().copied().collect();
184 Self::fill_checksum_field(&mut ret).unwrap();
185 ret
186 }
187
188 pub fn get_length(ogg_packet: &[u8]) -> io::Result<usize> {
190 if ogg_packet.len() < 27 {
191 Err(io::Error::new(ErrorKind::UnexpectedEof, format!("The given ogg page size is too small: {} < 27", ogg_packet.len())))
192 } else if ogg_packet[0..4] != *b"OggS" {
193 Err(io::Error::new(ErrorKind::InvalidData, format!("While parsing Ogg packet: expected `OggS`, got `{}`", String::from_utf8_lossy(&ogg_packet[0..4]))))
194 } else if ogg_packet[4] != 0 {
195 Err(io::Error::new(ErrorKind::InvalidData, format!("While parsing Ogg packet: invalid `version` = {} (should be zero)", ogg_packet[4])))
196 } else {
197 match ogg_packet[5] {
198 0 | 2 | 4 => (),
199 o => return Err(io::Error::new(ErrorKind::InvalidData, format!("While parsing Ogg packet: invalid `packet_type` = {o} (should be 0, 2, 4)"))),
200 }
201 let num_segments = ogg_packet[26] as usize;
202 let data_start = 27 + num_segments;
203 let segment_table = &ogg_packet[27..data_start];
204 let data_length: usize = segment_table.iter().map(|&s|s as usize).sum();
205 Ok(data_start + data_length)
206 }
207 }
208
209 pub fn from_bytes(ogg_packet: &[u8], packet_length: &mut usize) -> io::Result<Self> {
211 if ogg_packet.len() < 27 {
212 Err(io::Error::new(ErrorKind::UnexpectedEof, format!("The given ogg page size is too small: {} < 27", ogg_packet.len())))
213 } else if ogg_packet[0..4] != *b"OggS" {
214 Err(io::Error::new(ErrorKind::InvalidData, format!("While parsing Ogg packet: expected `OggS`, got `{}`", String::from_utf8_lossy(&ogg_packet[0..4]))))
215 } else if ogg_packet[4] != 0 {
216 Err(io::Error::new(ErrorKind::InvalidData, format!("While parsing Ogg packet: invalid `version` = {} (should be zero)", ogg_packet[4])))
217 } else {
218 let packet_type = match ogg_packet[5] {
219 0 => OggPacketType::Continuation,
220 2 => OggPacketType::BeginOfStream,
221 4 => OggPacketType::EndOfStream,
222 o => return Err(io::Error::new(ErrorKind::InvalidData, format!("While parsing Ogg packet: invalid `packet_type` = {o} (should be 0, 2, 4)"))),
223 };
224 let num_segments = ogg_packet[26] as usize;
225 let data_start = 27 + num_segments;
226 let segment_table = &ogg_packet[27..data_start];
227 let data_length: usize = segment_table.iter().map(|&s|s as usize).sum();
228 *packet_length = data_start + data_length;
229 if ogg_packet.len() < *packet_length {
230 Err(io::Error::new(ErrorKind::UnexpectedEof, format!("The given ogg page size is too small: {} < {packet_length}", ogg_packet.len())))
231 } else {
232 let ret = Self{
233 version: 0,
234 packet_type,
235 granule_position: u64::from_le_bytes(ogg_packet[6..14].try_into().unwrap()),
236 stream_id: u32::from_le_bytes(ogg_packet[14..18].try_into().unwrap()),
237 packet_index: u32::from_le_bytes(ogg_packet[18..22].try_into().unwrap()),
238 checksum: u32::from_le_bytes(ogg_packet[22..26].try_into().unwrap()),
239 segment_table: segment_table.to_vec(),
240 data: ogg_packet[data_start..*packet_length].to_vec(),
241 };
242 let checksum = Self::get_checksum(&ogg_packet[..*packet_length])?;
243 if ret.checksum != checksum {
244 Err(io::Error::new(ErrorKind::InvalidData, format!("Ogg packet checksum not match: should be 0x{:x}, got 0x{:x}", checksum, ret.checksum)))
245 } else {
246 Ok(ret)
247 }
248 }
249 }
250 }
251
252 pub fn from_cursor(cursor: &mut Cursor<Vec<u8>>) -> Vec<OggPacket> {
254 let mut data: &[u8] = cursor.get_ref();
255 let mut packet_length = 0usize;
256 let mut bytes_read = 0usize;
257 let mut ret = Vec::<OggPacket>::new();
258 while let Ok(packet) = Self::from_bytes(data, &mut packet_length) {
259 bytes_read += packet_length;
260 ret.push(packet);
261 data = &data[packet_length..];
262 if data.is_empty() {
263 break;
264 }
265 }
266 cursor.set_position(bytes_read as u64);
267 ret
268 }
269}
270
271impl Default for OggPacket {
272 fn default() -> Self {
273 Self {
274 version: 0,
275 packet_type: OggPacketType::BeginOfStream,
276 granule_position: 0,
277 stream_id: 0,
278 packet_index: 0,
279 checksum: 0,
280 segment_table: Vec::new(),
281 data: Vec::new(),
282 }
283 }
284}
285
286pub struct OggStreamReader<R>
288where
289 R: Read + Debug {
290 pub reader: R,
292
293 pub stream_id: u32,
295
296 e_o_s: bool,
298
299 e_o_f: bool,
301
302 cached_bytes: Vec<u8>,
304}
305
306impl<R> OggStreamReader<R>
307where
308 R: Read + Debug {
309 const READ_SIZE: usize = 2048;
310
311 pub fn new(reader: R) -> Self {
312 Self {
313 reader,
314 stream_id: 0,
315 e_o_s: false,
316 e_o_f: false,
317 cached_bytes: Vec::new(),
318 }
319 }
320
321 fn safe_read(&mut self, target_len: usize) -> io::Result<Vec<u8>> {
322 let mut buf = vec![0u8; target_len];
323 let mut bytes_read = 0usize;
324 while bytes_read < target_len {
325 let read = match self.reader.read(&mut buf[bytes_read..]) {
326 Ok(0) => break,
327 Ok(size) => size,
328 Err(e) => match e.kind() {
329 io::ErrorKind::Interrupted => {
330 0
331 }
332 io::ErrorKind::UnexpectedEof => {
333 break;
334 }
335 _ => {
336 if bytes_read > 0 {
337 break;
338 } else {
339 return Err(e);
340 }
341 }
342 }
343 };
344 bytes_read += read;
345 }
346 buf.truncate(bytes_read);
347 Ok(buf)
348 }
349
350 pub fn get_packet(&mut self) -> io::Result<Option<OggPacket>> {
351 let mut packet_length = 0usize;
352 match OggPacket::from_bytes(&self.cached_bytes, &mut packet_length) {
353 Ok(packet) => {
354 if packet.packet_type == OggPacketType::EndOfStream {
355 self.e_o_s = true;
356 }
357 self.cached_bytes = self.cached_bytes[packet_length..].to_vec();
358 Ok(Some(packet))
359 }
360 Err(e) => match e.kind() {
361 io::ErrorKind::UnexpectedEof => { let read = self.safe_read(Self::READ_SIZE)?;
363 self.cached_bytes.extend(&read);
364 if read.len() < Self::READ_SIZE {
365 if self.e_o_f == false {
366 self.e_o_f = true;
367 self.get_packet()
368 } else {
369 Err(e)
370 }
371 } else {
372 self.get_packet()
373 }
374 }
375 _ => Err(e)
376 }
377 }
378 }
379
380 pub fn is_eos(&self) -> bool {
381 self.e_o_s
382 }
383
384 pub fn is_eof(&self) -> bool {
385 self.e_o_f
386 }
387}
388
389
390pub struct OggStreamWriter<W>
392where
393 W: Write + Debug {
394 pub writer: W,
396
397 pub stream_id: u32,
399
400 pub packet_index: u32,
402
403 pub cur_packet: OggPacket,
405
406 pub granule_position: u64,
408
409 pub on_seal: Box<dyn FnMut(usize) -> u64>,
412
413 pub bytes_written: u64,
415}
416
417impl<W> OggStreamWriter<W>
418where
419 W: Write + Debug {
420 pub fn new(writer: W, stream_id: u32) -> Self {
421 Self {
422 writer,
423 stream_id,
424 packet_index : 0,
425 cur_packet: OggPacket::new(stream_id, OggPacketType::BeginOfStream, 0),
426 granule_position: 0,
427 bytes_written: 0,
428 on_seal: Box::new(|i|i as u64),
429 }
430 }
431
432 pub fn set_granule_position(&mut self, position: u64) {
435 self.granule_position = position
436 }
437
438 pub fn get_granule_position(&self) -> u64 {
440 self.granule_position
441 }
442
443 pub fn mark_cur_packet_as_end_of_stream(&mut self) {
445 self.cur_packet.packet_type = OggPacketType::EndOfStream;
446 }
447
448 pub fn get_bytes_written(&self) -> u64 {
450 self.bytes_written
451 }
452
453 pub fn set_on_seal_callback(&mut self, on_seal: Box<dyn FnMut(usize) -> u64>) {
455 self.on_seal = on_seal;
456 }
457
458 pub fn reset(&mut self) {
460 self.packet_index = 0;
461 self.cur_packet = OggPacket::new(self.stream_id, OggPacketType::BeginOfStream, 0);
462 self.granule_position = 0;
463 self.bytes_written = 0;
464 }
465
466 pub fn seal_packet(&mut self, granule_position: u64, is_end_of_stream: bool) -> io::Result<()> {
468 self.packet_index += 1;
469 self.granule_position = granule_position;
470 self.cur_packet.granule_position = self.granule_position;
471 let packed = if is_end_of_stream {
472 self.cur_packet.packet_type = OggPacketType::EndOfStream;
473 mem::take(&mut self.cur_packet).into_bytes()
474 } else {
475 mem::replace(&mut self.cur_packet, OggPacket::new(self.stream_id, OggPacketType::Continuation, self.packet_index)).into_bytes()
476 };
477 self.writer.write_all(&packed)?;
478 Ok(())
479 }
480}
481
482impl<W> Write for OggStreamWriter<W>
483where
484 W: Write + Debug {
485 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
486 self.bytes_written = buf.len() as u64;
487 let mut buf = buf;
488 let mut written_total = 0usize;
489 while !buf.is_empty() {
490 let written = self.cur_packet.write(buf);
491 buf = &buf[written..];
492 written_total += written;
493 if !buf.is_empty() {
494 self.granule_position = (self.on_seal)(self.cur_packet.get_inner_data_size());
495 self.seal_packet(self.granule_position, false)?;
496 }
497 }
498 Ok(written_total)
499 }
500
501 fn flush(&mut self) -> io::Result<()> {
502 self.writer.flush()
503 }
504}
505
506impl<W> Debug for OggStreamWriter<W>
507where
508 W: Write + Debug {
509 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
510 f.debug_struct(&format!("OggStreamWriter<{}>", std::any::type_name::<W>()))
511 .field("writer", &self.writer)
512 .field("stream_id", &format_args!("0x{:08x}", self.stream_id))
513 .field("packet_index", &self.packet_index)
514 .field("cur_packet", &self.cur_packet)
515 .field("granule_position", &self.granule_position)
516 .field("on_seal", &format_args!("<closure>"))
517 .field("bytes_written", &self.bytes_written)
518 .finish()
519 }
520}
521
522impl<W> Drop for OggStreamWriter<W>
523where
524 W: Write + Debug {
525 fn drop(&mut self) {
526 self.seal_packet(self.granule_position, true).unwrap();
527 }
528}
529