WIP: very incomplete.  This just adds enough generic stuff to support
the mapping in the following patch.
---
 configure                      |   6 +
 libavutil/Makefile             |   2 +
 libavutil/hwcontext.c          |   3 +
 libavutil/hwcontext.h          |   1 +
 libavutil/hwcontext_internal.h |   1 +
 libavutil/hwcontext_opencl.c   | 333 +++++++++++++++++++++++++++++++++++++++++
 libavutil/hwcontext_opencl.h   |  30 ++++
 7 files changed, 376 insertions(+)
 create mode 100644 libavutil/hwcontext_opencl.c
 create mode 100644 libavutil/hwcontext_opencl.h

diff --git a/configure b/configure
index ce52f50..e601de5 100755
--- a/configure
+++ b/configure
@@ -240,6 +240,7 @@ External library support:
   --enable-nvenc   Nvidia video encoding
   --enable-omx     OpenMAX IL
   --enable-omx-rpi OpenMAX IL for Raspberry Pi
+  --enable-opencl  OpenCL processing
   --enable-vaapi   Video Acceleration API (mainly Unix/Intel)
   --enable-vda     Apple Video Decode Acceleration [auto]
   --enable-vdpau   Nvidia Video Decode and Presentation API for Unix [auto]
@@ -1228,6 +1229,7 @@ HWACCEL_LIBRARY_LIST="
     mmal
     nvenc
     omx
+    opencl
     vaapi
     vda
     vdpau
@@ -4650,6 +4652,10 @@ enabled omx               && { check_header OMX_Core.h ||
                                     add_cflags -isystem/opt/vc/include/IL ; }
                                 check_header OMX_Core.h ; } ||
                                die "ERROR: OpenMAX IL headers not found"; }
+enabled opencl            && { { check_header CL/cl.h ||
+                                 die "ERROR: OpenCL headers not found" ; } &&
+                               { check_lib CL/cl.h clGetPlatformIDs -lOpenCL ||
+                                 die "ERROR: OpenCL ICD loader not found" ; } 
; }
 enabled openssl           && { check_pkg_config openssl openssl/ssl.h 
SSL_library_init && {
                                add_cflags $openssl_cflags && add_extralibs 
$openssl_libs; }||
                                check_lib openssl/ssl.h SSL_library_init -lssl 
-lcrypto ||
diff --git a/libavutil/Makefile b/libavutil/Makefile
index b10b4d2..2d80d3b 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -111,6 +111,7 @@ OBJS = adler32.o                                            
            \

 OBJS-$(CONFIG_CUDA)                     += hwcontext_cuda.o
 OBJS-$(CONFIG_DXVA2)                    += hwcontext_dxva2.o
+OBJS-$(CONFIG_OPENCL)                   += hwcontext_opencl.o
 OBJS-$(CONFIG_LIBMFX)                   += hwcontext_qsv.o
 OBJS-$(CONFIG_LZO)                      += lzo.o
 OBJS-$(CONFIG_VAAPI)                    += hwcontext_vaapi.o
@@ -121,6 +122,7 @@ OBJS += $(COMPAT_OBJS:%=../compat/%)
 SKIPHEADERS-$(CONFIG_CUDA)             += hwcontext_cuda.h
 SKIPHEADERS-$(CONFIG_DXVA2)            += hwcontext_dxva2.h
 SKIPHEADERS-$(CONFIG_LIBMFX)           += hwcontext_qsv.h
+SKIPHEADERS-$(CONFIG_OPENCL)           += hwcontext_opencl.h
 SKIPHEADERS-$(CONFIG_VAAPI)            += hwcontext_vaapi.h
 SKIPHEADERS-$(CONFIG_VDPAU)            += hwcontext_vdpau.h
 SKIPHEADERS-$(HAVE_ATOMICS_GCC)        += atomic_gcc.h
diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c
index 5702ee1..19162aa 100644
--- a/libavutil/hwcontext.c
+++ b/libavutil/hwcontext.c
@@ -44,6 +44,9 @@ static const HWContextType *hw_table[] = {
 #if CONFIG_VDPAU
     &ff_hwcontext_type_vdpau,
 #endif
+#if CONFIG_OPENCL
+    &ff_hwcontext_type_opencl,
+#endif
     NULL,
 };

diff --git a/libavutil/hwcontext.h b/libavutil/hwcontext.h
index 4473742..6f7c8ce 100644
--- a/libavutil/hwcontext.h
+++ b/libavutil/hwcontext.h
@@ -30,6 +30,7 @@ enum AVHWDeviceType {
     AV_HWDEVICE_TYPE_VAAPI,
     AV_HWDEVICE_TYPE_DXVA2,
     AV_HWDEVICE_TYPE_QSV,
+    AV_HWDEVICE_TYPE_OPENCL,
 };

 typedef struct AVHWDeviceInternal AVHWDeviceInternal;
diff --git a/libavutil/hwcontext_internal.h b/libavutil/hwcontext_internal.h
index 6aefca6..6e6697a 100644
--- a/libavutil/hwcontext_internal.h
+++ b/libavutil/hwcontext_internal.h
@@ -106,6 +106,7 @@ struct AVHWFramesInternal {

 extern const HWContextType ff_hwcontext_type_cuda;
 extern const HWContextType ff_hwcontext_type_dxva2;
+extern const HWContextType ff_hwcontext_type_opencl;
 extern const HWContextType ff_hwcontext_type_qsv;
 extern const HWContextType ff_hwcontext_type_vaapi;
 extern const HWContextType ff_hwcontext_type_vdpau;
diff --git a/libavutil/hwcontext_opencl.c b/libavutil/hwcontext_opencl.c
new file mode 100644
index 0000000..0a68afe
--- /dev/null
+++ b/libavutil/hwcontext_opencl.c
@@ -0,0 +1,333 @@
+/*
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+
+#include "config.h"
+
+#include "avassert.h"
+#include "common.h"
+#include "hwcontext.h"
+#include "hwcontext_internal.h"
+#include "hwcontext_opencl.h"
+#include "mem.h"
+
+
+typedef struct OpenCLDeviceContext {
+} OpenCLDeviceContext;
+
+static void opencl_error_callback(const char *errinfo,
+                                  const void *private_info, size_t cb,
+                                  void *user_data)
+{
+    AVHWDeviceContext *ctx = user_data;
+    av_log(ctx, AV_LOG_ERROR, "OpenCL error: %s.", errinfo);
+}
+
+static void opencl_device_free(AVHWDeviceContext *ctx)
+{
+    AVOpenCLDeviceContext *hwctx = ctx->hwctx;
+    cl_int cle;
+
+    cle = clReleaseContext(hwctx->context);
+    if (cle != CL_SUCCESS) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to release OpenCL "
+               "context: %d.\n", cle);
+    }
+}
+
+static int opencl_device_create(AVHWDeviceContext *ctx, const char *device,
+                                AVDictionary *opts, int flags)
+{
+    cl_uint      nb_platforms;
+    cl_platform_id *platforms = NULL;
+    cl_uint      nb_devices;
+    cl_device_id   *devices = NULL;
+    AVOpenCLDeviceContext *hwctx = ctx->hwctx;
+    cl_int cle;
+    int platform_idx, device_idx;
+    int ret;
+
+    platform_idx = 0;
+    device_idx = 0;
+    if (device) {
+        platform_idx = strtol(device, NULL, 0);
+        if (strchr(device, ':'))
+            device_idx = strtol(strchr(device, ':') + 1, NULL, 0);
+    }
+
+    cle = clGetPlatformIDs(0, NULL, &nb_platforms);
+    if (cle != CL_SUCCESS) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to get number of "
+               "OpenCL platforms: %d.\n", cle);
+        ret = AVERROR(ENOSYS);
+        goto fail;
+    }
+    if (nb_platforms < platform_idx) {
+        av_log(ctx, AV_LOG_ERROR, "Platform %d not found.\n",
+               platform_idx);
+        ret = AVERROR(ENOSYS);
+        goto fail;
+    }
+    av_log(ctx, AV_LOG_VERBOSE, "%d OpenCL platforms found.\n",
+           nb_platforms);
+
+    platforms = av_malloc_array(nb_platforms, sizeof(*platforms));
+    if (!platforms) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    cle = clGetPlatformIDs(nb_platforms, platforms, NULL);
+    if (cle != CL_SUCCESS) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to get list of OpenCL "
+               "platforms: %d.\n", cle);
+        ret = AVERROR(ENOSYS);
+        goto fail;
+    }
+
+    cle = clGetDeviceIDs(platforms[platform_idx],
+                         CL_DEVICE_TYPE_DEFAULT,
+                         0, NULL, &nb_devices);
+    if (cle != CL_SUCCESS) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to get number of "
+               "devices on platform %d: %d.\n", platform_idx, cle);
+        ret = AVERROR(ENOSYS);
+        goto fail;
+    }
+    if (nb_devices < device_idx) {
+        av_log(ctx, AV_LOG_ERROR, "Device %d not found on "
+               "platform %d.\n", device_idx, platform_idx);
+        ret = AVERROR(ENODEV);
+        goto fail;
+    }
+    av_log(ctx, AV_LOG_VERBOSE, "%d OpenCL devices found on "
+           "platform %d.\n", nb_devices, platform_idx);
+
+    devices = av_malloc_array(nb_devices, sizeof(*devices));
+    if (!devices) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    cle = clGetDeviceIDs(platforms[platform_idx],
+                         CL_DEVICE_TYPE_DEFAULT,
+                         nb_devices, devices, NULL);
+    if (cle != CL_SUCCESS) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to get list of devices "
+               "on platform %d: %d.\n", platform_idx, cle);
+        ret = AVERROR(ENODEV);
+        goto fail;
+    }
+
+    hwctx->context = clCreateContext(NULL, 1, devices + device_idx,
+                                     &opencl_error_callback, ctx,
+                                     &cle);
+    if (!hwctx->context) {
+        av_log(ctx, AV_LOG_ERROR, "Failed to create OpenCL context "
+               "on platform %d device %d: %d.\n",
+               platform_idx, device_idx, cle);
+        ret = AVERROR(ENODEV);
+        goto fail;
+    }
+
+    memcpy(&hwctx->platform_id, platforms + platform_idx,
+           sizeof(*platforms));
+    memcpy(&hwctx->device_id, devices + device_idx,
+           sizeof(*devices));
+
+    ctx->free = &opencl_device_free;
+
+    ret = 0;
+fail:
+    av_freep(&platforms);
+    av_freep(&devices);
+    return ret;
+}
+
+static int opencl_device_init(AVHWDeviceContext *hwdev)
+{
+    AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
+    OpenCLDeviceContext     *ctx = hwdev->internal->priv;
+
+    return 0;
+}
+
+static void opencl_device_uninit(AVHWDeviceContext *hwdev)
+{
+}
+
+static void opencl_buffer_free(void *opaque, uint8_t *data)
+{
+    AVHWFramesContext *hwfc = opaque;
+    cl_int cle;
+
+    cle = clReleaseMemObject((cl_mem)data);
+    if (cle != CL_SUCCESS) {
+        av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer: %d.\n",
+               cle);
+    }
+}
+
+static AVBufferRef *opencl_pool_alloc(void *opaque, int size)
+{
+    AVHWFramesContext      *hwfc = opaque;
+    AVOpenCLDeviceContext *hwctx = hwfc->device_ctx->hwctx;
+    cl_int cle;
+    cl_mem mem;
+    size_t total_size;
+    int i;
+    AVBufferRef *ref;
+
+    // We allocate a buffer covering the whole image and then make
+    // sub-buffers for each plane.  This makes sure that the image is
+    // one large object so that we can share with other APIs.
+
+    // This only supports NV12 currently.
+    // TODO: make this more general by using the AVPixFmtDescriptor
+    // of hwfc->sw_format.
+
+    total_size = 0;
+    for (i = 0; i < 2; i++)
+        total_size += hwfc->width * hwfc->height / (i + 1);
+
+    mem = clCreateBuffer(hwctx->context, CL_MEM_READ_WRITE,
+                         total_size, NULL, &cle);
+    if (!mem) {
+        av_log(hwfc, AV_LOG_ERROR, "Failed to allocate buffer "
+               "(%zu bytes): %d.\n", total_size, cle);
+        return NULL;
+    }
+
+    ref = av_buffer_create((uint8_t*)mem, sizeof(cl_mem),
+                           &opencl_buffer_free, hwfc, 0);
+    if (!ref)
+        return NULL;
+
+    return ref;
+}
+
+static int opencl_frames_init(AVHWFramesContext *hwfc)
+{
+    if (!hwfc->pool) {
+        hwfc->internal->pool_internal =
+            av_buffer_pool_init2(sizeof(cl_mem), hwfc,
+                                 &opencl_pool_alloc, NULL);
+        if (!hwfc->internal->pool_internal)
+            return AVERROR(ENOMEM);
+    }
+
+    return 0;
+}
+
+static void opencl_frames_uninit(AVHWFramesContext *hwfc)
+{
+}
+
+static int opencl_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
+{
+    AVOpenCLDeviceContext *hwctx = hwfc->device_ctx->hwctx;
+    cl_mem mem, mem_plane[4], image_plane[4];
+    cl_int cle;
+    size_t offset;
+    int i;
+
+    frame->buf[2] = av_buffer_pool_get(hwfc->pool);
+    if (!frame->buf[2])
+        return AVERROR(ENOMEM);
+
+    mem = (cl_mem)frame->buf[2]->data;
+
+    offset = 0;
+    for (i = 0; i < 2; i++) {
+        cl_buffer_region region = {
+            .origin = offset,
+            .size   = (hwfc->width * hwfc->height) / (i + 1),
+        };
+        cl_image_format image_format = {
+            .image_channel_order     = i ? CL_RG : CL_R,
+            .image_channel_data_type = CL_UNSIGNED_INT8,
+        };
+        cl_image_desc image_desc = {
+            .image_type      = CL_MEM_OBJECT_IMAGE2D,
+            .image_width     = hwfc->width  / (i + 1),
+            .image_height    = hwfc->height / (i + 1),
+            .image_row_pitch = hwfc->width,
+        };
+
+        mem_plane[i] = clCreateSubBuffer(mem, CL_MEM_READ_WRITE,
+                                         CL_BUFFER_CREATE_TYPE_REGION,
+                                         &region, &cle);
+        if (!mem_plane[i]) {
+            av_log(hwfc, AV_LOG_ERROR, "Failed to create sub-buffer "
+                   "for plane %d: %d.\n", i, cle);
+            return AVERROR(EIO);
+        }
+
+        image_desc.buffer = mem_plane[i];
+
+        image_plane[i] = clCreateImage(hwctx->context,
+                                       CL_MEM_READ_WRITE,
+                                       &image_format,
+                                       &image_desc,
+                                       NULL, &cle);
+        if (!image_plane[i]) {
+            av_log(hwfc, AV_LOG_ERROR, "Failed to create image from "
+                   "plane %d sub-buffer: %d.\n", i, cle);
+            return AVERROR(EIO);
+        }
+
+        offset += region.size;
+        frame->data[i] = (uint8_t*)image_plane[i];
+        frame->linesize[i] = hwfc->width;
+
+        frame->buf[i] = av_buffer_create((uint8_t*)image_plane[i],
+                                         sizeof(cl_mem),
+                                         &opencl_buffer_free,
+                                         hwfc, 0);
+        if (!frame->buf[i])
+            return AVERROR(ENOMEM);
+    }
+
+    frame->format  = AV_PIX_FMT_OPENCL;
+    frame->width   = hwfc->width;
+    frame->height  = hwfc->height;
+
+    return 0;
+}
+
+const HWContextType ff_hwcontext_type_opencl = {
+    .type              = AV_HWDEVICE_TYPE_OPENCL,
+    .name              = "OpenCL",
+
+    .device_hwctx_size = sizeof(AVOpenCLDeviceContext),
+    .device_priv_size  = sizeof(OpenCLDeviceContext),
+
+    .device_create     = &opencl_device_create,
+    .device_init       = &opencl_device_init,
+    .device_uninit     = &opencl_device_uninit,
+
+    .frames_init       = &opencl_frames_init,
+    .frames_uninit     = &opencl_frames_uninit,
+    .frames_get_buffer = &opencl_get_buffer,
+
+    .pix_fmts = (const enum AVPixelFormat[]) {
+        AV_PIX_FMT_OPENCL,
+        AV_PIX_FMT_NONE
+    },
+};
diff --git a/libavutil/hwcontext_opencl.h b/libavutil/hwcontext_opencl.h
new file mode 100644
index 0000000..655f933
--- /dev/null
+++ b/libavutil/hwcontext_opencl.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_HWCONTEXT_OPENCL_H
+#define AVUTIL_HWCONTEXT_OPENCL_H
+
+#include <CL/cl.h>
+
+typedef struct AVOpenCLDeviceContext {
+    cl_platform_id platform_id;
+    cl_device_id   device_id;
+    cl_context     context;
+} AVOpenCLDeviceContext;
+
+#endif /* AVUTIL_HWCONTEXT_OPENCL_H */
-- 
2.8.1

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

Reply via email to