scuffle_h265/
config.rs

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)]
10/// HEVC Decoder Configuration Record
11/// ISO/IEC 14496-15:2022(E) - 8.3.2.1
12pub struct HEVCDecoderConfigurationRecord {
13    /// The `configuration_version` as a u8. Matches the field as defined in ISO/IEC 23008-2.
14    pub configuration_version: u8,
15    /// The `general_profile_space` as a u8. Matches the field as defined in ISO/IEC 23008-2.
16    pub general_profile_space: u8,
17    /// The `general_tier_flag` as a bool. Matches the field as defined in ISO/IEC 23008-2.
18    pub general_tier_flag: bool,
19    /// The `general_profile_idc` as a u8. Matches the field as defined in ISO/IEC 23008-2.
20    pub general_profile_idc: u8,
21    /// The `general_profile_compatibility_flags` as a u32. Matches the field as defined in ISO/IEC 23008-2.
22    pub general_profile_compatibility_flags: u32,
23    /// The `general_constraint_indicator_flags` as a u64. Matches the field as defined in ISO/IEC 23008-2.
24    pub general_constraint_indicator_flags: u64,
25    /// The `general_level_idc` as a u32. Matches the field as defined in ISO/IEC 23008-2.
26    pub general_level_idc: u8,
27    /// The `min_spatial_segmentation_idc` as a u16. Matches the field as defined in ISO/IEC 23008-2.
28    pub min_spatial_segmentation_idc: u16,
29    /// The `chroma_format_idc` as a u8. Matches the field as defined in ISO/IEC 23008-2.
30    pub chroma_format_idc: u8,
31    /// The `bit_depth_luma_minus8` as a u8. Matches the field as defined in ISO/IEC 23008-2.
32    pub bit_depth_luma_minus8: u8,
33    /// The `bit_depth_chroma_minus8` as a u8. Matches the field as defined in ISO/IEC 23008-2.
34    pub bit_depth_chroma_minus8: u8,
35    /// The `parallelism_type` as a u8.
36    ///
37    /// 0 means the stream supports mixed types of parallel decoding or otherwise.
38    ///
39    /// 1 means the stream supports slice based parallel decoding.
40    ///
41    /// 2 means the stream supports tile based parallel decoding.
42    ///
43    /// 3 means the stream supports entropy coding sync based parallel decoding.
44    pub parallelism_type: u8,
45    /// The `avg_frame_rate` as a u16.
46    pub avg_frame_rate: u16,
47    /// The `constant_frame_rate` as a u8.
48    ///
49    /// 0 means the stream might have a constant frame rate.
50    ///
51    /// 1 means the stream has a constant framerate.
52    ///
53    /// 2 means the representation of each temporal layer in the stream has a constant framerate.
54    pub constant_frame_rate: u8,
55    /// The `num_temporal_layers` as a u8. This is the count of tepmoral layers or `sub-layer`s as defined in ISO/IEC 23008-2.
56    ///
57    /// 0 means the stream might be temporally scalable.
58    ///
59    /// 1 means the stream is NOT temporally scalable.
60    ///
61    /// 2 or more means the stream is temporally scalable, and the count of temporal layers is equal to this value.
62    pub num_temporal_layers: u8,
63    /// The `temporal_id_nested` as a bool.
64    ///
65    /// 0 means means the opposite might not be true (refer to what 1 means for this flag).
66    ///
67    /// 1 means all the activated SPS have `sps_temporal_id_nesting_flag` (as defined in ISC/IEC 23008-2) set to 1 and that temporal sub-layer up-switching to a higehr temporal layer can be done at any sample.
68    pub temporal_id_nested: bool,
69    /// The `length_size_minus_one` is the u8 length of the NALUnitLength minus one.
70    pub length_size_minus_one: u8,
71    /// The `arrays` is a vec of NaluArray.
72    /// Refer to the NaluArray struct in the NaluArray docs for more info.
73    pub arrays: Vec<NaluArray>,
74}
75
76#[derive(Debug, Clone, PartialEq)]
77/// Nalu Array Structure
78/// ISO/IEC 14496-15:2022(E) - 8.3.2.1
79pub struct NaluArray {
80    /// The `array_completeness` is a flag set to 1 when all NAL units are in the array and none are in the stream. It is set to 0 if otherwise.
81    pub array_completeness: bool,
82    /// The `nal_unit_type` is the type of the NAL units in the `nalus` vec, as defined in ISO/IEC 23008-2.
83    /// Refer to the `NaluType` enum for more info.
84    pub nal_unit_type: NaluType,
85    /// `nalus` is a vec of NAL units. Each of these will contain either a VPS, PPS, SPS, or an unknown u8 as specified in ISO/IEC 23008-2.
86    /// Refer to the `NaluType` enum for more info.
87    pub nalus: Vec<Bytes>,
88}
89
90#[derive(Debug, Clone, PartialEq, Copy)]
91/// The Nalu Type.
92/// ISO/IEC 23008-2:2020(E) - 7.4.2.2 (Table 7-1)
93pub enum NaluType {
94    /// The Video Parameter Set.
95    Vps,
96    /// The Picture Parameter Set.
97    Pps,
98    /// The Sequence Parameter Set.
99    Sps,
100    /// An unknown u8. This is the default value if the NaluType is set to something other than VPS, PPS, or SPS.
101    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    /// Demuxes an HEVCDecoderConfigurationRecord from a byte stream.
128    /// Returns a demuxed HEVCDecoderConfigurationRecord.
129    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)?; // reserved_4bits
141        let min_spatial_segmentation_idc = bit_reader.read_bits(12)? as u16;
142
143        bit_reader.seek_bits(6)?; // reserved_6bits
144        let parallelism_type = bit_reader.read_bits(2)? as u8;
145
146        bit_reader.seek_bits(6)?; // reserved_6bits
147        let chroma_format_idc = bit_reader.read_bits(2)? as u8;
148
149        bit_reader.seek_bits(5)?; // reserved_5bits
150        let bit_depth_luma_minus8 = bit_reader.read_bits(3)? as u8;
151
152        bit_reader.seek_bits(5)?; // reserved_5bits
153        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)?; // reserved
168
169            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    /// Returns the total byte size of the HEVCDecoderConfigurationRecord.
212    pub fn size(&self) -> u64 {
213        1 // configuration_version
214        + 1 // general_profile_space, general_tier_flag, general_profile_idc
215        + 4 // general_profile_compatibility_flags
216        + 6 // general_constraint_indicator_flags
217        + 1 // general_level_idc
218        + 2 // reserved_4bits, min_spatial_segmentation_idc
219        + 1 // reserved_6bits, parallelism_type
220        + 1 // reserved_6bits, chroma_format_idc
221        + 1 // reserved_5bits, bit_depth_luma_minus8
222        + 1 // reserved_5bits, bit_depth_chroma_minus8
223        + 2 // avg_frame_rate
224        + 1 // constant_frame_rate, num_temporal_layers, temporal_id_nested, length_size_minus_one
225        + 1 // num_of_arrays
226        + self.arrays.iter().map(|array| {
227            1 // array_completeness, reserved, nal_unit_type
228            + 2 // num_nalus
229            + array.nalus.iter().map(|nalu| {
230                2 // nal_unit_length
231                + nalu.len() as u64 // nal_unit
232            }).sum::<u64>()
233        }).sum::<u64>()
234    }
235
236    /// Muxes the HEVCDecoderConfigurationRecord into a byte stream.
237    /// Returns a muxed byte stream.
238    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)?; // reserved_4bits
250        bit_writer.write_bits(self.min_spatial_segmentation_idc as u64, 12)?;
251
252        bit_writer.write_bits(0b111111, 6)?; // reserved_6bits
253        bit_writer.write_bits(self.parallelism_type as u64, 2)?;
254
255        bit_writer.write_bits(0b111111, 6)?; // reserved_6bits
256        bit_writer.write_bits(self.chroma_format_idc as u64, 2)?;
257
258        bit_writer.write_bits(0b11111, 5)?; // reserved_5bits
259        bit_writer.write_bits(self.bit_depth_luma_minus8 as u64, 3)?;
260
261        bit_writer.write_bits(0b11111, 5)?; // reserved_5bits
262        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)?; // reserved
275            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        // h265 config
303        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}