mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / qcap / tests / capturegraph.c
blobcdd9a27828ad5e6b8ba15b33a5607e2d42b92d3f
1 /*
2 * Capture graph builder unit tests
4 * Copyright 2019 Zebediah Figura
5 * Copyright 2020 Zebediah Figura for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
23 #include "dshow.h"
24 #include "wine/strmbase.h"
25 #include "wine/test.h"
27 static ICaptureGraphBuilder2 *create_capture_graph(void)
29 ICaptureGraphBuilder2 *ret;
30 HRESULT hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL,
31 CLSCTX_INPROC_SERVER, &IID_ICaptureGraphBuilder2, (void **)&ret);
32 ok(hr == S_OK, "Failed to create capture graph builder, hr %#x.\n", hr);
33 return ret;
36 static const GUID testiid = {0x11111111}, testtype = {0x22222222};
38 struct testsource
40 struct strmbase_source pin;
41 IKsPropertySet IKsPropertySet_iface;
42 GUID category;
43 BOOL has_iface;
46 struct testsink
48 struct strmbase_sink pin;
49 BOOL has_iface;
52 struct testfilter
54 struct strmbase_filter filter;
55 struct testsource source1, source2;
56 struct testsink sink1, sink2;
57 BOOL filter_has_iface;
58 GUID source_type;
59 const GUID *sink_type;
62 static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface)
64 return CONTAINING_RECORD(iface, struct testfilter, filter);
67 static HRESULT testfilter_query_interface(struct strmbase_filter *iface, REFIID iid, void **out)
69 struct testfilter *filter = impl_from_strmbase_filter(iface);
71 ok(!IsEqualGUID(iid, &IID_IKsPropertySet), "Unexpected query for IKsPropertySet.\n");
73 if (filter->filter_has_iface && IsEqualGUID(iid, &testiid))
74 *out = &iface->IBaseFilter_iface;
75 else
76 return E_NOINTERFACE;
78 IUnknown_AddRef((IUnknown *)*out);
79 return S_OK;
82 static struct strmbase_pin *testfilter_get_pin(struct strmbase_filter *iface, unsigned int index)
84 struct testfilter *filter = impl_from_strmbase_filter(iface);
86 if (!index)
87 return &filter->source1.pin.pin;
88 else if (index == 1)
89 return &filter->sink1.pin.pin;
90 else if (index == 2)
91 return &filter->source2.pin.pin;
92 else if (index == 3)
93 return &filter->sink2.pin.pin;
94 return NULL;
97 static void testfilter_destroy(struct strmbase_filter *iface)
99 struct testfilter *filter = impl_from_strmbase_filter(iface);
100 strmbase_source_cleanup(&filter->source1.pin);
101 strmbase_source_cleanup(&filter->source2.pin);
102 strmbase_sink_cleanup(&filter->sink1.pin);
103 strmbase_sink_cleanup(&filter->sink2.pin);
104 strmbase_filter_cleanup(&filter->filter);
107 static const struct strmbase_filter_ops testfilter_ops =
109 .filter_query_interface = testfilter_query_interface,
110 .filter_get_pin = testfilter_get_pin,
111 .filter_destroy = testfilter_destroy,
114 static struct testsource *impl_from_IKsPropertySet(IKsPropertySet *iface)
116 return CONTAINING_RECORD(iface, struct testsource, IKsPropertySet_iface);
119 static HRESULT WINAPI property_set_QueryInterface(IKsPropertySet *iface, REFIID iid, void **out)
121 struct testsource *pin = impl_from_IKsPropertySet(iface);
122 return IPin_QueryInterface(&pin->pin.pin.IPin_iface, iid, out);
125 static ULONG WINAPI property_set_AddRef(IKsPropertySet *iface)
127 struct testsource *pin = impl_from_IKsPropertySet(iface);
128 return IPin_AddRef(&pin->pin.pin.IPin_iface);
131 static ULONG WINAPI property_set_Release(IKsPropertySet *iface)
133 struct testsource *pin = impl_from_IKsPropertySet(iface);
134 return IPin_Release(&pin->pin.pin.IPin_iface);
137 static HRESULT WINAPI property_set_Set(IKsPropertySet *iface, REFGUID set, DWORD id,
138 void *instance_data, DWORD instance_size, void *property_data, DWORD property_size)
140 ok(0, "Unexpected call.\n");
141 return E_NOTIMPL;
144 static HRESULT WINAPI property_set_Get(IKsPropertySet *iface, REFGUID set, DWORD id,
145 void *instance_data, DWORD instance_size, void *property_data, DWORD property_size, DWORD *ret_size)
147 struct testsource *pin = impl_from_IKsPropertySet(iface);
149 if (winetest_debug > 1) trace("%s->Get()\n", debugstr_w(pin->pin.pin.name));
151 ok(IsEqualGUID(set, &AMPROPSETID_Pin), "Got set %s.\n", debugstr_guid(set));
152 ok(id == AMPROPERTY_PIN_CATEGORY, "Got id %#x.\n", id);
153 ok(!instance_data, "Got instance data %p.\n", instance_data);
154 ok(!instance_size, "Got instance size %u.\n", instance_size);
155 ok(property_size == sizeof(GUID), "Got property size %u.\n", property_size);
156 ok(!!ret_size, "Expected non-NULL return size.\n");
157 memcpy(property_data, &pin->category, sizeof(GUID));
158 return S_OK;
161 static HRESULT WINAPI property_set_QuerySupported(IKsPropertySet *iface, REFGUID set, DWORD id, DWORD *flags)
163 ok(0, "Unexpected call.\n");
164 return E_NOTIMPL;
167 static const IKsPropertySetVtbl property_set_vtbl =
169 property_set_QueryInterface,
170 property_set_AddRef,
171 property_set_Release,
172 property_set_Set,
173 property_set_Get,
174 property_set_QuerySupported,
177 static struct testsource *impl_source_from_strmbase_pin(struct strmbase_pin *iface)
179 return CONTAINING_RECORD(iface, struct testsource, pin.pin);
182 static HRESULT testsource_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
184 struct testsource *pin = impl_source_from_strmbase_pin(iface);
186 if (pin->has_iface && IsEqualGUID(iid, &testiid))
187 *out = &pin->pin.pin.IPin_iface;
188 else if (pin->IKsPropertySet_iface.lpVtbl && IsEqualGUID(iid, &IID_IKsPropertySet))
189 *out = &pin->IKsPropertySet_iface;
190 else
191 return E_NOINTERFACE;
193 IUnknown_AddRef((IUnknown *)*out);
194 return S_OK;
197 static HRESULT testsource_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *mt)
199 struct testfilter *filter = impl_from_strmbase_filter(iface->filter);
201 if (!index)
203 memset(mt, 0, sizeof(*mt));
204 mt->majortype = filter->source_type;
205 return S_OK;
207 return VFW_S_NO_MORE_ITEMS;
210 static HRESULT WINAPI testsource_DecideBufferSize(struct strmbase_source *iface,
211 IMemAllocator *allocator, ALLOCATOR_PROPERTIES *props)
213 props->cBuffers = props->cbAlign = props->cbBuffer = 1;
214 return S_OK;
217 static const struct strmbase_source_ops testsource_ops =
219 .base.pin_query_interface = testsource_query_interface,
220 .base.pin_get_media_type = testsource_get_media_type,
221 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
222 .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator,
223 .pfnDecideBufferSize = testsource_DecideBufferSize,
226 static struct testsink *impl_sink_from_strmbase_pin(struct strmbase_pin *iface)
228 return CONTAINING_RECORD(iface, struct testsink, pin.pin);
231 static HRESULT testsink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
233 struct testsink *pin = impl_sink_from_strmbase_pin(iface);
235 ok(!IsEqualGUID(iid, &IID_IKsPropertySet), "Unexpected query for IKsPropertySet.\n");
237 if (IsEqualGUID(iid, &IID_IMemInputPin))
238 *out = &pin->pin.IMemInputPin_iface;
239 else if (pin->has_iface && IsEqualGUID(iid, &testiid))
240 *out = &pin->pin.pin.IPin_iface;
241 else
242 return E_NOINTERFACE;
244 IUnknown_AddRef((IUnknown *)*out);
245 return S_OK;
248 static HRESULT testsink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
250 struct testfilter *filter = impl_from_strmbase_filter(iface->filter);
252 if (filter->sink_type && !IsEqualGUID(&mt->majortype, filter->sink_type))
253 return S_FALSE;
254 return S_OK;
257 static const struct strmbase_sink_ops testsink_ops =
259 .base.pin_query_interface = testsink_query_interface,
260 .base.pin_query_accept = testsink_query_accept,
263 static void reset_interfaces(struct testfilter *filter)
265 filter->filter_has_iface = filter->sink1.has_iface = filter->sink2.has_iface = TRUE;
266 filter->source1.has_iface = filter->source2.has_iface = TRUE;
269 static void testfilter_init(struct testfilter *filter)
271 static const GUID clsid = {0xabacab};
272 memset(filter, 0, sizeof(*filter));
273 strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops);
274 strmbase_source_init(&filter->source1.pin, &filter->filter, L"source1", &testsource_ops);
275 strmbase_source_init(&filter->source2.pin, &filter->filter, L"source2", &testsource_ops);
276 strmbase_sink_init(&filter->sink1.pin, &filter->filter, L"sink1", &testsink_ops, NULL);
277 strmbase_sink_init(&filter->sink2.pin, &filter->filter, L"sink2", &testsink_ops, NULL);
278 reset_interfaces(filter);
281 static void test_find_interface(void)
283 static const AM_MEDIA_TYPE mt1 =
285 .majortype = {0x111},
286 .subtype = {0x222},
287 .formattype = {0x333},
289 static const AM_MEDIA_TYPE mt2 =
291 .majortype = {0x444},
292 .subtype = {0x555},
293 .formattype = {0x666},
295 static const GUID bogus_majortype = {0x777};
297 ICaptureGraphBuilder2 *capture_graph = create_capture_graph();
298 struct testfilter filter1, filter2, filter3;
299 IGraphBuilder *graph;
300 unsigned int i;
301 IUnknown *unk;
302 HRESULT hr;
303 ULONG ref;
305 struct
307 BOOL *expose;
308 const void *iface;
310 tests_from_filter2[] =
312 {&filter2.filter_has_iface, &filter2.filter.IBaseFilter_iface},
313 {&filter2.source1.has_iface, &filter2.source1.pin.pin.IPin_iface},
314 {&filter3.sink1.has_iface, &filter3.sink1.pin.pin.IPin_iface},
315 {&filter3.filter_has_iface, &filter3.filter.IBaseFilter_iface},
316 {&filter3.source1.has_iface, &filter3.source1.pin.pin.IPin_iface},
317 {&filter3.source2.has_iface, &filter3.source2.pin.pin.IPin_iface},
318 {&filter2.source2.has_iface, &filter2.source2.pin.pin.IPin_iface},
319 {&filter2.sink1.has_iface, &filter2.sink1.pin.pin.IPin_iface},
320 {&filter1.source1.has_iface, &filter1.source1.pin.pin.IPin_iface},
321 {&filter1.filter_has_iface, &filter1.filter.IBaseFilter_iface},
322 {&filter1.sink1.has_iface, &filter1.sink1.pin.pin.IPin_iface},
323 {&filter1.sink2.has_iface, &filter1.sink2.pin.pin.IPin_iface},
324 {&filter2.sink2.has_iface, &filter2.sink2.pin.pin.IPin_iface},
325 }, tests_from_filter1[] =
327 {&filter1.filter_has_iface, &filter1.filter.IBaseFilter_iface},
328 {&filter1.source1.has_iface, &filter1.source1.pin.pin.IPin_iface},
329 {&filter2.sink1.has_iface, &filter2.sink1.pin.pin.IPin_iface},
330 {&filter2.filter_has_iface, &filter2.filter.IBaseFilter_iface},
331 {&filter2.source1.has_iface, &filter2.source1.pin.pin.IPin_iface},
332 {&filter3.sink1.has_iface, &filter3.sink1.pin.pin.IPin_iface},
333 {&filter3.filter_has_iface, &filter3.filter.IBaseFilter_iface},
334 {&filter3.source1.has_iface, &filter3.source1.pin.pin.IPin_iface},
335 {&filter3.source2.has_iface, &filter3.source2.pin.pin.IPin_iface},
336 {&filter2.source2.has_iface, &filter2.source2.pin.pin.IPin_iface},
337 {&filter1.source2.has_iface, &filter1.source2.pin.pin.IPin_iface},
338 {&filter1.sink1.has_iface, &filter1.sink1.pin.pin.IPin_iface},
339 {&filter1.sink2.has_iface, &filter1.sink2.pin.pin.IPin_iface},
340 }, look_upstream_tests[] =
342 {&filter2.sink1.has_iface, &filter2.sink1.pin.pin.IPin_iface},
343 {&filter1.source1.has_iface, &filter1.source1.pin.pin.IPin_iface},
344 {&filter1.filter_has_iface, &filter1.filter.IBaseFilter_iface},
345 {&filter1.sink1.has_iface, &filter1.sink1.pin.pin.IPin_iface},
346 {&filter1.sink2.has_iface, &filter1.sink2.pin.pin.IPin_iface},
347 {&filter2.sink2.has_iface, &filter2.sink2.pin.pin.IPin_iface},
348 }, look_downstream_tests[] =
350 {&filter2.source1.has_iface, &filter2.source1.pin.pin.IPin_iface},
351 {&filter3.sink1.has_iface, &filter3.sink1.pin.pin.IPin_iface},
352 {&filter3.filter_has_iface, &filter3.filter.IBaseFilter_iface},
353 {&filter3.source1.has_iface, &filter3.source1.pin.pin.IPin_iface},
354 {&filter3.source2.has_iface, &filter3.source2.pin.pin.IPin_iface},
355 {&filter2.source2.has_iface, &filter2.source2.pin.pin.IPin_iface},
356 }, category_tests[] =
358 {&filter3.filter_has_iface, &filter3.filter.IBaseFilter_iface},
359 {&filter3.source1.has_iface, &filter3.source1.pin.pin.IPin_iface},
360 {&filter3.source2.has_iface, &filter3.source2.pin.pin.IPin_iface},
361 {&filter2.sink1.has_iface, &filter2.sink1.pin.pin.IPin_iface},
362 {&filter1.source1.has_iface, &filter1.source1.pin.pin.IPin_iface},
363 {&filter1.filter_has_iface, &filter1.filter.IBaseFilter_iface},
364 {&filter1.sink1.has_iface, &filter1.sink1.pin.pin.IPin_iface},
365 {&filter1.sink2.has_iface, &filter1.sink2.pin.pin.IPin_iface},
366 {&filter2.sink2.has_iface, &filter2.sink2.pin.pin.IPin_iface},
369 CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (void **)&graph);
370 hr = ICaptureGraphBuilder2_SetFiltergraph(capture_graph, graph);
371 ok(hr == S_OK, "Got hr %#x.\n", hr);
373 testfilter_init(&filter1);
374 IGraphBuilder_AddFilter(graph, &filter1.filter.IBaseFilter_iface, L"filter1");
375 testfilter_init(&filter2);
376 IGraphBuilder_AddFilter(graph, &filter2.filter.IBaseFilter_iface, L"filter2");
377 testfilter_init(&filter3);
378 IGraphBuilder_AddFilter(graph, &filter3.filter.IBaseFilter_iface, L"filter3");
380 hr = IGraphBuilder_ConnectDirect(graph, &filter1.source1.pin.pin.IPin_iface, &filter2.sink1.pin.pin.IPin_iface, &mt1);
381 ok(hr == S_OK, "Got hr %#x.\n", hr);
382 hr = IGraphBuilder_ConnectDirect(graph, &filter2.source1.pin.pin.IPin_iface, &filter3.sink1.pin.pin.IPin_iface, &mt2);
383 ok(hr == S_OK, "Got hr %#x.\n", hr);
385 /* Test search order without any restrictions applied. */
387 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, NULL, &bogus_majortype,
388 NULL, &testiid, (void **)&unk);
389 ok(hr == E_POINTER, "got hr %#x.\n", hr);
391 for (i = 0; i < ARRAY_SIZE(tests_from_filter2); ++i)
393 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, NULL, &bogus_majortype,
394 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
395 ok(hr == S_OK, "Test %u: got hr %#x.\n", i, hr);
396 ok(unk == tests_from_filter2[i].iface, "Test %u: got wrong interface %p.\n", i, unk);
397 IUnknown_Release(unk);
398 *tests_from_filter2[i].expose = FALSE;
401 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, NULL, &bogus_majortype,
402 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
403 ok(hr == E_FAIL, "Got hr %#x.\n", hr);
405 reset_interfaces(&filter1);
406 reset_interfaces(&filter2);
407 reset_interfaces(&filter3);
409 for (i = 0; i < ARRAY_SIZE(tests_from_filter1); ++i)
411 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, NULL, &bogus_majortype,
412 &filter1.filter.IBaseFilter_iface, &testiid, (void **)&unk);
413 ok(hr == S_OK, "Test %u: got hr %#x.\n", i, hr);
414 ok(unk == tests_from_filter1[i].iface, "Test %u: got wrong interface %p.\n", i, unk);
415 IUnknown_Release(unk);
416 *tests_from_filter1[i].expose = FALSE;
419 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, NULL, &bogus_majortype,
420 &filter1.filter.IBaseFilter_iface, &testiid, (void **)&unk);
421 ok(hr == E_FAIL, "Got hr %#x.\n", hr);
423 /* Test with upstream/downstream flags. */
425 reset_interfaces(&filter1);
426 reset_interfaces(&filter2);
427 reset_interfaces(&filter3);
429 for (i = 0; i < ARRAY_SIZE(look_upstream_tests); ++i)
431 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &LOOK_UPSTREAM_ONLY, &bogus_majortype,
432 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
433 ok(hr == S_OK, "Test %u: got hr %#x.\n", i, hr);
434 ok(unk == look_upstream_tests[i].iface, "Test %u: got wrong interface %p.\n", i, unk);
435 IUnknown_Release(unk);
436 *look_upstream_tests[i].expose = FALSE;
439 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &LOOK_UPSTREAM_ONLY, &bogus_majortype,
440 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
441 ok(hr == E_FAIL, "Got hr %#x.\n", hr);
443 reset_interfaces(&filter1);
444 reset_interfaces(&filter2);
445 reset_interfaces(&filter3);
447 for (i = 0; i < ARRAY_SIZE(look_downstream_tests); ++i)
449 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &LOOK_DOWNSTREAM_ONLY, &bogus_majortype,
450 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
451 ok(hr == S_OK, "Test %u: got hr %#x.\n", i, hr);
452 ok(unk == look_downstream_tests[i].iface, "Test %u: got wrong interface %p.\n", i, unk);
453 IUnknown_Release(unk);
454 *look_downstream_tests[i].expose = FALSE;
457 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &LOOK_DOWNSTREAM_ONLY, &bogus_majortype,
458 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
459 ok(hr == E_FAIL, "Got hr %#x.\n", hr);
461 /* Test with a category flag. */
463 reset_interfaces(&filter1);
464 reset_interfaces(&filter2);
465 reset_interfaces(&filter3);
467 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
468 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
469 ok(hr == S_OK, "Got hr %#x\n", hr);
470 ok(unk == (IUnknown *)&filter2.filter.IBaseFilter_iface, "Got wrong interface %p.\n", unk);
471 IUnknown_Release(unk);
472 filter2.filter_has_iface = FALSE;
474 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
475 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
476 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
478 filter2.source1.IKsPropertySet_iface.lpVtbl = &property_set_vtbl;
479 filter2.source1.category = PIN_CATEGORY_CAPTURE;
480 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
481 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
482 ok(hr == S_OK, "Got hr %#x.\n", hr);
483 ok(unk == (IUnknown *)&filter2.source1.pin.pin.IPin_iface, "Got wrong interface %p.\n", unk);
484 IUnknown_Release(unk);
485 filter2.source1.has_iface = FALSE;
487 /* Native returns the filter3 sink next, but suffers from a bug wherein it
488 * releases a reference to the wrong pin. */
489 filter3.sink1.has_iface = FALSE;
491 for (i = 0; i < ARRAY_SIZE(category_tests); ++i)
493 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
494 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
495 ok(hr == S_OK, "Test %u: got hr %#x.\n", i, hr);
496 ok(unk == category_tests[i].iface, "Test %u: got wrong interface %p.\n", i, unk);
497 IUnknown_Release(unk);
498 *category_tests[i].expose = FALSE;
501 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
502 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
503 ok(hr == E_FAIL, "Got hr %#x.\n", hr);
505 /* Test with a media type. */
507 filter1.source_type = filter2.source_type = testtype;
509 reset_interfaces(&filter1);
510 reset_interfaces(&filter2);
511 reset_interfaces(&filter3);
513 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &PIN_CATEGORY_CAPTURE, &bogus_majortype,
514 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
515 ok(hr == S_OK, "Got hr %#x\n", hr);
516 ok(unk == (IUnknown *)&filter2.filter.IBaseFilter_iface, "Got wrong interface %p.\n", unk);
517 IUnknown_Release(unk);
518 filter2.filter_has_iface = FALSE;
520 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &PIN_CATEGORY_CAPTURE, &bogus_majortype,
521 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
522 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
524 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &PIN_CATEGORY_CAPTURE, &mt2.majortype,
525 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
526 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
528 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &PIN_CATEGORY_CAPTURE, &testtype,
529 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
530 ok(hr == S_OK, "Got hr %#x.\n", hr);
531 ok(unk == (IUnknown *)&filter2.source1.pin.pin.IPin_iface, "Got wrong interface %p.\n", unk);
532 IUnknown_Release(unk);
533 filter2.source1.has_iface = FALSE;
535 filter3.sink1.has_iface = FALSE;
537 for (i = 0; i < ARRAY_SIZE(category_tests); ++i)
539 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
540 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
541 ok(hr == S_OK, "Test %u: got hr %#x.\n", i, hr);
542 ok(unk == category_tests[i].iface, "Test %u: got wrong interface %p.\n", i, unk);
543 IUnknown_Release(unk);
544 *category_tests[i].expose = FALSE;
547 hr = ICaptureGraphBuilder2_FindInterface(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
548 &filter2.filter.IBaseFilter_iface, &testiid, (void **)&unk);
549 ok(hr == E_FAIL, "Got hr %#x.\n", hr);
551 ref = ICaptureGraphBuilder2_Release(capture_graph);
552 ok(!ref, "Got outstanding refcount %d.\n", ref);
553 ref = IGraphBuilder_Release(graph);
554 ok(!ref, "Got outstanding refcount %d.\n", ref);
555 ref = IBaseFilter_Release(&filter1.filter.IBaseFilter_iface);
556 ok(!ref, "Got outstanding refcount %d.\n", ref);
557 ref = IBaseFilter_Release(&filter2.filter.IBaseFilter_iface);
558 ok(!ref, "Got outstanding refcount %d.\n", ref);
559 ref = IBaseFilter_Release(&filter3.filter.IBaseFilter_iface);
560 ok(!ref, "Got outstanding refcount %d.\n", ref);
563 static void test_find_pin(void)
565 static const AM_MEDIA_TYPE mt =
567 .majortype = {0x111},
568 .subtype = {0x222},
569 .formattype = {0x333},
572 ICaptureGraphBuilder2 *capture_graph = create_capture_graph();
573 struct testfilter filter1, filter2;
574 IGraphBuilder *graph;
575 HRESULT hr;
576 ULONG ref;
577 IPin *pin;
579 CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (void **)&graph);
580 hr = ICaptureGraphBuilder2_SetFiltergraph(capture_graph, graph);
581 ok(hr == S_OK, "Got hr %#x.\n", hr);
583 testfilter_init(&filter1);
584 testfilter_init(&filter2);
585 IGraphBuilder_AddFilter(graph, &filter1.filter.IBaseFilter_iface, L"filter1");
586 IGraphBuilder_AddFilter(graph, &filter2.filter.IBaseFilter_iface, L"filter2");
588 hr = IGraphBuilder_ConnectDirect(graph, &filter1.source1.pin.pin.IPin_iface,
589 &filter2.sink1.pin.pin.IPin_iface, &mt);
590 ok(hr == S_OK, "Got hr %#x.\n", hr);
592 hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface,
593 PINDIR_INPUT, NULL, NULL, FALSE, 0, &pin);
594 ok(hr == S_OK, "Got hr %#x.\n", hr);
595 ok(pin == &filter1.sink1.pin.pin.IPin_iface, "Got wrong pin.\n");
596 IPin_Release(pin);
598 hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface,
599 PINDIR_INPUT, NULL, NULL, FALSE, 1, &pin);
600 ok(hr == S_OK, "Got hr %#x.\n", hr);
601 ok(pin == &filter1.sink2.pin.pin.IPin_iface, "Got wrong pin.\n");
602 IPin_Release(pin);
604 hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface,
605 PINDIR_INPUT, NULL, NULL, FALSE, 2, &pin);
606 ok(hr == E_FAIL, "Got hr %#x.\n", hr);
608 hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface,
609 PINDIR_OUTPUT, NULL, NULL, FALSE, 0, &pin);
610 ok(hr == S_OK, "Got hr %#x.\n", hr);
611 ok(pin == &filter1.source1.pin.pin.IPin_iface, "Got wrong pin.\n");
612 IPin_Release(pin);
614 hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface,
615 PINDIR_OUTPUT, NULL, NULL, FALSE, 1, &pin);
616 ok(hr == S_OK, "Got hr %#x.\n", hr);
617 ok(pin == &filter1.source2.pin.pin.IPin_iface, "Got wrong pin.\n");
618 IPin_Release(pin);
620 hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface,
621 PINDIR_OUTPUT, NULL, NULL, FALSE, 2, &pin);
622 ok(hr == E_FAIL, "Got hr %#x.\n", hr);
624 /* Test the unconnected flag. */
626 hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface,
627 PINDIR_OUTPUT, NULL, NULL, TRUE, 0, &pin);
628 ok(hr == S_OK, "Got hr %#x.\n", hr);
629 ok(pin == &filter1.source2.pin.pin.IPin_iface, "Got wrong pin.\n");
630 IPin_Release(pin);
632 hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface,
633 PINDIR_OUTPUT, NULL, NULL, TRUE, 1, &pin);
634 ok(hr == E_FAIL, "Got hr %#x.\n", hr);
636 /* Test categories. */
638 filter1.source1.IKsPropertySet_iface.lpVtbl = &property_set_vtbl;
639 filter1.source1.category = PIN_CATEGORY_CAPTURE;
641 hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface,
642 PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, NULL, FALSE, 0, &pin);
643 ok(hr == S_OK, "Got hr %#x.\n", hr);
644 ok(pin == &filter1.source1.pin.pin.IPin_iface, "Got wrong pin.\n");
645 IPin_Release(pin);
647 hr = ICaptureGraphBuilder2_FindPin(capture_graph, (IUnknown *)&filter1.filter.IBaseFilter_iface,
648 PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE, NULL, FALSE, 1, &pin);
649 ok(hr == E_FAIL, "Got hr %#x.\n", hr);
651 ref = ICaptureGraphBuilder2_Release(capture_graph);
652 ok(!ref, "Got outstanding refcount %d.\n", ref);
653 ref = IGraphBuilder_Release(graph);
654 ok(!ref, "Got outstanding refcount %d.\n", ref);
655 ref = IBaseFilter_Release(&filter1.filter.IBaseFilter_iface);
656 ok(!ref, "Got outstanding refcount %d.\n", ref);
657 ref = IBaseFilter_Release(&filter2.filter.IBaseFilter_iface);
658 ok(!ref, "Got outstanding refcount %d.\n", ref);
661 static void disconnect_pins(IGraphBuilder *graph, struct testsource *pin)
663 HRESULT hr;
664 hr = IGraphBuilder_Disconnect(graph, pin->pin.pin.peer);
665 ok(hr == S_OK, "Got hr %#x.\n", hr);
666 hr = IGraphBuilder_Disconnect(graph, &pin->pin.pin.IPin_iface);
667 ok(hr == S_OK, "Got hr %#x.\n", hr);
670 static void check_smart_tee_pin_(int line, IPin *pin, const WCHAR *name)
672 PIN_INFO info;
673 GUID clsid;
675 IPin_QueryPinInfo(pin, &info);
676 ok_(__FILE__, line)(!wcscmp(info.achName, name), "Got name %s.\n", debugstr_w(info.achName));
677 IBaseFilter_GetClassID(info.pFilter, &clsid);
678 ok_(__FILE__, line)(IsEqualGUID(&clsid, &CLSID_SmartTee), "Got CLSID %s.\n", debugstr_guid(&clsid));
679 IBaseFilter_Release(info.pFilter);
681 #define check_smart_tee_pin(pin, name) check_smart_tee_pin_(__LINE__, pin, name)
683 static void test_render_stream(void)
685 static const GUID source_type = {0x1111};
686 static const GUID sink1_type = {0x8888};
687 static const GUID bad_type = {0x4444};
689 ICaptureGraphBuilder2 *capture_graph = create_capture_graph();
690 struct testfilter source, transform, sink, identity;
691 IGraphBuilder *graph;
692 HRESULT hr;
693 ULONG ref;
695 CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (void **)&graph);
696 hr = ICaptureGraphBuilder2_SetFiltergraph(capture_graph, graph);
697 ok(hr == S_OK, "Got hr %#x.\n", hr);
699 testfilter_init(&source);
700 testfilter_init(&transform);
701 testfilter_init(&sink);
702 testfilter_init(&identity);
703 IGraphBuilder_AddFilter(graph, &source.filter.IBaseFilter_iface, L"source");
704 IGraphBuilder_AddFilter(graph, &transform.filter.IBaseFilter_iface, L"transform");
705 IGraphBuilder_AddFilter(graph, &sink.filter.IBaseFilter_iface, L"sink");
707 source.source_type = source_type;
708 transform.sink_type = &source_type;
709 transform.source_type = sink1_type;
710 sink.sink_type = &sink1_type;
712 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL,
713 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
714 ok(hr == S_OK, "Got hr %#x.\n", hr);
715 ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
716 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
717 ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n");
718 ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n");
720 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL,
721 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
722 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
723 ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
724 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
725 todo_wine ok(source.source2.pin.pin.peer == &transform.sink2.pin.pin.IPin_iface, "Got wrong connection.\n");
726 todo_wine ok(transform.source2.pin.pin.peer == &sink.sink2.pin.pin.IPin_iface, "Got wrong connection.\n");
728 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL,
729 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
730 todo_wine ok(hr == E_FAIL, "Got hr %#x.\n", hr);
732 todo_wine disconnect_pins(graph, &source.source2);
733 todo_wine disconnect_pins(graph, &transform.source2);
735 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL,
736 (IUnknown *)&transform.source2.pin.pin.IPin_iface, NULL, &sink.filter.IBaseFilter_iface);
737 ok(hr == S_OK, "Got hr %#x.\n", hr);
738 ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
739 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
740 ok(transform.source2.pin.pin.peer == &sink.sink2.pin.pin.IPin_iface, "Got wrong connection.\n");
741 ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n");
743 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL,
744 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
745 ok(hr == E_FAIL, "Got hr %#x.\n", hr);
747 disconnect_pins(graph, &transform.source2);
749 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL,
750 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &transform.filter.IBaseFilter_iface);
751 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
752 ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
753 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
754 todo_wine ok(source.source2.pin.pin.peer == &transform.sink2.pin.pin.IPin_iface, "Got wrong connection.\n");
756 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL,
757 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
758 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
759 ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
760 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
761 todo_wine ok(source.source2.pin.pin.peer == &transform.sink2.pin.pin.IPin_iface, "Got wrong connection.\n");
762 todo_wine ok(transform.source2.pin.pin.peer == &sink.sink2.pin.pin.IPin_iface, "Got wrong connection.\n");
763 todo_wine disconnect_pins(graph, &source.source2);
764 todo_wine disconnect_pins(graph, &transform.source2);
766 /* Test from a source pin. */
767 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL,
768 (IUnknown *)&source.source1.pin.pin.IPin_iface, NULL, &sink.filter.IBaseFilter_iface);
769 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
770 ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
771 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
772 todo_wine ok(transform.source2.pin.pin.peer == &sink.sink2.pin.pin.IPin_iface, "Got wrong connection.\n");
773 ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n");
774 todo_wine disconnect_pins(graph, &transform.source2);
776 /* Only the first eligible source is tried. */
777 source.source_type = bad_type;
778 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL,
779 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
780 ok(hr == VFW_E_CANNOT_CONNECT, "Got hr %#x.\n", hr);
781 source.source_type = source_type;
783 disconnect_pins(graph, &transform.source1);
784 disconnect_pins(graph, &source.source1);
786 /* Test intermediate filters. */
788 IGraphBuilder_AddFilter(graph, &identity.filter.IBaseFilter_iface, L"identity");
789 identity.source_type = source_type;
790 identity.sink_type = &source_type;
791 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL,
792 (IUnknown *)&source.filter.IBaseFilter_iface,
793 &identity.filter.IBaseFilter_iface, &sink.filter.IBaseFilter_iface);
794 ok(hr == S_OK, "Got hr %#x.\n", hr);
795 ok(source.source1.pin.pin.peer == &identity.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
796 ok(identity.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
797 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
798 disconnect_pins(graph, &source.source1);
799 disconnect_pins(graph, &identity.source1);
800 disconnect_pins(graph, &transform.source1);
802 identity.sink_type = &bad_type;
803 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL,
804 (IUnknown *)&source.filter.IBaseFilter_iface,
805 &identity.filter.IBaseFilter_iface, &sink.filter.IBaseFilter_iface);
806 todo_wine ok(hr == E_FAIL, "Got hr %#x.\n", hr);
807 ok(!source.source1.pin.pin.peer, "Pin should not be connected.\n");
808 ok(!identity.source1.pin.pin.peer, "Pin should not be connected.\n");
809 ok(!transform.source1.pin.pin.peer, "Pin should not be connected.\n");
811 identity.source_type = sink1_type;
812 identity.sink_type = &sink1_type;
813 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL,
814 (IUnknown *)&source.filter.IBaseFilter_iface,
815 &identity.filter.IBaseFilter_iface, &sink.filter.IBaseFilter_iface);
816 ok(hr == S_OK, "Got hr %#x.\n", hr);
817 ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
818 ok(transform.source1.pin.pin.peer == &identity.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
819 ok(identity.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
820 disconnect_pins(graph, &source.source1);
821 disconnect_pins(graph, &transform.source1);
822 disconnect_pins(graph, &identity.source1);
824 identity.source_type = bad_type;
825 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, NULL,
826 (IUnknown *)&source.filter.IBaseFilter_iface,
827 &identity.filter.IBaseFilter_iface, &sink.filter.IBaseFilter_iface);
828 ok(hr == VFW_E_CANNOT_CONNECT, "Got hr %#x.\n", hr);
829 ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
830 ok(transform.source1.pin.pin.peer == &identity.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
831 ok(!identity.source1.pin.pin.peer, "Pin should not be connected.\n");
832 disconnect_pins(graph, &source.source1);
833 disconnect_pins(graph, &transform.source1);
835 /* Test media types. */
837 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, &bad_type,
838 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
839 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
840 ok(!source.source1.pin.pin.peer, "Pin should not be connected.\n");
841 ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n");
842 ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n");
843 ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n");
845 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, &sink1_type,
846 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
847 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
848 ok(!source.source1.pin.pin.peer, "Pin should not be connected.\n");
849 ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n");
850 ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n");
851 ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n");
853 identity.source_type = sink1_type;
854 identity.sink_type = &sink1_type;
855 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, &sink1_type,
856 (IUnknown *)&source.filter.IBaseFilter_iface,
857 &identity.filter.IBaseFilter_iface, &sink.filter.IBaseFilter_iface);
858 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
859 ok(!source.source1.pin.pin.peer, "Pin should not be connected.\n");
860 ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n");
861 ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n");
862 ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n");
864 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, &source_type,
865 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
866 ok(hr == S_OK, "Got hr %#x.\n", hr);
867 ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
868 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
869 ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n");
870 ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n");
872 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, NULL, &sink1_type,
873 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
874 ok(hr == S_OK, "Got hr %#x.\n", hr);
875 ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
876 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
877 ok(transform.source2.pin.pin.peer == &sink.sink2.pin.pin.IPin_iface, "Got wrong connection.\n");
878 ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n");
880 disconnect_pins(graph, &source.source1);
881 disconnect_pins(graph, &transform.source1);
882 disconnect_pins(graph, &transform.source2);
884 /* Test categories. */
886 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL,
887 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
888 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
889 ok(!source.source1.pin.pin.peer, "Pin should not be connected.\n");
890 ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n");
891 ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n");
892 ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n");
894 source.source1.IKsPropertySet_iface.lpVtbl = &property_set_vtbl;
895 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL,
896 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
897 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
898 ok(!source.source1.pin.pin.peer, "Pin should not be connected.\n");
899 ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n");
900 ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n");
901 ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n");
903 source.source1.category = PIN_CATEGORY_CC;
904 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL,
905 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
906 ok(hr == S_OK, "Got hr %#x.\n", hr);
907 ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
908 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
909 ok(!source.source2.pin.pin.peer, "Pin should not be connected.\n");
910 ok(!sink.sink2.pin.pin.peer, "Pin should not be connected.\n");
912 disconnect_pins(graph, &transform.source1);
914 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL,
915 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
916 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
917 ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
918 ok(!transform.source1.pin.pin.peer, "Pin should not be connected.\n");
920 transform.source1.IKsPropertySet_iface.lpVtbl = &property_set_vtbl;
921 transform.source1.category = PIN_CATEGORY_CC;
922 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL,
923 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
924 todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
925 ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
926 todo_wine ok(!transform.source1.pin.pin.peer, "Pin should not be connected.\n");
927 todo_wine ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n");
929 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL,
930 (IUnknown *)&source.source1.pin.pin.IPin_iface, NULL, &sink.filter.IBaseFilter_iface);
931 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
933 disconnect_pins(graph, &source.source1);
935 /* Test the CAPTURE and PREVIEW categories. */
937 source.source1.IKsPropertySet_iface.lpVtbl = transform.source1.IKsPropertySet_iface.lpVtbl = NULL;
938 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
939 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
940 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
941 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL,
942 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
943 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
945 source.source1.IKsPropertySet_iface.lpVtbl = &property_set_vtbl;
946 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
947 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
948 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
949 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL,
950 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
951 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
953 source.source1.category = PIN_CATEGORY_PREVIEW;
954 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
955 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
956 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
957 ok(!source.source1.pin.pin.peer, "Pin should not be connected.\n");
958 todo_wine ok(!sink.sink1.pin.pin.peer, "Pin should not be connected.\n");
960 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL,
961 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
962 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
963 todo_wine ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
964 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
965 disconnect_pins(graph, &transform.source1);
967 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL,
968 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
969 todo_wine ok(hr == E_FAIL, "Got hr %#x.\n", hr);
970 todo_wine disconnect_pins(graph, &source.source1);
972 source.source1.category = PIN_CATEGORY_CAPTURE;
973 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
974 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
975 ok(hr == S_OK, "Got hr %#x.\n", hr);
976 check_smart_tee_pin(source.source1.pin.pin.peer, L"Input");
977 check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Capture");
978 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
980 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
981 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
982 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
984 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL,
985 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
986 ok(hr == VFW_S_NOPREVIEWPIN, "Got hr %#x.\n", hr);
987 check_smart_tee_pin(source.source1.pin.pin.peer, L"Input");
988 check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Capture");
989 check_smart_tee_pin(transform.sink2.pin.pin.peer, L"Preview");
990 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
991 ok(transform.source2.pin.pin.peer == &sink.sink2.pin.pin.IPin_iface, "Got wrong connection.\n");
993 disconnect_pins(graph, &source.source1);
994 IGraphBuilder_RemoveFilter(graph, &transform.filter.IBaseFilter_iface);
995 IGraphBuilder_AddFilter(graph, &transform.filter.IBaseFilter_iface, L"transform");
997 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CC, NULL,
998 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
999 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
1001 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL,
1002 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
1003 ok(hr == VFW_S_NOPREVIEWPIN, "Got hr %#x.\n", hr);
1004 check_smart_tee_pin(source.source1.pin.pin.peer, L"Input");
1005 check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Preview");
1006 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
1008 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL,
1009 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
1010 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
1012 disconnect_pins(graph, &source.source1);
1013 IGraphBuilder_RemoveFilter(graph, &transform.filter.IBaseFilter_iface);
1014 IGraphBuilder_AddFilter(graph, &transform.filter.IBaseFilter_iface, L"transform");
1016 /* Test from the pin. */
1018 source.source1.category = PIN_CATEGORY_CAPTURE;
1019 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
1020 (IUnknown *)&source.source1.pin.pin.IPin_iface, NULL, &sink.filter.IBaseFilter_iface);
1021 ok(hr == S_OK, "Got hr %#x.\n", hr);
1022 check_smart_tee_pin(source.source1.pin.pin.peer, L"Input");
1023 check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Capture");
1024 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
1025 disconnect_pins(graph, &source.source1);
1026 IGraphBuilder_RemoveFilter(graph, &transform.filter.IBaseFilter_iface);
1027 IGraphBuilder_AddFilter(graph, &transform.filter.IBaseFilter_iface, L"transform");
1029 /* Test when both CAPTURE and PREVIEW are available. */
1031 source.source2.IKsPropertySet_iface.lpVtbl = &property_set_vtbl;
1032 source.source2.category = PIN_CATEGORY_PREVIEW;
1034 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
1035 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
1036 ok(hr == S_OK, "Got hr %#x.\n", hr);
1037 ok(source.source1.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
1038 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
1039 disconnect_pins(graph, &source.source1);
1040 disconnect_pins(graph, &transform.source1);
1042 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_PREVIEW, NULL,
1043 (IUnknown *)&source.filter.IBaseFilter_iface, NULL, &sink.filter.IBaseFilter_iface);
1044 ok(hr == S_OK, "Got hr %#x.\n", hr);
1045 ok(source.source2.pin.pin.peer == &transform.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
1046 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
1047 disconnect_pins(graph, &source.source2);
1048 disconnect_pins(graph, &transform.source1);
1050 hr = ICaptureGraphBuilder2_RenderStream(capture_graph, &PIN_CATEGORY_CAPTURE, NULL,
1051 (IUnknown *)&source.source1.pin.pin.IPin_iface, NULL, &sink.filter.IBaseFilter_iface);
1052 ok(hr == S_OK, "Got hr %#x.\n", hr);
1053 check_smart_tee_pin(source.source1.pin.pin.peer, L"Input");
1054 check_smart_tee_pin(transform.sink1.pin.pin.peer, L"Capture");
1055 ok(transform.source1.pin.pin.peer == &sink.sink1.pin.pin.IPin_iface, "Got wrong connection.\n");
1056 disconnect_pins(graph, &source.source1);
1057 disconnect_pins(graph, &transform.source1);
1059 ref = ICaptureGraphBuilder2_Release(capture_graph);
1060 ok(!ref, "Got outstanding refcount %d.\n", ref);
1061 ref = IGraphBuilder_Release(graph);
1062 ok(!ref, "Got outstanding refcount %d.\n", ref);
1063 ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface);
1064 ok(!ref, "Got outstanding refcount %d.\n", ref);
1065 ref = IBaseFilter_Release(&transform.filter.IBaseFilter_iface);
1066 ok(!ref, "Got outstanding refcount %d.\n", ref);
1067 ref = IBaseFilter_Release(&sink.filter.IBaseFilter_iface);
1068 ok(!ref, "Got outstanding refcount %d.\n", ref);
1071 START_TEST(capturegraph)
1073 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1075 test_find_interface();
1076 test_find_pin();
1077 test_render_stream();
1079 CoUninitialize();