1#![no_std]
3
4extern crate alloc;
5#[cfg(feature = "std")]
6extern crate std;
7
8mod ogg;
9
10use alloc::boxed::Box;
11use core::{convert::TryInto, fmt};
12
13pub struct Demuxer {
14 stream: ogg::Stream,
16
17 header: Option<InternalHeader>,
19 tags: Option<Box<[u8]>>,
20}
21
22impl Demuxer {
23 pub fn new() -> Self {
24 Self {
25 stream: ogg::Stream::new(),
26
27 header: None,
28 tags: None,
29 }
30 }
31
32 pub fn push(&mut self, data: &[u8]) -> Result<()> {
36 self.stream.push(data);
37 'next_page: loop {
38 let mut page = match self.stream.next() {
39 None => {
40 break;
41 }
42 Some(x) => x,
43 };
44 let page_header = page.header();
45
46 if self.header.is_none() {
47 loop {
48 let packet = match page.next() {
49 None => continue 'next_page,
50 Some(x) => x,
51 };
52
53 const ID_MAGIC: &[u8; 8] = b"OpusHead";
55 if page_header.bos {
56 if !packet.starts_with(ID_MAGIC)
58 || packet.get(8).ok_or(Error::Malformed)? & 0xF0 != 0
59 {
60 continue;
61 }
62 self.header = Some(InternalHeader {
63 serial: page_header.stream_serial,
64 header: Header {
65 channels: packet[9],
66 pre_skip: u16::from_le_bytes(
67 packet
68 .get(10..12)
69 .ok_or(Error::Malformed)?
70 .try_into()
71 .unwrap(),
72 ),
73 output_gain: i16::from_le_bytes(
74 packet
75 .get(16..18)
76 .ok_or(Error::Malformed)?
77 .try_into()
78 .unwrap(),
79 ),
80 },
81 });
82 break;
83 }
84 }
85 }
86
87 if self.tags.is_none() {
88 loop {
89 let packet = match page.next() {
90 None => continue 'next_page,
91 Some(x) => x,
92 };
93
94 const COMMENT_MAGIC: &[u8; 8] = b"OpusTags";
96 if Some(page_header.stream_serial) != self.header.as_ref().map(|x| x.serial) {
97 continue;
98 }
99 if packet.starts_with(COMMENT_MAGIC) {
100 self.tags = Some(packet.into());
101 break;
102 }
103 }
104 }
105
106 break;
107 }
108
109 Ok(())
110 }
111
112 #[inline]
114 pub fn header(&self) -> Option<&Header> {
115 self.header.as_ref().map(|x| &x.header)
116 }
117
118 #[inline]
120 pub fn tags(&self) -> Option<&[u8]> {
121 self.tags.as_deref()
122 }
123
124 pub fn next(&mut self) -> Option<&[u8]> {
127 let header = match (&self.header, &self.tags) {
128 (&Some(ref h), &Some(_)) => h,
129 _ => return None,
130 };
131 loop {
132 let page = self.stream.next()?;
133 if page.header().stream_serial != header.serial {
134 continue;
135 }
136 if let Some(packet) = page.into_next() {
137 unsafe {
139 return Some(core::mem::transmute::<&[u8], &[u8]>(packet));
140 }
141 }
142 }
143 }
144}
145
146impl Default for Demuxer {
147 fn default() -> Self {
148 Self::new()
149 }
150}
151
152struct InternalHeader {
153 serial: u32,
154 header: Header,
155}
156
157#[derive(Debug, Copy, Clone)]
158pub struct Header {
159 pub channels: u8,
161 pub pre_skip: u16,
163 pub output_gain: i16,
166}
167
168pub type Result<T> = core::result::Result<T, Error>;
169
170#[derive(Debug, Clone)]
171pub enum Error {
172 Malformed,
173}
174
175impl fmt::Display for Error {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 f.pad("malformed container")
178 }
179}
180
181#[cfg(feature = "std")]
182impl std::error::Error for Error {}