mkv_element/
frame.rs

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
11/// A Matroska encoded frame.
12pub struct Frame<'a> {
13    /// in matroska timestamp units
14    pub data: &'a [u8],
15    /// whether the frame is a keyframe
16    pub is_keyframe: bool,
17    /// whether the frame is invisible (mostly for subtitle tracks)
18    pub is_invisible: bool,
19    /// whether the frame is discardable (for video tracks, e.g. non-reference frames)
20    pub is_discardable: bool,
21    /// track number the frame belongs to
22    pub track_number: u64,
23    /// timestamp of the frame, in the same timescale as the Cluster timestamp
24    pub timestamp: i64,
25    /// duration of the frame, in the same timescale as the Cluster timestamp
26    pub duration: Option<NonZero<u64>>,
27}
28
29/// A block in a Cluster, either a SimpleBlock or a BlockGroup.
30///
31/// This is a convenience enum to allow handling both types of blocks uniformly.
32/// * when reading: often we just want to iterate over all blocks in a cluster, regardless of type.
33/// * when writing: we may want to write a list of blocks of mixed types.
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub enum ClusterBlock {
36    /// A SimpleBlock
37    Simple(SimpleBlock),
38    /// A BlockGroup
39    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        // Without automatic sum types or generators, it's kind of amusing to write an iterator
77        // FIXME: Replace this workaround with a generator or sum type iterator when Rust stabilizes generators (see https://github.com/rust-lang/rust/issues/43122)
78        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                    // no lacing, single frame
137                    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                    // EBML lacing
165                    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                    // fixed-size lacing
182                    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                    // no lacing
222                    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    /// frames in the cluster.
299    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}