mirror of
https://github.com/jellyfin/jellyfin-ffmpeg.git
synced 2026-09-02 21:03:08 +03:00
1185 lines
52 KiB
Diff
1185 lines
52 KiB
Diff
Index: FFmpeg/libavcodec/av1dec.c
|
|
===================================================================
|
|
--- FFmpeg.orig/libavcodec/av1dec.c
|
|
+++ FFmpeg/libavcodec/av1dec.c
|
|
@@ -688,8 +688,8 @@ static int get_pixel_format(AVCodecConte
|
|
|
|
static void av1_frame_unref(AV1Frame *f)
|
|
{
|
|
- ff_progress_frame_unref(&f->pf);
|
|
av_refstruct_unref(&f->hwaccel_picture_private);
|
|
+ ff_progress_frame_unref(&f->pf);
|
|
av_refstruct_unref(&f->header_ref);
|
|
f->raw_frame_header = NULL;
|
|
f->spatial_id = f->temporal_id = 0;
|
|
Index: FFmpeg/libavcodec/h264_picture.c
|
|
===================================================================
|
|
--- FFmpeg.orig/libavcodec/h264_picture.c
|
|
+++ FFmpeg/libavcodec/h264_picture.c
|
|
@@ -44,9 +44,9 @@ void ff_h264_unref_picture(H264Picture *
|
|
if (!pic->f || !pic->f->buf[0])
|
|
return;
|
|
|
|
+ av_refstruct_unref(&pic->hwaccel_picture_private);
|
|
ff_thread_release_ext_buffer(&pic->tf);
|
|
av_frame_unref(pic->f_grain);
|
|
- av_refstruct_unref(&pic->hwaccel_picture_private);
|
|
|
|
av_refstruct_unref(&pic->qscale_table_base);
|
|
av_refstruct_unref(&pic->mb_type_base);
|
|
Index: FFmpeg/libavcodec/hevc/refs.c
|
|
===================================================================
|
|
--- FFmpeg.orig/libavcodec/hevc/refs.c
|
|
+++ FFmpeg/libavcodec/hevc/refs.c
|
|
@@ -38,6 +38,8 @@ void ff_hevc_unref_frame(HEVCFrame *fram
|
|
if (!(frame->flags & ~HEVC_FRAME_FLAG_CORRUPT))
|
|
frame->flags = 0;
|
|
if (!frame->flags) {
|
|
+ av_refstruct_unref(&frame->hwaccel_picture_private);
|
|
+
|
|
ff_progress_frame_unref(&frame->tf);
|
|
av_frame_unref(frame->frame_grain);
|
|
frame->needs_fg = 0;
|
|
@@ -49,8 +51,6 @@ void ff_hevc_unref_frame(HEVCFrame *fram
|
|
frame->nb_rpl_elems = 0;
|
|
av_refstruct_unref(&frame->rpl_tab);
|
|
frame->refPicList = NULL;
|
|
-
|
|
- av_refstruct_unref(&frame->hwaccel_picture_private);
|
|
}
|
|
}
|
|
|
|
Index: FFmpeg/libavcodec/vp9.c
|
|
===================================================================
|
|
--- FFmpeg.orig/libavcodec/vp9.c
|
|
+++ FFmpeg/libavcodec/vp9.c
|
|
@@ -97,10 +97,10 @@ static void vp9_tile_data_free(VP9TileDa
|
|
|
|
static void vp9_frame_unref(VP9Frame *f)
|
|
{
|
|
+ av_refstruct_unref(&f->hwaccel_picture_private);
|
|
ff_progress_frame_unref(&f->tf);
|
|
av_refstruct_unref(&f->header_ref);
|
|
av_refstruct_unref(&f->extradata);
|
|
- av_refstruct_unref(&f->hwaccel_picture_private);
|
|
f->segmentation_map = NULL;
|
|
}
|
|
|
|
Index: FFmpeg/libavcodec/vulkan_decode.c
|
|
===================================================================
|
|
--- FFmpeg.orig/libavcodec/vulkan_decode.c
|
|
+++ FFmpeg/libavcodec/vulkan_decode.c
|
|
@@ -233,7 +233,8 @@ int ff_vk_decode_prepare_frame(FFVulkanD
|
|
(AVVkFrame *)pic->data[0],
|
|
hwfc->format[0],
|
|
VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR |
|
|
- (!is_current ? VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR : 0));
|
|
+ (hwfc->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR));
|
|
+ // the above fixes VUID-VkVideoBeginCodingInfoKHR-slotIndex-07245
|
|
if (err < 0)
|
|
return err;
|
|
|
|
@@ -335,15 +336,28 @@ int ff_vk_decode_add_slice(AVCodecContex
|
|
* easier, and gives us ample headroom. */
|
|
buf_size = 2 << av_log2(buf_size);
|
|
|
|
+ /* When the frames context uses DRM modifier tiling,
|
|
+ * hwctx->create_pnext contains VkImageDrmFormatModifierListCreateInfoEXT,
|
|
+ * which per spec does not extend VkBufferCreateInfo, so we need to find
|
|
+ * the VkVideoProfileListInfoKHR structure within it. */
|
|
+ void *buf_pnext = ctx->s.hwfc->create_pnext;
|
|
+ if (ctx->s.hwfc->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
|
|
+ buf_pnext = (void *)ff_vk_find_struct(ctx->s.hwfc->create_pnext,
|
|
+ VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
|
|
+
|
|
+ VkBufferUsageFlags buf_usage = DECODER_IS_SDR(avctx->codec_id) ?
|
|
+ (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
|
+ VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) :
|
|
+ VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR;
|
|
+
|
|
err = ff_vk_get_pooled_buffer(&ctx->s, &ctx->buf_pool, &new_ref,
|
|
- DECODER_IS_SDR(avctx->codec_id) ?
|
|
- (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
|
- VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) :
|
|
- VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR,
|
|
- ctx->s.hwfc->create_pnext, buf_size,
|
|
+ buf_usage, buf_pnext, buf_size,
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
|
- (DECODER_IS_SDR(avctx->codec_id) ?
|
|
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT : 0x0));
|
|
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
+ if (err < 0)
|
|
+ err = ff_vk_get_pooled_buffer(&ctx->s, &ctx->buf_pool, &new_ref,
|
|
+ buf_usage, buf_pnext, buf_size,
|
|
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
@@ -1033,8 +1047,8 @@ static int vulkan_decode_get_profile(AVC
|
|
"VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR are set!\n");
|
|
return AVERROR_EXTERNAL;
|
|
} else if ((dec_caps->flags & (VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR |
|
|
- VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR) ==
|
|
- VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR) &&
|
|
+ VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR)) ==
|
|
+ VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR &&
|
|
!(caps->flags & VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR)) {
|
|
av_log(avctx, AV_LOG_ERROR, "Cannot initialize Vulkan decoding session, buggy driver: "
|
|
"VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR set "
|
|
@@ -1217,7 +1231,9 @@ int ff_vk_frame_params(AVCodecContext *a
|
|
}
|
|
}
|
|
|
|
- hwfc->tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
+ if (hwfc->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
|
|
+ hwfc->tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
+
|
|
hwfc->usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
|
VK_IMAGE_USAGE_STORAGE_BIT |
|
|
VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
@@ -1382,10 +1398,22 @@ int ff_vk_decode_init(AVCodecContext *av
|
|
dpb_frames->height = s->frames->height;
|
|
|
|
dpb_hwfc = dpb_frames->hwctx;
|
|
- dpb_hwfc->create_pnext = (void *)ff_vk_find_struct(ctx->s.hwfc->create_pnext,
|
|
- VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
|
|
+ void *profile_list = (void *)ff_vk_find_struct(ctx->s.hwfc->create_pnext,
|
|
+ VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR);
|
|
+ /* Reference (DPB) images use the same tiling and pNext chain as output.
|
|
+ * If VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR is 0, the
|
|
+ * driver does not support separate output and DPB with different layouts/tiling. */
|
|
+ void *drm_create_pnext = ff_vk_find_struct(ctx->s.hwfc->create_pnext,
|
|
+ VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
|
|
+ if (drm_create_pnext) {
|
|
+ dpb_hwfc->create_pnext = drm_create_pnext;
|
|
+ dpb_hwfc->tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
|
|
+ av_assert2(ff_vk_find_struct(drm_create_pnext, VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR));
|
|
+ } else {
|
|
+ dpb_hwfc->create_pnext = profile_list;
|
|
+ dpb_hwfc->tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
+ }
|
|
dpb_hwfc->format[0] = s->hwfc->format[0];
|
|
- dpb_hwfc->tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
dpb_hwfc->usage = VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR;
|
|
|
|
if (ctx->common.layered_dpb)
|
|
Index: FFmpeg/libavcodec/vulkan_encode.c
|
|
===================================================================
|
|
--- FFmpeg.orig/libavcodec/vulkan_encode.c
|
|
+++ FFmpeg/libavcodec/vulkan_encode.c
|
|
@@ -28,6 +28,27 @@ const AVCodecHWConfigInternal *const ff_
|
|
NULL,
|
|
};
|
|
|
|
+static void vulkan_encode_free_pic(FFVulkanEncodeContext *ctx,
|
|
+ FFHWBaseEncodePicture *pic)
|
|
+{
|
|
+ FFVulkanFunctions *vk = &ctx->s.vkfn;
|
|
+
|
|
+ FFVulkanEncodePicture *vp = pic->priv;
|
|
+
|
|
+ if (vp->in.view)
|
|
+ vk->DestroyImageView(ctx->s.hwctx->act_dev, vp->in.view,
|
|
+ ctx->s.hwctx->alloc);
|
|
+
|
|
+ if (!ctx->common.layered_dpb && vp->dpb.view)
|
|
+ vk->DestroyImageView(ctx->s.hwctx->act_dev, vp->dpb.view,
|
|
+ ctx->s.hwctx->alloc);
|
|
+
|
|
+ vp->in.view = VK_NULL_HANDLE;
|
|
+ vp->dpb.view = VK_NULL_HANDLE;
|
|
+
|
|
+ ctx->slots[vp->dpb_slot.slotIndex] = NULL;
|
|
+}
|
|
+
|
|
av_cold void ff_vulkan_encode_uninit(FFVulkanEncodeContext *ctx)
|
|
{
|
|
FFVulkanContext *s = &ctx->s;
|
|
@@ -42,10 +63,15 @@ av_cold void ff_vulkan_encode_uninit(FFV
|
|
ctx->session_params,
|
|
s->hwctx->alloc);
|
|
|
|
- ff_hw_base_encode_close(&ctx->base);
|
|
+ /* Destroy the image views of any pictures still in the queue,
|
|
+ * as ff_hw_base_encode_close() only frees the picture structs */
|
|
+ for (FFHWBaseEncodePicture *pic = ctx->base.pic_start; pic; pic = pic->next)
|
|
+ vulkan_encode_free_pic(ctx, pic);
|
|
|
|
av_buffer_pool_uninit(&ctx->buf_pool);
|
|
|
|
+ ff_hw_base_encode_close(&ctx->base);
|
|
+
|
|
ff_vk_video_common_uninit(s, &ctx->common);
|
|
|
|
ff_vk_uninit(s);
|
|
@@ -95,19 +121,8 @@ static int vulkan_encode_init(AVCodecCon
|
|
static int vulkan_encode_free(AVCodecContext *avctx, FFHWBaseEncodePicture *pic)
|
|
{
|
|
FFVulkanEncodeContext *ctx = avctx->priv_data;
|
|
- FFVulkanFunctions *vk = &ctx->s.vkfn;
|
|
-
|
|
- FFVulkanEncodePicture *vp = pic->priv;
|
|
-
|
|
- if (vp->in.view)
|
|
- vk->DestroyImageView(ctx->s.hwctx->act_dev, vp->in.view,
|
|
- ctx->s.hwctx->alloc);
|
|
-
|
|
- if (!ctx->common.layered_dpb && vp->dpb.view)
|
|
- vk->DestroyImageView(ctx->s.hwctx->act_dev, vp->dpb.view,
|
|
- ctx->s.hwctx->alloc);
|
|
|
|
- ctx->slots[vp->dpb_slot.slotIndex] = NULL;
|
|
+ vulkan_encode_free_pic(ctx, pic);
|
|
|
|
return 0;
|
|
}
|
|
@@ -354,12 +369,15 @@ static int vulkan_encode_issue(AVCodecCo
|
|
if (err < 0)
|
|
goto fail;
|
|
|
|
- /* Source image layout conversion */
|
|
+ /* Source image layout conversion. Writes to it happened on other
|
|
+ * queues, and were made available by the semaphore wait: their access
|
|
+ * flags are not to be carried over, and may not even be valid on this
|
|
+ * queue. */
|
|
img_bar[nb_img_bar] = (VkImageMemoryBarrier2) {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
|
.pNext = NULL,
|
|
.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
|
|
- .srcAccessMask = vkf->access[0],
|
|
+ .srcAccessMask = VK_ACCESS_2_NONE,
|
|
.dstStageMask = VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR,
|
|
.dstAccessMask = VK_ACCESS_2_VIDEO_ENCODE_READ_BIT_KHR,
|
|
.oldLayout = vkf->layout[0],
|
|
@@ -1037,7 +1055,7 @@ av_cold int ff_vulkan_encode_init(AVCode
|
|
|
|
/* Create session */
|
|
session_create.pVideoProfile = &ctx->profile;
|
|
- session_create.flags = 0x0;
|
|
+ session_create.flags = VK_VIDEO_SESSION_CREATE_ALLOW_ENCODE_PARAMETER_OPTIMIZATIONS_BIT_KHR;
|
|
session_create.queueFamilyIndex = ctx->qf_enc->idx;
|
|
session_create.maxCodedExtent = ctx->caps.maxCodedExtent;
|
|
session_create.maxDpbSlots = ctx->caps.maxDpbSlots;
|
|
Index: FFmpeg/libavcodec/vulkan_encode.h
|
|
===================================================================
|
|
--- FFmpeg.orig/libavcodec/vulkan_encode.h
|
|
+++ FFmpeg/libavcodec/vulkan_encode.h
|
|
@@ -203,7 +203,7 @@ typedef struct FFVulkanEncodeContext {
|
|
|
|
#define VULKAN_ENCODE_COMMON_OPTIONS \
|
|
{ "qp", "Use an explicit constant quantizer for the whole stream", OFFSET(common.opts.qp), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, FLAGS }, \
|
|
- { "quality", "Set encode quality (trades off against speed, higher is faster)", OFFSET(common.opts.quality), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, \
|
|
+ { "quality", "Set encode quality (trades off against speed, higher is slower)", OFFSET(common.opts.quality), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, \
|
|
{ "rc_mode", "Select rate control type", OFFSET(common.opts.rc_mode), AV_OPT_TYPE_INT, { .i64 = FF_VK_RC_MODE_AUTO }, 0, FF_VK_RC_MODE_AUTO, FLAGS, "rc_mode" }, \
|
|
{ "auto", "Choose mode automatically based on parameters", 0, AV_OPT_TYPE_CONST, { .i64 = FF_VK_RC_MODE_AUTO }, INT_MIN, INT_MAX, FLAGS, "rc_mode" }, \
|
|
{ "driver", "Driver-specific rate control", 0, AV_OPT_TYPE_CONST, { .i64 = VK_VIDEO_ENCODE_RATE_CONTROL_MODE_DEFAULT_KHR }, INT_MIN, INT_MAX, FLAGS, "rc_mode" }, \
|
|
Index: FFmpeg/libavcodec/vulkan_encode_av1.c
|
|
===================================================================
|
|
--- FFmpeg.orig/libavcodec/vulkan_encode_av1.c
|
|
+++ FFmpeg/libavcodec/vulkan_encode_av1.c
|
|
@@ -593,7 +593,6 @@ static int init_profile(AVCodecContext *
|
|
FFVulkanEncodeContext *ctx = &enc->common;
|
|
FFVulkanContext *s = &ctx->s;
|
|
FFVulkanFunctions *vk = &ctx->s.vkfn;
|
|
- FFHWBaseEncodeContext *base_ctx = &ctx->base;
|
|
|
|
VkVideoEncodeAV1CapabilitiesKHR av1_caps = {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_CAPABILITIES_KHR,
|
|
@@ -631,31 +630,6 @@ static int init_profile(AVCodecContext *
|
|
};
|
|
profile->pNext = &enc->profile;
|
|
|
|
- /* Set level */
|
|
- if (avctx->level == AV_LEVEL_UNKNOWN) {
|
|
- const AV1LevelDescriptor *level;
|
|
- float framerate = 0.0;
|
|
-
|
|
- if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
|
|
- framerate = av_q2d(avctx->framerate);
|
|
-
|
|
- level = ff_av1_guess_level(avctx->bit_rate, enc->seq_tier,
|
|
- base_ctx->surface_width, base_ctx->surface_height,
|
|
- enc->tile_rows * enc->tile_cols,
|
|
- enc->tile_cols, framerate);
|
|
- if (level) {
|
|
- av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
|
|
- enc->seq_level_idx = level->level_idx;
|
|
- } else {
|
|
- av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to "
|
|
- "any normal level, using level 7.3 by default.\n");
|
|
- enc->seq_level_idx = STD_VIDEO_AV1_LEVEL_7_3;
|
|
- enc->seq_tier = 1;
|
|
- }
|
|
- } else {
|
|
- enc->seq_level_idx = ff_vk_av1_level_to_vk(avctx->level);
|
|
- }
|
|
-
|
|
/* User has explicitly specified a profile. */
|
|
if (avctx->profile != AV_PROFILE_UNKNOWN)
|
|
return 0;
|
|
@@ -750,6 +724,32 @@ static av_cold int init_sequence_headers
|
|
if (!desc)
|
|
return AVERROR(EINVAL);
|
|
|
|
+ enc->seq_tier = enc->common.opts.tier;
|
|
+
|
|
+ if (avctx->level == AV_LEVEL_UNKNOWN) {
|
|
+ const AV1LevelDescriptor *level;
|
|
+ float framerate = 0.0;
|
|
+
|
|
+ if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
|
|
+ framerate = av_q2d(avctx->framerate);
|
|
+
|
|
+ level = ff_av1_guess_level(avctx->bit_rate, enc->seq_tier,
|
|
+ base_ctx->surface_width, base_ctx->surface_height,
|
|
+ enc->tile_rows * enc->tile_cols,
|
|
+ enc->tile_cols, framerate);
|
|
+ if (level) {
|
|
+ av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
|
|
+ enc->seq_level_idx = level->level_idx;
|
|
+ } else {
|
|
+ av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to "
|
|
+ "any normal level, using level 7.3 by default.\n");
|
|
+ enc->seq_level_idx = STD_VIDEO_AV1_LEVEL_7_3;
|
|
+ enc->seq_tier = 1;
|
|
+ }
|
|
+ } else {
|
|
+ enc->seq_level_idx = avctx->level;
|
|
+ }
|
|
+
|
|
seq_obu->header.obu_type = AV1_OBU_SEQUENCE_HEADER;
|
|
*seq = (AV1RawSequenceHeader) {
|
|
.seq_profile = avctx->profile,
|
|
@@ -1023,7 +1023,7 @@ static int init_base_units(AVCodecContex
|
|
} else {
|
|
av_log(avctx, AV_LOG_ERROR, "Unable to get feedback for AV1 sequence header = %zu\n",
|
|
data_size);
|
|
- return err;
|
|
+ return AVERROR_EXTERNAL;
|
|
}
|
|
|
|
ret = vk->GetEncodedVideoSessionParametersKHR(s->hwctx->act_dev, ¶ms_info,
|
|
@@ -1031,7 +1031,8 @@ static int init_base_units(AVCodecContex
|
|
&data_size, data);
|
|
if (ret != VK_SUCCESS) {
|
|
av_log(avctx, AV_LOG_ERROR, "Error writing feedback units\n");
|
|
- return err;
|
|
+ err = AVERROR_EXTERNAL;
|
|
+ goto end;
|
|
}
|
|
|
|
av_log(avctx, AV_LOG_VERBOSE, "Feedback units written, overrides: %i\n",
|
|
@@ -1040,20 +1041,21 @@ static int init_base_units(AVCodecContex
|
|
params_feedback.hasOverrides = 1;
|
|
|
|
/* No need to sync any overrides */
|
|
+ err = 0;
|
|
if (!params_feedback.hasOverrides)
|
|
- return 0;
|
|
+ goto end;
|
|
|
|
/* Parse back tne units and override */
|
|
err = parse_feedback_units(avctx, data, data_size);
|
|
if (err < 0)
|
|
- return err;
|
|
+ goto end;
|
|
|
|
/* Create final session parameters */
|
|
err = create_session_params(avctx);
|
|
- if (err < 0)
|
|
- return err;
|
|
|
|
- return 0;
|
|
+end:
|
|
+ av_free(data);
|
|
+ return err;
|
|
}
|
|
|
|
static int vulkan_encode_av1_add_obu(AVCodecContext *avctx,
|
|
@@ -1229,6 +1231,8 @@ static av_cold int vulkan_encode_av1_ini
|
|
|
|
if (avctx->profile == AV_PROFILE_UNKNOWN)
|
|
avctx->profile = enc->common.opts.profile;
|
|
+ if (avctx->level == AV_LEVEL_UNKNOWN)
|
|
+ avctx->level = enc->common.opts.level;
|
|
|
|
enc->caps = (VkVideoEncodeAV1CapabilitiesKHR) {
|
|
.sType = VK_STRUCTURE_TYPE_VIDEO_ENCODE_AV1_CAPABILITIES_KHR,
|
|
@@ -1359,6 +1363,10 @@ static av_cold int vulkan_encode_av1_ini
|
|
static av_cold int vulkan_encode_av1_close(AVCodecContext *avctx)
|
|
{
|
|
VulkanEncodeAV1Context *enc = avctx->priv_data;
|
|
+
|
|
+ ff_cbs_fragment_free(&enc->current_access_unit);
|
|
+ ff_cbs_close(&enc->cbs);
|
|
+
|
|
av_free(enc->padding_payload);
|
|
ff_vulkan_encode_uninit(&enc->common);
|
|
return 0;
|
|
Index: FFmpeg/libavcodec/vulkan_encode_h264.c
|
|
===================================================================
|
|
--- FFmpeg.orig/libavcodec/vulkan_encode_h264.c
|
|
+++ FFmpeg/libavcodec/vulkan_encode_h264.c
|
|
@@ -702,7 +702,7 @@ static int init_profile(AVCodecContext *
|
|
AV_PROFILE_H264_CONSTRAINED_BASELINE,
|
|
AV_PROFILE_H264_MAIN,
|
|
AV_PROFILE_H264_HIGH,
|
|
- AV_PROFILE_H264_HIGH_10,
|
|
+ AV_PROFILE_H264_HIGH_444_PREDICTIVE,
|
|
};
|
|
int nb_profiles = FF_ARRAY_ELEMS(known_profiles);
|
|
|
|
@@ -834,12 +834,16 @@ static av_cold int init_sequence_headers
|
|
if (err < 0)
|
|
return err;
|
|
|
|
- units->raw_sps.seq_scaling_matrix_present_flag =
|
|
- !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_SCALING_MATRIX_PRESENT_FLAG_SET_BIT_KHR);
|
|
- units->raw_pps.pic_scaling_matrix_present_flag =
|
|
- !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_SCALING_MATRIX_PRESENT_FLAG_SET_BIT_KHR);
|
|
- units->raw_pps.transform_8x8_mode_flag =
|
|
- !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_TRANSFORM_8X8_MODE_FLAG_SET_BIT_KHR);
|
|
+ /* High profile syntax: the capabilities only signal implementation
|
|
+ * support, lesser profiles prohibit these outright */
|
|
+ if (units->raw_pps.more_rbsp_data) {
|
|
+ units->raw_sps.seq_scaling_matrix_present_flag =
|
|
+ !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_SCALING_MATRIX_PRESENT_FLAG_SET_BIT_KHR);
|
|
+ units->raw_pps.pic_scaling_matrix_present_flag =
|
|
+ !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_SCALING_MATRIX_PRESENT_FLAG_SET_BIT_KHR);
|
|
+ units->raw_pps.transform_8x8_mode_flag =
|
|
+ !!(enc->caps.stdSyntaxFlags & VK_VIDEO_ENCODE_H264_STD_TRANSFORM_8X8_MODE_FLAG_SET_BIT_KHR);
|
|
+ }
|
|
|
|
return 0;
|
|
}
|
|
@@ -1148,7 +1152,7 @@ static int init_base_units(AVCodecContex
|
|
return AVERROR(ENOMEM);
|
|
} else {
|
|
av_log(avctx, AV_LOG_ERROR, "Unable to get feedback for H.264 units = %zu\n", data_size);
|
|
- return err;
|
|
+ return AVERROR_EXTERNAL;
|
|
}
|
|
|
|
ret = vk->GetEncodedVideoSessionParametersKHR(s->hwctx->act_dev, ¶ms_info,
|
|
@@ -1156,7 +1160,8 @@ static int init_base_units(AVCodecContex
|
|
&data_size, data);
|
|
if (ret != VK_SUCCESS) {
|
|
av_log(avctx, AV_LOG_ERROR, "Error writing feedback units\n");
|
|
- return err;
|
|
+ err = AVERROR_EXTERNAL;
|
|
+ goto end;
|
|
}
|
|
|
|
av_log(avctx, AV_LOG_VERBOSE, "Feedback units written, overrides: %i (SPS: %i PPS: %i)\n",
|
|
@@ -1168,22 +1173,23 @@ static int init_base_units(AVCodecContex
|
|
h264_params_feedback.hasStdPPSOverrides = 1;
|
|
|
|
/* No need to sync any overrides */
|
|
+ err = 0;
|
|
if (!params_feedback.hasOverrides)
|
|
- return 0;
|
|
+ goto end;
|
|
|
|
/* Parse back tne units and override */
|
|
err = parse_feedback_units(avctx, data, data_size,
|
|
h264_params_feedback.hasStdSPSOverrides,
|
|
h264_params_feedback.hasStdPPSOverrides);
|
|
if (err < 0)
|
|
- return err;
|
|
+ goto end;
|
|
|
|
/* Create final session parameters */
|
|
err = create_session_params(avctx);
|
|
- if (err < 0)
|
|
- return err;
|
|
|
|
- return 0;
|
|
+end:
|
|
+ av_free(data);
|
|
+ return err;
|
|
}
|
|
|
|
static int vulkan_encode_h264_add_nal(AVCodecContext *avctx,
|
|
@@ -1474,6 +1480,12 @@ static av_cold int vulkan_encode_h264_in
|
|
return err;
|
|
|
|
flags = ctx->codec->flags;
|
|
+
|
|
+ /* Baseline profiles have no B-slices */
|
|
+ if (avctx->profile == AV_PROFILE_H264_BASELINE ||
|
|
+ avctx->profile == AV_PROFILE_H264_CONSTRAINED_BASELINE)
|
|
+ flags &= ~(FF_HW_FLAG_B_PICTURES | FF_HW_FLAG_B_PICTURE_REFERENCES);
|
|
+
|
|
if (!enc->caps.maxPPictureL0ReferenceCount &&
|
|
!enc->caps.maxBPictureL0ReferenceCount &&
|
|
!enc->caps.maxL1ReferenceCount) {
|
|
@@ -1561,6 +1573,13 @@ static av_cold int vulkan_encode_h264_in
|
|
static av_cold int vulkan_encode_h264_close(AVCodecContext *avctx)
|
|
{
|
|
VulkanEncodeH264Context *enc = avctx->priv_data;
|
|
+
|
|
+ ff_cbs_fragment_free(&enc->current_access_unit);
|
|
+ ff_cbs_close(&enc->cbs);
|
|
+
|
|
+ av_freep(&enc->sei_a53cc_data);
|
|
+ av_freep(&enc->sei_identifier_string);
|
|
+
|
|
ff_vulkan_encode_uninit(&enc->common);
|
|
return 0;
|
|
}
|
|
@@ -1580,7 +1599,7 @@ static const AVOption vulkan_encode_h264
|
|
{ PROFILE("constrained_baseline", AV_PROFILE_H264_CONSTRAINED_BASELINE) },
|
|
{ PROFILE("main", AV_PROFILE_H264_MAIN) },
|
|
{ PROFILE("high", AV_PROFILE_H264_HIGH) },
|
|
- { PROFILE("high444p", AV_PROFILE_H264_HIGH_10) },
|
|
+ { PROFILE("high444p", AV_PROFILE_H264_HIGH_444_PREDICTIVE) },
|
|
#undef PROFILE
|
|
|
|
{ "level", "Set level (level_idc)",
|
|
Index: FFmpeg/libavcodec/vulkan_encode_h265.c
|
|
===================================================================
|
|
--- FFmpeg.orig/libavcodec/vulkan_encode_h265.c
|
|
+++ FFmpeg/libavcodec/vulkan_encode_h265.c
|
|
@@ -793,14 +793,21 @@ static av_cold int init_sequence_headers
|
|
else if (enc->caps.transformBlockSizes & VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_4_BIT_KHR)
|
|
max_tb_size = 4;
|
|
|
|
- units->raw_sps.log2_min_luma_coding_block_size_minus3 = 0;
|
|
- units->raw_sps.log2_diff_max_min_luma_coding_block_size = av_log2(max_ctb_size) - 3;
|
|
+ /* Prefer 16x16 min CU when the CTB is at least 32; 8x8 min CU is much
|
|
+ * more expensive on some implementations for the common quality levels. */
|
|
+ if (max_ctb_size >= 32) {
|
|
+ units->raw_sps.log2_min_luma_coding_block_size_minus3 = 1;
|
|
+ units->raw_sps.log2_diff_max_min_luma_coding_block_size = av_log2(max_ctb_size) - 4;
|
|
+ } else {
|
|
+ units->raw_sps.log2_min_luma_coding_block_size_minus3 = 0;
|
|
+ units->raw_sps.log2_diff_max_min_luma_coding_block_size = av_log2(max_ctb_size) - 3;
|
|
+ }
|
|
units->raw_sps.log2_min_luma_transform_block_size_minus2 = av_log2(min_tb_size) - 2;
|
|
units->raw_sps.log2_diff_max_min_luma_transform_block_size = av_log2(max_tb_size) - av_log2(min_tb_size);
|
|
|
|
max_transform_hierarchy = av_log2(max_ctb_size) - av_log2(min_tb_size);
|
|
units->raw_sps.max_transform_hierarchy_depth_intra = max_transform_hierarchy;
|
|
- units->raw_sps.max_transform_hierarchy_depth_intra = max_transform_hierarchy;
|
|
+ units->raw_sps.max_transform_hierarchy_depth_inter = max_transform_hierarchy;
|
|
|
|
units->raw_sps.vui.bitstream_restriction_flag = 0;
|
|
units->raw_sps.vui.max_bytes_per_pic_denom = 2;
|
|
@@ -1227,7 +1234,19 @@ static int parse_feedback_units(AVCodecC
|
|
H265RawSPS *sps = au.units[i].content;
|
|
enc->units.raw_sps.pic_width_in_luma_samples = sps->pic_width_in_luma_samples;
|
|
enc->units.raw_sps.pic_height_in_luma_samples = sps->pic_height_in_luma_samples;
|
|
- enc->units.raw_sps.log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_luma_coding_block_size;
|
|
+ enc->units.raw_sps.conformance_window_flag = sps->conformance_window_flag;
|
|
+ enc->units.raw_sps.conf_win_left_offset = sps->conf_win_left_offset;
|
|
+ enc->units.raw_sps.conf_win_right_offset = sps->conf_win_right_offset;
|
|
+ enc->units.raw_sps.conf_win_top_offset = sps->conf_win_top_offset;
|
|
+ enc->units.raw_sps.conf_win_bottom_offset = sps->conf_win_bottom_offset;
|
|
+ enc->units.raw_sps.log2_min_luma_coding_block_size_minus3 =
|
|
+ sps->log2_min_luma_coding_block_size_minus3;
|
|
+ enc->units.raw_sps.log2_diff_max_min_luma_coding_block_size =
|
|
+ sps->log2_diff_max_min_luma_coding_block_size;
|
|
+ enc->units.raw_sps.log2_min_luma_transform_block_size_minus2 =
|
|
+ sps->log2_min_luma_transform_block_size_minus2;
|
|
+ enc->units.raw_sps.log2_diff_max_min_luma_transform_block_size =
|
|
+ sps->log2_diff_max_min_luma_transform_block_size;
|
|
enc->units.raw_sps.max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter;
|
|
enc->units.raw_sps.max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra;
|
|
}
|
|
@@ -1317,7 +1336,7 @@ static int init_base_units(AVCodecContex
|
|
return AVERROR(ENOMEM);
|
|
} else {
|
|
av_log(avctx, AV_LOG_ERROR, "Unable to get feedback for H.265 units = %zu\n", data_size);
|
|
- return err;
|
|
+ return AVERROR_EXTERNAL;
|
|
}
|
|
|
|
ret = vk->GetEncodedVideoSessionParametersKHR(s->hwctx->act_dev, ¶ms_info,
|
|
@@ -1325,7 +1344,8 @@ static int init_base_units(AVCodecContex
|
|
&data_size, data);
|
|
if (ret != VK_SUCCESS) {
|
|
av_log(avctx, AV_LOG_ERROR, "Error writing feedback units\n");
|
|
- return err;
|
|
+ err = AVERROR_EXTERNAL;
|
|
+ goto end;
|
|
}
|
|
|
|
av_log(avctx, AV_LOG_VERBOSE, "Feedback units written, overrides: %i (SPS: %i PPS: %i VPS: %i)\n",
|
|
@@ -1339,22 +1359,23 @@ static int init_base_units(AVCodecContex
|
|
h265_params_feedback.hasStdPPSOverrides = 1;
|
|
|
|
/* No need to sync any overrides */
|
|
+ err = 0;
|
|
if (!params_feedback.hasOverrides)
|
|
- return 0;
|
|
+ goto end;
|
|
|
|
/* Parse back tne units and override */
|
|
err = parse_feedback_units(avctx, data, data_size,
|
|
h265_params_feedback.hasStdSPSOverrides,
|
|
h265_params_feedback.hasStdPPSOverrides);
|
|
if (err < 0)
|
|
- return err;
|
|
+ goto end;
|
|
|
|
/* Create final session parameters */
|
|
err = create_session_params(avctx);
|
|
- if (err < 0)
|
|
- return err;
|
|
|
|
- return 0;
|
|
+end:
|
|
+ av_free(data);
|
|
+ return err;
|
|
}
|
|
|
|
static int vulkan_encode_h265_add_nal(AVCodecContext *avctx,
|
|
@@ -1595,23 +1616,21 @@ static av_cold int vulkan_encode_h265_in
|
|
|
|
av_log(avctx, AV_LOG_VERBOSE, " Capability flags:\n");
|
|
av_log(avctx, AV_LOG_VERBOSE, " hdr_compliance: %i\n",
|
|
- !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_HRD_COMPLIANCE_BIT_KHR));
|
|
+ !!(enc->caps.flags & VK_VIDEO_ENCODE_H265_CAPABILITY_HRD_COMPLIANCE_BIT_KHR));
|
|
av_log(avctx, AV_LOG_VERBOSE, " pred_weight_table_generated: %i\n",
|
|
- !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_PREDICTION_WEIGHT_TABLE_GENERATED_BIT_KHR));
|
|
+ !!(enc->caps.flags & VK_VIDEO_ENCODE_H265_CAPABILITY_PREDICTION_WEIGHT_TABLE_GENERATED_BIT_KHR));
|
|
av_log(avctx, AV_LOG_VERBOSE, " row_unaligned_slice: %i\n",
|
|
- !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_ROW_UNALIGNED_SLICE_BIT_KHR));
|
|
+ !!(enc->caps.flags & VK_VIDEO_ENCODE_H265_CAPABILITY_ROW_UNALIGNED_SLICE_SEGMENT_BIT_KHR));
|
|
av_log(avctx, AV_LOG_VERBOSE, " different_slice_type: %i\n",
|
|
- !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_DIFFERENT_SLICE_TYPE_BIT_KHR));
|
|
+ !!(enc->caps.flags & VK_VIDEO_ENCODE_H265_CAPABILITY_DIFFERENT_SLICE_SEGMENT_TYPE_BIT_KHR));
|
|
av_log(avctx, AV_LOG_VERBOSE, " b_frame_in_l0_list: %i\n",
|
|
- !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L0_LIST_BIT_KHR));
|
|
+ !!(enc->caps.flags & VK_VIDEO_ENCODE_H265_CAPABILITY_B_FRAME_IN_L0_LIST_BIT_KHR));
|
|
av_log(avctx, AV_LOG_VERBOSE, " b_frame_in_l1_list: %i\n",
|
|
- !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L1_LIST_BIT_KHR));
|
|
+ !!(enc->caps.flags & VK_VIDEO_ENCODE_H265_CAPABILITY_B_FRAME_IN_L1_LIST_BIT_KHR));
|
|
av_log(avctx, AV_LOG_VERBOSE, " per_pict_type_min_max_qp: %i\n",
|
|
- !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_PER_PICTURE_TYPE_MIN_MAX_QP_BIT_KHR));
|
|
+ !!(enc->caps.flags & VK_VIDEO_ENCODE_H265_CAPABILITY_PER_PICTURE_TYPE_MIN_MAX_QP_BIT_KHR));
|
|
av_log(avctx, AV_LOG_VERBOSE, " per_slice_constant_qp: %i\n",
|
|
- !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_PER_SLICE_CONSTANT_QP_BIT_KHR));
|
|
- av_log(avctx, AV_LOG_VERBOSE, " generate_prefix_nalu: %i\n",
|
|
- !!(enc->caps.flags & VK_VIDEO_ENCODE_H264_CAPABILITY_GENERATE_PREFIX_NALU_BIT_KHR));
|
|
+ !!(enc->caps.flags & VK_VIDEO_ENCODE_H265_CAPABILITY_PER_SLICE_SEGMENT_CONSTANT_QP_BIT_KHR));
|
|
|
|
av_log(avctx, AV_LOG_VERBOSE, " Capabilities:\n");
|
|
av_log(avctx, AV_LOG_VERBOSE, " maxLevelIdc: %i\n",
|
|
@@ -1698,6 +1717,12 @@ static av_cold int vulkan_encode_h265_in
|
|
static av_cold int vulkan_encode_h265_close(AVCodecContext *avctx)
|
|
{
|
|
VulkanEncodeH265Context *enc = avctx->priv_data;
|
|
+
|
|
+ ff_cbs_fragment_free(&enc->current_access_unit);
|
|
+ ff_cbs_close(&enc->cbs);
|
|
+
|
|
+ av_freep(&enc->sei_a53cc_data);
|
|
+
|
|
ff_vulkan_encode_uninit(&enc->common);
|
|
return 0;
|
|
}
|
|
Index: FFmpeg/libavcodec/vulkan_video.c
|
|
===================================================================
|
|
--- FFmpeg.orig/libavcodec/vulkan_video.c
|
|
+++ FFmpeg/libavcodec/vulkan_video.c
|
|
@@ -260,6 +260,7 @@ StdVideoAV1Level ff_vk_av1_level_to_vk(i
|
|
StdVideoH264ProfileIdc ff_vk_h264_profile_to_vk(int profile)
|
|
{
|
|
switch (profile) {
|
|
+ case AV_PROFILE_H264_BASELINE:
|
|
case AV_PROFILE_H264_CONSTRAINED_BASELINE: return STD_VIDEO_H264_PROFILE_IDC_BASELINE;
|
|
case AV_PROFILE_H264_MAIN: return STD_VIDEO_H264_PROFILE_IDC_MAIN;
|
|
case AV_PROFILE_H264_HIGH: return STD_VIDEO_H264_PROFILE_IDC_HIGH;
|
|
Index: FFmpeg/libavutil/hwcontext_vulkan.c
|
|
===================================================================
|
|
--- FFmpeg.orig/libavutil/hwcontext_vulkan.c
|
|
+++ FFmpeg/libavutil/hwcontext_vulkan.c
|
|
@@ -190,11 +190,18 @@ typedef struct VulkanFramesPriv {
|
|
|
|
/* Properties for DRM modifier for each plane in the image */
|
|
VkDrmFormatModifierPropertiesEXT drm_format_modifier_properties[5];
|
|
+
|
|
+ /* Set when physical device reports DEDICATED_ONLY for DMA-BUF export (try_export_flags) */
|
|
+ int export_requires_dedicated;
|
|
} VulkanFramesPriv;
|
|
|
|
typedef struct AVVkFrameInternal {
|
|
pthread_mutex_t update_mutex;
|
|
|
|
+ /* Binary semaphore for SYNC_FD export at DRM map time. Created once lazily,
|
|
+ * re-signaled each time via a submit in vulkan_map_to_drm. */
|
|
+ VkSemaphore drm_sync_sem;
|
|
+
|
|
#if CONFIG_CUDA
|
|
/* Importing external memory into cuda is really expensive so we keep the
|
|
* memory imported all the time */
|
|
@@ -2370,7 +2377,7 @@ static int alloc_mem(AVHWDeviceContext *
|
|
return 0;
|
|
}
|
|
|
|
-static void vulkan_free_internal(AVVkFrame *f)
|
|
+static void vulkan_free_internal(VulkanDevicePriv *p, AVVkFrame *f)
|
|
{
|
|
av_unused AVVkFrameInternal *internal = f->internal;
|
|
|
|
@@ -2402,6 +2409,10 @@ static void vulkan_free_internal(AVVkFra
|
|
}
|
|
#endif
|
|
|
|
+ if (internal->drm_sync_sem != VK_NULL_HANDLE)
|
|
+ p->vkctx.vkfn.DestroySemaphore(p->p.act_dev, internal->drm_sync_sem,
|
|
+ p->p.alloc);
|
|
+
|
|
pthread_mutex_destroy(&internal->update_mutex);
|
|
av_freep(&f->internal);
|
|
}
|
|
@@ -2429,7 +2440,7 @@ static void vulkan_frame_free(AVHWFrames
|
|
vk->WaitSemaphores(hwctx->act_dev, &sem_wait, UINT64_MAX);
|
|
}
|
|
|
|
- vulkan_free_internal(f);
|
|
+ vulkan_free_internal(p, f);
|
|
|
|
for (int i = 0; i < nb_images; i++) {
|
|
vk->DestroyImage(hwctx->act_dev, f->img[i], hwctx->alloc);
|
|
@@ -2476,6 +2487,10 @@ static int alloc_bind_mem(AVHWFramesCont
|
|
|
|
vk->GetImageMemoryRequirements2(hwctx->act_dev, &req_desc, &req);
|
|
|
|
+ av_log(hwfc, AV_LOG_TRACE,
|
|
+ "plane %d: driver reports prefersDedicatedAllocation=%i requiresDedicatedAllocation=%i\n",
|
|
+ img_cnt, ded_req.prefersDedicatedAllocation, ded_req.requiresDedicatedAllocation);
|
|
+
|
|
if (f->tiling == VK_IMAGE_TILING_LINEAR)
|
|
req.memoryRequirements.size = FFALIGN(req.memoryRequirements.size,
|
|
p->props.properties.limits.minMemoryMapAlignment);
|
|
@@ -2483,6 +2498,8 @@ static int alloc_bind_mem(AVHWFramesCont
|
|
/* In case the implementation prefers/requires dedicated allocation */
|
|
use_ded_mem = ded_req.prefersDedicatedAllocation |
|
|
ded_req.requiresDedicatedAllocation;
|
|
+ if (((VulkanFramesPriv *)hwfc->hwctx)->export_requires_dedicated)
|
|
+ use_ded_mem = 1;
|
|
if (use_ded_mem)
|
|
ded_alloc.image = f->img[img_cnt];
|
|
|
|
@@ -2850,11 +2867,12 @@ static void try_export_flags(AVHWFramesC
|
|
VkPhysicalDeviceImageFormatInfo2 pinfo = {
|
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
|
|
.pNext = !exp ? NULL : &enext,
|
|
- .format = vk_find_format_entry(hwfc->sw_format)->vkf,
|
|
+ .format = hwctx->format[0],
|
|
.type = VK_IMAGE_TYPE_2D,
|
|
.tiling = hwctx->tiling,
|
|
.usage = hwctx->usage,
|
|
- .flags = VK_IMAGE_CREATE_ALIAS_BIT,
|
|
+ .flags = (hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT && has_mods) ?
|
|
+ (hwctx->img_flags) : hwctx->img_flags ? hwctx->img_flags : (VkImageCreateFlags)(VK_IMAGE_CREATE_ALIAS_BIT),
|
|
};
|
|
|
|
nb_mods = has_mods ? drm_mod_info->drmFormatModifierCount : 1;
|
|
@@ -2865,9 +2883,18 @@ static void try_export_flags(AVHWFramesC
|
|
ret = vk->GetPhysicalDeviceImageFormatProperties2(dev_hwctx->phys_dev,
|
|
&pinfo, &props);
|
|
|
|
+ if (has_mods)
|
|
+ av_log(hwfc, AV_LOG_VERBOSE, "GetPhysicalDeviceImageFormatProperties2: mod[%d]=0x%llx -> %s\n",
|
|
+ i, (unsigned long long)phy_dev_mod_info.drmFormatModifier,
|
|
+ ret == VK_SUCCESS ? "OK" : "FAIL");
|
|
if (ret == VK_SUCCESS) {
|
|
*iexp |= exp;
|
|
*comp_handle_types |= eprops.externalMemoryProperties.compatibleHandleTypes;
|
|
+ if (exp == VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) {
|
|
+ VulkanFramesPriv *fp = hwfc->hwctx;
|
|
+ fp->export_requires_dedicated = !!(eprops.externalMemoryProperties.externalMemoryFeatures &
|
|
+ VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
@@ -2895,7 +2922,8 @@ static AVBufferRef *vulkan_pool_alloc(vo
|
|
? VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT
|
|
: VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT);
|
|
#else
|
|
- if (p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY)
|
|
+ if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_MEMORY) &&
|
|
+ (hwctx->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT))
|
|
try_export_flags(hwfc, &eiinfo.handleTypes, &e,
|
|
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT);
|
|
|
|
@@ -2914,8 +2942,10 @@ static AVBufferRef *vulkan_pool_alloc(vo
|
|
err = create_frame(hwfc, &f, hwctx->tiling, hwctx->usage, hwctx->img_flags,
|
|
hwctx->nb_layers,
|
|
eiinfo.handleTypes ? &eiinfo : hwctx->create_pnext);
|
|
- if (err)
|
|
+ if (err) {
|
|
+ av_log(hwfc, AV_LOG_ERROR, "vulkan_pool_alloc failed: create_frame failed: %d\n", err);
|
|
return NULL;
|
|
+ }
|
|
|
|
err = alloc_bind_mem(hwfc, f, eminfo, sizeof(*eminfo));
|
|
if (err)
|
|
@@ -2943,6 +2973,7 @@ static AVBufferRef *vulkan_pool_alloc(vo
|
|
return avbuf;
|
|
|
|
fail:
|
|
+ av_log(hwfc, AV_LOG_ERROR, "vulkan_pool_alloc failed with error %d\n", err);
|
|
vulkan_frame_free(hwfc, f);
|
|
return NULL;
|
|
}
|
|
@@ -3044,16 +3075,29 @@ static int vulkan_frames_init(AVHWFrames
|
|
}
|
|
|
|
/* Lone DPB images do not need additional flags. */
|
|
- if (!is_lone_dpb) {
|
|
+ /* With DRM modifier + video profile the caller has already chosen a valid
|
|
+ * usage/img_flags/chain; do not add usage or img_flags (supported_usage does
|
|
+ * not consider the actual modifier or video profile). */
|
|
+ int drm_mod_with_video = (hwctx->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT &&
|
|
+ ff_vk_find_struct(hwctx->create_pnext,
|
|
+ VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR));
|
|
+
|
|
+ if (!is_lone_dpb && !drm_mod_with_video) {
|
|
/* Image usage flags */
|
|
hwctx->usage |= supported_usage & (VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
|
VK_IMAGE_USAGE_STORAGE_BIT |
|
|
VK_IMAGE_USAGE_SAMPLED_BIT);
|
|
|
|
+ /* Frames which may double as active references (coinciding decode
|
|
+ * output) cannot support host transfers: decode submissions bake the
|
|
+ * image layout into their barriers at record time, so a host-side
|
|
+ * layout transition cannot be synchronized against them, not even
|
|
+ * by the frame lock and timeline semaphore. */
|
|
if (p->vkctx.extensions & FF_VK_EXT_HOST_IMAGE_COPY &&
|
|
!(p->dprops.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY) &&
|
|
- !(p->dprops.driverID == VK_DRIVER_ID_MOLTENVK))
|
|
+ !(p->dprops.driverID == VK_DRIVER_ID_MOLTENVK) &&
|
|
+ !(hwctx->usage & VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR))
|
|
hwctx->usage |= supported_usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT;
|
|
|
|
/* Enables encoding of images, if supported by format and extensions */
|
|
@@ -3163,8 +3207,8 @@ static int vulkan_frames_init(AVHWFrames
|
|
}
|
|
vk->GetPhysicalDeviceFormatProperties2(dev_hwctx->phys_dev, fmt->fallback[i], &fmtp);
|
|
|
|
- for (uint32_t i = 0; i < modp.drmFormatModifierCount; ++i) {
|
|
- VkDrmFormatModifierPropertiesEXT *m = &modp.pDrmFormatModifierProperties[i];
|
|
+ for (uint32_t j = 0; j < modp.drmFormatModifierCount; ++j) {
|
|
+ VkDrmFormatModifierPropertiesEXT *m = &modp.pDrmFormatModifierProperties[j];
|
|
if (m->drmFormatModifier == drm_mod.drmFormatModifier) {
|
|
mod_props = m;
|
|
break;
|
|
@@ -3502,7 +3546,7 @@ static int vulkan_map_from_drm_frame_des
|
|
&f->flags, &f->mem[i]);
|
|
if (err) {
|
|
close(idesc.fd);
|
|
- return err;
|
|
+ goto fail;
|
|
}
|
|
|
|
f->size[i] = req2.memoryRequirements.size;
|
|
@@ -3969,7 +4013,7 @@ static int vulkan_export_to_cuda(AVHWFra
|
|
return 0;
|
|
|
|
fail:
|
|
- vulkan_free_internal(dst_f);
|
|
+ vulkan_free_internal(p, dst_f);
|
|
return err;
|
|
}
|
|
|
|
@@ -3980,6 +4024,7 @@ static int vulkan_transfer_data_from_cud
|
|
CUcontext dummy;
|
|
AVVkFrame *dst_f;
|
|
AVVkFrameInternal *dst_int;
|
|
+ VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
|
|
VulkanFramesPriv *fp = hwfc->hwctx;
|
|
const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
|
|
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format);
|
|
@@ -4058,7 +4103,7 @@ static int vulkan_transfer_data_from_cud
|
|
|
|
fail:
|
|
CHECK_CU(cu->cuCtxPopCurrent(&dummy));
|
|
- vulkan_free_internal(dst_f);
|
|
+ vulkan_free_internal(p, dst_f);
|
|
av_buffer_unref(&dst->buf[0]);
|
|
return err;
|
|
}
|
|
@@ -4128,6 +4173,72 @@ static VkImageAspectFlags plane_index_to
|
|
return VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT;
|
|
}
|
|
|
|
+#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
|
|
+static int vulkan_drm_export_sync_fd(AVHWFramesContext *hwfc, AVVkFrame *f,
|
|
+ VulkanFramesPriv *fp, int nb_sems)
|
|
+{
|
|
+ int sync_fd = -1;
|
|
+ VkResult ret;
|
|
+ VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
|
|
+ AVVulkanDeviceContext *hwctx = &p->p;
|
|
+ FFVulkanFunctions *vk = &p->vkctx.vkfn;
|
|
+
|
|
+ if (f->internal->drm_sync_sem == VK_NULL_HANDLE) {
|
|
+ VkExportSemaphoreCreateInfo exp_info = {
|
|
+ .sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
|
|
+ .handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
|
|
+ };
|
|
+ VkSemaphoreTypeCreateInfo type_info = {
|
|
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
|
|
+ .pNext = &exp_info,
|
|
+ .semaphoreType = VK_SEMAPHORE_TYPE_BINARY,
|
|
+ };
|
|
+ VkSemaphoreCreateInfo sem_create = {
|
|
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
|
+ .pNext = &type_info,
|
|
+ };
|
|
+ ret = vk->CreateSemaphore(hwctx->act_dev, &sem_create, hwctx->alloc,
|
|
+ &f->internal->drm_sync_sem);
|
|
+ if (ret != VK_SUCCESS) {
|
|
+ av_log(hwctx, AV_LOG_ERROR, "Failed to create DRM export semaphore: %s\n",
|
|
+ ff_vk_ret2str(ret));
|
|
+ return AVERROR_EXTERNAL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Submit a lightweight exec that waits on the timeline semaphore
|
|
+ * (true last operation on the frame) and signals the binary semaphore,
|
|
+ * so any Vulkan frame can get a SYNC_FD regardless of origin. */
|
|
+ FFVkExecContext *exec = ff_vk_exec_get(&p->vkctx, &fp->compute_exec);
|
|
+ if (ff_vk_exec_start(&p->vkctx, exec) >= 0) {
|
|
+ for (int i = 0; i < nb_sems; i++)
|
|
+ ff_vk_exec_add_dep_wait_sem(&p->vkctx, exec, f->sem[i],
|
|
+ f->sem_value[i],
|
|
+ VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT);
|
|
+ ff_vk_exec_add_dep_bool_sem(&p->vkctx, exec, &f->internal->drm_sync_sem, 1,
|
|
+ VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, 0);
|
|
+ if (ff_vk_exec_submit(&p->vkctx, exec) >= 0) {
|
|
+ VkSemaphoreGetFdInfoKHR get_fd_info = {
|
|
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
|
|
+ .semaphore = f->internal->drm_sync_sem,
|
|
+ .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
|
|
+ };
|
|
+ ret = vk->GetSemaphoreFdKHR(hwctx->act_dev, &get_fd_info, &sync_fd);
|
|
+ if (ret != VK_SUCCESS) {
|
|
+ av_log(hwctx, AV_LOG_WARNING,
|
|
+ "Failed to get sync fd from DRM map export semaphore: %s\n",
|
|
+ ff_vk_ret2str(ret));
|
|
+ sync_fd = -1;
|
|
+ }
|
|
+ } else {
|
|
+ ff_vk_exec_discard_deps(&p->vkctx, exec);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return sync_fd;
|
|
+}
|
|
+#endif
|
|
+
|
|
static int vulkan_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
|
|
const AVFrame *src, int flags)
|
|
{
|
|
@@ -4138,15 +4249,14 @@ static int vulkan_map_to_drm(AVHWFramesC
|
|
AVVulkanDeviceContext *hwctx = &p->p;
|
|
FFVulkanFunctions *vk = &p->vkctx.vkfn;
|
|
VulkanFramesPriv *fp = hwfc->hwctx;
|
|
+ const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
|
|
const int nb_images = ff_vk_count_images(f);
|
|
VkImageDrmFormatModifierPropertiesEXT drm_mod = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
|
|
};
|
|
- VkSemaphoreWaitInfo wait_info = {
|
|
- .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
|
|
- .flags = 0x0,
|
|
- .semaphoreCount = nb_images,
|
|
- };
|
|
+ const int nb_sems = nb_images;
|
|
+ int free_drm_desc_on_err = 1;
|
|
+ int sync_fd = -1;
|
|
|
|
AVDRMFrameDescriptor *drm_desc = av_mallocz(sizeof(*drm_desc));
|
|
if (!drm_desc)
|
|
@@ -4156,16 +4266,36 @@ static int vulkan_map_to_drm(AVHWFramesC
|
|
if (err < 0)
|
|
goto end;
|
|
|
|
- /* Wait for the operation to finish so we can cleanly export it. */
|
|
- wait_info.pSemaphores = f->sem;
|
|
- wait_info.pValues = f->sem_value;
|
|
+#ifdef DMA_BUF_IOCTL_EXPORT_SYNC_FILE
|
|
+ if ((p->vkctx.extensions & FF_VK_EXT_EXTERNAL_FD_SEM) &&
|
|
+ f->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT &&
|
|
+ vk->GetSemaphoreFdKHR && vk->CreateSemaphore) {
|
|
+ err = vulkan_drm_export_sync_fd(hwfc, f, fp, nb_sems);
|
|
+ if (err < 0)
|
|
+ goto end;
|
|
+ sync_fd = err;
|
|
+ err = 0;
|
|
+ }
|
|
+#endif
|
|
|
|
- vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX);
|
|
+ if (sync_fd < 0) {
|
|
+ VkSemaphoreWaitInfo wait_info = {
|
|
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,
|
|
+ .flags = 0x0,
|
|
+ .semaphoreCount = nb_sems,
|
|
+ .pSemaphores = f->sem,
|
|
+ .pValues = f->sem_value,
|
|
+ };
|
|
+ vk->WaitSemaphores(hwctx->act_dev, &wait_info, UINT64_MAX);
|
|
+ }
|
|
|
|
err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, &vulkan_unmap_to_drm, drm_desc);
|
|
if (err < 0)
|
|
goto end;
|
|
|
|
+ /* It will be freed in ff_hwframe_map_create callback */
|
|
+ free_drm_desc_on_err = 0;
|
|
+
|
|
ret = vk->GetImageDrmFormatModifierPropertiesEXT(hwctx->act_dev, f->img[0],
|
|
&drm_mod);
|
|
if (ret != VK_SUCCESS) {
|
|
@@ -4174,7 +4304,7 @@ static int vulkan_map_to_drm(AVHWFramesC
|
|
goto end;
|
|
}
|
|
|
|
- for (int i = 0; (i < nb_images) && (f->mem[i]); i++) {
|
|
+ for (int i = 0; (i < planes) && (f->mem[i]); i++) {
|
|
VkMemoryGetFdInfoKHR export_info = {
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
|
|
.memory = f->mem[i],
|
|
@@ -4189,12 +4319,30 @@ static int vulkan_map_to_drm(AVHWFramesC
|
|
goto end;
|
|
}
|
|
|
|
+#if HAVE_LINUX_DMA_BUF_H && defined(DMA_BUF_IOCTL_IMPORT_SYNC_FILE)
|
|
+ if (sync_fd >= 0) {
|
|
+ int dup_fd = dup(sync_fd);
|
|
+ if (dup_fd >= 0) {
|
|
+ struct dma_buf_import_sync_file import_info = {
|
|
+ .flags = DMA_BUF_SYNC_WRITE,
|
|
+ .fd = dup_fd,
|
|
+ };
|
|
+ if (ioctl(drm_desc->objects[i].fd, DMA_BUF_IOCTL_IMPORT_SYNC_FILE, &import_info) < 0)
|
|
+ av_log(hwfc, AV_LOG_WARNING, "DMA_BUF_IOCTL_IMPORT_SYNC_FILE failed: %s\n", av_err2str(AVERROR(errno)));
|
|
+ close(dup_fd);
|
|
+ } else {
|
|
+ av_log(hwfc, AV_LOG_WARNING, "dup(sync_fd) failed: %s\n", av_err2str(AVERROR(errno)));
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
drm_desc->nb_objects++;
|
|
drm_desc->objects[i].size = f->size[i];
|
|
drm_desc->objects[i].format_modifier = drm_mod.drmFormatModifier;
|
|
}
|
|
|
|
- drm_desc->nb_layers = nb_images;
|
|
+ /* NV12 has 2 planes but 1 image/semaphore */
|
|
+ drm_desc->nb_layers = FFMAX(planes, nb_images);
|
|
for (int i = 0; i < drm_desc->nb_layers; i++) {
|
|
VkFormat plane_vkfmt = av_vkfmt_from_pixfmt(hwfc->sw_format)[i];
|
|
|
|
@@ -4209,13 +4357,14 @@ static int vulkan_map_to_drm(AVHWFramesC
|
|
|
|
for (int j = 0; j < drm_desc->layers[i].nb_planes; j++) {
|
|
VkSubresourceLayout layout;
|
|
+ int aspect_plane = (nb_images == 1) ? i : j;
|
|
VkImageSubresource sub = {
|
|
- .aspectMask = plane_index_to_aspect(j),
|
|
+ .aspectMask = plane_index_to_aspect(aspect_plane),
|
|
};
|
|
|
|
drm_desc->layers[i].planes[j].object_index = FFMIN(i, drm_desc->nb_objects - 1);
|
|
|
|
- vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[i], &sub, &layout);
|
|
+ vk->GetImageSubresourceLayout(hwctx->act_dev, f->img[FFMIN(i, nb_images - 1)], &sub, &layout);
|
|
drm_desc->layers[i].planes[j].offset = layout.offset;
|
|
drm_desc->layers[i].planes[j].pitch = layout.rowPitch;
|
|
}
|
|
@@ -4235,13 +4384,22 @@ static int vulkan_map_to_drm(AVHWFramesC
|
|
dst->width = src->width;
|
|
dst->height = src->height;
|
|
dst->data[0] = (uint8_t *)drm_desc;
|
|
+ dst->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx);
|
|
+
|
|
+ if (sync_fd >= 0)
|
|
+ close(sync_fd);
|
|
|
|
av_log(hwfc, AV_LOG_VERBOSE, "Mapped AVVkFrame to a DRM object!\n");
|
|
|
|
return 0;
|
|
|
|
end:
|
|
- av_free(drm_desc);
|
|
+ for (int i = 0; i < drm_desc->nb_objects; i++)
|
|
+ close(drm_desc->objects[i].fd);
|
|
+ if (free_drm_desc_on_err)
|
|
+ av_free(drm_desc);
|
|
+ if (sync_fd >= 0)
|
|
+ close(sync_fd);
|
|
return err;
|
|
}
|
|
|
|
@@ -4469,10 +4627,12 @@ static int vulkan_transfer_host(AVHWFram
|
|
if (compat)
|
|
continue;
|
|
|
|
+ /* This should only ever happen on uploads, so using UNDEFINED is safe */
|
|
+ av_assert1(upload);
|
|
layout_ch_info[nb_layout_ch] = (VkHostImageLayoutTransitionInfoEXT) {
|
|
.sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT,
|
|
.image = hwf_vk->img[i],
|
|
- .oldLayout = hwf_vk->layout[i],
|
|
+ .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
.subresourceRange = {
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
@@ -4594,8 +4754,27 @@ static int vulkan_transfer_frame(AVHWFra
|
|
if (swf->width > hwfc->width || swf->height > hwfc->height)
|
|
return AVERROR(EINVAL);
|
|
|
|
- if (hwctx->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT &&
|
|
- !(p->dprops.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY))
|
|
+ int host_copy = hwctx->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT &&
|
|
+ !(p->dprops.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY);
|
|
+
|
|
+ /* Host layout transitions may only originate from a host-copyable layout */
|
|
+ if (!upload && host_copy) {
|
|
+ for (int i = 0; i < nb_images; i++) {
|
|
+ int compat = 0;
|
|
+ for (int j = 0; j < p->vkctx.host_image_props.copySrcLayoutCount; j++) {
|
|
+ if (hwf_vk->layout[i] == p->vkctx.host_image_props.pCopySrcLayouts[j]) {
|
|
+ compat = 1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (!compat) {
|
|
+ host_copy = 0;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (host_copy)
|
|
return vulkan_transfer_host(hwfc, hwf, swf, upload);
|
|
|
|
for (int i = 0; i < av_pix_fmt_count_planes(swf->format); i++) {
|
|
@@ -4751,6 +4930,7 @@ static int vulkan_transfer_data_to_cuda(
|
|
CUcontext dummy;
|
|
AVVkFrame *dst_f;
|
|
AVVkFrameInternal *dst_int;
|
|
+ VulkanDevicePriv *p = hwfc->device_ctx->hwctx;
|
|
VulkanFramesPriv *fp = hwfc->hwctx;
|
|
const int planes = av_pix_fmt_count_planes(hwfc->sw_format);
|
|
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format);
|
|
@@ -4831,7 +5011,7 @@ static int vulkan_transfer_data_to_cuda(
|
|
|
|
fail:
|
|
CHECK_CU(cu->cuCtxPopCurrent(&dummy));
|
|
- vulkan_free_internal(dst_f);
|
|
+ vulkan_free_internal(p, dst_f);
|
|
av_buffer_unref(&dst->buf[0]);
|
|
return err;
|
|
}
|