qcap/tests: Remove old tests for smart tee streaming.
[wine.git] / dlls / qcap / tests / smartteefilter.c
blobdf741ba12843ee7e73c3eee6493c26e2f62385f1
1 /*
2 * Smart tee filter unit tests
4 * Copyright 2015 Damjan Jovanovic
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
22 #include "dshow.h"
23 #include "wine/strmbase.h"
24 #include "wine/test.h"
26 static const WCHAR sink_id[] = {'I','n','p','u','t',0};
27 static const WCHAR capture_id[] = {'C','a','p','t','u','r','e',0};
28 static const WCHAR preview_id[] = {'P','r','e','v','i','e','w',0};
30 static HANDLE event;
32 static IBaseFilter *create_smart_tee(void)
34 IBaseFilter *filter = NULL;
35 HRESULT hr = CoCreateInstance(&CLSID_SmartTee, NULL, CLSCTX_INPROC_SERVER,
36 &IID_IBaseFilter, (void **)&filter);
37 ok(hr == S_OK, "Got hr %#x.\n", hr);
38 return filter;
41 static ULONG get_refcount(void *iface)
43 IUnknown *unknown = iface;
44 IUnknown_AddRef(unknown);
45 return IUnknown_Release(unknown);
48 static inline BOOL compare_media_types(const AM_MEDIA_TYPE *a, const AM_MEDIA_TYPE *b)
50 return !memcmp(a, b, offsetof(AM_MEDIA_TYPE, pbFormat))
51 && !memcmp(a->pbFormat, b->pbFormat, a->cbFormat);
54 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
55 static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
57 IUnknown *iface = iface_ptr;
58 HRESULT hr, expected_hr;
59 IUnknown *unk;
61 expected_hr = supported ? S_OK : E_NOINTERFACE;
63 hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
64 ok_(__FILE__, line)(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr);
65 if (SUCCEEDED(hr))
66 IUnknown_Release(unk);
69 static void test_interfaces(void)
71 IBaseFilter *filter = create_smart_tee();
72 ULONG ref;
73 IPin *pin;
75 check_interface(filter, &IID_IBaseFilter, TRUE);
76 check_interface(filter, &IID_IMediaFilter, TRUE);
77 check_interface(filter, &IID_IPersist, TRUE);
78 check_interface(filter, &IID_IUnknown, TRUE);
80 check_interface(filter, &IID_IAMFilterMiscFlags, FALSE);
81 check_interface(filter, &IID_IBasicAudio, FALSE);
82 check_interface(filter, &IID_IBasicVideo, FALSE);
83 check_interface(filter, &IID_IKsPropertySet, FALSE);
84 check_interface(filter, &IID_IMediaPosition, FALSE);
85 check_interface(filter, &IID_IMediaSeeking, FALSE);
86 check_interface(filter, &IID_IPersistPropertyBag, FALSE);
87 check_interface(filter, &IID_IPin, FALSE);
88 check_interface(filter, &IID_IQualityControl, FALSE);
89 check_interface(filter, &IID_IQualProp, FALSE);
90 check_interface(filter, &IID_IReferenceClock, FALSE);
91 check_interface(filter, &IID_IVideoWindow, FALSE);
93 IBaseFilter_FindPin(filter, sink_id, &pin);
95 check_interface(pin, &IID_IMemInputPin, TRUE);
96 check_interface(pin, &IID_IPin, TRUE);
97 todo_wine check_interface(pin, &IID_IQualityControl, TRUE);
98 check_interface(pin, &IID_IUnknown, TRUE);
100 check_interface(pin, &IID_IAMStreamConfig, FALSE);
101 check_interface(pin, &IID_IAMStreamControl, FALSE);
102 check_interface(pin, &IID_IKsPropertySet, FALSE);
103 check_interface(pin, &IID_IMediaPosition, FALSE);
104 check_interface(pin, &IID_IMediaSeeking, FALSE);
105 check_interface(pin, &IID_IPropertyBag, FALSE);
107 IPin_Release(pin);
109 IBaseFilter_FindPin(filter, capture_id, &pin);
111 todo_wine check_interface(pin, &IID_IAMStreamControl, TRUE);
112 check_interface(pin, &IID_IPin, TRUE);
113 todo_wine check_interface(pin, &IID_IQualityControl, TRUE);
114 check_interface(pin, &IID_IUnknown, TRUE);
116 check_interface(pin, &IID_IAMStreamConfig, FALSE);
117 check_interface(pin, &IID_IAsyncReader, FALSE);
118 check_interface(pin, &IID_IKsPropertySet, FALSE);
119 check_interface(pin, &IID_IMediaPosition, FALSE);
120 check_interface(pin, &IID_IMediaSeeking, FALSE);
121 check_interface(pin, &IID_IPropertyBag, FALSE);
123 IPin_Release(pin);
125 IBaseFilter_FindPin(filter, preview_id, &pin);
127 todo_wine check_interface(pin, &IID_IAMStreamControl, TRUE);
128 check_interface(pin, &IID_IPin, TRUE);
129 todo_wine check_interface(pin, &IID_IQualityControl, TRUE);
130 check_interface(pin, &IID_IUnknown, TRUE);
132 check_interface(pin, &IID_IAMStreamConfig, FALSE);
133 check_interface(pin, &IID_IAsyncReader, FALSE);
134 check_interface(pin, &IID_IKsPropertySet, FALSE);
135 check_interface(pin, &IID_IMediaPosition, FALSE);
136 check_interface(pin, &IID_IMediaSeeking, FALSE);
137 check_interface(pin, &IID_IPropertyBag, FALSE);
139 IPin_Release(pin);
141 ref = IBaseFilter_Release(filter);
142 ok(!ref, "Got unexpected refcount %d.\n", ref);
145 static const GUID test_iid = {0x33333333};
146 static LONG outer_ref = 1;
148 static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID iid, void **out)
150 if (IsEqualGUID(iid, &IID_IUnknown)
151 || IsEqualGUID(iid, &IID_IBaseFilter)
152 || IsEqualGUID(iid, &test_iid))
154 *out = (IUnknown *)0xdeadbeef;
155 return S_OK;
157 ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid));
158 return E_NOINTERFACE;
161 static ULONG WINAPI outer_AddRef(IUnknown *iface)
163 return InterlockedIncrement(&outer_ref);
166 static ULONG WINAPI outer_Release(IUnknown *iface)
168 return InterlockedDecrement(&outer_ref);
171 static const IUnknownVtbl outer_vtbl =
173 outer_QueryInterface,
174 outer_AddRef,
175 outer_Release,
178 static IUnknown test_outer = {&outer_vtbl};
180 static void test_aggregation(void)
182 IBaseFilter *filter, *filter2;
183 IUnknown *unk, *unk2;
184 HRESULT hr;
185 ULONG ref;
187 filter = (IBaseFilter *)0xdeadbeef;
188 hr = CoCreateInstance(&CLSID_SmartTee, &test_outer, CLSCTX_INPROC_SERVER,
189 &IID_IBaseFilter, (void **)&filter);
190 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
191 ok(!filter, "Got interface %p.\n", filter);
193 hr = CoCreateInstance(&CLSID_SmartTee, &test_outer, CLSCTX_INPROC_SERVER,
194 &IID_IUnknown, (void **)&unk);
195 ok(hr == S_OK, "Got hr %#x.\n", hr);
196 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
197 ok(unk != &test_outer, "Returned IUnknown should not be outer IUnknown.\n");
198 ref = get_refcount(unk);
199 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
201 ref = IUnknown_AddRef(unk);
202 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
203 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
205 ref = IUnknown_Release(unk);
206 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
207 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
209 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, (void **)&unk2);
210 ok(hr == S_OK, "Got hr %#x.\n", hr);
211 ok(unk2 == unk, "Got unexpected IUnknown %p.\n", unk2);
212 IUnknown_Release(unk2);
214 hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void **)&filter);
215 ok(hr == S_OK, "Got hr %#x.\n", hr);
217 hr = IBaseFilter_QueryInterface(filter, &IID_IUnknown, (void **)&unk2);
218 ok(hr == S_OK, "Got hr %#x.\n", hr);
219 ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
221 hr = IBaseFilter_QueryInterface(filter, &IID_IBaseFilter, (void **)&filter2);
222 ok(hr == S_OK, "Got hr %#x.\n", hr);
223 ok(filter2 == (IBaseFilter *)0xdeadbeef, "Got unexpected IBaseFilter %p.\n", filter2);
225 hr = IUnknown_QueryInterface(unk, &test_iid, (void **)&unk2);
226 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
227 ok(!unk2, "Got unexpected IUnknown %p.\n", unk2);
229 hr = IBaseFilter_QueryInterface(filter, &test_iid, (void **)&unk2);
230 ok(hr == S_OK, "Got hr %#x.\n", hr);
231 ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
233 IBaseFilter_Release(filter);
234 ref = IUnknown_Release(unk);
235 ok(!ref, "Got unexpected refcount %d.\n", ref);
236 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
239 static void test_enum_pins(void)
241 IBaseFilter *filter = create_smart_tee();
242 IEnumPins *enum1, *enum2;
243 ULONG count, ref;
244 IPin *pins[4];
245 HRESULT hr;
247 ref = get_refcount(filter);
248 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
250 hr = IBaseFilter_EnumPins(filter, NULL);
251 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
253 hr = IBaseFilter_EnumPins(filter, &enum1);
254 ok(hr == S_OK, "Got hr %#x.\n", hr);
255 ref = get_refcount(filter);
256 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
257 ref = get_refcount(enum1);
258 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
260 hr = IEnumPins_Next(enum1, 1, NULL, NULL);
261 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
263 hr = IEnumPins_Next(enum1, 1, pins, NULL);
264 ok(hr == S_OK, "Got hr %#x.\n", hr);
265 ref = get_refcount(filter);
266 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
267 ref = get_refcount(pins[0]);
268 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
269 ref = get_refcount(enum1);
270 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
271 IPin_Release(pins[0]);
272 ref = get_refcount(filter);
273 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
275 hr = IEnumPins_Next(enum1, 1, pins, NULL);
276 ok(hr == S_OK, "Got hr %#x.\n", hr);
277 ref = get_refcount(filter);
278 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
279 ref = get_refcount(pins[0]);
280 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
281 ref = get_refcount(enum1);
282 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
283 IPin_Release(pins[0]);
284 ref = get_refcount(filter);
285 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
287 hr = IEnumPins_Next(enum1, 1, pins, NULL);
288 ok(hr == S_OK, "Got hr %#x.\n", hr);
289 ref = get_refcount(filter);
290 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
291 ref = get_refcount(pins[0]);
292 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
293 ref = get_refcount(enum1);
294 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
295 IPin_Release(pins[0]);
296 ref = get_refcount(filter);
297 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
299 hr = IEnumPins_Next(enum1, 1, pins, NULL);
300 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
302 hr = IEnumPins_Reset(enum1);
303 ok(hr == S_OK, "Got hr %#x.\n", hr);
305 hr = IEnumPins_Next(enum1, 1, pins, &count);
306 ok(hr == S_OK, "Got hr %#x.\n", hr);
307 ok(count == 1, "Got count %u.\n", count);
308 IPin_Release(pins[0]);
310 hr = IEnumPins_Next(enum1, 1, pins, &count);
311 ok(hr == S_OK, "Got hr %#x.\n", hr);
312 ok(count == 1, "Got count %u.\n", count);
313 IPin_Release(pins[0]);
315 hr = IEnumPins_Next(enum1, 1, pins, &count);
316 ok(hr == S_OK, "Got hr %#x.\n", hr);
317 ok(count == 1, "Got count %u.\n", count);
318 IPin_Release(pins[0]);
320 hr = IEnumPins_Next(enum1, 1, pins, &count);
321 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
322 ok(!count, "Got count %u.\n", count);
324 hr = IEnumPins_Reset(enum1);
325 ok(hr == S_OK, "Got hr %#x.\n", hr);
327 hr = IEnumPins_Next(enum1, 2, pins, NULL);
328 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
330 hr = IEnumPins_Next(enum1, 2, pins, &count);
331 ok(hr == S_OK, "Got hr %#x.\n", hr);
332 ok(count == 2, "Got count %u.\n", count);
333 IPin_Release(pins[0]);
334 IPin_Release(pins[1]);
336 hr = IEnumPins_Next(enum1, 2, pins, &count);
337 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
338 ok(count == 1, "Got count %u.\n", count);
339 IPin_Release(pins[0]);
341 hr = IEnumPins_Reset(enum1);
342 ok(hr == S_OK, "Got hr %#x.\n", hr);
344 hr = IEnumPins_Next(enum1, 4, pins, &count);
345 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
346 ok(count == 3, "Got count %u.\n", count);
347 IPin_Release(pins[0]);
348 IPin_Release(pins[1]);
349 IPin_Release(pins[2]);
351 hr = IEnumPins_Reset(enum1);
352 ok(hr == S_OK, "Got hr %#x.\n", hr);
354 hr = IEnumPins_Clone(enum1, &enum2);
355 ok(hr == S_OK, "Got hr %#x.\n", hr);
357 hr = IEnumPins_Skip(enum1, 4);
358 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
360 hr = IEnumPins_Skip(enum1, 3);
361 ok(hr == S_OK, "Got hr %#x.\n", hr);
363 hr = IEnumPins_Skip(enum1, 1);
364 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
366 hr = IEnumPins_Next(enum1, 1, pins, NULL);
367 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
369 hr = IEnumPins_Next(enum2, 1, pins, NULL);
370 ok(hr == S_OK, "Got hr %#x.\n", hr);
371 IPin_Release(pins[0]);
373 IEnumPins_Release(enum2);
374 IEnumPins_Release(enum1);
375 ref = IBaseFilter_Release(filter);
376 ok(!ref, "Got outstanding refcount %d.\n", ref);
379 static void test_find_pin(void)
381 IBaseFilter *filter = create_smart_tee();
382 IEnumPins *enum_pins;
383 IPin *pin, *pin2;
384 HRESULT hr;
385 ULONG ref;
387 hr = IBaseFilter_EnumPins(filter, &enum_pins);
388 ok(hr == S_OK, "Got hr %#x.\n", hr);
390 hr = IBaseFilter_FindPin(filter, sink_id, &pin);
391 ok(hr == S_OK, "Got hr %#x.\n", hr);
392 hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL);
393 ok(hr == S_OK, "Got hr %#x.\n", hr);
394 ok(pin2 == pin, "Expected pin %p, got %p.\n", pin, pin2);
395 IPin_Release(pin2);
396 IPin_Release(pin);
398 hr = IBaseFilter_FindPin(filter, capture_id, &pin);
399 ok(hr == S_OK, "Got hr %#x.\n", hr);
400 hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL);
401 ok(hr == S_OK, "Got hr %#x.\n", hr);
402 ok(pin2 == pin, "Expected pin %p, got %p.\n", pin, pin2);
403 IPin_Release(pin2);
404 IPin_Release(pin);
406 hr = IBaseFilter_FindPin(filter, preview_id, &pin);
407 ok(hr == S_OK, "Got hr %#x.\n", hr);
408 hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL);
409 ok(hr == S_OK, "Got hr %#x.\n", hr);
410 ok(pin2 == pin, "Expected pin %p, got %p.\n", pin, pin2);
411 IPin_Release(pin2);
412 IPin_Release(pin);
414 IEnumPins_Release(enum_pins);
415 ref = IBaseFilter_Release(filter);
416 ok(!ref, "Got outstanding refcount %d.\n", ref);
419 static void test_pin_info(void)
421 IBaseFilter *filter = create_smart_tee();
422 PIN_DIRECTION dir;
423 PIN_INFO info;
424 ULONG count;
425 HRESULT hr;
426 WCHAR *id;
427 ULONG ref;
428 IPin *pin;
430 hr = IBaseFilter_FindPin(filter, sink_id, &pin);
431 ok(hr == S_OK, "Got hr %#x.\n", hr);
432 ref = get_refcount(filter);
433 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
434 ref = get_refcount(pin);
435 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
437 hr = IPin_QueryPinInfo(pin, &info);
438 ok(hr == S_OK, "Got hr %#x.\n", hr);
439 ok(info.pFilter == filter, "Expected filter %p, got %p.\n", filter, info.pFilter);
440 ok(info.dir == PINDIR_INPUT, "Got direction %d.\n", info.dir);
441 ok(!lstrcmpW(info.achName, sink_id), "Got name %s.\n", wine_dbgstr_w(info.achName));
442 ref = get_refcount(filter);
443 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
444 ref = get_refcount(pin);
445 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
446 IBaseFilter_Release(info.pFilter);
448 hr = IPin_QueryDirection(pin, &dir);
449 ok(hr == S_OK, "Got hr %#x.\n", hr);
450 ok(dir == PINDIR_INPUT, "Got direction %d.\n", dir);
452 hr = IPin_QueryId(pin, &id);
453 ok(hr == S_OK, "Got hr %#x.\n", hr);
454 ok(!lstrcmpW(id, sink_id), "Got id %s.\n", wine_dbgstr_w(id));
455 CoTaskMemFree(id);
457 hr = IPin_QueryInternalConnections(pin, NULL, &count);
458 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
460 IPin_Release(pin);
462 hr = IBaseFilter_FindPin(filter, capture_id, &pin);
463 ok(hr == S_OK, "Got hr %#x.\n", hr);
465 hr = IPin_QueryPinInfo(pin, &info);
466 ok(hr == S_OK, "Got hr %#x.\n", hr);
467 ok(info.pFilter == filter, "Expected filter %p, got %p.\n", filter, info.pFilter);
468 ok(info.dir == PINDIR_OUTPUT, "Got direction %d.\n", info.dir);
469 ok(!lstrcmpW(info.achName, capture_id), "Got name %s.\n", wine_dbgstr_w(info.achName));
470 ref = get_refcount(filter);
471 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
472 ref = get_refcount(pin);
473 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
474 IBaseFilter_Release(info.pFilter);
476 hr = IPin_QueryDirection(pin, &dir);
477 ok(hr == S_OK, "Got hr %#x.\n", hr);
478 ok(dir == PINDIR_OUTPUT, "Got direction %d.\n", dir);
480 hr = IPin_QueryId(pin, &id);
481 ok(hr == S_OK, "Got hr %#x.\n", hr);
482 ok(!lstrcmpW(id, capture_id), "Got id %s.\n", wine_dbgstr_w(id));
483 CoTaskMemFree(id);
485 hr = IPin_QueryInternalConnections(pin, NULL, &count);
486 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
488 IPin_Release(pin);
490 hr = IBaseFilter_FindPin(filter, preview_id, &pin);
491 ok(hr == S_OK, "Got hr %#x.\n", hr);
493 hr = IPin_QueryPinInfo(pin, &info);
494 ok(hr == S_OK, "Got hr %#x.\n", hr);
495 ok(info.pFilter == filter, "Expected filter %p, got %p.\n", filter, info.pFilter);
496 ok(info.dir == PINDIR_OUTPUT, "Got direction %d.\n", info.dir);
497 ok(!lstrcmpW(info.achName, preview_id), "Got name %s.\n", wine_dbgstr_w(info.achName));
498 ref = get_refcount(filter);
499 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
500 ref = get_refcount(pin);
501 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
502 IBaseFilter_Release(info.pFilter);
504 hr = IPin_QueryDirection(pin, &dir);
505 ok(hr == S_OK, "Got hr %#x.\n", hr);
506 ok(dir == PINDIR_OUTPUT, "Got direction %d.\n", dir);
508 hr = IPin_QueryId(pin, &id);
509 ok(hr == S_OK, "Got hr %#x.\n", hr);
510 ok(!lstrcmpW(id, preview_id), "Got id %s.\n", wine_dbgstr_w(id));
511 CoTaskMemFree(id);
513 hr = IPin_QueryInternalConnections(pin, NULL, &count);
514 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
516 IPin_Release(pin);
518 ref = IBaseFilter_Release(filter);
519 ok(!ref, "Got outstanding refcount %d.\n", ref);
522 static void test_enum_media_types(void)
524 IBaseFilter *filter = create_smart_tee();
525 IEnumMediaTypes *enum1, *enum2;
526 AM_MEDIA_TYPE *mts[2];
527 ULONG ref, count;
528 HRESULT hr;
529 IPin *pin;
531 IBaseFilter_FindPin(filter, sink_id, &pin);
533 hr = IPin_EnumMediaTypes(pin, &enum1);
534 ok(hr == S_OK, "Got hr %#x.\n", hr);
536 hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL);
537 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
539 hr = IEnumMediaTypes_Next(enum1, 1, mts, &count);
540 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
541 ok(!count, "Got count %u.\n", count);
543 hr = IEnumMediaTypes_Reset(enum1);
544 ok(hr == S_OK, "Got hr %#x.\n", hr);
546 hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL);
547 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
549 hr = IEnumMediaTypes_Clone(enum1, &enum2);
550 ok(hr == S_OK, "Got hr %#x.\n", hr);
552 hr = IEnumMediaTypes_Skip(enum1, 1);
553 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
555 hr = IEnumMediaTypes_Next(enum2, 1, mts, NULL);
556 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
558 IEnumMediaTypes_Release(enum1);
559 IEnumMediaTypes_Release(enum2);
560 IPin_Release(pin);
562 ref = IBaseFilter_Release(filter);
563 ok(!ref, "Got outstanding refcount %d.\n", ref);
566 static void test_unconnected_filter_state(void)
568 IBaseFilter *filter = create_smart_tee();
569 FILTER_STATE state;
570 HRESULT hr;
571 ULONG ref;
573 hr = IBaseFilter_GetState(filter, 0, &state);
574 ok(hr == S_OK, "Got hr %#x.\n", hr);
575 ok(state == State_Stopped, "Got state %u.\n", state);
577 hr = IBaseFilter_Pause(filter);
578 ok(hr == S_OK, "Got hr %#x.\n", hr);
580 hr = IBaseFilter_GetState(filter, 0, &state);
581 ok(hr == VFW_S_CANT_CUE, "Got hr %#x.\n", hr);
582 ok(state == State_Paused, "Got state %u.\n", state);
584 hr = IBaseFilter_Run(filter, 0);
585 ok(hr == S_OK, "Got hr %#x.\n", hr);
587 hr = IBaseFilter_GetState(filter, 0, &state);
588 ok(hr == S_OK, "Got hr %#x.\n", hr);
589 ok(state == State_Running, "Got state %u.\n", state);
591 hr = IBaseFilter_Pause(filter);
592 ok(hr == S_OK, "Got hr %#x.\n", hr);
594 hr = IBaseFilter_GetState(filter, 0, &state);
595 ok(hr == VFW_S_CANT_CUE, "Got hr %#x.\n", hr);
596 ok(state == State_Paused, "Got state %u.\n", state);
598 hr = IBaseFilter_Stop(filter);
599 ok(hr == S_OK, "Got hr %#x.\n", hr);
601 hr = IBaseFilter_GetState(filter, 0, &state);
602 ok(hr == S_OK, "Got hr %#x.\n", hr);
603 ok(state == State_Stopped, "Got state %u.\n", state);
605 hr = IBaseFilter_Run(filter, 0);
606 ok(hr == S_OK, "Got hr %#x.\n", hr);
608 hr = IBaseFilter_GetState(filter, 0, &state);
609 ok(hr == S_OK, "Got hr %#x.\n", hr);
610 ok(state == State_Running, "Got state %u.\n", state);
612 hr = IBaseFilter_Stop(filter);
613 ok(hr == S_OK, "Got hr %#x.\n", hr);
615 hr = IBaseFilter_GetState(filter, 0, &state);
616 ok(hr == S_OK, "Got hr %#x.\n", hr);
617 ok(state == State_Stopped, "Got state %u.\n", state);
619 ref = IBaseFilter_Release(filter);
620 ok(!ref, "Got outstanding refcount %d.\n", ref);
623 struct testfilter
625 struct strmbase_filter filter;
626 struct strmbase_source source;
627 struct strmbase_sink sink;
628 const AM_MEDIA_TYPE *sink_mt;
629 AM_MEDIA_TYPE source_mt;
630 HANDLE sample_event, eos_event, segment_event;
631 BOOL preview;
632 unsigned int got_begin_flush, got_end_flush;
635 static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface)
637 return CONTAINING_RECORD(iface, struct testfilter, filter);
640 static struct strmbase_pin *testfilter_get_pin(struct strmbase_filter *iface, unsigned int index)
642 struct testfilter *filter = impl_from_strmbase_filter(iface);
643 if (!index)
644 return &filter->source.pin;
645 else if (index == 1)
646 return &filter->sink.pin;
647 return NULL;
650 static void testfilter_destroy(struct strmbase_filter *iface)
652 struct testfilter *filter = impl_from_strmbase_filter(iface);
653 CloseHandle(filter->sample_event);
654 CloseHandle(filter->eos_event);
655 CloseHandle(filter->segment_event);
656 strmbase_source_cleanup(&filter->source);
657 strmbase_sink_cleanup(&filter->sink);
658 strmbase_filter_cleanup(&filter->filter);
661 static const struct strmbase_filter_ops testfilter_ops =
663 .filter_get_pin = testfilter_get_pin,
664 .filter_destroy = testfilter_destroy,
667 static HRESULT testsource_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
669 return mt->bTemporalCompression ? S_OK : S_FALSE;
672 static HRESULT testsource_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *mt)
674 struct testfilter *filter = impl_from_strmbase_filter(iface->filter);
675 if (!index)
677 CopyMediaType(mt, &filter->source_mt);
678 return S_OK;
680 return VFW_S_NO_MORE_ITEMS;
683 static void test_sink_allocator(IPin *pin)
685 /* FIXME: We shouldn't need more than one sample, but Wine currently uses
686 * the same allocator for all three pins. */
687 ALLOCATOR_PROPERTIES req_props = {3, 256, 1, 0}, ret_props;
688 IMemAllocator *req_allocator, *ret_allocator;
689 IMemInputPin *input;
690 HRESULT hr;
692 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
694 hr = IMemInputPin_GetAllocatorRequirements(input, &ret_props);
695 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
697 hr = IMemInputPin_GetAllocator(input, &ret_allocator);
698 ok(hr == S_OK, "Got hr %#x.\n", hr);
700 hr = IMemInputPin_NotifyAllocator(input, ret_allocator, TRUE);
701 ok(hr == S_OK, "Got hr %#x.\n", hr);
702 IMemAllocator_Release(ret_allocator);
704 CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
705 &IID_IMemAllocator, (void **)&req_allocator);
707 hr = IMemInputPin_NotifyAllocator(input, req_allocator, TRUE);
708 ok(hr == S_OK, "Got hr %#x.\n", hr);
710 hr = IMemInputPin_GetAllocator(input, &ret_allocator);
711 ok(hr == S_OK, "Got hr %#x.\n", hr);
712 ok(ret_allocator == req_allocator, "Allocators didn't match.\n");
713 ok(hr == S_OK, "Got hr %#x.\n", hr);
714 IMemAllocator_Release(ret_allocator);
716 hr = IMemAllocator_SetProperties(req_allocator, &req_props, &ret_props);
717 ok(hr == S_OK, "Got hr %#x.\n", hr);
719 IMemAllocator_Release(req_allocator);
720 IMemInputPin_Release(input);
723 static HRESULT WINAPI testsource_AttemptConnection(struct strmbase_source *iface,
724 IPin *peer, const AM_MEDIA_TYPE *mt)
726 HRESULT hr;
728 iface->pin.peer = peer;
729 IPin_AddRef(peer);
730 CopyMediaType(&iface->pin.mt, mt);
732 if (FAILED(hr = IPin_ReceiveConnection(peer, &iface->pin.IPin_iface, mt)))
734 ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr);
735 IPin_Release(peer);
736 iface->pin.peer = NULL;
737 FreeMediaType(&iface->pin.mt);
740 test_sink_allocator(peer);
742 return hr;
745 static const struct strmbase_source_ops testsource_ops =
747 .base.pin_query_accept = testsource_query_accept,
748 .base.pin_get_media_type = testsource_get_media_type,
749 .pfnAttemptConnection = testsource_AttemptConnection,
752 static HRESULT testsink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
754 struct testfilter *filter = impl_from_strmbase_filter(iface->filter);
756 if (IsEqualGUID(iid, &IID_IMemInputPin))
757 *out = &filter->sink.IMemInputPin_iface;
758 else
759 return E_NOINTERFACE;
761 IUnknown_AddRef((IUnknown *)*out);
762 return S_OK;
765 static HRESULT testsink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
767 struct testfilter *filter = impl_from_strmbase_filter(iface->filter);
768 if (filter->sink_mt && !compare_media_types(mt, filter->sink_mt))
769 return S_FALSE;
770 return S_OK;
773 static HRESULT testsink_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *mt)
775 struct testfilter *filter = impl_from_strmbase_filter(iface->filter);
776 if (!index && filter->sink_mt)
778 CopyMediaType(mt, filter->sink_mt);
779 return S_OK;
781 return VFW_S_NO_MORE_ITEMS;
784 static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample *sample)
786 struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter);
787 REFERENCE_TIME start, stop;
788 BYTE *data, expect[200];
789 LONG size, i;
790 HRESULT hr;
792 size = IMediaSample_GetSize(sample);
793 ok(size == 256, "Got size %u.\n", size);
794 size = IMediaSample_GetActualDataLength(sample);
795 ok(size == 200, "Got valid size %u.\n", size);
797 hr = IMediaSample_GetPointer(sample, &data);
798 ok(hr == S_OK, "Got hr %#x.\n", hr);
799 for (i = 0; i < size; ++i)
800 expect[i] = i;
801 ok(!memcmp(data, expect, size), "Data didn't match.\n");
803 hr = IMediaSample_GetTime(sample, &start, &stop);
804 if (filter->preview)
806 ok(hr == VFW_E_SAMPLE_TIME_NOT_SET, "Got hr %#x.\n", hr);
808 else
810 ok(hr == S_OK, "Got hr %#x.\n", hr);
811 ok(start == 30000, "Got start time %s.\n", wine_dbgstr_longlong(start));
812 ok(stop == 40000, "Got stop time %s.\n", wine_dbgstr_longlong(stop));
815 hr = IMediaSample_GetMediaTime(sample, &start, &stop);
816 if (filter->preview)
818 todo_wine ok(hr == VFW_E_MEDIA_TIME_NOT_SET, "Got hr %#x.\n", hr);
820 else
822 ok(hr == S_OK, "Got hr %#x.\n", hr);
823 ok(start == 10000, "Got start time %s.\n", wine_dbgstr_longlong(start));
824 ok(stop == 20000, "Got stop time %s.\n", wine_dbgstr_longlong(stop));
827 hr = IMediaSample_IsDiscontinuity(sample);
828 todo_wine_if (filter->preview) ok(hr == filter->preview ? S_FALSE : S_OK, "Got hr %#x.\n", hr);
829 hr = IMediaSample_IsPreroll(sample);
830 ok(hr == S_OK, "Got hr %#x.\n", hr);
831 hr = IMediaSample_IsSyncPoint(sample);
832 ok(hr == S_OK, "Got hr %#x.\n", hr);
834 SetEvent(filter->sample_event);
836 return S_OK;
839 static HRESULT testsink_new_segment(struct strmbase_sink *iface,
840 REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
842 struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter);
843 ok(start == 10000, "Got start %s.\n", wine_dbgstr_longlong(start));
844 ok(stop == 20000, "Got stop %s.\n", wine_dbgstr_longlong(stop));
845 ok(rate == 1.0, "Got rate %.16e.\n", rate);
846 SetEvent(filter->segment_event);
847 return S_OK;
850 static HRESULT testsink_eos(struct strmbase_sink *iface)
852 struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter);
853 SetEvent(filter->eos_event);
854 return S_OK;
857 static HRESULT testsink_begin_flush(struct strmbase_sink *iface)
859 struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter);
860 ++filter->got_begin_flush;
861 return S_OK;
864 static HRESULT testsink_end_flush(struct strmbase_sink *iface)
866 struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter);
867 ++filter->got_end_flush;
868 return S_OK;
871 static const struct strmbase_sink_ops testsink_ops =
873 .base.pin_query_interface = testsink_query_interface,
874 .base.pin_query_accept = testsink_query_accept,
875 .base.pin_get_media_type = testsink_get_media_type,
876 .pfnReceive = testsink_Receive,
877 .sink_new_segment = testsink_new_segment,
878 .sink_eos = testsink_eos,
879 .sink_begin_flush = testsink_begin_flush,
880 .sink_end_flush = testsink_end_flush,
883 static void testfilter_init(struct testfilter *filter)
885 static const GUID clsid = {0xabacab};
886 memset(filter, 0, sizeof(*filter));
887 strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops);
888 strmbase_source_init(&filter->source, &filter->filter, L"source", &testsource_ops);
889 strmbase_sink_init(&filter->sink, &filter->filter, L"sink", &testsink_ops, NULL);
890 filter->sample_event = CreateEventW(NULL, FALSE, FALSE, NULL);
891 filter->segment_event = CreateEventW(NULL, FALSE, FALSE, NULL);
892 filter->eos_event = CreateEventW(NULL, FALSE, FALSE, NULL);
895 static void test_source_media_types(AM_MEDIA_TYPE req_mt, const AM_MEDIA_TYPE *source_mt, IPin *source)
897 IEnumMediaTypes *enummt;
898 AM_MEDIA_TYPE *mts[3];
899 ULONG count;
900 HRESULT hr;
902 hr = IPin_EnumMediaTypes(source, &enummt);
903 ok(hr == S_OK, "Got hr %#x.\n", hr);
904 hr = IEnumMediaTypes_Next(enummt, 3, mts, &count);
905 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
906 todo_wine ok(count == 2, "Got %u types.\n", count);
907 ok(compare_media_types(mts[0], &req_mt), "Media types didn't match.\n");
908 if (count > 1)
909 ok(compare_media_types(mts[1], source_mt), "Media types didn't match.\n");
910 CoTaskMemFree(mts[0]);
911 if (count > 1)
912 CoTaskMemFree(mts[1]);
913 IEnumMediaTypes_Release(enummt);
915 hr = IPin_QueryAccept(source, &req_mt);
916 ok(hr == S_OK, "Got hr %#x.\n", hr);
918 req_mt.lSampleSize = 2;
919 req_mt.bFixedSizeSamples = TRUE;
920 hr = IPin_QueryAccept(source, &req_mt);
921 ok(hr == S_OK, "Got hr %#x.\n", hr);
923 req_mt.cbFormat = sizeof(count);
924 req_mt.pbFormat = (BYTE *)&count;
925 hr = IPin_QueryAccept(source, &req_mt);
926 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
927 req_mt.cbFormat = 0;
928 req_mt.pbFormat = NULL;
930 req_mt.majortype = MEDIATYPE_Audio;
931 hr = IPin_QueryAccept(source, &req_mt);
932 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
933 req_mt.majortype = GUID_NULL;
934 hr = IPin_QueryAccept(source, &req_mt);
935 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
936 req_mt.majortype = MEDIATYPE_Stream;
938 req_mt.subtype = MEDIASUBTYPE_PCM;
939 hr = IPin_QueryAccept(source, &req_mt);
940 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
941 req_mt.subtype = GUID_NULL;
942 hr = IPin_QueryAccept(source, &req_mt);
943 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
944 req_mt.subtype = MEDIASUBTYPE_Avi;
946 req_mt.formattype = FORMAT_WaveFormatEx;
947 hr = IPin_QueryAccept(source, &req_mt);
948 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
949 req_mt.formattype = GUID_NULL;
950 hr = IPin_QueryAccept(source, &req_mt);
951 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
952 req_mt.formattype = FORMAT_None;
954 req_mt.majortype = MEDIATYPE_Audio;
955 req_mt.subtype = MEDIASUBTYPE_PCM;
956 req_mt.formattype = test_iid;
957 req_mt.cbFormat = sizeof(count);
958 req_mt.pbFormat = (BYTE *)&count;
959 req_mt.bTemporalCompression = TRUE;
960 hr = IPin_QueryAccept(source, &req_mt);
961 ok(hr == S_OK, "Got hr %#x.\n", hr);
964 static void test_source_connection(AM_MEDIA_TYPE req_mt, IFilterGraph2 *graph,
965 IMediaControl *control, struct testfilter *testsink, IPin *source)
967 const AM_MEDIA_TYPE sink_mt = req_mt;
968 AM_MEDIA_TYPE mt;
969 HRESULT hr;
970 IPin *peer;
972 peer = (IPin *)0xdeadbeef;
973 hr = IPin_ConnectedTo(source, &peer);
974 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
975 ok(!peer, "Got peer %p.\n", peer);
977 hr = IPin_ConnectionMediaType(source, &mt);
978 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
980 /* Exact connection. */
982 hr = IMediaControl_Pause(control);
983 ok(hr == S_OK, "Got hr %#x.\n", hr);
984 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt);
985 ok(hr == VFW_E_NOT_STOPPED, "Got hr %#x.\n", hr);
986 hr = IMediaControl_Stop(control);
987 ok(hr == S_OK, "Got hr %#x.\n", hr);
989 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt);
990 ok(hr == S_OK, "Got hr %#x.\n", hr);
992 hr = IPin_ConnectedTo(source, &peer);
993 ok(hr == S_OK, "Got hr %#x.\n", hr);
994 ok(peer == &testsink->sink.pin.IPin_iface, "Got peer %p.\n", peer);
995 IPin_Release(peer);
997 hr = IPin_ConnectionMediaType(source, &mt);
998 ok(hr == S_OK, "Got hr %#x.\n", hr);
999 ok(compare_media_types(&mt, &req_mt), "Media types didn't match.\n");
1000 ok(compare_media_types(&testsink->sink.pin.mt, &req_mt), "Media types didn't match.\n");
1002 hr = IMediaControl_Pause(control);
1003 ok(hr == S_OK, "Got hr %#x.\n", hr);
1004 hr = IFilterGraph2_Disconnect(graph, source);
1005 ok(hr == VFW_E_NOT_STOPPED, "Got hr %#x.\n", hr);
1006 hr = IMediaControl_Stop(control);
1007 ok(hr == S_OK, "Got hr %#x.\n", hr);
1009 hr = IFilterGraph2_Disconnect(graph, source);
1010 ok(hr == S_OK, "Got hr %#x.\n", hr);
1011 hr = IFilterGraph2_Disconnect(graph, source);
1012 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1013 ok(testsink->sink.pin.peer == source, "Got peer %p.\n", testsink->sink.pin.peer);
1014 IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface);
1016 req_mt.subtype = GUID_NULL;
1017 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt);
1018 todo_wine ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr);
1019 if (hr == S_OK)
1021 IFilterGraph2_Disconnect(graph, source);
1022 IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface);
1024 req_mt.subtype = sink_mt.subtype;
1026 req_mt.majortype = MEDIATYPE_Audio;
1027 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt);
1028 todo_wine ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr);
1029 if (hr == S_OK)
1031 IFilterGraph2_Disconnect(graph, source);
1032 IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface);
1035 /* Connection with wildcards. */
1037 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, NULL);
1038 ok(hr == S_OK, "Got hr %#x.\n", hr);
1039 ok(compare_media_types(&testsink->sink.pin.mt, &sink_mt), "Media types didn't match.\n");
1040 IFilterGraph2_Disconnect(graph, source);
1041 IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface);
1043 req_mt.majortype = GUID_NULL;
1044 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt);
1045 ok(hr == S_OK, "Got hr %#x.\n", hr);
1046 ok(compare_media_types(&testsink->sink.pin.mt, &sink_mt), "Media types didn't match.\n");
1047 IFilterGraph2_Disconnect(graph, source);
1048 IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface);
1050 req_mt.subtype = MEDIASUBTYPE_RGB32;
1051 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt);
1052 ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr);
1054 req_mt.subtype = GUID_NULL;
1055 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt);
1056 ok(hr == S_OK, "Got hr %#x.\n", hr);
1057 ok(compare_media_types(&testsink->sink.pin.mt, &sink_mt), "Media types didn't match.\n");
1058 IFilterGraph2_Disconnect(graph, source);
1059 IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface);
1061 req_mt.formattype = FORMAT_WaveFormatEx;
1062 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt);
1063 ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr);
1065 req_mt = sink_mt;
1066 req_mt.formattype = GUID_NULL;
1067 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt);
1068 ok(hr == S_OK, "Got hr %#x.\n", hr);
1069 ok(compare_media_types(&testsink->sink.pin.mt, &sink_mt), "Media types didn't match.\n");
1070 IFilterGraph2_Disconnect(graph, source);
1071 IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface);
1073 req_mt.subtype = MEDIASUBTYPE_RGB32;
1074 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt);
1075 ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr);
1077 req_mt.subtype = GUID_NULL;
1078 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt);
1079 ok(hr == S_OK, "Got hr %#x.\n", hr);
1080 ok(compare_media_types(&testsink->sink.pin.mt, &sink_mt), "Media types didn't match.\n");
1081 IFilterGraph2_Disconnect(graph, source);
1082 IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface);
1084 req_mt.majortype = MEDIATYPE_Audio;
1085 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &req_mt);
1086 ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr);
1088 testsink->sink_mt = &req_mt;
1089 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, NULL);
1090 todo_wine ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr);
1091 if (hr == S_OK)
1093 IFilterGraph2_Disconnect(graph, source);
1094 IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface);
1097 req_mt = sink_mt;
1098 req_mt.lSampleSize = 3;
1099 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, NULL);
1100 ok(hr == S_OK, "Got hr %#x.\n", hr);
1101 ok(compare_media_types(&testsink->sink.pin.mt, &req_mt), "Media types didn't match.\n");
1102 IFilterGraph2_Disconnect(graph, source);
1103 IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface);
1105 testsink->sink_mt = NULL;
1108 static void test_connect_pin(void)
1110 AM_MEDIA_TYPE req_mt =
1112 .majortype = MEDIATYPE_Stream,
1113 .subtype = MEDIASUBTYPE_Avi,
1114 .formattype = FORMAT_None,
1115 .lSampleSize = 1,
1117 IBaseFilter *filter = create_smart_tee();
1118 struct testfilter testsource, testsink;
1119 IPin *sink, *capture, *preview, *peer;
1120 AM_MEDIA_TYPE mt, *mts[3];
1121 IEnumMediaTypes *enummt;
1122 IMediaControl *control;
1123 IFilterGraph2 *graph;
1124 HRESULT hr;
1125 ULONG ref;
1127 testfilter_init(&testsource);
1128 testfilter_init(&testsink);
1129 CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
1130 &IID_IFilterGraph2, (void **)&graph);
1131 IFilterGraph2_AddFilter(graph, &testsource.filter.IBaseFilter_iface, L"source");
1132 IFilterGraph2_AddFilter(graph, &testsink.filter.IBaseFilter_iface, L"sink");
1133 IFilterGraph2_AddFilter(graph, filter, L"sample grabber");
1134 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
1135 IBaseFilter_FindPin(filter, L"Input", &sink);
1136 IBaseFilter_FindPin(filter, L"Capture", &capture);
1137 IBaseFilter_FindPin(filter, L"Preview", &preview);
1139 testsource.source_mt.majortype = MEDIATYPE_Video;
1140 testsource.source_mt.subtype = MEDIASUBTYPE_RGB8;
1141 testsource.source_mt.formattype = FORMAT_VideoInfo;
1143 hr = IPin_EnumMediaTypes(sink, &enummt);
1144 ok(hr == S_OK, "Got hr %#x.\n", hr);
1145 hr = IEnumMediaTypes_Next(enummt, 1, mts, NULL);
1146 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1147 IEnumMediaTypes_Release(enummt);
1149 hr = IPin_EnumMediaTypes(capture, &enummt);
1150 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
1151 hr = IPin_EnumMediaTypes(preview, &enummt);
1152 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
1154 hr = IPin_QueryAccept(sink, &req_mt);
1155 ok(hr == S_OK, "Got hr %#x.\n", hr);
1156 hr = IPin_QueryAccept(capture, &req_mt);
1157 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1158 hr = IPin_QueryAccept(preview, &req_mt);
1159 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1161 /* Test sink connection. */
1163 peer = (IPin *)0xdeadbeef;
1164 hr = IPin_ConnectedTo(sink, &peer);
1165 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
1166 ok(!peer, "Got peer %p.\n", peer);
1168 hr = IPin_ConnectionMediaType(sink, &mt);
1169 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
1171 hr = IMediaControl_Pause(control);
1172 ok(hr == S_OK, "Got hr %#x.\n", hr);
1173 hr = IFilterGraph2_ConnectDirect(graph, &testsource.source.pin.IPin_iface, sink, &req_mt);
1174 ok(hr == VFW_E_NOT_STOPPED, "Got hr %#x.\n", hr);
1175 hr = IMediaControl_Stop(control);
1176 ok(hr == S_OK, "Got hr %#x.\n", hr);
1178 hr = IFilterGraph2_ConnectDirect(graph, &testsource.source.pin.IPin_iface, sink, &req_mt);
1179 ok(hr == S_OK, "Got hr %#x.\n", hr);
1181 hr = IPin_ConnectedTo(sink, &peer);
1182 ok(hr == S_OK, "Got hr %#x.\n", hr);
1183 ok(peer == &testsource.source.pin.IPin_iface, "Got peer %p.\n", peer);
1184 IPin_Release(peer);
1186 hr = IPin_ConnectionMediaType(sink, &mt);
1187 ok(hr == S_OK, "Got hr %#x.\n", hr);
1188 ok(compare_media_types(&mt, &req_mt), "Media types didn't match.\n");
1190 hr = IPin_EnumMediaTypes(sink, &enummt);
1191 ok(hr == S_OK, "Got hr %#x.\n", hr);
1192 hr = IEnumMediaTypes_Next(enummt, 1, mts, NULL);
1193 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1194 IEnumMediaTypes_Release(enummt);
1196 test_source_media_types(req_mt, &testsource.source_mt, capture);
1197 test_source_media_types(req_mt, &testsource.source_mt, preview);
1198 test_source_connection(req_mt, graph, control, &testsink, capture);
1199 test_source_connection(req_mt, graph, control, &testsink, preview);
1201 hr = IMediaControl_Pause(control);
1202 ok(hr == S_OK, "Got hr %#x.\n", hr);
1203 hr = IFilterGraph2_Disconnect(graph, sink);
1204 ok(hr == VFW_E_NOT_STOPPED, "Got hr %#x.\n", hr);
1205 hr = IMediaControl_Stop(control);
1206 ok(hr == S_OK, "Got hr %#x.\n", hr);
1208 hr = IFilterGraph2_Disconnect(graph, sink);
1209 ok(hr == S_OK, "Got hr %#x.\n", hr);
1210 hr = IFilterGraph2_Disconnect(graph, sink);
1211 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1212 ok(testsource.source.pin.peer == sink, "Got peer %p.\n", testsource.source.pin.peer);
1213 IFilterGraph2_Disconnect(graph, &testsource.source.pin.IPin_iface);
1215 peer = (IPin *)0xdeadbeef;
1216 hr = IPin_ConnectedTo(sink, &peer);
1217 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
1218 ok(!peer, "Got peer %p.\n", peer);
1220 hr = IPin_ConnectionMediaType(sink, &mt);
1221 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
1223 IPin_Release(sink);
1224 IPin_Release(capture);
1225 IPin_Release(preview);
1226 IMediaControl_Release(control);
1227 ref = IFilterGraph2_Release(graph);
1228 ok(!ref, "Got outstanding refcount %d.\n", ref);
1229 ref = IBaseFilter_Release(filter);
1230 ok(!ref, "Got outstanding refcount %d.\n", ref);
1231 ref = IBaseFilter_Release(&testsource.filter.IBaseFilter_iface);
1232 ok(!ref, "Got outstanding refcount %d.\n", ref);
1233 ref = IBaseFilter_Release(&testsink.filter.IBaseFilter_iface);
1234 ok(!ref, "Got outstanding refcount %d.\n", ref);
1237 static void test_streaming(void)
1239 static const AM_MEDIA_TYPE req_mt =
1241 .majortype = {0x111},
1242 .subtype = {0x222},
1243 .formattype = {0x333},
1245 IBaseFilter *filter = create_smart_tee();
1246 struct testfilter testsource, testsink1, testsink2;
1247 IPin *sink, *capture, *preview;
1248 REFERENCE_TIME start, stop;
1249 IMemAllocator *allocator;
1250 IMediaControl *control;
1251 IFilterGraph2 *graph;
1252 IMediaSample *sample;
1253 IMemInputPin *input;
1254 LONG size, i;
1255 HRESULT hr;
1256 BYTE *data;
1257 ULONG ref;
1259 testfilter_init(&testsource);
1260 testfilter_init(&testsink1);
1261 testfilter_init(&testsink2);
1262 testsink2.preview = TRUE;
1263 CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
1264 &IID_IFilterGraph2, (void **)&graph);
1265 IFilterGraph2_AddFilter(graph, &testsource.filter.IBaseFilter_iface, L"source");
1266 IFilterGraph2_AddFilter(graph, &testsink1.filter.IBaseFilter_iface, L"sink1");
1267 IFilterGraph2_AddFilter(graph, &testsink2.filter.IBaseFilter_iface, L"sink2");
1268 IFilterGraph2_AddFilter(graph, filter, L"sample grabber");
1269 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
1270 IBaseFilter_FindPin(filter, L"Input", &sink);
1271 IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&input);
1272 IBaseFilter_FindPin(filter, L"Capture", &capture);
1273 IBaseFilter_FindPin(filter, L"Preview", &preview);
1275 hr = IFilterGraph2_ConnectDirect(graph, &testsource.source.pin.IPin_iface, sink, &req_mt);
1276 ok(hr == S_OK, "Got hr %#x.\n", hr);
1277 hr = IFilterGraph2_ConnectDirect(graph, capture, &testsink1.sink.pin.IPin_iface, &req_mt);
1278 ok(hr == S_OK, "Got hr %#x.\n", hr);
1279 hr = IFilterGraph2_ConnectDirect(graph, preview, &testsink2.sink.pin.IPin_iface, &req_mt);
1280 ok(hr == S_OK, "Got hr %#x.\n", hr);
1282 hr = IMemInputPin_ReceiveCanBlock(input);
1283 ok(hr == S_OK, "Got hr %#x.\n", hr);
1285 hr = IMemInputPin_GetAllocator(input, &allocator);
1286 ok(hr == S_OK, "Got hr %#x.\n", hr);
1288 hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
1289 ok(hr == VFW_E_NOT_COMMITTED, "Got hr %#x.\n", hr);
1291 hr = IMediaControl_Pause(control);
1292 ok(hr == S_OK, "Got hr %#x.\n", hr);
1294 hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
1295 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
1296 if (hr != S_OK)
1298 IMemAllocator_Commit(allocator);
1299 hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
1300 ok(hr == S_OK, "Got hr %#x.\n", hr);
1303 hr = IMediaSample_GetPointer(sample, &data);
1304 ok(hr == S_OK, "Got hr %#x.\n", hr);
1305 size = IMediaSample_GetSize(sample);
1306 ok(size == 256, "Got size %d.\n", size);
1307 for (i = 0; i < 200; ++i)
1308 data[i] = i;
1309 hr = IMediaSample_SetActualDataLength(sample, 200);
1310 ok(hr == S_OK, "Got hr %#x.\n", hr);
1312 start = 10000;
1313 stop = 20000;
1314 hr = IMediaSample_SetMediaTime(sample, &start, &stop);
1315 ok(hr == S_OK, "Got hr %#x.\n", hr);
1316 start = 30000;
1317 stop = 40000;
1318 hr = IMediaSample_SetTime(sample, &start, &stop);
1319 ok(hr == S_OK, "Got hr %#x.\n", hr);
1320 hr = IMediaSample_SetDiscontinuity(sample, TRUE);
1321 ok(hr == S_OK, "Got hr %#x.\n", hr);
1322 hr = IMediaSample_SetPreroll(sample, TRUE);
1323 ok(hr == S_OK, "Got hr %#x.\n", hr);
1324 hr = IMediaSample_SetSyncPoint(sample, TRUE);
1325 ok(hr == S_OK, "Got hr %#x.\n", hr);
1327 hr = IMemInputPin_Receive(input, sample);
1328 ok(hr == S_OK, "Got hr %#x.\n", hr);
1329 ok(!WaitForSingleObject(testsink1.sample_event, 1000), "Wait timed out.\n");
1330 ok(!WaitForSingleObject(testsink2.sample_event, 1000), "Wait timed out.\n");
1332 hr = IPin_NewSegment(sink, 10000, 20000, 1.0);
1333 ok(hr == S_OK, "Got hr %#x.\n", hr);
1334 ok(!WaitForSingleObject(testsink1.segment_event, 1000), "Wait timed out.\n");
1335 ok(!WaitForSingleObject(testsink2.segment_event, 1000), "Wait timed out.\n");
1337 hr = IPin_EndOfStream(sink);
1338 ok(hr == S_OK, "Got hr %#x.\n", hr);
1339 ok(!WaitForSingleObject(testsink1.eos_event, 1000), "Wait timed out.\n");
1340 ok(!WaitForSingleObject(testsink2.eos_event, 1000), "Wait timed out.\n");
1342 hr = IPin_EndOfStream(sink);
1343 ok(hr == S_OK, "Got hr %#x.\n", hr);
1344 ok(!WaitForSingleObject(testsink1.eos_event, 1000), "Wait timed out.\n");
1345 ok(!WaitForSingleObject(testsink2.eos_event, 1000), "Wait timed out.\n");
1347 ok(!testsink1.got_begin_flush, "Got %u calls to IPin::BeginFlush().\n", testsink1.got_begin_flush);
1348 ok(!testsink2.got_begin_flush, "Got %u calls to IPin::BeginFlush().\n", testsink2.got_begin_flush);
1349 hr = IPin_BeginFlush(sink);
1350 ok(hr == S_OK, "Got hr %#x.\n", hr);
1351 ok(testsink1.got_begin_flush == 1, "Got %u calls to IPin::BeginFlush().\n", testsink1.got_begin_flush);
1352 ok(testsink2.got_begin_flush == 1, "Got %u calls to IPin::BeginFlush().\n", testsink2.got_begin_flush);
1354 hr = IMemInputPin_Receive(input, sample);
1355 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1357 hr = IPin_EndOfStream(sink);
1358 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
1359 /* No EOS events are sent downstream, however. */
1361 ok(!testsink1.got_end_flush, "Got %u calls to IPin::EndFlush().\n", testsink1.got_end_flush);
1362 ok(!testsink2.got_end_flush, "Got %u calls to IPin::EndFlush().\n", testsink2.got_end_flush);
1363 hr = IPin_EndFlush(sink);
1364 ok(hr == S_OK, "Got hr %#x.\n", hr);
1365 ok(testsink1.got_end_flush == 1, "Got %u calls to IPin::EndFlush().\n", testsink1.got_end_flush);
1366 ok(testsink2.got_end_flush == 1, "Got %u calls to IPin::EndFlush().\n", testsink2.got_end_flush);
1368 hr = IMemInputPin_Receive(input, sample);
1369 ok(hr == S_OK, "Got hr %#x.\n", hr);
1370 ok(!WaitForSingleObject(testsink1.sample_event, 1000), "Wait timed out.\n");
1371 ok(!WaitForSingleObject(testsink2.sample_event, 1000), "Wait timed out.\n");
1373 hr = IMediaControl_Stop(control);
1374 ok(hr == S_OK, "Got hr %#x.\n", hr);
1376 hr = IMemInputPin_Receive(input, sample);
1377 todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
1379 hr = IPin_EndOfStream(sink);
1380 ok(hr == S_OK, "Got hr %#x.\n", hr);
1381 /* No EOS events are sent downstream, however. */
1383 IMediaSample_Release(sample);
1384 IMemAllocator_Release(allocator);
1385 IMemInputPin_Release(input);
1386 IPin_Release(sink);
1387 IPin_Release(capture);
1388 IPin_Release(preview);
1389 IMediaControl_Release(control);
1390 ref = IFilterGraph2_Release(graph);
1391 ok(!ref, "Got outstanding refcount %d.\n", ref);
1392 ref = IBaseFilter_Release(filter);
1393 ok(!ref, "Got outstanding refcount %d.\n", ref);
1394 ref = IBaseFilter_Release(&testsource.filter.IBaseFilter_iface);
1395 ok(!ref, "Got outstanding refcount %d.\n", ref);
1396 ref = IBaseFilter_Release(&testsink1.filter.IBaseFilter_iface);
1397 ok(!ref, "Got outstanding refcount %d.\n", ref);
1398 ref = IBaseFilter_Release(&testsink2.filter.IBaseFilter_iface);
1399 ok(!ref, "Got outstanding refcount %d.\n", ref);
1402 START_TEST(smartteefilter)
1404 CoInitialize(NULL);
1406 event = CreateEventW(NULL, FALSE, FALSE, NULL);
1408 test_interfaces();
1409 test_aggregation();
1410 test_enum_pins();
1411 test_find_pin();
1412 test_pin_info();
1413 test_enum_media_types();
1414 test_unconnected_filter_state();
1415 test_connect_pin();
1416 test_streaming();
1418 CloseHandle(event);
1419 CoUninitialize();