Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qcap/tests/capturegraph.c | 189 ++++++++++++++++++--------------- 1 file changed, 104 insertions(+), 85 deletions(-)
diff --git a/dlls/qcap/tests/capturegraph.c b/dlls/qcap/tests/capturegraph.c index 49c4e8fe755..d14753d9417 100644 --- a/dlls/qcap/tests/capturegraph.c +++ b/dlls/qcap/tests/capturegraph.c @@ -35,13 +35,25 @@ static ICaptureGraphBuilder2 *create_capture_graph(void)
static const GUID testiid = {0x11111111}, testtype = {0x22222222};
+struct testsource +{ + struct strmbase_source pin; + IKsPropertySet IKsPropertySet_iface; + BOOL has_iface; +}; + +struct testsink +{ + struct strmbase_sink pin; + BOOL has_iface; +}; + struct testfilter { struct strmbase_filter filter; - struct strmbase_source source, source2; - struct strmbase_sink sink, sink2; - BOOL filter_has_iface, source_has_iface, source2_has_iface, sink_has_iface, sink2_has_iface; - IKsPropertySet IKsPropertySet_iface; + struct testsource source1, source2; + struct testsink sink1, sink2; + BOOL filter_has_iface; };
static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -69,21 +81,23 @@ static struct strmbase_pin *testfilter_get_pin(struct strmbase_filter *iface, un struct testfilter *filter = impl_from_strmbase_filter(iface);
if (!index) - return &filter->source.pin; + return &filter->source1.pin.pin; else if (index == 1) - return &filter->sink.pin; + return &filter->sink1.pin.pin; else if (index == 2) - return &filter->source2.pin; + return &filter->source2.pin.pin; else if (index == 3) - return &filter->sink2.pin; + return &filter->sink2.pin.pin; return NULL; }
static void testfilter_destroy(struct strmbase_filter *iface) { struct testfilter *filter = impl_from_strmbase_filter(iface); - strmbase_source_cleanup(&filter->source); - strmbase_sink_cleanup(&filter->sink); + strmbase_source_cleanup(&filter->source1.pin); + strmbase_source_cleanup(&filter->source2.pin); + strmbase_sink_cleanup(&filter->sink1.pin); + strmbase_sink_cleanup(&filter->sink2.pin); strmbase_filter_cleanup(&filter->filter); }
@@ -94,27 +108,27 @@ static const struct strmbase_filter_ops testfilter_ops = .filter_destroy = testfilter_destroy, };
-static struct testfilter *impl_from_IKsPropertySet(IKsPropertySet *iface) +static struct testsource *impl_from_IKsPropertySet(IKsPropertySet *iface) { - return CONTAINING_RECORD(iface, struct testfilter, IKsPropertySet_iface); + return CONTAINING_RECORD(iface, struct testsource, IKsPropertySet_iface); }
static HRESULT WINAPI property_set_QueryInterface(IKsPropertySet *iface, REFIID iid, void **out) { - struct testfilter *filter = impl_from_IKsPropertySet(iface); - return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out); + struct testsource *pin = impl_from_IKsPropertySet(iface); + return IPin_QueryInterface(&pin->pin.pin.IPin_iface, iid, out); }
static ULONG WINAPI property_set_AddRef(IKsPropertySet *iface) { - struct testfilter *filter = impl_from_IKsPropertySet(iface); - return IPin_AddRef(&filter->source.pin.IPin_iface); + struct testsource *pin = impl_from_IKsPropertySet(iface); + return IPin_AddRef(&pin->pin.pin.IPin_iface); }
static ULONG WINAPI property_set_Release(IKsPropertySet *iface) { - struct testfilter *filter = impl_from_IKsPropertySet(iface); - return IPin_Release(&filter->source.pin.IPin_iface); + struct testsource *pin = impl_from_IKsPropertySet(iface); + return IPin_Release(&pin->pin.pin.IPin_iface); }
static HRESULT WINAPI property_set_Set(IKsPropertySet *iface, REFGUID set, DWORD id, @@ -155,17 +169,19 @@ static const IKsPropertySetVtbl property_set_vtbl = property_set_QuerySupported, };
+static struct testsource *impl_source_from_strmbase_pin(struct strmbase_pin *iface) +{ + return CONTAINING_RECORD(iface, struct testsource, pin.pin); +} + static HRESULT testsource_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) { - struct testfilter *filter = impl_from_strmbase_filter(iface->filter); - - if (iface == &filter->source.pin && filter->source_has_iface && IsEqualGUID(iid, &testiid)) - *out = &iface->IPin_iface; - else if (iface == &filter->source2.pin && filter->source2_has_iface && IsEqualGUID(iid, &testiid)) - *out = &iface->IPin_iface; - else if (iface == &filter->source.pin && filter->IKsPropertySet_iface.lpVtbl - && IsEqualGUID(iid, &IID_IKsPropertySet)) - *out = &filter->IKsPropertySet_iface; + struct testsource *pin = impl_source_from_strmbase_pin(iface); + + if (pin->has_iface && IsEqualGUID(iid, &testiid)) + *out = &pin->pin.pin.IPin_iface; + else if (pin->IKsPropertySet_iface.lpVtbl && IsEqualGUID(iid, &IID_IKsPropertySet)) + *out = &pin->IKsPropertySet_iface; else return E_NOINTERFACE;
@@ -204,18 +220,21 @@ static const struct strmbase_source_ops testsource_ops = .pfnDecideAllocator = testsource_DecideAllocator, };
+static struct testsink *impl_sink_from_strmbase_pin(struct strmbase_pin *iface) +{ + return CONTAINING_RECORD(iface, struct testsink, pin.pin); +} + static HRESULT testsink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) { - struct testfilter *filter = impl_from_strmbase_filter(iface->filter); + struct testsink *pin = impl_sink_from_strmbase_pin(iface);
ok(!IsEqualGUID(iid, &IID_IKsPropertySet), "Unexpected query for IKsPropertySet.\n");
if (IsEqualGUID(iid, &IID_IMemInputPin)) - *out = &filter->sink.IMemInputPin_iface; - else if (iface == &filter->sink.pin && filter->sink_has_iface && IsEqualGUID(iid, &testiid)) - *out = &iface->IPin_iface; - else if (iface == &filter->sink2.pin && filter->sink2_has_iface && IsEqualGUID(iid, &testiid)) - *out = &iface->IPin_iface; + *out = &pin->pin.IMemInputPin_iface; + else if (pin->has_iface && IsEqualGUID(iid, &testiid)) + *out = &pin->pin.pin.IPin_iface; else return E_NOINTERFACE;
@@ -237,8 +256,8 @@ static const struct strmbase_sink_ops testsink_ops =
static void reset_interfaces(struct testfilter *filter) { - filter->filter_has_iface = filter->sink_has_iface = filter->sink2_has_iface = TRUE; - filter->source_has_iface = filter->source2_has_iface = TRUE; + filter->filter_has_iface = filter->sink1.has_iface = filter->sink2.has_iface = TRUE; + filter->source1.has_iface = filter->source2.has_iface = TRUE; }
static void testfilter_init(struct testfilter *filter) @@ -246,10 +265,10 @@ static void testfilter_init(struct testfilter *filter) static const GUID clsid = {0xabacab}; memset(filter, 0, sizeof(*filter)); strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops); - strmbase_source_init(&filter->source, &filter->filter, L"source", &testsource_ops); - strmbase_source_init(&filter->source2, &filter->filter, L"source2", &testsource_ops); - strmbase_sink_init(&filter->sink, &filter->filter, L"sink", &testsink_ops, NULL); - strmbase_sink_init(&filter->sink2, &filter->filter, L"sink2", &testsink_ops, NULL); + strmbase_source_init(&filter->source1.pin, &filter->filter, L"source1", &testsource_ops); + strmbase_source_init(&filter->source2.pin, &filter->filter, L"source2", &testsource_ops); + strmbase_sink_init(&filter->sink1.pin, &filter->filter, L"sink1", &testsink_ops, NULL); + strmbase_sink_init(&filter->sink2.pin, &filter->filter, L"sink2", &testsink_ops, NULL); reset_interfaces(filter); }
@@ -285,60 +304,60 @@ static void test_find_interface(void) tests_from_filter2[] = { {&filter2.filter_has_iface, &filter2.filter.IBaseFilter_iface}, - {&filter2.source_has_iface, &filter2.source.pin.IPin_iface}, - {&filter3.sink_has_iface, &filter3.sink.pin.IPin_iface}, + {&filter2.source1.has_iface, &filter2.source1.pin.pin.IPin_iface}, + {&filter3.sink1.has_iface, &filter3.sink1.pin.pin.IPin_iface}, {&filter3.filter_has_iface, &filter3.filter.IBaseFilter_iface}, - {&filter3.source_has_iface, &filter3.source.pin.IPin_iface}, - {&filter3.source2_has_iface, &filter3.source2.pin.IPin_iface}, - {&filter2.source2_has_iface, &filter2.source2.pin.IPin_iface}, - {&filter2.sink_has_iface, &filter2.sink.pin.IPin_iface}, - {&filter1.source_has_iface, &filter1.source.pin.IPin_iface}, + {&filter3.source1.has_iface, &filter3.source1.pin.pin.IPin_iface}, + {&filter3.source2.has_iface, &filter3.source2.pin.pin.IPin_iface}, + {&filter2.source2.has_iface, &filter2.source2.pin.pin.IPin_iface}, + {&filter2.sink1.has_iface, &filter2.sink1.pin.pin.IPin_iface}, + {&filter1.source1.has_iface, &filter1.source1.pin.pin.IPin_iface}, {&filter1.filter_has_iface, &filter1.filter.IBaseFilter_iface}, - {&filter1.sink_has_iface, &filter1.sink.pin.IPin_iface}, - {&filter1.sink2_has_iface, &filter1.sink2.pin.IPin_iface}, - {&filter2.sink2_has_iface, &filter2.sink2.pin.IPin_iface}, + {&filter1.sink1.has_iface, &filter1.sink1.pin.pin.IPin_iface}, + {&filter1.sink2.has_iface, &filter1.sink2.pin.pin.IPin_iface}, + {&filter2.sink2.has_iface, &filter2.sink2.pin.pin.IPin_iface}, }, tests_from_filter1[] = { {&filter1.filter_has_iface, &filter1.filter.IBaseFilter_iface}, - {&filter1.source_has_iface, &filter1.source.pin.IPin_iface}, - {&filter2.sink_has_iface, &filter2.sink.pin.IPin_iface}, + {&filter1.source1.has_iface, &filter1.source1.pin.pin.IPin_iface}, + {&filter2.sink1.has_iface, &filter2.sink1.pin.pin.IPin_iface}, {&filter2.filter_has_iface, &filter2.filter.IBaseFilter_iface}, - {&filter2.source_has_iface, &filter2.source.pin.IPin_iface}, - {&filter3.sink_has_iface, &filter3.sink.pin.IPin_iface}, + {&filter2.source1.has_iface, &filter2.source1.pin.pin.IPin_iface}, + {&filter3.sink1.has_iface, &filter3.sink1.pin.pin.IPin_iface}, {&filter3.filter_has_iface, &filter3.filter.IBaseFilter_iface}, - {&filter3.source_has_iface, &filter3.source.pin.IPin_iface}, - {&filter3.source2_has_iface, &filter3.source2.pin.IPin_iface}, - {&filter2.source2_has_iface, &filter2.source2.pin.IPin_iface}, - {&filter1.source2_has_iface, &filter1.source2.pin.IPin_iface}, - {&filter1.sink_has_iface, &filter1.sink.pin.IPin_iface}, - {&filter1.sink2_has_iface, &filter1.sink2.pin.IPin_iface}, + {&filter3.source1.has_iface, &filter3.source1.pin.pin.IPin_iface}, + {&filter3.source2.has_iface, &filter3.source2.pin.pin.IPin_iface}, + {&filter2.source2.has_iface, &filter2.source2.pin.pin.IPin_iface}, + {&filter1.source2.has_iface, &filter1.source2.pin.pin.IPin_iface}, + {&filter1.sink1.has_iface, &filter1.sink1.pin.pin.IPin_iface}, + {&filter1.sink2.has_iface, &filter1.sink2.pin.pin.IPin_iface}, }, look_upstream_tests[] = { - {&filter2.sink_has_iface, &filter2.sink.pin.IPin_iface}, - {&filter1.source_has_iface, &filter1.source.pin.IPin_iface}, + {&filter2.sink1.has_iface, &filter2.sink1.pin.pin.IPin_iface}, + {&filter1.source1.has_iface, &filter1.source1.pin.pin.IPin_iface}, {&filter1.filter_has_iface, &filter1.filter.IBaseFilter_iface}, - {&filter1.sink_has_iface, &filter1.sink.pin.IPin_iface}, - {&filter1.sink2_has_iface, &filter1.sink2.pin.IPin_iface}, - {&filter2.sink2_has_iface, &filter2.sink2.pin.IPin_iface}, + {&filter1.sink1.has_iface, &filter1.sink1.pin.pin.IPin_iface}, + {&filter1.sink2.has_iface, &filter1.sink2.pin.pin.IPin_iface}, + {&filter2.sink2.has_iface, &filter2.sink2.pin.pin.IPin_iface}, }, look_downstream_tests[] = { - {&filter2.source_has_iface, &filter2.source.pin.IPin_iface}, - {&filter3.sink_has_iface, &filter3.sink.pin.IPin_iface}, + {&filter2.source1.has_iface, &filter2.source1.pin.pin.IPin_iface}, + {&filter3.sink1.has_iface, &filter3.sink1.pin.pin.IPin_iface}, {&filter3.filter_has_iface, &filter3.filter.IBaseFilter_iface}, - {&filter3.source_has_iface, &filter3.source.pin.IPin_iface}, - {&filter3.source2_has_iface, &filter3.source2.pin.IPin_iface}, - {&filter2.source2_has_iface, &filter2.source2.pin.IPin_iface}, + {&filter3.source1.has_iface, &filter3.source1.pin.pin.IPin_iface}, + {&filter3.source2.has_iface, &filter3.source2.pin.pin.IPin_iface}, + {&filter2.source2.has_iface, &filter2.source2.pin.pin.IPin_iface}, }, category_tests[] = { {&filter3.filter_has_iface, &filter3.filter.IBaseFilter_iface}, - {&filter3.source_has_iface, &filter3.source.pin.IPin_iface}, - {&filter3.source2_has_iface, &filter3.source2.pin.IPin_iface}, - {&filter2.sink_has_iface, &filter2.sink.pin.IPin_iface}, - {&filter1.source_has_iface, &filter1.source.pin.IPin_iface}, + {&filter3.source1.has_iface, &filter3.source1.pin.pin.IPin_iface}, + {&filter3.source2.has_iface, &filter3.source2.pin.pin.IPin_iface}, + {&filter2.sink1.has_iface, &filter2.sink1.pin.pin.IPin_iface}, + {&filter1.source1.has_iface, &filter1.source1.pin.pin.IPin_iface}, {&filter1.filter_has_iface, &filter1.filter.IBaseFilter_iface}, - {&filter1.sink_has_iface, &filter1.sink.pin.IPin_iface}, - {&filter1.sink2_has_iface, &filter1.sink2.pin.IPin_iface}, - {&filter2.sink2_has_iface, &filter2.sink2.pin.IPin_iface}, + {&filter1.sink1.has_iface, &filter1.sink1.pin.pin.IPin_iface}, + {&filter1.sink2.has_iface, &filter1.sink2.pin.pin.IPin_iface}, + {&filter2.sink2.has_iface, &filter2.sink2.pin.pin.IPin_iface}, };
CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (void **)&graph); @@ -352,9 +371,9 @@ static void test_find_interface(void) testfilter_init(&filter3); IGraphBuilder_AddFilter(graph, &filter3.filter.IBaseFilter_iface, L"filter3");
- hr = IGraphBuilder_ConnectDirect(graph, &filter1.source.pin.IPin_iface, &filter2.sink.pin.IPin_iface, &mt1); + hr = IGraphBuilder_ConnectDirect(graph, &filter1.source1.pin.pin.IPin_iface, &filter2.sink1.pin.pin.IPin_iface, &mt1); ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IGraphBuilder_ConnectDirect(graph, &filter2.source.pin.IPin_iface, &filter3.sink.pin.IPin_iface, &mt2); + hr = IGraphBuilder_ConnectDirect(graph, &filter2.source1.pin.pin.IPin_iface, &filter3.sink1.pin.pin.IPin_iface, &mt2); ok(hr == S_OK, "Got hr %#x.\n", hr);
/* Test search order without any restrictions applied. */ @@ -446,17 +465,17 @@ static void test_find_interface(void) &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk); ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
- filter2.IKsPropertySet_iface.lpVtbl = &property_set_vtbl; + filter2.source1.IKsPropertySet_iface.lpVtbl = &property_set_vtbl; hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &PIN_CATEGORY_CAPTURE, NULL, &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk); ok(hr == S_OK, "Got hr %#x.\n", hr); - ok(unk == (IUnknown *)&filter2.source.pin.IPin_iface, "Got wrong interface %p.\n", unk); + ok(unk == (IUnknown *)&filter2.source1.pin.pin.IPin_iface, "Got wrong interface %p.\n", unk); IUnknown_Release(unk); - filter2.source_has_iface = FALSE; + filter2.source1.has_iface = FALSE;
/* Native returns the filter3 sink next, but suffers from a bug wherein it * releases a reference to the wrong pin. */ - filter3.sink_has_iface = FALSE; + filter3.sink1.has_iface = FALSE;
for (i = 0; i < ARRAY_SIZE(category_tests); ++i) { @@ -496,11 +515,11 @@ static void test_find_interface(void) hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &PIN_CATEGORY_CAPTURE, &testtype, &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk); ok(hr == S_OK, "Got hr %#x.\n", hr); - ok(unk == (IUnknown *)&filter2.source.pin.IPin_iface, "Got wrong interface %p.\n", unk); + ok(unk == (IUnknown *)&filter2.source1.pin.pin.IPin_iface, "Got wrong interface %p.\n", unk); IUnknown_Release(unk); - filter2.source_has_iface = FALSE; + filter2.source1.has_iface = FALSE;
- filter3.sink_has_iface = FALSE; + filter3.sink1.has_iface = FALSE;
for (i = 0; i < ARRAY_SIZE(category_tests); ++i) {
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qcap/tests/capturegraph.c | 98 ++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+)
diff --git a/dlls/qcap/tests/capturegraph.c b/dlls/qcap/tests/capturegraph.c index d14753d9417..602fc801ba9 100644 --- a/dlls/qcap/tests/capturegraph.c +++ b/dlls/qcap/tests/capturegraph.c @@ -547,11 +547,109 @@ static void test_find_interface(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
+static void test_find_pin(void) +{ + static const AM_MEDIA_TYPE mt = + { + .majortype = {0x111}, + .subtype = {0x222}, + .formattype = {0x333}, + }; + + ICaptureGraphBuilder2 *capture_graph = create_capture_graph(); + struct testfilter filter1, filter2; + IGraphBuilder *graph; + HRESULT hr; + ULONG ref; + IPin *pin; + + CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (void **)&graph); + hr = ICaptureGraphBuilder2_SetFiltergraph(capture_graph, graph); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + testfilter_init(&filter1); + testfilter_init(&filter2); + IGraphBuilder_AddFilter(graph, &filter1.filter.IBaseFilter_iface, L"filter1"); + IGraphBuilder_AddFilter(graph, &filter2.filter.IBaseFilter_iface, L"filter2"); + + hr = IGraphBuilder_ConnectDirect(graph, &filter1.source1.pin.pin.IPin_iface, + &filter2.sink1.pin.pin.IPin_iface, &mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface, + PINDIR_INPUT, NULL, NULL, FALSE, 0, &pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(pin == &filter1.sink1.pin.pin.IPin_iface, "Got wrong pin.\n"); + IPin_Release(pin); + + hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface, + PINDIR_INPUT, NULL, NULL, FALSE, 1, &pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(pin == &filter1.sink2.pin.pin.IPin_iface, "Got wrong pin.\n"); + IPin_Release(pin); + + hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface, + PINDIR_INPUT, NULL, NULL, FALSE, 2, &pin); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + + hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface, + PINDIR_OUTPUT, NULL, NULL, FALSE, 0, &pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(pin == &filter1.source1.pin.pin.IPin_iface, "Got wrong pin.\n"); + IPin_Release(pin); + + hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface, + PINDIR_OUTPUT, NULL, NULL, FALSE, 1, &pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(pin == &filter1.source2.pin.pin.IPin_iface, "Got wrong pin.\n"); + IPin_Release(pin); + + hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface, + PINDIR_OUTPUT, NULL, NULL, FALSE, 2, &pin); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + + /* Test the unconnected flag. */ + + hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface, + PINDIR_OUTPUT, NULL, NULL, TRUE, 0, &pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(pin == &filter1.source2.pin.pin.IPin_iface, "Got wrong pin.\n"); + IPin_Release(pin); + + hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface, + PINDIR_OUTPUT, NULL, NULL, TRUE, 1, &pin); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + + /* Test categories. */ + + filter1.source1.IKsPropertySet_iface.lpVtbl = &property_set_vtbl; + + hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface, + PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, NULL, FALSE, 0, &pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(pin == &filter1.source1.pin.pin.IPin_iface, "Got wrong pin.\n"); + IPin_Release(pin); + + hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface, + PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, NULL, FALSE, 1, &pin); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + + ref = ICaptureGraphBuilder2_Release(capture_graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IGraphBuilder_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(&filter1.filter.IBaseFilter_iface); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(&filter2.filter.IBaseFilter_iface); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + START_TEST(capturegraph) { CoInitializeEx(NULL, COINIT_MULTITHREADED);
test_find_interface(); + test_find_pin();
CoUninitialize(); }
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qcap/tests/capturegraph.c | 449 ++++++++++++++++++++++++++++++- dlls/qcap/tests/smartteefilter.c | 231 ---------------- 2 files changed, 443 insertions(+), 237 deletions(-)
diff --git a/dlls/qcap/tests/capturegraph.c b/dlls/qcap/tests/capturegraph.c index 602fc801ba9..223bf972de0 100644 --- a/dlls/qcap/tests/capturegraph.c +++ b/dlls/qcap/tests/capturegraph.c @@ -39,6 +39,7 @@ struct testsource { struct strmbase_source pin; IKsPropertySet IKsPropertySet_iface; + GUID category; BOOL has_iface; };
@@ -54,6 +55,8 @@ struct testfilter struct testsource source1, source2; struct testsink sink1, sink2; BOOL filter_has_iface; + GUID source_type; + const GUID *sink_type; };
static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -141,7 +144,9 @@ static HRESULT WINAPI property_set_Set(IKsPropertySet *iface, REFGUID set, DWORD static HRESULT WINAPI property_set_Get(IKsPropertySet *iface, REFGUID set, DWORD id, void *instance_data, DWORD instance_size, void *property_data, DWORD property_size, DWORD *ret_size) { - if (winetest_debug > 1) trace("Get()\n"); + struct testsource *pin = impl_from_IKsPropertySet(iface); + + if (winetest_debug > 1) trace("%s->Get()\n", debugstr_w(pin->pin.pin.name));
ok(IsEqualGUID(set, &ROPSETID_Pin), "Got set %s.\n", debugstr_guid(set)); ok(id == AMPROPERTY_PIN_CATEGORY, "Got id %#x.\n", id); @@ -149,7 +154,7 @@ static HRESULT WINAPI property_set_Get(IKsPropertySet *iface, REFGUID set, DWORD ok(!instance_size, "Got instance size %u.\n", instance_size); ok(property_size == sizeof(GUID), "Got property size %u.\n", property_size); ok(!!ret_size, "Expected non-NULL return size.\n"); - memcpy(property_data, &PIN_CATEGORY_CAPTURE, sizeof(GUID)); + memcpy(property_data, &pin->category, sizeof(GUID)); return S_OK; }
@@ -196,18 +201,21 @@ static HRESULT testsource_query_accept(struct strmbase_pin *iface, const AM_MEDI
static HRESULT testsource_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *mt) { + struct testfilter *filter = impl_from_strmbase_filter(iface->filter); + if (!index) { memset(mt, 0, sizeof(*mt)); - mt->majortype = testtype; + mt->majortype = filter->source_type; return S_OK; } return VFW_S_NO_MORE_ITEMS; }
-static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface, - IMemInputPin *input, IMemAllocator **allocator) +static HRESULT WINAPI testsource_DecideBufferSize(struct strmbase_source *iface, + IMemAllocator *allocator, ALLOCATOR_PROPERTIES *props) { + props->cBuffers = props->cbAlign = props->cbBuffer = 1; return S_OK; }
@@ -217,7 +225,8 @@ static const struct strmbase_source_ops testsource_ops = .base.pin_query_accept = testsource_query_accept, .base.pin_get_media_type = testsource_get_media_type, .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, - .pfnDecideAllocator = testsource_DecideAllocator, + .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator, + .pfnDecideBufferSize = testsource_DecideBufferSize, };
static struct testsink *impl_sink_from_strmbase_pin(struct strmbase_pin *iface) @@ -244,6 +253,10 @@ static HRESULT testsink_query_interface(struct strmbase_pin *iface, REFIID iid,
static HRESULT testsink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) { + struct testfilter *filter = impl_from_strmbase_filter(iface->filter); + + if (filter->sink_type && !IsEqualGUID(&mt->majortype, filter->sink_type)) + return S_FALSE; return S_OK; }
@@ -466,6 +479,7 @@ static void test_find_interface(void) ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
filter2.source1.IKsPropertySet_iface.lpVtbl = &property_set_vtbl; + filter2.source1.category = PIN_CATEGORY_CAPTURE; hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &PIN_CATEGORY_CAPTURE, NULL, &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk); ok(hr == S_OK, "Got hr %#x.\n", hr); @@ -493,6 +507,8 @@ static void test_find_interface(void)
/* Test with a media type. */
+ filter1.source_type = filter2.source_type = testtype; + reset_interfaces(&filter1); reset_interfaces(&filter2); reset_interfaces(&filter3); @@ -623,6 +639,7 @@ static void test_find_pin(void) /* Test categories. */
filter1.source1.IKsPropertySet_iface.lpVtbl = &property_set_vtbl; + filter1.source1.category = PIN_CATEGORY_CAPTURE;
hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface, PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, NULL, FALSE, 0, &pin); @@ -644,12 +661,432 @@ static void test_find_pin(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
+static void disconnect_pins(IGraphBuilder *graph, struct testsource *pin) +{ + HRESULT hr; + hr = IGraphBuilder_Disconnect(graph, pin->pin.pin.peer); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IGraphBuilder_Disconnect(graph, &pin->pin.pin.IPin_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); +} + +static void check_smart_tee_pin_(int line, IPin *pin, const WCHAR *name) +{ + PIN_INFO info; + GUID clsid; + + IPin_QueryPinInfo(pin, &info); + ok_(__FILE__, line)(!wcscmp(info.achName, name), "Got name %s.\n", debugstr_w(info.achName)); + IBaseFilter_GetClassID(info.pFilter, &clsid); + ok_(__FILE__, line)(IsEqualGUID(&clsid, &CLSID_SmartTee), "Got CLSID %s.\n", debugstr_guid(&clsid)); + IBaseFilter_Release(info.pFilter); +} +#define check_smart_tee_pin(pin, name) check_smart_tee_pin_(__LINE__, pin, name) + +static void test_render_stream(void) +{ + static const GUID source_type = {0x1111}; + static const GUID sink1_type = {0x8888}; + static const GUID bad_type = {0x4444}; + + ICaptureGraphBuilder2 *capture_graph = create_capture_graph(); + struct testfilter source, transform, sink, identity; + IGraphBuilder *graph; + HRESULT hr; + ULONG ref; + + CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (void **)&graph); + hr = ICaptureGraphBuilder2_SetFiltergraph(capture_graph, graph); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + testfilter_init(&source); + testfilter_init(&transform); + testfilter_init(&sink); + testfilter_init(&identity); + IGraphBuilder_AddFilter(graph, &source.filter.IBaseFilter_iface, L"source"); + IGraphBuilder_AddFilter(graph, &transform.filter.IBaseFilter_iface, L"transform"); + IGraphBuilder_AddFilter(graph, &sink.filter.IBaseFilter_iface, L"sink"); + + source.source_type = source_type; + transform.sink_type = &source_type; + transform.source_type = sink1_type; + sink.sink_type = &sink1_type; + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n"); + ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n"); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + todo_wine ok(source.source2.pin.pin.peer == &transform.sink2.pin.pin.IPin_iface, "Got wrong connection.\n"); + todo_wine ok(transform.source2.pin.pin.peer == &sink.sink2.pin.pin.IPin_iface, "Got wrong connection.\n"); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + todo_wine ok(hr == E_FAIL, "Got hr %#x.\n", hr); + + todo_wine disconnect_pins(graph, &source.source2); + todo_wine disconnect_pins(graph, &transform.source2); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL, + (IUnknown *)&transform.source2.pin.pin.IPin_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source2.pin.pin.peer == &sink.sink2.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n"); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + + disconnect_pins(graph, &transform.source2); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &transform.filter.IBaseFilter_iface); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + todo_wine ok(source.source2.pin.pin.peer == &transform.sink2.pin.pin.IPin_iface, "Got wrong connection.\n"); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + todo_wine ok(source.source2.pin.pin.peer == &transform.sink2.pin.pin.IPin_iface, "Got wrong connection.\n"); + todo_wine ok(transform.source2.pin.pin.peer == &sink.sink2.pin.pin.IPin_iface, "Got wrong connection.\n"); + todo_wine disconnect_pins(graph, &source.source2); + todo_wine disconnect_pins(graph, &transform.source2); + + /* Test from a source pin. */ + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL, + (IUnknown *)&source.source1.pin.pin.IPin_iface, NULL, &sink.filter.IBaseFilter_iface); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + todo_wine ok(transform.source2.pin.pin.peer == &sink.sink2.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n"); + todo_wine disconnect_pins(graph, &transform.source2); + + /* Only the first eligible source is tried. */ + source.source_type = bad_type; + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == VFW_E_CANNOT_CONNECT, "Got hr %#x.\n", hr); + source.source_type = source_type; + + disconnect_pins(graph, &transform.source1); + disconnect_pins(graph, &source.source1); + + /* Test intermediate filters. */ + + IGraphBuilder_AddFilter(graph, &identity.filter.IBaseFilter_iface, L"identity"); + identity.source_type = source_type; + identity.sink_type = &source_type; + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, + &identity.filter.IBaseFilter_iface, &sink.filter.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &identity.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(identity.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + disconnect_pins(graph, &source.source1); + disconnect_pins(graph, &identity.source1); + disconnect_pins(graph, &transform.source1); + + identity.sink_type = &bad_type; + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, + &identity.filter.IBaseFilter_iface, &sink.filter.IBaseFilter_iface); + todo_wine ok(hr == E_FAIL, "Got hr %#x.\n", hr); + ok(!source.source1.pin.pin.peer, "Pin should not be connected.\n"); + ok(!identity.source1.pin.pin.peer, "Pin should not be connected.\n"); + ok(!transform.source1.pin.pin.peer, "Pin should not be connected.\n"); + + identity.source_type = sink1_type; + identity.sink_type = &sink1_type; + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, + &identity.filter.IBaseFilter_iface, &sink.filter.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &identity.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(identity.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + disconnect_pins(graph, &source.source1); + disconnect_pins(graph, &transform.source1); + disconnect_pins(graph, &identity.source1); + + identity.source_type = bad_type; + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, + &identity.filter.IBaseFilter_iface, &sink.filter.IBaseFilter_iface); + ok(hr == VFW_E_CANNOT_CONNECT, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &identity.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(!identity.source1.pin.pin.peer, "Pin should not be connected.\n"); + disconnect_pins(graph, &source.source1); + disconnect_pins(graph, &transform.source1); + + /* Test media types. */ + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, &bad_type, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!source.source1.pin.pin.peer, "Pin should not be connected.\n"); + ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n"); + ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n"); + ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n"); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, &sink1_type, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!source.source1.pin.pin.peer, "Pin should not be connected.\n"); + ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n"); + ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n"); + ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n"); + + identity.source_type = sink1_type; + identity.sink_type = &sink1_type; + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, &sink1_type, + (IUnknown *)&source.filter.IBaseFilter_iface, + &identity.filter.IBaseFilter_iface, &sink.filter.IBaseFilter_iface); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!source.source1.pin.pin.peer, "Pin should not be connected.\n"); + ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n"); + ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n"); + ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n"); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, &source_type, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n"); + ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n"); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, &sink1_type, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + todo_wine ok(transform.source2.pin.pin.peer == &sink.sink2.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n"); + + disconnect_pins(graph, &source.source1); + disconnect_pins(graph, &transform.source1); + todo_wine disconnect_pins(graph, &transform.source2); + + /* Test categories. */ + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(!source.source1.pin.pin.peer, "Pin should not be connected.\n"); + ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n"); + ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n"); + ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n"); + + source.source1.IKsPropertySet_iface.lpVtbl = &property_set_vtbl; + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(!source.source1.pin.pin.peer, "Pin should not be connected.\n"); + ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n"); + ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n"); + ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n"); + + source.source1.category = PIN_CATEGORY_CC; + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n"); + ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n"); + + disconnect_pins(graph, &transform.source1); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(!transform.source1.pin.pin.peer, "Pin should not be connected.\n"); + + transform.source1.IKsPropertySet_iface.lpVtbl = &property_set_vtbl; + transform.source1.category = PIN_CATEGORY_CC; + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + todo_wine ok(!transform.source1.pin.pin.peer, "Pin should not be connected.\n"); + todo_wine ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n"); + + if (0) + { + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL, + (IUnknown *)&source.source1.pin.pin.IPin_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + } + + disconnect_pins(graph, &source.source1); + + /* Test the CAPTURE and PREVIEW categories. */ + + source.source1.IKsPropertySet_iface.lpVtbl = transform.source1.IKsPropertySet_iface.lpVtbl = NULL; + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + source.source1.IKsPropertySet_iface.lpVtbl = &property_set_vtbl; + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + source.source1.category = PIN_CATEGORY_PREVIEW; + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(!source.source1.pin.pin.peer, "Pin should not be connected.\n"); + todo_wine ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n"); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + disconnect_pins(graph, &transform.source1); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + todo_wine ok(hr == E_FAIL, "Got hr %#x.\n", hr); + todo_wine disconnect_pins(graph, &source.source1); + + source.source1.category = PIN_CATEGORY_CAPTURE; + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + check_smart_tee_pin(source.source1.pin.pin.peer, L"Input"); + check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Capture"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + + if (0) + { + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + } + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == VFW_S_NOPREVIEWPIN, "Got hr %#x.\n", hr); + check_smart_tee_pin(source.source1.pin.pin.peer, L"Input"); + check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Capture"); + check_smart_tee_pin(transform.sink2.pin.pin.peer, L"Preview"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source2.pin.pin.peer == &sink.sink2.pin.pin.IPin_iface, "Got wrong connection.\n"); + + disconnect_pins(graph, &source.source1); + IGraphBuilder_RemoveFilter(graph, &transform.filter.IBaseFilter_iface); + IGraphBuilder_AddFilter(graph, &transform.filter.IBaseFilter_iface, L"transform"); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == VFW_S_NOPREVIEWPIN, "Got hr %#x.\n", hr); + check_smart_tee_pin(source.source1.pin.pin.peer, L"Input"); + check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Preview"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + + if (0) + { + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + } + + disconnect_pins(graph, &source.source1); + IGraphBuilder_RemoveFilter(graph, &transform.filter.IBaseFilter_iface); + IGraphBuilder_AddFilter(graph, &transform.filter.IBaseFilter_iface, L"transform"); + + /* Test from the pin. */ + + source.source1.category = PIN_CATEGORY_CAPTURE; + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL, + (IUnknown *)&source.source1.pin.pin.IPin_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine check_smart_tee_pin(source.source1.pin.pin.peer, L"Input"); + todo_wine check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Capture"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + disconnect_pins(graph, &source.source1); + IGraphBuilder_RemoveFilter(graph, &transform.filter.IBaseFilter_iface); + IGraphBuilder_AddFilter(graph, &transform.filter.IBaseFilter_iface, L"transform"); + + /* Test when both CAPTURE and PREVIEW are available. */ + + source.source2.IKsPropertySet_iface.lpVtbl = &property_set_vtbl; + source.source2.category = PIN_CATEGORY_PREVIEW; + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + disconnect_pins(graph, &source.source1); + disconnect_pins(graph, &transform.source1); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(source.source2.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + disconnect_pins(graph, &source.source2); + disconnect_pins(graph, &transform.source1); + + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL, + (IUnknown *)&source.source1.pin.pin.IPin_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine check_smart_tee_pin(source.source1.pin.pin.peer, L"Input"); + todo_wine check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Capture"); + ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); + disconnect_pins(graph, &source.source1); + disconnect_pins(graph, &transform.source1); + + ref = ICaptureGraphBuilder2_Release(capture_graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IGraphBuilder_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(&transform.filter.IBaseFilter_iface); + todo_wine ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(&sink.filter.IBaseFilter_iface); + todo_wine ok(!ref, "Got outstanding refcount %d.\n", ref); +} + START_TEST(capturegraph) { CoInitializeEx(NULL, COINIT_MULTITHREADED);
test_find_interface(); test_find_pin(); + test_render_stream();
CoUninitialize(); } diff --git a/dlls/qcap/tests/smartteefilter.c b/dlls/qcap/tests/smartteefilter.c index 4602d137386..134b8ed964b 100644 --- a/dlls/qcap/tests/smartteefilter.c +++ b/dlls/qcap/tests/smartteefilter.c @@ -2012,30 +2012,6 @@ static SourceFilter* create_video_SourceFilter(void) return This; }
-static SourceFilter* create_audio_SourceFilter(void) -{ - SourceFilter *This = create_SourceFilter(); - if (!This) - return NULL; - This->mediaType.majortype = MEDIATYPE_Audio; - This->mediaType.subtype = MEDIASUBTYPE_PCM; - This->mediaType.bFixedSizeSamples = FALSE; - This->mediaType.bTemporalCompression = FALSE; - This->mediaType.lSampleSize = 0; - This->mediaType.formattype = FORMAT_WaveFormatEx; - This->mediaType.pUnk = NULL; - This->mediaType.cbFormat = sizeof(WAVEFORMATEX); - This->mediaType.pbFormat = (BYTE*) &This->audioInfo; - This->audioInfo.wFormatTag = WAVE_FORMAT_PCM; - This->audioInfo.nChannels = 1; - This->audioInfo.nSamplesPerSec = 8000; - This->audioInfo.nAvgBytesPerSec = 16000; - This->audioInfo.nBlockAlign = 2; - This->audioInfo.wBitsPerSample = 16; - This->audioInfo.cbSize = 0; - return This; -} - static void test_smart_tee_filter_in_graph(IBaseFilter *smartTeeFilter, IPin *inputPin, IPin *capturePin, IPin *previewPin) { @@ -2298,207 +2274,6 @@ static void test_unconnected_filter_state(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
-static HRESULT get_connected_filter_classid(IPin *pin, GUID *guid) -{ - IPin *connectedPin = NULL; - PIN_INFO connectedPinInfo; - HRESULT hr = IPin_ConnectedTo(pin, &connectedPin); - ok(SUCCEEDED(hr), "IPin_ConnectedTo() failed, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - hr = IPin_QueryPinInfo(connectedPin, &connectedPinInfo); - ok(SUCCEEDED(hr), "IPin_QueryPinInfo() failed, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - if (connectedPinInfo.pFilter) { - hr = IBaseFilter_GetClassID(connectedPinInfo.pFilter, guid); - ok(SUCCEEDED(hr), "IBaseFilter_GetClassID() failed, hr=0x%08x\n", hr); - IBaseFilter_Release(connectedPinInfo.pFilter); - } -end: - if (connectedPin) - IPin_Release(connectedPin); - return hr; -} - -static void test_audio_preview(ICaptureGraphBuilder2 *captureGraphBuilder, IGraphBuilder *graphBuilder, - SourceFilter *audioSource, IBaseFilter *nullRenderer) -{ - GUID clsid; - HRESULT hr = ICaptureGraphBuilder2_RenderStream(captureGraphBuilder, &PIN_CATEGORY_PREVIEW, &MEDIATYPE_Audio, - (IUnknown*)&audioSource->IBaseFilter_iface, NULL, nullRenderer); - ok(hr == VFW_S_NOPREVIEWPIN, "ICaptureGraphBuilder2_RenderStream() returned hr=0x%08x\n", hr); - hr = get_connected_filter_classid(&audioSource->IPin_iface, &clsid); - if (FAILED(hr)) - return; - ok(IsEqualIID(&clsid, &CLSID_SmartTee), "unexpected connected filter %s\n", - wine_dbgstr_guid(&clsid)); -} - -static void test_audio_capture(ICaptureGraphBuilder2 *captureGraphBuilder, IGraphBuilder *graphBuilder, - SourceFilter *audioSource, IBaseFilter *nullRenderer) -{ - GUID clsid; - HRESULT hr = ICaptureGraphBuilder2_RenderStream(captureGraphBuilder, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, - (IUnknown*)&audioSource->IBaseFilter_iface, NULL, nullRenderer); - ok(hr == S_OK, "ICaptureGraphBuilder2_RenderStream() returned hr=0x%08x\n", hr); - hr = get_connected_filter_classid(&audioSource->IPin_iface, &clsid); - if (FAILED(hr)) - return; - ok(IsEqualIID(&clsid, &CLSID_SmartTee), "unexpected connected filter %s\n", - wine_dbgstr_guid(&clsid)); -} - -static void test_video_preview(ICaptureGraphBuilder2 *captureGraphBuilder, IGraphBuilder *graphBuilder, - SourceFilter *videoSource, IBaseFilter *nullRenderer) -{ - GUID clsid; - HRESULT hr = ICaptureGraphBuilder2_RenderStream(captureGraphBuilder, &PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, - (IUnknown*)&videoSource->IBaseFilter_iface, NULL, nullRenderer); - ok(hr == VFW_S_NOPREVIEWPIN, "ICaptureGraphBuilder2_RenderStream() failed, hr=0x%08x\n", hr); - hr = get_connected_filter_classid(&videoSource->IPin_iface, &clsid); - if (FAILED(hr)) - return; - ok(IsEqualIID(&clsid, &CLSID_SmartTee), "unexpected connected filter %s\n", - wine_dbgstr_guid(&clsid)); -} - -static void test_video_capture(ICaptureGraphBuilder2 *captureGraphBuilder, IGraphBuilder *graphBuilder, - SourceFilter *videoSource, IBaseFilter *nullRenderer) -{ - GUID clsid; - HRESULT hr = ICaptureGraphBuilder2_RenderStream(captureGraphBuilder, &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, - (IUnknown*)&videoSource->IBaseFilter_iface, NULL, nullRenderer); - ok(hr == S_OK, "ICaptureGraphBuilder2_RenderStream() failed, hr=0x%08x\n", hr); - hr = get_connected_filter_classid(&videoSource->IPin_iface, &clsid); - if (FAILED(hr)) - return; - ok(IsEqualIID(&clsid, &CLSID_SmartTee), "unexpected connected filter %s\n", - wine_dbgstr_guid(&clsid)); -} - -static void test_audio_smart_tee_filter_auto_insertion( - void (*test_function)(ICaptureGraphBuilder2 *cgb, IGraphBuilder *gb, - SourceFilter *audioSource, IBaseFilter *nullRenderer)) -{ - HRESULT hr; - ICaptureGraphBuilder2 *captureGraphBuilder = NULL; - IGraphBuilder *graphBuilder = NULL; - IBaseFilter *nullRenderer = NULL; - SourceFilter *audioSource = NULL; - - hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, - &IID_ICaptureGraphBuilder2, (void**)&captureGraphBuilder); - ok(SUCCEEDED(hr), "couldn't create capture graph builder, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, - (LPVOID*)&graphBuilder); - ok(SUCCEEDED(hr), "couldn't create graph builder, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - hr = ICaptureGraphBuilder2_SetFiltergraph(captureGraphBuilder, graphBuilder); - ok(SUCCEEDED(hr), "ICaptureGraphBuilder2_SetFilterGraph() failed, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - hr = CoCreateInstance(&CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, - &IID_IBaseFilter, (LPVOID*)&nullRenderer); - ok(SUCCEEDED(hr) || - /* Windows 2008: http://stackoverflow.com/questions/29410348/initialize-nullrender-failed-wit... */ - broken(hr == REGDB_E_CLASSNOTREG), "couldn't create NullRenderer, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - hr = IGraphBuilder_AddFilter(graphBuilder, nullRenderer, NULL); - ok(SUCCEEDED(hr), "IGraphBuilder_AddFilter() failed, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - audioSource = create_audio_SourceFilter(); - ok(audioSource != NULL, "couldn't create audio source\n"); - if (audioSource == NULL) - goto end; - hr = IGraphBuilder_AddFilter(graphBuilder, &audioSource->IBaseFilter_iface, NULL); - ok(SUCCEEDED(hr), "IGraphBuilder_AddFilter() failed, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - test_function(captureGraphBuilder, graphBuilder, audioSource, nullRenderer); - -end: - if (nullRenderer) - IBaseFilter_Release(nullRenderer); - if (audioSource) - IBaseFilter_Release(&audioSource->IBaseFilter_iface); - if (captureGraphBuilder) - ICaptureGraphBuilder2_Release(captureGraphBuilder); - if (graphBuilder) - IGraphBuilder_Release(graphBuilder); -} - -static void test_video_smart_tee_filter_auto_insertion( - void (*test_function)(ICaptureGraphBuilder2 *cgb, IGraphBuilder *gb, - SourceFilter *videoSource, IBaseFilter *nullRenderer)) -{ - HRESULT hr; - ICaptureGraphBuilder2 *captureGraphBuilder = NULL; - IGraphBuilder *graphBuilder = NULL; - IBaseFilter *nullRenderer = NULL; - SourceFilter *videoSource = NULL; - - hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, - &IID_ICaptureGraphBuilder2, (void**)&captureGraphBuilder); - ok(SUCCEEDED(hr), "couldn't create capture graph builder, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, - (LPVOID*)&graphBuilder); - ok(SUCCEEDED(hr), "couldn't create graph builder, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - hr = ICaptureGraphBuilder2_SetFiltergraph(captureGraphBuilder, graphBuilder); - ok(SUCCEEDED(hr), "ICaptureGraphBuilder2_SetFilterGraph() failed, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - hr = CoCreateInstance(&CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, - &IID_IBaseFilter, (LPVOID*)&nullRenderer); - ok(SUCCEEDED(hr) || - /* Windows 2008: http://stackoverflow.com/questions/29410348/initialize-nullrender-failed-wit... */ - broken(hr == REGDB_E_CLASSNOTREG), "couldn't create NullRenderer, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - hr = IGraphBuilder_AddFilter(graphBuilder, nullRenderer, NULL); - ok(SUCCEEDED(hr), "IGraphBuilder_AddFilter() failed, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - videoSource = create_video_SourceFilter(); - ok(videoSource != NULL, "couldn't create audio source\n"); - if (videoSource == NULL) - goto end; - hr = IGraphBuilder_AddFilter(graphBuilder, &videoSource->IBaseFilter_iface, NULL); - ok(SUCCEEDED(hr), "IGraphBuilder_AddFilter() failed, hr=0x%08x\n", hr); - if (FAILED(hr)) - goto end; - - test_function(captureGraphBuilder, graphBuilder, videoSource, nullRenderer); - -end: - if (nullRenderer) - IBaseFilter_Release(nullRenderer); - if (videoSource) - IBaseFilter_Release(&videoSource->IBaseFilter_iface); - if (captureGraphBuilder) - ICaptureGraphBuilder2_Release(captureGraphBuilder); - if (graphBuilder) - IGraphBuilder_Release(graphBuilder); -} - struct testfilter { struct strmbase_filter filter; @@ -3005,12 +2780,6 @@ START_TEST(smartteefilter)
test_smart_tee_filter();
- test_audio_smart_tee_filter_auto_insertion(test_audio_preview); - test_audio_smart_tee_filter_auto_insertion(test_audio_capture); - - test_video_smart_tee_filter_auto_insertion(test_video_preview); - test_video_smart_tee_filter_auto_insertion(test_video_capture); - CloseHandle(event); CoUninitialize(); }
Previously, if we tried to search from a matching but connected source, we would loop forever.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qcap/capturegraph.c | 140 +++++++++++++++++++-------------- dlls/qcap/tests/capturegraph.c | 39 ++++----- 2 files changed, 95 insertions(+), 84 deletions(-)
diff --git a/dlls/qcap/capturegraph.c b/dlls/qcap/capturegraph.c index 33b0ecfaa11..b49e45b9d6b 100644 --- a/dlls/qcap/capturegraph.c +++ b/dlls/qcap/capturegraph.c @@ -499,83 +499,88 @@ end: return hr; }
-static HRESULT find_unconnected_pin(CaptureGraphImpl *This, - const GUID *pCategory, const GUID *pType, IUnknown *pSource, IPin **out_pin) +static HRESULT find_unconnected_source_from_filter(CaptureGraphImpl *capture_graph, + const GUID *category, const GUID *majortype, IBaseFilter *filter, IPin **ret); + +static HRESULT find_unconnected_source_from_pin(CaptureGraphImpl *capture_graph, + const GUID *category, const GUID *majortype, IPin *pin, IPin **ret) { - int index = 0; - IPin *source_out; + PIN_INFO info; HRESULT hr; - BOOL usedSmartTeePreviewPin = FALSE; - - /* depth-first search the graph for the first unconnected pin that matches - * the given category and type */ - for(;;){ - IPin *nextpin; - - if (pCategory && (IsEqualIID(pCategory, &PIN_CATEGORY_CAPTURE) || IsEqualIID(pCategory, &PIN_CATEGORY_PREVIEW))){ - IBaseFilter *sourceFilter = NULL; - hr = IUnknown_QueryInterface(pSource, &IID_IBaseFilter, (void**)&sourceFilter); - if (SUCCEEDED(hr)) { - hr = match_smart_tee_pin(This, pCategory, pType, pSource, &source_out); - if (hr == VFW_S_NOPREVIEWPIN) - usedSmartTeePreviewPin = TRUE; - IBaseFilter_Release(sourceFilter); - } else { - hr = ICaptureGraphBuilder2_FindPin(&This->ICaptureGraphBuilder2_iface, pSource, PINDIR_OUTPUT, pCategory, pType, FALSE, index, &source_out); - } - if (FAILED(hr)) - return E_INVALIDARG; - } else { - hr = ICaptureGraphBuilder2_FindPin(&This->ICaptureGraphBuilder2_iface, pSource, PINDIR_OUTPUT, pCategory, pType, FALSE, index, &source_out); - if (FAILED(hr)) - return E_INVALIDARG; - } + IPin *peer;
- hr = IPin_ConnectedTo(source_out, &nextpin); - if(SUCCEEDED(hr)){ - PIN_INFO info; + if (category && (IsEqualGUID(category, &PIN_CATEGORY_CAPTURE) + || IsEqualGUID(category, &PIN_CATEGORY_PREVIEW))) + hr = match_smart_tee_pin(capture_graph, category, majortype, (IUnknown *)pin, &pin); + else + hr = ICaptureGraphBuilder2_FindPin(&capture_graph->ICaptureGraphBuilder2_iface, + (IUnknown *)pin, PINDIR_OUTPUT, category, majortype, FALSE, -1, &pin); + if (FAILED(hr)) + return hr;
- IPin_Release(source_out); + if (FAILED(IPin_ConnectedTo(pin, &peer))) + { + *ret = pin; + return hr; + }
- hr = IPin_QueryPinInfo(nextpin, &info); - if(FAILED(hr) || !info.pFilter){ - WARN("QueryPinInfo failed: %08x\n", hr); - return hr; - } + IPin_QueryPinInfo(peer, &info); + hr = find_unconnected_source_from_filter(capture_graph, category, majortype, info.pFilter, ret); + IBaseFilter_Release(info.pFilter); + IPin_Release(peer); + IPin_Release(pin); + return hr; +}
- hr = find_unconnected_pin(This, pCategory, pType, (IUnknown*)info.pFilter, out_pin); +static HRESULT find_unconnected_source_from_filter(CaptureGraphImpl *capture_graph, + const GUID *category, const GUID *majortype, IBaseFilter *filter, IPin **ret) +{ + IPin *pin, *peer; + HRESULT hr; + int index;
- IBaseFilter_Release(info.pFilter); + if (category && (IsEqualGUID(category, &PIN_CATEGORY_CAPTURE) + || IsEqualGUID(category, &PIN_CATEGORY_PREVIEW))) + { + if (FAILED(hr = match_smart_tee_pin(capture_graph, category, majortype, (IUnknown *)filter, &pin))) + return hr;
- if(SUCCEEDED(hr)) - return hr; - }else{ - *out_pin = source_out; - if(usedSmartTeePreviewPin) - return VFW_S_NOPREVIEWPIN; - return S_OK; + if (FAILED(IPin_ConnectedTo(pin, &peer))) + { + *ret = pin; + return hr; }
- index++; + IPin_Release(peer); + IPin_Release(pin); + return E_INVALIDARG; } + + for (index = 0; SUCCEEDED(ICaptureGraphBuilder2_FindPin(&capture_graph->ICaptureGraphBuilder2_iface, + (IUnknown *)filter, PINDIR_OUTPUT, category, majortype, FALSE, index, &pin)); ++index) + { + hr = find_unconnected_source_from_pin(capture_graph, category, majortype, pin, ret); + IPin_Release(pin); + if (SUCCEEDED(hr)) + return hr; + } + + return E_INVALIDARG; }
-static HRESULT WINAPI -fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 * iface, - const GUID *pCategory, - const GUID *pType, - IUnknown *pSource, - IBaseFilter *pfCompressor, - IBaseFilter *pfRenderer) +static HRESULT WINAPI fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 *iface, + const GUID *category, const GUID *majortype, IUnknown *source, + IBaseFilter *pfCompressor, IBaseFilter *pfRenderer) { CaptureGraphImpl *This = impl_from_ICaptureGraphBuilder2(iface); IPin *source_out = NULL, *renderer_in; BOOL rendererNeedsRelease = FALSE; HRESULT hr, return_hr = S_OK; + IBaseFilter *filter; + IPin *pin;
- FIXME("(%p/%p)->(%s, %s, %p, %p, %p) semi-stub!\n", This, iface, - debugstr_guid(pCategory), debugstr_guid(pType), - pSource, pfCompressor, pfRenderer); + TRACE("graph %p, category %s, majortype %s, source %p, intermediate %p, sink %p.\n", + This, debugstr_guid(category), debugstr_guid(majortype), source, pfCompressor, pfRenderer);
if (!This->mygraph) { @@ -583,12 +588,27 @@ fnCaptureGraphBuilder2_RenderStream(ICaptureGraphBuilder2 * iface, return E_UNEXPECTED; }
- if (pCategory && IsEqualIID(pCategory, &PIN_CATEGORY_VBI)) { + if (category && IsEqualGUID(category, &PIN_CATEGORY_VBI)) + { FIXME("Tee/Sink-to-Sink filter not supported\n"); return E_NOTIMPL; }
- hr = find_unconnected_pin(This, pCategory, pType, pSource, &source_out); + if (IUnknown_QueryInterface(source, &IID_IPin, (void **)&pin) == S_OK) + { + hr = find_unconnected_source_from_pin(This, category, majortype, pin, &source_out); + IPin_Release(pin); + } + else if (IUnknown_QueryInterface(source, &IID_IBaseFilter, (void **)&filter) == S_OK) + { + hr = find_unconnected_source_from_filter(This, category, majortype, filter, &source_out); + IBaseFilter_Release(filter); + } + else + { + WARN("Source object does not expose IBaseFilter or IPin.\n"); + return E_INVALIDARG; + } if (FAILED(hr)) return hr; return_hr = hr; diff --git a/dlls/qcap/tests/capturegraph.c b/dlls/qcap/tests/capturegraph.c index 223bf972de0..629bc92d895 100644 --- a/dlls/qcap/tests/capturegraph.c +++ b/dlls/qcap/tests/capturegraph.c @@ -929,12 +929,9 @@ static void test_render_stream(void) todo_wine ok(!transform.source1.pin.pin.peer, "Pin should not be connected.\n"); todo_wine ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n");
- if (0) - { - hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL, - (IUnknown *)&source.source1.pin.pin.IPin_iface, NULL, &sink.filter.IBaseFilter_iface); - ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); - } + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL, + (IUnknown *)&source.source1.pin.pin.IPin_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
disconnect_pins(graph, &source.source1);
@@ -983,12 +980,9 @@ static void test_render_stream(void) check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Capture"); ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
- if (0) - { - hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL, - (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); - ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); - } + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL, (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); @@ -1014,12 +1008,9 @@ static void test_render_stream(void) check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Preview"); ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
- if (0) - { - hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL, - (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); - ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); - } + hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL, + (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
disconnect_pins(graph, &source.source1); IGraphBuilder_RemoveFilter(graph, &transform.filter.IBaseFilter_iface); @@ -1031,8 +1022,8 @@ static void test_render_stream(void) hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL, (IUnknown *)&source.source1.pin.pin.IPin_iface, NULL, &sink.filter.IBaseFilter_iface); ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine check_smart_tee_pin(source.source1.pin.pin.peer, L"Input"); - todo_wine check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Capture"); + check_smart_tee_pin(source.source1.pin.pin.peer, L"Input"); + check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Capture"); ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); disconnect_pins(graph, &source.source1); IGraphBuilder_RemoveFilter(graph, &transform.filter.IBaseFilter_iface); @@ -1062,8 +1053,8 @@ static void test_render_stream(void) hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL, (IUnknown *)&source.source1.pin.pin.IPin_iface, NULL, &sink.filter.IBaseFilter_iface); ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine check_smart_tee_pin(source.source1.pin.pin.peer, L"Input"); - todo_wine check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Capture"); + check_smart_tee_pin(source.source1.pin.pin.peer, L"Input"); + check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Capture"); ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); disconnect_pins(graph, &source.source1); disconnect_pins(graph, &transform.source1); @@ -1075,9 +1066,9 @@ static void test_render_stream(void) ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface); ok(!ref, "Got outstanding refcount %d.\n", ref); ref = IBaseFilter_Release(&transform.filter.IBaseFilter_iface); - todo_wine ok(!ref, "Got outstanding refcount %d.\n", ref); + ok(!ref, "Got outstanding refcount %d.\n", ref); ref = IBaseFilter_Release(&sink.filter.IBaseFilter_iface); - todo_wine ok(!ref, "Got outstanding refcount %d.\n", ref); + ok(!ref, "Got outstanding refcount %d.\n", ref); }
START_TEST(capturegraph)
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qcap/capturegraph.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/dlls/qcap/capturegraph.c b/dlls/qcap/capturegraph.c index b49e45b9d6b..6c20e727a20 100644 --- a/dlls/qcap/capturegraph.c +++ b/dlls/qcap/capturegraph.c @@ -511,12 +511,17 @@ static HRESULT find_unconnected_source_from_pin(CaptureGraphImpl *capture_graph,
if (category && (IsEqualGUID(category, &PIN_CATEGORY_CAPTURE) || IsEqualGUID(category, &PIN_CATEGORY_PREVIEW))) - hr = match_smart_tee_pin(capture_graph, category, majortype, (IUnknown *)pin, &pin); + { + if (FAILED(hr = match_smart_tee_pin(capture_graph, category, majortype, (IUnknown *)pin, &pin))) + return hr; + } + else if (pin_matches(pin, PINDIR_OUTPUT, category, majortype, FALSE)) + { + IPin_AddRef(pin); + hr = S_OK; + } else - hr = ICaptureGraphBuilder2_FindPin(&capture_graph->ICaptureGraphBuilder2_iface, - (IUnknown *)pin, PINDIR_OUTPUT, category, majortype, FALSE, -1, &pin); - if (FAILED(hr)) - return hr; + return E_FAIL;
if (FAILED(IPin_ConnectedTo(pin, &peer))) {
find_unconnected_source_from_pin() already checks the category and majortype anyway.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qcap/capturegraph.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/dlls/qcap/capturegraph.c b/dlls/qcap/capturegraph.c index 6c20e727a20..a5b00df90b2 100644 --- a/dlls/qcap/capturegraph.c +++ b/dlls/qcap/capturegraph.c @@ -540,9 +540,9 @@ static HRESULT find_unconnected_source_from_pin(CaptureGraphImpl *capture_graph, static HRESULT find_unconnected_source_from_filter(CaptureGraphImpl *capture_graph, const GUID *category, const GUID *majortype, IBaseFilter *filter, IPin **ret) { + IEnumPins *enumpins; IPin *pin, *peer; HRESULT hr; - int index;
if (category && (IsEqualGUID(category, &PIN_CATEGORY_CAPTURE) || IsEqualGUID(category, &PIN_CATEGORY_PREVIEW))) @@ -561,14 +561,20 @@ static HRESULT find_unconnected_source_from_filter(CaptureGraphImpl *capture_gra return E_INVALIDARG; }
- for (index = 0; SUCCEEDED(ICaptureGraphBuilder2_FindPin(&capture_graph->ICaptureGraphBuilder2_iface, - (IUnknown *)filter, PINDIR_OUTPUT, category, majortype, FALSE, index, &pin)); ++index) + if (FAILED(hr = IBaseFilter_EnumPins(filter, &enumpins))) + return hr; + + while (IEnumPins_Next(enumpins, 1, &pin, NULL) == S_OK) { - hr = find_unconnected_source_from_pin(capture_graph, category, majortype, pin, ret); - IPin_Release(pin); - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr = find_unconnected_source_from_pin(capture_graph, category, majortype, pin, ret))) + { + IEnumPins_Release(enumpins); + IPin_Release(pin); return hr; + } + IPin_Release(pin); } + IEnumPins_Release(enumpins);
return E_INVALIDARG; }
https://bugs.winehq.org/show_bug.cgi?id=48766 Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qcap/capturegraph.c | 30 ++++++++++++++++++++---------- dlls/qcap/tests/capturegraph.c | 6 +++--- 2 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/dlls/qcap/capturegraph.c b/dlls/qcap/capturegraph.c index a5b00df90b2..822f68754e0 100644 --- a/dlls/qcap/capturegraph.c +++ b/dlls/qcap/capturegraph.c @@ -505,28 +505,38 @@ static HRESULT find_unconnected_source_from_filter(CaptureGraphImpl *capture_gra static HRESULT find_unconnected_source_from_pin(CaptureGraphImpl *capture_graph, const GUID *category, const GUID *majortype, IPin *pin, IPin **ret) { + PIN_DIRECTION dir; PIN_INFO info; HRESULT hr; IPin *peer;
+ IPin_QueryDirection(pin, &dir); + if (dir != PINDIR_OUTPUT) + return VFW_E_INVALID_DIRECTION; + if (category && (IsEqualGUID(category, &PIN_CATEGORY_CAPTURE) || IsEqualGUID(category, &PIN_CATEGORY_PREVIEW))) { if (FAILED(hr = match_smart_tee_pin(capture_graph, category, majortype, (IUnknown *)pin, &pin))) return hr; - } - else if (pin_matches(pin, PINDIR_OUTPUT, category, majortype, FALSE)) - { - IPin_AddRef(pin); - hr = S_OK; + + if (FAILED(IPin_ConnectedTo(pin, &peer))) + { + *ret = pin; + return S_OK; + } } else - return E_FAIL; - - if (FAILED(IPin_ConnectedTo(pin, &peer))) { - *ret = pin; - return hr; + if (FAILED(IPin_ConnectedTo(pin, &peer))) + { + if (!pin_matches(pin, PINDIR_OUTPUT, category, majortype, FALSE)) + return E_FAIL; + + IPin_AddRef(*ret = pin); + return S_OK; + } + IPin_AddRef(pin); }
IPin_QueryPinInfo(peer, &info); diff --git a/dlls/qcap/tests/capturegraph.c b/dlls/qcap/tests/capturegraph.c index 629bc92d895..49b4f8c6b9f 100644 --- a/dlls/qcap/tests/capturegraph.c +++ b/dlls/qcap/tests/capturegraph.c @@ -874,15 +874,15 @@ static void test_render_stream(void)
hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, &sink1_type, (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr); ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n"); - todo_wine ok(transform.source2.pin.pin.peer == &sink.sink2.pin.pin.IPin_iface, "Got wrong connection.\n"); + ok(transform.source2.pin.pin.peer == &sink.sink2.pin.pin.IPin_iface, "Got wrong connection.\n"); ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n");
disconnect_pins(graph, &source.source1); disconnect_pins(graph, &transform.source1); - todo_wine disconnect_pins(graph, &transform.source2); + disconnect_pins(graph, &transform.source2);
/* Test categories. */