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
);
567 IBaseFilter IBaseFilter_iface
;
570 DWORD receiveThreadId
;
572 IMemInputPin IMemInputPin_iface
;
573 IMemAllocator
*allocator
;
574 IBaseFilter
*nullRenderer
;
575 IPin
*nullRendererPin
;
576 IMemInputPin
*nullRendererMemInputPin
;
580 IEnumPins IEnumPins_iface
;
586 static SinkEnumPins
* create_SinkEnumPins(SinkFilter
*filter
);
588 static inline SinkFilter
* impl_from_SinkFilter_IBaseFilter(IBaseFilter
*iface
)
590 return CONTAINING_RECORD(iface
, SinkFilter
, IBaseFilter_iface
);
593 static inline SinkFilter
* impl_from_SinkFilter_IPin(IPin
*iface
)
595 return CONTAINING_RECORD(iface
, SinkFilter
, IPin_iface
);
598 static inline SinkFilter
* impl_from_SinkFilter_IMemInputPin(IMemInputPin
*iface
)
600 return CONTAINING_RECORD(iface
, SinkFilter
, IMemInputPin_iface
);
603 static inline SinkEnumPins
* impl_from_SinkFilter_IEnumPins(IEnumPins
*iface
)
605 return CONTAINING_RECORD(iface
, SinkEnumPins
, IEnumPins_iface
);
608 static HRESULT WINAPI
SinkFilter_QueryInterface(IBaseFilter
*iface
, REFIID riid
, void **ppv
)
610 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
611 if(IsEqualIID(riid
, &IID_IUnknown
)) {
612 *ppv
= &This
->IBaseFilter_iface
;
613 } else if(IsEqualIID(riid
, &IID_IPersist
)) {
614 *ppv
= &This
->IBaseFilter_iface
;
615 } else if(IsEqualIID(riid
, &IID_IMediaFilter
)) {
616 *ppv
= &This
->IBaseFilter_iface
;
617 } else if(IsEqualIID(riid
, &IID_IBaseFilter
)) {
618 *ppv
= &This
->IBaseFilter_iface
;
620 trace("no interface for %s\n", wine_dbgstr_guid(riid
));
622 return E_NOINTERFACE
;
624 IUnknown_AddRef((IUnknown
*)*ppv
);
628 static ULONG WINAPI
SinkFilter_AddRef(IBaseFilter
*iface
)
630 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
631 return InterlockedIncrement(&This
->ref
);
634 static ULONG WINAPI
SinkFilter_Release(IBaseFilter
*iface
)
636 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
637 ULONG ref
= InterlockedDecrement(&This
->ref
);
640 IMemAllocator_Release(This
->allocator
);
641 IMemInputPin_Release(This
->nullRendererMemInputPin
);
642 IPin_Release(This
->nullRendererPin
);
643 IBaseFilter_Release(This
->nullRenderer
);
649 static HRESULT WINAPI
SinkFilter_GetClassID(IBaseFilter
*iface
, CLSID
*pClassID
)
651 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
652 return IBaseFilter_GetClassID(This
->nullRenderer
, pClassID
);
655 static HRESULT WINAPI
SinkFilter_Stop(IBaseFilter
*iface
)
657 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
658 return IBaseFilter_Stop(This
->nullRenderer
);
661 static HRESULT WINAPI
SinkFilter_Pause(IBaseFilter
*iface
)
663 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
664 return IBaseFilter_Pause(This
->nullRenderer
);
667 static HRESULT WINAPI
SinkFilter_Run(IBaseFilter
*iface
, REFERENCE_TIME tStart
)
669 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
670 return IBaseFilter_Run(This
->nullRenderer
, tStart
);
673 static HRESULT WINAPI
SinkFilter_GetState(IBaseFilter
*iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*state
)
675 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
676 return IBaseFilter_GetState(This
->nullRenderer
, dwMilliSecsTimeout
, state
);
679 static HRESULT WINAPI
SinkFilter_SetSyncSource(IBaseFilter
*iface
, IReferenceClock
*pClock
)
681 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
682 return IBaseFilter_SetSyncSource(This
->nullRenderer
, pClock
);
685 static HRESULT WINAPI
SinkFilter_GetSyncSource(IBaseFilter
*iface
, IReferenceClock
**ppClock
)
687 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
688 return IBaseFilter_GetSyncSource(This
->nullRenderer
, ppClock
);
691 static HRESULT WINAPI
SinkFilter_EnumPins(IBaseFilter
*iface
, IEnumPins
**ppEnum
)
693 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
694 SinkEnumPins
*sinkEnumPins
= create_SinkEnumPins(This
);
696 *ppEnum
= &sinkEnumPins
->IEnumPins_iface
;
700 return E_OUTOFMEMORY
;
703 static HRESULT WINAPI
SinkFilter_FindPin(IBaseFilter
*iface
, LPCWSTR id
, IPin
**ppPin
)
705 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
706 HRESULT hr
= IBaseFilter_FindPin(This
->nullRenderer
, id
, ppPin
);
708 IPin_Release(*ppPin
);
709 *ppPin
= &This
->IPin_iface
;
710 IPin_AddRef(&This
->IPin_iface
);
715 static HRESULT WINAPI
SinkFilter_QueryFilterInfo(IBaseFilter
*iface
, FILTER_INFO
*pInfo
)
717 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
718 return IBaseFilter_QueryFilterInfo(This
->nullRenderer
, pInfo
);
721 static HRESULT WINAPI
SinkFilter_JoinFilterGraph(IBaseFilter
*iface
, IFilterGraph
*pGraph
, LPCWSTR pName
)
723 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
724 return IBaseFilter_JoinFilterGraph(This
->nullRenderer
, pGraph
, pName
);
727 static HRESULT WINAPI
SinkFilter_QueryVendorInfo(IBaseFilter
*iface
, LPWSTR
*pVendorInfo
)
729 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
730 return IBaseFilter_QueryVendorInfo(This
->nullRenderer
, pVendorInfo
);
733 static const IBaseFilterVtbl SinkFilterVtbl
= {
734 SinkFilter_QueryInterface
,
737 SinkFilter_GetClassID
,
742 SinkFilter_SetSyncSource
,
743 SinkFilter_GetSyncSource
,
746 SinkFilter_QueryFilterInfo
,
747 SinkFilter_JoinFilterGraph
,
748 SinkFilter_QueryVendorInfo
751 static HRESULT WINAPI
SinkEnumPins_QueryInterface(IEnumPins
*iface
, REFIID riid
, void **ppv
)
753 SinkEnumPins
*This
= impl_from_SinkFilter_IEnumPins(iface
);
754 if(IsEqualIID(riid
, &IID_IUnknown
)) {
755 *ppv
= &This
->IEnumPins_iface
;
756 } else if(IsEqualIID(riid
, &IID_IEnumPins
)) {
757 *ppv
= &This
->IEnumPins_iface
;
759 trace("no interface for %s\n", wine_dbgstr_guid(riid
));
761 return E_NOINTERFACE
;
763 IUnknown_AddRef((IUnknown
*)*ppv
);
767 static ULONG WINAPI
SinkEnumPins_AddRef(IEnumPins
*iface
)
769 SinkEnumPins
*This
= impl_from_SinkFilter_IEnumPins(iface
);
770 return InterlockedIncrement(&This
->ref
);
773 static ULONG WINAPI
SinkEnumPins_Release(IEnumPins
*iface
)
775 SinkEnumPins
*This
= impl_from_SinkFilter_IEnumPins(iface
);
777 ref
= InterlockedDecrement(&This
->ref
);
780 IBaseFilter_Release(&This
->filter
->IBaseFilter_iface
);
786 static HRESULT WINAPI
SinkEnumPins_Next(IEnumPins
*iface
, ULONG cPins
, IPin
**ppPins
, ULONG
*pcFetched
)
788 SinkEnumPins
*This
= impl_from_SinkFilter_IEnumPins(iface
);
791 if (cPins
> 1 && !pcFetched
)
797 if (This
->index
== 0) {
798 ppPins
[0] = &This
->filter
->IPin_iface
;
799 IPin_AddRef(&This
->filter
->IPin_iface
);
808 static HRESULT WINAPI
SinkEnumPins_Skip(IEnumPins
*iface
, ULONG cPins
)
810 SinkEnumPins
*This
= impl_from_SinkFilter_IEnumPins(iface
);
811 if (This
->index
+ cPins
>= 1)
813 This
->index
+= cPins
;
817 static HRESULT WINAPI
SinkEnumPins_Reset(IEnumPins
*iface
)
819 SinkEnumPins
*This
= impl_from_SinkFilter_IEnumPins(iface
);
824 static HRESULT WINAPI
SinkEnumPins_Clone(IEnumPins
*iface
, IEnumPins
**ppEnum
)
826 SinkEnumPins
*This
= impl_from_SinkFilter_IEnumPins(iface
);
827 SinkEnumPins
*clone
= create_SinkEnumPins(This
->filter
);
829 return E_OUTOFMEMORY
;
830 clone
->index
= This
->index
;
831 *ppEnum
= &clone
->IEnumPins_iface
;
835 static const IEnumPinsVtbl SinkEnumPinsVtbl
= {
836 SinkEnumPins_QueryInterface
,
838 SinkEnumPins_Release
,
845 static SinkEnumPins
* create_SinkEnumPins(SinkFilter
*filter
)
848 This
= CoTaskMemAlloc(sizeof(*This
));
852 This
->IEnumPins_iface
.lpVtbl
= &SinkEnumPinsVtbl
;
855 This
->filter
= filter
;
856 IBaseFilter_AddRef(&filter
->IBaseFilter_iface
);
860 static HRESULT WINAPI
SinkPin_QueryInterface(IPin
*iface
, REFIID riid
, void **ppv
)
862 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
863 if(IsEqualIID(riid
, &IID_IUnknown
)) {
864 *ppv
= &This
->IPin_iface
;
865 } else if(IsEqualIID(riid
, &IID_IPin
)) {
866 *ppv
= &This
->IPin_iface
;
867 } else if(IsEqualIID(riid
, &IID_IMemInputPin
)) {
868 *ppv
= &This
->IMemInputPin_iface
;
870 trace("no interface for %s\n", wine_dbgstr_guid(riid
));
872 return E_NOINTERFACE
;
874 IUnknown_AddRef((IUnknown
*)*ppv
);
878 static ULONG WINAPI
SinkPin_AddRef(IPin
*iface
)
880 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
881 return IBaseFilter_AddRef(&This
->IBaseFilter_iface
);
884 static ULONG WINAPI
SinkPin_Release(IPin
*iface
)
886 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
887 return IBaseFilter_Release(&This
->IBaseFilter_iface
);
890 static HRESULT WINAPI
SinkPin_Connect(IPin
*iface
, IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
892 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
893 return IPin_Connect(This
->nullRendererPin
, pReceivePin
, pmt
);
896 static HRESULT WINAPI
SinkPin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*pmt
)
898 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
899 return IPin_ReceiveConnection(This
->nullRendererPin
, connector
, pmt
);
902 static HRESULT WINAPI
SinkPin_Disconnect(IPin
*iface
)
904 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
905 return IPin_Disconnect(This
->nullRendererPin
);
908 static HRESULT WINAPI
SinkPin_ConnectedTo(IPin
*iface
, IPin
**pPin
)
910 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
911 return IPin_ConnectedTo(This
->nullRendererPin
, pPin
);
914 static HRESULT WINAPI
SinkPin_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*pmt
)
916 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
917 return IPin_ConnectionMediaType(This
->nullRendererPin
, pmt
);
920 static HRESULT WINAPI
SinkPin_QueryPinInfo(IPin
*iface
, PIN_INFO
*pInfo
)
922 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
923 HRESULT hr
= IPin_QueryPinInfo(This
->nullRendererPin
, pInfo
);
925 IBaseFilter_Release(pInfo
->pFilter
);
926 pInfo
->pFilter
= &This
->IBaseFilter_iface
;
927 IBaseFilter_AddRef(&This
->IBaseFilter_iface
);
932 static HRESULT WINAPI
SinkPin_QueryDirection(IPin
*iface
, PIN_DIRECTION
*pPinDir
)
934 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
935 return IPin_QueryDirection(This
->nullRendererPin
, pPinDir
);
938 static HRESULT WINAPI
SinkPin_QueryId(IPin
*iface
, LPWSTR
*id
)
940 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
941 return IPin_QueryId(This
->nullRendererPin
, id
);
944 static HRESULT WINAPI
SinkPin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*pmt
)
946 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
947 return IPin_QueryAccept(This
->nullRendererPin
, pmt
);
950 static HRESULT WINAPI
SinkPin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**ppEnum
)
952 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
953 return IPin_EnumMediaTypes(This
->nullRendererPin
, ppEnum
);
956 static HRESULT WINAPI
SinkPin_QueryInternalConnections(IPin
*iface
, IPin
**apPin
, ULONG
*nPin
)
958 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
959 return IPin_QueryInternalConnections(This
->nullRendererPin
, apPin
, nPin
);
962 static HRESULT WINAPI
SinkPin_EndOfStream(IPin
*iface
)
964 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
965 return IPin_EndOfStream(This
->nullRendererPin
);
968 static HRESULT WINAPI
SinkPin_BeginFlush(IPin
*iface
)
970 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
971 return IPin_BeginFlush(This
->nullRendererPin
);
974 static HRESULT WINAPI
SinkPin_EndFlush(IPin
*iface
)
976 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
977 return IPin_EndFlush(This
->nullRendererPin
);
980 static HRESULT WINAPI
SinkPin_NewSegment(IPin
*iface
, REFERENCE_TIME tStart
,
981 REFERENCE_TIME tStop
, double dRate
)
983 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
984 return IPin_NewSegment(This
->nullRendererPin
, tStart
, tStop
, dRate
);
987 static const IPinVtbl SinkPinVtbl
= {
988 SinkPin_QueryInterface
,
992 SinkPin_ReceiveConnection
,
995 SinkPin_ConnectionMediaType
,
996 SinkPin_QueryPinInfo
,
997 SinkPin_QueryDirection
,
1000 SinkPin_EnumMediaTypes
,
1001 SinkPin_QueryInternalConnections
,
1002 SinkPin_EndOfStream
,
1008 static HRESULT WINAPI
SinkMemInputPin_QueryInterface(IMemInputPin
*iface
, REFIID riid
, void **ppv
)
1010 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
1011 return IPin_QueryInterface(&This
->IPin_iface
, riid
, ppv
);
1014 static ULONG WINAPI
SinkMemInputPin_AddRef(IMemInputPin
*iface
)
1016 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
1017 return IBaseFilter_AddRef(&This
->IBaseFilter_iface
);
1020 static ULONG WINAPI
SinkMemInputPin_Release(IMemInputPin
*iface
)
1022 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
1023 return IBaseFilter_Release(&This
->IBaseFilter_iface
);
1026 static HRESULT WINAPI
SinkMemInputPin_GetAllocator(IMemInputPin
*iface
, IMemAllocator
**ppAllocator
)
1028 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
1029 ok(0, "SmartTeeFilter never calls IMemInputPin_GetAllocator()\n");
1030 return IMemInputPin_GetAllocator(This
->nullRendererMemInputPin
, ppAllocator
);
1033 static HRESULT WINAPI
SinkMemInputPin_NotifyAllocator(IMemInputPin
*iface
, IMemAllocator
*pAllocator
,
1036 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
1037 This
->allocator
= pAllocator
;
1038 IMemAllocator_AddRef(This
->allocator
);
1039 ok(bReadOnly
, "bReadOnly isn't supposed to be FALSE\n");
1040 return IMemInputPin_NotifyAllocator(This
->nullRendererMemInputPin
, pAllocator
, bReadOnly
);
1043 static HRESULT WINAPI
SinkMemInputPin_GetAllocatorRequirements(IMemInputPin
*iface
,
1044 ALLOCATOR_PROPERTIES
*pProps
)
1046 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
1047 ok(0, "SmartTeeFilter never calls IMemInputPin_GetAllocatorRequirements()\n");
1048 return IMemInputPin_GetAllocatorRequirements(This
->nullRendererMemInputPin
, pProps
);
1051 static HRESULT WINAPI
SinkMemInputPin_Receive(IMemInputPin
*iface
, IMediaSample
*pSample
)
1053 LONG samplesProcessed
;
1054 todo_wine
ok(0, "SmartTeeFilter never calls IMemInputPin_Receive(), only IMemInputPin_ReceiveMultiple()\n");
1055 return IMemInputPin_ReceiveMultiple(iface
, &pSample
, 1, &samplesProcessed
);
1058 static HRESULT WINAPI
SinkMemInputPin_ReceiveMultiple(IMemInputPin
*iface
, IMediaSample
**pSamples
,
1059 LONG nSamples
, LONG
*nSamplesProcessed
)
1061 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
1062 IMediaSample
*pSample
;
1063 REFERENCE_TIME startTime
, endTime
;
1065 ok(nSamples
== 1, "expected 1 sample, got %d\n", nSamples
);
1066 pSample
= pSamples
[0];
1067 hr
= IMediaSample_GetTime(pSample
, &startTime
, &endTime
);
1068 if (This
->isCapture
)
1069 ok(SUCCEEDED(hr
), "IMediaSample_GetTime() from Capture pin failed, hr=0x%08x\n", hr
);
1071 ok(hr
== VFW_E_SAMPLE_TIME_NOT_SET
, "IMediaSample_GetTime() from Preview pin returned hr=0x%08x\n", hr
);
1072 This
->receiveThreadId
= GetCurrentThreadId();
1074 return IMemInputPin_ReceiveMultiple(This
->nullRendererMemInputPin
, pSamples
,
1075 nSamples
, nSamplesProcessed
);
1078 static HRESULT WINAPI
SinkMemInputPin_ReceiveCanBlock(IMemInputPin
*iface
)
1080 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
1081 return IMemInputPin_ReceiveCanBlock(This
->nullRendererMemInputPin
);
1084 static const IMemInputPinVtbl SinkMemInputPinVtbl
= {
1085 SinkMemInputPin_QueryInterface
,
1086 SinkMemInputPin_AddRef
,
1087 SinkMemInputPin_Release
,
1088 SinkMemInputPin_GetAllocator
,
1089 SinkMemInputPin_NotifyAllocator
,
1090 SinkMemInputPin_GetAllocatorRequirements
,
1091 SinkMemInputPin_Receive
,
1092 SinkMemInputPin_ReceiveMultiple
,
1093 SinkMemInputPin_ReceiveCanBlock
1096 static SinkFilter
* create_SinkFilter(BOOL isCapture
)
1098 SinkFilter
*This
= NULL
;
1100 This
= CoTaskMemAlloc(sizeof(*This
));
1102 memset(This
, 0, sizeof(*This
));
1103 This
->IBaseFilter_iface
.lpVtbl
= &SinkFilterVtbl
;
1105 This
->isCapture
= isCapture
;
1106 This
->IPin_iface
.lpVtbl
= &SinkPinVtbl
;
1107 This
->IMemInputPin_iface
.lpVtbl
= &SinkMemInputPinVtbl
;
1108 hr
= CoCreateInstance(&CLSID_NullRenderer
, NULL
, CLSCTX_INPROC_SERVER
,
1109 &IID_IBaseFilter
, (LPVOID
*)&This
->nullRenderer
);
1110 if (SUCCEEDED(hr
)) {
1111 IEnumPins
*enumPins
= NULL
;
1112 hr
= IBaseFilter_EnumPins(This
->nullRenderer
, &enumPins
);
1113 if (SUCCEEDED(hr
)) {
1114 hr
= IEnumPins_Next(enumPins
, 1, &This
->nullRendererPin
, NULL
);
1115 IEnumPins_Release(enumPins
);
1116 if (SUCCEEDED(hr
)) {
1117 hr
= IPin_QueryInterface(This
->nullRendererPin
, &IID_IMemInputPin
,
1118 (LPVOID
*)&This
->nullRendererMemInputPin
);
1121 IPin_Release(This
->nullRendererPin
);
1124 IBaseFilter_Release(This
->nullRenderer
);
1126 CoTaskMemFree(This
);
1132 IBaseFilter IBaseFilter_iface
;
1135 IKsPropertySet IKsPropertySet_iface
;
1136 CRITICAL_SECTION cs
;
1138 IReferenceClock
*referenceClock
;
1139 FILTER_INFO filterInfo
;
1140 AM_MEDIA_TYPE mediaType
;
1141 VIDEOINFOHEADER videoInfo
;
1142 WAVEFORMATEX audioInfo
;
1144 IMemInputPin
*memInputPin
;
1145 IMemAllocator
*allocator
;
1146 DWORD mediaThreadId
;
1150 IEnumPins IEnumPins_iface
;
1153 SourceFilter
*filter
;
1157 IEnumMediaTypes IEnumMediaTypes_iface
;
1160 SourceFilter
*filter
;
1161 } SourceEnumMediaTypes
;
1163 static const WCHAR sourcePinName
[] = {'C','a','p','t','u','r','e',0};
1165 static SourceEnumPins
* create_SourceEnumPins(SourceFilter
*filter
);
1166 static SourceEnumMediaTypes
* create_SourceEnumMediaTypes(SourceFilter
*filter
);
1168 static inline SourceFilter
* impl_from_SourceFilter_IBaseFilter(IBaseFilter
*iface
)
1170 return CONTAINING_RECORD(iface
, SourceFilter
, IBaseFilter_iface
);
1173 static inline SourceFilter
* impl_from_SourceFilter_IPin(IPin
*iface
)
1175 return CONTAINING_RECORD(iface
, SourceFilter
, IPin_iface
);
1178 static inline SourceFilter
* impl_from_SourceFilter_IKsPropertySet(IKsPropertySet
*iface
)
1180 return CONTAINING_RECORD(iface
, SourceFilter
, IKsPropertySet_iface
);
1183 static inline SourceEnumPins
* impl_from_SourceFilter_IEnumPins(IEnumPins
*iface
)
1185 return CONTAINING_RECORD(iface
, SourceEnumPins
, IEnumPins_iface
);
1188 static inline SourceEnumMediaTypes
* impl_from_SourceFilter_IEnumMediaTypes(IEnumMediaTypes
*iface
)
1190 return CONTAINING_RECORD(iface
, SourceEnumMediaTypes
, IEnumMediaTypes_iface
);
1193 static HRESULT WINAPI
SourceFilter_QueryInterface(IBaseFilter
*iface
, REFIID riid
, void **ppv
)
1195 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
1196 if(IsEqualIID(riid
, &IID_IUnknown
)) {
1197 *ppv
= &This
->IBaseFilter_iface
;
1198 } else if(IsEqualIID(riid
, &IID_IPersist
)) {
1199 *ppv
= &This
->IBaseFilter_iface
;
1200 } else if(IsEqualIID(riid
, &IID_IMediaFilter
)) {
1201 *ppv
= &This
->IBaseFilter_iface
;
1202 } else if(IsEqualIID(riid
, &IID_IBaseFilter
)) {
1203 *ppv
= &This
->IBaseFilter_iface
;
1205 trace("no interface for %s\n", wine_dbgstr_guid(riid
));
1207 return E_NOINTERFACE
;
1209 IUnknown_AddRef((IUnknown
*)*ppv
);
1213 static ULONG WINAPI
SourceFilter_AddRef(IBaseFilter
*iface
)
1215 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
1216 return InterlockedIncrement(&This
->ref
);
1219 static ULONG WINAPI
SourceFilter_Release(IBaseFilter
*iface
)
1221 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
1222 ULONG ref
= InterlockedDecrement(&This
->ref
);
1224 if (This
->referenceClock
)
1225 IReferenceClock_Release(This
->referenceClock
);
1226 if (This
->connectedTo
)
1227 IPin_Disconnect(&This
->IPin_iface
);
1228 DeleteCriticalSection(&This
->cs
);
1229 CoTaskMemFree(This
);
1234 static HRESULT WINAPI
SourceFilter_GetClassID(IBaseFilter
*iface
, CLSID
*pClassID
)
1236 *pClassID
= CLSID_VfwCapture
;
1240 static HRESULT WINAPI
SourceFilter_Stop(IBaseFilter
*iface
)
1242 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
1243 EnterCriticalSection(&This
->cs
);
1244 IMemAllocator_Decommit(This
->allocator
);
1245 This
->state
= State_Stopped
;
1246 LeaveCriticalSection(&This
->cs
);
1250 static HRESULT WINAPI
SourceFilter_Pause(IBaseFilter
*iface
)
1252 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
1253 EnterCriticalSection(&This
->cs
);
1254 This
->state
= State_Paused
;
1255 LeaveCriticalSection(&This
->cs
);
1259 static DWORD WINAPI
media_thread(LPVOID param
)
1261 SourceFilter
*This
= (SourceFilter
*) param
;
1263 IMediaSample
*sample
= NULL
;
1264 REFERENCE_TIME startTime
;
1265 REFERENCE_TIME endTime
;
1268 hr
= IMemAllocator_GetBuffer(This
->allocator
, &sample
, NULL
, NULL
, 0);
1269 ok(SUCCEEDED(hr
), "IMemAllocator_GetBuffer() failed, hr=0x%08x\n", hr
);
1270 if (SUCCEEDED(hr
)) {
1273 hr
= IMediaSample_SetTime(sample
, &startTime
, &endTime
);
1274 ok(SUCCEEDED(hr
), "IMediaSample_SetTime() failed, hr=0x%08x\n", hr
);
1275 hr
= IMediaSample_SetMediaType(sample
, &This
->mediaType
);
1276 ok(SUCCEEDED(hr
), "IMediaSample_SetMediaType() failed, hr=0x%08x\n", hr
);
1278 hr
= IMediaSample_GetPointer(sample
, &buffer
);
1279 ok(SUCCEEDED(hr
), "IMediaSample_GetPointer() failed, hr=0x%08x\n", hr
);
1280 if (SUCCEEDED(hr
)) {
1281 /* 10 by 10 pixel 32 RGB */
1283 for (i
= 0; i
< 100; i
++)
1287 hr
= IMemInputPin_Receive(This
->memInputPin
, sample
);
1288 ok(SUCCEEDED(hr
), "delivering sample to SmartTeeFilter's Input pin failed, hr=0x%08x\n", hr
);
1290 IMediaSample_Release(sample
);
1295 static HRESULT WINAPI
SourceFilter_Run(IBaseFilter
*iface
, REFERENCE_TIME tStart
)
1297 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
1299 EnterCriticalSection(&This
->cs
);
1300 hr
= IMemAllocator_Commit(This
->allocator
);
1301 if (SUCCEEDED(hr
)) {
1302 HANDLE thread
= CreateThread(NULL
, 0, media_thread
, This
, 0, &This
->mediaThreadId
);
1303 ok(thread
!= NULL
, "couldn't create media thread, GetLastError()=%u\n", GetLastError());
1304 if (thread
!= NULL
) {
1305 CloseHandle(thread
);
1306 This
->state
= State_Running
;
1308 IMemAllocator_Decommit(This
->allocator
);
1312 LeaveCriticalSection(&This
->cs
);
1316 static HRESULT WINAPI
SourceFilter_GetState(IBaseFilter
*iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*state
)
1318 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
1319 EnterCriticalSection(&This
->cs
);
1320 *state
= This
->state
;
1321 LeaveCriticalSection(&This
->cs
);
1325 static HRESULT WINAPI
SourceFilter_SetSyncSource(IBaseFilter
*iface
, IReferenceClock
*pClock
)
1327 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
1328 EnterCriticalSection(&This
->cs
);
1329 if (This
->referenceClock
)
1330 IReferenceClock_Release(This
->referenceClock
);
1331 This
->referenceClock
= pClock
;
1332 if (This
->referenceClock
)
1333 IReferenceClock_AddRef(This
->referenceClock
);
1334 LeaveCriticalSection(&This
->cs
);
1338 static HRESULT WINAPI
SourceFilter_GetSyncSource(IBaseFilter
*iface
, IReferenceClock
**ppClock
)
1340 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
1341 EnterCriticalSection(&This
->cs
);
1342 *ppClock
= This
->referenceClock
;
1343 if (This
->referenceClock
)
1344 IReferenceClock_AddRef(This
->referenceClock
);
1345 LeaveCriticalSection(&This
->cs
);
1349 static HRESULT WINAPI
SourceFilter_EnumPins(IBaseFilter
*iface
, IEnumPins
**ppEnum
)
1351 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
1352 SourceEnumPins
*sourceEnumPins
= create_SourceEnumPins(This
);
1353 if (sourceEnumPins
) {
1354 *ppEnum
= &sourceEnumPins
->IEnumPins_iface
;
1358 return E_OUTOFMEMORY
;
1361 static HRESULT WINAPI
SourceFilter_FindPin(IBaseFilter
*iface
, LPCWSTR id
, IPin
**ppPin
)
1363 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
1367 if (lstrcmpW(id
, sourcePinName
) == 0) {
1368 *ppPin
= &This
->IPin_iface
;
1369 IPin_AddRef(&This
->IPin_iface
);
1372 return VFW_E_NOT_FOUND
;
1375 static HRESULT WINAPI
SourceFilter_QueryFilterInfo(IBaseFilter
*iface
, FILTER_INFO
*pInfo
)
1377 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
1380 EnterCriticalSection(&This
->cs
);
1381 *pInfo
= This
->filterInfo
;
1382 if (This
->filterInfo
.pGraph
)
1383 IFilterGraph_AddRef(This
->filterInfo
.pGraph
);
1384 LeaveCriticalSection(&This
->cs
);
1388 static HRESULT WINAPI
SourceFilter_JoinFilterGraph(IBaseFilter
*iface
, IFilterGraph
*pGraph
, LPCWSTR pName
)
1390 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
1391 EnterCriticalSection(&This
->cs
);
1393 lstrcpyW(This
->filterInfo
.achName
, pName
);
1395 This
->filterInfo
.achName
[0] = 0;
1396 This
->filterInfo
.pGraph
= pGraph
;
1397 LeaveCriticalSection(&This
->cs
);
1401 static HRESULT WINAPI
SourceFilter_QueryVendorInfo(IBaseFilter
*iface
, LPWSTR
*pVendorInfo
)
1406 static const IBaseFilterVtbl SourceFilterVtbl
= {
1407 SourceFilter_QueryInterface
,
1408 SourceFilter_AddRef
,
1409 SourceFilter_Release
,
1410 SourceFilter_GetClassID
,
1414 SourceFilter_GetState
,
1415 SourceFilter_SetSyncSource
,
1416 SourceFilter_GetSyncSource
,
1417 SourceFilter_EnumPins
,
1418 SourceFilter_FindPin
,
1419 SourceFilter_QueryFilterInfo
,
1420 SourceFilter_JoinFilterGraph
,
1421 SourceFilter_QueryVendorInfo
1424 static HRESULT WINAPI
SourceEnumPins_QueryInterface(IEnumPins
*iface
, REFIID riid
, void **ppv
)
1426 SourceEnumPins
*This
= impl_from_SourceFilter_IEnumPins(iface
);
1427 if(IsEqualIID(riid
, &IID_IUnknown
)) {
1428 *ppv
= &This
->IEnumPins_iface
;
1429 } else if(IsEqualIID(riid
, &IID_IEnumPins
)) {
1430 *ppv
= &This
->IEnumPins_iface
;
1432 trace("no interface for %s\n", wine_dbgstr_guid(riid
));
1434 return E_NOINTERFACE
;
1436 IUnknown_AddRef((IUnknown
*)*ppv
);
1440 static ULONG WINAPI
SourceEnumPins_AddRef(IEnumPins
*iface
)
1442 SourceEnumPins
*This
= impl_from_SourceFilter_IEnumPins(iface
);
1443 return InterlockedIncrement(&This
->ref
);
1446 static ULONG WINAPI
SourceEnumPins_Release(IEnumPins
*iface
)
1448 SourceEnumPins
*This
= impl_from_SourceFilter_IEnumPins(iface
);
1450 ref
= InterlockedDecrement(&This
->ref
);
1453 IBaseFilter_Release(&This
->filter
->IBaseFilter_iface
);
1454 CoTaskMemFree(This
);
1459 static HRESULT WINAPI
SourceEnumPins_Next(IEnumPins
*iface
, ULONG cPins
, IPin
**ppPins
, ULONG
*pcFetched
)
1461 SourceEnumPins
*This
= impl_from_SourceFilter_IEnumPins(iface
);
1464 if (cPins
> 1 && !pcFetched
)
1465 return E_INVALIDARG
;
1470 if (This
->index
== 0) {
1471 ppPins
[0] = &This
->filter
->IPin_iface
;
1472 IPin_AddRef(&This
->filter
->IPin_iface
);
1481 static HRESULT WINAPI
SourceEnumPins_Skip(IEnumPins
*iface
, ULONG cPins
)
1483 SourceEnumPins
*This
= impl_from_SourceFilter_IEnumPins(iface
);
1484 if (This
->index
+ cPins
>= 1)
1486 This
->index
+= cPins
;
1490 static HRESULT WINAPI
SourceEnumPins_Reset(IEnumPins
*iface
)
1492 SourceEnumPins
*This
= impl_from_SourceFilter_IEnumPins(iface
);
1497 static HRESULT WINAPI
SourceEnumPins_Clone(IEnumPins
*iface
, IEnumPins
**ppEnum
)
1499 SourceEnumPins
*This
= impl_from_SourceFilter_IEnumPins(iface
);
1500 SourceEnumPins
*clone
= create_SourceEnumPins(This
->filter
);
1502 return E_OUTOFMEMORY
;
1503 clone
->index
= This
->index
;
1504 *ppEnum
= &clone
->IEnumPins_iface
;
1508 static const IEnumPinsVtbl SourceEnumPinsVtbl
= {
1509 SourceEnumPins_QueryInterface
,
1510 SourceEnumPins_AddRef
,
1511 SourceEnumPins_Release
,
1512 SourceEnumPins_Next
,
1513 SourceEnumPins_Skip
,
1514 SourceEnumPins_Reset
,
1515 SourceEnumPins_Clone
1518 static SourceEnumPins
* create_SourceEnumPins(SourceFilter
*filter
)
1520 SourceEnumPins
*This
;
1521 This
= CoTaskMemAlloc(sizeof(*This
));
1525 This
->IEnumPins_iface
.lpVtbl
= &SourceEnumPinsVtbl
;
1528 This
->filter
= filter
;
1529 IBaseFilter_AddRef(&filter
->IBaseFilter_iface
);
1533 static HRESULT WINAPI
SourceEnumMediaTypes_QueryInterface(IEnumMediaTypes
*iface
, REFIID riid
, void **ppv
)
1535 SourceEnumMediaTypes
*This
= impl_from_SourceFilter_IEnumMediaTypes(iface
);
1536 if(IsEqualIID(riid
, &IID_IUnknown
)) {
1537 *ppv
= &This
->IEnumMediaTypes_iface
;
1538 } else if(IsEqualIID(riid
, &IID_IEnumMediaTypes
)) {
1539 *ppv
= &This
->IEnumMediaTypes_iface
;
1541 trace("no interface for %s\n", wine_dbgstr_guid(riid
));
1543 return E_NOINTERFACE
;
1545 IUnknown_AddRef((IUnknown
*)*ppv
);
1549 static ULONG WINAPI
SourceEnumMediaTypes_AddRef(IEnumMediaTypes
*iface
)
1551 SourceEnumMediaTypes
*This
= impl_from_SourceFilter_IEnumMediaTypes(iface
);
1552 return InterlockedIncrement(&This
->ref
);
1555 static ULONG WINAPI
SourceEnumMediaTypes_Release(IEnumMediaTypes
*iface
)
1557 SourceEnumMediaTypes
*This
= impl_from_SourceFilter_IEnumMediaTypes(iface
);
1559 ref
= InterlockedDecrement(&This
->ref
);
1562 IBaseFilter_Release(&This
->filter
->IBaseFilter_iface
);
1563 CoTaskMemFree(This
);
1568 static HRESULT WINAPI
SourceEnumMediaTypes_Next(IEnumMediaTypes
*iface
, ULONG cMediaTypes
, AM_MEDIA_TYPE
**ppMediaTypes
, ULONG
*pcFetched
)
1570 SourceEnumMediaTypes
*This
= impl_from_SourceFilter_IEnumMediaTypes(iface
);
1573 if (cMediaTypes
> 1 && !pcFetched
)
1574 return E_INVALIDARG
;
1577 if (cMediaTypes
== 0)
1579 if (This
->index
== 0) {
1580 ppMediaTypes
[0] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
));
1581 if (ppMediaTypes
[0]) {
1582 *ppMediaTypes
[0] = This
->filter
->mediaType
;
1583 ppMediaTypes
[0]->pbFormat
= CoTaskMemAlloc(This
->filter
->mediaType
.cbFormat
);
1584 if (ppMediaTypes
[0]->pbFormat
) {
1585 memcpy(ppMediaTypes
[0]->pbFormat
, This
->filter
->mediaType
.pbFormat
, This
->filter
->mediaType
.cbFormat
);
1591 CoTaskMemFree(ppMediaTypes
[0]);
1593 return E_OUTOFMEMORY
;
1598 static HRESULT WINAPI
SourceEnumMediaTypes_Skip(IEnumMediaTypes
*iface
, ULONG cMediaTypes
)
1600 SourceEnumMediaTypes
*This
= impl_from_SourceFilter_IEnumMediaTypes(iface
);
1601 This
->index
+= cMediaTypes
;
1602 if (This
->index
>= 1)
1607 static HRESULT WINAPI
SourceEnumMediaTypes_Reset(IEnumMediaTypes
*iface
)
1609 SourceEnumMediaTypes
*This
= impl_from_SourceFilter_IEnumMediaTypes(iface
);
1614 static HRESULT WINAPI
SourceEnumMediaTypes_Clone(IEnumMediaTypes
*iface
, IEnumMediaTypes
**ppEnum
)
1616 SourceEnumMediaTypes
*This
= impl_from_SourceFilter_IEnumMediaTypes(iface
);
1617 SourceEnumMediaTypes
*clone
= create_SourceEnumMediaTypes(This
->filter
);
1619 return E_OUTOFMEMORY
;
1620 clone
->index
= This
->index
;
1621 *ppEnum
= &clone
->IEnumMediaTypes_iface
;
1625 static const IEnumMediaTypesVtbl SourceEnumMediaTypesVtbl
= {
1626 SourceEnumMediaTypes_QueryInterface
,
1627 SourceEnumMediaTypes_AddRef
,
1628 SourceEnumMediaTypes_Release
,
1629 SourceEnumMediaTypes_Next
,
1630 SourceEnumMediaTypes_Skip
,
1631 SourceEnumMediaTypes_Reset
,
1632 SourceEnumMediaTypes_Clone
1635 static SourceEnumMediaTypes
* create_SourceEnumMediaTypes(SourceFilter
*filter
)
1637 SourceEnumMediaTypes
*This
;
1638 This
= CoTaskMemAlloc(sizeof(*This
));
1642 This
->IEnumMediaTypes_iface
.lpVtbl
= &SourceEnumMediaTypesVtbl
;
1645 This
->filter
= filter
;
1646 IBaseFilter_AddRef(&filter
->IBaseFilter_iface
);
1650 static HRESULT WINAPI
SourcePin_QueryInterface(IPin
*iface
, REFIID riid
, void **ppv
)
1652 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1653 if(IsEqualIID(riid
, &IID_IUnknown
)) {
1654 *ppv
= &This
->IPin_iface
;
1655 } else if(IsEqualIID(riid
, &IID_IPin
)) {
1656 *ppv
= &This
->IPin_iface
;
1657 } else if(IsEqualIID(riid
, &IID_IKsPropertySet
)) {
1658 *ppv
= &This
->IKsPropertySet_iface
;
1660 trace("no interface for %s\n", wine_dbgstr_guid(riid
));
1662 return E_NOINTERFACE
;
1664 IUnknown_AddRef((IUnknown
*)*ppv
);
1668 static ULONG WINAPI
SourcePin_AddRef(IPin
*iface
)
1670 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1671 return IBaseFilter_AddRef(&This
->IBaseFilter_iface
);
1674 static ULONG WINAPI
SourcePin_Release(IPin
*iface
)
1676 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1677 return IBaseFilter_Release(&This
->IBaseFilter_iface
);
1680 static HRESULT WINAPI
SourcePin_Connect(IPin
*iface
, IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
1682 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1685 if (pmt
&& !IsEqualGUID(&pmt
->majortype
, &GUID_NULL
) && !IsEqualGUID(&pmt
->majortype
, &MEDIATYPE_Video
))
1686 return VFW_E_TYPE_NOT_ACCEPTED
;
1687 if (pmt
&& !IsEqualGUID(&pmt
->subtype
, &GUID_NULL
) && !IsEqualGUID(&pmt
->subtype
, &MEDIASUBTYPE_RGB32
))
1688 return VFW_E_TYPE_NOT_ACCEPTED
;
1689 if (pmt
&& !IsEqualGUID(&pmt
->formattype
, &GUID_NULL
))
1690 return VFW_E_TYPE_NOT_ACCEPTED
;
1691 hr
= IPin_ReceiveConnection(pReceivePin
, &This
->IPin_iface
, &This
->mediaType
);
1692 ok(SUCCEEDED(hr
), "SmartTeeFilter's Input pin's IPin_ReceiveConnection() failed with 0x%08x\n", hr
);
1693 if (SUCCEEDED(hr
)) {
1694 EnterCriticalSection(&This
->cs
);
1695 hr
= IPin_QueryInterface(pReceivePin
, &IID_IMemInputPin
, (void**)&This
->memInputPin
);
1696 if (SUCCEEDED(hr
)) {
1697 hr
= IMemInputPin_GetAllocator(This
->memInputPin
, &This
->allocator
);
1698 ok(SUCCEEDED(hr
), "couldn't get allocator from SmartTeeFilter, hr=0x%08x\n", hr
);
1699 if (SUCCEEDED(hr
)) {
1700 ALLOCATOR_PROPERTIES requested
, actual
;
1701 ZeroMemory(&requested
, sizeof(ALLOCATOR_PROPERTIES
));
1702 IMemInputPin_GetAllocatorRequirements(This
->memInputPin
, &requested
);
1703 if (requested
.cBuffers
< 3) requested
.cBuffers
= 3;
1704 if (requested
.cbBuffer
< 4096) requested
.cbBuffer
= 4096;
1705 if (requested
.cbAlign
< 1) requested
.cbAlign
= 1;
1706 if (requested
.cbPrefix
< 0) requested
.cbPrefix
= 0;
1707 hr
= IMemAllocator_SetProperties(This
->allocator
, &requested
, &actual
);
1708 if (SUCCEEDED(hr
)) {
1709 hr
= IMemInputPin_NotifyAllocator(This
->memInputPin
, This
->allocator
, FALSE
);
1710 if (SUCCEEDED(hr
)) {
1711 This
->connectedTo
= pReceivePin
;
1712 IPin_AddRef(pReceivePin
);
1716 IMemAllocator_Release(This
->allocator
);
1717 This
->allocator
= NULL
;
1721 IMemInputPin_Release(This
->memInputPin
);
1722 This
->memInputPin
= NULL
;
1725 LeaveCriticalSection(&This
->cs
);
1728 IPin_Disconnect(pReceivePin
);
1733 static HRESULT WINAPI
SourcePin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*pmt
)
1735 return E_UNEXPECTED
;
1738 static HRESULT WINAPI
SourcePin_Disconnect(IPin
*iface
)
1740 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1742 EnterCriticalSection(&This
->cs
);
1743 if (This
->connectedTo
) {
1744 if (This
->state
== State_Stopped
) {
1745 IMemAllocator_Release(This
->allocator
);
1746 This
->allocator
= NULL
;
1747 IMemInputPin_Release(This
->memInputPin
);
1748 This
->memInputPin
= NULL
;
1749 IPin_Release(This
->connectedTo
);
1750 This
->connectedTo
= NULL
;
1754 hr
= VFW_E_NOT_STOPPED
;
1757 LeaveCriticalSection(&This
->cs
);
1761 static HRESULT WINAPI
SourcePin_ConnectedTo(IPin
*iface
, IPin
**pPin
)
1763 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1767 EnterCriticalSection(&This
->cs
);
1768 if (This
->connectedTo
) {
1769 *pPin
= This
->connectedTo
;
1770 IPin_AddRef(This
->connectedTo
);
1773 hr
= VFW_E_NOT_CONNECTED
;
1774 LeaveCriticalSection(&This
->cs
);
1778 static HRESULT WINAPI
SourcePin_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*pmt
)
1780 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1784 EnterCriticalSection(&This
->cs
);
1785 if (This
->connectedTo
) {
1786 *pmt
= This
->mediaType
;
1787 pmt
->pbFormat
= CoTaskMemAlloc(sizeof(This
->videoInfo
));
1788 if (pmt
->pbFormat
) {
1789 memcpy(pmt
->pbFormat
, &This
->videoInfo
, sizeof(This
->videoInfo
));
1792 memset(pmt
, 0, sizeof(*pmt
));
1796 memset(pmt
, 0, sizeof(*pmt
));
1797 hr
= VFW_E_NOT_CONNECTED
;
1799 LeaveCriticalSection(&This
->cs
);
1803 static HRESULT WINAPI
SourcePin_QueryPinInfo(IPin
*iface
, PIN_INFO
*pInfo
)
1805 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1808 lstrcpyW(pInfo
->achName
, sourcePinName
);
1809 pInfo
->dir
= PINDIR_OUTPUT
;
1810 pInfo
->pFilter
= &This
->IBaseFilter_iface
;
1811 IBaseFilter_AddRef(&This
->IBaseFilter_iface
);
1815 static HRESULT WINAPI
SourcePin_QueryDirection(IPin
*iface
, PIN_DIRECTION
*pPinDir
)
1819 *pPinDir
= PINDIR_OUTPUT
;
1823 static HRESULT WINAPI
SourcePin_QueryId(IPin
*iface
, LPWSTR
*id
)
1827 *id
= CoTaskMemAlloc((lstrlenW(sourcePinName
) + 1)*sizeof(WCHAR
));
1829 lstrcpyW(*id
, sourcePinName
);
1832 return E_OUTOFMEMORY
;
1835 static HRESULT WINAPI
SourcePin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*pmt
)
1840 static HRESULT WINAPI
SourcePin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**ppEnum
)
1842 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1843 SourceEnumMediaTypes
*sourceEnumMediaTypes
= create_SourceEnumMediaTypes(This
);
1844 if (sourceEnumMediaTypes
) {
1845 *ppEnum
= &sourceEnumMediaTypes
->IEnumMediaTypes_iface
;
1849 return E_OUTOFMEMORY
;
1852 static HRESULT WINAPI
SourcePin_QueryInternalConnections(IPin
*iface
, IPin
**apPin
, ULONG
*nPin
)
1857 static HRESULT WINAPI
SourcePin_EndOfStream(IPin
*iface
)
1859 return E_UNEXPECTED
;
1862 static HRESULT WINAPI
SourcePin_BeginFlush(IPin
*iface
)
1864 return E_UNEXPECTED
;
1867 static HRESULT WINAPI
SourcePin_EndFlush(IPin
*iface
)
1869 return E_UNEXPECTED
;
1872 static HRESULT WINAPI
SourcePin_NewSegment(IPin
*iface
, REFERENCE_TIME tStart
,
1873 REFERENCE_TIME tStop
, double dRate
)
1878 static const IPinVtbl SourcePinVtbl
= {
1879 SourcePin_QueryInterface
,
1883 SourcePin_ReceiveConnection
,
1884 SourcePin_Disconnect
,
1885 SourcePin_ConnectedTo
,
1886 SourcePin_ConnectionMediaType
,
1887 SourcePin_QueryPinInfo
,
1888 SourcePin_QueryDirection
,
1890 SourcePin_QueryAccept
,
1891 SourcePin_EnumMediaTypes
,
1892 SourcePin_QueryInternalConnections
,
1893 SourcePin_EndOfStream
,
1894 SourcePin_BeginFlush
,
1896 SourcePin_NewSegment
1899 static HRESULT WINAPI
SourceKSP_QueryInterface(IKsPropertySet
*iface
, REFIID riid
, LPVOID
*ppv
)
1901 SourceFilter
*This
= impl_from_SourceFilter_IKsPropertySet(iface
);
1902 return IPin_QueryInterface(&This
->IPin_iface
, riid
, ppv
);
1905 static ULONG WINAPI
SourceKSP_AddRef(IKsPropertySet
*iface
)
1907 SourceFilter
*This
= impl_from_SourceFilter_IKsPropertySet(iface
);
1908 return IBaseFilter_AddRef(&This
->IBaseFilter_iface
);
1911 static ULONG WINAPI
SourceKSP_Release(IKsPropertySet
*iface
)
1913 SourceFilter
*This
= impl_from_SourceFilter_IKsPropertySet(iface
);
1914 return IBaseFilter_Release(&This
->IBaseFilter_iface
);
1917 static HRESULT WINAPI
SourceKSP_Set(IKsPropertySet
*iface
, REFGUID guidPropSet
, DWORD dwPropID
,
1918 LPVOID pInstanceData
, DWORD cbInstanceData
, LPVOID pPropData
, DWORD cbPropData
)
1920 SourceFilter
*This
= impl_from_SourceFilter_IKsPropertySet(iface
);
1921 trace("(%p)->(%s, %u, %p, %u, %p, %u): stub\n", This
, wine_dbgstr_guid(guidPropSet
),
1922 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
);
1926 static HRESULT WINAPI
SourceKSP_Get(IKsPropertySet
*iface
, REFGUID guidPropSet
, DWORD dwPropID
,
1927 LPVOID pInstanceData
, DWORD cbInstanceData
, LPVOID pPropData
,
1928 DWORD cbPropData
, DWORD
*pcbReturned
)
1930 SourceFilter
*This
= impl_from_SourceFilter_IKsPropertySet(iface
);
1931 trace("(%p)->(%s, %u, %p, %u, %p, %u, %p)\n", This
, wine_dbgstr_guid(guidPropSet
),
1932 dwPropID
, pInstanceData
, cbInstanceData
, pPropData
, cbPropData
, pcbReturned
);
1933 if (IsEqualIID(guidPropSet
, &ROPSETID_Pin
)) {
1935 *pcbReturned
= sizeof(GUID
);
1937 LPGUID guid
= pPropData
;
1938 if (cbPropData
>= sizeof(GUID
))
1939 *guid
= PIN_CATEGORY_CAPTURE
;
1946 return E_PROP_SET_UNSUPPORTED
;
1949 static HRESULT WINAPI
SourceKSP_QuerySupported(IKsPropertySet
*iface
, REFGUID guidPropSet
,
1950 DWORD dwPropID
, DWORD
*pTypeSupport
)
1952 SourceFilter
*This
= impl_from_SourceFilter_IKsPropertySet(iface
);
1953 trace("(%p)->(%s, %u, %p): stub\n", This
, wine_dbgstr_guid(guidPropSet
),
1954 dwPropID
, pTypeSupport
);
1958 static const IKsPropertySetVtbl SourceKSPVtbl
=
1960 SourceKSP_QueryInterface
,
1965 SourceKSP_QuerySupported
1968 static SourceFilter
* create_SourceFilter(void)
1970 SourceFilter
*This
= NULL
;
1971 This
= CoTaskMemAlloc(sizeof(*This
));
1973 memset(This
, 0, sizeof(*This
));
1974 This
->IBaseFilter_iface
.lpVtbl
= &SourceFilterVtbl
;
1976 This
->IPin_iface
.lpVtbl
= &SourcePinVtbl
;
1977 This
->IKsPropertySet_iface
.lpVtbl
= &SourceKSPVtbl
;
1978 InitializeCriticalSection(&This
->cs
);
1984 static SourceFilter
* create_video_SourceFilter(void)
1986 SourceFilter
*This
= create_SourceFilter();
1989 This
->mediaType
.majortype
= MEDIATYPE_Video
;
1990 This
->mediaType
.subtype
= MEDIASUBTYPE_RGB32
;
1991 This
->mediaType
.bFixedSizeSamples
= FALSE
;
1992 This
->mediaType
.bTemporalCompression
= FALSE
;
1993 This
->mediaType
.lSampleSize
= 0;
1994 This
->mediaType
.formattype
= FORMAT_VideoInfo
;
1995 This
->mediaType
.pUnk
= NULL
;
1996 This
->mediaType
.cbFormat
= sizeof(VIDEOINFOHEADER
);
1997 This
->mediaType
.pbFormat
= (BYTE
*) &This
->videoInfo
;
1998 This
->videoInfo
.dwBitRate
= 1000000;
1999 This
->videoInfo
.dwBitErrorRate
= 0;
2000 This
->videoInfo
.AvgTimePerFrame
= 400000;
2001 This
->videoInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
2002 This
->videoInfo
.bmiHeader
.biWidth
= 10;
2003 This
->videoInfo
.bmiHeader
.biHeight
= 10;
2004 This
->videoInfo
.bmiHeader
.biPlanes
= 1;
2005 This
->videoInfo
.bmiHeader
.biBitCount
= 32;
2006 This
->videoInfo
.bmiHeader
.biCompression
= BI_RGB
;
2007 This
->videoInfo
.bmiHeader
.biSizeImage
= 0;
2008 This
->videoInfo
.bmiHeader
.biXPelsPerMeter
= 96;
2009 This
->videoInfo
.bmiHeader
.biYPelsPerMeter
= 96;
2010 This
->videoInfo
.bmiHeader
.biClrUsed
= 0;
2011 This
->videoInfo
.bmiHeader
.biClrImportant
= 0;
2015 static void test_smart_tee_filter_in_graph(IBaseFilter
*smartTeeFilter
, IPin
*inputPin
,
2016 IPin
*capturePin
, IPin
*previewPin
)
2019 IGraphBuilder
*graphBuilder
= NULL
;
2020 IMediaControl
*mediaControl
= NULL
;
2021 SourceFilter
*sourceFilter
= NULL
;
2022 SinkFilter
*captureSinkFilter
= NULL
;
2023 SinkFilter
*previewSinkFilter
= NULL
;
2026 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IGraphBuilder
,
2027 (LPVOID
*)&graphBuilder
);
2028 ok(SUCCEEDED(hr
), "couldn't create graph builder, hr=0x%08x\n", hr
);
2032 hr
= IGraphBuilder_AddFilter(graphBuilder
, smartTeeFilter
, NULL
);
2033 ok(SUCCEEDED(hr
), "couldn't add smart tee filter to graph, hr=0x%08x\n", hr
);
2037 captureSinkFilter
= create_SinkFilter(TRUE
);
2038 if (captureSinkFilter
== NULL
) {
2039 skip("couldn't create capture sink filter\n");
2042 hr
= IGraphBuilder_AddFilter(graphBuilder
, &captureSinkFilter
->IBaseFilter_iface
, NULL
);
2044 skip("couldn't add capture sink filter to graph, hr=0x%08x\n", hr
);
2048 previewSinkFilter
= create_SinkFilter(FALSE
);
2049 if (previewSinkFilter
== NULL
) {
2050 skip("couldn't create preview sink filter\n");
2053 hr
= IGraphBuilder_AddFilter(graphBuilder
, &previewSinkFilter
->IBaseFilter_iface
, NULL
);
2055 skip("couldn't add preview sink filter to graph, hr=0x%08x\n", hr
);
2059 hr
= IGraphBuilder_Connect(graphBuilder
, capturePin
, &captureSinkFilter
->IPin_iface
);
2060 ok(hr
== VFW_E_NOT_CONNECTED
, "connecting Capture pin without first connecting Input pin returned 0x%08x\n", hr
);
2061 hr
= IGraphBuilder_Connect(graphBuilder
, previewPin
, &previewSinkFilter
->IPin_iface
);
2062 ok(hr
== VFW_E_NOT_CONNECTED
, "connecting Preview pin without first connecting Input pin returned 0x%08x\n", hr
);
2064 sourceFilter
= create_video_SourceFilter();
2065 if (sourceFilter
== NULL
) {
2066 skip("couldn't create source filter\n");
2069 hr
= IGraphBuilder_AddFilter(graphBuilder
, &sourceFilter
->IBaseFilter_iface
, NULL
);
2070 ok(SUCCEEDED(hr
), "couldn't add source filter to graph, hr=0x%08x\n", hr
);
2074 hr
= IGraphBuilder_Connect(graphBuilder
, &sourceFilter
->IPin_iface
, inputPin
);
2075 ok(SUCCEEDED(hr
), "couldn't connect source filter to Input pin, hr=0x%08x\n", hr
);
2078 hr
= IGraphBuilder_Connect(graphBuilder
, capturePin
, &captureSinkFilter
->IPin_iface
);
2079 ok(SUCCEEDED(hr
), "couldn't connect Capture pin to sink, hr=0x%08x\n", hr
);
2082 hr
= IGraphBuilder_Connect(graphBuilder
, previewPin
, &previewSinkFilter
->IPin_iface
);
2083 ok(SUCCEEDED(hr
), "couldn't connect Preview pin to sink, hr=0x%08x\n", hr
);
2087 ok(sourceFilter
->allocator
== captureSinkFilter
->allocator
, "input and capture allocators don't match\n");
2088 ok(sourceFilter
->allocator
== previewSinkFilter
->allocator
, "input and preview allocators don't match\n");
2090 hr
= IGraphBuilder_QueryInterface(graphBuilder
, &IID_IMediaControl
, (void**)&mediaControl
);
2091 ok(SUCCEEDED(hr
), "couldn't get IMediaControl interface from IGraphBuilder, hr=0x%08x\n", hr
);
2094 hr
= IMediaControl_Run(mediaControl
);
2095 ok(SUCCEEDED(hr
), "IMediaControl_Run() failed, hr=0x%08x\n", hr
);
2099 endTime
= GetTickCount() + 5000;
2100 while (previewSinkFilter
->receiveThreadId
== 0 || captureSinkFilter
->receiveThreadId
== 0) {
2101 DWORD now
= GetTickCount();
2103 WaitForSingleObject(event
, endTime
- now
);
2107 if (previewSinkFilter
->receiveThreadId
!= 0 && captureSinkFilter
->receiveThreadId
!= 0) {
2108 todo_wine
ok(sourceFilter
->mediaThreadId
!= captureSinkFilter
->receiveThreadId
,
2109 "sending thread should != capture receiving thread\n");
2110 todo_wine
ok(sourceFilter
->mediaThreadId
!= previewSinkFilter
->receiveThreadId
,
2111 "sending thread should != preview receiving thread\n");
2112 todo_wine
ok(captureSinkFilter
->receiveThreadId
!= previewSinkFilter
->receiveThreadId
,
2113 "capture receiving thread should != preview receiving thread\n");
2115 ok(0, "timeout: threads did not receive sample in time\n");
2118 IMediaControl_Stop(mediaControl
);
2122 IMediaControl_Release(mediaControl
);
2124 IGraphBuilder_Release(graphBuilder
);
2126 IBaseFilter_Release(&sourceFilter
->IBaseFilter_iface
);
2127 if (captureSinkFilter
)
2128 IBaseFilter_Release(&captureSinkFilter
->IBaseFilter_iface
);
2129 if (previewSinkFilter
)
2130 IBaseFilter_Release(&previewSinkFilter
->IBaseFilter_iface
);
2133 static void test_smart_tee_filter(void)
2136 IBaseFilter
*smartTeeFilter
= NULL
;
2137 IEnumPins
*enumPins
= NULL
;
2139 IPin
*inputPin
= NULL
;
2140 IPin
*capturePin
= NULL
;
2141 IPin
*previewPin
= NULL
;
2142 FILTER_INFO filterInfo
;
2144 IMemInputPin
*memInputPin
= NULL
;
2146 hr
= CoCreateInstance(&CLSID_SmartTee
, NULL
, CLSCTX_INPROC_SERVER
,
2147 &IID_IBaseFilter
, (void**)&smartTeeFilter
);
2148 ok(SUCCEEDED(hr
), "couldn't create smart tee filter, hr=0x%08x\n", hr
);
2152 hr
= IBaseFilter_QueryFilterInfo(smartTeeFilter
, &filterInfo
);
2153 ok(SUCCEEDED(hr
), "QueryFilterInfo failed, hr=0x%08x\n", hr
);
2157 ok(!*filterInfo
.achName
,
2158 "filter's name is meant to be empty but it's %s\n", wine_dbgstr_w(filterInfo
.achName
));
2160 hr
= IBaseFilter_EnumPins(smartTeeFilter
, &enumPins
);
2161 ok(SUCCEEDED(hr
), "cannot enum filter pins, hr=0x%08x\n", hr
);
2165 while (IEnumPins_Next(enumPins
, 1, &pin
, NULL
) == S_OK
)
2170 IPin_AddRef(inputPin
);
2172 else if (pinNumber
== 1)
2175 IPin_AddRef(capturePin
);
2177 else if (pinNumber
== 2)
2180 IPin_AddRef(previewPin
);
2183 ok(0, "pin %d isn't supposed to exist\n", pinNumber
);
2189 ok(inputPin
&& capturePin
&& previewPin
, "couldn't find all pins\n");
2190 if (!(inputPin
&& capturePin
&& previewPin
))
2193 hr
= IPin_QueryInterface(inputPin
, &IID_IMemInputPin
, (void**)&memInputPin
);
2194 ok(SUCCEEDED(hr
), "couldn't get mem input pin, hr=0x%08x\n", hr
);
2197 hr
= IMemInputPin_ReceiveCanBlock(memInputPin
);
2198 ok(hr
== S_OK
, "unexpected IMemInputPin_ReceiveCanBlock() = 0x%08x\n", hr
);
2200 test_smart_tee_filter_in_graph(smartTeeFilter
, inputPin
, capturePin
, previewPin
);
2204 IPin_Release(inputPin
);
2206 IPin_Release(capturePin
);
2208 IPin_Release(previewPin
);
2210 IBaseFilter_Release(smartTeeFilter
);
2212 IEnumPins_Release(enumPins
);
2214 IMemInputPin_Release(memInputPin
);
2217 static void test_unconnected_filter_state(void)
2219 IBaseFilter
*filter
= create_smart_tee();
2224 hr
= IBaseFilter_GetState(filter
, 0, &state
);
2225 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2226 ok(state
== State_Stopped
, "Got state %u.\n", state
);
2228 hr
= IBaseFilter_Pause(filter
);
2229 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2231 hr
= IBaseFilter_GetState(filter
, 0, &state
);
2232 ok(hr
== VFW_S_CANT_CUE
, "Got hr %#x.\n", hr
);
2233 ok(state
== State_Paused
, "Got state %u.\n", state
);
2235 hr
= IBaseFilter_Run(filter
, 0);
2236 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2238 hr
= IBaseFilter_GetState(filter
, 0, &state
);
2239 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2240 ok(state
== State_Running
, "Got state %u.\n", state
);
2242 hr
= IBaseFilter_Pause(filter
);
2243 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2245 hr
= IBaseFilter_GetState(filter
, 0, &state
);
2246 ok(hr
== VFW_S_CANT_CUE
, "Got hr %#x.\n", hr
);
2247 ok(state
== State_Paused
, "Got state %u.\n", state
);
2249 hr
= IBaseFilter_Stop(filter
);
2250 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2252 hr
= IBaseFilter_GetState(filter
, 0, &state
);
2253 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2254 ok(state
== State_Stopped
, "Got state %u.\n", state
);
2256 hr
= IBaseFilter_Run(filter
, 0);
2257 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2259 hr
= IBaseFilter_GetState(filter
, 0, &state
);
2260 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2261 ok(state
== State_Running
, "Got state %u.\n", state
);
2263 hr
= IBaseFilter_Stop(filter
);
2264 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2266 hr
= IBaseFilter_GetState(filter
, 0, &state
);
2267 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2268 ok(state
== State_Stopped
, "Got state %u.\n", state
);
2270 ref
= IBaseFilter_Release(filter
);
2271 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2276 struct strmbase_filter filter
;
2277 struct strmbase_source source
;
2278 struct strmbase_sink sink
;
2279 const AM_MEDIA_TYPE
*sink_mt
;
2280 AM_MEDIA_TYPE source_mt
;
2283 static inline struct testfilter
*impl_from_strmbase_filter(struct strmbase_filter
*iface
)
2285 return CONTAINING_RECORD(iface
, struct testfilter
, filter
);
2288 static struct strmbase_pin
*testfilter_get_pin(struct strmbase_filter
*iface
, unsigned int index
)
2290 struct testfilter
*filter
= impl_from_strmbase_filter(iface
);
2292 return &filter
->source
.pin
;
2293 else if (index
== 1)
2294 return &filter
->sink
.pin
;
2298 static void testfilter_destroy(struct strmbase_filter
*iface
)
2300 struct testfilter
*filter
= impl_from_strmbase_filter(iface
);
2301 strmbase_source_cleanup(&filter
->source
);
2302 strmbase_sink_cleanup(&filter
->sink
);
2303 strmbase_filter_cleanup(&filter
->filter
);
2306 static const struct strmbase_filter_ops testfilter_ops
=
2308 .filter_get_pin
= testfilter_get_pin
,
2309 .filter_destroy
= testfilter_destroy
,
2312 static HRESULT
testsource_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*mt
)
2314 return mt
->bTemporalCompression
? S_OK
: S_FALSE
;
2317 static HRESULT
testsource_get_media_type(struct strmbase_pin
*iface
, unsigned int index
, AM_MEDIA_TYPE
*mt
)
2319 struct testfilter
*filter
= impl_from_strmbase_filter(iface
->filter
);
2322 CopyMediaType(mt
, &filter
->source_mt
);
2325 return VFW_S_NO_MORE_ITEMS
;
2328 static void test_sink_allocator(IPin
*pin
)
2330 ALLOCATOR_PROPERTIES req_props
= {1, 5000, 1, 0}, ret_props
;
2331 IMemAllocator
*req_allocator
, *ret_allocator
;
2332 IMemInputPin
*input
;
2335 IPin_QueryInterface(pin
, &IID_IMemInputPin
, (void **)&input
);
2337 hr
= IMemInputPin_GetAllocatorRequirements(input
, &ret_props
);
2338 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
2340 hr
= IMemInputPin_GetAllocator(input
, &ret_allocator
);
2341 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2343 hr
= IMemInputPin_NotifyAllocator(input
, ret_allocator
, TRUE
);
2344 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2345 IMemAllocator_Release(ret_allocator
);
2347 CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
,
2348 &IID_IMemAllocator
, (void **)&req_allocator
);
2350 hr
= IMemInputPin_NotifyAllocator(input
, req_allocator
, TRUE
);
2351 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2353 hr
= IMemInputPin_GetAllocator(input
, &ret_allocator
);
2354 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2355 ok(ret_allocator
== req_allocator
, "Allocators didn't match.\n");
2356 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2357 IMemAllocator_Release(ret_allocator
);
2359 hr
= IMemAllocator_SetProperties(req_allocator
, &req_props
, &ret_props
);
2360 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2362 hr
= IMemAllocator_Commit(req_allocator
);
2363 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2365 IMemAllocator_Release(req_allocator
);
2366 IMemInputPin_Release(input
);
2369 static HRESULT WINAPI
testsource_AttemptConnection(struct strmbase_source
*iface
,
2370 IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
2374 iface
->pin
.peer
= peer
;
2376 CopyMediaType(&iface
->pin
.mt
, mt
);
2378 if (FAILED(hr
= IPin_ReceiveConnection(peer
, &iface
->pin
.IPin_iface
, mt
)))
2380 ok(hr
== VFW_E_TYPE_NOT_ACCEPTED
, "Got hr %#x.\n", hr
);
2382 iface
->pin
.peer
= NULL
;
2383 FreeMediaType(&iface
->pin
.mt
);
2386 test_sink_allocator(peer
);
2391 static const struct strmbase_source_ops testsource_ops
=
2393 .base
.pin_query_accept
= testsource_query_accept
,
2394 .base
.pin_get_media_type
= testsource_get_media_type
,
2395 .pfnAttemptConnection
= testsource_AttemptConnection
,
2398 static HRESULT
testsink_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
2400 struct testfilter
*filter
= impl_from_strmbase_filter(iface
->filter
);
2402 if (IsEqualGUID(iid
, &IID_IMemInputPin
))
2403 *out
= &filter
->sink
.IMemInputPin_iface
;
2405 return E_NOINTERFACE
;
2407 IUnknown_AddRef((IUnknown
*)*out
);
2411 static HRESULT
testsink_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*mt
)
2413 struct testfilter
*filter
= impl_from_strmbase_filter(iface
->filter
);
2414 if (filter
->sink_mt
&& !compare_media_types(mt
, filter
->sink_mt
))
2419 static HRESULT
testsink_get_media_type(struct strmbase_pin
*iface
, unsigned int index
, AM_MEDIA_TYPE
*mt
)
2421 struct testfilter
*filter
= impl_from_strmbase_filter(iface
->filter
);
2422 if (!index
&& filter
->sink_mt
)
2424 CopyMediaType(mt
, filter
->sink_mt
);
2427 return VFW_S_NO_MORE_ITEMS
;
2430 static HRESULT WINAPI
testsink_Receive(struct strmbase_sink
*iface
, IMediaSample
*sample
)
2435 static const struct strmbase_sink_ops testsink_ops
=
2437 .base
.pin_query_interface
= testsink_query_interface
,
2438 .base
.pin_query_accept
= testsink_query_accept
,
2439 .base
.pin_get_media_type
= testsink_get_media_type
,
2440 .pfnReceive
= testsink_Receive
,
2443 static void testfilter_init(struct testfilter
*filter
)
2445 static const GUID clsid
= {0xabacab};
2446 memset(filter
, 0, sizeof(*filter
));
2447 strmbase_filter_init(&filter
->filter
, NULL
, &clsid
, &testfilter_ops
);
2448 strmbase_source_init(&filter
->source
, &filter
->filter
, L
"source", &testsource_ops
);
2449 strmbase_sink_init(&filter
->sink
, &filter
->filter
, L
"sink", &testsink_ops
, NULL
);
2452 static void test_source_media_types(AM_MEDIA_TYPE req_mt
, const AM_MEDIA_TYPE
*source_mt
, IPin
*source
)
2454 IEnumMediaTypes
*enummt
;
2455 AM_MEDIA_TYPE
*mts
[3];
2459 hr
= IPin_EnumMediaTypes(source
, &enummt
);
2460 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2461 hr
= IEnumMediaTypes_Next(enummt
, 3, mts
, &count
);
2462 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2463 todo_wine
ok(count
== 2, "Got %u types.\n", count
);
2464 ok(compare_media_types(mts
[0], &req_mt
), "Media types didn't match.\n");
2466 ok(compare_media_types(mts
[1], source_mt
), "Media types didn't match.\n");
2467 CoTaskMemFree(mts
[0]);
2469 CoTaskMemFree(mts
[1]);
2470 IEnumMediaTypes_Release(enummt
);
2472 hr
= IPin_QueryAccept(source
, &req_mt
);
2473 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2475 req_mt
.lSampleSize
= 2;
2476 req_mt
.bFixedSizeSamples
= TRUE
;
2477 hr
= IPin_QueryAccept(source
, &req_mt
);
2478 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2480 req_mt
.cbFormat
= sizeof(count
);
2481 req_mt
.pbFormat
= (BYTE
*)&count
;
2482 hr
= IPin_QueryAccept(source
, &req_mt
);
2483 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2484 req_mt
.cbFormat
= 0;
2485 req_mt
.pbFormat
= NULL
;
2487 req_mt
.majortype
= MEDIATYPE_Audio
;
2488 hr
= IPin_QueryAccept(source
, &req_mt
);
2489 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2490 req_mt
.majortype
= GUID_NULL
;
2491 hr
= IPin_QueryAccept(source
, &req_mt
);
2492 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2493 req_mt
.majortype
= MEDIATYPE_Stream
;
2495 req_mt
.subtype
= MEDIASUBTYPE_PCM
;
2496 hr
= IPin_QueryAccept(source
, &req_mt
);
2497 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2498 req_mt
.subtype
= GUID_NULL
;
2499 hr
= IPin_QueryAccept(source
, &req_mt
);
2500 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2501 req_mt
.subtype
= MEDIASUBTYPE_Avi
;
2503 req_mt
.formattype
= FORMAT_WaveFormatEx
;
2504 hr
= IPin_QueryAccept(source
, &req_mt
);
2505 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2506 req_mt
.formattype
= GUID_NULL
;
2507 hr
= IPin_QueryAccept(source
, &req_mt
);
2508 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2509 req_mt
.formattype
= FORMAT_None
;
2511 req_mt
.majortype
= MEDIATYPE_Audio
;
2512 req_mt
.subtype
= MEDIASUBTYPE_PCM
;
2513 req_mt
.formattype
= test_iid
;
2514 req_mt
.cbFormat
= sizeof(count
);
2515 req_mt
.pbFormat
= (BYTE
*)&count
;
2516 req_mt
.bTemporalCompression
= TRUE
;
2517 hr
= IPin_QueryAccept(source
, &req_mt
);
2518 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2521 static void test_source_connection(AM_MEDIA_TYPE req_mt
, IFilterGraph2
*graph
,
2522 struct testfilter
*testsink
, IPin
*source
)
2524 const AM_MEDIA_TYPE sink_mt
= req_mt
;
2529 peer
= (IPin
*)0xdeadbeef;
2530 hr
= IPin_ConnectedTo(source
, &peer
);
2531 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
2532 ok(!peer
, "Got peer %p.\n", peer
);
2534 hr
= IPin_ConnectionMediaType(source
, &mt
);
2535 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
2537 /* Exact connection. */
2539 hr
= IFilterGraph2_ConnectDirect(graph
, source
, &testsink
->sink
.pin
.IPin_iface
, &req_mt
);
2540 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2542 hr
= IPin_ConnectedTo(source
, &peer
);
2543 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2544 ok(peer
== &testsink
->sink
.pin
.IPin_iface
, "Got peer %p.\n", peer
);
2547 hr
= IPin_ConnectionMediaType(source
, &mt
);
2548 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2549 ok(compare_media_types(&mt
, &req_mt
), "Media types didn't match.\n");
2550 ok(compare_media_types(&testsink
->sink
.pin
.mt
, &req_mt
), "Media types didn't match.\n");
2552 hr
= IFilterGraph2_Disconnect(graph
, source
);
2553 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2554 hr
= IFilterGraph2_Disconnect(graph
, source
);
2555 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2556 ok(testsink
->sink
.pin
.peer
== source
, "Got peer %p.\n", testsink
->sink
.pin
.peer
);
2557 IFilterGraph2_Disconnect(graph
, &testsink
->sink
.pin
.IPin_iface
);
2559 req_mt
.subtype
= GUID_NULL
;
2560 hr
= IFilterGraph2_ConnectDirect(graph
, source
, &testsink
->sink
.pin
.IPin_iface
, &req_mt
);
2561 todo_wine
ok(hr
== VFW_E_TYPE_NOT_ACCEPTED
, "Got hr %#x.\n", hr
);
2564 IFilterGraph2_Disconnect(graph
, source
);
2565 IFilterGraph2_Disconnect(graph
, &testsink
->sink
.pin
.IPin_iface
);
2567 req_mt
.subtype
= sink_mt
.subtype
;
2569 req_mt
.majortype
= MEDIATYPE_Audio
;
2570 hr
= IFilterGraph2_ConnectDirect(graph
, source
, &testsink
->sink
.pin
.IPin_iface
, &req_mt
);
2571 todo_wine
ok(hr
== VFW_E_TYPE_NOT_ACCEPTED
, "Got hr %#x.\n", hr
);
2574 IFilterGraph2_Disconnect(graph
, source
);
2575 IFilterGraph2_Disconnect(graph
, &testsink
->sink
.pin
.IPin_iface
);
2578 /* Connection with wildcards. */
2580 hr
= IFilterGraph2_ConnectDirect(graph
, source
, &testsink
->sink
.pin
.IPin_iface
, NULL
);
2581 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2582 ok(compare_media_types(&testsink
->sink
.pin
.mt
, &sink_mt
), "Media types didn't match.\n");
2583 IFilterGraph2_Disconnect(graph
, source
);
2584 IFilterGraph2_Disconnect(graph
, &testsink
->sink
.pin
.IPin_iface
);
2586 req_mt
.majortype
= GUID_NULL
;
2587 hr
= IFilterGraph2_ConnectDirect(graph
, source
, &testsink
->sink
.pin
.IPin_iface
, &req_mt
);
2588 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2589 ok(compare_media_types(&testsink
->sink
.pin
.mt
, &sink_mt
), "Media types didn't match.\n");
2590 IFilterGraph2_Disconnect(graph
, source
);
2591 IFilterGraph2_Disconnect(graph
, &testsink
->sink
.pin
.IPin_iface
);
2593 req_mt
.subtype
= MEDIASUBTYPE_RGB32
;
2594 hr
= IFilterGraph2_ConnectDirect(graph
, source
, &testsink
->sink
.pin
.IPin_iface
, &req_mt
);
2595 ok(hr
== VFW_E_NO_ACCEPTABLE_TYPES
, "Got hr %#x.\n", hr
);
2597 req_mt
.subtype
= GUID_NULL
;
2598 hr
= IFilterGraph2_ConnectDirect(graph
, source
, &testsink
->sink
.pin
.IPin_iface
, &req_mt
);
2599 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2600 ok(compare_media_types(&testsink
->sink
.pin
.mt
, &sink_mt
), "Media types didn't match.\n");
2601 IFilterGraph2_Disconnect(graph
, source
);
2602 IFilterGraph2_Disconnect(graph
, &testsink
->sink
.pin
.IPin_iface
);
2604 req_mt
.formattype
= FORMAT_WaveFormatEx
;
2605 hr
= IFilterGraph2_ConnectDirect(graph
, source
, &testsink
->sink
.pin
.IPin_iface
, &req_mt
);
2606 ok(hr
== VFW_E_NO_ACCEPTABLE_TYPES
, "Got hr %#x.\n", hr
);
2609 req_mt
.formattype
= GUID_NULL
;
2610 hr
= IFilterGraph2_ConnectDirect(graph
, source
, &testsink
->sink
.pin
.IPin_iface
, &req_mt
);
2611 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2612 ok(compare_media_types(&testsink
->sink
.pin
.mt
, &sink_mt
), "Media types didn't match.\n");
2613 IFilterGraph2_Disconnect(graph
, source
);
2614 IFilterGraph2_Disconnect(graph
, &testsink
->sink
.pin
.IPin_iface
);
2616 req_mt
.subtype
= MEDIASUBTYPE_RGB32
;
2617 hr
= IFilterGraph2_ConnectDirect(graph
, source
, &testsink
->sink
.pin
.IPin_iface
, &req_mt
);
2618 ok(hr
== VFW_E_NO_ACCEPTABLE_TYPES
, "Got hr %#x.\n", hr
);
2620 req_mt
.subtype
= GUID_NULL
;
2621 hr
= IFilterGraph2_ConnectDirect(graph
, source
, &testsink
->sink
.pin
.IPin_iface
, &req_mt
);
2622 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2623 ok(compare_media_types(&testsink
->sink
.pin
.mt
, &sink_mt
), "Media types didn't match.\n");
2624 IFilterGraph2_Disconnect(graph
, source
);
2625 IFilterGraph2_Disconnect(graph
, &testsink
->sink
.pin
.IPin_iface
);
2627 req_mt
.majortype
= MEDIATYPE_Audio
;
2628 hr
= IFilterGraph2_ConnectDirect(graph
, source
, &testsink
->sink
.pin
.IPin_iface
, &req_mt
);
2629 ok(hr
== VFW_E_NO_ACCEPTABLE_TYPES
, "Got hr %#x.\n", hr
);
2631 testsink
->sink_mt
= &req_mt
;
2632 hr
= IFilterGraph2_ConnectDirect(graph
, source
, &testsink
->sink
.pin
.IPin_iface
, NULL
);
2633 todo_wine
ok(hr
== VFW_E_NO_ACCEPTABLE_TYPES
, "Got hr %#x.\n", hr
);
2636 IFilterGraph2_Disconnect(graph
, source
);
2637 IFilterGraph2_Disconnect(graph
, &testsink
->sink
.pin
.IPin_iface
);
2641 req_mt
.lSampleSize
= 3;
2642 hr
= IFilterGraph2_ConnectDirect(graph
, source
, &testsink
->sink
.pin
.IPin_iface
, NULL
);
2643 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2644 ok(compare_media_types(&testsink
->sink
.pin
.mt
, &req_mt
), "Media types didn't match.\n");
2645 IFilterGraph2_Disconnect(graph
, source
);
2646 IFilterGraph2_Disconnect(graph
, &testsink
->sink
.pin
.IPin_iface
);
2648 testsink
->sink_mt
= NULL
;
2651 static void test_connect_pin(void)
2653 AM_MEDIA_TYPE req_mt
=
2655 .majortype
= MEDIATYPE_Stream
,
2656 .subtype
= MEDIASUBTYPE_Avi
,
2657 .formattype
= FORMAT_None
,
2660 IBaseFilter
*filter
= create_smart_tee();
2661 struct testfilter testsource
, testsink
;
2662 IPin
*sink
, *capture
, *preview
, *peer
;
2663 AM_MEDIA_TYPE mt
, *mts
[3];
2664 IEnumMediaTypes
*enummt
;
2665 IFilterGraph2
*graph
;
2669 testfilter_init(&testsource
);
2670 testfilter_init(&testsink
);
2671 CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
2672 &IID_IFilterGraph2
, (void **)&graph
);
2673 IFilterGraph2_AddFilter(graph
, &testsource
.filter
.IBaseFilter_iface
, L
"source");
2674 IFilterGraph2_AddFilter(graph
, &testsink
.filter
.IBaseFilter_iface
, L
"sink");
2675 IFilterGraph2_AddFilter(graph
, filter
, L
"sample grabber");
2676 IBaseFilter_FindPin(filter
, L
"Input", &sink
);
2677 IBaseFilter_FindPin(filter
, L
"Capture", &capture
);
2678 IBaseFilter_FindPin(filter
, L
"Preview", &preview
);
2680 testsource
.source_mt
.majortype
= MEDIATYPE_Video
;
2681 testsource
.source_mt
.subtype
= MEDIASUBTYPE_RGB8
;
2682 testsource
.source_mt
.formattype
= FORMAT_VideoInfo
;
2684 hr
= IPin_EnumMediaTypes(sink
, &enummt
);
2685 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2686 hr
= IEnumMediaTypes_Next(enummt
, 1, mts
, NULL
);
2687 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2688 IEnumMediaTypes_Release(enummt
);
2690 hr
= IPin_EnumMediaTypes(capture
, &enummt
);
2691 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
2692 hr
= IPin_EnumMediaTypes(preview
, &enummt
);
2693 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
2695 hr
= IPin_QueryAccept(sink
, &req_mt
);
2696 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2697 hr
= IPin_QueryAccept(capture
, &req_mt
);
2698 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2699 hr
= IPin_QueryAccept(preview
, &req_mt
);
2700 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2702 /* Test sink connection. */
2704 peer
= (IPin
*)0xdeadbeef;
2705 hr
= IPin_ConnectedTo(sink
, &peer
);
2706 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
2707 ok(!peer
, "Got peer %p.\n", peer
);
2709 hr
= IPin_ConnectionMediaType(sink
, &mt
);
2710 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
2712 hr
= IFilterGraph2_ConnectDirect(graph
, &testsource
.source
.pin
.IPin_iface
, sink
, &req_mt
);
2713 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2715 hr
= IPin_ConnectedTo(sink
, &peer
);
2716 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2717 ok(peer
== &testsource
.source
.pin
.IPin_iface
, "Got peer %p.\n", peer
);
2720 hr
= IPin_ConnectionMediaType(sink
, &mt
);
2721 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2722 ok(compare_media_types(&mt
, &req_mt
), "Media types didn't match.\n");
2724 hr
= IPin_EnumMediaTypes(sink
, &enummt
);
2725 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2726 hr
= IEnumMediaTypes_Next(enummt
, 1, mts
, NULL
);
2727 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2728 IEnumMediaTypes_Release(enummt
);
2730 test_source_media_types(req_mt
, &testsource
.source_mt
, capture
);
2731 test_source_media_types(req_mt
, &testsource
.source_mt
, preview
);
2732 test_source_connection(req_mt
, graph
, &testsink
, capture
);
2733 test_source_connection(req_mt
, graph
, &testsink
, preview
);
2735 hr
= IFilterGraph2_Disconnect(graph
, sink
);
2736 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2737 hr
= IFilterGraph2_Disconnect(graph
, sink
);
2738 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2739 ok(testsource
.source
.pin
.peer
== sink
, "Got peer %p.\n", testsource
.source
.pin
.peer
);
2740 IFilterGraph2_Disconnect(graph
, &testsource
.source
.pin
.IPin_iface
);
2742 peer
= (IPin
*)0xdeadbeef;
2743 hr
= IPin_ConnectedTo(sink
, &peer
);
2744 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
2745 ok(!peer
, "Got peer %p.\n", peer
);
2747 hr
= IPin_ConnectionMediaType(sink
, &mt
);
2748 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
2751 IPin_Release(capture
);
2752 IPin_Release(preview
);
2753 ref
= IFilterGraph2_Release(graph
);
2754 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2755 ref
= IBaseFilter_Release(filter
);
2756 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2757 ref
= IBaseFilter_Release(&testsource
.filter
.IBaseFilter_iface
);
2758 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2759 ref
= IBaseFilter_Release(&testsink
.filter
.IBaseFilter_iface
);
2760 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2763 START_TEST(smartteefilter
)
2767 event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
2774 test_enum_media_types();
2775 test_unconnected_filter_state();
2778 test_smart_tee_filter();