/*
* (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));
}