FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hwcontext_vaapi.c
Go to the documentation of this file.
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 <drm_fourcc.h>
31 # ifndef DRM_FORMAT_MOD_INVALID
32 # define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
33 # endif
34 #endif
35 
36 #include <fcntl.h>
37 #if HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40 
41 
42 #include "avassert.h"
43 #include "buffer.h"
44 #include "common.h"
45 #include "hwcontext.h"
46 #include "hwcontext_drm.h"
47 #include "hwcontext_internal.h"
48 #include "hwcontext_vaapi.h"
49 #include "mem.h"
50 #include "pixdesc.h"
51 #include "pixfmt.h"
52 
53 
54 typedef struct VAAPIDevicePriv {
55 #if HAVE_VAAPI_X11
56  Display *x11_display;
57 #endif
58 
59  int drm_fd;
61 
62 typedef struct VAAPISurfaceFormat {
64  VAImageFormat image_format;
66 
67 typedef struct VAAPIDeviceContext {
68  // Surface formats which can be used with this device.
72 
73 typedef struct VAAPIFramesContext {
74  // Surface attributes set at create time.
75  VASurfaceAttrib *attributes;
77  // RT format of the underlying surface (Intel driver ignores this anyway).
78  unsigned int rt_format;
79  // Whether vaDeriveImage works.
82 
83 typedef struct VAAPIMapping {
84  // Handle to the derived or copied image which is mapped.
85  VAImage image;
86  // The mapping flags actually used.
87  int flags;
88 } VAAPIMapping;
89 
90 #define MAP(va, rt, av) { \
91  VA_FOURCC_ ## va, \
92  VA_RT_FORMAT_ ## rt, \
93  AV_PIX_FMT_ ## av \
94  }
95 // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
96 // plane swap cases. The frame handling below tries to hide these.
97 static const struct {
98  unsigned int fourcc;
99  unsigned int rt_format;
101 } vaapi_format_map[] = {
102  MAP(NV12, YUV420, NV12),
103  MAP(YV12, YUV420, YUV420P), // With U/V planes swapped.
104  MAP(IYUV, YUV420, YUV420P),
105 #ifdef VA_FOURCC_I420
106  MAP(I420, YUV420, YUV420P),
107 #endif
108 #ifdef VA_FOURCC_YV16
109  MAP(YV16, YUV422, YUV422P), // With U/V planes swapped.
110 #endif
111  MAP(422H, YUV422, YUV422P),
112  MAP(UYVY, YUV422, UYVY422),
113  MAP(YUY2, YUV422, YUYV422),
114  MAP(411P, YUV411, YUV411P),
115  MAP(422V, YUV422, YUV440P),
116  MAP(444P, YUV444, YUV444P),
117  MAP(Y800, YUV400, GRAY8),
118 #ifdef VA_FOURCC_P010
119  MAP(P010, YUV420_10BPP, P010),
120 #endif
121  MAP(BGRA, RGB32, BGRA),
122  MAP(BGRX, RGB32, BGR0),
123  MAP(RGBA, RGB32, RGBA),
124  MAP(RGBX, RGB32, RGB0),
125 #ifdef VA_FOURCC_ABGR
126  MAP(ABGR, RGB32, ABGR),
127  MAP(XBGR, RGB32, 0BGR),
128 #endif
129  MAP(ARGB, RGB32, ARGB),
130  MAP(XRGB, RGB32, 0RGB),
131 };
132 #undef MAP
133 
135 {
136  int i;
137  for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
138  if (vaapi_format_map[i].fourcc == fourcc)
139  return vaapi_format_map[i].pix_fmt;
140  return AV_PIX_FMT_NONE;
141 }
142 
144  enum AVPixelFormat pix_fmt,
145  VAImageFormat **image_format)
146 {
147  VAAPIDeviceContext *ctx = hwdev->internal->priv;
148  int i;
149 
150  for (i = 0; i < ctx->nb_formats; i++) {
151  if (ctx->formats[i].pix_fmt == pix_fmt) {
152  if (image_format)
153  *image_format = &ctx->formats[i].image_format;
154  return 0;
155  }
156  }
157  return AVERROR(EINVAL);
158 }
159 
161  const void *hwconfig,
162  AVHWFramesConstraints *constraints)
163 {
164  AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
165  const AVVAAPIHWConfig *config = hwconfig;
166  VAAPIDeviceContext *ctx = hwdev->internal->priv;
167  VASurfaceAttrib *attr_list = NULL;
168  VAStatus vas;
169  enum AVPixelFormat pix_fmt;
170  unsigned int fourcc;
171  int err, i, j, attr_count, pix_fmt_count;
172 
173  if (config &&
175  attr_count = 0;
176  vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
177  0, &attr_count);
178  if (vas != VA_STATUS_SUCCESS) {
179  av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
180  "%d (%s).\n", vas, vaErrorStr(vas));
181  err = AVERROR(ENOSYS);
182  goto fail;
183  }
184 
185  attr_list = av_malloc(attr_count * sizeof(*attr_list));
186  if (!attr_list) {
187  err = AVERROR(ENOMEM);
188  goto fail;
189  }
190 
191  vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
192  attr_list, &attr_count);
193  if (vas != VA_STATUS_SUCCESS) {
194  av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
195  "%d (%s).\n", vas, vaErrorStr(vas));
196  err = AVERROR(ENOSYS);
197  goto fail;
198  }
199 
200  pix_fmt_count = 0;
201  for (i = 0; i < attr_count; i++) {
202  switch (attr_list[i].type) {
203  case VASurfaceAttribPixelFormat:
204  fourcc = attr_list[i].value.value.i;
205  pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
206  if (pix_fmt != AV_PIX_FMT_NONE) {
207  ++pix_fmt_count;
208  } else {
209  // Something unsupported - ignore.
210  }
211  break;
212  case VASurfaceAttribMinWidth:
213  constraints->min_width = attr_list[i].value.value.i;
214  break;
215  case VASurfaceAttribMinHeight:
216  constraints->min_height = attr_list[i].value.value.i;
217  break;
218  case VASurfaceAttribMaxWidth:
219  constraints->max_width = attr_list[i].value.value.i;
220  break;
221  case VASurfaceAttribMaxHeight:
222  constraints->max_height = attr_list[i].value.value.i;
223  break;
224  }
225  }
226  if (pix_fmt_count == 0) {
227  // Nothing usable found. Presumably there exists something which
228  // works, so leave the set null to indicate unknown.
229  constraints->valid_sw_formats = NULL;
230  } else {
231  constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
232  sizeof(pix_fmt));
233  if (!constraints->valid_sw_formats) {
234  err = AVERROR(ENOMEM);
235  goto fail;
236  }
237 
238  for (i = j = 0; i < attr_count; i++) {
239  if (attr_list[i].type != VASurfaceAttribPixelFormat)
240  continue;
241  fourcc = attr_list[i].value.value.i;
242  pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
243  if (pix_fmt != AV_PIX_FMT_NONE)
244  constraints->valid_sw_formats[j++] = pix_fmt;
245  }
246  av_assert0(j == pix_fmt_count);
247  constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
248  }
249  } else {
250  // No configuration supplied.
251  // Return the full set of image formats known by the implementation.
252  constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
253  sizeof(pix_fmt));
254  if (!constraints->valid_sw_formats) {
255  err = AVERROR(ENOMEM);
256  goto fail;
257  }
258  for (i = 0; i < ctx->nb_formats; i++)
259  constraints->valid_sw_formats[i] = ctx->formats[i].pix_fmt;
260  constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE;
261  }
262 
263  constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
264  if (!constraints->valid_hw_formats) {
265  err = AVERROR(ENOMEM);
266  goto fail;
267  }
268  constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
269  constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
270 
271  err = 0;
272 fail:
273  av_freep(&attr_list);
274  return err;
275 }
276 
277 static const struct {
278  const char *friendly_name;
279  const char *match_string;
280  unsigned int quirks;
282  {
283  "Intel i965 (Quick Sync)",
284  "i965",
286  },
287  {
288  "Intel iHD",
289  "ubit",
291  },
292  {
293  "VDPAU wrapper",
294  "Splitted-Desktop Systems VDPAU backend for VA-API",
296  },
297 };
298 
300 {
301  VAAPIDeviceContext *ctx = hwdev->internal->priv;
302  AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
303  VAImageFormat *image_list = NULL;
304  VAStatus vas;
305  const char *vendor_string;
306  int err, i, image_count;
307  enum AVPixelFormat pix_fmt;
308  unsigned int fourcc;
309 
310  image_count = vaMaxNumImageFormats(hwctx->display);
311  if (image_count <= 0) {
312  err = AVERROR(EIO);
313  goto fail;
314  }
315  image_list = av_malloc(image_count * sizeof(*image_list));
316  if (!image_list) {
317  err = AVERROR(ENOMEM);
318  goto fail;
319  }
320  vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
321  if (vas != VA_STATUS_SUCCESS) {
322  err = AVERROR(EIO);
323  goto fail;
324  }
325 
326  ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
327  if (!ctx->formats) {
328  err = AVERROR(ENOMEM);
329  goto fail;
330  }
331  ctx->nb_formats = 0;
332  for (i = 0; i < image_count; i++) {
333  fourcc = image_list[i].fourcc;
334  pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
335  if (pix_fmt == AV_PIX_FMT_NONE) {
336  av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
337  fourcc);
338  } else {
339  av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
340  fourcc, av_get_pix_fmt_name(pix_fmt));
341  ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
342  ctx->formats[ctx->nb_formats].image_format = image_list[i];
343  ++ctx->nb_formats;
344  }
345  }
346 
348  av_log(hwdev, AV_LOG_VERBOSE, "Not detecting driver: "
349  "quirks set by user.\n");
350  } else {
351  // Detect the driver in use and set quirk flags if necessary.
352  vendor_string = vaQueryVendorString(hwctx->display);
353  hwctx->driver_quirks = 0;
354  if (vendor_string) {
355  for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
356  if (strstr(vendor_string,
358  av_log(hwdev, AV_LOG_VERBOSE, "Matched \"%s\" as known "
359  "driver \"%s\".\n", vendor_string,
361  hwctx->driver_quirks |=
362  vaapi_driver_quirks_table[i].quirks;
363  break;
364  }
365  }
367  av_log(hwdev, AV_LOG_VERBOSE, "Unknown driver \"%s\", "
368  "assuming standard behaviour.\n", vendor_string);
369  }
370  }
371  }
372 
373  av_free(image_list);
374  return 0;
375 fail:
376  av_freep(&ctx->formats);
377  av_free(image_list);
378  return err;
379 }
380 
382 {
383  VAAPIDeviceContext *ctx = hwdev->internal->priv;
384 
385  av_freep(&ctx->formats);
386 }
387 
388 static void vaapi_buffer_free(void *opaque, uint8_t *data)
389 {
390  AVHWFramesContext *hwfc = opaque;
391  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
392  VASurfaceID surface_id;
393  VAStatus vas;
394 
395  surface_id = (VASurfaceID)(uintptr_t)data;
396 
397  vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
398  if (vas != VA_STATUS_SUCCESS) {
399  av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
400  "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
401  }
402 }
403 
404 static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
405 {
406  AVHWFramesContext *hwfc = opaque;
408  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
409  AVVAAPIFramesContext *avfc = hwfc->hwctx;
410  VASurfaceID surface_id;
411  VAStatus vas;
412  AVBufferRef *ref;
413 
414  if (hwfc->initial_pool_size > 0 &&
415  avfc->nb_surfaces >= hwfc->initial_pool_size)
416  return NULL;
417 
418  vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
419  hwfc->width, hwfc->height,
420  &surface_id, 1,
421  ctx->attributes, ctx->nb_attributes);
422  if (vas != VA_STATUS_SUCCESS) {
423  av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
424  "%d (%s).\n", vas, vaErrorStr(vas));
425  return NULL;
426  }
427  av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
428 
429  ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
430  sizeof(surface_id), &vaapi_buffer_free,
432  if (!ref) {
433  vaDestroySurfaces(hwctx->display, &surface_id, 1);
434  return NULL;
435  }
436 
437  if (hwfc->initial_pool_size > 0) {
438  // This is a fixed-size pool, so we must still be in the initial
439  // allocation sequence.
441  avfc->surface_ids[avfc->nb_surfaces] = surface_id;
442  ++avfc->nb_surfaces;
443  }
444 
445  return ref;
446 }
447 
449 {
450  AVVAAPIFramesContext *avfc = hwfc->hwctx;
452  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
453  VAImageFormat *expected_format;
454  AVBufferRef *test_surface = NULL;
455  VASurfaceID test_surface_id;
456  VAImage test_image;
457  VAStatus vas;
458  int err, i;
459  unsigned int fourcc, rt_format;
460 
461  for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
462  if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) {
463  fourcc = vaapi_format_map[i].fourcc;
464  rt_format = vaapi_format_map[i].rt_format;
465  break;
466  }
467  }
468  if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
469  av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
471  return AVERROR(EINVAL);
472  }
473 
474  if (!hwfc->pool) {
476  int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
477  int need_pixel_format = 1;
478  for (i = 0; i < avfc->nb_attributes; i++) {
479  if (avfc->attributes[i].type == VASurfaceAttribMemoryType)
480  need_memory_type = 0;
481  if (avfc->attributes[i].type == VASurfaceAttribPixelFormat)
482  need_pixel_format = 0;
483  }
484  ctx->nb_attributes =
485  avfc->nb_attributes + need_memory_type + need_pixel_format;
486 
487  ctx->attributes = av_malloc(ctx->nb_attributes *
488  sizeof(*ctx->attributes));
489  if (!ctx->attributes) {
490  err = AVERROR(ENOMEM);
491  goto fail;
492  }
493 
494  for (i = 0; i < avfc->nb_attributes; i++)
495  ctx->attributes[i] = avfc->attributes[i];
496  if (need_memory_type) {
497  ctx->attributes[i++] = (VASurfaceAttrib) {
498  .type = VASurfaceAttribMemoryType,
499  .flags = VA_SURFACE_ATTRIB_SETTABLE,
500  .value.type = VAGenericValueTypeInteger,
501  .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
502  };
503  }
504  if (need_pixel_format) {
505  ctx->attributes[i++] = (VASurfaceAttrib) {
506  .type = VASurfaceAttribPixelFormat,
507  .flags = VA_SURFACE_ATTRIB_SETTABLE,
508  .value.type = VAGenericValueTypeInteger,
509  .value.value.i = fourcc,
510  };
511  }
512  av_assert0(i == ctx->nb_attributes);
513  } else {
514  ctx->attributes = NULL;
515  ctx->nb_attributes = 0;
516  }
517 
518  ctx->rt_format = rt_format;
519 
520  if (hwfc->initial_pool_size > 0) {
521  // This pool will be usable as a render target, so we need to store
522  // all of the surface IDs somewhere that vaCreateContext() calls
523  // will be able to access them.
524  avfc->nb_surfaces = 0;
525  avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
526  sizeof(*avfc->surface_ids));
527  if (!avfc->surface_ids) {
528  err = AVERROR(ENOMEM);
529  goto fail;
530  }
531  } else {
532  // This pool allows dynamic sizing, and will not be usable as a
533  // render target.
534  avfc->nb_surfaces = 0;
535  avfc->surface_ids = NULL;
536  }
537 
538  hwfc->internal->pool_internal =
539  av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
541  if (!hwfc->internal->pool_internal) {
542  av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
543  err = AVERROR(ENOMEM);
544  goto fail;
545  }
546  }
547 
548  // Allocate a single surface to test whether vaDeriveImage() is going
549  // to work for the specific configuration.
550  if (hwfc->pool) {
551  test_surface = av_buffer_pool_get(hwfc->pool);
552  if (!test_surface) {
553  av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
554  "user-configured buffer pool.\n");
555  err = AVERROR(ENOMEM);
556  goto fail;
557  }
558  } else {
559  test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
560  if (!test_surface) {
561  av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
562  "internal buffer pool.\n");
563  err = AVERROR(ENOMEM);
564  goto fail;
565  }
566  }
567  test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
568 
569  ctx->derive_works = 0;
570 
572  hwfc->sw_format, &expected_format);
573  if (err == 0) {
574  vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
575  if (vas == VA_STATUS_SUCCESS) {
576  if (expected_format->fourcc == test_image.format.fourcc) {
577  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
578  ctx->derive_works = 1;
579  } else {
580  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
581  "derived image format %08x does not match "
582  "expected format %08x.\n",
583  expected_format->fourcc, test_image.format.fourcc);
584  }
585  vaDestroyImage(hwctx->display, test_image.image_id);
586  } else {
587  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
588  "deriving image does not work: "
589  "%d (%s).\n", vas, vaErrorStr(vas));
590  }
591  } else {
592  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
593  "image format is not supported.\n");
594  }
595 
596  av_buffer_unref(&test_surface);
597  return 0;
598 
599 fail:
600  av_buffer_unref(&test_surface);
601  av_freep(&avfc->surface_ids);
602  av_freep(&ctx->attributes);
603  return err;
604 }
605 
607 {
608  AVVAAPIFramesContext *avfc = hwfc->hwctx;
610 
611  av_freep(&avfc->surface_ids);
612  av_freep(&ctx->attributes);
613 }
614 
616 {
617  frame->buf[0] = av_buffer_pool_get(hwfc->pool);
618  if (!frame->buf[0])
619  return AVERROR(ENOMEM);
620 
621  frame->data[3] = frame->buf[0]->data;
622  frame->format = AV_PIX_FMT_VAAPI;
623  frame->width = hwfc->width;
624  frame->height = hwfc->height;
625 
626  return 0;
627 }
628 
631  enum AVPixelFormat **formats)
632 {
634  enum AVPixelFormat *pix_fmts;
635  int i, k, sw_format_available;
636 
637  sw_format_available = 0;
638  for (i = 0; i < ctx->nb_formats; i++) {
639  if (ctx->formats[i].pix_fmt == hwfc->sw_format)
640  sw_format_available = 1;
641  }
642 
643  pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
644  if (!pix_fmts)
645  return AVERROR(ENOMEM);
646 
647  if (sw_format_available) {
648  pix_fmts[0] = hwfc->sw_format;
649  k = 1;
650  } else {
651  k = 0;
652  }
653  for (i = 0; i < ctx->nb_formats; i++) {
654  if (ctx->formats[i].pix_fmt == hwfc->sw_format)
655  continue;
656  av_assert0(k < ctx->nb_formats);
657  pix_fmts[k++] = ctx->formats[i].pix_fmt;
658  }
659  pix_fmts[k] = AV_PIX_FMT_NONE;
660 
661  *formats = pix_fmts;
662  return 0;
663 }
664 
666  HWMapDescriptor *hwmap)
667 {
668  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
669  VAAPIMapping *map = hwmap->priv;
670  VASurfaceID surface_id;
671  VAStatus vas;
672 
673  surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
674  av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
675 
676  vas = vaUnmapBuffer(hwctx->display, map->image.buf);
677  if (vas != VA_STATUS_SUCCESS) {
678  av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
679  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
680  }
681 
682  if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
683  !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
684  vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
685  0, 0, hwfc->width, hwfc->height,
686  0, 0, hwfc->width, hwfc->height);
687  if (vas != VA_STATUS_SUCCESS) {
688  av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
689  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
690  }
691  }
692 
693  vas = vaDestroyImage(hwctx->display, map->image.image_id);
694  if (vas != VA_STATUS_SUCCESS) {
695  av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
696  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
697  }
698 
699  av_free(map);
700 }
701 
703  AVFrame *dst, const AVFrame *src, int flags)
704 {
705  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
707  VASurfaceID surface_id;
708  VAImageFormat *image_format;
709  VAAPIMapping *map;
710  VAStatus vas;
711  void *address = NULL;
712  int err, i;
713 
714  surface_id = (VASurfaceID)(uintptr_t)src->data[3];
715  av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
716 
717  if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
718  // Requested direct mapping but it is not possible.
719  return AVERROR(EINVAL);
720  }
721  if (dst->format == AV_PIX_FMT_NONE)
722  dst->format = hwfc->sw_format;
723  if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
724  // Requested direct mapping but the formats do not match.
725  return AVERROR(EINVAL);
726  }
727 
728  err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
729  if (err < 0) {
730  // Requested format is not a valid output format.
731  return AVERROR(EINVAL);
732  }
733 
734  map = av_malloc(sizeof(*map));
735  if (!map)
736  return AVERROR(ENOMEM);
737  map->flags = flags;
738  map->image.image_id = VA_INVALID_ID;
739 
740  vas = vaSyncSurface(hwctx->display, surface_id);
741  if (vas != VA_STATUS_SUCCESS) {
742  av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
743  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
744  err = AVERROR(EIO);
745  goto fail;
746  }
747 
748  // The memory which we map using derive need not be connected to the CPU
749  // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
750  // memory is mappable but not cached, so normal memcpy()-like access is
751  // very slow to read it (but writing is ok). It is possible to read much
752  // faster with a copy routine which is aware of the limitation, but we
753  // assume for now that the user is not aware of that and would therefore
754  // prefer not to be given direct-mapped memory if they request read access.
755  if (ctx->derive_works && dst->format == hwfc->sw_format &&
756  ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
757  vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
758  if (vas != VA_STATUS_SUCCESS) {
759  av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
760  "surface %#x: %d (%s).\n",
761  surface_id, vas, vaErrorStr(vas));
762  err = AVERROR(EIO);
763  goto fail;
764  }
765  if (map->image.format.fourcc != image_format->fourcc) {
766  av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
767  "is in wrong format: expected %#08x, got %#08x.\n",
768  surface_id, image_format->fourcc, map->image.format.fourcc);
769  err = AVERROR(EIO);
770  goto fail;
771  }
773  } else {
774  vas = vaCreateImage(hwctx->display, image_format,
775  hwfc->width, hwfc->height, &map->image);
776  if (vas != VA_STATUS_SUCCESS) {
777  av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
778  "surface %#x: %d (%s).\n",
779  surface_id, vas, vaErrorStr(vas));
780  err = AVERROR(EIO);
781  goto fail;
782  }
783  if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
784  vas = vaGetImage(hwctx->display, surface_id, 0, 0,
785  hwfc->width, hwfc->height, map->image.image_id);
786  if (vas != VA_STATUS_SUCCESS) {
787  av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
788  "surface %#x: %d (%s).\n",
789  surface_id, vas, vaErrorStr(vas));
790  err = AVERROR(EIO);
791  goto fail;
792  }
793  }
794  }
795 
796  vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
797  if (vas != VA_STATUS_SUCCESS) {
798  av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
799  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
800  err = AVERROR(EIO);
801  goto fail;
802  }
803 
805  dst, src, &vaapi_unmap_frame, map);
806  if (err < 0)
807  goto fail;
808 
809  dst->width = src->width;
810  dst->height = src->height;
811 
812  for (i = 0; i < map->image.num_planes; i++) {
813  dst->data[i] = (uint8_t*)address + map->image.offsets[i];
814  dst->linesize[i] = map->image.pitches[i];
815  }
816  if (
817 #ifdef VA_FOURCC_YV16
818  map->image.format.fourcc == VA_FOURCC_YV16 ||
819 #endif
820  map->image.format.fourcc == VA_FOURCC_YV12) {
821  // Chroma planes are YVU rather than YUV, so swap them.
822  FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
823  }
824 
825  return 0;
826 
827 fail:
828  if (map) {
829  if (address)
830  vaUnmapBuffer(hwctx->display, map->image.buf);
831  if (map->image.image_id != VA_INVALID_ID)
832  vaDestroyImage(hwctx->display, map->image.image_id);
833  av_free(map);
834  }
835  return err;
836 }
837 
839  AVFrame *dst, const AVFrame *src)
840 {
841  AVFrame *map;
842  int err;
843 
844  if (dst->width > hwfc->width || dst->height > hwfc->height)
845  return AVERROR(EINVAL);
846 
847  map = av_frame_alloc();
848  if (!map)
849  return AVERROR(ENOMEM);
850  map->format = dst->format;
851 
852  err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
853  if (err)
854  goto fail;
855 
856  map->width = dst->width;
857  map->height = dst->height;
858 
859  err = av_frame_copy(dst, map);
860  if (err)
861  goto fail;
862 
863  err = 0;
864 fail:
865  av_frame_free(&map);
866  return err;
867 }
868 
870  AVFrame *dst, const AVFrame *src)
871 {
872  AVFrame *map;
873  int err;
874 
875  if (src->width > hwfc->width || src->height > hwfc->height)
876  return AVERROR(EINVAL);
877 
878  map = av_frame_alloc();
879  if (!map)
880  return AVERROR(ENOMEM);
881  map->format = src->format;
882 
884  if (err)
885  goto fail;
886 
887  map->width = src->width;
888  map->height = src->height;
889 
890  err = av_frame_copy(map, src);
891  if (err)
892  goto fail;
893 
894  err = 0;
895 fail:
896  av_frame_free(&map);
897  return err;
898 }
899 
901  const AVFrame *src, int flags)
902 {
903  int err;
904 
905  if (dst->format != AV_PIX_FMT_NONE) {
906  err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
907  if (err < 0)
908  return AVERROR(ENOSYS);
909  }
910 
911  err = vaapi_map_frame(hwfc, dst, src, flags);
912  if (err)
913  return err;
914 
915  err = av_frame_copy_props(dst, src);
916  if (err)
917  return err;
918 
919  return 0;
920 }
921 
922 #if CONFIG_LIBDRM
923 
924 #define DRM_MAP(va, layers, ...) { \
925  VA_FOURCC_ ## va, \
926  layers, \
927  { __VA_ARGS__ } \
928  }
929 static const struct {
930  uint32_t va_fourcc;
931  int nb_layer_formats;
932  uint32_t layer_formats[AV_DRM_MAX_PLANES];
933 } vaapi_drm_format_map[] = {
934 #ifdef DRM_FORMAT_R8
935  DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88),
936 #endif
937  DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
938 #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
939  DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
940 #endif
941  DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
942  DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
943  DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888),
944  DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888),
945 #ifdef VA_FOURCC_ABGR
946  DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888),
947  DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888),
948 #endif
949  DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
950  DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
951 };
952 #undef DRM_MAP
953 
954 static void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc,
955  HWMapDescriptor *hwmap)
956 {
957  AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
958 
959  VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv;
960 
961  av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id);
962 
963  vaDestroySurfaces(dst_dev->display, &surface_id, 1);
964 }
965 
966 static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst,
967  const AVFrame *src, int flags)
968 {
969  AVHWFramesContext *dst_fc =
971  AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
972  const AVDRMFrameDescriptor *desc;
973  VASurfaceID surface_id;
974  VAStatus vas;
975  uint32_t va_fourcc, va_rt_format;
976  int err, i, j, k;
977 
978  unsigned long buffer_handle;
979  VASurfaceAttribExternalBuffers buffer_desc;
980  VASurfaceAttrib attrs[2] = {
981  {
982  .type = VASurfaceAttribMemoryType,
983  .flags = VA_SURFACE_ATTRIB_SETTABLE,
984  .value.type = VAGenericValueTypeInteger,
985  .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
986  },
987  {
988  .type = VASurfaceAttribExternalBufferDescriptor,
989  .flags = VA_SURFACE_ATTRIB_SETTABLE,
990  .value.type = VAGenericValueTypePointer,
991  .value.value.p = &buffer_desc,
992  }
993  };
994 
995  desc = (AVDRMFrameDescriptor*)src->data[0];
996 
997  if (desc->nb_objects != 1) {
998  av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames "
999  "made from a single DRM object.\n");
1000  return AVERROR(EINVAL);
1001  }
1002 
1003  va_fourcc = 0;
1004  for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1005  if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats)
1006  continue;
1007  for (j = 0; j < desc->nb_layers; j++) {
1008  if (desc->layers[j].format !=
1009  vaapi_drm_format_map[i].layer_formats[j])
1010  break;
1011  }
1012  if (j != desc->nb_layers)
1013  continue;
1014  va_fourcc = vaapi_drm_format_map[i].va_fourcc;
1015  break;
1016  }
1017  if (!va_fourcc) {
1018  av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported "
1019  "by VAAPI.\n");
1020  return AVERROR(EINVAL);
1021  }
1022 
1023  av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as "
1024  "%08x.\n", desc->objects[0].fd, va_fourcc);
1025 
1026  for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
1027  if (vaapi_format_map[i].fourcc == va_fourcc)
1028  va_rt_format = vaapi_format_map[i].rt_format;
1029  }
1030 
1031  buffer_handle = desc->objects[0].fd;
1032  buffer_desc.pixel_format = va_fourcc;
1033  buffer_desc.width = src_fc->width;
1034  buffer_desc.height = src_fc->height;
1035  buffer_desc.data_size = desc->objects[0].size;
1036  buffer_desc.buffers = &buffer_handle;
1037  buffer_desc.num_buffers = 1;
1038  buffer_desc.flags = 0;
1039 
1040  k = 0;
1041  for (i = 0; i < desc->nb_layers; i++) {
1042  for (j = 0; j < desc->layers[i].nb_planes; j++) {
1043  buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
1044  buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
1045  ++k;
1046  }
1047  }
1048  buffer_desc.num_planes = k;
1049 
1050  vas = vaCreateSurfaces(dst_dev->display, va_rt_format,
1051  src->width, src->height,
1052  &surface_id, 1,
1053  attrs, FF_ARRAY_ELEMS(attrs));
1054  if (vas != VA_STATUS_SUCCESS) {
1055  av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM "
1056  "object: %d (%s).\n", vas, vaErrorStr(vas));
1057  return AVERROR(EIO);
1058  }
1059  av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id);
1060 
1061  err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
1062  &vaapi_unmap_from_drm,
1063  (void*)(uintptr_t)surface_id);
1064  if (err < 0)
1065  return err;
1066 
1067  dst->width = src->width;
1068  dst->height = src->height;
1069  dst->data[3] = (uint8_t*)(uintptr_t)surface_id;
1070 
1071  av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to "
1072  "surface %#x.\n", desc->objects[0].fd, surface_id);
1073 
1074  return 0;
1075 }
1076 
1077 #if VA_CHECK_VERSION(1, 1, 0)
1078 static void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc,
1079  HWMapDescriptor *hwmap)
1080 {
1081  AVDRMFrameDescriptor *drm_desc = hwmap->priv;
1082  int i;
1083 
1084  for (i = 0; i < drm_desc->nb_objects; i++)
1085  close(drm_desc->objects[i].fd);
1086 
1087  av_freep(&drm_desc);
1088 }
1089 
1090 static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst,
1091  const AVFrame *src, int flags)
1092 {
1093  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1094  VASurfaceID surface_id;
1095  VAStatus vas;
1096  VADRMPRIMESurfaceDescriptor va_desc;
1097  AVDRMFrameDescriptor *drm_desc = NULL;
1098  uint32_t export_flags;
1099  int err, i, j;
1100 
1101  surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1102 
1103  export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
1104  if (flags & AV_HWFRAME_MAP_READ)
1105  export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
1106  if (flags & AV_HWFRAME_MAP_WRITE)
1107  export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
1108 
1109  vas = vaExportSurfaceHandle(hwctx->display, surface_id,
1110  VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
1111  export_flags, &va_desc);
1112  if (vas != VA_STATUS_SUCCESS) {
1113  if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
1114  return AVERROR(ENOSYS);
1115  av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: "
1116  "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
1117  return AVERROR(EIO);
1118  }
1119 
1120  drm_desc = av_mallocz(sizeof(*drm_desc));
1121  if (!drm_desc) {
1122  err = AVERROR(ENOMEM);
1123  goto fail;
1124  }
1125 
1126  // By some bizarre coincidence, these structures are very similar...
1127  drm_desc->nb_objects = va_desc.num_objects;
1128  for (i = 0; i < va_desc.num_objects; i++) {
1129  drm_desc->objects[i].fd = va_desc.objects[i].fd;
1130  drm_desc->objects[i].size = va_desc.objects[i].size;
1131  drm_desc->objects[i].format_modifier =
1132  va_desc.objects[i].drm_format_modifier;
1133  }
1134  drm_desc->nb_layers = va_desc.num_layers;
1135  for (i = 0; i < va_desc.num_layers; i++) {
1136  drm_desc->layers[i].format = va_desc.layers[i].drm_format;
1137  drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes;
1138  for (j = 0; j < va_desc.layers[i].num_planes; j++) {
1139  drm_desc->layers[i].planes[j].object_index =
1140  va_desc.layers[i].object_index[j];
1141  drm_desc->layers[i].planes[j].offset =
1142  va_desc.layers[i].offset[j];
1143  drm_desc->layers[i].planes[j].pitch =
1144  va_desc.layers[i].pitch[j];
1145  }
1146  }
1147 
1148  err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
1149  &vaapi_unmap_to_drm_esh, drm_desc);
1150  if (err < 0)
1151  goto fail;
1152 
1153  dst->width = src->width;
1154  dst->height = src->height;
1155  dst->data[0] = (uint8_t*)drm_desc;
1156 
1157  return 0;
1158 
1159 fail:
1160  for (i = 0; i < va_desc.num_objects; i++)
1161  close(va_desc.objects[i].fd);
1162  av_freep(&drm_desc);
1163  return err;
1164 }
1165 #endif
1166 
1167 #if VA_CHECK_VERSION(0, 36, 0)
1168 typedef struct VAAPIDRMImageBufferMapping {
1169  VAImage image;
1170  VABufferInfo buffer_info;
1171 
1172  AVDRMFrameDescriptor drm_desc;
1173 } VAAPIDRMImageBufferMapping;
1174 
1175 static void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc,
1176  HWMapDescriptor *hwmap)
1177 {
1178  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1179  VAAPIDRMImageBufferMapping *mapping = hwmap->priv;
1180  VASurfaceID surface_id;
1181  VAStatus vas;
1182 
1183  surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
1184  av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n",
1185  surface_id);
1186 
1187  // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
1188  // so we shouldn't close them separately.
1189 
1190  vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1191  if (vas != VA_STATUS_SUCCESS) {
1192  av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer "
1193  "handle of image %#x (derived from surface %#x): "
1194  "%d (%s).\n", mapping->image.buf, surface_id,
1195  vas, vaErrorStr(vas));
1196  }
1197 
1198  vas = vaDestroyImage(hwctx->display, mapping->image.image_id);
1199  if (vas != VA_STATUS_SUCCESS) {
1200  av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image "
1201  "derived from surface %#x: %d (%s).\n",
1202  surface_id, vas, vaErrorStr(vas));
1203  }
1204 
1205  av_free(mapping);
1206 }
1207 
1208 static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst,
1209  const AVFrame *src, int flags)
1210 {
1211  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1212  VAAPIDRMImageBufferMapping *mapping = NULL;
1213  VASurfaceID surface_id;
1214  VAStatus vas;
1215  int err, i, p;
1216 
1217  surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1218  av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n",
1219  surface_id);
1220 
1221  mapping = av_mallocz(sizeof(*mapping));
1222  if (!mapping)
1223  return AVERROR(ENOMEM);
1224 
1225  vas = vaDeriveImage(hwctx->display, surface_id,
1226  &mapping->image);
1227  if (vas != VA_STATUS_SUCCESS) {
1228  av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
1229  "surface %#x: %d (%s).\n",
1230  surface_id, vas, vaErrorStr(vas));
1231  err = AVERROR(EIO);
1232  goto fail;
1233  }
1234 
1235  for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1236  if (vaapi_drm_format_map[i].va_fourcc ==
1237  mapping->image.format.fourcc)
1238  break;
1239  }
1240  if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) {
1241  av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for "
1242  "VAAPI format %#x.\n", mapping->image.format.fourcc);
1243  err = AVERROR(EINVAL);
1244  goto fail_derived;
1245  }
1246 
1247  mapping->buffer_info.mem_type =
1248  VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
1249 
1250  mapping->drm_desc.nb_layers =
1251  vaapi_drm_format_map[i].nb_layer_formats;
1252  if (mapping->drm_desc.nb_layers > 1) {
1253  if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
1254  av_log(hwfc, AV_LOG_ERROR, "Image properties do not match "
1255  "expected format: got %d planes, but expected %d.\n",
1256  mapping->image.num_planes, mapping->drm_desc.nb_layers);
1257  err = AVERROR(EINVAL);
1258  goto fail_derived;
1259  }
1260 
1261  for(p = 0; p < mapping->drm_desc.nb_layers; p++) {
1262  mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) {
1263  .format = vaapi_drm_format_map[i].layer_formats[p],
1264  .nb_planes = 1,
1265  .planes[0] = {
1266  .object_index = 0,
1267  .offset = mapping->image.offsets[p],
1268  .pitch = mapping->image.pitches[p],
1269  },
1270  };
1271  }
1272  } else {
1273  mapping->drm_desc.layers[0].format =
1274  vaapi_drm_format_map[i].layer_formats[0];
1275  mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes;
1276  for (p = 0; p < mapping->image.num_planes; p++) {
1277  mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) {
1278  .object_index = 0,
1279  .offset = mapping->image.offsets[p],
1280  .pitch = mapping->image.pitches[p],
1281  };
1282  }
1283  }
1284 
1285  vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf,
1286  &mapping->buffer_info);
1287  if (vas != VA_STATUS_SUCCESS) {
1288  av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer "
1289  "handle from image %#x (derived from surface %#x): "
1290  "%d (%s).\n", mapping->image.buf, surface_id,
1291  vas, vaErrorStr(vas));
1292  err = AVERROR(EIO);
1293  goto fail_derived;
1294  }
1295 
1296  av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
1297  mapping->buffer_info.handle);
1298 
1299  mapping->drm_desc.nb_objects = 1;
1300  mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) {
1301  .fd = mapping->buffer_info.handle,
1302  .size = mapping->image.data_size,
1303  // There is no way to get the format modifier with this API.
1304  .format_modifier = DRM_FORMAT_MOD_INVALID,
1305  };
1306 
1308  dst, src, &vaapi_unmap_to_drm_abh,
1309  mapping);
1310  if (err < 0)
1311  goto fail_mapped;
1312 
1313  dst->data[0] = (uint8_t*)&mapping->drm_desc;
1314  dst->width = src->width;
1315  dst->height = src->height;
1316 
1317  return 0;
1318 
1319 fail_mapped:
1320  vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1321 fail_derived:
1322  vaDestroyImage(hwctx->display, mapping->image.image_id);
1323 fail:
1324  av_freep(&mapping);
1325  return err;
1326 }
1327 #endif
1328 
1329 static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
1330  const AVFrame *src, int flags)
1331 {
1332 #if VA_CHECK_VERSION(1, 1, 0)
1333  int err;
1334  err = vaapi_map_to_drm_esh(hwfc, dst, src, flags);
1335  if (err != AVERROR(ENOSYS))
1336  return err;
1337 #endif
1338 #if VA_CHECK_VERSION(0, 36, 0)
1339  return vaapi_map_to_drm_abh(hwfc, dst, src, flags);
1340 #endif
1341  return AVERROR(ENOSYS);
1342 }
1343 
1344 #endif /* CONFIG_LIBDRM */
1345 
1346 static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
1347  const AVFrame *src, int flags)
1348 {
1349  switch (src->format) {
1350 #if CONFIG_LIBDRM
1351  case AV_PIX_FMT_DRM_PRIME:
1352  return vaapi_map_from_drm(hwfc, dst, src, flags);
1353 #endif
1354  default:
1355  return AVERROR(ENOSYS);
1356  }
1357 }
1358 
1360  const AVFrame *src, int flags)
1361 {
1362  switch (dst->format) {
1363 #if CONFIG_LIBDRM
1364  case AV_PIX_FMT_DRM_PRIME:
1365  return vaapi_map_to_drm(hwfc, dst, src, flags);
1366 #endif
1367  default:
1368  return vaapi_map_to_memory(hwfc, dst, src, flags);
1369  }
1370 }
1371 
1373 {
1374  AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1375  VAAPIDevicePriv *priv = ctx->user_opaque;
1376 
1377  if (hwctx->display)
1378  vaTerminate(hwctx->display);
1379 
1380 #if HAVE_VAAPI_X11
1381  if (priv->x11_display)
1382  XCloseDisplay(priv->x11_display);
1383 #endif
1384 
1385  if (priv->drm_fd >= 0)
1386  close(priv->drm_fd);
1387 
1388  av_freep(&priv);
1389 }
1390 
1391 #if CONFIG_VAAPI_1
1392 static void vaapi_device_log_error(void *context, const char *message)
1393 {
1394  AVHWDeviceContext *ctx = context;
1395 
1396  av_log(ctx, AV_LOG_ERROR, "libva: %s", message);
1397 }
1398 
1399 static void vaapi_device_log_info(void *context, const char *message)
1400 {
1401  AVHWDeviceContext *ctx = context;
1402 
1403  av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message);
1404 }
1405 #endif
1406 
1408  VADisplay display)
1409 {
1410  AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1411  int major, minor;
1412  VAStatus vas;
1413 
1414 #if CONFIG_VAAPI_1
1415  vaSetErrorCallback(display, &vaapi_device_log_error, ctx);
1416  vaSetInfoCallback (display, &vaapi_device_log_info, ctx);
1417 #endif
1418 
1419  hwctx->display = display;
1420 
1421  vas = vaInitialize(display, &major, &minor);
1422  if (vas != VA_STATUS_SUCCESS) {
1423  av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
1424  "connection: %d (%s).\n", vas, vaErrorStr(vas));
1425  return AVERROR(EIO);
1426  }
1427  av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
1428  "version %d.%d\n", major, minor);
1429 
1430  return 0;
1431 }
1432 
1433 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
1434  AVDictionary *opts, int flags)
1435 {
1436  VAAPIDevicePriv *priv;
1437  VADisplay display = NULL;
1438 
1439  priv = av_mallocz(sizeof(*priv));
1440  if (!priv)
1441  return AVERROR(ENOMEM);
1442 
1443  priv->drm_fd = -1;
1444 
1445  ctx->user_opaque = priv;
1446  ctx->free = vaapi_device_free;
1447 
1448 #if HAVE_VAAPI_X11
1449  if (!display && !(device && device[0] == '/')) {
1450  // Try to open the device as an X11 display.
1451  priv->x11_display = XOpenDisplay(device);
1452  if (!priv->x11_display) {
1453  av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
1454  "%s.\n", XDisplayName(device));
1455  } else {
1456  display = vaGetDisplay(priv->x11_display);
1457  if (!display) {
1458  av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
1459  "from X11 display %s.\n", XDisplayName(device));
1460  return AVERROR_UNKNOWN;
1461  }
1462 
1463  av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
1464  "X11 display %s.\n", XDisplayName(device));
1465  }
1466  }
1467 #endif
1468 
1469 #if HAVE_VAAPI_DRM
1470  if (!display) {
1471  // Try to open the device as a DRM path.
1472  // Default to using the first render node if the user did not
1473  // supply a path.
1474  const char *path = device ? device : "/dev/dri/renderD128";
1475  priv->drm_fd = open(path, O_RDWR);
1476  if (priv->drm_fd < 0) {
1477  av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
1478  path);
1479  } else {
1480  display = vaGetDisplayDRM(priv->drm_fd);
1481  if (!display) {
1482  av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
1483  "from DRM device %s.\n", path);
1484  return AVERROR_UNKNOWN;
1485  }
1486 
1487  av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
1488  "DRM device %s.\n", path);
1489  }
1490  }
1491 #endif
1492 
1493  if (!display) {
1494  av_log(ctx, AV_LOG_ERROR, "No VA display found for "
1495  "device: %s.\n", device ? device : "");
1496  return AVERROR(EINVAL);
1497  }
1498 
1499  return vaapi_device_connect(ctx, display);
1500 }
1501 
1503  AVHWDeviceContext *src_ctx, int flags)
1504 {
1505 #if HAVE_VAAPI_DRM
1506  if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) {
1507  AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
1508  VADisplay *display;
1509  VAAPIDevicePriv *priv;
1510 
1511  if (src_hwctx->fd < 0) {
1512  av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated "
1513  "device to derive a VA display from.\n");
1514  return AVERROR(EINVAL);
1515  }
1516 
1517  priv = av_mallocz(sizeof(*priv));
1518  if (!priv)
1519  return AVERROR(ENOMEM);
1520 
1521  // Inherits the fd from the source context, which will close it.
1522  priv->drm_fd = -1;
1523 
1524  ctx->user_opaque = priv;
1525  ctx->free = &vaapi_device_free;
1526 
1527  display = vaGetDisplayDRM(src_hwctx->fd);
1528  if (!display) {
1529  av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from "
1530  "DRM device.\n");
1531  return AVERROR(EIO);
1532  }
1533 
1534  return vaapi_device_connect(ctx, display);
1535  }
1536 #endif
1537  return AVERROR(ENOSYS);
1538 }
1539 
1542  .name = "VAAPI",
1543 
1544  .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
1545  .device_priv_size = sizeof(VAAPIDeviceContext),
1546  .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
1547  .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
1548  .frames_priv_size = sizeof(VAAPIFramesContext),
1549 
1550  .device_create = &vaapi_device_create,
1551  .device_derive = &vaapi_device_derive,
1553  .device_uninit = &vaapi_device_uninit,
1554  .frames_get_constraints = &vaapi_frames_get_constraints,
1555  .frames_init = &vaapi_frames_init,
1556  .frames_uninit = &vaapi_frames_uninit,
1557  .frames_get_buffer = &vaapi_get_buffer,
1558  .transfer_get_formats = &vaapi_transfer_get_formats,
1559  .transfer_data_to = &vaapi_transfer_data_to,
1560  .transfer_data_from = &vaapi_transfer_data_from,
1561  .map_to = &vaapi_map_to,
1562  .map_from = &vaapi_map_from,
1563 
1564  .pix_fmts = (const enum AVPixelFormat[]) {
1567  },
1568 };
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:60
#define NULL
Definition: coverity.c:32
The maximum number of layers/planes in a DRM frame.
Definition: hwcontext_drm.h:39
#define P
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it...
Definition: buffer.c:125
VAAPI-specific data associated with a frame pool.
static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
This structure describes decoded (raw) audio or video data.
Definition: frame.h:218
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:101
static void vaapi_device_free(AVHWDeviceContext *ctx)
static int device_init(AVFormatContext *ctx, int *width, int *height, uint32_t pixelformat)
Definition: v4l2.c:188
Memory handling functions.
VASurfaceAttrib * attributes
Set by the user to apply surface attributes to all surfaces in the frame pool.
AVBufferRef * buf[AV_NUM_DATA_POINTERS]
AVBuffer references backing the data for this frame.
Definition: frame.h:410
const char * desc
Definition: nvenc.c:65
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:228
static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
unsigned int rt_format
#define RGBA(r, g, b, a)
Definition: dvbsubdec.c:39
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:236
The driver does not support the VASurfaceAttribMemoryType attribute, so the surface allocation code w...
#define src
Definition: vp8dsp.c:254
int max_width
The maximum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:457
int nb_objects
Number of DRM objects making up this frame.
The quirks field has been set by the user and should not be detected automatically by av_hwdevice_ctx...
API-specific header for AV_HWDEVICE_TYPE_VAAPI.
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame...
Definition: frame.h:556
static int vaapi_transfer_data_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
static int vaapi_device_init(AVHWDeviceContext *hwdev)
DRM frame descriptor.
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
AVBufferPool * pool_internal
enum AVHWDeviceType type
uint8_t
#define av_malloc(s)
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:189
static void vaapi_buffer_free(void *opaque, uint8_t *data)
static int vaapi_device_connect(AVHWDeviceContext *ctx, VADisplay display)
size_t size
Total size of the object.
Definition: hwcontext_drm.h:58
DRM plane descriptor.
Definition: hwcontext_drm.h:74
static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
static const struct @258 vaapi_format_map[]
static AVFrame * frame
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:91
static const struct @259 vaapi_driver_quirks_table[]
static int flags
Definition: log.c:55
AVDRMLayerDescriptor layers[AV_DRM_MAX_PLANES]
Array of layers in the frame.
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
#define AV_BUFFER_FLAG_READONLY
Always treat the buffer as read-only, even when it has only one reference.
Definition: buffer.h:113
ptrdiff_t size
Definition: opengl_enc.c:101
static int vaapi_device_derive(AVHWDeviceContext *ctx, AVHWDeviceContext *src_ctx, int flags)
The mapped frame will be overwritten completely in subsequent operations, so the current frame data n...
Definition: hwcontext.h:513
#define av_log(a,...)
static int vaapi_map_frame(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
int fd
DRM PRIME fd for the object.
Definition: hwcontext_drm.h:52
int nb_layers
Number of layers in the frame.
DRM layer descriptor.
Definition: hwcontext_drm.h:96
The driver does not destroy parameter buffers when they are used by vaRenderPicture().
int object_index
Index of the object containing this plane in the objects array of the enclosing frame descriptor...
Definition: hwcontext_drm.h:79
int width
Definition: frame.h:276
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
VAAPI hardware pipeline configuration details.
void(* free)(struct AVHWDeviceContext *ctx)
This field may be set by the caller before calling av_hwdevice_ctx_init().
Definition: hwcontext.h:103
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:202
ptrdiff_t pitch
Pitch (linesize) of this plane.
Definition: hwcontext_drm.h:87
The mapping must be direct.
Definition: hwcontext.h:519
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
DRM object descriptor.
Definition: hwcontext_drm.h:48
simple assert() macros that are a bit more flexible than ISO C assert().
int nb_planes
Number of planes in the layer.
AVBufferRef * av_buffer_create(uint8_t *data, int size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:28
enum AVHWDeviceType type
This field identifies the underlying API used for hardware access.
Definition: hwcontext.h:78
VASurfaceAttrib * attributes
#define fail()
Definition: checkasm.h:116
int av_frame_copy(AVFrame *dst, const AVFrame *src)
Copy the frame data from src to dst.
Definition: frame.c:790
const char * match_string
int initial_pool_size
Initial size of the frame pool.
Definition: hwcontext.h:198
AVDictionary * opts
Definition: movenc.c:50
static int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
AVFrame * source
A reference to the original source of the mapping.
AVDRMPlaneDescriptor planes[AV_DRM_MAX_PLANES]
Array of planes in this layer.
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition: hwcontext.h:148
The mapping must be readable.
Definition: hwcontext.h:503
enum AVPixelFormat pix_fmt
AVFormatContext * ctx
Definition: movenc.c:48
The mapping must be writeable.
Definition: hwcontext.h:507
static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats)
AVDRMObjectDescriptor objects[AV_DRM_MAX_PLANES]
Array of objects making up the frame.
static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
uint64_t format_modifier
Format modifier applied to the object (DRM_FORMAT_MOD_*).
Definition: hwcontext_drm.h:65
AVBufferPool * av_buffer_pool_init2(int size, void *opaque, AVBufferRef *(*alloc)(void *opaque, int size), void(*pool_free)(void *opaque))
Allocate and initialize a buffer pool with a more complex allocator.
Definition: buffer.c:218
static int vaapi_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
static void vaapi_unmap_frame(AVHWFramesContext *hwfc, HWMapDescriptor *hwmap)
#define FF_ARRAY_ELEMS(a)
VADisplay display
The VADisplay handle, to be filled by the user.
VAAPISurfaceFormat * formats
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames...
Definition: frame.h:291
int min_width
The minimum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:450
void * priv
Hardware-specific private data associated with the mapping.
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition: hwcontext.h:432
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:249
const char * friendly_name
uint8_t * data
The data buffer.
Definition: buffer.h:89
static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
static int vaapi_frames_init(AVHWFramesContext *hwfc)
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition: hwcontext.h:161
unsigned int driver_quirks
Driver quirks to apply - this is filled by av_hwdevice_ctx_init(), with reference to a table of known...
GLint GLenum type
Definition: opengl_enc.c:105
int ff_hwframe_map_create(AVBufferRef *hwframe_ref, AVFrame *dst, const AVFrame *src, void(*unmap)(AVHWFramesContext *ctx, HWMapDescriptor *hwmap), void *priv)
Definition: hwcontext.c:689
DRM-managed buffers exposed through PRIME buffer sharing.
Definition: pixfmt.h:324
#define MAP(va, rt, av)
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:123
refcounted data buffer API
enum AVPixelFormat * valid_hw_formats
A list of possible values for format in the hw_frames_ctx, terminated by AV_PIX_FMT_NONE.
Definition: hwcontext.h:437
const VDPAUPixFmtMap * map
static int vaapi_get_image_format(AVHWDeviceContext *hwdev, enum AVPixelFormat pix_fmt, VAImageFormat **image_format)
API-specific header for AV_HWDEVICE_TYPE_DRM.
AVHWFramesInternal * internal
Private data used internally by libavutil.
Definition: hwcontext.h:133
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:266
static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:232
void * user_opaque
Arbitrary user data, to be used e.g.
Definition: hwcontext.h:108
VAImageFormat image_format
enum AVPixelFormat pix_fmt
static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device, AVDictionary *opts, int flags)
A reference to a data buffer.
Definition: buffer.h:81
common internal and external API header
if(ret< 0)
Definition: vf_mcdeint.c:279
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:107
int fd
File descriptor of DRM device.
static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev, const void *hwconfig, AVHWFramesConstraints *constraints)
uint32_t format
Format of the layer (DRM_FORMAT_*).
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
AVHWFrameTransferDirection
Definition: hwcontext.h:394
static AVBufferRef * vaapi_pool_alloc(void *opaque, int size)
pixel format definitions
AVBufferPool * pool
A pool from which the frames are allocated by av_hwframe_get_buffer().
Definition: hwcontext.h:189
#define av_free(p)
enum AVPixelFormat * valid_sw_formats
A list of possible values for sw_format in the hw_frames_ctx, terminated by AV_PIX_FMT_NONE.
Definition: hwcontext.h:444
ptrdiff_t offset
Offset within that object of this plane.
Definition: hwcontext_drm.h:83
#define H
Definition: pixlet.c:39
unsigned int quirks
VAAPI connection details.
VAConfigID config_id
ID of a VAAPI pipeline configuration.
int height
Definition: frame.h:276
const HWContextType ff_hwcontext_type_vaapi
#define av_freep(p)
VASurfaceID * surface_ids
The surfaces IDs of all surfaces in the pool after creation.
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:334
#define av_malloc_array(a, b)
formats
Definition: signature.h:48
#define FFSWAP(type, a, b)
Definition: common.h:99
AVHWDeviceInternal * internal
Private data used internally by libavutil.
Definition: hwcontext.h:70
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition: pixdesc.c:2279
The driver does not support surface attributes at all.
unsigned int rt_format
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:221
AVPixelFormat
Pixel format.
Definition: pixfmt.h:60
unsigned int fourcc
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:652
#define V
Definition: avdct.c:30