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#include <windows.h> 22 23#define COBJMACROS 24 25#include <initguid.h> 26#include <d3d11.h> 27#include <dxgi1_2.h> 28 29#if HAVE_DXGIDEBUG_H 30#include <dxgidebug.h> 31#endif 32 33#include "avassert.h" 34#include "common.h" 35#include "hwcontext.h" 36#include "hwcontext_d3d11va.h" 37#include "hwcontext_internal.h" 38#include "imgutils.h" 39#include "pixdesc.h" 40#include "pixfmt.h" 41#include "thread.h" 42#include "compat/w32dlfcn.h" 43 44typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory); 45 46static AVOnce functions_loaded = AV_ONCE_INIT; 47 48static PFN_CREATE_DXGI_FACTORY mCreateDXGIFactory; 49static PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice; 50 51static av_cold void load_functions(void) 52{ 53#if !HAVE_UWP 54 // We let these "leak" - this is fine, as unloading has no great benefit, and 55 // Windows will mark a DLL as loaded forever if its internal refcount overflows 56 // from too many LoadLibrary calls. 57 HANDLE d3dlib, dxgilib; 58 59 d3dlib = dlopen("d3d11.dll", 0); 60 dxgilib = dlopen("dxgi.dll", 0); 61 if (!d3dlib || !dxgilib) 62 return; 63 64 mD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE) GetProcAddress(d3dlib, "D3D11CreateDevice"); 65 mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) GetProcAddress(dxgilib, "CreateDXGIFactory"); 66#else 67 // In UWP (which lacks LoadLibrary), CreateDXGIFactory isn't available, 68 // only CreateDXGIFactory1 69 mD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE) D3D11CreateDevice; 70 mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) CreateDXGIFactory1; 71#endif 72} 73 74typedef struct D3D11VAFramesContext { 75 int nb_surfaces; 76 int nb_surfaces_used; 77 78 DXGI_FORMAT format; 79 80 ID3D11Texture2D *staging_texture; 81} D3D11VAFramesContext; 82 83static const struct { 84 DXGI_FORMAT d3d_format; 85 enum AVPixelFormat pix_fmt; 86} supported_formats[] = { 87 { DXGI_FORMAT_NV12, AV_PIX_FMT_NV12 }, 88 { DXGI_FORMAT_P010, AV_PIX_FMT_P010 }, 89 // Special opaque formats. The pix_fmt is merely a place holder, as the 90 // opaque format cannot be accessed directly. 91 { DXGI_FORMAT_420_OPAQUE, AV_PIX_FMT_YUV420P }, 92}; 93 94static void d3d11va_default_lock(void *ctx) 95{ 96 WaitForSingleObjectEx(ctx, INFINITE, FALSE); 97} 98 99static void d3d11va_default_unlock(void *ctx) 100{ 101 ReleaseMutex(ctx); 102} 103 104static void d3d11va_frames_uninit(AVHWFramesContext *ctx) 105{ 106 AVD3D11VAFramesContext *frames_hwctx = ctx->hwctx; 107 D3D11VAFramesContext *s = ctx->internal->priv; 108 109 if (frames_hwctx->texture) 110 ID3D11Texture2D_Release(frames_hwctx->texture); 111 frames_hwctx->texture = NULL; 112 113 if (s->staging_texture) 114 ID3D11Texture2D_Release(s->staging_texture); 115 s->staging_texture = NULL; 116 117 av_freep(&frames_hwctx->texture_infos); 118} 119 120static int d3d11va_frames_get_constraints(AVHWDeviceContext *ctx, 121 const void *hwconfig, 122 AVHWFramesConstraints *constraints) 123{ 124 AVD3D11VADeviceContext *device_hwctx = ctx->hwctx; 125 int nb_sw_formats = 0; 126 HRESULT hr; 127 int i; 128 129 constraints->valid_sw_formats = av_malloc_array(FF_ARRAY_ELEMS(supported_formats) + 1, 130 sizeof(*constraints->valid_sw_formats)); 131 if (!constraints->valid_sw_formats) 132 return AVERROR(ENOMEM); 133 134 for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { 135 UINT format_support = 0; 136 hr = ID3D11Device_CheckFormatSupport(device_hwctx->device, supported_formats[i].d3d_format, &format_support); 137 if (SUCCEEDED(hr) && (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D)) 138 constraints->valid_sw_formats[nb_sw_formats++] = supported_formats[i].pix_fmt; 139 } 140 constraints->valid_sw_formats[nb_sw_formats] = AV_PIX_FMT_NONE; 141 142 constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats)); 143 if (!constraints->valid_hw_formats) 144 return AVERROR(ENOMEM); 145 146 constraints->valid_hw_formats[0] = AV_PIX_FMT_D3D11; 147 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; 148 149 return 0; 150} 151 152static void free_texture(void *opaque, uint8_t *data) 153{ 154 ID3D11Texture2D_Release((ID3D11Texture2D *)opaque); 155 av_free(data); 156} 157 158static AVBufferRef *wrap_texture_buf(AVHWFramesContext *ctx, ID3D11Texture2D *tex, int index) 159{ 160 AVBufferRef *buf; 161 AVD3D11FrameDescriptor *desc = av_mallocz(sizeof(*desc)); 162 D3D11VAFramesContext *s = ctx->internal->priv; 163 AVD3D11VAFramesContext *frames_hwctx = ctx->hwctx; 164 if (!desc) { 165 ID3D11Texture2D_Release(tex); 166 return NULL; 167 } 168 169 if (s->nb_surfaces <= s->nb_surfaces_used) { 170 frames_hwctx->texture_infos = av_realloc_f(frames_hwctx->texture_infos, 171 s->nb_surfaces_used + 1, 172 sizeof(*frames_hwctx->texture_infos)); 173 if (!frames_hwctx->texture_infos) { 174 ID3D11Texture2D_Release(tex); 175 return NULL; 176 } 177 s->nb_surfaces = s->nb_surfaces_used + 1; 178 } 179 180 frames_hwctx->texture_infos[s->nb_surfaces_used].texture = tex; 181 frames_hwctx->texture_infos[s->nb_surfaces_used].index = index; 182 s->nb_surfaces_used++; 183 184 desc->texture = tex; 185 desc->index = index; 186 187 buf = av_buffer_create((uint8_t *)desc, sizeof(desc), free_texture, tex, 0); 188 if (!buf) { 189 ID3D11Texture2D_Release(tex); 190 av_free(desc); 191 return NULL; 192 } 193 194 return buf; 195} 196 197static AVBufferRef *d3d11va_alloc_single(AVHWFramesContext *ctx) 198{ 199 D3D11VAFramesContext *s = ctx->internal->priv; 200 AVD3D11VAFramesContext *hwctx = ctx->hwctx; 201 AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; 202 HRESULT hr; 203 ID3D11Texture2D *tex; 204 D3D11_TEXTURE2D_DESC texDesc = { 205 .Width = ctx->width, 206 .Height = ctx->height, 207 .MipLevels = 1, 208 .Format = s->format, 209 .SampleDesc = { .Count = 1 }, 210 .ArraySize = 1, 211 .Usage = D3D11_USAGE_DEFAULT, 212 .BindFlags = hwctx->BindFlags, 213 .MiscFlags = hwctx->MiscFlags, 214 }; 215 216 hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &tex); 217 if (FAILED(hr)) { 218 av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr); 219 return NULL; 220 } 221 222 return wrap_texture_buf(ctx, tex, 0); 223} 224 225static AVBufferRef *d3d11va_pool_alloc(void *opaque, size_t size) 226{ 227 AVHWFramesContext *ctx = (AVHWFramesContext*)opaque; 228 D3D11VAFramesContext *s = ctx->internal->priv; 229 AVD3D11VAFramesContext *hwctx = ctx->hwctx; 230 D3D11_TEXTURE2D_DESC texDesc; 231 232 if (!hwctx->texture) 233 return d3d11va_alloc_single(ctx); 234 235 ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc); 236 237 if (s->nb_surfaces_used >= texDesc.ArraySize) { 238 av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n"); 239 return NULL; 240 } 241 242 ID3D11Texture2D_AddRef(hwctx->texture); 243 return wrap_texture_buf(ctx, hwctx->texture, s->nb_surfaces_used); 244} 245 246static int d3d11va_frames_init(AVHWFramesContext *ctx) 247{ 248 AVD3D11VAFramesContext *hwctx = ctx->hwctx; 249 AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; 250 D3D11VAFramesContext *s = ctx->internal->priv; 251 252 int i; 253 HRESULT hr; 254 D3D11_TEXTURE2D_DESC texDesc; 255 256 for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { 257 if (ctx->sw_format == supported_formats[i].pix_fmt) { 258 s->format = supported_formats[i].d3d_format; 259 break; 260 } 261 } 262 if (i == FF_ARRAY_ELEMS(supported_formats)) { 263 av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n", 264 av_get_pix_fmt_name(ctx->sw_format)); 265 return AVERROR(EINVAL); 266 } 267 268 texDesc = (D3D11_TEXTURE2D_DESC){ 269 .Width = ctx->width, 270 .Height = ctx->height, 271 .MipLevels = 1, 272 .Format = s->format, 273 .SampleDesc = { .Count = 1 }, 274 .ArraySize = ctx->initial_pool_size, 275 .Usage = D3D11_USAGE_DEFAULT, 276 .BindFlags = hwctx->BindFlags, 277 .MiscFlags = hwctx->MiscFlags, 278 }; 279 280 if (hwctx->texture) { 281 D3D11_TEXTURE2D_DESC texDesc2; 282 ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc2); 283 284 if (texDesc.Width != texDesc2.Width || 285 texDesc.Height != texDesc2.Height || 286 texDesc.Format != texDesc2.Format) { 287 av_log(ctx, AV_LOG_ERROR, "User-provided texture has mismatching parameters\n"); 288 return AVERROR(EINVAL); 289 } 290 } else if (!(texDesc.BindFlags & D3D11_BIND_RENDER_TARGET) && texDesc.ArraySize > 0) { 291 hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &hwctx->texture); 292 if (FAILED(hr)) { 293 av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr); 294 return AVERROR_UNKNOWN; 295 } 296 } 297 298 hwctx->texture_infos = av_realloc_f(NULL, ctx->initial_pool_size, sizeof(*hwctx->texture_infos)); 299 if (!hwctx->texture_infos) 300 return AVERROR(ENOMEM); 301 s->nb_surfaces = ctx->initial_pool_size; 302 303 ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(AVD3D11FrameDescriptor), 304 ctx, d3d11va_pool_alloc, NULL); 305 if (!ctx->internal->pool_internal) 306 return AVERROR(ENOMEM); 307 308 return 0; 309} 310 311static int d3d11va_get_buffer(AVHWFramesContext *ctx, AVFrame *frame) 312{ 313 AVD3D11FrameDescriptor *desc; 314 315 frame->buf[0] = av_buffer_pool_get(ctx->pool); 316 if (!frame->buf[0]) 317 return AVERROR(ENOMEM); 318 319 desc = (AVD3D11FrameDescriptor *)frame->buf[0]->data; 320 321 frame->data[0] = (uint8_t *)desc->texture; 322 frame->data[1] = (uint8_t *)desc->index; 323 frame->format = AV_PIX_FMT_D3D11; 324 frame->width = ctx->width; 325 frame->height = ctx->height; 326 327 return 0; 328} 329 330static int d3d11va_transfer_get_formats(AVHWFramesContext *ctx, 331 enum AVHWFrameTransferDirection dir, 332 enum AVPixelFormat **formats) 333{ 334 D3D11VAFramesContext *s = ctx->internal->priv; 335 enum AVPixelFormat *fmts; 336 337 fmts = av_malloc_array(2, sizeof(*fmts)); 338 if (!fmts) 339 return AVERROR(ENOMEM); 340 341 fmts[0] = ctx->sw_format; 342 fmts[1] = AV_PIX_FMT_NONE; 343 344 // Don't signal support for opaque formats. Actual access would fail. 345 if (s->format == DXGI_FORMAT_420_OPAQUE) 346 fmts[0] = AV_PIX_FMT_NONE; 347 348 *formats = fmts; 349 350 return 0; 351} 352 353static int d3d11va_create_staging_texture(AVHWFramesContext *ctx, DXGI_FORMAT format) 354{ 355 AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; 356 D3D11VAFramesContext *s = ctx->internal->priv; 357 HRESULT hr; 358 D3D11_TEXTURE2D_DESC texDesc = { 359 .Width = ctx->width, 360 .Height = ctx->height, 361 .MipLevels = 1, 362 .Format = format, 363 .SampleDesc = { .Count = 1 }, 364 .ArraySize = 1, 365 .Usage = D3D11_USAGE_STAGING, 366 .CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE, 367 }; 368 369 hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &s->staging_texture); 370 if (FAILED(hr)) { 371 av_log(ctx, AV_LOG_ERROR, "Could not create the staging texture (%lx)\n", (long)hr); 372 return AVERROR_UNKNOWN; 373 } 374 375 return 0; 376} 377 378static void fill_texture_ptrs(uint8_t *data[4], int linesize[4], 379 AVHWFramesContext *ctx, 380 D3D11_TEXTURE2D_DESC *desc, 381 D3D11_MAPPED_SUBRESOURCE *map) 382{ 383 int i; 384 385 for (i = 0; i < 4; i++) 386 linesize[i] = map->RowPitch; 387 388 av_image_fill_pointers(data, ctx->sw_format, desc->Height, 389 (uint8_t*)map->pData, linesize); 390} 391 392static int d3d11va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst, 393 const AVFrame *src) 394{ 395 AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; 396 D3D11VAFramesContext *s = ctx->internal->priv; 397 int download = src->format == AV_PIX_FMT_D3D11; 398 const AVFrame *frame = download ? src : dst; 399 const AVFrame *other = download ? dst : src; 400 // (The interface types are compatible.) 401 ID3D11Resource *texture = (ID3D11Resource *)(ID3D11Texture2D *)frame->data[0]; 402 int index = (intptr_t)frame->data[1]; 403 ID3D11Resource *staging; 404 int w = FFMIN(dst->width, src->width); 405 int h = FFMIN(dst->height, src->height); 406 uint8_t *map_data[4]; 407 int map_linesize[4]; 408 D3D11_TEXTURE2D_DESC desc; 409 D3D11_MAPPED_SUBRESOURCE map; 410 HRESULT hr; 411 412 if (frame->hw_frames_ctx->data != (uint8_t *)ctx || other->format != ctx->sw_format) 413 return AVERROR(EINVAL); 414 415 device_hwctx->lock(device_hwctx->lock_ctx); 416 417 if (!s->staging_texture) { 418 ID3D11Texture2D_GetDesc((ID3D11Texture2D *)texture, &desc); 419 int res = d3d11va_create_staging_texture(ctx, desc.Format); 420 if (res < 0) 421 return res; 422 } 423 424 staging = (ID3D11Resource *)s->staging_texture; 425 426 ID3D11Texture2D_GetDesc(s->staging_texture, &desc); 427 428 if (download) { 429 ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context, 430 staging, 0, 0, 0, 0, 431 texture, index, NULL); 432 433 hr = ID3D11DeviceContext_Map(device_hwctx->device_context, 434 staging, 0, D3D11_MAP_READ, 0, &map); 435 if (FAILED(hr)) 436 goto map_failed; 437 438 fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map); 439 440 av_image_copy(dst->data, dst->linesize, (const uint8_t **)map_data, map_linesize, 441 ctx->sw_format, w, h); 442 443 ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0); 444 } else { 445 hr = ID3D11DeviceContext_Map(device_hwctx->device_context, 446 staging, 0, D3D11_MAP_WRITE, 0, &map); 447 if (FAILED(hr)) 448 goto map_failed; 449 450 fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map); 451 452 av_image_copy(map_data, map_linesize, (const uint8_t **)src->data, src->linesize, 453 ctx->sw_format, w, h); 454 455 ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0); 456 457 ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context, 458 texture, index, 0, 0, 0, 459 staging, 0, NULL); 460 } 461 462 device_hwctx->unlock(device_hwctx->lock_ctx); 463 return 0; 464 465map_failed: 466 av_log(ctx, AV_LOG_ERROR, "Unable to lock D3D11VA surface (%lx)\n", (long)hr); 467 device_hwctx->unlock(device_hwctx->lock_ctx); 468 return AVERROR_UNKNOWN; 469} 470 471static int d3d11va_device_init(AVHWDeviceContext *hwdev) 472{ 473 AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx; 474 HRESULT hr; 475 476 if (!device_hwctx->lock) { 477 device_hwctx->lock_ctx = CreateMutex(NULL, 0, NULL); 478 if (device_hwctx->lock_ctx == INVALID_HANDLE_VALUE) { 479 av_log(NULL, AV_LOG_ERROR, "Failed to create a mutex\n"); 480 return AVERROR(EINVAL); 481 } 482 device_hwctx->lock = d3d11va_default_lock; 483 device_hwctx->unlock = d3d11va_default_unlock; 484 } 485 486 if (!device_hwctx->device_context) { 487 ID3D11Device_GetImmediateContext(device_hwctx->device, &device_hwctx->device_context); 488 if (!device_hwctx->device_context) 489 return AVERROR_UNKNOWN; 490 } 491 492 if (!device_hwctx->video_device) { 493 hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device, &IID_ID3D11VideoDevice, 494 (void **)&device_hwctx->video_device); 495 if (FAILED(hr)) 496 return AVERROR_UNKNOWN; 497 } 498 499 if (!device_hwctx->video_context) { 500 hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device_context, &IID_ID3D11VideoContext, 501 (void **)&device_hwctx->video_context); 502 if (FAILED(hr)) 503 return AVERROR_UNKNOWN; 504 } 505 506 return 0; 507} 508 509static void d3d11va_device_uninit(AVHWDeviceContext *hwdev) 510{ 511 AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx; 512 513 if (device_hwctx->device) { 514 ID3D11Device_Release(device_hwctx->device); 515 device_hwctx->device = NULL; 516 } 517 518 if (device_hwctx->device_context) { 519 ID3D11DeviceContext_Release(device_hwctx->device_context); 520 device_hwctx->device_context = NULL; 521 } 522 523 if (device_hwctx->video_device) { 524 ID3D11VideoDevice_Release(device_hwctx->video_device); 525 device_hwctx->video_device = NULL; 526 } 527 528 if (device_hwctx->video_context) { 529 ID3D11VideoContext_Release(device_hwctx->video_context); 530 device_hwctx->video_context = NULL; 531 } 532 533 if (device_hwctx->lock == d3d11va_default_lock) { 534 CloseHandle(device_hwctx->lock_ctx); 535 device_hwctx->lock_ctx = INVALID_HANDLE_VALUE; 536 device_hwctx->lock = NULL; 537 } 538} 539 540static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device, 541 AVDictionary *opts, int flags) 542{ 543 AVD3D11VADeviceContext *device_hwctx = ctx->hwctx; 544 545 HRESULT hr; 546 IDXGIAdapter *pAdapter = NULL; 547 ID3D10Multithread *pMultithread; 548 UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT; 549 int is_debug = !!av_dict_get(opts, "debug", NULL, 0); 550 int ret; 551 552 // (On UWP we can't check this.) 553#if !HAVE_UWP 554 if (!LoadLibrary("d3d11_1sdklayers.dll")) 555 is_debug = 0; 556#endif 557 558 if (is_debug) 559 creationFlags |= D3D11_CREATE_DEVICE_DEBUG; 560 561 if ((ret = ff_thread_once(&functions_loaded, load_functions)) != 0) 562 return AVERROR_UNKNOWN; 563 if (!mD3D11CreateDevice || !mCreateDXGIFactory) { 564 av_log(ctx, AV_LOG_ERROR, "Failed to load D3D11 library or its functions\n"); 565 return AVERROR_UNKNOWN; 566 } 567 568 if (device) { 569 IDXGIFactory2 *pDXGIFactory; 570 hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&pDXGIFactory); 571 if (SUCCEEDED(hr)) { 572 int adapter = atoi(device); 573 if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter))) 574 pAdapter = NULL; 575 IDXGIFactory2_Release(pDXGIFactory); 576 } 577 } 578 579 if (pAdapter) { 580 DXGI_ADAPTER_DESC desc; 581 hr = IDXGIAdapter2_GetDesc(pAdapter, &desc); 582 if (!FAILED(hr)) { 583 av_log(ctx, AV_LOG_INFO, "Using device %04x:%04x (%ls).\n", 584 desc.VendorId, desc.DeviceId, desc.Description); 585 } 586 } 587 588 hr = mD3D11CreateDevice(pAdapter, pAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, NULL, creationFlags, NULL, 0, 589 D3D11_SDK_VERSION, &device_hwctx->device, NULL, NULL); 590 if (pAdapter) 591 IDXGIAdapter_Release(pAdapter); 592 if (FAILED(hr)) { 593 av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device (%lx)\n", (long)hr); 594 return AVERROR_UNKNOWN; 595 } 596 597 hr = ID3D11Device_QueryInterface(device_hwctx->device, &IID_ID3D10Multithread, (void **)&pMultithread); 598 if (SUCCEEDED(hr)) { 599 ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE); 600 ID3D10Multithread_Release(pMultithread); 601 } 602 603#if !HAVE_UWP && HAVE_DXGIDEBUG_H 604 if (is_debug) { 605 HANDLE dxgidebug_dll = LoadLibrary("dxgidebug.dll"); 606 if (dxgidebug_dll) { 607 HRESULT (WINAPI * pf_DXGIGetDebugInterface)(const GUID *riid, void **ppDebug) 608 = (void *)GetProcAddress(dxgidebug_dll, "DXGIGetDebugInterface"); 609 if (pf_DXGIGetDebugInterface) { 610 IDXGIDebug *dxgi_debug = NULL; 611 hr = pf_DXGIGetDebugInterface(&IID_IDXGIDebug, (void**)&dxgi_debug); 612 if (SUCCEEDED(hr) && dxgi_debug) 613 IDXGIDebug_ReportLiveObjects(dxgi_debug, DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL); 614 } 615 } 616 } 617#endif 618 619 return 0; 620} 621 622const HWContextType ff_hwcontext_type_d3d11va = { 623 .type = AV_HWDEVICE_TYPE_D3D11VA, 624 .name = "D3D11VA", 625 626 .device_hwctx_size = sizeof(AVD3D11VADeviceContext), 627 .frames_hwctx_size = sizeof(AVD3D11VAFramesContext), 628 .frames_priv_size = sizeof(D3D11VAFramesContext), 629 630 .device_create = d3d11va_device_create, 631 .device_init = d3d11va_device_init, 632 .device_uninit = d3d11va_device_uninit, 633 .frames_get_constraints = d3d11va_frames_get_constraints, 634 .frames_init = d3d11va_frames_init, 635 .frames_uninit = d3d11va_frames_uninit, 636 .frames_get_buffer = d3d11va_get_buffer, 637 .transfer_get_formats = d3d11va_transfer_get_formats, 638 .transfer_data_to = d3d11va_transfer_data, 639 .transfer_data_from = d3d11va_transfer_data, 640 641 .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_D3D11, AV_PIX_FMT_NONE }, 642}; 643