Libav
hwcontext_vaapi.c
Go to the documentation of this file.
1 /*
2  * This file is part of Libav.
3  *
4  * Libav 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  * Libav 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 Libav; 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 #include <fcntl.h>
29 #if HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
32 
33 
34 #include "avassert.h"
35 #include "buffer.h"
36 #include "common.h"
37 #include "hwcontext.h"
38 #include "hwcontext_internal.h"
39 #include "hwcontext_vaapi.h"
40 #include "mem.h"
41 #include "pixdesc.h"
42 #include "pixfmt.h"
43 
44 typedef struct VAAPIDevicePriv {
45 #if HAVE_VAAPI_X11
46  Display *x11_display;
47 #endif
48 
49  int drm_fd;
51 
52 typedef struct VAAPISurfaceFormat {
54  VAImageFormat image_format;
56 
57 typedef struct VAAPIDeviceContext {
58  // Surface formats which can be used with this device.
62 
63 typedef struct VAAPIFramesContext {
64  // Surface attributes set at create time.
65  VASurfaceAttrib *attributes;
67  // RT format of the underlying surface (Intel driver ignores this anyway).
68  unsigned int rt_format;
69  // Whether vaDeriveImage works.
72 
73 enum {
77 };
78 
79 typedef struct VAAPISurfaceMap {
80  // The source hardware frame of this mapping (with hw_frames_ctx set).
81  const AVFrame *source;
82  // VAAPI_MAP_* flags which apply to this mapping.
83  int flags;
84  // Handle to the derived or copied image which is mapped.
85  VAImage image;
87 
88 #define MAP(va, rt, av) { \
89  VA_FOURCC_ ## va, \
90  VA_RT_FORMAT_ ## rt, \
91  AV_PIX_FMT_ ## av \
92  }
93 // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
94 // plane swap cases. The frame handling below tries to hide these.
95 static struct {
96  unsigned int fourcc;
97  unsigned int rt_format;
99 } vaapi_format_map[] = {
100  MAP(NV12, YUV420, NV12),
101  MAP(YV12, YUV420, YUV420P), // With U/V planes swapped.
102  MAP(IYUV, YUV420, YUV420P),
103  //MAP(I420, YUV420, YUV420P), // Not in libva but used by Intel driver.
104 #ifdef VA_FOURCC_YV16
105  MAP(YV16, YUV422, YUV422P), // With U/V planes swapped.
106 #endif
107  MAP(422H, YUV422, YUV422P),
108  MAP(UYVY, YUV422, UYVY422),
109  MAP(YUY2, YUV422, YUYV422),
110  MAP(Y800, YUV400, GRAY8),
111 #ifdef VA_FOURCC_P010
112  //MAP(P010, YUV420_10BPP, P010),
113 #endif
114  MAP(BGRA, RGB32, BGRA),
115  //MAP(BGRX, RGB32, BGR0),
116  MAP(RGBA, RGB32, RGBA),
117  //MAP(RGBX, RGB32, RGB0),
118  MAP(ABGR, RGB32, ABGR),
119  //MAP(XBGR, RGB32, 0BGR),
120  MAP(ARGB, RGB32, ARGB),
121  //MAP(XRGB, RGB32, 0RGB),
122 };
123 #undef MAP
124 
126 {
127  int i;
128  for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
129  if (vaapi_format_map[i].fourcc == fourcc)
130  return vaapi_format_map[i].pix_fmt;
131  return AV_PIX_FMT_NONE;
132 }
133 
135  enum AVPixelFormat pix_fmt,
136  VAImageFormat **image_format)
137 {
138  VAAPIDeviceContext *ctx = hwdev->internal->priv;
139  int i;
140 
141  for (i = 0; i < ctx->nb_formats; i++) {
142  if (ctx->formats[i].pix_fmt == pix_fmt) {
143  *image_format = &ctx->formats[i].image_format;
144  return 0;
145  }
146  }
147  return AVERROR(EINVAL);
148 }
149 
151  const void *hwconfig,
152  AVHWFramesConstraints *constraints)
153 {
154  AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
155  const AVVAAPIHWConfig *config = hwconfig;
156  VAAPIDeviceContext *ctx = hwdev->internal->priv;
157  VASurfaceAttrib *attr_list = NULL;
158  VAStatus vas;
159  enum AVPixelFormat pix_fmt;
160  unsigned int fourcc;
161  int err, i, j, attr_count, pix_fmt_count;
162 
163  if (config) {
164  attr_count = 0;
165  vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
166  0, &attr_count);
167  if (vas != VA_STATUS_SUCCESS) {
168  av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
169  "%d (%s).\n", vas, vaErrorStr(vas));
170  err = AVERROR(ENOSYS);
171  goto fail;
172  }
173 
174  attr_list = av_malloc(attr_count * sizeof(*attr_list));
175  if (!attr_list) {
176  err = AVERROR(ENOMEM);
177  goto fail;
178  }
179 
180  vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
181  attr_list, &attr_count);
182  if (vas != VA_STATUS_SUCCESS) {
183  av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
184  "%d (%s).\n", vas, vaErrorStr(vas));
185  err = AVERROR(ENOSYS);
186  goto fail;
187  }
188 
189  pix_fmt_count = 0;
190  for (i = 0; i < attr_count; i++) {
191  switch (attr_list[i].type) {
192  case VASurfaceAttribPixelFormat:
193  fourcc = attr_list[i].value.value.i;
194  pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
195  if (pix_fmt != AV_PIX_FMT_NONE) {
196  ++pix_fmt_count;
197  } else {
198  // Something unsupported - ignore.
199  }
200  break;
201  case VASurfaceAttribMinWidth:
202  constraints->min_width = attr_list[i].value.value.i;
203  break;
204  case VASurfaceAttribMinHeight:
205  constraints->min_height = attr_list[i].value.value.i;
206  break;
207  case VASurfaceAttribMaxWidth:
208  constraints->max_width = attr_list[i].value.value.i;
209  break;
210  case VASurfaceAttribMaxHeight:
211  constraints->max_height = attr_list[i].value.value.i;
212  break;
213  }
214  }
215  if (pix_fmt_count == 0) {
216  // Nothing usable found. Presumably there exists something which
217  // works, so leave the set null to indicate unknown.
218  constraints->valid_sw_formats = NULL;
219  } else {
220  constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
221  sizeof(pix_fmt));
222  if (!constraints->valid_sw_formats) {
223  err = AVERROR(ENOMEM);
224  goto fail;
225  }
226 
227  for (i = j = 0; i < attr_count; i++) {
228  if (attr_list[i].type != VASurfaceAttribPixelFormat)
229  continue;
230  fourcc = attr_list[i].value.value.i;
231  pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
232  if (pix_fmt != AV_PIX_FMT_NONE)
233  constraints->valid_sw_formats[j++] = pix_fmt;
234  }
235  av_assert0(j == pix_fmt_count);
236  constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
237  }
238  } else {
239  // No configuration supplied.
240  // Return the full set of image formats known by the implementation.
241  constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
242  sizeof(pix_fmt));
243  if (!constraints->valid_sw_formats) {
244  err = AVERROR(ENOMEM);
245  goto fail;
246  }
247  for (i = 0; i < ctx->nb_formats; i++)
248  constraints->valid_sw_formats[i] = ctx->formats[i].pix_fmt;
249  constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE;
250  }
251 
252  constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
253  if (!constraints->valid_hw_formats) {
254  err = AVERROR(ENOMEM);
255  goto fail;
256  }
257  constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
258  constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
259 
260  err = 0;
261 fail:
262  av_freep(&attr_list);
263  return err;
264 }
265 
266 static const struct {
267  const char *friendly_name;
268  const char *match_string;
269  unsigned int quirks;
271  {
272  "Intel i965 (Quick Sync)",
273  "i965",
275  },
276 };
277 
279 {
280  VAAPIDeviceContext *ctx = hwdev->internal->priv;
281  AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
282  VAImageFormat *image_list = NULL;
283  VAStatus vas;
284  const char *vendor_string;
285  int err, i, image_count;
286  enum AVPixelFormat pix_fmt;
287  unsigned int fourcc;
288 
289  image_count = vaMaxNumImageFormats(hwctx->display);
290  if (image_count <= 0) {
291  err = AVERROR(EIO);
292  goto fail;
293  }
294  image_list = av_malloc(image_count * sizeof(*image_list));
295  if (!image_list) {
296  err = AVERROR(ENOMEM);
297  goto fail;
298  }
299  vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
300  if (vas != VA_STATUS_SUCCESS) {
301  err = AVERROR(EIO);
302  goto fail;
303  }
304 
305  ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
306  if (!ctx->formats) {
307  err = AVERROR(ENOMEM);
308  goto fail;
309  }
310  ctx->nb_formats = 0;
311  for (i = 0; i < image_count; i++) {
312  fourcc = image_list[i].fourcc;
313  pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
314  if (pix_fmt == AV_PIX_FMT_NONE) {
315  av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
316  fourcc);
317  } else {
318  av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
319  fourcc, av_get_pix_fmt_name(pix_fmt));
320  ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
321  ctx->formats[ctx->nb_formats].image_format = image_list[i];
322  ++ctx->nb_formats;
323  }
324  }
325 
327  av_log(hwdev, AV_LOG_VERBOSE, "Not detecting driver: "
328  "quirks set by user.\n");
329  } else {
330  // Detect the driver in use and set quirk flags if necessary.
331  vendor_string = vaQueryVendorString(hwctx->display);
332  hwctx->driver_quirks = 0;
333  if (vendor_string) {
334  for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
335  if (strstr(vendor_string,
337  av_log(hwdev, AV_LOG_VERBOSE, "Matched \"%s\" as known "
338  "driver \"%s\".\n", vendor_string,
340  hwctx->driver_quirks |=
341  vaapi_driver_quirks_table[i].quirks;
342  break;
343  }
344  }
346  av_log(hwdev, AV_LOG_VERBOSE, "Unknown driver \"%s\", "
347  "assuming standard behaviour.\n", vendor_string);
348  }
349  }
350  }
351 
352  av_free(image_list);
353  return 0;
354 fail:
355  av_freep(&ctx->formats);
356  av_free(image_list);
357  return err;
358 }
359 
361 {
362  VAAPIDeviceContext *ctx = hwdev->internal->priv;
363 
364  av_freep(&ctx->formats);
365 }
366 
367 static void vaapi_buffer_free(void *opaque, uint8_t *data)
368 {
369  AVHWFramesContext *hwfc = opaque;
370  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
371  VASurfaceID surface_id;
372  VAStatus vas;
373 
374  surface_id = (VASurfaceID)(uintptr_t)data;
375 
376  vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
377  if (vas != VA_STATUS_SUCCESS) {
378  av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
379  "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
380  }
381 }
382 
383 static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
384 {
385  AVHWFramesContext *hwfc = opaque;
387  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
388  AVVAAPIFramesContext *avfc = hwfc->hwctx;
389  VASurfaceID surface_id;
390  VAStatus vas;
391  AVBufferRef *ref;
392 
393  if (hwfc->initial_pool_size > 0 &&
394  avfc->nb_surfaces >= hwfc->initial_pool_size)
395  return NULL;
396 
397  vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
398  hwfc->width, hwfc->height,
399  &surface_id, 1,
400  ctx->attributes, ctx->nb_attributes);
401  if (vas != VA_STATUS_SUCCESS) {
402  av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
403  "%d (%s).\n", vas, vaErrorStr(vas));
404  return NULL;
405  }
406  av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
407 
408  ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
409  sizeof(surface_id), &vaapi_buffer_free,
411  if (!ref) {
412  vaDestroySurfaces(hwctx->display, &surface_id, 1);
413  return NULL;
414  }
415 
416  if (hwfc->initial_pool_size > 0) {
417  // This is a fixed-size pool, so we must still be in the initial
418  // allocation sequence.
420  avfc->surface_ids[avfc->nb_surfaces] = surface_id;
421  ++avfc->nb_surfaces;
422  }
423 
424  return ref;
425 }
426 
428 {
429  AVVAAPIFramesContext *avfc = hwfc->hwctx;
431  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
432  VAImageFormat *expected_format;
433  AVBufferRef *test_surface = NULL;
434  VASurfaceID test_surface_id;
435  VAImage test_image;
436  VAStatus vas;
437  int err, i;
438  unsigned int fourcc, rt_format;
439 
440  for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
441  if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) {
442  fourcc = vaapi_format_map[i].fourcc;
443  rt_format = vaapi_format_map[i].rt_format;
444  break;
445  }
446  }
447  if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
448  av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
450  return AVERROR(EINVAL);
451  }
452 
453  if (!hwfc->pool) {
454  int need_memory_type = 1, need_pixel_format = 1;
455  for (i = 0; i < avfc->nb_attributes; i++) {
456  if (ctx->attributes[i].type == VASurfaceAttribMemoryType)
457  need_memory_type = 0;
458  if (ctx->attributes[i].type == VASurfaceAttribPixelFormat)
459  need_pixel_format = 0;
460  }
461  ctx->nb_attributes =
462  avfc->nb_attributes + need_memory_type + need_pixel_format;
463 
464  ctx->attributes = av_malloc(ctx->nb_attributes *
465  sizeof(*ctx->attributes));
466  if (!ctx->attributes) {
467  err = AVERROR(ENOMEM);
468  goto fail;
469  }
470 
471  for (i = 0; i < avfc->nb_attributes; i++)
472  ctx->attributes[i] = avfc->attributes[i];
473  if (need_memory_type) {
474  ctx->attributes[i++] = (VASurfaceAttrib) {
475  .type = VASurfaceAttribMemoryType,
476  .flags = VA_SURFACE_ATTRIB_SETTABLE,
477  .value.type = VAGenericValueTypeInteger,
478  .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
479  };
480  }
481  if (need_pixel_format) {
482  ctx->attributes[i++] = (VASurfaceAttrib) {
483  .type = VASurfaceAttribPixelFormat,
484  .flags = VA_SURFACE_ATTRIB_SETTABLE,
485  .value.type = VAGenericValueTypeInteger,
486  .value.value.i = fourcc,
487  };
488  }
489  av_assert0(i == ctx->nb_attributes);
490 
491  ctx->rt_format = rt_format;
492 
493  if (hwfc->initial_pool_size > 0) {
494  // This pool will be usable as a render target, so we need to store
495  // all of the surface IDs somewhere that vaCreateContext() calls
496  // will be able to access them.
497  avfc->nb_surfaces = 0;
498  avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
499  sizeof(*avfc->surface_ids));
500  if (!avfc->surface_ids) {
501  err = AVERROR(ENOMEM);
502  goto fail;
503  }
504  } else {
505  // This pool allows dynamic sizing, and will not be usable as a
506  // render target.
507  avfc->nb_surfaces = 0;
508  avfc->surface_ids = NULL;
509  }
510 
511  hwfc->internal->pool_internal =
512  av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
514  if (!hwfc->internal->pool_internal) {
515  av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
516  err = AVERROR(ENOMEM);
517  goto fail;
518  }
519  }
520 
521  // Allocate a single surface to test whether vaDeriveImage() is going
522  // to work for the specific configuration.
523  if (hwfc->pool) {
524  test_surface = av_buffer_pool_get(hwfc->pool);
525  if (!test_surface) {
526  av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
527  "user-configured buffer pool.\n");
528  err = AVERROR(ENOMEM);
529  goto fail;
530  }
531  } else {
532  test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
533  if (!test_surface) {
534  av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
535  "internal buffer pool.\n");
536  err = AVERROR(ENOMEM);
537  goto fail;
538  }
539  }
540  test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
541 
542  ctx->derive_works = 0;
543 
545  hwfc->sw_format, &expected_format);
546  if (err == 0) {
547  vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
548  if (vas == VA_STATUS_SUCCESS) {
549  if (expected_format->fourcc == test_image.format.fourcc) {
550  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
551  ctx->derive_works = 1;
552  } else {
553  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
554  "derived image format %08x does not match "
555  "expected format %08x.\n",
556  expected_format->fourcc, test_image.format.fourcc);
557  }
558  vaDestroyImage(hwctx->display, test_image.image_id);
559  } else {
560  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
561  "deriving image does not work: "
562  "%d (%s).\n", vas, vaErrorStr(vas));
563  }
564  } else {
565  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
566  "image format is not supported.\n");
567  }
568 
569  av_buffer_unref(&test_surface);
570  return 0;
571 
572 fail:
573  av_buffer_unref(&test_surface);
574  av_freep(&avfc->surface_ids);
575  av_freep(&ctx->attributes);
576  return err;
577 }
578 
580 {
581  AVVAAPIFramesContext *avfc = hwfc->hwctx;
583 
584  av_freep(&avfc->surface_ids);
585  av_freep(&ctx->attributes);
586 }
587 
588 static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
589 {
590  frame->buf[0] = av_buffer_pool_get(hwfc->pool);
591  if (!frame->buf[0])
592  return AVERROR(ENOMEM);
593 
594  frame->data[3] = frame->buf[0]->data;
595  frame->format = AV_PIX_FMT_VAAPI;
596  frame->width = hwfc->width;
597  frame->height = hwfc->height;
598 
599  return 0;
600 }
601 
604  enum AVPixelFormat **formats)
605 {
607  enum AVPixelFormat *pix_fmts, preferred_format;
608  int i, k;
609 
610  preferred_format = hwfc->sw_format;
611 
612  pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
613  if (!pix_fmts)
614  return AVERROR(ENOMEM);
615 
616  pix_fmts[0] = preferred_format;
617  k = 1;
618  for (i = 0; i < ctx->nb_formats; i++) {
619  if (ctx->formats[i].pix_fmt == preferred_format)
620  continue;
621  av_assert0(k < ctx->nb_formats);
622  pix_fmts[k++] = ctx->formats[i].pix_fmt;
623  }
624  av_assert0(k == ctx->nb_formats);
625  pix_fmts[k] = AV_PIX_FMT_NONE;
626 
627  *formats = pix_fmts;
628  return 0;
629 }
630 
631 static void vaapi_unmap_frame(void *opaque, uint8_t *data)
632 {
633  AVHWFramesContext *hwfc = opaque;
634  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
636  const AVFrame *src;
637  VASurfaceID surface_id;
638  VAStatus vas;
639 
640  src = map->source;
641  surface_id = (VASurfaceID)(uintptr_t)src->data[3];
642  av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
643 
644  vas = vaUnmapBuffer(hwctx->display, map->image.buf);
645  if (vas != VA_STATUS_SUCCESS) {
646  av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
647  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
648  }
649 
650  if ((map->flags & VAAPI_MAP_WRITE) &&
651  !(map->flags & VAAPI_MAP_DIRECT)) {
652  vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
653  0, 0, hwfc->width, hwfc->height,
654  0, 0, hwfc->width, hwfc->height);
655  if (vas != VA_STATUS_SUCCESS) {
656  av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
657  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
658  }
659  }
660 
661  vas = vaDestroyImage(hwctx->display, map->image.image_id);
662  if (vas != VA_STATUS_SUCCESS) {
663  av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
664  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
665  }
666 
667  av_free(map);
668 }
669 
671  AVFrame *dst, const AVFrame *src, int flags)
672 {
673  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
675  VASurfaceID surface_id;
676  VAImageFormat *image_format;
678  VAStatus vas;
679  void *address = NULL;
680  int err, i;
681 
682  surface_id = (VASurfaceID)(uintptr_t)src->data[3];
683  av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
684 
685  if (!ctx->derive_works && (flags & VAAPI_MAP_DIRECT)) {
686  // Requested direct mapping but it is not possible.
687  return AVERROR(EINVAL);
688  }
689  if (dst->format == AV_PIX_FMT_NONE)
690  dst->format = hwfc->sw_format;
691  if (dst->format != hwfc->sw_format && (flags & VAAPI_MAP_DIRECT)) {
692  // Requested direct mapping but the formats do not match.
693  return AVERROR(EINVAL);
694  }
695 
696  err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
697  if (err < 0) {
698  // Requested format is not a valid output format.
699  return AVERROR(EINVAL);
700  }
701 
702  map = av_malloc(sizeof(VAAPISurfaceMap));
703  if (!map)
704  return AVERROR(ENOMEM);
705 
706  map->source = src;
707  map->flags = flags;
708  map->image.image_id = VA_INVALID_ID;
709 
710  vas = vaSyncSurface(hwctx->display, surface_id);
711  if (vas != VA_STATUS_SUCCESS) {
712  av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
713  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
714  err = AVERROR(EIO);
715  goto fail;
716  }
717 
718  // The memory which we map using derive need not be connected to the CPU
719  // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
720  // memory is mappable but not cached, so normal memcpy()-like access is
721  // very slow to read it (but writing is ok). It is possible to read much
722  // faster with a copy routine which is aware of the limitation, but we
723  // assume for now that the user is not aware of that and would therefore
724  // prefer not to be given direct-mapped memory if they request read access.
725  if (ctx->derive_works &&
726  ((flags & VAAPI_MAP_DIRECT) || !(flags & VAAPI_MAP_READ))) {
727  vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
728  if (vas != VA_STATUS_SUCCESS) {
729  av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
730  "surface %#x: %d (%s).\n",
731  surface_id, vas, vaErrorStr(vas));
732  err = AVERROR(EIO);
733  goto fail;
734  }
735  if (map->image.format.fourcc != image_format->fourcc) {
736  av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
737  "is in wrong format: expected %#08x, got %#08x.\n",
738  surface_id, image_format->fourcc, map->image.format.fourcc);
739  err = AVERROR(EIO);
740  goto fail;
741  }
742  map->flags |= VAAPI_MAP_DIRECT;
743  } else {
744  vas = vaCreateImage(hwctx->display, image_format,
745  hwfc->width, hwfc->height, &map->image);
746  if (vas != VA_STATUS_SUCCESS) {
747  av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
748  "surface %#x: %d (%s).\n",
749  surface_id, vas, vaErrorStr(vas));
750  err = AVERROR(EIO);
751  goto fail;
752  }
753  if (flags & VAAPI_MAP_READ) {
754  vas = vaGetImage(hwctx->display, surface_id, 0, 0,
755  hwfc->width, hwfc->height, map->image.image_id);
756  if (vas != VA_STATUS_SUCCESS) {
757  av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
758  "surface %#x: %d (%s).\n",
759  surface_id, vas, vaErrorStr(vas));
760  err = AVERROR(EIO);
761  goto fail;
762  }
763  }
764  }
765 
766  vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
767  if (vas != VA_STATUS_SUCCESS) {
768  av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
769  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
770  err = AVERROR(EIO);
771  goto fail;
772  }
773 
774  dst->width = src->width;
775  dst->height = src->height;
776 
777  for (i = 0; i < map->image.num_planes; i++) {
778  dst->data[i] = (uint8_t*)address + map->image.offsets[i];
779  dst->linesize[i] = map->image.pitches[i];
780  }
781  if (
782 #ifdef VA_FOURCC_YV16
783  map->image.format.fourcc == VA_FOURCC_YV16 ||
784 #endif
785  map->image.format.fourcc == VA_FOURCC_YV12) {
786  // Chroma planes are YVU rather than YUV, so swap them.
787  FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
788  }
789 
790  dst->buf[0] = av_buffer_create((uint8_t*)map, sizeof(*map),
791  &vaapi_unmap_frame, hwfc, 0);
792  if (!dst->buf[0]) {
793  err = AVERROR(ENOMEM);
794  goto fail;
795  }
796 
797  return 0;
798 
799 fail:
800  if (map) {
801  if (address)
802  vaUnmapBuffer(hwctx->display, map->image.buf);
803  if (map->image.image_id != VA_INVALID_ID)
804  vaDestroyImage(hwctx->display, map->image.image_id);
805  av_free(map);
806  }
807  return err;
808 }
809 
811  AVFrame *dst, const AVFrame *src)
812 {
813  AVFrame *map;
814  int err;
815 
816  if (dst->width > hwfc->width || dst->height > hwfc->height)
817  return AVERROR(EINVAL);
818 
819  map = av_frame_alloc();
820  if (!map)
821  return AVERROR(ENOMEM);
822  map->format = dst->format;
823 
824  err = vaapi_map_frame(hwfc, map, src, VAAPI_MAP_READ);
825  if (err)
826  goto fail;
827 
828  map->width = dst->width;
829  map->height = dst->height;
830 
831  err = av_frame_copy(dst, map);
832  if (err)
833  goto fail;
834 
835  err = 0;
836 fail:
837  av_frame_free(&map);
838  return err;
839 }
840 
842  AVFrame *dst, const AVFrame *src)
843 {
844  AVFrame *map;
845  int err;
846 
847  if (src->width > hwfc->width || src->height > hwfc->height)
848  return AVERROR(EINVAL);
849 
850  map = av_frame_alloc();
851  if (!map)
852  return AVERROR(ENOMEM);
853  map->format = src->format;
854 
855  err = vaapi_map_frame(hwfc, map, dst, VAAPI_MAP_WRITE);
856  if (err)
857  goto fail;
858 
859  map->width = src->width;
860  map->height = src->height;
861 
862  err = av_frame_copy(map, src);
863  if (err)
864  goto fail;
865 
866  err = 0;
867 fail:
868  av_frame_free(&map);
869  return err;
870 }
871 
873 {
874  AVVAAPIDeviceContext *hwctx = ctx->hwctx;
875  VAAPIDevicePriv *priv = ctx->user_opaque;
876 
877  if (hwctx->display)
878  vaTerminate(hwctx->display);
879 
880 #if HAVE_VAAPI_X11
881  if (priv->x11_display)
882  XCloseDisplay(priv->x11_display);
883 #endif
884 
885  if (priv->drm_fd >= 0)
886  close(priv->drm_fd);
887 
888  av_freep(&priv);
889 }
890 
891 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
892  AVDictionary *opts, int flags)
893 {
894  AVVAAPIDeviceContext *hwctx = ctx->hwctx;
895  VAAPIDevicePriv *priv;
896  VADisplay display = 0;
897  VAStatus vas;
898  int major, minor;
899 
900  priv = av_mallocz(sizeof(*priv));
901  if (!priv)
902  return AVERROR(ENOMEM);
903 
904  priv->drm_fd = -1;
905 
906  ctx->user_opaque = priv;
907  ctx->free = vaapi_device_free;
908 
909 #if HAVE_VAAPI_X11
910  if (!display && !(device && device[0] == '/')) {
911  // Try to open the device as an X11 display.
912  priv->x11_display = XOpenDisplay(device);
913  if (!priv->x11_display) {
914  av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
915  "%s.\n", XDisplayName(device));
916  } else {
917  display = vaGetDisplay(priv->x11_display);
918  if (!display) {
919  av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
920  "from X11 display %s.\n", XDisplayName(device));
921  return AVERROR_UNKNOWN;
922  }
923 
924  av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
925  "X11 display %s.\n", XDisplayName(device));
926  }
927  }
928 #endif
929 
930 #if HAVE_VAAPI_DRM
931  if (!display) {
932  // Try to open the device as a DRM path.
933  // Default to using the first render node if the user did not
934  // supply a path.
935  const char *path = device ? device : "/dev/dri/renderD128";
936  priv->drm_fd = open(path, O_RDWR);
937  if (priv->drm_fd < 0) {
938  av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
939  path);
940  } else {
941  display = vaGetDisplayDRM(priv->drm_fd);
942  if (!display) {
943  av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
944  "from DRM device %s.\n", path);
945  return AVERROR_UNKNOWN;
946  }
947 
948  av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
949  "DRM device %s.\n", path);
950  }
951  }
952 #endif
953 
954  if (!display) {
955  av_log(ctx, AV_LOG_ERROR, "No VA display found for "
956  "device: %s.\n", device ? device : "");
957  return AVERROR(EINVAL);
958  }
959 
960  hwctx->display = display;
961 
962  vas = vaInitialize(display, &major, &minor);
963  if (vas != VA_STATUS_SUCCESS) {
964  av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
965  "connection: %d (%s).\n", vas, vaErrorStr(vas));
966  return AVERROR(EIO);
967  }
968  av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
969  "version %d.%d\n", major, minor);
970 
971  return 0;
972 }
973 
976  .name = "VAAPI",
977 
978  .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
979  .device_priv_size = sizeof(VAAPIDeviceContext),
980  .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
981  .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
982  .frames_priv_size = sizeof(VAAPIFramesContext),
983 
984  .device_create = &vaapi_device_create,
986  .device_uninit = &vaapi_device_uninit,
987  .frames_get_constraints = &vaapi_frames_get_constraints,
988  .frames_init = &vaapi_frames_init,
989  .frames_uninit = &vaapi_frames_uninit,
990  .frames_get_buffer = &vaapi_get_buffer,
991  .transfer_get_formats = &vaapi_transfer_get_formats,
992  .transfer_data_to = &vaapi_transfer_data_to,
993  .transfer_data_from = &vaapi_transfer_data_from,
994 
995  .pix_fmts = (const enum AVPixelFormat[]) {
998  },
999 };
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:54
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:62
static struct @166 vaapi_format_map[]
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:106
int size
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:140
static void vaapi_device_free(AVHWDeviceContext *ctx)
static const struct @167 vaapi_driver_quirks_table[]
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:308
av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (%s)\, len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt), use_generic ? ac->func_descr_generic :ac->func_descr)
static enum AVSampleFormat formats[]
Definition: avresample.c:163
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:222
static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
unsigned int rt_format
#define FF_ARRAY_ELEMS(a)
#define RGBA(r, g, b, a)
Definition: dvbsubdec.c:94
int max_width
The maximum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:399
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:202
API-specific header for AV_HWDEVICE_TYPE_VAAPI.
static int vaapi_transfer_data_from(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
static int vaapi_device_init(AVHWDeviceContext *hwdev)
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
AVBufferPool * pool_internal
const AVFrame * source
enum AVHWDeviceType type
uint8_t
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:68
static void vaapi_buffer_free(void *opaque, uint8_t *data)
#define H
Definition: swscale.c:341
static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:85
const char data[16]
Definition: mxf.c:70
static int flags
Definition: log.c:50
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:140
#define AV_BUFFER_FLAG_READONLY
Always treat the buffer as read-only, even when it has only one reference.
Definition: buffer.h:113
static int vaapi_map_frame(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
#define src
Definition: vp8dsp.c:254
int width
width and height of the video frame
Definition: frame.h:179
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:124
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:190
VAAPI hardware pipeline configuration details.
#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:80
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:145
simple assert() macros that are a bit more flexible than ISO C assert().
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
VASurfaceAttrib * attributes
#define fail()
Definition: checkasm.h:80
int av_frame_copy(AVFrame *dst, const AVFrame *src)
Copy the frame data from src to dst.
Definition: frame.c:556
const char * match_string
int initial_pool_size
Initial size of the frame pool.
Definition: hwcontext.h:192
AVDictionary * opts
Definition: movenc.c:50
The driver does not destroy parameter buffers when they are used by vaRenderPicture().
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition: hwcontext.h:142
enum AVPixelFormat pix_fmt
AVFormatContext * ctx
Definition: movenc.c:48
static int device_init(AVFormatContext *ctx, int *width, int *height, uint32_t pix_fmt)
Definition: v4l2.c:177
static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats)
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:197
static int vaapi_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
if(ac->has_optimized_func)
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:191
NULL
Definition: eval.c:55
int min_width
The minimum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:392
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition: hwcontext.h:374
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:158
const char * friendly_name
uint8_t * data
The data buffer.
Definition: buffer.h:89
static int vaapi_frames_init(AVHWFramesContext *hwfc)
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition: hwcontext.h:155
unsigned int driver_quirks
Driver quirks to apply - this is filled by av_hwdevice_ctx_init(), with reference to a table of known...
The quirks field has been set by the user and should not be detected automatically by av_hwdevice_ctx...
#define MAP(va, rt, av)
static void vaapi_unmap_frame(void *opaque, uint8_t *data)
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:117
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:379
const VDPAUPixFmtMap * map
static int vaapi_get_image_format(AVHWDeviceContext *hwdev, enum AVPixelFormat pix_fmt, VAImageFormat **image_format)
AVHWFramesInternal * internal
Private data used internally by libavutil.
Definition: hwcontext.h:127
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:257
static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
static void * av_malloc_array(size_t nmemb, size_t size)
Definition: mem.h:92
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:146
void * user_opaque
Arbitrary user data, to be used e.g.
Definition: hwcontext.h:102
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
static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev, const void *hwconfig, AVHWFramesConstraints *constraints)
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:61
AVHWFrameTransferDirection
Definition: hwcontext.h:336
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:183
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:386
unsigned int quirks
VAAPI connection details.
VAConfigID config_id
ID of a VAAPI pipeline configuration.
void(* free)(struct AVHWDeviceContext *ctx)
This field may be set by the caller before calling av_hwdevice_ctx_init().
Definition: hwcontext.h:97
int height
Definition: frame.h:179
const HWContextType ff_hwcontext_type_vaapi
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:310
#define FFSWAP(type, a, b)
Definition: common.h:69
AVHWDeviceInternal * internal
Private data used internally by libavutil.
Definition: hwcontext.h:64
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:1704
unsigned int rt_format
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:215
AVPixelFormat
Pixel format.
Definition: pixfmt.h:57
unsigned int fourcc
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:211