diff options
author | kinddragon <kinddragon@users.sourceforge.net> | 2010-05-10 02:19:44 +0400 |
---|---|---|
committer | kinddragon <kinddragon@users.sourceforge.net> | 2010-05-10 02:19:44 +0400 |
commit | 145591c273c8ad7e5be88b7031b5dab79bbb50dc (patch) | |
tree | f22b6a57710bcd05223412670dc92cd28501cd9d /src/filters/renderer | |
parent | c96bab8947a48e6f0c98cf20b654b7f5bf5641b8 (diff) | |
parent | 7b6b0c551b34ffc5da173e05bdb57875cffa24f1 (diff) |
Branch videorenderslib merged to trunk
git-svn-id: https://mpc-hc.svn.sourceforge.net/svnroot/mpc-hc/trunk@1872 10f7b99b-c216-0410-bff0-8a66a9350fd8
Diffstat (limited to 'src/filters/renderer')
43 files changed, 20517 insertions, 0 deletions
diff --git a/src/filters/renderer/VideoRenderers/AllocatorCommon.cpp b/src/filters/renderer/VideoRenderers/AllocatorCommon.cpp new file mode 100644 index 000000000..311f6bc97 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/AllocatorCommon.cpp @@ -0,0 +1,322 @@ +/*
+ * $Id$
+ *
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include <initguid.h>
+#include "AllocatorCommon.h"
+#include "../DSUtil/DSUtil.h"
+
+#include "VMR9AllocatorPresenter.h"
+#include "RM9AllocatorPresenter.h"
+#include "QT9AllocatorPresenter.h"
+#include "DXRAllocatorPresenter.h"
+#include "madVRAllocatorPresenter.h"
+#include "EVRAllocatorPresenter.h"
+
+bool IsVMR9InGraph(IFilterGraph* pFG)
+{
+ BeginEnumFilters(pFG, pEF, pBF)
+ if(CComQIPtr<IVMRWindowlessControl9>(pBF)) return(true);
+ EndEnumFilters
+ return(false);
+}
+
+//
+
+HRESULT CreateAP9(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP)
+{
+ CheckPointer(ppAP, E_POINTER);
+
+ *ppAP = NULL;
+
+ using namespace DSObjects;
+
+ HRESULT hr = E_FAIL;
+ CString Error;
+ if(clsid == CLSID_VMR9AllocatorPresenter && !(*ppAP = DNew CVMR9AllocatorPresenter(hWnd, bFullscreen, hr, Error))
+ || clsid == CLSID_RM9AllocatorPresenter && !(*ppAP = DNew CRM9AllocatorPresenter(hWnd, bFullscreen, hr, Error))
+ || clsid == CLSID_QT9AllocatorPresenter && !(*ppAP = DNew CQT9AllocatorPresenter(hWnd, bFullscreen, hr, Error))
+ || clsid == CLSID_DXRAllocatorPresenter && !(*ppAP = DNew CDXRAllocatorPresenter(hWnd, hr, Error))
+ || clsid == CLSID_madVRAllocatorPresenter && !(*ppAP = DNew CmadVRAllocatorPresenter(hWnd, hr, Error)))
+ return E_OUTOFMEMORY;
+
+ if(*ppAP == NULL)
+ return E_FAIL;
+
+ (*ppAP)->AddRef();
+
+ if(FAILED(hr))
+ {
+ Error += L"\n";
+ Error += GetWindowsErrorMessage(hr, NULL);
+
+ MessageBox(hWnd, Error, L"Error creating DX9 allocation presenter", MB_OK|MB_ICONERROR);
+ (*ppAP)->Release();
+ *ppAP = NULL;
+ }
+ else if (!Error.IsEmpty())
+ {
+ MessageBox(hWnd, Error, L"Warning creating DX9 allocation presenter", MB_OK|MB_ICONWARNING);
+ }
+
+ return hr;
+}
+
+HRESULT CreateEVR(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP)
+{
+ HRESULT hr = E_FAIL;
+ if (clsid == CLSID_EVRAllocatorPresenter)
+ {
+ CString Error;
+ *ppAP = DNew DSObjects::CEVRAllocatorPresenter(hWnd, bFullscreen, hr, Error);
+ (*ppAP)->AddRef();
+
+ if(FAILED(hr))
+ {
+ Error += L"\n";
+ Error += GetWindowsErrorMessage(hr, NULL);
+ MessageBox(hWnd, Error, L"Error creating EVR Custom renderer", MB_OK | MB_ICONERROR);
+ (*ppAP)->Release();
+ *ppAP = NULL;
+ }
+ else if (!Error.IsEmpty())
+ {
+ MessageBox(hWnd, Error, L"Warning creating EVR Custom renderer", MB_OK|MB_ICONWARNING);
+ }
+ }
+
+ return hr;
+}
+
+CString GetWindowsErrorMessage(HRESULT _Error, HMODULE _Module)
+{
+
+ switch (_Error)
+ {
+ case D3DERR_WRONGTEXTUREFORMAT :
+ return _T("D3DERR_WRONGTEXTUREFORMAT");
+ case D3DERR_UNSUPPORTEDCOLOROPERATION :
+ return _T("D3DERR_UNSUPPORTEDCOLOROPERATION");
+ case D3DERR_UNSUPPORTEDCOLORARG :
+ return _T("D3DERR_UNSUPPORTEDCOLORARG");
+ case D3DERR_UNSUPPORTEDALPHAOPERATION :
+ return _T("D3DERR_UNSUPPORTEDALPHAOPERATION");
+ case D3DERR_UNSUPPORTEDALPHAARG :
+ return _T("D3DERR_UNSUPPORTEDALPHAARG");
+ case D3DERR_TOOMANYOPERATIONS :
+ return _T("D3DERR_TOOMANYOPERATIONS");
+ case D3DERR_CONFLICTINGTEXTUREFILTER :
+ return _T("D3DERR_CONFLICTINGTEXTUREFILTER");
+ case D3DERR_UNSUPPORTEDFACTORVALUE :
+ return _T("D3DERR_UNSUPPORTEDFACTORVALUE");
+ case D3DERR_CONFLICTINGRENDERSTATE :
+ return _T("D3DERR_CONFLICTINGRENDERSTATE");
+ case D3DERR_UNSUPPORTEDTEXTUREFILTER :
+ return _T("D3DERR_UNSUPPORTEDTEXTUREFILTER");
+ case D3DERR_CONFLICTINGTEXTUREPALETTE :
+ return _T("D3DERR_CONFLICTINGTEXTUREPALETTE");
+ case D3DERR_DRIVERINTERNALERROR :
+ return _T("D3DERR_DRIVERINTERNALERROR");
+ case D3DERR_NOTFOUND :
+ return _T("D3DERR_NOTFOUND");
+ case D3DERR_MOREDATA :
+ return _T("D3DERR_MOREDATA");
+ case D3DERR_DEVICELOST :
+ return _T("D3DERR_DEVICELOST");
+ case D3DERR_DEVICENOTRESET :
+ return _T("D3DERR_DEVICENOTRESET");
+ case D3DERR_NOTAVAILABLE :
+ return _T("D3DERR_NOTAVAILABLE");
+ case D3DERR_OUTOFVIDEOMEMORY :
+ return _T("D3DERR_OUTOFVIDEOMEMORY");
+ case D3DERR_INVALIDDEVICE :
+ return _T("D3DERR_INVALIDDEVICE");
+ case D3DERR_INVALIDCALL :
+ return _T("D3DERR_INVALIDCALL");
+ case D3DERR_DRIVERINVALIDCALL :
+ return _T("D3DERR_DRIVERINVALIDCALL");
+ case D3DERR_WASSTILLDRAWING :
+ return _T("D3DERR_WASSTILLDRAWING");
+ case D3DOK_NOAUTOGEN :
+ return _T("D3DOK_NOAUTOGEN");
+ case D3DERR_DEVICEREMOVED :
+ return _T("D3DERR_DEVICEREMOVED");
+ case S_NOT_RESIDENT :
+ return _T("S_NOT_RESIDENT");
+ case S_RESIDENT_IN_SHARED_MEMORY :
+ return _T("S_RESIDENT_IN_SHARED_MEMORY");
+ case S_PRESENT_MODE_CHANGED :
+ return _T("S_PRESENT_MODE_CHANGED");
+ case S_PRESENT_OCCLUDED :
+ return _T("S_PRESENT_OCCLUDED");
+ case D3DERR_DEVICEHUNG :
+ return _T("D3DERR_DEVICEHUNG");
+ case E_UNEXPECTED :
+ return _T("E_UNEXPECTED");
+ }
+
+ CString errmsg;
+ LPVOID lpMsgBuf;
+ if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_HMODULE,
+ _Module, _Error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL))
+ {
+ errmsg = (LPCTSTR)lpMsgBuf;
+ LocalFree(lpMsgBuf);
+ }
+ CString Temp;
+ Temp.Format(L"0x%08x ", _Error);
+ return Temp + errmsg;
+}
+
+const wchar_t *GetD3DFormatStr(D3DFORMAT Format)
+{
+ switch (Format)
+ {
+ case D3DFMT_R8G8B8 :
+ return L"R8G8B8";
+ case D3DFMT_A8R8G8B8 :
+ return L"A8R8G8B8";
+ case D3DFMT_X8R8G8B8 :
+ return L"X8R8G8B8";
+ case D3DFMT_R5G6B5 :
+ return L"R5G6B5";
+ case D3DFMT_X1R5G5B5 :
+ return L"X1R5G5B5";
+ case D3DFMT_A1R5G5B5 :
+ return L"A1R5G5B5";
+ case D3DFMT_A4R4G4B4 :
+ return L"A4R4G4B4";
+ case D3DFMT_R3G3B2 :
+ return L"R3G3B2";
+ case D3DFMT_A8 :
+ return L"A8";
+ case D3DFMT_A8R3G3B2 :
+ return L"A8R3G3B2";
+ case D3DFMT_X4R4G4B4 :
+ return L"X4R4G4B4";
+ case D3DFMT_A2B10G10R10:
+ return L"A2B10G10R10";
+ case D3DFMT_A8B8G8R8 :
+ return L"A8B8G8R8";
+ case D3DFMT_X8B8G8R8 :
+ return L"X8B8G8R8";
+ case D3DFMT_G16R16 :
+ return L"G16R16";
+ case D3DFMT_A2R10G10B10:
+ return L"A2R10G10B10";
+ case D3DFMT_A16B16G16R16 :
+ return L"A16B16G16R16";
+ case D3DFMT_A8P8 :
+ return L"A8P8";
+ case D3DFMT_P8 :
+ return L"P8";
+ case D3DFMT_L8 :
+ return L"L8";
+ case D3DFMT_A8L8 :
+ return L"A8L8";
+ case D3DFMT_A4L4 :
+ return L"A4L4";
+ case D3DFMT_V8U8 :
+ return L"V8U8";
+ case D3DFMT_L6V5U5 :
+ return L"L6V5U5";
+ case D3DFMT_X8L8V8U8 :
+ return L"X8L8V8U8";
+ case D3DFMT_Q8W8V8U8 :
+ return L"Q8W8V8U8";
+ case D3DFMT_V16U16 :
+ return L"V16U16";
+ case D3DFMT_A2W10V10U10:
+ return L"A2W10V10U10";
+ case D3DFMT_UYVY :
+ return L"UYVY";
+ case D3DFMT_R8G8_B8G8:
+ return L"R8G8_B8G8";
+ case D3DFMT_YUY2 :
+ return L"YUY2";
+ case D3DFMT_G8R8_G8B8:
+ return L"G8R8_G8B8";
+ case D3DFMT_DXT1 :
+ return L"DXT1";
+ case D3DFMT_DXT2 :
+ return L"DXT2";
+ case D3DFMT_DXT3 :
+ return L"DXT3";
+ case D3DFMT_DXT4 :
+ return L"DXT4";
+ case D3DFMT_DXT5 :
+ return L"DXT5";
+ case D3DFMT_D16_LOCKABLE :
+ return L"D16_LOCKABLE";
+ case D3DFMT_D32:
+ return L"D32";
+ case D3DFMT_D15S1:
+ return L"D15S1";
+ case D3DFMT_D24S8:
+ return L"D24S8";
+ case D3DFMT_D24X8:
+ return L"D24X8";
+ case D3DFMT_D24X4S4:
+ return L"D24X4S4";
+ case D3DFMT_D16:
+ return L"D16";
+ case D3DFMT_D32F_LOCKABLE:
+ return L"D32F_LOCKABLE";
+ case D3DFMT_D24FS8 :
+ return L"D24FS8";
+ case D3DFMT_D32_LOCKABLE :
+ return L"D32_LOCKABLE";
+ case D3DFMT_S8_LOCKABLE:
+ return L"S8_LOCKABLE";
+ case D3DFMT_L16:
+ return L"L16";
+ case D3DFMT_VERTEXDATA :
+ return L"VERTEXDATA";
+ case D3DFMT_INDEX16:
+ return L"INDEX16";
+ case D3DFMT_INDEX32:
+ return L"INDEX32";
+ case D3DFMT_Q16W16V16U16 :
+ return L"Q16W16V16U16";
+ case D3DFMT_MULTI2_ARGB8 :
+ return L"MULTI2_ARGB8";
+ case D3DFMT_R16F :
+ return L"R16F";
+ case D3DFMT_G16R16F:
+ return L"G16R16F";
+ case D3DFMT_A16B16G16R16F:
+ return L"A16B16G16R16F";
+ case D3DFMT_R32F :
+ return L"R32F";
+ case D3DFMT_G32R32F:
+ return L"G32R32F";
+ case D3DFMT_A32B32G32R32F:
+ return L"A32B32G32R32F";
+ case D3DFMT_CxV8U8 :
+ return L"CxV8U8";
+ case D3DFMT_A1 :
+ return L"A1";
+ case D3DFMT_BINARYBUFFER :
+ return L"BINARYBUFFER";
+ }
+ return L"Unknown";
+}
diff --git a/src/filters/renderer/VideoRenderers/AllocatorCommon.h b/src/filters/renderer/VideoRenderers/AllocatorCommon.h new file mode 100644 index 000000000..e132c3c44 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/AllocatorCommon.h @@ -0,0 +1,79 @@ +/*
+ * $Id$
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <d3d9.h>
+#include <d3dx9.h>
+#include <Vmr9.h>
+#include "../SubPic/ISubPic.h"
+#include "../SubPic/DX9SubPic.h"
+#include "PixelShaderCompiler.h"
+
+// {4E4834FA-22C2-40e2-9446-F77DD05D245E}
+DEFINE_GUID(CLSID_VMR9AllocatorPresenter,
+ 0x4e4834fa, 0x22c2, 0x40e2, 0x94, 0x46, 0xf7, 0x7d, 0xd0, 0x5d, 0x24, 0x5e);
+
+// {A1542F93-EB53-4e11-8D34-05C57ABA9207}
+DEFINE_GUID(CLSID_RM9AllocatorPresenter,
+ 0xa1542f93, 0xeb53, 0x4e11, 0x8d, 0x34, 0x5, 0xc5, 0x7a, 0xba, 0x92, 0x7);
+
+// {622A4032-70CE-4040-8231-0F24F2886618}
+DEFINE_GUID(CLSID_QT9AllocatorPresenter,
+ 0x622a4032, 0x70ce, 0x4040, 0x82, 0x31, 0xf, 0x24, 0xf2, 0x88, 0x66, 0x18);
+
+// {B72EBDD4-831D-440f-A656-B48F5486CD82}
+DEFINE_GUID(CLSID_DXRAllocatorPresenter,
+ 0xb72ebdd4, 0x831d, 0x440f, 0xa6, 0x56, 0xb4, 0x8f, 0x54, 0x86, 0xcd, 0x82);
+
+// {C7ED3100-9002-4595-9DCA-B30B30413429}
+DEFINE_GUID(CLSID_madVRAllocatorPresenter,
+ 0xc7ed3100, 0x9002, 0x4595, 0x9d, 0xca, 0xb3, 0xb, 0x30, 0x41, 0x34, 0x29);
+
+DEFINE_GUID(CLSID_EVRAllocatorPresenter,
+ 0x7612b889, 0xe070, 0x4bcc, 0xb8, 0x8, 0x91, 0xcb, 0x79, 0x41, 0x74, 0xab);
+
+extern CCritSec g_ffdshowReceive;
+extern bool queue_ffdshow_support;
+
+extern bool IsVMR9InGraph(IFilterGraph* pFG);
+extern CString GetWindowsErrorMessage(HRESULT _Error, HMODULE _Module);
+extern const wchar_t *GetD3DFormatStr(D3DFORMAT Format);
+
+extern HRESULT CreateAP9(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP);
+extern HRESULT CreateEVR(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP);
+
+// Support ffdshow queuing.
+// This interface is used to check version of Media Player Classic.
+// {A273C7F6-25D4-46b0-B2C8-4F7FADC44E37}
+DEFINE_GUID(IID_IVMRffdshow9,
+ 0xa273c7f6, 0x25d4, 0x46b0, 0xb2, 0xc8, 0x4f, 0x7f, 0xad, 0xc4, 0x4e, 0x37);
+
+MIDL_INTERFACE("A273C7F6-25D4-46b0-B2C8-4F7FADC44E37")
+IVMRffdshow9 :
+public IUnknown
+{
+public:
+ virtual STDMETHODIMP support_ffdshow(void) = 0;
+};
+
diff --git a/src/filters/renderer/VideoRenderers/AllocatorCommon7.cpp b/src/filters/renderer/VideoRenderers/AllocatorCommon7.cpp new file mode 100644 index 000000000..f094311dd --- /dev/null +++ b/src/filters/renderer/VideoRenderers/AllocatorCommon7.cpp @@ -0,0 +1,71 @@ +/*
+ * $Id: DX7AllocatorPresenter.cpp 1813 2010-04-27 02:03:56Z kinddragon $
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include <initguid.h>
+#include "AllocatorCommon7.h"
+#include "../DSUtil/DSUtil.h"
+
+#include "DX7AllocatorPresenter.h"
+#include "VMR7AllocatorPresenter.h"
+#include "RM7AllocatorPresenter.h"
+#include "QT7AllocatorPresenter.h"
+
+
+bool IsVMR7InGraph(IFilterGraph* pFG)
+{
+ BeginEnumFilters(pFG, pEF, pBF)
+ if(CComQIPtr<IVMRWindowlessControl>(pBF)) return(true);
+ EndEnumFilters
+ return(false);
+}
+
+using namespace DSObjects;
+
+//
+
+HRESULT CreateAP7(const CLSID& clsid, HWND hWnd, ISubPicAllocatorPresenter** ppAP)
+{
+ CheckPointer(ppAP, E_POINTER);
+
+ *ppAP = NULL;
+
+ HRESULT hr;
+ if(clsid == CLSID_VMR7AllocatorPresenter && !(*ppAP = DNew CVMR7AllocatorPresenter(hWnd, hr))
+ || clsid == CLSID_RM7AllocatorPresenter && !(*ppAP = DNew CRM7AllocatorPresenter(hWnd, hr))
+ || clsid == CLSID_QT7AllocatorPresenter && !(*ppAP = DNew CQT7AllocatorPresenter(hWnd, hr)))
+ return E_OUTOFMEMORY;
+
+ if(*ppAP == NULL)
+ return E_FAIL;
+
+ (*ppAP)->AddRef();
+
+ if(FAILED(hr))
+ {
+ (*ppAP)->Release();
+ *ppAP = NULL;
+ }
+
+ return hr;
+}
diff --git a/src/filters/renderer/VideoRenderers/AllocatorCommon7.h b/src/filters/renderer/VideoRenderers/AllocatorCommon7.h new file mode 100644 index 000000000..fc18ddd4e --- /dev/null +++ b/src/filters/renderer/VideoRenderers/AllocatorCommon7.h @@ -0,0 +1,43 @@ +/*
+ * $Id: DX7AllocatorPresenter.h 1790 2010-04-18 20:29:12Z tetsuo55 $
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "../SubPic/ISubPic.h"
+
+
+// {495CF191-810D-44c7-92C5-E7D46AE00F44}
+DEFINE_GUID(CLSID_VMR7AllocatorPresenter,
+ 0x495cf191, 0x810d, 0x44c7, 0x92, 0xc5, 0xe7, 0xd4, 0x6a, 0xe0, 0xf, 0x44);
+
+// {97B3462E-1752-4dfb-A038-271060BC7A94}
+DEFINE_GUID(CLSID_RM7AllocatorPresenter,
+ 0x97b3462e, 0x1752, 0x4dfb, 0xa0, 0x38, 0x27, 0x10, 0x60, 0xbc, 0x7a, 0x94);
+
+// {36CC5A71-441C-462a-9D10-48A19485938D}
+DEFINE_GUID(CLSID_QT7AllocatorPresenter,
+ 0x36cc5a71, 0x441c, 0x462a, 0x9d, 0x10, 0x48, 0xa1, 0x94, 0x85, 0x93, 0x8d);
+
+extern HRESULT CreateAP7(const CLSID& clsid, HWND hWnd, ISubPicAllocatorPresenter** ppAP);
+
+extern bool IsVMR7InGraph(IFilterGraph* pFG);
diff --git a/src/filters/renderer/VideoRenderers/D3DFont.cpp b/src/filters/renderer/VideoRenderers/D3DFont.cpp new file mode 100644 index 000000000..5bc1b8414 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/D3DFont.cpp @@ -0,0 +1,915 @@ +/*
+ * $Id$
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include <stdio.h>
+#include <tchar.h>
+#include <d3dx9.h>
+#include "D3DFont.h"
+
+//-----------------------------------------------------------------------------
+// Miscellaneous helper functions
+//-----------------------------------------------------------------------------
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+//-----------------------------------------------------------------------------
+// Custom vertex types for rendering text
+//-----------------------------------------------------------------------------
+#define MAX_NUM_VERTICES 50*6
+
+struct FONT2DVERTEX
+{
+ D3DXVECTOR4 p;
+ DWORD color;
+ FLOAT tu, tv;
+};
+struct FONT3DVERTEX
+{
+ D3DXVECTOR3 p;
+ D3DXVECTOR3 n;
+ FLOAT tu, tv;
+};
+
+#define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
+#define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
+
+
+inline FONT2DVERTEX InitFont2DVertex( const D3DXVECTOR4& p, D3DCOLOR color,
+ FLOAT tu, FLOAT tv )
+{
+ FONT2DVERTEX v;
+ v.p = p;
+ v.color = color;
+ v.tu = tu;
+ v.tv = tv;
+ return v;
+}
+
+inline FONT3DVERTEX InitFont3DVertex( const D3DXVECTOR3& p, const D3DXVECTOR3& n,
+ FLOAT tu, FLOAT tv )
+{
+ FONT3DVERTEX v;
+ v.p = p;
+ v.n = n;
+ v.tu = tu;
+ v.tv = tv;
+ return v;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CD3DFont()
+// Desc: Font class constructor
+//-----------------------------------------------------------------------------
+CD3DFont::CD3DFont( const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags )
+{
+ _tcsncpy( m_strFontName, strFontName, sizeof(m_strFontName) / sizeof(TCHAR) );
+ m_strFontName[sizeof(m_strFontName) / sizeof(TCHAR) - 1] = _T('\0');
+ m_dwFontHeight = dwHeight;
+ m_dwFontFlags = dwFlags;
+ m_dwSpacing = 0;
+
+ m_pd3dDevice = NULL;
+ m_pTexture = NULL;
+ m_pVB = NULL;
+
+ m_pStateBlockSaved = NULL;
+ m_pStateBlockDrawText = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ~CD3DFont()
+// Desc: Font class destructor
+//-----------------------------------------------------------------------------
+CD3DFont::~CD3DFont()
+{
+ InvalidateDeviceObjects();
+ DeleteDeviceObjects();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateGDIFont
+// Desc: Create a font based on the current state of related member variables
+// and return the handle (or null on error)
+//-----------------------------------------------------------------------------
+HRESULT CD3DFont::CreateGDIFont( HDC hDC, HFONT* pFont )
+{
+ // Create a font. By specifying ANTIALIASED_QUALITY, we might get an
+ // antialiased font, but this is not guaranteed.
+ INT nHeight = -MulDiv( m_dwFontHeight,
+ (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale),
+ 72 );
+ DWORD dwBold = (m_dwFontFlags & D3DFONT_BOLD) ? FW_BOLD : FW_NORMAL;
+ DWORD dwItalic = (m_dwFontFlags & D3DFONT_ITALIC) ? TRUE : FALSE;
+ *pFont = CreateFont( nHeight, 0, 0, 0, dwBold, dwItalic,
+ FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
+ CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
+ VARIABLE_PITCH, m_strFontName );
+
+ if( *pFont == NULL )
+ return E_FAIL;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: PaintAlphabet
+// Desc: Paint the printable characters for the given GDI font onto the
+// provided device context. If the bMeasureOnly flag is set, no drawing
+// will occur.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFont::PaintAlphabet( HDC hDC, BOOL bMeasureOnly )
+{
+ SIZE size;
+ TCHAR str[2] = _T("x"); // One-character, null-terminated string
+
+ // Calculate the spacing between characters based on line height
+ if( 0 == GetTextExtentPoint32( hDC, str, 1, &size ) )
+ return E_FAIL;
+ m_dwSpacing = (DWORD) ceil(size.cy * 0.3f);
+
+ // Set the starting point for the drawing
+ DWORD x = m_dwSpacing;
+ DWORD y = 0;
+
+ // For each character, draw text on the DC and advance the current position
+ for( char c = 32; c < 127; c++ )
+ {
+ str[0] = c;
+ if( 0 == GetTextExtentPoint32( hDC, str, 1, &size ) )
+ return E_FAIL;
+
+ if( (DWORD)(x + size.cx + m_dwSpacing) > m_dwTexWidth )
+ {
+ x = m_dwSpacing;
+ y += size.cy + 1;
+ }
+
+ // Check to see if there's room to write the character here
+ if( y + size.cy > m_dwTexHeight )
+ return D3DERR_MOREDATA;
+
+ if( !bMeasureOnly )
+ {
+ // Perform the actual drawing
+ if( 0 == ExtTextOut( hDC, x+0, y+0, ETO_OPAQUE, NULL, str, 1, NULL ) )
+ return E_FAIL;
+
+ m_fTexCoords[c-32][0] = ((FLOAT)(x + 0 - m_dwSpacing))/m_dwTexWidth;
+ m_fTexCoords[c-32][1] = ((FLOAT)(y + 0 + 0 ))/m_dwTexHeight;
+ m_fTexCoords[c-32][2] = ((FLOAT)(x + size.cx + m_dwSpacing))/m_dwTexWidth;
+ m_fTexCoords[c-32][3] = ((FLOAT)(y + size.cy + 0 ))/m_dwTexHeight;
+ }
+
+ x += size.cx + (2 * m_dwSpacing);
+ }
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: InitDeviceObjects()
+// Desc: Initializes device-dependent objects, including the vertex buffer used
+// for rendering text and the texture map which stores the font image.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFont::InitDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice )
+{
+ HRESULT hr = S_OK;
+ HFONT hFont = NULL;
+ HFONT hFontOld = NULL;
+ HDC hDC = NULL;
+ HBITMAP hbmBitmap = NULL;
+ HGDIOBJ hbmOld = NULL;
+
+ // Keep a local copy of the device
+ m_pd3dDevice = pd3dDevice;
+
+ // Assume we will draw fonts into texture without scaling unless the
+ // required texture size is found to be larger than the device max
+ m_fTextScale = 1.0f;
+
+ hDC = CreateCompatibleDC( NULL );
+ SetMapMode( hDC, MM_TEXT );
+
+ hr = CreateGDIFont( hDC, &hFont );
+ if( FAILED(hr) )
+ goto LCleanReturn;
+
+ hFontOld = (HFONT) SelectObject( hDC, hFont );
+
+ // Calculate the dimensions for the smallest power-of-two texture which
+ // can hold all the printable characters
+ m_dwTexWidth = m_dwTexHeight = 128;
+ while( D3DERR_MOREDATA == ( hr = PaintAlphabet( hDC, true ) ) )
+ {
+ m_dwTexWidth *= 2;
+ m_dwTexHeight *= 2;
+ }
+
+ if( FAILED(hr) )
+ goto LCleanReturn;
+
+ // If requested texture is too big, use a smaller texture and smaller font,
+ // and scale up when rendering.
+ D3DCAPS9 d3dCaps;
+ m_pd3dDevice->GetDeviceCaps( &d3dCaps );
+
+ if( m_dwTexWidth > d3dCaps.MaxTextureWidth )
+ {
+ m_fTextScale = (FLOAT)d3dCaps.MaxTextureWidth / (FLOAT)m_dwTexWidth;
+ m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth;
+
+ bool bFirstRun = true; // Flag clear after first run
+
+ do
+ {
+ // If we've already tried fitting the new text, the scale is still
+ // too large. Reduce and try again.
+ if( !bFirstRun)
+ m_fTextScale *= 0.9f;
+
+ // The font has to be scaled to fit on the maximum texture size; our
+ // current font is too big and needs to be recreated to scale.
+ DeleteObject( SelectObject( hDC, hFontOld ) );
+
+ hr = CreateGDIFont( hDC, &hFont );
+ if( FAILED(hr) )
+ goto LCleanReturn;
+
+ hFontOld = (HFONT) SelectObject( hDC, hFont );
+
+ bFirstRun = false;
+ }
+ while( D3DERR_MOREDATA == ( hr = PaintAlphabet( hDC, true ) ) );
+ }
+
+
+ // Create a new texture for the font
+ hr = m_pd3dDevice->CreateTexture( m_dwTexWidth, m_dwTexHeight, 1,
+ 0, D3DFMT_A4R4G4B4,
+ D3DPOOL_MANAGED, &m_pTexture, NULL );
+ if( FAILED(hr) )
+ goto LCleanReturn;
+
+ // Prepare to create a bitmap
+ DWORD* pBitmapBits;
+ BITMAPINFO bmi;
+ ZeroMemory( &bmi.bmiHeader, sizeof(BITMAPINFOHEADER) );
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = (int)m_dwTexWidth;
+ bmi.bmiHeader.biHeight = -(int)m_dwTexHeight;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biBitCount = 32;
+
+ // Create a bitmap for the font
+ hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
+ (void**)&pBitmapBits, NULL, 0 );
+
+ hbmOld = SelectObject( hDC, hbmBitmap );
+
+ // Set text properties
+ SetTextColor( hDC, RGB(255,255,255) );
+ SetBkColor( hDC, 0x00000000 );
+ SetTextAlign( hDC, TA_TOP );
+
+ // Paint the alphabet onto the selected bitmap
+ hr = PaintAlphabet( hDC, false );
+ if( FAILED(hr) )
+ goto LCleanReturn;
+
+ // Lock the surface and write the alpha values for the set pixels
+ D3DLOCKED_RECT d3dlr;
+ m_pTexture->LockRect( 0, &d3dlr, 0, 0 );
+ BYTE* pDstRow;
+ pDstRow = (BYTE*)d3dlr.pBits;
+ WORD* pDst16;
+ BYTE bAlpha; // 4-bit measure of pixel intensity
+ DWORD x, y;
+
+ for( y=0; y < m_dwTexHeight; y++ )
+ {
+ pDst16 = (WORD*)pDstRow;
+ for( x=0; x < m_dwTexWidth; x++ )
+ {
+ bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth*y + x] & 0xff) >> 4);
+ if (bAlpha > 0)
+ {
+ *pDst16++ = (WORD) ((bAlpha << 12) | 0x0fff);
+ }
+ else
+ {
+ *pDst16++ = 0x0000;
+ }
+ }
+ pDstRow += d3dlr.Pitch;
+ }
+
+ hr = S_OK;
+
+ // Done updating texture, so clean up used objects
+LCleanReturn:
+ if( m_pTexture )
+ m_pTexture->UnlockRect(0);
+
+ SelectObject( hDC, hbmOld );
+ SelectObject( hDC, hFontOld );
+ DeleteObject( hbmBitmap );
+ DeleteObject( hFont );
+ DeleteDC( hDC );
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: RestoreDeviceObjects()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CD3DFont::RestoreDeviceObjects()
+{
+ HRESULT hr;
+
+ // Create vertex buffer for the letters
+ int vertexSize = max( sizeof(FONT2DVERTEX), sizeof(FONT3DVERTEX ) );
+ if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( MAX_NUM_VERTICES * vertexSize,
+ D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0,
+ D3DPOOL_DEFAULT, &m_pVB, NULL ) ) )
+ {
+ return hr;
+ }
+
+ bool bSupportsAlphaBlend = true;
+ LPDIRECT3D9 pd3d9 = NULL;
+ if( SUCCEEDED( m_pd3dDevice->GetDirect3D( &pd3d9 ) ) )
+ {
+ D3DCAPS9 Caps;
+ D3DDISPLAYMODE Mode;
+ LPDIRECT3DSURFACE9 pSurf = NULL;
+ D3DSURFACE_DESC Desc;
+ m_pd3dDevice->GetDeviceCaps( &Caps );
+ m_pd3dDevice->GetDisplayMode( 0, &Mode );
+ if( SUCCEEDED( m_pd3dDevice->GetRenderTarget( 0, &pSurf ) ) )
+ {
+ pSurf->GetDesc( &Desc );
+ if( FAILED( pd3d9->CheckDeviceFormat( Caps.AdapterOrdinal, Caps.DeviceType, Mode.Format,
+ D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_SURFACE,
+ Desc.Format ) ) )
+ {
+ bSupportsAlphaBlend = false;
+ }
+ SAFE_RELEASE( pSurf );
+ }
+ SAFE_RELEASE( pd3d9 );
+ }
+
+ // Create the state blocks for rendering text
+ for( UINT which=0; which<2; which++ )
+ {
+ m_pd3dDevice->BeginStateBlock();
+ m_pd3dDevice->SetTexture( 0, m_pTexture );
+
+ if ( D3DFONT_ZENABLE & m_dwFontFlags )
+ m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
+ else
+ m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
+
+ if( bSupportsAlphaBlend )
+ {
+ m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
+ m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
+ m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
+ }
+ else
+ {
+ m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
+ }
+ m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
+ m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF, 0x08 );
+ m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
+ m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
+ m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
+ m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE, FALSE );
+ m_pd3dDevice->SetRenderState( D3DRS_CLIPPING, TRUE );
+ m_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE, FALSE );
+ m_pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND, D3DVBF_DISABLE );
+ m_pd3dDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
+ m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );
+ m_pd3dDevice->SetRenderState( D3DRS_COLORWRITEENABLE,
+ D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN |
+ D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
+ m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
+ m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
+ m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
+ m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
+ m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
+ m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
+ m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
+ m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
+ m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
+ m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
+ m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
+ m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
+ m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE );
+
+ if( which==0 )
+ m_pd3dDevice->EndStateBlock( &m_pStateBlockSaved );
+ else
+ m_pd3dDevice->EndStateBlock( &m_pStateBlockDrawText );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: InvalidateDeviceObjects()
+// Desc: Destroys all device-dependent objects
+//-----------------------------------------------------------------------------
+HRESULT CD3DFont::InvalidateDeviceObjects()
+{
+ SAFE_RELEASE( m_pVB );
+ SAFE_RELEASE( m_pStateBlockSaved );
+ SAFE_RELEASE( m_pStateBlockDrawText );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DeleteDeviceObjects()
+// Desc: Destroys all device-dependent objects
+//-----------------------------------------------------------------------------
+HRESULT CD3DFont::DeleteDeviceObjects()
+{
+ SAFE_RELEASE( m_pTexture );
+ m_pd3dDevice = NULL;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: GetTextExtent()
+// Desc: Get the dimensions of a text string
+//-----------------------------------------------------------------------------
+HRESULT CD3DFont::GetTextExtent( const TCHAR* strText, SIZE* pSize )
+{
+ if( NULL==strText || NULL==pSize )
+ return E_FAIL;
+
+ FLOAT fRowWidth = 0.0f;
+ FLOAT fRowHeight = (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
+ FLOAT fWidth = 0.0f;
+ FLOAT fHeight = fRowHeight;
+
+ while( *strText )
+ {
+ TCHAR c = *strText++;
+
+ if( c == _T('\n') )
+ {
+ fRowWidth = 0.0f;
+ fHeight += fRowHeight;
+ }
+
+ if( (c-32) < 0 || (c-32) >= 128-32 )
+ continue;
+
+ FLOAT tx1 = m_fTexCoords[c-32][0];
+ FLOAT tx2 = m_fTexCoords[c-32][2];
+
+ fRowWidth += (tx2-tx1)*m_dwTexWidth - 2*m_dwSpacing;
+
+ if( fRowWidth > fWidth )
+ fWidth = fRowWidth;
+ }
+
+ pSize->cx = (int)fWidth;
+ pSize->cy = (int)fHeight;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DrawTextScaled()
+// Desc: Draws scaled 2D text. Note that x and y are in viewport coordinates
+// (ranging from -1 to +1). fXScale and fYScale are the size fraction
+// relative to the entire viewport. For example, a fXScale of 0.25 is
+// 1/8th of the screen width. This allows you to output text at a fixed
+// fraction of the viewport, even if the screen or window size changes.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFont::DrawTextScaled( FLOAT x, FLOAT y, FLOAT z,
+ FLOAT fXScale, FLOAT fYScale, DWORD dwColor,
+ const TCHAR* strText, DWORD dwFlags )
+{
+ if( m_pd3dDevice == NULL )
+ return E_FAIL;
+
+ // Set up renderstate
+ m_pStateBlockSaved->Capture();
+ m_pStateBlockDrawText->Apply();
+ m_pd3dDevice->SetFVF( D3DFVF_FONT2DVERTEX );
+ m_pd3dDevice->SetPixelShader( NULL );
+ m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT2DVERTEX) );
+
+ // Set filter states
+ if( dwFlags & D3DFONT_FILTERED )
+ {
+ m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
+ m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
+ }
+
+ D3DVIEWPORT9 vp;
+ m_pd3dDevice->GetViewport( &vp );
+ FLOAT fLineHeight = ( m_fTexCoords[0][3] - m_fTexCoords[0][1] ) * m_dwTexHeight;
+
+ // Center the text block in the viewport
+ if( dwFlags & D3DFONT_CENTERED_X )
+ {
+ const TCHAR* strTextTmp = strText;
+ float xFinal = 0.0f;
+
+ while( *strTextTmp )
+ {
+ TCHAR c = *strTextTmp++;
+
+ if( c == _T('\n') )
+ break; // Isn't supported.
+ if( (c-32) < 0 || (c-32) >= 128-32 )
+ continue;
+
+ FLOAT tx1 = m_fTexCoords[c-32][0];
+ FLOAT tx2 = m_fTexCoords[c-32][2];
+
+ FLOAT w = (tx2-tx1)*m_dwTexWidth;
+
+ w *= (fXScale*vp.Height)/fLineHeight;
+
+ xFinal += w - (2 * m_dwSpacing) * (fXScale*vp.Height)/fLineHeight;
+ }
+
+ x = -xFinal/vp.Width;
+ }
+ if( dwFlags & D3DFONT_CENTERED_Y )
+ {
+ y = -fLineHeight/vp.Height;
+ }
+
+ FLOAT sx = (x+1.0f)*vp.Width/2;
+ FLOAT sy = (y+1.0f)*vp.Height/2;
+ FLOAT sz = z;
+ FLOAT rhw = 1.0f;
+
+ // Adjust for character spacing
+ sx -= m_dwSpacing * (fXScale*vp.Height)/fLineHeight;
+ FLOAT fStartX = sx;
+
+ // Fill vertex buffer
+ FONT2DVERTEX* pVertices;
+ DWORD dwNumTriangles = 0L;
+ m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
+
+ while( *strText )
+ {
+ TCHAR c = *strText++;
+
+ if( c == _T('\n') )
+ {
+ sx = fStartX;
+ sy += fYScale*vp.Height;
+ }
+
+ if( (c-32) < 0 || (c-32) >= 128-32 )
+ continue;
+
+ FLOAT tx1 = m_fTexCoords[c-32][0];
+ FLOAT ty1 = m_fTexCoords[c-32][1];
+ FLOAT tx2 = m_fTexCoords[c-32][2];
+ FLOAT ty2 = m_fTexCoords[c-32][3];
+
+ FLOAT w = (tx2-tx1)*m_dwTexWidth;
+ FLOAT h = (ty2-ty1)*m_dwTexHeight;
+
+ w *= (fXScale*vp.Height)/fLineHeight;
+ h *= (fYScale*vp.Height)/fLineHeight;
+
+ if( c != _T(' ') )
+ {
+ *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx1, ty2 );
+ *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
+ *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
+ *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx2, ty1 );
+ *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,sz,rhw), dwColor, tx2, ty2 );
+ *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,sz,rhw), dwColor, tx1, ty1 );
+ dwNumTriangles += 2;
+
+ if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
+ {
+ // Unlock, render, and relock the vertex buffer
+ m_pVB->Unlock();
+ m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
+ m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
+ dwNumTriangles = 0L;
+ }
+ }
+
+ sx += w - (2 * m_dwSpacing) * (fXScale*vp.Height)/fLineHeight;
+ }
+
+ // Unlock and render the vertex buffer
+ m_pVB->Unlock();
+ if( dwNumTriangles > 0 )
+ m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
+
+ // Restore the modified renderstates
+ m_pStateBlockSaved->Apply();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DrawText()
+// Desc: Draws 2D text. Note that sx and sy are in pixels
+//-----------------------------------------------------------------------------
+HRESULT CD3DFont::DrawText( FLOAT sx, FLOAT sy, DWORD dwColor,
+ const TCHAR* strText, DWORD dwFlags )
+{
+ if( m_pd3dDevice == NULL )
+ return E_FAIL;
+
+ // Setup renderstate
+ m_pStateBlockSaved->Capture();
+ m_pStateBlockDrawText->Apply();
+ m_pd3dDevice->SetFVF( D3DFVF_FONT2DVERTEX );
+ m_pd3dDevice->SetPixelShader( NULL );
+ m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT2DVERTEX) );
+
+ // Set filter states
+ if( dwFlags & D3DFONT_FILTERED )
+ {
+ m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
+ m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
+ }
+
+ // Center the text block in the viewport
+ if( dwFlags & D3DFONT_CENTERED_X )
+ {
+ D3DVIEWPORT9 vp;
+ m_pd3dDevice->GetViewport( &vp );
+ const TCHAR* strTextTmp = strText;
+ float xFinal = 0.0f;
+
+ while( *strTextTmp )
+ {
+ TCHAR c = *strTextTmp++;
+
+ if( c == _T('\n') )
+ break; // Isn't supported.
+ if( (c-32) < 0 || (c-32) >= 128-32 )
+ continue;
+
+ FLOAT tx1 = m_fTexCoords[c-32][0];
+ FLOAT tx2 = m_fTexCoords[c-32][2];
+
+ FLOAT w = (tx2-tx1) * m_dwTexWidth / m_fTextScale;
+
+ xFinal += w - (2 * m_dwSpacing);
+ }
+
+ sx = (vp.Width-xFinal)/2.0f;
+ }
+ if( dwFlags & D3DFONT_CENTERED_Y )
+ {
+ D3DVIEWPORT9 vp;
+ m_pd3dDevice->GetViewport( &vp );
+ float fLineHeight = ((m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight);
+ sy = (vp.Height-fLineHeight)/2;
+ }
+
+ // Adjust for character spacing
+ sx -= m_dwSpacing;
+ FLOAT fStartX = sx;
+
+ // Fill vertex buffer
+ FONT2DVERTEX* pVertices = NULL;
+ DWORD dwNumTriangles = 0;
+ m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
+
+ while( *strText )
+ {
+ TCHAR c = *strText++;
+
+ if( c == _T('\n') )
+ {
+ sx = fStartX;
+ sy += (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
+ }
+
+ if( (c-32) < 0 || (c-32) >= 128-32 )
+ continue;
+
+ FLOAT tx1 = m_fTexCoords[c-32][0];
+ FLOAT ty1 = m_fTexCoords[c-32][1];
+ FLOAT tx2 = m_fTexCoords[c-32][2];
+ FLOAT ty2 = m_fTexCoords[c-32][3];
+
+ FLOAT w = (tx2-tx1) * m_dwTexWidth / m_fTextScale;
+ FLOAT h = (ty2-ty1) * m_dwTexHeight / m_fTextScale;
+
+ if( c != _T(' ') )
+ {
+ *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx1, ty2 );
+ *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
+ *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
+ *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx2, ty1 );
+ *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.9f,1.0f), dwColor, tx2, ty2 );
+ *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.9f,1.0f), dwColor, tx1, ty1 );
+ dwNumTriangles += 2;
+
+ if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
+ {
+ // Unlock, render, and relock the vertex buffer
+ m_pVB->Unlock();
+ m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
+ pVertices = NULL;
+ m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
+ dwNumTriangles = 0L;
+ }
+ }
+
+ sx += w - (2 * m_dwSpacing);
+ }
+
+ // Unlock and render the vertex buffer
+ m_pVB->Unlock();
+ if( dwNumTriangles > 0 )
+ m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
+
+ // Restore the modified renderstates
+ m_pStateBlockSaved->Apply();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: Render3DText()
+// Desc: Renders 3D text
+//-----------------------------------------------------------------------------
+HRESULT CD3DFont::Render3DText( const TCHAR* strText, DWORD dwFlags )
+{
+ if( m_pd3dDevice == NULL )
+ return E_FAIL;
+
+ // Setup renderstate
+ m_pStateBlockSaved->Capture();
+ m_pStateBlockDrawText->Apply();
+ m_pd3dDevice->SetFVF( D3DFVF_FONT3DVERTEX );
+ m_pd3dDevice->SetPixelShader( NULL );
+ m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT3DVERTEX) );
+
+ // Set filter states
+ if( dwFlags & D3DFONT_FILTERED )
+ {
+ m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
+ m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
+ }
+
+ // Position for each text element
+ FLOAT x = 0.0f;
+ FLOAT y = 0.0f;
+
+ // Center the text block at the origin (not the viewport)
+ if( dwFlags & D3DFONT_CENTERED_X )
+ {
+ SIZE sz;
+ GetTextExtent( strText, &sz );
+ x = -(((FLOAT)sz.cx)/10.0f)/2.0f;
+ }
+ if( dwFlags & D3DFONT_CENTERED_Y )
+ {
+ SIZE sz;
+ GetTextExtent( strText, &sz );
+ y = -(((FLOAT)sz.cy)/10.0f)/2.0f;
+ }
+
+ // Turn off culling for two-sided text
+ if( dwFlags & D3DFONT_TWOSIDED )
+ m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
+
+ // Adjust for character spacing
+ x -= m_dwSpacing / 10.0f;
+ FLOAT fStartX = x;
+ TCHAR c;
+
+ // Fill vertex buffer
+ FONT3DVERTEX* pVertices;
+ DWORD dwNumTriangles = 0L;
+ m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
+
+ while( (c = *strText++) != 0 )
+ {
+ if( c == '\n' )
+ {
+ x = fStartX;
+ y -= (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight/10.0f;
+ }
+
+ if( (c-32) < 0 || (c-32) >= 128-32 )
+ continue;
+
+ FLOAT tx1 = m_fTexCoords[c-32][0];
+ FLOAT ty1 = m_fTexCoords[c-32][1];
+ FLOAT tx2 = m_fTexCoords[c-32][2];
+ FLOAT ty2 = m_fTexCoords[c-32][3];
+
+ FLOAT w = (tx2-tx1) * m_dwTexWidth / ( 10.0f * m_fTextScale );
+ FLOAT h = (ty2-ty1) * m_dwTexHeight / ( 10.0f * m_fTextScale );
+
+ if( c != _T(' ') )
+ {
+ *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+0,0), D3DXVECTOR3(0,0,-1), tx1, ty2 );
+ *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
+ *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
+ *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+h,0), D3DXVECTOR3(0,0,-1), tx2, ty1 );
+ *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+w,y+0,0), D3DXVECTOR3(0,0,-1), tx2, ty2 );
+ *pVertices++ = InitFont3DVertex( D3DXVECTOR3(x+0,y+h,0), D3DXVECTOR3(0,0,-1), tx1, ty1 );
+ dwNumTriangles += 2;
+
+ if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )
+ {
+ // Unlock, render, and relock the vertex buffer
+ m_pVB->Unlock();
+ m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
+ m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );
+ dwNumTriangles = 0L;
+ }
+ }
+
+ x += w - (2 * m_dwSpacing) / 10.0f;
+ }
+
+ // Unlock and render the vertex buffer
+ m_pVB->Unlock();
+ if( dwNumTriangles > 0 )
+ m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );
+
+ // Restore the modified renderstates
+ m_pStateBlockSaved->Apply();
+
+ return S_OK;
+}
diff --git a/src/filters/renderer/VideoRenderers/D3DFont.h b/src/filters/renderer/VideoRenderers/D3DFont.h new file mode 100644 index 000000000..34d603a80 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/D3DFont.h @@ -0,0 +1,81 @@ +/*
+ * $Id$
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+// Font creation flags
+#define D3DFONT_BOLD 0x0001
+#define D3DFONT_ITALIC 0x0002
+#define D3DFONT_ZENABLE 0x0004
+
+// Font rendering flags
+#define D3DFONT_CENTERED_X 0x0001
+#define D3DFONT_CENTERED_Y 0x0002
+#define D3DFONT_TWOSIDED 0x0004
+#define D3DFONT_FILTERED 0x0008
+
+
+class CD3DFont
+{
+ TCHAR m_strFontName[80]; // Font properties
+ DWORD m_dwFontHeight;
+ DWORD m_dwFontFlags;
+
+ LPDIRECT3DDEVICE9 m_pd3dDevice; // A D3DDevice used for rendering
+ LPDIRECT3DTEXTURE9 m_pTexture; // The d3d texture for this font
+ LPDIRECT3DVERTEXBUFFER9 m_pVB; // VertexBuffer for rendering text
+ DWORD m_dwTexWidth; // Texture dimensions
+ DWORD m_dwTexHeight;
+ FLOAT m_fTextScale;
+ FLOAT m_fTexCoords[128-32][4];
+ DWORD m_dwSpacing; // Character pixel spacing per side
+
+ // Stateblocks for setting and restoring render states
+ LPDIRECT3DSTATEBLOCK9 m_pStateBlockSaved;
+ LPDIRECT3DSTATEBLOCK9 m_pStateBlockDrawText;
+
+ HRESULT CreateGDIFont( HDC hDC, HFONT* pFont );
+ HRESULT PaintAlphabet( HDC hDC, BOOL bMeasureOnly=FALSE );
+
+public:
+ // 2D and 3D text drawing functions
+ HRESULT DrawText( FLOAT x, FLOAT y, DWORD dwColor,
+ const TCHAR* strText, DWORD dwFlags=0L );
+ HRESULT DrawTextScaled( FLOAT x, FLOAT y, FLOAT z,
+ FLOAT fXScale, FLOAT fYScale, DWORD dwColor,
+ const TCHAR* strText, DWORD dwFlags=0L );
+ HRESULT Render3DText( const TCHAR* strText, DWORD dwFlags=0L );
+
+ // Function to get extent of text
+ HRESULT GetTextExtent( const TCHAR* strText, SIZE* pSize );
+
+ // Initializing and destroying device-dependent objects
+ HRESULT InitDeviceObjects( IDirect3DDevice9* pd3dDevice );
+ HRESULT RestoreDeviceObjects();
+ HRESULT InvalidateDeviceObjects();
+ HRESULT DeleteDeviceObjects();
+
+ // Constructor / destructor
+ CD3DFont( const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags=0L );
+ ~CD3DFont();
+};
diff --git a/src/filters/renderer/VideoRenderers/DX7AllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/DX7AllocatorPresenter.cpp new file mode 100644 index 000000000..e15e9cf2d --- /dev/null +++ b/src/filters/renderer/VideoRenderers/DX7AllocatorPresenter.cpp @@ -0,0 +1,488 @@ +/*
+ * $Id$
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include "RenderersSettings.h"
+
+#include "DX7AllocatorPresenter.h"
+#include "../SubPic/DX7SubPic.h"
+
+using namespace DSObjects;
+
+//
+
+static HRESULT TextureBlt(IDirect3DDevice7* pD3DDev, IDirectDrawSurface7* pTexture, Vector dst[4], CRect src)
+{
+ if(!pTexture)
+ return E_POINTER;
+
+ ASSERT(pD3DDev);
+ HRESULT hr;
+
+ do
+ {
+ DDSURFACEDESC2 ddsd;
+ INITDDSTRUCT(ddsd);
+ if(FAILED(hr = pTexture->GetSurfaceDesc(&ddsd)))
+ break;
+
+ float w = (float)ddsd.dwWidth;
+ float h = (float)ddsd.dwHeight;
+
+ struct
+ {
+ float x, y, z, rhw;
+ float tu, tv;
+ }
+ pVertices[] =
+ {
+ {(float)dst[0].x, (float)dst[0].y, (float)dst[0].z, 1.0f/(float)dst[0].z, (float)src.left / w, (float)src.top / h},
+ {(float)dst[1].x, (float)dst[1].y, (float)dst[1].z, 1.0f/(float)dst[1].z, (float)src.right / w, (float)src.top / h},
+ {(float)dst[2].x, (float)dst[2].y, (float)dst[2].z, 1.0f/(float)dst[2].z, (float)src.left / w, (float)src.bottom / h},
+ {(float)dst[3].x, (float)dst[3].y, (float)dst[3].z, 1.0f/(float)dst[3].z, (float)src.right / w, (float)src.bottom / h},
+ };
+
+ for(int i = 0; i < countof(pVertices); i++)
+ {
+ pVertices[i].x -= 0.5;
+ pVertices[i].y -= 0.5;
+ }
+
+ hr = pD3DDev->SetTexture(0, pTexture);
+
+ pD3DDev->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
+ pD3DDev->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE);
+ pD3DDev->SetRenderState(D3DRENDERSTATE_BLENDENABLE, FALSE);
+ pD3DDev->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
+
+ pD3DDev->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR);
+ pD3DDev->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_LINEAR);
+ pD3DDev->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTFP_LINEAR);
+
+ pD3DDev->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
+
+ //
+
+ if(FAILED(hr = pD3DDev->BeginScene()))
+ break;
+
+ hr = pD3DDev->DrawPrimitive(D3DPT_TRIANGLESTRIP,
+ D3DFVF_XYZRHW | D3DFVF_TEX1,
+ pVertices, 4, D3DDP_WAIT);
+ pD3DDev->EndScene();
+
+ //
+
+ pD3DDev->SetTexture(0, NULL);
+
+ return S_OK;
+ }
+ while(0);
+
+ return E_FAIL;
+}
+
+//
+// CDX7AllocatorPresenter
+//
+
+CDX7AllocatorPresenter::CDX7AllocatorPresenter(HWND hWnd, HRESULT& hr)
+ : ISubPicAllocatorPresenterImpl(hWnd, hr, NULL)
+ , m_ScreenSize(0, 0)
+{
+ if(FAILED(hr)) return;
+
+ if(FAILED(hr = DirectDrawCreateEx(NULL, (VOID**)&m_pDD, IID_IDirectDraw7, NULL))
+ || FAILED(hr = m_pDD->SetCooperativeLevel(AfxGetMainWnd()->GetSafeHwnd(), DDSCL_NORMAL)))
+ return;
+
+ if(!(m_pD3D = m_pDD))
+ {
+ hr = E_NOINTERFACE;
+ return;
+ }
+
+ hr = CreateDevice();
+ if (FAILED(hr))
+ {
+ TRACE("CreateDevice failed: 0x%08x\n", (LONG)hr);
+ }
+}
+
+HRESULT CDX7AllocatorPresenter::CreateDevice()
+{
+ m_pD3DDev = NULL;
+
+ m_pPrimary = NULL;
+ m_pBackBuffer = NULL;
+
+ DDSURFACEDESC2 ddsd;
+ INITDDSTRUCT(ddsd);
+ if(FAILED(m_pDD->GetDisplayMode(&ddsd)) ||
+ ddsd.ddpfPixelFormat.dwRGBBitCount <= 8)
+ return DDERR_INVALIDMODE;
+
+ m_ScreenSize.SetSize(ddsd.dwWidth, ddsd.dwHeight);
+
+ HRESULT hr;
+
+ // m_pPrimary
+
+ INITDDSTRUCT(ddsd);
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+ if(FAILED(hr = m_pDD->CreateSurface(&ddsd, &m_pPrimary, NULL)))
+ return hr;
+
+ CComPtr<IDirectDrawClipper> pcClipper;
+ if(FAILED(hr = m_pDD->CreateClipper(0, &pcClipper, NULL)))
+ return hr;
+ pcClipper->SetHWnd(0, m_hWnd);
+ m_pPrimary->SetClipper(pcClipper);
+
+ // m_pBackBuffer
+
+ INITDDSTRUCT(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = /*DDSCAPS_OFFSCREENPLAIN |*/ DDSCAPS_VIDEOMEMORY | DDSCAPS_3DDEVICE;
+ ddsd.dwWidth = m_ScreenSize.cx;
+ ddsd.dwHeight = m_ScreenSize.cy;
+ if(FAILED(hr = m_pDD->CreateSurface(&ddsd, &m_pBackBuffer, NULL)))
+ return hr;
+
+ pcClipper = NULL;
+ if(FAILED(hr = m_pDD->CreateClipper(0, &pcClipper, NULL)))
+ return hr;
+ BYTE rgnDataBuffer[1024];
+ HRGN hrgn = CreateRectRgn(0, 0, ddsd.dwWidth, ddsd.dwHeight);
+ GetRegionData(hrgn, sizeof(rgnDataBuffer), (RGNDATA*)rgnDataBuffer);
+ DeleteObject(hrgn);
+ pcClipper->SetClipList((RGNDATA*)rgnDataBuffer, 0);
+ m_pBackBuffer->SetClipper(pcClipper);
+
+ // m_pD3DDev
+
+ if(FAILED(hr = m_pD3D->CreateDevice(IID_IDirect3DHALDevice, m_pBackBuffer, &m_pD3DDev))) // this seems to fail if the desktop size is too large (width or height >2048)
+ return hr;
+
+ //
+
+ CComPtr<ISubPicProvider> pSubPicProvider;
+ if(m_pSubPicQueue) m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider);
+
+ CSize size;
+ switch(GetRenderersSettings().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;
+ case 6:
+ size.SetSize(2560, 1600);
+ break;
+ case 7:
+ size.SetSize(1920, 1080);
+ break;
+ case 8:
+ size.SetSize(1320, 900);
+ break;
+ case 9:
+ size.SetSize(1280, 720);
+ break;
+ }
+
+ if(m_pAllocator)
+ {
+ m_pAllocator->ChangeDevice(m_pD3DDev);
+ }
+ else
+ {
+ m_pAllocator = DNew CDX7SubPicAllocator(m_pD3DDev, size, GetRenderersSettings().fSPCPow2Tex);
+ if(!m_pAllocator || FAILED(hr))
+ return E_FAIL;
+ }
+
+ hr = S_OK;
+ m_pSubPicQueue = GetRenderersSettings().nSPCSize > 0
+ ? (ISubPicQueue*)DNew CSubPicQueue(GetRenderersSettings().nSPCSize, !GetRenderersSettings().fSPCAllowAnimationWhenBuffering, m_pAllocator, &hr)
+ : (ISubPicQueue*)DNew CSubPicQueueNoThread(m_pAllocator, &hr);
+ if(!m_pSubPicQueue || FAILED(hr))
+ return E_FAIL;
+
+ if(pSubPicProvider) m_pSubPicQueue->SetSubPicProvider(pSubPicProvider);
+
+ return S_OK;
+}
+
+HRESULT CDX7AllocatorPresenter::AllocSurfaces()
+{
+ CAutoLock cAutoLock(this);
+
+ CRenderersSettings& s = GetRenderersSettings();
+
+ m_pVideoTexture = NULL;
+ m_pVideoSurface = NULL;
+
+ DDSURFACEDESC2 ddsd;
+ INITDDSTRUCT(ddsd);
+ ddsd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
+ ddsd.dwWidth = m_NativeVideoSize.cx;
+ ddsd.dwHeight = m_NativeVideoSize.cy;
+ ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
+ ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
+ ddsd.ddpfPixelFormat.dwRGBBitCount = 32;
+ ddsd.ddpfPixelFormat.dwRBitMask = 0x00FF0000;
+ ddsd.ddpfPixelFormat.dwGBitMask = 0x0000FF00;
+ ddsd.ddpfPixelFormat.dwBBitMask = 0x000000FF;
+
+ if(s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D || s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D)
+ {
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_TEXTURE;
+// ddsd.ddpfPixelFormat.dwFlags |= DDPF_ALPHAPIXELS;
+// ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0xFF000000;
+ }
+
+ HRESULT hr = m_pDD->CreateSurface(&ddsd, &m_pVideoSurface, NULL);
+ if(FAILED(hr))
+ {
+ // FIXME: eh, dx9 has no problem creating a 32bpp surface under a 16bpp desktop, but dx7 fails here (textures are ok)
+ DDSURFACEDESC2 ddsd2;
+ INITDDSTRUCT(ddsd2);
+ if(!(s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D || s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D)
+ && SUCCEEDED(m_pDD->GetDisplayMode(&ddsd2))
+ && ddsd2.ddpfPixelFormat.dwRGBBitCount == 16)
+ {
+ ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
+ ddsd.ddpfPixelFormat.dwRBitMask = 0x0000F800;
+ ddsd.ddpfPixelFormat.dwGBitMask = 0x000007E0;
+ ddsd.ddpfPixelFormat.dwBBitMask = 0x0000001F;
+ hr = m_pDD->CreateSurface(&ddsd, &m_pVideoSurface, NULL);
+ }
+
+ if(FAILED(hr))
+ return hr;
+ }
+
+ if(s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D)
+ m_pVideoTexture = m_pVideoSurface;
+
+ DDBLTFX fx;
+ INITDDSTRUCT(fx);
+ fx.dwFillColor = 0;
+ hr = m_pVideoSurface->Blt(NULL, NULL, NULL, DDBLT_WAIT|DDBLT_COLORFILL, &fx);
+
+ return S_OK;
+}
+
+void CDX7AllocatorPresenter::DeleteSurfaces()
+{
+ CAutoLock cAutoLock(this);
+
+ m_pVideoTexture = NULL;
+ m_pVideoSurface = NULL;
+}
+
+// ISubPicAllocatorPresenter
+
+STDMETHODIMP CDX7AllocatorPresenter::CreateRenderer(IUnknown** ppRenderer)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP_(bool) CDX7AllocatorPresenter::Paint(bool fAll)
+{
+ if (m_bPendingResetDevice)
+ {
+ SendResetRequest();
+ return false;
+ }
+
+ 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_pPrimary || !m_pBackBuffer || !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);
+ MapWindowRect(m_hWnd, HWND_DESKTOP, &rDstPri);
+
+ if(fAll)
+ {
+ // clear the backbuffer
+
+ CRect rl(0, 0, rDstVid.left, rSrcPri.bottom);
+ CRect rr(rDstVid.right, 0, rSrcPri.right, rSrcPri.bottom);
+ CRect rt(0, 0, rSrcPri.right, rDstVid.top);
+ CRect rb(0, rDstVid.bottom, rSrcPri.right, rSrcPri.bottom);
+
+ DDBLTFX fx;
+ INITDDSTRUCT(fx);
+ fx.dwFillColor = 0;
+ hr = m_pBackBuffer->Blt(NULL, NULL, NULL, DDBLT_WAIT|DDBLT_COLORFILL, &fx);
+
+ // paint the video on the backbuffer
+
+ if(!rDstVid.IsRectEmpty())
+ {
+ if(m_pVideoTexture)
+ {
+ Vector v[4];
+ Transform(rDstVid, v);
+ hr = TextureBlt(m_pD3DDev, m_pVideoTexture, v, rSrcVid);
+ }
+ else
+ {
+ hr = m_pBackBuffer->Blt(rDstVid, m_pVideoSurface, rSrcVid, DDBLT_WAIT, NULL);
+ }
+ }
+
+ // paint the text on the backbuffer
+
+ AlphaBltSubPic(rSrcPri.Size());
+ }
+
+ // wait vsync
+
+ m_pDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL);
+
+ // blt to the primary surface
+
+ hr = m_pPrimary->Blt(rDstPri, m_pBackBuffer, rSrcPri, DDBLT_WAIT, NULL);
+
+ if(hr == DDERR_SURFACELOST)
+ {
+ m_bPendingResetDevice = true;
+ SendResetRequest();
+ return false;
+ }
+
+ return(true);
+}
+
+void CDX7AllocatorPresenter::SendResetRequest()
+{
+ if (!m_bDeviceResetRequested)
+ {
+ m_bDeviceResetRequested = true;
+ AfxGetApp()->m_pMainWnd->PostMessage(WM_RESET_DEVICE);
+ }
+}
+
+STDMETHODIMP_(bool) CDX7AllocatorPresenter::ResetDevice()
+{
+ HRESULT hr;
+ DeleteSurfaces();
+ if(FAILED(hr = CreateDevice()) || FAILED(hr = AllocSurfaces()))
+ {
+ //DDERR_UNSUPPORTEDMODE - 0x8876024e
+ TRACE("ResetDevice failed: 0x%08x\n", (LONG)hr);
+ m_bDeviceResetRequested = false;
+ return false;
+ }
+ TRACE("ResetDevice\n");
+ m_bPendingResetDevice = false;
+ m_bDeviceResetRequested = false;
+ return true;
+}
+
+STDMETHODIMP CDX7AllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size)
+{
+ CheckPointer(size, E_POINTER);
+
+ HRESULT hr;
+
+ DDSURFACEDESC2 ddsd;
+ INITDDSTRUCT(ddsd);
+ if(FAILED(m_pVideoSurface->GetSurfaceDesc(&ddsd)))
+ return E_FAIL;
+
+ if(ddsd.ddpfPixelFormat.dwRGBBitCount != 16 && ddsd.ddpfPixelFormat.dwRGBBitCount != 32)
+ return E_FAIL;
+
+ DWORD required = sizeof(BITMAPINFOHEADER) + (ddsd.dwWidth*ddsd.dwHeight*32>>3);
+ if(!lpDib)
+ {
+ *size = required;
+ return S_OK;
+ }
+ if(*size < required) return E_OUTOFMEMORY;
+ *size = required;
+
+ INITDDSTRUCT(ddsd);
+ if(FAILED(hr = m_pVideoSurface->Lock(NULL, &ddsd, DDLOCK_WAIT|DDLOCK_SURFACEMEMORYPTR|DDLOCK_READONLY|DDLOCK_NOSYSLOCK, NULL)))
+ {
+ // TODO
+ return hr;
+ }
+
+ BITMAPINFOHEADER* bih = (BITMAPINFOHEADER*)lpDib;
+ memset(bih, 0, sizeof(BITMAPINFOHEADER));
+ bih->biSize = sizeof(BITMAPINFOHEADER);
+ bih->biWidth = ddsd.dwWidth;
+ bih->biHeight = ddsd.dwHeight;
+ 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*)ddsd.lpSurface + ddsd.lPitch*(ddsd.dwHeight-1), -(int)ddsd.lPitch, ddsd.ddpfPixelFormat.dwRGBBitCount);
+
+ m_pVideoSurface->Unlock(NULL);
+
+ /*
+ BitBltFromRGBToRGB(
+ w, h,
+ (BYTE*)ddsd.lpSurface, ddsd.lPitch, ddsd.ddpfPixelFormat.dwRGBBitCount,
+ (BYTE*)bm.bmBits, bm.bmWidthBytes, bm.bmBitsPixel);
+ m_pVideoSurfaceOff->Unlock(NULL);
+ fOk = true;
+ }
+ */
+
+ return S_OK;
+}
diff --git a/src/filters/renderer/VideoRenderers/DX7AllocatorPresenter.h b/src/filters/renderer/VideoRenderers/DX7AllocatorPresenter.h new file mode 100644 index 000000000..da59c1ef8 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/DX7AllocatorPresenter.h @@ -0,0 +1,64 @@ +/*
+ * $Id$
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "AllocatorCommon7.h"
+#include <ddraw.h>
+#include <d3d.h>
+
+namespace DSObjects
+{
+
+ class CDX7AllocatorPresenter
+ : public ISubPicAllocatorPresenterImpl
+ {
+ protected:
+ CSize m_ScreenSize;
+
+ CComPtr<IDirectDraw7> m_pDD;
+ CComQIPtr<IDirect3D7, &IID_IDirect3D7> m_pD3D;
+ CComPtr<IDirect3DDevice7> m_pD3DDev;
+
+ CComPtr<IDirectDrawSurface7> m_pPrimary;
+ CComPtr<IDirectDrawSurface7> m_pBackBuffer;
+ CComPtr<IDirectDrawSurface7> m_pVideoTexture;
+ CComPtr<IDirectDrawSurface7> m_pVideoSurface;
+
+ virtual HRESULT CreateDevice();
+ virtual HRESULT AllocSurfaces();
+ virtual void DeleteSurfaces();
+
+ void SendResetRequest();
+
+ public:
+ CDX7AllocatorPresenter(HWND hWnd, HRESULT& hr);
+
+ // ISubPicAllocatorPresenter
+ STDMETHODIMP CreateRenderer(IUnknown** ppRenderer);
+ STDMETHODIMP_(bool) Paint(bool fAll);
+ STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size);
+ STDMETHODIMP_(bool) ResetDevice();
+ };
+
+}
diff --git a/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp new file mode 100644 index 000000000..cb103561d --- /dev/null +++ b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.cpp @@ -0,0 +1,3366 @@ +/*
+ * $Id$
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include "RenderersSettings.h"
+#include "DX9AllocatorPresenter.h"
+#include <initguid.h>
+#include <utility>
+#include "../apps/mplayerc/resource.h"
+#include "../SubPic/DX9SubPic.h"
+#include "IPinHook.h"
+
+CCritSec g_ffdshowReceive;
+bool queue_ffdshow_support = false;
+
+// only for debugging
+//#define DISABLE_USING_D3D9EX
+
+#define FRAMERATE_MAX_DELTA 3000
+//#pragma optimize("", off)
+//#pragma inline_depth(0)
+
+#pragma pack(push, 1)
+template<int texcoords>
+struct MYD3DVERTEX
+{
+ float x, y, z, rhw;
+ struct
+ {
+ float u, v;
+ } t[texcoords];
+};
+template<>
+struct MYD3DVERTEX<0>
+{
+ float x, y, z, rhw;
+ DWORD Diffuse;
+};
+#pragma pack(pop)
+
+template<int texcoords>
+static void AdjustQuad(MYD3DVERTEX<texcoords>* v, double dx, double dy)
+{
+ double offset = 0.5;
+
+ for(int i = 0; i < 4; i++)
+ {
+ v[i].x -= offset;
+ v[i].y -= offset;
+
+ for(int j = 0; j < max(texcoords-1, 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(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);
+ }
+
+ //
+
+ 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]));
+
+ //
+
+ for(int i = 0; i < texcoords; i++)
+ {
+ pD3DDev->SetTexture(i, NULL);
+ }
+
+ return S_OK;
+ }
+ while(0);
+
+ return E_FAIL;
+}
+
+static HRESULT DrawRect(IDirect3DDevice9* pD3DDev, MYD3DVERTEX<0> v[4])
+{
+ if(!pD3DDev)
+ return E_POINTER;
+
+ do
+ {
+ HRESULT 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, TRUE);
+ hr = pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
+ hr = pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
+ //D3DRS_COLORVERTEX
+ 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);
+
+ hr = pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX0 | D3DFVF_DIFFUSE);
+ // hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(v[0]));
+
+ MYD3DVERTEX<0> tmp = v[2];
+ v[2] = v[3];
+ v[3] = tmp;
+ hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0]));
+
+ return S_OK;
+ }
+ while(0);
+
+ return E_FAIL;
+}
+
+using namespace DSObjects;
+using namespace std;
+
+// CDX9AllocatorPresenter
+
+CDX9AllocatorPresenter::CDX9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, bool bIsEVR, CString &_Error)
+ : ISubPicAllocatorPresenterImpl(hWnd, hr, &_Error)
+ , m_ScreenSize(0, 0)
+ , m_RefreshRate(0)
+ , m_bicubicA(0)
+ , m_nTearingPos(0)
+ , m_nNbDXSurface(1)
+ , m_nVMR9Surfaces(0)
+ , m_iVMR9Surface(0)
+ , m_nCurSurface(0)
+ , m_rtTimePerFrame(0)
+ , m_bInterlaced(false)
+ , m_nUsedBuffer(0)
+ , m_OrderedPaint(0)
+ , m_bCorrectedFrameTime(0)
+ , m_FrameTimeCorrection(0)
+ , m_LastSampleTime(0)
+ , m_LastFrameDuration(0)
+ , m_bAlternativeVSync(0)
+ , m_bIsEVR(bIsEVR)
+ , m_VSyncMode(0)
+ , m_TextScale(1.0)
+ , m_MainThreadId(0)
+ , m_bNeedCheckSample(true)
+ , m_pDirectDraw(NULL)
+ , m_hVSyncThread(NULL)
+ , m_hEvtQuit(NULL)
+ , m_bIsFullscreen(bFullscreen)
+ , m_CurrentAdapter(0)
+{
+ HINSTANCE hDll;
+
+ if(FAILED(hr))
+ {
+ _Error += L"ISubPicAllocatorPresenterImpl failed\n";
+ return;
+ }
+
+ m_pD3DXLoadSurfaceFromMemory = NULL;
+ m_pD3DXCreateLine = NULL;
+ m_pD3DXCreateFont = NULL;
+ m_pD3DXCreateSprite = NULL;
+ hDll = GetRenderersData()->GetD3X9Dll();
+ if(hDll)
+ {
+ (FARPROC&)m_pD3DXLoadSurfaceFromMemory = GetProcAddress(hDll, "D3DXLoadSurfaceFromMemory");
+ (FARPROC&)m_pD3DXCreateLine = GetProcAddress(hDll, "D3DXCreateLine");
+ (FARPROC&)m_pD3DXCreateFont = GetProcAddress(hDll, "D3DXCreateFontW");
+ (FARPROC&)m_pD3DXCreateSprite = GetProcAddress(hDll, "D3DXCreateSprite");
+ }
+ else
+ {
+ _Error += L"No D3DX9 dll found. To enable stats, shaders and complex resizers, please make sure to install the latest DirectX End-User Runtime.\n";
+ }
+
+ m_pDwmIsCompositionEnabled = NULL;
+ m_pDwmEnableComposition = NULL;
+ m_hDWMAPI = LoadLibrary(L"dwmapi.dll");
+ if (m_hDWMAPI)
+ {
+ (FARPROC &)m_pDwmIsCompositionEnabled = GetProcAddress(m_hDWMAPI, "DwmIsCompositionEnabled");
+ (FARPROC &)m_pDwmEnableComposition = GetProcAddress(m_hDWMAPI, "DwmEnableComposition");
+ }
+
+ m_pDirect3DCreate9Ex = NULL;
+ m_hD3D9 = LoadLibrary(L"d3d9.dll");
+#ifdef DISABLE_USING_D3D9EX
+ if (m_hD3D9)
+ (FARPROC &)m_pDirect3DCreate9Ex = GetProcAddress(m_hD3D9, "Direct3DCreate9Ex");
+#endif
+
+ if (m_pDirect3DCreate9Ex)
+ {
+ m_pDirect3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx);
+ if(!m_pD3DEx)
+ m_pDirect3DCreate9Ex(D3D9b_SDK_VERSION, &m_pD3DEx);
+ }
+ if(!m_pD3DEx)
+ {
+ m_pD3D.Attach(Direct3DCreate9(D3D_SDK_VERSION));
+ if(!m_pD3D)
+ m_pD3D.Attach(Direct3DCreate9(D3D9b_SDK_VERSION));
+ }
+ else
+ m_pD3D = m_pD3DEx;
+
+ m_DetectedFrameRate = 0.0;
+ m_DetectedFrameTime = 0.0;
+ m_DetectedFrameTimeStdDev = 0.0;
+ m_DetectedLock = false;
+ ZeroMemory(m_DetectedFrameTimeHistory, sizeof(m_DetectedFrameTimeHistory));
+ ZeroMemory(m_DetectedFrameTimeHistoryHistory, sizeof(m_DetectedFrameTimeHistoryHistory));
+ m_DetectedFrameTimePos = 0;
+ ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap));
+
+ ZeroMemory(m_ldDetectedRefreshRateList, sizeof(m_ldDetectedRefreshRateList));
+ ZeroMemory(m_ldDetectedScanlineRateList, sizeof(m_ldDetectedScanlineRateList));
+ m_DetectedRefreshRatePos = 0;
+ m_DetectedRefreshTimePrim = 0;
+ m_DetectedScanlineTime = 0;
+ m_DetectedScanlineTimePrim = 0;
+ m_DetectedRefreshRate = 0;
+ CRenderersSettings& s = GetRenderersSettings();
+
+ if (s.m_RenderSettings.iVMRDisableDesktopComposition)
+ {
+ m_bDesktopCompositionDisabled = true;
+ if (m_pDwmEnableComposition)
+ m_pDwmEnableComposition(0);
+ }
+ else
+ {
+ m_bDesktopCompositionDisabled = false;
+ }
+
+ hr = CreateDevice(_Error);
+
+ memset (m_pllJitter, 0, sizeof(m_pllJitter));
+ memset (m_pllSyncOffset, 0, sizeof(m_pllSyncOffset));
+ m_nNextJitter = 0;
+ m_nNextSyncOffset = 0;
+ m_llLastPerf = 0;
+ m_fAvrFps = 0.0;
+ m_fJitterStdDev = 0.0;
+ m_fSyncOffsetStdDev = 0.0;
+ m_fSyncOffsetAvr = 0.0;
+ m_bSyncStatsAvailable = false;
+}
+
+CDX9AllocatorPresenter::~CDX9AllocatorPresenter()
+{
+ if (m_bDesktopCompositionDisabled)
+ {
+ m_bDesktopCompositionDisabled = false;
+ if (m_pDwmEnableComposition)
+ m_pDwmEnableComposition(1);
+ }
+
+ StopWorkerThreads();
+ m_pFont = NULL;
+ m_pLine = NULL;
+ m_pD3DDev = NULL;
+ m_pD3DDevEx = NULL;
+ m_pPSC.Free();
+ m_pD3D = NULL;
+ m_pD3DEx = NULL;
+ if (m_hDWMAPI)
+ {
+ FreeLibrary(m_hDWMAPI);
+ m_hDWMAPI = NULL;
+ }
+ if (m_hD3D9)
+ {
+ FreeLibrary(m_hD3D9);
+ m_hD3D9 = NULL;
+ }
+}
+
+void ModerateFloat(double& Value, double Target, double& ValuePrim, double ChangeSpeed);
+
+#if 0
+class CRandom31
+{
+public:
+
+ CRandom31()
+ {
+ m_Seed = 12164;
+ }
+
+ void f_SetSeed(int32 _Seed)
+ {
+ m_Seed = _Seed;
+ }
+ int32 f_GetSeed()
+ {
+ return m_Seed;
+ }
+ /*
+ Park and Miller's psuedo-random number generator.
+ */
+ int32 m_Seed;
+ int32 f_Get()
+ {
+ static const int32 A = 16807;
+ static const int32 M = 2147483647; // 2^31 - 1
+ static const int32 q = M / A; // M / A
+ static const int32 r = M % A; // M % A
+ m_Seed = A * (m_Seed % q) - r * (m_Seed / q);
+ if (m_Seed < 0)
+ m_Seed += M;
+ return m_Seed;
+ }
+
+ static int32 fs_Max()
+ {
+ return 2147483646;
+ }
+
+ double f_GetFloat()
+ {
+ return double(f_Get()) * (1.0 / double(fs_Max()));
+ }
+};
+
+class CVSyncEstimation
+{
+private:
+ class CHistoryEntry
+ {
+ public:
+ CHistoryEntry()
+ {
+ m_Time = 0;
+ m_ScanLine = -1;
+ }
+ LONGLONG m_Time;
+ int m_ScanLine;
+ };
+
+ class CSolution
+ {
+ public:
+ CSolution()
+ {
+ m_ScanLines = 1000;
+ m_ScanLinesPerSecond = m_ScanLines * 100;
+ }
+ int m_ScanLines;
+ double m_ScanLinesPerSecond;
+ double m_SqrSum;
+
+ void f_Mutate(double _Amount, CRandom31 &_Random, int _MinScans)
+ {
+ int ToDo = _Random.f_Get() % 10;
+ if (ToDo == 0)
+ m_ScanLines = m_ScanLines / 2;
+ else if (ToDo == 1)
+ m_ScanLines = m_ScanLines * 2;
+
+ m_ScanLines = m_ScanLines * (1.0 + (_Random.f_GetFloat() * _Amount) - _Amount * 0.5);
+ m_ScanLines = max(m_ScanLines, _MinScans);
+
+ if (ToDo == 2)
+ m_ScanLinesPerSecond /= (_Random.f_Get() % 4) + 1;
+ else if (ToDo == 3)
+ m_ScanLinesPerSecond *= (_Random.f_Get() % 4) + 1;
+
+ m_ScanLinesPerSecond *= 1.0 + (_Random.f_GetFloat() * _Amount) - _Amount * 0.5;
+ }
+
+ void f_SpawnInto(CSolution &_Other, CRandom31 &_Random, int _MinScans)
+ {
+ _Other = *this;
+ _Other.f_Mutate(_Random.f_GetFloat() * 0.1, _Random, _MinScans);
+ }
+
+ static int fs_Compare(const void *_pFirst, const void *_pSecond)
+ {
+ const CSolution *pFirst = (const CSolution *)_pFirst;
+ const CSolution *pSecond = (const CSolution *)_pSecond;
+ if (pFirst->m_SqrSum < pSecond->m_SqrSum)
+ return -1;
+ else if (pFirst->m_SqrSum > pSecond->m_SqrSum)
+ return 1;
+ return 0;
+ }
+
+
+ };
+
+ enum
+ {
+ ENumHistory = 128
+ };
+
+ CHistoryEntry m_History[ENumHistory];
+ int m_iHistory;
+ CSolution m_OldSolutions[2];
+
+ CRandom31 m_Random;
+
+
+ double fp_GetSquareSum(double _ScansPerSecond, double _ScanLines)
+ {
+ double SquareSum = 0;
+ int nHistory = min(m_nHistory, ENumHistory);
+ int iHistory = m_iHistory - nHistory;
+ if (iHistory < 0)
+ iHistory += ENumHistory;
+ for (int i = 1; i < nHistory; ++i)
+ {
+ int iHistory0 = iHistory + i - 1;
+ int iHistory1 = iHistory + i;
+ if (iHistory0 < 0)
+ iHistory0 += ENumHistory;
+ iHistory0 = iHistory0 % ENumHistory;
+ iHistory1 = iHistory1 % ENumHistory;
+ ASSERT(m_History[iHistory0].m_Time != 0);
+ ASSERT(m_History[iHistory1].m_Time != 0);
+
+ double DeltaTime = (m_History[iHistory1].m_Time - m_History[iHistory0].m_Time)/10000000.0;
+ double PredictedScanLine = m_History[iHistory0].m_ScanLine + DeltaTime * _ScansPerSecond;
+ PredictedScanLine = fmod(PredictedScanLine, _ScanLines);
+ double Delta = (m_History[iHistory1].m_ScanLine - PredictedScanLine);
+ double DeltaSqr = Delta * Delta;
+ SquareSum += DeltaSqr;
+ }
+ return SquareSum;
+ }
+
+ int m_nHistory;
+public:
+
+ CVSyncEstimation()
+ {
+ m_iHistory = 0;
+ m_nHistory = 0;
+ }
+
+ void f_AddSample(int _ScanLine, LONGLONG _Time)
+ {
+ m_History[m_iHistory].m_ScanLine = _ScanLine;
+ m_History[m_iHistory].m_Time = _Time;
+ ++m_nHistory;
+ m_iHistory = (m_iHistory + 1) % ENumHistory;
+ }
+
+ void f_GetEstimation(double &_RefreshRate, int &_ScanLines, int _ScreenSizeY, int _WindowsRefreshRate)
+ {
+ _RefreshRate = 0;
+ _ScanLines = 0;
+
+ int iHistory = m_iHistory;
+ // We have a full history
+ if (m_nHistory > 10)
+ {
+ for (int l = 0; l < 5; ++l)
+ {
+ const int nSol = 3+5+5+3;
+ CSolution Solutions[nSol];
+
+ Solutions[0] = m_OldSolutions[0];
+ Solutions[1] = m_OldSolutions[1];
+ Solutions[2].m_ScanLines = _ScreenSizeY;
+ Solutions[2].m_ScanLinesPerSecond = _ScreenSizeY * _WindowsRefreshRate;
+
+ int iStart = 3;
+ for (int i = iStart; i < iStart + 5; ++i)
+ Solutions[0].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY);
+ iStart += 5;
+ for (int i = iStart; i < iStart + 5; ++i)
+ Solutions[1].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY);
+ iStart += 5;
+ for (int i = iStart; i < iStart + 3; ++i)
+ Solutions[2].f_SpawnInto(Solutions[i], m_Random, _ScreenSizeY);
+
+ int Start = 2;
+ if (l == 0)
+ Start = 0;
+ for (int i = Start; i < nSol; ++i)
+ Solutions[i].m_SqrSum = fp_GetSquareSum(Solutions[i].m_ScanLinesPerSecond, Solutions[i].m_ScanLines);
+
+ qsort(Solutions, nSol, sizeof(Solutions[0]), &CSolution::fs_Compare);
+ for (int i = 0; i < 2; ++i)
+ m_OldSolutions[i] = Solutions[i];
+ }
+
+ _ScanLines = m_OldSolutions[0].m_ScanLines + 0.5;
+ _RefreshRate = 1.0 / (m_OldSolutions[0].m_ScanLines / m_OldSolutions[0].m_ScanLinesPerSecond);
+ }
+ else
+ {
+ m_OldSolutions[0].m_ScanLines = _ScreenSizeY;
+ m_OldSolutions[1].m_ScanLines = _ScreenSizeY;
+ }
+ }
+};
+#endif
+
+void CDX9AllocatorPresenter::VSyncThread()
+{
+ HANDLE hAvrt;
+ HANDLE hEvts[] = { m_hEvtQuit};
+ bool bQuit = false;
+ TIMECAPS tc;
+ DWORD dwResolution;
+ DWORD dwUser = 0;
+ DWORD dwTaskIndex = 0;
+
+ // Tell Vista Multimedia Class Scheduler we are a playback thretad (increase priority)
+// if (pfAvSetMmThreadCharacteristicsW)
+// hAvrt = pfAvSetMmThreadCharacteristicsW (L"Playback", &dwTaskIndex);
+// if (pfAvSetMmThreadPriority)
+// pfAvSetMmThreadPriority (hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/);
+
+// Sleep(2000); // Remove ugly patch : create a 2s delay on opening files with Win7!
+
+ timeGetDevCaps(&tc, sizeof(TIMECAPS));
+ dwResolution = min(max(tc.wPeriodMin, 0), tc.wPeriodMax);
+ dwUser = timeBeginPeriod(dwResolution);
+ CRenderersData *pApp = GetRenderersData();
+ CRenderersSettings& s = GetRenderersSettings();
+
+ while (!bQuit)
+ {
+
+ DWORD dwObject = WaitForMultipleObjects (countof(hEvts), hEvts, FALSE, 1);
+ switch (dwObject)
+ {
+ case WAIT_OBJECT_0 :
+ bQuit = true;
+ break;
+ case WAIT_TIMEOUT :
+ {
+ // Do our stuff
+ if (m_pD3DDev && s.m_RenderSettings.iVMR9VSync)
+ {
+
+ int VSyncPos = GetVBlackPos();
+ int WaitRange = max(m_ScreenSize.cy / 40, 5);
+ int MinRange = max(min(int(0.003 * double(m_ScreenSize.cy) * double(m_RefreshRate) + 0.5), m_ScreenSize.cy/3), 5); // 1.8 ms or max 33 % of Time
+
+ VSyncPos += MinRange + WaitRange;
+
+ VSyncPos = VSyncPos % m_ScreenSize.cy;
+ if (VSyncPos < 0)
+ VSyncPos += m_ScreenSize.cy;
+
+ int ScanLine = 0;
+ int bInVBlank = 0;
+ int StartScanLine = ScanLine;
+ int LastPos = ScanLine;
+ ScanLine = (VSyncPos + 1) % m_ScreenSize.cy;
+ if (ScanLine < 0)
+ ScanLine += m_ScreenSize.cy;
+ int FirstScanLine = ScanLine;
+ int ScanLineMiddle = ScanLine + m_ScreenSize.cy/2;
+ ScanLineMiddle = ScanLineMiddle % m_ScreenSize.cy;
+ if (ScanLineMiddle < 0)
+ ScanLineMiddle += m_ScreenSize.cy;
+
+ int ScanlineStart = ScanLine;
+ bool bTakenLock;
+ WaitForVBlankRange(ScanlineStart, 5, true, true, false, bTakenLock);
+ LONGLONG TimeStart = pApp->GetPerfCounter();
+
+ WaitForVBlankRange(ScanLineMiddle, 5, true, true, false, bTakenLock);
+ LONGLONG TimeMiddle = pApp->GetPerfCounter();
+
+ int ScanlineEnd = ScanLine;
+ WaitForVBlankRange(ScanlineEnd, 5, true, true, false, bTakenLock);
+ LONGLONG TimeEnd = pApp->GetPerfCounter();
+
+ double nSeconds = double(TimeEnd - TimeStart) / 10000000.0;
+ LONGLONG DiffMiddle = TimeMiddle - TimeStart;
+ LONGLONG DiffEnd = TimeEnd - TimeMiddle;
+ double DiffDiff;
+ if (DiffEnd > DiffMiddle)
+ DiffDiff = double(DiffEnd) / double(DiffMiddle);
+ else
+ DiffDiff = double(DiffMiddle) / double(DiffEnd);
+ if (nSeconds > 0.003 && DiffDiff < 1.3)
+ {
+ double ScanLineSeconds;
+ double nScanLines;
+ if (ScanLineMiddle > ScanlineEnd)
+ {
+ ScanLineSeconds = double(TimeMiddle - TimeStart) / 10000000.0;
+ nScanLines = ScanLineMiddle - ScanlineStart;
+ }
+ else
+ {
+ ScanLineSeconds = double(TimeEnd - TimeMiddle) / 10000000.0;
+ nScanLines = ScanlineEnd - ScanLineMiddle;
+ }
+
+ double ScanLineTime = ScanLineSeconds / nScanLines;
+
+ int iPos = m_DetectedRefreshRatePos % 100;
+ m_ldDetectedScanlineRateList[iPos] = ScanLineTime;
+ if (m_DetectedScanlineTime && ScanlineStart != ScanlineEnd)
+ {
+ int Diff = ScanlineEnd - ScanlineStart;
+ nSeconds -= double(Diff) * m_DetectedScanlineTime;
+ }
+ m_ldDetectedRefreshRateList[iPos] = nSeconds;
+ double Average = 0;
+ double AverageScanline = 0;
+ int nPos = min(iPos + 1, 100);
+ for (int i = 0; i < nPos; ++i)
+ {
+ Average += m_ldDetectedRefreshRateList[i];
+ AverageScanline += m_ldDetectedScanlineRateList[i];
+ }
+
+ if (nPos)
+ {
+ Average /= double(nPos);
+ AverageScanline /= double(nPos);
+ }
+ else
+ {
+ Average = 0;
+ AverageScanline = 0;
+ }
+
+ double ThisValue = Average;
+
+ if (Average > 0.0 && AverageScanline > 0.0)
+ {
+ CAutoLock Lock(&m_RefreshRateLock);
+ ++m_DetectedRefreshRatePos;
+ if (m_DetectedRefreshTime == 0 || m_DetectedRefreshTime / ThisValue > 1.01 || m_DetectedRefreshTime / ThisValue < 0.99)
+ {
+ m_DetectedRefreshTime = ThisValue;
+ m_DetectedRefreshTimePrim = 0;
+ }
+ ModerateFloat(m_DetectedRefreshTime, ThisValue, m_DetectedRefreshTimePrim, 1.5);
+ if (m_DetectedRefreshTime > 0.0)
+ m_DetectedRefreshRate = 1.0/m_DetectedRefreshTime;
+ else
+ m_DetectedRefreshRate = 0.0;
+
+ if (m_DetectedScanlineTime == 0 || m_DetectedScanlineTime / AverageScanline > 1.01 || m_DetectedScanlineTime / AverageScanline < 0.99)
+ {
+ m_DetectedScanlineTime = AverageScanline;
+ m_DetectedScanlineTimePrim = 0;
+ }
+ ModerateFloat(m_DetectedScanlineTime, AverageScanline, m_DetectedScanlineTimePrim, 1.5);
+ if (m_DetectedScanlineTime > 0.0)
+ m_DetectedScanlinesPerFrame = m_DetectedRefreshTime / m_DetectedScanlineTime;
+ else
+ m_DetectedScanlinesPerFrame = 0;
+ }
+ //TRACE("Refresh: %f\n", RefreshRate);
+ }
+ }
+ else
+ {
+ m_DetectedRefreshRate = 0.0;
+ m_DetectedScanlinesPerFrame = 0.0;
+ }
+ }
+ break;
+ }
+ }
+
+ timeEndPeriod (dwResolution);
+// if (pfAvRevertMmThreadCharacteristics) pfAvRevertMmThreadCharacteristics (hAvrt);
+}
+
+
+DWORD WINAPI CDX9AllocatorPresenter::VSyncThreadStatic(LPVOID lpParam)
+{
+ SetThreadName(-1, "CDX9Presenter::VSyncThread");
+ CDX9AllocatorPresenter* pThis = (CDX9AllocatorPresenter*) lpParam;
+ pThis->VSyncThread();
+ return 0;
+}
+
+void CDX9AllocatorPresenter::StartWorkerThreads()
+{
+ DWORD dwThreadId;
+
+ if ( m_bIsEVR )
+ {
+ m_hEvtQuit = CreateEvent( NULL, TRUE, FALSE, NULL );
+ if ( m_hEvtQuit != NULL ) // Don't create a thread with no stop switch
+ {
+ m_hVSyncThread = ::CreateThread( NULL, 0, VSyncThreadStatic, (LPVOID)this, 0, &dwThreadId );
+ if ( m_hVSyncThread != NULL )
+ SetThreadPriority( m_hVSyncThread, THREAD_PRIORITY_HIGHEST );
+ }
+ }
+}
+
+void CDX9AllocatorPresenter::StopWorkerThreads()
+{
+ if ( m_bIsEVR )
+ {
+ if ( m_hEvtQuit != NULL )
+ {
+ SetEvent( m_hEvtQuit );
+
+ if ( m_hVSyncThread != NULL )
+ {
+ if ( WaitForSingleObject(m_hVSyncThread, 10000) == WAIT_TIMEOUT )
+ {
+ ASSERT(FALSE);
+ TerminateThread( m_hVSyncThread, 0xDEAD );
+ }
+
+ CloseHandle( m_hVSyncThread );
+ m_hVSyncThread = NULL;
+ }
+
+ CloseHandle( m_hEvtQuit );
+ m_hEvtQuit = NULL;
+ }
+ }
+}
+
+bool CDX9AllocatorPresenter::SettingsNeedResetDevice()
+{
+ CRenderersSettings& s = GetRenderersSettings();
+ CRenderersSettings::CRendererSettingsEVR & New = GetRenderersSettings().m_RenderSettings;
+ CRenderersSettings::CRendererSettingsEVR & Current = m_LastRendererSettings;
+
+ bool bRet = false;
+
+ bRet = bRet || New.fVMR9AlterativeVSync != Current.fVMR9AlterativeVSync;
+ bRet = bRet || New.iVMR9VSyncAccurate != Current.iVMR9VSyncAccurate;
+
+ if (m_bIsFullscreen)
+ {
+ bRet = bRet || New.iVMR9FullscreenGUISupport != Current.iVMR9FullscreenGUISupport;
+ }
+ else
+ {
+ if (Current.iVMRDisableDesktopComposition)
+ {
+ if (!m_bDesktopCompositionDisabled)
+ {
+ m_bDesktopCompositionDisabled = true;
+ if (m_pDwmEnableComposition)
+ m_pDwmEnableComposition(0);
+ }
+ }
+ else
+ {
+ if (m_bDesktopCompositionDisabled)
+ {
+ m_bDesktopCompositionDisabled = false;
+ if (m_pDwmEnableComposition)
+ m_pDwmEnableComposition(1);
+ }
+ }
+ }
+
+ if (m_bIsEVR)
+ {
+ bRet = bRet || New.iEVRHighColorResolution != Current.iEVRHighColorResolution;
+ }
+
+ m_LastRendererSettings = s.m_RenderSettings;
+
+ return bRet;
+}
+
+HRESULT CDX9AllocatorPresenter::CreateDevice(CString &_Error)
+{
+ StopWorkerThreads();
+ CRenderersSettings& s = GetRenderersSettings();
+ m_VBlankEndWait = 0;
+ m_VBlankMin = 300000;
+ m_VBlankMinCalc = 300000;
+ m_VBlankMax = 0;
+ m_VBlankStartWait = 0;
+ m_VBlankWaitTime = 0;
+ m_VBlankLockTime = 0;
+ m_PresentWaitTime = 0;
+ m_PresentWaitTimeMin = 3000000000;
+ m_PresentWaitTimeMax = 0;
+
+ m_LastRendererSettings = s.m_RenderSettings;
+
+ m_VBlankEndPresent = -100000;
+ m_VBlankStartMeasureTime = 0;
+ m_VBlankStartMeasure = 0;
+
+ m_PaintTime = 0;
+ m_PaintTimeMin = 3000000000;
+ m_PaintTimeMax = 0;
+
+ m_RasterStatusWaitTime = 0;
+ m_RasterStatusWaitTimeMin = 3000000000;
+ m_RasterStatusWaitTimeMax = 0;
+ m_RasterStatusWaitTimeMaxCalc = 0;
+
+ m_ClockDiff = 0.0;
+ m_ClockDiffPrim = 0.0;
+ m_ClockDiffCalc = 0.0;
+
+ m_ModeratedTimeSpeed = 1.0;
+ m_ModeratedTimeSpeedDiff = 0.0;
+ m_ModeratedTimeSpeedPrim = 0;
+ ZeroMemory(m_TimeChangeHistory, sizeof(m_TimeChangeHistory));
+ ZeroMemory(m_ClockChangeHistory, sizeof(m_ClockChangeHistory));
+ m_ClockTimeChangeHistoryPos = 0;
+
+ m_pPSC.Free();
+ m_pD3DDev = NULL;
+ m_pD3DDevEx = NULL;
+ m_pDirectDraw = NULL;
+
+ m_pResizerPixelShader[0] = 0;
+ m_pResizerPixelShader[1] = 0;
+ m_pResizerPixelShader[2] = 0;
+ m_pResizerPixelShader[3] = 0;
+
+ POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition();
+ while(pos)
+ {
+ CExternalPixelShader &Shader = m_pPixelShadersScreenSpace.GetNext(pos);
+ Shader.m_pPixelShader = NULL;
+ }
+ pos = m_pPixelShaders.GetHeadPosition();
+ while(pos)
+ {
+ CExternalPixelShader &Shader = m_pPixelShaders.GetNext(pos);
+ Shader.m_pPixelShader = NULL;
+ }
+
+ if(!m_pD3D)
+ {
+ _Error += L"Failed to create D3D9\n";
+ return E_UNEXPECTED;
+ }
+
+ D3DDISPLAYMODE d3ddm;
+ HRESULT hr;
+ ZeroMemory(&d3ddm, sizeof(d3ddm));
+ m_CurrentAdapter = GetAdapter(m_pD3D);
+ if(FAILED(m_pD3D->GetAdapterDisplayMode(m_CurrentAdapter, &d3ddm)))
+ {
+ _Error += L"GetAdapterDisplayMode failed\n";
+ return E_UNEXPECTED;
+ }
+
+ /* // TODO : add nVidia PerfHUD !!!
+
+ // Set default settings
+ UINT AdapterToUse=D3DADAPTER_DEFAULT;
+ D3DDEVTYPE DeviceType=D3DDEVTYPE_HAL;
+
+ #if SHIPPING_VERSION
+ // When building a shipping version, disable PerfHUD (opt-out)
+ #else
+ // Look for 'NVIDIA PerfHUD' adapter
+ // If it is present, override default settings
+ for (UINT Adapter=0;Adapter<g_pD3D->GetAdapterCount();Adapter++)
+ {
+ D3DADAPTER_IDENTIFIER9 Identifier;
+ HRESULT Res;
+
+ Res = g_pD3D->GetAdapterIdentifier(Adapter,0,&Identifier);
+ if (strstr(Identifier.Description,"PerfHUD") != 0)
+ {
+ AdapterToUse=Adapter;
+ DeviceType=D3DDEVTYPE_REF;
+ break;
+ }
+ }
+ #endif
+
+ if (FAILED(g_pD3D->CreateDevice( AdapterToUse, DeviceType, hWnd,
+ D3DCREATE_HARDWARE_VERTEXPROCESSING,
+ &d3dpp, &g_pd3dDevice) ) )
+ {
+ return E_FAIL;
+ }
+ */
+
+
+//#define ENABLE_DDRAWSYNC
+#ifdef ENABLE_DDRAWSYNC
+ hr = DirectDrawCreate(NULL, &m_pDirectDraw, NULL) ;
+ if (hr == S_OK)
+ {
+ hr = m_pDirectDraw->SetCooperativeLevel(m_hWnd, DDSCL_NORMAL) ;
+ }
+#endif
+
+ m_RefreshRate = d3ddm.RefreshRate;
+ m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height);
+
+ D3DPRESENT_PARAMETERS pp;
+ ZeroMemory(&pp, sizeof(pp));
+
+ BOOL bCompositionEnabled = false;
+ if (m_pDwmIsCompositionEnabled)
+ m_pDwmIsCompositionEnabled(&bCompositionEnabled);
+
+ m_bCompositionEnabled = bCompositionEnabled != 0;
+
+ m_bAlternativeVSync = s.m_RenderSettings.fVMR9AlterativeVSync;
+ m_bHighColorResolution = s.m_RenderSettings.iEVRHighColorResolution && m_bIsEVR;
+
+ if (m_bIsFullscreen)
+ {
+ pp.Windowed = false;
+ pp.BackBufferWidth = d3ddm.Width;
+ pp.BackBufferHeight = d3ddm.Height;
+ pp.hDeviceWindow = m_hWnd;
+ if(m_bAlternativeVSync)
+ {
+ pp.BackBufferCount = 3;
+ pp.SwapEffect = D3DSWAPEFFECT_DISCARD; // Ne pas mettre D3DSWAPEFFECT_COPY car cela entraine une desynchro audio sur les MKV ! // Copy needed for sync now? FLIP only stutters.
+ pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+ }
+ else
+ {
+ pp.BackBufferCount = 3;
+ pp.SwapEffect = D3DSWAPEFFECT_DISCARD; // Ne pas mettre D3DSWAPEFFECT_COPY car cela entraine une desynchro audio sur les MKV ! // Copy needed for sync now? FLIP only stutters.
+ pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
+ }
+ pp.Flags = D3DPRESENTFLAG_VIDEO;
+ if (s.m_RenderSettings.iVMR9FullscreenGUISupport && !m_bHighColorResolution)
+ pp.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
+ if (m_bHighColorResolution)
+ pp.BackBufferFormat = D3DFMT_A2R10G10B10;
+ else
+ pp.BackBufferFormat = d3ddm.Format;
+
+ m_D3DDevExError = L"No m_pD3DEx";
+ if (m_pD3DEx)
+ {
+ D3DDISPLAYMODEEX DisplayMode;
+ ZeroMemory(&DisplayMode, sizeof(DisplayMode));
+ DisplayMode.Size = sizeof(DisplayMode);
+ m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, NULL);
+
+ DisplayMode.Format = pp.BackBufferFormat;
+ pp.FullScreen_RefreshRateInHz = DisplayMode.RefreshRate;
+
+ m_CurrentAdapter = GetAdapter(m_pD3D, true);
+ hr = m_pD3DEx->CreateDeviceEx(
+ m_CurrentAdapter, D3DDEVTYPE_HAL, m_hWnd,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED, //D3DCREATE_MANAGED
+ &pp, &DisplayMode, &m_pD3DDevEx);
+
+ m_D3DDevExError = GetWindowsErrorMessage(hr, m_hD3D9);
+ if (m_pD3DDevEx)
+ {
+ m_pD3DDev = m_pD3DDevEx;
+ m_BackbufferType = pp.BackBufferFormat;
+ m_DisplayType = DisplayMode.Format;
+ }
+ }
+
+ if (!m_pD3DDev)
+ {
+ m_CurrentAdapter = GetAdapter(m_pD3D, true);
+ hr = m_pD3D->CreateDevice(
+ m_CurrentAdapter, D3DDEVTYPE_HAL, m_hWnd,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED, //D3DCREATE_MANAGED
+ &pp, &m_pD3DDev);
+ if (m_pD3DDev)
+ {
+ m_BackbufferType = pp.BackBufferFormat;
+ m_DisplayType = d3ddm.Format;
+ }
+ }
+ if (m_pD3DDev && s.m_RenderSettings.iVMR9FullscreenGUISupport && !m_bHighColorResolution)
+ {
+ m_pD3DDev->SetDialogBoxMode(true);
+ //if (m_pD3DDev->SetDialogBoxMode(true) != S_OK)
+ // ExitProcess(0);
+
+ }
+
+ TRACE("CreateDevice: %d\n", (LONG)hr);
+ ASSERT (SUCCEEDED (hr));
+ }
+ else
+ {
+ 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;
+ m_BackbufferType = d3ddm.Format;
+ m_DisplayType = d3ddm.Format;
+ if (m_bHighColorResolution)
+ {
+ m_BackbufferType = D3DFMT_A2R10G10B10;
+ pp.BackBufferFormat = D3DFMT_A2R10G10B10;
+ }
+ if (bCompositionEnabled || m_bAlternativeVSync)
+ {
+ // Desktop composition takes care of the VSYNC
+ pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+ }
+ else
+ {
+ pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
+ }
+
+// if(m_fVMRSyncFix = GetRenderersData()->m_s.fVMRSyncFix)
+// pp.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
+
+ m_CurrentAdapter = GetAdapter(m_pD3D, true);
+ if (m_pD3DEx)
+ {
+ hr = m_pD3DEx->CreateDeviceEx(
+ m_CurrentAdapter, D3DDEVTYPE_HAL, m_hWnd,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED, //D3DCREATE_MANAGED
+ &pp, NULL, &m_pD3DDevEx);
+ if (m_pD3DDevEx)
+ m_pD3DDev = m_pD3DDevEx;
+ }
+ else
+ {
+ hr = m_pD3D->CreateDevice(
+ m_CurrentAdapter, D3DDEVTYPE_HAL, m_hWnd,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED, //D3DCREATE_MANAGED
+ &pp, &m_pD3DDev);
+ }
+ }
+
+ m_MainThreadId = GetCurrentThreadId();
+
+ if (m_pD3DDevEx)
+ {
+ m_pD3DDevEx->SetGPUThreadPriority(7);
+ }
+
+ if(FAILED(hr))
+ {
+ _Error += L"CreateDevice failed\n";
+
+ return hr;
+ }
+
+ m_pPSC.Attach(DNew 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(GetRenderersSettings().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;
+ case 6:
+ size.SetSize(2560, 1600);
+ break;
+ case 7:
+ size.SetSize(1920, 1080);
+ break;
+ case 8:
+ size.SetSize(1320, 900);
+ break;
+ case 9:
+ size.SetSize(1280, 720);
+ break;
+ }
+
+ if(m_pAllocator)
+ {
+ m_pAllocator->ChangeDevice(m_pD3DDev);
+ }
+ else
+ {
+ m_pAllocator = DNew CDX9SubPicAllocator(m_pD3DDev, size, GetRenderersSettings().fSPCPow2Tex);
+ if(!m_pAllocator)
+ {
+ _Error += L"CDX9SubPicAllocator failed\n";
+
+ return E_FAIL;
+ }
+ }
+
+ hr = S_OK;
+ m_pSubPicQueue = GetRenderersSettings().nSPCSize > 0
+ ? (ISubPicQueue*)DNew CSubPicQueue(GetRenderersSettings().nSPCSize, !GetRenderersSettings().fSPCAllowAnimationWhenBuffering, m_pAllocator, &hr)
+ : (ISubPicQueue*)DNew CSubPicQueueNoThread(m_pAllocator, &hr);
+ if(!m_pSubPicQueue || FAILED(hr))
+ {
+ _Error += L"m_pSubPicQueue failed\n";
+
+ return E_FAIL;
+ }
+
+ if(pSubPicProvider) m_pSubPicQueue->SetSubPicProvider(pSubPicProvider);
+
+ m_pFont = NULL;
+ if (m_pD3DXCreateFont)
+ {
+ int MinSize = 1600;
+ int CurrentSize = min(m_ScreenSize.cx, MinSize);
+ double Scale = double(CurrentSize) / double(MinSize);
+ m_TextScale = Scale;
+ m_pD3DXCreateFont( m_pD3DDev, // D3D device
+ -24.0*Scale, // Height
+ -11.0*Scale, // Width
+ CurrentSize < 800 ? FW_NORMAL : FW_BOLD, // Weight
+ 0, // MipLevels, 0 = autogen mipmaps
+ FALSE, // Italic
+ DEFAULT_CHARSET, // CharSet
+ OUT_DEFAULT_PRECIS, // OutputPrecision
+ ANTIALIASED_QUALITY, // Quality
+ FIXED_PITCH | FF_DONTCARE, // PitchAndFamily
+ L"Lucida Console", // pFaceName
+ &m_pFont); // ppFont
+ }
+
+
+ m_pSprite = NULL;
+
+ if (m_pD3DXCreateSprite)
+ {
+ m_pD3DXCreateSprite( m_pD3DDev, // D3D device
+ &m_pSprite);
+ }
+
+ m_pLine = NULL;
+ if (m_pD3DXCreateLine)
+ m_pD3DXCreateLine (m_pD3DDev, &m_pLine);
+
+ m_LastAdapterCheck = GetRenderersData()->GetPerfCounter();
+
+ StartWorkerThreads();
+
+ return S_OK;
+}
+
+HRESULT CDX9AllocatorPresenter::AllocSurfaces(D3DFORMAT Format)
+{
+ CAutoLock cAutoLock(this);
+ CAutoLock cRenderLock(&m_RenderLock);
+
+ CRenderersSettings& s = GetRenderersSettings();
+
+ for(int i = 0; i < m_nNbDXSurface+2; i++)
+ {
+ m_pVideoTexture[i] = NULL;
+ m_pVideoSurface[i] = NULL;
+ }
+
+ m_pScreenSizeTemporaryTexture[0] = NULL;
+ m_pScreenSizeTemporaryTexture[1] = NULL;
+
+ m_SurfaceType = Format;
+
+ HRESULT hr;
+
+ if(s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D || s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D)
+ {
+ int nTexturesNeeded = s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D ? m_nNbDXSurface+2 : 1;
+
+ for(int i = 0; i < nTexturesNeeded; i++)
+ {
+ if(FAILED(hr = m_pD3DDev->CreateTexture(
+ m_NativeVideoSize.cx, m_NativeVideoSize.cy, 1,
+ D3DUSAGE_RENDERTARGET, Format/*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 < m_nNbDXSurface+2; 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[m_nCurSurface], NULL)))
+ return hr;
+ }
+
+ hr = m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], NULL, 0);
+
+ return S_OK;
+}
+
+void CDX9AllocatorPresenter::DeleteSurfaces()
+{
+ CAutoLock cAutoLock(this);
+ CAutoLock cRenderLock(&m_RenderLock);
+
+ for(int i = 0; i < m_nNbDXSurface+2; i++)
+ {
+ m_pVideoTexture[i] = NULL;
+ m_pVideoSurface[i] = NULL;
+ }
+}
+
+UINT CDX9AllocatorPresenter::GetAdapter(IDirect3D9* pD3D, bool bCreateDevice)
+{
+ if(m_hWnd == NULL || pD3D == NULL)
+ return D3DADAPTER_DEFAULT;
+
+ CRenderersSettings& s = GetRenderersSettings();
+ if(bCreateDevice && (pD3D->GetAdapterCount()>1) && (s.D3D9RenderDevice != _T("")))
+ {
+ TCHAR strGUID[50];
+ D3DADAPTER_IDENTIFIER9 adapterIdentifier;
+ m_D3D9Device = _T("");
+
+ for(UINT adp = 0, num_adp = pD3D->GetAdapterCount(); adp < num_adp; ++adp)
+ {
+ if (pD3D->GetAdapterIdentifier(adp, 0, &adapterIdentifier) == S_OK)
+ {
+ if ((::StringFromGUID2(adapterIdentifier.DeviceIdentifier, strGUID, 50) > 0) && (s.D3D9RenderDevice == strGUID))
+ {
+ m_D3D9Device = adapterIdentifier.Description;
+ return adp;
+ }
+ }
+ }
+ }
+
+ 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)
+ {
+ if(bCreateDevice)
+ {
+ D3DADAPTER_IDENTIFIER9 adapterIdentifier;
+ if (pD3D->GetAdapterIdentifier(adp, 0, &adapterIdentifier) == S_OK)
+ m_D3D9Device = adapterIdentifier.Description;
+ }
+ 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, bool bNeedScreenSizeTexture)
+{
+ HRESULT hr;
+
+ do
+ {
+ if (bicubicA)
+ {
+ if (!m_pResizerPixelShader[0])
+ break;
+ if (!m_pResizerPixelShader[1])
+ break;
+ if (!m_pResizerPixelShader[2])
+ break;
+ if (!m_pResizerPixelShader[3])
+ break;
+ if (m_bicubicA != bicubicA)
+ break;
+ if (!m_pScreenSizeTemporaryTexture[0])
+ break;
+ if (bNeedScreenSizeTexture)
+ {
+ if (!m_pScreenSizeTemporaryTexture[1])
+ break;
+ }
+ }
+ else
+ {
+ if (!m_pResizerPixelShader[0])
+ break;
+ if (bNeedScreenSizeTexture)
+ {
+ if (!m_pScreenSizeTemporaryTexture[0])
+ break;
+ if (!m_pScreenSizeTemporaryTexture[1])
+ break;
+ }
+ }
+ return S_OK;
+ }
+ while (0);
+
+ m_bicubicA = bicubicA;
+ m_pScreenSizeTemporaryTexture[0] = NULL;
+ m_pScreenSizeTemporaryTexture[1] = 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_pass1", "main_bicubic2pass_pass2"};
+
+ ASSERT(countof(pEntries) == countof(m_pResizerPixelShader));
+
+ for(int i = 0; i < countof(pEntries); i++)
+ {
+ CString ErrorMessage;
+ CString DissAssembly;
+ hr = m_pPSC->CompileShader(str, pEntries[i], pProfile, 0, &m_pResizerPixelShader[i], &DissAssembly, &ErrorMessage);
+ if(FAILED(hr))
+ {
+ TRACE("%ws", ErrorMessage.GetString());
+ ASSERT (0);
+ return hr;
+ }
+ /*
+ if (i == 2 || i == 3)
+ {
+ const wchar_t *pStr = DissAssembly.GetString();
+ TRACE("DisAsm: %s\n", pEntries[i]);
+ const wchar_t *pStrStart = pStr;
+ while (*pStr)
+ {
+ while (*pStr && *pStr != '\n')
+ ++pStr;
+ if (*pStr == '\n')
+ ++pStr;
+ if (*pStr == '\r')
+ ++pStr;
+ CString Test(pStrStart, pStr - pStrStart);
+ TRACE("%ws", Test.GetString());
+ pStrStart = pStr;
+ }
+ }
+ */
+ }
+
+ if(m_bicubicA || bNeedScreenSizeTexture)
+ {
+ if(FAILED(m_pD3DDev->CreateTexture(
+ min(m_ScreenSize.cx, (int)m_caps.MaxTextureWidth), min(max(m_ScreenSize.cy, m_NativeVideoSize.cy), (int)m_caps.MaxTextureHeight), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
+ D3DPOOL_DEFAULT, &m_pScreenSizeTemporaryTexture[0], NULL)))
+ {
+ ASSERT(0);
+ m_pScreenSizeTemporaryTexture[0] = NULL; // will do 1 pass then
+ }
+ }
+ if(m_bicubicA || bNeedScreenSizeTexture)
+ {
+ if(FAILED(m_pD3DDev->CreateTexture(
+ min(m_ScreenSize.cx, (int)m_caps.MaxTextureWidth), min(max(m_ScreenSize.cy, m_NativeVideoSize.cy), (int)m_caps.MaxTextureHeight), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
+ D3DPOOL_DEFAULT, &m_pScreenSizeTemporaryTexture[1], NULL)))
+ {
+ ASSERT(0);
+ m_pScreenSizeTemporaryTexture[1] = NULL; // will do 1 pass then
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT CDX9AllocatorPresenter::TextureCopy(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::DrawRect(DWORD _Color, DWORD _Alpha, const CRect &_Rect)
+{
+ DWORD Color = D3DCOLOR_ARGB(_Alpha, GetRValue(_Color), GetGValue(_Color), GetBValue(_Color));
+ MYD3DVERTEX<0> v[] =
+ {
+ {float(_Rect.left), float(_Rect.top), 0.5f, 2.0f, Color},
+ {float(_Rect.right), float(_Rect.top), 0.5f, 2.0f, Color},
+ {float(_Rect.left), float(_Rect.bottom), 0.5f, 2.0f, Color},
+ {float(_Rect.right), float(_Rect.bottom), 0.5f, 2.0f, Color},
+ };
+
+ for(int i = 0; i < countof(v); i++)
+ {
+ v[i].x -= 0.5;
+ v[i].y -= 0.5;
+ }
+
+ return ::DrawRect(m_pD3DDev, v);
+}
+
+HRESULT CDX9AllocatorPresenter::TextureResize(IDirect3DTexture9* pTexture, Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect &SrcRect)
+{
+ 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;
+ float dx2 = 1.0/w;
+ float dy2 = 1.0/h;
+
+ MYD3DVERTEX<1> v[] =
+ {
+ {dst[0].x, dst[0].y, dst[0].z, 1.0f/dst[0].z, SrcRect.left * dx2, SrcRect.top * dy2},
+ {dst[1].x, dst[1].y, dst[1].z, 1.0f/dst[1].z, SrcRect.right * dx2, SrcRect.top * dy2},
+ {dst[2].x, dst[2].y, dst[2].z, 1.0f/dst[2].z, SrcRect.left * dx2, SrcRect.bottom * dy2},
+ {dst[3].x, dst[3].y, dst[3].z, 1.0f/dst[3].z, SrcRect.right * dx2, SrcRect.bottom * dy2},
+ };
+
+ AdjustQuad(v, 0, 0);
+
+ hr = m_pD3DDev->SetTexture(0, pTexture);
+
+ hr = m_pD3DDev->SetPixelShader(NULL);
+
+ hr = TextureBlt(m_pD3DDev, v, filter);
+
+ return hr;
+}
+
+HRESULT CDX9AllocatorPresenter::TextureResizeBilinear(IDirect3DTexture9* pTexture, Vector dst[4], const CRect &SrcRect)
+{
+ HRESULT hr;
+
+ D3DSURFACE_DESC desc;
+ if(!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc)))
+ return E_FAIL;
+
+ // make const to give compiler a chance of optimising, also float faster than double and converted to float to sent to PS anyway
+ const float dx = 1.0f/(float)desc.Width;
+ const float dy = 1.0f/(float)desc.Height;
+ const float tx0 = SrcRect.left;
+ const float tx1 = SrcRect.right;
+ const float ty0 = SrcRect.top;
+ const float ty1 = SrcRect.bottom;
+
+ MYD3DVERTEX<1> v[] =
+ {
+ {dst[0].x, dst[0].y, dst[0].z, 1.0f/dst[0].z, tx0, ty0},
+ {dst[1].x, dst[1].y, dst[1].z, 1.0f/dst[1].z, tx1, ty0},
+ {dst[2].x, dst[2].y, dst[2].z, 1.0f/dst[2].z, tx0, ty1},
+ {dst[3].x, dst[3].y, dst[3].z, 1.0f/dst[3].z, tx1, ty1},
+ };
+
+ AdjustQuad(v, 1.0, 1.0);
+
+ hr = m_pD3DDev->SetTexture(0, pTexture);
+
+ float fConstData[][4] = {{dx*0.5f, dy*0.5f, 0, 0}, {dx, dy, 0, 0}, {dx, 0, 0, 0}, {0, dy, 0, 0}};
+ hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, countof(fConstData));
+
+ hr = m_pD3DDev->SetTexture(0, pTexture);
+ hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[0]);
+
+ hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT);
+
+ //
+
+ m_pD3DDev->SetPixelShader(NULL);
+
+ return hr;
+}
+
+HRESULT CDX9AllocatorPresenter::TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, Vector dst[4], const CRect &SrcRect)
+{
+ HRESULT hr;
+
+ D3DSURFACE_DESC desc;
+ if(!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc)))
+ return E_FAIL;
+
+ // make const to give compiler a chance of optimising, also float faster than double and converted to float to sent to PS anyway
+ const float dx = 1.0f/(float)desc.Width;
+ const float dy = 1.0f/(float)desc.Height;
+ const float tx0 = SrcRect.left;
+ const float tx1 = SrcRect.right;
+ const float ty0 = SrcRect.top;
+ const float ty1 = SrcRect.bottom;
+
+ MYD3DVERTEX<1> v[] =
+ {
+ {dst[0].x, dst[0].y, dst[0].z, 1.0f/dst[0].z, tx0, ty0},
+ {dst[1].x, dst[1].y, dst[1].z, 1.0f/dst[1].z, tx1, ty0},
+ {dst[2].x, dst[2].y, dst[2].z, 1.0f/dst[2].z, tx0, ty1},
+ {dst[3].x, dst[3].y, dst[3].z, 1.0f/dst[3].z, tx1, ty1},
+ };
+
+ AdjustQuad(v, 1.0, 1.0);
+
+ hr = m_pD3DDev->SetTexture(0, pTexture);
+
+ float fConstData[][4] = {{dx*0.5f, dy*0.5f, 0, 0}, {dx, dy, 0, 0}, {dx, 0, 0, 0}, {0, dy, 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(IDirect3DTexture9* pTexture, Vector dst[4], const CRect &SrcRect)
+{
+ // The 2 pass sampler is incorrect in that it only does bilinear resampling in the y direction.
+ return TextureResizeBicubic1pass(pTexture, dst, SrcRect);
+
+ 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, SrcRect);
+
+ D3DSURFACE_DESC desc;
+ if(!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc)))
+ return E_FAIL;
+
+ float Tex0_Width = desc.Width;
+ float Tex0_Height = desc.Height;
+
+ double dx0 = 1.0/desc.Width;
+ double dy0 = 1.0/desc.Height;
+
+ CSize SrcTextSize = CSize(desc.Width, desc.Height);
+ double w = (double)SrcRect.Width();
+ double h = (double)SrcRect.Height();
+
+ CRect dst1(0, 0, (int)(dst[3].x - dst[0].x), (int)h);
+
+ if(!m_pScreenSizeTemporaryTexture[0] || FAILED(m_pScreenSizeTemporaryTexture[0]->GetLevelDesc(0, &desc)))
+ return TextureResizeBicubic1pass(pTexture, dst, SrcRect);
+
+ float Tex1_Width = desc.Width;
+ float Tex1_Height = desc.Height;
+
+ double dx1 = 1.0/desc.Width;
+ double dy1 = 1.0/desc.Height;
+
+ double dw = (double)dst1.Width() / desc.Width;
+ double dh = (double)dst1.Height() / desc.Height;
+
+ float dx2 = 1.0f/SrcTextSize.cx;
+ float dy2 = 1.0f/SrcTextSize.cy;
+ float tx0 = SrcRect.left;
+ float tx1 = SrcRect.right;
+ float ty0 = SrcRect.top;
+ float ty1 = SrcRect.bottom;
+
+ float tx0_2 = 0;
+ float tx1_2 = dst1.Width();
+ float ty0_2 = 0;
+ float ty1_2 = h;
+
+// ASSERT(dst1.Height() == desc.Height);
+
+ if(dst1.Width() > (int)desc.Width || dst1.Height() > (int)desc.Height)
+ // if(dst1.Width() != desc.Width || dst1.Height() != desc.Height)
+ return TextureResizeBicubic1pass(pTexture, dst, SrcRect);
+
+ MYD3DVERTEX<1> vx[] =
+ {
+ {(float)dst1.left, (float)dst1.top, 0.5f, 2.0f, tx0, ty0},
+ {(float)dst1.right, (float)dst1.top, 0.5f, 2.0f, tx1, ty0},
+ {(float)dst1.left, (float)dst1.bottom, 0.5f, 2.0f, tx0, ty1},
+ {(float)dst1.right, (float)dst1.bottom, 0.5f, 2.0f, tx1, ty1},
+ };
+
+ AdjustQuad(vx, 1.0, 0.0); // Casimir666 : bug ici, génére des bandes verticales! TODO : pourquoi ??????
+
+ MYD3DVERTEX<1> vy[] =
+ {
+ {dst[0].x, dst[0].y, dst[0].z, 1.0/dst[0].z, tx0_2, ty0_2},
+ {dst[1].x, dst[1].y, dst[1].z, 1.0/dst[1].z, tx1_2, ty0_2},
+ {dst[2].x, dst[2].y, dst[2].z, 1.0/dst[2].z, tx0_2, ty1_2},
+ {dst[3].x, dst[3].y, dst[3].z, 1.0/dst[3].z, tx1_2, ty1_2},
+ };
+
+
+ AdjustQuad(vy, 0.0, 1.0); // Casimir666 : bug ici, génére des bandes horizontales! TODO : pourquoi ??????
+
+ hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[2]);
+ {
+ float fConstData[][4] = {{0.5f / Tex0_Width, 0.5f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 1.0f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 0, 0, 0}, {0, 1.0f / Tex0_Height, 0, 0}, {Tex0_Width, Tex0_Height, 0, 0}};
+ hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, countof(fConstData));
+ }
+
+ hr = m_pD3DDev->SetTexture(0, pTexture);
+
+ CComPtr<IDirect3DSurface9> pRTOld;
+ hr = m_pD3DDev->GetRenderTarget(0, &pRTOld);
+
+ CComPtr<IDirect3DSurface9> pRT;
+ hr = m_pScreenSizeTemporaryTexture[0]->GetSurfaceLevel(0, &pRT);
+ hr = m_pD3DDev->SetRenderTarget(0, pRT);
+
+ hr = TextureBlt(m_pD3DDev, vx, D3DTEXF_POINT);
+
+ hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[3]);
+ {
+ float fConstData[][4] = {{0.5f / Tex1_Width, 0.5f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 1.0f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 0, 0, 0}, {0, 1.0f / Tex1_Height, 0, 0}, {Tex1_Width, Tex1_Height, 0, 0}};
+ hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, countof(fConstData));
+ }
+
+ hr = m_pD3DDev->SetTexture(0, m_pScreenSizeTemporaryTexture[0]);
+
+ hr = m_pD3DDev->SetRenderTarget(0, pRTOld);
+
+ hr = TextureBlt(m_pD3DDev, vy, D3DTEXF_POINT);
+
+ m_pD3DDev->SetPixelShader(NULL);
+
+ return hr;
+}
+
+HRESULT CDX9AllocatorPresenter::AlphaBlt(RECT* pSrc, RECT* pDst, IDirect3DTexture9* pTexture)
+{
+ if(!pSrc || !pDst)
+ return E_POINTER;
+
+ CRect src(*pSrc), dst(*pDst);
+
+ HRESULT hr;
+
+ do
+ {
+ D3DSURFACE_DESC d3dsd;
+ ZeroMemory(&d3dsd, sizeof(d3dsd));
+ if(FAILED(pTexture->GetLevelDesc(0, &d3dsd)) /*|| d3dsd.Type != D3DRTYPE_TEXTURE*/)
+ break;
+
+ float w = (float)d3dsd.Width;
+ float h = (float)d3dsd.Height;
+
+ struct
+ {
+ float x, y, z, rhw;
+ float tu, tv;
+ }
+ pVertices[] =
+ {
+ {(float)dst.left, (float)dst.top, 0.5f, 2.0f, (float)src.left / w, (float)src.top / h},
+ {(float)dst.right, (float)dst.top, 0.5f, 2.0f, (float)src.right / w, (float)src.top / h},
+ {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, (float)src.left / w, (float)src.bottom / h},
+ {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, (float)src.right / w, (float)src.bottom / h},
+ };
+ /*
+ for(int i = 0; i < countof(pVertices); i++)
+ {
+ pVertices[i].x -= 0.5;
+ pVertices[i].y -= 0.5;
+ }
+ */
+
+ hr = m_pD3DDev->SetTexture(0, pTexture);
+
+ DWORD abe, sb, db;
+ hr = m_pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe);
+ hr = m_pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb);
+ hr = m_pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db);
+
+ hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE);
+ hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE);
+ hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+ hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ...
+ hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst
+
+ hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
+
+ hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+ hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+ hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
+
+ hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+ hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+
+ /*//
+
+ D3DCAPS9 d3dcaps9;
+ hr = m_pD3DDev->GetDeviceCaps(&d3dcaps9);
+ if(d3dcaps9.AlphaCmpCaps & D3DPCMPCAPS_LESS)
+ {
+ hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x000000FE);
+ hr = m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
+ hr = m_pD3DDev->SetRenderState(D3DRS_ALPHAFUNC, D3DPCMPCAPS_LESS);
+ }
+
+ *///
+
+ hr = m_pD3DDev->SetPixelShader(NULL);
+
+ hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
+ hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0]));
+
+ //
+
+ m_pD3DDev->SetTexture(0, NULL);
+
+ m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe);
+ m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb);
+ m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, db);
+
+ return S_OK;
+ }
+ while(0);
+
+ return E_FAIL;
+}
+
+void CDX9AllocatorPresenter::CalculateJitter(LONGLONG PerfCounter)
+{
+ // Calculate the jitter!
+ LONGLONG llPerf = PerfCounter;
+ if ((m_rtTimePerFrame != 0) && (labs ((long)(llPerf - m_llLastPerf)) < m_rtTimePerFrame*3) )
+ {
+ m_nNextJitter = (m_nNextJitter+1) % NB_JITTER;
+ m_pllJitter[m_nNextJitter] = llPerf - m_llLastPerf;
+
+ m_MaxJitter = MINLONG64;
+ m_MinJitter = MAXLONG64;
+
+ // Calculate the real FPS
+ LONGLONG llJitterSum = 0;
+ LONGLONG llJitterSumAvg = 0;
+ for (int i=0; i<NB_JITTER; i++)
+ {
+ LONGLONG Jitter = m_pllJitter[i];
+ llJitterSum += Jitter;
+ llJitterSumAvg += Jitter;
+ }
+ double FrameTimeMean = double(llJitterSumAvg)/NB_JITTER;
+ m_fJitterMean = FrameTimeMean;
+ double DeviationSum = 0;
+ for (int i=0; i<NB_JITTER; i++)
+ {
+ LONGLONG DevInt = m_pllJitter[i] - FrameTimeMean;
+ double Deviation = DevInt;
+ DeviationSum += Deviation*Deviation;
+ m_MaxJitter = max(m_MaxJitter, DevInt);
+ m_MinJitter = min(m_MinJitter, DevInt);
+ }
+ double StdDev = sqrt(DeviationSum/NB_JITTER);
+
+ m_fJitterStdDev = StdDev;
+
+ m_fAvrFps = 10000000.0/(double(llJitterSum)/NB_JITTER);
+ }
+
+ m_llLastPerf = llPerf;
+}
+
+bool CDX9AllocatorPresenter::GetVBlank(int &_ScanLine, int &_bInVBlank, bool _bMeasureTime)
+{
+ LONGLONG llPerf;
+ if (_bMeasureTime)
+ llPerf = GetRenderersData()->GetPerfCounter();
+
+ int ScanLine = 0;
+ _ScanLine = 0;
+ _bInVBlank = 0;
+ if (m_pDirectDraw)
+ {
+ DWORD ScanLineGet = 0;
+ m_pDirectDraw->GetScanLine(&ScanLineGet);
+ BOOL InVBlank;
+ if (m_pDirectDraw->GetVerticalBlankStatus (&InVBlank) != S_OK)
+ return false;
+ ScanLine = ScanLineGet;
+ _bInVBlank = InVBlank;
+ if (InVBlank)
+ ScanLine = 0;
+ }
+ else
+ {
+ D3DRASTER_STATUS RasterStatus;
+ if (m_pD3DDev->GetRasterStatus(0, &RasterStatus) != S_OK)
+ return false;
+ ScanLine = RasterStatus.ScanLine;
+ _bInVBlank = RasterStatus.InVBlank;
+ }
+ if (_bMeasureTime)
+ {
+ m_VBlankMax = max(m_VBlankMax, ScanLine);
+ if (ScanLine != 0 && !_bInVBlank)
+ m_VBlankMinCalc = min(m_VBlankMinCalc, ScanLine);
+ m_VBlankMin = m_VBlankMax - m_ScreenSize.cy;
+ }
+ if (_bInVBlank)
+ _ScanLine = 0;
+ else if (m_VBlankMin != 300000)
+ _ScanLine = ScanLine - m_VBlankMin;
+ else
+ _ScanLine = ScanLine;
+
+ if (_bMeasureTime)
+ {
+ LONGLONG Time = GetRenderersData()->GetPerfCounter() - llPerf;
+ m_RasterStatusWaitTimeMaxCalc = max(m_RasterStatusWaitTimeMaxCalc, Time);
+ }
+
+ return true;
+}
+
+bool CDX9AllocatorPresenter::WaitForVBlankRange(int &_RasterStart, int _RasterSize, bool _bWaitIfInside, bool _bNeedAccurate, bool _bMeasure, bool &_bTakenLock)
+{
+ if (_bMeasure)
+ m_RasterStatusWaitTimeMaxCalc = 0;
+ bool bWaited = false;
+ int ScanLine = 0;
+ int InVBlank = 0;
+ LONGLONG llPerf;
+ if (_bMeasure)
+ llPerf = GetRenderersData()->GetPerfCounter();
+ GetVBlank(ScanLine, InVBlank, _bMeasure);
+ if (_bMeasure)
+ m_VBlankStartWait = ScanLine;
+
+ static bool bOneWait = true;
+ if (bOneWait && _bMeasure)
+ {
+ bOneWait = false;
+ // If we are already in the wanted interval we need to wait until we aren't, this improves sync when for example you are playing 23.976 Hz material on a 24 Hz refresh rate
+ int nInVBlank = 0;
+ while (1)
+ {
+ if (!GetVBlank(ScanLine, InVBlank, _bMeasure))
+ break;
+
+ if (InVBlank && nInVBlank == 0)
+ {
+ nInVBlank = 1;
+ }
+ else if (!InVBlank && nInVBlank == 1)
+ {
+ nInVBlank = 2;
+ }
+ else if (InVBlank && nInVBlank == 2)
+ {
+ nInVBlank = 3;
+ }
+ else if (!InVBlank && nInVBlank == 3)
+ {
+ break;
+ }
+ }
+ }
+ if (_bWaitIfInside)
+ {
+ int ScanLineDiff = long(ScanLine) - _RasterStart;
+ if (ScanLineDiff > m_ScreenSize.cy / 2)
+ ScanLineDiff -= m_ScreenSize.cy;
+ else if (ScanLineDiff < -m_ScreenSize.cy / 2)
+ ScanLineDiff += m_ScreenSize.cy;
+
+ if (ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize)
+ {
+ bWaited = true;
+ // If we are already in the wanted interval we need to wait until we aren't, this improves sync when for example you are playing 23.976 Hz material on a 24 Hz refresh rate
+ int LastLineDiff = ScanLineDiff;
+ while (1)
+ {
+ if (!GetVBlank(ScanLine, InVBlank, _bMeasure))
+ break;
+ int ScanLineDiff = long(ScanLine) - _RasterStart;
+ if (ScanLineDiff > m_ScreenSize.cy / 2)
+ ScanLineDiff -= m_ScreenSize.cy;
+ else if (ScanLineDiff < -m_ScreenSize.cy / 2)
+ ScanLineDiff += m_ScreenSize.cy;
+ if (!(ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize) || (LastLineDiff < 0 && ScanLineDiff > 0))
+ break;
+ LastLineDiff = ScanLineDiff;
+ Sleep(1); // Just sleep
+ }
+ }
+ }
+ double RefreshRate = GetRefreshRate();
+ LONG ScanLines = GetScanLines();
+ int MinRange = max(min(int(0.0015 * double(ScanLines) * RefreshRate + 0.5), ScanLines/3), 5); // 1.5 ms or max 33 % of Time
+ int NoSleepStart = _RasterStart - MinRange;
+ int NoSleepRange = MinRange;
+ if (NoSleepStart < 0)
+ NoSleepStart += m_ScreenSize.cy;
+
+ int MinRange2 = max(min(int(0.0050 * double(ScanLines) * RefreshRate + 0.5), ScanLines/3), 5); // 5 ms or max 33 % of Time
+ int D3DDevLockStart = _RasterStart - MinRange2;
+ int D3DDevLockRange = MinRange2;
+ if (D3DDevLockStart < 0)
+ D3DDevLockStart += m_ScreenSize.cy;
+
+ int ScanLineDiff = ScanLine - _RasterStart;
+ if (ScanLineDiff > m_ScreenSize.cy / 2)
+ ScanLineDiff -= m_ScreenSize.cy;
+ else if (ScanLineDiff < -m_ScreenSize.cy / 2)
+ ScanLineDiff += m_ScreenSize.cy;
+ int LastLineDiff = ScanLineDiff;
+
+
+ int ScanLineDiffSleep = long(ScanLine) - NoSleepStart;
+ if (ScanLineDiffSleep > m_ScreenSize.cy / 2)
+ ScanLineDiffSleep -= m_ScreenSize.cy;
+ else if (ScanLineDiffSleep < -m_ScreenSize.cy / 2)
+ ScanLineDiffSleep += m_ScreenSize.cy;
+ int LastLineDiffSleep = ScanLineDiffSleep;
+
+
+ int ScanLineDiffLock = long(ScanLine) - D3DDevLockStart;
+ if (ScanLineDiffLock > m_ScreenSize.cy / 2)
+ ScanLineDiffLock -= m_ScreenSize.cy;
+ else if (ScanLineDiffLock < -m_ScreenSize.cy / 2)
+ ScanLineDiffLock += m_ScreenSize.cy;
+ int LastLineDiffLock = ScanLineDiffLock;
+
+ LONGLONG llPerfLock;
+
+ while (1)
+ {
+ if (!GetVBlank(ScanLine, InVBlank, _bMeasure))
+ break;
+ int ScanLineDiff = long(ScanLine) - _RasterStart;
+ if (ScanLineDiff > m_ScreenSize.cy / 2)
+ ScanLineDiff -= m_ScreenSize.cy;
+ else if (ScanLineDiff < -m_ScreenSize.cy / 2)
+ ScanLineDiff += m_ScreenSize.cy;
+ if ((ScanLineDiff >= 0 && ScanLineDiff <= _RasterSize) || (LastLineDiff < 0 && ScanLineDiff > 0))
+ break;
+
+ LastLineDiff = ScanLineDiff;
+
+ bWaited = true;
+
+ int ScanLineDiffLock = long(ScanLine) - D3DDevLockStart;
+ if (ScanLineDiffLock > m_ScreenSize.cy / 2)
+ ScanLineDiffLock -= m_ScreenSize.cy;
+ else if (ScanLineDiffLock < -m_ScreenSize.cy / 2)
+ ScanLineDiffLock += m_ScreenSize.cy;
+
+ if (((ScanLineDiffLock >= 0 && ScanLineDiffLock <= D3DDevLockRange) || (LastLineDiffLock < 0 && ScanLineDiffLock > 0)))
+ {
+ if (!_bTakenLock && _bMeasure)
+ {
+ _bTakenLock = true;
+ llPerfLock = GetRenderersData()->GetPerfCounter();
+ LockD3DDevice();
+ }
+ }
+ LastLineDiffLock = ScanLineDiffLock;
+
+
+ int ScanLineDiffSleep = long(ScanLine) - NoSleepStart;
+ if (ScanLineDiffSleep > m_ScreenSize.cy / 2)
+ ScanLineDiffSleep -= m_ScreenSize.cy;
+ else if (ScanLineDiffSleep < -m_ScreenSize.cy / 2)
+ ScanLineDiffSleep += m_ScreenSize.cy;
+
+ if (!((ScanLineDiffSleep >= 0 && ScanLineDiffSleep <= NoSleepRange) || (LastLineDiffSleep < 0 && ScanLineDiffSleep > 0)) || !_bNeedAccurate)
+ {
+ //TRACE("%d\n", RasterStatus.ScanLine);
+ Sleep(1); // Don't sleep for the last 1.5 ms scan lines, so we get maximum precision
+ }
+ LastLineDiffSleep = ScanLineDiffSleep;
+ }
+ _RasterStart = ScanLine;
+ if (_bMeasure)
+ {
+ m_VBlankEndWait = ScanLine;
+ m_VBlankWaitTime = GetRenderersData()->GetPerfCounter() - llPerf;
+
+ if (_bTakenLock)
+ {
+ m_VBlankLockTime = GetRenderersData()->GetPerfCounter() - llPerfLock;
+ }
+ else
+ m_VBlankLockTime = 0;
+
+ m_RasterStatusWaitTime = m_RasterStatusWaitTimeMaxCalc;
+ m_RasterStatusWaitTimeMin = min(m_RasterStatusWaitTimeMin, m_RasterStatusWaitTime);
+ m_RasterStatusWaitTimeMax = max(m_RasterStatusWaitTimeMax, m_RasterStatusWaitTime);
+ }
+
+ return bWaited;
+}
+
+int CDX9AllocatorPresenter::GetVBlackPos()
+{
+ CRenderersSettings& s = GetRenderersSettings();
+ BOOL bCompositionEnabled = m_bCompositionEnabled;
+
+ int WaitRange = max(m_ScreenSize.cy / 40, 5);
+ if (!bCompositionEnabled)
+ {
+ if (m_bAlternativeVSync)
+ {
+ return s.m_RenderSettings.iVMR9VSyncOffset;
+ }
+ else
+ {
+ int MinRange = max(min(int(0.005 * double(m_ScreenSize.cy) * GetRefreshRate() + 0.5), m_ScreenSize.cy/3), 5); // 5 ms or max 33 % of Time
+ int WaitFor = m_ScreenSize.cy - (MinRange + WaitRange);
+ return WaitFor;
+ }
+ }
+ else
+ {
+ int WaitFor = m_ScreenSize.cy / 2;
+ return WaitFor;
+ }
+}
+
+
+bool CDX9AllocatorPresenter::WaitForVBlank(bool &_Waited, bool &_bTakenLock)
+{
+ CRenderersSettings& s = GetRenderersSettings();
+ if (!s.m_RenderSettings.iVMR9VSync)
+ {
+ _Waited = true;
+ m_VBlankWaitTime = 0;
+ m_VBlankLockTime = 0;
+ m_VBlankEndWait = 0;
+ m_VBlankStartWait = 0;
+ return true;
+ }
+// _Waited = true;
+// return false;
+
+ BOOL bCompositionEnabled = m_bCompositionEnabled;
+ int WaitFor = GetVBlackPos();
+
+ if (!bCompositionEnabled)
+ {
+ if (m_bAlternativeVSync)
+ {
+ _Waited = WaitForVBlankRange(WaitFor, 0, false, true, true, _bTakenLock);
+ return false;
+ }
+ else
+ {
+ _Waited = WaitForVBlankRange(WaitFor, 0, false, s.m_RenderSettings.iVMR9VSyncAccurate, true, _bTakenLock);
+ return true;
+ }
+ }
+ else
+ {
+ // Instead we wait for VBlack after the present, this seems to fix the stuttering problem. It's also possible to fix by removing the Sleep above, but that isn't an option.
+ WaitForVBlankRange(WaitFor, 0, false, s.m_RenderSettings.iVMR9VSyncAccurate, true, _bTakenLock);
+
+ return false;
+ }
+}
+
+void CDX9AllocatorPresenter::UpdateAlphaBitmap()
+{
+ m_VMR9AlphaBitmapData.Free();
+
+ if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0)
+ {
+ HBITMAP hBitmap = (HBITMAP)GetCurrentObject (m_VMR9AlphaBitmap.hdc, OBJ_BITMAP);
+ if (!hBitmap)
+ return;
+ DIBSECTION info = {0};
+ if (!::GetObject(hBitmap, sizeof( DIBSECTION ), &info ))
+ return;
+
+ m_VMR9AlphaBitmapRect = CRect(0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight);
+ m_VMR9AlphaBitmapWidthBytes = info.dsBm.bmWidthBytes;
+
+ if (m_VMR9AlphaBitmapData.Allocate(info.dsBm.bmWidthBytes * info.dsBm.bmHeight))
+ {
+ memcpy((BYTE *)m_VMR9AlphaBitmapData, info.dsBm.bmBits, info.dsBm.bmWidthBytes * info.dsBm.bmHeight);
+ }
+ }
+}
+
+STDMETHODIMP_(bool) CDX9AllocatorPresenter::Paint(bool fAll)
+{
+ if (m_bPendingResetDevice)
+ {
+ SendResetRequest();
+ return false;
+ }
+
+ CRenderersSettings& s = GetRenderersSettings();
+
+// TRACE("Thread: %d\n", (LONG)((CRITICAL_SECTION &)m_RenderLock).OwningThread);
+
+#if 0
+ if (TryEnterCriticalSection (&(CRITICAL_SECTION &)(*((CCritSec *)this))))
+ {
+ LeaveCriticalSection((&(CRITICAL_SECTION &)(*((CCritSec *)this))));
+ }
+ else
+ {
+ __debugbreak();
+ }
+#endif
+
+ CRenderersData * pApp = GetRenderersData();
+
+ LONGLONG StartPaint = pApp->GetPerfCounter();
+ CAutoLock cRenderLock(&m_RenderLock);
+
+ if(m_WindowRect.right <= m_WindowRect.left || m_WindowRect.bottom <= m_WindowRect.top
+ || m_NativeVideoSize.cx <= 0 || m_NativeVideoSize.cy <= 0
+ || !m_pVideoSurface)
+ {
+ if (m_OrderedPaint)
+ --m_OrderedPaint;
+ else
+ {
+// TRACE("UNORDERED PAINT!!!!!!\n");
+ }
+
+
+ return(false);
+ }
+
+ HRESULT hr;
+
+ CRect rSrcVid(CPoint(0, 0), GetVisibleVideoSize());
+ CRect rDstVid(m_VideoRect);
+
+ CRect rSrcPri(CPoint(0, 0), m_WindowRect.Size());
+ CRect rDstPri(m_WindowRect);
+
+ m_pD3DDev->BeginScene();
+
+ 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[m_nCurSurface])
+ {
+ CComPtr<IDirect3DTexture9> pVideoTexture = m_pVideoTexture[m_nCurSurface];
+
+ if(m_pVideoTexture[m_nNbDXSurface] && m_pVideoTexture[m_nNbDXSurface+1] && !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)
+
+ int src = m_nCurSurface, dst = m_nNbDXSurface;
+
+#if 1
+ D3DSURFACE_DESC desc;
+ m_pVideoTexture[src]->GetLevelDesc(0, &desc);
+
+ float fConstData[][4] =
+ {
+ {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC},
+ {1.0f / desc.Width, 1.0f / desc.Height, 0, 0},
+ };
+#else
+ CSize VideoSize = GetVisibleVideoSize();
+
+ float fConstData[][4] =
+ {
+ {(float)VideoSize.cx, (float)VideoSize.cy, (float)(counter++), (float)diff / CLOCKS_PER_SEC},
+ {1.0f / VideoSize.cx, 1.0f / VideoSize.cy, 0, 0},
+ };
+#endif
+
+ hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, countof(fConstData));
+
+ CComPtr<IDirect3DSurface9> pRT;
+ hr = m_pD3DDev->GetRenderTarget(0, &pRT);
+
+ POSITION pos = m_pPixelShaders.GetHeadPosition();
+ while(pos)
+ {
+ pVideoTexture = m_pVideoTexture[dst];
+
+ hr = m_pD3DDev->SetRenderTarget(0, m_pVideoSurface[dst]);
+ CExternalPixelShader &Shader = m_pPixelShaders.GetNext(pos);
+ if (!Shader.m_pPixelShader)
+ Shader.Compile(m_pPSC);
+ hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader);
+ TextureCopy(m_pVideoTexture[src]);
+
+ //if(++src > 2) src = 1;
+ //if(++dst > 2) dst = 1;
+ src = dst;
+ if(++dst >= m_nNbDXSurface+2) dst = m_nNbDXSurface;
+ }
+
+ hr = m_pD3DDev->SetRenderTarget(0, pRT);
+ hr = m_pD3DDev->SetPixelShader(NULL);
+ }
+
+ Vector dst[4];
+ Transform(rDstVid, dst);
+
+ DWORD iDX9Resizer = s.iDX9Resizer;
+
+ float A = 0;
+
+ switch(iDX9Resizer)
+ {
+ case 3:
+ A = -0.60f;
+ break;
+ case 4:
+ A = -0.751f;
+ break; // FIXME : 0.75 crash recent D3D, or eat CPU
+ case 5:
+ A = -1.00f;
+ break;
+ }
+ bool bScreenSpacePixelShaders = !m_pPixelShadersScreenSpace.IsEmpty();
+
+ hr = InitResizers(A, bScreenSpacePixelShaders);
+
+ if (!m_pScreenSizeTemporaryTexture[0] || !m_pScreenSizeTemporaryTexture[1])
+ bScreenSpacePixelShaders = false;
+
+ if (bScreenSpacePixelShaders)
+ {
+ CComPtr<IDirect3DSurface9> pRT;
+ hr = m_pScreenSizeTemporaryTexture[1]->GetSurfaceLevel(0, &pRT);
+ if (hr != S_OK)
+ bScreenSpacePixelShaders = false;
+ if (bScreenSpacePixelShaders)
+ {
+ hr = m_pD3DDev->SetRenderTarget(0, pRT);
+ if (hr != S_OK)
+ bScreenSpacePixelShaders = false;
+ hr = m_pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0);
+ }
+ }
+
+ if(rSrcVid.Size() != rDstVid.Size())
+ {
+// if((iDX9Resizer == 0 || iDX9Resizer == 1 || rSrcVid.Size() == rDstVid.Size() || FAILED(hr)))
+ if(iDX9Resizer == 0 || iDX9Resizer == 1)
+ {
+ D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR;
+ hr = TextureResize(pVideoTexture, dst, Filter, rSrcVid);
+ }
+ else if(iDX9Resizer == 2)
+ {
+ hr = TextureResizeBilinear(pVideoTexture, dst, rSrcVid);
+ }
+ else if(iDX9Resizer >= 3)
+ {
+ hr = TextureResizeBicubic2pass(pVideoTexture, dst, rSrcVid);
+ }
+ }
+ else hr = TextureResize(pVideoTexture, dst, D3DTEXF_POINT, rSrcVid);
+
+ if (bScreenSpacePixelShaders)
+ {
+ static __int64 counter = 555;
+ static long start = clock() + 333;
+
+ long stop = clock() + 333;
+ 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)
+
+ D3DSURFACE_DESC desc;
+ m_pScreenSizeTemporaryTexture[0]->GetLevelDesc(0, &desc);
+
+#if 1
+ float fConstData[][4] =
+ {
+ {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC},
+ {1.0f / desc.Width, 1.0f / desc.Height, 0, 0},
+ };
+#else
+ float fConstData[][4] =
+ {
+ {(float)m_ScreenSize.cx, (float)m_ScreenSize.cy, (float)(counter++), (float)diff / CLOCKS_PER_SEC},
+ {1.0f / m_ScreenSize.cx, 1.0f / m_ScreenSize.cy, 0, 0},
+ };
+#endif
+
+ hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, countof(fConstData));
+
+ int src = 1, dst = 0;
+
+ POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition();
+ while(pos)
+ {
+ if (m_pPixelShadersScreenSpace.GetTailPosition() == pos)
+ {
+ m_pD3DDev->SetRenderTarget(0, pBackBuffer);
+ }
+ else
+ {
+ CComPtr<IDirect3DSurface9> pRT;
+ hr = m_pScreenSizeTemporaryTexture[dst]->GetSurfaceLevel(0, &pRT);
+ m_pD3DDev->SetRenderTarget(0, pRT);
+ }
+
+ CExternalPixelShader &Shader = m_pPixelShadersScreenSpace.GetNext(pos);
+ if (!Shader.m_pPixelShader)
+ Shader.Compile(m_pPSC);
+ hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader);
+ TextureCopy(m_pScreenSizeTemporaryTexture[src]);
+
+ swap(src, dst);
+ }
+
+ hr = m_pD3DDev->SetPixelShader(NULL);
+ }
+ }
+ 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[m_nCurSurface], rSrcVid, pBackBuffer, rDstVid, m_filter);
+
+ // Support ffdshow queueing
+ // m_pD3DDev->StretchRect may fail if ffdshow is using queue output samples.
+ // Here we don't want to show the black buffer.
+ if(FAILED(hr))
+ {
+ if (m_OrderedPaint)
+ --m_OrderedPaint;
+ else
+ {
+// TRACE("UNORDERED PAINT!!!!!!\n");
+ }
+
+ return false;
+ }
+ }
+ }
+ }
+
+ // paint the text on the backbuffer
+
+ AlphaBltSubPic(rSrcPri.Size());
+ }
+
+
+ // Casimir666 : affichage de l'OSD
+ if (m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_UPDATE)
+ {
+ CAutoLock BitMapLock(&m_VMR9AlphaBitmapLock);
+ CRect rcSrc (m_VMR9AlphaBitmap.rSrc);
+ m_pOSDTexture = NULL;
+ m_pOSDSurface = NULL;
+ if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0 && (BYTE *)m_VMR9AlphaBitmapData)
+ {
+ if( (m_pD3DXLoadSurfaceFromMemory != NULL) &&
+ SUCCEEDED(hr = m_pD3DDev->CreateTexture(rcSrc.Width(), rcSrc.Height(), 1,
+ D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
+ D3DPOOL_DEFAULT, &m_pOSDTexture, NULL)) )
+ {
+ if (SUCCEEDED (hr = m_pOSDTexture->GetSurfaceLevel(0, &m_pOSDSurface)))
+ {
+ hr = m_pD3DXLoadSurfaceFromMemory (m_pOSDSurface,
+ NULL,
+ NULL,
+ (BYTE *)m_VMR9AlphaBitmapData,
+ D3DFMT_A8R8G8B8,
+ m_VMR9AlphaBitmapWidthBytes,
+ NULL,
+ &m_VMR9AlphaBitmapRect,
+ D3DX_FILTER_NONE,
+ m_VMR9AlphaBitmap.clrSrcKey);
+ }
+ if (FAILED (hr))
+ {
+ m_pOSDTexture = NULL;
+ m_pOSDSurface = NULL;
+ }
+ }
+ }
+ m_VMR9AlphaBitmap.dwFlags ^= VMRBITMAP_UPDATE;
+
+ }
+
+ if (pApp->m_fDisplayStats)
+ DrawStats();
+
+ {
+ CString Temp;
+ Temp.Format(L"GPU %7.3f ms", (double(m_WaitForGPUTime)/10000.0));
+
+// TRACE("%ws\n", Temp.GetString());
+ }
+
+ if (m_pOSDTexture) AlphaBlt(rSrcPri, rDstPri, m_pOSDTexture);
+
+ m_pD3DDev->EndScene();
+
+ BOOL bCompositionEnabled = m_bCompositionEnabled;
+
+ bool bDoVSyncInPresent = (!bCompositionEnabled && !m_bAlternativeVSync) || !s.m_RenderSettings.iVMR9VSync;
+
+ LONGLONG PresentWaitTime = 0;
+ /* if(fAll && m_fVMRSyncFix && bDoVSyncInPresent)
+ {
+ LONGLONG llPerf = pApp->GetPerfCounter();
+ D3DLOCKED_RECT lr;
+ if(SUCCEEDED(pBackBuffer->LockRect(&lr, NULL, 0)))
+ pBackBuffer->UnlockRect();
+ PresentWaitTime = pApp->GetPerfCounter() - llPerf;
+ }*/
+
+ CComPtr<IDirect3DQuery9> pEventQuery;
+
+ m_pD3DDev->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);
+ if (pEventQuery)
+ pEventQuery->Issue(D3DISSUE_END);
+
+ if (s.m_RenderSettings.iVMRFlushGPUBeforeVSync && pEventQuery)
+ {
+ LONGLONG llPerf = pApp->GetPerfCounter();
+ BOOL Data;
+ //Sleep(5);
+ LONGLONG FlushStartTime = pApp->GetPerfCounter();
+ while(S_FALSE == pEventQuery->GetData( &Data, sizeof(Data), D3DGETDATA_FLUSH ))
+ {
+ if (!s.m_RenderSettings.iVMRFlushGPUWait)
+ break;
+ Sleep(1);
+ if (pApp->GetPerfCounter() - FlushStartTime > 500000)
+ break; // timeout after 50 ms
+ }
+ if (s.m_RenderSettings.iVMRFlushGPUWait)
+ m_WaitForGPUTime = pApp->GetPerfCounter() - llPerf;
+ else
+ m_WaitForGPUTime = 0;
+ }
+ else
+ m_WaitForGPUTime = 0;
+
+ if (fAll)
+ {
+ m_PaintTime = (GetRenderersData()->GetPerfCounter() - StartPaint);
+ m_PaintTimeMin = min(m_PaintTimeMin, m_PaintTime);
+ m_PaintTimeMax = max(m_PaintTimeMax, m_PaintTime);
+ }
+
+ bool bWaited = false;
+ bool bTakenLock = false;
+ if (fAll)
+ {
+ // Only sync to refresh when redrawing all
+ bool bTest = WaitForVBlank(bWaited, bTakenLock);
+ ASSERT(bTest == bDoVSyncInPresent);
+ if (!bDoVSyncInPresent)
+ {
+ LONGLONG Time = pApp->GetPerfCounter();
+ OnVBlankFinished(fAll, Time);
+ if (!m_bIsEVR || m_OrderedPaint)
+ CalculateJitter(Time);
+ }
+ }
+
+ // Create a device pointer m_pd3dDevice
+
+ // Create a query object
+ {
+ CComPtr<IDirect3DQuery9> pEventQuery;
+ m_pD3DDev->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);
+
+ LONGLONG llPerf = pApp->GetPerfCounter();
+ if (m_pD3DDevEx)
+ {
+ if (m_bIsFullscreen)
+ hr = m_pD3DDevEx->PresentEx(NULL, NULL, NULL, NULL, NULL);
+ else
+ hr = m_pD3DDevEx->PresentEx(rSrcPri, rDstPri, NULL, NULL, NULL);
+ }
+ else
+ {
+ if (m_bIsFullscreen)
+ hr = m_pD3DDev->Present(NULL, NULL, NULL, NULL);
+ else
+ hr = m_pD3DDev->Present(rSrcPri, rDstPri, NULL, NULL);
+ }
+ // Issue an End event
+ if (pEventQuery)
+ pEventQuery->Issue(D3DISSUE_END);
+
+ BOOL Data;
+
+ if (s.m_RenderSettings.iVMRFlushGPUAfterPresent && pEventQuery)
+ {
+ LONGLONG FlushStartTime = pApp->GetPerfCounter();
+ while (S_FALSE == pEventQuery->GetData( &Data, sizeof(Data), D3DGETDATA_FLUSH ))
+ {
+ if (!s.m_RenderSettings.iVMRFlushGPUWait)
+ break;
+ if (pApp->GetPerfCounter() - FlushStartTime > 500000)
+ break; // timeout after 50 ms
+ }
+ }
+
+ int ScanLine;
+ int bInVBlank;
+ GetVBlank(ScanLine, bInVBlank, false);
+
+ if (fAll && (!m_bIsEVR || m_OrderedPaint))
+ {
+ m_VBlankEndPresent = ScanLine;
+ }
+
+ while (ScanLine == 0 || bInVBlank)
+ {
+ GetVBlank(ScanLine, bInVBlank, false);
+
+ }
+ m_VBlankStartMeasureTime = pApp->GetPerfCounter();
+ m_VBlankStartMeasure = ScanLine;
+
+ if (fAll && bDoVSyncInPresent)
+ {
+ m_PresentWaitTime = (pApp->GetPerfCounter() - llPerf) + PresentWaitTime;
+ m_PresentWaitTimeMin = min(m_PresentWaitTimeMin, m_PresentWaitTime);
+ m_PresentWaitTimeMax = max(m_PresentWaitTimeMax, m_PresentWaitTime);
+ }
+ else
+ {
+ m_PresentWaitTime = 0;
+ m_PresentWaitTimeMin = min(m_PresentWaitTimeMin, m_PresentWaitTime);
+ m_PresentWaitTimeMax = max(m_PresentWaitTimeMax, m_PresentWaitTime);
+ }
+ }
+
+ if (bDoVSyncInPresent)
+ {
+ LONGLONG Time = pApp->GetPerfCounter();
+ if (!m_bIsEVR || m_OrderedPaint)
+ CalculateJitter(Time);
+ OnVBlankFinished(fAll, Time);
+ }
+
+ if (bTakenLock)
+ UnlockD3DDevice();
+
+ /*if (!bWaited)
+ {
+ bWaited = true;
+ WaitForVBlank(bWaited);
+ TRACE("Double VBlank\n");
+ ASSERT(bWaited);
+ if (!bDoVSyncInPresent)
+ {
+ CalculateJitter();
+ OnVBlankFinished(fAll);
+ }
+ }*/
+
+ bool fResetDevice = m_bPendingResetDevice;
+
+ if(hr == D3DERR_DEVICELOST && m_pD3DDev->TestCooperativeLevel() == D3DERR_DEVICENOTRESET
+ || hr == S_PRESENT_MODE_CHANGED)
+ {
+ fResetDevice = true;
+ }
+
+ if (SettingsNeedResetDevice())
+ fResetDevice = true;
+
+ bCompositionEnabled = false;
+ if (m_pDwmIsCompositionEnabled)
+ m_pDwmIsCompositionEnabled(&bCompositionEnabled);
+ if ((bCompositionEnabled != 0) != m_bCompositionEnabled)
+ {
+ if (m_bIsFullscreen)
+ {
+ m_bCompositionEnabled = (bCompositionEnabled != 0);
+ }
+ else
+ fResetDevice = true;
+ }
+
+ if(s.fResetDevice)
+ {
+ LONGLONG time = GetRenderersData()->GetPerfCounter();
+ if (time > m_LastAdapterCheck + 20000000) // check every 2 sec.
+ {
+ m_LastAdapterCheck = time;
+#ifdef _DEBUG
+ D3DDEVICE_CREATION_PARAMETERS Parameters;
+ if(SUCCEEDED(m_pD3DDev->GetCreationParameters(&Parameters)))
+ {
+ ASSERT(Parameters.AdapterOrdinal == m_CurrentAdapter);
+ }
+#endif
+ if(m_CurrentAdapter != GetAdapter(m_pD3D))
+ {
+ fResetDevice = true;
+ }
+#ifdef _DEBUG
+ else
+ {
+ ASSERT(m_pD3D->GetAdapterMonitor(m_CurrentAdapter) == m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D)));
+ }
+#endif
+ }
+ }
+
+ if(fResetDevice)
+ {
+ m_bPendingResetDevice = true;
+ SendResetRequest();
+ }
+
+ if (m_OrderedPaint)
+ --m_OrderedPaint;
+ else
+ {
+ //if (m_bIsEVR)
+ // TRACE("UNORDERED PAINT!!!!!!\n");
+ }
+ return(true);
+}
+
+double CDX9AllocatorPresenter::GetFrameTime()
+{
+ if (m_DetectedLock)
+ return m_DetectedFrameTime;
+
+ return m_rtTimePerFrame / 10000000.0;
+}
+
+double CDX9AllocatorPresenter::GetFrameRate()
+{
+ if (m_DetectedLock)
+ return m_DetectedFrameRate;
+
+ return 10000000.0 / m_rtTimePerFrame;
+}
+
+void CDX9AllocatorPresenter::SendResetRequest()
+{
+ if (!m_bDeviceResetRequested)
+ {
+ m_bDeviceResetRequested = true;
+ AfxGetApp()->m_pMainWnd->PostMessage(WM_RESET_DEVICE);
+ }
+}
+
+STDMETHODIMP_(bool) CDX9AllocatorPresenter::ResetDevice()
+{
+ TRACE("ResetDevice\n");
+ _ASSERT(m_MainThreadId == GetCurrentThreadId());
+ StopWorkerThreads();
+ DeleteSurfaces();
+ HRESULT hr;
+ CString Error;
+ // TODO: Report error messages here
+ if(FAILED(hr = CreateDevice(Error)) || FAILED(hr = AllocSurfaces()))
+ {
+ // TODO: We should probably pause player
+#ifdef _DEBUG
+ Error += GetWindowsErrorMessage(hr, NULL);
+ TRACE("D3D Reset Error\n%ws\n\n", Error.GetBuffer());
+#endif
+ m_bDeviceResetRequested = false;
+ return false;
+ }
+ OnResetDevice();
+ m_bDeviceResetRequested = false;
+ m_bPendingResetDevice = false;
+
+ return true;
+}
+
+void CDX9AllocatorPresenter::DrawText(const RECT &rc, const CString &strText, int _Priority)
+{
+ if (_Priority < 1)
+ return;
+ int Quality = 1;
+ D3DXCOLOR Color1( 1.0f, 0.2f, 0.2f, 1.0f );
+ D3DXCOLOR Color0( 0.0f, 0.0f, 0.0f, 1.0f );
+ RECT Rect1 = rc;
+ RECT Rect2 = rc;
+ if (Quality == 1)
+ OffsetRect (&Rect2 , 2, 2);
+ else
+ OffsetRect (&Rect2 , -1, -1);
+ if (Quality > 0)
+ m_pFont->DrawText( m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ OffsetRect (&Rect2 , 1, 0);
+ if (Quality > 3)
+ m_pFont->DrawText( m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ OffsetRect (&Rect2 , 1, 0);
+ if (Quality > 2)
+ m_pFont->DrawText( m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ OffsetRect (&Rect2 , 0, 1);
+ if (Quality > 3)
+ m_pFont->DrawText( m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ OffsetRect (&Rect2 , 0, 1);
+ if (Quality > 1)
+ m_pFont->DrawText( m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ OffsetRect (&Rect2 , -1, 0);
+ if (Quality > 3)
+ m_pFont->DrawText( m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ OffsetRect (&Rect2 , -1, 0);
+ if (Quality > 2)
+ m_pFont->DrawText( m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ OffsetRect (&Rect2 , 0, -1);
+ if (Quality > 3)
+ m_pFont->DrawText( m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ m_pFont->DrawText( m_pSprite, strText, -1, &Rect1, DT_NOCLIP, Color1);
+}
+
+
+void CDX9AllocatorPresenter::DrawStats()
+{
+ CRenderersSettings& s = GetRenderersSettings();
+ CRenderersData * pApp = GetRenderersData();
+ int bDetailedStats = 2;
+ switch (pApp->m_fDisplayStats)
+ {
+ case 1:
+ bDetailedStats = 2;
+ break;
+ case 2:
+ bDetailedStats = 1;
+ break;
+ case 3:
+ bDetailedStats = 0;
+ break;
+ }
+
+ LONGLONG llMaxJitter = m_MaxJitter;
+ LONGLONG llMinJitter = m_MinJitter;
+ LONGLONG llMaxSyncOffset = m_MaxSyncOffset;
+ LONGLONG llMinSyncOffset = m_MinSyncOffset;
+ if (m_pFont && m_pSprite)
+ {
+ m_pSprite->Begin(D3DXSPRITE_ALPHABLEND);
+ RECT rc = {700, 40, 0, 0 };
+ rc.left = 40;
+ CString strText;
+ int TextHeight = 25.0*m_TextScale + 0.5;
+// strText.Format(L"Frame rate : %7.03f (%7.3f ms = %.03f, %s) (%7.3f ms = %.03f%s) Clock: %7.3f ms %+1.4f %% %+1.9f %+1.9f", m_fAvrFps, double(m_rtTimePerFrame) / 10000.0, 10000000.0 / (double)(m_rtTimePerFrame), m_bInterlaced ? L"I" : L"P", GetFrameTime() * 1000.0, GetFrameRate(), m_DetectedLock ? L" L" : L"", m_ClockDiff/10000.0, m_ModeratedTimeSpeed*100.0 - 100.0, m_ModeratedTimeSpeedDiff, m_ClockDiffCalc/10000.0);
+ if (bDetailedStats > 1)
+ {
+ if (m_bIsEVR)
+ strText.Format(L"Frame rate : %7.03f (%7.3f ms = %.03f, %s) (%7.3f ms = %.03f%s, %2.03f StdDev) Clock: %1.4f %%", m_fAvrFps, double(m_rtTimePerFrame) / 10000.0, 10000000.0 / (double)(m_rtTimePerFrame), m_bInterlaced ? L"I" : L"P", GetFrameTime() * 1000.0, GetFrameRate(), m_DetectedLock ? L" L" : L"", m_DetectedFrameTimeStdDev / 10000.0, m_ModeratedTimeSpeed*100.0);
+ else
+ strText.Format(L"Frame rate : %7.03f (%7.3f ms = %.03f, %s)", m_fAvrFps, double(m_rtTimePerFrame) / 10000.0, 10000000.0 / (double)(m_rtTimePerFrame), m_bInterlaced ? L"I" : L"P");
+ }
+// strText.Format(L"Frame rate : %7.03f (%7.3f ms = %.03f, %s) (%7.3f ms = %.03f%s, %2.03f StdDev)", m_fAvrFps, double(m_rtTimePerFrame) / 10000.0, 10000000.0 / (double)(m_rtTimePerFrame), m_bInterlaced ? L"I" : L"P", GetFrameTime() * 1000.0, GetFrameRate(), m_DetectedLock ? L" L" : L"", m_DetectedFrameTimeStdDev / 10000.0);
+ else
+ strText.Format(L"Frame rate : %7.03f (%.03f%s)", m_fAvrFps, GetFrameRate(), m_DetectedLock ? L" L" : L"");
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+
+ if (bDetailedStats > 1)
+ {
+ strText.Format(L"Settings : ");
+
+ if (m_bIsEVR)
+ strText += "EVR ";
+ else
+ strText += "VMR9 ";
+
+ if (m_bIsFullscreen)
+ strText += "FS ";
+ if (s.m_RenderSettings.iVMR9FullscreenGUISupport)
+ strText += "FSGui ";
+
+ if (s.m_RenderSettings.iVMRDisableDesktopComposition)
+ strText += "DisDC ";
+
+ if (s.m_RenderSettings.iVMRFlushGPUBeforeVSync)
+ strText += "GPUFlushBV ";
+ if (s.m_RenderSettings.iVMRFlushGPUAfterPresent)
+ strText += "GPUFlushAP ";
+
+ if (s.m_RenderSettings.iVMRFlushGPUWait)
+ strText += "GPUFlushWt ";
+
+ if (s.m_RenderSettings.iVMR9VSync)
+ strText += "VS ";
+ if (s.m_RenderSettings.fVMR9AlterativeVSync)
+ strText += "AltVS ";
+ if (s.m_RenderSettings.iVMR9VSyncAccurate)
+ strText += "AccVS ";
+ if (s.m_RenderSettings.iVMR9VSyncOffset)
+ strText.AppendFormat(L"VSOfst(%d)", s.m_RenderSettings.iVMR9VSyncOffset);
+
+ if (m_bIsEVR)
+ {
+ if (s.m_RenderSettings.iEVRHighColorResolution)
+ strText += "10bit ";
+ if (s.m_RenderSettings.iEVREnableFrameTimeCorrection)
+ strText += "FTC ";
+ if (s.m_RenderSettings.iEVROutputRange == 0)
+ strText += "0-255 ";
+ else if (s.m_RenderSettings.iEVROutputRange == 1)
+ strText += "16-235 ";
+ }
+
+
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+
+ }
+
+ if (bDetailedStats > 1)
+ {
+ strText.Format(L"Formats : Surface %s Backbuffer %s Display %s Device %s D3DExError: %s", GetD3DFormatStr(m_SurfaceType), GetD3DFormatStr(m_BackbufferType), GetD3DFormatStr(m_DisplayType), m_pD3DDevEx ? L"D3DDevEx" : L"D3DDev", m_D3DDevExError.GetString());
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+
+ if (m_bIsEVR)
+ {
+ strText.Format(L"Refresh rate : %.05f Hz SL: %4d (%3d Hz) Last Duration: %10.6f Corrected Frame Time: %s", m_DetectedRefreshRate, int(m_DetectedScanlinesPerFrame + 0.5), m_RefreshRate, double(m_LastFrameDuration)/10000.0, m_bCorrectedFrameTime?L"Yes":L"No");
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+ }
+ }
+
+ if (m_bSyncStatsAvailable)
+ {
+ if (bDetailedStats > 1)
+ strText.Format(L"Sync offset : Min = %+8.3f ms, Max = %+8.3f ms, StdDev = %7.3f ms, Avr = %7.3f ms, Mode = %d", (double(llMinSyncOffset)/10000.0), (double(llMaxSyncOffset)/10000.0), m_fSyncOffsetStdDev/10000.0, m_fSyncOffsetAvr/10000.0, m_VSyncMode);
+ else
+ strText.Format(L"Sync offset : Mode = %d", m_VSyncMode);
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+ }
+
+ if (bDetailedStats > 1)
+ {
+ strText.Format(L"Jitter : Min = %+8.3f ms, Max = %+8.3f ms, StdDev = %7.3f ms", (double(llMinJitter)/10000.0), (double(llMaxJitter)/10000.0), m_fJitterStdDev/10000.0);
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+ }
+
+ if (m_pAllocator && bDetailedStats > 1)
+ {
+ CDX9SubPicAllocator *pAlloc = (CDX9SubPicAllocator *)m_pAllocator.p;
+ int nFree = 0;
+ int nAlloc = 0;
+ int nSubPic = 0;
+ REFERENCE_TIME QueueNow = 0;
+ REFERENCE_TIME QueueStart = 0;
+ REFERENCE_TIME QueueEnd = 0;
+ if (m_pSubPicQueue)
+ {
+ m_pSubPicQueue->GetStats(nSubPic, QueueNow, QueueStart, QueueEnd);
+ if (QueueStart)
+ QueueStart -= QueueNow;
+ if (QueueEnd)
+ QueueEnd -= QueueNow;
+ }
+ pAlloc->GetStats(nFree, nAlloc);
+ strText.Format(L"Subtitles : Free %d Allocated %d Buffered %d QueueStart %7.3f QueueEnd %7.3f", nFree, nAlloc, nSubPic, (double(QueueStart)/10000000.0), (double(QueueEnd)/10000000.0));
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+ }
+
+ if (bDetailedStats > 1)
+ {
+ if (m_VBlankEndPresent == -100000)
+ strText.Format(L"VBlank Wait : Start %4d End %4d Wait %7.3f ms Lock %7.3f ms Offset %4d Max %4d", m_VBlankStartWait, m_VBlankEndWait, (double(m_VBlankWaitTime)/10000.0), (double(m_VBlankLockTime)/10000.0), m_VBlankMin, m_VBlankMax - m_VBlankMin);
+ else
+ strText.Format(L"VBlank Wait : Start %4d End %4d Wait %7.3f ms Lock %7.3f ms Offset %4d Max %4d EndPresent %4d", m_VBlankStartWait, m_VBlankEndWait, (double(m_VBlankWaitTime)/10000.0), (double(m_VBlankLockTime)/10000.0), m_VBlankMin, m_VBlankMax - m_VBlankMin, m_VBlankEndPresent);
+ }
+ else
+ {
+ if (m_VBlankEndPresent == -100000)
+ strText.Format(L"VBlank Wait : Start %4d End %4d", m_VBlankStartWait, m_VBlankEndWait);
+ else
+ strText.Format(L"VBlank Wait : Start %4d End %4d EP %4d", m_VBlankStartWait, m_VBlankEndWait, m_VBlankEndPresent);
+ }
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+
+ BOOL bCompositionEnabled = m_bCompositionEnabled;
+
+ bool bDoVSyncInPresent = (!bCompositionEnabled && !m_bAlternativeVSync) || !s.m_RenderSettings.iVMR9VSync;
+
+ if (bDetailedStats > 1 && bDoVSyncInPresent)
+ {
+ strText.Format(L"Present Wait : Wait %7.3f ms Min %7.3f ms Max %7.3f ms", (double(m_PresentWaitTime)/10000.0), (double(m_PresentWaitTimeMin)/10000.0), (double(m_PresentWaitTimeMax)/10000.0));
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+ }
+
+ if (bDetailedStats > 1)
+ {
+ if (m_WaitForGPUTime)
+ strText.Format(L"Paint Time : Draw %7.3f ms Min %7.3f ms Max %7.3f ms GPU %7.3f ms", (double(m_PaintTime-m_WaitForGPUTime)/10000.0), (double(m_PaintTimeMin)/10000.0), (double(m_PaintTimeMax)/10000.0), (double(m_WaitForGPUTime)/10000.0));
+ else
+ strText.Format(L"Paint Time : Draw %7.3f ms Min %7.3f ms Max %7.3f ms", (double(m_PaintTime-m_WaitForGPUTime)/10000.0), (double(m_PaintTimeMin)/10000.0), (double(m_PaintTimeMax)/10000.0));
+ }
+ else
+ {
+ if (m_WaitForGPUTime)
+ strText.Format(L"Paint Time : Draw %7.3f ms GPU %7.3f ms", (double(m_PaintTime - m_WaitForGPUTime)/10000.0), (double(m_WaitForGPUTime)/10000.0));
+ else
+ strText.Format(L"Paint Time : Draw %7.3f ms", (double(m_PaintTime - m_WaitForGPUTime)/10000.0));
+ }
+ DrawText(rc, strText, 2);
+ OffsetRect (&rc, 0, TextHeight);
+
+ if (bDetailedStats > 1)
+ {
+ strText.Format(L"Raster Status: Wait %7.3f ms Min %7.3f ms Max %7.3f ms", (double(m_RasterStatusWaitTime)/10000.0), (double(m_RasterStatusWaitTimeMin)/10000.0), (double(m_RasterStatusWaitTimeMax)/10000.0));
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+ }
+
+ if (bDetailedStats > 1)
+ {
+ if (m_bIsEVR)
+ strText.Format(L"Buffering : Buffered %3d Free %3d Current Surface %3d", m_nUsedBuffer, m_nNbDXSurface - m_nUsedBuffer, m_nCurSurface, m_nVMR9Surfaces, m_iVMR9Surface);
+ else
+ strText.Format(L"Buffering : VMR9Surfaces %3d VMR9Surface %3d", m_nVMR9Surfaces, m_iVMR9Surface);
+ }
+ else
+ strText.Format(L"Buffered : %3d", m_nUsedBuffer);
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+
+ if (bDetailedStats > 1)
+ {
+ strText.Format(L"Video size : %d x %d (AR = %d x %d)", m_NativeVideoSize.cx, m_NativeVideoSize.cy, m_AspectRatio.cx, m_AspectRatio.cy);
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+ if (m_pVideoTexture[0] || m_pVideoSurface[0])
+ {
+ D3DSURFACE_DESC desc;
+ if (m_pVideoTexture[0])
+ m_pVideoTexture[0]->GetLevelDesc(0, &desc);
+ else if (m_pVideoSurface[0])
+ m_pVideoSurface[0]->GetDesc(&desc);
+
+ if (desc.Width != m_NativeVideoSize.cx || desc.Height != m_NativeVideoSize.cy)
+ {
+ strText.Format(L"Texture size : %d x %d", desc.Width, desc.Height);
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+ }
+ }
+
+
+ strText.Format(L"%-13s: %s", GetDXVAVersion(), GetDXVADecoderDescription());
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+
+ if(m_D3D9Device != _T(""))
+ {
+ strText = "Render device: " + m_D3D9Device;
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+ }
+
+ strText.Format(L"DirectX SDK : %d", GetRenderersData()->GetDXSdkRelease());
+ DrawText(rc, strText, 1);
+ OffsetRect (&rc, 0, TextHeight);
+
+ for (int i=0; i<6; i++)
+ {
+ if (m_strStatsMsg[i][0])
+ {
+ DrawText(rc, m_strStatsMsg[i], 1);
+ OffsetRect (&rc, 0, TextHeight);
+ }
+ }
+ }
+ m_pSprite->End();
+ }
+
+ if (m_pLine && bDetailedStats)
+ {
+ D3DXVECTOR2 Points[NB_JITTER];
+ int nIndex;
+
+ int StartX = 0;
+ int StartY = 0;
+ int ScaleX = 1;
+ int ScaleY = 1;
+ int DrawWidth = 625 * ScaleX + 50;
+ int DrawHeight = 500 * ScaleY;
+ int Alpha = 80;
+ StartX = m_WindowRect.Width() - (DrawWidth + 20);
+ StartY = m_WindowRect.Height() - (DrawHeight + 20);
+
+ DrawRect(RGB(0,0,0), Alpha, CRect(StartX, StartY, StartX + DrawWidth, StartY + DrawHeight));
+ // === Jitter Graduation
+// m_pLine->SetWidth(2.2); // Width
+// m_pLine->SetAntialias(1);
+ m_pLine->SetWidth(2.5); // Width
+ m_pLine->SetAntialias(1);
+// m_pLine->SetGLLines(1);
+ m_pLine->Begin();
+
+ for (int i=10; i<500*ScaleY; i+= 20*ScaleY)
+ {
+ Points[0].x = (FLOAT)StartX;
+ Points[0].y = (FLOAT)(StartY + i);
+ Points[1].x = (FLOAT)(StartX + ((i-10)%80 ? 50 : 625 * ScaleX));
+ Points[1].y = (FLOAT)(StartY + i);
+ if (i == 250) Points[1].x += 50;
+ m_pLine->Draw (Points, 2, D3DCOLOR_XRGB(100,100,255));
+ }
+
+ // === Jitter curve
+ if (m_rtTimePerFrame)
+ {
+ for (int i=0; i<NB_JITTER; i++)
+ {
+ nIndex = (m_nNextJitter+1+i) % NB_JITTER;
+ if (nIndex < 0)
+ nIndex += NB_JITTER;
+ double Jitter = m_pllJitter[nIndex] - m_fJitterMean;
+ Points[i].x = (FLOAT)(StartX + (i*5*ScaleX+5));
+ Points[i].y = (FLOAT)(StartY + ((Jitter*ScaleY)/5000.0 + 250.0* ScaleY));
+ }
+ m_pLine->Draw (Points, NB_JITTER, D3DCOLOR_XRGB(255,100,100));
+
+ if (m_bSyncStatsAvailable)
+ {
+ for (int i=0; i<NB_JITTER; i++)
+ {
+ nIndex = (m_nNextSyncOffset+1+i) % NB_JITTER;
+ if (nIndex < 0)
+ nIndex += NB_JITTER;
+ Points[i].x = (FLOAT)(StartX + (i*5*ScaleX+5));
+ Points[i].y = (FLOAT)(StartY + ((m_pllSyncOffset[nIndex]*ScaleY)/5000 + 250*ScaleY));
+ }
+ m_pLine->Draw (Points, NB_JITTER, D3DCOLOR_XRGB(100,200,100));
+ }
+ }
+ m_pLine->End();
+ }
+
+ // === Text
+
+}
+
+STDMETHODIMP CDX9AllocatorPresenter::GetDIB(BYTE* lpDib, DWORD* size)
+{
+ CheckPointer(size, E_POINTER);
+
+ HRESULT hr;
+
+ D3DSURFACE_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ m_pVideoSurface[m_nCurSurface]->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[m_nCurSurface];
+ 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[m_nCurSurface], 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)
+{
+ return SetPixelShader2(pSrcData, pTarget, false);
+}
+
+STDMETHODIMP CDX9AllocatorPresenter::SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace)
+{
+ CAutoLock cRenderLock(&m_RenderLock);
+
+ CAtlList<CExternalPixelShader> *pPixelShaders;
+ if (bScreenSpace)
+ pPixelShaders = &m_pPixelShadersScreenSpace;
+ else
+ pPixelShaders = &m_pPixelShaders;
+
+ if(!pSrcData && !pTarget)
+ {
+ pPixelShaders->RemoveAll();
+ m_pD3DDev->SetPixelShader(NULL);
+ return S_OK;
+ }
+
+ if(!pSrcData || !pTarget)
+ return E_INVALIDARG;
+
+ CExternalPixelShader Shader;
+ Shader.m_SourceData = pSrcData;
+ Shader.m_SourceTarget = pTarget;
+
+ CComPtr<IDirect3DPixelShader9> pPixelShader;
+
+ HRESULT hr = Shader.Compile(m_pPSC);
+ if(FAILED(hr))
+ return hr;
+
+ pPixelShaders->AddTail(Shader);
+
+ Paint(false);
+
+ return S_OK;
+}
diff --git a/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h new file mode 100644 index 000000000..605bdd19c --- /dev/null +++ b/src/filters/renderer/VideoRenderers/DX9AllocatorPresenter.h @@ -0,0 +1,352 @@ +/*
+ * $Id$
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "AllocatorCommon.h"
+#include "RenderersSettings.h"
+#include <d3d9.h>
+
+#define VMRBITMAP_UPDATE 0x80000000
+#define MAX_PICTURE_SLOTS (60+2) // Last 2 for pixels shader!
+
+#define NB_JITTER 126
+
+extern bool g_bNoDuration;
+extern bool g_bExternalSubtitleTime;
+
+namespace DSObjects
+{
+
+class CDX9AllocatorPresenter
+ : public ISubPicAllocatorPresenterImpl
+{
+public:
+ CCritSec m_VMR9AlphaBitmapLock;
+ void UpdateAlphaBitmap();
+protected:
+ CSize m_ScreenSize;
+ UINT m_RefreshRate;
+
+// bool m_fVMRSyncFix;
+ bool m_bAlternativeVSync;
+ bool m_bHighColorResolution;
+ bool m_bCompositionEnabled;
+ bool m_bIsEVR;
+ int m_OrderedPaint;
+ int m_VSyncMode;
+ bool m_bDesktopCompositionDisabled;
+ bool m_bIsFullscreen;
+ bool m_bNeedCheckSample;
+ DWORD m_MainThreadId;
+
+ CRenderersSettings::CRendererSettingsEVR m_LastRendererSettings;
+
+ HRESULT (__stdcall * m_pDwmIsCompositionEnabled)(__out BOOL* pfEnabled);
+ HRESULT (__stdcall * m_pDwmEnableComposition)(UINT uCompositionAction);
+
+ HMODULE m_hDWMAPI;
+
+ HRESULT (__stdcall * m_pDirect3DCreate9Ex)(UINT SDKVersion, IDirect3D9Ex**);
+ HMODULE m_hD3D9;
+
+ CCritSec m_RenderLock;
+ CComPtr<IDirectDraw> m_pDirectDraw;
+
+ CComPtr<IDirect3D9Ex> m_pD3DEx;
+ CComPtr<IDirect3D9> m_pD3D;
+ CComPtr<IDirect3DDevice9Ex> m_pD3DDevEx;
+
+ void LockD3DDevice()
+ {
+ if (m_pD3DDev)
+ {
+ _RTL_CRITICAL_SECTION *pCritSec = (_RTL_CRITICAL_SECTION *)((size_t)m_pD3DDev.p + sizeof(size_t));
+
+ if (!IsBadReadPtr(pCritSec, sizeof(*pCritSec)) && !IsBadWritePtr(pCritSec, sizeof(*pCritSec))
+ && !IsBadReadPtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo))) && !IsBadWritePtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo))))
+ {
+ if (pCritSec->DebugInfo->CriticalSection == pCritSec)
+ EnterCriticalSection(pCritSec);
+ }
+ }
+ }
+
+ void UnlockD3DDevice()
+ {
+ if (m_pD3DDev)
+ {
+ _RTL_CRITICAL_SECTION *pCritSec = (_RTL_CRITICAL_SECTION *)((size_t)m_pD3DDev.p + sizeof(size_t));
+
+ if (!IsBadReadPtr(pCritSec, sizeof(*pCritSec)) && !IsBadWritePtr(pCritSec, sizeof(*pCritSec))
+ && !IsBadReadPtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo))) && !IsBadWritePtr(pCritSec->DebugInfo, sizeof(*(pCritSec->DebugInfo))))
+ {
+ if (pCritSec->DebugInfo->CriticalSection == pCritSec)
+ LeaveCriticalSection(pCritSec);
+ }
+ }
+ }
+ CString m_D3DDevExError;
+ CComPtr<IDirect3DDevice9> m_pD3DDev;
+ CComPtr<IDirect3DTexture9> m_pVideoTexture[MAX_PICTURE_SLOTS];
+ CComPtr<IDirect3DSurface9> m_pVideoSurface[MAX_PICTURE_SLOTS];
+ CComPtr<IDirect3DTexture9> m_pOSDTexture;
+ CComPtr<IDirect3DSurface9> m_pOSDSurface;
+ CComPtr<ID3DXLine> m_pLine;
+ CComPtr<ID3DXFont> m_pFont;
+ CComPtr<ID3DXSprite> m_pSprite;
+ class CExternalPixelShader
+ {
+ public:
+ CComPtr<IDirect3DPixelShader9> m_pPixelShader;
+ CStringA m_SourceData;
+ CStringA m_SourceTarget;
+ HRESULT Compile(CPixelShaderCompiler *pCompiler)
+ {
+ HRESULT hr = pCompiler->CompileShader(m_SourceData, "main", m_SourceTarget, 0, &m_pPixelShader);
+ if(FAILED(hr))
+ return hr;
+
+ return S_OK;
+ }
+ };
+ CAtlList<CExternalPixelShader> m_pPixelShaders;
+ CAtlList<CExternalPixelShader> m_pPixelShadersScreenSpace;
+ CComPtr<IDirect3DPixelShader9> m_pResizerPixelShader[4]; // bl, bc1, bc2_1, bc2_2
+ CComPtr<IDirect3DTexture9> m_pScreenSizeTemporaryTexture[2];
+ D3DFORMAT m_SurfaceType;
+ D3DFORMAT m_BackbufferType;
+ D3DFORMAT m_DisplayType;
+ D3DTEXTUREFILTERTYPE m_filter;
+ D3DCAPS9 m_caps;
+
+ CAutoPtr<CPixelShaderCompiler> m_pPSC;
+
+ bool SettingsNeedResetDevice();
+
+ virtual HRESULT CreateDevice(CString &_Error);
+// virtual HRESULT AllocSurfaces(D3DFORMAT Format = D3DFMT_A2B10G10R10);
+ virtual HRESULT AllocSurfaces(D3DFORMAT Format = D3DFMT_A8R8G8B8);
+ virtual void DeleteSurfaces();
+
+ // Thread stuff
+ HANDLE m_hEvtQuit; // Stop rendering thread event
+ HANDLE m_hVSyncThread;
+ static DWORD WINAPI VSyncThreadStatic(LPVOID lpParam);
+ void VSyncThread();
+ void StartWorkerThreads();
+ void StopWorkerThreads();
+
+ LONGLONG m_LastAdapterCheck;
+ UINT m_CurrentAdapter;
+ UINT GetAdapter(IDirect3D9 *pD3D, bool GetAdapter = false);
+
+ float m_bicubicA;
+ HRESULT InitResizers(float bicubicA, bool bNeedScreenSizeTexture);
+
+ bool GetVBlank(int &_ScanLine, int &_bInVBlank, bool _bMeasureTime);
+ bool WaitForVBlankRange(int &_RasterStart, int _RasterEnd, bool _bWaitIfInside, bool _bNeedAccurate, bool _bMeasure, bool &_bTakenLock);
+ bool WaitForVBlank(bool &_Waited, bool &_bTakenLock);
+ int GetVBlackPos();
+ void CalculateJitter(LONGLONG PerformanceCounter);
+ virtual void OnVBlankFinished(bool fAll, LONGLONG PerformanceCounter) {}
+
+ HRESULT DrawRect(DWORD _Color, DWORD _Alpha, const CRect &_Rect);
+ HRESULT TextureCopy(IDirect3DTexture9* pTexture);
+ HRESULT TextureResize(IDirect3DTexture9* pTexture, Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect &SrcRect);
+ HRESULT TextureResizeBilinear(IDirect3DTexture9* pTexture, Vector dst[4], const CRect &SrcRect);
+ HRESULT TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, Vector dst[4], const CRect &SrcRect);
+ HRESULT TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, Vector dst[4], const CRect &SrcRect);
+
+ // Casimir666
+ typedef HRESULT (WINAPI * D3DXLoadSurfaceFromMemoryPtr)(
+ LPDIRECT3DSURFACE9 pDestSurface,
+ CONST PALETTEENTRY* pDestPalette,
+ CONST RECT* pDestRect,
+ LPCVOID pSrcMemory,
+ D3DFORMAT SrcFormat,
+ UINT SrcPitch,
+ CONST PALETTEENTRY* pSrcPalette,
+ CONST RECT* pSrcRect,
+ DWORD Filter,
+ D3DCOLOR ColorKey);
+
+ typedef HRESULT (WINAPI* D3DXCreateLinePtr) (LPDIRECT3DDEVICE9 pDevice, LPD3DXLINE* ppLine);
+
+ typedef HRESULT (WINAPI* D3DXCreateFontPtr)(
+ LPDIRECT3DDEVICE9 pDevice,
+ int Height,
+ UINT Width,
+ UINT Weight,
+ UINT MipLevels,
+ bool Italic,
+ DWORD CharSet,
+ DWORD OutputPrecision,
+ DWORD Quality,
+ DWORD PitchAndFamily,
+ LPCWSTR pFaceName,
+ LPD3DXFONT* ppFont);
+
+
+ void DrawText(const RECT &rc, const CString &strText, int _Priority);
+ void DrawStats();
+ HRESULT AlphaBlt(RECT* pSrc, RECT* pDst, IDirect3DTexture9* pTexture);
+ virtual void OnResetDevice() {};
+ void SendResetRequest();
+
+ double GetFrameTime();
+ double GetFrameRate();
+
+
+ int m_nTearingPos;
+ VMR9AlphaBitmap m_VMR9AlphaBitmap;
+ CAutoVectorPtr<BYTE> m_VMR9AlphaBitmapData;
+ CRect m_VMR9AlphaBitmapRect;
+ int m_VMR9AlphaBitmapWidthBytes;
+
+ D3DXLoadSurfaceFromMemoryPtr m_pD3DXLoadSurfaceFromMemory;
+ D3DXCreateLinePtr m_pD3DXCreateLine;
+ D3DXCreateFontPtr m_pD3DXCreateFont;
+ HRESULT (__stdcall *m_pD3DXCreateSprite)(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE * ppSprite);
+
+
+
+ int m_nNbDXSurface; // Total number of DX Surfaces
+ int m_nVMR9Surfaces; // Total number of DX Surfaces
+ int m_iVMR9Surface;
+ int m_nCurSurface; // Surface currently displayed
+ long m_nUsedBuffer;
+
+ double m_fAvrFps; // Estimate the real FPS
+ double m_fJitterStdDev; // Estimate the Jitter std dev
+ double m_fJitterMean;
+ double m_fSyncOffsetStdDev;
+ double m_fSyncOffsetAvr;
+ double m_DetectedRefreshRate;
+
+ CCritSec m_RefreshRateLock;
+ double m_DetectedRefreshTime;
+ double m_DetectedRefreshTimePrim;
+ double m_DetectedScanlineTime;
+ double m_DetectedScanlineTimePrim;
+ double m_DetectedScanlinesPerFrame;
+
+ double GetRefreshRate()
+ {
+ if (m_DetectedRefreshRate)
+ return m_DetectedRefreshRate;
+ return m_RefreshRate;
+ }
+
+ LONG GetScanLines()
+ {
+ if (m_DetectedRefreshRate)
+ return m_DetectedScanlinesPerFrame;
+ return m_ScreenSize.cy;
+ }
+
+ double m_ldDetectedRefreshRateList[100];
+ double m_ldDetectedScanlineRateList[100];
+ int m_DetectedRefreshRatePos;
+ bool m_bSyncStatsAvailable;
+ LONGLONG m_pllJitter [NB_JITTER]; // Jitter buffer for stats
+ LONGLONG m_pllSyncOffset [NB_JITTER]; // Jitter buffer for stats
+ LONGLONG m_llLastPerf;
+ LONGLONG m_JitterStdDev;
+ LONGLONG m_MaxJitter;
+ LONGLONG m_MinJitter;
+ LONGLONG m_MaxSyncOffset;
+ LONGLONG m_MinSyncOffset;
+ int m_nNextJitter;
+ int m_nNextSyncOffset;
+ REFERENCE_TIME m_rtTimePerFrame;
+ double m_DetectedFrameRate;
+ double m_DetectedFrameTime;
+ double m_DetectedFrameTimeStdDev;
+ bool m_DetectedLock;
+ LONGLONG m_DetectedFrameTimeHistory[60];
+ double m_DetectedFrameTimeHistoryHistory[500];
+ int m_DetectedFrameTimePos;
+ int m_bInterlaced;
+
+ double m_TextScale;
+
+ int m_VBlankEndWait;
+ int m_VBlankStartWait;
+ LONGLONG m_VBlankWaitTime;
+ LONGLONG m_VBlankLockTime;
+ int m_VBlankMin;
+ int m_VBlankMinCalc;
+ int m_VBlankMax;
+ int m_VBlankEndPresent;
+ LONGLONG m_VBlankStartMeasureTime;
+ int m_VBlankStartMeasure;
+
+ LONGLONG m_PresentWaitTime;
+ LONGLONG m_PresentWaitTimeMin;
+ LONGLONG m_PresentWaitTimeMax;
+
+ LONGLONG m_PaintTime;
+ LONGLONG m_PaintTimeMin;
+ LONGLONG m_PaintTimeMax;
+
+ LONGLONG m_WaitForGPUTime;
+
+ LONGLONG m_RasterStatusWaitTime;
+ LONGLONG m_RasterStatusWaitTimeMin;
+ LONGLONG m_RasterStatusWaitTimeMax;
+ LONGLONG m_RasterStatusWaitTimeMaxCalc;
+
+ double m_ClockDiffCalc;
+ double m_ClockDiffPrim;
+ double m_ClockDiff;
+
+ double m_TimeChangeHistory[100];
+ double m_ClockChangeHistory[100];
+ int m_ClockTimeChangeHistoryPos;
+ double m_ModeratedTimeSpeed;
+ double m_ModeratedTimeSpeedPrim;
+ double m_ModeratedTimeSpeedDiff;
+
+ bool m_bCorrectedFrameTime;
+ int m_FrameTimeCorrection;
+ LONGLONG m_LastFrameDuration;
+ LONGLONG m_LastSampleTime;
+
+ CString m_strStatsMsg[10];
+
+ CString m_D3D9Device;
+
+public:
+ CDX9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, bool bIsEVR, CString &_Error);
+ ~CDX9AllocatorPresenter();
+
+ // ISubPicAllocatorPresenter
+ STDMETHODIMP CreateRenderer(IUnknown** ppRenderer);
+ STDMETHODIMP_(bool) Paint(bool fAll);
+ STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size);
+ STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget);
+ STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace);
+ STDMETHODIMP_(bool) ResetDevice();
+};
+}
diff --git a/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.cpp new file mode 100644 index 000000000..941d1b9ec --- /dev/null +++ b/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.cpp @@ -0,0 +1,242 @@ +/*
+ * $Id$
+ *
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include "RenderersSettings.h"
+#include "DXRAllocatorPresenter.h"
+#include <moreuuids.h>
+
+using namespace DSObjects;
+
+//
+// CDXRAllocatorPresenter
+//
+
+CDXRAllocatorPresenter::CDXRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString &_Error)
+ : ISubPicAllocatorPresenterImpl(hWnd, hr, &_Error)
+ , m_ScreenSize(0, 0)
+{
+ if(FAILED(hr))
+ {
+ _Error += L"ISubPicAllocatorPresenterImpl failed\n";
+ 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(GetRenderersSettings().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;
+ case 6:
+ size.SetSize(2560, 1600);
+ break;
+ case 7:
+ size.SetSize(1920, 1080);
+ break;
+ case 8:
+ size.SetSize(1320, 900);
+ break;
+ case 9:
+ size.SetSize(1280, 720);
+ break;
+ }
+
+ if(m_pAllocator)
+ {
+ m_pAllocator->ChangeDevice(pD3DDev);
+ }
+ else
+ {
+ m_pAllocator = DNew CDX9SubPicAllocator(pD3DDev, size, GetRenderersSettings().fSPCPow2Tex);
+ if(!m_pAllocator)
+ return E_FAIL;
+ }
+
+ HRESULT hr = S_OK;
+
+ m_pSubPicQueue = GetRenderersSettings().nSPCSize > 0
+ ? (ISubPicQueue*)DNew CSubPicQueue(GetRenderersSettings().nSPCSize, !GetRenderersSettings().fSPCAllowAnimationWhenBuffering, m_pAllocator, &hr)
+ : (ISubPicQueue*)DNew 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 = DNew CSubRenderCallback(this);
+ if(FAILED(pSR->SetCallback(m_pSRCB)))
+ {
+ m_pDXR = NULL;
+ return E_FAIL;
+ }
+
+ (*ppRenderer = this)->AddRef();
+
+ MONITORINFO mi;
+ mi.cbSize = sizeof(MONITORINFO);
+ if (GetMonitorInfo(MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), &mi))
+ m_ScreenSize.SetSize(mi.rcMonitor.right-mi.rcMonitor.left, mi.rcMonitor.bottom-mi.rcMonitor.top);
+
+ 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
+}
diff --git a/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.h b/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.h new file mode 100644 index 000000000..fef02e56c --- /dev/null +++ b/src/filters/renderer/VideoRenderers/DXRAllocatorPresenter.h @@ -0,0 +1,104 @@ +/*
+ * $Id$
+ *
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "AllocatorCommon.h"
+
+namespace DSObjects
+{
+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;
+ CSize m_ScreenSize;
+
+public:
+ CDXRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString &_Error);
+ 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);
+};
+}
diff --git a/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp new file mode 100644 index 000000000..6ed708080 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.cpp @@ -0,0 +1,2722 @@ +/*
+ * $Id$
+ *
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+
+#include "EVRAllocatorPresenter.h"
+#include <Mferror.h>
+#include "IPinHook.h"
+#include "MacrovisionKicker.h"
+
+#if (0) // Set to 1 to activate EVR traces
+#define TRACE_EVR TRACE
+#else
+#define TRACE_EVR
+#endif
+
+typedef enum
+{
+ MSG_MIXERIN,
+ MSG_MIXEROUT
+} EVR_STATS_MSG;
+
+// Guid to tag IMFSample with DirectX surface index
+static const GUID GUID_SURFACE_INDEX = { 0x30c8e9f6, 0x415, 0x4b81, { 0xa3, 0x15, 0x1, 0xa, 0xc6, 0xa9, 0xda, 0x19 } };
+
+
+// === Helper functions
+#define CheckHR(exp) {if(FAILED(hr = exp)) return hr;}
+
+MFOffset MakeOffset(float v)
+{
+ MFOffset offset;
+ offset.value = short(v);
+ offset.fract = WORD(65536 * (v-offset.value));
+ return offset;
+}
+
+MFVideoArea MakeArea(float x, float y, DWORD width, DWORD height)
+{
+ MFVideoArea area;
+ area.OffsetX = MakeOffset(x);
+ area.OffsetY = MakeOffset(y);
+ area.Area.cx = width;
+ area.Area.cy = height;
+ return area;
+}
+
+
+/// === Outer EVR
+
+namespace DSObjects
+{
+class COuterEVR
+ : public CUnknown
+ , public IVMRffdshow9
+ , public IVMRMixerBitmap9
+ , public IBaseFilter
+{
+ CComPtr<IUnknown> m_pEVR;
+ VMR9AlphaBitmap* m_pVMR9AlphaBitmap;
+ CEVRAllocatorPresenter *m_pAllocatorPresenter;
+
+public:
+
+ // IBaseFilter
+ virtual HRESULT STDMETHODCALLTYPE EnumPins(__out IEnumPins **ppEnum)
+ {
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->EnumPins(ppEnum);
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, __out IPin **ppPin)
+ {
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->FindPin(Id, ppPin);
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE QueryFilterInfo(__out FILTER_INFO *pInfo)
+ {
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->QueryFilterInfo(pInfo);
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE JoinFilterGraph(__in_opt IFilterGraph *pGraph, __in_opt LPCWSTR pName)
+ {
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->JoinFilterGraph(pGraph, pName);
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE QueryVendorInfo(__out LPWSTR *pVendorInfo)
+ {
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->QueryVendorInfo(pVendorInfo);
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE Stop( void)
+ {
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->Stop();
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE Pause( void)
+ {
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->Pause();
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE Run( REFERENCE_TIME tStart)
+ {
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->Run(tStart);
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetState( DWORD dwMilliSecsTimeout, __out FILTER_STATE *State);
+
+ virtual HRESULT STDMETHODCALLTYPE SetSyncSource(__in_opt IReferenceClock *pClock)
+ {
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->SetSyncSource(pClock);
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetSyncSource(__deref_out_opt IReferenceClock **pClock)
+ {
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->GetSyncSource(pClock);
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetClassID(__RPC__out CLSID *pClassID)
+ {
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->GetClassID(pClassID);
+ return E_NOTIMPL;
+ }
+
+ COuterEVR(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CEVRAllocatorPresenter *pAllocatorPresenter) : CUnknown(pName, pUnk)
+ {
+ hr = m_pEVR.CoCreateInstance(CLSID_EnhancedVideoRenderer, GetOwner());
+ m_pVMR9AlphaBitmap = pVMR9AlphaBitmap;
+ m_pAllocatorPresenter = pAllocatorPresenter;
+ }
+
+ ~COuterEVR();
+
+ DECLARE_IUNKNOWN;
+ STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv)
+ {
+ HRESULT hr;
+
+ if(riid == __uuidof(IVMRMixerBitmap9))
+ {
+ return GetInterface((IVMRMixerBitmap9*)this, ppv);
+ }
+ if (riid == __uuidof(IMediaFilter))
+ {
+ return GetInterface((IMediaFilter*)this, ppv);
+ }
+ if (riid == __uuidof(IPersist))
+ {
+ return GetInterface((IPersist*)this, ppv);
+ }
+ if (riid == __uuidof(IBaseFilter))
+ {
+ return GetInterface((IBaseFilter*)this, ppv);
+ }
+
+ hr = m_pEVR ? m_pEVR->QueryInterface(riid, ppv) : E_NOINTERFACE;
+ if(m_pEVR && FAILED(hr))
+ {
+ if(riid == __uuidof(IVMRffdshow9)) // Support ffdshow queueing. We show ffdshow that this is patched Media Player Classic.
+ return GetInterface((IVMRffdshow9*)this, ppv);
+ }
+
+ return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv);
+ }
+
+ // IVMRffdshow9
+ STDMETHODIMP support_ffdshow()
+ {
+ queue_ffdshow_support = true;
+ return S_OK;
+ }
+
+ // IVMRMixerBitmap9
+ STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms);
+
+ STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms);
+
+ STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms);
+};
+}
+
+using namespace DSObjects;
+
+HRESULT STDMETHODCALLTYPE COuterEVR::GetState( DWORD dwMilliSecsTimeout, __out FILTER_STATE *State)
+{
+ HRESULT ReturnValue;
+ if (m_pAllocatorPresenter->GetState(dwMilliSecsTimeout, State, ReturnValue))
+ return ReturnValue;
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->GetState(dwMilliSecsTimeout, State);
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP COuterEVR::GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms)
+{
+ CheckPointer(pBmpParms, E_POINTER);
+ CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock);
+ memcpy (pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap));
+ return S_OK;
+}
+
+STDMETHODIMP COuterEVR::SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms)
+{
+ CheckPointer(pBmpParms, E_POINTER);
+ CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock);
+ memcpy (m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap));
+ m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE;
+ m_pAllocatorPresenter->UpdateAlphaBitmap();
+ return S_OK;
+}
+
+STDMETHODIMP COuterEVR::UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms)
+{
+ CheckPointer(pBmpParms, E_POINTER);
+ CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock);
+ memcpy (m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap));
+ m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE;
+ m_pAllocatorPresenter->UpdateAlphaBitmap();
+ return S_OK;
+}
+
+COuterEVR::~COuterEVR()
+{
+}
+
+CEVRAllocatorPresenter::CEVRAllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString &_Error)
+ : CDX9AllocatorPresenter(hWnd, bFullscreen, hr, true, _Error)
+{
+ HMODULE hLib;
+ CRenderersSettings& s = GetRenderersSettings();
+
+ m_nResetToken = 0;
+ m_hThread = INVALID_HANDLE_VALUE;
+ m_hGetMixerThread= INVALID_HANDLE_VALUE;
+ m_hEvtFlush = INVALID_HANDLE_VALUE;
+ m_hEvtQuit = INVALID_HANDLE_VALUE;
+ m_bEvtQuit = 0;
+ m_bEvtFlush = 0;
+ m_ModeratedTime = 0;
+ m_ModeratedTimeLast = -1;
+ m_ModeratedClockLast = -1;
+
+ if (FAILED (hr))
+ {
+ _Error += L"DX9AllocatorPresenter failed\n";
+ return;
+ }
+
+ // Load EVR specifics DLLs
+ hLib = LoadLibrary (L"dxva2.dll");
+ pfDXVA2CreateDirect3DDeviceManager9 = hLib ? (PTR_DXVA2CreateDirect3DDeviceManager9) GetProcAddress (hLib, "DXVA2CreateDirect3DDeviceManager9") : NULL;
+
+ // Load EVR functions
+ hLib = LoadLibrary (L"evr.dll");
+ pfMFCreateDXSurfaceBuffer = hLib ? (PTR_MFCreateDXSurfaceBuffer) GetProcAddress (hLib, "MFCreateDXSurfaceBuffer") : NULL;
+ pfMFCreateVideoSampleFromSurface = hLib ? (PTR_MFCreateVideoSampleFromSurface) GetProcAddress (hLib, "MFCreateVideoSampleFromSurface") : NULL;
+ pfMFCreateVideoMediaType = hLib ? (PTR_MFCreateVideoMediaType) GetProcAddress (hLib, "MFCreateVideoMediaType") : NULL;
+
+ if (!pfDXVA2CreateDirect3DDeviceManager9 || !pfMFCreateDXSurfaceBuffer || !pfMFCreateVideoSampleFromSurface || !pfMFCreateVideoMediaType)
+ {
+ if (!pfDXVA2CreateDirect3DDeviceManager9)
+ _Error += L"Could not find DXVA2CreateDirect3DDeviceManager9 (dxva2.dll)\n";
+ if (!pfMFCreateDXSurfaceBuffer)
+ _Error += L"Could not find MFCreateDXSurfaceBuffer (evr.dll)\n";
+ if (!pfMFCreateVideoSampleFromSurface)
+ _Error += L"Could not find MFCreateVideoSampleFromSurface (evr.dll)\n";
+ if (!pfMFCreateVideoMediaType)
+ _Error += L"Could not find MFCreateVideoMediaType (evr.dll)\n";
+ hr = E_FAIL;
+ return;
+ }
+
+ // Load mfplat fuctions
+#if 0
+ hLib = LoadLibrary (L"mfplat.dll");
+ (FARPROC &)pMFCreateMediaType = GetProcAddress(hLib, "MFCreateMediaType");
+ (FARPROC &)pMFInitMediaTypeFromAMMediaType = GetProcAddress(hLib, "MFInitMediaTypeFromAMMediaType");
+ (FARPROC &)pMFInitAMMediaTypeFromMFMediaType = GetProcAddress(hLib, "MFInitAMMediaTypeFromMFMediaType");
+
+ if (!pMFCreateMediaType || !pMFInitMediaTypeFromAMMediaType || !pMFInitAMMediaTypeFromMFMediaType)
+ {
+ hr = E_FAIL;
+ return;
+ }
+#endif
+
+ // Load Vista specifics DLLs
+ hLib = LoadLibrary (L"AVRT.dll");
+ pfAvSetMmThreadCharacteristicsW = hLib ? (PTR_AvSetMmThreadCharacteristicsW) GetProcAddress (hLib, "AvSetMmThreadCharacteristicsW") : NULL;
+ pfAvSetMmThreadPriority = hLib ? (PTR_AvSetMmThreadPriority) GetProcAddress (hLib, "AvSetMmThreadPriority") : NULL;
+ pfAvRevertMmThreadCharacteristics = hLib ? (PTR_AvRevertMmThreadCharacteristics) GetProcAddress (hLib, "AvRevertMmThreadCharacteristics") : NULL;
+
+ // Init DXVA manager
+ hr = pfDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DManager);
+ if (SUCCEEDED (hr))
+ {
+ hr = m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken);
+ if (!SUCCEEDED (hr))
+ {
+ _Error += L"m_pD3DManager->ResetDevice failed\n";
+ }
+ }
+ else
+ _Error += L"DXVA2CreateDirect3DDeviceManager9 failed\n";
+
+ CComPtr<IDirectXVideoDecoderService> pDecoderService;
+ HANDLE hDevice;
+ if (SUCCEEDED (m_pD3DManager->OpenDeviceHandle(&hDevice)) &&
+ SUCCEEDED (m_pD3DManager->GetVideoService (hDevice, __uuidof(IDirectXVideoDecoderService), (void**)&pDecoderService)))
+ {
+ TRACE_EVR ("EVR: DXVA2 : device handle = 0x%08x", hDevice);
+ HookDirectXVideoDecoderService (pDecoderService);
+
+ m_pD3DManager->CloseDeviceHandle (hDevice);
+ }
+
+
+ // Bufferize frame only with 3D texture!
+ if (s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D)
+ m_nNbDXSurface = max (min (s.iEvrBuffers, MAX_PICTURE_SLOTS-2), 4);
+ else
+ m_nNbDXSurface = 1;
+
+ ResetStats();
+ m_nRenderState = Shutdown;
+ m_fUseInternalTimer = false;
+ m_LastSetOutputRange = -1;
+ m_bPendingRenegotiate = false;
+ m_bPendingMediaFinished = false;
+ m_bWaitingSample = false;
+ m_pCurrentDisplaydSample = NULL;
+ m_nStepCount = 0;
+ m_dwVideoAspectRatioMode = MFVideoARMode_PreservePicture;
+ m_dwVideoRenderPrefs = (MFVideoRenderPrefs)0;
+ m_BorderColor = RGB (0,0,0);
+ m_bSignaledStarvation = false;
+ m_StarvationClock = 0;
+ m_pOuterEVR = NULL;
+ m_LastScheduledSampleTime = -1;
+ m_LastScheduledUncorrectedSampleTime = -1;
+ m_MaxSampleDuration = 0;
+ m_LastSampleOffset = 0;
+ ZeroMemory(m_VSyncOffsetHistory, sizeof(m_VSyncOffsetHistory));
+ m_VSyncOffsetHistoryPos = 0;
+ m_bLastSampleOffsetValid = false;
+}
+
+CEVRAllocatorPresenter::~CEVRAllocatorPresenter(void)
+{
+ StopWorkerThreads(); // If not already done...
+ m_pMediaType = NULL;
+ m_pClock = NULL;
+
+ m_pD3DManager = NULL;
+}
+
+
+void CEVRAllocatorPresenter::ResetStats()
+{
+ m_pcFrames = 0;
+ m_nDroppedUpdate = 0;
+ m_pcFramesDrawn = 0;
+ m_piAvg = 0;
+ m_piDev = 0;
+}
+
+
+HRESULT CEVRAllocatorPresenter::CheckShutdown() const
+{
+ if (m_nRenderState == Shutdown)
+ {
+ return MF_E_SHUTDOWN;
+ }
+ else
+ {
+ return S_OK;
+ }
+}
+
+
+void CEVRAllocatorPresenter::StartWorkerThreads()
+{
+ DWORD dwThreadId;
+
+ if (m_nRenderState == Shutdown)
+ {
+ m_hEvtQuit = CreateEvent (NULL, TRUE, FALSE, NULL);
+ m_hEvtFlush = CreateEvent (NULL, TRUE, FALSE, NULL);
+
+ m_hThread = ::CreateThread(NULL, 0, PresentThread, (LPVOID)this, 0, &dwThreadId);
+ SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL);
+ m_hGetMixerThread = ::CreateThread(NULL, 0, GetMixerThreadStatic, (LPVOID)this, 0, &dwThreadId);
+ SetThreadPriority(m_hGetMixerThread, THREAD_PRIORITY_HIGHEST);
+
+ m_nRenderState = Stopped;
+ TRACE_EVR ("EVR: Worker threads started...\n");
+ }
+}
+
+void CEVRAllocatorPresenter::StopWorkerThreads()
+{
+ if (m_nRenderState != Shutdown)
+ {
+ SetEvent (m_hEvtFlush);
+ m_bEvtFlush = true;
+ SetEvent (m_hEvtQuit);
+ m_bEvtQuit = true;
+ if ((m_hThread != INVALID_HANDLE_VALUE) && (WaitForSingleObject (m_hThread, 10000) == WAIT_TIMEOUT))
+ {
+ ASSERT (FALSE);
+ TerminateThread (m_hThread, 0xDEAD);
+ }
+ if ((m_hGetMixerThread != INVALID_HANDLE_VALUE) && (WaitForSingleObject (m_hGetMixerThread, 10000) == WAIT_TIMEOUT))
+ {
+ ASSERT (FALSE);
+ TerminateThread (m_hGetMixerThread, 0xDEAD);
+ }
+
+ if (m_hThread != INVALID_HANDLE_VALUE) CloseHandle (m_hThread);
+ if (m_hGetMixerThread != INVALID_HANDLE_VALUE) CloseHandle (m_hGetMixerThread);
+ if (m_hEvtFlush != INVALID_HANDLE_VALUE) CloseHandle (m_hEvtFlush);
+ if (m_hEvtQuit != INVALID_HANDLE_VALUE) CloseHandle (m_hEvtQuit);
+
+ m_bEvtFlush = false;
+ m_bEvtQuit = false;
+
+
+ TRACE_EVR ("EVR: Worker threads stopped...\n");
+ }
+ m_nRenderState = Shutdown;
+}
+
+
+STDMETHODIMP CEVRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer)
+{
+ CheckPointer(ppRenderer, E_POINTER);
+
+ *ppRenderer = NULL;
+
+ HRESULT hr = E_FAIL;
+
+ do
+ {
+ CMacrovisionKicker* pMK = DNew CMacrovisionKicker(NAME("CMacrovisionKicker"), NULL);
+ CComPtr<IUnknown> pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK;
+
+ COuterEVR *pOuterEVR = DNew COuterEVR(NAME("COuterEVR"), pUnk, hr, &m_VMR9AlphaBitmap, this);
+ m_pOuterEVR = pOuterEVR;
+
+ pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuterEVR);
+ CComQIPtr<IBaseFilter> pBF = pUnk;
+
+ if (FAILED (hr)) break;
+
+ // Set EVR custom presenter
+ CComPtr<IMFVideoPresenter> pVP;
+ CComPtr<IMFVideoRenderer> pMFVR;
+ CComQIPtr<IMFGetService, &__uuidof(IMFGetService)> pMFGS = pBF;
+
+ hr = pMFGS->GetService (MR_VIDEO_RENDER_SERVICE, IID_IMFVideoRenderer, (void**)&pMFVR);
+
+ if(SUCCEEDED(hr)) hr = QueryInterface (__uuidof(IMFVideoPresenter), (void**)&pVP);
+ if(SUCCEEDED(hr)) hr = pMFVR->InitializeRenderer (NULL, pVP);
+
+#if 1
+ CComPtr<IPin> pPin = GetFirstPin(pBF);
+ CComQIPtr<IMemInputPin> pMemInputPin = pPin;
+
+ // No NewSegment : no chocolate :o)
+ m_fUseInternalTimer = HookNewSegmentAndReceive((IPinC*)(IPin*)pPin, (IMemInputPinC*)(IMemInputPin*)pMemInputPin);
+#else
+ m_fUseInternalTimer = false;
+#endif
+
+ if(FAILED(hr))
+ *ppRenderer = NULL;
+ else
+ *ppRenderer = pBF.Detach();
+
+ }
+ while (0);
+
+ return hr;
+}
+
+STDMETHODIMP_(bool) CEVRAllocatorPresenter::Paint(bool fAll)
+{
+ return __super::Paint (fAll);
+}
+
+STDMETHODIMP CEVRAllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
+{
+ HRESULT hr;
+ if(riid == __uuidof(IMFClockStateSink))
+ hr = GetInterface((IMFClockStateSink*)this, ppv);
+ else if(riid == __uuidof(IMFVideoPresenter))
+ hr = GetInterface((IMFVideoPresenter*)this, ppv);
+ else if(riid == __uuidof(IMFTopologyServiceLookupClient))
+ hr = GetInterface((IMFTopologyServiceLookupClient*)this, ppv);
+ else if(riid == __uuidof(IMFVideoDeviceID))
+ hr = GetInterface((IMFVideoDeviceID*)this, ppv);
+ else if(riid == __uuidof(IMFGetService))
+ hr = GetInterface((IMFGetService*)this, ppv);
+ else if(riid == __uuidof(IMFAsyncCallback))
+ hr = GetInterface((IMFAsyncCallback*)this, ppv);
+ else if(riid == __uuidof(IMFVideoDisplayControl))
+ hr = GetInterface((IMFVideoDisplayControl*)this, ppv);
+ else if(riid == __uuidof(IEVRTrustedVideoPlugin))
+ hr = GetInterface((IEVRTrustedVideoPlugin*)this, ppv);
+ else if(riid == IID_IQualProp)
+ hr = GetInterface((IQualProp*)this, ppv);
+ else if(riid == __uuidof(IMFRateSupport))
+ hr = GetInterface((IMFRateSupport*)this, ppv);
+ else if(riid == __uuidof(IDirect3DDeviceManager9))
+// hr = GetInterface((IDirect3DDeviceManager9*)this, ppv);
+ hr = m_pD3DManager->QueryInterface (__uuidof(IDirect3DDeviceManager9), (void**) ppv);
+ else
+ hr = __super::NonDelegatingQueryInterface(riid, ppv);
+
+ return hr;
+}
+
+
+// IMFClockStateSink
+STDMETHODIMP CEVRAllocatorPresenter::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset)
+{
+ m_nRenderState = Started;
+
+ TRACE_EVR ("EVR: OnClockStart hnsSystemTime = %I64d, llClockStartOffset = %I64d\n", hnsSystemTime, llClockStartOffset);
+ m_ModeratedTimeLast = -1;
+ m_ModeratedClockLast = -1;
+
+ return S_OK;
+}
+
+STDMETHODIMP CEVRAllocatorPresenter::OnClockStop(MFTIME hnsSystemTime)
+{
+ TRACE_EVR ("EVR: OnClockStop hnsSystemTime = %I64d\n", hnsSystemTime);
+ m_nRenderState = Stopped;
+
+ m_ModeratedClockLast = -1;
+ m_ModeratedTimeLast = -1;
+ return S_OK;
+}
+
+STDMETHODIMP CEVRAllocatorPresenter::OnClockPause(MFTIME hnsSystemTime)
+{
+ TRACE_EVR ("EVR: OnClockPause hnsSystemTime = %I64d\n", hnsSystemTime);
+ if (!m_bSignaledStarvation)
+ m_nRenderState = Paused;
+ m_ModeratedTimeLast = -1;
+ m_ModeratedClockLast = -1;
+ return S_OK;
+}
+
+STDMETHODIMP CEVRAllocatorPresenter::OnClockRestart(MFTIME hnsSystemTime)
+{
+ m_nRenderState = Started;
+
+ m_ModeratedTimeLast = -1;
+ m_ModeratedClockLast = -1;
+ TRACE_EVR ("EVR: OnClockRestart hnsSystemTime = %I64d\n", hnsSystemTime);
+
+ return S_OK;
+}
+
+
+STDMETHODIMP CEVRAllocatorPresenter::OnClockSetRate(MFTIME hnsSystemTime, float flRate)
+{
+ ASSERT (FALSE);
+ return E_NOTIMPL;
+}
+
+
+// IBaseFilter delegate
+bool CEVRAllocatorPresenter::GetState( DWORD dwMilliSecsTimeout, FILTER_STATE *State, HRESULT &_ReturnValue)
+{
+ CAutoLock lock(&m_SampleQueueLock);
+
+ if (m_bSignaledStarvation)
+ {
+ int nSamples = max(m_nNbDXSurface / 2, 1);
+ if ((m_ScheduledSamples.GetCount() < nSamples || m_LastSampleOffset < -m_rtTimePerFrame*2) && !g_bNoDuration)
+ {
+ *State = (FILTER_STATE)Paused;
+ _ReturnValue = VFW_S_STATE_INTERMEDIATE;
+ return true;
+ }
+ m_bSignaledStarvation = false;
+ }
+ return false;
+}
+
+// IQualProp
+STDMETHODIMP CEVRAllocatorPresenter::get_FramesDroppedInRenderer(int *pcFrames)
+{
+ *pcFrames = m_pcFrames;
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::get_FramesDrawn(int *pcFramesDrawn)
+{
+ *pcFramesDrawn = m_pcFramesDrawn;
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::get_AvgFrameRate(int *piAvgFrameRate)
+{
+ *piAvgFrameRate = (int)(m_fAvrFps * 100);
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::get_Jitter(int *iJitter)
+{
+ *iJitter = (int)((m_fJitterStdDev/10000.0) + 0.5);
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::get_AvgSyncOffset(int *piAvg)
+{
+ *piAvg = (int)((m_fSyncOffsetAvr/10000.0) + 0.5);
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::get_DevSyncOffset(int *piDev)
+{
+ *piDev = (int)((m_fSyncOffsetStdDev/10000.0) + 0.5);
+ return S_OK;
+}
+
+
+// IMFRateSupport
+STDMETHODIMP CEVRAllocatorPresenter::GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float *pflRate)
+{
+ // TODO : not finished...
+ *pflRate = 0;
+ return S_OK;
+}
+
+STDMETHODIMP CEVRAllocatorPresenter::GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float *pflRate)
+{
+ HRESULT hr = S_OK;
+ float fMaxRate = 0.0f;
+
+ CAutoLock lock(this);
+
+ CheckPointer(pflRate, E_POINTER);
+ CheckHR(CheckShutdown());
+
+ // Get the maximum forward rate.
+ fMaxRate = GetMaxRate(fThin);
+
+ // For reverse playback, swap the sign.
+ if (eDirection == MFRATE_REVERSE)
+ fMaxRate = -fMaxRate;
+
+ *pflRate = fMaxRate;
+
+ return hr;
+}
+
+STDMETHODIMP CEVRAllocatorPresenter::IsRateSupported(BOOL fThin, float flRate, float *pflNearestSupportedRate)
+{
+ // fRate can be negative for reverse playback.
+ // pfNearestSupportedRate can be NULL.
+
+ CAutoLock lock(this);
+
+ HRESULT hr = S_OK;
+ float fMaxRate = 0.0f;
+ float fNearestRate = flRate; // Default.
+
+ CheckPointer (pflNearestSupportedRate, E_POINTER);
+ CheckHR(hr = CheckShutdown());
+
+ // Find the maximum forward rate.
+ fMaxRate = GetMaxRate(fThin);
+
+ if (fabsf(flRate) > fMaxRate)
+ {
+ // The (absolute) requested rate exceeds the maximum rate.
+ hr = MF_E_UNSUPPORTED_RATE;
+
+ // The nearest supported rate is fMaxRate.
+ fNearestRate = fMaxRate;
+ if (flRate < 0)
+ {
+ // For reverse playback, swap the sign.
+ fNearestRate = -fNearestRate;
+ }
+ }
+
+ // Return the nearest supported rate if the caller requested it.
+ if (pflNearestSupportedRate != NULL)
+ *pflNearestSupportedRate = fNearestRate;
+
+ return hr;
+}
+
+
+float CEVRAllocatorPresenter::GetMaxRate(BOOL bThin)
+{
+ float fMaxRate = FLT_MAX; // Default.
+ UINT32 fpsNumerator = 0, fpsDenominator = 0;
+ UINT MonitorRateHz = 0;
+
+ if (!bThin && (m_pMediaType != NULL))
+ {
+ // Non-thinned: Use the frame rate and monitor refresh rate.
+
+ // Frame rate:
+ MFGetAttributeRatio(m_pMediaType, MF_MT_FRAME_RATE,
+ &fpsNumerator, &fpsDenominator);
+
+ // Monitor refresh rate:
+ MonitorRateHz = m_RefreshRate; // D3DDISPLAYMODE
+
+ if (fpsDenominator && fpsNumerator && MonitorRateHz)
+ {
+ // Max Rate = Refresh Rate / Frame Rate
+ fMaxRate = (float)MulDiv(
+ MonitorRateHz, fpsDenominator, fpsNumerator);
+ }
+ }
+ return fMaxRate;
+}
+
+void CEVRAllocatorPresenter::CompleteFrameStep(bool bCancel)
+{
+ if (m_nStepCount > 0)
+ {
+ if (bCancel || (m_nStepCount == 1))
+ {
+ m_pSink->Notify(EC_STEP_COMPLETE, bCancel ? TRUE : FALSE, 0);
+ m_nStepCount = 0;
+ }
+ else
+ m_nStepCount--;
+ }
+}
+
+// IMFVideoPresenter
+STDMETHODIMP CEVRAllocatorPresenter::ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam)
+{
+ HRESULT hr = S_OK;
+
+ switch (eMessage)
+ {
+ case MFVP_MESSAGE_BEGINSTREAMING : // The EVR switched from stopped to paused. The presenter should allocate resources
+ ResetStats();
+ TRACE_EVR ("EVR: MFVP_MESSAGE_BEGINSTREAMING\n");
+ break;
+
+ case MFVP_MESSAGE_CANCELSTEP : // Cancels a frame step
+ TRACE_EVR ("EVR: MFVP_MESSAGE_CANCELSTEP\n");
+ CompleteFrameStep (true);
+ break;
+
+ case MFVP_MESSAGE_ENDOFSTREAM : // All input streams have ended.
+ TRACE_EVR ("EVR: MFVP_MESSAGE_ENDOFSTREAM\n");
+ m_bPendingMediaFinished = true;
+ break;
+
+ case MFVP_MESSAGE_ENDSTREAMING : // The EVR switched from running or paused to stopped. The presenter should free resources
+ TRACE_EVR ("EVR: MFVP_MESSAGE_ENDSTREAMING\n");
+ break;
+
+ case MFVP_MESSAGE_FLUSH : // The presenter should discard any pending samples
+ SetEvent(m_hEvtFlush);
+ m_bEvtFlush = true;
+ TRACE_EVR ("EVR: MFVP_MESSAGE_FLUSH\n");
+ while (WaitForSingleObject(m_hEvtFlush, 1) == WAIT_OBJECT_0);
+ break;
+
+ case MFVP_MESSAGE_INVALIDATEMEDIATYPE : // The mixer's output format has changed. The EVR will initiate format negotiation, as described previously
+ /*
+ 1) The EVR sets the media type on the reference stream.
+ 2) The EVR calls IMFVideoPresenter::ProcessMessage on the presenter with the MFVP_MESSAGE_INVALIDATEMEDIATYPE message.
+ 3) The presenter sets the media type on the mixer's output stream.
+ 4) The EVR sets the media type on the substreams.
+ */
+ m_bPendingRenegotiate = true;
+ while (*((volatile bool *)&m_bPendingRenegotiate))
+ Sleep(1);
+ break;
+
+ case MFVP_MESSAGE_PROCESSINPUTNOTIFY : // One input stream on the mixer has received a new sample
+// GetImageFromMixer();
+ break;
+
+ case MFVP_MESSAGE_STEP : // Requests a frame step.
+ TRACE_EVR ("EVR: MFVP_MESSAGE_STEP\n");
+ m_nStepCount = ulParam;
+ hr = S_OK;
+ break;
+
+ default :
+ ASSERT (FALSE);
+ break;
+ }
+ return hr;
+}
+
+
+HRESULT CEVRAllocatorPresenter::IsMediaTypeSupported(IMFMediaType* pMixerType)
+{
+ HRESULT hr;
+ AM_MEDIA_TYPE* pAMMedia;
+ UINT nInterlaceMode;
+
+ CheckHR (pMixerType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia));
+ CheckHR (pMixerType->GetUINT32 (MF_MT_INTERLACE_MODE, &nInterlaceMode));
+
+
+ /* if ( (pAMMedia->majortype != MEDIATYPE_Video) ||
+ (nInterlaceMode != MFVideoInterlace_Progressive) ||
+ ( (pAMMedia->subtype != MEDIASUBTYPE_RGB32) && (pAMMedia->subtype != MEDIASUBTYPE_RGB24) &&
+ (pAMMedia->subtype != MEDIASUBTYPE_YUY2) && (pAMMedia->subtype != MEDIASUBTYPE_NV12) ) )
+ hr = MF_E_INVALIDMEDIATYPE;*/
+ if ( (pAMMedia->majortype != MEDIATYPE_Video))
+ hr = MF_E_INVALIDMEDIATYPE;
+ pMixerType->FreeRepresentation (FORMAT_VideoInfo2, (void*)pAMMedia);
+ return hr;
+}
+
+
+HRESULT CEVRAllocatorPresenter::CreateProposedOutputType(IMFMediaType* pMixerType, IMFMediaType** pType)
+{
+ HRESULT hr;
+ AM_MEDIA_TYPE* pAMMedia = NULL;
+ LARGE_INTEGER i64Size;
+ MFVIDEOFORMAT* VideoFormat;
+
+ CheckHR (pMixerType->GetRepresentation (FORMAT_MFVideoFormat, (void**)&pAMMedia));
+
+ VideoFormat = (MFVIDEOFORMAT*)pAMMedia->pbFormat;
+ hr = pfMFCreateVideoMediaType (VideoFormat, &m_pMediaType);
+
+ if (0)
+ {
+ // This code doesn't work, use same method as VMR9 instead
+ if (VideoFormat->videoInfo.FramesPerSecond.Numerator != 0)
+ {
+ switch (VideoFormat->videoInfo.InterlaceMode)
+ {
+ case MFVideoInterlace_Progressive:
+ case MFVideoInterlace_MixedInterlaceOrProgressive:
+ default:
+ {
+ m_rtTimePerFrame = (10000000I64*VideoFormat->videoInfo.FramesPerSecond.Denominator)/VideoFormat->videoInfo.FramesPerSecond.Numerator;
+ m_bInterlaced = false;
+ }
+ break;
+ case MFVideoInterlace_FieldSingleUpper:
+ case MFVideoInterlace_FieldSingleLower:
+ case MFVideoInterlace_FieldInterleavedUpperFirst:
+ case MFVideoInterlace_FieldInterleavedLowerFirst:
+ {
+ m_rtTimePerFrame = (20000000I64*VideoFormat->videoInfo.FramesPerSecond.Denominator)/VideoFormat->videoInfo.FramesPerSecond.Numerator;
+ m_bInterlaced = true;
+ }
+ break;
+ }
+ }
+ }
+
+ m_AspectRatio.cx = VideoFormat->videoInfo.PixelAspectRatio.Numerator;
+ m_AspectRatio.cy = VideoFormat->videoInfo.PixelAspectRatio.Denominator;
+
+ if (SUCCEEDED (hr))
+ {
+ i64Size.HighPart = VideoFormat->videoInfo.dwWidth;
+ i64Size.LowPart = VideoFormat->videoInfo.dwHeight;
+ m_pMediaType->SetUINT64 (MF_MT_FRAME_SIZE, i64Size.QuadPart);
+
+ m_pMediaType->SetUINT32 (MF_MT_PAN_SCAN_ENABLED, 0);
+
+ CRenderersSettings& s = GetRenderersSettings();
+
+#if 1
+ if (s.m_RenderSettings.iEVROutputRange == 1)
+ m_pMediaType->SetUINT32 (MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_16_235);
+ else
+ m_pMediaType->SetUINT32 (MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_0_255);
+
+// m_pMediaType->SetUINT32 (MF_MT_TRANSFER_FUNCTION, MFVideoTransFunc_10);
+
+#else
+
+ m_pMediaType->SetUINT32 (MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_0_255);
+ if (s.iEVROutputRange == 1)
+ m_pMediaType->SetUINT32 (MF_MT_YUV_MATRIX, MFVideoTransferMatrix_BT601);
+ else
+ m_pMediaType->SetUINT32 (MF_MT_YUV_MATRIX, MFVideoTransferMatrix_BT709);
+#endif
+
+
+ m_LastSetOutputRange = s.m_RenderSettings.iEVROutputRange;
+
+ i64Size.HighPart = m_AspectRatio.cx;
+ i64Size.LowPart = m_AspectRatio.cy;
+ m_pMediaType->SetUINT64 (MF_MT_PIXEL_ASPECT_RATIO, i64Size.QuadPart);
+
+ MFVideoArea Area = MakeArea (0, 0, VideoFormat->videoInfo.dwWidth, VideoFormat->videoInfo.dwHeight);
+ m_pMediaType->SetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&Area, sizeof(MFVideoArea));
+
+ }
+
+ m_AspectRatio.cx *= VideoFormat->videoInfo.dwWidth;
+ m_AspectRatio.cy *= VideoFormat->videoInfo.dwHeight;
+
+ bool bDoneSomething = true;
+
+ if(m_AspectRatio.cx >= 1 && m_AspectRatio.cy >= 1) //if any of these is 0, it will stuck into a infinite loop
+ {
+ while (bDoneSomething)
+ {
+ bDoneSomething = false;
+ INT MinNum = min(m_AspectRatio.cx, m_AspectRatio.cy);
+ INT i;
+ for (i = 2; i < MinNum+1; ++i)
+ {
+ if (m_AspectRatio.cx%i == 0 && m_AspectRatio.cy%i ==0)
+ break;
+ }
+ if (i != MinNum + 1)
+ {
+ m_AspectRatio.cx = m_AspectRatio.cx / i;
+ m_AspectRatio.cy = m_AspectRatio.cy / i;
+ bDoneSomething = true;
+ }
+ }
+ }
+
+ pMixerType->FreeRepresentation (FORMAT_MFVideoFormat, (void*)pAMMedia);
+ m_pMediaType->QueryInterface (__uuidof(IMFMediaType), (void**) pType);
+
+ return hr;
+}
+
+HRESULT CEVRAllocatorPresenter::SetMediaType(IMFMediaType* pType)
+{
+ HRESULT hr;
+ AM_MEDIA_TYPE* pAMMedia = NULL;
+ CString strTemp;
+
+ CheckPointer (pType, E_POINTER);
+ CheckHR (pType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia));
+
+ hr = InitializeDevice (pAMMedia);
+ if (SUCCEEDED (hr))
+ {
+ strTemp = GetMediaTypeName (pAMMedia->subtype);
+ strTemp.Replace (L"MEDIASUBTYPE_", L"");
+ m_strStatsMsg[MSG_MIXEROUT].Format (L"Mixer output : %s", strTemp);
+ }
+
+ pType->FreeRepresentation (FORMAT_VideoInfo2, (void*)pAMMedia);
+
+ return hr;
+}
+
+LONGLONG GetMediaTypeMerit(IMFMediaType *pMediaType)
+{
+ AM_MEDIA_TYPE* pAMMedia = NULL;
+ MFVIDEOFORMAT* VideoFormat;
+
+ HRESULT hr;
+ CheckHR (pMediaType->GetRepresentation (FORMAT_MFVideoFormat, (void**)&pAMMedia));
+ VideoFormat = (MFVIDEOFORMAT*)pAMMedia->pbFormat;
+
+ LONGLONG Merit = 0;
+ switch (VideoFormat->surfaceInfo.Format)
+ {
+ case FCC('NV12'):
+ Merit = 90000000;
+ break;
+ case FCC('YV12'):
+ Merit = 80000000;
+ break;
+ case FCC('YUY2'):
+ Merit = 70000000;
+ break;
+ case FCC('UYVY'):
+ Merit = 60000000;
+ break;
+
+ case D3DFMT_X8R8G8B8: // Never opt for RGB
+ case D3DFMT_A8R8G8B8:
+ case D3DFMT_R8G8B8:
+ case D3DFMT_R5G6B5:
+ Merit = 0;
+ break;
+ default:
+ Merit = 1000;
+ break;
+ }
+
+ pMediaType->FreeRepresentation (FORMAT_MFVideoFormat, (void*)pAMMedia);
+
+ return Merit;
+}
+
+LPCTSTR FindD3DFormat(const D3DFORMAT Format);
+
+LPCTSTR GetMediaTypeFormatDesc(IMFMediaType *pMediaType)
+{
+ AM_MEDIA_TYPE* pAMMedia = NULL;
+ MFVIDEOFORMAT* VideoFormat;
+
+ HRESULT hr;
+ hr = pMediaType->GetRepresentation (FORMAT_MFVideoFormat, (void**)&pAMMedia);
+ VideoFormat = (MFVIDEOFORMAT*)pAMMedia->pbFormat;
+
+ LPCTSTR Type = FindD3DFormat((D3DFORMAT)VideoFormat->surfaceInfo.Format);
+
+ pMediaType->FreeRepresentation (FORMAT_MFVideoFormat, (void*)pAMMedia);
+
+ return Type;
+}
+
+HRESULT CEVRAllocatorPresenter::RenegotiateMediaType()
+{
+ HRESULT hr = S_OK;
+
+ CComPtr<IMFMediaType> pMixerType;
+ CComPtr<IMFMediaType> pType;
+
+ if (!m_pMixer)
+ {
+ return MF_E_INVALIDREQUEST;
+ }
+
+ CInterfaceArray<IMFMediaType> ValidMixerTypes;
+
+ // Loop through all of the mixer's proposed output types.
+ DWORD iTypeIndex = 0;
+ while ((hr != MF_E_NO_MORE_TYPES))
+ {
+ pMixerType = NULL;
+ pType = NULL;
+ m_pMediaType = NULL;
+
+ // Step 1. Get the next media type supported by mixer.
+ hr = m_pMixer->GetOutputAvailableType(0, iTypeIndex++, &pMixerType);
+ if (FAILED(hr))
+ {
+ break;
+ }
+
+ // Step 2. Check if we support this media type.
+ if (SUCCEEDED(hr))
+ hr = IsMediaTypeSupported(pMixerType);
+
+ if (SUCCEEDED(hr))
+ hr = CreateProposedOutputType(pMixerType, &pType);
+
+ // Step 4. Check if the mixer will accept this media type.
+ if (SUCCEEDED(hr))
+ hr = m_pMixer->SetOutputType(0, pType, MFT_SET_TYPE_TEST_ONLY);
+
+ if (SUCCEEDED(hr))
+ {
+ LONGLONG Merit = GetMediaTypeMerit(pType);
+
+ int nTypes = ValidMixerTypes.GetCount();
+ int iInsertPos = 0;
+ for (int i = 0; i < nTypes; ++i)
+ {
+ LONGLONG ThisMerit = GetMediaTypeMerit(ValidMixerTypes[i]);
+ if (Merit > ThisMerit)
+ {
+ iInsertPos = i;
+ break;
+ }
+ else
+ iInsertPos = i+1;
+ }
+
+ ValidMixerTypes.InsertAt(iInsertPos, pType);
+ }
+ }
+
+
+ int nValidTypes = ValidMixerTypes.GetCount();
+ for (int i = 0; i < nValidTypes; ++i)
+ {
+ // Step 3. Adjust the mixer's type to match our requirements.
+ pType = ValidMixerTypes[i];
+ TRACE_EVR("EVR: Valid mixer output type: %ws\n", GetMediaTypeFormatDesc(pType));
+ }
+
+ for (int i = 0; i < nValidTypes; ++i)
+ {
+ // Step 3. Adjust the mixer's type to match our requirements.
+ pType = ValidMixerTypes[i];
+
+
+ TRACE_EVR("EVR: Trying mixer output type: %ws\n", GetMediaTypeFormatDesc(pType));
+
+ // Step 5. Try to set the media type on ourselves.
+ hr = SetMediaType(pType);
+
+ // Step 6. Set output media type on mixer.
+ if (SUCCEEDED(hr))
+ {
+ hr = m_pMixer->SetOutputType(0, pType, 0);
+
+ // If something went wrong, clear the media type.
+ if (FAILED(hr))
+ {
+ SetMediaType(NULL);
+ }
+ else
+ break;
+ }
+ }
+
+ pMixerType = NULL;
+ pType = NULL;
+ return hr;
+}
+
+
+bool CEVRAllocatorPresenter::GetImageFromMixer()
+{
+ MFT_OUTPUT_DATA_BUFFER Buffer;
+ HRESULT hr = S_OK;
+ DWORD dwStatus;
+ REFERENCE_TIME nsSampleTime;
+ LONGLONG llClockBefore = 0;
+ LONGLONG llClockAfter = 0;
+ LONGLONG llMixerLatency;
+ UINT dwSurface;
+
+ bool bDoneSomething = false;
+
+ while (SUCCEEDED(hr))
+ {
+ CComPtr<IMFSample> pSample;
+
+ if (FAILED (GetFreeSample (&pSample)))
+ {
+ m_bWaitingSample = true;
+ break;
+ }
+
+ memset (&Buffer, 0, sizeof(Buffer));
+ Buffer.pSample = pSample;
+ pSample->GetUINT32 (GUID_SURFACE_INDEX, &dwSurface);
+
+ {
+ llClockBefore = GetRenderersData()->GetPerfCounter();
+ hr = m_pMixer->ProcessOutput (0 , 1, &Buffer, &dwStatus);
+ llClockAfter = GetRenderersData()->GetPerfCounter();
+ }
+
+ if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
+ {
+ MoveToFreeList (pSample, false);
+ break;
+ }
+
+ if (m_pSink)
+ {
+ //CAutoLock autolock(this); We shouldn't need to lock here, m_pSink is thread safe
+ llMixerLatency = llClockAfter - llClockBefore;
+ m_pSink->Notify (EC_PROCESSING_LATENCY, (LONG_PTR)&llMixerLatency, 0);
+ }
+
+ pSample->GetSampleTime (&nsSampleTime);
+ REFERENCE_TIME nsDuration;
+ pSample->GetSampleDuration (&nsDuration);
+
+ if (GetRenderersData()->m_fTearingTest)
+ {
+ RECT rcTearing;
+
+ rcTearing.left = m_nTearingPos;
+ rcTearing.top = 0;
+ rcTearing.right = rcTearing.left + 4;
+ rcTearing.bottom = m_NativeVideoSize.cy;
+ m_pD3DDev->ColorFill (m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB (255,255,0,0));
+
+ rcTearing.left = (rcTearing.right + 15) % m_NativeVideoSize.cx;
+ rcTearing.right = rcTearing.left + 4;
+ m_pD3DDev->ColorFill (m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB (255,255,0,0));
+ m_nTearingPos = (m_nTearingPos + 7) % m_NativeVideoSize.cx;
+ }
+
+ LONGLONG TimePerFrame = m_rtTimePerFrame;
+ TRACE_EVR ("EVR: Get from Mixer : %d (%I64d) (%I64d)\n", dwSurface, nsSampleTime, TimePerFrame!=0?nsSampleTime/TimePerFrame:0);
+
+ MoveToScheduledList (pSample, false);
+ bDoneSomething = true;
+ if (m_rtTimePerFrame == 0)
+ break;
+ }
+
+ return bDoneSomething;
+}
+
+
+
+STDMETHODIMP CEVRAllocatorPresenter::GetCurrentMediaType(__deref_out IMFVideoMediaType **ppMediaType)
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(this); // Hold the critical section.
+
+ CheckPointer (ppMediaType, E_POINTER);
+ CheckHR (CheckShutdown());
+
+ if (m_pMediaType == NULL)
+ CheckHR(MF_E_NOT_INITIALIZED);
+
+ CheckHR(m_pMediaType->QueryInterface( __uuidof(IMFVideoMediaType), (void**)&ppMediaType));
+
+ return hr;
+}
+
+
+
+// IMFTopologyServiceLookupClient
+STDMETHODIMP CEVRAllocatorPresenter::InitServicePointers(/* [in] */ __in IMFTopologyServiceLookup *pLookup)
+{
+ HRESULT hr;
+ DWORD dwObjects = 1;
+
+ TRACE_EVR ("EVR: CEVRAllocatorPresenter::InitServicePointers\n");
+ hr = pLookup->LookupService (MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_MIXER_SERVICE,
+ __uuidof (IMFTransform), (void**)&m_pMixer, &dwObjects);
+
+ hr = pLookup->LookupService (MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE,
+ __uuidof (IMediaEventSink ), (void**)&m_pSink, &dwObjects);
+
+ hr = pLookup->LookupService (MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE,
+ __uuidof (IMFClock ), (void**)&m_pClock, &dwObjects);
+
+
+ StartWorkerThreads();
+ return S_OK;
+}
+
+STDMETHODIMP CEVRAllocatorPresenter::ReleaseServicePointers()
+{
+ TRACE_EVR ("EVR: CEVRAllocatorPresenter::ReleaseServicePointers\n");
+ StopWorkerThreads();
+ m_pMixer = NULL;
+ m_pSink = NULL;
+ m_pClock = NULL;
+ return S_OK;
+}
+
+
+// IMFVideoDeviceID
+STDMETHODIMP CEVRAllocatorPresenter::GetDeviceID(/* [out] */ __out IID *pDeviceID)
+{
+ CheckPointer(pDeviceID, E_POINTER);
+ *pDeviceID = IID_IDirect3DDevice9;
+ return S_OK;
+}
+
+
+// IMFGetService
+STDMETHODIMP CEVRAllocatorPresenter::GetService (/* [in] */ __RPC__in REFGUID guidService,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */ __RPC__deref_out_opt LPVOID *ppvObject)
+{
+ if (guidService == MR_VIDEO_RENDER_SERVICE)
+ return NonDelegatingQueryInterface (riid, ppvObject);
+ else if (guidService == MR_VIDEO_ACCELERATION_SERVICE)
+ return m_pD3DManager->QueryInterface (__uuidof(IDirect3DDeviceManager9), (void**) ppvObject);
+
+ return E_NOINTERFACE;
+}
+
+
+// IMFAsyncCallback
+STDMETHODIMP CEVRAllocatorPresenter::GetParameters( /* [out] */ __RPC__out DWORD *pdwFlags, /* [out] */ __RPC__out DWORD *pdwQueue)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CEVRAllocatorPresenter::Invoke ( /* [in] */ __RPC__in_opt IMFAsyncResult *pAsyncResult)
+{
+ return E_NOTIMPL;
+}
+
+
+// IMFVideoDisplayControl
+STDMETHODIMP CEVRAllocatorPresenter::GetNativeVideoSize(SIZE *pszVideo, SIZE *pszARVideo)
+{
+ if (pszVideo)
+ {
+ pszVideo->cx = m_NativeVideoSize.cx;
+ pszVideo->cy = m_NativeVideoSize.cy;
+ }
+ if (pszARVideo)
+ {
+ pszARVideo->cx = m_NativeVideoSize.cx * m_AspectRatio.cx;
+ pszARVideo->cy = m_NativeVideoSize.cy * m_AspectRatio.cy;
+ }
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::GetIdealVideoSize(SIZE *pszMin, SIZE *pszMax)
+{
+ if (pszMin)
+ {
+ pszMin->cx = 1;
+ pszMin->cy = 1;
+ }
+
+ if (pszMax)
+ {
+ D3DDISPLAYMODE d3ddm;
+
+ ZeroMemory(&d3ddm, sizeof(d3ddm));
+ if(SUCCEEDED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D), &d3ddm)))
+ {
+ pszMax->cx = d3ddm.Width;
+ pszMax->cy = d3ddm.Height;
+ }
+ }
+
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::SetVideoPosition(const MFVideoNormalizedRect *pnrcSource, const LPRECT prcDest)
+{
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::GetVideoPosition(MFVideoNormalizedRect *pnrcSource, LPRECT prcDest)
+{
+ // Always all source rectangle ?
+ if (pnrcSource)
+ {
+ pnrcSource->left = 0.0;
+ pnrcSource->top = 0.0;
+ pnrcSource->right = 1.0;
+ pnrcSource->bottom = 1.0;
+ }
+
+ if (prcDest)
+ memcpy (prcDest, &m_VideoRect, sizeof(m_VideoRect));//GetClientRect (m_hWnd, prcDest);
+
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::SetAspectRatioMode(DWORD dwAspectRatioMode)
+{
+ m_dwVideoAspectRatioMode = (MFVideoAspectRatioMode)dwAspectRatioMode;
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::GetAspectRatioMode(DWORD *pdwAspectRatioMode)
+{
+ CheckPointer (pdwAspectRatioMode, E_POINTER);
+ *pdwAspectRatioMode = m_dwVideoAspectRatioMode;
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::SetVideoWindow(HWND hwndVideo)
+{
+ ASSERT (m_hWnd == hwndVideo); // What if not ??
+// m_hWnd = hwndVideo;
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::GetVideoWindow(HWND *phwndVideo)
+{
+ CheckPointer (phwndVideo, E_POINTER);
+ *phwndVideo = m_hWnd;
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::RepaintVideo()
+{
+ Paint (true);
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::GetCurrentImage(BITMAPINFOHEADER *pBih, BYTE **pDib, DWORD *pcbDib, LONGLONG *pTimeStamp)
+{
+ ASSERT (FALSE);
+ return E_NOTIMPL;
+}
+STDMETHODIMP CEVRAllocatorPresenter::SetBorderColor(COLORREF Clr)
+{
+ m_BorderColor = Clr;
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::GetBorderColor(COLORREF *pClr)
+{
+ CheckPointer (pClr, E_POINTER);
+ *pClr = m_BorderColor;
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::SetRenderingPrefs(DWORD dwRenderFlags)
+{
+ m_dwVideoRenderPrefs = (MFVideoRenderPrefs)dwRenderFlags;
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::GetRenderingPrefs(DWORD *pdwRenderFlags)
+{
+ CheckPointer(pdwRenderFlags, E_POINTER);
+ *pdwRenderFlags = m_dwVideoRenderPrefs;
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::SetFullscreen(BOOL fFullscreen)
+{
+ ASSERT (FALSE);
+ return E_NOTIMPL;
+}
+STDMETHODIMP CEVRAllocatorPresenter::GetFullscreen(BOOL *pfFullscreen)
+{
+ ASSERT (FALSE);
+ return E_NOTIMPL;
+}
+
+
+// IEVRTrustedVideoPlugin
+STDMETHODIMP CEVRAllocatorPresenter::IsInTrustedVideoMode(BOOL *pYes)
+{
+ CheckPointer(pYes, E_POINTER);
+ *pYes = TRUE;
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::CanConstrict(BOOL *pYes)
+{
+ CheckPointer(pYes, E_POINTER);
+ *pYes = TRUE;
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::SetConstriction(DWORD dwKPix)
+{
+ return S_OK;
+}
+STDMETHODIMP CEVRAllocatorPresenter::DisableImageExport(BOOL bDisable)
+{
+ return S_OK;
+}
+
+
+// IDirect3DDeviceManager9
+STDMETHODIMP CEVRAllocatorPresenter::ResetDevice(IDirect3DDevice9 *pDevice,UINT resetToken)
+{
+ HRESULT hr = m_pD3DManager->ResetDevice (pDevice, resetToken);
+ return hr;
+}
+STDMETHODIMP CEVRAllocatorPresenter::OpenDeviceHandle(HANDLE *phDevice)
+{
+ HRESULT hr = m_pD3DManager->OpenDeviceHandle (phDevice);
+ return hr;
+}
+STDMETHODIMP CEVRAllocatorPresenter::CloseDeviceHandle(HANDLE hDevice)
+{
+ HRESULT hr = m_pD3DManager->CloseDeviceHandle(hDevice);
+ return hr;
+}
+STDMETHODIMP CEVRAllocatorPresenter::TestDevice(HANDLE hDevice)
+{
+ HRESULT hr = m_pD3DManager->TestDevice(hDevice);
+ return hr;
+}
+STDMETHODIMP CEVRAllocatorPresenter::LockDevice(HANDLE hDevice, IDirect3DDevice9 **ppDevice, BOOL fBlock)
+{
+ HRESULT hr = m_pD3DManager->LockDevice(hDevice, ppDevice, fBlock);
+ return hr;
+}
+STDMETHODIMP CEVRAllocatorPresenter::UnlockDevice(HANDLE hDevice, BOOL fSaveState)
+{
+ HRESULT hr = m_pD3DManager->UnlockDevice(hDevice, fSaveState);
+ return hr;
+}
+STDMETHODIMP CEVRAllocatorPresenter::GetVideoService(HANDLE hDevice, REFIID riid, void **ppService)
+{
+ HRESULT hr = m_pD3DManager->GetVideoService(hDevice, riid, ppService);
+
+ if (riid == __uuidof(IDirectXVideoDecoderService))
+ {
+ UINT nNbDecoder = 5;
+ GUID* pDecoderGuid;
+ IDirectXVideoDecoderService* pDXVAVideoDecoder = (IDirectXVideoDecoderService*) *ppService;
+ pDXVAVideoDecoder->GetDecoderDeviceGuids (&nNbDecoder, &pDecoderGuid);
+ }
+ else if (riid == __uuidof(IDirectXVideoProcessorService))
+ {
+ IDirectXVideoProcessorService* pDXVAProcessor = (IDirectXVideoProcessorService*) *ppService;
+ }
+
+ return hr;
+}
+
+
+STDMETHODIMP CEVRAllocatorPresenter::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight)
+{
+ // This function should be called...
+ ASSERT (FALSE);
+
+ 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 CEVRAllocatorPresenter::InitializeDevice(AM_MEDIA_TYPE* pMediaType)
+{
+ HRESULT hr;
+ CAutoLock lock(this);
+ CAutoLock lock2(&m_ImageProcessingLock);
+ CAutoLock cRenderLock(&m_RenderLock);
+
+ RemoveAllSamples();
+ DeleteSurfaces();
+
+ VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*) pMediaType->pbFormat;
+ int w = vih2->bmiHeader.biWidth;
+ int h = abs(vih2->bmiHeader.biHeight);
+
+ m_NativeVideoSize = CSize(w, h);
+ if (m_bHighColorResolution)
+ hr = AllocSurfaces(D3DFMT_A2R10G10B10);
+ else
+ hr = AllocSurfaces(D3DFMT_X8R8G8B8);
+
+
+ for(int i = 0; i < m_nNbDXSurface; i++)
+ {
+ CComPtr<IMFSample> pMFSample;
+ hr = pfMFCreateVideoSampleFromSurface (m_pVideoSurface[i], &pMFSample);
+
+ if (SUCCEEDED (hr))
+ {
+ pMFSample->SetUINT32 (GUID_SURFACE_INDEX, i);
+ m_FreeSamples.AddTail (pMFSample);
+ }
+ ASSERT (SUCCEEDED (hr));
+ }
+
+
+ return hr;
+}
+
+
+DWORD WINAPI CEVRAllocatorPresenter::GetMixerThreadStatic(LPVOID lpParam)
+{
+ SetThreadName(-1, "CEVRPresenter::MixerThread");
+ CEVRAllocatorPresenter* pThis = (CEVRAllocatorPresenter*) lpParam;
+ pThis->GetMixerThread();
+ return 0;
+}
+
+
+DWORD WINAPI CEVRAllocatorPresenter::PresentThread(LPVOID lpParam)
+{
+ SetThreadName(-1, "CEVRPresenter::PresentThread");
+ CEVRAllocatorPresenter* pThis = (CEVRAllocatorPresenter*) lpParam;
+ pThis->RenderThread();
+ return 0;
+}
+
+
+void CEVRAllocatorPresenter::CheckWaitingSampleFromMixer()
+{
+ if (m_bWaitingSample)
+ {
+ m_bWaitingSample = false;
+ //GetImageFromMixer(); // Do this in processing thread instead
+ }
+}
+
+
+bool ExtractInterlaced(const AM_MEDIA_TYPE* pmt)
+{
+ if (pmt->formattype==FORMAT_VideoInfo)
+ return false;
+ else if (pmt->formattype==FORMAT_VideoInfo2)
+ return (((VIDEOINFOHEADER2*)pmt->pbFormat)->dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0;
+ else if (pmt->formattype==FORMAT_MPEGVideo)
+ return false;
+ else if (pmt->formattype==FORMAT_MPEG2Video)
+ return (((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr.dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0;
+ else
+ return false;
+}
+
+
+void CEVRAllocatorPresenter::GetMixerThread()
+{
+ HANDLE hAvrt;
+ HANDLE hEvts[] = { m_hEvtQuit};
+ bool bQuit = false;
+ TIMECAPS tc;
+ DWORD dwResolution;
+ DWORD dwUser = 0;
+ DWORD dwTaskIndex = 0;
+
+ // Tell Vista Multimedia Class Scheduler we are a playback thretad (increase priority)
+// if (pfAvSetMmThreadCharacteristicsW)
+// hAvrt = pfAvSetMmThreadCharacteristicsW (L"Playback", &dwTaskIndex);
+// if (pfAvSetMmThreadPriority)
+// pfAvSetMmThreadPriority (hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/);
+
+ timeGetDevCaps(&tc, sizeof(TIMECAPS));
+ dwResolution = min(max(tc.wPeriodMin, 0), tc.wPeriodMax);
+ dwUser = timeBeginPeriod(dwResolution);
+
+ while (!bQuit)
+ {
+ DWORD dwObject = WaitForMultipleObjects (countof(hEvts), hEvts, FALSE, 1);
+ switch (dwObject)
+ {
+ case WAIT_OBJECT_0 :
+ bQuit = true;
+ break;
+ case WAIT_TIMEOUT :
+ {
+ bool bDoneSomething = false;
+ {
+ CAutoLock AutoLock(&m_ImageProcessingLock);
+ bDoneSomething = GetImageFromMixer();
+ }
+ if (m_rtTimePerFrame == 0 && bDoneSomething)
+ {
+ //CAutoLock lock(this);
+ //CAutoLock lock2(&m_ImageProcessingLock);
+ //CAutoLock cRenderLock(&m_RenderLock);
+
+ // Use the code from VMR9 to get the movie fps, as this method is reliable.
+ CComPtr<IPin> pPin;
+ CMediaType mt;
+ if (
+ SUCCEEDED (m_pOuterEVR->FindPin(L"EVR Input0", &pPin)) &&
+ SUCCEEDED (pPin->ConnectionMediaType(&mt)) )
+ {
+ ExtractAvgTimePerFrame (&mt, m_rtTimePerFrame);
+
+ m_bInterlaced = ExtractInterlaced(&mt);
+
+ }
+ // If framerate not set by Video Decoder choose 23.97...
+ if (m_rtTimePerFrame == 0)
+ m_rtTimePerFrame = 417166;
+
+ // Update internal subtitle clock
+ if(m_fUseInternalTimer && m_pSubPicQueue)
+ {
+ m_fps = (float)(10000000.0 / m_rtTimePerFrame);
+ m_pSubPicQueue->SetFPS(m_fps);
+ }
+
+ }
+
+ }
+ break;
+ }
+ }
+
+ timeEndPeriod (dwResolution);
+// if (pfAvRevertMmThreadCharacteristics) pfAvRevertMmThreadCharacteristics (hAvrt);
+}
+
+void ModerateFloat(double& Value, double Target, double& ValuePrim, double ChangeSpeed)
+{
+ double xbiss = (-(ChangeSpeed)*(ValuePrim) - (Value-Target)*(ChangeSpeed*ChangeSpeed)*0.25f);
+ ValuePrim += xbiss;
+ Value += ValuePrim;
+}
+
+LONGLONG CEVRAllocatorPresenter::GetClockTime(LONGLONG PerformanceCounter)
+{
+ LONGLONG llClockTime;
+ MFTIME nsCurrentTime;
+ m_pClock->GetCorrelatedTime(0, &llClockTime, &nsCurrentTime);
+ DWORD Characteristics = 0;
+ m_pClock->GetClockCharacteristics(&Characteristics);
+ MFCLOCK_STATE State;
+ m_pClock->GetState(0, &State);
+
+ if (!(Characteristics & MFCLOCK_CHARACTERISTICS_FLAG_FREQUENCY_10MHZ))
+ {
+ MFCLOCK_PROPERTIES Props;
+ if (m_pClock->GetProperties(&Props) == S_OK)
+ llClockTime = (llClockTime * 10000000) / Props.qwClockFrequency; // Make 10 MHz
+
+ }
+ LONGLONG llPerf = PerformanceCounter;
+// return llClockTime + (llPerf - nsCurrentTime);
+ double Target = llClockTime + (llPerf - nsCurrentTime) * m_ModeratedTimeSpeed;
+
+ bool bReset = false;
+ if (m_ModeratedTimeLast < 0 || State != m_LastClockState || m_ModeratedClockLast < 0)
+ {
+ bReset = true;
+ m_ModeratedTimeLast = llPerf;
+ m_ModeratedClockLast = llClockTime;
+ }
+
+ m_LastClockState = State;
+
+ double TimeChange = llPerf - m_ModeratedTimeLast;
+ double ClockChange = llClockTime - m_ModeratedClockLast;
+
+ m_ModeratedTimeLast = llPerf;
+ m_ModeratedClockLast = llClockTime;
+
+#if 1
+
+ if (bReset)
+ {
+ m_ModeratedTimeSpeed = 1.0;
+ m_ModeratedTimeSpeedPrim = 0.0;
+ ZeroMemory(m_TimeChangeHistory, sizeof(m_TimeChangeHistory));
+ ZeroMemory(m_ClockChangeHistory, sizeof(m_ClockChangeHistory));
+ m_ClockTimeChangeHistoryPos = 0;
+ }
+ if (TimeChange)
+ {
+ int Pos = m_ClockTimeChangeHistoryPos % 100;
+ int nHistory = min(m_ClockTimeChangeHistoryPos, 100);
+ ++m_ClockTimeChangeHistoryPos;
+ if (nHistory > 50)
+ {
+ int iLastPos = (Pos - (nHistory)) % 100;
+ if (iLastPos < 0)
+ iLastPos += 100;
+
+ double TimeChange = llPerf - m_TimeChangeHistory[iLastPos];
+ double ClockChange = llClockTime - m_ClockChangeHistory[iLastPos];
+
+ double ClockSpeedTarget = ClockChange / TimeChange;
+ double ChangeSpeed = 0.1;
+ if (ClockSpeedTarget > m_ModeratedTimeSpeed)
+ {
+ if (ClockSpeedTarget / m_ModeratedTimeSpeed > 0.1)
+ ChangeSpeed = 0.1;
+ else
+ ChangeSpeed = 0.01;
+ }
+ else
+ {
+ if (m_ModeratedTimeSpeed / ClockSpeedTarget > 0.1)
+ ChangeSpeed = 0.1;
+ else
+ ChangeSpeed = 0.01;
+ }
+ ModerateFloat(m_ModeratedTimeSpeed, ClockSpeedTarget, m_ModeratedTimeSpeedPrim, ChangeSpeed);
+// m_ModeratedTimeSpeed = TimeChange / ClockChange;
+ }
+ m_TimeChangeHistory[Pos] = llPerf;
+ m_ClockChangeHistory[Pos] = llClockTime;
+ }
+
+ return Target;
+#else
+ double EstimateTime = m_ModeratedTime + TimeChange * m_ModeratedTimeSpeed + m_ClockDiffCalc;
+ double Diff = Target - EstimateTime;
+
+ // > 5 ms just set it
+ if ((fabs(Diff) > 50000.0 || bReset))
+ {
+
+// TRACE_EVR("EVR: Reset clock at diff: %f ms\n", (m_ModeratedTime - Target) /10000.0);
+ if (State == MFCLOCK_STATE_RUNNING)
+ {
+ if (bReset)
+ {
+ m_ModeratedTimeSpeed = 1.0;
+ m_ModeratedTimeSpeedPrim = 0.0;
+ m_ClockDiffCalc = 0;
+ m_ClockDiffPrim = 0;
+ m_ModeratedTime = Target;
+ m_ModeratedTimer = llPerf;
+ }
+ else
+ {
+ EstimateTime = m_ModeratedTime + TimeChange * m_ModeratedTimeSpeed;
+ Diff = Target - EstimateTime;
+ m_ClockDiffCalc = Diff;
+ m_ClockDiffPrim = 0;
+ }
+ }
+ else
+ {
+ m_ModeratedTimeSpeed = 0.0;
+ m_ModeratedTimeSpeedPrim = 0.0;
+ m_ClockDiffCalc = 0;
+ m_ClockDiffPrim = 0;
+ m_ModeratedTime = Target;
+ m_ModeratedTimer = llPerf;
+ }
+ }
+
+ {
+ LONGLONG ModerateTime = 10000;
+ double ChangeSpeed = 1.00;
+ /* if (m_ModeratedTimeSpeedPrim != 0.0)
+ {
+ if (m_ModeratedTimeSpeedPrim < 0.1)
+ ChangeSpeed = 0.1;
+ }*/
+
+ int nModerate = 0;
+ double Change = 0;
+ while (m_ModeratedTimer < llPerf - ModerateTime)
+ {
+ m_ModeratedTimer += ModerateTime;
+ m_ModeratedTime += double(ModerateTime) * m_ModeratedTimeSpeed;
+
+ double TimerDiff = llPerf - m_ModeratedTimer;
+
+ double Diff = (double)(m_ModeratedTime - (Target - TimerDiff));
+
+ double TimeSpeedTarget;
+ double AbsDiff = fabs(Diff);
+ TimeSpeedTarget = 1.0 - (Diff / 1000000.0);
+// TimeSpeedTarget = m_ModeratedTimeSpeed - (Diff / 100000000000.0);
+ //if (AbsDiff > 20000.0)
+// TimeSpeedTarget = 1.0 - (Diff / 1000000.0);
+ /*else if (AbsDiff > 5000.0)
+ TimeSpeedTarget = 1.0 - (Diff / 100000000.0);
+ else
+ TimeSpeedTarget = 1.0 - (Diff / 500000000.0);*/
+ double StartMod = m_ModeratedTimeSpeed;
+ ModerateFloat(m_ModeratedTimeSpeed, TimeSpeedTarget, m_ModeratedTimeSpeedPrim, ChangeSpeed);
+ m_ModeratedTimeSpeed = TimeSpeedTarget;
+ ++nModerate;
+ Change += m_ModeratedTimeSpeed - StartMod;
+ }
+ if (nModerate)
+ m_ModeratedTimeSpeedDiff = Change / nModerate;
+
+ double Ret = m_ModeratedTime + double(llPerf - m_ModeratedTimer) * m_ModeratedTimeSpeed;
+ double Diff = Target - Ret;
+ ModerateFloat(m_ClockDiffCalc, Diff, m_ClockDiffPrim, ChangeSpeed*0.1);
+
+ Ret += m_ClockDiffCalc;
+ Diff = Target - Ret;
+ m_ClockDiff = Diff;
+ return LONGLONG(Ret + 0.5);
+ }
+
+ return Target;
+ return LONGLONG(m_ModeratedTime + 0.5);
+#endif
+}
+
+void CEVRAllocatorPresenter::OnVBlankFinished(bool fAll, LONGLONG PerformanceCounter)
+{
+ if (!m_pCurrentDisplaydSample || !m_OrderedPaint || !fAll)
+ return;
+
+ LONGLONG llClockTime;
+ LONGLONG nsSampleTime;
+ LONGLONG SampleDuration = 0;
+ if (!m_bSignaledStarvation)
+ {
+ llClockTime = GetClockTime(PerformanceCounter);
+ m_StarvationClock = llClockTime;
+ }
+ else
+ {
+ llClockTime = m_StarvationClock;
+ }
+ if (FAILED(m_pCurrentDisplaydSample->GetSampleDuration(&SampleDuration)))
+ SampleDuration = 0;
+
+ if (FAILED(m_pCurrentDisplaydSample->GetSampleTime(&nsSampleTime)))
+ nsSampleTime = llClockTime;
+ LONGLONG TimePerFrame = m_rtTimePerFrame;
+ if (!TimePerFrame)
+ return;
+ if (SampleDuration > 1)
+ TimePerFrame = SampleDuration;
+ {
+ m_nNextSyncOffset = (m_nNextSyncOffset+1) % NB_JITTER;
+ LONGLONG SyncOffset = nsSampleTime - llClockTime;
+
+ m_pllSyncOffset[m_nNextSyncOffset] = SyncOffset;
+// TRACE_EVR("EVR: SyncOffset(%d, %d): %8I64d %8I64d %8I64d \n", m_nCurSurface, m_VSyncMode, m_LastPredictedSync, -SyncOffset, m_LastPredictedSync - (-SyncOffset));
+
+ m_MaxSyncOffset = MINLONG64;
+ m_MinSyncOffset = MAXLONG64;
+
+ LONGLONG AvrageSum = 0;
+ for (int i=0; i<NB_JITTER; i++)
+ {
+ LONGLONG Offset = m_pllSyncOffset[i];
+ AvrageSum += Offset;
+ m_MaxSyncOffset = max(m_MaxSyncOffset, Offset);
+ m_MinSyncOffset = min(m_MinSyncOffset, Offset);
+ }
+ double MeanOffset = double(AvrageSum)/NB_JITTER;
+ double DeviationSum = 0;
+ for (int i=0; i<NB_JITTER; i++)
+ {
+ double Deviation = double(m_pllSyncOffset[i]) - MeanOffset;
+ DeviationSum += Deviation*Deviation;
+ }
+ double StdDev = sqrt(DeviationSum/NB_JITTER);
+
+ m_fSyncOffsetAvr = MeanOffset;
+ m_bSyncStatsAvailable = true;
+ m_fSyncOffsetStdDev = StdDev;
+
+
+ }
+}
+
+STDMETHODIMP_(bool) CEVRAllocatorPresenter::ResetDevice()
+{
+ CAutoLock lock(this);
+ CAutoLock lock2(&m_ImageProcessingLock);
+ CAutoLock cRenderLock(&m_RenderLock);
+
+ RemoveAllSamples();
+
+ bool bResult = __super::ResetDevice();
+
+ for(int i = 0; i < m_nNbDXSurface; i++)
+ {
+ CComPtr<IMFSample> pMFSample;
+ HRESULT hr = pfMFCreateVideoSampleFromSurface (m_pVideoSurface[i], &pMFSample);
+
+ if (SUCCEEDED (hr))
+ {
+ pMFSample->SetUINT32 (GUID_SURFACE_INDEX, i);
+ m_FreeSamples.AddTail (pMFSample);
+ }
+ ASSERT (SUCCEEDED (hr));
+ }
+ return bResult;
+}
+
+void CEVRAllocatorPresenter::RenderThread()
+{
+ HANDLE hAvrt;
+ DWORD dwTaskIndex = 0;
+ HANDLE hEvts[] = { m_hEvtQuit, m_hEvtFlush};
+ bool bQuit = false;
+ TIMECAPS tc;
+ DWORD dwResolution;
+ MFTIME nsSampleTime;
+ LONGLONG llClockTime;
+ DWORD dwUser = 0;
+ DWORD dwObject;
+
+
+ // Tell Vista Multimedia Class Scheduler we are a playback thretad (increase priority)
+ if (pfAvSetMmThreadCharacteristicsW) hAvrt = pfAvSetMmThreadCharacteristicsW (L"Playback", &dwTaskIndex);
+ if (pfAvSetMmThreadPriority) pfAvSetMmThreadPriority (hAvrt, AVRT_PRIORITY_HIGH /*AVRT_PRIORITY_CRITICAL*/);
+
+ timeGetDevCaps(&tc, sizeof(TIMECAPS));
+ dwResolution = min(max(tc.wPeriodMin, 0), tc.wPeriodMax);
+ dwUser = timeBeginPeriod(dwResolution);
+ CRenderersSettings& s = GetRenderersSettings();
+
+ int NextSleepTime = 1;
+ while (!bQuit)
+ {
+ LONGLONG llPerf = GetRenderersData()->GetPerfCounter();
+ if (!s.m_RenderSettings.iVMR9VSyncAccurate && NextSleepTime == 0)
+ NextSleepTime = 1;
+ dwObject = WaitForMultipleObjects (countof(hEvts), hEvts, FALSE, max(NextSleepTime < 0 ? 1 : NextSleepTime, 0));
+ /* dwObject = WAIT_TIMEOUT;
+ if (m_bEvtFlush)
+ dwObject = WAIT_OBJECT_0 + 1;
+ else if (m_bEvtQuit)
+ dwObject = WAIT_OBJECT_0;*/
+// if (NextSleepTime)
+// TRACE_EVR("EVR: Sleep: %7.3f\n", double(GetRenderersData()->GetPerfCounter()-llPerf) / 10000.0);
+ if (NextSleepTime > 1)
+ NextSleepTime = 0;
+ else if (NextSleepTime == 0)
+ NextSleepTime = -1;
+ switch (dwObject)
+ {
+ case WAIT_OBJECT_0 :
+ bQuit = true;
+ break;
+ case WAIT_OBJECT_0 + 1 :
+ // Flush pending samples!
+ FlushSamples();
+ m_bEvtFlush = false;
+ ResetEvent(m_hEvtFlush);
+ TRACE_EVR ("EVR: Flush done!\n");
+ break;
+
+ case WAIT_TIMEOUT :
+
+ if (m_LastSetOutputRange != -1 && m_LastSetOutputRange != s.m_RenderSettings.iEVROutputRange || m_bPendingRenegotiate)
+ {
+ FlushSamples();
+ RenegotiateMediaType();
+ m_bPendingRenegotiate = false;
+ }
+ if (m_bPendingResetDevice)
+ SendResetRequest();
+
+ // Discard timer events if playback stop
+// if ((dwObject == WAIT_OBJECT_0 + 3) && (m_nRenderState != Started)) continue;
+
+// TRACE_EVR ("EVR: RenderThread ==>> Waiting buffer\n");
+
+// if (WaitForMultipleObjects (countof(hEvtsBuff), hEvtsBuff, FALSE, INFINITE) == WAIT_OBJECT_0+2)
+ {
+ CComPtr<IMFSample> pMFSample;
+ LONGLONG llPerf = GetRenderersData()->GetPerfCounter();
+ int nSamplesLeft = 0;
+ if (SUCCEEDED (GetScheduledSample(&pMFSample, nSamplesLeft)))
+ {
+// pMFSample->GetUINT32 (GUID_SURFACE_INDEX, (UINT32*)&m_nCurSurface);
+ m_pCurrentDisplaydSample = pMFSample;
+
+ bool bValidSampleTime = true;
+ HRESULT hGetSampleTime = pMFSample->GetSampleTime (&nsSampleTime);
+ if (hGetSampleTime != S_OK || nsSampleTime == 0)
+ {
+ bValidSampleTime = false;
+ }
+ // We assume that all samples have the same duration
+ LONGLONG SampleDuration = 0;
+ pMFSample->GetSampleDuration(&SampleDuration);
+
+// TRACE_EVR ("EVR: RenderThread ==>> Presenting surface %d (%I64d)\n", m_nCurSurface, nsSampleTime);
+
+ bool bStepForward = false;
+
+ if (m_nStepCount < 0)
+ {
+ // Drop frame
+ TRACE_EVR ("EVR: Dropped frame\n");
+ m_pcFrames++;
+ bStepForward = true;
+ m_nStepCount = 0;
+ }
+ else if (m_nStepCount > 0)
+ {
+ pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32 *)&m_nCurSurface);
+ ++m_OrderedPaint;
+ if (!g_bExternalSubtitleTime)
+ __super::SetTime (g_tSegmentStart + nsSampleTime);
+ Paint(true);
+ m_nDroppedUpdate = 0;
+ CompleteFrameStep (false);
+ bStepForward = true;
+ }
+ else if ((m_nRenderState == Started))
+ {
+ LONGLONG CurrentCounter = GetRenderersData()->GetPerfCounter();
+ // Calculate wake up timer
+ if (!m_bSignaledStarvation)
+ {
+ llClockTime = GetClockTime(CurrentCounter);
+ m_StarvationClock = llClockTime;
+ }
+ else
+ {
+ llClockTime = m_StarvationClock;
+ }
+
+ if (!bValidSampleTime)
+ {
+ // Just play as fast as possible
+ bStepForward = true;
+ pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32 *)&m_nCurSurface);
+ ++m_OrderedPaint;
+ if (!g_bExternalSubtitleTime)
+ __super::SetTime (g_tSegmentStart + nsSampleTime);
+ Paint(true);
+ }
+ else
+ {
+ LONGLONG TimePerFrame = GetFrameTime() * 10000000.0;
+ LONGLONG DrawTime = (m_PaintTime) * 0.9 - 20000.0; // 2 ms offset
+ //if (!s.iVMR9VSync)
+ DrawTime = 0;
+
+ LONGLONG SyncOffset = 0;
+ LONGLONG VSyncTime = 0;
+ LONGLONG TimeToNextVSync = -1;
+ bool bVSyncCorrection = false;
+ double DetectedRefreshTime;
+ double DetectedScanlinesPerFrame;
+ double DetectedScanlineTime;
+ int DetectedRefreshRatePos;
+ {
+ CAutoLock Lock(&m_RefreshRateLock);
+ DetectedRefreshTime = m_DetectedRefreshTime;
+ DetectedRefreshRatePos = m_DetectedRefreshRatePos;
+ DetectedScanlinesPerFrame = m_DetectedScanlinesPerFrame;
+ DetectedScanlineTime = m_DetectedScanlineTime;
+ }
+
+ if (DetectedRefreshRatePos < 20 || !DetectedRefreshTime || !DetectedScanlinesPerFrame)
+ {
+ DetectedRefreshTime = 1.0/m_RefreshRate;
+ DetectedScanlinesPerFrame = m_ScreenSize.cy;
+ DetectedScanlineTime = DetectedRefreshTime / double(m_ScreenSize.cy);
+ }
+
+ if (s.m_RenderSettings.iVMR9VSync)
+ {
+ bVSyncCorrection = true;
+ double TargetVSyncPos = GetVBlackPos();
+ double RefreshLines = DetectedScanlinesPerFrame;
+ double ScanlinesPerSecond = 1.0/DetectedScanlineTime;
+ double CurrentVSyncPos = fmod(double(m_VBlankStartMeasure) + ScanlinesPerSecond * ((CurrentCounter - m_VBlankStartMeasureTime) / 10000000.0), RefreshLines);
+ double LinesUntilVSync = 0;
+ //TargetVSyncPos -= ScanlinesPerSecond * (DrawTime/10000000.0);
+ //TargetVSyncPos -= 10;
+ TargetVSyncPos = fmod(TargetVSyncPos, RefreshLines);
+ if (TargetVSyncPos < 0)
+ TargetVSyncPos += RefreshLines;
+ if (TargetVSyncPos > CurrentVSyncPos)
+ LinesUntilVSync = TargetVSyncPos - CurrentVSyncPos;
+ else
+ LinesUntilVSync = (RefreshLines - CurrentVSyncPos) + TargetVSyncPos;
+ double TimeUntilVSync = LinesUntilVSync * DetectedScanlineTime;
+ TimeToNextVSync = TimeUntilVSync * 10000000.0;
+ VSyncTime = DetectedRefreshTime * 10000000.0;
+
+ LONGLONG ClockTimeAtNextVSync = llClockTime + (TimeUntilVSync * 10000000.0) * m_ModeratedTimeSpeed;
+
+ SyncOffset = (nsSampleTime - ClockTimeAtNextVSync);
+
+// if (SyncOffset < 0)
+// TRACE_EVR("EVR: SyncOffset(%d): %I64d %I64d %I64d\n", m_nCurSurface, SyncOffset, TimePerFrame, VSyncTime);
+ }
+ else
+ SyncOffset = (nsSampleTime - llClockTime);
+
+ //LONGLONG SyncOffset = nsSampleTime - llClockTime;
+ TRACE_EVR ("EVR: SyncOffset: %I64d SampleFrame: %I64d ClockFrame: %I64d\n", SyncOffset, TimePerFrame!=0 ? nsSampleTime/TimePerFrame : 0, TimePerFrame!=0 ? llClockTime /TimePerFrame : 0);
+ if (SampleDuration > 1 && !m_DetectedLock)
+ TimePerFrame = SampleDuration;
+
+ LONGLONG MinMargin;
+ if (m_FrameTimeCorrection && 0)
+ MinMargin = 15000.0;
+ else
+ MinMargin = 15000.0 + min(m_DetectedFrameTimeStdDev, 20000.0);
+ LONGLONG TimePerFrameMargin = min(double(TimePerFrame)*0.11, max(double(TimePerFrame)*0.02, MinMargin));
+ LONGLONG TimePerFrameMargin0 = TimePerFrameMargin/2;
+ LONGLONG TimePerFrameMargin1 = 0;
+
+ if (m_DetectedLock && TimePerFrame < VSyncTime)
+ VSyncTime = TimePerFrame;
+
+ if (m_VSyncMode == 1)
+ TimePerFrameMargin1 = -TimePerFrameMargin;
+ else if (m_VSyncMode == 2)
+ TimePerFrameMargin1 = TimePerFrameMargin;
+
+ m_LastSampleOffset = SyncOffset;
+ m_bLastSampleOffsetValid = true;
+
+ LONGLONG VSyncOffset0 = 0;
+ bool bDoVSyncCorrection = false;
+ if ((SyncOffset < -(TimePerFrame + TimePerFrameMargin0 - TimePerFrameMargin1)) && nSamplesLeft > 0) // Only drop if we have something else to display at once
+ {
+ // Drop frame
+ TRACE_EVR ("EVR: Dropped frame\n");
+ m_pcFrames++;
+ bStepForward = true;
+ ++m_nDroppedUpdate;
+ NextSleepTime = 0;
+// VSyncOffset0 = (-SyncOffset) - VSyncTime;
+ //VSyncOffset0 = (-SyncOffset) - VSyncTime + TimePerFrameMargin1;
+ //m_LastPredictedSync = VSyncOffset0;
+ bDoVSyncCorrection = false;
+ }
+ else if (SyncOffset < TimePerFrameMargin1)
+ {
+
+ if (bVSyncCorrection)
+ {
+// VSyncOffset0 = -SyncOffset;
+ VSyncOffset0 = -SyncOffset;
+ bDoVSyncCorrection = true;
+ }
+
+ // Paint and prepare for next frame
+ TRACE_EVR ("EVR: Normalframe\n");
+ m_nDroppedUpdate = 0;
+ bStepForward = true;
+ pMFSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32 *)&m_nCurSurface);
+ m_LastFrameDuration = nsSampleTime - m_LastSampleTime;
+ m_LastSampleTime = nsSampleTime;
+ m_LastPredictedSync = VSyncOffset0;
+
+ ++m_OrderedPaint;
+
+ if (!g_bExternalSubtitleTime)
+ __super::SetTime (g_tSegmentStart + nsSampleTime);
+ Paint(true);
+ //m_pSink->Notify(EC_SCRUB_TIME, LODWORD(nsSampleTime), HIDWORD(nsSampleTime));
+
+ NextSleepTime = 0;
+ m_pcFramesDrawn++;
+ }
+ else
+ {
+ if (TimeToNextVSync >= 0 && SyncOffset > 0)
+ {
+ NextSleepTime = ((TimeToNextVSync)/10000) - 2;
+ }
+ else
+ NextSleepTime = ((SyncOffset)/10000) - 2;
+
+ if (NextSleepTime > TimePerFrame)
+ NextSleepTime = 1;
+
+ if (NextSleepTime < 0)
+ NextSleepTime = 0;
+ NextSleepTime = 1;
+ //TRACE_EVR ("EVR: Delay\n");
+ }
+
+ if (bDoVSyncCorrection)
+ {
+ //LONGLONG VSyncOffset0 = (((SyncOffset) % VSyncTime) + VSyncTime) % VSyncTime;
+ LONGLONG Margin = TimePerFrameMargin;
+
+ LONGLONG VSyncOffsetMin = 30000000000000;
+ LONGLONG VSyncOffsetMax = -30000000000000;
+ for (int i = 0; i < 5; ++i)
+ {
+ VSyncOffsetMin = min(m_VSyncOffsetHistory[i], VSyncOffsetMin);
+ VSyncOffsetMax = max(m_VSyncOffsetHistory[i], VSyncOffsetMax);
+ }
+
+ m_VSyncOffsetHistory[m_VSyncOffsetHistoryPos] = VSyncOffset0;
+ m_VSyncOffsetHistoryPos = (m_VSyncOffsetHistoryPos + 1) % 5;
+
+// LONGLONG VSyncTime2 = VSyncTime2 + (VSyncOffsetMax - VSyncOffsetMin);
+ //VSyncOffsetMin; = (((VSyncOffsetMin) % VSyncTime) + VSyncTime) % VSyncTime;
+ //VSyncOffsetMax = (((VSyncOffsetMax) % VSyncTime) + VSyncTime) % VSyncTime;
+
+// TRACE_EVR("EVR: SyncOffset(%d, %d): %8I64d %8I64d %8I64d %8I64d\n", m_nCurSurface, m_VSyncMode,VSyncOffset0, VSyncOffsetMin, VSyncOffsetMax, VSyncOffsetMax - VSyncOffsetMin);
+
+ if (m_VSyncMode == 0)
+ {
+ // 23.976 in 60 Hz
+ if (VSyncOffset0 < Margin && VSyncOffsetMax > (VSyncTime - Margin))
+ {
+ m_VSyncMode = 2;
+ }
+ else if (VSyncOffset0 > (VSyncTime - Margin) && VSyncOffsetMin < Margin)
+ {
+ m_VSyncMode = 1;
+ }
+ }
+ else if (m_VSyncMode == 2)
+ {
+ if (VSyncOffsetMin > (Margin))
+ {
+ m_VSyncMode = 0;
+ }
+ }
+ else if (m_VSyncMode == 1)
+ {
+ if (VSyncOffsetMax < (VSyncTime - Margin))
+ {
+ m_VSyncMode = 0;
+ }
+ }
+ }
+
+ }
+ }
+
+ m_pCurrentDisplaydSample = NULL;
+ if (bStepForward)
+ {
+ MoveToFreeList(pMFSample, true);
+ CheckWaitingSampleFromMixer();
+ m_MaxSampleDuration = max(SampleDuration, m_MaxSampleDuration);
+ }
+ else
+ MoveToScheduledList(pMFSample, true);
+ }
+ else if (m_bLastSampleOffsetValid && m_LastSampleOffset < -10000000) // Only starve if we are 1 seconds behind
+ {
+ if (m_nRenderState == Started && !g_bNoDuration)
+ {
+ m_pSink->Notify(EC_STARVATION, 0, 0);
+ m_bSignaledStarvation = true;
+ }
+ }
+ //GetImageFromMixer();
+ }
+// else
+// {
+// TRACE_EVR ("EVR: RenderThread ==>> Flush before rendering frame!\n");
+// }
+
+ break;
+ }
+ }
+
+ timeEndPeriod (dwResolution);
+ if (pfAvRevertMmThreadCharacteristics) pfAvRevertMmThreadCharacteristics (hAvrt);
+}
+
+void CEVRAllocatorPresenter::OnResetDevice()
+{
+ HRESULT hr;
+
+ // Reset DXVA Manager, and get new buffers
+ hr = m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken);
+
+ // Not necessary, but Microsoft documentation say Presenter should send this message...
+ if (m_pSink)
+ m_pSink->Notify (EC_DISPLAY_CHANGED, 0, 0);
+}
+
+void CEVRAllocatorPresenter::RemoveAllSamples()
+{
+ CAutoLock AutoLock(&m_ImageProcessingLock);
+
+ FlushSamples();
+ m_ScheduledSamples.RemoveAll();
+ m_FreeSamples.RemoveAll();
+ m_LastScheduledSampleTime = -1;
+ m_LastScheduledUncorrectedSampleTime = -1;
+ m_nUsedBuffer = 0;
+}
+
+HRESULT CEVRAllocatorPresenter::GetFreeSample(IMFSample** ppSample)
+{
+ CAutoLock lock(&m_SampleQueueLock);
+ HRESULT hr = S_OK;
+
+ if (m_FreeSamples.GetCount() > 1) // <= Cannot use first free buffer (can be currently displayed)
+ {
+ InterlockedIncrement (&m_nUsedBuffer);
+ *ppSample = m_FreeSamples.RemoveHead().Detach();
+ }
+ else
+ hr = MF_E_SAMPLEALLOCATOR_EMPTY;
+
+ return hr;
+}
+
+
+HRESULT CEVRAllocatorPresenter::GetScheduledSample(IMFSample** ppSample, int &_Count)
+{
+ CAutoLock lock(&m_SampleQueueLock);
+ HRESULT hr = S_OK;
+
+ _Count = m_ScheduledSamples.GetCount();
+ if (_Count > 0)
+ {
+ *ppSample = m_ScheduledSamples.RemoveHead().Detach();
+ --_Count;
+ }
+ else
+ hr = MF_E_SAMPLEALLOCATOR_EMPTY;
+
+ return hr;
+}
+
+
+void CEVRAllocatorPresenter::MoveToFreeList(IMFSample* pSample, bool bTail)
+{
+ CAutoLock lock(&m_SampleQueueLock);
+ InterlockedDecrement (&m_nUsedBuffer);
+ if (m_bPendingMediaFinished && m_nUsedBuffer == 0)
+ {
+ m_bPendingMediaFinished = false;
+ m_pSink->Notify (EC_COMPLETE, 0, 0);
+ }
+ if (bTail)
+ m_FreeSamples.AddTail (pSample);
+ else
+ m_FreeSamples.AddHead(pSample);
+}
+
+
+void CEVRAllocatorPresenter::MoveToScheduledList(IMFSample* pSample, bool _bSorted)
+{
+
+ if (_bSorted)
+ {
+ CAutoLock lock(&m_SampleQueueLock);
+ // Insert sorted
+ /* POSITION Iterator = m_ScheduledSamples.GetHeadPosition();
+
+ LONGLONG NewSampleTime;
+ pSample->GetSampleTime(&NewSampleTime);
+
+ while (Iterator != NULL)
+ {
+ POSITION CurrentPos = Iterator;
+ IMFSample *pIter = m_ScheduledSamples.GetNext(Iterator);
+ LONGLONG SampleTime;
+ pIter->GetSampleTime(&SampleTime);
+ if (NewSampleTime < SampleTime)
+ {
+ m_ScheduledSamples.InsertBefore(CurrentPos, pSample);
+ return;
+ }
+ }*/
+
+ m_ScheduledSamples.AddHead(pSample);
+ }
+ else
+ {
+
+ CAutoLock lock(&m_SampleQueueLock);
+
+ CRenderersSettings& s = GetRenderersSettings();
+ double ForceFPS = 0.0;
+// double ForceFPS = 59.94;
+// double ForceFPS = 23.976;
+ if (ForceFPS != 0.0)
+ m_rtTimePerFrame = 10000000.0 / ForceFPS;
+ LONGLONG Duration = m_rtTimePerFrame;
+ LONGLONG PrevTime = m_LastScheduledUncorrectedSampleTime;
+ LONGLONG Time;
+ LONGLONG SetDuration;
+ pSample->GetSampleDuration(&SetDuration);
+ pSample->GetSampleTime(&Time);
+ m_LastScheduledUncorrectedSampleTime = Time;
+
+ m_bCorrectedFrameTime = false;
+
+ LONGLONG Diff2 = PrevTime - m_LastScheduledSampleTimeFP*10000000.0;
+ LONGLONG Diff = Time - PrevTime;
+ if (PrevTime == -1)
+ Diff = 0;
+ if (Diff < 0)
+ Diff = -Diff;
+ if (Diff2 < 0)
+ Diff2 = -Diff2;
+ if (Diff < m_rtTimePerFrame*8 && m_rtTimePerFrame && Diff2 < m_rtTimePerFrame*8) // Detect seeking
+ {
+ int iPos = (m_DetectedFrameTimePos++) % 60;
+ LONGLONG Diff = Time - PrevTime;
+ if (PrevTime == -1)
+ Diff = 0;
+ m_DetectedFrameTimeHistory[iPos] = Diff;
+
+ if (m_DetectedFrameTimePos >= 10)
+ {
+ int nFrames = min(m_DetectedFrameTimePos, 60);
+ LONGLONG DectedSum = 0;
+ for (int i = 0; i < nFrames; ++i)
+ {
+ DectedSum += m_DetectedFrameTimeHistory[i];
+ }
+
+ double Average = double(DectedSum) / double(nFrames);
+ double DeviationSum = 0.0;
+ for (int i = 0; i < nFrames; ++i)
+ {
+ double Deviation = m_DetectedFrameTimeHistory[i] - Average;
+ DeviationSum += Deviation*Deviation;
+ }
+
+ double StdDev = sqrt(DeviationSum/double(nFrames));
+
+ m_DetectedFrameTimeStdDev = StdDev;
+
+ double DetectedRate = 1.0/ (double(DectedSum) / (nFrames * 10000000.0) );
+
+ double AllowedError = 0.0003;
+
+ static double AllowedValues[] = {60.0, 59.94, 50.0, 48.0, 47.952, 30.0, 29.97, 25.0, 24.0, 23.976};
+
+ int nAllowed = sizeof(AllowedValues) / sizeof(AllowedValues[0]);
+ for (int i = 0; i < nAllowed; ++i)
+ {
+ if (fabs(1.0 - DetectedRate / AllowedValues[i]) < AllowedError)
+ {
+ DetectedRate = AllowedValues[i];
+ break;
+ }
+ }
+
+ m_DetectedFrameTimeHistoryHistory[m_DetectedFrameTimePos % 500] = DetectedRate;
+
+ class CAutoInt
+ {
+ public:
+
+ int m_Int;
+
+ CAutoInt()
+ {
+ m_Int = 0;
+ }
+ CAutoInt(int _Other)
+ {
+ m_Int = _Other;
+ }
+
+ operator int () const
+ {
+ return m_Int;
+ }
+
+ CAutoInt &operator ++ ()
+ {
+ ++m_Int;
+ return *this;
+ }
+ };
+
+
+ CMap<double, double, CAutoInt, CAutoInt> Map;
+
+ for (int i = 0; i < 500; ++i)
+ {
+ ++Map[m_DetectedFrameTimeHistoryHistory[i]];
+ }
+
+ POSITION Pos = Map.GetStartPosition();
+ double BestVal = 0.0;
+ int BestNum = 5;
+ while (Pos)
+ {
+ double Key;
+ CAutoInt Value;
+ Map.GetNextAssoc(Pos, Key, Value);
+ if (Value.m_Int > BestNum && Key != 0.0)
+ {
+ BestNum = Value.m_Int;
+ BestVal = Key;
+ }
+ }
+
+ m_DetectedLock = false;
+ for (int i = 0; i < nAllowed; ++i)
+ {
+ if (BestVal == AllowedValues[i])
+ {
+ m_DetectedLock = true;
+ break;
+ }
+ }
+ if (BestVal != 0.0)
+ {
+ m_DetectedFrameRate = BestVal;
+ m_DetectedFrameTime = 1.0 / BestVal;
+ }
+ }
+
+ LONGLONG PredictedNext = PrevTime + m_rtTimePerFrame;
+ LONGLONG PredictedDiff = PredictedNext - Time;
+ if (PredictedDiff < 0)
+ PredictedDiff = -PredictedDiff;
+
+ if (m_DetectedFrameTime != 0.0
+ //&& PredictedDiff > 15000
+ && m_DetectedLock && s.m_RenderSettings.iEVREnableFrameTimeCorrection)
+ {
+ double CurrentTime = Time / 10000000.0;
+ double LastTime = m_LastScheduledSampleTimeFP;
+ double PredictedTime = LastTime + m_DetectedFrameTime;
+ if (fabs(PredictedTime - CurrentTime) > 0.0015) // 1.5 ms wrong, lets correct
+ {
+ CurrentTime = PredictedTime;
+ Time = CurrentTime * 10000000.0;
+ pSample->SetSampleTime(Time);
+ pSample->SetSampleDuration(m_DetectedFrameTime * 10000000.0);
+ m_bCorrectedFrameTime = true;
+ m_FrameTimeCorrection = 30;
+ }
+ m_LastScheduledSampleTimeFP = CurrentTime;
+ }
+ else
+ m_LastScheduledSampleTimeFP = Time / 10000000.0;
+ }
+ else
+ {
+ m_LastScheduledSampleTimeFP = Time / 10000000.0;
+ if (Diff > m_rtTimePerFrame*8)
+ {
+ // Seek
+ m_bSignaledStarvation = false;
+ m_DetectedFrameTimePos = 0;
+ m_DetectedLock = false;
+ }
+ }
+
+// TRACE_EVR("EVR: Time: %f %f %f\n", Time / 10000000.0, SetDuration / 10000000.0, m_DetectedFrameRate);
+ if (!m_bCorrectedFrameTime && m_FrameTimeCorrection)
+ --m_FrameTimeCorrection;
+
+#if 0
+ if (Time <= m_LastScheduledUncorrectedSampleTime && m_LastScheduledSampleTime >= 0)
+ PrevTime = m_LastScheduledSampleTime;
+
+ m_bCorrectedFrameTime = false;
+ if (PrevTime != -1 && (Time >= PrevTime - ((Duration*20)/9) || Time == 0) || ForceFPS != 0.0)
+ {
+ if (Time - PrevTime > ((Duration*20)/9) && Time - PrevTime < Duration * 8 || Time == 0 || ((Time - PrevTime) < (Duration / 11)) || ForceFPS != 0.0)
+ {
+ // Error!!!!
+ Time = PrevTime + Duration;
+ pSample->SetSampleTime(Time);
+ pSample->SetSampleDuration(Duration);
+ m_bCorrectedFrameTime = true;
+ TRACE_EVR("EVR: Corrected invalid sample time\n");
+ }
+ }
+ if (Time+Duration*10 < m_LastScheduledSampleTime)
+ {
+ // Flush when repeating movie
+ FlushSamplesInternal();
+ }
+#endif
+
+#if 0
+ static LONGLONG LastDuration = 0;
+ LONGLONG SetDuration = m_rtTimePerFrame;
+ pSample->GetSampleDuration(&SetDuration);
+ if (SetDuration != LastDuration)
+ {
+ TRACE_EVR("EVR: Old duration: %I64d New duration: %I64d\n", LastDuration, SetDuration);
+ }
+ LastDuration = SetDuration;
+#endif
+ m_LastScheduledSampleTime = Time;
+
+ m_ScheduledSamples.AddTail(pSample);
+
+ }
+}
+
+
+
+void CEVRAllocatorPresenter::FlushSamples()
+{
+ CAutoLock lock(this);
+ CAutoLock lock2(&m_SampleQueueLock);
+
+ FlushSamplesInternal();
+ m_LastScheduledSampleTime = -1;
+}
+
+void CEVRAllocatorPresenter::FlushSamplesInternal()
+{
+ while (m_ScheduledSamples.GetCount() > 0)
+ {
+ CComPtr<IMFSample> pMFSample;
+
+ pMFSample = m_ScheduledSamples.RemoveHead();
+ MoveToFreeList (pMFSample, true);
+ }
+
+ m_LastSampleOffset = 0;
+ m_bLastSampleOffsetValid = false;
+ m_bSignaledStarvation = false;
+}
diff --git a/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.h b/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.h new file mode 100644 index 000000000..9939c6f0e --- /dev/null +++ b/src/filters/renderer/VideoRenderers/EVRAllocatorPresenter.h @@ -0,0 +1,279 @@ +/*
+ * $Id$
+ *
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "DX9AllocatorPresenter.h"
+#include <mfapi.h> // API Media Foundation
+#include <evr9.h>
+
+namespace DSObjects
+{
+// dxva.dll
+typedef HRESULT (__stdcall *PTR_DXVA2CreateDirect3DDeviceManager9)(UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager);
+
+// mf.dll
+typedef HRESULT (__stdcall *PTR_MFCreatePresentationClock)(IMFPresentationClock** ppPresentationClock);
+
+// evr.dll
+typedef HRESULT (__stdcall *PTR_MFCreateDXSurfaceBuffer)(REFIID riid, IUnknown* punkSurface, BOOL fBottomUpWhenLinear, IMFMediaBuffer** ppBuffer);
+typedef HRESULT (__stdcall *PTR_MFCreateVideoSampleFromSurface)(IUnknown* pUnkSurface, IMFSample** ppSample);
+typedef HRESULT (__stdcall *PTR_MFCreateVideoMediaType)(const MFVIDEOFORMAT* pVideoFormat, IMFVideoMediaType** ppIVideoMediaType);
+
+// AVRT.dll
+typedef HANDLE (__stdcall *PTR_AvSetMmThreadCharacteristicsW)(LPCWSTR TaskName, LPDWORD TaskIndex);
+typedef BOOL (__stdcall *PTR_AvSetMmThreadPriority)(HANDLE AvrtHandle, AVRT_PRIORITY Priority);
+typedef BOOL (__stdcall *PTR_AvRevertMmThreadCharacteristics)(HANDLE AvrtHandle);
+
+class COuterEVR;
+
+class CEVRAllocatorPresenter :
+ public CDX9AllocatorPresenter,
+ public IMFGetService,
+ public IMFTopologyServiceLookupClient,
+ public IMFVideoDeviceID,
+ public IMFVideoPresenter,
+ public IDirect3DDeviceManager9,
+
+ public IMFAsyncCallback,
+ public IQualProp,
+ public IMFRateSupport,
+ public IMFVideoDisplayControl,
+ public IEVRTrustedVideoPlugin
+/* public IMFVideoPositionMapper, // Non mandatory EVR Presenter Interfaces (see later...)
+*/
+{
+public:
+ CEVRAllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString &_Error);
+ ~CEVRAllocatorPresenter(void);
+
+ DECLARE_IUNKNOWN;
+ STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);
+
+ STDMETHODIMP CreateRenderer(IUnknown** ppRenderer);
+ STDMETHODIMP_(bool) Paint(bool fAll);
+ STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight);
+ STDMETHODIMP InitializeDevice(AM_MEDIA_TYPE* pMediaType);
+ STDMETHODIMP_(bool) ResetDevice();
+
+ // IMFClockStateSink
+ STDMETHODIMP OnClockStart(/* [in] */ MFTIME hnsSystemTime, /* [in] */ LONGLONG llClockStartOffset);
+ STDMETHODIMP STDMETHODCALLTYPE OnClockStop(/* [in] */ MFTIME hnsSystemTime);
+ STDMETHODIMP STDMETHODCALLTYPE OnClockPause(/* [in] */ MFTIME hnsSystemTime);
+ STDMETHODIMP STDMETHODCALLTYPE OnClockRestart(/* [in] */ MFTIME hnsSystemTime);
+ STDMETHODIMP STDMETHODCALLTYPE OnClockSetRate(/* [in] */ MFTIME hnsSystemTime, /* [in] */ float flRate);
+
+ // IBaseFilter delegate
+ bool GetState( DWORD dwMilliSecsTimeout, FILTER_STATE *State, HRESULT &_ReturnValue);
+
+ // IQualProp (EVR statistics window)
+ STDMETHODIMP get_FramesDroppedInRenderer (int *pcFrames);
+ STDMETHODIMP get_FramesDrawn (int *pcFramesDrawn);
+ STDMETHODIMP get_AvgFrameRate (int *piAvgFrameRate);
+ STDMETHODIMP get_Jitter (int *iJitter);
+ STDMETHODIMP get_AvgSyncOffset (int *piAvg);
+ STDMETHODIMP get_DevSyncOffset (int *piDev);
+
+
+ // IMFRateSupport
+ STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float *pflRate);
+ STDMETHODIMP GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float *pflRate);
+ STDMETHODIMP IsRateSupported(BOOL fThin, float flRate, float *pflNearestSupportedRate);
+
+ float GetMaxRate(BOOL bThin);
+
+
+ // IMFVideoPresenter
+ STDMETHODIMP ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam);
+ STDMETHODIMP GetCurrentMediaType(__deref_out IMFVideoMediaType **ppMediaType);
+
+ // IMFTopologyServiceLookupClient
+ STDMETHODIMP InitServicePointers(/* [in] */ __in IMFTopologyServiceLookup *pLookup);
+ STDMETHODIMP ReleaseServicePointers();
+
+ // IMFVideoDeviceID
+ STDMETHODIMP GetDeviceID(/* [out] */ __out IID *pDeviceID);
+
+ // IMFGetService
+ STDMETHODIMP GetService (/* [in] */ __RPC__in REFGUID guidService,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */ __RPC__deref_out_opt LPVOID *ppvObject);
+
+ // IMFAsyncCallback
+ STDMETHODIMP GetParameters( /* [out] */ __RPC__out DWORD *pdwFlags, /* [out] */ __RPC__out DWORD *pdwQueue);
+ STDMETHODIMP Invoke ( /* [in] */ __RPC__in_opt IMFAsyncResult *pAsyncResult);
+
+ // IMFVideoDisplayControl
+ STDMETHODIMP GetNativeVideoSize(SIZE *pszVideo, SIZE *pszARVideo);
+ STDMETHODIMP GetIdealVideoSize(SIZE *pszMin, SIZE *pszMax);
+ STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect *pnrcSource, const LPRECT prcDest);
+ STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect *pnrcSource, LPRECT prcDest);
+ STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode);
+ STDMETHODIMP GetAspectRatioMode(DWORD *pdwAspectRatioMode);
+ STDMETHODIMP SetVideoWindow(HWND hwndVideo);
+ STDMETHODIMP GetVideoWindow(HWND *phwndVideo);
+ STDMETHODIMP RepaintVideo( void);
+ STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER *pBih, BYTE **pDib, DWORD *pcbDib, LONGLONG *pTimeStamp);
+ STDMETHODIMP SetBorderColor(COLORREF Clr);
+ STDMETHODIMP GetBorderColor(COLORREF *pClr);
+ STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags);
+ STDMETHODIMP GetRenderingPrefs(DWORD *pdwRenderFlags);
+ STDMETHODIMP SetFullscreen(BOOL fFullscreen);
+ STDMETHODIMP GetFullscreen(BOOL *pfFullscreen);
+
+ // IEVRTrustedVideoPlugin
+ STDMETHODIMP IsInTrustedVideoMode(BOOL *pYes);
+ STDMETHODIMP CanConstrict(BOOL *pYes);
+ STDMETHODIMP SetConstriction(DWORD dwKPix);
+ STDMETHODIMP DisableImageExport(BOOL bDisable);
+
+ // IDirect3DDeviceManager9
+ STDMETHODIMP ResetDevice(IDirect3DDevice9 *pDevice,UINT resetToken);
+ STDMETHODIMP OpenDeviceHandle(HANDLE *phDevice);
+ STDMETHODIMP CloseDeviceHandle(HANDLE hDevice);
+ STDMETHODIMP TestDevice(HANDLE hDevice);
+ STDMETHODIMP LockDevice(HANDLE hDevice, IDirect3DDevice9 **ppDevice, BOOL fBlock);
+ STDMETHODIMP UnlockDevice(HANDLE hDevice, BOOL fSaveState);
+ STDMETHODIMP GetVideoService(HANDLE hDevice, REFIID riid, void **ppService);
+
+protected :
+ void OnResetDevice();
+ virtual void OnVBlankFinished(bool fAll, LONGLONG PerformanceCounter);
+
+ double m_ModeratedTime;
+ LONGLONG m_ModeratedTimeLast;
+ LONGLONG m_ModeratedClockLast;
+ LONGLONG m_ModeratedTimer;
+ MFCLOCK_STATE m_LastClockState;
+ LONGLONG GetClockTime(LONGLONG PerformanceCounter);
+
+private :
+
+ typedef enum
+ {
+ Started = State_Running,
+ Stopped = State_Stopped,
+ Paused = State_Paused,
+ Shutdown = State_Running + 1
+ } RENDER_STATE;
+
+ COuterEVR* m_pOuterEVR;
+ CComPtr<IMFClock> m_pClock;
+ CComPtr<IDirect3DDeviceManager9> m_pD3DManager;
+ CComPtr<IMFTransform> m_pMixer;
+ CComPtr<IMediaEventSink> m_pSink;
+ CComPtr<IMFVideoMediaType> m_pMediaType;
+ MFVideoAspectRatioMode m_dwVideoAspectRatioMode;
+ MFVideoRenderPrefs m_dwVideoRenderPrefs;
+ COLORREF m_BorderColor;
+
+
+ HANDLE m_hEvtQuit; // Stop rendering thread event
+ bool m_bEvtQuit;
+ HANDLE m_hEvtFlush; // Discard all buffers
+ bool m_bEvtFlush;
+
+ bool m_fUseInternalTimer;
+ int32 m_LastSetOutputRange;
+ bool m_bPendingRenegotiate;
+ bool m_bPendingMediaFinished;
+
+ HANDLE m_hThread;
+ HANDLE m_hGetMixerThread;
+ RENDER_STATE m_nRenderState;
+
+ CCritSec m_SampleQueueLock;
+ CCritSec m_ImageProcessingLock;
+
+ CInterfaceList<IMFSample, &IID_IMFSample> m_FreeSamples;
+ CInterfaceList<IMFSample, &IID_IMFSample> m_ScheduledSamples;
+ IMFSample * m_pCurrentDisplaydSample;
+ bool m_bWaitingSample;
+ bool m_bLastSampleOffsetValid;
+ LONGLONG m_LastScheduledSampleTime;
+ double m_LastScheduledSampleTimeFP;
+ LONGLONG m_LastScheduledUncorrectedSampleTime;
+ LONGLONG m_MaxSampleDuration;
+ LONGLONG m_LastSampleOffset;
+ LONGLONG m_VSyncOffsetHistory[5];
+ LONGLONG m_LastPredictedSync;
+ int m_VSyncOffsetHistoryPos;
+
+ UINT m_nResetToken;
+ int m_nStepCount;
+
+ bool m_bSignaledStarvation;
+ LONGLONG m_StarvationClock;
+
+ // Stats variable for IQualProp
+ UINT m_pcFrames;
+ UINT m_nDroppedUpdate;
+ UINT m_pcFramesDrawn; // Retrieves the number of frames drawn since streaming started
+ UINT m_piAvg;
+ UINT m_piDev;
+
+
+ void GetMixerThread();
+ static DWORD WINAPI GetMixerThreadStatic(LPVOID lpParam);
+
+ bool GetImageFromMixer();
+ void RenderThread();
+ static DWORD WINAPI PresentThread(LPVOID lpParam);
+ void ResetStats();
+ void StartWorkerThreads();
+ void StopWorkerThreads();
+ HRESULT CheckShutdown() const;
+ void CompleteFrameStep(bool bCancel);
+ void CheckWaitingSampleFromMixer();
+
+ void RemoveAllSamples();
+ HRESULT GetFreeSample(IMFSample** ppSample);
+ HRESULT GetScheduledSample(IMFSample** ppSample, int &_Count);
+ void MoveToFreeList(IMFSample* pSample, bool bTail);
+ void MoveToScheduledList(IMFSample* pSample, bool _bSorted);
+ void FlushSamples();
+ void FlushSamplesInternal();
+
+ // === Media type negociation functions
+ HRESULT RenegotiateMediaType();
+ HRESULT IsMediaTypeSupported(IMFMediaType* pMixerType);
+ HRESULT CreateProposedOutputType(IMFMediaType* pMixerType, IMFMediaType** pType);
+ HRESULT SetMediaType(IMFMediaType* pType);
+
+ // === Functions pointers on Vista / .Net3 specifics library
+ PTR_DXVA2CreateDirect3DDeviceManager9 pfDXVA2CreateDirect3DDeviceManager9;
+ PTR_MFCreateDXSurfaceBuffer pfMFCreateDXSurfaceBuffer;
+ PTR_MFCreateVideoSampleFromSurface pfMFCreateVideoSampleFromSurface;
+ PTR_MFCreateVideoMediaType pfMFCreateVideoMediaType;
+
+#if 0
+ HRESULT (__stdcall *pMFCreateMediaType)(__deref_out IMFMediaType** ppMFType);
+ HRESULT (__stdcall *pMFInitMediaTypeFromAMMediaType)(__in IMFMediaType *pMFType, __in const AM_MEDIA_TYPE *pAMType);
+ HRESULT (__stdcall *pMFInitAMMediaTypeFromMFMediaType)(__in IMFMediaType *pMFType, __in GUID guidFormatBlockType, __inout AM_MEDIA_TYPE *pAMType);
+#endif
+
+ PTR_AvSetMmThreadCharacteristicsW pfAvSetMmThreadCharacteristicsW;
+ PTR_AvSetMmThreadPriority pfAvSetMmThreadPriority;
+ PTR_AvRevertMmThreadCharacteristics pfAvRevertMmThreadCharacteristics;
+};
+
+}
diff --git a/src/filters/renderer/VideoRenderers/IPinHook.cpp b/src/filters/renderer/VideoRenderers/IPinHook.cpp new file mode 100644 index 000000000..266f75fbe --- /dev/null +++ b/src/filters/renderer/VideoRenderers/IPinHook.cpp @@ -0,0 +1,1584 @@ +/*
+ * $Id$
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+
+#include <d3dx9.h>
+#include <dxva.h>
+#include <dxva2api.h>
+#include <moreuuids.h>
+
+#include "IPinHook.h"
+#include "AllocatorCommon.h"
+
+#define LOG_FILE _T("dxva.log")
+
+//#define LOG_BITSTREAM
+//#define LOG_MATRIX
+
+REFERENCE_TIME g_tSegmentStart = 0;
+REFERENCE_TIME g_tSampleStart = 0;
+GUID g_guidDXVADecoder = GUID_NULL;
+int g_nDXVAVersion = 0;
+
+IPinCVtbl* g_pPinCVtbl = NULL;
+IMemInputPinCVtbl* g_pMemInputPinCVtbl = NULL;
+
+/*
+typedef struct
+{
+ const GUID* Guid;
+ const LPCTSTR Description;
+} DXVA2_DECODER;
+
+const DXVA2_DECODER DXVA2Decoder[] =
+{
+ { &GUID_NULL, _T("Not using DXVA") },
+ { &DXVA2_ModeH264_A, _T("H.264 motion compensation, no FGT") },
+ { &DXVA2_ModeH264_B, _T("H.264 motion compensation, FGT") },
+ { &DXVA2_ModeH264_C, _T("H.264 IDCT, no FGT") },
+ { &DXVA2_ModeH264_D, _T("H.264 IDCT, FGT") },
+ { &DXVA2_ModeH264_E, _T("H.264 bitstream decoder, no FGT") },
+ { &DXVA2_ModeH264_F, _T("H.264 bitstream decoder, FGT") },
+ { &DXVA2_ModeMPEG2_IDCT, _T("MPEG-2 IDCT") },
+ { &DXVA2_ModeMPEG2_MoComp, _T("MPEG-2 motion compensation") },
+ { &DXVA2_ModeMPEG2_VLD, _T("MPEG-2 variable-length decoder") },
+ { &DXVA_ModeMPEG2_A, _T("MPEG-2 A") }, // TODO : find label !!!
+ { &DXVA_ModeMPEG2_B, _T("MPEG-2 B") },
+ { &DXVA_ModeMPEG2_C, _T("MPEG-2 IDCT") },
+ { &DXVA_ModeMPEG2_D, _T("MPEG-2 D") },
+ { &DXVA2_ModeVC1_A, _T("VC-1 post processing") },
+ { &DXVA2_ModeVC1_B, _T("VC-1 motion compensation") },
+ { &DXVA2_ModeVC1_C, _T("VC-1 IDCT") },
+ { &DXVA2_ModeVC1_D, _T("VC-1 bitstream decoder") },
+ { &DXVA2_ModeWMV8_A, _T("WMV 8 post processing.") },
+ { &DXVA2_ModeWMV8_B, _T("WMV8 motion compensation") },
+ { &DXVA2_ModeWMV9_A, _T("WMV9 post processing") },
+ { &DXVA2_ModeWMV9_B, _T("WMV9 motion compensation") },
+ { &DXVA2_ModeWMV9_C, _T("WMV9 IDCT") },
+};
+*/
+
+typedef struct
+{
+ const int Format;
+ const LPCTSTR Description;
+} D3DFORMAT_TYPE;
+
+const D3DFORMAT_TYPE D3DFormatType[] =
+{
+ { D3DFMT_UNKNOWN , _T("D3DFMT_UNKNOWN ") },
+ { D3DFMT_R8G8B8 , _T("D3DFMT_R8G8B8 ") },
+ { D3DFMT_A8R8G8B8 , _T("D3DFMT_A8R8G8B8 ") },
+ { D3DFMT_X8R8G8B8 , _T("D3DFMT_X8R8G8B8 ") },
+ { D3DFMT_R5G6B5 , _T("D3DFMT_R5G6B5 ") },
+ { D3DFMT_X1R5G5B5 , _T("D3DFMT_X1R5G5B5 ") },
+ { D3DFMT_A1R5G5B5 , _T("D3DFMT_A1R5G5B5 ") },
+ { D3DFMT_A4R4G4B4 , _T("D3DFMT_A4R4G4B4 ") },
+ { D3DFMT_R3G3B2 , _T("D3DFMT_R3G3B2 ") },
+ { D3DFMT_A8 , _T("D3DFMT_A8 ") },
+ { D3DFMT_A8R3G3B2 , _T("D3DFMT_A8R3G3B2 ") },
+ { D3DFMT_X4R4G4B4 , _T("D3DFMT_X4R4G4B4 ") },
+ { D3DFMT_A2B10G10R10 , _T("D3DFMT_A2B10G10R10 ") },
+ { D3DFMT_A8B8G8R8 , _T("D3DFMT_A8B8G8R8 ") },
+ { D3DFMT_X8B8G8R8 , _T("D3DFMT_X8B8G8R8 ") },
+ { D3DFMT_G16R16 , _T("D3DFMT_G16R16 ") },
+ { D3DFMT_A2R10G10B10 , _T("D3DFMT_A2R10G10B10 ") },
+ { D3DFMT_A16B16G16R16 , _T("D3DFMT_A16B16G16R16 ") },
+ { D3DFMT_A8P8 , _T("D3DFMT_A8P8 ") },
+ { D3DFMT_P8 , _T("D3DFMT_P8 ") },
+ { D3DFMT_L8 , _T("D3DFMT_L8 ") },
+ { D3DFMT_A8L8 , _T("D3DFMT_A8L8 ") },
+ { D3DFMT_A4L4 , _T("D3DFMT_A4L4 ") },
+ { D3DFMT_X8L8V8U8 , _T("D3DFMT_X8L8V8U8 ") },
+ { D3DFMT_Q8W8V8U8 , _T("D3DFMT_Q8W8V8U8 ") },
+ { D3DFMT_V16U16 , _T("D3DFMT_V16U16 ") },
+ { D3DFMT_A2W10V10U10 , _T("D3DFMT_A2W10V10U10 ") },
+ { D3DFMT_UYVY , _T("D3DFMT_UYVY ") },
+ { D3DFMT_R8G8_B8G8 , _T("D3DFMT_R8G8_B8G8 ") },
+ { D3DFMT_YUY2 , _T("D3DFMT_YUY2 ") },
+ { D3DFMT_G8R8_G8B8 , _T("D3DFMT_G8R8_G8B8 ") },
+ { D3DFMT_DXT1 , _T("D3DFMT_DXT1 ") },
+ { D3DFMT_DXT2 , _T("D3DFMT_DXT2 ") },
+ { D3DFMT_DXT3 , _T("D3DFMT_DXT3 ") },
+ { D3DFMT_DXT4 , _T("D3DFMT_DXT4 ") },
+ { D3DFMT_DXT5 , _T("D3DFMT_DXT5 ") },
+ { D3DFMT_D16_LOCKABLE , _T("D3DFMT_D16_LOCKABLE ") },
+ { D3DFMT_D32 , _T("D3DFMT_D32 ") },
+ { D3DFMT_D15S1 , _T("D3DFMT_D15S1 ") },
+ { D3DFMT_D24S8 , _T("D3DFMT_D24S8 ") },
+ { D3DFMT_D24X8 , _T("D3DFMT_D24X8 ") },
+ { D3DFMT_D24X4S4 , _T("D3DFMT_D24X4S4 ") },
+ { D3DFMT_D16 , _T("D3DFMT_D16 ") },
+ { D3DFMT_D32F_LOCKABLE , _T("D3DFMT_D32F_LOCKABLE") },
+ { D3DFMT_D24FS8 , _T("D3DFMT_D24FS8 ") },
+ { D3DFMT_L16 , _T("D3DFMT_L16 ") },
+ { D3DFMT_VERTEXDATA , _T("D3DFMT_VERTEXDATA ") },
+ { D3DFMT_INDEX16 , _T("D3DFMT_INDEX16 ") },
+ { D3DFMT_INDEX32 , _T("D3DFMT_INDEX32 ") },
+ { D3DFMT_Q16W16V16U16 , _T("D3DFMT_Q16W16V16U16 ") },
+
+ { MAKEFOURCC('N','V','1','2') , _T("D3DFMT_NV12") },
+ { MAKEFOURCC('N','V','2','4') , _T("D3DFMT_NV24") },
+};
+
+const LPCTSTR DXVAVersion[] = { _T("DXVA "), _T("DXVA1"), _T("DXVA2") };
+
+LPCTSTR GetDXVADecoderDescription()
+{
+ return GetDXVAMode (&g_guidDXVADecoder);
+}
+
+LPCTSTR GetDXVAVersion()
+{
+ return DXVAVersion[g_nDXVAVersion];
+}
+
+LPCTSTR FindD3DFormat(const D3DFORMAT Format)
+{
+ for (int i=0; i<countof(D3DFormatType); i++)
+ {
+ if (Format == D3DFormatType[i].Format)
+ return D3DFormatType[i].Description;
+ }
+
+ return D3DFormatType[0].Description;
+}
+
+// === DirectShow hooks
+static HRESULT (STDMETHODCALLTYPE * NewSegmentOrg)(IPinC * This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate) = NULL;
+
+static HRESULT STDMETHODCALLTYPE NewSegmentMine(IPinC * This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate)
+{
+ g_tSegmentStart = tStart;
+ return NewSegmentOrg(This, tStart, tStop, dRate);
+}
+
+static HRESULT ( STDMETHODCALLTYPE *ReceiveOrg )( IMemInputPinC * This, IMediaSample *pSample) = NULL;
+
+static HRESULT STDMETHODCALLTYPE ReceiveMineI(IMemInputPinC * This, IMediaSample *pSample)
+{
+ REFERENCE_TIME rtStart, rtStop;
+ if(pSample && SUCCEEDED(pSample->GetTime(&rtStart, &rtStop)))
+ g_tSampleStart = rtStart;
+ return ReceiveOrg(This, pSample);
+}
+
+static HRESULT STDMETHODCALLTYPE ReceiveMine(IMemInputPinC * This, IMediaSample *pSample)
+{
+ // Support ffdshow queueing.
+ // To avoid black out on pause, we have to lock g_ffdshowReceive to synchronize with CMainFrame::OnPlayPause.
+ if(queue_ffdshow_support)
+ {
+ CAutoLock lck(&g_ffdshowReceive);
+ return ReceiveMineI(This,pSample);
+ }
+ return ReceiveMineI(This,pSample);
+}
+
+
+void UnhookNewSegmentAndReceive()
+{
+ BOOL res;
+ DWORD flOldProtect = 0;
+
+ // Casimir666 : unhook previous VTables
+ if (g_pPinCVtbl && g_pMemInputPinCVtbl)
+ {
+ res = VirtualProtect(g_pPinCVtbl, sizeof(IPinCVtbl), PAGE_WRITECOPY, &flOldProtect);
+ if (g_pPinCVtbl->NewSegment == NewSegmentMine)
+ g_pPinCVtbl->NewSegment = NewSegmentOrg;
+ res = VirtualProtect(g_pPinCVtbl, sizeof(IPinCVtbl), flOldProtect, &flOldProtect);
+
+ res = VirtualProtect(g_pMemInputPinCVtbl, sizeof(IMemInputPinCVtbl), PAGE_WRITECOPY, &flOldProtect);
+ if (g_pMemInputPinCVtbl->Receive == ReceiveMine)
+ g_pMemInputPinCVtbl->Receive = ReceiveOrg;
+ res = VirtualProtect(g_pMemInputPinCVtbl, sizeof(IMemInputPinCVtbl), flOldProtect, &flOldProtect);
+
+ g_pPinCVtbl = NULL;
+ g_pMemInputPinCVtbl = NULL;
+ NewSegmentOrg = NULL;
+ ReceiveOrg = NULL;
+ }
+}
+
+bool HookNewSegmentAndReceive(IPinC* pPinC, IMemInputPinC* pMemInputPinC)
+{
+ if(!pPinC || !pMemInputPinC || (GetVersion()&0x80000000))
+ return false;
+
+ g_tSegmentStart = 0;
+ g_tSampleStart = 0;
+
+ BOOL res;
+ DWORD flOldProtect = 0;
+
+ UnhookNewSegmentAndReceive();
+
+ // Casimir666 : change sizeof(IPinC) to sizeof(IPinCVtbl) to fix crash with EVR hack on Vista!
+ res = VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), PAGE_WRITECOPY, &flOldProtect);
+ if(NewSegmentOrg == NULL) NewSegmentOrg = pPinC->lpVtbl->NewSegment;
+ pPinC->lpVtbl->NewSegment = NewSegmentMine;
+ res = VirtualProtect(pPinC->lpVtbl, sizeof(IPinCVtbl), flOldProtect, &flOldProtect);
+
+ // Casimir666 : change sizeof(IMemInputPinC) to sizeof(IMemInputPinCVtbl) to fix crash with EVR hack on Vista!
+ res = VirtualProtect(pMemInputPinC->lpVtbl, sizeof(IMemInputPinCVtbl), PAGE_WRITECOPY, &flOldProtect);
+ if(ReceiveOrg == NULL) ReceiveOrg = pMemInputPinC->lpVtbl->Receive;
+ pMemInputPinC->lpVtbl->Receive = ReceiveMine;
+ res = VirtualProtect(pMemInputPinC->lpVtbl, sizeof(IMemInputPinCVtbl), flOldProtect, &flOldProtect);
+
+ g_pPinCVtbl = pPinC->lpVtbl;
+ g_pMemInputPinCVtbl = pMemInputPinC->lpVtbl;
+
+ return true;
+}
+
+
+// === DXVA1 hooks
+
+#define MAX_BUFFER_TYPE 15
+BYTE* g_ppBuffer[MAX_BUFFER_TYPE];
+
+
+static HRESULT ( STDMETHODCALLTYPE *GetVideoAcceleratorGUIDsOrg )( IAMVideoAcceleratorC * This,/* [out][in] */ LPDWORD pdwNumGuidsSupported,/* [out][in] */ LPGUID pGuidsSupported) = NULL;
+static HRESULT ( STDMETHODCALLTYPE *GetUncompFormatsSupportedOrg )( IAMVideoAcceleratorC * This,/* [in] */ const GUID *pGuid,/* [out][in] */ LPDWORD pdwNumFormatsSupported,/* [out][in] */ LPDDPIXELFORMAT pFormatsSupported) = NULL;
+static HRESULT ( STDMETHODCALLTYPE *GetInternalMemInfoOrg )( IAMVideoAcceleratorC * This,/* [in] */ const GUID *pGuid,/* [in] */ const AMVAUncompDataInfo *pamvaUncompDataInfo,/* [out][in] */ LPAMVAInternalMemInfo pamvaInternalMemInfo) = NULL;
+static HRESULT ( STDMETHODCALLTYPE *GetCompBufferInfoOrg )( IAMVideoAcceleratorC * This,/* [in] */ const GUID *pGuid,/* [in] */ const AMVAUncompDataInfo *pamvaUncompDataInfo,/* [out][in] */ LPDWORD pdwNumTypesCompBuffers,/* [out] */ LPAMVACompBufferInfo pamvaCompBufferInfo) = NULL;
+static HRESULT ( STDMETHODCALLTYPE *GetInternalCompBufferInfoOrg )( IAMVideoAcceleratorC * This,/* [out][in] */ LPDWORD pdwNumTypesCompBuffers,/* [out] */ LPAMVACompBufferInfo pamvaCompBufferInfo) = NULL;
+static HRESULT ( STDMETHODCALLTYPE *BeginFrameOrg )( IAMVideoAcceleratorC * This,/* [in] */ const AMVABeginFrameInfo *amvaBeginFrameInfo) = NULL;
+static HRESULT ( STDMETHODCALLTYPE *EndFrameOrg )( IAMVideoAcceleratorC * This,/* [in] */ const AMVAEndFrameInfo *pEndFrameInfo) = NULL;
+static HRESULT ( STDMETHODCALLTYPE *GetBufferOrg )( IAMVideoAcceleratorC * This,/* [in] */ DWORD dwTypeIndex,/* [in] */ DWORD dwBufferIndex,/* [in] */ BOOL bReadOnly,/* [out] */ LPVOID *ppBuffer,/* [out] */ LONG *lpStride) = NULL;
+static HRESULT ( STDMETHODCALLTYPE *ReleaseBufferOrg )( IAMVideoAcceleratorC * This,/* [in] */ DWORD dwTypeIndex,/* [in] */ DWORD dwBufferIndex) = NULL;
+static HRESULT ( STDMETHODCALLTYPE *ExecuteOrg )( IAMVideoAcceleratorC * This,/* [in] */ DWORD dwFunction,/* [in] */ LPVOID lpPrivateInputData,/* [in] */ DWORD cbPrivateInputData,/* [in] */ LPVOID lpPrivateOutputDat,/* [in] */ DWORD cbPrivateOutputData,/* [in] */ DWORD dwNumBuffers,/* [in] */ const AMVABUFFERINFO *pamvaBufferInfo) = NULL;
+static HRESULT ( STDMETHODCALLTYPE *QueryRenderStatusOrg )( IAMVideoAcceleratorC * This,/* [in] */ DWORD dwTypeIndex,/* [in] */ DWORD dwBufferIndex,/* [in] */ DWORD dwFlags) = NULL;
+static HRESULT ( STDMETHODCALLTYPE *DisplayFrameOrg )( IAMVideoAcceleratorC * This,/* [in] */ DWORD dwFlipToIndex,/* [in] */ IMediaSample *pMediaSample) = NULL;
+
+static void LOG_TOFILE(LPCTSTR FileName, LPCTSTR fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ int nCount = _vsctprintf(fmt, args) + 1;
+ if(TCHAR* buff = DNew TCHAR[nCount])
+ {
+ FILE* f;
+ _vstprintf_s(buff, nCount, fmt, args);
+ if(_tfopen_s(&f, FileName, _T("at")) == 0)
+ {
+ fseek(f, 0, 2);
+ _ftprintf(f, _T("%s\n"), buff);
+ fclose(f);
+ }
+ delete [] buff;
+ }
+ va_end(args);
+}
+
+#ifdef _DEBUG
+static void LOG(LPCTSTR fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+// int nCount = _vsctprintf(fmt, args) + 1;
+ TCHAR buff[3000];
+ FILE* f;
+ _vstprintf_s(buff, countof(buff), fmt, args);
+ if(_tfopen_s(&f, LOG_FILE, _T("at")) == 0)
+ {
+ fseek(f, 0, 2);
+ _ftprintf(f, _T("%s\n"), buff);
+ fclose(f);
+ }
+
+ va_end(args);
+}
+static void LOGPF(LPCTSTR prefix, const DDPIXELFORMAT* p, int n)
+{
+ for(int i = 0; i < n; i++)
+ {
+ LOG(_T("%s[%d].dwSize = %d"), prefix, i, p[i].dwSize);
+ LOG(_T("%s[%d].dwFlags = %08x"), prefix, i, p[i].dwFlags);
+ LOG(_T("%s[%d].dwFourCC = %4.4hs"), prefix, i, &p[i].dwFourCC);
+ LOG(_T("%s[%d].dwRGBBitCount = %08x"), prefix, i, &p[i].dwRGBBitCount);
+ LOG(_T("%s[%d].dwRBitMask = %08x"), prefix, i, &p[i].dwRBitMask);
+ LOG(_T("%s[%d].dwGBitMask = %08x"), prefix, i, &p[i].dwGBitMask);
+ LOG(_T("%s[%d].dwBBitMask = %08x"), prefix, i, &p[i].dwBBitMask);
+ LOG(_T("%s[%d].dwRGBAlphaBitMask = %08x"), prefix, i, &p[i].dwRGBAlphaBitMask);
+ }
+}
+
+static void LOGUDI(LPCTSTR prefix, const AMVAUncompDataInfo* p, int n)
+{
+ for(int i = 0; i < n; i++)
+ {
+ LOG(_T("%s[%d].dwUncompWidth = %d"), prefix, i, p[i].dwUncompWidth);
+ LOG(_T("%s[%d].dwUncompHeight = %d"), prefix, i, p[i].dwUncompHeight);
+
+ CString prefix2;
+ prefix2.Format(_T("%s[%d]"), prefix, i);
+ LOGPF(prefix2, &p[i].ddUncompPixelFormat, 1);
+ }
+}
+
+
+static void LogDXVA_PicParams_H264 (DXVA_PicParams_H264* pPic)
+{
+ CString strRes;
+ int i;
+ static bool bFirstParam = true;
+
+ if (bFirstParam)
+ {
+ LOG_TOFILE (_T("picture.log"), _T("RefPicFlag,wFrameWidthInMbsMinus1,wFrameHeightInMbsMinus1,CurrPic.Index7Bits,num_ref_frames,wBitFields,bit_depth_luma_minus8,bit_depth_chroma_minus8,Reserved16Bits,StatusReportFeedbackNumber,RFL.Index7Bits[0],") \
+ _T("RFL.Index7Bits[1],RFL.Index7Bits[2],RFL.Index7Bits[3],RFL.Index7Bits[4],RFL.Index7Bits[5],") \
+ _T("RFL.Index7Bits[6],RFL.Index7Bits[7],RFL.Index7Bits[8],RFL.Index7Bits[9],RFL.Index7Bits[10],") \
+ _T("RFL.Index7Bits[11],RFL.Index7Bits[12],RFL.Index7Bits[13],RFL.Index7Bits[14],RFL.Index7Bits[15],") \
+ _T("CurrFieldOrderCnt[0], CurrFieldOrderCnt[1],FieldOrderCntList[0][0], FieldOrderCntList[0][1],FieldOrderCntList[1][0], FieldOrderCntList[1][1],FieldOrderCntList[2][0], FieldOrderCntList[2][1],FieldOrderCntList[3][0], FieldOrderCntList[3][1],FieldOrderCntList[4][0], FieldOrderCntList[4][1],FieldOrderCntList[5][0],") \
+ _T("FieldOrderCntList[5][1],FieldOrderCntList[6][0], FieldOrderCntList[6][1],FieldOrderCntList[7][0], FieldOrderCntList[7][1],FieldOrderCntList[8][0], FieldOrderCntList[8][1],FieldOrderCntList[9][0], FieldOrderCntList[9][1],FieldOrderCntList[10][0], FieldOrderCntList[10][1],FieldOrderCntList[11][0],")\
+ _T("FieldOrderCntList[11][1],FieldOrderCntList[12][0], FieldOrderCntList[12][1],FieldOrderCntList[13][0], FieldOrderCntList[13][1],FieldOrderCntList[14][0], FieldOrderCntList[14][1],FieldOrderCntList[15][0], FieldOrderCntList[15][1],pic_init_qs_minus26,chroma_qp_index_offset,second_chroma_qp_index_offset,")\
+ _T("ContinuationFlag,pic_init_qp_minus26,num_ref_idx_l0_active_minus1,num_ref_idx_l1_active_minus1,Reserved8BitsA,FrameNumList[0],FrameNumList[1],FrameNumList[2],FrameNumList[3],FrameNumList[4],FrameNumList[5],FrameNumList[6],FrameNumList[7],FrameNumList[8],FrameNumList[9],FrameNumList[10],FrameNumList[11],")\
+ _T("FrameNumList[12],FrameNumList[13],FrameNumList[14],FrameNumList[15],UsedForReferenceFlags,NonExistingFrameFlags,frame_num,log2_max_frame_num_minus4,pic_order_cnt_type,log2_max_pic_order_cnt_lsb_minus4,delta_pic_order_always_zero_flag,direct_8x8_inference_flag,entropy_coding_mode_flag,pic_order_present_flag,")\
+ _T("num_slice_groups_minus1,slice_group_map_type,deblocking_filter_control_present_flag,redundant_pic_cnt_present_flag,Reserved8BitsB,slice_group_change_rate_minus1"));
+
+ }
+ bFirstParam = false;
+
+ strRes.AppendFormat(_T("%d,"), pPic->RefPicFlag);
+ strRes.AppendFormat(_T("%d,"), pPic->wFrameWidthInMbsMinus1);
+ strRes.AppendFormat(_T("%d,"), pPic->wFrameHeightInMbsMinus1);
+
+ // DXVA_PicEntry_H264 CurrPic)); /* flag is bot field flag */
+// strRes.AppendFormat(_T("%d,"), pPic->CurrPic.AssociatedFlag);
+// strRes.AppendFormat(_T("%d,"), pPic->CurrPic.bPicEntry);
+ strRes.AppendFormat(_T("%d,"), pPic->CurrPic.Index7Bits);
+
+
+ strRes.AppendFormat(_T("%d,"), pPic->num_ref_frames);
+ strRes.AppendFormat(_T("%d,"), pPic->wBitFields);
+ strRes.AppendFormat(_T("%d,"), pPic->bit_depth_luma_minus8);
+ strRes.AppendFormat(_T("%d,"), pPic->bit_depth_chroma_minus8);
+
+ strRes.AppendFormat(_T("%d,"), pPic->Reserved16Bits);
+ strRes.AppendFormat(_T("%d,"), pPic->StatusReportFeedbackNumber);
+
+ for (i =0; i<16; i++)
+ {
+// strRes.AppendFormat(_T("%d,"), pPic->RefFrameList[i].AssociatedFlag);
+// strRes.AppendFormat(_T("%d,"), pPic->RefFrameList[i].bPicEntry);
+ strRes.AppendFormat(_T("%d,"), pPic->RefFrameList[i].Index7Bits);
+ }
+
+ strRes.AppendFormat(_T("%d, %d,"), pPic->CurrFieldOrderCnt[0], pPic->CurrFieldOrderCnt[1]);
+
+ for (int i=0; i<16; i++)
+ strRes.AppendFormat(_T("%d, %d,"), pPic->FieldOrderCntList[i][0], pPic->FieldOrderCntList[i][1]);
+// strRes.AppendFormat(_T("%d,"), pPic->FieldOrderCntList[16][2]);
+
+ strRes.AppendFormat(_T("%d,"), pPic->pic_init_qs_minus26);
+ strRes.AppendFormat(_T("%d,"), pPic->chroma_qp_index_offset); /* also used for QScb */
+ strRes.AppendFormat(_T("%d,"), pPic->second_chroma_qp_index_offset); /* also for QScr */
+ strRes.AppendFormat(_T("%d,"), pPic->ContinuationFlag);
+
+ /* remainder for parsing */
+ strRes.AppendFormat(_T("%d,"), pPic->pic_init_qp_minus26);
+ strRes.AppendFormat(_T("%d,"), pPic->num_ref_idx_l0_active_minus1);
+ strRes.AppendFormat(_T("%d,"), pPic->num_ref_idx_l1_active_minus1);
+ strRes.AppendFormat(_T("%d,"), pPic->Reserved8BitsA);
+
+ for (int i=0; i<16; i++)
+ strRes.AppendFormat(_T("%d,"), pPic->FrameNumList[i]);
+
+// strRes.AppendFormat(_T("%d,"), pPic->FrameNumList[16]);
+ strRes.AppendFormat(_T("%d,"), pPic->UsedForReferenceFlags);
+ strRes.AppendFormat(_T("%d,"), pPic->NonExistingFrameFlags);
+ strRes.AppendFormat(_T("%d,"), pPic->frame_num);
+
+ strRes.AppendFormat(_T("%d,"), pPic->log2_max_frame_num_minus4);
+ strRes.AppendFormat(_T("%d,"), pPic->pic_order_cnt_type);
+ strRes.AppendFormat(_T("%d,"), pPic->log2_max_pic_order_cnt_lsb_minus4);
+ strRes.AppendFormat(_T("%d,"), pPic->delta_pic_order_always_zero_flag);
+
+ strRes.AppendFormat(_T("%d,"), pPic->direct_8x8_inference_flag);
+ strRes.AppendFormat(_T("%d,"), pPic->entropy_coding_mode_flag);
+ strRes.AppendFormat(_T("%d,"), pPic->pic_order_present_flag);
+ strRes.AppendFormat(_T("%d,"), pPic->num_slice_groups_minus1);
+
+ strRes.AppendFormat(_T("%d,"), pPic->slice_group_map_type);
+ strRes.AppendFormat(_T("%d,"), pPic->deblocking_filter_control_present_flag);
+ strRes.AppendFormat(_T("%d,"), pPic->redundant_pic_cnt_present_flag);
+ strRes.AppendFormat(_T("%d,"), pPic->Reserved8BitsB);
+
+ strRes.AppendFormat(_T("%d,"), pPic->slice_group_change_rate_minus1);
+
+ //for (int i=0; i<810; i++)
+ // strRes.AppendFormat(_T("%d,"), pPic->SliceGroupMap[i]);
+// strRes.AppendFormat(_T("%d,"), pPic->SliceGroupMap[810]);
+
+ // SABOTAGE !!!
+//for (int i=0; i<16; i++)
+//{
+// pPic->FieldOrderCntList[i][0] = pPic->FieldOrderCntList[i][1] = 0;
+// pPic->RefFrameList[i].AssociatedFlag = 1;
+// pPic->RefFrameList[i].bPicEntry = 255;
+// pPic->RefFrameList[i].Index7Bits = 127;
+//}
+
+ // === Dump PicParams!
+ //static FILE* hPict = NULL;
+ //if (!hPict) hPict = fopen ("PicParam.bin", "wb");
+ //if (hPict)
+ //{
+ // fwrite (pPic, sizeof (DXVA_PicParams_H264), 1, hPict);
+ //}
+
+ LOG_TOFILE (_T("picture.log"), strRes);
+}
+
+static void LogH264SliceShort (DXVA_Slice_H264_Short* pSlice, int nCount)
+{
+ CString strRes;
+ static bool bFirstSlice = true;
+
+ if (bFirstSlice)
+ {
+ strRes = _T("nCnt, BSNALunitDataLocation, SliceBytesInBuffer, wBadSliceChopping");
+ LOG_TOFILE (_T("sliceshort.log"), strRes);
+ strRes = "";
+ bFirstSlice = false;
+ }
+
+ for (int i=0; i<nCount; i++)
+ {
+ strRes.AppendFormat(_T("%d,"), i);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].BSNALunitDataLocation);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].SliceBytesInBuffer);
+ strRes.AppendFormat(_T("%d"), pSlice[i].wBadSliceChopping);
+
+ LOG_TOFILE (_T("sliceshort.log"), strRes);
+ strRes = "";
+ }
+}
+
+static void LogSliceInfo (DXVA_SliceInfo* pSlice, int nCount)
+{
+ CString strRes;
+ static bool bFirstSlice = true;
+
+ if (bFirstSlice)
+ {
+ strRes = _T("nCnt, wHorizontalPosition, wVerticalPosition, dwSliceBitsInBuffer,dwSliceDataLocation, bStartCodeBitOffset, bReservedBits, wMBbitOffset, wNumberMBsInSlice, wQuantizerScaleCode, wBadSliceChopping");
+
+ LOG_TOFILE (_T("sliceshort.log"), strRes);
+ strRes = "";
+ bFirstSlice = false;
+ }
+
+ for (int i=0; i<nCount; i++)
+ {
+ strRes.AppendFormat(_T("%d,"), i);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].wHorizontalPosition);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].wVerticalPosition);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].dwSliceBitsInBuffer);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].dwSliceDataLocation);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].bStartCodeBitOffset);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].bReservedBits);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].wMBbitOffset);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].wNumberMBsInSlice);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].wQuantizerScaleCode);
+ strRes.AppendFormat(_T("%d"), pSlice[i].wBadSliceChopping);
+
+ LOG_TOFILE (_T("sliceshort.log"), strRes);
+ strRes = "";
+ }
+}
+
+static void LogH264SliceLong (DXVA_Slice_H264_Long* pSlice, int nCount)
+{
+ static bool bFirstSlice = true;
+ CString strRes;
+
+ if (bFirstSlice)
+ {
+ strRes = _T("nCnt, BSNALunitDataLocation, SliceBytesInBuffer, wBadSliceChopping,") \
+ _T("first_mb_in_slice, NumMbsForSlice, BitOffsetToSliceData, slice_type,luma_log2_weight_denom,chroma_log2_weight_denom,") \
+ _T("num_ref_idx_l0_active_minus1,num_ref_idx_l1_active_minus1,slice_alpha_c0_offset_div2,slice_beta_offset_div2,") \
+ _T("Reserved8Bits,slice_qs_delta,slice_qp_delta,redundant_pic_cnt,direct_spatial_mv_pred_flag,cabac_init_idc,") \
+ _T("disable_deblocking_filter_idc,slice_id,");
+
+ for (int i=0; i<2; i++) /* L0 & L1 */
+ {
+ for (int j=0; j<32; j++)
+ {
+ strRes.AppendFormat(_T("R[%d][%d].AssociatedFlag,"), i, j);
+ strRes.AppendFormat(_T("R[%d][%d].bPicEntry,"), i, j);
+ strRes.AppendFormat(_T("R[%d][%d].Index7Bits,"), i, j);
+ }
+ }
+
+ for (int a=0; a<2; a++) /* L0 & L1; Y, Cb, Cr */
+ {
+ for (int b=0; b<32; b++)
+ {
+ for (int c=0; c<3; c++)
+ {
+ for (int d=0; d<2; d++)
+ {
+ strRes.AppendFormat(_T("W[%d][%d][%d][%d],"), a,b,c,d);
+ }
+ }
+ }
+ }
+
+
+ LOG_TOFILE (_T("slicelong.log"), strRes);
+ strRes = "";
+ }
+ bFirstSlice = false;
+
+ for (int i=0; i<nCount; i++)
+ {
+ strRes.AppendFormat(_T("%d,"), i);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].BSNALunitDataLocation);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].SliceBytesInBuffer);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].wBadSliceChopping);
+
+ strRes.AppendFormat(_T("%d,"), pSlice[i].first_mb_in_slice);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].NumMbsForSlice);
+
+ strRes.AppendFormat(_T("%d,"), pSlice[i].BitOffsetToSliceData);
+
+ strRes.AppendFormat(_T("%d,"), pSlice[i].slice_type);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].luma_log2_weight_denom);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].chroma_log2_weight_denom);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].num_ref_idx_l0_active_minus1);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].num_ref_idx_l1_active_minus1);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].slice_alpha_c0_offset_div2);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].slice_beta_offset_div2);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].Reserved8Bits);
+
+ strRes.AppendFormat(_T("%d,"), pSlice[i].slice_qs_delta);
+
+ strRes.AppendFormat(_T("%d,"), pSlice[i].slice_qp_delta);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].redundant_pic_cnt);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].direct_spatial_mv_pred_flag);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].cabac_init_idc);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].disable_deblocking_filter_idc);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].slice_id);
+
+ for (int a=0; a<2; a++) /* L0 & L1 */
+ {
+ for (int b=0; b<32; b++)
+ {
+ strRes.AppendFormat(_T("%d,"), pSlice[i].RefPicList[a][b].AssociatedFlag);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].RefPicList[a][b].bPicEntry);
+ strRes.AppendFormat(_T("%d,"), pSlice[i].RefPicList[a][b].Index7Bits);
+ }
+ }
+
+ for (int a=0; a<2; a++) /* L0 & L1; Y, Cb, Cr */
+ {
+ for (int b=0; b<32; b++)
+ {
+ for (int c=0; c<3; c++)
+ {
+ for (int d=0; d<2; d++)
+ {
+ strRes.AppendFormat(_T("%d,"), pSlice[i].Weights[a][b][c][d]);
+ }
+ }
+ }
+ }
+
+ LOG_TOFILE (_T("slicelong.log"), strRes);
+ strRes = "";
+ }
+}
+
+static void LogDXVA_PictureParameters (DXVA_PictureParameters* pPic)
+{
+ static bool bFirstPictureParam = true;
+ CString strRes;
+
+ if (bFirstPictureParam)
+ LOG_TOFILE (_T("picture.log"), _T("wDecodedPictureIndex,wDeblockedPictureIndex,wForwardRefPictureIndex,wBackwardRefPictureIndex,wPicWidthInMBminus1,wPicHeightInMBminus1,bMacroblockWidthMinus1,bMacroblockHeightMinus1,bBlockWidthMinus1,bBlockHeightMinus1,bBPPminus1,bPicStructure,bSecondField,bPicIntra,bPicBackwardPrediction,bBidirectionalAveragingMode,bMVprecisionAndChromaRelation,bChromaFormat,bPicScanFixed,bPicScanMethod,bPicReadbackRequests,bRcontrol,bPicSpatialResid8,bPicOverflowBlocks,bPicExtrapolation,bPicDeblocked,bPicDeblockConfined,bPic4MVallowed,bPicOBMC,bPicBinPB,bMV_RPS,bReservedBits,wBitstreamFcodes,wBitstreamPCEelements,bBitstreamConcealmentNeed,bBitstreamConcealmentMethod"));
+ bFirstPictureParam = false;
+
+ strRes.Format (_T("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d"),
+ pPic->wDecodedPictureIndex,
+ pPic->wDeblockedPictureIndex,
+ pPic->wForwardRefPictureIndex,
+ pPic->wBackwardRefPictureIndex,
+ pPic->wPicWidthInMBminus1,
+ pPic->wPicHeightInMBminus1,
+ pPic->bMacroblockWidthMinus1,
+ pPic->bMacroblockHeightMinus1,
+ pPic->bBlockWidthMinus1,
+ pPic->bBlockHeightMinus1,
+ pPic->bBPPminus1,
+ pPic->bPicStructure,
+ pPic->bSecondField,
+ pPic->bPicIntra,
+ pPic->bPicBackwardPrediction,
+ pPic->bBidirectionalAveragingMode,
+ pPic->bMVprecisionAndChromaRelation,
+ pPic->bChromaFormat,
+ pPic->bPicScanFixed,
+ pPic->bPicScanMethod,
+ pPic->bPicReadbackRequests,
+ pPic->bRcontrol,
+ pPic->bPicSpatialResid8,
+ pPic->bPicOverflowBlocks,
+ pPic->bPicExtrapolation,
+ pPic->bPicDeblocked,
+ pPic->bPicDeblockConfined,
+ pPic->bPic4MVallowed,
+ pPic->bPicOBMC,
+ pPic->bPicBinPB,
+ pPic->bMV_RPS,
+ pPic->bReservedBits,
+ pPic->wBitstreamFcodes,
+ pPic->wBitstreamPCEelements,
+ pPic->bBitstreamConcealmentNeed,
+ pPic->bBitstreamConcealmentMethod);
+
+ LOG_TOFILE (_T("picture.log"), strRes);
+}
+
+void LogDXVA_Bitstream(BYTE* pBuffer, int nSize)
+{
+ CString strRes;
+ static bool bFirstBitstream = true;
+
+ if (bFirstBitstream)
+ LOG_TOFILE (_T("bitstream.log"), _T("Size,Start, Stop"));
+ bFirstBitstream = false;
+
+ strRes.Format (_T("%d, -"), nSize);
+
+ for (int i=0; i<20; i++)
+ {
+ if (i < nSize)
+ strRes.AppendFormat (_T(" %02x"), pBuffer[i]);
+ else
+ strRes.Append(_T(" --"));
+ }
+
+ strRes.Append (_T(", -"), nSize);
+ for (int i=0; i<20; i++)
+ {
+ if (nSize-i >= 0)
+ strRes.AppendFormat (_T(" %02x"), pBuffer[i]);
+ else
+ strRes.Append(_T(" --"));
+ }
+
+ LOG_TOFILE (_T("bitstream.log"), strRes);
+
+}
+
+#else
+inline static void LOG(...) { }
+inline static void LOGPF(LPCTSTR prefix, const DDPIXELFORMAT* p, int n) {}
+inline static void LOGUDI(LPCTSTR prefix, const AMVAUncompDataInfo* p, int n) {}
+inline static void LogDXVA_PicParams_H264 (DXVA_PicParams_H264* pPic) {}
+inline static void LogDXVA_PictureParameters (DXVA_PictureParameters* pPic) {}
+inline static void LogDXVA_Bitstream(BYTE* pBuffer, int nSize) {}
+#endif
+
+
+
+static HRESULT STDMETHODCALLTYPE GetVideoAcceleratorGUIDsMine(IAMVideoAcceleratorC * This, LPDWORD pdwNumGuidsSupported, LPGUID pGuidsSupported)
+{
+ LOG(_T("\nGetVideoAcceleratorGUIDs"));
+
+ if(pdwNumGuidsSupported)
+ {
+ LOG(_T("[in] *pdwNumGuidsSupported = %d"), *pdwNumGuidsSupported);
+ }
+
+ HRESULT hr = GetVideoAcceleratorGUIDsOrg(This, pdwNumGuidsSupported, pGuidsSupported);
+
+ LOG(_T("hr = %08x"), hr);
+
+ if(pdwNumGuidsSupported)
+ {
+ LOG(_T("[out] *pdwNumGuidsSupported = %d"), *pdwNumGuidsSupported);
+
+ if(pGuidsSupported)
+ {
+ for(DWORD i = 0; i < *pdwNumGuidsSupported; i++)
+ {
+ LOG(_T("[out] pGuidsSupported[%d] = %s"), i, CStringFromGUID(pGuidsSupported[i]));
+ }
+ }
+ }
+
+ return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE GetUncompFormatsSupportedMine(IAMVideoAcceleratorC * This, const GUID *pGuid, LPDWORD pdwNumFormatsSupported, LPDDPIXELFORMAT pFormatsSupported)
+{
+ LOG(_T("\nGetUncompFormatsSupported"));
+
+ if(pGuid)
+ {
+ LOG(_T("[in] *pGuid = %s"), CStringFromGUID(*pGuid));
+ }
+
+ if(pdwNumFormatsSupported)
+ {
+ LOG(_T("[in] *pdwNumFormatsSupported = %d"), *pdwNumFormatsSupported);
+ }
+
+ HRESULT hr = GetUncompFormatsSupportedOrg(This, pGuid, pdwNumFormatsSupported, pFormatsSupported);
+
+ LOG(_T("hr = %08x"), hr);
+
+ if(pdwNumFormatsSupported)
+ {
+ LOG(_T("[out] *pdwNumFormatsSupported = %d"), *pdwNumFormatsSupported);
+
+ if(pFormatsSupported)
+ {
+ LOGPF(_T("[out] pFormatsSupported"), pFormatsSupported, *pdwNumFormatsSupported);
+ }
+ }
+
+ return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE GetInternalMemInfoMine(IAMVideoAcceleratorC * This, const GUID *pGuid, const AMVAUncompDataInfo *pamvaUncompDataInfo, LPAMVAInternalMemInfo pamvaInternalMemInfo)
+{
+ LOG(_T("\nGetInternalMemInfo"));
+
+ HRESULT hr = GetInternalMemInfoOrg(This, pGuid, pamvaUncompDataInfo, pamvaInternalMemInfo);
+
+ LOG(_T("hr = %08x"), hr);
+
+ return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE GetCompBufferInfoMine(IAMVideoAcceleratorC * This, const GUID *pGuid, const AMVAUncompDataInfo *pamvaUncompDataInfo, LPDWORD pdwNumTypesCompBuffers, LPAMVACompBufferInfo pamvaCompBufferInfo)
+{
+ LOG(_T("\nGetCompBufferInfo"));
+
+ if(pGuid)
+ {
+ g_guidDXVADecoder = *pGuid;
+ g_nDXVAVersion = 1;
+ LOG(_T("[in] *pGuid = %s"), CStringFromGUID(*pGuid));
+
+ if(pdwNumTypesCompBuffers)
+ {
+ LOG(_T("[in] *pdwNumTypesCompBuffers = %d"), *pdwNumTypesCompBuffers);
+ }
+ }
+
+ HRESULT hr = GetCompBufferInfoOrg(This, pGuid, pamvaUncompDataInfo, pdwNumTypesCompBuffers, pamvaCompBufferInfo);
+
+ LOG(_T("hr = %08x"), hr);
+
+ //if(pdwNumTypesCompBuffers)
+ //{
+ // LOG(_T("[out] *pdwNumTypesCompBuffers = %d"), *pdwNumTypesCompBuffers);
+
+ // if(pamvaUncompDataInfo)
+ // {
+ // LOGUDI(_T("[out] pamvaUncompDataInfo"), pamvaUncompDataInfo, *pdwNumTypesCompBuffers);
+ // }
+ //}
+
+ return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE GetInternalCompBufferInfoMine(IAMVideoAcceleratorC * This, LPDWORD pdwNumTypesCompBuffers, LPAMVACompBufferInfo pamvaCompBufferInfo)
+{
+ LOG(_T("\nGetInternalCompBufferInfo"));
+
+ HRESULT hr = GetInternalCompBufferInfoOrg(This, pdwNumTypesCompBuffers, pamvaCompBufferInfo);
+
+ LOG(_T("hr = %08x"), hr);
+
+ return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE BeginFrameMine(IAMVideoAcceleratorC * This, const AMVABeginFrameInfo *amvaBeginFrameInfo)
+{
+ LOG(_T("\nBeginFrame"));
+
+ if(amvaBeginFrameInfo)
+ {
+ LOG(_T("[in] amvaBeginFrameInfo->dwDestSurfaceIndex = %08x"), amvaBeginFrameInfo->dwDestSurfaceIndex);
+ LOG(_T("[in] amvaBeginFrameInfo->pInputData = %08x"), amvaBeginFrameInfo->pInputData);
+ LOG(_T("[in] amvaBeginFrameInfo->dwSizeInputData = %08x"), amvaBeginFrameInfo->dwSizeInputData);
+ LOG(_T("[in] amvaBeginFrameInfo->pOutputData = %08x"), amvaBeginFrameInfo->pOutputData);
+ LOG(_T("[in] amvaBeginFrameInfo->dwSizeOutputData = %08x"), amvaBeginFrameInfo->dwSizeOutputData);
+ }
+ if(amvaBeginFrameInfo && (amvaBeginFrameInfo->dwSizeInputData == 4))
+ {
+ LOG(_T("[in] amvaBeginFrameInfo->pInputData => dwDestSurfaceIndex = %ld "),
+ ((DWORD*)amvaBeginFrameInfo->pInputData)[0]);
+ }
+
+
+ HRESULT hr = BeginFrameOrg(This, amvaBeginFrameInfo);
+
+ LOG(_T("hr = %08x"), hr);
+
+ return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE EndFrameMine(IAMVideoAcceleratorC * This, const AMVAEndFrameInfo *pEndFrameInfo)
+{
+ LOG(_T("\nEndFrame"));
+
+ if(pEndFrameInfo)
+ {
+ LOG(_T("[in] pEndFrameInfo->dwSizeMiscData = %08x"), pEndFrameInfo->dwSizeMiscData);
+ LOG(_T("[in] pEndFrameInfo->pMiscData = %08x"), pEndFrameInfo->pMiscData);
+
+ if (pEndFrameInfo->dwSizeMiscData >= 4)
+ LOG(_T("[out] pEndFrameInfo->pMiscData = %02x %02x %02x %02x "),
+ ((BYTE*)pEndFrameInfo->pMiscData)[0],
+ ((BYTE*)pEndFrameInfo->pMiscData)[1],
+ ((BYTE*)pEndFrameInfo->pMiscData)[2],
+ ((BYTE*)pEndFrameInfo->pMiscData)[3]);
+
+ }
+
+ HRESULT hr = EndFrameOrg(This, pEndFrameInfo);
+
+ LOG(_T("hr = %08x"), hr);
+
+ return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE GetBufferMine(IAMVideoAcceleratorC * This, DWORD dwTypeIndex, DWORD dwBufferIndex, BOOL bReadOnly, LPVOID *ppBuffer, LONG *lpStride)
+{
+
+ HRESULT hr = GetBufferOrg(This, dwTypeIndex, dwBufferIndex, bReadOnly, ppBuffer, lpStride);
+
+ LOG(_T("\nGetBuffer"));
+
+ LOG(_T("[in] dwTypeIndex = %08x"), dwTypeIndex);
+ LOG(_T("[in] dwBufferIndex = %08x"), dwBufferIndex);
+ LOG(_T("[in] bReadOnly = %08x"), bReadOnly);
+ LOG(_T("[in] ppBuffer = %08x"), ppBuffer);
+ LOG(_T("[out] *lpStride = %08x"), *lpStride);
+ LOG(_T("hr = %08x"), hr);
+
+ g_ppBuffer [dwTypeIndex] = (BYTE*)*ppBuffer;
+ //LOG(_T("[out] *ppBuffer = %02x %02x %02x %02x ..."), ((BYTE*)*ppBuffer)[0], ((BYTE*)*ppBuffer)[1], ((BYTE*)*ppBuffer)[2], ((BYTE*)*ppBuffer)[3]);
+
+ return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE ReleaseBufferMine(IAMVideoAcceleratorC * This, DWORD dwTypeIndex, DWORD dwBufferIndex)
+{
+ LOG(_T("\nReleaseBuffer"));
+
+ LOG(_T("[in] dwTypeIndex = %08x"), dwTypeIndex);
+ LOG(_T("[in] dwBufferIndex = %08x"), dwBufferIndex);
+
+ HRESULT hr = ReleaseBufferOrg(This, dwTypeIndex, dwBufferIndex);
+
+ LOG(_T("hr = %08x"), hr);
+
+ return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE ExecuteMine(IAMVideoAcceleratorC* This, DWORD dwFunction, LPVOID lpPrivateInputData, DWORD cbPrivateInputData,
+ LPVOID lpPrivateOutputData, DWORD cbPrivateOutputData, DWORD dwNumBuffers, const AMVABUFFERINFO *pamvaBufferInfo)
+{
+#ifdef _DEBUG
+ LOG(_T("\nExecute"));
+ LOG(_T("[in] dwFunction = %08x"), dwFunction);
+ if(lpPrivateInputData)
+ {
+ if (dwFunction == 0x01000000)
+ {
+ DXVA_BufferDescription* pBuffDesc = (DXVA_BufferDescription*)lpPrivateInputData;
+
+ for (DWORD i=0; i<dwNumBuffers; i++)
+ {
+ LOG(_T("[in] lpPrivateInputData, buffer description %d"), i);
+ LOG(_T(" pBuffDesc->dwTypeIndex = %d"), pBuffDesc[i].dwTypeIndex);
+ LOG(_T(" pBuffDesc->dwBufferIndex = %d"), pBuffDesc[i].dwBufferIndex);
+ LOG(_T(" pBuffDesc->dwDataOffset = %d"), pBuffDesc[i].dwDataOffset);
+ LOG(_T(" pBuffDesc->dwDataSize = %d"), pBuffDesc[i].dwDataSize);
+ LOG(_T(" pBuffDesc->dwFirstMBaddress = %d"), pBuffDesc[i].dwFirstMBaddress);
+ LOG(_T(" pBuffDesc->dwHeight = %d"), pBuffDesc[i].dwHeight);
+ LOG(_T(" pBuffDesc->dwStride = %d"), pBuffDesc[i].dwStride);
+ LOG(_T(" pBuffDesc->dwWidth = %d"), pBuffDesc[i].dwWidth);
+ LOG(_T(" pBuffDesc->dwNumMBsInBuffer = %d"), pBuffDesc[i].dwNumMBsInBuffer);
+ LOG(_T(" pBuffDesc->dwReservedBits = %d"), pBuffDesc[i].dwReservedBits);
+ }
+ }
+ else if ((dwFunction == 0xfffff101) || (dwFunction == 0xfffff501))
+ {
+ DXVA_ConfigPictureDecode* ConfigRequested = (DXVA_ConfigPictureDecode*)lpPrivateInputData;
+ LOG(_T("[in] lpPrivateInputData, config requested"));
+ LOG(_T(" pBuffDesc->dwTypeIndex = %d"), ConfigRequested->bConfig4GroupedCoefs);
+ LOG(_T(" ConfigRequested->bConfigBitstreamRaw = %d"), ConfigRequested->bConfigBitstreamRaw);
+ LOG(_T(" ConfigRequested->bConfigHostInverseScan = %d"), ConfigRequested->bConfigHostInverseScan);
+ LOG(_T(" ConfigRequested->bConfigIntraResidUnsigned = %d"), ConfigRequested->bConfigIntraResidUnsigned);
+ LOG(_T(" ConfigRequested->bConfigMBcontrolRasterOrder = %d"), ConfigRequested->bConfigMBcontrolRasterOrder);
+ LOG(_T(" ConfigRequested->bConfigResid8Subtraction = %d"), ConfigRequested->bConfigResid8Subtraction);
+ LOG(_T(" ConfigRequested->bConfigResidDiffAccelerator = %d"), ConfigRequested->bConfigResidDiffAccelerator);
+ LOG(_T(" ConfigRequested->bConfigResidDiffHost = %d"), ConfigRequested->bConfigResidDiffHost);
+ LOG(_T(" ConfigRequested->bConfigSpatialHost8or9Clipping= %d"), ConfigRequested->bConfigSpatialHost8or9Clipping);
+ LOG(_T(" ConfigRequested->bConfigSpatialResid8 = %d"), ConfigRequested->bConfigSpatialResid8);
+ LOG(_T(" ConfigRequested->bConfigSpatialResidInterleaved= %d"), ConfigRequested->bConfigSpatialResidInterleaved);
+ LOG(_T(" ConfigRequested->bConfigSpecificIDCT = %d"), ConfigRequested->bConfigSpecificIDCT);
+ LOG(_T(" ConfigRequested->dwFunction = %d"), ConfigRequested->dwFunction);
+ LOG(_T(" ConfigRequested->guidConfigBitstreamEncryption = %s"), CStringFromGUID (ConfigRequested->guidConfigBitstreamEncryption));
+ LOG(_T(" ConfigRequested->guidConfigMBcontrolEncryption = %s"), CStringFromGUID (ConfigRequested->guidConfigMBcontrolEncryption));
+ LOG(_T(" ConfigRequested->guidConfigResidDiffEncryption = %s"), CStringFromGUID (ConfigRequested->guidConfigResidDiffEncryption));
+ }
+ else
+ LOG(_T("[in] lpPrivateInputData = %02x %02x %02x %02x ..."),
+ ((BYTE*)lpPrivateInputData)[0],
+ ((BYTE*)lpPrivateInputData)[1],
+ ((BYTE*)lpPrivateInputData)[2],
+ ((BYTE*)lpPrivateInputData)[3]);
+ }
+ LOG(_T("[in] cbPrivateInputData = %08x"), cbPrivateInputData);
+ LOG(_T("[in] lpPrivateOutputData = %08x"), lpPrivateOutputData);
+ LOG(_T("[in] cbPrivateOutputData = %08x"), cbPrivateOutputData);
+ LOG(_T("[in] dwNumBuffers = %08x"), dwNumBuffers);
+ if(pamvaBufferInfo)
+ {
+ for (DWORD i=0; i<dwNumBuffers; i++)
+ {
+ LOG(_T("[in] pamvaBufferInfo, buffer description %d"), i);
+ LOG(_T("[in] pamvaBufferInfo->dwTypeIndex = %08x"), pamvaBufferInfo[i].dwTypeIndex);
+ LOG(_T("[in] pamvaBufferInfo->dwBufferIndex = %08x"), pamvaBufferInfo[i].dwBufferIndex);
+ LOG(_T("[in] pamvaBufferInfo->dwDataOffset = %08x"), pamvaBufferInfo[i].dwDataOffset);
+ LOG(_T("[in] pamvaBufferInfo->dwDataSize = %08x"), pamvaBufferInfo[i].dwDataSize);
+ }
+ }
+
+
+ for (DWORD i=0; i<dwNumBuffers; i++)
+ {
+ if (pamvaBufferInfo[i].dwTypeIndex == DXVA_PICTURE_DECODE_BUFFER)
+ {
+ if (g_guidDXVADecoder == DXVA2_ModeH264_E || g_guidDXVADecoder == DXVA_Intel_H264_ClearVideo)
+ LogDXVA_PicParams_H264 ((DXVA_PicParams_H264*)g_ppBuffer[pamvaBufferInfo[i].dwTypeIndex]);
+ else if (g_guidDXVADecoder == DXVA2_ModeVC1_D)
+ LogDXVA_PictureParameters((DXVA_PictureParameters*)g_ppBuffer[pamvaBufferInfo[i].dwTypeIndex]);
+ }
+ else if (pamvaBufferInfo[i].dwTypeIndex == DXVA_SLICE_CONTROL_BUFFER && (pamvaBufferInfo[i].dwDataSize % sizeof(DXVA_Slice_H264_Short)) == 0)
+ {
+ for (WORD j=0; j<pamvaBufferInfo[i].dwDataSize / sizeof(DXVA_Slice_H264_Short); j++)
+ {
+ DXVA_Slice_H264_Short* pSlice = &(((DXVA_Slice_H264_Short*)g_ppBuffer[pamvaBufferInfo[i].dwTypeIndex])[j]);
+ LOG(_T(" - BSNALunitDataLocation %d"), pSlice->BSNALunitDataLocation);
+ LOG(_T(" - SliceBytesInBuffer %d"), pSlice->SliceBytesInBuffer);
+ LOG(_T(" - wBadSliceChopping %d"), pSlice->wBadSliceChopping);
+ }
+ }
+ else if (pamvaBufferInfo[i].dwTypeIndex == DXVA_BITSTREAM_DATA_BUFFER)
+ {
+
+ LogDXVA_Bitstream(g_ppBuffer[pamvaBufferInfo[i].dwTypeIndex], pamvaBufferInfo[i].dwDataSize);
+#if defined(LOG_BITSTREAM) && defined(_DEBUG)
+ char strFile[_MAX_PATH];
+ static int nNb = 1;
+ sprintf (strFile, "BitStream%d.bin", nNb++);
+ FILE* hFile = fopen (strFile, "wb");
+ if (hFile)
+ {
+ fwrite (g_ppBuffer[pamvaBufferInfo[i].dwTypeIndex],
+ 1,
+ pamvaBufferInfo[i].dwDataSize,
+ hFile);
+ fclose (hFile);
+ }
+#endif
+ }
+ }
+#endif
+
+ HRESULT hr = ExecuteOrg(This, dwFunction, lpPrivateInputData, cbPrivateInputData, lpPrivateOutputData, cbPrivateOutputData, dwNumBuffers, pamvaBufferInfo);
+
+ LOG(_T("hr = %08x"), hr);
+
+ if(lpPrivateOutputData && (dwFunction == 0x01000000))
+ {
+ LOG(_T("[out] *lpPrivateOutputData : Result = %08x"), ((DWORD*)lpPrivateOutputData)[0]);
+ }
+
+ return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE QueryRenderStatusMine(IAMVideoAcceleratorC * This, DWORD dwTypeIndex, DWORD dwBufferIndex, DWORD dwFlags)
+{
+
+ HRESULT hr = QueryRenderStatusOrg(This, dwTypeIndex, dwBufferIndex, dwFlags);
+ LOG(_T("\nQueryRenderStatus Type=%d Index=%d hr = %08x"), dwTypeIndex, dwBufferIndex, hr);
+
+ return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE DisplayFrameMine(IAMVideoAcceleratorC * This, DWORD dwFlipToIndex, IMediaSample *pMediaSample)
+{
+ LOG(_T("\nEnter DisplayFrame : %d"), dwFlipToIndex);
+
+ HRESULT hr = DisplayFrameOrg(This, dwFlipToIndex, pMediaSample);
+
+ LOG(_T("Leave DisplayFrame : hr = %08x"), hr);
+
+ return hr;
+}
+
+void HookAMVideoAccelerator(IAMVideoAcceleratorC* pAMVideoAcceleratorC)
+{
+ BOOL res;
+ DWORD flOldProtect = 0;
+ res = VirtualProtect(pAMVideoAcceleratorC->lpVtbl, sizeof(IAMVideoAcceleratorC), PAGE_WRITECOPY, &flOldProtect);
+
+ g_guidDXVADecoder = GUID_NULL;
+ g_nDXVAVersion = 0;
+
+ if(GetVideoAcceleratorGUIDsOrg == NULL) GetVideoAcceleratorGUIDsOrg = pAMVideoAcceleratorC->lpVtbl->GetVideoAcceleratorGUIDs;
+ if(GetUncompFormatsSupportedOrg == NULL) GetUncompFormatsSupportedOrg = pAMVideoAcceleratorC->lpVtbl->GetUncompFormatsSupported;
+ if(GetInternalMemInfoOrg == NULL) GetInternalMemInfoOrg = pAMVideoAcceleratorC->lpVtbl->GetInternalMemInfo;
+ if(GetCompBufferInfoOrg == NULL) GetCompBufferInfoOrg = pAMVideoAcceleratorC->lpVtbl->GetCompBufferInfo;
+ if(GetInternalCompBufferInfoOrg == NULL) GetInternalCompBufferInfoOrg = pAMVideoAcceleratorC->lpVtbl->GetInternalCompBufferInfo;
+ if(BeginFrameOrg == NULL) BeginFrameOrg = pAMVideoAcceleratorC->lpVtbl->BeginFrame;
+ if(EndFrameOrg == NULL) EndFrameOrg = pAMVideoAcceleratorC->lpVtbl->EndFrame;
+ if(GetBufferOrg == NULL) GetBufferOrg = pAMVideoAcceleratorC->lpVtbl->GetBuffer;
+ if(ReleaseBufferOrg == NULL) ReleaseBufferOrg = pAMVideoAcceleratorC->lpVtbl->ReleaseBuffer;
+ if(ExecuteOrg == NULL) ExecuteOrg = pAMVideoAcceleratorC->lpVtbl->Execute;
+ if(QueryRenderStatusOrg == NULL) QueryRenderStatusOrg = pAMVideoAcceleratorC->lpVtbl->QueryRenderStatus;
+ if(DisplayFrameOrg == NULL) DisplayFrameOrg = pAMVideoAcceleratorC->lpVtbl->DisplayFrame;
+
+ pAMVideoAcceleratorC->lpVtbl->GetVideoAcceleratorGUIDs = GetVideoAcceleratorGUIDsMine;
+ pAMVideoAcceleratorC->lpVtbl->GetUncompFormatsSupported = GetUncompFormatsSupportedMine;
+ pAMVideoAcceleratorC->lpVtbl->GetInternalMemInfo = GetInternalMemInfoMine;
+ pAMVideoAcceleratorC->lpVtbl->GetCompBufferInfo = GetCompBufferInfoMine;
+ pAMVideoAcceleratorC->lpVtbl->GetInternalCompBufferInfo = GetInternalCompBufferInfoMine;
+ pAMVideoAcceleratorC->lpVtbl->BeginFrame = BeginFrameMine;
+ pAMVideoAcceleratorC->lpVtbl->EndFrame = EndFrameMine;
+ pAMVideoAcceleratorC->lpVtbl->GetBuffer = GetBufferMine;
+ pAMVideoAcceleratorC->lpVtbl->ReleaseBuffer = ReleaseBufferMine;
+ pAMVideoAcceleratorC->lpVtbl->Execute = ExecuteMine;
+ pAMVideoAcceleratorC->lpVtbl->QueryRenderStatus = QueryRenderStatusMine;
+ pAMVideoAcceleratorC->lpVtbl->DisplayFrame = DisplayFrameMine;
+
+ res = VirtualProtect(pAMVideoAcceleratorC->lpVtbl, sizeof(IAMVideoAcceleratorC), PAGE_EXECUTE, &flOldProtect);
+
+#ifdef _DEBUG
+ ::DeleteFile (LOG_FILE);
+ ::DeleteFile (_T("picture.log"));
+ ::DeleteFile (_T("slicelong.log"));
+ ::DeleteFile (_T("sliceshort.log"));
+ ::DeleteFile (_T("bitstream.log"));
+#endif
+}
+
+
+
+// === Hook for DXVA2
+
+
+static void LogDecodeBufferDesc(DXVA2_DecodeBufferDesc* pDecodeBuff)
+{
+ LOG(_T("DecodeBufferDesc type : %d Size=%d NumMBsInBuffer=%d"), pDecodeBuff->CompressedBufferType, pDecodeBuff->DataSize, pDecodeBuff->NumMBsInBuffer);
+ //LOG(_T(" - BufferIndex %d"), pDecodeBuff->BufferIndex);
+ //LOG(_T(" - DataOffset %d"), pDecodeBuff->DataOffset);
+ //LOG(_T(" - DataSize %d"), pDecodeBuff->DataSize);
+ //LOG(_T(" - FirstMBaddress %d"), pDecodeBuff->FirstMBaddress);
+ //LOG(_T(" - NumMBsInBuffer %d"), pDecodeBuff->NumMBsInBuffer);
+ //LOG(_T(" - Width %d"), pDecodeBuff->Width);
+ //LOG(_T(" - Height %d"), pDecodeBuff->Height);
+ //LOG(_T(" - Stride %d"), pDecodeBuff->Stride);
+ //LOG(_T(" - ReservedBits %d"), pDecodeBuff->ReservedBits);
+ //LOG(_T(" - pvPVPState %d"), pDecodeBuff->pvPVPState);
+}
+
+class CFakeDirectXVideoDecoder : public CUnknown, public IDirectXVideoDecoder
+{
+private :
+ CComPtr<IDirectXVideoDecoder> m_pDec;
+ BYTE* m_ppBuffer[MAX_BUFFER_TYPE];
+ UINT m_ppBufferLen[MAX_BUFFER_TYPE];
+
+public :
+ CFakeDirectXVideoDecoder(LPUNKNOWN pUnk, IDirectXVideoDecoder* pDec) : CUnknown(_T("Fake DXVA2 Dec"), pUnk)
+ {
+ m_pDec.Attach (pDec);
+ memset (m_ppBuffer, 0, sizeof(m_ppBuffer));
+ }
+
+ ~CFakeDirectXVideoDecoder()
+ {
+ LOG(_T("CFakeDirectXVideoDecoder destroyed !\n"));
+ }
+
+ DECLARE_IUNKNOWN;
+
+ STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv)
+ {
+ if(riid == __uuidof(IDirectXVideoDecoder))
+ return GetInterface((IDirectXVideoDecoder*)this, ppv);
+ else
+ return __super::NonDelegatingQueryInterface(riid, ppv);
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetVideoDecoderService(IDirectXVideoDecoderService **ppService)
+ {
+ HRESULT hr = m_pDec->GetVideoDecoderService (ppService);
+ LOG(_T("IDirectXVideoDecoder::GetVideoDecoderService hr = %08x\n"), hr);
+ return hr;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetCreationParameters(GUID *pDeviceGuid, DXVA2_VideoDesc *pVideoDesc, DXVA2_ConfigPictureDecode *pConfig, IDirect3DSurface9 ***pDecoderRenderTargets, UINT *pNumSurfaces)
+ {
+ HRESULT hr = m_pDec->GetCreationParameters(pDeviceGuid, pVideoDesc, pConfig, pDecoderRenderTargets, pNumSurfaces);
+ LOG(_T("IDirectXVideoDecoder::GetCreationParameters hr = %08x\n"), hr);
+ return hr;
+ }
+
+
+ virtual HRESULT STDMETHODCALLTYPE GetBuffer(UINT BufferType, void **ppBuffer, UINT *pBufferSize)
+ {
+ HRESULT hr = m_pDec->GetBuffer(BufferType, ppBuffer, pBufferSize);
+
+ if (BufferType < MAX_BUFFER_TYPE)
+ {
+ m_ppBuffer[BufferType] = (BYTE*)*ppBuffer;
+ m_ppBufferLen[BufferType] = *pBufferSize;
+ }
+// LOG(_T("IDirectXVideoDecoder::GetBuffer Type = %d, hr = %08x"), BufferType, hr);
+
+ return hr;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer(UINT BufferType)
+ {
+ HRESULT hr = m_pDec->ReleaseBuffer (BufferType);
+// LOG(_T("IDirectXVideoDecoder::ReleaseBuffer Type = %d, hr = %08x"), BufferType, hr);
+ return hr;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE BeginFrame(IDirect3DSurface9 *pRenderTarget, void *pvPVPData)
+ {
+ HRESULT hr = m_pDec->BeginFrame (pRenderTarget, pvPVPData);
+ LOG(_T("IDirectXVideoDecoder::BeginFrame pRenderTarget = %08x, hr = %08x"), pRenderTarget, hr);
+ return hr;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE EndFrame(HANDLE *pHandleComplete)
+ {
+ HRESULT hr = m_pDec->EndFrame (pHandleComplete);
+ LOG(_T("IDirectXVideoDecoder::EndFrame Handle=0x%08x hr = %08x\n"), pHandleComplete, hr);
+ return hr;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE Execute(const DXVA2_DecodeExecuteParams *pExecuteParams)
+ {
+ for (DWORD i=0; i<pExecuteParams->NumCompBuffers; i++)
+ {
+ CString strBuffer;
+
+ LogDecodeBufferDesc (&pExecuteParams->pCompressedBuffers[i]);
+ /*
+ for (int j=0; j<4000 && j<pExecuteParams->pCompressedBuffers[i].DataSize; j++)
+ strBuffer.AppendFormat (_T("%02x "), m_ppBuffer[pExecuteParams->pCompressedBuffers[i].CompressedBufferType][j]);
+
+ LOG (_T(" - Buffer type=%d, offset=%d, size=%d"),
+ pExecuteParams->pCompressedBuffers[i].CompressedBufferType,
+ pExecuteParams->pCompressedBuffers[i].DataOffset,
+ pExecuteParams->pCompressedBuffers[i].DataSize);
+
+ LOG (strBuffer);*/
+
+ if (pExecuteParams->pCompressedBuffers[i].CompressedBufferType == DXVA2_PictureParametersBufferType)
+ {
+ if (g_guidDXVADecoder == DXVA2_ModeH264_E || g_guidDXVADecoder == DXVA_Intel_H264_ClearVideo)
+ LogDXVA_PicParams_H264 ((DXVA_PicParams_H264*)m_ppBuffer[pExecuteParams->pCompressedBuffers[i].CompressedBufferType]);
+ else if (g_guidDXVADecoder == DXVA2_ModeVC1_D || g_guidDXVADecoder == DXVA2_ModeMPEG2_VLD)
+ LogDXVA_PictureParameters((DXVA_PictureParameters*)m_ppBuffer[pExecuteParams->pCompressedBuffers[i].CompressedBufferType]);
+ }
+
+#if defined(_DEBUG)
+ if (g_guidDXVADecoder == DXVA2_ModeH264_E || g_guidDXVADecoder == DXVA_Intel_H264_ClearVideo)
+ {
+ if (pExecuteParams->pCompressedBuffers[i].CompressedBufferType == DXVA2_SliceControlBufferType)
+ {
+ if (pExecuteParams->pCompressedBuffers[i].DataSize % sizeof(DXVA_Slice_H264_Long) == 0)
+ {
+ DXVA_Slice_H264_Long* pSlice = (DXVA_Slice_H264_Long*)m_ppBuffer[pExecuteParams->pCompressedBuffers[i].CompressedBufferType];
+ LogH264SliceLong (pSlice, pExecuteParams->pCompressedBuffers[i].DataSize / sizeof(DXVA_Slice_H264_Long));
+ }
+ else if (pExecuteParams->pCompressedBuffers[i].DataSize % sizeof(DXVA_Slice_H264_Short) == 0)
+ {
+ DXVA_Slice_H264_Short* pSlice = (DXVA_Slice_H264_Short*)m_ppBuffer[pExecuteParams->pCompressedBuffers[i].CompressedBufferType];
+ LogH264SliceShort (pSlice, pExecuteParams->pCompressedBuffers[i].DataSize / sizeof(DXVA_Slice_H264_Short));
+ }
+ }
+ }
+ else if (g_guidDXVADecoder == DXVA2_ModeMPEG2_VLD)
+ {
+ if (pExecuteParams->pCompressedBuffers[i].CompressedBufferType == DXVA2_SliceControlBufferType)
+ {
+ DXVA_SliceInfo* pSlice = (DXVA_SliceInfo*)m_ppBuffer[pExecuteParams->pCompressedBuffers[i].CompressedBufferType];
+ LogSliceInfo (pSlice, pExecuteParams->pCompressedBuffers[i].DataSize / sizeof(DXVA_SliceInfo));
+ }
+ }
+#endif
+
+#if defined(LOG_MATRIX) && defined(_DEBUG)
+ if (pExecuteParams->pCompressedBuffers[i].CompressedBufferType == DXVA2_InverseQuantizationMatrixBufferType)
+ {
+ char strFile[_MAX_PATH];
+ static int nNb = 1;
+ sprintf (strFile, "Matrix%d.bin", nNb++);
+ FILE* hFile = fopen (strFile, "wb");
+ if (hFile)
+ {
+ fwrite (m_ppBuffer[pExecuteParams->pCompressedBuffers[i].CompressedBufferType],
+ 1,
+ pExecuteParams->pCompressedBuffers[i].DataSize,
+ hFile);
+ fclose (hFile);
+ }
+ }
+#endif
+
+#if defined(_DEBUG)
+ if (pExecuteParams->pCompressedBuffers[i].CompressedBufferType == DXVA2_BitStreamDateBufferType)
+ {
+ LogDXVA_Bitstream(m_ppBuffer[pExecuteParams->pCompressedBuffers[i].CompressedBufferType], pExecuteParams->pCompressedBuffers[i].DataSize);
+#if defined(LOG_BITSTREAM)
+ char strFile[_MAX_PATH];
+ static int nNb = 1;
+ sprintf (strFile, "BitStream%d.bin", nNb++);
+ FILE* hFile = fopen (strFile, "wb");
+ if (hFile)
+ {
+ fwrite (m_ppBuffer[pExecuteParams->pCompressedBuffers[i].CompressedBufferType],
+ 1,
+ pExecuteParams->pCompressedBuffers[i].DataSize,
+ hFile);
+ fclose (hFile);
+ }
+#endif
+ }
+#endif
+ }
+
+ HRESULT hr = m_pDec->Execute (pExecuteParams);
+
+ if (pExecuteParams->pExtensionData)
+ LOG(_T("IDirectXVideoDecoder::Execute %d buffer, fct = %d (in=%d, out=%d), hr = %08x"),
+ pExecuteParams->NumCompBuffers,
+ pExecuteParams->pExtensionData->Function,
+ pExecuteParams->pExtensionData->PrivateInputDataSize,
+ pExecuteParams->pExtensionData->PrivateOutputDataSize,
+ hr);
+ else
+ LOG(_T("IDirectXVideoDecoder::Execute %d buffer, hr = %08x"), pExecuteParams->NumCompBuffers, hr);
+ return hr;
+ }
+};
+
+
+interface IDirectXVideoDecoderServiceC;
+struct IDirectXVideoDecoderServiceCVtbl
+{
+ BEGIN_INTERFACE
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IDirectXVideoDecoderServiceC* pThis, /* [in] */ REFIID riid, /* [iid_is][out] */ void **ppvObject );
+ ULONG ( STDMETHODCALLTYPE *AddRef )(IDirectXVideoDecoderServiceC* pThis);
+ ULONG ( STDMETHODCALLTYPE *Release )(IDirectXVideoDecoderServiceC* pThis);
+ HRESULT (STDMETHODCALLTYPE* CreateSurface)(IDirectXVideoDecoderServiceC* pThis, __in UINT Width, __in UINT Height, __in UINT BackBuffers, __in D3DFORMAT Format, __in D3DPOOL Pool, __in DWORD Usage, __in DWORD DxvaType, __out_ecount(BackBuffers+1) IDirect3DSurface9 **ppSurface, __inout_opt HANDLE *pSharedHandle);
+
+ HRESULT (STDMETHODCALLTYPE* GetDecoderDeviceGuids)(
+ IDirectXVideoDecoderServiceC* pThis,
+ __out UINT* pCount,
+ __deref_out_ecount_opt(*pCount) GUID** pGuids);
+
+ HRESULT (STDMETHODCALLTYPE* GetDecoderRenderTargets)(
+ IDirectXVideoDecoderServiceC* pThis,
+ __in REFGUID Guid,
+ __out UINT* pCount,
+ __deref_out_ecount_opt(*pCount) D3DFORMAT** pFormats);
+
+ HRESULT (STDMETHODCALLTYPE* GetDecoderConfigurations)(
+ IDirectXVideoDecoderServiceC* pThis,
+ __in REFGUID Guid,
+ __in const DXVA2_VideoDesc* pVideoDesc,
+ __reserved void* pReserved,
+ __out UINT* pCount,
+ __deref_out_ecount_opt(*pCount) DXVA2_ConfigPictureDecode **ppConfigs);
+
+ HRESULT (STDMETHODCALLTYPE* CreateVideoDecoder)(
+ IDirectXVideoDecoderServiceC* pThis,
+ __in REFGUID Guid,
+ __in const DXVA2_VideoDesc* pVideoDesc,
+ __in const DXVA2_ConfigPictureDecode* pConfig,
+ __in_ecount(NumRenderTargets) IDirect3DSurface9 **ppDecoderRenderTargets,
+ __in UINT NumRenderTargets,
+ __deref_out IDirectXVideoDecoder** ppDecode);
+
+ END_INTERFACE
+};
+
+interface IDirectXVideoDecoderServiceC
+{
+ CONST_VTBL struct IDirectXVideoDecoderServiceCVtbl *lpVtbl;
+};
+
+
+IDirectXVideoDecoderServiceCVtbl* g_pIDirectXVideoDecoderServiceCVtbl;
+static HRESULT (STDMETHODCALLTYPE* CreateVideoDecoderOrg ) (IDirectXVideoDecoderServiceC* pThis, __in REFGUID Guid, __in const DXVA2_VideoDesc* pVideoDesc, __in const DXVA2_ConfigPictureDecode* pConfig, __in_ecount(NumRenderTargets) IDirect3DSurface9 **ppDecoderRenderTargets, __in UINT NumRenderTargets, __deref_out IDirectXVideoDecoder** ppDecode) = NULL;
+static HRESULT (STDMETHODCALLTYPE* GetDecoderDeviceGuidsOrg)(IDirectXVideoDecoderServiceC* pThis, __out UINT* pCount, __deref_out_ecount_opt(*pCount) GUID** pGuids) = NULL;
+static HRESULT (STDMETHODCALLTYPE* GetDecoderConfigurationsOrg) (IDirectXVideoDecoderServiceC* pThis, __in REFGUID Guid, __in const DXVA2_VideoDesc* pVideoDesc, __reserved void* pReserved, __out UINT* pCount, __deref_out_ecount_opt(*pCount) DXVA2_ConfigPictureDecode **ppConfigs) = NULL;
+
+
+
+static void LogDXVA2Config (const DXVA2_ConfigPictureDecode* pConfig)
+{
+ LOG(_T("Config"));
+ LOG(_T(" - Config4GroupedCoefs %d"), pConfig->Config4GroupedCoefs);
+ LOG(_T(" - ConfigBitstreamRaw %d"), pConfig->ConfigBitstreamRaw);
+ LOG(_T(" - ConfigDecoderSpecific %d"), pConfig->ConfigDecoderSpecific);
+ LOG(_T(" - ConfigHostInverseScan %d"), pConfig->ConfigHostInverseScan);
+ LOG(_T(" - ConfigIntraResidUnsigned %d"), pConfig->ConfigIntraResidUnsigned);
+ LOG(_T(" - ConfigMBcontrolRasterOrder %d"), pConfig->ConfigMBcontrolRasterOrder);
+ LOG(_T(" - ConfigMinRenderTargetBuffCount %d"), pConfig->ConfigMinRenderTargetBuffCount);
+ LOG(_T(" - ConfigResid8Subtraction %d"), pConfig->ConfigResid8Subtraction);
+ LOG(_T(" - ConfigResidDiffAccelerator %d"), pConfig->ConfigResidDiffAccelerator);
+ LOG(_T(" - ConfigResidDiffHost %d"), pConfig->ConfigResidDiffHost);
+ LOG(_T(" - ConfigSpatialHost8or9Clipping %d"), pConfig->ConfigSpatialHost8or9Clipping);
+ LOG(_T(" - ConfigSpatialResid8 %d"), pConfig->ConfigSpatialResid8);
+ LOG(_T(" - ConfigSpatialResidInterleaved %d"), pConfig->ConfigSpatialResidInterleaved);
+ LOG(_T(" - ConfigSpecificIDCT %d"), pConfig->ConfigSpecificIDCT);
+ LOG(_T(" - guidConfigBitstreamEncryption %s"), CStringFromGUID(pConfig->guidConfigBitstreamEncryption));
+ LOG(_T(" - guidConfigMBcontrolEncryption %s"), CStringFromGUID(pConfig->guidConfigMBcontrolEncryption));
+ LOG(_T(" - guidConfigResidDiffEncryption %s"), CStringFromGUID(pConfig->guidConfigResidDiffEncryption));
+}
+
+static void LogDXVA2VideoDesc (const DXVA2_VideoDesc* pVideoDesc)
+{
+ LOG(_T("VideoDesc"));
+ LOG(_T(" - Format %s (0x%08x)"), FindD3DFormat(pVideoDesc->Format), pVideoDesc->Format);
+ LOG(_T(" - InputSampleFreq %d/%d"), pVideoDesc->InputSampleFreq.Numerator, pVideoDesc->InputSampleFreq.Denominator);
+ LOG(_T(" - OutputFrameFreq %d/%d"), pVideoDesc->OutputFrameFreq.Numerator, pVideoDesc->OutputFrameFreq.Denominator);
+ LOG(_T(" - SampleFormat %d"), pVideoDesc->SampleFormat.value);
+ LOG(_T(" - SampleHeight %d"), pVideoDesc->SampleHeight);
+ LOG(_T(" - SampleWidth %d"), pVideoDesc->SampleWidth);
+ LOG(_T(" - UABProtectionLevel %d"), pVideoDesc->UABProtectionLevel);
+}
+
+static void LogVideoCardCaps(IDirectXVideoDecoderService* pDecoderService)
+{
+ HRESULT hr;
+ UINT cDecoderGuids = 0;
+ GUID* pDecoderGuids = NULL;
+
+ hr = pDecoderService->GetDecoderDeviceGuids(&cDecoderGuids, &pDecoderGuids);
+ if (SUCCEEDED(hr))
+ {
+ // Look for the decoder GUIDs we want.
+ for (UINT iGuid = 0; iGuid < cDecoderGuids; iGuid++)
+ {
+ LOG (_T("=== New mode : %s"), GetDXVAMode (&pDecoderGuids[iGuid]));
+
+ // Find a configuration that we support.
+ UINT cFormats = 0;
+ UINT cConfigurations = 0;
+ D3DFORMAT* pFormats = NULL;
+ DXVA2_ConfigPictureDecode* pConfig = NULL;
+ DXVA2_VideoDesc m_VideoDesc;
+
+ hr = pDecoderService->GetDecoderRenderTargets(pDecoderGuids[iGuid], &cFormats, &pFormats);
+
+ if (SUCCEEDED(hr))
+ {
+ // Look for a format that matches our output format.
+ for (UINT iFormat = 0; iFormat < cFormats; iFormat++)
+ {
+ LOG (_T("Direct 3D format : %s"), FindD3DFormat(pFormats[iFormat]));
+ // Fill in the video description. Set the width, height, format, and frame rate.
+ memset(&m_VideoDesc, 0, sizeof(m_VideoDesc));
+ m_VideoDesc.SampleWidth = 1280;
+ m_VideoDesc.SampleHeight = 720;
+ m_VideoDesc.Format = pFormats[iFormat];
+
+ // Get the available configurations.
+ hr = pDecoderService->GetDecoderConfigurations(pDecoderGuids[iGuid], &m_VideoDesc, NULL, &cConfigurations, &pConfig);
+
+ if (SUCCEEDED(hr))
+ {
+
+ // Find a supported configuration.
+ for (UINT iConfig = 0; iConfig < cConfigurations; iConfig++)
+ {
+ LogDXVA2Config (&pConfig[iConfig]);
+ }
+
+ CoTaskMemFree(pConfig);
+ }
+ }
+ }
+
+ LOG(_T("\n"));
+ CoTaskMemFree(pFormats);
+ }
+ }
+}
+
+static HRESULT STDMETHODCALLTYPE CreateVideoDecoderMine(
+ IDirectXVideoDecoderServiceC* pThis,
+ __in REFGUID Guid,
+ __in const DXVA2_VideoDesc* pVideoDesc,
+ __in const DXVA2_ConfigPictureDecode* pConfig,
+ __in_ecount(NumRenderTargets) IDirect3DSurface9 **ppDecoderRenderTargets,
+ __in UINT NumRenderTargets,
+ __deref_out IDirectXVideoDecoder** ppDecode)
+{
+// DebugBreak();
+// ((DXVA2_VideoDesc*)pVideoDesc)->Format = (D3DFORMAT)0x3231564E;
+ g_guidDXVADecoder = Guid;
+ g_nDXVAVersion = 2;
+
+
+#ifdef _DEBUG
+ LOG(_T("\n\n"));
+ LogDXVA2VideoDesc(pVideoDesc);
+ LogDXVA2Config(pConfig);
+#endif
+
+ HRESULT hr = CreateVideoDecoderOrg(pThis, Guid, pVideoDesc, pConfig, ppDecoderRenderTargets, NumRenderTargets, ppDecode);
+
+ if (FAILED (hr))
+ g_guidDXVADecoder = GUID_NULL;
+ else
+ {
+#ifdef _DEBUG
+ if ((Guid == DXVA2_ModeH264_E) ||
+ (Guid == DXVA2_ModeVC1_D) ||
+ (Guid == DXVA_Intel_H264_ClearVideo) ||
+ (Guid == DXVA2_ModeMPEG2_VLD))
+ {
+ *ppDecode = DNew CFakeDirectXVideoDecoder (NULL, *ppDecode);
+ (*ppDecode)->AddRef();
+ }
+
+ for (DWORD i=0; i<NumRenderTargets; i++)
+ LOG(_T(" - Surf %d : %08x"), i, ppDecoderRenderTargets[i]);
+#endif
+ }
+
+ LOG(_T("IDirectXVideoDecoderService::CreateVideoDecoder %s (%d render targets) hr = %08x"), GetDXVAMode(&g_guidDXVADecoder), NumRenderTargets, hr);
+
+ return hr;
+}
+
+
+
+static HRESULT STDMETHODCALLTYPE GetDecoderDeviceGuidsMine (IDirectXVideoDecoderServiceC* pThis,
+ __out UINT* pCount,
+ __deref_out_ecount_opt(*pCount) GUID** pGuids)
+{
+ HRESULT hr = GetDecoderDeviceGuidsOrg(pThis, pCount, pGuids);
+ LOG(_T("IDirectXVideoDecoderService::GetDecoderDeviceGuids hr = %08x\n"), hr);
+
+ return hr;
+}
+
+static HRESULT STDMETHODCALLTYPE GetDecoderConfigurationsMine (IDirectXVideoDecoderServiceC* pThis,
+ __in REFGUID Guid,
+ __in const DXVA2_VideoDesc* pVideoDesc,
+ __reserved void* pReserved,
+ __out UINT* pCount,
+ __deref_out_ecount_opt(*pCount) DXVA2_ConfigPictureDecode **ppConfigs)
+{
+ HRESULT hr = GetDecoderConfigurationsOrg(pThis, Guid, pVideoDesc, pReserved, pCount, ppConfigs);
+
+ // Force LongSlice decoding !
+// memcpy (&(*ppConfigs)[1], &(*ppConfigs)[0], sizeof(DXVA2_ConfigPictureDecode));
+
+ return hr;
+}
+
+void HookDirectXVideoDecoderService(void* pIDirectXVideoDecoderService)
+{
+ IDirectXVideoDecoderServiceC* pIDirectXVideoDecoderServiceC = (IDirectXVideoDecoderServiceC*) pIDirectXVideoDecoderService;
+
+ BOOL res;
+ DWORD flOldProtect = 0;
+
+ // Casimir666 : unhook previous VTables
+ if (g_pIDirectXVideoDecoderServiceCVtbl)
+ {
+ res = VirtualProtect(g_pIDirectXVideoDecoderServiceCVtbl, sizeof(g_pIDirectXVideoDecoderServiceCVtbl), PAGE_WRITECOPY, &flOldProtect);
+ if (g_pIDirectXVideoDecoderServiceCVtbl->CreateVideoDecoder == CreateVideoDecoderMine)
+ g_pIDirectXVideoDecoderServiceCVtbl->CreateVideoDecoder = CreateVideoDecoderOrg;
+
+#ifdef _DEBUG
+ if (g_pIDirectXVideoDecoderServiceCVtbl->GetDecoderConfigurations == GetDecoderConfigurationsMine)
+ g_pIDirectXVideoDecoderServiceCVtbl->GetDecoderConfigurations = GetDecoderConfigurationsOrg;
+
+ //if (g_pIDirectXVideoDecoderServiceCVtbl->GetDecoderDeviceGuids == GetDecoderDeviceGuidsMine)
+ // g_pIDirectXVideoDecoderServiceCVtbl->GetDecoderDeviceGuids = GetDecoderDeviceGuidsOrg;
+#endif
+
+ res = VirtualProtect(g_pIDirectXVideoDecoderServiceCVtbl, sizeof(g_pIDirectXVideoDecoderServiceCVtbl), flOldProtect, &flOldProtect);
+
+ g_pIDirectXVideoDecoderServiceCVtbl = NULL;
+ CreateVideoDecoderOrg = NULL;
+ GetDecoderConfigurationsOrg = NULL;
+ g_guidDXVADecoder = GUID_NULL;
+ g_nDXVAVersion = 0;
+ }
+
+ // TODO : remove log file !!
+#ifdef _DEBUG
+ ::DeleteFile (LOG_FILE);
+ ::DeleteFile (_T("picture.log"));
+ ::DeleteFile (_T("slicelong.log"));
+#endif
+
+ if (pIDirectXVideoDecoderService)
+ {
+ res = VirtualProtect(pIDirectXVideoDecoderServiceC->lpVtbl, sizeof(IDirectXVideoDecoderServiceCVtbl), PAGE_WRITECOPY, &flOldProtect);
+
+ CreateVideoDecoderOrg = pIDirectXVideoDecoderServiceC->lpVtbl->CreateVideoDecoder;
+ pIDirectXVideoDecoderServiceC->lpVtbl->CreateVideoDecoder = CreateVideoDecoderMine;
+
+#ifdef _DEBUG
+ GetDecoderConfigurationsOrg = pIDirectXVideoDecoderServiceC->lpVtbl->GetDecoderConfigurations;
+ pIDirectXVideoDecoderServiceC->lpVtbl->GetDecoderConfigurations = GetDecoderConfigurationsMine;
+
+ //GetDecoderDeviceGuidsOrg = pIDirectXVideoDecoderServiceC->lpVtbl->GetDecoderDeviceGuids;
+ //pIDirectXVideoDecoderServiceC->lpVtbl->GetDecoderDeviceGuids = GetDecoderDeviceGuidsMine;
+#endif
+
+ res = VirtualProtect(pIDirectXVideoDecoderServiceC->lpVtbl, sizeof(IDirectXVideoDecoderServiceCVtbl), flOldProtect, &flOldProtect);
+
+ g_pIDirectXVideoDecoderServiceCVtbl = pIDirectXVideoDecoderServiceC->lpVtbl;
+ }
+}
\ No newline at end of file diff --git a/src/filters/renderer/VideoRenderers/IPinHook.h b/src/filters/renderer/VideoRenderers/IPinHook.h new file mode 100644 index 000000000..325ea7f9d --- /dev/null +++ b/src/filters/renderer/VideoRenderers/IPinHook.h @@ -0,0 +1,188 @@ +/*
+ * $Id$
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+interface IPinC;
+
+typedef struct IPinCVtbl
+{
+ BEGIN_INTERFACE
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IPinC * This, /* [in] */ REFIID riid, /* [iid_is][out] */ void **ppvObject );
+ ULONG ( STDMETHODCALLTYPE *AddRef )( IPinC * This );
+ ULONG ( STDMETHODCALLTYPE *Release )( IPinC * This );
+ HRESULT ( STDMETHODCALLTYPE *Connect )( IPinC * This, /* [in] */ IPinC *pReceivePin, /* [in] */ const AM_MEDIA_TYPE *pmt );
+ HRESULT ( STDMETHODCALLTYPE *ReceiveConnection )( IPinC * This, /* [in] */ IPinC *pConnector, /* [in] */ const AM_MEDIA_TYPE *pmt );
+ HRESULT ( STDMETHODCALLTYPE *Disconnect )( IPinC * This );
+ HRESULT ( STDMETHODCALLTYPE *ConnectedTo )( IPinC * This, /* [out] */ IPinC **pPin );
+ HRESULT ( STDMETHODCALLTYPE *ConnectionMediaType )( IPinC * This, /* [out] */ AM_MEDIA_TYPE *pmt );
+ HRESULT ( STDMETHODCALLTYPE *QueryPinInfo )( IPinC * This, /* [out] */ PIN_INFO *pInfo );
+ HRESULT ( STDMETHODCALLTYPE *QueryDirection )( IPinC * This, /* [out] */ PIN_DIRECTION *pPinDir );
+ HRESULT ( STDMETHODCALLTYPE *QueryId )( IPinC * This, /* [out] */ LPWSTR *Id );
+ HRESULT ( STDMETHODCALLTYPE *QueryAccept )( IPinC * This, /* [in] */ const AM_MEDIA_TYPE *pmt );
+ HRESULT ( STDMETHODCALLTYPE *EnumMediaTypes )( IPinC * This, /* [out] */ IEnumMediaTypes **ppEnum );
+ HRESULT ( STDMETHODCALLTYPE *QueryInternalConnections )( IPinC * This, /* [out] */ IPinC **apPin, /* [out][in] */ ULONG *nPin );
+ HRESULT ( STDMETHODCALLTYPE *EndOfStream )( IPinC * This );
+ HRESULT ( STDMETHODCALLTYPE *BeginFlush )( IPinC * This );
+ HRESULT ( STDMETHODCALLTYPE *EndFlush )( IPinC * This );
+ HRESULT ( STDMETHODCALLTYPE *NewSegment )( IPinC * This, /* [in] */ REFERENCE_TIME tStart, /* [in] */ REFERENCE_TIME tStop, /* [in] */ double dRate );
+ END_INTERFACE
+} IPinCVtbl;
+
+interface IPinC
+{
+ CONST_VTBL struct IPinCVtbl *lpVtbl;
+};
+
+interface IMemInputPinC;
+
+typedef struct IMemInputPinCVtbl
+{
+ BEGIN_INTERFACE
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )( IPinC * This, /* [in] */ REFIID riid, /* [iid_is][out] */ void **ppvObject );
+ ULONG ( STDMETHODCALLTYPE *AddRef )( IPinC * This );
+ ULONG ( STDMETHODCALLTYPE *Release )( IPinC * This );
+ HRESULT ( STDMETHODCALLTYPE *GetAllocator )( IMemInputPinC * This, IMemAllocator **ppAllocator);
+ HRESULT ( STDMETHODCALLTYPE *NotifyAllocator )( IMemInputPinC * This, IMemAllocator *pAllocator, BOOL bReadOnly);
+ HRESULT ( STDMETHODCALLTYPE *GetAllocatorRequirements )( IMemInputPinC * This, ALLOCATOR_PROPERTIES *pProps);
+ HRESULT ( STDMETHODCALLTYPE *Receive )( IMemInputPinC * This, IMediaSample *pSample);
+ HRESULT ( STDMETHODCALLTYPE *ReceiveMultiple )( IMemInputPinC * This, IMediaSample **pSamples, long nSamples, long *nSamplesProcessed);
+ HRESULT ( STDMETHODCALLTYPE *ReceiveCanBlock )( IMemInputPinC * This);
+ END_INTERFACE
+} IMemInputPinCVtbl;
+
+interface IMemInputPinC
+{
+ CONST_VTBL struct IMemInputPinCVtbl *lpVtbl;
+};
+
+extern bool HookNewSegmentAndReceive(IPinC* pPinC, IMemInputPinC* pMemInputPin);
+extern void UnhookNewSegmentAndReceive();
+extern REFERENCE_TIME g_tSegmentStart, g_tSampleStart, g_rtTimePerFrame;
+
+//
+
+#include <videoacc.h>
+
+interface IAMVideoAcceleratorC;
+
+typedef struct IAMVideoAcceleratorCVtbl
+{
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IAMVideoAcceleratorC * This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IAMVideoAcceleratorC * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IAMVideoAcceleratorC * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVideoAcceleratorGUIDs )(
+ IAMVideoAcceleratorC * This,
+ /* [out][in] */ LPDWORD pdwNumGuidsSupported,
+ /* [out][in] */ LPGUID pGuidsSupported);
+
+ HRESULT ( STDMETHODCALLTYPE *GetUncompFormatsSupported )(
+ IAMVideoAcceleratorC * This,
+ /* [in] */ const GUID *pGuid,
+ /* [out][in] */ LPDWORD pdwNumFormatsSupported,
+ /* [out][in] */ LPDDPIXELFORMAT pFormatsSupported);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInternalMemInfo )(
+ IAMVideoAcceleratorC * This,
+ /* [in] */ const GUID *pGuid,
+ /* [in] */ const AMVAUncompDataInfo *pamvaUncompDataInfo,
+ /* [out][in] */ LPAMVAInternalMemInfo pamvaInternalMemInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCompBufferInfo )(
+ IAMVideoAcceleratorC * This,
+ /* [in] */ const GUID *pGuid,
+ /* [in] */ const AMVAUncompDataInfo *pamvaUncompDataInfo,
+ /* [out][in] */ LPDWORD pdwNumTypesCompBuffers,
+ /* [out] */ LPAMVACompBufferInfo pamvaCompBufferInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInternalCompBufferInfo )(
+ IAMVideoAcceleratorC * This,
+ /* [out][in] */ LPDWORD pdwNumTypesCompBuffers,
+ /* [out] */ LPAMVACompBufferInfo pamvaCompBufferInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginFrame )(
+ IAMVideoAcceleratorC * This,
+ /* [in] */ const AMVABeginFrameInfo *amvaBeginFrameInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *EndFrame )(
+ IAMVideoAcceleratorC * This,
+ /* [in] */ const AMVAEndFrameInfo *pEndFrameInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBuffer )(
+ IAMVideoAcceleratorC * This,
+ /* [in] */ DWORD dwTypeIndex,
+ /* [in] */ DWORD dwBufferIndex,
+ /* [in] */ BOOL bReadOnly,
+ /* [out] */ LPVOID *ppBuffer,
+ /* [out] */ LONG *lpStride);
+
+ HRESULT ( STDMETHODCALLTYPE *ReleaseBuffer )(
+ IAMVideoAcceleratorC * This,
+ /* [in] */ DWORD dwTypeIndex,
+ /* [in] */ DWORD dwBufferIndex);
+
+ HRESULT ( STDMETHODCALLTYPE *Execute )(
+ IAMVideoAcceleratorC * This,
+ /* [in] */ DWORD dwFunction,
+ /* [in] */ LPVOID lpPrivateInputData,
+ /* [in] */ DWORD cbPrivateInputData,
+ /* [in] */ LPVOID lpPrivateOutputDat,
+ /* [in] */ DWORD cbPrivateOutputData,
+ /* [in] */ DWORD dwNumBuffers,
+ /* [in] */ const AMVABUFFERINFO *pamvaBufferInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *QueryRenderStatus )(
+ IAMVideoAcceleratorC * This,
+ /* [in] */ DWORD dwTypeIndex,
+ /* [in] */ DWORD dwBufferIndex,
+ /* [in] */ DWORD dwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *DisplayFrame )(
+ IAMVideoAcceleratorC * This,
+ /* [in] */ DWORD dwFlipToIndex,
+ /* [in] */ IMediaSample *pMediaSample);
+
+ END_INTERFACE
+} IAMVideoAcceleratorCVtbl;
+
+interface IAMVideoAcceleratorC
+{
+ CONST_VTBL struct IAMVideoAcceleratorCVtbl *lpVtbl;
+};
+
+extern void HookAMVideoAccelerator(IAMVideoAcceleratorC* pAMVideoAcceleratorC);
+
+// DXVA2 hooks
+extern void HookDirectXVideoDecoderService(void* pIDirectXVideoDecoderService);
+LPCTSTR GetDXVADecoderDescription();
+LPCTSTR GetDXVAVersion();
diff --git a/src/filters/renderer/VideoRenderers/IQTVideoSurface.h b/src/filters/renderer/VideoRenderers/IQTVideoSurface.h new file mode 100644 index 000000000..2f55ca95e --- /dev/null +++ b/src/filters/renderer/VideoRenderers/IQTVideoSurface.h @@ -0,0 +1,36 @@ +/*
+ * $Id$
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+//
+// IQTVideoSurface
+//
+
+[uuid("A6AE36F7-A6F2-4157-AF54-6599857E4E20")]
+interface IQTVideoSurface :
+public IUnknown
+{
+ STDMETHOD (BeginBlt) (const BITMAP& bm) PURE;
+ STDMETHOD (DoBlt) (const BITMAP& bm) PURE;
+};
diff --git a/src/filters/renderer/VideoRenderers/MacrovisionKicker.cpp b/src/filters/renderer/VideoRenderers/MacrovisionKicker.cpp new file mode 100644 index 000000000..7933fbc18 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/MacrovisionKicker.cpp @@ -0,0 +1,95 @@ +/*
+ * $Id$
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include "MacrovisionKicker.h"
+
+
+//
+// CMacrovisionKicker
+//
+
+CMacrovisionKicker::CMacrovisionKicker(const TCHAR* pName, LPUNKNOWN pUnk)
+ : CUnknown(pName, pUnk)
+{
+}
+
+CMacrovisionKicker::~CMacrovisionKicker()
+{
+}
+
+void CMacrovisionKicker::SetInner(IUnknown* pUnk)
+{
+ m_pInner = pUnk;
+}
+
+STDMETHODIMP CMacrovisionKicker::NonDelegatingQueryInterface(REFIID riid, void** ppv)
+{
+ if(riid == __uuidof(IUnknown))
+ return __super::NonDelegatingQueryInterface(riid, ppv);
+ if(riid == __uuidof(IKsPropertySet) && CComQIPtr<IKsPropertySet>(m_pInner))
+ return GetInterface((IKsPropertySet*)this, ppv);
+
+ HRESULT hr = m_pInner ? m_pInner->QueryInterface(riid, ppv) : E_NOINTERFACE;
+
+ return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv);
+}
+
+// IKsPropertySet
+
+STDMETHODIMP CMacrovisionKicker::Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength)
+{
+ if(CComQIPtr<IKsPropertySet> pKsPS = m_pInner)
+ {
+ if(PropSet == AM_KSPROPSETID_CopyProt && Id == AM_PROPERTY_COPY_MACROVISION
+ /*&& DataLength == 4 && *(DWORD*)pPropertyData*/)
+ {
+ TRACE(_T("Oops, no-no-no, no macrovision please\n"));
+ return S_OK;
+ }
+
+ return pKsPS->Set(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength);
+ }
+
+ return E_UNEXPECTED;
+}
+
+STDMETHODIMP CMacrovisionKicker::Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned)
+{
+ if(CComQIPtr<IKsPropertySet> pKsPS = m_pInner)
+ {
+ return pKsPS->Get(PropSet, Id, pInstanceData, InstanceLength, pPropertyData, DataLength, pBytesReturned);
+ }
+
+ return E_UNEXPECTED;
+}
+
+STDMETHODIMP CMacrovisionKicker::QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport)
+{
+ if(CComQIPtr<IKsPropertySet> pKsPS = m_pInner)
+ {
+ return pKsPS->QuerySupported(PropSet, Id, pTypeSupport);
+ }
+
+ return E_UNEXPECTED;
+}
diff --git a/src/filters/renderer/VideoRenderers/MacrovisionKicker.h b/src/filters/renderer/VideoRenderers/MacrovisionKicker.h new file mode 100644 index 000000000..f033aaf0f --- /dev/null +++ b/src/filters/renderer/VideoRenderers/MacrovisionKicker.h @@ -0,0 +1,45 @@ +/*
+ * $Id$
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+class CMacrovisionKicker
+ : public CUnknown
+ , public IKsPropertySet
+{
+ CComPtr<IUnknown> m_pInner;
+
+public:
+ CMacrovisionKicker(const TCHAR* pName, LPUNKNOWN pUnk);
+ virtual ~CMacrovisionKicker();
+
+ void SetInner(IUnknown* pUnk);
+
+ DECLARE_IUNKNOWN;
+ STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);
+
+ // IKsPropertySet
+ STDMETHODIMP Set(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength);
+ STDMETHODIMP Get(REFGUID PropSet, ULONG Id, LPVOID pInstanceData, ULONG InstanceLength, LPVOID pPropertyData, ULONG DataLength, ULONG* pBytesReturned);
+ STDMETHODIMP QuerySupported(REFGUID PropSet, ULONG Id, ULONG* pTypeSupport);
+};
diff --git a/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp new file mode 100644 index 000000000..462003835 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.cpp @@ -0,0 +1,110 @@ +/*
+ * $Id$
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include "PixelShaderCompiler.h"
+#include "RenderersSettings.h"
+#include "../apps/mplayerc/resource.h"
+
+
+CPixelShaderCompiler::CPixelShaderCompiler(IDirect3DDevice9* pD3DDev, bool fStaySilent)
+ : m_pD3DDev(pD3DDev)
+ , m_pD3DXCompileShader(NULL)
+ , m_pD3DXDisassembleShader(NULL)
+{
+ HINSTANCE hDll;
+ hDll = GetRenderersData()->GetD3X9Dll();
+
+ if(hDll)
+ {
+ m_pD3DXCompileShader = (D3DXCompileShaderPtr)GetProcAddress(hDll, "D3DXCompileShader");
+ m_pD3DXDisassembleShader = (D3DXDisassembleShaderPtr)GetProcAddress(hDll, "D3DXDisassembleShader");
+ }
+
+ if(!fStaySilent)
+ {
+ if(!hDll)
+ {
+ AfxMessageBox(ResStr(IDS_PIXELSHADERCOMPILER_0), MB_OK);
+ }
+ else if(!m_pD3DXCompileShader || !m_pD3DXDisassembleShader)
+ {
+ AfxMessageBox(ResStr(IDS_PIXELSHADERCOMPILER_1), MB_OK);
+ }
+ }
+}
+
+CPixelShaderCompiler::~CPixelShaderCompiler()
+{
+}
+
+HRESULT CPixelShaderCompiler::CompileShader(
+ LPCSTR pSrcData,
+ LPCSTR pFunctionName,
+ LPCSTR pProfile,
+ DWORD Flags,
+ IDirect3DPixelShader9** ppPixelShader,
+ CString* disasm,
+ CString* errmsg)
+{
+ if(!m_pD3DXCompileShader || !m_pD3DXDisassembleShader)
+ return E_FAIL;
+
+ HRESULT hr;
+
+ CComPtr<ID3DXBuffer> pShader, pDisAsm, pErrorMsgs;
+ hr = m_pD3DXCompileShader(pSrcData, strlen(pSrcData), NULL, NULL, pFunctionName, pProfile, Flags, &pShader, &pErrorMsgs, NULL);
+
+ if(FAILED(hr))
+ {
+ if(errmsg)
+ {
+ CStringA msg = "Unexpected compiler error";
+
+ if(pErrorMsgs)
+ {
+ int len = pErrorMsgs->GetBufferSize();
+ memcpy(msg.GetBufferSetLength(len), pErrorMsgs->GetBufferPointer(), len);
+ }
+
+ *errmsg = msg;
+ }
+
+ return hr;
+ }
+
+ if(ppPixelShader)
+ {
+ if(!m_pD3DDev) return E_FAIL;
+ hr = m_pD3DDev->CreatePixelShader((DWORD*)pShader->GetBufferPointer(), ppPixelShader);
+ if(FAILED(hr)) return hr;
+ }
+
+ if(disasm)
+ {
+ hr = m_pD3DXDisassembleShader((DWORD*)pShader->GetBufferPointer(), FALSE, NULL, &pDisAsm);
+ if(SUCCEEDED(hr) && pDisAsm) *disasm = CStringA((const char*)pDisAsm->GetBufferPointer());
+ }
+
+ return S_OK;
+}
diff --git a/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h new file mode 100644 index 000000000..a941cc505 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/PixelShaderCompiler.h @@ -0,0 +1,66 @@ +/*
+ * $Id$
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <d3dx9shader.h>
+
+
+class CPixelShaderCompiler
+{
+ typedef HRESULT (WINAPI * D3DXCompileShaderPtr) (
+ LPCSTR pSrcData,
+ UINT SrcDataLen,
+ CONST D3DXMACRO* pDefines,
+ LPD3DXINCLUDE pInclude,
+ LPCSTR pFunctionName,
+ LPCSTR pProfile,
+ DWORD Flags,
+ LPD3DXBUFFER* ppShader,
+ LPD3DXBUFFER* ppErrorMsgs,
+ LPD3DXCONSTANTTABLE* ppConstantTable);
+
+ typedef HRESULT (WINAPI * D3DXDisassembleShaderPtr) (
+ CONST DWORD* pShader,
+ bool EnableColorCode,
+ LPCSTR pComments,
+ LPD3DXBUFFER* ppDisassembly);
+
+ D3DXCompileShaderPtr m_pD3DXCompileShader;
+ D3DXDisassembleShaderPtr m_pD3DXDisassembleShader;
+
+ CComPtr<IDirect3DDevice9> m_pD3DDev;
+
+public:
+ CPixelShaderCompiler(IDirect3DDevice9* pD3DDev, bool fStaySilent = false);
+ virtual ~CPixelShaderCompiler();
+
+ HRESULT CompileShader(
+ LPCSTR pSrcData,
+ LPCSTR pFunctionName,
+ LPCSTR pProfile,
+ DWORD Flags,
+ IDirect3DPixelShader9** ppPixelShader,
+ CString* disasm = NULL,
+ CString* errmsg = NULL);
+};
diff --git a/src/filters/renderer/VideoRenderers/QT7AllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/QT7AllocatorPresenter.cpp new file mode 100644 index 000000000..451c5b2e0 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/QT7AllocatorPresenter.cpp @@ -0,0 +1,160 @@ +/*
+ * $Id: DX7AllocatorPresenter.cpp 1813 2010-04-27 02:03:56Z kinddragon $
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include "QT7AllocatorPresenter.h"
+
+using namespace DSObjects;
+
+//
+// CQT7AllocatorPresenter
+//
+
+CQT7AllocatorPresenter::CQT7AllocatorPresenter(HWND hWnd, HRESULT& hr)
+ : CDX7AllocatorPresenter(hWnd, hr)
+{
+}
+
+STDMETHODIMP CQT7AllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
+{
+ CheckPointer(ppv, E_POINTER);
+
+ return
+ QI(IQTVideoSurface)
+ __super::NonDelegatingQueryInterface(riid, ppv);
+}
+
+HRESULT CQT7AllocatorPresenter::AllocSurfaces()
+{
+ CAutoLock cAutoLock(this);
+
+ m_pVideoSurfaceOff = NULL;
+
+ DDSURFACEDESC2 ddsd;
+ INITDDSTRUCT(ddsd);
+ ddsd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = m_NativeVideoSize.cx;
+ ddsd.dwHeight = m_NativeVideoSize.cy;
+ ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
+ ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
+ ddsd.ddpfPixelFormat.dwRGBBitCount = 32;
+ ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0xFF000000;
+ ddsd.ddpfPixelFormat.dwRBitMask = 0x00FF0000;
+ ddsd.ddpfPixelFormat.dwGBitMask = 0x0000FF00;
+ ddsd.ddpfPixelFormat.dwBBitMask = 0x000000FF;
+
+ HRESULT hr = m_pDD->CreateSurface(&ddsd, &m_pVideoSurfaceOff, NULL);
+ if(FAILED(hr)) return E_FAIL;
+
+ DDBLTFX fx;
+ INITDDSTRUCT(fx);
+ fx.dwFillColor = 0;
+ m_pVideoSurfaceOff->Blt(NULL, NULL, NULL, DDBLT_WAIT|DDBLT_COLORFILL, &fx);
+
+ return __super::AllocSurfaces();
+}
+
+void CQT7AllocatorPresenter::DeleteSurfaces()
+{
+ CAutoLock cAutoLock(this);
+
+ m_pVideoSurfaceOff = NULL;
+
+ __super::DeleteSurfaces();
+}
+
+// IQTVideoSurface
+
+STDMETHODIMP CQT7AllocatorPresenter::BeginBlt(const BITMAP& bm)
+{
+ CAutoLock cAutoLock(this);
+
+ DeleteSurfaces();
+
+ m_NativeVideoSize = m_AspectRatio = CSize(bm.bmWidth, abs(bm.bmHeight));
+
+ HRESULT hr;
+ if(FAILED(hr = AllocSurfaces()))
+ return hr;
+
+ return S_OK;
+}
+
+STDMETHODIMP CQT7AllocatorPresenter::DoBlt(const BITMAP& bm)
+{
+ if(!m_pVideoSurface || !m_pVideoSurfaceOff)
+ return E_FAIL;
+
+ bool fOk = false;
+
+ DDSURFACEDESC2 ddsd;
+ INITDDSTRUCT(ddsd);
+ if(FAILED(m_pVideoSurfaceOff->GetSurfaceDesc(&ddsd)))
+ return E_FAIL;
+
+ int w = bm.bmWidth;
+ int h = abs(bm.bmHeight);
+ int bpp = bm.bmBitsPixel;
+
+ if((bpp == 16 || bpp == 24 || bpp == 32) && w == ddsd.dwWidth && h == ddsd.dwHeight)
+ {
+ INITDDSTRUCT(ddsd);
+ if(SUCCEEDED(m_pVideoSurfaceOff->Lock(NULL, &ddsd, DDLOCK_WAIT|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WRITEONLY, NULL)))
+ {
+ BitBltFromRGBToRGB(
+ w, h,
+ (BYTE*)ddsd.lpSurface, ddsd.lPitch, ddsd.ddpfPixelFormat.dwRGBBitCount,
+ (BYTE*)bm.bmBits, bm.bmWidthBytes, bm.bmBitsPixel);
+ m_pVideoSurfaceOff->Unlock(NULL);
+ fOk = true;
+ }
+ }
+
+ if(!fOk)
+ {
+ DDBLTFX fx;
+ INITDDSTRUCT(fx);
+ fx.dwFillColor = 0;
+ m_pVideoSurfaceOff->Blt(NULL, NULL, NULL, DDBLT_WAIT|DDBLT_COLORFILL, &fx);
+
+ 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);
+ }
+ }
+
+ m_pVideoSurface->Blt(NULL, m_pVideoSurfaceOff, NULL, DDBLT_WAIT, NULL);
+
+ Paint(true);
+
+ return S_OK;
+}
diff --git a/src/filters/renderer/VideoRenderers/QT7AllocatorPresenter.h b/src/filters/renderer/VideoRenderers/QT7AllocatorPresenter.h new file mode 100644 index 000000000..466bc8dcd --- /dev/null +++ b/src/filters/renderer/VideoRenderers/QT7AllocatorPresenter.h @@ -0,0 +1,53 @@ +/*
+ * $Id: DX7AllocatorPresenter.h 1790 2010-04-18 20:29:12Z tetsuo55 $
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "DX7AllocatorPresenter.h"
+#include "IQTVideoSurface.h"
+
+namespace DSObjects
+{
+
+ class CQT7AllocatorPresenter
+ : public CDX7AllocatorPresenter
+ , public IQTVideoSurface
+ {
+ CComPtr<IDirectDrawSurface7> m_pVideoSurfaceOff;
+
+ protected:
+ HRESULT AllocSurfaces();
+ void DeleteSurfaces();
+
+ public:
+ CQT7AllocatorPresenter(HWND hWnd, HRESULT& hr);
+
+ DECLARE_IUNKNOWN
+ STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);
+
+ // IQTVideoSurface
+ STDMETHODIMP BeginBlt(const BITMAP& bm);
+ STDMETHODIMP DoBlt(const BITMAP& bm);
+ };
+
+}
diff --git a/src/filters/renderer/VideoRenderers/QT9AllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/QT9AllocatorPresenter.cpp new file mode 100644 index 000000000..115f5b4a3 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/QT9AllocatorPresenter.cpp @@ -0,0 +1,135 @@ +/*
+ * $Id$
+ *
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include "QT9AllocatorPresenter.h"
+
+using namespace DSObjects;
+
+//
+// CQT9AllocatorPresenter
+//
+
+CQT9AllocatorPresenter::CQT9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString &_Error)
+ : CDX9AllocatorPresenter(hWnd, bFullscreen, hr, false, _Error)
+{
+}
+
+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);
+ CAutoLock cRenderLock(&m_RenderLock);
+ 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[m_nCurSurface], NULL, D3DTEXF_NONE);
+
+ Paint(true);
+
+ return S_OK;
+}
diff --git a/src/filters/renderer/VideoRenderers/QT9AllocatorPresenter.h b/src/filters/renderer/VideoRenderers/QT9AllocatorPresenter.h new file mode 100644 index 000000000..1ffca90f4 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/QT9AllocatorPresenter.h @@ -0,0 +1,50 @@ +/*
+ * $Id$
+ *
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "DX9AllocatorPresenter.h"
+#include "IQTVideoSurface.h"
+
+namespace DSObjects
+{
+class CQT9AllocatorPresenter
+ : public CDX9AllocatorPresenter
+ , public IQTVideoSurface
+{
+ CComPtr<IDirect3DSurface9> m_pVideoSurfaceOff;
+
+protected:
+ HRESULT AllocSurfaces();
+ void DeleteSurfaces();
+
+public:
+ CQT9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString &_Error);
+
+ DECLARE_IUNKNOWN
+ STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);
+
+ // IQTVideoSurface
+ STDMETHODIMP BeginBlt(const BITMAP& bm);
+ STDMETHODIMP DoBlt(const BITMAP& bm);
+};
+}
diff --git a/src/filters/renderer/VideoRenderers/RM7AllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/RM7AllocatorPresenter.cpp new file mode 100644 index 000000000..272ea2f1f --- /dev/null +++ b/src/filters/renderer/VideoRenderers/RM7AllocatorPresenter.cpp @@ -0,0 +1,275 @@ +/*
+ * $Id: DX7AllocatorPresenter.cpp 1813 2010-04-27 02:03:56Z kinddragon $
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include "RM7AllocatorPresenter.h"
+
+using namespace DSObjects;
+
+//
+// CRM7AllocatorPresenter
+//
+
+CRM7AllocatorPresenter::CRM7AllocatorPresenter(HWND hWnd, HRESULT& hr)
+: CDX7AllocatorPresenter(hWnd, hr)
+{
+}
+
+STDMETHODIMP CRM7AllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
+{
+ CheckPointer(ppv, E_POINTER);
+
+ return
+ QI2(IRMAVideoSurface)
+ __super::NonDelegatingQueryInterface(riid, ppv);
+}
+
+HRESULT CRM7AllocatorPresenter::AllocSurfaces()
+{
+ CAutoLock cAutoLock(this);
+
+ m_pVideoSurfaceOff = NULL;
+ m_pVideoSurfaceYUY2 = NULL;
+
+ DDSURFACEDESC2 ddsd;
+ DDBLTFX fx;
+
+ INITDDSTRUCT(ddsd);
+ ddsd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = m_NativeVideoSize.cx;
+ ddsd.dwHeight = m_NativeVideoSize.cy;
+ ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
+ ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
+ ddsd.ddpfPixelFormat.dwRGBBitCount = 32;
+ ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0xFF000000;
+ ddsd.ddpfPixelFormat.dwRBitMask = 0x00FF0000;
+ ddsd.ddpfPixelFormat.dwGBitMask = 0x0000FF00;
+ ddsd.ddpfPixelFormat.dwBBitMask = 0x000000FF;
+
+ HRESULT hr = m_pDD->CreateSurface(&ddsd, &m_pVideoSurfaceOff, NULL);
+ if(FAILED(hr)) return E_FAIL;
+
+ INITDDSTRUCT(fx);
+ fx.dwFillColor = 0;
+ m_pVideoSurfaceOff->Blt(NULL, NULL, NULL, DDBLT_WAIT|DDBLT_COLORFILL, &fx);
+
+ INITDDSTRUCT(ddsd);
+ ddsd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = m_NativeVideoSize.cx;
+ ddsd.dwHeight = m_NativeVideoSize.cy;
+ ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
+ ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
+ ddsd.ddpfPixelFormat.dwYUVBitCount = 16;
+ ddsd.ddpfPixelFormat.dwFourCC = '2YUY';
+
+ hr = m_pDD->CreateSurface(&ddsd, &m_pVideoSurfaceYUY2, NULL);
+
+ if(FAILED(m_pVideoSurfaceOff->Blt(NULL, m_pVideoSurfaceYUY2, NULL, DDBLT_WAIT, NULL)))
+ m_pVideoSurfaceYUY2 = NULL;
+
+ if(m_pVideoSurfaceYUY2)
+ {
+ INITDDSTRUCT(fx);
+ fx.dwFillColor = 0x80108010;
+ m_pVideoSurfaceYUY2->Blt(NULL, NULL, NULL, DDBLT_WAIT|DDBLT_COLORFILL, &fx);
+ }
+
+ return __super::AllocSurfaces();
+}
+
+void CRM7AllocatorPresenter::DeleteSurfaces()
+{
+ CAutoLock cAutoLock(this);
+
+ m_pVideoSurfaceOff = NULL;
+ m_pVideoSurfaceYUY2 = NULL;
+
+ __super::DeleteSurfaces();
+}
+
+// IRMAVideoSurface
+
+STDMETHODIMP CRM7AllocatorPresenter::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;
+
+ DDSURFACEDESC2 ddsd;
+
+ 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)
+ {
+ INITDDSTRUCT(ddsd);
+ if(SUCCEEDED(m_pVideoSurfaceYUY2->Lock(src2, &ddsd, DDLOCK_WAIT|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WRITEONLY, NULL)))
+ {
+ BitBltFromI420ToYUY2(src.Width(), src.Height(), (BYTE*)ddsd.lpSurface, ddsd.lPitch, y, u, v, pitch);
+ m_pVideoSurfaceYUY2->Unlock(src2);
+ fYUY2 = true;
+ }
+ }
+ else
+ {
+ INITDDSTRUCT(ddsd);
+ if(SUCCEEDED(m_pVideoSurfaceOff->Lock(src2, &ddsd, DDLOCK_WAIT|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WRITEONLY, NULL)))
+ {
+ BitBltFromI420ToRGB(src.Width(), src.Height(), (BYTE*)ddsd.lpSurface, ddsd.lPitch, ddsd.ddpfPixelFormat.dwRGBBitCount, y, u, v, pitch);
+ m_pVideoSurfaceOff->Unlock(src2);
+ 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)
+ {
+ INITDDSTRUCT(ddsd);
+ if(SUCCEEDED(m_pVideoSurfaceYUY2->Lock(src2, &ddsd, DDLOCK_WAIT|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WRITEONLY, NULL)))
+ {
+ BitBltFromYUY2ToYUY2(src.Width(), src.Height(), (BYTE*)ddsd.lpSurface, ddsd.lPitch, yvyu, pitch);
+ m_pVideoSurfaceYUY2->Unlock(src2);
+ fYUY2 = true;
+ }
+ }
+ else
+ {
+ INITDDSTRUCT(ddsd);
+ if(SUCCEEDED(m_pVideoSurfaceOff->Lock(src2, &ddsd, DDLOCK_WAIT|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WRITEONLY, NULL)))
+ {
+ BitBltFromYUY2ToRGB(src.Width(), src.Height(), (BYTE*)ddsd.lpSurface, ddsd.lPitch, ddsd.ddpfPixelFormat.dwRGBBitCount, yvyu, pitch);
+ m_pVideoSurfaceOff->Unlock(src2);
+ 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);
+
+ INITDDSTRUCT(ddsd);
+ if(SUCCEEDED(m_pVideoSurfaceOff->Lock(src2, &ddsd, DDLOCK_WAIT|DDLOCK_SURFACEMEMORYPTR|DDLOCK_WRITEONLY, NULL)))
+ {
+ BYTE* lpSurface = (BYTE*)ddsd.lpSurface;
+ if(pBitmapInfo->biHeight > 0)
+ {
+ lpSurface += ddsd.lPitch*(src.Height()-1);
+ ddsd.lPitch = -ddsd.lPitch;
+ }
+ BitBltFromRGBToRGB(src.Width(), src.Height(), lpSurface, ddsd.lPitch, ddsd.ddpfPixelFormat.dwRGBBitCount, rgb, pitch, pBitmapInfo->biBitCount);
+ fRGB = true;
+ m_pVideoSurfaceOff->Unlock(src2);
+ }
+ }
+
+ if(!fRGB && !fYUY2)
+ {
+ DDBLTFX fx;
+ INITDDSTRUCT(fx);
+ fx.dwFillColor = 0;
+ m_pVideoSurfaceOff->Blt(NULL, NULL, NULL, DDBLT_WAIT|DDBLT_COLORFILL, &fx);
+
+ 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_pVideoSurface->Blt(dst, m_pVideoSurfaceOff, src2, DDBLT_WAIT, NULL);
+ if(fYUY2)
+ hr = m_pVideoSurface->Blt(dst, m_pVideoSurfaceYUY2, src2, DDBLT_WAIT, NULL);
+
+ Paint(true);
+
+ return PNR_OK;
+}
+
+STDMETHODIMP CRM7AllocatorPresenter::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 CRM7AllocatorPresenter::OptimizedBlt(UCHAR* pImageBits, REF(PNxRect) rDestRect, REF(PNxRect) rSrcRect)
+{
+ return PNR_NOTIMPL;
+}
+
+STDMETHODIMP CRM7AllocatorPresenter::EndOptimizedBlt()
+{
+ return PNR_NOTIMPL;
+}
+
+STDMETHODIMP CRM7AllocatorPresenter::GetOptimizedFormat(REF(RMA_COMPRESSION_TYPE) ulType)
+{
+ return PNR_NOTIMPL;
+}
+
+STDMETHODIMP CRM7AllocatorPresenter::GetPreferredFormat(REF(RMA_COMPRESSION_TYPE) ulType)
+{
+ ulType = RMA_I420;
+ return PNR_OK;
+}
diff --git a/src/filters/renderer/VideoRenderers/RM7AllocatorPresenter.h b/src/filters/renderer/VideoRenderers/RM7AllocatorPresenter.h new file mode 100644 index 000000000..ab1d8fe78 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/RM7AllocatorPresenter.h @@ -0,0 +1,64 @@ +/*
+ * $Id: DX7AllocatorPresenter.h 1790 2010-04-18 20:29:12Z tetsuo55 $
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "DX7AllocatorPresenter.h"
+#include <RealMedia/pntypes.h>
+#include <RealMedia/pnwintyp.h>
+#include <RealMedia/pncom.h>
+#include <RealMedia/rmavsurf.h>
+
+namespace DSObjects
+{
+
+ class CRM7AllocatorPresenter
+ : public CDX7AllocatorPresenter
+ , public IRMAVideoSurface
+ {
+ CComPtr<IDirectDrawSurface7> m_pVideoSurfaceOff;
+ CComPtr<IDirectDrawSurface7> m_pVideoSurfaceYUY2;
+
+ RMABitmapInfoHeader m_bitmapInfo;
+ RMABitmapInfoHeader m_lastBitmapInfo;
+
+ protected:
+ HRESULT AllocSurfaces();
+ void DeleteSurfaces();
+
+ public:
+ CRM7AllocatorPresenter(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);
+ };
+
+}
diff --git a/src/filters/renderer/VideoRenderers/RM9AllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/RM9AllocatorPresenter.cpp new file mode 100644 index 000000000..7d5c25795 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/RM9AllocatorPresenter.cpp @@ -0,0 +1,252 @@ +/*
+ * $Id$
+ *
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include "RM9AllocatorPresenter.h"
+
+using namespace DSObjects;
+
+//
+// CRM9AllocatorPresenter
+//
+
+CRM9AllocatorPresenter::CRM9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString &_Error)
+ : CDX9AllocatorPresenter(hWnd, bFullscreen, hr, false, _Error)
+{
+}
+
+STDMETHODIMP CRM9AllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
+{
+ CheckPointer(ppv, E_POINTER);
+
+ return
+ QI2(IRMAVideoSurface)
+ __super::NonDelegatingQueryInterface(riid, ppv);
+}
+
+HRESULT CRM9AllocatorPresenter::AllocSurfaces()
+{
+ CAutoLock cAutoLock(this);
+ CAutoLock cRenderLock(&m_RenderLock);
+
+ 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);
+ CAutoLock cRenderLock(&m_RenderLock);
+ 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[m_nCurSurface], dst, D3DTEXF_NONE);
+ if(fYUY2)
+ hr = m_pD3DDev->StretchRect(m_pVideoSurfaceYUY2, src2, m_pVideoSurface[m_nCurSurface], dst, D3DTEXF_NONE);
+
+ Paint(true);
+
+ return PNR_OK;
+}
+
+STDMETHODIMP CRM9AllocatorPresenter::BeginOptimizedBlt(RMABitmapInfoHeader* pBitmapInfo)
+{
+ CAutoLock cAutoLock(this);
+ CAutoLock cRenderLock(&m_RenderLock);
+ 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;
+}
diff --git a/src/filters/renderer/VideoRenderers/RM9AllocatorPresenter.h b/src/filters/renderer/VideoRenderers/RM9AllocatorPresenter.h new file mode 100644 index 000000000..c673a2664 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/RM9AllocatorPresenter.h @@ -0,0 +1,62 @@ +/*
+ * $Id$
+ *
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "DX9AllocatorPresenter.h"
+#include <RealMedia/pntypes.h>
+#include <RealMedia/pnwintyp.h>
+#include <RealMedia/pncom.h>
+#include <RealMedia/rmavsurf.h>
+#include "IQTVideoSurface.h"
+
+namespace DSObjects
+{
+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, bool bFullscreen, HRESULT& hr, CString &_Error);
+
+ 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);
+};
+}
diff --git a/src/filters/renderer/VideoRenderers/RenderersSettings.cpp b/src/filters/renderer/VideoRenderers/RenderersSettings.cpp new file mode 100644 index 000000000..5668e6b96 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/RenderersSettings.cpp @@ -0,0 +1,108 @@ +/*
+ * $Id: mplayerc.cpp 1803 2010-04-20 19:45:33Z xhmikosr $
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include "RenderersSettings.h"
+#include <d3dx9.h>
+
+#pragma comment(lib, "winmm.lib")
+
+/////////////////////////////////////////////////////////////////////////////
+// CRenderersData construction
+
+CRenderersData::CRenderersData()
+{
+ m_fTearingTest = false;
+ m_fDisplayStats = false;
+ m_bResetStats = false;
+ m_hD3DX9Dll = NULL;
+ m_nDXSdkRelease = 0;
+}
+
+LONGLONG CRenderersData::GetPerfCounter()
+{
+ LARGE_INTEGER i64Ticks100ns;
+ LARGE_INTEGER llPerfFrequency;
+
+ QueryPerformanceFrequency (&llPerfFrequency);
+ if (llPerfFrequency.QuadPart != 0)
+ {
+ QueryPerformanceCounter (&i64Ticks100ns);
+ return llMulDiv (i64Ticks100ns.QuadPart, 10000000, llPerfFrequency.QuadPart, 0);
+ }
+ else
+ {
+ // ms to 100ns units
+ return timeGetTime() * 10000;
+ }
+}
+
+HINSTANCE CRenderersData::GetD3X9Dll()
+{
+ if (m_hD3DX9Dll == NULL)
+ {
+ int min_ver = D3DX_SDK_VERSION;
+ int max_ver = D3DX_SDK_VERSION;
+
+ m_nDXSdkRelease = 0;
+
+ if(D3DX_SDK_VERSION >= 42)
+ {
+ // August 2009 SDK (v42) is not compatible with older versions
+ min_ver = 42;
+ }
+ else
+ {
+ if(D3DX_SDK_VERSION > 33)
+ {
+ // versions between 34 and 41 have no known compatibility issues
+ min_ver = 34;
+ }
+ else
+ {
+ // The minimum version that supports the functionality required by MPC is 24
+ min_ver = 24;
+
+ if(D3DX_SDK_VERSION == 33)
+ {
+ // The April 2007 SDK (v33) should not be used (crash sometimes during shader compilation)
+ max_ver = 32;
+ }
+ }
+ }
+
+ // load latest compatible version of the DLL that is available
+ for (int i=max_ver; i>=min_ver; i--)
+ {
+ m_strD3DX9Version.Format(_T("d3dx9_%d.dll"), i);
+ m_hD3DX9Dll = LoadLibrary (m_strD3DX9Version);
+ if (m_hD3DX9Dll)
+ {
+ m_nDXSdkRelease = i;
+ break;
+ }
+ }
+ }
+
+ return m_hD3DX9Dll;
+}
diff --git a/src/filters/renderer/VideoRenderers/RenderersSettings.h b/src/filters/renderer/VideoRenderers/RenderersSettings.h new file mode 100644 index 000000000..96b28c49b --- /dev/null +++ b/src/filters/renderer/VideoRenderers/RenderersSettings.h @@ -0,0 +1,196 @@ +/*
+ * $Id: mplayerc.h 1826 2010-05-02 01:20:06Z kinddragon $
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+enum
+{
+ WM_REARRANGERENDERLESS = WM_APP+1,
+ WM_RESET_DEVICE,
+};
+
+#define WM_MYMOUSELAST WM_XBUTTONDBLCLK
+
+enum
+{
+ VIDRNDT_RM_DEFAULT,
+ VIDRNDT_RM_DX7,
+ VIDRNDT_RM_DX9,
+};
+
+enum
+{
+ VIDRNDT_QT_DEFAULT,
+ VIDRNDT_QT_DX7,
+ VIDRNDT_QT_DX9,
+};
+
+enum
+{
+ VIDRNDT_AP_SURFACE,
+ VIDRNDT_AP_TEXTURE2D,
+ VIDRNDT_AP_TEXTURE3D,
+};
+
+class CRenderersSettings
+{
+
+public:
+ bool fResetDevice;
+
+ class CRendererSettingsShared
+ {
+ public:
+ CRendererSettingsShared()
+ {
+ SetDefault();
+ }
+ bool fVMR9AlterativeVSync;
+ int iVMR9VSyncOffset;
+ bool iVMR9VSyncAccurate;
+ bool iVMR9FullscreenGUISupport;
+ bool iVMR9VSync;
+ bool iVMRDisableDesktopComposition;
+ int iVMRFlushGPUBeforeVSync;
+ int iVMRFlushGPUAfterPresent;
+ int iVMRFlushGPUWait;
+
+ // SyncRenderer settings
+ int bSynchronizeVideo;
+ int bSynchronizeDisplay;
+ int bSynchronizeNearest;
+ int iLineDelta;
+ int iColumnDelta;
+ double fCycleDelta;
+ double fTargetSyncOffset;
+ double fControlLimit;
+
+ void SetDefault()
+ {
+ fVMR9AlterativeVSync = 0;
+ iVMR9VSyncOffset = 0;
+ iVMR9VSyncAccurate = 1;
+ iVMR9FullscreenGUISupport = 0;
+ iVMR9VSync = 1;
+ iVMRDisableDesktopComposition = 0;
+ iVMRFlushGPUBeforeVSync = 1;
+ iVMRFlushGPUAfterPresent = 1;
+ iVMRFlushGPUWait = 0;
+ bSynchronizeVideo = 0;
+ bSynchronizeDisplay = 0;
+ bSynchronizeNearest = 1;
+ iLineDelta = 0;
+ iColumnDelta = 0;
+ fCycleDelta = 0.0012;
+ fTargetSyncOffset = 12.0;
+ fControlLimit = 2.0;
+ }
+ void SetOptimal()
+ {
+ fVMR9AlterativeVSync = 1;
+ iVMR9VSyncAccurate = 1;
+ iVMR9VSync = 1;
+ iVMRDisableDesktopComposition = 1;
+ iVMRFlushGPUBeforeVSync = 1;
+ iVMRFlushGPUAfterPresent = 1;
+ iVMRFlushGPUWait = 0;
+ bSynchronizeVideo = 0;
+ bSynchronizeDisplay = 0;
+ bSynchronizeNearest = 1;
+ iLineDelta = 0;
+ iColumnDelta = 0;
+ fCycleDelta = 0.0012;
+ fTargetSyncOffset = 12.0;
+ fControlLimit = 2.0;
+ }
+ };
+ class CRendererSettingsEVR : public CRendererSettingsShared
+ {
+ public:
+ bool iEVRHighColorResolution;
+ bool iEVREnableFrameTimeCorrection;
+ int iEVROutputRange;
+
+ CRendererSettingsEVR()
+ {
+ SetDefault();
+ }
+ void SetDefault()
+ {
+ CRendererSettingsShared::SetDefault();
+ iEVRHighColorResolution = 0;
+ iEVREnableFrameTimeCorrection = 0;
+ iEVROutputRange = 0;
+ }
+ void SetOptimal()
+ {
+ CRendererSettingsShared::SetOptimal();
+ iEVRHighColorResolution = 0;
+ }
+ };
+
+ CRendererSettingsEVR m_RenderSettings;
+
+ int iAPSurfaceUsage;
+ //bool fVMRSyncFix;
+ int iDX9Resizer;
+ bool fVMR9MixerMode;
+ bool fVMR9MixerYUV;
+ int iEvrBuffers;
+
+ int nSPCSize;
+ int nSPCMaxRes;
+ bool fSPCPow2Tex;
+ bool fSPCAllowAnimationWhenBuffering;
+
+ CString D3D9RenderDevice;
+};
+
+
+class CRenderersData
+{
+ HINSTANCE m_hD3DX9Dll;
+ int m_nDXSdkRelease;
+
+public:
+ CRenderersData();
+
+ // === CASIMIR666
+ bool m_fTearingTest;
+ int m_fDisplayStats;
+ bool m_bResetStats; // Set to reset the presentation statistics
+ CString m_strD3DX9Version;
+
+ LONGLONG GetPerfCounter();
+ HINSTANCE GetD3X9Dll();
+ int GetDXSdkRelease()
+ {
+ return m_nDXSdkRelease;
+ };
+};
+
+extern CRenderersData* GetRenderersData();
+extern CRenderersSettings& GetRenderersSettings();
+
+extern bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype);
+extern bool IsVistaOrAbove();
diff --git a/src/filters/renderer/VideoRenderers/SyncAllocatorPresenter.h b/src/filters/renderer/VideoRenderers/SyncAllocatorPresenter.h new file mode 100644 index 000000000..9e3caaa0d --- /dev/null +++ b/src/filters/renderer/VideoRenderers/SyncAllocatorPresenter.h @@ -0,0 +1,35 @@ +/*
+* $Id: SyncAllocatorPresenter.h 1292 2009-10-03 23:20:26Z ar-jar $
+*
+* (C) 2003-2006 Gabest
+* (C) 2006-2010 see AUTHORS
+*
+* This file is part of mplayerc.
+*
+* Mplayerc 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.
+*
+* Mplayerc 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 <http://www.gnu.org/licenses/>.
+*
+*/
+
+#pragma once
+
+// {F9F62627-E3EF-4a2e-B6C9-5D4C0DC3326B}
+DEFINE_GUID(CLSID_SyncAllocatorPresenter, 0xf9f62627, 0xe3ef, 0x4a2e, 0xb6, 0xc9, 0x5d, 0x4c, 0xd, 0xc3, 0x32, 0x6b);
+
+[uuid("F891C2A9-1DFF-45e0-9129-30C0990C5A9F")]
+interface ISyncClockAdviser : public IUnknown
+{
+ STDMETHOD (AdviseSyncClock)(ISyncClock* sC) PURE;
+};
+
+HRESULT CreateSyncRenderer(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP);
\ No newline at end of file diff --git a/src/filters/renderer/VideoRenderers/SyncRenderer.cpp b/src/filters/renderer/VideoRenderers/SyncRenderer.cpp new file mode 100644 index 000000000..c3ec0e813 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/SyncRenderer.cpp @@ -0,0 +1,4627 @@ +/*
+* $Id: SyncRenderer.cpp 1293 2009-10-04 07:50:53Z ar-jar $
+*
+* (C) 2003-2006 Gabest
+* (C) 2006-2010 see AUTHORS
+*
+* This file is part of mplayerc.
+*
+* Mplayerc 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.
+*
+* Mplayerc 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 <http://www.gnu.org/licenses/>.
+*
+*/
+
+#include "stdafx.h"
+#include "../../filters/misc/SyncClock/Interfaces.h"
+#include <atlbase.h>
+#include <atlcoll.h>
+#include "../apps/mplayerc/resource.h"
+#include "../DSUtil/DSUtil.h"
+#include <strsafe.h> // Required in CGenlock
+#include <Videoacc.h>
+#include <initguid.h>
+#include <d3d9.h>
+#include <d3dx9.h>
+#include <Vmr9.h>
+#include <evr.h>
+#include <mfapi.h>
+#include <Mferror.h>
+#include <vector>
+#include "../SubPic/DX9SubPic.h"
+#include <moreuuids.h>
+#include "MacrovisionKicker.h"
+#include "IPinHook.h"
+#include "PixelShaderCompiler.h"
+#include "SyncRenderer.h"
+
+// only for debugging
+//#define DISABLE_USING_D3D9EX
+
+using namespace GothSync;
+using namespace std;
+
+extern bool LoadResource(UINT resid, CStringA& str, LPCTSTR restype);
+
+CString GothSyncErrorMessage(HRESULT _Error, HMODULE _Module)
+{
+
+ switch (_Error)
+ {
+ case D3DERR_WRONGTEXTUREFORMAT :
+ return _T("D3DERR_WRONGTEXTUREFORMAT");
+ case D3DERR_UNSUPPORTEDCOLOROPERATION :
+ return _T("D3DERR_UNSUPPORTEDCOLOROPERATION");
+ case D3DERR_UNSUPPORTEDCOLORARG :
+ return _T("D3DERR_UNSUPPORTEDCOLORARG");
+ case D3DERR_UNSUPPORTEDALPHAOPERATION :
+ return _T("D3DERR_UNSUPPORTEDALPHAOPERATION");
+ case D3DERR_UNSUPPORTEDALPHAARG :
+ return _T("D3DERR_UNSUPPORTEDALPHAARG");
+ case D3DERR_TOOMANYOPERATIONS :
+ return _T("D3DERR_TOOMANYOPERATIONS");
+ case D3DERR_CONFLICTINGTEXTUREFILTER :
+ return _T("D3DERR_CONFLICTINGTEXTUREFILTER");
+ case D3DERR_UNSUPPORTEDFACTORVALUE :
+ return _T("D3DERR_UNSUPPORTEDFACTORVALUE");
+ case D3DERR_CONFLICTINGRENDERSTATE :
+ return _T("D3DERR_CONFLICTINGRENDERSTATE");
+ case D3DERR_UNSUPPORTEDTEXTUREFILTER :
+ return _T("D3DERR_UNSUPPORTEDTEXTUREFILTER");
+ case D3DERR_CONFLICTINGTEXTUREPALETTE :
+ return _T("D3DERR_CONFLICTINGTEXTUREPALETTE");
+ case D3DERR_DRIVERINTERNALERROR :
+ return _T("D3DERR_DRIVERINTERNALERROR");
+ case D3DERR_NOTFOUND :
+ return _T("D3DERR_NOTFOUND");
+ case D3DERR_MOREDATA :
+ return _T("D3DERR_MOREDATA");
+ case D3DERR_DEVICELOST :
+ return _T("D3DERR_DEVICELOST");
+ case D3DERR_DEVICENOTRESET :
+ return _T("D3DERR_DEVICENOTRESET");
+ case D3DERR_NOTAVAILABLE :
+ return _T("D3DERR_NOTAVAILABLE");
+ case D3DERR_OUTOFVIDEOMEMORY :
+ return _T("D3DERR_OUTOFVIDEOMEMORY");
+ case D3DERR_INVALIDDEVICE :
+ return _T("D3DERR_INVALIDDEVICE");
+ case D3DERR_INVALIDCALL :
+ return _T("D3DERR_INVALIDCALL");
+ case D3DERR_DRIVERINVALIDCALL :
+ return _T("D3DERR_DRIVERINVALIDCALL");
+ case D3DERR_WASSTILLDRAWING :
+ return _T("D3DERR_WASSTILLDRAWING");
+ case D3DOK_NOAUTOGEN :
+ return _T("D3DOK_NOAUTOGEN");
+ case D3DERR_DEVICEREMOVED :
+ return _T("D3DERR_DEVICEREMOVED");
+ case S_NOT_RESIDENT :
+ return _T("S_NOT_RESIDENT");
+ case S_RESIDENT_IN_SHARED_MEMORY :
+ return _T("S_RESIDENT_IN_SHARED_MEMORY");
+ case S_PRESENT_MODE_CHANGED :
+ return _T("S_PRESENT_MODE_CHANGED");
+ case S_PRESENT_OCCLUDED :
+ return _T("S_PRESENT_OCCLUDED");
+ case D3DERR_DEVICEHUNG :
+ return _T("D3DERR_DEVICEHUNG");
+ case E_UNEXPECTED :
+ return _T("E_UNEXPECTED");
+ }
+
+ CString errmsg;
+ LPVOID lpMsgBuf;
+ if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_HMODULE,
+ _Module, _Error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL))
+ {
+ errmsg = (LPCTSTR)lpMsgBuf;
+ LocalFree(lpMsgBuf);
+ }
+ CString Temp;
+ Temp.Format(L"0x%08x ", _Error);
+ return Temp + errmsg;
+}
+
+CBaseAP::CBaseAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString &_Error):
+ ISubPicAllocatorPresenterImpl(hWnd, hr, &_Error),
+ m_ScreenSize(0, 0),
+ m_bicubicA(0),
+ m_nDXSurface(1),
+ m_nVMR9Surfaces(0),
+ m_iVMR9Surface(0),
+ m_nCurSurface(0),
+ m_bSnapToVSync(false),
+ m_bInterlaced(0),
+ m_nUsedBuffer(0),
+ m_TextScale(1.0),
+ m_dMainThreadId(0),
+ m_bNeedCheckSample(true),
+ m_hEvtQuit(INVALID_HANDLE_VALUE),
+ m_bIsFullscreen(bFullscreen),
+ m_uSyncGlitches(0),
+ m_pGenlock(NULL),
+ m_lAudioLag(0),
+ m_lAudioLagMin(10000),
+ m_lAudioLagMax(-10000),
+ m_pAudioStats(NULL),
+ m_nNextJitter(0),
+ m_nNextSyncOffset(0),
+ m_llLastSyncTime(0),
+ m_fAvrFps(0.0),
+ m_fJitterStdDev(0.0),
+ m_fSyncOffsetStdDev(0.0),
+ m_fSyncOffsetAvr(0.0),
+ m_llHysteresis(0),
+ m_uD3DRefreshRate(0),
+ m_dD3DRefreshCycle(0),
+ m_dDetectedScanlineTime(0.0),
+ m_dEstRefreshCycle(0.0),
+ m_dFrameCycle(0.0),
+ m_dOptimumDisplayCycle(0.0),
+ m_dCycleDifference(1.0),
+ m_llEstVBlankTime(0),
+ m_CurrentAdapter(0)
+{
+ if(FAILED(hr))
+ {
+ _Error += L"ISubPicAllocatorPresenterImpl failed\n";
+ return;
+ }
+
+ HINSTANCE hDll;
+ m_pD3DXLoadSurfaceFromMemory = NULL;
+ m_pD3DXCreateLine = NULL;
+ m_pD3DXCreateFont = NULL;
+ m_pD3DXCreateSprite = NULL;
+ hDll = GetRenderersData()->GetD3X9Dll();
+ if(hDll)
+ {
+ (FARPROC &)m_pD3DXLoadSurfaceFromMemory = GetProcAddress(hDll, "D3DXLoadSurfaceFromMemory");
+ (FARPROC &)m_pD3DXCreateLine = GetProcAddress(hDll, "D3DXCreateLine");
+ (FARPROC &)m_pD3DXCreateFont = GetProcAddress(hDll, "D3DXCreateFontW");
+ (FARPROC &)m_pD3DXCreateSprite = GetProcAddress(hDll, "D3DXCreateSprite");
+ }
+ else
+ {
+ _Error += L"No D3DX9 dll found. To enable stats, shaders and complex resizers, please install the latest DirectX End-User Runtime.\n";
+ }
+
+ m_pDwmIsCompositionEnabled = NULL;
+ m_pDwmEnableComposition = NULL;
+ m_hDWMAPI = LoadLibrary(L"dwmapi.dll");
+ if (m_hDWMAPI)
+ {
+ (FARPROC &)m_pDwmIsCompositionEnabled = GetProcAddress(m_hDWMAPI, "DwmIsCompositionEnabled");
+ (FARPROC &)m_pDwmEnableComposition = GetProcAddress(m_hDWMAPI, "DwmEnableComposition");
+ }
+
+ m_pDirect3DCreate9Ex = NULL;
+ m_hD3D9 = LoadLibrary(L"d3d9.dll");
+#ifndef DISABLE_USING_D3D9EX
+ if (m_hD3D9)
+ (FARPROC &)m_pDirect3DCreate9Ex = GetProcAddress(m_hD3D9, "Direct3DCreate9Ex");
+#endif
+
+ if (m_pDirect3DCreate9Ex)
+ {
+ _tprintf(_T("m_pDirect3DCreate9Ex\n"));
+ m_pDirect3DCreate9Ex(D3D_SDK_VERSION, &m_pD3DEx);
+ if(!m_pD3DEx)
+ {
+ m_pDirect3DCreate9Ex(D3D9b_SDK_VERSION, &m_pD3DEx);
+ }
+ }
+ if(!m_pD3DEx)
+ {
+ m_pD3D.Attach(Direct3DCreate9(D3D_SDK_VERSION));
+ if(!m_pD3D)
+ {
+ m_pD3D.Attach(Direct3DCreate9(D3D9b_SDK_VERSION));
+ }
+ if(m_pD3D)
+ _tprintf(_T("m_pDirect3DCreate9\n"));
+ }
+ else
+ m_pD3D = m_pD3DEx;
+
+ ZeroMemory(&m_VMR9AlphaBitmap, sizeof(m_VMR9AlphaBitmap));
+
+ CRenderersSettings& s = GetRenderersSettings();
+ if (s.m_RenderSettings.iVMRDisableDesktopComposition)
+ {
+ m_bDesktopCompositionDisabled = true;
+ if (m_pDwmEnableComposition) m_pDwmEnableComposition(0);
+ }
+ else
+ {
+ m_bDesktopCompositionDisabled = false;
+ }
+
+ m_pGenlock = new CGenlock(s.m_RenderSettings.fTargetSyncOffset, s.m_RenderSettings.fControlLimit, s.m_RenderSettings.iLineDelta, s.m_RenderSettings.iColumnDelta, s.m_RenderSettings.fCycleDelta, 0); // Must be done before CreateDXDevice
+ hr = CreateDXDevice(_Error);
+ memset (m_pllJitter, 0, sizeof(m_pllJitter));
+ memset (m_pllSyncOffset, 0, sizeof(m_pllSyncOffset));
+}
+
+CBaseAP::~CBaseAP()
+{
+ if (m_bDesktopCompositionDisabled)
+ {
+ m_bDesktopCompositionDisabled = false;
+ if (m_pDwmEnableComposition)
+ m_pDwmEnableComposition(1);
+ }
+
+ m_pFont = NULL;
+ m_pLine = NULL;
+ m_pD3DDev = NULL;
+ m_pD3DDevEx = NULL;
+ m_pPSC.Free();
+ m_pD3D = NULL;
+ m_pD3DEx = NULL;
+ if (m_hDWMAPI)
+ {
+ FreeLibrary(m_hDWMAPI);
+ m_hDWMAPI = NULL;
+ }
+ if (m_hD3D9)
+ {
+ FreeLibrary(m_hD3D9);
+ m_hD3D9 = NULL;
+ }
+ m_pAudioStats = NULL;
+ if (m_pGenlock)
+ {
+ delete m_pGenlock;
+ m_pGenlock = NULL;
+ }
+}
+
+template<int texcoords>
+void CBaseAP::AdjustQuad(MYD3DVERTEX<texcoords>* v, double dx, double dy)
+{
+ double offset = 0.5;
+
+ for(int i = 0; i < 4; i++)
+ {
+ v[i].x -= offset;
+ v[i].y -= offset;
+
+ for(int j = 0; j < max(texcoords-1, 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>
+HRESULT CBaseAP::TextureBlt(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);
+ }
+
+ hr = pD3DDev->SetFVF(D3DFVF_XYZRHW | FVF);
+
+ MYD3DVERTEX<texcoords> tmp = v[2];
+ v[2] = v[3];
+ v[3] = tmp;
+ hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0]));
+
+ for(int i = 0; i < texcoords; i++)
+ {
+ pD3DDev->SetTexture(i, NULL);
+ }
+
+ return S_OK;
+ }
+ while(0);
+ return E_FAIL;
+}
+
+HRESULT CBaseAP::DrawRectBase(IDirect3DDevice9* pD3DDev, MYD3DVERTEX<0> v[4])
+{
+ if(!pD3DDev) return E_POINTER;
+
+ do
+ {
+ HRESULT 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, TRUE);
+ hr = pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
+ hr = pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
+ 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);
+
+ hr = pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX0 | D3DFVF_DIFFUSE);
+
+ MYD3DVERTEX<0> tmp = v[2];
+ v[2] = v[3];
+ v[3] = tmp;
+ hr = pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, v, sizeof(v[0]));
+
+ return S_OK;
+ }
+ while(0);
+ return E_FAIL;
+}
+
+MFOffset CBaseAP::GetOffset(float v)
+{
+ MFOffset offset;
+ offset.value = short(v);
+ offset.fract = WORD(65536 * (v-offset.value));
+ return offset;
+}
+
+MFVideoArea CBaseAP::GetArea(float x, float y, DWORD width, DWORD height)
+{
+ MFVideoArea area;
+ area.OffsetX = GetOffset(x);
+ area.OffsetY = GetOffset(y);
+ area.Area.cx = width;
+ area.Area.cy = height;
+ return area;
+}
+
+void CBaseAP::ResetStats()
+{
+ m_pGenlock->ResetStats();
+ m_lAudioLag = 0;
+ m_lAudioLagMin = 10000;
+ m_lAudioLagMax = -10000;
+ m_MinJitter = MAXLONG64;
+ m_MaxJitter = MINLONG64;
+ m_MinSyncOffset = MAXLONG64;
+ m_MaxSyncOffset = MINLONG64;
+ m_uSyncGlitches = 0;
+ m_pcFramesDropped = 0;
+}
+
+bool CBaseAP::SettingsNeedResetDevice()
+{
+ CRenderersSettings& s = GetRenderersSettings();
+ CRenderersSettings::CRendererSettingsEVR & New = s.m_RenderSettings;
+ CRenderersSettings::CRendererSettingsEVR & Current = m_LastRendererSettings;
+
+ bool bRet = false;
+ if (!m_bIsFullscreen)
+ {
+ if (Current.iVMRDisableDesktopComposition)
+ {
+ if (!m_bDesktopCompositionDisabled)
+ {
+ m_bDesktopCompositionDisabled = true;
+ if (m_pDwmEnableComposition)
+ m_pDwmEnableComposition(0);
+ }
+ }
+ else
+ {
+ if (m_bDesktopCompositionDisabled)
+ {
+ m_bDesktopCompositionDisabled = false;
+ if (m_pDwmEnableComposition)
+ m_pDwmEnableComposition(1);
+ }
+ }
+ }
+ bRet = bRet || New.iEVRHighColorResolution != Current.iEVRHighColorResolution;
+ m_LastRendererSettings = s.m_RenderSettings;
+ return bRet;
+}
+
+HRESULT CBaseAP::CreateDXDevice(CString &_Error)
+{
+ TRACE("--> CBaseAP::CreateDXDevice on thread: %d\n", GetCurrentThreadId());
+ CRenderersSettings& s = GetRenderersSettings();
+ m_LastRendererSettings = s.m_RenderSettings;
+ HRESULT hr = E_FAIL;
+
+ m_pFont = NULL;
+ m_pSprite = NULL;
+ m_pLine = NULL;
+
+ m_pPSC.Free();
+ m_pD3DDev = NULL;
+ m_pD3DDevEx = NULL;
+
+ m_pResizerPixelShader[0] = 0;
+ m_pResizerPixelShader[1] = 0;
+ m_pResizerPixelShader[2] = 0;
+ m_pResizerPixelShader[3] = 0;
+
+ POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition();
+ while(pos)
+ {
+ CExternalPixelShader &Shader = m_pPixelShadersScreenSpace.GetNext(pos);
+ Shader.m_pPixelShader = NULL;
+ }
+ pos = m_pPixelShaders.GetHeadPosition();
+ while(pos)
+ {
+ CExternalPixelShader &Shader = m_pPixelShaders.GetNext(pos);
+ Shader.m_pPixelShader = NULL;
+ }
+
+ if(!m_pD3D)
+ {
+ _Error += L"Failed to create Direct3D device\n";
+ return E_UNEXPECTED;
+ }
+
+ D3DDISPLAYMODE d3ddm;
+ ZeroMemory(&d3ddm, sizeof(d3ddm));
+ m_CurrentAdapter = GetAdapter(m_pD3D);
+ if(FAILED(m_pD3D->GetAdapterDisplayMode(m_CurrentAdapter, &d3ddm)))
+ {
+ _Error += L"Can not retrieve display mode data\n";
+ return E_UNEXPECTED;
+ }
+
+ if FAILED(m_pD3D->GetDeviceCaps(m_CurrentAdapter, D3DDEVTYPE_HAL, &m_caps))
+ if ((m_caps.Caps & D3DCAPS_READ_SCANLINE) == 0)
+ {
+ _Error += L"Video card does not have scanline access. Display synchronization is not possible.\n";
+ return E_UNEXPECTED;
+ }
+
+ m_uD3DRefreshRate = d3ddm.RefreshRate;
+ m_dD3DRefreshCycle = 1000.0 / (double)m_uD3DRefreshRate; // In ms
+ m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height);
+ m_pGenlock->SetDisplayResolution(d3ddm.Width, d3ddm.Height);
+
+ BOOL bCompositionEnabled = false;
+ if (m_pDwmIsCompositionEnabled) m_pDwmIsCompositionEnabled(&bCompositionEnabled);
+ m_bCompositionEnabled = bCompositionEnabled != 0;
+
+ ZeroMemory(&pp, sizeof(pp));
+ if (m_bIsFullscreen) // Exclusive mode fullscreen
+ {
+ pp.Windowed = FALSE;
+ pp.BackBufferWidth = d3ddm.Width;
+ pp.BackBufferHeight = d3ddm.Height;
+ pp.hDeviceWindow = m_hWnd;
+ _tprintf(_T("Wnd in CreateDXDevice: %d\n"), m_hWnd);
+ pp.BackBufferCount = 3;
+ pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
+ pp.Flags = D3DPRESENTFLAG_VIDEO;
+ m_bHighColorResolution = s.m_RenderSettings.iEVRHighColorResolution;
+ if (m_bHighColorResolution)
+ {
+ if(FAILED(m_pD3D->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, D3DFMT_A2R10G10B10, false)))
+ {
+ m_strStatsMsg[MSG_ERROR].Format (L"10 bit RGB is not supported by this graphics device in this resolution.");
+ m_bHighColorResolution = false;
+ }
+ }
+
+ if (m_bHighColorResolution)
+ pp.BackBufferFormat = D3DFMT_A2R10G10B10;
+ else
+ pp.BackBufferFormat = d3ddm.Format;
+
+ if (m_pD3DEx)
+ {
+ D3DDISPLAYMODEEX DisplayMode;
+ ZeroMemory(&DisplayMode, sizeof(DisplayMode));
+ DisplayMode.Size = sizeof(DisplayMode);
+ m_pD3DEx->GetAdapterDisplayModeEx(m_CurrentAdapter, &DisplayMode, NULL);
+
+ DisplayMode.Format = pp.BackBufferFormat;
+ pp.FullScreen_RefreshRateInHz = DisplayMode.RefreshRate;
+
+ if FAILED(m_pD3DEx->CreateDeviceEx(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED, &pp, &DisplayMode, &m_pD3DDevEx))
+ {
+ _Error += GothSyncErrorMessage(hr, m_hD3D9);
+ return hr;
+ }
+ if (m_pD3DDevEx)
+ {
+ m_pD3DDev = m_pD3DDevEx;
+ m_BackbufferType = pp.BackBufferFormat;
+ m_DisplayType = DisplayMode.Format;
+ }
+ }
+ else
+ {
+ if FAILED(m_pD3D->CreateDevice(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED, &pp, &m_pD3DDev))
+ {
+ _Error += GothSyncErrorMessage(hr, m_hD3D9);
+ return hr;
+ }
+ _tprintf(_T("Created full-screen device\n"));
+ if (m_pD3DDev)
+ {
+ m_BackbufferType = pp.BackBufferFormat;
+ m_DisplayType = d3ddm.Format;
+ }
+ }
+ }
+ else // Windowed
+ {
+ 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;
+ m_BackbufferType = d3ddm.Format;
+ m_DisplayType = d3ddm.Format;
+ m_bHighColorResolution = s.m_RenderSettings.iEVRHighColorResolution;
+ if (m_bHighColorResolution)
+ {
+ if(FAILED(m_pD3D->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3ddm.Format, D3DFMT_A2R10G10B10, false)))
+ {
+ m_strStatsMsg[MSG_ERROR].Format (L"10 bit RGB is not supported by this graphics device in this resolution.");
+ m_bHighColorResolution = false;
+ }
+ }
+
+ if (m_bHighColorResolution)
+ {
+ m_BackbufferType = D3DFMT_A2R10G10B10;
+ pp.BackBufferFormat = D3DFMT_A2R10G10B10;
+ }
+ if (bCompositionEnabled)
+ {
+ // Desktop composition presents the whole desktop
+ pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+ }
+ else
+ {
+ pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
+ }
+ if (m_pD3DEx)
+ {
+ if FAILED(m_pD3DEx->CreateDeviceEx(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED, &pp, NULL, &m_pD3DDevEx))
+ {
+ _Error += GothSyncErrorMessage(hr, m_hD3D9);
+ return hr;
+ }
+ if (m_pD3DDevEx) m_pD3DDev = m_pD3DDevEx;
+ }
+ else
+ {
+ if FAILED(m_pD3D->CreateDevice(m_CurrentAdapter, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_MULTITHREADED, &pp, &m_pD3DDev))
+ {
+ _Error += GothSyncErrorMessage(hr, m_hD3D9);
+ return hr;
+ }
+ _tprintf(_T("Created windowed device\n"));
+ }
+ }
+
+ if (m_pD3DDevEx)
+ {
+ m_pD3DDevEx->SetGPUThreadPriority(7);
+ }
+
+ m_pPSC.Attach(DNew CPixelShaderCompiler(m_pD3DDev, true));
+ m_filter = D3DTEXF_NONE;
+
+ if(m_caps.StretchRectFilterCaps&D3DPTFILTERCAPS_MINFLINEAR && m_caps.StretchRectFilterCaps&D3DPTFILTERCAPS_MAGFLINEAR)
+ m_filter = D3DTEXF_LINEAR;
+
+ m_bicubicA = 0;
+
+ CSize size;
+ switch(GetRenderersSettings().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;
+ case 6:
+ size.SetSize(2560, 1600);
+ break;
+ case 7:
+ size.SetSize(1920, 1080);
+ break;
+ case 8:
+ size.SetSize(1320, 900);
+ break;
+ case 9:
+ size.SetSize(1280, 720);
+ break;
+ }
+
+ if(m_pAllocator)
+ {
+ m_pAllocator->ChangeDevice(m_pD3DDev);
+ }
+ else
+ {
+ m_pAllocator = DNew CDX9SubPicAllocator(m_pD3DDev, size, GetRenderersSettings().fSPCPow2Tex);
+ if(!m_pAllocator)
+ {
+ _Error += L"CDX9SubPicAllocator failed\n";
+ return E_FAIL;
+ }
+ }
+
+ hr = S_OK;
+
+ CComPtr<ISubPicProvider> pSubPicProvider;
+ if(m_pSubPicQueue)
+ {
+ _tprintf(_T("m_pSubPicQueue != NULL\n"));
+ m_pSubPicQueue->GetSubPicProvider(&pSubPicProvider);
+ }
+
+ m_pSubPicQueue = NULL;
+ m_pSubPicQueue = GetRenderersSettings().nSPCSize > 0
+ ? (ISubPicQueue*)DNew CSubPicQueue(GetRenderersSettings().nSPCSize, !GetRenderersSettings().fSPCAllowAnimationWhenBuffering, m_pAllocator, &hr)
+ : (ISubPicQueue*)DNew CSubPicQueueNoThread(m_pAllocator, &hr);
+ if(!m_pSubPicQueue || FAILED(hr))
+ {
+ _Error += L"m_pSubPicQueue failed\n";
+ return E_FAIL;
+ }
+
+ if(pSubPicProvider) m_pSubPicQueue->SetSubPicProvider(pSubPicProvider);
+
+ if (m_pD3DXCreateFont)
+ {
+ int MinSize = 1600;
+ int CurrentSize = min(m_ScreenSize.cx, MinSize);
+ double Scale = double(CurrentSize) / double(MinSize);
+ m_TextScale = Scale;
+ m_pD3DXCreateFont(m_pD3DDev, -24.0*Scale, -11.0*Scale, CurrentSize < 800 ? FW_NORMAL : FW_BOLD, 0, FALSE,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FIXED_PITCH | FF_DONTCARE, L"Lucida Console", &m_pFont);
+ }
+ if (m_pD3DXCreateSprite) m_pD3DXCreateSprite(m_pD3DDev, &m_pSprite);
+ if (m_pD3DXCreateLine) m_pD3DXCreateLine (m_pD3DDev, &m_pLine);
+ m_LastAdapterCheck = GetRenderersData()->GetPerfCounter();
+ return S_OK;
+}
+
+HRESULT CBaseAP::ResetDXDevice(CString &_Error)
+{
+ CRenderersSettings& s = GetRenderersSettings();
+ m_LastRendererSettings = s.m_RenderSettings;
+ HRESULT hr = E_FAIL;
+
+ hr = m_pD3DDev->TestCooperativeLevel();
+ if ((hr != D3DERR_DEVICENOTRESET) && (hr != D3D_OK)) return hr;
+
+ CComPtr<IEnumPins> rendererInputEnum;
+ vector<CComPtr<IPin>> decoderOutput;
+ vector<CComPtr<IPin>> rendererInput;
+ FILTER_INFO filterInfo;
+
+ bool disconnected = FALSE;
+
+ // Disconnect all pins to release video memory resources
+ if (m_pD3DDev)
+ {
+ ZeroMemory(&filterInfo, sizeof(filterInfo));
+ m_pOuterEVR->QueryFilterInfo(&filterInfo); // This addref's the pGraph member
+ if (SUCCEEDED(m_pOuterEVR->EnumPins(&rendererInputEnum)))
+ {
+ CComPtr<IPin> input;
+ CComPtr<IPin> output;
+ while (hr = rendererInputEnum->Next(1, &input.p, 0), hr == S_OK) // Must have .p here
+ {
+ _tprintf(_T("Pin found\n"));
+ input->ConnectedTo(&output.p);
+ if (output != NULL)
+ {
+ rendererInput.push_back(input);
+ decoderOutput.push_back(output);
+ }
+ input.Release();
+ output.Release();
+ }
+ }
+ else return hr;
+ for (DWORD i = 0; i < decoderOutput.size(); i++)
+ {
+ _tprintf(_T("Disconnecting pin\n"));
+ filterInfo.pGraph->Disconnect(decoderOutput.at(i).p);
+ filterInfo.pGraph->Disconnect(rendererInput.at(i).p);
+ _tprintf(_T("Pin disconnected\n"));
+ }
+ disconnected = true;
+ }
+
+ // Release more resources
+ m_pSubPicQueue = NULL;
+ m_pFont = NULL;
+ m_pSprite = NULL;
+ m_pLine = NULL;
+ m_pPSC.Free();
+
+ m_pResizerPixelShader[0] = 0;
+ m_pResizerPixelShader[1] = 0;
+ m_pResizerPixelShader[2] = 0;
+ m_pResizerPixelShader[3] = 0;
+
+ POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition();
+ while(pos)
+ {
+ CExternalPixelShader &Shader = m_pPixelShadersScreenSpace.GetNext(pos);
+ Shader.m_pPixelShader = NULL;
+ }
+ pos = m_pPixelShaders.GetHeadPosition();
+ while(pos)
+ {
+ CExternalPixelShader &Shader = m_pPixelShaders.GetNext(pos);
+ Shader.m_pPixelShader = NULL;
+ }
+
+ D3DDISPLAYMODE d3ddm;
+ ZeroMemory(&d3ddm, sizeof(d3ddm));
+ if(FAILED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D), &d3ddm)))
+ {
+ _Error += L"Can not retrieve display mode data\n";
+ return E_UNEXPECTED;
+ }
+
+ m_uD3DRefreshRate = d3ddm.RefreshRate;
+ m_dD3DRefreshCycle = 1000.0 / (double)m_uD3DRefreshRate; // In ms
+ m_ScreenSize.SetSize(d3ddm.Width, d3ddm.Height);
+ m_pGenlock->SetDisplayResolution(d3ddm.Width, d3ddm.Height);
+
+ D3DPRESENT_PARAMETERS pp;
+ ZeroMemory(&pp, sizeof(pp));
+
+ BOOL bCompositionEnabled = false;
+ if (m_pDwmIsCompositionEnabled) m_pDwmIsCompositionEnabled(&bCompositionEnabled);
+ m_bCompositionEnabled = bCompositionEnabled != 0;
+ m_bHighColorResolution = s.m_RenderSettings.iEVRHighColorResolution;
+
+ if (m_bIsFullscreen) // Exclusive mode fullscreen
+ {
+ pp.BackBufferWidth = d3ddm.Width;
+ pp.BackBufferHeight = d3ddm.Height;
+ if (m_bHighColorResolution)
+ pp.BackBufferFormat = D3DFMT_A2R10G10B10;
+ else
+ pp.BackBufferFormat = d3ddm.Format;
+ if(FAILED(m_pD3DEx->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, pp.BackBufferFormat, pp.BackBufferFormat, false)))
+ {
+ _Error += L"10 bit RGB is not supported by this graphics device in exclusive mode fullscreen.\n";
+ return hr;
+ }
+
+ D3DDISPLAYMODEEX DisplayMode;
+ ZeroMemory(&DisplayMode, sizeof(DisplayMode));
+ DisplayMode.Size = sizeof(DisplayMode);
+ if (m_pD3DDevEx)
+ {
+ m_pD3DEx->GetAdapterDisplayModeEx(GetAdapter(m_pD3DEx), &DisplayMode, NULL);
+ DisplayMode.Format = pp.BackBufferFormat;
+ pp.FullScreen_RefreshRateInHz = DisplayMode.RefreshRate;
+ if FAILED(m_pD3DDevEx->Reset(&pp))
+ {
+ _Error += GothSyncErrorMessage(hr, m_hD3D9);
+ return hr;
+ }
+ }
+ else if (m_pD3DDev)
+ {
+ if FAILED(m_pD3DDev->Reset(&pp))
+ {
+ _Error += GothSyncErrorMessage(hr, m_hD3D9);
+ return hr;
+ }
+ }
+ else
+ {
+ _Error += L"No device.\n";
+ return hr;
+ }
+ m_BackbufferType = pp.BackBufferFormat;
+ m_DisplayType = d3ddm.Format;
+ }
+ else // Windowed
+ {
+ pp.BackBufferWidth = d3ddm.Width;
+ pp.BackBufferHeight = d3ddm.Height;
+ m_BackbufferType = d3ddm.Format;
+ m_DisplayType = d3ddm.Format;
+ if (m_bHighColorResolution)
+ {
+ m_BackbufferType = D3DFMT_A2R10G10B10;
+ pp.BackBufferFormat = D3DFMT_A2R10G10B10;
+ }
+ if(FAILED(m_pD3DEx->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, pp.BackBufferFormat, pp.BackBufferFormat, false)))
+ {
+ _Error += L"10 bit RGB is not supported by this graphics device in windowed mode.\n";
+ return hr;
+ }
+ if (bCompositionEnabled)
+ {
+ // Desktop composition presents the whole desktop
+ pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
+ }
+ else
+ {
+ pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
+ }
+ if (m_pD3DDevEx)
+ if FAILED(m_pD3DDevEx->Reset(&pp))
+ {
+ _Error += GothSyncErrorMessage(hr, m_hD3D9);
+ return hr;
+ }
+ else if (m_pD3DDev)
+ if FAILED(m_pD3DDevEx->Reset(&pp))
+ {
+ _Error += GothSyncErrorMessage(hr, m_hD3D9);
+ return hr;
+ }
+ else
+ {
+ _Error += L"No device.\n";
+ return hr;
+ }
+ }
+
+ if (disconnected)
+ {
+ for (DWORD i = 0; i < decoderOutput.size(); i++)
+ {
+ if (FAILED(filterInfo.pGraph->ConnectDirect(decoderOutput.at(i).p, rendererInput.at(i).p, NULL)))
+ {
+ return hr;
+ }
+ }
+
+ if (filterInfo.pGraph != NULL)
+ {
+ filterInfo.pGraph->Release();
+ }
+ }
+
+ m_pPSC.Attach(DNew CPixelShaderCompiler(m_pD3DDev, true));
+ m_filter = D3DTEXF_NONE;
+
+ 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(GetRenderersSettings().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;
+ case 6:
+ size.SetSize(2560, 1600);
+ break;
+ case 7:
+ size.SetSize(1920, 1080);
+ break;
+ case 8:
+ size.SetSize(1320, 900);
+ break;
+ case 9:
+ size.SetSize(1280, 720);
+ break;
+ }
+
+ if(m_pAllocator)
+ {
+ m_pAllocator->ChangeDevice(m_pD3DDev);
+ }
+ else
+ {
+ m_pAllocator = DNew CDX9SubPicAllocator(m_pD3DDev, size, GetRenderersSettings().fSPCPow2Tex);
+ if(!m_pAllocator)
+ {
+ _Error += L"CDX9SubPicAllocator failed\n";
+
+ return E_FAIL;
+ }
+ }
+
+ hr = S_OK;
+ m_pSubPicQueue = GetRenderersSettings().nSPCSize > 0
+ ? (ISubPicQueue*)DNew CSubPicQueue(GetRenderersSettings().nSPCSize, !GetRenderersSettings().fSPCAllowAnimationWhenBuffering, m_pAllocator, &hr)
+ : (ISubPicQueue*)DNew CSubPicQueueNoThread(m_pAllocator, &hr);
+ if(!m_pSubPicQueue || FAILED(hr))
+ {
+ _Error += L"m_pSubPicQueue failed\n";
+
+ return E_FAIL;
+ }
+
+ if(pSubPicProvider) m_pSubPicQueue->SetSubPicProvider(pSubPicProvider);
+
+ m_pFont = NULL;
+ if (m_pD3DXCreateFont)
+ {
+ int MinSize = 1600;
+ int CurrentSize = min(m_ScreenSize.cx, MinSize);
+ double Scale = double(CurrentSize) / double(MinSize);
+ m_TextScale = Scale;
+ m_pD3DXCreateFont(m_pD3DDev, -24.0*Scale, -11.0*Scale, CurrentSize < 800 ? FW_NORMAL : FW_BOLD, 0, FALSE,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FIXED_PITCH | FF_DONTCARE, L"Lucida Console", &m_pFont);
+ }
+ m_pSprite = NULL;
+ if (m_pD3DXCreateSprite) m_pD3DXCreateSprite(m_pD3DDev, &m_pSprite);
+ m_pLine = NULL;
+ if (m_pD3DXCreateLine) m_pD3DXCreateLine (m_pD3DDev, &m_pLine);
+ return S_OK;
+}
+
+HRESULT CBaseAP::AllocSurfaces(D3DFORMAT Format)
+{
+ CAutoLock cAutoLock(this);
+ CAutoLock cRenderLock(&m_allocatorLock);
+
+ CRenderersSettings& s = GetRenderersSettings();
+
+ for(int i = 0; i < m_nDXSurface+2; i++)
+ {
+ m_pVideoTexture[i] = NULL;
+ m_pVideoSurface[i] = NULL;
+ }
+
+ m_pScreenSizeTemporaryTexture[0] = NULL;
+ m_pScreenSizeTemporaryTexture[1] = NULL;
+ m_SurfaceType = Format;
+
+ HRESULT hr;
+ if(s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE2D || s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D)
+ {
+ int nTexturesNeeded = s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D ? m_nDXSurface+2 : 1;
+
+ for(int i = 0; i < nTexturesNeeded; i++)
+ {
+ if(FAILED(hr = m_pD3DDev->CreateTexture(
+ m_NativeVideoSize.cx, m_NativeVideoSize.cy, 1, D3DUSAGE_RENDERTARGET, Format, 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 < m_nDXSurface+2; i++)
+ {
+ m_pVideoTexture[i] = NULL;
+ }
+ }
+ }
+ else
+ {
+ if(FAILED(hr = m_pD3DDev->CreateOffscreenPlainSurface(m_NativeVideoSize.cx, m_NativeVideoSize.cy, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &m_pVideoSurface[m_nCurSurface], NULL)))
+ return hr;
+ }
+
+ hr = m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], NULL, 0);
+ return S_OK;
+}
+
+void CBaseAP::DeleteSurfaces()
+{
+ CAutoLock cAutoLock(this);
+ CAutoLock cRenderLock(&m_allocatorLock);
+
+ for(int i = 0; i < m_nDXSurface+2; i++)
+ {
+ m_pVideoTexture[i] = NULL;
+ m_pVideoSurface[i] = NULL;
+ }
+}
+
+UINT CBaseAP::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 CBaseAP::CreateRenderer(IUnknown** ppRenderer)
+{
+ return E_NOTIMPL;
+}
+
+bool CBaseAP::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 CBaseAP::InitResizers(float bicubicA, bool bNeedScreenSizeTexture)
+{
+ HRESULT hr;
+ do
+ {
+ if (bicubicA)
+ {
+ if (!m_pResizerPixelShader[0])
+ break;
+ if (!m_pResizerPixelShader[1])
+ break;
+ if (!m_pResizerPixelShader[2])
+ break;
+ if (!m_pResizerPixelShader[3])
+ break;
+ if (m_bicubicA != bicubicA)
+ break;
+ if (!m_pScreenSizeTemporaryTexture[0])
+ break;
+ if (bNeedScreenSizeTexture)
+ {
+ if (!m_pScreenSizeTemporaryTexture[1])
+ break;
+ }
+ }
+ else
+ {
+ if (!m_pResizerPixelShader[0])
+ break;
+ if (bNeedScreenSizeTexture)
+ {
+ if (!m_pScreenSizeTemporaryTexture[0])
+ break;
+ if (!m_pScreenSizeTemporaryTexture[1])
+ break;
+ }
+ }
+ return S_OK;
+ }
+ while (0);
+
+ m_bicubicA = bicubicA;
+ m_pScreenSizeTemporaryTexture[0] = NULL;
+ m_pScreenSizeTemporaryTexture[1] = 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_pass1", "main_bicubic2pass_pass2"};
+
+ ASSERT(countof(pEntries) == countof(m_pResizerPixelShader));
+ for(int i = 0; i < countof(pEntries); i++)
+ {
+ CString ErrorMessage;
+ CString DissAssembly;
+ hr = m_pPSC->CompileShader(str, pEntries[i], pProfile, 0, &m_pResizerPixelShader[i], &DissAssembly, &ErrorMessage);
+ if(FAILED(hr))
+ {
+ TRACE("%ws", ErrorMessage.GetString());
+ ASSERT (0);
+ return hr;
+ }
+ }
+ if(m_bicubicA || bNeedScreenSizeTexture)
+ {
+ if(FAILED(m_pD3DDev->CreateTexture(
+ min(m_ScreenSize.cx, (int)m_caps.MaxTextureWidth), min(max(m_ScreenSize.cy, m_NativeVideoSize.cy), (int)m_caps.MaxTextureHeight), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
+ D3DPOOL_DEFAULT, &m_pScreenSizeTemporaryTexture[0], NULL)))
+ {
+ ASSERT(0);
+ m_pScreenSizeTemporaryTexture[0] = NULL; // will do 1 pass then
+ }
+ }
+ if(m_bicubicA || bNeedScreenSizeTexture)
+ {
+ if(FAILED(m_pD3DDev->CreateTexture(
+ min(m_ScreenSize.cx, (int)m_caps.MaxTextureWidth), min(max(m_ScreenSize.cy, m_NativeVideoSize.cy), (int)m_caps.MaxTextureHeight), 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
+ D3DPOOL_DEFAULT, &m_pScreenSizeTemporaryTexture[1], NULL)))
+ {
+ ASSERT(0);
+ m_pScreenSizeTemporaryTexture[1] = NULL; // will do 1 pass then
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CBaseAP::TextureCopy(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 CBaseAP::DrawRect(DWORD _Color, DWORD _Alpha, const CRect &_Rect)
+{
+ DWORD Color = D3DCOLOR_ARGB(_Alpha, GetRValue(_Color), GetGValue(_Color), GetBValue(_Color));
+ MYD3DVERTEX<0> v[] =
+ {
+ {float(_Rect.left), float(_Rect.top), 0.5f, 2.0f, Color},
+ {float(_Rect.right), float(_Rect.top), 0.5f, 2.0f, Color},
+ {float(_Rect.left), float(_Rect.bottom), 0.5f, 2.0f, Color},
+ {float(_Rect.right), float(_Rect.bottom), 0.5f, 2.0f, Color},
+ };
+ for(int i = 0; i < countof(v); i++)
+ {
+ v[i].x -= 0.5;
+ v[i].y -= 0.5;
+ }
+ return DrawRectBase(m_pD3DDev, v);
+}
+
+HRESULT CBaseAP::TextureResize(IDirect3DTexture9* pTexture, Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect &SrcRect)
+{
+ 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;
+ float dx2 = 1.0/w;
+ float dy2 = 1.0/h;
+
+ MYD3DVERTEX<1> v[] =
+ {
+ {dst[0].x, dst[0].y, dst[0].z, 1.0f/dst[0].z, SrcRect.left * dx2, SrcRect.top * dy2},
+ {dst[1].x, dst[1].y, dst[1].z, 1.0f/dst[1].z, SrcRect.right * dx2, SrcRect.top * dy2},
+ {dst[2].x, dst[2].y, dst[2].z, 1.0f/dst[2].z, SrcRect.left * dx2, SrcRect.bottom * dy2},
+ {dst[3].x, dst[3].y, dst[3].z, 1.0f/dst[3].z, SrcRect.right * dx2, SrcRect.bottom * dy2},
+ };
+ AdjustQuad(v, 0, 0);
+ hr = m_pD3DDev->SetTexture(0, pTexture);
+ hr = m_pD3DDev->SetPixelShader(NULL);
+ hr = TextureBlt(m_pD3DDev, v, filter);
+ return hr;
+}
+
+HRESULT CBaseAP::TextureResizeBilinear(IDirect3DTexture9* pTexture, Vector dst[4], const CRect &SrcRect)
+{
+ 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;
+ float tx0 = SrcRect.left;
+ float tx1 = SrcRect.right;
+ float ty0 = SrcRect.top;
+ float ty1 = SrcRect.bottom;
+
+ MYD3DVERTEX<1> v[] =
+ {
+ {dst[0].x, dst[0].y, dst[0].z, 1.0f/dst[0].z, tx0, ty0},
+ {dst[1].x, dst[1].y, dst[1].z, 1.0f/dst[1].z, tx1, ty0},
+ {dst[2].x, dst[2].y, dst[2].z, 1.0f/dst[2].z, tx0, ty1},
+ {dst[3].x, dst[3].y, dst[3].z, 1.0f/dst[3].z, tx1, ty1},
+ };
+ AdjustQuad(v, 1.0, 1.0);
+ float fConstData[][4] = {{0.5f / w, 0.5f / h, 0, 0}, {1.0f / w, 1.0f / h, 0, 0}, {1.0f / w, 0, 0, 0}, {0, 1.0f / h, 0, 0}, {w, h, 0, 0}};
+ hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, countof(fConstData));
+ hr = m_pD3DDev->SetTexture(0, pTexture);
+ hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[0]);
+ hr = TextureBlt(m_pD3DDev, v, D3DTEXF_POINT);
+ m_pD3DDev->SetPixelShader(NULL);
+ return hr;
+}
+
+HRESULT CBaseAP::TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, Vector dst[4], const CRect &SrcRect)
+{
+ HRESULT hr;
+
+ D3DSURFACE_DESC desc;
+ if(!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc)))
+ return E_FAIL;
+
+ double w = (double)desc.Width;
+ double h = (double)desc.Height;
+
+ double sw = SrcRect.Width();
+ double sh = SrcRect.Height();
+
+ double dx = 1.0f/w;
+ double dy = 1.0f/h;
+
+ float dx2 = 1.0f/w;
+ float dy2 = 1.0f/h;
+ float tx0 = SrcRect.left;
+ float tx1 = SrcRect.right;
+ float ty0 = SrcRect.top;
+ float ty1 = SrcRect.bottom;
+
+ MYD3DVERTEX<1> v[] =
+ {
+ {dst[0].x, dst[0].y, dst[0].z, 1.0f/dst[0].z, tx0, ty0},
+ {dst[1].x, dst[1].y, dst[1].z, 1.0f/dst[1].z, tx1, ty0},
+ {dst[2].x, dst[2].y, dst[2].z, 1.0f/dst[2].z, tx0, ty1},
+ {dst[3].x, dst[3].y, dst[3].z, 1.0f/dst[3].z, tx1, ty1},
+ };
+ AdjustQuad(v, 1.0, 1.0);
+ hr = m_pD3DDev->SetTexture(0, pTexture);
+ float fConstData[][4] = {{0.5f / w, 0.5f / h, 0, 0}, {1.0f / w, 1.0f / h, 0, 0}, {1.0f / w, 0, 0, 0}, {0, 1.0f / h, 0, 0}, {w, 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 CBaseAP::TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, Vector dst[4], const CRect &SrcRect)
+{
+ // The 2 pass sampler is incorrect in that it only does bilinear resampling in the y direction.
+ return TextureResizeBicubic1pass(pTexture, dst, SrcRect);
+
+ 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, SrcRect);
+
+ D3DSURFACE_DESC desc;
+ if(!pTexture || FAILED(pTexture->GetLevelDesc(0, &desc)))
+ return E_FAIL;
+
+ float Tex0_Width = desc.Width;
+ float Tex0_Height = desc.Height;
+
+ double dx0 = 1.0/desc.Width;
+ double dy0 = 1.0/desc.Height;
+
+ CSize SrcTextSize = CSize(desc.Width, desc.Height);
+ double w = (double)SrcRect.Width();
+ double h = (double)SrcRect.Height();
+
+ CRect dst1(0, 0, (int)(dst[3].x - dst[0].x), (int)h);
+
+ if(!m_pScreenSizeTemporaryTexture[0] || FAILED(m_pScreenSizeTemporaryTexture[0]->GetLevelDesc(0, &desc)))
+ return TextureResizeBicubic1pass(pTexture, dst, SrcRect);
+
+ float Tex1_Width = desc.Width;
+ float Tex1_Height = desc.Height;
+
+ double dx1 = 1.0/desc.Width;
+ double dy1 = 1.0/desc.Height;
+
+ double dw = (double)dst1.Width() / desc.Width;
+ double dh = (double)dst1.Height() / desc.Height;
+
+ float dx2 = 1.0f/SrcTextSize.cx;
+ float dy2 = 1.0f/SrcTextSize.cy;
+ float tx0 = SrcRect.left;
+ float tx1 = SrcRect.right;
+ float ty0 = SrcRect.top;
+ float ty1 = SrcRect.bottom;
+
+ float tx0_2 = 0;
+ float tx1_2 = dst1.Width();
+ float ty0_2 = 0;
+ float ty1_2 = h;
+
+ if(dst1.Width() > (int)desc.Width || dst1.Height() > (int)desc.Height)
+ return TextureResizeBicubic1pass(pTexture, dst, SrcRect);
+
+ MYD3DVERTEX<1> vx[] =
+ {
+ {(float)dst1.left, (float)dst1.top, 0.5f, 2.0f, tx0, ty0},
+ {(float)dst1.right, (float)dst1.top, 0.5f, 2.0f, tx1, ty0},
+ {(float)dst1.left, (float)dst1.bottom, 0.5f, 2.0f, tx0, ty1},
+ {(float)dst1.right, (float)dst1.bottom, 0.5f, 2.0f, tx1, ty1},
+ };
+ AdjustQuad(vx, 1.0, 0.0); // Casimir666 : bug ici, génére des bandes verticales! TODO : pourquoi ??????
+ MYD3DVERTEX<1> vy[] =
+ {
+ {dst[0].x, dst[0].y, dst[0].z, 1.0/dst[0].z, tx0_2, ty0_2},
+ {dst[1].x, dst[1].y, dst[1].z, 1.0/dst[1].z, tx1_2, ty0_2},
+ {dst[2].x, dst[2].y, dst[2].z, 1.0/dst[2].z, tx0_2, ty1_2},
+ {dst[3].x, dst[3].y, dst[3].z, 1.0/dst[3].z, tx1_2, ty1_2},
+ };
+ AdjustQuad(vy, 0.0, 1.0);
+ hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[2]);
+ {
+ float fConstData[][4] = {{0.5f / Tex0_Width, 0.5f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 1.0f / Tex0_Height, 0, 0}, {1.0f / Tex0_Width, 0, 0, 0}, {0, 1.0f / Tex0_Height, 0, 0}, {Tex0_Width, Tex0_Height, 0, 0}};
+ hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, countof(fConstData));
+ }
+ hr = m_pD3DDev->SetTexture(0, pTexture);
+ CComPtr<IDirect3DSurface9> pRTOld;
+ hr = m_pD3DDev->GetRenderTarget(0, &pRTOld);
+ CComPtr<IDirect3DSurface9> pRT;
+ hr = m_pScreenSizeTemporaryTexture[0]->GetSurfaceLevel(0, &pRT);
+ hr = m_pD3DDev->SetRenderTarget(0, pRT);
+ hr = TextureBlt(m_pD3DDev, vx, D3DTEXF_POINT);
+ hr = m_pD3DDev->SetPixelShader(m_pResizerPixelShader[3]);
+ {
+ float fConstData[][4] = {{0.5f / Tex1_Width, 0.5f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 1.0f / Tex1_Height, 0, 0}, {1.0f / Tex1_Width, 0, 0, 0}, {0, 1.0f / Tex1_Height, 0, 0}, {Tex1_Width, Tex1_Height, 0, 0}};
+ hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, countof(fConstData));
+ }
+ hr = m_pD3DDev->SetTexture(0, m_pScreenSizeTemporaryTexture[0]);
+ hr = m_pD3DDev->SetRenderTarget(0, pRTOld);
+ hr = TextureBlt(m_pD3DDev, vy, D3DTEXF_POINT);
+ m_pD3DDev->SetPixelShader(NULL);
+ return hr;
+}
+
+HRESULT CBaseAP::AlphaBlt(RECT* pSrc, RECT* pDst, IDirect3DTexture9* pTexture)
+{
+ if(!pSrc || !pDst)
+ return E_POINTER;
+
+ CRect src(*pSrc), dst(*pDst);
+
+ HRESULT hr;
+
+ do
+ {
+ D3DSURFACE_DESC d3dsd;
+ ZeroMemory(&d3dsd, sizeof(d3dsd));
+ if(FAILED(pTexture->GetLevelDesc(0, &d3dsd)) /*|| d3dsd.Type != D3DRTYPE_TEXTURE*/)
+ break;
+
+ float w = (float)d3dsd.Width;
+ float h = (float)d3dsd.Height;
+
+ struct
+ {
+ float x, y, z, rhw;
+ float tu, tv;
+ }
+ pVertices[] =
+ {
+ {(float)dst.left, (float)dst.top, 0.5f, 2.0f, (float)src.left / w, (float)src.top / h},
+ {(float)dst.right, (float)dst.top, 0.5f, 2.0f, (float)src.right / w, (float)src.top / h},
+ {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, (float)src.left / w, (float)src.bottom / h},
+ {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, (float)src.right / w, (float)src.bottom / h},
+ };
+
+ hr = m_pD3DDev->SetTexture(0, pTexture);
+
+ DWORD abe, sb, db;
+ hr = m_pD3DDev->GetRenderState(D3DRS_ALPHABLENDENABLE, &abe);
+ hr = m_pD3DDev->GetRenderState(D3DRS_SRCBLEND, &sb);
+ hr = m_pD3DDev->GetRenderState(D3DRS_DESTBLEND, &db);
+
+ hr = m_pD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ hr = m_pD3DDev->SetRenderState(D3DRS_LIGHTING, FALSE);
+ hr = m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE);
+ hr = m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+ hr = m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); // pre-multiplied src and ...
+ hr = m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); // ... inverse alpha channel for dst
+
+ hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ hr = m_pD3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
+
+ hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+ hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+ hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
+
+ hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+ hr = m_pD3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+
+ hr = m_pD3DDev->SetPixelShader(NULL);
+
+ hr = m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
+ hr = m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0]));
+
+ m_pD3DDev->SetTexture(0, NULL);
+
+ m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, abe);
+ m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, sb);
+ m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, db);
+
+ return S_OK;
+ }
+ while(0);
+ return E_FAIL;
+}
+
+// Update the array m_pllJitter with a new vsync period. Calculate min, max and stddev.
+void CBaseAP::SyncStats(LONGLONG syncTime)
+{
+ m_nNextJitter = (m_nNextJitter+1) % NB_JITTER;
+ LONGLONG jitter = syncTime - m_llLastSyncTime;
+ m_pllJitter[m_nNextJitter] = jitter;
+ double syncDeviation = ((double)m_pllJitter[m_nNextJitter] - m_fJitterMean) / 10000.0;
+ if (abs(syncDeviation) > (GetDisplayCycle() / 2))
+ m_uSyncGlitches++;
+
+ LONGLONG llJitterSum = 0;
+ LONGLONG llJitterSumAvg = 0;
+ for (int i=0; i<NB_JITTER; i++)
+ {
+ LONGLONG Jitter = m_pllJitter[i];
+ llJitterSum += Jitter;
+ llJitterSumAvg += Jitter;
+ }
+ m_fJitterMean = double(llJitterSumAvg) / NB_JITTER;
+ double DeviationSum = 0;
+
+ for (int i=0; i<NB_JITTER; i++)
+ {
+ LONGLONG DevInt = m_pllJitter[i] - m_fJitterMean;
+ double Deviation = DevInt;
+ DeviationSum += Deviation*Deviation;
+ m_MaxJitter = max(m_MaxJitter, DevInt);
+ m_MinJitter = min(m_MinJitter, DevInt);
+ }
+
+ m_fJitterStdDev = sqrt(DeviationSum/NB_JITTER);
+ m_fAvrFps = 10000000.0/(double(llJitterSum)/NB_JITTER);
+ m_llLastSyncTime = syncTime;
+}
+
+// Collect the difference between periodEnd and periodStart in an array, calculate mean and stddev.
+void CBaseAP::SyncOffsetStats(LONGLONG syncOffset)
+{
+ m_nNextSyncOffset = (m_nNextSyncOffset+1) % NB_JITTER;
+ m_pllSyncOffset[m_nNextSyncOffset] = syncOffset;
+
+ LONGLONG AvrageSum = 0;
+ for (int i=0; i<NB_JITTER; i++)
+ {
+ LONGLONG Offset = m_pllSyncOffset[i];
+ AvrageSum += Offset;
+ m_MaxSyncOffset = max(m_MaxSyncOffset, Offset);
+ m_MinSyncOffset = min(m_MinSyncOffset, Offset);
+ }
+ double MeanOffset = double(AvrageSum)/NB_JITTER;
+ double DeviationSum = 0;
+ for (int i=0; i<NB_JITTER; i++)
+ {
+ double Deviation = double(m_pllSyncOffset[i]) - MeanOffset;
+ DeviationSum += Deviation*Deviation;
+ }
+ double StdDev = sqrt(DeviationSum/NB_JITTER);
+
+ m_fSyncOffsetAvr = MeanOffset;
+ m_fSyncOffsetStdDev = StdDev;
+}
+
+void CBaseAP::UpdateAlphaBitmap()
+{
+ m_VMR9AlphaBitmapData.Free();
+
+ if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0)
+ {
+ HBITMAP hBitmap = (HBITMAP)GetCurrentObject (m_VMR9AlphaBitmap.hdc, OBJ_BITMAP);
+ if (!hBitmap)
+ return;
+ DIBSECTION info = {0};
+ if (!::GetObject(hBitmap, sizeof( DIBSECTION ), &info ))
+ return;
+
+ m_VMR9AlphaBitmapRect = CRect(0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight);
+ m_VMR9AlphaBitmapWidthBytes = info.dsBm.bmWidthBytes;
+
+ if (m_VMR9AlphaBitmapData.Allocate(info.dsBm.bmWidthBytes * info.dsBm.bmHeight))
+ {
+ memcpy((BYTE *)m_VMR9AlphaBitmapData, info.dsBm.bmBits, info.dsBm.bmWidthBytes * info.dsBm.bmHeight);
+ }
+ }
+}
+
+// Present a sample (frame) using DirectX.
+STDMETHODIMP_(bool) CBaseAP::Paint(bool fAll)
+{
+ if (m_bPendingResetDevice)
+ {
+ SendResetRequest();
+ return false;
+ }
+
+ CRenderersSettings& s = GetRenderersSettings();
+ CRenderersData * pApp = GetRenderersData();
+ D3DRASTER_STATUS rasterStatus;
+ REFERENCE_TIME llCurRefTime = 0;
+ REFERENCE_TIME llSyncOffset = 0;
+ double dSyncOffset = 0.0;
+
+ CAutoLock cRenderLock(&m_allocatorLock);
+
+ // Estimate time for next vblank based on number of remaining lines in this frame. This algorithm seems to be
+ // accurate within one ms why there should not be any need for a more accurate one. The wiggly line seen
+ // when using sync to nearest and sync display is most likely due to inaccuracies in the audio-card-based
+ // reference clock. The wiggles are not seen with the perfcounter-based reference clock of the sync to video option.
+ m_pD3DDev->GetRasterStatus(0, &rasterStatus);
+ m_uScanLineEnteringPaint = rasterStatus.ScanLine;
+ if (m_pRefClock) m_pRefClock->GetTime(&llCurRefTime);
+ int dScanLines = max((int)m_ScreenSize.cy - m_uScanLineEnteringPaint, 0);
+ dSyncOffset = dScanLines * m_dDetectedScanlineTime; // ms
+ llSyncOffset = REFERENCE_TIME(10000.0 * dSyncOffset); // Reference time units (100 ns)
+ m_llEstVBlankTime = llCurRefTime + llSyncOffset; // Estimated time for the start of next vblank
+
+ 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);
+
+ m_pD3DDev->BeginScene();
+ CComPtr<IDirect3DSurface9> pBackBuffer;
+ m_pD3DDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
+ m_pD3DDev->SetRenderTarget(0, pBackBuffer);
+ hr = m_pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0);
+ if(!rDstVid.IsRectEmpty())
+ {
+ if(m_pVideoTexture[m_nCurSurface])
+ {
+ CComPtr<IDirect3DTexture9> pVideoTexture = m_pVideoTexture[m_nCurSurface];
+
+ if(m_pVideoTexture[m_nDXSurface] && m_pVideoTexture[m_nDXSurface+1] && !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)
+
+ int src = m_nCurSurface, dst = m_nDXSurface;
+
+ D3DSURFACE_DESC desc;
+ m_pVideoTexture[src]->GetLevelDesc(0, &desc);
+
+ float fConstData[][4] =
+ {
+ {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC},
+ {1.0f / desc.Width, 1.0f / desc.Height, 0, 0},
+ };
+
+ hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, countof(fConstData));
+
+ CComPtr<IDirect3DSurface9> pRT;
+ hr = m_pD3DDev->GetRenderTarget(0, &pRT);
+
+ POSITION pos = m_pPixelShaders.GetHeadPosition();
+ while(pos)
+ {
+ pVideoTexture = m_pVideoTexture[dst];
+
+ hr = m_pD3DDev->SetRenderTarget(0, m_pVideoSurface[dst]);
+ CExternalPixelShader &Shader = m_pPixelShaders.GetNext(pos);
+ if (!Shader.m_pPixelShader)
+ Shader.Compile(m_pPSC);
+ hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader);
+ TextureCopy(m_pVideoTexture[src]);
+
+ src = dst;
+ if(++dst >= m_nDXSurface+2) dst = m_nDXSurface;
+ }
+
+ hr = m_pD3DDev->SetRenderTarget(0, pRT);
+ hr = m_pD3DDev->SetPixelShader(NULL);
+ }
+
+ Vector dst[4];
+ Transform(rDstVid, dst);
+
+ DWORD iDX9Resizer = s.iDX9Resizer;
+
+ float A = 0;
+
+ switch(iDX9Resizer)
+ {
+ case 3:
+ A = -0.60f;
+ break;
+ case 4:
+ A = -0.751f;
+ break; // FIXME : 0.75 crash recent D3D, or eat CPU
+ case 5:
+ A = -1.00f;
+ break;
+ }
+ bool bScreenSpacePixelShaders = !m_pPixelShadersScreenSpace.IsEmpty();
+
+ hr = InitResizers(A, bScreenSpacePixelShaders);
+
+ if (!m_pScreenSizeTemporaryTexture[0] || !m_pScreenSizeTemporaryTexture[1])
+ bScreenSpacePixelShaders = false;
+
+ if (bScreenSpacePixelShaders)
+ {
+ CComPtr<IDirect3DSurface9> pRT;
+ hr = m_pScreenSizeTemporaryTexture[1]->GetSurfaceLevel(0, &pRT);
+ if (hr != S_OK)
+ bScreenSpacePixelShaders = false;
+ if (bScreenSpacePixelShaders)
+ {
+ hr = m_pD3DDev->SetRenderTarget(0, pRT);
+ if (hr != S_OK)
+ bScreenSpacePixelShaders = false;
+ hr = m_pD3DDev->Clear(0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0);
+ }
+ }
+
+ if(rSrcVid.Size() != rDstVid.Size())
+ {
+ if(iDX9Resizer == 0 || iDX9Resizer == 1)
+ {
+ D3DTEXTUREFILTERTYPE Filter = iDX9Resizer == 0 ? D3DTEXF_POINT : D3DTEXF_LINEAR;
+ hr = TextureResize(pVideoTexture, dst, Filter, rSrcVid);
+ }
+ else if(iDX9Resizer == 2)
+ {
+ hr = TextureResizeBilinear(pVideoTexture, dst, rSrcVid);
+ }
+ else if(iDX9Resizer >= 3)
+ {
+ hr = TextureResizeBicubic2pass(pVideoTexture, dst, rSrcVid);
+ }
+ }
+ else hr = TextureResize(pVideoTexture, dst, D3DTEXF_POINT, rSrcVid);
+
+ if (bScreenSpacePixelShaders)
+ {
+ static __int64 counter = 555;
+ static long start = clock() + 333;
+
+ long stop = clock() + 333;
+ 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)
+
+ D3DSURFACE_DESC desc;
+ m_pScreenSizeTemporaryTexture[0]->GetLevelDesc(0, &desc);
+
+ float fConstData[][4] =
+ {
+ {(float)desc.Width, (float)desc.Height, (float)(counter++), (float)diff / CLOCKS_PER_SEC},
+ {1.0f / desc.Width, 1.0f / desc.Height, 0, 0},
+ };
+
+ hr = m_pD3DDev->SetPixelShaderConstantF(0, (float*)fConstData, countof(fConstData));
+
+ int src = 1, dst = 0;
+
+ POSITION pos = m_pPixelShadersScreenSpace.GetHeadPosition();
+ while(pos)
+ {
+ if (m_pPixelShadersScreenSpace.GetTailPosition() == pos)
+ {
+ m_pD3DDev->SetRenderTarget(0, pBackBuffer);
+ }
+ else
+ {
+ CComPtr<IDirect3DSurface9> pRT;
+ hr = m_pScreenSizeTemporaryTexture[dst]->GetSurfaceLevel(0, &pRT);
+ m_pD3DDev->SetRenderTarget(0, pRT);
+ }
+
+ CExternalPixelShader &Shader = m_pPixelShadersScreenSpace.GetNext(pos);
+ if (!Shader.m_pPixelShader)
+ Shader.Compile(m_pPSC);
+ hr = m_pD3DDev->SetPixelShader(Shader.m_pPixelShader);
+ TextureCopy(m_pScreenSizeTemporaryTexture[src]);
+
+ swap(src, dst);
+ }
+
+ hr = m_pD3DDev->SetPixelShader(NULL);
+ }
+ }
+ else
+ {
+ if(pBackBuffer)
+ {
+ ClipToSurface(pBackBuffer, rSrcVid, rDstVid);
+ // 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[m_nCurSurface], rSrcVid, pBackBuffer, rDstVid, m_filter);
+ if(FAILED(hr)) return false;
+ }
+ }
+ }
+ AlphaBltSubPic(rSrcPri.Size());
+ if (m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_UPDATE)
+ {
+ CAutoLock BitMapLock(&m_VMR9AlphaBitmapLock);
+ CRect rcSrc (m_VMR9AlphaBitmap.rSrc);
+ m_pOSDTexture = NULL;
+ m_pOSDSurface = NULL;
+ if ((m_VMR9AlphaBitmap.dwFlags & VMRBITMAP_DISABLE) == 0 && (BYTE *)m_VMR9AlphaBitmapData)
+ {
+ if( (m_pD3DXLoadSurfaceFromMemory != NULL) &&
+ SUCCEEDED(hr = m_pD3DDev->CreateTexture(rcSrc.Width(), rcSrc.Height(), 1,
+ D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
+ D3DPOOL_DEFAULT, &m_pOSDTexture, NULL)) )
+ {
+ if (SUCCEEDED (hr = m_pOSDTexture->GetSurfaceLevel(0, &m_pOSDSurface)))
+ {
+ hr = m_pD3DXLoadSurfaceFromMemory (m_pOSDSurface, NULL, NULL, (BYTE *)m_VMR9AlphaBitmapData, D3DFMT_A8R8G8B8, m_VMR9AlphaBitmapWidthBytes,
+ NULL, &m_VMR9AlphaBitmapRect, D3DX_FILTER_NONE, m_VMR9AlphaBitmap.clrSrcKey);
+ }
+ if (FAILED (hr))
+ {
+ m_pOSDTexture = NULL;
+ m_pOSDSurface = NULL;
+ }
+ }
+ }
+ m_VMR9AlphaBitmap.dwFlags ^= VMRBITMAP_UPDATE;
+ }
+ if (pApp->m_fDisplayStats) DrawStats();
+ if (m_pOSDTexture) AlphaBlt(rSrcPri, rDstPri, m_pOSDTexture);
+ m_pD3DDev->EndScene();
+
+ if (m_pD3DDevEx)
+ {
+ if (m_bIsFullscreen)
+ hr = m_pD3DDevEx->PresentEx(NULL, NULL, NULL, NULL, NULL);
+ else
+ hr = m_pD3DDevEx->PresentEx(rSrcPri, rDstPri, NULL, NULL, NULL);
+ }
+ else
+ {
+ if (m_bIsFullscreen)
+ hr = m_pD3DDev->Present(NULL, NULL, NULL, NULL);
+ else
+ hr = m_pD3DDev->Present(rSrcPri, rDstPri, NULL, NULL);
+ }
+ if(FAILED(hr)) _tprintf(_T("Device lost or something\n"));
+ // Calculate timing statistics
+ if (m_pRefClock) m_pRefClock->GetTime(&llCurRefTime); // To check if we called Present too late to hit the right vsync
+ m_llEstVBlankTime = max(m_llEstVBlankTime, llCurRefTime); // Sometimes the real value is larger than the estimated value (but never smaller)
+ if (pApp->m_fDisplayStats < 3) // Partial on-screen statistics
+ SyncStats(m_llEstVBlankTime); // Max of estimate and real. Sometimes Present may actually return immediately so we need the estimate as a lower bound
+ if (pApp->m_fDisplayStats == 1) // Full on-screen statistics
+ SyncOffsetStats(-llSyncOffset); // Minus because we want time to flow downward in the graph in DrawStats
+
+ // Adjust sync
+ double frameCycle = (double)((m_llSampleTime - m_llLastSampleTime) / 10000.0);
+ if (frameCycle < 0) frameCycle = 0.0; // Happens when searching.
+
+ if (s.m_RenderSettings.bSynchronizeVideo) m_pGenlock->ControlClock(dSyncOffset, frameCycle);
+ else if (s.m_RenderSettings.bSynchronizeDisplay) m_pGenlock->ControlDisplay(dSyncOffset, frameCycle);
+ else m_pGenlock->UpdateStats(dSyncOffset, frameCycle); // No sync or sync to nearest neighbor
+
+ m_dFrameCycle = m_pGenlock->frameCycleAvg;
+ if (m_dFrameCycle > 0.0) m_fps = 1000.0 / m_dFrameCycle;
+ m_dCycleDifference = GetCycleDifference();
+ if (abs(m_dCycleDifference) < 0.05) // If less than 5% speed difference
+ m_bSnapToVSync = true;
+ else
+ m_bSnapToVSync = false;
+
+ // Check how well audio is matching rate (if at all)
+ DWORD tmp;
+ if (m_pAudioStats != NULL)
+ {
+ m_pAudioStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_ACCUMERROR, &m_lAudioLag, &tmp);
+ m_lAudioLagMin = min((long)m_lAudioLag, m_lAudioLagMin);
+ m_lAudioLagMax = max((long)m_lAudioLag, m_lAudioLagMax);
+ m_pAudioStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_MODE, &m_lAudioSlaveMode, &tmp);
+ }
+
+ if (pApp->m_bResetStats)
+ {
+ ResetStats();
+ pApp->m_bResetStats = false;
+ }
+
+ bool fResetDevice = m_bPendingResetDevice;
+ if(hr == D3DERR_DEVICELOST && m_pD3DDev->TestCooperativeLevel() == D3DERR_DEVICENOTRESET || hr == S_PRESENT_MODE_CHANGED)
+ fResetDevice = true;
+ if (SettingsNeedResetDevice())
+ fResetDevice = true;
+
+ BOOL bCompositionEnabled = false;
+ if (m_pDwmIsCompositionEnabled) m_pDwmIsCompositionEnabled(&bCompositionEnabled);
+ if ((bCompositionEnabled != 0) != m_bCompositionEnabled)
+ {
+ if (m_bIsFullscreen)
+ {
+ m_bCompositionEnabled = (bCompositionEnabled != 0);
+ }
+ else
+ fResetDevice = true;
+ }
+
+ if(s.fResetDevice)
+ {
+ LONGLONG time = GetRenderersData()->GetPerfCounter();
+ if (time > m_LastAdapterCheck + 20000000) // check every 2 sec.
+ {
+ m_LastAdapterCheck = time;
+#ifdef _DEBUG
+ D3DDEVICE_CREATION_PARAMETERS Parameters;
+ if(SUCCEEDED(m_pD3DDev->GetCreationParameters(&Parameters)))
+ {
+ ASSERT(Parameters.AdapterOrdinal == m_CurrentAdapter);
+ }
+#endif
+ if(m_CurrentAdapter != GetAdapter(m_pD3D))
+ {
+ fResetDevice = true;
+ }
+#ifdef _DEBUG
+ else
+ {
+ ASSERT(m_pD3D->GetAdapterMonitor(m_CurrentAdapter) == m_pD3D->GetAdapterMonitor(GetAdapter(m_pD3D)));
+ }
+#endif
+ }
+ }
+
+ if(fResetDevice)
+ {
+ m_bPendingResetDevice = true;
+ SendResetRequest();
+ }
+ return(true);
+}
+
+void CBaseAP::SendResetRequest()
+{
+ if (!m_bDeviceResetRequested)
+ {
+ m_bDeviceResetRequested = true;
+ AfxGetApp()->m_pMainWnd->PostMessage(WM_RESET_DEVICE);
+ }
+}
+
+STDMETHODIMP_(bool) CBaseAP::ResetDevice()
+{
+ DeleteSurfaces();
+ HRESULT hr;
+ CString Error;
+ if(FAILED(hr = CreateDXDevice(Error)) || FAILED(hr = AllocSurfaces()))
+ {
+ m_bDeviceResetRequested = false;
+ return false;
+ }
+ m_pGenlock->SetMonitor(GetAdapter(m_pD3D));
+ m_pGenlock->GetTiming();
+ OnResetDevice();
+ m_bDeviceResetRequested = false;
+ m_bPendingResetDevice = false;
+ return true;
+}
+
+void CBaseAP::DrawText(const RECT &rc, const CString &strText, int _Priority)
+{
+ if (_Priority < 1) return;
+ int Quality = 1;
+ D3DXCOLOR Color1(1.0f, 0.2f, 0.2f, 1.0f );
+ D3DXCOLOR Color0(0.0f, 0.0f, 0.0f, 1.0f );
+ RECT Rect1 = rc;
+ RECT Rect2 = rc;
+ if (Quality == 1)
+ OffsetRect(&Rect2 , 2, 2);
+ else
+ OffsetRect(&Rect2 , -1, -1);
+ if (Quality > 0)
+ m_pFont->DrawText(m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ OffsetRect (&Rect2 , 1, 0);
+ if (Quality > 3)
+ m_pFont->DrawText(m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ OffsetRect (&Rect2 , 1, 0);
+ if (Quality > 2)
+ m_pFont->DrawText(m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ OffsetRect (&Rect2 , 0, 1);
+ if (Quality > 3)
+ m_pFont->DrawText(m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ OffsetRect (&Rect2 , 0, 1);
+ if (Quality > 1)
+ m_pFont->DrawText(m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ OffsetRect (&Rect2 , -1, 0);
+ if (Quality > 3)
+ m_pFont->DrawText( m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ OffsetRect (&Rect2 , -1, 0);
+ if (Quality > 2)
+ m_pFont->DrawText(m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ OffsetRect (&Rect2 , 0, -1);
+ if (Quality > 3)
+ m_pFont->DrawText(m_pSprite, strText, -1, &Rect2, DT_NOCLIP, Color0);
+ m_pFont->DrawText( m_pSprite, strText, -1, &Rect1, DT_NOCLIP, Color1);
+}
+
+void CBaseAP::DrawStats()
+{
+ CRenderersSettings& s = GetRenderersSettings();
+ CRenderersData * pApp = GetRenderersData();
+
+ LONGLONG llMaxJitter = m_MaxJitter;
+ LONGLONG llMinJitter = m_MinJitter;
+ LONGLONG llMaxSyncOffset = m_MaxSyncOffset;
+ LONGLONG llMinSyncOffset = m_MinSyncOffset;
+
+ RECT rc = {20, 20, 520, 520 };
+ // pApp->m_fDisplayStats = 1 for full stats, 2 for little less, 3 for basic, 0 for no stats
+ if (m_pFont && m_pSprite)
+ {
+ m_pSprite->Begin(D3DXSPRITE_ALPHABLEND);
+ CString strText;
+ int TextHeight = 25.0*m_TextScale + 0.5;
+
+ strText.Format(L"Frames drawn from stream start: %d | Sample time stamp: %d ms", m_pcFramesDrawn, (LONG)(m_llSampleTime / 10000));
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+
+ if (pApp->m_fDisplayStats == 1)
+ {
+ strText.Format(L"Frame cycle: %.3f ms [%.3f ms, %.3f ms] | Frame rate: %.3f fps", m_dFrameCycle, m_pGenlock->minFrameCycle, m_pGenlock->maxFrameCycle, m_fps);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+
+ strText.Format(L"Measured closest match display cycle: %.3f ms | Measured base display cycle: %.3f ms", m_dOptimumDisplayCycle, m_dEstRefreshCycle);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+
+ strText.Format(L"Display cycle - frame cycle mismatch: %.3f %%", 100 * m_dCycleDifference);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+
+ strText.Format(L"Actual frame cycle: %+5.3f ms [%+.3f ms, %+.3f ms] | Actual frame rate: %.3f fps", m_fJitterMean / 10000.0, (double(llMinJitter)/10000.0), (double(llMaxJitter)/10000.0), 10000000.0 / m_fJitterMean);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+
+ strText.Format(L"Display cycle from Windows: %.3f ms | Display refresh rate from Windows: %d Hz", m_dD3DRefreshCycle, m_uD3DRefreshRate);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+
+ if (m_pGenlock->powerstripTimingExists)
+ {
+ strText.Format(L"Display cycle from Powerstrip: %.3f ms | Display refresh rate from Powerstrip: %.3f Hz", 1000.0 / m_pGenlock->curDisplayFreq, m_pGenlock->curDisplayFreq);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+ }
+
+ if ((m_caps.Caps & D3DCAPS_READ_SCANLINE) == 0)
+ {
+ strText.Format(L"Graphics device does not support scan line access. No sync is possible");
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+ }
+
+ strText.Format(L"Video resolution: %d x %d | Aspect ratio: %d x %d", m_NativeVideoSize.cx, m_NativeVideoSize.cy, m_AspectRatio.cx, m_AspectRatio.cy);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+
+ strText.Format(L"Display resolution: %d x %d", m_ScreenSize.cx, m_ScreenSize.cy);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+
+ if (s.m_RenderSettings.bSynchronizeDisplay || s.m_RenderSettings.bSynchronizeVideo)
+ {
+ if (s.m_RenderSettings.bSynchronizeDisplay && !m_pGenlock->PowerstripRunning())
+ {
+ strText.Format(L"PowerStrip is not running. No display sync is possible.");
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+ }
+ else
+ {
+ strText.Format(L"Sync adjustment: %d | # of adjustments: %d", m_pGenlock->adjDelta, (m_pGenlock->clockAdjustmentsMade + m_pGenlock->displayAdjustmentsMade) / 2);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+ }
+ }
+ }
+
+ strText.Format(L"Average sync offset: %3.1f ms [%.1f ms, %.1f ms] | Target sync offset: %3.1f ms", m_pGenlock->syncOffsetAvg, m_pGenlock->minSyncOffset, m_pGenlock->maxSyncOffset, s.m_RenderSettings.fTargetSyncOffset);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+
+ if (pApp->m_fDisplayStats < 3)
+ {
+ strText.Format(L"# of sync glitches: %d", m_uSyncGlitches);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+
+ strText.Format(L"# of frames dropped: %d", m_pcFramesDropped);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+ }
+
+ if (pApp->m_fDisplayStats == 1)
+ {
+ if (m_pAudioStats && s.m_RenderSettings.bSynchronizeVideo)
+ {
+ strText.Format(L"Audio lag: %3d ms [%d ms, %d ms] | %s", m_lAudioLag, m_lAudioLagMin, m_lAudioLagMax, (m_lAudioSlaveMode == 4) ? _T("Audio renderer is matching rate (for analog sound output)") : _T("Audio renderer is not matching rate"));
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+ }
+
+ strText.Format(L"Sample waiting time: %d ms", m_lNextSampleWait);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+ if (s.m_RenderSettings.bSynchronizeNearest)
+ {
+ strText.Format(L"Sample paint time correction: %2d ms | Hysteresis: %d", m_lShiftToNearest, m_llHysteresis /10000);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+ }
+
+ strText.Format(L"Buffered: %3d | Free: %3d | Current surface: %3d", m_nUsedBuffer, m_nDXSurface - m_nUsedBuffer, m_nCurSurface, m_nVMR9Surfaces, m_iVMR9Surface);
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+
+ strText.Format(L"Settings: ");
+
+ if (m_bIsFullscreen)
+ strText += "D3DFS ";
+ if (s.m_RenderSettings.iVMRDisableDesktopComposition)
+ strText += "DisDC ";
+ if (s.m_RenderSettings.bSynchronizeVideo)
+ strText += "SyncVideo ";
+ if (s.m_RenderSettings.bSynchronizeDisplay)
+ strText += "SyncDisplay ";
+ if (s.m_RenderSettings.bSynchronizeNearest)
+ strText += "SyncNearest ";
+ if (m_bHighColorResolution)
+ strText += "10 bit ";
+ if (s.m_RenderSettings.iEVROutputRange == 0)
+ strText += "0-255 ";
+ else if (s.m_RenderSettings.iEVROutputRange == 1)
+ strText += "16-235 ";
+
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+
+ strText.Format(L"%s: %s", GetDXVAVersion(), GetDXVADecoderDescription());
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+
+ strText.Format(L"DirectX SDK: %d", GetRenderersData()->GetDXSdkRelease());
+ DrawText(rc, strText, 1);
+ OffsetRect(&rc, 0, TextHeight);
+
+ for (int i=0; i<6; i++)
+ {
+ if (m_strStatsMsg[i][0])
+ {
+ DrawText(rc, m_strStatsMsg[i], 1);
+ OffsetRect(&rc, 0, TextHeight);
+ }
+ }
+ }
+ OffsetRect(&rc, 0, TextHeight); // Extra "line feed"
+ m_pSprite->End();
+ }
+
+ if (m_pLine && (pApp->m_fDisplayStats < 3))
+ {
+ D3DXVECTOR2 Points[NB_JITTER];
+ int nIndex;
+
+ int DrawWidth = 625;
+ int DrawHeight = 250;
+ int Alpha = 80;
+ int StartX = rc.left;
+ int StartY = rc.top;
+
+ DrawRect(RGB(0, 0, 0), Alpha, CRect(StartX, StartY, StartX + DrawWidth, StartY + DrawHeight));
+ m_pLine->SetWidth(2.5);
+ m_pLine->SetAntialias(1);
+ m_pLine->Begin();
+
+ for (int i = 0; i <= DrawHeight; i += 5)
+ {
+ Points[0].x = (FLOAT)StartX;
+ Points[0].y = (FLOAT)(StartY + i);
+ Points[1].x = (FLOAT)(StartX + ((i + 25) % 25 ? 50 : 625));
+ Points[1].y = (FLOAT)(StartY + i);
+ m_pLine->Draw(Points, 2, D3DCOLOR_XRGB(100, 100, 255));
+ }
+
+ for (int i = 0; i < DrawWidth; i += 125) // Every 25:th sample
+ {
+ Points[0].x = (FLOAT)(StartX + i);
+ Points[0].y = (FLOAT)(StartY + DrawHeight / 2);
+ Points[1].x = (FLOAT)(StartX + i);
+ Points[1].y = (FLOAT)(StartY + DrawHeight / 2 + 10);
+ m_pLine->Draw(Points, 2, D3DCOLOR_XRGB(100, 100, 255));
+ }
+
+ for (int i = 0; i < NB_JITTER; i++)
+ {
+ nIndex = (m_nNextJitter + 1 + i) % NB_JITTER;
+ if (nIndex < 0)
+ nIndex += NB_JITTER;
+ double Jitter = m_pllJitter[nIndex] - m_fJitterMean;
+ Points[i].x = (FLOAT)(StartX + (i * 5));
+ Points[i].y = (FLOAT)(StartY + (Jitter / 2000.0 + 125.0));
+ }
+ m_pLine->Draw(Points, NB_JITTER, D3DCOLOR_XRGB(255, 100, 100));
+
+ if (pApp->m_fDisplayStats == 1) // Full on-screen statistics
+ {
+ for (int i = 0; i < NB_JITTER; i++)
+ {
+ nIndex = (m_nNextSyncOffset + 1 + i) % NB_JITTER;
+ if (nIndex < 0)
+ nIndex += NB_JITTER;
+ Points[i].x = (FLOAT)(StartX + (i * 5));
+ Points[i].y = (FLOAT)(StartY + ((m_pllSyncOffset[nIndex]) / 2000 + 125));
+ }
+ m_pLine->Draw(Points, NB_JITTER, D3DCOLOR_XRGB(100, 200, 100));
+ }
+ m_pLine->End();
+ }
+}
+
+double CBaseAP::GetRefreshRate()
+{
+ if (m_pGenlock->powerstripTimingExists) return m_pGenlock->curDisplayFreq;
+ else return (double)m_uD3DRefreshRate;
+}
+
+double CBaseAP::GetDisplayCycle()
+{
+ if (m_pGenlock->powerstripTimingExists) return 1000.0 / m_pGenlock->curDisplayFreq;
+ else return (double)m_dD3DRefreshCycle;
+}
+
+double CBaseAP::GetCycleDifference()
+{
+ double dBaseDisplayCycle = GetDisplayCycle();
+ UINT i;
+ double minDiff = 1.0;
+ if (dBaseDisplayCycle == 0.0 || m_dFrameCycle == 0.0)
+ return 1.0;
+ else
+ {
+ for (i = 1; i <= 8; i++) // Try a lot of multiples of the display frequency
+ {
+ double dDisplayCycle = i * dBaseDisplayCycle;
+ double diff = (dDisplayCycle - m_dFrameCycle) / m_dFrameCycle;
+ if (abs(diff) < abs(minDiff))
+ {
+ minDiff = diff;
+ m_dOptimumDisplayCycle = dDisplayCycle;
+ }
+ }
+ }
+ return minDiff;
+}
+
+void CBaseAP::EstimateRefreshTimings()
+{
+ if (m_pD3DDev)
+ {
+ CRenderersData *pApp = GetRenderersData();
+ D3DRASTER_STATUS rasterStatus;
+ m_pD3DDev->GetRasterStatus(0, &rasterStatus);
+ while (rasterStatus.ScanLine != 0) m_pD3DDev->GetRasterStatus(0, &rasterStatus);
+ while (rasterStatus.ScanLine == 0) m_pD3DDev->GetRasterStatus(0, &rasterStatus);
+ m_pD3DDev->GetRasterStatus(0, &rasterStatus);
+ LONGLONG startTime = pApp->GetPerfCounter();
+ UINT startLine = rasterStatus.ScanLine;
+ LONGLONG endTime = 0;
+ LONGLONG time = 0;
+ UINT endLine = 0;
+ UINT line = 0;
+ bool done = false;
+ while (!done) // Estimate time for one scan line
+ {
+ m_pD3DDev->GetRasterStatus(0, &rasterStatus);
+ line = rasterStatus.ScanLine;
+ time = pApp->GetPerfCounter();
+ if (line > 0)
+ {
+ endLine = line;
+ endTime = time;
+ }
+ else
+ done = true;
+ }
+ m_dDetectedScanlineTime = (double)(endTime - startTime) / (double)((endLine - startLine) * 10000.0);
+
+ // Estimate the display refresh rate from the vsyncs
+ m_pD3DDev->GetRasterStatus(0, &rasterStatus);
+ while (rasterStatus.ScanLine != 0) m_pD3DDev->GetRasterStatus(0, &rasterStatus);
+ // Now we're at the start of a vsync
+ startTime = pApp->GetPerfCounter();
+ UINT i;
+ for (i = 1; i <= 50; i++)
+ {
+ m_pD3DDev->GetRasterStatus(0, &rasterStatus);
+ while (rasterStatus.ScanLine == 0) m_pD3DDev->GetRasterStatus(0, &rasterStatus);
+ while (rasterStatus.ScanLine != 0) m_pD3DDev->GetRasterStatus(0, &rasterStatus);
+ // Now we're at the next vsync
+ }
+ endTime = pApp->GetPerfCounter();
+ m_dEstRefreshCycle = (double)(endTime - startTime) / ((i - 1) * 10000.0);
+ }
+}
+
+bool CBaseAP::ExtractInterlaced(const AM_MEDIA_TYPE* pmt)
+{
+ if (pmt->formattype==FORMAT_VideoInfo)
+ return false;
+ else if (pmt->formattype==FORMAT_VideoInfo2)
+ return (((VIDEOINFOHEADER2*)pmt->pbFormat)->dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0;
+ else if (pmt->formattype==FORMAT_MPEGVideo)
+ return false;
+ else if (pmt->formattype==FORMAT_MPEG2Video)
+ return (((MPEG2VIDEOINFO*)pmt->pbFormat)->hdr.dwInterlaceFlags & AMINTERLACE_IsInterlaced) != 0;
+ else
+ return false;
+}
+
+STDMETHODIMP CBaseAP::GetDIB(BYTE* lpDib, DWORD* size)
+{
+ CheckPointer(size, E_POINTER);
+
+ HRESULT hr;
+
+ D3DSURFACE_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ m_pVideoSurface[m_nCurSurface]->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[m_nCurSurface];
+ 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[m_nCurSurface], 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 CBaseAP::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget)
+{
+ return SetPixelShader2(pSrcData, pTarget, false);
+}
+
+STDMETHODIMP CBaseAP::SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace)
+{
+ CAutoLock cRenderLock(&m_allocatorLock);
+
+ CAtlList<CExternalPixelShader> *pPixelShaders;
+ if (bScreenSpace)
+ pPixelShaders = &m_pPixelShadersScreenSpace;
+ else
+ pPixelShaders = &m_pPixelShaders;
+
+ if(!pSrcData && !pTarget)
+ {
+ pPixelShaders->RemoveAll();
+ m_pD3DDev->SetPixelShader(NULL);
+ return S_OK;
+ }
+
+ if(!pSrcData || !pTarget)
+ return E_INVALIDARG;
+
+ CExternalPixelShader Shader;
+ Shader.m_SourceData = pSrcData;
+ Shader.m_SourceTarget = pTarget;
+
+ CComPtr<IDirect3DPixelShader9> pPixelShader;
+
+ HRESULT hr = Shader.Compile(m_pPSC);
+ if(FAILED(hr))
+ return hr;
+
+ pPixelShaders->AddTail(Shader);
+ Paint(true);
+ return S_OK;
+}
+
+
+CSyncAP::CSyncAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString &_Error): CBaseAP(hWnd, bFullscreen, hr, _Error)
+{
+ HMODULE hLib;
+ CRenderersSettings& s = GetRenderersSettings();
+
+ m_nResetToken = 0;
+ m_hRenderThread = INVALID_HANDLE_VALUE;
+ m_hMixerThread= INVALID_HANDLE_VALUE;
+ m_hEvtFlush = INVALID_HANDLE_VALUE;
+ m_hEvtQuit = INVALID_HANDLE_VALUE;
+ m_hEvtSkip = INVALID_HANDLE_VALUE;
+ m_bEvtQuit = 0;
+ m_bEvtFlush = 0;
+
+ if (FAILED (hr))
+ {
+ _Error += L"SyncAP failed\n";
+ return;
+ }
+
+ // Load EVR specifics DLLs
+ hLib = LoadLibrary (L"dxva2.dll");
+ pfDXVA2CreateDirect3DDeviceManager9 = hLib ? (PTR_DXVA2CreateDirect3DDeviceManager9) GetProcAddress (hLib, "DXVA2CreateDirect3DDeviceManager9") : NULL;
+
+ // Load EVR functions
+ hLib = LoadLibrary (L"evr.dll");
+ pfMFCreateDXSurfaceBuffer = hLib ? (PTR_MFCreateDXSurfaceBuffer)GetProcAddress (hLib, "MFCreateDXSurfaceBuffer") : NULL;
+ pfMFCreateVideoSampleFromSurface = hLib ? (PTR_MFCreateVideoSampleFromSurface)GetProcAddress (hLib, "MFCreateVideoSampleFromSurface") : NULL;
+ pfMFCreateVideoMediaType = hLib ? (PTR_MFCreateVideoMediaType)GetProcAddress (hLib, "MFCreateVideoMediaType") : NULL;
+
+ if (!pfDXVA2CreateDirect3DDeviceManager9 || !pfMFCreateDXSurfaceBuffer || !pfMFCreateVideoSampleFromSurface || !pfMFCreateVideoMediaType)
+ {
+ if (!pfDXVA2CreateDirect3DDeviceManager9)
+ _Error += L"Could not find DXVA2CreateDirect3DDeviceManager9 (dxva2.dll)\n";
+ if (!pfMFCreateDXSurfaceBuffer)
+ _Error += L"Could not find MFCreateDXSurfaceBuffer (evr.dll)\n";
+ if (!pfMFCreateVideoSampleFromSurface)
+ _Error += L"Could not find MFCreateVideoSampleFromSurface (evr.dll)\n";
+ if (!pfMFCreateVideoMediaType)
+ _Error += L"Could not find MFCreateVideoMediaType (evr.dll)\n";
+ hr = E_FAIL;
+ return;
+ }
+
+ // Load Vista specific DLLs
+ hLib = LoadLibrary (L"avrt.dll");
+ pfAvSetMmThreadCharacteristicsW = hLib ? (PTR_AvSetMmThreadCharacteristicsW) GetProcAddress (hLib, "AvSetMmThreadCharacteristicsW") : NULL;
+ pfAvSetMmThreadPriority = hLib ? (PTR_AvSetMmThreadPriority) GetProcAddress (hLib, "AvSetMmThreadPriority") : NULL;
+ pfAvRevertMmThreadCharacteristics = hLib ? (PTR_AvRevertMmThreadCharacteristics) GetProcAddress (hLib, "AvRevertMmThreadCharacteristics") : NULL;
+
+ // Init DXVA manager
+ hr = pfDXVA2CreateDirect3DDeviceManager9(&m_nResetToken, &m_pD3DManager);
+ if (SUCCEEDED (hr))
+ {
+ hr = m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken);
+ if (!SUCCEEDED (hr))
+ {
+ _Error += L"m_pD3DManager->ResetDevice failed\n";
+ }
+ }
+ else
+ _Error += L"DXVA2CreateDirect3DDeviceManager9 failed\n";
+
+ CComPtr<IDirectXVideoDecoderService> pDecoderService;
+ HANDLE hDevice;
+ if (SUCCEEDED (m_pD3DManager->OpenDeviceHandle(&hDevice)) &&
+ SUCCEEDED (m_pD3DManager->GetVideoService (hDevice, __uuidof(IDirectXVideoDecoderService), (void**)&pDecoderService)))
+ {
+ HookDirectXVideoDecoderService (pDecoderService);
+ m_pD3DManager->CloseDeviceHandle (hDevice);
+ }
+
+ // Bufferize frame only with 3D texture
+ if (s.iAPSurfaceUsage == VIDRNDT_AP_TEXTURE3D)
+ m_nDXSurface = max(min (s.iEvrBuffers, MAX_PICTURE_SLOTS-2), 4);
+ else
+ m_nDXSurface = 1;
+
+ m_nRenderState = Shutdown;
+ m_bStepping = false;
+ m_bUseInternalTimer = false;
+ m_LastSetOutputRange = -1;
+ m_bPendingRenegotiate = false;
+ m_bPendingMediaFinished = false;
+ m_pCurrentDisplaydSample = NULL;
+ m_nStepCount = 0;
+ m_dwVideoAspectRatioMode = MFVideoARMode_PreservePicture;
+ m_dwVideoRenderPrefs = (MFVideoRenderPrefs)0;
+ m_BorderColor = RGB (0,0,0);
+ m_pOuterEVR = NULL;
+ m_bPrerolled = false;
+ m_lShiftToNearest = -1; // Illegal value to start with
+}
+
+CSyncAP::~CSyncAP(void)
+{
+ StopWorkerThreads();
+ m_pMediaType = NULL;
+ m_pClock = NULL;
+ m_pD3DManager = NULL;
+}
+
+HRESULT CSyncAP::CheckShutdown() const
+{
+ if (m_nRenderState == Shutdown) return MF_E_SHUTDOWN;
+ else return S_OK;
+}
+
+void CSyncAP::StartWorkerThreads()
+{
+ DWORD dwThreadId;
+ if (m_nRenderState == Shutdown)
+ {
+ m_hEvtQuit = CreateEvent(NULL, TRUE, FALSE, NULL);
+ m_hEvtFlush = CreateEvent(NULL, TRUE, FALSE, NULL);
+ m_hEvtSkip = CreateEvent(NULL, TRUE, FALSE, NULL);
+ m_hMixerThread = ::CreateThread(NULL, 0, MixerThreadStatic, (LPVOID)this, 0, &dwThreadId);
+ SetThreadPriority(m_hMixerThread, THREAD_PRIORITY_HIGHEST);
+ m_hRenderThread = ::CreateThread(NULL, 0, RenderThreadStatic, (LPVOID)this, 0, &dwThreadId);
+ SetThreadPriority(m_hRenderThread, THREAD_PRIORITY_TIME_CRITICAL);
+ m_nRenderState = Stopped;
+ }
+}
+
+void CSyncAP::StopWorkerThreads()
+{
+ if (m_nRenderState != Shutdown)
+ {
+ SetEvent(m_hEvtFlush);
+ m_bEvtFlush = true;
+ SetEvent(m_hEvtQuit);
+ m_bEvtQuit = true;
+ SetEvent(m_hEvtSkip);
+ m_bEvtSkip = true;
+ if ((m_hRenderThread != INVALID_HANDLE_VALUE) && (WaitForSingleObject (m_hRenderThread, 10000) == WAIT_TIMEOUT))
+ {
+ ASSERT (FALSE);
+ TerminateThread (m_hRenderThread, 0xDEAD);
+ }
+ if (m_hRenderThread != INVALID_HANDLE_VALUE) CloseHandle (m_hRenderThread);
+ if ((m_hMixerThread != INVALID_HANDLE_VALUE) && (WaitForSingleObject (m_hMixerThread, 10000) == WAIT_TIMEOUT))
+ {
+ ASSERT (FALSE);
+ TerminateThread (m_hMixerThread, 0xDEAD);
+ }
+ if (m_hMixerThread != INVALID_HANDLE_VALUE) CloseHandle (m_hMixerThread);
+
+ if (m_hEvtFlush != INVALID_HANDLE_VALUE) CloseHandle(m_hEvtFlush);
+ if (m_hEvtQuit != INVALID_HANDLE_VALUE) CloseHandle(m_hEvtQuit);
+ if (m_hEvtSkip != INVALID_HANDLE_VALUE) CloseHandle(m_hEvtSkip);
+
+ m_bEvtFlush = false;
+ m_bEvtQuit = false;
+ m_bEvtSkip = false;
+ }
+ m_nRenderState = Shutdown;
+}
+
+STDMETHODIMP CSyncAP::CreateRenderer(IUnknown** ppRenderer)
+{
+ CheckPointer(ppRenderer, E_POINTER);
+ *ppRenderer = NULL;
+ HRESULT hr = E_FAIL;
+
+ do
+ {
+ CMacrovisionKicker* pMK = DNew CMacrovisionKicker(NAME("CMacrovisionKicker"), NULL);
+ CComPtr<IUnknown> pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK;
+
+ CSyncRenderer *pOuterEVR = DNew CSyncRenderer(NAME("CSyncRenderer"), pUnk, hr, &m_VMR9AlphaBitmap, this);
+ m_pOuterEVR = pOuterEVR;
+
+ pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuterEVR);
+ CComQIPtr<IBaseFilter> pBF = pUnk;
+
+ if (FAILED(hr)) break;
+
+ // Set EVR custom presenter
+ CComPtr<IMFVideoPresenter> pVP;
+ CComPtr<IMFVideoRenderer> pMFVR;
+ CComQIPtr<IMFGetService, &__uuidof(IMFGetService)> pMFGS = pBF;
+
+ hr = pMFGS->GetService (MR_VIDEO_RENDER_SERVICE, IID_IMFVideoRenderer, (void**)&pMFVR);
+
+ if(SUCCEEDED(hr)) hr = QueryInterface(__uuidof(IMFVideoPresenter), (void**)&pVP);
+ if(SUCCEEDED(hr)) hr = pMFVR->InitializeRenderer(NULL, pVP);
+
+ CComPtr<IPin> pPin = GetFirstPin(pBF);
+ CComQIPtr<IMemInputPin> pMemInputPin = pPin;
+
+ m_bUseInternalTimer = HookNewSegmentAndReceive((IPinC*)(IPin*)pPin, (IMemInputPinC*)(IMemInputPin*)pMemInputPin);
+ if(FAILED(hr))
+ *ppRenderer = NULL;
+ else
+ *ppRenderer = pBF.Detach();
+ }
+ while (0);
+
+ return hr;
+}
+
+STDMETHODIMP_(bool) CSyncAP::Paint(bool fAll)
+{
+ return __super::Paint(fAll);
+}
+
+STDMETHODIMP CSyncAP::NonDelegatingQueryInterface(REFIID riid, void** ppv)
+{
+ HRESULT hr;
+ if(riid == __uuidof(IMFClockStateSink))
+ hr = GetInterface((IMFClockStateSink*)this, ppv);
+ else if(riid == __uuidof(IMFVideoPresenter))
+ hr = GetInterface((IMFVideoPresenter*)this, ppv);
+ else if(riid == __uuidof(IMFTopologyServiceLookupClient))
+ hr = GetInterface((IMFTopologyServiceLookupClient*)this, ppv);
+ else if(riid == __uuidof(IMFVideoDeviceID))
+ hr = GetInterface((IMFVideoDeviceID*)this, ppv);
+ else if(riid == __uuidof(IMFGetService))
+ hr = GetInterface((IMFGetService*)this, ppv);
+ else if(riid == __uuidof(IMFAsyncCallback))
+ hr = GetInterface((IMFAsyncCallback*)this, ppv);
+ else if(riid == __uuidof(IMFVideoDisplayControl))
+ hr = GetInterface((IMFVideoDisplayControl*)this, ppv);
+ else if(riid == __uuidof(IEVRTrustedVideoPlugin))
+ hr = GetInterface((IEVRTrustedVideoPlugin*)this, ppv);
+ else if(riid == IID_IQualProp)
+ hr = GetInterface((IQualProp*)this, ppv);
+ else if(riid == __uuidof(IMFRateSupport))
+ hr = GetInterface((IMFRateSupport*)this, ppv);
+ else if(riid == __uuidof(IDirect3DDeviceManager9))
+ hr = m_pD3DManager->QueryInterface (__uuidof(IDirect3DDeviceManager9), (void**) ppv);
+ else if(riid == __uuidof(ISyncClockAdviser))
+ hr = GetInterface((ISyncClockAdviser*)this, ppv);
+ else
+ hr = __super::NonDelegatingQueryInterface(riid, ppv);
+
+ return hr;
+}
+
+// IMFClockStateSink
+STDMETHODIMP CSyncAP::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset)
+{
+ m_nRenderState = Started;
+ return S_OK;
+}
+
+STDMETHODIMP CSyncAP::OnClockStop(MFTIME hnsSystemTime)
+{
+ m_nRenderState = Stopped;
+ return S_OK;
+}
+
+STDMETHODIMP CSyncAP::OnClockPause(MFTIME hnsSystemTime)
+{
+ m_nRenderState = Paused;
+ return S_OK;
+}
+
+STDMETHODIMP CSyncAP::OnClockRestart(MFTIME hnsSystemTime)
+{
+ m_nRenderState = Started;
+ return S_OK;
+}
+
+STDMETHODIMP CSyncAP::OnClockSetRate(MFTIME hnsSystemTime, float flRate)
+{
+ return E_NOTIMPL;
+}
+
+// IBaseFilter delegate
+bool CSyncAP::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *State, HRESULT &_ReturnValue)
+{
+ CAutoLock lock(&m_SampleQueueLock);
+ switch(m_nRenderState)
+ {
+ case Started:
+ *State = State_Running;
+ break;
+ case Paused:
+ *State = State_Paused;
+ break;
+ case Stopped:
+ *State = State_Stopped;
+ break;
+ default:
+ *State = State_Stopped;
+ _ReturnValue = E_FAIL;
+ }
+ _ReturnValue = S_OK;
+ return true;
+}
+
+// IQualProp
+STDMETHODIMP CSyncAP::get_FramesDroppedInRenderer(int *pcFrames)
+{
+ *pcFrames = m_pcFramesDropped;
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::get_FramesDrawn(int *pcFramesDrawn)
+{
+ *pcFramesDrawn = m_pcFramesDrawn;
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::get_AvgFrameRate(int *piAvgFrameRate)
+{
+ *piAvgFrameRate = (int)(m_fAvrFps * 100);
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::get_Jitter(int *iJitter)
+{
+ *iJitter = (int)((m_fJitterStdDev/10000.0) + 0.5);
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::get_AvgSyncOffset(int *piAvg)
+{
+ *piAvg = (int)((m_fSyncOffsetAvr/10000.0) + 0.5);
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::get_DevSyncOffset(int *piDev)
+{
+ *piDev = (int)((m_fSyncOffsetStdDev/10000.0) + 0.5);
+ return S_OK;
+}
+
+// IMFRateSupport
+STDMETHODIMP CSyncAP::GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float *pflRate)
+{
+ *pflRate = 0;
+ return S_OK;
+}
+
+STDMETHODIMP CSyncAP::GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float *pflRate)
+{
+ HRESULT hr = S_OK;
+ float fMaxRate = 0.0f;
+
+ CAutoLock lock(this);
+
+ CheckPointer(pflRate, E_POINTER);
+ CheckHR(CheckShutdown());
+
+ // Get the maximum forward rate.
+ fMaxRate = GetMaxRate(fThin);
+
+ // For reverse playback, swap the sign.
+ if (eDirection == MFRATE_REVERSE)
+ fMaxRate = -fMaxRate;
+
+ *pflRate = fMaxRate;
+ return hr;
+}
+
+STDMETHODIMP CSyncAP::IsRateSupported(BOOL fThin, float flRate, float *pflNearestSupportedRate)
+{
+ // fRate can be negative for reverse playback.
+ // pfNearestSupportedRate can be NULL.
+ CAutoLock lock(this);
+ HRESULT hr = S_OK;
+ float fMaxRate = 0.0f;
+ float fNearestRate = flRate; // Default.
+
+ CheckPointer (pflNearestSupportedRate, E_POINTER);
+ CheckHR(hr = CheckShutdown());
+
+ // Find the maximum forward rate.
+ fMaxRate = GetMaxRate(fThin);
+
+ if (fabsf(flRate) > fMaxRate)
+ {
+ // The (absolute) requested rate exceeds the maximum rate.
+ hr = MF_E_UNSUPPORTED_RATE;
+
+ // The nearest supported rate is fMaxRate.
+ fNearestRate = fMaxRate;
+ if (flRate < 0)
+ {
+ // For reverse playback, swap the sign.
+ fNearestRate = -fNearestRate;
+ }
+ }
+ // Return the nearest supported rate if the caller requested it.
+ if (pflNearestSupportedRate != NULL) *pflNearestSupportedRate = fNearestRate;
+ return hr;
+}
+
+float CSyncAP::GetMaxRate(BOOL bThin)
+{
+ float fMaxRate = FLT_MAX; // Default.
+ UINT32 fpsNumerator = 0, fpsDenominator = 0;
+ UINT MonitorRateHz = 0;
+
+ if (!bThin && (m_pMediaType != NULL))
+ {
+ // Non-thinned: Use the frame rate and monitor refresh rate.
+
+ // Frame rate:
+ MFGetAttributeRatio(m_pMediaType, MF_MT_FRAME_RATE,
+ &fpsNumerator, &fpsDenominator);
+
+ // Monitor refresh rate:
+ MonitorRateHz = m_uD3DRefreshRate; // D3DDISPLAYMODE
+
+ if (fpsDenominator && fpsNumerator && MonitorRateHz)
+ {
+ // Max Rate = Refresh Rate / Frame Rate
+ fMaxRate = (float)MulDiv(MonitorRateHz, fpsDenominator, fpsNumerator);
+ }
+ }
+ return fMaxRate;
+}
+
+void CSyncAP::CompleteFrameStep(bool bCancel)
+{
+ if (m_nStepCount > 0)
+ {
+ if (bCancel || (m_nStepCount == 1))
+ {
+ m_pSink->Notify(EC_STEP_COMPLETE, bCancel ? TRUE : FALSE, 0);
+ m_nStepCount = 0;
+ }
+ else
+ m_nStepCount--;
+ }
+}
+
+// IMFVideoPresenter
+STDMETHODIMP CSyncAP::ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam)
+{
+ HRESULT hr = S_OK;
+ CRenderersSettings& s = GetRenderersSettings();
+
+ switch (eMessage)
+ {
+ case MFVP_MESSAGE_BEGINSTREAMING:
+ hr = BeginStreaming();
+ m_llHysteresis = 0;
+ m_lShiftToNearest = 0;
+ m_bStepping = false;
+ break;
+
+ case MFVP_MESSAGE_CANCELSTEP:
+ m_bStepping = false;
+ CompleteFrameStep(true);
+ break;
+
+ case MFVP_MESSAGE_ENDOFSTREAM:
+ m_bPendingMediaFinished = true;
+ break;
+
+ case MFVP_MESSAGE_ENDSTREAMING:
+ m_pGenlock->ResetTiming();
+ m_pRefClock = NULL;
+ break;
+
+ case MFVP_MESSAGE_FLUSH:
+ SetEvent(m_hEvtFlush);
+ m_bEvtFlush = true;
+ while (WaitForSingleObject(m_hEvtFlush, 1) == WAIT_OBJECT_0);
+ break;
+
+ case MFVP_MESSAGE_INVALIDATEMEDIATYPE:
+ m_bPendingRenegotiate = true;
+ while (*((volatile bool *)&m_bPendingRenegotiate)) Sleep(1);
+ break;
+
+ case MFVP_MESSAGE_PROCESSINPUTNOTIFY:
+ break;
+
+ case MFVP_MESSAGE_STEP:
+ m_nStepCount = ulParam;
+ m_bStepping = true;
+ break;
+
+ default :
+ ASSERT(FALSE);
+ break;
+ }
+ return hr;
+}
+
+HRESULT CSyncAP::IsMediaTypeSupported(IMFMediaType* pMixerType)
+{
+ HRESULT hr;
+ AM_MEDIA_TYPE* pAMMedia;
+ UINT nInterlaceMode;
+
+ CheckHR (pMixerType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia));
+ CheckHR (pMixerType->GetUINT32 (MF_MT_INTERLACE_MODE, &nInterlaceMode));
+
+ if ( (pAMMedia->majortype != MEDIATYPE_Video)) hr = MF_E_INVALIDMEDIATYPE;
+ pMixerType->FreeRepresentation(FORMAT_VideoInfo2, (void*)pAMMedia);
+ return hr;
+}
+
+HRESULT CSyncAP::CreateProposedOutputType(IMFMediaType* pMixerType, IMFMediaType** pType)
+{
+ HRESULT hr;
+ AM_MEDIA_TYPE *pAMMedia = NULL;
+ LARGE_INTEGER i64Size;
+ MFVIDEOFORMAT *VideoFormat;
+
+ CheckHR(pMixerType->GetRepresentation(FORMAT_MFVideoFormat, (void**)&pAMMedia));
+
+ VideoFormat = (MFVIDEOFORMAT*)pAMMedia->pbFormat;
+ hr = pfMFCreateVideoMediaType(VideoFormat, &m_pMediaType);
+
+ m_AspectRatio.cx = VideoFormat->videoInfo.PixelAspectRatio.Numerator;
+ m_AspectRatio.cy = VideoFormat->videoInfo.PixelAspectRatio.Denominator;
+
+ if (SUCCEEDED (hr))
+ {
+ i64Size.HighPart = VideoFormat->videoInfo.dwWidth;
+ i64Size.LowPart = VideoFormat->videoInfo.dwHeight;
+ m_pMediaType->SetUINT64(MF_MT_FRAME_SIZE, i64Size.QuadPart);
+ m_pMediaType->SetUINT32(MF_MT_PAN_SCAN_ENABLED, 0);
+ CRenderersSettings& s = GetRenderersSettings();
+
+ if (s.m_RenderSettings.iEVROutputRange == 1)
+ m_pMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_16_235);
+ else
+ m_pMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_0_255);
+
+ m_LastSetOutputRange = s.m_RenderSettings.iEVROutputRange;
+ i64Size.HighPart = m_AspectRatio.cx;
+ i64Size.LowPart = m_AspectRatio.cy;
+ m_pMediaType->SetUINT64(MF_MT_PIXEL_ASPECT_RATIO, i64Size.QuadPart);
+
+ MFVideoArea Area = GetArea(0, 0, VideoFormat->videoInfo.dwWidth, VideoFormat->videoInfo.dwHeight);
+ m_pMediaType->SetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&Area, sizeof(MFVideoArea));
+ }
+
+ m_AspectRatio.cx *= VideoFormat->videoInfo.dwWidth;
+ m_AspectRatio.cy *= VideoFormat->videoInfo.dwHeight;
+
+ bool bDoneSomething = true;
+
+ if(m_AspectRatio.cx >= 1 && m_AspectRatio.cy >= 1)
+ {
+ while (bDoneSomething)
+ {
+ bDoneSomething = false;
+ INT MinNum = min(m_AspectRatio.cx, m_AspectRatio.cy);
+ INT i;
+ for (i = 2; i < MinNum+1; ++i)
+ {
+ if (m_AspectRatio.cx%i == 0 && m_AspectRatio.cy%i ==0)
+ break;
+ }
+ if (i != MinNum + 1)
+ {
+ m_AspectRatio.cx = m_AspectRatio.cx / i;
+ m_AspectRatio.cy = m_AspectRatio.cy / i;
+ bDoneSomething = true;
+ }
+ }
+ }
+
+ pMixerType->FreeRepresentation(FORMAT_MFVideoFormat, (void*)pAMMedia);
+ m_pMediaType->QueryInterface(__uuidof(IMFMediaType), (void**) pType);
+
+ return hr;
+}
+
+HRESULT CSyncAP::SetMediaType(IMFMediaType* pType)
+{
+ HRESULT hr;
+ AM_MEDIA_TYPE* pAMMedia = NULL;
+ CString strTemp;
+
+ CheckPointer(pType, E_POINTER);
+ CheckHR(pType->GetRepresentation(FORMAT_VideoInfo2, (void**)&pAMMedia));
+
+ hr = InitializeDevice(pAMMedia);
+ if (SUCCEEDED(hr))
+ {
+ strTemp = GetMediaTypeName(pAMMedia->subtype);
+ strTemp.Replace(L"MEDIASUBTYPE_", L"");
+ m_strStatsMsg[MSG_MIXEROUT].Format (L"Mixer output: %s", strTemp);
+ }
+
+ pType->FreeRepresentation(FORMAT_VideoInfo2, (void*)pAMMedia);
+
+ return hr;
+}
+
+typedef struct
+{
+ const int Format;
+ const LPCTSTR Description;
+} D3DFORMAT_TYPE;
+
+LONGLONG CSyncAP::GetMediaTypeMerit(IMFMediaType *pMediaType)
+{
+ AM_MEDIA_TYPE *pAMMedia = NULL;
+ MFVIDEOFORMAT *VideoFormat;
+
+ HRESULT hr;
+ CheckHR(pMediaType->GetRepresentation (FORMAT_MFVideoFormat, (void**)&pAMMedia));
+ VideoFormat = (MFVIDEOFORMAT*)pAMMedia->pbFormat;
+
+ LONGLONG Merit = 0;
+ switch (VideoFormat->surfaceInfo.Format)
+ {
+ case FCC('NV12'):
+ Merit = 90000000;
+ break;
+ case FCC('YV12'):
+ Merit = 80000000;
+ break;
+ case FCC('YUY2'):
+ Merit = 70000000;
+ break;
+ case FCC('UYVY'):
+ Merit = 60000000;
+ break;
+
+ case D3DFMT_X8R8G8B8: // Never opt for RGB
+ case D3DFMT_A8R8G8B8:
+ case D3DFMT_R8G8B8:
+ case D3DFMT_R5G6B5:
+ Merit = 0;
+ break;
+ default:
+ Merit = 1000;
+ break;
+ }
+ pMediaType->FreeRepresentation(FORMAT_MFVideoFormat, (void*)pAMMedia);
+ return Merit;
+}
+
+HRESULT CSyncAP::RenegotiateMediaType()
+{
+ HRESULT hr = S_OK;
+
+ CComPtr<IMFMediaType> pMixerType;
+ CComPtr<IMFMediaType> pType;
+
+ if (!m_pMixer) return MF_E_INVALIDREQUEST;
+
+ CInterfaceArray<IMFMediaType> ValidMixerTypes;
+ // Loop through all of the mixer's proposed output types.
+ DWORD iTypeIndex = 0;
+ while ((hr != MF_E_NO_MORE_TYPES))
+ {
+ pMixerType = NULL;
+ pType = NULL;
+ m_pMediaType = NULL;
+
+ // Step 1. Get the next media type supported by mixer.
+ hr = m_pMixer->GetOutputAvailableType(0, iTypeIndex++, &pMixerType);
+ if (FAILED(hr))
+ {
+ break;
+ }
+ // Step 2. Check if we support this media type.
+ if (SUCCEEDED(hr))
+ hr = IsMediaTypeSupported(pMixerType);
+ if (SUCCEEDED(hr))
+ hr = CreateProposedOutputType(pMixerType, &pType);
+ // Step 4. Check if the mixer will accept this media type.
+ if (SUCCEEDED(hr))
+ hr = m_pMixer->SetOutputType(0, pType, MFT_SET_TYPE_TEST_ONLY);
+ if (SUCCEEDED(hr))
+ {
+ LONGLONG Merit = GetMediaTypeMerit(pType);
+
+ int nTypes = ValidMixerTypes.GetCount();
+ int iInsertPos = 0;
+ for (int i = 0; i < nTypes; ++i)
+ {
+ LONGLONG ThisMerit = GetMediaTypeMerit(ValidMixerTypes[i]);
+ if (Merit > ThisMerit)
+ {
+ iInsertPos = i;
+ break;
+ }
+ else
+ iInsertPos = i+1;
+ }
+ ValidMixerTypes.InsertAt(iInsertPos, pType);
+ }
+ }
+
+ int nValidTypes = ValidMixerTypes.GetCount();
+ for (int i = 0; i < nValidTypes; ++i)
+ {
+ pType = ValidMixerTypes[i];
+ }
+
+ for (int i = 0; i < nValidTypes; ++i)
+ {
+ pType = ValidMixerTypes[i];
+ hr = SetMediaType(pType);
+ if (SUCCEEDED(hr))
+ {
+ hr = m_pMixer->SetOutputType(0, pType, 0);
+ // If something went wrong, clear the media type.
+ if (FAILED(hr))
+ {
+ SetMediaType(NULL);
+ }
+ else
+ break;
+ }
+ }
+
+ pMixerType = NULL;
+ pType = NULL;
+ return hr;
+}
+
+bool CSyncAP::GetSampleFromMixer()
+{
+ MFT_OUTPUT_DATA_BUFFER Buffer;
+ HRESULT hr = S_OK;
+ DWORD dwStatus;
+ LONGLONG llClockBefore = 0;
+ LONGLONG llClockAfter = 0;
+ LONGLONG llMixerLatency;
+
+ UINT dwSurface;
+ bool newSample = false;
+
+ while(SUCCEEDED(hr)) // Get as many frames as there are and that we have samples for
+ {
+ CComPtr<IMFSample> pSample;
+ CComPtr<IMFSample> pNewSample;
+ if (FAILED(GetFreeSample(&pSample))) // All samples are taken for the moment. Better luck next time
+ {
+ break;
+ }
+
+ memset(&Buffer, 0, sizeof(Buffer));
+ Buffer.pSample = pSample;
+ pSample->GetUINT32(GUID_SURFACE_INDEX, &dwSurface);
+ {
+ llClockBefore = GetRenderersData()->GetPerfCounter();
+ hr = m_pMixer->ProcessOutput(0 , 1, &Buffer, &dwStatus);
+ llClockAfter = GetRenderersData()->GetPerfCounter();
+ }
+
+ if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) // There are no samples left in the mixer
+ {
+ MoveToFreeList(pSample, false);
+ break;
+ }
+ if (m_pSink)
+ {
+ llMixerLatency = llClockAfter - llClockBefore;
+ m_pSink->Notify (EC_PROCESSING_LATENCY, (LONG_PTR)&llMixerLatency, 0);
+ }
+
+ newSample = true;
+
+ if (GetRenderersData()->m_fTearingTest)
+ {
+ RECT rcTearing;
+
+ rcTearing.left = m_nTearingPos;
+ rcTearing.top = 0;
+ rcTearing.right = rcTearing.left + 4;
+ rcTearing.bottom = m_NativeVideoSize.cy;
+ m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB (255,255,0,0));
+
+ rcTearing.left = (rcTearing.right + 15) % m_NativeVideoSize.cx;
+ rcTearing.right = rcTearing.left + 4;
+ m_pD3DDev->ColorFill(m_pVideoSurface[dwSurface], &rcTearing, D3DCOLOR_ARGB (255,255,0,0));
+ m_nTearingPos = (m_nTearingPos + 7) % m_NativeVideoSize.cx;
+ }
+ MoveToScheduledList(pSample, false); // Schedule, then go back to see if there is more where that came from
+ }
+ return newSample;
+}
+
+STDMETHODIMP CSyncAP::GetCurrentMediaType(__deref_out IMFVideoMediaType **ppMediaType)
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(this);
+ CheckPointer(ppMediaType, E_POINTER);
+ CheckHR(CheckShutdown());
+
+ if (m_pMediaType == NULL)
+ CheckHR(MF_E_NOT_INITIALIZED);
+
+ CheckHR(m_pMediaType->QueryInterface(__uuidof(IMFVideoMediaType), (void**)&ppMediaType));
+ return hr;
+}
+
+// IMFTopologyServiceLookupClient
+STDMETHODIMP CSyncAP::InitServicePointers(__in IMFTopologyServiceLookup *pLookup)
+{
+ HRESULT hr;
+ DWORD dwObjects = 1;
+ hr = pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_MIXER_SERVICE, __uuidof (IMFTransform), (void**)&m_pMixer, &dwObjects);
+ hr = pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, __uuidof (IMediaEventSink ), (void**)&m_pSink, &dwObjects);
+ hr = pLookup->LookupService(MF_SERVICE_LOOKUP_GLOBAL, 0, MR_VIDEO_RENDER_SERVICE, __uuidof (IMFClock ), (void**)&m_pClock, &dwObjects);
+ StartWorkerThreads();
+ return S_OK;
+}
+
+STDMETHODIMP CSyncAP::ReleaseServicePointers()
+{
+ StopWorkerThreads();
+ m_pMixer = NULL;
+ m_pSink = NULL;
+ m_pClock = NULL;
+ return S_OK;
+}
+
+// IMFVideoDeviceID
+STDMETHODIMP CSyncAP::GetDeviceID( __out IID *pDeviceID)
+{
+ CheckPointer(pDeviceID, E_POINTER);
+ *pDeviceID = IID_IDirect3DDevice9;
+ return S_OK;
+}
+
+// IMFGetService
+STDMETHODIMP CSyncAP::GetService( __RPC__in REFGUID guidService, __RPC__in REFIID riid, __RPC__deref_out_opt LPVOID *ppvObject)
+{
+ if (guidService == MR_VIDEO_RENDER_SERVICE)
+ return NonDelegatingQueryInterface (riid, ppvObject);
+ else if (guidService == MR_VIDEO_ACCELERATION_SERVICE)
+ return m_pD3DManager->QueryInterface (__uuidof(IDirect3DDeviceManager9), (void**) ppvObject);
+
+ return E_NOINTERFACE;
+}
+
+
+// IMFAsyncCallback
+STDMETHODIMP CSyncAP::GetParameters( __RPC__out DWORD *pdwFlags, __RPC__out DWORD *pdwQueue)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CSyncAP::Invoke( __RPC__in_opt IMFAsyncResult *pAsyncResult)
+{
+ return E_NOTIMPL;
+}
+
+// IMFVideoDisplayControl
+STDMETHODIMP CSyncAP::GetNativeVideoSize(SIZE *pszVideo, SIZE *pszARVideo)
+{
+ if (pszVideo)
+ {
+ pszVideo->cx = m_NativeVideoSize.cx;
+ pszVideo->cy = m_NativeVideoSize.cy;
+ }
+ if (pszARVideo)
+ {
+ pszARVideo->cx = m_NativeVideoSize.cx * m_AspectRatio.cx;
+ pszARVideo->cy = m_NativeVideoSize.cy * m_AspectRatio.cy;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CSyncAP::GetIdealVideoSize(SIZE *pszMin, SIZE *pszMax)
+{
+ if (pszMin)
+ {
+ pszMin->cx = 1;
+ pszMin->cy = 1;
+ }
+
+ if (pszMax)
+ {
+ D3DDISPLAYMODE d3ddm;
+
+ ZeroMemory(&d3ddm, sizeof(d3ddm));
+ if(SUCCEEDED(m_pD3D->GetAdapterDisplayMode(GetAdapter(m_pD3D), &d3ddm)))
+ {
+ pszMax->cx = d3ddm.Width;
+ pszMax->cy = d3ddm.Height;
+ }
+ }
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::SetVideoPosition(const MFVideoNormalizedRect *pnrcSource, const LPRECT prcDest)
+{
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::GetVideoPosition(MFVideoNormalizedRect *pnrcSource, LPRECT prcDest)
+{
+ if (pnrcSource)
+ {
+ pnrcSource->left = 0.0;
+ pnrcSource->top = 0.0;
+ pnrcSource->right = 1.0;
+ pnrcSource->bottom = 1.0;
+ }
+ if (prcDest)
+ memcpy (prcDest, &m_VideoRect, sizeof(m_VideoRect));//GetClientRect (m_hWnd, prcDest);
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::SetAspectRatioMode(DWORD dwAspectRatioMode)
+{
+ m_dwVideoAspectRatioMode = (MFVideoAspectRatioMode)dwAspectRatioMode;
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::GetAspectRatioMode(DWORD *pdwAspectRatioMode)
+{
+ CheckPointer (pdwAspectRatioMode, E_POINTER);
+ *pdwAspectRatioMode = m_dwVideoAspectRatioMode;
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::SetVideoWindow(HWND hwndVideo)
+{
+ ASSERT (m_hWnd == hwndVideo);
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::GetVideoWindow(HWND *phwndVideo)
+{
+ CheckPointer(phwndVideo, E_POINTER);
+ *phwndVideo = m_hWnd;
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::RepaintVideo()
+{
+ Paint(true);
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::GetCurrentImage(BITMAPINFOHEADER *pBih, BYTE **pDib, DWORD *pcbDib, LONGLONG *pTimeStamp)
+{
+ ASSERT (FALSE);
+ return E_NOTIMPL;
+}
+STDMETHODIMP CSyncAP::SetBorderColor(COLORREF Clr)
+{
+ m_BorderColor = Clr;
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::GetBorderColor(COLORREF *pClr)
+{
+ CheckPointer (pClr, E_POINTER);
+ *pClr = m_BorderColor;
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::SetRenderingPrefs(DWORD dwRenderFlags)
+{
+ m_dwVideoRenderPrefs = (MFVideoRenderPrefs)dwRenderFlags;
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::GetRenderingPrefs(DWORD *pdwRenderFlags)
+{
+ CheckPointer(pdwRenderFlags, E_POINTER);
+ *pdwRenderFlags = m_dwVideoRenderPrefs;
+ return S_OK;
+}
+STDMETHODIMP CSyncAP::SetFullscreen(BOOL fFullscreen)
+{
+ ASSERT (FALSE);
+ return E_NOTIMPL;
+}
+STDMETHODIMP CSyncAP::GetFullscreen(BOOL *pfFullscreen)
+{
+ ASSERT (FALSE);
+ return E_NOTIMPL;
+}
+
+// IEVRTrustedVideoPlugin
+STDMETHODIMP CSyncAP::IsInTrustedVideoMode(BOOL *pYes)
+{
+ CheckPointer(pYes, E_POINTER);
+ *pYes = TRUE;
+ return S_OK;
+}
+
+STDMETHODIMP CSyncAP::CanConstrict(BOOL *pYes)
+{
+ CheckPointer(pYes, E_POINTER);
+ *pYes = TRUE;
+ return S_OK;
+}
+
+STDMETHODIMP CSyncAP::SetConstriction(DWORD dwKPix)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CSyncAP::DisableImageExport(BOOL bDisable)
+{
+ return S_OK;
+}
+
+// IDirect3DDeviceManager9
+STDMETHODIMP CSyncAP::ResetDevice(IDirect3DDevice9 *pDevice,UINT resetToken)
+{
+ HRESULT hr = m_pD3DManager->ResetDevice (pDevice, resetToken);
+ return hr;
+}
+
+STDMETHODIMP CSyncAP::OpenDeviceHandle(HANDLE *phDevice)
+{
+ HRESULT hr = m_pD3DManager->OpenDeviceHandle (phDevice);
+ return hr;
+}
+
+STDMETHODIMP CSyncAP::CloseDeviceHandle(HANDLE hDevice)
+{
+ HRESULT hr = m_pD3DManager->CloseDeviceHandle(hDevice);
+ return hr;
+}
+
+STDMETHODIMP CSyncAP::TestDevice(HANDLE hDevice)
+{
+ HRESULT hr = m_pD3DManager->TestDevice(hDevice);
+ return hr;
+}
+
+STDMETHODIMP CSyncAP::LockDevice(HANDLE hDevice, IDirect3DDevice9 **ppDevice, BOOL fBlock)
+{
+ HRESULT hr = m_pD3DManager->LockDevice(hDevice, ppDevice, fBlock);
+ return hr;
+}
+
+STDMETHODIMP CSyncAP::UnlockDevice(HANDLE hDevice, BOOL fSaveState)
+{
+ HRESULT hr = m_pD3DManager->UnlockDevice(hDevice, fSaveState);
+ return hr;
+}
+
+STDMETHODIMP CSyncAP::GetVideoService(HANDLE hDevice, REFIID riid, void **ppService)
+{
+ HRESULT hr = m_pD3DManager->GetVideoService(hDevice, riid, ppService);
+
+ if (riid == __uuidof(IDirectXVideoDecoderService))
+ {
+ UINT nNbDecoder = 5;
+ GUID* pDecoderGuid;
+ IDirectXVideoDecoderService* pDXVAVideoDecoder = (IDirectXVideoDecoderService*) *ppService;
+ pDXVAVideoDecoder->GetDecoderDeviceGuids (&nNbDecoder, &pDecoderGuid);
+ }
+ else if (riid == __uuidof(IDirectXVideoProcessorService))
+ {
+ IDirectXVideoProcessorService* pDXVAProcessor = (IDirectXVideoProcessorService*) *ppService;
+ }
+
+ return hr;
+}
+
+STDMETHODIMP CSyncAP::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight)
+{
+ // This function should be called...
+ ASSERT (FALSE);
+
+ 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 CSyncAP::InitializeDevice(AM_MEDIA_TYPE* pMediaType)
+{
+ HRESULT hr;
+ CAutoLock lock(this);
+ CAutoLock lock2(&m_ImageProcessingLock);
+ CAutoLock cRenderLock(&m_allocatorLock);
+
+ RemoveAllSamples();
+ DeleteSurfaces();
+
+ VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*) pMediaType->pbFormat;
+ int w = vih2->bmiHeader.biWidth;
+ int h = abs(vih2->bmiHeader.biHeight);
+
+ m_NativeVideoSize = CSize(w, h);
+ if (m_bHighColorResolution)
+ hr = AllocSurfaces(D3DFMT_A2R10G10B10);
+ else
+ hr = AllocSurfaces(D3DFMT_X8R8G8B8);
+
+ for(int i = 0; i < m_nDXSurface; i++)
+ {
+ CComPtr<IMFSample> pMFSample;
+ hr = pfMFCreateVideoSampleFromSurface(m_pVideoSurface[i], &pMFSample);
+ if (SUCCEEDED (hr))
+ {
+ pMFSample->SetUINT32(GUID_SURFACE_INDEX, i);
+ m_FreeSamples.AddTail (pMFSample);
+ }
+ ASSERT (SUCCEEDED (hr));
+ }
+ return hr;
+}
+
+DWORD WINAPI CSyncAP::MixerThreadStatic(LPVOID lpParam)
+{
+ CSyncAP *pThis = (CSyncAP*) lpParam;
+ pThis->MixerThread();
+ return 0;
+}
+
+void CSyncAP::MixerThread()
+{
+ HANDLE hAvrt;
+ HANDLE hEvts[] = {m_hEvtQuit};
+ bool bQuit = false;
+ TIMECAPS tc;
+ DWORD dwResolution;
+ DWORD dwUser = 0;
+ DWORD dwTaskIndex = 0;
+
+ timeGetDevCaps(&tc, sizeof(TIMECAPS));
+ dwResolution = min(max(tc.wPeriodMin, 0), tc.wPeriodMax);
+ dwUser = timeBeginPeriod(dwResolution);
+
+ while (!bQuit)
+ {
+ DWORD dwObject = WaitForMultipleObjects (countof(hEvts), hEvts, FALSE, 1);
+ switch (dwObject)
+ {
+ case WAIT_OBJECT_0 :
+ bQuit = true;
+ break;
+ case WAIT_TIMEOUT :
+ {
+ bool bNewSample = false;
+ {
+ CAutoLock AutoLock(&m_ImageProcessingLock);
+ bNewSample = GetSampleFromMixer();
+ }
+ if(m_bUseInternalTimer && m_pSubPicQueue)
+ {
+ m_pSubPicQueue->SetFPS(m_fps);
+ }
+ }
+ break;
+ }
+ }
+ timeEndPeriod (dwResolution);
+}
+
+DWORD WINAPI CSyncAP::RenderThreadStatic(LPVOID lpParam)
+{
+ CSyncAP *pThis = (CSyncAP*)lpParam;
+ pThis->RenderThread();
+ return 0;
+}
+
+// Get samples that have been received and queued up by MixerThread() and present them at the correct time by calling Paint().
+void CSyncAP::RenderThread()
+{
+ HANDLE hAvrt;
+ DWORD dwTaskIndex = 0;
+ HANDLE hEvts[] = {m_hEvtQuit, m_hEvtFlush, m_hEvtSkip};
+ bool bQuit = false;
+ TIMECAPS tc;
+ DWORD dwResolution;
+ LONGLONG llRefClockTime;
+ double dTargetSyncOffset;
+ MFTIME llSystemTime;
+ DWORD dwUser = 0;
+ DWORD dwObject;
+ int nSamplesLeft;
+ CComPtr<IMFSample>pNewSample = NULL; // The sample next in line to be presented
+
+ // Tell Vista Multimedia Class Scheduler we are doing threaded playback (increase priority)
+ if (pfAvSetMmThreadCharacteristicsW) hAvrt = pfAvSetMmThreadCharacteristicsW (L"Playback", &dwTaskIndex);
+ if (pfAvSetMmThreadPriority) pfAvSetMmThreadPriority (hAvrt, AVRT_PRIORITY_HIGH);
+
+ CRenderersSettings& s = GetRenderersSettings();
+
+ // Set timer resolution
+ timeGetDevCaps(&tc, sizeof(TIMECAPS));
+ dwResolution = min(max(tc.wPeriodMin, 0), tc.wPeriodMax);
+ dwUser = timeBeginPeriod(dwResolution);
+ pNewSample = NULL;
+
+ while (!bQuit)
+ {
+ m_lNextSampleWait = 1; // Default value for running this loop
+ nSamplesLeft = 0;
+ bool stepForward = false;
+ LONG lDisplayCycle = (LONG)(GetDisplayCycle());
+ LONG lDisplayCycle2 = (LONG)(GetDisplayCycle() / 2.0); // These are a couple of empirically determined constants used the control the "snap" function
+ LONG lDisplayCycle4 = (LONG)(GetDisplayCycle() / 4.0);
+
+ CRenderersSettings& s = GetRenderersSettings();
+ dTargetSyncOffset = s.m_RenderSettings.fTargetSyncOffset;
+
+ if ((m_nRenderState == Started || !m_bPrerolled) && !pNewSample) // If either streaming or the pre-roll sample and no sample yet fetched
+ {
+ if (SUCCEEDED(GetScheduledSample(&pNewSample, nSamplesLeft))) // Get the next sample
+ {
+ m_llLastSampleTime = m_llSampleTime;
+ if (!m_bPrerolled)
+ {
+ m_bPrerolled = true; // m_bPrerolled is a ticket to show one (1) frame immediately
+ m_lNextSampleWait = 0; // Present immediately
+ }
+ else if (SUCCEEDED(pNewSample->GetSampleTime(&m_llSampleTime))) // Get zero-based sample due time
+ {
+ if (m_llLastSampleTime == m_llSampleTime) // In the rare case there are duplicate frames in the movie. There really shouldn't be but it happens.
+ {
+ MoveToFreeList(pNewSample, true);
+ pNewSample = NULL;
+ m_lNextSampleWait = 0;
+ }
+ else
+ {
+ m_pClock->GetCorrelatedTime(0, &llRefClockTime, &llSystemTime); // Get zero-based reference clock time. llSystemTime is not used for anything here
+ m_lNextSampleWait = (LONG)((m_llSampleTime - llRefClockTime) / 10000); // Time left until sample is due, in ms
+ if (m_bStepping)
+ {
+ m_lNextSampleWait = 0;
+ }
+ else if (s.m_RenderSettings.bSynchronizeNearest) // Present at the closest "safe" occasion at dTargetSyncOffset ms before vsync to avoid tearing
+ {
+ if (m_lNextSampleWait < -lDisplayCycle) // We have to allow slightly negative numbers at this stage. Otherwise we get "choking" when frame rate > refresh rate
+ {
+ SetEvent(m_hEvtSkip);
+ m_bEvtSkip = true;
+ }
+ REFERENCE_TIME rtRefClockTimeNow;
+ if (m_pRefClock) m_pRefClock->GetTime(&rtRefClockTimeNow); // Reference clock time now
+ LONG lLastVsyncTime = (LONG)((m_llEstVBlankTime - rtRefClockTimeNow) / 10000); // Last vsync time relative to now
+ if (abs(lLastVsyncTime) > lDisplayCycle) lLastVsyncTime = - lDisplayCycle; // To even out glitches in the beginning
+
+ LONGLONG llNextSampleWait = (LONGLONG)(((double)lLastVsyncTime + GetDisplayCycle() - dTargetSyncOffset) * 10000); // Time from now util next safe time to Paint()
+ while ((llRefClockTime + llNextSampleWait) < (m_llSampleTime + m_llHysteresis)) // While the proposed time is in the past of sample presentation time
+ {
+ llNextSampleWait = llNextSampleWait + (LONGLONG)(GetDisplayCycle() * 10000); // Try the next possible time, one display cycle ahead
+ }
+ m_lNextSampleWait = (LONG)(llNextSampleWait / 10000);
+ m_lShiftToNearestPrev = m_lShiftToNearest;
+ m_lShiftToNearest = (LONG)((llRefClockTime + llNextSampleWait - m_llSampleTime) / 10000); // The adjustment made to get to the sweet point in time, in ms
+
+ // If m_lShiftToNearest is pushed a whole cycle into the future, then we are getting more frames
+ // than we can chew and we need to throw one away. We don't want to wait many cycles and skip many
+ // frames.
+ if (m_lShiftToNearest > (lDisplayCycle + 1))
+ {
+ SetEvent(m_hEvtSkip);
+ m_bEvtSkip = true;
+ }
+
+ // We need to add a hysteresis to the control of the timing adjustment to avoid judder when
+ // presentation time is close to vsync and the renderer couldn't otherwise make up its mind
+ // whether to present before the vsync or after. That kind of indecisiveness leads to judder.
+ if (m_bSnapToVSync)
+ {
+
+ if ((m_lShiftToNearestPrev - m_lShiftToNearest) > lDisplayCycle2) // If a step down in the m_lShiftToNearest function. Display slower than video.
+ {
+ m_bVideoSlowerThanDisplay = false;
+ m_llHysteresis = -(LONGLONG)(10000 * lDisplayCycle4);
+ }
+ else if ((m_lShiftToNearest - m_lShiftToNearestPrev) > lDisplayCycle2) // If a step up
+ {
+ m_bVideoSlowerThanDisplay = true;
+ m_llHysteresis = (LONGLONG)(10000 * lDisplayCycle4);
+ }
+ else if ((m_lShiftToNearest < (3 * lDisplayCycle4)) && (m_lShiftToNearest > lDisplayCycle4))
+ m_llHysteresis = 0; // Reset when between 1/4 and 3/4 of the way either way
+
+ if ((m_lShiftToNearest < lDisplayCycle2) && (m_llHysteresis > 0)) m_llHysteresis = 0; // Should never really be in this territory.
+ if (m_lShiftToNearest < 0) m_llHysteresis = 0; // A glitch might get us to a sticky state where both these numbers are negative.
+ if ((m_lShiftToNearest > lDisplayCycle2) && (m_llHysteresis < 0)) m_llHysteresis = 0;
+ }
+ }
+
+ if (m_lNextSampleWait < 0) // Skip late or duplicate sample.
+ {
+ SetEvent(m_hEvtSkip);
+ m_bEvtSkip = true;
+ }
+
+ if (m_lNextSampleWait > 1000)
+ {
+ m_lNextSampleWait = 1000; // So as to avoid full a full stop when sample is far in the future (shouldn't really happen).
+ }
+ }
+ } // if got new sample
+ }
+ }
+ // Wait for the next presentation time (m_lNextSampleWait) or some other event.
+ dwObject = WaitForMultipleObjects(countof(hEvts), hEvts, FALSE, (DWORD)m_lNextSampleWait);
+ switch (dwObject)
+ {
+ case WAIT_OBJECT_0: // Quit
+ bQuit = true;
+ break;
+
+ case WAIT_OBJECT_0 + 1: // Flush
+ if (pNewSample) MoveToFreeList(pNewSample, true);
+ pNewSample = NULL;
+ FlushSamples();
+ m_bEvtFlush = false;
+ ResetEvent(m_hEvtFlush);
+ m_bPrerolled = false;
+ m_lShiftToNearest = 0;
+ stepForward = true;
+ break;
+
+ case WAIT_OBJECT_0 + 2: // Skip sample
+ m_pcFramesDropped++;
+ m_llSampleTime = m_llLastSampleTime; // This sample will never be shown
+ m_bEvtSkip = false;
+ ResetEvent(m_hEvtSkip);
+ stepForward = true;
+ break;
+
+ case WAIT_TIMEOUT: // Time to show the sample or something
+ if (m_LastSetOutputRange != -1 && m_LastSetOutputRange != s.m_RenderSettings.iEVROutputRange || m_bPendingRenegotiate)
+ {
+ if (pNewSample) MoveToFreeList(pNewSample, true);
+ pNewSample = NULL;
+ FlushSamples();
+ RenegotiateMediaType();
+ m_bPendingRenegotiate = false;
+ }
+
+ if (m_bPendingResetDevice)
+ {
+ if (pNewSample)
+ MoveToFreeList(pNewSample, true);
+ pNewSample = NULL;
+ SendResetRequest();
+ }
+ else if (m_nStepCount < 0)
+ {
+ m_nStepCount = 0;
+ m_pcFramesDropped++;
+ stepForward = true;
+ }
+ else if (pNewSample && (m_nStepCount > 0))
+ {
+ pNewSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32 *)&m_nCurSurface);
+ if (!g_bExternalSubtitleTime) __super::SetTime (g_tSegmentStart + m_llSampleTime);
+ Paint(true);
+ CompleteFrameStep(false);
+ m_pcFramesDrawn++;
+ stepForward = true;
+ }
+ else if (pNewSample && !m_bStepping) // When a stepped frame is shown, a new one is fetched that we don't want to show here while stepping
+ {
+ pNewSample->GetUINT32(GUID_SURFACE_INDEX, (UINT32*)&m_nCurSurface);
+ if (!g_bExternalSubtitleTime) __super::SetTime (g_tSegmentStart + m_llSampleTime);
+ Paint(true);
+ m_pcFramesDrawn++;
+ stepForward = true;
+ }
+ break;
+ } // switch
+ if (pNewSample && stepForward)
+ {
+ MoveToFreeList(pNewSample, true);
+ pNewSample = NULL;
+ }
+ } // while
+ if (pNewSample)
+ {
+ MoveToFreeList(pNewSample, true);
+ pNewSample = NULL;
+ }
+ timeEndPeriod (dwResolution);
+ if (pfAvRevertMmThreadCharacteristics) pfAvRevertMmThreadCharacteristics(hAvrt);
+}
+
+STDMETHODIMP_(bool) CSyncAP::ResetDevice()
+{
+ CAutoLock lock(this);
+ CAutoLock lock2(&m_ImageProcessingLock);
+ CAutoLock cRenderLock(&m_allocatorLock);
+ RemoveAllSamples();
+
+ bool bResult = __super::ResetDevice();
+
+ for(int i = 0; i < m_nDXSurface; i++)
+ {
+ CComPtr<IMFSample> pMFSample;
+ HRESULT hr = pfMFCreateVideoSampleFromSurface (m_pVideoSurface[i], &pMFSample);
+ if (SUCCEEDED (hr))
+ {
+ pMFSample->SetUINT32(GUID_SURFACE_INDEX, i);
+ m_FreeSamples.AddTail(pMFSample);
+ }
+ ASSERT(SUCCEEDED (hr));
+ }
+ return bResult;
+}
+
+void CSyncAP::OnResetDevice()
+{
+ TRACE("--> CSyncAP::OnResetDevice on thread: %d\n", GetCurrentThreadId());
+ HRESULT hr;
+ hr = m_pD3DManager->ResetDevice(m_pD3DDev, m_nResetToken);
+ if (m_pSink) m_pSink->Notify(EC_DISPLAY_CHANGED, 0, 0);
+ CSize videoSize = GetVisibleVideoSize();
+ if (m_pSink) m_pSink->Notify(EC_VIDEO_SIZE_CHANGED, MAKELPARAM(videoSize.cx, videoSize.cy), 0);
+}
+
+void CSyncAP::RemoveAllSamples()
+{
+ CAutoLock AutoLock(&m_ImageProcessingLock);
+ FlushSamples();
+ m_ScheduledSamples.RemoveAll();
+ m_FreeSamples.RemoveAll();
+ m_nUsedBuffer = 0;
+}
+
+HRESULT CSyncAP::GetFreeSample(IMFSample** ppSample)
+{
+ CAutoLock lock(&m_SampleQueueLock);
+ HRESULT hr = S_OK;
+
+ if (m_FreeSamples.GetCount() > 1) // Cannot use first free buffer (can be currently displayed)
+ {
+ InterlockedIncrement(&m_nUsedBuffer);
+ *ppSample = m_FreeSamples.RemoveHead().Detach();
+ }
+ else
+ hr = MF_E_SAMPLEALLOCATOR_EMPTY;
+
+ return hr;
+}
+
+HRESULT CSyncAP::GetScheduledSample(IMFSample** ppSample, int &_Count)
+{
+ CAutoLock lock(&m_SampleQueueLock);
+ HRESULT hr = S_OK;
+
+ _Count = m_ScheduledSamples.GetCount();
+ if (_Count > 0)
+ {
+ *ppSample = m_ScheduledSamples.RemoveHead().Detach();
+ --_Count;
+ }
+ else
+ hr = MF_E_SAMPLEALLOCATOR_EMPTY;
+
+ return hr;
+}
+
+void CSyncAP::MoveToFreeList(IMFSample* pSample, bool bTail)
+{
+ CAutoLock lock(&m_SampleQueueLock);
+ InterlockedDecrement(&m_nUsedBuffer);
+ if (m_bPendingMediaFinished && m_nUsedBuffer == 0)
+ {
+ m_bPendingMediaFinished = false;
+ m_pSink->Notify(EC_COMPLETE, 0, 0);
+ }
+ if (bTail)
+ m_FreeSamples.AddTail(pSample);
+ else
+ m_FreeSamples.AddHead(pSample);
+}
+
+void CSyncAP::MoveToScheduledList(IMFSample* pSample, bool _bSorted)
+{
+ if (_bSorted)
+ {
+ CAutoLock lock(&m_SampleQueueLock);
+ m_ScheduledSamples.AddHead(pSample);
+ }
+ else
+ {
+ CAutoLock lock(&m_SampleQueueLock);
+ m_ScheduledSamples.AddTail(pSample);
+ }
+}
+
+void CSyncAP::FlushSamples()
+{
+ CAutoLock lock(this);
+ CAutoLock lock2(&m_SampleQueueLock);
+ FlushSamplesInternal();
+}
+
+void CSyncAP::FlushSamplesInternal()
+{
+ m_bPrerolled = false;
+ while (m_ScheduledSamples.GetCount() > 0)
+ {
+ CComPtr<IMFSample> pMFSample;
+ pMFSample = m_ScheduledSamples.RemoveHead();
+ MoveToFreeList(pMFSample, true);
+ }
+}
+
+HRESULT CSyncAP::AdviseSyncClock(ISyncClock* sC)
+{
+ return m_pGenlock->AdviseSyncClock(sC);
+}
+
+HRESULT CSyncAP::BeginStreaming()
+{
+ CRenderersSettings& s = GetRenderersSettings();
+ m_pcFramesDropped = 0;
+ m_pcFramesDrawn = 0;
+
+ CComPtr<IBaseFilter> pEVR;
+ FILTER_INFO filterInfo;
+ ZeroMemory(&filterInfo, sizeof(filterInfo));
+ m_pOuterEVR->QueryInterface (__uuidof(IBaseFilter), (void**)&pEVR);
+ pEVR->QueryFilterInfo(&filterInfo); // This addref's the pGraph member
+
+ BeginEnumFilters(filterInfo.pGraph, pEF, pBF)
+ if(CComQIPtr<IAMAudioRendererStats> pAS = pBF)
+ {
+ m_pAudioStats = pAS;
+ };
+ EndEnumFilters
+
+ pEVR->GetSyncSource(&m_pRefClock);
+ if (filterInfo.pGraph) filterInfo.pGraph->Release();
+ m_pGenlock->SetMonitor(GetAdapter(m_pD3D));
+ m_pGenlock->GetTiming();
+
+ ResetStats();
+ EstimateRefreshTimings();
+ if (m_dFrameCycle > 0.0) m_dCycleDifference = GetCycleDifference(); // Might have moved to another display
+ return S_OK;
+}
+
+HRESULT CreateSyncRenderer(const CLSID& clsid, HWND hWnd, bool bFullscreen, ISubPicAllocatorPresenter** ppAP)
+{
+ HRESULT hr = E_FAIL;
+ if (clsid == CLSID_SyncAllocatorPresenter)
+ {
+ CString Error;
+ *ppAP = DNew CSyncAP(hWnd, bFullscreen, hr, Error);
+ (*ppAP)->AddRef();
+
+ if(FAILED(hr))
+ {
+ Error += L"\n";
+ Error += GothSyncErrorMessage(hr, NULL);
+ MessageBox(hWnd, Error, L"Error creating Sync Renderer", MB_OK | MB_ICONERROR);
+ (*ppAP)->Release();
+ *ppAP = NULL;
+ }
+ else if (!Error.IsEmpty())
+ {
+ MessageBox(hWnd, Error, L"Warning creating Sync Renderer", MB_OK|MB_ICONWARNING);
+ }
+ }
+ return hr;
+}
+
+CSyncRenderer::CSyncRenderer(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CSyncAP *pAllocatorPresenter): CUnknown(pName, pUnk)
+{
+ hr = m_pEVR.CoCreateInstance(CLSID_EnhancedVideoRenderer, GetOwner());
+ m_pVMR9AlphaBitmap = pVMR9AlphaBitmap;
+ m_pAllocatorPresenter = pAllocatorPresenter;
+}
+
+CSyncRenderer::~CSyncRenderer()
+{
+}
+
+HRESULT STDMETHODCALLTYPE CSyncRenderer::GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE *State)
+{
+ HRESULT ReturnValue;
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->GetState(dwMilliSecsTimeout, State);
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CSyncRenderer::EnumPins(__out IEnumPins **ppEnum)
+{
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->EnumPins(ppEnum);
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CSyncRenderer::FindPin(LPCWSTR Id, __out IPin **ppPin)
+{
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->FindPin(Id, ppPin);
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CSyncRenderer::QueryFilterInfo(__out FILTER_INFO *pInfo)
+{
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->QueryFilterInfo(pInfo);
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CSyncRenderer::JoinFilterGraph(__in_opt IFilterGraph *pGraph, __in_opt LPCWSTR pName)
+{
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->JoinFilterGraph(pGraph, pName);
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CSyncRenderer::QueryVendorInfo(__out LPWSTR *pVendorInfo)
+{
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->QueryVendorInfo(pVendorInfo);
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CSyncRenderer::Stop( void)
+{
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->Stop();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CSyncRenderer::Pause(void)
+{
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->Pause();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CSyncRenderer::Run(REFERENCE_TIME tStart)
+{
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->Run(tStart);
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CSyncRenderer::SetSyncSource(__in_opt IReferenceClock *pClock)
+{
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->SetSyncSource(pClock);
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CSyncRenderer::GetSyncSource(__deref_out_opt IReferenceClock **pClock)
+{
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->GetSyncSource(pClock);
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CSyncRenderer::GetClassID(__RPC__out CLSID *pClassID)
+{
+ CComPtr<IBaseFilter> pEVRBase;
+ if (m_pEVR)
+ m_pEVR->QueryInterface(&pEVRBase);
+ if (pEVRBase)
+ return pEVRBase->GetClassID(pClassID);
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CSyncRenderer::GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms)
+{
+ CheckPointer(pBmpParms, E_POINTER);
+ CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock);
+ memcpy (pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap));
+ return S_OK;
+}
+
+STDMETHODIMP CSyncRenderer::SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms)
+{
+ CheckPointer(pBmpParms, E_POINTER);
+ CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock);
+ memcpy (m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap));
+ m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE;
+ m_pAllocatorPresenter->UpdateAlphaBitmap();
+ return S_OK;
+}
+
+STDMETHODIMP CSyncRenderer::UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms)
+{
+ CheckPointer(pBmpParms, E_POINTER);
+ CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock);
+ memcpy (m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap));
+ m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE;
+ m_pAllocatorPresenter->UpdateAlphaBitmap();
+ return S_OK;
+}
+
+STDMETHODIMP CSyncRenderer::support_ffdshow()
+{
+ queue_ffdshow_support = true;
+ return S_OK;
+}
+
+STDMETHODIMP CSyncRenderer::NonDelegatingQueryInterface(REFIID riid, void** ppv)
+{
+ HRESULT hr;
+
+ if(riid == __uuidof(IVMRMixerBitmap9))
+ return GetInterface((IVMRMixerBitmap9*)this, ppv);
+
+ if (riid == __uuidof(IBaseFilter))
+ {
+ return GetInterface((IBaseFilter*)this, ppv);
+ }
+
+ if (riid == __uuidof(IMediaFilter))
+ {
+ return GetInterface((IMediaFilter*)this, ppv);
+ }
+ if (riid == __uuidof(IPersist))
+ {
+ return GetInterface((IPersist*)this, ppv);
+ }
+ if (riid == __uuidof(IBaseFilter))
+ {
+ return GetInterface((IBaseFilter*)this, ppv);
+ }
+
+ hr = m_pEVR ? m_pEVR->QueryInterface(riid, ppv) : E_NOINTERFACE;
+ if(m_pEVR && FAILED(hr))
+ {
+ if(riid == __uuidof(IVMRffdshow9)) // Support ffdshow queueing. We show ffdshow that this is patched Media Player Classic.
+ return GetInterface((IVMRffdshow9*)this, ppv);
+ }
+ return SUCCEEDED(hr) ? hr : __super::NonDelegatingQueryInterface(riid, ppv);
+}
+
+CGenlock::CGenlock(DOUBLE target, DOUBLE limit, INT lineD, INT colD, DOUBLE clockD, UINT mon):
+ targetSyncOffset(target), // Target sync offset, typically around 10 ms
+ controlLimit(limit), // How much sync offset is allowed to drift from target sync offset before control kicks in
+ lineDelta(lineD), // Number of rows used in display frequency adjustment, typically 1 (one)
+ columnDelta(colD), // Number of columns used in display frequency adjustment, typically 1 - 2
+ cycleDelta(clockD), // Delta used in clock speed adjustment. In fractions of 1.0. Typically around 0.001
+ monitor(mon) // The monitor to be adjusted if the display refresh rate is the controlled parameter
+{
+ lowSyncOffset = targetSyncOffset - controlLimit;
+ highSyncOffset = targetSyncOffset + controlLimit;
+ adjDelta = 0;
+ displayAdjustmentsMade = 0;
+ clockAdjustmentsMade = 0;
+ displayFreqCruise = 0;
+ displayFreqFaster = 0;
+ displayFreqSlower = 0;
+ curDisplayFreq = 0;
+ psWnd = NULL;
+ liveSource = FALSE;
+ powerstripTimingExists = FALSE;
+ syncOffsetFifo = new MovingAverage(64);
+ frameCycleFifo = new MovingAverage(4);
+}
+
+CGenlock::~CGenlock()
+{
+ ResetTiming();
+ if(syncOffsetFifo != NULL)
+ {
+ delete syncOffsetFifo;
+ syncOffsetFifo = NULL;
+ }
+ if(frameCycleFifo != NULL)
+ {
+ delete frameCycleFifo;
+ frameCycleFifo = NULL;
+ }
+ syncClock = NULL;
+};
+
+BOOL CGenlock::PowerstripRunning()
+{
+ psWnd = FindWindow(_T("TPShidden"), NULL);
+ if (!psWnd) return FALSE; // Powerstrip is not running
+ else return TRUE;
+}
+
+// Get the display timing parameters through PowerStrip (if running).
+HRESULT CGenlock::GetTiming()
+{
+ ATOM getTiming;
+ LPARAM lParam = NULL;
+ WPARAM wParam = monitor;
+ INT i = 0;
+ INT j = 0;
+ INT params = 0;
+ BOOL done = FALSE;
+ TCHAR tmpStr[MAX_LOADSTRING];
+
+ CAutoLock lock(&csGenlockLock);
+ if (!PowerstripRunning()) return E_FAIL;
+
+ getTiming = static_cast<ATOM>(SendMessage(psWnd, UM_GETTIMING, wParam, lParam));
+ GlobalGetAtomName(getTiming, savedTiming, MAX_LOADSTRING);
+
+ while (params < TIMING_PARAM_CNT)
+ {
+ while (savedTiming[i] != ',' && savedTiming[i] != '\0')
+ {
+ tmpStr[j++] = savedTiming[i];
+ tmpStr[j] = '\0';
+ i++;
+ }
+ i++; // Skip trailing comma
+ j = 0;
+ displayTiming[params] = _ttoi(tmpStr);
+ displayTimingSave[params] = displayTiming[params];
+ params++;
+ }
+
+ // The display update frequency is controlled by adding and subtracting pixels form the
+ // image. This is done by either subtracting columns or rows or both. Some displays like
+ // row adjustments and some column adjustments. One should probably not do both.
+ StringCchPrintf(faster, MAX_LOADSTRING, TEXT("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\0"),
+ displayTiming[0],
+ displayTiming[HFRONTPORCH] - columnDelta,
+ displayTiming[2],
+ displayTiming[3],
+ displayTiming[4],
+ displayTiming[VFRONTPORCH] - lineDelta,
+ displayTiming[6],
+ displayTiming[7],
+ displayTiming[PIXELCLOCK],
+ displayTiming[9]
+ );
+
+ // Nominal update frequency
+ StringCchPrintf(cruise, MAX_LOADSTRING, TEXT("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\0"),
+ displayTiming[0],
+ displayTiming[HFRONTPORCH],
+ displayTiming[2],
+ displayTiming[3],
+ displayTiming[4],
+ displayTiming[VFRONTPORCH],
+ displayTiming[6],
+ displayTiming[7],
+ displayTiming[PIXELCLOCK],
+ displayTiming[9]
+ );
+
+ // Lower than nominal update frequency
+ StringCchPrintf(slower, MAX_LOADSTRING, TEXT("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\0"),
+ displayTiming[0],
+ displayTiming[HFRONTPORCH] + columnDelta,
+ displayTiming[2],
+ displayTiming[3],
+ displayTiming[4],
+ displayTiming[VFRONTPORCH] + lineDelta,
+ displayTiming[6],
+ displayTiming[7],
+ displayTiming[PIXELCLOCK],
+ displayTiming[9]
+ );
+
+ totalColumns = displayTiming[HACTIVE] + displayTiming[HFRONTPORCH] + displayTiming[HSYNCWIDTH] + displayTiming[HBACKPORCH];
+ totalLines = displayTiming[VACTIVE] + displayTiming[VFRONTPORCH] + displayTiming[VSYNCWIDTH] + displayTiming[VBACKPORCH];
+ pixelClock = 1000 * displayTiming[PIXELCLOCK]; // Pixels/s
+ displayFreqCruise = (DOUBLE)pixelClock / (totalLines * totalColumns); // Frames/s
+ displayFreqSlower = (DOUBLE)pixelClock / ((totalLines + lineDelta) * (totalColumns + columnDelta));
+ displayFreqFaster = (DOUBLE)pixelClock / ((totalLines - lineDelta) * (totalColumns - columnDelta));
+ curDisplayFreq = displayFreqCruise;
+ GlobalDeleteAtom(getTiming);
+ adjDelta = 0;
+ powerstripTimingExists = TRUE;
+ return S_OK;
+}
+
+// Reset display timing parameters to nominal.
+HRESULT CGenlock::ResetTiming()
+{
+ LPARAM lParam = NULL;
+ WPARAM wParam = monitor;
+ ATOM setTiming;
+ LRESULT ret;
+ CAutoLock lock(&csGenlockLock);
+
+ if (!PowerstripRunning()) return E_FAIL;
+
+ if (displayAdjustmentsMade > 0)
+ {
+ setTiming = GlobalAddAtom(cruise);
+ lParam = setTiming;
+ ret = SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam);
+ GlobalDeleteAtom(setTiming);
+ curDisplayFreq = displayFreqCruise;
+ }
+ adjDelta = 0;
+ return S_OK;
+}
+
+// Reset reference clock speed to nominal.
+HRESULT CGenlock::ResetClock()
+{
+ adjDelta = 0;
+ if (syncClock == NULL) return E_FAIL;
+ else return syncClock->AdjustClock(1.0);
+ return S_OK;
+}
+
+HRESULT CGenlock::SetTargetSyncOffset(DOUBLE targetD)
+{
+ targetSyncOffset = targetD;
+ lowSyncOffset = targetD - controlLimit;
+ highSyncOffset = targetD + controlLimit;
+ return S_OK;
+}
+
+HRESULT CGenlock::GetTargetSyncOffset(DOUBLE *targetD)
+{
+ *targetD = targetSyncOffset;
+ return S_OK;
+}
+
+HRESULT CGenlock::SetControlLimit(DOUBLE cL)
+{
+ controlLimit = cL;
+ return S_OK;
+}
+
+HRESULT CGenlock::GetControlLimit(DOUBLE *cL)
+{
+ *cL = controlLimit;
+ return S_OK;
+}
+
+HRESULT CGenlock::SetDisplayResolution(UINT columns, UINT lines)
+{
+ visibleColumns = columns;
+ visibleLines = lines;
+ return S_OK;
+}
+
+HRESULT CGenlock::AdviseSyncClock(ISyncClock* sC)
+{
+ if (!sC) return E_FAIL;
+ if (syncClock) syncClock = NULL; // Release any outstanding references if this is called repeatedly
+ syncClock = sC;
+ return S_OK;
+}
+
+// Set the monitor to control. This is best done manually as not all monitors can be controlled
+// so automatic detection of monitor to control might have unintended effects.
+// The PowerStrip API uses zero-based monitor numbers, i.e. the default monitor is 0.
+HRESULT CGenlock::SetMonitor(UINT mon)
+{
+ monitor = mon;
+ return S_OK;
+}
+
+HRESULT CGenlock::ResetStats()
+{
+ CAutoLock lock(&csGenlockLock);
+ minSyncOffset = 1000000.0;
+ maxSyncOffset = -1000000.0;
+ minFrameCycle = 1000000.0;
+ maxFrameCycle = -1000000.0;
+ displayAdjustmentsMade = 0;
+ clockAdjustmentsMade = 0;
+ return S_OK;
+}
+
+// Synchronize by adjusting display refresh rate
+HRESULT CGenlock::ControlDisplay(double syncOffset, double frameCycle)
+{
+ LPARAM lParam = NULL;
+ WPARAM wParam = monitor;
+ ATOM setTiming;
+
+ CRenderersSettings& s = GetRenderersSettings();
+ targetSyncOffset = s.m_RenderSettings.fTargetSyncOffset;
+ lowSyncOffset = targetSyncOffset - s.m_RenderSettings.fControlLimit;
+ highSyncOffset = targetSyncOffset + s.m_RenderSettings.fControlLimit;
+
+ syncOffsetAvg = syncOffsetFifo->Average(syncOffset);
+ minSyncOffset = min(minSyncOffset, syncOffset);
+ maxSyncOffset = max(maxSyncOffset, syncOffset);
+ frameCycleAvg = frameCycleFifo->Average(frameCycle);
+ minFrameCycle = min(minFrameCycle, frameCycle);
+ maxFrameCycle = max(maxFrameCycle, frameCycle);
+
+ if (!PowerstripRunning() || !powerstripTimingExists) return E_FAIL;
+ // Adjust as seldom as possible by checking the current controlState before changing it.
+ if ((syncOffsetAvg > highSyncOffset) && (adjDelta != 1))
+ // Speed up display refresh rate by subtracting pixels from the image.
+ {
+ adjDelta = 1; // Increase refresh rate
+ curDisplayFreq = displayFreqFaster;
+ setTiming = GlobalAddAtom(faster);
+ lParam = setTiming;
+ SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam);
+ GlobalDeleteAtom(setTiming);
+ displayAdjustmentsMade++;
+ }
+ else
+ // Slow down display refresh rate by adding pixels to the image.
+ if ((syncOffsetAvg < lowSyncOffset) && (adjDelta != -1))
+ {
+ adjDelta = -1;
+ curDisplayFreq = displayFreqSlower;
+ setTiming = GlobalAddAtom(slower);
+ lParam = setTiming;
+ SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam);
+ GlobalDeleteAtom(setTiming);
+ displayAdjustmentsMade++;
+ }
+ else
+ // Cruise.
+ if ((syncOffsetAvg < targetSyncOffset) && (adjDelta == 1))
+ {
+ adjDelta = 0;
+ curDisplayFreq = displayFreqCruise;
+ setTiming = GlobalAddAtom(cruise);
+ lParam = setTiming;
+ SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam);
+ GlobalDeleteAtom(setTiming);
+ displayAdjustmentsMade++;
+ }
+ else if ((syncOffsetAvg > targetSyncOffset) && (adjDelta == -1))
+ {
+ adjDelta = 0;
+ curDisplayFreq = displayFreqCruise;
+ setTiming = GlobalAddAtom(cruise);
+ lParam = setTiming;
+ SendMessage(psWnd, UM_SETCUSTOMTIMINGFAST, wParam, lParam);
+ GlobalDeleteAtom(setTiming);
+ displayAdjustmentsMade++;
+ }
+ return S_OK;
+}
+
+// Synchronize by adjusting reference clock rate (and therefore video FPS).
+// Todo: check so that we don't have a live source
+HRESULT CGenlock::ControlClock(double syncOffset, double frameCycle)
+{
+ CRenderersSettings& s = GetRenderersSettings();
+ targetSyncOffset = s.m_RenderSettings.fTargetSyncOffset;
+ lowSyncOffset = targetSyncOffset - s.m_RenderSettings.fControlLimit;
+ highSyncOffset = targetSyncOffset + s.m_RenderSettings.fControlLimit;
+
+ syncOffsetAvg = syncOffsetFifo->Average(syncOffset);
+ minSyncOffset = min(minSyncOffset, syncOffset);
+ maxSyncOffset = max(maxSyncOffset, syncOffset);
+ frameCycleAvg = frameCycleFifo->Average(frameCycle);
+ minFrameCycle = min(minFrameCycle, frameCycle);
+ maxFrameCycle = max(maxFrameCycle, frameCycle);
+
+ if (!syncClock) return E_FAIL;
+ // Adjust as seldom as possible by checking the current controlState before changing it.
+ if ((syncOffsetAvg > highSyncOffset) && (adjDelta != 1))
+ // Slow down video stream.
+ {
+ adjDelta = 1;
+ syncClock->AdjustClock(1.0 - cycleDelta); // Makes the clock move slower by providing smaller increments
+ clockAdjustmentsMade++;
+ }
+ else
+ // Speed up video stream.
+ if ((syncOffsetAvg < lowSyncOffset) && (adjDelta != -1))
+ {
+ adjDelta = -1;
+ syncClock->AdjustClock(1.0 + cycleDelta);
+ clockAdjustmentsMade++;
+ }
+ else
+ // Cruise.
+ if ((syncOffsetAvg < targetSyncOffset) && (adjDelta == 1))
+ {
+ adjDelta = 0;
+ syncClock->AdjustClock(1.0);
+ clockAdjustmentsMade++;
+ }
+ else if ((syncOffsetAvg > targetSyncOffset) && (adjDelta == -1))
+ {
+ adjDelta = 0;
+ syncClock->AdjustClock(1.0);
+ clockAdjustmentsMade++;
+ }
+ return S_OK;
+}
+
+// Don't adjust anything, just update the syncOffset stats
+HRESULT CGenlock::UpdateStats(double syncOffset, double frameCycle)
+{
+ syncOffsetAvg = syncOffsetFifo->Average(syncOffset);
+ minSyncOffset = min(minSyncOffset, syncOffset);
+ maxSyncOffset = max(maxSyncOffset, syncOffset);
+ frameCycleAvg = frameCycleFifo->Average(frameCycle);
+ minFrameCycle = min(minFrameCycle, frameCycle);
+ maxFrameCycle = max(maxFrameCycle, frameCycle);
+ return S_OK;
+}
\ No newline at end of file diff --git a/src/filters/renderer/VideoRenderers/SyncRenderer.h b/src/filters/renderer/VideoRenderers/SyncRenderer.h new file mode 100644 index 000000000..3e8f3bf5a --- /dev/null +++ b/src/filters/renderer/VideoRenderers/SyncRenderer.h @@ -0,0 +1,690 @@ +/*
+* $Id: SyncRenderer.h 1292 2009-10-03 23:20:26Z ar-jar $
+*
+* (C) 2003-2006 Gabest
+* (C) 2006-2010 see AUTHORS
+*
+* This file is part of mplayerc.
+*
+* Mplayerc 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.
+*
+* Mplayerc 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 <http://www.gnu.org/licenses/>.
+*
+*/
+
+#pragma once
+#include "../SubPic/ISubPic.h"
+#include "RenderersSettings.h"
+#include "SyncAllocatorPresenter.h"
+#include "AllocatorCommon.h"
+#include <dxva2api.h>
+
+#define VMRBITMAP_UPDATE 0x80000000
+#define MAX_PICTURE_SLOTS (60+2) // Last 2 for pixels shader!
+#define NB_JITTER 126
+
+extern bool g_bNoDuration; // Defined in MainFrm.cpp
+extern bool g_bExternalSubtitleTime;
+
+// Possible messages to the PowerStrip API. PowerStrip is used to control
+// the display frequency in one of the video - display synchronization modes.
+// Powerstrip can also through a CGenlock object give very accurate timing data
+// (given) that the gfx board is supported by PS.
+#define UM_SETCUSTOMTIMING (WM_USER+200)
+#define UM_SETREFRESHRATE (WM_USER+201)
+#define UM_SETPOLARITY (WM_USER+202)
+#define UM_REMOTECONTROL (WM_USER+210)
+#define UM_SETGAMMARAMP (WM_USER+203)
+#define UM_CREATERESOLUTION (WM_USER+204)
+#define UM_GETTIMING (WM_USER+205)
+#define UM_SETCUSTOMTIMINGFAST (WM_USER+211) // Sets timing without writing to file. Faster
+
+#define PositiveHorizontalPolarity 0x00
+#define PositiveVerticalPolarity 0x00
+#define NegativeHorizontalPolarity 0x02
+#define NegativeVerticalPolarity 0x04
+#define HideTrayIcon 0x00
+#define ShowTrayIcon 0x01
+#define ClosePowerStrip 0x63
+
+#define HACTIVE 0
+#define HFRONTPORCH 1
+#define HSYNCWIDTH 2
+#define HBACKPORCH 3
+#define VACTIVE 4
+#define VFRONTPORCH 5
+#define VSYNCWIDTH 6
+#define VBACKPORCH 7
+#define PIXELCLOCK 8
+#define UNKNOWN 9
+
+#define MAX_FIFO_SIZE 1024
+
+#define CheckHR(exp) {if(FAILED(hr = exp)) return hr;}
+
+// Guid to tag IMFSample with DirectX surface index
+static const GUID GUID_SURFACE_INDEX = { 0x30c8e9f6, 0x415, 0x4b81, { 0xa3, 0x15, 0x1, 0xa, 0xc6, 0xa9, 0xda, 0x19 } };
+
+namespace GothSync
+{
+typedef enum
+{
+ MSG_MIXERIN,
+ MSG_MIXEROUT,
+ MSG_ERROR
+} EVR_STATS_MSG;
+
+#pragma pack(push, 1)
+
+template<int texcoords>
+struct MYD3DVERTEX
+{
+ float x, y, z, rhw;
+ struct
+ {
+ float u, v;
+ } t[texcoords];
+};
+
+template<>
+struct MYD3DVERTEX<0>
+{
+ float x, y, z, rhw;
+ DWORD Diffuse;
+};
+
+#pragma pack(pop)
+
+class CGenlock;
+class CSyncRenderer;
+
+// Base allocator-presenter
+class CBaseAP:
+ public ISubPicAllocatorPresenterImpl
+{
+protected:
+ CRenderersSettings::CRendererSettingsEVR m_LastRendererSettings;
+
+ HMODULE m_hDWMAPI;
+ HRESULT (__stdcall * m_pDwmIsCompositionEnabled)(__out BOOL* pfEnabled);
+ HRESULT (__stdcall * m_pDwmEnableComposition)(UINT uCompositionAction);
+ HMODULE m_hD3D9;
+ HRESULT (__stdcall * m_pDirect3DCreate9Ex)(UINT SDKVersion, IDirect3D9Ex**);
+
+ CCritSec m_allocatorLock;
+ CComPtr<IDirect3D9Ex> m_pD3DEx;
+ CComPtr<IDirect3D9> m_pD3D;
+ CComPtr<IDirect3DDevice9Ex> m_pD3DDevEx;
+ CComPtr<IDirect3DDevice9> m_pD3DDev;
+
+ CComPtr<IDirect3DTexture9> m_pVideoTexture[MAX_PICTURE_SLOTS];
+ CComPtr<IDirect3DSurface9> m_pVideoSurface[MAX_PICTURE_SLOTS];
+ CComPtr<IDirect3DTexture9> m_pOSDTexture;
+ CComPtr<IDirect3DSurface9> m_pOSDSurface;
+ CComPtr<ID3DXLine> m_pLine;
+ CComPtr<ID3DXFont> m_pFont;
+ CComPtr<ID3DXSprite> m_pSprite;
+ CSyncRenderer *m_pOuterEVR;
+
+ class CExternalPixelShader
+ {
+ public:
+ CComPtr<IDirect3DPixelShader9> m_pPixelShader;
+ CStringA m_SourceData;
+ CStringA m_SourceTarget;
+ HRESULT Compile(CPixelShaderCompiler *pCompiler)
+ {
+ HRESULT hr = pCompiler->CompileShader(m_SourceData, "main", m_SourceTarget, 0, &m_pPixelShader);
+ if(FAILED(hr)) return hr;
+ return S_OK;
+ }
+ };
+
+ CAutoPtr<CPixelShaderCompiler> m_pPSC;
+ CAtlList<CExternalPixelShader> m_pPixelShaders;
+ CAtlList<CExternalPixelShader> m_pPixelShadersScreenSpace;
+ CComPtr<IDirect3DPixelShader9> m_pResizerPixelShader[4]; // bl, bc1, bc2_1, bc2_2
+ CComPtr<IDirect3DTexture9> m_pScreenSizeTemporaryTexture[2];
+
+ D3DFORMAT m_SurfaceType;
+ D3DFORMAT m_BackbufferType;
+ D3DFORMAT m_DisplayType;
+ D3DTEXTUREFILTERTYPE m_filter;
+ D3DCAPS9 m_caps;
+ D3DPRESENT_PARAMETERS pp;
+
+ bool SettingsNeedResetDevice();
+ void SendResetRequest();
+ virtual HRESULT CreateDXDevice(CString &_Error);
+ virtual HRESULT ResetDXDevice(CString &_Error);
+ virtual HRESULT AllocSurfaces(D3DFORMAT Format = D3DFMT_A8R8G8B8);
+ virtual void DeleteSurfaces();
+
+ HANDLE m_hEvtQuit; // Stop rendering thread event
+ LONGLONG m_LastAdapterCheck;
+ UINT m_CurrentAdapter;
+ UINT GetAdapter(IDirect3D9 *pD3D);
+
+ float m_bicubicA;
+ HRESULT InitResizers(float bicubicA, bool bNeedScreenSizeTexture);
+
+ // Functions to trace timing performance
+ void SyncStats(LONGLONG syncTime);
+ void SyncOffsetStats(LONGLONG syncOffset);
+ void DrawText(const RECT &rc, const CString &strText, int _Priority);
+ void DrawStats();
+
+ template<int texcoords>
+ void AdjustQuad(MYD3DVERTEX<texcoords>* v, double dx, double dy);
+ template<int texcoords>
+ HRESULT TextureBlt(IDirect3DDevice9* pD3DDev, MYD3DVERTEX<texcoords> v[4], D3DTEXTUREFILTERTYPE filter);
+ MFOffset GetOffset(float v);
+ MFVideoArea GetArea(float x, float y, DWORD width, DWORD height);
+ bool ClipToSurface(IDirect3DSurface9* pSurface, CRect& s, CRect& d);
+
+ HRESULT DrawRectBase(IDirect3DDevice9* pD3DDev, MYD3DVERTEX<0> v[4]);
+ HRESULT DrawRect(DWORD _Color, DWORD _Alpha, const CRect &_Rect);
+ HRESULT TextureCopy(IDirect3DTexture9* pTexture);
+ HRESULT TextureResize(IDirect3DTexture9* pTexture, Vector dst[4], D3DTEXTUREFILTERTYPE filter, const CRect &SrcRect);
+ HRESULT TextureResizeBilinear(IDirect3DTexture9* pTexture, Vector dst[4], const CRect &SrcRect);
+ HRESULT TextureResizeBicubic1pass(IDirect3DTexture9* pTexture, Vector dst[4], const CRect &SrcRect);
+ HRESULT TextureResizeBicubic2pass(IDirect3DTexture9* pTexture, Vector dst[4], const CRect &SrcRect);
+
+ typedef HRESULT (WINAPI * D3DXLoadSurfaceFromMemoryPtr)(
+ LPDIRECT3DSURFACE9 pDestSurface,
+ CONST PALETTEENTRY* pDestPalette,
+ CONST RECT* pDestRect,
+ LPCVOID pSrcMemory,
+ D3DFORMAT SrcFormat,
+ UINT SrcPitch,
+ CONST PALETTEENTRY* pSrcPalette,
+ CONST RECT* pSrcRect,
+ DWORD Filter,
+ D3DCOLOR ColorKey);
+
+ typedef HRESULT (WINAPI* D3DXCreateLinePtr)
+ (LPDIRECT3DDEVICE9 pDevice,
+ LPD3DXLINE* ppLine);
+
+ typedef HRESULT (WINAPI* D3DXCreateFontPtr)(
+ LPDIRECT3DDEVICE9 pDevice,
+ int Height,
+ UINT Width,
+ UINT Weight,
+ UINT MipLevels,
+ bool Italic,
+ DWORD CharSet,
+ DWORD OutputPrecision,
+ DWORD Quality,
+ DWORD PitchAndFamily,
+ LPCWSTR pFaceName,
+ LPD3DXFONT* ppFont);
+
+ HRESULT AlphaBlt(RECT* pSrc, RECT* pDst, IDirect3DTexture9* pTexture);
+
+ virtual void OnResetDevice() {};
+
+ int m_nTearingPos;
+ VMR9AlphaBitmap m_VMR9AlphaBitmap;
+ CAutoVectorPtr<BYTE> m_VMR9AlphaBitmapData;
+ CRect m_VMR9AlphaBitmapRect;
+ int m_VMR9AlphaBitmapWidthBytes;
+
+ D3DXLoadSurfaceFromMemoryPtr m_pD3DXLoadSurfaceFromMemory;
+ D3DXCreateLinePtr m_pD3DXCreateLine;
+ D3DXCreateFontPtr m_pD3DXCreateFont;
+ HRESULT (__stdcall *m_pD3DXCreateSprite)(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE * ppSprite);
+
+ int m_nDXSurface; // Total number of DX Surfaces
+ int m_nVMR9Surfaces;
+ int m_iVMR9Surface;
+ int m_nCurSurface; // Surface currently displayed
+ long m_nUsedBuffer;
+
+ LONG m_lNextSampleWait; // Waiting time for next sample in EVR
+ bool m_bSnapToVSync; // True if framerate is low enough so that snap to vsync makes sense
+
+ UINT m_uScanLineEnteringPaint; // The active scan line when entering Paint()
+ REFERENCE_TIME m_llEstVBlankTime; // Next vblank start time in reference clock "coordinates"
+
+ double m_fAvrFps; // Estimate the true FPS as given by the distance between vsyncs when a frame has been presented
+ double m_fJitterStdDev; // VSync estimate std dev
+ double m_fJitterMean; // Mean time between two syncpulses when a frame has been presented (i.e. when Paint() has been called
+
+ double m_fSyncOffsetAvr; // Mean time between the call of Paint() and vsync. To avoid tearing this should be several ms at least
+ double m_fSyncOffsetStdDev; // The std dev of the above
+
+ bool m_bHighColorResolution;
+ bool m_bCompositionEnabled;
+ bool m_bDesktopCompositionDisabled;
+ bool m_bIsFullscreen;
+ bool m_bNeedCheckSample;
+ DWORD m_dMainThreadId;
+
+ CSize m_ScreenSize;
+
+ // Display and frame rates and cycles
+ double m_dDetectedScanlineTime; // Time for one (horizontal) scan line. Extracted at stream start and used to calculate vsync time
+ UINT m_uD3DRefreshRate; // As got when creating the d3d device
+ double m_dD3DRefreshCycle; // Display refresh cycle ms
+ double m_dEstRefreshCycle; // As estimated from scan lines
+ double m_dFrameCycle; // Average sample time, extracted from the samples themselves
+ // double m_fps is defined in ISubPic.h
+ double m_dOptimumDisplayCycle; // The display cycle that is closest to the frame rate. A multiple of the actual display cycle
+ double m_dCycleDifference; // Difference in video and display cycle time relative to the video cycle time
+
+ UINT m_pcFramesDropped;
+ UINT m_pcFramesDuplicated;
+ UINT m_pcFramesDrawn;
+
+ LONGLONG m_pllJitter [NB_JITTER]; // Vertical sync time stats
+ LONGLONG m_pllSyncOffset [NB_JITTER]; // Sync offset time stats
+ int m_nNextJitter;
+ int m_nNextSyncOffset;
+ LONGLONG m_JitterStdDev;
+
+ LONGLONG m_llLastSyncTime;
+
+ LONGLONG m_MaxJitter;
+ LONGLONG m_MinJitter;
+ LONGLONG m_MaxSyncOffset;
+ LONGLONG m_MinSyncOffset;
+ UINT m_uSyncGlitches;
+
+ LONGLONG m_llSampleTime, m_llLastSampleTime; // Present time for the current sample
+ LONG m_lSampleLatency, m_lLastSampleLatency; // Time between intended and actual presentation time
+ LONG m_lMinSampleLatency, m_lLastMinSampleLatency;
+ LONGLONG m_llHysteresis;
+ LONG m_lHysteresis;
+ LONG m_lShiftToNearest, m_lShiftToNearestPrev;
+ bool m_bVideoSlowerThanDisplay;
+
+ int m_bInterlaced;
+ double m_TextScale;
+ CString m_strStatsMsg[10];
+
+ CGenlock *m_pGenlock; // The video - display synchronizer class
+ CComPtr<IReferenceClock> m_pRefClock; // The reference clock. Used in Paint()
+ CComPtr<IAMAudioRendererStats> m_pAudioStats; // Audio statistics from audio renderer. To check so that audio is in sync
+ DWORD m_lAudioLag; // Time difference between audio and video when the audio renderer is matching rate to the external reference clock
+ long m_lAudioLagMin, m_lAudioLagMax; // The accumulated difference between the audio renderer and the master clock
+ DWORD m_lAudioSlaveMode; // To check whether the audio renderer matches rate with SyncClock (returns the value 4 if it does)
+
+ double GetRefreshRate(); // Get the best estimate of the display refresh rate in Hz
+ double GetDisplayCycle(); // Get the best estimate of the display cycle time in milliseconds
+ double GetCycleDifference(); // Get the difference in video and display cycle times.
+ void EstimateRefreshTimings(); // Estimate the times for one scan line and one frame respectively from the actual refresh data
+ bool ExtractInterlaced(const AM_MEDIA_TYPE* pmt);
+
+public:
+ CBaseAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString &_Error);
+ ~CBaseAP();
+
+ CCritSec m_VMR9AlphaBitmapLock;
+ void UpdateAlphaBitmap();
+ void ResetStats();
+
+ // ISubPicAllocatorPresenter
+ STDMETHODIMP CreateRenderer(IUnknown** ppRenderer);
+ STDMETHODIMP_(bool) Paint(bool fAll);
+ STDMETHODIMP GetDIB(BYTE* lpDib, DWORD* size);
+ STDMETHODIMP SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget);
+ STDMETHODIMP SetPixelShader2(LPCSTR pSrcData, LPCSTR pTarget, bool bScreenSpace);
+ STDMETHODIMP_(bool) ResetDevice();
+};
+
+class CSyncAP:
+ public CBaseAP,
+ public IMFGetService,
+ public IMFTopologyServiceLookupClient,
+ public IMFVideoDeviceID,
+ public IMFVideoPresenter,
+ public IDirect3DDeviceManager9,
+ public IMFAsyncCallback,
+ public IQualProp,
+ public IMFRateSupport,
+ public IMFVideoDisplayControl,
+ public IEVRTrustedVideoPlugin,
+ public ISyncClockAdviser
+
+{
+public:
+ CSyncAP(HWND hWnd, bool bFullscreen, HRESULT& hr, CString &_Error);
+ ~CSyncAP(void);
+
+ DECLARE_IUNKNOWN;
+ STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);
+
+ STDMETHODIMP CreateRenderer(IUnknown** ppRenderer);
+ STDMETHODIMP_(bool) Paint(bool fAll);
+ STDMETHODIMP GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight);
+ STDMETHODIMP InitializeDevice(AM_MEDIA_TYPE* pMediaType);
+ STDMETHODIMP_(bool) ResetDevice();
+
+ // IMFClockStateSink
+ STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset);
+ STDMETHODIMP STDMETHODCALLTYPE OnClockStop(MFTIME hnsSystemTime);
+ STDMETHODIMP STDMETHODCALLTYPE OnClockPause(MFTIME hnsSystemTime);
+ STDMETHODIMP STDMETHODCALLTYPE OnClockRestart(MFTIME hnsSystemTime);
+ STDMETHODIMP STDMETHODCALLTYPE OnClockSetRate(MFTIME hnsSystemTime, float flRate);
+
+ // IBaseFilter delegate
+ bool GetState( DWORD dwMilliSecsTimeout, FILTER_STATE *State, HRESULT &_ReturnValue);
+
+ // IQualProp (EVR statistics window). These are incompletely implemented currently
+ STDMETHODIMP get_FramesDroppedInRenderer(int *pcFrames);
+ STDMETHODIMP get_FramesDrawn(int *pcFramesDrawn);
+ STDMETHODIMP get_AvgFrameRate(int *piAvgFrameRate);
+ STDMETHODIMP get_Jitter(int *iJitter);
+ STDMETHODIMP get_AvgSyncOffset(int *piAvg);
+ STDMETHODIMP get_DevSyncOffset(int *piDev);
+
+ // IMFRateSupport
+ STDMETHODIMP GetSlowestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float *pflRate);
+ STDMETHODIMP GetFastestRate(MFRATE_DIRECTION eDirection, BOOL fThin, float *pflRate);
+ STDMETHODIMP IsRateSupported(BOOL fThin, float flRate, float *pflNearestSupportedRate);
+ float GetMaxRate(BOOL bThin);
+
+ // IMFVideoPresenter
+ STDMETHODIMP ProcessMessage(MFVP_MESSAGE_TYPE eMessage, ULONG_PTR ulParam);
+ STDMETHODIMP GetCurrentMediaType(__deref_out IMFVideoMediaType **ppMediaType);
+
+ // IMFTopologyServiceLookupClient
+ STDMETHODIMP InitServicePointers(__in IMFTopologyServiceLookup *pLookup);
+ STDMETHODIMP ReleaseServicePointers();
+
+ // IMFVideoDeviceID
+ STDMETHODIMP GetDeviceID(__out IID *pDeviceID);
+
+ // IMFGetService
+ STDMETHODIMP GetService (__RPC__in REFGUID guidService, __RPC__in REFIID riid, __RPC__deref_out_opt LPVOID *ppvObject);
+
+ // IMFAsyncCallback
+ STDMETHODIMP GetParameters(__RPC__out DWORD *pdwFlags, /* [out] */ __RPC__out DWORD *pdwQueue);
+ STDMETHODIMP Invoke(__RPC__in_opt IMFAsyncResult *pAsyncResult);
+
+ // IMFVideoDisplayControl
+ STDMETHODIMP GetNativeVideoSize(SIZE *pszVideo, SIZE *pszARVideo);
+ STDMETHODIMP GetIdealVideoSize(SIZE *pszMin, SIZE *pszMax);
+ STDMETHODIMP SetVideoPosition(const MFVideoNormalizedRect *pnrcSource, const LPRECT prcDest);
+ STDMETHODIMP GetVideoPosition(MFVideoNormalizedRect *pnrcSource, LPRECT prcDest);
+ STDMETHODIMP SetAspectRatioMode(DWORD dwAspectRatioMode);
+ STDMETHODIMP GetAspectRatioMode(DWORD *pdwAspectRatioMode);
+ STDMETHODIMP SetVideoWindow(HWND hwndVideo);
+ STDMETHODIMP GetVideoWindow(HWND *phwndVideo);
+ STDMETHODIMP RepaintVideo( void);
+ STDMETHODIMP GetCurrentImage(BITMAPINFOHEADER *pBih, BYTE **pDib, DWORD *pcbDib, LONGLONG *pTimeStamp);
+ STDMETHODIMP SetBorderColor(COLORREF Clr);
+ STDMETHODIMP GetBorderColor(COLORREF *pClr);
+ STDMETHODIMP SetRenderingPrefs(DWORD dwRenderFlags);
+ STDMETHODIMP GetRenderingPrefs(DWORD *pdwRenderFlags);
+ STDMETHODIMP SetFullscreen(BOOL fFullscreen);
+ STDMETHODIMP GetFullscreen(BOOL *pfFullscreen);
+
+ // IEVRTrustedVideoPlugin
+ STDMETHODIMP IsInTrustedVideoMode(BOOL *pYes);
+ STDMETHODIMP CanConstrict(BOOL *pYes);
+ STDMETHODIMP SetConstriction(DWORD dwKPix);
+ STDMETHODIMP DisableImageExport(BOOL bDisable);
+
+ // IDirect3DDeviceManager9
+ STDMETHODIMP ResetDevice(IDirect3DDevice9 *pDevice,UINT resetToken);
+ STDMETHODIMP OpenDeviceHandle(HANDLE *phDevice);
+ STDMETHODIMP CloseDeviceHandle(HANDLE hDevice);
+ STDMETHODIMP TestDevice(HANDLE hDevice);
+ STDMETHODIMP LockDevice(HANDLE hDevice, IDirect3DDevice9 **ppDevice, BOOL fBlock);
+ STDMETHODIMP UnlockDevice(HANDLE hDevice, BOOL fSaveState);
+ STDMETHODIMP GetVideoService(HANDLE hDevice, REFIID riid, void **ppService);
+
+protected:
+ void OnResetDevice();
+ MFCLOCK_STATE m_LastClockState;
+
+private:
+ // dxva.dll
+ typedef HRESULT (__stdcall *PTR_DXVA2CreateDirect3DDeviceManager9)(UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager);
+ // mf.dll
+ typedef HRESULT (__stdcall *PTR_MFCreatePresentationClock)(IMFPresentationClock** ppPresentationClock);
+ // evr.dll
+ typedef HRESULT (__stdcall *PTR_MFCreateDXSurfaceBuffer)(REFIID riid, IUnknown* punkSurface, BOOL fBottomUpWhenLinear, IMFMediaBuffer** ppBuffer);
+ typedef HRESULT (__stdcall *PTR_MFCreateVideoSampleFromSurface)(IUnknown* pUnkSurface, IMFSample** ppSample);
+ typedef HRESULT (__stdcall *PTR_MFCreateVideoMediaType)(const MFVIDEOFORMAT* pVideoFormat, IMFVideoMediaType** ppIVideoMediaType);
+ // avrt.dll
+ typedef HANDLE (__stdcall *PTR_AvSetMmThreadCharacteristicsW)(LPCWSTR TaskName, LPDWORD TaskIndex);
+ typedef BOOL (__stdcall *PTR_AvSetMmThreadPriority)(HANDLE AvrtHandle, AVRT_PRIORITY Priority);
+ typedef BOOL (__stdcall *PTR_AvRevertMmThreadCharacteristics)(HANDLE AvrtHandle);
+
+ typedef enum
+ {
+ Started = State_Running,
+ Stopped = State_Stopped,
+ Paused = State_Paused,
+ Shutdown = State_Running + 1
+ } RENDER_STATE;
+
+ CComPtr<IMFClock> m_pClock;
+ CComPtr<IDirect3DDeviceManager9> m_pD3DManager;
+ CComPtr<IMFTransform> m_pMixer;
+ CComPtr<IMediaEventSink> m_pSink;
+ CComPtr<IMFVideoMediaType> m_pMediaType;
+ MFVideoAspectRatioMode m_dwVideoAspectRatioMode;
+ MFVideoRenderPrefs m_dwVideoRenderPrefs;
+ COLORREF m_BorderColor;
+
+ HANDLE m_hEvtQuit; // Stop rendering thread event
+ bool m_bEvtQuit;
+ HANDLE m_hEvtFlush; // Discard all buffers
+ bool m_bEvtFlush;
+ HANDLE m_hEvtSkip; // Skip frame
+ bool m_bEvtSkip;
+
+ bool m_bUseInternalTimer;
+ int32 m_LastSetOutputRange;
+ bool m_bPendingRenegotiate;
+ bool m_bPendingMediaFinished;
+ bool m_bPrerolled; // true if first sample has been displayed.
+
+ HANDLE m_hRenderThread;
+ HANDLE m_hMixerThread;
+ RENDER_STATE m_nRenderState;
+ bool m_bStepping;
+
+ CCritSec m_SampleQueueLock;
+ CCritSec m_ImageProcessingLock;
+
+ CInterfaceList<IMFSample, &IID_IMFSample> m_FreeSamples;
+ CInterfaceList<IMFSample, &IID_IMFSample> m_ScheduledSamples;
+ IMFSample *m_pCurrentDisplaydSample;
+ UINT m_nResetToken;
+ int m_nStepCount;
+
+ bool GetSampleFromMixer();
+ void MixerThread();
+ static DWORD WINAPI MixerThreadStatic(LPVOID lpParam);
+ void RenderThread();
+ static DWORD WINAPI RenderThreadStatic(LPVOID lpParam);
+
+ void StartWorkerThreads();
+ void StopWorkerThreads();
+ HRESULT CheckShutdown() const;
+ void CompleteFrameStep(bool bCancel);
+
+ void RemoveAllSamples();
+ STDMETHODIMP AdviseSyncClock(ISyncClock* sC);
+ HRESULT BeginStreaming();
+ HRESULT GetFreeSample(IMFSample** ppSample);
+ HRESULT GetScheduledSample(IMFSample** ppSample, int &_Count);
+ void MoveToFreeList(IMFSample* pSample, bool bTail);
+ void MoveToScheduledList(IMFSample* pSample, bool _bSorted);
+ void FlushSamples();
+ void FlushSamplesInternal();
+
+ LONGLONG GetMediaTypeMerit(IMFMediaType *pMediaType);
+ HRESULT RenegotiateMediaType();
+ HRESULT IsMediaTypeSupported(IMFMediaType* pMixerType);
+ HRESULT CreateProposedOutputType(IMFMediaType* pMixerType, IMFMediaType** pType);
+ HRESULT SetMediaType(IMFMediaType* pType);
+
+ // Functions pointers for Vista/.NET3 specific library
+ PTR_DXVA2CreateDirect3DDeviceManager9 pfDXVA2CreateDirect3DDeviceManager9;
+ PTR_MFCreateDXSurfaceBuffer pfMFCreateDXSurfaceBuffer;
+ PTR_MFCreateVideoSampleFromSurface pfMFCreateVideoSampleFromSurface;
+ PTR_MFCreateVideoMediaType pfMFCreateVideoMediaType;
+
+ PTR_AvSetMmThreadCharacteristicsW pfAvSetMmThreadCharacteristicsW;
+ PTR_AvSetMmThreadPriority pfAvSetMmThreadPriority;
+ PTR_AvRevertMmThreadCharacteristics pfAvRevertMmThreadCharacteristics;
+};
+
+class CSyncRenderer:
+ public CUnknown,
+ public IVMRffdshow9,
+ public IVMRMixerBitmap9,
+ public IBaseFilter
+{
+ CComPtr<IUnknown> m_pEVR;
+ VMR9AlphaBitmap *m_pVMR9AlphaBitmap;
+ CSyncAP *m_pAllocatorPresenter;
+
+public:
+ CSyncRenderer(const TCHAR* pName, LPUNKNOWN pUnk, HRESULT& hr, VMR9AlphaBitmap* pVMR9AlphaBitmap, CSyncAP *pAllocatorPresenter);
+ ~CSyncRenderer();
+
+ // IBaseFilter
+ virtual HRESULT STDMETHODCALLTYPE EnumPins(__out IEnumPins **ppEnum);
+ virtual HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, __out IPin **ppPin);
+ virtual HRESULT STDMETHODCALLTYPE QueryFilterInfo(__out FILTER_INFO *pInfo);
+ virtual HRESULT STDMETHODCALLTYPE JoinFilterGraph(__in_opt IFilterGraph *pGraph, __in_opt LPCWSTR pName);
+ virtual HRESULT STDMETHODCALLTYPE QueryVendorInfo(__out LPWSTR *pVendorInfo);
+ virtual HRESULT STDMETHODCALLTYPE Stop(void);
+ virtual HRESULT STDMETHODCALLTYPE Pause(void);
+ virtual HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart);
+ virtual HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, __out FILTER_STATE *State);
+ virtual HRESULT STDMETHODCALLTYPE SetSyncSource(__in_opt IReferenceClock *pClock);
+ virtual HRESULT STDMETHODCALLTYPE GetSyncSource(__deref_out_opt IReferenceClock **pClock);
+ virtual HRESULT STDMETHODCALLTYPE GetClassID(__RPC__out CLSID *pClassID);
+
+ // IVMRffdshow9
+ virtual HRESULT STDMETHODCALLTYPE support_ffdshow();
+
+ // IVMRMixerBitmap9
+ STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms);
+ STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms);
+ STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms);
+
+ DECLARE_IUNKNOWN;
+ virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid, void** ppvObject);
+};
+
+class CGenlock
+{
+public:
+ class MovingAverage
+ {
+ public:
+ MovingAverage(INT size):
+ fifoSize(size),
+ oldestSample(0),
+ sum(0)
+ {
+ if (fifoSize > MAX_FIFO_SIZE)
+ {
+ fifoSize = MAX_FIFO_SIZE;
+ }
+ for (INT i = 0; i < MAX_FIFO_SIZE; i++)
+ fifo[i] = 0;
+ }
+
+ ~MovingAverage()
+ {
+ }
+
+ double Average(double sample)
+ {
+ sum = sum + sample - fifo[oldestSample];
+ fifo[oldestSample] = sample;
+ oldestSample++;
+ if (oldestSample == fifoSize)
+ oldestSample = 0;
+ return sum / fifoSize;
+ }
+
+ private:
+ INT fifoSize;
+ double fifo[MAX_FIFO_SIZE];
+ INT oldestSample;
+ double sum;
+ };
+
+ CGenlock(DOUBLE target, DOUBLE limit, INT rowD, INT colD, DOUBLE clockD, UINT mon);
+ ~CGenlock();
+
+ BOOL PowerstripRunning(); // TRUE if PowerStrip is running
+ HRESULT GetTiming(); // Get the string representing the display's current timing parameters
+ HRESULT ResetTiming(); // Reset timing to what was last registered by GetTiming()
+ HRESULT ResetClock(); // Reset reference clock speed to nominal
+ HRESULT SetTargetSyncOffset(DOUBLE targetD);
+ HRESULT GetTargetSyncOffset(DOUBLE *targetD);
+ HRESULT SetControlLimit(DOUBLE cL);
+ HRESULT GetControlLimit(DOUBLE *cL);
+ HRESULT SetDisplayResolution(UINT columns, UINT lines);
+ HRESULT AdviseSyncClock(ISyncClock* sC);
+ HRESULT SetMonitor(UINT mon); // Set the number of the monitor to synchronize
+ HRESULT ResetStats(); // Reset timing statistics
+
+ HRESULT ControlDisplay(double syncOffset, double frameCycle); // Adjust the frequency of the display if needed
+ HRESULT ControlClock(double syncOffset, double frameCycle); // Adjust the frequency of the clock if needed
+ HRESULT UpdateStats(double syncOffset, double frameCycle); // Don't adjust anything, just update the syncOffset stats
+
+ BOOL powerstripTimingExists; // TRUE if display timing has been got through Powerstrip
+ BOOL liveSource; // TRUE if live source -> display sync is the only option
+ INT adjDelta; // -1 for display slower in relation to video, 0 for keep, 1 for faster
+ INT lineDelta; // The number of rows added or subtracted when adjusting display fps
+ INT columnDelta; // The number of colums added or subtracted when adjusting display fps
+ DOUBLE cycleDelta; // Adjustment factor for cycle time as fraction of nominal value
+ UINT displayAdjustmentsMade; // The number of adjustments made to display refresh rate
+ UINT clockAdjustmentsMade; // The number of adjustments made to clock frequency
+
+ UINT totalLines, totalColumns; // Including the porches and sync widths
+ UINT visibleLines, visibleColumns; // The nominal resolution
+ MovingAverage *syncOffsetFifo;
+ MovingAverage *frameCycleFifo;
+ DOUBLE minSyncOffset, maxSyncOffset;
+ DOUBLE syncOffsetAvg; // Average of the above
+ DOUBLE minFrameCycle, maxFrameCycle;
+ DOUBLE frameCycleAvg;
+
+ UINT pixelClock; // In pixels/s
+ DOUBLE displayFreqCruise; // Nominal display frequency in frames/s
+ DOUBLE displayFreqSlower;
+ DOUBLE displayFreqFaster;
+ DOUBLE curDisplayFreq; // Current (adjusted) display frequency
+ DOUBLE controlLimit; // How much the sync offset is allowed to drift from target sync offset
+ WPARAM monitor; // The monitor to be controlled. 0-based.
+ CComPtr<ISyncClock> syncClock; // Interface to an adjustable reference clock
+
+private:
+ HWND psWnd; // PowerStrip window
+ const static INT TIMING_PARAM_CNT = 10;
+ const static INT MAX_LOADSTRING = 100;
+ UINT displayTiming[TIMING_PARAM_CNT]; // Display timing parameters
+ UINT displayTimingSave[TIMING_PARAM_CNT]; // So that we can reset the display at exit
+ TCHAR faster[MAX_LOADSTRING]; // String corresponding to faster display frequency
+ TCHAR cruise[MAX_LOADSTRING]; // String corresponding to nominal display frequency
+ TCHAR slower[MAX_LOADSTRING]; // String corresponding to slower display frequency
+ TCHAR savedTiming[MAX_LOADSTRING]; // String version of saved timing (to be restored upon exit)
+ DOUBLE lowSyncOffset; // The closest we want to let the scheduled render time to get to the next vsync. In % of the frame time
+ DOUBLE targetSyncOffset; // Where we want the scheduled render time to be in relation to the next vsync
+ DOUBLE highSyncOffset; // The furthers we want to let the scheduled render time to get to the next vsync
+ CCritSec csGenlockLock;
+};
+}
diff --git a/src/filters/renderer/VideoRenderers/VMR7AllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/VMR7AllocatorPresenter.cpp new file mode 100644 index 000000000..a450fdc32 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/VMR7AllocatorPresenter.cpp @@ -0,0 +1,369 @@ +/*
+ * $Id: DX7AllocatorPresenter.cpp 1813 2010-04-27 02:03:56Z kinddragon $
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include "RenderersSettings.h"
+
+#include "VMR7AllocatorPresenter.h"
+#include "IPinHook.h"
+
+extern bool g_bNoDuration; // Defined in MainFrm.cpp
+extern bool g_bExternalSubtitleTime;
+
+using namespace DSObjects;
+
+//
+// CVMR7AllocatorPresenter
+//
+
+#define MY_USER_ID 0x6ABE51
+
+CVMR7AllocatorPresenter::CVMR7AllocatorPresenter(HWND hWnd, HRESULT& hr)
+ : CDX7AllocatorPresenter(hWnd, hr)
+ , m_fUseInternalTimer(false)
+{
+ if(FAILED(hr))
+ return;
+
+ if(FAILED(hr = m_pSA.CoCreateInstance(CLSID_AllocPresenter)))
+ {
+ hr = E_FAIL;
+ return;
+ }
+}
+
+STDMETHODIMP CVMR7AllocatorPresenter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
+{
+ CheckPointer(ppv, E_POINTER);
+
+ return
+ QI(IVMRSurfaceAllocator)
+ QI(IVMRImagePresenter)
+ QI(IVMRWindowlessControl)
+ __super::NonDelegatingQueryInterface(riid, ppv);
+}
+
+HRESULT CVMR7AllocatorPresenter::CreateDevice()
+{
+ HRESULT hr = __super::CreateDevice();
+ if(FAILED(hr)) return hr;
+
+ if(m_pIVMRSurfAllocNotify)
+ {
+ HMONITOR hMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST);
+ if(FAILED(hr = m_pIVMRSurfAllocNotify->ChangeDDrawDevice(m_pDD, hMonitor)))
+ return(false);
+ }
+
+ return hr;
+}
+
+void CVMR7AllocatorPresenter::DeleteSurfaces()
+{
+ CAutoLock cAutoLock(this);
+
+ m_pSA->FreeSurface(MY_USER_ID);
+
+ __super::DeleteSurfaces();
+}
+
+// ISubPicAllocatorPresenter
+
+STDMETHODIMP CVMR7AllocatorPresenter::CreateRenderer(IUnknown** ppRenderer)
+{
+ CheckPointer(ppRenderer, E_POINTER);
+
+ *ppRenderer = NULL;
+
+ HRESULT hr;
+
+ do
+ {
+ CComPtr<IBaseFilter> pBF;
+
+ if(FAILED(hr = pBF.CoCreateInstance(CLSID_VideoMixingRenderer)))
+ break;
+
+ CComQIPtr<IVMRFilterConfig> pConfig = pBF;
+ if(!pConfig)
+ break;
+
+ if(FAILED(hr = pConfig->SetRenderingMode(VMRMode_Renderless)))
+ break;
+
+ CComQIPtr<IVMRSurfaceAllocatorNotify> pSAN = pBF;
+ if(!pSAN)
+ break;
+
+ if(FAILED(hr = pSAN->AdviseSurfaceAllocator(MY_USER_ID, static_cast<IVMRSurfaceAllocator*>(this)))
+ || FAILED(hr = AdviseNotify(pSAN)))
+ break;
+
+ CComPtr<IPin> pPin = GetFirstPin(pBF);
+ CComQIPtr<IMemInputPin> pMemInputPin = pPin;
+ m_fUseInternalTimer = HookNewSegmentAndReceive((IPinC*)(IPin*)pPin, (IMemInputPinC*)(IMemInputPin*)pMemInputPin);
+
+ *ppRenderer = (IUnknown*)pBF.Detach();
+
+ return S_OK;
+ }
+ while(0);
+
+ return E_FAIL;
+}
+
+STDMETHODIMP_(void) CVMR7AllocatorPresenter::SetTime(REFERENCE_TIME rtNow)
+{
+ __super::SetTime(rtNow);
+// m_fUseInternalTimer = false;
+}
+
+// IVMRSurfaceAllocator
+
+STDMETHODIMP CVMR7AllocatorPresenter::AllocateSurface(DWORD_PTR dwUserID, VMRALLOCATIONINFO* lpAllocInfo, DWORD* lpdwBuffer, LPDIRECTDRAWSURFACE7* lplpSurface)
+{
+ if(!lpAllocInfo || !lpdwBuffer || !lplpSurface)
+ return E_POINTER;
+
+ if(!m_pIVMRSurfAllocNotify)
+ return E_FAIL;
+
+ HRESULT hr;
+
+ DeleteSurfaces();
+
+ // HACK: yv12 will fail to blt onto the backbuffer anyway, but if we first
+ // allocate it and then let our FreeSurface callback call m_pSA->FreeSurface,
+ // then that might stall for about 30 seconds because of some unknown buggy code
+ // behind <ddraw surface>->Release()
+
+ if(lpAllocInfo->lpHdr->biBitCount < 16)
+ return E_FAIL;
+
+ hr = m_pSA->AllocateSurface(dwUserID, lpAllocInfo, lpdwBuffer, lplpSurface);
+ if(FAILED(hr))
+ return hr;
+
+ m_NativeVideoSize = CSize(abs(lpAllocInfo->lpHdr->biWidth), abs(lpAllocInfo->lpHdr->biHeight));
+ m_AspectRatio = m_NativeVideoSize;
+ 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;
+
+ // test if the colorspace is acceptable
+ if(FAILED(hr = m_pVideoSurface->Blt(NULL, *lplpSurface, NULL, DDBLT_WAIT, NULL)))
+ {
+ DeleteSurfaces();
+ return hr;
+ }
+
+ DDBLTFX fx;
+ INITDDSTRUCT(fx);
+ fx.dwFillColor = 0;
+ m_pVideoSurface->Blt(NULL, NULL, NULL, DDBLT_WAIT|DDBLT_COLORFILL, &fx);
+
+ return hr;
+}
+
+STDMETHODIMP CVMR7AllocatorPresenter::FreeSurface(DWORD_PTR dwUserID)
+{
+ DeleteSurfaces();
+ return S_OK;
+}
+
+STDMETHODIMP CVMR7AllocatorPresenter::PrepareSurface(DWORD_PTR dwUserID, IDirectDrawSurface7* lpSurface, DWORD dwSurfaceFlags)
+{
+ SetThreadName(-1, "CVMR7AllocatorPresenter");
+
+ if(!lpSurface)
+ return E_POINTER;
+
+ // FIXME: sometimes the msmpeg4/divx3/wmv decoder wants to reuse our
+ // surface (expects it to point to the same mem every time), and to avoid
+ // problems we can't call m_pSA->PrepareSurface (flips? clears?).
+ return S_OK;
+ /*
+ return m_pSA->PrepareSurface(dwUserID, lpSurface, dwSurfaceFlags);
+ */
+}
+
+STDMETHODIMP CVMR7AllocatorPresenter::AdviseNotify(IVMRSurfaceAllocatorNotify* lpIVMRSurfAllocNotify)
+{
+ CAutoLock cAutoLock(this);
+
+ m_pIVMRSurfAllocNotify = lpIVMRSurfAllocNotify;
+
+ HRESULT hr;
+ HMONITOR hMonitor = MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST);
+ if(FAILED(hr = m_pIVMRSurfAllocNotify->SetDDrawDevice(m_pDD, hMonitor)))
+ return hr;
+
+ return m_pSA->AdviseNotify(lpIVMRSurfAllocNotify);
+}
+
+// IVMRImagePresenter
+
+STDMETHODIMP CVMR7AllocatorPresenter::StartPresenting(DWORD_PTR dwUserID)
+{
+ if (!m_bPendingResetDevice)
+ {
+ ASSERT(m_pD3DDev);
+ }
+
+ CAutoLock cAutoLock(this);
+
+ return m_pD3DDev ? S_OK : E_FAIL;
+}
+
+STDMETHODIMP CVMR7AllocatorPresenter::StopPresenting(DWORD_PTR dwUserID)
+{
+ return S_OK;
+}
+
+STDMETHODIMP CVMR7AllocatorPresenter::PresentImage(DWORD_PTR dwUserID, VMRPRESENTATIONINFO* lpPresInfo)
+{
+ if(!lpPresInfo || !lpPresInfo->lpSurf)
+ return E_POINTER;
+
+ CAutoLock cAutoLock(this);
+
+ if (!m_bPendingResetDevice)
+ m_pVideoSurface->Blt(NULL, lpPresInfo->lpSurf, NULL, DDBLT_WAIT, NULL);
+
+ 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 && !g_bExternalSubtitleTime)
+ {
+ __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;
+}
+
+// IVMRWindowlessControl
+//
+// 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 CVMR7AllocatorPresenter::GetNativeVideoSize(LONG* lpWidth, LONG* lpHeight, LONG* lpARWidth, LONG* lpARHeight)
+{
+ CSize vs = m_NativeVideoSize, ar = m_AspectRatio;
+ // DVD Nav. bug workaround fix
+ vs.cx = vs.cy * ar.cx / ar.cy;
+ if(lpWidth) *lpWidth = vs.cx;
+ if(lpHeight) *lpHeight = vs.cy;
+ if(lpARWidth) *lpARWidth = ar.cx;
+ if(lpARHeight) *lpARHeight = ar.cy;
+ return S_OK;
+}
+
+STDMETHODIMP CVMR7AllocatorPresenter::GetMinIdealVideoSize(LONG* lpWidth, LONG* lpHeight)
+{
+ return E_NOTIMPL;
+}
+STDMETHODIMP CVMR7AllocatorPresenter::GetMaxIdealVideoSize(LONG* lpWidth, LONG* lpHeight)
+{
+ return E_NOTIMPL;
+}
+STDMETHODIMP CVMR7AllocatorPresenter::SetVideoPosition(const LPRECT lpSRCRect, const LPRECT lpDSTRect)
+{
+ return E_NOTIMPL; // we have our own method for this
+}
+
+STDMETHODIMP CVMR7AllocatorPresenter::GetVideoPosition(LPRECT lpSRCRect, LPRECT lpDSTRect)
+{
+ CopyRect(lpSRCRect, CRect(CPoint(0, 0), m_NativeVideoSize));
+ CopyRect(lpDSTRect, &m_VideoRect);
+ // DVD Nav. bug workaround fix
+ GetNativeVideoSize(&lpSRCRect->right, &lpSRCRect->bottom, NULL, NULL);
+ return S_OK;
+}
+
+STDMETHODIMP CVMR7AllocatorPresenter::GetAspectRatioMode(DWORD* lpAspectRatioMode)
+{
+ if(lpAspectRatioMode) *lpAspectRatioMode = AM_ARMODE_STRETCHED;
+ return S_OK;
+}
+
+STDMETHODIMP CVMR7AllocatorPresenter::SetAspectRatioMode(DWORD AspectRatioMode)
+{
+ return E_NOTIMPL;
+}
+STDMETHODIMP CVMR7AllocatorPresenter::SetVideoClippingWindow(HWND hwnd)
+{
+ return E_NOTIMPL;
+}
+STDMETHODIMP CVMR7AllocatorPresenter::RepaintVideo(HWND hwnd, HDC hdc)
+{
+ return E_NOTIMPL;
+}
+STDMETHODIMP CVMR7AllocatorPresenter::DisplayModeChanged()
+{
+ return E_NOTIMPL;
+}
+STDMETHODIMP CVMR7AllocatorPresenter::GetCurrentImage(BYTE** lpDib)
+{
+ return E_NOTIMPL;
+}
+STDMETHODIMP CVMR7AllocatorPresenter::SetBorderColor(COLORREF Clr)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CVMR7AllocatorPresenter::GetBorderColor(COLORREF* lpClr)
+{
+ if(lpClr) *lpClr = 0;
+ return S_OK;
+}
+
+STDMETHODIMP CVMR7AllocatorPresenter::SetColorKey(COLORREF Clr)
+{
+ return E_NOTIMPL;
+}
+STDMETHODIMP CVMR7AllocatorPresenter::GetColorKey(COLORREF* lpClr)
+{
+ return E_NOTIMPL;
+}
diff --git a/src/filters/renderer/VideoRenderers/VMR7AllocatorPresenter.h b/src/filters/renderer/VideoRenderers/VMR7AllocatorPresenter.h new file mode 100644 index 000000000..6d6716c08 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/VMR7AllocatorPresenter.h @@ -0,0 +1,84 @@ +/*
+ * $Id: DX7AllocatorPresenter.h 1790 2010-04-18 20:29:12Z tetsuo55 $
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "DX7AllocatorPresenter.h"
+
+namespace DSObjects
+{
+
+ class CVMR7AllocatorPresenter
+ : public CDX7AllocatorPresenter
+ , public IVMRSurfaceAllocator
+ , public IVMRImagePresenter
+ , public IVMRWindowlessControl
+ {
+ CComPtr<IVMRSurfaceAllocatorNotify> m_pIVMRSurfAllocNotify;
+ CComPtr<IVMRSurfaceAllocator> m_pSA;
+
+ HRESULT CreateDevice();
+ void DeleteSurfaces();
+
+ bool m_fUseInternalTimer;
+
+ public:
+ CVMR7AllocatorPresenter(HWND hWnd, HRESULT& hr);
+
+ DECLARE_IUNKNOWN
+ STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv);
+
+ // ISubPicAllocatorPresenter
+ STDMETHODIMP CreateRenderer(IUnknown** ppRenderer);
+ STDMETHODIMP_(void) SetTime(REFERENCE_TIME rtNow);
+
+ // IVMRSurfaceAllocator
+ STDMETHODIMP AllocateSurface(DWORD_PTR dwUserID, VMRALLOCATIONINFO* lpAllocInfo, DWORD* lpdwBuffer, LPDIRECTDRAWSURFACE7* lplpSurface);
+ STDMETHODIMP FreeSurface(DWORD_PTR dwUserID);
+ STDMETHODIMP PrepareSurface(DWORD_PTR dwUserID, IDirectDrawSurface7* lpSurface, DWORD dwSurfaceFlags);
+ STDMETHODIMP AdviseNotify(IVMRSurfaceAllocatorNotify* lpIVMRSurfAllocNotify);
+
+ // IVMRImagePresenter
+ STDMETHODIMP StartPresenting(DWORD_PTR dwUserID);
+ STDMETHODIMP StopPresenting(DWORD_PTR dwUserID);
+ STDMETHODIMP PresentImage(DWORD_PTR dwUserID, VMRPRESENTATIONINFO* lpPresInfo);
+
+ // IVMRWindowlessControl
+ 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);
+ STDMETHODIMP SetColorKey(COLORREF Clr);
+ STDMETHODIMP GetColorKey(COLORREF* lpClr);
+ };
+
+}
diff --git a/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.cpp new file mode 100644 index 000000000..a1a9975be --- /dev/null +++ b/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.cpp @@ -0,0 +1,1058 @@ +/*
+ * $Id$
+ *
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include "VMR9AllocatorPresenter.h"
+#include "IPinHook.h"
+#include "MacrovisionKicker.h"
+
+// ISubPicAllocatorPresenter
+
+namespace DSObjects
+{
+class COuterVMR9
+ : public CUnknown
+ , public IVideoWindow
+ , public IBasicVideo2
+ , public IVMRWindowlessControl
+ , public IVMRffdshow9
+ , public IVMRMixerBitmap9
+{
+ CComPtr<IUnknown> m_pVMR;
+ VMR9AlphaBitmap* m_pVMR9AlphaBitmap;
+ CDX9AllocatorPresenter *m_pAllocatorPresenter;
+
+public:
+
+ COuterVMR9(const TCHAR* pName, LPUNKNOWN pUnk, VMR9AlphaBitmap* pVMR9AlphaBitmap, CDX9AllocatorPresenter *_pAllocatorPresenter) : CUnknown(pName, pUnk)
+ {
+ m_pVMR.CoCreateInstance(CLSID_VideoMixingRenderer9, GetOwner());
+ m_pVMR9AlphaBitmap = pVMR9AlphaBitmap;
+ m_pAllocatorPresenter = _pAllocatorPresenter;
+ }
+
+ ~COuterVMR9()
+ {
+ m_pVMR = NULL;
+ }
+
+ DECLARE_IUNKNOWN;
+ STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv)
+ {
+ HRESULT hr;
+
+ // Casimir666 : en mode Renderless faire l'incrustation à la place du VMR
+ if(riid == __uuidof(IVMRMixerBitmap9))
+ return GetInterface((IVMRMixerBitmap9*)this, ppv);
+
+ 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(IVMRffdshow9)) // Support ffdshow queueing. We show ffdshow that this is patched Media Player Classic.
+ return GetInterface((IVMRffdshow9*)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;
+ }
+ // IVMRffdshow9
+ STDMETHODIMP support_ffdshow()
+ {
+ queue_ffdshow_support = true;
+ return S_OK;
+ }
+
+ 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;
+ }
+
+ // IVMRMixerBitmap9
+ STDMETHODIMP GetAlphaBitmapParameters(VMR9AlphaBitmap* pBmpParms)
+ {
+ CheckPointer(pBmpParms, E_POINTER);
+ CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock);
+ memcpy (pBmpParms, m_pVMR9AlphaBitmap, sizeof(VMR9AlphaBitmap));
+ return S_OK;
+ }
+
+ STDMETHODIMP SetAlphaBitmap(const VMR9AlphaBitmap* pBmpParms)
+ {
+ CheckPointer(pBmpParms, E_POINTER);
+ CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock);
+ memcpy (m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap));
+ m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE;
+ m_pAllocatorPresenter->UpdateAlphaBitmap();
+ return S_OK;
+ }
+
+ STDMETHODIMP UpdateAlphaBitmapParameters(const VMR9AlphaBitmap* pBmpParms)
+ {
+ CheckPointer(pBmpParms, E_POINTER);
+ CAutoLock BitMapLock(&m_pAllocatorPresenter->m_VMR9AlphaBitmapLock);
+ memcpy (m_pVMR9AlphaBitmap, pBmpParms, sizeof(VMR9AlphaBitmap));
+ m_pVMR9AlphaBitmap->dwFlags |= VMRBITMAP_UPDATE;
+ m_pAllocatorPresenter->UpdateAlphaBitmap();
+ return S_OK;
+ }
+};
+}
+
+using namespace DSObjects;
+
+//
+// CVMR9AllocatorPresenter
+//
+
+#define MY_USER_ID 0x6ABE51
+
+CVMR9AllocatorPresenter::CVMR9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString &_Error)
+ : CDX9AllocatorPresenter(hWnd, bFullscreen, hr, false, _Error)
+ , 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(CString &_Error)
+{
+ HRESULT hr = __super::CreateDevice(_Error);
+ if(FAILED(hr))
+ return hr;
+
+ if(m_pIVMRSurfAllocNotify)
+ {
+ HMONITOR hMonitor = m_pD3D->GetAdapterMonitor(m_CurrentAdapter);
+ if(FAILED(hr = m_pIVMRSurfAllocNotify->ChangeD3DDevice(m_pD3DDev, hMonitor)))
+ {
+ _Error += L"m_pIVMRSurfAllocNotify->ChangeD3DDevice failed";
+ return(false);
+ }
+ }
+
+ return hr;
+}
+
+void CVMR9AllocatorPresenter::DeleteSurfaces()
+{
+ CAutoLock cAutoLock(this);
+ CAutoLock cRenderLock(&m_RenderLock);
+
+ m_pSurfaces.RemoveAll();
+
+ return __super::DeleteSurfaces();
+}
+
+STDMETHODIMP CVMR9AllocatorPresenter::CreateRenderer(IUnknown** ppRenderer)
+{
+ CheckPointer(ppRenderer, E_POINTER);
+
+ *ppRenderer = NULL;
+
+ HRESULT hr;
+
+ do
+ {
+ CMacrovisionKicker* pMK = DNew CMacrovisionKicker(NAME("CMacrovisionKicker"), NULL);
+ CComPtr<IUnknown> pUnk = (IUnknown*)(INonDelegatingUnknown*)pMK;
+
+ COuterVMR9 *pOuter = DNew COuterVMR9(NAME("COuterVMR9"), pUnk, &m_VMR9AlphaBitmap, this);
+
+
+ pMK->SetInner((IUnknown*)(INonDelegatingUnknown*)pOuter);
+ CComQIPtr<IBaseFilter> pBF = pUnk;
+
+ 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;
+
+ CRenderersSettings& s = GetRenderersSettings();
+
+ if(s.fVMR9MixerMode)
+ {
+ if(FAILED(hr = pConfig->SetNumberOfStreams(1)))
+ break;
+
+ if(CComQIPtr<IVMRMixerControl9> pMC = pBF)
+ {
+ DWORD dwPrefs;
+ pMC->GetMixingPrefs(&dwPrefs);
+
+ // See http://msdn.microsoft.com/en-us/library/dd390928(VS.85).aspx
+ dwPrefs |= MixerPref9_NonSquareMixing;
+ dwPrefs |= MixerPref9_NoDecimation;
+ if(s.fVMR9MixerYUV && !IsVistaOrAbove())
+ {
+ 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();
+
+ int nOriginal = *lpNumBuffers;
+
+ if (*lpNumBuffers == 1)
+ {
+ *lpNumBuffers = 4;
+ m_nVMR9Surfaces = 4;
+ }
+ else
+ m_nVMR9Surfaces = 0;
+ 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_pSurfaces.SetCount(*lpNumBuffers);
+
+ m_bNeedCheckSample = true;
+ m_NativeVideoSize = CSize(w, h);
+ CSize VideoSize = GetVisibleVideoSize();
+ int arx = lpAllocInfo->szAspectRatio.cx;
+ int ary = lpAllocInfo->szAspectRatio.cy;
+ if(arx > 0 && ary > 0)
+ {
+ arx = arx / ((float) m_NativeVideoSize.cx / VideoSize.cx);
+ ary = ary / ((float) m_NativeVideoSize.cy / VideoSize.cy);
+ m_AspectRatio.SetSize(arx, ary);
+ }
+ else
+ m_AspectRatio = VideoSize;
+
+ 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[m_nCurSurface], NULL, D3DTEXF_NONE)))
+ {
+ DeleteSurfaces();
+ return E_FAIL;
+ }
+ }
+
+ hr = m_pD3DDev->ColorFill(m_pVideoSurface[m_nCurSurface], NULL, 0);
+
+ if (m_nVMR9Surfaces && m_nVMR9Surfaces != *lpNumBuffers)
+ m_nVMR9Surfaces = *lpNumBuffers;
+ *lpNumBuffers = min(nOriginal, *lpNumBuffers);
+ m_iVMR9Surface = 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 cRenderLock(&m_RenderLock);
+
+ if (m_nVMR9Surfaces)
+ {
+ ++m_iVMR9Surface;
+ m_iVMR9Surface = m_iVMR9Surface % m_nVMR9Surfaces;
+ (*lplpSurface = m_pSurfaces[m_iVMR9Surface + SurfaceIndex])->AddRef();
+ }
+ else
+ {
+ m_iVMR9Surface = SurfaceIndex;
+ (*lplpSurface = m_pSurfaces[SurfaceIndex])->AddRef();
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP CVMR9AllocatorPresenter::AdviseNotify(IVMRSurfaceAllocatorNotify9* lpIVMRSurfAllocNotify)
+{
+ CAutoLock cAutoLock(this);
+ CAutoLock cRenderLock(&m_RenderLock);
+
+ 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)
+{
+ if (!m_bPendingResetDevice)
+ {
+ ASSERT(m_pD3DDev);
+ }
+
+ CAutoLock cAutoLock(this);
+ CAutoLock cRenderLock(&m_RenderLock);
+
+ return m_pD3DDev ? S_OK : E_FAIL;
+}
+
+STDMETHODIMP CVMR9AllocatorPresenter::StopPresenting(DWORD_PTR dwUserID)
+{
+ return S_OK;
+}
+
+
+STDMETHODIMP CVMR9AllocatorPresenter::PresentImage(DWORD_PTR dwUserID, VMR9PresentationInfo* lpPresInfo)
+{
+ SetThreadName(-1, "CVMR9AllocatorPresenter");
+ CheckPointer(m_pIVMRSurfAllocNotify, E_UNEXPECTED);
+
+ if (m_rtTimePerFrame == 0 || m_bNeedCheckSample)
+ {
+ m_bNeedCheckSample = false;
+ CComPtr<IBaseFilter> pVMR9;
+ CComPtr<IPin> pPin;
+ CMediaType mt;
+
+ if (SUCCEEDED (m_pIVMRSurfAllocNotify->QueryInterface (__uuidof(IBaseFilter), (void**)&pVMR9)) &&
+ SUCCEEDED (pVMR9->FindPin(L"VMR Input0", &pPin)) &&
+ SUCCEEDED (pPin->ConnectionMediaType(&mt)) )
+ {
+ ExtractAvgTimePerFrame (&mt, m_rtTimePerFrame);
+
+ CSize NativeVideoSize = m_NativeVideoSize;
+ CSize AspectRatio = m_AspectRatio;
+ if (mt.formattype==FORMAT_VideoInfo || mt.formattype==FORMAT_MPEGVideo)
+ {
+ VIDEOINFOHEADER *vh = (VIDEOINFOHEADER*)mt.pbFormat;
+
+ NativeVideoSize = CSize(vh->bmiHeader.biWidth, abs(vh->bmiHeader.biHeight));
+ if (vh->rcTarget.right - vh->rcTarget.left > 0)
+ NativeVideoSize.cx = vh->rcTarget.right - vh->rcTarget.left;
+ else if (vh->rcSource.right - vh->rcSource.left > 0)
+ NativeVideoSize.cx = vh->rcSource.right - vh->rcSource.left;
+
+ if (vh->rcTarget.bottom - vh->rcTarget.top > 0)
+ NativeVideoSize.cy = vh->rcTarget.bottom - vh->rcTarget.top;
+ else if (vh->rcSource.bottom - vh->rcSource.top > 0)
+ NativeVideoSize.cy = vh->rcSource.bottom - vh->rcSource.top;
+ }
+ else if (mt.formattype==FORMAT_VideoInfo2 || mt.formattype==FORMAT_MPEG2Video)
+ {
+ VIDEOINFOHEADER2 *vh = (VIDEOINFOHEADER2*)mt.pbFormat;
+
+ if (vh->dwPictAspectRatioX && vh->dwPictAspectRatioY)
+ AspectRatio = CSize(vh->dwPictAspectRatioX, vh->dwPictAspectRatioY);
+
+ NativeVideoSize = CSize(vh->bmiHeader.biWidth, abs(vh->bmiHeader.biHeight));
+ if (vh->rcTarget.right - vh->rcTarget.left > 0)
+ NativeVideoSize.cx = vh->rcTarget.right - vh->rcTarget.left;
+ else if (vh->rcSource.right - vh->rcSource.left > 0)
+ NativeVideoSize.cx = vh->rcSource.right - vh->rcSource.left;
+
+ if (vh->rcTarget.bottom - vh->rcTarget.top > 0)
+ NativeVideoSize.cy = vh->rcTarget.bottom - vh->rcTarget.top;
+ else if (vh->rcSource.bottom - vh->rcSource.top > 0)
+ NativeVideoSize.cy = vh->rcSource.bottom - vh->rcSource.top;
+ }
+ if (m_NativeVideoSize != NativeVideoSize || m_AspectRatio != AspectRatio)
+ {
+ m_NativeVideoSize = NativeVideoSize;
+ m_AspectRatio = AspectRatio;
+ AfxGetApp()->m_pMainWnd->PostMessage(WM_REARRANGERENDERLESS);
+ }
+ }
+ // If framerate not set by Video Decoder choose 23.97...
+ if (m_rtTimePerFrame == 0) m_rtTimePerFrame = 417166;
+
+ m_fps = 10000000.0 / m_rtTimePerFrame;
+ }
+
+ HRESULT hr;
+
+ if(!lpPresInfo || !lpPresInfo->lpSurf)
+ return E_POINTER;
+
+ CAutoLock cAutoLock(this);
+ CAutoLock cRenderLock(&m_RenderLock);
+
+ if(lpPresInfo->rtEnd > lpPresInfo->rtStart)
+ {
+ if(m_pSubPicQueue)
+ {
+ m_pSubPicQueue->SetFPS(m_fps);
+
+ if(m_fUseInternalTimer && !g_bExternalSubtitleTime)
+ {
+ __super::SetTime(g_tSegmentStart + g_tSampleStart);
+ }
+ }
+ }
+
+ CSize VideoSize = GetVisibleVideoSize();
+ int arx = lpPresInfo->szAspectRatio.cx;
+ int ary = lpPresInfo->szAspectRatio.cy;
+ if(arx > 0 && ary > 0)
+ {
+ arx = arx / ((float) m_NativeVideoSize.cx / VideoSize.cx);
+ ary = ary / ((float) m_NativeVideoSize.cy / VideoSize.cy);
+ VideoSize.cx = VideoSize.cy*arx/ary;
+ }
+ if(VideoSize != GetVideoSize())
+ {
+ m_AspectRatio.SetSize(arx, ary);
+ AfxGetApp()->m_pMainWnd->PostMessage(WM_REARRANGERENDERLESS);
+ }
+
+ if (!m_bPendingResetDevice)
+ {
+ CComPtr<IDirect3DTexture9> pTexture;
+ lpPresInfo->lpSurf->GetContainer(IID_IDirect3DTexture9, (void**)&pTexture);
+
+ if(pTexture)
+ {
+ m_pVideoSurface[m_nCurSurface] = lpPresInfo->lpSurf;
+ if(m_pVideoTexture[m_nCurSurface])
+ m_pVideoTexture[m_nCurSurface] = pTexture;
+ }
+ else
+ {
+ hr = m_pD3DDev->StretchRect(lpPresInfo->lpSurf, NULL, m_pVideoSurface[m_nCurSurface], NULL, D3DTEXF_NONE);
+ }
+
+ // Tear test bars
+ if (GetRenderersData()->m_fTearingTest)
+ {
+ RECT rcTearing;
+
+ rcTearing.left = m_nTearingPos;
+ rcTearing.top = 0;
+ rcTearing.right = rcTearing.left + 4;
+ rcTearing.bottom = m_NativeVideoSize.cy;
+ m_pD3DDev->ColorFill (m_pVideoSurface[m_nCurSurface], &rcTearing, D3DCOLOR_ARGB (255,255,0,0));
+
+ rcTearing.left = (rcTearing.right + 15) % m_NativeVideoSize.cx;
+ rcTearing.right = rcTearing.left + 4;
+ m_pD3DDev->ColorFill (m_pVideoSurface[m_nCurSurface], &rcTearing, D3DCOLOR_ARGB (255,255,0,0));
+
+ m_nTearingPos = (m_nTearingPos + 7) % m_NativeVideoSize.cx;
+ }
+ }
+
+ 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), GetVisibleVideoSize()));
+ 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;
+}
diff --git a/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.h b/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.h new file mode 100644 index 000000000..587839afe --- /dev/null +++ b/src/filters/renderer/VideoRenderers/VMR9AllocatorPresenter.h @@ -0,0 +1,81 @@ +/*
+ * $Id$
+ *
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "DX9AllocatorPresenter.h"
+
+namespace DSObjects
+{
+class CVMR9AllocatorPresenter
+ : public CDX9AllocatorPresenter
+ , public IVMRSurfaceAllocator9
+ , public IVMRImagePresenter9
+ , public IVMRWindowlessControl9
+{
+protected:
+ CComPtr<IVMRSurfaceAllocatorNotify9> m_pIVMRSurfAllocNotify;
+ CInterfaceArray<IDirect3DSurface9> m_pSurfaces;
+
+ HRESULT CreateDevice(CString &_Error);
+ void DeleteSurfaces();
+
+ bool m_fUseInternalTimer;
+ REFERENCE_TIME m_rtPrevStart;
+
+public:
+ CVMR9AllocatorPresenter(HWND hWnd, bool bFullscreen, HRESULT& hr, CString &_Error);
+
+ 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);
+};
+}
diff --git a/src/filters/renderer/VideoRenderers/VideoRenderers.vcproj b/src/filters/renderer/VideoRenderers/VideoRenderers.vcproj new file mode 100644 index 000000000..86ea743ac --- /dev/null +++ b/src/filters/renderer/VideoRenderers/VideoRenderers.vcproj @@ -0,0 +1,536 @@ +<?xml version="1.0" encoding="windows-1250"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="VideoRenderers"
+ ProjectGUID="{FB565A7A-50DC-4A0D-852D-5E7F74DAB82C}"
+ RootNamespace="mplayerc"
+ Keyword="MFCProj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release Unicode|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\common.vsprops;..\..\..\release.vsprops"
+ UseOfMFC="1"
+ UseOfATL="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="1"
+ WholeProgramOptimization="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine=""
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release_unicode/mplayerc.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/MP"
+ AdditionalIncludeDirectories="..\..\..\..\include;..\..\..\..\include\dx;..\..\..\..\include\atl;..\..\BaseClasses;..\..\..\zlib"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;DETOURS_X32"
+ BufferSecurityCheck="true"
+ EnableEnhancedInstructionSet="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile="$(OutDir)\$(ProjectName).pch"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ AdditionalIncludeDirectories=""
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\..\..\..\lib\$(ProjectName)RU.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine=""
+ ExcludedFromBuild="false"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release Unicode|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\common.vsprops;..\..\..\release.vsprops"
+ UseOfMFC="1"
+ UseOfATL="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="1"
+ WholeProgramOptimization="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine=""
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ TargetEnvironment="3"
+ TypeLibraryName=".\Release_unicode/mplayerc.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/MP"
+ AdditionalIncludeDirectories="..\..\..\..\include;..\..\..\..\include\dx;..\..\..\..\include\atl;..\..\BaseClasses;..\..\..\zlib"
+ PreprocessorDefinitions="_WIN64;NDEBUG;_WINDOWS;DETOURS_X64"
+ BufferSecurityCheck="true"
+ EnableEnhancedInstructionSet="0"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile="$(OutDir)\$(ProjectName).pch"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ AdditionalIncludeDirectories=""
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\..\..\..\lib64\$(ProjectName)RU.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine=""
+ ExcludedFromBuild="false"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug Unicode|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\common.vsprops;..\..\..\debug.vsprops"
+ UseOfMFC="1"
+ UseOfATL="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine=""
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ TargetEnvironment="1"
+ TypeLibraryName="$(OutDir)\$(ProjectName).tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/MP"
+ AdditionalIncludeDirectories="..\..\..\..\include;..\..\..\..\include\dx;..\..\..\..\include\atl;..\..\BaseClasses;..\..\..\zlib"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DETOURS_X32"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile="$(OutDir)\$(ProjectName).pch"
+ ShowIncludes="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\..\..\..\lib\$(ProjectName)DU.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug Unicode|x64"
+ OutputDirectory="$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+ ConfigurationType="4"
+ InheritedPropertySheets="..\..\..\common.vsprops;..\..\..\debug.vsprops"
+ UseOfMFC="1"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine=""
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ TargetEnvironment="3"
+ TypeLibraryName="$(OutDir)\$(ProjectName).tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/MP"
+ AdditionalIncludeDirectories="..\..\..\..\include;..\..\..\..\include\dx;..\..\..\..\include\atl;..\..\BaseClasses;..\..\..\zlib"
+ PreprocessorDefinitions="_WIN64;_DEBUG;_WINDOWS;DETOURS_X64"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile="$(OutDir)\$(ProjectName).pch"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="..\..\..\..\lib64\$(ProjectName)DU.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath=".\AllocatorCommon.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\AllocatorCommon7.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\D3DFont.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\DX7AllocatorPresenter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\DX9AllocatorPresenter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\DXRAllocatorPresenter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\EVRAllocatorPresenter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\IPinHook.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\MacrovisionKicker.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\madVRAllocatorPresenter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\PixelShaderCompiler.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\QT7AllocatorPresenter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\QT9AllocatorPresenter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\RenderersSettings.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\RM7AllocatorPresenter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\RM9AllocatorPresenter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\stdafx.cpp"
+ >
+ <FileConfiguration
+ Name="Release Unicode|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\SyncRenderer.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\VMR7AllocatorPresenter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\VMR9AllocatorPresenter.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath=".\AllocatorCommon.h"
+ >
+ </File>
+ <File
+ RelativePath=".\AllocatorCommon7.h"
+ >
+ </File>
+ <File
+ RelativePath=".\D3DFont.h"
+ >
+ </File>
+ <File
+ RelativePath=".\DX7AllocatorPresenter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\DX9AllocatorPresenter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\DXRAllocatorPresenter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\EVRAllocatorPresenter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\IPinHook.h"
+ >
+ </File>
+ <File
+ RelativePath=".\MacrovisionKicker.h"
+ >
+ </File>
+ <File
+ RelativePath=".\madVRAllocatorPresenter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\PixelShaderCompiler.h"
+ >
+ </File>
+ <File
+ RelativePath=".\QT7AllocatorPresenter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\QT9AllocatorPresenter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\RenderersSettings.h"
+ >
+ </File>
+ <File
+ RelativePath=".\RM7AllocatorPresenter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\RM9AllocatorPresenter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\stdafx.h"
+ >
+ </File>
+ <File
+ RelativePath=".\SyncAllocatorPresenter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\SyncRenderer.h"
+ >
+ </File>
+ <File
+ RelativePath=".\VMR7AllocatorPresenter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\VMR9AllocatorPresenter.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ <Global
+ Name="DevPartner_IsInstrumented"
+ Value="1"
+ />
+ <Global
+ Name="RESOURCE_FILE"
+ Value="mplayerc.rc"
+ />
+ </Globals>
+</VisualStudioProject>
diff --git a/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.cpp b/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.cpp new file mode 100644 index 000000000..9da9fdeec --- /dev/null +++ b/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.cpp @@ -0,0 +1,242 @@ +/*
+ * $Id$
+ *
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
+#include "madVRAllocatorPresenter.h"
+#include "RenderersSettings.h"
+#include <moreuuids.h>
+
+using namespace DSObjects;
+
+//
+// CmadVRAllocatorPresenter
+//
+
+CmadVRAllocatorPresenter::CmadVRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString &_Error)
+ : ISubPicAllocatorPresenterImpl(hWnd, hr, &_Error)
+ , m_ScreenSize(0, 0)
+{
+ if(FAILED(hr))
+ {
+ _Error += L"ISubPicAllocatorPresenterImpl failed\n";
+ return;
+ }
+
+ hr = S_OK;
+}
+
+CmadVRAllocatorPresenter::~CmadVRAllocatorPresenter()
+{
+ 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 CmadVRAllocatorPresenter::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 CmadVRAllocatorPresenter::SetDevice(IDirect3DDevice9* pD3DDev)
+{
+ CheckPointer(pD3DDev, E_POINTER);
+
+ CSize size;
+ switch(GetRenderersSettings().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;
+ case 6:
+ size.SetSize(2560, 1600);
+ break;
+ case 7:
+ size.SetSize(1920, 1080);
+ break;
+ case 8:
+ size.SetSize(1320, 900);
+ break;
+ case 9:
+ size.SetSize(1280, 720);
+ break;
+ }
+
+ if(m_pAllocator)
+ {
+ m_pAllocator->ChangeDevice(pD3DDev);
+ }
+ else
+ {
+ m_pAllocator = DNew CDX9SubPicAllocator(pD3DDev, size, GetRenderersSettings().fSPCPow2Tex);
+ if(!m_pAllocator)
+ return E_FAIL;
+ }
+
+ HRESULT hr = S_OK;
+
+ m_pSubPicQueue = GetRenderersSettings().nSPCSize > 0
+ ? (ISubPicQueue*)DNew CSubPicQueue(GetRenderersSettings().nSPCSize, !GetRenderersSettings().fSPCAllowAnimationWhenBuffering, m_pAllocator, &hr)
+ : (ISubPicQueue*)DNew CSubPicQueueNoThread(m_pAllocator, &hr);
+ if(!m_pSubPicQueue || FAILED(hr))
+ return E_FAIL;
+
+ if(m_SubPicProvider) m_pSubPicQueue->SetSubPicProvider(m_SubPicProvider);
+
+ return S_OK;
+}
+
+HRESULT CmadVRAllocatorPresenter::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 CmadVRAllocatorPresenter::CreateRenderer(IUnknown** ppRenderer)
+{
+ CheckPointer(ppRenderer, E_POINTER);
+
+ if(m_pDXR) return E_UNEXPECTED;
+ m_pDXR.CoCreateInstance(CLSID_madVR, GetOwner());
+ if(!m_pDXR) return E_FAIL;
+
+ CComQIPtr<ISubRender> pSR = m_pDXR;
+ if(!pSR)
+ {
+ m_pDXR = NULL;
+ return E_FAIL;
+ }
+
+ m_pSRCB = DNew CSubRenderCallback(this);
+ if(FAILED(pSR->SetCallback(m_pSRCB)))
+ {
+ m_pDXR = NULL;
+ return E_FAIL;
+ }
+
+ (*ppRenderer = this)->AddRef();
+
+ MONITORINFO mi;
+ mi.cbSize = sizeof(MONITORINFO);
+ if (GetMonitorInfo(MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST), &mi))
+ m_ScreenSize.SetSize(mi.rcMonitor.right-mi.rcMonitor.left, mi.rcMonitor.bottom-mi.rcMonitor.top);
+
+ return S_OK;
+}
+
+STDMETHODIMP_(void) CmadVRAllocatorPresenter::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) CmadVRAllocatorPresenter::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) CmadVRAllocatorPresenter::Paint(bool fAll)
+{
+ return false; // TODO
+}
+
+STDMETHODIMP CmadVRAllocatorPresenter::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 CmadVRAllocatorPresenter::SetPixelShader(LPCSTR pSrcData, LPCSTR pTarget)
+{
+ return E_NOTIMPL; // TODO
+}
diff --git a/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.h b/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.h new file mode 100644 index 000000000..1bf230a71 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/madVRAllocatorPresenter.h @@ -0,0 +1,104 @@ +/*
+ * $Id$
+ *
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "AllocatorCommon.h"
+
+namespace DSObjects
+{
+class CmadVRAllocatorPresenter
+ : public ISubPicAllocatorPresenterImpl
+{
+ class CSubRenderCallback : public CUnknown, public ISubRenderCallback, public CCritSec
+ {
+ CmadVRAllocatorPresenter* m_pDXRAP;
+
+ public:
+ CSubRenderCallback(CmadVRAllocatorPresenter* 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(CmadVRAllocatorPresenter* 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;
+ CSize m_ScreenSize;
+
+public:
+ CmadVRAllocatorPresenter(HWND hWnd, HRESULT& hr, CString &_Error);
+ virtual ~CmadVRAllocatorPresenter();
+
+ 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);
+};
+}
diff --git a/src/filters/renderer/VideoRenderers/stdafx.cpp b/src/filters/renderer/VideoRenderers/stdafx.cpp new file mode 100644 index 000000000..346b89373 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/stdafx.cpp @@ -0,0 +1,27 @@ +/*
+ * $Id: stdafx.cpp 1686 2010-02-20 21:26:33Z povaddict $
+ * stdafx.cpp : source file that includes just the standard includes
+ * mplayerc.pch will be the pre-compiled header
+ * stdafx.obj will contain the pre-compiled type information
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "stdafx.h"
diff --git a/src/filters/renderer/VideoRenderers/stdafx.h b/src/filters/renderer/VideoRenderers/stdafx.h new file mode 100644 index 000000000..f7470f231 --- /dev/null +++ b/src/filters/renderer/VideoRenderers/stdafx.h @@ -0,0 +1,57 @@ +/*
+ * $Id: stdafx.h 1785 2010-04-09 14:12:59Z xhmikosr $
+ * stdafx.h : include file for standard system include files,
+ * or project specific include files that are used frequently, but
+ * are changed infrequently
+ *
+ * (C) 2003-2006 Gabest
+ * (C) 2006-2010 see AUTHORS
+ *
+ * This file is part of mplayerc.
+ *
+ * Mplayerc 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.
+ *
+ * Mplayerc 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if !defined(AFX_STDAFX_H__C76533D6_6242_4BEB_8FD3_C6BE58F07225__INCLUDED_)
+#define AFX_STDAFX_H__C76533D6_6242_4BEB_8FD3_C6BE58F07225__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+#include "../../../DSUtil/SharedInclude.h"
+
+//#define _WIN32_IE 0x0600
+#define WINVER 0x0600
+
+#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
+
+#define ResStr(id) CString(MAKEINTRESOURCE(id))
+
+#include <afxdisp.h>
+#include <afxole.h>
+
+#include <streams.h>
+#include <dvdmedia.h>
+#include <mpconfig.h>
+#ifndef _WIN64
+#include <qt/qt.h>
+#endif
+
+#include "../../../DSUtil/DSUtil.h"
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_STDAFX_H__C76533D6_6242_4BEB_8FD3_C6BE58F07225__INCLUDED_)
|