WIP.
---
 configure                    |   5 +
 libavutil/hwcontext_opencl.c | 354 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 359 insertions(+)

diff --git a/configure b/configure
index e601de5..1311612 100755
--- a/configure
+++ b/configure
@@ -1655,6 +1655,7 @@ HAVE_LIST="
     libdc1394_1
     libdc1394_2
     MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS
+    intel_opencl_vaapi
     sdl
     section_data_rel_ro
     threads
@@ -4735,6 +4736,10 @@ if enabled libcdio; then
     die "ERROR: No usable libcdio/cdparanoia found"
 fi

+if enabled opencl ; then
+    check_type "CL/cl_intel.h" "clCreateImageFromFdINTEL_fn" && enable 
intel_opencl_vaapi
+fi
+
 check_lib X11/Xlib.h XOpenDisplay -lX11 && enable xlib

 if enabled libxcb || enabled x11grab && ! disabled libxcb; then
diff --git a/libavutil/hwcontext_opencl.c b/libavutil/hwcontext_opencl.c
index 0a68afe..50de8fa 100644
--- a/libavutil/hwcontext_opencl.c
+++ b/libavutil/hwcontext_opencl.c
@@ -27,8 +27,20 @@
 #include "hwcontext_opencl.h"
 #include "mem.h"

+#if HAVE_INTEL_OPENCL_VAAPI
+#include <unistd.h>
+#include <CL/cl_intel.h>
+#include "hwcontext_vaapi.h"
+#include <va/va_drmcommon.h>
+#endif
+

 typedef struct OpenCLDeviceContext {
+#if HAVE_INTEL_OPENCL_VAAPI
+    clGetMemObjectFdIntel_fn     clGetMemObjectFdIntel;
+    clCreateImageFromFdINTEL_fn  clCreateImageFromFdINTEL;
+    clCreateBufferFromFdINTEL_fn clCreateBufferFromFdINTEL;
+#endif
 } OpenCLDeviceContext;

 static void opencl_error_callback(const char *errinfo,
@@ -165,6 +177,43 @@ static int opencl_device_init(AVHWDeviceContext *hwdev)
     AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
     OpenCLDeviceContext     *ctx = hwdev->internal->priv;

+#if HAVE_INTEL_OPENCL_VAAPI
+    // Check for the right extension before calling this...
+
+    ctx->clGetMemObjectFdIntel =
+        clGetExtensionFunctionAddressForPlatform(hwctx->platform_id,
+                                                 "clGetMemObjectFdIntel");
+    if (!ctx->clGetMemObjectFdIntel) {
+        av_log(hwdev, AV_LOG_WARNING,
+               "Intel OpenCL to VAAPI mapping not found.\n");
+    } else {
+        av_log(hwdev, AV_LOG_WARNING,
+               "Intel OpenCL to VAAPI mapping found.\n");
+    }
+
+    ctx->clCreateBufferFromFdINTEL =
+        clGetExtensionFunctionAddressForPlatform(hwctx->platform_id,
+                                                 "clCreateBufferFromFdINTEL");
+    if (!ctx->clCreateBufferFromFdINTEL) {
+        av_log(hwdev, AV_LOG_WARNING,
+               "Intel VAAPI to OpenCL mapping not found.\n");
+    } else {
+        av_log(hwdev, AV_LOG_WARNING,
+               "Intel VAAPI to OpenCL mapping found.\n");
+    }
+
+    ctx->clCreateImageFromFdINTEL =
+        clGetExtensionFunctionAddressForPlatform(hwctx->platform_id,
+                                                 "clCreateImageFromFdINTEL");
+    if (!ctx->clCreateImageFromFdINTEL) {
+        av_log(hwdev, AV_LOG_WARNING,
+               "Intel VAAPI to OpenCL mapping not found.\n");
+    } else {
+        av_log(hwdev, AV_LOG_WARNING,
+               "Intel VAAPI to OpenCL mapping found.\n");
+    }
+#endif
+
     return 0;
 }

@@ -311,6 +360,308 @@ static int opencl_get_buffer(AVHWFramesContext *hwfc, 
AVFrame *frame)
     return 0;
 }

+#if HAVE_INTEL_OPENCL_VAAPI
+
+typedef struct VAAPItoOpenCLMapping {
+    VAImage      va_image;
+    VABufferInfo va_buffer_info;
+
+    int       nb_planes;
+    cl_mem       plane[4];
+} VAAPItoOpenCLMapping;
+
+static void opencl_unmap_from_vaapi(AVHWFramesContext *src_fc,
+                                    FFHWMapDescriptor *hwmap)
+{
+    VAAPItoOpenCLMapping *mapping = hwmap->priv;
+    AVVAAPIDeviceContext *src_dev = src_fc->device_ctx->hwctx;
+    VASurfaceID surface_id;
+    VAStatus vas;
+    cl_int cle;
+    int i;
+
+    surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
+    av_log(src_fc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from OpenCL.\n",
+           surface_id);
+
+    for (i = 0; i < mapping->nb_planes; i++) {
+        cle = clReleaseMemObject(mapping->plane[i]);
+        if (cle != CL_SUCCESS) {
+            av_log(src_fc, AV_LOG_ERROR, "Failed to release CL "
+                   "buffer of plane %d of VA image %#x (derived "
+                   "from surface %#x): %d.\n", i,
+                   mapping->va_image.buf, surface_id, cle);
+        }
+    }
+
+    vas = vaReleaseBufferHandle(src_dev->display,
+                                mapping->va_image.buf);
+    if (vas != VA_STATUS_SUCCESS) {
+        av_log(src_fc, AV_LOG_ERROR, "Failed to release buffer "
+               "handle of image %#x (derived from surface %#x): "
+               "%d (%s).\n", mapping->va_image.buf, surface_id,
+               vas, vaErrorStr(vas));
+    }
+
+    vas = vaDestroyImage(src_dev->display,
+                         mapping->va_image.image_id);
+    if (vas != VA_STATUS_SUCCESS) {
+        av_log(src_fc, AV_LOG_ERROR, "Failed to destroy image "
+               "derived from surface %#x: %d (%s).\n",
+               surface_id, vas, vaErrorStr(vas));
+    }
+
+    av_free(mapping);
+}
+
+static int opencl_map_from_vaapi(AVHWFramesContext *dst_fc, AVFrame *dst,
+                                 const AVFrame *src, int flags)
+{
+    AVHWFramesContext      *src_fc =
+        (AVHWFramesContext*)src->hw_frames_ctx->data;
+    AVVAAPIDeviceContext  *src_dev = src_fc->device_ctx->hwctx;
+    AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
+    OpenCLDeviceContext       *ctx = dst_fc->device_ctx->internal->priv;
+    VAAPItoOpenCLMapping  *mapping = NULL;
+    VASurfaceID surface_id;
+    VAStatus vas;
+    cl_int cle;
+    int err, i;
+
+    surface_id = (VASurfaceID)(uintptr_t)src->data[3];
+    av_log(src_fc, AV_LOG_DEBUG, "Map VAAPI surface %#x to OpenCL.\n",
+           surface_id);
+
+    mapping = av_malloc(sizeof(*mapping));
+    if (!mapping) {
+        err = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    vas = vaDeriveImage(src_dev->display, surface_id,
+                        &mapping->va_image);
+    if (vas != VA_STATUS_SUCCESS) {
+        av_log(src_fc, AV_LOG_ERROR, "Failed to derive image from "
+               "surface %#x: %d (%s).\n",
+               surface_id, vas, vaErrorStr(vas));
+        return AVERROR(EIO);
+    }
+
+    mapping->va_buffer_info.mem_type =
+        VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
+
+    vas = vaAcquireBufferHandle(src_dev->display,
+                                mapping->va_image.buf,
+                                &mapping->va_buffer_info);
+    if (vas != VA_STATUS_SUCCESS) {
+        av_log(src_fc, AV_LOG_ERROR, "Failed to get buffer "
+               "handle from image %#x (derived from surface %#x): "
+               "%d (%s).\n", mapping->va_image.buf, surface_id,
+               vas, vaErrorStr(vas));
+        vaDestroyImage(src_dev->display, mapping->va_image.buf);
+        return AVERROR(EIO);
+    }
+
+    av_log(dst_fc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
+           mapping->va_buffer_info.handle);
+
+    mapping->nb_planes = mapping->va_image.num_planes;
+    for (i = 0; i < mapping->nb_planes; i++) {
+        cl_import_image_info_intel cl_image_info = {
+            .fd   = mapping->va_buffer_info.handle,
+            .size = mapping->va_buffer_info.mem_size,
+            .type = CL_MEM_OBJECT_IMAGE2D,
+            .fmt  = {
+                .image_channel_order     = i ? CL_RG : CL_R,
+                .image_channel_data_type = CL_UNSIGNED_INT8,
+            },
+            .offset    = mapping->va_image.offsets[i],
+            .width     = mapping->va_image.width  / (i + 1),
+            .height    = mapping->va_image.height / (i + 1),
+            .row_pitch = mapping->va_image.pitches[i],
+        };
+
+        mapping->plane[i] =
+            ctx->clCreateImageFromFdINTEL(dst_dev->context,
+                                           &cl_image_info, &cle);
+        if (!mapping->plane[i]) {
+            av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL buffer "
+                   "from plane %d of VA image %#x (derived from "
+                   "surface %#x): %d.\n", i,
+                   mapping->va_image.buf, surface_id, cle);
+            return AVERROR(EIO);
+        }
+
+        dst->data[i] = (uint8_t*)mapping->plane[i];
+        dst->linesize[i] = mapping->va_image.pitches[i];
+    }
+
+    err = ff_hwframe_map_create(src->hw_frames_ctx,
+                                dst, src, &opencl_unmap_from_vaapi,
+                                mapping);
+    if (err < 0)
+        goto fail;
+
+    dst->width  = src->width;
+    dst->height = src->height;
+
+    av_log(dst_fc, AV_LOG_DEBUG, "Mapped successfully!\n");
+
+    return 0;
+
+fail:
+    // TODO: cleanup.
+    return err;
+}
+
+typedef struct OpenCLtoVAAPIMapping {
+    int         fd;
+
+    VASurfaceID surface_id;
+} OpenCLtoVAAPIMapping;
+
+static void opencl_unmap_to_vaapi(AVHWFramesContext *dst_fc,
+                                  FFHWMapDescriptor *hwmap)
+{
+    OpenCLtoVAAPIMapping *mapping = hwmap->priv;
+    AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
+
+    av_log(dst_fc, AV_LOG_VERBOSE, "Unmap fd %d / surface %#x.\n",
+           mapping->fd, mapping->surface_id);
+
+    vaDestroySurfaces(dst_dev->display, &mapping->surface_id, 1);
+
+    close(mapping->fd);
+
+    av_free(mapping);
+}
+
+static int opencl_map_to_vaapi(AVHWFramesContext *src_fc, AVFrame *dst,
+                               const AVFrame *src, int flags)
+{
+    AVOpenCLDeviceContext *src_dev = src_fc->device_ctx->hwctx;
+    OpenCLDeviceContext       *ctx = src_fc->device_ctx->internal->priv;
+    AVHWFramesContext      *dst_fc =
+        (AVHWFramesContext*)dst->hw_frames_ctx->data;
+    AVVAAPIDeviceContext  *dst_dev = dst_fc->device_ctx->hwctx;
+    OpenCLtoVAAPIMapping  *mapping = NULL;
+    VAStatus vas;
+    cl_int cle;
+    int err;
+
+    mapping = av_malloc(sizeof(*mapping));
+    if (!mapping) {
+        err = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    cle = ctx->clGetMemObjectFdIntel(src_dev->context,
+                                     (cl_mem)src->data[0],
+                                     &mapping->fd);
+    if (cle != CL_SUCCESS) {
+        av_log(src_fc, AV_LOG_ERROR, "Failed to get PRIME fd from "
+               "CL buffer: %d.\n", cle);
+        return AVERROR(EIO);
+    }
+
+    av_log(dst_fc, AV_LOG_DEBUG, "DRM PRIME fd is %d.\n",
+           mapping->fd);
+
+    {
+        unsigned long buffer_handle = mapping->fd;
+
+        VASurfaceAttribExternalBuffers buffer_desc = {
+            .pixel_format = VA_FOURCC_NV12,
+            .width        = src_fc->width,
+            .height       = src_fc->height,
+            .data_size    = src_fc->width * src_fc->height * 3 / 2,
+            .num_planes   = 2,
+            .pitches[0]   = src_fc->width,
+            .offsets[0]   = 0,
+            .pitches[1]   = src_fc->width,
+            .offsets[1]   = src_fc->width * src_fc->height,
+            .buffers      = &buffer_handle,
+            .num_buffers  = 1,
+        };
+
+        VASurfaceAttrib attrs[2] = {
+            {
+                .type  = VASurfaceAttribMemoryType,
+                .flags = VA_SURFACE_ATTRIB_SETTABLE,
+                .value.type    = VAGenericValueTypeInteger,
+                .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
+            },
+            {
+                .type  = VASurfaceAttribExternalBufferDescriptor,
+                .flags = VA_SURFACE_ATTRIB_SETTABLE,
+                .value.type    = VAGenericValueTypePointer,
+                .value.value.p = &buffer_desc,
+            }
+        };
+
+        vas = vaCreateSurfaces(dst_dev->display,
+                               VA_RT_FORMAT_YUV420,
+                               src->width, src->height,
+                               &mapping->surface_id, 1,
+                               attrs, FF_ARRAY_ELEMS(attrs));
+        if(vas != VA_STATUS_SUCCESS) {
+            av_log(ctx, AV_LOG_ERROR, "Failed to create surface from "
+                   "DRM buffer: %d (%s).\n", vas, vaErrorStr(vas));
+            return AVERROR(EIO);
+        }
+    }
+
+    err = ff_hwframe_map_create(dst->hw_frames_ctx,
+                                dst, src, &opencl_unmap_to_vaapi,
+                                mapping);
+    if (err < 0)
+        goto fail;
+
+    dst->width  = src->width;
+    dst->height = src->height;
+    dst->data[3] = (uint8_t*)(uintptr_t)mapping->surface_id;
+
+    av_log(dst_fc, AV_LOG_DEBUG, "Mapped successfully!\n");
+
+    return 0;
+
+fail:
+    // TODO: cleanup.
+    return err;
+}
+
+#endif
+
+static int opencl_map_to(AVHWFramesContext *ctx, AVFrame *dst,
+                         const AVFrame *src, int flags)
+{
+    av_assert0(dst->format == AV_PIX_FMT_OPENCL);
+    switch (src->format) {
+
+#if HAVE_INTEL_OPENCL_VAAPI
+    case AV_PIX_FMT_VAAPI:
+        return opencl_map_from_vaapi(ctx, dst, src, flags);
+#endif
+    default:
+        return AVERROR(ENOSYS);
+    }
+}
+
+static int opencl_map_from(AVHWFramesContext *ctx, AVFrame *dst,
+                           const AVFrame *src, int flags)
+{
+    av_assert0(src->format == AV_PIX_FMT_OPENCL);
+    switch (dst->format) {
+
+#if HAVE_INTEL_OPENCL_VAAPI
+    case AV_PIX_FMT_VAAPI:
+        return opencl_map_to_vaapi(ctx, dst, src, flags);
+#endif
+    default:
+        return AVERROR(ENOSYS);
+    }
+}
+
 const HWContextType ff_hwcontext_type_opencl = {
     .type              = AV_HWDEVICE_TYPE_OPENCL,
     .name              = "OpenCL",
@@ -326,6 +677,9 @@ const HWContextType ff_hwcontext_type_opencl = {
     .frames_uninit     = &opencl_frames_uninit,
     .frames_get_buffer = &opencl_get_buffer,

+    .map_to            = &opencl_map_to,
+    .map_from          = &opencl_map_from,
+
     .pix_fmts = (const enum AVPixelFormat[]) {
         AV_PIX_FMT_OPENCL,
         AV_PIX_FMT_NONE
-- 
2.8.1

_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to