/* * (C) 2003-2006 Gabest * (C) 2006-2013 see Authors.txt * * This file is part of MPC-HC. * * MPC-HC is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * MPC-HC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "stdafx.h" #include "NullRenderers.h" #include "moreuuids.h" #define USE_DXVA #ifdef USE_DXVA #include #include #include // DXVA2 #include #include // API Media Foundation #include // dxva.dll typedef HRESULT(__stdcall* PTR_DXVA2CreateDirect3DDeviceManager9)(UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager); typedef HRESULT(__stdcall* PTR_DXVA2CreateVideoService)(IDirect3DDevice9* pDD, REFIID riid, void** ppService); class CNullVideoRendererInputPin : public CRendererInputPin, public IMFGetService, public IDirectXVideoMemoryConfiguration, public IMFVideoDisplayControl { public: CNullVideoRendererInputPin(CBaseRenderer* pRenderer, HRESULT* phr, LPCWSTR Name); ~CNullVideoRendererInputPin() { if (m_pD3DDeviceManager) { if (m_hDevice != INVALID_HANDLE_VALUE) { m_pD3DDeviceManager->CloseDeviceHandle(m_hDevice); m_hDevice = INVALID_HANDLE_VALUE; } m_pD3DDeviceManager = nullptr; } if (m_pD3DDev) { m_pD3DDev = nullptr; } if (m_hDXVA2Lib) { FreeLibrary(m_hDXVA2Lib); } } DECLARE_IUNKNOWN STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv); STDMETHODIMP GetAllocator(IMemAllocator** ppAllocator) { // Renderer shouldn't manage allocator for DXVA return E_NOTIMPL; } STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES* pProps) { // 1 buffer required memset(pProps, 0, sizeof(ALLOCATOR_PROPERTIES)); pProps->cbBuffer = 1; return S_OK; } // IMFGetService STDMETHODIMP GetService(REFGUID guidService, REFIID riid, LPVOID* ppvObject); // IDirectXVideoMemoryConfiguration STDMETHODIMP GetAvailableSurfaceTypeByIndex(DWORD dwTypeIndex, DXVA2_SurfaceType* pdwType); STDMETHODIMP SetSurfaceType(DXVA2_SurfaceType dwType); // IMFVideoDisplayControl STDMETHODIMP GetNativeVideoSize(SIZE* pszVideo, SIZE* pszARVideo) { return E_NOTIMPL; }; STDMETHODIMP GetIdealVideoSize(SIZE* pszMin, SIZE* pszMax) { return E_NOTIMPL; }; STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect* pnrcSource, const LPRECT prcDest) { return E_NOTIMPL; }; STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect* pnrcSource, LPRECT prcDest) { return E_NOTIMPL; }; STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode) { return E_NOTIMPL; }; STDMETHODIMP GetAspectRatioMode(DWORD* pdwAspectRatioMode) { return E_NOTIMPL; }; STDMETHODIMP SetVideoWindow(HWND hwndVideo) { return E_NOTIMPL; }; STDMETHODIMP GetVideoWindow(HWND* phwndVideo); STDMETHODIMP RepaintVideo() { return E_NOTIMPL; }; STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER* pBih, BYTE** pDib, DWORD* pcbDib, LONGLONG* pTimeStamp) { return E_NOTIMPL; }; STDMETHODIMP SetBorderColor(COLORREF Clr) { return E_NOTIMPL; }; STDMETHODIMP GetBorderColor(COLORREF* pClr) { return E_NOTIMPL; }; STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags) { return E_NOTIMPL; }; STDMETHODIMP GetRenderingPrefs(DWORD* pdwRenderFlags) { return E_NOTIMPL; }; STDMETHODIMP SetFullscreen(BOOL fFullscreen) { return E_NOTIMPL; }; STDMETHODIMP GetFullscreen(BOOL* pfFullscreen) { return E_NOTIMPL; }; private: HMODULE m_hDXVA2Lib; PTR_DXVA2CreateDirect3DDeviceManager9 pfDXVA2CreateDirect3DDeviceManager9; PTR_DXVA2CreateVideoService pfDXVA2CreateVideoService; CComPtr m_pD3D; CComPtr m_pD3DDev; CComPtr m_pD3DDeviceManager; UINT m_nResetTocken; HANDLE m_hDevice; HWND m_hWnd; void CreateSurface(); }; CNullVideoRendererInputPin::CNullVideoRendererInputPin(CBaseRenderer* pRenderer, HRESULT* phr, LPCWSTR Name) : CRendererInputPin(pRenderer, phr, Name) , m_hDXVA2Lib(nullptr) , m_pD3DDev(nullptr) , m_pD3DDeviceManager(nullptr) , m_hDevice(INVALID_HANDLE_VALUE) { CreateSurface(); m_hDXVA2Lib = LoadLibrary(L"dxva2.dll"); if (m_hDXVA2Lib) { pfDXVA2CreateDirect3DDeviceManager9 = reinterpret_cast(GetProcAddress(m_hDXVA2Lib, "DXVA2CreateDirect3DDeviceManager9")); pfDXVA2CreateVideoService = reinterpret_cast(GetProcAddress(m_hDXVA2Lib, "DXVA2CreateVideoService")); pfDXVA2CreateDirect3DDeviceManager9(&m_nResetTocken, &m_pD3DDeviceManager); } // Initialize Device Manager with DX surface if (m_pD3DDev) { m_pD3DDeviceManager->ResetDevice(m_pD3DDev, m_nResetTocken); m_pD3DDeviceManager->OpenDeviceHandle(&m_hDevice); } } void CNullVideoRendererInputPin::CreateSurface() { m_pD3D.Attach(Direct3DCreate9(D3D_SDK_VERSION)); if (!m_pD3D) { m_pD3D.Attach(Direct3DCreate9(D3D9b_SDK_VERSION)); } m_hWnd = nullptr; // TODO : put true window D3DDISPLAYMODE d3ddm; ZeroMemory(&d3ddm, sizeof(d3ddm)); m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm); D3DPRESENT_PARAMETERS pp; ZeroMemory(&pp, sizeof(pp)); pp.Windowed = TRUE; pp.hDeviceWindow = m_hWnd; pp.SwapEffect = D3DSWAPEFFECT_COPY; pp.Flags = D3DPRESENTFLAG_VIDEO; pp.BackBufferCount = 1; pp.BackBufferWidth = d3ddm.Width; pp.BackBufferHeight = d3ddm.Height; pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, //| D3DCREATE_MANAGED, &pp, &m_pD3DDev); } STDMETHODIMP CNullVideoRendererInputPin::NonDelegatingQueryInterface(REFIID riid, void** ppv) { CheckPointer(ppv, E_POINTER); return (riid == __uuidof(IMFGetService)) ? GetInterface((IMFGetService*)this, ppv) : __super::NonDelegatingQueryInterface(riid, ppv); } STDMETHODIMP CNullVideoRendererInputPin::GetService(REFGUID guidService, REFIID riid, LPVOID* ppvObject) { if (m_pD3DDeviceManager != nullptr && guidService == MR_VIDEO_ACCELERATION_SERVICE) { if (riid == __uuidof(IDirect3DDeviceManager9)) { return m_pD3DDeviceManager->QueryInterface(riid, ppvObject); } else if (riid == __uuidof(IDirectXVideoDecoderService) || riid == __uuidof(IDirectXVideoProcessorService)) { return m_pD3DDeviceManager->GetVideoService(m_hDevice, riid, ppvObject); } else if (riid == __uuidof(IDirectXVideoAccelerationService)) { // TODO : to be tested.... return pfDXVA2CreateVideoService(m_pD3DDev, riid, ppvObject); } else if (riid == __uuidof(IDirectXVideoMemoryConfiguration)) { GetInterface((IDirectXVideoMemoryConfiguration*)this, ppvObject); return S_OK; } } else if (guidService == MR_VIDEO_RENDER_SERVICE) { if (riid == __uuidof(IMFVideoDisplayControl)) { GetInterface((IMFVideoDisplayControl*)this, ppvObject); return S_OK; } } return E_NOINTERFACE; } STDMETHODIMP CNullVideoRendererInputPin::GetAvailableSurfaceTypeByIndex(DWORD dwTypeIndex, DXVA2_SurfaceType* pdwType) { if (dwTypeIndex == 0) { *pdwType = DXVA2_SurfaceType_DecoderRenderTarget; return S_OK; } else { return MF_E_NO_MORE_TYPES; } } STDMETHODIMP CNullVideoRendererInputPin::SetSurfaceType(DXVA2_SurfaceType dwType) { return S_OK; } STDMETHODIMP CNullVideoRendererInputPin::GetVideoWindow(HWND* phwndVideo) { CheckPointer(phwndVideo, E_POINTER); *phwndVideo = m_hWnd; // Important to implement this method (used by mpc) return S_OK; } #endif // USE_DXVA // // CNullRenderer // CNullRenderer::CNullRenderer(REFCLSID clsid, TCHAR* pName, LPUNKNOWN pUnk, HRESULT* phr) : CBaseRenderer(clsid, pName, pUnk, phr) { } // // CNullVideoRenderer // CNullVideoRenderer::CNullVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr) : CNullRenderer(__uuidof(this), NAME("Null Video Renderer"), pUnk, phr) { } HRESULT CNullVideoRenderer::CheckMediaType(const CMediaType* pmt) { return pmt->majortype == MEDIATYPE_Video || pmt->subtype == MEDIASUBTYPE_MPEG2_VIDEO ? S_OK : E_FAIL; } // // CNullUVideoRenderer // CNullUVideoRenderer::CNullUVideoRenderer(LPUNKNOWN pUnk, HRESULT* phr) : CNullRenderer(__uuidof(this), NAME("Null Video Renderer (Uncompressed)"), pUnk, phr) { #ifdef USE_DXVA m_pInputPin = DEBUG_NEW CNullVideoRendererInputPin(this, phr, L"In"); #endif } HRESULT CNullUVideoRenderer::CheckMediaType(const CMediaType* pmt) { return pmt->majortype == MEDIATYPE_Video && (pmt->subtype == MEDIASUBTYPE_YV12 || pmt->subtype == MEDIASUBTYPE_NV12 || pmt->subtype == MEDIASUBTYPE_I420 || pmt->subtype == MEDIASUBTYPE_YUYV || pmt->subtype == MEDIASUBTYPE_IYUV || pmt->subtype == MEDIASUBTYPE_YVU9 || pmt->subtype == MEDIASUBTYPE_Y411 || pmt->subtype == MEDIASUBTYPE_Y41P || pmt->subtype == MEDIASUBTYPE_YUY2 || pmt->subtype == MEDIASUBTYPE_YVYU || pmt->subtype == MEDIASUBTYPE_UYVY || pmt->subtype == MEDIASUBTYPE_Y211 || pmt->subtype == MEDIASUBTYPE_RGB1 || pmt->subtype == MEDIASUBTYPE_RGB4 || pmt->subtype == MEDIASUBTYPE_RGB8 || pmt->subtype == MEDIASUBTYPE_RGB565 || pmt->subtype == MEDIASUBTYPE_RGB555 || pmt->subtype == MEDIASUBTYPE_RGB24 || pmt->subtype == MEDIASUBTYPE_RGB32 || pmt->subtype == MEDIASUBTYPE_ARGB1555 || pmt->subtype == MEDIASUBTYPE_ARGB4444 || pmt->subtype == MEDIASUBTYPE_ARGB32 || pmt->subtype == MEDIASUBTYPE_A2R10G10B10 || pmt->subtype == MEDIASUBTYPE_A2B10G10R10) ? S_OK : E_FAIL; } HRESULT CNullUVideoRenderer::DoRenderSample(IMediaSample* pSample) { #ifdef USE_DXVA CComQIPtr pService = pSample; if (pService != nullptr) { CComPtr pSurface; if (SUCCEEDED(pService->GetService(MR_BUFFER_SERVICE, __uuidof(IDirect3DSurface9), (void**)&pSurface))) { // TODO : render surface... } } #endif return S_OK; } // // CNullAudioRenderer // CNullAudioRenderer::CNullAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr) : CNullRenderer(__uuidof(this), NAME("Null Audio Renderer"), pUnk, phr) { } HRESULT CNullAudioRenderer::CheckMediaType(const CMediaType* pmt) { return pmt->majortype == MEDIATYPE_Audio || pmt->majortype == MEDIATYPE_Midi || pmt->subtype == MEDIASUBTYPE_MPEG2_AUDIO || pmt->subtype == MEDIASUBTYPE_DOLBY_AC3 || pmt->subtype == MEDIASUBTYPE_DVD_LPCM_AUDIO || pmt->subtype == MEDIASUBTYPE_DTS || pmt->subtype == MEDIASUBTYPE_SDDS || pmt->subtype == MEDIASUBTYPE_MPEG1AudioPayload || pmt->subtype == MEDIASUBTYPE_MPEG1Audio ? S_OK : E_FAIL; } // // CNullUAudioRenderer // CNullUAudioRenderer::CNullUAudioRenderer(LPUNKNOWN pUnk, HRESULT* phr) : CNullRenderer(__uuidof(this), NAME("Null Audio Renderer (Uncompressed)"), pUnk, phr) { } HRESULT CNullUAudioRenderer::CheckMediaType(const CMediaType* pmt) { return pmt->majortype == MEDIATYPE_Audio && (pmt->subtype == MEDIASUBTYPE_PCM || pmt->subtype == MEDIASUBTYPE_IEEE_FLOAT || pmt->subtype == MEDIASUBTYPE_DRM_Audio || pmt->subtype == MEDIASUBTYPE_DOLBY_AC3_SPDIF || pmt->subtype == MEDIASUBTYPE_RAW_SPORT || pmt->subtype == MEDIASUBTYPE_SPDIF_TAG_241h) ? S_OK : E_FAIL; } HRESULT CNullUAudioRenderer::DoRenderSample(IMediaSample* pSample) { #if _DEBUG && 0 static int nNb = 1; if (nNb < 100) { const long lSize = pSample->GetActualDataLength(); BYTE* pMediaBuffer = nullptr; HRESULT hr = pSample->GetPointer(&pMediaBuffer); char strFile[MAX_PATH]; sprintf_s(strFile, "AudioData%02d.bin", nNb++); FILE* hFile = fopen(strFile, "wb"); if (hFile) { fwrite(pMediaBuffer, 1, lSize, hFile); fclose(hFile); } } #endif return S_OK; } // // CNullTextRenderer // HRESULT CNullTextRenderer::CTextInputPin::CheckMediaType(const CMediaType* pmt) { return pmt->majortype == MEDIATYPE_Text || pmt->majortype == MEDIATYPE_ScriptCommand || pmt->majortype == MEDIATYPE_Subtitle || pmt->subtype == MEDIASUBTYPE_DVD_SUBPICTURE || pmt->subtype == MEDIASUBTYPE_CVD_SUBPICTURE || pmt->subtype == MEDIASUBTYPE_SVCD_SUBPICTURE ? S_OK : E_FAIL; } CNullTextRenderer::CNullTextRenderer(LPUNKNOWN pUnk, HRESULT* phr) : CBaseFilter(NAME("CNullTextRenderer"), pUnk, this, __uuidof(this), phr) { m_pInput.Attach(DEBUG_NEW CTextInputPin(this, this, phr)); }