mkv_element/
frame.rs

1use crate::{
2    base::VInt64,
3    functional::{Decode, Encode},
4    lacer::Lacer,
5    leaf::SimpleBlock,
6    master::{BlockGroup, Cluster},
7};
8
9/// A Matroska encoded frame.
10pub struct Frame<'a> {
11    /// in matroska timestamp units
12    pub data: &'a [u8],
13    /// whether the frame is a keyframe
14    pub is_keyframe: bool,
15    /// whether the frame is invisible (mostly for subtitle tracks)
16    pub is_invisible: bool,
17    /// whether the frame is discardable (for video tracks, e.g. non-reference frames)
18    pub is_discardable: bool,
19    /// track number the frame belongs to
20    pub track_number: u64,
21    /// timestamp of the frame, in the same timescale as the Cluster timestamp
22    pub timestamp: i64,
23}
24
25/// A block in a Cluster, either a SimpleBlock or a BlockGroup.
26///
27/// This is a convenience enum to allow handling both types of blocks uniformly.
28/// * when reading: often we just want to iterate over all blocks in a cluster, regardless of type.
29/// * when writing: we may want to write a list of blocks of mixed types.
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub enum ClusterBlock {
32    /// A SimpleBlock
33    Simple(SimpleBlock),
34    /// A BlockGroup
35    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        // Without automatic sum types or generators, it's kind of amusing to write an iterator
73        // FIXME: Replace this workaround with a generator or sum type iterator when Rust stabilizes generators (see https://github.com/rust-lang/rust/issues/43122)
74        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                    // no lacing, single frame
133                    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                    // EBML lacing
159                    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                    // fixed-size lacing
175                    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                    // no lacing
214                    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    /// frames in the cluster.
287    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}