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
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};
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
);
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
;
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
);
66 IUnknown_Release(unk
);
69 static void test_interfaces(void)
71 IBaseFilter
*filter
= create_smart_tee();
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
);
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
);
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
);
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;
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
,
178 static IUnknown test_outer
= {&outer_vtbl
};
180 static void test_aggregation(void)
182 IBaseFilter
*filter
, *filter2
;
183 IUnknown
*unk
, *unk2
;
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
;
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
;
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
);
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
);
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
);
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();
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
));
457 hr
= IPin_QueryInternalConnections(pin
, NULL
, &count
);
458 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
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
));
485 hr
= IPin_QueryInternalConnections(pin
, NULL
, &count
);
486 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
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
));
513 hr
= IPin_QueryInternalConnections(pin
, NULL
, &count
);
514 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
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];
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
);
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();
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
);
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
;
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
);
644 return &filter
->source
.pin
;
646 return &filter
->sink
.pin
;
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
);
677 CopyMediaType(mt
, &filter
->source_mt
);
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
;
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
)
728 iface
->pin
.peer
= 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
);
736 iface
->pin
.peer
= NULL
;
737 FreeMediaType(&iface
->pin
.mt
);
740 test_sink_allocator(peer
);
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
;
759 return E_NOINTERFACE
;
761 IUnknown_AddRef((IUnknown
*)*out
);
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
))
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
);
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];
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
)
801 ok(!memcmp(data
, expect
, size
), "Data didn't match.\n");
803 hr
= IMediaSample_GetTime(sample
, &start
, &stop
);
806 ok(hr
== VFW_E_SAMPLE_TIME_NOT_SET
, "Got hr %#x.\n", hr
);
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
);
818 todo_wine
ok(hr
== VFW_E_MEDIA_TIME_NOT_SET
, "Got hr %#x.\n", hr
);
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
);
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
);
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
);
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
;
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
;
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];
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");
909 ok(compare_media_types(mts
[1], source_mt
), "Media types didn't match.\n");
910 CoTaskMemFree(mts
[0]);
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
);
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
;
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
);
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
);
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
);
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
);
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
);
1093 IFilterGraph2_Disconnect(graph
, source
);
1094 IFilterGraph2_Disconnect(graph
, &testsink
->sink
.pin
.IPin_iface
);
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
,
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
;
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
);
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
);
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},
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
;
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
);
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
)
1309 hr
= IMediaSample_SetActualDataLength(sample
, 200);
1310 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1314 hr
= IMediaSample_SetMediaTime(sample
, &start
, &stop
);
1315 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
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
);
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
)
1406 event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1413 test_enum_media_types();
1414 test_unconnected_filter_state();