aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLynne <dev@lynne.ee>2022-12-18 08:31:03 +0100
committerLynne <dev@lynne.ee>2023-05-29 00:41:57 +0200
commit023ae6103f0e0db1610ef3988290e37fea47661d (patch)
tree0837b2d80db3f1269a2baa33cddcd4fb410996c9
parent6733a1a456b1720ec58f83c21352d54406229102 (diff)
downloadffmpeg-023ae6103f0e0db1610ef3988290e37fea47661d.tar.gz
libavcodec: add Vulkan common video code
-rwxr-xr-xconfigure2
-rw-r--r--libavcodec/Makefile2
-rw-r--r--libavcodec/hwconfig.h2
-rw-r--r--libavcodec/vulkan.c19
-rw-r--r--libavcodec/vulkan.h24
-rw-r--r--libavcodec/vulkan_video.c361
-rw-r--r--libavcodec/vulkan_video.h97
7 files changed, 506 insertions, 1 deletions
diff --git a/configure b/configure
index 84668dd4f9..43c02ecb22 100755
--- a/configure
+++ b/configure
@@ -327,7 +327,6 @@ External library support:
--disable-securetransport disable Secure Transport, needed for TLS support
on OSX if openssl and gnutls are not used [autodetect]
--enable-vapoursynth enable VapourSynth demuxer [no]
- --disable-vulkan disable Vulkan code [autodetect]
--disable-xlib disable xlib [autodetect]
--disable-zlib disable zlib [autodetect]
@@ -354,6 +353,7 @@ External library support:
--disable-vaapi disable Video Acceleration API (mainly Unix/Intel) code [autodetect]
--disable-vdpau disable Nvidia Video Decode and Presentation API for Unix code [autodetect]
--disable-videotoolbox disable VideoToolbox code [autodetect]
+ --disable-vulkan disable Vulkan code [autodetect]
Toolchain options:
--arch=ARCH select architecture [$arch]
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 9c38240025..8580d4ca1d 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -982,6 +982,7 @@ OBJS-$(CONFIG_NVDEC) += nvdec.o
OBJS-$(CONFIG_VAAPI) += vaapi_decode.o
OBJS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.o
OBJS-$(CONFIG_VDPAU) += vdpau.o
+OBJS-$(CONFIG_VULKAN) += vulkan.o vulkan_video.o
OBJS-$(CONFIG_AV1_D3D11VA_HWACCEL) += dxva2_av1.o
OBJS-$(CONFIG_AV1_DXVA2_HWACCEL) += dxva2_av1.o
@@ -1290,6 +1291,7 @@ SKIPHEADERS-$(CONFIG_XVMC) += xvmc.h
SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_decode.h vaapi_hevc.h vaapi_encode.h
SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h vdpau_internal.h
SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.h vt_internal.h
+SKIPHEADERS-$(CONFIG_VULKAN) += vulkan.h vulkan_video.h
SKIPHEADERS-$(CONFIG_V4L2_M2M) += v4l2_buffers.h v4l2_context.h v4l2_m2m.h
SKIPHEADERS-$(CONFIG_ZLIB) += zlib_wrapper.h
diff --git a/libavcodec/hwconfig.h b/libavcodec/hwconfig.h
index d88dc37c8c..e8c6186151 100644
--- a/libavcodec/hwconfig.h
+++ b/libavcodec/hwconfig.h
@@ -78,6 +78,8 @@ void ff_hwaccel_uninit(AVCodecContext *avctx);
HW_CONFIG_HWACCEL(1, 1, 1, VDPAU, VDPAU, ff_ ## codec ## _vdpau_hwaccel)
#define HWACCEL_VIDEOTOOLBOX(codec) \
HW_CONFIG_HWACCEL(1, 1, 1, VIDEOTOOLBOX, VIDEOTOOLBOX, ff_ ## codec ## _videotoolbox_hwaccel)
+#define HWACCEL_VULKAN(codec) \
+ HW_CONFIG_HWACCEL(1, 1, 1, VULKAN, VULKAN, ff_ ## codec ## _vulkan_hwaccel)
#define HWACCEL_D3D11VA(codec) \
HW_CONFIG_HWACCEL(0, 0, 1, D3D11VA_VLD, NONE, ff_ ## codec ## _d3d11va_hwaccel)
diff --git a/libavcodec/vulkan.c b/libavcodec/vulkan.c
new file mode 100644
index 0000000000..fc8a1fa47b
--- /dev/null
+++ b/libavcodec/vulkan.c
@@ -0,0 +1,19 @@
+/*
+ * 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 "libavutil/vulkan.c"
diff --git a/libavcodec/vulkan.h b/libavcodec/vulkan.h
new file mode 100644
index 0000000000..b15efd4add
--- /dev/null
+++ b/libavcodec/vulkan.h
@@ -0,0 +1,24 @@
+/*
+ * 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
+ */
+
+#ifndef AVCODEC_VULKAN_H
+#define AVCODEC_VULKAN_H
+
+#include "libavutil/vulkan.h"
+
+#endif /* AVCODEC_VULKAN_H */
diff --git a/libavcodec/vulkan_video.c b/libavcodec/vulkan_video.c
new file mode 100644
index 0000000000..5fb867df87
--- /dev/null
+++ b/libavcodec/vulkan_video.c
@@ -0,0 +1,361 @@
+/*
+ * 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 "codec_id.h"
+
+#include "vulkan_video.h"
+
+const FFVkCodecMap ff_vk_codec_map[AV_CODEC_ID_FIRST_AUDIO] = {
+ [AV_CODEC_ID_H264] = {
+ 0,
+ 0,
+ FF_VK_EXT_VIDEO_DECODE_H264,
+ VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR,
+ },
+ [AV_CODEC_ID_HEVC] = {
+ 0,
+ 0,
+ FF_VK_EXT_VIDEO_DECODE_H265,
+ VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR
+ },
+};
+
+#define ASPECT_2PLANE (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT)
+#define ASPECT_3PLANE (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)
+
+static const struct FFVkFormatMapEntry {
+ VkFormat vkf;
+ enum AVPixelFormat pixfmt;
+ VkImageAspectFlags aspect;
+} vk_format_map[] = {
+ /* Gray formats */
+ { VK_FORMAT_R8_UNORM, AV_PIX_FMT_GRAY8, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GRAY16, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_R32_SFLOAT, AV_PIX_FMT_GRAYF32, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ /* RGB formats */
+ { VK_FORMAT_R16G16B16A16_UNORM, AV_PIX_FMT_XV36, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_B8G8R8A8_UNORM, AV_PIX_FMT_BGRA, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_R8G8B8A8_UNORM, AV_PIX_FMT_RGBA, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_R8G8B8_UNORM, AV_PIX_FMT_RGB24, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_B8G8R8_UNORM, AV_PIX_FMT_BGR24, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_R16G16B16_UNORM, AV_PIX_FMT_RGB48, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_R16G16B16A16_UNORM, AV_PIX_FMT_RGBA64, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_R5G6B5_UNORM_PACK16, AV_PIX_FMT_RGB565, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_B5G6R5_UNORM_PACK16, AV_PIX_FMT_BGR565, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_B8G8R8A8_UNORM, AV_PIX_FMT_BGR0, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_R8G8B8A8_UNORM, AV_PIX_FMT_RGB0, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_A2R10G10B10_UNORM_PACK32, AV_PIX_FMT_X2RGB10, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ /* Planar RGB */
+ { VK_FORMAT_R8_UNORM, AV_PIX_FMT_GBRAP, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_R16_UNORM, AV_PIX_FMT_GBRAP16, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_R32_SFLOAT, AV_PIX_FMT_GBRPF32, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_R32_SFLOAT, AV_PIX_FMT_GBRAPF32, VK_IMAGE_ASPECT_COLOR_BIT },
+
+ /* Two-plane 420 YUV at 8, 10, 12 and 16 bits */
+ { VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, AV_PIX_FMT_NV12, ASPECT_2PLANE },
+ { VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, AV_PIX_FMT_P010, ASPECT_2PLANE },
+ { VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, AV_PIX_FMT_P012, ASPECT_2PLANE },
+ { VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, AV_PIX_FMT_P016, ASPECT_2PLANE },
+
+ /* Two-plane 422 YUV at 8, 10 and 16 bits */
+ { VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, AV_PIX_FMT_NV16, ASPECT_2PLANE },
+ { VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, AV_PIX_FMT_P210, ASPECT_2PLANE },
+ { VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, AV_PIX_FMT_P212, ASPECT_2PLANE },
+ { VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, AV_PIX_FMT_P216, ASPECT_2PLANE },
+
+ /* Two-plane 444 YUV at 8, 10 and 16 bits */
+ { VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, AV_PIX_FMT_NV24, ASPECT_2PLANE },
+ { VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16, AV_PIX_FMT_P410, ASPECT_2PLANE },
+ { VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16, AV_PIX_FMT_P412, ASPECT_2PLANE },
+ { VK_FORMAT_G16_B16R16_2PLANE_444_UNORM, AV_PIX_FMT_P416, ASPECT_2PLANE },
+
+ /* Three-plane 420, 422, 444 at 8, 10, 12 and 16 bits */
+ { VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, AV_PIX_FMT_YUV420P, ASPECT_3PLANE },
+ { VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, AV_PIX_FMT_YUV420P10, ASPECT_3PLANE },
+ { VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, AV_PIX_FMT_YUV420P12, ASPECT_3PLANE },
+ { VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, AV_PIX_FMT_YUV420P16, ASPECT_3PLANE },
+ { VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, AV_PIX_FMT_YUV422P, ASPECT_3PLANE },
+ { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, AV_PIX_FMT_YUV422P10, ASPECT_3PLANE },
+ { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, AV_PIX_FMT_YUV422P12, ASPECT_3PLANE },
+ { VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, AV_PIX_FMT_YUV422P16, ASPECT_3PLANE },
+ { VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, AV_PIX_FMT_YUV444P, ASPECT_3PLANE },
+ { VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, AV_PIX_FMT_YUV444P10, ASPECT_3PLANE },
+ { VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, AV_PIX_FMT_YUV444P12, ASPECT_3PLANE },
+ { VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, AV_PIX_FMT_YUV444P16, ASPECT_3PLANE },
+
+ /* Single plane 422 at 8, 10 and 12 bits */
+ { VK_FORMAT_G8B8G8R8_422_UNORM, AV_PIX_FMT_YUYV422, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_B8G8R8G8_422_UNORM, AV_PIX_FMT_UYVY422, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, AV_PIX_FMT_Y210, VK_IMAGE_ASPECT_COLOR_BIT },
+ { VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, AV_PIX_FMT_Y212, VK_IMAGE_ASPECT_COLOR_BIT },
+};
+static const int nb_vk_format_map = FF_ARRAY_ELEMS(vk_format_map);
+
+enum AVPixelFormat ff_vk_pix_fmt_from_vkfmt(VkFormat vkf)
+{
+ for (int i = 0; i < nb_vk_format_map; i++)
+ if (vk_format_map[i].vkf == vkf)
+ return vk_format_map[i].pixfmt;
+ return AV_PIX_FMT_NONE;
+}
+
+VkImageAspectFlags ff_vk_aspect_bits_from_vkfmt(VkFormat vkf)
+{
+ for (int i = 0; i < nb_vk_format_map; i++)
+ if (vk_format_map[i].vkf == vkf)
+ return vk_format_map[i].aspect;
+ return VK_IMAGE_ASPECT_NONE;
+}
+
+VkVideoChromaSubsamplingFlagBitsKHR ff_vk_subsampling_from_av_desc(const AVPixFmtDescriptor *desc)
+{
+ if (desc->nb_components == 1)
+ return VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR;
+ else if (!desc->log2_chroma_w && !desc->log2_chroma_h)
+ return VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR;
+ else if (!desc->log2_chroma_w && desc->log2_chroma_h == 1)
+ return VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR;
+ else if (desc->log2_chroma_w == 1 && desc->log2_chroma_h == 1)
+ return VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR;
+ return VK_VIDEO_CHROMA_SUBSAMPLING_INVALID_KHR;
+}
+
+VkVideoComponentBitDepthFlagBitsKHR ff_vk_depth_from_av_depth(int depth)
+{
+ switch (depth) {
+ case 8: return VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR;
+ case 10: return VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR;
+ case 12: return VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR;
+ default: break;
+ }
+ return VK_VIDEO_COMPONENT_BIT_DEPTH_INVALID_KHR;
+}
+
+static void free_data_buf(void *opaque, uint8_t *data)
+{
+ FFVulkanContext *ctx = opaque;
+ FFVkVideoBuffer *buf = (FFVkVideoBuffer *)data;
+ ff_vk_unmap_buffer(ctx, &buf->buf, 0);
+ ff_vk_free_buf(ctx, &buf->buf);
+ av_free(data);
+}
+
+static AVBufferRef *alloc_data_buf(void *opaque, size_t size)
+{
+ AVBufferRef *ref;
+ uint8_t *buf = av_mallocz(size);
+ if (!buf)
+ return NULL;
+
+ ref = av_buffer_create(buf, size, free_data_buf, opaque, 0);
+ if (!ref)
+ av_free(buf);
+ return ref;
+}
+
+int ff_vk_video_get_buffer(FFVulkanContext *ctx, FFVkVideoCommon *s,
+ AVBufferRef **buf, VkBufferUsageFlags usage,
+ void *create_pNext, size_t size)
+{
+ int err;
+ AVBufferRef *ref;
+ FFVkVideoBuffer *data;
+
+ if (!s->buf_pool) {
+ s->buf_pool = av_buffer_pool_init2(sizeof(FFVkVideoBuffer), ctx,
+ alloc_data_buf, NULL);
+ if (!s->buf_pool)
+ return AVERROR(ENOMEM);
+ }
+
+ *buf = ref = av_buffer_pool_get(s->buf_pool);
+ if (!ref)
+ return AVERROR(ENOMEM);
+
+ data = (FFVkVideoBuffer *)ref->data;
+
+ if (data->buf.size >= size)
+ return 0;
+
+ /* No point in requesting anything smaller. */
+ size = FFMAX(size, 1024*1024);
+
+ /* Align buffer to nearest power of two. Makes fragmentation management
+ * easier, and gives us ample headroom. */
+ size--;
+ size |= size >> 1;
+ size |= size >> 2;
+ size |= size >> 4;
+ size |= size >> 8;
+ size |= size >> 16;
+ size++;
+
+ ff_vk_free_buf(ctx, &data->buf);
+ memset(data, 0, sizeof(FFVkVideoBuffer));
+
+ err = ff_vk_create_buf(ctx, &data->buf, size,
+ create_pNext, NULL, usage,
+ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
+ if (err < 0) {
+ av_buffer_unref(&ref);
+ return err;
+ }
+
+ /* Map the buffer */
+ err = ff_vk_map_buffer(ctx, &data->buf, &data->mem, 0);
+ if (err < 0) {
+ av_buffer_unref(&ref);
+ return err;
+ }
+
+ return 0;
+}
+
+av_cold void ff_vk_video_common_uninit(FFVulkanContext *s,
+ FFVkVideoCommon *common)
+{
+ FFVulkanFunctions *vk = &s->vkfn;
+
+ if (common->session) {
+ vk->DestroyVideoSessionKHR(s->hwctx->act_dev, common->session,
+ s->hwctx->alloc);
+ common->session = NULL;
+ }
+
+ if (common->nb_mem && common->mem)
+ for (int i = 0; i < common->nb_mem; i++)
+ vk->FreeMemory(s->hwctx->act_dev, common->mem[i], s->hwctx->alloc);
+
+ av_freep(&common->mem);
+
+ av_buffer_pool_uninit(&common->buf_pool);
+}
+
+av_cold int ff_vk_video_common_init(void *log, FFVulkanContext *s,
+ FFVkVideoCommon *common,
+ VkVideoSessionCreateInfoKHR *session_create)
+{
+ int err;
+ VkResult ret;
+ FFVulkanFunctions *vk = &s->vkfn;
+ VkMemoryRequirements2 *mem_req = NULL;
+ VkVideoSessionMemoryRequirementsKHR *mem = NULL;
+ VkBindVideoSessionMemoryInfoKHR *bind_mem = NULL;
+
+ /* Create session */
+ ret = vk->CreateVideoSessionKHR(s->hwctx->act_dev, session_create,
+ s->hwctx->alloc, &common->session);
+ if (ret != VK_SUCCESS)
+ return AVERROR_EXTERNAL;
+
+ /* Get memory requirements */
+ ret = vk->GetVideoSessionMemoryRequirementsKHR(s->hwctx->act_dev,
+ common->session,
+ &common->nb_mem,
+ NULL);
+ if (ret != VK_SUCCESS) {
+ err = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ /* Allocate all memory needed to actually allocate memory */
+ common->mem = av_mallocz(sizeof(*common->mem)*common->nb_mem);
+ if (!common->mem) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+ mem = av_mallocz(sizeof(*mem)*common->nb_mem);
+ if (!mem) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+ mem_req = av_mallocz(sizeof(*mem_req)*common->nb_mem);
+ if (!mem_req) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+ bind_mem = av_mallocz(sizeof(*bind_mem)*common->nb_mem);
+ if (!bind_mem) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ /* Set the needed fields to get the memory requirements */
+ for (int i = 0; i < common->nb_mem; i++) {
+ mem_req[i] = (VkMemoryRequirements2) {
+ .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
+ };
+ mem[i] = (VkVideoSessionMemoryRequirementsKHR) {
+ .sType = VK_STRUCTURE_TYPE_VIDEO_SESSION_MEMORY_REQUIREMENTS_KHR,
+ .memoryRequirements = mem_req[i].memoryRequirements,
+ };
+ }
+
+ /* Finally get the memory requirements */
+ ret = vk->GetVideoSessionMemoryRequirementsKHR(s->hwctx->act_dev,
+ common->session, &common->nb_mem,
+ mem);
+ if (ret != VK_SUCCESS) {
+ err = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ /* Now allocate each requested memory.
+ * For ricing, could pool together memory that ends up in the same index. */
+ for (int i = 0; i < common->nb_mem; i++) {
+ err = ff_vk_alloc_mem(s, &mem[i].memoryRequirements,
+ UINT32_MAX, NULL, NULL, &common->mem[i]);
+ if (err < 0)
+ goto fail;
+
+ bind_mem[i] = (VkBindVideoSessionMemoryInfoKHR) {
+ .sType = VK_STRUCTURE_TYPE_BIND_VIDEO_SESSION_MEMORY_INFO_KHR,
+ .memory = common->mem[i],
+ .memoryBindIndex = mem[i].memoryBindIndex,
+ .memoryOffset = 0,
+ .memorySize = mem[i].memoryRequirements.size,
+ };
+
+ av_log(log, AV_LOG_VERBOSE, "Allocating %lu bytes in bind index %i for video session\n",
+ bind_mem[i].memorySize, bind_mem[i].memoryBindIndex);
+ }
+
+ /* Bind the allocated memory */
+ ret = vk->BindVideoSessionMemoryKHR(s->hwctx->act_dev, common->session,
+ common->nb_mem, bind_mem);
+ if (ret != VK_SUCCESS) {
+ err = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ av_freep(&mem);
+ av_freep(&mem_req);
+ av_freep(&bind_mem);
+
+ return 0;
+
+fail:
+ av_freep(&mem);
+ av_freep(&mem_req);
+ av_freep(&bind_mem);
+
+ ff_vk_video_common_uninit(s, common);
+ return err;
+}
diff --git a/libavcodec/vulkan_video.h b/libavcodec/vulkan_video.h
new file mode 100644
index 0000000000..b4adde4ec1
--- /dev/null
+++ b/libavcodec/vulkan_video.h
@@ -0,0 +1,97 @@
+/*
+ * 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
+ */
+
+#ifndef AVCODEC_VULKAN_VIDEO_H
+#define AVCODEC_VULKAN_VIDEO_H
+
+#include "codec_id.h"
+#include "vulkan.h"
+
+#include <vk_video/vulkan_video_codecs_common.h>
+
+#define CODEC_VER_MAJ(ver) (ver >> 22)
+#define CODEC_VER_MIN(ver) ((ver >> 12) & ((1 << 10) - 1))
+#define CODEC_VER_PAT(ver) (ver & ((1 << 12) - 1))
+#define CODEC_VER(ver) CODEC_VER_MAJ(ver), CODEC_VER_MIN(ver), CODEC_VER_PAT(ver)
+
+typedef struct FFVkCodecMap {
+ FFVulkanExtensions encode_extension;
+ VkVideoCodecOperationFlagBitsKHR encode_op;
+ FFVulkanExtensions decode_extension;
+ VkVideoCodecOperationFlagBitsKHR decode_op;
+} FFVkCodecMap;
+
+typedef struct FFVkVideoSession {
+ VkVideoSessionKHR session;
+ VkDeviceMemory *mem;
+ uint32_t nb_mem;
+
+ AVBufferPool *buf_pool;
+} FFVkVideoCommon;
+
+/**
+ * Index is codec_id.
+ */
+extern const FFVkCodecMap ff_vk_codec_map[AV_CODEC_ID_FIRST_AUDIO];
+
+/**
+ * Get pixfmt from a Vulkan format.
+ */
+enum AVPixelFormat ff_vk_pix_fmt_from_vkfmt(VkFormat vkf);
+
+/**
+ * Get aspect bits which include all planes from a VkFormat.
+ */
+VkImageAspectFlags ff_vk_aspect_bits_from_vkfmt(VkFormat vkf);
+
+/**
+ * Get Vulkan's chroma subsampling from a pixfmt descriptor.
+ */
+VkVideoChromaSubsamplingFlagBitsKHR ff_vk_subsampling_from_av_desc(const AVPixFmtDescriptor *desc);
+
+/**
+ * Get Vulkan's bit depth from an [8:12] integer.
+ */
+VkVideoComponentBitDepthFlagBitsKHR ff_vk_depth_from_av_depth(int depth);
+
+typedef struct FFVkVideoBuffer {
+ FFVkBuffer buf;
+ uint8_t *mem;
+} FFVkVideoBuffer;
+
+/**
+ * Get a mapped FFVkPooledBuffer with a specific guaranteed minimum size
+ * from a pool.
+ */
+int ff_vk_video_get_buffer(FFVulkanContext *ctx, FFVkVideoCommon *s,
+ AVBufferRef **buf, VkBufferUsageFlags usage,
+ void *create_pNext, size_t size);
+
+/**
+ * Initialize video session, allocating and binding necessary memory.
+ */
+int ff_vk_video_common_init(void *log, FFVulkanContext *s,
+ FFVkVideoCommon *common,
+ VkVideoSessionCreateInfoKHR *session_create);
+
+/**
+ * Free video session and required resources.
+ */
+void ff_vk_video_common_uninit(FFVulkanContext *s, FFVkVideoCommon *common);
+
+#endif /* AVCODEC_VULKAN_VIDEO_H */