mfplat: Add support for local MFT registration.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2020-01-29 15:36:21 +03:00 committed by Alexandre Julliard
parent be45be2de7
commit 97f646edab
4 changed files with 288 additions and 33 deletions

View File

@ -43,6 +43,27 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat); WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
static HRESULT heap_strdupW(const WCHAR *str, WCHAR **dest)
{
HRESULT hr = S_OK;
if (str)
{
unsigned int size;
size = (lstrlenW(str) + 1) * sizeof(WCHAR);
*dest = heap_alloc(size);
if (*dest)
memcpy(*dest, str, size);
else
hr = E_OUTOFMEMORY;
}
else
*dest = NULL;
return hr;
}
static LONG platform_lock; static LONG platform_lock;
struct local_handler struct local_handler
@ -65,6 +86,24 @@ static CRITICAL_SECTION local_handlers_section = { NULL, -1, 0, 0, 0, 0 };
static struct list local_scheme_handlers = LIST_INIT(local_scheme_handlers); static struct list local_scheme_handlers = LIST_INIT(local_scheme_handlers);
static struct list local_bytestream_handlers = LIST_INIT(local_bytestream_handlers); static struct list local_bytestream_handlers = LIST_INIT(local_bytestream_handlers);
struct local_mft
{
struct list entry;
IClassFactory *factory;
CLSID clsid;
GUID category;
WCHAR *name;
DWORD flags;
MFT_REGISTER_TYPE_INFO *input_types;
UINT32 input_types_count;
MFT_REGISTER_TYPE_INFO *output_types;
UINT32 output_types_count;
};
static CRITICAL_SECTION local_mfts_section = { NULL, -1, 0, 0, 0, 0 };
static struct list local_mfts = LIST_INIT(local_mfts);
struct transform_activate struct transform_activate
{ {
struct attributes attributes; struct attributes attributes;
@ -736,32 +775,164 @@ HRESULT WINAPI MFTRegister(CLSID clsid, GUID category, LPWSTR name, UINT32 flags
return hr; return hr;
} }
HRESULT WINAPI MFTRegisterLocal(IClassFactory *factory, REFGUID category, LPCWSTR name, static void release_local_mft(struct local_mft *mft)
UINT32 flags, UINT32 cinput, const MFT_REGISTER_TYPE_INFO *input_types,
UINT32 coutput, const MFT_REGISTER_TYPE_INFO* output_types)
{ {
FIXME("(%p, %s, %s, %x, %u, %p, %u, %p)\n", factory, debugstr_guid(category), debugstr_w(name), if (mft->factory)
flags, cinput, input_types, coutput, output_types); IClassFactory_Release(mft->factory);
heap_free(mft->name);
heap_free(mft->input_types);
heap_free(mft->output_types);
heap_free(mft);
}
return S_OK; static HRESULT mft_register_local(IClassFactory *factory, REFCLSID clsid, REFGUID category, LPCWSTR name, UINT32 flags,
UINT32 input_count, const MFT_REGISTER_TYPE_INFO *input_types, UINT32 output_count,
const MFT_REGISTER_TYPE_INFO *output_types)
{
struct local_mft *mft, *cur, *unreg_mft = NULL;
HRESULT hr;
if (!factory && !clsid)
{
WARN("Can't register without factory or CLSID.\n");
return E_FAIL;
}
mft = heap_alloc_zero(sizeof(*mft));
if (!mft)
return E_OUTOFMEMORY;
mft->factory = factory;
if (mft->factory)
IClassFactory_AddRef(mft->factory);
if (clsid)
mft->clsid = *clsid;
mft->category = *category;
mft->flags = flags;
if (FAILED(hr = heap_strdupW(name, &mft->name)))
goto failed;
if (input_count && input_types)
{
mft->input_types_count = input_count;
if (!(mft->input_types = heap_calloc(mft->input_types_count, sizeof(*input_types))))
{
hr = E_OUTOFMEMORY;
goto failed;
}
memcpy(mft->input_types, input_types, mft->input_types_count * sizeof(*input_types));
}
if (output_count && output_types)
{
mft->output_types_count = output_count;
if (!(mft->output_types = heap_calloc(mft->output_types_count, sizeof(*output_types))))
{
hr = E_OUTOFMEMORY;
goto failed;
}
memcpy(mft->output_types, output_types, mft->output_types_count * sizeof(*output_types));
}
EnterCriticalSection(&local_mfts_section);
LIST_FOR_EACH_ENTRY(cur, &local_mfts, struct local_mft, entry)
{
if (cur->factory == factory)
{
unreg_mft = cur;
list_remove(&cur->entry);
break;
}
}
list_add_tail(&local_mfts, &mft->entry);
LeaveCriticalSection(&local_mfts_section);
if (unreg_mft)
release_local_mft(unreg_mft);
failed:
if (FAILED(hr))
release_local_mft(mft);
return hr;
}
HRESULT WINAPI MFTRegisterLocal(IClassFactory *factory, REFGUID category, LPCWSTR name, UINT32 flags,
UINT32 input_count, const MFT_REGISTER_TYPE_INFO *input_types, UINT32 output_count,
const MFT_REGISTER_TYPE_INFO *output_types)
{
TRACE("%p, %s, %s, %#x, %u, %p, %u, %p.\n", factory, debugstr_guid(category), debugstr_w(name), flags, input_count,
input_types, output_count, output_types);
return mft_register_local(factory, NULL, category, name, flags, input_count, input_types, output_count, output_types);
} }
HRESULT WINAPI MFTRegisterLocalByCLSID(REFCLSID clsid, REFGUID category, LPCWSTR name, UINT32 flags, HRESULT WINAPI MFTRegisterLocalByCLSID(REFCLSID clsid, REFGUID category, LPCWSTR name, UINT32 flags,
UINT32 input_count, const MFT_REGISTER_TYPE_INFO *input_types, UINT32 output_count, UINT32 input_count, const MFT_REGISTER_TYPE_INFO *input_types, UINT32 output_count,
const MFT_REGISTER_TYPE_INFO *output_types) const MFT_REGISTER_TYPE_INFO *output_types)
{ {
TRACE("%s, %s, %s, %#x, %u, %p, %u, %p.\n", debugstr_guid(clsid), debugstr_guid(category), debugstr_w(name), flags,
FIXME("%s, %s, %s, %#x, %u, %p, %u, %p.\n", debugstr_guid(clsid), debugstr_guid(category), debugstr_w(name), flags,
input_count, input_types, output_count, output_types); input_count, input_types, output_count, output_types);
return E_NOTIMPL; return mft_register_local(NULL, clsid, category, name, flags, input_count, input_types, output_count, output_types);
}
static HRESULT mft_unregister_local(IClassFactory *factory, REFCLSID clsid)
{
struct local_mft *cur, *cur2;
BOOL unregister_all = !factory && !clsid;
struct list unreg;
list_init(&unreg);
EnterCriticalSection(&local_mfts_section);
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &local_mfts, struct local_mft, entry)
{
if (!unregister_all)
{
if ((factory && cur->factory == factory) || IsEqualCLSID(&cur->clsid, clsid))
{
list_remove(&cur->entry);
list_add_tail(&unreg, &cur->entry);
break;
}
}
else
{
list_remove(&cur->entry);
list_add_tail(&unreg, &cur->entry);
}
}
LeaveCriticalSection(&local_mfts_section);
if (!unregister_all && list_empty(&unreg))
return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &unreg, struct local_mft, entry)
{
list_remove(&cur->entry);
release_local_mft(cur);
}
return S_OK;
}
HRESULT WINAPI MFTUnregisterLocalByCLSID(CLSID clsid)
{
TRACE("%s.\n", debugstr_guid(&clsid));
return mft_unregister_local(NULL, &clsid);
} }
HRESULT WINAPI MFTUnregisterLocal(IClassFactory *factory) HRESULT WINAPI MFTUnregisterLocal(IClassFactory *factory)
{ {
FIXME("(%p)\n", factory); TRACE("%p.\n", factory);
return S_OK; return mft_unregister_local(factory, NULL);
} }
MFTIME WINAPI MFGetSystemTime(void) MFTIME WINAPI MFGetSystemTime(void)
@ -7683,27 +7854,6 @@ static const IMFAsyncCallbackVtbl async_create_file_callback_vtbl =
async_create_file_callback_Invoke, async_create_file_callback_Invoke,
}; };
static HRESULT heap_strdupW(const WCHAR *str, WCHAR **dest)
{
HRESULT hr = S_OK;
if (str)
{
unsigned int size;
size = (lstrlenW(str) + 1) * sizeof(WCHAR);
*dest = heap_alloc(size);
if (*dest)
memcpy(*dest, str, size);
else
hr = E_OUTOFMEMORY;
}
else
*dest = NULL;
return hr;
}
/*********************************************************************** /***********************************************************************
* MFBeginCreateFile (mfplat.@) * MFBeginCreateFile (mfplat.@)
*/ */

View File

@ -150,7 +150,7 @@
@ stdcall MFTRegisterLocalByCLSID(ptr ptr wstr long long ptr long ptr) @ stdcall MFTRegisterLocalByCLSID(ptr ptr wstr long long ptr long ptr)
@ stdcall MFTUnregister(int128) @ stdcall MFTUnregister(int128)
@ stdcall MFTUnregisterLocal(ptr) @ stdcall MFTUnregisterLocal(ptr)
@ stub MFTUnregisterLocalByCLSID @ stdcall MFTUnregisterLocalByCLSID(int128)
@ stub MFTraceError @ stub MFTraceError
@ stub MFTraceFuncEnter @ stub MFTraceFuncEnter
@ stub MFUnblockThread @ stub MFUnblockThread

View File

@ -78,6 +78,14 @@ static HRESULT (WINAPI *pMFRegisterLocalByteStreamHandler)(const WCHAR *extensio
IMFActivate *activate); IMFActivate *activate);
static HRESULT (WINAPI *pMFRegisterLocalSchemeHandler)(const WCHAR *scheme, IMFActivate *activate); static HRESULT (WINAPI *pMFRegisterLocalSchemeHandler)(const WCHAR *scheme, IMFActivate *activate);
static HRESULT (WINAPI *pMFCreateTransformActivate)(IMFActivate **activate); static HRESULT (WINAPI *pMFCreateTransformActivate)(IMFActivate **activate);
static HRESULT (WINAPI *pMFTRegisterLocal)(IClassFactory *factory, REFGUID category, LPCWSTR name,
UINT32 flags, UINT32 cinput, const MFT_REGISTER_TYPE_INFO *input_types, UINT32 coutput,
const MFT_REGISTER_TYPE_INFO* output_types);
static HRESULT (WINAPI *pMFTRegisterLocalByCLSID)(REFCLSID clsid, REFGUID category, LPCWSTR name, UINT32 flags,
UINT32 input_count, const MFT_REGISTER_TYPE_INFO *input_types, UINT32 output_count,
const MFT_REGISTER_TYPE_INFO *output_types);
static HRESULT (WINAPI *pMFTUnregisterLocal)(IClassFactory *factory);
static HRESULT (WINAPI *pMFTUnregisterLocalByCLSID)(CLSID clsid);
static const WCHAR mp4file[] = {'t','e','s','t','.','m','p','4',0}; static const WCHAR mp4file[] = {'t','e','s','t','.','m','p','4',0};
static const WCHAR fileschemeW[] = {'f','i','l','e',':','/','/',0}; static const WCHAR fileschemeW[] = {'f','i','l','e',':','/','/',0};
@ -529,6 +537,10 @@ static void init_functions(void)
X(MFRegisterLocalSchemeHandler); X(MFRegisterLocalSchemeHandler);
X(MFRemovePeriodicCallback); X(MFRemovePeriodicCallback);
X(MFCreateTransformActivate); X(MFCreateTransformActivate);
X(MFTRegisterLocal);
X(MFTRegisterLocalByCLSID);
X(MFTUnregisterLocal);
X(MFTUnregisterLocalByCLSID);
#undef X #undef X
if ((mod = LoadLibraryA("d3d11.dll"))) if ((mod = LoadLibraryA("d3d11.dll")))
@ -3823,6 +3835,97 @@ static void test_MFCreateTransformActivate(void)
IMFActivate_Release(activate); IMFActivate_Release(activate);
} }
static HRESULT WINAPI test_mft_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **obj)
{
if (IsEqualIID(riid, &IID_IClassFactory) ||
IsEqualIID(riid, &IID_IUnknown))
{
*obj = iface;
IClassFactory_AddRef(iface);
return S_OK;
}
*obj = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI test_mft_factory_AddRef(IClassFactory *iface)
{
return 2;
}
static ULONG WINAPI test_mft_factory_Release(IClassFactory *iface)
{
return 1;
}
static HRESULT WINAPI test_mft_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **obj)
{
ok(0, "Unexpected call.\n");
return E_NOTIMPL;
}
static HRESULT WINAPI test_mft_factory_LockServer(IClassFactory *iface, BOOL fLock)
{
return S_OK;
}
static const IClassFactoryVtbl test_mft_factory_vtbl =
{
test_mft_factory_QueryInterface,
test_mft_factory_AddRef,
test_mft_factory_Release,
test_mft_factory_CreateInstance,
test_mft_factory_LockServer,
};
static void test_MFTRegisterLocal(void)
{
IClassFactory test_factory = { &test_mft_factory_vtbl };
MFT_REGISTER_TYPE_INFO input_types[1];
HRESULT hr;
if (!pMFTRegisterLocal)
{
win_skip("MFTRegisterLocal() is not available.\n");
return;
}
input_types[0].guidMajorType = MFMediaType_Audio;
input_types[0].guidSubtype = MFAudioFormat_PCM;
hr = pMFTRegisterLocal(&test_factory, &MFT_CATEGORY_OTHER, L"Local MFT name", 0, 1, input_types, 0, NULL);
ok(hr == S_OK, "Failed to register MFT, hr %#x.\n", hr);
hr = pMFTRegisterLocal(&test_factory, &MFT_CATEGORY_OTHER, L"Local MFT name", 0, 1, input_types, 0, NULL);
ok(hr == S_OK, "Failed to register MFT, hr %#x.\n", hr);
hr = pMFTUnregisterLocal(&test_factory);
ok(hr == S_OK, "Failed to unregister MFT, hr %#x.\n", hr);
hr = pMFTUnregisterLocal(&test_factory);
ok(hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Unexpected hr %#x.\n", hr);
hr = pMFTUnregisterLocal(NULL);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = pMFTRegisterLocalByCLSID(&MFT_CATEGORY_OTHER, &MFT_CATEGORY_OTHER, L"Local MFT name 2", 0, 1, input_types,
0, NULL);
ok(hr == S_OK, "Failed to register MFT, hr %#x.\n", hr);
hr = pMFTUnregisterLocal(NULL);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = pMFTUnregisterLocalByCLSID(MFT_CATEGORY_OTHER);
ok(hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Unexpected hr %#x.\n", hr);
hr = pMFTRegisterLocalByCLSID(&MFT_CATEGORY_OTHER, &MFT_CATEGORY_OTHER, L"Local MFT name 2", 0, 1, input_types,
0, NULL);
ok(hr == S_OK, "Failed to register MFT, hr %#x.\n", hr);
hr = pMFTUnregisterLocalByCLSID(MFT_CATEGORY_OTHER);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
}
START_TEST(mfplat) START_TEST(mfplat)
{ {
CoInitialize(NULL); CoInitialize(NULL);
@ -3862,6 +3965,7 @@ START_TEST(mfplat)
test_create_property_store(); test_create_property_store();
test_dxgi_device_manager(); test_dxgi_device_manager();
test_MFCreateTransformActivate(); test_MFCreateTransformActivate();
test_MFTRegisterLocal();
CoUninitialize(); CoUninitialize();
} }

View File

@ -451,6 +451,7 @@ HRESULT WINAPI MFUnlockPlatform(void);
HRESULT WINAPI MFUnlockWorkQueue(DWORD queue); HRESULT WINAPI MFUnlockWorkQueue(DWORD queue);
HRESULT WINAPI MFTUnregister(CLSID clsid); HRESULT WINAPI MFTUnregister(CLSID clsid);
HRESULT WINAPI MFTUnregisterLocal(IClassFactory *factory); HRESULT WINAPI MFTUnregisterLocal(IClassFactory *factory);
HRESULT WINAPI MFTUnregisterLocalByCLSID(CLSID clsid);
HRESULT WINAPI MFGetPluginControl(IMFPluginControl**); HRESULT WINAPI MFGetPluginControl(IMFPluginControl**);
HRESULT WINAPI MFWrapMediaType(IMFMediaType *original, REFGUID major, REFGUID subtype, IMFMediaType **wrapped); HRESULT WINAPI MFWrapMediaType(IMFMediaType *original, REFGUID major, REFGUID subtype, IMFMediaType **wrapped);
HRESULT WINAPI MFUnwrapMediaType(IMFMediaType *wrapped, IMFMediaType **original); HRESULT WINAPI MFUnwrapMediaType(IMFMediaType *wrapped, IMFMediaType **original);