1use byteorder::{BigEndian, WriteBytesExt};
2use serde::Serialize;
3use std::io::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 const TYPE: BoxType = BoxType::Hev1Box;
63
64 fn box_size(&self) -> u64 {
65 self.get_size()
66 }
67
68 fn to_json(&self) -> Result<String, Error> {
69 Ok(serde_json::to_string(&self).unwrap())
70 }
71
72 fn summary(&self) -> Result<String, Error> {
73 let s = format!(
74 "data_reference_index={} width={} height={} frame_count={}",
75 self.data_reference_index, self.width, self.height, self.frame_count
76 );
77 Ok(s)
78 }
79}
80
81impl BlockReader for Hev1Box {
82 fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
83 reader.get_u32(); reader.get_u16(); let data_reference_index = reader.get_u16();
87
88 reader.get_u32(); reader.get_u64(); reader.get_u32(); let width = reader.get_u16();
93 let height = reader.get_u16();
94
95 let horizresolution = FixedPointU16::new_raw(reader.get_u32());
96 let vertresolution = FixedPointU16::new_raw(reader.get_u32());
97
98 reader.get_u32(); let frame_count = reader.get_u16();
101
102 reader.skip(32); let depth = reader.get_u16();
105
106 reader.get_i16(); Ok(Hev1Box {
109 data_reference_index,
110 width,
111 height,
112 horizresolution,
113 vertresolution,
114 frame_count,
115 depth,
116 hvcc: reader.find_box::<HvcCBox>()?,
117 })
118 }
119
120 fn size_hint() -> usize {
121 78
122 }
123}
124
125impl<W: Write> WriteBox<&mut W> for Hev1Box {
126 fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
127 let size = self.box_size();
128 BoxHeader::new(Self::TYPE, size).write(writer)?;
129
130 writer.write_u32::<BigEndian>(0)?; writer.write_u16::<BigEndian>(0)?; writer.write_u16::<BigEndian>(self.data_reference_index)?;
133
134 writer.write_u32::<BigEndian>(0)?; writer.write_u64::<BigEndian>(0)?; writer.write_u32::<BigEndian>(0)?; writer.write_u16::<BigEndian>(self.width)?;
138 writer.write_u16::<BigEndian>(self.height)?;
139 writer.write_u32::<BigEndian>(self.horizresolution.raw_value())?;
140 writer.write_u32::<BigEndian>(self.vertresolution.raw_value())?;
141 writer.write_u32::<BigEndian>(0)?; writer.write_u16::<BigEndian>(self.frame_count)?;
143 write_zeros(writer, 32)?;
145 writer.write_u16::<BigEndian>(self.depth)?;
146 writer.write_i16::<BigEndian>(-1)?; self.hvcc.write_box(writer)?;
149
150 Ok(size)
151 }
152}
153
154#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize)]
155pub struct HvcCBox {
156 pub configuration_version: u8,
157 pub general_profile_space: u8,
158 pub general_tier_flag: bool,
159 pub general_profile_idc: u8,
160 pub general_profile_compatibility_flags: u32,
161 pub general_constraint_indicator_flag: u64,
162 pub general_level_idc: u8,
163 pub min_spatial_segmentation_idc: u16,
164 pub parallelism_type: u8,
165 pub chroma_format_idc: u8,
166 pub bit_depth_luma_minus8: u8,
167 pub bit_depth_chroma_minus8: u8,
168 pub avg_frame_rate: u16,
169 pub constant_frame_rate: u8,
170 pub num_temporal_layers: u8,
171 pub temporal_id_nested: bool,
172 pub length_size_minus_one: u8,
173 pub arrays: Vec<HvcCArray>,
174}
175
176impl HvcCBox {
177 pub fn new() -> Self {
178 Self {
179 configuration_version: 1,
180 ..Default::default()
181 }
182 }
183}
184
185impl Mp4Box for HvcCBox {
186 const TYPE: BoxType = BoxType::HvcCBox;
187
188 fn box_size(&self) -> u64 {
189 HEADER_SIZE
190 + 23
191 + self
192 .arrays
193 .iter()
194 .map(|a| 3 + a.nalus.iter().map(|x| 2 + x.data.len() as u64).sum::<u64>())
195 .sum::<u64>()
196 }
197
198 fn to_json(&self) -> Result<String, Error> {
199 Ok(serde_json::to_string(&self).unwrap())
200 }
201
202 fn summary(&self) -> Result<String, Error> {
203 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={}",
204 self.configuration_version,
205 self.general_profile_space,
206 self.general_tier_flag,
207 self.general_profile_idc,
208 self.general_profile_compatibility_flags,
209 self.general_constraint_indicator_flag,
210 self.general_level_idc,
211 self.min_spatial_segmentation_idc,
212 self.parallelism_type,
213 self.chroma_format_idc,
214 self.bit_depth_luma_minus8,
215 self.bit_depth_chroma_minus8,
216 self.avg_frame_rate,
217 self.constant_frame_rate,
218 self.num_temporal_layers,
219 self.temporal_id_nested,
220 self.length_size_minus_one
221 ))
222 }
223}
224
225#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
226pub struct HvcCArrayNalu {
227 pub size: u16,
228 pub data: Vec<u8>,
229}
230
231#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
232pub struct HvcCArray {
233 pub completeness: bool,
234 pub nal_unit_type: u8,
235 pub nalus: Vec<HvcCArrayNalu>,
236}
237
238impl BlockReader for HvcCBox {
239 fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
240 let configuration_version = reader.get_u8();
241 let params = reader.get_u8();
242 let general_profile_space = params & 0b11000000 >> 6;
243 let general_tier_flag = (params & 0b00100000 >> 5) > 0;
244 let general_profile_idc = params & 0b00011111;
245
246 let general_profile_compatibility_flags = reader.get_u32();
247 let general_constraint_indicator_flag = reader.get_u48();
248
249 let general_level_idc = reader.get_u8();
250 let min_spatial_segmentation_idc = reader.get_u16() & 0x0FFF;
251 let parallelism_type = reader.get_u8() & 0b11;
252 let chroma_format_idc = reader.get_u8() & 0b11;
253 let bit_depth_luma_minus8 = reader.get_u8() & 0b111;
254 let bit_depth_chroma_minus8 = reader.get_u8() & 0b111;
255 let avg_frame_rate = reader.get_u16();
256
257 let params = reader.get_u8();
258 let constant_frame_rate = params & 0b11000000 >> 6;
259 let num_temporal_layers = params & 0b00111000 >> 3;
260 let temporal_id_nested = (params & 0b00000100 >> 2) > 0;
261 let length_size_minus_one = params & 0b000011;
262
263 let num_of_arrays = reader.get_u8();
264
265 if reader.remaining() < num_of_arrays as usize * 3 {
266 return Err(Error::InvalidData(""));
267 }
268
269 let mut arrays = Vec::with_capacity(num_of_arrays as _);
270
271 for _ in 0..num_of_arrays {
272 let params = reader.get_u8();
273 let num_nalus = reader.get_u16();
274
275 if reader.remaining() < num_nalus as usize * 2 {
276 return Err(Error::InvalidData(""));
277 }
278
279 let mut nalus = Vec::with_capacity(num_nalus as usize);
280
281 for _ in 0..num_nalus {
282 let size = reader.get_u16();
283
284 nalus.push(HvcCArrayNalu {
285 size,
286 data: reader.collect(size as _)?,
287 })
288 }
289
290 arrays.push(HvcCArray {
291 completeness: (params & 0b10000000) > 0,
292 nal_unit_type: params & 0b111111,
293 nalus,
294 });
295 }
296
297 Ok(HvcCBox {
298 configuration_version,
299 general_profile_space,
300 general_tier_flag,
301 general_profile_idc,
302 general_profile_compatibility_flags,
303 general_constraint_indicator_flag,
304 general_level_idc,
305 min_spatial_segmentation_idc,
306 parallelism_type,
307 chroma_format_idc,
308 bit_depth_luma_minus8,
309 bit_depth_chroma_minus8,
310 avg_frame_rate,
311 constant_frame_rate,
312 num_temporal_layers,
313 temporal_id_nested,
314 length_size_minus_one,
315 arrays,
316 })
317 }
318
319 fn size_hint() -> usize {
320 23
321 }
322}
323
324impl<W: Write> WriteBox<&mut W> for HvcCBox {
325 fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
326 let size = self.box_size();
327 BoxHeader::new(Self::TYPE, size).write(writer)?;
328
329 writer.write_u8(self.configuration_version)?;
330 let general_profile_space = (self.general_profile_space & 0b11) << 6;
331 let general_tier_flag = u8::from(self.general_tier_flag) << 5;
332 let general_profile_idc = self.general_profile_idc & 0b11111;
333
334 writer.write_u8(general_profile_space | general_tier_flag | general_profile_idc)?;
335 writer.write_u32::<BigEndian>(self.general_profile_compatibility_flags)?;
336 writer.write_u48::<BigEndian>(self.general_constraint_indicator_flag)?;
337 writer.write_u8(self.general_level_idc)?;
338
339 writer.write_u16::<BigEndian>(self.min_spatial_segmentation_idc & 0x0FFF)?;
340 writer.write_u8(self.parallelism_type & 0b11)?;
341 writer.write_u8(self.chroma_format_idc & 0b11)?;
342 writer.write_u8(self.bit_depth_luma_minus8 & 0b111)?;
343 writer.write_u8(self.bit_depth_chroma_minus8 & 0b111)?;
344 writer.write_u16::<BigEndian>(self.avg_frame_rate)?;
345
346 let constant_frame_rate = (self.constant_frame_rate & 0b11) << 6;
347 let num_temporal_layers = (self.num_temporal_layers & 0b111) << 3;
348 let temporal_id_nested = u8::from(self.temporal_id_nested) << 2;
349 let length_size_minus_one = self.length_size_minus_one & 0b11;
350 writer.write_u8(
351 constant_frame_rate | num_temporal_layers | temporal_id_nested | length_size_minus_one,
352 )?;
353 writer.write_u8(self.arrays.len() as u8)?;
354 for arr in &self.arrays {
355 writer.write_u8((arr.nal_unit_type & 0b111111) | u8::from(arr.completeness) << 7)?;
356 writer.write_u16::<BigEndian>(arr.nalus.len() as _)?;
357
358 for nalu in &arr.nalus {
359 writer.write_u16::<BigEndian>(nalu.size)?;
360 writer.write_all(&nalu.data)?;
361 }
362 }
363
364 Ok(size)
365 }
366}
367
368#[cfg(test)]
369mod tests {
370 use super::*;
371 use crate::mp4box::BoxHeader;
372
373 #[tokio::test]
374 async fn test_hev1() {
375 let src_box = Hev1Box {
376 data_reference_index: 1,
377 width: 320,
378 height: 240,
379 horizresolution: FixedPointU16::new(0x48),
380 vertresolution: FixedPointU16::new(0x48),
381 frame_count: 1,
382 depth: 24,
383 hvcc: HvcCBox {
384 configuration_version: 1,
385 ..Default::default()
386 },
387 };
388 let mut buf = Vec::new();
389 src_box.write_box(&mut buf).unwrap();
390 assert_eq!(buf.len(), src_box.box_size() as usize);
391
392 let mut reader = buf.as_slice();
393 let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
394 assert_eq!(header.kind, BoxType::Hev1Box);
395 assert_eq!(src_box.box_size(), header.size);
396
397 let dst_box = Hev1Box::read_block(&mut reader).unwrap();
398 assert_eq!(src_box, dst_box);
399 }
400}