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 VAAPIDeviceContext *ctx = hwdev->internal->priv;
159 VASurfaceAttrib *attr_list = NULL;
161 enum AVPixelFormat pix_fmt;
163 int err, i, j, attr_count, pix_fmt_count;
167 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
169 if (vas != VA_STATUS_SUCCESS) {
170 av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
171 "%d (%s).\n", vas, vaErrorStr(vas));
172 err = AVERROR(ENOSYS);
176 attr_list = av_malloc(attr_count * sizeof(*attr_list));
178 err = AVERROR(ENOMEM);
182 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
183 attr_list, &attr_count);
184 if (vas != VA_STATUS_SUCCESS) {
185 av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
186 "%d (%s).\n", vas, vaErrorStr(vas));
187 err = AVERROR(ENOSYS);
192 for (i = 0; i < attr_count; i++) {
193 switch (attr_list[i].type) {
194 case VASurfaceAttribPixelFormat:
195 fourcc = attr_list[i].value.value.i;
196 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
197 if (pix_fmt != AV_PIX_FMT_NONE) {
200 // Something unsupported - ignore.
203 case VASurfaceAttribMinWidth:
204 constraints->min_width = attr_list[i].value.value.i;
206 case VASurfaceAttribMinHeight:
207 constraints->min_height = attr_list[i].value.value.i;
209 case VASurfaceAttribMaxWidth:
210 constraints->max_width = attr_list[i].value.value.i;
212 case VASurfaceAttribMaxHeight:
213 constraints->max_height = attr_list[i].value.value.i;
217 if (pix_fmt_count == 0) {
218 // Nothing usable found. Presumably there exists something which
219 // works, so leave the set null to indicate unknown.
220 constraints->valid_sw_formats = NULL;
222 constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
224 if (!constraints->valid_sw_formats) {
225 err = AVERROR(ENOMEM);
229 for (i = j = 0; i < attr_count; i++) {
230 if (attr_list[i].type != VASurfaceAttribPixelFormat)
232 fourcc = attr_list[i].value.value.i;
233 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
234 if (pix_fmt != AV_PIX_FMT_NONE)
235 constraints->valid_sw_formats[j++] = pix_fmt;
237 av_assert0(j == pix_fmt_count);
238 constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
241 // No configuration supplied.
242 // Return the full set of image formats known by the implementation.
243 constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
245 if (!constraints->valid_sw_formats) {
246 err = AVERROR(ENOMEM);
249 for (i = 0; i < ctx->nb_formats; i++)
250 constraints->valid_sw_formats[i] = ctx->formats[i].pix_fmt;
251 constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE;
254 constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
255 if (!constraints->valid_hw_formats) {
256 err = AVERROR(ENOMEM);
259 constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
260 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
264 av_freep(&attr_list);
268 static int vaapi_device_init(AVHWDeviceContext *hwdev)
270 VAAPIDeviceContext *ctx = hwdev->internal->priv;
271 AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
272 VAImageFormat *image_list = NULL;
274 int err, i, image_count;
275 enum AVPixelFormat pix_fmt;
278 image_count = vaMaxNumImageFormats(hwctx->display);
279 if (image_count <= 0) {
283 image_list = av_malloc(image_count * sizeof(*image_list));
285 err = AVERROR(ENOMEM);
288 vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
289 if (vas != VA_STATUS_SUCCESS) {
294 ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
296 err = AVERROR(ENOMEM);
300 for (i = 0; i < image_count; i++) {
301 fourcc = image_list[i].fourcc;
302 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
303 if (pix_fmt == AV_PIX_FMT_NONE) {
304 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
307 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
308 fourcc, av_get_pix_fmt_name(pix_fmt));
309 ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
310 ctx->formats[ctx->nb_formats].image_format = image_list[i];
318 av_freep(&ctx->formats);
323 static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
325 VAAPIDeviceContext *ctx = hwdev->internal->priv;
327 av_freep(&ctx->formats);
330 static void vaapi_buffer_free(void *opaque, uint8_t *data)
332 AVHWFramesContext *hwfc = opaque;
333 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
334 VASurfaceID surface_id;
337 surface_id = (VASurfaceID)(uintptr_t)data;
339 vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
340 if (vas != VA_STATUS_SUCCESS) {
341 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
342 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
346 static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
348 AVHWFramesContext *hwfc = opaque;
349 VAAPIFramesContext *ctx = hwfc->internal->priv;
350 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
351 AVVAAPIFramesContext *avfc = hwfc->hwctx;
352 VASurfaceID surface_id;
356 vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
357 hwfc->width, hwfc->height,
359 ctx->attributes, ctx->nb_attributes);
360 if (vas != VA_STATUS_SUCCESS) {
361 av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
362 "%d (%s).\n", vas, vaErrorStr(vas));
365 av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
367 ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
368 sizeof(surface_id), &vaapi_buffer_free,
369 hwfc, AV_BUFFER_FLAG_READONLY);
371 vaDestroySurfaces(hwctx->display, &surface_id, 1);
375 if (hwfc->initial_pool_size > 0) {
376 // This is a fixed-size pool, so we must still be in the initial
377 // allocation sequence.
378 av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
379 avfc->surface_ids[avfc->nb_surfaces] = surface_id;
386 static int vaapi_frames_init(AVHWFramesContext *hwfc)
388 AVVAAPIFramesContext *avfc = hwfc->hwctx;
389 VAAPIFramesContext *ctx = hwfc->internal->priv;
390 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
391 VAImageFormat *expected_format;
392 AVBufferRef *test_surface = NULL;
393 VASurfaceID test_surface_id;
397 unsigned int fourcc, rt_format;
399 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
400 if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) {
401 fourcc = vaapi_format_map[i].fourcc;
402 rt_format = vaapi_format_map[i].rt_format;
406 if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
407 av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
408 av_get_pix_fmt_name(hwfc->sw_format));
409 return AVERROR(EINVAL);
413 int need_memory_type = 1, need_pixel_format = 1;
414 for (i = 0; i < avfc->nb_attributes; i++) {
415 if (ctx->attributes[i].type == VASurfaceAttribMemoryType)
416 need_memory_type = 0;
417 if (ctx->attributes[i].type == VASurfaceAttribPixelFormat)
418 need_pixel_format = 0;
421 avfc->nb_attributes + need_memory_type + need_pixel_format;
423 ctx->attributes = av_malloc(ctx->nb_attributes *
424 sizeof(*ctx->attributes));
425 if (!ctx->attributes) {
426 err = AVERROR(ENOMEM);
430 for (i = 0; i < avfc->nb_attributes; i++)
431 ctx->attributes[i] = avfc->attributes[i];
432 if (need_memory_type) {
433 ctx->attributes[i++] = (VASurfaceAttrib) {
434 .type = VASurfaceAttribMemoryType,
435 .flags = VA_SURFACE_ATTRIB_SETTABLE,
436 .value.type = VAGenericValueTypeInteger,
437 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
440 if (need_pixel_format) {
441 ctx->attributes[i++] = (VASurfaceAttrib) {
442 .type = VASurfaceAttribPixelFormat,
443 .flags = VA_SURFACE_ATTRIB_SETTABLE,
444 .value.type = VAGenericValueTypeInteger,
445 .value.value.i = fourcc,
448 av_assert0(i == ctx->nb_attributes);
450 ctx->rt_format = rt_format;
452 if (hwfc->initial_pool_size > 0) {
453 // This pool will be usable as a render target, so we need to store
454 // all of the surface IDs somewhere that vaCreateContext() calls
455 // will be able to access them.
456 avfc->nb_surfaces = 0;
457 avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
458 sizeof(*avfc->surface_ids));
459 if (!avfc->surface_ids) {
460 err = AVERROR(ENOMEM);
464 // This pool allows dynamic sizing, and will not be usable as a
466 avfc->nb_surfaces = 0;
467 avfc->surface_ids = NULL;
470 hwfc->internal->pool_internal =
471 av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
472 &vaapi_pool_alloc, NULL);
473 if (!hwfc->internal->pool_internal) {
474 av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
475 err = AVERROR(ENOMEM);
480 // Allocate a single surface to test whether vaDeriveImage() is going
481 // to work for the specific configuration.
483 test_surface = av_buffer_pool_get(hwfc->pool);
485 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
486 "user-configured buffer pool.\n");
487 err = AVERROR(ENOMEM);
491 test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
493 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
494 "internal buffer pool.\n");
495 err = AVERROR(ENOMEM);
499 test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
501 ctx->derive_works = 0;
503 err = vaapi_get_image_format(hwfc->device_ctx,
504 hwfc->sw_format, &expected_format);
506 vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
507 if (vas == VA_STATUS_SUCCESS) {
508 if (expected_format->fourcc == test_image.format.fourcc) {
509 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
510 ctx->derive_works = 1;
512 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
513 "derived image format %08x does not match "
514 "expected format %08x.\n",
515 expected_format->fourcc, test_image.format.fourcc);
517 vaDestroyImage(hwctx->display, test_image.image_id);
519 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
520 "deriving image does not work: "
521 "%d (%s).\n", vas, vaErrorStr(vas));
524 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
525 "image format is not supported.\n");
528 av_buffer_unref(&test_surface);
532 av_buffer_unref(&test_surface);
533 av_freep(&avfc->surface_ids);
534 av_freep(&ctx->attributes);
538 static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
540 AVVAAPIFramesContext *avfc = hwfc->hwctx;
541 VAAPIFramesContext *ctx = hwfc->internal->priv;
543 av_freep(&avfc->surface_ids);
544 av_freep(&ctx->attributes);
547 static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
549 frame->buf[0] = av_buffer_pool_get(hwfc->pool);
551 return AVERROR(ENOMEM);
553 frame->data[3] = frame->buf[0]->data;
554 frame->format = AV_PIX_FMT_VAAPI;
555 frame->width = hwfc->width;
556 frame->height = hwfc->height;
561 static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
562 enum AVHWFrameTransferDirection dir,
563 enum AVPixelFormat **formats)
565 VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
566 enum AVPixelFormat *pix_fmts, preferred_format;
569 preferred_format = hwfc->sw_format;
571 pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
573 return AVERROR(ENOMEM);
575 pix_fmts[0] = preferred_format;
577 for (i = 0; i < ctx->nb_formats; i++) {
578 if (ctx->formats[i].pix_fmt == preferred_format)
580 av_assert0(k < ctx->nb_formats);
581 pix_fmts[k++] = ctx->formats[i].pix_fmt;
583 av_assert0(k == ctx->nb_formats);
584 pix_fmts[k] = AV_PIX_FMT_NONE;
590 static void vaapi_unmap_frame(void *opaque, uint8_t *data)
592 AVHWFramesContext *hwfc = opaque;
593 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
594 VAAPISurfaceMap *map = (VAAPISurfaceMap*)data;
596 VASurfaceID surface_id;
600 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
601 av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
603 vas = vaUnmapBuffer(hwctx->display, map->image.buf);
604 if (vas != VA_STATUS_SUCCESS) {
605 av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
606 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
609 if ((map->flags & VAAPI_MAP_WRITE) &&
610 !(map->flags & VAAPI_MAP_DIRECT)) {
611 vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
612 0, 0, hwfc->width, hwfc->height,
613 0, 0, hwfc->width, hwfc->height);
614 if (vas != VA_STATUS_SUCCESS) {
615 av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
616 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
620 vas = vaDestroyImage(hwctx->display, map->image.image_id);
621 if (vas != VA_STATUS_SUCCESS) {
622 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
623 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
629 static int vaapi_map_frame(AVHWFramesContext *hwfc,
630 AVFrame *dst, const AVFrame *src, int flags)
632 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
633 VAAPIFramesContext *ctx = hwfc->internal->priv;
634 VASurfaceID surface_id;
635 VAImageFormat *image_format;
636 VAAPISurfaceMap *map;
638 void *address = NULL;
641 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
642 av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
644 if (!ctx->derive_works && (flags & VAAPI_MAP_DIRECT)) {
645 // Requested direct mapping but it is not possible.
646 return AVERROR(EINVAL);
648 if (dst->format == AV_PIX_FMT_NONE)
649 dst->format = hwfc->sw_format;
650 if (dst->format != hwfc->sw_format && (flags & VAAPI_MAP_DIRECT)) {
651 // Requested direct mapping but the formats do not match.
652 return AVERROR(EINVAL);
655 err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
657 // Requested format is not a valid output format.
658 return AVERROR(EINVAL);
661 map = av_malloc(sizeof(VAAPISurfaceMap));
663 return AVERROR(ENOMEM);
667 map->image.image_id = VA_INVALID_ID;
669 vas = vaSyncSurface(hwctx->display, surface_id);
670 if (vas != VA_STATUS_SUCCESS) {
671 av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
672 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
677 // The memory which we map using derive need not be connected to the CPU
678 // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
679 // memory is mappable but not cached, so normal memcpy()-like access is
680 // very slow to read it (but writing is ok). It is possible to read much
681 // faster with a copy routine which is aware of the limitation, but we
682 // assume for now that the user is not aware of that and would therefore
683 // prefer not to be given direct-mapped memory if they request read access.
684 if (ctx->derive_works &&
685 ((flags & VAAPI_MAP_DIRECT) || !(flags & VAAPI_MAP_READ))) {
686 vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
687 if (vas != VA_STATUS_SUCCESS) {
688 av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
689 "surface %#x: %d (%s).\n",
690 surface_id, vas, vaErrorStr(vas));
694 if (map->image.format.fourcc != image_format->fourcc) {
695 av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
696 "is in wrong format: expected %#08x, got %#08x.\n",
697 surface_id, image_format->fourcc, map->image.format.fourcc);
701 map->flags |= VAAPI_MAP_DIRECT;
703 vas = vaCreateImage(hwctx->display, image_format,
704 hwfc->width, hwfc->height, &map->image);
705 if (vas != VA_STATUS_SUCCESS) {
706 av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
707 "surface %#x: %d (%s).\n",
708 surface_id, vas, vaErrorStr(vas));
712 if (flags & VAAPI_MAP_READ) {
713 vas = vaGetImage(hwctx->display, surface_id, 0, 0,
714 hwfc->width, hwfc->height, map->image.image_id);
715 if (vas != VA_STATUS_SUCCESS) {
716 av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
717 "surface %#x: %d (%s).\n",
718 surface_id, vas, vaErrorStr(vas));
725 vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
726 if (vas != VA_STATUS_SUCCESS) {
727 av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
728 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
733 dst->width = src->width;
734 dst->height = src->height;
736 for (i = 0; i < map->image.num_planes; i++) {
737 dst->data[i] = (uint8_t*)address + map->image.offsets[i];
738 dst->linesize[i] = map->image.pitches[i];
741 #ifdef VA_FOURCC_YV16
742 map->image.format.fourcc == VA_FOURCC_YV16 ||
744 map->image.format.fourcc == VA_FOURCC_YV12) {
745 // Chroma planes are YVU rather than YUV, so swap them.
746 FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
749 dst->buf[0] = av_buffer_create((uint8_t*)map, sizeof(*map),
750 &vaapi_unmap_frame, hwfc, 0);
752 err = AVERROR(ENOMEM);
761 vaUnmapBuffer(hwctx->display, map->image.buf);
762 if (map->image.image_id != VA_INVALID_ID)
763 vaDestroyImage(hwctx->display, map->image.image_id);
769 static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
770 AVFrame *dst, const AVFrame *src)
775 map = av_frame_alloc();
777 return AVERROR(ENOMEM);
778 map->format = dst->format;
780 err = vaapi_map_frame(hwfc, map, src, VAAPI_MAP_READ);
784 err = av_frame_copy(dst, map);
794 static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
795 AVFrame *dst, const AVFrame *src)
800 map = av_frame_alloc();
802 return AVERROR(ENOMEM);
803 map->format = src->format;
805 err = vaapi_map_frame(hwfc, map, dst, VAAPI_MAP_WRITE);
809 err = av_frame_copy(map, src);
819 static void vaapi_device_free(AVHWDeviceContext *ctx)
821 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
822 VAAPIDevicePriv *priv = ctx->user_opaque;
825 vaTerminate(hwctx->display);
828 if (priv->x11_display)
829 XCloseDisplay(priv->x11_display);
832 if (priv->drm_fd >= 0)
838 static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
839 AVDictionary *opts, int flags)
841 AVVAAPIDeviceContext *hwctx = ctx->hwctx;
842 VAAPIDevicePriv *priv;
843 VADisplay display = 0;
847 priv = av_mallocz(sizeof(*priv));
849 return AVERROR(ENOMEM);
853 ctx->user_opaque = priv;
854 ctx->free = vaapi_device_free;
857 if (!display && !(device && device[0] == '/')) {
858 // Try to open the device as an X11 display.
859 priv->x11_display = XOpenDisplay(device);
860 if (!priv->x11_display) {
861 av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
862 "%s.\n", XDisplayName(device));
864 display = vaGetDisplay(priv->x11_display);
866 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
867 "from X11 display %s.\n", XDisplayName(device));
868 return AVERROR_UNKNOWN;
871 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
872 "X11 display %s.\n", XDisplayName(device));
878 if (!display && device) {
879 // Try to open the device as a DRM path.
880 priv->drm_fd = open(device, O_RDWR);
881 if (priv->drm_fd < 0) {
882 av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
885 display = vaGetDisplayDRM(priv->drm_fd);
887 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
888 "from DRM device %s.\n", device);
889 return AVERROR_UNKNOWN;
892 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
893 "DRM device %s.\n", device);
899 av_log(ctx, AV_LOG_ERROR, "No VA display found for "
900 "device: %s.\n", device ? device : "");
901 return AVERROR(EINVAL);
904 hwctx->display = display;
906 vas = vaInitialize(display, &major, &minor);
907 if (vas != VA_STATUS_SUCCESS) {
908 av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
909 "connection: %d (%s).\n", vas, vaErrorStr(vas));
912 av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
913 "version %d.%d\n", major, minor);
918 const HWContextType ff_hwcontext_type_vaapi = {
919 .type = AV_HWDEVICE_TYPE_VAAPI,
922 .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
923 .device_priv_size = sizeof(VAAPIDeviceContext),
924 .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
925 .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
926 .frames_priv_size = sizeof(VAAPIFramesContext),
928 .device_create = &vaapi_device_create,
929 .device_init = &vaapi_device_init,
930 .device_uninit = &vaapi_device_uninit,
931 .frames_get_constraints = &vaapi_frames_get_constraints,
932 .frames_init = &vaapi_frames_init,
933 .frames_uninit = &vaapi_frames_uninit,
934 .frames_get_buffer = &vaapi_get_buffer,
935 .transfer_get_formats = &vaapi_transfer_get_formats,
936 .transfer_data_to = &vaapi_transfer_data_to,
937 .transfer_data_from = &vaapi_transfer_data_from,
939 .pix_fmts = (const enum AVPixelFormat[]) {