2 * Null renderer filter unit tests
4 * Copyright 2018 Zebediah Figura
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 IBaseFilter
*create_null_renderer(void)
28 IBaseFilter
*filter
= NULL
;
29 HRESULT hr
= CoCreateInstance(&CLSID_NullRenderer
, NULL
, CLSCTX_INPROC_SERVER
,
30 &IID_IBaseFilter
, (void **)&filter
);
31 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
35 static ULONG
get_refcount(void *iface
)
37 IUnknown
*unknown
= iface
;
38 IUnknown_AddRef(unknown
);
39 return IUnknown_Release(unknown
);
42 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
43 static void check_interface_(unsigned int line
, void *iface_ptr
, REFIID iid
, BOOL supported
)
45 IUnknown
*iface
= iface_ptr
;
46 HRESULT hr
, expected_hr
;
49 expected_hr
= supported
? S_OK
: E_NOINTERFACE
;
51 hr
= IUnknown_QueryInterface(iface
, iid
, (void **)&unk
);
52 ok_(__FILE__
, line
)(hr
== expected_hr
, "Got hr %#x, expected %#x.\n", hr
, expected_hr
);
54 IUnknown_Release(unk
);
57 static void test_interfaces(void)
59 IBaseFilter
*filter
= create_null_renderer();
63 check_interface(filter
, &IID_IBaseFilter
, TRUE
);
64 check_interface(filter
, &IID_IMediaFilter
, TRUE
);
65 check_interface(filter
, &IID_IMediaPosition
, TRUE
);
66 check_interface(filter
, &IID_IMediaSeeking
, TRUE
);
67 check_interface(filter
, &IID_IPersist
, TRUE
);
68 check_interface(filter
, &IID_IUnknown
, TRUE
);
70 check_interface(filter
, &IID_IAMFilterMiscFlags
, FALSE
);
71 check_interface(filter
, &IID_IBasicAudio
, FALSE
);
72 check_interface(filter
, &IID_IBasicVideo
, FALSE
);
73 check_interface(filter
, &IID_IKsPropertySet
, FALSE
);
74 check_interface(filter
, &IID_IPersistPropertyBag
, FALSE
);
75 check_interface(filter
, &IID_IPin
, FALSE
);
76 todo_wine
check_interface(filter
, &IID_IQualityControl
, FALSE
);
77 check_interface(filter
, &IID_IQualProp
, FALSE
);
78 check_interface(filter
, &IID_IReferenceClock
, FALSE
);
79 check_interface(filter
, &IID_IVideoWindow
, FALSE
);
81 IBaseFilter_FindPin(filter
, L
"In", &pin
);
83 check_interface(pin
, &IID_IMemInputPin
, TRUE
);
84 check_interface(pin
, &IID_IPin
, TRUE
);
85 todo_wine
check_interface(pin
, &IID_IQualityControl
, TRUE
);
86 check_interface(pin
, &IID_IUnknown
, TRUE
);
88 check_interface(pin
, &IID_IKsPropertySet
, FALSE
);
89 check_interface(pin
, &IID_IMediaPosition
, FALSE
);
90 check_interface(pin
, &IID_IMediaSeeking
, FALSE
);
93 ref
= IBaseFilter_Release(filter
);
94 ok(!ref
, "Got unexpected refcount %d.\n", ref
);
97 static void test_enum_pins(void)
99 IBaseFilter
*filter
= create_null_renderer();
100 IEnumPins
*enum1
, *enum2
;
105 ref
= get_refcount(filter
);
106 ok(ref
== 1, "Got unexpected refcount %d.\n", ref
);
108 hr
= IBaseFilter_EnumPins(filter
, NULL
);
109 ok(hr
== E_POINTER
, "Got hr %#x.\n", hr
);
111 hr
= IBaseFilter_EnumPins(filter
, &enum1
);
112 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
113 ref
= get_refcount(filter
);
114 ok(ref
== 2, "Got unexpected refcount %d.\n", ref
);
115 ref
= get_refcount(enum1
);
116 ok(ref
== 1, "Got unexpected refcount %d.\n", ref
);
118 hr
= IEnumPins_Next(enum1
, 1, NULL
, NULL
);
119 ok(hr
== E_POINTER
, "Got hr %#x.\n", hr
);
121 hr
= IEnumPins_Next(enum1
, 1, pins
, NULL
);
122 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
123 ref
= get_refcount(filter
);
124 ok(ref
== 3, "Got unexpected refcount %d.\n", ref
);
125 ref
= get_refcount(pins
[0]);
126 ok(ref
== 3, "Got unexpected refcount %d.\n", ref
);
127 ref
= get_refcount(enum1
);
128 ok(ref
== 1, "Got unexpected refcount %d.\n", ref
);
129 IPin_Release(pins
[0]);
130 ref
= get_refcount(filter
);
131 ok(ref
== 2, "Got unexpected refcount %d.\n", ref
);
133 hr
= IEnumPins_Next(enum1
, 1, pins
, NULL
);
134 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
136 hr
= IEnumPins_Reset(enum1
);
137 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
139 hr
= IEnumPins_Next(enum1
, 1, pins
, &count
);
140 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
141 ok(count
== 1, "Got count %u.\n", count
);
142 IPin_Release(pins
[0]);
144 hr
= IEnumPins_Next(enum1
, 1, pins
, &count
);
145 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
146 ok(!count
, "Got count %u.\n", count
);
148 hr
= IEnumPins_Reset(enum1
);
149 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
151 hr
= IEnumPins_Next(enum1
, 2, pins
, NULL
);
152 ok(hr
== E_INVALIDARG
, "Got hr %#x.\n", hr
);
154 hr
= IEnumPins_Next(enum1
, 2, pins
, &count
);
155 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
156 ok(count
== 1, "Got count %u.\n", count
);
157 IPin_Release(pins
[0]);
159 hr
= IEnumPins_Reset(enum1
);
160 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
162 hr
= IEnumPins_Clone(enum1
, &enum2
);
163 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
165 hr
= IEnumPins_Skip(enum1
, 2);
166 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
168 hr
= IEnumPins_Skip(enum1
, 1);
169 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
171 hr
= IEnumPins_Skip(enum1
, 1);
172 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
174 hr
= IEnumPins_Next(enum1
, 1, pins
, NULL
);
175 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
177 hr
= IEnumPins_Next(enum2
, 1, pins
, NULL
);
178 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
179 IPin_Release(pins
[0]);
181 IEnumPins_Release(enum2
);
182 IEnumPins_Release(enum1
);
183 ref
= IBaseFilter_Release(filter
);
184 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
187 static void test_find_pin(void)
189 IBaseFilter
*filter
= create_null_renderer();
190 IEnumPins
*enum_pins
;
195 hr
= IBaseFilter_FindPin(filter
, L
"input pin", &pin
);
196 ok(hr
== VFW_E_NOT_FOUND
, "Got hr %#x.\n", hr
);
198 hr
= IBaseFilter_EnumPins(filter
, &enum_pins
);
199 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
201 hr
= IBaseFilter_FindPin(filter
, L
"In", &pin
);
202 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
203 hr
= IEnumPins_Next(enum_pins
, 1, &pin2
, NULL
);
204 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
205 ok(pin2
== pin
, "Expected pin %p, got %p.\n", pin
, pin2
);
209 IEnumPins_Release(enum_pins
);
210 ref
= IBaseFilter_Release(filter
);
211 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
214 static void test_pin_info(void)
216 IBaseFilter
*filter
= create_null_renderer();
224 hr
= IBaseFilter_FindPin(filter
, L
"In", &pin
);
225 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
226 ref
= get_refcount(filter
);
227 ok(ref
== 2, "Got unexpected refcount %d.\n", ref
);
228 ref
= get_refcount(pin
);
229 ok(ref
== 2, "Got unexpected refcount %d.\n", ref
);
231 hr
= IPin_QueryPinInfo(pin
, &info
);
232 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
233 ok(info
.pFilter
== filter
, "Expected filter %p, got %p.\n", filter
, info
.pFilter
);
234 ok(info
.dir
== PINDIR_INPUT
, "Got direction %d.\n", info
.dir
);
235 ok(!wcscmp(info
.achName
, L
"In"), "Got name %s.\n", wine_dbgstr_w(info
.achName
));
236 ref
= get_refcount(filter
);
237 ok(ref
== 3, "Got unexpected refcount %d.\n", ref
);
238 ref
= get_refcount(pin
);
239 ok(ref
== 3, "Got unexpected refcount %d.\n", ref
);
240 IBaseFilter_Release(info
.pFilter
);
242 hr
= IPin_QueryDirection(pin
, &dir
);
243 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
244 ok(dir
== PINDIR_INPUT
, "Got direction %d.\n", dir
);
246 hr
= IPin_QueryId(pin
, &id
);
247 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
248 ok(!wcscmp(id
, L
"In"), "Got id %s.\n", wine_dbgstr_w(id
));
251 hr
= IPin_QueryInternalConnections(pin
, NULL
, NULL
);
252 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
255 ref
= IBaseFilter_Release(filter
);
256 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
259 static const GUID test_iid
= {0x33333333};
260 static LONG outer_ref
= 1;
262 static HRESULT WINAPI
outer_QueryInterface(IUnknown
*iface
, REFIID iid
, void **out
)
264 if (IsEqualGUID(iid
, &IID_IUnknown
)
265 || IsEqualGUID(iid
, &IID_IBaseFilter
)
266 || IsEqualGUID(iid
, &test_iid
))
268 *out
= (IUnknown
*)0xdeadbeef;
271 ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid
));
272 return E_NOINTERFACE
;
275 static ULONG WINAPI
outer_AddRef(IUnknown
*iface
)
277 return InterlockedIncrement(&outer_ref
);
280 static ULONG WINAPI
outer_Release(IUnknown
*iface
)
282 return InterlockedDecrement(&outer_ref
);
285 static const IUnknownVtbl outer_vtbl
=
287 outer_QueryInterface
,
292 static IUnknown test_outer
= {&outer_vtbl
};
294 static void test_aggregation(void)
296 IBaseFilter
*filter
, *filter2
;
297 IUnknown
*unk
, *unk2
;
301 filter
= (IBaseFilter
*)0xdeadbeef;
302 hr
= CoCreateInstance(&CLSID_NullRenderer
, &test_outer
, CLSCTX_INPROC_SERVER
,
303 &IID_IBaseFilter
, (void **)&filter
);
304 ok(hr
== E_NOINTERFACE
, "Got hr %#x.\n", hr
);
305 ok(!filter
, "Got interface %p.\n", filter
);
307 hr
= CoCreateInstance(&CLSID_NullRenderer
, &test_outer
, CLSCTX_INPROC_SERVER
,
308 &IID_IUnknown
, (void **)&unk
);
309 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
310 ok(outer_ref
== 1, "Got unexpected refcount %d.\n", outer_ref
);
311 ok(unk
!= &test_outer
, "Returned IUnknown should not be outer IUnknown.\n");
312 ref
= get_refcount(unk
);
313 ok(ref
== 1, "Got unexpected refcount %d.\n", ref
);
315 ref
= IUnknown_AddRef(unk
);
316 ok(ref
== 2, "Got unexpected refcount %d.\n", ref
);
317 ok(outer_ref
== 1, "Got unexpected refcount %d.\n", outer_ref
);
319 ref
= IUnknown_Release(unk
);
320 ok(ref
== 1, "Got unexpected refcount %d.\n", ref
);
321 ok(outer_ref
== 1, "Got unexpected refcount %d.\n", outer_ref
);
323 hr
= IUnknown_QueryInterface(unk
, &IID_IUnknown
, (void **)&unk2
);
324 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
325 ok(unk2
== unk
, "Got unexpected IUnknown %p.\n", unk2
);
326 IUnknown_Release(unk2
);
328 hr
= IUnknown_QueryInterface(unk
, &IID_IBaseFilter
, (void **)&filter
);
329 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
331 hr
= IBaseFilter_QueryInterface(filter
, &IID_IUnknown
, (void **)&unk2
);
332 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
333 ok(unk2
== (IUnknown
*)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2
);
335 hr
= IBaseFilter_QueryInterface(filter
, &IID_IBaseFilter
, (void **)&filter2
);
336 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
337 ok(filter2
== (IBaseFilter
*)0xdeadbeef, "Got unexpected IBaseFilter %p.\n", filter2
);
339 hr
= IUnknown_QueryInterface(unk
, &test_iid
, (void **)&unk2
);
340 ok(hr
== E_NOINTERFACE
, "Got hr %#x.\n", hr
);
341 ok(!unk2
, "Got unexpected IUnknown %p.\n", unk2
);
343 hr
= IBaseFilter_QueryInterface(filter
, &test_iid
, (void **)&unk2
);
344 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
345 ok(unk2
== (IUnknown
*)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2
);
347 IBaseFilter_Release(filter
);
348 ref
= IUnknown_Release(unk
);
349 ok(!ref
, "Got unexpected refcount %d.\n", ref
);
350 ok(outer_ref
== 1, "Got unexpected refcount %d.\n", outer_ref
);
353 static void test_media_types(void)
355 IBaseFilter
*filter
= create_null_renderer();
356 AM_MEDIA_TYPE mt
= {}, *pmt
;
357 IEnumMediaTypes
*enummt
;
362 IBaseFilter_FindPin(filter
, L
"In", &pin
);
364 hr
= IPin_EnumMediaTypes(pin
, &enummt
);
365 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
367 hr
= IEnumMediaTypes_Next(enummt
, 1, &pmt
, NULL
);
368 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
370 IEnumMediaTypes_Release(enummt
);
372 hr
= IPin_QueryAccept(pin
, &mt
);
373 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
376 ref
= IBaseFilter_Release(filter
);
377 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
380 static void test_enum_media_types(void)
382 IBaseFilter
*filter
= create_null_renderer();
383 IEnumMediaTypes
*enum1
, *enum2
;
384 AM_MEDIA_TYPE
*mts
[2];
389 IBaseFilter_FindPin(filter
, L
"In", &pin
);
391 hr
= IPin_EnumMediaTypes(pin
, &enum1
);
392 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
394 hr
= IEnumMediaTypes_Next(enum1
, 1, mts
, NULL
);
395 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
397 hr
= IEnumMediaTypes_Next(enum1
, 1, mts
, &count
);
398 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
399 ok(!count
, "Got count %u.\n", count
);
401 hr
= IEnumMediaTypes_Reset(enum1
);
402 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
404 hr
= IEnumMediaTypes_Next(enum1
, 1, mts
, NULL
);
405 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
407 hr
= IEnumMediaTypes_Clone(enum1
, &enum2
);
408 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
410 hr
= IEnumMediaTypes_Skip(enum1
, 1);
411 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
413 hr
= IEnumMediaTypes_Next(enum2
, 1, mts
, NULL
);
414 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
416 IEnumMediaTypes_Release(enum1
);
417 IEnumMediaTypes_Release(enum2
);
420 ref
= IBaseFilter_Release(filter
);
421 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
426 struct strmbase_filter filter
;
427 struct strmbase_source source
;
430 static inline struct testfilter
*impl_from_strmbase_filter(struct strmbase_filter
*iface
)
432 return CONTAINING_RECORD(iface
, struct testfilter
, filter
);
435 static struct strmbase_pin
*testfilter_get_pin(struct strmbase_filter
*iface
, unsigned int index
)
437 struct testfilter
*filter
= impl_from_strmbase_filter(iface
);
439 return &filter
->source
.pin
;
443 static void testfilter_destroy(struct strmbase_filter
*iface
)
445 struct testfilter
*filter
= impl_from_strmbase_filter(iface
);
446 strmbase_source_cleanup(&filter
->source
);
447 strmbase_filter_cleanup(&filter
->filter
);
450 static const struct strmbase_filter_ops testfilter_ops
=
452 .filter_get_pin
= testfilter_get_pin
,
453 .filter_destroy
= testfilter_destroy
,
456 static HRESULT WINAPI
testsource_DecideAllocator(struct strmbase_source
*iface
,
457 IMemInputPin
*peer
, IMemAllocator
**allocator
)
462 static const struct strmbase_source_ops testsource_ops
=
464 .pfnAttemptConnection
= BaseOutputPinImpl_AttemptConnection
,
465 .pfnDecideAllocator
= testsource_DecideAllocator
,
468 static void testfilter_init(struct testfilter
*filter
)
470 static const GUID clsid
= {0xabacab};
471 strmbase_filter_init(&filter
->filter
, NULL
, &clsid
, &testfilter_ops
);
472 strmbase_source_init(&filter
->source
, &filter
->filter
, L
"", &testsource_ops
);
475 static void test_allocator(IMemInputPin
*input
)
477 IMemAllocator
*req_allocator
, *ret_allocator
;
478 ALLOCATOR_PROPERTIES props
;
481 hr
= IMemInputPin_GetAllocatorRequirements(input
, &props
);
482 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
484 hr
= IMemInputPin_GetAllocator(input
, &ret_allocator
);
485 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
489 hr
= IMemAllocator_GetProperties(ret_allocator
, &props
);
490 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
491 ok(!props
.cBuffers
, "Got %d buffers.\n", props
.cBuffers
);
492 ok(!props
.cbBuffer
, "Got size %d.\n", props
.cbBuffer
);
493 ok(!props
.cbAlign
, "Got alignment %d.\n", props
.cbAlign
);
494 ok(!props
.cbPrefix
, "Got prefix %d.\n", props
.cbPrefix
);
496 hr
= IMemInputPin_NotifyAllocator(input
, ret_allocator
, TRUE
);
497 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
498 IMemAllocator_Release(ret_allocator
);
501 hr
= IMemInputPin_NotifyAllocator(input
, NULL
, TRUE
);
502 ok(hr
== E_POINTER
, "Got hr %#x.\n", hr
);
504 CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
,
505 &IID_IMemAllocator
, (void **)&req_allocator
);
507 hr
= IMemInputPin_NotifyAllocator(input
, req_allocator
, TRUE
);
508 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
510 hr
= IMemInputPin_GetAllocator(input
, &ret_allocator
);
511 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
512 ok(ret_allocator
== req_allocator
, "Allocators didn't match.\n");
514 IMemAllocator_Release(req_allocator
);
515 IMemAllocator_Release(ret_allocator
);
518 struct frame_thread_params
521 IMediaSample
*sample
;
524 static DWORD WINAPI
frame_thread(void *arg
)
526 struct frame_thread_params
*params
= arg
;
529 if (winetest_debug
> 1) trace("%04x: Sending frame.\n", GetCurrentThreadId());
530 hr
= IMemInputPin_Receive(params
->sink
, params
->sample
);
531 if (winetest_debug
> 1) trace("%04x: Returned %#x.\n", GetCurrentThreadId(), hr
);
532 IMediaSample_Release(params
->sample
);
537 static HANDLE
send_frame_time(IMemInputPin
*sink
, REFERENCE_TIME start_time
, unsigned char color
)
539 struct frame_thread_params
*params
= malloc(sizeof(*params
));
540 IMemAllocator
*allocator
;
541 REFERENCE_TIME end_time
;
542 IMediaSample
*sample
;
547 hr
= IMemInputPin_GetAllocator(sink
, &allocator
);
548 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
550 hr
= IMemAllocator_GetBuffer(allocator
, &sample
, NULL
, NULL
, 0);
551 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
553 hr
= IMediaSample_GetPointer(sample
, &data
);
554 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
555 memset(data
, color
, 32 * 16 * 2);
557 hr
= IMediaSample_SetActualDataLength(sample
, 32 * 16 * 2);
558 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
560 start_time
*= 10000000;
561 end_time
= start_time
+ 10000000;
562 hr
= IMediaSample_SetTime(sample
, &start_time
, &end_time
);
563 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
566 params
->sample
= sample
;
567 thread
= CreateThread(NULL
, 0, frame_thread
, params
, 0, NULL
);
569 IMemAllocator_Release(allocator
);
573 static HANDLE
send_frame(IMemInputPin
*sink
)
575 return send_frame_time(sink
, 0, 0x55); /* purple */
578 static HRESULT
join_thread_(int line
, HANDLE thread
)
581 ok_(__FILE__
, line
)(!WaitForSingleObject(thread
, 1000), "Wait failed.\n");
582 GetExitCodeThread(thread
, &ret
);
586 #define join_thread(a) join_thread_(__LINE__, a)
588 static void test_filter_state(IMemInputPin
*input
, IFilterGraph2
*graph
)
590 IMemAllocator
*allocator
;
591 IMediaControl
*control
;
592 IMediaSample
*sample
;
597 IFilterGraph2_QueryInterface(graph
, &IID_IMediaControl
, (void **)&control
);
599 thread
= send_frame(input
);
600 hr
= join_thread(thread
);
601 todo_wine
ok(hr
== E_FAIL
, "Got hr %#x.\n", hr
);
603 /* The renderer is not fully paused until it receives a sample. The thread
604 * sending the sample blocks in IMemInputPin_Receive() until the filter is
607 hr
= IMediaControl_Pause(control
);
608 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
610 hr
= IMediaControl_GetState(control
, 0, &state
);
611 ok(hr
== VFW_S_STATE_INTERMEDIATE
, "Got hr %#x.\n", hr
);
613 thread
= send_frame(input
);
615 hr
= IMediaControl_GetState(control
, 1000, &state
);
616 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
618 ok(WaitForSingleObject(thread
, 100) == WAIT_TIMEOUT
, "Thread should block in Receive().\n");
620 hr
= IMediaControl_Stop(control
);
621 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
623 hr
= join_thread(thread
);
624 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
626 /* The sink will decommit our allocator for us when stopping, and recommit
627 * it when pausing. */
628 hr
= IMemInputPin_GetAllocator(input
, &allocator
);
629 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
630 hr
= IMemAllocator_GetBuffer(allocator
, &sample
, NULL
, NULL
, 0);
631 todo_wine
ok(hr
== VFW_E_NOT_COMMITTED
, "Got hr %#x.\n", hr
);
632 if (hr
== S_OK
) IMediaSample_Release(sample
);
634 hr
= IMemAllocator_Commit(allocator
);
635 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
636 thread
= send_frame(input
);
637 hr
= join_thread(thread
);
638 todo_wine
ok(hr
== E_FAIL
, "Got hr %#x.\n", hr
);
640 hr
= IMediaControl_Pause(control
);
641 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
643 hr
= IMediaControl_GetState(control
, 0, &state
);
644 ok(hr
== VFW_S_STATE_INTERMEDIATE
, "Got hr %#x.\n", hr
);
646 thread
= send_frame(input
);
648 hr
= IMediaControl_GetState(control
, 1000, &state
);
649 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
651 ok(WaitForSingleObject(thread
, 100) == WAIT_TIMEOUT
, "Thread should block in Receive().\n");
653 hr
= IMediaControl_Run(control
);
654 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
656 hr
= IMediaControl_GetState(control
, 0, &state
);
657 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
659 hr
= join_thread(thread
);
660 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
662 thread
= send_frame(input
);
663 hr
= join_thread(thread
);
664 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
666 hr
= IMediaControl_Pause(control
);
667 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
669 hr
= IMediaControl_GetState(control
, 0, &state
);
670 todo_wine
ok(hr
== VFW_S_STATE_INTERMEDIATE
, "Got hr %#x.\n", hr
);
672 thread
= send_frame(input
);
674 hr
= IMediaControl_GetState(control
, 1000, &state
);
675 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
677 ok(WaitForSingleObject(thread
, 100) == WAIT_TIMEOUT
, "Thread should block in Receive().\n");
679 hr
= IMediaControl_Run(control
);
680 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
682 hr
= IMediaControl_GetState(control
, 0, &state
);
683 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
685 hr
= join_thread(thread
);
686 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
688 hr
= IMediaControl_Pause(control
);
689 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
691 hr
= IMediaControl_GetState(control
, 0, &state
);
692 todo_wine
ok(hr
== VFW_S_STATE_INTERMEDIATE
, "Got hr %#x.\n", hr
);
693 ok(state
== State_Paused
, "Got state %u.\n", state
);
695 hr
= IMediaControl_Stop(control
);
696 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
698 hr
= IMediaControl_GetState(control
, 0, &state
);
699 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
701 hr
= IMediaControl_Pause(control
);
702 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
704 hr
= IMediaControl_GetState(control
, 0, &state
);
705 ok(hr
== VFW_S_STATE_INTERMEDIATE
, "Got hr %#x.\n", hr
);
706 ok(state
== State_Paused
, "Got state %u.\n", state
);
708 hr
= IMediaControl_Run(control
);
709 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
711 hr
= IMediaControl_GetState(control
, 0, &state
);
712 todo_wine
ok(hr
== VFW_S_STATE_INTERMEDIATE
, "Got hr %#x.\n", hr
);
713 ok(state
== State_Running
, "Got state %u.\n", state
);
715 thread
= send_frame(input
);
716 hr
= join_thread(thread
);
717 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
719 hr
= IMediaControl_GetState(control
, 0, &state
);
720 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
722 hr
= IMediaControl_Stop(control
);
723 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
725 hr
= IMediaControl_GetState(control
, 0, &state
);
726 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
728 IMemAllocator_Release(allocator
);
729 IMediaControl_Release(control
);
732 static void test_flushing(IPin
*pin
, IMemInputPin
*input
, IFilterGraph2
*graph
)
734 IMediaControl
*control
;
739 IFilterGraph2_QueryInterface(graph
, &IID_IMediaControl
, (void **)&control
);
741 hr
= IMediaControl_Pause(control
);
742 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
744 thread
= send_frame(input
);
745 ok(WaitForSingleObject(thread
, 100) == WAIT_TIMEOUT
, "Thread should block in Receive().\n");
747 hr
= IMediaControl_GetState(control
, 0, &state
);
748 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
750 hr
= IPin_BeginFlush(pin
);
751 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
753 hr
= join_thread(thread
);
754 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
756 thread
= send_frame(input
);
757 hr
= join_thread(thread
);
758 todo_wine
ok(hr
== E_FAIL
, "Got hr %#x.\n", hr
);
760 hr
= IPin_EndFlush(pin
);
761 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
763 /* We dropped the sample we were holding, so now we need a new one... */
765 hr
= IMediaControl_GetState(control
, 0, &state
);
766 todo_wine
ok(hr
== VFW_S_STATE_INTERMEDIATE
, "Got hr %#x.\n", hr
);
768 thread
= send_frame(input
);
769 ok(WaitForSingleObject(thread
, 100) == WAIT_TIMEOUT
, "Thread should block in Receive().\n");
771 hr
= IMediaControl_Run(control
);
772 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
773 hr
= join_thread(thread
);
774 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
776 hr
= IPin_BeginFlush(pin
);
777 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
779 hr
= join_thread(send_frame(input
));
780 todo_wine
ok(hr
== E_FAIL
, "Got hr %#x.\n", hr
);
782 hr
= IPin_EndFlush(pin
);
783 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
785 hr
= join_thread(send_frame(input
));
786 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
788 hr
= IMediaControl_Stop(control
);
789 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
791 IMediaControl_Release(control
);
794 static void test_connect_pin(void)
796 static const AM_MEDIA_TYPE req_mt
=
798 .majortype
= {0x111},
800 .formattype
= {0x333},
802 ALLOCATOR_PROPERTIES req_props
= {1, 32 * 16 * 4, 1, 0}, ret_props
;
803 IBaseFilter
*filter
= create_null_renderer();
804 struct testfilter source
;
805 IMemAllocator
*allocator
;
806 IMediaControl
*control
;
807 IFilterGraph2
*graph
;
814 testfilter_init(&source
);
816 CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
817 &IID_IFilterGraph2
, (void **)&graph
);
818 IFilterGraph2_AddFilter(graph
, &source
.filter
.IBaseFilter_iface
, L
"source");
819 IFilterGraph2_AddFilter(graph
, filter
, L
"sink");
820 IFilterGraph2_QueryInterface(graph
, &IID_IMediaControl
, (void **)&control
);
822 IBaseFilter_FindPin(filter
, L
"In", &pin
);
824 peer
= (IPin
*)0xdeadbeef;
825 hr
= IPin_ConnectedTo(pin
, &peer
);
826 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
827 ok(!peer
, "Got peer %p.\n", peer
);
829 hr
= IPin_ConnectionMediaType(pin
, &mt
);
830 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
832 hr
= IMediaControl_Pause(control
);
833 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
834 hr
= IFilterGraph2_ConnectDirect(graph
, &source
.source
.pin
.IPin_iface
, pin
, &req_mt
);
835 ok(hr
== VFW_E_NOT_STOPPED
, "Got hr %#x.\n", hr
);
836 hr
= IMediaControl_Stop(control
);
837 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
839 hr
= IFilterGraph2_ConnectDirect(graph
, &source
.source
.pin
.IPin_iface
, pin
, &req_mt
);
840 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
842 hr
= IPin_ConnectedTo(pin
, &peer
);
843 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
844 ok(peer
== &source
.source
.pin
.IPin_iface
, "Got peer %p.\n", peer
);
847 hr
= IPin_ConnectionMediaType(pin
, &mt
);
848 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
849 ok(!memcmp(&mt
, &req_mt
, sizeof(AM_MEDIA_TYPE
)), "Media types didn't match.\n");
851 hr
= IMediaControl_Pause(control
);
852 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
853 hr
= IFilterGraph2_Disconnect(graph
, pin
);
854 ok(hr
== VFW_E_NOT_STOPPED
, "Got hr %#x.\n", hr
);
855 hr
= IMediaControl_Stop(control
);
856 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
858 IPin_QueryInterface(pin
, &IID_IMemInputPin
, (void **)&input
);
860 test_allocator(input
);
862 hr
= IMemInputPin_GetAllocator(input
, &allocator
);
863 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
864 hr
= IMemAllocator_SetProperties(allocator
, &req_props
, &ret_props
);
865 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
866 ok(!memcmp(&ret_props
, &req_props
, sizeof(req_props
)), "Properties did not match.\n");
867 hr
= IMemAllocator_Commit(allocator
);
868 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
869 IMemAllocator_Release(allocator
);
871 hr
= IMemInputPin_ReceiveCanBlock(input
);
872 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
874 test_filter_state(input
, graph
);
875 test_flushing(pin
, input
, graph
);
877 hr
= IFilterGraph2_Disconnect(graph
, pin
);
878 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
879 hr
= IFilterGraph2_Disconnect(graph
, pin
);
880 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
881 ok(source
.source
.pin
.peer
== pin
, "Got peer %p.\n", peer
);
882 IFilterGraph2_Disconnect(graph
, &source
.source
.pin
.IPin_iface
);
884 peer
= (IPin
*)0xdeadbeef;
885 hr
= IPin_ConnectedTo(pin
, &peer
);
886 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
887 ok(!peer
, "Got peer %p.\n", peer
);
889 hr
= IPin_ConnectionMediaType(pin
, &mt
);
890 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
892 IMemInputPin_Release(input
);
894 IMediaControl_Release(control
);
895 ref
= IFilterGraph2_Release(graph
);
896 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
897 ref
= IBaseFilter_Release(filter
);
898 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
899 ref
= IBaseFilter_Release(&source
.filter
.IBaseFilter_iface
);
900 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
903 START_TEST(nullrenderer
)
910 if (FAILED(hr
= CoCreateInstance(&CLSID_NullRenderer
, NULL
, CLSCTX_INPROC_SERVER
,
911 &IID_IBaseFilter
, (void **)&filter
)))
913 /* qedit.dll does not exist on 2003. */
914 win_skip("Failed to create null renderer filter, hr %#x.\n", hr
);
917 IBaseFilter_Release(filter
);
925 test_enum_media_types();