History

lavu: add new D3D11 pixfmt and hwcontext

To be used with the new d3d11 hwaccel decode API. With the new hwaccel API, we don't want surfaces to depend on the decoder (other than the required dimension and format). The old D3D11VA pixfmt uses ID3D11VideoDecoderOutputView pointers, which include the decoder configuration, and thus is incompatible with the new hwaccel API. This patch introduces AV_PIX_FMT_D3D11, which uses ID3D11Texture2D and an index. It's simpler and compatible with the new hwaccel API. The introduced hwcontext supports only the new pixfmt. Frame upload code untested. Significantly based on work by Steve Lhomme <robux4@gmail.com>, but with heavy changes/rewrites. Merges Libav commit fff90422d181744cd75dbf011687ee7095f02875.

wm4 committed 9 years ago

Commit 33035111 parent 4d62ee610 files · +680 −2Browse files

Unified · Split

10 files
  1. doc/APIchanges +3 −0
  2. libavutil/Makefile +3 −0
  3. libavutil/hwcontext.c +4 −0
  4. libavutil/hwcontext.h +1 −0
  5. libavutil/hwcontext_d3d11va.c +490 −0
  6. libavutil/hwcontext_d3d11va.h +160 −0
  7. libavutil/hwcontext_internal.h +1 −0
  8. libavutil/pixdesc.c +4 −0
  9. libavutil/pixfmt.h +13 −1
  10. libavutil/version.h +1 −1
doc/APIchanges+3−0
@@ -15,6 +15,9 @@ libavutil: 2015-08-28 · 14 unmodified lines
1515
1616 API changes, most recent first:
1717
18+2017-xx-xx - xxxxxxx - lavu 56.67.100 - hwcontext.h
19+ Add AV_HWDEVICE_TYPE_D3D11VA and AV_PIX_FMT_D3D11.
20+
1821 2017-06-24 - xxxxxxx - lavf 57.75.100 - avio.h
1922 Add AVIO_DATA_MARKER_FLUSH_POINT to signal preferred flush points to aviobuf.
2023
libavutil/Makefile+3−0
@@ -33,6 +33,7 @@ HEADERS = adler32.h \ · 32 unmodified lines
3333 hmac.h \
3434 hwcontext.h \
3535 hwcontext_cuda.h \
36+ hwcontext_d3d11va.h \
3637 hwcontext_dxva2.h \
3738 hwcontext_qsv.h \
3839 hwcontext_vaapi.h \
@@ -156,6 +157,7 @@ OBJS = adler32.o \ · 117 unmodified lines
156157 OBJS-$(!HAVE_ATOMICS_NATIVE) += atomic.o \
157158
158159 OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o
160+OBJS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.o
159161 OBJS-$(CONFIG_DXVA2) += hwcontext_dxva2.o
160162 OBJS-$(CONFIG_QSV) += hwcontext_qsv.o
161163 OBJS-$(CONFIG_LZO) += lzo.o
@@ -171,6 +173,7 @@ SLIBOBJS-$(HAVE_GNU_WINDRES) += avutilres.o · 9 unmodified lines
171173
172174 SKIPHEADERS-$(HAVE_CUDA_H) += hwcontext_cuda.h
173175 SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda_internal.h
176+SKIPHEADERS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.h
174177 SKIPHEADERS-$(CONFIG_DXVA2) += hwcontext_dxva2.h
175178 SKIPHEADERS-$(CONFIG_QSV) += hwcontext_qsv.h
176179 SKIPHEADERS-$(CONFIG_VAAPI) += hwcontext_vaapi.h
libavutil/hwcontext.c+4−0
@@ -32,6 +32,9 @@ static const HWContextType *const hw_table[] = { · 31 unmodified lines
3232 #if CONFIG_CUDA
3333 &ff_hwcontext_type_cuda,
3434 #endif
35+#if CONFIG_D3D11VA
36+ &ff_hwcontext_type_d3d11va,
37+#endif
3538 #if CONFIG_DXVA2
3639 &ff_hwcontext_type_dxva2,
3740 #endif
@@ -53,6 +56,7 @@ static const HWContextType *const hw_table[] = { · 15 unmodified lines
5356 static const char *const hw_type_names[] = {
5457 [AV_HWDEVICE_TYPE_CUDA] = "cuda",
5558 [AV_HWDEVICE_TYPE_DXVA2] = "dxva2",
59+ [AV_HWDEVICE_TYPE_D3D11VA] = "d3d11va",
5660 [AV_HWDEVICE_TYPE_QSV] = "qsv",
5761 [AV_HWDEVICE_TYPE_VAAPI] = "vaapi",
5862 [AV_HWDEVICE_TYPE_VDPAU] = "vdpau",
libavutil/hwcontext.h+1−0
@@ -32,6 +32,7 @@ enum AVHWDeviceType { · 31 unmodified lines
3232 AV_HWDEVICE_TYPE_QSV,
3333 AV_HWDEVICE_TYPE_VIDEOTOOLBOX,
3434 AV_HWDEVICE_TYPE_NONE,
35+ AV_HWDEVICE_TYPE_D3D11VA,
3536 };
3637
3738 typedef struct AVHWDeviceInternal AVHWDeviceInternal;
libavutil/hwcontext_d3d11va.c+490−0
@@ -0,0 +1,490 @@
1+/*
2+ * This file is part of Libav.
3+ *
4+ * Libav 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+ * Libav 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 Libav; if not, write to the Free Software
16+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+ */
18+
19+#include <windows.h>
20+
21+#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600
22+#undef _WIN32_WINNT
23+#define _WIN32_WINNT 0x0600
24+#endif
25+#define COBJMACROS
26+
27+#include <initguid.h>
28+#include <d3d11.h>
29+#include <dxgi1_2.h>
30+
31+#include "avassert.h"
32+#include "common.h"
33+#include "hwcontext.h"
34+#include "hwcontext_d3d11va.h"
35+#include "hwcontext_internal.h"
36+#include "imgutils.h"
37+#include "pixdesc.h"
38+#include "pixfmt.h"
39+
40+typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
41+
42+typedef struct D3D11VAFramesContext {
43+ int nb_surfaces_used;
44+
45+ DXGI_FORMAT format;
46+
47+ ID3D11Texture2D *staging_texture;
48+} D3D11VAFramesContext;
49+
50+static const struct {
51+ DXGI_FORMAT d3d_format;
52+ enum AVPixelFormat pix_fmt;
53+} supported_formats[] = {
54+ { DXGI_FORMAT_NV12, AV_PIX_FMT_NV12 },
55+ { DXGI_FORMAT_P010, AV_PIX_FMT_P010 },
56+};
57+
58+static void d3d11va_default_lock(void *ctx)
59+{
60+ WaitForSingleObjectEx(ctx, INFINITE, FALSE);
61+}
62+
63+static void d3d11va_default_unlock(void *ctx)
64+{
65+ ReleaseMutex(ctx);
66+}
67+
68+static void d3d11va_frames_uninit(AVHWFramesContext *ctx)
69+{
70+ AVD3D11VAFramesContext *frames_hwctx = ctx->hwctx;
71+ D3D11VAFramesContext *s = ctx->internal->priv;
72+
73+ if (frames_hwctx->texture)
74+ ID3D11Texture2D_Release(frames_hwctx->texture);
75+
76+ if (s->staging_texture)
77+ ID3D11Texture2D_Release(s->staging_texture);
78+}
79+
80+static void free_texture(void *opaque, uint8_t *data)
81+{
82+ ID3D11Texture2D_Release((ID3D11Texture2D *)opaque);
83+}
84+
85+static AVBufferRef *wrap_texture_buf(ID3D11Texture2D *tex, int index)
86+{
87+ AVBufferRef *buf;
88+ AVD3D11FrameDescriptor *desc = av_mallocz(sizeof(*desc));
89+ if (!desc) {
90+ ID3D11Texture2D_Release(tex);
91+ return NULL;
92+ }
93+
94+ desc->texture = tex;
95+ desc->index = index;
96+
97+ buf = av_buffer_create((uint8_t *)desc, sizeof(desc), free_texture, tex, 0);
98+ if (!buf) {
99+ ID3D11Texture2D_Release(tex);
100+ av_free(desc);
101+ return NULL;
102+ }
103+
104+ return buf;
105+}
106+
107+static AVBufferRef *d3d11va_alloc_single(AVHWFramesContext *ctx)
108+{
109+ D3D11VAFramesContext *s = ctx->internal->priv;
110+ AVD3D11VAFramesContext *hwctx = ctx->hwctx;
111+ AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
112+ HRESULT hr;
113+ ID3D11Texture2D *tex;
114+ D3D11_TEXTURE2D_DESC texDesc = {
115+ .Width = ctx->width,
116+ .Height = ctx->height,
117+ .MipLevels = 1,
118+ .Format = s->format,
119+ .SampleDesc = { .Count = 1 },
120+ .ArraySize = 1,
121+ .Usage = D3D11_USAGE_DEFAULT,
122+ .BindFlags = hwctx->BindFlags,
123+ .MiscFlags = hwctx->MiscFlags,
124+ };
125+
126+ hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &tex);
127+ if (FAILED(hr)) {
128+ av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr);
129+ return NULL;
130+ }
131+
132+ return wrap_texture_buf(tex, 0);
133+}
134+
135+static AVBufferRef *d3d11va_pool_alloc(void *opaque, int size)
136+{
137+ AVHWFramesContext *ctx = (AVHWFramesContext*)opaque;
138+ D3D11VAFramesContext *s = ctx->internal->priv;
139+ AVD3D11VAFramesContext *hwctx = ctx->hwctx;
140+ D3D11_TEXTURE2D_DESC texDesc;
141+
142+ if (!hwctx->texture)
143+ return d3d11va_alloc_single(ctx);
144+
145+ ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc);
146+
147+ if (s->nb_surfaces_used >= texDesc.ArraySize) {
148+ av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n");
149+ return NULL;
150+ }
151+
152+ ID3D11Texture2D_AddRef(hwctx->texture);
153+ return wrap_texture_buf(hwctx->texture, s->nb_surfaces_used++);
154+}
155+
156+static int d3d11va_frames_init(AVHWFramesContext *ctx)
157+{
158+ AVD3D11VAFramesContext *hwctx = ctx->hwctx;
159+ AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
160+ D3D11VAFramesContext *s = ctx->internal->priv;
161+
162+ int i;
163+ HRESULT hr;
164+ D3D11_TEXTURE2D_DESC texDesc;
165+
166+ for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
167+ if (ctx->sw_format == supported_formats[i].pix_fmt) {
168+ s->format = supported_formats[i].d3d_format;
169+ break;
170+ }
171+ }
172+ if (i == FF_ARRAY_ELEMS(supported_formats)) {
173+ av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n",
174+ av_get_pix_fmt_name(ctx->sw_format));
175+ return AVERROR(EINVAL);
176+ }
177+
178+ texDesc = (D3D11_TEXTURE2D_DESC){
179+ .Width = ctx->width,
180+ .Height = ctx->height,
181+ .MipLevels = 1,
182+ .Format = s->format,
183+ .SampleDesc = { .Count = 1 },
184+ .ArraySize = ctx->initial_pool_size,
185+ .Usage = D3D11_USAGE_DEFAULT,
186+ .BindFlags = hwctx->BindFlags,
187+ .MiscFlags = hwctx->MiscFlags,
188+ };
189+
190+ if (hwctx->texture) {
191+ D3D11_TEXTURE2D_DESC texDesc2;
192+ ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc2);
193+
194+ if (texDesc.Width != texDesc2.Width ||
195+ texDesc.Height != texDesc2.Height ||
196+ texDesc.Format != texDesc2.Format) {
197+ av_log(ctx, AV_LOG_ERROR, "User-provided texture has mismatching parameters\n");
198+ return AVERROR(EINVAL);
199+ }
200+ } else if (texDesc.ArraySize > 0) {
201+ hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &hwctx->texture);
202+ if (FAILED(hr)) {
203+ av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr);
204+ return AVERROR_UNKNOWN;
205+ }
206+ }
207+
208+ texDesc.ArraySize = 1;
209+ texDesc.Usage = D3D11_USAGE_STAGING;
210+ texDesc.BindFlags = 0;
211+ texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
212+ texDesc.MiscFlags = 0;
213+ hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &s->staging_texture);
214+ if (FAILED(hr)) {
215+ av_log(ctx, AV_LOG_ERROR, "Could not create the staging texture (%lx)\n", (long)hr);
216+ return AVERROR_UNKNOWN;
217+ }
218+
219+ ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(AVD3D11FrameDescriptor),
220+ ctx, d3d11va_pool_alloc, NULL);
221+ if (!ctx->internal->pool_internal)
222+ return AVERROR(ENOMEM);
223+
224+ return 0;
225+}
226+
227+static int d3d11va_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
228+{
229+ AVD3D11FrameDescriptor *desc;
230+
231+ frame->buf[0] = av_buffer_pool_get(ctx->pool);
232+ if (!frame->buf[0])
233+ return AVERROR(ENOMEM);
234+
235+ desc = (AVD3D11FrameDescriptor *)frame->buf[0]->data;
236+
237+ frame->data[0] = (uint8_t *)desc->texture;
238+ frame->data[1] = (uint8_t *)desc->index;
239+ frame->format = AV_PIX_FMT_D3D11;
240+ frame->width = ctx->width;
241+ frame->height = ctx->height;
242+
243+ return 0;
244+}
245+
246+static int d3d11va_transfer_get_formats(AVHWFramesContext *ctx,
247+ enum AVHWFrameTransferDirection dir,
248+ enum AVPixelFormat **formats)
249+{
250+ enum AVPixelFormat *fmts;
251+
252+ fmts = av_malloc_array(2, sizeof(*fmts));
253+ if (!fmts)
254+ return AVERROR(ENOMEM);
255+
256+ fmts[0] = ctx->sw_format;
257+ fmts[1] = AV_PIX_FMT_NONE;
258+
259+ *formats = fmts;
260+
261+ return 0;
262+}
263+
264+static void fill_texture_ptrs(uint8_t *data[4], int linesize[4],
265+ AVHWFramesContext *ctx,
266+ D3D11_TEXTURE2D_DESC *desc,
267+ D3D11_MAPPED_SUBRESOURCE *map)
268+{
269+ int i;
270+
271+ for (i = 0; i < 4; i++)
272+ linesize[i] = map->RowPitch;
273+
274+ av_image_fill_pointers(data, ctx->sw_format, desc->Height,
275+ (uint8_t*)map->pData, linesize);
276+}
277+
278+static int d3d11va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst,
279+ const AVFrame *src)
280+{
281+ AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
282+ D3D11VAFramesContext *s = ctx->internal->priv;
283+ int download = src->format == AV_PIX_FMT_D3D11;
284+ const AVFrame *frame = download ? src : dst;
285+ const AVFrame *other = download ? dst : src;
286+ // (The interface types are compatible.)
287+ ID3D11Resource *texture = (ID3D11Resource *)(ID3D11Texture2D *)frame->data[0];
288+ int index = (intptr_t)frame->data[1];
289+ ID3D11Resource *staging = (ID3D11Resource *)s->staging_texture;
290+ int w = FFMIN(dst->width, src->width);
291+ int h = FFMIN(dst->height, src->height);
292+ uint8_t *map_data[4];
293+ int map_linesize[4];
294+ D3D11_TEXTURE2D_DESC desc;
295+ D3D11_MAPPED_SUBRESOURCE map;
296+ HRESULT hr;
297+
298+ if (frame->hw_frames_ctx->data != (uint8_t *)ctx || other->format != ctx->sw_format)
299+ return AVERROR(EINVAL);
300+
301+ device_hwctx->lock(device_hwctx->lock_ctx);
302+
303+ ID3D11Texture2D_GetDesc(s->staging_texture, &desc);
304+
305+ if (download) {
306+ ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context,
307+ staging, 0, 0, 0, 0,
308+ texture, index, NULL);
309+
310+ hr = ID3D11DeviceContext_Map(device_hwctx->device_context,
311+ staging, 0, D3D11_MAP_READ, 0, &map);
312+ if (FAILED(hr))
313+ goto map_failed;
314+
315+ fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map);
316+
317+ av_image_copy(dst->data, dst->linesize, map_data, map_linesize,
318+ ctx->sw_format, w, h);
319+
320+ ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0);
321+ } else {
322+ hr = ID3D11DeviceContext_Map(device_hwctx->device_context,
323+ staging, 0, D3D11_MAP_WRITE, 0, &map);
324+ if (FAILED(hr))
325+ goto map_failed;
326+
327+ fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map);
328+
329+ av_image_copy(map_data, map_linesize, src->data, src->linesize,
330+ ctx->sw_format, w, h);
331+
332+ ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0);
333+
334+ ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context,
335+ texture, index, 0, 0, 0,
336+ staging, 0, NULL);
337+ }
338+
339+ device_hwctx->unlock(device_hwctx->lock_ctx);
340+ return 0;
341+
342+map_failed:
343+ av_log(ctx, AV_LOG_ERROR, "Unable to lock D3D11VA surface (%lx)\n", (long)hr);
344+ device_hwctx->unlock(device_hwctx->lock_ctx);
345+ return AVERROR_UNKNOWN;
346+}
347+
348+static int d3d11va_device_init(AVHWDeviceContext *hwdev)
349+{
350+ AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx;
351+ HRESULT hr;
352+
353+ if (!device_hwctx->lock) {
354+ device_hwctx->lock_ctx = CreateMutex(NULL, 0, NULL);
355+ if (device_hwctx->lock_ctx == INVALID_HANDLE_VALUE) {
356+ av_log(NULL, AV_LOG_ERROR, "Failed to create a mutex\n");
357+ return AVERROR(EINVAL);
358+ }
359+ device_hwctx->lock = d3d11va_default_lock;
360+ device_hwctx->unlock = d3d11va_default_unlock;
361+ }
362+
363+ if (!device_hwctx->device_context) {
364+ ID3D11Device_GetImmediateContext(device_hwctx->device, &device_hwctx->device_context);
365+ if (!device_hwctx->device_context)
366+ return AVERROR_UNKNOWN;
367+ }
368+
369+ if (!device_hwctx->video_device) {
370+ hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device, &IID_ID3D11VideoDevice,
371+ (void **)&device_hwctx->video_device);
372+ if (FAILED(hr))
373+ return AVERROR_UNKNOWN;
374+ }
375+
376+ if (!device_hwctx->video_context) {
377+ hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device_context, &IID_ID3D11VideoContext,
378+ (void **)&device_hwctx->video_context);
379+ if (FAILED(hr))
380+ return AVERROR_UNKNOWN;
381+ }
382+
383+ return 0;
384+}
385+
386+static void d3d11va_device_uninit(AVHWDeviceContext *hwdev)
387+{
388+ AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx;
389+
390+ if (device_hwctx->device)
391+ ID3D11Device_Release(device_hwctx->device);
392+
393+ if (device_hwctx->device_context)
394+ ID3D11DeviceContext_Release(device_hwctx->device_context);
395+
396+ if (device_hwctx->video_device)
397+ ID3D11VideoDevice_Release(device_hwctx->video_device);
398+
399+ if (device_hwctx->video_context)
400+ ID3D11VideoContext_Release(device_hwctx->video_context);
401+
402+ if (device_hwctx->lock == d3d11va_default_lock)
403+ CloseHandle(device_hwctx->lock_ctx);
404+}
405+
406+static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
407+ AVDictionary *opts, int flags)
408+{
409+ AVD3D11VADeviceContext *device_hwctx = ctx->hwctx;
410+ HANDLE d3dlib;
411+
412+ HRESULT hr;
413+ PFN_D3D11_CREATE_DEVICE createD3D;
414+ IDXGIAdapter *pAdapter = NULL;
415+ ID3D10Multithread *pMultithread;
416+ UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
417+
418+ if (device) {
419+ PFN_CREATE_DXGI_FACTORY mCreateDXGIFactory;
420+ HMODULE dxgilib = LoadLibrary("dxgi.dll");
421+ if (!dxgilib)
422+ return AVERROR_UNKNOWN;
423+
424+ mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) GetProcAddress(dxgilib, "CreateDXGIFactory");
425+ if (mCreateDXGIFactory) {
426+ IDXGIFactory2 *pDXGIFactory;
427+ hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&pDXGIFactory);
428+ if (SUCCEEDED(hr)) {
429+ int adapter = atoi(device);
430+ if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter)))
431+ pAdapter = NULL;
432+ IDXGIFactory2_Release(pDXGIFactory);
433+ }
434+ }
435+ FreeLibrary(dxgilib);
436+ }
437+
438+ // We let this "leak" - this is fine, as unloading has no great benefit, and
439+ // Windows will mark a DLL as loaded forever if its internal refcount overflows
440+ // from too many LoadLibrary calls.
441+ d3dlib = LoadLibrary("d3d11.dll");
442+ if (!d3dlib) {
443+ av_log(ctx, AV_LOG_ERROR, "Failed to load D3D11 library\n");
444+ return AVERROR_UNKNOWN;
445+ }
446+
447+ createD3D = (PFN_D3D11_CREATE_DEVICE) GetProcAddress(d3dlib, "D3D11CreateDevice");
448+ if (!createD3D) {
449+ av_log(ctx, AV_LOG_ERROR, "Failed to locate D3D11CreateDevice\n");
450+ return AVERROR_UNKNOWN;
451+ }
452+
453+ hr = createD3D(pAdapter, pAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, NULL, creationFlags, NULL, 0,
454+ D3D11_SDK_VERSION, &device_hwctx->device, NULL, NULL);
455+ if (pAdapter)
456+ IDXGIAdapter_Release(pAdapter);
457+ if (FAILED(hr)) {
458+ av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device (%lx)\n", (long)hr);
459+ return AVERROR_UNKNOWN;
460+ }
461+
462+ hr = ID3D11Device_QueryInterface(device_hwctx->device, &IID_ID3D10Multithread, (void **)&pMultithread);
463+ if (SUCCEEDED(hr)) {
464+ ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
465+ ID3D10Multithread_Release(pMultithread);
466+ }
467+
468+ return 0;
469+}
470+
471+const HWContextType ff_hwcontext_type_d3d11va = {
472+ .type = AV_HWDEVICE_TYPE_D3D11VA,
473+ .name = "D3D11VA",
474+
475+ .device_hwctx_size = sizeof(AVD3D11VADeviceContext),
476+ .frames_hwctx_size = sizeof(AVD3D11VAFramesContext),
477+ .frames_priv_size = sizeof(D3D11VAFramesContext),
478+
479+ .device_create = d3d11va_device_create,
480+ .device_init = d3d11va_device_init,
481+ .device_uninit = d3d11va_device_uninit,
482+ .frames_init = d3d11va_frames_init,
483+ .frames_uninit = d3d11va_frames_uninit,
484+ .frames_get_buffer = d3d11va_get_buffer,
485+ .transfer_get_formats = d3d11va_transfer_get_formats,
486+ .transfer_data_to = d3d11va_transfer_data,
487+ .transfer_data_from = d3d11va_transfer_data,
488+
489+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_D3D11, AV_PIX_FMT_NONE },
490+};
libavutil/hwcontext_d3d11va.h+160−0
@@ -0,0 +1,160 @@
1+/*
2+ * This file is part of Libav.
3+ *
4+ * Libav 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+ * Libav 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 Libav; if not, write to the Free Software
16+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+ */
18+
19+#ifndef AVUTIL_HWCONTEXT_D3D11VA_H
20+#define AVUTIL_HWCONTEXT_D3D11VA_H
21+
22+/**
23+ * @file
24+ * An API-specific header for AV_HWDEVICE_TYPE_D3D11VA.
25+ *
26+ * The default pool implementation will be fixed-size if initial_pool_size is
27+ * set (and allocate elements from an array texture). Otherwise it will allocate
28+ * individual textures. Be aware that decoding requires a single array texture.
29+ */
30+
31+#include <d3d11.h>
32+
33+/**
34+ * This struct is allocated as AVHWDeviceContext.hwctx
35+ */
36+typedef struct AVD3D11VADeviceContext {
37+ /**
38+ * Device used for texture creation and access. This can also be used to
39+ * set the libavcodec decoding device.
40+ *
41+ * Must be set by the user. This is the only mandatory field - the other
42+ * device context fields are set from this and are available for convenience.
43+ *
44+ * Deallocating the AVHWDeviceContext will always release this interface,
45+ * and it does not matter whether it was user-allocated.
46+ */
47+ ID3D11Device *device;
48+
49+ /**
50+ * If unset, this will be set from the device field on init.
51+ *
52+ * Deallocating the AVHWDeviceContext will always release this interface,
53+ * and it does not matter whether it was user-allocated.
54+ */
55+ ID3D11DeviceContext *device_context;
56+
57+ /**
58+ * If unset, this will be set from the device field on init.
59+ *
60+ * Deallocating the AVHWDeviceContext will always release this interface,
61+ * and it does not matter whether it was user-allocated.
62+ */
63+ ID3D11VideoDevice *video_device;
64+
65+ /**
66+ * If unset, this will be set from the device_context field on init.
67+ *
68+ * Deallocating the AVHWDeviceContext will always release this interface,
69+ * and it does not matter whether it was user-allocated.
70+ */
71+ ID3D11VideoContext *video_context;
72+
73+ /**
74+ * Callbacks for locking. They protect accesses to device_context and
75+ * video_context calls. They also protect access to the internal staging
76+ * texture (for av_hwframe_transfer_data() calls). They do NOT protect
77+ * access to hwcontext or decoder state in general.
78+ *
79+ * If unset on init, the hwcontext implementation will set them to use an
80+ * internal mutex.
81+ *
82+ * The underlying lock must be recursive. lock_ctx is for free use by the
83+ * locking implementation.
84+ */
85+ void (*lock)(void *lock_ctx);
86+ void (*unlock)(void *lock_ctx);
87+ void *lock_ctx;
88+} AVD3D11VADeviceContext;
89+
90+/**
91+ * D3D11 frame descriptor for pool allocation.
92+ *
93+ * In user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs
94+ * with the data pointer pointing at an object of this type describing the
95+ * planes of the frame.
96+ *
97+ * This has no use outside of custom allocation, and AVFrame AVBufferRef do not
98+ * necessarily point to an instance of this struct.
99+ */
100+typedef struct AVD3D11FrameDescriptor {
101+ /**
102+ * The texture in which the frame is located. The reference count is
103+ * managed by the AVBufferRef, and destroying the reference will release
104+ * the interface.
105+ *
106+ * Normally stored in AVFrame.data[0].
107+ */
108+ ID3D11Texture2D *texture;
109+
110+ /**
111+ * The index into the array texture element representing the frame, or 0
112+ * if the texture is not an array texture.
113+ *
114+ * Normally stored in AVFrame.data[1] (cast from intptr_t).
115+ */
116+ intptr_t index;
117+} AVD3D11FrameDescriptor;
118+
119+/**
120+ * This struct is allocated as AVHWFramesContext.hwctx
121+ */
122+typedef struct AVD3D11VAFramesContext {
123+ /**
124+ * The canonical texture used for pool allocation. If this is set to NULL
125+ * on init, the hwframes implementation will allocate and set an array
126+ * texture if initial_pool_size > 0.
127+ *
128+ * The only situation when the API user should set this is:
129+ * - the user wants to do manual pool allocation (setting
130+ * AVHWFramesContext.pool), instead of letting AVHWFramesContext
131+ * allocate the pool
132+ * - of an array texture
133+ * - and wants it to use it for decoding
134+ * - this has to be done before calling av_hwframe_ctx_init()
135+ *
136+ * Deallocating the AVHWFramesContext will always release this interface,
137+ * and it does not matter whether it was user-allocated.
138+ *
139+ * This is in particular used by the libavcodec D3D11VA hwaccel, which
140+ * requires a single array texture. It will create ID3D11VideoDecoderOutputView
141+ * objects for each array texture element on decoder initialization.
142+ */
143+ ID3D11Texture2D *texture;
144+
145+ /**
146+ * D3D11_TEXTURE2D_DESC.BindFlags used for texture creation. The user must
147+ * at least set D3D11_BIND_DECODER if the frames context is to be used for
148+ * video decoding.
149+ * This field is ignored/invalid if a user-allocated texture is provided.
150+ */
151+ UINT BindFlags;
152+
153+ /**
154+ * D3D11_TEXTURE2D_DESC.MiscFlags used for texture creation.
155+ * This field is ignored/invalid if a user-allocated texture is provided.
156+ */
157+ UINT MiscFlags;
158+} AVD3D11VAFramesContext;
159+
160+#endif /* AVUTIL_HWCONTEXT_D3D11VA_H */
libavutil/hwcontext_internal.h+1−0
@@ -158,6 +158,7 @@ int ff_hwframe_map_create(AVBufferRef *hwframe_ref, · 157 unmodified lines
158158
159159
160160 extern const HWContextType ff_hwcontext_type_cuda;
161+extern const HWContextType ff_hwcontext_type_d3d11va;
161162 extern const HWContextType ff_hwcontext_type_dxva2;
162163 extern const HWContextType ff_hwcontext_type_qsv;
163164 extern const HWContextType ff_hwcontext_type_vaapi;
libavutil/pixdesc.c+4−0
@@ -2158,6 +2158,10 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { · 2157 unmodified lines
21582158 .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR |
21592159 AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA,
21602160 },
2161+ [AV_PIX_FMT_D3D11] = {
2162+ .name = "d3d11",
2163+ .flags = AV_PIX_FMT_FLAG_HWACCEL,
2164+ },
21612165 };
21622166 #if FF_API_PLUS1_MINUS1
21632167 FF_ENABLE_DEPRECATION_WARNINGS
libavutil/pixfmt.h+13−1
@@ -240,7 +240,7 @@ enum AVPixelFormat { · 239 unmodified lines
240240 */
241241 AV_PIX_FMT_MMAL,
242242
243− AV_PIX_FMT_D3D11VA_VLD, ///< HW decoding through Direct3D11, Picture.data[3] contains a ID3D11VideoDecoderOutputView pointer
243+ AV_PIX_FMT_D3D11VA_VLD, ///< HW decoding through Direct3D11 via old API, Picture.data[3] contains a ID3D11VideoDecoderOutputView pointer
244244
245245 /**
246246 * HW acceleration through CUDA. data[i] contain CUdeviceptr pointers
@@ -314,6 +314,18 @@ enum AVPixelFormat { · 67 unmodified lines
314314 AV_PIX_FMT_P016LE, ///< like NV12, with 16bpp per component, little-endian
315315 AV_PIX_FMT_P016BE, ///< like NV12, with 16bpp per component, big-endian
316316
317+ /**
318+ * Hardware surfaces for Direct3D11.
319+ *
320+ * This is preferred over the legacy AV_PIX_FMT_D3D11VA_VLD. The new D3D11
321+ * hwaccel API and filtering support AV_PIX_FMT_D3D11 only.
322+ *
323+ * data[0] contains a ID3D11Texture2D pointer, and data[1] contains the
324+ * texture array index of the frame as intptr_t if the ID3D11Texture2D is
325+ * an array texture (or always 0 if it's a normal texture).
326+ */
327+ AV_PIX_FMT_D3D11,
328+
317329 AV_PIX_FMT_NB ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions
318330 };
319331
libavutil/version.h+1−1
@@ -80,7 +80,7 @@ · 79 unmodified lines
8080
8181
8282 #define LIBAVUTIL_VERSION_MAJOR 55
83−#define LIBAVUTIL_VERSION_MINOR 66
83+#define LIBAVUTIL_VERSION_MINOR 67
8484 #define LIBAVUTIL_VERSION_MICRO 100
8585
8686 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t