mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
h264dec: add Vulkan hwaccel
Thanks to Dave Airlie for figuring out a lot of the parameters.
This commit is contained in:
parent
1e8fefff93
commit
a9fbe8b472
2
configure
vendored
2
configure
vendored
@ -3038,6 +3038,8 @@ h264_vdpau_hwaccel_deps="vdpau"
|
||||
h264_vdpau_hwaccel_select="h264_decoder"
|
||||
h264_videotoolbox_hwaccel_deps="videotoolbox"
|
||||
h264_videotoolbox_hwaccel_select="h264_decoder"
|
||||
h264_vulkan_hwaccel_deps="vulkan"
|
||||
h264_vulkan_hwaccel_select="h264_decoder"
|
||||
hevc_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_HEVC"
|
||||
hevc_d3d11va_hwaccel_select="hevc_decoder"
|
||||
hevc_d3d11va2_hwaccel_deps="d3d11va DXVA_PicParams_HEVC"
|
||||
|
@ -998,6 +998,7 @@ OBJS-$(CONFIG_H264_QSV_HWACCEL) += qsvdec.o
|
||||
OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o
|
||||
OBJS-$(CONFIG_H264_VDPAU_HWACCEL) += vdpau_h264.o
|
||||
OBJS-$(CONFIG_H264_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o
|
||||
OBJS-$(CONFIG_H264_VULKAN_HWACCEL) += vulkan_decode.o vulkan_h264.o
|
||||
OBJS-$(CONFIG_HEVC_D3D11VA_HWACCEL) += dxva2_hevc.o
|
||||
OBJS-$(CONFIG_HEVC_DXVA2_HWACCEL) += dxva2_hevc.o
|
||||
OBJS-$(CONFIG_HEVC_NVDEC_HWACCEL) += nvdec_hevc.o
|
||||
|
@ -781,7 +781,8 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
|
||||
CONFIG_H264_NVDEC_HWACCEL + \
|
||||
CONFIG_H264_VAAPI_HWACCEL + \
|
||||
CONFIG_H264_VIDEOTOOLBOX_HWACCEL + \
|
||||
CONFIG_H264_VDPAU_HWACCEL)
|
||||
CONFIG_H264_VDPAU_HWACCEL + \
|
||||
CONFIG_H264_VULKAN_HWACCEL)
|
||||
enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
|
||||
const enum AVPixelFormat *choices = pix_fmts;
|
||||
int i;
|
||||
@ -802,6 +803,9 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
|
||||
#if CONFIG_H264_VIDEOTOOLBOX_HWACCEL
|
||||
if (h->avctx->colorspace != AVCOL_SPC_RGB)
|
||||
*fmt++ = AV_PIX_FMT_VIDEOTOOLBOX;
|
||||
#endif
|
||||
#if CONFIG_H264_VULKAN_HWACCEL
|
||||
*fmt++ = AV_PIX_FMT_VULKAN;
|
||||
#endif
|
||||
if (CHROMA444(h)) {
|
||||
if (h->avctx->colorspace == AVCOL_SPC_RGB) {
|
||||
@ -821,6 +825,9 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
#if CONFIG_H264_VULKAN_HWACCEL
|
||||
*fmt++ = AV_PIX_FMT_VULKAN;
|
||||
#endif
|
||||
if (CHROMA444(h)) {
|
||||
if (h->avctx->colorspace == AVCOL_SPC_RGB) {
|
||||
*fmt++ = AV_PIX_FMT_GBRP12;
|
||||
@ -846,6 +853,9 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
|
||||
#if CONFIG_H264_VDPAU_HWACCEL
|
||||
*fmt++ = AV_PIX_FMT_VDPAU;
|
||||
#endif
|
||||
#if CONFIG_H264_VULKAN_HWACCEL
|
||||
*fmt++ = AV_PIX_FMT_VULKAN;
|
||||
#endif
|
||||
#if CONFIG_H264_NVDEC_HWACCEL
|
||||
*fmt++ = AV_PIX_FMT_CUDA;
|
||||
#endif
|
||||
|
@ -1100,6 +1100,9 @@ const FFCodec ff_h264_decoder = {
|
||||
#endif
|
||||
#if CONFIG_H264_VIDEOTOOLBOX_HWACCEL
|
||||
HWACCEL_VIDEOTOOLBOX(h264),
|
||||
#endif
|
||||
#if CONFIG_H264_VULKAN_HWACCEL
|
||||
HWACCEL_VULKAN(h264),
|
||||
#endif
|
||||
NULL
|
||||
},
|
||||
|
@ -36,6 +36,7 @@ extern const AVHWAccel ff_h264_nvdec_hwaccel;
|
||||
extern const AVHWAccel ff_h264_vaapi_hwaccel;
|
||||
extern const AVHWAccel ff_h264_vdpau_hwaccel;
|
||||
extern const AVHWAccel ff_h264_videotoolbox_hwaccel;
|
||||
extern const AVHWAccel ff_h264_vulkan_hwaccel;
|
||||
extern const AVHWAccel ff_hevc_d3d11va_hwaccel;
|
||||
extern const AVHWAccel ff_hevc_d3d11va2_hwaccel;
|
||||
extern const AVHWAccel ff_hevc_dxva2_hwaccel;
|
||||
|
559
libavcodec/vulkan_h264.c
Normal file
559
libavcodec/vulkan_h264.c
Normal file
@ -0,0 +1,559 @@
|
||||
/*
|
||||
* 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 "h264dec.h"
|
||||
#include "h264_ps.h"
|
||||
|
||||
#include "vulkan_decode.h"
|
||||
|
||||
const VkExtensionProperties ff_vk_dec_h264_ext = {
|
||||
.extensionName = VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_EXTENSION_NAME,
|
||||
.specVersion = VK_STD_VULKAN_VIDEO_CODEC_H264_DECODE_SPEC_VERSION,
|
||||
};
|
||||
|
||||
typedef struct H264VulkanDecodePicture {
|
||||
FFVulkanDecodePicture vp;
|
||||
|
||||
/* Current picture */
|
||||
StdVideoDecodeH264ReferenceInfo h264_ref;
|
||||
VkVideoDecodeH264DpbSlotInfoKHR vkh264_ref;
|
||||
|
||||
/* Picture refs */
|
||||
H264Picture *ref_src [H264_MAX_PICTURE_COUNT];
|
||||
StdVideoDecodeH264ReferenceInfo h264_refs [H264_MAX_PICTURE_COUNT];
|
||||
VkVideoDecodeH264DpbSlotInfoKHR vkh264_refs[H264_MAX_PICTURE_COUNT];
|
||||
|
||||
/* Current picture (contd.) */
|
||||
StdVideoDecodeH264PictureInfo h264pic;
|
||||
VkVideoDecodeH264PictureInfoKHR h264_pic_info;
|
||||
} H264VulkanDecodePicture;
|
||||
|
||||
static int vk_h264_fill_pict(AVCodecContext *avctx, H264Picture **ref_src,
|
||||
VkVideoReferenceSlotInfoKHR *ref_slot, /* Main structure */
|
||||
VkVideoPictureResourceInfoKHR *ref, /* Goes in ^ */
|
||||
VkVideoDecodeH264DpbSlotInfoKHR *vkh264_ref, /* Goes in ^ */
|
||||
StdVideoDecodeH264ReferenceInfo *h264_ref, /* Goes in ^ */
|
||||
H264Picture *pic, int is_current,
|
||||
int is_field, int picture_structure,
|
||||
int dpb_slot_index)
|
||||
{
|
||||
FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
|
||||
H264VulkanDecodePicture *hp = pic->hwaccel_picture_private;
|
||||
FFVulkanDecodePicture *vkpic = &hp->vp;
|
||||
|
||||
int err = ff_vk_decode_prepare_frame(dec, pic->f, vkpic, is_current,
|
||||
dec->dedicated_dpb);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
*h264_ref = (StdVideoDecodeH264ReferenceInfo) {
|
||||
.FrameNum = pic->long_ref ? pic->pic_id : pic->frame_num,
|
||||
.PicOrderCnt = { pic->field_poc[0], pic->field_poc[1] },
|
||||
.flags = (StdVideoDecodeH264ReferenceInfoFlags) {
|
||||
.top_field_flag = is_field ? !!(picture_structure & PICT_TOP_FIELD) : 0,
|
||||
.bottom_field_flag = is_field ? !!(picture_structure & PICT_BOTTOM_FIELD) : 0,
|
||||
.used_for_long_term_reference = pic->reference && pic->long_ref,
|
||||
.is_non_existing = 0,
|
||||
},
|
||||
};
|
||||
|
||||
*vkh264_ref = (VkVideoDecodeH264DpbSlotInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR,
|
||||
.pStdReferenceInfo = h264_ref,
|
||||
};
|
||||
|
||||
*ref = (VkVideoPictureResourceInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR,
|
||||
.codedOffset = (VkOffset2D){ 0, 0 },
|
||||
.codedExtent = (VkExtent2D){ pic->f->width, pic->f->height },
|
||||
.baseArrayLayer = dec->layered_dpb ? dpb_slot_index : 0,
|
||||
.imageViewBinding = vkpic->img_view_ref,
|
||||
};
|
||||
|
||||
*ref_slot = (VkVideoReferenceSlotInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR,
|
||||
.pNext = vkh264_ref,
|
||||
.slotIndex = dpb_slot_index,
|
||||
.pPictureResource = ref,
|
||||
};
|
||||
|
||||
if (ref_src)
|
||||
*ref_src = pic;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static StdVideoH264LevelIdc convert_to_vk_level_idc(int level_idc)
|
||||
{
|
||||
switch (level_idc) {
|
||||
case 10: return STD_VIDEO_H264_LEVEL_IDC_1_0;
|
||||
case 11: return STD_VIDEO_H264_LEVEL_IDC_1_1;
|
||||
case 12: return STD_VIDEO_H264_LEVEL_IDC_1_2;
|
||||
case 13: return STD_VIDEO_H264_LEVEL_IDC_1_3;
|
||||
case 20: return STD_VIDEO_H264_LEVEL_IDC_2_0;
|
||||
case 21: return STD_VIDEO_H264_LEVEL_IDC_2_1;
|
||||
case 22: return STD_VIDEO_H264_LEVEL_IDC_2_2;
|
||||
case 30: return STD_VIDEO_H264_LEVEL_IDC_3_0;
|
||||
case 31: return STD_VIDEO_H264_LEVEL_IDC_3_1;
|
||||
case 32: return STD_VIDEO_H264_LEVEL_IDC_3_2;
|
||||
case 40: return STD_VIDEO_H264_LEVEL_IDC_4_0;
|
||||
case 41: return STD_VIDEO_H264_LEVEL_IDC_4_1;
|
||||
case 42: return STD_VIDEO_H264_LEVEL_IDC_4_2;
|
||||
case 50: return STD_VIDEO_H264_LEVEL_IDC_5_0;
|
||||
case 51: return STD_VIDEO_H264_LEVEL_IDC_5_1;
|
||||
case 52: return STD_VIDEO_H264_LEVEL_IDC_5_2;
|
||||
case 60: return STD_VIDEO_H264_LEVEL_IDC_6_0;
|
||||
case 61: return STD_VIDEO_H264_LEVEL_IDC_6_1;
|
||||
default:
|
||||
case 62: return STD_VIDEO_H264_LEVEL_IDC_6_2;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_sps(const SPS *sps,
|
||||
StdVideoH264ScalingLists *vksps_scaling,
|
||||
StdVideoH264HrdParameters *vksps_vui_header,
|
||||
StdVideoH264SequenceParameterSetVui *vksps_vui,
|
||||
StdVideoH264SequenceParameterSet *vksps)
|
||||
{
|
||||
*vksps_scaling = (StdVideoH264ScalingLists) {
|
||||
.scaling_list_present_mask = sps->scaling_matrix_present_mask,
|
||||
.use_default_scaling_matrix_mask = 0, /* We already fill in the default matrix */
|
||||
};
|
||||
|
||||
for (int i = 0; i < STD_VIDEO_H264_SCALING_LIST_4X4_NUM_LISTS; i++)
|
||||
memcpy(vksps_scaling->ScalingList4x4[i], sps->scaling_matrix4[i],
|
||||
STD_VIDEO_H264_SCALING_LIST_4X4_NUM_ELEMENTS * sizeof(**sps->scaling_matrix4));
|
||||
|
||||
for (int i = 0; i < STD_VIDEO_H264_SCALING_LIST_8X8_NUM_LISTS; i++)
|
||||
memcpy(vksps_scaling->ScalingList8x8[i], sps->scaling_matrix8[i],
|
||||
STD_VIDEO_H264_SCALING_LIST_8X8_NUM_ELEMENTS * sizeof(**sps->scaling_matrix8));
|
||||
|
||||
*vksps_vui_header = (StdVideoH264HrdParameters) {
|
||||
.cpb_cnt_minus1 = sps->cpb_cnt - 1,
|
||||
.bit_rate_scale = sps->bit_rate_scale,
|
||||
.initial_cpb_removal_delay_length_minus1 = sps->initial_cpb_removal_delay_length - 1,
|
||||
.cpb_removal_delay_length_minus1 = sps->cpb_removal_delay_length - 1,
|
||||
.dpb_output_delay_length_minus1 = sps->dpb_output_delay_length - 1,
|
||||
.time_offset_length = sps->time_offset_length,
|
||||
};
|
||||
|
||||
for (int i = 0; i < sps->cpb_cnt; i++) {
|
||||
vksps_vui_header->bit_rate_value_minus1[i] = sps->bit_rate_value[i] - 1;
|
||||
vksps_vui_header->cpb_size_value_minus1[i] = sps->cpb_size_value[i] - 1;
|
||||
vksps_vui_header->cbr_flag[i] = (sps->cpr_flag >> i) & 0x1;
|
||||
}
|
||||
|
||||
*vksps_vui = (StdVideoH264SequenceParameterSetVui) {
|
||||
.aspect_ratio_idc = sps->vui.aspect_ratio_idc,
|
||||
.sar_width = sps->vui.sar.num,
|
||||
.sar_height = sps->vui.sar.den,
|
||||
.video_format = sps->vui.video_format,
|
||||
.colour_primaries = sps->vui.colour_primaries,
|
||||
.transfer_characteristics = sps->vui.transfer_characteristics,
|
||||
.matrix_coefficients = sps->vui.matrix_coeffs,
|
||||
.num_units_in_tick = sps->num_units_in_tick,
|
||||
.time_scale = sps->time_scale,
|
||||
.pHrdParameters = vksps_vui_header,
|
||||
.max_num_reorder_frames = sps->num_reorder_frames,
|
||||
.max_dec_frame_buffering = sps->max_dec_frame_buffering,
|
||||
.flags = (StdVideoH264SpsVuiFlags) {
|
||||
.aspect_ratio_info_present_flag = sps->vui.aspect_ratio_info_present_flag,
|
||||
.overscan_info_present_flag = sps->vui.overscan_info_present_flag,
|
||||
.overscan_appropriate_flag = sps->vui.overscan_appropriate_flag,
|
||||
.video_signal_type_present_flag = sps->vui.video_signal_type_present_flag,
|
||||
.video_full_range_flag = sps->vui.video_full_range_flag,
|
||||
.color_description_present_flag = sps->vui.colour_description_present_flag,
|
||||
.chroma_loc_info_present_flag = sps->vui.chroma_location,
|
||||
.timing_info_present_flag = sps->timing_info_present_flag,
|
||||
.fixed_frame_rate_flag = sps->fixed_frame_rate_flag,
|
||||
.bitstream_restriction_flag = sps->bitstream_restriction_flag,
|
||||
.nal_hrd_parameters_present_flag = sps->nal_hrd_parameters_present_flag,
|
||||
.vcl_hrd_parameters_present_flag = sps->vcl_hrd_parameters_present_flag,
|
||||
},
|
||||
};
|
||||
|
||||
*vksps = (StdVideoH264SequenceParameterSet) {
|
||||
.profile_idc = sps->profile_idc,
|
||||
.level_idc = convert_to_vk_level_idc(sps->level_idc),
|
||||
.seq_parameter_set_id = sps->sps_id,
|
||||
.chroma_format_idc = sps->chroma_format_idc,
|
||||
.bit_depth_luma_minus8 = sps->bit_depth_luma - 8,
|
||||
.bit_depth_chroma_minus8 = sps->bit_depth_chroma - 8,
|
||||
.log2_max_frame_num_minus4 = sps->log2_max_frame_num - 4,
|
||||
.pic_order_cnt_type = sps->poc_type,
|
||||
.log2_max_pic_order_cnt_lsb_minus4 = sps->poc_type ? 0 : sps->log2_max_poc_lsb - 4,
|
||||
.offset_for_non_ref_pic = sps->offset_for_non_ref_pic,
|
||||
.offset_for_top_to_bottom_field = sps->offset_for_top_to_bottom_field,
|
||||
.num_ref_frames_in_pic_order_cnt_cycle = sps->poc_cycle_length,
|
||||
.max_num_ref_frames = sps->ref_frame_count,
|
||||
.pic_width_in_mbs_minus1 = sps->mb_width - 1,
|
||||
.pic_height_in_map_units_minus1 = (sps->mb_height/(2 - sps->frame_mbs_only_flag)) - 1,
|
||||
.frame_crop_left_offset = sps->crop_left,
|
||||
.frame_crop_right_offset = sps->crop_right,
|
||||
.frame_crop_top_offset = sps->crop_top,
|
||||
.frame_crop_bottom_offset = sps->crop_bottom,
|
||||
.flags = (StdVideoH264SpsFlags) {
|
||||
.constraint_set0_flag = (sps->constraint_set_flags >> 0) & 0x1,
|
||||
.constraint_set1_flag = (sps->constraint_set_flags >> 1) & 0x1,
|
||||
.constraint_set2_flag = (sps->constraint_set_flags >> 2) & 0x1,
|
||||
.constraint_set3_flag = (sps->constraint_set_flags >> 3) & 0x1,
|
||||
.constraint_set4_flag = (sps->constraint_set_flags >> 4) & 0x1,
|
||||
.constraint_set5_flag = (sps->constraint_set_flags >> 5) & 0x1,
|
||||
.direct_8x8_inference_flag = sps->direct_8x8_inference_flag,
|
||||
.mb_adaptive_frame_field_flag = sps->mb_aff,
|
||||
.frame_mbs_only_flag = sps->frame_mbs_only_flag,
|
||||
.delta_pic_order_always_zero_flag = sps->delta_pic_order_always_zero_flag,
|
||||
.separate_colour_plane_flag = sps->residual_color_transform_flag,
|
||||
.gaps_in_frame_num_value_allowed_flag = sps->gaps_in_frame_num_allowed_flag,
|
||||
.qpprime_y_zero_transform_bypass_flag = sps->transform_bypass,
|
||||
.frame_cropping_flag = sps->crop,
|
||||
.seq_scaling_matrix_present_flag = sps->scaling_matrix_present,
|
||||
.vui_parameters_present_flag = sps->vui_parameters_present_flag,
|
||||
},
|
||||
.pOffsetForRefFrame = sps->offset_for_ref_frame,
|
||||
.pScalingLists = vksps_scaling,
|
||||
.pSequenceParameterSetVui = vksps_vui,
|
||||
};
|
||||
}
|
||||
|
||||
static void set_pps(const PPS *pps, const SPS *sps,
|
||||
StdVideoH264ScalingLists *vkpps_scaling,
|
||||
StdVideoH264PictureParameterSet *vkpps)
|
||||
{
|
||||
*vkpps_scaling = (StdVideoH264ScalingLists) {
|
||||
.scaling_list_present_mask = pps->pic_scaling_matrix_present_mask,
|
||||
.use_default_scaling_matrix_mask = 0, /* We already fill in the default matrix */
|
||||
};
|
||||
|
||||
for (int i = 0; i < STD_VIDEO_H264_SCALING_LIST_4X4_NUM_LISTS; i++)
|
||||
memcpy(vkpps_scaling->ScalingList4x4[i], pps->scaling_matrix4[i],
|
||||
STD_VIDEO_H264_SCALING_LIST_4X4_NUM_ELEMENTS * sizeof(**pps->scaling_matrix4));
|
||||
|
||||
for (int i = 0; i < STD_VIDEO_H264_SCALING_LIST_8X8_NUM_LISTS; i++)
|
||||
memcpy(vkpps_scaling->ScalingList8x8[i], pps->scaling_matrix8[i],
|
||||
STD_VIDEO_H264_SCALING_LIST_8X8_NUM_ELEMENTS * sizeof(**pps->scaling_matrix8));
|
||||
|
||||
*vkpps = (StdVideoH264PictureParameterSet) {
|
||||
.seq_parameter_set_id = pps->sps_id,
|
||||
.pic_parameter_set_id = pps->pps_id,
|
||||
.num_ref_idx_l0_default_active_minus1 = pps->ref_count[0] - 1,
|
||||
.num_ref_idx_l1_default_active_minus1 = pps->ref_count[1] - 1,
|
||||
.weighted_bipred_idc = pps->weighted_bipred_idc,
|
||||
.pic_init_qp_minus26 = pps->init_qp - 26,
|
||||
.pic_init_qs_minus26 = pps->init_qs - 26,
|
||||
.chroma_qp_index_offset = pps->chroma_qp_index_offset[0],
|
||||
.second_chroma_qp_index_offset = pps->chroma_qp_index_offset[1],
|
||||
.flags = (StdVideoH264PpsFlags) {
|
||||
.transform_8x8_mode_flag = pps->transform_8x8_mode,
|
||||
.redundant_pic_cnt_present_flag = pps->redundant_pic_cnt_present,
|
||||
.constrained_intra_pred_flag = pps->constrained_intra_pred,
|
||||
.deblocking_filter_control_present_flag = pps->deblocking_filter_parameters_present,
|
||||
.weighted_pred_flag = pps->weighted_pred,
|
||||
.bottom_field_pic_order_in_frame_present_flag = pps->pic_order_present,
|
||||
.entropy_coding_mode_flag = pps->cabac,
|
||||
.pic_scaling_matrix_present_flag = pps->pic_scaling_matrix_present_flag,
|
||||
},
|
||||
.pScalingLists = vkpps_scaling,
|
||||
};
|
||||
}
|
||||
|
||||
static int vk_h264_create_params(AVCodecContext *avctx, AVBufferRef **buf)
|
||||
{
|
||||
VkResult ret;
|
||||
FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
|
||||
FFVulkanDecodeShared *ctx = (FFVulkanDecodeShared *)dec->shared_ref->data;
|
||||
FFVulkanFunctions *vk = &ctx->s.vkfn;
|
||||
const H264Context *h = avctx->priv_data;
|
||||
|
||||
/* SPS */
|
||||
StdVideoH264ScalingLists vksps_scaling[MAX_SPS_COUNT];
|
||||
StdVideoH264HrdParameters vksps_vui_header[MAX_SPS_COUNT];
|
||||
StdVideoH264SequenceParameterSetVui vksps_vui[MAX_SPS_COUNT];
|
||||
StdVideoH264SequenceParameterSet vksps[MAX_SPS_COUNT];
|
||||
|
||||
/* PPS */
|
||||
StdVideoH264ScalingLists vkpps_scaling[MAX_PPS_COUNT];
|
||||
StdVideoH264PictureParameterSet vkpps[MAX_PPS_COUNT];
|
||||
|
||||
VkVideoDecodeH264SessionParametersAddInfoKHR h264_params_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR,
|
||||
.pStdSPSs = vksps,
|
||||
.stdSPSCount = 0,
|
||||
.pStdPPSs = vkpps,
|
||||
.stdPPSCount = 0,
|
||||
};
|
||||
VkVideoDecodeH264SessionParametersCreateInfoKHR h264_params = {
|
||||
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR,
|
||||
.pParametersAddInfo = &h264_params_info,
|
||||
};
|
||||
VkVideoSessionParametersCreateInfoKHR session_params_create = {
|
||||
.sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR,
|
||||
.pNext = &h264_params,
|
||||
.videoSession = ctx->common.session,
|
||||
.videoSessionParametersTemplate = NULL,
|
||||
};
|
||||
|
||||
AVBufferRef *tmp;
|
||||
VkVideoSessionParametersKHR *par = av_malloc(sizeof(*par));
|
||||
if (!par)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
/* SPS list */
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(h->ps.sps_list); i++) {
|
||||
if (h->ps.sps_list[i]) {
|
||||
const SPS *sps_l = (const SPS *)h->ps.sps_list[i]->data;
|
||||
int idx = h264_params_info.stdSPSCount;
|
||||
set_sps(sps_l, &vksps_scaling[idx], &vksps_vui_header[idx], &vksps_vui[idx], &vksps[idx]);
|
||||
h264_params_info.stdSPSCount++;
|
||||
}
|
||||
}
|
||||
|
||||
/* PPS list */
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(h->ps.pps_list); i++) {
|
||||
if (h->ps.pps_list[i]) {
|
||||
const PPS *pps_l = (const PPS *)h->ps.pps_list[i]->data;
|
||||
int idx = h264_params_info.stdPPSCount;
|
||||
set_pps(pps_l, pps_l->sps, &vkpps_scaling[idx], &vkpps[idx]);
|
||||
h264_params_info.stdPPSCount++;
|
||||
}
|
||||
}
|
||||
|
||||
h264_params.maxStdSPSCount = h264_params_info.stdSPSCount;
|
||||
h264_params.maxStdPPSCount = h264_params_info.stdPPSCount;
|
||||
|
||||
/* Create session parameters */
|
||||
ret = vk->CreateVideoSessionParametersKHR(ctx->s.hwctx->act_dev, &session_params_create,
|
||||
ctx->s.hwctx->alloc, par);
|
||||
if (ret != VK_SUCCESS) {
|
||||
av_log(avctx, AV_LOG_ERROR, "Unable to create Vulkan video session parameters: %s!\n",
|
||||
ff_vk_ret2str(ret));
|
||||
return AVERROR_EXTERNAL;
|
||||
}
|
||||
|
||||
tmp = av_buffer_create((uint8_t *)par, sizeof(*par), ff_vk_decode_free_params,
|
||||
ctx, 0);
|
||||
if (!tmp) {
|
||||
ff_vk_decode_free_params(ctx, (uint8_t *)par);
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
av_log(avctx, AV_LOG_DEBUG, "Created frame parameters: %i SPS %i PPS\n",
|
||||
h264_params_info.stdSPSCount, h264_params_info.stdPPSCount);
|
||||
|
||||
*buf = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vk_h264_start_frame(AVCodecContext *avctx,
|
||||
av_unused const uint8_t *buffer,
|
||||
av_unused uint32_t size)
|
||||
{
|
||||
int err;
|
||||
int dpb_slot_index = 0;
|
||||
H264Context *h = avctx->priv_data;
|
||||
H264Picture *pic = h->cur_pic_ptr;
|
||||
FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
|
||||
H264VulkanDecodePicture *hp = pic->hwaccel_picture_private;
|
||||
FFVulkanDecodePicture *vp = &hp->vp;
|
||||
|
||||
if (!dec->session_params || dec->params_changed) {
|
||||
av_buffer_unref(&dec->session_params);
|
||||
err = vk_h264_create_params(avctx, &dec->session_params);
|
||||
if (err < 0)
|
||||
return err;
|
||||
dec->params_changed = 0;
|
||||
}
|
||||
|
||||
/* Fill in main slot */
|
||||
dpb_slot_index = 0;
|
||||
for (unsigned slot = 0; slot < H264_MAX_PICTURE_COUNT; slot++) {
|
||||
if (pic == &h->DPB[slot]) {
|
||||
dpb_slot_index = slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
err = vk_h264_fill_pict(avctx, NULL, &vp->ref_slot, &vp->ref,
|
||||
&hp->vkh264_ref, &hp->h264_ref, pic, 1,
|
||||
h->DPB[dpb_slot_index].field_picture,
|
||||
h->DPB[dpb_slot_index].reference,
|
||||
dpb_slot_index);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Fill in short-term references */
|
||||
for (int i = 0; i < h->short_ref_count; i++) {
|
||||
dpb_slot_index = 0;
|
||||
for (unsigned slot = 0; slot < H264_MAX_PICTURE_COUNT; slot++) {
|
||||
if (h->short_ref[i] == &h->DPB[slot]) {
|
||||
dpb_slot_index = slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
err = vk_h264_fill_pict(avctx, &hp->ref_src[i], &vp->ref_slots[i],
|
||||
&vp->refs[i], &hp->vkh264_refs[i],
|
||||
&hp->h264_refs[i], h->short_ref[i], 0,
|
||||
h->DPB[dpb_slot_index].field_picture,
|
||||
h->DPB[dpb_slot_index].reference,
|
||||
dpb_slot_index);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Fill in long-term refs */
|
||||
for (int r = 0, i = h->short_ref_count; i < h->short_ref_count + h->long_ref_count; i++, r++) {
|
||||
dpb_slot_index = 0;
|
||||
for (unsigned slot = 0; slot < H264_MAX_PICTURE_COUNT; slot++) {
|
||||
if (h->long_ref[i] == &h->DPB[slot]) {
|
||||
dpb_slot_index = slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
err = vk_h264_fill_pict(avctx, &hp->ref_src[i], &vp->ref_slots[i],
|
||||
&vp->refs[i], &hp->vkh264_refs[i],
|
||||
&hp->h264_refs[i], h->long_ref[r], 0,
|
||||
h->DPB[dpb_slot_index].field_picture,
|
||||
h->DPB[dpb_slot_index].reference,
|
||||
dpb_slot_index);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
hp->h264pic = (StdVideoDecodeH264PictureInfo) {
|
||||
.seq_parameter_set_id = pic->pps->sps_id,
|
||||
.pic_parameter_set_id = pic->pps->pps_id,
|
||||
.frame_num = 0, /* Set later */
|
||||
.idr_pic_id = 0, /* Set later */
|
||||
.PicOrderCnt[0] = pic->field_poc[0],
|
||||
.PicOrderCnt[1] = pic->field_poc[1],
|
||||
.flags = (StdVideoDecodeH264PictureInfoFlags) {
|
||||
.field_pic_flag = FIELD_PICTURE(h),
|
||||
.is_intra = 1, /* Set later */
|
||||
.IdrPicFlag = h->picture_idr,
|
||||
.bottom_field_flag = h->picture_structure != PICT_FRAME &&
|
||||
h->picture_structure & PICT_BOTTOM_FIELD,
|
||||
.is_reference = h->nal_ref_idc != 0,
|
||||
.complementary_field_pair = h->first_field && FIELD_PICTURE(h),
|
||||
},
|
||||
};
|
||||
|
||||
hp->h264_pic_info = (VkVideoDecodeH264PictureInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_KHR,
|
||||
.pStdPictureInfo = &hp->h264pic,
|
||||
.sliceCount = 0,
|
||||
};
|
||||
|
||||
vp->decode_info = (VkVideoDecodeInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR,
|
||||
.pNext = &hp->h264_pic_info,
|
||||
.flags = 0x0,
|
||||
.pSetupReferenceSlot = &vp->ref_slot,
|
||||
.referenceSlotCount = h->short_ref_count + h->long_ref_count,
|
||||
.pReferenceSlots = vp->ref_slots,
|
||||
.dstPictureResource = (VkVideoPictureResourceInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR,
|
||||
.codedOffset = (VkOffset2D){ 0, 0 },
|
||||
.codedExtent = (VkExtent2D){ pic->f->width, pic->f->height },
|
||||
.baseArrayLayer = 0,
|
||||
.imageViewBinding = vp->img_view_out,
|
||||
},
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vk_h264_decode_slice(AVCodecContext *avctx,
|
||||
const uint8_t *data,
|
||||
uint32_t size)
|
||||
{
|
||||
const H264Context *h = avctx->priv_data;
|
||||
const H264SliceContext *sl = &h->slice_ctx[0];
|
||||
H264VulkanDecodePicture *hp = h->cur_pic_ptr->hwaccel_picture_private;
|
||||
FFVulkanDecodePicture *vp = &hp->vp;
|
||||
|
||||
int err = ff_vk_decode_add_slice(avctx, vp, data, size, 1,
|
||||
&hp->h264_pic_info.sliceCount,
|
||||
&hp->h264_pic_info.pSliceOffsets);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
hp->h264pic.frame_num = sl->frame_num;
|
||||
hp->h264pic.idr_pic_id = sl->idr_pic_id;
|
||||
|
||||
/* Frame is only intra of all slices are marked as intra */
|
||||
if (sl->slice_type != AV_PICTURE_TYPE_I && sl->slice_type != AV_PICTURE_TYPE_SI)
|
||||
hp->h264pic.flags.is_intra = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vk_h264_end_frame(AVCodecContext *avctx)
|
||||
{
|
||||
const H264Context *h = avctx->priv_data;
|
||||
H264Picture *pic = h->cur_pic_ptr;
|
||||
H264VulkanDecodePicture *hp = pic->hwaccel_picture_private;
|
||||
FFVulkanDecodePicture *vp = &hp->vp;
|
||||
FFVulkanDecodePicture *rvp[H264_MAX_PICTURE_COUNT] = { 0 };
|
||||
AVFrame *rav[H264_MAX_PICTURE_COUNT] = { 0 };
|
||||
|
||||
for (int i = 0; i < vp->decode_info.referenceSlotCount; i++) {
|
||||
H264Picture *rp = hp->ref_src[i];
|
||||
H264VulkanDecodePicture *rhp = rp->hwaccel_picture_private;
|
||||
|
||||
rvp[i] = &rhp->vp;
|
||||
rav[i] = hp->ref_src[i]->f;
|
||||
}
|
||||
|
||||
av_log(avctx, AV_LOG_VERBOSE, "Decoding frame, %lu bytes, %i slices\n",
|
||||
vp->slices_size, hp->h264_pic_info.sliceCount);
|
||||
|
||||
return ff_vk_decode_frame(avctx, pic->f, vp, rav, rvp);
|
||||
}
|
||||
|
||||
static void vk_h264_free_frame_priv(void *_hwctx, uint8_t *data)
|
||||
{
|
||||
AVHWDeviceContext *hwctx = _hwctx;
|
||||
H264VulkanDecodePicture *hp = (H264VulkanDecodePicture *)data;
|
||||
|
||||
/* Free frame resources, this also destroys the session parameters. */
|
||||
ff_vk_decode_free_frame(hwctx, &hp->vp);
|
||||
|
||||
/* Free frame context */
|
||||
av_free(hp);
|
||||
}
|
||||
|
||||
const AVHWAccel ff_h264_vulkan_hwaccel = {
|
||||
.name = "h264_vulkan",
|
||||
.type = AVMEDIA_TYPE_VIDEO,
|
||||
.id = AV_CODEC_ID_H264,
|
||||
.pix_fmt = AV_PIX_FMT_VULKAN,
|
||||
.start_frame = &vk_h264_start_frame,
|
||||
.decode_slice = &vk_h264_decode_slice,
|
||||
.end_frame = &vk_h264_end_frame,
|
||||
.free_frame_priv = &vk_h264_free_frame_priv,
|
||||
.frame_priv_data_size = sizeof(H264VulkanDecodePicture),
|
||||
.init = &ff_vk_decode_init,
|
||||
.update_thread_context = &ff_vk_update_thread_context,
|
||||
.decode_params = &ff_vk_params_changed,
|
||||
.flush = &ff_vk_decode_flush,
|
||||
.uninit = &ff_vk_decode_uninit,
|
||||
.frame_params = &ff_vk_frame_params,
|
||||
.priv_data_size = sizeof(FFVulkanDecodeContext),
|
||||
.caps_internal = HWACCEL_CAP_ASYNC_SAFE | HWACCEL_CAP_THREAD_SAFE,
|
||||
};
|
Loading…
Reference in New Issue
Block a user