mfreadwrite/reader: Enable DXGI device manager path.
[wine/zf.git] / dlls / qcap / tests / videocapture.c
blobfafd18009f4807834d10f529852daa669aa635e0
1 /*
2 * WDM video capture filter unit tests
4 * Copyright 2019 Damjan Jovanovic
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/test.h"
24 #include "wine/strmbase.h"
26 static BOOL compare_media_types(const AM_MEDIA_TYPE *a, const AM_MEDIA_TYPE *b)
28 return !memcmp(a, b, offsetof(AM_MEDIA_TYPE, pbFormat))
29 && !memcmp(a->pbFormat, b->pbFormat, a->cbFormat);
32 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
33 static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
35 IUnknown *iface = iface_ptr;
36 HRESULT hr, expected_hr;
37 IUnknown *unk;
39 expected_hr = supported ? S_OK : E_NOINTERFACE;
41 hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
42 ok_(__FILE__, line)(hr == expected_hr, "Got hr %#x, expected %#x.\n", hr, expected_hr);
43 if (SUCCEEDED(hr))
44 IUnknown_Release(unk);
47 static void test_media_types(IPin *pin)
49 IEnumMediaTypes *enum_media_types;
50 AM_MEDIA_TYPE mt, *pmt;
51 HRESULT hr;
53 hr = IPin_EnumMediaTypes(pin, &enum_media_types);
54 ok(hr == S_OK, "Got hr %#x.\n", hr);
56 while (IEnumMediaTypes_Next(enum_media_types, 1, &pmt, NULL) == S_OK)
58 hr = IPin_QueryAccept(pin, pmt);
59 ok(hr == S_OK, "Got hr %#x.\n", hr);
60 CoTaskMemFree(pmt);
62 IEnumMediaTypes_Release(enum_media_types);
64 hr = IPin_QueryAccept(pin, NULL);
65 todo_wine ok(hr == E_POINTER, "Got hr %#x.\n", hr);
67 memset(&mt, 0, sizeof(mt));
68 hr = IPin_QueryAccept(pin, &mt);
69 ok(hr != S_OK, "Got hr %#x.\n", hr);
71 mt.majortype = MEDIATYPE_Video;
72 hr = IPin_QueryAccept(pin, &mt);
73 ok(hr != S_OK, "Got hr %#x.\n", hr);
75 mt.formattype = FORMAT_VideoInfo;
76 hr = IPin_QueryAccept(pin, &mt);
77 ok(hr != S_OK, "Got hr %#x.\n", hr);
79 mt.formattype = FORMAT_None;
80 hr = IPin_QueryAccept(pin, &mt);
81 ok(hr != S_OK, "Got hr %#x.\n", hr);
84 static void test_stream_config(IPin *pin)
86 VIDEOINFOHEADER *video_info, *video_info2;
87 LONG depth, compression, count, size, i;
88 IEnumMediaTypes *enum_media_types;
89 AM_MEDIA_TYPE *format, *format2;
90 IAMStreamConfig *stream_config;
91 VIDEO_STREAM_CONFIG_CAPS vscc;
92 HRESULT hr;
94 hr = IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **)&stream_config);
95 ok(hr == S_OK, "Got hr %#x.\n", hr);
97 hr = IAMStreamConfig_GetFormat(stream_config, &format);
98 ok(hr == S_OK, "Got hr %#x.\n", hr);
99 ok(IsEqualGUID(&format->majortype, &MEDIATYPE_Video), "Got wrong majortype: %s.\n",
100 debugstr_guid(&format->majortype));
102 hr = IAMStreamConfig_SetFormat(stream_config, format);
103 ok(hr == S_OK, "Got hr %#x.\n", hr);
105 /* After setting the format, a single media type is enumerated.
106 * This persists until the filter is released. */
107 IPin_EnumMediaTypes(pin, &enum_media_types);
108 hr = IEnumMediaTypes_Next(enum_media_types, 1, &format2, NULL);
109 ok(hr == S_OK, "Got hr %#x.\n", hr);
110 DeleteMediaType(format2);
111 hr = IEnumMediaTypes_Next(enum_media_types, 1, &format2, NULL);
112 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
113 IEnumMediaTypes_Release(enum_media_types);
115 format->majortype = MEDIATYPE_Audio;
116 hr = IAMStreamConfig_SetFormat(stream_config, format);
117 ok(hr == E_FAIL, "Got hr %#x.\n", hr);
119 format->majortype = MEDIATYPE_Video;
120 video_info = (VIDEOINFOHEADER *)format->pbFormat;
121 video_info->bmiHeader.biWidth--;
122 video_info->bmiHeader.biHeight--;
123 hr = IAMStreamConfig_SetFormat(stream_config, format);
124 ok(hr == E_FAIL, "Got hr %#x.\n", hr);
126 depth = video_info->bmiHeader.biBitCount;
127 compression = video_info->bmiHeader.biCompression;
128 video_info->bmiHeader.biWidth++;
129 video_info->bmiHeader.biHeight++;
130 video_info->bmiHeader.biBitCount = 0;
131 video_info->bmiHeader.biCompression = 0;
132 hr = IAMStreamConfig_SetFormat(stream_config, format);
133 ok(hr == S_OK, "Got hr %#x.\n", hr);
135 hr = IAMStreamConfig_GetFormat(stream_config, &format2);
136 ok(hr == S_OK, "Got hr %#x.\n", hr);
137 ok(IsEqualGUID(&format2->majortype, &MEDIATYPE_Video), "Got wrong majortype: %s.\n",
138 debugstr_guid(&format2->majortype));
139 video_info2 = (VIDEOINFOHEADER *)format2->pbFormat;
140 ok(video_info2->bmiHeader.biBitCount == depth, "Got wrong depth: %d.\n",
141 video_info2->bmiHeader.biBitCount);
142 ok(video_info2->bmiHeader.biCompression == compression,
143 "Got wrong compression: %d.\n", video_info2->bmiHeader.biCompression);
144 FreeMediaType(format2);
146 video_info->bmiHeader.biWidth = 10000000;
147 video_info->bmiHeader.biHeight = 10000000;
148 hr = IAMStreamConfig_SetFormat(stream_config, format);
149 ok(hr == E_FAIL, "Got hr %#x.\n", hr);
150 FreeMediaType(format);
152 count = 0xdeadbeef;
153 size = 0xdeadbeef;
154 /* Crash on Windows */
155 if (0)
157 hr = IAMStreamConfig_GetNumberOfCapabilities(stream_config, &count, NULL);
158 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
160 hr = IAMStreamConfig_GetNumberOfCapabilities(stream_config, NULL, &size);
161 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
163 hr = IAMStreamConfig_GetStreamCaps(stream_config, 0, NULL, (BYTE *)&vscc);
164 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
166 hr = IAMStreamConfig_GetStreamCaps(stream_config, 0, &format, NULL);
167 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
170 hr = IAMStreamConfig_GetNumberOfCapabilities(stream_config, &count, &size);
171 ok(hr == S_OK, "Got hr %#x.\n", hr);
172 ok(count != 0xdeadbeef, "Got wrong count: %d.\n", count);
173 ok(size == sizeof(VIDEO_STREAM_CONFIG_CAPS), "Got wrong size: %d.\n", size);
175 hr = IAMStreamConfig_GetStreamCaps(stream_config, 100000, NULL, NULL);
176 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
178 hr = IAMStreamConfig_GetStreamCaps(stream_config, 100000, &format, (BYTE *)&vscc);
179 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
181 for (i = 0; i < count; ++i)
183 hr = IAMStreamConfig_GetStreamCaps(stream_config, i, &format, (BYTE *)&vscc);
184 ok(hr == S_OK, "Got hr %#x.\n", hr);
185 ok(IsEqualGUID(&format->majortype, &MEDIATYPE_Video), "Got wrong majortype: %s.\n",
186 debugstr_guid(&MEDIATYPE_Video));
187 ok(IsEqualGUID(&vscc.guid, &FORMAT_VideoInfo)
188 || IsEqualGUID(&vscc.guid, &FORMAT_VideoInfo2), "Got wrong guid: %s.\n",
189 debugstr_guid(&vscc.guid));
191 hr = IAMStreamConfig_SetFormat(stream_config, format);
192 ok(hr == S_OK, "Got hr %#x.\n", hr);
194 hr = IAMStreamConfig_GetFormat(stream_config, &format2);
195 ok(hr == S_OK, "Got hr %#x.\n", hr);
196 ok(compare_media_types(format, format2), "Media types didn't match.\n");
197 DeleteMediaType(format2);
199 hr = IPin_EnumMediaTypes(pin, &enum_media_types);
200 ok(hr == S_OK, "Got hr %#x.\n", hr);
201 hr = IEnumMediaTypes_Next(enum_media_types, 1, &format2, NULL);
202 ok(hr == S_OK, "Got hr %#x.\n", hr);
203 ok(compare_media_types(format, format2), "Media types didn't match.\n");
204 DeleteMediaType(format2);
205 IEnumMediaTypes_Release(enum_media_types);
207 DeleteMediaType(format);
210 IAMStreamConfig_Release(stream_config);
213 static void test_pin_interfaces(IPin *pin)
215 todo_wine check_interface(pin, &IID_IAMBufferNegotiation, TRUE);
216 check_interface(pin, &IID_IAMStreamConfig, TRUE);
217 todo_wine check_interface(pin, &IID_IAMStreamControl, TRUE);
218 todo_wine check_interface(pin, &IID_IKsPin, TRUE);
219 check_interface(pin, &IID_IKsPropertySet, TRUE);
220 todo_wine check_interface(pin, &IID_IMediaSeeking, TRUE);
221 check_interface(pin, &IID_IPin, TRUE);
222 todo_wine check_interface(pin, &IID_IQualityControl, TRUE);
223 todo_wine check_interface(pin, &IID_ISpecifyPropertyPages, TRUE);
225 check_interface(pin, &IID_IAMCrossbar, FALSE);
226 check_interface(pin, &IID_IAMDroppedFrames, FALSE);
227 check_interface(pin, &IID_IAMFilterMiscFlags, FALSE);
228 check_interface(pin, &IID_IAMPushSource, FALSE);
229 check_interface(pin, &IID_IAMTVTuner, FALSE);
230 check_interface(pin, &IID_IAMVideoCompression, FALSE);
231 check_interface(pin, &IID_IAMVideoProcAmp, FALSE);
232 check_interface(pin, &IID_IPersistPropertyBag, FALSE);
233 check_interface(pin, &IID_IStreamBuilder, FALSE);
236 static void test_pins(IBaseFilter *filter)
238 IEnumPins *enum_pins;
239 IPin *pin;
240 HRESULT hr;
242 hr = IBaseFilter_EnumPins(filter, &enum_pins);
243 ok(hr == S_OK, "Got hr %#x.\n", hr);
245 while ((hr = IEnumPins_Next(enum_pins, 1, &pin, NULL)) == S_OK)
247 PIN_DIRECTION pin_direction;
248 IPin_QueryDirection(pin, &pin_direction);
249 if (pin_direction == PINDIR_OUTPUT)
251 test_pin_interfaces(pin);
252 test_media_types(pin);
253 test_stream_config(pin);
255 IPin_Release(pin);
258 IEnumPins_Release(enum_pins);
261 static void test_filter_interfaces(IBaseFilter *filter)
263 check_interface(filter, &IID_IAMFilterMiscFlags, TRUE);
264 check_interface(filter, &IID_IAMVideoControl, TRUE);
265 check_interface(filter, &IID_IAMVideoProcAmp, TRUE);
266 check_interface(filter, &IID_IBaseFilter, TRUE);
267 todo_wine check_interface(filter, &IID_IKsPropertySet, TRUE);
268 todo_wine check_interface(filter, &IID_IMediaSeeking, TRUE);
269 check_interface(filter, &IID_IPersistPropertyBag, TRUE);
270 todo_wine check_interface(filter, &IID_ISpecifyPropertyPages, TRUE);
272 check_interface(filter, &IID_IAMCrossbar, FALSE);
273 check_interface(filter, &IID_IAMPushSource, FALSE);
274 check_interface(filter, &IID_IAMStreamConfig, FALSE);
275 check_interface(filter, &IID_IAMTVTuner, FALSE);
276 check_interface(filter, &IID_IAMVideoCompression, FALSE);
277 check_interface(filter, &IID_IAMVfwCaptureDialogs, FALSE);
278 check_interface(filter, &IID_IPin, FALSE);
279 check_interface(filter, &IID_IReferenceClock, FALSE);
280 check_interface(filter, &IID_IOverlayNotify, FALSE);
283 static void test_misc_flags(IBaseFilter *filter)
285 IAMFilterMiscFlags *misc_flags;
286 ULONG flags;
287 HRESULT hr;
289 hr = IBaseFilter_QueryInterface(filter, &IID_IAMFilterMiscFlags, (void **)&misc_flags);
290 ok(hr == S_OK, "Got hr %#x.\n", hr);
292 flags = IAMFilterMiscFlags_GetMiscFlags(misc_flags);
293 ok(flags == AM_FILTER_MISC_FLAGS_IS_SOURCE
294 || broken(!flags) /* win7 */, "Got wrong flags: %#x.\n", flags);
296 IAMFilterMiscFlags_Release(misc_flags);
299 struct testfilter
301 struct strmbase_filter filter;
302 struct strmbase_sink sink;
305 static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface)
307 return CONTAINING_RECORD(iface, struct testfilter, filter);
310 static struct strmbase_pin *testfilter_get_pin(struct strmbase_filter *iface, unsigned int index)
312 struct testfilter *filter = impl_from_strmbase_filter(iface);
313 if (!index)
314 return &filter->sink.pin;
315 return NULL;
318 static void testfilter_destroy(struct strmbase_filter *iface)
320 struct testfilter *filter = impl_from_strmbase_filter(iface);
321 strmbase_sink_cleanup(&filter->sink);
322 strmbase_filter_cleanup(&filter->filter);
325 static const struct strmbase_filter_ops testfilter_ops =
327 .filter_get_pin = testfilter_get_pin,
328 .filter_destroy = testfilter_destroy,
331 static HRESULT testsink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
333 struct testfilter *filter = impl_from_strmbase_filter(iface->filter);
335 if (IsEqualGUID(iid, &IID_IMemInputPin))
336 *out = &filter->sink.IMemInputPin_iface;
337 else
338 return E_NOINTERFACE;
340 IUnknown_AddRef((IUnknown *)*out);
341 return S_OK;
344 static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample *sample)
346 return S_OK;
349 static const struct strmbase_sink_ops testsink_ops =
351 .base.pin_query_interface = testsink_query_interface,
352 .pfnReceive = testsink_Receive,
355 static void testfilter_init(struct testfilter *filter)
357 static const GUID clsid = {0xabacab};
358 memset(filter, 0, sizeof(*filter));
359 strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops);
360 strmbase_sink_init(&filter->sink, &filter->filter, L"sink", &testsink_ops, NULL);
363 static void test_connect_pin(IBaseFilter *filter, IPin *source)
365 AM_MEDIA_TYPE req_mt, default_mt, mt, *mts[2];
366 IAMStreamConfig *stream_config;
367 struct testfilter testsink;
368 IEnumMediaTypes *enummt;
369 IFilterGraph2 *graph;
370 ULONG count, ref;
371 HRESULT hr;
372 IPin *peer;
374 CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
375 &IID_IFilterGraph2, (void **)&graph);
376 testfilter_init(&testsink);
377 IFilterGraph2_AddFilter(graph, &testsink.filter.IBaseFilter_iface, L"sink");
378 IFilterGraph2_AddFilter(graph, filter, L"source");
379 hr = IPin_QueryInterface(source, &IID_IAMStreamConfig, (void **)&stream_config);
380 ok(hr == S_OK, "Got hr %#x.\n", hr);
382 peer = (IPin *)0xdeadbeef;
383 hr = IPin_ConnectedTo(source, &peer);
384 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
385 ok(!peer, "Got peer %p.\n", peer);
387 hr = IPin_ConnectionMediaType(source, &mt);
388 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
390 hr = IPin_EnumMediaTypes(source, &enummt);
391 ok(hr == S_OK, "Got hr %#x.\n", hr);
392 hr = IEnumMediaTypes_Next(enummt, 2, mts, &count);
393 ok(SUCCEEDED(hr), "Got hr %#x.\n", hr);
394 CopyMediaType(&req_mt, mts[count - 1]);
395 CopyMediaType(&default_mt, mts[0]);
396 DeleteMediaType(mts[0]);
397 if (count > 1)
398 DeleteMediaType(mts[1]);
399 IEnumMediaTypes_Release(enummt);
401 hr = IAMStreamConfig_GetFormat(stream_config, &mts[0]);
402 ok(hr == S_OK, "Got hr %#x.\n", hr);
403 ok(compare_media_types(mts[0], &default_mt), "Media types didn't match.\n");
404 DeleteMediaType(mts[0]);
406 hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
407 ok(hr == S_OK, "Got hr %#x.\n", hr);
409 hr = IPin_ConnectedTo(source, &peer);
410 ok(hr == S_OK, "Got hr %#x.\n", hr);
411 ok(peer == &testsink.sink.pin.IPin_iface, "Got peer %p.\n", peer);
412 IPin_Release(peer);
414 hr = IPin_ConnectionMediaType(source, &mt);
415 ok(hr == S_OK, "Got hr %#x.\n", hr);
416 ok(compare_media_types(&mt, &req_mt), "Media types didn't match.\n");
417 ok(compare_media_types(&testsink.sink.pin.mt, &req_mt), "Media types didn't match.\n");
418 FreeMediaType(&mt);
420 hr = IAMStreamConfig_GetFormat(stream_config, &mts[0]);
421 ok(hr == S_OK, "Got hr %#x.\n", hr);
422 ok(compare_media_types(mts[0], &req_mt), "Media types didn't match.\n");
423 DeleteMediaType(mts[0]);
425 hr = IPin_EnumMediaTypes(source, &enummt);
426 ok(hr == S_OK, "Got hr %#x.\n", hr);
427 hr = IEnumMediaTypes_Next(enummt, 1, mts, NULL);
428 ok(hr == S_OK, "Got hr %#x.\n", hr);
429 ok(compare_media_types(mts[0], &default_mt), "Media types didn't match.\n");
430 DeleteMediaType(mts[0]);
431 IEnumMediaTypes_Release(enummt);
433 hr = IFilterGraph2_Disconnect(graph, source);
434 ok(hr == S_OK, "Got hr %#x.\n", hr);
435 hr = IFilterGraph2_Disconnect(graph, source);
436 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
437 ok(testsink.sink.pin.peer == source, "Got peer %p.\n", testsink.sink.pin.peer);
438 IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface);
440 hr = IAMStreamConfig_GetFormat(stream_config, &mts[0]);
441 ok(hr == S_OK, "Got hr %#x.\n", hr);
442 ok(compare_media_types(mts[0], &default_mt), "Media types didn't match.\n");
443 DeleteMediaType(mts[0]);
445 FreeMediaType(&req_mt);
446 FreeMediaType(&default_mt);
447 IAMStreamConfig_Release(stream_config);
448 ref = IFilterGraph2_Release(graph);
449 ok(!ref, "Got outstanding refcount %d.\n", ref);
450 ref = IBaseFilter_Release(&testsink.filter.IBaseFilter_iface);
451 ok(!ref, "Got outstanding refcount %d.\n", ref);
454 static void test_connection(IMoniker *moniker)
456 IEnumPins *enum_pins;
457 IBaseFilter *filter;
458 HRESULT hr;
459 ULONG ref;
460 IPin *pin;
462 hr = IMoniker_BindToObject(moniker, NULL, NULL, &IID_IBaseFilter, (void **)&filter);
463 ok(hr == S_OK, "Got hr %#x.\n", hr);
465 hr = IBaseFilter_EnumPins(filter, &enum_pins);
466 ok(hr == S_OK, "Got hr %#x.\n", hr);
468 while (IEnumPins_Next(enum_pins, 1, &pin, NULL) == S_OK)
470 PIN_DIRECTION dir;
471 IPin_QueryDirection(pin, &dir);
472 if (dir == PINDIR_OUTPUT)
474 test_connect_pin(filter, pin);
476 IPin_Release(pin);
479 IEnumPins_Release(enum_pins);
480 ref = IBaseFilter_Release(filter);
481 ok(!ref, "Got outstanding refcount %d.\n", ref);
484 START_TEST(videocapture)
486 ICreateDevEnum *dev_enum;
487 IEnumMoniker *class_enum;
488 IBaseFilter *filter;
489 IMoniker *moniker;
490 WCHAR *name;
491 HRESULT hr;
492 ULONG ref;
494 CoInitialize(NULL);
496 hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
497 &IID_ICreateDevEnum, (void **)&dev_enum);
498 ok(hr == S_OK, "Got hr %#x.\n", hr);
500 hr = ICreateDevEnum_CreateClassEnumerator(dev_enum, &CLSID_VideoInputDeviceCategory, &class_enum, 0);
501 if (hr == S_FALSE)
503 skip("No video capture devices present.\n");
504 ICreateDevEnum_Release(dev_enum);
505 CoUninitialize();
506 return;
508 ok(hr == S_OK, "Got hr=%#x.\n", hr);
510 while (IEnumMoniker_Next(class_enum, 1, &moniker, NULL) == S_OK)
512 hr = IMoniker_GetDisplayName(moniker, NULL, NULL, &name);
513 ok(hr == S_OK, "Got hr %#x.\n", hr);
514 trace("Testing device %s.\n", wine_dbgstr_w(name));
515 CoTaskMemFree(name);
517 if (FAILED(hr = IMoniker_BindToObject(moniker, NULL, NULL, &IID_IBaseFilter, (void **)&filter)))
519 skip("Failed to open device %s, hr %#x.\n", debugstr_w(name), hr);
520 IMoniker_Release(moniker);
521 continue;
524 test_filter_interfaces(filter);
525 test_pins(filter);
526 test_misc_flags(filter);
528 ref = IBaseFilter_Release(filter);
529 ok(!ref, "Got outstanding refcount %d.\n", ref);
531 test_connection(moniker);
533 IMoniker_Release(moniker);
536 ICreateDevEnum_Release(dev_enum);
537 IEnumMoniker_Release(class_enum);
538 CoUninitialize();