mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / qedit / tests / nullrenderer.c
blob1800f4dad4c675cd0bf4de845371561addf5202d
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 %#x.\n", hr);
32 return filter;
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;
47 IUnknown *unk;
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);
53 if (SUCCEEDED(hr))
54 IUnknown_Release(unk);
57 static void test_interfaces(void)
59 IBaseFilter *filter = create_null_renderer();
60 ULONG ref;
61 IPin *pin;
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);
92 IPin_Release(pin);
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;
101 ULONG count, ref;
102 IPin *pins[2];
103 HRESULT hr;
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;
191 IPin *pin, *pin2;
192 HRESULT hr;
193 ULONG ref;
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);
206 IPin_Release(pin2);
207 IPin_Release(pin);
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();
217 PIN_DIRECTION dir;
218 PIN_INFO info;
219 HRESULT hr;
220 WCHAR *id;
221 ULONG ref;
222 IPin *pin;
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));
249 CoTaskMemFree(id);
251 hr = IPin_QueryInternalConnections(pin, NULL, NULL);
252 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
254 IPin_Release(pin);
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;
269 return S_OK;
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,
288 outer_AddRef,
289 outer_Release,
292 static IUnknown test_outer = {&outer_vtbl};
294 static void test_aggregation(void)
296 IBaseFilter *filter, *filter2;
297 IUnknown *unk, *unk2;
298 HRESULT hr;
299 ULONG ref;
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;
358 HRESULT hr;
359 ULONG ref;
360 IPin *pin;
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);
375 IPin_Release(pin);
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];
385 ULONG ref, count;
386 HRESULT hr;
387 IPin *pin;
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);
418 IPin_Release(pin);
420 ref = IBaseFilter_Release(filter);
421 ok(!ref, "Got outstanding refcount %d.\n", ref);
424 struct testfilter
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);
438 if (!index)
439 return &filter->source.pin;
440 return NULL;
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)
459 return S_OK;
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;
479 HRESULT hr;
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);
487 if (hr == S_OK)
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
520 IMemInputPin *sink;
521 IMediaSample *sample;
524 static DWORD WINAPI frame_thread(void *arg)
526 struct frame_thread_params *params = arg;
527 HRESULT hr;
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);
533 free(params);
534 return hr;
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;
543 HANDLE thread;
544 HRESULT hr;
545 BYTE *data;
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);
565 params->sink = sink;
566 params->sample = sample;
567 thread = CreateThread(NULL, 0, frame_thread, params, 0, NULL);
569 IMemAllocator_Release(allocator);
570 return thread;
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)
580 DWORD ret;
581 ok_(__FILE__, line)(!WaitForSingleObject(thread, 1000), "Wait failed.\n");
582 GetExitCodeThread(thread, &ret);
583 CloseHandle(thread);
584 return 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;
593 OAFilterState state;
594 HANDLE thread;
595 HRESULT hr;
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
605 * stopped or run. */
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;
735 OAFilterState state;
736 HANDLE thread;
737 HRESULT hr;
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},
799 .subtype = {0x222},
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;
808 IMemInputPin *input;
809 AM_MEDIA_TYPE mt;
810 IPin *pin, *peer;
811 HRESULT hr;
812 ULONG ref;
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);
845 IPin_Release(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);
893 IPin_Release(pin);
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)
905 IBaseFilter *filter;
906 HRESULT hr;
908 CoInitialize(NULL);
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);
915 return;
917 IBaseFilter_Release(filter);
919 test_interfaces();
920 test_enum_pins();
921 test_find_pin();
922 test_pin_info();
923 test_aggregation();
924 test_media_types();
925 test_enum_media_types();
926 test_connect_pin();
928 CoUninitialize();