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 #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 typedef struct VAAPIMapping {
74  // Handle to the derived or copied image which is mapped.
75  VAImage image;
76  // The mapping flags actually used.
77  int flags;
78 } VAAPIMapping;
79 
80 #define MAP(va, rt, av) { \
81  VA_FOURCC_ ## va, \
82  VA_RT_FORMAT_ ## rt, \
83  AV_PIX_FMT_ ## av \
84  }
85 // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
86 // plane swap cases. The frame handling below tries to hide these.
87 static struct {
88  unsigned int fourcc;
89  unsigned int rt_format;
91 } vaapi_format_map[] = {
92  MAP(NV12, YUV420, NV12),
93  MAP(YV12, YUV420, YUV420P), // With U/V planes swapped.
94  MAP(IYUV, YUV420, YUV420P),
95  //MAP(I420, YUV420, YUV420P), // Not in libva but used by Intel driver.
96 #ifdef VA_FOURCC_YV16
97  MAP(YV16, YUV422, YUV422P), // With U/V planes swapped.
98 #endif
99  MAP(422H, YUV422, YUV422P),
100  MAP(UYVY, YUV422, UYVY422),
101  MAP(YUY2, YUV422, YUYV422),
102  MAP(Y800, YUV400, GRAY8),
103 #ifdef VA_FOURCC_P010
104  MAP(P010, YUV420_10BPP, P010),
105 #endif
106  MAP(BGRA, RGB32, BGRA),
107  MAP(BGRX, RGB32, BGR0),
108  MAP(RGBA, RGB32, RGBA),
109  MAP(RGBX, RGB32, RGB0),
110 #ifdef VA_FOURCC_ABGR
111  MAP(ABGR, RGB32, ABGR),
112  MAP(XBGR, RGB32, 0BGR),
113 #endif
114  MAP(ARGB, RGB32, ARGB),
115  MAP(XRGB, RGB32, 0RGB),
116 };
117 #undef MAP
118 
120 {
121  int i;
122  for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
123  if (vaapi_format_map[i].fourcc == fourcc)
124  return vaapi_format_map[i].pix_fmt;
125  return AV_PIX_FMT_NONE;
126 }
127 
129  enum AVPixelFormat pix_fmt,
130  VAImageFormat **image_format)
131 {
132  VAAPIDeviceContext *ctx = hwdev->internal->priv;
133  int i;
134 
135  for (i = 0; i < ctx->nb_formats; i++) {
136  if (ctx->formats[i].pix_fmt == pix_fmt) {
137  if (image_format)
138  *image_format = &ctx->formats[i].image_format;
139  return 0;
140  }
141  }
142  return AVERROR(EINVAL);
143 }
144 
146  const void *hwconfig,
147  AVHWFramesConstraints *constraints)
148 {
149  AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
150  const AVVAAPIHWConfig *config = hwconfig;
151  VAAPIDeviceContext *ctx = hwdev->internal->priv;
152  VASurfaceAttrib *attr_list = NULL;
153  VAStatus vas;
154  enum AVPixelFormat pix_fmt;
155  unsigned int fourcc;
156  int err, i, j, attr_count, pix_fmt_count;
157 
158  if (config) {
159  attr_count = 0;
160  vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
161  0, &attr_count);
162  if (vas != VA_STATUS_SUCCESS) {
163  av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
164  "%d (%s).\n", vas, vaErrorStr(vas));
165  err = AVERROR(ENOSYS);
166  goto fail;
167  }
168 
169  attr_list = av_malloc(attr_count * sizeof(*attr_list));
170  if (!attr_list) {
171  err = AVERROR(ENOMEM);
172  goto fail;
173  }
174 
175  vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
176  attr_list, &attr_count);
177  if (vas != VA_STATUS_SUCCESS) {
178  av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
179  "%d (%s).\n", vas, vaErrorStr(vas));
180  err = AVERROR(ENOSYS);
181  goto fail;
182  }
183 
184  pix_fmt_count = 0;
185  for (i = 0; i < attr_count; i++) {
186  switch (attr_list[i].type) {
187  case VASurfaceAttribPixelFormat:
188  fourcc = attr_list[i].value.value.i;
189  pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
190  if (pix_fmt != AV_PIX_FMT_NONE) {
191  ++pix_fmt_count;
192  } else {
193  // Something unsupported - ignore.
194  }
195  break;
196  case VASurfaceAttribMinWidth:
197  constraints->min_width = attr_list[i].value.value.i;
198  break;
199  case VASurfaceAttribMinHeight:
200  constraints->min_height = attr_list[i].value.value.i;
201  break;
202  case VASurfaceAttribMaxWidth:
203  constraints->max_width = attr_list[i].value.value.i;
204  break;
205  case VASurfaceAttribMaxHeight:
206  constraints->max_height = attr_list[i].value.value.i;
207  break;
208  }
209  }
210  if (pix_fmt_count == 0) {
211  // Nothing usable found. Presumably there exists something which
212  // works, so leave the set null to indicate unknown.
213  constraints->valid_sw_formats = NULL;
214  } else {
215  constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
216  sizeof(pix_fmt));
217  if (!constraints->valid_sw_formats) {
218  err = AVERROR(ENOMEM);
219  goto fail;
220  }
221 
222  for (i = j = 0; i < attr_count; i++) {
223  if (attr_list[i].type != VASurfaceAttribPixelFormat)
224  continue;
225  fourcc = attr_list[i].value.value.i;
226  pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
227  if (pix_fmt != AV_PIX_FMT_NONE)
228  constraints->valid_sw_formats[j++] = pix_fmt;
229  }
230  av_assert0(j == pix_fmt_count);
231  constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
232  }
233  } else {
234  // No configuration supplied.
235  // Return the full set of image formats known by the implementation.
236  constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
237  sizeof(pix_fmt));
238  if (!constraints->valid_sw_formats) {
239  err = AVERROR(ENOMEM);
240  goto fail;
241  }
242  for (i = 0; i < ctx->nb_formats; i++)
243  constraints->valid_sw_formats[i] = ctx->formats[i].pix_fmt;
244  constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE;
245  }
246 
247  constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
248  if (!constraints->valid_hw_formats) {
249  err = AVERROR(ENOMEM);
250  goto fail;
251  }
252  constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
253  constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
254 
255  err = 0;
256 fail:
257  av_freep(&attr_list);
258  return err;
259 }
260 
261 static const struct {
262  const char *friendly_name;
263  const char *match_string;
264  unsigned int quirks;
266  {
267  "Intel i965 (Quick Sync)",
268  "i965",
270  },
271  {
272  "Intel iHD",
273  "ubit",
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 = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
455  int need_pixel_format = 1;
456  for (i = 0; i < avfc->nb_attributes; i++) {
457  if (ctx->attributes[i].type == VASurfaceAttribMemoryType)
458  need_memory_type = 0;
459  if (ctx->attributes[i].type == VASurfaceAttribPixelFormat)
460  need_pixel_format = 0;
461  }
462  ctx->nb_attributes =
463  avfc->nb_attributes + need_memory_type + need_pixel_format;
464 
465  ctx->attributes = av_malloc(ctx->nb_attributes *
466  sizeof(*ctx->attributes));
467  if (!ctx->attributes) {
468  err = AVERROR(ENOMEM);
469  goto fail;
470  }
471 
472  for (i = 0; i < avfc->nb_attributes; i++)
473  ctx->attributes[i] = avfc->attributes[i];
474  if (need_memory_type) {
475  ctx->attributes[i++] = (VASurfaceAttrib) {
476  .type = VASurfaceAttribMemoryType,
477  .flags = VA_SURFACE_ATTRIB_SETTABLE,
478  .value.type = VAGenericValueTypeInteger,
479  .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
480  };
481  }
482  if (need_pixel_format) {
483  ctx->attributes[i++] = (VASurfaceAttrib) {
484  .type = VASurfaceAttribPixelFormat,
485  .flags = VA_SURFACE_ATTRIB_SETTABLE,
486  .value.type = VAGenericValueTypeInteger,
487  .value.value.i = fourcc,
488  };
489  }
490  av_assert0(i == ctx->nb_attributes);
491 
492  ctx->rt_format = rt_format;
493 
494  if (hwfc->initial_pool_size > 0) {
495  // This pool will be usable as a render target, so we need to store
496  // all of the surface IDs somewhere that vaCreateContext() calls
497  // will be able to access them.
498  avfc->nb_surfaces = 0;
499  avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
500  sizeof(*avfc->surface_ids));
501  if (!avfc->surface_ids) {
502  err = AVERROR(ENOMEM);
503  goto fail;
504  }
505  } else {
506  // This pool allows dynamic sizing, and will not be usable as a
507  // render target.
508  avfc->nb_surfaces = 0;
509  avfc->surface_ids = NULL;
510  }
511 
512  hwfc->internal->pool_internal =
513  av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
515  if (!hwfc->internal->pool_internal) {
516  av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
517  err = AVERROR(ENOMEM);
518  goto fail;
519  }
520  }
521 
522  // Allocate a single surface to test whether vaDeriveImage() is going
523  // to work for the specific configuration.
524  if (hwfc->pool) {
525  test_surface = av_buffer_pool_get(hwfc->pool);
526  if (!test_surface) {
527  av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
528  "user-configured buffer pool.\n");
529  err = AVERROR(ENOMEM);
530  goto fail;
531  }
532  } else {
533  test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
534  if (!test_surface) {
535  av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
536  "internal buffer pool.\n");
537  err = AVERROR(ENOMEM);
538  goto fail;
539  }
540  }
541  test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
542 
543  ctx->derive_works = 0;
544 
546  hwfc->sw_format, &expected_format);
547  if (err == 0) {
548  vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
549  if (vas == VA_STATUS_SUCCESS) {
550  if (expected_format->fourcc == test_image.format.fourcc) {
551  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
552  ctx->derive_works = 1;
553  } else {
554  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
555  "derived image format %08x does not match "
556  "expected format %08x.\n",
557  expected_format->fourcc, test_image.format.fourcc);
558  }
559  vaDestroyImage(hwctx->display, test_image.image_id);
560  } else {
561  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
562  "deriving image does not work: "
563  "%d (%s).\n", vas, vaErrorStr(vas));
564  }
565  } else {
566  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
567  "image format is not supported.\n");
568  }
569 
570  av_buffer_unref(&test_surface);
571  return 0;
572 
573 fail:
574  av_buffer_unref(&test_surface);
575  av_freep(&avfc->surface_ids);
576  av_freep(&ctx->attributes);
577  return err;
578 }
579 
581 {
582  AVVAAPIFramesContext *avfc = hwfc->hwctx;
584 
585  av_freep(&avfc->surface_ids);
586  av_freep(&ctx->attributes);
587 }
588 
590 {
591  frame->buf[0] = av_buffer_pool_get(hwfc->pool);
592  if (!frame->buf[0])
593  return AVERROR(ENOMEM);
594 
595  frame->data[3] = frame->buf[0]->data;
596  frame->format = AV_PIX_FMT_VAAPI;
597  frame->width = hwfc->width;
598  frame->height = hwfc->height;
599 
600  return 0;
601 }
602 
605  enum AVPixelFormat **formats)
606 {
608  enum AVPixelFormat *pix_fmts, preferred_format;
609  int i, k;
610 
611  preferred_format = hwfc->sw_format;
612 
613  pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
614  if (!pix_fmts)
615  return AVERROR(ENOMEM);
616 
617  pix_fmts[0] = preferred_format;
618  k = 1;
619  for (i = 0; i < ctx->nb_formats; i++) {
620  if (ctx->formats[i].pix_fmt == preferred_format)
621  continue;
622  av_assert0(k < ctx->nb_formats);
623  pix_fmts[k++] = ctx->formats[i].pix_fmt;
624  }
625  av_assert0(k == ctx->nb_formats);
626  pix_fmts[k] = AV_PIX_FMT_NONE;
627 
628  *formats = pix_fmts;
629  return 0;
630 }
631 
633  HWMapDescriptor *hwmap)
634 {
635  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
636  VAAPIMapping *map = hwmap->priv;
637  VASurfaceID surface_id;
638  VAStatus vas;
639 
640  surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
641  av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
642 
643  vas = vaUnmapBuffer(hwctx->display, map->image.buf);
644  if (vas != VA_STATUS_SUCCESS) {
645  av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
646  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
647  }
648 
649  if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
650  !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
651  vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
652  0, 0, hwfc->width, hwfc->height,
653  0, 0, hwfc->width, hwfc->height);
654  if (vas != VA_STATUS_SUCCESS) {
655  av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
656  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
657  }
658  }
659 
660  vas = vaDestroyImage(hwctx->display, map->image.image_id);
661  if (vas != VA_STATUS_SUCCESS) {
662  av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
663  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
664  }
665 
666  av_free(map);
667 }
668 
670  AVFrame *dst, const AVFrame *src, int flags)
671 {
672  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
674  VASurfaceID surface_id;
675  VAImageFormat *image_format;
676  VAAPIMapping *map;
677  VAStatus vas;
678  void *address = NULL;
679  int err, i;
680 
681  surface_id = (VASurfaceID)(uintptr_t)src->data[3];
682  av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
683 
684  if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
685  // Requested direct mapping but it is not possible.
686  return AVERROR(EINVAL);
687  }
688  if (dst->format == AV_PIX_FMT_NONE)
689  dst->format = hwfc->sw_format;
690  if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
691  // Requested direct mapping but the formats do not match.
692  return AVERROR(EINVAL);
693  }
694 
695  err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
696  if (err < 0) {
697  // Requested format is not a valid output format.
698  return AVERROR(EINVAL);
699  }
700 
701  map = av_malloc(sizeof(*map));
702  if (!map)
703  return AVERROR(ENOMEM);
704  map->flags = flags;
705  map->image.image_id = VA_INVALID_ID;
706 
707  vas = vaSyncSurface(hwctx->display, surface_id);
708  if (vas != VA_STATUS_SUCCESS) {
709  av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
710  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
711  err = AVERROR(EIO);
712  goto fail;
713  }
714 
715  // The memory which we map using derive need not be connected to the CPU
716  // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
717  // memory is mappable but not cached, so normal memcpy()-like access is
718  // very slow to read it (but writing is ok). It is possible to read much
719  // faster with a copy routine which is aware of the limitation, but we
720  // assume for now that the user is not aware of that and would therefore
721  // prefer not to be given direct-mapped memory if they request read access.
722  if (ctx->derive_works && dst->format == hwfc->sw_format &&
723  ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
724  vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
725  if (vas != VA_STATUS_SUCCESS) {
726  av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
727  "surface %#x: %d (%s).\n",
728  surface_id, vas, vaErrorStr(vas));
729  err = AVERROR(EIO);
730  goto fail;
731  }
732  if (map->image.format.fourcc != image_format->fourcc) {
733  av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
734  "is in wrong format: expected %#08x, got %#08x.\n",
735  surface_id, image_format->fourcc, map->image.format.fourcc);
736  err = AVERROR(EIO);
737  goto fail;
738  }
740  } else {
741  vas = vaCreateImage(hwctx->display, image_format,
742  hwfc->width, hwfc->height, &map->image);
743  if (vas != VA_STATUS_SUCCESS) {
744  av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
745  "surface %#x: %d (%s).\n",
746  surface_id, vas, vaErrorStr(vas));
747  err = AVERROR(EIO);
748  goto fail;
749  }
750  if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
751  vas = vaGetImage(hwctx->display, surface_id, 0, 0,
752  hwfc->width, hwfc->height, map->image.image_id);
753  if (vas != VA_STATUS_SUCCESS) {
754  av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
755  "surface %#x: %d (%s).\n",
756  surface_id, vas, vaErrorStr(vas));
757  err = AVERROR(EIO);
758  goto fail;
759  }
760  }
761  }
762 
763  vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
764  if (vas != VA_STATUS_SUCCESS) {
765  av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
766  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
767  err = AVERROR(EIO);
768  goto fail;
769  }
770 
772  dst, src, &vaapi_unmap_frame, map);
773  if (err < 0)
774  goto fail;
775 
776  dst->width = src->width;
777  dst->height = src->height;
778 
779  for (i = 0; i < map->image.num_planes; i++) {
780  dst->data[i] = (uint8_t*)address + map->image.offsets[i];
781  dst->linesize[i] = map->image.pitches[i];
782  }
783  if (
784 #ifdef VA_FOURCC_YV16
785  map->image.format.fourcc == VA_FOURCC_YV16 ||
786 #endif
787  map->image.format.fourcc == VA_FOURCC_YV12) {
788  // Chroma planes are YVU rather than YUV, so swap them.
789  FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
790  }
791 
792  return 0;
793 
794 fail:
795  if (map) {
796  if (address)
797  vaUnmapBuffer(hwctx->display, map->image.buf);
798  if (map->image.image_id != VA_INVALID_ID)
799  vaDestroyImage(hwctx->display, map->image.image_id);
800  av_free(map);
801  }
802  return err;
803 }
804 
806  AVFrame *dst, const AVFrame *src)
807 {
808  AVFrame *map;
809  int err;
810 
811  if (dst->width > hwfc->width || dst->height > hwfc->height)
812  return AVERROR(EINVAL);
813 
814  map = av_frame_alloc();
815  if (!map)
816  return AVERROR(ENOMEM);
817  map->format = dst->format;
818 
819  err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
820  if (err)
821  goto fail;
822 
823  map->width = dst->width;
824  map->height = dst->height;
825 
826  err = av_frame_copy(dst, map);
827  if (err)
828  goto fail;
829 
830  err = 0;
831 fail:
832  av_frame_free(&map);
833  return err;
834 }
835 
837  AVFrame *dst, const AVFrame *src)
838 {
839  AVFrame *map;
840  int err;
841 
842  if (src->width > hwfc->width || src->height > hwfc->height)
843  return AVERROR(EINVAL);
844 
845  map = av_frame_alloc();
846  if (!map)
847  return AVERROR(ENOMEM);
848  map->format = src->format;
849 
851  if (err)
852  goto fail;
853 
854  map->width = src->width;
855  map->height = src->height;
856 
857  err = av_frame_copy(map, src);
858  if (err)
859  goto fail;
860 
861  err = 0;
862 fail:
863  av_frame_free(&map);
864  return err;
865 }
866 
867 static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
868  const AVFrame *src, int flags)
869 {
870  int err;
871 
872  if (dst->format != AV_PIX_FMT_NONE) {
873  err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
874  if (err < 0)
875  return AVERROR(ENOSYS);
876  }
877 
878  err = vaapi_map_frame(hwfc, dst, src, flags);
879  if (err)
880  return err;
881 
882  err = av_frame_copy_props(dst, src);
883  if (err)
884  return err;
885 
886  return 0;
887 }
888 
890 {
891  AVVAAPIDeviceContext *hwctx = ctx->hwctx;
892  VAAPIDevicePriv *priv = ctx->user_opaque;
893 
894  if (hwctx->display)
895  vaTerminate(hwctx->display);
896 
897 #if HAVE_VAAPI_X11
898  if (priv->x11_display)
899  XCloseDisplay(priv->x11_display);
900 #endif
901 
902  if (priv->drm_fd >= 0)
903  close(priv->drm_fd);
904 
905  av_freep(&priv);
906 }
907 
908 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
909  AVDictionary *opts, int flags)
910 {
911  AVVAAPIDeviceContext *hwctx = ctx->hwctx;
912  VAAPIDevicePriv *priv;
913  VADisplay display = 0;
914  VAStatus vas;
915  int major, minor;
916 
917  priv = av_mallocz(sizeof(*priv));
918  if (!priv)
919  return AVERROR(ENOMEM);
920 
921  priv->drm_fd = -1;
922 
923  ctx->user_opaque = priv;
924  ctx->free = vaapi_device_free;
925 
926 #if HAVE_VAAPI_X11
927  if (!display && !(device && device[0] == '/')) {
928  // Try to open the device as an X11 display.
929  priv->x11_display = XOpenDisplay(device);
930  if (!priv->x11_display) {
931  av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
932  "%s.\n", XDisplayName(device));
933  } else {
934  display = vaGetDisplay(priv->x11_display);
935  if (!display) {
936  av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
937  "from X11 display %s.\n", XDisplayName(device));
938  return AVERROR_UNKNOWN;
939  }
940 
941  av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
942  "X11 display %s.\n", XDisplayName(device));
943  }
944  }
945 #endif
946 
947 #if HAVE_VAAPI_DRM
948  if (!display) {
949  // Try to open the device as a DRM path.
950  // Default to using the first render node if the user did not
951  // supply a path.
952  const char *path = device ? device : "/dev/dri/renderD128";
953  priv->drm_fd = open(path, O_RDWR);
954  if (priv->drm_fd < 0) {
955  av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
956  path);
957  } else {
958  display = vaGetDisplayDRM(priv->drm_fd);
959  if (!display) {
960  av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
961  "from DRM device %s.\n", path);
962  return AVERROR_UNKNOWN;
963  }
964 
965  av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
966  "DRM device %s.\n", path);
967  }
968  }
969 #endif
970 
971  if (!display) {
972  av_log(ctx, AV_LOG_ERROR, "No VA display found for "
973  "device: %s.\n", device ? device : "");
974  return AVERROR(EINVAL);
975  }
976 
977  hwctx->display = display;
978 
979  vas = vaInitialize(display, &major, &minor);
980  if (vas != VA_STATUS_SUCCESS) {
981  av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
982  "connection: %d (%s).\n", vas, vaErrorStr(vas));
983  return AVERROR(EIO);
984  }
985  av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
986  "version %d.%d\n", major, minor);
987 
988  return 0;
989 }
990 
993  .name = "VAAPI",
994 
995  .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
996  .device_priv_size = sizeof(VAAPIDeviceContext),
997  .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
998  .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
999  .frames_priv_size = sizeof(VAAPIFramesContext),
1000 
1001  .device_create = &vaapi_device_create,
1003  .device_uninit = &vaapi_device_uninit,
1004  .frames_get_constraints = &vaapi_frames_get_constraints,
1005  .frames_init = &vaapi_frames_init,
1006  .frames_uninit = &vaapi_frames_uninit,
1007  .frames_get_buffer = &vaapi_get_buffer,
1008  .transfer_get_formats = &vaapi_transfer_get_formats,
1009  .transfer_data_to = &vaapi_transfer_data_to,
1010  .transfer_data_from = &vaapi_transfer_data_from,
1011  .map_to = NULL,
1012  .map_from = &vaapi_map_from,
1013 
1014  .pix_fmts = (const enum AVPixelFormat[]) {
1017  },
1018 };
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:54
#define NULL
Definition: coverity.c:32
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:187
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:101
static void vaapi_device_free(AVHWDeviceContext *ctx)
The mapped frame will be overwritten completely in subsequent operations, so the current frame data n...
Definition: hwcontext.h:454
The mapping must be writeable.
Definition: hwcontext.h:448
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:370
static FFServerConfig config
Definition: ffserver.c:193
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 RGBA(r, g, b, a)
Definition: dvbsubdec.c:96
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:222
#define src
Definition: vp8dsp.c:254
int max_width
The maximum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:398
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:515
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
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:150
static void vaapi_buffer_free(void *opaque, uint8_t *data)
static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
static AVFrame * frame
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:85
static int flags
Definition: log.c:57
#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
#define av_log(a,...)
static int vaapi_map_frame(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags)
int width
width and height of the video frame
Definition: frame.h:239
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
The driver does not support the VASurfaceAttribMemoryType attribute, so the surface allocation code w...
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:97
#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:163
The quirks field has been set by the user and should not be detected automatically by av_hwdevice_ctx...
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
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:89
int av_frame_copy(AVFrame *dst, const AVFrame *src)
Copy the frame data from src to dst.
Definition: frame.c:733
const char * match_string
int initial_pool_size
Initial size of the frame pool.
Definition: hwcontext.h:192
AVDictionary * opts
Definition: movenc.c:50
AVFrame * source
A reference to the original source of the mapping.
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition: hwcontext.h:142
enum AVPixelFormat pix_fmt
AVFormatContext * ctx
Definition: movenc.c:48
static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats)
static const struct @242 vaapi_driver_quirks_table[]
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:251
int min_width
The minimum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:391
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:373
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:218
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:155
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:553
#define MAP(va, rt, av)
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:378
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:262
The mapping must be readable.
Definition: hwcontext.h:444
static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:201
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
if(ret< 0)
Definition: vf_mcdeint.c:282
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:107
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:71
AVHWFrameTransferDirection
Definition: hwcontext.h:335
static AVBufferRef * vaapi_pool_alloc(void *opaque, int size)
The driver does not destroy parameter buffers when they are used by vaRenderPicture().
pixel format definitions
AVBufferPool * pool
A pool from which the frames are allocated by av_hwframe_get_buffer().
Definition: hwcontext.h:183
#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:385
The mapping must be direct.
Definition: hwcontext.h:460
#define H
Definition: pixlet.c:37
unsigned int quirks
VAAPI connection details.
VAConfigID config_id
ID of a VAAPI pipeline configuration.
static struct @241 vaapi_format_map[]
int height
Definition: frame.h:239
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: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:2249
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: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:596