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 "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 
47 
49 static PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice;
50 
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, "CreateDXGIFactory1");
66  if (!mCreateDXGIFactory)
67  mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) GetProcAddress(dxgilib, "CreateDXGIFactory");
68 #else
69  // In UWP (which lacks LoadLibrary), CreateDXGIFactory isn't available,
70  // only CreateDXGIFactory1
71  mD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE) D3D11CreateDevice;
72  mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) CreateDXGIFactory1;
73 #endif
74 }
75 
76 typedef struct D3D11VAFramesContext {
77  /**
78  * The public AVD3D11VAFramesContext. See hwcontext_d3d11va.h for it.
79  */
81 
84 
85  DXGI_FORMAT format;
86 
87  ID3D11Texture2D *staging_texture;
89 
90 static const struct {
91  DXGI_FORMAT d3d_format;
93 } supported_formats[] = {
94  { DXGI_FORMAT_NV12, AV_PIX_FMT_NV12 },
95  { DXGI_FORMAT_P010, AV_PIX_FMT_P010 },
97  { DXGI_FORMAT_R10G10B10A2_UNORM, AV_PIX_FMT_X2BGR10 },
99  { DXGI_FORMAT_AYUV, AV_PIX_FMT_VUYX },
100  { DXGI_FORMAT_YUY2, AV_PIX_FMT_YUYV422 },
101  { DXGI_FORMAT_Y210, AV_PIX_FMT_Y210 },
102  { DXGI_FORMAT_Y410, AV_PIX_FMT_XV30 },
103  { DXGI_FORMAT_P016, AV_PIX_FMT_P012 },
104  { DXGI_FORMAT_Y216, AV_PIX_FMT_Y212 },
105  { DXGI_FORMAT_Y416, AV_PIX_FMT_XV36 },
106  // Special opaque formats. The pix_fmt is merely a place holder, as the
107  // opaque format cannot be accessed directly.
108  { DXGI_FORMAT_420_OPAQUE, AV_PIX_FMT_YUV420P },
109 };
110 
111 static void d3d11va_default_lock(void *ctx)
112 {
113  WaitForSingleObjectEx(ctx, INFINITE, FALSE);
114 }
115 
116 static void d3d11va_default_unlock(void *ctx)
117 {
118  ReleaseMutex(ctx);
119 }
120 
122 {
123  D3D11VAFramesContext *s = ctx->hwctx;
124  AVD3D11VAFramesContext *frames_hwctx = &s->p;
125 
126  if (frames_hwctx->texture)
127  ID3D11Texture2D_Release(frames_hwctx->texture);
128  frames_hwctx->texture = NULL;
129 
130  if (s->staging_texture)
131  ID3D11Texture2D_Release(s->staging_texture);
132  s->staging_texture = NULL;
133 
134  av_freep(&frames_hwctx->texture_infos);
135 }
136 
138  const void *hwconfig,
139  AVHWFramesConstraints *constraints)
140 {
141  AVD3D11VADeviceContext *device_hwctx = ctx->hwctx;
142  int nb_sw_formats = 0;
143  HRESULT hr;
144  int i;
145 
147  sizeof(*constraints->valid_sw_formats));
148  if (!constraints->valid_sw_formats)
149  return AVERROR(ENOMEM);
150 
151  for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
152  UINT format_support = 0;
153  hr = ID3D11Device_CheckFormatSupport(device_hwctx->device, supported_formats[i].d3d_format, &format_support);
154  if (SUCCEEDED(hr) && (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D))
155  constraints->valid_sw_formats[nb_sw_formats++] = supported_formats[i].pix_fmt;
156  }
157  constraints->valid_sw_formats[nb_sw_formats] = AV_PIX_FMT_NONE;
158 
159  constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
160  if (!constraints->valid_hw_formats)
161  return AVERROR(ENOMEM);
162 
163  constraints->valid_hw_formats[0] = AV_PIX_FMT_D3D11;
164  constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
165 
166  return 0;
167 }
168 
169 static void free_texture(void *opaque, uint8_t *data)
170 {
171  ID3D11Texture2D_Release((ID3D11Texture2D *)opaque);
172  av_free(data);
173 }
174 
175 static AVBufferRef *wrap_texture_buf(AVHWFramesContext *ctx, ID3D11Texture2D *tex, int index)
176 {
177  AVBufferRef *buf;
179  D3D11VAFramesContext *s = ctx->hwctx;
180  AVD3D11VAFramesContext *frames_hwctx = &s->p;
181  if (!desc) {
182  ID3D11Texture2D_Release(tex);
183  return NULL;
184  }
185 
186  if (s->nb_surfaces <= s->nb_surfaces_used) {
187  frames_hwctx->texture_infos = av_realloc_f(frames_hwctx->texture_infos,
188  s->nb_surfaces_used + 1,
189  sizeof(*frames_hwctx->texture_infos));
190  if (!frames_hwctx->texture_infos) {
191  ID3D11Texture2D_Release(tex);
192  return NULL;
193  }
194  s->nb_surfaces = s->nb_surfaces_used + 1;
195  }
196 
197  frames_hwctx->texture_infos[s->nb_surfaces_used].texture = tex;
198  frames_hwctx->texture_infos[s->nb_surfaces_used].index = index;
199  s->nb_surfaces_used++;
200 
201  desc->texture = tex;
202  desc->index = index;
203 
204  buf = av_buffer_create((uint8_t *)desc, sizeof(desc), free_texture, tex, 0);
205  if (!buf) {
206  ID3D11Texture2D_Release(tex);
207  av_free(desc);
208  return NULL;
209  }
210 
211  return buf;
212 }
213 
215 {
216  D3D11VAFramesContext *s = ctx->hwctx;
217  AVD3D11VAFramesContext *hwctx = &s->p;
218  AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
219  HRESULT hr;
220  ID3D11Texture2D *tex;
221  D3D11_TEXTURE2D_DESC texDesc = {
222  .Width = ctx->width,
223  .Height = ctx->height,
224  .MipLevels = 1,
225  .Format = s->format,
226  .SampleDesc = { .Count = 1 },
227  .ArraySize = 1,
228  .Usage = D3D11_USAGE_DEFAULT,
229  .BindFlags = hwctx->BindFlags,
230  .MiscFlags = hwctx->MiscFlags,
231  };
232 
233  hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &tex);
234  if (FAILED(hr)) {
235  av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr);
236  return NULL;
237  }
238 
239  return wrap_texture_buf(ctx, tex, 0);
240 }
241 
242 static AVBufferRef *d3d11va_pool_alloc(void *opaque, size_t size)
243 {
245  D3D11VAFramesContext *s = ctx->hwctx;
246  AVD3D11VAFramesContext *hwctx = &s->p;
247  D3D11_TEXTURE2D_DESC texDesc;
248 
249  if (!hwctx->texture)
250  return d3d11va_alloc_single(ctx);
251 
252  ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc);
253 
254  if (s->nb_surfaces_used >= texDesc.ArraySize) {
255  av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n");
256  return NULL;
257  }
258 
259  ID3D11Texture2D_AddRef(hwctx->texture);
260  return wrap_texture_buf(ctx, hwctx->texture, s->nb_surfaces_used);
261 }
262 
264 {
265  AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
266  D3D11VAFramesContext *s = ctx->hwctx;
267  AVD3D11VAFramesContext *hwctx = &s->p;
268 
269  int i;
270  HRESULT hr;
271  D3D11_TEXTURE2D_DESC texDesc;
272 
273  for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
274  if (ctx->sw_format == supported_formats[i].pix_fmt) {
275  s->format = supported_formats[i].d3d_format;
276  break;
277  }
278  }
280  av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n",
281  av_get_pix_fmt_name(ctx->sw_format));
282  return AVERROR(EINVAL);
283  }
284 
285  texDesc = (D3D11_TEXTURE2D_DESC){
286  .Width = ctx->width,
287  .Height = ctx->height,
288  .MipLevels = 1,
289  .Format = s->format,
290  .SampleDesc = { .Count = 1 },
291  .ArraySize = ctx->initial_pool_size,
292  .Usage = D3D11_USAGE_DEFAULT,
293  .BindFlags = hwctx->BindFlags,
294  .MiscFlags = hwctx->MiscFlags,
295  };
296 
297  if (hwctx->texture) {
298  D3D11_TEXTURE2D_DESC texDesc2;
299  ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc2);
300 
301  if (texDesc.Width != texDesc2.Width ||
302  texDesc.Height != texDesc2.Height ||
303  texDesc.Format != texDesc2.Format) {
304  av_log(ctx, AV_LOG_ERROR, "User-provided texture has mismatching parameters\n");
305  return AVERROR(EINVAL);
306  }
307 
308  ctx->initial_pool_size = texDesc2.ArraySize;
309  hwctx->BindFlags = texDesc2.BindFlags;
310  hwctx->MiscFlags = texDesc2.MiscFlags;
311  } else if (!(texDesc.BindFlags & D3D11_BIND_RENDER_TARGET) && texDesc.ArraySize > 0) {
312  hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &hwctx->texture);
313  if (FAILED(hr)) {
314  av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr);
315  return AVERROR_UNKNOWN;
316  }
317  }
318 
319  hwctx->texture_infos = av_realloc_f(NULL, ctx->initial_pool_size, sizeof(*hwctx->texture_infos));
320  if (!hwctx->texture_infos)
321  return AVERROR(ENOMEM);
322  s->nb_surfaces = ctx->initial_pool_size;
323 
327  if (!ffhwframesctx(ctx)->pool_internal)
328  return AVERROR(ENOMEM);
329 
330  return 0;
331 }
332 
334 {
336 
337  frame->buf[0] = av_buffer_pool_get(ctx->pool);
338  if (!frame->buf[0])
339  return AVERROR(ENOMEM);
340 
342 
343  frame->data[0] = (uint8_t *)desc->texture;
344  frame->data[1] = (uint8_t *)desc->index;
346  frame->width = ctx->width;
347  frame->height = ctx->height;
348 
349  return 0;
350 }
351 
354  enum AVPixelFormat **formats)
355 {
356  D3D11VAFramesContext *s = ctx->hwctx;
357  enum AVPixelFormat *fmts;
358 
359  fmts = av_malloc_array(2, sizeof(*fmts));
360  if (!fmts)
361  return AVERROR(ENOMEM);
362 
363  fmts[0] = ctx->sw_format;
364  fmts[1] = AV_PIX_FMT_NONE;
365 
366  // Don't signal support for opaque formats. Actual access would fail.
367  if (s->format == DXGI_FORMAT_420_OPAQUE)
368  fmts[0] = AV_PIX_FMT_NONE;
369 
370  *formats = fmts;
371 
372  return 0;
373 }
374 
376 {
377  AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
378  D3D11VAFramesContext *s = ctx->hwctx;
379  HRESULT hr;
380  D3D11_TEXTURE2D_DESC texDesc = {
381  .Width = ctx->width,
382  .Height = ctx->height,
383  .MipLevels = 1,
384  .Format = format,
385  .SampleDesc = { .Count = 1 },
386  .ArraySize = 1,
387  .Usage = D3D11_USAGE_STAGING,
388  .CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE,
389  };
390 
391  hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &s->staging_texture);
392  if (FAILED(hr)) {
393  av_log(ctx, AV_LOG_ERROR, "Could not create the staging texture (%lx)\n", (long)hr);
394  return AVERROR_UNKNOWN;
395  }
396 
397  return 0;
398 }
399 
400 static void fill_texture_ptrs(uint8_t *data[4], int linesize[4],
402  D3D11_TEXTURE2D_DESC *desc,
403  D3D11_MAPPED_SUBRESOURCE *map)
404 {
405  int i;
406 
407  for (i = 0; i < 4; i++)
408  linesize[i] = map->RowPitch;
409 
410  av_image_fill_pointers(data, ctx->sw_format, desc->Height,
411  (uint8_t*)map->pData, linesize);
412 }
413 
415  const AVFrame *src)
416 {
417  AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
418  D3D11VAFramesContext *s = ctx->hwctx;
419  int download = src->format == AV_PIX_FMT_D3D11;
420  const AVFrame *frame = download ? src : dst;
421  const AVFrame *other = download ? dst : src;
422  // (The interface types are compatible.)
423  ID3D11Resource *texture = (ID3D11Resource *)(ID3D11Texture2D *)frame->data[0];
424  int index = (intptr_t)frame->data[1];
425  ID3D11Resource *staging;
426  int w = FFMIN(dst->width, src->width);
427  int h = FFMIN(dst->height, src->height);
428  uint8_t *map_data[4];
429  int map_linesize[4];
430  D3D11_TEXTURE2D_DESC desc;
431  D3D11_MAPPED_SUBRESOURCE map;
432  HRESULT hr;
433  int res;
434 
435  if (frame->hw_frames_ctx->data != (uint8_t *)ctx || other->format != ctx->sw_format)
436  return AVERROR(EINVAL);
437 
438  device_hwctx->lock(device_hwctx->lock_ctx);
439 
440  if (!s->staging_texture) {
441  ID3D11Texture2D_GetDesc((ID3D11Texture2D *)texture, &desc);
442  res = d3d11va_create_staging_texture(ctx, desc.Format);
443  if (res < 0)
444  return res;
445  }
446 
447  staging = (ID3D11Resource *)s->staging_texture;
448 
449  ID3D11Texture2D_GetDesc(s->staging_texture, &desc);
450 
451  if (download) {
452  ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context,
453  staging, 0, 0, 0, 0,
454  texture, index, NULL);
455 
456  hr = ID3D11DeviceContext_Map(device_hwctx->device_context,
457  staging, 0, D3D11_MAP_READ, 0, &map);
458  if (FAILED(hr))
459  goto map_failed;
460 
461  fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map);
462 
463  av_image_copy2(dst->data, dst->linesize, map_data, map_linesize,
464  ctx->sw_format, w, h);
465 
466  ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0);
467  } else {
468  hr = ID3D11DeviceContext_Map(device_hwctx->device_context,
469  staging, 0, D3D11_MAP_WRITE, 0, &map);
470  if (FAILED(hr))
471  goto map_failed;
472 
473  fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map);
474 
475  av_image_copy2(map_data, map_linesize, src->data, src->linesize,
476  ctx->sw_format, w, h);
477 
478  ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0);
479 
480  ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context,
481  texture, index, 0, 0, 0,
482  staging, 0, NULL);
483  }
484 
485  device_hwctx->unlock(device_hwctx->lock_ctx);
486  return 0;
487 
488 map_failed:
489  av_log(ctx, AV_LOG_ERROR, "Unable to lock D3D11VA surface (%lx)\n", (long)hr);
490  device_hwctx->unlock(device_hwctx->lock_ctx);
491  return AVERROR_UNKNOWN;
492 }
493 
495 {
496  AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx;
497  HRESULT hr;
498 
499  if (!device_hwctx->lock) {
500  device_hwctx->lock_ctx = CreateMutex(NULL, 0, NULL);
501  if (device_hwctx->lock_ctx == INVALID_HANDLE_VALUE) {
502  av_log(NULL, AV_LOG_ERROR, "Failed to create a mutex\n");
503  return AVERROR(EINVAL);
504  }
505  device_hwctx->lock = d3d11va_default_lock;
506  device_hwctx->unlock = d3d11va_default_unlock;
507  }
508 
509  if (!device_hwctx->device_context) {
510  ID3D11Device_GetImmediateContext(device_hwctx->device, &device_hwctx->device_context);
511  if (!device_hwctx->device_context)
512  return AVERROR_UNKNOWN;
513  }
514 
515  if (!device_hwctx->video_device) {
516  hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device, &IID_ID3D11VideoDevice,
517  (void **)&device_hwctx->video_device);
518  if (FAILED(hr))
519  return AVERROR_UNKNOWN;
520  }
521 
522  if (!device_hwctx->video_context) {
523  hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device_context, &IID_ID3D11VideoContext,
524  (void **)&device_hwctx->video_context);
525  if (FAILED(hr))
526  return AVERROR_UNKNOWN;
527  }
528 
529  return 0;
530 }
531 
533 {
534  AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx;
535 
536  if (device_hwctx->device) {
537  ID3D11Device_Release(device_hwctx->device);
538  device_hwctx->device = NULL;
539  }
540 
541  if (device_hwctx->device_context) {
542  ID3D11DeviceContext_Release(device_hwctx->device_context);
543  device_hwctx->device_context = NULL;
544  }
545 
546  if (device_hwctx->video_device) {
547  ID3D11VideoDevice_Release(device_hwctx->video_device);
548  device_hwctx->video_device = NULL;
549  }
550 
551  if (device_hwctx->video_context) {
552  ID3D11VideoContext_Release(device_hwctx->video_context);
553  device_hwctx->video_context = NULL;
554  }
555 
556  if (device_hwctx->lock == d3d11va_default_lock) {
557  CloseHandle(device_hwctx->lock_ctx);
558  device_hwctx->lock_ctx = INVALID_HANDLE_VALUE;
559  device_hwctx->lock = NULL;
560  }
561 }
562 
563 static int d3d11va_device_find_adapter_by_vendor_id(AVHWDeviceContext *ctx, uint32_t flags, const char *vendor_id)
564 {
565  HRESULT hr;
566  IDXGIAdapter *adapter = NULL;
567  IDXGIFactory2 *factory;
568  int adapter_id = 0;
569  long int id = strtol(vendor_id, NULL, 0);
570 
571  hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&factory);
572  if (FAILED(hr)) {
573  av_log(ctx, AV_LOG_ERROR, "CreateDXGIFactory returned error\n");
574  return -1;
575  }
576 
577  while (IDXGIFactory2_EnumAdapters(factory, adapter_id++, &adapter) != DXGI_ERROR_NOT_FOUND) {
578  ID3D11Device* device = NULL;
579  DXGI_ADAPTER_DESC adapter_desc;
580 
581  hr = mD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, flags, NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL);
582  if (FAILED(hr)) {
583  av_log(ctx, AV_LOG_DEBUG, "D3D11CreateDevice returned error, try next adapter\n");
584  IDXGIAdapter_Release(adapter);
585  continue;
586  }
587 
588  hr = IDXGIAdapter2_GetDesc(adapter, &adapter_desc);
589  ID3D11Device_Release(device);
590  IDXGIAdapter_Release(adapter);
591  if (FAILED(hr)) {
592  av_log(ctx, AV_LOG_DEBUG, "IDXGIAdapter2_GetDesc returned error, try next adapter\n");
593  continue;
594  } else if (adapter_desc.VendorId == id) {
595  IDXGIFactory2_Release(factory);
596  return adapter_id - 1;
597  }
598  }
599 
600  IDXGIFactory2_Release(factory);
601  return -1;
602 }
603 
604 static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
605  AVDictionary *opts, int flags)
606 {
607  AVD3D11VADeviceContext *device_hwctx = ctx->hwctx;
608 
609  HRESULT hr;
610  IDXGIAdapter *pAdapter = NULL;
611  ID3D10Multithread *pMultithread;
612  UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
613  int is_debug = !!av_dict_get(opts, "debug", NULL, 0);
614  int ret;
615  int adapter = -1;
616 
617  if (is_debug) {
618  creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
619  av_log(ctx, AV_LOG_INFO, "Enabling d3d11 debugging.\n");
620  }
621 
623  return AVERROR_UNKNOWN;
625  av_log(ctx, AV_LOG_ERROR, "Failed to load D3D11 library or its functions\n");
626  return AVERROR_UNKNOWN;
627  }
628 
629  if (device) {
630  adapter = atoi(device);
631  } else {
632  AVDictionaryEntry *e = av_dict_get(opts, "vendor_id", NULL, 0);
633  if (e && e->value) {
634  adapter = d3d11va_device_find_adapter_by_vendor_id(ctx, creationFlags, e->value);
635  if (adapter < 0) {
636  av_log(ctx, AV_LOG_ERROR, "Failed to find d3d11va adapter by "
637  "vendor id %s\n", e->value);
638  return AVERROR_UNKNOWN;
639  }
640  }
641  }
642 
643  if (adapter >= 0) {
644  IDXGIFactory2 *pDXGIFactory;
645 
646  av_log(ctx, AV_LOG_VERBOSE, "Selecting d3d11va adapter %d\n", adapter);
647  hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&pDXGIFactory);
648  if (SUCCEEDED(hr)) {
649  if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter)))
650  pAdapter = NULL;
651  IDXGIFactory2_Release(pDXGIFactory);
652  }
653  }
654 
655  if (pAdapter) {
656  DXGI_ADAPTER_DESC desc;
657  hr = IDXGIAdapter2_GetDesc(pAdapter, &desc);
658  if (!FAILED(hr)) {
659  av_log(ctx, AV_LOG_INFO, "Using device %04x:%04x (%ls).\n",
660  desc.VendorId, desc.DeviceId, desc.Description);
661  }
662  }
663 
664  hr = mD3D11CreateDevice(pAdapter, pAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, NULL, creationFlags, NULL, 0,
665  D3D11_SDK_VERSION, &device_hwctx->device, NULL, NULL);
666  if (pAdapter)
667  IDXGIAdapter_Release(pAdapter);
668  if (FAILED(hr)) {
669  av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device (%lx)\n", (long)hr);
670  return AVERROR_UNKNOWN;
671  }
672 
673  hr = ID3D11Device_QueryInterface(device_hwctx->device, &IID_ID3D10Multithread, (void **)&pMultithread);
674  if (SUCCEEDED(hr)) {
675  ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
676  ID3D10Multithread_Release(pMultithread);
677  }
678 
679 #if !HAVE_UWP && HAVE_DXGIDEBUG_H
680  if (is_debug) {
681  HANDLE dxgidebug_dll = LoadLibrary("dxgidebug.dll");
682  if (dxgidebug_dll) {
683  HRESULT (WINAPI * pf_DXGIGetDebugInterface)(const GUID *riid, void **ppDebug)
684  = (void *)GetProcAddress(dxgidebug_dll, "DXGIGetDebugInterface");
685  if (pf_DXGIGetDebugInterface) {
686  IDXGIDebug *dxgi_debug = NULL;
687  hr = pf_DXGIGetDebugInterface(&IID_IDXGIDebug, (void**)&dxgi_debug);
688  if (SUCCEEDED(hr) && dxgi_debug) {
689  IDXGIDebug_ReportLiveObjects(dxgi_debug, DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL);
690  av_log(ctx, AV_LOG_INFO, "Enabled dxgi debugging.\n");
691  } else {
692  av_log(ctx, AV_LOG_WARNING, "Failed enabling dxgi debugging.\n");
693  }
694  } else {
695  av_log(ctx, AV_LOG_WARNING, "Failed getting dxgi debug interface.\n");
696  }
697  } else {
698  av_log(ctx, AV_LOG_WARNING, "Failed loading dxgi debug library.\n");
699  }
700  }
701 #endif
702 
703  return 0;
704 }
705 
708  .name = "D3D11VA",
709 
710  .device_hwctx_size = sizeof(AVD3D11VADeviceContext),
711  .frames_hwctx_size = sizeof(D3D11VAFramesContext),
712 
713  .device_create = d3d11va_device_create,
714  .device_init = d3d11va_device_init,
715  .device_uninit = d3d11va_device_uninit,
716  .frames_get_constraints = d3d11va_frames_get_constraints,
717  .frames_init = d3d11va_frames_init,
718  .frames_uninit = d3d11va_frames_uninit,
719  .frames_get_buffer = d3d11va_get_buffer,
720  .transfer_get_formats = d3d11va_transfer_get_formats,
721  .transfer_data_to = d3d11va_transfer_data,
722  .transfer_data_from = d3d11va_transfer_data,
723 
724  .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_D3D11, AV_PIX_FMT_NONE },
725 };
d3d11va_alloc_single
static AVBufferRef * d3d11va_alloc_single(AVHWFramesContext *ctx)
Definition: hwcontext_d3d11va.c:214
formats
formats
Definition: signature.h:48
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:186
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
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
d3d11va_transfer_get_formats
static int d3d11va_transfer_get_formats(AVHWFramesContext *ctx, enum AVHWFrameTransferDirection dir, enum AVPixelFormat **formats)
Definition: hwcontext_d3d11va.c:352
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:375
pixdesc.h
AVFrame::width
int width
Definition: frame.h:447
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
data
const char data[16]
Definition: mxf.c:148
d3d11va_transfer_data
static int d3d11va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src)
Definition: hwcontext_d3d11va.c:414
AV_PIX_FMT_XV30
#define AV_PIX_FMT_XV30
Definition: pixfmt.h:534
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
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
AVFrame::buf
AVBufferRef * buf[AV_NUM_DATA_POINTERS]
AVBuffer references backing the data for this frame.
Definition: frame.h:588
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:400
PFN_CREATE_DXGI_FACTORY
HRESULT(WINAPI * PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory)
Definition: hwcontext_d3d11va.c:44
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:396
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:706
d3d11va_get_buffer
static int d3d11va_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
Definition: hwcontext_d3d11va.c:333
d3d_format
DXGI_FORMAT d3d_format
Definition: hwcontext_d3d11va.c:91
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:375
D3D11VAFramesContext::format
DXGI_FORMAT format
Definition: hwcontext_d3d11va.c:85
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:121
d3d11va_default_unlock
static void d3d11va_default_unlock(void *ctx)
Definition: hwcontext_d3d11va.c:116
D3D11VAFramesContext::nb_surfaces_used
int nb_surfaces_used
Definition: hwcontext_d3d11va.c:83
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:137
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:532
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:180
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:51
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:384
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:604
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:46
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
ctx
AVFormatContext * ctx
Definition: movenc.c:48
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
frame
static AVFrame * frame
Definition: demux_decode.c:54
av_realloc_f
#define av_realloc_f(p, o, n)
Definition: tableprint_vlc.h:32
opts
AVDictionary * opts
Definition: movenc.c:50
D3D11VAFramesContext::nb_surfaces
int nb_surfaces
Definition: hwcontext_d3d11va.c:82
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
supported_formats
static const struct @363 supported_formats[]
NULL
#define NULL
Definition: coverity.c:32
d3d11va_default_lock
static void d3d11va_default_lock(void *ctx)
Definition: hwcontext_d3d11va.c:111
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:175
AVOnce
#define AVOnce
Definition: thread.h:202
index
int index
Definition: gxfenc.c:89
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:563
AV_PIX_FMT_X2BGR10
#define AV_PIX_FMT_X2BGR10
Definition: pixfmt.h:537
AV_PIX_FMT_P012
#define AV_PIX_FMT_P012
Definition: pixfmt.h:529
size
int size
Definition: twinvq_data.h:10344
d3d11va_frames_init
static int d3d11va_frames_init(AVHWFramesContext *ctx)
Definition: hwcontext_d3d11va.c:263
mCreateDXGIFactory
static PFN_CREATE_DXGI_FACTORY mCreateDXGIFactory
Definition: hwcontext_d3d11va.c:48
AVFrame::format
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition: frame.h:462
free_texture
static void free_texture(void *opaque, uint8_t *data)
Definition: hwcontext_d3d11va.c:169
AV_PIX_FMT_Y212
#define AV_PIX_FMT_Y212
Definition: pixfmt.h:533
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:191
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:255
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:254
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
mD3D11CreateDevice
static PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice
Definition: hwcontext_d3d11va.c:49
AVFrame::hw_frames_ctx
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame.
Definition: frame.h:726
AVFrame::height
int height
Definition: frame.h:447
d3d11va_pool_alloc
static AVBufferRef * d3d11va_pool_alloc(void *opaque, size_t size)
Definition: hwcontext_d3d11va.c:242
pix_fmt
enum AVPixelFormat pix_fmt
Definition: hwcontext_d3d11va.c:92
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:76
d3d11va_device_uninit
static void d3d11va_device_uninit(AVHWDeviceContext *hwdev)
Definition: hwcontext_d3d11va.c:532
D3D11VAFramesContext::staging_texture
ID3D11Texture2D * staging_texture
Definition: hwcontext_d3d11va.c:87
AV_PIX_FMT_P010
#define AV_PIX_FMT_P010
Definition: pixfmt.h:528
desc
const char * desc
Definition: libsvtav1.c:75
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:494
D3D11VAFramesContext::p
AVD3D11VAFramesContext p
The public AVD3D11VAFramesContext.
Definition: hwcontext_d3d11va.c:80
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:546
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
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:535
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
hwcontext.h
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:420
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:2038
AVDictionaryEntry::value
char * value
Definition: dict.h:91
AV_PIX_FMT_VUYX
@ AV_PIX_FMT_VUYX
packed VUYX 4:4:4, 32bpp, Variant of VUYA where alpha channel is left undefined
Definition: pixfmt.h:406
hwcontext_d3d11va.h
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:2882