www.pudn.com > VCMPlayerClassic_Coder.rar > DX9AllocatorPresenter.cpp


/* 
 *	Copyright (C) 2003-2006 Gabest
 *	http://www.gabest.org
 *
 *  This Program 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 2, or (at your option)
 *  any later version.
 *   
 *  This Program 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 GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *  http://www.gnu.org/copyleft/gpl.html
 *
 */

#include "stdafx.h"
#include "mplayerc.h"
#include 
#include 
#include "..\..\DSUtil\DSUtil.h"

#include 

#include 
#include "DX9AllocatorPresenter.h"
#include 
#include 
#include 
#include "..\..\SubPic\DX9SubPic.h"
#include "..\..\..\include\RealMedia\pntypes.h"
#include "..\..\..\include\RealMedia\pnwintyp.h"
#include "..\..\..\include\RealMedia\pncom.h"
#include "..\..\..\include\RealMedia\rmavsurf.h"
#include "IQTVideoSurface.h"
#include "..\..\..\include\moreuuids.h"

#include "MacrovisionKicker.h"
#include "IPinHook.h"

#include "PixelShaderCompiler.h"

bool IsVMR9InGraph(IFilterGraph* pFG)
{
	BeginEnumFilters(pFG, pEF, pBF)
		if(CComQIPtr(pBF)) return(true);
	EndEnumFilters
	return(false);
}

namespace DSObjects
{

class CDX9AllocatorPresenter
	: public ISubPicAllocatorPresenterImpl
{
protected:
	CSize m_ScreenSize;
	bool m_fVMRSyncFix;

	CComPtr m_pD3D;
    CComPtr m_pD3DDev;
	CComPtr m_pVideoTexture[3];
	CComPtr m_pVideoSurface[3];
	CInterfaceList m_pPixelShaders;
	CComPtr m_pResizerPixelShader[3]; // bl, bc1, bc2
	CComPtr m_pResizerBicubic1stPass;
	D3DTEXTUREFILTERTYPE m_filter;
	D3DCAPS9 m_caps;

	CAutoPtr m_pPSC;

	virtual HRESULT CreateDevice();
	virtual HRESULT AllocSurfaces();
	virtual void DeleteSurfaces();

    UINT GetAdapter(IDirect3D9 *pD3D);

	float m_bicubicA;
	HRESULT InitResizers(float bicubicA);

	HRESULT TextureCopy(CComPtr pTexture);
	HRESULT TextureResize(CComPtr pTexture, Vector dst[4], D3DTEXTUREFILTERTYPE filter);
	HRESULT TextureResizeBilinear(CComPtr pTexture, Vector dst[4]);
	HRESULT TextureResizeBicubic1pass(CComPtr pTexture, Vector dst[4]);
	HRESULT TextureResizeBicubic2pass(CComPtr pTexture, Vector dst[4]);

public:
	CDX9AllocatorPresenter(HWND hWnd, HRESULT& hr);

	// ISubPicAllocatorPresenter
	STDMETHODIMP CreateRenderer(IUnknown** ppRenderer);
	STDMETHODIMP_(bool) Paint(bool fAll);
	STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size);
	STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget);
};

class CVMR9AllocatorPresenter
	: public CDX9AllocatorPresenter
	, public IVMRSurfaceAllocator9
	, public IVMRImagePresenter9
	, public IVMRWindowlessControl9
{
protected:
	CComPtr m_pIVMRSurfAllocNotify;
	CInterfaceArray m_pSurfaces;

	HRESULT CreateDevice();
	void DeleteSurfaces();

	bool m_fUseInternalTimer;
	REFERENCE_TIME m_rtPrevStart;

public:
	CVMR9AllocatorPresenter(HWND hWnd, HRESULT& hr);

	DECLARE_IUNKNOWN
    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);

	// ISubPicAllocatorPresenter
	STDMETHODIMP CreateRenderer(IUnknown** ppRenderer);
	STDMETHODIMP_(void) SetTime(REFERENCE_TIME rtNow);

    // IVMRSurfaceAllocator9
    STDMETHODIMP InitializeDevice(DWORD_PTR dwUserID, VMR9AllocationInfo* lpAllocInfo, DWORD* lpNumBuffers);
    STDMETHODIMP TerminateDevice(DWORD_PTR dwID);
    STDMETHODIMP GetSurface(DWORD_PTR dwUserID, DWORD SurfaceIndex, DWORD SurfaceFlags, IDirect3DSurface9** lplpSurface);
    STDMETHODIMP AdviseNotify(IVMRSurfaceAllocatorNotify9* lpIVMRSurfAllocNotify);

    // IVMRImagePresenter9
    STDMETHODIMP StartPresenting(DWORD_PTR dwUserID);
    STDMETHODIMP StopPresenting(DWORD_PTR dwUserID);
    STDMETHODIMP PresentImage(DWORD_PTR dwUserID, VMR9PresentationInfo* lpPresInfo);

	// IVMRWindowlessControl9
	STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight);
	STDMETHODIMP GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight);
	STDMETHODIMP GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight);
	STDMETHODIMP SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect);
    STDMETHODIMP GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect);
	STDMETHODIMP GetAspectRatioMode(DWORD* lpAspectRatioMode);
	STDMETHODIMP SetAspectRatioMode(DWORD AspectRatioMode);
	STDMETHODIMP SetVideoClippingWindow(HWND hwnd);
	STDMETHODIMP RepaintVideo(HWND hwnd, HDC hdc);
	STDMETHODIMP DisplayModeChanged();
	STDMETHODIMP GetCurrentImage(BYTE** lpDib);
	STDMETHODIMP SetBorderColor(COLORREF Clr);
	STDMETHODIMP GetBorderColor(COLORREF* lpClr);
};

class CRM9AllocatorPresenter
	: public CDX9AllocatorPresenter
	, public IRMAVideoSurface
{
	CComPtr m_pVideoSurfaceOff;
	CComPtr m_pVideoSurfaceYUY2;

    RMABitmapInfoHeader m_bitmapInfo;
    RMABitmapInfoHeader m_lastBitmapInfo;

protected:
	HRESULT AllocSurfaces();
	void DeleteSurfaces();

public:
	CRM9AllocatorPresenter(HWND hWnd, HRESULT& hr);

	DECLARE_IUNKNOWN
    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);

	// IRMAVideoSurface
    STDMETHODIMP Blt(UCHAR*	pImageData, RMABitmapInfoHeader* pBitmapInfo, REF(PNxRect) inDestRect, REF(PNxRect) inSrcRect);
	STDMETHODIMP BeginOptimizedBlt(RMABitmapInfoHeader* pBitmapInfo);
	STDMETHODIMP OptimizedBlt(UCHAR* pImageBits, REF(PNxRect) rDestRect, REF(PNxRect) rSrcRect);
	STDMETHODIMP EndOptimizedBlt();
	STDMETHODIMP GetOptimizedFormat(REF(RMA_COMPRESSION_TYPE) ulType);
    STDMETHODIMP GetPreferredFormat(REF(RMA_COMPRESSION_TYPE) ulType);
};

class CQT9AllocatorPresenter
	: public CDX9AllocatorPresenter
	, public IQTVideoSurface
{
	CComPtr m_pVideoSurfaceOff;

protected:
	 HRESULT AllocSurfaces();
	 void DeleteSurfaces();

public:
	CQT9AllocatorPresenter(HWND hWnd, HRESULT& hr);

	DECLARE_IUNKNOWN
    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);

	// IQTVideoSurface
	STDMETHODIMP BeginBlt(const BITMAP& bm);
	STDMETHODIMP DoBlt(const BITMAP& bm);
};

class CDXRAllocatorPresenter
	: public ISubPicAllocatorPresenterImpl
{
	class CSubRenderCallback : public CUnknown, public ISubRenderCallback, public CCritSec
	{
		CDXRAllocatorPresenter* m_pDXRAP;

	public:
		CSubRenderCallback(CDXRAllocatorPresenter* pDXRAP)
			: CUnknown(_T("CSubRender"), NULL)
			, m_pDXRAP(pDXRAP)
		{
		}

		DECLARE_IUNKNOWN
		STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv)
		{
			return 
				QI(ISubRenderCallback)
				__super::NonDelegatingQueryInterface(riid, ppv);
		}

		void SetDXRAP(CDXRAllocatorPresenter* pDXRAP)
		{
			CAutoLock cAutoLock(this);
			m_pDXRAP = pDXRAP;
		}

		// ISubRenderCallback

		STDMETHODIMP SetDevice(IDirect3DDevice9* pD3DDev)
		{
			CAutoLock cAutoLock(this);
			return m_pDXRAP ? m_pDXRAP->SetDevice(pD3DDev) : E_UNEXPECTED;
		}

		STDMETHODIMP Render(REFERENCE_TIME rtStart, int left, int top, int right, int bottom, int width, int height)
		{
			CAutoLock cAutoLock(this);
			return m_pDXRAP ? m_pDXRAP->Render(rtStart, 0, 0, left, top, right, bottom, width, height) : E_UNEXPECTED;
		}

		// ISubRendererCallback2

		STDMETHODIMP RenderEx(REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME AvgTimePerFrame, int left, int top, int right, int bottom, int width, int height)
		{
			CAutoLock cAutoLock(this);
			return m_pDXRAP ? m_pDXRAP->Render(rtStart, rtStop, AvgTimePerFrame, left, top, right, bottom, width, height) : E_UNEXPECTED;
		}
	};

	CComPtr m_pDXR;
	CComPtr m_pSRCB;

public:
	CDXRAllocatorPresenter(HWND hWnd, HRESULT& hr);
	virtual ~CDXRAllocatorPresenter();

	DECLARE_IUNKNOWN
    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);

	HRESULT SetDevice(IDirect3DDevice9* pD3DDev);
	HRESULT Render(
		REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME atpf,
		int left, int top, int bottom, int right, int width, int height);

	// ISubPicAllocatorPresenter
	STDMETHODIMP CreateRenderer(IUnknown** ppRenderer);
	STDMETHODIMP_(void) SetPosition(RECT w, RECT v);
	STDMETHODIMP_(SIZE) GetVideoSize(bool fCorrectAR);
	STDMETHODIMP_(bool) Paint(bool fAll);
	STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size);
	STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget);
};

}
using namespace DSObjects;

//

HRESULT CreateAP9(const CLSID& clsid, HWND hWnd, ISubPicAllocatorPresenter** ppAP)
{
	CheckPointer(ppAP, E_POINTER);

	*ppAP = NULL;

	HRESULT hr = E_FAIL;
	if(clsid == CLSID_VMR9AllocatorPresenter && !(*ppAP = new CVMR9AllocatorPresenter(hWnd, hr))
	|| clsid == CLSID_RM9AllocatorPresenter && !(*ppAP = new CRM9AllocatorPresenter(hWnd, hr))
	|| clsid == CLSID_QT9AllocatorPresenter && !(*ppAP = new CQT9AllocatorPresenter(hWnd, hr))
	|| clsid == CLSID_DXRAllocatorPresenter && !(*ppAP = new CDXRAllocatorPresenter(hWnd, hr)))
		return E_OUTOFMEMORY;

	if(*ppAP == NULL)
		return E_FAIL;

	(*ppAP)->AddRef();

	if(FAILED(hr))
	{
		(*ppAP)->Release();
		*ppAP = NULL;
	}

	return hr;
}

//

#pragma pack(push, 1)
template
struct MYD3DVERTEX {float x, y, z, rhw; struct {float u, v;} t[texcoords];};
#pragma pack(pop)

template
static void AdjustQuad(MYD3DVERTEX* v, float dx, float dy)
{
	float offset = 0.5f;

	for(int i = 0; i < 4; i++)
	{
		v[i].x -= offset;
		v[i].y -= offset;
		
		for(int j = 0; j < texcoords-1; j++)
		{
			v[i].t[j].u -= offset*dx;
			v[i].t[j].v -= offset*dy;
		}

		if(texcoords > 1)
		{
			v[i].t[texcoords-1].u -= offset;
			v[i].t[texcoords-1].v -= offset;
		}
	}
}

template
static HRESULT TextureBlt(CComPtr pD3DDev, MYD3DVERTEX v[4], D3DTEXTUREFILTERTYPE filter = D3DTEXF_LINEAR)
{
	if(!pD3DDev)
		return E_POINTER;

	DWORD FVF = 0;

	switch(texcoords)
	{
	case 1: FVF = D3DFVF_TEX1; break;
	case 2: FVF = D3DFVF_TEX2; break;
	case 3: FVF = D3DFVF_TEX3; break;
	case 4: FVF = D3DFVF_TEX4; break;
	case 5: FVF = D3DFVF_TEX5; break;
	case 6: FVF = D3DFVF_TEX6; break;
	case 7: FVF = D3DFVF_TEX7; break;
	case 8: FVF = D3DFVF_TEX8; break;
	default: return E_FAIL;
	}

	HRESULT hr;

    do
	{
        hr = pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
        hr = pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE);
		hr = pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE);
		hr = pD3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE);
    	hr = pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
		hr = pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); 
		hr = pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); 
		hr = pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA|D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED); 

		for(int i = 0; i < texcoords; i++)
		{
			hr = pD3DDev->SetSamplerState(i, D3DSAMP_MAGFILTER, filter);
			hr = pD3DDev->SetSamplerState(i, D3DSAMP_MINFILTER, filter);
			hr = pD3DDev->SetSamplerState(i, D3DSAMP_MIPFILTER, filter);

			hr = pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
			hr = pD3DDev->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
		}

		//

		if(FAILED(hr = pD3DDev->BeginScene()))
			break;

        hr = pD3DDev->SetFVF(D3DFVF_XYZRHW | FVF);
		// hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(v[0]));

		MYD3DVERTEX tmp = v[2]; v[2] = v[3]; v[3] = tmp;
		hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0]));	

		hr = pD3DDev->EndScene();

        //

		for(int i = 0; i < texcoords; i++)
		{
			pD3DDev->SetTexture(i, NULL);
		}

		return S_OK;
    }
	while(0);

    return E_FAIL;
}

// CDX9AllocatorPresenter

CDX9AllocatorPresenter::CDX9AllocatorPresenter(HWND hWnd, HRESULT& hr) 
	: ISubPicAllocatorPresenterImpl(hWnd, hr)
	, m_ScreenSize(0, 0)
	, m_bicubicA(0)
{
	if(FAILED(hr)) return;
	m_pD3D.Attach(Direct3DCreate9(D3D_SDK_VERSION));
	if(!m_pD3D) m_pD3D.Attach(Direct3DCreate9(D3D9b_SDK_VERSION));
	if(!m_pD3D) {hr = E_FAIL; return;}
	hr = CreateDevice();
}

HRESULT CDX9AllocatorPresenter::CreateDevice()
{
	m_pPSC.Free();
    m_pD3DDev = NULL;

	D3DDISPLAYMODE d3dd