2 * This file is part of FFmpeg.
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.
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.
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
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.
74 VAAPI_MAP_READ = 0x01,
75 VAAPI_MAP_WRITE = 0x02,
76 VAAPI_MAP_DIRECT = 0x04,
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.
84 // Handle to the derived or copied image which is mapped.
88 #define MAP(va, rt, av) { \
90 VA_RT_FORMAT_ ## rt, \
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.
97 unsigned int rt_format;
98 enum AVPixelFormat pix_fmt;
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.
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),
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),
125 static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
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;
134 static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
135 enum AVPixelFormat pix_fmt,
136 VAImageFormat **image_format)
138 VAAPIDeviceContext *ctx = hwdev->internal->priv;
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;
147 return AVERROR(EINVAL);
150 static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
151 const void *hwconfig,
152 AVHWFramesConstraints *constraints)
154 AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
155 const AVVAAPIHWConfig *config = hwconfig;
156 AVVAAPIHWConfig *tmp_config;
157 VASurfaceAttrib *attr_list = NULL;
159 enum AVPixelFormat pix_fmt;
161 int err, i, j, attr_count, pix_fmt_count;
164 // No configuration was provided, so we create a temporary pipeline
165 // configuration in order to query all supported image formats.
167 tmp_config = av_mallocz(sizeof(*config));
169 return AVERROR(ENOMEM);
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);
192 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
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);
201 attr_list = av_malloc(attr_count * sizeof(*attr_list));
203 err = AVERROR(ENOMEM);
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);
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) {
225 // Something unsupported - ignore.
228 case VASurfaceAttribMinWidth:
229 constraints->min_width = attr_list[i].value.value.i;
231 case VASurfaceAttribMinHeight:
232 constraints->min_height = attr_list[i].value.value.i;
234 case VASurfaceAttribMaxWidth:
235 constraints->max_width = attr_list[i].value.value.i;
237 case VASurfaceAttribMaxHeight:
238 constraints->max_height = attr_list[i].value.value.i;
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;
247 constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
249 if (!constraints->valid_sw_formats) {
250 err = AVERROR(ENOMEM);
254 for (i = j = 0; i < attr_count; i++) {
255 if (attr_list[i].type != VASurfaceAttribPixelFormat)
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;
262 av_assert0(j == pix_fmt_count);
263 constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
266 constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
267 if (!constraints->valid_hw_formats) {
268 err = AVERROR(ENOMEM);
271 constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
272 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
276 av_freep(&attr_list);
278 vaDestroyConfig(hwctx->display, tmp_config->config_id);
279 av_freep(&tmp_config);
284 static int vaapi_device_init(AVHWDeviceContext *hwdev)
286 VAAPIDeviceContext *ctx = hwdev->internal->priv;
287 AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
288 AVHWFramesConstraints *constraints = NULL;
289 VAImageFormat *image_list = NULL;
291 int err, i, j, image_count;
292 enum AVPixelFormat pix_fmt;
295 constraints = av_mallocz(sizeof(*constraints));
299 err = vaapi_frames_get_constraints(hwdev, NULL, constraints);
303 image_count = vaMaxNumImageFormats(hwctx->display);
304 if (image_count <= 0) {
308 image_list = av_malloc(image_count * sizeof(*image_list));
310 err = AVERROR(ENOMEM);
313 vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
314 if (vas != VA_STATUS_SUCCESS) {
319 ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
321 err = AVERROR(ENOMEM);
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])
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];
339 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n", fourcc);
344 av_hwframe_constraints_free(&constraints);
347 av_freep(&ctx->formats);
349 av_hwframe_constraints_free(&constraints);
353 static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
355 VAAPIDeviceContext *ctx = hwdev->internal->priv;
357 av_freep(&ctx->formats);
360 static void vaapi_buffer_free(void *opaque, uint8_t *data)
362 AVHWFramesContext *hwfc = opaque;
363 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
364 VASurfaceID surface_id;
367 surface_id = (VASurfaceID)(uintptr_t)data;
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));
376 static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
378 AVHWFramesContext *hwfc = opaque;
379 VAAPIFramesContext *ctx = hwfc->internal->priv;
380 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
381 AVVAAPIFramesContext *avfc = hwfc->hwctx;
382 VASurfaceID surface_id;
386 vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
387 hwfc->width, hwfc->height,
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));
395 av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
397 ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
398 sizeof(surface_id), &vaapi_buffer_free,
399 hwfc, AV_BUFFER_FLAG_READONLY);
401 vaDestroySurfaces(hwctx->display, &surface_id, 1);
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.
408 av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
409 avfc->surface_ids[avfc->nb_surfaces] = surface_id;
416 static int vaapi_frames_init(AVHWFramesContext *hwfc)
418 AVVAAPIFramesContext *avfc = hwfc->hwctx;
419 VAAPIFramesContext *ctx = hwfc->internal->priv;
420 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
421 VAImageFormat *expected_format;
422 AVBufferRef *test_surface = NULL;
423 VASurfaceID test_surface_id;
427 unsigned int fourcc, rt_format;
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;
436 if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
437 av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
438 av_get_pix_fmt_name(hwfc->sw_format));
439 return AVERROR(EINVAL);
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;
451 avfc->nb_attributes + need_memory_type + need_pixel_format;
453 ctx->attributes = av_malloc(ctx->nb_attributes *
454 sizeof(*ctx->attributes));
455 if (!ctx->attributes) {
456 err = AVERROR(ENOMEM);
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,
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,
478 av_assert0(i == ctx->nb_attributes);
480 ctx->rt_format = rt_format;
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);
494 // This pool allows dynamic sizing, and will not be usable as a
496 avfc->nb_surfaces = 0;
497 avfc->surface_ids = NULL;
500 hwfc->internal->pool_internal =
501 av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
502 &vaapi_pool_alloc, NULL);
503 if (!hwfc->internal->pool_internal) {
504 av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
505 err = AVERROR(ENOMEM);
510 // Allocate a single surface to test whether vaDeriveImage() is going
511 // to work for the specific configuration.
513 test_surface = av_buffer_pool_get(hwfc->pool);
515 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
516 "user-configured buffer pool.\n");
517 err = AVERROR(ENOMEM);
521 test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
523 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
524 "internal buffer pool.\n");
525 err = AVERROR(ENOMEM);
529 test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
531 ctx->derive_works = 0;
533 err = vaapi_get_image_format(hwfc->device_ctx,
534 hwfc->sw_format, &expected_format);
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;
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);
547 vaDestroyImage(hwctx->display, test_image.image_id);
549 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
550 "deriving image does not work: "
551 "%d (%s).\n", vas, vaErrorStr(vas));
554 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
555 "image format is not supported.\n");
558 av_buffer_unref(&test_surface);
562 av_buffer_unref(&test_surface);
563 av_freep(&avfc->surface_ids);
564 av_freep(&ctx->attributes);
568 static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
570 AVVAAPIFramesContext *avfc = hwfc->hwctx;
571 VAAPIFramesContext *ctx = hwfc->internal->priv;
573 av_freep(&avfc->surface_ids);
574 av_freep(&ctx->attributes);
577 static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
579 frame->buf[0] = av_buffer_pool_get(hwfc->pool);
581 return AVERROR(ENOMEM);
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;
591 static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
592 enum AVHWFrameTransferDirection dir,
593 enum AVPixelFormat **formats)
595 VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
596 enum AVPixelFormat *pix_fmts, preferred_format;
599 preferred_format = hwfc->sw_format;
601 pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
603 return AVERROR(ENOMEM);
605 pix_fmts[0] = preferred_format;
607 for (i = 0; i < ctx->nb_formats; i++) {
608 if (ctx->formats[i].pix_fmt == preferred_format)
610 av_assert0(k < ctx->nb_formats);
611 pix_fmts[k++] = ctx->formats[i].pix_fmt;
613 av_assert0(k == ctx->nb_formats);
614 pix_fmts[k] = AV_PIX_FMT_NONE;
620 static void vaapi_unmap_frame(void *opaque, uint8_t *data)
622 AVHWFramesContext *hwfc = opaque;
623 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
624 VAAPISurfaceMap *map = (VAAPISurfaceMap*)data;
626 VASurfaceID surface_id;
630 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
631 av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
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));
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));
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));
659 static int vaapi_map_frame(AVHWFramesContext *hwfc,
660 AVFrame *dst, const AVFrame *src, int flags)
662 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
663 VAAPIFramesContext *ctx = hwfc->internal->priv;
664 VASurfaceID surface_id;
665 VAImageFormat *image_format;
666 VAAPISurfaceMap *map;
668 void *address = NULL;
671 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
672 av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
674 if (!ctx->derive_works && (flags & VAAPI_MAP_DIRECT)) {
675 // Requested direct mapping but it is not possible.
676 return AVERROR(EINVAL);
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);
685 err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
687 // Requested format is not a valid output format.
688 return AVERROR(EINVAL);
691 map = av_malloc(sizeof(VAAPISurfaceMap));
693 return AVERROR(ENOMEM);
697 map->image.image_id = VA_INVALID_ID;
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));
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));
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);
731 map->flags |= VAAPI_MAP_DIRECT;
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));
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));
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));
763 dst->width = src->width;
764 dst->height = src->height;
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];
771 #ifdef VA_FOURCC_YV16
772 map->image.format.fourcc == VA_FOURCC_YV16 ||
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]);
779 dst->buf[0] = av_buffer_create((uint8_t*)map, sizeof(*map),
780 &vaapi_unmap_frame, hwfc, 0);
782 err = AVERROR(ENOMEM);
791 vaUnmapBuffer(hwctx->display, map->image.buf);
792 if (map->image.image_id != VA_INVALID_ID)
793 vaDestroyImage(hwctx->display, map->image.image_id);
799 static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
800 AVFrame *dst, const AVFrame *src)
805 map = av_frame_alloc();
807 return AVERROR(ENOMEM);
808 map->format = dst->format;
810 err = vaapi_map_frame(hwfc, map, src, VAAPI_MAP_READ);
814 err = av_frame_copy(dst, map);
824 static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
825 AVFrame *dst, const AVFrame *src)
830 map = av_frame_alloc();
832 return AVERROR(ENOMEM);
833 map->format = src->format;
835 err = vaapi_map_frame(hwfc, map, dst, VAAPI_MAP_WRITE);
839 err = av_frame_copy(map, src);
849 static void vaapi_device_free(AVHWDeviceContext *ctx)
851 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
852 VAAPIDevicePriv *priv = ctx->user_opaque;
855 vaTerminate(hwctx->display);
858 if (priv->x11_display)
859 XCloseDisplay(priv->x11_display);
862 if (priv->drm_fd >= 0)
868 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
869 AVDictionary *opts, int flags)
871 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
872 VAAPIDevicePriv *priv;
873 VADisplay display = 0;
877 priv = av_mallocz(sizeof(*priv));
879 return AVERROR(ENOMEM);
883 ctx->user_opaque = priv;
884 ctx->free = vaapi_device_free;
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));
894 display = vaGetDisplay(priv->x11_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;
901 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
902 "X11 display %s.\n", XDisplayName(device));
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",
915 display = vaGetDisplayDRM(priv->drm_fd);
917 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
918 "from DRM device %s.\n", device);
919 return AVERROR_UNKNOWN;
922 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
923 "DRM device %s.\n", device);
929 av_log(ctx, AV_LOG_ERROR, "No VA display found for "
930 "device: %s.\n", device ? device : "");
931 return AVERROR(EINVAL);
934 hwctx->display = display;
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));
942 av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
943 "version %d.%d\n", major, minor);
948 const HWContextType ff_hwcontext_type_vaapi = {
949 .type = AV_HWDEVICE_TYPE_VAAPI,
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),
958 .device_create = &vaapi_device_create,
959 .device_init = &vaapi_device_init,
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,
969 .pix_fmts = (const enum AVPixelFormat[]) {