[FFmpeg-devel] [PATCH] lavu: add VKAPI hwcontext implementation

suji.velupillai at broadcom.com suji.velupillai at broadcom.com
Fri Mar 12 00:09:21 EET 2021


From: Suji Velupillai <suji.velupillai at broadcom.com>

Initial commit to add VKAPI hardware accelerator implementation.
The depedency component vkil source code can be obtained from github
https://github.com/Broadcom/vkil

Signed-off-by: Suji Velupillai <suji.velupillai at broadcom.com>
---
 configure                      |   8 +-
 doc/APIchanges                 |   4 +
 libavutil/Makefile             |   2 +
 libavutil/hwcontext.c          |   4 +
 libavutil/hwcontext.h          |   1 +
 libavutil/hwcontext_internal.h |   1 +
 libavutil/hwcontext_vkapi.c    | 522 +++++++++++++++++++++++++++++++++
 libavutil/hwcontext_vkapi.h    | 104 +++++++
 libavutil/pixdesc.c            |   4 +
 libavutil/pixfmt.h             |   6 +
 10 files changed, 655 insertions(+), 1 deletion(-)
 create mode 100644 libavutil/hwcontext_vkapi.c
 create mode 100644 libavutil/hwcontext_vkapi.h

diff --git a/configure b/configure
index d11942fced..73eb4539ee 100755
--- a/configure
+++ b/configure
@@ -348,6 +348,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-vkapi          disable VKAPI code [autodetect]
 
 Toolchain options:
   --arch=ARCH              select architecture [$arch]
@@ -1844,6 +1845,7 @@ HWACCEL_AUTODETECT_LIBRARY_LIST="
     vaapi
     vdpau
     videotoolbox
+    vkapi
     v4l2_m2m
     xvmc
 "
@@ -2919,6 +2921,7 @@ nvdec_deps="ffnvcodec"
 vaapi_x11_deps="xlib"
 videotoolbox_hwaccel_deps="videotoolbox pthreads"
 videotoolbox_hwaccel_extralibs="-framework QuartzCore"
+vkapi_deps="libvkil"
 xvmc_deps="X11_extensions_XvMClib_h"
 
 av1_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_AV1"
@@ -3708,7 +3711,7 @@ avformat_deps="avcodec avutil"
 avformat_suggest="libm network zlib"
 avresample_deps="avutil"
 avresample_suggest="libm"
-avutil_suggest="clock_gettime ffnvcodec libm libdrm libmfx opencl user32 vaapi vulkan videotoolbox corefoundation corevideo coremedia bcrypt"
+avutil_suggest="clock_gettime ffnvcodec libm libdrm libmfx opencl user32 vaapi vulkan vkapi videotoolbox corefoundation corevideo coremedia bcrypt"
 postproc_deps="avutil gpl"
 postproc_suggest="libm"
 swresample_deps="avutil"
@@ -6734,6 +6737,9 @@ enabled vdpau &&
 enabled vdpau &&
     check_lib vdpau_x11 "vdpau/vdpau.h vdpau/vdpau_x11.h" vdp_device_create_x11 -lvdpau -lX11
 
+enabled vkapi &&
+    check_lib libvkil vkil_api.h vkil_create_api -lvkil
+
 enabled crystalhd && check_lib crystalhd "stdint.h libcrystalhd/libcrystalhd_if.h" DtsCrystalHDVersion -lcrystalhd
 
 enabled vulkan &&
diff --git a/doc/APIchanges b/doc/APIchanges
index 13350c0db0..ccab2e6465 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -15,6 +15,10 @@ libavutil:     2017-10-21
 
 API changes, most recent first:
 
+2021-03-11 - xxxxxxxxxx - lavu yy.yy.yyy - hwcontext.h
+  Add AV_PIX_FMT_VKAPI
+  Add AV_HWDEVICE_TYPE_VKAPI and implementation.
+
 2021-03-10 - xxxxxxxxxx - lavf 58.72.100 - avformat.h
   Change AVBufferRef related AVStream function and struct size
   parameter and fields type to size_t at next major bump.
diff --git a/libavutil/Makefile b/libavutil/Makefile
index 27bafe9e12..4044b133a3 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -45,6 +45,7 @@ HEADERS = adler32.h                                                     \
           hwcontext_vaapi.h                                             \
           hwcontext_videotoolbox.h                                      \
           hwcontext_vdpau.h                                             \
+          hwcontext_vkapi.h                                             \
           hwcontext_vulkan.h                                            \
           imgutils.h                                                    \
           intfloat.h                                                    \
@@ -185,6 +186,7 @@ OBJS-$(CONFIG_QSV)                      += hwcontext_qsv.o
 OBJS-$(CONFIG_VAAPI)                    += hwcontext_vaapi.o
 OBJS-$(CONFIG_VIDEOTOOLBOX)             += hwcontext_videotoolbox.o
 OBJS-$(CONFIG_VDPAU)                    += hwcontext_vdpau.o
+OBJS-$(CONFIG_VKAPI)                    += hwcontext_vkapi.o
 OBJS-$(CONFIG_VULKAN)                   += hwcontext_vulkan.o
 
 OBJS += $(COMPAT_OBJS:%=../compat/%)
diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c
index d13d0f7c9b..4c13db6578 100644
--- a/libavutil/hwcontext.c
+++ b/libavutil/hwcontext.c
@@ -59,6 +59,9 @@ static const HWContextType * const hw_table[] = {
 #if CONFIG_MEDIACODEC
     &ff_hwcontext_type_mediacodec,
 #endif
+#if CONFIG_VKAPI
+    &ff_hwcontext_type_vkapi,
+#endif
 #if CONFIG_VULKAN
     &ff_hwcontext_type_vulkan,
 #endif
@@ -76,6 +79,7 @@ static const char *const hw_type_names[] = {
     [AV_HWDEVICE_TYPE_VDPAU]  = "vdpau",
     [AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox",
     [AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec",
+    [AV_HWDEVICE_TYPE_VKAPI]  = "vkapi",
     [AV_HWDEVICE_TYPE_VULKAN] = "vulkan",
 };
 
diff --git a/libavutil/hwcontext.h b/libavutil/hwcontext.h
index 04d19d89c2..b862f45aa3 100644
--- a/libavutil/hwcontext.h
+++ b/libavutil/hwcontext.h
@@ -36,6 +36,7 @@ enum AVHWDeviceType {
     AV_HWDEVICE_TYPE_DRM,
     AV_HWDEVICE_TYPE_OPENCL,
     AV_HWDEVICE_TYPE_MEDIACODEC,
+    AV_HWDEVICE_TYPE_VKAPI,
     AV_HWDEVICE_TYPE_VULKAN,
 };
 
diff --git a/libavutil/hwcontext_internal.h b/libavutil/hwcontext_internal.h
index e6266494ac..c5270759a4 100644
--- a/libavutil/hwcontext_internal.h
+++ b/libavutil/hwcontext_internal.h
@@ -173,6 +173,7 @@ extern const HWContextType ff_hwcontext_type_vaapi;
 extern const HWContextType ff_hwcontext_type_vdpau;
 extern const HWContextType ff_hwcontext_type_videotoolbox;
 extern const HWContextType ff_hwcontext_type_mediacodec;
+extern const HWContextType ff_hwcontext_type_vkapi;
 extern const HWContextType ff_hwcontext_type_vulkan;
 
 #endif /* AVUTIL_HWCONTEXT_INTERNAL_H */
diff --git a/libavutil/hwcontext_vkapi.c b/libavutil/hwcontext_vkapi.c
new file mode 100644
index 0000000000..089b0a47d6
--- /dev/null
+++ b/libavutil/hwcontext_vkapi.c
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2018 Broadcom
+ *
+ * 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 "avassert.h"
+#include "buffer.h"
+#include "buffer_internal.h"
+#include "common.h"
+#include "hwcontext.h"
+#include "hwcontext_internal.h"
+#include "hwcontext_vkapi.h"
+#include "imgutils.h"
+#include "mem.h"
+#include "pixdesc.h"
+#include "pixfmt.h"
+
+#define VKAPI_FRAME_ALIGNMENT 256
+
+static const enum AVPixelFormat supported_formats[] = {
+    AV_PIX_FMT_NV12,
+    AV_PIX_FMT_NV21,
+    AV_PIX_FMT_P010,
+    AV_PIX_FMT_P016,
+    AV_PIX_FMT_VKAPI,
+    AV_PIX_FMT_NONE,
+};
+
+/**
+ * Check if the format fmt is in an array
+ *
+ * @param fmt the format to check if exists
+ * @param fmts the array to check the format
+ * @return 1 if format is presnet in an array, 0 otherwise
+ */
+static int vkapi_fmt_is_in(int fmt, const int *fmts)
+{
+    const int *p;
+
+    for (p = fmts; *p != -1; p++) {
+        if (fmt == *p)
+            return 1;
+    }
+
+    return 0;
+}
+
+/**
+ * Convert the pixel format from the AVPixelFormat to a vk_format_type
+ * equivalent.
+ *
+ * @param pixel_format an AVPixelFormat
+ * @return a vkil_format_type if match found, otherwise return an error code
+ */
+static int vkapi_av2vk_fmt(enum AVPixelFormat pixel_format)
+{
+    switch (pixel_format) {
+    case AV_PIX_FMT_NV12:
+        return VK_FORMAT_NV12;
+    case AV_PIX_FMT_NV21:
+        return VK_FORMAT_NV21;
+    case AV_PIX_FMT_P010:
+        return VK_FORMAT_P010;
+    case AV_PIX_FMT_VKAPI:
+        return VK_FORMAT_YOL2;
+    default:
+        return AVERROR(EINVAL);
+    }
+}
+
+/**
+ * Provide the number of buffer currently referenced in the hardware pool
+ *
+ * @param ctx the hardware frames context
+ * @return number of buffer in use in the internal pool
+ */
+static int vkapi_get_pool_occupancy(AVHWFramesContext *ctx)
+{
+    int val = atomic_load(&ctx->internal->pool_internal->refcount);
+
+    return (val - 1);
+}
+
+/**
+ * Get the reference on the frame hwprops
+ *
+ * @param frame the ffmpeg AVFrame structure
+ * @param phw_surface_desc vkil buffer surface associated with the AVFrame
+ * @return 0 if succesfull, otherwise return an error code
+ */
+static int vkapi_frame_ref_hwprops(const AVFrame *frame, void *phw_surface_desc)
+{
+    void **hw_surface_desc = phw_surface_desc;
+
+    if (frame->format != AV_PIX_FMT_VKAPI)
+        return AVERROR_BUG;
+
+    *hw_surface_desc = frame->data[3];
+
+    if (!(*hw_surface_desc))
+        return AVERROR_BUG;
+
+    return 0;
+}
+
+/**
+ * Set a ffmpeg AVFrame with the vkil buffer surface properties
+ *
+ * @param frame the ffmpeg AVFrame structure
+ * @param hw_surface_desc the vkil buffer surface to be associated with the AVFrame
+ * @return 0 if succesfull, otherwise return an error code
+ */
+static int vkapi_frame_set_hwprops(AVFrame *frame,
+                                   const vkil_buffer_surface *hw_surface_desc)
+{
+    if (frame->format != AV_PIX_FMT_VKAPI)
+        return AVERROR_BUG;
+
+    // vkil buffer surface description is stored in ffmpeg AVframe:data[3]
+    av_assert0(frame->data[3]);
+
+    // the "hard copy" only the buffer descriptor
+    memcpy((vkil_buffer_surface *)frame->data[3], hw_surface_desc,
+           sizeof(vkil_buffer_surface));
+
+    return 0;
+}
+
+/**
+ * Retrieve vkil buffer surface properties associated with an ffmpeg AVFrame
+ *
+ * @param frame the ffmpeg AVFrame structure
+ * @param hw_surface_desc a vkil buffer surface, where where to extract the property
+ * @return 0 if succesfull, otherwise return an error code
+ */
+static int vkapi_frame_get_hwprops(const AVFrame *frame,
+                                   vkil_buffer_surface *hw_surface_desc)
+{
+    if (frame->format != AV_PIX_FMT_VKAPI)
+        return AVERROR_BUG;
+
+    // the frame is hw tunneled (hw format)
+    // vkil buffer surface description is stored in ffmpeg AVframe:data[3]
+    av_assert0(frame->data[3]);
+
+    // the "hard copy" only the buffer descriptor
+    memcpy(hw_surface_desc, (vkil_buffer_surface *)frame->data[3],
+           sizeof(vkil_buffer_surface));
+
+    return 0;
+}
+
+static void vkapi_pool_release(void *opaque, uint8_t *data)
+{
+    av_free(data);
+}
+
+static AVBufferRef *vkapi_pool_alloc(void *opaque, int size)
+{
+    AVHWFramesContext *ctx = opaque;
+    AVBufferRef *ret_ptr = NULL;
+    vkil_buffer_surface *hw_surface_desc;
+
+    hw_surface_desc = av_mallocz(sizeof(vkil_buffer_surface));
+    if (!hw_surface_desc) {
+        av_log(hw_surface_desc, AV_LOG_ERROR, "av_mallocz failed\n");
+        goto out;
+    }
+
+    ret_ptr = av_buffer_create((uint8_t *)hw_surface_desc,
+                               sizeof(*hw_surface_desc), vkapi_pool_release,
+                               NULL, AV_BUFFER_FLAG_READONLY);
+    if (!ret_ptr) {
+        av_log(ctx, AV_LOG_ERROR, "av_buffer_create failed\n");
+        av_free(hw_surface_desc);
+    }
+
+out:
+    return ret_ptr;
+}
+
+static int vkapi_frames_init(AVHWFramesContext *ctx)
+{
+    int aligned_width = FFALIGN(ctx->width, VKAPI_FRAME_ALIGNMENT);
+    int ret = AVERROR(EINVAL);
+    int valid_format = vkapi_fmt_is_in(ctx->sw_format, supported_formats);
+    VKAPIFramesContext *vk_framectx = ctx->hwctx;
+
+    if (!valid_format)
+        goto fail;
+
+    // set default VKAPIFramesContext
+    vk_framectx->color.range = AVCOL_RANGE_UNSPECIFIED;
+    vk_framectx->color.primaries = AVCOL_PRI_UNSPECIFIED;
+    vk_framectx->color.trc = AVCOL_TRC_UNSPECIFIED;
+    vk_framectx->color.space = AVCOL_SPC_UNSPECIFIED;
+
+    if (!ctx->pool) {
+        int size;
+
+        switch (ctx->sw_format) {
+        case AV_PIX_FMT_VKAPI:
+            size = sizeof(void *);
+            break;
+        case AV_PIX_FMT_NV12:
+        case AV_PIX_FMT_NV21:
+            size = (aligned_width * ctx->height * 3) >> 1;
+            break;
+        case AV_PIX_FMT_P010:
+        case AV_PIX_FMT_P016:
+            size = aligned_width * ctx->height * 3;
+            break;
+        default:
+            goto fail;
+        }
+
+        ctx->internal->pool_internal = av_buffer_pool_init2(size, ctx, vkapi_pool_alloc, NULL);
+        if (!ctx->internal->pool_internal) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
+    }
+
+    return 0;
+
+fail:
+    av_log(ctx, AV_LOG_ERROR, "vkapi_frames_init failed on error %d\n", ret);
+    return ret;
+
+}
+
+static int vkapi_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
+{
+    int ret = 0;
+
+    frame->buf[0] = av_buffer_pool_get(ctx->pool);
+    if (!frame->buf[0]) {
+        av_log(ctx, AV_LOG_ERROR, "av_buffer_pool_get failed\n");
+        ret = AVERROR(ENOMEM);
+    } else {
+        // vkil data are stored in frame->data[3]
+        frame->data[3] = frame->buf[0]->data;
+        frame->format = AV_PIX_FMT_VKAPI;
+        frame->width  = ctx->width;
+        frame->height = ctx->height;
+    }
+
+    return ret;
+}
+
+static int vkapi_transfer_get_formats(AVHWFramesContext *ctx,
+                                      enum AVHWFrameTransferDirection dir,
+                                      enum AVPixelFormat **formats)
+{
+    enum AVPixelFormat *fmts;
+    int ret = 0;
+
+    // this allocation freed in hwcontext::transfer_data_alloc
+    fmts = av_malloc_array(2, sizeof(*fmts));
+    if (!fmts) {
+        av_log(ctx, AV_LOG_ERROR, "vkapi_transfer_get_formats failed\n");
+        ret = AVERROR(ENOMEM);
+    } else {
+        fmts[0] = ctx->sw_format;
+        fmts[1] = AV_PIX_FMT_NONE;
+        *formats = fmts;
+    }
+
+    return ret;
+}
+
+static int vkapi_convert_AV2VK_Frame(vkil_buffer_surface *dst,
+                                     const AVFrame *src)
+{
+    int i;
+
+    av_assert0(src->interlaced_frame == 0);
+
+    dst->max_size.width  = src->width;
+    dst->max_size.height = src->height;
+    dst->format           = vkapi_av2vk_fmt(src->format);
+    dst->quality          = src->quality;
+    dst->prefix.type      = VKIL_BUF_SURFACE;
+    dst->prefix.port_id   = 0; // set to default (first port)
+    dst->prefix.flags     = 0; // other fields set to zero (default value)
+
+    for (i = 0; i < VKIL_BUF_NPLANES; i++) {
+        dst->plane_top[i] = src->data[i];
+        dst->plane_bot[i] = src->data[i + VKIL_BUF_NPLANES];
+        dst->stride[i] = src->linesize[i];
+        // sanity check: vk structure requires 32 bits alignment
+        if (((uintptr_t)dst->plane_top[i] & (VKIL_BUF_ALIGN -1)) ||
+            ((uintptr_t)dst->plane_bot[i] & (VKIL_BUF_ALIGN -1)) ||
+            (dst->stride[i] &(VKIL_BUF_ALIGN -1)))
+                return AVERROR(EINVAL);
+    }
+
+    return 0;
+}
+
+static int vkapi_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst,
+                                    const AVFrame *src)
+{
+    int ret;
+    int32_t size;
+    VKAPIFramesContext *hw_framectx;
+    AVHWFramesContext *avhw_framectx;
+    VKAPIDeviceContext *hw_devicectx;
+    vkil_buffer_surface *surface;
+    vkil_buffer metadata;
+
+    hw_devicectx = ctx->device_ctx->hwctx;
+
+    av_assert0(src->hw_frames_ctx->data);
+    avhw_framectx = (AVHWFramesContext *)src->hw_frames_ctx->data;
+
+    av_assert0(avhw_framectx->hwctx);
+    hw_framectx = avhw_framectx->hwctx;
+    vkapi_frame_ref_hwprops(src, &surface);
+
+    // populate the vkil_surface structure with the destination pointer on the host
+    vkapi_convert_AV2VK_Frame(surface, dst);
+
+    // blocking call as ffmpeg assume the transfer is complete on return
+    ret = hw_devicectx->ilapi->transfer_buffer2(hw_framectx->ilctx, surface,
+                                                VK_CMD_DOWNLOAD | VK_CMD_OPT_BLOCKING,
+                                                &size);
+    if (ret < 0)
+        goto fail;
+
+
+    if (src->data[VKAPI_METADATA_PLANE]) {
+        // Dereference if any transferred frame that has an associated metadata buffer
+        // no need to transfer it back to host
+        metadata.handle = (uint32_t)src->data[VKAPI_METADATA_PLANE];
+        metadata.type = VKIL_BUF_META_DATA;
+        metadata.ref = 1;
+        ret = hw_devicectx->ilapi->xref_buffer(hw_framectx->ilctx, &metadata, -1,
+                                               VK_CMD_RUN | VK_CMD_OPT_BLOCKING);
+        if (ret)
+            goto fail;
+    }
+
+    return 0;
+
+fail:
+    av_log(ctx, AV_LOG_ERROR, "failure %d on vkapi_transfer_data_to\n", ret);
+    return AVERROR(EINVAL);
+}
+
+static int vkapi_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst,
+                                  const AVFrame *src)
+{
+    int ret;
+    int32_t i, size = 0;
+    VKAPIFramesContext *hw_framectx;
+    AVHWFramesContext *avhw_framectx;
+    VKAPIDeviceContext *hw_devicectx;
+    vkil_buffer_surface *surface;
+    vkil_context *ilctx;
+    uint8_t *tmp_data[4] = {NULL, NULL, NULL, NULL};
+    int linesize[4];
+
+    av_assert0(VKIL_BUF_NPLANES * 2 <= 4);
+
+    hw_devicectx = ctx->device_ctx->hwctx;
+
+    av_assert0(dst->hw_frames_ctx->data);
+    avhw_framectx = (AVHWFramesContext *)dst->hw_frames_ctx->data;
+
+    av_assert0(avhw_framectx->hwctx);
+    hw_framectx = avhw_framectx->hwctx;
+
+    ret = vkapi_frame_ref_hwprops(dst, &surface);
+    if (ret < 0) {
+        ret = AVERROR(EINVAL);
+        goto fail;
+    }
+
+    // populate the vkil_surface structure with the origin pointer on the host
+    ret = vkapi_convert_AV2VK_Frame(surface, src);
+    if (ret) {
+        ret = av_image_alloc(tmp_data, linesize, src->width, src->height,
+                             src->format, VKIL_BUF_ALIGN);
+        if (ret < 0)
+            goto fail;
+
+        av_image_copy(tmp_data, linesize, (const uint8_t **)src->data,
+                      src->linesize, src->format, src->width, src->height);
+
+        for (i = 0; i < VKIL_BUF_NPLANES; i++) {
+                surface->plane_top[i]= tmp_data[i];
+                surface->plane_bot[i]= tmp_data[VKIL_BUF_NPLANES + i];
+                surface->stride[i] = linesize[i];
+        }
+    }
+
+    surface->quality = dst->quality;
+
+    ilctx = hw_framectx->ilctx;
+    if (!ilctx) {
+        ret = AVERROR(EINVAL);
+        goto fail;
+    }
+
+    // blocking call as ffmpeg assumes the transfer is complete on return
+    ret = hw_devicectx->ilapi->transfer_buffer2(ilctx, surface,
+                                                VK_CMD_UPLOAD | VK_CMD_OPT_BLOCKING,
+                                                &size);
+    if (ret < 0) {
+        ret = AVERROR(EINVAL);
+        goto fail;
+     }
+
+    hw_framectx->handle = surface->prefix.handle;
+
+    if (tmp_data[0])
+        av_free(tmp_data[0]);
+
+    return 0;
+
+fail:
+    if (tmp_data[0])
+            av_free(tmp_data[0]);
+
+    av_log(ctx, AV_LOG_ERROR, "failure %d on vkapi_transfer_data_to\n", ret);
+    return ret;
+}
+
+static void vkapi_device_uninit(AVHWDeviceContext *ctx)
+{
+    VKAPIDeviceContext *hwctx;
+
+    av_assert0(ctx);
+    av_assert0(ctx->hwctx);
+
+    hwctx = ctx->hwctx;
+
+    if (hwctx->ilapi)
+        vkil_destroy_api((void **)&hwctx->ilapi);
+}
+
+static int vkapi_device_init(AVHWDeviceContext *ctx)
+{
+    VKAPIDeviceContext *hwctx;
+    int ret = AVERROR_EXTERNAL;
+
+    av_assert0(ctx);
+    av_assert0(ctx->hwctx);
+
+    hwctx = ctx->hwctx;
+    hwctx->frame_set_hwprops = vkapi_frame_set_hwprops;
+    hwctx->frame_get_hwprops = vkapi_frame_get_hwprops;
+    hwctx->frame_ref_hwprops = vkapi_frame_ref_hwprops;
+    hwctx->fmt_is_in = vkapi_fmt_is_in;
+    hwctx->av2vk_fmt = vkapi_av2vk_fmt;
+    hwctx->get_pool_occupancy = vkapi_get_pool_occupancy;
+
+    if (!(hwctx->ilapi = vkil_create_api())) {
+        av_log(ctx, AV_LOG_ERROR, "ctx->ilapi failed to be created\n");
+        goto out;
+    }
+
+    if (!hwctx->ilapi->init) {
+        av_log(ctx, AV_LOG_ERROR, "ctx->ilapi not properly initialized\n");
+        goto out;
+    }
+
+    ret = 0;
+
+out:
+    if (ret)
+        vkapi_device_uninit(ctx);
+
+    return ret;
+}
+
+static int vkapi_device_create(AVHWDeviceContext *ctx, const char *device,
+                               AVDictionary *opts, int flags)
+{
+    /* nothing to do at this time */
+    return 0;
+}
+
+const HWContextType ff_hwcontext_type_vkapi = {
+    .type                   = AV_HWDEVICE_TYPE_VKAPI,
+    .name                   = "VKAPI",
+
+    .device_hwctx_size      = sizeof(VKAPIDeviceContext),
+    .frames_hwctx_size      = sizeof(VKAPIFramesContext),
+
+    .device_create          = vkapi_device_create,
+    .device_init            = vkapi_device_init,
+    .device_uninit          = vkapi_device_uninit,
+
+    .frames_init            = vkapi_frames_init,
+    .frames_get_buffer      = vkapi_get_buffer,
+
+    .transfer_get_formats   = vkapi_transfer_get_formats,
+    .transfer_data_to       = vkapi_transfer_data_to,
+    .transfer_data_from     = vkapi_transfer_data_from,
+
+    .pix_fmts = (const enum AVPixelFormat[]) {
+        AV_PIX_FMT_VKAPI,
+        AV_PIX_FMT_NONE
+    },
+};
diff --git a/libavutil/hwcontext_vkapi.h b/libavutil/hwcontext_vkapi.h
new file mode 100644
index 0000000000..096602b42e
--- /dev/null
+++ b/libavutil/hwcontext_vkapi.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018 Broadcom
+ *
+ * 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 AVUTIL_HWCONTEXT_VKAPI_H
+#define AVUTIL_HWCONTEXT_VKAPI_H
+
+#include <vkil_api.h>
+
+#define VKAPI_METADATA_PLANE 4
+
+/**
+ * @file
+ * API-specific header for AV_HWDEVICE_TYPE_VKAPI.
+ */
+
+/**
+ * Allocated as AVHWDeviceContext.hwctx
+ */
+typedef struct VKAPIDeviceContext {
+    /**
+     * Holds pointers to hardware specific functions
+     */
+    vkil_api *ilapi;
+    /**
+     * Internal functions definitions
+     */
+    /**
+     * Get the hwprops reference from the AVFrame:data[3]
+     */
+    int (*frame_ref_hwprops)(const AVFrame *frame, void *phw_surface_desc);
+    /**
+     * Set the hwprops into AVFrame:data[3]
+     */
+    int (*frame_set_hwprops)(AVFrame *frame, const vkil_buffer_surface *hw_surface_desc);
+    /**
+     * Get the hwprops from AVFrame:data[3]
+     */
+    int (*frame_get_hwprops)(const AVFrame *frame, vkil_buffer_surface *hw_surface_desc);
+    /**
+     * Check if format is in an array
+     */
+    int (*fmt_is_in)(int fmt, const int *fmts);
+    /**
+     * Convert AVPixelFormat to VKAPI equivalent pixel format
+     */
+    int (*av2vk_fmt)(enum AVPixelFormat pixel_format);
+    /**
+     * Get no of buffer count reference in the hardware pool
+     */
+    int (*get_pool_occupancy)(AVHWFramesContext *ctx);
+} VKAPIDeviceContext;
+
+/**
+ * Contains color information for hardware
+ */
+typedef struct VKAPIColorContext {
+    enum AVColorRange range;
+    enum AVColorPrimaries primaries;
+    enum AVColorTransferCharacteristic trc;
+    enum AVColorSpace space;
+    enum AVChromaLocation chroma_location;
+} VKAPIColorContext;
+
+/**
+ * Allocated as AVHWFramesContext.hwctx
+ */
+typedef struct VKAPIFramesContext {
+    /**
+     * Handle to a hardware frame context
+     */
+    uint32_t handle;
+    /**
+     * Hardware component port associated to the frame context
+     */
+    uint32_t port_id;
+    uint32_t extra_port_id;
+    /**
+     * Color information
+     */
+    VKAPIColorContext color;
+    /**
+     * ilcontext associated to the frame context
+     */
+    vkil_context *ilctx;
+} VKAPIFramesContext;
+
+#endif /* AVUTIL_HWCONTEXT_VKAPI_H */
diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c
index 2a919461a5..1d2f242e57 100644
--- a/libavutil/pixdesc.c
+++ b/libavutil/pixdesc.c
@@ -2391,6 +2391,10 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
         },
         .flags = AV_PIX_FMT_FLAG_PLANAR,
     },
+    [AV_PIX_FMT_VKAPI] = {
+        .name = "vkapi",
+        .flags = AV_PIX_FMT_FLAG_HWACCEL,
+    },
     [AV_PIX_FMT_VULKAN] = {
         .name = "vulkan",
         .flags = AV_PIX_FMT_FLAG_HWACCEL,
diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h
index 46ef211add..3ae607a3d6 100644
--- a/libavutil/pixfmt.h
+++ b/libavutil/pixfmt.h
@@ -348,6 +348,12 @@ enum AVPixelFormat {
     AV_PIX_FMT_NV24,      ///< planar YUV 4:4:4, 24bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V)
     AV_PIX_FMT_NV42,      ///< as above, but U and V bytes are swapped
 
+    /**
+     * VKAPI hardware acceleration.
+     * data[3] contains a pointer to the vkil_buffer_surface structure
+     */
+    AV_PIX_FMT_VKAPI,
+
     /**
      * Vulkan hardware images.
      *
-- 
2.17.1



More information about the ffmpeg-devel mailing list