FFmpeg
hwcontext_d3d11va.c
Go to the documentation of this file.
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 "mem.h"
40 #include "pixdesc.h"
41 #include "pixfmt.h"
42 #include "thread.h"
43 #include "compat/w32dlfcn.h"
44 
45 typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
46 
48 
50 static PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice;
51 
52 static av_cold void load_functions(void)
53 {
54 #if !HAVE_UWP
55  // We let these "leak" - this is fine, as unloading has no great benefit, and
56  // Windows will mark a DLL as loaded forever if its internal refcount overflows
57  // from too many LoadLibrary calls.
58  HANDLE d3dlib, dxgilib;
59 
60  d3dlib = dlopen("d3d11.dll", 0);
61  dxgilib = dlopen("dxgi.dll", 0);
62  if (!d3dlib || !dxgilib)
63  return;
64 
65  mD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE) GetProcAddress(d3dlib, "D3D11CreateDevice");
66  mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) GetProcAddress(dxgilib, "CreateDXGIFactory1");
67  if (!mCreateDXGIFactory)
68  mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) GetProcAddress(dxgilib, "CreateDXGIFactory");
69 #else
70  // In UWP (which lacks LoadLibrary), CreateDXGIFactory isn't available,
71  // only CreateDXGIFactory1
72  mD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE) D3D11CreateDevice;
73  mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) CreateDXGIFactory1;
74 #endif
75 }
76 
77 typedef struct D3D11VAFramesContext {
78  /**
79  * The public AVD3D11VAFramesContext. See hwcontext_d3d11va.h for it.
80  */
82 
85 
86  DXGI_FORMAT format;
87 
88  ID3D11Texture2D *staging_texture;
90 
91 static const struct {
92  DXGI_FORMAT d3d_format;
94 } supported_formats[] = {
95  { DXGI_FORMAT_NV12, AV_PIX_FMT_NV12 },
96  { DXGI_FORMAT_P010, AV_PIX_FMT_P010 },
98  { DXGI_FORMAT_R10G10B10A2_UNORM, AV_PIX_FMT_X2BGR10 },
100  { DXGI_FORMAT_AYUV, AV_PIX_FMT_VUYX },
101  { DXGI_FORMAT_YUY2, AV_PIX_FMT_YUYV422 },
102  { DXGI_FORMAT_Y210, AV_PIX_FMT_Y210 },
103  { DXGI_FORMAT_Y410, AV_PIX_FMT_XV30 },
104  { DXGI_FORMAT_P016, AV_PIX_FMT_P012 },
105  { DXGI_FORMAT_Y216, AV_PIX_FMT_Y216 },
106  { DXGI_FORMAT_Y416, AV_PIX_FMT_XV48 },
107  // There is no 12bit pixel format defined in DXGI_FORMAT*, use 16bit to compatible
108  // with 12 bit AV_PIX_FMT* formats.
109  { DXGI_FORMAT_Y216, AV_PIX_FMT_Y212 },
110  { DXGI_FORMAT_Y416, AV_PIX_FMT_XV36 },
111  // Special opaque formats. The pix_fmt is merely a place holder, as the
112  // opaque format cannot be accessed directly.
113  { DXGI_FORMAT_420_OPAQUE, AV_PIX_FMT_YUV420P },
114 };
115 
116 static void d3d11va_default_lock(void *ctx)
117 {
118  WaitForSingleObjectEx(ctx, INFINITE, FALSE);
119 }
120 
121 static void d3d11va_default_unlock(void *ctx)
122 {
123  ReleaseMutex(ctx);
124 }
125 
127 {
128  D3D11VAFramesContext *s = ctx->hwctx;
129  AVD3D11VAFramesContext *frames_hwctx = &s->p;
130 
131  if (frames_hwctx->texture)
132  ID3D11Texture2D_Release(frames_hwctx->texture);
133  frames_hwctx->texture = NULL;
134 
135  if (s->staging_texture)
136  ID3D11Texture2D_Release(s->staging_texture);
137  s->staging_texture = NULL;
138 
139  av_freep(&frames_hwctx->texture_infos);
140 }
141 
143  const void *hwconfig,
144  AVHWFramesConstraints *constraints)
145 {
146  AVD3D11VADeviceContext *device_hwctx = ctx->hwctx;
147  int nb_sw_formats = 0;
148  HRESULT hr;
149  int i;
150 
152  sizeof(*constraints->valid_sw_formats));
153  if (!constraints->valid_sw_formats)
154  return AVERROR(ENOMEM);
155 
156  for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
157  UINT format_support = 0;
158  hr = ID3D11Device_CheckFormatSupport(device_hwctx->device, supported_formats[i].d3d_format, &format_support);
159  if (SUCCEEDED(hr) && (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D))
160  constraints->valid_sw_formats[nb_sw_formats++] = supported_formats[i].pix_fmt;
161  }
162  constraints->valid_sw_formats[nb_sw_formats] = AV_PIX_FMT_NONE;
163 
164  constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
165  if (!constraints->valid_hw_formats)
166  return AVERROR(ENOMEM);
167 
168  constraints->valid_hw_formats[0] = AV_PIX_FMT_D3D11;
169  constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
170 
171  return 0;
172 }
173 
174 static void free_texture(void *opaque, uint8_t *data)
175 {
176  ID3D11Texture2D_Release((ID3D11Texture2D *)opaque);
177  av_free(data);
178 }
179 
180 static AVBufferRef *wrap_texture_buf(AVHWFramesContext *ctx, ID3D11Texture2D *tex, int index)
181 {
182  AVBufferRef *buf;
184  D3D11VAFramesContext *s = ctx->hwctx;
185  AVD3D11VAFramesContext *frames_hwctx = &s->p;
186  if (!desc) {
187  ID3D11Texture2D_Release(tex);
188  return NULL;
189  }
190 
191  if (s->nb_surfaces <= s->nb_surfaces_used) {
192  frames_hwctx->texture_infos = av_realloc_f(frames_hwctx->texture_infos,
193  s->nb_surfaces_used + 1,
194  sizeof(*frames_hwctx->texture_infos));
195  if (!frames_hwctx->texture_infos) {
196  ID3D11Texture2D_Release(tex);
197  av_free(desc);
198  return NULL;
199  }
200  s->nb_surfaces = s->nb_surfaces_used + 1;
201  }
202 
203  frames_hwctx->texture_infos[s->nb_surfaces_used].texture = tex;
204  frames_hwctx->texture_infos[s->nb_surfaces_used].index = index;
205  s->nb_surfaces_used++;
206 
207  desc->texture = tex;
208  desc->index = index;
209 
210  buf = av_buffer_create((uint8_t *)desc, sizeof(*desc), free_texture, tex, 0);
211  if (!buf) {
212  ID3D11Texture2D_Release(tex);
213  av_free(desc);
214  return NULL;
215  }
216 
217  return buf;
218 }
219 
221 {
222  D3D11VAFramesContext *s = ctx->hwctx;
223  AVD3D11VAFramesContext *hwctx = &s->p;
224  AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
225  HRESULT hr;
226  ID3D11Texture2D *tex;
227  D3D11_TEXTURE2D_DESC texDesc = {
228  .Width = ctx->width,
229  .Height = ctx->height,
230  .MipLevels = 1,
231  .Format = s->format,
232  .SampleDesc = { .Count = 1 },
233  .ArraySize = 1,
234  .Usage = D3D11_USAGE_DEFAULT,
235  .BindFlags = hwctx->BindFlags,
236  .MiscFlags = hwctx->MiscFlags,
237  };
238 
239  hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &tex);
240  if (FAILED(hr)) {
241  av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr);
242  return NULL;
243  }
244 
245  return wrap_texture_buf(ctx, tex, 0);
246 }
247 
248 static AVBufferRef *d3d11va_pool_alloc(void *opaque, size_t size)
249 {
251  D3D11VAFramesContext *s = ctx->hwctx;
252  AVD3D11VAFramesContext *hwctx = &s->p;
253  D3D11_TEXTURE2D_DESC texDesc;
254 
255  if (!hwctx->texture)
256  return d3d11va_alloc_single(ctx);
257 
258  ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc);
259 
260  if (s->nb_surfaces_used >= texDesc.ArraySize) {
261  av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n");
262  return NULL;
263  }
264 
265  ID3D11Texture2D_AddRef(hwctx->texture);
266  return wrap_texture_buf(ctx, hwctx->texture, s->nb_surfaces_used);
267 }
268 
270 {
271  AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
272  D3D11VAFramesContext *s = ctx->hwctx;
273  AVD3D11VAFramesContext *hwctx = &s->p;
274 
275  int i;
276  HRESULT hr;
277  D3D11_TEXTURE2D_DESC texDesc;
278 
279  for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
280  if (ctx->sw_format == supported_formats[i].pix_fmt) {
281  s->format = supported_formats[i].d3d_format;
282  break;
283  }
284  }
286  av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n",
287  av_get_pix_fmt_name(ctx->sw_format));
288  return AVERROR(EINVAL);
289  }
290 
291  texDesc = (D3D11_TEXTURE2D_DESC){
292  .Width = ctx->width,
293  .Height = ctx->height,
294  .MipLevels = 1,
295  .Format = s->format,
296  .SampleDesc = { .Count = 1 },
297  .ArraySize = ctx->initial_pool_size,
298  .Usage = D3D11_USAGE_DEFAULT,
299  .BindFlags = hwctx->BindFlags,
300  .MiscFlags = hwctx->MiscFlags,
301  };
302 
303  if (hwctx->texture) {
304  D3D11_TEXTURE2D_DESC texDesc2;
305  ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc2);
306 
307  if (texDesc.Width != texDesc2.Width ||
308  texDesc.Height != texDesc2.Height ||
309  texDesc.Format != texDesc2.Format) {
310  av_log(ctx, AV_LOG_ERROR, "User-provided texture has mismatching parameters\n");
311  return AVERROR(EINVAL);
312  }
313 
314  ctx->initial_pool_size = texDesc2.ArraySize;
315  hwctx->BindFlags = texDesc2.BindFlags;
316  hwctx->MiscFlags = texDesc2.MiscFlags;
317  } else if (!(texDesc.BindFlags & D3D11_BIND_RENDER_TARGET) && texDesc.ArraySize > 0) {
318  hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &hwctx->texture);
319  if (FAILED(hr)) {
320  av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr);
321  return AVERROR_UNKNOWN;
322  }
323  }
324 
325  hwctx->texture_infos = av_realloc_f(NULL, ctx->initial_pool_size, sizeof(*hwctx->texture_infos));
326  if (!hwctx->texture_infos)
327  return AVERROR(ENOMEM);
328  s->nb_surfaces = ctx->initial_pool_size;
329 
333  if (!ffhwframesctx(ctx)->pool_internal)
334  return AVERROR(ENOMEM);
335 
336  return 0;
337 }
338 
340 {
342 
343  frame->buf[0] = av_buffer_pool_get(ctx->pool);
344  if (!frame->buf[0])
345  return AVERROR(ENOMEM);
346 
347  desc = (AVD3D11FrameDescriptor *)frame->buf[0]->data;
348 
349  frame->data[0] = (uint8_t *)desc->texture;
350  frame->data[1] = (uint8_t *)desc->index;
351  frame->format = AV_PIX_FMT_D3D11;
352  frame->width = ctx->width;
353  frame->height = ctx->height;
354 
355  return 0;
356 }
357 
360  enum AVPixelFormat **formats)
361 {
362  D3D11VAFramesContext *s = ctx->hwctx;
363  enum AVPixelFormat *fmts;
364 
365  fmts = av_malloc_array(2, sizeof(*fmts));
366  if (!fmts)
367  return AVERROR(ENOMEM);
368 
369  fmts[0] = ctx->sw_format;
370  fmts[1] = AV_PIX_FMT_NONE;
371 
372  // Don't signal support for opaque formats. Actual access would fail.
373  if (s->format == DXGI_FORMAT_420_OPAQUE)
374  fmts[0] = AV_PIX_FMT_NONE;
375 
376  *formats = fmts;
377 
378  return 0;
379 }
380 
382 {
383  AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
384  D3D11VAFramesContext *s = ctx->hwctx;
385  HRESULT hr;
386  D3D11_TEXTURE2D_DESC texDesc = {
387  .Width = ctx->width,
388  .Height = ctx->height,
389  .MipLevels = 1,
390  .Format = format,
391  .SampleDesc = { .Count = 1 },
392  .ArraySize = 1,
393  .Usage = D3D11_USAGE_STAGING,
394  .CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE,
395  };
396 
397  hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &s->staging_texture);
398  if (FAILED(hr)) {
399  av_log(ctx, AV_LOG_ERROR, "Could not create the staging texture (%lx)\n", (long)hr);
400  return AVERROR_UNKNOWN;
401  }
402 
403  return 0;
404 }
405 
406 static void fill_texture_ptrs(uint8_t *data[4], int linesize[4],
408  D3D11_TEXTURE2D_DESC *desc,
409  D3D11_MAPPED_SUBRESOURCE *map)
410 {
411  int i;
412 
413  for (i = 0; i < 4; i++)
414  linesize[i] = map->RowPitch;
415 
416  av_image_fill_pointers(data, ctx->sw_format, desc->Height,
417  (uint8_t*)map->pData, linesize);
418 }
419 
421  const AVFrame *src)
422 {
423  AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
424  D3D11VAFramesContext *s = ctx->hwctx;
425  int download = src->format == AV_PIX_FMT_D3D11;
426  const AVFrame *frame = download ? src : dst;
427  const AVFrame *other = download ? dst : src;
428  // (The interface types are compatible.)
429  ID3D11Resource *texture = (ID3D11Resource *)(ID3D11Texture2D *)frame->data[0];
430  int index = (intptr_t)frame->data[1];
431  ID3D11Resource *staging;
432  int w = FFMIN(dst->width, src->width);
433  int h = FFMIN(dst->height, src->height);
434  uint8_t *map_data[4];
435  int map_linesize[4];
436  D3D11_TEXTURE2D_DESC desc;
437  D3D11_MAPPED_SUBRESOURCE map;
438  HRESULT hr;
439  int res;
440 
441  if (frame->hw_frames_ctx->data != (uint8_t *)ctx || other->format != ctx->sw_format)
442  return AVERROR(EINVAL);
443 
444  device_hwctx->lock(device_hwctx->lock_ctx);
445 
446  if (!s->staging_texture) {
447  ID3D11Texture2D_GetDesc((ID3D11Texture2D *)texture, &desc);
448  res = d3d11va_create_staging_texture(ctx, desc.Format);
449  if (res < 0)
450  return res;
451  }
452 
453  staging = (ID3D11Resource *)s->staging_texture;
454 
455  ID3D11Texture2D_GetDesc(s->staging_texture, &desc);
456 
457  if (download) {
458  ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context,
459  staging, 0, 0, 0, 0,
460  texture, index, NULL);
461 
462  hr = ID3D11DeviceContext_Map(device_hwctx->device_context,
463  staging, 0, D3D11_MAP_READ, 0, &map);
464  if (FAILED(hr))
465  goto map_failed;
466 
467  fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map);
468 
469  av_image_copy2(dst->data, dst->linesize, map_data, map_linesize,
470  ctx->sw_format, w, h);
471 
472  ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0);
473  } else {
474  hr = ID3D11DeviceContext_Map(device_hwctx->device_context,
475  staging, 0, D3D11_MAP_WRITE, 0, &map);
476  if (FAILED(hr))
477  goto map_failed;
478 
479  fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map);
480 
481  av_image_copy2(map_data, map_linesize, src->data, src->linesize,
482  ctx->sw_format, w, h);
483 
484  ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0);
485 
486  ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context,
487  texture, index, 0, 0, 0,
488  staging, 0, NULL);
489  }
490 
491  device_hwctx->unlock(device_hwctx->lock_ctx);
492  return 0;
493 
494 map_failed:
495  av_log(ctx, AV_LOG_ERROR, "Unable to lock D3D11VA surface (%lx)\n", (long)hr);
496  device_hwctx->unlock(device_hwctx->lock_ctx);
497  return AVERROR_UNKNOWN;
498 }
499 
501 {
502  AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx;
503  HRESULT hr;
504 
505  if (!device_hwctx->lock) {
506  device_hwctx->lock_ctx = CreateMutex(NULL, 0, NULL);
507  if (device_hwctx->lock_ctx == INVALID_HANDLE_VALUE) {
508  av_log(NULL, AV_LOG_ERROR, "Failed to create a mutex\n");
509  return AVERROR(EINVAL);
510  }
511  device_hwctx->lock = d3d11va_default_lock;
512  device_hwctx->unlock = d3d11va_default_unlock;
513  }
514 
515  if (!device_hwctx->device_context) {
516  ID3D11Device_GetImmediateContext(device_hwctx->device, &device_hwctx->device_context);
517  if (!device_hwctx->device_context)
518  return AVERROR_UNKNOWN;
519  }
520 
521  if (!device_hwctx->video_device) {
522  hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device, &IID_ID3D11VideoDevice,
523  (void **)&device_hwctx->video_device);
524  if (FAILED(hr))
525  return AVERROR_UNKNOWN;
526  }
527 
528  if (!device_hwctx->video_context) {
529  hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device_context, &IID_ID3D11VideoContext,
530  (void **)&device_hwctx->video_context);
531  if (FAILED(hr))
532  return AVERROR_UNKNOWN;
533  }
534 
535  return 0;
536 }
537 
539 {
540  AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx;
541 
542  if (device_hwctx->device) {
543  ID3D11Device_Release(device_hwctx->device);
544  device_hwctx->device = NULL;
545  }
546 
547  if (device_hwctx->device_context) {
548  ID3D11DeviceContext_Release(device_hwctx->device_context);
549  device_hwctx->device_context = NULL;
550  }
551 
552  if (device_hwctx->video_device) {
553  ID3D11VideoDevice_Release(device_hwctx->video_device);
554  device_hwctx->video_device = NULL;
555  }
556 
557  if (device_hwctx->video_context) {
558  ID3D11VideoContext_Release(device_hwctx->video_context);
559  device_hwctx->video_context = NULL;
560  }
561 
562  if (device_hwctx->lock == d3d11va_default_lock) {
563  CloseHandle(device_hwctx->lock_ctx);
564  device_hwctx->lock_ctx = INVALID_HANDLE_VALUE;
565  device_hwctx->lock = NULL;
566  }
567 }
568 
569 static int d3d11va_device_find_adapter_by_vendor_id(AVHWDeviceContext *ctx, uint32_t flags, const char *vendor_id)
570 {
571  HRESULT hr;
572  IDXGIAdapter *adapter = NULL;
573  IDXGIFactory2 *factory;
574  int adapter_id = 0;
575  long int id = strtol(vendor_id, NULL, 0);
576 
577  hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&factory);
578  if (FAILED(hr)) {
579  av_log(ctx, AV_LOG_ERROR, "CreateDXGIFactory returned error\n");
580  return -1;
581  }
582 
583  while (IDXGIFactory2_EnumAdapters(factory, adapter_id++, &adapter) != DXGI_ERROR_NOT_FOUND) {
584  ID3D11Device* device = NULL;
585  DXGI_ADAPTER_DESC adapter_desc;
586 
587  hr = mD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, flags, NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL);
588  if (FAILED(hr)) {
589  av_log(ctx, AV_LOG_DEBUG, "D3D11CreateDevice returned error, try next adapter\n");
590  IDXGIAdapter_Release(adapter);
591  continue;
592  }
593 
594  hr = IDXGIAdapter2_GetDesc(adapter, &adapter_desc);
595  ID3D11Device_Release(device);
596  IDXGIAdapter_Release(adapter);
597  if (FAILED(hr)) {
598  av_log(ctx, AV_LOG_DEBUG, "IDXGIAdapter2_GetDesc returned error, try next adapter\n");
599  continue;
600  } else if (adapter_desc.VendorId == id) {
601  IDXGIFactory2_Release(factory);
602  return adapter_id - 1;
603  }
604  }
605 
606  IDXGIFactory2_Release(factory);
607  return -1;
608 }
609 
610 static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
611  AVDictionary *opts, int flags)
612 {
613  AVD3D11VADeviceContext *device_hwctx = ctx->hwctx;
614 
615  HRESULT hr;
616  IDXGIAdapter *pAdapter = NULL;
617  ID3D10Multithread *pMultithread;
618  UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
619  int is_debug = !!av_dict_get(opts, "debug", NULL, 0);
620  int ret;
621  int adapter = -1;
622 
623  if (is_debug) {
624  creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
625  av_log(ctx, AV_LOG_INFO, "Enabling d3d11 debugging.\n");
626  }
627 
629  return AVERROR_UNKNOWN;
631  av_log(ctx, AV_LOG_ERROR, "Failed to load D3D11 library or its functions\n");
632  return AVERROR_UNKNOWN;
633  }
634 
635  if (device) {
636  adapter = atoi(device);
637  } else {
638  AVDictionaryEntry *e = av_dict_get(opts, "vendor_id", NULL, 0);
639  if (e && e->value) {
640  adapter = d3d11va_device_find_adapter_by_vendor_id(ctx, creationFlags, e->value);
641  if (adapter < 0) {
642  av_log(ctx, AV_LOG_ERROR, "Failed to find d3d11va adapter by "
643  "vendor id %s\n", e->value);
644  return AVERROR_UNKNOWN;
645  }
646  }
647  }
648 
649  if (adapter >= 0) {
650  IDXGIFactory2 *pDXGIFactory;
651 
652  av_log(ctx, AV_LOG_VERBOSE, "Selecting d3d11va adapter %d\n", adapter);
653  hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&pDXGIFactory);
654  if (SUCCEEDED(hr)) {
655  if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter)))
656  pAdapter = NULL;
657  IDXGIFactory2_Release(pDXGIFactory);
658  }
659  }
660 
661  if (pAdapter) {
662  DXGI_ADAPTER_DESC desc;
663  hr = IDXGIAdapter2_GetDesc(pAdapter, &desc);
664  if (!FAILED(hr)) {
665  av_log(ctx, AV_LOG_INFO, "Using device %04x:%04x (%ls).\n",
666  desc.VendorId, desc.DeviceId, desc.Description);
667  }
668  }
669 
670  hr = mD3D11CreateDevice(pAdapter, pAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, NULL, creationFlags, NULL, 0,
671  D3D11_SDK_VERSION, &device_hwctx->device, NULL, NULL);
672  if (pAdapter)
673  IDXGIAdapter_Release(pAdapter);
674  if (FAILED(hr)) {
675  av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device (%lx)\n", (long)hr);
676  return AVERROR_UNKNOWN;
677  }
678 
679  hr = ID3D11Device_QueryInterface(device_hwctx->device, &IID_ID3D10Multithread, (void **)&pMultithread);
680  if (SUCCEEDED(hr)) {
681  ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
682  ID3D10Multithread_Release(pMultithread);
683  }
684 
685 #if !HAVE_UWP && HAVE_DXGIDEBUG_H
686  if (is_debug) {
687  HANDLE dxgidebug_dll = LoadLibrary("dxgidebug.dll");
688  if (dxgidebug_dll) {
689  HRESULT (WINAPI * pf_DXGIGetDebugInterface)(const GUID *riid, void **ppDebug)
690  = (void *)GetProcAddress(dxgidebug_dll, "DXGIGetDebugInterface");
691  if (pf_DXGIGetDebugInterface) {
692  IDXGIDebug *dxgi_debug = NULL;
693  hr = pf_DXGIGetDebugInterface(&IID_IDXGIDebug, (void**)&dxgi_debug);
694  if (SUCCEEDED(hr) && dxgi_debug) {
695  IDXGIDebug_ReportLiveObjects(dxgi_debug, DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL);
696  av_log(ctx, AV_LOG_INFO, "Enabled dxgi debugging.\n");
697  } else {
698  av_log(ctx, AV_LOG_WARNING, "Failed enabling dxgi debugging.\n");
699  }
700  } else {
701  av_log(ctx, AV_LOG_WARNING, "Failed getting dxgi debug interface.\n");
702  }
703  } else {
704  av_log(ctx, AV_LOG_WARNING, "Failed loading dxgi debug library.\n");
705  }
706  }
707 #endif
708 
709  return 0;
710 }
711 
714  .name = "D3D11VA",
715 
716  .device_hwctx_size = sizeof(AVD3D11VADeviceContext),
717  .frames_hwctx_size = sizeof(D3D11VAFramesContext),
718 
719  .device_create = d3d11va_device_create,
720  .device_init = d3d11va_device_init,
721  .device_uninit = d3d11va_device_uninit,
722  .frames_get_constraints = d3d11va_frames_get_constraints,
723  .frames_init = d3d11va_frames_init,
724  .frames_uninit = d3d11va_frames_uninit,
725  .frames_get_buffer = d3d11va_get_buffer,
726  .transfer_get_formats = d3d11va_transfer_get_formats,
727  .transfer_data_to = d3d11va_transfer_data,
728  .transfer_data_from = d3d11va_transfer_data,
729 
730  .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_D3D11, AV_PIX_FMT_NONE },
731 };
d3d11va_alloc_single
static AVBufferRef * d3d11va_alloc_single(AVHWFramesContext *ctx)
Definition: hwcontext_d3d11va.c:220
formats
formats
Definition: signature.h:47
AVHWDeviceContext::hwctx
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:85
FFHWFramesContext::pool_internal
AVBufferPool * pool_internal
Definition: hwcontext_internal.h:101
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:215
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
DXGI_FORMAT_B8G8R8A8_UNORM
@ DXGI_FORMAT_B8G8R8A8_UNORM
Definition: dds.c:91
thread.h
d3d11va_transfer_get_formats
static int d3d11va_transfer_get_formats(AVHWFramesContext *ctx, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats)
Definition: hwcontext_d3d11va.c:358
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:389
pixdesc.h
AVD3D11VAFramesContext::MiscFlags
UINT MiscFlags
D3D11_TEXTURE2D_DESC.MiscFlags used for texture creation.
Definition: hwcontext_d3d11va.h:166
w
uint8_t w
Definition: llviddspenc.c:38
AV_PIX_FMT_Y216
#define AV_PIX_FMT_Y216
Definition: pixfmt.h:558
data
const char data[16]
Definition: mxf.c:149
d3d11va_transfer_data
static int d3d11va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src)
Definition: hwcontext_d3d11va.c:420
supported_formats
static const struct @441 supported_formats[]
AV_PIX_FMT_XV30
#define AV_PIX_FMT_XV30
Definition: pixfmt.h:559
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:225
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:102
AVDictionary
Definition: dict.c:34
AVHWFramesConstraints::valid_hw_formats
enum AVPixelFormat * valid_hw_formats
A list of possible values for format in the hw_frames_ctx, terminated by AV_PIX_FMT_NONE.
Definition: hwcontext.h:446
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:73
fill_texture_ptrs
static void fill_texture_ptrs(uint8_t *data[4], int linesize[4], AVHWFramesContext *ctx, D3D11_TEXTURE2D_DESC *desc, D3D11_MAPPED_SUBRESOURCE *map)
Definition: hwcontext_d3d11va.c:406
PFN_CREATE_DXGI_FACTORY
HRESULT(WINAPI * PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory)
Definition: hwcontext_d3d11va.c:45
AVHWFramesConstraints
This struct describes the constraints on hardware frames attached to a given device with a hardware-s...
Definition: hwcontext.h:441
AVD3D11VAFramesContext::BindFlags
UINT BindFlags
D3D11_TEXTURE2D_DESC.BindFlags used for texture creation.
Definition: hwcontext_d3d11va.h:160
ff_hwcontext_type_d3d11va
const HWContextType ff_hwcontext_type_d3d11va
Definition: hwcontext_d3d11va.c:712
d3d11va_get_buffer
static int d3d11va_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
Definition: hwcontext_d3d11va.c:339
d3d_format
DXGI_FORMAT d3d_format
Definition: hwcontext_d3d11va.c:92
AVD3D11FrameDescriptor::texture
ID3D11Texture2D * texture
The texture in which the frame is located.
Definition: hwcontext_d3d11va.h:117
d3d11va_create_staging_texture
static int d3d11va_create_staging_texture(AVHWFramesContext *ctx, DXGI_FORMAT format)
Definition: hwcontext_d3d11va.c:381
D3D11VAFramesContext::format
DXGI_FORMAT format
Definition: hwcontext_d3d11va.c:86
AV_HWDEVICE_TYPE_D3D11VA
@ AV_HWDEVICE_TYPE_D3D11VA
Definition: hwcontext.h:35
av_buffer_pool_init2
AVBufferPool * av_buffer_pool_init2(size_t size, void *opaque, AVBufferRef *(*alloc)(void *opaque, size_t size), void(*pool_free)(void *opaque))
Allocate and initialize a buffer pool with a more complex allocator.
Definition: buffer.c:259
d3d11va_frames_uninit
static void d3d11va_frames_uninit(AVHWFramesContext *ctx)
Definition: hwcontext_d3d11va.c:126
d3d11va_default_unlock
static void d3d11va_default_unlock(void *ctx)
Definition: hwcontext_d3d11va.c:121
D3D11VAFramesContext::nb_surfaces_used
int nb_surfaces_used
Definition: hwcontext_d3d11va.c:84
AV_PIX_FMT_XV48
#define AV_PIX_FMT_XV48
Definition: pixfmt.h:561
av_image_fill_pointers
int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int height, uint8_t *ptr, const int linesizes[4])
Fill plane data pointers for an image with pixel format pix_fmt and height height.
Definition: imgutils.c:145
d3d11va_frames_get_constraints
static int d3d11va_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints)
Definition: hwcontext_d3d11va.c:142
AVHWDeviceContext
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:60
AV_PIX_FMT_Y210
#define AV_PIX_FMT_Y210
Definition: pixfmt.h:556
avassert.h
HWContextType::type
enum AVHWDeviceType type
Definition: hwcontext_internal.h:30
ffhwframesctx
static FFHWFramesContext * ffhwframesctx(AVHWFramesContext *ctx)
Definition: hwcontext_internal.h:115
ff_thread_once
static int ff_thread_once(char *control, void(*routine)(void))
Definition: thread.h:205
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
av_cold
#define av_cold
Definition: attributes.h:90
load_functions
static av_cold void load_functions(void)
Definition: hwcontext_d3d11va.c:52
AVHWFramesConstraints::valid_sw_formats
enum AVPixelFormat * valid_sw_formats
A list of possible values for sw_format in the hw_frames_ctx, terminated by AV_PIX_FMT_NONE.
Definition: hwcontext.h:453
av_dict_get
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:62
av_buffer_pool_get
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:390
AVD3D11VADeviceContext::video_context
ID3D11VideoContext * video_context
If unset, this will be set from the device_context field on init.
Definition: hwcontext_d3d11va.h:80
s
#define s(width, name)
Definition: cbs_vp9.c:198
AVD3D11VADeviceContext::device
ID3D11Device * device
Device used for texture creation and access.
Definition: hwcontext_d3d11va.h:56
d3d11va_device_create
static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device, AVDictionary *opts, int flags)
Definition: hwcontext_d3d11va.c:610
format
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample format(the sample packing is implied by the sample format) and sample rate. The lists are not just lists
functions_loaded
static AVOnce functions_loaded
Definition: hwcontext_d3d11va.c:47
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:230
ctx
AVFormatContext * ctx
Definition: movenc.c:49
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:73
av_realloc_f
#define av_realloc_f(p, o, n)
Definition: tableprint_vlc.h:32
opts
AVDictionary * opts
Definition: movenc.c:51
D3D11VAFramesContext::nb_surfaces
int nb_surfaces
Definition: hwcontext_d3d11va.c:83
AV_ONCE_INIT
#define AV_ONCE_INIT
Definition: thread.h:203
AVD3D11VAFramesContext::texture_infos
AVD3D11FrameDescriptor * texture_infos
In case if texture structure member above is not NULL contains the same texture pointer for all eleme...
Definition: hwcontext_d3d11va.h:175
AVD3D11VADeviceContext::lock_ctx
void * lock_ctx
Definition: hwcontext_d3d11va.h:96
NULL
#define NULL
Definition: coverity.c:32
d3d11va_default_lock
static void d3d11va_default_lock(void *ctx)
Definition: hwcontext_d3d11va.c:116
AVD3D11VADeviceContext::video_device
ID3D11VideoDevice * video_device
If unset, this will be set from the device field on init.
Definition: hwcontext_d3d11va.h:72
AV_PIX_FMT_YUYV422
@ AV_PIX_FMT_YUYV422
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
Definition: pixfmt.h:74
wrap_texture_buf
static AVBufferRef * wrap_texture_buf(AVHWFramesContext *ctx, ID3D11Texture2D *tex, int index)
Definition: hwcontext_d3d11va.c:180
AVOnce
#define AVOnce
Definition: thread.h:202
index
int index
Definition: gxfenc.c:90
AVD3D11VADeviceContext::unlock
void(* unlock)(void *lock_ctx)
Definition: hwcontext_d3d11va.h:95
AVD3D11VAFramesContext
This struct is allocated as AVHWFramesContext.hwctx.
Definition: hwcontext_d3d11va.h:131
av_buffer_create
AVBufferRef * av_buffer_create(uint8_t *data, size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:55
d3d11va_device_find_adapter_by_vendor_id
static int d3d11va_device_find_adapter_by_vendor_id(AVHWDeviceContext *ctx, uint32_t flags, const char *vendor_id)
Definition: hwcontext_d3d11va.c:569
AV_PIX_FMT_X2BGR10
#define AV_PIX_FMT_X2BGR10
Definition: pixfmt.h:564
AV_PIX_FMT_P012
#define AV_PIX_FMT_P012
Definition: pixfmt.h:553
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:83
size
int size
Definition: twinvq_data.h:10344
d3d11va_frames_init
static int d3d11va_frames_init(AVHWFramesContext *ctx)
Definition: hwcontext_d3d11va.c:269
mCreateDXGIFactory
static PFN_CREATE_DXGI_FACTORY mCreateDXGIFactory
Definition: hwcontext_d3d11va.c:49
AVFrame::format
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition: frame.h:476
free_texture
static void free_texture(void *opaque, uint8_t *data)
Definition: hwcontext_d3d11va.c:174
AV_PIX_FMT_Y212
#define AV_PIX_FMT_Y212
Definition: pixfmt.h:557
AVD3D11VAFramesContext::texture
ID3D11Texture2D * texture
The canonical texture used for pool allocation.
Definition: hwcontext_d3d11va.h:152
AV_PIX_FMT_D3D11
@ AV_PIX_FMT_D3D11
Hardware surfaces for Direct3D11.
Definition: pixfmt.h:336
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:220
DXGI_FORMAT_R16G16B16A16_FLOAT
@ DXGI_FORMAT_R16G16B16A16_FLOAT
Definition: dds.c:62
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:31
common.h
AVD3D11VADeviceContext
This struct is allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_d3d11va.h:45
AVD3D11FrameDescriptor::index
intptr_t index
The index into the array texture element representing the frame, or 0 if the texture is not an array ...
Definition: hwcontext_d3d11va.h:125
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:256
AVD3D11VADeviceContext::lock
void(* lock)(void *lock_ctx)
Callbacks for locking.
Definition: hwcontext_d3d11va.h:94
AVHWFrameTransferDirection
AVHWFrameTransferDirection
Definition: hwcontext.h:403
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:115
ret
ret
Definition: filter_design.txt:187
pixfmt.h
AV_PIX_FMT_NV12
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:96
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
mD3D11CreateDevice
static PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice
Definition: hwcontext_d3d11va.c:50
d3d11va_pool_alloc
static AVBufferRef * d3d11va_pool_alloc(void *opaque, size_t size)
Definition: hwcontext_d3d11va.c:248
pix_fmt
enum AVPixelFormat pix_fmt
Definition: hwcontext_d3d11va.c:93
av_image_copy2
static void av_image_copy2(uint8_t *const dst_data[4], const int dst_linesizes[4], uint8_t *const src_data[4], const int src_linesizes[4], enum AVPixelFormat pix_fmt, int width, int height)
Wrapper around av_image_copy() to workaround the limitation that the conversion from uint8_t * const ...
Definition: imgutils.h:184
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
D3D11VAFramesContext
Definition: hwcontext_d3d11va.c:77
d3d11va_device_uninit
static void d3d11va_device_uninit(AVHWDeviceContext *hwdev)
Definition: hwcontext_d3d11va.c:538
D3D11VAFramesContext::staging_texture
ID3D11Texture2D * staging_texture
Definition: hwcontext_d3d11va.c:88
AV_PIX_FMT_P010
#define AV_PIX_FMT_P010
Definition: pixfmt.h:552
desc
const char * desc
Definition: libsvtav1.c:79
mem.h
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
d3d11va_device_init
static int d3d11va_device_init(AVHWDeviceContext *hwdev)
Definition: hwcontext_d3d11va.c:500
D3D11VAFramesContext::p
AVD3D11VAFramesContext p
The public AVD3D11VAFramesContext.
Definition: hwcontext_d3d11va.c:81
hwcontext_internal.h
map
const VDPAUPixFmtMap * map
Definition: hwcontext_vdpau.c:71
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
AVDictionaryEntry
Definition: dict.h:89
AV_PIX_FMT_RGBAF16
#define AV_PIX_FMT_RGBAF16
Definition: pixfmt.h:574
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
AVD3D11FrameDescriptor
D3D11 frame descriptor for pool allocation.
Definition: hwcontext_d3d11va.h:109
imgutils.h
AV_PIX_FMT_XV36
#define AV_PIX_FMT_XV36
Definition: pixfmt.h:560
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:482
hwcontext.h
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
HWContextType
Definition: hwcontext_internal.h:29
AVD3D11VADeviceContext::device_context
ID3D11DeviceContext * device_context
If unset, this will be set from the device field on init.
Definition: hwcontext_d3d11va.h:64
ID3D11Device
void ID3D11Device
Definition: nvenc.h:28
h
h
Definition: vp9dsp_template.c:2070
AVDictionaryEntry::value
char * value
Definition: dict.h:91
AV_PIX_FMT_VUYX
@ AV_PIX_FMT_VUYX
packed VUYX 4:4:4:4, 32bpp, Variant of VUYA where alpha channel is left undefined
Definition: pixfmt.h:406
hwcontext_d3d11va.h
src
#define src
Definition: vp8dsp.c:248
w32dlfcn.h
av_get_pix_fmt_name
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition: pixdesc.c:3090