Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * H.266/VVC helper functions for muxers | ||
3 | * | ||
4 | * Copyright (C) 2022, Thomas Siedel | ||
5 | * | ||
6 | * This file is part of FFmpeg. | ||
7 | * | ||
8 | * FFmpeg is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU Lesser General Public | ||
10 | * License as published by the Free Software Foundation; either | ||
11 | * version 2.1 of the License, or (at your option) any later version. | ||
12 | * | ||
13 | * FFmpeg is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * Lesser General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU Lesser General Public | ||
19 | * License along with FFmpeg; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
21 | */ | ||
22 | |||
23 | #include "libavcodec/get_bits.h" | ||
24 | #include "libavcodec/put_bits.h" | ||
25 | #include "libavcodec/golomb.h" | ||
26 | #include "libavcodec/vvc.h" | ||
27 | #include "libavutil/avassert.h" | ||
28 | #include "libavutil/intreadwrite.h" | ||
29 | #include "libavutil/mem.h" | ||
30 | #include "avc.h" | ||
31 | #include "avio.h" | ||
32 | #include "avio_internal.h" | ||
33 | #include "nal.h" | ||
34 | #include "vvc.h" | ||
35 | |||
36 | enum { | ||
37 | OPI_INDEX, | ||
38 | VPS_INDEX, | ||
39 | SPS_INDEX, | ||
40 | PPS_INDEX, | ||
41 | SEI_PREFIX_INDEX, | ||
42 | SEI_SUFFIX_INDEX, | ||
43 | NB_ARRAYS | ||
44 | }; | ||
45 | |||
46 | typedef struct VVCCNALUnitArray { | ||
47 | uint8_t array_completeness; | ||
48 | uint8_t NAL_unit_type; | ||
49 | uint16_t num_nalus; | ||
50 | uint16_t *nal_unit_length; | ||
51 | uint8_t **nal_unit; | ||
52 | } VVCCNALUnitArray; | ||
53 | |||
54 | typedef struct VVCPTLRecord { | ||
55 | uint8_t num_bytes_constraint_info; | ||
56 | uint8_t general_profile_idc; | ||
57 | uint8_t general_tier_flag; | ||
58 | uint8_t general_level_idc; | ||
59 | uint8_t ptl_frame_only_constraint_flag; | ||
60 | uint8_t ptl_multilayer_enabled_flag; | ||
61 | uint8_t general_constraint_info[9]; | ||
62 | uint8_t ptl_sublayer_level_present_flag[VVC_MAX_SUBLAYERS - 1]; | ||
63 | uint8_t sublayer_level_idc[VVC_MAX_SUBLAYERS - 1]; | ||
64 | uint8_t ptl_num_sub_profiles; | ||
65 | uint32_t general_sub_profile_idc[VVC_MAX_SUB_PROFILES]; | ||
66 | } VVCPTLRecord; | ||
67 | |||
68 | typedef struct VVCDecoderConfigurationRecord { | ||
69 | uint8_t lengthSizeMinusOne; | ||
70 | uint8_t ptl_present_flag; | ||
71 | uint16_t ols_idx; | ||
72 | uint8_t num_sublayers; | ||
73 | uint8_t constant_frame_rate; | ||
74 | uint8_t chroma_format_idc; | ||
75 | uint8_t bit_depth_minus8; | ||
76 | VVCPTLRecord ptl; | ||
77 | uint16_t max_picture_width; | ||
78 | uint16_t max_picture_height; | ||
79 | uint16_t avg_frame_rate; | ||
80 | uint8_t num_of_arrays; | ||
81 | VVCCNALUnitArray arrays[NB_ARRAYS]; | ||
82 | } VVCDecoderConfigurationRecord; | ||
83 | |||
84 | 3 | static void vvcc_update_ptl(VVCDecoderConfigurationRecord *vvcc, | |
85 | VVCPTLRecord *ptl) | ||
86 | { | ||
87 | /* | ||
88 | * The level indication general_level_idc must indicate a level of | ||
89 | * capability equal to or greater than the highest level indicated for the | ||
90 | * highest tier in all the parameter sets. | ||
91 | */ | ||
92 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (vvcc->ptl.general_tier_flag < ptl->general_tier_flag) |
93 | ✗ | vvcc->ptl.general_level_idc = ptl->general_level_idc; | |
94 | else | ||
95 | 3 | vvcc->ptl.general_level_idc = | |
96 | 3 | FFMAX(vvcc->ptl.general_level_idc, ptl->general_level_idc); | |
97 | |||
98 | /* | ||
99 | * The tier indication general_tier_flag must indicate a tier equal to or | ||
100 | * greater than the highest tier indicated in all the parameter sets. | ||
101 | */ | ||
102 | 3 | vvcc->ptl.general_tier_flag = | |
103 | 3 | FFMAX(vvcc->ptl.general_tier_flag, ptl->general_tier_flag); | |
104 | |||
105 | /* | ||
106 | * The profile indication general_profile_idc must indicate a profile to | ||
107 | * which the stream associated with this configuration record conforms. | ||
108 | * | ||
109 | * If the sequence parameter sets are marked with different profiles, then | ||
110 | * the stream may need examination to determine which profile, if any, the | ||
111 | * entire stream conforms to. If the entire stream is not examined, or the | ||
112 | * examination reveals that there is no profile to which the entire stream | ||
113 | * conforms, then the entire stream must be split into two or more | ||
114 | * sub-streams with separate configuration records in which these rules can | ||
115 | * be met. | ||
116 | * | ||
117 | * Note: set the profile to the highest value for the sake of simplicity. | ||
118 | */ | ||
119 | 3 | vvcc->ptl.general_profile_idc = | |
120 | 3 | FFMAX(vvcc->ptl.general_profile_idc, ptl->general_profile_idc); | |
121 | |||
122 | /* | ||
123 | * Each bit in flags may only be set if all | ||
124 | * the parameter sets set that bit. | ||
125 | */ | ||
126 | 3 | vvcc->ptl.ptl_frame_only_constraint_flag &= | |
127 | 3 | ptl->ptl_frame_only_constraint_flag; | |
128 | 3 | vvcc->ptl.ptl_multilayer_enabled_flag &= ptl->ptl_multilayer_enabled_flag; | |
129 | |||
130 | /* | ||
131 | * Constraints Info | ||
132 | */ | ||
133 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (ptl->num_bytes_constraint_info) { |
134 | ✗ | vvcc->ptl.num_bytes_constraint_info = ptl->num_bytes_constraint_info; | |
135 | ✗ | memcpy(&vvcc->ptl.general_constraint_info[0], | |
136 | ✗ | &ptl->general_constraint_info[0], ptl->num_bytes_constraint_info); | |
137 | } else { | ||
138 | 3 | vvcc->ptl.num_bytes_constraint_info = 1; | |
139 | 3 | memset(&vvcc->ptl.general_constraint_info[0], 0, sizeof(vvcc->ptl.general_constraint_info)); | |
140 | } | ||
141 | |||
142 | /* | ||
143 | * Each bit in flags may only be set if one of | ||
144 | * the parameter sets set that bit. | ||
145 | */ | ||
146 | 3 | memset(vvcc->ptl.ptl_sublayer_level_present_flag, 0, | |
147 | 3 | sizeof(uint8_t) * vvcc->num_sublayers - 1); | |
148 | 3 | memset(vvcc->ptl.sublayer_level_idc, 0, | |
149 | 3 | sizeof(uint8_t) * vvcc->num_sublayers - 1); | |
150 | |||
151 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | for (int i = vvcc->num_sublayers - 2; i >= 0; i--) { |
152 | ✗ | vvcc->ptl.ptl_sublayer_level_present_flag[i] |= | |
153 | ✗ | ptl->ptl_sublayer_level_present_flag[i]; | |
154 | ✗ | if (vvcc->ptl.ptl_sublayer_level_present_flag[i]) { | |
155 | ✗ | vvcc->ptl.sublayer_level_idc[i] = | |
156 | ✗ | FFMAX(vvcc->ptl.sublayer_level_idc[i], | |
157 | ptl->sublayer_level_idc[i]); | ||
158 | } else { | ||
159 | ✗ | if (i == vvcc->num_sublayers - 1) { | |
160 | ✗ | vvcc->ptl.sublayer_level_idc[i] = vvcc->ptl.general_level_idc; | |
161 | } else { | ||
162 | ✗ | vvcc->ptl.sublayer_level_idc[i] = | |
163 | ✗ | vvcc->ptl.sublayer_level_idc[i + 1]; | |
164 | } | ||
165 | } | ||
166 | } | ||
167 | |||
168 | 3 | vvcc->ptl.ptl_num_sub_profiles = | |
169 | 3 | FFMAX(vvcc->ptl.ptl_num_sub_profiles, ptl->ptl_num_sub_profiles); | |
170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (vvcc->ptl.ptl_num_sub_profiles) { |
171 | ✗ | for (int i = 0; i < vvcc->ptl.ptl_num_sub_profiles; i++) { | |
172 | ✗ | vvcc->ptl.general_sub_profile_idc[i] = | |
173 | ✗ | ptl->general_sub_profile_idc[i]; | |
174 | } | ||
175 | } | ||
176 | 3 | } | |
177 | |||
178 | 3 | static void vvcc_parse_ptl(GetBitContext *gb, | |
179 | VVCDecoderConfigurationRecord *vvcc, | ||
180 | unsigned int profileTierPresentFlag, | ||
181 | unsigned int max_sub_layers_minus1) | ||
182 | { | ||
183 | 3 | VVCPTLRecord general_ptl = { 0 }; | |
184 | |||
185 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | if (profileTierPresentFlag) { |
186 | 2 | general_ptl.general_profile_idc = get_bits(gb, 7); | |
187 | 2 | general_ptl.general_tier_flag = get_bits1(gb); | |
188 | } | ||
189 | 3 | general_ptl.general_level_idc = get_bits(gb, 8); | |
190 | |||
191 | 3 | general_ptl.ptl_frame_only_constraint_flag = get_bits1(gb); | |
192 | 3 | general_ptl.ptl_multilayer_enabled_flag = get_bits1(gb); | |
193 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | if (profileTierPresentFlag) { // parse constraint info |
194 | 2 | general_ptl.num_bytes_constraint_info = get_bits1(gb); // gci_present_flag | |
195 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (general_ptl.num_bytes_constraint_info) { |
196 | int gci_num_reserved_bits, j; | ||
197 | ✗ | for (j = 0; j < 8; j++) | |
198 | ✗ | general_ptl.general_constraint_info[j] = get_bits(gb, 8); | |
199 | ✗ | general_ptl.general_constraint_info[j++] = get_bits(gb, 7); | |
200 | |||
201 | ✗ | gci_num_reserved_bits = get_bits(gb, 8); | |
202 | ✗ | general_ptl.num_bytes_constraint_info = j; | |
203 | ✗ | skip_bits(gb, gci_num_reserved_bits); | |
204 | } | ||
205 | 2 | align_get_bits(gb); | |
206 | } | ||
207 | |||
208 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | for (int i = max_sub_layers_minus1 - 1; i >= 0; i--) |
209 | ✗ | general_ptl.ptl_sublayer_level_present_flag[i] = get_bits1(gb); | |
210 | |||
211 | 3 | align_get_bits(gb); | |
212 | |||
213 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | for (int i = max_sub_layers_minus1 - 1; i >= 0; i--) { |
214 | ✗ | if (general_ptl.ptl_sublayer_level_present_flag[i]) | |
215 | ✗ | general_ptl.sublayer_level_idc[i] = get_bits(gb, 8); | |
216 | } | ||
217 | |||
218 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | if (profileTierPresentFlag) { |
219 | 2 | general_ptl.ptl_num_sub_profiles = get_bits(gb, 8); | |
220 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (general_ptl.ptl_num_sub_profiles) { |
221 | ✗ | for (int i = 0; i < general_ptl.ptl_num_sub_profiles; i++) | |
222 | ✗ | general_ptl.general_sub_profile_idc[i] = get_bits_long(gb, 32); | |
223 | } | ||
224 | } | ||
225 | |||
226 | 3 | vvcc_update_ptl(vvcc, &general_ptl); | |
227 | 3 | } | |
228 | |||
229 | 1 | static int vvcc_parse_vps(GetBitContext *gb, | |
230 | VVCDecoderConfigurationRecord *vvcc) | ||
231 | { | ||
232 | unsigned int vps_max_layers_minus1; | ||
233 | unsigned int vps_max_sublayers_minus1; | ||
234 | unsigned int vps_default_ptl_dpb_hrd_max_tid_flag; | ||
235 | unsigned int vps_all_independent_layers_flag; | ||
236 | |||
237 | unsigned int vps_pt_present_flag[VVC_MAX_PTLS]; | ||
238 | unsigned int vps_ptl_max_tid[VVC_MAX_PTLS]; | ||
239 | 1 | unsigned int vps_num_ptls_minus1 = 0; | |
240 | |||
241 | /* | ||
242 | * vps_video_parameter_set_id u(4) | ||
243 | */ | ||
244 | 1 | skip_bits(gb, 4); | |
245 | |||
246 | 1 | vps_max_layers_minus1 = get_bits(gb, 6); | |
247 | 1 | vps_max_sublayers_minus1 = get_bits(gb, 3); | |
248 | |||
249 | /* | ||
250 | * numTemporalLayers greater than 1 indicates that the stream to which this | ||
251 | * configuration record applies is temporally scalable and the contained | ||
252 | * number of temporal layers (also referred to as temporal sub-layer or | ||
253 | * sub-layer in ISO/IEC 23008-2) is equal to numTemporalLayers. Value 1 | ||
254 | * indicates that the stream is not temporally scalable. Value 0 indicates | ||
255 | * that it is unknown whether the stream is temporally scalable. | ||
256 | */ | ||
257 | 1 | vvcc->num_sublayers = FFMAX(vvcc->num_sublayers, | |
258 | vps_max_sublayers_minus1 + 1); | ||
259 | |||
260 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (vps_max_layers_minus1 > 0 && vps_max_sublayers_minus1 > 0) |
261 | ✗ | vps_default_ptl_dpb_hrd_max_tid_flag = get_bits1(gb); | |
262 | else | ||
263 | 1 | vps_default_ptl_dpb_hrd_max_tid_flag = 0; | |
264 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (vps_max_layers_minus1 > 0) |
265 | 1 | vps_all_independent_layers_flag = get_bits1(gb); | |
266 | else | ||
267 | ✗ | vps_all_independent_layers_flag = 1; | |
268 | |||
269 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (int i = 0; i <= vps_max_layers_minus1; i++) { |
270 | 2 | skip_bits(gb, 6); //vps_layer_id[i] | |
271 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
2 | if (i > 0 && !vps_all_independent_layers_flag) { |
272 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if (!get_bits1(gb)) { // vps_independent_layer_flag[i] |
273 | 1 | unsigned int vps_max_tid_ref_present_flag = get_bits1(gb); | |
274 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (int j = 0; j < i; j++) { |
275 | 1 | unsigned int vps_direct_ref_layer_flag = get_bits1(gb); | |
276 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | if (vps_max_tid_ref_present_flag && vps_direct_ref_layer_flag) |
277 | ✗ | skip_bits(gb, 3); // vps_max_tid_il_ref_pics_plus1 | |
278 | } | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | |||
283 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (vps_max_layers_minus1 > 0) { |
284 | unsigned int vps_each_layer_is_an_ols_flag; | ||
285 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (vps_all_independent_layers_flag) |
286 | ✗ | vps_each_layer_is_an_ols_flag = get_bits1(gb); | |
287 | else | ||
288 | 1 | vps_each_layer_is_an_ols_flag = 0; | |
289 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (!vps_each_layer_is_an_ols_flag) { |
290 | unsigned int vps_ols_mode_idc; | ||
291 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (!vps_all_independent_layers_flag) |
292 | 1 | vps_ols_mode_idc = get_bits(gb, 2); | |
293 | else | ||
294 | ✗ | vps_ols_mode_idc = 2; | |
295 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (vps_ols_mode_idc == 2) { |
296 | 1 | unsigned int vps_num_output_layer_sets_minus2 = get_bits(gb, 8); | |
297 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (int i = 1; i <= vps_num_output_layer_sets_minus2 + 1; i++) { |
298 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (int j = 0; j <= vps_max_layers_minus1; j++) { |
299 | 2 | skip_bits1(gb); // vps_ols_output_layer_flag[i][j] | |
300 | } | ||
301 | } | ||
302 | } | ||
303 | } | ||
304 | 1 | vps_num_ptls_minus1 = get_bits(gb, 8); | |
305 | } | ||
306 | |||
307 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (int i = 0; i <= vps_num_ptls_minus1; i++) { |
308 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (i > 0) |
309 | 1 | vps_pt_present_flag[i] = get_bits1(gb); | |
310 | else | ||
311 | 1 | vps_pt_present_flag[i] = 1; | |
312 | |||
313 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!vps_default_ptl_dpb_hrd_max_tid_flag) |
314 | 2 | vps_ptl_max_tid[i] = get_bits(gb, 3); | |
315 | else | ||
316 | ✗ | vps_ptl_max_tid[i] = vps_max_sublayers_minus1; | |
317 | } | ||
318 | |||
319 | 1 | align_get_bits(gb); | |
320 | |||
321 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (int i = 0; i <= vps_num_ptls_minus1; i++) |
322 | 2 | vvcc_parse_ptl(gb, vvcc, vps_pt_present_flag[i], vps_ptl_max_tid[i]); | |
323 | 1 | vvcc->ptl_present_flag = 1; | |
324 | |||
325 | /* nothing useful for vvcc past this point */ | ||
326 | 1 | return 0; | |
327 | } | ||
328 | |||
329 | 1 | static int vvcc_parse_sps(GetBitContext *gb, | |
330 | VVCDecoderConfigurationRecord *vvcc) | ||
331 | { | ||
332 | unsigned int sps_max_sublayers_minus1, sps_log2_ctu_size_minus5; | ||
333 | unsigned int sps_subpic_same_size_flag, sps_pic_height_max_in_luma_samples, | ||
334 | sps_pic_width_max_in_luma_samples; | ||
335 | unsigned int sps_independent_subpics_flag; | ||
336 | |||
337 | 1 | skip_bits(gb, 8); // sps_seq_parameter_set_id && sps_video_parameter_set_id | |
338 | 1 | sps_max_sublayers_minus1 = get_bits(gb, 3); | |
339 | |||
340 | /* | ||
341 | * numTemporalLayers greater than 1 indicates that the stream to which this | ||
342 | * configuration record applies is temporally scalable and the contained | ||
343 | * number of temporal layers (also referred to as temporal sub-layer or | ||
344 | * sub-layer in ISO/IEC 23008-2) is equal to numTemporalLayers. Value 1 | ||
345 | * indicates that the stream is not temporally scalable. Value 0 indicates | ||
346 | * that it is unknown whether the stream is temporally scalable. | ||
347 | */ | ||
348 | 1 | vvcc->num_sublayers = FFMAX(vvcc->num_sublayers, | |
349 | sps_max_sublayers_minus1 + 1); | ||
350 | |||
351 | 1 | vvcc->chroma_format_idc = get_bits(gb, 2); | |
352 | 1 | sps_log2_ctu_size_minus5 = get_bits(gb, 2); | |
353 | |||
354 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if (get_bits1(gb)) { // sps_ptl_dpb_hrd_params_present_flag |
355 | 1 | vvcc->ptl_present_flag = 1; | |
356 | 1 | vvcc_parse_ptl(gb, vvcc, 1, sps_max_sublayers_minus1); | |
357 | } | ||
358 | |||
359 | 1 | skip_bits1(gb); // sps_gdr_enabled_flag | |
360 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if (get_bits(gb, 1)) // sps_ref_pic_resampling_enabled_flag |
361 | 1 | skip_bits1(gb); // sps_res_change_in_clvs_allowed_flag | |
362 | |||
363 | 1 | sps_pic_width_max_in_luma_samples = get_ue_golomb_long(gb); | |
364 | 1 | vvcc->max_picture_width = | |
365 | 1 | FFMAX(vvcc->max_picture_width, sps_pic_width_max_in_luma_samples); | |
366 | 1 | sps_pic_height_max_in_luma_samples = get_ue_golomb_long(gb); | |
367 | 1 | vvcc->max_picture_height = | |
368 | 1 | FFMAX(vvcc->max_picture_height, sps_pic_height_max_in_luma_samples); | |
369 | |||
370 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (get_bits1(gb)) { |
371 | ✗ | get_ue_golomb_long(gb); // sps_conf_win_left_offset | |
372 | ✗ | get_ue_golomb_long(gb); // sps_conf_win_right_offset | |
373 | ✗ | get_ue_golomb_long(gb); // sps_conf_win_top_offset | |
374 | ✗ | get_ue_golomb_long(gb); // sps_conf_win_bottom_offset | |
375 | } | ||
376 | |||
377 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (get_bits1(gb)) { // sps_subpic_info_present_flag |
378 | ✗ | const unsigned int sps_num_subpics_minus1 = get_ue_golomb_long(gb); | |
379 | ✗ | const int ctb_log2_size_y = sps_log2_ctu_size_minus5 + 5; | |
380 | ✗ | const int ctb_size_y = 1 << ctb_log2_size_y; | |
381 | ✗ | const int tmp_width_val = AV_CEIL_RSHIFT(sps_pic_width_max_in_luma_samples, ctb_log2_size_y); | |
382 | ✗ | const int tmp_height_val = AV_CEIL_RSHIFT(sps_pic_height_max_in_luma_samples, ctb_log2_size_y); | |
383 | ✗ | const int wlen = av_ceil_log2(tmp_width_val); | |
384 | ✗ | const int hlen = av_ceil_log2(tmp_height_val); | |
385 | unsigned int sps_subpic_id_len; | ||
386 | ✗ | if (sps_num_subpics_minus1 > 0) { // sps_num_subpics_minus1 | |
387 | ✗ | sps_independent_subpics_flag = get_bits1(gb); | |
388 | ✗ | sps_subpic_same_size_flag = get_bits1(gb); | |
389 | } | ||
390 | ✗ | for (int i = 0; sps_num_subpics_minus1 > 0 && i <= sps_num_subpics_minus1; i++) { | |
391 | ✗ | if (!sps_subpic_same_size_flag || i == 0) { | |
392 | ✗ | if (i > 0 && sps_pic_width_max_in_luma_samples > ctb_size_y) | |
393 | ✗ | skip_bits(gb, wlen); | |
394 | ✗ | if (i > 0 && sps_pic_height_max_in_luma_samples > ctb_size_y) | |
395 | ✗ | skip_bits(gb, hlen); | |
396 | ✗ | if (i < sps_num_subpics_minus1 && sps_pic_width_max_in_luma_samples > ctb_size_y) | |
397 | ✗ | skip_bits(gb, wlen); | |
398 | ✗ | if (i < sps_num_subpics_minus1 && sps_pic_height_max_in_luma_samples > ctb_size_y) | |
399 | ✗ | skip_bits(gb, hlen); | |
400 | } | ||
401 | ✗ | if (!sps_independent_subpics_flag) { | |
402 | ✗ | skip_bits(gb, 2); // sps_subpic_treated_as_pic_flag && sps_loop_filter_across_subpic_enabled_flag | |
403 | } | ||
404 | } | ||
405 | ✗ | sps_subpic_id_len = get_ue_golomb_long(gb) + 1; | |
406 | ✗ | if (get_bits1(gb)) { // sps_subpic_id_mapping_explicitly_signalled_flag | |
407 | ✗ | if (get_bits1(gb)) // sps_subpic_id_mapping_present_flag | |
408 | ✗ | for (int i = 0; i <= sps_num_subpics_minus1; i++) { | |
409 | ✗ | skip_bits_long(gb, sps_subpic_id_len); // sps_subpic_id[i] | |
410 | } | ||
411 | } | ||
412 | } | ||
413 | 1 | vvcc->bit_depth_minus8 = get_ue_golomb_long(gb); | |
414 | |||
415 | /* nothing useful for vvcc past this point */ | ||
416 | 1 | return 0; | |
417 | } | ||
418 | |||
419 | 1 | static int vvcc_parse_pps(GetBitContext *gb, | |
420 | VVCDecoderConfigurationRecord *vvcc) | ||
421 | { | ||
422 | |||
423 | // Nothing of importance to parse in PPS | ||
424 | /* nothing useful for vvcc past this point */ | ||
425 | 1 | return 0; | |
426 | } | ||
427 | |||
428 | 3 | static void nal_unit_parse_header(GetBitContext *gb, uint8_t *nal_type) | |
429 | { | ||
430 | /* | ||
431 | * forbidden_zero_bit u(1) | ||
432 | * nuh_reserved_zero_bit u(1) | ||
433 | * nuh_layer_id u(6) | ||
434 | */ | ||
435 | 3 | skip_bits(gb, 8); | |
436 | 3 | *nal_type = get_bits(gb, 5); | |
437 | |||
438 | /* | ||
439 | * nuh_temporal_id_plus1 u(3) | ||
440 | */ | ||
441 | 3 | skip_bits(gb, 3); | |
442 | 3 | } | |
443 | |||
444 | 3 | static int vvcc_array_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size, | |
445 | uint8_t nal_type, int ps_array_completeness, | ||
446 | VVCCNALUnitArray *array) | ||
447 | { | ||
448 | int ret; | ||
449 | uint16_t num_nalus; | ||
450 | |||
451 | 3 | num_nalus = array->num_nalus; | |
452 | |||
453 | 3 | ret = av_reallocp_array(&array->nal_unit, num_nalus + 1, sizeof(uint8_t *)); | |
454 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (ret < 0) |
455 | ✗ | return ret; | |
456 | |||
457 | ret = | ||
458 | 3 | av_reallocp_array(&array->nal_unit_length, num_nalus + 1, | |
459 | sizeof(uint16_t)); | ||
460 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (ret < 0) |
461 | ✗ | return ret; | |
462 | |||
463 | 3 | array->nal_unit[num_nalus] = nal_buf; | |
464 | 3 | array->nal_unit_length[num_nalus] = nal_size; | |
465 | 3 | array->NAL_unit_type = nal_type; | |
466 | 3 | array->num_nalus++; | |
467 | |||
468 | /* | ||
469 | * When the sample entry name is 'vvc1', the following applies: | ||
470 | * • The value of array_completeness shall be equal to 1 for arrays of SPS, | ||
471 | * and PPS NAL units. | ||
472 | * • If a VVC bitstream includes DCI NAL unit(s), the value of | ||
473 | * array_completeness shall be equal to 1 for the array of DCI units. | ||
474 | * Otherwise, NAL_unit_type shall not indicate DCI NAL units. | ||
475 | * • If a VVC bitstream includes VPS NAL unit(s), the value of | ||
476 | * array_completeness shall be equal to 1 for the array of VPS NAL units. | ||
477 | * Otherwise, NAL_unit_type shall not indicate VPS NAL units. | ||
478 | * When the value of array_completeness is equal to 1 for an array of a | ||
479 | * particular NAL_unit_type value, NAL units of that NAL_unit_type value | ||
480 | * cannot be updated without causing a different sample entry to be used. | ||
481 | * When the sample entry name is 'vvi1', the value of array_completeness | ||
482 | * of at least one of the following arrays shall be equal to 0: | ||
483 | • The array of DCI NAL units, if present. | ||
484 | • The array of VPS NAL units, if present. | ||
485 | • The array of SPS NAL units | ||
486 | • The array of PPS NAL units. | ||
487 | */ | ||
488 |
5/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
3 | if (nal_type == VVC_VPS_NUT || nal_type == VVC_SPS_NUT || |
489 | ✗ | nal_type == VVC_PPS_NUT || nal_type == VVC_DCI_NUT ) | |
490 | 3 | array->array_completeness = ps_array_completeness; | |
491 | |||
492 | 3 | return 0; | |
493 | } | ||
494 | |||
495 | 3 | static int vvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size, | |
496 | int ps_array_completeness, | ||
497 | VVCDecoderConfigurationRecord *vvcc, | ||
498 | unsigned array_idx) | ||
499 | { | ||
500 | 3 | int ret = 0; | |
501 | GetBitContext gbc; | ||
502 | uint8_t nal_type; | ||
503 | uint8_t *rbsp_buf; | ||
504 | uint32_t rbsp_size; | ||
505 | |||
506 | 3 | rbsp_buf = ff_nal_unit_extract_rbsp(nal_buf, nal_size, &rbsp_size, 2); | |
507 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (!rbsp_buf) { |
508 | ✗ | ret = AVERROR(ENOMEM); | |
509 | ✗ | goto end; | |
510 | } | ||
511 | |||
512 | 3 | ret = init_get_bits8(&gbc, rbsp_buf, rbsp_size); | |
513 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (ret < 0) |
514 | ✗ | goto end; | |
515 | |||
516 | 3 | nal_unit_parse_header(&gbc, &nal_type); | |
517 | |||
518 | /* | ||
519 | * Note: only 'declarative' SEI messages are allowed in | ||
520 | * vvcc. Perhaps the SEI playload type should be checked | ||
521 | * and non-declarative SEI messages discarded? | ||
522 | */ | ||
523 | 3 | ret = vvcc_array_add_nal_unit(nal_buf, nal_size, nal_type, | |
524 | ps_array_completeness, | ||
525 | &vvcc->arrays[array_idx]); | ||
526 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (ret < 0) |
527 | ✗ | goto end; | |
528 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (vvcc->arrays[array_idx].num_nalus == 1) |
529 | 3 | vvcc->num_of_arrays++; | |
530 | |||
531 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if (nal_type == VVC_VPS_NUT) |
532 | 1 | ret = vvcc_parse_vps(&gbc, vvcc); | |
533 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | else if (nal_type == VVC_SPS_NUT) |
534 | 1 | ret = vvcc_parse_sps(&gbc, vvcc); | |
535 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | else if (nal_type == VVC_PPS_NUT) |
536 | 1 | ret = vvcc_parse_pps(&gbc, vvcc); | |
537 | ✗ | else if (nal_type == VVC_OPI_NUT) { | |
538 | // not yet supported | ||
539 | } | ||
540 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (ret < 0) |
541 | ✗ | goto end; | |
542 | |||
543 | 3 | end: | |
544 | 3 | av_free(rbsp_buf); | |
545 | 3 | return ret; | |
546 | } | ||
547 | |||
548 | 1 | static void vvcc_init(VVCDecoderConfigurationRecord *vvcc) | |
549 | { | ||
550 | 1 | memset(vvcc, 0, sizeof(VVCDecoderConfigurationRecord)); | |
551 | 1 | vvcc->lengthSizeMinusOne = 3; // 4 bytes | |
552 | 1 | vvcc->ptl.ptl_frame_only_constraint_flag = | |
553 | 1 | vvcc->ptl.ptl_multilayer_enabled_flag = 1; | |
554 | 1 | } | |
555 | |||
556 | 1 | static void vvcc_close(VVCDecoderConfigurationRecord *vvcc) | |
557 | { | ||
558 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
|
7 | for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc->arrays); i++) { |
559 | 6 | VVCCNALUnitArray *const array = &vvcc->arrays[i]; | |
560 | |||
561 | 6 | array->num_nalus = 0; | |
562 | 6 | av_freep(&array->nal_unit); | |
563 | 6 | av_freep(&array->nal_unit_length); | |
564 | } | ||
565 | |||
566 | 1 | vvcc->num_of_arrays = 0; | |
567 | 1 | } | |
568 | |||
569 | 1 | static int vvcc_write(AVIOContext *pb, VVCDecoderConfigurationRecord *vvcc) | |
570 | { | ||
571 | 1 | uint16_t vps_count = 0, sps_count = 0, pps_count = 0; | |
572 | /* | ||
573 | * It's unclear how to properly compute these fields, so | ||
574 | * let's always set them to values meaning 'unspecified'. | ||
575 | */ | ||
576 | 1 | vvcc->avg_frame_rate = 0; | |
577 | 1 | vvcc->constant_frame_rate = 1; | |
578 | |||
579 | 1 | av_log(NULL, AV_LOG_TRACE, | |
580 | "lengthSizeMinusOne: %" PRIu8 "\n", | ||
581 | 1 | vvcc->lengthSizeMinusOne); | |
582 | 1 | av_log(NULL, AV_LOG_TRACE, | |
583 | "ptl_present_flag: %" PRIu8 "\n", | ||
584 | 1 | vvcc->ptl_present_flag); | |
585 | 1 | av_log(NULL, AV_LOG_TRACE, | |
586 | 1 | "ols_idx: %" PRIu16 "\n", vvcc->ols_idx); | |
587 | 1 | av_log(NULL, AV_LOG_TRACE, | |
588 | "num_sublayers: %" PRIu8 "\n", | ||
589 | 1 | vvcc->num_sublayers); | |
590 | 1 | av_log(NULL, AV_LOG_TRACE, | |
591 | "constant_frame_rate: %" PRIu8 "\n", | ||
592 | 1 | vvcc->constant_frame_rate); | |
593 | 1 | av_log(NULL, AV_LOG_TRACE, | |
594 | "chroma_format_idc: %" PRIu8 "\n", | ||
595 | 1 | vvcc->chroma_format_idc); | |
596 | |||
597 | 1 | av_log(NULL, AV_LOG_TRACE, | |
598 | "bit_depth_minus8: %" PRIu8 "\n", | ||
599 | 1 | vvcc->bit_depth_minus8); | |
600 | 1 | av_log(NULL, AV_LOG_TRACE, | |
601 | "num_bytes_constraint_info: %" PRIu8 "\n", | ||
602 | 1 | vvcc->ptl.num_bytes_constraint_info); | |
603 | 1 | av_log(NULL, AV_LOG_TRACE, | |
604 | "general_profile_idc: %" PRIu8 "\n", | ||
605 | 1 | vvcc->ptl.general_profile_idc); | |
606 | 1 | av_log(NULL, AV_LOG_TRACE, | |
607 | "general_tier_flag: %" PRIu8 "\n", | ||
608 | 1 | vvcc->ptl.general_tier_flag); | |
609 | 1 | av_log(NULL, AV_LOG_TRACE, | |
610 | "general_level_idc: %" PRIu8 "\n", | ||
611 | 1 | vvcc->ptl.general_level_idc); | |
612 | 1 | av_log(NULL, AV_LOG_TRACE, | |
613 | "ptl_frame_only_constraint_flag: %" PRIu8 "\n", | ||
614 | 1 | vvcc->ptl.ptl_frame_only_constraint_flag); | |
615 | 1 | av_log(NULL, AV_LOG_TRACE, | |
616 | "ptl_multilayer_enabled_flag: %" PRIu8 "\n", | ||
617 | 1 | vvcc->ptl.ptl_multilayer_enabled_flag); | |
618 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (int i = 0; i < vvcc->ptl.num_bytes_constraint_info; i++) { |
619 | 1 | av_log(NULL, AV_LOG_TRACE, | |
620 | "general_constraint_info[%d]: %" PRIu8 "\n", i, | ||
621 | 1 | vvcc->ptl.general_constraint_info[i]); | |
622 | } | ||
623 | |||
624 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | for (int i = 0; i < vvcc->num_sublayers - 1; i++) { |
625 | ✗ | av_log(NULL, AV_LOG_TRACE, | |
626 | "ptl_sublayer_level_present_flag[%d]: %" PRIu8 "\n", i, | ||
627 | ✗ | vvcc->ptl.ptl_sublayer_level_present_flag[i]); | |
628 | ✗ | av_log(NULL, AV_LOG_TRACE, | |
629 | "sublayer_level_idc[%d]: %" PRIu8 "\n", i, | ||
630 | ✗ | vvcc->ptl.sublayer_level_idc[i]); | |
631 | } | ||
632 | |||
633 | 1 | av_log(NULL, AV_LOG_TRACE, | |
634 | "num_sub_profiles: %" PRIu8 "\n", | ||
635 | 1 | vvcc->ptl.ptl_num_sub_profiles); | |
636 | |||
637 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | for (unsigned i = 0; i < vvcc->ptl.ptl_num_sub_profiles; i++) { |
638 | ✗ | av_log(NULL, AV_LOG_TRACE, | |
639 | "general_sub_profile_idc[%u]: %" PRIx32 "\n", i, | ||
640 | vvcc->ptl.general_sub_profile_idc[i]); | ||
641 | } | ||
642 | |||
643 | 1 | av_log(NULL, AV_LOG_TRACE, | |
644 | "max_picture_width: %" PRIu16 "\n", | ||
645 | 1 | vvcc->max_picture_width); | |
646 | 1 | av_log(NULL, AV_LOG_TRACE, | |
647 | "max_picture_height: %" PRIu16 "\n", | ||
648 | 1 | vvcc->max_picture_height); | |
649 | 1 | av_log(NULL, AV_LOG_TRACE, | |
650 | "avg_frame_rate: %" PRIu16 "\n", | ||
651 | 1 | vvcc->avg_frame_rate); | |
652 | |||
653 | 1 | av_log(NULL, AV_LOG_TRACE, | |
654 | "num_of_arrays: %" PRIu8 "\n", | ||
655 | 1 | vvcc->num_of_arrays); | |
656 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
|
7 | for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc->arrays); i++) { |
657 | 6 | const VVCCNALUnitArray *const array = &vvcc->arrays[i]; | |
658 | |||
659 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (array->num_nalus == 0) |
660 | 3 | continue; | |
661 | |||
662 | 3 | av_log(NULL, AV_LOG_TRACE, | |
663 | "array_completeness[%u]: %" PRIu8 "\n", i, | ||
664 | 3 | array->array_completeness); | |
665 | 3 | av_log(NULL, AV_LOG_TRACE, | |
666 | "NAL_unit_type[%u]: %" PRIu8 "\n", i, | ||
667 | 3 | array->NAL_unit_type); | |
668 | 3 | av_log(NULL, AV_LOG_TRACE, | |
669 | "num_nalus[%u]: %" PRIu16 "\n", i, | ||
670 | 3 | array->num_nalus); | |
671 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | for (unsigned j = 0; j < array->num_nalus; j++) |
672 | 3 | av_log(NULL, AV_LOG_TRACE, | |
673 | "nal_unit_length[%u][%u]: %" | ||
674 | 3 | PRIu16 "\n", i, j, array->nal_unit_length[j]); | |
675 | } | ||
676 | |||
677 | /* | ||
678 | * We need at least one of each: SPS and PPS. | ||
679 | */ | ||
680 | 1 | vps_count = vvcc->arrays[VPS_INDEX].num_nalus; | |
681 | 1 | sps_count = vvcc->arrays[SPS_INDEX].num_nalus; | |
682 | 1 | pps_count = vvcc->arrays[PPS_INDEX].num_nalus; | |
683 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (vps_count > VVC_MAX_VPS_COUNT) |
684 | ✗ | return AVERROR_INVALIDDATA; | |
685 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (!sps_count || sps_count > VVC_MAX_SPS_COUNT) |
686 | ✗ | return AVERROR_INVALIDDATA; | |
687 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (!pps_count || pps_count > VVC_MAX_PPS_COUNT) |
688 | ✗ | return AVERROR_INVALIDDATA; | |
689 | |||
690 | /* bit(5) reserved = ‘11111’b; | ||
691 | unsigned int (2) LengthSizeMinusOne | ||
692 | unsigned int (1) ptl_present_flag */ | ||
693 | 1 | avio_w8(pb, vvcc->lengthSizeMinusOne << 1 | vvcc->ptl_present_flag | 0xf8); | |
694 | |||
695 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (vvcc->ptl_present_flag) { |
696 | uint8_t buf[64]; | ||
697 | PutBitContext pbc; | ||
698 | |||
699 | 1 | init_put_bits(&pbc, buf, sizeof(buf)); | |
700 | /* | ||
701 | * unsigned int(9) ols_idx; | ||
702 | * unsigned int(3) num_sublayers; | ||
703 | * unsigned int(2) constant_frame_rate; | ||
704 | * unsigned int(2) chroma_format_idc; */ | ||
705 | 1 | avio_wb16(pb, | |
706 | 1 | vvcc->ols_idx << 7 | vvcc->num_sublayers << 4 | vvcc-> | |
707 | 1 | constant_frame_rate << 2 | vvcc->chroma_format_idc); | |
708 | |||
709 | /* unsigned int(3) bit_depth_minus8; | ||
710 | bit(5) reserved = ‘11111’b; */ | ||
711 | 1 | avio_w8(pb, vvcc->bit_depth_minus8 << 5 | 0x1f); | |
712 | |||
713 | //VVCPTLRecord | ||
714 | |||
715 | /* bit(2) reserved = ‘00’b; | ||
716 | unsigned int (6) num_bytes_constraint_info */ | ||
717 | 1 | avio_w8(pb, vvcc->ptl.num_bytes_constraint_info & 0x3f); | |
718 | |||
719 | /* unsigned int (7) general_profile_idc | ||
720 | unsigned int (1) general_tier_flag */ | ||
721 | 1 | avio_w8(pb, | |
722 | 1 | vvcc->ptl.general_profile_idc << 1 | vvcc->ptl.general_tier_flag); | |
723 | |||
724 | /* unsigned int (8) general_level_idc */ | ||
725 | 1 | avio_w8(pb, vvcc->ptl.general_level_idc); | |
726 | |||
727 | /* | ||
728 | * unsigned int (1) ptl_frame_only_constraint_flag | ||
729 | * unsigned int (1) ptl_multilayer_enabled_flag | ||
730 | * unsigned int (8*num_bytes_constraint_info -2) general_constraint_info */ | ||
731 | 1 | put_bits(&pbc, 1, vvcc->ptl.ptl_frame_only_constraint_flag); | |
732 | 1 | put_bits(&pbc, 1, vvcc->ptl.ptl_multilayer_enabled_flag); | |
733 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | av_assert0(vvcc->ptl.num_bytes_constraint_info); |
734 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | for (int i = 0; i < vvcc->ptl.num_bytes_constraint_info - 1; i++) |
735 | ✗ | put_bits(&pbc, 8, vvcc->ptl.general_constraint_info[i]); | |
736 | 1 | put_bits(&pbc, 6, vvcc->ptl.general_constraint_info[vvcc->ptl.num_bytes_constraint_info - 1] & 0x3f); | |
737 | 1 | flush_put_bits(&pbc); | |
738 | 1 | avio_write(pb, buf, put_bytes_output(&pbc)); | |
739 | |||
740 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (vvcc->num_sublayers > 1) { |
741 | ✗ | uint8_t ptl_sublayer_level_present_flags = 0; | |
742 | ✗ | for (int i = vvcc->num_sublayers - 2; i >= 0; i--) { | |
743 | ✗ | ptl_sublayer_level_present_flags = | |
744 | ✗ | (ptl_sublayer_level_present_flags << 1 | vvcc->ptl. | |
745 | ✗ | ptl_sublayer_level_present_flag[i]); | |
746 | } | ||
747 | ✗ | avio_w8(pb, ptl_sublayer_level_present_flags); | |
748 | } | ||
749 | |||
750 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | for (int i = vvcc->num_sublayers - 2; i >= 0; i--) { |
751 | ✗ | if (vvcc->ptl.ptl_sublayer_level_present_flag[i]) | |
752 | ✗ | avio_w8(pb, vvcc->ptl.sublayer_level_idc[i]); | |
753 | } | ||
754 | |||
755 | /* unsigned int(8) num_sub_profiles; */ | ||
756 | 1 | avio_w8(pb, vvcc->ptl.ptl_num_sub_profiles); | |
757 | |||
758 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | for (int j = 0; j < vvcc->ptl.ptl_num_sub_profiles; j++) { |
759 | /* unsigned int(32) general_sub_profile_idc[j]; */ | ||
760 | ✗ | avio_wb32(pb, vvcc->ptl.general_sub_profile_idc[j]); | |
761 | } | ||
762 | |||
763 | //End of VvcPTLRecord | ||
764 | |||
765 | /* | ||
766 | * unsigned int(16) max_picture_width;*/ | ||
767 | 1 | avio_wb16(pb, vvcc->max_picture_width); | |
768 | |||
769 | /* | ||
770 | * unsigned int(16) max_picture_height;*/ | ||
771 | 1 | avio_wb16(pb, vvcc->max_picture_height); | |
772 | |||
773 | /* | ||
774 | * unsigned int(16) avg_frame_rate; */ | ||
775 | 1 | avio_wb16(pb, vvcc->avg_frame_rate); | |
776 | } | ||
777 | |||
778 | /* unsigned int(8) num_of_arrays; */ | ||
779 | 1 | avio_w8(pb, vvcc->num_of_arrays); | |
780 | |||
781 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
|
7 | for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc->arrays); i++) { |
782 | 6 | const VVCCNALUnitArray *const array = &vvcc->arrays[i]; | |
783 | |||
784 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (!array->num_nalus) |
785 | 3 | continue; | |
786 | /* | ||
787 | * bit(1) array_completeness; | ||
788 | * unsigned int(2) reserved = 0; | ||
789 | * unsigned int(5) NAL_unit_type; | ||
790 | */ | ||
791 | 3 | avio_w8(pb, array->array_completeness << 7 | | |
792 | 3 | array->NAL_unit_type & 0x1f); | |
793 | /* unsigned int(16) num_nalus; */ | ||
794 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (array->NAL_unit_type != VVC_DCI_NUT && |
795 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | array->NAL_unit_type != VVC_OPI_NUT) |
796 | 3 | avio_wb16(pb, array->num_nalus); | |
797 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | for (int j = 0; j < array->num_nalus; j++) { |
798 | /* unsigned int(16) nal_unit_length; */ | ||
799 | 3 | avio_wb16(pb, array->nal_unit_length[j]); | |
800 | |||
801 | /* bit(8*nal_unit_length) nal_unit; */ | ||
802 | 3 | avio_write(pb, array->nal_unit[j], | |
803 | 3 | array->nal_unit_length[j]); | |
804 | } | ||
805 | } | ||
806 | |||
807 | 1 | return 0; | |
808 | } | ||
809 | |||
810 | 10 | int ff_vvc_annexb2mp4(AVIOContext *pb, const uint8_t *buf_in, | |
811 | int size, int filter_ps, int *ps_count) | ||
812 | { | ||
813 | 10 | int num_ps = 0, ret = 0; | |
814 | 10 | uint8_t *buf, *end, *start = NULL; | |
815 | |||
816 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if (!filter_ps) { |
817 | 10 | ret = ff_nal_parse_units(pb, buf_in, size); | |
818 | 10 | goto end; | |
819 | } | ||
820 | |||
821 | ✗ | ret = ff_nal_parse_units_buf(buf_in, &start, &size); | |
822 | ✗ | if (ret < 0) | |
823 | ✗ | goto end; | |
824 | |||
825 | ✗ | ret = 0; | |
826 | ✗ | buf = start; | |
827 | ✗ | end = start + size; | |
828 | |||
829 | ✗ | while (end - buf > 4) { | |
830 | ✗ | uint32_t len = FFMIN(AV_RB32(buf), end - buf - 4); | |
831 | ✗ | uint8_t type = (buf[5] >> 3); | |
832 | |||
833 | ✗ | buf += 4; | |
834 | |||
835 | ✗ | switch (type) { | |
836 | ✗ | case VVC_VPS_NUT: | |
837 | case VVC_SPS_NUT: | ||
838 | case VVC_PPS_NUT: | ||
839 | ✗ | num_ps++; | |
840 | ✗ | break; | |
841 | ✗ | default: | |
842 | ✗ | ret += 4 + len; | |
843 | ✗ | avio_wb32(pb, len); | |
844 | ✗ | avio_write(pb, buf, len); | |
845 | ✗ | break; | |
846 | } | ||
847 | |||
848 | ✗ | buf += len; | |
849 | } | ||
850 | |||
851 | ✗ | end: | |
852 | 10 | av_free(start); | |
853 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (ps_count) |
854 | ✗ | *ps_count = num_ps; | |
855 | 10 | return ret; | |
856 | } | ||
857 | |||
858 | ✗ | int ff_vvc_annexb2mp4_buf(const uint8_t *buf_in, uint8_t **buf_out, | |
859 | int *size, int filter_ps, int *ps_count) | ||
860 | { | ||
861 | AVIOContext *pb; | ||
862 | int ret; | ||
863 | |||
864 | ✗ | ret = avio_open_dyn_buf(&pb); | |
865 | ✗ | if (ret < 0) | |
866 | ✗ | return ret; | |
867 | |||
868 | ✗ | ret = ff_vvc_annexb2mp4(pb, buf_in, *size, filter_ps, ps_count); | |
869 | ✗ | if (ret < 0) { | |
870 | ✗ | ffio_free_dyn_buf(&pb); | |
871 | ✗ | return ret; | |
872 | } | ||
873 | |||
874 | ✗ | *size = avio_close_dyn_buf(pb, buf_out); | |
875 | |||
876 | ✗ | return 0; | |
877 | } | ||
878 | |||
879 | 1 | int ff_isom_write_vvcc(AVIOContext *pb, const uint8_t *data, | |
880 | int size, int ps_array_completeness) | ||
881 | { | ||
882 | VVCDecoderConfigurationRecord vvcc; | ||
883 | uint8_t *buf, *end, *start; | ||
884 | int ret; | ||
885 | |||
886 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (size < 6) { |
887 | /* We can't write a valid vvcc from the provided data */ | ||
888 | ✗ | return AVERROR_INVALIDDATA; | |
889 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | } else if ((*data & 0xf8) == 0xf8) { |
890 | /* Data is already vvcc-formatted */ | ||
891 | ✗ | avio_write(pb, data, size); | |
892 | ✗ | return 0; | |
893 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | } else if (!(AV_RB24(data) == 1 || AV_RB32(data) == 1)) { |
894 | /* Not a valid Annex B start code prefix */ | ||
895 | ✗ | return AVERROR_INVALIDDATA; | |
896 | } | ||
897 | |||
898 | 1 | ret = ff_nal_parse_units_buf(data, &start, &size); | |
899 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ret < 0) |
900 | ✗ | return ret; | |
901 | |||
902 | 1 | vvcc_init(&vvcc); | |
903 | |||
904 | 1 | buf = start; | |
905 | 1 | end = start + size; | |
906 | |||
907 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | while (end - buf > 4) { |
908 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | uint32_t len = FFMIN(AV_RB32(buf), end - buf - 4); |
909 | 3 | uint8_t type = (buf[5] >> 3); | |
910 | |||
911 | 3 | buf += 4; | |
912 | |||
913 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc.arrays); i++) { |
914 | static const uint8_t array_idx_to_type[] = | ||
915 | { VVC_OPI_NUT, VVC_VPS_NUT, VVC_SPS_NUT, | ||
916 | VVC_PPS_NUT, VVC_PREFIX_SEI_NUT, VVC_SUFFIX_SEI_NUT }; | ||
917 | |||
918 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
|
9 | if (type == array_idx_to_type[i]) { |
919 | 3 | ret = vvcc_add_nal_unit(buf, len, ps_array_completeness, | |
920 | &vvcc, i); | ||
921 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (ret < 0) |
922 | ✗ | goto end; | |
923 | 3 | break; | |
924 | } | ||
925 | } | ||
926 | |||
927 | 3 | buf += len; | |
928 | } | ||
929 | |||
930 | 1 | ret = vvcc_write(pb, &vvcc); | |
931 | |||
932 | 1 | end: | |
933 | 1 | vvcc_close(&vvcc); | |
934 | 1 | av_free(start); | |
935 | 1 | return ret; | |
936 | } | ||
937 |