diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c index 5035f80c7f7..b1059ca9d58 100644 --- a/dlls/quartz/tests/filtergraph.c +++ b/dlls/quartz/tests/filtergraph.c @@ -767,6 +767,7 @@ struct testpin PIN_DIRECTION dir; IBaseFilter *filter; IPin *peer; + AM_MEDIA_TYPE *mt; IEnumMediaTypes IEnumMediaTypes_iface; const AM_MEDIA_TYPE *types; @@ -991,7 +992,19 @@ static HRESULT WINAPI testpin_EndOfStream(IPin *iface) return E_NOTIMPL; } -static HRESULT WINAPI testsink_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt) +static HRESULT WINAPI no_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI no_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI no_EnumMediaTypes(IPin *iface, IEnumMediaTypes **out) { ok(0, "Unexpected call.\n"); return E_NOTIMPL; @@ -1007,18 +1020,12 @@ static HRESULT WINAPI testsink_ReceiveConnection(IPin *iface, IPin *peer, const return S_OK; } -static HRESULT WINAPI testsink_EnumMediaTypes(IPin *iface, IEnumMediaTypes **out) -{ - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} - static const IPinVtbl testsink_vtbl = { testpin_QueryInterface, testpin_AddRef, testpin_Release, - testsink_Connect, + no_Connect, testsink_ReceiveConnection, testpin_Disconnect, testpin_ConnectedTo, @@ -1027,7 +1034,7 @@ static const IPinVtbl testsink_vtbl = testpin_QueryDirection, testpin_QueryId, testpin_QueryAccept, - testsink_EnumMediaTypes, + no_EnumMediaTypes, testpin_QueryInternalConnections, testpin_EndOfStream, testpin_BeginFlush, @@ -1057,19 +1064,13 @@ static HRESULT WINAPI testsource_Connect(IPin *iface, IPin *peer, const AM_MEDIA return IPin_ReceiveConnection(peer, &pin->IPin_iface, mt); } -static HRESULT WINAPI testsource_ReceiveConnection(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt) -{ - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} - static const IPinVtbl testsource_vtbl = { testpin_QueryInterface, testpin_AddRef, testpin_Release, testsource_Connect, - testsource_ReceiveConnection, + no_ReceiveConnection, testpin_Disconnect, testpin_ConnectedTo, testpin_ConnectionMediaType, @@ -1864,6 +1865,156 @@ static void test_add_remove_filter(void) ok(filter.ref == 1, "Got outstanding refcount %d.\n", filter.ref); } +static HRESULT WINAPI test_connect_direct_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt) +{ + struct testpin *pin = impl_from_IPin(iface); + if (winetest_debug > 1) trace("%p->Connect()\n", pin); + + pin->peer = peer; + IPin_AddRef(peer); + pin->mt = (AM_MEDIA_TYPE *)mt; + return S_OK; +} + +static const IPinVtbl test_connect_direct_vtbl = +{ + testpin_QueryInterface, + testpin_AddRef, + testpin_Release, + test_connect_direct_Connect, + no_ReceiveConnection, + testpin_Disconnect, + testpin_ConnectedTo, + testpin_ConnectionMediaType, + testpin_QueryPinInfo, + testpin_QueryDirection, + testpin_QueryId, + testpin_QueryAccept, + no_EnumMediaTypes, + testpin_QueryInternalConnections, + testpin_EndOfStream, + testpin_BeginFlush, + testpin_EndFlush, + testpin_NewSegment +}; + +static void test_connect_direct_init(struct testpin *pin, PIN_DIRECTION dir) +{ + memset(pin, 0, sizeof(*pin)); + pin->IPin_iface.lpVtbl = &test_connect_direct_vtbl; + pin->ref = 1; + pin->dir = dir; +} + +static void test_connect_direct(void) +{ + struct testpin source_pin, sink_pin; + struct testfilter source, sink; + + IFilterGraph2 *graph = create_graph(); + AM_MEDIA_TYPE mt; + HRESULT hr; + + test_connect_direct_init(&source_pin, PINDIR_OUTPUT); + test_connect_direct_init(&sink_pin, PINDIR_INPUT); + testfilter_init(&source, &source_pin, 1); + testfilter_init(&sink, &sink_pin, 1); + + hr = IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IFilterGraph2_AddFilter(graph, &sink.IBaseFilter_iface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IFilterGraph2_ConnectDirect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &sink_pin.IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(!source_pin.mt, "Got mt %p.\n", source_pin.mt); + ok(!sink_pin.peer, "Got peer %p.\n", sink_pin.peer); + + hr = IFilterGraph2_Disconnect(graph, &sink_pin.IPin_iface); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + ok(source_pin.peer == &sink_pin.IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(!sink_pin.peer, "Got peer %p.\n", sink_pin.peer); + + hr = IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!source_pin.peer, "Got peer %p.\n", source_pin.peer); + ok(!sink_pin.peer, "Got peer %p.\n", sink_pin.peer); + + /* Swap the pins when connecting. */ + hr = IFilterGraph2_ConnectDirect(graph, &sink_pin.IPin_iface, &source_pin.IPin_iface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); +todo_wine + ok(sink_pin.peer == &source_pin.IPin_iface, "Got peer %p.\n", sink_pin.peer); + ok(!sink_pin.mt, "Got mt %p.\n", sink_pin.mt); +todo_wine + ok(!source_pin.peer, "Got peer %p.\n", source_pin.peer); + + hr = IFilterGraph2_Disconnect(graph, &sink_pin.IPin_iface); +todo_wine + ok(hr == S_OK, "Got hr %#x.\n", hr); +todo_wine + ok(!source_pin.peer, "Got peer %p.\n", source_pin.peer); + ok(!sink_pin.peer, "Got peer %p.\n", sink_pin.peer); + + /* Disconnect() does not disconnect the peer. */ + hr = IFilterGraph2_ConnectDirect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &sink_pin.IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(!source_pin.mt, "Got mt %p.\n", source_pin.mt); + ok(!sink_pin.peer, "Got peer %p.\n", sink_pin.peer); + + sink_pin.peer = &source_pin.IPin_iface; + IPin_AddRef(sink_pin.peer); + + hr = IFilterGraph2_Disconnect(graph, &sink_pin.IPin_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &sink_pin.IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(!sink_pin.peer, "Got peer %p.\n", sink_pin.peer); + + hr = IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!source_pin.peer, "Got peer %p.\n", source_pin.peer); + ok(!sink_pin.peer, "Got peer %p.\n", sink_pin.peer); + + /* Test specifying the media type. */ + hr = IFilterGraph2_ConnectDirect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface, &mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &sink_pin.IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(source_pin.mt == &mt, "Got mt %p.\n", source_pin.mt); + ok(!sink_pin.peer, "Got peer %p.\n", sink_pin.peer); + + /* Both pins are disconnected when a filter is removed. */ + sink_pin.peer = &source_pin.IPin_iface; + IPin_AddRef(sink_pin.peer); + hr = IFilterGraph2_RemoveFilter(graph, &source.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!source_pin.peer, "Got peer %p.\n", source_pin.peer); + ok(!sink_pin.peer, "Got peer %p.\n", sink_pin.peer); + + /* Or when the graph is destroyed. */ + hr = IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IFilterGraph2_ConnectDirect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &sink_pin.IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(!source_pin.mt, "Got mt %p.\n", source_pin.mt); + ok(!sink_pin.peer, "Got peer %p.\n", sink_pin.peer); + IPin_AddRef(sink_pin.peer = &source_pin.IPin_iface); + + hr = IFilterGraph2_Release(graph); + ok(!hr, "Got outstanding refcount %d.\n", hr); + ok(source.ref == 1, "Got outstanding refcount %d.\n", source.ref); + ok(sink.ref == 1, "Got outstanding refcount %d.\n", sink.ref); + ok(source_pin.ref == 1, "Got outstanding refcount %d.\n", source_pin.ref); +todo_wine + ok(sink_pin.ref == 1, "Got outstanding refcount %d.\n", sink_pin.ref); + ok(!source_pin.peer, "Got peer %p.\n", source_pin.peer); + ok(!sink_pin.peer, "Got peer %p.\n", sink_pin.peer); +} + START_TEST(filtergraph) { CoInitializeEx(NULL, COINIT_MULTITHREADED); @@ -1876,6 +2027,7 @@ START_TEST(filtergraph) test_aggregate_filter_graph(); test_control_delegation(); test_add_remove_filter(); + test_connect_direct(); CoUninitialize(); test_render_with_multithread();