| 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 | 7 | 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 7 times.
|
7 | if (vvcc->ptl.general_tier_flag < ptl->general_tier_flag) |
| 93 | ✗ | vvcc->ptl.general_level_idc = ptl->general_level_idc; | |
| 94 | else | ||
| 95 | 7 | vvcc->ptl.general_level_idc = | |
| 96 | 7 | 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 | 7 | vvcc->ptl.general_tier_flag = | |
| 103 | 7 | 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 | 7 | vvcc->ptl.general_profile_idc = | |
| 120 | 7 | 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 | 7 | vvcc->ptl.ptl_frame_only_constraint_flag &= | |
| 127 | 7 | ptl->ptl_frame_only_constraint_flag; | |
| 128 | 7 | 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 7 times.
|
7 | 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 | 7 | vvcc->ptl.num_bytes_constraint_info = 1; | |
| 139 | 7 | 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 | 7 | memset(vvcc->ptl.ptl_sublayer_level_present_flag, 0, | |
| 147 | 7 | sizeof(uint8_t) * vvcc->num_sublayers - 1); | |
| 148 | 7 | memset(vvcc->ptl.sublayer_level_idc, 0, | |
| 149 | 7 | sizeof(uint8_t) * vvcc->num_sublayers - 1); | |
| 150 | |||
| 151 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7 times.
|
11 | for (int i = vvcc->num_sublayers - 2; i >= 0; i--) { |
| 152 | 4 | vvcc->ptl.ptl_sublayer_level_present_flag[i] |= | |
| 153 | 4 | ptl->ptl_sublayer_level_present_flag[i]; | |
| 154 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | 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 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (i == vvcc->num_sublayers - 1) { |
| 160 | ✗ | vvcc->ptl.sublayer_level_idc[i] = vvcc->ptl.general_level_idc; | |
| 161 | } else { | ||
| 162 | 4 | vvcc->ptl.sublayer_level_idc[i] = | |
| 163 | 4 | vvcc->ptl.sublayer_level_idc[i + 1]; | |
| 164 | } | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | 7 | vvcc->ptl.ptl_num_sub_profiles = | |
| 169 | 7 | FFMAX(vvcc->ptl.ptl_num_sub_profiles, ptl->ptl_num_sub_profiles); | |
| 170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | 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 | 7 | } | |
| 177 | |||
| 178 | 7 | static void vvcc_parse_ptl(GetBitContext *gb, | |
| 179 | VVCDecoderConfigurationRecord *vvcc, | ||
| 180 | unsigned int profileTierPresentFlag, | ||
| 181 | unsigned int max_sub_layers_minus1) | ||
| 182 | { | ||
| 183 | 7 | VVCPTLRecord general_ptl = { 0 }; | |
| 184 | |||
| 185 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
|
7 | if (profileTierPresentFlag) { |
| 186 | 5 | general_ptl.general_profile_idc = get_bits(gb, 7); | |
| 187 | 5 | general_ptl.general_tier_flag = get_bits1(gb); | |
| 188 | } | ||
| 189 | 7 | general_ptl.general_level_idc = get_bits(gb, 8); | |
| 190 | |||
| 191 | 7 | general_ptl.ptl_frame_only_constraint_flag = get_bits1(gb); | |
| 192 | 7 | general_ptl.ptl_multilayer_enabled_flag = get_bits1(gb); | |
| 193 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
|
7 | if (profileTierPresentFlag) { // parse constraint info |
| 194 | 5 | general_ptl.num_bytes_constraint_info = get_bits1(gb); // gci_present_flag | |
| 195 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | 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 | 5 | align_get_bits(gb); | |
| 206 | } | ||
| 207 | |||
| 208 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7 times.
|
11 | for (int i = max_sub_layers_minus1 - 1; i >= 0; i--) |
| 209 | 4 | general_ptl.ptl_sublayer_level_present_flag[i] = get_bits1(gb); | |
| 210 | |||
| 211 | 7 | align_get_bits(gb); | |
| 212 | |||
| 213 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7 times.
|
11 | for (int i = max_sub_layers_minus1 - 1; i >= 0; i--) { |
| 214 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | 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 5 times.
✓ Branch 1 taken 2 times.
|
7 | if (profileTierPresentFlag) { |
| 219 | 5 | general_ptl.ptl_num_sub_profiles = get_bits(gb, 8); | |
| 220 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | 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 | 7 | vvcc_update_ptl(vvcc, &general_ptl); | |
| 227 | 7 | } | |
| 228 | |||
| 229 | 2 | 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 | 2 | unsigned int vps_num_ptls_minus1 = 0; | |
| 240 | |||
| 241 | /* | ||
| 242 | * vps_video_parameter_set_id u(4) | ||
| 243 | */ | ||
| 244 | 2 | skip_bits(gb, 4); | |
| 245 | |||
| 246 | 2 | vps_max_layers_minus1 = get_bits(gb, 6); | |
| 247 | 2 | 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 | 2 | vvcc->num_sublayers = FFMAX(vvcc->num_sublayers, | |
| 258 | vps_max_sublayers_minus1 + 1); | ||
| 259 | |||
| 260 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | 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 | 2 | vps_default_ptl_dpb_hrd_max_tid_flag = 0; | |
| 264 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (vps_max_layers_minus1 > 0) |
| 265 | 2 | vps_all_independent_layers_flag = get_bits1(gb); | |
| 266 | else | ||
| 267 | ✗ | vps_all_independent_layers_flag = 1; | |
| 268 | |||
| 269 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | for (int i = 0; i <= vps_max_layers_minus1; i++) { |
| 270 | 4 | skip_bits(gb, 6); //vps_layer_id[i] | |
| 271 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
4 | if (i > 0 && !vps_all_independent_layers_flag) { |
| 272 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (!get_bits1(gb)) { // vps_independent_layer_flag[i] |
| 273 | 2 | unsigned int vps_max_tid_ref_present_flag = get_bits1(gb); | |
| 274 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | for (int j = 0; j < i; j++) { |
| 275 | 2 | unsigned int vps_direct_ref_layer_flag = get_bits1(gb); | |
| 276 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2 | 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 2 times.
✗ Branch 1 not taken.
|
2 | 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 2 times.
|
2 | if (vps_all_independent_layers_flag) |
| 286 | ✗ | vps_each_layer_is_an_ols_flag = get_bits1(gb); | |
| 287 | else | ||
| 288 | 2 | vps_each_layer_is_an_ols_flag = 0; | |
| 289 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!vps_each_layer_is_an_ols_flag) { |
| 290 | unsigned int vps_ols_mode_idc; | ||
| 291 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!vps_all_independent_layers_flag) |
| 292 | 2 | vps_ols_mode_idc = get_bits(gb, 2); | |
| 293 | else | ||
| 294 | ✗ | vps_ols_mode_idc = 2; | |
| 295 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (vps_ols_mode_idc == 2) { |
| 296 | 2 | unsigned int vps_num_output_layer_sets_minus2 = get_bits(gb, 8); | |
| 297 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | for (int i = 1; i <= vps_num_output_layer_sets_minus2 + 1; i++) { |
| 298 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | for (int j = 0; j <= vps_max_layers_minus1; j++) { |
| 299 | 4 | skip_bits1(gb); // vps_ols_output_layer_flag[i][j] | |
| 300 | } | ||
| 301 | } | ||
| 302 | } | ||
| 303 | } | ||
| 304 | 2 | vps_num_ptls_minus1 = get_bits(gb, 8); | |
| 305 | } | ||
| 306 | |||
| 307 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | for (int i = 0; i <= vps_num_ptls_minus1; i++) { |
| 308 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (i > 0) |
| 309 | 2 | vps_pt_present_flag[i] = get_bits1(gb); | |
| 310 | else | ||
| 311 | 2 | vps_pt_present_flag[i] = 1; | |
| 312 | |||
| 313 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (!vps_default_ptl_dpb_hrd_max_tid_flag) |
| 314 | 4 | vps_ptl_max_tid[i] = get_bits(gb, 3); | |
| 315 | else | ||
| 316 | ✗ | vps_ptl_max_tid[i] = vps_max_sublayers_minus1; | |
| 317 | } | ||
| 318 | |||
| 319 | 2 | align_get_bits(gb); | |
| 320 | |||
| 321 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | for (int i = 0; i <= vps_num_ptls_minus1; i++) |
| 322 | 4 | vvcc_parse_ptl(gb, vvcc, vps_pt_present_flag[i], vps_ptl_max_tid[i]); | |
| 323 | 2 | vvcc->ptl_present_flag = 1; | |
| 324 | |||
| 325 | /* nothing useful for vvcc past this point */ | ||
| 326 | 2 | return 0; | |
| 327 | } | ||
| 328 | |||
| 329 | 3 | 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 | 3 | skip_bits(gb, 8); // sps_seq_parameter_set_id && sps_video_parameter_set_id | |
| 338 | 3 | 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 | 3 | vvcc->num_sublayers = FFMAX(vvcc->num_sublayers, | |
| 349 | sps_max_sublayers_minus1 + 1); | ||
| 350 | |||
| 351 | 3 | vvcc->chroma_format_idc = get_bits(gb, 2); | |
| 352 | 3 | sps_log2_ctu_size_minus5 = get_bits(gb, 2); | |
| 353 | |||
| 354 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | if (get_bits1(gb)) { // sps_ptl_dpb_hrd_params_present_flag |
| 355 | 3 | vvcc->ptl_present_flag = 1; | |
| 356 | 3 | vvcc_parse_ptl(gb, vvcc, 1, sps_max_sublayers_minus1); | |
| 357 | } | ||
| 358 | |||
| 359 | 3 | skip_bits1(gb); // sps_gdr_enabled_flag | |
| 360 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | if (get_bits(gb, 1)) // sps_ref_pic_resampling_enabled_flag |
| 361 | 3 | skip_bits1(gb); // sps_res_change_in_clvs_allowed_flag | |
| 362 | |||
| 363 | 3 | sps_pic_width_max_in_luma_samples = get_ue_golomb_long(gb); | |
| 364 | 3 | vvcc->max_picture_width = | |
| 365 | 3 | FFMAX(vvcc->max_picture_width, sps_pic_width_max_in_luma_samples); | |
| 366 | 3 | sps_pic_height_max_in_luma_samples = get_ue_golomb_long(gb); | |
| 367 | 3 | vvcc->max_picture_height = | |
| 368 | 3 | FFMAX(vvcc->max_picture_height, sps_pic_height_max_in_luma_samples); | |
| 369 | |||
| 370 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | 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 3 times.
|
3 | 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 | 3 | vvcc->bit_depth_minus8 = get_ue_golomb_long(gb); | |
| 414 | |||
| 415 | /* nothing useful for vvcc past this point */ | ||
| 416 | 3 | return 0; | |
| 417 | } | ||
| 418 | |||
| 419 | 3 | 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 | 3 | return 0; | |
| 426 | } | ||
| 427 | |||
| 428 | 8 | 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 | 8 | skip_bits(gb, 8); | |
| 436 | 8 | *nal_type = get_bits(gb, 5); | |
| 437 | |||
| 438 | /* | ||
| 439 | * nuh_temporal_id_plus1 u(3) | ||
| 440 | */ | ||
| 441 | 8 | skip_bits(gb, 3); | |
| 442 | 8 | } | |
| 443 | |||
| 444 | 8 | 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 | 8 | num_nalus = array->num_nalus; | |
| 452 | |||
| 453 | 8 | ret = av_reallocp_array(&array->nal_unit, num_nalus + 1, sizeof(uint8_t *)); | |
| 454 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (ret < 0) |
| 455 | ✗ | return ret; | |
| 456 | |||
| 457 | ret = | ||
| 458 | 8 | av_reallocp_array(&array->nal_unit_length, num_nalus + 1, | |
| 459 | sizeof(uint16_t)); | ||
| 460 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (ret < 0) |
| 461 | ✗ | return ret; | |
| 462 | |||
| 463 | 8 | array->nal_unit[num_nalus] = nal_buf; | |
| 464 | 8 | array->nal_unit_length[num_nalus] = nal_size; | |
| 465 | 8 | array->NAL_unit_type = nal_type; | |
| 466 | 8 | 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 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
|
8 | if (nal_type == VVC_VPS_NUT || nal_type == VVC_SPS_NUT || |
| 489 | ✗ | nal_type == VVC_PPS_NUT || nal_type == VVC_DCI_NUT ) | |
| 490 | 8 | array->array_completeness = ps_array_completeness; | |
| 491 | |||
| 492 | 8 | return 0; | |
| 493 | } | ||
| 494 | |||
| 495 | 8 | 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 | 8 | int ret = 0; | |
| 501 | GetBitContext gbc; | ||
| 502 | uint8_t nal_type; | ||
| 503 | uint8_t *rbsp_buf; | ||
| 504 | uint32_t rbsp_size; | ||
| 505 | |||
| 506 | 8 | rbsp_buf = ff_nal_unit_extract_rbsp(nal_buf, nal_size, &rbsp_size, 2); | |
| 507 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (!rbsp_buf) { |
| 508 | ✗ | ret = AVERROR(ENOMEM); | |
| 509 | ✗ | goto end; | |
| 510 | } | ||
| 511 | |||
| 512 | 8 | ret = init_get_bits8(&gbc, rbsp_buf, rbsp_size); | |
| 513 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (ret < 0) |
| 514 | ✗ | goto end; | |
| 515 | |||
| 516 | 8 | 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 | 8 | 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 8 times.
|
8 | if (ret < 0) |
| 527 | ✗ | goto end; | |
| 528 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (vvcc->arrays[array_idx].num_nalus == 1) |
| 529 | 8 | vvcc->num_of_arrays++; | |
| 530 | |||
| 531 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
|
8 | if (nal_type == VVC_VPS_NUT) |
| 532 | 2 | ret = vvcc_parse_vps(&gbc, vvcc); | |
| 533 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | else if (nal_type == VVC_SPS_NUT) |
| 534 | 3 | ret = vvcc_parse_sps(&gbc, vvcc); | |
| 535 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | else if (nal_type == VVC_PPS_NUT) |
| 536 | 3 | 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 8 times.
✗ Branch 1 not taken.
|
8 | if (ret < 0) |
| 541 | ✗ | goto end; | |
| 542 | |||
| 543 | 8 | end: | |
| 544 | 8 | av_free(rbsp_buf); | |
| 545 | 8 | return ret; | |
| 546 | } | ||
| 547 | |||
| 548 | 3 | static void vvcc_init(VVCDecoderConfigurationRecord *vvcc) | |
| 549 | { | ||
| 550 | 3 | memset(vvcc, 0, sizeof(VVCDecoderConfigurationRecord)); | |
| 551 | 3 | vvcc->lengthSizeMinusOne = 3; // 4 bytes | |
| 552 | 3 | vvcc->ptl.ptl_frame_only_constraint_flag = | |
| 553 | 3 | vvcc->ptl.ptl_multilayer_enabled_flag = 1; | |
| 554 | 3 | } | |
| 555 | |||
| 556 | 3 | static void vvcc_close(VVCDecoderConfigurationRecord *vvcc) | |
| 557 | { | ||
| 558 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 3 times.
|
21 | for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc->arrays); i++) { |
| 559 | 18 | VVCCNALUnitArray *const array = &vvcc->arrays[i]; | |
| 560 | |||
| 561 | 18 | array->num_nalus = 0; | |
| 562 | 18 | av_freep(&array->nal_unit); | |
| 563 | 18 | av_freep(&array->nal_unit_length); | |
| 564 | } | ||
| 565 | |||
| 566 | 3 | vvcc->num_of_arrays = 0; | |
| 567 | 3 | } | |
| 568 | |||
| 569 | 3 | static int vvcc_write(AVIOContext *pb, VVCDecoderConfigurationRecord *vvcc) | |
| 570 | { | ||
| 571 | 3 | 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 | 3 | vvcc->avg_frame_rate = 0; | |
| 577 | 3 | vvcc->constant_frame_rate = 1; | |
| 578 | |||
| 579 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 580 | "lengthSizeMinusOne: %" PRIu8 "\n", | ||
| 581 | 3 | vvcc->lengthSizeMinusOne); | |
| 582 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 583 | "ptl_present_flag: %" PRIu8 "\n", | ||
| 584 | 3 | vvcc->ptl_present_flag); | |
| 585 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 586 | 3 | "ols_idx: %" PRIu16 "\n", vvcc->ols_idx); | |
| 587 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 588 | "num_sublayers: %" PRIu8 "\n", | ||
| 589 | 3 | vvcc->num_sublayers); | |
| 590 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 591 | "constant_frame_rate: %" PRIu8 "\n", | ||
| 592 | 3 | vvcc->constant_frame_rate); | |
| 593 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 594 | "chroma_format_idc: %" PRIu8 "\n", | ||
| 595 | 3 | vvcc->chroma_format_idc); | |
| 596 | |||
| 597 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 598 | "bit_depth_minus8: %" PRIu8 "\n", | ||
| 599 | 3 | vvcc->bit_depth_minus8); | |
| 600 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 601 | "num_bytes_constraint_info: %" PRIu8 "\n", | ||
| 602 | 3 | vvcc->ptl.num_bytes_constraint_info); | |
| 603 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 604 | "general_profile_idc: %" PRIu8 "\n", | ||
| 605 | 3 | vvcc->ptl.general_profile_idc); | |
| 606 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 607 | "general_tier_flag: %" PRIu8 "\n", | ||
| 608 | 3 | vvcc->ptl.general_tier_flag); | |
| 609 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 610 | "general_level_idc: %" PRIu8 "\n", | ||
| 611 | 3 | vvcc->ptl.general_level_idc); | |
| 612 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 613 | "ptl_frame_only_constraint_flag: %" PRIu8 "\n", | ||
| 614 | 3 | vvcc->ptl.ptl_frame_only_constraint_flag); | |
| 615 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 616 | "ptl_multilayer_enabled_flag: %" PRIu8 "\n", | ||
| 617 | 3 | vvcc->ptl.ptl_multilayer_enabled_flag); | |
| 618 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | for (int i = 0; i < vvcc->ptl.num_bytes_constraint_info; i++) { |
| 619 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 620 | "general_constraint_info[%d]: %" PRIu8 "\n", i, | ||
| 621 | 3 | vvcc->ptl.general_constraint_info[i]); | |
| 622 | } | ||
| 623 | |||
| 624 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
|
7 | for (int i = 0; i < vvcc->num_sublayers - 1; i++) { |
| 625 | 4 | av_log(NULL, AV_LOG_TRACE, | |
| 626 | "ptl_sublayer_level_present_flag[%d]: %" PRIu8 "\n", i, | ||
| 627 | 4 | vvcc->ptl.ptl_sublayer_level_present_flag[i]); | |
| 628 | 4 | av_log(NULL, AV_LOG_TRACE, | |
| 629 | "sublayer_level_idc[%d]: %" PRIu8 "\n", i, | ||
| 630 | 4 | vvcc->ptl.sublayer_level_idc[i]); | |
| 631 | } | ||
| 632 | |||
| 633 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 634 | "num_sub_profiles: %" PRIu8 "\n", | ||
| 635 | 3 | vvcc->ptl.ptl_num_sub_profiles); | |
| 636 | |||
| 637 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | 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 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 644 | "max_picture_width: %" PRIu16 "\n", | ||
| 645 | 3 | vvcc->max_picture_width); | |
| 646 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 647 | "max_picture_height: %" PRIu16 "\n", | ||
| 648 | 3 | vvcc->max_picture_height); | |
| 649 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 650 | "avg_frame_rate: %" PRIu16 "\n", | ||
| 651 | 3 | vvcc->avg_frame_rate); | |
| 652 | |||
| 653 | 3 | av_log(NULL, AV_LOG_TRACE, | |
| 654 | "num_of_arrays: %" PRIu8 "\n", | ||
| 655 | 3 | vvcc->num_of_arrays); | |
| 656 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 3 times.
|
21 | for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc->arrays); i++) { |
| 657 | 18 | const VVCCNALUnitArray *const array = &vvcc->arrays[i]; | |
| 658 | |||
| 659 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 8 times.
|
18 | if (array->num_nalus == 0) |
| 660 | 10 | continue; | |
| 661 | |||
| 662 | 8 | av_log(NULL, AV_LOG_TRACE, | |
| 663 | "array_completeness[%u]: %" PRIu8 "\n", i, | ||
| 664 | 8 | array->array_completeness); | |
| 665 | 8 | av_log(NULL, AV_LOG_TRACE, | |
| 666 | "NAL_unit_type[%u]: %" PRIu8 "\n", i, | ||
| 667 | 8 | array->NAL_unit_type); | |
| 668 | 8 | av_log(NULL, AV_LOG_TRACE, | |
| 669 | "num_nalus[%u]: %" PRIu16 "\n", i, | ||
| 670 | 8 | array->num_nalus); | |
| 671 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | for (unsigned j = 0; j < array->num_nalus; j++) |
| 672 | 8 | av_log(NULL, AV_LOG_TRACE, | |
| 673 | "nal_unit_length[%u][%u]: %" | ||
| 674 | 8 | 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 | 3 | vps_count = vvcc->arrays[VPS_INDEX].num_nalus; | |
| 681 | 3 | sps_count = vvcc->arrays[SPS_INDEX].num_nalus; | |
| 682 | 3 | pps_count = vvcc->arrays[PPS_INDEX].num_nalus; | |
| 683 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (vps_count > VVC_MAX_VPS_COUNT) |
| 684 | ✗ | return AVERROR_INVALIDDATA; | |
| 685 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
3 | if (!sps_count || sps_count > VVC_MAX_SPS_COUNT) |
| 686 | ✗ | return AVERROR_INVALIDDATA; | |
| 687 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
3 | 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 | 3 | avio_w8(pb, vvcc->lengthSizeMinusOne << 1 | vvcc->ptl_present_flag | 0xf8); | |
| 694 | |||
| 695 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (vvcc->ptl_present_flag) { |
| 696 | uint8_t buf[64]; | ||
| 697 | PutBitContext pbc; | ||
| 698 | |||
| 699 | 3 | 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 | 3 | avio_wb16(pb, | |
| 706 | 3 | vvcc->ols_idx << 7 | vvcc->num_sublayers << 4 | vvcc-> | |
| 707 | 3 | constant_frame_rate << 2 | vvcc->chroma_format_idc); | |
| 708 | |||
| 709 | /* unsigned int(3) bit_depth_minus8; | ||
| 710 | bit(5) reserved = ‘11111’b; */ | ||
| 711 | 3 | 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 | 3 | 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 | 3 | avio_w8(pb, | |
| 722 | 3 | vvcc->ptl.general_profile_idc << 1 | vvcc->ptl.general_tier_flag); | |
| 723 | |||
| 724 | /* unsigned int (8) general_level_idc */ | ||
| 725 | 3 | 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 | 3 | put_bits(&pbc, 1, vvcc->ptl.ptl_frame_only_constraint_flag); | |
| 732 | 3 | put_bits(&pbc, 1, vvcc->ptl.ptl_multilayer_enabled_flag); | |
| 733 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | av_assert0(vvcc->ptl.num_bytes_constraint_info); |
| 734 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | 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 | 3 | put_bits(&pbc, 6, vvcc->ptl.general_constraint_info[vvcc->ptl.num_bytes_constraint_info - 1] & 0x3f); | |
| 737 | 3 | flush_put_bits(&pbc); | |
| 738 | 3 | avio_write(pb, buf, put_bytes_output(&pbc)); | |
| 739 | |||
| 740 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if (vvcc->num_sublayers > 1) { |
| 741 | 1 | uint8_t ptl_sublayer_level_present_flags = 0; | |
| 742 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
|
5 | for (int i = vvcc->num_sublayers - 2; i >= 0; i--) { |
| 743 | 4 | ptl_sublayer_level_present_flags = | |
| 744 | 4 | (ptl_sublayer_level_present_flags << 1 | vvcc->ptl. | |
| 745 | 4 | ptl_sublayer_level_present_flag[i]); | |
| 746 | } | ||
| 747 | 1 | avio_w8(pb, ptl_sublayer_level_present_flags); | |
| 748 | } | ||
| 749 | |||
| 750 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
|
7 | for (int i = vvcc->num_sublayers - 2; i >= 0; i--) { |
| 751 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | 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 | 3 | avio_w8(pb, vvcc->ptl.ptl_num_sub_profiles); | |
| 757 | |||
| 758 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | 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 | 3 | avio_wb16(pb, vvcc->max_picture_width); | |
| 768 | |||
| 769 | /* | ||
| 770 | * unsigned int(16) max_picture_height;*/ | ||
| 771 | 3 | avio_wb16(pb, vvcc->max_picture_height); | |
| 772 | |||
| 773 | /* | ||
| 774 | * unsigned int(16) avg_frame_rate; */ | ||
| 775 | 3 | avio_wb16(pb, vvcc->avg_frame_rate); | |
| 776 | } | ||
| 777 | |||
| 778 | /* unsigned int(8) num_of_arrays; */ | ||
| 779 | 3 | avio_w8(pb, vvcc->num_of_arrays); | |
| 780 | |||
| 781 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 3 times.
|
21 | for (unsigned i = 0; i < FF_ARRAY_ELEMS(vvcc->arrays); i++) { |
| 782 | 18 | const VVCCNALUnitArray *const array = &vvcc->arrays[i]; | |
| 783 | |||
| 784 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 8 times.
|
18 | if (!array->num_nalus) |
| 785 | 10 | continue; | |
| 786 | /* | ||
| 787 | * bit(1) array_completeness; | ||
| 788 | * unsigned int(2) reserved = 0; | ||
| 789 | * unsigned int(5) NAL_unit_type; | ||
| 790 | */ | ||
| 791 | 8 | avio_w8(pb, array->array_completeness << 7 | | |
| 792 | 8 | array->NAL_unit_type & 0x1f); | |
| 793 | /* unsigned int(16) num_nalus; */ | ||
| 794 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (array->NAL_unit_type != VVC_DCI_NUT && |
| 795 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | array->NAL_unit_type != VVC_OPI_NUT) |
| 796 | 8 | avio_wb16(pb, array->num_nalus); | |
| 797 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | for (int j = 0; j < array->num_nalus; j++) { |
| 798 | /* unsigned int(16) nal_unit_length; */ | ||
| 799 | 8 | avio_wb16(pb, array->nal_unit_length[j]); | |
| 800 | |||
| 801 | /* bit(8*nal_unit_length) nal_unit; */ | ||
| 802 | 8 | avio_write(pb, array->nal_unit[j], | |
| 803 | 8 | array->nal_unit_length[j]); | |
| 804 | } | ||
| 805 | } | ||
| 806 | |||
| 807 | 3 | return 0; | |
| 808 | } | ||
| 809 | |||
| 810 | 27 | int ff_vvc_annexb2mp4(AVIOContext *pb, const uint8_t *buf_in, | |
| 811 | int size, int filter_ps, int *ps_count) | ||
| 812 | { | ||
| 813 | 27 | int num_ps = 0, ret = 0; | |
| 814 | 27 | uint8_t *buf, *end, *start = NULL; | |
| 815 | |||
| 816 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | if (!filter_ps) { |
| 817 | 27 | ret = ff_nal_parse_units(pb, buf_in, size); | |
| 818 | 27 | 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 | 27 | av_free(start); | |
| 853 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
|
27 | if (ps_count) |
| 854 | ✗ | *ps_count = num_ps; | |
| 855 | 27 | return ret; | |
| 856 | } | ||
| 857 | |||
| 858 | 17 | 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 | 17 | ret = avio_open_dyn_buf(&pb); | |
| 865 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (ret < 0) |
| 866 | ✗ | return ret; | |
| 867 | |||
| 868 | 17 | ret = ff_vvc_annexb2mp4(pb, buf_in, *size, filter_ps, ps_count); | |
| 869 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (ret < 0) { |
| 870 | ✗ | ffio_free_dyn_buf(&pb); | |
| 871 | ✗ | return ret; | |
| 872 | } | ||
| 873 | |||
| 874 | 17 | *size = avio_close_dyn_buf(pb, buf_out); | |
| 875 | |||
| 876 | 17 | return 0; | |
| 877 | } | ||
| 878 | |||
| 879 | 3 | 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 3 times.
|
3 | 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 3 times.
|
3 | } else if ((*data & 0xf8) == 0xf8) { |
| 890 | /* Data is already vvcc-formatted */ | ||
| 891 | ✗ | avio_write(pb, data, size); | |
| 892 | ✗ | return 0; | |
| 893 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
3 | } 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 | 3 | ret = ff_nal_parse_units_buf(data, &start, &size); | |
| 899 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (ret < 0) |
| 900 | ✗ | return ret; | |
| 901 | |||
| 902 | 3 | vvcc_init(&vvcc); | |
| 903 | |||
| 904 | 3 | buf = start; | |
| 905 | 3 | end = start + size; | |
| 906 | |||
| 907 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
|
11 | while (end - buf > 4) { |
| 908 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | uint32_t len = FFMIN(AV_RB32(buf), end - buf - 4); |
| 909 | 8 | uint8_t type = (buf[5] >> 3); | |
| 910 | |||
| 911 | 8 | buf += 4; | |
| 912 | |||
| 913 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | 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 8 times.
✓ Branch 1 taken 17 times.
|
25 | if (type == array_idx_to_type[i]) { |
| 919 | 8 | ret = vvcc_add_nal_unit(buf, len, ps_array_completeness, | |
| 920 | &vvcc, i); | ||
| 921 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (ret < 0) |
| 922 | ✗ | goto end; | |
| 923 | 8 | break; | |
| 924 | } | ||
| 925 | } | ||
| 926 | |||
| 927 | 8 | buf += len; | |
| 928 | } | ||
| 929 | |||
| 930 | 3 | ret = vvcc_write(pb, &vvcc); | |
| 931 | |||
| 932 | 3 | end: | |
| 933 | 3 | vvcc_close(&vvcc); | |
| 934 | 3 | av_free(start); | |
| 935 | 3 | return ret; | |
| 936 | } | ||
| 937 |