When seeking through MBAFF-coded H264, this can happen. Decoding calls end_frame without calling start_frame. We are unable to decode this, as no frame state has been set. Happens for both VAAPI and Vulkan. Could be an issue elsewhere, hence the individual commit.
564 lines
24 KiB
C
564 lines
24 KiB
C
/*
|
|
* 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;
|
|
FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
|
|
FFVulkanDecodePicture *vp = &hp->vp;
|
|
FFVulkanDecodePicture *rvp[H264_MAX_PICTURE_COUNT] = { 0 };
|
|
AVFrame *rav[H264_MAX_PICTURE_COUNT] = { 0 };
|
|
|
|
if (!dec->session_params)
|
|
return AVERROR(EINVAL);
|
|
|
|
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,
|
|
};
|