1use std::io::{
2 Read, Write, {self},
3};
4
5use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
6use bytes::Bytes;
7use scuffle_bytes_util::{BitReader, BitWriter};
8
9#[derive(Debug, Clone, PartialEq)]
10pub struct HEVCDecoderConfigurationRecord {
13 pub configuration_version: u8,
15 pub general_profile_space: u8,
17 pub general_tier_flag: bool,
19 pub general_profile_idc: u8,
21 pub general_profile_compatibility_flags: u32,
23 pub general_constraint_indicator_flags: u64,
25 pub general_level_idc: u8,
27 pub min_spatial_segmentation_idc: u16,
29 pub chroma_format_idc: u8,
31 pub bit_depth_luma_minus8: u8,
33 pub bit_depth_chroma_minus8: u8,
35 pub parallelism_type: u8,
45 pub avg_frame_rate: u16,
47 pub constant_frame_rate: u8,
55 pub num_temporal_layers: u8,
63 pub temporal_id_nested: bool,
69 pub length_size_minus_one: u8,
71 pub arrays: Vec<NaluArray>,
74}
75
76#[derive(Debug, Clone, PartialEq)]
77pub struct NaluArray {
80 pub array_completeness: bool,
82 pub nal_unit_type: NaluType,
85 pub nalus: Vec<Bytes>,
88}
89
90#[derive(Debug, Clone, PartialEq, Copy)]
91pub enum NaluType {
94 Vps,
96 Pps,
98 Sps,
100 Unknown(u8),
102}
103
104impl From<u8> for NaluType {
105 fn from(value: u8) -> Self {
106 match value {
107 32 => NaluType::Vps,
108 33 => NaluType::Sps,
109 34 => NaluType::Pps,
110 _ => NaluType::Unknown(value),
111 }
112 }
113}
114
115impl From<NaluType> for u8 {
116 fn from(value: NaluType) -> Self {
117 match value {
118 NaluType::Vps => 32,
119 NaluType::Sps => 33,
120 NaluType::Pps => 34,
121 NaluType::Unknown(value) => value,
122 }
123 }
124}
125
126impl HEVCDecoderConfigurationRecord {
127 pub fn demux(data: &mut io::Cursor<Bytes>) -> io::Result<Self> {
130 let mut bit_reader = BitReader::new(data);
131
132 let configuration_version = bit_reader.read_u8()?;
133 let general_profile_space = bit_reader.read_bits(2)? as u8;
134 let general_tier_flag = bit_reader.read_bit()?;
135 let general_profile_idc = bit_reader.read_bits(5)? as u8;
136 let general_profile_compatibility_flags = bit_reader.read_u32::<LittleEndian>()?;
137 let general_constraint_indicator_flags = bit_reader.read_u48::<LittleEndian>()?;
138 let general_level_idc = bit_reader.read_u8()?;
139
140 bit_reader.seek_bits(4)?; let min_spatial_segmentation_idc = bit_reader.read_bits(12)? as u16;
142
143 bit_reader.seek_bits(6)?; let parallelism_type = bit_reader.read_bits(2)? as u8;
145
146 bit_reader.seek_bits(6)?; let chroma_format_idc = bit_reader.read_bits(2)? as u8;
148
149 bit_reader.seek_bits(5)?; let bit_depth_luma_minus8 = bit_reader.read_bits(3)? as u8;
151
152 bit_reader.seek_bits(5)?; let bit_depth_chroma_minus8 = bit_reader.read_bits(3)? as u8;
154
155 let avg_frame_rate = bit_reader.read_u16::<BigEndian>()?;
156 let constant_frame_rate = bit_reader.read_bits(2)? as u8;
157 let num_temporal_layers = bit_reader.read_bits(3)? as u8;
158 let temporal_id_nested = bit_reader.read_bit()?;
159 let length_size_minus_one = bit_reader.read_bits(2)? as u8;
160
161 let num_of_arrays = bit_reader.read_u8()?;
162
163 let mut arrays = Vec::with_capacity(num_of_arrays as usize);
164
165 for _ in 0..num_of_arrays {
166 let array_completeness = bit_reader.read_bit()?;
167 bit_reader.seek_bits(1)?; let nal_unit_type = bit_reader.read_bits(6)? as u8;
170
171 let num_nalus = bit_reader.read_u16::<BigEndian>()?;
172
173 let mut nalus = Vec::with_capacity(num_nalus as usize);
174
175 for _ in 0..num_nalus {
176 let nal_unit_length = bit_reader.read_u16::<BigEndian>()?;
177 let mut data = vec![0; nal_unit_length as usize];
178 bit_reader.read_exact(&mut data)?;
179 nalus.push(data.into());
180 }
181
182 arrays.push(NaluArray {
183 array_completeness,
184 nal_unit_type: nal_unit_type.into(),
185 nalus,
186 });
187 }
188
189 Ok(HEVCDecoderConfigurationRecord {
190 configuration_version,
191 general_profile_space,
192 general_tier_flag,
193 general_profile_idc,
194 general_profile_compatibility_flags,
195 general_constraint_indicator_flags,
196 general_level_idc,
197 min_spatial_segmentation_idc,
198 parallelism_type,
199 chroma_format_idc,
200 bit_depth_luma_minus8,
201 bit_depth_chroma_minus8,
202 avg_frame_rate,
203 constant_frame_rate,
204 num_temporal_layers,
205 temporal_id_nested,
206 length_size_minus_one,
207 arrays,
208 })
209 }
210
211 pub fn size(&self) -> u64 {
213 1 + 1 + 4 + 6 + 1 + 2 + 1 + 1 + 1 + 1 + 2 + 1 + 1 + self.arrays.iter().map(|array| {
227 1 + 2 + array.nalus.iter().map(|nalu| {
230 2 + nalu.len() as u64 }).sum::<u64>()
233 }).sum::<u64>()
234 }
235
236 pub fn mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
239 let mut bit_writer = BitWriter::new(writer);
240
241 bit_writer.write_u8(self.configuration_version)?;
242 bit_writer.write_bits(self.general_profile_space as u64, 2)?;
243 bit_writer.write_bit(self.general_tier_flag)?;
244 bit_writer.write_bits(self.general_profile_idc as u64, 5)?;
245 bit_writer.write_u32::<LittleEndian>(self.general_profile_compatibility_flags)?;
246 bit_writer.write_u48::<LittleEndian>(self.general_constraint_indicator_flags)?;
247 bit_writer.write_u8(self.general_level_idc)?;
248
249 bit_writer.write_bits(0b1111, 4)?; bit_writer.write_bits(self.min_spatial_segmentation_idc as u64, 12)?;
251
252 bit_writer.write_bits(0b111111, 6)?; bit_writer.write_bits(self.parallelism_type as u64, 2)?;
254
255 bit_writer.write_bits(0b111111, 6)?; bit_writer.write_bits(self.chroma_format_idc as u64, 2)?;
257
258 bit_writer.write_bits(0b11111, 5)?; bit_writer.write_bits(self.bit_depth_luma_minus8 as u64, 3)?;
260
261 bit_writer.write_bits(0b11111, 5)?; bit_writer.write_bits(self.bit_depth_chroma_minus8 as u64, 3)?;
263
264 bit_writer.write_u16::<BigEndian>(self.avg_frame_rate)?;
265 bit_writer.write_bits(self.constant_frame_rate as u64, 2)?;
266
267 bit_writer.write_bits(self.num_temporal_layers as u64, 3)?;
268 bit_writer.write_bit(self.temporal_id_nested)?;
269 bit_writer.write_bits(self.length_size_minus_one as u64, 2)?;
270
271 bit_writer.write_u8(self.arrays.len() as u8)?;
272 for array in &self.arrays {
273 bit_writer.write_bit(array.array_completeness)?;
274 bit_writer.write_bits(0b0, 1)?; bit_writer.write_bits(u8::from(array.nal_unit_type) as u64, 6)?;
276
277 bit_writer.write_u16::<BigEndian>(array.nalus.len() as u16)?;
278
279 for nalu in &array.nalus {
280 bit_writer.write_u16::<BigEndian>(nalu.len() as u16)?;
281 bit_writer.write_all(nalu)?;
282 }
283 }
284
285 bit_writer.finish()?;
286
287 Ok(())
288 }
289}
290
291#[cfg(test)]
292#[cfg_attr(all(test, coverage_nightly), coverage(off))]
293mod tests {
294 use std::io;
295
296 use bytes::Bytes;
297
298 use crate::{ColorConfig, HEVCDecoderConfigurationRecord, NaluType, Sps};
299
300 #[test]
301 fn test_config_demux() {
302 let data = Bytes::from(b"\x01\x01@\0\0\0\x90\0\0\0\0\0\x99\xf0\0\xfc\xfd\xf8\xf8\0\0\x0f\x03 \0\x01\0\x18@\x01\x0c\x01\xff\xff\x01@\0\0\x03\0\x90\0\0\x03\0\0\x03\0\x99\x95@\x90!\0\x01\0=B\x01\x01\x01@\0\0\x03\0\x90\0\0\x03\0\0\x03\0\x99\xa0\x01@ \x05\xa1e\x95R\x90\x84d_\xf8\xc0Z\x80\x80\x80\x82\0\0\x03\0\x02\0\0\x03\x01 \xc0\x0b\xbc\xa2\0\x02bX\0\x011-\x08\"\0\x01\0\x07D\x01\xc0\x93|\x0c\xc9".to_vec());
304
305 let config = HEVCDecoderConfigurationRecord::demux(&mut io::Cursor::new(data)).unwrap();
306
307 assert_eq!(config.configuration_version, 1);
308 assert_eq!(config.general_profile_space, 0);
309 assert!(!config.general_tier_flag);
310 assert_eq!(config.general_profile_idc, 1);
311 assert_eq!(config.general_profile_compatibility_flags, 64);
312 assert_eq!(config.general_constraint_indicator_flags, 144);
313 assert_eq!(config.general_level_idc, 153);
314 assert_eq!(config.min_spatial_segmentation_idc, 0);
315 assert_eq!(config.parallelism_type, 0);
316 assert_eq!(config.chroma_format_idc, 1);
317 assert_eq!(config.bit_depth_luma_minus8, 0);
318 assert_eq!(config.bit_depth_chroma_minus8, 0);
319 assert_eq!(config.avg_frame_rate, 0);
320 assert_eq!(config.constant_frame_rate, 0);
321 assert_eq!(config.num_temporal_layers, 1);
322 assert!(config.temporal_id_nested);
323 assert_eq!(config.length_size_minus_one, 3);
324 assert_eq!(config.arrays.len(), 3);
325
326 let vps = &config.arrays[0];
327 assert!(!vps.array_completeness);
328 assert_eq!(vps.nal_unit_type, NaluType::Vps);
329 assert_eq!(vps.nalus.len(), 1);
330
331 let sps = &config.arrays[1];
332 assert!(!sps.array_completeness);
333 assert_eq!(sps.nal_unit_type, NaluType::Sps);
334 assert_eq!(sps.nalus.len(), 1);
335 let sps = Sps::parse(sps.nalus[0].clone()).unwrap();
336 assert_eq!(
337 sps,
338 Sps {
339 color_config: Some(ColorConfig {
340 full_range: false,
341 color_primaries: 1,
342 matrix_coefficients: 1,
343 transfer_characteristics: 1,
344 }),
345 frame_rate: 144.0,
346 width: 2560,
347 height: 1440,
348 }
349 );
350
351 let pps = &config.arrays[2];
352 assert!(!pps.array_completeness);
353 assert_eq!(pps.nal_unit_type, NaluType::Pps);
354 assert_eq!(pps.nalus.len(), 1);
355 }
356
357 #[test]
358 fn test_config_mux() {
359 let data = Bytes::from(b"\x01\x01@\0\0\0\x90\0\0\0\0\0\x99\xf0\0\xfc\xfd\xf8\xf8\0\0\x0f\x03 \0\x01\0\x18@\x01\x0c\x01\xff\xff\x01@\0\0\x03\0\x90\0\0\x03\0\0\x03\0\x99\x95@\x90!\0\x01\0=B\x01\x01\x01@\0\0\x03\0\x90\0\0\x03\0\0\x03\0\x99\xa0\x01@ \x05\xa1e\x95R\x90\x84d_\xf8\xc0Z\x80\x80\x80\x82\0\0\x03\0\x02\0\0\x03\x01 \xc0\x0b\xbc\xa2\0\x02bX\0\x011-\x08\"\0\x01\0\x07D\x01\xc0\x93|\x0c\xc9".to_vec());
360
361 let config = HEVCDecoderConfigurationRecord::demux(&mut io::Cursor::new(data.clone())).unwrap();
362
363 assert_eq!(config.size(), data.len() as u64);
364
365 let mut buf = Vec::new();
366 config.mux(&mut buf).unwrap();
367
368 assert_eq!(buf, data.to_vec());
369 }
370}