Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qasf/dmowrapper.c | 46 +++++++ dlls/qasf/tests/dmowrapper.c | 240 ++++++++++++++++++++++++++++++++++- dlls/strmbase/pin.c | 3 + include/wine/strmbase.h | 2 + 4 files changed, 285 insertions(+), 6 deletions(-)
diff --git a/dlls/qasf/dmowrapper.c b/dlls/qasf/dmowrapper.c index 28d8e82175c..7a18d0ba079 100644 --- a/dlls/qasf/dmowrapper.c +++ b/dlls/qasf/dmowrapper.c @@ -166,10 +166,56 @@ static HRESULT dmo_wrapper_source_get_media_type(struct strmbase_pin *iface, uns return hr == S_OK ? S_OK : VFW_S_NO_MORE_ITEMS; }
+static HRESULT WINAPI dmo_wrapper_source_DecideBufferSize(struct strmbase_source *iface, + IMemAllocator *allocator, ALLOCATOR_PROPERTIES *props) +{ + struct dmo_wrapper *filter = impl_from_strmbase_filter(iface->pin.filter); + DWORD index = impl_source_from_strmbase_pin(&iface->pin) - filter->sources; + ALLOCATOR_PROPERTIES ret_props; + DWORD size = 0, alignment = 0; + IMediaObject *dmo; + HRESULT hr; + + IUnknown_QueryInterface(filter->dmo, &IID_IMediaObject, (void **)&dmo); + + if (SUCCEEDED(hr = IMediaObject_SetOutputType(dmo, index, + (const DMO_MEDIA_TYPE *)&iface->pin.mt, 0))) + hr = IMediaObject_GetOutputSizeInfo(dmo, index, &size, &alignment); + + if (SUCCEEDED(hr)) + { + props->cBuffers = max(props->cBuffers, 1); + props->cbBuffer = max(max(props->cbBuffer, size), 16384); + props->cbAlign = max(props->cbAlign, alignment); + hr = IMemAllocator_SetProperties(allocator, props, &ret_props); + } + + IMediaObject_Release(dmo); + + return hr; +} + +static void dmo_wrapper_source_disconnect(struct strmbase_source *iface) +{ + struct dmo_wrapper *filter = impl_from_strmbase_filter(iface->pin.filter); + IMediaObject *dmo; + + IUnknown_QueryInterface(filter->dmo, &IID_IMediaObject, (void **)&dmo); + + IMediaObject_SetOutputType(dmo, impl_source_from_strmbase_pin(&iface->pin) - filter->sources, + NULL, DMO_SET_TYPEF_CLEAR); + + IMediaObject_Release(dmo); +} + static const struct strmbase_source_ops source_ops = { .base.pin_query_accept = dmo_wrapper_source_query_accept, .base.pin_get_media_type = dmo_wrapper_source_get_media_type, + .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, + .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator, + .pfnDecideBufferSize = dmo_wrapper_source_DecideBufferSize, + .source_disconnect = dmo_wrapper_source_disconnect, };
static inline struct dmo_wrapper *impl_from_IDMOWrapperFilter(IDMOWrapperFilter *iface) diff --git a/dlls/qasf/tests/dmowrapper.c b/dlls/qasf/tests/dmowrapper.c index 641fa689042..dbb9d9d17f3 100644 --- a/dlls/qasf/tests/dmowrapper.c +++ b/dlls/qasf/tests/dmowrapper.c @@ -61,10 +61,13 @@ static const IMediaObjectVtbl dmo_vtbl; static IMediaObject testdmo = {&dmo_vtbl}; static IUnknown *testdmo_outer_unk; static LONG testdmo_refcount = 1; -static AM_MEDIA_TYPE testdmo_input_mt; -static BOOL testdmo_input_mt_set; +static AM_MEDIA_TYPE testdmo_input_mt, testdmo_output_mt; +static BOOL testdmo_input_mt_set, testdmo_output_mt_set;
static HRESULT testdmo_GetInputSizeInfo_hr = E_NOTIMPL; +static HRESULT testdmo_GetOutputSizeInfo_hr = S_OK; +static DWORD testdmo_output_size = 123; +static DWORD testdmo_output_alignment = 1;
static HRESULT WINAPI dmo_inner_QueryInterface(IUnknown *iface, REFIID iid, void **out) { @@ -183,6 +186,13 @@ static HRESULT WINAPI dmo_SetOutputType(IMediaObject *iface, DWORD index, const strmbase_dump_media_type((AM_MEDIA_TYPE *)type); if (flags & DMO_SET_TYPEF_TEST_ONLY) return type->lSampleSize == 321 ? S_OK : S_FALSE; + if (flags & DMO_SET_TYPEF_CLEAR) + { + testdmo_output_mt_set = FALSE; + return S_OK; + } + MoCopyMediaType((DMO_MEDIA_TYPE *)&testdmo_output_mt, type); + testdmo_output_mt_set = TRUE; return S_OK; }
@@ -210,8 +220,10 @@ static HRESULT WINAPI dmo_GetInputSizeInfo(IMediaObject *iface, DWORD index,
static HRESULT WINAPI dmo_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + if (winetest_debug > 1) trace("GetOutputSizeInfo(%u)\n", index); + *size = testdmo_output_size; + *alignment = testdmo_output_alignment; + return testdmo_GetOutputSizeInfo_hr; }
static HRESULT WINAPI dmo_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency) @@ -1137,6 +1149,71 @@ static void test_sink_allocator(IMemInputPin *input) IMemAllocator_Release(ret_allocator); }
+static void test_source_allocator(IFilterGraph2 *graph, IPin *source, struct testfilter *testsink) +{ + ALLOCATOR_PROPERTIES props, req_props = {2, 30000, 32, 0}; + IMemAllocator *allocator; + HRESULT hr; + + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &mt2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ok(!!testsink->sink.pAllocator, "Expected an allocator.\n"); + hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(props.cBuffers == 1, "Got %d buffers.\n", props.cBuffers); + ok(props.cbBuffer == 16384, "Got size %d.\n", props.cbBuffer); + ok(props.cbAlign == 1, "Got alignment %d.\n", props.cbAlign); + ok(!props.cbPrefix, "Got prefix %d.\n", props.cbPrefix); + + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + + testdmo_output_alignment = 16; + testdmo_output_size = 20000; + + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &mt2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ok(!!testsink->sink.pAllocator, "Expected an allocator.\n"); + hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(props.cBuffers == 1, "Got %d buffers.\n", props.cBuffers); + ok(props.cbBuffer == 20000, "Got size %d.\n", props.cbBuffer); + ok(props.cbAlign == 16, "Got alignment %d.\n", props.cbAlign); + ok(!props.cbPrefix, "Got prefix %d.\n", props.cbPrefix); + + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + + testdmo_GetOutputSizeInfo_hr = E_NOTIMPL; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &mt2); + ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr); + testdmo_GetOutputSizeInfo_hr = S_OK; + + CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, + &IID_IMemAllocator, (void **)&allocator); + testsink->sink.pAllocator = allocator; + + hr = IMemAllocator_SetProperties(allocator, &req_props, &props); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &mt2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ok(testsink->sink.pAllocator == allocator, "Expected an allocator.\n"); + hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(props.cBuffers == 1, "Got %d buffers.\n", props.cBuffers); + ok(props.cbBuffer == 20000, "Got size %d.\n", props.cbBuffer); + ok(props.cbAlign == 16, "Got alignment %d.\n", props.cbAlign); + ok(!props.cbPrefix, "Got prefix %d.\n", props.cbPrefix); + + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface); + +} + static void test_connect_pin(void) { AM_MEDIA_TYPE req_mt = @@ -1146,20 +1223,23 @@ static void test_connect_pin(void) .formattype = FORMAT_None, }; IBaseFilter *filter = create_dmo_wrapper(); - struct testfilter testsource; + struct testfilter testsource, testsink; + IPin *sink, *source, *peer; IMemInputPin *meminput; IFilterGraph2 *graph; - IPin *sink, *peer; AM_MEDIA_TYPE mt; HRESULT hr; ULONG ref;
testfilter_init(&testsource); + testfilter_init(&testsink); CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (void **)&graph); IFilterGraph2_AddFilter(graph, &testsource.filter.IBaseFilter_iface, L"source"); + IFilterGraph2_AddFilter(graph, &testsink.filter.IBaseFilter_iface, L"sink"); IFilterGraph2_AddFilter(graph, filter, L"DMO wrapper"); IBaseFilter_FindPin(filter, L"in0", &sink); + IBaseFilter_FindPin(filter, L"out0", &source); IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&meminput);
/* Test sink connection. */ @@ -1194,6 +1274,149 @@ static void test_connect_pin(void)
test_sink_allocator(meminput);
+ /* Test source connection. */ + peer = (IPin *)0xdeadbeef; + hr = IPin_ConnectedTo(source, &peer); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + ok(!peer, "Got peer %p.\n", peer); + + hr = IPin_ConnectionMediaType(source, &mt); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + + ok(!testdmo_output_mt_set, "Output type should not be set.\n"); + + /* Exact connection. */ + + req_mt = mt2; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IPin_ConnectedTo(source, &peer); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(peer == &testsink.sink.pin.IPin_iface, "Got peer %p.\n", peer); + IPin_Release(peer); + + hr = IPin_ConnectionMediaType(source, &mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&mt, &req_mt), "Media types didn't match.\n"); + + ok(testdmo_output_mt_set, "Ouput type should be set.\n"); + ok(compare_media_types(&testdmo_output_mt, &req_mt), "Media types didn't match.\n"); + + hr = IFilterGraph2_Disconnect(graph, source); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IFilterGraph2_Disconnect(graph, source); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + ok(testsink.sink.pin.peer == source, "Got peer %p.\n", testsink.sink.pin.peer); + IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface); + + peer = (IPin *)0xdeadbeef; + hr = IPin_ConnectedTo(source, &peer); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + ok(!peer, "Got peer %p.\n", peer); + + hr = IPin_ConnectionMediaType(source, &mt); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr); + + ok(!testdmo_output_mt_set, "Output type should not be set.\n"); + + req_mt.lSampleSize = 0; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); + + /* Connection with wildcards. */ + + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&testsink.sink.pin.mt, &mt2), "Media types didn't match.\n"); + ok(testdmo_output_mt_set, "Ouput type should be set.\n"); + ok(compare_media_types(&testdmo_output_mt, &mt2), "Media types didn't match.\n"); + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface); + + req_mt.majortype = GUID_NULL; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&testsink.sink.pin.mt, &mt2), "Media types didn't match.\n"); + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface); + + req_mt.subtype = MEDIASUBTYPE_RGB32; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + + req_mt.subtype = GUID_NULL; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&testsink.sink.pin.mt, &mt2), "Media types didn't match.\n"); + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface); + + req_mt.formattype = FORMAT_WaveFormatEx; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + + req_mt = mt2; + req_mt.formattype = GUID_NULL; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&testsink.sink.pin.mt, &mt2), "Media types didn't match.\n"); + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface); + + req_mt.subtype = MEDIASUBTYPE_RGB32; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + + req_mt.subtype = GUID_NULL; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&testsink.sink.pin.mt, &mt2), "Media types didn't match.\n"); + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface); + + req_mt.majortype = MEDIATYPE_Audio; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + + mt = req_mt; + testsink.sink_mt = &mt; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&testsink.sink.pin.mt, &mt), "Media types didn't match.\n"); + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface); + + mt.lSampleSize = 1; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + mt.lSampleSize = 321; + + mt.majortype = mt.subtype = mt.formattype = GUID_NULL; + req_mt = mt; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(&testsink.sink.pin.mt, &mt), "Media types didn't match.\n"); + IFilterGraph2_Disconnect(graph, source); + IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface); + + req_mt.majortype = mt2.majortype; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + req_mt.majortype = GUID_NULL; + + req_mt.subtype = mt2.subtype; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + req_mt.subtype = GUID_NULL; + + req_mt.formattype = mt2.formattype; + hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); + ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr); + req_mt.formattype = GUID_NULL; + + testsink.sink_mt = NULL; + hr = IFilterGraph2_Disconnect(graph, sink); ok(hr == S_OK, "Got hr %#x.\n", hr); hr = IFilterGraph2_Disconnect(graph, sink); @@ -1211,7 +1434,10 @@ static void test_connect_pin(void)
ok(!testdmo_input_mt_set, "Input type should not be set.\n");
+ test_source_allocator(graph, source, &testsink); + IPin_Release(sink); + IPin_Release(source); IMemInputPin_Release(meminput); ref = IFilterGraph2_Release(graph); ok(!ref, "Got outstanding refcount %d.\n", ref); @@ -1219,6 +1445,8 @@ static void test_connect_pin(void) ok(!ref, "Got outstanding refcount %d.\n", ref); ref = IBaseFilter_Release(&testsource.filter.IBaseFilter_iface); ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(&testsink.filter.IBaseFilter_iface); + ok(!ref, "Got outstanding refcount %d.\n", ref); }
START_TEST(dmowrapper) diff --git a/dlls/strmbase/pin.c b/dlls/strmbase/pin.c index 8a565b536e2..4676c9d82b0 100644 --- a/dlls/strmbase/pin.c +++ b/dlls/strmbase/pin.c @@ -555,6 +555,9 @@ static HRESULT WINAPI source_Disconnect(IPin *iface) return VFW_E_NOT_STOPPED; }
+ if (This->pFuncsTable->source_disconnect) + This->pFuncsTable->source_disconnect(This); + if (This->pMemInputPin) { IMemInputPin_Release(This->pMemInputPin); diff --git a/include/wine/strmbase.h b/include/wine/strmbase.h index 5151e68644b..0e0f73afa3c 100644 --- a/include/wine/strmbase.h +++ b/include/wine/strmbase.h @@ -74,6 +74,8 @@ struct strmbase_source_ops BaseOutputPin_DecideBufferSize pfnDecideBufferSize; /* Required for BaseOutputPinImpl_AttemptConnection */ BaseOutputPin_DecideAllocator pfnDecideAllocator; + + void (*source_disconnect)(struct strmbase_source *pin); };
struct strmbase_sink