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 };
177 let mut buf = Vec::new();
178 expected.encode(&mut buf).unwrap();
179
180 let mut buf = buf.as_ref();
181 let decoded = Hev1::decode(&mut buf).unwrap();
182 assert_eq!(decoded, expected);
183 }
184
185 const ENCODED_HVCC_LIBHEIF: &[u8] = &[
187 0x00, 0x00, 0x00, 0x7e, 0x68, 0x76, 0x63, 0x43, 0x01, 0x01, 0x60, 0x00, 0x00, 0x00, 0x90,
188 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xf0, 0x00, 0xfc, 0xfd, 0xf8, 0xf8, 0x00, 0x00, 0x0f,
189 0x03, 0x20, 0x00, 0x01, 0x00, 0x19, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60, 0x00,
190 0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0x99, 0x8a, 0x02,
191 0x40, 0x21, 0x00, 0x01, 0x00, 0x30, 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00,
192 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x78, 0xa0, 0x02, 0x80, 0x80, 0x35, 0x9f,
193 0x59, 0x66, 0x62, 0xa4, 0x91, 0x26, 0xbf, 0xfc, 0x1a, 0xb0, 0x1a, 0xac, 0x04, 0x00, 0x00,
194 0x03, 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0x64, 0x20, 0x22, 0x00, 0x01, 0x00, 0x07, 0x44,
195 0x01, 0xc1, 0x72, 0xb6, 0x62, 0x40,
196 ];
197
198 #[test]
199 fn test_hvcc_libheif_decode() {
200 let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_HVCC_LIBHEIF);
201
202 let hvcc = Hvcc {
203 configuration_version: 1,
204 general_profile_space: 0,
205 general_tier_flag: false,
206 general_profile_idc: 1,
207 general_profile_compatibility_flags: [96, 0, 0, 0],
208 general_constraint_indicator_flags: [144, 0, 0, 0, 0, 0],
209 general_level_idc: 120,
210 min_spatial_segmentation_idc: 0,
211 parallelism_type: 0,
212 chroma_format_idc: 1,
213 bit_depth_luma_minus8: 0,
214 bit_depth_chroma_minus8: 0,
215 avg_frame_rate: 0,
216 constant_frame_rate: 0,
217 num_temporal_layers: 1,
218 temporal_id_nested: true,
219 length_size_minus_one: 3,
220 arrays: vec![
221 HvcCArray {
222 completeness: false,
223 nal_unit_type: 32,
224 nalus: vec![vec![
225 64, 1, 12, 1, 255, 255, 1, 96, 0, 0, 3, 0, 144, 0, 0, 3, 0, 0, 3, 0, 120,
226 153, 138, 2, 64,
227 ]],
228 },
229 HvcCArray {
230 completeness: false,
231 nal_unit_type: 33,
232 nalus: vec![vec![
233 66, 1, 1, 1, 96, 0, 0, 3, 0, 144, 0, 0, 3, 0, 0, 3, 0, 120, 160, 2, 128,
234 128, 53, 159, 89, 102, 98, 164, 145, 38, 191, 252, 26, 176, 26, 172, 4, 0,
235 0, 3, 0, 4, 0, 0, 3, 0, 100, 32,
236 ]],
237 },
238 HvcCArray {
239 completeness: false,
240 nal_unit_type: 34,
241 nalus: vec![vec![68, 1, 193, 114, 182, 98, 64]],
242 },
243 ],
244 };
245 let decoded = Hvcc::decode(buf).unwrap();
246 assert_eq!(decoded, hvcc);
247 }
248
249 #[test]
250 fn test_hvcc_libheif_encode() {
251 let hvcc = Hvcc {
252 configuration_version: 1,
253 general_profile_space: 0,
254 general_tier_flag: false,
255 general_profile_idc: 1,
256 general_profile_compatibility_flags: [96, 0, 0, 0],
257 general_constraint_indicator_flags: [144, 0, 0, 0, 0, 0],
258 general_level_idc: 120,
259 min_spatial_segmentation_idc: 0,
260 parallelism_type: 0,
261 chroma_format_idc: 1,
262 bit_depth_luma_minus8: 0,
263 bit_depth_chroma_minus8: 0,
264 avg_frame_rate: 0,
265 constant_frame_rate: 0,
266 num_temporal_layers: 1,
267 temporal_id_nested: true,
268 length_size_minus_one: 3,
269 arrays: vec![
270 HvcCArray {
271 completeness: false,
272 nal_unit_type: 32,
273 nalus: vec![vec![
274 64, 1, 12, 1, 255, 255, 1, 96, 0, 0, 3, 0, 144, 0, 0, 3, 0, 0, 3, 0, 120,
275 153, 138, 2, 64,
276 ]],
277 },
278 HvcCArray {
279 completeness: false,
280 nal_unit_type: 33,
281 nalus: vec![vec![
282 66, 1, 1, 1, 96, 0, 0, 3, 0, 144, 0, 0, 3, 0, 0, 3, 0, 120, 160, 2, 128,
283 128, 53, 159, 89, 102, 98, 164, 145, 38, 191, 252, 26, 176, 26, 172, 4, 0,
284 0, 3, 0, 4, 0, 0, 3, 0, 100, 32,
285 ]],
286 },
287 HvcCArray {
288 completeness: false,
289 nal_unit_type: 34,
290 nalus: vec![vec![68, 1, 193, 114, 182, 98, 64]],
291 },
292 ],
293 };
294 let mut buf = Vec::new();
295 hvcc.encode(&mut buf).unwrap();
296
297 assert_eq!(buf.as_slice(), ENCODED_HVCC_LIBHEIF);
298 }
299
300 const ENCODED_HVCC_MPEG: &[u8] = &[
303 0x00, 0x00, 0x00, 0xa8, 0x68, 0x76, 0x63, 0x43, 0x01, 0x01, 0x60, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0xf0, 0x00, 0xfd, 0xfd, 0xf8, 0xf8, 0x00, 0x00, 0x0f,
305 0x03, 0xa0, 0x00, 0x01, 0x00, 0x41, 0x40, 0x01, 0x0c, 0x11, 0xff, 0xff, 0x01, 0x60, 0x00,
306 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x7b, 0x94, 0x90,
307 0x57, 0x00, 0x00, 0x03, 0x03, 0xe9, 0x00, 0x00, 0xea, 0x60, 0x7f, 0x7b, 0x10, 0x00, 0x04,
308 0x30, 0x24, 0xcf, 0x75, 0x88, 0x0f, 0x00, 0x08, 0x82, 0x80, 0x7b, 0x07, 0x80, 0x04, 0x38,
309 0xa0, 0x0e, 0x0a, 0x52, 0x7b, 0x90, 0xa0, 0x20, 0x20, 0x2c, 0x10, 0xa1, 0x00, 0x01, 0x00,
310 0x31, 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
311 0x00, 0x00, 0x03, 0x00, 0x7b, 0xa0, 0x07, 0x82, 0x00, 0x88, 0x7d, 0xe5, 0x94, 0x99, 0x24,
312 0x6d, 0x86, 0x96, 0x22, 0xaa, 0x4c, 0x4c, 0x32, 0xfb, 0x3e, 0xbc, 0xdf, 0x96, 0x7d, 0x78,
313 0x51, 0x18, 0x9c, 0xbb, 0x64, 0xa2, 0x00, 0x01, 0x00, 0x08, 0x44, 0x01, 0xc1, 0xa5, 0x58,
314 0x11, 0xd0, 0x2a,
315 ];
316
317 #[test]
318 fn test_hvcc_mpeg_decode() {
319 let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_HVCC_MPEG);
320
321 let hvcc = Hvcc {
374 configuration_version: 1,
375 general_profile_space: 0,
376 general_tier_flag: false,
377 general_profile_idc: 1,
378 general_profile_compatibility_flags: [0x60, 0x00, 0x00, 0x00],
379 general_constraint_indicator_flags: [0, 0, 0, 0, 0, 0],
380 general_level_idc: 123,
381 min_spatial_segmentation_idc: 0,
382 parallelism_type: 1,
383 chroma_format_idc: 1,
384 bit_depth_luma_minus8: 0,
385 bit_depth_chroma_minus8: 0,
386 avg_frame_rate: 0,
387 constant_frame_rate: 0,
388 num_temporal_layers: 1,
389 temporal_id_nested: true,
390 length_size_minus_one: 3,
391 arrays: vec![
392 HvcCArray {
393 completeness: true,
394 nal_unit_type: 32,
395 nalus: vec![vec![
396 0x40, 0x01, 0x0C, 0x11, 0xFF, 0xFF, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00,
397 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x7B, 0x94, 0x90,
398 0x57, 0x00, 0x00, 0x03, 0x03, 0xE9, 0x00, 0x00, 0xEA, 0x60, 0x7F, 0x7B,
399 0x10, 0x00, 0x04, 0x30, 0x24, 0xCF, 0x75, 0x88, 0x0F, 0x00, 0x08, 0x82,
400 0x80, 0x7B, 0x07, 0x80, 0x04, 0x38, 0xA0, 0x0E, 0x0A, 0x52, 0x7B, 0x90,
401 0xA0, 0x20, 0x20, 0x2C, 0x10,
402 ]],
403 },
404 HvcCArray {
405 completeness: true,
406 nal_unit_type: 33,
407 nalus: vec![vec![
408 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
409 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x7B, 0xA0, 0x07, 0x82, 0x00, 0x88,
410 0x7D, 0xE5, 0x94, 0x99, 0x24, 0x6D, 0x86, 0x96, 0x22, 0xAA, 0x4C, 0x4C,
411 0x32, 0xFB, 0x3E, 0xBC, 0xDF, 0x96, 0x7D, 0x78, 0x51, 0x18, 0x9C, 0xBB,
412 0x64,
413 ]],
414 },
415 HvcCArray {
416 completeness: true,
417 nal_unit_type: 34,
418 nalus: vec![vec![0x44, 0x01, 0xC1, 0xA5, 0x58, 0x11, 0xD0, 0x2A]],
419 },
420 ],
421 };
422 let decoded = Hvcc::decode(buf).unwrap();
423 assert_eq!(decoded, hvcc);
424 }
425
426 #[test]
427 fn test_hvcc_mpeg_encode() {
428 let hvcc = Hvcc {
429 configuration_version: 1,
430 general_profile_space: 0,
431 general_tier_flag: false,
432 general_profile_idc: 1,
433 general_profile_compatibility_flags: [0x60, 0x00, 0x00, 0x00],
434 general_constraint_indicator_flags: [0, 0, 0, 0, 0, 0],
435 general_level_idc: 123,
436 min_spatial_segmentation_idc: 0,
437 parallelism_type: 1,
438 chroma_format_idc: 1,
439 bit_depth_luma_minus8: 0,
440 bit_depth_chroma_minus8: 0,
441 avg_frame_rate: 0,
442 constant_frame_rate: 0,
443 num_temporal_layers: 1,
444 temporal_id_nested: true,
445 length_size_minus_one: 3,
446 arrays: vec![
447 HvcCArray {
448 completeness: true,
449 nal_unit_type: 32,
450 nalus: vec![vec![
451 0x40, 0x01, 0x0C, 0x11, 0xFF, 0xFF, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00,
452 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x7B, 0x94, 0x90,
453 0x57, 0x00, 0x00, 0x03, 0x03, 0xE9, 0x00, 0x00, 0xEA, 0x60, 0x7F, 0x7B,
454 0x10, 0x00, 0x04, 0x30, 0x24, 0xCF, 0x75, 0x88, 0x0F, 0x00, 0x08, 0x82,
455 0x80, 0x7B, 0x07, 0x80, 0x04, 0x38, 0xA0, 0x0E, 0x0A, 0x52, 0x7B, 0x90,
456 0xA0, 0x20, 0x20, 0x2C, 0x10,
457 ]],
458 },
459 HvcCArray {
460 completeness: true,
461 nal_unit_type: 33,
462 nalus: vec![vec![
463 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
464 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x7B, 0xA0, 0x07, 0x82, 0x00, 0x88,
465 0x7D, 0xE5, 0x94, 0x99, 0x24, 0x6D, 0x86, 0x96, 0x22, 0xAA, 0x4C, 0x4C,
466 0x32, 0xFB, 0x3E, 0xBC, 0xDF, 0x96, 0x7D, 0x78, 0x51, 0x18, 0x9C, 0xBB,
467 0x64,
468 ]],
469 },
470 HvcCArray {
471 completeness: true,
472 nal_unit_type: 34,
473 nalus: vec![vec![0x44, 0x01, 0xC1, 0xA5, 0x58, 0x11, 0xD0, 0x2A]],
474 },
475 ],
476 };
477 let mut buf = Vec::new();
478 hvcc.encode(&mut buf).unwrap();
479
480 assert_eq!(buf.as_slice(), ENCODED_HVCC_MPEG);
481 }
482}