mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / qcap / tests / filewriter.c
blobd6dbc3faded4e7eb483325d777221839aabeb089
1 /*
2 * File writer filter unit tests
4 * Copyright (C) 2020 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_file_writer(void)
28 IBaseFilter *filter = NULL;
29 HRESULT hr = CoCreateInstance(&CLSID_FileWriter, NULL,
30 CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void **)&filter);
31 ok(hr == S_OK, "Got hr %#x.\n", hr);
32 return filter;
35 static WCHAR *set_filename(IBaseFilter *filter)
37 static WCHAR filename[MAX_PATH];
38 IFileSinkFilter *filesink;
39 WCHAR path[MAX_PATH];
40 HRESULT hr;
42 GetTempPathW(ARRAY_SIZE(path), path);
43 GetTempFileNameW(path, L"qfw", 0, filename);
44 DeleteFileW(filename);
46 IBaseFilter_QueryInterface(filter, &IID_IFileSinkFilter, (void **)&filesink);
47 hr = IFileSinkFilter_SetFileName(filesink, filename, NULL);
48 ok(hr == S_OK, "Got hr %#x.\n", hr);
49 IFileSinkFilter_Release(filesink);
50 return filename;
53 static ULONG get_refcount(void *iface)
55 IUnknown *unknown = iface;
56 IUnknown_AddRef(unknown);
57 return IUnknown_Release(unknown);
60 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
61 static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
63 IUnknown *iface = iface_ptr;
64 HRESULT hr, expected_hr;
65 IUnknown *unk;
67 expected_hr = supported ? S_OK : E_NOINTERFACE;
69 hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
70 ok_(__FILE__, line)(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr);
71 if (SUCCEEDED(hr))
72 IUnknown_Release(unk);
75 static void test_interfaces(void)
77 IBaseFilter *filter = create_file_writer();
78 ULONG ref;
79 IPin *pin;
81 check_interface(filter, &IID_IAMFilterMiscFlags, TRUE);
82 check_interface(filter, &IID_IBaseFilter, TRUE);
83 check_interface(filter, &IID_IFileSinkFilter, TRUE);
84 todo_wine check_interface(filter, &IID_IFileSinkFilter2, TRUE);
85 check_interface(filter, &IID_IMediaFilter, TRUE);
86 check_interface(filter, &IID_IPersist, TRUE);
87 todo_wine check_interface(filter, &IID_IPersistStream, TRUE);
88 check_interface(filter, &IID_IUnknown, TRUE);
90 check_interface(filter, &IID_IBasicAudio, FALSE);
91 check_interface(filter, &IID_IBasicVideo, FALSE);
92 check_interface(filter, &IID_IKsPropertySet, FALSE);
93 check_interface(filter, &IID_IMediaPosition, FALSE);
94 check_interface(filter, &IID_IMediaSeeking, FALSE);
95 check_interface(filter, &IID_IPersistPropertyBag, FALSE);
96 check_interface(filter, &IID_IPin, FALSE);
97 check_interface(filter, &IID_IQualityControl, FALSE);
98 check_interface(filter, &IID_IQualProp, FALSE);
99 check_interface(filter, &IID_IReferenceClock, FALSE);
100 check_interface(filter, &IID_IVideoWindow, FALSE);
102 IBaseFilter_FindPin(filter, L"in", &pin);
104 check_interface(pin, &IID_IMemInputPin, TRUE);
105 check_interface(pin, &IID_IPin, TRUE);
106 todo_wine check_interface(pin, &IID_IQualityControl, TRUE);
107 check_interface(pin, &IID_IUnknown, TRUE);
109 check_interface(pin, &IID_IKsPropertySet, FALSE);
110 check_interface(pin, &IID_IMediaPosition, FALSE);
111 check_interface(pin, &IID_IMediaSeeking, FALSE);
113 IPin_Release(pin);
114 ref = IBaseFilter_Release(filter);
115 ok(!ref, "Got unexpected refcount %d.\n", ref);
118 static const GUID test_iid = {0x33333333};
119 static LONG outer_ref = 1;
121 static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID iid, void **out)
123 if (IsEqualGUID(iid, &IID_IUnknown)
124 || IsEqualGUID(iid, &IID_IBaseFilter)
125 || IsEqualGUID(iid, &test_iid))
127 *out = (IUnknown *)0xdeadbeef;
128 return S_OK;
130 ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid));
131 return E_NOINTERFACE;
134 static ULONG WINAPI outer_AddRef(IUnknown *iface)
136 return InterlockedIncrement(&outer_ref);
139 static ULONG WINAPI outer_Release(IUnknown *iface)
141 return InterlockedDecrement(&outer_ref);
144 static const IUnknownVtbl outer_vtbl =
146 outer_QueryInterface,
147 outer_AddRef,
148 outer_Release,
151 static IUnknown test_outer = {&outer_vtbl};
153 static void test_aggregation(void)
155 IBaseFilter *filter, *filter2;
156 IUnknown *unk, *unk2;
157 HRESULT hr;
158 ULONG ref;
160 filter = (IBaseFilter *)0xdeadbeef;
161 hr = CoCreateInstance(&CLSID_FileWriter, &test_outer, CLSCTX_INPROC_SERVER,
162 &IID_IBaseFilter, (void **)&filter);
163 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
164 ok(!filter, "Got interface %p.\n", filter);
166 hr = CoCreateInstance(&CLSID_FileWriter, &test_outer, CLSCTX_INPROC_SERVER,
167 &IID_IUnknown, (void **)&unk);
168 ok(hr == S_OK, "Got hr %#x.\n", hr);
169 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
170 ok(unk != &test_outer, "Returned IUnknown should not be outer IUnknown.\n");
171 ref = get_refcount(unk);
172 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
174 ref = IUnknown_AddRef(unk);
175 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
176 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
178 ref = IUnknown_Release(unk);
179 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
180 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
182 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, (void **)&unk2);
183 ok(hr == S_OK, "Got hr %#x.\n", hr);
184 ok(unk2 == unk, "Got unexpected IUnknown %p.\n", unk2);
185 IUnknown_Release(unk2);
187 hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void **)&filter);
188 ok(hr == S_OK, "Got hr %#x.\n", hr);
190 hr = IBaseFilter_QueryInterface(filter, &IID_IUnknown, (void **)&unk2);
191 ok(hr == S_OK, "Got hr %#x.\n", hr);
192 ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
194 hr = IBaseFilter_QueryInterface(filter, &IID_IBaseFilter, (void **)&filter2);
195 ok(hr == S_OK, "Got hr %#x.\n", hr);
196 ok(filter2 == (IBaseFilter *)0xdeadbeef, "Got unexpected IBaseFilter %p.\n", filter2);
198 hr = IUnknown_QueryInterface(unk, &test_iid, (void **)&unk2);
199 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
200 ok(!unk2, "Got unexpected IUnknown %p.\n", unk2);
202 hr = IBaseFilter_QueryInterface(filter, &test_iid, (void **)&unk2);
203 ok(hr == S_OK, "Got hr %#x.\n", hr);
204 ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
206 IBaseFilter_Release(filter);
207 ref = IUnknown_Release(unk);
208 ok(!ref, "Got unexpected refcount %d.\n", ref);
209 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
212 static void test_enum_pins(void)
214 IBaseFilter *filter = create_file_writer();
215 IEnumPins *enum1, *enum2;
216 ULONG count, ref;
217 IPin *pins[2];
218 HRESULT hr;
220 ref = get_refcount(filter);
221 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
223 hr = IBaseFilter_EnumPins(filter, NULL);
224 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
226 hr = IBaseFilter_EnumPins(filter, &enum1);
227 ok(hr == S_OK, "Got hr %#x.\n", hr);
228 ref = get_refcount(filter);
229 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
230 ref = get_refcount(enum1);
231 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
233 hr = IEnumPins_Next(enum1, 1, NULL, NULL);
234 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
236 hr = IEnumPins_Next(enum1, 1, pins, NULL);
237 ok(hr == S_OK, "Got hr %#x.\n", hr);
238 ref = get_refcount(filter);
239 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
240 ref = get_refcount(pins[0]);
241 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
242 ref = get_refcount(enum1);
243 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
244 IPin_Release(pins[0]);
245 ref = get_refcount(filter);
246 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
248 hr = IEnumPins_Next(enum1, 1, pins, NULL);
249 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
251 hr = IEnumPins_Reset(enum1);
252 ok(hr == S_OK, "Got hr %#x.\n", hr);
254 hr = IEnumPins_Next(enum1, 1, pins, &count);
255 ok(hr == S_OK, "Got hr %#x.\n", hr);
256 ok(count == 1, "Got count %u.\n", count);
257 IPin_Release(pins[0]);
259 hr = IEnumPins_Next(enum1, 1, pins, &count);
260 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
261 ok(!count, "Got count %u.\n", count);
263 hr = IEnumPins_Reset(enum1);
264 ok(hr == S_OK, "Got hr %#x.\n", hr);
266 hr = IEnumPins_Next(enum1, 2, pins, NULL);
267 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
269 hr = IEnumPins_Next(enum1, 2, pins, &count);
270 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
271 ok(count == 1, "Got count %u.\n", count);
272 IPin_Release(pins[0]);
274 hr = IEnumPins_Reset(enum1);
275 ok(hr == S_OK, "Got hr %#x.\n", hr);
277 hr = IEnumPins_Clone(enum1, &enum2);
278 ok(hr == S_OK, "Got hr %#x.\n", hr);
280 hr = IEnumPins_Skip(enum1, 2);
281 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
283 hr = IEnumPins_Skip(enum1, 1);
284 ok(hr == S_OK, "Got hr %#x.\n", hr);
286 hr = IEnumPins_Skip(enum1, 1);
287 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
289 hr = IEnumPins_Next(enum1, 1, pins, NULL);
290 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
292 hr = IEnumPins_Next(enum2, 1, pins, NULL);
293 ok(hr == S_OK, "Got hr %#x.\n", hr);
294 IPin_Release(pins[0]);
296 IEnumPins_Release(enum2);
297 IEnumPins_Release(enum1);
298 ref = IBaseFilter_Release(filter);
299 ok(!ref, "Got outstanding refcount %d.\n", ref);
302 static void test_find_pin(void)
304 IBaseFilter *filter = create_file_writer();
305 IEnumPins *enum_pins;
306 IPin *pin, *pin2;
307 HRESULT hr;
308 ULONG ref;
310 hr = IBaseFilter_EnumPins(filter, &enum_pins);
311 ok(hr == S_OK, "Got hr %#x.\n", hr);
313 hr = IBaseFilter_FindPin(filter, L"in", &pin);
314 ok(hr == S_OK, "Got hr %#x.\n", hr);
315 hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL);
316 ok(hr == S_OK, "Got hr %#x.\n", hr);
317 ok(pin2 == pin, "Expected pin %p, got %p.\n", pin, pin2);
318 IPin_Release(pin2);
319 IPin_Release(pin);
321 IEnumPins_Release(enum_pins);
322 ref = IBaseFilter_Release(filter);
323 ok(!ref, "Got outstanding refcount %d.\n", ref);
326 static void test_pin_info(void)
328 IBaseFilter *filter = create_file_writer();
329 PIN_DIRECTION dir;
330 PIN_INFO info;
331 HRESULT hr;
332 WCHAR *id;
333 ULONG ref;
334 IPin *pin;
336 hr = IBaseFilter_FindPin(filter, L"in", &pin);
337 ok(hr == S_OK, "Got hr %#x.\n", hr);
338 ref = get_refcount(filter);
339 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
340 ref = get_refcount(pin);
341 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
343 hr = IPin_QueryPinInfo(pin, &info);
344 ok(hr == S_OK, "Got hr %#x.\n", hr);
345 ok(info.pFilter == filter, "Expected filter %p, got %p.\n", filter, info.pFilter);
346 ok(info.dir == PINDIR_INPUT, "Got direction %d.\n", info.dir);
347 ok(!wcscmp(info.achName, L"in"), "Got name %s.\n", wine_dbgstr_w(info.achName));
348 ref = get_refcount(filter);
349 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
350 ref = get_refcount(pin);
351 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
352 IBaseFilter_Release(info.pFilter);
354 hr = IPin_QueryDirection(pin, &dir);
355 ok(hr == S_OK, "Got hr %#x.\n", hr);
356 ok(dir == PINDIR_INPUT, "Got direction %d.\n", dir);
358 hr = IPin_QueryId(pin, &id);
359 ok(hr == S_OK, "Got hr %#x.\n", hr);
360 ok(!wcscmp(id, L"in"), "Got id %s.\n", wine_dbgstr_w(id));
361 CoTaskMemFree(id);
363 hr = IPin_QueryInternalConnections(pin, NULL, NULL);
364 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
366 IPin_Release(pin);
367 ref = IBaseFilter_Release(filter);
368 ok(!ref, "Got outstanding refcount %d.\n", ref);
371 static void test_media_types(void)
373 IBaseFilter *filter = create_file_writer();
374 AM_MEDIA_TYPE mt = {{0}}, *pmt;
375 IEnumMediaTypes *enummt;
376 WCHAR *filename;
377 HRESULT hr;
378 ULONG ref;
379 IPin *pin;
381 IBaseFilter_FindPin(filter, L"in", &pin);
383 hr = IPin_EnumMediaTypes(pin, &enummt);
384 ok(hr == S_OK, "Got hr %#x.\n", hr);
386 hr = IEnumMediaTypes_Next(enummt, 1, &pmt, NULL);
387 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
389 IEnumMediaTypes_Release(enummt);
391 hr = IPin_QueryAccept(pin, &mt);
392 ok(hr == S_OK, "Got hr %#x.\n", hr);
393 mt.majortype = MEDIATYPE_Audio;
394 mt.subtype = MEDIASUBTYPE_PCM;
395 mt.formattype = FORMAT_WaveFormatEx;
396 hr = IPin_QueryAccept(pin, &mt);
397 ok(hr == S_OK, "Got hr %#x.\n", hr);
399 filename = set_filename(filter);
401 hr = IPin_EnumMediaTypes(pin, &enummt);
402 ok(hr == S_OK, "Got hr %#x.\n", hr);
404 hr = IEnumMediaTypes_Next(enummt, 1, &pmt, NULL);
405 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
407 IEnumMediaTypes_Release(enummt);
409 memset(&mt, 0, sizeof(AM_MEDIA_TYPE));
410 hr = IPin_QueryAccept(pin, &mt);
411 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
412 mt.majortype = MEDIATYPE_Video;
413 hr = IPin_QueryAccept(pin, &mt);
414 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
415 mt.majortype = MEDIATYPE_Audio;
416 hr = IPin_QueryAccept(pin, &mt);
417 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
418 mt.majortype = MEDIATYPE_Stream;
419 hr = IPin_QueryAccept(pin, &mt);
420 ok(hr == S_OK, "Got hr %#x.\n", hr);
422 mt.subtype = MEDIASUBTYPE_PCM;
423 mt.formattype = FORMAT_WaveFormatEx;
424 hr = IPin_QueryAccept(pin, &mt);
425 ok(hr == S_OK, "Got hr %#x.\n", hr);
427 IPin_Release(pin);
428 ref = IBaseFilter_Release(filter);
429 ok(!ref, "Got outstanding refcount %d.\n", ref);
430 ok(GetFileAttributesW(filename) == INVALID_FILE_ATTRIBUTES, "File should not exist.\n");
433 static void test_enum_media_types(void)
435 IBaseFilter *filter = create_file_writer();
436 IEnumMediaTypes *enum1, *enum2;
437 AM_MEDIA_TYPE *mts[2];
438 ULONG ref, count;
439 HRESULT hr;
440 IPin *pin;
442 IBaseFilter_FindPin(filter, L"in", &pin);
444 hr = IPin_EnumMediaTypes(pin, &enum1);
445 ok(hr == S_OK, "Got hr %#x.\n", hr);
447 hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL);
448 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
450 hr = IEnumMediaTypes_Next(enum1, 1, mts, &count);
451 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
452 ok(!count, "Got count %u.\n", count);
454 hr = IEnumMediaTypes_Reset(enum1);
455 ok(hr == S_OK, "Got hr %#x.\n", hr);
457 hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL);
458 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
460 hr = IEnumMediaTypes_Clone(enum1, &enum2);
461 ok(hr == S_OK, "Got hr %#x.\n", hr);
463 hr = IEnumMediaTypes_Skip(enum1, 1);
464 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
466 hr = IEnumMediaTypes_Next(enum2, 1, mts, NULL);
467 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
469 IEnumMediaTypes_Release(enum1);
470 IEnumMediaTypes_Release(enum2);
471 IPin_Release(pin);
473 ref = IBaseFilter_Release(filter);
474 ok(!ref, "Got outstanding refcount %d.\n", ref);
477 struct testfilter
479 struct strmbase_filter filter;
480 struct strmbase_source source;
483 static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface)
485 return CONTAINING_RECORD(iface, struct testfilter, filter);
488 static struct strmbase_pin *testfilter_get_pin(struct strmbase_filter *iface, unsigned int index)
490 struct testfilter *filter = impl_from_strmbase_filter(iface);
491 if (!index)
492 return &filter->source.pin;
493 return NULL;
496 static void testfilter_destroy(struct strmbase_filter *iface)
498 struct testfilter *filter = impl_from_strmbase_filter(iface);
499 strmbase_source_cleanup(&filter->source);
500 strmbase_filter_cleanup(&filter->filter);
503 static const struct strmbase_filter_ops testfilter_ops =
505 .filter_get_pin = testfilter_get_pin,
506 .filter_destroy = testfilter_destroy,
509 static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface,
510 IMemInputPin *peer, IMemAllocator **allocator)
512 return S_OK;
515 static const struct strmbase_source_ops testsource_ops =
517 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
518 .pfnDecideAllocator = testsource_DecideAllocator,
521 static void testfilter_init(struct testfilter *filter)
523 static const GUID clsid = {0xabacab};
524 strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops);
525 strmbase_source_init(&filter->source, &filter->filter, L"", &testsource_ops);
528 static void test_allocator(IMemInputPin *input, IMemAllocator *allocator)
530 ALLOCATOR_PROPERTIES props, ret_props;
531 IMemAllocator *ret_allocator;
532 HRESULT hr;
534 memset(&props, 0xcc, sizeof(props));
535 hr = IMemInputPin_GetAllocatorRequirements(input, &props);
536 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
537 if (hr == S_OK)
539 ok(!props.cBuffers, "Got %d buffers.\n", props.cBuffers);
540 ok(!props.cbBuffer, "Got size %d.\n", props.cbBuffer);
541 ok(props.cbAlign == 512, "Got alignment %d.\n", props.cbAlign);
542 ok(!props.cbPrefix, "Got prefix %d.\n", props.cbPrefix);
545 hr = IMemInputPin_GetAllocator(input, &ret_allocator);
546 todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
548 hr = IMemInputPin_NotifyAllocator(input, NULL, TRUE);
549 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
551 props.cBuffers = 1;
552 props.cbBuffer = 512;
553 props.cbAlign = 512;
554 props.cbPrefix = 0;
555 hr = IMemAllocator_SetProperties(allocator, &props, &ret_props);
556 ok(hr == S_OK, "Got hr %#x.\n", hr);
558 hr = IMemInputPin_NotifyAllocator(input, allocator, TRUE);
559 ok(hr == S_OK, "Got hr %#x.\n", hr);
561 hr = IMemInputPin_GetAllocator(input, &ret_allocator);
562 todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
563 if (hr == S_OK)
564 IMemAllocator_Release(ret_allocator);
567 static void test_filter_state(IMediaControl *control)
569 OAFilterState state;
570 HRESULT hr;
572 hr = IMediaControl_GetState(control, 0, &state);
573 ok(hr == S_OK, "Got hr %#x.\n", hr);
574 ok(state == State_Stopped, "Got state %u.\n", state);
576 hr = IMediaControl_Pause(control);
577 ok(hr == S_OK, "Got hr %#x.\n", hr);
579 hr = IMediaControl_GetState(control, 0, &state);
580 ok(hr == S_OK, "Got hr %#x.\n", hr);
581 ok(state == State_Paused, "Got state %u.\n", state);
583 hr = IMediaControl_Run(control);
584 ok(hr == S_OK, "Got hr %#x.\n", hr);
586 hr = IMediaControl_GetState(control, 0, &state);
587 ok(hr == S_OK, "Got hr %#x.\n", hr);
588 ok(state == State_Running, "Got state %u.\n", state);
590 hr = IMediaControl_Pause(control);
591 ok(hr == S_OK, "Got hr %#x.\n", hr);
593 hr = IMediaControl_GetState(control, 0, &state);
594 ok(hr == S_OK, "Got hr %#x.\n", hr);
595 ok(state == State_Paused, "Got state %u.\n", state);
597 hr = IMediaControl_Stop(control);
598 ok(hr == S_OK, "Got hr %#x.\n", hr);
600 hr = IMediaControl_GetState(control, 0, &state);
601 ok(hr == S_OK, "Got hr %#x.\n", hr);
602 ok(state == State_Stopped, "Got state %u.\n", state);
604 hr = IMediaControl_Run(control);
605 ok(hr == S_OK, "Got hr %#x.\n", hr);
607 hr = IMediaControl_GetState(control, 0, &state);
608 ok(hr == S_OK, "Got hr %#x.\n", hr);
609 ok(state == State_Running, "Got state %u.\n", state);
611 hr = IMediaControl_Stop(control);
612 ok(hr == S_OK, "Got hr %#x.\n", hr);
614 hr = IMediaControl_GetState(control, 0, &state);
615 ok(hr == S_OK, "Got hr %#x.\n", hr);
616 ok(state == State_Stopped, "Got state %u.\n", state);
619 static void test_sample_processing(IMediaControl *control, IMemInputPin *input,
620 IMemAllocator *allocator, const WCHAR *filename)
622 REFERENCE_TIME start, stop;
623 IMediaSample *sample;
624 BYTE buffer[600];
625 FILE *file;
626 HRESULT hr;
627 BYTE *data;
628 LONG size;
630 hr = IMemInputPin_ReceiveCanBlock(input);
631 ok(hr == S_OK, "Got hr %#x.\n", hr);
633 hr = IMediaControl_Pause(control);
634 ok(hr == S_OK, "Got hr %#x.\n", hr);
636 hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
637 ok(hr == VFW_E_NOT_COMMITTED, "Got hr %#x.\n", hr);
639 hr = IMemAllocator_Commit(allocator);
640 ok(hr == S_OK, "Got hr %#x.\n", hr);
642 hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
643 ok(hr == S_OK, "Got hr %#x.\n", hr);
645 hr = IMediaSample_GetPointer(sample, &data);
646 ok(hr == S_OK, "Got hr %#x.\n", hr);
647 size = IMediaSample_GetSize(sample);
648 ok(size == 512, "Got size %d.\n", size);
649 memset(data, 0xcc, size);
650 start = 0;
651 stop = 512;
652 hr = IMediaSample_SetTime(sample, &start, &stop);
653 ok(hr == S_OK, "Got hr %#x.\n", hr);
655 strcpy((char *)data, "abcdefghi");
656 hr = IMediaSample_SetActualDataLength(sample, 9);
657 ok(hr == S_OK, "Got hr %#x.\n", hr);
658 hr = IMemInputPin_Receive(input, sample);
659 ok(hr == S_OK, "Got hr %#x.\n", hr);
661 memset(data, 0xcc, size);
662 strcpy((char *)data, "123456");
663 hr = IMediaSample_SetActualDataLength(sample, 6);
664 ok(hr == S_OK, "Got hr %#x.\n", hr);
665 hr = IMemInputPin_Receive(input, sample);
666 ok(hr == S_OK, "Got hr %#x.\n", hr);
668 file = _wfopen(filename, L"rb");
669 ok(!!file, "Failed to open file: %s.\n", strerror(errno));
670 size = fread(buffer, 1, sizeof(buffer), file);
671 ok(size == 512, "Got size %d.\n", size);
672 ok(!memcmp(buffer, "123456\0\xcc\xcc\xcc", 10), "Got data %s.\n",
673 debugstr_an((char *)buffer, size));
674 fclose(file);
676 hr = IMediaControl_Stop(control);
677 ok(hr == S_OK, "Got hr %#x.\n", hr);
678 IMediaSample_Release(sample);
681 static unsigned int check_ec_complete(IMediaEvent *eventsrc, DWORD timeout)
683 LONG_PTR param1, param2;
684 unsigned int ret = 0;
685 HRESULT hr;
686 LONG code;
688 while ((hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, timeout)) == S_OK)
690 if (code == EC_COMPLETE)
692 ok(param1 == S_OK, "Got param1 %#lx.\n", param1);
693 ok(!param2, "Got param2 %#lx.\n", param2);
694 ret++;
696 IMediaEvent_FreeEventParams(eventsrc, code, param1, param2);
697 timeout = 0;
699 ok(hr == E_ABORT, "Got hr %#x.\n", hr);
701 return ret;
704 static void test_eos(IFilterGraph2 *graph, IMediaControl *control, IPin *pin)
706 IMediaEvent *eventsrc;
707 HRESULT hr;
708 BOOL ret;
710 IFilterGraph2_QueryInterface(graph, &IID_IMediaEvent, (void **)&eventsrc);
712 hr = IMediaControl_Pause(control);
713 ok(hr == S_OK, "Got hr %#x.\n", hr);
714 ret = check_ec_complete(eventsrc, 0);
715 ok(!ret, "Got unexpected EC_COMPLETE.\n");
717 hr = IPin_EndOfStream(pin);
718 ok(hr == S_OK, "Got hr %#x.\n", hr);
719 ret = check_ec_complete(eventsrc, 0);
720 ok(!ret, "Got unexpected EC_COMPLETE.\n");
722 hr = IMediaControl_Run(control);
723 ok(hr == S_OK, "Got hr %#x.\n", hr);
724 ret = check_ec_complete(eventsrc, 0);
725 ok(ret == 1, "Expected EC_COMPLETE.\n");
727 hr = IMediaControl_Stop(control);
728 ok(hr == S_OK, "Got hr %#x.\n", hr);
729 IMediaEvent_Release(eventsrc);
732 static void test_connect_pin(void)
734 AM_MEDIA_TYPE req_mt =
736 .majortype = {0x1111},
737 .subtype = {0x2222},
738 .formattype = {0x3333},
741 IBaseFilter *filter = create_file_writer();
742 WCHAR *filename = set_filename(filter);
743 struct testfilter source;
744 IMemAllocator *allocator;
745 IMediaControl *control;
746 IMemInputPin *meminput;
747 IFilterGraph2 *graph;
748 AM_MEDIA_TYPE mt;
749 IPin *pin, *peer;
750 HRESULT hr;
751 ULONG ref;
752 BOOL ret;
754 testfilter_init(&source);
755 CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (void **)&graph);
756 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
757 hr = IFilterGraph2_AddFilter(graph, filter, L"filewriter");
758 ok(hr == S_OK, "Got hr %#x.\n", hr);
759 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, L"source");
760 IBaseFilter_FindPin(filter, L"in", &pin);
761 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&meminput);
763 peer = (IPin *)0xdeadbeef;
764 hr = IPin_ConnectedTo(pin, &peer);
765 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
766 ok(!peer, "Got peer %p.\n", peer);
768 hr = IPin_ConnectionMediaType(pin, &mt);
769 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
771 hr = IMediaControl_Pause(control);
772 ok(hr == S_OK, "Got hr %#x.\n", hr);
773 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
774 ok(hr == VFW_E_NOT_STOPPED, "Got hr %#x.\n", hr);
775 hr = IMediaControl_Stop(control);
776 ok(hr == S_OK, "Got hr %#x.\n", hr);
778 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
779 ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr);
780 req_mt.majortype = MEDIATYPE_Stream;
781 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
782 ok(hr == S_OK, "Got hr %#x.\n", hr);
784 hr = IPin_ConnectedTo(pin, &peer);
785 ok(hr == S_OK, "Got hr %#x.\n", hr);
786 ok(peer == &source.source.pin.IPin_iface, "Got peer %p.\n", peer);
787 IPin_Release(peer);
789 hr = IPin_ConnectionMediaType(pin, &mt);
790 ok(hr == S_OK, "Got hr %#x.\n", hr);
791 ok(!memcmp(&mt, &req_mt, sizeof(AM_MEDIA_TYPE)), "Media types didn't match.\n");
793 hr = IMediaControl_Pause(control);
794 ok(hr == S_OK, "Got hr %#x.\n", hr);
795 hr = IFilterGraph2_Disconnect(graph, pin);
796 ok(hr == VFW_E_NOT_STOPPED, "Got hr %#x.\n", hr);
797 hr = IMediaControl_Stop(control);
798 todo_wine ok(hr == VFW_E_NO_ALLOCATOR, "Got hr %#x.\n", hr);
800 CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
801 &IID_IMemAllocator, (void **)&allocator);
803 test_allocator(meminput, allocator);
804 test_filter_state(control);
805 test_sample_processing(control, meminput, allocator, filename);
806 test_eos(graph, control, pin);
808 hr = IFilterGraph2_Disconnect(graph, pin);
809 ok(hr == S_OK, "Got hr %#x.\n", hr);
810 hr = IFilterGraph2_Disconnect(graph, pin);
811 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
812 ok(source.source.pin.peer == pin, "Got peer %p.\n", source.source.pin.peer);
813 IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
815 peer = (IPin *)0xdeadbeef;
816 hr = IPin_ConnectedTo(pin, &peer);
817 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
818 ok(!peer, "Got peer %p.\n", peer);
820 hr = IPin_ConnectionMediaType(pin, &mt);
821 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
823 ret = DeleteFileW(filename);
824 ok(ret, "Failed to delete file, error %u.\n", GetLastError());
825 IMediaControl_Release(control);
826 ref = IFilterGraph2_Release(graph);
827 ok(!ref, "Got outstanding refcount %d.\n", ref);
828 IMemInputPin_Release(meminput);
829 IPin_Release(pin);
830 ref = IBaseFilter_Release(filter);
831 ok(!ref, "Got outstanding refcount %d.\n", ref);
832 ref = IMemAllocator_Release(allocator);
833 ok(!ref, "Got outstanding refcount %d.\n", ref);
834 ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface);
835 ok(!ref, "Got outstanding refcount %d.\n", ref);
838 static void test_misc_flags(void)
840 IBaseFilter *filter = create_file_writer();
841 IAMFilterMiscFlags *misc_flags;
842 ULONG flags, ref;
844 IBaseFilter_QueryInterface(filter, &IID_IAMFilterMiscFlags, (void **)&misc_flags);
846 flags = IAMFilterMiscFlags_GetMiscFlags(misc_flags);
847 ok(flags == AM_FILTER_MISC_FLAGS_IS_RENDERER, "Got flags %#x.\n", flags);
849 IAMFilterMiscFlags_Release(misc_flags);
850 ref = IBaseFilter_Release(filter);
851 ok(!ref, "Got outstanding refcount %d.\n", ref);
854 START_TEST(filewriter)
856 CoInitializeEx(NULL, COINIT_MULTITHREADED);
858 test_interfaces();
859 test_aggregation();
860 test_enum_pins();
861 test_find_pin();
862 test_pin_info();
863 test_media_types();
864 test_enum_media_types();
865 test_connect_pin();
866 test_misc_flags();
868 CoUninitialize();