webm_iterable/matroska_spec/blocks/
simple_block.rs

1use std::convert::{TryInto, TryFrom};
2
3use ebml_iterable::tools::{self as ebml_tools, Vint};
4
5use crate::{MatroskaSpec, errors::WebmCoercionError};
6use super::block::{Block, BlockLacing, Frame};
7use super::block_utils::{read_frame_data, write_frame_data};
8
9///
10/// A typed interpretation of the Matroska "SimpleBlock" element.
11/// 
12/// This struct has fields specific to the [SimpleBlock](https://www.matroska.org/technical/basics.html#simpleblock-structure) element as defined by the [Matroska Spec](http://www.matroska.org/technical/specs/index.html).  This struct implements `TryFrom<&MatroskaSpec>` and `Into<MatroskaSpec>` to simplify coercion to and from regular enum variants.
13/// 
14/// ## Example
15/// 
16/// ```
17/// # use std::convert::TryInto;
18/// use webm_iterable::matroska_spec::{MatroskaSpec, SimpleBlock};
19/// 
20/// let variant = &MatroskaSpec::SimpleBlock(vec![0x81,0x00,0x01,0x9d,0x00,0x00,0x00]);
21/// let mut simple_block: SimpleBlock = variant.try_into().unwrap();
22/// assert_eq!(true, simple_block.discardable);
23/// ```
24/// 
25#[derive(Clone, Debug)]
26pub struct SimpleBlock<'a> {
27    /// Raw frame data used to create the simple block (avoids the extra allocation of using owned_frame_data)
28    frame_data: &'a [u8],
29
30    /// Owned frame data that can be set to allow changing frame data on the simple block
31    owned_frame_data: Option<Vec<u8>>,
32
33    pub track: u64,
34    pub timestamp: i16,
35
36    pub invisible: bool,
37    pub lacing: Option<BlockLacing>,
38    pub discardable: bool,
39    pub keyframe: bool,
40}
41
42impl<'a> SimpleBlock<'a> {
43    ///
44    /// Reads the raw frame data of the simple block.
45    /// 
46    /// Frame data can be formatted differently depending on the block lacing.  Generally, it is easier to use [`Self::read_frame_data()`] rather than this method to access the frames in the block.  This method is provided in the event raw packet data needs to be handled in a special way (for example, if the data is encrypted).
47    /// 
48    pub fn raw_frame_data(&self) -> &[u8] {
49        self.owned_frame_data.as_deref().unwrap_or(self.frame_data)
50    }
51
52    ///
53    /// Reads the frames encoded in the simple block.
54    /// 
55    /// This method outputs the binary frames encoded in the block, taking into account any block lacing.  Details on block lacing can be found in the [Matroska spec](https://www.matroska.org/technical/notes.html).
56    /// 
57    /// # Errors
58    /// 
59    /// This method can return an error if the frame data is malformed.
60    /// 
61    pub fn read_frame_data(&self) -> Result<Vec<Frame>, WebmCoercionError> {
62        read_frame_data(self.owned_frame_data.as_deref().unwrap_or(self.frame_data), &self.lacing)
63    }
64
65    ///
66    /// Updates the frame data contained in the simple block.
67    /// 
68    /// This method writes frame data to a newly allocated vector owned by the block.  Future calls to [`Self::read_frame_data()`] and [`Self::raw_frame_data()`] will use the data set via this method.
69    /// 
70    /// # Panics
71    /// 
72    /// This method can panic if the block has its lacing set as ['BlockLacing::FixedSize`] and the input frames are not all the same length.
73    /// 
74    pub fn set_frame_data(&mut self, frames: &Vec<Frame>) {
75        let (data, new_lacing) = write_frame_data(frames, self.lacing);
76        self.lacing = new_lacing;
77        self.owned_frame_data = Some(data);
78    }
79
80    ///
81    /// Creates a new simple block with the given data.
82    /// 
83    /// Primarily used when you want to write with a given frame.
84    /// For example, when you want to remux a video with libvpx.
85    /// 
86    /// # Safety
87    /// The frame data is not checked for validity.
88    /// 
89    pub fn new_uncheked(frame_data: &'a [u8], track: u64, timestamp: i16, invisible: bool, lacing: Option<BlockLacing>, discardable: bool, keyframe: bool) -> Self {
90        SimpleBlock {
91            frame_data,
92            owned_frame_data: None,
93            track,
94            timestamp,
95            invisible,
96            lacing,
97            discardable,
98            keyframe,
99        }
100    }
101}
102
103impl<'a> TryFrom<&'a Vec<u8>> for SimpleBlock<'a> {
104    type Error = WebmCoercionError;
105
106    fn try_from(value: &'a Vec<u8>) -> Result<Self, Self::Error> {
107       value.as_slice().try_into()
108    }
109}
110
111impl<'a> TryFrom<&'a [u8]> for SimpleBlock<'a> {
112    type Error = WebmCoercionError;
113
114    fn try_from(data: &'a [u8]) -> Result<Self, Self::Error> {
115        let block: Block = data.try_into()?;
116        let mut position: usize = 0;
117        let (_track, track_size) = ebml_tools::read_vint(data)
118            .map_err(|_| WebmCoercionError::SimpleBlockCoercionError(String::from("Unable to read track data in SimpleBlock.")))?
119            .ok_or_else(|| WebmCoercionError::SimpleBlockCoercionError(String::from("Unable to read track data in SimpleBlock.")))?;
120
121        position += track_size + 2;
122        let flags: u8 = data[position];
123        position += 1;
124
125        let keyframe = flags & 0x80 == 0x80;
126        let discardable = flags & 0x01 == 0x01;
127
128        Ok(SimpleBlock {
129            frame_data: &data[position..],
130            owned_frame_data: None,
131            track: block.track,
132            timestamp: block.timestamp,
133            invisible: block.invisible,
134            lacing: block.lacing,
135            discardable,
136            keyframe,
137        })
138    }
139}
140
141impl<'a> TryFrom<&'a MatroskaSpec> for SimpleBlock<'a> {
142    type Error = WebmCoercionError;
143
144    fn try_from(value: &'a MatroskaSpec) -> Result<Self, Self::Error> {
145        match value {
146            MatroskaSpec::SimpleBlock(data) => {
147                SimpleBlock::try_from(data.as_slice())
148            },
149            _ => Err(WebmCoercionError::SimpleBlockCoercionError(String::from("Only 'SimpleBlock' variants can be converted to a SimpleBlock struct")))
150        }
151    }
152}
153
154impl From<SimpleBlock<'_>> for MatroskaSpec {
155    fn from(simple_block: SimpleBlock) -> Self {        
156        let mut flags: u8 = 0x00;
157        if simple_block.invisible {
158          flags |= 0x08;
159        }
160        
161        if simple_block.lacing.is_some() {
162          match simple_block.lacing.unwrap() {
163            BlockLacing::Xiph => { flags |= 0x02; },
164            BlockLacing::Ebml => { flags |= 0x06; },
165            BlockLacing::FixedSize => { flags |= 0x04; },
166          }
167        }
168
169        if simple_block.discardable {
170            flags |= 0x01;
171        }
172
173        if simple_block.keyframe {
174            flags |= 0x80;
175        }
176
177        let data = simple_block.owned_frame_data.as_deref().unwrap_or(simple_block.frame_data);
178        let mut result = Vec::with_capacity(data.len() + 11);
179        result.extend_from_slice(&simple_block.track.as_vint().expect("Unable to convert track value to vint"));
180        result.extend_from_slice(&simple_block.timestamp.to_be_bytes());
181        result.extend_from_slice(&flags.to_be_bytes());
182        result.extend_from_slice(data);
183
184        MatroskaSpec::SimpleBlock(result)
185    }
186}
187
188#[cfg(test)]
189mod tests {
190    use std::convert::TryFrom;
191
192    use super::MatroskaSpec;
193    use super::SimpleBlock;
194    use super::Frame;
195    use super::BlockLacing;
196
197    #[test]
198    fn decode_encode_simple_block() {
199        let block_content = vec![0x81,0x00,0x01,0x8d,0x01,0x00,0x00];
200        let copy = MatroskaSpec::SimpleBlock(block_content.clone());
201        let simple_block = SimpleBlock::try_from(&copy).unwrap();
202
203        assert!(simple_block.keyframe);
204        assert!(simple_block.discardable);
205        assert!(simple_block.invisible);
206        assert_eq!(Some(BlockLacing::FixedSize), simple_block.lacing);
207        assert_eq!(1, simple_block.track);
208        assert_eq!(1, simple_block.timestamp);
209        assert_eq!(2, simple_block.read_frame_data().unwrap().len());
210
211        let encoded: MatroskaSpec = simple_block.into();
212
213        match encoded {
214            MatroskaSpec::SimpleBlock(data) => {
215                assert_eq!(block_content, data);
216            },
217            _ => panic!("not simple block variant?"),
218        }
219    }
220
221    #[test]
222    fn encode_decode_simple_block_nolacing() {
223        let frames = vec![Frame { data: &[0x01, 0x02, 0x03] }];
224        let mut simple_block = SimpleBlock {
225            frame_data: &[],
226            owned_frame_data: None,
227            track: 1,
228            timestamp: 15,
229            invisible: false,
230            discardable: false,
231            keyframe: true,
232            lacing: None
233        };
234        simple_block.set_frame_data(&frames);
235
236        let encoded: MatroskaSpec = simple_block.clone().into();
237        let redecoded = SimpleBlock::try_from(&encoded).unwrap();
238
239        assert_eq!(simple_block.keyframe, redecoded.keyframe);
240        assert_eq!(simple_block.discardable, redecoded.discardable);
241        assert_eq!(simple_block.invisible, redecoded.invisible);
242        assert_eq!(simple_block.lacing, redecoded.lacing);
243        assert_eq!(simple_block.track, redecoded.track);
244        assert_eq!(simple_block.timestamp, redecoded.timestamp);
245        let redecoded_data = redecoded.read_frame_data().unwrap();
246        for i in 0..frames.len() {
247            assert_eq!(frames[i].data, redecoded_data[i].data);
248        }
249    }
250
251    #[test]
252    fn encode_decode_simple_block_xiphlacing() {
253        let frames = vec![Frame { data: &[0x01, 0x02, 0x03] }, Frame { data: &[0x04, 0x05, 0x06] }, Frame { data: &[0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e] }];
254        let mut simple_block = SimpleBlock {
255            frame_data: &[],
256            owned_frame_data: None,
257            track: 1,
258            timestamp: 15,
259            invisible: false,
260            discardable: false,
261            keyframe: true,
262            lacing: Some(BlockLacing::Xiph)
263        };
264        simple_block.set_frame_data(&frames);
265
266        let encoded: MatroskaSpec = simple_block.clone().into();
267        let redecoded = SimpleBlock::try_from(&encoded).unwrap();
268
269        assert_eq!(simple_block.keyframe, redecoded.keyframe);
270        assert_eq!(simple_block.discardable, redecoded.discardable);
271        assert_eq!(simple_block.invisible, redecoded.invisible);
272        assert_eq!(simple_block.lacing, redecoded.lacing);
273        assert_eq!(simple_block.track, redecoded.track);
274        assert_eq!(simple_block.timestamp, redecoded.timestamp);
275        let redecoded_data = redecoded.read_frame_data().unwrap();
276        for i in 0..frames.len() {
277            assert_eq!(frames[i].data, redecoded_data[i].data);
278        }
279    }
280
281    #[test]
282    fn encode_decode_simple_block_ebmllacing() {
283        let frames = vec![Frame { data: &[0x01, 0x02, 0x03] }, Frame { data: &[0x04, 0x05, 0x06] }, Frame { data: &[0x00] }, Frame { data: &[0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e] }, Frame { data: &[0x01, 0x02] }];
284        let mut simple_block = SimpleBlock {
285            frame_data: &[],
286            owned_frame_data: None,
287            track: 1,
288            timestamp: 15,
289            invisible: false,
290            discardable: false,
291            keyframe: true,
292            lacing: Some(BlockLacing::Ebml)
293        };
294        simple_block.set_frame_data(&frames);
295
296        let encoded: MatroskaSpec = simple_block.clone().into();
297        let redecoded = SimpleBlock::try_from(&encoded).unwrap();
298
299        assert_eq!(simple_block.keyframe, redecoded.keyframe);
300        assert_eq!(simple_block.discardable, redecoded.discardable);
301        assert_eq!(simple_block.invisible, redecoded.invisible);
302        assert_eq!(simple_block.lacing, redecoded.lacing);
303        assert_eq!(simple_block.track, redecoded.track);
304        assert_eq!(simple_block.timestamp, redecoded.timestamp);
305        let redecoded_data = redecoded.read_frame_data().unwrap();
306        for i in 0..frames.len() {
307            assert_eq!(frames[i].data, redecoded_data[i].data);
308        }
309    }
310
311    #[test]
312    fn encode_decode_simple_block_fixedlacing() {
313        let frames = vec![Frame { data: &[0x01, 0x02, 0x03] }, Frame { data: &[0x04, 0x05, 0x06] }];
314        let mut simple_block = SimpleBlock {
315            frame_data: &[],
316            owned_frame_data: None,
317            track: 1,
318            timestamp: 15,
319            invisible: false,
320            discardable: false,
321            keyframe: true,
322            lacing: Some(BlockLacing::FixedSize)
323        };
324        simple_block.set_frame_data(&frames);
325
326        let encoded: MatroskaSpec = simple_block.clone().into();
327        let redecoded = SimpleBlock::try_from(&encoded).unwrap();
328
329        assert_eq!(simple_block.keyframe, redecoded.keyframe);
330        assert_eq!(simple_block.discardable, redecoded.discardable);
331        assert_eq!(simple_block.invisible, redecoded.invisible);
332        assert_eq!(simple_block.lacing, redecoded.lacing);
333        assert_eq!(simple_block.track, redecoded.track);
334        assert_eq!(simple_block.timestamp, redecoded.timestamp);
335        let redecoded_data = redecoded.read_frame_data().unwrap();
336        for i in 0..frames.len() {
337            assert_eq!(frames[i].data, redecoded_data[i].data);
338        }
339    }
340}