1use crate::*;
2
3#[derive(Default, Debug, Clone, PartialEq, Eq)]
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5pub struct Hvcc {
6 pub configuration_version: u8,
7 pub general_profile_space: u8,
8 pub general_tier_flag: bool,
9 pub general_profile_idc: u8,
10 pub general_profile_compatibility_flags: [u8; 4],
11 pub general_constraint_indicator_flags: [u8; 6],
12 pub general_level_idc: u8,
13 pub min_spatial_segmentation_idc: u16,
14 pub parallelism_type: u8,
15 pub chroma_format_idc: u8,
16 pub bit_depth_luma_minus8: u8,
17 pub bit_depth_chroma_minus8: u8,
18 pub avg_frame_rate: u16,
19 pub constant_frame_rate: u8,
20 pub num_temporal_layers: u8,
21 pub temporal_id_nested: bool,
22 pub length_size_minus_one: u8,
23 pub arrays: Vec<HvcCArray>,
24}
25
26impl Hvcc {
27 pub fn new() -> Self {
28 Self {
29 configuration_version: 1,
30 ..Default::default()
31 }
32 }
33}
34
35#[derive(Debug, Clone, PartialEq, Eq, Default)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37pub struct HvcCArray {
38 pub completeness: bool,
39 pub nal_unit_type: u8,
40 pub nalus: Vec<Vec<u8>>,
41}
42
43impl Atom for Hvcc {
44 const KIND: FourCC = FourCC::new(b"hvcC");
45
46 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
47 let configuration_version = u8::decode(buf)?;
48 let params = u8::decode(buf)?;
49 let general_profile_space = (params & 0b11000000) >> 6;
50 let general_tier_flag = ((params & 0b00100000) >> 5) != 0;
51 let general_profile_idc = params & 0b00011111;
52
53 let general_profile_compatibility_flags = <[u8; 4]>::decode(buf)?;
54 let general_constraint_indicator_flags = <[u8; 6]>::decode(buf)?;
55 let general_level_idc = u8::decode(buf)?;
56 let min_spatial_segmentation_idc = u16::decode(buf)? & 0x0FFF;
57 let parallelism_type = u8::decode(buf)? & 0b11;
58 let chroma_format_idc = u8::decode(buf)? & 0b11;
59 let bit_depth_luma_minus8 = u8::decode(buf)? & 0b111;
60 let bit_depth_chroma_minus8 = u8::decode(buf)? & 0b111;
61 let avg_frame_rate = u16::decode(buf)?;
62
63 let params = u8::decode(buf)?;
64 let constant_frame_rate = (params & 0b11000000) >> 6;
65 let num_temporal_layers = (params & 0b00111000) >> 3;
66 let temporal_id_nested = ((params & 0b00000100) >> 2) != 0;
67 let length_size_minus_one = params & 0b000011;
68
69 let num_of_arrays = u8::decode(buf)?;
70
71 let mut arrays = Vec::with_capacity(num_of_arrays as _);
72 for _ in 0..num_of_arrays {
73 let params = u8::decode(buf)?;
74 let num_nalus = u16::decode(buf)?;
75 let mut nalus = Vec::with_capacity(num_nalus as usize);
76
77 for _ in 0..num_nalus {
78 let size = u16::decode(buf)? as usize;
79 let data = Vec::decode_exact(buf, size)?;
80 nalus.push(data)
81 }
82
83 arrays.push(HvcCArray {
84 completeness: (params & 0b10000000) > 0,
85 nal_unit_type: params & 0b111111,
86 nalus,
87 });
88 }
89
90 Ok(Hvcc {
91 configuration_version,
92 general_profile_space,
93 general_tier_flag,
94 general_profile_idc,
95 general_profile_compatibility_flags,
96 general_constraint_indicator_flags,
97 general_level_idc,
98 min_spatial_segmentation_idc,
99 parallelism_type,
100 chroma_format_idc,
101 bit_depth_luma_minus8,
102 bit_depth_chroma_minus8,
103 avg_frame_rate,
104 constant_frame_rate,
105 num_temporal_layers,
106 temporal_id_nested,
107 length_size_minus_one,
108 arrays,
109 })
110 }
111
112 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
113 self.configuration_version.encode(buf)?;
114 let general_profile_space = (self.general_profile_space & 0b11) << 6;
115 let general_tier_flag = u8::from(self.general_tier_flag) << 5;
116 let general_profile_idc = self.general_profile_idc & 0b11111;
117
118 (general_profile_space | general_tier_flag | general_profile_idc).encode(buf)?;
119 self.general_profile_compatibility_flags.encode(buf)?;
120 self.general_constraint_indicator_flags.encode(buf)?;
121 self.general_level_idc.encode(buf)?;
122
123 (0xF000 | (self.min_spatial_segmentation_idc & 0x0FFF)).encode(buf)?;
124 (0b11111100 | (self.parallelism_type & 0b11)).encode(buf)?;
125 (0b11111100 | (self.chroma_format_idc & 0b11)).encode(buf)?;
126 (0b11111000 | (self.bit_depth_luma_minus8 & 0b111)).encode(buf)?;
127 (0b11111000 | (self.bit_depth_chroma_minus8 & 0b111)).encode(buf)?;
128 self.avg_frame_rate.encode(buf)?;
129
130 let constant_frame_rate = (self.constant_frame_rate & 0b11) << 6;
131 let num_temporal_layers = (self.num_temporal_layers & 0b111) << 3;
132 let temporal_id_nested = u8::from(self.temporal_id_nested) << 2;
133 let length_size_minus_one = self.length_size_minus_one & 0b11;
134 (constant_frame_rate | num_temporal_layers | temporal_id_nested | length_size_minus_one)
135 .encode(buf)?;
136 (self.arrays.len() as u8).encode(buf)?;
137 for arr in &self.arrays {
138 ((arr.nal_unit_type & 0b111111) | (u8::from(arr.completeness) << 7)).encode(buf)?;
139 (arr.nalus.len() as u16).encode(buf)?;
140
141 for nalu in &arr.nalus {
142 (nalu.len() as u16).encode(buf)?;
143 nalu.encode(buf)?;
144 }
145 }
146
147 Ok(())
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn test_hev1() {
157 let expected = Hev1 {
158 visual: Visual {
159 data_reference_index: 1,
160 width: 320,
161 height: 240,
162 horizresolution: 0x48.into(),
163 vertresolution: 0x48.into(),
164 frame_count: 1,
165 compressor: "ya boy".into(),
166 depth: 24,
167 },
168 hvcc: Hvcc {
169 configuration_version: 1,
170 ..Default::default()
171 },
172 btrt: None,
173 colr: None,
174 pasp: None,
175 taic: None,
176 fiel: None,
177 };
178 let mut buf = Vec::new();
179 expected.encode(&mut buf).unwrap();
180
181 let mut buf = buf.as_ref();
182 let decoded = Hev1::decode(&mut buf).unwrap();
183 assert_eq!(decoded, expected);
184 }
185
186 const ENCODED_HVCC_LIBHEIF: &[u8] = &[
188 0x00, 0x00, 0x00, 0x7e, 0x68, 0x76, 0x63, 0x43, 0x01, 0x01, 0x60, 0x00, 0x00, 0x00, 0x90,
189 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xf0, 0x00, 0xfc, 0xfd, 0xf8, 0xf8, 0x00, 0x00, 0x0f,
190 0x03, 0x20, 0x00, 0x01, 0x00, 0x19, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60, 0x00,
191 0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x99, 0x8a, 0x02,
192 0x40, 0x21, 0x00, 0x01, 0x00, 0x30, 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00,
193 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0xa0, 0x02, 0x80, 0x80, 0x35, 0x9f,
194 0x59, 0x66, 0x62, 0xa4, 0x91, 0x26, 0xbf, 0xfc, 0x1a, 0xb0, 0x1a, 0xac, 0x04, 0x00, 0x00,
195 0x03, 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0x64, 0x20, 0x22, 0x00, 0x01, 0x00, 0x07, 0x44,
196 0x01, 0xc1, 0x72, 0xb6, 0x62, 0x40,
197 ];
198
199 #[test]
200 fn test_hvcc_libheif_decode() {
201 let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_HVCC_LIBHEIF);
202
203 let hvcc = Hvcc {
204 configuration_version: 1,
205 general_profile_space: 0,
206 general_tier_flag: false,
207 general_profile_idc: 1,
208 general_profile_compatibility_flags: [96, 0, 0, 0],
209 general_constraint_indicator_flags: [144, 0, 0, 0, 0, 0],
210 general_level_idc: 120,
211 min_spatial_segmentation_idc: 0,
212 parallelism_type: 0,
213 chroma_format_idc: 1,
214 bit_depth_luma_minus8: 0,
215 bit_depth_chroma_minus8: 0,
216 avg_frame_rate: 0,
217 constant_frame_rate: 0,
218 num_temporal_layers: 1,
219 temporal_id_nested: true,
220 length_size_minus_one: 3,
221 arrays: vec![
222 HvcCArray {
223 completeness: false,
224 nal_unit_type: 32,
225 nalus: vec![vec![
226 64, 1, 12, 1, 255, 255, 1, 96, 0, 0, 3, 0, 144, 0, 0, 3, 0, 0, 3, 0, 120,
227 153, 138, 2, 64,
228 ]],
229 },
230 HvcCArray {
231 completeness: false,
232 nal_unit_type: 33,
233 nalus: vec![vec![
234 66, 1, 1, 1, 96, 0, 0, 3, 0, 144, 0, 0, 3, 0, 0, 3, 0, 120, 160, 2, 128,
235 128, 53, 159, 89, 102, 98, 164, 145, 38, 191, 252, 26, 176, 26, 172, 4, 0,
236 0, 3, 0, 4, 0, 0, 3, 0, 100, 32,
237 ]],
238 },
239 HvcCArray {
240 completeness: false,
241 nal_unit_type: 34,
242 nalus: vec![vec![68, 1, 193, 114, 182, 98, 64]],
243 },
244 ],
245 };
246 let decoded = Hvcc::decode(buf).unwrap();
247 assert_eq!(decoded, hvcc);
248 }
249
250 #[test]
251 fn test_hvcc_libheif_encode() {
252 let hvcc = Hvcc {
253 configuration_version: 1,
254 general_profile_space: 0,
255 general_tier_flag: false,
256 general_profile_idc: 1,
257 general_profile_compatibility_flags: [96, 0, 0, 0],
258 general_constraint_indicator_flags: [144, 0, 0, 0, 0, 0],
259 general_level_idc: 120,
260 min_spatial_segmentation_idc: 0,
261 parallelism_type: 0,
262 chroma_format_idc: 1,
263 bit_depth_luma_minus8: 0,
264 bit_depth_chroma_minus8: 0,
265 avg_frame_rate: 0,
266 constant_frame_rate: 0,
267 num_temporal_layers: 1,
268 temporal_id_nested: true,
269 length_size_minus_one: 3,
270 arrays: vec![
271 HvcCArray {
272 completeness: false,
273 nal_unit_type: 32,
274 nalus: vec![vec![
275 64, 1, 12, 1, 255, 255, 1, 96, 0, 0, 3, 0, 144, 0, 0, 3, 0, 0, 3, 0, 120,
276 153, 138, 2, 64,
277 ]],
278 },
279 HvcCArray {
280 completeness: false,
281 nal_unit_type: 33,
282 nalus: vec![vec![
283 66, 1, 1, 1, 96, 0, 0, 3, 0, 144, 0, 0, 3, 0, 0, 3, 0, 120, 160, 2, 128,
284 128, 53, 159, 89, 102, 98, 164, 145, 38, 191, 252, 26, 176, 26, 172, 4, 0,
285 0, 3, 0, 4, 0, 0, 3, 0, 100, 32,
286 ]],
287 },
288 HvcCArray {
289 completeness: false,
290 nal_unit_type: 34,
291 nalus: vec![vec![68, 1, 193, 114, 182, 98, 64]],
292 },
293 ],
294 };
295 let mut buf = Vec::new();
296 hvcc.encode(&mut buf).unwrap();
297
298 assert_eq!(buf.as_slice(), ENCODED_HVCC_LIBHEIF);
299 }
300
301 const ENCODED_HVCC_MPEG: &[u8] = &[
304 0x00, 0x00, 0x00, 0xa8, 0x68, 0x76, 0x63, 0x43, 0x01, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00,
305 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0xf0, 0x00, 0xfd, 0xfd, 0xf8, 0xf8, 0x00, 0x00, 0x0f,
306 0x03, 0xa0, 0x00, 0x01, 0x00, 0x41, 0x40, 0x01, 0x0c, 0x11, 0xff, 0xff, 0x01, 0x60, 0x00,
307 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x7b, 0x94, 0x90,
308 0x57, 0x00, 0x00, 0x03, 0x03, 0xe9, 0x00, 0x00, 0xea, 0x60, 0x7f, 0x7b, 0x10, 0x00, 0x04,
309 0x30, 0x24, 0xcf, 0x75, 0x88, 0x0f, 0x00, 0x08, 0x82, 0x80, 0x7b, 0x07, 0x80, 0x04, 0x38,
310 0xa0, 0x0e, 0x0a, 0x52, 0x7b, 0x90, 0xa0, 0x20, 0x20, 0x2c, 0x10, 0xa1, 0x00, 0x01, 0x00,
311 0x31, 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
312 0x00, 0x00, 0x03, 0x00, 0x7b, 0xa0, 0x07, 0x82, 0x00, 0x88, 0x7d, 0xe5, 0x94, 0x99, 0x24,
313 0x6d, 0x86, 0x96, 0x22, 0xaa, 0x4c, 0x4c, 0x32, 0xfb, 0x3e, 0xbc, 0xdf, 0x96, 0x7d, 0x78,
314 0x51, 0x18, 0x9c, 0xbb, 0x64, 0xa2, 0x00, 0x01, 0x00, 0x08, 0x44, 0x01, 0xc1, 0xa5, 0x58,
315 0x11, 0xd0, 0x2a,
316 ];
317
318 #[test]
319 fn test_hvcc_mpeg_decode() {
320 let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_HVCC_MPEG);
321
322 let hvcc = Hvcc {
375 configuration_version: 1,
376 general_profile_space: 0,
377 general_tier_flag: false,
378 general_profile_idc: 1,
379 general_profile_compatibility_flags: [0x60, 0x00, 0x00, 0x00],
380 general_constraint_indicator_flags: [0, 0, 0, 0, 0, 0],
381 general_level_idc: 123,
382 min_spatial_segmentation_idc: 0,
383 parallelism_type: 1,
384 chroma_format_idc: 1,
385 bit_depth_luma_minus8: 0,
386 bit_depth_chroma_minus8: 0,
387 avg_frame_rate: 0,
388 constant_frame_rate: 0,
389 num_temporal_layers: 1,
390 temporal_id_nested: true,
391 length_size_minus_one: 3,
392 arrays: vec![
393 HvcCArray {
394 completeness: true,
395 nal_unit_type: 32,
396 nalus: vec![vec![
397 0x40, 0x01, 0x0C, 0x11, 0xFF, 0xFF, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00,
398 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x7B, 0x94, 0x90,
399 0x57, 0x00, 0x00, 0x03, 0x03, 0xE9, 0x00, 0x00, 0xEA, 0x60, 0x7F, 0x7B,
400 0x10, 0x00, 0x04, 0x30, 0x24, 0xCF, 0x75, 0x88, 0x0F, 0x00, 0x08, 0x82,
401 0x80, 0x7B, 0x07, 0x80, 0x04, 0x38, 0xA0, 0x0E, 0x0A, 0x52, 0x7B, 0x90,
402 0xA0, 0x20, 0x20, 0x2C, 0x10,
403 ]],
404 },
405 HvcCArray {
406 completeness: true,
407 nal_unit_type: 33,
408 nalus: vec![vec![
409 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
410 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x7B, 0xA0, 0x07, 0x82, 0x00, 0x88,
411 0x7D, 0xE5, 0x94, 0x99, 0x24, 0x6D, 0x86, 0x96, 0x22, 0xAA, 0x4C, 0x4C,
412 0x32, 0xFB, 0x3E, 0xBC, 0xDF, 0x96, 0x7D, 0x78, 0x51, 0x18, 0x9C, 0xBB,
413 0x64,
414 ]],
415 },
416 HvcCArray {
417 completeness: true,
418 nal_unit_type: 34,
419 nalus: vec![vec![0x44, 0x01, 0xC1, 0xA5, 0x58, 0x11, 0xD0, 0x2A]],
420 },
421 ],
422 };
423 let decoded = Hvcc::decode(buf).unwrap();
424 assert_eq!(decoded, hvcc);
425 }
426
427 #[test]
428 fn test_hvcc_mpeg_encode() {
429 let hvcc = Hvcc {
430 configuration_version: 1,
431 general_profile_space: 0,
432 general_tier_flag: false,
433 general_profile_idc: 1,
434 general_profile_compatibility_flags: [0x60, 0x00, 0x00, 0x00],
435 general_constraint_indicator_flags: [0, 0, 0, 0, 0, 0],
436 general_level_idc: 123,
437 min_spatial_segmentation_idc: 0,
438 parallelism_type: 1,
439 chroma_format_idc: 1,
440 bit_depth_luma_minus8: 0,
441 bit_depth_chroma_minus8: 0,
442 avg_frame_rate: 0,
443 constant_frame_rate: 0,
444 num_temporal_layers: 1,
445 temporal_id_nested: true,
446 length_size_minus_one: 3,
447 arrays: vec![
448 HvcCArray {
449 completeness: true,
450 nal_unit_type: 32,
451 nalus: vec![vec![
452 0x40, 0x01, 0x0C, 0x11, 0xFF, 0xFF, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00,
453 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x7B, 0x94, 0x90,
454 0x57, 0x00, 0x00, 0x03, 0x03, 0xE9, 0x00, 0x00, 0xEA, 0x60, 0x7F, 0x7B,
455 0x10, 0x00, 0x04, 0x30, 0x24, 0xCF, 0x75, 0x88, 0x0F, 0x00, 0x08, 0x82,
456 0x80, 0x7B, 0x07, 0x80, 0x04, 0x38, 0xA0, 0x0E, 0x0A, 0x52, 0x7B, 0x90,
457 0xA0, 0x20, 0x20, 0x2C, 0x10,
458 ]],
459 },
460 HvcCArray {
461 completeness: true,
462 nal_unit_type: 33,
463 nalus: vec![vec![
464 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
465 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x7B, 0xA0, 0x07, 0x82, 0x00, 0x88,
466 0x7D, 0xE5, 0x94, 0x99, 0x24, 0x6D, 0x86, 0x96, 0x22, 0xAA, 0x4C, 0x4C,
467 0x32, 0xFB, 0x3E, 0xBC, 0xDF, 0x96, 0x7D, 0x78, 0x51, 0x18, 0x9C, 0xBB,
468 0x64,
469 ]],
470 },
471 HvcCArray {
472 completeness: true,
473 nal_unit_type: 34,
474 nalus: vec![vec![0x44, 0x01, 0xC1, 0xA5, 0x58, 0x11, 0xD0, 0x2A]],
475 },
476 ],
477 };
478 let mut buf = Vec::new();
479 hvcc.encode(&mut buf).unwrap();
480
481 assert_eq!(buf.as_slice(), ENCODED_HVCC_MPEG);
482 }
483}