]> git.sesse.net Git - ffmpeg/blob - libavutil/hwcontext_opencl.c
hwcontext_opencl: QSV to OpenCL mapping for Intel Media SDK
[ffmpeg] / libavutil / hwcontext_opencl.c
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 #include <string.h>
20
21 #include "config.h"
22
23 #include "avassert.h"
24 #include "avstring.h"
25 #include "common.h"
26 #include "hwcontext.h"
27 #include "hwcontext_internal.h"
28 #include "hwcontext_opencl.h"
29 #include "mem.h"
30 #include "pixdesc.h"
31
32 #if HAVE_OPENCL_VAAPI_BEIGNET
33 #include <unistd.h>
34 #include <va/va.h>
35 #include <va/va_drmcommon.h>
36 #include <CL/cl_intel.h>
37 #include "hwcontext_vaapi.h"
38 #endif
39
40 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
41 #include <mfx/mfxstructures.h>
42 #include <va/va.h>
43 #include <CL/va_ext.h>
44 #include "hwcontext_vaapi.h"
45 #endif
46
47
48 typedef struct OpenCLDeviceContext {
49     // Default command queue to use for transfer/mapping operations on
50     // the device.  If the user supplies one, this is a reference to it.
51     // Otherwise, it is newly-created.
52     cl_command_queue command_queue;
53
54     // The platform the context exists on.  This is needed to query and
55     // retrieve extension functions.
56     cl_platform_id platform_id;
57
58     // Platform/device-specific functions.
59 #if HAVE_OPENCL_VAAPI_BEIGNET
60     int vaapi_mapping_usable;
61     clCreateImageFromFdINTEL_fn  clCreateImageFromFdINTEL;
62 #endif
63
64 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
65     int qsv_mapping_usable;
66     clCreateFromVA_APIMediaSurfaceINTEL_fn
67         clCreateFromVA_APIMediaSurfaceINTEL;
68     clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn
69         clEnqueueAcquireVA_APIMediaSurfacesINTEL;
70     clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn
71         clEnqueueReleaseVA_APIMediaSurfacesINTEL;
72 #endif
73 } OpenCLDeviceContext;
74
75 typedef struct OpenCLFramesContext {
76     // Command queue used for transfer/mapping operations on this frames
77     // context.  If the user supplies one, this is a reference to it.
78     // Otherwise, it is a reference to the default command queue for the
79     // device.
80     cl_command_queue command_queue;
81 } OpenCLFramesContext;
82
83
84 static void opencl_error_callback(const char *errinfo,
85                                   const void *private_info, size_t cb,
86                                   void *user_data)
87 {
88     AVHWDeviceContext *ctx = user_data;
89     av_log(ctx, AV_LOG_ERROR, "OpenCL error: %s\n", errinfo);
90 }
91
92 static void opencl_device_free(AVHWDeviceContext *hwdev)
93 {
94     AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
95     cl_int cle;
96
97     cle = clReleaseContext(hwctx->context);
98     if (cle != CL_SUCCESS) {
99         av_log(hwdev, AV_LOG_ERROR, "Failed to release OpenCL "
100                "context: %d.\n", cle);
101     }
102 }
103
104 static struct {
105     const char *key;
106     cl_platform_info name;
107 } opencl_platform_params[] = {
108     { "platform_profile",    CL_PLATFORM_PROFILE    },
109     { "platform_version",    CL_PLATFORM_VERSION    },
110     { "platform_name",       CL_PLATFORM_NAME       },
111     { "platform_vendor",     CL_PLATFORM_VENDOR     },
112     { "platform_extensions", CL_PLATFORM_EXTENSIONS },
113 };
114
115 static struct {
116     const char *key;
117     cl_device_info name;
118 } opencl_device_params[] = {
119     { "device_name",         CL_DEVICE_NAME         },
120     { "device_vendor",       CL_DEVICE_VENDOR       },
121     { "driver_version",      CL_DRIVER_VERSION      },
122     { "device_version",      CL_DEVICE_VERSION      },
123     { "device_profile",      CL_DEVICE_PROFILE      },
124     { "device_extensions",   CL_DEVICE_EXTENSIONS   },
125 };
126
127 static struct {
128     const char *key;
129     cl_device_type type;
130 } opencl_device_types[] = {
131     { "cpu",         CL_DEVICE_TYPE_CPU         },
132     { "gpu",         CL_DEVICE_TYPE_GPU         },
133     { "accelerator", CL_DEVICE_TYPE_ACCELERATOR },
134     { "custom",      CL_DEVICE_TYPE_CUSTOM      },
135     { "default",     CL_DEVICE_TYPE_DEFAULT     },
136     { "all",         CL_DEVICE_TYPE_ALL         },
137 };
138
139 static char *opencl_get_platform_string(cl_platform_id platform_id,
140                                         cl_platform_info key)
141 {
142     char *str;
143     size_t size;
144     cl_int cle;
145     cle = clGetPlatformInfo(platform_id, key, 0, NULL, &size);
146     if (cle != CL_SUCCESS)
147         return NULL;
148     str = av_malloc(size);
149     if (!str)
150         return NULL;
151     cle = clGetPlatformInfo(platform_id, key, size, str, &size);
152     if (cle != CL_SUCCESS) {
153         av_free(str);
154         return NULL;
155     }
156     av_assert0(strlen(str) + 1 == size);
157     return str;
158 }
159
160 static char *opencl_get_device_string(cl_device_id device_id,
161                                       cl_device_info key)
162 {
163     char *str;
164     size_t size;
165     cl_int cle;
166     cle = clGetDeviceInfo(device_id, key, 0, NULL, &size);
167     if (cle != CL_SUCCESS)
168         return NULL;
169     str = av_malloc(size);
170     if (!str)
171         return NULL;
172     cle = clGetDeviceInfo(device_id, key, size, str, &size);
173     if (cle != CL_SUCCESS) {
174         av_free(str);
175         return NULL;
176     }
177     av_assert0(strlen(str) + 1== size);
178     return str;
179 }
180
181 static int opencl_check_platform_extension(cl_platform_id platform_id,
182                                            const char *name)
183 {
184     char *str;
185     int found = 0;
186     str = opencl_get_platform_string(platform_id,
187                                      CL_PLATFORM_EXTENSIONS);
188     if (str && strstr(str, name))
189         found = 1;
190     av_free(str);
191     return found;
192 }
193
194 static int opencl_check_device_extension(cl_device_id device_id,
195                                          const char *name)
196 {
197     char *str;
198     int found = 0;
199     str = opencl_get_device_string(device_id,
200                                    CL_DEVICE_EXTENSIONS);
201     if (str && strstr(str, name))
202         found = 1;
203     av_free(str);
204     return found;
205 }
206
207 static av_unused int opencl_check_extension(AVHWDeviceContext *hwdev,
208                                             const char *name)
209 {
210     AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
211     OpenCLDeviceContext    *priv = hwdev->internal->priv;
212
213     if (opencl_check_platform_extension(priv->platform_id, name)) {
214         av_log(hwdev, AV_LOG_DEBUG,
215                "%s found as platform extension.\n", name);
216         return 1;
217     }
218
219     if (opencl_check_device_extension(hwctx->device_id, name)) {
220         av_log(hwdev, AV_LOG_DEBUG,
221                "%s found as device extension.\n", name);
222         return 1;
223     }
224
225     return 0;
226 }
227
228 static int opencl_enumerate_platforms(AVHWDeviceContext *hwdev,
229                                       cl_uint *nb_platforms,
230                                       cl_platform_id **platforms,
231                                       void *context)
232 {
233     cl_int cle;
234
235     cle = clGetPlatformIDs(0, NULL, nb_platforms);
236     if (cle != CL_SUCCESS) {
237         av_log(hwdev, AV_LOG_ERROR, "Failed to get number of "
238                "OpenCL platforms: %d.\n", cle);
239         return AVERROR(ENODEV);
240     }
241     av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL platforms found.\n",
242            *nb_platforms);
243
244     *platforms = av_malloc_array(*nb_platforms, sizeof(**platforms));
245     if (!*platforms)
246         return AVERROR(ENOMEM);
247
248     cle = clGetPlatformIDs(*nb_platforms, *platforms, NULL);
249     if (cle != CL_SUCCESS) {
250         av_log(hwdev, AV_LOG_ERROR, "Failed to get list of OpenCL "
251                "platforms: %d.\n", cle);
252         av_freep(platforms);
253         return AVERROR(ENODEV);
254     }
255
256     return 0;
257 }
258
259 static int opencl_filter_platform(AVHWDeviceContext *hwdev,
260                                   cl_platform_id platform_id,
261                                   const char *platform_name,
262                                   void *context)
263 {
264     AVDictionary *opts = context;
265     const AVDictionaryEntry *param;
266     char *str;
267     int i, ret = 0;
268
269     for (i = 0; i < FF_ARRAY_ELEMS(opencl_platform_params); i++) {
270         param = av_dict_get(opts, opencl_platform_params[i].key,
271                             NULL, 0);
272         if (!param)
273             continue;
274
275         str = opencl_get_platform_string(platform_id,
276                                          opencl_platform_params[i].name);
277         if (!str) {
278             av_log(hwdev, AV_LOG_ERROR, "Failed to query %s "
279                    "of platform \"%s\".\n",
280                    opencl_platform_params[i].key, platform_name);
281             return AVERROR_UNKNOWN;
282         }
283         if (!av_stristr(str, param->value)) {
284             av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n",
285                    param->key, str);
286             ret = 1;
287         }
288         av_free(str);
289     }
290
291     return ret;
292 }
293
294 static int opencl_enumerate_devices(AVHWDeviceContext *hwdev,
295                                     cl_platform_id platform_id,
296                                     const char *platform_name,
297                                     cl_uint *nb_devices,
298                                     cl_device_id **devices,
299                                     void *context)
300 {
301     cl_int cle;
302
303     cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL,
304                          0, NULL, nb_devices);
305     if (cle == CL_DEVICE_NOT_FOUND) {
306         av_log(hwdev, AV_LOG_DEBUG, "No devices found "
307                "on platform \"%s\".\n", platform_name);
308         *nb_devices = 0;
309         return 0;
310     } else if (cle != CL_SUCCESS) {
311         av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
312                "on platform \"%s\": %d.\n", platform_name, cle);
313         return AVERROR(ENODEV);
314     }
315     av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL devices found on "
316            "platform \"%s\".\n", *nb_devices, platform_name);
317
318     *devices = av_malloc_array(*nb_devices, sizeof(**devices));
319     if (!*devices)
320         return AVERROR(ENOMEM);
321
322     cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL,
323                          *nb_devices, *devices, NULL);
324     if (cle != CL_SUCCESS) {
325         av_log(hwdev, AV_LOG_ERROR, "Failed to get list of devices "
326                "on platform \"%s\": %d.\n", platform_name, cle);
327         av_freep(devices);
328         return AVERROR(ENODEV);
329     }
330
331     return 0;
332 }
333
334 static int opencl_filter_device(AVHWDeviceContext *hwdev,
335                                 cl_device_id device_id,
336                                 const char *device_name,
337                                 void *context)
338 {
339     AVDictionary *opts = context;
340     const AVDictionaryEntry *param;
341     char *str;
342     int i, ret = 0;
343
344     param = av_dict_get(opts, "device_type", NULL, 0);
345     if (param) {
346         cl_device_type match_type = 0, device_type;
347         cl_int cle;
348
349         for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_types); i++) {
350             if (!strcmp(opencl_device_types[i].key, param->value)) {
351                 match_type = opencl_device_types[i].type;
352                 break;
353             }
354         }
355         if (!match_type) {
356             av_log(hwdev, AV_LOG_ERROR, "Unknown device type %s.\n",
357                    param->value);
358             return AVERROR(EINVAL);
359         }
360
361         cle = clGetDeviceInfo(device_id, CL_DEVICE_TYPE,
362                               sizeof(device_type), &device_type, NULL);
363         if (cle != CL_SUCCESS) {
364             av_log(hwdev, AV_LOG_ERROR, "Failed to query device type "
365                    "of device \"%s\".\n", device_name);
366             return AVERROR_UNKNOWN;
367         }
368
369         if (!(device_type & match_type)) {
370             av_log(hwdev, AV_LOG_DEBUG, "device_type does not match.\n");
371             return 1;
372         }
373     }
374
375     for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_params); i++) {
376         param = av_dict_get(opts, opencl_device_params[i].key,
377                             NULL, 0);
378         if (!param)
379             continue;
380
381         str = opencl_get_device_string(device_id,
382                                        opencl_device_params[i].name);
383         if (!str) {
384             av_log(hwdev, AV_LOG_ERROR, "Failed to query %s "
385                    "of device \"%s\".\n",
386                    opencl_device_params[i].key, device_name);
387             return AVERROR_UNKNOWN;
388         }
389         if (!av_stristr(str, param->value)) {
390             av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n",
391                    param->key, str);
392             ret = 1;
393         }
394         av_free(str);
395     }
396
397     return ret;
398 }
399
400 typedef struct OpenCLDeviceSelector {
401     int platform_index;
402     int device_index;
403     void *context;
404     int (*enumerate_platforms)(AVHWDeviceContext *hwdev,
405                                cl_uint *nb_platforms,
406                                cl_platform_id **platforms,
407                                void *context);
408     int (*filter_platform)    (AVHWDeviceContext *hwdev,
409                                cl_platform_id platform_id,
410                                const char *platform_name,
411                                void *context);
412     int (*enumerate_devices)  (AVHWDeviceContext *hwdev,
413                                cl_platform_id platform_id,
414                                const char *platform_name,
415                                cl_uint *nb_devices,
416                                cl_device_id **devices,
417                                void *context);
418     int (*filter_device)      (AVHWDeviceContext *hwdev,
419                                cl_device_id device_id,
420                                const char *device_name,
421                                void *context);
422 } OpenCLDeviceSelector;
423
424 static int opencl_device_create_internal(AVHWDeviceContext *hwdev,
425                                          const OpenCLDeviceSelector *selector,
426                                          cl_context_properties *props)
427 {
428     cl_uint      nb_platforms;
429     cl_platform_id *platforms = NULL;
430     cl_platform_id  platform_id;
431     cl_uint      nb_devices;
432     cl_device_id   *devices = NULL;
433     AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
434     cl_int cle;
435     cl_context_properties default_props[3];
436     char *platform_name_src = NULL,
437          *device_name_src   = NULL;
438     int err, found, p, d;
439
440     err = selector->enumerate_platforms(hwdev, &nb_platforms, &platforms,
441                                         selector->context);
442     if (err)
443         return err;
444
445     found = 0;
446     for (p = 0; p < nb_platforms; p++) {
447         const char *platform_name;
448
449         if (selector->platform_index >= 0 &&
450             selector->platform_index != p)
451             continue;
452
453         av_freep(&platform_name_src);
454         platform_name_src = opencl_get_platform_string(platforms[p],
455                                                            CL_PLATFORM_NAME);
456         if (platform_name_src)
457             platform_name = platform_name_src;
458         else
459             platform_name = "Unknown Platform";
460
461         if (selector->filter_platform) {
462             err = selector->filter_platform(hwdev, platforms[p],
463                                             platform_name,
464                                             selector->context);
465             if (err < 0)
466                 goto fail;
467             if (err > 0)
468                 continue;
469         }
470
471         err = opencl_enumerate_devices(hwdev, platforms[p], platform_name,
472                                        &nb_devices, &devices,
473                                        selector->context);
474         if (err < 0)
475             continue;
476
477         for (d = 0; d < nb_devices; d++) {
478             const char *device_name;
479
480             if (selector->device_index >= 0 &&
481                 selector->device_index != d)
482                 continue;
483
484             av_freep(&device_name_src);
485             device_name_src = opencl_get_device_string(devices[d],
486                                                            CL_DEVICE_NAME);
487             if (device_name_src)
488                 device_name = device_name_src;
489             else
490                 device_name = "Unknown Device";
491
492             if (selector->filter_device) {
493                 err = selector->filter_device(hwdev, devices[d],
494                                               device_name,
495                                               selector->context);
496                 if (err < 0)
497                     goto fail;
498                 if (err > 0)
499                     continue;
500             }
501
502             av_log(hwdev, AV_LOG_VERBOSE, "%d.%d: %s / %s\n", p, d,
503                    platform_name, device_name);
504
505             ++found;
506             platform_id      = platforms[p];
507             hwctx->device_id = devices[d];
508         }
509
510         av_freep(&devices);
511     }
512
513     if (found == 0) {
514         av_log(hwdev, AV_LOG_ERROR, "No matching devices found.\n");
515         err = AVERROR(ENODEV);
516         goto fail;
517     }
518     if (found > 1) {
519         av_log(hwdev, AV_LOG_ERROR, "More than one matching device found.\n");
520         err = AVERROR(ENODEV);
521         goto fail;
522     }
523
524     if (!props) {
525         props = default_props;
526         default_props[0] = CL_CONTEXT_PLATFORM;
527         default_props[1] = (intptr_t)platform_id;
528         default_props[2] = 0;
529     } else {
530         if (props[0] == CL_CONTEXT_PLATFORM && props[1] == 0)
531             props[1] = (intptr_t)platform_id;
532     }
533
534     hwctx->context = clCreateContext(props, 1, &hwctx->device_id,
535                                      &opencl_error_callback, hwdev, &cle);
536     if (!hwctx->context) {
537         av_log(hwdev, AV_LOG_ERROR, "Failed to create OpenCL context: "
538                "%d.\n", cle);
539         err = AVERROR(ENODEV);
540         goto fail;
541     }
542
543     hwdev->free = &opencl_device_free;
544
545     err = 0;
546 fail:
547     av_freep(&platform_name_src);
548     av_freep(&device_name_src);
549     av_freep(&platforms);
550     av_freep(&devices);
551     return err;
552 }
553
554 static int opencl_device_create(AVHWDeviceContext *hwdev, const char *device,
555                                 AVDictionary *opts, int flags)
556 {
557     OpenCLDeviceSelector selector = {
558         .context = opts,
559         .enumerate_platforms = &opencl_enumerate_platforms,
560         .filter_platform     = &opencl_filter_platform,
561         .enumerate_devices   = &opencl_enumerate_devices,
562         .filter_device       = &opencl_filter_device,
563     };
564
565     if (device && device[0]) {
566         // Match one or both indices for platform and device.
567         int d = -1, p = -1, ret;
568         if (device[0] == '.')
569             ret = sscanf(device, ".%d", &d);
570         else
571             ret = sscanf(device, "%d.%d", &p, &d);
572         if (ret < 1) {
573             av_log(hwdev, AV_LOG_ERROR, "Invalid OpenCL platform/device "
574                    "index specification \"%s\".\n", device);
575             return AVERROR(EINVAL);
576         }
577         selector.platform_index = p;
578         selector.device_index   = d;
579     } else {
580         selector.platform_index = -1;
581         selector.device_index   = -1;
582     }
583
584     return opencl_device_create_internal(hwdev, &selector, NULL);
585 }
586
587 static int opencl_device_init(AVHWDeviceContext *hwdev)
588 {
589     AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
590     OpenCLDeviceContext    *priv = hwdev->internal->priv;
591     cl_int cle;
592
593     if (hwctx->command_queue) {
594         cle = clRetainCommandQueue(hwctx->command_queue);
595         if (cle != CL_SUCCESS) {
596             av_log(hwdev, AV_LOG_ERROR, "Failed to retain external "
597                    "command queue: %d.\n", cle);
598             return AVERROR(EIO);
599         }
600         priv->command_queue = hwctx->command_queue;
601     } else {
602         priv->command_queue = clCreateCommandQueue(hwctx->context,
603                                                    hwctx->device_id,
604                                                    0, &cle);
605         if (!priv->command_queue) {
606             av_log(hwdev, AV_LOG_ERROR, "Failed to create internal "
607                    "command queue: %d.\n", cle);
608             return AVERROR(EIO);
609         }
610     }
611
612     cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_PLATFORM,
613                           sizeof(priv->platform_id), &priv->platform_id,
614                           NULL);
615     if (cle != CL_SUCCESS) {
616         av_log(hwdev, AV_LOG_ERROR, "Failed to determine the OpenCL "
617                "platform containing the device.\n");
618         return AVERROR(EIO);
619     }
620
621 #define CL_FUNC(name, desc) do {                                \
622         if (fail)                                               \
623             break;                                              \
624         priv->name = clGetExtensionFunctionAddressForPlatform(  \
625             priv->platform_id, #name);                          \
626         if (!priv->name) {                                      \
627             av_log(hwdev, AV_LOG_VERBOSE,                       \
628                    desc " function not found (%s).\n", #name);  \
629             fail = 1;                                           \
630         } else {                                                \
631             av_log(hwdev, AV_LOG_VERBOSE,                       \
632                    desc " function found (%s).\n", #name);      \
633         }                                                       \
634     } while (0)
635
636 #if HAVE_OPENCL_VAAPI_BEIGNET
637     {
638         int fail = 0;
639
640         CL_FUNC(clCreateImageFromFdINTEL,
641                 "Intel DRM to OpenCL image mapping");
642
643         if (fail) {
644             av_log(hwdev, AV_LOG_WARNING, "VAAPI to OpenCL mapping "
645                    "not usable.\n");
646             priv->vaapi_mapping_usable = 0;
647         } else {
648             priv->vaapi_mapping_usable = 1;
649         }
650     }
651 #endif
652
653 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
654     {
655         size_t props_size;
656         cl_context_properties *props = NULL;
657         VADisplay va_display;
658         const char *va_ext = "cl_intel_va_api_media_sharing";
659         int i, fail = 0;
660
661         if (!opencl_check_extension(hwdev, va_ext)) {
662             av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
663                    "required for QSV to OpenCL mapping.\n", va_ext);
664             goto no_qsv;
665         }
666
667         cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES,
668                                0, NULL, &props_size);
669         if (cle != CL_SUCCESS) {
670             av_log(hwdev, AV_LOG_VERBOSE, "Failed to get context "
671                    "properties: %d.\n", cle);
672             goto no_qsv;
673         }
674         if (props_size == 0) {
675             av_log(hwdev, AV_LOG_VERBOSE, "Media sharing must be "
676                    "enabled on context creation to use QSV to "
677                    "OpenCL mapping.\n");
678             goto no_qsv;
679         }
680
681         props = av_malloc(props_size);
682         if (!props)
683             return AVERROR(ENOMEM);
684
685         cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES,
686                                props_size, props, NULL);
687         if (cle != CL_SUCCESS) {
688             av_log(hwdev, AV_LOG_VERBOSE, "Failed to get context "
689                    "properties: %d.\n", cle);
690             goto no_qsv;
691         }
692
693         va_display = NULL;
694         for (i = 0; i < (props_size / sizeof(*props) - 1); i++) {
695             if (props[i] == CL_CONTEXT_VA_API_DISPLAY_INTEL) {
696                 va_display = (VADisplay)(intptr_t)props[i+1];
697                 break;
698             }
699         }
700         if (!va_display) {
701             av_log(hwdev, AV_LOG_VERBOSE, "Media sharing must be "
702                    "enabled on context creation to use QSV to "
703                    "OpenCL mapping.\n");
704             goto no_qsv;
705         }
706         if (!vaDisplayIsValid(va_display)) {
707             av_log(hwdev, AV_LOG_VERBOSE, "A valid VADisplay is "
708                    "required on context creation to use QSV to "
709                    "OpenCL mapping.\n");
710             goto no_qsv;
711         }
712
713         CL_FUNC(clCreateFromVA_APIMediaSurfaceINTEL,
714                 "Intel QSV to OpenCL mapping");
715         CL_FUNC(clEnqueueAcquireVA_APIMediaSurfacesINTEL,
716                 "Intel QSV in OpenCL acquire");
717         CL_FUNC(clEnqueueReleaseVA_APIMediaSurfacesINTEL,
718                 "Intel QSV in OpenCL release");
719
720         if (fail) {
721         no_qsv:
722             av_log(hwdev, AV_LOG_WARNING, "QSV to OpenCL mapping "
723                    "not usable.\n");
724             priv->qsv_mapping_usable = 0;
725         } else {
726             priv->qsv_mapping_usable = 1;
727         }
728         av_free(props);
729     }
730 #endif
731
732 #undef CL_FUNC
733
734     return 0;
735 }
736
737 static void opencl_device_uninit(AVHWDeviceContext *hwdev)
738 {
739     OpenCLDeviceContext *priv = hwdev->internal->priv;
740     cl_int cle;
741
742     if (priv->command_queue) {
743         cle = clReleaseCommandQueue(priv->command_queue);
744         if (cle != CL_SUCCESS) {
745             av_log(hwdev, AV_LOG_ERROR, "Failed to release internal "
746                    "command queue reference: %d.\n", cle);
747         }
748     }
749 }
750
751 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
752 static int opencl_filter_intel_media_vaapi_platform(AVHWDeviceContext *hwdev,
753                                                     cl_platform_id platform_id,
754                                                     const char *platform_name,
755                                                     void *context)
756 {
757     // This doesn't exist as a platform extension, so just test whether
758     // the function we will use for device enumeration exists.
759
760     if (!clGetExtensionFunctionAddressForPlatform(platform_id,
761             "clGetDeviceIDsFromVA_APIMediaAdapterINTEL")) {
762         av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not export the "
763                "VAAPI device enumeration function.\n", platform_name);
764         return 1;
765     } else {
766         return 0;
767     }
768 }
769
770 static int opencl_enumerate_intel_media_vaapi_devices(AVHWDeviceContext *hwdev,
771                                                       cl_platform_id platform_id,
772                                                       const char *platform_name,
773                                                       cl_uint *nb_devices,
774                                                       cl_device_id **devices,
775                                                       void *context)
776 {
777     VADisplay va_display = context;
778     clGetDeviceIDsFromVA_APIMediaAdapterINTEL_fn
779         clGetDeviceIDsFromVA_APIMediaAdapterINTEL;
780     cl_int cle;
781     int err;
782
783     clGetDeviceIDsFromVA_APIMediaAdapterINTEL =
784         clGetExtensionFunctionAddressForPlatform(platform_id,
785             "clGetDeviceIDsFromVA_APIMediaAdapterINTEL");
786     if (!clGetDeviceIDsFromVA_APIMediaAdapterINTEL) {
787         av_log(hwdev, AV_LOG_ERROR, "Failed to get address of "
788                "clGetDeviceIDsFromVA_APIMediaAdapterINTEL().\n");
789         return AVERROR_UNKNOWN;
790     }
791
792     cle = clGetDeviceIDsFromVA_APIMediaAdapterINTEL(
793         platform_id, CL_VA_API_DISPLAY_INTEL, va_display,
794         CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, 0, NULL, nb_devices);
795     if (cle == CL_DEVICE_NOT_FOUND) {
796         av_log(hwdev, AV_LOG_DEBUG, "No VAAPI-supporting devices found "
797                "on platform \"%s\".\n", platform_name);
798         *nb_devices = 0;
799         return 0;
800     } else if (cle != CL_SUCCESS) {
801         av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
802                "on platform \"%s\": %d.\n", platform_name, cle);
803         return AVERROR_UNKNOWN;
804     }
805
806     *devices = av_malloc_array(*nb_devices, sizeof(**devices));
807     if (!*devices)
808         return AVERROR(ENOMEM);
809
810     cle = clGetDeviceIDsFromVA_APIMediaAdapterINTEL(
811         platform_id, CL_VA_API_DISPLAY_INTEL, va_display,
812         CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, *nb_devices, *devices, NULL);
813     if (cle != CL_SUCCESS) {
814         av_log(hwdev, AV_LOG_ERROR, "Failed to get list of VAAPI-supporting "
815                "devices on platform \"%s\": %d.\n", platform_name, cle);
816         av_freep(devices);
817         return AVERROR_UNKNOWN;
818     }
819
820     return 0;
821 }
822
823 static int opencl_filter_intel_media_vaapi_device(AVHWDeviceContext *hwdev,
824                                                   cl_device_id device_id,
825                                                   const char *device_name,
826                                                   void *context)
827 {
828     const char *va_ext = "cl_intel_va_api_media_sharing";
829
830     if (opencl_check_device_extension(device_id, va_ext)) {
831         return 0;
832     } else {
833         av_log(hwdev, AV_LOG_DEBUG, "Device %s does not support the "
834                "%s extension.\n", device_name, va_ext);
835         return 1;
836     }
837 }
838 #endif
839
840 static int opencl_device_derive(AVHWDeviceContext *hwdev,
841                                 AVHWDeviceContext *src_ctx,
842                                 int flags)
843 {
844     int err;
845     switch (src_ctx->type) {
846
847 #if HAVE_OPENCL_VAAPI_BEIGNET
848     case AV_HWDEVICE_TYPE_VAAPI:
849         {
850             // Surface mapping works via DRM PRIME fds with no special
851             // initialisation required in advance.  This just finds the
852             // Beignet ICD by name.
853             AVDictionary *opts = NULL;
854
855             err = av_dict_set(&opts, "platform_vendor", "Intel", 0);
856             if (err >= 0)
857                 err = av_dict_set(&opts, "platform_version", "beignet", 0);
858             if (err >= 0) {
859                 OpenCLDeviceSelector selector = {
860                     .platform_index      = -1,
861                     .device_index        = 0,
862                     .context             = opts,
863                     .enumerate_platforms = &opencl_enumerate_platforms,
864                     .filter_platform     = &opencl_filter_platform,
865                     .enumerate_devices   = &opencl_enumerate_devices,
866                     .filter_device       = NULL,
867                 };
868                 err = opencl_device_create_internal(hwdev, &selector, NULL);
869             }
870             av_dict_free(&opts);
871         }
872         break;
873 #endif
874
875 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
876         // The generic code automatically attempts to derive from all
877         // ancestors of the given device, so we can ignore QSV devices here
878         // and just consider the inner VAAPI device it was derived from.
879     case AV_HWDEVICE_TYPE_VAAPI:
880         {
881             AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx;
882             cl_context_properties props[7] = {
883                 CL_CONTEXT_PLATFORM,
884                 0,
885                 CL_CONTEXT_VA_API_DISPLAY_INTEL,
886                 (intptr_t)src_hwctx->display,
887                 CL_CONTEXT_INTEROP_USER_SYNC,
888                 CL_FALSE,
889                 0,
890             };
891             OpenCLDeviceSelector selector = {
892                 .platform_index      = -1,
893                 .device_index        = -1,
894                 .context             = src_hwctx->display,
895                 .enumerate_platforms = &opencl_enumerate_platforms,
896                 .filter_platform     = &opencl_filter_intel_media_vaapi_platform,
897                 .enumerate_devices   = &opencl_enumerate_intel_media_vaapi_devices,
898                 .filter_device       = &opencl_filter_intel_media_vaapi_device,
899             };
900
901             err = opencl_device_create_internal(hwdev, &selector, props);
902         }
903         break;
904 #endif
905
906     default:
907         err = AVERROR(ENOSYS);
908         break;
909     }
910
911     if (err < 0)
912         return err;
913
914     return opencl_device_init(hwdev);
915 }
916
917 static int opencl_get_plane_format(enum AVPixelFormat pixfmt,
918                                    int plane, int width, int height,
919                                    cl_image_format *image_format,
920                                    cl_image_desc *image_desc)
921 {
922     const AVPixFmtDescriptor *desc;
923     const AVComponentDescriptor *comp;
924     int channels = 0, order = 0, depth = 0, step = 0;
925     int wsub, hsub, alpha;
926     int c;
927
928     if (plane >= AV_NUM_DATA_POINTERS)
929         return AVERROR(ENOENT);
930
931     desc = av_pix_fmt_desc_get(pixfmt);
932
933     // Only normal images are allowed.
934     if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM |
935                        AV_PIX_FMT_FLAG_HWACCEL   |
936                        AV_PIX_FMT_FLAG_PAL))
937         return AVERROR(EINVAL);
938
939     wsub = 1 << desc->log2_chroma_w;
940     hsub = 1 << desc->log2_chroma_h;
941     // Subsampled components must be exact.
942     if (width & wsub - 1 || height & hsub - 1)
943         return AVERROR(EINVAL);
944
945     for (c = 0; c < desc->nb_components; c++) {
946         comp = &desc->comp[c];
947         if (comp->plane != plane)
948             continue;
949         // The step size must be a power of two.
950         if (comp->step != 1 && comp->step != 2 &&
951             comp->step != 4 && comp->step != 8)
952             return AVERROR(EINVAL);
953         // The bits in each component must be packed in the
954         // most-significant-bits of the relevant bytes.
955         if (comp->shift + comp->depth != 8 &&
956             comp->shift + comp->depth != 16)
957             return AVERROR(EINVAL);
958         // The depth must not vary between components.
959         if (depth && comp->depth != depth)
960             return AVERROR(EINVAL);
961         // If a single data element crosses multiple bytes then
962         // it must match the native endianness.
963         if (comp->depth > 8 &&
964             HAVE_BIGENDIAN == !(desc->flags & AV_PIX_FMT_FLAG_BE))
965             return AVERROR(EINVAL);
966         // A single data element must not contain multiple samples
967         // from the same component.
968         if (step && comp->step != step)
969             return AVERROR(EINVAL);
970         order = order * 10 + c + 1;
971         depth = comp->depth;
972         step  = comp->step;
973         alpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA &&
974                  c == desc->nb_components - 1);
975         ++channels;
976     }
977     if (channels == 0)
978         return AVERROR(ENOENT);
979
980     memset(image_format, 0, sizeof(*image_format));
981     memset(image_desc,   0, sizeof(*image_desc));
982     image_desc->image_type = CL_MEM_OBJECT_IMAGE2D;
983
984     if (plane == 0 || alpha) {
985         image_desc->image_width     = width;
986         image_desc->image_height    = height;
987         image_desc->image_row_pitch = step * width;
988     } else {
989         image_desc->image_width     = width  / wsub;
990         image_desc->image_height    = height / hsub;
991         image_desc->image_row_pitch = step * width / wsub;
992     }
993
994     if (depth <= 8) {
995         image_format->image_channel_data_type = CL_UNORM_INT8;
996     } else {
997         if (depth <= 16)
998             image_format->image_channel_data_type = CL_UNORM_INT16;
999         else
1000             return AVERROR(EINVAL);
1001     }
1002
1003 #define CHANNEL_ORDER(order, type) \
1004     case order: image_format->image_channel_order = type; break;
1005     switch (order) {
1006         CHANNEL_ORDER(1,    CL_R);
1007         CHANNEL_ORDER(2,    CL_R);
1008         CHANNEL_ORDER(3,    CL_R);
1009         CHANNEL_ORDER(4,    CL_R);
1010         CHANNEL_ORDER(12,   CL_RG);
1011         CHANNEL_ORDER(23,   CL_RG);
1012         CHANNEL_ORDER(1234, CL_RGBA);
1013         CHANNEL_ORDER(3214, CL_BGRA);
1014         CHANNEL_ORDER(4123, CL_ARGB);
1015 #ifdef CL_ABGR
1016         CHANNEL_ORDER(4321, CL_ABGR);
1017 #endif
1018     default:
1019         return AVERROR(EINVAL);
1020     }
1021 #undef CHANNEL_ORDER
1022
1023     return 0;
1024 }
1025
1026 static int opencl_frames_get_constraints(AVHWDeviceContext *hwdev,
1027                                          const void *hwconfig,
1028                                          AVHWFramesConstraints *constraints)
1029 {
1030     AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
1031     cl_uint nb_image_formats;
1032     cl_image_format *image_formats = NULL;
1033     cl_int cle;
1034     enum AVPixelFormat pix_fmt;
1035     int err, pix_fmts_found;
1036     size_t max_width, max_height;
1037
1038     cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_WIDTH,
1039                           sizeof(max_width), &max_width, NULL);
1040     if (cle != CL_SUCCESS) {
1041         av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum "
1042                "supported image width: %d.\n", cle);
1043     } else {
1044         constraints->max_width = max_width;
1045     }
1046     cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_HEIGHT,
1047                           sizeof(max_height), &max_height, NULL);
1048     if (cle != CL_SUCCESS) {
1049         av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum "
1050                "supported image height: %d.\n", cle);
1051     } else {
1052         constraints->max_height = max_height;
1053     }
1054     av_log(hwdev, AV_LOG_DEBUG, "Maximum supported image size %dx%d.\n",
1055            constraints->max_width, constraints->max_height);
1056
1057     cle = clGetSupportedImageFormats(hwctx->context,
1058                                      CL_MEM_READ_WRITE,
1059                                      CL_MEM_OBJECT_IMAGE2D,
1060                                      0, NULL, &nb_image_formats);
1061     if (cle != CL_SUCCESS) {
1062         av_log(hwdev, AV_LOG_ERROR, "Failed to query supported "
1063                "image formats: %d.\n", cle);
1064         err = AVERROR(ENOSYS);
1065         goto fail;
1066     }
1067     if (nb_image_formats == 0) {
1068         av_log(hwdev, AV_LOG_ERROR, "No image support in OpenCL "
1069                "driver (zero supported image formats).\n");
1070         err = AVERROR(ENOSYS);
1071         goto fail;
1072     }
1073
1074     image_formats =
1075         av_malloc_array(nb_image_formats, sizeof(*image_formats));
1076     if (!image_formats) {
1077         err = AVERROR(ENOMEM);
1078         goto fail;
1079     }
1080
1081     cle = clGetSupportedImageFormats(hwctx->context,
1082                                      CL_MEM_READ_WRITE,
1083                                      CL_MEM_OBJECT_IMAGE2D,
1084                                      nb_image_formats,
1085                                      image_formats, NULL);
1086     if (cle != CL_SUCCESS) {
1087         av_log(hwdev, AV_LOG_ERROR, "Failed to query supported "
1088                "image formats: %d.\n", cle);
1089         err = AVERROR(ENOSYS);
1090         goto fail;
1091     }
1092
1093     pix_fmts_found = 0;
1094     for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++) {
1095         cl_image_format image_format;
1096         cl_image_desc   image_desc;
1097         int plane, i;
1098
1099         for (plane = 0;; plane++) {
1100             err = opencl_get_plane_format(pix_fmt, plane, 0, 0,
1101                                           &image_format,
1102                                           &image_desc);
1103             if (err < 0)
1104                 break;
1105
1106             for (i = 0; i < nb_image_formats; i++) {
1107                 if (image_formats[i].image_channel_order ==
1108                     image_format.image_channel_order &&
1109                     image_formats[i].image_channel_data_type ==
1110                     image_format.image_channel_data_type)
1111                     break;
1112             }
1113             if (i == nb_image_formats) {
1114                 err = AVERROR(EINVAL);
1115                 break;
1116             }
1117         }
1118         if (err != AVERROR(ENOENT))
1119             continue;
1120
1121         av_log(hwdev, AV_LOG_DEBUG, "Format %s supported.\n",
1122                av_get_pix_fmt_name(pix_fmt));
1123
1124         err = av_reallocp_array(&constraints->valid_sw_formats,
1125                                 pix_fmts_found + 2,
1126                                 sizeof(*constraints->valid_sw_formats));
1127         if (err < 0)
1128             goto fail;
1129         constraints->valid_sw_formats[pix_fmts_found] = pix_fmt;
1130         constraints->valid_sw_formats[pix_fmts_found + 1] =
1131             AV_PIX_FMT_NONE;
1132         ++pix_fmts_found;
1133     }
1134
1135     av_freep(&image_formats);
1136
1137     constraints->valid_hw_formats =
1138         av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
1139     if (!constraints->valid_hw_formats) {
1140         err = AVERROR(ENOMEM);
1141         goto fail;
1142     }
1143     constraints->valid_hw_formats[0] = AV_PIX_FMT_OPENCL;
1144     constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
1145
1146     return 0;
1147
1148 fail:
1149     av_freep(&image_formats);
1150     return err;
1151 }
1152
1153 static void opencl_pool_free(void *opaque, uint8_t *data)
1154 {
1155     AVHWFramesContext       *hwfc = opaque;
1156     AVOpenCLFrameDescriptor *desc = (AVOpenCLFrameDescriptor*)data;
1157     cl_int cle;
1158     int p;
1159
1160     for (p = 0; p < desc->nb_planes; p++) {
1161         cle = clReleaseMemObject(desc->planes[p]);
1162         if (cle != CL_SUCCESS) {
1163             av_log(hwfc, AV_LOG_ERROR, "Failed to release plane %d: "
1164                    "%d.\n", p, cle);
1165         }
1166     }
1167
1168     av_free(desc);
1169 }
1170
1171 static AVBufferRef *opencl_pool_alloc(void *opaque, int size)
1172 {
1173     AVHWFramesContext      *hwfc = opaque;
1174     AVOpenCLDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1175     AVOpenCLFrameDescriptor *desc;
1176     cl_int cle;
1177     cl_mem image;
1178     cl_image_format image_format;
1179     cl_image_desc   image_desc;
1180     int err, p;
1181     AVBufferRef *ref;
1182
1183     desc = av_mallocz(sizeof(*desc));
1184     if (!desc)
1185         return NULL;
1186
1187     for (p = 0;; p++) {
1188         err = opencl_get_plane_format(hwfc->sw_format, p,
1189                                       hwfc->width, hwfc->height,
1190                                       &image_format, &image_desc);
1191         if (err == AVERROR(ENOENT))
1192             break;
1193         if (err < 0)
1194             goto fail;
1195
1196         // For generic image objects, the pitch is determined by the
1197         // implementation.
1198         image_desc.image_row_pitch = 0;
1199
1200         image = clCreateImage(hwctx->context, CL_MEM_READ_WRITE,
1201                               &image_format, &image_desc, NULL, &cle);
1202         if (!image) {
1203             av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
1204                    "plane %d: %d.\n", p, cle);
1205             goto fail;
1206         }
1207
1208         desc->planes[p] = image;
1209     }
1210
1211     desc->nb_planes = p;
1212
1213     ref = av_buffer_create((uint8_t*)desc, sizeof(*desc),
1214                            &opencl_pool_free, hwfc, 0);
1215     if (!ref)
1216         goto fail;
1217
1218     return ref;
1219
1220 fail:
1221     for (p = 0; desc->planes[p]; p++)
1222         clReleaseMemObject(desc->planes[p]);
1223     av_free(desc);
1224     return NULL;
1225 }
1226
1227 static int opencl_frames_init_command_queue(AVHWFramesContext *hwfc)
1228 {
1229     AVOpenCLFramesContext *hwctx = hwfc->hwctx;
1230     OpenCLDeviceContext *devpriv = hwfc->device_ctx->internal->priv;
1231     OpenCLFramesContext    *priv = hwfc->internal->priv;
1232     cl_int cle;
1233
1234     priv->command_queue = hwctx->command_queue ? hwctx->command_queue
1235                                                : devpriv->command_queue;
1236     cle = clRetainCommandQueue(priv->command_queue);
1237     if (cle != CL_SUCCESS) {
1238         av_log(hwfc, AV_LOG_ERROR, "Failed to retain frame "
1239                "command queue: %d.\n", cle);
1240         return AVERROR(EIO);
1241     }
1242
1243     return 0;
1244 }
1245
1246 static int opencl_frames_init(AVHWFramesContext *hwfc)
1247 {
1248     if (!hwfc->pool) {
1249         hwfc->internal->pool_internal =
1250             av_buffer_pool_init2(sizeof(cl_mem), hwfc,
1251                                  &opencl_pool_alloc, NULL);
1252         if (!hwfc->internal->pool_internal)
1253             return AVERROR(ENOMEM);
1254     }
1255
1256     return opencl_frames_init_command_queue(hwfc);
1257 }
1258
1259 static void opencl_frames_uninit(AVHWFramesContext *hwfc)
1260 {
1261     OpenCLFramesContext *priv = hwfc->internal->priv;
1262     cl_int cle;
1263
1264     cle = clReleaseCommandQueue(priv->command_queue);
1265     if (cle != CL_SUCCESS) {
1266         av_log(hwfc, AV_LOG_ERROR, "Failed to release frame "
1267                "command queue: %d.\n", cle);
1268     }
1269 }
1270
1271 static int opencl_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
1272 {
1273     AVOpenCLFrameDescriptor *desc;
1274     int p;
1275
1276     frame->buf[0] = av_buffer_pool_get(hwfc->pool);
1277     if (!frame->buf[0])
1278         return AVERROR(ENOMEM);
1279
1280     desc = (AVOpenCLFrameDescriptor*)frame->buf[0]->data;
1281
1282     for (p = 0; p < desc->nb_planes; p++)
1283         frame->data[p] = (uint8_t*)desc->planes[p];
1284
1285     frame->format  = AV_PIX_FMT_OPENCL;
1286     frame->width   = hwfc->width;
1287     frame->height  = hwfc->height;
1288
1289     return 0;
1290 }
1291
1292 static int opencl_transfer_get_formats(AVHWFramesContext *hwfc,
1293                                        enum AVHWFrameTransferDirection dir,
1294                                        enum AVPixelFormat **formats)
1295 {
1296     enum AVPixelFormat *fmts;
1297
1298     fmts = av_malloc_array(2, sizeof(*fmts));
1299     if (!fmts)
1300         return AVERROR(ENOMEM);
1301
1302     fmts[0] = hwfc->sw_format;
1303     fmts[1] = AV_PIX_FMT_NONE;
1304
1305     *formats = fmts;
1306     return 0;
1307 }
1308
1309 static int opencl_wait_events(AVHWFramesContext *hwfc,
1310                               cl_event *events, int nb_events)
1311 {
1312     cl_int cle;
1313     int i;
1314
1315     cle = clWaitForEvents(nb_events, events);
1316     if (cle != CL_SUCCESS) {
1317         av_log(hwfc, AV_LOG_ERROR, "Failed to wait for event "
1318                "completion: %d.\n", cle);
1319         return AVERROR(EIO);
1320     }
1321
1322     for (i = 0; i < nb_events; i++) {
1323         cle = clReleaseEvent(events[i]);
1324         if (cle != CL_SUCCESS) {
1325             av_log(hwfc, AV_LOG_ERROR, "Failed to release "
1326                    "event: %d.\n", cle);
1327         }
1328     }
1329
1330     return 0;
1331 }
1332
1333 static int opencl_transfer_data_from(AVHWFramesContext *hwfc,
1334                                      AVFrame *dst, const AVFrame *src)
1335 {
1336     OpenCLFramesContext *priv = hwfc->internal->priv;
1337     cl_image_format image_format;
1338     cl_image_desc image_desc;
1339     cl_int cle;
1340     size_t origin[3] = { 0, 0, 0 };
1341     size_t region[3];
1342     cl_event events[AV_NUM_DATA_POINTERS];
1343     int err, p;
1344
1345     if (dst->format != hwfc->sw_format)
1346         return AVERROR(EINVAL);
1347
1348     for (p = 0;; p++) {
1349         err = opencl_get_plane_format(hwfc->sw_format, p,
1350                                       src->width, src->height,
1351                                       &image_format, &image_desc);
1352         if (err < 0) {
1353             if (err == AVERROR(ENOENT))
1354                 err = 0;
1355             break;
1356         }
1357
1358         if (!dst->data[p]) {
1359             av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on "
1360                    "destination frame for transfer.\n", p);
1361             err = AVERROR(EINVAL);
1362             break;
1363         }
1364
1365         region[0] = image_desc.image_width;
1366         region[1] = image_desc.image_height;
1367         region[2] = 1;
1368
1369         cle = clEnqueueReadImage(priv->command_queue,
1370                                  (cl_mem)src->data[p],
1371                                  CL_FALSE, origin, region,
1372                                  dst->linesize[p], 0,
1373                                  dst->data[p],
1374                                  0, NULL, &events[p]);
1375         if (cle != CL_SUCCESS) {
1376             av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue read of "
1377                    "OpenCL image plane %d: %d.\n", p, cle);
1378             err = AVERROR(EIO);
1379             break;
1380         }
1381     }
1382
1383     opencl_wait_events(hwfc, events, p);
1384
1385     return err;
1386 }
1387
1388 static int opencl_transfer_data_to(AVHWFramesContext *hwfc,
1389                                    AVFrame *dst, const AVFrame *src)
1390 {
1391     OpenCLFramesContext *priv = hwfc->internal->priv;
1392     cl_image_format image_format;
1393     cl_image_desc image_desc;
1394     cl_int cle;
1395     size_t origin[3] = { 0, 0, 0 };
1396     size_t region[3];
1397     cl_event events[AV_NUM_DATA_POINTERS];
1398     int err, p;
1399
1400     if (src->format != hwfc->sw_format)
1401         return AVERROR(EINVAL);
1402
1403     for (p = 0;; p++) {
1404         err = opencl_get_plane_format(hwfc->sw_format, p,
1405                                       src->width, src->height,
1406                                       &image_format, &image_desc);
1407         if (err < 0) {
1408             if (err == AVERROR(ENOENT))
1409                 err = 0;
1410             break;
1411         }
1412
1413         if (!src->data[p]) {
1414             av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on "
1415                    "source frame for transfer.\n", p);
1416             err = AVERROR(EINVAL);
1417             break;
1418         }
1419
1420         region[0] = image_desc.image_width;
1421         region[1] = image_desc.image_height;
1422         region[2] = 1;
1423
1424         cle = clEnqueueWriteImage(priv->command_queue,
1425                                   (cl_mem)dst->data[p],
1426                                   CL_FALSE, origin, region,
1427                                   src->linesize[p], 0,
1428                                   src->data[p],
1429                                   0, NULL, &events[p]);
1430         if (cle != CL_SUCCESS) {
1431             av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue write of "
1432                    "OpenCL image plane %d: %d.\n", p, cle);
1433             err = AVERROR(EIO);
1434             break;
1435         }
1436     }
1437
1438     opencl_wait_events(hwfc, events, p);
1439
1440     return err;
1441 }
1442
1443 typedef struct OpenCLMapping {
1444     // The mapped addresses for each plane.
1445     // The destination frame is not available when we unmap, so these
1446     // need to be stored separately.
1447     void *address[AV_NUM_DATA_POINTERS];
1448 } OpenCLMapping;
1449
1450 static void opencl_unmap_frame(AVHWFramesContext *hwfc,
1451                                HWMapDescriptor *hwmap)
1452 {
1453     OpenCLFramesContext *priv = hwfc->internal->priv;
1454     OpenCLMapping *map = hwmap->priv;
1455     cl_event events[AV_NUM_DATA_POINTERS];
1456     int p, e;
1457     cl_int cle;
1458
1459     for (p = e = 0; p < FF_ARRAY_ELEMS(map->address); p++) {
1460         if (!map->address[p])
1461             break;
1462
1463         cle = clEnqueueUnmapMemObject(priv->command_queue,
1464                                       (cl_mem)hwmap->source->data[p],
1465                                       map->address[p],
1466                                       0, NULL, &events[e]);
1467         if (cle != CL_SUCCESS) {
1468             av_log(hwfc, AV_LOG_ERROR, "Failed to unmap OpenCL "
1469                    "image plane %d: %d.\n", p, cle);
1470         }
1471         ++e;
1472     }
1473
1474     opencl_wait_events(hwfc, events, e);
1475
1476     av_free(map);
1477 }
1478
1479 static int opencl_map_frame(AVHWFramesContext *hwfc, AVFrame *dst,
1480                             const AVFrame *src, int flags)
1481 {
1482     OpenCLFramesContext *priv = hwfc->internal->priv;
1483     cl_map_flags map_flags;
1484     cl_image_format image_format;
1485     cl_image_desc image_desc;
1486     cl_int cle;
1487     OpenCLMapping *map;
1488     size_t origin[3] = { 0, 0, 0 };
1489     size_t region[3];
1490     size_t row_pitch;
1491     cl_event events[AV_NUM_DATA_POINTERS];
1492     int err, p;
1493
1494     av_assert0(hwfc->sw_format == dst->format);
1495
1496     if (flags & AV_HWFRAME_MAP_OVERWRITE &&
1497         !(flags & AV_HWFRAME_MAP_READ)) {
1498         // This is mutually exclusive with the read/write flags, so
1499         // there is no way to map with read here.
1500         map_flags = CL_MAP_WRITE_INVALIDATE_REGION;
1501     } else {
1502         map_flags = 0;
1503         if (flags & AV_HWFRAME_MAP_READ)
1504             map_flags |= CL_MAP_READ;
1505         if (flags & AV_HWFRAME_MAP_WRITE)
1506             map_flags |= CL_MAP_WRITE;
1507     }
1508
1509     map = av_mallocz(sizeof(*map));
1510     if (!map)
1511         return AVERROR(ENOMEM);
1512
1513     for (p = 0;; p++) {
1514         err = opencl_get_plane_format(hwfc->sw_format, p,
1515                                       src->width, src->height,
1516                                       &image_format, &image_desc);
1517         if (err == AVERROR(ENOENT))
1518             break;
1519         if (err < 0)
1520             goto fail;
1521
1522         region[0] = image_desc.image_width;
1523         region[1] = image_desc.image_height;
1524         region[2] = 1;
1525
1526         map->address[p] =
1527             clEnqueueMapImage(priv->command_queue,
1528                               (cl_mem)src->data[p],
1529                               CL_FALSE, map_flags, origin, region,
1530                               &row_pitch, NULL, 0, NULL,
1531                               &events[p], &cle);
1532         if (!map->address[p]) {
1533             av_log(hwfc, AV_LOG_ERROR, "Failed to map OpenCL "
1534                    "image plane %d: %d.\n", p, cle);
1535             err = AVERROR(EIO);
1536             goto fail;
1537         }
1538
1539         dst->data[p] = map->address[p];
1540
1541         av_log(hwfc, AV_LOG_DEBUG, "Map plane %d (%p -> %p).\n",
1542                p, src->data[p], dst->data[p]);
1543     }
1544
1545     err = opencl_wait_events(hwfc, events, p);
1546     if (err < 0)
1547         goto fail;
1548
1549     err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
1550                                 &opencl_unmap_frame, map);
1551     if (err < 0)
1552         goto fail;
1553
1554     dst->width  = src->width;
1555     dst->height = src->height;
1556
1557     return 0;
1558
1559 fail:
1560     for (p = 0; p < AV_NUM_DATA_POINTERS; p++) {
1561         if (!map->address[p])
1562             break;
1563         clEnqueueUnmapMemObject(priv->command_queue,
1564                                 (cl_mem)src->data[p],
1565                                 map->address[p],
1566                                 0, NULL, &events[p]);
1567     }
1568     if (p > 0)
1569         opencl_wait_events(hwfc, events, p);
1570     av_freep(&map);
1571     return err;
1572 }
1573
1574 #if HAVE_OPENCL_VAAPI_BEIGNET
1575
1576 typedef struct VAAPItoOpenCLMapping {
1577     VAImage      va_image;
1578     VABufferInfo va_buffer_info;
1579
1580     AVOpenCLFrameDescriptor frame;
1581 } VAAPItoOpenCLMapping;
1582
1583 static void opencl_unmap_from_vaapi(AVHWFramesContext *src_fc,
1584                                     HWMapDescriptor *hwmap)
1585 {
1586     VAAPItoOpenCLMapping *mapping = hwmap->priv;
1587     AVVAAPIDeviceContext *src_dev = src_fc->device_ctx->hwctx;
1588     VASurfaceID surface_id;
1589     VAStatus vas;
1590     cl_int cle;
1591     int i;
1592
1593     surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
1594     av_log(src_fc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from OpenCL.\n",
1595            surface_id);
1596
1597     for (i = 0; i < mapping->frame.nb_planes; i++) {
1598         cle = clReleaseMemObject(mapping->frame.planes[i]);
1599         if (cle != CL_SUCCESS) {
1600             av_log(src_fc, AV_LOG_ERROR, "Failed to release CL "
1601                    "buffer of plane %d of VA image %#x (derived "
1602                    "from surface %#x): %d.\n", i,
1603                    mapping->va_image.buf, surface_id, cle);
1604         }
1605     }
1606
1607     vas = vaReleaseBufferHandle(src_dev->display,
1608                                 mapping->va_image.buf);
1609     if (vas != VA_STATUS_SUCCESS) {
1610         av_log(src_fc, AV_LOG_ERROR, "Failed to release buffer "
1611                "handle of image %#x (derived from surface %#x): "
1612                "%d (%s).\n", mapping->va_image.buf, surface_id,
1613                vas, vaErrorStr(vas));
1614     }
1615
1616     vas = vaDestroyImage(src_dev->display,
1617                          mapping->va_image.image_id);
1618     if (vas != VA_STATUS_SUCCESS) {
1619         av_log(src_fc, AV_LOG_ERROR, "Failed to destroy image "
1620                "derived from surface %#x: %d (%s).\n",
1621                surface_id, vas, vaErrorStr(vas));
1622     }
1623
1624     av_free(mapping);
1625 }
1626
1627 static int opencl_map_from_vaapi(AVHWFramesContext *dst_fc, AVFrame *dst,
1628                                  const AVFrame *src, int flags)
1629 {
1630     AVHWFramesContext      *src_fc =
1631         (AVHWFramesContext*)src->hw_frames_ctx->data;
1632     AVVAAPIDeviceContext  *src_dev = src_fc->device_ctx->hwctx;
1633     AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
1634     OpenCLDeviceContext      *priv = dst_fc->device_ctx->internal->priv;
1635     VAAPItoOpenCLMapping  *mapping = NULL;
1636     VASurfaceID surface_id;
1637     VAStatus vas;
1638     cl_int cle;
1639     int err, p;
1640
1641     surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1642     av_log(src_fc, AV_LOG_DEBUG, "Map VAAPI surface %#x to OpenCL.\n",
1643            surface_id);
1644
1645     mapping = av_mallocz(sizeof(*mapping));
1646     if (!mapping)
1647         return AVERROR(ENOMEM);
1648
1649     vas = vaDeriveImage(src_dev->display, surface_id,
1650                         &mapping->va_image);
1651     if (vas != VA_STATUS_SUCCESS) {
1652         av_log(src_fc, AV_LOG_ERROR, "Failed to derive image from "
1653                "surface %#x: %d (%s).\n",
1654                surface_id, vas, vaErrorStr(vas));
1655         err = AVERROR(EIO);
1656         goto fail;
1657     }
1658
1659     mapping->va_buffer_info.mem_type =
1660         VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
1661
1662     vas = vaAcquireBufferHandle(src_dev->display,
1663                                 mapping->va_image.buf,
1664                                 &mapping->va_buffer_info);
1665     if (vas != VA_STATUS_SUCCESS) {
1666         av_log(src_fc, AV_LOG_ERROR, "Failed to get buffer "
1667                "handle from image %#x (derived from surface %#x): "
1668                "%d (%s).\n", mapping->va_image.buf, surface_id,
1669                vas, vaErrorStr(vas));
1670         vaDestroyImage(src_dev->display, mapping->va_image.buf);
1671         err = AVERROR(EIO);
1672         goto fail_derived;
1673     }
1674
1675     av_log(dst_fc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
1676            mapping->va_buffer_info.handle);
1677
1678     mapping->frame.nb_planes = mapping->va_image.num_planes;
1679     for (p = 0; p < mapping->frame.nb_planes; p++) {
1680         cl_import_image_info_intel image_info = {
1681             .fd   = mapping->va_buffer_info.handle,
1682             .size = mapping->va_buffer_info.mem_size,
1683             .type = CL_MEM_OBJECT_IMAGE2D,
1684             .offset    = mapping->va_image.offsets[p],
1685             .row_pitch = mapping->va_image.pitches[p],
1686         };
1687         cl_image_desc image_desc;
1688
1689         err = opencl_get_plane_format(src_fc->sw_format, p,
1690                                       mapping->va_image.width,
1691                                       mapping->va_image.height,
1692                                       &image_info.fmt,
1693                                       &image_desc);
1694         if (err < 0) {
1695             av_log(dst_fc, AV_LOG_ERROR, "VA %#x (derived from "
1696                    "surface %#x) has invalid parameters: %d.\n",
1697                    mapping->va_image.buf, surface_id, err);
1698             goto fail_mapped;
1699         }
1700         image_info.width  = image_desc.image_width;
1701         image_info.height = image_desc.image_height;
1702
1703         mapping->frame.planes[p] =
1704             priv->clCreateImageFromFdINTEL(dst_dev->context,
1705                                            &image_info, &cle);
1706         if (!mapping->frame.planes[p]) {
1707             av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL image "
1708                    "from plane %d of VA image %#x (derived from "
1709                    "surface %#x): %d.\n", p,
1710                    mapping->va_image.buf, surface_id, cle);
1711             err = AVERROR(EIO);
1712             goto fail_mapped;
1713         }
1714
1715         dst->data[p] = (uint8_t*)mapping->frame.planes[p];
1716     }
1717
1718     err = ff_hwframe_map_create(src->hw_frames_ctx,
1719                                 dst, src, &opencl_unmap_from_vaapi,
1720                                 mapping);
1721     if (err < 0)
1722         goto fail_mapped;
1723
1724     dst->width  = src->width;
1725     dst->height = src->height;
1726
1727     return 0;
1728
1729 fail_mapped:
1730     for (p = 0; p < mapping->frame.nb_planes; p++) {
1731         if (mapping->frame.planes[p])
1732             clReleaseMemObject(mapping->frame.planes[p]);
1733     }
1734     vaReleaseBufferHandle(src_dev->display, mapping->va_image.buf);
1735 fail_derived:
1736     vaDestroyImage(src_dev->display, mapping->va_image.image_id);
1737 fail:
1738     av_freep(&mapping);
1739     return err;
1740 }
1741
1742 #endif
1743
1744 static inline cl_mem_flags opencl_mem_flags_for_mapping(int map_flags)
1745 {
1746     if ((map_flags & AV_HWFRAME_MAP_READ) &&
1747         (map_flags & AV_HWFRAME_MAP_WRITE))
1748         return CL_MEM_READ_WRITE;
1749     else if (map_flags & AV_HWFRAME_MAP_READ)
1750         return CL_MEM_READ_ONLY;
1751     else if (map_flags & AV_HWFRAME_MAP_WRITE)
1752         return CL_MEM_WRITE_ONLY;
1753     else
1754         return 0;
1755 }
1756
1757 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
1758
1759 static void opencl_unmap_from_qsv(AVHWFramesContext *dst_fc,
1760                                   HWMapDescriptor *hwmap)
1761 {
1762     AVOpenCLFrameDescriptor    *desc = hwmap->priv;
1763     OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
1764     OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
1765     cl_event event;
1766     cl_int cle;
1767     int p;
1768
1769     av_log(dst_fc, AV_LOG_DEBUG, "Unmap QSV/VAAPI surface from OpenCL.\n");
1770
1771     cle = device_priv->clEnqueueReleaseVA_APIMediaSurfacesINTEL(
1772         frames_priv->command_queue, desc->nb_planes, desc->planes,
1773         0, NULL, &event);
1774     if (cle != CL_SUCCESS) {
1775         av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface "
1776                "handles: %d.\n", cle);
1777     }
1778
1779     opencl_wait_events(dst_fc, &event, 1);
1780
1781     for (p = 0; p < desc->nb_planes; p++) {
1782         cle = clReleaseMemObject(desc->planes[p]);
1783         if (cle != CL_SUCCESS) {
1784             av_log(dst_fc, AV_LOG_ERROR, "Failed to release CL "
1785                    "image of plane %d of QSV/VAAPI surface: %d\n",
1786                    p, cle);
1787         }
1788     }
1789
1790     av_free(desc);
1791 }
1792
1793 static int opencl_map_from_qsv(AVHWFramesContext *dst_fc, AVFrame *dst,
1794                                const AVFrame *src, int flags)
1795 {
1796     AVHWFramesContext *src_fc =
1797         (AVHWFramesContext*)src->hw_frames_ctx->data;
1798     AVOpenCLDeviceContext   *dst_dev = dst_fc->device_ctx->hwctx;
1799     OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
1800     OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
1801     AVOpenCLFrameDescriptor *desc;
1802     VASurfaceID va_surface;
1803     cl_mem_flags cl_flags;
1804     cl_event event;
1805     cl_int cle;
1806     int err, p;
1807
1808     if (src->format == AV_PIX_FMT_QSV) {
1809         mfxFrameSurface1 *mfx_surface = (mfxFrameSurface1*)src->data[3];
1810         va_surface = *(VASurfaceID*)mfx_surface->Data.MemId;
1811     } else if (src->format == AV_PIX_FMT_VAAPI) {
1812         va_surface = (VASurfaceID)(uintptr_t)src->data[3];
1813     } else {
1814         return AVERROR(ENOSYS);
1815     }
1816
1817     cl_flags = opencl_mem_flags_for_mapping(flags);
1818     if (!cl_flags)
1819         return AVERROR(EINVAL);
1820
1821     av_log(src_fc, AV_LOG_DEBUG, "Map QSV/VAAPI surface %#x to "
1822            "OpenCL.\n", va_surface);
1823
1824     desc = av_mallocz(sizeof(*desc));
1825     if (!desc)
1826         return AVERROR(ENOMEM);
1827
1828     // The cl_intel_va_api_media_sharing extension only supports NV12
1829     // surfaces, so for now there are always exactly two planes.
1830     desc->nb_planes = 2;
1831
1832     for (p = 0; p < desc->nb_planes; p++) {
1833         desc->planes[p] =
1834             device_priv->clCreateFromVA_APIMediaSurfaceINTEL(
1835                 dst_dev->context, cl_flags, &va_surface, p, &cle);
1836         if (!desc->planes[p]) {
1837             av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL "
1838                    "image from plane %d of QSV/VAAPI surface "
1839                    "%#x: %d.\n", p, va_surface, cle);
1840             err = AVERROR(EIO);
1841             goto fail;
1842         }
1843
1844         dst->data[p] = (uint8_t*)desc->planes[p];
1845     }
1846
1847     cle = device_priv->clEnqueueAcquireVA_APIMediaSurfacesINTEL(
1848         frames_priv->command_queue, desc->nb_planes, desc->planes,
1849         0, NULL, &event);
1850     if (cle != CL_SUCCESS) {
1851         av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface "
1852                "handles: %d.\n", cle);
1853         err = AVERROR(EIO);
1854         goto fail;
1855     }
1856
1857     err = opencl_wait_events(dst_fc, &event, 1);
1858     if (err < 0)
1859         goto fail;
1860
1861     err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
1862                                 &opencl_unmap_from_qsv, desc);
1863     if (err < 0)
1864         goto fail;
1865
1866     dst->width  = src->width;
1867     dst->height = src->height;
1868
1869     return 0;
1870
1871 fail:
1872     for (p = 0; p < desc->nb_planes; p++)
1873         if (desc->planes[p])
1874             clReleaseMemObject(desc->planes[p]);
1875     av_freep(&desc);
1876     return err;
1877 }
1878
1879 #endif
1880
1881 static int opencl_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
1882                            const AVFrame *src, int flags)
1883 {
1884     av_assert0(src->format == AV_PIX_FMT_OPENCL);
1885     if (hwfc->sw_format != dst->format)
1886         return AVERROR(ENOSYS);
1887     return opencl_map_frame(hwfc, dst, src, flags);
1888 }
1889
1890 static int opencl_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
1891                          const AVFrame *src, int flags)
1892 {
1893     OpenCLDeviceContext *priv = hwfc->device_ctx->internal->priv;
1894     av_assert0(dst->format == AV_PIX_FMT_OPENCL);
1895     switch (src->format) {
1896 #if HAVE_OPENCL_VAAPI_BEIGNET
1897     case AV_PIX_FMT_VAAPI:
1898         if (priv->vaapi_mapping_usable)
1899             return opencl_map_from_vaapi(hwfc, dst, src, flags);
1900 #endif
1901 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
1902     case AV_PIX_FMT_QSV:
1903     case AV_PIX_FMT_VAAPI:
1904         if (priv->qsv_mapping_usable)
1905             return opencl_map_from_qsv(hwfc, dst, src, flags);
1906 #endif
1907     }
1908     return AVERROR(ENOSYS);
1909 }
1910
1911 static int opencl_frames_derive_to(AVHWFramesContext *dst_fc,
1912                                    AVHWFramesContext *src_fc, int flags)
1913 {
1914     OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv;
1915     switch (src_fc->device_ctx->type) {
1916 #if HAVE_OPENCL_VAAPI_BEIGNET
1917     case AV_HWDEVICE_TYPE_VAAPI:
1918         if (!priv->vaapi_mapping_usable)
1919             return AVERROR(ENOSYS);
1920         break;
1921 #endif
1922 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
1923     case AV_HWDEVICE_TYPE_QSV:
1924     case AV_HWDEVICE_TYPE_VAAPI:
1925         if (!priv->qsv_mapping_usable)
1926             return AVERROR(ENOSYS);
1927         break;
1928 #endif
1929     default:
1930         return AVERROR(ENOSYS);
1931     }
1932     return opencl_frames_init_command_queue(dst_fc);
1933 }
1934
1935 const HWContextType ff_hwcontext_type_opencl = {
1936     .type                   = AV_HWDEVICE_TYPE_OPENCL,
1937     .name                   = "OpenCL",
1938
1939     .device_hwctx_size      = sizeof(AVOpenCLDeviceContext),
1940     .device_priv_size       = sizeof(OpenCLDeviceContext),
1941     .frames_hwctx_size      = sizeof(AVOpenCLFramesContext),
1942     .frames_priv_size       = sizeof(OpenCLFramesContext),
1943
1944     .device_create          = &opencl_device_create,
1945     .device_derive          = &opencl_device_derive,
1946     .device_init            = &opencl_device_init,
1947     .device_uninit          = &opencl_device_uninit,
1948
1949     .frames_get_constraints = &opencl_frames_get_constraints,
1950     .frames_init            = &opencl_frames_init,
1951     .frames_uninit          = &opencl_frames_uninit,
1952     .frames_get_buffer      = &opencl_get_buffer,
1953
1954     .transfer_get_formats   = &opencl_transfer_get_formats,
1955     .transfer_data_to       = &opencl_transfer_data_to,
1956     .transfer_data_from     = &opencl_transfer_data_from,
1957
1958     .map_from               = &opencl_map_from,
1959     .map_to                 = &opencl_map_to,
1960     .frames_derive_to       = &opencl_frames_derive_to,
1961
1962     .pix_fmts = (const enum AVPixelFormat[]) {
1963         AV_PIX_FMT_OPENCL,
1964         AV_PIX_FMT_NONE
1965     },
1966 };