vkd3d: Disable printf format checks.
[wine.git] / dlls / qedit / tests / nullrenderer.c
blobafc86e10d3403b4c8b118f48a72564c6944e88d5
1 /*
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
21 #define COBJMACROS
22 #include "dshow.h"
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 %#lx.\n", hr);
32 return filter;
35 static IFilterGraph2 *create_graph(void)
37 IFilterGraph2 *ret;
38 HRESULT hr;
39 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (void **)&ret);
40 ok(hr == S_OK, "Got hr %#lx.\n", hr);
41 return ret;
44 static ULONG get_refcount(void *iface)
46 IUnknown *unknown = iface;
47 IUnknown_AddRef(unknown);
48 return IUnknown_Release(unknown);
51 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
52 static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
54 IUnknown *iface = iface_ptr;
55 HRESULT hr, expected_hr;
56 IUnknown *unk;
58 expected_hr = supported ? S_OK : E_NOINTERFACE;
60 hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
61 ok_(__FILE__, line)(hr == expected_hr, "Got hr %#lx, expected %#lx.\n", hr, expected_hr);
62 if (SUCCEEDED(hr))
63 IUnknown_Release(unk);
66 static void test_interfaces(void)
68 IBaseFilter *filter = create_null_renderer();
69 ULONG ref;
70 IPin *pin;
72 check_interface(filter, &IID_IBaseFilter, TRUE);
73 check_interface(filter, &IID_IMediaFilter, TRUE);
74 check_interface(filter, &IID_IMediaPosition, TRUE);
75 check_interface(filter, &IID_IMediaSeeking, TRUE);
76 check_interface(filter, &IID_IPersist, TRUE);
77 check_interface(filter, &IID_IUnknown, TRUE);
79 check_interface(filter, &IID_IAMFilterMiscFlags, FALSE);
80 check_interface(filter, &IID_IBasicAudio, FALSE);
81 check_interface(filter, &IID_IBasicVideo, FALSE);
82 check_interface(filter, &IID_IKsPropertySet, FALSE);
83 check_interface(filter, &IID_IPersistPropertyBag, FALSE);
84 check_interface(filter, &IID_IPin, FALSE);
85 todo_wine check_interface(filter, &IID_IQualityControl, FALSE);
86 check_interface(filter, &IID_IQualProp, FALSE);
87 check_interface(filter, &IID_IReferenceClock, FALSE);
88 check_interface(filter, &IID_IVideoWindow, FALSE);
90 IBaseFilter_FindPin(filter, L"In", &pin);
92 check_interface(pin, &IID_IMemInputPin, TRUE);
93 check_interface(pin, &IID_IPin, TRUE);
94 todo_wine check_interface(pin, &IID_IQualityControl, TRUE);
95 check_interface(pin, &IID_IUnknown, TRUE);
97 check_interface(pin, &IID_IKsPropertySet, FALSE);
98 check_interface(pin, &IID_IMediaPosition, FALSE);
99 check_interface(pin, &IID_IMediaSeeking, FALSE);
101 IPin_Release(pin);
102 ref = IBaseFilter_Release(filter);
103 ok(!ref, "Got unexpected refcount %ld.\n", ref);
106 static void test_enum_pins(void)
108 IBaseFilter *filter = create_null_renderer();
109 IEnumPins *enum1, *enum2;
110 ULONG count, ref;
111 IPin *pins[2];
112 HRESULT hr;
114 ref = get_refcount(filter);
115 ok(ref == 1, "Got unexpected refcount %ld.\n", ref);
117 hr = IBaseFilter_EnumPins(filter, NULL);
118 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
120 hr = IBaseFilter_EnumPins(filter, &enum1);
121 ok(hr == S_OK, "Got hr %#lx.\n", hr);
122 ref = get_refcount(filter);
123 ok(ref == 2, "Got unexpected refcount %ld.\n", ref);
124 ref = get_refcount(enum1);
125 ok(ref == 1, "Got unexpected refcount %ld.\n", ref);
127 hr = IEnumPins_Next(enum1, 1, NULL, NULL);
128 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
130 hr = IEnumPins_Next(enum1, 1, pins, NULL);
131 ok(hr == S_OK, "Got hr %#lx.\n", hr);
132 ref = get_refcount(filter);
133 ok(ref == 3, "Got unexpected refcount %ld.\n", ref);
134 ref = get_refcount(pins[0]);
135 ok(ref == 3, "Got unexpected refcount %ld.\n", ref);
136 ref = get_refcount(enum1);
137 ok(ref == 1, "Got unexpected refcount %ld.\n", ref);
138 IPin_Release(pins[0]);
139 ref = get_refcount(filter);
140 ok(ref == 2, "Got unexpected refcount %ld.\n", ref);
142 hr = IEnumPins_Next(enum1, 1, pins, NULL);
143 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
145 hr = IEnumPins_Reset(enum1);
146 ok(hr == S_OK, "Got hr %#lx.\n", hr);
148 hr = IEnumPins_Next(enum1, 1, pins, &count);
149 ok(hr == S_OK, "Got hr %#lx.\n", hr);
150 ok(count == 1, "Got count %lu.\n", count);
151 IPin_Release(pins[0]);
153 hr = IEnumPins_Next(enum1, 1, pins, &count);
154 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
155 ok(!count, "Got count %lu.\n", count);
157 hr = IEnumPins_Reset(enum1);
158 ok(hr == S_OK, "Got hr %#lx.\n", hr);
160 hr = IEnumPins_Next(enum1, 2, pins, NULL);
161 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
163 hr = IEnumPins_Next(enum1, 2, pins, &count);
164 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
165 ok(count == 1, "Got count %lu.\n", count);
166 IPin_Release(pins[0]);
168 hr = IEnumPins_Reset(enum1);
169 ok(hr == S_OK, "Got hr %#lx.\n", hr);
171 hr = IEnumPins_Clone(enum1, &enum2);
172 ok(hr == S_OK, "Got hr %#lx.\n", hr);
174 hr = IEnumPins_Skip(enum1, 2);
175 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
177 hr = IEnumPins_Skip(enum1, 1);
178 ok(hr == S_OK, "Got hr %#lx.\n", hr);
180 hr = IEnumPins_Skip(enum1, 1);
181 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
183 hr = IEnumPins_Next(enum1, 1, pins, NULL);
184 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
186 hr = IEnumPins_Next(enum2, 1, pins, NULL);
187 ok(hr == S_OK, "Got hr %#lx.\n", hr);
188 IPin_Release(pins[0]);
190 IEnumPins_Release(enum2);
191 IEnumPins_Release(enum1);
192 ref = IBaseFilter_Release(filter);
193 ok(!ref, "Got outstanding refcount %ld.\n", ref);
196 static void test_find_pin(void)
198 IBaseFilter *filter = create_null_renderer();
199 IEnumPins *enum_pins;
200 IPin *pin, *pin2;
201 HRESULT hr;
202 ULONG ref;
204 hr = IBaseFilter_FindPin(filter, L"input pin", &pin);
205 ok(hr == VFW_E_NOT_FOUND, "Got hr %#lx.\n", hr);
207 hr = IBaseFilter_EnumPins(filter, &enum_pins);
208 ok(hr == S_OK, "Got hr %#lx.\n", hr);
210 hr = IBaseFilter_FindPin(filter, L"In", &pin);
211 ok(hr == S_OK, "Got hr %#lx.\n", hr);
212 hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL);
213 ok(hr == S_OK, "Got hr %#lx.\n", hr);
214 ok(pin2 == pin, "Expected pin %p, got %p.\n", pin, pin2);
215 IPin_Release(pin2);
216 IPin_Release(pin);
218 IEnumPins_Release(enum_pins);
219 ref = IBaseFilter_Release(filter);
220 ok(!ref, "Got outstanding refcount %ld.\n", ref);
223 static void test_pin_info(void)
225 IBaseFilter *filter = create_null_renderer();
226 PIN_DIRECTION dir;
227 PIN_INFO info;
228 HRESULT hr;
229 WCHAR *id;
230 ULONG ref;
231 IPin *pin;
233 hr = IBaseFilter_FindPin(filter, L"In", &pin);
234 ok(hr == S_OK, "Got hr %#lx.\n", hr);
235 ref = get_refcount(filter);
236 ok(ref == 2, "Got unexpected refcount %ld.\n", ref);
237 ref = get_refcount(pin);
238 ok(ref == 2, "Got unexpected refcount %ld.\n", ref);
240 hr = IPin_QueryPinInfo(pin, &info);
241 ok(hr == S_OK, "Got hr %#lx.\n", hr);
242 ok(info.pFilter == filter, "Expected filter %p, got %p.\n", filter, info.pFilter);
243 ok(info.dir == PINDIR_INPUT, "Got direction %d.\n", info.dir);
244 ok(!wcscmp(info.achName, L"In"), "Got name %s.\n", wine_dbgstr_w(info.achName));
245 ref = get_refcount(filter);
246 ok(ref == 3, "Got unexpected refcount %ld.\n", ref);
247 ref = get_refcount(pin);
248 ok(ref == 3, "Got unexpected refcount %ld.\n", ref);
249 IBaseFilter_Release(info.pFilter);
251 hr = IPin_QueryDirection(pin, &dir);
252 ok(hr == S_OK, "Got hr %#lx.\n", hr);
253 ok(dir == PINDIR_INPUT, "Got direction %d.\n", dir);
255 hr = IPin_QueryId(pin, &id);
256 ok(hr == S_OK, "Got hr %#lx.\n", hr);
257 ok(!wcscmp(id, L"In"), "Got id %s.\n", wine_dbgstr_w(id));
258 CoTaskMemFree(id);
260 hr = IPin_QueryInternalConnections(pin, NULL, NULL);
261 ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
263 IPin_Release(pin);
264 ref = IBaseFilter_Release(filter);
265 ok(!ref, "Got outstanding refcount %ld.\n", ref);
268 static const GUID test_iid = {0x33333333};
269 static LONG outer_ref = 1;
271 static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID iid, void **out)
273 if (IsEqualGUID(iid, &IID_IUnknown)
274 || IsEqualGUID(iid, &IID_IBaseFilter)
275 || IsEqualGUID(iid, &test_iid))
277 *out = (IUnknown *)0xdeadbeef;
278 return S_OK;
280 ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid));
281 return E_NOINTERFACE;
284 static ULONG WINAPI outer_AddRef(IUnknown *iface)
286 return InterlockedIncrement(&outer_ref);
289 static ULONG WINAPI outer_Release(IUnknown *iface)
291 return InterlockedDecrement(&outer_ref);
294 static const IUnknownVtbl outer_vtbl =
296 outer_QueryInterface,
297 outer_AddRef,
298 outer_Release,
301 static IUnknown test_outer = {&outer_vtbl};
303 static void test_aggregation(void)
305 IBaseFilter *filter, *filter2;
306 IUnknown *unk, *unk2;
307 HRESULT hr;
308 ULONG ref;
310 filter = (IBaseFilter *)0xdeadbeef;
311 hr = CoCreateInstance(&CLSID_NullRenderer, &test_outer, CLSCTX_INPROC_SERVER,
312 &IID_IBaseFilter, (void **)&filter);
313 ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr);
314 ok(!filter, "Got interface %p.\n", filter);
316 hr = CoCreateInstance(&CLSID_NullRenderer, &test_outer, CLSCTX_INPROC_SERVER,
317 &IID_IUnknown, (void **)&unk);
318 ok(hr == S_OK, "Got hr %#lx.\n", hr);
319 ok(outer_ref == 1, "Got unexpected refcount %ld.\n", outer_ref);
320 ok(unk != &test_outer, "Returned IUnknown should not be outer IUnknown.\n");
321 ref = get_refcount(unk);
322 ok(ref == 1, "Got unexpected refcount %ld.\n", ref);
324 ref = IUnknown_AddRef(unk);
325 ok(ref == 2, "Got unexpected refcount %ld.\n", ref);
326 ok(outer_ref == 1, "Got unexpected refcount %ld.\n", outer_ref);
328 ref = IUnknown_Release(unk);
329 ok(ref == 1, "Got unexpected refcount %ld.\n", ref);
330 ok(outer_ref == 1, "Got unexpected refcount %ld.\n", outer_ref);
332 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, (void **)&unk2);
333 ok(hr == S_OK, "Got hr %#lx.\n", hr);
334 ok(unk2 == unk, "Got unexpected IUnknown %p.\n", unk2);
335 IUnknown_Release(unk2);
337 hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void **)&filter);
338 ok(hr == S_OK, "Got hr %#lx.\n", hr);
340 hr = IBaseFilter_QueryInterface(filter, &IID_IUnknown, (void **)&unk2);
341 ok(hr == S_OK, "Got hr %#lx.\n", hr);
342 ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
344 hr = IBaseFilter_QueryInterface(filter, &IID_IBaseFilter, (void **)&filter2);
345 ok(hr == S_OK, "Got hr %#lx.\n", hr);
346 ok(filter2 == (IBaseFilter *)0xdeadbeef, "Got unexpected IBaseFilter %p.\n", filter2);
348 hr = IUnknown_QueryInterface(unk, &test_iid, (void **)&unk2);
349 ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr);
350 ok(!unk2, "Got unexpected IUnknown %p.\n", unk2);
352 hr = IBaseFilter_QueryInterface(filter, &test_iid, (void **)&unk2);
353 ok(hr == S_OK, "Got hr %#lx.\n", hr);
354 ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
356 IBaseFilter_Release(filter);
357 ref = IUnknown_Release(unk);
358 ok(!ref, "Got unexpected refcount %ld.\n", ref);
359 ok(outer_ref == 1, "Got unexpected refcount %ld.\n", outer_ref);
362 static void test_media_types(void)
364 IBaseFilter *filter = create_null_renderer();
365 AM_MEDIA_TYPE mt = {}, *pmt;
366 IEnumMediaTypes *enummt;
367 HRESULT hr;
368 ULONG ref;
369 IPin *pin;
371 IBaseFilter_FindPin(filter, L"In", &pin);
373 hr = IPin_EnumMediaTypes(pin, &enummt);
374 ok(hr == S_OK, "Got hr %#lx.\n", hr);
376 hr = IEnumMediaTypes_Next(enummt, 1, &pmt, NULL);
377 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
379 IEnumMediaTypes_Release(enummt);
381 hr = IPin_QueryAccept(pin, &mt);
382 ok(hr == S_OK, "Got hr %#lx.\n", hr);
384 IPin_Release(pin);
385 ref = IBaseFilter_Release(filter);
386 ok(!ref, "Got outstanding refcount %ld.\n", ref);
389 static void test_enum_media_types(void)
391 IBaseFilter *filter = create_null_renderer();
392 IEnumMediaTypes *enum1, *enum2;
393 AM_MEDIA_TYPE *mts[2];
394 ULONG ref, count;
395 HRESULT hr;
396 IPin *pin;
398 IBaseFilter_FindPin(filter, L"In", &pin);
400 hr = IPin_EnumMediaTypes(pin, &enum1);
401 ok(hr == S_OK, "Got hr %#lx.\n", hr);
403 hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL);
404 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
406 hr = IEnumMediaTypes_Next(enum1, 1, mts, &count);
407 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
408 ok(!count, "Got count %lu.\n", count);
410 hr = IEnumMediaTypes_Reset(enum1);
411 ok(hr == S_OK, "Got hr %#lx.\n", hr);
413 hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL);
414 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
416 hr = IEnumMediaTypes_Clone(enum1, &enum2);
417 ok(hr == S_OK, "Got hr %#lx.\n", hr);
419 hr = IEnumMediaTypes_Skip(enum1, 1);
420 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
422 hr = IEnumMediaTypes_Next(enum2, 1, mts, NULL);
423 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
425 IEnumMediaTypes_Release(enum1);
426 IEnumMediaTypes_Release(enum2);
427 IPin_Release(pin);
429 ref = IBaseFilter_Release(filter);
430 ok(!ref, "Got outstanding refcount %ld.\n", ref);
433 struct testfilter
435 struct strmbase_filter filter;
436 struct strmbase_source source;
439 static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface)
441 return CONTAINING_RECORD(iface, struct testfilter, filter);
444 static struct strmbase_pin *testfilter_get_pin(struct strmbase_filter *iface, unsigned int index)
446 struct testfilter *filter = impl_from_strmbase_filter(iface);
447 if (!index)
448 return &filter->source.pin;
449 return NULL;
452 static void testfilter_destroy(struct strmbase_filter *iface)
454 struct testfilter *filter = impl_from_strmbase_filter(iface);
455 strmbase_source_cleanup(&filter->source);
456 strmbase_filter_cleanup(&filter->filter);
459 static const struct strmbase_filter_ops testfilter_ops =
461 .filter_get_pin = testfilter_get_pin,
462 .filter_destroy = testfilter_destroy,
465 static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface,
466 IMemInputPin *peer, IMemAllocator **allocator)
468 return S_OK;
471 static const struct strmbase_source_ops testsource_ops =
473 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
474 .pfnDecideAllocator = testsource_DecideAllocator,
477 static void testfilter_init(struct testfilter *filter)
479 static const GUID clsid = {0xabacab};
480 strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops);
481 strmbase_source_init(&filter->source, &filter->filter, L"", &testsource_ops);
484 static void test_allocator(IMemInputPin *input)
486 IMemAllocator *req_allocator, *ret_allocator;
487 ALLOCATOR_PROPERTIES props;
488 HRESULT hr;
490 hr = IMemInputPin_GetAllocatorRequirements(input, &props);
491 ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
493 hr = IMemInputPin_GetAllocator(input, &ret_allocator);
494 todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr);
496 if (hr == S_OK)
498 hr = IMemAllocator_GetProperties(ret_allocator, &props);
499 ok(hr == S_OK, "Got hr %#lx.\n", hr);
500 ok(!props.cBuffers, "Got %ld buffers.\n", props.cBuffers);
501 ok(!props.cbBuffer, "Got size %ld.\n", props.cbBuffer);
502 ok(!props.cbAlign, "Got alignment %ld.\n", props.cbAlign);
503 ok(!props.cbPrefix, "Got prefix %ld.\n", props.cbPrefix);
505 hr = IMemInputPin_NotifyAllocator(input, ret_allocator, TRUE);
506 ok(hr == S_OK, "Got hr %#lx.\n", hr);
507 IMemAllocator_Release(ret_allocator);
510 hr = IMemInputPin_NotifyAllocator(input, NULL, TRUE);
511 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
513 CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
514 &IID_IMemAllocator, (void **)&req_allocator);
516 hr = IMemInputPin_NotifyAllocator(input, req_allocator, TRUE);
517 ok(hr == S_OK, "Got hr %#lx.\n", hr);
519 hr = IMemInputPin_GetAllocator(input, &ret_allocator);
520 ok(hr == S_OK, "Got hr %#lx.\n", hr);
521 ok(ret_allocator == req_allocator, "Allocators didn't match.\n");
523 IMemAllocator_Release(req_allocator);
524 IMemAllocator_Release(ret_allocator);
527 struct frame_thread_params
529 IMemInputPin *sink;
530 IMediaSample *sample;
533 static DWORD WINAPI frame_thread(void *arg)
535 struct frame_thread_params *params = arg;
536 HRESULT hr;
538 if (winetest_debug > 1) trace("%04lx: Sending frame.\n", GetCurrentThreadId());
539 hr = IMemInputPin_Receive(params->sink, params->sample);
540 if (winetest_debug > 1) trace("%04lx: Returned %#lx.\n", GetCurrentThreadId(), hr);
541 IMediaSample_Release(params->sample);
542 free(params);
543 return hr;
546 static HANDLE send_frame_time(IMemInputPin *sink, REFERENCE_TIME start_time, unsigned char color)
548 struct frame_thread_params *params = malloc(sizeof(*params));
549 IMemAllocator *allocator;
550 REFERENCE_TIME end_time;
551 IMediaSample *sample;
552 HANDLE thread;
553 HRESULT hr;
554 BYTE *data;
556 hr = IMemInputPin_GetAllocator(sink, &allocator);
557 ok(hr == S_OK, "Got hr %#lx.\n", hr);
559 hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
560 ok(hr == S_OK, "Got hr %#lx.\n", hr);
562 hr = IMediaSample_GetPointer(sample, &data);
563 ok(hr == S_OK, "Got hr %#lx.\n", hr);
564 memset(data, color, 32 * 16 * 2);
566 hr = IMediaSample_SetActualDataLength(sample, 32 * 16 * 2);
567 ok(hr == S_OK, "Got hr %#lx.\n", hr);
569 start_time *= 10000000;
570 end_time = start_time + 10000000;
571 hr = IMediaSample_SetTime(sample, &start_time, &end_time);
572 ok(hr == S_OK, "Got hr %#lx.\n", hr);
574 params->sink = sink;
575 params->sample = sample;
576 thread = CreateThread(NULL, 0, frame_thread, params, 0, NULL);
578 IMemAllocator_Release(allocator);
579 return thread;
582 static HANDLE send_frame(IMemInputPin *sink)
584 return send_frame_time(sink, 0, 0x55); /* purple */
587 static HRESULT join_thread_(int line, HANDLE thread)
589 DWORD ret;
590 ok_(__FILE__, line)(!WaitForSingleObject(thread, 1000), "Wait failed.\n");
591 GetExitCodeThread(thread, &ret);
592 CloseHandle(thread);
593 return ret;
595 #define join_thread(a) join_thread_(__LINE__, a)
597 static void test_filter_state(IMemInputPin *input, IFilterGraph2 *graph)
599 IMemAllocator *allocator;
600 IMediaControl *control;
601 IMediaSample *sample;
602 OAFilterState state;
603 HANDLE thread;
604 HRESULT hr;
606 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
608 thread = send_frame(input);
609 hr = join_thread(thread);
610 todo_wine ok(hr == E_FAIL, "Got hr %#lx.\n", hr);
612 /* The renderer is not fully paused until it receives a sample. The thread
613 * sending the sample blocks in IMemInputPin_Receive() until the filter is
614 * stopped or run. */
616 hr = IMediaControl_Pause(control);
617 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
619 hr = IMediaControl_GetState(control, 0, &state);
620 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
622 thread = send_frame(input);
624 hr = IMediaControl_GetState(control, 1000, &state);
625 ok(hr == S_OK, "Got hr %#lx.\n", hr);
627 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
629 hr = IMediaControl_Stop(control);
630 ok(hr == S_OK, "Got hr %#lx.\n", hr);
632 hr = join_thread(thread);
633 ok(hr == S_OK, "Got hr %#lx.\n", hr);
635 /* The sink will decommit our allocator for us when stopping, and recommit
636 * it when pausing. */
637 hr = IMemInputPin_GetAllocator(input, &allocator);
638 ok(hr == S_OK, "Got hr %#lx.\n", hr);
639 hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
640 todo_wine ok(hr == VFW_E_NOT_COMMITTED, "Got hr %#lx.\n", hr);
641 if (hr == S_OK) IMediaSample_Release(sample);
643 hr = IMemAllocator_Commit(allocator);
644 ok(hr == S_OK, "Got hr %#lx.\n", hr);
645 thread = send_frame(input);
646 hr = join_thread(thread);
647 todo_wine ok(hr == E_FAIL, "Got hr %#lx.\n", hr);
649 hr = IMediaControl_Pause(control);
650 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
652 hr = IMediaControl_GetState(control, 0, &state);
653 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
655 thread = send_frame(input);
657 hr = IMediaControl_GetState(control, 1000, &state);
658 ok(hr == S_OK, "Got hr %#lx.\n", hr);
660 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
662 hr = IMediaControl_Run(control);
663 ok(hr == S_OK, "Got hr %#lx.\n", hr);
665 hr = IMediaControl_GetState(control, 0, &state);
666 ok(hr == S_OK, "Got hr %#lx.\n", hr);
668 hr = join_thread(thread);
669 ok(hr == S_OK, "Got hr %#lx.\n", hr);
671 thread = send_frame(input);
672 hr = join_thread(thread);
673 ok(hr == S_OK, "Got hr %#lx.\n", hr);
675 hr = IMediaControl_Pause(control);
676 todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
678 hr = IMediaControl_GetState(control, 0, &state);
679 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
681 thread = send_frame(input);
683 hr = IMediaControl_GetState(control, 1000, &state);
684 ok(hr == S_OK, "Got hr %#lx.\n", hr);
686 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
688 hr = IMediaControl_Run(control);
689 ok(hr == S_OK, "Got hr %#lx.\n", hr);
691 hr = IMediaControl_GetState(control, 0, &state);
692 ok(hr == S_OK, "Got hr %#lx.\n", hr);
694 hr = join_thread(thread);
695 ok(hr == S_OK, "Got hr %#lx.\n", hr);
697 hr = IMediaControl_Pause(control);
698 todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
700 hr = IMediaControl_GetState(control, 0, &state);
701 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
702 ok(state == State_Paused, "Got state %lu.\n", state);
704 hr = IMediaControl_Stop(control);
705 ok(hr == S_OK, "Got hr %#lx.\n", hr);
707 hr = IMediaControl_GetState(control, 0, &state);
708 ok(hr == S_OK, "Got hr %#lx.\n", hr);
710 hr = IMediaControl_Pause(control);
711 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
713 hr = IMediaControl_GetState(control, 0, &state);
714 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
715 ok(state == State_Paused, "Got state %lu.\n", state);
717 hr = IMediaControl_Run(control);
718 todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
720 hr = IMediaControl_GetState(control, 0, &state);
721 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
722 ok(state == State_Running, "Got state %lu.\n", state);
724 thread = send_frame(input);
725 hr = join_thread(thread);
726 ok(hr == S_OK, "Got hr %#lx.\n", hr);
728 hr = IMediaControl_GetState(control, 0, &state);
729 ok(hr == S_OK, "Got hr %#lx.\n", hr);
731 hr = IMediaControl_Stop(control);
732 ok(hr == S_OK, "Got hr %#lx.\n", hr);
734 hr = IMediaControl_GetState(control, 0, &state);
735 ok(hr == S_OK, "Got hr %#lx.\n", hr);
737 IMemAllocator_Release(allocator);
738 IMediaControl_Release(control);
741 static void test_flushing(IPin *pin, IMemInputPin *input, IFilterGraph2 *graph)
743 IMediaControl *control;
744 OAFilterState state;
745 HANDLE thread;
746 HRESULT hr;
748 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
750 hr = IMediaControl_Pause(control);
751 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
753 thread = send_frame(input);
754 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
756 hr = IMediaControl_GetState(control, 0, &state);
757 ok(hr == S_OK, "Got hr %#lx.\n", hr);
759 hr = IPin_BeginFlush(pin);
760 ok(hr == S_OK, "Got hr %#lx.\n", hr);
762 hr = join_thread(thread);
763 ok(hr == S_OK, "Got hr %#lx.\n", hr);
765 thread = send_frame(input);
766 hr = join_thread(thread);
767 todo_wine ok(hr == E_FAIL, "Got hr %#lx.\n", hr);
769 hr = IPin_EndFlush(pin);
770 ok(hr == S_OK, "Got hr %#lx.\n", hr);
772 /* We dropped the sample we were holding, so now we need a new one... */
774 hr = IMediaControl_GetState(control, 0, &state);
775 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
777 thread = send_frame(input);
778 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
780 hr = IMediaControl_Run(control);
781 ok(hr == S_OK, "Got hr %#lx.\n", hr);
782 hr = join_thread(thread);
783 ok(hr == S_OK, "Got hr %#lx.\n", hr);
785 hr = IPin_BeginFlush(pin);
786 ok(hr == S_OK, "Got hr %#lx.\n", hr);
788 hr = join_thread(send_frame(input));
789 todo_wine ok(hr == E_FAIL, "Got hr %#lx.\n", hr);
791 hr = IPin_EndFlush(pin);
792 ok(hr == S_OK, "Got hr %#lx.\n", hr);
794 hr = join_thread(send_frame(input));
795 ok(hr == S_OK, "Got hr %#lx.\n", hr);
797 hr = IMediaControl_Stop(control);
798 ok(hr == S_OK, "Got hr %#lx.\n", hr);
800 IMediaControl_Release(control);
803 static unsigned int check_event_code(IMediaEvent *eventsrc, DWORD timeout, LONG expected_code, LONG_PTR expected1, LONG_PTR expected2)
805 LONG_PTR param1, param2;
806 unsigned int ret = 0;
807 HRESULT hr;
808 LONG code;
810 while ((hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, timeout)) == S_OK)
812 if (code == expected_code)
814 ok(param1 == expected1, "Got param1 %#Ix.\n", param1);
815 ok(param2 == expected2, "Got param2 %#Ix.\n", param2);
816 ret++;
818 IMediaEvent_FreeEventParams(eventsrc, code, param1, param2);
819 timeout = 0;
821 ok(hr == E_ABORT, "Got hr %#lx.\n", hr);
823 return ret;
826 static unsigned int check_ec_complete(IMediaEvent *eventsrc, DWORD timeout)
828 return check_event_code(eventsrc, timeout, EC_COMPLETE, S_OK, 0);
831 static void test_connect_pin(void)
833 static const AM_MEDIA_TYPE req_mt =
835 .majortype = {0x111},
836 .subtype = {0x222},
837 .formattype = {0x333},
839 ALLOCATOR_PROPERTIES req_props = {1, 32 * 16 * 4, 1, 0}, ret_props;
840 IBaseFilter *filter = create_null_renderer();
841 struct testfilter source;
842 IMemAllocator *allocator;
843 IMediaControl *control;
844 IFilterGraph2 *graph;
845 IMemInputPin *input;
846 AM_MEDIA_TYPE mt;
847 IPin *pin, *peer;
848 HRESULT hr;
849 ULONG ref;
851 testfilter_init(&source);
853 CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
854 &IID_IFilterGraph2, (void **)&graph);
855 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, L"source");
856 IFilterGraph2_AddFilter(graph, filter, L"sink");
857 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
859 IBaseFilter_FindPin(filter, L"In", &pin);
861 peer = (IPin *)0xdeadbeef;
862 hr = IPin_ConnectedTo(pin, &peer);
863 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
864 ok(!peer, "Got peer %p.\n", peer);
866 hr = IPin_ConnectionMediaType(pin, &mt);
867 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
869 hr = IMediaControl_Pause(control);
870 ok(hr == S_OK, "Got hr %#lx.\n", hr);
871 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
872 ok(hr == VFW_E_NOT_STOPPED, "Got hr %#lx.\n", hr);
873 hr = IMediaControl_Stop(control);
874 ok(hr == S_OK, "Got hr %#lx.\n", hr);
876 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
877 ok(hr == S_OK, "Got hr %#lx.\n", hr);
879 hr = IPin_ConnectedTo(pin, &peer);
880 ok(hr == S_OK, "Got hr %#lx.\n", hr);
881 ok(peer == &source.source.pin.IPin_iface, "Got peer %p.\n", peer);
882 IPin_Release(peer);
884 hr = IPin_ConnectionMediaType(pin, &mt);
885 ok(hr == S_OK, "Got hr %#lx.\n", hr);
886 ok(!memcmp(&mt, &req_mt, sizeof(AM_MEDIA_TYPE)), "Media types didn't match.\n");
888 hr = IMediaControl_Pause(control);
889 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
890 hr = IFilterGraph2_Disconnect(graph, pin);
891 ok(hr == VFW_E_NOT_STOPPED, "Got hr %#lx.\n", hr);
892 hr = IMediaControl_Stop(control);
893 ok(hr == S_OK, "Got hr %#lx.\n", hr);
895 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
897 test_allocator(input);
899 hr = IMemInputPin_GetAllocator(input, &allocator);
900 ok(hr == S_OK, "Got hr %#lx.\n", hr);
901 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
902 ok(hr == S_OK, "Got hr %#lx.\n", hr);
903 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
904 hr = IMemAllocator_Commit(allocator);
905 ok(hr == S_OK, "Got hr %#lx.\n", hr);
906 IMemAllocator_Release(allocator);
908 hr = IMemInputPin_ReceiveCanBlock(input);
909 ok(hr == S_OK, "Got hr %#lx.\n", hr);
911 test_filter_state(input, graph);
912 test_flushing(pin, input, graph);
914 hr = IFilterGraph2_Disconnect(graph, pin);
915 ok(hr == S_OK, "Got hr %#lx.\n", hr);
916 hr = IFilterGraph2_Disconnect(graph, pin);
917 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
918 ok(source.source.pin.peer == pin, "Got peer %p.\n", peer);
919 IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
921 peer = (IPin *)0xdeadbeef;
922 hr = IPin_ConnectedTo(pin, &peer);
923 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
924 ok(!peer, "Got peer %p.\n", peer);
926 hr = IPin_ConnectionMediaType(pin, &mt);
927 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
929 IMemInputPin_Release(input);
930 IPin_Release(pin);
931 IMediaControl_Release(control);
932 ref = IFilterGraph2_Release(graph);
933 ok(!ref, "Got outstanding refcount %ld.\n", ref);
934 ref = IBaseFilter_Release(filter);
935 ok(!ref, "Got outstanding refcount %ld.\n", ref);
936 ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface);
937 ok(!ref, "Got outstanding refcount %ld.\n", ref);
940 static void test_unconnected_eos(void)
942 IBaseFilter *filter = create_null_renderer();
943 IFilterGraph2 *graph = create_graph();
944 IMediaControl *control;
945 IMediaEvent *eventsrc;
946 unsigned int ret;
947 HRESULT hr;
948 ULONG ref;
950 hr = IFilterGraph2_AddFilter(graph, filter, L"renderer");
951 ok(hr == S_OK, "Got hr %#lx.\n", hr);
953 hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
954 ok(hr == S_OK, "Got hr %#lx.\n", hr);
956 hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaEvent, (void **)&eventsrc);
957 ok(hr == S_OK, "Got hr %#lx.\n", hr);
959 ret = check_ec_complete(eventsrc, 0);
960 ok(!ret, "Got %u EC_COMPLETE events.\n", ret);
962 hr = IMediaControl_Pause(control);
963 ok(hr == S_OK, "Got hr %#lx.\n", hr);
965 ret = check_ec_complete(eventsrc, 0);
966 ok(!ret, "Got %u EC_COMPLETE events.\n", ret);
968 hr = IMediaControl_Run(control);
969 ok(hr == S_OK, "Got hr %#lx.\n", hr);
971 ret = check_ec_complete(eventsrc, 0);
972 ok(ret == 1, "Got %u EC_COMPLETE events.\n", ret);
974 hr = IMediaControl_Pause(control);
975 ok(hr == S_OK, "Got hr %#lx.\n", hr);
977 ret = check_ec_complete(eventsrc, 0);
978 ok(!ret, "Got %u EC_COMPLETE events.\n", ret);
980 hr = IMediaControl_Run(control);
981 ok(hr == S_OK, "Got hr %#lx.\n", hr);
983 ret = check_ec_complete(eventsrc, 0);
984 ok(ret == 1, "Got %u EC_COMPLETE events.\n", ret);
986 hr = IMediaControl_Stop(control);
987 ok(hr == S_OK, "Got hr %#lx.\n", hr);
989 ret = check_ec_complete(eventsrc, 0);
990 ok(!ret, "Got %u EC_COMPLETE events.\n", ret);
992 hr = IMediaControl_Run(control);
993 ok(hr == S_OK, "Got hr %#lx.\n", hr);
995 ret = check_ec_complete(eventsrc, 0);
996 ok(ret == 1, "Got %u EC_COMPLETE events.\n", ret);
998 IMediaControl_Release(control);
999 IMediaEvent_Release(eventsrc);
1000 ref = IFilterGraph2_Release(graph);
1001 ok(!ref, "Got outstanding refcount %ld.\n", ref);
1002 ref = IBaseFilter_Release(filter);
1003 ok(!ref, "Got outstanding refcount %ld.\n", ref);
1006 START_TEST(nullrenderer)
1008 IBaseFilter *filter;
1009 HRESULT hr;
1011 CoInitialize(NULL);
1013 if (FAILED(hr = CoCreateInstance(&CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER,
1014 &IID_IBaseFilter, (void **)&filter)))
1016 /* qedit.dll does not exist on 2003. */
1017 win_skip("Failed to create null renderer filter, hr %#lx.\n", hr);
1018 return;
1020 IBaseFilter_Release(filter);
1022 test_interfaces();
1023 test_enum_pins();
1024 test_find_pin();
1025 test_pin_info();
1026 test_aggregation();
1027 test_media_types();
1028 test_enum_media_types();
1029 test_connect_pin();
1030 test_unconnected_eos();
1032 CoUninitialize();