diff --git a/source-code/PD-Loader.sln b/source-code/PD-Loader.sln
index e6e5059..ee6d287 100644
--- a/source-code/PD-Loader.sln
+++ b/source-code/PD-Loader.sln
@@ -17,6 +17,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fakedll", "source\fakedll\f
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DivaSound", "source\plugins\DivaSound\DivaSound.vcxproj", "{EE1A551A-49A0-40F2-8C2E-862D0AE55B43}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DivaMovie", "source\plugins\DivaMovie\DivaMovie.vcxproj", "{1994C586-F73B-4EF2-BA3E-2A0FC3034B1A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -79,6 +81,12 @@ Global
{EE1A551A-49A0-40F2-8C2E-862D0AE55B43}.Release|x64.ActiveCfg = Release|x64
{EE1A551A-49A0-40F2-8C2E-862D0AE55B43}.Release|x64.Build.0 = Release|x64
{EE1A551A-49A0-40F2-8C2E-862D0AE55B43}.Release|x86.ActiveCfg = Release|x64
+ {1994C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Debug|x64.ActiveCfg = Debug|x64
+ {1994C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Debug|x64.Build.0 = Debug|x64
+ {1994C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Debug|x86.ActiveCfg = Debug|x64
+ {1994C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x64.ActiveCfg = Release|x64
+ {1994C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x64.Build.0 = Release|x64
+ {1994C586-F73B-4EF2-BA3E-2A0FC3034B1A}.Release|x86.ActiveCfg = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/source-code/source/plugins/DivaMovie/DivaMovie.vcxproj b/source-code/source/plugins/DivaMovie/DivaMovie.vcxproj
new file mode 100644
index 0000000..35db075
--- /dev/null
+++ b/source-code/source/plugins/DivaMovie/DivaMovie.vcxproj
@@ -0,0 +1,92 @@
+
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ {1994C586-F73B-4EF2-BA3E-2A0FC3034B1A}
+ DivaMovie
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v142
+ MultiByte
+
+
+ DynamicLibrary
+ false
+ v142
+ true
+ MultiByte
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .dva
+
+
+ .dva
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ ..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories)
+
+
+ Console
+ ..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories)
+ detours.lib;evr.lib;mfplat.lib;mfuuid.lib;strmiids.lib;syelog.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ ..\..\..\dependencies\detours\include;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ true
+ detours.lib;evr.lib;mfplat.lib;mfuuid.lib;syelog.lib;%(AdditionalDependencies)
+ ..\..\..\dependencies\detours\lib;%(AdditionalLibraryDirectories)
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source-code/source/plugins/DivaMovie/DivaMovie.vcxproj.filters b/source-code/source/plugins/DivaMovie/DivaMovie.vcxproj.filters
new file mode 100644
index 0000000..d746774
--- /dev/null
+++ b/source-code/source/plugins/DivaMovie/DivaMovie.vcxproj.filters
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source-code/source/plugins/DivaMovie/dllmain.cpp b/source-code/source/plugins/DivaMovie/dllmain.cpp
new file mode 100644
index 0000000..ccfa5f9
--- /dev/null
+++ b/source-code/source/plugins/DivaMovie/dllmain.cpp
@@ -0,0 +1,170 @@
+#include "framework.h"
+
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+IDirect3DDeviceManager9* deviceManager;
+
+IMFTransform* mfTransform;
+int width;
+int height;
+unsigned long samplesize;
+unsigned long subtype;
+
+IMFSample* dstSample;
+IDirect3DSurface9* dstSurface;
+IMFSample* srcSample;
+IMFMediaBuffer* srcBuffer;
+
+HRESULT initialize(IMFTransform* transform)
+{
+ HRESULT result = S_OK;
+
+ IMFMediaType* type = NULL;
+ IMFMediaBuffer* buffer = NULL;
+ HANDLE hDevice = NULL;
+ IDirectXVideoAccelerationService* service = NULL;
+
+ AM_MEDIA_TYPE* format = NULL;
+ VIDEOINFOHEADER2* header = NULL;
+
+ // Release what we already had beforehand
+ SAFE_RELEASE(mfTransform);
+ SAFE_RELEASE(dstSample);
+ SAFE_RELEASE(dstSurface);
+ SAFE_RELEASE(srcSample);
+ SAFE_RELEASE(srcBuffer);
+
+ ASSERT(transform->GetOutputCurrentType(0, &type));
+ ASSERT(type->GetRepresentation(AM_MEDIA_TYPE_REPRESENTATION, (void**)&format));
+
+ header = (VIDEOINFOHEADER2*)format->pbFormat;
+
+ width = header->bmiHeader.biWidth;
+ height = header->bmiHeader.biHeight;
+ samplesize = format->lSampleSize;
+ subtype = format->subtype.Data1;
+
+ // System memory sample
+ ASSERT(MFCreateSample(&srcSample));
+ ASSERT(MFCreateMemoryBuffer(format->lSampleSize, &buffer));
+ ASSERT(srcSample->AddBuffer(buffer));
+ ASSERT(buffer->QueryInterface(&srcBuffer));
+
+ // Video memory sample
+ ASSERT(deviceManager->OpenDeviceHandle(&hDevice));
+ ASSERT(deviceManager->GetVideoService(hDevice, __uuidof(IDirectXVideoAccelerationService), (void**)& service));
+ ASSERT(service->CreateSurface(width, height, 0, (D3DFORMAT)subtype, D3DPOOL_DEFAULT, 0, DXVA2_VideoSoftwareRenderTarget, &dstSurface, NULL));
+ ASSERT(MFCreateVideoSampleFromSurface(dstSurface, &dstSample));
+ ASSERT(deviceManager->CloseDeviceHandle(hDevice));
+
+ mfTransform = transform;
+ mfTransform->AddRef();
+
+end:
+ if (format)
+ type->FreeRepresentation(AM_MEDIA_TYPE_REPRESENTATION, format);
+
+ SAFE_RELEASE(service);
+ SAFE_RELEASE(buffer);
+ SAFE_RELEASE(type);
+
+ return result;
+}
+
+VTABLE_HOOK(HRESULT, IMFTransform, ProcessOutput, DWORD dwFlags, DWORD cOutputBufferCount,
+ MFT_OUTPUT_DATA_BUFFER* pOutputSamples, DWORD* pdwStatus)
+{
+ if (pOutputSamples->pSample != NULL || deviceManager == NULL || cOutputBufferCount != 1)
+ return originalProcessOutput(This, dwFlags, cOutputBufferCount, pOutputSamples, pdwStatus);
+
+ HRESULT result = S_OK;
+
+ if (mfTransform != This)
+ ASSERT(initialize(This));
+
+ pOutputSamples->pSample = srcSample;
+ pOutputSamples->pSample->AddRef();
+
+ ASSERT(originalProcessOutput(This, dwFlags, cOutputBufferCount, pOutputSamples, pdwStatus));
+
+ D3DLOCKED_RECT rect;
+ BYTE* buf;
+ ASSERT(srcBuffer->Lock(&buf, NULL, NULL));
+ ASSERT(dstSurface->LockRect(&rect, NULL, NULL));
+ ASSERT(MFCopyImage((BYTE*)rect.pBits, rect.Pitch, buf, samplesize, samplesize, 1));
+ ASSERT(dstSurface->UnlockRect());
+ ASSERT(srcBuffer->Unlock());
+
+ LONGLONG duration;
+ ASSERT(srcSample->GetSampleDuration(&duration));
+ ASSERT(dstSample->SetSampleDuration(duration));
+
+ LONGLONG time;
+ ASSERT(srcSample->GetSampleTime(&time));
+ ASSERT(dstSample->SetSampleTime(time));
+
+ DWORD flags;
+ ASSERT(srcSample->GetSampleFlags(&flags));
+ ASSERT(dstSample->SetSampleFlags(flags));
+
+ pOutputSamples->pSample->Release();
+ pOutputSamples->pSample = dstSample;
+ pOutputSamples->pSample->AddRef();
+end:
+ return result;
+}
+
+VTABLE_HOOK(HRESULT, IMFTransform, ProcessMessage, MFT_MESSAGE_TYPE eMessage, ULONG_PTR ulParam)
+{
+ HRESULT result = originalProcessMessage(This, eMessage, ulParam);
+ if (eMessage == MFT_MESSAGE_SET_D3D_MANAGER && result == MF_E_UNSUPPORTED_D3D_TYPE)
+ {
+ result = originalProcessMessage(This, eMessage, NULL);
+ if (SUCCEEDED(result))
+ INSTALL_VTABLE_HOOK(This, ProcessOutput, 25);
+ }
+ return result;
+}
+
+HOOK(void*, IMFTransformInitializer, 0x140420B90, void* a1, void* a2, IMFTransform** transform)
+{
+ void* result = originalIMFTransformInitializer(a1, a2, transform);
+ INSTALL_VTABLE_HOOK(*transform, ProcessMessage, 23);
+ return result;
+}
+
+HOOK(HRESULT, DXVA2CreateDirect3DDeviceManager, PROC_ADDRESS("dxva2.dll", "DXVA2CreateDirect3DDeviceManager9"),
+ UINT* pResetToken, IDirect3DDeviceManager9** ppDeviceManager)
+{
+ HRESULT result = originalDXVA2CreateDirect3DDeviceManager(pResetToken, ppDeviceManager);
+
+ if (FAILED(result))
+ return result;
+
+ if (deviceManager)
+ deviceManager->Release();
+
+ deviceManager = *ppDeviceManager;
+ deviceManager->AddRef();
+
+ return result;
+}
+
+BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
+{
+ if (ul_reason_for_call == DLL_PROCESS_ATTACH)
+ {
+ INSTALL_HOOK(DXVA2CreateDirect3DDeviceManager);
+ INSTALL_HOOK(IMFTransformInitializer);
+ }
+
+ return TRUE;
+}
\ No newline at end of file
diff --git a/source-code/source/plugins/DivaMovie/framework.h b/source-code/source/plugins/DivaMovie/framework.h
new file mode 100644
index 0000000..08002d0
--- /dev/null
+++ b/source-code/source/plugins/DivaMovie/framework.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN
+
+#include
+#include
+#include
+
+#if _DEBUG
+#define PRINT(value, ...) printf(value, __VA_ARGS__);
+#else
+#define PRINT(value, ...)
+#endif
+
+#define PROC_ADDRESS(libraryName, procName) \
+ GetProcAddress(LoadLibrary(TEXT(libraryName)), procName)
+
+#define SAFE_RELEASE(object) if (object) { object->Release(); object = NULL; }
+
+#define VTABLE_HOOK(returnType, className, functionName, ...) \
+ typedef returnType functionName(className* This, __VA_ARGS__); \
+ functionName* original##functionName; \
+ returnType implOf##functionName(className* This, __VA_ARGS__)
+
+#define INSTALL_VTABLE_HOOK(object, functionName, functionIndex) \
+ { \
+ void** addr = &(*(void***)object)[functionIndex]; \
+ if (*addr != implOf##functionName) \
+ { \
+ PRINT("[DivaMovie] Installing %s hook...\n", #functionName); \
+ original##functionName = (functionName*)*addr; \
+ DWORD oldProtect; \
+ VirtualProtect(addr, sizeof(void*), PAGE_EXECUTE_READWRITE, &oldProtect); \
+ *addr = implOf##functionName; \
+ VirtualProtect(addr, sizeof(void*), oldProtect, NULL); \
+ } \
+ }
+
+#define HOOK(returnType, function, location, ...) \
+ typedef returnType function(__VA_ARGS__); \
+ function* original##function = (function*)location; \
+ returnType implOf##function(__VA_ARGS__)
+
+#define INSTALL_HOOK(functionName) \
+ { \
+ PRINT("[DivaMovie] Installing %s hook...\n", #functionName); \
+ DetourTransactionBegin(); \
+ DetourUpdateThread(GetCurrentThread()); \
+ DetourAttach((void**)&original##functionName, implOf##functionName); \
+ DetourTransactionCommit(); \
+ }
+
+#define ASSERT(function) \
+ if (FAILED(result = (function))) \
+ { \
+ PRINT("[DivaMovie] %s failed (error code: 0x%08x)\n", #function, (unsigned int)result); \
+ goto end; \
+ } \
+ else \
+ { \
+ PRINT("[DivaMovie] %s succeeded\n", #function); \
+ }
\ No newline at end of file