use crate::Result;
#[repr(Rust, packed)]
#[derive(Debug, Clone)]
pub struct OggHeader {
pub capture_pattern: [u8; 4],
pub version: u8,
pub header_type: u8,
pub granule_position: u64,
pub bitstream_serial: u32,
pub page_sequence: u32,
pub checksum: u32,
pub page_segments: u8,
}
pub struct Page {
pub header: OggHeader,
pub segments: Vec<Vec<u8>>,
}
pub struct PageReader {
data: Vec<u8>,
}
impl PageReader {
pub fn new() -> Self {
Self { data: vec![] }
}
pub fn append_bytes(&mut self, data: &[u8]) {
self.data.extend_from_slice(data)
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Result<Option<Page>> {
let hdr_size = std::mem::size_of::<OggHeader>();
if self.data.len() < hdr_size {
return Ok(None);
}
let hdr: OggHeader =
unsafe { std::ptr::read_unaligned(self.data.as_ptr() as *const OggHeader) };
if &hdr.capture_pattern != b"OggS" {
return Err(crate::Error::OggUnexpectedCapturePattern(hdr.capture_pattern));
}
if hdr.version != 0 {
return Err(crate::Error::OggUnsupportedVersion(hdr.version));
}
let nsegments = hdr.page_segments as usize;
if self.data.len() < hdr_size + nsegments {
return Ok(None);
}
let segment_table = &self.data[hdr_size..hdr_size + nsegments];
let page_size =
hdr_size + nsegments + segment_table.iter().map(|v| *v as usize).sum::<usize>();
if self.data.len() < page_size {
return Ok(None);
}
let mut segments = Vec::with_capacity(nsegments);
let mut start_offset = hdr_size + nsegments;
for &slen in segment_table.iter() {
segments.push(self.data[start_offset..start_offset + slen as usize].to_vec());
start_offset += slen as usize;
}
self.data.drain(..page_size);
Ok(Some(Page { header: hdr, segments }))
}
}
pub struct PacketReader {
page_reader: PageReader,
segments: Vec<Vec<u8>>,
packets: std::collections::VecDeque<Vec<u8>>,
}
impl PacketReader {
pub fn new() -> Self {
Self {
page_reader: PageReader::new(),
segments: vec![],
packets: std::collections::VecDeque::new(),
}
}
pub fn append_bytes(&mut self, data: &[u8]) {
self.page_reader.append_bytes(data)
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Result<Option<Vec<u8>>> {
while let Some(page) = self.page_reader.next()? {
for segment in page.segments.into_iter() {
let slen = segment.len();
self.segments.push(segment);
if slen < 255 {
let packet = self.segments.concat();
self.packets.push_back(packet);
self.segments.clear();
}
}
}
let p = self.packets.pop_front();
Ok(p)
}
}
impl Default for PageReader {
fn default() -> Self {
Self::new()
}
}
impl Default for PacketReader {
fn default() -> Self {
Self::new()
}
}