| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * H.266 / VVC parser | ||
| 3 | * | ||
| 4 | * Copyright (C) 2021 Nuo Mi <nuomi2021@gmail.com> | ||
| 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 "libavutil/mem.h" | ||
| 24 | #include "cbs.h" | ||
| 25 | #include "cbs_h266.h" | ||
| 26 | #include "parser.h" | ||
| 27 | #include "parser_internal.h" | ||
| 28 | |||
| 29 | #define START_CODE 0x000001 ///< start_code_prefix_one_3bytes | ||
| 30 | #define IS_IDR(nut) (nut == VVC_IDR_W_RADL || nut == VVC_IDR_N_LP) | ||
| 31 | #define IS_H266_SLICE(nut) (nut <= VVC_RASL_NUT || (nut >= VVC_IDR_W_RADL && nut <= VVC_GDR_NUT)) | ||
| 32 | |||
| 33 | typedef struct PuInfo { | ||
| 34 | const H266RawPPS *pps; | ||
| 35 | const H266RawSPS *sps; | ||
| 36 | const H266RawPictureHeader *ph; | ||
| 37 | const H266RawSlice *slice; | ||
| 38 | int pic_type; | ||
| 39 | } PuInfo; | ||
| 40 | |||
| 41 | typedef struct AuDetector { | ||
| 42 | uint8_t prev_layer_id; | ||
| 43 | int prev_tid0_poc; | ||
| 44 | int prev_poc; | ||
| 45 | } AuDetector; | ||
| 46 | |||
| 47 | typedef struct VVCParserContext { | ||
| 48 | ParseContext pc; | ||
| 49 | CodedBitstreamContext *cbc; | ||
| 50 | |||
| 51 | CodedBitstreamFragment picture_unit; | ||
| 52 | |||
| 53 | AVPacket au; | ||
| 54 | AVPacket last_au; | ||
| 55 | |||
| 56 | AuDetector au_detector; | ||
| 57 | |||
| 58 | int parsed_extradata; | ||
| 59 | } VVCParserContext; | ||
| 60 | |||
| 61 | static const enum AVPixelFormat pix_fmts_8bit[] = { | ||
| 62 | AV_PIX_FMT_GRAY8, AV_PIX_FMT_YUV420P, | ||
| 63 | AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P | ||
| 64 | }; | ||
| 65 | |||
| 66 | static const enum AVPixelFormat pix_fmts_10bit[] = { | ||
| 67 | AV_PIX_FMT_GRAY10, AV_PIX_FMT_YUV420P10, | ||
| 68 | AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10 | ||
| 69 | }; | ||
| 70 | |||
| 71 | 3135 | static int get_format(const H266RawSPS *sps) | |
| 72 | { | ||
| 73 |
2/3✓ Branch 0 taken 34 times.
✓ Branch 1 taken 3101 times.
✗ Branch 2 not taken.
|
3135 | switch (sps->sps_bitdepth_minus8) { |
| 74 | 34 | case 0: | |
| 75 | 34 | return pix_fmts_8bit[sps->sps_chroma_format_idc]; | |
| 76 | 3101 | case 2: | |
| 77 | 3101 | return pix_fmts_10bit[sps->sps_chroma_format_idc]; | |
| 78 | } | ||
| 79 | ✗ | return AV_PIX_FMT_NONE; | |
| 80 | } | ||
| 81 | |||
| 82 | /** | ||
| 83 | * Find the end of the current frame in the bitstream. | ||
| 84 | * @return the position of the first byte of the next frame, or END_NOT_FOUND | ||
| 85 | */ | ||
| 86 | 11569 | static int find_frame_end(AVCodecParserContext *s, const uint8_t *buf, | |
| 87 | int buf_size) | ||
| 88 | { | ||
| 89 | 11569 | VVCParserContext *ctx = s->priv_data; | |
| 90 | 11569 | ParseContext *pc = &ctx->pc; | |
| 91 | int i; | ||
| 92 | |||
| 93 |
2/2✓ Branch 0 taken 8532870 times.
✓ Branch 1 taken 8459 times.
|
8541329 | for (i = 0; i < buf_size; i++) { |
| 94 | int nut, code_len; | ||
| 95 | |||
| 96 | 8532870 | pc->state64 = (pc->state64 << 8) | buf[i]; | |
| 97 | |||
| 98 |
2/2✓ Branch 0 taken 8520505 times.
✓ Branch 1 taken 12365 times.
|
8532870 | if (((pc->state64 >> 3 * 8) & 0xFFFFFF) != START_CODE) |
| 99 | 8520505 | continue; | |
| 100 | |||
| 101 |
2/2✓ Branch 0 taken 6926 times.
✓ Branch 1 taken 5439 times.
|
12365 | code_len = ((pc->state64 >> 3 * 8) & 0xFFFFFFFF) == 0x01 ? 4 : 3; |
| 102 | |||
| 103 | 12365 | nut = (pc->state64 >> (8 + 3)) & 0x1F; | |
| 104 | // 7.4.2.4.3 and 7.4.2.4.4 | ||
| 105 |
5/6✓ Branch 0 taken 5713 times.
✓ Branch 1 taken 6652 times.
✓ Branch 2 taken 2248 times.
✓ Branch 3 taken 3465 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2248 times.
|
12365 | if ((nut >= VVC_OPI_NUT && nut <= VVC_PREFIX_APS_NUT && |
| 106 |
2/2✓ Branch 0 taken 10073 times.
✓ Branch 1 taken 44 times.
|
10117 | nut != VVC_PH_NUT) || nut == VVC_AUD_NUT |
| 107 |
4/4✓ Branch 0 taken 144 times.
✓ Branch 1 taken 9929 times.
✓ Branch 2 taken 135 times.
✓ Branch 3 taken 9 times.
|
10073 | || (nut == VVC_PREFIX_SEI_NUT && !pc->frame_start_found) |
| 108 |
2/4✓ Branch 0 taken 10064 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10064 times.
✗ Branch 3 not taken.
|
10064 | || nut == VVC_RSV_NVCL_26 || nut == VVC_UNSPEC_28 |
| 109 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10064 times.
|
10064 | || nut == VVC_UNSPEC_29) { |
| 110 |
2/2✓ Branch 0 taken 752 times.
✓ Branch 1 taken 1549 times.
|
2301 | if (pc->frame_start_found) { |
| 111 | 752 | pc->frame_start_found = 0; | |
| 112 | 752 | return i - (code_len + 2); | |
| 113 | } | ||
| 114 |
7/8✓ Branch 0 taken 9902 times.
✓ Branch 1 taken 162 times.
✓ Branch 2 taken 3851 times.
✓ Branch 3 taken 6051 times.
✓ Branch 4 taken 3851 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 601 times.
✓ Branch 7 taken 3250 times.
|
10064 | } else if (nut == VVC_PH_NUT || IS_H266_SLICE(nut)) { |
| 115 | 6814 | int sh_picture_header_in_slice_header_flag = buf[i] >> 7; | |
| 116 | |||
| 117 |
4/4✓ Branch 0 taken 6652 times.
✓ Branch 1 taken 162 times.
✓ Branch 2 taken 5366 times.
✓ Branch 3 taken 1286 times.
|
6814 | if (nut == VVC_PH_NUT || sh_picture_header_in_slice_header_flag) { |
| 118 |
2/2✓ Branch 0 taken 3170 times.
✓ Branch 1 taken 2358 times.
|
5528 | if (!pc->frame_start_found) { |
| 119 | 3170 | pc->frame_start_found = 1; | |
| 120 | } else { // First slice of next frame found | ||
| 121 | 2358 | pc->frame_start_found = 0; | |
| 122 | 2358 | return i - (code_len + 2); | |
| 123 | } | ||
| 124 | } | ||
| 125 | } | ||
| 126 | } | ||
| 127 | 8459 | return END_NOT_FOUND; | |
| 128 | } | ||
| 129 | |||
| 130 | 3180 | static int get_pict_type(const CodedBitstreamFragment *pu) | |
| 131 | { | ||
| 132 | 3180 | int has_p = 0; | |
| 133 |
2/2✓ Branch 0 taken 6516 times.
✓ Branch 1 taken 1432 times.
|
7948 | for (int i = 0; i < pu->nb_units; i++) { |
| 134 | 6516 | CodedBitstreamUnit *unit = &pu->units[i]; | |
| 135 |
5/6✓ Branch 0 taken 3701 times.
✓ Branch 1 taken 2815 times.
✓ Branch 2 taken 3701 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 603 times.
✓ Branch 5 taken 3098 times.
|
6516 | if (IS_H266_SLICE(unit->type)) { |
| 136 | 3418 | const H266RawSlice *slice = unit->content; | |
| 137 | 3418 | uint8_t type = slice->header.sh_slice_type; | |
| 138 |
2/2✓ Branch 0 taken 1748 times.
✓ Branch 1 taken 1670 times.
|
3418 | if (type == VVC_SLICE_TYPE_B) { |
| 139 | 1748 | return AV_PICTURE_TYPE_B; | |
| 140 | } | ||
| 141 |
2/2✓ Branch 0 taken 1068 times.
✓ Branch 1 taken 602 times.
|
1670 | if (type == VVC_SLICE_TYPE_P) { |
| 142 | 1068 | has_p = 1; | |
| 143 | } | ||
| 144 | } | ||
| 145 | } | ||
| 146 |
2/2✓ Branch 0 taken 1068 times.
✓ Branch 1 taken 364 times.
|
1432 | return has_p ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I; |
| 147 | } | ||
| 148 | |||
| 149 | 3135 | static void set_parser_ctx(AVCodecParserContext *s, AVCodecContext *avctx, | |
| 150 | const PuInfo *pu) | ||
| 151 | { | ||
| 152 | static const uint8_t h266_sub_width_c[] = { | ||
| 153 | 1, 2, 2, 1 | ||
| 154 | }; | ||
| 155 | static const uint8_t h266_sub_height_c[] = { | ||
| 156 | 1, 2, 1, 1 | ||
| 157 | }; | ||
| 158 | 3135 | const H266RawSPS *sps = pu->sps; | |
| 159 | 3135 | const H266RawPPS *pps = pu->pps; | |
| 160 | 3135 | const H266RawNALUnitHeader *nal = &pu->slice->header.nal_unit_header; | |
| 161 | |||
| 162 | 3135 | s->pict_type = pu->pic_type; | |
| 163 | 3135 | s->format = get_format(sps); | |
| 164 | 3135 | s->picture_structure = AV_PICTURE_STRUCTURE_FRAME; | |
| 165 | |||
| 166 | 9396 | s->key_frame = nal->nal_unit_type == VVC_IDR_W_RADL || | |
| 167 |
2/2✓ Branch 0 taken 2795 times.
✓ Branch 1 taken 331 times.
|
3126 | nal->nal_unit_type == VVC_IDR_N_LP || |
| 168 |
4/4✓ Branch 0 taken 3126 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 2776 times.
✓ Branch 3 taken 19 times.
|
9037 | nal->nal_unit_type == VVC_CRA_NUT || |
| 169 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2774 times.
|
2776 | nal->nal_unit_type == VVC_GDR_NUT; |
| 170 | |||
| 171 | 3135 | s->coded_width = pps->pps_pic_width_in_luma_samples; | |
| 172 | 3135 | s->coded_height = pps->pps_pic_height_in_luma_samples; | |
| 173 | 3135 | s->width = pps->pps_pic_width_in_luma_samples - | |
| 174 | 3135 | (pps->pps_conf_win_left_offset + pps->pps_conf_win_right_offset) * | |
| 175 | 3135 | h266_sub_width_c[sps->sps_chroma_format_idc]; | |
| 176 | 3135 | s->height = pps->pps_pic_height_in_luma_samples - | |
| 177 | 3135 | (pps->pps_conf_win_top_offset + pps->pps_conf_win_bottom_offset) * | |
| 178 | 3135 | h266_sub_height_c[sps->sps_chroma_format_idc]; | |
| 179 | |||
| 180 | 3135 | avctx->profile = sps->profile_tier_level.general_profile_idc; | |
| 181 | 3135 | avctx->level = sps->profile_tier_level.general_level_idc; | |
| 182 | |||
| 183 | 3135 | avctx->colorspace = (enum AVColorSpace) sps->vui.vui_matrix_coeffs; | |
| 184 | 3135 | avctx->color_primaries = (enum AVColorPrimaries) sps->vui.vui_colour_primaries; | |
| 185 | 3135 | avctx->color_trc = (enum AVColorTransferCharacteristic) sps->vui.vui_transfer_characteristics; | |
| 186 | 3135 | avctx->color_range = | |
| 187 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3135 times.
|
3135 | sps->vui.vui_full_range_flag ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; |
| 188 | |||
| 189 |
1/2✓ Branch 0 taken 3135 times.
✗ Branch 1 not taken.
|
3135 | if (sps->sps_ptl_dpb_hrd_params_present_flag && |
| 190 |
2/2✓ Branch 0 taken 120 times.
✓ Branch 1 taken 3015 times.
|
3135 | sps->sps_timing_hrd_params_present_flag) { |
| 191 | 120 | uint32_t num = sps->sps_general_timing_hrd_parameters.num_units_in_tick; | |
| 192 | 120 | uint32_t den = sps->sps_general_timing_hrd_parameters.time_scale; | |
| 193 | |||
| 194 |
2/4✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
|
120 | if (num != 0 && den != 0) |
| 195 | 120 | av_reduce(&avctx->framerate.den, &avctx->framerate.num, | |
| 196 | num, den, 1 << 30); | ||
| 197 | } | ||
| 198 | 3135 | } | |
| 199 | |||
| 200 | //8.3.1 Decoding process for picture order count. | ||
| 201 | //VTM did not follow the spec, and it's much simpler than spec. | ||
| 202 | //We follow the VTM. | ||
| 203 | 3180 | static void get_slice_poc(VVCParserContext *s, int *poc, | |
| 204 | const H266RawSPS *sps, | ||
| 205 | const H266RawPictureHeader *ph, | ||
| 206 | const H266RawSliceHeader *slice, void *log_ctx) | ||
| 207 | { | ||
| 208 | int poc_msb, max_poc_lsb, poc_lsb; | ||
| 209 | 3180 | AuDetector *d = &s->au_detector; | |
| 210 | 3180 | max_poc_lsb = 1 << (sps->sps_log2_max_pic_order_cnt_lsb_minus4 + 4); | |
| 211 | 3180 | poc_lsb = ph->ph_pic_order_cnt_lsb; | |
| 212 |
4/4✓ Branch 0 taken 3171 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 336 times.
✓ Branch 3 taken 2835 times.
|
3180 | if (IS_IDR(slice->nal_unit_header.nal_unit_type)) { |
| 213 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 345 times.
|
345 | if (ph->ph_poc_msb_cycle_present_flag) |
| 214 | ✗ | poc_msb = ph->ph_poc_msb_cycle_val * max_poc_lsb; | |
| 215 | else | ||
| 216 | 345 | poc_msb = 0; | |
| 217 | } else { | ||
| 218 | 2835 | int prev_poc = d->prev_tid0_poc; | |
| 219 | 2835 | int prev_poc_lsb = prev_poc & (max_poc_lsb - 1); | |
| 220 | 2835 | int prev_poc_msb = prev_poc - prev_poc_lsb; | |
| 221 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2835 times.
|
2835 | if (ph->ph_poc_msb_cycle_present_flag) { |
| 222 | ✗ | poc_msb = ph->ph_poc_msb_cycle_val * max_poc_lsb; | |
| 223 | } else { | ||
| 224 |
2/2✓ Branch 0 taken 1128 times.
✓ Branch 1 taken 1707 times.
|
2835 | if ((poc_lsb < prev_poc_lsb) && ((prev_poc_lsb - poc_lsb) >= |
| 225 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1124 times.
|
1128 | (max_poc_lsb / 2))) |
| 226 | 4 | poc_msb = prev_poc_msb + (unsigned)max_poc_lsb; | |
| 227 |
2/2✓ Branch 0 taken 1682 times.
✓ Branch 1 taken 1149 times.
|
2831 | else if ((poc_lsb > prev_poc_lsb) && ((poc_lsb - prev_poc_lsb) > |
| 228 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1682 times.
|
1682 | (max_poc_lsb / 2))) |
| 229 | ✗ | poc_msb = prev_poc_msb - (unsigned)max_poc_lsb; | |
| 230 | else | ||
| 231 | 2831 | poc_msb = prev_poc_msb; | |
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | 3180 | *poc = poc_msb + poc_lsb; | |
| 236 | 3180 | } | |
| 237 | |||
| 238 | 62 | static void au_detector_init(AuDetector *d) | |
| 239 | { | ||
| 240 | 62 | d->prev_layer_id = UINT8_MAX; | |
| 241 | 62 | d->prev_poc = INT_MAX; | |
| 242 | 62 | d->prev_tid0_poc = INT_MAX; | |
| 243 | 62 | } | |
| 244 | |||
| 245 | 3180 | static int is_au_start(VVCParserContext *s, const PuInfo *pu, void *log_ctx) | |
| 246 | { | ||
| 247 | //7.4.2.4.3 | ||
| 248 | 3180 | AuDetector *d = &s->au_detector; | |
| 249 | 3180 | const H266RawSPS *sps = pu->sps; | |
| 250 | 3180 | const H266RawNALUnitHeader *nal = &pu->slice->header.nal_unit_header; | |
| 251 | 3180 | const H266RawPictureHeader *ph = pu->ph; | |
| 252 | 3180 | const H266RawSlice *slice = pu->slice; | |
| 253 | int ret, poc, nut; | ||
| 254 | |||
| 255 | 3180 | get_slice_poc(s, &poc, sps, ph, &slice->header, log_ctx); | |
| 256 | |||
| 257 |
3/4✓ Branch 0 taken 45 times.
✓ Branch 1 taken 3135 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 45 times.
|
3180 | ret = (nal->nuh_layer_id <= d->prev_layer_id) || (poc != d->prev_poc); |
| 258 | |||
| 259 | 3180 | nut = nal->nal_unit_type; | |
| 260 | 3180 | d->prev_layer_id = nal->nuh_layer_id; | |
| 261 | 3180 | d->prev_poc = poc; | |
| 262 |
2/2✓ Branch 0 taken 1642 times.
✓ Branch 1 taken 1538 times.
|
3180 | if (nal->nuh_temporal_id_plus1 == 1 && |
| 263 |
3/4✓ Branch 0 taken 1630 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 1630 times.
✗ Branch 3 not taken.
|
1642 | !ph->ph_non_ref_pic_flag && nut != VVC_RADL_NUT |
| 264 |
1/2✓ Branch 0 taken 1630 times.
✗ Branch 1 not taken.
|
1630 | && nut != VVC_RASL_NUT) { |
| 265 | 1630 | d->prev_tid0_poc = poc; | |
| 266 | } | ||
| 267 | 3180 | return ret; | |
| 268 | } | ||
| 269 | |||
| 270 | 3180 | static int get_pu_info(PuInfo *info, const CodedBitstreamH266Context *h266, | |
| 271 | const CodedBitstreamFragment *pu, void *logctx) | ||
| 272 | { | ||
| 273 | const H266RawNALUnitHeader *nal; | ||
| 274 | int ret; | ||
| 275 | |||
| 276 | 3180 | memset(info, 0, sizeof(*info)); | |
| 277 |
1/2✓ Branch 0 taken 4847 times.
✗ Branch 1 not taken.
|
4847 | for (int i = 0; i < pu->nb_units; i++) { |
| 278 | 4847 | nal = pu->units[i].content; | |
| 279 |
2/2✓ Branch 0 taken 588 times.
✓ Branch 1 taken 4259 times.
|
4847 | if (!nal) |
| 280 | 588 | continue; | |
| 281 |
2/2✓ Branch 0 taken 106 times.
✓ Branch 1 taken 4153 times.
|
4259 | if ( nal->nal_unit_type == VVC_PH_NUT ) { |
| 282 | 106 | const H266RawPH *ph = pu->units[i].content; | |
| 283 | 106 | info->ph = &ph->ph_picture_header; | |
| 284 |
5/6✓ Branch 0 taken 1339 times.
✓ Branch 1 taken 2814 times.
✓ Branch 2 taken 1339 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 366 times.
✓ Branch 5 taken 973 times.
|
4153 | } else if (IS_H266_SLICE(nal->nal_unit_type)) { |
| 285 | 3180 | info->slice = pu->units[i].content; | |
| 286 |
2/2✓ Branch 0 taken 3074 times.
✓ Branch 1 taken 106 times.
|
3180 | if (info->slice->header.sh_picture_header_in_slice_header_flag) |
| 287 | 3074 | info->ph = &info->slice->header.sh_picture_header; | |
| 288 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3180 times.
|
3180 | if (!info->ph) { |
| 289 | ✗ | av_log(logctx, AV_LOG_ERROR, | |
| 290 | "can't find picture header in picture unit.\n"); | ||
| 291 | ✗ | ret = AVERROR_INVALIDDATA; | |
| 292 | ✗ | goto error; | |
| 293 | } | ||
| 294 | 3180 | break; | |
| 295 | } | ||
| 296 | } | ||
| 297 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3180 times.
|
3180 | if (!info->slice) { |
| 298 | ✗ | av_log(logctx, AV_LOG_ERROR, "can't find slice in picture unit.\n"); | |
| 299 | ✗ | ret = AVERROR_INVALIDDATA; | |
| 300 | ✗ | goto error; | |
| 301 | } | ||
| 302 | 3180 | info->pps = h266->pps[info->ph->ph_pic_parameter_set_id]; | |
| 303 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3180 times.
|
3180 | if (!info->pps) { |
| 304 | ✗ | av_log(logctx, AV_LOG_ERROR, "PPS id %d is not available.\n", | |
| 305 | ✗ | info->ph->ph_pic_parameter_set_id); | |
| 306 | ✗ | ret = AVERROR_INVALIDDATA; | |
| 307 | ✗ | goto error; | |
| 308 | } | ||
| 309 | 3180 | info->sps = h266->sps[info->pps->pps_seq_parameter_set_id]; | |
| 310 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3180 times.
|
3180 | if (!info->sps) { |
| 311 | ✗ | av_log(logctx, AV_LOG_ERROR, "SPS id %d is not available.\n", | |
| 312 | ✗ | info->pps->pps_seq_parameter_set_id); | |
| 313 | ✗ | ret = AVERROR_INVALIDDATA; | |
| 314 | ✗ | goto error; | |
| 315 | } | ||
| 316 | 3180 | info->pic_type = get_pict_type(pu); | |
| 317 | 3180 | return 0; | |
| 318 | ✗ | error: | |
| 319 | ✗ | memset(info, 0, sizeof(*info)); | |
| 320 | ✗ | return ret; | |
| 321 | } | ||
| 322 | |||
| 323 | 3180 | static int append_au(AVPacket *pkt, const uint8_t *buf, int buf_size) | |
| 324 | { | ||
| 325 | 3180 | int offset = pkt->size; | |
| 326 | int ret; | ||
| 327 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3180 times.
|
3180 | if ((ret = av_grow_packet(pkt, buf_size)) < 0) |
| 328 | ✗ | goto end; | |
| 329 | 3180 | memcpy(pkt->data + offset, buf, buf_size); | |
| 330 | 3180 | end: | |
| 331 | 3180 | return ret; | |
| 332 | } | ||
| 333 | |||
| 334 | /** | ||
| 335 | * Parse NAL units of found picture and decode some basic information. | ||
| 336 | * | ||
| 337 | * @param s parser context. | ||
| 338 | * @param avctx codec context. | ||
| 339 | * @param buf buffer with field/frame data. | ||
| 340 | * @param buf_size size of the buffer. | ||
| 341 | * @return < 0 for error, == 0 for a complete au, > 0 is not a completed au. | ||
| 342 | */ | ||
| 343 | 3184 | static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, | |
| 344 | int buf_size, AVCodecContext *avctx) | ||
| 345 | { | ||
| 346 | 3184 | VVCParserContext *ctx = s->priv_data; | |
| 347 | 3184 | const CodedBitstreamH266Context *h266 = ctx->cbc->priv_data; | |
| 348 | |||
| 349 | 3184 | CodedBitstreamFragment *pu = &ctx->picture_unit; | |
| 350 | int ret; | ||
| 351 | PuInfo info; | ||
| 352 | |||
| 353 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3180 times.
|
3184 | if (!buf_size) { |
| 354 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (ctx->au.size) { |
| 355 | 4 | av_packet_move_ref(&ctx->last_au, &ctx->au); | |
| 356 | 4 | return 0; | |
| 357 | } | ||
| 358 | ✗ | return 1; | |
| 359 | } | ||
| 360 | |||
| 361 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3180 times.
|
3180 | if ((ret = ff_cbs_read(ctx->cbc, pu, NULL, buf, buf_size)) < 0) { |
| 362 | ✗ | av_log(avctx, AV_LOG_ERROR, "Failed to parse picture unit.\n"); | |
| 363 | ✗ | goto end; | |
| 364 | } | ||
| 365 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3180 times.
|
3180 | if ((ret = get_pu_info(&info, h266, pu, avctx)) < 0) |
| 366 | ✗ | goto end; | |
| 367 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3180 times.
|
3180 | if (append_au(&ctx->au, buf, buf_size) < 0) { |
| 368 | ✗ | ret = AVERROR(ENOMEM); | |
| 369 | ✗ | goto end; | |
| 370 | } | ||
| 371 |
2/2✓ Branch 1 taken 3135 times.
✓ Branch 2 taken 45 times.
|
3180 | if (is_au_start(ctx, &info, avctx)) { |
| 372 | 3135 | set_parser_ctx(s, avctx, &info); | |
| 373 | 3135 | av_packet_move_ref(&ctx->last_au, &ctx->au); | |
| 374 | } else { | ||
| 375 | 45 | ret = 1; //not a completed au | |
| 376 | } | ||
| 377 | 3180 | end: | |
| 378 | 3180 | ff_cbs_fragment_reset(pu); | |
| 379 | 3180 | return ret; | |
| 380 | } | ||
| 381 | |||
| 382 | /** | ||
| 383 | * Combine PU to AU | ||
| 384 | * | ||
| 385 | * @param s parser context. | ||
| 386 | * @param avctx codec context. | ||
| 387 | * @param buf buffer to a PU. | ||
| 388 | * @param buf_size size of the buffer. | ||
| 389 | * @return < 0 for error, == 0 a complete au, > 0 not a completed au. | ||
| 390 | */ | ||
| 391 | 3184 | static int combine_au(AVCodecParserContext *s, AVCodecContext *avctx, | |
| 392 | const uint8_t **buf, int *buf_size) | ||
| 393 | { | ||
| 394 | 3184 | VVCParserContext *ctx = s->priv_data; | |
| 395 | int ret; | ||
| 396 | |||
| 397 | 3184 | ctx->cbc->log_ctx = avctx; | |
| 398 | |||
| 399 | 3184 | av_packet_unref(&ctx->last_au); | |
| 400 | 3184 | ret = parse_nal_units(s, *buf, *buf_size, avctx); | |
| 401 |
2/2✓ Branch 0 taken 3139 times.
✓ Branch 1 taken 45 times.
|
3184 | if (ret == 0) { |
| 402 |
1/2✓ Branch 0 taken 3139 times.
✗ Branch 1 not taken.
|
3139 | if (ctx->last_au.size) { |
| 403 | 3139 | *buf = ctx->last_au.data; | |
| 404 | 3139 | *buf_size = ctx->last_au.size; | |
| 405 | } else { | ||
| 406 | ✗ | ret = 1; //no output | |
| 407 | } | ||
| 408 | } | ||
| 409 | 3184 | ctx->cbc->log_ctx = NULL; | |
| 410 | 3184 | return ret; | |
| 411 | } | ||
| 412 | |||
| 413 | 11580 | static int vvc_parser_parse(AVCodecParserContext *s, AVCodecContext *avctx, | |
| 414 | const uint8_t **poutbuf, int *poutbuf_size, | ||
| 415 | const uint8_t *buf, int buf_size) | ||
| 416 | { | ||
| 417 | int next, ret; | ||
| 418 | 11580 | VVCParserContext *ctx = s->priv_data; | |
| 419 | 11580 | ParseContext *pc = &ctx->pc; | |
| 420 | 11580 | CodedBitstreamFragment *pu = &ctx->picture_unit; | |
| 421 | |||
| 422 | 11580 | int is_dummy_buf = !buf_size; | |
| 423 | 11580 | int flush = !buf_size; | |
| 424 | 11580 | const uint8_t *dummy_buf = buf; | |
| 425 | |||
| 426 | 11580 | *poutbuf = NULL; | |
| 427 | 11580 | *poutbuf_size = 0; | |
| 428 | |||
| 429 |
4/4✓ Branch 0 taken 9146 times.
✓ Branch 1 taken 2434 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 9086 times.
|
11580 | if (avctx->extradata_size && !ctx->parsed_extradata) { |
| 430 | 60 | ctx->parsed_extradata = 1; | |
| 431 | |||
| 432 | 60 | ret = ff_cbs_read_extradata_from_codec(ctx->cbc, pu, avctx); | |
| 433 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | if (ret < 0) |
| 434 | ✗ | av_log(avctx, AV_LOG_WARNING, "Failed to parse extradata.\n"); | |
| 435 | |||
| 436 | 60 | ff_cbs_fragment_reset(pu); | |
| 437 | } | ||
| 438 | |||
| 439 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11569 times.
|
11580 | if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { |
| 440 | 11 | next = buf_size; | |
| 441 | } else { | ||
| 442 | 11569 | next = find_frame_end(s, buf, buf_size); | |
| 443 |
2/2✓ Branch 1 taken 8339 times.
✓ Branch 2 taken 3230 times.
|
11569 | if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) |
| 444 | 8339 | return buf_size; | |
| 445 | } | ||
| 446 | |||
| 447 | 3241 | is_dummy_buf &= (dummy_buf == buf); | |
| 448 | |||
| 449 |
2/2✓ Branch 0 taken 3180 times.
✓ Branch 1 taken 61 times.
|
3241 | if (!is_dummy_buf) { |
| 450 | 3180 | ret = combine_au(s, avctx, &buf, &buf_size); | |
| 451 |
4/4✓ Branch 0 taken 45 times.
✓ Branch 1 taken 3135 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 41 times.
|
3180 | if (ret > 0 && flush) { |
| 452 | 4 | buf_size = 0; | |
| 453 | 4 | ret = combine_au(s, avctx, &buf, &buf_size); | |
| 454 | } | ||
| 455 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 3139 times.
|
3180 | if (ret != 0) |
| 456 | 41 | return next; | |
| 457 | } | ||
| 458 | |||
| 459 | 3200 | *poutbuf = buf; | |
| 460 | 3200 | *poutbuf_size = buf_size; | |
| 461 | |||
| 462 | 3200 | return next; | |
| 463 | } | ||
| 464 | |||
| 465 | static const CodedBitstreamUnitType decompose_unit_types[] = { | ||
| 466 | VVC_TRAIL_NUT, | ||
| 467 | VVC_STSA_NUT, | ||
| 468 | VVC_RADL_NUT, | ||
| 469 | VVC_RASL_NUT, | ||
| 470 | VVC_IDR_W_RADL, | ||
| 471 | VVC_IDR_N_LP, | ||
| 472 | VVC_CRA_NUT, | ||
| 473 | VVC_GDR_NUT, | ||
| 474 | VVC_VPS_NUT, | ||
| 475 | VVC_SPS_NUT, | ||
| 476 | VVC_PPS_NUT, | ||
| 477 | VVC_PH_NUT, | ||
| 478 | VVC_AUD_NUT, | ||
| 479 | }; | ||
| 480 | |||
| 481 | 62 | static av_cold int vvc_parser_init(AVCodecParserContext *s) | |
| 482 | { | ||
| 483 | 62 | VVCParserContext *ctx = s->priv_data; | |
| 484 | int ret; | ||
| 485 | |||
| 486 | 62 | ret = ff_cbs_init(&ctx->cbc, AV_CODEC_ID_VVC, NULL); | |
| 487 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
|
62 | if (ret < 0) |
| 488 | ✗ | return ret; | |
| 489 | 62 | au_detector_init(&ctx->au_detector); | |
| 490 | |||
| 491 | 62 | ctx->cbc->decompose_unit_types = decompose_unit_types; | |
| 492 | 62 | ctx->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types); | |
| 493 | |||
| 494 | 62 | return ret; | |
| 495 | } | ||
| 496 | |||
| 497 | 62 | static av_cold void vvc_parser_close(AVCodecParserContext *s) | |
| 498 | { | ||
| 499 | 62 | VVCParserContext *ctx = s->priv_data; | |
| 500 | |||
| 501 | 62 | av_packet_unref(&ctx->au); | |
| 502 | 62 | av_packet_unref(&ctx->last_au); | |
| 503 | 62 | ff_cbs_fragment_free(&ctx->picture_unit); | |
| 504 | |||
| 505 | 62 | ff_cbs_close(&ctx->cbc); | |
| 506 | 62 | av_freep(&ctx->pc.buffer); | |
| 507 | 62 | } | |
| 508 | |||
| 509 | const FFCodecParser ff_vvc_parser = { | ||
| 510 | PARSER_CODEC_LIST(AV_CODEC_ID_VVC), | ||
| 511 | .priv_data_size = sizeof(VVCParserContext), | ||
| 512 | .init = vvc_parser_init, | ||
| 513 | .close = vvc_parser_close, | ||
| 514 | .parse = vvc_parser_parse, | ||
| 515 | }; | ||
| 516 |