[vlc-devel] [PATCH] d3d11va: add a Direct3D11 decoder using avcodec
Jean-Baptiste Kempf
jb at videolan.org
Tue May 12 13:36:45 CEST 2015
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
> contrib/src/ffmpeg/rules.mak | 2 +-
I don't think this is necessary, since it should be defaulted in libav.
> +#include <libavcodec/avcodec.h>
> +# define COBJMACROS
> +# include <libavcodec/d3d11va.h>
Weird indentation.
> +#include <windows.h>
> +#include <windowsx.h>
Windowsx.h usage is debatable.
>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?
--
With my kindest regards,
--
Jean-Baptiste Kempf
http://www.jbkempf.com/ - +33 672 704 734
Sent from my Electronic Device
More information about the vlc-devel
mailing list