Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/tests/filtergraph.c | 184 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 168 insertions(+), 16 deletions(-)
diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c index 5035f80..b1059ca 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();
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/tests/filtergraph.c | 375 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 354 insertions(+), 21 deletions(-)
diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c index b1059ca..5bfe7b6 100644 --- a/dlls/quartz/tests/filtergraph.c +++ b/dlls/quartz/tests/filtergraph.c @@ -538,7 +538,7 @@ static void rungraph(IFilterGraph2 *graph) test_media_event(graph); }
-static HRESULT test_graph_builder_connect(WCHAR *filename) +static HRESULT test_graph_builder_connect_file(WCHAR *filename) { static const WCHAR outputW[] = {'O','u','t','p','u','t',0}; static const WCHAR inW[] = {'I','n',0}; @@ -608,7 +608,7 @@ static void test_render_run(const WCHAR *file) refs = IFilterGraph2_Release(graph); ok(!refs, "Graph has %u references\n", refs);
- hr = test_graph_builder_connect(filename); + hr = test_graph_builder_connect_file(filename); todo_wine ok(hr == VFW_E_CANNOT_CONNECT, "got %#x\n", hr); } @@ -620,7 +620,7 @@ todo_wine refs = IFilterGraph2_Release(graph); ok(!refs, "Graph has %u references\n", refs);
- hr = test_graph_builder_connect(filename); + hr = test_graph_builder_connect_file(filename); ok(hr == S_OK || hr == VFW_S_PARTIAL_RENDER, "got %#x\n", hr); }
@@ -772,6 +772,9 @@ struct testpin IEnumMediaTypes IEnumMediaTypes_iface; const AM_MEDIA_TYPE *types; unsigned int type_count, enum_idx; + AM_MEDIA_TYPE *request_mt, *accept_mt; + + HRESULT QueryInternalConnections_hr; };
static inline struct testpin *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface) @@ -942,7 +945,9 @@ static HRESULT WINAPI testpin_QueryDirection(IPin *iface, PIN_DIRECTION *dir) static HRESULT WINAPI testpin_QueryId(IPin *iface, WCHAR **id) { if (winetest_debug > 1) trace("%p->QueryId()\n", iface); - return E_NOTIMPL; + *id = CoTaskMemAlloc(1); + (*id)[0] = 0; + return S_OK; }
static HRESULT WINAPI testpin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mt) @@ -964,8 +969,11 @@ static HRESULT WINAPI testpin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **out)
static HRESULT WINAPI testpin_QueryInternalConnections(IPin *iface, IPin **out, ULONG *count) { - if (winetest_debug > 1) trace("%p->QueryInternalConnections()\n", iface); - return E_NOTIMPL; + struct testpin *pin = impl_from_IPin(iface); + if (winetest_debug > 1) trace("%p->QueryInternalConnections()\n", pin); + + *count = 0; + return pin->QueryInternalConnections_hr; }
static HRESULT WINAPI testpin_BeginFlush(IPin *iface) @@ -1015,6 +1023,9 @@ static HRESULT WINAPI testsink_ReceiveConnection(IPin *iface, IPin *peer, const struct testpin *pin = impl_from_IPin(iface); if (winetest_debug > 1) trace("%p->ReceiveConnection(%p)\n", pin, peer);
+ if (pin->accept_mt && memcmp(pin->accept_mt, mt, sizeof(*mt))) + return VFW_E_TYPE_NOT_ACCEPTED; + pin->peer = peer; IPin_AddRef(peer); return S_OK; @@ -1042,26 +1053,35 @@ static const IPinVtbl testsink_vtbl = testpin_NewSegment };
-static void testsink_init(struct testpin *pin) +static void testpin_init(struct testpin *pin, const IPinVtbl *vtbl, PIN_DIRECTION dir) { memset(pin, 0, sizeof(*pin)); - pin->IPin_iface.lpVtbl = &testsink_vtbl; - pin->ref = 1; - pin->dir = PINDIR_INPUT; - + pin->IPin_iface.lpVtbl = vtbl; pin->IEnumMediaTypes_iface.lpVtbl = &testenummt_vtbl; + pin->ref = 1; + pin->dir = dir; + pin->QueryInternalConnections_hr = E_NOTIMPL; +} + +static void testsink_init(struct testpin *pin) +{ + testpin_init(pin, &testsink_vtbl, PINDIR_INPUT); }
static HRESULT WINAPI testsource_Connect(IPin *iface, IPin *peer, const AM_MEDIA_TYPE *mt) { struct testpin *pin = impl_from_IPin(iface); + HRESULT hr; if (winetest_debug > 1) trace("%p->Connect(%p)\n", pin, peer);
ok(!mt, "Got media type %p.\n", mt);
- pin->peer = peer; - IPin_AddRef(peer); - return IPin_ReceiveConnection(peer, &pin->IPin_iface, mt); + if (SUCCEEDED(hr = IPin_ReceiveConnection(peer, &pin->IPin_iface, pin->request_mt))) + { + pin->peer = peer; + IPin_AddRef(peer); + } + return hr; }
static const IPinVtbl testsource_vtbl = @@ -1088,12 +1108,7 @@ static const IPinVtbl testsource_vtbl =
static void testsource_init(struct testpin *pin, const AM_MEDIA_TYPE *types, int type_count) { - memset(pin, 0, sizeof(*pin)); - pin->IPin_iface.lpVtbl = &testsource_vtbl; - pin->ref = 1; - pin->dir = PINDIR_OUTPUT; - - pin->IEnumMediaTypes_iface.lpVtbl = &testenummt_vtbl; + testpin_init(pin, &testsource_vtbl, PINDIR_OUTPUT); pin->types = types; pin->type_count = type_count; } @@ -1224,7 +1239,7 @@ static ULONG WINAPI testfilter_Release(IBaseFilter *iface) static HRESULT WINAPI testfilter_GetClassID(IBaseFilter *iface, CLSID *clsid) { if (winetest_debug > 1) trace("%p->GetClassID()\n", iface); - return E_NOTIMPL; + return S_OK; }
static HRESULT WINAPI testfilter_Stop(IBaseFilter *iface) @@ -1608,6 +1623,292 @@ out: ok(parser_pins[1].ref == 1, "Got outstanding refcount %d.\n", parser_pins[1].ref); }
+static void test_graph_builder_connect(void) +{ + static const WCHAR testW[] = {'t','e','s','t',0}; + static const GUID parser1_clsid = {0x12345678}; + static const GUID parser2_clsid = {0x87654321}; + AM_MEDIA_TYPE source_type = {{0}}, sink_type = {{0}}, parser3_type = {{0}}; + struct testpin source_pin, sink_pin, sink2_pin, parser1_pins[3], parser2_pins[2], parser3_pins[2]; + struct testfilter source, sink, sink2, parser1, parser2, parser3; + struct testfilter_cf parser1_cf = { {&testfilter_cf_vtbl}, &parser1 }; + struct testfilter_cf parser2_cf = { {&testfilter_cf_vtbl}, &parser2 }; + + IFilterGraph2 *graph = create_graph(); + REGFILTERPINS2 regpins[2] = {0}; + REGPINTYPES regtypes = {0}; + REGFILTER2 regfilter = {0}; + IFilterMapper2 *mapper; + DWORD cookie1, cookie2; + HRESULT hr; + ULONG ref; + + memset(&source_type.majortype, 0xcc, sizeof(GUID)); + memset(&sink_type.majortype, 0x66, sizeof(GUID)); + testsource_init(&source_pin, &source_type, 1); + source_pin.request_mt = &source_type; + testfilter_init(&source, &source_pin, 1); + testsink_init(&sink_pin); + testfilter_init(&sink, &sink_pin, 1); + testsink_init(&sink2_pin); + testfilter_init(&sink2, &sink2_pin, 1); + + testsink_init(&parser1_pins[0]); + testsource_init(&parser1_pins[1], &sink_type, 1); + parser1_pins[1].request_mt = &sink_type; + testsource_init(&parser1_pins[2], &sink_type, 1); + parser1_pins[2].request_mt = &sink_type; + testfilter_init(&parser1, parser1_pins, 3); + parser1.pin_count = 2; + + testsink_init(&parser2_pins[0]); + testsource_init(&parser2_pins[1], &sink_type, 1); + parser2_pins[1].request_mt = &sink_type; + testfilter_init(&parser2, parser2_pins, 2); + + testsink_init(&parser3_pins[0]); + testsource_init(&parser3_pins[1], &sink_type, 1); + parser3_pins[1].request_mt = &parser3_type; + testfilter_init(&parser3, parser3_pins, 2); + + IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL); + IFilterGraph2_AddFilter(graph, &sink.IBaseFilter_iface, NULL); + + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &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); + IFilterGraph2_Disconnect(graph, source_pin.peer); + IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); + + sink_pin.accept_mt = &sink_type; + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); +todo_wine + ok(hr == VFW_E_CANNOT_CONNECT, "Got hr %#x.\n", hr); + ok(!source_pin.peer, "Got peer %p.\n", source_pin.peer); + + /* Test usage of intermediate filters. Similarly to Render(), filters are + * simply tried in enumeration order. */ + + IFilterGraph2_AddFilter(graph, &parser1.IBaseFilter_iface, NULL); + IFilterGraph2_AddFilter(graph, &parser2.IBaseFilter_iface, NULL); + + sink_pin.accept_mt = NULL; + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &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); + IFilterGraph2_Disconnect(graph, source_pin.peer); + IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); + + sink_pin.accept_mt = &sink_type; + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); +todo_wine { + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &parser2_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(sink_pin.peer == &parser2_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); +} + IFilterGraph2_Disconnect(graph, source_pin.peer); + IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); + IFilterGraph2_Disconnect(graph, sink_pin.peer); + IFilterGraph2_Disconnect(graph, &sink_pin.IPin_iface); + + IFilterGraph2_RemoveFilter(graph, &parser1.IBaseFilter_iface); + IFilterGraph2_AddFilter(graph, &parser1.IBaseFilter_iface, NULL); + + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); +todo_wine { + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &parser1_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(sink_pin.peer == &parser1_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); +} + IFilterGraph2_Disconnect(graph, source_pin.peer); + IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); + IFilterGraph2_Disconnect(graph, sink_pin.peer); + IFilterGraph2_Disconnect(graph, &sink_pin.IPin_iface); + + /* No preference is given to smaller chains. */ + + IFilterGraph2_AddFilter(graph, &parser3.IBaseFilter_iface, NULL); + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); +todo_wine { + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &parser3_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(parser3_pins[1].peer == &parser1_pins[0].IPin_iface, "Got peer %p.\n", parser3_pins[1].peer); + ok(sink_pin.peer == &parser1_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); +} + IFilterGraph2_Disconnect(graph, source_pin.peer); + IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); + IFilterGraph2_Disconnect(graph, parser3_pins[0].peer); + IFilterGraph2_Disconnect(graph, &parser3_pins[0].IPin_iface); + IFilterGraph2_Disconnect(graph, sink_pin.peer); + IFilterGraph2_Disconnect(graph, &sink_pin.IPin_iface); + + IFilterGraph2_RemoveFilter(graph, &parser3.IBaseFilter_iface); + IFilterGraph2_RemoveFilter(graph, &parser2.IBaseFilter_iface); + + /* Extra source pins on an intermediate filter are not rendered. */ + + IFilterGraph2_RemoveFilter(graph, &parser1.IBaseFilter_iface); + parser1.pin_count = 3; + IFilterGraph2_AddFilter(graph, &parser1.IBaseFilter_iface, NULL); + IFilterGraph2_AddFilter(graph, &sink2.IBaseFilter_iface, NULL); + + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); +todo_wine { + ok(hr == VFW_S_PARTIAL_RENDER, "Got hr %#x.\n", hr); + ok(source_pin.peer == &parser1_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(sink_pin.peer == &parser1_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); +} + ok(!parser1_pins[2].peer, "Got peer %p.\n", parser1_pins[2].peer); + IFilterGraph2_Disconnect(graph, source_pin.peer); + IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); + IFilterGraph2_Disconnect(graph, sink_pin.peer); + IFilterGraph2_Disconnect(graph, &sink_pin.IPin_iface); + parser1.pin_count = 2; + + /* QueryInternalConnections is not used to find output pins. */ + + parser1_pins[1].QueryInternalConnections_hr = S_OK; + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); +todo_wine { + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &parser1_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(sink_pin.peer == &parser1_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); +} + IFilterGraph2_Disconnect(graph, source_pin.peer); + IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); + IFilterGraph2_Disconnect(graph, sink_pin.peer); + IFilterGraph2_Disconnect(graph, &sink_pin.IPin_iface); + + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + /* Test enumeration of filters from the registry. */ + + graph = create_graph(); + IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL); + IFilterGraph2_AddFilter(graph, &sink.IBaseFilter_iface, NULL); + + CoRegisterClassObject(&parser1_clsid, (IUnknown *)&parser1_cf.IClassFactory_iface, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie1); + CoRegisterClassObject(&parser2_clsid, (IUnknown *)&parser2_cf.IClassFactory_iface, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie2); + + CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, + &IID_IFilterMapper2, (void **)&mapper); + + regfilter.dwVersion = 2; + regfilter.dwMerit = MERIT_UNLIKELY; + regfilter.cPins2 = 2; + regfilter.rgPins2 = regpins; + regpins[0].dwFlags = 0; + regpins[0].cInstances = 1; + regpins[0].nMediaTypes = 1; + regpins[0].lpMediaType = ®types; + regpins[1].dwFlags = REG_PINFLAG_B_OUTPUT; + regpins[1].cInstances = 1; + regpins[1].nMediaTypes = 1; + regpins[1].lpMediaType = ®types; + regtypes.clsMajorType = &source_type.majortype; + regtypes.clsMinorType = &MEDIASUBTYPE_NULL; + hr = IFilterMapper2_RegisterFilter(mapper, &parser1_clsid, testW, NULL, NULL, NULL, ®filter); + if (hr == E_ACCESSDENIED) + { + skip("Not enough permission to register filters.\n"); + goto out; + } + ok(hr == S_OK, "Got hr %#x.\n", hr); + + IFilterMapper2_RegisterFilter(mapper, &parser2_clsid, testW, NULL, NULL, NULL, ®filter); + + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &parser1_pins[0].IPin_iface + || source_pin.peer == &parser2_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(sink_pin.peer == &parser1_pins[1].IPin_iface + || sink_pin.peer == &parser2_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); + + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + /* Preference is given to filters already in the graph. */ + + graph = create_graph(); + IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL); + IFilterGraph2_AddFilter(graph, &sink.IBaseFilter_iface, NULL); + IFilterGraph2_AddFilter(graph, &parser1.IBaseFilter_iface, NULL); + + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &parser1_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(sink_pin.peer == &parser1_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); + + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + /* Preference is given to filters with higher merit. */ + + graph = create_graph(); + IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL); + IFilterGraph2_AddFilter(graph, &sink.IBaseFilter_iface, NULL); + + IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &parser1_clsid); + IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &parser2_clsid); + + regfilter.dwMerit = MERIT_UNLIKELY; + IFilterMapper2_RegisterFilter(mapper, &parser1_clsid, testW, NULL, NULL, NULL, ®filter); + regfilter.dwMerit = MERIT_PREFERRED; + IFilterMapper2_RegisterFilter(mapper, &parser2_clsid, testW, NULL, NULL, NULL, ®filter); + + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &parser2_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(sink_pin.peer == &parser2_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); + + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + graph = create_graph(); + IFilterGraph2_AddFilter(graph, &source.IBaseFilter_iface, NULL); + IFilterGraph2_AddFilter(graph, &sink.IBaseFilter_iface, NULL); + + IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &parser1_clsid); + IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &parser2_clsid); + + regfilter.dwMerit = MERIT_PREFERRED; + IFilterMapper2_RegisterFilter(mapper, &parser1_clsid, testW, NULL, NULL, NULL, ®filter); + regfilter.dwMerit = MERIT_UNLIKELY; + IFilterMapper2_RegisterFilter(mapper, &parser2_clsid, testW, NULL, NULL, NULL, ®filter); + + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &parser1_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(sink_pin.peer == &parser1_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); + + IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &parser1_clsid); + IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &parser2_clsid); + +out: + CoRevokeClassObject(cookie1); + CoRevokeClassObject(cookie2); + IFilterMapper2_Release(mapper); + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ok(source.ref == 1, "Got outstanding refcount %d.\n", source.ref); + ok(source_pin.ref == 1, "Got outstanding refcount %d.\n", source_pin.ref); + ok(sink.ref == 1, "Got outstanding refcount %d.\n", sink.ref); + ok(sink_pin.ref == 1, "Got outstanding refcount %d.\n", sink_pin.ref); + ok(parser1.ref == 1, "Got outstanding refcount %d.\n", parser1.ref); + ok(parser1_pins[0].ref == 1, "Got outstanding refcount %d.\n", parser1_pins[0].ref); + ok(parser1_pins[1].ref == 1, "Got outstanding refcount %d.\n", parser1_pins[1].ref); + ok(parser1_pins[2].ref == 1, "Got outstanding refcount %d.\n", parser1_pins[2].ref); + ok(parser2.ref == 1, "Got outstanding refcount %d.\n", parser2.ref); + ok(parser2_pins[0].ref == 1, "Got outstanding refcount %d.\n", parser2_pins[0].ref); + ok(parser2_pins[1].ref == 1, "Got outstanding refcount %d.\n", parser2_pins[1].ref); + ok(parser3.ref == 1, "Got outstanding refcount %d.\n", parser3.ref); + ok(parser3_pins[0].ref == 1, "Got outstanding refcount %d.\n", parser3_pins[0].ref); + ok(parser3_pins[1].ref == 1, "Got outstanding refcount %d.\n", parser3_pins[1].ref); +} + typedef struct IUnknownImpl { IUnknown IUnknown_iface; @@ -1942,6 +2243,22 @@ static void test_connect_direct(void) ok(!source_pin.peer, "Got peer %p.\n", source_pin.peer); ok(!sink_pin.peer, "Got peer %p.\n", sink_pin.peer);
+ hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &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(!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); @@ -1958,6 +2275,21 @@ todo_wine ok(!source_pin.peer, "Got peer %p.\n", source_pin.peer); ok(!sink_pin.peer, "Got peer %p.\n", sink_pin.peer);
+ hr = IFilterGraph2_Connect(graph, &sink_pin.IPin_iface, &source_pin.IPin_iface); + 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); @@ -2024,6 +2356,7 @@ START_TEST(filtergraph) test_render_run(mpegfile); test_enum_filters(); test_graph_builder_render(); + test_graph_builder_connect(); test_aggregate_filter_graph(); test_control_delegation(); test_add_remove_filter();
The tests need the following patch in order to pass.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/filtergraph.c | 102 +++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 50 deletions(-)
diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index 1fa6476..6fe5b80 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -1070,6 +1070,55 @@ static HRESULT GetInternalConnections(IBaseFilter* pfilter, IPin* pinputpin, IPi return S_OK; }
+/* Attempt to connect one of the output pins on filter to sink. Helper for + * FilterGraph2_Connect(). */ +static HRESULT connect_output_pin(IFilterGraphImpl *graph, IBaseFilter *filter, IPin *sink) +{ + IEnumPins *enumpins; + PIN_DIRECTION dir; + HRESULT hr; + WCHAR *id; + IPin *pin; + + hr = IBaseFilter_EnumPins(filter, &enumpins); + if (FAILED(hr)) + return hr; + + while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK) + { + IPin_QueryDirection(pin, &dir); + if (dir == PINDIR_OUTPUT) + { + hr = IPin_QueryId(pin, &id); + if (FAILED(hr)) + { + IPin_Release(pin); + IEnumPins_Release(enumpins); + return hr; + } + + if (id[0] == '~') + { + TRACE("Skipping non-rendered pin %s.\n", debugstr_w(id)); + IPin_Release(pin); + IEnumPins_Release(enumpins); + return E_FAIL; + } + + if (SUCCEEDED(IFilterGraph2_Connect(&graph->IFilterGraph2_iface, pin, sink))) + { + IPin_Release(pin); + IEnumPins_Release(enumpins); + return S_OK; + } + } + IPin_Release(pin); + } + + IEnumPins_Release(enumpins); + return VFW_E_CANNOT_CONNECT; +} + /*** IGraphBuilder methods ***/ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, IPin *ppinIn) { @@ -1081,13 +1130,11 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, IEnumPins* penumpins; IEnumMoniker* pEnumMoniker; GUID tab[2]; - ULONG nb = 0; IMoniker* pMoniker; ULONG pin; PIN_INFO PinInfo; CLSID FilterCLSID; PIN_DIRECTION dir; - unsigned int i = 0; IFilterMapper2 *pFilterMapper2 = NULL;
TRACE("(%p/%p)->(%p, %p)\n", This, iface, ppinOut, ppinIn); @@ -1196,11 +1243,10 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, }
hr = VFW_E_CANNOT_RENDER; - while(IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, &nb) == S_OK) + while (IEnumMoniker_Next(pEnumMoniker, 1, &pMoniker, NULL) == S_OK) { VARIANT var; GUID clsid; - IPin** ppins = NULL; IPin* ppinfilter = NULL; IBaseFilter* pfilter = NULL; IAMGraphBuilderCallback *callback = NULL; @@ -1297,52 +1343,10 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, } TRACE("Successfully connected to filter, follow chain...\n");
- /* Render all output pins of the filter by calling IFilterGraph2_Connect on each of them */ - hr = GetInternalConnections(pfilter, ppinfilter, &ppins, &nb); - - if (SUCCEEDED(hr)) { - if (nb == 0) { - IPin_Disconnect(ppinfilter); - IPin_Disconnect(ppinOut); - goto error; - } - TRACE("pins to consider: %d\n", nb); - for(i = 0; i < nb; i++) - { - LPWSTR pinname = NULL; - - TRACE("Processing pin %u\n", i); - - hr = IPin_QueryId(ppins[i], &pinname); - if (SUCCEEDED(hr)) - { - if (pinname[0] == '~') - { - TRACE("Pinname=%s, skipping\n", debugstr_w(pinname)); - hr = E_FAIL; - } - else - hr = IFilterGraph2_Connect(iface, ppins[i], ppinIn); - CoTaskMemFree(pinname); - } - - if (FAILED(hr)) { - TRACE("Cannot connect pin %p (%x)\n", ppinfilter, hr); - } - IPin_Release(ppins[i]); - if (SUCCEEDED(hr)) break; - } - while (++i < nb) IPin_Release(ppins[i]); - CoTaskMemFree(ppins); + if (SUCCEEDED(hr = connect_output_pin(This, pfilter, ppinIn))) + { IPin_Release(ppinfilter); IBaseFilter_Release(pfilter); - if (FAILED(hr)) - { - IPin_Disconnect(ppinfilter); - IPin_Disconnect(ppinOut); - IFilterGraph2_RemoveFilter(iface, pfilter); - continue; - } break; }
@@ -1353,8 +1357,6 @@ error: IFilterGraph2_RemoveFilter(iface, pfilter); IBaseFilter_Release(pfilter); } - while (++i < nb) IPin_Release(ppins[i]); - CoTaskMemFree(ppins); }
IEnumMoniker_Release(pEnumMoniker);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/filtergraph.c | 35 ++++++++++++++++++++++++++++++++--- dlls/quartz/tests/filtergraph.c | 11 +---------- 2 files changed, 33 insertions(+), 13 deletions(-)
diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index 6fe5b80..fb1bfc2 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -1123,7 +1123,9 @@ static HRESULT connect_output_pin(IFilterGraphImpl *graph, IBaseFilter *filter, static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, IPin *ppinIn) { IFilterGraphImpl *This = impl_from_IFilterGraph2(iface); + struct filter *filter; HRESULT hr; + IPin *pin; AM_MEDIA_TYPE* mt = NULL; IEnumMediaTypes* penummt = NULL; ULONG nbmt; @@ -1131,7 +1133,6 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, IEnumMoniker* pEnumMoniker; GUID tab[2]; IMoniker* pMoniker; - ULONG pin; PIN_INFO PinInfo; CLSID FilterCLSID; PIN_DIRECTION dir; @@ -1194,6 +1195,34 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut,
TRACE("Direct connection failed, trying to render using extra filters\n");
+ LIST_FOR_EACH_ENTRY(filter, &This->filters, struct filter, entry) + { + hr = IBaseFilter_EnumPins(filter->filter, &penumpins); + if (FAILED(hr)) + goto out; + + while (IEnumPins_Next(penumpins, 1, &pin, NULL) == S_OK) + { + IPin_QueryDirection(pin, &dir); + if (dir == PINDIR_INPUT && SUCCEEDED(IFilterGraph2_ConnectDirect(iface, + ppinOut, pin, NULL))) + { + if (SUCCEEDED(hr = connect_output_pin(This, filter->filter, ppinIn))) + { + IPin_Release(pin); + IEnumPins_Release(penumpins); + goto out; + } + + IFilterGraph2_Disconnect(iface, pin); + IFilterGraph2_Disconnect(iface, ppinOut); + } + IPin_Release(pin); + } + + IEnumPins_Release(penumpins); + } + hr = IPin_QueryPinInfo(ppinIn, &PinInfo); if (FAILED(hr)) goto out; @@ -1324,14 +1353,14 @@ static HRESULT WINAPI FilterGraph2_Connect(IFilterGraph2 *iface, IPin *ppinOut, goto error; }
- hr = IEnumPins_Next(penumpins, 1, &ppinfilter, &pin); + hr = IEnumPins_Next(penumpins, 1, &ppinfilter, NULL); IEnumPins_Release(penumpins);
if (FAILED(hr)) { WARN("Obtaining next pin: (%x)\n", hr); goto error; } - if (pin == 0) { + if (hr == S_FALSE) { WARN("Cannot use this filter: no pins\n"); goto error; } diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c index 5bfe7b6..76dfc16 100644 --- a/dlls/quartz/tests/filtergraph.c +++ b/dlls/quartz/tests/filtergraph.c @@ -1701,11 +1701,9 @@ todo_wine
sink_pin.accept_mt = &sink_type; hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); -todo_wine { ok(hr == S_OK, "Got hr %#x.\n", hr); ok(source_pin.peer == &parser2_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); ok(sink_pin.peer == &parser2_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); -} IFilterGraph2_Disconnect(graph, source_pin.peer); IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); IFilterGraph2_Disconnect(graph, sink_pin.peer); @@ -1715,11 +1713,9 @@ todo_wine { IFilterGraph2_AddFilter(graph, &parser1.IBaseFilter_iface, NULL);
hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); -todo_wine { ok(hr == S_OK, "Got hr %#x.\n", hr); ok(source_pin.peer == &parser1_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); ok(sink_pin.peer == &parser1_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); -} IFilterGraph2_Disconnect(graph, source_pin.peer); IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); IFilterGraph2_Disconnect(graph, sink_pin.peer); @@ -1729,12 +1725,10 @@ todo_wine {
IFilterGraph2_AddFilter(graph, &parser3.IBaseFilter_iface, NULL); hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); -todo_wine { ok(hr == S_OK, "Got hr %#x.\n", hr); ok(source_pin.peer == &parser3_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); ok(parser3_pins[1].peer == &parser1_pins[0].IPin_iface, "Got peer %p.\n", parser3_pins[1].peer); ok(sink_pin.peer == &parser1_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); -} IFilterGraph2_Disconnect(graph, source_pin.peer); IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); IFilterGraph2_Disconnect(graph, parser3_pins[0].peer); @@ -1753,11 +1747,10 @@ todo_wine { IFilterGraph2_AddFilter(graph, &sink2.IBaseFilter_iface, NULL);
hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); -todo_wine { +todo_wine ok(hr == VFW_S_PARTIAL_RENDER, "Got hr %#x.\n", hr); ok(source_pin.peer == &parser1_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); ok(sink_pin.peer == &parser1_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); -} ok(!parser1_pins[2].peer, "Got peer %p.\n", parser1_pins[2].peer); IFilterGraph2_Disconnect(graph, source_pin.peer); IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); @@ -1769,11 +1762,9 @@ todo_wine {
parser1_pins[1].QueryInternalConnections_hr = S_OK; hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); -todo_wine { ok(hr == S_OK, "Got hr %#x.\n", hr); ok(source_pin.peer == &parser1_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); ok(sink_pin.peer == &parser1_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); -} IFilterGraph2_Disconnect(graph, source_pin.peer); IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); IFilterGraph2_Disconnect(graph, sink_pin.peer);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/filtergraph.c | 20 ++++++-------------- dlls/quartz/tests/filtergraph.c | 41 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 17 deletions(-)
diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index fb1bfc2..03d4091 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -1075,9 +1075,8 @@ static HRESULT GetInternalConnections(IBaseFilter* pfilter, IPin* pinputpin, IPi static HRESULT connect_output_pin(IFilterGraphImpl *graph, IBaseFilter *filter, IPin *sink) { IEnumPins *enumpins; - PIN_DIRECTION dir; + PIN_INFO info; HRESULT hr; - WCHAR *id; IPin *pin;
hr = IBaseFilter_EnumPins(filter, &enumpins); @@ -1086,20 +1085,13 @@ static HRESULT connect_output_pin(IFilterGraphImpl *graph, IBaseFilter *filter,
while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK) { - IPin_QueryDirection(pin, &dir); - if (dir == PINDIR_OUTPUT) + IPin_QueryPinInfo(pin, &info); + IBaseFilter_Release(info.pFilter); + if (info.dir == PINDIR_OUTPUT) { - hr = IPin_QueryId(pin, &id); - if (FAILED(hr)) + if (info.achName[0] == '~') { - IPin_Release(pin); - IEnumPins_Release(enumpins); - return hr; - } - - if (id[0] == '~') - { - TRACE("Skipping non-rendered pin %s.\n", debugstr_w(id)); + TRACE("Skipping non-rendered pin %s.\n", debugstr_w(info.achName)); IPin_Release(pin); IEnumPins_Release(enumpins); return E_FAIL; diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c index 76dfc16..d9dc66b 100644 --- a/dlls/quartz/tests/filtergraph.c +++ b/dlls/quartz/tests/filtergraph.c @@ -768,6 +768,8 @@ struct testpin IBaseFilter *filter; IPin *peer; AM_MEDIA_TYPE *mt; + WCHAR name[10]; + WCHAR id[10];
IEnumMediaTypes IEnumMediaTypes_iface; const AM_MEDIA_TYPE *types; @@ -928,7 +930,7 @@ static HRESULT WINAPI testpin_QueryPinInfo(IPin *iface, PIN_INFO *info) info->pFilter = pin->filter; IBaseFilter_AddRef(pin->filter); info->dir = pin->dir; - info->achName[0] = 0; + lstrcpyW(info->achName, pin->name); return S_OK; }
@@ -944,9 +946,10 @@ static HRESULT WINAPI testpin_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
static HRESULT WINAPI testpin_QueryId(IPin *iface, WCHAR **id) { + struct testpin *pin = impl_from_IPin(iface); if (winetest_debug > 1) trace("%p->QueryId()\n", iface); - *id = CoTaskMemAlloc(1); - (*id)[0] = 0; + *id = CoTaskMemAlloc(11); + lstrcpyW(*id, pin->id); return S_OK; }
@@ -1770,6 +1773,38 @@ todo_wine IFilterGraph2_Disconnect(graph, sink_pin.peer); IFilterGraph2_Disconnect(graph, &sink_pin.IPin_iface);
+ /* A pin whose name (not ID) begins with a tilde is not connected. */ + + parser1_pins[1].name[0] = '~'; + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); +todo_wine + ok(hr == VFW_E_CANNOT_CONNECT, "Got hr %#x.\n", hr); + ok(!source_pin.peer, "Got peer %p.\n", source_pin.peer); + + parser1.pin_count = 3; + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); +todo_wine { + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &parser1_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(sink_pin.peer == &parser1_pins[2].IPin_iface, "Got peer %p.\n", sink_pin.peer); +} + IFilterGraph2_Disconnect(graph, source_pin.peer); + IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); + IFilterGraph2_Disconnect(graph, sink_pin.peer); + IFilterGraph2_Disconnect(graph, &sink_pin.IPin_iface); + parser1.pin_count = 2; + + parser1_pins[1].name[0] = 0; + parser1_pins[1].id[0] = '~'; + hr = IFilterGraph2_Connect(graph, &source_pin.IPin_iface, &sink_pin.IPin_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source_pin.peer == &parser1_pins[0].IPin_iface, "Got peer %p.\n", source_pin.peer); + ok(sink_pin.peer == &parser1_pins[1].IPin_iface, "Got peer %p.\n", sink_pin.peer); + IFilterGraph2_Disconnect(graph, source_pin.peer); + IFilterGraph2_Disconnect(graph, &source_pin.IPin_iface); + IFilterGraph2_Disconnect(graph, sink_pin.peer); + IFilterGraph2_Disconnect(graph, &sink_pin.IPin_iface); + ref = IFilterGraph2_Release(graph); ok(!ref, "Got outstanding refcount %d.\n", ref);
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=42327
Your paranoid android.
=== w864 (64 bit Windows report) ===
=== w864 (task log) ===
Task errors: TestBot process got stuck or died unexpectedly The previous 1 run(s) terminated abnormally