scuffle_h265/sps/
profile_tier_level.rs

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