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
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
);
35 static WCHAR
*set_filename(IBaseFilter
*filter
)
37 static WCHAR filename
[MAX_PATH
];
38 IFileSinkFilter
*filesink
;
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
);
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
;
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
);
72 IUnknown_Release(unk
);
75 static void test_interfaces(void)
77 IBaseFilter
*filter
= create_file_writer();
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
);
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;
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
,
151 static IUnknown test_outer
= {&outer_vtbl
};
153 static void test_aggregation(void)
155 IBaseFilter
*filter
, *filter2
;
156 IUnknown
*unk
, *unk2
;
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
;
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
;
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
);
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();
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
));
363 hr
= IPin_QueryInternalConnections(pin
, NULL
, NULL
);
364 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
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
;
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
);
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];
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
);
473 ref
= IBaseFilter_Release(filter
);
474 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
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
);
492 return &filter
->source
.pin
;
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
)
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
;
534 memset(&props
, 0xcc, sizeof(props
));
535 hr
= IMemInputPin_GetAllocatorRequirements(input
, &props
);
536 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
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
);
552 props
.cbBuffer
= 512;
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
);
564 IMemAllocator_Release(ret_allocator
);
567 static void test_filter_state(IMediaControl
*control
)
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
;
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
);
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
));
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;
688 while ((hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, 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
);
696 IMediaEvent_FreeEventParams(eventsrc
, code
, param1
, param2
);
699 ok(hr
== E_ABORT
, "Got hr %#x.\n", hr
);
704 static void test_eos(IFilterGraph2
*graph
, IMediaControl
*control
, IPin
*pin
)
706 IMediaEvent
*eventsrc
;
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},
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
;
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
);
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
);
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
;
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
);
864 test_enum_media_types();