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