2025-11-28 00:35:46 +09:00

580 lines
12 KiB
C++

#include "CHWMFT.h"
#include <strsafe.h>
#include <mfapi.h>
#include <initguid.h>
#pragma region HelperMacros
// Helper Macros
#define SAFERELEASE(x) \
if((x) != NULL) \
{ \
(x)->Release(); \
(x) = NULL; \
} \
#define SAFEREGCLOSEKEY(x) \
if((x) != NULL) \
{ \
RegCloseKey(x); \
(x) = NULL; \
} \
#define SAFEARRAYDELETE(x) \
if((x) != NULL) \
{ \
delete[] (x); \
(x) = NULL; \
} \
#pragma endregion HelperMacros
#pragma region GlobalDefines
// {C637E2D2-01A0-4ACE-9C43-D2AF07E00B8C}
DEFINE_GUID(CLSID_MYMFT,
0xc637e2d2, 0x1a0, 0x4ace, 0x9c, 0x43, 0xd2, 0xaf, 0x7, 0xe0, 0xb, 0x8c);
#define MY_MFT_NAME L"Win8 SDK HW MFT Sample"
#define MFT_CODEC_MERIT 8 /*Todo: Replace this with the actual codec Merit*/
#pragma endregion GlobalDefines
#pragma region ClassFactory
// Implements the class factory for the MFT
class ClassFactory : public IClassFactory
{
protected:
volatile ULONG m_ulRefCount; // Reference count.
static volatile ULONG m_ulServerLocks; // Number of server locks
public:
ClassFactory(void)
{
m_ulRefCount = 1;
}
static bool IsLocked(void)
{
return (m_ulServerLocks != 0);
}
// IUnknown methods
ULONG __stdcall AddRef(void)
{
return InterlockedIncrement(&m_ulRefCount);
}
ULONG __stdcall Release(void)
{
ULONG ulRef = 0;
if(m_ulRefCount > 0)
{
ulRef = InterlockedDecrement(&m_ulRefCount);
}
if(ulRef == 0)
{
delete this;
}
return ulRef;
}
HRESULT __stdcall QueryInterface(
REFIID riid,
void** ppvObject)
{
HRESULT hr = S_OK;
do
{
if(ppvObject == NULL)
{
hr = E_POINTER;
break;
}
if(riid == IID_IUnknown)
{
*ppvObject = (IUnknown*)this;
}
else if(riid == IID_IClassFactory)
{
*ppvObject = (IClassFactory*)this;
}
else
{
*ppvObject = NULL;
hr = E_NOINTERFACE;
break;
}
AddRef();
}while(false);
return hr;
}
HRESULT __stdcall CreateInstance(
IUnknown *pUnkOuter,
REFIID riid, void**
ppv)
{
HRESULT hr = S_OK;
IMFTransform* pHWMFT = NULL;
do
{
if (pUnkOuter != NULL)
{
// This MFT not support aggregation.
hr = CLASS_E_NOAGGREGATION;
break;
}
hr = CHWMFT::CreateInstance(&pHWMFT);
if(FAILED(hr))
{
break;
}
hr = pHWMFT->QueryInterface(riid,
ppv
);
if(FAILED(hr))
{
break;
}
}while(false);
SAFERELEASE(pHWMFT);
return hr;
}
HRESULT __stdcall LockServer(
BOOL bLock)
{
HRESULT hr = S_OK;
do
{
if(bLock != FALSE)
{
InterlockedIncrement(&m_ulServerLocks);
}
else
{
InterlockedDecrement(&m_ulServerLocks);
}
}while(false);
return hr;
}
};
#pragma endregion ClassFactory
#pragma region GlobalVariables
HMODULE g_hModule = NULL; // DLL module handle
volatile ULONG CHWMFT::m_ulNumObjects = 0; // Number of active COM objects
volatile ULONG ClassFactory::m_ulServerLocks = 0; // Number of server locks
#pragma endregion GlobalVariables
#pragma region HelperFunctions
HRESULT CreateObjectKeyName(
_In_ const GUID& guid,
_Out_writes_(dwMax) WCHAR* pwszName,
_In_ const DWORD dwMax)
{
HRESULT hr = S_OK;
do
{
if(pwszName == NULL)
{
hr = E_POINTER;
break;
}
if(StringCchPrintf(pwszName,
dwMax,
L"CLSID\\{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
guid.Data1,
guid.Data2,
guid.Data3,
guid.Data4[0],
guid.Data4[1],
guid.Data4[2],
guid.Data4[3],
guid.Data4[4],
guid.Data4[5],
guid.Data4[6],
guid.Data4[7]
) < 0)
{
hr = E_FAIL;
break;
}
}while(false);
return hr;
}
HRESULT SetKeyValue(
HKEY hKey,
const WCHAR* pwszName,
const WCHAR* pwszValue)
{
HRESULT hr = S_OK;
do
{
hr = HRESULT_FROM_WIN32(
RegSetValueEx(hKey,
pwszName,
0,
REG_SZ,
(BYTE*)pwszValue,
(DWORD)((wcslen(pwszValue) + 1) * sizeof(WCHAR))
)
);
if(FAILED(hr))
{
break;
}
}while(false);
return hr;
}
HRESULT RegisterObject(
const GUID& guid,
const WCHAR* pwszDescription,
const WCHAR* pwszThreadingModel)
{
HRESULT hr = S_OK;
HKEY hKey = NULL;
HKEY hSubkey = NULL;
DWORD dwFileNameLen = 0;
WCHAR pwszBuffer[MAX_PATH] = {0};
do
{
if(g_hModule == NULL)
{
hr = E_UNEXPECTED;
break;
}
// Create the name of the key from the object's CLSID
hr = CreateObjectKeyName(guid,
pwszBuffer,
sizeof(pwszBuffer) / sizeof(pwszBuffer[0])
);
if(FAILED(hr))
{
break;
}
// Create the new key.
hr = HRESULT_FROM_WIN32(
RegCreateKeyEx(
HKEY_CLASSES_ROOT,
pwszBuffer,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
NULL
)
);
if(FAILED(hr))
{
break;
}
hr = SetKeyValue(hKey,
NULL,
pwszDescription);
if(FAILED(hr))
{
break;
}
// Create the "InprocServer32" subkey
hr = HRESULT_FROM_WIN32(
RegCreateKeyEx(
hKey,
L"InprocServer32",
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hSubkey,
NULL
)
);
// The default value for this subkey is the path to the DLL.
// Get the name of the module ...
dwFileNameLen = GetModuleFileName(g_hModule,
pwszBuffer,
MAX_PATH);
if (dwFileNameLen == 0)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
else if (dwFileNameLen == MAX_PATH)
{
hr = E_FAIL; // buffer too small
}
if(FAILED(hr))
{
break;
}
// ... and set the default key value.
hr = SetKeyValue(hSubkey,
NULL,
pwszBuffer
);
if(FAILED(hr))
{
break;
}
// Add a new value to the subkey, for "ThreadingModel" = <threading model>
hr = SetKeyValue(hSubkey,
L"ThreadingModel",
pwszThreadingModel
);
if(FAILED(hr))
{
break;
}
}while(false);
SAFEREGCLOSEKEY(hSubkey);
SAFEREGCLOSEKEY(hKey);
return hr;
}
HRESULT UnregisterObject(
const GUID& guid)
{
HRESULT hr = S_OK;
WCHAR pwszBuffer[MAX_PATH] = {0};
do
{
hr = CreateObjectKeyName(guid,
pwszBuffer,
sizeof(pwszBuffer) / sizeof(pwszBuffer[0])
);
if(FAILED(hr))
{
break;
}
hr = HRESULT_FROM_WIN32(
RegDeleteTree(HKEY_CLASSES_ROOT,
pwszBuffer
)
);
if(FAILED(hr))
{
break;
}
}while(false);
return hr;
}
#pragma endregion HelperFunctions
#pragma region DLLFunctions
BOOL APIENTRY DllMain(
HANDLE hModule,
DWORD dwReason,
LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
g_hModule = (HMODULE)hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
// Nothing to do
break;
case DLL_PROCESS_DETACH:
break;
};
return TRUE;
}
HRESULT __stdcall DllCanUnloadNow(void)
{
HRESULT hr = S_FALSE;
do
{
if ((ClassFactory::IsLocked() != FALSE) || (CHWMFT::m_ulNumObjects != 0))
{
break;
}
hr = S_OK;
}while(false);
return hr;
}
HRESULT __stdcall DllRegisterServer(void)
{
HRESULT hr = S_OK;
MFT_REGISTER_TYPE_INFO* pmftrtiInput = NULL;
MFT_REGISTER_TYPE_INFO* pmftrtiOutput = NULL;
IMFAttributes* pMFTAttributes = NULL;
do
{
pmftrtiInput = new MFT_REGISTER_TYPE_INFO[g_dwNumInputTypes];
if(pmftrtiInput == NULL)
{
hr = E_OUTOFMEMORY;
break;
}
pmftrtiOutput = new MFT_REGISTER_TYPE_INFO[g_dwNumOutputTypes];
if(pmftrtiOutput == NULL)
{
hr = E_OUTOFMEMORY;
break;
}
for(DWORD i = 0; i < g_dwNumInputTypes; i++)
{
pmftrtiInput[i].guidMajorType = MFMediaType_Video;
pmftrtiInput[i].guidSubtype = *(g_ppguidInputTypes[i]);
}
for(DWORD i = 0; i < g_dwNumOutputTypes; i++)
{
pmftrtiOutput[i].guidMajorType = MFMediaType_Video;
pmftrtiOutput[i].guidSubtype = *(g_ppguidOutputTypes[i]);
}
/****************************************
** !!MSFT_TODO: Report as HW MFT
****************************************
// Since this is a HW MFT, we have to set MFT_CODEC_MERIT_Attribute
hr = MFCreateAttributes(&pMFTAttributes, 1);
if(FAILED(hr))
{
break;
}
hr = pMFTAttributes->SetUINT32(MFT_CODEC_MERIT_Attribute, MFT_CODEC_MERIT);
if(FAILED(hr))
{
break;
}
*/
// Register the object with COM
hr = RegisterObject(CLSID_MYMFT,
MY_MFT_NAME,
L"Both");
if(FAILED(hr))
{
break;
}
// Register the MFT with MF
hr = MFTRegister(
CLSID_MYMFT,
MFT_CATEGORY_VIDEO_DECODER, // This MFT acts as a video decoder
MY_MFT_NAME,
/****************************************
** !!MSFT_TODO: Report as HW MFT
****************************************
MFT_ENUM_FLAG_HARDWARE,*/ MFT_ENUM_FLAG_ASYNCMFT,
g_dwNumInputTypes,
pmftrtiInput,
g_dwNumOutputTypes,
pmftrtiOutput,
pMFTAttributes
);
if(FAILED(hr))
{
break;
}
}while(false);
SAFEARRAYDELETE(pmftrtiInput);
SAFEARRAYDELETE(pmftrtiOutput);
SAFERELEASE(pMFTAttributes);
return hr;
}
HRESULT __stdcall DllUnregisterServer(void)
{
UnregisterObject(CLSID_MYMFT);
return S_OK;
}
HRESULT __stdcall DllGetClassObject(
_In_ REFCLSID clsid,
_In_ REFIID riid,
_Outptr_ void** ppv)
{
HRESULT hr = S_OK;
ClassFactory* pFactory = NULL;
do
{
if (clsid != CLSID_MYMFT)
{
hr = CLASS_E_CLASSNOTAVAILABLE;
break;
}
pFactory = new ClassFactory();
if (pFactory == NULL)
{
hr = E_OUTOFMEMORY;
break;
}
hr = pFactory->QueryInterface(riid, ppv);
if(FAILED(hr))
{
break;
}
}while(false);
SAFERELEASE(pFactory);
return hr;
}
#pragma endregion DLLFunctions