DX9AllocatorPresenter.cpp from guliverkli at Krugle
Show DX9AllocatorPresenter.cpp syntax highlighted
/*
* 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 <atlbase.h>
#include <atlcoll.h>
#include "..\..\DSUtil\DSUtil.h"
#include <Videoacc.h>
#include <initguid.h>
#include "DX9AllocatorPresenter.h"
#include <d3d9.h>
#include <d3dx9.h>
#include <Vmr9.h>
#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<IVMRWindowlessControl9>(pBF)) return(true);
EndEnumFilters
return(false);
}
namespace DSObjects
{
class CDX9AllocatorPresenter
: public ISubPicAllocatorPresenterImpl
{
protected:
CSize m_ScreenSize;
bool m_fVMRSyncFix;
CComPtr<IDirect3D9> m_pD3D;
CComPtr<IDirect3DDevice9> m_pD3DDev;
CComPtr<IDirect3DTexture9> m_pVideoTexture[3];
CComPtr<IDirect3DSurface9> m_pVideoSurface[3];
CInterfaceList<IDirect3DPixelShader9> m_pPixelShaders;
CComPtr<IDirect3DPixelShader9> m_pResizerPixelShader[3]; // bl, bc1, bc2
CComPtr<IDirect3DTexture9> m_pResizerBicubic1stPass;
D3DTEXTUREFILTERTYPE m_filter;
D3DCAPS9 m_caps;
CAutoPtr<CPixelShaderCompiler> 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<IDirect3DTexture9> pTexture);
HRESULT TextureResize(CComPtr<IDirect3DTexture9> pTexture, Vector dst[4], D3DTEXTUREFILTERTYPE filter);
HRESULT TextureResizeBilinear(CComPtr<IDirect3DTexture9> pTexture, Vector dst[4]);
HRESULT TextureResizeBicubic1pass(CComPtr<IDirect3DTexture9> pTexture, Vector dst[4]);
HRESULT TextureResizeBicubic2pass(CComPtr<IDirect3DTexture9> 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<IVMRSurfaceAllocatorNotify9> m_pIVMRSurfAllocNotify;
CInterfaceArray<IDirect3DSurface9> 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<IDirect3DSurface9> m_pVideoSurfaceOff;
CComPtr<IDirect3DSurface9> 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<IDirect3DSurface9> 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<IUnknown> m_pDXR;
CComPtr<ISubRenderCallback> 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<int texcoords>
struct MYD3DVERTEX {float x, y, z, rhw; struct {float u, v;} t[texcoords];};
#pragma pack(pop)
template<int texcoords>
static void AdjustQuad(MYD3DVERTEX<texcoords>* 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<int texcoords>
static HRESULT TextureBlt(CComPtr<IDirect3DDevice9> pD3DDev, MYD3DVERTEX<texcoords> 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<texcoords> 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 d3ddm;
ZeroMemory(&d3ddm, sizeof(d3ddm));
if(FAILED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D), &d3ddm)))
return E_UNEXPECTED;
m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height);
D3DPRESENT_PARAMETERS pp;
ZeroMemory(&pp, sizeof(pp));
pp.Windowed = TRUE;
pp.hDeviceWindow = m_hWnd;
pp.SwapEffect = D3DSWAPEFFECT_COPY;
pp.Flags = D3DPRESENTFLAG_VIDEO;
pp.BackBufferWidth = d3ddm.Width;
pp.BackBufferHeight = d3ddm.Height;
pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
if(m_fVMRSyncFix = AfxGetMyApp()->m_s.fVMRSyncFix)
pp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
HRESULT hr = m_pD3D->CreateDevice(
GetAdapter(m_pD3D), D3DDEVTYPE_HAL, m_hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED, //D3DCREATE_MANAGED
&pp, &m_pD3DDev);
/*
HRESULT hr = m_pD3D->CreateDevice(
m_pD3D->GetAdapterCount()-1, D3DDEVTYPE_REF, m_hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED, //D3DCREATE_MANAGED
&pp, &m_pD3DDev);
*/
if(FAILED(hr))
return hr;
m_pPSC.Attach(new CPixelShaderCompiler(m_pD3DDev, true));
//
m_filter = D3DTEXF_NONE;
ZeroMemory(&m_caps, sizeof(m_caps));
m_pD3DDev->GetDeviceCaps(&m_caps);
if((m_caps.StretchRectFilterCaps&D3DPTFILTERCAPS_MINFLINEAR)
&& (m_caps.StretchRectFilterCaps&D3DPTFILTERCAPS_MAGFLINEAR))
m_filter = D3DTEXF_LINEAR;
//
m_bicubicA = 0;
//
CComPtr<ISubPicProvider> pSubPicProvider;
if(m_pSubPicQueue) m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider);
CSize size;
switch(AfxGetAppSettings().nSPCMaxRes)
{
case 0: default: size = m_ScreenSize; break;
case 1: size.SetSize(1024, 768); break;
case 2: size.SetSize(800, 600); break;
case 3: size.SetSize(640, 480); break;
case 4: size.SetSize(512, 384); break;
case 5: size.SetSize(384, 288); break;
}
if(m_pAllocator)
{
m_pAllocator->ChangeDevice(m_pD3DDev);
}
else
{
m_pAllocator = new CDX9SubPicAllocator(m_pD3DDev, size, AfxGetAppSettings().fSPCPow2Tex);
if(!m_pAllocator)
return E_FAIL;
}
hr = S_OK;
m_pSubPicQueue = AfxGetAppSettings().nSPCSize > 0
? (ISubPicQueue*)new CSubPicQueue(AfxGetAppSettings().nSPCSize, m_pAllocator, &hr)
: (ISubPicQueue*)new CSubPicQueueNoThread(m_pAllocator, &hr);
if(!m_pSubPicQueue || FAILED(hr))
return E_FAIL;
if(pSubPicProvider) m_pSubPicQueue->SetSubPicProvider(pSubPicProvider);
return S_OK;
}
HRESULT CDX9AllocatorPresenter::AllocSurfaces()
{
CAutoLock cAutoLock(this);
AppSettings& s = AfxGetAppSettings();
for(int i = 0; i < countof(m_pVideoTexture); i++)
{
m_pVideoTexture[i] = NULL;
m_pVideoSurface[i] = NULL;
}
m_pResizerBicubic1stPass = NULL;
HRESULT hr;
if(s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D || s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D)
{
int nTexturesNeeded = s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D ? countof(m_pVideoTexture) : 1;
for(int i = 0; i < nTexturesNeeded; i++)
{
if(FAILED(hr = m_pD3DDev->CreateTexture(
m_NativeVideoSize.cx, m_NativeVideoSize.cy, 1,
D3DUSAGE_RENDERTARGET, /*D3DFMT_X8R8G8B8*/D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT, &m_pVideoTexture[i], NULL)))
return hr;
if(FAILED(hr = m_pVideoTexture[i]->GetSurfaceLevel(0, &m_pVideoSurface[i])))
return hr;
}
if(s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D)
{
for(int i = 0; i < countof(m_pVideoTexture); i++)
{
m_pVideoTexture[i] = NULL;
}
}
}
else
{
if(FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(
m_NativeVideoSize.cx, m_NativeVideoSize.cy,
D3DFMT_X8R8G8B8/*D3DFMT_A8R8G8B8*/,
D3DPOOL_DEFAULT, &m_pVideoSurface[0], NULL)))
return hr;
}
hr = m_pD3DDev->ColorFill(m_pVideoSurface[0], NULL, 0);
return S_OK;
}
void CDX9AllocatorPresenter::DeleteSurfaces()
{
CAutoLock cAutoLock(this);
for(int i = 0; i < countof(m_pVideoTexture); i++)
{
m_pVideoTexture[i] = NULL;
m_pVideoSurface[i] = NULL;
}
}
UINT CDX9AllocatorPresenter::GetAdapter(IDirect3D9* pD3D)
{
if(m_hWnd == NULL || pD3D == NULL)
return D3DADAPTER_DEFAULT;
HMONITOR hMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST);
if(hMonitor == NULL) return D3DADAPTER_DEFAULT;
for(UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp)
{
HMONITOR hAdpMon = pD3D->GetAdapterMonitor(adp);
if(hAdpMon == hMonitor) return adp;
}
return D3DADAPTER_DEFAULT;
}
// ISubPicAllocatorPresenter
STDMETHODIMP CDX9AllocatorPresenter::CreateRenderer(IUnknown** ppRenderer)
{
return E_NOTIMPL;
}
static bool ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d)
{
D3DSURFACE_DESC d3dsd;
ZeroMemory(&d3dsd, sizeof(d3dsd));
if(FAILED(pSurface->GetDesc(&d3dsd)))
return(false);
int w = d3dsd.Width, h = d3dsd.Height;
int sw = s.Width(), sh = s.Height();
int dw = d.Width(), dh = d.Height();
if(d.left >= w || d.right < 0 || d.top >= h || d.bottom < 0
|| sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0)
{
s.SetRectEmpty();
d.SetRectEmpty();
return(true);
}
if(d.right > w) {s.right -= (d.right-w)*sw/dw; d.right = w;}
if(d.bottom > h) {s.bottom -= (d.bottom-h)*sh/dh; d.bottom = h;}
if(d.left < 0) {s.left += (0-d.left)*sw/dw; d.left = 0;}
if(d.top < 0) {s.top += (0-d.top)*sh/dh; d.top = 0;}
return(true);
}
HRESULT CDX9AllocatorPresenter::InitResizers(float bicubicA)
{
HRESULT hr;
if(m_pResizerPixelShader[0] && m_bicubicA == 0 && bicubicA == 0
|| m_pResizerPixelShader[1] && m_pResizerPixelShader[2] && m_bicubicA == bicubicA && m_pResizerBicubic1stPass)
return S_OK;
m_bicubicA = bicubicA;
m_pResizerBicubic1stPass = NULL;
for(int i = 0; i < countof(m_pResizerPixelShader); i++)
m_pResizerPixelShader[i] = NULL;
if(m_caps.PixelShaderVersion < D3DPS_VERSION(2, 0))
return E_FAIL;
LPCSTR pProfile = m_caps.PixelShaderVersion >= D3DPS_VERSION(3, 0) ? "ps_3_0" : "ps_2_0";
CStringA str;
if(!LoadResource(IDF_SHADER_RESIZER, str, _T("FILE")))
return E_FAIL;
CStringA A;
A.Format("(%f)", bicubicA);
str.Replace("_The_Value_Of_A_Is_Set_Here_", A);
LPCSTR pEntries[] = {"main_bilinear", "main_bicubic1pass", "main_bicubic2pass"};
ASSERT(countof(pEntries) == countof(m_pResizerPixelShader));
for(int i = 0; i < countof(pEntries); i++)
{
hr = m_pPSC->CompileShader(str, pEntries[i], pProfile, 0, &m_pResizerPixelShader[i]);
if(FAILED(hr)) return hr;
}
if(m_bicubicA)
{
if(FAILED(m_pD3DDev->CreateTexture(
min(max(2048, m_ScreenSize.cx), m_caps.MaxTextureWidth), m_NativeVideoSize.cy, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT, &m_pResizerBicubic1stPass, NULL)))
{
ASSERT(0);
m_pResizerBicubic1stPass = NULL; // will do 1 pass then
}
}
return S_OK;
}
HRESULT CDX9AllocatorPresenter::TextureCopy(CComPtr<IDirect3DTexture9> pTexture)
{
HRESULT hr;
D3DSURFACE_DESC desc;
if(!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc)))
return E_FAIL;
float w = (float)desc.Width;
float h = (float)desc.Height;
MYD3DVERTEX<1> v[] =
{
{0, 0, 0.5f, 2.0f, 0, 0},
{w, 0, 0.5f, 2.0f, 1, 0},
{0, h, 0.5f, 2.0f, 0, 1},
{w, h, 0.5f, 2.0f, 1, 1},
};
for(int i = 0; i < countof(v); i++)
{
v[i].x -= 0.5;
v[i].y -= 0.5;
}
hr = m_pD3DDev->SetTexture(0, pTexture);
return TextureBlt(m_pD3DDev, v, D3DTEXF_LINEAR);
}
HRESULT CDX9AllocatorPresenter::TextureResize(CComPtr<IDirect3DTexture9> pTexture, Vector dst[4], D3DTEXTUREFILTERTYPE filter)
{
HRESULT hr;
D3DSURFACE_DESC desc;
if(!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc)))
return E_FAIL;
float w = (float)desc.Width;
float h = (float)desc.Height;
float dx = 1.0f/w;
float dy = 1.0f/h;
MYD3DVERTEX<1> v[] =
{
{dst[0].x, dst[0].y, dst[0].z, 1.0f/dst[0].z, 0, 0},
{dst[1].x, dst[1].y, dst[1].z, 1.0f/dst[1].z, 1, 0},
{dst[2].x, dst[2].y, dst[2].z, 1.0f/dst[2].z, 0, 1},
{dst[3].x, dst[3].y, dst[3].z, 1.0f/dst[3].z, 1, 1},
};
AdjustQuad(v, dx, dy);
hr = m_pD3DDev->SetTexture(0, pTexture);
hr = m_pD3DDev->SetPixelShader(NULL);
hr = TextureBlt(m_pD3DDev, v, filter);
return hr;
}
HRESULT CDX9AllocatorPresenter::TextureResizeBilinear(CComPtr<IDirect3DTexture9> pTexture, Vector dst[4])
{
HRESULT hr;
D3DSURFACE_DESC desc;
if(!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc)))
return E_FAIL;
float w = (float)desc.Width;
float h = (float)desc.Height;
float dx = 1.0f/w;
float dy = 1.0f/h;
MYD3DVERTEX<5> v[] =
{
{dst[0].x, dst[0].y, dst[0].z, 1.0f/dst[0].z, 0, 0, 0+dx, 0, 0, 0+dy, 0+dx, 0+dy, 0, 0},
{dst[1].x, dst[1].y, dst[1].z, 1.0f/dst[1].z, 1, 0, 1+dx, 0, 1, 0+dy, 1+dx, 0+dy, w, 0},
{dst[2].x, dst[2].y, dst[2].z, 1.0f/dst[2].z, 0, 1, 0+dx, 1, 0, 1+dy, 0+dx, 1+dy, 0, h},
{dst[3].x, dst[3].y, dst[3].z, 1.0f/dst[3].z, 1, 1, 1+dx, 1, 1, 1+dy, 1+dx, 1+dy, w, h},
};
AdjustQuad(v, dx, dy);
hr = m_pD3DDev->SetTexture(0, pTexture);
hr = m_pD3DDev->SetTexture(1, pTexture);
hr = m_pD3DDev->SetTexture(2, pTexture);
hr = m_pD3DDev->SetTexture(3, pTexture);
hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[0]);
hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT);
//
m_pD3DDev->SetPixelShader(NULL);
return hr;
}
HRESULT CDX9AllocatorPresenter::TextureResizeBicubic1pass(CComPtr<IDirect3DTexture9> pTexture, Vector dst[4])
{
HRESULT hr;
D3DSURFACE_DESC desc;
if(!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc)))
return E_FAIL;
float w = (float)desc.Width;
float h = (float)desc.Height;
float dx = 1.0f/w;
float dy = 1.0f/h;
MYD3DVERTEX<2> v[] =
{
{dst[0].x, dst[0].y, dst[0].z, 1.0f/dst[0].z, 0, 0, 0, 0},
{dst[1].x, dst[1].y, dst[1].z, 1.0f/dst[1].z, 1, 0, w, 0},
{dst[2].x, dst[2].y, dst[2].z, 1.0f/dst[2].z, 0, 1, 0, h},
{dst[3].x, dst[3].y, dst[3].z, 1.0f/dst[3].z, 1, 1, w, h},
};
AdjustQuad(v, dx, dy);
hr = m_pD3DDev->SetTexture(0, pTexture);
float fConstData[][4] = {{w, h, 0, 0}, {1.0f / w, 1.0f / h, 0, 0}, {1.0f / w, 0, 0, 0}, {0, 1.0f / h, 0, 0}};
hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, countof(fConstData));
hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[1]);
hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT);
m_pD3DDev->SetPixelShader(NULL);
return hr;
}
HRESULT CDX9AllocatorPresenter::TextureResizeBicubic2pass(CComPtr<IDirect3DTexture9> pTexture, Vector dst[4])
{
// return TextureResizeBicubic1pass(pTexture, dst);
HRESULT hr;
// rotated?
if(dst[0].z != dst[1].z || dst[2].z != dst[3].z || dst[0].z != dst[3].z
|| dst[0].y != dst[1].y || dst[0].x != dst[2].x || dst[2].y != dst[3].y || dst[1].x != dst[3].x)
return TextureResizeBicubic1pass(pTexture, dst);
D3DSURFACE_DESC desc;
if(!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc)))
return E_FAIL;
float dx = 1.0f/desc.Width;
float w = (float)desc.Width;
float h = (float)desc.Height;
CRect dst1(0, 0, (int)(dst[3].x - dst[0].x), (int)h);
if(!m_pResizerBicubic1stPass || FAILED(m_pResizerBicubic1stPass->GetLevelDesc(0, &desc)))
return TextureResizeBicubic1pass(pTexture, dst);
float dy = 1.0f/desc.Height;
float dw = (float)dst1.Width() / desc.Width;
float dh = (float)dst1.Height() / desc.Height;
ASSERT(dst1.Height() == desc.Height);
if(dst1.Width() > desc.Width || dst1.Height() > desc.Height)
// if(dst1.Width() != desc.Width || dst1.Height() != desc.Height)
return TextureResizeBicubic1pass(pTexture, dst);
MYD3DVERTEX<5> vx[] =
{
{(float)dst1.left, (float)dst1.top, 0.5f, 2.0f, 0-dx, 0, 0, 0, 0+dx, 0, 0+dx*2, 0, 0, 0},
{(float)dst1.right, (float)dst1.top, 0.5f, 2.0f, 1-dx, 0, 1, 0, 1+dx, 0, 1+dx*2, 0, w, 0},
{(float)dst1.left, (float)dst1.bottom, 0.5f, 2.0f, 0-dx, 1, 0, 1, 0+dx, 1, 0+dx*2, 1, 0, 0},
{(float)dst1.right, (float)dst1.bottom, 0.5f, 2.0f, 1-dx, 1, 1, 1, 1+dx, 1, 1+dx*2, 1, w, 0},
};
AdjustQuad(vx, dx, 0);
MYD3DVERTEX<5> vy[] =
{
{dst[0].x, dst[0].y, dst[0].z, 1.0f/dst[0].z, 0, 0-dy, 0, 0, 0, 0+dy, 0, 0+dy*2, 0, 0},
{dst[1].x, dst[1].y, dst[1].z, 1.0f/dst[1].z, dw, 0-dy, dw, 0, dw, 0+dy, dw, 0+dy*2, 0, 0},
{dst[2].x, dst[2].y, dst[2].z, 1.0f/dst[2].z, 0, dh-dy, 0, dh, 0, dh+dy, 0, dh+dy*2, h, 0},
{dst[3].x, dst[3].y, dst[3].z, 1.0f/dst[3].z, dw, dh-dy, dw, dh, dw, dh+dy, dw, dh+dy*2, h, 0},
};
AdjustQuad(vy, 0, dy);
hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[2]);
hr = m_pD3DDev->SetTexture(0, pTexture);
hr = m_pD3DDev->SetTexture(1, pTexture);
hr = m_pD3DDev->SetTexture(2, pTexture);
hr = m_pD3DDev->SetTexture(3, pTexture);
CComPtr<IDirect3DSurface9> pRTOld;
hr = m_pD3DDev->GetRenderTarget(0, &pRTOld);
CComPtr<IDirect3DSurface9> pRT;
hr = m_pResizerBicubic1stPass->GetSurfaceLevel(0, &pRT);
hr = m_pD3DDev->SetRenderTarget(0, pRT);
hr = TextureBlt(m_pD3DDev, vx, D3DTEXF_POINT);
hr = m_pD3DDev->SetTexture(0, m_pResizerBicubic1stPass);
hr = m_pD3DDev->SetTexture(1, m_pResizerBicubic1stPass);
hr = m_pD3DDev->SetTexture(2, m_pResizerBicubic1stPass);
hr = m_pD3DDev->SetTexture(3, m_pResizerBicubic1stPass);
hr = m_pD3DDev->SetRenderTarget(0, pRTOld);
hr = TextureBlt(m_pD3DDev, vy, D3DTEXF_POINT);
m_pD3DDev->SetPixelShader(NULL);
return hr;
}
STDMETHODIMP_(bool) CDX9AllocatorPresenter::Paint(bool fAll)
{
CAutoLock cAutoLock(this);
if(m_WindowRect.right <= m_WindowRect.left || m_WindowRect.bottom <= m_WindowRect.top
|| m_NativeVideoSize.cx <= 0 || m_NativeVideoSize.cy <= 0
|| !m_pVideoSurface)
return(false);
HRESULT hr;
CRect rSrcVid(CPoint(0, 0), m_NativeVideoSize);
CRect rDstVid(m_VideoRect);
CRect rSrcPri(CPoint(0, 0), m_WindowRect.Size());
CRect rDstPri(m_WindowRect);
CComPtr<IDirect3DSurface9> pBackBuffer;
m_pD3DDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
m_pD3DDev->SetRenderTarget(0, pBackBuffer);
if(fAll)
{
// clear the backbuffer
hr = m_pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0);
// paint the video on the backbuffer
if(!rDstVid.IsRectEmpty())
{
if(m_pVideoTexture[0])
{
CComPtr<IDirect3DTexture9> pVideoTexture = m_pVideoTexture[0];
if(m_pVideoTexture[1] && m_pVideoTexture[2] && !m_pPixelShaders.IsEmpty())
{
static __int64 counter = 0;
static long start = clock();
long stop = clock();
long diff = stop - start;
if(diff >= 10*60*CLOCKS_PER_SEC) start = stop; // reset after 10 min (ps float has its limits in both range and accuracy)
float fConstData[][4] =
{
{(float)m_NativeVideoSize.cx, (float)m_NativeVideoSize.cy, (float)(counter++), (float)diff / CLOCKS_PER_SEC},
{1.0f / m_NativeVideoSize.cx, 1.0f / m_NativeVideoSize.cy, 0, 0},
};
hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, countof(fConstData));
CComPtr<IDirect3DSurface9> pRT;
hr = m_pD3DDev->GetRenderTarget(0, &pRT);
int src = 0, dst = 1;
POSITION pos = m_pPixelShaders.GetHeadPosition();
while(pos)
{
pVideoTexture = m_pVideoTexture[dst];
hr = m_pD3DDev->SetRenderTarget(0, m_pVideoSurface[dst]);
hr = m_pD3DDev->SetPixelShader(m_pPixelShaders.GetNext(pos));
TextureCopy(m_pVideoTexture[src]);
if(++src > 2) src = 1;
if(++dst > 2) dst = 1;
}
hr = m_pD3DDev->SetRenderTarget(0, pRT);
hr = m_pD3DDev->SetPixelShader(NULL);
}
Vector dst[4];
Transform(rDstVid, dst);
DWORD iDX9Resizer = AfxGetAppSettings().iDX9Resizer;
float A = 0;
switch(iDX9Resizer)
{
case 3: A = -0.60f; break;
case 4: A = -0.75f; break;
case 5: A = -1.00f; break;
}
hr = InitResizers(A);
if(iDX9Resizer == 0 || iDX9Resizer == 1 || rSrcVid.Size() == rDstVid.Size() || FAILED(hr))
{
hr = TextureResize(pVideoTexture, dst, iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR);
}
else if(iDX9Resizer == 2)
{
hr = TextureResizeBilinear(pVideoTexture, dst);
}
else if(iDX9Resizer >= 3)
{
hr = TextureResizeBicubic2pass(pVideoTexture, dst);
}
}
else
{
if(pBackBuffer)
{
ClipToSurface(pBackBuffer, rSrcVid, rDstVid); // grrr
// IMPORTANT: rSrcVid has to be aligned on mod2 for yuy2->rgb conversion with StretchRect!!!
rSrcVid.left &= ~1; rSrcVid.right &= ~1;
rSrcVid.top &= ~1; rSrcVid.bottom &= ~1;
hr = m_pD3DDev->StretchRect(m_pVideoSurface[0], rSrcVid, pBackBuffer, rDstVid, m_filter);
}
}
}
// paint the text on the backbuffer
AlphaBltSubPic(rSrcPri.Size());
}
if(m_fVMRSyncFix)
{
D3DLOCKED_RECT lr;
if(SUCCEEDED(pBackBuffer->LockRect(&lr, NULL, 0)))
pBackBuffer->UnlockRect();
}
hr = m_pD3DDev->Present(rSrcPri, rDstPri, NULL, NULL);
bool fResetDevice = false;
if(hr == D3DERR_DEVICELOST && m_pD3DDev->TestCooperativeLevel() == D3DERR_DEVICENOTRESET)
{
fResetDevice = true;
}
D3DDEVICE_CREATION_PARAMETERS Parameters;
if(SUCCEEDED(m_pD3DDev->GetCreationParameters(&Parameters))
&& m_pD3D->GetAdapterMonitor(Parameters.AdapterOrdinal) != m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D)))
{
fResetDevice = true;
}
if(fResetDevice)
{
DeleteSurfaces();
if(FAILED(hr = CreateDevice()) || FAILED(hr = AllocSurfaces()))
return false;
}
return true;
}
STDMETHODIMP CDX9AllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size)
{
CheckPointer(size, E_POINTER);
HRESULT hr;
D3DSURFACE_DESC desc;
memset(&desc, 0, sizeof(desc));
m_pVideoSurface[0]->GetDesc(&desc);
DWORD required = sizeof(BITMAPINFOHEADER) + (desc.Width * desc.Height * 32 >> 3);
if(!lpDib) {*size = required; return S_OK;}
if(*size < required) return E_OUTOFMEMORY;
*size = required;
CComPtr<IDirect3DSurface9> pSurface = m_pVideoSurface[0];
D3DLOCKED_RECT r;
if(FAILED(hr = pSurface->LockRect(&r, NULL, D3DLOCK_READONLY)))
{
pSurface = NULL;
if(FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &pSurface, NULL))
|| FAILED(hr = m_pD3DDev->GetRenderTargetData(m_pVideoSurface[0], pSurface))
|| FAILED(hr = pSurface->LockRect(&r, NULL, D3DLOCK_READONLY)))
return hr;
}
BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)lpDib;
memset(bih, 0, sizeof(BITMAPINFOHEADER));
bih->biSize = sizeof(BITMAPINFOHEADER);
bih->biWidth = desc.Width;
bih->biHeight = desc.Height;
bih->biBitCount = 32;
bih->biPlanes = 1;
bih->biSizeImage = bih->biWidth * bih->biHeight * bih->biBitCount >> 3;
BitBltFromRGBToRGB(
bih->biWidth, bih->biHeight,
(BYTE*)(bih + 1), bih->biWidth*bih->biBitCount>>3, bih->biBitCount,
(BYTE*)r.pBits + r.Pitch*(desc.Height-1), -(int)r.Pitch, 32);
pSurface->UnlockRect();
return S_OK;
}
STDMETHODIMP CDX9AllocatorPresenter::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget)
{
CAutoLock cAutoLock(this);
if(!pSrcData && !pTarget)
{
m_pPixelShaders.RemoveAll();
m_pD3DDev->SetPixelShader(NULL);
return S_OK;
}
if(!pSrcData || !pTarget)
return E_INVALIDARG;
CComPtr<IDirect3DPixelShader9> pPixelShader;
HRESULT hr = m_pPSC->CompileShader(pSrcData, "main", pTarget, 0, &pPixelShader);
if(FAILED(hr)) return hr;
m_pPixelShaders.AddTail(pPixelShader);
Paint(true);
return S_OK;
}
//
// CVMR9AllocatorPresenter
//
#define MY_USER_ID 0x6ABE51
CVMR9AllocatorPresenter::CVMR9AllocatorPresenter(HWND hWnd, HRESULT& hr)
: CDX9AllocatorPresenter(hWnd, hr)
, m_fUseInternalTimer(false)
, m_rtPrevStart(-1)
{
}
STDMETHODIMP CVMR9AllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
CheckPointer(ppv, E_POINTER);
return
QI(IVMRSurfaceAllocator9)
QI(IVMRImagePresenter9)
QI(IVMRWindowlessControl9)
__super::NonDelegatingQueryInterface(riid, ppv);
}
HRESULT CVMR9AllocatorPresenter::CreateDevice()
{
HRESULT hr = __super::CreateDevice();
if(FAILED(hr)) return hr;
if(m_pIVMRSurfAllocNotify)
{
HMONITOR hMonitor = m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D));
if(FAILED(hr = m_pIVMRSurfAllocNotify->ChangeD3DDevice(m_pD3DDev, hMonitor)))
return(false);
}
return hr;
}
void CVMR9AllocatorPresenter::DeleteSurfaces()
{
CAutoLock cAutoLock(this);
m_pSurfaces.RemoveAll();
return __super::DeleteSurfaces();
}
// ISubPicAllocatorPresenter
class COuterVMR9
: public CUnknown
, public IVideoWindow
, public IBasicVideo2
, public IVMRWindowlessControl
{
CComPtr<IUnknown> m_pVMR;
public:
COuterVMR9(const TCHAR* pName, LPUNKNOWN pUnk) : CUnknown(pName, pUnk)
{
m_pVMR.CoCreateInstance(CLSID_VideoMixingRenderer9, GetOwner());
}
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
HRESULT hr = m_pVMR ? m_pVMR->QueryInterface(riid, ppv) : E_NOINTERFACE;
if(m_pVMR && FAILED(hr))
{
if(riid == __uuidof(IVideoWindow))
return GetInterface((IVideoWindow*)this, ppv);
if(riid == __uuidof(IBasicVideo))
return GetInterface((IBasicVideo*)this, ppv);
if(riid == __uuidof(IBasicVideo2))
return GetInterface((IBasicVideo2*)this, ppv);
/* if(riid == __uuidof(IVMRWindowlessControl))
return GetInterface((IVMRWindowlessControl*)this, ppv);
*/ }
return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv);
}
// IVMRWindowlessControl
STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight)
{
if(CComQIPtr<IVMRWindowlessControl9> pWC9 = m_pVMR)
{
return pWC9->GetNativeVideoSize(lpWidth, lpHeight, lpARWidth, lpARHeight);
}
return E_NOTIMPL;
}
STDMETHODIMP GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight) {return E_NOTIMPL;}
STDMETHODIMP GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight) {return E_NOTIMPL;}
STDMETHODIMP SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect) {return E_NOTIMPL;}
STDMETHODIMP GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect)
{
if(CComQIPtr<IVMRWindowlessControl9> pWC9 = m_pVMR)
{
return pWC9->GetVideoPosition(lpSRCRect, lpDSTRect);
}
return E_NOTIMPL;
}
STDMETHODIMP GetAspectRatioMode(DWORD* lpAspectRatioMode)
{
if(CComQIPtr<IVMRWindowlessControl9> pWC9 = m_pVMR)
{
*lpAspectRatioMode = VMR_ARMODE_NONE;
return S_OK;
}
return E_NOTIMPL;
}
STDMETHODIMP SetAspectRatioMode(DWORD AspectRatioMode) {return E_NOTIMPL;}
STDMETHODIMP SetVideoClippingWindow(HWND hwnd) {return E_NOTIMPL;}
STDMETHODIMP RepaintVideo(HWND hwnd, HDC hdc) {return E_NOTIMPL;}
STDMETHODIMP DisplayModeChanged() {return E_NOTIMPL;}
STDMETHODIMP GetCurrentImage(BYTE** lpDib) {return E_NOTIMPL;}
STDMETHODIMP SetBorderColor(COLORREF Clr) {return E_NOTIMPL;}
STDMETHODIMP GetBorderColor(COLORREF* lpClr) {return E_NOTIMPL;}
STDMETHODIMP SetColorKey(COLORREF Clr) {return E_NOTIMPL;}
STDMETHODIMP GetColorKey(COLORREF* lpClr) {return E_NOTIMPL;}
// IVideoWindow
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) {return E_NOTIMPL;}
STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) {return E_NOTIMPL;}
STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) {return E_NOTIMPL;}
STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) {return E_NOTIMPL;}
STDMETHODIMP put_Caption(BSTR strCaption) {return E_NOTIMPL;}
STDMETHODIMP get_Caption(BSTR* strCaption) {return E_NOTIMPL;}
STDMETHODIMP put_WindowStyle(long WindowStyle) {return E_NOTIMPL;}
STDMETHODIMP get_WindowStyle(long* WindowStyle) {return E_NOTIMPL;}
STDMETHODIMP put_WindowStyleEx(long WindowStyleEx) {return E_NOTIMPL;}
STDMETHODIMP get_WindowStyleEx(long* WindowStyleEx) {return E_NOTIMPL;}
STDMETHODIMP put_AutoShow(long AutoShow) {return E_NOTIMPL;}
STDMETHODIMP get_AutoShow(long* AutoShow) {return E_NOTIMPL;}
STDMETHODIMP put_WindowState(long WindowState) {return E_NOTIMPL;}
STDMETHODIMP get_WindowState(long* WindowState) {return E_NOTIMPL;}
STDMETHODIMP put_BackgroundPalette(long BackgroundPalette) {return E_NOTIMPL;}
STDMETHODIMP get_BackgroundPalette(long* pBackgroundPalette) {return E_NOTIMPL;}
STDMETHODIMP put_Visible(long Visible) {return E_NOTIMPL;}
STDMETHODIMP get_Visible(long* pVisible) {return E_NOTIMPL;}
STDMETHODIMP put_Left(long Left) {return E_NOTIMPL;}
STDMETHODIMP get_Left(long* pLeft) {return E_NOTIMPL;}
STDMETHODIMP put_Width(long Width) {return E_NOTIMPL;}
STDMETHODIMP get_Width(long* pWidth)
{
if(CComQIPtr<IVMRWindowlessControl9> pWC9 = m_pVMR)
{
CRect s, d;
HRESULT hr = pWC9->GetVideoPosition(&s, &d);
*pWidth = d.Width();
return hr;
}
return E_NOTIMPL;
}
STDMETHODIMP put_Top(long Top) {return E_NOTIMPL;}
STDMETHODIMP get_Top(long* pTop) {return E_NOTIMPL;}
STDMETHODIMP put_Height(long Height) {return E_NOTIMPL;}
STDMETHODIMP get_Height(long* pHeight)
{
if(CComQIPtr<IVMRWindowlessControl9> pWC9 = m_pVMR)
{
CRect s, d;
HRESULT hr = pWC9->GetVideoPosition(&s, &d);
*pHeight = d.Height();
return hr;
}
return E_NOTIMPL;
}
STDMETHODIMP put_Owner(OAHWND Owner) {return E_NOTIMPL;}
STDMETHODIMP get_Owner(OAHWND* Owner) {return E_NOTIMPL;}
STDMETHODIMP put_MessageDrain(OAHWND Drain) {return E_NOTIMPL;}
STDMETHODIMP get_MessageDrain(OAHWND* Drain) {return E_NOTIMPL;}
STDMETHODIMP get_BorderColor(long* Color) {return E_NOTIMPL;}
STDMETHODIMP put_BorderColor(long Color) {return E_NOTIMPL;}
STDMETHODIMP get_FullScreenMode(long* FullScreenMode) {return E_NOTIMPL;}
STDMETHODIMP put_FullScreenMode(long FullScreenMode) {return E_NOTIMPL;}
STDMETHODIMP SetWindowForeground(long Focus) {return E_NOTIMPL;}
STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd, long uMsg, LONG_PTR wParam, LONG_PTR lParam) {return E_NOTIMPL;}
STDMETHODIMP SetWindowPosition(long Left, long Top, long Width, long Height) {return E_NOTIMPL;}
STDMETHODIMP GetWindowPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) {return E_NOTIMPL;}
STDMETHODIMP GetMinIdealImageSize(long* pWidth, long* pHeight) {return E_NOTIMPL;}
STDMETHODIMP GetMaxIdealImageSize(long* pWidth, long* pHeight) {return E_NOTIMPL;}
STDMETHODIMP GetRestorePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight) {return E_NOTIMPL;}
STDMETHODIMP HideCursor(long HideCursor) {return E_NOTIMPL;}
STDMETHODIMP IsCursorHidden(long* CursorHidden) {return E_NOTIMPL;}
// IBasicVideo2
STDMETHODIMP get_AvgTimePerFrame(REFTIME* pAvgTimePerFrame) {return E_NOTIMPL;}
STDMETHODIMP get_BitRate(long* pBitRate) {return E_NOTIMPL;}
STDMETHODIMP get_BitErrorRate(long* pBitErrorRate) {return E_NOTIMPL;}
STDMETHODIMP get_VideoWidth(long* pVideoWidth) {return E_NOTIMPL;}
STDMETHODIMP get_VideoHeight(long* pVideoHeight) {return E_NOTIMPL;}
STDMETHODIMP put_SourceLeft(long SourceLeft) {return E_NOTIMPL;}
STDMETHODIMP get_SourceLeft(long* pSourceLeft) {return E_NOTIMPL;}
STDMETHODIMP put_SourceWidth(long SourceWidth) {return E_NOTIMPL;}
STDMETHODIMP get_SourceWidth(long* pSourceWidth) {return E_NOTIMPL;}
STDMETHODIMP put_SourceTop(long SourceTop) {return E_NOTIMPL;}
STDMETHODIMP get_SourceTop(long* pSourceTop) {return E_NOTIMPL;}
STDMETHODIMP put_SourceHeight(long SourceHeight) {return E_NOTIMPL;}
STDMETHODIMP get_SourceHeight(long* pSourceHeight) {return E_NOTIMPL;}
STDMETHODIMP put_DestinationLeft(long DestinationLeft) {return E_NOTIMPL;}
STDMETHODIMP get_DestinationLeft(long* pDestinationLeft) {return E_NOTIMPL;}
STDMETHODIMP put_DestinationWidth(long DestinationWidth) {return E_NOTIMPL;}
STDMETHODIMP get_DestinationWidth(long* pDestinationWidth) {return E_NOTIMPL;}
STDMETHODIMP put_DestinationTop(long DestinationTop) {return E_NOTIMPL;}
STDMETHODIMP get_DestinationTop(long* pDestinationTop) {return E_NOTIMPL;}
STDMETHODIMP put_DestinationHeight(long DestinationHeight) {return E_NOTIMPL;}
STDMETHODIMP get_DestinationHeight(long* pDestinationHeight) {return E_NOTIMPL;}
STDMETHODIMP SetSourcePosition(long Left, long Top, long Width, long Height) {return E_NOTIMPL;}
STDMETHODIMP GetSourcePosition(long* pLeft, long* pTop, long* pWidth, long* pHeight)
{
// DVD Nav. bug workaround fix
{
*pLeft = *pTop = 0;
return GetVideoSize(pWidth, pHeight);
}
/*
if(CComQIPtr<IVMRWindowlessControl9> pWC9 = m_pVMR)
{
CRect s, d;
HRESULT hr = pWC9->GetVideoPosition(&s, &d);
*pLeft = s.left;
*pTop = s.top;
*pWidth = s.Width();
*pHeight = s.Height();
return hr;
}
*/
return E_NOTIMPL;
}
STDMETHODIMP SetDefaultSourcePosition() {return E_NOTIMPL;}
STDMETHODIMP SetDestinationPosition(long Left, long Top, long Width, long Height) {return E_NOTIMPL;}
STDMETHODIMP GetDestinationPosition(long* pLeft, long* pTop, long* pWidth, long* pHeight)
{
if(CComQIPtr<IVMRWindowlessControl9> pWC9 = m_pVMR)
{
CRect s, d;
HRESULT hr = pWC9->GetVideoPosition(&s, &d);
*pLeft = d.left;
*pTop = d.top;
*pWidth = d.Width();
*pHeight = d.Height();
return hr;
}
return E_NOTIMPL;
}
STDMETHODIMP SetDefaultDestinationPosition() {return E_NOTIMPL;}
STDMETHODIMP GetVideoSize(long* pWidth, long* pHeight)
{
if(CComQIPtr<IVMRWindowlessControl9> pWC9 = m_pVMR)
{
LONG aw, ah;
// return pWC9->GetNativeVideoSize(pWidth, pHeight, &aw, &ah);
// DVD Nav. bug workaround fix
HRESULT hr = pWC9->GetNativeVideoSize(pWidth, pHeight, &aw, &ah);
*pWidth = *pHeight * aw / ah;
return hr;
}
return E_NOTIMPL;
}
STDMETHODIMP GetVideoPaletteEntries(long StartIndex, long Entries, long* pRetrieved, long* pPalette) {return E_NOTIMPL;}
STDMETHODIMP GetCurrentImage(long* pBufferSize, long* pDIBImage) {return E_NOTIMPL;}
STDMETHODIMP IsUsingDefaultSource() {return E_NOTIMPL;}
STDMETHODIMP IsUsingDefaultDestination() {return E_NOTIMPL;}
STDMETHODIMP GetPreferredAspectRatio(long* plAspectX, long* plAspectY)
{
if(CComQIPtr<IVMRWindowlessControl9> pWC9 = m_pVMR)
{
LONG w, h;
return pWC9->GetNativeVideoSize(&w, &h, plAspectX, plAspectY);
}
return E_NOTIMPL;
}
};
STDMETHODIMP CVMR9AllocatorPresenter::CreateRenderer(IUnknown** ppRenderer)
{
CheckPointer(ppRenderer, E_POINTER);
*ppRenderer = NULL;
HRESULT hr;
do
{
CMacrovisionKicker* pMK = new CMacrovisionKicker(NAME("CMacrovisionKicker"), NULL);
CComPtr<IUnknown> pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK;
pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)new COuterVMR9(NAME("COuterVMR9"), pUnk));
CComQIPtr<IBaseFilter> pBF = pUnk;
/*
CComQIPtr<IBaseFilter> pBF = (IUnknown*)(INonDelegatingUnknown*)new COuterVMR9(NAME("COuterVMR9"), NULL);
if(!pBF) pBF.CoCreateInstance(CLSID_VideoMixingRenderer9);
*/
CComPtr<IPin> pPin = GetFirstPin(pBF);
CComQIPtr<IMemInputPin> pMemInputPin = pPin;
m_fUseInternalTimer = HookNewSegmentAndReceive((IPinC*)(IPin*)pPin, (IMemInputPinC*)(IMemInputPin*)pMemInputPin);
/*
if(CComQIPtr<IAMVideoAccelerator> pAMVA = pPin)
HookAMVideoAccelerator((IAMVideoAcceleratorC*)(IAMVideoAccelerator*)pAMVA);
*/
CComQIPtr<IVMRFilterConfig9> pConfig = pBF;
if(!pConfig)
break;
AppSettings& s = AfxGetAppSettings();
if(s.fVMR9MixerMode)
{
if(FAILED(hr = pConfig->SetNumberOfStreams(1)))
break;
if(s.fVMR9MixerYUV)
{
if(CComQIPtr<IVMRMixerControl9> pMC = pBF)
{
DWORD dwPrefs;
pMC->GetMixingPrefs(&dwPrefs);
dwPrefs &= ~MixerPref9_RenderTargetMask;
dwPrefs |= MixerPref9_RenderTargetYUV;
pMC->SetMixingPrefs(dwPrefs);
}
}
}
if(FAILED(hr = pConfig->SetRenderingMode(VMR9Mode_Renderless)))
break;
CComQIPtr<IVMRSurfaceAllocatorNotify9> pSAN = pBF;
if(!pSAN)
break;
if(FAILED(hr = pSAN->AdviseSurfaceAllocator(MY_USER_ID, static_cast<IVMRSurfaceAllocator9*>(this)))
|| FAILED(hr = AdviseNotify(pSAN)))
break;
*ppRenderer = (IUnknown*)pBF.Detach();
return S_OK;
}
while(0);
return E_FAIL;
}
STDMETHODIMP_(void) CVMR9AllocatorPresenter::SetTime(REFERENCE_TIME rtNow)
{
__super::SetTime(rtNow);
m_fUseInternalTimer = false;
}
// IVMRSurfaceAllocator9
STDMETHODIMP CVMR9AllocatorPresenter::InitializeDevice(DWORD_PTR dwUserID, VMR9AllocationInfo* lpAllocInfo, DWORD* lpNumBuffers)
{
if(!lpAllocInfo || !lpNumBuffers)
return E_POINTER;
if(!m_pIVMRSurfAllocNotify)
return E_FAIL;
if((GetAsyncKeyState(VK_CONTROL)&0x80000000))
if(lpAllocInfo->Format == '21VY' || lpAllocInfo->Format == '024I')
return E_FAIL;
DeleteSurfaces();
m_pSurfaces.SetCount(*lpNumBuffers);
int w = lpAllocInfo->dwWidth;
int h = abs((int)lpAllocInfo->dwHeight);
HRESULT hr;
if(lpAllocInfo->dwFlags & VMR9AllocFlag_3DRenderTarget)
lpAllocInfo->dwFlags |= VMR9AllocFlag_TextureSurface;
hr = m_pIVMRSurfAllocNotify->AllocateSurfaceHelper(lpAllocInfo, lpNumBuffers, &m_pSurfaces[0]);
if(FAILED(hr)) return hr;
m_NativeVideoSize = m_AspectRatio = CSize(w, h);
int arx = lpAllocInfo->szAspectRatio.cx, ary = lpAllocInfo->szAspectRatio.cy;
if(arx > 0 && ary > 0) m_AspectRatio.SetSize(arx, ary);
if(FAILED(hr = AllocSurfaces()))
return hr;
if(!(lpAllocInfo->dwFlags & VMR9AllocFlag_TextureSurface))
{
// test if the colorspace is acceptable
if(FAILED(hr = m_pD3DDev->StretchRect(m_pSurfaces[0], NULL, m_pVideoSurface[0], NULL, D3DTEXF_NONE)))
{
DeleteSurfaces();
return E_FAIL;
}
}
hr = m_pD3DDev->ColorFill(m_pVideoSurface[0], NULL, 0);
return hr;
}
STDMETHODIMP CVMR9AllocatorPresenter::TerminateDevice(DWORD_PTR dwUserID)
{
DeleteSurfaces();
return S_OK;
}
STDMETHODIMP CVMR9AllocatorPresenter::GetSurface(DWORD_PTR dwUserID, DWORD SurfaceIndex, DWORD SurfaceFlags, IDirect3DSurface9** lplpSurface)
{
if(!lplpSurface)
return E_POINTER;
if(SurfaceIndex >= m_pSurfaces.GetCount())
return E_FAIL;
CAutoLock cAutoLock(this);
(*lplpSurface = m_pSurfaces[SurfaceIndex])->AddRef();
return S_OK;
}
STDMETHODIMP CVMR9AllocatorPresenter::AdviseNotify(IVMRSurfaceAllocatorNotify9* lpIVMRSurfAllocNotify)
{
CAutoLock cAutoLock(this);
m_pIVMRSurfAllocNotify = lpIVMRSurfAllocNotify;
HRESULT hr;
HMONITOR hMonitor = m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D));
if(FAILED(hr = m_pIVMRSurfAllocNotify->SetD3DDevice(m_pD3DDev, hMonitor)))
return hr;
return S_OK;
}
// IVMRImagePresenter9
STDMETHODIMP CVMR9AllocatorPresenter::StartPresenting(DWORD_PTR dwUserID)
{
CAutoLock cAutoLock(this);
ASSERT(m_pD3DDev);
return m_pD3DDev ? S_OK : E_FAIL;
}
STDMETHODIMP CVMR9AllocatorPresenter::StopPresenting(DWORD_PTR dwUserID)
{
return S_OK;
}
STDMETHODIMP CVMR9AllocatorPresenter::PresentImage(DWORD_PTR dwUserID, VMR9PresentationInfo* lpPresInfo)
{
CheckPointer(m_pIVMRSurfAllocNotify, E_UNEXPECTED);
HRESULT hr;
if(!lpPresInfo || !lpPresInfo->lpSurf)
return E_POINTER;
CAutoLock cAutoLock(this);
CComPtr<IDirect3DTexture9> pTexture;
lpPresInfo->lpSurf->GetContainer(IID_IDirect3DTexture9, (void**)&pTexture);
if(pTexture)
{
m_pVideoSurface[0] = lpPresInfo->lpSurf;
if(m_pVideoTexture[0]) m_pVideoTexture[0] = pTexture;
}
else
{
hr = m_pD3DDev->StretchRect(lpPresInfo->lpSurf, NULL, m_pVideoSurface[0], NULL, D3DTEXF_NONE);
}
if(lpPresInfo->rtEnd > lpPresInfo->rtStart)
{
REFERENCE_TIME rtTimePerFrame = lpPresInfo->rtEnd - lpPresInfo->rtStart;
m_fps = 10000000.0 / rtTimePerFrame;
if(m_pSubPicQueue)
{
m_pSubPicQueue->SetFPS(m_fps);
if(m_fUseInternalTimer)
{
__super::SetTime(g_tSegmentStart + g_tSampleStart);
}
}
}
CSize VideoSize = m_NativeVideoSize;
int arx = lpPresInfo->szAspectRatio.cx, ary = lpPresInfo->szAspectRatio.cy;
if(arx > 0 && ary > 0) VideoSize.cx = VideoSize.cy*arx/ary;
if(VideoSize != GetVideoSize())
{
m_AspectRatio.SetSize(arx, ary);
AfxGetApp()->m_pMainWnd->PostMessage(WM_REARRANGERENDERLESS);
}
Paint(true);
return S_OK;
}
// IVMRWindowlessControl9
//
// It is only implemented (partially) for the dvd navigator's
// menu handling, which needs to know a few things about the
// location of our window.
STDMETHODIMP CVMR9AllocatorPresenter::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight)
{
if(lpWidth) *lpWidth = m_NativeVideoSize.cx;
if(lpHeight) *lpHeight = m_NativeVideoSize.cy;
if(lpARWidth) *lpARWidth = m_AspectRatio.cx;
if(lpARHeight) *lpARHeight = m_AspectRatio.cy;
return S_OK;
}
STDMETHODIMP CVMR9AllocatorPresenter::GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight) {return E_NOTIMPL;}
STDMETHODIMP CVMR9AllocatorPresenter::GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight) {return E_NOTIMPL;}
STDMETHODIMP CVMR9AllocatorPresenter::SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect) {return E_NOTIMPL;} // we have our own method for this
STDMETHODIMP CVMR9AllocatorPresenter::GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect)
{
CopyRect(lpSRCRect, CRect(CPoint(0, 0), m_NativeVideoSize));
CopyRect(lpDSTRect, &m_VideoRect);
return S_OK;
}
STDMETHODIMP CVMR9AllocatorPresenter::GetAspectRatioMode(DWORD* lpAspectRatioMode)
{
if(lpAspectRatioMode) *lpAspectRatioMode = AM_ARMODE_STRETCHED;
return S_OK;
}
STDMETHODIMP CVMR9AllocatorPresenter::SetAspectRatioMode(DWORD AspectRatioMode) {return E_NOTIMPL;}
STDMETHODIMP CVMR9AllocatorPresenter::SetVideoClippingWindow(HWND hwnd) {return E_NOTIMPL;}
STDMETHODIMP CVMR9AllocatorPresenter::RepaintVideo(HWND hwnd, HDC hdc) {return E_NOTIMPL;}
STDMETHODIMP CVMR9AllocatorPresenter::DisplayModeChanged() {return E_NOTIMPL;}
STDMETHODIMP CVMR9AllocatorPresenter::GetCurrentImage(BYTE** lpDib) {return E_NOTIMPL;}
STDMETHODIMP CVMR9AllocatorPresenter::SetBorderColor(COLORREF Clr) {return E_NOTIMPL;}
STDMETHODIMP CVMR9AllocatorPresenter::GetBorderColor(COLORREF* lpClr)
{
if(lpClr) *lpClr = 0;
return S_OK;
}
//
// CRM9AllocatorPresenter
//
CRM9AllocatorPresenter::CRM9AllocatorPresenter(HWND hWnd, HRESULT& hr)
: CDX9AllocatorPresenter(hWnd, hr)
{
}
STDMETHODIMP CRM9AllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
CheckPointer(ppv, E_POINTER);
return
QI2(IRMAVideoSurface)
__super::NonDelegatingQueryInterface(riid, ppv);
}
HRESULT CRM9AllocatorPresenter::AllocSurfaces()
{
CAutoLock cAutoLock(this);
m_pVideoSurfaceOff = NULL;
m_pVideoSurfaceYUY2 = NULL;
HRESULT hr;
if(FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(
m_NativeVideoSize.cx, m_NativeVideoSize.cy, D3DFMT_X8R8G8B8,
D3DPOOL_DEFAULT, &m_pVideoSurfaceOff, NULL)))
return hr;
m_pD3DDev->ColorFill(m_pVideoSurfaceOff, NULL, 0);
if(FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(
m_NativeVideoSize.cx, m_NativeVideoSize.cy, D3DFMT_YUY2,
D3DPOOL_DEFAULT, &m_pVideoSurfaceYUY2, NULL)))
m_pVideoSurfaceYUY2 = NULL;
if(m_pVideoSurfaceYUY2)
{
m_pD3DDev->ColorFill(m_pVideoSurfaceOff, NULL, 0x80108010);
}
return __super::AllocSurfaces();
}
void CRM9AllocatorPresenter::DeleteSurfaces()
{
CAutoLock cAutoLock(this);
m_pVideoSurfaceOff = NULL;
m_pVideoSurfaceYUY2 = NULL;
__super::DeleteSurfaces();
}
// IRMAVideoSurface
STDMETHODIMP CRM9AllocatorPresenter::Blt(UCHAR* pImageData, RMABitmapInfoHeader* pBitmapInfo, REF(PNxRect) inDestRect, REF(PNxRect) inSrcRect)
{
if(!m_pVideoSurface || !m_pVideoSurfaceOff)
return E_FAIL;
bool fRGB = false;
bool fYUY2 = false;
CRect src((RECT*)&inSrcRect), dst((RECT*)&inDestRect), src2(CPoint(0,0), src.Size());
if(src.Width() > dst.Width() || src.Height() > dst.Height())
return E_FAIL;
D3DSURFACE_DESC d3dsd;
ZeroMemory(&d3dsd, sizeof(d3dsd));
if(FAILED(m_pVideoSurfaceOff->GetDesc(&d3dsd)))
return E_FAIL;
int dbpp =
d3dsd.Format == D3DFMT_R8G8B8 || d3dsd.Format == D3DFMT_X8R8G8B8 || d3dsd.Format == D3DFMT_A8R8G8B8 ? 32 :
d3dsd.Format == D3DFMT_R5G6B5 ? 16 : 0;
if(pBitmapInfo->biCompression == '024I')
{
DWORD pitch = pBitmapInfo->biWidth;
DWORD size = pitch*abs(pBitmapInfo->biHeight);
BYTE* y = pImageData + src.top*pitch + src.left;
BYTE* u = pImageData + size + src.top*(pitch/2) + src.left/2;
BYTE* v = pImageData + size + size/4 + src.top*(pitch/2) + src.left/2;
if(m_pVideoSurfaceYUY2)
{
D3DLOCKED_RECT r;
if(SUCCEEDED(m_pVideoSurfaceYUY2->LockRect(&r, src2, 0)))
{
BitBltFromI420ToYUY2(src.Width(), src.Height(), (BYTE*)r.pBits, r.Pitch, y, u, v, pitch);
m_pVideoSurfaceYUY2->UnlockRect();
fYUY2 = true;
}
}
else
{
D3DLOCKED_RECT r;
if(SUCCEEDED(m_pVideoSurfaceOff->LockRect(&r, src2, 0)))
{
BitBltFromI420ToRGB(src.Width(), src.Height(), (BYTE*)r.pBits, r.Pitch, dbpp, y, u, v, pitch);
m_pVideoSurfaceOff->UnlockRect();
fRGB = true;
}
}
}
else if(pBitmapInfo->biCompression == '2YUY')
{
DWORD w = pBitmapInfo->biWidth;
DWORD h = abs(pBitmapInfo->biHeight);
DWORD pitch = pBitmapInfo->biWidth*2;
BYTE* yvyu = pImageData + src.top*pitch + src.left*2;
if(m_pVideoSurfaceYUY2)
{
D3DLOCKED_RECT r;
if(SUCCEEDED(m_pVideoSurfaceYUY2->LockRect(&r, src2, 0)))
{
BitBltFromYUY2ToYUY2(src.Width(), src.Height(), (BYTE*)r.pBits, r.Pitch, yvyu, pitch);
m_pVideoSurfaceYUY2->UnlockRect();
fYUY2 = true;
}
}
else
{
D3DLOCKED_RECT r;
if(SUCCEEDED(m_pVideoSurfaceOff->LockRect(&r, src2, 0)))
{
BitBltFromYUY2ToRGB(src.Width(), src.Height(), (BYTE*)r.pBits, r.Pitch, dbpp, yvyu, pitch);
m_pVideoSurfaceOff->UnlockRect();
fRGB = true;
}
}
}
else if(pBitmapInfo->biCompression == 0 || pBitmapInfo->biCompression == 3
|| pBitmapInfo->biCompression == 'BGRA')
{
DWORD w = pBitmapInfo->biWidth;
DWORD h = abs(pBitmapInfo->biHeight);
DWORD pitch = pBitmapInfo->biWidth*pBitmapInfo->biBitCount>>3;
BYTE* rgb = pImageData + src.top*pitch + src.left*(pBitmapInfo->biBitCount>>3);
D3DLOCKED_RECT r;
if(SUCCEEDED(m_pVideoSurfaceOff->LockRect(&r, src2, 0)))
{
BYTE* pBits = (BYTE*)r.pBits;
if(pBitmapInfo->biHeight > 0) {pBits += r.Pitch*(src.Height()-1); r.Pitch = -r.Pitch;}
BitBltFromRGBToRGB(src.Width(), src.Height(), pBits, r.Pitch, dbpp, rgb, pitch, pBitmapInfo->biBitCount);
m_pVideoSurfaceOff->UnlockRect();
fRGB = true;
}
}
if(!fRGB && !fYUY2)
{
m_pD3DDev->ColorFill(m_pVideoSurfaceOff, NULL, 0);
HDC hDC;
if(SUCCEEDED(m_pVideoSurfaceOff->GetDC(&hDC)))
{
CString str;
str.Format(_T("Sorry, this format is not supported"));
SetBkColor(hDC, 0);
SetTextColor(hDC, 0x404040);
TextOut(hDC, 10, 10, str, str.GetLength());
m_pVideoSurfaceOff->ReleaseDC(hDC);
fRGB = true;
}
}
HRESULT hr;
if(fRGB)
hr = m_pD3DDev->StretchRect(m_pVideoSurfaceOff, src2, m_pVideoSurface[0], dst, D3DTEXF_NONE);
if(fYUY2)
hr = m_pD3DDev->StretchRect(m_pVideoSurfaceYUY2, src2, m_pVideoSurface[0], dst, D3DTEXF_NONE);
Paint(true);
return PNR_OK;
}
STDMETHODIMP CRM9AllocatorPresenter::BeginOptimizedBlt(RMABitmapInfoHeader* pBitmapInfo)
{
CAutoLock cAutoLock(this);
DeleteSurfaces();
m_NativeVideoSize = m_AspectRatio = CSize(pBitmapInfo->biWidth, abs(pBitmapInfo->biHeight));
if(FAILED(AllocSurfaces())) return E_FAIL;
return PNR_NOTIMPL;
}
STDMETHODIMP CRM9AllocatorPresenter::OptimizedBlt(UCHAR* pImageBits, REF(PNxRect) rDestRect, REF(PNxRect) rSrcRect)
{
return PNR_NOTIMPL;
}
STDMETHODIMP CRM9AllocatorPresenter::EndOptimizedBlt()
{
return PNR_NOTIMPL;
}
STDMETHODIMP CRM9AllocatorPresenter::GetOptimizedFormat(REF(RMA_COMPRESSION_TYPE) ulType)
{
return PNR_NOTIMPL;
}
STDMETHODIMP CRM9AllocatorPresenter::GetPreferredFormat(REF(RMA_COMPRESSION_TYPE) ulType)
{
ulType = RMA_I420;
return PNR_OK;
}
//
// CQT9AllocatorPresenter
//
CQT9AllocatorPresenter::CQT9AllocatorPresenter(HWND hWnd, HRESULT& hr)
: CDX9AllocatorPresenter(hWnd, hr)
{
}
STDMETHODIMP CQT9AllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
CheckPointer(ppv, E_POINTER);
return
QI(IQTVideoSurface)
__super::NonDelegatingQueryInterface(riid, ppv);
}
HRESULT CQT9AllocatorPresenter::AllocSurfaces()
{
HRESULT hr;
m_pVideoSurfaceOff = NULL;
if(FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(
m_NativeVideoSize.cx, m_NativeVideoSize.cy, D3DFMT_X8R8G8B8,
D3DPOOL_DEFAULT, &m_pVideoSurfaceOff, NULL)))
return hr;
return __super::AllocSurfaces();
}
void CQT9AllocatorPresenter::DeleteSurfaces()
{
m_pVideoSurfaceOff = NULL;
__super::DeleteSurfaces();
}
// IQTVideoSurface
STDMETHODIMP CQT9AllocatorPresenter::BeginBlt(const BITMAP& bm)
{
CAutoLock cAutoLock(this);
DeleteSurfaces();
m_NativeVideoSize = m_AspectRatio = CSize(bm.bmWidth, abs(bm.bmHeight));
if(FAILED(AllocSurfaces())) return E_FAIL;
return S_OK;
}
STDMETHODIMP CQT9AllocatorPresenter::DoBlt(const BITMAP& bm)
{
if(!m_pVideoSurface || !m_pVideoSurfaceOff)
return E_FAIL;
bool fOk = false;
D3DSURFACE_DESC d3dsd;
ZeroMemory(&d3dsd, sizeof(d3dsd));
if(FAILED(m_pVideoSurfaceOff->GetDesc(&d3dsd)))
return E_FAIL;
int w = bm.bmWidth;
int h = abs(bm.bmHeight);
int bpp = bm.bmBitsPixel;
int dbpp =
d3dsd.Format == D3DFMT_R8G8B8 || d3dsd.Format == D3DFMT_X8R8G8B8 || d3dsd.Format == D3DFMT_A8R8G8B8 ? 32 :
d3dsd.Format == D3DFMT_R5G6B5 ? 16 : 0;
if((bpp == 16 || bpp == 24 || bpp == 32) && w == d3dsd.Width && h == d3dsd.Height)
{
D3DLOCKED_RECT r;
if(SUCCEEDED(m_pVideoSurfaceOff->LockRect(&r, NULL, 0)))
{
BitBltFromRGBToRGB(
w, h,
(BYTE*)r.pBits, r.Pitch, dbpp,
(BYTE*)bm.bmBits, bm.bmWidthBytes, bm.bmBitsPixel);
m_pVideoSurfaceOff->UnlockRect();
fOk = true;
}
}
if(!fOk)
{
m_pD3DDev->ColorFill(m_pVideoSurfaceOff, NULL, 0);
HDC hDC;
if(SUCCEEDED(m_pVideoSurfaceOff->GetDC(&hDC)))
{
CString str;
str.Format(_T("Sorry, this color format is not supported"));
SetBkColor(hDC, 0);
SetTextColor(hDC, 0x404040);
TextOut(hDC, 10, 10, str, str.GetLength());
m_pVideoSurfaceOff->ReleaseDC(hDC);
}
}
m_pD3DDev->StretchRect(m_pVideoSurfaceOff, NULL, m_pVideoSurface[0], NULL, D3DTEXF_NONE);
Paint(true);
return S_OK;
}
//
// CDXRAllocatorPresenter
//
CDXRAllocatorPresenter::CDXRAllocatorPresenter(HWND hWnd, HRESULT& hr)
: ISubPicAllocatorPresenterImpl(hWnd, hr)
{
if(FAILED(hr)) return;
hr = S_OK;
}
CDXRAllocatorPresenter::~CDXRAllocatorPresenter()
{
if(m_pSRCB)
{
// nasty, but we have to let it know about our death somehow
((CSubRenderCallback*)(ISubRenderCallback*)m_pSRCB)->SetDXRAP(NULL);
}
// the order is important here
m_pSubPicQueue = NULL;
m_pAllocator = NULL;
m_pDXR = NULL;
}
STDMETHODIMP CDXRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
/*
if(riid == __uuidof(IVideoWindow))
return GetInterface((IVideoWindow*)this, ppv);
if(riid == __uuidof(IBasicVideo))
return GetInterface((IBasicVideo*)this, ppv);
if(riid == __uuidof(IBasicVideo2))
return GetInterface((IBasicVideo2*)this, ppv);
*/
/*
if(riid == __uuidof(IVMRWindowlessControl))
return GetInterface((IVMRWindowlessControl*)this, ppv);
*/
if(riid != IID_IUnknown && m_pDXR)
{
if(SUCCEEDED(m_pDXR->QueryInterface(riid, ppv)))
return S_OK;
}
return __super::NonDelegatingQueryInterface(riid, ppv);
}
HRESULT CDXRAllocatorPresenter::SetDevice(IDirect3DDevice9* pD3DDev)
{
CheckPointer(pD3DDev, E_POINTER);
CSize size;
switch(AfxGetAppSettings().nSPCMaxRes)
{
// TODO: m_ScreenSize ?
// case 0: default: size = m_ScreenSize; break;
default:
case 1: size.SetSize(1024, 768); break;
case 2: size.SetSize(800, 600); break;
case 3: size.SetSize(640, 480); break;
case 4: size.SetSize(512, 384); break;
case 5: size.SetSize(384, 288); break;
}
if(m_pAllocator)
{
m_pAllocator->ChangeDevice(pD3DDev);
}
else
{
m_pAllocator = new CDX9SubPicAllocator(pD3DDev, size, AfxGetAppSettings().fSPCPow2Tex);
if(!m_pAllocator)
return E_FAIL;
}
HRESULT hr = S_OK;
m_pSubPicQueue = AfxGetAppSettings().nSPCSize > 0
? (ISubPicQueue*)new CSubPicQueue(AfxGetAppSettings().nSPCSize, m_pAllocator, &hr)
: (ISubPicQueue*)new CSubPicQueueNoThread(m_pAllocator, &hr);
if(!m_pSubPicQueue || FAILED(hr))
return E_FAIL;
if(m_SubPicProvider) m_pSubPicQueue->SetSubPicProvider(m_SubPicProvider);
return S_OK;
}
HRESULT CDXRAllocatorPresenter::Render(
REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, REFERENCE_TIME atpf,
int left, int top, int right, int bottom, int width, int height)
{
__super::SetPosition(CRect(0, 0, width, height), CRect(left, top, right, bottom)); // needed? should be already set by the player
SetTime(rtStart);
if(atpf > 0 && m_pSubPicQueue) m_pSubPicQueue->SetFPS(10000000.0 / atpf);
AlphaBltSubPic(CSize(width, height));
return S_OK;
}
// ISubPicAllocatorPresenter
STDMETHODIMP CDXRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer)
{
CheckPointer(ppRenderer, E_POINTER);
if(m_pDXR) return E_UNEXPECTED;
m_pDXR.CoCreateInstance(CLSID_DXR, GetOwner());
if(!m_pDXR) return E_FAIL;
CComQIPtr<ISubRender> pSR = m_pDXR;
if(!pSR) {m_pDXR = NULL; return E_FAIL;}
m_pSRCB = new CSubRenderCallback(this);
if(FAILED(pSR->SetCallback(m_pSRCB))) {m_pDXR = NULL; return E_FAIL;}
(*ppRenderer = this)->AddRef();
return S_OK;
}
STDMETHODIMP_(void) CDXRAllocatorPresenter::SetPosition(RECT w, RECT v)
{
if(CComQIPtr<IBasicVideo> pBV = m_pDXR)
{
pBV->SetDefaultSourcePosition();
pBV->SetDestinationPosition(v.left, v.top, v.right - v.left, v.bottom - v.top);
}
if(CComQIPtr<IVideoWindow> pVW = m_pDXR)
{
pVW->SetWindowPosition(w.left, w.top, w.right - w.left, w.bottom - w.top);
}
}
STDMETHODIMP_(SIZE) CDXRAllocatorPresenter::GetVideoSize(bool fCorrectAR)
{
SIZE size = {0, 0};
if(!fCorrectAR)
{
if(CComQIPtr<IBasicVideo> pBV = m_pDXR)
pBV->GetVideoSize(&size.cx, &size.cy);
}
else
{
if(CComQIPtr<IBasicVideo2> pBV2 = m_pDXR)
pBV2->GetPreferredAspectRatio(&size.cx, &size.cy);
}
return size;
}
STDMETHODIMP_(bool) CDXRAllocatorPresenter::Paint(bool fAll)
{
return false; // TODO
}
STDMETHODIMP CDXRAllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size)
{
HRESULT hr = E_NOTIMPL;
if(CComQIPtr<IBasicVideo> pBV = m_pDXR)
hr = pBV->GetCurrentImage((long*)size, (long*)lpDib);
return hr;
}
STDMETHODIMP CDXRAllocatorPresenter::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget)
{
return E_NOTIMPL; // TODO
}
See more files for this project here