[vlc-devel] [PATCH] d3d11va: add a Direct3D11 decoder using avcodec
Steve Lhomme
robux4 at videolabs.io
Tue May 12 13:43:12 CEST 2015
On Tue, May 12, 2015 at 1:36 PM, Jean-Baptiste Kempf <jb at videolan.org> wrote:
> On 12 May, Steve Lhomme wrote :
>> ---
>> the necessary patch to libav is pending
>>
>> the patch to d3d11.h in mingw-w64 is also pending for approval so a copy is provided in contribs
>>
>> currently outputs NV12 planes, it could output D3D11 surfaces later
>> ---
>> contrib/src/d3d11/d3d11.h | 9859 +++++++++++++++++++++++++++++++++++++++
>> contrib/src/d3d11/rules.mak | 9 +
>
> This part should be in a different patch
OK, I'll split in 1/2 parts.
>> contrib/src/ffmpeg/rules.mak | 2 +-
>
> I don't think this is necessary, since it should be defaulted in libav.
Yes, I just copied how it's done for dxva2. It will produce a nice
warning if it's not detected. That's the main use I think.
>> +#include <libavcodec/avcodec.h>
>> +# define COBJMACROS
>> +# include <libavcodec/d3d11va.h>
>
> Weird indentation.
A lot of code if copied from dxva2.c including the styling.
>> +#include <windows.h>
>> +#include <windowsx.h>
>
> Windowsx.h usage is debatable.
Probably unneeded.
> From here...
>
>> +/* dxva2api.h GUIDs: http://msdn.microsoft.com/en-us/library/windows/desktop/ms697067(v=vs100).aspx
>> + * assume that they are declared in dxva2api.h */
>> +#define MS_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
>> +
>> +#ifdef __MINGW32__
>> +# include <_mingw.h>
>> +
>> +# if !defined(__MINGW64_VERSION_MAJOR)
>> +# undef MS_GUID
>> +# define MS_GUID DEFINE_GUID /* dxva2api.h fails to declare those, redefine as static */
>> +# define DXVA2_E_NEW_VIDEO_DEVICE MAKE_HRESULT(1, 4, 4097)
>> +# else
>> +# include <dxva.h>
>> +# endif
>> +#include <d3d10.h>
>> +
>> +#endif /* __MINGW32__ */
>> +
>> +MS_GUID (DXVA_NoEncrypt, 0x1b81bed0, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);
>> +
>> +DEFINE_GUID(IID_ID3D11VideoDevice, 0x10EC4D5B, 0x975A, 0x4689, 0xB9, 0xE4, 0xD0, 0xAA, 0xC3, 0x0F, 0xE3, 0x33);
>> +DEFINE_GUID(IID_ID3D11VideoContext, 0x61F21C45, 0x3C0E, 0x4a74, 0x9C, 0xEA, 0x67, 0x10, 0x0D, 0x9A, 0xD5, 0xE4);
>> +DEFINE_GUID(IID_IDXGIDevice, 0x54ec77fa, 0x1377, 0x44e6, 0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8, 0x4c);
>> +DEFINE_GUID(IID_ID3D10Multithread, 0x9b7e4e00, 0x342c, 0x4106, 0xa1, 0x9f, 0x4f, 0x27, 0x04, 0xf6, 0x89, 0xf0);
>> +#ifndef NDEBUG
>> +#ifndef __IDXGIDebug_FWD_DEFINED__
>> +#define __IDXGIDebug_FWD_DEFINED__
>> +typedef interface IDXGIDebug IDXGIDebug;
>> +
>> +#endif /* __IDXGIDebug_FWD_DEFINED__ */
>> +
>> +DEFINE_GUID(DXGI_DEBUG_ALL, 0xe48ae283, 0xda80, 0x490b, 0x87, 0xe6, 0x43, 0xe9, 0xa9, 0xcf, 0xda, 0x8);
>> +DEFINE_GUID(DXGI_DEBUG_DX, 0x35cdd7fc, 0x13b2, 0x421d, 0xa5, 0xd7, 0x7e, 0x44, 0x51, 0x28, 0x7d, 0x64);
>> +DEFINE_GUID(DXGI_DEBUG_DXGI, 0x25cddaa4, 0xb1c6, 0x47e1, 0xac, 0x3e, 0x98, 0x87, 0x5b, 0x5a, 0x2e, 0x2a);
>> +DEFINE_GUID(DXGI_DEBUG_APP, 0x6cd6e01, 0x4219, 0x4ebd, 0x87, 0x9, 0x27, 0xed, 0x23, 0x36, 0xc, 0x62);
>> +
>> +typedef
>> +enum DXGI_DEBUG_RLO_FLAGS
>> + {
>> + DXGI_DEBUG_RLO_SUMMARY = 0x1,
>> + DXGI_DEBUG_RLO_DETAIL = 0x2,
>> + DXGI_DEBUG_RLO_ALL = 0x3
>> + } DXGI_DEBUG_RLO_FLAGS;
>> +
>> +#ifndef __IDXGIDebug_INTERFACE_DEFINED__
>> +#define __IDXGIDebug_INTERFACE_DEFINED__
>> +
>> +/* interface IDXGIDebug */
>> +/* [unique][local][object][uuid] */
>> +
>> +
>> +EXTERN_C const IID IID_IDXGIDebug;
>> +
>> +#if defined(__cplusplus) && !defined(CINTERFACE)
>> +
>> + MIDL_INTERFACE("119E7452-DE9E-40fe-8806-88F90C12B441")
>> + IDXGIDebug : public IUnknown
>> + {
>> + public:
>> + virtual HRESULT STDMETHODCALLTYPE ReportLiveObjects(
>> + GUID apiid,
>> + DXGI_DEBUG_RLO_FLAGS flags) = 0;
>> +
>> + };
>> +
>> +
>> +#else /* C style interface */
>> +
>> + typedef struct IDXGIDebugVtbl
>> + {
>> + BEGIN_INTERFACE
>> +
>> + HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
>> + IDXGIDebug * This,
>> + /* [in] */ REFIID riid,
>> + /* [annotation][iid_is][out] */
>> + void **ppvObject);
>> +
>> + ULONG ( STDMETHODCALLTYPE *AddRef )(
>> + IDXGIDebug * This);
>> +
>> + ULONG ( STDMETHODCALLTYPE *Release )(
>> + IDXGIDebug * This);
>> +
>> + HRESULT ( STDMETHODCALLTYPE *ReportLiveObjects )(
>> + IDXGIDebug * This,
>> + GUID apiid,
>> + DXGI_DEBUG_RLO_FLAGS flags);
>> +
>> + END_INTERFACE
>> + } IDXGIDebugVtbl;
>> +
>> + interface IDXGIDebug
>> + {
>> + CONST_VTBL struct IDXGIDebugVtbl *lpVtbl;
>> + };
>> +
>> +
>> +
>> +#ifdef COBJMACROS
>> +
>> +
>> +#define IDXGIDebug_QueryInterface(This,riid,ppvObject) \
>> + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
>> +
>> +#define IDXGIDebug_AddRef(This) \
>> + ( (This)->lpVtbl -> AddRef(This) )
>> +
>> +#define IDXGIDebug_Release(This) \
>> + ( (This)->lpVtbl -> Release(This) )
>> +
>> +
>> +#define IDXGIDebug_ReportLiveObjects(This,apiid,flags) \
>> + ( (This)->lpVtbl -> ReportLiveObjects(This,apiid,flags) )
>> +
>> +#endif /* COBJMACROS */
>> +
>> +
>> +#endif /* C style interface */
>> +
>> +
>> +
>> +
>> +#endif /* __IDXGIDebug_INTERFACE_DEFINED__ */
>> +
>> +DEFINE_GUID(IID_IDXGIDebug,0x119E7452,0xDE9E,0x40fe,0x88,0x06,0x88,0xF9,0x0C,0x12,0xB4,0x41);
>> +
>> +#ifndef __ID3D11Debug_FWD_DEFINED__
>> +#define __ID3D11Debug_FWD_DEFINED__
>> +typedef interface ID3D11Debug ID3D11Debug;
>> +
>> +#endif /* __ID3D11Debug_FWD_DEFINED__ */
>> +
>> +typedef
>> +enum D3D11_RLDO_FLAGS
>> + {
>> + D3D11_RLDO_SUMMARY = 0x1,
>> + D3D11_RLDO_DETAIL = 0x2
>> + } D3D11_RLDO_FLAGS;
>> +
>> +#ifndef __ID3D11Debug_INTERFACE_DEFINED__
>> +#define __ID3D11Debug_INTERFACE_DEFINED__
>> +
>> +/* interface ID3D11Debug */
>> +/* [unique][local][object][uuid] */
>> +
>> +
>> +#if defined(__cplusplus) && !defined(CINTERFACE)
>> +
>> + MIDL_INTERFACE("79cf2233-7536-4948-9d36-1e4692dc5760")
>> + ID3D11Debug : public IUnknown
>> + {
>> + public:
>> + virtual HRESULT STDMETHODCALLTYPE SetFeatureMask(
>> + UINT Mask) = 0;
>> +
>> + virtual UINT STDMETHODCALLTYPE GetFeatureMask( void) = 0;
>> +
>> + virtual HRESULT STDMETHODCALLTYPE SetPresentPerRenderOpDelay(
>> + UINT Milliseconds) = 0;
>> +
>> + virtual UINT STDMETHODCALLTYPE GetPresentPerRenderOpDelay( void) = 0;
>> +
>> + virtual HRESULT STDMETHODCALLTYPE SetSwapChain(
>> + /* [annotation] */
>> + _In_opt_ IDXGISwapChain *pSwapChain) = 0;
>> +
>> + virtual HRESULT STDMETHODCALLTYPE GetSwapChain(
>> + /* [annotation] */
>> + _Out_ IDXGISwapChain **ppSwapChain) = 0;
>> +
>> + virtual HRESULT STDMETHODCALLTYPE ValidateContext(
>> + /* [annotation] */
>> + _In_ ID3D11DeviceContext *pContext) = 0;
>> +
>> + virtual HRESULT STDMETHODCALLTYPE ReportLiveDeviceObjects(
>> + D3D11_RLDO_FLAGS Flags) = 0;
>> +
>> + virtual HRESULT STDMETHODCALLTYPE ValidateContextForDispatch(
>> + /* [annotation] */
>> + _In_ ID3D11DeviceContext *pContext) = 0;
>> +
>> + };
>> +
>> +
>> +#else /* C style interface */
>> +
>> + typedef struct ID3D11DebugVtbl
>> + {
>> + BEGIN_INTERFACE
>> +
>> + HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
>> + ID3D11Debug * This,
>> + /* [in] */ REFIID riid,
>> + /* [annotation][iid_is][out] */
>> + void **ppvObject);
>> +
>> + ULONG ( STDMETHODCALLTYPE *AddRef )(
>> + ID3D11Debug * This);
>> +
>> + ULONG ( STDMETHODCALLTYPE *Release )(
>> + ID3D11Debug * This);
>> +
>> + HRESULT ( STDMETHODCALLTYPE *SetFeatureMask )(
>> + ID3D11Debug * This,
>> + UINT Mask);
>> +
>> + UINT ( STDMETHODCALLTYPE *GetFeatureMask )(
>> + ID3D11Debug * This);
>> +
>> + HRESULT ( STDMETHODCALLTYPE *SetPresentPerRenderOpDelay )(
>> + ID3D11Debug * This,
>> + UINT Milliseconds);
>> +
>> + UINT ( STDMETHODCALLTYPE *GetPresentPerRenderOpDelay )(
>> + ID3D11Debug * This);
>> +
>> + HRESULT ( STDMETHODCALLTYPE *SetSwapChain )(
>> + ID3D11Debug * This,
>> + /* [annotation] */
>> + _In_opt_ IDXGISwapChain *pSwapChain);
>> +
>> + HRESULT ( STDMETHODCALLTYPE *GetSwapChain )(
>> + ID3D11Debug * This,
>> + /* [annotation] */
>> + _Out_ IDXGISwapChain **ppSwapChain);
>> +
>> + HRESULT ( STDMETHODCALLTYPE *ValidateContext )(
>> + ID3D11Debug * This,
>> + /* [annotation] */
>> + _In_ ID3D11DeviceContext *pContext);
>> +
>> + HRESULT ( STDMETHODCALLTYPE *ReportLiveDeviceObjects )(
>> + ID3D11Debug * This,
>> + D3D11_RLDO_FLAGS Flags);
>> +
>> + HRESULT ( STDMETHODCALLTYPE *ValidateContextForDispatch )(
>> + ID3D11Debug * This,
>> + /* [annotation] */
>> + _In_ ID3D11DeviceContext *pContext);
>> +
>> + END_INTERFACE
>> + } ID3D11DebugVtbl;
>> +
>> + interface ID3D11Debug
>> + {
>> + CONST_VTBL struct ID3D11DebugVtbl *lpVtbl;
>> + };
>> +
>> +
>> +
>> +#ifdef COBJMACROS
>> +
>> +
>> +#define ID3D11Debug_QueryInterface(This,riid,ppvObject) \
>> + ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
>> +
>> +#define ID3D11Debug_AddRef(This) \
>> + ( (This)->lpVtbl -> AddRef(This) )
>> +
>> +#define ID3D11Debug_Release(This) \
>> + ( (This)->lpVtbl -> Release(This) )
>> +
>> +
>> +#define ID3D11Debug_SetFeatureMask(This,Mask) \
>> + ( (This)->lpVtbl -> SetFeatureMask(This,Mask) )
>> +
>> +#define ID3D11Debug_GetFeatureMask(This) \
>> + ( (This)->lpVtbl -> GetFeatureMask(This) )
>> +
>> +#define ID3D11Debug_SetPresentPerRenderOpDelay(This,Milliseconds) \
>> + ( (This)->lpVtbl -> SetPresentPerRenderOpDelay(This,Milliseconds) )
>> +
>> +#define ID3D11Debug_GetPresentPerRenderOpDelay(This) \
>> + ( (This)->lpVtbl -> GetPresentPerRenderOpDelay(This) )
>> +
>> +#define ID3D11Debug_SetSwapChain(This,pSwapChain) \
>> + ( (This)->lpVtbl -> SetSwapChain(This,pSwapChain) )
>> +
>> +#define ID3D11Debug_GetSwapChain(This,ppSwapChain) \
>> + ( (This)->lpVtbl -> GetSwapChain(This,ppSwapChain) )
>> +
>> +#define ID3D11Debug_ValidateContext(This,pContext) \
>> + ( (This)->lpVtbl -> ValidateContext(This,pContext) )
>> +
>> +#define ID3D11Debug_ReportLiveDeviceObjects(This,Flags) \
>> + ( (This)->lpVtbl -> ReportLiveDeviceObjects(This,Flags) )
>> +
>> +#define ID3D11Debug_ValidateContextForDispatch(This,pContext) \
>> + ( (This)->lpVtbl -> ValidateContextForDispatch(This,pContext) )
>> +
>> +#endif /* COBJMACROS */
>> +
>> +
>> +#endif /* C style interface */
>> +
>> +
>> +
>> +
>> +#endif /* __ID3D11Debug_INTERFACE_DEFINED__ */
>> +
>> +DEFINE_GUID(IID_ID3D11Debug,0x79cf2233,0x7536,0x4948,0x9d,0x36,0x1e,0x46,0x92,0xdc,0x57,0x60);
>> +
>> +#endif
>> +
>
> ... to here, this has nothing to do in our codebase.
>
>
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_MPEG2_MOCOMP, 0xe6a9f44b, 0x61b0, 0x4563,0x9e,0xa4,0x63,0xd2,0xa3,0xc6,0xfe,0x66);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_MPEG2_IDCT, 0xbf22ad00, 0x03ea, 0x4690,0x80,0x77,0x47,0x33,0x46,0x20,0x9b,0x7e);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_MPEG2_VLD, 0xee27417f, 0x5e28, 0x4e65,0xbe,0xea,0x1d,0x26,0xb5,0x08,0xad,0xc9);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_MPEG1_VLD, 0x6f3ec719, 0x3735, 0x42cc,0x80,0x63,0x65,0xcc,0x3c,0xb3,0x66,0x16);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_MPEG2and1_VLD, 0x86695f12, 0x340e, 0x4f04,0x9f,0xd3,0x92,0x53,0xdd,0x32,0x74,0x60);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_H264_MOCOMP_NOFGT, 0x1b81be64, 0xa0c7, 0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_H264_MOCOMP_FGT, 0x1b81be65, 0xa0c7, 0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_H264_IDCT_NOFGT, 0x1b81be66, 0xa0c7, 0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_H264_IDCT_FGT, 0x1b81be67, 0xa0c7, 0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_H264_VLD_NOFGT, 0x1b81be68, 0xa0c7, 0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_H264_VLD_FGT, 0x1b81be69, 0xa0c7, 0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(DXVA_Intel_H264_NoFGT_ClearVideo, 0x604F8E68, 0x4951, 0x4c54,0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_H264_VLD_WITHFMOASO_NOFGT, 0xd5f04ff9, 0x3418,0x45d8,0x95,0x61,0x32,0xa7,0x6a,0xae,0x2d,0xdd);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_H264_VLD_STEREO_PROGRESSIVE_NOFGT, 0xd79be8da, 0x0cf1,0x4c81,0xb8,0x2a,0x69,0xa4,0xe2,0x36,0xf4,0x3d);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_H264_VLD_STEREO_NOFGT, 0xf9aaccbb, 0xc2b6,0x4cfc,0x87,0x79,0x57,0x07,0xb1,0x76,0x05,0x52);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_H264_VLD_MULTIVIEW_NOFGT, 0x705b9d82, 0x76cf,0x49d6,0xb7,0xe6,0xac,0x88,0x72,0xdb,0x01,0x3c);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_WMV8_POSTPROC, 0x1b81be80, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_WMV8_MOCOMP, 0x1b81be81, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_WMV9_POSTPROC, 0x1b81be90, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_WMV9_MOCOMP, 0x1b81be91, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_WMV9_IDCT, 0x1b81be94, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_VC1_POSTPROC, 0x1b81beA0, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_VC1_MOCOMP, 0x1b81beA1, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_VC1_IDCT, 0x1b81beA2, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_VC1_VLD, 0x1b81beA3, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_VC1_D2010, 0x1b81beA4, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_MPEG4PT2_VLD_SIMPLE, 0xefd64d74, 0xc9e8,0x41d7,0xa5,0xe9,0xe9,0xb0,0xe3,0x9f,0xa3,0x19);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_MPEG4PT2_VLD_ADVSIMPLE_NOGMC, 0xed418a9f, 0x010d,0x4eda,0x9a,0xe3,0x9a,0x65,0x35,0x8d,0x8d,0x2e);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_MPEG4PT2_VLD_ADVSIMPLE_GMC, 0xab998b5b, 0x4258,0x44a9,0x9f,0xeb,0x94,0xe5,0x97,0xa6,0xba,0xae);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_HEVC_VLD_MAIN, 0x5b11d51b, 0x2f4c,0x4452,0xbc,0xc3,0x09,0xf2,0xa1,0x16,0x0c,0xc0);
>> +DEFINE_GUID(D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10, 0x107af0e0, 0xef1a,0x4d19,0xab,0xa8,0x67,0xa1,0x63,0x07,0x3d,0x13);
>> +
>> +/* */
>> +typedef struct {
>> + const char *name;
>> + const GUID *guid;
>> + int codec;
>> + const int *p_profiles; // NULL or ends with 0
>> +} d3d11va_mode_t;
>> +
>> +static const int PROF_MPEG2_SIMPLE[] = { FF_PROFILE_MPEG2_SIMPLE, 0 };
>> +static const int PROF_MPEG2_MAIN[] = { FF_PROFILE_MPEG2_SIMPLE,
>> + FF_PROFILE_MPEG2_MAIN, 0 };
>> +static const int PROF_H264_HIGH[] = { FF_PROFILE_H264_CONSTRAINED_BASELINE,
>> + FF_PROFILE_H264_MAIN,
>> + FF_PROFILE_H264_HIGH, 0 };
>> +static const int PROF_HEVC_MAIN[] = { FF_PROFILE_HEVC_MAIN, 0 };
>> +static const int PROF_HEVC_MAIN10[] = { FF_PROFILE_HEVC_MAIN,
>> + FF_PROFILE_HEVC_MAIN_10, 0 };
>> +
>> +/* XXX Prefered modes must come first */
>> +static const d3d11va_mode_t d3d11va_modes[] = {
>> + /* MPEG-1/2 */
>> + { "MPEG-2 variable-length decoder", &D3D11_DECODER_PROFILE_MPEG2_VLD, AV_CODEC_ID_MPEG2VIDEO, PROF_MPEG2_SIMPLE },
>> + { "MPEG-2 & MPEG-1 variable-length decoder", &D3D11_DECODER_PROFILE_MPEG2and1_VLD, AV_CODEC_ID_MPEG2VIDEO, PROF_MPEG2_MAIN },
>> + { "MPEG-2 & MPEG-1 variable-length decoder", &D3D11_DECODER_PROFILE_MPEG2and1_VLD, AV_CODEC_ID_MPEG1VIDEO, NULL },
>> + { "MPEG-2 motion compensation", &D3D11_DECODER_PROFILE_MPEG2_MOCOMP, 0, NULL },
>> + { "MPEG-2 inverse discrete cosine transform", &D3D11_DECODER_PROFILE_MPEG2_IDCT, 0, NULL },
>> +
>> + /* MPEG-1 http://download.microsoft.com/download/B/1/7/B172A3C8-56F2-4210-80F1-A97BEA9182ED/DXVA_MPEG1_VLD.pdf */
>> + { "MPEG-1 variable-length decoder, no D pictures", &D3D11_DECODER_PROFILE_MPEG1_VLD, 0, NULL },
>> +
>> + /* H.264 http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=3d1c290b-310b-4ea2-bf76-714063a6d7a6 */
>> + { "H.264 variable-length decoder, film grain technology", &D3D11_DECODER_PROFILE_H264_VLD_FGT, AV_CODEC_ID_H264, PROF_H264_HIGH },
>> + { "H.264 variable-length decoder, no film grain technology", &D3D11_DECODER_PROFILE_H264_VLD_NOFGT, AV_CODEC_ID_H264, PROF_H264_HIGH },
>> + { "H.264 variable-length decoder, no film grain technology, FMO/ASO", &D3D11_DECODER_PROFILE_H264_VLD_WITHFMOASO_NOFGT, AV_CODEC_ID_H264, PROF_H264_HIGH },
>> +
>> + { "H.264 inverse discrete cosine transform, film grain technology", &D3D11_DECODER_PROFILE_H264_IDCT_FGT, 0, NULL },
>> + { "H.264 inverse discrete cosine transform, no film grain technology", &D3D11_DECODER_PROFILE_H264_IDCT_NOFGT, 0, NULL },
>> +
>> + { "H.264 motion compensation, film grain technology", &D3D11_DECODER_PROFILE_H264_MOCOMP_FGT, 0, NULL },
>> + { "H.264 motion compensation, no film grain technology", &D3D11_DECODER_PROFILE_H264_MOCOMP_NOFGT, 0, NULL },
>> +
>> + /* http://download.microsoft.com/download/2/D/0/2D02E72E-7890-430F-BA91-4A363F72F8C8/DXVA_H264_MVC.pdf */
>> + { "H.264 stereo high profile, mbs flag set", &D3D11_DECODER_PROFILE_H264_VLD_STEREO_PROGRESSIVE_NOFGT, 0, NULL },
>> + { "H.264 stereo high profile", &D3D11_DECODER_PROFILE_H264_VLD_STEREO_NOFGT, 0, NULL },
>> + { "H.264 multiview high profile", &D3D11_DECODER_PROFILE_H264_VLD_MULTIVIEW_NOFGT, 0, NULL },
>> +
>> + /* WMV */
>> + { "Windows Media Video 8 motion compensation", &D3D11_DECODER_PROFILE_WMV8_MOCOMP, 0, NULL },
>> + { "Windows Media Video 8 post processing", &D3D11_DECODER_PROFILE_WMV8_POSTPROC, 0, NULL },
>> +
>> + { "Windows Media Video 9 IDCT", &D3D11_DECODER_PROFILE_WMV9_IDCT, 0, NULL },
>> + { "Windows Media Video 9 motion compensation", &D3D11_DECODER_PROFILE_WMV9_MOCOMP, 0, NULL },
>> + { "Windows Media Video 9 post processing", &D3D11_DECODER_PROFILE_WMV9_POSTPROC, 0, NULL },
>> +
>> + /* VC-1 */
>> + { "VC-1 variable-length decoder", &D3D11_DECODER_PROFILE_VC1_VLD, AV_CODEC_ID_VC1, NULL },
>> + { "VC-1 variable-length decoder", &D3D11_DECODER_PROFILE_VC1_VLD, AV_CODEC_ID_WMV3, NULL },
>> + { "VC-1 variable-length decoder", &D3D11_DECODER_PROFILE_VC1_D2010, AV_CODEC_ID_VC1, NULL },
>> + { "VC-1 variable-length decoder", &D3D11_DECODER_PROFILE_VC1_D2010, AV_CODEC_ID_WMV3, NULL },
>> +
>> + { "VC-1 inverse discrete cosine transform", &D3D11_DECODER_PROFILE_VC1_IDCT, 0, NULL },
>> + { "VC-1 motion compensation", &D3D11_DECODER_PROFILE_VC1_MOCOMP, 0, NULL },
>> + { "VC-1 post processing", &D3D11_DECODER_PROFILE_VC1_POSTPROC, 0, NULL },
>> +
>> + /* Xvid/Divx: TODO */
>> + { "MPEG-4 Part 2 variable-length decoder, Simple Profile", &D3D11_DECODER_PROFILE_MPEG4PT2_VLD_SIMPLE, 0, NULL },
>> + { "MPEG-4 Part 2 variable-length decoder, Simple&Advanced Profile, no GMC", &D3D11_DECODER_PROFILE_MPEG4PT2_VLD_ADVSIMPLE_NOGMC, 0, NULL },
>> + { "MPEG-4 Part 2 variable-length decoder, Simple&Advanced Profile, GMC", &D3D11_DECODER_PROFILE_MPEG4PT2_VLD_ADVSIMPLE_GMC, 0, NULL },
>> +
>> + /* HEVC */
>> + { "HEVC Main profile", &D3D11_DECODER_PROFILE_HEVC_VLD_MAIN, AV_CODEC_ID_HEVC, PROF_HEVC_MAIN },
>> + { "HEVC Main 10 profile", &D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10, AV_CODEC_ID_HEVC, PROF_HEVC_MAIN10 },
>> +
>> + { NULL, NULL, 0, NULL }
>> +};
>> +
>> +static const d3d11va_mode_t *Dxva2FindMode(const GUID *guid)
>> +{
>> + for (unsigned i = 0; d3d11va_modes[i].name; i++) {
>> + if (IsEqualGUID(d3d11va_modes[i].guid, guid))
>> + return &d3d11va_modes[i];
>> + }
>> + return NULL;
>> +}
>> +
>> +/* */
>> +typedef struct {
>> + const char *name;
>> + DXGI_FORMAT format;
>> + vlc_fourcc_t codec;
>> +} d3d_format_t;
>> +/* XXX Prefered format must come first */
>> +static const d3d_format_t d3d_formats[] = {
>> + { "NV12", DXGI_FORMAT_NV12, VLC_CODEC_NV12 },
>> + { "I420L", DXGI_FORMAT_P010, VLC_CODEC_I420_10L },
>> + { "YUY2", DXGI_FORMAT_YUY2, VLC_CODEC_I420_10L },
>> + { "B8G8R8A8", DXGI_FORMAT_B8G8R8A8_UNORM, VLC_CODEC_BGRA },
>> +
>> + { NULL, 0, 0 }
>> +};
>> +
>> +/* */
>> +typedef struct {
>> + ID3D11VideoDecoderOutputView *d3d;
>> + int refcount;
>> + unsigned int order;
>> + vlc_mutex_t *p_lock;
>> +} vlc_va_surface_t;
>> +
>> +#define VA_D3D11_MAX_SURFACE_COUNT (64)
>> +struct vlc_va_sys_t
>> +{
>> + int codec_id;
>> + int width;
>> + int height;
>> +
>> + vlc_mutex_t surface_lock;
>> +
>> + /* DLL */
>> + HINSTANCE hd3d11_dll;
>> +#ifndef NDEBUG
>> + HINSTANCE dxgidebug_dll;
>> +#endif
>> +
>> + /* Direct3D */
>> + ID3D11Device *d3ddev;
>> + ID3D11DeviceContext *d3dctx;
>> +
>> + /* Device manager */
>> + UINT token;
>> +
>> + /* Video service */
>> + ID3D11VideoDevice *d3dvidev;
>> + ID3D11VideoContext *d3dvidctx;
>> + GUID input;
>> + DXGI_FORMAT render;
>> +
>> + /* Video decoder */
>> + D3D11_VIDEO_DECODER_CONFIG cfg;
>> + ID3D11VideoDecoder *decoder;
>> +
>> + /* avcodec internals */
>> + struct AVD3D11VAContext hw;
>> +
>> + /* Extraction */
>> + ID3D11Resource *staging;
>> + copy_cache_t *p_copy_cache;
>> +
>> + /* */
>> + int surface_count;
>> + int surface_order;
>> + int surface_width;
>> + int surface_height;
>> + vlc_fourcc_t surface_chroma;
>> +
>> + int thread_count;
>> +
>> + vlc_va_surface_t surface[VA_D3D11_MAX_SURFACE_COUNT];
>> + ID3D11VideoDecoderOutputView* hw_surface[VA_D3D11_MAX_SURFACE_COUNT];
>> +};
>> +
>> +/* */
>> +static int D3dCreateDevice(vlc_va_t *);
>> +static void D3dDestroyDevice(vlc_va_sys_t *);
>> +static char *DxDescribe(vlc_va_sys_t *);
>> +
>> +#if 0
>> +static int D3dCreateDeviceManager(vlc_va_t *);
>> +static void D3dDestroyDeviceManager(vlc_va_sys_t *);
>> +#endif
>> +
>> +static int DxCreateVideoService(vlc_va_t *);
>> +static void DxDestroyVideoService(vlc_va_sys_t *);
>> +static int DxFindVideoServiceConversion(vlc_va_t *, GUID *input, DXGI_FORMAT *output, const es_format_t *fmt);
>> +
>> +static int DxCreateVideoDecoder(vlc_va_t *,
>> + int codec_id, const video_format_t *, bool);
>> +static void DxDestroyVideoDecoder(vlc_va_sys_t *);
>> +static int DxResetVideoDecoder(vlc_va_t *);
>> +
>> +static bool profile_supported(const d3d11va_mode_t *mode, const es_format_t *fmt);
>> +
>> +/* */
>> +static int Setup(vlc_va_t *va, AVCodecContext *avctx, vlc_fourcc_t *chroma)
>> +{
>> + vlc_va_sys_t *sys = va->sys;
>> +
>> + if (sys->width == avctx->coded_width && sys->height == avctx->coded_height
>> + && sys->decoder != NULL)
>> + goto ok;
>> +
>> + /* */
>> + DxDestroyVideoDecoder(sys);
>> +
>> + avctx->hwaccel_context = NULL;
>> + *chroma = 0;
>> + if (avctx->coded_width <= 0 || avctx->coded_height <= 0)
>> + return VLC_EGENERIC;
>> +
>> + /* FIXME transmit a video_format_t by VaSetup directly */
>> + video_format_t fmt;
>> + memset(&fmt, 0, sizeof(fmt));
>> + fmt.i_width = avctx->coded_width;
>> + fmt.i_height = avctx->coded_height;
>> +
>> + if (DxCreateVideoDecoder(va, sys->codec_id, &fmt, avctx->active_thread_type & FF_THREAD_FRAME))
>> + return VLC_EGENERIC;
>> + /* */
>> + sys->hw.decoder = sys->decoder;
>> + sys->hw.video_context = sys->d3dvidctx;
>> + sys->hw.cfg = &sys->cfg;
>> + sys->hw.surface_count = sys->surface_count;
>> + sys->hw.surface = sys->hw_surface;
>> +
>> + /* */
>> +ok:
>> + avctx->hwaccel_context = &sys->hw;
>> + *chroma = VLC_CODEC_NV12; /* TODO use an opaque format for direct rendering */
>> +
>> + return VLC_SUCCESS;
>> +}
>> +
>> +
>> +static int Extract(vlc_va_t *va, picture_t *picture, uint8_t *data)
>> +{
>> + vlc_va_sys_t *sys = va->sys;
>> + ID3D11VideoDecoderOutputView *d3d = (ID3D11VideoDecoderOutputView*)(uintptr_t)data;
>> + ID3D11Resource *p_texture = NULL;
>> + D3D11_TEXTURE2D_DESC texDesc;
>> + D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
>> + D3D11_MAPPED_SUBRESOURCE mappedResource;
>> + HRESULT hr;
>> +
>> + assert( picture->format.i_chroma == VLC_CODEC_NV12);
>> +
>> + ID3D11VideoDecoderOutputView_GetDesc( d3d, &viewDesc );
>> +
>> + ID3D11VideoDecoderOutputView_GetResource( d3d, &p_texture );
>> + if (!p_texture) {
>> + msg_Err(va, "Failed to get the texture of the outputview." );
>> + goto error;
>> + }
>> +
>> + ID3D11Texture2D_GetDesc( (ID3D11Texture2D*) p_texture, &texDesc);
>> +
>> + /* extract to NV12 planes */
>> + ID3D11DeviceContext_CopySubresourceRegion(sys->d3dctx, sys->staging, 0, 0, 0, 0,
>> + p_texture, viewDesc.Texture2D.ArraySlice, NULL);
>> +
>> + hr = ID3D11DeviceContext_Map(sys->d3dctx, sys->staging, 0, D3D11_MAP_READ, 0, &mappedResource);
>> + if (FAILED(hr)) {
>> + msg_Err(va, "Failed to map the texture surface pixels (hr=0x%0lx)", hr );
>> + goto error;
>> + }
>> +
>> + uint8_t *plane[2] = {
>> + mappedResource.pData,
>> + (uint8_t*)mappedResource.pData + mappedResource.RowPitch * texDesc.Height,
>> + };
>> + size_t pitch[2] = {
>> + mappedResource.RowPitch,
>> + mappedResource.RowPitch,
>> + };
>> + CopyFromNv12ToNv12(picture, plane, pitch, texDesc.Width, texDesc.Height, sys->p_copy_cache );
>> +
>> + ID3D11DeviceContext_Unmap(sys->d3dctx, sys->staging, 0);
>> +
>> + if (p_texture!=NULL)
>> + ID3D11Resource_Release(p_texture);
>> + return VLC_SUCCESS;
>> +
>> +error:
>> + if (p_texture!=NULL)
>> + ID3D11Resource_Release(p_texture);
>> + return VLC_EGENERIC;
>> +}
>> +
>> +/* FIXME it is nearly common with VAAPI */
>> +static int Get(vlc_va_t *va, picture_t *pic, uint8_t **data)
>> +{
>> + vlc_va_sys_t *sys = va->sys;
>> +
>> +#if TODO
>> + /* Check the device */
>> + /* see MFCreateDXGIDeviceManager in mfplat.dll, not avail in Win7 */
>> + HRESULT hr = IDirect3DDeviceManager9_TestDevice(sys->devmng, sys->device);
>> + if (hr == DXVA2_E_NEW_VIDEO_DEVICE) {
>> + if (DxResetVideoDecoder(va))
>> + return VLC_EGENERIC;
>> + } else if (FAILED(hr)) {
>> + msg_Err(va, "IDirect3DDeviceManager9_TestDevice %u", (unsigned)hr);
>> + return VLC_EGENERIC;
>> + }
>> +#endif
>> +
>> + vlc_mutex_lock( &sys->surface_lock );
>> +
>> + /* Grab an unused surface, in case none are, try the oldest
>> + * XXX using the oldest is a workaround in case a problem happens with libavcodec */
>> + int i, old;
>> + for (i = 0, old = 0; i < sys->surface_count; i++) {
>> + vlc_va_surface_t *surface = &sys->surface[i];
>> +
>> + if (!surface->refcount)
>> + break;
>> +
>> + if (surface->order < sys->surface[old].order)
>> + old = i;
>> + }
>> + if (i >= sys->surface_count)
>> + i = old;
>> +
>> + vlc_va_surface_t *surface = &sys->surface[i];
>> +
>> + surface->refcount = 1;
>> + surface->order = sys->surface_order++;
>> + *data = (void *)surface->d3d;
>> + pic->context = surface;
>> +
>> + vlc_mutex_unlock( &sys->surface_lock );
>> +
>> + return VLC_SUCCESS;
>> +}
>> +
>> +static void Release(void *opaque, uint8_t *data)
>> +{
>> + picture_t *pic = opaque;
>> + vlc_va_surface_t *surface = pic->context;
>> + vlc_mutex_lock( surface->p_lock );
>> +
>> + surface->refcount--;
>> + pic->context = NULL;
>> + picture_Release(pic);
>> + (void) data;
>> +
>> + vlc_mutex_unlock( surface->p_lock );
>> +}
>> +
>> +static void Close(vlc_va_t *va, AVCodecContext *ctx)
>> +{
>> + vlc_va_sys_t *sys = va->sys;
>> +
>> + (void) ctx;
>> + DxDestroyVideoDecoder(sys);
>> + DxDestroyVideoService(sys);
>> +#if 0
>> + D3dDestroyDeviceManager(sys);
>> +#endif
>> + D3dDestroyDevice(sys);
>> +
>> + if (sys->p_copy_cache!=NULL) {
>> + CopyCleanCache(sys->p_copy_cache);
>> + free( sys->p_copy_cache );
>> + }
>> +
>> + if (sys->hd3d11_dll)
>> + FreeLibrary(sys->hd3d11_dll);
>> +#ifndef NDEBUG
>> + if (sys->dxgidebug_dll)
>> + FreeLibrary(sys->dxgidebug_dll);
>> +#endif
>> + vlc_mutex_destroy( &sys->surface_lock );
>> +
>> + free((char *)va->description);
>> + free(sys);
>> +}
>> +
>> +static int Open(vlc_va_t *va, AVCodecContext *ctx, enum PixelFormat pix_fmt,
>> + const es_format_t *fmt, picture_sys_t *p_sys)
>> +{
>> + int err = VLC_EGENERIC;
>> +
>> + if (pix_fmt != AV_PIX_FMT_D3D11VA_VLD)
>> + return VLC_EGENERIC;
>> +
>> + VLC_UNUSED(p_sys);
>> +
>> + vlc_va_sys_t *sys = calloc(1, sizeof (*sys));
>> + if (unlikely(sys == NULL))
>> + return VLC_ENOMEM;
>> +
>> + sys->p_copy_cache = calloc(1, sizeof(*sys->p_copy_cache));
>> + if (!sys->p_copy_cache) {
>> + err = VLC_ENOMEM;
>> + goto error;
>> + }
>> + CopyInitCache( sys->p_copy_cache, fmt->video.i_width );
>> +
>> + va->sys = sys;
>> + sys->codec_id = ctx->codec_id;
>> +
>> + vlc_mutex_init( &sys->surface_lock );
>> +
>> + /* Load dll*/
>> + sys->hd3d11_dll = LoadLibrary(TEXT("D3D11.DLL"));
>> + if (!sys->hd3d11_dll) {
>> + msg_Warn(va, "cannot load d3d11.dll");
>> + goto error;
>> + }
>> + msg_Dbg(va, "DLLs loaded");
>> +
>> +#ifndef NDEBUG
>> + sys->dxgidebug_dll = LoadLibrary(TEXT("DXGIDEBUG.DLL"));
>> +#endif
>> +
>> + sys->d3ddev = NULL;
>> +
>> + if (sys->d3ddev) {
>> + msg_Dbg(va, "Reusing D3D11 device");
>> + } else {
>> + /* */
>> + if (D3dCreateDevice(va)) {
>> + msg_Err(va, "Failed to create Direct3D device");
>> + goto error;
>> + }
>> + msg_Dbg(va, "D3dCreateDevice succeed");
>> + }
>> +
>> +#if 0
>> + if (D3dCreateDeviceManager(va)) {
>> + msg_Err(va, "D3dCreateDeviceManager failed");
>> + goto error;
>> + }
>> +#endif
>> +
>> + if (DxCreateVideoService(va)) {
>> + msg_Err(va, "DxCreateVideoService failed");
>> + goto error;
>> + }
>> +
>> + /* */
>> + if (DxFindVideoServiceConversion(va, &sys->input, &sys->render, fmt)) {
>> + msg_Err(va, "DxFindVideoServiceConversion failed");
>> + goto error;
>> + }
>> +
>> + sys->thread_count = ctx->thread_count;
>> +
>> + /* TODO print the hardware name/vendor for debugging purposes */
>> + va->description = DxDescribe(sys);
>> + va->setup = Setup;
>> + va->get = Get;
>> + va->release = Release;
>> + va->extract = Extract;
>> + return VLC_SUCCESS;
>> +
>> +error:
>> + Close(va, ctx);
>> + return err;
>> +}
>> +/* */
>> +
>> +/**
>> + * It creates a Direct3D device usable for decoding
>> + */
>> +static int D3dCreateDevice(vlc_va_t *va)
>> +{
>> + vlc_va_sys_t *sys = va->sys;
>> + HRESULT hr;
>> +
>> + /* */
>> + PFN_D3D11_CREATE_DEVICE pf_CreateDevice;
>> + pf_CreateDevice = (void *)GetProcAddress(sys->hd3d11_dll, "D3D11CreateDevice");
>> + if (!pf_CreateDevice) {
>> + msg_Err(va, "Cannot locate reference to D3D11CreateDevice ABI in DLL");
>> + return VLC_EGENERIC;
>> + }
>> +
>> + UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
>> +# if !defined(NDEBUG) //&& defined(_MSC_VER)
>> + creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
>> +# endif
>> +
>> + /* */
>> + ID3D11Device *d3ddev;
>> + ID3D11DeviceContext *d3dctx;
>> + hr = pf_CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL,
>> + creationFlags, NULL, 0,
>> + D3D11_SDK_VERSION, &d3ddev, NULL, &d3dctx);
>> + if (FAILED(hr)) {
>> + msg_Err(va, "D3D11CreateDevice failed. (hr=0x%lX)", hr);
>> + return VLC_EGENERIC;
>> + }
>> + sys->d3ddev = d3ddev;
>> + sys->d3dctx = d3dctx;
>> +
>> + ID3D11VideoContext *d3dvidctx = NULL;
>> + hr = ID3D11DeviceContext_QueryInterface(d3dctx, &IID_ID3D11VideoContext, (void **)&d3dvidctx);
>> + if (FAILED(hr)) {
>> + msg_Err(va, "Could not Query ID3D11VideoDevice Interface. (hr=0x%lX)", hr);
>> + return VLC_EGENERIC;
>> + }
>> + sys->d3dvidctx = d3dvidctx;
>> +
>> +#ifndef NDEBUG
>> + HRESULT (WINAPI * pf_DXGIGetDebugInterface)(const GUID *riid, void **ppDebug);
>> + if (sys->dxgidebug_dll) {
>> + pf_DXGIGetDebugInterface = (void *)GetProcAddress(sys->dxgidebug_dll, "DXGIGetDebugInterface");
>> + if (pf_DXGIGetDebugInterface) {
>> + IDXGIDebug *pDXGIDebug = NULL;
>> + hr = pf_DXGIGetDebugInterface(&IID_IDXGIDebug, (void**)&pDXGIDebug);
>> + if (SUCCEEDED(hr) && pDXGIDebug) {
>> + hr = IDXGIDebug_ReportLiveObjects(pDXGIDebug, DXGI_DEBUG_DX, DXGI_DEBUG_RLO_DETAIL);
>> + }
>> + }
>> + }
>> +
>> + ID3D11Debug *pD3D11Debug;
>> + hr = ID3D11Device_QueryInterface(d3ddev, &IID_ID3D11Debug, (void **) &pD3D11Debug);
>> + if (SUCCEEDED(hr)) {
>> + hr = ID3D11Debug_ReportLiveDeviceObjects(pD3D11Debug, D3D11_RLDO_DETAIL);
>> + ID3D11Debug_Release(pD3D11Debug);
>> + }
>> +#endif
>> +
>> + return VLC_SUCCESS;
>> +}
>> +
>> +/**
>> + * It releases a Direct3D device and its resources.
>> + */
>> +static void D3dDestroyDevice(vlc_va_sys_t *va)
>> +{
>> + if (va->d3dvidctx)
>> + ID3D11VideoContext_Release(va->d3dvidctx);
>> + if (va->d3dctx)
>> + ID3D11DeviceContext_Release(va->d3dctx);
>> + if (va->d3ddev)
>> + ID3D11Device_Release(va->d3ddev);
>> +}
>> +/**
>> + * It describes our Direct3D object
>> + */
>> +static char *DxDescribe(vlc_va_sys_t *p_sys)
>> +{
>> + static const struct {
>> + unsigned id;
>> + char name[32];
>> + } vendors [] = {
>> + { 0x1002, "ATI" },
>> + { 0x10DE, "NVIDIA" },
>> + { 0x1106, "VIA" },
>> + { 0x8086, "Intel" },
>> + { 0x5333, "S3 Graphics" },
>> + { 0, "" }
>> + };
>> +
>> + IDXGIDevice *pDXGIDevice = NULL;
>> + HRESULT hr = ID3D11Device_QueryInterface(p_sys->d3ddev, &IID_IDXGIDevice, (void **)&pDXGIDevice);
>> + if (FAILED(hr)) {
>> + return NULL;
>> + }
>> +
>> + IDXGIAdapter *p_adapter;
>> + hr = IDXGIDevice_GetAdapter(pDXGIDevice, &p_adapter);
>> + if (FAILED(hr)) {
>> + IDXGIDevice_Release(pDXGIDevice);
>> + return NULL;
>> + }
>> +
>> + DXGI_ADAPTER_DESC adapterDesc;
>> + if (SUCCEEDED(IDXGIAdapter_GetDesc(p_adapter, &adapterDesc))) {
>> + const char *vendor = "Unknown";
>> + for (int i = 0; vendors[i].id != 0; i++) {
>> + if (vendors[i].id == adapterDesc.VendorId) {
>> + vendor = vendors[i].name;
>> + break;
>> + }
>> + }
>> +
>> + char *description;
>> + if (asprintf(&description, "D3D11VA (%s, vendor %u(%s), device %u, revision %u)",
>> + FromWide(adapterDesc.Description),
>> + adapterDesc.VendorId, vendor, adapterDesc.DeviceId, adapterDesc.Revision) < 0)
>> + return NULL;
>> + IDXGIAdapter_Release(p_adapter);
>> + IDXGIDevice_Release(pDXGIDevice);
>> + return description;
>> + }
>> +
>> + IDXGIAdapter_Release(p_adapter);
>> + IDXGIDevice_Release(pDXGIDevice);
>> + return NULL;
>> +}
>> +
>> +#if 0
>> +/**
>> + * It creates a Direct3D device manager
>> + */
>> +static int D3dCreateDeviceManager(vlc_va_t *va)
>> +{
>> + vlc_va_sys_t *sys = va->sys;
>> +
>> + HRESULT (WINAPI *CreateDeviceManager9)(UINT *pResetToken,
>> + IDirect3DDeviceManager9 **);
>> + CreateDeviceManager9 =
>> + (void *)GetProcAddress(sys->hdxva2_dll,
>> + "DXVA2CreateDirect3DDeviceManager9");
>> +
>> + if (!CreateDeviceManager9) {
>> + msg_Err(va, "cannot load function");
>> + return VLC_EGENERIC;
>> + }
>> + msg_Dbg(va, "OurDirect3DCreateDeviceManager9 Success!");
>> +
>> + UINT token;
>> + IDirect3DDeviceManager9 *devmng;
>> + if (FAILED(CreateDeviceManager9(&token, &devmng))) {
>> + msg_Err(va, " OurDirect3DCreateDeviceManager9 failed");
>> + return VLC_EGENERIC;
>> + }
>> + sys->token = token;
>> + sys->devmng = devmng;
>> + msg_Info(va, "obtained IDirect3DDeviceManager9");
>> +
>> + HRESULT hr = IDirect3DDeviceManager9_ResetDevice(devmng, sys->d3ddev, token);
>> + if (FAILED(hr)) {
>> + msg_Err(va, "IDirect3DDeviceManager9_ResetDevice failed: %08x", (unsigned)hr);
>> + return VLC_EGENERIC;
>> + }
>> + return VLC_SUCCESS;
>> +}
>> +/**
>> + * It destroys a Direct3D device manager
>> + */
>> +static void D3dDestroyDeviceManager(vlc_va_sys_t *va)
>> +{
>> + if (va->devmng)
>> + IDirect3DDeviceManager9_Release(va->devmng);
>> +}
>> +#endif
>> +
>> +/**
>> + * It creates a DirectX video service
>> + */
>> +static int DxCreateVideoService(vlc_va_t *va)
>> +{
>> + vlc_va_sys_t *sys = va->sys;
>> +
>> + ID3D11VideoDevice *d3dvidev = NULL;
>> + HRESULT hr = ID3D11Device_QueryInterface(sys->d3ddev, &IID_ID3D11VideoDevice, (void **)&d3dvidev);
>> + if (FAILED(hr)) {
>> + msg_Err(va, "Could not Query ID3D11VideoDevice Interface. (hr=0x%lX)", hr);
>> + return VLC_EGENERIC;
>> + }
>> + sys->d3dvidev = d3dvidev;
>> +
>> + return VLC_SUCCESS;
>> +}
>> +
>> +/**
>> + * It destroys a DirectX video service
>> + */
>> +static void DxDestroyVideoService(vlc_va_sys_t *va)
>> +{
>> + if (va->d3dvidev)
>> + ID3D11VideoDevice_Release(va->d3dvidev);
>> +}
>> +
>> +static bool profile_supported(const d3d11va_mode_t *mode, const es_format_t *fmt)
>> +{
>> + bool is_supported = mode->p_profiles == NULL || !mode->p_profiles[0];
>> + if (!is_supported)
>> + {
>> + int profile = fmt->i_profile;
>> + if (mode->codec == AV_CODEC_ID_H264)
>> + {
>> + size_t h264_profile;
>> + if ( h264_get_profile_level(fmt, &h264_profile, NULL, NULL) )
>> + profile = h264_profile;
>> + }
>> +
>> + if (profile <= 0)
>> + is_supported = true;
>> + else for (const int *p_profile = &mode->p_profiles[0]; *p_profile; ++p_profile)
>> + {
>> + if (*p_profile == profile)
>> + {
>> + is_supported = true;
>> + break;
>> + }
>> + }
>> + }
>> + return is_supported;
>> +}
>> +
>> +/**
>> + * Find the best suited decoder mode GUID and render format.
>> + */
>> +static int DxFindVideoServiceConversion(vlc_va_t *va, GUID *input, DXGI_FORMAT *output, const es_format_t *fmt)
>> +{
>> + vlc_va_sys_t *sys = va->sys;
>> + HRESULT hr;
>> +
>> + /* Retreive supported modes from the decoder service */
>> + UINT input_count = ID3D11VideoDevice_GetVideoDecoderProfileCount(sys->d3dvidev);
>> + GUID input_list[input_count];
>> + memset(input_list, 0, sizeof(input_list));
>> + for (UINT i = 0; i < input_count; i++) {
>> + hr = ID3D11VideoDevice_GetVideoDecoderProfile(sys->d3dvidev, i, &input_list[i]);
>> + if (FAILED(hr))
>> + {
>> + msg_Err(va, "GetVideoDecoderProfile %d failed. (hr=0x%lX)", i, hr);
>> + continue;
>> + }
>> + }
>> + for (unsigned i = 0; i < input_count; i++) {
>> + const GUID *g = &input_list[i];
>> + const d3d11va_mode_t *mode = Dxva2FindMode(g);
>> + if (mode) {
>> + msg_Dbg(va, "- '%s' is supported by hardware", mode->name);
>> + } else {
>> + msg_Warn(va, "- Unknown GUID = " GUID_FMT, GUID_PRINT( *g ) );
>> + }
>> + }
>> +
>> + /* Try all supported mode by our priority */
>> + for (unsigned i = 0; d3d11va_modes[i].name; i++) {
>> + const d3d11va_mode_t *mode = &d3d11va_modes[i];
>> + if (!mode->codec || mode->codec != sys->codec_id)
>> + continue;
>> +
>> + /* */
>> + bool is_supported = false;
>> + for (const GUID *g = &input_list[0]; !is_supported && g < &input_list[input_count]; g++) {
>> + is_supported = IsEqualGUID(mode->guid, g);
>> + }
>> + if ( is_supported )
>> + {
>> + is_supported = profile_supported( mode, fmt );
>> + if (!is_supported)
>> + msg_Warn( va, "Unsupported profile for D3D11 HWAccel: %d", fmt->i_profile );
>> + }
>> + if (!is_supported)
>> + continue;
>> +
>> + /* */
>> + msg_Dbg(va, "Trying to use '%s' as input", mode->name);
>> + for (unsigned j = 0; d3d_formats[j].name; j++) {
>> + const d3d_format_t *format = &d3d_formats[j];
>> +
>> + BOOL is_supported = false;
>> + hr = ID3D11VideoDevice_CheckVideoDecoderFormat(sys->d3dvidev, mode->guid, format->format, &is_supported);
>> + if (FAILED(hr) || !is_supported)
>> + continue;
>> + msg_Dbg(va, "%s is supported for output", format->name);
>> + }
>> +
>> + /* */
>> + for (unsigned j = 0; d3d_formats[j].name; j++) {
>> + const d3d_format_t *format = &d3d_formats[j];
>> +
>> + /* */
>> + BOOL is_supported = false;
>> + hr = ID3D11VideoDevice_CheckVideoDecoderFormat(sys->d3dvidev, mode->guid, format->format, &is_supported);
>> + if (FAILED(hr) || !is_supported)
>> + continue;
>> +
>> + /* We have our solution */
>> + msg_Dbg(va, "Using '%s' to decode to '%s'", mode->name, format->name);
>> + *input = *mode->guid;
>> + *output = format->format;
>> + return VLC_SUCCESS;
>> + }
>> + }
>> + return VLC_EGENERIC;
>> +}
>> +
>> +/**
>> + * It creates a DXVA2 decoder using the given video format
>> + */
>> +static int DxCreateVideoDecoder(vlc_va_t *va, int codec_id,
>> + const video_format_t *fmt, bool b_threading)
>> +{
>> + vlc_va_sys_t *sys = va->sys;
>> + int surface_alignment = 16;
>> + int surface_count = 4;
>> + HRESULT hr;
>> +
>> + ID3D10Multithread *pMultithread;
>> + hr = ID3D11Device_QueryInterface(sys->d3ddev, &IID_ID3D10Multithread, (void **)&pMultithread);
>> + if (SUCCEEDED(hr)) {
>> + ID3D10Multithread_SetMultithreadProtected(pMultithread, b_threading && sys->thread_count > 1);
>> + ID3D10Multithread_Release(pMultithread);
>> + }
>> +
>> + /* */
>> + msg_Dbg(va, "DxCreateVideoDecoder id %d %dx%d",
>> + codec_id, fmt->i_width, fmt->i_height);
>> +
>> + sys->width = fmt->i_width;
>> + sys->height = fmt->i_height;
>> +
>> + switch ( codec_id )
>> + {
>> + case AV_CODEC_ID_MPEG2VIDEO:
>> + /* decoding MPEG-2 requires additional alignment on some Intel GPUs,
>> + but it causes issues for H.264 on certain AMD GPUs..... */
>> + surface_alignment = 32;
>> + surface_count += 2;
>> + break;
>> + case AV_CODEC_ID_HEVC:
>> + /* the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensure
>> + all coding features have enough room to work with */
>> + surface_alignment = 128;
>> + surface_count += 16;
>> + break;
>> + case AV_CODEC_ID_H264:
>> + surface_count += 16;
>> + break;
>> + default:
>> + surface_count += 2;
>> + }
>> +
>> +#define ALIGN(x, y) (((x) + ((y) - 1)) & ~((y) - 1))
>> + sys->surface_width = ALIGN(fmt->i_width, surface_alignment);
>> + sys->surface_height = ALIGN(fmt->i_height, surface_alignment);
>> +
>> + if ( b_threading )
>> + surface_count += sys->thread_count;
>> +
>> + if (surface_count > VA_D3D11_MAX_SURFACE_COUNT)
>> + return VLC_EGENERIC;
>> +
>> + D3D11_TEXTURE2D_DESC texDesc;
>> + ZeroMemory(&texDesc, sizeof(texDesc));
>> + texDesc.Width = sys->surface_width;
>> + texDesc.Height = sys->surface_height;
>> + texDesc.MipLevels = 1;
>> + texDesc.Format = sys->render;
>> + texDesc.SampleDesc.Count = 1;
>> + texDesc.MiscFlags = 0; // D3D11_RESOURCE_MISC_SHARED
>> + texDesc.ArraySize = 1;
>> + texDesc.Usage = D3D11_USAGE_STAGING;
>> + texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
>> + texDesc.BindFlags = 0;
>> +
>> + sys->staging = NULL;
>> + hr = ID3D11Device_CreateTexture2D( sys->d3ddev, &texDesc, NULL,
>> + (ID3D11Texture2D**) &sys->staging);
>> + if (FAILED(hr)) {
>> + msg_Err(va, "Failed to create a staging texture to extract surface pixels (hr=0x%0lx)", hr );
>> + return VLC_EGENERIC;
>> + }
>> +
>> + texDesc.ArraySize = surface_count;
>> + texDesc.Usage = D3D11_USAGE_DEFAULT; //D3D11_USAGE_DYNAMIC; //D3D11_USAGE_STAGING; // D3D11_USAGE_DEFAULT
>> + texDesc.BindFlags = D3D11_BIND_DECODER;// | D3D11_BIND_UNORDERED_ACCESS;
>> + texDesc.CPUAccessFlags = 0; //D3D11_CPU_ACCESS_READ;
>> +
>> + ID3D11Texture2D *p_texture;
>> + hr = ID3D11Device_CreateTexture2D( sys->d3ddev, &texDesc, NULL, &p_texture );
>> + if (FAILED(hr)) {
>> + msg_Err(va, "CreateTexture2D %d failed. (hr=0x%0lx)", sys->surface_count, hr);
>> + return VLC_EGENERIC;
>> + }
>> +
>> + D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
>> + ZeroMemory(&viewDesc, sizeof(viewDesc));
>> + viewDesc.DecodeProfile = sys->input;
>> + viewDesc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
>> +
>> + for (sys->surface_count = 0; sys->surface_count < surface_count; sys->surface_count++) {
>> + vlc_va_surface_t *surface = &sys->surface[sys->surface_count];
>> +
>> + viewDesc.Texture2D.ArraySlice = sys->surface_count;
>> +
>> + ID3D11Resource *p_resource = (ID3D11Resource*) p_texture;
>> + hr = ID3D11VideoDevice_CreateVideoDecoderOutputView( sys->d3dvidev, p_resource,
>> + &viewDesc, &surface->d3d );
>> + if (FAILED(hr)) {
>> + msg_Err(va, "CreateVideoDecoderOutputView %d failed. (hr=0x%0lx)", sys->surface_count, hr);
>> + ID3D11Texture2D_Release(p_texture);
>> + return VLC_EGENERIC;
>> + }
>> + surface->refcount = 0;
>> + surface->order = 0;
>> + surface->p_lock = &sys->surface_lock;
>> + sys->hw_surface[sys->surface_count] = surface->d3d;
>> + }
>> + msg_Dbg(va, "ID3D11VideoDecoderOutputView succeed with %d surfaces (%dx%d)",
>> + sys->surface_count, fmt->i_width, fmt->i_height);
>> +
>> + D3D11_VIDEO_DECODER_DESC decoderDesc;
>> + ZeroMemory(&decoderDesc, sizeof(decoderDesc));
>> + decoderDesc.Guid = sys->input;
>> + decoderDesc.SampleWidth = sys->surface_width;
>> + decoderDesc.SampleHeight = sys->surface_height;
>> + decoderDesc.OutputFormat = sys->render;
>> +
>> + UINT cfg_count;
>> + hr = ID3D11VideoDevice_GetVideoDecoderConfigCount( sys->d3dvidev, &decoderDesc, &cfg_count );
>> + if (FAILED(hr)) {
>> + msg_Err(va, "GetVideoDecoderConfigCount failed. (hr=0x%lX)", hr);
>> + return VLC_EGENERIC;
>> + }
>> +
>> + /* List all configurations available for the decoder */
>> + D3D11_VIDEO_DECODER_CONFIG cfg_list[cfg_count];
>> + for (unsigned i = 0; i < cfg_count; i++) {
>> + hr = ID3D11VideoDevice_GetVideoDecoderConfig( sys->d3dvidev, &decoderDesc, i, &cfg_list[i] );
>> + if (FAILED(hr)) {
>> + msg_Err(va, "GetVideoDecoderConfig failed. (hr=0x%lX)", hr);
>> + return VLC_EGENERIC;
>> + }
>> + }
>> +
>> + msg_Dbg(va, "we got %d decoder configurations", cfg_count);
>> +
>> + /* Select the best decoder configuration */
>> + int cfg_score = 0;
>> + for (unsigned i = 0; i < cfg_count; i++) {
>> + const D3D11_VIDEO_DECODER_CONFIG *cfg = &cfg_list[i];
>> +
>> + /* */
>> + msg_Dbg(va, "configuration[%d] ConfigBitstreamRaw %d",
>> + i, cfg->ConfigBitstreamRaw);
>> +
>> + /* */
>> + int score;
>> + if (cfg->ConfigBitstreamRaw == 1)
>> + score = 1;
>> + else if (codec_id == AV_CODEC_ID_H264 && cfg->ConfigBitstreamRaw == 2)
>> + score = 2;
>> + else
>> + continue;
>> + if (IsEqualGUID(&cfg->guidConfigBitstreamEncryption, &DXVA_NoEncrypt))
>> + score += 16;
>> +
>> + if (cfg_score < score) {
>> + sys->cfg = *cfg;
>> + cfg_score = score;
>> + }
>> + }
>> + if (cfg_score <= 0) {
>> + msg_Err(va, "Failed to find a supported decoder configuration");
>> + return VLC_EGENERIC;
>> + }
>> + hr = ID3D11VideoDevice_CreateVideoDecoder( sys->d3dvidev, &decoderDesc, &sys->cfg, &sys->decoder );
>> + if (FAILED(hr)) {
>> + msg_Err(va, "ID3D11VideoDevice_CreateVideoDecoder failed. (hr=0x%lX)", hr);
>> + sys->decoder = NULL;
>> + return VLC_EGENERIC;
>> + }
>> +
>> + if (IsEqualGUID(&sys->input, &DXVA_Intel_H264_NoFGT_ClearVideo))
>> + sys->hw.workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;
>> +
>> + msg_Dbg(va, "DxCreateVideoDecoder succeed");
>> + return VLC_SUCCESS;
>> +}
>> +
>> +static void DxDestroyVideoDecoder(vlc_va_sys_t *va)
>> +{
>> + for (int i = 0; i < va->surface_count; i++) {
>> + ID3D11Resource *p_texture;
>> + ID3D11VideoDecoderOutputView_GetResource( va->surface[i].d3d, &p_texture );
>> + ID3D11Resource_Release(p_texture);
>> + ID3D11VideoDecoderOutputView_Release(va->surface[i].d3d);
>> + }
>> + va->surface_count = 0;
>> +
>> + if (va->staging)
>> + ID3D11Resource_Release(va->staging);
>> + if (va->decoder)
>> + ID3D11VideoDecoder_Release(va->decoder);
>> + va->decoder = NULL;
>> +}
>> +
>> +static int DxResetVideoDecoder(vlc_va_t *va)
>> +{
>> + msg_Err(va, "DxResetVideoDecoder unimplemented");
>> + return VLC_EGENERIC;
>> +}
>
> We can't mutualize any code with Dxva2?
Yes some things are common, even some IDs are copied between DXVA2 and
D3D11 with different names. Factorizing the code means doing it before
adding the new code though. Isn't it better to do it once d3d11va.c
and dxva2.c are both in the repo ?
Steve
More information about the vlc-devel
mailing list