Skip to content

Commit 35560e9

Browse files
hev1 box parser (alfg#101)
Co-authored-by: Alfred Gutierrez <[email protected]>
1 parent 19e4eaa commit 35560e9

File tree

2 files changed

+163
-11
lines changed

2 files changed

+163
-11
lines changed

src/mp4box/hev1.rs

Lines changed: 155 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -158,15 +158,33 @@ impl<W: Write> WriteBox<&mut W> for Hev1Box {
158158
}
159159
}
160160

161-
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
161+
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize)]
162162
pub struct HvcCBox {
163163
pub configuration_version: u8,
164+
pub general_profile_space: u8,
165+
pub general_tier_flag: bool,
166+
pub general_profile_idc: u8,
167+
pub general_profile_compatibility_flags: u32,
168+
pub general_constraint_indicator_flag: u64,
169+
pub general_level_idc: u8,
170+
pub min_spatial_segmentation_idc: u16,
171+
pub parallelism_type: u8,
172+
pub chroma_format_idc: u8,
173+
pub bit_depth_luma_minus8: u8,
174+
pub bit_depth_chroma_minus8: u8,
175+
pub avg_frame_rate: u16,
176+
pub constant_frame_rate: u8,
177+
pub num_temporal_layers: u8,
178+
pub temporal_id_nested: bool,
179+
pub length_size_minus_one: u8,
180+
pub arrays: Vec<HvcCArray>,
164181
}
165182

166183
impl HvcCBox {
167184
pub fn new() -> Self {
168185
Self {
169186
configuration_version: 1,
187+
..Default::default()
170188
}
171189
}
172190
}
@@ -177,29 +195,122 @@ impl Mp4Box for HvcCBox {
177195
}
178196

179197
fn box_size(&self) -> u64 {
180-
HEADER_SIZE + 1
198+
HEADER_SIZE
199+
+ 23
200+
+ self
201+
.arrays
202+
.iter()
203+
.map(|a| 3 + a.nalus.iter().map(|x| 2 + x.data.len() as u64).sum::<u64>())
204+
.sum::<u64>()
181205
}
182206

183207
fn to_json(&self) -> Result<String> {
184208
Ok(serde_json::to_string(&self).unwrap())
185209
}
186210

187211
fn summary(&self) -> Result<String> {
188-
let s = format!("configuration_version={}", self.configuration_version);
189-
Ok(s)
212+
Ok(format!("configuration_version={} general_profile_space={} general_tier_flag={} general_profile_idc={} general_profile_compatibility_flags={} general_constraint_indicator_flag={} general_level_idc={} min_spatial_segmentation_idc={} parallelism_type={} chroma_format_idc={} bit_depth_luma_minus8={} bit_depth_chroma_minus8={} avg_frame_rate={} constant_frame_rate={} num_temporal_layers={} temporal_id_nested={} length_size_minus_one={}",
213+
self.configuration_version,
214+
self.general_profile_space,
215+
self.general_tier_flag,
216+
self.general_profile_idc,
217+
self.general_profile_compatibility_flags,
218+
self.general_constraint_indicator_flag,
219+
self.general_level_idc,
220+
self.min_spatial_segmentation_idc,
221+
self.parallelism_type,
222+
self.chroma_format_idc,
223+
self.bit_depth_luma_minus8,
224+
self.bit_depth_chroma_minus8,
225+
self.avg_frame_rate,
226+
self.constant_frame_rate,
227+
self.num_temporal_layers,
228+
self.temporal_id_nested,
229+
self.length_size_minus_one
230+
))
190231
}
191232
}
192233

193-
impl<R: Read + Seek> ReadBox<&mut R> for HvcCBox {
194-
fn read_box(reader: &mut R, size: u64) -> Result<Self> {
195-
let start = box_start(reader)?;
234+
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
235+
pub struct HvcCArrayNalu {
236+
pub size: u16,
237+
pub data: Vec<u8>,
238+
}
196239

197-
let configuration_version = reader.read_u8()?;
240+
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
241+
pub struct HvcCArray {
242+
pub completeness: bool,
243+
pub nal_unit_type: u8,
244+
pub nalus: Vec<HvcCArrayNalu>,
245+
}
198246

199-
skip_bytes_to(reader, start + size)?;
247+
impl<R: Read + Seek> ReadBox<&mut R> for HvcCBox {
248+
fn read_box(reader: &mut R, _size: u64) -> Result<Self> {
249+
let configuration_version = reader.read_u8()?;
250+
let params = reader.read_u8()?;
251+
let general_profile_space = params & 0b11000000 >> 6;
252+
let general_tier_flag = (params & 0b00100000 >> 5) > 0;
253+
let general_profile_idc = params & 0b00011111;
254+
255+
let general_profile_compatibility_flags = reader.read_u32::<BigEndian>()?;
256+
let general_constraint_indicator_flag = reader.read_u48::<BigEndian>()?;
257+
let general_level_idc = reader.read_u8()?;
258+
let min_spatial_segmentation_idc = reader.read_u16::<BigEndian>()? & 0x0FFF;
259+
let parallelism_type = reader.read_u8()? & 0b11;
260+
let chroma_format_idc = reader.read_u8()? & 0b11;
261+
let bit_depth_luma_minus8 = reader.read_u8()? & 0b111;
262+
let bit_depth_chroma_minus8 = reader.read_u8()? & 0b111;
263+
let avg_frame_rate = reader.read_u16::<BigEndian>()?;
264+
265+
let params = reader.read_u8()?;
266+
let constant_frame_rate = params & 0b11000000 >> 6;
267+
let num_temporal_layers = params & 0b00111000 >> 3;
268+
let temporal_id_nested = (params & 0b00000100 >> 2) > 0;
269+
let length_size_minus_one = params & 0b000011;
270+
271+
let num_of_arrays = reader.read_u8()?;
272+
273+
let mut arrays = Vec::with_capacity(num_of_arrays as _);
274+
for _ in 0..num_of_arrays {
275+
let params = reader.read_u8()?;
276+
let num_nalus = reader.read_u16::<BigEndian>()?;
277+
let mut nalus = Vec::with_capacity(num_nalus as usize);
278+
279+
for _ in 0..num_nalus {
280+
let size = reader.read_u16::<BigEndian>()?;
281+
let mut data = vec![0; size as usize];
282+
283+
reader.read_exact(&mut data)?;
284+
285+
nalus.push(HvcCArrayNalu { size, data })
286+
}
287+
288+
arrays.push(HvcCArray {
289+
completeness: (params & 0b10000000) > 0,
290+
nal_unit_type: params & 0b111111,
291+
nalus,
292+
});
293+
}
200294

201295
Ok(HvcCBox {
202296
configuration_version,
297+
general_profile_space,
298+
general_tier_flag,
299+
general_profile_idc,
300+
general_profile_compatibility_flags,
301+
general_constraint_indicator_flag,
302+
general_level_idc,
303+
min_spatial_segmentation_idc,
304+
parallelism_type,
305+
chroma_format_idc,
306+
bit_depth_luma_minus8,
307+
bit_depth_chroma_minus8,
308+
avg_frame_rate,
309+
constant_frame_rate,
310+
num_temporal_layers,
311+
temporal_id_nested,
312+
length_size_minus_one,
313+
arrays,
203314
})
204315
}
205316
}
@@ -210,6 +321,40 @@ impl<W: Write> WriteBox<&mut W> for HvcCBox {
210321
BoxHeader::new(self.box_type(), size).write(writer)?;
211322

212323
writer.write_u8(self.configuration_version)?;
324+
let general_profile_space = (self.general_profile_space & 0b11) << 6;
325+
let general_tier_flag = u8::from(self.general_tier_flag) << 5;
326+
let general_profile_idc = self.general_profile_idc & 0b11111;
327+
328+
writer.write_u8(general_profile_space | general_tier_flag | general_profile_idc)?;
329+
writer.write_u32::<BigEndian>(self.general_profile_compatibility_flags)?;
330+
writer.write_u48::<BigEndian>(self.general_constraint_indicator_flag)?;
331+
writer.write_u8(self.general_level_idc)?;
332+
333+
writer.write_u16::<BigEndian>(self.min_spatial_segmentation_idc & 0x0FFF)?;
334+
writer.write_u8(self.parallelism_type & 0b11)?;
335+
writer.write_u8(self.chroma_format_idc & 0b11)?;
336+
writer.write_u8(self.bit_depth_luma_minus8 & 0b111)?;
337+
writer.write_u8(self.bit_depth_chroma_minus8 & 0b111)?;
338+
writer.write_u16::<BigEndian>(self.avg_frame_rate)?;
339+
340+
let constant_frame_rate = (self.constant_frame_rate & 0b11) << 6;
341+
let num_temporal_layers = (self.num_temporal_layers & 0b111) << 3;
342+
let temporal_id_nested = u8::from(self.temporal_id_nested) << 2;
343+
let length_size_minus_one = self.length_size_minus_one & 0b11;
344+
writer.write_u8(
345+
constant_frame_rate | num_temporal_layers | temporal_id_nested | length_size_minus_one,
346+
)?;
347+
writer.write_u8(self.arrays.len() as u8)?;
348+
for arr in &self.arrays {
349+
writer.write_u8((arr.nal_unit_type & 0b111111) | u8::from(arr.completeness) << 7)?;
350+
writer.write_u16::<BigEndian>(arr.nalus.len() as _)?;
351+
352+
for nalu in &arr.nalus {
353+
writer.write_u16::<BigEndian>(nalu.size)?;
354+
writer.write_all(&nalu.data)?;
355+
}
356+
}
357+
213358
Ok(size)
214359
}
215360
}
@@ -232,6 +377,7 @@ mod tests {
232377
depth: 24,
233378
hvcc: HvcCBox {
234379
configuration_version: 1,
380+
..Default::default()
235381
},
236382
};
237383
let mut buf = Vec::new();

src/types.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,15 +657,21 @@ pub fn creation_time(creation_time: u64) -> u64 {
657657
}
658658
}
659659

660-
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize)]
660+
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
661661
pub enum DataType {
662-
#[default]
663662
Binary = 0x000000,
664663
Text = 0x000001,
665664
Image = 0x00000D,
666665
TempoCpil = 0x000015,
667666
}
668667

668+
#[allow(clippy::derivable_impls)]
669+
impl std::default::Default for DataType {
670+
fn default() -> Self {
671+
DataType::Binary
672+
}
673+
}
674+
669675
impl TryFrom<u32> for DataType {
670676
type Error = Error;
671677
fn try_from(value: u32) -> Result<DataType> {

0 commit comments

Comments
 (0)