scuffle_h265/
config.rs

1use std::io::{
2    Read, Write, {self},
3};
4
5use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
6use scuffle_bytes_util::zero_copy::{Deserialize, Serialize};
7use scuffle_bytes_util::{BitReader, BitWriter, BytesCow};
8
9use crate::{ConstantFrameRate, NALUnitType, NumTemporalLayers, ParallelismType, ProfileCompatibilityFlags};
10
11/// HEVC Decoder Configuration Record.
12///
13/// ISO/IEC 14496-15 - 8.3.2.1
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct HEVCDecoderConfigurationRecord<'a> {
16    /// Matches the [`general_profile_space`](crate::Profile::profile_space) field as defined in ISO/IEC 23008-2.
17    pub general_profile_space: u8,
18    /// Matches the [`general_tier_flag`](crate::Profile::tier_flag) field as defined in ISO/IEC 23008-2.
19    pub general_tier_flag: bool,
20    /// Matches the [`general_profile_idc`](crate::Profile::profile_idc) field as defined in ISO/IEC 23008-2.
21    pub general_profile_idc: u8,
22    /// Matches the [`general_profile_compatibility_flag`](crate::Profile::profile_compatibility_flag) field as defined in ISO/IEC 23008-2.
23    pub general_profile_compatibility_flags: ProfileCompatibilityFlags,
24    /// This is stored as a 48-bit (6 bytes) unsigned integer.
25    /// Therefore only the first 48 bits of this value are used.
26    pub general_constraint_indicator_flags: u64,
27    /// Matches the [`general_level_idc`](crate::Profile::level_idc) field as defined in ISO/IEC 23008-2.
28    pub general_level_idc: u8,
29    /// Matches the [`min_spatial_segmentation_idc`](crate::BitStreamRestriction::min_spatial_segmentation_idc) field as defined in ISO/IEC 23008-2.
30    pub min_spatial_segmentation_idc: u16,
31    /// See [`ParallelismType`] for more info.
32    pub parallelism_type: ParallelismType,
33    /// Matches the [`chroma_format_idc`](crate::SpsRbsp::chroma_format_idc) field as defined in ISO/IEC 23008-2.
34    pub chroma_format_idc: u8,
35    /// Matches the [`bit_depth_luma_minus8`](crate::SpsRbsp::bit_depth_luma_minus8) field as defined in ISO/IEC 23008-2.
36    pub bit_depth_luma_minus8: u8,
37    /// Matches the [`bit_depth_chroma_minus8`](crate::SpsRbsp::bit_depth_chroma_minus8) field as defined in ISO/IEC 23008-2.
38    pub bit_depth_chroma_minus8: u8,
39    /// Gives the average frame rate in units of frames/(256 seconds), for the stream to
40    /// which this configuration record applies.
41    ///
42    /// Value 0 indicates an unspecified average frame rate.
43    pub avg_frame_rate: u16,
44    /// See [`ConstantFrameRate`] for more info.
45    pub constant_frame_rate: ConstantFrameRate,
46    /// This is the count of tepmoral layers or sub-layers as defined in ISO/IEC 23008-2.
47    pub num_temporal_layers: NumTemporalLayers,
48    /// Equal to `true` indicates that all SPSs that are activated when the stream to which
49    /// this configuration record applies is decoded have
50    /// [`sps_temporal_id_nesting_flag`](crate::SpsRbsp::sps_temporal_id_nesting_flag) as defined in
51    /// ISO/IEC 23008-2 equal to `true` and temporal sub-layer up-switching to any higher temporal layer
52    /// can be performed at any sample.
53    ///
54    /// Value `false` indicates that the conditions above are not or may not be met.
55    pub temporal_id_nested: bool,
56    /// This value plus 1 indicates the length in bytes of the `NALUnitLength` field in an
57    /// HEVC video sample in the stream to which this configuration record applies.
58    ///
59    /// For example, a size of one byte is indicated with a value of 0.
60    /// The value of this field is one of 0, 1, or 3
61    /// corresponding to a length encoded with 1, 2, or 4 bytes, respectively.
62    pub length_size_minus_one: u8,
63    /// [`NaluArray`]s in that are part of this configuration record.
64    pub arrays: Vec<NaluArray<'a>>,
65}
66
67/// Nalu Array Structure
68///
69/// ISO/IEC 14496-15 - 8.3.2.1
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct NaluArray<'a> {
72    /// When equal to `true` indicates that all NAL units of the given type are in the
73    /// following array and none are in the stream; when equal to `false` indicates that additional NAL units
74    /// of the indicated type may be in the stream; the default and permitted values are constrained by
75    /// the sample entry name.
76    pub array_completeness: bool,
77    /// Indicates the type of the NAL units in the following array (which shall be all of
78    /// that type); it takes a value as defined in ISO/IEC 23008-2; it is restricted to take one of the
79    /// values indicating a VPS, SPS, PPS, prefix SEI, or suffix SEI NAL unit.
80    pub nal_unit_type: NALUnitType,
81    /// The raw byte stream of NAL units.
82    ///
83    /// You might want to use [`SpsNALUnit::parse`](crate::SpsNALUnit::parse)
84    /// to parse an SPS NAL unit.
85    pub nalus: Vec<BytesCow<'a>>,
86}
87
88impl<'a> Deserialize<'a> for HEVCDecoderConfigurationRecord<'a> {
89    fn deserialize<R>(mut reader: R) -> io::Result<Self>
90    where
91        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
92    {
93        let mut bit_reader = BitReader::new(reader.as_std());
94
95        // This demuxer only supports version 1
96        let configuration_version = bit_reader.read_u8()?;
97        if configuration_version != 1 {
98            return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid configuration version"));
99        }
100
101        let general_profile_space = bit_reader.read_bits(2)? as u8;
102        let general_tier_flag = bit_reader.read_bit()?;
103        let general_profile_idc = bit_reader.read_bits(5)? as u8;
104        let general_profile_compatibility_flags =
105            ProfileCompatibilityFlags::from_bits_retain(bit_reader.read_u32::<BigEndian>()?);
106        let general_constraint_indicator_flags = bit_reader.read_u48::<BigEndian>()?;
107        let general_level_idc = bit_reader.read_u8()?;
108
109        bit_reader.read_bits(4)?; // reserved_4bits
110        let min_spatial_segmentation_idc = bit_reader.read_bits(12)? as u16;
111
112        bit_reader.read_bits(6)?; // reserved_6bits
113        let parallelism_type = bit_reader.read_bits(2)? as u8;
114
115        bit_reader.read_bits(6)?; // reserved_6bits
116        let chroma_format_idc = bit_reader.read_bits(2)? as u8;
117
118        bit_reader.read_bits(5)?; // reserved_5bits
119        let bit_depth_luma_minus8 = bit_reader.read_bits(3)? as u8;
120
121        bit_reader.read_bits(5)?; // reserved_5bits
122        let bit_depth_chroma_minus8 = bit_reader.read_bits(3)? as u8;
123
124        let avg_frame_rate = bit_reader.read_u16::<BigEndian>()?;
125        let constant_frame_rate = bit_reader.read_bits(2)? as u8;
126        let num_temporal_layers = bit_reader.read_bits(3)? as u8;
127        let temporal_id_nested = bit_reader.read_bit()?;
128        let length_size_minus_one = bit_reader.read_bits(2)? as u8;
129
130        if length_size_minus_one == 2 {
131            return Err(io::Error::new(
132                io::ErrorKind::InvalidData,
133                "length_size_minus_one must be 0, 1, or 3",
134            ));
135        }
136
137        let num_of_arrays = bit_reader.read_u8()?;
138
139        let mut arrays = Vec::with_capacity(num_of_arrays as usize);
140
141        for _ in 0..num_of_arrays {
142            let array_completeness = bit_reader.read_bit()?;
143            bit_reader.read_bits(1)?; // reserved
144
145            let nal_unit_type = bit_reader.read_bits(6)? as u8;
146            let nal_unit_type = NALUnitType::from(nal_unit_type);
147            if nal_unit_type != NALUnitType::VpsNut
148                && nal_unit_type != NALUnitType::SpsNut
149                && nal_unit_type != NALUnitType::PpsNut
150                && nal_unit_type != NALUnitType::PrefixSeiNut
151                && nal_unit_type != NALUnitType::SuffixSeiNut
152            {
153                return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid nal_unit_type"));
154            }
155
156            let num_nalus = bit_reader.read_u16::<BigEndian>()?;
157            let mut nalus = Vec::with_capacity(num_nalus as usize);
158            for _ in 0..num_nalus {
159                let nal_unit_length = bit_reader.read_u16::<BigEndian>()?;
160                let mut data = vec![0; nal_unit_length as usize];
161                bit_reader.read_exact(&mut data)?;
162                nalus.push(data.into());
163            }
164
165            arrays.push(NaluArray {
166                array_completeness,
167                nal_unit_type,
168                nalus,
169            });
170        }
171
172        Ok(HEVCDecoderConfigurationRecord {
173            general_profile_space,
174            general_tier_flag,
175            general_profile_idc,
176            general_profile_compatibility_flags,
177            general_constraint_indicator_flags,
178            general_level_idc,
179            min_spatial_segmentation_idc,
180            parallelism_type: ParallelismType(parallelism_type),
181            chroma_format_idc,
182            bit_depth_luma_minus8,
183            bit_depth_chroma_minus8,
184            avg_frame_rate,
185            constant_frame_rate: ConstantFrameRate(constant_frame_rate),
186            num_temporal_layers: NumTemporalLayers(num_temporal_layers),
187            temporal_id_nested,
188            length_size_minus_one,
189            arrays,
190        })
191    }
192}
193
194impl Serialize for HEVCDecoderConfigurationRecord<'_> {
195    fn serialize<W>(&self, writer: W) -> io::Result<()>
196    where
197        W: std::io::Write,
198    {
199        let mut bit_writer = BitWriter::new(writer);
200
201        // This muxer only supports version 1
202        bit_writer.write_u8(1)?; // configuration_version
203        bit_writer.write_bits(self.general_profile_space as u64, 2)?;
204        bit_writer.write_bit(self.general_tier_flag)?;
205        bit_writer.write_bits(self.general_profile_idc as u64, 5)?;
206        bit_writer.write_u32::<BigEndian>(self.general_profile_compatibility_flags.bits())?;
207        bit_writer.write_u48::<BigEndian>(self.general_constraint_indicator_flags)?;
208        bit_writer.write_u8(self.general_level_idc)?;
209
210        bit_writer.write_bits(0b1111, 4)?; // reserved_4bits
211        bit_writer.write_bits(self.min_spatial_segmentation_idc as u64, 12)?;
212
213        bit_writer.write_bits(0b111111, 6)?; // reserved_6bits
214        bit_writer.write_bits(self.parallelism_type.0 as u64, 2)?;
215
216        bit_writer.write_bits(0b111111, 6)?; // reserved_6bits
217        bit_writer.write_bits(self.chroma_format_idc as u64, 2)?;
218
219        bit_writer.write_bits(0b11111, 5)?; // reserved_5bits
220        bit_writer.write_bits(self.bit_depth_luma_minus8 as u64, 3)?;
221
222        bit_writer.write_bits(0b11111, 5)?; // reserved_5bits
223        bit_writer.write_bits(self.bit_depth_chroma_minus8 as u64, 3)?;
224
225        bit_writer.write_u16::<BigEndian>(self.avg_frame_rate)?;
226        bit_writer.write_bits(self.constant_frame_rate.0 as u64, 2)?;
227
228        bit_writer.write_bits(self.num_temporal_layers.0 as u64, 3)?;
229        bit_writer.write_bit(self.temporal_id_nested)?;
230        bit_writer.write_bits(self.length_size_minus_one as u64, 2)?;
231
232        bit_writer.write_u8(self.arrays.len() as u8)?;
233        for array in &self.arrays {
234            bit_writer.write_bit(array.array_completeness)?;
235            bit_writer.write_bits(0b0, 1)?; // reserved
236            bit_writer.write_bits(u8::from(array.nal_unit_type) as u64, 6)?;
237
238            bit_writer.write_u16::<BigEndian>(array.nalus.len() as u16)?;
239
240            for nalu in &array.nalus {
241                bit_writer.write_u16::<BigEndian>(nalu.len() as u16)?;
242                bit_writer.write_all(nalu.as_bytes())?;
243            }
244        }
245
246        bit_writer.finish()?;
247
248        Ok(())
249    }
250}
251
252#[cfg(feature = "isobmff")]
253impl isobmff::IsoSized for HEVCDecoderConfigurationRecord<'_> {
254    fn size(&self) -> usize {
255        1 // configuration_version
256        + 1 // general_profile_space, general_tier_flag, general_profile_idc
257        + 4 // general_profile_compatibility_flags
258        + 6 // general_constraint_indicator_flags
259        + 1 // general_level_idc
260        + 2 // reserved_4bits, min_spatial_segmentation_idc
261        + 1 // reserved_6bits, parallelism_type
262        + 1 // reserved_6bits, chroma_format_idc
263        + 1 // reserved_5bits, bit_depth_luma_minus8
264        + 1 // reserved_5bits, bit_depth_chroma_minus8
265        + 2 // avg_frame_rate
266        + 1 // constant_frame_rate, num_temporal_layers, temporal_id_nested, length_size_minus_one
267        + 1 // num_of_arrays
268        + self.arrays.iter().map(|array| {
269            1 // array_completeness, reserved, nal_unit_type
270            + 2 // num_nalus
271            + array.nalus.iter().map(|nalu| {
272                2 // nal_unit_length
273                + nalu.len() // nal_unit
274            }).sum::<usize>()
275        }).sum::<usize>()
276    }
277}
278
279#[cfg(test)]
280#[cfg_attr(all(test, coverage_nightly), coverage(off))]
281mod tests {
282    use std::io;
283
284    use scuffle_bytes_util::zero_copy::{Deserialize, Slice};
285
286    use crate::{
287        ConstantFrameRate, HEVCDecoderConfigurationRecord, NALUnitType, NumTemporalLayers, ParallelismType,
288        ProfileCompatibilityFlags, SpsNALUnit,
289    };
290
291    #[test]
292    fn test_config_demux() {
293        // h265 config
294        let data = 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";
295
296        let config = HEVCDecoderConfigurationRecord::deserialize(Slice::from(&data[..])).unwrap();
297
298        assert_eq!(config.general_profile_space, 0);
299        assert!(!config.general_tier_flag);
300        assert_eq!(config.general_profile_idc, 1);
301        assert_eq!(
302            config.general_profile_compatibility_flags,
303            ProfileCompatibilityFlags::MainProfile
304        );
305        assert_eq!(config.general_constraint_indicator_flags, (1 << 47) | (1 << 44)); // 1. bit and 4. bit
306        assert_eq!(config.general_level_idc, 153);
307        assert_eq!(config.min_spatial_segmentation_idc, 0);
308        assert_eq!(config.parallelism_type, ParallelismType::MixedOrUnknown);
309        assert_eq!(config.chroma_format_idc, 1);
310        assert_eq!(config.bit_depth_luma_minus8, 0);
311        assert_eq!(config.bit_depth_chroma_minus8, 0);
312        assert_eq!(config.avg_frame_rate, 0);
313        assert_eq!(config.constant_frame_rate, ConstantFrameRate::Unknown);
314        assert_eq!(config.num_temporal_layers, NumTemporalLayers::NotScalable);
315        assert!(config.temporal_id_nested);
316        assert_eq!(config.length_size_minus_one, 3);
317        assert_eq!(config.arrays.len(), 3);
318
319        let vps = &config.arrays[0];
320        assert!(!vps.array_completeness);
321        assert_eq!(vps.nal_unit_type, NALUnitType::VpsNut);
322        assert_eq!(vps.nalus.len(), 1);
323
324        let sps = &config.arrays[1];
325        assert!(!sps.array_completeness);
326        assert_eq!(sps.nal_unit_type, NALUnitType::SpsNut);
327        assert_eq!(sps.nalus.len(), 1);
328        let sps = SpsNALUnit::parse(io::Cursor::new(sps.nalus[0].clone())).unwrap();
329        insta::assert_debug_snapshot!(sps);
330
331        let pps = &config.arrays[2];
332        assert!(!pps.array_completeness);
333        assert_eq!(pps.nal_unit_type, NALUnitType::PpsNut);
334        assert_eq!(pps.nalus.len(), 1);
335    }
336
337    #[test]
338    #[cfg(feature = "isobmff")]
339    fn test_config_mux() {
340        use isobmff::IsoSized;
341        use scuffle_bytes_util::zero_copy::Serialize;
342
343        let data = 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";
344
345        let config = HEVCDecoderConfigurationRecord::deserialize(Slice::from(&data[..])).unwrap();
346
347        assert_eq!(config.size(), data.len());
348
349        let mut buf = Vec::new();
350        config.serialize(&mut buf).unwrap();
351
352        assert_eq!(buf, data.to_vec());
353    }
354}