diff --git a/dlls/qasf/Makefile.in b/dlls/qasf/Makefile.in index 7ca314e20ba..c1d34a42dab 100644 --- a/dlls/qasf/Makefile.in +++ b/dlls/qasf/Makefile.in @@ -1,5 +1,5 @@ MODULE = qasf.dll -IMPORTS = strmbase dmoguids strmiids uuid +IMPORTS = strmbase dmoguids strmiids uuid ole32 EXTRADLLFLAGS = -mno-cygwin diff --git a/dlls/qasf/dmowrapper.c b/dlls/qasf/dmowrapper.c index d4547d4ba30..1f11c9ff7ef 100644 --- a/dlls/qasf/dmowrapper.c +++ b/dlls/qasf/dmowrapper.c @@ -26,6 +26,8 @@ struct dmo_wrapper { struct strmbase_filter filter; IDMOWrapperFilter IDMOWrapperFilter_iface; + + IUnknown *dmo; }; static inline struct dmo_wrapper *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -58,9 +60,23 @@ static ULONG WINAPI dmo_wrapper_filter_Release(IDMOWrapperFilter *iface) static HRESULT WINAPI dmo_wrapper_filter_Init(IDMOWrapperFilter *iface, REFCLSID clsid, REFCLSID category) { - FIXME("iface %p, clsid %s, category %s, stub!\n", - iface, wine_dbgstr_guid(clsid), wine_dbgstr_guid(category)); - return E_NOTIMPL; + struct dmo_wrapper *filter = impl_from_IDMOWrapperFilter(iface); + IUnknown *unk; + HRESULT hr; + + TRACE("filter %p, clsid %s, category %s.\n", filter, debugstr_guid(clsid), debugstr_guid(category)); + + if (FAILED(hr = CoCreateInstance(clsid, &filter->filter.IUnknown_inner, + CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&unk))) + return hr; + + EnterCriticalSection(&filter->filter.csFilter); + + filter->dmo = unk; + + LeaveCriticalSection(&filter->filter.csFilter); + + return S_OK; } static const IDMOWrapperFilterVtbl dmo_wrapper_filter_vtbl = @@ -80,6 +96,8 @@ static void dmo_wrapper_destroy(struct strmbase_filter *iface) { struct dmo_wrapper *filter = impl_from_strmbase_filter(iface); + if (filter->dmo) + IUnknown_Release(filter->dmo); strmbase_filter_cleanup(&filter->filter); free(filter); } @@ -95,6 +113,8 @@ static HRESULT dmo_wrapper_query_interface(struct strmbase_filter *iface, REFIID return S_OK; } + if (filter->dmo && !IsEqualGUID(iid, &IID_IUnknown)) + return IUnknown_QueryInterface(filter->dmo, iid, out); return E_NOINTERFACE; } diff --git a/dlls/qasf/tests/Makefile.in b/dlls/qasf/tests/Makefile.in index dd04f4b438f..47bb22e78ab 100644 --- a/dlls/qasf/tests/Makefile.in +++ b/dlls/qasf/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = qasf.dll -IMPORTS = dmoguids strmiids uuid ole32 +IMPORTS = dmoguids strmiids uuid msdmo ole32 C_SRCS = \ dmowrapper.c diff --git a/dlls/qasf/tests/dmowrapper.c b/dlls/qasf/tests/dmowrapper.c index e061ca24177..9345b91a178 100644 --- a/dlls/qasf/tests/dmowrapper.c +++ b/dlls/qasf/tests/dmowrapper.c @@ -24,14 +24,286 @@ #include "dmodshow.h" #include "wine/test.h" +static const GUID testdmo_clsid = {0x1234}; static const GUID test_iid = {0x33333333}; +static const IMediaObjectVtbl dmo_vtbl; + +static IMediaObject testdmo = {&dmo_vtbl}; +static IUnknown *testdmo_outer_unk; +static LONG testdmo_refcount = 1; + +static HRESULT WINAPI dmo_inner_QueryInterface(IUnknown *iface, REFIID iid, void **out) +{ + if (winetest_debug > 1) trace("QueryInterface(%s)\n", wine_dbgstr_guid(iid)); + + if (IsEqualGUID(iid, &IID_IUnknown)) + *out = iface; + else if (IsEqualGUID(iid, &IID_IMediaObject) || IsEqualGUID(iid, &test_iid)) + *out = &testdmo; + else + return E_NOINTERFACE; + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI dmo_inner_AddRef(IUnknown *iface) +{ + return InterlockedIncrement(&testdmo_refcount); +} + +static ULONG WINAPI dmo_inner_Release(IUnknown *iface) +{ + return InterlockedDecrement(&testdmo_refcount); +} + +static const IUnknownVtbl dmo_inner_vtbl = +{ + dmo_inner_QueryInterface, + dmo_inner_AddRef, + dmo_inner_Release, +}; + +static IUnknown testdmo_inner = {&dmo_inner_vtbl}; + +static HRESULT WINAPI dmo_QueryInterface(IMediaObject *iface, REFIID iid, void **out) +{ + return IUnknown_QueryInterface(testdmo_outer_unk, iid, out); +} + +static ULONG WINAPI dmo_AddRef(IMediaObject *iface) +{ + return IUnknown_AddRef(testdmo_outer_unk); +} + +static ULONG WINAPI dmo_Release(IMediaObject *iface) +{ + return IUnknown_Release(testdmo_outer_unk); +} + +static HRESULT WINAPI dmo_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output) +{ + if (winetest_debug > 1) trace("GetStreamCount()\n"); + *input = 1; + *output = 2; + return S_OK; +} + +static HRESULT WINAPI dmo_GetInputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_GetOutputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags) +{ + if (winetest_debug > 1) trace("GetOutputStreamInfo(%u)\n", index); + *flags = 0; + return S_OK; +} + +static HRESULT WINAPI dmo_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index, DMO_MEDIA_TYPE *type) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index, DMO_MEDIA_TYPE *type) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_SetInputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_SetOutputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_GetInputSizeInfo(IMediaObject *iface, DWORD index, + DWORD *size, DWORD *lookahead, DWORD *align) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_SetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME latency) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_Flush(IMediaObject *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_Discontinuity(IMediaObject *iface, DWORD index) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_AllocateStreamingResources(IMediaObject *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_FreeStreamingResources(IMediaObject *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_ProcessInput(IMediaObject *iface, DWORD index, + IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_ProcessOutput(IMediaObject *iface, DWORD flags, + DWORD count, DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI dmo_Lock(IMediaObject *iface, LONG lock) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IMediaObjectVtbl dmo_vtbl = +{ + dmo_QueryInterface, + dmo_AddRef, + dmo_Release, + dmo_GetStreamCount, + dmo_GetInputStreamInfo, + dmo_GetOutputStreamInfo, + dmo_GetInputType, + dmo_GetOutputType, + dmo_SetInputType, + dmo_SetOutputType, + dmo_GetInputCurrentType, + dmo_GetOutputCurrentType, + dmo_GetInputSizeInfo, + dmo_GetOutputSizeInfo, + dmo_GetInputMaxLatency, + dmo_SetInputMaxLatency, + dmo_Flush, + dmo_Discontinuity, + dmo_AllocateStreamingResources, + dmo_FreeStreamingResources, + dmo_GetInputStatus, + dmo_ProcessInput, + dmo_ProcessOutput, + dmo_Lock, +}; + +static HRESULT WINAPI dmo_cf_QueryInterface(IClassFactory *iface, REFIID iid, void **out) +{ + if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IClassFactory)) + { + *out = iface; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI dmo_cf_AddRef(IClassFactory *iface) +{ + return 2; +} + +static ULONG WINAPI dmo_cf_Release(IClassFactory *iface) +{ + return 1; +} + +static HRESULT WINAPI dmo_cf_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID iid, void **out) +{ + ok(!!outer, "Expected to be created aggregated.\n"); + ok(IsEqualGUID(iid, &IID_IUnknown), "Got unexpected iid %s.\n", wine_dbgstr_guid(iid)); + + *out = &testdmo_inner; + IUnknown_AddRef(&testdmo_inner); + testdmo_outer_unk = outer; + return S_OK; +} + +static HRESULT WINAPI dmo_cf_LockServer(IClassFactory *iface, BOOL lock) +{ + ok(0, "Unexpected call.\n"); + return S_OK; +} + +static const IClassFactoryVtbl dmo_cf_vtbl = +{ + dmo_cf_QueryInterface, + dmo_cf_AddRef, + dmo_cf_Release, + dmo_cf_CreateInstance, + dmo_cf_LockServer, +}; + +static IClassFactory testdmo_cf = {&dmo_cf_vtbl}; + static IBaseFilter *create_dmo_wrapper(void) { + IDMOWrapperFilter *wrapper; IBaseFilter *filter = NULL; HRESULT hr = CoCreateInstance(&CLSID_DMOWrapperFilter, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void **)&filter); ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IBaseFilter_QueryInterface(filter, &IID_IDMOWrapperFilter, (void **)&wrapper); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IDMOWrapperFilter_Init(wrapper, &testdmo_clsid, &DMOCATEGORY_AUDIO_DECODER); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IDMOWrapperFilter_Release(wrapper); + return filter; } @@ -169,14 +441,49 @@ static void test_aggregation(void) IBaseFilter_Release(filter); ref = IUnknown_Release(unk); ok(!ref, "Got unexpected refcount %d.\n", ref); + + /* Test also aggregation of the inner media object. */ + + filter = create_dmo_wrapper(); + + hr = IBaseFilter_QueryInterface(filter, &IID_IMediaObject, (void **)&unk); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(unk == (IUnknown *)&testdmo, "Got unexpected object %p.\n", unk); + IUnknown_Release(unk); + + hr = IBaseFilter_QueryInterface(filter, &test_iid, (void **)&unk); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(unk == (IUnknown *)&testdmo, "Got unexpected object %p.\n", unk); + IUnknown_Release(unk); + + ref = IBaseFilter_Release(filter); + ok(!ref, "Got unexpected refcount %d.\n", ref); } START_TEST(dmowrapper) { + DWORD cookie; + HRESULT hr; + CoInitializeEx(NULL, COINIT_MULTITHREADED); + hr = DMORegister(L"Wine test DMO", &testdmo_clsid, &DMOCATEGORY_AUDIO_DECODER, 0, 0, NULL, 0, NULL); + if (FAILED(hr)) + { + skip("Failed to register DMO, hr %#x.\n", hr); + return; + } + ok(hr == S_OK, "Failed to register class, hr %#x.\n", hr); + + hr = CoRegisterClassObject(&testdmo_clsid, (IUnknown *)&testdmo_cf, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie); + ok(hr == S_OK, "Failed to register class, hr %#x.\n", hr); + test_interfaces(); test_aggregation(); + CoRevokeClassObject(cookie); + DMOUnregister(&testdmo_clsid, &DMOCATEGORY_AUDIO_DECODER); + CoUninitialize(); }