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 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 #ifdef VA_FOURCC_ABGR
119  MAP(ABGR, RGB32, ABGR),
120  MAP(XBGR, RGB32, 0BGR),
121 #endif
122  MAP(ARGB, RGB32, ARGB),
123  MAP(XRGB, RGB32, 0RGB),
124 };
125 #undef MAP
126 
128 {
129  int i;
130  for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
131  if (vaapi_format_map[i].fourcc == fourcc)
132  return vaapi_format_map[i].pix_fmt;
133  return AV_PIX_FMT_NONE;
134 }
135 
137  enum AVPixelFormat pix_fmt,
138  VAImageFormat **image_format)
139 {
140  VAAPIDeviceContext *ctx = hwdev->internal->priv;
141  int i;
142 
143  for (i = 0; i < ctx->nb_formats; i++) {
144  if (ctx->formats[i].pix_fmt == pix_fmt) {
145  *image_format = &ctx->formats[i].image_format;
146  return 0;
147  }
148  }
149  return AVERROR(EINVAL);
150 }
151 
153  const void *hwconfig,
154  AVHWFramesConstraints *constraints)
155 {
156  AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
157  const AVVAAPIHWConfig *config = hwconfig;
158  VAAPIDeviceContext *ctx = hwdev->internal->priv;
159  VASurfaceAttrib *attr_list = NULL;
160  VAStatus vas;
161  enum AVPixelFormat pix_fmt;
162  unsigned int fourcc;
163  int err, i, j, attr_count, pix_fmt_count;
164 
165  if (config) {
166  attr_count = 0;
167  vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
168  0, &attr_count);
169  if (vas != VA_STATUS_SUCCESS) {
170  av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
171  "%d (%s).\n", vas, vaErrorStr(vas));
172  err = AVERROR(ENOSYS);
173  goto fail;
174  }
175 
176  attr_list = av_malloc(attr_count * sizeof(*attr_list));
177  if (!attr_list) {
178  err = AVERROR(ENOMEM);
179  goto fail;
180  }
181 
182  vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
183  attr_list, &attr_count);
184  if (vas != VA_STATUS_SUCCESS) {
185  av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
186  "%d (%s).\n", vas, vaErrorStr(vas));
187  err = AVERROR(ENOSYS);
188  goto fail;
189  }
190 
191  pix_fmt_count = 0;
192  for (i = 0; i < attr_count; i++) {
193  switch (attr_list[i].type) {
194  case VASurfaceAttribPixelFormat:
195  fourcc = attr_list[i].value.value.i;
196  pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
197  if (pix_fmt != AV_PIX_FMT_NONE) {
198  ++pix_fmt_count;
199  } else {
200  // Something unsupported - ignore.
201  }
202  break;
203  case VASurfaceAttribMinWidth:
204  constraints->min_width = attr_list[i].value.value.i;
205  break;
206  case VASurfaceAttribMinHeight:
207  constraints->min_height = attr_list[i].value.value.i;
208  break;
209  case VASurfaceAttribMaxWidth:
210  constraints->max_width = attr_list[i].value.value.i;
211  break;
212  case VASurfaceAttribMaxHeight:
213  constraints->max_height = attr_list[i].value.value.i;
214  break;
215  }
216  }
217  if (pix_fmt_count == 0) {
218  // Nothing usable found. Presumably there exists something which
219  // works, so leave the set null to indicate unknown.
220  constraints->valid_sw_formats = NULL;
221  } else {
222  constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
223  sizeof(pix_fmt));
224  if (!constraints->valid_sw_formats) {
225  err = AVERROR(ENOMEM);
226  goto fail;
227  }
228 
229  for (i = j = 0; i < attr_count; i++) {
230  if (attr_list[i].type != VASurfaceAttribPixelFormat)
231  continue;
232  fourcc = attr_list[i].value.value.i;
233  pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
234  if (pix_fmt != AV_PIX_FMT_NONE)
235  constraints->valid_sw_formats[j++] = pix_fmt;
236  }
237  av_assert0(j == pix_fmt_count);
238  constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
239  }
240  } else {
241  // No configuration supplied.
242  // Return the full set of image formats known by the implementation.
243  constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
244  sizeof(pix_fmt));
245  if (!constraints->valid_sw_formats) {
246  err = AVERROR(ENOMEM);
247  goto fail;
248  }
249  for (i = 0; i < ctx->nb_formats; i++)
250  constraints->valid_sw_formats[i] = ctx->formats[i].pix_fmt;
251  constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE;
252  }
253 
254  constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
255  if (!constraints->valid_hw_formats) {
256  err = AVERROR(ENOMEM);
257  goto fail;
258  }
259  constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
260  constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
261 
262  err = 0;
263 fail:
264  av_freep(&attr_list);
265  return err;
266 }
267 
269 {
270  VAAPIDeviceContext *ctx = hwdev->internal->priv;
271  AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
272  VAImageFormat *image_list = NULL;
273  VAStatus vas;
274  int err, i, image_count;
275  enum AVPixelFormat pix_fmt;
276  unsigned int fourcc;
277 
278  image_count = vaMaxNumImageFormats(hwctx->display);
279  if (image_count <= 0) {
280  err = AVERROR(EIO);
281  goto fail;
282  }
283  image_list = av_malloc(image_count * sizeof(*image_list));
284  if (!image_list) {
285  err = AVERROR(ENOMEM);
286  goto fail;
287  }
288  vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
289  if (vas != VA_STATUS_SUCCESS) {
290  err = AVERROR(EIO);
291  goto fail;
292  }
293 
294  ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
295  if (!ctx->formats) {
296  err = AVERROR(ENOMEM);
297  goto fail;
298  }
299  ctx->nb_formats = 0;
300  for (i = 0; i < image_count; i++) {
301  fourcc = image_list[i].fourcc;
302  pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
303  if (pix_fmt == AV_PIX_FMT_NONE) {
304  av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
305  fourcc);
306  } else {
307  av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
308  fourcc, av_get_pix_fmt_name(pix_fmt));
309  ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
310  ctx->formats[ctx->nb_formats].image_format = image_list[i];
311  ++ctx->nb_formats;
312  }
313  }
314 
315  av_free(image_list);
316  return 0;
317 fail:
318  av_freep(&ctx->formats);
319  av_free(image_list);
320  return err;
321 }
322 
324 {
325  VAAPIDeviceContext *ctx = hwdev->internal->priv;
326 
327  av_freep(&ctx->formats);
328 }
329 
330 static void vaapi_buffer_free(void *opaque, uint8_t *data)
331 {
332  AVHWFramesContext *hwfc = opaque;
333  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
334  VASurfaceID surface_id;
335  VAStatus vas;
336 
337  surface_id = (VASurfaceID)(uintptr_t)data;
338 
339  vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
340  if (vas != VA_STATUS_SUCCESS) {
341  av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
342  "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
343  }
344 }
345 
346 static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
347 {
348  AVHWFramesContext *hwfc = opaque;
350  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
351  AVVAAPIFramesContext *avfc = hwfc->hwctx;
352  VASurfaceID surface_id;
353  VAStatus vas;
354  AVBufferRef *ref;
355 
356  vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
357  hwfc->width, hwfc->height,
358  &surface_id, 1,
359  ctx->attributes, ctx->nb_attributes);
360  if (vas != VA_STATUS_SUCCESS) {
361  av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
362  "%d (%s).\n", vas, vaErrorStr(vas));
363  return NULL;
364  }
365  av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
366 
367  ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
368  sizeof(surface_id), &vaapi_buffer_free,
370  if (!ref) {
371  vaDestroySurfaces(hwctx->display, &surface_id, 1);
372  return NULL;
373  }
374 
375  if (hwfc->initial_pool_size > 0) {
376  // This is a fixed-size pool, so we must still be in the initial
377  // allocation sequence.
379  avfc->surface_ids[avfc->nb_surfaces] = surface_id;
380  ++avfc->nb_surfaces;
381  }
382 
383  return ref;
384 }
385 
387 {
388  AVVAAPIFramesContext *avfc = hwfc->hwctx;
390  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
391  VAImageFormat *expected_format;
392  AVBufferRef *test_surface = NULL;
393  VASurfaceID test_surface_id;
394  VAImage test_image;
395  VAStatus vas;
396  int err, i;
397  unsigned int fourcc, rt_format;
398 
399  for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
400  if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) {
401  fourcc = vaapi_format_map[i].fourcc;
402  rt_format = vaapi_format_map[i].rt_format;
403  break;
404  }
405  }
406  if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
407  av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
409  return AVERROR(EINVAL);
410  }
411 
412  if (!hwfc->pool) {
413  int need_memory_type = 1, need_pixel_format = 1;
414  for (i = 0; i < avfc->nb_attributes; i++) {
415  if (ctx->attributes[i].type == VASurfaceAttribMemoryType)
416  need_memory_type = 0;
417  if (ctx->attributes[i].type == VASurfaceAttribPixelFormat)
418  need_pixel_format = 0;
419  }
420  ctx->nb_attributes =
421  avfc->nb_attributes + need_memory_type + need_pixel_format;
422 
423  ctx->attributes = av_malloc(ctx->nb_attributes *
424  sizeof(*ctx->attributes));
425  if (!ctx->attributes) {
426  err = AVERROR(ENOMEM);
427  goto fail;
428  }
429 
430  for (i = 0; i < avfc->nb_attributes; i++)
431  ctx->attributes[i] = avfc->attributes[i];
432  if (need_memory_type) {
433  ctx->attributes[i++] = (VASurfaceAttrib) {
434  .type = VASurfaceAttribMemoryType,
435  .flags = VA_SURFACE_ATTRIB_SETTABLE,
436  .value.type = VAGenericValueTypeInteger,
437  .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
438  };
439  }
440  if (need_pixel_format) {
441  ctx->attributes[i++] = (VASurfaceAttrib) {
442  .type = VASurfaceAttribPixelFormat,
443  .flags = VA_SURFACE_ATTRIB_SETTABLE,
444  .value.type = VAGenericValueTypeInteger,
445  .value.value.i = fourcc,
446  };
447  }
448  av_assert0(i == ctx->nb_attributes);
449 
450  ctx->rt_format = rt_format;
451 
452  if (hwfc->initial_pool_size > 0) {
453  // This pool will be usable as a render target, so we need to store
454  // all of the surface IDs somewhere that vaCreateContext() calls
455  // will be able to access them.
456  avfc->nb_surfaces = 0;
457  avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
458  sizeof(*avfc->surface_ids));
459  if (!avfc->surface_ids) {
460  err = AVERROR(ENOMEM);
461  goto fail;
462  }
463  } else {
464  // This pool allows dynamic sizing, and will not be usable as a
465  // render target.
466  avfc->nb_surfaces = 0;
467  avfc->surface_ids = NULL;
468  }
469 
470  hwfc->internal->pool_internal =
471  av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
473  if (!hwfc->internal->pool_internal) {
474  av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
475  err = AVERROR(ENOMEM);
476  goto fail;
477  }
478  }
479 
480  // Allocate a single surface to test whether vaDeriveImage() is going
481  // to work for the specific configuration.
482  if (hwfc->pool) {
483  test_surface = av_buffer_pool_get(hwfc->pool);
484  if (!test_surface) {
485  av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
486  "user-configured buffer pool.\n");
487  err = AVERROR(ENOMEM);
488  goto fail;
489  }
490  } else {
491  test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
492  if (!test_surface) {
493  av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
494  "internal buffer pool.\n");
495  err = AVERROR(ENOMEM);
496  goto fail;
497  }
498  }
499  test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
500 
501  ctx->derive_works = 0;
502 
504  hwfc->sw_format, &expected_format);
505  if (err == 0) {
506  vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
507  if (vas == VA_STATUS_SUCCESS) {
508  if (expected_format->fourcc == test_image.format.fourcc) {
509  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
510  ctx->derive_works = 1;
511  } else {
512  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
513  "derived image format %08x does not match "
514  "expected format %08x.\n",
515  expected_format->fourcc, test_image.format.fourcc);
516  }
517  vaDestroyImage(hwctx->display, test_image.image_id);
518  } else {
519  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
520  "deriving image does not work: "
521  "%d (%s).\n", vas, vaErrorStr(vas));
522  }
523  } else {
524  av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
525  "image format is not supported.\n");
526  }
527 
528  av_buffer_unref(&test_surface);
529  return 0;
530 
531 fail:
532  av_buffer_unref(&test_surface);
533  av_freep(&avfc->surface_ids);
534  av_freep(&ctx->attributes);
535  return err;
536 }
537 
539 {
540  AVVAAPIFramesContext *avfc = hwfc->hwctx;
542 
543  av_freep(&avfc->surface_ids);
544  av_freep(&ctx->attributes);
545 }
546 
548 {
549  frame->buf[0] = av_buffer_pool_get(hwfc->pool);
550  if (!frame->buf[0])
551  return AVERROR(ENOMEM);
552 
553  frame->data[3] = frame->buf[0]->data;
554  frame->format = AV_PIX_FMT_VAAPI;
555  frame->width = hwfc->width;
556  frame->height = hwfc->height;
557 
558  return 0;
559 }
560 
563  enum AVPixelFormat **formats)
564 {
566  enum AVPixelFormat *pix_fmts, preferred_format;
567  int i, k;
568 
569  preferred_format = hwfc->sw_format;
570 
571  pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
572  if (!pix_fmts)
573  return AVERROR(ENOMEM);
574 
575  pix_fmts[0] = preferred_format;
576  k = 1;
577  for (i = 0; i < ctx->nb_formats; i++) {
578  if (ctx->formats[i].pix_fmt == preferred_format)
579  continue;
580  av_assert0(k < ctx->nb_formats);
581  pix_fmts[k++] = ctx->formats[i].pix_fmt;
582  }
583  av_assert0(k == ctx->nb_formats);
584  pix_fmts[k] = AV_PIX_FMT_NONE;
585 
586  *formats = pix_fmts;
587  return 0;
588 }
589 
590 static void vaapi_unmap_frame(void *opaque, uint8_t *data)
591 {
592  AVHWFramesContext *hwfc = opaque;
593  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
595  const AVFrame *src;
596  VASurfaceID surface_id;
597  VAStatus vas;
598 
599  src = map->source;
600  surface_id = (VASurfaceID)(uintptr_t)src->data[3];
601  av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
602 
603  vas = vaUnmapBuffer(hwctx->display, map->image.buf);
604  if (vas != VA_STATUS_SUCCESS) {
605  av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
606  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
607  }
608 
609  if ((map->flags & VAAPI_MAP_WRITE) &&
610  !(map->flags & VAAPI_MAP_DIRECT)) {
611  vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
612  0, 0, hwfc->width, hwfc->height,
613  0, 0, hwfc->width, hwfc->height);
614  if (vas != VA_STATUS_SUCCESS) {
615  av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
616  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
617  }
618  }
619 
620  vas = vaDestroyImage(hwctx->display, map->image.image_id);
621  if (vas != VA_STATUS_SUCCESS) {
622  av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
623  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
624  }
625 
626  av_free(map);
627 }
628 
630  AVFrame *dst, const AVFrame *src, int flags)
631 {
632  AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
634  VASurfaceID surface_id;
635  VAImageFormat *image_format;
637  VAStatus vas;
638  void *address = NULL;
639  int err, i;
640 
641  surface_id = (VASurfaceID)(uintptr_t)src->data[3];
642  av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
643 
644  if (!ctx->derive_works && (flags & VAAPI_MAP_DIRECT)) {
645  // Requested direct mapping but it is not possible.
646  return AVERROR(EINVAL);
647  }
648  if (dst->format == AV_PIX_FMT_NONE)
649  dst->format = hwfc->sw_format;
650  if (dst->format != hwfc->sw_format && (flags & VAAPI_MAP_DIRECT)) {
651  // Requested direct mapping but the formats do not match.
652  return AVERROR(EINVAL);
653  }
654 
655  err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
656  if (err < 0) {
657  // Requested format is not a valid output format.
658  return AVERROR(EINVAL);
659  }
660 
661  map = av_malloc(sizeof(VAAPISurfaceMap));
662  if (!map)
663  return AVERROR(ENOMEM);
664 
665  map->source = src;
666  map->flags = flags;
667  map->image.image_id = VA_INVALID_ID;
668 
669  vas = vaSyncSurface(hwctx->display, surface_id);
670  if (vas != VA_STATUS_SUCCESS) {
671  av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
672  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
673  err = AVERROR(EIO);
674  goto fail;
675  }
676 
677  // The memory which we map using derive need not be connected to the CPU
678  // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
679  // memory is mappable but not cached, so normal memcpy()-like access is
680  // very slow to read it (but writing is ok). It is possible to read much
681  // faster with a copy routine which is aware of the limitation, but we
682  // assume for now that the user is not aware of that and would therefore
683  // prefer not to be given direct-mapped memory if they request read access.
684  if (ctx->derive_works &&
685  ((flags & VAAPI_MAP_DIRECT) || !(flags & VAAPI_MAP_READ))) {
686  vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
687  if (vas != VA_STATUS_SUCCESS) {
688  av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
689  "surface %#x: %d (%s).\n",
690  surface_id, vas, vaErrorStr(vas));
691  err = AVERROR(EIO);
692  goto fail;
693  }
694  if (map->image.format.fourcc != image_format->fourcc) {
695  av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
696  "is in wrong format: expected %#08x, got %#08x.\n",
697  surface_id, image_format->fourcc, map->image.format.fourcc);
698  err = AVERROR(EIO);
699  goto fail;
700  }
701  map->flags |= VAAPI_MAP_DIRECT;
702  } else {
703  vas = vaCreateImage(hwctx->display, image_format,
704  hwfc->width, hwfc->height, &map->image);
705  if (vas != VA_STATUS_SUCCESS) {
706  av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
707  "surface %#x: %d (%s).\n",
708  surface_id, vas, vaErrorStr(vas));
709  err = AVERROR(EIO);
710  goto fail;
711  }
712  if (flags & VAAPI_MAP_READ) {
713  vas = vaGetImage(hwctx->display, surface_id, 0, 0,
714  hwfc->width, hwfc->height, map->image.image_id);
715  if (vas != VA_STATUS_SUCCESS) {
716  av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
717  "surface %#x: %d (%s).\n",
718  surface_id, vas, vaErrorStr(vas));
719  err = AVERROR(EIO);
720  goto fail;
721  }
722  }
723  }
724 
725  vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
726  if (vas != VA_STATUS_SUCCESS) {
727  av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
728  "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
729  err = AVERROR(EIO);
730  goto fail;
731  }
732 
733  dst->width = src->width;
734  dst->height = src->height;
735 
736  for (i = 0; i < map->image.num_planes; i++) {
737  dst->data[i] = (uint8_t*)address + map->image.offsets[i];
738  dst->linesize[i] = map->image.pitches[i];
739  }
740  if (
741 #ifdef VA_FOURCC_YV16
742  map->image.format.fourcc == VA_FOURCC_YV16 ||
743 #endif
744  map->image.format.fourcc == VA_FOURCC_YV12) {
745  // Chroma planes are YVU rather than YUV, so swap them.
746  FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
747  }
748 
749  dst->buf[0] = av_buffer_create((uint8_t*)map, sizeof(*map),
750  &vaapi_unmap_frame, hwfc, 0);
751  if (!dst->buf[0]) {
752  err = AVERROR(ENOMEM);
753  goto fail;
754  }
755 
756  return 0;
757 
758 fail:
759  if (map) {
760  if (address)
761  vaUnmapBuffer(hwctx->display, map->image.buf);
762  if (map->image.image_id != VA_INVALID_ID)
763  vaDestroyImage(hwctx->display, map->image.image_id);
764  av_free(map);
765  }
766  return err;
767 }
768 
770  AVFrame *dst, const AVFrame *src)
771 {
772  AVFrame *map;
773  int err;
774 
775  map = av_frame_alloc();
776  if (!map)
777  return AVERROR(ENOMEM);
778  map->format = dst->format;
779 
780  err = vaapi_map_frame(hwfc, map, src, VAAPI_MAP_READ);
781  if (err)
782  goto fail;
783 
784  err = av_frame_copy(dst, map);
785  if (err)
786  goto fail;
787 
788  err = 0;
789 fail:
790  av_frame_free(&map);
791  return err;
792 }
793 
795  AVFrame *dst, const AVFrame *src)
796 {
797  AVFrame *map;
798  int err;
799 
800  map = av_frame_alloc();
801  if (!map)
802  return AVERROR(ENOMEM);
803  map->format = src->format;
804 
805  err = vaapi_map_frame(hwfc, map, dst, VAAPI_MAP_WRITE);
806  if (err)
807  goto fail;
808 
809  err = av_frame_copy(map, src);
810  if (err)
811  goto fail;
812 
813  err = 0;
814 fail:
815  av_frame_free(&map);
816  return err;
817 }
818 
820 {
821  AVVAAPIDeviceContext *hwctx = ctx->hwctx;
822  VAAPIDevicePriv *priv = ctx->user_opaque;
823 
824  if (hwctx->display)
825  vaTerminate(hwctx->display);
826 
827 #if HAVE_VAAPI_X11
828  if (priv->x11_display)
829  XCloseDisplay(priv->x11_display);
830 #endif
831 
832  if (priv->drm_fd >= 0)
833  close(priv->drm_fd);
834 
835  av_freep(&priv);
836 }
837 
838 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
839  AVDictionary *opts, int flags)
840 {
841  AVVAAPIDeviceContext *hwctx = ctx->hwctx;
842  VAAPIDevicePriv *priv;
843  VADisplay display = 0;
844  VAStatus vas;
845  int major, minor;
846 
847  priv = av_mallocz(sizeof(*priv));
848  if (!priv)
849  return AVERROR(ENOMEM);
850 
851  priv->drm_fd = -1;
852 
853  ctx->user_opaque = priv;
854  ctx->free = vaapi_device_free;
855 
856 #if HAVE_VAAPI_X11
857  if (!display && !(device && device[0] == '/')) {
858  // Try to open the device as an X11 display.
859  priv->x11_display = XOpenDisplay(device);
860  if (!priv->x11_display) {
861  av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
862  "%s.\n", XDisplayName(device));
863  } else {
864  display = vaGetDisplay(priv->x11_display);
865  if (!display) {
866  av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
867  "from X11 display %s.\n", XDisplayName(device));
868  return AVERROR_UNKNOWN;
869  }
870 
871  av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
872  "X11 display %s.\n", XDisplayName(device));
873  }
874  }
875 #endif
876 
877 #if HAVE_VAAPI_DRM
878  if (!display && device) {
879  // Try to open the device as a DRM path.
880  priv->drm_fd = open(device, O_RDWR);
881  if (priv->drm_fd < 0) {
882  av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
883  device);
884  } else {
885  display = vaGetDisplayDRM(priv->drm_fd);
886  if (!display) {
887  av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
888  "from DRM device %s.\n", device);
889  return AVERROR_UNKNOWN;
890  }
891 
892  av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
893  "DRM device %s.\n", device);
894  }
895  }
896 #endif
897 
898  if (!display) {
899  av_log(ctx, AV_LOG_ERROR, "No VA display found for "
900  "device: %s.\n", device ? device : "");
901  return AVERROR(EINVAL);
902  }
903 
904  hwctx->display = display;
905 
906  vas = vaInitialize(display, &major, &minor);
907  if (vas != VA_STATUS_SUCCESS) {
908  av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
909  "connection: %d (%s).\n", vas, vaErrorStr(vas));
910  return AVERROR(EIO);
911  }
912  av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
913  "version %d.%d\n", major, minor);
914 
915  return 0;
916 }
917 
920  .name = "VAAPI",
921 
922  .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
923  .device_priv_size = sizeof(VAAPIDeviceContext),
924  .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
925  .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
926  .frames_priv_size = sizeof(VAAPIFramesContext),
927 
928  .device_create = &vaapi_device_create,
930  .device_uninit = &vaapi_device_uninit,
931  .frames_get_constraints = &vaapi_frames_get_constraints,
932  .frames_init = &vaapi_frames_init,
933  .frames_uninit = &vaapi_frames_uninit,
934  .frames_get_buffer = &vaapi_get_buffer,
935  .transfer_get_formats = &vaapi_transfer_get_formats,
936  .transfer_data_to = &vaapi_transfer_data_to,
937  .transfer_data_from = &vaapi_transfer_data_from,
938 
939  .pix_fmts = (const enum AVPixelFormat[]) {
942  },
943 };
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:124
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:184
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:186
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:367
static FFServerConfig config
Definition: ffserver.c:202
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 RGBA(r, g, b, a)
Definition: dvbsubdec.c:153
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:252
int max_width
The maximum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:391
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
#define av_malloc(s)
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:145
static void vaapi_buffer_free(void *opaque, uint8_t *data)
#define H
Definition: swscale.c:355
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
#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:236
#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: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:158
#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:83
int av_frame_copy(AVFrame *dst, const AVFrame *src)
Copy the frame data from src to dst.
Definition: frame.c:719
int initial_pool_size
Initial size of the frame pool.
Definition: hwcontext.h:192
AVDictionary * opts
Definition: movenc.c:50
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)
#define src
Definition: vp9dsp.c:530
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:217
static int vaapi_transfer_data_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src)
#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:248
int min_width
The minimum size of frames in this hw_frames_ctx.
Definition: hwcontext.h:384
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition: hwcontext.h:366
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:215
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
GLint GLenum type
Definition: opengl_enc.c:105
#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:371
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
static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
static int flags
Definition: cpu.c:47
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:198
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:328
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
#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:378
VAAPI connection details.
VAConfigID config_id
ID of a VAAPI pipeline configuration.
int height
Definition: frame.h:236
const HWContextType ff_hwcontext_type_vaapi
#define av_freep(p)
VASurfaceID * surface_ids
The surfaces IDs of all surfaces in the pool after creation.
static struct @237 vaapi_format_map[]
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:380
#define av_malloc_array(a, b)
#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:2182
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