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