Skip to main content

mkv_element/
frame.rs

1use std::num::NonZero;
2
3use crate::{
4    base::VInt64,
5    lacer::Lacer,
6    leaf::SimpleBlock,
7    master::{BlockGroup, Cluster},
8    *,
9};
10
11/// Frame data, either a single frame or multiple frames (in case of lacing)
12/// See `Frame` for more details.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum FrameData<'a> {
15    /// single frame data
16    Single(&'a [u8]),
17    /// multiple frame data (in case of lacing)
18    Multiple(Vec<&'a [u8]>),
19}
20
21impl<'a> FrameData<'a> {
22    fn single(data: &'a [u8]) -> Self {
23        FrameData::Single(data)
24    }
25    fn multiple(data: Vec<&'a [u8]>) -> Self {
26        FrameData::Multiple(data)
27    }
28}
29/// A Matroska Frame, representing a block(SimpleBlock/BlockGroup).
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct Frame<'a> {
32    /// frame data, either a single frame or multiple frames (in case of lacing)
33    pub data: FrameData<'a>,
34    /// whether the frame is a keyframe
35    pub is_keyframe: bool,
36    /// whether the frame is invisible (mostly for subtitle tracks)
37    pub is_invisible: bool,
38    /// whether the frame is discardable (for video tracks, e.g. non-reference frames)
39    pub is_discardable: bool,
40    /// track number the frame belongs to
41    pub track_number: u64,
42    /// timestamp of the frame, in the same timescale as the Cluster timestamp
43    pub timestamp: i64,
44    /// duration of the frame, in the same timescale as the Cluster timestamp
45    pub duration: Option<NonZero<u64>>,
46}
47
48/// A block in a Cluster, either a SimpleBlock or a BlockGroup.
49///
50/// This is a convenience enum to allow handling both types of blocks uniformly.
51/// * when reading: often we just want to iterate over all blocks in a cluster, regardless of type.
52/// * when writing: we may want to write a list of blocks of mixed types.
53#[derive(Debug, Clone, PartialEq, Eq)]
54pub enum ClusterBlock {
55    /// A SimpleBlock
56    Simple(SimpleBlock),
57    /// A BlockGroup
58    Group(BlockGroup),
59}
60impl ClusterBlock {
61    fn block_ref(&self) -> BlockRef<'_> {
62        match self {
63            ClusterBlock::Simple(b) => BlockRef::Simple(b),
64            ClusterBlock::Group(b) => BlockRef::Group(b),
65        }
66    }
67}
68impl From<SimpleBlock> for ClusterBlock {
69    fn from(b: SimpleBlock) -> Self {
70        ClusterBlock::Simple(b)
71    }
72}
73impl From<BlockGroup> for ClusterBlock {
74    fn from(b: BlockGroup) -> Self {
75        ClusterBlock::Group(b)
76    }
77}
78
79impl Encode for ClusterBlock {
80    fn encode<B: BufMut>(&self, buf: &mut B) -> crate::Result<()> {
81        match self {
82            ClusterBlock::Simple(b) => b.encode(buf),
83            ClusterBlock::Group(b) => b.encode(buf),
84        }
85    }
86}
87
88enum BlockRef<'a> {
89    Simple(&'a crate::leaf::SimpleBlock),
90    Group(&'a crate::master::BlockGroup),
91}
92
93impl<'a> BlockRef<'a> {
94    /// Converts the block into a single frame, placing delaced frames into a FrameData::Multiple.
95    fn into_frame(self, cluster_ts: u64) -> crate::Result<Frame<'a>> {
96        match self {
97            BlockRef::Simple(block) => {
98                let body_buf = &mut &block[..];
99                let track_number = VInt64::decode(body_buf)?;
100                let relative_timestamp = body_buf.try_get_i16()?;
101                let flag = body_buf.try_get_u8()?;
102                let data = *body_buf;
103                let lacing = (flag >> 1) & 0x03;
104                Ok(Frame {
105                    data: match lacing {
106                        0 => FrameData::single(data),
107                        0b01 => FrameData::multiple(Lacer::Xiph.delace(data)?),
108                        0b11 => FrameData::multiple(Lacer::Ebml.delace(data)?),
109                        _ => FrameData::multiple(Lacer::FixedSize.delace(data)?),
110                    },
111                    is_keyframe: (flag & 0x80) != 0,
112                    is_invisible: (flag & 0x08) != 0,
113                    is_discardable: (flag & 0x01) != 0,
114                    track_number: *track_number,
115                    timestamp: cluster_ts as i64 + relative_timestamp as i64,
116                    duration: None,
117                })
118            }
119            BlockRef::Group(g) => {
120                let block = &g.block;
121                let body_buf = &mut &block[..];
122                let track_number = VInt64::decode(body_buf)?;
123                let relative_timestamp = body_buf.try_get_i16()?;
124                let flag = body_buf.try_get_u8()?;
125                let data = *body_buf;
126                let lacing = (flag >> 1) & 0x03;
127
128                Ok(Frame {
129                    data: match lacing {
130                        0 => FrameData::single(data),
131                        0b01 => FrameData::multiple(Lacer::Xiph.delace(data)?),
132                        0b11 => FrameData::multiple(Lacer::Ebml.delace(data)?),
133                        _ => FrameData::multiple(Lacer::FixedSize.delace(data)?),
134                    },
135                    is_keyframe: g.reference_block.is_empty(),
136                    is_invisible: flag & 0x08 != 0,
137                    is_discardable: false,
138                    track_number: *track_number,
139                    timestamp: cluster_ts as i64 + relative_timestamp as i64,
140                    duration: g.block_duration.and_then(|d| NonZero::new(*d)),
141                })
142            }
143        }
144    }
145}
146
147impl<'a> From<&'a crate::leaf::SimpleBlock> for BlockRef<'a> {
148    fn from(b: &'a crate::leaf::SimpleBlock) -> Self {
149        BlockRef::Simple(b)
150    }
151}
152impl<'a> From<&'a crate::master::BlockGroup> for BlockRef<'a> {
153    fn from(b: &'a crate::master::BlockGroup) -> Self {
154        BlockRef::Group(b)
155    }
156}
157
158impl Cluster {
159    /// frames in the cluster.
160    pub fn frames(&self) -> impl Iterator<Item = crate::Result<Frame<'_>>> + '_ {
161        self.blocks
162            .iter()
163            .map(|b| b.block_ref().into_frame(*self.timestamp))
164    }
165}