FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/vaapi_vvc.c
Date: 2026-09-28 04:46:15
Exec Total Coverage
Lines: 0 427 0.0%
Functions: 0 8 0.0%
Branches: 0 198 0.0%

Line Branch Exec Source
1 /*
2 * VVC HW decode acceleration through VA API
3 *
4 * Copyright (c) 2024 Intel Corporation
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 <va/va.h>
24 #include <va/va_dec_vvc.h>
25
26 #include "vvc/dec.h"
27 #include "vvc/refs.h"
28 #include "hwaccel_internal.h"
29 #include "vaapi_decode.h"
30
31 typedef struct VAAPIDecodePictureVVC {
32 VAAPIDecodePicture pic;
33 VAPictureParameterBufferVVC pic_param;
34 VASliceParameterBufferVVC slice_param;
35 int decode_issued;
36 } VAAPIDecodePictureVVC;
37
38 ✗ static void init_vaapi_pic(VAPictureVVC *va_pic)
39 {
40 ✗ va_pic->picture_id = VA_INVALID_ID;
41 ✗ va_pic->flags = VA_PICTURE_VVC_INVALID;
42 ✗ va_pic->pic_order_cnt = 0;
43 ✗ }
44
45 ✗ static void fill_vaapi_pic(VAPictureVVC *va_pic, const VVCFrame *pic)
46 {
47 ✗ va_pic->picture_id = ff_vaapi_get_surface_id(pic->frame);
48 ✗ va_pic->pic_order_cnt = pic->poc;
49 ✗ va_pic->flags = 0;
50
51 ✗ if (pic->flags & VVC_FRAME_FLAG_LONG_REF)
52 ✗ va_pic->flags |= VA_PICTURE_VVC_LONG_TERM_REFERENCE;
53 ✗ }
54
55 ✗ static void fill_vaapi_reference_frames(const VVCFrameContext *h, VAPictureParameterBufferVVC *pp)
56 {
57 ✗ const VVCFrame *current_picture = h->ref;
58 int i, j;
59
60 ✗ for (i = 0, j = 0; i < FF_ARRAY_ELEMS(pp->ReferenceFrames); i++) {
61 ✗ const VVCFrame *frame = NULL;
62
63 ✗ while (!frame && j < FF_ARRAY_ELEMS(h->DPB)) {
64 ✗ if ((&h->DPB[j] != current_picture ) &&
65 ✗ (h->DPB[j].flags & (VVC_FRAME_FLAG_LONG_REF | VVC_FRAME_FLAG_SHORT_REF)))
66 ✗ frame = &h->DPB[j];
67 ✗ j++;
68 }
69
70 ✗ init_vaapi_pic(&pp->ReferenceFrames[i]);
71
72 ✗ if (frame) {
73 VAAPIDecodePictureVVC *pic;
74 ✗ fill_vaapi_pic(&pp->ReferenceFrames[i], frame);
75 ✗ pic = frame->hwaccel_picture_private;
76 ✗ if (!pic->decode_issued)
77 ✗ pp->ReferenceFrames[i].flags |= VA_PICTURE_VVC_UNAVAILABLE_REFERENCE;
78 }
79 }
80 ✗ }
81
82 ✗ static int vaapi_vvc_start_frame(AVCodecContext *avctx,
83 av_unused const AVBufferRef *buffer_ref,
84 av_unused const uint8_t *buffer,
85 av_unused uint32_t size)
86 {
87 ✗ const VVCContext *h = avctx->priv_data;
88 ✗ VVCFrameContext *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs];
89 ✗ const H266RawSPS *sps = fc->ps.sps->r;
90 ✗ const H266RawPPS *pps = fc->ps.pps->r;
91 ✗ const H266RawPictureHeader *ph = fc->ps.ph.r;
92 ✗ VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private;
93 ✗ VAPictureParameterBufferVVC *pic_param = &pic->pic_param;
94 ✗ uint16_t tile_dim, exp_slice_height_in_ctus[VVC_MAX_SLICES] = {0};
95 int i, j, k, err;
96
97 ✗ pic->pic.output_surface = ff_vaapi_get_surface_id(fc->ref->frame);
98
99 ✗ *pic_param = (VAPictureParameterBufferVVC) {
100 ✗ .pps_pic_width_in_luma_samples = pps->pps_pic_width_in_luma_samples,
101 ✗ .pps_pic_height_in_luma_samples = pps->pps_pic_height_in_luma_samples,
102 ✗ .sps_num_subpics_minus1 = sps->sps_num_subpics_minus1,
103 ✗ .sps_chroma_format_idc = sps->sps_chroma_format_idc,
104 ✗ .sps_bitdepth_minus8 = sps->sps_bitdepth_minus8,
105 ✗ .sps_log2_ctu_size_minus5 = sps->sps_log2_ctu_size_minus5,
106 ✗ .sps_log2_min_luma_coding_block_size_minus2 = sps->sps_log2_min_luma_coding_block_size_minus2,
107 ✗ .sps_log2_transform_skip_max_size_minus2 = sps->sps_log2_transform_skip_max_size_minus2,
108 ✗ .sps_six_minus_max_num_merge_cand = sps->sps_six_minus_max_num_merge_cand,
109 ✗ .sps_five_minus_max_num_subblock_merge_cand = sps->sps_five_minus_max_num_subblock_merge_cand,
110 ✗ .sps_max_num_merge_cand_minus_max_num_gpm_cand = sps->sps_max_num_merge_cand_minus_max_num_gpm_cand,
111 ✗ .sps_log2_parallel_merge_level_minus2 = sps->sps_log2_parallel_merge_level_minus2,
112 ✗ .sps_min_qp_prime_ts = sps->sps_min_qp_prime_ts,
113 ✗ .sps_six_minus_max_num_ibc_merge_cand = sps->sps_six_minus_max_num_ibc_merge_cand,
114 ✗ .sps_num_ladf_intervals_minus2 = sps->sps_num_ladf_intervals_minus2,
115 ✗ .sps_ladf_lowest_interval_qp_offset = sps->sps_ladf_lowest_interval_qp_offset,
116 .sps_flags.bits = {
117 ✗ .sps_subpic_info_present_flag = sps->sps_subpic_info_present_flag,
118 ✗ .sps_independent_subpics_flag = sps->sps_independent_subpics_flag,
119 ✗ .sps_subpic_same_size_flag = sps->sps_subpic_same_size_flag,
120 ✗ .sps_entropy_coding_sync_enabled_flag = sps->sps_entropy_coding_sync_enabled_flag,
121 ✗ .sps_qtbtt_dual_tree_intra_flag = sps->sps_qtbtt_dual_tree_intra_flag,
122 ✗ .sps_max_luma_transform_size_64_flag = sps->sps_max_luma_transform_size_64_flag,
123 ✗ .sps_transform_skip_enabled_flag = sps->sps_transform_skip_enabled_flag,
124 ✗ .sps_bdpcm_enabled_flag = sps->sps_bdpcm_enabled_flag,
125 ✗ .sps_mts_enabled_flag = sps->sps_mts_enabled_flag,
126 ✗ .sps_explicit_mts_intra_enabled_flag = sps->sps_explicit_mts_intra_enabled_flag,
127 ✗ .sps_explicit_mts_inter_enabled_flag = sps->sps_explicit_mts_inter_enabled_flag,
128 ✗ .sps_lfnst_enabled_flag = sps->sps_lfnst_enabled_flag,
129 ✗ .sps_joint_cbcr_enabled_flag = sps->sps_joint_cbcr_enabled_flag,
130 ✗ .sps_same_qp_table_for_chroma_flag = sps->sps_same_qp_table_for_chroma_flag,
131 ✗ .sps_sao_enabled_flag = sps->sps_sao_enabled_flag,
132 ✗ .sps_alf_enabled_flag = sps->sps_alf_enabled_flag,
133 ✗ .sps_ccalf_enabled_flag = sps->sps_ccalf_enabled_flag,
134 ✗ .sps_lmcs_enabled_flag = sps->sps_lmcs_enabled_flag,
135 ✗ .sps_sbtmvp_enabled_flag = sps->sps_sbtmvp_enabled_flag,
136 ✗ .sps_amvr_enabled_flag = sps->sps_amvr_enabled_flag,
137 ✗ .sps_smvd_enabled_flag = sps->sps_smvd_enabled_flag,
138 ✗ .sps_mmvd_enabled_flag = sps->sps_mmvd_enabled_flag,
139 ✗ .sps_sbt_enabled_flag = sps->sps_sbt_enabled_flag,
140 ✗ .sps_affine_enabled_flag = sps->sps_affine_enabled_flag,
141 ✗ .sps_6param_affine_enabled_flag = sps->sps_6param_affine_enabled_flag,
142 ✗ .sps_affine_amvr_enabled_flag = sps->sps_affine_amvr_enabled_flag,
143 ✗ .sps_affine_prof_enabled_flag = sps->sps_affine_prof_enabled_flag,
144 ✗ .sps_bcw_enabled_flag = sps->sps_bcw_enabled_flag,
145 ✗ .sps_ciip_enabled_flag = sps->sps_ciip_enabled_flag,
146 ✗ .sps_gpm_enabled_flag = sps->sps_gpm_enabled_flag,
147 ✗ .sps_isp_enabled_flag = sps->sps_isp_enabled_flag,
148 ✗ .sps_mrl_enabled_flag = sps->sps_mrl_enabled_flag,
149 ✗ .sps_mip_enabled_flag = sps->sps_mip_enabled_flag,
150 ✗ .sps_cclm_enabled_flag = sps->sps_cclm_enabled_flag,
151 ✗ .sps_chroma_horizontal_collocated_flag = sps->sps_chroma_horizontal_collocated_flag,
152 ✗ .sps_chroma_vertical_collocated_flag = sps->sps_chroma_vertical_collocated_flag,
153 ✗ .sps_palette_enabled_flag = sps->sps_palette_enabled_flag,
154 ✗ .sps_act_enabled_flag = sps->sps_act_enabled_flag,
155 ✗ .sps_ibc_enabled_flag = sps->sps_ibc_enabled_flag,
156 ✗ .sps_ladf_enabled_flag = sps->sps_ladf_enabled_flag,
157 ✗ .sps_explicit_scaling_list_enabled_flag = sps->sps_explicit_scaling_list_enabled_flag,
158 ✗ .sps_scaling_matrix_for_lfnst_disabled_flag = sps->sps_scaling_matrix_for_lfnst_disabled_flag,
159 ✗ .sps_scaling_matrix_for_alternative_colour_space_disabled_flag = sps->sps_scaling_matrix_for_alternative_colour_space_disabled_flag,
160 ✗ .sps_scaling_matrix_designated_colour_space_flag = sps->sps_scaling_matrix_designated_colour_space_flag,
161 ✗ .sps_virtual_boundaries_enabled_flag = sps->sps_virtual_boundaries_enabled_flag,
162 ✗ .sps_virtual_boundaries_present_flag = sps->sps_virtual_boundaries_present_flag,
163 },
164 ✗ .NumVerVirtualBoundaries = sps->sps_virtual_boundaries_present_flag ?
165 sps->sps_num_ver_virtual_boundaries :
166 ph->ph_num_ver_virtual_boundaries,
167 ✗ .NumHorVirtualBoundaries = sps->sps_virtual_boundaries_present_flag ?
168 sps->sps_num_hor_virtual_boundaries :
169 ph->ph_num_hor_virtual_boundaries,
170 ✗ .pps_scaling_win_left_offset = pps->pps_scaling_win_left_offset,
171 ✗ .pps_scaling_win_right_offset = pps->pps_scaling_win_right_offset,
172 ✗ .pps_scaling_win_top_offset = pps->pps_scaling_win_top_offset,
173 ✗ .pps_scaling_win_bottom_offset = pps->pps_scaling_win_bottom_offset,
174 ✗ .pps_num_exp_tile_columns_minus1 = pps->pps_num_exp_tile_columns_minus1,
175 ✗ .pps_num_exp_tile_rows_minus1 = pps->pps_num_exp_tile_rows_minus1,
176 ✗ .pps_num_slices_in_pic_minus1 = pps->pps_num_slices_in_pic_minus1,
177 ✗ .pps_pic_width_minus_wraparound_offset = pps->pps_pic_width_minus_wraparound_offset,
178 ✗ .pps_cb_qp_offset = pps->pps_cb_qp_offset,
179 ✗ .pps_cr_qp_offset = pps->pps_cr_qp_offset,
180 ✗ .pps_joint_cbcr_qp_offset_value = pps->pps_joint_cbcr_qp_offset_value,
181 ✗ .pps_chroma_qp_offset_list_len_minus1 = pps->pps_chroma_qp_offset_list_len_minus1,
182 .pps_flags.bits = {
183 ✗ .pps_loop_filter_across_tiles_enabled_flag = pps->pps_loop_filter_across_tiles_enabled_flag,
184 ✗ .pps_rect_slice_flag = pps->pps_rect_slice_flag,
185 ✗ .pps_single_slice_per_subpic_flag = pps->pps_single_slice_per_subpic_flag,
186 ✗ .pps_loop_filter_across_slices_enabled_flag = pps->pps_loop_filter_across_slices_enabled_flag,
187 ✗ .pps_weighted_pred_flag = pps->pps_weighted_pred_flag,
188 ✗ .pps_weighted_bipred_flag = pps->pps_weighted_bipred_flag,
189 ✗ .pps_ref_wraparound_enabled_flag = pps->pps_ref_wraparound_enabled_flag,
190 ✗ .pps_cu_qp_delta_enabled_flag = pps->pps_cu_qp_delta_enabled_flag,
191 ✗ .pps_cu_chroma_qp_offset_list_enabled_flag = pps->pps_cu_chroma_qp_offset_list_enabled_flag,
192 ✗ .pps_deblocking_filter_override_enabled_flag = pps->pps_deblocking_filter_override_enabled_flag,
193 ✗ .pps_deblocking_filter_disabled_flag = pps->pps_deblocking_filter_disabled_flag,
194 ✗ .pps_dbf_info_in_ph_flag = pps->pps_dbf_info_in_ph_flag,
195 ✗ .pps_sao_info_in_ph_flag = pps->pps_sao_info_in_ph_flag,
196 ✗ .pps_alf_info_in_ph_flag = pps->pps_alf_info_in_ph_flag,
197 },
198 ✗ .ph_lmcs_aps_id = ph->ph_lmcs_aps_id,
199 ✗ .ph_scaling_list_aps_id = ph->ph_scaling_list_aps_id,
200 ✗ .ph_log2_diff_min_qt_min_cb_intra_slice_luma = ph->ph_log2_diff_min_qt_min_cb_intra_slice_luma,
201 ✗ .ph_max_mtt_hierarchy_depth_intra_slice_luma = ph->ph_max_mtt_hierarchy_depth_intra_slice_luma,
202 ✗ .ph_log2_diff_max_bt_min_qt_intra_slice_luma = ph->ph_log2_diff_max_bt_min_qt_intra_slice_luma,
203 ✗ .ph_log2_diff_max_tt_min_qt_intra_slice_luma = ph->ph_log2_diff_max_tt_min_qt_intra_slice_luma,
204 ✗ .ph_log2_diff_min_qt_min_cb_intra_slice_chroma = ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma,
205 ✗ .ph_max_mtt_hierarchy_depth_intra_slice_chroma = ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma,
206 ✗ .ph_log2_diff_max_bt_min_qt_intra_slice_chroma = ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma,
207 ✗ .ph_log2_diff_max_tt_min_qt_intra_slice_chroma = ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma,
208 ✗ .ph_cu_qp_delta_subdiv_intra_slice = ph->ph_cu_qp_delta_subdiv_intra_slice,
209 ✗ .ph_cu_chroma_qp_offset_subdiv_intra_slice = ph->ph_cu_chroma_qp_offset_subdiv_intra_slice,
210 ✗ .ph_log2_diff_min_qt_min_cb_inter_slice = ph->ph_log2_diff_min_qt_min_cb_inter_slice,
211 ✗ .ph_max_mtt_hierarchy_depth_inter_slice = ph->ph_max_mtt_hierarchy_depth_inter_slice,
212 ✗ .ph_log2_diff_max_bt_min_qt_inter_slice = ph->ph_log2_diff_max_bt_min_qt_inter_slice,
213 ✗ .ph_log2_diff_max_tt_min_qt_inter_slice = ph->ph_log2_diff_max_tt_min_qt_inter_slice,
214 ✗ .ph_cu_qp_delta_subdiv_inter_slice = ph->ph_cu_qp_delta_subdiv_inter_slice,
215 ✗ .ph_cu_chroma_qp_offset_subdiv_inter_slice = ph->ph_cu_chroma_qp_offset_subdiv_inter_slice,
216 .ph_flags.bits= {
217 ✗ .ph_non_ref_pic_flag = ph->ph_non_ref_pic_flag,
218 ✗ .ph_alf_enabled_flag = ph->ph_alf_enabled_flag,
219 ✗ .ph_alf_cb_enabled_flag = ph->ph_alf_cb_enabled_flag,
220 ✗ .ph_alf_cr_enabled_flag = ph->ph_alf_cr_enabled_flag,
221 ✗ .ph_alf_cc_cb_enabled_flag = ph->ph_alf_cc_cb_enabled_flag,
222 ✗ .ph_alf_cc_cr_enabled_flag = ph->ph_alf_cc_cr_enabled_flag,
223 ✗ .ph_lmcs_enabled_flag = ph->ph_lmcs_enabled_flag,
224 ✗ .ph_chroma_residual_scale_flag = ph->ph_chroma_residual_scale_flag,
225 ✗ .ph_explicit_scaling_list_enabled_flag = ph->ph_explicit_scaling_list_enabled_flag,
226 ✗ .ph_virtual_boundaries_present_flag = ph->ph_virtual_boundaries_present_flag,
227 ✗ .ph_temporal_mvp_enabled_flag = ph->ph_temporal_mvp_enabled_flag,
228 ✗ .ph_mmvd_fullpel_only_flag = ph->ph_mmvd_fullpel_only_flag,
229 ✗ .ph_mvd_l1_zero_flag = ph->ph_mvd_l1_zero_flag,
230 ✗ .ph_bdof_disabled_flag = ph->ph_bdof_disabled_flag,
231 ✗ .ph_dmvr_disabled_flag = ph->ph_dmvr_disabled_flag,
232 ✗ .ph_prof_disabled_flag = ph->ph_prof_disabled_flag,
233 ✗ .ph_joint_cbcr_sign_flag = ph->ph_joint_cbcr_sign_flag,
234 ✗ .ph_sao_luma_enabled_flag = ph->ph_sao_luma_enabled_flag,
235 ✗ .ph_sao_chroma_enabled_flag = ph->ph_sao_chroma_enabled_flag,
236 ✗ .ph_deblocking_filter_disabled_flag = ph->ph_deblocking_filter_disabled_flag,
237 },
238 .PicMiscFlags.fields = {
239 ✗ .IntraPicFlag = pps->pps_mixed_nalu_types_in_pic_flag ? 0 : IS_IRAP(h) ? 1 : 0,
240 }
241 };
242
243 ✗ fill_vaapi_pic(&pic_param->CurrPic, fc->ref);
244 ✗ fill_vaapi_reference_frames(fc, pic_param);
245
246 ✗ for (i = 0; i < VVC_MAX_SAMPLE_ARRAYS; i++)
247 ✗ for (j = 0; j < VVC_MAX_POINTS_IN_QP_TABLE; j++)
248 ✗ pic_param->ChromaQpTable[i][j] = fc->ps.sps->chroma_qp_table[i][j];
249 ✗ for (i = 0; i < 4; i++) {
250 ✗ pic_param->sps_ladf_qp_offset[i] = sps->sps_ladf_qp_offset[i];
251 ✗ pic_param->sps_ladf_delta_threshold_minus1[i] = sps->sps_ladf_delta_threshold_minus1[i];
252 }
253
254 ✗ for (i = 0; i < (sps->sps_virtual_boundaries_present_flag ? sps->sps_num_ver_virtual_boundaries : ph->ph_num_ver_virtual_boundaries); i++) {
255 ✗ pic_param->VirtualBoundaryPosX[i] = (sps->sps_virtual_boundaries_present_flag ?
256 ✗ (sps->sps_virtual_boundary_pos_x_minus1[i] + 1) :
257 ✗ (ph->ph_virtual_boundary_pos_x_minus1[i] + 1)) * 8;
258 }
259
260 ✗ for (i = 0; i < (sps->sps_virtual_boundaries_present_flag ? sps->sps_num_hor_virtual_boundaries : ph->ph_num_hor_virtual_boundaries); i++) {
261 ✗ pic_param->VirtualBoundaryPosY[i] = (sps->sps_virtual_boundaries_present_flag ?
262 ✗ (sps->sps_virtual_boundary_pos_y_minus1[i] + 1) :
263 ✗ (ph->ph_virtual_boundary_pos_y_minus1[i] + 1)) * 8;
264 }
265
266 ✗ for (i = 0; i < 6; i++) {
267 ✗ pic_param->pps_cb_qp_offset_list[i] = pps->pps_cb_qp_offset_list[i];
268 ✗ pic_param->pps_cr_qp_offset_list[i] = pps->pps_cr_qp_offset_list[i];
269 ✗ pic_param->pps_joint_cbcr_qp_offset_list[i] = pps->pps_joint_cbcr_qp_offset_list[i];
270 }
271
272 ✗ err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
273 VAPictureParameterBufferType,
274 ✗ &pic->pic_param, sizeof(VAPictureParameterBufferVVC));
275 ✗ if (err < 0)
276 ✗ goto fail;
277
278 ✗ for (i = 0; i <= sps->sps_num_subpics_minus1 && sps->sps_subpic_info_present_flag; i++) {
279 ✗ VASubPicVVC subpic_param = {
280 ✗ .sps_subpic_ctu_top_left_x = sps->sps_subpic_ctu_top_left_x[i],
281 ✗ .sps_subpic_ctu_top_left_y = sps->sps_subpic_ctu_top_left_y[i],
282 ✗ .sps_subpic_width_minus1 = sps->sps_subpic_width_minus1[i],
283 ✗ .sps_subpic_height_minus1 = sps->sps_subpic_height_minus1[i],
284 ✗ .SubpicIdVal = pps->sub_pic_id_val[i],
285 .subpic_flags.bits = {
286 ✗ .sps_subpic_treated_as_pic_flag = sps->sps_subpic_treated_as_pic_flag[i],
287 ✗ .sps_loop_filter_across_subpic_enabled_flag = sps->sps_loop_filter_across_subpic_enabled_flag[i],
288 }
289 };
290 ✗ err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
291 VASubPicBufferType,
292 &subpic_param, sizeof(VASubPicVVC));
293 ✗ if (err < 0)
294 ✗ goto fail;
295 }
296
297 ✗ for (i = 0; i < VVC_MAX_ALF_COUNT; i++) {
298 ✗ const VVCALF *alf_list = h->ps.alf_list[i];
299 ✗ if (alf_list) {
300 ✗ const H266RawAPS *alf = alf_list->r;
301 ✗ VAAlfDataVVC alf_param = {
302 .aps_adaptation_parameter_set_id = i,
303 ✗ .alf_luma_num_filters_signalled_minus1 = alf->alf_luma_num_filters_signalled_minus1,
304 ✗ .alf_chroma_num_alt_filters_minus1 = alf->alf_chroma_num_alt_filters_minus1,
305 ✗ .alf_cc_cb_filters_signalled_minus1 = alf->alf_cc_cb_filters_signalled_minus1,
306 ✗ .alf_cc_cr_filters_signalled_minus1 = alf->alf_cc_cr_filters_signalled_minus1,
307 .alf_flags.bits = {
308 ✗ .alf_luma_filter_signal_flag = alf->alf_luma_filter_signal_flag,
309 ✗ .alf_chroma_filter_signal_flag = alf->alf_chroma_filter_signal_flag,
310 ✗ .alf_cc_cb_filter_signal_flag = alf->alf_cc_cb_filter_signal_flag,
311 ✗ .alf_cc_cr_filter_signal_flag = alf->alf_cc_cr_filter_signal_flag,
312 ✗ .alf_luma_clip_flag = alf->alf_luma_clip_flag,
313 ✗ .alf_chroma_clip_flag = alf->alf_chroma_clip_flag,
314 }
315 };
316
317 ✗ for (j = 0; j < 25; j++)
318 ✗ alf_param.alf_luma_coeff_delta_idx[j] = alf->alf_luma_coeff_delta_idx[j];
319
320 ✗ for (j = 0; j < 25; j++) {
321 ✗ for (k = 0; k < 12; k++) {
322 ✗ alf_param.filtCoeff[j][k] = alf->alf_luma_coeff_abs[j][k] * (1 - 2 * alf->alf_luma_coeff_sign[j][k]);
323 ✗ alf_param.alf_luma_clip_idx[j][k] = alf->alf_luma_clip_idx[j][k];
324 }
325 }
326
327 ✗ for (j = 0; j < 8; j++) {
328 ✗ for (k = 0; k < 6; k++) {
329 ✗ alf_param.AlfCoeffC[j][k] = alf->alf_chroma_coeff_abs[j][k] * (1 - 2 * alf->alf_chroma_coeff_sign[j][k]);
330 ✗ alf_param.alf_chroma_clip_idx[j][k] = alf->alf_chroma_clip_idx[j][k];
331 }
332 }
333
334 ✗ for (j = 0; j < 4; j++) {
335 ✗ for (k = 0; k < 7; k++) {
336 ✗ if (alf->alf_cc_cb_mapped_coeff_abs[j][k])
337 ✗ alf_param.CcAlfApsCoeffCb[j][k] = (1 - 2 * alf->alf_cc_cb_coeff_sign[j][k]) * (1 << (alf->alf_cc_cb_mapped_coeff_abs[j][k] - 1));
338 ✗ if (alf->alf_cc_cr_mapped_coeff_abs[j][k])
339 ✗ alf_param.CcAlfApsCoeffCr[j][k] = (1 - 2 * alf->alf_cc_cr_coeff_sign[j][k]) * (1 << (alf->alf_cc_cr_mapped_coeff_abs[j][k] - 1));
340 }
341 }
342
343 ✗ err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
344 VAAlfBufferType,
345 &alf_param, sizeof(VAAlfDataVVC));
346 ✗ if (err < 0)
347 ✗ goto fail;
348 }
349 }
350
351 ✗ for (i = 0; i < VVC_MAX_LMCS_COUNT; i++) {
352 ✗ const H266RawAPS *lmcs = h->ps.lmcs_list[i];
353 ✗ if (lmcs) {
354 ✗ VALmcsDataVVC lmcs_param = {
355 .aps_adaptation_parameter_set_id = i,
356 ✗ .lmcs_min_bin_idx = lmcs->lmcs_min_bin_idx,
357 ✗ .lmcs_delta_max_bin_idx = lmcs->lmcs_delta_max_bin_idx,
358 ✗ .lmcsDeltaCrs = (1 - 2 * lmcs->lmcs_delta_sign_crs_flag) * lmcs->lmcs_delta_abs_crs,
359 };
360
361 ✗ for (j = lmcs->lmcs_min_bin_idx; j <= 15 - lmcs->lmcs_delta_max_bin_idx; j++)
362 ✗ lmcs_param.lmcsDeltaCW[j] = (1 - 2 * lmcs->lmcs_delta_sign_cw_flag[j]) * lmcs->lmcs_delta_abs_cw[j];
363
364 ✗ err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
365 VALmcsBufferType,
366 &lmcs_param, sizeof(VALmcsDataVVC));
367 ✗ if (err < 0)
368 ✗ goto fail;
369 }
370 }
371
372 ✗ for (i = 0; i < VVC_MAX_SL_COUNT; i++) {
373 ✗ const VVCScalingList *sl = h->ps.scaling_list[i];
374 ✗ if (sl) {
375 int l;
376
377 ✗ VAScalingListVVC sl_param = {
378 .aps_adaptation_parameter_set_id = i,
379 };
380
381 ✗ for (j = 0; j < 14; j++)
382 ✗ sl_param.ScalingMatrixDCRec[j] = sl->scaling_matrix_dc_rec[j];
383
384 ✗ for (j = 0; j < 2; j++)
385 ✗ for (k = 0; k < 2; k++)
386 ✗ for (l = 0; l < 2; l++)
387 ✗ sl_param.ScalingMatrixRec2x2[j][k][l] = sl->scaling_matrix_rec[j][l * 2 + k];
388
389 ✗ for (j = 2; j < 8; j++)
390 ✗ for (k = 0; k < 4; k++)
391 ✗ for (l = 0; l < 4; l++)
392 ✗ sl_param.ScalingMatrixRec4x4[j - 2][k][l] = sl->scaling_matrix_rec[j][l * 4 + k];
393
394 ✗ for (j = 8; j < 28; j++)
395 ✗ for (k = 0; k < 8; k++)
396 ✗ for (l = 0; l < 8; l++)
397 ✗ sl_param.ScalingMatrixRec8x8[j - 8][k][l] = sl->scaling_matrix_rec[j][l * 8 + k];
398
399 ✗ err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
400 VAIQMatrixBufferType,
401 &sl_param, sizeof(VAScalingListVVC));
402 ✗ if (err < 0)
403 ✗ goto fail;
404 }
405 }
406
407 ✗ for (i = 0; i <= pps->pps_num_exp_tile_columns_minus1; i++) {
408 ✗ tile_dim = pps->pps_tile_column_width_minus1[i];
409 ✗ err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
410 VATileBufferType,
411 &tile_dim, sizeof(tile_dim));
412 ✗ if (err < 0)
413 ✗ goto fail;
414 }
415
416 ✗ for (i = 0; i <= pps->pps_num_exp_tile_rows_minus1; i++) {
417 ✗ tile_dim = pps->pps_tile_row_height_minus1[i];
418 ✗ err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
419 VATileBufferType,
420 &tile_dim, sizeof(tile_dim));
421 ✗ if (err < 0)
422 ✗ goto fail;
423 }
424
425 ✗ if (!pps->pps_no_pic_partition_flag && pps->pps_rect_slice_flag && !pps->pps_single_slice_per_subpic_flag) {
426 ✗ for (i = 0; i <= pps->pps_num_slices_in_pic_minus1; i++) {
427 ✗ for (j = 0; j < pps->pps_num_exp_slices_in_tile[i]; j++) {
428 ✗ exp_slice_height_in_ctus[i + j] = pps->pps_exp_slice_height_in_ctus_minus1[i][j] + 1;
429 }
430 }
431 ✗ for (i = 0; i <= pps->pps_num_slices_in_pic_minus1; i++) {
432 ✗ VASliceStructVVC ss_param = {
433 ✗ .SliceTopLeftTileIdx = pps->slice_top_left_tile_idx[i],
434 ✗ .pps_slice_width_in_tiles_minus1 = pps->pps_slice_width_in_tiles_minus1[i],
435 ✗ .pps_slice_height_in_tiles_minus1 = pps->pps_slice_height_in_tiles_minus1[i],
436 };
437
438 ✗ if (pps->pps_slice_width_in_tiles_minus1[i] > 0 || pps->pps_slice_height_in_tiles_minus1[i] > 0)
439 ✗ ss_param.pps_exp_slice_height_in_ctus_minus1 = 0;
440 else {
441 ✗ if (pps->num_slices_in_tile[i] == 1)
442 ✗ ss_param.pps_exp_slice_height_in_ctus_minus1 = pps->row_height_val[pps->slice_top_left_tile_idx[i] / pps->num_tile_columns] - 1;
443 ✗ else if (exp_slice_height_in_ctus[i])
444 ✗ ss_param.pps_exp_slice_height_in_ctus_minus1 = exp_slice_height_in_ctus[i] - 1;
445 else
446 ✗ continue;
447 }
448
449 ✗ err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
450 VASliceStructBufferType,
451 &ss_param, sizeof(VASliceStructVVC));
452 ✗ if (err < 0)
453 ✗ goto fail;
454 }
455 }
456
457 ✗ return 0;
458
459 ✗ fail:
460 ✗ ff_vaapi_decode_cancel(avctx, &pic->pic);
461 ✗ return err;
462 }
463
464 ✗ static uint8_t get_ref_pic_index(const VVCContext *h, const VVCFrame *frame)
465 {
466 ✗ VVCFrameContext *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs];
467 ✗ VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private;
468 ✗ VAPictureParameterBufferVVC *pp = (VAPictureParameterBufferVVC *)&pic->pic_param;
469 uint8_t i;
470
471 ✗ if (!frame)
472 ✗ return 0xFF;
473
474 ✗ for (i = 0; i < FF_ARRAY_ELEMS(pp->ReferenceFrames); i++) {
475 ✗ VASurfaceID pid = pp->ReferenceFrames[i].picture_id;
476 ✗ int poc = pp->ReferenceFrames[i].pic_order_cnt;
477 ✗ if (pid != VA_INVALID_ID && pid == ff_vaapi_get_surface_id(frame->frame) && poc == frame->poc)
478 ✗ return i;
479 }
480
481 ✗ return 0xFF;
482 }
483
484 ✗ static int get_slice_data_byte_offset(const uint8_t *buffer, uint32_t size, const SliceContext* sc)
485 {
486 ✗ const H266RawSlice *slice = sc->ref;
487 ✗ int num_identical_bytes = slice->data_size < 32 ? slice->data_size : 32;
488
489 ✗ for (int i = 0; i < size; i++) {
490 ✗ int skip_bytes = 0;
491 ✗ if (i >=2 && buffer[i] == 0x03 && !buffer[i - 1] && !buffer[i - 2])
492 ✗ continue;
493
494 ✗ for (int j = 0; j < num_identical_bytes; j++) {
495 ✗ if (i >= 2 && buffer[i + j + skip_bytes] == 0x03 && !buffer[i + j + skip_bytes - 1] && !buffer[i + j + skip_bytes - 2])
496 ✗ skip_bytes++;
497
498 ✗ if (buffer[i + j + skip_bytes] != slice->data[j])
499 ✗ break;
500
501 ✗ if (j + 1 == num_identical_bytes)
502 ✗ return i;
503 }
504 }
505
506 ✗ return 0;
507 }
508
509 ✗ static int vaapi_vvc_decode_slice(AVCodecContext *avctx,
510 const uint8_t *buffer,
511 uint32_t size)
512 {
513 ✗ const VVCContext *h = avctx->priv_data;
514 ✗ VVCFrameContext *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs];
515 ✗ const SliceContext *sc = fc->slices[fc->nb_slices];
516 ✗ const H266RawPPS *pps = fc->ps.pps->r;
517 ✗ const H266RawPictureHeader *ph = fc->ps.ph.r;
518 ✗ const H266RawSliceHeader *sh = sc->sh.r;
519 ✗ VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private;
520 ✗ VASliceParameterBufferVVC *slice_param = &pic->slice_param;
521 int nb_list, i, err;
522
523 ✗ *slice_param = (VASliceParameterBufferVVC) {
524 .slice_data_size = size,
525 .slice_data_offset = 0,
526 .slice_data_flag = VA_SLICE_DATA_FLAG_ALL,
527 ✗ .slice_data_byte_offset = get_slice_data_byte_offset(buffer, size, sc),
528 ✗ .sh_subpic_id = sh->sh_subpic_id,
529 ✗ .sh_slice_address = sh->sh_slice_address,
530 ✗ .sh_num_tiles_in_slice_minus1 = sh->sh_num_tiles_in_slice_minus1,
531 ✗ .sh_slice_type = sh->sh_slice_type,
532 ✗ .sh_num_alf_aps_ids_luma = sh->sh_num_alf_aps_ids_luma,
533 ✗ .sh_alf_aps_id_chroma = sh->sh_alf_aps_id_chroma,
534 ✗ .sh_alf_cc_cb_aps_id = sh->sh_alf_cc_cb_aps_id,
535 ✗ .sh_alf_cc_cr_aps_id = sh->sh_alf_cc_cr_aps_id,
536 ✗ .NumRefIdxActive[0] = sh->num_ref_idx_active[0],
537 ✗ .NumRefIdxActive[1] = sh->num_ref_idx_active[1],
538 ✗ .sh_collocated_ref_idx = sh->sh_collocated_ref_idx,
539 ✗ .SliceQpY = pps->pps_qp_delta_info_in_ph_flag ?
540 ✗ 26 + pps->pps_init_qp_minus26 + ph->ph_qp_delta :
541 ✗ 26 + pps->pps_init_qp_minus26 + sh->sh_qp_delta,
542 ✗ .sh_cb_qp_offset = sh->sh_cb_qp_offset,
543 ✗ .sh_cr_qp_offset = sh->sh_cr_qp_offset,
544 ✗ .sh_joint_cbcr_qp_offset = sh->sh_joint_cbcr_qp_offset,
545 ✗ .sh_luma_beta_offset_div2 = sh->sh_luma_beta_offset_div2,
546 ✗ .sh_luma_tc_offset_div2 = sh->sh_luma_tc_offset_div2,
547 ✗ .sh_cb_beta_offset_div2 = sh->sh_cb_beta_offset_div2,
548 ✗ .sh_cb_tc_offset_div2 = sh->sh_cb_tc_offset_div2,
549 ✗ .sh_cr_beta_offset_div2 = sh->sh_cr_beta_offset_div2,
550 ✗ .sh_cr_tc_offset_div2 = sh->sh_cr_tc_offset_div2,
551 .WPInfo = {
552 ✗ .luma_log2_weight_denom = sh->sh_pred_weight_table.luma_log2_weight_denom,
553 ✗ .delta_chroma_log2_weight_denom = sh->sh_pred_weight_table.delta_chroma_log2_weight_denom,
554 ✗ .num_l0_weights = sh->sh_pred_weight_table.num_l0_weights,
555 ✗ .num_l1_weights = sh->sh_pred_weight_table.num_l1_weights,
556 },
557 .sh_flags.bits = {
558 ✗ .sh_alf_enabled_flag = sh->sh_alf_enabled_flag,
559 ✗ .sh_alf_cb_enabled_flag = sh->sh_alf_cb_enabled_flag,
560 ✗ .sh_alf_cr_enabled_flag = sh->sh_alf_cr_enabled_flag,
561 ✗ .sh_alf_cc_cb_enabled_flag = sh->sh_alf_cc_cb_enabled_flag,
562 ✗ .sh_alf_cc_cr_enabled_flag = sh->sh_alf_cc_cr_enabled_flag,
563 ✗ .sh_lmcs_used_flag = sh->sh_lmcs_used_flag,
564 ✗ .sh_explicit_scaling_list_used_flag = sh->sh_explicit_scaling_list_used_flag,
565 ✗ .sh_cabac_init_flag = sh->sh_cabac_init_flag,
566 ✗ .sh_collocated_from_l0_flag = sh->sh_collocated_from_l0_flag,
567 ✗ .sh_cu_chroma_qp_offset_enabled_flag = sh->sh_cu_chroma_qp_offset_enabled_flag,
568 ✗ .sh_sao_luma_used_flag = sh->sh_sao_luma_used_flag,
569 ✗ .sh_sao_chroma_used_flag = sh->sh_sao_chroma_used_flag,
570 ✗ .sh_deblocking_filter_disabled_flag = sh->sh_deblocking_filter_disabled_flag,
571 ✗ .sh_dep_quant_used_flag = sh->sh_dep_quant_used_flag,
572 ✗ .sh_sign_data_hiding_used_flag = sh->sh_sign_data_hiding_used_flag,
573 ✗ .sh_ts_residual_coding_disabled_flag = sh->sh_ts_residual_coding_disabled_flag,
574 },
575 };
576
577 ✗ memset(&slice_param->RefPicList, 0xFF, sizeof(slice_param->RefPicList));
578
579 ✗ nb_list = (sh->sh_slice_type == VVC_SLICE_TYPE_B) ?
580 ✗ 2 : (sh->sh_slice_type == VVC_SLICE_TYPE_I ? 0 : 1);
581 ✗ for (int list_idx = 0; list_idx < nb_list; list_idx++) {
582 ✗ RefPicList *rpl = &sc->rpl[list_idx];
583
584 ✗ for (i = 0; i < rpl->nb_refs; i++)
585 ✗ slice_param->RefPicList[list_idx][i] = get_ref_pic_index(h, rpl->refs[i].ref);
586 }
587
588 ✗ for (i = 0; i < 7; i++)
589 ✗ slice_param->sh_alf_aps_id_luma[i] = sh->sh_alf_aps_id_luma[i];
590
591 ✗ for (i = 0; i < 15; i++) {
592 ✗ slice_param->WPInfo.luma_weight_l0_flag[i] = sh->sh_pred_weight_table.luma_weight_l0_flag[i];
593 ✗ slice_param->WPInfo.chroma_weight_l0_flag[i] = sh->sh_pred_weight_table.chroma_weight_l0_flag[i];
594 ✗ slice_param->WPInfo.delta_luma_weight_l0[i] = sh->sh_pred_weight_table.delta_luma_weight_l0[i];
595 ✗ slice_param->WPInfo.luma_offset_l0[i] = sh->sh_pred_weight_table.luma_offset_l0[i];
596 ✗ slice_param->WPInfo.luma_weight_l1_flag[i] = sh->sh_pred_weight_table.luma_weight_l1_flag[i];
597 ✗ slice_param->WPInfo.chroma_weight_l1_flag[i] = sh->sh_pred_weight_table.chroma_weight_l1_flag[i];
598 ✗ slice_param->WPInfo.delta_luma_weight_l1[i] = sh->sh_pred_weight_table.delta_luma_weight_l1[i];
599 ✗ slice_param->WPInfo.luma_offset_l1[i] = sh->sh_pred_weight_table.luma_offset_l1[i];
600 }
601
602 ✗ for (i = 0; i < 15; i++) {
603 ✗ for (int j = 0; j < 2; j++) {
604 ✗ slice_param->WPInfo.delta_chroma_weight_l0[i][j] = sh->sh_pred_weight_table.delta_chroma_weight_l0[i][j];
605 ✗ slice_param->WPInfo.delta_chroma_offset_l0[i][j] = sh->sh_pred_weight_table.delta_chroma_offset_l0[i][j];
606 ✗ slice_param->WPInfo.delta_chroma_weight_l1[i][j] = sh->sh_pred_weight_table.delta_chroma_weight_l1[i][j];
607 ✗ slice_param->WPInfo.delta_chroma_offset_l1[i][j] = sh->sh_pred_weight_table.delta_chroma_offset_l1[i][j];
608 }
609 }
610
611 ✗ err = ff_vaapi_decode_make_slice_buffer(avctx, &pic->pic,
612 ✗ &pic->slice_param, 1,
613 sizeof(VASliceParameterBufferVVC),
614 buffer, size);
615 ✗ if (err) {
616 ✗ ff_vaapi_decode_cancel(avctx, &pic->pic);
617 ✗ return err;
618 }
619
620 ✗ return 0;
621 }
622
623 ✗ static int vaapi_vvc_end_frame(AVCodecContext *avctx)
624 {
625
626 ✗ const VVCContext *h = avctx->priv_data;
627 ✗ VVCFrameContext *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs];
628 ✗ VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private;
629 int ret;
630
631 ✗ ret = ff_vaapi_decode_issue(avctx, &pic->pic);
632 ✗ if (ret < 0)
633 ✗ goto fail;
634
635 ✗ pic->decode_issued = 1;
636
637 ✗ return 0;
638
639 ✗ fail:
640 ✗ ff_vaapi_decode_cancel(avctx, &pic->pic);
641 ✗ return ret;
642 }
643
644 const FFHWAccel ff_vvc_vaapi_hwaccel = {
645 .p.name = "vvc_vaapi",
646 .p.type = AVMEDIA_TYPE_VIDEO,
647 .p.id = AV_CODEC_ID_VVC,
648 .p.pix_fmt = AV_PIX_FMT_VAAPI,
649 .start_frame = &vaapi_vvc_start_frame,
650 .end_frame = &vaapi_vvc_end_frame,
651 .decode_slice = &vaapi_vvc_decode_slice,
652 .frame_priv_data_size = sizeof(VAAPIDecodePictureVVC),
653 .init = &ff_vaapi_decode_init,
654 .uninit = &ff_vaapi_decode_uninit,
655 .frame_params = &ff_vaapi_common_frame_params,
656 .priv_data_size = sizeof(VAAPIDecodeContext),
657 .caps_internal = HWACCEL_CAP_ASYNC_SAFE,
658 };
659