1/* 2 * This file is part of FFmpeg. 3 * 4 * FFmpeg is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * FFmpeg is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with FFmpeg; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include "config.h" 20 21#if HAVE_VAAPI_X11 22# include <va/va_x11.h> 23#endif 24#if HAVE_VAAPI_DRM 25# include <va/va_drm.h> 26#endif 27 28#if CONFIG_LIBDRM 29# include <va/va_drmcommon.h> 30# include <xf86drm.h> 31# include <drm_fourcc.h> 32# ifndef DRM_FORMAT_MOD_INVALID 33# define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1) 34# endif 35#endif 36 37#include <fcntl.h> 38#if HAVE_UNISTD_H 39# include <unistd.h> 40#endif 41 42 43#include "avassert.h" 44#include "buffer.h" 45#include "common.h" 46#include "hwcontext.h" 47#include "hwcontext_drm.h" 48#include "hwcontext_internal.h" 49#include "hwcontext_vaapi.h" 50#include "mem.h" 51#include "pixdesc.h" 52#include "pixfmt.h" 53 54 55typedef struct VAAPIDevicePriv { 56#if HAVE_VAAPI_X11 57 Display *x11_display; 58#endif 59 60 int drm_fd; 61} VAAPIDevicePriv; 62 63typedef struct VAAPISurfaceFormat { 64 enum AVPixelFormat pix_fmt; 65 VAImageFormat image_format; 66} VAAPISurfaceFormat; 67 68typedef struct VAAPIDeviceContext { 69 // Surface formats which can be used with this device. 70 VAAPISurfaceFormat *formats; 71 int nb_formats; 72} VAAPIDeviceContext; 73 74typedef struct VAAPIFramesContext { 75 // Surface attributes set at create time. 76 VASurfaceAttrib *attributes; 77 int nb_attributes; 78 // RT format of the underlying surface (Intel driver ignores this anyway). 79 unsigned int rt_format; 80 // Whether vaDeriveImage works. 81 int derive_works; 82 // Caches whether VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 is unsupported for 83 // surface imports. 84 int prime_2_import_unsupported; 85} VAAPIFramesContext; 86 87typedef struct VAAPIMapping { 88 // Handle to the derived or copied image which is mapped. 89 VAImage image; 90 // The mapping flags actually used. 91 int flags; 92} VAAPIMapping; 93 94typedef struct VAAPIFormat { 95 unsigned int fourcc; 96 unsigned int rt_format; 97 enum AVPixelFormat pix_fmt; 98 int chroma_planes_swapped; 99} VAAPIFormatDescriptor; 100 101#define MAP(va, rt, av, swap_uv) { \ 102 VA_FOURCC_ ## va, \ 103 VA_RT_FORMAT_ ## rt, \ 104 AV_PIX_FMT_ ## av, \ 105 swap_uv, \ 106 } 107// The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V 108// plane swap cases. The frame handling below tries to hide these. 109static const VAAPIFormatDescriptor vaapi_format_map[] = { 110 MAP(NV12, YUV420, NV12, 0), 111#ifdef VA_FOURCC_I420 112 MAP(I420, YUV420, YUV420P, 0), 113#endif 114 MAP(YV12, YUV420, YUV420P, 1), 115 MAP(IYUV, YUV420, YUV420P, 0), 116 MAP(422H, YUV422, YUV422P, 0), 117#ifdef VA_FOURCC_YV16 118 MAP(YV16, YUV422, YUV422P, 1), 119#endif 120 MAP(UYVY, YUV422, UYVY422, 0), 121 MAP(YUY2, YUV422, YUYV422, 0), 122#ifdef VA_FOURCC_Y210 123 MAP(Y210, YUV422_10, Y210, 0), 124#endif 125 MAP(411P, YUV411, YUV411P, 0), 126 MAP(422V, YUV422, YUV440P, 0), 127 MAP(444P, YUV444, YUV444P, 0), 128 MAP(Y800, YUV400, GRAY8, 0), 129#ifdef VA_FOURCC_P010 130 MAP(P010, YUV420_10BPP, P010, 0), 131#endif 132 MAP(BGRA, RGB32, BGRA, 0), 133 MAP(BGRX, RGB32, BGR0, 0), 134 MAP(RGBA, RGB32, RGBA, 0), 135 MAP(RGBX, RGB32, RGB0, 0), 136#ifdef VA_FOURCC_ABGR 137 MAP(ABGR, RGB32, ABGR, 0), 138 MAP(XBGR, RGB32, 0BGR, 0), 139#endif 140 MAP(ARGB, RGB32, ARGB, 0), 141 MAP(XRGB, RGB32, 0RGB, 0), 142#ifdef VA_FOURCC_X2R10G10B10 143 MAP(X2R10G10B10, RGB32_10, X2RGB10, 0), 144#endif 145}; 146#undef MAP 147 148static const VAAPIFormatDescriptor * 149 vaapi_format_from_fourcc(unsigned int fourcc) 150{ 151 int i; 152 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) 153 if (vaapi_format_map[i].fourcc == fourcc) 154 return &vaapi_format_map[i]; 155 return NULL; 156} 157 158static const VAAPIFormatDescriptor * 159 vaapi_format_from_pix_fmt(enum AVPixelFormat pix_fmt) 160{ 161 int i; 162 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) 163 if (vaapi_format_map[i].pix_fmt == pix_fmt) 164 return &vaapi_format_map[i]; 165 return NULL; 166} 167 168static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc) 169{ 170 const VAAPIFormatDescriptor *desc; 171 desc = vaapi_format_from_fourcc(fourcc); 172 if (desc) 173 return desc->pix_fmt; 174 else 175 return AV_PIX_FMT_NONE; 176} 177 178static int vaapi_get_image_format(AVHWDeviceContext *hwdev, 179 enum AVPixelFormat pix_fmt, 180 VAImageFormat **image_format) 181{ 182 VAAPIDeviceContext *ctx = hwdev->internal->priv; 183 int i; 184 185 for (i = 0; i < ctx->nb_formats; i++) { 186 if (ctx->formats[i].pix_fmt == pix_fmt) { 187 if (image_format) 188 *image_format = &ctx->formats[i].image_format; 189 return 0; 190 } 191 } 192 return AVERROR(EINVAL); 193} 194 195static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev, 196 const void *hwconfig, 197 AVHWFramesConstraints *constraints) 198{ 199 AVVAAPIDeviceContext *hwctx = hwdev->hwctx; 200 const AVVAAPIHWConfig *config = hwconfig; 201 VAAPIDeviceContext *ctx = hwdev->internal->priv; 202 VASurfaceAttrib *attr_list = NULL; 203 VAStatus vas; 204 enum AVPixelFormat pix_fmt; 205 unsigned int fourcc; 206 int err, i, j, attr_count, pix_fmt_count; 207 208 if (config && 209 !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) { 210 attr_count = 0; 211 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id, 212 0, &attr_count); 213 if (vas != VA_STATUS_SUCCESS) { 214 av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: " 215 "%d (%s).\n", vas, vaErrorStr(vas)); 216 err = AVERROR(ENOSYS); 217 goto fail; 218 } 219 220 attr_list = av_malloc(attr_count * sizeof(*attr_list)); 221 if (!attr_list) { 222 err = AVERROR(ENOMEM); 223 goto fail; 224 } 225 226 vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id, 227 attr_list, &attr_count); 228 if (vas != VA_STATUS_SUCCESS) { 229 av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: " 230 "%d (%s).\n", vas, vaErrorStr(vas)); 231 err = AVERROR(ENOSYS); 232 goto fail; 233 } 234 235 pix_fmt_count = 0; 236 for (i = 0; i < attr_count; i++) { 237 switch (attr_list[i].type) { 238 case VASurfaceAttribPixelFormat: 239 fourcc = attr_list[i].value.value.i; 240 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc); 241 if (pix_fmt != AV_PIX_FMT_NONE) { 242 ++pix_fmt_count; 243 } else { 244 // Something unsupported - ignore. 245 } 246 break; 247 case VASurfaceAttribMinWidth: 248 constraints->min_width = attr_list[i].value.value.i; 249 break; 250 case VASurfaceAttribMinHeight: 251 constraints->min_height = attr_list[i].value.value.i; 252 break; 253 case VASurfaceAttribMaxWidth: 254 constraints->max_width = attr_list[i].value.value.i; 255 break; 256 case VASurfaceAttribMaxHeight: 257 constraints->max_height = attr_list[i].value.value.i; 258 break; 259 } 260 } 261 if (pix_fmt_count == 0) { 262 // Nothing usable found. Presumably there exists something which 263 // works, so leave the set null to indicate unknown. 264 constraints->valid_sw_formats = NULL; 265 } else { 266 constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1, 267 sizeof(pix_fmt)); 268 if (!constraints->valid_sw_formats) { 269 err = AVERROR(ENOMEM); 270 goto fail; 271 } 272 273 for (i = j = 0; i < attr_count; i++) { 274 int k; 275 276 if (attr_list[i].type != VASurfaceAttribPixelFormat) 277 continue; 278 fourcc = attr_list[i].value.value.i; 279 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc); 280 281 if (pix_fmt == AV_PIX_FMT_NONE) 282 continue; 283 284 for (k = 0; k < j; k++) { 285 if (constraints->valid_sw_formats[k] == pix_fmt) 286 break; 287 } 288 289 if (k == j) 290 constraints->valid_sw_formats[j++] = pix_fmt; 291 } 292 constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE; 293 } 294 } else { 295 // No configuration supplied. 296 // Return the full set of image formats known by the implementation. 297 constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1, 298 sizeof(pix_fmt)); 299 if (!constraints->valid_sw_formats) { 300 err = AVERROR(ENOMEM); 301 goto fail; 302 } 303 for (i = j = 0; i < ctx->nb_formats; i++) { 304 int k; 305 306 for (k = 0; k < j; k++) { 307 if (constraints->valid_sw_formats[k] == ctx->formats[i].pix_fmt) 308 break; 309 } 310 311 if (k == j) 312 constraints->valid_sw_formats[j++] = ctx->formats[i].pix_fmt; 313 } 314 315 constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE; 316 } 317 318 constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt)); 319 if (!constraints->valid_hw_formats) { 320 err = AVERROR(ENOMEM); 321 goto fail; 322 } 323 constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI; 324 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; 325 326 err = 0; 327fail: 328 av_freep(&attr_list); 329 return err; 330} 331 332static const struct { 333 const char *friendly_name; 334 const char *match_string; 335 unsigned int quirks; 336} vaapi_driver_quirks_table[] = { 337#if !VA_CHECK_VERSION(1, 0, 0) 338 // The i965 driver did not conform before version 2.0. 339 { 340 "Intel i965 (Quick Sync)", 341 "i965", 342 AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS, 343 }, 344#endif 345 { 346 "Intel iHD", 347 "ubit", 348 AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE, 349 }, 350 { 351 "VDPAU wrapper", 352 "Splitted-Desktop Systems VDPAU backend for VA-API", 353 AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES, 354 }, 355}; 356 357static int vaapi_device_init(AVHWDeviceContext *hwdev) 358{ 359 VAAPIDeviceContext *ctx = hwdev->internal->priv; 360 AVVAAPIDeviceContext *hwctx = hwdev->hwctx; 361 VAImageFormat *image_list = NULL; 362 VAStatus vas; 363 const char *vendor_string; 364 int err, i, image_count; 365 enum AVPixelFormat pix_fmt; 366 unsigned int fourcc; 367 368 image_count = vaMaxNumImageFormats(hwctx->display); 369 if (image_count <= 0) { 370 err = AVERROR(EIO); 371 goto fail; 372 } 373 image_list = av_malloc(image_count * sizeof(*image_list)); 374 if (!image_list) { 375 err = AVERROR(ENOMEM); 376 goto fail; 377 } 378 vas = vaQueryImageFormats(hwctx->display, image_list, &image_count); 379 if (vas != VA_STATUS_SUCCESS) { 380 err = AVERROR(EIO); 381 goto fail; 382 } 383 384 ctx->formats = av_malloc(image_count * sizeof(*ctx->formats)); 385 if (!ctx->formats) { 386 err = AVERROR(ENOMEM); 387 goto fail; 388 } 389 ctx->nb_formats = 0; 390 for (i = 0; i < image_count; i++) { 391 fourcc = image_list[i].fourcc; 392 pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc); 393 if (pix_fmt == AV_PIX_FMT_NONE) { 394 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n", 395 fourcc); 396 } else { 397 av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n", 398 fourcc, av_get_pix_fmt_name(pix_fmt)); 399 ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt; 400 ctx->formats[ctx->nb_formats].image_format = image_list[i]; 401 ++ctx->nb_formats; 402 } 403 } 404 405 vendor_string = vaQueryVendorString(hwctx->display); 406 if (vendor_string) 407 av_log(hwdev, AV_LOG_VERBOSE, "VAAPI driver: %s.\n", vendor_string); 408 409 if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) { 410 av_log(hwdev, AV_LOG_VERBOSE, "Using quirks set by user (%#x).\n", 411 hwctx->driver_quirks); 412 } else { 413 // Detect the driver in use and set quirk flags if necessary. 414 hwctx->driver_quirks = 0; 415 if (vendor_string) { 416 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) { 417 if (strstr(vendor_string, 418 vaapi_driver_quirks_table[i].match_string)) { 419 av_log(hwdev, AV_LOG_VERBOSE, "Matched driver string " 420 "as known nonstandard driver \"%s\", setting " 421 "quirks (%#x).\n", 422 vaapi_driver_quirks_table[i].friendly_name, 423 vaapi_driver_quirks_table[i].quirks); 424 hwctx->driver_quirks |= 425 vaapi_driver_quirks_table[i].quirks; 426 break; 427 } 428 } 429 if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) { 430 av_log(hwdev, AV_LOG_VERBOSE, "Driver not found in known " 431 "nonstandard list, using standard behaviour.\n"); 432 } 433 } else { 434 av_log(hwdev, AV_LOG_VERBOSE, "Driver has no vendor string, " 435 "assuming standard behaviour.\n"); 436 } 437 } 438 439 av_free(image_list); 440 return 0; 441fail: 442 av_freep(&ctx->formats); 443 av_free(image_list); 444 return err; 445} 446 447static void vaapi_device_uninit(AVHWDeviceContext *hwdev) 448{ 449 VAAPIDeviceContext *ctx = hwdev->internal->priv; 450 451 av_freep(&ctx->formats); 452} 453 454static void vaapi_buffer_free(void *opaque, uint8_t *data) 455{ 456 AVHWFramesContext *hwfc = opaque; 457 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 458 VASurfaceID surface_id; 459 VAStatus vas; 460 461 surface_id = (VASurfaceID)(uintptr_t)data; 462 463 vas = vaDestroySurfaces(hwctx->display, &surface_id, 1); 464 if (vas != VA_STATUS_SUCCESS) { 465 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: " 466 "%d (%s).\n", surface_id, vas, vaErrorStr(vas)); 467 } 468} 469 470static AVBufferRef *vaapi_pool_alloc(void *opaque, size_t size) 471{ 472 AVHWFramesContext *hwfc = opaque; 473 VAAPIFramesContext *ctx = hwfc->internal->priv; 474 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 475 AVVAAPIFramesContext *avfc = hwfc->hwctx; 476 VASurfaceID surface_id; 477 VAStatus vas; 478 AVBufferRef *ref; 479 480 if (hwfc->initial_pool_size > 0 && 481 avfc->nb_surfaces >= hwfc->initial_pool_size) 482 return NULL; 483 484 vas = vaCreateSurfaces(hwctx->display, ctx->rt_format, 485 hwfc->width, hwfc->height, 486 &surface_id, 1, 487 ctx->attributes, ctx->nb_attributes); 488 if (vas != VA_STATUS_SUCCESS) { 489 av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: " 490 "%d (%s).\n", vas, vaErrorStr(vas)); 491 return NULL; 492 } 493 av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id); 494 495 ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id, 496 sizeof(surface_id), &vaapi_buffer_free, 497 hwfc, AV_BUFFER_FLAG_READONLY); 498 if (!ref) { 499 vaDestroySurfaces(hwctx->display, &surface_id, 1); 500 return NULL; 501 } 502 503 if (hwfc->initial_pool_size > 0) { 504 // This is a fixed-size pool, so we must still be in the initial 505 // allocation sequence. 506 av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size); 507 avfc->surface_ids[avfc->nb_surfaces] = surface_id; 508 ++avfc->nb_surfaces; 509 } 510 511 return ref; 512} 513 514static int vaapi_frames_init(AVHWFramesContext *hwfc) 515{ 516 AVVAAPIFramesContext *avfc = hwfc->hwctx; 517 VAAPIFramesContext *ctx = hwfc->internal->priv; 518 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 519 const VAAPIFormatDescriptor *desc; 520 VAImageFormat *expected_format; 521 AVBufferRef *test_surface = NULL; 522 VASurfaceID test_surface_id; 523 VAImage test_image; 524 VAStatus vas; 525 int err, i; 526 527 desc = vaapi_format_from_pix_fmt(hwfc->sw_format); 528 if (!desc) { 529 av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n", 530 av_get_pix_fmt_name(hwfc->sw_format)); 531 return AVERROR(EINVAL); 532 } 533 534 if (!hwfc->pool) { 535 if (!(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) { 536 int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE); 537 int need_pixel_format = 1; 538 for (i = 0; i < avfc->nb_attributes; i++) { 539 if (avfc->attributes[i].type == VASurfaceAttribMemoryType) 540 need_memory_type = 0; 541 if (avfc->attributes[i].type == VASurfaceAttribPixelFormat) 542 need_pixel_format = 0; 543 } 544 ctx->nb_attributes = 545 avfc->nb_attributes + need_memory_type + need_pixel_format; 546 547 ctx->attributes = av_malloc(ctx->nb_attributes * 548 sizeof(*ctx->attributes)); 549 if (!ctx->attributes) { 550 err = AVERROR(ENOMEM); 551 goto fail; 552 } 553 554 for (i = 0; i < avfc->nb_attributes; i++) 555 ctx->attributes[i] = avfc->attributes[i]; 556 if (need_memory_type) { 557 ctx->attributes[i++] = (VASurfaceAttrib) { 558 .type = VASurfaceAttribMemoryType, 559 .flags = VA_SURFACE_ATTRIB_SETTABLE, 560 .value.type = VAGenericValueTypeInteger, 561 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA, 562 }; 563 } 564 if (need_pixel_format) { 565 ctx->attributes[i++] = (VASurfaceAttrib) { 566 .type = VASurfaceAttribPixelFormat, 567 .flags = VA_SURFACE_ATTRIB_SETTABLE, 568 .value.type = VAGenericValueTypeInteger, 569 .value.value.i = desc->fourcc, 570 }; 571 } 572 av_assert0(i == ctx->nb_attributes); 573 } else { 574 ctx->attributes = NULL; 575 ctx->nb_attributes = 0; 576 } 577 578 ctx->rt_format = desc->rt_format; 579 580 if (hwfc->initial_pool_size > 0) { 581 // This pool will be usable as a render target, so we need to store 582 // all of the surface IDs somewhere that vaCreateContext() calls 583 // will be able to access them. 584 avfc->nb_surfaces = 0; 585 avfc->surface_ids = av_malloc(hwfc->initial_pool_size * 586 sizeof(*avfc->surface_ids)); 587 if (!avfc->surface_ids) { 588 err = AVERROR(ENOMEM); 589 goto fail; 590 } 591 } else { 592 // This pool allows dynamic sizing, and will not be usable as a 593 // render target. 594 avfc->nb_surfaces = 0; 595 avfc->surface_ids = NULL; 596 } 597 598 hwfc->internal->pool_internal = 599 av_buffer_pool_init2(sizeof(VASurfaceID), hwfc, 600 &vaapi_pool_alloc, NULL); 601 if (!hwfc->internal->pool_internal) { 602 av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n"); 603 err = AVERROR(ENOMEM); 604 goto fail; 605 } 606 } 607 608 // Allocate a single surface to test whether vaDeriveImage() is going 609 // to work for the specific configuration. 610 if (hwfc->pool) { 611 test_surface = av_buffer_pool_get(hwfc->pool); 612 if (!test_surface) { 613 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from " 614 "user-configured buffer pool.\n"); 615 err = AVERROR(ENOMEM); 616 goto fail; 617 } 618 } else { 619 test_surface = av_buffer_pool_get(hwfc->internal->pool_internal); 620 if (!test_surface) { 621 av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from " 622 "internal buffer pool.\n"); 623 err = AVERROR(ENOMEM); 624 goto fail; 625 } 626 } 627 test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data; 628 629 ctx->derive_works = 0; 630 631 err = vaapi_get_image_format(hwfc->device_ctx, 632 hwfc->sw_format, &expected_format); 633 if (err == 0) { 634 vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image); 635 if (vas == VA_STATUS_SUCCESS) { 636 if (expected_format->fourcc == test_image.format.fourcc) { 637 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n"); 638 ctx->derive_works = 1; 639 } else { 640 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: " 641 "derived image format %08x does not match " 642 "expected format %08x.\n", 643 expected_format->fourcc, test_image.format.fourcc); 644 } 645 vaDestroyImage(hwctx->display, test_image.image_id); 646 } else { 647 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: " 648 "deriving image does not work: " 649 "%d (%s).\n", vas, vaErrorStr(vas)); 650 } 651 } else { 652 av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: " 653 "image format is not supported.\n"); 654 } 655 656 av_buffer_unref(&test_surface); 657 return 0; 658 659fail: 660 av_buffer_unref(&test_surface); 661 av_freep(&avfc->surface_ids); 662 av_freep(&ctx->attributes); 663 return err; 664} 665 666static void vaapi_frames_uninit(AVHWFramesContext *hwfc) 667{ 668 AVVAAPIFramesContext *avfc = hwfc->hwctx; 669 VAAPIFramesContext *ctx = hwfc->internal->priv; 670 671 av_freep(&avfc->surface_ids); 672 av_freep(&ctx->attributes); 673} 674 675static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame) 676{ 677 frame->buf[0] = av_buffer_pool_get(hwfc->pool); 678 if (!frame->buf[0]) 679 return AVERROR(ENOMEM); 680 681 frame->data[3] = frame->buf[0]->data; 682 frame->format = AV_PIX_FMT_VAAPI; 683 frame->width = hwfc->width; 684 frame->height = hwfc->height; 685 686 return 0; 687} 688 689static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc, 690 enum AVHWFrameTransferDirection dir, 691 enum AVPixelFormat **formats) 692{ 693 VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv; 694 enum AVPixelFormat *pix_fmts; 695 int i, k, sw_format_available; 696 697 sw_format_available = 0; 698 for (i = 0; i < ctx->nb_formats; i++) { 699 if (ctx->formats[i].pix_fmt == hwfc->sw_format) 700 sw_format_available = 1; 701 } 702 703 pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts)); 704 if (!pix_fmts) 705 return AVERROR(ENOMEM); 706 707 if (sw_format_available) { 708 pix_fmts[0] = hwfc->sw_format; 709 k = 1; 710 } else { 711 k = 0; 712 } 713 for (i = 0; i < ctx->nb_formats; i++) { 714 if (ctx->formats[i].pix_fmt == hwfc->sw_format) 715 continue; 716 av_assert0(k < ctx->nb_formats); 717 pix_fmts[k++] = ctx->formats[i].pix_fmt; 718 } 719 pix_fmts[k] = AV_PIX_FMT_NONE; 720 721 *formats = pix_fmts; 722 return 0; 723} 724 725static void vaapi_unmap_frame(AVHWFramesContext *hwfc, 726 HWMapDescriptor *hwmap) 727{ 728 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 729 VAAPIMapping *map = hwmap->priv; 730 VASurfaceID surface_id; 731 VAStatus vas; 732 733 surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3]; 734 av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id); 735 736 vas = vaUnmapBuffer(hwctx->display, map->image.buf); 737 if (vas != VA_STATUS_SUCCESS) { 738 av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface " 739 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); 740 } 741 742 if ((map->flags & AV_HWFRAME_MAP_WRITE) && 743 !(map->flags & AV_HWFRAME_MAP_DIRECT)) { 744 vas = vaPutImage(hwctx->display, surface_id, map->image.image_id, 745 0, 0, hwfc->width, hwfc->height, 746 0, 0, hwfc->width, hwfc->height); 747 if (vas != VA_STATUS_SUCCESS) { 748 av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface " 749 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); 750 } 751 } 752 753 vas = vaDestroyImage(hwctx->display, map->image.image_id); 754 if (vas != VA_STATUS_SUCCESS) { 755 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface " 756 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); 757 } 758 759 av_free(map); 760} 761 762static int vaapi_map_frame(AVHWFramesContext *hwfc, 763 AVFrame *dst, const AVFrame *src, int flags) 764{ 765 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 766 VAAPIFramesContext *ctx = hwfc->internal->priv; 767 VASurfaceID surface_id; 768 const VAAPIFormatDescriptor *desc; 769 VAImageFormat *image_format; 770 VAAPIMapping *map; 771 VAStatus vas; 772 void *address = NULL; 773 int err, i; 774 775 surface_id = (VASurfaceID)(uintptr_t)src->data[3]; 776 av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id); 777 778 if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) { 779 // Requested direct mapping but it is not possible. 780 return AVERROR(EINVAL); 781 } 782 if (dst->format == AV_PIX_FMT_NONE) 783 dst->format = hwfc->sw_format; 784 if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) { 785 // Requested direct mapping but the formats do not match. 786 return AVERROR(EINVAL); 787 } 788 789 err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format); 790 if (err < 0) { 791 // Requested format is not a valid output format. 792 return AVERROR(EINVAL); 793 } 794 795 map = av_malloc(sizeof(*map)); 796 if (!map) 797 return AVERROR(ENOMEM); 798 map->flags = flags; 799 map->image.image_id = VA_INVALID_ID; 800 801 vas = vaSyncSurface(hwctx->display, surface_id); 802 if (vas != VA_STATUS_SUCCESS) { 803 av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface " 804 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); 805 err = AVERROR(EIO); 806 goto fail; 807 } 808 809 // The memory which we map using derive need not be connected to the CPU 810 // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the 811 // memory is mappable but not cached, so normal memcpy()-like access is 812 // very slow to read it (but writing is ok). It is possible to read much 813 // faster with a copy routine which is aware of the limitation, but we 814 // assume for now that the user is not aware of that and would therefore 815 // prefer not to be given direct-mapped memory if they request read access. 816 if (ctx->derive_works && dst->format == hwfc->sw_format && 817 ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) { 818 vas = vaDeriveImage(hwctx->display, surface_id, &map->image); 819 if (vas != VA_STATUS_SUCCESS) { 820 av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from " 821 "surface %#x: %d (%s).\n", 822 surface_id, vas, vaErrorStr(vas)); 823 err = AVERROR(EIO); 824 goto fail; 825 } 826 if (map->image.format.fourcc != image_format->fourcc) { 827 av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x " 828 "is in wrong format: expected %#08x, got %#08x.\n", 829 surface_id, image_format->fourcc, map->image.format.fourcc); 830 err = AVERROR(EIO); 831 goto fail; 832 } 833 map->flags |= AV_HWFRAME_MAP_DIRECT; 834 } else { 835 vas = vaCreateImage(hwctx->display, image_format, 836 hwfc->width, hwfc->height, &map->image); 837 if (vas != VA_STATUS_SUCCESS) { 838 av_log(hwfc, AV_LOG_ERROR, "Failed to create image for " 839 "surface %#x: %d (%s).\n", 840 surface_id, vas, vaErrorStr(vas)); 841 err = AVERROR(EIO); 842 goto fail; 843 } 844 if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) { 845 vas = vaGetImage(hwctx->display, surface_id, 0, 0, 846 hwfc->width, hwfc->height, map->image.image_id); 847 if (vas != VA_STATUS_SUCCESS) { 848 av_log(hwfc, AV_LOG_ERROR, "Failed to read image from " 849 "surface %#x: %d (%s).\n", 850 surface_id, vas, vaErrorStr(vas)); 851 err = AVERROR(EIO); 852 goto fail; 853 } 854 } 855 } 856 857 vas = vaMapBuffer(hwctx->display, map->image.buf, &address); 858 if (vas != VA_STATUS_SUCCESS) { 859 av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface " 860 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); 861 err = AVERROR(EIO); 862 goto fail; 863 } 864 865 err = ff_hwframe_map_create(src->hw_frames_ctx, 866 dst, src, &vaapi_unmap_frame, map); 867 if (err < 0) 868 goto fail; 869 870 dst->width = src->width; 871 dst->height = src->height; 872 873 for (i = 0; i < map->image.num_planes; i++) { 874 dst->data[i] = (uint8_t*)address + map->image.offsets[i]; 875 dst->linesize[i] = map->image.pitches[i]; 876 } 877 878 desc = vaapi_format_from_fourcc(map->image.format.fourcc); 879 if (desc && desc->chroma_planes_swapped) { 880 // Chroma planes are YVU rather than YUV, so swap them. 881 FFSWAP(uint8_t*, dst->data[1], dst->data[2]); 882 } 883 884 return 0; 885 886fail: 887 if (map) { 888 if (address) 889 vaUnmapBuffer(hwctx->display, map->image.buf); 890 if (map->image.image_id != VA_INVALID_ID) 891 vaDestroyImage(hwctx->display, map->image.image_id); 892 av_free(map); 893 } 894 return err; 895} 896 897static int vaapi_transfer_data_from(AVHWFramesContext *hwfc, 898 AVFrame *dst, const AVFrame *src) 899{ 900 AVFrame *map; 901 int err; 902 903 if (dst->width > hwfc->width || dst->height > hwfc->height) 904 return AVERROR(EINVAL); 905 906 map = av_frame_alloc(); 907 if (!map) 908 return AVERROR(ENOMEM); 909 map->format = dst->format; 910 911 err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ); 912 if (err) 913 goto fail; 914 915 map->width = dst->width; 916 map->height = dst->height; 917 918 err = av_frame_copy(dst, map); 919 if (err) 920 goto fail; 921 922 err = 0; 923fail: 924 av_frame_free(&map); 925 return err; 926} 927 928static int vaapi_transfer_data_to(AVHWFramesContext *hwfc, 929 AVFrame *dst, const AVFrame *src) 930{ 931 AVFrame *map; 932 int err; 933 934 if (src->width > hwfc->width || src->height > hwfc->height) 935 return AVERROR(EINVAL); 936 937 map = av_frame_alloc(); 938 if (!map) 939 return AVERROR(ENOMEM); 940 map->format = src->format; 941 942 err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE); 943 if (err) 944 goto fail; 945 946 map->width = src->width; 947 map->height = src->height; 948 949 err = av_frame_copy(map, src); 950 if (err) 951 goto fail; 952 953 err = 0; 954fail: 955 av_frame_free(&map); 956 return err; 957} 958 959static int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst, 960 const AVFrame *src, int flags) 961{ 962 int err; 963 964 if (dst->format != AV_PIX_FMT_NONE) { 965 err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL); 966 if (err < 0) 967 return AVERROR(ENOSYS); 968 } 969 970 err = vaapi_map_frame(hwfc, dst, src, flags); 971 if (err) 972 return err; 973 974 err = av_frame_copy_props(dst, src); 975 if (err) 976 return err; 977 978 return 0; 979} 980 981#if CONFIG_LIBDRM 982 983#define DRM_MAP(va, layers, ...) { \ 984 VA_FOURCC_ ## va, \ 985 layers, \ 986 { __VA_ARGS__ } \ 987 } 988static const struct { 989 uint32_t va_fourcc; 990 int nb_layer_formats; 991 uint32_t layer_formats[AV_DRM_MAX_PLANES]; 992} vaapi_drm_format_map[] = { 993#ifdef DRM_FORMAT_R8 994 DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88), 995 DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_GR88), 996#endif 997 DRM_MAP(NV12, 1, DRM_FORMAT_NV12), 998#if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16) 999 DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616), 1000#endif 1001 DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888), 1002 DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888), 1003 DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888), 1004 DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888), 1005#ifdef VA_FOURCC_ABGR 1006 DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888), 1007 DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888), 1008#endif 1009 DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888), 1010 DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888), 1011}; 1012#undef DRM_MAP 1013 1014static void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc, 1015 HWMapDescriptor *hwmap) 1016{ 1017 AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; 1018 1019 VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv; 1020 1021 av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id); 1022 1023 vaDestroySurfaces(dst_dev->display, &surface_id, 1); 1024} 1025 1026static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst, 1027 const AVFrame *src, int flags) 1028{ 1029#if VA_CHECK_VERSION(1, 1, 0) 1030 VAAPIFramesContext *src_vafc = src_fc->internal->priv; 1031 int use_prime2; 1032#else 1033 int k; 1034#endif 1035 AVHWFramesContext *dst_fc = 1036 (AVHWFramesContext*)dst->hw_frames_ctx->data; 1037 AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; 1038 const AVDRMFrameDescriptor *desc; 1039 const VAAPIFormatDescriptor *format_desc; 1040 VASurfaceID surface_id; 1041 VAStatus vas = VA_STATUS_SUCCESS; 1042 uint32_t va_fourcc; 1043 int err, i, j; 1044 1045#if !VA_CHECK_VERSION(1, 1, 0) 1046 unsigned long buffer_handle; 1047 VASurfaceAttribExternalBuffers buffer_desc; 1048 VASurfaceAttrib attrs[2] = { 1049 { 1050 .type = VASurfaceAttribMemoryType, 1051 .flags = VA_SURFACE_ATTRIB_SETTABLE, 1052 .value.type = VAGenericValueTypeInteger, 1053 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME, 1054 }, 1055 { 1056 .type = VASurfaceAttribExternalBufferDescriptor, 1057 .flags = VA_SURFACE_ATTRIB_SETTABLE, 1058 .value.type = VAGenericValueTypePointer, 1059 .value.value.p = &buffer_desc, 1060 } 1061 }; 1062#endif 1063 1064 desc = (AVDRMFrameDescriptor*)src->data[0]; 1065 1066 if (desc->nb_objects != 1) { 1067 av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames " 1068 "made from a single DRM object.\n"); 1069 return AVERROR(EINVAL); 1070 } 1071 1072 va_fourcc = 0; 1073 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) { 1074 if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats) 1075 continue; 1076 for (j = 0; j < desc->nb_layers; j++) { 1077 if (desc->layers[j].format != 1078 vaapi_drm_format_map[i].layer_formats[j]) 1079 break; 1080 } 1081 if (j != desc->nb_layers) 1082 continue; 1083 va_fourcc = vaapi_drm_format_map[i].va_fourcc; 1084 break; 1085 } 1086 if (!va_fourcc) { 1087 av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported " 1088 "by VAAPI.\n"); 1089 return AVERROR(EINVAL); 1090 } 1091 1092 av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as " 1093 "%08x.\n", desc->objects[0].fd, va_fourcc); 1094 1095 format_desc = vaapi_format_from_fourcc(va_fourcc); 1096 av_assert0(format_desc); 1097 1098#if VA_CHECK_VERSION(1, 1, 0) 1099 use_prime2 = !src_vafc->prime_2_import_unsupported && 1100 desc->objects[0].format_modifier != DRM_FORMAT_MOD_INVALID; 1101 if (use_prime2) { 1102 VADRMPRIMESurfaceDescriptor prime_desc; 1103 VASurfaceAttrib prime_attrs[2] = { 1104 { 1105 .type = VASurfaceAttribMemoryType, 1106 .flags = VA_SURFACE_ATTRIB_SETTABLE, 1107 .value.type = VAGenericValueTypeInteger, 1108 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, 1109 }, 1110 { 1111 .type = VASurfaceAttribExternalBufferDescriptor, 1112 .flags = VA_SURFACE_ATTRIB_SETTABLE, 1113 .value.type = VAGenericValueTypePointer, 1114 .value.value.p = &prime_desc, 1115 } 1116 }; 1117 prime_desc.fourcc = va_fourcc; 1118 prime_desc.width = src_fc->width; 1119 prime_desc.height = src_fc->height; 1120 prime_desc.num_objects = desc->nb_objects; 1121 for (i = 0; i < desc->nb_objects; ++i) { 1122 prime_desc.objects[i].fd = desc->objects[i].fd; 1123 prime_desc.objects[i].size = desc->objects[i].size; 1124 prime_desc.objects[i].drm_format_modifier = 1125 desc->objects[i].format_modifier; 1126 } 1127 1128 prime_desc.num_layers = desc->nb_layers; 1129 for (i = 0; i < desc->nb_layers; ++i) { 1130 prime_desc.layers[i].drm_format = desc->layers[i].format; 1131 prime_desc.layers[i].num_planes = desc->layers[i].nb_planes; 1132 for (j = 0; j < desc->layers[i].nb_planes; ++j) { 1133 prime_desc.layers[i].object_index[j] = 1134 desc->layers[i].planes[j].object_index; 1135 prime_desc.layers[i].offset[j] = desc->layers[i].planes[j].offset; 1136 prime_desc.layers[i].pitch[j] = desc->layers[i].planes[j].pitch; 1137 } 1138 1139 if (format_desc->chroma_planes_swapped && 1140 desc->layers[i].nb_planes == 3) { 1141 FFSWAP(uint32_t, prime_desc.layers[i].pitch[1], 1142 prime_desc.layers[i].pitch[2]); 1143 FFSWAP(uint32_t, prime_desc.layers[i].offset[1], 1144 prime_desc.layers[i].offset[2]); 1145 } 1146 } 1147 1148 /* 1149 * We can query for PRIME_2 support with vaQuerySurfaceAttributes, but that 1150 * that needs the config_id which we don't have here . Both Intel and 1151 * Gallium seem to do the correct error checks, so lets just try the 1152 * PRIME_2 import first. 1153 */ 1154 vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format, 1155 src->width, src->height, &surface_id, 1, 1156 prime_attrs, FF_ARRAY_ELEMS(prime_attrs)); 1157 if (vas != VA_STATUS_SUCCESS) 1158 src_vafc->prime_2_import_unsupported = 1; 1159 } 1160 1161 if (!use_prime2 || vas != VA_STATUS_SUCCESS) { 1162 int k; 1163 unsigned long buffer_handle; 1164 VASurfaceAttribExternalBuffers buffer_desc; 1165 VASurfaceAttrib buffer_attrs[2] = { 1166 { 1167 .type = VASurfaceAttribMemoryType, 1168 .flags = VA_SURFACE_ATTRIB_SETTABLE, 1169 .value.type = VAGenericValueTypeInteger, 1170 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME, 1171 }, 1172 { 1173 .type = VASurfaceAttribExternalBufferDescriptor, 1174 .flags = VA_SURFACE_ATTRIB_SETTABLE, 1175 .value.type = VAGenericValueTypePointer, 1176 .value.value.p = &buffer_desc, 1177 } 1178 }; 1179 1180 buffer_handle = desc->objects[0].fd; 1181 buffer_desc.pixel_format = va_fourcc; 1182 buffer_desc.width = src_fc->width; 1183 buffer_desc.height = src_fc->height; 1184 buffer_desc.data_size = desc->objects[0].size; 1185 buffer_desc.buffers = &buffer_handle; 1186 buffer_desc.num_buffers = 1; 1187 buffer_desc.flags = 0; 1188 1189 k = 0; 1190 for (i = 0; i < desc->nb_layers; i++) { 1191 for (j = 0; j < desc->layers[i].nb_planes; j++) { 1192 buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch; 1193 buffer_desc.offsets[k] = desc->layers[i].planes[j].offset; 1194 ++k; 1195 } 1196 } 1197 buffer_desc.num_planes = k; 1198 1199 if (format_desc->chroma_planes_swapped && 1200 buffer_desc.num_planes == 3) { 1201 FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]); 1202 FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]); 1203 } 1204 1205 vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format, 1206 src->width, src->height, 1207 &surface_id, 1, 1208 buffer_attrs, FF_ARRAY_ELEMS(buffer_attrs)); 1209 } 1210#else 1211 buffer_handle = desc->objects[0].fd; 1212 buffer_desc.pixel_format = va_fourcc; 1213 buffer_desc.width = src_fc->width; 1214 buffer_desc.height = src_fc->height; 1215 buffer_desc.data_size = desc->objects[0].size; 1216 buffer_desc.buffers = &buffer_handle; 1217 buffer_desc.num_buffers = 1; 1218 buffer_desc.flags = 0; 1219 1220 k = 0; 1221 for (i = 0; i < desc->nb_layers; i++) { 1222 for (j = 0; j < desc->layers[i].nb_planes; j++) { 1223 buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch; 1224 buffer_desc.offsets[k] = desc->layers[i].planes[j].offset; 1225 ++k; 1226 } 1227 } 1228 buffer_desc.num_planes = k; 1229 1230 if (format_desc->chroma_planes_swapped && 1231 buffer_desc.num_planes == 3) { 1232 FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]); 1233 FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]); 1234 } 1235 1236 vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format, 1237 src->width, src->height, 1238 &surface_id, 1, 1239 attrs, FF_ARRAY_ELEMS(attrs)); 1240#endif 1241 if (vas != VA_STATUS_SUCCESS) { 1242 av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM " 1243 "object: %d (%s).\n", vas, vaErrorStr(vas)); 1244 return AVERROR(EIO); 1245 } 1246 av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id); 1247 1248 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, 1249 &vaapi_unmap_from_drm, 1250 (void*)(uintptr_t)surface_id); 1251 if (err < 0) 1252 return err; 1253 1254 dst->width = src->width; 1255 dst->height = src->height; 1256 dst->data[3] = (uint8_t*)(uintptr_t)surface_id; 1257 1258 av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to " 1259 "surface %#x.\n", desc->objects[0].fd, surface_id); 1260 1261 return 0; 1262} 1263 1264#if VA_CHECK_VERSION(1, 1, 0) 1265static void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc, 1266 HWMapDescriptor *hwmap) 1267{ 1268 AVDRMFrameDescriptor *drm_desc = hwmap->priv; 1269 int i; 1270 1271 for (i = 0; i < drm_desc->nb_objects; i++) 1272 close(drm_desc->objects[i].fd); 1273 1274 av_freep(&drm_desc); 1275} 1276 1277static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst, 1278 const AVFrame *src, int flags) 1279{ 1280 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 1281 VASurfaceID surface_id; 1282 VAStatus vas; 1283 VADRMPRIMESurfaceDescriptor va_desc; 1284 AVDRMFrameDescriptor *drm_desc = NULL; 1285 uint32_t export_flags; 1286 int err, i, j; 1287 1288 surface_id = (VASurfaceID)(uintptr_t)src->data[3]; 1289 1290 export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS; 1291 if (flags & AV_HWFRAME_MAP_READ) 1292 export_flags |= VA_EXPORT_SURFACE_READ_ONLY; 1293 if (flags & AV_HWFRAME_MAP_WRITE) 1294 export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY; 1295 1296 vas = vaExportSurfaceHandle(hwctx->display, surface_id, 1297 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, 1298 export_flags, &va_desc); 1299 if (vas != VA_STATUS_SUCCESS) { 1300 if (vas == VA_STATUS_ERROR_UNIMPLEMENTED) 1301 return AVERROR(ENOSYS); 1302 av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: " 1303 "%d (%s).\n", surface_id, vas, vaErrorStr(vas)); 1304 return AVERROR(EIO); 1305 } 1306 1307 drm_desc = av_mallocz(sizeof(*drm_desc)); 1308 if (!drm_desc) { 1309 err = AVERROR(ENOMEM); 1310 goto fail; 1311 } 1312 1313 // By some bizarre coincidence, these structures are very similar... 1314 drm_desc->nb_objects = va_desc.num_objects; 1315 for (i = 0; i < va_desc.num_objects; i++) { 1316 drm_desc->objects[i].fd = va_desc.objects[i].fd; 1317 drm_desc->objects[i].size = va_desc.objects[i].size; 1318 drm_desc->objects[i].format_modifier = 1319 va_desc.objects[i].drm_format_modifier; 1320 } 1321 drm_desc->nb_layers = va_desc.num_layers; 1322 for (i = 0; i < va_desc.num_layers; i++) { 1323 drm_desc->layers[i].format = va_desc.layers[i].drm_format; 1324 drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes; 1325 for (j = 0; j < va_desc.layers[i].num_planes; j++) { 1326 drm_desc->layers[i].planes[j].object_index = 1327 va_desc.layers[i].object_index[j]; 1328 drm_desc->layers[i].planes[j].offset = 1329 va_desc.layers[i].offset[j]; 1330 drm_desc->layers[i].planes[j].pitch = 1331 va_desc.layers[i].pitch[j]; 1332 } 1333 } 1334 1335 err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, 1336 &vaapi_unmap_to_drm_esh, drm_desc); 1337 if (err < 0) 1338 goto fail; 1339 1340 dst->width = src->width; 1341 dst->height = src->height; 1342 dst->data[0] = (uint8_t*)drm_desc; 1343 1344 return 0; 1345 1346fail: 1347 for (i = 0; i < va_desc.num_objects; i++) 1348 close(va_desc.objects[i].fd); 1349 av_freep(&drm_desc); 1350 return err; 1351} 1352#endif 1353 1354#if VA_CHECK_VERSION(0, 36, 0) 1355typedef struct VAAPIDRMImageBufferMapping { 1356 VAImage image; 1357 VABufferInfo buffer_info; 1358 1359 AVDRMFrameDescriptor drm_desc; 1360} VAAPIDRMImageBufferMapping; 1361 1362static void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc, 1363 HWMapDescriptor *hwmap) 1364{ 1365 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 1366 VAAPIDRMImageBufferMapping *mapping = hwmap->priv; 1367 VASurfaceID surface_id; 1368 VAStatus vas; 1369 1370 surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3]; 1371 av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n", 1372 surface_id); 1373 1374 // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(), 1375 // so we shouldn't close them separately. 1376 1377 vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf); 1378 if (vas != VA_STATUS_SUCCESS) { 1379 av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer " 1380 "handle of image %#x (derived from surface %#x): " 1381 "%d (%s).\n", mapping->image.buf, surface_id, 1382 vas, vaErrorStr(vas)); 1383 } 1384 1385 vas = vaDestroyImage(hwctx->display, mapping->image.image_id); 1386 if (vas != VA_STATUS_SUCCESS) { 1387 av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image " 1388 "derived from surface %#x: %d (%s).\n", 1389 surface_id, vas, vaErrorStr(vas)); 1390 } 1391 1392 av_free(mapping); 1393} 1394 1395static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst, 1396 const AVFrame *src, int flags) 1397{ 1398 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 1399 VAAPIDRMImageBufferMapping *mapping = NULL; 1400 VASurfaceID surface_id; 1401 VAStatus vas; 1402 int err, i, p; 1403 1404 surface_id = (VASurfaceID)(uintptr_t)src->data[3]; 1405 av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n", 1406 surface_id); 1407 1408 mapping = av_mallocz(sizeof(*mapping)); 1409 if (!mapping) 1410 return AVERROR(ENOMEM); 1411 1412 vas = vaDeriveImage(hwctx->display, surface_id, 1413 &mapping->image); 1414 if (vas != VA_STATUS_SUCCESS) { 1415 av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from " 1416 "surface %#x: %d (%s).\n", 1417 surface_id, vas, vaErrorStr(vas)); 1418 err = AVERROR(EIO); 1419 goto fail; 1420 } 1421 1422 for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) { 1423 if (vaapi_drm_format_map[i].va_fourcc == 1424 mapping->image.format.fourcc) 1425 break; 1426 } 1427 if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) { 1428 av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for " 1429 "VAAPI format %#x.\n", mapping->image.format.fourcc); 1430 err = AVERROR(EINVAL); 1431 goto fail_derived; 1432 } 1433 1434 mapping->buffer_info.mem_type = 1435 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME; 1436 1437 mapping->drm_desc.nb_layers = 1438 vaapi_drm_format_map[i].nb_layer_formats; 1439 if (mapping->drm_desc.nb_layers > 1) { 1440 if (mapping->drm_desc.nb_layers != mapping->image.num_planes) { 1441 av_log(hwfc, AV_LOG_ERROR, "Image properties do not match " 1442 "expected format: got %d planes, but expected %d.\n", 1443 mapping->image.num_planes, mapping->drm_desc.nb_layers); 1444 err = AVERROR(EINVAL); 1445 goto fail_derived; 1446 } 1447 1448 for(p = 0; p < mapping->drm_desc.nb_layers; p++) { 1449 mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) { 1450 .format = vaapi_drm_format_map[i].layer_formats[p], 1451 .nb_planes = 1, 1452 .planes[0] = { 1453 .object_index = 0, 1454 .offset = mapping->image.offsets[p], 1455 .pitch = mapping->image.pitches[p], 1456 }, 1457 }; 1458 } 1459 } else { 1460 mapping->drm_desc.layers[0].format = 1461 vaapi_drm_format_map[i].layer_formats[0]; 1462 mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes; 1463 for (p = 0; p < mapping->image.num_planes; p++) { 1464 mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) { 1465 .object_index = 0, 1466 .offset = mapping->image.offsets[p], 1467 .pitch = mapping->image.pitches[p], 1468 }; 1469 } 1470 } 1471 1472 vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf, 1473 &mapping->buffer_info); 1474 if (vas != VA_STATUS_SUCCESS) { 1475 av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer " 1476 "handle from image %#x (derived from surface %#x): " 1477 "%d (%s).\n", mapping->image.buf, surface_id, 1478 vas, vaErrorStr(vas)); 1479 err = AVERROR(EIO); 1480 goto fail_derived; 1481 } 1482 1483 av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n", 1484 mapping->buffer_info.handle); 1485 1486 mapping->drm_desc.nb_objects = 1; 1487 mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) { 1488 .fd = mapping->buffer_info.handle, 1489 .size = mapping->image.data_size, 1490 // There is no way to get the format modifier with this API. 1491 .format_modifier = DRM_FORMAT_MOD_INVALID, 1492 }; 1493 1494 err = ff_hwframe_map_create(src->hw_frames_ctx, 1495 dst, src, &vaapi_unmap_to_drm_abh, 1496 mapping); 1497 if (err < 0) 1498 goto fail_mapped; 1499 1500 dst->data[0] = (uint8_t*)&mapping->drm_desc; 1501 dst->width = src->width; 1502 dst->height = src->height; 1503 1504 return 0; 1505 1506fail_mapped: 1507 vaReleaseBufferHandle(hwctx->display, mapping->image.buf); 1508fail_derived: 1509 vaDestroyImage(hwctx->display, mapping->image.image_id); 1510fail: 1511 av_freep(&mapping); 1512 return err; 1513} 1514#endif 1515 1516static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst, 1517 const AVFrame *src, int flags) 1518{ 1519#if VA_CHECK_VERSION(1, 1, 0) 1520 int err; 1521 err = vaapi_map_to_drm_esh(hwfc, dst, src, flags); 1522 if (err != AVERROR(ENOSYS)) 1523 return err; 1524#endif 1525#if VA_CHECK_VERSION(0, 36, 0) 1526 return vaapi_map_to_drm_abh(hwfc, dst, src, flags); 1527#endif 1528 return AVERROR(ENOSYS); 1529} 1530 1531#endif /* CONFIG_LIBDRM */ 1532 1533static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst, 1534 const AVFrame *src, int flags) 1535{ 1536 switch (src->format) { 1537#if CONFIG_LIBDRM 1538 case AV_PIX_FMT_DRM_PRIME: 1539 return vaapi_map_from_drm(hwfc, dst, src, flags); 1540#endif 1541 default: 1542 return AVERROR(ENOSYS); 1543 } 1544} 1545 1546static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst, 1547 const AVFrame *src, int flags) 1548{ 1549 switch (dst->format) { 1550#if CONFIG_LIBDRM 1551 case AV_PIX_FMT_DRM_PRIME: 1552 return vaapi_map_to_drm(hwfc, dst, src, flags); 1553#endif 1554 default: 1555 return vaapi_map_to_memory(hwfc, dst, src, flags); 1556 } 1557} 1558 1559static void vaapi_device_free(AVHWDeviceContext *ctx) 1560{ 1561 AVVAAPIDeviceContext *hwctx = ctx->hwctx; 1562 VAAPIDevicePriv *priv = ctx->user_opaque; 1563 1564 if (hwctx->display) 1565 vaTerminate(hwctx->display); 1566 1567#if HAVE_VAAPI_X11 1568 if (priv->x11_display) 1569 XCloseDisplay(priv->x11_display); 1570#endif 1571 1572 if (priv->drm_fd >= 0) 1573 close(priv->drm_fd); 1574 1575 av_freep(&priv); 1576} 1577 1578#if CONFIG_VAAPI_1 1579static void vaapi_device_log_error(void *context, const char *message) 1580{ 1581 AVHWDeviceContext *ctx = context; 1582 1583 av_log(ctx, AV_LOG_ERROR, "libva: %s", message); 1584} 1585 1586static void vaapi_device_log_info(void *context, const char *message) 1587{ 1588 AVHWDeviceContext *ctx = context; 1589 1590 av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message); 1591} 1592#endif 1593 1594static int vaapi_device_connect(AVHWDeviceContext *ctx, 1595 VADisplay display) 1596{ 1597 AVVAAPIDeviceContext *hwctx = ctx->hwctx; 1598 int major, minor; 1599 VAStatus vas; 1600 1601#if CONFIG_VAAPI_1 1602 vaSetErrorCallback(display, &vaapi_device_log_error, ctx); 1603 vaSetInfoCallback (display, &vaapi_device_log_info, ctx); 1604#endif 1605 1606 hwctx->display = display; 1607 1608 vas = vaInitialize(display, &major, &minor); 1609 if (vas != VA_STATUS_SUCCESS) { 1610 av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI " 1611 "connection: %d (%s).\n", vas, vaErrorStr(vas)); 1612 return AVERROR(EIO); 1613 } 1614 av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: " 1615 "version %d.%d\n", major, minor); 1616 1617 return 0; 1618} 1619 1620static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device, 1621 AVDictionary *opts, int flags) 1622{ 1623 VAAPIDevicePriv *priv; 1624 VADisplay display = NULL; 1625 const AVDictionaryEntry *ent; 1626 int try_drm, try_x11, try_all; 1627 1628 priv = av_mallocz(sizeof(*priv)); 1629 if (!priv) 1630 return AVERROR(ENOMEM); 1631 1632 priv->drm_fd = -1; 1633 1634 ctx->user_opaque = priv; 1635 ctx->free = vaapi_device_free; 1636 1637 ent = av_dict_get(opts, "connection_type", NULL, 0); 1638 if (ent) { 1639 try_all = try_drm = try_x11 = 0; 1640 if (!strcmp(ent->value, "drm")) { 1641 try_drm = 1; 1642 } else if (!strcmp(ent->value, "x11")) { 1643 try_x11 = 1; 1644 } else { 1645 av_log(ctx, AV_LOG_ERROR, "Invalid connection type %s.\n", 1646 ent->value); 1647 return AVERROR(EINVAL); 1648 } 1649 } else { 1650 try_all = 1; 1651 try_drm = HAVE_VAAPI_DRM; 1652 try_x11 = HAVE_VAAPI_X11; 1653 } 1654 1655#if HAVE_VAAPI_DRM 1656 while (!display && try_drm) { 1657 // If the device is specified, try to open it as a DRM device node. 1658 // If not, look for a usable render node, possibly restricted to those 1659 // using a specified kernel driver. 1660 int loglevel = try_all ? AV_LOG_VERBOSE : AV_LOG_ERROR; 1661 if (device) { 1662 priv->drm_fd = open(device, O_RDWR); 1663 if (priv->drm_fd < 0) { 1664 av_log(ctx, loglevel, "Failed to open %s as " 1665 "DRM device node.\n", device); 1666 break; 1667 } 1668 } else { 1669 char path[64]; 1670 int n, max_devices = 8; 1671#if CONFIG_LIBDRM 1672 const AVDictionaryEntry *kernel_driver; 1673 kernel_driver = av_dict_get(opts, "kernel_driver", NULL, 0); 1674#endif 1675 for (n = 0; n < max_devices; n++) { 1676 snprintf(path, sizeof(path), 1677 "/dev/dri/renderD%d", 128 + n); 1678 priv->drm_fd = open(path, O_RDWR); 1679 if (priv->drm_fd < 0) { 1680 av_log(ctx, AV_LOG_VERBOSE, "Cannot open " 1681 "DRM render node for device %d.\n", n); 1682 break; 1683 } 1684#if CONFIG_LIBDRM 1685 if (kernel_driver) { 1686 drmVersion *info; 1687 info = drmGetVersion(priv->drm_fd); 1688 if (strcmp(kernel_driver->value, info->name)) { 1689 av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d " 1690 "with non-matching kernel driver (%s).\n", 1691 n, info->name); 1692 drmFreeVersion(info); 1693 close(priv->drm_fd); 1694 priv->drm_fd = -1; 1695 continue; 1696 } 1697 av_log(ctx, AV_LOG_VERBOSE, "Trying to use " 1698 "DRM render node for device %d, " 1699 "with matching kernel driver (%s).\n", 1700 n, info->name); 1701 drmFreeVersion(info); 1702 } else 1703#endif 1704 { 1705 av_log(ctx, AV_LOG_VERBOSE, "Trying to use " 1706 "DRM render node for device %d.\n", n); 1707 } 1708 break; 1709 } 1710 if (n >= max_devices) 1711 break; 1712 } 1713 1714 display = vaGetDisplayDRM(priv->drm_fd); 1715 if (!display) { 1716 av_log(ctx, AV_LOG_VERBOSE, "Cannot open a VA display " 1717 "from DRM device %s.\n", device); 1718 return AVERROR_EXTERNAL; 1719 } 1720 break; 1721 } 1722#endif 1723 1724#if HAVE_VAAPI_X11 1725 if (!display && try_x11) { 1726 // Try to open the device as an X11 display. 1727 priv->x11_display = XOpenDisplay(device); 1728 if (!priv->x11_display) { 1729 av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display " 1730 "%s.\n", XDisplayName(device)); 1731 } else { 1732 display = vaGetDisplay(priv->x11_display); 1733 if (!display) { 1734 av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display " 1735 "from X11 display %s.\n", XDisplayName(device)); 1736 return AVERROR_UNKNOWN; 1737 } 1738 1739 av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via " 1740 "X11 display %s.\n", XDisplayName(device)); 1741 } 1742 } 1743#endif 1744 1745 if (!display) { 1746 if (device) 1747 av_log(ctx, AV_LOG_ERROR, "No VA display found for " 1748 "device %s.\n", device); 1749 else 1750 av_log(ctx, AV_LOG_ERROR, "No VA display found for " 1751 "any default device.\n"); 1752 return AVERROR(EINVAL); 1753 } 1754 1755 ent = av_dict_get(opts, "driver", NULL, 0); 1756 if (ent) { 1757#if VA_CHECK_VERSION(0, 38, 0) 1758 VAStatus vas; 1759 vas = vaSetDriverName(display, ent->value); 1760 if (vas != VA_STATUS_SUCCESS) { 1761 av_log(ctx, AV_LOG_ERROR, "Failed to set driver name to " 1762 "%s: %d (%s).\n", ent->value, vas, vaErrorStr(vas)); 1763 vaTerminate(display); 1764 return AVERROR_EXTERNAL; 1765 } 1766#else 1767 av_log(ctx, AV_LOG_WARNING, "Driver name setting is not " 1768 "supported with this VAAPI version.\n"); 1769#endif 1770 } 1771 1772 return vaapi_device_connect(ctx, display); 1773} 1774 1775static int vaapi_device_derive(AVHWDeviceContext *ctx, 1776 AVHWDeviceContext *src_ctx, 1777 AVDictionary *opts, int flags) 1778{ 1779#if HAVE_VAAPI_DRM 1780 if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) { 1781 AVDRMDeviceContext *src_hwctx = src_ctx->hwctx; 1782 VADisplay *display; 1783 VAAPIDevicePriv *priv; 1784 int fd; 1785 1786 if (src_hwctx->fd < 0) { 1787 av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated " 1788 "device to derive a VA display from.\n"); 1789 return AVERROR(EINVAL); 1790 } 1791 1792#if CONFIG_LIBDRM 1793 { 1794 int node_type = drmGetNodeTypeFromFd(src_hwctx->fd); 1795 char *render_node; 1796 if (node_type < 0) { 1797 av_log(ctx, AV_LOG_ERROR, "DRM instance fd does not appear " 1798 "to refer to a DRM device.\n"); 1799 return AVERROR(EINVAL); 1800 } 1801 if (node_type == DRM_NODE_RENDER) { 1802 fd = src_hwctx->fd; 1803 } else { 1804 render_node = drmGetRenderDeviceNameFromFd(src_hwctx->fd); 1805 if (!render_node) { 1806 av_log(ctx, AV_LOG_VERBOSE, "Using non-render node " 1807 "because the device does not have an " 1808 "associated render node.\n"); 1809 fd = src_hwctx->fd; 1810 } else { 1811 fd = open(render_node, O_RDWR); 1812 if (fd < 0) { 1813 av_log(ctx, AV_LOG_VERBOSE, "Using non-render node " 1814 "because the associated render node " 1815 "could not be opened.\n"); 1816 fd = src_hwctx->fd; 1817 } else { 1818 av_log(ctx, AV_LOG_VERBOSE, "Using render node %s " 1819 "in place of non-render DRM device.\n", 1820 render_node); 1821 } 1822 free(render_node); 1823 } 1824 } 1825 } 1826#else 1827 fd = src_hwctx->fd; 1828#endif 1829 1830 priv = av_mallocz(sizeof(*priv)); 1831 if (!priv) { 1832 if (fd != src_hwctx->fd) { 1833 // The fd was opened in this function. 1834 close(fd); 1835 } 1836 return AVERROR(ENOMEM); 1837 } 1838 1839 if (fd == src_hwctx->fd) { 1840 // The fd is inherited from the source context and we are holding 1841 // a reference to that, we don't want to close it from here. 1842 priv->drm_fd = -1; 1843 } else { 1844 priv->drm_fd = fd; 1845 } 1846 1847 ctx->user_opaque = priv; 1848 ctx->free = &vaapi_device_free; 1849 1850 display = vaGetDisplayDRM(fd); 1851 if (!display) { 1852 av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from " 1853 "DRM device.\n"); 1854 return AVERROR(EIO); 1855 } 1856 1857 return vaapi_device_connect(ctx, display); 1858 } 1859#endif 1860 return AVERROR(ENOSYS); 1861} 1862 1863const HWContextType ff_hwcontext_type_vaapi = { 1864 .type = AV_HWDEVICE_TYPE_VAAPI, 1865 .name = "VAAPI", 1866 1867 .device_hwctx_size = sizeof(AVVAAPIDeviceContext), 1868 .device_priv_size = sizeof(VAAPIDeviceContext), 1869 .device_hwconfig_size = sizeof(AVVAAPIHWConfig), 1870 .frames_hwctx_size = sizeof(AVVAAPIFramesContext), 1871 .frames_priv_size = sizeof(VAAPIFramesContext), 1872 1873 .device_create = &vaapi_device_create, 1874 .device_derive = &vaapi_device_derive, 1875 .device_init = &vaapi_device_init, 1876 .device_uninit = &vaapi_device_uninit, 1877 .frames_get_constraints = &vaapi_frames_get_constraints, 1878 .frames_init = &vaapi_frames_init, 1879 .frames_uninit = &vaapi_frames_uninit, 1880 .frames_get_buffer = &vaapi_get_buffer, 1881 .transfer_get_formats = &vaapi_transfer_get_formats, 1882 .transfer_data_to = &vaapi_transfer_data_to, 1883 .transfer_data_from = &vaapi_transfer_data_from, 1884 .map_to = &vaapi_map_to, 1885 .map_from = &vaapi_map_from, 1886 1887 .pix_fmts = (const enum AVPixelFormat[]) { 1888 AV_PIX_FMT_VAAPI, 1889 AV_PIX_FMT_NONE 1890 }, 1891}; 1892