webm_iterable/matroska_spec/blocks/
block.rs1use std::convert::{TryFrom, TryInto};
2use ebml_iterable::tools::{self as ebml_tools, Vint};
3
4use crate::errors::WebmCoercionError;
5use crate::MatroskaSpec;
6use super::block_utils::{read_frame_data, write_frame_data};
7
8#[derive(PartialEq, Copy, Clone, Debug)]
14pub enum BlockLacing {
15 Xiph,
16 Ebml,
17 FixedSize,
18}
19
20#[derive(Clone, Debug)]
26pub struct Frame<'a> {
27 pub data: &'a [u8]
28}
29
30#[derive(Clone, Debug)]
47pub struct Block<'a> {
48 frame_data: &'a [u8],
50
51 owned_frame_data: Option<Vec<u8>>,
53
54 pub track: u64,
55 pub timestamp: i16,
56
57 pub invisible: bool,
58 pub lacing: Option<BlockLacing>,
59}
60
61impl<'a> Block<'a> {
62 pub fn raw_frame_data(&self) -> &[u8] {
68 self.owned_frame_data.as_deref().unwrap_or(self.frame_data)
69 }
70
71 pub fn read_frame_data(&self) -> Result<Vec<Frame>, WebmCoercionError> {
81 read_frame_data(self.owned_frame_data.as_deref().unwrap_or(self.frame_data), &self.lacing)
82 }
83
84 pub fn set_frame_data(&mut self, frames: &Vec<Frame>) {
94 let (data, new_lacing) = write_frame_data(frames, self.lacing);
95 self.lacing = new_lacing;
96 self.owned_frame_data = Some(data);
97 }
98
99 pub fn new_uncheked(track: u64, timestamp: i16, invisible: bool, lacing: Option<BlockLacing>, frame_data: &'a [u8]) -> Self {
106 Block {
107 frame_data,
108 owned_frame_data: None,
109 track,
110 timestamp,
111 invisible,
112 lacing,
113 }
114 }
115}
116
117impl<'a> TryFrom<&'a Vec<u8>> for Block<'a> {
118 type Error = WebmCoercionError;
119
120 fn try_from(value: &'a Vec<u8>) -> Result<Self, Self::Error> {
121 value.as_slice().try_into()
122 }
123}
124
125impl<'a> TryFrom<&'a [u8]> for Block<'a> {
126 type Error = WebmCoercionError;
127
128 fn try_from(data: &'a [u8]) -> Result<Self, Self::Error> {
129 let mut position: usize = 0;
130 let (track, track_size) = ebml_tools::read_vint(data)
131 .map_err(|_| WebmCoercionError::BlockCoercionError(String::from("Unable to read track data in Block.")))?
132 .ok_or_else(|| WebmCoercionError::BlockCoercionError(String::from("Unable to read track data in Block.")))?;
133
134 position += track_size;
135
136 let value: [u8; 2] = data[position..position + 2].try_into()
137 .map_err(|_| WebmCoercionError::BlockCoercionError(String::from("Attempting to create Block tag, but binary data length was not 2")))?;
138 let timestamp = i16::from_be_bytes(value);
139 position += 2;
140
141 let flags: u8 = data[position];
142 position += 1;
143 let invisible = (flags & 0x08) == 0x08;
144
145 let lacing: Option<BlockLacing>;
146 if flags & 0x06 == 0x06 {
147 lacing = Some(BlockLacing::Ebml);
148 } else if flags & 0x06 == 0x04 {
149 lacing = Some(BlockLacing::FixedSize);
150 } else if flags & 0x06 == 0x02 {
151 lacing = Some(BlockLacing::Xiph);
152 } else {
153 lacing = None;
154 }
155
156 let payload = &data[position..];
157
158 Ok(Block {
159 frame_data: payload,
160 owned_frame_data: None,
161 track,
162 timestamp,
163 invisible,
164 lacing,
165 })
166 }
167}
168
169impl<'a> TryFrom<&'a MatroskaSpec> for Block<'a> {
170 type Error = WebmCoercionError;
171
172 fn try_from(value: &'a MatroskaSpec) -> Result<Self, Self::Error> {
173 match value {
174 MatroskaSpec::Block(data) => {
175 Block::try_from(data.as_slice())
176 }
177 _ => Err(WebmCoercionError::BlockCoercionError(String::from("Expected binary tag type for Block tag, but received a different type!"))),
178 }
179 }
180}
181
182impl From<Block<'_>> for MatroskaSpec {
183 fn from(block: Block) -> Self {
184 let mut flags: u8 = 0x00;
185 if block.invisible {
186 flags |= 0x08;
187 }
188
189 if block.lacing.is_some() {
190 match block.lacing.unwrap() {
191 BlockLacing::Xiph => {
192 flags |= 0x02;
193 }
194 BlockLacing::Ebml => {
195 flags |= 0x06;
196 }
197 BlockLacing::FixedSize => {
198 flags |= 0x04;
199 }
200 }
201 }
202
203 let data = block.owned_frame_data.as_deref().unwrap_or(block.frame_data);
204 let mut result = Vec::with_capacity(data.len() + 11);
205 result.extend_from_slice(&block.track.as_vint().expect("Unable to convert track value to vint"));
206 result.extend_from_slice(&block.timestamp.to_be_bytes());
207 result.extend_from_slice(&flags.to_be_bytes());
208 result.extend_from_slice(data);
209
210 MatroskaSpec::Block(result)
211 }
212}