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}