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