1use crate::{
2 base::VInt64,
3 functional::{Decode, Encode},
4 lacer::Lacer,
5 leaf::SimpleBlock,
6 master::{BlockGroup, Cluster},
7};
8
9pub struct Frame<'a> {
11 pub data: &'a [u8],
13 pub is_keyframe: bool,
15 pub is_invisible: bool,
17 pub is_discardable: bool,
19 pub track_number: u64,
21 pub timestamp: i64,
23}
24
25#[derive(Debug, Clone, PartialEq, Eq)]
31pub enum ClusterBlock {
32 Simple(SimpleBlock),
34 Group(BlockGroup),
36}
37impl ClusterBlock {
38 fn block_ref(&self) -> BlockRef<'_> {
39 match self {
40 ClusterBlock::Simple(b) => BlockRef::Simple(b),
41 ClusterBlock::Group(b) => BlockRef::Group(b),
42 }
43 }
44}
45impl From<SimpleBlock> for ClusterBlock {
46 fn from(b: SimpleBlock) -> Self {
47 ClusterBlock::Simple(b)
48 }
49}
50impl From<BlockGroup> for ClusterBlock {
51 fn from(b: BlockGroup) -> Self {
52 ClusterBlock::Group(b)
53 }
54}
55
56impl Encode for ClusterBlock {
57 fn encode<B: crate::functional::BufMut>(&self, buf: &mut B) -> crate::Result<()> {
58 match self {
59 ClusterBlock::Simple(b) => b.encode(buf),
60 ClusterBlock::Group(b) => b.encode(buf),
61 }
62 }
63}
64
65enum BlockRef<'a> {
66 Simple(&'a crate::leaf::SimpleBlock),
67 Group(&'a crate::master::BlockGroup),
68}
69
70impl<'a> BlockRef<'a> {
71 fn into_frames(self, cluster_ts: u64) -> impl Iterator<Item = crate::Result<Frame<'a>>> + 'a {
72 enum Output<T1, T2, T3, T4, T5, T6, T7> {
75 Once(T1),
76 Xiph(T2),
77 Xiph2(T3),
78 Ebml(T4),
79 Ebml2(T5),
80 FixedSize(T6),
81 FixedSize2(T7),
82 }
83
84 impl<O, T1, T2, T3, T4, T5, T6, T7> Iterator for Output<T1, T2, T3, T4, T5, T6, T7>
85 where
86 T1: Iterator<Item = O>,
87 T2: Iterator<Item = O>,
88 T3: Iterator<Item = O>,
89 T4: Iterator<Item = O>,
90 T5: Iterator<Item = O>,
91 T6: Iterator<Item = O>,
92 T7: Iterator<Item = O>,
93 {
94 type Item = O;
95 fn next(&mut self) -> Option<Self::Item> {
96 match self {
97 Output::Once(it) => it.next(),
98 Output::Xiph(it) => it.next(),
99 Output::Xiph2(it) => it.next(),
100 Output::Ebml(it) => it.next(),
101 Output::Ebml2(it) => it.next(),
102 Output::FixedSize(it) => it.next(),
103 Output::FixedSize2(it) => it.next(),
104 }
105 }
106 }
107
108 match self {
109 BlockRef::Simple(block) => {
110 let body_buf = &mut &block[..];
111
112 let track_number = match VInt64::decode(body_buf) {
113 Ok(num) => num,
114 Err(e) => return Output::Once(std::iter::once(Err(e))),
115 };
116
117 let relative_timestamp = match i16::decode(body_buf) {
118 Ok(ts) => ts,
119 Err(e) => return Output::Once(std::iter::once(Err(e))),
120 };
121
122 let flag = match u8::decode(body_buf) {
123 Ok(f) => f,
124 Err(e) => return Output::Once(std::iter::once(Err(e))),
125 };
126
127 let data = *body_buf;
128
129 let lacing = (flag >> 1) & 0x03;
130
131 if lacing == 0 {
132 Output::Once(std::iter::once(Ok(Frame {
134 data,
135 is_keyframe: (flag & 0x80) != 0,
136 is_invisible: (flag & 0x08) != 0,
137 is_discardable: (flag & 0x01) != 0,
138 track_number: *track_number,
139 timestamp: cluster_ts as i64 + relative_timestamp as i64,
140 })))
141 } else if lacing == 0b01 {
142 let data = match Lacer::Xiph.delace(data) {
143 Ok(frames) => frames,
144 Err(e) => return Output::Once(std::iter::once(Err(e))),
145 };
146
147 Output::Xiph(data.into_iter().map(move |d| {
148 Ok(Frame {
149 data: d,
150 is_keyframe: (flag & 0x80) != 0,
151 is_invisible: (flag & 0x08) != 0,
152 is_discardable: (flag & 0x01) != 0,
153 track_number: *track_number,
154 timestamp: cluster_ts as i64 + relative_timestamp as i64,
155 })
156 }))
157 } else if lacing == 0b11 {
158 let data = match Lacer::Ebml.delace(data) {
160 Ok(frames) => frames,
161 Err(e) => return Output::Once(std::iter::once(Err(e))),
162 };
163 Output::Ebml(data.into_iter().map(move |d| {
164 Ok(Frame {
165 data: d,
166 is_keyframe: (flag & 0x80) != 0,
167 is_invisible: (flag & 0x08) != 0,
168 is_discardable: (flag & 0x01) != 0,
169 track_number: *track_number,
170 timestamp: cluster_ts as i64 + relative_timestamp as i64,
171 })
172 }))
173 } else {
174 let data = match Lacer::FixedSize.delace(data) {
176 Ok(frames) => frames,
177 Err(e) => return Output::Once(std::iter::once(Err(e))),
178 };
179 Output::FixedSize(data.into_iter().map(move |d| {
180 Ok(Frame {
181 data: d,
182 is_keyframe: (flag & 0x80) != 0,
183 is_invisible: (flag & 0x08) != 0,
184 is_discardable: (flag & 0x01) != 0,
185 track_number: *track_number,
186 timestamp: cluster_ts as i64 + relative_timestamp as i64,
187 })
188 }))
189 }
190 }
191 BlockRef::Group(g) => {
192 let block = &g.block;
193 let body_buf = &mut &block[..];
194
195 let track_number = match VInt64::decode(body_buf) {
196 Ok(num) => num,
197 Err(e) => return Output::Once(std::iter::once(Err(e))),
198 };
199
200 let relative_timestamp = match i16::decode(body_buf) {
201 Ok(ts) => ts,
202 Err(e) => return Output::Once(std::iter::once(Err(e))),
203 };
204
205 let flag = match u8::decode(body_buf) {
206 Ok(f) => f,
207 Err(e) => return Output::Once(std::iter::once(Err(e))),
208 };
209
210 let data = *body_buf;
211 let lacing = (flag >> 1) & 0x03;
212 if lacing == 0 {
213 Output::Once(std::iter::once(Ok(Frame {
215 data,
216 is_keyframe: g.reference_block.is_empty(),
217 is_invisible: flag & 0x08 != 0,
218 is_discardable: false,
219 track_number: *track_number,
220 timestamp: cluster_ts as i64 + relative_timestamp as i64,
221 })))
222 } else if lacing == 0b01 {
223 let data = match Lacer::Xiph.delace(data) {
224 Ok(frames) => frames,
225 Err(e) => return Output::Once(std::iter::once(Err(e))),
226 };
227
228 Output::Xiph2(data.into_iter().map(move |d| {
229 Ok(Frame {
230 data: d,
231 is_keyframe: g.reference_block.is_empty(),
232 is_invisible: flag & 0x08 != 0,
233 is_discardable: false,
234 track_number: *track_number,
235 timestamp: cluster_ts as i64 + relative_timestamp as i64,
236 })
237 }))
238 } else if lacing == 0b11 {
239 let data = match Lacer::Ebml.delace(data) {
240 Ok(frames) => frames,
241 Err(e) => return Output::Once(std::iter::once(Err(e))),
242 };
243 Output::Ebml2(data.into_iter().map(move |d| {
244 Ok(Frame {
245 data: d,
246 is_keyframe: g.reference_block.is_empty(),
247 is_invisible: flag & 0x08 != 0,
248 is_discardable: false,
249 track_number: *track_number,
250 timestamp: cluster_ts as i64 + relative_timestamp as i64,
251 })
252 }))
253 } else {
254 let data = match Lacer::FixedSize.delace(data) {
255 Ok(frames) => frames,
256 Err(e) => return Output::Once(std::iter::once(Err(e))),
257 };
258 Output::FixedSize2(data.into_iter().map(move |d| {
259 Ok(Frame {
260 data: d,
261 is_keyframe: g.reference_block.is_empty(),
262 is_invisible: flag & 0x08 != 0,
263 is_discardable: false,
264 track_number: *track_number,
265 timestamp: cluster_ts as i64 + relative_timestamp as i64,
266 })
267 }))
268 }
269 }
270 }
271 }
272}
273
274impl<'a> From<&'a crate::leaf::SimpleBlock> for BlockRef<'a> {
275 fn from(b: &'a crate::leaf::SimpleBlock) -> Self {
276 BlockRef::Simple(b)
277 }
278}
279impl<'a> From<&'a crate::master::BlockGroup> for BlockRef<'a> {
280 fn from(b: &'a crate::master::BlockGroup) -> Self {
281 BlockRef::Group(b)
282 }
283}
284
285impl Cluster {
286 pub fn frames(&self) -> impl Iterator<Item = crate::Result<Frame<'_>>> + '_ {
288 self.blocks
289 .iter()
290 .map(|b| b.block_ref())
291 .flat_map(|b| b.into_frames(*self.timestamp))
292 }
293}