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}