diff options
author | Fei Wang <fei.w.wang@intel.com> | 2024-10-28 16:55:25 +0800 |
---|---|---|
committer | Haihao Xiang <haihao.xiang@intel.com> | 2024-11-01 12:13:07 +0800 |
commit | e726fdeb0550d121e287fc9c5ee6673ab8f66bf4 (patch) | |
tree | fecc5de24e1c615876c94c5b132520ff23f0bc4e | |
parent | 4dc18c78cd1872a6de0b9640a4c5eca35f5dfbfd (diff) | |
download | ffmpeg-e726fdeb0550d121e287fc9c5ee6673ab8f66bf4.tar.gz |
lavc/vaapi_dec: Add VVC decoder
Signed-off-by: Fei Wang <fei.w.wang@intel.com>
-rw-r--r-- | Changelog | 1 | ||||
-rwxr-xr-x | configure | 3 | ||||
-rw-r--r-- | libavcodec/Makefile | 1 | ||||
-rw-r--r-- | libavcodec/hwaccels.h | 1 | ||||
-rw-r--r-- | libavcodec/vaapi_decode.c | 4 | ||||
-rw-r--r-- | libavcodec/vaapi_vvc.c | 657 | ||||
-rw-r--r-- | libavcodec/version.h | 2 | ||||
-rw-r--r-- | libavcodec/vvc/dec.c | 15 |
8 files changed, 682 insertions, 2 deletions
@@ -3,6 +3,7 @@ releases are sorted from youngest to oldest. version <next>: - yasm support dropped, users need to use nasm +- VVC VAAPI decoder version 7.1: - Raw Captions with Time (RCWT) closed caption demuxer @@ -3289,6 +3289,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" @@ -7310,6 +7312,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 dd5d0de898..270f39d5b3 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1064,6 +1064,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 2b9bdc8fc9..910a024032 100644 --- a/libavcodec/hwaccels.h +++ b/libavcodec/hwaccels.h @@ -83,6 +83,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 7753f72106..4ac2df5b43 100644 --- a/libavcodec/vaapi_decode.c +++ b/libavcodec/vaapi_decode.c @@ -464,6 +464,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 }; @@ -629,6 +632,7 @@ static int vaapi_decode_make_config(AVCodecContext *avctx, // Add per-codec number of surfaces used for storing reference frames. switch (avctx->codec_id) { case AV_CODEC_ID_H264: + case AV_CODEC_ID_H266: case AV_CODEC_ID_HEVC: case AV_CODEC_ID_AV1: frames->initial_pool_size += 16; diff --git a/libavcodec/vaapi_vvc.c b/libavcodec/vaapi_vvc.c new file mode 100644 index 0000000000..310b56e5a4 --- /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/dec.h" +#include "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_ccalf_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_byte_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_byte_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->refs[i].ref); + } + + 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, 1, + 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 9411511e04..728ab8839d 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,7 +29,7 @@ #include "version_major.h" -#define LIBAVCODEC_VERSION_MINOR 22 +#define LIBAVCODEC_VERSION_MINOR 23 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ diff --git a/libavcodec/vvc/dec.c b/libavcodec/vvc/dec.c index 8e8d66851a..50be9f9922 100644 --- a/libavcodec/vvc/dec.c +++ b/libavcodec/vvc/dec.c @@ -35,6 +35,7 @@ #include "data.h" #include "refs.h" #include "thread.h" +#include "config_components.h" #define TAB_MAX 32 @@ -772,14 +773,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; } @@ -1171,4 +1178,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 + }, }; |