scuffle_h265/sps/
profile_tier_level.rs

1use std::io;
2
3use byteorder::{BigEndian, ReadBytesExt};
4use scuffle_bytes_util::{BitReader, range_check};
5
6use crate::ProfileCompatibilityFlags;
7
8/// Profile, tier and level.
9///
10/// `profile_tier_level(profilePresentFlag, maxNumSubLayersMinus1)`
11///
12/// - ISO/IEC 23008-2 - 7.3.3
13/// - ISO/IEC 23008-2 - 7.4.4
14#[derive(Debug, Clone, PartialEq)]
15pub struct ProfileTierLevel {
16    /// `general_profile_space`, `general_tier_flag`, `general_profile_idc`, `general_profile_compatibility_flag[j]`,
17    /// `general_progressive_source_flag`, `general_interlaced_source_flag`, `general_non_packed_constraint_flag`,
18    /// `general_frame_only_constraint_flag`, `general_max_12bit_constraint_flag`, `general_max_10bit_constraint_flag`,
19    /// `general_max_8bit_constraint_flag`, `general_max_422chroma_constraint_flag`,
20    /// `general_max_420chroma_constraint_flag`, `general_max_monochrome_constraint_flag`,
21    /// `general_intra_constraint_flag`, `general_one_picture_only_constraint_flag`,
22    /// `general_lower_bit_rate_constraint_flag`, `general_max_14bit_constraint_flag`, `general_inbld_flag`
23    /// and `general_level_idc`.
24    pub general_profile: Profile,
25    /// `sub_layer_profile_space[i]`, `sub_layer_tier_flag[i]`,
26    /// `sub_layer_profile_idc[i]`,
27    /// `sub_layer_profile_compatibility_flag[i][j]`,
28    /// `sub_layer_progressive_source_flag[i]`,
29    /// `sub_layer_interlaced_source_flag[i]`,
30    /// `sub_layer_non_packed_constraint_flag[i]`,
31    /// `sub_layer_frame_only_constraint_flag[i]`,
32    /// `sub_layer_max_12bit_constraint_flag[i]`,
33    /// `sub_layer_max_10bit_constraint_flag[i]`,
34    /// `sub_layer_max_8bit_constraint_flag[i]`,
35    /// `sub_layer_max_422chroma_constraint_flag[i]`,
36    /// `sub_layer_max_420chroma_constraint_flag[i]`,
37    /// `sub_layer_max_monochrome_constraint_flag[i]`,
38    /// `sub_layer_intra_constraint_flag[i]`,
39    /// `sub_layer_one_picture_only_constraint_flag[i]`,
40    /// `sub_layer_lower_bit_rate_constraint_flag[i]`,
41    /// `sub_layer_max_14bit_constraint_flag[i]`,
42    /// `sub_layer_inbld_flag[i]`, and
43    /// `sub_layer_level_idc[i]`.
44    pub sub_layer_profiles: Vec<Profile>,
45}
46
47impl ProfileTierLevel {
48    pub(crate) fn parse<R: io::Read>(bit_reader: &mut BitReader<R>, max_num_sub_layers_minus_1: u8) -> io::Result<Self> {
49        // When parsing SPSs, the profile_present_flag is always true. (See 7.3.2.2.1)
50        // Since this decoder only supports SPS decoding, it is assumed to be true here.
51
52        let mut general_profile = Profile::parse(bit_reader, true)?;
53        // inbld_flag is inferred to be 0 when not present for the genral profile
54        general_profile.inbld_flag = Some(general_profile.inbld_flag.unwrap_or(false));
55
56        let mut sub_layer_profile_present_flags = Vec::with_capacity(max_num_sub_layers_minus_1 as usize);
57        let mut sub_layer_level_present_flags = Vec::with_capacity(max_num_sub_layers_minus_1 as usize);
58        for _ in 0..max_num_sub_layers_minus_1 {
59            sub_layer_profile_present_flags.push(bit_reader.read_bit()?); // sub_layer_profile_present_flag
60            sub_layer_level_present_flags.push(bit_reader.read_bit()?); // sub_layer_level_present_flag
61        }
62
63        // reserved_zero_2bits
64        if max_num_sub_layers_minus_1 > 0 && max_num_sub_layers_minus_1 < 8 {
65            bit_reader.read_bits(2 * (8 - max_num_sub_layers_minus_1))?;
66        }
67
68        let mut sub_layer_profiles = vec![None; max_num_sub_layers_minus_1 as usize];
69        let mut sub_layer_level_idcs = vec![None; max_num_sub_layers_minus_1 as usize];
70
71        for i in 0..max_num_sub_layers_minus_1 as usize {
72            if sub_layer_profile_present_flags[i] {
73                sub_layer_profiles[i] = Some(Profile::parse(bit_reader, sub_layer_level_present_flags[i])?);
74            }
75
76            if sub_layer_level_present_flags[i] {
77                sub_layer_level_idcs[i] = Some(bit_reader.read_u8()?);
78            }
79        }
80
81        let mut last_profile = general_profile.clone();
82        let mut sub_layer_profiles: Vec<_> = sub_layer_profiles
83            .into_iter()
84            .rev()
85            .map(|profile| match profile {
86                Some(profile) => {
87                    let profile = profile.merge(&last_profile);
88                    last_profile = profile.clone();
89                    profile
90                }
91                None => last_profile.clone(),
92            })
93            .collect();
94        sub_layer_profiles.reverse(); // reverse back to original order
95
96        Ok(ProfileTierLevel {
97            general_profile,
98            sub_layer_profiles,
99        })
100    }
101}
102
103/// Profile part of the Profile, tier and level structure.
104#[derive(Debug, Clone, PartialEq)]
105pub struct Profile {
106    /// Decoders shall ignore the CVS when `general_profile_space` is not equal to 0.
107    pub profile_space: u8,
108    /// Specifies the tier context for the interpretation of `general_level_idc` as specified in ISO/IEC 23008-2 - Annex A.
109    pub tier_flag: bool,
110    /// When `general_profile_space` is equal to 0, indicates a profile to which the CVS
111    /// conforms as specified in ISO/IEC 23008-2 - Annex A.
112    pub profile_idc: u8,
113    /// `profile_compatibility_flag[j]` equal to `true`, when `general_profile_space` is equal to 0, indicates
114    /// that the CVS conforms to the profile indicated by `general_profile_idc` equal to `j`
115    /// as specified in ISO/IEC 23008-2 - Annex A.
116    pub profile_compatibility_flag: ProfileCompatibilityFlags,
117    /// - If `general_progressive_source_flag` is equal to `true` and
118    ///   [`general_interlaced_source_flag`](Profile::interlaced_source_flag) is equal to `false`, the
119    ///   source scan type of the pictures in the CVS should be interpreted as progressive only.
120    /// - Otherwise, if `general_progressive_source_flag` is equal to `false` and
121    ///   [`general_interlaced_source_flag`](Profile::interlaced_source_flag) is equal to `true`, the
122    ///   source scan type of the pictures in the CVS should be interpreted as interlaced only.
123    /// - Otherwise, if `general_progressive_source_flag` is equal to `false` and
124    ///   [`general_interlaced_source_flag`](Profile::interlaced_source_flag) is equal to `false`, the
125    ///   source scan type of the pictures in the CVS should be interpreted as unknown or
126    ///   unspecified.
127    /// - Otherwise (`general_progressive_source_flag` is equal to `true` and
128    ///   [`general_interlaced_source_flag`](Profile::interlaced_source_flag) is equal to `true`),
129    ///   the source scan type of each picture in the CVS is indicated at the picture level using the syntax
130    ///   element `source_scan_type` in a picture timing SEI message.
131    pub progressive_source_flag: bool,
132    /// See [`progressive_source_flag`](Profile::progressive_source_flag).
133    pub interlaced_source_flag: bool,
134    /// Equal to `true` specifies that there are no frame packing arrangement
135    /// SEI messages, segmented rectangular frame packing arrangement SEI messages, equirectangular
136    /// projection SEI messages, or cubemap projection SEI messages present in the CVS.
137    ///
138    /// Equal to `false` indicates that there may or may not be one or more frame
139    /// packing arrangement SEI messages, segmented rectangular frame packing arrangement SEI messages,
140    /// equirectangular projection SEI messages, or cubemap projection SEI messages present in the CVS.
141    pub non_packed_constraint_flag: bool,
142    /// Equal to `true` specifies that `field_seq_flag` is equal to 0.
143    ///
144    /// Equal to `false` indicates that `field_seq_flag` may or may not be equal to 0.
145    pub frame_only_constraint_flag: bool,
146    /// Any additional flags that may be present in the profile.
147    pub additional_flags: ProfileAdditionalFlags,
148    /// Equal to `true` specifies that the INBLD capability as specified in ISO/IEC 23008-2 - Annex F is required for
149    /// decoding of the layer to which the `profile_tier_level( )` syntax structure applies.
150    ///
151    /// Equal to `false` specifies that the INBLD capability as specified in ISO/IEC 23008-2 - Annex F is not required for
152    /// decoding of the layer to which the profile_tier_level( ) syntax structure applies.
153    pub inbld_flag: Option<bool>,
154    /// Indicates a level to which the CVS conforms as specified in ISO/IEC 23008-2 - Annex A.
155    ///
156    /// Always present for the general profile.
157    pub level_idc: Option<u8>,
158}
159
160impl Profile {
161    fn parse<R: io::Read>(bit_reader: &mut BitReader<R>, level_present: bool) -> io::Result<Self> {
162        let profile_space = bit_reader.read_bits(2)? as u8;
163        let tier_flag = bit_reader.read_bit()?;
164        let profile_idc = bit_reader.read_bits(5)? as u8;
165
166        let profile_compatibility_flag = ProfileCompatibilityFlags::from_bits_retain(bit_reader.read_u32::<BigEndian>()?);
167
168        let check_profile_idcs = |profiles: ProfileCompatibilityFlags| {
169            profiles.contains(ProfileCompatibilityFlags::from_bits_retain(1 << profile_idc))
170                || profile_compatibility_flag.intersects(profiles)
171        };
172
173        let progressive_source_flag = bit_reader.read_bit()?;
174        let interlaced_source_flag = bit_reader.read_bit()?;
175        let non_packed_constraint_flag = bit_reader.read_bit()?;
176        let frame_only_constraint_flag = bit_reader.read_bit()?;
177
178        let additional_flags = if check_profile_idcs(
179            ProfileCompatibilityFlags::FormatRangeExtensionsProfile
180                | ProfileCompatibilityFlags::HighThroughputProfile
181                | ProfileCompatibilityFlags::Profile6
182                | ProfileCompatibilityFlags::Profile7
183                | ProfileCompatibilityFlags::Profile8
184                | ProfileCompatibilityFlags::ScreenContentCodingExtensionsProfile
185                | ProfileCompatibilityFlags::Profile10
186                | ProfileCompatibilityFlags::HighThroughputScreenContentCodingExtensionsProfile,
187        ) {
188            let max_12bit_constraint_flag = bit_reader.read_bit()?;
189            let max_10bit_constraint_flag = bit_reader.read_bit()?;
190            let max_8bit_constraint_flag = bit_reader.read_bit()?;
191            let max_422chroma_constraint_flag = bit_reader.read_bit()?;
192            let max_420chroma_constraint_flag = bit_reader.read_bit()?;
193            let max_monochrome_constraint_flag = bit_reader.read_bit()?;
194            let intra_constraint_flag = bit_reader.read_bit()?;
195            let one_picture_only_constraint_flag = bit_reader.read_bit()?;
196            let lower_bit_rate_constraint_flag = bit_reader.read_bit()?;
197
198            let max_14bit_constraint_flag = if check_profile_idcs(
199                ProfileCompatibilityFlags::HighThroughputProfile
200                    | ProfileCompatibilityFlags::ScreenContentCodingExtensionsProfile
201                    | ProfileCompatibilityFlags::Profile10
202                    | ProfileCompatibilityFlags::HighThroughputScreenContentCodingExtensionsProfile,
203            ) {
204                let max_14bit_constraint_flag = bit_reader.read_bit()?;
205                bit_reader.read_bits(33)?;
206                Some(max_14bit_constraint_flag)
207            } else {
208                bit_reader.read_bits(34)?;
209                None
210            };
211
212            ProfileAdditionalFlags::Full {
213                max_12bit_constraint_flag,
214                max_10bit_constraint_flag,
215                max_8bit_constraint_flag,
216                max_422chroma_constraint_flag,
217                max_420chroma_constraint_flag,
218                max_monochrome_constraint_flag,
219                intra_constraint_flag,
220                one_picture_only_constraint_flag,
221                lower_bit_rate_constraint_flag,
222                max_14bit_constraint_flag,
223            }
224        } else if check_profile_idcs(ProfileCompatibilityFlags::Main10Profile) {
225            bit_reader.read_bits(7)?; // reserved_zero_7bits
226            let one_picture_only_constraint_flag = bit_reader.read_bit()?;
227            bit_reader.read_bits(35)?; // reserved_zero_35bits
228            ProfileAdditionalFlags::Main10Profile {
229                one_picture_only_constraint_flag,
230            }
231        } else {
232            bit_reader.read_bits(43)?; // reserved_zero_43bits
233            ProfileAdditionalFlags::None
234        };
235
236        let inbld_flag = if check_profile_idcs(
237            ProfileCompatibilityFlags::MainProfile
238                | ProfileCompatibilityFlags::Main10Profile
239                | ProfileCompatibilityFlags::MainStillPictureProfile
240                | ProfileCompatibilityFlags::FormatRangeExtensionsProfile
241                | ProfileCompatibilityFlags::HighThroughputProfile
242                | ProfileCompatibilityFlags::ScreenContentCodingExtensionsProfile
243                | ProfileCompatibilityFlags::HighThroughputScreenContentCodingExtensionsProfile,
244        ) {
245            Some(bit_reader.read_bit()?)
246        } else {
247            bit_reader.read_bit()?; // reserved_zero_bit
248            None
249        };
250
251        let mut level_idc_value = None;
252        if level_present {
253            let level_idc = bit_reader.read_bits(8)? as u8;
254            range_check!(level_idc, 0, 254)?;
255            level_idc_value = Some(level_idc);
256        }
257
258        Ok(Profile {
259            profile_space,
260            tier_flag,
261            profile_idc,
262            profile_compatibility_flag,
263            progressive_source_flag,
264            interlaced_source_flag,
265            non_packed_constraint_flag,
266            frame_only_constraint_flag,
267            additional_flags,
268            inbld_flag,
269            level_idc: level_idc_value,
270        })
271    }
272
273    fn merge(self, defaults: &Self) -> Self {
274        Self {
275            additional_flags: self.additional_flags.merge(&defaults.additional_flags),
276            inbld_flag: self.inbld_flag.or(defaults.inbld_flag),
277            level_idc: self.level_idc.or(defaults.level_idc),
278            ..self
279        }
280    }
281}
282
283/// Additional profile flags that can be present in the [profile](Profile).
284#[derive(Debug, Clone, PartialEq)]
285pub enum ProfileAdditionalFlags {
286    /// All additional flags are present.
287    Full {
288        /// Semantics specified in ISO/IEC 23008-2 - Annex A.
289        max_12bit_constraint_flag: bool,
290        /// Semantics specified in ISO/IEC 23008-2 - Annex A.
291        max_10bit_constraint_flag: bool,
292        /// Semantics specified in ISO/IEC 23008-2 - Annex A.
293        max_8bit_constraint_flag: bool,
294        /// Semantics specified in ISO/IEC 23008-2 - Annex A.
295        max_422chroma_constraint_flag: bool,
296        /// Semantics specified in ISO/IEC 23008-2 - Annex A.
297        max_420chroma_constraint_flag: bool,
298        /// Semantics specified in ISO/IEC 23008-2 - Annex A.
299        max_monochrome_constraint_flag: bool,
300        /// Semantics specified in ISO/IEC 23008-2 - Annex A.
301        intra_constraint_flag: bool,
302        /// Semantics specified in ISO/IEC 23008-2 - Annex A.
303        one_picture_only_constraint_flag: bool,
304        /// Semantics specified in ISO/IEC 23008-2 - Annex A.
305        lower_bit_rate_constraint_flag: bool,
306        /// Semantics specified in ISO/IEC 23008-2 - Annex A.
307        max_14bit_constraint_flag: Option<bool>,
308    },
309    /// Only the `one_picture_only_constraint_flag` is present because `profile_idc` is 2 or `general_profile_compatibility_flag[2]` is `true`.
310    Main10Profile {
311        /// Semantics specified in ISO/IEC 23008-2 - Annex A.
312        one_picture_only_constraint_flag: bool,
313    },
314    /// No additional flags are present.
315    None,
316}
317
318impl ProfileAdditionalFlags {
319    fn merge(self, defaults: &Self) -> Self {
320        match (&self, defaults) {
321            (Self::Full { .. }, _) => self,
322            (
323                Self::Main10Profile {
324                    one_picture_only_constraint_flag,
325                },
326                Self::Full {
327                    max_12bit_constraint_flag,
328                    max_10bit_constraint_flag,
329                    max_8bit_constraint_flag,
330                    max_422chroma_constraint_flag,
331                    max_420chroma_constraint_flag,
332                    max_monochrome_constraint_flag,
333                    intra_constraint_flag,
334                    lower_bit_rate_constraint_flag,
335                    max_14bit_constraint_flag,
336                    ..
337                },
338            ) => Self::Full {
339                max_12bit_constraint_flag: *max_12bit_constraint_flag,
340                max_10bit_constraint_flag: *max_10bit_constraint_flag,
341                max_8bit_constraint_flag: *max_8bit_constraint_flag,
342                max_422chroma_constraint_flag: *max_422chroma_constraint_flag,
343                max_420chroma_constraint_flag: *max_420chroma_constraint_flag,
344                max_monochrome_constraint_flag: *max_monochrome_constraint_flag,
345                intra_constraint_flag: *intra_constraint_flag,
346                one_picture_only_constraint_flag: *one_picture_only_constraint_flag,
347                lower_bit_rate_constraint_flag: *lower_bit_rate_constraint_flag,
348                max_14bit_constraint_flag: *max_14bit_constraint_flag,
349            },
350            (Self::Main10Profile { .. }, _) => self,
351            (Self::None, _) => defaults.clone(),
352        }
353    }
354}