]> git.sesse.net Git - ffmpeg/blob - libavutil/hwcontext_vaapi.c
avutil/buffer: Switch AVBuffer API to size_t
[ffmpeg] / libavutil / hwcontext_vaapi.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 "config.h"
20
21 #if HAVE_VAAPI_X11
22 #   include <va/va_x11.h>
23 #endif
24 #if HAVE_VAAPI_DRM
25 #   include <va/va_drm.h>
26 #endif
27
28 #if CONFIG_LIBDRM
29 #   include <va/va_drmcommon.h>
30 #   include <xf86drm.h>
31 #   include <drm_fourcc.h>
32 #   ifndef DRM_FORMAT_MOD_INVALID
33 #       define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
34 #   endif
35 #endif
36
37 #include <fcntl.h>
38 #if HAVE_UNISTD_H
39 #   include <unistd.h>
40 #endif
41
42
43 #include "avassert.h"
44 #include "buffer.h"
45 #include "common.h"
46 #include "hwcontext.h"
47 #include "hwcontext_drm.h"
48 #include "hwcontext_internal.h"
49 #include "hwcontext_vaapi.h"
50 #include "mem.h"
51 #include "pixdesc.h"
52 #include "pixfmt.h"
53
54
55 typedef struct VAAPIDevicePriv {
56 #if HAVE_VAAPI_X11
57     Display *x11_display;
58 #endif
59
60     int drm_fd;
61 } VAAPIDevicePriv;
62
63 typedef struct VAAPISurfaceFormat {
64     enum AVPixelFormat pix_fmt;
65     VAImageFormat image_format;
66 } VAAPISurfaceFormat;
67
68 typedef struct VAAPIDeviceContext {
69     // Surface formats which can be used with this device.
70     VAAPISurfaceFormat *formats;
71     int              nb_formats;
72 } VAAPIDeviceContext;
73
74 typedef struct VAAPIFramesContext {
75     // Surface attributes set at create time.
76     VASurfaceAttrib *attributes;
77     int           nb_attributes;
78     // RT format of the underlying surface (Intel driver ignores this anyway).
79     unsigned int rt_format;
80     // Whether vaDeriveImage works.
81     int derive_works;
82 } VAAPIFramesContext;
83
84 typedef struct VAAPIMapping {
85     // Handle to the derived or copied image which is mapped.
86     VAImage image;
87     // The mapping flags actually used.
88     int flags;
89 } VAAPIMapping;
90
91 typedef struct VAAPIFormat {
92     unsigned int fourcc;
93     unsigned int rt_format;
94     enum AVPixelFormat pix_fmt;
95     int chroma_planes_swapped;
96 } VAAPIFormatDescriptor;
97
98 #define MAP(va, rt, av, swap_uv) { \
99         VA_FOURCC_ ## va, \
100         VA_RT_FORMAT_ ## rt, \
101         AV_PIX_FMT_ ## av, \
102         swap_uv, \
103     }
104 // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
105 // plane swap cases.  The frame handling below tries to hide these.
106 static const VAAPIFormatDescriptor vaapi_format_map[] = {
107     MAP(NV12, YUV420,  NV12,    0),
108 #ifdef VA_FOURCC_I420
109     MAP(I420, YUV420,  YUV420P, 0),
110 #endif
111     MAP(YV12, YUV420,  YUV420P, 1),
112     MAP(IYUV, YUV420,  YUV420P, 0),
113     MAP(422H, YUV422,  YUV422P, 0),
114 #ifdef VA_FOURCC_YV16
115     MAP(YV16, YUV422,  YUV422P, 1),
116 #endif
117     MAP(UYVY, YUV422,  UYVY422, 0),
118     MAP(YUY2, YUV422,  YUYV422, 0),
119 #ifdef VA_FOURCC_Y210
120     MAP(Y210, YUV422_10,  Y210, 0),
121 #endif
122     MAP(411P, YUV411,  YUV411P, 0),
123     MAP(422V, YUV422,  YUV440P, 0),
124     MAP(444P, YUV444,  YUV444P, 0),
125     MAP(Y800, YUV400,  GRAY8,   0),
126 #ifdef VA_FOURCC_P010
127     MAP(P010, YUV420_10BPP, P010, 0),
128 #endif
129     MAP(BGRA, RGB32,   BGRA, 0),
130     MAP(BGRX, RGB32,   BGR0, 0),
131     MAP(RGBA, RGB32,   RGBA, 0),
132     MAP(RGBX, RGB32,   RGB0, 0),
133 #ifdef VA_FOURCC_ABGR
134     MAP(ABGR, RGB32,   ABGR, 0),
135     MAP(XBGR, RGB32,   0BGR, 0),
136 #endif
137     MAP(ARGB, RGB32,   ARGB, 0),
138     MAP(XRGB, RGB32,   0RGB, 0),
139 #ifdef VA_FOURCC_X2R10G10B10
140     MAP(X2R10G10B10, RGB32_10, X2RGB10, 0),
141 #endif
142 };
143 #undef MAP
144
145 static const VAAPIFormatDescriptor *
146     vaapi_format_from_fourcc(unsigned int fourcc)
147 {
148     int i;
149     for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
150         if (vaapi_format_map[i].fourcc == fourcc)
151             return &vaapi_format_map[i];
152     return NULL;
153 }
154
155 static const VAAPIFormatDescriptor *
156     vaapi_format_from_pix_fmt(enum AVPixelFormat pix_fmt)
157 {
158     int i;
159     for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
160         if (vaapi_format_map[i].pix_fmt == pix_fmt)
161             return &vaapi_format_map[i];
162     return NULL;
163 }
164
165 static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
166 {
167     const VAAPIFormatDescriptor *desc;
168     desc = vaapi_format_from_fourcc(fourcc);
169     if (desc)
170         return desc->pix_fmt;
171     else
172         return AV_PIX_FMT_NONE;
173 }
174
175 static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
176                                   enum AVPixelFormat pix_fmt,
177                                   VAImageFormat **image_format)
178 {
179     VAAPIDeviceContext *ctx = hwdev->internal->priv;
180     int i;
181
182     for (i = 0; i < ctx->nb_formats; i++) {
183         if (ctx->formats[i].pix_fmt == pix_fmt) {
184             if (image_format)
185                 *image_format = &ctx->formats[i].image_format;
186             return 0;
187         }
188     }
189     return AVERROR(EINVAL);
190 }
191
192 static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
193                                         const void *hwconfig,
194                                         AVHWFramesConstraints *constraints)
195 {
196     AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
197     const AVVAAPIHWConfig *config = hwconfig;
198     VAAPIDeviceContext *ctx = hwdev->internal->priv;
199     VASurfaceAttrib *attr_list = NULL;
200     VAStatus vas;
201     enum AVPixelFormat pix_fmt;
202     unsigned int fourcc;
203     int err, i, j, attr_count, pix_fmt_count;
204
205     if (config &&
206         !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
207         attr_count = 0;
208         vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
209                                        0, &attr_count);
210         if (vas != VA_STATUS_SUCCESS) {
211             av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
212                    "%d (%s).\n", vas, vaErrorStr(vas));
213             err = AVERROR(ENOSYS);
214             goto fail;
215         }
216
217         attr_list = av_malloc(attr_count * sizeof(*attr_list));
218         if (!attr_list) {
219             err = AVERROR(ENOMEM);
220             goto fail;
221         }
222
223         vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
224                                        attr_list, &attr_count);
225         if (vas != VA_STATUS_SUCCESS) {
226             av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
227                    "%d (%s).\n", vas, vaErrorStr(vas));
228             err = AVERROR(ENOSYS);
229             goto fail;
230         }
231
232         pix_fmt_count = 0;
233         for (i = 0; i < attr_count; i++) {
234             switch (attr_list[i].type) {
235             case VASurfaceAttribPixelFormat:
236                 fourcc = attr_list[i].value.value.i;
237                 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
238                 if (pix_fmt != AV_PIX_FMT_NONE) {
239                     ++pix_fmt_count;
240                 } else {
241                     // Something unsupported - ignore.
242                 }
243                 break;
244             case VASurfaceAttribMinWidth:
245                 constraints->min_width  = attr_list[i].value.value.i;
246                 break;
247             case VASurfaceAttribMinHeight:
248                 constraints->min_height = attr_list[i].value.value.i;
249                 break;
250             case VASurfaceAttribMaxWidth:
251                 constraints->max_width  = attr_list[i].value.value.i;
252                 break;
253             case VASurfaceAttribMaxHeight:
254                 constraints->max_height = attr_list[i].value.value.i;
255                 break;
256             }
257         }
258         if (pix_fmt_count == 0) {
259             // Nothing usable found.  Presumably there exists something which
260             // works, so leave the set null to indicate unknown.
261             constraints->valid_sw_formats = NULL;
262         } else {
263             constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
264                                                             sizeof(pix_fmt));
265             if (!constraints->valid_sw_formats) {
266                 err = AVERROR(ENOMEM);
267                 goto fail;
268             }
269
270             for (i = j = 0; i < attr_count; i++) {
271                 int k;
272
273                 if (attr_list[i].type != VASurfaceAttribPixelFormat)
274                     continue;
275                 fourcc = attr_list[i].value.value.i;
276                 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
277
278                 if (pix_fmt == AV_PIX_FMT_NONE)
279                     continue;
280
281                 for (k = 0; k < j; k++) {
282                     if (constraints->valid_sw_formats[k] == pix_fmt)
283                         break;
284                 }
285
286                 if (k == j)
287                     constraints->valid_sw_formats[j++] = pix_fmt;
288             }
289             constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
290         }
291     } else {
292         // No configuration supplied.
293         // Return the full set of image formats known by the implementation.
294         constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
295                                                         sizeof(pix_fmt));
296         if (!constraints->valid_sw_formats) {
297             err = AVERROR(ENOMEM);
298             goto fail;
299         }
300         for (i = j = 0; i < ctx->nb_formats; i++) {
301             int k;
302
303             for (k = 0; k < j; k++) {
304                 if (constraints->valid_sw_formats[k] == ctx->formats[i].pix_fmt)
305                     break;
306             }
307
308             if (k == j)
309                 constraints->valid_sw_formats[j++] = ctx->formats[i].pix_fmt;
310         }
311
312         constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
313     }
314
315     constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
316     if (!constraints->valid_hw_formats) {
317         err = AVERROR(ENOMEM);
318         goto fail;
319     }
320     constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
321     constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
322
323     err = 0;
324 fail:
325     av_freep(&attr_list);
326     return err;
327 }
328
329 static const struct {
330     const char *friendly_name;
331     const char *match_string;
332     unsigned int quirks;
333 } vaapi_driver_quirks_table[] = {
334 #if !VA_CHECK_VERSION(1, 0, 0)
335     // The i965 driver did not conform before version 2.0.
336     {
337         "Intel i965 (Quick Sync)",
338         "i965",
339         AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS,
340     },
341 #endif
342     {
343         "Intel iHD",
344         "ubit",
345         AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE,
346     },
347     {
348         "VDPAU wrapper",
349         "Splitted-Desktop Systems VDPAU backend for VA-API",
350         AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES,
351     },
352 };
353
354 static int vaapi_device_init(AVHWDeviceContext *hwdev)
355 {
356     VAAPIDeviceContext *ctx = hwdev->internal->priv;
357     AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
358     VAImageFormat *image_list = NULL;
359     VAStatus vas;
360     const char *vendor_string;
361     int err, i, image_count;
362     enum AVPixelFormat pix_fmt;
363     unsigned int fourcc;
364
365     image_count = vaMaxNumImageFormats(hwctx->display);
366     if (image_count <= 0) {
367         err = AVERROR(EIO);
368         goto fail;
369     }
370     image_list = av_malloc(image_count * sizeof(*image_list));
371     if (!image_list) {
372         err = AVERROR(ENOMEM);
373         goto fail;
374     }
375     vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
376     if (vas != VA_STATUS_SUCCESS) {
377         err = AVERROR(EIO);
378         goto fail;
379     }
380
381     ctx->formats  = av_malloc(image_count * sizeof(*ctx->formats));
382     if (!ctx->formats) {
383         err = AVERROR(ENOMEM);
384         goto fail;
385     }
386     ctx->nb_formats = 0;
387     for (i = 0; i < image_count; i++) {
388         fourcc  = image_list[i].fourcc;
389         pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
390         if (pix_fmt == AV_PIX_FMT_NONE) {
391             av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
392                    fourcc);
393         } else {
394             av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
395                    fourcc, av_get_pix_fmt_name(pix_fmt));
396             ctx->formats[ctx->nb_formats].pix_fmt      = pix_fmt;
397             ctx->formats[ctx->nb_formats].image_format = image_list[i];
398             ++ctx->nb_formats;
399         }
400     }
401
402     vendor_string = vaQueryVendorString(hwctx->display);
403     if (vendor_string)
404         av_log(hwdev, AV_LOG_VERBOSE, "VAAPI driver: %s.\n", vendor_string);
405
406     if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) {
407         av_log(hwdev, AV_LOG_VERBOSE, "Using quirks set by user (%#x).\n",
408                hwctx->driver_quirks);
409     } else {
410         // Detect the driver in use and set quirk flags if necessary.
411         hwctx->driver_quirks = 0;
412         if (vendor_string) {
413             for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
414                 if (strstr(vendor_string,
415                            vaapi_driver_quirks_table[i].match_string)) {
416                     av_log(hwdev, AV_LOG_VERBOSE, "Matched driver string "
417                            "as known nonstandard driver \"%s\", setting "
418                            "quirks (%#x).\n",
419                            vaapi_driver_quirks_table[i].friendly_name,
420                            vaapi_driver_quirks_table[i].quirks);
421                     hwctx->driver_quirks |=
422                         vaapi_driver_quirks_table[i].quirks;
423                     break;
424                 }
425             }
426             if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) {
427                 av_log(hwdev, AV_LOG_VERBOSE, "Driver not found in known "
428                        "nonstandard list, using standard behaviour.\n");
429             }
430         } else {
431             av_log(hwdev, AV_LOG_VERBOSE, "Driver has no vendor string, "
432                    "assuming standard behaviour.\n");
433         }
434     }
435
436     av_free(image_list);
437     return 0;
438 fail:
439     av_freep(&ctx->formats);
440     av_free(image_list);
441     return err;
442 }
443
444 static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
445 {
446     VAAPIDeviceContext *ctx = hwdev->internal->priv;
447
448     av_freep(&ctx->formats);
449 }
450
451 static void vaapi_buffer_free(void *opaque, uint8_t *data)
452 {
453     AVHWFramesContext     *hwfc = opaque;
454     AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
455     VASurfaceID surface_id;
456     VAStatus vas;
457
458     surface_id = (VASurfaceID)(uintptr_t)data;
459
460     vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
461     if (vas != VA_STATUS_SUCCESS) {
462         av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
463                "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
464     }
465 }
466
467 static AVBufferRef *vaapi_pool_alloc(void *opaque, size_t size)
468 {
469     AVHWFramesContext     *hwfc = opaque;
470     VAAPIFramesContext     *ctx = hwfc->internal->priv;
471     AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
472     AVVAAPIFramesContext  *avfc = hwfc->hwctx;
473     VASurfaceID surface_id;
474     VAStatus vas;
475     AVBufferRef *ref;
476
477     if (hwfc->initial_pool_size > 0 &&
478         avfc->nb_surfaces >= hwfc->initial_pool_size)
479         return NULL;
480
481     vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
482                            hwfc->width, hwfc->height,
483                            &surface_id, 1,
484                            ctx->attributes, ctx->nb_attributes);
485     if (vas != VA_STATUS_SUCCESS) {
486         av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
487                "%d (%s).\n", vas, vaErrorStr(vas));
488         return NULL;
489     }
490     av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
491
492     ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
493                            sizeof(surface_id), &vaapi_buffer_free,
494                            hwfc, AV_BUFFER_FLAG_READONLY);
495     if (!ref) {
496         vaDestroySurfaces(hwctx->display, &surface_id, 1);
497         return NULL;
498     }
499
500     if (hwfc->initial_pool_size > 0) {
501         // This is a fixed-size pool, so we must still be in the initial
502         // allocation sequence.
503         av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
504         avfc->surface_ids[avfc->nb_surfaces] = surface_id;
505         ++avfc->nb_surfaces;
506     }
507
508     return ref;
509 }
510
511 static int vaapi_frames_init(AVHWFramesContext *hwfc)
512 {
513     AVVAAPIFramesContext  *avfc = hwfc->hwctx;
514     VAAPIFramesContext     *ctx = hwfc->internal->priv;
515     AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
516     const VAAPIFormatDescriptor *desc;
517     VAImageFormat *expected_format;
518     AVBufferRef *test_surface = NULL;
519     VASurfaceID test_surface_id;
520     VAImage test_image;
521     VAStatus vas;
522     int err, i;
523
524     desc = vaapi_format_from_pix_fmt(hwfc->sw_format);
525     if (!desc) {
526         av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
527                av_get_pix_fmt_name(hwfc->sw_format));
528         return AVERROR(EINVAL);
529     }
530
531     if (!hwfc->pool) {
532         if (!(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
533             int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
534             int need_pixel_format = 1;
535             for (i = 0; i < avfc->nb_attributes; i++) {
536                 if (avfc->attributes[i].type == VASurfaceAttribMemoryType)
537                     need_memory_type  = 0;
538                 if (avfc->attributes[i].type == VASurfaceAttribPixelFormat)
539                     need_pixel_format = 0;
540             }
541             ctx->nb_attributes =
542                 avfc->nb_attributes + need_memory_type + need_pixel_format;
543
544             ctx->attributes = av_malloc(ctx->nb_attributes *
545                                         sizeof(*ctx->attributes));
546             if (!ctx->attributes) {
547                 err = AVERROR(ENOMEM);
548                 goto fail;
549             }
550
551             for (i = 0; i < avfc->nb_attributes; i++)
552                 ctx->attributes[i] = avfc->attributes[i];
553             if (need_memory_type) {
554                 ctx->attributes[i++] = (VASurfaceAttrib) {
555                     .type          = VASurfaceAttribMemoryType,
556                     .flags         = VA_SURFACE_ATTRIB_SETTABLE,
557                     .value.type    = VAGenericValueTypeInteger,
558                     .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
559                 };
560             }
561             if (need_pixel_format) {
562                 ctx->attributes[i++] = (VASurfaceAttrib) {
563                     .type          = VASurfaceAttribPixelFormat,
564                     .flags         = VA_SURFACE_ATTRIB_SETTABLE,
565                     .value.type    = VAGenericValueTypeInteger,
566                     .value.value.i = desc->fourcc,
567                 };
568             }
569             av_assert0(i == ctx->nb_attributes);
570         } else {
571             ctx->attributes = NULL;
572             ctx->nb_attributes = 0;
573         }
574
575         ctx->rt_format = desc->rt_format;
576
577         if (hwfc->initial_pool_size > 0) {
578             // This pool will be usable as a render target, so we need to store
579             // all of the surface IDs somewhere that vaCreateContext() calls
580             // will be able to access them.
581             avfc->nb_surfaces = 0;
582             avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
583                                           sizeof(*avfc->surface_ids));
584             if (!avfc->surface_ids) {
585                 err = AVERROR(ENOMEM);
586                 goto fail;
587             }
588         } else {
589             // This pool allows dynamic sizing, and will not be usable as a
590             // render target.
591             avfc->nb_surfaces = 0;
592             avfc->surface_ids = NULL;
593         }
594
595         hwfc->internal->pool_internal =
596             av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
597                                  &vaapi_pool_alloc, NULL);
598         if (!hwfc->internal->pool_internal) {
599             av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
600             err = AVERROR(ENOMEM);
601             goto fail;
602         }
603     }
604
605     // Allocate a single surface to test whether vaDeriveImage() is going
606     // to work for the specific configuration.
607     if (hwfc->pool) {
608         test_surface = av_buffer_pool_get(hwfc->pool);
609         if (!test_surface) {
610             av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
611                    "user-configured buffer pool.\n");
612             err = AVERROR(ENOMEM);
613             goto fail;
614         }
615     } else {
616         test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
617         if (!test_surface) {
618             av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
619                    "internal buffer pool.\n");
620             err = AVERROR(ENOMEM);
621             goto fail;
622         }
623     }
624     test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
625
626     ctx->derive_works = 0;
627
628     err = vaapi_get_image_format(hwfc->device_ctx,
629                                  hwfc->sw_format, &expected_format);
630     if (err == 0) {
631         vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
632         if (vas == VA_STATUS_SUCCESS) {
633             if (expected_format->fourcc == test_image.format.fourcc) {
634                 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
635                 ctx->derive_works = 1;
636             } else {
637                 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
638                        "derived image format %08x does not match "
639                        "expected format %08x.\n",
640                        expected_format->fourcc, test_image.format.fourcc);
641             }
642             vaDestroyImage(hwctx->display, test_image.image_id);
643         } else {
644             av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
645                    "deriving image does not work: "
646                    "%d (%s).\n", vas, vaErrorStr(vas));
647         }
648     } else {
649         av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
650                "image format is not supported.\n");
651     }
652
653     av_buffer_unref(&test_surface);
654     return 0;
655
656 fail:
657     av_buffer_unref(&test_surface);
658     av_freep(&avfc->surface_ids);
659     av_freep(&ctx->attributes);
660     return err;
661 }
662
663 static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
664 {
665     AVVAAPIFramesContext *avfc = hwfc->hwctx;
666     VAAPIFramesContext    *ctx = hwfc->internal->priv;
667
668     av_freep(&avfc->surface_ids);
669     av_freep(&ctx->attributes);
670 }
671
672 static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
673 {
674     frame->buf[0] = av_buffer_pool_get(hwfc->pool);
675     if (!frame->buf[0])
676         return AVERROR(ENOMEM);
677
678     frame->data[3] = frame->buf[0]->data;
679     frame->format  = AV_PIX_FMT_VAAPI;
680     frame->width   = hwfc->width;
681     frame->height  = hwfc->height;
682
683     return 0;
684 }
685
686 static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
687                                       enum AVHWFrameTransferDirection dir,
688                                       enum AVPixelFormat **formats)
689 {
690     VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
691     enum AVPixelFormat *pix_fmts;
692     int i, k, sw_format_available;
693
694     sw_format_available = 0;
695     for (i = 0; i < ctx->nb_formats; i++) {
696         if (ctx->formats[i].pix_fmt == hwfc->sw_format)
697             sw_format_available = 1;
698     }
699
700     pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
701     if (!pix_fmts)
702         return AVERROR(ENOMEM);
703
704     if (sw_format_available) {
705         pix_fmts[0] = hwfc->sw_format;
706         k = 1;
707     } else {
708         k = 0;
709     }
710     for (i = 0; i < ctx->nb_formats; i++) {
711         if (ctx->formats[i].pix_fmt == hwfc->sw_format)
712             continue;
713         av_assert0(k < ctx->nb_formats);
714         pix_fmts[k++] = ctx->formats[i].pix_fmt;
715     }
716     pix_fmts[k] = AV_PIX_FMT_NONE;
717
718     *formats = pix_fmts;
719     return 0;
720 }
721
722 static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
723                               HWMapDescriptor *hwmap)
724 {
725     AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
726     VAAPIMapping           *map = hwmap->priv;
727     VASurfaceID surface_id;
728     VAStatus vas;
729
730     surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
731     av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
732
733     vas = vaUnmapBuffer(hwctx->display, map->image.buf);
734     if (vas != VA_STATUS_SUCCESS) {
735         av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
736                "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
737     }
738
739     if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
740         !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
741         vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
742                          0, 0, hwfc->width, hwfc->height,
743                          0, 0, hwfc->width, hwfc->height);
744         if (vas != VA_STATUS_SUCCESS) {
745             av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
746                    "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
747         }
748     }
749
750     vas = vaDestroyImage(hwctx->display, map->image.image_id);
751     if (vas != VA_STATUS_SUCCESS) {
752         av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
753                "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
754     }
755
756     av_free(map);
757 }
758
759 static int vaapi_map_frame(AVHWFramesContext *hwfc,
760                            AVFrame *dst, const AVFrame *src, int flags)
761 {
762     AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
763     VAAPIFramesContext *ctx = hwfc->internal->priv;
764     VASurfaceID surface_id;
765     const VAAPIFormatDescriptor *desc;
766     VAImageFormat *image_format;
767     VAAPIMapping *map;
768     VAStatus vas;
769     void *address = NULL;
770     int err, i;
771
772     surface_id = (VASurfaceID)(uintptr_t)src->data[3];
773     av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
774
775     if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
776         // Requested direct mapping but it is not possible.
777         return AVERROR(EINVAL);
778     }
779     if (dst->format == AV_PIX_FMT_NONE)
780         dst->format = hwfc->sw_format;
781     if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
782         // Requested direct mapping but the formats do not match.
783         return AVERROR(EINVAL);
784     }
785
786     err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
787     if (err < 0) {
788         // Requested format is not a valid output format.
789         return AVERROR(EINVAL);
790     }
791
792     map = av_malloc(sizeof(*map));
793     if (!map)
794         return AVERROR(ENOMEM);
795     map->flags = flags;
796     map->image.image_id = VA_INVALID_ID;
797
798     vas = vaSyncSurface(hwctx->display, surface_id);
799     if (vas != VA_STATUS_SUCCESS) {
800         av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
801                "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
802         err = AVERROR(EIO);
803         goto fail;
804     }
805
806     // The memory which we map using derive need not be connected to the CPU
807     // in a way conducive to fast access.  On Gen7-Gen9 Intel graphics, the
808     // memory is mappable but not cached, so normal memcpy()-like access is
809     // very slow to read it (but writing is ok).  It is possible to read much
810     // faster with a copy routine which is aware of the limitation, but we
811     // assume for now that the user is not aware of that and would therefore
812     // prefer not to be given direct-mapped memory if they request read access.
813     if (ctx->derive_works && dst->format == hwfc->sw_format &&
814         ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
815         vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
816         if (vas != VA_STATUS_SUCCESS) {
817             av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
818                    "surface %#x: %d (%s).\n",
819                    surface_id, vas, vaErrorStr(vas));
820             err = AVERROR(EIO);
821             goto fail;
822         }
823         if (map->image.format.fourcc != image_format->fourcc) {
824             av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
825                    "is in wrong format: expected %#08x, got %#08x.\n",
826                    surface_id, image_format->fourcc, map->image.format.fourcc);
827             err = AVERROR(EIO);
828             goto fail;
829         }
830         map->flags |= AV_HWFRAME_MAP_DIRECT;
831     } else {
832         vas = vaCreateImage(hwctx->display, image_format,
833                             hwfc->width, hwfc->height, &map->image);
834         if (vas != VA_STATUS_SUCCESS) {
835             av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
836                    "surface %#x: %d (%s).\n",
837                    surface_id, vas, vaErrorStr(vas));
838             err = AVERROR(EIO);
839             goto fail;
840         }
841         if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
842             vas = vaGetImage(hwctx->display, surface_id, 0, 0,
843                              hwfc->width, hwfc->height, map->image.image_id);
844             if (vas != VA_STATUS_SUCCESS) {
845                 av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
846                        "surface %#x: %d (%s).\n",
847                        surface_id, vas, vaErrorStr(vas));
848                 err = AVERROR(EIO);
849                 goto fail;
850             }
851         }
852     }
853
854     vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
855     if (vas != VA_STATUS_SUCCESS) {
856         av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
857                "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
858         err = AVERROR(EIO);
859         goto fail;
860     }
861
862     err = ff_hwframe_map_create(src->hw_frames_ctx,
863                                 dst, src, &vaapi_unmap_frame, map);
864     if (err < 0)
865         goto fail;
866
867     dst->width  = src->width;
868     dst->height = src->height;
869
870     for (i = 0; i < map->image.num_planes; i++) {
871         dst->data[i] = (uint8_t*)address + map->image.offsets[i];
872         dst->linesize[i] = map->image.pitches[i];
873     }
874
875     desc = vaapi_format_from_fourcc(map->image.format.fourcc);
876     if (desc && desc->chroma_planes_swapped) {
877         // Chroma planes are YVU rather than YUV, so swap them.
878         FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
879     }
880
881     return 0;
882
883 fail:
884     if (map) {
885         if (address)
886             vaUnmapBuffer(hwctx->display, map->image.buf);
887         if (map->image.image_id != VA_INVALID_ID)
888             vaDestroyImage(hwctx->display, map->image.image_id);
889         av_free(map);
890     }
891     return err;
892 }
893
894 static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
895                                     AVFrame *dst, const AVFrame *src)
896 {
897     AVFrame *map;
898     int err;
899
900     if (dst->width > hwfc->width || dst->height > hwfc->height)
901         return AVERROR(EINVAL);
902
903     map = av_frame_alloc();
904     if (!map)
905         return AVERROR(ENOMEM);
906     map->format = dst->format;
907
908     err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
909     if (err)
910         goto fail;
911
912     map->width  = dst->width;
913     map->height = dst->height;
914
915     err = av_frame_copy(dst, map);
916     if (err)
917         goto fail;
918
919     err = 0;
920 fail:
921     av_frame_free(&map);
922     return err;
923 }
924
925 static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
926                                   AVFrame *dst, const AVFrame *src)
927 {
928     AVFrame *map;
929     int err;
930
931     if (src->width > hwfc->width || src->height > hwfc->height)
932         return AVERROR(EINVAL);
933
934     map = av_frame_alloc();
935     if (!map)
936         return AVERROR(ENOMEM);
937     map->format = src->format;
938
939     err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
940     if (err)
941         goto fail;
942
943     map->width  = src->width;
944     map->height = src->height;
945
946     err = av_frame_copy(map, src);
947     if (err)
948         goto fail;
949
950     err = 0;
951 fail:
952     av_frame_free(&map);
953     return err;
954 }
955
956 static int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst,
957                                const AVFrame *src, int flags)
958 {
959     int err;
960
961     if (dst->format != AV_PIX_FMT_NONE) {
962         err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
963         if (err < 0)
964             return AVERROR(ENOSYS);
965     }
966
967     err = vaapi_map_frame(hwfc, dst, src, flags);
968     if (err)
969         return err;
970
971     err = av_frame_copy_props(dst, src);
972     if (err)
973         return err;
974
975     return 0;
976 }
977
978 #if CONFIG_LIBDRM
979
980 #define DRM_MAP(va, layers, ...) { \
981         VA_FOURCC_ ## va, \
982         layers, \
983         { __VA_ARGS__ } \
984     }
985 static const struct {
986     uint32_t va_fourcc;
987     int   nb_layer_formats;
988     uint32_t layer_formats[AV_DRM_MAX_PLANES];
989 } vaapi_drm_format_map[] = {
990 #ifdef DRM_FORMAT_R8
991     DRM_MAP(NV12, 2, DRM_FORMAT_R8,  DRM_FORMAT_RG88),
992 #endif
993     DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
994 #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
995     DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
996 #endif
997     DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
998     DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
999     DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888),
1000     DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888),
1001 #ifdef VA_FOURCC_ABGR
1002     DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888),
1003     DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888),
1004 #endif
1005     DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
1006     DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
1007 };
1008 #undef DRM_MAP
1009
1010 static void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc,
1011                                  HWMapDescriptor *hwmap)
1012 {
1013     AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
1014
1015     VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv;
1016
1017     av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id);
1018
1019     vaDestroySurfaces(dst_dev->display, &surface_id, 1);
1020 }
1021
1022 static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst,
1023                               const AVFrame *src, int flags)
1024 {
1025     AVHWFramesContext      *dst_fc =
1026         (AVHWFramesContext*)dst->hw_frames_ctx->data;
1027     AVVAAPIDeviceContext  *dst_dev = dst_fc->device_ctx->hwctx;
1028     const AVDRMFrameDescriptor *desc;
1029     const VAAPIFormatDescriptor *format_desc;
1030     VASurfaceID surface_id;
1031     VAStatus vas;
1032     uint32_t va_fourcc;
1033     int err, i, j, k;
1034
1035     unsigned long buffer_handle;
1036     VASurfaceAttribExternalBuffers buffer_desc;
1037     VASurfaceAttrib attrs[2] = {
1038         {
1039             .type  = VASurfaceAttribMemoryType,
1040             .flags = VA_SURFACE_ATTRIB_SETTABLE,
1041             .value.type    = VAGenericValueTypeInteger,
1042             .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
1043         },
1044         {
1045             .type  = VASurfaceAttribExternalBufferDescriptor,
1046             .flags = VA_SURFACE_ATTRIB_SETTABLE,
1047             .value.type    = VAGenericValueTypePointer,
1048             .value.value.p = &buffer_desc,
1049         }
1050     };
1051
1052     desc = (AVDRMFrameDescriptor*)src->data[0];
1053
1054     if (desc->nb_objects != 1) {
1055         av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames "
1056                "made from a single DRM object.\n");
1057         return AVERROR(EINVAL);
1058     }
1059
1060     va_fourcc = 0;
1061     for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1062         if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats)
1063             continue;
1064         for (j = 0; j < desc->nb_layers; j++) {
1065             if (desc->layers[j].format !=
1066                 vaapi_drm_format_map[i].layer_formats[j])
1067                 break;
1068         }
1069         if (j != desc->nb_layers)
1070             continue;
1071         va_fourcc = vaapi_drm_format_map[i].va_fourcc;
1072         break;
1073     }
1074     if (!va_fourcc) {
1075         av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported "
1076                "by VAAPI.\n");
1077         return AVERROR(EINVAL);
1078     }
1079
1080     av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as "
1081            "%08x.\n", desc->objects[0].fd, va_fourcc);
1082
1083     format_desc = vaapi_format_from_fourcc(va_fourcc);
1084     av_assert0(format_desc);
1085
1086     buffer_handle = desc->objects[0].fd;
1087     buffer_desc.pixel_format = va_fourcc;
1088     buffer_desc.width        = src_fc->width;
1089     buffer_desc.height       = src_fc->height;
1090     buffer_desc.data_size    = desc->objects[0].size;
1091     buffer_desc.buffers      = &buffer_handle;
1092     buffer_desc.num_buffers  = 1;
1093     buffer_desc.flags        = 0;
1094
1095     k = 0;
1096     for (i = 0; i < desc->nb_layers; i++) {
1097         for (j = 0; j < desc->layers[i].nb_planes; j++) {
1098             buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
1099             buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
1100             ++k;
1101         }
1102     }
1103     buffer_desc.num_planes = k;
1104
1105     if (format_desc->chroma_planes_swapped &&
1106         buffer_desc.num_planes == 3) {
1107         FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]);
1108         FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]);
1109     }
1110
1111     vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format,
1112                            src->width, src->height,
1113                            &surface_id, 1,
1114                            attrs, FF_ARRAY_ELEMS(attrs));
1115     if (vas != VA_STATUS_SUCCESS) {
1116         av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM "
1117                "object: %d (%s).\n", vas, vaErrorStr(vas));
1118         return AVERROR(EIO);
1119     }
1120     av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id);
1121
1122     err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
1123                                 &vaapi_unmap_from_drm,
1124                                 (void*)(uintptr_t)surface_id);
1125     if (err < 0)
1126         return err;
1127
1128     dst->width   = src->width;
1129     dst->height  = src->height;
1130     dst->data[3] = (uint8_t*)(uintptr_t)surface_id;
1131
1132     av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to "
1133            "surface %#x.\n", desc->objects[0].fd, surface_id);
1134
1135     return 0;
1136 }
1137
1138 #if VA_CHECK_VERSION(1, 1, 0)
1139 static void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc,
1140                                    HWMapDescriptor *hwmap)
1141 {
1142     AVDRMFrameDescriptor *drm_desc = hwmap->priv;
1143     int i;
1144
1145     for (i = 0; i < drm_desc->nb_objects; i++)
1146         close(drm_desc->objects[i].fd);
1147
1148     av_freep(&drm_desc);
1149 }
1150
1151 static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst,
1152                                 const AVFrame *src, int flags)
1153 {
1154     AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1155     VASurfaceID surface_id;
1156     VAStatus vas;
1157     VADRMPRIMESurfaceDescriptor va_desc;
1158     AVDRMFrameDescriptor *drm_desc = NULL;
1159     uint32_t export_flags;
1160     int err, i, j;
1161
1162     surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1163
1164     export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
1165     if (flags & AV_HWFRAME_MAP_READ)
1166         export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
1167     if (flags & AV_HWFRAME_MAP_WRITE)
1168         export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
1169
1170     vas = vaExportSurfaceHandle(hwctx->display, surface_id,
1171                                 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
1172                                 export_flags, &va_desc);
1173     if (vas != VA_STATUS_SUCCESS) {
1174         if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
1175             return AVERROR(ENOSYS);
1176         av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: "
1177                "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
1178         return AVERROR(EIO);
1179     }
1180
1181     drm_desc = av_mallocz(sizeof(*drm_desc));
1182     if (!drm_desc) {
1183         err = AVERROR(ENOMEM);
1184         goto fail;
1185     }
1186
1187     // By some bizarre coincidence, these structures are very similar...
1188     drm_desc->nb_objects = va_desc.num_objects;
1189     for (i = 0; i < va_desc.num_objects; i++) {
1190         drm_desc->objects[i].fd   = va_desc.objects[i].fd;
1191         drm_desc->objects[i].size = va_desc.objects[i].size;
1192         drm_desc->objects[i].format_modifier =
1193             va_desc.objects[i].drm_format_modifier;
1194     }
1195     drm_desc->nb_layers = va_desc.num_layers;
1196     for (i = 0; i < va_desc.num_layers; i++) {
1197         drm_desc->layers[i].format    = va_desc.layers[i].drm_format;
1198         drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes;
1199         for (j = 0; j < va_desc.layers[i].num_planes; j++) {
1200             drm_desc->layers[i].planes[j].object_index =
1201                 va_desc.layers[i].object_index[j];
1202             drm_desc->layers[i].planes[j].offset =
1203                 va_desc.layers[i].offset[j];
1204             drm_desc->layers[i].planes[j].pitch =
1205                 va_desc.layers[i].pitch[j];
1206         }
1207     }
1208
1209     err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
1210                                 &vaapi_unmap_to_drm_esh, drm_desc);
1211     if (err < 0)
1212         goto fail;
1213
1214     dst->width   = src->width;
1215     dst->height  = src->height;
1216     dst->data[0] = (uint8_t*)drm_desc;
1217
1218     return 0;
1219
1220 fail:
1221     for (i = 0; i < va_desc.num_objects; i++)
1222         close(va_desc.objects[i].fd);
1223     av_freep(&drm_desc);
1224     return err;
1225 }
1226 #endif
1227
1228 #if VA_CHECK_VERSION(0, 36, 0)
1229 typedef struct VAAPIDRMImageBufferMapping {
1230     VAImage      image;
1231     VABufferInfo buffer_info;
1232
1233     AVDRMFrameDescriptor drm_desc;
1234 } VAAPIDRMImageBufferMapping;
1235
1236 static void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc,
1237                                   HWMapDescriptor *hwmap)
1238 {
1239     AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1240     VAAPIDRMImageBufferMapping *mapping = hwmap->priv;
1241     VASurfaceID surface_id;
1242     VAStatus vas;
1243
1244     surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
1245     av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n",
1246            surface_id);
1247
1248     // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
1249     // so we shouldn't close them separately.
1250
1251     vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1252     if (vas != VA_STATUS_SUCCESS) {
1253         av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer "
1254                "handle of image %#x (derived from surface %#x): "
1255                "%d (%s).\n", mapping->image.buf, surface_id,
1256                vas, vaErrorStr(vas));
1257     }
1258
1259     vas = vaDestroyImage(hwctx->display, mapping->image.image_id);
1260     if (vas != VA_STATUS_SUCCESS) {
1261         av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image "
1262                "derived from surface %#x: %d (%s).\n",
1263                surface_id, vas, vaErrorStr(vas));
1264     }
1265
1266     av_free(mapping);
1267 }
1268
1269 static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst,
1270                                 const AVFrame *src, int flags)
1271 {
1272     AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1273     VAAPIDRMImageBufferMapping *mapping = NULL;
1274     VASurfaceID surface_id;
1275     VAStatus vas;
1276     int err, i, p;
1277
1278     surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1279     av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n",
1280            surface_id);
1281
1282     mapping = av_mallocz(sizeof(*mapping));
1283     if (!mapping)
1284         return AVERROR(ENOMEM);
1285
1286     vas = vaDeriveImage(hwctx->display, surface_id,
1287                         &mapping->image);
1288     if (vas != VA_STATUS_SUCCESS) {
1289         av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
1290                "surface %#x: %d (%s).\n",
1291                surface_id, vas, vaErrorStr(vas));
1292         err = AVERROR(EIO);
1293         goto fail;
1294     }
1295
1296     for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1297         if (vaapi_drm_format_map[i].va_fourcc ==
1298             mapping->image.format.fourcc)
1299             break;
1300     }
1301     if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) {
1302         av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for "
1303                "VAAPI format %#x.\n", mapping->image.format.fourcc);
1304         err = AVERROR(EINVAL);
1305         goto fail_derived;
1306     }
1307
1308     mapping->buffer_info.mem_type =
1309         VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
1310
1311     mapping->drm_desc.nb_layers =
1312         vaapi_drm_format_map[i].nb_layer_formats;
1313     if (mapping->drm_desc.nb_layers > 1) {
1314         if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
1315             av_log(hwfc, AV_LOG_ERROR, "Image properties do not match "
1316                    "expected format: got %d planes, but expected %d.\n",
1317                    mapping->image.num_planes, mapping->drm_desc.nb_layers);
1318             err = AVERROR(EINVAL);
1319             goto fail_derived;
1320         }
1321
1322         for(p = 0; p < mapping->drm_desc.nb_layers; p++) {
1323             mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) {
1324                 .format    = vaapi_drm_format_map[i].layer_formats[p],
1325                 .nb_planes = 1,
1326                 .planes[0] = {
1327                     .object_index = 0,
1328                     .offset       = mapping->image.offsets[p],
1329                     .pitch        = mapping->image.pitches[p],
1330                 },
1331             };
1332         }
1333     } else {
1334         mapping->drm_desc.layers[0].format =
1335             vaapi_drm_format_map[i].layer_formats[0];
1336         mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes;
1337         for (p = 0; p < mapping->image.num_planes; p++) {
1338             mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) {
1339                 .object_index = 0,
1340                 .offset       = mapping->image.offsets[p],
1341                 .pitch        = mapping->image.pitches[p],
1342             };
1343         }
1344     }
1345
1346     vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf,
1347                                 &mapping->buffer_info);
1348     if (vas != VA_STATUS_SUCCESS) {
1349         av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer "
1350                "handle from image %#x (derived from surface %#x): "
1351                "%d (%s).\n", mapping->image.buf, surface_id,
1352                vas, vaErrorStr(vas));
1353         err = AVERROR(EIO);
1354         goto fail_derived;
1355     }
1356
1357     av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
1358            mapping->buffer_info.handle);
1359
1360     mapping->drm_desc.nb_objects = 1;
1361     mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) {
1362         .fd   = mapping->buffer_info.handle,
1363         .size = mapping->image.data_size,
1364         // There is no way to get the format modifier with this API.
1365         .format_modifier = DRM_FORMAT_MOD_INVALID,
1366     };
1367
1368     err = ff_hwframe_map_create(src->hw_frames_ctx,
1369                                 dst, src, &vaapi_unmap_to_drm_abh,
1370                                 mapping);
1371     if (err < 0)
1372         goto fail_mapped;
1373
1374     dst->data[0] = (uint8_t*)&mapping->drm_desc;
1375     dst->width   = src->width;
1376     dst->height  = src->height;
1377
1378     return 0;
1379
1380 fail_mapped:
1381     vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1382 fail_derived:
1383     vaDestroyImage(hwctx->display, mapping->image.image_id);
1384 fail:
1385     av_freep(&mapping);
1386     return err;
1387 }
1388 #endif
1389
1390 static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
1391                             const AVFrame *src, int flags)
1392 {
1393 #if VA_CHECK_VERSION(1, 1, 0)
1394     int err;
1395     err = vaapi_map_to_drm_esh(hwfc, dst, src, flags);
1396     if (err != AVERROR(ENOSYS))
1397         return err;
1398 #endif
1399 #if VA_CHECK_VERSION(0, 36, 0)
1400     return vaapi_map_to_drm_abh(hwfc, dst, src, flags);
1401 #endif
1402     return AVERROR(ENOSYS);
1403 }
1404
1405 #endif /* CONFIG_LIBDRM */
1406
1407 static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
1408                         const AVFrame *src, int flags)
1409 {
1410     switch (src->format) {
1411 #if CONFIG_LIBDRM
1412     case AV_PIX_FMT_DRM_PRIME:
1413         return vaapi_map_from_drm(hwfc, dst, src, flags);
1414 #endif
1415     default:
1416         return AVERROR(ENOSYS);
1417     }
1418 }
1419
1420 static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
1421                           const AVFrame *src, int flags)
1422 {
1423     switch (dst->format) {
1424 #if CONFIG_LIBDRM
1425     case AV_PIX_FMT_DRM_PRIME:
1426         return vaapi_map_to_drm(hwfc, dst, src, flags);
1427 #endif
1428     default:
1429         return vaapi_map_to_memory(hwfc, dst, src, flags);
1430     }
1431 }
1432
1433 static void vaapi_device_free(AVHWDeviceContext *ctx)
1434 {
1435     AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1436     VAAPIDevicePriv      *priv  = ctx->user_opaque;
1437
1438     if (hwctx->display)
1439         vaTerminate(hwctx->display);
1440
1441 #if HAVE_VAAPI_X11
1442     if (priv->x11_display)
1443         XCloseDisplay(priv->x11_display);
1444 #endif
1445
1446     if (priv->drm_fd >= 0)
1447         close(priv->drm_fd);
1448
1449     av_freep(&priv);
1450 }
1451
1452 #if CONFIG_VAAPI_1
1453 static void vaapi_device_log_error(void *context, const char *message)
1454 {
1455     AVHWDeviceContext *ctx = context;
1456
1457     av_log(ctx, AV_LOG_ERROR, "libva: %s", message);
1458 }
1459
1460 static void vaapi_device_log_info(void *context, const char *message)
1461 {
1462     AVHWDeviceContext *ctx = context;
1463
1464     av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message);
1465 }
1466 #endif
1467
1468 static int vaapi_device_connect(AVHWDeviceContext *ctx,
1469                                 VADisplay display)
1470 {
1471     AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1472     int major, minor;
1473     VAStatus vas;
1474
1475 #if CONFIG_VAAPI_1
1476     vaSetErrorCallback(display, &vaapi_device_log_error, ctx);
1477     vaSetInfoCallback (display, &vaapi_device_log_info,  ctx);
1478 #endif
1479
1480     hwctx->display = display;
1481
1482     vas = vaInitialize(display, &major, &minor);
1483     if (vas != VA_STATUS_SUCCESS) {
1484         av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
1485                "connection: %d (%s).\n", vas, vaErrorStr(vas));
1486         return AVERROR(EIO);
1487     }
1488     av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
1489            "version %d.%d\n", major, minor);
1490
1491     return 0;
1492 }
1493
1494 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
1495                                AVDictionary *opts, int flags)
1496 {
1497     VAAPIDevicePriv *priv;
1498     VADisplay display = NULL;
1499     const AVDictionaryEntry *ent;
1500     int try_drm, try_x11, try_all;
1501
1502     priv = av_mallocz(sizeof(*priv));
1503     if (!priv)
1504         return AVERROR(ENOMEM);
1505
1506     priv->drm_fd = -1;
1507
1508     ctx->user_opaque = priv;
1509     ctx->free        = vaapi_device_free;
1510
1511     ent = av_dict_get(opts, "connection_type", NULL, 0);
1512     if (ent) {
1513         try_all = try_drm = try_x11 = 0;
1514         if (!strcmp(ent->value, "drm")) {
1515             try_drm = 1;
1516         } else if (!strcmp(ent->value, "x11")) {
1517             try_x11 = 1;
1518         } else {
1519             av_log(ctx, AV_LOG_ERROR, "Invalid connection type %s.\n",
1520                    ent->value);
1521             return AVERROR(EINVAL);
1522         }
1523     } else {
1524         try_all = 1;
1525         try_drm = HAVE_VAAPI_DRM;
1526         try_x11 = HAVE_VAAPI_X11;
1527     }
1528
1529 #if HAVE_VAAPI_DRM
1530     while (!display && try_drm) {
1531         // If the device is specified, try to open it as a DRM device node.
1532         // If not, look for a usable render node, possibly restricted to those
1533         // using a specified kernel driver.
1534         int loglevel = try_all ? AV_LOG_VERBOSE : AV_LOG_ERROR;
1535         if (device) {
1536             priv->drm_fd = open(device, O_RDWR);
1537             if (priv->drm_fd < 0) {
1538                 av_log(ctx, loglevel, "Failed to open %s as "
1539                        "DRM device node.\n", device);
1540                 break;
1541             }
1542         } else {
1543             char path[64];
1544             int n, max_devices = 8;
1545 #if CONFIG_LIBDRM
1546             const AVDictionaryEntry *kernel_driver;
1547             kernel_driver = av_dict_get(opts, "kernel_driver", NULL, 0);
1548 #endif
1549             for (n = 0; n < max_devices; n++) {
1550                 snprintf(path, sizeof(path),
1551                          "/dev/dri/renderD%d", 128 + n);
1552                 priv->drm_fd = open(path, O_RDWR);
1553                 if (priv->drm_fd < 0) {
1554                     av_log(ctx, AV_LOG_VERBOSE, "Cannot open "
1555                            "DRM render node for device %d.\n", n);
1556                     break;
1557                 }
1558 #if CONFIG_LIBDRM
1559                 if (kernel_driver) {
1560                     drmVersion *info;
1561                     info = drmGetVersion(priv->drm_fd);
1562                     if (strcmp(kernel_driver->value, info->name)) {
1563                         av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d "
1564                                "with non-matching kernel driver (%s).\n",
1565                                n, info->name);
1566                         drmFreeVersion(info);
1567                         close(priv->drm_fd);
1568                         priv->drm_fd = -1;
1569                         continue;
1570                     }
1571                     av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
1572                            "DRM render node for device %d, "
1573                            "with matching kernel driver (%s).\n",
1574                            n, info->name);
1575                     drmFreeVersion(info);
1576                 } else
1577 #endif
1578                 {
1579                     av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
1580                            "DRM render node for device %d.\n", n);
1581                 }
1582                 break;
1583             }
1584             if (n >= max_devices)
1585                 break;
1586         }
1587
1588         display = vaGetDisplayDRM(priv->drm_fd);
1589         if (!display) {
1590             av_log(ctx, AV_LOG_VERBOSE, "Cannot open a VA display "
1591                    "from DRM device %s.\n", device);
1592             return AVERROR_EXTERNAL;
1593         }
1594         break;
1595     }
1596 #endif
1597
1598 #if HAVE_VAAPI_X11
1599     if (!display && try_x11) {
1600         // Try to open the device as an X11 display.
1601         priv->x11_display = XOpenDisplay(device);
1602         if (!priv->x11_display) {
1603             av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
1604                    "%s.\n", XDisplayName(device));
1605         } else {
1606             display = vaGetDisplay(priv->x11_display);
1607             if (!display) {
1608                 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
1609                        "from X11 display %s.\n", XDisplayName(device));
1610                 return AVERROR_UNKNOWN;
1611             }
1612
1613             av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
1614                    "X11 display %s.\n", XDisplayName(device));
1615         }
1616     }
1617 #endif
1618
1619     if (!display) {
1620         if (device)
1621             av_log(ctx, AV_LOG_ERROR, "No VA display found for "
1622                    "device %s.\n", device);
1623         else
1624             av_log(ctx, AV_LOG_ERROR, "No VA display found for "
1625                    "any default device.\n");
1626         return AVERROR(EINVAL);
1627     }
1628
1629     ent = av_dict_get(opts, "driver", NULL, 0);
1630     if (ent) {
1631 #if VA_CHECK_VERSION(0, 38, 0)
1632         VAStatus vas;
1633         vas = vaSetDriverName(display, ent->value);
1634         if (vas != VA_STATUS_SUCCESS) {
1635             av_log(ctx, AV_LOG_ERROR, "Failed to set driver name to "
1636                    "%s: %d (%s).\n", ent->value, vas, vaErrorStr(vas));
1637             vaTerminate(display);
1638             return AVERROR_EXTERNAL;
1639         }
1640 #else
1641         av_log(ctx, AV_LOG_WARNING, "Driver name setting is not "
1642                "supported with this VAAPI version.\n");
1643 #endif
1644     }
1645
1646     return vaapi_device_connect(ctx, display);
1647 }
1648
1649 static int vaapi_device_derive(AVHWDeviceContext *ctx,
1650                                AVHWDeviceContext *src_ctx,
1651                                AVDictionary *opts, int flags)
1652 {
1653 #if HAVE_VAAPI_DRM
1654     if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) {
1655         AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
1656         VADisplay *display;
1657         VAAPIDevicePriv *priv;
1658         int fd;
1659
1660         if (src_hwctx->fd < 0) {
1661             av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated "
1662                    "device to derive a VA display from.\n");
1663             return AVERROR(EINVAL);
1664         }
1665
1666 #if CONFIG_LIBDRM
1667         {
1668             int node_type = drmGetNodeTypeFromFd(src_hwctx->fd);
1669             char *render_node;
1670             if (node_type < 0) {
1671                 av_log(ctx, AV_LOG_ERROR, "DRM instance fd does not appear "
1672                        "to refer to a DRM device.\n");
1673                 return AVERROR(EINVAL);
1674             }
1675             if (node_type == DRM_NODE_RENDER) {
1676                 fd = src_hwctx->fd;
1677             } else {
1678                 render_node = drmGetRenderDeviceNameFromFd(src_hwctx->fd);
1679                 if (!render_node) {
1680                     av_log(ctx, AV_LOG_VERBOSE, "Using non-render node "
1681                            "because the device does not have an "
1682                            "associated render node.\n");
1683                     fd = src_hwctx->fd;
1684                 } else {
1685                     fd = open(render_node, O_RDWR);
1686                     if (fd < 0) {
1687                         av_log(ctx, AV_LOG_VERBOSE, "Using non-render node "
1688                                "because the associated render node "
1689                                "could not be opened.\n");
1690                         fd = src_hwctx->fd;
1691                     } else {
1692                         av_log(ctx, AV_LOG_VERBOSE, "Using render node %s "
1693                                "in place of non-render DRM device.\n",
1694                                render_node);
1695                     }
1696                     free(render_node);
1697                 }
1698             }
1699         }
1700 #else
1701         fd = src_hwctx->fd;
1702 #endif
1703
1704         priv = av_mallocz(sizeof(*priv));
1705         if (!priv) {
1706             if (fd != src_hwctx->fd) {
1707                 // The fd was opened in this function.
1708                 close(fd);
1709             }
1710             return AVERROR(ENOMEM);
1711         }
1712
1713         if (fd == src_hwctx->fd) {
1714             // The fd is inherited from the source context and we are holding
1715             // a reference to that, we don't want to close it from here.
1716             priv->drm_fd = -1;
1717         } else {
1718             priv->drm_fd = fd;
1719         }
1720
1721         ctx->user_opaque = priv;
1722         ctx->free        = &vaapi_device_free;
1723
1724         display = vaGetDisplayDRM(fd);
1725         if (!display) {
1726             av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from "
1727                    "DRM device.\n");
1728             return AVERROR(EIO);
1729         }
1730
1731         return vaapi_device_connect(ctx, display);
1732     }
1733 #endif
1734     return AVERROR(ENOSYS);
1735 }
1736
1737 const HWContextType ff_hwcontext_type_vaapi = {
1738     .type                   = AV_HWDEVICE_TYPE_VAAPI,
1739     .name                   = "VAAPI",
1740
1741     .device_hwctx_size      = sizeof(AVVAAPIDeviceContext),
1742     .device_priv_size       = sizeof(VAAPIDeviceContext),
1743     .device_hwconfig_size   = sizeof(AVVAAPIHWConfig),
1744     .frames_hwctx_size      = sizeof(AVVAAPIFramesContext),
1745     .frames_priv_size       = sizeof(VAAPIFramesContext),
1746
1747     .device_create          = &vaapi_device_create,
1748     .device_derive          = &vaapi_device_derive,
1749     .device_init            = &vaapi_device_init,
1750     .device_uninit          = &vaapi_device_uninit,
1751     .frames_get_constraints = &vaapi_frames_get_constraints,
1752     .frames_init            = &vaapi_frames_init,
1753     .frames_uninit          = &vaapi_frames_uninit,
1754     .frames_get_buffer      = &vaapi_get_buffer,
1755     .transfer_get_formats   = &vaapi_transfer_get_formats,
1756     .transfer_data_to       = &vaapi_transfer_data_to,
1757     .transfer_data_from     = &vaapi_transfer_data_from,
1758     .map_to                 = &vaapi_map_to,
1759     .map_from               = &vaapi_map_from,
1760
1761     .pix_fmts = (const enum AVPixelFormat[]) {
1762         AV_PIX_FMT_VAAPI,
1763         AV_PIX_FMT_NONE
1764     },
1765 };