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