From 97f646edabea52e136713830612eb737df3689dd Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Wed, 29 Jan 2020 15:36:21 +0300 Subject: [PATCH] mfplat: Add support for local MFT registration. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/mfplat/main.c | 214 +++++++++++++++++++++++++++++++------ dlls/mfplat/mfplat.spec | 2 +- dlls/mfplat/tests/mfplat.c | 104 ++++++++++++++++++ include/mfapi.h | 1 + 4 files changed, 288 insertions(+), 33 deletions(-) diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index df11e189a2b..c8beeda9738 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -43,6 +43,27 @@ 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; 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_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 attributes attributes; @@ -736,32 +775,164 @@ HRESULT WINAPI MFTRegister(CLSID clsid, GUID category, LPWSTR name, UINT32 flags return hr; } -HRESULT WINAPI MFTRegisterLocal(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 void release_local_mft(struct local_mft *mft) { - FIXME("(%p, %s, %s, %x, %u, %p, %u, %p)\n", factory, debugstr_guid(category), debugstr_w(name), - flags, cinput, input_types, coutput, output_types); + if (mft->factory) + 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, UINT32 input_count, const MFT_REGISTER_TYPE_INFO *input_types, UINT32 output_count, const MFT_REGISTER_TYPE_INFO *output_types) { - - FIXME("%s, %s, %s, %#x, %u, %p, %u, %p.\n", debugstr_guid(clsid), debugstr_guid(category), debugstr_w(name), flags, + TRACE("%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); - 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) { - FIXME("(%p)\n", factory); + TRACE("%p.\n", factory); - return S_OK; + return mft_unregister_local(factory, NULL); } MFTIME WINAPI MFGetSystemTime(void) @@ -7683,27 +7854,6 @@ static const IMFAsyncCallbackVtbl async_create_file_callback_vtbl = 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.@) */ diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index e3ec8bcb8b9..a13c192cafd 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -150,7 +150,7 @@ @ stdcall MFTRegisterLocalByCLSID(ptr ptr wstr long long ptr long ptr) @ stdcall MFTUnregister(int128) @ stdcall MFTUnregisterLocal(ptr) -@ stub MFTUnregisterLocalByCLSID +@ stdcall MFTUnregisterLocalByCLSID(int128) @ stub MFTraceError @ stub MFTraceFuncEnter @ stub MFUnblockThread diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index ba896f37115..d0e05650c2d 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -78,6 +78,14 @@ static HRESULT (WINAPI *pMFRegisterLocalByteStreamHandler)(const WCHAR *extensio IMFActivate *activate); static HRESULT (WINAPI *pMFRegisterLocalSchemeHandler)(const WCHAR *scheme, 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 fileschemeW[] = {'f','i','l','e',':','/','/',0}; @@ -529,6 +537,10 @@ static void init_functions(void) X(MFRegisterLocalSchemeHandler); X(MFRemovePeriodicCallback); X(MFCreateTransformActivate); + X(MFTRegisterLocal); + X(MFTRegisterLocalByCLSID); + X(MFTUnregisterLocal); + X(MFTUnregisterLocalByCLSID); #undef X if ((mod = LoadLibraryA("d3d11.dll"))) @@ -3823,6 +3835,97 @@ static void test_MFCreateTransformActivate(void) 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) { CoInitialize(NULL); @@ -3862,6 +3965,7 @@ START_TEST(mfplat) test_create_property_store(); test_dxgi_device_manager(); test_MFCreateTransformActivate(); + test_MFTRegisterLocal(); CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index 182fb19dbf5..7c9e713ac2d 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -451,6 +451,7 @@ HRESULT WINAPI MFUnlockPlatform(void); HRESULT WINAPI MFUnlockWorkQueue(DWORD queue); HRESULT WINAPI MFTUnregister(CLSID clsid); HRESULT WINAPI MFTUnregisterLocal(IClassFactory *factory); +HRESULT WINAPI MFTUnregisterLocalByCLSID(CLSID clsid); HRESULT WINAPI MFGetPluginControl(IMFPluginControl**); HRESULT WINAPI MFWrapMediaType(IMFMediaType *original, REFGUID major, REFGUID subtype, IMFMediaType **wrapped); HRESULT WINAPI MFUnwrapMediaType(IMFMediaType *wrapped, IMFMediaType **original);