• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
44 typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
45 
46 static AVOnce functions_loaded = AV_ONCE_INIT;
47 
48 static PFN_CREATE_DXGI_FACTORY mCreateDXGIFactory;
49 static PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice;
50 
load_functions(void)51 static 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 
74 typedef struct D3D11VAFramesContext {
75     int nb_surfaces;
76     int nb_surfaces_used;
77 
78     DXGI_FORMAT format;
79 
80     ID3D11Texture2D *staging_texture;
81 } D3D11VAFramesContext;
82 
83 static 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 
d3d11va_default_lock(void * ctx)94 static void d3d11va_default_lock(void *ctx)
95 {
96     WaitForSingleObjectEx(ctx, INFINITE, FALSE);
97 }
98 
d3d11va_default_unlock(void * ctx)99 static void d3d11va_default_unlock(void *ctx)
100 {
101     ReleaseMutex(ctx);
102 }
103 
d3d11va_frames_uninit(AVHWFramesContext * ctx)104 static 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 
d3d11va_frames_get_constraints(AVHWDeviceContext * ctx,const void * hwconfig,AVHWFramesConstraints * constraints)120 static 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 
free_texture(void * opaque,uint8_t * data)152 static void free_texture(void *opaque, uint8_t *data)
153 {
154     ID3D11Texture2D_Release((ID3D11Texture2D *)opaque);
155     av_free(data);
156 }
157 
wrap_texture_buf(AVHWFramesContext * ctx,ID3D11Texture2D * tex,int index)158 static 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 
d3d11va_alloc_single(AVHWFramesContext * ctx)197 static 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 
d3d11va_pool_alloc(void * opaque,size_t size)225 static 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 
d3d11va_frames_init(AVHWFramesContext * ctx)246 static 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 
d3d11va_get_buffer(AVHWFramesContext * ctx,AVFrame * frame)311 static 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 
d3d11va_transfer_get_formats(AVHWFramesContext * ctx,enum AVHWFrameTransferDirection dir,enum AVPixelFormat ** formats)330 static 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 
d3d11va_create_staging_texture(AVHWFramesContext * ctx,DXGI_FORMAT format)353 static 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 
fill_texture_ptrs(uint8_t * data[4],int linesize[4],AVHWFramesContext * ctx,D3D11_TEXTURE2D_DESC * desc,D3D11_MAPPED_SUBRESOURCE * map)378 static 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 
d3d11va_transfer_data(AVHWFramesContext * ctx,AVFrame * dst,const AVFrame * src)392 static 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 
465 map_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 
d3d11va_device_init(AVHWDeviceContext * hwdev)471 static 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 
d3d11va_device_uninit(AVHWDeviceContext * hwdev)509 static 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 
d3d11va_device_create(AVHWDeviceContext * ctx,const char * device,AVDictionary * opts,int flags)540 static 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 
622 const 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