1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
2use serde::Serialize;
3use std::io::{Read, Seek, Write};
4
5use crate::mp4box::*;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
8pub struct Hev1Box {
9 pub data_reference_index: u16,
10 pub width: u16,
11 pub height: u16,
12
13 #[serde(with = "value_u32")]
14 pub horizresolution: FixedPointU16,
15
16 #[serde(with = "value_u32")]
17 pub vertresolution: FixedPointU16,
18 pub frame_count: u16,
19 pub depth: u16,
20 pub hvcc: HvcCBox,
21}
22
23impl Default for Hev1Box {
24 fn default() -> Self {
25 Hev1Box {
26 data_reference_index: 0,
27 width: 0,
28 height: 0,
29 horizresolution: FixedPointU16::new(0x48),
30 vertresolution: FixedPointU16::new(0x48),
31 frame_count: 1,
32 depth: 0x0018,
33 hvcc: HvcCBox::default(),
34 }
35 }
36}
37
38impl Hev1Box {
39 pub fn new(config: &HevcConfig) -> Self {
40 Hev1Box {
41 data_reference_index: 1,
42 width: config.width,
43 height: config.height,
44 horizresolution: FixedPointU16::new(0x48),
45 vertresolution: FixedPointU16::new(0x48),
46 frame_count: 1,
47 depth: 0x0018,
48 hvcc: HvcCBox::new(),
49 }
50 }
51
52 pub fn get_type(&self) -> BoxType {
53 BoxType::Hev1Box
54 }
55
56 pub fn get_size(&self) -> u64 {
57 HEADER_SIZE + 8 + 70 + self.hvcc.box_size()
58 }
59}
60
61impl Mp4Box for Hev1Box {
62 fn box_type(&self) -> BoxType {
63 self.get_type()
64 }
65
66 fn box_size(&self) -> u64 {
67 self.get_size()
68 }
69
70 fn to_json(&self) -> Result<String> {
71 Ok(serde_json::to_string(&self).unwrap())
72 }
73
74 fn summary(&self) -> Result<String> {
75 let s = format!(
76 "data_reference_index={} width={} height={} frame_count={}",
77 self.data_reference_index, self.width, self.height, self.frame_count
78 );
79 Ok(s)
80 }
81}
82
83impl<R: Read + Seek> ReadBox<&mut R> for Hev1Box {
84 fn read_box(reader: &mut R, size: u64) -> Result<Self> {
85 let start = box_start(reader)?;
86
87 reader.read_u32::<BigEndian>()?; reader.read_u16::<BigEndian>()?; let data_reference_index = reader.read_u16::<BigEndian>()?;
90
91 reader.read_u32::<BigEndian>()?; reader.read_u64::<BigEndian>()?; reader.read_u32::<BigEndian>()?; let width = reader.read_u16::<BigEndian>()?;
95 let height = reader.read_u16::<BigEndian>()?;
96 let horizresolution = FixedPointU16::new_raw(reader.read_u32::<BigEndian>()?);
97 let vertresolution = FixedPointU16::new_raw(reader.read_u32::<BigEndian>()?);
98 reader.read_u32::<BigEndian>()?; let frame_count = reader.read_u16::<BigEndian>()?;
100 skip_bytes(reader, 32)?; let depth = reader.read_u16::<BigEndian>()?;
102 reader.read_i16::<BigEndian>()?; let header = BoxHeader::read(reader)?;
105 let BoxHeader { name, size: s } = header;
106 if s > size {
107 return Err(Error::InvalidData(
108 "hev1 box contains a box with a larger size than it",
109 ));
110 }
111 if name == BoxType::HvcCBox {
112 let hvcc = HvcCBox::read_box(reader, s)?;
113
114 skip_bytes_to(reader, start + size)?;
115
116 Ok(Hev1Box {
117 data_reference_index,
118 width,
119 height,
120 horizresolution,
121 vertresolution,
122 frame_count,
123 depth,
124 hvcc,
125 })
126 } else {
127 Err(Error::InvalidData("hvcc not found"))
128 }
129 }
130}
131
132impl<W: Write> WriteBox<&mut W> for Hev1Box {
133 fn write_box(&self, writer: &mut W) -> Result<u64> {
134 let size = self.box_size();
135 BoxHeader::new(self.box_type(), size).write(writer)?;
136
137 writer.write_u32::<BigEndian>(0)?; writer.write_u16::<BigEndian>(0)?; writer.write_u16::<BigEndian>(self.data_reference_index)?;
140
141 writer.write_u32::<BigEndian>(0)?; writer.write_u64::<BigEndian>(0)?; writer.write_u32::<BigEndian>(0)?; writer.write_u16::<BigEndian>(self.width)?;
145 writer.write_u16::<BigEndian>(self.height)?;
146 writer.write_u32::<BigEndian>(self.horizresolution.raw_value())?;
147 writer.write_u32::<BigEndian>(self.vertresolution.raw_value())?;
148 writer.write_u32::<BigEndian>(0)?; writer.write_u16::<BigEndian>(self.frame_count)?;
150 write_zeros(writer, 32)?;
152 writer.write_u16::<BigEndian>(self.depth)?;
153 writer.write_i16::<BigEndian>(-1)?; self.hvcc.write_box(writer)?;
156
157 Ok(size)
158 }
159}
160
161#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize)]
162pub struct HvcCBox {
163 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>,
181}
182
183impl HvcCBox {
184 pub fn new() -> Self {
185 Self {
186 configuration_version: 1,
187 ..Default::default()
188 }
189 }
190}
191
192impl Mp4Box for HvcCBox {
193 fn box_type(&self) -> BoxType {
194 BoxType::HvcCBox
195 }
196
197 fn box_size(&self) -> u64 {
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>()
205 }
206
207 fn to_json(&self) -> Result<String> {
208 Ok(serde_json::to_string(&self).unwrap())
209 }
210
211 fn summary(&self) -> Result<String> {
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 ))
231 }
232}
233
234#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
235pub struct HvcCArrayNalu {
236 pub size: u16,
237 pub data: Vec<u8>,
238}
239
240#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
241pub struct HvcCArray {
242 pub completeness: bool,
243 pub nal_unit_type: u8,
244 pub nalus: Vec<HvcCArrayNalu>,
245}
246
247impl<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 }
294
295 Ok(HvcCBox {
296 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,
314 })
315 }
316}
317
318impl<W: Write> WriteBox<&mut W> for HvcCBox {
319 fn write_box(&self, writer: &mut W) -> Result<u64> {
320 let size = self.box_size();
321 BoxHeader::new(self.box_type(), size).write(writer)?;
322
323 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
358 Ok(size)
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use super::*;
365 use crate::mp4box::BoxHeader;
366 use std::io::Cursor;
367
368 #[test]
369 fn test_hev1() {
370 let src_box = Hev1Box {
371 data_reference_index: 1,
372 width: 320,
373 height: 240,
374 horizresolution: FixedPointU16::new(0x48),
375 vertresolution: FixedPointU16::new(0x48),
376 frame_count: 1,
377 depth: 24,
378 hvcc: HvcCBox {
379 configuration_version: 1,
380 ..Default::default()
381 },
382 };
383 let mut buf = Vec::new();
384 src_box.write_box(&mut buf).unwrap();
385 assert_eq!(buf.len(), src_box.box_size() as usize);
386
387 let mut reader = Cursor::new(&buf);
388 let header = BoxHeader::read(&mut reader).unwrap();
389 assert_eq!(header.name, BoxType::Hev1Box);
390 assert_eq!(src_box.box_size(), header.size);
391
392 let dst_box = Hev1Box::read_box(&mut reader, header.size).unwrap();
393 assert_eq!(src_box, dst_box);
394 }
395}