d3d11va: don't use the external pool for NVIDIA hardware with too many slices
[vlc.git] / modules / codec / avcodec / d3d11va.c
1 /*****************************************************************************
2  * d3d11va.c: Direct3D11 Video Acceleration decoder
3  *****************************************************************************
4  * Copyright © 2009 Geoffroy Couprie
5  * Copyright © 2009 Laurent Aimar
6  * Copyright © 2015 Steve Lhomme
7  * Copyright © 2015 VideoLabs
8  *
9  * Authors: Geoffroy Couprie <geal@videolan.org>
10  *          Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
11  *          Steve Lhomme <robux4@gmail.com>
12  *
13  * This program is free software; you can redistribute it and/or modify it
14  * under the terms of the GNU Lesser General Public License as published by
15  * the Free Software Foundation; either version 2.1 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 /**
29   * See https://msdn.microsoft.com/en-us/library/windows/desktop/hh162912%28v=vs.85%29.aspx
30   **/
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 # undef WINAPI_FAMILY
36 # define WINAPI_FAMILY WINAPI_FAMILY_DESKTOP_APP
37
38 #include <assert.h>
39
40 #include <vlc_common.h>
41 #include <vlc_picture.h>
42 #include <vlc_plugin.h>
43 #include <vlc_charset.h>
44 #include <vlc_codec.h>
45
46 #define COBJMACROS
47 #include <initguid.h>
48 #include <d3d11.h>
49 #include <libavcodec/d3d11va.h>
50
51 #include "../../video_chroma/d3d11_fmt.h"
52
53 #define D3D_Device          ID3D11Device
54 #define D3D_DecoderType     ID3D11VideoDecoder
55 #define D3D_DecoderDevice   ID3D11VideoDevice
56 #define D3D_DecoderSurface  ID3D11VideoDecoderOutputView
57 #include "directx_va.h"
58
59 static int Open(vlc_va_t *, AVCodecContext *, enum PixelFormat,
60                 const es_format_t *, picture_sys_t *p_sys);
61 static void Close(vlc_va_t *, AVCodecContext *);
62
63 vlc_module_begin()
64     set_description(N_("Direct3D11 Video Acceleration"))
65     set_capability("hw decoder", 0)
66     set_category(CAT_INPUT)
67     set_subcategory(SUBCAT_INPUT_VCODEC)
68     set_callbacks(Open, Close)
69 vlc_module_end()
70
71 #if VLC_WINSTORE_APP
72 #define pf_CreateDevice                 D3D11CreateDevice
73 #endif
74
75 /*
76  * In this mode libavcodec doesn't need the whole array on texture on startup
77  * So we get the surfaces from the decoder pool when needed. We don't need to
78  * extract the decoded surface into the decoder picture anymore.
79  */
80 #define D3D11_DIRECT_DECODE  LIBAVCODEC_VERSION_CHECK( 57, 30, 3, 72, 101 )
81
82 #include <initguid.h> /* must be last included to not redefine existing GUIDs */
83
84 /* dxva2api.h GUIDs: http://msdn.microsoft.com/en-us/library/windows/desktop/ms697067(v=vs100).aspx
85  * assume that they are declared in dxva2api.h */
86 #define MS_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
87
88 #ifdef __MINGW32__
89 # include <_mingw.h>
90
91 # if !defined(__MINGW64_VERSION_MAJOR)
92 #  undef MS_GUID
93 #  define MS_GUID DEFINE_GUID /* dxva2api.h fails to declare those, redefine as static */
94 #  define DXVA2_E_NEW_VIDEO_DEVICE MAKE_HRESULT(1, 4, 4097)
95 # else
96 #  include <dxva.h>
97 # endif
98
99 #endif /* __MINGW32__ */
100
101 #if !defined(NDEBUG) && defined(HAVE_DXGIDEBUG_H)
102 # include <dxgidebug.h>
103 #endif
104
105 DEFINE_GUID(DXVA_Intel_H264_NoFGT_ClearVideo,       0x604F8E68, 0x4951, 0x4c54, 0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6);
106
107 DEFINE_GUID(DXVA2_NoEncrypt,                        0x1b81bed0, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);
108
109 struct vlc_va_sys_t
110 {
111     directx_sys_t                dx_sys;
112     vlc_fourcc_t                 i_chroma;
113     UINT                         totalTextureSlices;
114
115 #if !defined(NDEBUG) && defined(HAVE_DXGIDEBUG_H)
116     HINSTANCE                    dxgidebug_dll;
117 #endif
118
119     /* Video service */
120     ID3D11VideoContext           *d3dvidctx;
121     DXGI_FORMAT                  render;
122
123     ID3D11DeviceContext          *d3dctx;
124     HANDLE                       context_mutex;
125
126     /* pool */
127     bool                         b_extern_pool;
128     picture_t                    *extern_pics[MAX_SURFACE_COUNT];
129
130     /* Video decoder */
131     D3D11_VIDEO_DECODER_CONFIG   cfg;
132
133     /* avcodec internals */
134     struct AVD3D11VAContext      hw;
135
136     /* I420_OPAQUE processor */
137     ID3D11VideoProcessorEnumerator *procEnumerator;
138     ID3D11VideoProcessor           *videoProcessor;
139     DXGI_FORMAT                    processorFormat;
140 };
141
142 /* */
143 static int D3dCreateDevice(vlc_va_t *);
144 static void D3dDestroyDevice(vlc_va_t *);
145 static char *DxDescribe(directx_sys_t *);
146
147 static int DxCreateVideoService(vlc_va_t *);
148 static void DxDestroyVideoService(vlc_va_t *);
149 static int DxGetInputList(vlc_va_t *, input_list_t *);
150 static int DxSetupOutput(vlc_va_t *, const GUID *, const video_format_t *);
151
152 static int DxCreateDecoderSurfaces(vlc_va_t *, int codec_id, const video_format_t *fmt);
153 static void DxDestroySurfaces(vlc_va_t *);
154 static void SetupAVCodecContext(vlc_va_t *);
155
156 static picture_t *DxAllocPicture(vlc_va_t *, const video_format_t *, unsigned index);
157
158 /* */
159 static void Setup(vlc_va_t *va, vlc_fourcc_t *chroma)
160 {
161     *chroma = va->sys->i_chroma;
162 }
163
164 void SetupAVCodecContext(vlc_va_t *va)
165 {
166     vlc_va_sys_t *sys = va->sys;
167     directx_sys_t *dx_sys = &sys->dx_sys;
168
169     sys->hw.video_context = sys->d3dvidctx;
170     sys->hw.decoder = dx_sys->decoder;
171     sys->hw.cfg = &sys->cfg;
172     sys->hw.surface_count = dx_sys->surface_count;
173     sys->hw.surface = dx_sys->hw_surface;
174     sys->hw.context_mutex = sys->context_mutex;
175
176     if (IsEqualGUID(&dx_sys->input, &DXVA_Intel_H264_NoFGT_ClearVideo))
177         sys->hw.workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;
178 }
179
180 static int Extract(vlc_va_t *va, picture_t *output, uint8_t *data)
181 {
182     vlc_va_sys_t *sys = va->sys;
183     ID3D11VideoDecoderOutputView *src = (ID3D11VideoDecoderOutputView*)(uintptr_t)data;
184     vlc_va_surface_t *surface = output->p_sys->va_surface;
185     int ret = VLC_SUCCESS;
186
187     picture_sys_t *p_sys_out = surface ? surface->p_pic->p_sys : output->p_sys;
188
189     assert(p_sys_out->texture[KNOWN_DXGI_INDEX] != NULL);
190
191 #ifdef ID3D11VideoContext_VideoProcessorBlt
192     if (sys->videoProcessor)
193     {
194         picture_sys_t *p_sys_in = surface->p_pic->p_sys;
195         assert(p_sys_in->decoder == src);
196
197         if( sys->context_mutex != INVALID_HANDLE_VALUE ) {
198             WaitForSingleObjectEx( sys->context_mutex, INFINITE, FALSE );
199         }
200
201         // extract the decoded video to a the output Texture
202         if (p_sys_out->decoder == NULL)
203         {
204             D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outDesc = {
205                 .ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D,
206             };
207
208             HRESULT hr = ID3D11VideoDevice_CreateVideoProcessorOutputView(sys->dx_sys.d3ddec,
209                                                              p_sys_out->resource[KNOWN_DXGI_INDEX],
210                                                              sys->procEnumerator,
211                                                              &outDesc,
212                                                              &p_sys_out->decoder);
213             if (FAILED(hr))
214             {
215                 msg_Err(va, "Failed to create the processor output. (hr=0x%lX)", hr);
216                 ret = VLC_EGENERIC;
217                 goto done;
218             }
219         }
220
221         D3D11_VIDEO_PROCESSOR_STREAM stream = {
222             .Enable = TRUE,
223             .pInputSurface = p_sys_in->processorInput,
224         };
225
226         HRESULT hr = ID3D11VideoContext_VideoProcessorBlt(sys->d3dvidctx, sys->videoProcessor,
227                                                   p_sys_out->decoder,
228                                                   0, 1, &stream);
229         if (FAILED(hr))
230         {
231             msg_Err(va, "Failed to process the video. (hr=0x%lX)", hr);
232             ret = VLC_EGENERIC;
233         }
234 done:
235         if( sys->context_mutex  != INVALID_HANDLE_VALUE ) {
236             ReleaseMutex( sys->context_mutex );
237         }
238     }
239 #endif
240 #if !D3D11_DIRECT_DECODE
241 #ifdef ID3D11VideoContext_VideoProcessorBlt
242     else
243 #endif
244     {
245         picture_sys_t *p_sys_in = surface->p_pic->p_sys;
246         assert(p_sys_in->decoder == src);
247
248         if( sys->context_mutex != INVALID_HANDLE_VALUE ) {
249             WaitForSingleObjectEx( sys->context_mutex, INFINITE, FALSE );
250         }
251
252         D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
253         ID3D11VideoDecoderOutputView_GetDesc( src, &viewDesc );
254
255         D3D11_TEXTURE2D_DESC dstDesc;
256         ID3D11Texture2D_GetDesc( p_sys_out->texture[KNOWN_DXGI_INDEX], &dstDesc);
257
258         /* copy decoder slice to surface */
259         D3D11_BOX copyBox = {
260             .right = dstDesc.Width, .bottom = dstDesc.Height, .back = 1,
261         };
262         ID3D11DeviceContext_CopySubresourceRegion(sys->d3dctx, p_sys_out->resource[KNOWN_DXGI_INDEX],
263                                                   p_sys_out->slice_index, 0, 0, 0,
264                                                   p_sys_in->resource[KNOWN_DXGI_INDEX],
265                                                   viewDesc.Texture2D.ArraySlice,
266                                                   &copyBox);
267         if( sys->context_mutex  != INVALID_HANDLE_VALUE ) {
268             ReleaseMutex( sys->context_mutex );
269         }
270     }
271 #endif
272     if (!output->p_sys && surface->p_pic && surface->p_pic->p_sys)
273         /* HW decoding in a software pipe, pass the texture to upstream filters */
274         output->p_sys = surface->p_pic->p_sys;
275
276     return ret;
277 }
278
279 static int CheckDevice(vlc_va_t *va)
280 {
281     VLC_UNUSED(va);
282 #ifdef TODO
283     /* Check the device */
284     /* see MFCreateDXGIDeviceManager in mfplat.dll, not avail in Win7 */
285     HRESULT hr = IDirect3DDeviceManager9_TestDevice(sys->devmng, sys->device);
286     if (hr == DXVA2_E_NEW_VIDEO_DEVICE) {
287         if (DxResetVideoDecoder(va))
288             return VLC_EGENERIC;
289     } else if (FAILED(hr)) {
290         msg_Err(va, "IDirect3DDeviceManager9_TestDevice %u", (unsigned)hr);
291         return VLC_EGENERIC;
292     }
293 #endif
294     return VLC_SUCCESS;
295 }
296
297 static int Get(vlc_va_t *va, picture_t *pic, uint8_t **data)
298 {
299 #if D3D11_DIRECT_DECODE
300     picture_sys_t *p_sys = pic->p_sys;
301     if (p_sys == NULL)
302     {
303         assert(!va->sys->b_extern_pool);
304         vlc_va_surface_t *va_surface = directx_va_Get(va, &va->sys->dx_sys, data);
305         if (!va_surface)
306             return VLC_EGENERIC;
307         pic->p_sys = va_surface->p_pic->p_sys;
308         pic->p_sys->va_surface = va_surface;
309         return VLC_SUCCESS;
310     }
311
312     if (p_sys->decoder == NULL)
313     {
314         HRESULT hr;
315
316         directx_sys_t *dx_sys = &va->sys->dx_sys;
317
318         D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
319         ZeroMemory(&viewDesc, sizeof(viewDesc));
320         viewDesc.DecodeProfile = dx_sys->input;
321         viewDesc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
322         viewDesc.Texture2D.ArraySlice = p_sys->slice_index;
323
324         hr = ID3D11VideoDevice_CreateVideoDecoderOutputView( dx_sys->d3ddec,
325                                                              p_sys->resource[KNOWN_DXGI_INDEX],
326                                                              &viewDesc,
327                                                              &p_sys->decoder );
328         if (FAILED(hr)) {
329             msg_Warn(va, "CreateVideoDecoderOutputView %d failed. (hr=0x%0lx)", p_sys->slice_index, hr);
330             D3D11_TEXTURE2D_DESC texDesc;
331             ID3D11Texture2D_GetDesc(p_sys->texture[KNOWN_DXGI_INDEX], &texDesc);
332             assert(texDesc.BindFlags & D3D11_BIND_DECODER);
333             p_sys->decoder = NULL;
334         }
335     }
336     if (p_sys->decoder == NULL)
337         return VLC_EGENERIC;
338     *data = p_sys->decoder;
339     return VLC_SUCCESS;
340 #endif
341     vlc_va_surface_t *va_surface = directx_va_Get(va, &va->sys->dx_sys, data);
342     if (!va_surface)
343         return VLC_EGENERIC;
344     pic->p_sys = va_surface->p_pic->p_sys;
345     pic->p_sys->va_surface = va_surface;
346     return VLC_SUCCESS;
347 }
348
349 static void Close(vlc_va_t *va, AVCodecContext *ctx)
350 {
351     vlc_va_sys_t *sys = va->sys;
352
353     (void) ctx;
354
355     directx_va_Close(va, &sys->dx_sys);
356
357 #if !defined(NDEBUG) && defined(HAVE_DXGIDEBUG_H)
358     if (sys->dxgidebug_dll)
359         FreeLibrary(sys->dxgidebug_dll);
360 #endif
361
362     free((char *)va->description);
363     free(sys);
364 }
365
366 static vlc_fourcc_t d3d11va_fourcc(enum PixelFormat swfmt)
367 {
368     switch (swfmt)
369     {
370         case AV_PIX_FMT_YUV420P10LE:
371             return VLC_CODEC_D3D11_OPAQUE_10B;
372         default:
373             return VLC_CODEC_D3D11_OPAQUE;
374     }
375 }
376
377 static void ReleasePic(void *opaque, uint8_t *data)
378 {
379     (void)data;
380     picture_t *pic = opaque;
381     directx_va_Release(pic->p_sys->va_surface);
382     pic->p_sys->va_surface = NULL;
383     picture_Release(pic);
384 }
385
386 static int Open(vlc_va_t *va, AVCodecContext *ctx, enum PixelFormat pix_fmt,
387                 const es_format_t *fmt, picture_sys_t *p_sys)
388 {
389     int err = VLC_EGENERIC;
390     directx_sys_t *dx_sys;
391
392     if (pix_fmt != AV_PIX_FMT_D3D11VA_VLD)
393         return VLC_EGENERIC;
394
395     vlc_va_sys_t *sys = calloc(1, sizeof (*sys));
396     if (unlikely(sys == NULL))
397         return VLC_ENOMEM;
398
399 #if !defined(NDEBUG) && defined(HAVE_DXGIDEBUG_H)
400     sys->dxgidebug_dll = LoadLibrary(TEXT("DXGIDEBUG.DLL"));
401 #endif
402
403     dx_sys = &sys->dx_sys;
404
405     dx_sys->pf_check_device            = CheckDevice;
406     dx_sys->pf_create_device           = D3dCreateDevice;
407     dx_sys->pf_destroy_device          = D3dDestroyDevice;
408     dx_sys->pf_create_video_service    = DxCreateVideoService;
409     dx_sys->pf_destroy_video_service   = DxDestroyVideoService;
410     dx_sys->pf_create_decoder_surfaces = DxCreateDecoderSurfaces;
411     dx_sys->pf_destroy_surfaces        = DxDestroySurfaces;
412     dx_sys->pf_setup_avcodec_ctx       = SetupAVCodecContext;
413     dx_sys->pf_get_input_list          = DxGetInputList;
414     dx_sys->pf_setup_output            = DxSetupOutput;
415     dx_sys->pf_alloc_surface_pic       = DxAllocPicture;
416     dx_sys->psz_decoder_dll            = TEXT("D3D11.DLL");
417
418     va->sys = sys;
419
420     dx_sys->d3ddev = NULL;
421     va->sys->render = DXGI_FORMAT_UNKNOWN;
422     if ( p_sys != NULL && p_sys->context != NULL ) {
423         void *d3dvidctx = NULL;
424         HRESULT hr = ID3D11DeviceContext_QueryInterface(p_sys->context, &IID_ID3D11VideoContext, &d3dvidctx);
425         if (FAILED(hr)) {
426            msg_Err(va, "Could not Query ID3D11VideoContext Interface from the picture. (hr=0x%lX)", hr);
427         } else {
428             ID3D11DeviceContext_GetDevice( p_sys->context, &dx_sys->d3ddev );
429             HANDLE context_lock = INVALID_HANDLE_VALUE;
430             UINT dataSize = sizeof(context_lock);
431             hr = ID3D11Device_GetPrivateData(dx_sys->d3ddev, &GUID_CONTEXT_MUTEX, &dataSize, &context_lock);
432             if (FAILED(hr))
433                 msg_Warn(va, "No mutex found to lock the decoder");
434             sys->context_mutex = context_lock;
435
436             sys->d3dctx = p_sys->context;
437             sys->d3dvidctx = d3dvidctx;
438
439             assert(p_sys->texture[KNOWN_DXGI_INDEX] != NULL);
440             D3D11_TEXTURE2D_DESC dstDesc;
441             ID3D11Texture2D_GetDesc( p_sys->texture[KNOWN_DXGI_INDEX], &dstDesc);
442             sys->render = dstDesc.Format;
443             va->sys->totalTextureSlices = dstDesc.ArraySize;
444         }
445     }
446
447     sys->i_chroma = d3d11va_fourcc(ctx->sw_pix_fmt);
448
449 #if VLC_WINSTORE_APP
450     err = directx_va_Open(va, &sys->dx_sys, ctx, fmt, false);
451 #else
452     err = directx_va_Open(va, &sys->dx_sys, ctx, fmt, dx_sys->d3ddev == NULL || va->sys->d3dctx == NULL);
453 #endif
454     if (err!=VLC_SUCCESS)
455         goto error;
456
457     err = directx_va_Setup(va, &sys->dx_sys, ctx);
458     if (err != VLC_SUCCESS)
459         goto error;
460
461     ctx->hwaccel_context = &sys->hw;
462
463     /* TODO print the hardware name/vendor for debugging purposes */
464     va->description = DxDescribe(dx_sys);
465     va->setup   = Setup;
466     va->get     = Get;
467 #if D3D11_DIRECT_DECODE
468     va->release = sys->b_extern_pool ? NULL : ReleasePic;
469 #else
470     va->release = ReleasePic;
471 #endif
472     va->extract = Extract;
473
474     return VLC_SUCCESS;
475
476 error:
477     Close(va, ctx);
478     return err;
479 }
480
481 /**
482  * It creates a Direct3D device usable for decoding
483  */
484 static int D3dCreateDevice(vlc_va_t *va)
485 {
486     directx_sys_t *dx_sys = &va->sys->dx_sys;
487     HRESULT hr;
488
489     if (dx_sys->d3ddev && va->sys->d3dctx) {
490         msg_Dbg(va, "Reusing Direct3D11 device");
491         ID3D11DeviceContext_AddRef(va->sys->d3dctx);
492         return VLC_SUCCESS;
493     }
494
495 #if !VLC_WINSTORE_APP
496     /* */
497     PFN_D3D11_CREATE_DEVICE pf_CreateDevice;
498     pf_CreateDevice = (void *)GetProcAddress(dx_sys->hdecoder_dll, "D3D11CreateDevice");
499     if (!pf_CreateDevice) {
500         msg_Err(va, "Cannot locate reference to D3D11CreateDevice ABI in DLL");
501         return VLC_EGENERIC;
502     }
503 #endif
504
505     UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
506 #if !defined(NDEBUG) //&& defined(_MSC_VER)
507     creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
508 #endif
509
510     /* */
511     ID3D11Device *d3ddev;
512     ID3D11DeviceContext *d3dctx;
513     hr = pf_CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL,
514                                  creationFlags, NULL, 0,
515                                  D3D11_SDK_VERSION, &d3ddev, NULL, &d3dctx);
516     if (FAILED(hr)) {
517         msg_Err(va, "D3D11CreateDevice failed. (hr=0x%lX)", hr);
518         return VLC_EGENERIC;
519     }
520     dx_sys->d3ddev = d3ddev;
521     va->sys->d3dctx = d3dctx;
522
523     void *d3dvidctx = NULL;
524     hr = ID3D11DeviceContext_QueryInterface(d3dctx, &IID_ID3D11VideoContext, &d3dvidctx);
525     if (FAILED(hr)) {
526        msg_Err(va, "Could not Query ID3D11VideoContext Interface. (hr=0x%lX)", hr);
527        return VLC_EGENERIC;
528     }
529     va->sys->d3dvidctx = d3dvidctx;
530
531 #if !defined(NDEBUG) && defined(HAVE_DXGIDEBUG_H)
532     HRESULT (WINAPI  * pf_DXGIGetDebugInterface)(const GUID *riid, void **ppDebug);
533     if (va->sys->dxgidebug_dll) {
534         pf_DXGIGetDebugInterface = (void *)GetProcAddress(va->sys->dxgidebug_dll, "DXGIGetDebugInterface");
535         if (pf_DXGIGetDebugInterface) {
536             IDXGIDebug *pDXGIDebug = NULL;
537             hr = pf_DXGIGetDebugInterface(&IID_IDXGIDebug, (void**)&pDXGIDebug);
538             if (SUCCEEDED(hr) && pDXGIDebug) {
539                 hr = IDXGIDebug_ReportLiveObjects(pDXGIDebug, DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL);
540             }
541         }
542     }
543 #endif
544
545     return VLC_SUCCESS;
546 }
547
548 /**
549  * It releases a Direct3D device and its resources.
550  */
551 static void D3dDestroyDevice(vlc_va_t *va)
552 {
553     if (va->sys->d3dvidctx)
554         ID3D11VideoContext_Release(va->sys->d3dvidctx);
555     if (va->sys->d3dctx)
556         ID3D11DeviceContext_Release(va->sys->d3dctx);
557     if (va->sys->videoProcessor)
558         ID3D11VideoProcessor_Release(va->sys->videoProcessor);
559     if (va->sys->procEnumerator)
560         ID3D11VideoProcessorEnumerator_Release(va->sys->procEnumerator);
561 }
562 /**
563  * It describes our Direct3D object
564  */
565 static char *DxDescribe(directx_sys_t *dx_sys)
566 {
567     static const struct {
568         unsigned id;
569         char     name[32];
570     } vendors [] = {
571         { 0x1002, "ATI" },
572         { 0x10DE, "NVIDIA" },
573         { 0x1106, "VIA" },
574         { 0x8086, "Intel" },
575         { 0x5333, "S3 Graphics" },
576         { 0x4D4F4351, "Qualcomm" },
577         { 0, "" }
578     };
579
580     IDXGIAdapter *p_adapter = D3D11DeviceAdapter(dx_sys->d3ddev);
581     if (!p_adapter) {
582        return NULL;
583     }
584
585     char *description = NULL;
586     DXGI_ADAPTER_DESC adapterDesc;
587     if (SUCCEEDED(IDXGIAdapter_GetDesc(p_adapter, &adapterDesc))) {
588         const char *vendor = "Unknown";
589         for (int i = 0; vendors[i].id != 0; i++) {
590             if (vendors[i].id == adapterDesc.VendorId) {
591                 vendor = vendors[i].name;
592                 break;
593             }
594         }
595
596         char *utfdesc = FromWide(adapterDesc.Description);
597         if (likely(utfdesc!=NULL))
598         {
599             if (asprintf(&description, "D3D11VA (%s, vendor %u(%s), device %u, revision %u)",
600                          utfdesc,
601                          adapterDesc.VendorId, vendor, adapterDesc.DeviceId, adapterDesc.Revision) < 0)
602                 description = NULL;
603             free(utfdesc);
604         }
605     }
606
607     IDXGIAdapter_Release(p_adapter);
608     return description;
609 }
610
611 /**
612  * It creates a DirectX video service
613  */
614 static int DxCreateVideoService(vlc_va_t *va)
615 {
616     directx_sys_t *dx_sys = &va->sys->dx_sys;
617
618     void *d3dviddev = NULL;
619     HRESULT hr = ID3D11Device_QueryInterface(dx_sys->d3ddev, &IID_ID3D11VideoDevice, &d3dviddev);
620     if (FAILED(hr)) {
621        msg_Err(va, "Could not Query ID3D11VideoDevice Interface. (hr=0x%lX)", hr);
622        return VLC_EGENERIC;
623     }
624     dx_sys->d3ddec = d3dviddev;
625
626     return VLC_SUCCESS;
627 }
628
629 /**
630  * It destroys a DirectX video service
631  */
632 static void DxDestroyVideoService(vlc_va_t *va)
633 {
634     VLC_UNUSED(va);
635 }
636
637 static void ReleaseInputList(input_list_t *p_list)
638 {
639     free(p_list->list);
640 }
641
642 static int DxGetInputList(vlc_va_t *va, input_list_t *p_list)
643 {
644     directx_sys_t *dx_sys = &va->sys->dx_sys;
645     HRESULT hr;
646
647     UINT input_count = ID3D11VideoDevice_GetVideoDecoderProfileCount(dx_sys->d3ddec);
648
649     p_list->count = input_count;
650     p_list->list = calloc(input_count, sizeof(*p_list->list));
651     if (unlikely(p_list->list == NULL)) {
652         return VLC_ENOMEM;
653     }
654     p_list->pf_release = ReleaseInputList;
655
656     for (unsigned i = 0; i < input_count; i++) {
657         hr = ID3D11VideoDevice_GetVideoDecoderProfile(dx_sys->d3ddec, i, &p_list->list[i]);
658         if (FAILED(hr))
659         {
660             msg_Err(va, "GetVideoDecoderProfile %d failed. (hr=0x%lX)", i, hr);
661             ReleaseInputList(p_list);
662             return VLC_EGENERIC;
663         }
664     }
665
666     return VLC_SUCCESS;
667 }
668
669 #ifdef ID3D11VideoContext_VideoProcessorBlt
670 static bool SetupProcessor(vlc_va_t *va, const video_format_t *fmt)
671 {
672     vlc_va_sys_t *sys = va->sys;
673     directx_sys_t *dx_sys = &va->sys->dx_sys;
674     HRESULT hr;
675
676     ID3D11VideoProcessorEnumerator *processorEnumerator;
677     D3D11_VIDEO_PROCESSOR_CONTENT_DESC processorDesc = {
678         .InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE,   /* TODO */
679         .InputFrameRate = {
680             .Numerator   = fmt->i_frame_rate_base > 0 ? fmt->i_frame_rate : 0,
681             .Denominator = fmt->i_frame_rate_base,
682         },
683         .InputWidth   = fmt->i_width,
684         .InputHeight  = fmt->i_height,
685         .OutputWidth  = fmt->i_width,
686         .OutputHeight = fmt->i_height,
687         .Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL,
688     };
689     hr = ID3D11VideoDevice_CreateVideoProcessorEnumerator(dx_sys->d3ddec, &processorDesc, &processorEnumerator);
690     if ( processorEnumerator == NULL )
691     {
692         msg_Dbg(va, "Can't get a video processor for the video.");
693         return false;
694     }
695
696     UINT flags;
697 #ifndef NDEBUG
698     for (int format = 0; format < 188; format++) {
699         hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, format, &flags);
700         if (SUCCEEDED(hr) && (flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT))
701             msg_Dbg(va, "processor format %s (%d) is supported for input", DxgiFormatToStr(format),format);
702         if (SUCCEEDED(hr) && (flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT))
703             msg_Dbg(va, "processor format %s (%d) is supported for output", DxgiFormatToStr(format),format);
704     }
705 #endif
706     DXGI_FORMAT processorOutput = DXGI_FORMAT_UNKNOWN;
707     if ( sys->render != DXGI_FORMAT_UNKNOWN )
708     {
709         /* shortcut for the rendering output */
710         hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, sys->render, &flags);
711         if (FAILED(hr) || !(flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT))
712             msg_Dbg(va, "processor format %s not supported for output", DxgiFormatToStr(sys->render));
713         else
714             processorOutput = sys->render;
715     }
716
717     if (processorOutput == DXGI_FORMAT_UNKNOWN)
718     {
719         // check if we can create render texture of that format
720         // check the decoder can output to that format
721         const d3d_format_t *found;
722         found = FindD3D11Format( dx_sys->d3ddev, 0, 0, true,
723                                  D3D11_FORMAT_SUPPORT_SHADER_LOAD | D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT);
724         if (found)
725             processorOutput = found->formatTexture;
726     }
727
728     if (processorOutput != DXGI_FORMAT_UNKNOWN)
729     {
730         D3D11_VIDEO_PROCESSOR_CAPS processorCaps;
731
732         hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorCaps(processorEnumerator, &processorCaps);
733
734         for (UINT type = 0; type < processorCaps.RateConversionCapsCount; ++type)
735         {
736             hr = ID3D11VideoDevice_CreateVideoProcessor(dx_sys->d3ddec,
737                                                         processorEnumerator, type, &sys->videoProcessor);
738             if (SUCCEEDED(hr))
739                 break;
740             sys->videoProcessor = NULL;
741         }
742
743         if (sys->videoProcessor != NULL)
744         {
745             sys->processorFormat = processorOutput;
746             sys->procEnumerator  = processorEnumerator;
747             return true;
748         }
749     }
750     ID3D11VideoProcessorEnumerator_Release(processorEnumerator);
751     return false;
752 }
753 #endif
754
755 static int DxSetupOutput(vlc_va_t *va, const GUID *input, const video_format_t *fmt)
756 {
757     directx_sys_t *dx_sys = &va->sys->dx_sys;
758     HRESULT hr;
759
760 #ifndef NDEBUG
761     BOOL bSupported = false;
762     for (int format = 0; format < 188; format++) {
763         hr = ID3D11VideoDevice_CheckVideoDecoderFormat(dx_sys->d3ddec, input, format, &bSupported);
764         if (SUCCEEDED(hr) && bSupported)
765             msg_Dbg(va, "format %s is supported for output", DxgiFormatToStr(format));
766     }
767 #endif
768
769     DXGI_FORMAT processorInput[4];
770     int idx = 0;
771     if ( va->sys->render != DXGI_FORMAT_UNKNOWN )
772         processorInput[idx++] = va->sys->render;
773     processorInput[idx++] = DXGI_FORMAT_NV12;
774     processorInput[idx++] = DXGI_FORMAT_420_OPAQUE;
775     processorInput[idx++] = DXGI_FORMAT_UNKNOWN;
776
777     char *psz_decoder_name = directx_va_GetDecoderName(input);
778
779     /* */
780     for (idx = 0; processorInput[idx] != DXGI_FORMAT_UNKNOWN; ++idx)
781     {
782         BOOL is_supported = false;
783         hr = ID3D11VideoDevice_CheckVideoDecoderFormat(dx_sys->d3ddec, input, processorInput[idx], &is_supported);
784         if (SUCCEEDED(hr) && is_supported)
785             msg_Dbg(va, "%s output is supported for decoder %s.", DxgiFormatToStr(processorInput[idx]), psz_decoder_name);
786         else
787         {
788             msg_Dbg(va, "Can't get a decoder output format %s for decoder %s.", DxgiFormatToStr(processorInput[idx]), psz_decoder_name);
789             continue;
790         }
791
792        // check if we can create render texture of that format
793        // check the decoder can output to that format
794        if ( !DeviceSupportsFormat(dx_sys->d3ddev, processorInput[idx],
795                                   D3D11_FORMAT_SUPPORT_SHADER_LOAD) )
796        {
797            msg_Dbg(va, "Format %s needs a processor", DxgiFormatToStr(processorInput[idx]));
798 #ifdef ID3D11VideoContext_VideoProcessorBlt
799            if (!SetupProcessor( va, fmt ))
800                 continue;
801             msg_Dbg(va, "Using processor %s to %s", DxgiFormatToStr(processorInput[idx]), DxgiFormatToStr(va->sys->processorFormat));
802 #else
803             continue;
804 #endif
805         }
806
807         D3D11_VIDEO_DECODER_DESC decoderDesc;
808         ZeroMemory(&decoderDesc, sizeof(decoderDesc));
809         decoderDesc.Guid = *input;
810         decoderDesc.SampleWidth = fmt->i_width;
811         decoderDesc.SampleHeight = fmt->i_height;
812         decoderDesc.OutputFormat = processorInput[idx];
813
814         UINT cfg_count = 0;
815         hr = ID3D11VideoDevice_GetVideoDecoderConfigCount( dx_sys->d3ddec, &decoderDesc, &cfg_count );
816         if (FAILED(hr))
817         {
818             msg_Err( va, "Failed to get configuration for decoder %s. (hr=0x%lX)", psz_decoder_name, hr );
819             continue;
820         }
821         if (cfg_count == 0) {
822             msg_Err( va, "No decoder configuration possible for %s %dx%d",
823                      DxgiFormatToStr(decoderDesc.OutputFormat),
824                      decoderDesc.SampleWidth, decoderDesc.SampleHeight );
825             continue;
826         }
827
828         msg_Dbg(va, "Using output format %s for decoder %s", DxgiFormatToStr(processorInput[idx]), psz_decoder_name);
829         if ( va->sys->render == processorInput[idx] )
830         {
831             /* NVIDIA cards crash when calling CreateVideoDecoderOutputView
832              * on more than 30 slices */
833             if (va->sys->totalTextureSlices <= 30 || !isNvidiaHardware(dx_sys->d3ddev))
834                 va->sys->b_extern_pool = true;
835             else
836                 msg_Warn( va, "NVIDIA GPU with too many slices (%d) detected, use internal pool",
837                           va->sys->totalTextureSlices );
838         }
839         va->sys->render = processorInput[idx];
840         free(psz_decoder_name);
841         return VLC_SUCCESS;
842     }
843     free(psz_decoder_name);
844
845     msg_Dbg(va, "Output format from picture source not supported.");
846     return VLC_EGENERIC;
847 }
848
849 /**
850  * It creates a Direct3D11 decoder using the given video format
851  */
852 static int DxCreateDecoderSurfaces(vlc_va_t *va, int codec_id, const video_format_t *fmt)
853 {
854     vlc_va_sys_t *sys = va->sys;
855     directx_sys_t *dx_sys = &va->sys->dx_sys;
856     HRESULT hr;
857
858     ID3D10Multithread *pMultithread;
859     hr = ID3D11Device_QueryInterface( dx_sys->d3ddev, &IID_ID3D10Multithread, (void **)&pMultithread);
860     if (SUCCEEDED(hr)) {
861         ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE);
862         ID3D10Multithread_Release(pMultithread);
863     }
864
865 #if VLC_WINSTORE_APP
866     /* On the Xbox 1/S, any decoding of H264 with one dimension over 2304
867      * crashes totally the device */
868     if (codec_id == AV_CODEC_ID_H264 &&
869         (dx_sys->surface_width > 2304 || dx_sys->surface_height > 2304) &&
870         isXboxHardware(dx_sys->d3ddev))
871     {
872         msg_Warn(va, "%dx%d resolution not supported by your hardware", dx_sys->surface_width, dx_sys->surface_height);
873         dx_sys->surface_count = 0;
874         return VLC_EGENERIC;
875     }
876 #endif
877
878     D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
879     ZeroMemory(&viewDesc, sizeof(viewDesc));
880     viewDesc.DecodeProfile = dx_sys->input;
881     viewDesc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
882
883     if (sys->b_extern_pool)
884     {
885 #if D3D11_DIRECT_DECODE
886         dx_sys->surface_count = 0;
887 #else
888         size_t surface_idx;
889         for (surface_idx = 0; surface_idx < dx_sys->surface_count; surface_idx++) {
890             picture_t *pic = decoder_NewPicture( (decoder_t*) va->obj.parent );
891             sys->extern_pics[surface_idx] = pic;
892             dx_sys->hw_surface[surface_idx] = NULL;
893             if (pic==NULL)
894             {
895                 msg_Warn(va, "not enough decoder pictures %d out of %d", surface_idx, dx_sys->surface_count);
896                 sys->b_extern_pool = false;
897                 break;
898             }
899
900             D3D11_TEXTURE2D_DESC texDesc;
901             ID3D11Texture2D_GetDesc(pic->p_sys->texture[KNOWN_DXGI_INDEX], &texDesc);
902             if (texDesc.ArraySize < dx_sys->surface_count)
903             {
904                 msg_Warn(va, "not enough decoding slices in the texture (%d/%d)",
905                          texDesc.ArraySize, dx_sys->surface_count);
906                 sys->b_extern_pool = false;
907                 break;
908             }
909             assert(texDesc.Format == sys->render);
910             assert(texDesc.BindFlags & D3D11_BIND_DECODER);
911
912 #if !LIBAVCODEC_VERSION_CHECK( 57, 27, 2, 61, 102 )
913             if (pic->p_sys->slice_index != surface_idx)
914             {
915                 msg_Warn(va, "d3d11va requires decoding slices to be the first in the texture (%d/%d)",
916                          pic->p_sys->slice_index, surface_idx);
917                 sys->b_extern_pool = false;
918                 break;
919             }
920 #endif
921
922             viewDesc.Texture2D.ArraySlice = pic->p_sys->slice_index;
923             hr = ID3D11VideoDevice_CreateVideoDecoderOutputView( dx_sys->d3ddec,
924                                                                  pic->p_sys->resource[KNOWN_DXGI_INDEX],
925                                                                  &viewDesc,
926                                                                  &pic->p_sys->decoder );
927             if (FAILED(hr)) {
928                 msg_Warn(va, "CreateVideoDecoderOutputView %d failed. (hr=0x%0lx)", surface_idx, hr);
929                 sys->b_extern_pool = false;
930                 break;
931             }
932             sys->dx_sys.hw_surface[surface_idx] = pic->p_sys->decoder;
933         }
934
935         if (!sys->b_extern_pool)
936         {
937             for (size_t i = 0; i < surface_idx; ++i)
938             {
939                 if (dx_sys->hw_surface[i])
940                 {
941                     ID3D11VideoDecoderOutputView_Release(dx_sys->hw_surface[i]);
942                     dx_sys->hw_surface[i] = NULL;
943                 }
944                 if (sys->extern_pics[i])
945                 {
946                     sys->extern_pics[i]->p_sys->decoder = NULL;
947                     picture_Release(sys->extern_pics[i]);
948                     sys->extern_pics[i] = NULL;
949                 }
950             }
951         }
952         else
953 #endif
954             msg_Dbg(va, "using external surface pool");
955     }
956
957     if (!sys->b_extern_pool)
958     {
959         D3D11_TEXTURE2D_DESC texDesc;
960         ZeroMemory(&texDesc, sizeof(texDesc));
961         texDesc.Width = dx_sys->surface_width;
962         texDesc.Height = dx_sys->surface_height;
963         texDesc.MipLevels = 1;
964         texDesc.Format = sys->render;
965         texDesc.SampleDesc.Count = 1;
966         texDesc.MiscFlags = 0;
967         texDesc.ArraySize = dx_sys->surface_count;
968         texDesc.Usage = D3D11_USAGE_DEFAULT;
969         texDesc.BindFlags = D3D11_BIND_DECODER;
970         texDesc.CPUAccessFlags = 0;
971
972         ID3D11Texture2D *p_texture;
973         hr = ID3D11Device_CreateTexture2D( dx_sys->d3ddev, &texDesc, NULL, &p_texture );
974         if (FAILED(hr)) {
975             msg_Err(va, "CreateTexture2D %d failed. (hr=0x%0lx)", dx_sys->surface_count, hr);
976             dx_sys->surface_count = 0;
977             return VLC_EGENERIC;
978         }
979
980         int surface_count = dx_sys->surface_count;
981         for (dx_sys->surface_count = 0; dx_sys->surface_count < surface_count; dx_sys->surface_count++) {
982             sys->extern_pics[dx_sys->surface_count] = NULL;
983             viewDesc.Texture2D.ArraySlice = dx_sys->surface_count;
984
985             hr = ID3D11VideoDevice_CreateVideoDecoderOutputView( dx_sys->d3ddec,
986                                                                  (ID3D11Resource*) p_texture,
987                                                                  &viewDesc,
988                                                                  &dx_sys->hw_surface[dx_sys->surface_count] );
989             if (FAILED(hr)) {
990                 msg_Err(va, "CreateVideoDecoderOutputView %d failed. (hr=0x%0lx)", dx_sys->surface_count, hr);
991                 ID3D11Texture2D_Release(p_texture);
992                 return VLC_EGENERIC;
993             }
994         }
995     }
996     msg_Dbg(va, "ID3D11VideoDecoderOutputView succeed with %d surfaces (%dx%d)",
997             dx_sys->surface_count, dx_sys->surface_width, dx_sys->surface_height);
998
999     D3D11_VIDEO_DECODER_DESC decoderDesc;
1000     ZeroMemory(&decoderDesc, sizeof(decoderDesc));
1001     decoderDesc.Guid = dx_sys->input;
1002     decoderDesc.SampleWidth = fmt->i_width;
1003     decoderDesc.SampleHeight = fmt->i_height;
1004     decoderDesc.OutputFormat = sys->render;
1005
1006     UINT cfg_count;
1007     hr = ID3D11VideoDevice_GetVideoDecoderConfigCount( dx_sys->d3ddec, &decoderDesc, &cfg_count );
1008     if (FAILED(hr)) {
1009         msg_Err(va, "GetVideoDecoderConfigCount failed. (hr=0x%lX)", hr);
1010         return VLC_EGENERIC;
1011     }
1012
1013     /* List all configurations available for the decoder */
1014     D3D11_VIDEO_DECODER_CONFIG cfg_list[cfg_count];
1015     for (unsigned i = 0; i < cfg_count; i++) {
1016         hr = ID3D11VideoDevice_GetVideoDecoderConfig( dx_sys->d3ddec, &decoderDesc, i, &cfg_list[i] );
1017         if (FAILED(hr)) {
1018             msg_Err(va, "GetVideoDecoderConfig failed. (hr=0x%lX)", hr);
1019             return VLC_EGENERIC;
1020         }
1021     }
1022
1023     msg_Dbg(va, "we got %d decoder configurations", cfg_count);
1024
1025     /* Select the best decoder configuration */
1026     int cfg_score = 0;
1027     for (unsigned i = 0; i < cfg_count; i++) {
1028         const D3D11_VIDEO_DECODER_CONFIG *cfg = &cfg_list[i];
1029
1030         /* */
1031         msg_Dbg(va, "configuration[%d] ConfigBitstreamRaw %d",
1032                 i, cfg->ConfigBitstreamRaw);
1033
1034         /* */
1035         int score;
1036         if (cfg->ConfigBitstreamRaw == 1)
1037             score = 1;
1038         else if (codec_id == AV_CODEC_ID_H264 && cfg->ConfigBitstreamRaw == 2)
1039             score = 2;
1040         else
1041             continue;
1042         if (IsEqualGUID(&cfg->guidConfigBitstreamEncryption, &DXVA2_NoEncrypt))
1043             score += 16;
1044
1045         if (cfg_score < score) {
1046             sys->cfg = *cfg;
1047             cfg_score = score;
1048         }
1049     }
1050     if (cfg_score <= 0) {
1051         msg_Err(va, "Failed to find a supported decoder configuration");
1052         return VLC_EGENERIC;
1053     }
1054
1055     /* Create the decoder */
1056     ID3D11VideoDecoder *decoder;
1057     hr = ID3D11VideoDevice_CreateVideoDecoder( dx_sys->d3ddec, &decoderDesc, &sys->cfg, &decoder );
1058     if (FAILED(hr)) {
1059         msg_Err(va, "ID3D11VideoDevice_CreateVideoDecoder failed. (hr=0x%lX)", hr);
1060         dx_sys->decoder = NULL;
1061         return VLC_EGENERIC;
1062     }
1063     dx_sys->decoder = decoder;
1064
1065     msg_Dbg(va, "DxCreateDecoderSurfaces succeed");
1066     return VLC_SUCCESS;
1067 }
1068
1069 static void DxDestroySurfaces(vlc_va_t *va)
1070 {
1071     directx_sys_t *dx_sys = &va->sys->dx_sys;
1072     if (dx_sys->surface_count && !va->sys->b_extern_pool) {
1073         ID3D11Resource *p_texture;
1074         ID3D11VideoDecoderOutputView_GetResource( dx_sys->hw_surface[0], &p_texture );
1075         ID3D11Resource_Release(p_texture);
1076         ID3D11Resource_Release(p_texture);
1077     }
1078 }
1079
1080 static void DestroyPicture(picture_t *picture)
1081 {
1082     picture_sys_t *p_sys = picture->p_sys;
1083     ReleasePictureSys(p_sys);
1084     free(p_sys);
1085     free(picture);
1086 }
1087
1088 static picture_t *DxAllocPicture(vlc_va_t *va, const video_format_t *fmt, unsigned index)
1089 {
1090     vlc_va_sys_t *sys = va->sys;
1091     if (sys->b_extern_pool)
1092         return sys->extern_pics[index];
1093
1094     video_format_t src_fmt = *fmt;
1095     src_fmt.i_chroma = sys->i_chroma;
1096     picture_sys_t *pic_sys = calloc(1, sizeof(*pic_sys));
1097     if (unlikely(pic_sys == NULL))
1098         return NULL;
1099
1100     pic_sys->decoder = sys->dx_sys.hw_surface[index];
1101     ID3D11VideoDecoderOutputView_GetResource(pic_sys->decoder, &pic_sys->resource[KNOWN_DXGI_INDEX]);
1102     pic_sys->context  = sys->d3dctx;
1103
1104     if (sys->procEnumerator)
1105     {
1106         /* the decoder output will be used as a processor input */
1107         D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc = {
1108             .ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D,
1109             .Texture2D.MipSlice = 0,
1110             .Texture2D.ArraySlice = index,
1111         };
1112
1113         HRESULT hr = ID3D11VideoDevice_CreateVideoProcessorInputView(sys->dx_sys.d3ddec,
1114                                                         pic_sys->resource[KNOWN_DXGI_INDEX],
1115                                                         sys->procEnumerator,
1116                                                         &inDesc,
1117                                                         &pic_sys->processorInput);
1118         if (FAILED(hr))
1119         {
1120             msg_Err(va, "Failed to create the processor input ArraySlice=%d. (hr=0x%lX)", inDesc.Texture2D.ArraySlice, hr);
1121             return NULL;
1122         }
1123     }
1124
1125     picture_resource_t res = {
1126         .p_sys      = pic_sys,
1127         .pf_destroy = DestroyPicture,
1128     };
1129     picture_t *pic = picture_NewFromResource(&src_fmt, &res);
1130     if (unlikely(pic == NULL))
1131     {
1132         free(pic_sys);
1133         return NULL;
1134     }
1135     return pic;
1136 }
1137