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