webm_iterable/matroska_spec/blocks/
simple_block.rs1use 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#[derive(Clone, Debug)]
26pub struct SimpleBlock<'a> {
27 frame_data: &'a [u8],
29
30 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 pub fn raw_frame_data(&self) -> &[u8] {
49 self.owned_frame_data.as_deref().unwrap_or(self.frame_data)
50 }
51
52 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 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 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(©).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}