diff mbox series

[FFmpeg-devel,v1,7/7] lavc/vaapi_dec: Add VVC decoder

Message ID 20240328012631.777476-7-fei.w.wang@intel.com
State New
Headers show
Series [FFmpeg-devel,v1,1/7] lavc/vaapi_dec: Create VA parameters dynamically | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Wang, Fei W March 28, 2024, 1:26 a.m. UTC
From: Fei Wang <fei.w.wang@intel.com>

Signed-off-by: Fei Wang <fei.w.wang@intel.com>
---
 Changelog                 |   4 +
 configure                 |   3 +
 libavcodec/Makefile       |   1 +
 libavcodec/hwaccels.h     |   1 +
 libavcodec/vaapi_decode.c |   7 +
 libavcodec/vaapi_vvc.c    | 657 ++++++++++++++++++++++++++++++++++++++
 libavcodec/version.h      |   2 +-
 libavcodec/vvc/vvcdec.c   |  15 +-
 8 files changed, 688 insertions(+), 2 deletions(-)
 create mode 100644 libavcodec/vaapi_vvc.c

Comments

Nuo Mi April 2, 2024, 12:48 p.m. UTC | #1
On Thu, Mar 28, 2024 at 9:27 AM <fei.w.wang-at-intel.com@ffmpeg.org> wrote:

> From: Fei Wang <fei.w.wang@intel.com>
>
> Signed-off-by: Fei Wang <fei.w.wang@intel.com>
> ---
>  Changelog                 |   4 +
>  configure                 |   3 +
>  libavcodec/Makefile       |   1 +
>  libavcodec/hwaccels.h     |   1 +
>  libavcodec/vaapi_decode.c |   7 +
>  libavcodec/vaapi_vvc.c    | 657 ++++++++++++++++++++++++++++++++++++++
>  libavcodec/version.h      |   2 +-
>  libavcodec/vvc/vvcdec.c   |  15 +-
>  8 files changed, 688 insertions(+), 2 deletions(-)
>  create mode 100644 libavcodec/vaapi_vvc.c
>
> diff --git a/Changelog b/Changelog
> index e83a00e35c..3108e65558 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -1,6 +1,10 @@
>  Entries are sorted chronologically from oldest to youngest within each
> release,
>  releases are sorted from youngest to oldest.
>
> +version <next>:
> +- VVC VAAPI decoder
> +
> +
>  version 7.0:
>  - DXV DXT1 encoder
>  - LEAD MCMP decoder
> diff --git a/configure b/configure
> index 2a1d22310b..d902c9adc8 100755
> --- a/configure
> +++ b/configure
> @@ -3258,6 +3258,8 @@ vp9_vdpau_hwaccel_deps="vdpau VdpPictureInfoVP9"
>  vp9_vdpau_hwaccel_select="vp9_decoder"
>  vp9_videotoolbox_hwaccel_deps="videotoolbox"
>  vp9_videotoolbox_hwaccel_select="vp9_decoder"
> +vvc_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferVVC"
> +vvc_vaapi_hwaccel_select="vvc_decoder"
>  wmv3_d3d11va_hwaccel_select="vc1_d3d11va_hwaccel"
>  wmv3_d3d11va2_hwaccel_select="vc1_d3d11va2_hwaccel"
>  wmv3_d3d12va_hwaccel_select="vc1_d3d12va_hwaccel"
> @@ -7250,6 +7252,7 @@ if enabled vaapi; then
>      check_cpp_condition vaapi_1 "va/va.h" "VA_CHECK_VERSION(1, 0, 0)"
>
>      check_type "va/va.h va/va_dec_hevc.h" "VAPictureParameterBufferHEVC"
> +    check_type "va/va.h va/va_dec_vvc.h" "VAPictureParameterBufferVVC"
>      check_struct "va/va.h" "VADecPictureParameterBufferVP9" bit_depth
>      check_struct "va/va.h" "VADecPictureParameterBufferAV1" bit_depth_idx
>      check_type   "va/va.h va/va_vpp.h"
> "VAProcFilterParameterBufferHDRToneMapping"
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 9ce6d445c1..343b037636 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -1054,6 +1054,7 @@ OBJS-$(CONFIG_VP9_VAAPI_HWACCEL)          +=
> vaapi_vp9.o
>  OBJS-$(CONFIG_VP9_VDPAU_HWACCEL)          += vdpau_vp9.o
>  OBJS-$(CONFIG_VP9_VIDEOTOOLBOX_HWACCEL)   += videotoolbox_vp9.o
>  OBJS-$(CONFIG_VP8_QSV_HWACCEL)            += qsvdec.o
> +OBJS-$(CONFIG_VVC_VAAPI_HWACCEL)          += vaapi_vvc.o
>
>  # Objects duplicated from other libraries for shared builds
>  SHLIBOBJS                              += log2_tab.o reverse.o
> diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h
> index 5171e4c7d7..88d6b9a9b5 100644
> --- a/libavcodec/hwaccels.h
> +++ b/libavcodec/hwaccels.h
> @@ -82,6 +82,7 @@ extern const struct FFHWAccel ff_vp9_nvdec_hwaccel;
>  extern const struct FFHWAccel ff_vp9_vaapi_hwaccel;
>  extern const struct FFHWAccel ff_vp9_vdpau_hwaccel;
>  extern const struct FFHWAccel ff_vp9_videotoolbox_hwaccel;
> +extern const struct FFHWAccel ff_vvc_vaapi_hwaccel;
>  extern const struct FFHWAccel ff_wmv3_d3d11va_hwaccel;
>  extern const struct FFHWAccel ff_wmv3_d3d11va2_hwaccel;
>  extern const struct FFHWAccel ff_wmv3_d3d12va_hwaccel;
> diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c
> index 1b1972a2a9..ceeb1f1a12 100644
> --- a/libavcodec/vaapi_decode.c
> +++ b/libavcodec/vaapi_decode.c
> @@ -455,6 +455,9 @@ static const struct {
>      MAP(AV1,         AV1_MAIN,        AV1Profile0),
>      MAP(AV1,         AV1_HIGH,        AV1Profile1),
>  #endif
> +#if VA_CHECK_VERSION(1, 22, 0)
> +    MAP(H266,        VVC_MAIN_10,     VVCMain10),
> +#endif
>
>  #undef MAP
>  };
> @@ -627,6 +630,10 @@ static int vaapi_decode_make_config(AVCodecContext
> *avctx,
>          case AV_CODEC_ID_VP8:
>              frames->initial_pool_size += 3;
>              break;
> +        case AV_CODEC_ID_H266:
> +            // Add additional 16 for maximum 16 frames delay in vvc
> native decode.
> +            frames->initial_pool_size += 32;
>
One frame of 8k YUV444, 10 bits, is about 200MB. Thirty-two frames amount
to approximately 6GB.Can we dynamically allocate the buffer pool?

The software decoder requires a delay of 16 frames to ensure full
utilization of CPUs. In the future, we may consider increasing this to 32
or even 64 frames.
However, for hardware decoding, given that all processing occurs on the
GPU, we do not require any delay.

+            break;
>          default:
>              frames->initial_pool_size += 2;
>          }
> diff --git a/libavcodec/vaapi_vvc.c b/libavcodec/vaapi_vvc.c
> new file mode 100644
> index 0000000000..6141005688
> --- /dev/null
> +++ b/libavcodec/vaapi_vvc.c
> @@ -0,0 +1,657 @@
> +/*
> + * VVC HW decode acceleration through VA API
> + *
> + * Copyright (c) 2024 Intel Corporation
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> + */
> +
> +#include <va/va.h>
> +#include <va/va_dec_vvc.h>
> +
> +#include "vvc/vvcdec.h"
> +#include "vvc/vvc_refs.h"
> +#include "hwaccel_internal.h"
> +#include "vaapi_decode.h"
> +
> +typedef struct VAAPIDecodePictureVVC {
> +    VAAPIDecodePicture          pic;
> +    VAPictureParameterBufferVVC pic_param;
> +    VASliceParameterBufferVVC   slice_param;
> +    int                         decode_issued;
> +} VAAPIDecodePictureVVC;
> +
> +static void init_vaapi_pic(VAPictureVVC *va_pic)
> +{
> +    va_pic->picture_id    = VA_INVALID_ID;
> +    va_pic->flags         = VA_PICTURE_VVC_INVALID;
> +    va_pic->pic_order_cnt = 0;
> +}
> +
> +static void fill_vaapi_pic(VAPictureVVC *va_pic, const VVCFrame *pic)
> +{
> +    va_pic->picture_id    = ff_vaapi_get_surface_id(pic->frame);
> +    va_pic->pic_order_cnt = pic->poc;
> +    va_pic->flags         = 0;
> +
> +    if (pic->flags & VVC_FRAME_FLAG_LONG_REF)
> +        va_pic->flags |= VA_PICTURE_VVC_LONG_TERM_REFERENCE;
> +}
> +
> +static void fill_vaapi_reference_frames(const VVCFrameContext *h,
> VAPictureParameterBufferVVC *pp)
> +{
> +    const VVCFrame *current_picture = h->ref;
> +    int i, j;
> +
> +    for (i = 0, j = 0; i < FF_ARRAY_ELEMS(pp->ReferenceFrames); i++) {
> +        const VVCFrame *frame = NULL;
> +
> +        while (!frame && j < FF_ARRAY_ELEMS(h->DPB)) {
> +            if ((&h->DPB[j] != current_picture ) &&
> +                (h->DPB[j].flags & (VVC_FRAME_FLAG_LONG_REF |
> VVC_FRAME_FLAG_SHORT_REF)))
> +                frame = &h->DPB[j];
> +            j++;
> +        }
> +
> +        init_vaapi_pic(&pp->ReferenceFrames[i]);
> +
> +        if (frame) {
> +            VAAPIDecodePictureVVC *pic;
> +            fill_vaapi_pic(&pp->ReferenceFrames[i], frame);
> +            pic = frame->hwaccel_picture_private;
> +            if (!pic->decode_issued)
> +               pp->ReferenceFrames[i].flags |=
> VA_PICTURE_VVC_UNAVAILABLE_REFERENCE;
> +        }
> +    }
> +}
> +
> +static int vaapi_vvc_start_frame(AVCodecContext          *avctx,
> +                                 av_unused const uint8_t *buffer,
> +                                 av_unused uint32_t       size)
> +{
> +    const VVCContext                    *h = avctx->priv_data;
> +    VVCFrameContext                    *fc = &h->fcs[(h->nb_frames +
> h->nb_fcs) % h->nb_fcs];
> +    const H266RawSPS                  *sps = fc->ps.sps->r;
> +    const H266RawPPS                  *pps = fc->ps.pps->r;
> +    const H266RawPictureHeader         *ph = fc->ps.ph.r;
> +    VAAPIDecodePictureVVC             *pic =
> fc->ref->hwaccel_picture_private;
> +    VAPictureParameterBufferVVC *pic_param = &pic->pic_param;
> +    uint16_t tile_dim, exp_slice_height_in_ctus[VVC_MAX_SLICES] = {0};
> +    int i, j, k, err;
> +
> +    pic->pic.output_surface = ff_vaapi_get_surface_id(fc->ref->frame);
> +
> +    *pic_param = (VAPictureParameterBufferVVC) {
> +        .pps_pic_width_in_luma_samples                 =
> pps->pps_pic_width_in_luma_samples,
> +        .pps_pic_height_in_luma_samples                =
> pps->pps_pic_height_in_luma_samples,
> +        .sps_num_subpics_minus1                        =
> sps->sps_num_subpics_minus1,
> +        .sps_chroma_format_idc                         =
> sps->sps_chroma_format_idc,
> +        .sps_bitdepth_minus8                           =
> sps->sps_bitdepth_minus8,
> +        .sps_log2_ctu_size_minus5                      =
> sps->sps_log2_ctu_size_minus5,
> +        .sps_log2_min_luma_coding_block_size_minus2    =
> sps->sps_log2_min_luma_coding_block_size_minus2,
> +        .sps_log2_transform_skip_max_size_minus2       =
> sps->sps_log2_transform_skip_max_size_minus2,
> +        .sps_six_minus_max_num_merge_cand              =
> sps->sps_six_minus_max_num_merge_cand,
> +        .sps_five_minus_max_num_subblock_merge_cand    =
> sps->sps_five_minus_max_num_subblock_merge_cand,
> +        .sps_max_num_merge_cand_minus_max_num_gpm_cand =
> sps->sps_max_num_merge_cand_minus_max_num_gpm_cand,
> +        .sps_log2_parallel_merge_level_minus2          =
> sps->sps_log2_parallel_merge_level_minus2,
> +        .sps_min_qp_prime_ts                           =
> sps->sps_min_qp_prime_ts,
> +        .sps_six_minus_max_num_ibc_merge_cand          =
> sps->sps_six_minus_max_num_ibc_merge_cand,
> +        .sps_num_ladf_intervals_minus2                 =
> sps->sps_num_ladf_intervals_minus2,
> +        .sps_ladf_lowest_interval_qp_offset            =
> sps->sps_ladf_lowest_interval_qp_offset,
> +        .sps_flags.bits = {
> +            .sps_subpic_info_present_flag
>   = sps->sps_subpic_info_present_flag,
> +            .sps_independent_subpics_flag
>   = sps->sps_independent_subpics_flag,
> +            .sps_subpic_same_size_flag
>  = sps->sps_subpic_same_size_flag,
> +            .sps_entropy_coding_sync_enabled_flag
>   = sps->sps_entropy_coding_sync_enabled_flag,
> +            .sps_qtbtt_dual_tree_intra_flag
>   = sps->sps_qtbtt_dual_tree_intra_flag,
> +            .sps_max_luma_transform_size_64_flag
>  = sps->sps_max_luma_transform_size_64_flag,
> +            .sps_transform_skip_enabled_flag
>  = sps->sps_transform_skip_enabled_flag,
> +            .sps_bdpcm_enabled_flag
>   = sps->sps_bdpcm_enabled_flag,
> +            .sps_mts_enabled_flag
>   = sps->sps_mts_enabled_flag,
> +            .sps_explicit_mts_intra_enabled_flag
>  = sps->sps_explicit_mts_intra_enabled_flag,
> +            .sps_explicit_mts_inter_enabled_flag
>  = sps->sps_explicit_mts_inter_enabled_flag,
> +            .sps_lfnst_enabled_flag
>   = sps->sps_lfnst_enabled_flag,
> +            .sps_joint_cbcr_enabled_flag
>  = sps->sps_joint_cbcr_enabled_flag,
> +            .sps_same_qp_table_for_chroma_flag
>  = sps->sps_same_qp_table_for_chroma_flag,
> +            .sps_sao_enabled_flag
>   = sps->sps_sao_enabled_flag,
> +            .sps_alf_enabled_flag
>   = sps->sps_alf_enabled_flag,
> +            .sps_ccalf_enabled_flag
>   = sps->sps_alf_enabled_flag,
> +            .sps_lmcs_enabled_flag
>  = sps->sps_lmcs_enabled_flag,
> +            .sps_sbtmvp_enabled_flag
>  = sps->sps_sbtmvp_enabled_flag,
> +            .sps_amvr_enabled_flag
>  = sps->sps_amvr_enabled_flag,
> +            .sps_smvd_enabled_flag
>  = sps->sps_smvd_enabled_flag,
> +            .sps_mmvd_enabled_flag
>  = sps->sps_mmvd_enabled_flag,
> +            .sps_sbt_enabled_flag
>   = sps->sps_sbt_enabled_flag,
> +            .sps_affine_enabled_flag
>  = sps->sps_affine_enabled_flag,
> +            .sps_6param_affine_enabled_flag
>   = sps->sps_6param_affine_enabled_flag,
> +            .sps_affine_amvr_enabled_flag
>   = sps->sps_affine_amvr_enabled_flag,
> +            .sps_affine_prof_enabled_flag
>   = sps->sps_affine_prof_enabled_flag,
> +            .sps_bcw_enabled_flag
>   = sps->sps_bcw_enabled_flag,
> +            .sps_ciip_enabled_flag
>  = sps->sps_ciip_enabled_flag,
> +            .sps_gpm_enabled_flag
>   = sps->sps_gpm_enabled_flag,
> +            .sps_isp_enabled_flag
>   = sps->sps_isp_enabled_flag,
> +            .sps_mrl_enabled_flag
>   = sps->sps_mrl_enabled_flag,
> +            .sps_mip_enabled_flag
>   = sps->sps_mip_enabled_flag,
> +            .sps_cclm_enabled_flag
>  = sps->sps_cclm_enabled_flag,
> +            .sps_chroma_horizontal_collocated_flag
>  = sps->sps_chroma_horizontal_collocated_flag,
> +            .sps_chroma_vertical_collocated_flag
>  = sps->sps_chroma_vertical_collocated_flag,
> +            .sps_palette_enabled_flag
>   = sps->sps_palette_enabled_flag,
> +            .sps_act_enabled_flag
>   = sps->sps_act_enabled_flag,
> +            .sps_ibc_enabled_flag
>   = sps->sps_ibc_enabled_flag,
> +            .sps_ladf_enabled_flag
>  = sps->sps_ladf_enabled_flag,
> +            .sps_explicit_scaling_list_enabled_flag
>   = sps->sps_explicit_scaling_list_enabled_flag,
> +            .sps_scaling_matrix_for_lfnst_disabled_flag
>   = sps->sps_scaling_matrix_for_lfnst_disabled_flag,
> +
> .sps_scaling_matrix_for_alternative_colour_space_disabled_flag =
> sps->sps_scaling_matrix_for_alternative_colour_space_disabled_flag,
> +            .sps_scaling_matrix_designated_colour_space_flag
>  = sps->sps_scaling_matrix_designated_colour_space_flag,
> +            .sps_virtual_boundaries_enabled_flag
>  = sps->sps_virtual_boundaries_enabled_flag,
> +            .sps_virtual_boundaries_present_flag
>  = sps->sps_virtual_boundaries_present_flag,
> +        },
> +        .NumVerVirtualBoundaries               =
> sps->sps_virtual_boundaries_present_flag ?
> +
>  sps->sps_num_ver_virtual_boundaries :
> +
>  ph->ph_num_ver_virtual_boundaries,
> +        .NumHorVirtualBoundaries               =
> sps->sps_virtual_boundaries_present_flag ?
> +
>  sps->sps_num_hor_virtual_boundaries :
> +
>  ph->ph_num_hor_virtual_boundaries,
> +        .pps_scaling_win_left_offset           =
> pps->pps_scaling_win_left_offset,
> +        .pps_scaling_win_right_offset          =
> pps->pps_scaling_win_right_offset,
> +        .pps_scaling_win_top_offset            =
> pps->pps_scaling_win_top_offset,
> +        .pps_scaling_win_bottom_offset         =
> pps->pps_scaling_win_bottom_offset,
> +        .pps_num_exp_tile_columns_minus1       =
> pps->pps_num_exp_tile_columns_minus1,
> +        .pps_num_exp_tile_rows_minus1          =
> pps->pps_num_exp_tile_rows_minus1,
> +        .pps_num_slices_in_pic_minus1          =
> pps->pps_num_slices_in_pic_minus1,
> +        .pps_pic_width_minus_wraparound_offset =
> pps->pps_pic_width_minus_wraparound_offset,
> +        .pps_cb_qp_offset                      = pps->pps_cb_qp_offset,
> +        .pps_cr_qp_offset                      = pps->pps_cr_qp_offset,
> +        .pps_joint_cbcr_qp_offset_value        =
> pps->pps_joint_cbcr_qp_offset_value,
> +        .pps_chroma_qp_offset_list_len_minus1  =
> pps->pps_chroma_qp_offset_list_len_minus1,
> +        .pps_flags.bits = {
> +            .pps_loop_filter_across_tiles_enabled_flag   =
> pps->pps_loop_filter_across_tiles_enabled_flag,
> +            .pps_rect_slice_flag                         =
> pps->pps_rect_slice_flag,
> +            .pps_single_slice_per_subpic_flag            =
> pps->pps_single_slice_per_subpic_flag,
> +            .pps_loop_filter_across_slices_enabled_flag  =
> pps->pps_loop_filter_across_slices_enabled_flag,
> +            .pps_weighted_pred_flag                      =
> pps->pps_weighted_pred_flag,
> +            .pps_weighted_bipred_flag                    =
> pps->pps_weighted_bipred_flag,
> +            .pps_ref_wraparound_enabled_flag             =
> pps->pps_ref_wraparound_enabled_flag,
> +            .pps_cu_qp_delta_enabled_flag                =
> pps->pps_cu_qp_delta_enabled_flag,
> +            .pps_cu_chroma_qp_offset_list_enabled_flag   =
> pps->pps_cu_chroma_qp_offset_list_enabled_flag,
> +            .pps_deblocking_filter_override_enabled_flag =
> pps->pps_deblocking_filter_override_enabled_flag,
> +            .pps_deblocking_filter_disabled_flag         =
> pps->pps_deblocking_filter_disabled_flag,
> +            .pps_dbf_info_in_ph_flag                     =
> pps->pps_dbf_info_in_ph_flag,
> +            .pps_sao_info_in_ph_flag                     =
> pps->pps_sao_info_in_ph_flag,
> +            .pps_alf_info_in_ph_flag                     =
> pps->pps_alf_info_in_ph_flag,
> +        },
> +        .ph_lmcs_aps_id                                =
> ph->ph_lmcs_aps_id,
> +        .ph_scaling_list_aps_id                        =
> ph->ph_scaling_list_aps_id,
> +        .ph_log2_diff_min_qt_min_cb_intra_slice_luma   =
> ph->ph_log2_diff_min_qt_min_cb_intra_slice_luma,
> +        .ph_max_mtt_hierarchy_depth_intra_slice_luma   =
> ph->ph_max_mtt_hierarchy_depth_intra_slice_luma,
> +        .ph_log2_diff_max_bt_min_qt_intra_slice_luma   =
> ph->ph_log2_diff_max_bt_min_qt_intra_slice_luma,
> +        .ph_log2_diff_max_tt_min_qt_intra_slice_luma   =
> ph->ph_log2_diff_max_tt_min_qt_intra_slice_luma,
> +        .ph_log2_diff_min_qt_min_cb_intra_slice_chroma =
> ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma,
> +        .ph_max_mtt_hierarchy_depth_intra_slice_chroma =
> ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma,
> +        .ph_log2_diff_max_bt_min_qt_intra_slice_chroma =
> ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma,
> +        .ph_log2_diff_max_tt_min_qt_intra_slice_chroma =
> ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma,
> +        .ph_cu_qp_delta_subdiv_intra_slice             =
> ph->ph_cu_qp_delta_subdiv_intra_slice,
> +        .ph_cu_chroma_qp_offset_subdiv_intra_slice     =
> ph->ph_cu_chroma_qp_offset_subdiv_intra_slice,
> +        .ph_log2_diff_min_qt_min_cb_inter_slice        =
> ph->ph_log2_diff_min_qt_min_cb_inter_slice,
> +        .ph_max_mtt_hierarchy_depth_inter_slice        =
> ph->ph_max_mtt_hierarchy_depth_inter_slice,
> +        .ph_log2_diff_max_bt_min_qt_inter_slice        =
> ph->ph_log2_diff_max_bt_min_qt_inter_slice,
> +        .ph_log2_diff_max_tt_min_qt_inter_slice        =
> ph->ph_log2_diff_max_tt_min_qt_inter_slice,
> +        .ph_cu_qp_delta_subdiv_inter_slice             =
> ph->ph_cu_qp_delta_subdiv_inter_slice,
> +        .ph_cu_chroma_qp_offset_subdiv_inter_slice     =
> ph->ph_cu_chroma_qp_offset_subdiv_inter_slice,
> +        .ph_flags.bits= {
> +            .ph_non_ref_pic_flag                   =
> ph->ph_non_ref_pic_flag,
> +            .ph_alf_enabled_flag                   =
> ph->ph_alf_enabled_flag,
> +            .ph_alf_cb_enabled_flag                =
> ph->ph_alf_cb_enabled_flag,
> +            .ph_alf_cr_enabled_flag                =
> ph->ph_alf_cr_enabled_flag,
> +            .ph_alf_cc_cb_enabled_flag             =
> ph->ph_alf_cc_cb_enabled_flag,
> +            .ph_alf_cc_cr_enabled_flag             =
> ph->ph_alf_cc_cr_enabled_flag,
> +            .ph_lmcs_enabled_flag                  =
> ph->ph_lmcs_enabled_flag,
> +            .ph_chroma_residual_scale_flag         =
> ph->ph_chroma_residual_scale_flag,
> +            .ph_explicit_scaling_list_enabled_flag =
> ph->ph_explicit_scaling_list_enabled_flag,
> +            .ph_virtual_boundaries_present_flag    =
> ph->ph_virtual_boundaries_present_flag,
> +            .ph_temporal_mvp_enabled_flag          =
> ph->ph_temporal_mvp_enabled_flag,
> +            .ph_mmvd_fullpel_only_flag             =
> ph->ph_mmvd_fullpel_only_flag,
> +            .ph_mvd_l1_zero_flag                   =
> ph->ph_mvd_l1_zero_flag,
> +            .ph_bdof_disabled_flag                 =
> ph->ph_bdof_disabled_flag,
> +            .ph_dmvr_disabled_flag                 =
> ph->ph_dmvr_disabled_flag,
> +            .ph_prof_disabled_flag                 =
> ph->ph_prof_disabled_flag,
> +            .ph_joint_cbcr_sign_flag               =
> ph->ph_joint_cbcr_sign_flag,
> +            .ph_sao_luma_enabled_flag              =
> ph->ph_sao_luma_enabled_flag,
> +            .ph_sao_chroma_enabled_flag            =
> ph->ph_sao_chroma_enabled_flag,
> +            .ph_deblocking_filter_disabled_flag    =
> ph->ph_deblocking_filter_disabled_flag,
> +        },
> +        .PicMiscFlags.fields = {
> +            .IntraPicFlag = pps->pps_mixed_nalu_types_in_pic_flag ? 0 :
> IS_IRAP(h) ? 1 : 0,
> +        }
> +    };
> +
> +    fill_vaapi_pic(&pic_param->CurrPic, fc->ref);
> +    fill_vaapi_reference_frames(fc, pic_param);
> +
> +    for (i = 0; i < VVC_MAX_SAMPLE_ARRAYS; i++)
> +        for (j = 0; j < VVC_MAX_POINTS_IN_QP_TABLE; j++)
> +            pic_param->ChromaQpTable[i][j] =
> fc->ps.sps->chroma_qp_table[i][j];
> +    for (i = 0; i < 4; i++) {
> +        pic_param->sps_ladf_qp_offset[i]              =
> sps->sps_ladf_qp_offset[i];
> +        pic_param->sps_ladf_delta_threshold_minus1[i] =
> sps->sps_ladf_delta_threshold_minus1[i];
> +    }
> +
> +    for (i = 0; i < (sps->sps_virtual_boundaries_present_flag ?
> sps->sps_num_ver_virtual_boundaries : ph->ph_num_ver_virtual_boundaries);
> i++) {
> +        pic_param->VirtualBoundaryPosX[i] =
> (sps->sps_virtual_boundaries_present_flag ?
> +
> (sps->sps_virtual_boundary_pos_x_minus1[ i ] + 1) :
> +
> (ph->ph_virtual_boundary_pos_x_minus1[i] + 1)) * 8;
> +    }
> +
> +    for (i = 0; i < (sps->sps_virtual_boundaries_present_flag ?
> sps->sps_num_hor_virtual_boundaries : ph->ph_num_hor_virtual_boundaries);
> i++) {
> +        pic_param->VirtualBoundaryPosY[i] =
> (sps->sps_virtual_boundaries_present_flag ?
> +
> (sps->sps_virtual_boundary_pos_y_minus1[ i ] + 1) :
> +
> (ph->ph_virtual_boundary_pos_y_minus1[i] + 1)) * 8;
> +    }
> +
> +    for (i = 0; i < 6; i++) {
> +        pic_param->pps_cb_qp_offset_list[i]         =
> pps->pps_cb_qp_offset_list[i];
> +        pic_param->pps_cr_qp_offset_list[i]         =
> pps->pps_cr_qp_offset_list[i];
> +        pic_param->pps_joint_cbcr_qp_offset_list[i] =
> pps->pps_joint_cbcr_qp_offset_list[i];
> +    }
> +
> +    err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
> +                                            VAPictureParameterBufferType,
> +                                            &pic->pic_param,
> sizeof(VAPictureParameterBufferVVC));
> +    if (err < 0)
> +        goto fail;
> +
> +    for (i = 0; i <= sps->sps_num_subpics_minus1 &&
> sps->sps_subpic_info_present_flag; i++) {
> +        VASubPicVVC subpic_param = {
> +            .sps_subpic_ctu_top_left_x =
> sps->sps_subpic_ctu_top_left_x[i],
> +            .sps_subpic_ctu_top_left_y =
> sps->sps_subpic_ctu_top_left_y[i],
> +            .sps_subpic_width_minus1   = sps->sps_subpic_width_minus1[i],
> +            .sps_subpic_height_minus1  = sps->sps_subpic_height_minus1[i],
> +            .SubpicIdVal               = pps->sub_pic_id_val[i],
> +            .subpic_flags.bits = {
> +                .sps_subpic_treated_as_pic_flag             =
> sps->sps_subpic_treated_as_pic_flag[i],
> +                .sps_loop_filter_across_subpic_enabled_flag =
> sps->sps_loop_filter_across_subpic_enabled_flag[i],
> +            }
> +        };
> +        err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
> +                                                VASubPicBufferType,
> +                                                &subpic_param,
> sizeof(VASubPicVVC));
> +        if (err < 0)
> +            goto fail;
> +    }
> +
> +    for (i = 0; i < VVC_MAX_ALF_COUNT; i++) {
> +        const VVCALF *alf_list = h->ps.alf_list[i];
> +        if (alf_list) {
> +            const H266RawAPS *alf = alf_list->r;
> +            VAAlfDataVVC alf_param = {
> +                .aps_adaptation_parameter_set_id = i,
> +                .alf_luma_num_filters_signalled_minus1 =
> alf->alf_luma_num_filters_signalled_minus1,
> +                .alf_chroma_num_alt_filters_minus1     =
> alf->alf_chroma_num_alt_filters_minus1,
> +                .alf_cc_cb_filters_signalled_minus1    =
> alf->alf_cc_cb_filters_signalled_minus1,
> +                .alf_cc_cr_filters_signalled_minus1    =
> alf->alf_cc_cr_filters_signalled_minus1,
> +                .alf_flags.bits = {
> +                    .alf_luma_filter_signal_flag   =
> alf->alf_luma_filter_signal_flag,
> +                    .alf_chroma_filter_signal_flag =
> alf->alf_chroma_filter_signal_flag,
> +                    .alf_cc_cb_filter_signal_flag  =
> alf->alf_cc_cb_filter_signal_flag,
> +                    .alf_cc_cr_filter_signal_flag  =
> alf->alf_cc_cr_filter_signal_flag,
> +                    .alf_luma_clip_flag            =
> alf->alf_luma_clip_flag,
> +                    .alf_chroma_clip_flag          =
> alf->alf_chroma_clip_flag,
> +                }
> +            };
> +
> +            for (j = 0; j < 25; j++)
> +                alf_param.alf_luma_coeff_delta_idx[j] =
> alf->alf_luma_coeff_delta_idx[j];
> +
> +            for (j = 0; j < 25; j++) {
> +                for (k = 0; k < 12; k++) {
> +                    alf_param.filtCoeff[j][k]         =
> alf->alf_luma_coeff_abs[j][k] * (1 - 2 * alf->alf_luma_coeff_sign[j][k]);
> +                    alf_param.alf_luma_clip_idx[j][k] =
> alf->alf_luma_clip_idx[j][k];
> +                }
> +            }
> +
> +            for (j = 0; j < 8; j++) {
> +                for (k = 0; k < 6; k++) {
> +                    alf_param.AlfCoeffC[j][k]           =
> alf->alf_chroma_coeff_abs[j][k] * (1 - 2 *
> alf->alf_chroma_coeff_sign[j][k]);
> +                    alf_param.alf_chroma_clip_idx[j][k] =
> alf->alf_chroma_clip_idx[j][k];
> +                }
> +            }
> +
> +            for (j = 0; j < 4; j++) {
> +                for (k = 0; k < 7; k++) {
> +                    if (alf->alf_cc_cb_mapped_coeff_abs[j][k])
> +                        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));
> +                    if (alf->alf_cc_cr_mapped_coeff_abs[j][k])
> +                        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));
> +                }
> +            }
> +
> +            err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
> +                                                    VAAlfBufferType,
> +                                                    &alf_param,
> sizeof(VAAlfDataVVC));
> +            if (err < 0)
> +                goto fail;
> +        }
> +    }
> +
> +    for (i = 0; i < VVC_MAX_LMCS_COUNT; i++) {
> +        const H266RawAPS *lmcs = h->ps.lmcs_list[i];
> +        if (lmcs) {
> +            VALmcsDataVVC lmcs_param = {
> +                .aps_adaptation_parameter_set_id = i,
> +                .lmcs_min_bin_idx                = lmcs->lmcs_min_bin_idx,
> +                .lmcs_delta_max_bin_idx          =
> lmcs->lmcs_delta_max_bin_idx,
> +                .lmcsDeltaCrs                    = (1 - 2 *
> lmcs->lmcs_delta_sign_crs_flag) * lmcs->lmcs_delta_abs_crs,
> +            };
> +
> +            for (j = lmcs->lmcs_min_bin_idx; j <= 15 -
> lmcs->lmcs_delta_max_bin_idx; j++)
> +                lmcs_param.lmcsDeltaCW[j] = (1 - 2 *
> lmcs->lmcs_delta_sign_cw_flag[j]) * lmcs->lmcs_delta_abs_cw[j];
> +
> +            err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
> +                                                    VALmcsBufferType,
> +                                                    &lmcs_param,
> sizeof(VALmcsDataVVC));
> +            if (err < 0)
> +                goto fail;
> +        }
> +    }
> +
> +    for (i = 0; i < VVC_MAX_SL_COUNT; i++) {
> +        const VVCScalingList *sl = h->ps.scaling_list[i];
> +        if (sl) {
> +            int l;
> +
> +            VAScalingListVVC sl_param = {
> +                .aps_adaptation_parameter_set_id = i,
> +            };
> +
> +            for (j = 0; j < 14; j++)
> +                sl_param.ScalingMatrixDCRec[j] =
> sl->scaling_matrix_dc_rec[j];
> +
> +            for (j = 0; j < 2; j++)
> +                for (k = 0; k < 2; k++)
> +                    for (l = 0; l < 2; l++)
> +                        sl_param.ScalingMatrixRec2x2[j][k][l] =
> sl->scaling_matrix_rec[j][l * 2 + k];
> +
> +            for (j = 2; j < 8; j++)
> +                for (k = 0; k < 4; k++)
> +                    for (l = 0; l < 4; l++)
> +                        sl_param.ScalingMatrixRec4x4[j - 2][k][l] =
> sl->scaling_matrix_rec[j][l * 4 + k];
> +
> +            for (j = 8; j < 28; j++)
> +                for (k = 0; k < 8; k++)
> +                    for (l = 0; l < 8; l++)
> +                        sl_param.ScalingMatrixRec8x8[j - 8][k][l] =
> sl->scaling_matrix_rec[j][l * 8 + k];
> +
> +            err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
> +                                                    VAIQMatrixBufferType,
> +                                                    &sl_param,
> sizeof(VAScalingListVVC));
> +            if (err < 0)
> +                goto fail;
> +        }
> +    }
> +
> +    for (i = 0; i <= pps->pps_num_exp_tile_columns_minus1; i++) {
> +        tile_dim = pps->pps_tile_column_width_minus1[i];
> +        err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
> +                                                VATileBufferType,
> +                                                &tile_dim,
> sizeof(tile_dim));
> +        if (err < 0)
> +            goto fail;
> +    }
> +
> +    for (i = 0; i <= pps->pps_num_exp_tile_rows_minus1; i++) {
> +        tile_dim = pps->pps_tile_row_height_minus1[i];
> +        err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
> +                                                VATileBufferType,
> +                                                &tile_dim,
> sizeof(tile_dim));
> +        if (err < 0)
> +            goto fail;
> +    }
> +
> +    if (!pps->pps_no_pic_partition_flag && pps->pps_rect_slice_flag &&
> !pps->pps_single_slice_per_subpic_flag) {
> +        for (i = 0; i <= pps->pps_num_slices_in_pic_minus1; i++) {
> +            for (j = 0; j < pps->pps_num_exp_slices_in_tile[i]; j++) {
> +                exp_slice_height_in_ctus[i + j] =
> pps->pps_exp_slice_height_in_ctus_minus1[i][j] + 1;
> +            }
> +        }
> +        for (i = 0; i <= pps->pps_num_slices_in_pic_minus1; i++) {
> +            VASliceStructVVC ss_param = {
> +                .SliceTopLeftTileIdx              =
> pps->slice_top_left_tile_idx[i],
> +                .pps_slice_width_in_tiles_minus1  =
> pps->pps_slice_width_in_tiles_minus1[i],
> +                .pps_slice_height_in_tiles_minus1 =
> pps->pps_slice_height_in_tiles_minus1[i],
> +            };
> +
> +            if (pps->pps_slice_width_in_tiles_minus1[i] > 0 ||
> pps->pps_slice_height_in_tiles_minus1[i] > 0)
> +                ss_param.pps_exp_slice_height_in_ctus_minus1 = 0;
> +            else {
> +                if (pps->num_slices_in_tile[i] == 1)
> +                    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;
> +                else if (exp_slice_height_in_ctus[i])
> +                    ss_param.pps_exp_slice_height_in_ctus_minus1 =
> exp_slice_height_in_ctus[i] - 1;
> +                else
> +                    continue;
> +            }
> +
> +            err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
> +
> VASliceStructBufferType,
> +                                                    &ss_param,
> sizeof(VASliceStructVVC));
> +            if (err < 0)
> +                goto fail;
> +        }
> +    }
> +
> +    return 0;
> +
> +fail:
> +    ff_vaapi_decode_cancel(avctx, &pic->pic);
> +    return err;
> +}
> +
> +static uint8_t get_ref_pic_index(const VVCContext *h, const VVCFrame
> *frame)
> +{
> +    VVCFrameContext             *fc = &h->fcs[(h->nb_frames + h->nb_fcs)
> % h->nb_fcs];
> +    VAAPIDecodePictureVVC      *pic = fc->ref->hwaccel_picture_private;
> +    VAPictureParameterBufferVVC *pp = (VAPictureParameterBufferVVC
> *)&pic->pic_param;
> +    uint8_t i;
> +
> +    if (!frame)
> +        return 0xFF;
> +
> +    for (i = 0; i < FF_ARRAY_ELEMS(pp->ReferenceFrames); i++) {
> +        VASurfaceID pid = pp->ReferenceFrames[i].picture_id;
> +        int poc = pp->ReferenceFrames[i].pic_order_cnt;
> +        if (pid != VA_INVALID_ID && pid ==
> ff_vaapi_get_surface_id(frame->frame) && poc == frame->poc)
> +            return i;
> +    }
> +
> +    return 0xFF;
> +}
> +
> +static int get_slice_data_offset(const uint8_t *buffer, uint32_t size,
> const SliceContext* sc)
> +{
> +    const H266RawSlice *slice = sc->ref;
> +    int num_identical_bytes   = slice->data_size < 32 ? slice->data_size
> : 32;
> +
> +    for (int i = 0; i < size; i++) {
> +        int skip_bytes = 0;
> +        if (i >=2 && buffer[i] == 0x03 && !buffer[i - 1] && !buffer[i -
> 2])
> +            continue;
> +
> +        for (int j = 0; j < num_identical_bytes; j++) {
> +            if (i >= 2 && buffer[i + j + skip_bytes] == 0x03 && !buffer[i
> + j + skip_bytes - 1] && !buffer[i + j + skip_bytes - 2])
> +                skip_bytes++;
> +
> +            if (buffer[i + j + skip_bytes] != slice->data[j])
> +                break;
> +
> +            if (j + 1 == num_identical_bytes)
> +                return i;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +static int vaapi_vvc_decode_slice(AVCodecContext *avctx,
> +                                   const uint8_t *buffer,
> +                                   uint32_t       size)
> +{
> +    const VVCContext                    *h = avctx->priv_data;
> +    VVCFrameContext                    *fc = &h->fcs[(h->nb_frames +
> h->nb_fcs) % h->nb_fcs];
> +    const SliceContext                 *sc = fc->slices[fc->nb_slices];
> +    const H266RawPPS                  *pps = fc->ps.pps->r;
> +    const H266RawPictureHeader         *ph = fc->ps.ph.r;
> +    const H266RawSliceHeader           *sh = sc->sh.r;
> +    VAAPIDecodePictureVVC             *pic =
> fc->ref->hwaccel_picture_private;
> +    VASliceParameterBufferVVC *slice_param = &pic->slice_param;
> +    int nb_list, i, err;
> +
> +    *slice_param = (VASliceParameterBufferVVC) {
> +        .slice_data_size                 = size,
> +        .slice_data_offset               = 0,
> +        .slice_data_flag                 = VA_SLICE_DATA_FLAG_ALL,
> +        .slice_data_byte_offset          = get_slice_data_offset(buffer,
> size, sc),
> +        .sh_subpic_id                    = sh->sh_subpic_id,
> +        .sh_slice_address                = sh->sh_slice_address,
> +        .sh_num_tiles_in_slice_minus1    =
> sh->sh_num_tiles_in_slice_minus1,
> +        .sh_slice_type                   = sh->sh_slice_type,
> +        .sh_num_alf_aps_ids_luma         = sh->sh_num_alf_aps_ids_luma,
> +        .sh_alf_aps_id_chroma            = sh->sh_alf_aps_id_chroma,
> +        .sh_alf_cc_cb_aps_id             = sh->sh_alf_cc_cb_aps_id,
> +        .sh_alf_cc_cr_aps_id             = sh->sh_alf_cc_cr_aps_id,
> +        .NumRefIdxActive[0]              = sh->num_ref_idx_active[0],
> +        .NumRefIdxActive[1]              = sh->num_ref_idx_active[1],
> +        .sh_collocated_ref_idx           = sh->sh_collocated_ref_idx,
> +        .SliceQpY                        =
> pps->pps_qp_delta_info_in_ph_flag ?
> +                                           26 + pps->pps_init_qp_minus26
> + ph->ph_qp_delta :
> +                                           26 + pps->pps_init_qp_minus26
> + sh->sh_qp_delta,
> +        .sh_cb_qp_offset                 = sh->sh_cb_qp_offset,
> +        .sh_cr_qp_offset                 = sh->sh_cr_qp_offset,
> +        .sh_joint_cbcr_qp_offset         = sh->sh_joint_cbcr_qp_offset,
> +        .sh_luma_beta_offset_div2        = sh->sh_luma_beta_offset_div2,
> +        .sh_luma_tc_offset_div2          = sh->sh_luma_tc_offset_div2,
> +        .sh_cb_beta_offset_div2          = sh->sh_cb_beta_offset_div2,
> +        .sh_cb_tc_offset_div2            = sh->sh_cb_tc_offset_div2,
> +        .sh_cr_beta_offset_div2          = sh->sh_cr_beta_offset_div2,
> +        .sh_cr_tc_offset_div2            = sh->sh_cr_tc_offset_div2,
> +        .WPInfo = {
> +            .luma_log2_weight_denom         =
> sh->sh_pred_weight_table.luma_log2_weight_denom,
> +            .delta_chroma_log2_weight_denom =
> sh->sh_pred_weight_table.delta_chroma_log2_weight_denom,
> +            .num_l0_weights                 =
> sh->sh_pred_weight_table.num_l0_weights,
> +            .num_l1_weights                 =
> sh->sh_pred_weight_table.num_l1_weights,
> +        },
> +        .sh_flags.bits = {
> +            .sh_alf_enabled_flag                 =
> sh->sh_alf_enabled_flag,
> +            .sh_alf_cb_enabled_flag              =
> sh->sh_alf_cb_enabled_flag,
> +            .sh_alf_cr_enabled_flag              =
> sh->sh_alf_cr_enabled_flag,
> +            .sh_alf_cc_cb_enabled_flag           =
> sh->sh_alf_cc_cb_enabled_flag,
> +            .sh_alf_cc_cr_enabled_flag           =
> sh->sh_alf_cc_cr_enabled_flag,
> +            .sh_lmcs_used_flag                   = sh->sh_lmcs_used_flag,
> +            .sh_explicit_scaling_list_used_flag  =
> sh->sh_explicit_scaling_list_used_flag,
> +            .sh_cabac_init_flag                  = sh->sh_cabac_init_flag,
> +            .sh_collocated_from_l0_flag          =
> sh->sh_collocated_from_l0_flag,
> +            .sh_cu_chroma_qp_offset_enabled_flag =
> sh->sh_cu_chroma_qp_offset_enabled_flag,
> +            .sh_sao_luma_used_flag               =
> sh->sh_sao_luma_used_flag,
> +            .sh_sao_chroma_used_flag             =
> sh->sh_sao_chroma_used_flag,
> +            .sh_deblocking_filter_disabled_flag  =
> sh->sh_deblocking_filter_disabled_flag,
> +            .sh_dep_quant_used_flag              =
> sh->sh_dep_quant_used_flag,
> +            .sh_sign_data_hiding_used_flag       =
> sh->sh_sign_data_hiding_used_flag,
> +            .sh_ts_residual_coding_disabled_flag =
> sh->sh_ts_residual_coding_disabled_flag,
> +        },
> +    };
> +
> +    memset(&slice_param->RefPicList, 0xFF,
> sizeof(slice_param->RefPicList));
> +
> +    nb_list = (sh->sh_slice_type == VVC_SLICE_TYPE_B) ?
> +              2 : (sh->sh_slice_type == VVC_SLICE_TYPE_I ? 0 : 1);
> +    for (int list_idx = 0; list_idx < nb_list; list_idx++) {
> +        RefPicList *rpl = &sc->rpl[list_idx];
> +
> +        for (i = 0; i < rpl->nb_refs; i++)
> +            slice_param->RefPicList[list_idx][i] = get_ref_pic_index(h,
> rpl->ref[i]);
> +    }
> +
> +    for (i = 0; i < 7; i++)
> +        slice_param->sh_alf_aps_id_luma[i] = sh->sh_alf_aps_id_luma[i];
> +
> +    for (i = 0; i < 15; i++) {
> +        slice_param->WPInfo.luma_weight_l0_flag[i]   =
> sh->sh_pred_weight_table.luma_weight_l0_flag[i];
> +        slice_param->WPInfo.chroma_weight_l0_flag[i] =
> sh->sh_pred_weight_table.chroma_weight_l0_flag[i];
> +        slice_param->WPInfo.delta_luma_weight_l0[i]  =
> sh->sh_pred_weight_table.delta_luma_weight_l0[i];
> +        slice_param->WPInfo.luma_offset_l0[i]        =
> sh->sh_pred_weight_table.luma_offset_l0[i];
> +        slice_param->WPInfo.luma_weight_l1_flag[i]   =
> sh->sh_pred_weight_table.luma_weight_l1_flag[i];
> +        slice_param->WPInfo.chroma_weight_l1_flag[i] =
> sh->sh_pred_weight_table.chroma_weight_l1_flag[i];
> +        slice_param->WPInfo.delta_luma_weight_l1[i]  =
> sh->sh_pred_weight_table.delta_luma_weight_l1[i];
> +        slice_param->WPInfo.luma_offset_l1[i]        =
> sh->sh_pred_weight_table.luma_offset_l1[i];
> +    }
> +
> +    for (i = 0; i < 15; i++) {
> +        for (int j = 0; j < 2; j++) {
> +            slice_param->WPInfo.delta_chroma_weight_l0[i][j] =
> sh->sh_pred_weight_table.delta_chroma_weight_l0[i][j];
> +            slice_param->WPInfo.delta_chroma_offset_l0[i][j] =
> sh->sh_pred_weight_table.delta_chroma_offset_l0[i][j];
> +            slice_param->WPInfo.delta_chroma_weight_l1[i][j] =
> sh->sh_pred_weight_table.delta_chroma_weight_l1[i][j];
> +            slice_param->WPInfo.delta_chroma_offset_l1[i][j] =
> sh->sh_pred_weight_table.delta_chroma_offset_l1[i][j];
> +        }
> +    }
> +
> +    err = ff_vaapi_decode_make_slice_buffer(avctx, &pic->pic,
> +                                            &pic->slice_param,
> +
> sizeof(VASliceParameterBufferVVC),
> +                                            buffer, size);
> +    if (err) {
> +        ff_vaapi_decode_cancel(avctx, &pic->pic);
> +        return err;
> +    }
> +
> +    return 0;
> +}
> +
> +static int vaapi_vvc_end_frame(AVCodecContext *avctx)
> +{
> +
> +    const VVCContext        *h = avctx->priv_data;
> +    VVCFrameContext        *fc = &h->fcs[(h->nb_frames + h->nb_fcs) %
> h->nb_fcs];
> +    VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private;
> +    int ret;
> +
> +    ret = ff_vaapi_decode_issue(avctx, &pic->pic);
> +    if (ret < 0)
> +        goto fail;
> +
> +    pic->decode_issued = 1;
> +
> +    return 0;
> +
> +fail:
> +    ff_vaapi_decode_cancel(avctx, &pic->pic);
> +    return ret;
> +}
> +
> +const FFHWAccel ff_vvc_vaapi_hwaccel = {
> +    .p.name               = "vvc_vaapi",
> +    .p.type               = AVMEDIA_TYPE_VIDEO,
> +    .p.id                 = AV_CODEC_ID_VVC,
> +    .p.pix_fmt            = AV_PIX_FMT_VAAPI,
> +    .start_frame          = &vaapi_vvc_start_frame,
> +    .end_frame            = &vaapi_vvc_end_frame,
> +    .decode_slice         = &vaapi_vvc_decode_slice,
> +    .frame_priv_data_size = sizeof(VAAPIDecodePictureVVC),
> +    .init                 = &ff_vaapi_decode_init,
> +    .uninit               = &ff_vaapi_decode_uninit,
> +    .frame_params         = &ff_vaapi_common_frame_params,
> +    .priv_data_size       = sizeof(VAAPIDecodeContext),
> +    .caps_internal        = HWACCEL_CAP_ASYNC_SAFE,
> +};
> diff --git a/libavcodec/version.h b/libavcodec/version.h
> index 06631ffa8c..7aa95fc3f1 100644
> --- a/libavcodec/version.h
> +++ b/libavcodec/version.h
> @@ -29,7 +29,7 @@
>
>  #include "version_major.h"
>
> -#define LIBAVCODEC_VERSION_MINOR   4
> +#define LIBAVCODEC_VERSION_MINOR   5
>  #define LIBAVCODEC_VERSION_MICRO 100
>
>  #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
> diff --git a/libavcodec/vvc/vvcdec.c b/libavcodec/vvc/vvcdec.c
> index f2e269ce76..b204a0c73a 100644
> --- a/libavcodec/vvc/vvcdec.c
> +++ b/libavcodec/vvc/vvcdec.c
> @@ -29,6 +29,7 @@
>  #include "libavutil/cpu.h"
>  #include "libavutil/thread.h"
>
> +#include "config_components.h"
>  #include "vvcdec.h"
>  #include "vvc_ctu.h"
>  #include "vvc_data.h"
> @@ -724,14 +725,20 @@ static int slice_start(SliceContext *sc, VVCContext
> *s, VVCFrameContext *fc,
>
>  static enum AVPixelFormat get_format(AVCodecContext *avctx, const VVCSPS
> *sps)
>  {
> -#define HWACCEL_MAX 0
> +#define HWACCEL_MAX CONFIG_VVC_VAAPI_HWACCEL
>
>      enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
>
>      switch (sps->pix_fmt) {
>      case AV_PIX_FMT_YUV420P:
> +#if CONFIG_VVC_VAAPI_HWACCEL
> +        *fmt++ = AV_PIX_FMT_VAAPI;
> +#endif
>          break;
>      case AV_PIX_FMT_YUV420P10:
> +#if CONFIG_VVC_VAAPI_HWACCEL
> +        *fmt++ = AV_PIX_FMT_VAAPI;
> +#endif
>          break;
>      }
>
> @@ -1100,4 +1107,10 @@ const FFCodec ff_vvc_decoder = {
>      .caps_internal  = FF_CODEC_CAP_EXPORTS_CROPPING |
> FF_CODEC_CAP_INIT_CLEANUP |
>                        FF_CODEC_CAP_AUTO_THREADS,
>      .p.profiles     = NULL_IF_CONFIG_SMALL(ff_vvc_profiles),
> +    .hw_configs     = (const AVCodecHWConfigInternal *const []) {
> +#if CONFIG_VVC_VAAPI_HWACCEL
> +                    HWACCEL_VAAPI(vvc),
> +#endif
> +    NULL
> +    },
>  };
> --
> 2.25.1
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>
Wang, Fei W April 3, 2024, 3:31 a.m. UTC | #2
On Tue, 2024-04-02 at 20:48 +0800, Nuo Mi wrote:
> 
> 
> On Thu, Mar 28, 2024 at 9:27 AM <fei.w.wang-at-intel.com@ffmpeg.org>
> wrote:
> > From: Fei Wang <fei.w.wang@intel.com>
> > 
> > Signed-off-by: Fei Wang <fei.w.wang@intel.com>
> > ---
> >  Changelog                 |   4 +
> >  configure                 |   3 +
> >  libavcodec/Makefile       |   1 +
> >  libavcodec/hwaccels.h     |   1 +
> >  libavcodec/vaapi_decode.c |   7 +
> >  libavcodec/vaapi_vvc.c    | 657
> > ++++++++++++++++++++++++++++++++++++++
> >  libavcodec/version.h      |   2 +-
> >  libavcodec/vvc/vvcdec.c   |  15 +-
> >  8 files changed, 688 insertions(+), 2 deletions(-)
> >  create mode 100644 libavcodec/vaapi_vvc.c
> > 
> > diff --git a/Changelog b/Changelog
> > index e83a00e35c..3108e65558 100644
> > --- a/Changelog
> > +++ b/Changelog
> > @@ -1,6 +1,10 @@
> >  Entries are sorted chronologically from oldest to youngest within
> > each release,
> >  releases are sorted from youngest to oldest.
> > 
> > +version <next>:
> > +- VVC VAAPI decoder
> > +
> > +
> >  version 7.0:
> >  - DXV DXT1 encoder
> >  - LEAD MCMP decoder
> > diff --git a/configure b/configure
> > index 2a1d22310b..d902c9adc8 100755
> > --- a/configure
> > +++ b/configure
> > @@ -3258,6 +3258,8 @@ vp9_vdpau_hwaccel_deps="vdpau
> > VdpPictureInfoVP9"
> >  vp9_vdpau_hwaccel_select="vp9_decoder"
> >  vp9_videotoolbox_hwaccel_deps="videotoolbox"
> >  vp9_videotoolbox_hwaccel_select="vp9_decoder"
> > +vvc_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferVVC"
> > +vvc_vaapi_hwaccel_select="vvc_decoder"
> >  wmv3_d3d11va_hwaccel_select="vc1_d3d11va_hwaccel"
> >  wmv3_d3d11va2_hwaccel_select="vc1_d3d11va2_hwaccel"
> >  wmv3_d3d12va_hwaccel_select="vc1_d3d12va_hwaccel"
> > @@ -7250,6 +7252,7 @@ if enabled vaapi; then
> >      check_cpp_condition vaapi_1 "va/va.h" "VA_CHECK_VERSION(1, 0,
> > 0)"
> > 
> >      check_type "va/va.h va/va_dec_hevc.h"
> > "VAPictureParameterBufferHEVC"
> > +    check_type "va/va.h va/va_dec_vvc.h"
> > "VAPictureParameterBufferVVC"
> >      check_struct "va/va.h" "VADecPictureParameterBufferVP9"
> > bit_depth
> >      check_struct "va/va.h" "VADecPictureParameterBufferAV1"
> > bit_depth_idx
> >      check_type   "va/va.h va/va_vpp.h"
> > "VAProcFilterParameterBufferHDRToneMapping"
> > diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> > index 9ce6d445c1..343b037636 100644
> > --- a/libavcodec/Makefile
> > +++ b/libavcodec/Makefile
> > @@ -1054,6 +1054,7 @@ OBJS-$(CONFIG_VP9_VAAPI_HWACCEL)          +=
> > vaapi_vp9.o
> >  OBJS-$(CONFIG_VP9_VDPAU_HWACCEL)          += vdpau_vp9.o
> >  OBJS-$(CONFIG_VP9_VIDEOTOOLBOX_HWACCEL)   += videotoolbox_vp9.o
> >  OBJS-$(CONFIG_VP8_QSV_HWACCEL)            += qsvdec.o
> > +OBJS-$(CONFIG_VVC_VAAPI_HWACCEL)          += vaapi_vvc.o
> > 
> >  # Objects duplicated from other libraries for shared builds
> >  SHLIBOBJS                              += log2_tab.o reverse.o
> > diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h
> > index 5171e4c7d7..88d6b9a9b5 100644
> > --- a/libavcodec/hwaccels.h
> > +++ b/libavcodec/hwaccels.h
> > @@ -82,6 +82,7 @@ extern const struct FFHWAccel
> > ff_vp9_nvdec_hwaccel;
> >  extern const struct FFHWAccel ff_vp9_vaapi_hwaccel;
> >  extern const struct FFHWAccel ff_vp9_vdpau_hwaccel;
> >  extern const struct FFHWAccel ff_vp9_videotoolbox_hwaccel;
> > +extern const struct FFHWAccel ff_vvc_vaapi_hwaccel;
> >  extern const struct FFHWAccel ff_wmv3_d3d11va_hwaccel;
> >  extern const struct FFHWAccel ff_wmv3_d3d11va2_hwaccel;
> >  extern const struct FFHWAccel ff_wmv3_d3d12va_hwaccel;
> > diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c
> > index 1b1972a2a9..ceeb1f1a12 100644
> > --- a/libavcodec/vaapi_decode.c
> > +++ b/libavcodec/vaapi_decode.c
> > @@ -455,6 +455,9 @@ static const struct {
> >      MAP(AV1,         AV1_MAIN,        AV1Profile0),
> >      MAP(AV1,         AV1_HIGH,        AV1Profile1),
> >  #endif
> > +#if VA_CHECK_VERSION(1, 22, 0)
> > +    MAP(H266,        VVC_MAIN_10,     VVCMain10),
> > +#endif
> > 
> >  #undef MAP
> >  };
> > @@ -627,6 +630,10 @@ static int
> > vaapi_decode_make_config(AVCodecContext *avctx,
> >          case AV_CODEC_ID_VP8:
> >              frames->initial_pool_size += 3;
> >              break;
> > +        case AV_CODEC_ID_H266:
> > +            // Add additional 16 for maximum 16 frames delay in
> > vvc native decode.
> > +            frames->initial_pool_size += 32;
> 
> One frame of 8k YUV444, 10 bits, is about 200MB. Thirty-two frames
> amount to approximately 6GB.Can we dynamically allocate the buffer
> pool? 

It's processing in other thread:
https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=11316

> 
> The software decoder requires a delay of 16 frames to ensure full
> utilization of CPUs. In the future, we may consider increasing this
> to 32 or even 64 frames.
> However, for hardware decoding, given that all processing occurs on
> the GPU, we do not require any delay.

The delay can avoid sync hardware task immediately once it is
submitted, which can avoid hardware switch tasks frequently and drop
performance. If the number will increase, I'd prefer to set it as an
option and diff the default value for hardware with software.

Thanks
Fei
> 
> > +            break;
> >          default:
> >              frames->initial_pool_size += 2;
> >          }
> > diff --git a/libavcodec/vaapi_vvc.c b/libavcodec/vaapi_vvc.c
> > new file mode 100644
> > index 0000000000..6141005688
> > --- /dev/null
> > +++ b/libavcodec/vaapi_vvc.c
> > @@ -0,0 +1,657 @@
> > +/*
> > + * VVC HW decode acceleration through VA API
> > + *
> > + * Copyright (c) 2024 Intel Corporation
> > + *
> > + * This file is part of FFmpeg.
> > + *
> > + * FFmpeg is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2.1 of the License, or (at your option) any later
> > version.
> > + *
> > + * FFmpeg is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General
> > Public
> > + * License along with FFmpeg; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> > 02110-1301 USA
> > + */
> > +
> > +#include <va/va.h>
> > +#include <va/va_dec_vvc.h>
> > +
> > +#include "vvc/vvcdec.h"
> > +#include "vvc/vvc_refs.h"
> > +#include "hwaccel_internal.h"
> > +#include "vaapi_decode.h"
> > +
> > +typedef struct VAAPIDecodePictureVVC {
> > +    VAAPIDecodePicture          pic;
> > +    VAPictureParameterBufferVVC pic_param;
> > +    VASliceParameterBufferVVC   slice_param;
> > +    int                         decode_issued;
> > +} VAAPIDecodePictureVVC;
> > +
> > +static void init_vaapi_pic(VAPictureVVC *va_pic)
> > +{
> > +    va_pic->picture_id    = VA_INVALID_ID;
> > +    va_pic->flags         = VA_PICTURE_VVC_INVALID;
> > +    va_pic->pic_order_cnt = 0;
> > +}
> > +
> > +static void fill_vaapi_pic(VAPictureVVC *va_pic, const VVCFrame
> > *pic)
> > +{
> > +    va_pic->picture_id    = ff_vaapi_get_surface_id(pic->frame);
> > +    va_pic->pic_order_cnt = pic->poc;
> > +    va_pic->flags         = 0;
> > +
> > +    if (pic->flags & VVC_FRAME_FLAG_LONG_REF)
> > +        va_pic->flags |= VA_PICTURE_VVC_LONG_TERM_REFERENCE;
> > +}
> > +
> > +static void fill_vaapi_reference_frames(const VVCFrameContext *h,
> > VAPictureParameterBufferVVC *pp)
> > +{
> > +    const VVCFrame *current_picture = h->ref;
> > +    int i, j;
> > +
> > +    for (i = 0, j = 0; i < FF_ARRAY_ELEMS(pp->ReferenceFrames);
> > i++) {
> > +        const VVCFrame *frame = NULL;
> > +
> > +        while (!frame && j < FF_ARRAY_ELEMS(h->DPB)) {
> > +            if ((&h->DPB[j] != current_picture ) &&
> > +                (h->DPB[j].flags & (VVC_FRAME_FLAG_LONG_REF |
> > VVC_FRAME_FLAG_SHORT_REF)))
> > +                frame = &h->DPB[j];
> > +            j++;
> > +        }
> > +
> > +        init_vaapi_pic(&pp->ReferenceFrames[i]);
> > +
> > +        if (frame) {
> > +            VAAPIDecodePictureVVC *pic;
> > +            fill_vaapi_pic(&pp->ReferenceFrames[i], frame);
> > +            pic = frame->hwaccel_picture_private;
> > +            if (!pic->decode_issued)
> > +               pp->ReferenceFrames[i].flags |=
> > VA_PICTURE_VVC_UNAVAILABLE_REFERENCE;
> > +        }
> > +    }
> > +}
> > +
> > +static int vaapi_vvc_start_frame(AVCodecContext          *avctx,
> > +                                 av_unused const uint8_t *buffer,
> > +                                 av_unused uint32_t       size)
> > +{
> > +    const VVCContext                    *h = avctx->priv_data;
> > +    VVCFrameContext                    *fc = &h->fcs[(h->nb_frames 
> > + h->nb_fcs) % h->nb_fcs];
> > +    const H266RawSPS                  *sps = fc->ps.sps->r;
> > +    const H266RawPPS                  *pps = fc->ps.pps->r;
> > +    const H266RawPictureHeader         *ph = fc->ps.ph.r;
> > +    VAAPIDecodePictureVVC             *pic = fc->ref-
> > >hwaccel_picture_private;
> > +    VAPictureParameterBufferVVC *pic_param = &pic->pic_param;
> > +    uint16_t tile_dim, exp_slice_height_in_ctus[VVC_MAX_SLICES] =
> > {0};
> > +    int i, j, k, err;
> > +
> > +    pic->pic.output_surface = ff_vaapi_get_surface_id(fc->ref-
> > >frame);
> > +
> > +    *pic_param = (VAPictureParameterBufferVVC) {
> > +        .pps_pic_width_in_luma_samples                 = pps-
> > >pps_pic_width_in_luma_samples,
> > +        .pps_pic_height_in_luma_samples                = pps-
> > >pps_pic_height_in_luma_samples,
> > +        .sps_num_subpics_minus1                        = sps-
> > >sps_num_subpics_minus1,
> > +        .sps_chroma_format_idc                         = sps-
> > >sps_chroma_format_idc,
> > +        .sps_bitdepth_minus8                           = sps-
> > >sps_bitdepth_minus8,
> > +        .sps_log2_ctu_size_minus5                      = sps-
> > >sps_log2_ctu_size_minus5,
> > +        .sps_log2_min_luma_coding_block_size_minus2    = sps-
> > >sps_log2_min_luma_coding_block_size_minus2,
> > +        .sps_log2_transform_skip_max_size_minus2       = sps-
> > >sps_log2_transform_skip_max_size_minus2,
> > +        .sps_six_minus_max_num_merge_cand              = sps-
> > >sps_six_minus_max_num_merge_cand,
> > +        .sps_five_minus_max_num_subblock_merge_cand    = sps-
> > >sps_five_minus_max_num_subblock_merge_cand,
> > +        .sps_max_num_merge_cand_minus_max_num_gpm_cand = sps-
> > >sps_max_num_merge_cand_minus_max_num_gpm_cand,
> > +        .sps_log2_parallel_merge_level_minus2          = sps-
> > >sps_log2_parallel_merge_level_minus2,
> > +        .sps_min_qp_prime_ts                           = sps-
> > >sps_min_qp_prime_ts,
> > +        .sps_six_minus_max_num_ibc_merge_cand          = sps-
> > >sps_six_minus_max_num_ibc_merge_cand,
> > +        .sps_num_ladf_intervals_minus2                 = sps-
> > >sps_num_ladf_intervals_minus2,
> > +        .sps_ladf_lowest_interval_qp_offset            = sps-
> > >sps_ladf_lowest_interval_qp_offset,
> > +        .sps_flags.bits = {
> > +            .sps_subpic_info_present_flag                         
> >         = sps->sps_subpic_info_present_flag,
> > +            .sps_independent_subpics_flag                         
> >         = sps->sps_independent_subpics_flag,
> > +            .sps_subpic_same_size_flag                           
> >          = sps->sps_subpic_same_size_flag,
> > +            .sps_entropy_coding_sync_enabled_flag                 
> >         = sps->sps_entropy_coding_sync_enabled_flag,
> > +            .sps_qtbtt_dual_tree_intra_flag                       
> >         = sps->sps_qtbtt_dual_tree_intra_flag,
> > +            .sps_max_luma_transform_size_64_flag                 
> >          = sps->sps_max_luma_transform_size_64_flag,
> > +            .sps_transform_skip_enabled_flag                     
> >          = sps->sps_transform_skip_enabled_flag,
> > +            .sps_bdpcm_enabled_flag                               
> >         = sps->sps_bdpcm_enabled_flag,
> > +            .sps_mts_enabled_flag                                 
> >         = sps->sps_mts_enabled_flag,
> > +            .sps_explicit_mts_intra_enabled_flag                 
> >          = sps->sps_explicit_mts_intra_enabled_flag,
> > +            .sps_explicit_mts_inter_enabled_flag                 
> >          = sps->sps_explicit_mts_inter_enabled_flag,
> > +            .sps_lfnst_enabled_flag                               
> >         = sps->sps_lfnst_enabled_flag,
> > +            .sps_joint_cbcr_enabled_flag                         
> >          = sps->sps_joint_cbcr_enabled_flag,
> > +            .sps_same_qp_table_for_chroma_flag                   
> >          = sps->sps_same_qp_table_for_chroma_flag,
> > +            .sps_sao_enabled_flag                                 
> >         = sps->sps_sao_enabled_flag,
> > +            .sps_alf_enabled_flag                                 
> >         = sps->sps_alf_enabled_flag,
> > +            .sps_ccalf_enabled_flag                               
> >         = sps->sps_alf_enabled_flag,
> > +            .sps_lmcs_enabled_flag                               
> >          = sps->sps_lmcs_enabled_flag,
> > +            .sps_sbtmvp_enabled_flag                             
> >          = sps->sps_sbtmvp_enabled_flag,
> > +            .sps_amvr_enabled_flag                               
> >          = sps->sps_amvr_enabled_flag,
> > +            .sps_smvd_enabled_flag                               
> >          = sps->sps_smvd_enabled_flag,
> > +            .sps_mmvd_enabled_flag                               
> >          = sps->sps_mmvd_enabled_flag,
> > +            .sps_sbt_enabled_flag                                 
> >         = sps->sps_sbt_enabled_flag,
> > +            .sps_affine_enabled_flag                             
> >          = sps->sps_affine_enabled_flag,
> > +            .sps_6param_affine_enabled_flag                       
> >         = sps->sps_6param_affine_enabled_flag,
> > +            .sps_affine_amvr_enabled_flag                         
> >         = sps->sps_affine_amvr_enabled_flag,
> > +            .sps_affine_prof_enabled_flag                         
> >         = sps->sps_affine_prof_enabled_flag,
> > +            .sps_bcw_enabled_flag                                 
> >         = sps->sps_bcw_enabled_flag,
> > +            .sps_ciip_enabled_flag                               
> >          = sps->sps_ciip_enabled_flag,
> > +            .sps_gpm_enabled_flag                                 
> >         = sps->sps_gpm_enabled_flag,
> > +            .sps_isp_enabled_flag                                 
> >         = sps->sps_isp_enabled_flag,
> > +            .sps_mrl_enabled_flag                                 
> >         = sps->sps_mrl_enabled_flag,
> > +            .sps_mip_enabled_flag                                 
> >         = sps->sps_mip_enabled_flag,
> > +            .sps_cclm_enabled_flag                               
> >          = sps->sps_cclm_enabled_flag,
> > +            .sps_chroma_horizontal_collocated_flag               
> >          = sps->sps_chroma_horizontal_collocated_flag,
> > +            .sps_chroma_vertical_collocated_flag                 
> >          = sps->sps_chroma_vertical_collocated_flag,
> > +            .sps_palette_enabled_flag                             
> >         = sps->sps_palette_enabled_flag,
> > +            .sps_act_enabled_flag                                 
> >         = sps->sps_act_enabled_flag,
> > +            .sps_ibc_enabled_flag                                 
> >         = sps->sps_ibc_enabled_flag,
> > +            .sps_ladf_enabled_flag                               
> >          = sps->sps_ladf_enabled_flag,
> > +            .sps_explicit_scaling_list_enabled_flag               
> >         = sps->sps_explicit_scaling_list_enabled_flag,
> > +            .sps_scaling_matrix_for_lfnst_disabled_flag           
> >         = sps->sps_scaling_matrix_for_lfnst_disabled_flag,
> > +           
> > .sps_scaling_matrix_for_alternative_colour_space_disabled_flag =
> > sps->sps_scaling_matrix_for_alternative_colour_space_disabled_flag,
> > +            .sps_scaling_matrix_designated_colour_space_flag     
> >          = sps->sps_scaling_matrix_designated_colour_space_flag,
> > +            .sps_virtual_boundaries_enabled_flag                 
> >          = sps->sps_virtual_boundaries_enabled_flag,
> > +            .sps_virtual_boundaries_present_flag                 
> >          = sps->sps_virtual_boundaries_present_flag,
> > +        },
> > +        .NumVerVirtualBoundaries               = sps-
> > >sps_virtual_boundaries_present_flag ?
> > +                                                 sps-
> > >sps_num_ver_virtual_boundaries :
> > +                                                 ph-
> > >ph_num_ver_virtual_boundaries,
> > +        .NumHorVirtualBoundaries               = sps-
> > >sps_virtual_boundaries_present_flag ?
> > +                                                 sps-
> > >sps_num_hor_virtual_boundaries :
> > +                                                 ph-
> > >ph_num_hor_virtual_boundaries,
> > +        .pps_scaling_win_left_offset           = pps-
> > >pps_scaling_win_left_offset,
> > +        .pps_scaling_win_right_offset          = pps-
> > >pps_scaling_win_right_offset,
> > +        .pps_scaling_win_top_offset            = pps-
> > >pps_scaling_win_top_offset,
> > +        .pps_scaling_win_bottom_offset         = pps-
> > >pps_scaling_win_bottom_offset,
> > +        .pps_num_exp_tile_columns_minus1       = pps-
> > >pps_num_exp_tile_columns_minus1,
> > +        .pps_num_exp_tile_rows_minus1          = pps-
> > >pps_num_exp_tile_rows_minus1,
> > +        .pps_num_slices_in_pic_minus1          = pps-
> > >pps_num_slices_in_pic_minus1,
> > +        .pps_pic_width_minus_wraparound_offset = pps-
> > >pps_pic_width_minus_wraparound_offset,
> > +        .pps_cb_qp_offset                      = pps-
> > >pps_cb_qp_offset,
> > +        .pps_cr_qp_offset                      = pps-
> > >pps_cr_qp_offset,
> > +        .pps_joint_cbcr_qp_offset_value        = pps-
> > >pps_joint_cbcr_qp_offset_value,
> > +        .pps_chroma_qp_offset_list_len_minus1  = pps-
> > >pps_chroma_qp_offset_list_len_minus1,
> > +        .pps_flags.bits = {
> > +            .pps_loop_filter_across_tiles_enabled_flag   = pps-
> > >pps_loop_filter_across_tiles_enabled_flag,
> > +            .pps_rect_slice_flag                         = pps-
> > >pps_rect_slice_flag,
> > +            .pps_single_slice_per_subpic_flag            = pps-
> > >pps_single_slice_per_subpic_flag,
> > +            .pps_loop_filter_across_slices_enabled_flag  = pps-
> > >pps_loop_filter_across_slices_enabled_flag,
> > +            .pps_weighted_pred_flag                      = pps-
> > >pps_weighted_pred_flag,
> > +            .pps_weighted_bipred_flag                    = pps-
> > >pps_weighted_bipred_flag,
> > +            .pps_ref_wraparound_enabled_flag             = pps-
> > >pps_ref_wraparound_enabled_flag,
> > +            .pps_cu_qp_delta_enabled_flag                = pps-
> > >pps_cu_qp_delta_enabled_flag,
> > +            .pps_cu_chroma_qp_offset_list_enabled_flag   = pps-
> > >pps_cu_chroma_qp_offset_list_enabled_flag,
> > +            .pps_deblocking_filter_override_enabled_flag = pps-
> > >pps_deblocking_filter_override_enabled_flag,
> > +            .pps_deblocking_filter_disabled_flag         = pps-
> > >pps_deblocking_filter_disabled_flag,
> > +            .pps_dbf_info_in_ph_flag                     = pps-
> > >pps_dbf_info_in_ph_flag,
> > +            .pps_sao_info_in_ph_flag                     = pps-
> > >pps_sao_info_in_ph_flag,
> > +            .pps_alf_info_in_ph_flag                     = pps-
> > >pps_alf_info_in_ph_flag,
> > +        },
> > +        .ph_lmcs_aps_id                                = ph-
> > >ph_lmcs_aps_id,
> > +        .ph_scaling_list_aps_id                        = ph-
> > >ph_scaling_list_aps_id,
> > +        .ph_log2_diff_min_qt_min_cb_intra_slice_luma   = ph-
> > >ph_log2_diff_min_qt_min_cb_intra_slice_luma,
> > +        .ph_max_mtt_hierarchy_depth_intra_slice_luma   = ph-
> > >ph_max_mtt_hierarchy_depth_intra_slice_luma,
> > +        .ph_log2_diff_max_bt_min_qt_intra_slice_luma   = ph-
> > >ph_log2_diff_max_bt_min_qt_intra_slice_luma,
> > +        .ph_log2_diff_max_tt_min_qt_intra_slice_luma   = ph-
> > >ph_log2_diff_max_tt_min_qt_intra_slice_luma,
> > +        .ph_log2_diff_min_qt_min_cb_intra_slice_chroma = ph-
> > >ph_log2_diff_min_qt_min_cb_intra_slice_chroma,
> > +        .ph_max_mtt_hierarchy_depth_intra_slice_chroma = ph-
> > >ph_max_mtt_hierarchy_depth_intra_slice_chroma,
> > +        .ph_log2_diff_max_bt_min_qt_intra_slice_chroma = ph-
> > >ph_log2_diff_max_bt_min_qt_intra_slice_chroma,
> > +        .ph_log2_diff_max_tt_min_qt_intra_slice_chroma = ph-
> > >ph_log2_diff_max_tt_min_qt_intra_slice_chroma,
> > +        .ph_cu_qp_delta_subdiv_intra_slice             = ph-
> > >ph_cu_qp_delta_subdiv_intra_slice,
> > +        .ph_cu_chroma_qp_offset_subdiv_intra_slice     = ph-
> > >ph_cu_chroma_qp_offset_subdiv_intra_slice,
> > +        .ph_log2_diff_min_qt_min_cb_inter_slice        = ph-
> > >ph_log2_diff_min_qt_min_cb_inter_slice,
> > +        .ph_max_mtt_hierarchy_depth_inter_slice        = ph-
> > >ph_max_mtt_hierarchy_depth_inter_slice,
> > +        .ph_log2_diff_max_bt_min_qt_inter_slice        = ph-
> > >ph_log2_diff_max_bt_min_qt_inter_slice,
> > +        .ph_log2_diff_max_tt_min_qt_inter_slice        = ph-
> > >ph_log2_diff_max_tt_min_qt_inter_slice,
> > +        .ph_cu_qp_delta_subdiv_inter_slice             = ph-
> > >ph_cu_qp_delta_subdiv_inter_slice,
> > +        .ph_cu_chroma_qp_offset_subdiv_inter_slice     = ph-
> > >ph_cu_chroma_qp_offset_subdiv_inter_slice,
> > +        .ph_flags.bits= {
> > +            .ph_non_ref_pic_flag                   = ph-
> > >ph_non_ref_pic_flag,
> > +            .ph_alf_enabled_flag                   = ph-
> > >ph_alf_enabled_flag,
> > +            .ph_alf_cb_enabled_flag                = ph-
> > >ph_alf_cb_enabled_flag,
> > +            .ph_alf_cr_enabled_flag                = ph-
> > >ph_alf_cr_enabled_flag,
> > +            .ph_alf_cc_cb_enabled_flag             = ph-
> > >ph_alf_cc_cb_enabled_flag,
> > +            .ph_alf_cc_cr_enabled_flag             = ph-
> > >ph_alf_cc_cr_enabled_flag,
> > +            .ph_lmcs_enabled_flag                  = ph-
> > >ph_lmcs_enabled_flag,
> > +            .ph_chroma_residual_scale_flag         = ph-
> > >ph_chroma_residual_scale_flag,
> > +            .ph_explicit_scaling_list_enabled_flag = ph-
> > >ph_explicit_scaling_list_enabled_flag,
> > +            .ph_virtual_boundaries_present_flag    = ph-
> > >ph_virtual_boundaries_present_flag,
> > +            .ph_temporal_mvp_enabled_flag          = ph-
> > >ph_temporal_mvp_enabled_flag,
> > +            .ph_mmvd_fullpel_only_flag             = ph-
> > >ph_mmvd_fullpel_only_flag,
> > +            .ph_mvd_l1_zero_flag                   = ph-
> > >ph_mvd_l1_zero_flag,
> > +            .ph_bdof_disabled_flag                 = ph-
> > >ph_bdof_disabled_flag,
> > +            .ph_dmvr_disabled_flag                 = ph-
> > >ph_dmvr_disabled_flag,
> > +            .ph_prof_disabled_flag                 = ph-
> > >ph_prof_disabled_flag,
> > +            .ph_joint_cbcr_sign_flag               = ph-
> > >ph_joint_cbcr_sign_flag,
> > +            .ph_sao_luma_enabled_flag              = ph-
> > >ph_sao_luma_enabled_flag,
> > +            .ph_sao_chroma_enabled_flag            = ph-
> > >ph_sao_chroma_enabled_flag,
> > +            .ph_deblocking_filter_disabled_flag    = ph-
> > >ph_deblocking_filter_disabled_flag,
> > +        },
> > +        .PicMiscFlags.fields = {
> > +            .IntraPicFlag = pps->pps_mixed_nalu_types_in_pic_flag
> > ? 0 : IS_IRAP(h) ? 1 : 0,
> > +        }
> > +    };
> > +
> > +    fill_vaapi_pic(&pic_param->CurrPic, fc->ref);
> > +    fill_vaapi_reference_frames(fc, pic_param);
> > +
> > +    for (i = 0; i < VVC_MAX_SAMPLE_ARRAYS; i++)
> > +        for (j = 0; j < VVC_MAX_POINTS_IN_QP_TABLE; j++)
> > +            pic_param->ChromaQpTable[i][j] = fc->ps.sps-
> > >chroma_qp_table[i][j];
> > +    for (i = 0; i < 4; i++) {
> > +        pic_param->sps_ladf_qp_offset[i]              = sps-
> > >sps_ladf_qp_offset[i];
> > +        pic_param->sps_ladf_delta_threshold_minus1[i] = sps-
> > >sps_ladf_delta_threshold_minus1[i];
> > +    }
> > +
> > +    for (i = 0; i < (sps->sps_virtual_boundaries_present_flag ?
> > sps->sps_num_ver_virtual_boundaries : ph-
> > >ph_num_ver_virtual_boundaries); i++) {
> > +        pic_param->VirtualBoundaryPosX[i] = (sps-
> > >sps_virtual_boundaries_present_flag ?
> > +                                            (sps-
> > >sps_virtual_boundary_pos_x_minus1[ i ] + 1) :
> > +                                            (ph-
> > >ph_virtual_boundary_pos_x_minus1[i] + 1)) * 8;
> > +    }
> > +
> > +    for (i = 0; i < (sps->sps_virtual_boundaries_present_flag ?
> > sps->sps_num_hor_virtual_boundaries : ph-
> > >ph_num_hor_virtual_boundaries); i++) {
> > +        pic_param->VirtualBoundaryPosY[i] = (sps-
> > >sps_virtual_boundaries_present_flag ?
> > +                                            (sps-
> > >sps_virtual_boundary_pos_y_minus1[ i ] + 1) :
> > +                                            (ph-
> > >ph_virtual_boundary_pos_y_minus1[i] + 1)) * 8;
> > +    }
> > +
> > +    for (i = 0; i < 6; i++) {
> > +        pic_param->pps_cb_qp_offset_list[i]         = pps-
> > >pps_cb_qp_offset_list[i];
> > +        pic_param->pps_cr_qp_offset_list[i]         = pps-
> > >pps_cr_qp_offset_list[i];
> > +        pic_param->pps_joint_cbcr_qp_offset_list[i] = pps-
> > >pps_joint_cbcr_qp_offset_list[i];
> > +    }
> > +
> > +    err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
> > +                                           
> > VAPictureParameterBufferType,
> > +                                            &pic->pic_param,
> > sizeof(VAPictureParameterBufferVVC));
> > +    if (err < 0)
> > +        goto fail;
> > +
> > +    for (i = 0; i <= sps->sps_num_subpics_minus1 && sps-
> > >sps_subpic_info_present_flag; i++) {
> > +        VASubPicVVC subpic_param = {
> > +            .sps_subpic_ctu_top_left_x = sps-
> > >sps_subpic_ctu_top_left_x[i],
> > +            .sps_subpic_ctu_top_left_y = sps-
> > >sps_subpic_ctu_top_left_y[i],
> > +            .sps_subpic_width_minus1   = sps-
> > >sps_subpic_width_minus1[i],
> > +            .sps_subpic_height_minus1  = sps-
> > >sps_subpic_height_minus1[i],
> > +            .SubpicIdVal               = pps->sub_pic_id_val[i],
> > +            .subpic_flags.bits = {
> > +                .sps_subpic_treated_as_pic_flag             = sps-
> > >sps_subpic_treated_as_pic_flag[i],
> > +                .sps_loop_filter_across_subpic_enabled_flag = sps-
> > >sps_loop_filter_across_subpic_enabled_flag[i],
> > +            }
> > +        };
> > +        err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
> > +                                               
> > VASubPicBufferType,
> > +                                                &subpic_param,
> > sizeof(VASubPicVVC));
> > +        if (err < 0)
> > +            goto fail;
> > +    }
> > +
> > +    for (i = 0; i < VVC_MAX_ALF_COUNT; i++) {
> > +        const VVCALF *alf_list = h->ps.alf_list[i];
> > +        if (alf_list) {
> > +            const H266RawAPS *alf = alf_list->r;
> > +            VAAlfDataVVC alf_param = {
> > +                .aps_adaptation_parameter_set_id = i,
> > +                .alf_luma_num_filters_signalled_minus1 = alf-
> > >alf_luma_num_filters_signalled_minus1,
> > +                .alf_chroma_num_alt_filters_minus1     = alf-
> > >alf_chroma_num_alt_filters_minus1,
> > +                .alf_cc_cb_filters_signalled_minus1    = alf-
> > >alf_cc_cb_filters_signalled_minus1,
> > +                .alf_cc_cr_filters_signalled_minus1    = alf-
> > >alf_cc_cr_filters_signalled_minus1,
> > +                .alf_flags.bits = {
> > +                    .alf_luma_filter_signal_flag   = alf-
> > >alf_luma_filter_signal_flag,
> > +                    .alf_chroma_filter_signal_flag = alf-
> > >alf_chroma_filter_signal_flag,
> > +                    .alf_cc_cb_filter_signal_flag  = alf-
> > >alf_cc_cb_filter_signal_flag,
> > +                    .alf_cc_cr_filter_signal_flag  = alf-
> > >alf_cc_cr_filter_signal_flag,
> > +                    .alf_luma_clip_flag            = alf-
> > >alf_luma_clip_flag,
> > +                    .alf_chroma_clip_flag          = alf-
> > >alf_chroma_clip_flag,
> > +                }
> > +            };
> > +
> > +            for (j = 0; j < 25; j++)
> > +                alf_param.alf_luma_coeff_delta_idx[j] = alf-
> > >alf_luma_coeff_delta_idx[j];
> > +
> > +            for (j = 0; j < 25; j++) {
> > +                for (k = 0; k < 12; k++) {
> > +                    alf_param.filtCoeff[j][k]         = alf-
> > >alf_luma_coeff_abs[j][k] * (1 - 2 * alf-
> > >alf_luma_coeff_sign[j][k]);
> > +                    alf_param.alf_luma_clip_idx[j][k] = alf-
> > >alf_luma_clip_idx[j][k];
> > +                }
> > +            }
> > +
> > +            for (j = 0; j < 8; j++) {
> > +                for (k = 0; k < 6; k++) {
> > +                    alf_param.AlfCoeffC[j][k]           = alf-
> > >alf_chroma_coeff_abs[j][k] * (1 - 2 * alf-
> > >alf_chroma_coeff_sign[j][k]);
> > +                    alf_param.alf_chroma_clip_idx[j][k] = alf-
> > >alf_chroma_clip_idx[j][k];
> > +                }
> > +            }
> > +
> > +            for (j = 0; j < 4; j++) {
> > +                for (k = 0; k < 7; k++) {
> > +                    if (alf->alf_cc_cb_mapped_coeff_abs[j][k])
> > +                        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));
> > +                    if (alf->alf_cc_cr_mapped_coeff_abs[j][k])
> > +                        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));
> > +                }
> > +            }
> > +
> > +            err = ff_vaapi_decode_make_param_buffer(avctx, &pic-
> > >pic,
> > +                                                   
> > VAAlfBufferType,
> > +                                                    &alf_param,
> > sizeof(VAAlfDataVVC));
> > +            if (err < 0)
> > +                goto fail;
> > +        }
> > +    }
> > +
> > +    for (i = 0; i < VVC_MAX_LMCS_COUNT; i++) {
> > +        const H266RawAPS *lmcs = h->ps.lmcs_list[i];
> > +        if (lmcs) {
> > +            VALmcsDataVVC lmcs_param = {
> > +                .aps_adaptation_parameter_set_id = i,
> > +                .lmcs_min_bin_idx                = lmcs-
> > >lmcs_min_bin_idx,
> > +                .lmcs_delta_max_bin_idx          = lmcs-
> > >lmcs_delta_max_bin_idx,
> > +                .lmcsDeltaCrs                    = (1 - 2 * lmcs-
> > >lmcs_delta_sign_crs_flag) * lmcs->lmcs_delta_abs_crs,
> > +            };
> > +
> > +            for (j = lmcs->lmcs_min_bin_idx; j <= 15 - lmcs-
> > >lmcs_delta_max_bin_idx; j++)
> > +                lmcs_param.lmcsDeltaCW[j] = (1 - 2 * lmcs-
> > >lmcs_delta_sign_cw_flag[j]) * lmcs->lmcs_delta_abs_cw[j];
> > +
> > +            err = ff_vaapi_decode_make_param_buffer(avctx, &pic-
> > >pic,
> > +                                                   
> > VALmcsBufferType,
> > +                                                    &lmcs_param,
> > sizeof(VALmcsDataVVC));
> > +            if (err < 0)
> > +                goto fail;
> > +        }
> > +    }
> > +
> > +    for (i = 0; i < VVC_MAX_SL_COUNT; i++) {
> > +        const VVCScalingList *sl = h->ps.scaling_list[i];
> > +        if (sl) {
> > +            int l;
> > +
> > +            VAScalingListVVC sl_param = {
> > +                .aps_adaptation_parameter_set_id = i,
> > +            };
> > +
> > +            for (j = 0; j < 14; j++)
> > +                sl_param.ScalingMatrixDCRec[j] = sl-
> > >scaling_matrix_dc_rec[j];
> > +
> > +            for (j = 0; j < 2; j++)
> > +                for (k = 0; k < 2; k++)
> > +                    for (l = 0; l < 2; l++)
> > +                        sl_param.ScalingMatrixRec2x2[j][k][l] =
> > sl->scaling_matrix_rec[j][l * 2 + k];
> > +
> > +            for (j = 2; j < 8; j++)
> > +                for (k = 0; k < 4; k++)
> > +                    for (l = 0; l < 4; l++)
> > +                        sl_param.ScalingMatrixRec4x4[j - 2][k][l]
> > = sl->scaling_matrix_rec[j][l * 4 + k];
> > +
> > +            for (j = 8; j < 28; j++)
> > +                for (k = 0; k < 8; k++)
> > +                    for (l = 0; l < 8; l++)
> > +                        sl_param.ScalingMatrixRec8x8[j - 8][k][l]
> > = sl->scaling_matrix_rec[j][l * 8 + k];
> > +
> > +            err = ff_vaapi_decode_make_param_buffer(avctx, &pic-
> > >pic,
> > +                                                   
> > VAIQMatrixBufferType,
> > +                                                    &sl_param,
> > sizeof(VAScalingListVVC));
> > +            if (err < 0)
> > +                goto fail;
> > +        }
> > +    }
> > +
> > +    for (i = 0; i <= pps->pps_num_exp_tile_columns_minus1; i++) {
> > +        tile_dim = pps->pps_tile_column_width_minus1[i];
> > +        err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
> > +                                                VATileBufferType,
> > +                                                &tile_dim,
> > sizeof(tile_dim));
> > +        if (err < 0)
> > +            goto fail;
> > +    }
> > +
> > +    for (i = 0; i <= pps->pps_num_exp_tile_rows_minus1; i++) {
> > +        tile_dim = pps->pps_tile_row_height_minus1[i];
> > +        err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
> > +                                                VATileBufferType,
> > +                                                &tile_dim,
> > sizeof(tile_dim));
> > +        if (err < 0)
> > +            goto fail;
> > +    }
> > +
> > +    if (!pps->pps_no_pic_partition_flag && pps-
> > >pps_rect_slice_flag && !pps->pps_single_slice_per_subpic_flag) {
> > +        for (i = 0; i <= pps->pps_num_slices_in_pic_minus1; i++) {
> > +            for (j = 0; j < pps->pps_num_exp_slices_in_tile[i];
> > j++) {
> > +                exp_slice_height_in_ctus[i + j] = pps-
> > >pps_exp_slice_height_in_ctus_minus1[i][j] + 1;
> > +            }
> > +        }
> > +        for (i = 0; i <= pps->pps_num_slices_in_pic_minus1; i++) {
> > +            VASliceStructVVC ss_param = {
> > +                .SliceTopLeftTileIdx              = pps-
> > >slice_top_left_tile_idx[i],
> > +                .pps_slice_width_in_tiles_minus1  = pps-
> > >pps_slice_width_in_tiles_minus1[i],
> > +                .pps_slice_height_in_tiles_minus1 = pps-
> > >pps_slice_height_in_tiles_minus1[i],
> > +            };
> > +
> > +            if (pps->pps_slice_width_in_tiles_minus1[i] > 0 ||
> > pps->pps_slice_height_in_tiles_minus1[i] > 0)
> > +                ss_param.pps_exp_slice_height_in_ctus_minus1 = 0;
> > +            else {
> > +                if (pps->num_slices_in_tile[i] == 1)
> > +                    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;
> > +                else if (exp_slice_height_in_ctus[i])
> > +                    ss_param.pps_exp_slice_height_in_ctus_minus1 =
> > exp_slice_height_in_ctus[i] - 1;
> > +                else
> > +                    continue;
> > +            }
> > +
> > +            err = ff_vaapi_decode_make_param_buffer(avctx, &pic-
> > >pic,
> > +                                                   
> > VASliceStructBufferType,
> > +                                                    &ss_param,
> > sizeof(VASliceStructVVC));
> > +            if (err < 0)
> > +                goto fail;
> > +        }
> > +    }
> > +
> > +    return 0;
> > +
> > +fail:
> > +    ff_vaapi_decode_cancel(avctx, &pic->pic);
> > +    return err;
> > +}
> > +
> > +static uint8_t get_ref_pic_index(const VVCContext *h, const
> > VVCFrame *frame)
> > +{
> > +    VVCFrameContext             *fc = &h->fcs[(h->nb_frames + h-
> > >nb_fcs) % h->nb_fcs];
> > +    VAAPIDecodePictureVVC      *pic = fc->ref-
> > >hwaccel_picture_private;
> > +    VAPictureParameterBufferVVC *pp = (VAPictureParameterBufferVVC
> > *)&pic->pic_param;
> > +    uint8_t i;
> > +
> > +    if (!frame)
> > +        return 0xFF;
> > +
> > +    for (i = 0; i < FF_ARRAY_ELEMS(pp->ReferenceFrames); i++) {
> > +        VASurfaceID pid = pp->ReferenceFrames[i].picture_id;
> > +        int poc = pp->ReferenceFrames[i].pic_order_cnt;
> > +        if (pid != VA_INVALID_ID && pid ==
> > ff_vaapi_get_surface_id(frame->frame) && poc == frame->poc)
> > +            return i;
> > +    }
> > +
> > +    return 0xFF;
> > +}
> > +
> > +static int get_slice_data_offset(const uint8_t *buffer, uint32_t
> > size, const SliceContext* sc)
> > +{
> > +    const H266RawSlice *slice = sc->ref;
> > +    int num_identical_bytes   = slice->data_size < 32 ? slice-
> > >data_size : 32;
> > +
> > +    for (int i = 0; i < size; i++) {
> > +        int skip_bytes = 0;
> > +        if (i >=2 && buffer[i] == 0x03 && !buffer[i - 1] &&
> > !buffer[i - 2])
> > +            continue;
> > +
> > +        for (int j = 0; j < num_identical_bytes; j++) {
> > +            if (i >= 2 && buffer[i + j + skip_bytes] == 0x03 &&
> > !buffer[i + j + skip_bytes - 1] && !buffer[i + j + skip_bytes - 2])
> > +                skip_bytes++;
> > +
> > +            if (buffer[i + j + skip_bytes] != slice->data[j])
> > +                break;
> > +
> > +            if (j + 1 == num_identical_bytes)
> > +                return i;
> > +        }
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int vaapi_vvc_decode_slice(AVCodecContext *avctx,
> > +                                   const uint8_t *buffer,
> > +                                   uint32_t       size)
> > +{
> > +    const VVCContext                    *h = avctx->priv_data;
> > +    VVCFrameContext                    *fc = &h->fcs[(h->nb_frames 
> > + h->nb_fcs) % h->nb_fcs];
> > +    const SliceContext                 *sc = fc->slices[fc-
> > >nb_slices];
> > +    const H266RawPPS                  *pps = fc->ps.pps->r;
> > +    const H266RawPictureHeader         *ph = fc->ps.ph.r;
> > +    const H266RawSliceHeader           *sh = sc->sh.r;
> > +    VAAPIDecodePictureVVC             *pic = fc->ref-
> > >hwaccel_picture_private;
> > +    VASliceParameterBufferVVC *slice_param = &pic->slice_param;
> > +    int nb_list, i, err;
> > +
> > +    *slice_param = (VASliceParameterBufferVVC) {
> > +        .slice_data_size                 = size,
> > +        .slice_data_offset               = 0,
> > +        .slice_data_flag                 = VA_SLICE_DATA_FLAG_ALL,
> > +        .slice_data_byte_offset          =
> > get_slice_data_offset(buffer, size, sc),
> > +        .sh_subpic_id                    = sh->sh_subpic_id,
> > +        .sh_slice_address                = sh->sh_slice_address,
> > +        .sh_num_tiles_in_slice_minus1    = sh-
> > >sh_num_tiles_in_slice_minus1,
> > +        .sh_slice_type                   = sh->sh_slice_type,
> > +        .sh_num_alf_aps_ids_luma         = sh-
> > >sh_num_alf_aps_ids_luma,
> > +        .sh_alf_aps_id_chroma            = sh-
> > >sh_alf_aps_id_chroma,
> > +        .sh_alf_cc_cb_aps_id             = sh-
> > >sh_alf_cc_cb_aps_id,
> > +        .sh_alf_cc_cr_aps_id             = sh-
> > >sh_alf_cc_cr_aps_id,
> > +        .NumRefIdxActive[0]              = sh-
> > >num_ref_idx_active[0],
> > +        .NumRefIdxActive[1]              = sh-
> > >num_ref_idx_active[1],
> > +        .sh_collocated_ref_idx           = sh-
> > >sh_collocated_ref_idx,
> > +        .SliceQpY                        = pps-
> > >pps_qp_delta_info_in_ph_flag ?
> > +                                           26 + pps-
> > >pps_init_qp_minus26 + ph->ph_qp_delta :
> > +                                           26 + pps-
> > >pps_init_qp_minus26 + sh->sh_qp_delta,
> > +        .sh_cb_qp_offset                 = sh->sh_cb_qp_offset,
> > +        .sh_cr_qp_offset                 = sh->sh_cr_qp_offset,
> > +        .sh_joint_cbcr_qp_offset         = sh-
> > >sh_joint_cbcr_qp_offset,
> > +        .sh_luma_beta_offset_div2        = sh-
> > >sh_luma_beta_offset_div2,
> > +        .sh_luma_tc_offset_div2          = sh-
> > >sh_luma_tc_offset_div2,
> > +        .sh_cb_beta_offset_div2          = sh-
> > >sh_cb_beta_offset_div2,
> > +        .sh_cb_tc_offset_div2            = sh-
> > >sh_cb_tc_offset_div2,
> > +        .sh_cr_beta_offset_div2          = sh-
> > >sh_cr_beta_offset_div2,
> > +        .sh_cr_tc_offset_div2            = sh-
> > >sh_cr_tc_offset_div2,
> > +        .WPInfo = {
> > +            .luma_log2_weight_denom         = sh-
> > >sh_pred_weight_table.luma_log2_weight_denom,
> > +            .delta_chroma_log2_weight_denom = sh-
> > >sh_pred_weight_table.delta_chroma_log2_weight_denom,
> > +            .num_l0_weights                 = sh-
> > >sh_pred_weight_table.num_l0_weights,
> > +            .num_l1_weights                 = sh-
> > >sh_pred_weight_table.num_l1_weights,
> > +        },
> > +        .sh_flags.bits = {
> > +            .sh_alf_enabled_flag                 = sh-
> > >sh_alf_enabled_flag,
> > +            .sh_alf_cb_enabled_flag              = sh-
> > >sh_alf_cb_enabled_flag,
> > +            .sh_alf_cr_enabled_flag              = sh-
> > >sh_alf_cr_enabled_flag,
> > +            .sh_alf_cc_cb_enabled_flag           = sh-
> > >sh_alf_cc_cb_enabled_flag,
> > +            .sh_alf_cc_cr_enabled_flag           = sh-
> > >sh_alf_cc_cr_enabled_flag,
> > +            .sh_lmcs_used_flag                   = sh-
> > >sh_lmcs_used_flag,
> > +            .sh_explicit_scaling_list_used_flag  = sh-
> > >sh_explicit_scaling_list_used_flag,
> > +            .sh_cabac_init_flag                  = sh-
> > >sh_cabac_init_flag,
> > +            .sh_collocated_from_l0_flag          = sh-
> > >sh_collocated_from_l0_flag,
> > +            .sh_cu_chroma_qp_offset_enabled_flag = sh-
> > >sh_cu_chroma_qp_offset_enabled_flag,
> > +            .sh_sao_luma_used_flag               = sh-
> > >sh_sao_luma_used_flag,
> > +            .sh_sao_chroma_used_flag             = sh-
> > >sh_sao_chroma_used_flag,
> > +            .sh_deblocking_filter_disabled_flag  = sh-
> > >sh_deblocking_filter_disabled_flag,
> > +            .sh_dep_quant_used_flag              = sh-
> > >sh_dep_quant_used_flag,
> > +            .sh_sign_data_hiding_used_flag       = sh-
> > >sh_sign_data_hiding_used_flag,
> > +            .sh_ts_residual_coding_disabled_flag = sh-
> > >sh_ts_residual_coding_disabled_flag,
> > +        },
> > +    };
> > +
> > +    memset(&slice_param->RefPicList, 0xFF, sizeof(slice_param-
> > >RefPicList));
> > +
> > +    nb_list = (sh->sh_slice_type == VVC_SLICE_TYPE_B) ?
> > +              2 : (sh->sh_slice_type == VVC_SLICE_TYPE_I ? 0 : 1);
> > +    for (int list_idx = 0; list_idx < nb_list; list_idx++) {
> > +        RefPicList *rpl = &sc->rpl[list_idx];
> > +
> > +        for (i = 0; i < rpl->nb_refs; i++)
> > +            slice_param->RefPicList[list_idx][i] =
> > get_ref_pic_index(h, rpl->ref[i]);
> > +    }
> > +
> > +    for (i = 0; i < 7; i++)
> > +        slice_param->sh_alf_aps_id_luma[i] = sh-
> > >sh_alf_aps_id_luma[i];
> > +
> > +    for (i = 0; i < 15; i++) {
> > +        slice_param->WPInfo.luma_weight_l0_flag[i]   = sh-
> > >sh_pred_weight_table.luma_weight_l0_flag[i];
> > +        slice_param->WPInfo.chroma_weight_l0_flag[i] = sh-
> > >sh_pred_weight_table.chroma_weight_l0_flag[i];
> > +        slice_param->WPInfo.delta_luma_weight_l0[i]  = sh-
> > >sh_pred_weight_table.delta_luma_weight_l0[i];
> > +        slice_param->WPInfo.luma_offset_l0[i]        = sh-
> > >sh_pred_weight_table.luma_offset_l0[i];
> > +        slice_param->WPInfo.luma_weight_l1_flag[i]   = sh-
> > >sh_pred_weight_table.luma_weight_l1_flag[i];
> > +        slice_param->WPInfo.chroma_weight_l1_flag[i] = sh-
> > >sh_pred_weight_table.chroma_weight_l1_flag[i];
> > +        slice_param->WPInfo.delta_luma_weight_l1[i]  = sh-
> > >sh_pred_weight_table.delta_luma_weight_l1[i];
> > +        slice_param->WPInfo.luma_offset_l1[i]        = sh-
> > >sh_pred_weight_table.luma_offset_l1[i];
> > +    }
> > +
> > +    for (i = 0; i < 15; i++) {
> > +        for (int j = 0; j < 2; j++) {
> > +            slice_param->WPInfo.delta_chroma_weight_l0[i][j] = sh-
> > >sh_pred_weight_table.delta_chroma_weight_l0[i][j];
> > +            slice_param->WPInfo.delta_chroma_offset_l0[i][j] = sh-
> > >sh_pred_weight_table.delta_chroma_offset_l0[i][j];
> > +            slice_param->WPInfo.delta_chroma_weight_l1[i][j] = sh-
> > >sh_pred_weight_table.delta_chroma_weight_l1[i][j];
> > +            slice_param->WPInfo.delta_chroma_offset_l1[i][j] = sh-
> > >sh_pred_weight_table.delta_chroma_offset_l1[i][j];
> > +        }
> > +    }
> > +
> > +    err = ff_vaapi_decode_make_slice_buffer(avctx, &pic->pic,
> > +                                            &pic->slice_param,
> > +                                           
> > sizeof(VASliceParameterBufferVVC),
> > +                                            buffer, size);
> > +    if (err) {
> > +        ff_vaapi_decode_cancel(avctx, &pic->pic);
> > +        return err;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int vaapi_vvc_end_frame(AVCodecContext *avctx)
> > +{
> > +
> > +    const VVCContext        *h = avctx->priv_data;
> > +    VVCFrameContext        *fc = &h->fcs[(h->nb_frames + h-
> > >nb_fcs) % h->nb_fcs];
> > +    VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private;
> > +    int ret;
> > +
> > +    ret = ff_vaapi_decode_issue(avctx, &pic->pic);
> > +    if (ret < 0)
> > +        goto fail;
> > +
> > +    pic->decode_issued = 1;
> > +
> > +    return 0;
> > +
> > +fail:
> > +    ff_vaapi_decode_cancel(avctx, &pic->pic);
> > +    return ret;
> > +}
> > +
> > +const FFHWAccel ff_vvc_vaapi_hwaccel = {
> > +    .p.name               = "vvc_vaapi",
> > +    .p.type               = AVMEDIA_TYPE_VIDEO,
> > +    .p.id                 = AV_CODEC_ID_VVC,
> > +    .p.pix_fmt            = AV_PIX_FMT_VAAPI,
> > +    .start_frame          = &vaapi_vvc_start_frame,
> > +    .end_frame            = &vaapi_vvc_end_frame,
> > +    .decode_slice         = &vaapi_vvc_decode_slice,
> > +    .frame_priv_data_size = sizeof(VAAPIDecodePictureVVC),
> > +    .init                 = &ff_vaapi_decode_init,
> > +    .uninit               = &ff_vaapi_decode_uninit,
> > +    .frame_params         = &ff_vaapi_common_frame_params,
> > +    .priv_data_size       = sizeof(VAAPIDecodeContext),
> > +    .caps_internal        = HWACCEL_CAP_ASYNC_SAFE,
> > +};
> > diff --git a/libavcodec/version.h b/libavcodec/version.h
> > index 06631ffa8c..7aa95fc3f1 100644
> > --- a/libavcodec/version.h
> > +++ b/libavcodec/version.h
> > @@ -29,7 +29,7 @@
> > 
> >  #include "version_major.h"
> > 
> > -#define LIBAVCODEC_VERSION_MINOR   4
> > +#define LIBAVCODEC_VERSION_MINOR   5
> >  #define LIBAVCODEC_VERSION_MICRO 100
> > 
> >  #define LIBAVCODEC_VERSION_INT 
> > AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
> > diff --git a/libavcodec/vvc/vvcdec.c b/libavcodec/vvc/vvcdec.c
> > index f2e269ce76..b204a0c73a 100644
> > --- a/libavcodec/vvc/vvcdec.c
> > +++ b/libavcodec/vvc/vvcdec.c
> > @@ -29,6 +29,7 @@
> >  #include "libavutil/cpu.h"
> >  #include "libavutil/thread.h"
> > 
> > +#include "config_components.h"
> >  #include "vvcdec.h"
> >  #include "vvc_ctu.h"
> >  #include "vvc_data.h"
> > @@ -724,14 +725,20 @@ static int slice_start(SliceContext *sc,
> > VVCContext *s, VVCFrameContext *fc,
> > 
> >  static enum AVPixelFormat get_format(AVCodecContext *avctx, const
> > VVCSPS *sps)
> >  {
> > -#define HWACCEL_MAX 0
> > +#define HWACCEL_MAX CONFIG_VVC_VAAPI_HWACCEL
> > 
> >      enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
> > 
> >      switch (sps->pix_fmt) {
> >      case AV_PIX_FMT_YUV420P:
> > +#if CONFIG_VVC_VAAPI_HWACCEL
> > +        *fmt++ = AV_PIX_FMT_VAAPI;
> > +#endif
> >          break;
> >      case AV_PIX_FMT_YUV420P10:
> > +#if CONFIG_VVC_VAAPI_HWACCEL
> > +        *fmt++ = AV_PIX_FMT_VAAPI;
> > +#endif
> >          break;
> >      }
> > 
> > @@ -1100,4 +1107,10 @@ const FFCodec ff_vvc_decoder = {
> >      .caps_internal  = FF_CODEC_CAP_EXPORTS_CROPPING |
> > FF_CODEC_CAP_INIT_CLEANUP |
> >                        FF_CODEC_CAP_AUTO_THREADS,
> >      .p.profiles     = NULL_IF_CONFIG_SMALL(ff_vvc_profiles),
> > +    .hw_configs     = (const AVCodecHWConfigInternal *const []) {
> > +#if CONFIG_VVC_VAAPI_HWACCEL
> > +                    HWACCEL_VAAPI(vvc),
> > +#endif
> > +    NULL
> > +    },
> >  };
Nuo Mi April 6, 2024, 5:03 a.m. UTC | #3
>
> > > --- a/libavcodec/vaapi_decode.c
> > > +++ b/libavcodec/vaapi_decode.c
> > > @@ -455,6 +455,9 @@ static const struct {
> > >      MAP(AV1,         AV1_MAIN,        AV1Profile0),
> > >      MAP(AV1,         AV1_HIGH,        AV1Profile1),
> > >  #endif
> > > +#if VA_CHECK_VERSION(1, 22, 0)
> > > +    MAP(H266,        VVC_MAIN_10,     VVCMain10),
> > > +#endif
> > >
> > >  #undef MAP
> > >  };
> > > @@ -627,6 +630,10 @@ static int
> > > vaapi_decode_make_config(AVCodecContext *avctx,
> > >          case AV_CODEC_ID_VP8:
> > >              frames->initial_pool_size += 3;
> > >              break;
> > > +        case AV_CODEC_ID_H266:
> > > +            // Add additional 16 for maximum 16 frames delay in
> > > vvc native decode.
> > > +            frames->initial_pool_size += 32;
> >
> > One frame of 8k YUV444, 10 bits, is about 200MB. Thirty-two frames
> > amount to approximately 6GB.Can we dynamically allocate the buffer
> > pool?
>
> It's processing in other thread:
> https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=11316
>
> >
> > The software decoder requires a delay of 16 frames to ensure full
> > utilization of CPUs. In the future, we may consider increasing this
> > to 32 or even 64 frames.
> > However, for hardware decoding, given that all processing occurs on
> > the GPU, we do not require any delay.
>
> The delay can avoid sync hardware task immediately once it is
> submitted, which can avoid hardware switch tasks frequently and drop
> performance. If the number will increase, I'd prefer to set it as an
> option and diff the default value for hardware with software.

Why does VVC require such a large frame pool while other hardware codecs do
not?
What makes VVC so special?"
diff mbox series

Patch

diff --git a/Changelog b/Changelog
index e83a00e35c..3108e65558 100644
--- a/Changelog
+++ b/Changelog
@@ -1,6 +1,10 @@ 
 Entries are sorted chronologically from oldest to youngest within each release,
 releases are sorted from youngest to oldest.
 
+version <next>:
+- VVC VAAPI decoder
+
+
 version 7.0:
 - DXV DXT1 encoder
 - LEAD MCMP decoder
diff --git a/configure b/configure
index 2a1d22310b..d902c9adc8 100755
--- a/configure
+++ b/configure
@@ -3258,6 +3258,8 @@  vp9_vdpau_hwaccel_deps="vdpau VdpPictureInfoVP9"
 vp9_vdpau_hwaccel_select="vp9_decoder"
 vp9_videotoolbox_hwaccel_deps="videotoolbox"
 vp9_videotoolbox_hwaccel_select="vp9_decoder"
+vvc_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferVVC"
+vvc_vaapi_hwaccel_select="vvc_decoder"
 wmv3_d3d11va_hwaccel_select="vc1_d3d11va_hwaccel"
 wmv3_d3d11va2_hwaccel_select="vc1_d3d11va2_hwaccel"
 wmv3_d3d12va_hwaccel_select="vc1_d3d12va_hwaccel"
@@ -7250,6 +7252,7 @@  if enabled vaapi; then
     check_cpp_condition vaapi_1 "va/va.h" "VA_CHECK_VERSION(1, 0, 0)"
 
     check_type "va/va.h va/va_dec_hevc.h" "VAPictureParameterBufferHEVC"
+    check_type "va/va.h va/va_dec_vvc.h" "VAPictureParameterBufferVVC"
     check_struct "va/va.h" "VADecPictureParameterBufferVP9" bit_depth
     check_struct "va/va.h" "VADecPictureParameterBufferAV1" bit_depth_idx
     check_type   "va/va.h va/va_vpp.h" "VAProcFilterParameterBufferHDRToneMapping"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 9ce6d445c1..343b037636 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1054,6 +1054,7 @@  OBJS-$(CONFIG_VP9_VAAPI_HWACCEL)          += vaapi_vp9.o
 OBJS-$(CONFIG_VP9_VDPAU_HWACCEL)          += vdpau_vp9.o
 OBJS-$(CONFIG_VP9_VIDEOTOOLBOX_HWACCEL)   += videotoolbox_vp9.o
 OBJS-$(CONFIG_VP8_QSV_HWACCEL)            += qsvdec.o
+OBJS-$(CONFIG_VVC_VAAPI_HWACCEL)          += vaapi_vvc.o
 
 # Objects duplicated from other libraries for shared builds
 SHLIBOBJS                              += log2_tab.o reverse.o
diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h
index 5171e4c7d7..88d6b9a9b5 100644
--- a/libavcodec/hwaccels.h
+++ b/libavcodec/hwaccels.h
@@ -82,6 +82,7 @@  extern const struct FFHWAccel ff_vp9_nvdec_hwaccel;
 extern const struct FFHWAccel ff_vp9_vaapi_hwaccel;
 extern const struct FFHWAccel ff_vp9_vdpau_hwaccel;
 extern const struct FFHWAccel ff_vp9_videotoolbox_hwaccel;
+extern const struct FFHWAccel ff_vvc_vaapi_hwaccel;
 extern const struct FFHWAccel ff_wmv3_d3d11va_hwaccel;
 extern const struct FFHWAccel ff_wmv3_d3d11va2_hwaccel;
 extern const struct FFHWAccel ff_wmv3_d3d12va_hwaccel;
diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c
index 1b1972a2a9..ceeb1f1a12 100644
--- a/libavcodec/vaapi_decode.c
+++ b/libavcodec/vaapi_decode.c
@@ -455,6 +455,9 @@  static const struct {
     MAP(AV1,         AV1_MAIN,        AV1Profile0),
     MAP(AV1,         AV1_HIGH,        AV1Profile1),
 #endif
+#if VA_CHECK_VERSION(1, 22, 0)
+    MAP(H266,        VVC_MAIN_10,     VVCMain10),
+#endif
 
 #undef MAP
 };
@@ -627,6 +630,10 @@  static int vaapi_decode_make_config(AVCodecContext *avctx,
         case AV_CODEC_ID_VP8:
             frames->initial_pool_size += 3;
             break;
+        case AV_CODEC_ID_H266:
+            // Add additional 16 for maximum 16 frames delay in vvc native decode.
+            frames->initial_pool_size += 32;
+            break;
         default:
             frames->initial_pool_size += 2;
         }
diff --git a/libavcodec/vaapi_vvc.c b/libavcodec/vaapi_vvc.c
new file mode 100644
index 0000000000..6141005688
--- /dev/null
+++ b/libavcodec/vaapi_vvc.c
@@ -0,0 +1,657 @@ 
+/*
+ * VVC HW decode acceleration through VA API
+ *
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <va/va.h>
+#include <va/va_dec_vvc.h>
+
+#include "vvc/vvcdec.h"
+#include "vvc/vvc_refs.h"
+#include "hwaccel_internal.h"
+#include "vaapi_decode.h"
+
+typedef struct VAAPIDecodePictureVVC {
+    VAAPIDecodePicture          pic;
+    VAPictureParameterBufferVVC pic_param;
+    VASliceParameterBufferVVC   slice_param;
+    int                         decode_issued;
+} VAAPIDecodePictureVVC;
+
+static void init_vaapi_pic(VAPictureVVC *va_pic)
+{
+    va_pic->picture_id    = VA_INVALID_ID;
+    va_pic->flags         = VA_PICTURE_VVC_INVALID;
+    va_pic->pic_order_cnt = 0;
+}
+
+static void fill_vaapi_pic(VAPictureVVC *va_pic, const VVCFrame *pic)
+{
+    va_pic->picture_id    = ff_vaapi_get_surface_id(pic->frame);
+    va_pic->pic_order_cnt = pic->poc;
+    va_pic->flags         = 0;
+
+    if (pic->flags & VVC_FRAME_FLAG_LONG_REF)
+        va_pic->flags |= VA_PICTURE_VVC_LONG_TERM_REFERENCE;
+}
+
+static void fill_vaapi_reference_frames(const VVCFrameContext *h, VAPictureParameterBufferVVC *pp)
+{
+    const VVCFrame *current_picture = h->ref;
+    int i, j;
+
+    for (i = 0, j = 0; i < FF_ARRAY_ELEMS(pp->ReferenceFrames); i++) {
+        const VVCFrame *frame = NULL;
+
+        while (!frame && j < FF_ARRAY_ELEMS(h->DPB)) {
+            if ((&h->DPB[j] != current_picture ) &&
+                (h->DPB[j].flags & (VVC_FRAME_FLAG_LONG_REF | VVC_FRAME_FLAG_SHORT_REF)))
+                frame = &h->DPB[j];
+            j++;
+        }
+
+        init_vaapi_pic(&pp->ReferenceFrames[i]);
+
+        if (frame) {
+            VAAPIDecodePictureVVC *pic;
+            fill_vaapi_pic(&pp->ReferenceFrames[i], frame);
+            pic = frame->hwaccel_picture_private;
+            if (!pic->decode_issued)
+               pp->ReferenceFrames[i].flags |= VA_PICTURE_VVC_UNAVAILABLE_REFERENCE;
+        }
+    }
+}
+
+static int vaapi_vvc_start_frame(AVCodecContext          *avctx,
+                                 av_unused const uint8_t *buffer,
+                                 av_unused uint32_t       size)
+{
+    const VVCContext                    *h = avctx->priv_data;
+    VVCFrameContext                    *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs];
+    const H266RawSPS                  *sps = fc->ps.sps->r;
+    const H266RawPPS                  *pps = fc->ps.pps->r;
+    const H266RawPictureHeader         *ph = fc->ps.ph.r;
+    VAAPIDecodePictureVVC             *pic = fc->ref->hwaccel_picture_private;
+    VAPictureParameterBufferVVC *pic_param = &pic->pic_param;
+    uint16_t tile_dim, exp_slice_height_in_ctus[VVC_MAX_SLICES] = {0};
+    int i, j, k, err;
+
+    pic->pic.output_surface = ff_vaapi_get_surface_id(fc->ref->frame);
+
+    *pic_param = (VAPictureParameterBufferVVC) {
+        .pps_pic_width_in_luma_samples                 = pps->pps_pic_width_in_luma_samples,
+        .pps_pic_height_in_luma_samples                = pps->pps_pic_height_in_luma_samples,
+        .sps_num_subpics_minus1                        = sps->sps_num_subpics_minus1,
+        .sps_chroma_format_idc                         = sps->sps_chroma_format_idc,
+        .sps_bitdepth_minus8                           = sps->sps_bitdepth_minus8,
+        .sps_log2_ctu_size_minus5                      = sps->sps_log2_ctu_size_minus5,
+        .sps_log2_min_luma_coding_block_size_minus2    = sps->sps_log2_min_luma_coding_block_size_minus2,
+        .sps_log2_transform_skip_max_size_minus2       = sps->sps_log2_transform_skip_max_size_minus2,
+        .sps_six_minus_max_num_merge_cand              = sps->sps_six_minus_max_num_merge_cand,
+        .sps_five_minus_max_num_subblock_merge_cand    = sps->sps_five_minus_max_num_subblock_merge_cand,
+        .sps_max_num_merge_cand_minus_max_num_gpm_cand = sps->sps_max_num_merge_cand_minus_max_num_gpm_cand,
+        .sps_log2_parallel_merge_level_minus2          = sps->sps_log2_parallel_merge_level_minus2,
+        .sps_min_qp_prime_ts                           = sps->sps_min_qp_prime_ts,
+        .sps_six_minus_max_num_ibc_merge_cand          = sps->sps_six_minus_max_num_ibc_merge_cand,
+        .sps_num_ladf_intervals_minus2                 = sps->sps_num_ladf_intervals_minus2,
+        .sps_ladf_lowest_interval_qp_offset            = sps->sps_ladf_lowest_interval_qp_offset,
+        .sps_flags.bits = {
+            .sps_subpic_info_present_flag                                  = sps->sps_subpic_info_present_flag,
+            .sps_independent_subpics_flag                                  = sps->sps_independent_subpics_flag,
+            .sps_subpic_same_size_flag                                     = sps->sps_subpic_same_size_flag,
+            .sps_entropy_coding_sync_enabled_flag                          = sps->sps_entropy_coding_sync_enabled_flag,
+            .sps_qtbtt_dual_tree_intra_flag                                = sps->sps_qtbtt_dual_tree_intra_flag,
+            .sps_max_luma_transform_size_64_flag                           = sps->sps_max_luma_transform_size_64_flag,
+            .sps_transform_skip_enabled_flag                               = sps->sps_transform_skip_enabled_flag,
+            .sps_bdpcm_enabled_flag                                        = sps->sps_bdpcm_enabled_flag,
+            .sps_mts_enabled_flag                                          = sps->sps_mts_enabled_flag,
+            .sps_explicit_mts_intra_enabled_flag                           = sps->sps_explicit_mts_intra_enabled_flag,
+            .sps_explicit_mts_inter_enabled_flag                           = sps->sps_explicit_mts_inter_enabled_flag,
+            .sps_lfnst_enabled_flag                                        = sps->sps_lfnst_enabled_flag,
+            .sps_joint_cbcr_enabled_flag                                   = sps->sps_joint_cbcr_enabled_flag,
+            .sps_same_qp_table_for_chroma_flag                             = sps->sps_same_qp_table_for_chroma_flag,
+            .sps_sao_enabled_flag                                          = sps->sps_sao_enabled_flag,
+            .sps_alf_enabled_flag                                          = sps->sps_alf_enabled_flag,
+            .sps_ccalf_enabled_flag                                        = sps->sps_alf_enabled_flag,
+            .sps_lmcs_enabled_flag                                         = sps->sps_lmcs_enabled_flag,
+            .sps_sbtmvp_enabled_flag                                       = sps->sps_sbtmvp_enabled_flag,
+            .sps_amvr_enabled_flag                                         = sps->sps_amvr_enabled_flag,
+            .sps_smvd_enabled_flag                                         = sps->sps_smvd_enabled_flag,
+            .sps_mmvd_enabled_flag                                         = sps->sps_mmvd_enabled_flag,
+            .sps_sbt_enabled_flag                                          = sps->sps_sbt_enabled_flag,
+            .sps_affine_enabled_flag                                       = sps->sps_affine_enabled_flag,
+            .sps_6param_affine_enabled_flag                                = sps->sps_6param_affine_enabled_flag,
+            .sps_affine_amvr_enabled_flag                                  = sps->sps_affine_amvr_enabled_flag,
+            .sps_affine_prof_enabled_flag                                  = sps->sps_affine_prof_enabled_flag,
+            .sps_bcw_enabled_flag                                          = sps->sps_bcw_enabled_flag,
+            .sps_ciip_enabled_flag                                         = sps->sps_ciip_enabled_flag,
+            .sps_gpm_enabled_flag                                          = sps->sps_gpm_enabled_flag,
+            .sps_isp_enabled_flag                                          = sps->sps_isp_enabled_flag,
+            .sps_mrl_enabled_flag                                          = sps->sps_mrl_enabled_flag,
+            .sps_mip_enabled_flag                                          = sps->sps_mip_enabled_flag,
+            .sps_cclm_enabled_flag                                         = sps->sps_cclm_enabled_flag,
+            .sps_chroma_horizontal_collocated_flag                         = sps->sps_chroma_horizontal_collocated_flag,
+            .sps_chroma_vertical_collocated_flag                           = sps->sps_chroma_vertical_collocated_flag,
+            .sps_palette_enabled_flag                                      = sps->sps_palette_enabled_flag,
+            .sps_act_enabled_flag                                          = sps->sps_act_enabled_flag,
+            .sps_ibc_enabled_flag                                          = sps->sps_ibc_enabled_flag,
+            .sps_ladf_enabled_flag                                         = sps->sps_ladf_enabled_flag,
+            .sps_explicit_scaling_list_enabled_flag                        = sps->sps_explicit_scaling_list_enabled_flag,
+            .sps_scaling_matrix_for_lfnst_disabled_flag                    = sps->sps_scaling_matrix_for_lfnst_disabled_flag,
+            .sps_scaling_matrix_for_alternative_colour_space_disabled_flag = sps->sps_scaling_matrix_for_alternative_colour_space_disabled_flag,
+            .sps_scaling_matrix_designated_colour_space_flag               = sps->sps_scaling_matrix_designated_colour_space_flag,
+            .sps_virtual_boundaries_enabled_flag                           = sps->sps_virtual_boundaries_enabled_flag,
+            .sps_virtual_boundaries_present_flag                           = sps->sps_virtual_boundaries_present_flag,
+        },
+        .NumVerVirtualBoundaries               = sps->sps_virtual_boundaries_present_flag ?
+                                                 sps->sps_num_ver_virtual_boundaries :
+                                                 ph->ph_num_ver_virtual_boundaries,
+        .NumHorVirtualBoundaries               = sps->sps_virtual_boundaries_present_flag ?
+                                                 sps->sps_num_hor_virtual_boundaries :
+                                                 ph->ph_num_hor_virtual_boundaries,
+        .pps_scaling_win_left_offset           = pps->pps_scaling_win_left_offset,
+        .pps_scaling_win_right_offset          = pps->pps_scaling_win_right_offset,
+        .pps_scaling_win_top_offset            = pps->pps_scaling_win_top_offset,
+        .pps_scaling_win_bottom_offset         = pps->pps_scaling_win_bottom_offset,
+        .pps_num_exp_tile_columns_minus1       = pps->pps_num_exp_tile_columns_minus1,
+        .pps_num_exp_tile_rows_minus1          = pps->pps_num_exp_tile_rows_minus1,
+        .pps_num_slices_in_pic_minus1          = pps->pps_num_slices_in_pic_minus1,
+        .pps_pic_width_minus_wraparound_offset = pps->pps_pic_width_minus_wraparound_offset,
+        .pps_cb_qp_offset                      = pps->pps_cb_qp_offset,
+        .pps_cr_qp_offset                      = pps->pps_cr_qp_offset,
+        .pps_joint_cbcr_qp_offset_value        = pps->pps_joint_cbcr_qp_offset_value,
+        .pps_chroma_qp_offset_list_len_minus1  = pps->pps_chroma_qp_offset_list_len_minus1,
+        .pps_flags.bits = {
+            .pps_loop_filter_across_tiles_enabled_flag   = pps->pps_loop_filter_across_tiles_enabled_flag,
+            .pps_rect_slice_flag                         = pps->pps_rect_slice_flag,
+            .pps_single_slice_per_subpic_flag            = pps->pps_single_slice_per_subpic_flag,
+            .pps_loop_filter_across_slices_enabled_flag  = pps->pps_loop_filter_across_slices_enabled_flag,
+            .pps_weighted_pred_flag                      = pps->pps_weighted_pred_flag,
+            .pps_weighted_bipred_flag                    = pps->pps_weighted_bipred_flag,
+            .pps_ref_wraparound_enabled_flag             = pps->pps_ref_wraparound_enabled_flag,
+            .pps_cu_qp_delta_enabled_flag                = pps->pps_cu_qp_delta_enabled_flag,
+            .pps_cu_chroma_qp_offset_list_enabled_flag   = pps->pps_cu_chroma_qp_offset_list_enabled_flag,
+            .pps_deblocking_filter_override_enabled_flag = pps->pps_deblocking_filter_override_enabled_flag,
+            .pps_deblocking_filter_disabled_flag         = pps->pps_deblocking_filter_disabled_flag,
+            .pps_dbf_info_in_ph_flag                     = pps->pps_dbf_info_in_ph_flag,
+            .pps_sao_info_in_ph_flag                     = pps->pps_sao_info_in_ph_flag,
+            .pps_alf_info_in_ph_flag                     = pps->pps_alf_info_in_ph_flag,
+        },
+        .ph_lmcs_aps_id                                = ph->ph_lmcs_aps_id,
+        .ph_scaling_list_aps_id                        = ph->ph_scaling_list_aps_id,
+        .ph_log2_diff_min_qt_min_cb_intra_slice_luma   = ph->ph_log2_diff_min_qt_min_cb_intra_slice_luma,
+        .ph_max_mtt_hierarchy_depth_intra_slice_luma   = ph->ph_max_mtt_hierarchy_depth_intra_slice_luma,
+        .ph_log2_diff_max_bt_min_qt_intra_slice_luma   = ph->ph_log2_diff_max_bt_min_qt_intra_slice_luma,
+        .ph_log2_diff_max_tt_min_qt_intra_slice_luma   = ph->ph_log2_diff_max_tt_min_qt_intra_slice_luma,
+        .ph_log2_diff_min_qt_min_cb_intra_slice_chroma = ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma,
+        .ph_max_mtt_hierarchy_depth_intra_slice_chroma = ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma,
+        .ph_log2_diff_max_bt_min_qt_intra_slice_chroma = ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma,
+        .ph_log2_diff_max_tt_min_qt_intra_slice_chroma = ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma,
+        .ph_cu_qp_delta_subdiv_intra_slice             = ph->ph_cu_qp_delta_subdiv_intra_slice,
+        .ph_cu_chroma_qp_offset_subdiv_intra_slice     = ph->ph_cu_chroma_qp_offset_subdiv_intra_slice,
+        .ph_log2_diff_min_qt_min_cb_inter_slice        = ph->ph_log2_diff_min_qt_min_cb_inter_slice,
+        .ph_max_mtt_hierarchy_depth_inter_slice        = ph->ph_max_mtt_hierarchy_depth_inter_slice,
+        .ph_log2_diff_max_bt_min_qt_inter_slice        = ph->ph_log2_diff_max_bt_min_qt_inter_slice,
+        .ph_log2_diff_max_tt_min_qt_inter_slice        = ph->ph_log2_diff_max_tt_min_qt_inter_slice,
+        .ph_cu_qp_delta_subdiv_inter_slice             = ph->ph_cu_qp_delta_subdiv_inter_slice,
+        .ph_cu_chroma_qp_offset_subdiv_inter_slice     = ph->ph_cu_chroma_qp_offset_subdiv_inter_slice,
+        .ph_flags.bits= {
+            .ph_non_ref_pic_flag                   = ph->ph_non_ref_pic_flag,
+            .ph_alf_enabled_flag                   = ph->ph_alf_enabled_flag,
+            .ph_alf_cb_enabled_flag                = ph->ph_alf_cb_enabled_flag,
+            .ph_alf_cr_enabled_flag                = ph->ph_alf_cr_enabled_flag,
+            .ph_alf_cc_cb_enabled_flag             = ph->ph_alf_cc_cb_enabled_flag,
+            .ph_alf_cc_cr_enabled_flag             = ph->ph_alf_cc_cr_enabled_flag,
+            .ph_lmcs_enabled_flag                  = ph->ph_lmcs_enabled_flag,
+            .ph_chroma_residual_scale_flag         = ph->ph_chroma_residual_scale_flag,
+            .ph_explicit_scaling_list_enabled_flag = ph->ph_explicit_scaling_list_enabled_flag,
+            .ph_virtual_boundaries_present_flag    = ph->ph_virtual_boundaries_present_flag,
+            .ph_temporal_mvp_enabled_flag          = ph->ph_temporal_mvp_enabled_flag,
+            .ph_mmvd_fullpel_only_flag             = ph->ph_mmvd_fullpel_only_flag,
+            .ph_mvd_l1_zero_flag                   = ph->ph_mvd_l1_zero_flag,
+            .ph_bdof_disabled_flag                 = ph->ph_bdof_disabled_flag,
+            .ph_dmvr_disabled_flag                 = ph->ph_dmvr_disabled_flag,
+            .ph_prof_disabled_flag                 = ph->ph_prof_disabled_flag,
+            .ph_joint_cbcr_sign_flag               = ph->ph_joint_cbcr_sign_flag,
+            .ph_sao_luma_enabled_flag              = ph->ph_sao_luma_enabled_flag,
+            .ph_sao_chroma_enabled_flag            = ph->ph_sao_chroma_enabled_flag,
+            .ph_deblocking_filter_disabled_flag    = ph->ph_deblocking_filter_disabled_flag,
+        },
+        .PicMiscFlags.fields = {
+            .IntraPicFlag = pps->pps_mixed_nalu_types_in_pic_flag ? 0 : IS_IRAP(h) ? 1 : 0,
+        }
+    };
+
+    fill_vaapi_pic(&pic_param->CurrPic, fc->ref);
+    fill_vaapi_reference_frames(fc, pic_param);
+
+    for (i = 0; i < VVC_MAX_SAMPLE_ARRAYS; i++)
+        for (j = 0; j < VVC_MAX_POINTS_IN_QP_TABLE; j++)
+            pic_param->ChromaQpTable[i][j] = fc->ps.sps->chroma_qp_table[i][j];
+    for (i = 0; i < 4; i++) {
+        pic_param->sps_ladf_qp_offset[i]              = sps->sps_ladf_qp_offset[i];
+        pic_param->sps_ladf_delta_threshold_minus1[i] = sps->sps_ladf_delta_threshold_minus1[i];
+    }
+
+    for (i = 0; i < (sps->sps_virtual_boundaries_present_flag ? sps->sps_num_ver_virtual_boundaries : ph->ph_num_ver_virtual_boundaries); i++) {
+        pic_param->VirtualBoundaryPosX[i] = (sps->sps_virtual_boundaries_present_flag ?
+                                            (sps->sps_virtual_boundary_pos_x_minus1[ i ] + 1) :
+                                            (ph->ph_virtual_boundary_pos_x_minus1[i] + 1)) * 8;
+    }
+
+    for (i = 0; i < (sps->sps_virtual_boundaries_present_flag ? sps->sps_num_hor_virtual_boundaries : ph->ph_num_hor_virtual_boundaries); i++) {
+        pic_param->VirtualBoundaryPosY[i] = (sps->sps_virtual_boundaries_present_flag ?
+                                            (sps->sps_virtual_boundary_pos_y_minus1[ i ] + 1) :
+                                            (ph->ph_virtual_boundary_pos_y_minus1[i] + 1)) * 8;
+    }
+
+    for (i = 0; i < 6; i++) {
+        pic_param->pps_cb_qp_offset_list[i]         = pps->pps_cb_qp_offset_list[i];
+        pic_param->pps_cr_qp_offset_list[i]         = pps->pps_cr_qp_offset_list[i];
+        pic_param->pps_joint_cbcr_qp_offset_list[i] = pps->pps_joint_cbcr_qp_offset_list[i];
+    }
+
+    err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
+                                            VAPictureParameterBufferType,
+                                            &pic->pic_param, sizeof(VAPictureParameterBufferVVC));
+    if (err < 0)
+        goto fail;
+
+    for (i = 0; i <= sps->sps_num_subpics_minus1 && sps->sps_subpic_info_present_flag; i++) {
+        VASubPicVVC subpic_param = {
+            .sps_subpic_ctu_top_left_x = sps->sps_subpic_ctu_top_left_x[i],
+            .sps_subpic_ctu_top_left_y = sps->sps_subpic_ctu_top_left_y[i],
+            .sps_subpic_width_minus1   = sps->sps_subpic_width_minus1[i],
+            .sps_subpic_height_minus1  = sps->sps_subpic_height_minus1[i],
+            .SubpicIdVal               = pps->sub_pic_id_val[i],
+            .subpic_flags.bits = {
+                .sps_subpic_treated_as_pic_flag             = sps->sps_subpic_treated_as_pic_flag[i],
+                .sps_loop_filter_across_subpic_enabled_flag = sps->sps_loop_filter_across_subpic_enabled_flag[i],
+            }
+        };
+        err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
+                                                VASubPicBufferType,
+                                                &subpic_param, sizeof(VASubPicVVC));
+        if (err < 0)
+            goto fail;
+    }
+
+    for (i = 0; i < VVC_MAX_ALF_COUNT; i++) {
+        const VVCALF *alf_list = h->ps.alf_list[i];
+        if (alf_list) {
+            const H266RawAPS *alf = alf_list->r;
+            VAAlfDataVVC alf_param = {
+                .aps_adaptation_parameter_set_id = i,
+                .alf_luma_num_filters_signalled_minus1 = alf->alf_luma_num_filters_signalled_minus1,
+                .alf_chroma_num_alt_filters_minus1     = alf->alf_chroma_num_alt_filters_minus1,
+                .alf_cc_cb_filters_signalled_minus1    = alf->alf_cc_cb_filters_signalled_minus1,
+                .alf_cc_cr_filters_signalled_minus1    = alf->alf_cc_cr_filters_signalled_minus1,
+                .alf_flags.bits = {
+                    .alf_luma_filter_signal_flag   = alf->alf_luma_filter_signal_flag,
+                    .alf_chroma_filter_signal_flag = alf->alf_chroma_filter_signal_flag,
+                    .alf_cc_cb_filter_signal_flag  = alf->alf_cc_cb_filter_signal_flag,
+                    .alf_cc_cr_filter_signal_flag  = alf->alf_cc_cr_filter_signal_flag,
+                    .alf_luma_clip_flag            = alf->alf_luma_clip_flag,
+                    .alf_chroma_clip_flag          = alf->alf_chroma_clip_flag,
+                }
+            };
+
+            for (j = 0; j < 25; j++)
+                alf_param.alf_luma_coeff_delta_idx[j] = alf->alf_luma_coeff_delta_idx[j];
+
+            for (j = 0; j < 25; j++) {
+                for (k = 0; k < 12; k++) {
+                    alf_param.filtCoeff[j][k]         = alf->alf_luma_coeff_abs[j][k] * (1 - 2 * alf->alf_luma_coeff_sign[j][k]);
+                    alf_param.alf_luma_clip_idx[j][k] = alf->alf_luma_clip_idx[j][k];
+                }
+            }
+
+            for (j = 0; j < 8; j++) {
+                for (k = 0; k < 6; k++) {
+                    alf_param.AlfCoeffC[j][k]           = alf->alf_chroma_coeff_abs[j][k] * (1 - 2 * alf->alf_chroma_coeff_sign[j][k]);
+                    alf_param.alf_chroma_clip_idx[j][k] = alf->alf_chroma_clip_idx[j][k];
+                }
+            }
+
+            for (j = 0; j < 4; j++) {
+                for (k = 0; k < 7; k++) {
+                    if (alf->alf_cc_cb_mapped_coeff_abs[j][k])
+                        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));
+                    if (alf->alf_cc_cr_mapped_coeff_abs[j][k])
+                        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));
+                }
+            }
+
+            err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
+                                                    VAAlfBufferType,
+                                                    &alf_param, sizeof(VAAlfDataVVC));
+            if (err < 0)
+                goto fail;
+        }
+    }
+
+    for (i = 0; i < VVC_MAX_LMCS_COUNT; i++) {
+        const H266RawAPS *lmcs = h->ps.lmcs_list[i];
+        if (lmcs) {
+            VALmcsDataVVC lmcs_param = {
+                .aps_adaptation_parameter_set_id = i,
+                .lmcs_min_bin_idx                = lmcs->lmcs_min_bin_idx,
+                .lmcs_delta_max_bin_idx          = lmcs->lmcs_delta_max_bin_idx,
+                .lmcsDeltaCrs                    = (1 - 2 * lmcs->lmcs_delta_sign_crs_flag) * lmcs->lmcs_delta_abs_crs,
+            };
+
+            for (j = lmcs->lmcs_min_bin_idx; j <= 15 - lmcs->lmcs_delta_max_bin_idx; j++)
+                lmcs_param.lmcsDeltaCW[j] = (1 - 2 * lmcs->lmcs_delta_sign_cw_flag[j]) * lmcs->lmcs_delta_abs_cw[j];
+
+            err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
+                                                    VALmcsBufferType,
+                                                    &lmcs_param, sizeof(VALmcsDataVVC));
+            if (err < 0)
+                goto fail;
+        }
+    }
+
+    for (i = 0; i < VVC_MAX_SL_COUNT; i++) {
+        const VVCScalingList *sl = h->ps.scaling_list[i];
+        if (sl) {
+            int l;
+
+            VAScalingListVVC sl_param = {
+                .aps_adaptation_parameter_set_id = i,
+            };
+
+            for (j = 0; j < 14; j++)
+                sl_param.ScalingMatrixDCRec[j] = sl->scaling_matrix_dc_rec[j];
+
+            for (j = 0; j < 2; j++)
+                for (k = 0; k < 2; k++)
+                    for (l = 0; l < 2; l++)
+                        sl_param.ScalingMatrixRec2x2[j][k][l] = sl->scaling_matrix_rec[j][l * 2 + k];
+
+            for (j = 2; j < 8; j++)
+                for (k = 0; k < 4; k++)
+                    for (l = 0; l < 4; l++)
+                        sl_param.ScalingMatrixRec4x4[j - 2][k][l] = sl->scaling_matrix_rec[j][l * 4 + k];
+
+            for (j = 8; j < 28; j++)
+                for (k = 0; k < 8; k++)
+                    for (l = 0; l < 8; l++)
+                        sl_param.ScalingMatrixRec8x8[j - 8][k][l] = sl->scaling_matrix_rec[j][l * 8 + k];
+
+            err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
+                                                    VAIQMatrixBufferType,
+                                                    &sl_param, sizeof(VAScalingListVVC));
+            if (err < 0)
+                goto fail;
+        }
+    }
+
+    for (i = 0; i <= pps->pps_num_exp_tile_columns_minus1; i++) {
+        tile_dim = pps->pps_tile_column_width_minus1[i];
+        err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
+                                                VATileBufferType,
+                                                &tile_dim, sizeof(tile_dim));
+        if (err < 0)
+            goto fail;
+    }
+
+    for (i = 0; i <= pps->pps_num_exp_tile_rows_minus1; i++) {
+        tile_dim = pps->pps_tile_row_height_minus1[i];
+        err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
+                                                VATileBufferType,
+                                                &tile_dim, sizeof(tile_dim));
+        if (err < 0)
+            goto fail;
+    }
+
+    if (!pps->pps_no_pic_partition_flag && pps->pps_rect_slice_flag && !pps->pps_single_slice_per_subpic_flag) {
+        for (i = 0; i <= pps->pps_num_slices_in_pic_minus1; i++) {
+            for (j = 0; j < pps->pps_num_exp_slices_in_tile[i]; j++) {
+                exp_slice_height_in_ctus[i + j] = pps->pps_exp_slice_height_in_ctus_minus1[i][j] + 1;
+            }
+        }
+        for (i = 0; i <= pps->pps_num_slices_in_pic_minus1; i++) {
+            VASliceStructVVC ss_param = {
+                .SliceTopLeftTileIdx              = pps->slice_top_left_tile_idx[i],
+                .pps_slice_width_in_tiles_minus1  = pps->pps_slice_width_in_tiles_minus1[i],
+                .pps_slice_height_in_tiles_minus1 = pps->pps_slice_height_in_tiles_minus1[i],
+            };
+
+            if (pps->pps_slice_width_in_tiles_minus1[i] > 0 || pps->pps_slice_height_in_tiles_minus1[i] > 0)
+                ss_param.pps_exp_slice_height_in_ctus_minus1 = 0;
+            else {
+                if (pps->num_slices_in_tile[i] == 1)
+                    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;
+                else if (exp_slice_height_in_ctus[i])
+                    ss_param.pps_exp_slice_height_in_ctus_minus1 = exp_slice_height_in_ctus[i] - 1;
+                else
+                    continue;
+            }
+
+            err = ff_vaapi_decode_make_param_buffer(avctx, &pic->pic,
+                                                    VASliceStructBufferType,
+                                                    &ss_param, sizeof(VASliceStructVVC));
+            if (err < 0)
+                goto fail;
+        }
+    }
+
+    return 0;
+
+fail:
+    ff_vaapi_decode_cancel(avctx, &pic->pic);
+    return err;
+}
+
+static uint8_t get_ref_pic_index(const VVCContext *h, const VVCFrame *frame)
+{
+    VVCFrameContext             *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs];
+    VAAPIDecodePictureVVC      *pic = fc->ref->hwaccel_picture_private;
+    VAPictureParameterBufferVVC *pp = (VAPictureParameterBufferVVC *)&pic->pic_param;
+    uint8_t i;
+
+    if (!frame)
+        return 0xFF;
+
+    for (i = 0; i < FF_ARRAY_ELEMS(pp->ReferenceFrames); i++) {
+        VASurfaceID pid = pp->ReferenceFrames[i].picture_id;
+        int poc = pp->ReferenceFrames[i].pic_order_cnt;
+        if (pid != VA_INVALID_ID && pid == ff_vaapi_get_surface_id(frame->frame) && poc == frame->poc)
+            return i;
+    }
+
+    return 0xFF;
+}
+
+static int get_slice_data_offset(const uint8_t *buffer, uint32_t size, const SliceContext* sc)
+{
+    const H266RawSlice *slice = sc->ref;
+    int num_identical_bytes   = slice->data_size < 32 ? slice->data_size : 32;
+
+    for (int i = 0; i < size; i++) {
+        int skip_bytes = 0;
+        if (i >=2 && buffer[i] == 0x03 && !buffer[i - 1] && !buffer[i - 2])
+            continue;
+
+        for (int j = 0; j < num_identical_bytes; j++) {
+            if (i >= 2 && buffer[i + j + skip_bytes] == 0x03 && !buffer[i + j + skip_bytes - 1] && !buffer[i + j + skip_bytes - 2])
+                skip_bytes++;
+
+            if (buffer[i + j + skip_bytes] != slice->data[j])
+                break;
+
+            if (j + 1 == num_identical_bytes)
+                return i;
+        }
+    }
+
+    return 0;
+}
+
+static int vaapi_vvc_decode_slice(AVCodecContext *avctx,
+                                   const uint8_t *buffer,
+                                   uint32_t       size)
+{
+    const VVCContext                    *h = avctx->priv_data;
+    VVCFrameContext                    *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs];
+    const SliceContext                 *sc = fc->slices[fc->nb_slices];
+    const H266RawPPS                  *pps = fc->ps.pps->r;
+    const H266RawPictureHeader         *ph = fc->ps.ph.r;
+    const H266RawSliceHeader           *sh = sc->sh.r;
+    VAAPIDecodePictureVVC             *pic = fc->ref->hwaccel_picture_private;
+    VASliceParameterBufferVVC *slice_param = &pic->slice_param;
+    int nb_list, i, err;
+
+    *slice_param = (VASliceParameterBufferVVC) {
+        .slice_data_size                 = size,
+        .slice_data_offset               = 0,
+        .slice_data_flag                 = VA_SLICE_DATA_FLAG_ALL,
+        .slice_data_byte_offset          = get_slice_data_offset(buffer, size, sc),
+        .sh_subpic_id                    = sh->sh_subpic_id,
+        .sh_slice_address                = sh->sh_slice_address,
+        .sh_num_tiles_in_slice_minus1    = sh->sh_num_tiles_in_slice_minus1,
+        .sh_slice_type                   = sh->sh_slice_type,
+        .sh_num_alf_aps_ids_luma         = sh->sh_num_alf_aps_ids_luma,
+        .sh_alf_aps_id_chroma            = sh->sh_alf_aps_id_chroma,
+        .sh_alf_cc_cb_aps_id             = sh->sh_alf_cc_cb_aps_id,
+        .sh_alf_cc_cr_aps_id             = sh->sh_alf_cc_cr_aps_id,
+        .NumRefIdxActive[0]              = sh->num_ref_idx_active[0],
+        .NumRefIdxActive[1]              = sh->num_ref_idx_active[1],
+        .sh_collocated_ref_idx           = sh->sh_collocated_ref_idx,
+        .SliceQpY                        = pps->pps_qp_delta_info_in_ph_flag ?
+                                           26 + pps->pps_init_qp_minus26 + ph->ph_qp_delta :
+                                           26 + pps->pps_init_qp_minus26 + sh->sh_qp_delta,
+        .sh_cb_qp_offset                 = sh->sh_cb_qp_offset,
+        .sh_cr_qp_offset                 = sh->sh_cr_qp_offset,
+        .sh_joint_cbcr_qp_offset         = sh->sh_joint_cbcr_qp_offset,
+        .sh_luma_beta_offset_div2        = sh->sh_luma_beta_offset_div2,
+        .sh_luma_tc_offset_div2          = sh->sh_luma_tc_offset_div2,
+        .sh_cb_beta_offset_div2          = sh->sh_cb_beta_offset_div2,
+        .sh_cb_tc_offset_div2            = sh->sh_cb_tc_offset_div2,
+        .sh_cr_beta_offset_div2          = sh->sh_cr_beta_offset_div2,
+        .sh_cr_tc_offset_div2            = sh->sh_cr_tc_offset_div2,
+        .WPInfo = {
+            .luma_log2_weight_denom         = sh->sh_pred_weight_table.luma_log2_weight_denom,
+            .delta_chroma_log2_weight_denom = sh->sh_pred_weight_table.delta_chroma_log2_weight_denom,
+            .num_l0_weights                 = sh->sh_pred_weight_table.num_l0_weights,
+            .num_l1_weights                 = sh->sh_pred_weight_table.num_l1_weights,
+        },
+        .sh_flags.bits = {
+            .sh_alf_enabled_flag                 = sh->sh_alf_enabled_flag,
+            .sh_alf_cb_enabled_flag              = sh->sh_alf_cb_enabled_flag,
+            .sh_alf_cr_enabled_flag              = sh->sh_alf_cr_enabled_flag,
+            .sh_alf_cc_cb_enabled_flag           = sh->sh_alf_cc_cb_enabled_flag,
+            .sh_alf_cc_cr_enabled_flag           = sh->sh_alf_cc_cr_enabled_flag,
+            .sh_lmcs_used_flag                   = sh->sh_lmcs_used_flag,
+            .sh_explicit_scaling_list_used_flag  = sh->sh_explicit_scaling_list_used_flag,
+            .sh_cabac_init_flag                  = sh->sh_cabac_init_flag,
+            .sh_collocated_from_l0_flag          = sh->sh_collocated_from_l0_flag,
+            .sh_cu_chroma_qp_offset_enabled_flag = sh->sh_cu_chroma_qp_offset_enabled_flag,
+            .sh_sao_luma_used_flag               = sh->sh_sao_luma_used_flag,
+            .sh_sao_chroma_used_flag             = sh->sh_sao_chroma_used_flag,
+            .sh_deblocking_filter_disabled_flag  = sh->sh_deblocking_filter_disabled_flag,
+            .sh_dep_quant_used_flag              = sh->sh_dep_quant_used_flag,
+            .sh_sign_data_hiding_used_flag       = sh->sh_sign_data_hiding_used_flag,
+            .sh_ts_residual_coding_disabled_flag = sh->sh_ts_residual_coding_disabled_flag,
+        },
+    };
+
+    memset(&slice_param->RefPicList, 0xFF, sizeof(slice_param->RefPicList));
+
+    nb_list = (sh->sh_slice_type == VVC_SLICE_TYPE_B) ?
+              2 : (sh->sh_slice_type == VVC_SLICE_TYPE_I ? 0 : 1);
+    for (int list_idx = 0; list_idx < nb_list; list_idx++) {
+        RefPicList *rpl = &sc->rpl[list_idx];
+
+        for (i = 0; i < rpl->nb_refs; i++)
+            slice_param->RefPicList[list_idx][i] = get_ref_pic_index(h, rpl->ref[i]);
+    }
+
+    for (i = 0; i < 7; i++)
+        slice_param->sh_alf_aps_id_luma[i] = sh->sh_alf_aps_id_luma[i];
+
+    for (i = 0; i < 15; i++) {
+        slice_param->WPInfo.luma_weight_l0_flag[i]   = sh->sh_pred_weight_table.luma_weight_l0_flag[i];
+        slice_param->WPInfo.chroma_weight_l0_flag[i] = sh->sh_pred_weight_table.chroma_weight_l0_flag[i];
+        slice_param->WPInfo.delta_luma_weight_l0[i]  = sh->sh_pred_weight_table.delta_luma_weight_l0[i];
+        slice_param->WPInfo.luma_offset_l0[i]        = sh->sh_pred_weight_table.luma_offset_l0[i];
+        slice_param->WPInfo.luma_weight_l1_flag[i]   = sh->sh_pred_weight_table.luma_weight_l1_flag[i];
+        slice_param->WPInfo.chroma_weight_l1_flag[i] = sh->sh_pred_weight_table.chroma_weight_l1_flag[i];
+        slice_param->WPInfo.delta_luma_weight_l1[i]  = sh->sh_pred_weight_table.delta_luma_weight_l1[i];
+        slice_param->WPInfo.luma_offset_l1[i]        = sh->sh_pred_weight_table.luma_offset_l1[i];
+    }
+
+    for (i = 0; i < 15; i++) {
+        for (int j = 0; j < 2; j++) {
+            slice_param->WPInfo.delta_chroma_weight_l0[i][j] = sh->sh_pred_weight_table.delta_chroma_weight_l0[i][j];
+            slice_param->WPInfo.delta_chroma_offset_l0[i][j] = sh->sh_pred_weight_table.delta_chroma_offset_l0[i][j];
+            slice_param->WPInfo.delta_chroma_weight_l1[i][j] = sh->sh_pred_weight_table.delta_chroma_weight_l1[i][j];
+            slice_param->WPInfo.delta_chroma_offset_l1[i][j] = sh->sh_pred_weight_table.delta_chroma_offset_l1[i][j];
+        }
+    }
+
+    err = ff_vaapi_decode_make_slice_buffer(avctx, &pic->pic,
+                                            &pic->slice_param,
+                                            sizeof(VASliceParameterBufferVVC),
+                                            buffer, size);
+    if (err) {
+        ff_vaapi_decode_cancel(avctx, &pic->pic);
+        return err;
+    }
+
+    return 0;
+}
+
+static int vaapi_vvc_end_frame(AVCodecContext *avctx)
+{
+
+    const VVCContext        *h = avctx->priv_data;
+    VVCFrameContext        *fc = &h->fcs[(h->nb_frames + h->nb_fcs) % h->nb_fcs];
+    VAAPIDecodePictureVVC *pic = fc->ref->hwaccel_picture_private;
+    int ret;
+
+    ret = ff_vaapi_decode_issue(avctx, &pic->pic);
+    if (ret < 0)
+        goto fail;
+
+    pic->decode_issued = 1;
+
+    return 0;
+
+fail:
+    ff_vaapi_decode_cancel(avctx, &pic->pic);
+    return ret;
+}
+
+const FFHWAccel ff_vvc_vaapi_hwaccel = {
+    .p.name               = "vvc_vaapi",
+    .p.type               = AVMEDIA_TYPE_VIDEO,
+    .p.id                 = AV_CODEC_ID_VVC,
+    .p.pix_fmt            = AV_PIX_FMT_VAAPI,
+    .start_frame          = &vaapi_vvc_start_frame,
+    .end_frame            = &vaapi_vvc_end_frame,
+    .decode_slice         = &vaapi_vvc_decode_slice,
+    .frame_priv_data_size = sizeof(VAAPIDecodePictureVVC),
+    .init                 = &ff_vaapi_decode_init,
+    .uninit               = &ff_vaapi_decode_uninit,
+    .frame_params         = &ff_vaapi_common_frame_params,
+    .priv_data_size       = sizeof(VAAPIDecodeContext),
+    .caps_internal        = HWACCEL_CAP_ASYNC_SAFE,
+};
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 06631ffa8c..7aa95fc3f1 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@ 
 
 #include "version_major.h"
 
-#define LIBAVCODEC_VERSION_MINOR   4
+#define LIBAVCODEC_VERSION_MINOR   5
 #define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
diff --git a/libavcodec/vvc/vvcdec.c b/libavcodec/vvc/vvcdec.c
index f2e269ce76..b204a0c73a 100644
--- a/libavcodec/vvc/vvcdec.c
+++ b/libavcodec/vvc/vvcdec.c
@@ -29,6 +29,7 @@ 
 #include "libavutil/cpu.h"
 #include "libavutil/thread.h"
 
+#include "config_components.h"
 #include "vvcdec.h"
 #include "vvc_ctu.h"
 #include "vvc_data.h"
@@ -724,14 +725,20 @@  static int slice_start(SliceContext *sc, VVCContext *s, VVCFrameContext *fc,
 
 static enum AVPixelFormat get_format(AVCodecContext *avctx, const VVCSPS *sps)
 {
-#define HWACCEL_MAX 0
+#define HWACCEL_MAX CONFIG_VVC_VAAPI_HWACCEL
 
     enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
 
     switch (sps->pix_fmt) {
     case AV_PIX_FMT_YUV420P:
+#if CONFIG_VVC_VAAPI_HWACCEL
+        *fmt++ = AV_PIX_FMT_VAAPI;
+#endif
         break;
     case AV_PIX_FMT_YUV420P10:
+#if CONFIG_VVC_VAAPI_HWACCEL
+        *fmt++ = AV_PIX_FMT_VAAPI;
+#endif
         break;
     }
 
@@ -1100,4 +1107,10 @@  const FFCodec ff_vvc_decoder = {
     .caps_internal  = FF_CODEC_CAP_EXPORTS_CROPPING | FF_CODEC_CAP_INIT_CLEANUP |
                       FF_CODEC_CAP_AUTO_THREADS,
     .p.profiles     = NULL_IF_CONFIG_SMALL(ff_vvc_profiles),
+    .hw_configs     = (const AVCodecHWConfigInternal *const []) {
+#if CONFIG_VVC_VAAPI_HWACCEL
+                    HWACCEL_VAAPI(vvc),
+#endif
+    NULL
+    },
 };