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