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 #ifdef VA_FOURCC_ABGR
119 MAP(ABGR, RGB32, ABGR),
120 MAP(XBGR, RGB32, 0BGR),
122 MAP(ARGB, RGB32, ARGB),
123 MAP(XRGB, RGB32, 0RGB),
127 static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
130 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
131 if (vaapi_format_map[i].fourcc == fourcc)
132 return vaapi_format_map[i].pix_fmt;
133 return AV_PIX_FMT_NONE;
136 static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
137 enum AVPixelFormat pix_fmt,
138 VAImageFormat **image_format)
140 VAAPIDeviceContext *ctx = hwdev->internal->priv;
143 for (i = 0; i < ctx->nb_formats; i++) {
144 if (ctx->formats[i].pix_fmt == pix_fmt) {
145 *image_format = &ctx->formats[i].image_format;
149 return AVERROR(EINVAL);
152 static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
153 const void *hwconfig,
154 AVHWFramesConstraints *constraints)
156 AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
157 const AVVAAPIHWConfig *config = hwconfig;
158 AVVAAPIHWConfig *tmp_config;
159 VASurfaceAttrib *attr_list = NULL;
161 enum AVPixelFormat pix_fmt;
163 int err, i, j, attr_count, pix_fmt_count;
166 // No configuration was provided, so we create a temporary pipeline
167 // configuration in order to query all supported image formats.
169 tmp_config = av_mallocz(sizeof(*config));
171 return AVERROR(ENOMEM);
173 vas = vaCreateConfig(hwctx->display,
174 VAProfileNone, VAEntrypointVideoProc,
175 NULL, 0, &tmp_config->config_id);
176 if (vas != VA_STATUS_SUCCESS) {
177 // No vpp. We might still be able to do something useful if
178 // codecs are supported, so try to make the most-commonly
179 // supported decoder configuration we can to query instead.
180 vas = vaCreateConfig(hwctx->display,
181 VAProfileH264ConstrainedBaseline,
182 VAEntrypointVLD, NULL, 0,
183 &tmp_config->config_id);
184 if (vas != VA_STATUS_SUCCESS) {
185 av_freep(&tmp_config);
186 return AVERROR(ENOSYS);
194 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
196 if (vas != VA_STATUS_SUCCESS) {
197 av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
198 "%d (%s).\n", vas, vaErrorStr(vas));
199 err = AVERROR(ENOSYS);
203 attr_list = av_malloc(attr_count * sizeof(*attr_list));
205 err = AVERROR(ENOMEM);
209 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
210 attr_list, &attr_count);
211 if (vas != VA_STATUS_SUCCESS) {
212 av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
213 "%d (%s).\n", vas, vaErrorStr(vas));
214 err = AVERROR(ENOSYS);
219 for (i = 0; i < attr_count; i++) {
220 switch (attr_list[i].type) {
221 case VASurfaceAttribPixelFormat:
222 fourcc = attr_list[i].value.value.i;
223 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
224 if (pix_fmt != AV_PIX_FMT_NONE) {
227 // Something unsupported - ignore.
230 case VASurfaceAttribMinWidth:
231 constraints->min_width = attr_list[i].value.value.i;
233 case VASurfaceAttribMinHeight:
234 constraints->min_height = attr_list[i].value.value.i;
236 case VASurfaceAttribMaxWidth:
237 constraints->max_width = attr_list[i].value.value.i;
239 case VASurfaceAttribMaxHeight:
240 constraints->max_height = attr_list[i].value.value.i;
244 if (pix_fmt_count == 0) {
245 // Nothing usable found. Presumably there exists something which
246 // works, so leave the set null to indicate unknown.
247 constraints->valid_sw_formats = NULL;
249 constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
251 if (!constraints->valid_sw_formats) {
252 err = AVERROR(ENOMEM);
256 for (i = j = 0; i < attr_count; i++) {
257 if (attr_list[i].type != VASurfaceAttribPixelFormat)
259 fourcc = attr_list[i].value.value.i;
260 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
261 if (pix_fmt != AV_PIX_FMT_NONE)
262 constraints->valid_sw_formats[j++] = pix_fmt;
264 av_assert0(j == pix_fmt_count);
265 constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
268 constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
269 if (!constraints->valid_hw_formats) {
270 err = AVERROR(ENOMEM);
273 constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
274 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
278 av_freep(&attr_list);
280 vaDestroyConfig(hwctx->display, tmp_config->config_id);
281 av_freep(&tmp_config);
286 static int vaapi_device_init(AVHWDeviceContext *hwdev)
288 VAAPIDeviceContext *ctx = hwdev->internal->priv;
289 AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
290 AVHWFramesConstraints *constraints = NULL;
291 VAImageFormat *image_list = NULL;
293 int err, i, j, image_count;
294 enum AVPixelFormat pix_fmt;
297 constraints = av_mallocz(sizeof(*constraints));
301 err = vaapi_frames_get_constraints(hwdev, NULL, constraints);
305 image_count = vaMaxNumImageFormats(hwctx->display);
306 if (image_count <= 0) {
310 image_list = av_malloc(image_count * sizeof(*image_list));
312 err = AVERROR(ENOMEM);
315 vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
316 if (vas != VA_STATUS_SUCCESS) {
321 ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
323 err = AVERROR(ENOMEM);
327 for (i = 0; i < image_count; i++) {
328 fourcc = image_list[i].fourcc;
329 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
330 for (j = 0; constraints->valid_sw_formats[j] != AV_PIX_FMT_NONE; j++) {
331 if (pix_fmt == constraints->valid_sw_formats[j])
334 if (constraints->valid_sw_formats[j] != AV_PIX_FMT_NONE) {
335 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
336 fourcc, av_get_pix_fmt_name(pix_fmt));
337 ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
338 ctx->formats[ctx->nb_formats].image_format = image_list[i];
341 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n", fourcc);
346 av_hwframe_constraints_free(&constraints);
349 av_freep(&ctx->formats);
351 av_hwframe_constraints_free(&constraints);
355 static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
357 VAAPIDeviceContext *ctx = hwdev->internal->priv;
359 av_freep(&ctx->formats);
362 static void vaapi_buffer_free(void *opaque, uint8_t *data)
364 AVHWFramesContext *hwfc = opaque;
365 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
366 VASurfaceID surface_id;
369 surface_id = (VASurfaceID)(uintptr_t)data;
371 vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
372 if (vas != VA_STATUS_SUCCESS) {
373 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
374 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
378 static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
380 AVHWFramesContext *hwfc = opaque;
381 VAAPIFramesContext *ctx = hwfc->internal->priv;
382 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
383 AVVAAPIFramesContext *avfc = hwfc->hwctx;
384 VASurfaceID surface_id;
388 vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
389 hwfc->width, hwfc->height,
391 ctx->attributes, ctx->nb_attributes);
392 if (vas != VA_STATUS_SUCCESS) {
393 av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
394 "%d (%s).\n", vas, vaErrorStr(vas));
397 av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
399 ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
400 sizeof(surface_id), &vaapi_buffer_free,
401 hwfc, AV_BUFFER_FLAG_READONLY);
403 vaDestroySurfaces(hwctx->display, &surface_id, 1);
407 if (hwfc->initial_pool_size > 0) {
408 // This is a fixed-size pool, so we must still be in the initial
409 // allocation sequence.
410 av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
411 avfc->surface_ids[avfc->nb_surfaces] = surface_id;
418 static int vaapi_frames_init(AVHWFramesContext *hwfc)
420 AVVAAPIFramesContext *avfc = hwfc->hwctx;
421 VAAPIFramesContext *ctx = hwfc->internal->priv;
422 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
423 VAImageFormat *expected_format;
424 AVBufferRef *test_surface = NULL;
425 VASurfaceID test_surface_id;
429 unsigned int fourcc, rt_format;
431 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
432 if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) {
433 fourcc = vaapi_format_map[i].fourcc;
434 rt_format = vaapi_format_map[i].rt_format;
438 if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
439 av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
440 av_get_pix_fmt_name(hwfc->sw_format));
441 return AVERROR(EINVAL);
445 int need_memory_type = 1, need_pixel_format = 1;
446 for (i = 0; i < avfc->nb_attributes; i++) {
447 if (ctx->attributes[i].type == VASurfaceAttribMemoryType)
448 need_memory_type = 0;
449 if (ctx->attributes[i].type == VASurfaceAttribPixelFormat)
450 need_pixel_format = 0;
453 avfc->nb_attributes + need_memory_type + need_pixel_format;
455 ctx->attributes = av_malloc(ctx->nb_attributes *
456 sizeof(*ctx->attributes));
457 if (!ctx->attributes) {
458 err = AVERROR(ENOMEM);
462 for (i = 0; i < avfc->nb_attributes; i++)
463 ctx->attributes[i] = avfc->attributes[i];
464 if (need_memory_type) {
465 ctx->attributes[i++] = (VASurfaceAttrib) {
466 .type = VASurfaceAttribMemoryType,
467 .flags = VA_SURFACE_ATTRIB_SETTABLE,
468 .value.type = VAGenericValueTypeInteger,
469 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
472 if (need_pixel_format) {
473 ctx->attributes[i++] = (VASurfaceAttrib) {
474 .type = VASurfaceAttribPixelFormat,
475 .flags = VA_SURFACE_ATTRIB_SETTABLE,
476 .value.type = VAGenericValueTypeInteger,
477 .value.value.i = fourcc,
480 av_assert0(i == ctx->nb_attributes);
482 ctx->rt_format = rt_format;
484 if (hwfc->initial_pool_size > 0) {
485 // This pool will be usable as a render target, so we need to store
486 // all of the surface IDs somewhere that vaCreateContext() calls
487 // will be able to access them.
488 avfc->nb_surfaces = 0;
489 avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
490 sizeof(*avfc->surface_ids));
491 if (!avfc->surface_ids) {
492 err = AVERROR(ENOMEM);
496 // This pool allows dynamic sizing, and will not be usable as a
498 avfc->nb_surfaces = 0;
499 avfc->surface_ids = NULL;
502 hwfc->internal->pool_internal =
503 av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
504 &vaapi_pool_alloc, NULL);
505 if (!hwfc->internal->pool_internal) {
506 av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
507 err = AVERROR(ENOMEM);
512 // Allocate a single surface to test whether vaDeriveImage() is going
513 // to work for the specific configuration.
515 test_surface = av_buffer_pool_get(hwfc->pool);
517 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
518 "user-configured buffer pool.\n");
519 err = AVERROR(ENOMEM);
523 test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
525 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
526 "internal buffer pool.\n");
527 err = AVERROR(ENOMEM);
531 test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
533 ctx->derive_works = 0;
535 err = vaapi_get_image_format(hwfc->device_ctx,
536 hwfc->sw_format, &expected_format);
538 vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
539 if (vas == VA_STATUS_SUCCESS) {
540 if (expected_format->fourcc == test_image.format.fourcc) {
541 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
542 ctx->derive_works = 1;
544 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
545 "derived image format %08x does not match "
546 "expected format %08x.\n",
547 expected_format->fourcc, test_image.format.fourcc);
549 vaDestroyImage(hwctx->display, test_image.image_id);
551 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
552 "deriving image does not work: "
553 "%d (%s).\n", vas, vaErrorStr(vas));
556 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
557 "image format is not supported.\n");
560 av_buffer_unref(&test_surface);
564 av_buffer_unref(&test_surface);
565 av_freep(&avfc->surface_ids);
566 av_freep(&ctx->attributes);
570 static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
572 AVVAAPIFramesContext *avfc = hwfc->hwctx;
573 VAAPIFramesContext *ctx = hwfc->internal->priv;
575 av_freep(&avfc->surface_ids);
576 av_freep(&ctx->attributes);
579 static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
581 frame->buf[0] = av_buffer_pool_get(hwfc->pool);
583 return AVERROR(ENOMEM);
585 frame->data[3] = frame->buf[0]->data;
586 frame->format = AV_PIX_FMT_VAAPI;
587 frame->width = hwfc->width;
588 frame->height = hwfc->height;
593 static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
594 enum AVHWFrameTransferDirection dir,
595 enum AVPixelFormat **formats)
597 VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
598 enum AVPixelFormat *pix_fmts, preferred_format;
601 preferred_format = hwfc->sw_format;
603 pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
605 return AVERROR(ENOMEM);
607 pix_fmts[0] = preferred_format;
609 for (i = 0; i < ctx->nb_formats; i++) {
610 if (ctx->formats[i].pix_fmt == preferred_format)
612 av_assert0(k < ctx->nb_formats);
613 pix_fmts[k++] = ctx->formats[i].pix_fmt;
615 av_assert0(k == ctx->nb_formats);
616 pix_fmts[k] = AV_PIX_FMT_NONE;
622 static void vaapi_unmap_frame(void *opaque, uint8_t *data)
624 AVHWFramesContext *hwfc = opaque;
625 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
626 VAAPISurfaceMap *map = (VAAPISurfaceMap*)data;
628 VASurfaceID surface_id;
632 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
633 av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
635 vas = vaUnmapBuffer(hwctx->display, map->image.buf);
636 if (vas != VA_STATUS_SUCCESS) {
637 av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
638 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
641 if ((map->flags & VAAPI_MAP_WRITE) &&
642 !(map->flags & VAAPI_MAP_DIRECT)) {
643 vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
644 0, 0, hwfc->width, hwfc->height,
645 0, 0, hwfc->width, hwfc->height);
646 if (vas != VA_STATUS_SUCCESS) {
647 av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
648 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
652 vas = vaDestroyImage(hwctx->display, map->image.image_id);
653 if (vas != VA_STATUS_SUCCESS) {
654 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
655 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
661 static int vaapi_map_frame(AVHWFramesContext *hwfc,
662 AVFrame *dst, const AVFrame *src, int flags)
664 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
665 VAAPIFramesContext *ctx = hwfc->internal->priv;
666 VASurfaceID surface_id;
667 VAImageFormat *image_format;
668 VAAPISurfaceMap *map;
670 void *address = NULL;
673 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
674 av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
676 if (!ctx->derive_works && (flags & VAAPI_MAP_DIRECT)) {
677 // Requested direct mapping but it is not possible.
678 return AVERROR(EINVAL);
680 if (dst->format == AV_PIX_FMT_NONE)
681 dst->format = hwfc->sw_format;
682 if (dst->format != hwfc->sw_format && (flags & VAAPI_MAP_DIRECT)) {
683 // Requested direct mapping but the formats do not match.
684 return AVERROR(EINVAL);
687 err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
689 // Requested format is not a valid output format.
690 return AVERROR(EINVAL);
693 map = av_malloc(sizeof(VAAPISurfaceMap));
695 return AVERROR(ENOMEM);
699 map->image.image_id = VA_INVALID_ID;
701 vas = vaSyncSurface(hwctx->display, surface_id);
702 if (vas != VA_STATUS_SUCCESS) {
703 av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
704 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
709 // The memory which we map using derive need not be connected to the CPU
710 // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
711 // memory is mappable but not cached, so normal memcpy()-like access is
712 // very slow to read it (but writing is ok). It is possible to read much
713 // faster with a copy routine which is aware of the limitation, but we
714 // assume for now that the user is not aware of that and would therefore
715 // prefer not to be given direct-mapped memory if they request read access.
716 if (ctx->derive_works &&
717 ((flags & VAAPI_MAP_DIRECT) || !(flags & VAAPI_MAP_READ))) {
718 vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
719 if (vas != VA_STATUS_SUCCESS) {
720 av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
721 "surface %#x: %d (%s).\n",
722 surface_id, vas, vaErrorStr(vas));
726 if (map->image.format.fourcc != image_format->fourcc) {
727 av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
728 "is in wrong format: expected %#08x, got %#08x.\n",
729 surface_id, image_format->fourcc, map->image.format.fourcc);
733 map->flags |= VAAPI_MAP_DIRECT;
735 vas = vaCreateImage(hwctx->display, image_format,
736 hwfc->width, hwfc->height, &map->image);
737 if (vas != VA_STATUS_SUCCESS) {
738 av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
739 "surface %#x: %d (%s).\n",
740 surface_id, vas, vaErrorStr(vas));
744 if (flags & VAAPI_MAP_READ) {
745 vas = vaGetImage(hwctx->display, surface_id, 0, 0,
746 hwfc->width, hwfc->height, map->image.image_id);
747 if (vas != VA_STATUS_SUCCESS) {
748 av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
749 "surface %#x: %d (%s).\n",
750 surface_id, vas, vaErrorStr(vas));
757 vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
758 if (vas != VA_STATUS_SUCCESS) {
759 av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
760 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
765 dst->width = src->width;
766 dst->height = src->height;
768 for (i = 0; i < map->image.num_planes; i++) {
769 dst->data[i] = (uint8_t*)address + map->image.offsets[i];
770 dst->linesize[i] = map->image.pitches[i];
773 #ifdef VA_FOURCC_YV16
774 map->image.format.fourcc == VA_FOURCC_YV16 ||
776 map->image.format.fourcc == VA_FOURCC_YV12) {
777 // Chroma planes are YVU rather than YUV, so swap them.
778 FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
781 dst->buf[0] = av_buffer_create((uint8_t*)map, sizeof(*map),
782 &vaapi_unmap_frame, hwfc, 0);
784 err = AVERROR(ENOMEM);
793 vaUnmapBuffer(hwctx->display, map->image.buf);
794 if (map->image.image_id != VA_INVALID_ID)
795 vaDestroyImage(hwctx->display, map->image.image_id);
801 static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
802 AVFrame *dst, const AVFrame *src)
807 map = av_frame_alloc();
809 return AVERROR(ENOMEM);
810 map->format = dst->format;
812 err = vaapi_map_frame(hwfc, map, src, VAAPI_MAP_READ);
816 err = av_frame_copy(dst, map);
826 static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
827 AVFrame *dst, const AVFrame *src)
832 map = av_frame_alloc();
834 return AVERROR(ENOMEM);
835 map->format = src->format;
837 err = vaapi_map_frame(hwfc, map, dst, VAAPI_MAP_WRITE);
841 err = av_frame_copy(map, src);
851 static void vaapi_device_free(AVHWDeviceContext *ctx)
853 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
854 VAAPIDevicePriv *priv = ctx->user_opaque;
857 vaTerminate(hwctx->display);
860 if (priv->x11_display)
861 XCloseDisplay(priv->x11_display);
864 if (priv->drm_fd >= 0)
870 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
871 AVDictionary *opts, int flags)
873 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
874 VAAPIDevicePriv *priv;
875 VADisplay display = 0;
879 priv = av_mallocz(sizeof(*priv));
881 return AVERROR(ENOMEM);
885 ctx->user_opaque = priv;
886 ctx->free = vaapi_device_free;
889 if (!display && !(device && device[0] == '/')) {
890 // Try to open the device as an X11 display.
891 priv->x11_display = XOpenDisplay(device);
892 if (!priv->x11_display) {
893 av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
894 "%s.\n", XDisplayName(device));
896 display = vaGetDisplay(priv->x11_display);
898 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
899 "from X11 display %s.\n", XDisplayName(device));
900 return AVERROR_UNKNOWN;
903 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
904 "X11 display %s.\n", XDisplayName(device));
910 if (!display && device) {
911 // Try to open the device as a DRM path.
912 priv->drm_fd = open(device, O_RDWR);
913 if (priv->drm_fd < 0) {
914 av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
917 display = vaGetDisplayDRM(priv->drm_fd);
919 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
920 "from DRM device %s.\n", device);
921 return AVERROR_UNKNOWN;
924 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
925 "DRM device %s.\n", device);
931 av_log(ctx, AV_LOG_ERROR, "No VA display found for "
932 "device: %s.\n", device ? device : "");
933 return AVERROR(EINVAL);
936 hwctx->display = display;
938 vas = vaInitialize(display, &major, &minor);
939 if (vas != VA_STATUS_SUCCESS) {
940 av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
941 "connection: %d (%s).\n", vas, vaErrorStr(vas));
944 av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
945 "version %d.%d\n", major, minor);
950 const HWContextType ff_hwcontext_type_vaapi = {
951 .type = AV_HWDEVICE_TYPE_VAAPI,
954 .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
955 .device_priv_size = sizeof(VAAPIDeviceContext),
956 .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
957 .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
958 .frames_priv_size = sizeof(VAAPIFramesContext),
960 .device_create = &vaapi_device_create,
961 .device_init = &vaapi_device_init,
962 .device_uninit = &vaapi_device_uninit,
963 .frames_get_constraints = &vaapi_frames_get_constraints,
964 .frames_init = &vaapi_frames_init,
965 .frames_uninit = &vaapi_frames_uninit,
966 .frames_get_buffer = &vaapi_get_buffer,
967 .transfer_get_formats = &vaapi_transfer_get_formats,
968 .transfer_data_to = &vaapi_transfer_data_to,
969 .transfer_data_from = &vaapi_transfer_data_from,
971 .pix_fmts = (const enum AVPixelFormat[]) {