Uses the cl_intel_va_api_media_sharing extension, which supports only
NV12 surfaces and only mapping from QSV to OpenCL.
---
 configure                    |   5 +
 libavutil/hwcontext_opencl.c | 246 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 251 insertions(+)

diff --git a/configure b/configure
index a6933288b..10f2fdaf7 100755
--- a/configure
+++ b/configure
@@ -1706,6 +1706,7 @@ HAVE_LIST="
     $TYPES_LIST
     dos_paths
     dxva2_lib
+    intel_opencl_qsv
     intel_opencl_vaapi
     libc_msvcrt
     MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS
@@ -4826,6 +4827,10 @@ enabled vaapi &&
 if enabled opencl && enabled vaapi ; then
     check_type "CL/cl_intel.h" "clCreateImageFromFdINTEL_fn" &&
         enable intel_opencl_vaapi
+    if enabled libmfx ; then
+        check_type "CL/cl.h CL/va_ext.h" 
"clCreateFromVA_APIMediaSurfaceINTEL_fn" &&
+            enable intel_opencl_qsv
+    fi
 fi
 
 enabled vdpau &&
diff --git a/libavutil/hwcontext_opencl.c b/libavutil/hwcontext_opencl.c
index 7d14052b8..f380b35af 100644
--- a/libavutil/hwcontext_opencl.c
+++ b/libavutil/hwcontext_opencl.c
@@ -37,6 +37,13 @@
 #include "hwcontext_vaapi.h"
 #endif
 
+#if HAVE_INTEL_OPENCL_QSV
+#include <mfx/mfxstructures.h>
+#include <va/va.h>
+#include <CL/va_ext.h>
+#include "hwcontext_vaapi.h"
+#endif
+
 // The maximum number of planes in an image.  This must be structly
 // less than AV_NUM_DATA_POINTERS because we place the whole-frame
 // reference in a buffer entry after the final plane.  For now, four
@@ -57,6 +64,16 @@ typedef struct OpenCLDeviceContext {
     clCreateImageFromFdINTEL_fn  clCreateImageFromFdINTEL;
     clCreateBufferFromFdINTEL_fn clCreateBufferFromFdINTEL;
 #endif
+
+#if HAVE_INTEL_OPENCL_QSV
+    int qsv_enabled;
+    clCreateFromVA_APIMediaSurfaceINTEL_fn
+        clCreateFromVA_APIMediaSurfaceINTEL;
+    clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn
+        clEnqueueAcquireVA_APIMediaSurfacesINTEL;
+    clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn
+        clEnqueueReleaseVA_APIMediaSurfacesINTEL;
+#endif
 } OpenCLDeviceContext;
 
 static void opencl_error_callback(const char *errinfo,
@@ -325,6 +342,71 @@ static int opencl_device_init(AVHWDeviceContext *hwdev)
     }
 #endif
 
+#if HAVE_INTEL_OPENCL_QSV
+    {
+        size_t props_size;
+        cl_context_properties *props = NULL;
+        VADisplay va_display;
+        int i;
+
+        cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES,
+                               0, NULL, &props_size);
+        if (cle != CL_SUCCESS) {
+            av_log(hwdev, AV_LOG_ERROR, "Failed to get context "
+                   "properties: %d.\n", cle);
+            goto no_qsv;
+        }
+
+        props = av_malloc(props_size);
+        if (!props)
+            return AVERROR(ENOMEM);
+
+        cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES,
+                               props_size, props, NULL);
+        if (cle != CL_SUCCESS) {
+            av_log(hwdev, AV_LOG_ERROR, "Failed to get context "
+                   "properties: %d.\n", cle);
+            goto no_qsv;
+        }
+
+        va_display = NULL;
+        for (i = 0; i < (props_size / sizeof(*props) - 1); i++) {
+            if (props[i] == CL_CONTEXT_VA_API_DISPLAY_INTEL) {
+                va_display = (VADisplay)(intptr_t)props[i+1];
+                break;
+            }
+        }
+        if (!va_display) {
+            av_log(hwdev, AV_LOG_ERROR, "Media sharing must be "
+                   "enabled on context creation to use QSV to "
+                   "OpenCL mapping.\n");
+            goto no_qsv;
+        }
+        if (!vaDisplayIsValid(va_display)) {
+            av_log(hwdev, AV_LOG_ERROR, "A valid VADisplay is "
+                   "required on context creation to use QSV to "
+                   "OpenCL mapping.\n");
+            goto no_qsv;
+        }
+
+        CL_FUNC(clCreateFromVA_APIMediaSurfaceINTEL,
+                "Intel QSV to OpenCL mapping", no_qsv);
+        CL_FUNC(clEnqueueAcquireVA_APIMediaSurfacesINTEL,
+                "Intel QSV in OpenCL acquire", no_qsv);
+        CL_FUNC(clEnqueueReleaseVA_APIMediaSurfacesINTEL,
+                "Intel QSV in OpenCL release", no_qsv);
+
+        ctx->qsv_enabled = 1;
+        if (0) {
+        no_qsv:
+            av_log(hwdev, AV_LOG_ERROR, "QSV to OpenCL mapping "
+                   "not usable.\n");
+            ctx->qsv_enabled = 0;
+        }
+        av_free(props);
+    }
+#endif
+
 #undef CL_FUNC
 
     return 0;
@@ -360,6 +442,30 @@ static int opencl_device_derive(AVHWDeviceContext *ctx,
             err = opencl_device_init(ctx);
         break;
 #endif
+#if HAVE_INTEL_OPENCL_QSV
+        // The generic code automatically attempts to derive from all
+        // ancestors of the given device, so we can ignore QSV devices
+        // here and just consider the inner device it was derived from.
+    case AV_HWDEVICE_TYPE_VAAPI:
+        {
+            AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx;
+            cl_context_properties props[5] = {
+                CL_CONTEXT_VA_API_DISPLAY_INTEL,
+                (intptr_t)src_hwctx->display,
+                CL_CONTEXT_INTEROP_USER_SYNC,
+                CL_FALSE,
+                0,
+            };
+            err = av_dict_set(&opts, "device_extensions",
+                              "cl_intel_va_api_media_sharing", 0);
+            if (err >= 0)
+                err = opencl_device_create_internal(ctx, NULL, opts,
+                                                    0, props);
+            if (err >= 0)
+                err = opencl_device_init(ctx);
+        }
+        break;
+#endif
     default:
         err = AVERROR(ENOSYS);
         break;
@@ -1362,6 +1468,141 @@ fail:
 
 #endif
 
+#if HAVE_INTEL_OPENCL_QSV
+
+typedef struct QSVtoOpenCLMapping {
+    int nb_planes;
+    cl_mem plane[MAX_PLANES];
+} QSVtoOpenCLMapping;
+
+static void opencl_unmap_from_qsv(AVHWFramesContext *dst_fc,
+                                  HWMapDescriptor *hwmap)
+{
+    QSVtoOpenCLMapping *mapping = hwmap->priv;
+    OpenCLDeviceContext    *ctx = dst_fc->device_ctx->internal->priv;
+    cl_event event;
+    cl_int cle;
+    int i;
+
+    av_log(dst_fc, AV_LOG_DEBUG, "Unmap QSV/VAAPI surface from OpenCL.\n");
+
+    cle = ctx->clEnqueueReleaseVA_APIMediaSurfacesINTEL(
+        ctx->command_queue, mapping->nb_planes, mapping->plane,
+        0, NULL, &event);
+    if (cle != CL_SUCCESS) {
+        av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface "
+               "handle: %d.\n", cle);
+    }
+
+    opencl_wait_events(dst_fc, &event, 1);
+
+    for (i = 0; i < mapping->nb_planes; i++) {
+        cle = clReleaseMemObject(mapping->plane[i]);
+        if (cle != CL_SUCCESS) {
+            av_log(dst_fc, AV_LOG_ERROR, "Failed to release CL "
+                   "image of plane %d of QSV/VAAPI surface.\n", cle);
+        }
+    }
+
+    av_free(mapping);
+}
+
+static int opencl_map_from_qsv(AVHWFramesContext *dst_fc, AVFrame *dst,
+                               const AVFrame *src, int flags)
+{
+    AVHWFramesContext      *src_fc =
+        (AVHWFramesContext*)src->hw_frames_ctx->data;
+    AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
+    OpenCLDeviceContext       *ctx = dst_fc->device_ctx->internal->priv;
+    QSVtoOpenCLMapping    *mapping = NULL;
+    VASurfaceID va_surface;
+    cl_mem_flags cl_flags;
+    cl_event event;
+    cl_int cle;
+    int err, i;
+
+    if (src->format == AV_PIX_FMT_QSV) {
+        mfxFrameSurface1 *mfx_surface = (mfxFrameSurface1*)src->data[3];
+        va_surface = *(VASurfaceID*)mfx_surface->Data.MemId;
+    } else if (src->format == AV_PIX_FMT_VAAPI) {
+        va_surface = (VASurfaceID)(uintptr_t)src->data[3];
+    } else {
+        return AVERROR(ENOSYS);
+    }
+
+    if (flags & (AV_HWFRAME_MAP_READ | AV_HWFRAME_MAP_WRITE))
+        cl_flags = CL_MEM_READ_WRITE;
+    else if (flags & AV_HWFRAME_MAP_READ)
+        cl_flags = CL_MEM_READ_ONLY;
+    else if (flags & AV_HWFRAME_MAP_WRITE)
+        cl_flags = CL_MEM_WRITE_ONLY;
+    else
+        return AVERROR(EINVAL);
+
+    av_log(src_fc, AV_LOG_DEBUG, "Map QSV/VAAPI surface %#x to "
+           "OpenCL.\n", va_surface);
+
+    mapping = av_mallocz(sizeof(*mapping));
+    if (!mapping) {
+        err = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    // The cl_intel_va_api_media_sharing extension only supports NV12
+    // surfaces, so for now there are always exactly two planes.
+    mapping->nb_planes = 2;
+
+    for (i = 0; i < mapping->nb_planes; i++) {
+        mapping->plane[i] = ctx->clCreateFromVA_APIMediaSurfaceINTEL(
+            dst_dev->context, cl_flags, &va_surface, i, &cle);
+        if (!mapping->plane[i]) {
+            av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL "
+                   "image from plane %d of QSV/VAAPI surface "
+                   "%#x: %d.\n", i, va_surface, cle);
+            err = AVERROR(EIO);
+            goto fail;
+        }
+
+        dst->data[i]     = (uint8_t*)mapping->plane[i];
+        dst->linesize[i] = src_fc->width;
+    }
+
+    cle = ctx->clEnqueueAcquireVA_APIMediaSurfacesINTEL(
+        ctx->command_queue, mapping->nb_planes, mapping->plane,
+        0, NULL, &event);
+    if (cle != CL_SUCCESS) {
+        av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface "
+               "handle: %d.\n", cle);
+        err = AVERROR(EIO);
+        goto fail;
+    }
+
+    err = opencl_wait_events(dst_fc, &event, 1);
+    if (err < 0)
+        goto fail;
+
+    err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
+                                &opencl_unmap_from_qsv, mapping);
+    if (err < 0)
+        goto fail;
+
+    dst->width  = src->width;
+    dst->height = src->height;
+
+    return 0;
+
+fail:
+    if (mapping) {
+        for (i = 0; i < mapping->nb_planes; i++)
+            if (mapping->plane[i])
+                clReleaseMemObject(mapping->plane[i]);
+    }
+    av_freep(&mapping);
+    return err;
+}
+
+#endif
+
 
 static int opencl_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
                          const AVFrame *src, int flags)
@@ -1372,6 +1613,11 @@ static int opencl_map_to(AVHWFramesContext *hwfc, 
AVFrame *dst,
     case AV_PIX_FMT_VAAPI:
         return opencl_map_from_vaapi(hwfc, dst, src, flags);
 #endif
+#if HAVE_INTEL_OPENCL_QSV
+    case AV_PIX_FMT_QSV:
+    case AV_PIX_FMT_VAAPI:
+        return opencl_map_from_qsv(hwfc, dst, src, flags);
+#endif
     default:
         return AVERROR(ENOSYS);
     }
-- 
2.11.0

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

Reply via email to