Browse code

lavu: OpenCL hwcontext implementation

Mark Thompson authored on 2017/03/05 08:57:47
Showing 9 changed files
... ...
@@ -289,7 +289,7 @@ External library support:
289 289
   --enable-mediacodec      enable Android MediaCodec support [no]
290 290
   --enable-libmysofa       enable libmysofa, needed for sofalizer filter [no]
291 291
   --enable-openal          enable OpenAL 1.1 capture support [no]
292
-  --enable-opencl          enable OpenCL code
292
+  --enable-opencl          enable OpenCL processing [no]
293 293
   --enable-opengl          enable OpenGL rendering [no]
294 294
   --enable-openssl         enable openssl, needed for https support
295 295
                            if gnutls is not used [no]
... ...
@@ -1633,7 +1633,6 @@ EXTERNAL_LIBRARY_LIST="
1633 1633
     libzvbi
1634 1634
     mediacodec
1635 1635
     openal
1636
-    opencl
1637 1636
     opengl
1638 1637
 "
1639 1638
 
... ...
@@ -1669,6 +1668,7 @@ HWACCEL_LIBRARY_LIST="
1669 1669
     libmfx
1670 1670
     mmal
1671 1671
     omx
1672
+    opencl
1672 1673
 "
1673 1674
 
1674 1675
 DOCUMENT_LIST="
... ...
@@ -15,6 +15,10 @@ libavutil:     2017-10-21
15 15
 
16 16
 API changes, most recent first:
17 17
 
18
+2017-11-xx - xxxxxxx - lavu 55.2.0 - hwcontext.h hwcontext_opencl.h
19
+  Add AV_HWDEVICE_TYPE_OPENCL and a new installed header with
20
+  OpenCL-specific hwcontext definitions.
21
+
18 22
 2017-11-xx - xxxxxxx - lavu 55.1.0 - pixfmt.h
19 23
   Add AV_PIX_FMT_OPENCL.
20 24
 
... ...
@@ -165,6 +165,7 @@ OBJS-$(CONFIG_QSV)                   += hwcontext_qsv.o
165 165
 OBJS-$(CONFIG_LIBDRM)                   += hwcontext_drm.o
166 166
 OBJS-$(CONFIG_LZO)                      += lzo.o
167 167
 OBJS-$(CONFIG_OPENCL)                   += opencl.o opencl_internal.o
168
+OBJS-$(CONFIG_OPENCL)                   += hwcontext_opencl.o
168 169
 OBJS-$(CONFIG_VAAPI)                    += hwcontext_vaapi.o
169 170
 OBJS-$(CONFIG_VIDEOTOOLBOX)             += hwcontext_videotoolbox.o
170 171
 OBJS-$(CONFIG_VDPAU)                    += hwcontext_vdpau.o
... ...
@@ -179,6 +180,7 @@ SKIPHEADERS-$(CONFIG_CUDA)             += hwcontext_cuda_internal.h
179 179
 SKIPHEADERS-$(CONFIG_D3D11VA)          += hwcontext_d3d11va.h
180 180
 SKIPHEADERS-$(CONFIG_DXVA2)            += hwcontext_dxva2.h
181 181
 SKIPHEADERS-$(CONFIG_QSV)           += hwcontext_qsv.h
182
+SKIPHEADERS-$(CONFIG_OPENCL)           += hwcontext_opencl.h
182 183
 SKIPHEADERS-$(CONFIG_VAAPI)            += hwcontext_vaapi.h
183 184
 SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX)     += hwcontext_videotoolbox.h
184 185
 SKIPHEADERS-$(CONFIG_VDPAU)            += hwcontext_vdpau.h
... ...
@@ -41,6 +41,9 @@ static const HWContextType * const hw_table[] = {
41 41
 #if CONFIG_DXVA2
42 42
     &ff_hwcontext_type_dxva2,
43 43
 #endif
44
+#if CONFIG_OPENCL
45
+    &ff_hwcontext_type_opencl,
46
+#endif
44 47
 #if CONFIG_QSV
45 48
     &ff_hwcontext_type_qsv,
46 49
 #endif
... ...
@@ -61,6 +64,7 @@ static const char *const hw_type_names[] = {
61 61
     [AV_HWDEVICE_TYPE_DRM]    = "drm",
62 62
     [AV_HWDEVICE_TYPE_DXVA2]  = "dxva2",
63 63
     [AV_HWDEVICE_TYPE_D3D11VA] = "d3d11va",
64
+    [AV_HWDEVICE_TYPE_OPENCL] = "opencl",
64 65
     [AV_HWDEVICE_TYPE_QSV]    = "qsv",
65 66
     [AV_HWDEVICE_TYPE_VAAPI]  = "vaapi",
66 67
     [AV_HWDEVICE_TYPE_VDPAU]  = "vdpau",
... ...
@@ -34,6 +34,7 @@ enum AVHWDeviceType {
34 34
     AV_HWDEVICE_TYPE_VIDEOTOOLBOX,
35 35
     AV_HWDEVICE_TYPE_D3D11VA,
36 36
     AV_HWDEVICE_TYPE_DRM,
37
+    AV_HWDEVICE_TYPE_OPENCL,
37 38
 };
38 39
 
39 40
 typedef struct AVHWDeviceInternal AVHWDeviceInternal;
... ...
@@ -161,6 +161,7 @@ extern const HWContextType ff_hwcontext_type_cuda;
161 161
 extern const HWContextType ff_hwcontext_type_d3d11va;
162 162
 extern const HWContextType ff_hwcontext_type_drm;
163 163
 extern const HWContextType ff_hwcontext_type_dxva2;
164
+extern const HWContextType ff_hwcontext_type_opencl;
164 165
 extern const HWContextType ff_hwcontext_type_qsv;
165 166
 extern const HWContextType ff_hwcontext_type_vaapi;
166 167
 extern const HWContextType ff_hwcontext_type_vdpau;
167 168
new file mode 100644
... ...
@@ -0,0 +1,1303 @@
0
+/*
1
+ * This file is part of FFmpeg.
2
+ *
3
+ * FFmpeg is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * FFmpeg is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with FFmpeg; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+#include <string.h>
19
+
20
+#include "config.h"
21
+
22
+#include "avassert.h"
23
+#include "avstring.h"
24
+#include "common.h"
25
+#include "hwcontext.h"
26
+#include "hwcontext_internal.h"
27
+#include "hwcontext_opencl.h"
28
+#include "mem.h"
29
+#include "pixdesc.h"
30
+
31
+
32
+typedef struct OpenCLDeviceContext {
33
+    // Default command queue to use for transfer/mapping operations on
34
+    // the device.  If the user supplies one, this is a reference to it.
35
+    // Otherwise, it is newly-created.
36
+    cl_command_queue command_queue;
37
+
38
+    // The platform the context exists on.  This is needed to query and
39
+    // retrieve extension functions.
40
+    cl_platform_id platform_id;
41
+
42
+    // Platform/device-specific functions.
43
+} OpenCLDeviceContext;
44
+
45
+typedef struct OpenCLFramesContext {
46
+    // Command queue used for transfer/mapping operations on this frames
47
+    // context.  If the user supplies one, this is a reference to it.
48
+    // Otherwise, it is a reference to the default command queue for the
49
+    // device.
50
+    cl_command_queue command_queue;
51
+} OpenCLFramesContext;
52
+
53
+
54
+static void opencl_error_callback(const char *errinfo,
55
+                                  const void *private_info, size_t cb,
56
+                                  void *user_data)
57
+{
58
+    AVHWDeviceContext *ctx = user_data;
59
+    av_log(ctx, AV_LOG_ERROR, "OpenCL error: %s\n", errinfo);
60
+}
61
+
62
+static void opencl_device_free(AVHWDeviceContext *hwdev)
63
+{
64
+    AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
65
+    cl_int cle;
66
+
67
+    cle = clReleaseContext(hwctx->context);
68
+    if (cle != CL_SUCCESS) {
69
+        av_log(hwdev, AV_LOG_ERROR, "Failed to release OpenCL "
70
+               "context: %d.\n", cle);
71
+    }
72
+}
73
+
74
+static struct {
75
+    const char *key;
76
+    cl_platform_info name;
77
+} opencl_platform_params[] = {
78
+    { "platform_profile",    CL_PLATFORM_PROFILE    },
79
+    { "platform_version",    CL_PLATFORM_VERSION    },
80
+    { "platform_name",       CL_PLATFORM_NAME       },
81
+    { "platform_vendor",     CL_PLATFORM_VENDOR     },
82
+    { "platform_extensions", CL_PLATFORM_EXTENSIONS },
83
+};
84
+
85
+static struct {
86
+    const char *key;
87
+    cl_device_info name;
88
+} opencl_device_params[] = {
89
+    { "device_name",         CL_DEVICE_NAME         },
90
+    { "device_vendor",       CL_DEVICE_VENDOR       },
91
+    { "driver_version",      CL_DRIVER_VERSION      },
92
+    { "device_version",      CL_DEVICE_VERSION      },
93
+    { "device_profile",      CL_DEVICE_PROFILE      },
94
+    { "device_extensions",   CL_DEVICE_EXTENSIONS   },
95
+};
96
+
97
+static struct {
98
+    const char *key;
99
+    cl_device_type type;
100
+} opencl_device_types[] = {
101
+    { "cpu",         CL_DEVICE_TYPE_CPU         },
102
+    { "gpu",         CL_DEVICE_TYPE_GPU         },
103
+    { "accelerator", CL_DEVICE_TYPE_ACCELERATOR },
104
+    { "custom",      CL_DEVICE_TYPE_CUSTOM      },
105
+    { "default",     CL_DEVICE_TYPE_DEFAULT     },
106
+    { "all",         CL_DEVICE_TYPE_ALL         },
107
+};
108
+
109
+static char *opencl_get_platform_string(cl_platform_id platform_id,
110
+                                        cl_platform_info key)
111
+{
112
+    char *str;
113
+    size_t size;
114
+    cl_int cle;
115
+    cle = clGetPlatformInfo(platform_id, key, 0, NULL, &size);
116
+    if (cle != CL_SUCCESS)
117
+        return NULL;
118
+    str = av_malloc(size);
119
+    if (!str)
120
+        return NULL;
121
+    cle = clGetPlatformInfo(platform_id, key, size, str, &size);
122
+    if (cle != CL_SUCCESS) {
123
+        av_free(str);
124
+        return NULL;
125
+    }
126
+    av_assert0(strlen(str) + 1 == size);
127
+    return str;
128
+}
129
+
130
+static char *opencl_get_device_string(cl_device_id device_id,
131
+                                      cl_device_info key)
132
+{
133
+    char *str;
134
+    size_t size;
135
+    cl_int cle;
136
+    cle = clGetDeviceInfo(device_id, key, 0, NULL, &size);
137
+    if (cle != CL_SUCCESS)
138
+        return NULL;
139
+    str = av_malloc(size);
140
+    if (!str)
141
+        return NULL;
142
+    cle = clGetDeviceInfo(device_id, key, size, str, &size);
143
+    if (cle != CL_SUCCESS) {
144
+        av_free(str);
145
+        return NULL;
146
+    }
147
+    av_assert0(strlen(str) + 1== size);
148
+    return str;
149
+}
150
+
151
+static int opencl_check_platform_extension(cl_platform_id platform_id,
152
+                                           const char *name)
153
+{
154
+    char *str;
155
+    int found = 0;
156
+    str = opencl_get_platform_string(platform_id,
157
+                                     CL_PLATFORM_EXTENSIONS);
158
+    if (str && strstr(str, name))
159
+        found = 1;
160
+    av_free(str);
161
+    return found;
162
+}
163
+
164
+static int opencl_check_device_extension(cl_device_id device_id,
165
+                                         const char *name)
166
+{
167
+    char *str;
168
+    int found = 0;
169
+    str = opencl_get_device_string(device_id,
170
+                                   CL_DEVICE_EXTENSIONS);
171
+    if (str && strstr(str, name))
172
+        found = 1;
173
+    av_free(str);
174
+    return found;
175
+}
176
+
177
+static av_unused int opencl_check_extension(AVHWDeviceContext *hwdev,
178
+                                            const char *name)
179
+{
180
+    AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
181
+    OpenCLDeviceContext    *priv = hwdev->internal->priv;
182
+
183
+    if (opencl_check_platform_extension(priv->platform_id, name)) {
184
+        av_log(hwdev, AV_LOG_DEBUG,
185
+               "%s found as platform extension.\n", name);
186
+        return 1;
187
+    }
188
+
189
+    if (opencl_check_device_extension(hwctx->device_id, name)) {
190
+        av_log(hwdev, AV_LOG_DEBUG,
191
+               "%s found as device extension.\n", name);
192
+        return 1;
193
+    }
194
+
195
+    return 0;
196
+}
197
+
198
+static int opencl_enumerate_platforms(AVHWDeviceContext *hwdev,
199
+                                      cl_uint *nb_platforms,
200
+                                      cl_platform_id **platforms,
201
+                                      void *context)
202
+{
203
+    cl_int cle;
204
+
205
+    cle = clGetPlatformIDs(0, NULL, nb_platforms);
206
+    if (cle != CL_SUCCESS) {
207
+        av_log(hwdev, AV_LOG_ERROR, "Failed to get number of "
208
+               "OpenCL platforms: %d.\n", cle);
209
+        return AVERROR(ENODEV);
210
+    }
211
+    av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL platforms found.\n",
212
+           *nb_platforms);
213
+
214
+    *platforms = av_malloc_array(*nb_platforms, sizeof(**platforms));
215
+    if (!*platforms)
216
+        return AVERROR(ENOMEM);
217
+
218
+    cle = clGetPlatformIDs(*nb_platforms, *platforms, NULL);
219
+    if (cle != CL_SUCCESS) {
220
+        av_log(hwdev, AV_LOG_ERROR, "Failed to get list of OpenCL "
221
+               "platforms: %d.\n", cle);
222
+        av_freep(platforms);
223
+        return AVERROR(ENODEV);
224
+    }
225
+
226
+    return 0;
227
+}
228
+
229
+static int opencl_filter_platform(AVHWDeviceContext *hwdev,
230
+                                  cl_platform_id platform_id,
231
+                                  const char *platform_name,
232
+                                  void *context)
233
+{
234
+    AVDictionary *opts = context;
235
+    const AVDictionaryEntry *param;
236
+    char *str;
237
+    int i, ret = 0;
238
+
239
+    for (i = 0; i < FF_ARRAY_ELEMS(opencl_platform_params); i++) {
240
+        param = av_dict_get(opts, opencl_platform_params[i].key,
241
+                            NULL, 0);
242
+        if (!param)
243
+            continue;
244
+
245
+        str = opencl_get_platform_string(platform_id,
246
+                                         opencl_platform_params[i].name);
247
+        if (!str) {
248
+            av_log(hwdev, AV_LOG_ERROR, "Failed to query %s "
249
+                   "of platform \"%s\".\n",
250
+                   opencl_platform_params[i].key, platform_name);
251
+            return AVERROR_UNKNOWN;
252
+        }
253
+        if (!av_stristr(str, param->value)) {
254
+            av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n",
255
+                   param->key, str);
256
+            ret = 1;
257
+        }
258
+        av_free(str);
259
+    }
260
+
261
+    return ret;
262
+}
263
+
264
+static int opencl_enumerate_devices(AVHWDeviceContext *hwdev,
265
+                                    cl_platform_id platform_id,
266
+                                    const char *platform_name,
267
+                                    cl_uint *nb_devices,
268
+                                    cl_device_id **devices,
269
+                                    void *context)
270
+{
271
+    cl_int cle;
272
+
273
+    cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL,
274
+                         0, NULL, nb_devices);
275
+    if (cle == CL_DEVICE_NOT_FOUND) {
276
+        av_log(hwdev, AV_LOG_DEBUG, "No devices found "
277
+               "on platform \"%s\".\n", platform_name);
278
+        *nb_devices = 0;
279
+        return 0;
280
+    } else if (cle != CL_SUCCESS) {
281
+        av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
282
+               "on platform \"%s\": %d.\n", platform_name, cle);
283
+        return AVERROR(ENODEV);
284
+    }
285
+    av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL devices found on "
286
+           "platform \"%s\".\n", *nb_devices, platform_name);
287
+
288
+    *devices = av_malloc_array(*nb_devices, sizeof(**devices));
289
+    if (!*devices)
290
+        return AVERROR(ENOMEM);
291
+
292
+    cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL,
293
+                         *nb_devices, *devices, NULL);
294
+    if (cle != CL_SUCCESS) {
295
+        av_log(hwdev, AV_LOG_ERROR, "Failed to get list of devices "
296
+               "on platform \"%s\": %d.\n", platform_name, cle);
297
+        av_freep(devices);
298
+        return AVERROR(ENODEV);
299
+    }
300
+
301
+    return 0;
302
+}
303
+
304
+static int opencl_filter_device(AVHWDeviceContext *hwdev,
305
+                                cl_device_id device_id,
306
+                                const char *device_name,
307
+                                void *context)
308
+{
309
+    AVDictionary *opts = context;
310
+    const AVDictionaryEntry *param;
311
+    char *str;
312
+    int i, ret = 0;
313
+
314
+    param = av_dict_get(opts, "device_type", NULL, 0);
315
+    if (param) {
316
+        cl_device_type match_type = 0, device_type;
317
+        cl_int cle;
318
+
319
+        for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_types); i++) {
320
+            if (!strcmp(opencl_device_types[i].key, param->value)) {
321
+                match_type = opencl_device_types[i].type;
322
+                break;
323
+            }
324
+        }
325
+        if (!match_type) {
326
+            av_log(hwdev, AV_LOG_ERROR, "Unknown device type %s.\n",
327
+                   param->value);
328
+            return AVERROR(EINVAL);
329
+        }
330
+
331
+        cle = clGetDeviceInfo(device_id, CL_DEVICE_TYPE,
332
+                              sizeof(device_type), &device_type, NULL);
333
+        if (cle != CL_SUCCESS) {
334
+            av_log(hwdev, AV_LOG_ERROR, "Failed to query device type "
335
+                   "of device \"%s\".\n", device_name);
336
+            return AVERROR_UNKNOWN;
337
+        }
338
+
339
+        if (!(device_type & match_type)) {
340
+            av_log(hwdev, AV_LOG_DEBUG, "device_type does not match.\n");
341
+            return 1;
342
+        }
343
+    }
344
+
345
+    for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_params); i++) {
346
+        param = av_dict_get(opts, opencl_device_params[i].key,
347
+                            NULL, 0);
348
+        if (!param)
349
+            continue;
350
+
351
+        str = opencl_get_device_string(device_id,
352
+                                       opencl_device_params[i].name);
353
+        if (!str) {
354
+            av_log(hwdev, AV_LOG_ERROR, "Failed to query %s "
355
+                   "of device \"%s\".\n",
356
+                   opencl_device_params[i].key, device_name);
357
+            return AVERROR_UNKNOWN;
358
+        }
359
+        if (!av_stristr(str, param->value)) {
360
+            av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n",
361
+                   param->key, str);
362
+            ret = 1;
363
+        }
364
+        av_free(str);
365
+    }
366
+
367
+    return ret;
368
+}
369
+
370
+typedef struct OpenCLDeviceSelector {
371
+    int platform_index;
372
+    int device_index;
373
+    void *context;
374
+    int (*enumerate_platforms)(AVHWDeviceContext *hwdev,
375
+                               cl_uint *nb_platforms,
376
+                               cl_platform_id **platforms,
377
+                               void *context);
378
+    int (*filter_platform)    (AVHWDeviceContext *hwdev,
379
+                               cl_platform_id platform_id,
380
+                               const char *platform_name,
381
+                               void *context);
382
+    int (*enumerate_devices)  (AVHWDeviceContext *hwdev,
383
+                               cl_platform_id platform_id,
384
+                               const char *platform_name,
385
+                               cl_uint *nb_devices,
386
+                               cl_device_id **devices,
387
+                               void *context);
388
+    int (*filter_device)      (AVHWDeviceContext *hwdev,
389
+                               cl_device_id device_id,
390
+                               const char *device_name,
391
+                               void *context);
392
+} OpenCLDeviceSelector;
393
+
394
+static int opencl_device_create_internal(AVHWDeviceContext *hwdev,
395
+                                         const OpenCLDeviceSelector *selector,
396
+                                         cl_context_properties *props)
397
+{
398
+    cl_uint      nb_platforms;
399
+    cl_platform_id *platforms = NULL;
400
+    cl_platform_id  platform_id;
401
+    cl_uint      nb_devices;
402
+    cl_device_id   *devices = NULL;
403
+    AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
404
+    cl_int cle;
405
+    cl_context_properties default_props[3];
406
+    char *platform_name_src = NULL,
407
+         *device_name_src   = NULL;
408
+    int err, found, p, d;
409
+
410
+    err = selector->enumerate_platforms(hwdev, &nb_platforms, &platforms,
411
+                                        selector->context);
412
+    if (err)
413
+        return err;
414
+
415
+    found = 0;
416
+    for (p = 0; p < nb_platforms; p++) {
417
+        const char *platform_name;
418
+
419
+        if (selector->platform_index >= 0 &&
420
+            selector->platform_index != p)
421
+            continue;
422
+
423
+        av_freep(&platform_name_src);
424
+        platform_name_src = opencl_get_platform_string(platforms[p],
425
+                                                           CL_PLATFORM_NAME);
426
+        if (platform_name_src)
427
+            platform_name = platform_name_src;
428
+        else
429
+            platform_name = "Unknown Platform";
430
+
431
+        if (selector->filter_platform) {
432
+            err = selector->filter_platform(hwdev, platforms[p],
433
+                                            platform_name,
434
+                                            selector->context);
435
+            if (err < 0)
436
+                goto fail;
437
+            if (err > 0)
438
+                continue;
439
+        }
440
+
441
+        err = opencl_enumerate_devices(hwdev, platforms[p], platform_name,
442
+                                       &nb_devices, &devices,
443
+                                       selector->context);
444
+        if (err < 0)
445
+            continue;
446
+
447
+        for (d = 0; d < nb_devices; d++) {
448
+            const char *device_name;
449
+
450
+            if (selector->device_index >= 0 &&
451
+                selector->device_index != d)
452
+                continue;
453
+
454
+            av_freep(&device_name_src);
455
+            device_name_src = opencl_get_device_string(devices[d],
456
+                                                           CL_DEVICE_NAME);
457
+            if (device_name_src)
458
+                device_name = device_name_src;
459
+            else
460
+                device_name = "Unknown Device";
461
+
462
+            if (selector->filter_device) {
463
+                err = selector->filter_device(hwdev, devices[d],
464
+                                              device_name,
465
+                                              selector->context);
466
+                if (err < 0)
467
+                    goto fail;
468
+                if (err > 0)
469
+                    continue;
470
+            }
471
+
472
+            av_log(hwdev, AV_LOG_VERBOSE, "%d.%d: %s / %s\n", p, d,
473
+                   platform_name, device_name);
474
+
475
+            ++found;
476
+            platform_id      = platforms[p];
477
+            hwctx->device_id = devices[d];
478
+        }
479
+
480
+        av_freep(&devices);
481
+    }
482
+
483
+    if (found == 0) {
484
+        av_log(hwdev, AV_LOG_ERROR, "No matching devices found.\n");
485
+        err = AVERROR(ENODEV);
486
+        goto fail;
487
+    }
488
+    if (found > 1) {
489
+        av_log(hwdev, AV_LOG_ERROR, "More than one matching device found.\n");
490
+        err = AVERROR(ENODEV);
491
+        goto fail;
492
+    }
493
+
494
+    if (!props) {
495
+        props = default_props;
496
+        default_props[0] = CL_CONTEXT_PLATFORM;
497
+        default_props[1] = (intptr_t)platform_id;
498
+        default_props[2] = 0;
499
+    } else {
500
+        if (props[0] == CL_CONTEXT_PLATFORM && props[1] == 0)
501
+            props[1] = (intptr_t)platform_id;
502
+    }
503
+
504
+    hwctx->context = clCreateContext(props, 1, &hwctx->device_id,
505
+                                     &opencl_error_callback, hwdev, &cle);
506
+    if (!hwctx->context) {
507
+        av_log(hwdev, AV_LOG_ERROR, "Failed to create OpenCL context: "
508
+               "%d.\n", cle);
509
+        err = AVERROR(ENODEV);
510
+        goto fail;
511
+    }
512
+
513
+    hwdev->free = &opencl_device_free;
514
+
515
+    err = 0;
516
+fail:
517
+    av_freep(&platform_name_src);
518
+    av_freep(&device_name_src);
519
+    av_freep(&platforms);
520
+    av_freep(&devices);
521
+    return err;
522
+}
523
+
524
+static int opencl_device_create(AVHWDeviceContext *hwdev, const char *device,
525
+                                AVDictionary *opts, int flags)
526
+{
527
+    OpenCLDeviceSelector selector = {
528
+        .context = opts,
529
+        .enumerate_platforms = &opencl_enumerate_platforms,
530
+        .filter_platform     = &opencl_filter_platform,
531
+        .enumerate_devices   = &opencl_enumerate_devices,
532
+        .filter_device       = &opencl_filter_device,
533
+    };
534
+
535
+    if (device && device[0]) {
536
+        // Match one or both indices for platform and device.
537
+        int d = -1, p = -1, ret;
538
+        if (device[0] == '.')
539
+            ret = sscanf(device, ".%d", &d);
540
+        else
541
+            ret = sscanf(device, "%d.%d", &p, &d);
542
+        if (ret < 1) {
543
+            av_log(hwdev, AV_LOG_ERROR, "Invalid OpenCL platform/device "
544
+                   "index specification \"%s\".\n", device);
545
+            return AVERROR(EINVAL);
546
+        }
547
+        selector.platform_index = p;
548
+        selector.device_index   = d;
549
+    } else {
550
+        selector.platform_index = -1;
551
+        selector.device_index   = -1;
552
+    }
553
+
554
+    return opencl_device_create_internal(hwdev, &selector, NULL);
555
+}
556
+
557
+static int opencl_device_init(AVHWDeviceContext *hwdev)
558
+{
559
+    AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
560
+    OpenCLDeviceContext    *priv = hwdev->internal->priv;
561
+    cl_int cle;
562
+
563
+    if (hwctx->command_queue) {
564
+        cle = clRetainCommandQueue(hwctx->command_queue);
565
+        if (cle != CL_SUCCESS) {
566
+            av_log(hwdev, AV_LOG_ERROR, "Failed to retain external "
567
+                   "command queue: %d.\n", cle);
568
+            return AVERROR(EIO);
569
+        }
570
+        priv->command_queue = hwctx->command_queue;
571
+    } else {
572
+        priv->command_queue = clCreateCommandQueue(hwctx->context,
573
+                                                   hwctx->device_id,
574
+                                                   0, &cle);
575
+        if (!priv->command_queue) {
576
+            av_log(hwdev, AV_LOG_ERROR, "Failed to create internal "
577
+                   "command queue: %d.\n", cle);
578
+            return AVERROR(EIO);
579
+        }
580
+    }
581
+
582
+    cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_PLATFORM,
583
+                          sizeof(priv->platform_id), &priv->platform_id,
584
+                          NULL);
585
+    if (cle != CL_SUCCESS) {
586
+        av_log(hwdev, AV_LOG_ERROR, "Failed to determine the OpenCL "
587
+               "platform containing the device.\n");
588
+        return AVERROR(EIO);
589
+    }
590
+
591
+    return 0;
592
+}
593
+
594
+static void opencl_device_uninit(AVHWDeviceContext *hwdev)
595
+{
596
+    OpenCLDeviceContext *priv = hwdev->internal->priv;
597
+    cl_int cle;
598
+
599
+    if (priv->command_queue) {
600
+        cle = clReleaseCommandQueue(priv->command_queue);
601
+        if (cle != CL_SUCCESS) {
602
+            av_log(hwdev, AV_LOG_ERROR, "Failed to release internal "
603
+                   "command queue reference: %d.\n", cle);
604
+        }
605
+    }
606
+}
607
+
608
+static int opencl_get_plane_format(enum AVPixelFormat pixfmt,
609
+                                   int plane, int width, int height,
610
+                                   cl_image_format *image_format,
611
+                                   cl_image_desc *image_desc)
612
+{
613
+    const AVPixFmtDescriptor *desc;
614
+    const AVComponentDescriptor *comp;
615
+    int channels = 0, order = 0, depth = 0, step = 0;
616
+    int wsub, hsub, alpha;
617
+    int c;
618
+
619
+    if (plane >= AV_NUM_DATA_POINTERS)
620
+        return AVERROR(ENOENT);
621
+
622
+    desc = av_pix_fmt_desc_get(pixfmt);
623
+
624
+    // Only normal images are allowed.
625
+    if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM |
626
+                       AV_PIX_FMT_FLAG_HWACCEL   |
627
+                       AV_PIX_FMT_FLAG_PAL))
628
+        return AVERROR(EINVAL);
629
+
630
+    wsub = 1 << desc->log2_chroma_w;
631
+    hsub = 1 << desc->log2_chroma_h;
632
+    // Subsampled components must be exact.
633
+    if (width & wsub - 1 || height & hsub - 1)
634
+        return AVERROR(EINVAL);
635
+
636
+    for (c = 0; c < desc->nb_components; c++) {
637
+        comp = &desc->comp[c];
638
+        if (comp->plane != plane)
639
+            continue;
640
+        // The step size must be a power of two.
641
+        if (comp->step != 1 && comp->step != 2 &&
642
+            comp->step != 4 && comp->step != 8)
643
+            return AVERROR(EINVAL);
644
+        // The bits in each component must be packed in the
645
+        // most-significant-bits of the relevant bytes.
646
+        if (comp->shift + comp->depth != 8 &&
647
+            comp->shift + comp->depth != 16)
648
+            return AVERROR(EINVAL);
649
+        // The depth must not vary between components.
650
+        if (depth && comp->depth != depth)
651
+            return AVERROR(EINVAL);
652
+        // If a single data element crosses multiple bytes then
653
+        // it must match the native endianness.
654
+        if (comp->depth > 8 &&
655
+            HAVE_BIGENDIAN == !(desc->flags & AV_PIX_FMT_FLAG_BE))
656
+            return AVERROR(EINVAL);
657
+        // A single data element must not contain multiple samples
658
+        // from the same component.
659
+        if (step && comp->step != step)
660
+            return AVERROR(EINVAL);
661
+        order = order * 10 + c + 1;
662
+        depth = comp->depth;
663
+        step  = comp->step;
664
+        alpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA &&
665
+                 c == desc->nb_components - 1);
666
+        ++channels;
667
+    }
668
+    if (channels == 0)
669
+        return AVERROR(ENOENT);
670
+
671
+    memset(image_format, 0, sizeof(*image_format));
672
+    memset(image_desc,   0, sizeof(*image_desc));
673
+    image_desc->image_type = CL_MEM_OBJECT_IMAGE2D;
674
+
675
+    if (plane == 0 || alpha) {
676
+        image_desc->image_width     = width;
677
+        image_desc->image_height    = height;
678
+        image_desc->image_row_pitch = step * width;
679
+    } else {
680
+        image_desc->image_width     = width  / wsub;
681
+        image_desc->image_height    = height / hsub;
682
+        image_desc->image_row_pitch = step * width / wsub;
683
+    }
684
+
685
+    if (depth <= 8) {
686
+        image_format->image_channel_data_type = CL_UNORM_INT8;
687
+    } else {
688
+        if (depth <= 16)
689
+            image_format->image_channel_data_type = CL_UNORM_INT16;
690
+        else
691
+            return AVERROR(EINVAL);
692
+    }
693
+
694
+#define CHANNEL_ORDER(order, type) \
695
+    case order: image_format->image_channel_order = type; break;
696
+    switch (order) {
697
+        CHANNEL_ORDER(1,    CL_R);
698
+        CHANNEL_ORDER(2,    CL_R);
699
+        CHANNEL_ORDER(3,    CL_R);
700
+        CHANNEL_ORDER(4,    CL_R);
701
+        CHANNEL_ORDER(12,   CL_RG);
702
+        CHANNEL_ORDER(23,   CL_RG);
703
+        CHANNEL_ORDER(1234, CL_RGBA);
704
+        CHANNEL_ORDER(3214, CL_BGRA);
705
+        CHANNEL_ORDER(4123, CL_ARGB);
706
+#ifdef CL_ABGR
707
+        CHANNEL_ORDER(4321, CL_ABGR);
708
+#endif
709
+    default:
710
+        return AVERROR(EINVAL);
711
+    }
712
+#undef CHANNEL_ORDER
713
+
714
+    return 0;
715
+}
716
+
717
+static int opencl_frames_get_constraints(AVHWDeviceContext *hwdev,
718
+                                         const void *hwconfig,
719
+                                         AVHWFramesConstraints *constraints)
720
+{
721
+    AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
722
+    cl_uint nb_image_formats;
723
+    cl_image_format *image_formats = NULL;
724
+    cl_int cle;
725
+    enum AVPixelFormat pix_fmt;
726
+    int err, pix_fmts_found;
727
+    size_t max_width, max_height;
728
+
729
+    cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_WIDTH,
730
+                          sizeof(max_width), &max_width, NULL);
731
+    if (cle != CL_SUCCESS) {
732
+        av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum "
733
+               "supported image width: %d.\n", cle);
734
+    } else {
735
+        constraints->max_width = max_width;
736
+    }
737
+    cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_HEIGHT,
738
+                          sizeof(max_height), &max_height, NULL);
739
+    if (cle != CL_SUCCESS) {
740
+        av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum "
741
+               "supported image height: %d.\n", cle);
742
+    } else {
743
+        constraints->max_height = max_height;
744
+    }
745
+    av_log(hwdev, AV_LOG_DEBUG, "Maximum supported image size %dx%d.\n",
746
+           constraints->max_width, constraints->max_height);
747
+
748
+    cle = clGetSupportedImageFormats(hwctx->context,
749
+                                     CL_MEM_READ_WRITE,
750
+                                     CL_MEM_OBJECT_IMAGE2D,
751
+                                     0, NULL, &nb_image_formats);
752
+    if (cle != CL_SUCCESS) {
753
+        av_log(hwdev, AV_LOG_ERROR, "Failed to query supported "
754
+               "image formats: %d.\n", cle);
755
+        err = AVERROR(ENOSYS);
756
+        goto fail;
757
+    }
758
+    if (nb_image_formats == 0) {
759
+        av_log(hwdev, AV_LOG_ERROR, "No image support in OpenCL "
760
+               "driver (zero supported image formats).\n");
761
+        err = AVERROR(ENOSYS);
762
+        goto fail;
763
+    }
764
+
765
+    image_formats =
766
+        av_malloc_array(nb_image_formats, sizeof(*image_formats));
767
+    if (!image_formats) {
768
+        err = AVERROR(ENOMEM);
769
+        goto fail;
770
+    }
771
+
772
+    cle = clGetSupportedImageFormats(hwctx->context,
773
+                                     CL_MEM_READ_WRITE,
774
+                                     CL_MEM_OBJECT_IMAGE2D,
775
+                                     nb_image_formats,
776
+                                     image_formats, NULL);
777
+    if (cle != CL_SUCCESS) {
778
+        av_log(hwdev, AV_LOG_ERROR, "Failed to query supported "
779
+               "image formats: %d.\n", cle);
780
+        err = AVERROR(ENOSYS);
781
+        goto fail;
782
+    }
783
+
784
+    pix_fmts_found = 0;
785
+    for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++) {
786
+        cl_image_format image_format;
787
+        cl_image_desc   image_desc;
788
+        int plane, i;
789
+
790
+        for (plane = 0;; plane++) {
791
+            err = opencl_get_plane_format(pix_fmt, plane, 0, 0,
792
+                                          &image_format,
793
+                                          &image_desc);
794
+            if (err < 0)
795
+                break;
796
+
797
+            for (i = 0; i < nb_image_formats; i++) {
798
+                if (image_formats[i].image_channel_order ==
799
+                    image_format.image_channel_order &&
800
+                    image_formats[i].image_channel_data_type ==
801
+                    image_format.image_channel_data_type)
802
+                    break;
803
+            }
804
+            if (i == nb_image_formats) {
805
+                err = AVERROR(EINVAL);
806
+                break;
807
+            }
808
+        }
809
+        if (err != AVERROR(ENOENT))
810
+            continue;
811
+
812
+        av_log(hwdev, AV_LOG_DEBUG, "Format %s supported.\n",
813
+               av_get_pix_fmt_name(pix_fmt));
814
+
815
+        err = av_reallocp_array(&constraints->valid_sw_formats,
816
+                                pix_fmts_found + 2,
817
+                                sizeof(*constraints->valid_sw_formats));
818
+        if (err < 0)
819
+            goto fail;
820
+        constraints->valid_sw_formats[pix_fmts_found] = pix_fmt;
821
+        constraints->valid_sw_formats[pix_fmts_found + 1] =
822
+            AV_PIX_FMT_NONE;
823
+        ++pix_fmts_found;
824
+    }
825
+
826
+    av_freep(&image_formats);
827
+
828
+    constraints->valid_hw_formats =
829
+        av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
830
+    if (!constraints->valid_hw_formats) {
831
+        err = AVERROR(ENOMEM);
832
+        goto fail;
833
+    }
834
+    constraints->valid_hw_formats[0] = AV_PIX_FMT_OPENCL;
835
+    constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
836
+
837
+    return 0;
838
+
839
+fail:
840
+    av_freep(&image_formats);
841
+    return err;
842
+}
843
+
844
+static void opencl_pool_free(void *opaque, uint8_t *data)
845
+{
846
+    AVHWFramesContext       *hwfc = opaque;
847
+    AVOpenCLFrameDescriptor *desc = (AVOpenCLFrameDescriptor*)data;
848
+    cl_int cle;
849
+    int p;
850
+
851
+    for (p = 0; p < desc->nb_planes; p++) {
852
+        cle = clReleaseMemObject(desc->planes[p]);
853
+        if (cle != CL_SUCCESS) {
854
+            av_log(hwfc, AV_LOG_ERROR, "Failed to release plane %d: "
855
+                   "%d.\n", p, cle);
856
+        }
857
+    }
858
+
859
+    av_free(desc);
860
+}
861
+
862
+static AVBufferRef *opencl_pool_alloc(void *opaque, int size)
863
+{
864
+    AVHWFramesContext      *hwfc = opaque;
865
+    AVOpenCLDeviceContext *hwctx = hwfc->device_ctx->hwctx;
866
+    AVOpenCLFrameDescriptor *desc;
867
+    cl_int cle;
868
+    cl_mem image;
869
+    cl_image_format image_format;
870
+    cl_image_desc   image_desc;
871
+    int err, p;
872
+    AVBufferRef *ref;
873
+
874
+    desc = av_mallocz(sizeof(*desc));
875
+    if (!desc)
876
+        return NULL;
877
+
878
+    for (p = 0;; p++) {
879
+        err = opencl_get_plane_format(hwfc->sw_format, p,
880
+                                      hwfc->width, hwfc->height,
881
+                                      &image_format, &image_desc);
882
+        if (err == AVERROR(ENOENT))
883
+            break;
884
+        if (err < 0)
885
+            goto fail;
886
+
887
+        // For generic image objects, the pitch is determined by the
888
+        // implementation.
889
+        image_desc.image_row_pitch = 0;
890
+
891
+        image = clCreateImage(hwctx->context, CL_MEM_READ_WRITE,
892
+                              &image_format, &image_desc, NULL, &cle);
893
+        if (!image) {
894
+            av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
895
+                   "plane %d: %d.\n", p, cle);
896
+            goto fail;
897
+        }
898
+
899
+        desc->planes[p] = image;
900
+    }
901
+
902
+    desc->nb_planes = p;
903
+
904
+    ref = av_buffer_create((uint8_t*)desc, sizeof(*desc),
905
+                           &opencl_pool_free, hwfc, 0);
906
+    if (!ref)
907
+        goto fail;
908
+
909
+    return ref;
910
+
911
+fail:
912
+    for (p = 0; desc->planes[p]; p++)
913
+        clReleaseMemObject(desc->planes[p]);
914
+    av_free(desc);
915
+    return NULL;
916
+}
917
+
918
+static int opencl_frames_init_command_queue(AVHWFramesContext *hwfc)
919
+{
920
+    AVOpenCLFramesContext *hwctx = hwfc->hwctx;
921
+    OpenCLDeviceContext *devpriv = hwfc->device_ctx->internal->priv;
922
+    OpenCLFramesContext    *priv = hwfc->internal->priv;
923
+    cl_int cle;
924
+
925
+    priv->command_queue = hwctx->command_queue ? hwctx->command_queue
926
+                                               : devpriv->command_queue;
927
+    cle = clRetainCommandQueue(priv->command_queue);
928
+    if (cle != CL_SUCCESS) {
929
+        av_log(hwfc, AV_LOG_ERROR, "Failed to retain frame "
930
+               "command queue: %d.\n", cle);
931
+        return AVERROR(EIO);
932
+    }
933
+
934
+    return 0;
935
+}
936
+
937
+static int opencl_frames_init(AVHWFramesContext *hwfc)
938
+{
939
+    if (!hwfc->pool) {
940
+        hwfc->internal->pool_internal =
941
+            av_buffer_pool_init2(sizeof(cl_mem), hwfc,
942
+                                 &opencl_pool_alloc, NULL);
943
+        if (!hwfc->internal->pool_internal)
944
+            return AVERROR(ENOMEM);
945
+    }
946
+
947
+    return opencl_frames_init_command_queue(hwfc);
948
+}
949
+
950
+static void opencl_frames_uninit(AVHWFramesContext *hwfc)
951
+{
952
+    OpenCLFramesContext *priv = hwfc->internal->priv;
953
+    cl_int cle;
954
+
955
+    cle = clReleaseCommandQueue(priv->command_queue);
956
+    if (cle != CL_SUCCESS) {
957
+        av_log(hwfc, AV_LOG_ERROR, "Failed to release frame "
958
+               "command queue: %d.\n", cle);
959
+    }
960
+}
961
+
962
+static int opencl_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
963
+{
964
+    AVOpenCLFrameDescriptor *desc;
965
+    int p;
966
+
967
+    frame->buf[0] = av_buffer_pool_get(hwfc->pool);
968
+    if (!frame->buf[0])
969
+        return AVERROR(ENOMEM);
970
+
971
+    desc = (AVOpenCLFrameDescriptor*)frame->buf[0]->data;
972
+
973
+    for (p = 0; p < desc->nb_planes; p++)
974
+        frame->data[p] = (uint8_t*)desc->planes[p];
975
+
976
+    frame->format  = AV_PIX_FMT_OPENCL;
977
+    frame->width   = hwfc->width;
978
+    frame->height  = hwfc->height;
979
+
980
+    return 0;
981
+}
982
+
983
+static int opencl_transfer_get_formats(AVHWFramesContext *hwfc,
984
+                                       enum AVHWFrameTransferDirection dir,
985
+                                       enum AVPixelFormat **formats)
986
+{
987
+    enum AVPixelFormat *fmts;
988
+
989
+    fmts = av_malloc_array(2, sizeof(*fmts));
990
+    if (!fmts)
991
+        return AVERROR(ENOMEM);
992
+
993
+    fmts[0] = hwfc->sw_format;
994
+    fmts[1] = AV_PIX_FMT_NONE;
995
+
996
+    *formats = fmts;
997
+    return 0;
998
+}
999
+
1000
+static int opencl_wait_events(AVHWFramesContext *hwfc,
1001
+                              cl_event *events, int nb_events)
1002
+{
1003
+    cl_int cle;
1004
+    int i;
1005
+
1006
+    cle = clWaitForEvents(nb_events, events);
1007
+    if (cle != CL_SUCCESS) {
1008
+        av_log(hwfc, AV_LOG_ERROR, "Failed to wait for event "
1009
+               "completion: %d.\n", cle);
1010
+        return AVERROR(EIO);
1011
+    }
1012
+
1013
+    for (i = 0; i < nb_events; i++) {
1014
+        cle = clReleaseEvent(events[i]);
1015
+        if (cle != CL_SUCCESS) {
1016
+            av_log(hwfc, AV_LOG_ERROR, "Failed to release "
1017
+                   "event: %d.\n", cle);
1018
+        }
1019
+    }
1020
+
1021
+    return 0;
1022
+}
1023
+
1024
+static int opencl_transfer_data_from(AVHWFramesContext *hwfc,
1025
+                                     AVFrame *dst, const AVFrame *src)
1026
+{
1027
+    OpenCLFramesContext *priv = hwfc->internal->priv;
1028
+    cl_image_format image_format;
1029
+    cl_image_desc image_desc;
1030
+    cl_int cle;
1031
+    size_t origin[3] = { 0, 0, 0 };
1032
+    size_t region[3];
1033
+    cl_event events[AV_NUM_DATA_POINTERS];
1034
+    int err, p;
1035
+
1036
+    if (dst->format != hwfc->sw_format)
1037
+        return AVERROR(EINVAL);
1038
+
1039
+    for (p = 0;; p++) {
1040
+        err = opencl_get_plane_format(hwfc->sw_format, p,
1041
+                                      src->width, src->height,
1042
+                                      &image_format, &image_desc);
1043
+        if (err < 0) {
1044
+            if (err == AVERROR(ENOENT))
1045
+                err = 0;
1046
+            break;
1047
+        }
1048
+
1049
+        if (!dst->data[p]) {
1050
+            av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on "
1051
+                   "destination frame for transfer.\n", p);
1052
+            err = AVERROR(EINVAL);
1053
+            break;
1054
+        }
1055
+
1056
+        region[0] = image_desc.image_width;
1057
+        region[1] = image_desc.image_height;
1058
+        region[2] = 1;
1059
+
1060
+        cle = clEnqueueReadImage(priv->command_queue,
1061
+                                 (cl_mem)src->data[p],
1062
+                                 CL_FALSE, origin, region,
1063
+                                 dst->linesize[p], 0,
1064
+                                 dst->data[p],
1065
+                                 0, NULL, &events[p]);
1066
+        if (cle != CL_SUCCESS) {
1067
+            av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue read of "
1068
+                   "OpenCL image plane %d: %d.\n", p, cle);
1069
+            err = AVERROR(EIO);
1070
+            break;
1071
+        }
1072
+    }
1073
+
1074
+    opencl_wait_events(hwfc, events, p);
1075
+
1076
+    return err;
1077
+}
1078
+
1079
+static int opencl_transfer_data_to(AVHWFramesContext *hwfc,
1080
+                                   AVFrame *dst, const AVFrame *src)
1081
+{
1082
+    OpenCLFramesContext *priv = hwfc->internal->priv;
1083
+    cl_image_format image_format;
1084
+    cl_image_desc image_desc;
1085
+    cl_int cle;
1086
+    size_t origin[3] = { 0, 0, 0 };
1087
+    size_t region[3];
1088
+    cl_event events[AV_NUM_DATA_POINTERS];
1089
+    int err, p;
1090
+
1091
+    if (src->format != hwfc->sw_format)
1092
+        return AVERROR(EINVAL);
1093
+
1094
+    for (p = 0;; p++) {
1095
+        err = opencl_get_plane_format(hwfc->sw_format, p,
1096
+                                      src->width, src->height,
1097
+                                      &image_format, &image_desc);
1098
+        if (err < 0) {
1099
+            if (err == AVERROR(ENOENT))
1100
+                err = 0;
1101
+            break;
1102
+        }
1103
+
1104
+        if (!src->data[p]) {
1105
+            av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on "
1106
+                   "source frame for transfer.\n", p);
1107
+            err = AVERROR(EINVAL);
1108
+            break;
1109
+        }
1110
+
1111
+        region[0] = image_desc.image_width;
1112
+        region[1] = image_desc.image_height;
1113
+        region[2] = 1;
1114
+
1115
+        cle = clEnqueueWriteImage(priv->command_queue,
1116
+                                  (cl_mem)dst->data[p],
1117
+                                  CL_FALSE, origin, region,
1118
+                                  src->linesize[p], 0,
1119
+                                  src->data[p],
1120
+                                  0, NULL, &events[p]);
1121
+        if (cle != CL_SUCCESS) {
1122
+            av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue write of "
1123
+                   "OpenCL image plane %d: %d.\n", p, cle);
1124
+            err = AVERROR(EIO);
1125
+            break;
1126
+        }
1127
+    }
1128
+
1129
+    opencl_wait_events(hwfc, events, p);
1130
+
1131
+    return err;
1132
+}
1133
+
1134
+typedef struct OpenCLMapping {
1135
+    // The mapped addresses for each plane.
1136
+    // The destination frame is not available when we unmap, so these
1137
+    // need to be stored separately.
1138
+    void *address[AV_NUM_DATA_POINTERS];
1139
+} OpenCLMapping;
1140
+
1141
+static void opencl_unmap_frame(AVHWFramesContext *hwfc,
1142
+                               HWMapDescriptor *hwmap)
1143
+{
1144
+    OpenCLFramesContext *priv = hwfc->internal->priv;
1145
+    OpenCLMapping *map = hwmap->priv;
1146
+    cl_event events[AV_NUM_DATA_POINTERS];
1147
+    int p, e;
1148
+    cl_int cle;
1149
+
1150
+    for (p = e = 0; p < FF_ARRAY_ELEMS(map->address); p++) {
1151
+        if (!map->address[p])
1152
+            break;
1153
+
1154
+        cle = clEnqueueUnmapMemObject(priv->command_queue,
1155
+                                      (cl_mem)hwmap->source->data[p],
1156
+                                      map->address[p],
1157
+                                      0, NULL, &events[e]);
1158
+        if (cle != CL_SUCCESS) {
1159
+            av_log(hwfc, AV_LOG_ERROR, "Failed to unmap OpenCL "
1160
+                   "image plane %d: %d.\n", p, cle);
1161
+        }
1162
+        ++e;
1163
+    }
1164
+
1165
+    opencl_wait_events(hwfc, events, e);
1166
+
1167
+    av_free(map);
1168
+}
1169
+
1170
+static int opencl_map_frame(AVHWFramesContext *hwfc, AVFrame *dst,
1171
+                            const AVFrame *src, int flags)
1172
+{
1173
+    OpenCLFramesContext *priv = hwfc->internal->priv;
1174
+    cl_map_flags map_flags;
1175
+    cl_image_format image_format;
1176
+    cl_image_desc image_desc;
1177
+    cl_int cle;
1178
+    OpenCLMapping *map;
1179
+    size_t origin[3] = { 0, 0, 0 };
1180
+    size_t region[3];
1181
+    size_t row_pitch;
1182
+    cl_event events[AV_NUM_DATA_POINTERS];
1183
+    int err, p;
1184
+
1185
+    av_assert0(hwfc->sw_format == dst->format);
1186
+
1187
+    if (flags & AV_HWFRAME_MAP_OVERWRITE &&
1188
+        !(flags & AV_HWFRAME_MAP_READ)) {
1189
+        // This is mutually exclusive with the read/write flags, so
1190
+        // there is no way to map with read here.
1191
+        map_flags = CL_MAP_WRITE_INVALIDATE_REGION;
1192
+    } else {
1193
+        map_flags = 0;
1194
+        if (flags & AV_HWFRAME_MAP_READ)
1195
+            map_flags |= CL_MAP_READ;
1196
+        if (flags & AV_HWFRAME_MAP_WRITE)
1197
+            map_flags |= CL_MAP_WRITE;
1198
+    }
1199
+
1200
+    map = av_mallocz(sizeof(*map));
1201
+    if (!map)
1202
+        return AVERROR(ENOMEM);
1203
+
1204
+    for (p = 0;; p++) {
1205
+        err = opencl_get_plane_format(hwfc->sw_format, p,
1206
+                                      src->width, src->height,
1207
+                                      &image_format, &image_desc);
1208
+        if (err == AVERROR(ENOENT))
1209
+            break;
1210
+        if (err < 0)
1211
+            goto fail;
1212
+
1213
+        region[0] = image_desc.image_width;
1214
+        region[1] = image_desc.image_height;
1215
+        region[2] = 1;
1216
+
1217
+        map->address[p] =
1218
+            clEnqueueMapImage(priv->command_queue,
1219
+                              (cl_mem)src->data[p],
1220
+                              CL_FALSE, map_flags, origin, region,
1221
+                              &row_pitch, NULL, 0, NULL,
1222
+                              &events[p], &cle);
1223
+        if (!map->address[p]) {
1224
+            av_log(hwfc, AV_LOG_ERROR, "Failed to map OpenCL "
1225
+                   "image plane %d: %d.\n", p, cle);
1226
+            err = AVERROR(EIO);
1227
+            goto fail;
1228
+        }
1229
+
1230
+        dst->data[p] = map->address[p];
1231
+
1232
+        av_log(hwfc, AV_LOG_DEBUG, "Map plane %d (%p -> %p).\n",
1233
+               p, src->data[p], dst->data[p]);
1234
+    }
1235
+
1236
+    err = opencl_wait_events(hwfc, events, p);
1237
+    if (err < 0)
1238
+        goto fail;
1239
+
1240
+    err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
1241
+                                &opencl_unmap_frame, map);
1242
+    if (err < 0)
1243
+        goto fail;
1244
+
1245
+    dst->width  = src->width;
1246
+    dst->height = src->height;
1247
+
1248
+    return 0;
1249
+
1250
+fail:
1251
+    for (p = 0; p < AV_NUM_DATA_POINTERS; p++) {
1252
+        if (!map->address[p])
1253
+            break;
1254
+        clEnqueueUnmapMemObject(priv->command_queue,
1255
+                                (cl_mem)src->data[p],
1256
+                                map->address[p],
1257
+                                0, NULL, &events[p]);
1258
+    }
1259
+    if (p > 0)
1260
+        opencl_wait_events(hwfc, events, p);
1261
+    av_freep(&map);
1262
+    return err;
1263
+}
1264
+
1265
+static int opencl_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
1266
+                           const AVFrame *src, int flags)
1267
+{
1268
+    av_assert0(src->format == AV_PIX_FMT_OPENCL);
1269
+    if (hwfc->sw_format != dst->format)
1270
+        return AVERROR(ENOSYS);
1271
+    return opencl_map_frame(hwfc, dst, src, flags);
1272
+}
1273
+
1274
+const HWContextType ff_hwcontext_type_opencl = {
1275
+    .type                   = AV_HWDEVICE_TYPE_OPENCL,
1276
+    .name                   = "OpenCL",
1277
+
1278
+    .device_hwctx_size      = sizeof(AVOpenCLDeviceContext),
1279
+    .device_priv_size       = sizeof(OpenCLDeviceContext),
1280
+    .frames_hwctx_size      = sizeof(AVOpenCLFramesContext),
1281
+    .frames_priv_size       = sizeof(OpenCLFramesContext),
1282
+
1283
+    .device_create          = &opencl_device_create,
1284
+    .device_init            = &opencl_device_init,
1285
+    .device_uninit          = &opencl_device_uninit,
1286
+
1287
+    .frames_get_constraints = &opencl_frames_get_constraints,
1288
+    .frames_init            = &opencl_frames_init,
1289
+    .frames_uninit          = &opencl_frames_uninit,
1290
+    .frames_get_buffer      = &opencl_get_buffer,
1291
+
1292
+    .transfer_get_formats   = &opencl_transfer_get_formats,
1293
+    .transfer_data_to       = &opencl_transfer_data_to,
1294
+    .transfer_data_from     = &opencl_transfer_data_from,
1295
+
1296
+    .map_from               = &opencl_map_from,
1297
+
1298
+    .pix_fmts = (const enum AVPixelFormat[]) {
1299
+        AV_PIX_FMT_OPENCL,
1300
+        AV_PIX_FMT_NONE
1301
+    },
1302
+};
0 1303
new file mode 100644
... ...
@@ -0,0 +1,96 @@
0
+/*
1
+ * This file is part of FFmpeg.
2
+ *
3
+ * FFmpeg is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * FFmpeg is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with FFmpeg; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+#ifndef AVUTIL_HWCONTEXT_OPENCL_H
19
+#define AVUTIL_HWCONTEXT_OPENCL_H
20
+
21
+#include <CL/cl.h>
22
+
23
+#include "frame.h"
24
+
25
+/**
26
+ * @file
27
+ * API-specific header for AV_HWDEVICE_TYPE_OPENCL.
28
+ *
29
+ * Pools allocated internally are always dynamic, and are primarily intended
30
+ * to be used in OpenCL-only cases.  If interoperation is required, it is
31
+ * typically required to allocate frames in the other API and then map the
32
+ * frames context to OpenCL with av_hwframe_ctx_create_derived().
33
+ */
34
+
35
+/**
36
+ * OpenCL frame descriptor for pool allocation.
37
+ *
38
+ * In user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs
39
+ * with the data pointer pointing at an object of this type describing the
40
+ * planes of the frame.
41
+ */
42
+typedef struct AVOpenCLFrameDescriptor {
43
+    /**
44
+     * Number of planes in the frame.
45
+     */
46
+    int nb_planes;
47
+    /**
48
+     * OpenCL image2d objects for each plane of the frame.
49
+     */
50
+    cl_mem planes[AV_NUM_DATA_POINTERS];
51
+} AVOpenCLFrameDescriptor;
52
+
53
+/**
54
+ * OpenCL device details.
55
+ *
56
+ * Allocated as AVHWDeviceContext.hwctx
57
+ */
58
+typedef struct AVOpenCLDeviceContext {
59
+    /**
60
+     * The primary device ID of the device.  If multiple OpenCL devices
61
+     * are associated with the context then this is the one which will
62
+     * be used for all operations internal to FFmpeg.
63
+     */
64
+    cl_device_id device_id;
65
+    /**
66
+     * The OpenCL context which will contain all operations and frames on
67
+     * this device.
68
+     */
69
+    cl_context context;
70
+    /**
71
+     * The default command queue for this device, which will be used by all
72
+     * frames contexts which do not have their own command queue.  If not
73
+     * intialised by the user, a default queue will be created on the
74
+     * primary device.
75
+     */
76
+    cl_command_queue command_queue;
77
+} AVOpenCLDeviceContext;
78
+
79
+/**
80
+ * OpenCL-specific data associated with a frame pool.
81
+ *
82
+ * Allocated as AVHWFramesContext.hwctx.
83
+ */
84
+typedef struct AVOpenCLFramesContext {
85
+    /**
86
+     * The command queue used for internal asynchronous operations on this
87
+     * device (av_hwframe_transfer_data(), av_hwframe_map()).
88
+     *
89
+     * If this is not set, the command queue from the associated device is
90
+     * used instead.
91
+     */
92
+    cl_command_queue command_queue;
93
+} AVOpenCLFramesContext;
94
+
95
+#endif /* AVUTIL_HWCONTEXT_OPENCL_H */
... ...
@@ -80,7 +80,7 @@
80 80
 
81 81
 
82 82
 #define LIBAVUTIL_VERSION_MAJOR  56
83
-#define LIBAVUTIL_VERSION_MINOR   1
83
+#define LIBAVUTIL_VERSION_MINOR   2
84 84
 #define LIBAVUTIL_VERSION_MICRO 100
85 85
 
86 86
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \