2 * This file is part of Libav.
4 * Libav is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * Libav is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with Libav; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 # include <va/va_x11.h>
25 # include <va/va_drm.h>
37 #include "hwcontext.h"
38 #include "hwcontext_internal.h"
39 #include "hwcontext_vaapi.h"
44 typedef struct VAAPIDevicePriv {
52 typedef struct VAAPISurfaceFormat {
53 enum AVPixelFormat pix_fmt;
54 VAImageFormat image_format;
57 typedef struct VAAPIDeviceContext {
58 // Surface formats which can be used with this device.
59 VAAPISurfaceFormat *formats;
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.
73 typedef struct VAAPIMapping {
74 // Handle to the derived or copied image which is mapped.
76 // The mapping flags actually used.
80 #define MAP(va, rt, av) { \
82 VA_RT_FORMAT_ ## rt, \
85 // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
86 // plane swap cases. The frame handling below tries to hide these.
89 unsigned int rt_format;
90 enum AVPixelFormat pix_fmt;
91 } vaapi_format_map[] = {
92 MAP(NV12, YUV420, NV12),
93 MAP(YV12, YUV420, YUV420P), // With U/V planes swapped.
94 MAP(IYUV, YUV420, YUV420P),
95 //MAP(I420, YUV420, YUV420P), // Not in libva but used by Intel driver.
97 MAP(YV16, YUV422, YUV422P), // With U/V planes swapped.
99 MAP(422H, YUV422, YUV422P),
100 MAP(UYVY, YUV422, UYVY422),
101 MAP(YUY2, YUV422, YUYV422),
102 MAP(Y800, YUV400, GRAY8),
103 #ifdef VA_FOURCC_P010
104 MAP(P010, YUV420_10BPP, P010),
106 MAP(BGRA, RGB32, BGRA),
107 //MAP(BGRX, RGB32, BGR0),
108 MAP(RGBA, RGB32, RGBA),
109 //MAP(RGBX, RGB32, RGB0),
110 MAP(ABGR, RGB32, ABGR),
111 //MAP(XBGR, RGB32, 0BGR),
112 MAP(ARGB, RGB32, ARGB),
113 //MAP(XRGB, RGB32, 0RGB),
117 static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
120 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
121 if (vaapi_format_map[i].fourcc == fourcc)
122 return vaapi_format_map[i].pix_fmt;
123 return AV_PIX_FMT_NONE;
126 static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
127 enum AVPixelFormat pix_fmt,
128 VAImageFormat **image_format)
130 VAAPIDeviceContext *ctx = hwdev->internal->priv;
133 for (i = 0; i < ctx->nb_formats; i++) {
134 if (ctx->formats[i].pix_fmt == pix_fmt) {
136 *image_format = &ctx->formats[i].image_format;
140 return AVERROR(EINVAL);
143 static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
144 const void *hwconfig,
145 AVHWFramesConstraints *constraints)
147 AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
148 const AVVAAPIHWConfig *config = hwconfig;
149 VAAPIDeviceContext *ctx = hwdev->internal->priv;
150 VASurfaceAttrib *attr_list = NULL;
152 enum AVPixelFormat pix_fmt;
154 int err, i, j, attr_count, pix_fmt_count;
158 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
160 if (vas != VA_STATUS_SUCCESS) {
161 av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
162 "%d (%s).\n", vas, vaErrorStr(vas));
163 err = AVERROR(ENOSYS);
167 attr_list = av_malloc(attr_count * sizeof(*attr_list));
169 err = AVERROR(ENOMEM);
173 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
174 attr_list, &attr_count);
175 if (vas != VA_STATUS_SUCCESS) {
176 av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
177 "%d (%s).\n", vas, vaErrorStr(vas));
178 err = AVERROR(ENOSYS);
183 for (i = 0; i < attr_count; i++) {
184 switch (attr_list[i].type) {
185 case VASurfaceAttribPixelFormat:
186 fourcc = attr_list[i].value.value.i;
187 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
188 if (pix_fmt != AV_PIX_FMT_NONE) {
191 // Something unsupported - ignore.
194 case VASurfaceAttribMinWidth:
195 constraints->min_width = attr_list[i].value.value.i;
197 case VASurfaceAttribMinHeight:
198 constraints->min_height = attr_list[i].value.value.i;
200 case VASurfaceAttribMaxWidth:
201 constraints->max_width = attr_list[i].value.value.i;
203 case VASurfaceAttribMaxHeight:
204 constraints->max_height = attr_list[i].value.value.i;
208 if (pix_fmt_count == 0) {
209 // Nothing usable found. Presumably there exists something which
210 // works, so leave the set null to indicate unknown.
211 constraints->valid_sw_formats = NULL;
213 constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
215 if (!constraints->valid_sw_formats) {
216 err = AVERROR(ENOMEM);
220 for (i = j = 0; i < attr_count; i++) {
221 if (attr_list[i].type != VASurfaceAttribPixelFormat)
223 fourcc = attr_list[i].value.value.i;
224 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
225 if (pix_fmt != AV_PIX_FMT_NONE)
226 constraints->valid_sw_formats[j++] = pix_fmt;
228 av_assert0(j == pix_fmt_count);
229 constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
232 // No configuration supplied.
233 // Return the full set of image formats known by the implementation.
234 constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
236 if (!constraints->valid_sw_formats) {
237 err = AVERROR(ENOMEM);
240 for (i = 0; i < ctx->nb_formats; i++)
241 constraints->valid_sw_formats[i] = ctx->formats[i].pix_fmt;
242 constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE;
245 constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
246 if (!constraints->valid_hw_formats) {
247 err = AVERROR(ENOMEM);
250 constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
251 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
255 av_freep(&attr_list);
259 static const struct {
260 const char *friendly_name;
261 const char *match_string;
263 } vaapi_driver_quirks_table[] = {
265 "Intel i965 (Quick Sync)",
267 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS,
272 AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE,
276 static int vaapi_device_init(AVHWDeviceContext *hwdev)
278 VAAPIDeviceContext *ctx = hwdev->internal->priv;
279 AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
280 VAImageFormat *image_list = NULL;
282 const char *vendor_string;
283 int err, i, image_count;
284 enum AVPixelFormat pix_fmt;
287 image_count = vaMaxNumImageFormats(hwctx->display);
288 if (image_count <= 0) {
292 image_list = av_malloc(image_count * sizeof(*image_list));
294 err = AVERROR(ENOMEM);
297 vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
298 if (vas != VA_STATUS_SUCCESS) {
303 ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
305 err = AVERROR(ENOMEM);
309 for (i = 0; i < image_count; i++) {
310 fourcc = image_list[i].fourcc;
311 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
312 if (pix_fmt == AV_PIX_FMT_NONE) {
313 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
316 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
317 fourcc, av_get_pix_fmt_name(pix_fmt));
318 ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
319 ctx->formats[ctx->nb_formats].image_format = image_list[i];
324 if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) {
325 av_log(hwdev, AV_LOG_VERBOSE, "Not detecting driver: "
326 "quirks set by user.\n");
328 // Detect the driver in use and set quirk flags if necessary.
329 vendor_string = vaQueryVendorString(hwctx->display);
330 hwctx->driver_quirks = 0;
332 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
333 if (strstr(vendor_string,
334 vaapi_driver_quirks_table[i].match_string)) {
335 av_log(hwdev, AV_LOG_VERBOSE, "Matched \"%s\" as known "
336 "driver \"%s\".\n", vendor_string,
337 vaapi_driver_quirks_table[i].friendly_name);
338 hwctx->driver_quirks |=
339 vaapi_driver_quirks_table[i].quirks;
343 if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) {
344 av_log(hwdev, AV_LOG_VERBOSE, "Unknown driver \"%s\", "
345 "assuming standard behaviour.\n", vendor_string);
353 av_freep(&ctx->formats);
358 static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
360 VAAPIDeviceContext *ctx = hwdev->internal->priv;
362 av_freep(&ctx->formats);
365 static void vaapi_buffer_free(void *opaque, uint8_t *data)
367 AVHWFramesContext *hwfc = opaque;
368 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
369 VASurfaceID surface_id;
372 surface_id = (VASurfaceID)(uintptr_t)data;
374 vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
375 if (vas != VA_STATUS_SUCCESS) {
376 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
377 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
381 static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
383 AVHWFramesContext *hwfc = opaque;
384 VAAPIFramesContext *ctx = hwfc->internal->priv;
385 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
386 AVVAAPIFramesContext *avfc = hwfc->hwctx;
387 VASurfaceID surface_id;
391 if (hwfc->initial_pool_size > 0 &&
392 avfc->nb_surfaces >= hwfc->initial_pool_size)
395 vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
396 hwfc->width, hwfc->height,
398 ctx->attributes, ctx->nb_attributes);
399 if (vas != VA_STATUS_SUCCESS) {
400 av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
401 "%d (%s).\n", vas, vaErrorStr(vas));
404 av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
406 ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
407 sizeof(surface_id), &vaapi_buffer_free,
408 hwfc, AV_BUFFER_FLAG_READONLY);
410 vaDestroySurfaces(hwctx->display, &surface_id, 1);
414 if (hwfc->initial_pool_size > 0) {
415 // This is a fixed-size pool, so we must still be in the initial
416 // allocation sequence.
417 av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
418 avfc->surface_ids[avfc->nb_surfaces] = surface_id;
425 static int vaapi_frames_init(AVHWFramesContext *hwfc)
427 AVVAAPIFramesContext *avfc = hwfc->hwctx;
428 VAAPIFramesContext *ctx = hwfc->internal->priv;
429 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
430 VAImageFormat *expected_format;
431 AVBufferRef *test_surface = NULL;
432 VASurfaceID test_surface_id;
436 unsigned int fourcc, rt_format;
438 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
439 if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) {
440 fourcc = vaapi_format_map[i].fourcc;
441 rt_format = vaapi_format_map[i].rt_format;
445 if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
446 av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
447 av_get_pix_fmt_name(hwfc->sw_format));
448 return AVERROR(EINVAL);
452 int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
453 int need_pixel_format = 1;
454 for (i = 0; i < avfc->nb_attributes; i++) {
455 if (ctx->attributes[i].type == VASurfaceAttribMemoryType)
456 need_memory_type = 0;
457 if (ctx->attributes[i].type == VASurfaceAttribPixelFormat)
458 need_pixel_format = 0;
461 avfc->nb_attributes + need_memory_type + need_pixel_format;
463 ctx->attributes = av_malloc(ctx->nb_attributes *
464 sizeof(*ctx->attributes));
465 if (!ctx->attributes) {
466 err = AVERROR(ENOMEM);
470 for (i = 0; i < avfc->nb_attributes; i++)
471 ctx->attributes[i] = avfc->attributes[i];
472 if (need_memory_type) {
473 ctx->attributes[i++] = (VASurfaceAttrib) {
474 .type = VASurfaceAttribMemoryType,
475 .flags = VA_SURFACE_ATTRIB_SETTABLE,
476 .value.type = VAGenericValueTypeInteger,
477 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
480 if (need_pixel_format) {
481 ctx->attributes[i++] = (VASurfaceAttrib) {
482 .type = VASurfaceAttribPixelFormat,
483 .flags = VA_SURFACE_ATTRIB_SETTABLE,
484 .value.type = VAGenericValueTypeInteger,
485 .value.value.i = fourcc,
488 av_assert0(i == ctx->nb_attributes);
490 ctx->rt_format = rt_format;
492 if (hwfc->initial_pool_size > 0) {
493 // This pool will be usable as a render target, so we need to store
494 // all of the surface IDs somewhere that vaCreateContext() calls
495 // will be able to access them.
496 avfc->nb_surfaces = 0;
497 avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
498 sizeof(*avfc->surface_ids));
499 if (!avfc->surface_ids) {
500 err = AVERROR(ENOMEM);
504 // This pool allows dynamic sizing, and will not be usable as a
506 avfc->nb_surfaces = 0;
507 avfc->surface_ids = NULL;
510 hwfc->internal->pool_internal =
511 av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
512 &vaapi_pool_alloc, NULL);
513 if (!hwfc->internal->pool_internal) {
514 av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
515 err = AVERROR(ENOMEM);
520 // Allocate a single surface to test whether vaDeriveImage() is going
521 // to work for the specific configuration.
523 test_surface = av_buffer_pool_get(hwfc->pool);
525 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
526 "user-configured buffer pool.\n");
527 err = AVERROR(ENOMEM);
531 test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
533 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
534 "internal buffer pool.\n");
535 err = AVERROR(ENOMEM);
539 test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
541 ctx->derive_works = 0;
543 err = vaapi_get_image_format(hwfc->device_ctx,
544 hwfc->sw_format, &expected_format);
546 vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
547 if (vas == VA_STATUS_SUCCESS) {
548 if (expected_format->fourcc == test_image.format.fourcc) {
549 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
550 ctx->derive_works = 1;
552 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
553 "derived image format %08x does not match "
554 "expected format %08x.\n",
555 expected_format->fourcc, test_image.format.fourcc);
557 vaDestroyImage(hwctx->display, test_image.image_id);
559 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
560 "deriving image does not work: "
561 "%d (%s).\n", vas, vaErrorStr(vas));
564 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
565 "image format is not supported.\n");
568 av_buffer_unref(&test_surface);
572 av_buffer_unref(&test_surface);
573 av_freep(&avfc->surface_ids);
574 av_freep(&ctx->attributes);
578 static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
580 AVVAAPIFramesContext *avfc = hwfc->hwctx;
581 VAAPIFramesContext *ctx = hwfc->internal->priv;
583 av_freep(&avfc->surface_ids);
584 av_freep(&ctx->attributes);
587 static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
589 frame->buf[0] = av_buffer_pool_get(hwfc->pool);
591 return AVERROR(ENOMEM);
593 frame->data[3] = frame->buf[0]->data;
594 frame->format = AV_PIX_FMT_VAAPI;
595 frame->width = hwfc->width;
596 frame->height = hwfc->height;
601 static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
602 enum AVHWFrameTransferDirection dir,
603 enum AVPixelFormat **formats)
605 VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
606 enum AVPixelFormat *pix_fmts, preferred_format;
609 preferred_format = hwfc->sw_format;
611 pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
613 return AVERROR(ENOMEM);
615 pix_fmts[0] = preferred_format;
617 for (i = 0; i < ctx->nb_formats; i++) {
618 if (ctx->formats[i].pix_fmt == preferred_format)
620 av_assert0(k < ctx->nb_formats);
621 pix_fmts[k++] = ctx->formats[i].pix_fmt;
623 av_assert0(k == ctx->nb_formats);
624 pix_fmts[k] = AV_PIX_FMT_NONE;
630 static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
631 HWMapDescriptor *hwmap)
633 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
634 VAAPIMapping *map = hwmap->priv;
635 VASurfaceID surface_id;
638 surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
639 av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
641 vas = vaUnmapBuffer(hwctx->display, map->image.buf);
642 if (vas != VA_STATUS_SUCCESS) {
643 av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
644 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
647 if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
648 !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
649 vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
650 0, 0, hwfc->width, hwfc->height,
651 0, 0, hwfc->width, hwfc->height);
652 if (vas != VA_STATUS_SUCCESS) {
653 av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
654 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
658 vas = vaDestroyImage(hwctx->display, map->image.image_id);
659 if (vas != VA_STATUS_SUCCESS) {
660 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
661 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
667 static int vaapi_map_frame(AVHWFramesContext *hwfc,
668 AVFrame *dst, const AVFrame *src, int flags)
670 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
671 VAAPIFramesContext *ctx = hwfc->internal->priv;
672 VASurfaceID surface_id;
673 VAImageFormat *image_format;
676 void *address = NULL;
679 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
680 av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
682 if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
683 // Requested direct mapping but it is not possible.
684 return AVERROR(EINVAL);
686 if (dst->format == AV_PIX_FMT_NONE)
687 dst->format = hwfc->sw_format;
688 if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
689 // Requested direct mapping but the formats do not match.
690 return AVERROR(EINVAL);
693 err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
695 // Requested format is not a valid output format.
696 return AVERROR(EINVAL);
699 map = av_malloc(sizeof(*map));
701 return AVERROR(ENOMEM);
703 map->image.image_id = VA_INVALID_ID;
705 vas = vaSyncSurface(hwctx->display, surface_id);
706 if (vas != VA_STATUS_SUCCESS) {
707 av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
708 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
713 // The memory which we map using derive need not be connected to the CPU
714 // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
715 // memory is mappable but not cached, so normal memcpy()-like access is
716 // very slow to read it (but writing is ok). It is possible to read much
717 // faster with a copy routine which is aware of the limitation, but we
718 // assume for now that the user is not aware of that and would therefore
719 // prefer not to be given direct-mapped memory if they request read access.
720 if (ctx->derive_works && dst->format == hwfc->sw_format &&
721 ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
722 vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
723 if (vas != VA_STATUS_SUCCESS) {
724 av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
725 "surface %#x: %d (%s).\n",
726 surface_id, vas, vaErrorStr(vas));
730 if (map->image.format.fourcc != image_format->fourcc) {
731 av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
732 "is in wrong format: expected %#08x, got %#08x.\n",
733 surface_id, image_format->fourcc, map->image.format.fourcc);
737 map->flags |= AV_HWFRAME_MAP_DIRECT;
739 vas = vaCreateImage(hwctx->display, image_format,
740 hwfc->width, hwfc->height, &map->image);
741 if (vas != VA_STATUS_SUCCESS) {
742 av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
743 "surface %#x: %d (%s).\n",
744 surface_id, vas, vaErrorStr(vas));
748 if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
749 vas = vaGetImage(hwctx->display, surface_id, 0, 0,
750 hwfc->width, hwfc->height, map->image.image_id);
751 if (vas != VA_STATUS_SUCCESS) {
752 av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
753 "surface %#x: %d (%s).\n",
754 surface_id, vas, vaErrorStr(vas));
761 vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
762 if (vas != VA_STATUS_SUCCESS) {
763 av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
764 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
769 err = ff_hwframe_map_create(src->hw_frames_ctx,
770 dst, src, &vaapi_unmap_frame, map);
774 dst->width = src->width;
775 dst->height = src->height;
777 for (i = 0; i < map->image.num_planes; i++) {
778 dst->data[i] = (uint8_t*)address + map->image.offsets[i];
779 dst->linesize[i] = map->image.pitches[i];
782 #ifdef VA_FOURCC_YV16
783 map->image.format.fourcc == VA_FOURCC_YV16 ||
785 map->image.format.fourcc == VA_FOURCC_YV12) {
786 // Chroma planes are YVU rather than YUV, so swap them.
787 FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
795 vaUnmapBuffer(hwctx->display, map->image.buf);
796 if (map->image.image_id != VA_INVALID_ID)
797 vaDestroyImage(hwctx->display, map->image.image_id);
803 static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
804 AVFrame *dst, const AVFrame *src)
809 if (dst->width > hwfc->width || dst->height > hwfc->height)
810 return AVERROR(EINVAL);
812 map = av_frame_alloc();
814 return AVERROR(ENOMEM);
815 map->format = dst->format;
817 err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
821 map->width = dst->width;
822 map->height = dst->height;
824 err = av_frame_copy(dst, map);
834 static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
835 AVFrame *dst, const AVFrame *src)
840 if (src->width > hwfc->width || src->height > hwfc->height)
841 return AVERROR(EINVAL);
843 map = av_frame_alloc();
845 return AVERROR(ENOMEM);
846 map->format = src->format;
848 err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
852 map->width = src->width;
853 map->height = src->height;
855 err = av_frame_copy(map, src);
865 static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
866 const AVFrame *src, int flags)
870 if (dst->format != AV_PIX_FMT_NONE) {
871 err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
873 return AVERROR(ENOSYS);
876 err = vaapi_map_frame(hwfc, dst, src, flags);
880 err = av_frame_copy_props(dst, src);
887 static void vaapi_device_free(AVHWDeviceContext *ctx)
889 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
890 VAAPIDevicePriv *priv = ctx->user_opaque;
893 vaTerminate(hwctx->display);
896 if (priv->x11_display)
897 XCloseDisplay(priv->x11_display);
900 if (priv->drm_fd >= 0)
906 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
907 AVDictionary *opts, int flags)
909 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
910 VAAPIDevicePriv *priv;
911 VADisplay display = 0;
915 priv = av_mallocz(sizeof(*priv));
917 return AVERROR(ENOMEM);
921 ctx->user_opaque = priv;
922 ctx->free = vaapi_device_free;
925 if (!display && !(device && device[0] == '/')) {
926 // Try to open the device as an X11 display.
927 priv->x11_display = XOpenDisplay(device);
928 if (!priv->x11_display) {
929 av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
930 "%s.\n", XDisplayName(device));
932 display = vaGetDisplay(priv->x11_display);
934 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
935 "from X11 display %s.\n", XDisplayName(device));
936 return AVERROR_UNKNOWN;
939 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
940 "X11 display %s.\n", XDisplayName(device));
947 // Try to open the device as a DRM path.
948 // Default to using the first render node if the user did not
950 const char *path = device ? device : "/dev/dri/renderD128";
951 priv->drm_fd = open(path, O_RDWR);
952 if (priv->drm_fd < 0) {
953 av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
956 display = vaGetDisplayDRM(priv->drm_fd);
958 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
959 "from DRM device %s.\n", path);
960 return AVERROR_UNKNOWN;
963 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
964 "DRM device %s.\n", path);
970 av_log(ctx, AV_LOG_ERROR, "No VA display found for "
971 "device: %s.\n", device ? device : "");
972 return AVERROR(EINVAL);
975 hwctx->display = display;
977 vas = vaInitialize(display, &major, &minor);
978 if (vas != VA_STATUS_SUCCESS) {
979 av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
980 "connection: %d (%s).\n", vas, vaErrorStr(vas));
983 av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
984 "version %d.%d\n", major, minor);
989 const HWContextType ff_hwcontext_type_vaapi = {
990 .type = AV_HWDEVICE_TYPE_VAAPI,
993 .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
994 .device_priv_size = sizeof(VAAPIDeviceContext),
995 .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
996 .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
997 .frames_priv_size = sizeof(VAAPIFramesContext),
999 .device_create = &vaapi_device_create,
1000 .device_init = &vaapi_device_init,
1001 .device_uninit = &vaapi_device_uninit,
1002 .frames_get_constraints = &vaapi_frames_get_constraints,
1003 .frames_init = &vaapi_frames_init,
1004 .frames_uninit = &vaapi_frames_uninit,
1005 .frames_get_buffer = &vaapi_get_buffer,
1006 .transfer_get_formats = &vaapi_transfer_get_formats,
1007 .transfer_data_to = &vaapi_transfer_data_to,
1008 .transfer_data_from = &vaapi_transfer_data_from,
1010 .map_from = &vaapi_map_from,
1012 .pix_fmts = (const enum AVPixelFormat[]) {