quartz/vmr9: Perform image stretching in Present() instead of StretchRect().
[wine.git] / dlls / quartz / tests / vmr9.c
blobfc2794c5cb782ca31054242e36f6a749d93698b5
1 /*
2 * Video Mixing Renderer 9 unit tests
4 * Copyright 2019 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 #include <stdint.h>
22 #define COBJMACROS
23 #include "ocidl.h"
24 #include "olectl.h"
25 #include "initguid.h"
26 #include "dshow.h"
27 #include "qedit.h"
28 #include "d3d9.h"
29 #include "vmr9.h"
30 #include "wmcodecdsp.h"
31 #include "wine/heap.h"
32 #include "wine/strmbase.h"
33 #include "wine/test.h"
35 static IBaseFilter *create_vmr9(DWORD mode)
37 IBaseFilter *filter = NULL;
38 IVMRFilterConfig9 *config;
39 HRESULT hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
40 &IID_IBaseFilter, (void **)&filter);
41 ok(hr == S_OK, "Got hr %#x.\n", hr);
42 if (mode)
44 hr = IBaseFilter_QueryInterface(filter, &IID_IVMRFilterConfig9, (void **)&config);
45 ok(hr == S_OK, "Got hr %#x.\n", hr);
46 hr = IVMRFilterConfig9_SetRenderingMode(config, mode);
47 ok(hr == S_OK || broken(hr == E_FAIL), "Got hr %#x.\n", hr);
48 IVMRFilterConfig9_Release(config);
50 return filter;
53 static HRESULT set_mixing_mode(IBaseFilter *filter, DWORD count)
55 IVMRFilterConfig9 *config;
56 HRESULT hr;
58 hr = IBaseFilter_QueryInterface(filter, &IID_IVMRFilterConfig9, (void **)&config);
59 ok(hr == S_OK, "Got hr %#x.\n", hr);
61 hr = IVMRFilterConfig9_SetNumberOfStreams(config, count);
62 todo_wine_if (count != 1) ok(hr == S_OK, "Got hr %#x.\n", hr);
64 IVMRFilterConfig9_Release(config);
65 return hr;
68 static inline BOOL compare_media_types(const AM_MEDIA_TYPE *a, const AM_MEDIA_TYPE *b)
70 return !memcmp(a, b, offsetof(AM_MEDIA_TYPE, pbFormat))
71 && !memcmp(a->pbFormat, b->pbFormat, a->cbFormat);
74 static BOOL compare_double(double f, double g, unsigned int ulps)
76 int64_t x = *(int64_t *)&f;
77 int64_t y = *(int64_t *)&g;
79 if (x < 0)
80 x = INT64_MIN - x;
81 if (y < 0)
82 y = INT64_MIN - y;
84 if (abs(x - y) > ulps)
85 return FALSE;
87 return TRUE;
90 static IFilterGraph2 *create_graph(void)
92 IFilterGraph2 *ret;
93 HRESULT hr;
94 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (void **)&ret);
95 ok(hr == S_OK, "Failed to create FilterGraph: %#x\n", hr);
96 return ret;
99 static ULONG get_refcount(void *iface)
101 IUnknown *unknown = iface;
102 IUnknown_AddRef(unknown);
103 return IUnknown_Release(unknown);
106 static void test_filter_config(void)
108 IVMRFilterConfig9 *config;
109 DWORD count, mode;
110 HRESULT hr;
111 ULONG ref;
113 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
114 &IID_IVMRFilterConfig9, (void **)&config);
115 ok(hr == S_OK, "Got hr %#x.\n", hr);
117 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
118 ok(hr == S_OK, "Got hr %#x.\n", hr);
119 ok(mode == VMRMode_Windowed, "Got mode %#x.\n", mode);
121 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowed);
122 ok(hr == S_OK || broken(hr == E_FAIL), "Got hr %#x.\n", hr);
124 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
125 ok(hr == S_OK, "Got hr %#x.\n", hr);
126 ok(mode == VMR9Mode_Windowed, "Got mode %#x.\n", mode);
128 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowed);
129 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
131 ref = IVMRFilterConfig9_Release(config);
132 ok(!ref, "Got outstanding refcount %d.\n", ref);
134 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
135 &IID_IVMRFilterConfig9, (void **)&config);
136 ok(hr == S_OK, "Got hr %#x.\n", hr);
138 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowless);
139 ok(hr == S_OK || broken(hr == E_FAIL), "Got hr %#x.\n", hr);
141 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
142 ok(hr == S_OK, "Got hr %#x.\n", hr);
143 ok(mode == VMR9Mode_Windowless, "Got mode %#x.\n", mode);
145 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowed);
146 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
148 ref = IVMRFilterConfig9_Release(config);
149 ok(!ref, "Got outstanding refcount %d.\n", ref);
151 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
152 &IID_IVMRFilterConfig9, (void **)&config);
153 ok(hr == S_OK, "Got hr %#x.\n", hr);
155 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Renderless);
156 ok(hr == S_OK, "Got hr %#x.\n", hr);
158 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
159 ok(hr == S_OK, "Got hr %#x.\n", hr);
160 ok(mode == VMR9Mode_Renderless, "Got mode %#x.\n", mode);
162 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowless);
163 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
165 ref = IVMRFilterConfig9_Release(config);
166 ok(!ref, "Got outstanding refcount %d.\n", ref);
168 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
169 &IID_IVMRFilterConfig9, (void **)&config);
170 ok(hr == S_OK, "Got hr %#x.\n", hr);
172 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &count);
173 todo_wine ok(hr == VFW_E_VMR_NOT_IN_MIXER_MODE, "Got hr %#x.\n", hr);
175 hr = IVMRFilterConfig9_SetNumberOfStreams(config, 3);
176 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
178 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &count);
179 todo_wine {
180 ok(hr == S_OK, "Got hr %#x.\n", hr);
181 ok(count == 3, "Got count %u.\n", count);
184 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
185 ok(hr == S_OK, "Got hr %#x.\n", hr);
186 ok(mode == VMR9Mode_Windowed, "Got mode %#x.\n", mode);
188 /* Despite MSDN, you can still change the rendering mode after setting the
189 * stream count. */
190 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowless);
191 ok(hr == S_OK || broken(hr == E_FAIL), "Got hr %#x.\n", hr);
193 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
194 ok(hr == S_OK, "Got hr %#x.\n", hr);
195 ok(mode == VMR9Mode_Windowless, "Got mode %#x.\n", mode);
197 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &count);
198 todo_wine {
199 ok(hr == S_OK, "Got hr %#x.\n", hr);
200 ok(count == 3, "Got count %u.\n", count);
203 ref = IVMRFilterConfig9_Release(config);
204 ok(!ref, "Got outstanding refcount %d.\n", ref);
207 #define check_interface_broken(a, b, c) check_interface_(__LINE__, a, b, c, TRUE)
208 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c, FALSE)
209 static HRESULT check_interface_(unsigned int line, void *iface, REFIID riid, BOOL supported, BOOL is_broken)
211 HRESULT hr, expected_hr, broken_hr;
212 IUnknown *unknown = iface, *out;
214 if (supported)
216 expected_hr = S_OK;
217 broken_hr = E_NOINTERFACE;
219 else
221 expected_hr = E_NOINTERFACE;
222 broken_hr = S_OK;
225 hr = IUnknown_QueryInterface(unknown, riid, (void **)&out);
226 ok_(__FILE__, line)(hr == expected_hr || broken(is_broken && hr == broken_hr),
227 "Got hr %#x, expected %#x.\n", hr, expected_hr);
228 if (SUCCEEDED(hr))
229 IUnknown_Release(out);
230 return hr;
233 static void test_common_interfaces(IBaseFilter *filter)
235 IPin *pin;
237 check_interface(filter, &IID_IAMCertifiedOutputProtection, TRUE);
238 check_interface(filter, &IID_IAMFilterMiscFlags, TRUE);
239 check_interface(filter, &IID_IBaseFilter, TRUE);
240 todo_wine check_interface(filter, &IID_IKsPropertySet, TRUE);
241 check_interface(filter, &IID_IMediaFilter, TRUE);
242 check_interface(filter, &IID_IMediaPosition, TRUE);
243 check_interface(filter, &IID_IMediaSeeking, TRUE);
244 check_interface(filter, &IID_IPersist, TRUE);
245 check_interface(filter, &IID_IQualityControl, TRUE);
246 todo_wine check_interface(filter, &IID_IQualProp, TRUE);
247 check_interface(filter, &IID_IUnknown, TRUE);
248 todo_wine check_interface(filter, &IID_IVMRAspectRatioControl9, TRUE);
249 todo_wine check_interface(filter, &IID_IVMRDeinterlaceControl9, TRUE);
250 check_interface(filter, &IID_IVMRFilterConfig9, TRUE);
251 check_interface(filter, &IID_IVMRMixerBitmap9, TRUE);
253 check_interface(filter, &IID_IBasicAudio, FALSE);
254 check_interface(filter, &IID_IDirectDrawVideo, FALSE);
255 check_interface(filter, &IID_IPersistPropertyBag, FALSE);
256 check_interface(filter, &IID_IPin, FALSE);
257 check_interface(filter, &IID_IReferenceClock, FALSE);
258 check_interface(filter, &IID_IVMRAspectRatioControl, FALSE);
259 check_interface(filter, &IID_IVMRDeinterlaceControl, FALSE);
260 todo_wine check_interface(filter, &IID_IVMRFilterConfig, FALSE);
261 check_interface(filter, &IID_IVMRMixerBitmap, FALSE);
262 check_interface(filter, &IID_IVMRMixerControl, FALSE);
263 todo_wine check_interface(filter, &IID_IVMRMonitorConfig, FALSE);
264 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify, FALSE);
265 check_interface(filter, &IID_IVMRWindowlessControl, FALSE);
267 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
269 check_interface(pin, &IID_IMemInputPin, TRUE);
270 check_interface(pin, &IID_IOverlay, TRUE);
271 check_interface(pin, &IID_IPin, TRUE);
272 todo_wine check_interface(pin, &IID_IQualityControl, TRUE);
273 check_interface(pin, &IID_IUnknown, TRUE);
275 check_interface(pin, &IID_IKsPropertySet, FALSE);
276 check_interface(pin, &IID_IMediaPosition, FALSE);
277 check_interface(pin, &IID_IMediaSeeking, FALSE);
279 IPin_Release(pin);
282 static void test_interfaces(void)
284 IBaseFilter *filter = create_vmr9(0);
285 ULONG ref;
287 test_common_interfaces(filter);
289 check_interface(filter, &IID_IBasicVideo, TRUE);
290 todo_wine check_interface(filter, &IID_IBasicVideo2, TRUE);
291 check_interface(filter, &IID_IVideoWindow, TRUE);
292 /* IVMRMonitorConfig9 may not be available if the d3d9 device has
293 * insufficient support. */
294 check_interface_broken(filter, &IID_IVMRMonitorConfig9, TRUE);
296 check_interface(filter, &IID_IVMRMixerControl9, FALSE);
297 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify9, FALSE);
298 check_interface(filter, &IID_IVMRWindowlessControl9, FALSE);
300 ref = IBaseFilter_Release(filter);
301 ok(!ref, "Got outstanding refcount %d.\n", ref);
303 filter = create_vmr9(VMR9Mode_Windowless);
304 test_common_interfaces(filter);
306 /* IVMRMonitorConfig9 may not be available if the d3d9 device has
307 * insufficient support. */
308 check_interface_broken(filter, &IID_IVMRMonitorConfig9, TRUE);
309 check_interface(filter, &IID_IVMRWindowlessControl9, TRUE);
311 todo_wine check_interface(filter, &IID_IBasicVideo, FALSE);
312 check_interface(filter, &IID_IBasicVideo2, FALSE);
313 todo_wine check_interface(filter, &IID_IVideoWindow, FALSE);
314 check_interface(filter, &IID_IVMRMixerControl9, FALSE);
315 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify9, FALSE);
317 ref = IBaseFilter_Release(filter);
318 ok(!ref, "Got outstanding refcount %d.\n", ref);
320 filter = create_vmr9(VMR9Mode_Renderless);
321 test_common_interfaces(filter);
323 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify9, TRUE);
325 todo_wine check_interface(filter, &IID_IBasicVideo, FALSE);
326 check_interface(filter, &IID_IBasicVideo2, FALSE);
327 todo_wine check_interface(filter, &IID_IVideoWindow, FALSE);
328 todo_wine check_interface(filter, &IID_IVMRMonitorConfig9, FALSE);
329 check_interface(filter, &IID_IVMRWindowlessControl9, FALSE);
331 ref = IBaseFilter_Release(filter);
332 ok(!ref, "Got outstanding refcount %d.\n", ref);
334 filter = create_vmr9(VMR9Mode_Windowed);
335 if (SUCCEEDED(set_mixing_mode(filter, 1)))
337 test_common_interfaces(filter);
339 check_interface(filter, &IID_IBasicVideo, TRUE);
340 todo_wine check_interface(filter, &IID_IBasicVideo2, TRUE);
341 check_interface(filter, &IID_IVideoWindow, TRUE);
342 todo_wine check_interface(filter, &IID_IVMRMixerControl9, TRUE);
343 /* IVMRMonitorConfig9 may not be available if the d3d9 device has
344 * insufficient support. */
345 check_interface_broken(filter, &IID_IVMRMonitorConfig9, TRUE);
347 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify9, FALSE);
348 check_interface(filter, &IID_IVMRWindowlessControl9, FALSE);
350 ref = IBaseFilter_Release(filter);
351 ok(!ref, "Got outstanding refcount %d.\n", ref);
355 static const GUID test_iid = {0x33333333};
356 static LONG outer_ref = 1;
358 static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID iid, void **out)
360 if (IsEqualGUID(iid, &IID_IUnknown)
361 || IsEqualGUID(iid, &IID_IBaseFilter)
362 || IsEqualGUID(iid, &test_iid))
364 *out = (IUnknown *)0xdeadbeef;
365 return S_OK;
367 ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid));
368 return E_NOINTERFACE;
371 static ULONG WINAPI outer_AddRef(IUnknown *iface)
373 return InterlockedIncrement(&outer_ref);
376 static ULONG WINAPI outer_Release(IUnknown *iface)
378 return InterlockedDecrement(&outer_ref);
381 static const IUnknownVtbl outer_vtbl =
383 outer_QueryInterface,
384 outer_AddRef,
385 outer_Release,
388 static IUnknown test_outer = {&outer_vtbl};
390 static void test_aggregation(void)
392 IBaseFilter *filter, *filter2;
393 IUnknown *unk, *unk2;
394 HRESULT hr;
395 ULONG ref;
397 filter = (IBaseFilter *)0xdeadbeef;
398 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, &test_outer, CLSCTX_INPROC_SERVER,
399 &IID_IBaseFilter, (void **)&filter);
400 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
401 ok(!filter, "Got interface %p.\n", filter);
403 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, &test_outer, CLSCTX_INPROC_SERVER,
404 &IID_IUnknown, (void **)&unk);
405 ok(hr == S_OK, "Got hr %#x.\n", hr);
406 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
407 ok(unk != &test_outer, "Returned IUnknown should not be outer IUnknown.\n");
408 ref = get_refcount(unk);
409 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
411 ref = IUnknown_AddRef(unk);
412 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
413 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
415 ref = IUnknown_Release(unk);
416 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
417 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
419 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, (void **)&unk2);
420 ok(hr == S_OK, "Got hr %#x.\n", hr);
421 ok(unk2 == unk, "Got unexpected IUnknown %p.\n", unk2);
422 IUnknown_Release(unk2);
424 hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void **)&filter);
425 ok(hr == S_OK, "Got hr %#x.\n", hr);
427 hr = IBaseFilter_QueryInterface(filter, &IID_IUnknown, (void **)&unk2);
428 ok(hr == S_OK, "Got hr %#x.\n", hr);
429 ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
431 hr = IBaseFilter_QueryInterface(filter, &IID_IBaseFilter, (void **)&filter2);
432 ok(hr == S_OK, "Got hr %#x.\n", hr);
433 ok(filter2 == (IBaseFilter *)0xdeadbeef, "Got unexpected IBaseFilter %p.\n", filter2);
435 hr = IUnknown_QueryInterface(unk, &test_iid, (void **)&unk2);
436 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
437 ok(!unk2, "Got unexpected IUnknown %p.\n", unk2);
439 hr = IBaseFilter_QueryInterface(filter, &test_iid, (void **)&unk2);
440 ok(hr == S_OK, "Got hr %#x.\n", hr);
441 ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
443 IBaseFilter_Release(filter);
444 ref = IUnknown_Release(unk);
445 ok(!ref, "Got unexpected refcount %d.\n", ref);
446 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
449 static void test_enum_pins(void)
451 IBaseFilter *filter = create_vmr9(0);
452 IEnumPins *enum1, *enum2;
453 ULONG count, ref;
454 IPin *pins[3];
455 HRESULT hr;
457 ref = get_refcount(filter);
458 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
460 hr = IBaseFilter_EnumPins(filter, NULL);
461 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
463 hr = IBaseFilter_EnumPins(filter, &enum1);
464 ok(hr == S_OK, "Got hr %#x.\n", hr);
465 ref = get_refcount(filter);
466 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
467 ref = get_refcount(enum1);
468 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
470 hr = IEnumPins_Next(enum1, 1, NULL, NULL);
471 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
473 hr = IEnumPins_Next(enum1, 1, pins, NULL);
474 ok(hr == S_OK, "Got hr %#x.\n", hr);
475 ref = get_refcount(filter);
476 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
477 ref = get_refcount(pins[0]);
478 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
479 ref = get_refcount(enum1);
480 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
481 IPin_Release(pins[0]);
482 ref = get_refcount(filter);
483 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
485 hr = IEnumPins_Next(enum1, 1, pins, NULL);
486 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
488 hr = IEnumPins_Reset(enum1);
489 ok(hr == S_OK, "Got hr %#x.\n", hr);
491 hr = IEnumPins_Next(enum1, 1, pins, &count);
492 ok(hr == S_OK, "Got hr %#x.\n", hr);
493 ok(count == 1, "Got count %u.\n", count);
494 IPin_Release(pins[0]);
496 hr = IEnumPins_Next(enum1, 1, pins, &count);
497 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
498 ok(!count, "Got count %u.\n", count);
500 hr = IEnumPins_Reset(enum1);
501 ok(hr == S_OK, "Got hr %#x.\n", hr);
503 hr = IEnumPins_Next(enum1, 2, pins, NULL);
504 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
506 hr = IEnumPins_Next(enum1, 2, pins, &count);
507 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
508 ok(count == 1, "Got count %u.\n", count);
509 IPin_Release(pins[0]);
511 hr = IEnumPins_Reset(enum1);
512 ok(hr == S_OK, "Got hr %#x.\n", hr);
514 hr = IEnumPins_Clone(enum1, &enum2);
515 ok(hr == S_OK, "Got hr %#x.\n", hr);
517 hr = IEnumPins_Skip(enum1, 2);
518 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
520 hr = IEnumPins_Skip(enum1, 1);
521 ok(hr == S_OK, "Got hr %#x.\n", hr);
523 hr = IEnumPins_Skip(enum1, 1);
524 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
526 hr = IEnumPins_Next(enum1, 1, pins, NULL);
527 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
529 hr = IEnumPins_Next(enum2, 1, pins, NULL);
530 ok(hr == S_OK, "Got hr %#x.\n", hr);
531 IPin_Release(pins[0]);
533 IEnumPins_Release(enum2);
535 if (SUCCEEDED(set_mixing_mode(filter, 2)))
537 hr = IEnumPins_Next(enum1, 1, pins, NULL);
538 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
540 hr = IEnumPins_Reset(enum1);
541 ok(hr == S_OK, "Got hr %#x.\n", hr);
543 hr = IEnumPins_Next(enum1, 1, pins, NULL);
544 ok(hr == S_OK, "Got hr %#x.\n", hr);
545 IPin_Release(pins[0]);
547 hr = IEnumPins_Next(enum1, 1, pins, NULL);
548 ok(hr == S_OK, "Got hr %#x.\n", hr);
549 IPin_Release(pins[0]);
551 hr = IEnumPins_Next(enum1, 1, pins, NULL);
552 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
554 hr = IEnumPins_Reset(enum1);
555 ok(hr == S_OK, "Got hr %#x.\n", hr);
557 hr = IEnumPins_Next(enum1, 2, pins, &count);
558 ok(hr == S_OK, "Got hr %#x.\n", hr);
559 ok(count == 2, "Got count %u.\n", count);
560 IPin_Release(pins[0]);
561 IPin_Release(pins[1]);
563 hr = IEnumPins_Reset(enum1);
564 ok(hr == S_OK, "Got hr %#x.\n", hr);
566 hr = IEnumPins_Next(enum1, 3, pins, &count);
567 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
568 ok(count == 2, "Got count %u.\n", count);
569 IPin_Release(pins[0]);
570 IPin_Release(pins[1]);
573 IEnumPins_Release(enum1);
574 ref = IBaseFilter_Release(filter);
575 ok(!ref, "Got outstanding refcount %d.\n", ref);
578 static void test_find_pin(void)
580 IBaseFilter *filter = create_vmr9(0);
581 IEnumPins *enum_pins;
582 IPin *pin, *pin2;
583 HRESULT hr;
584 ULONG ref;
586 IBaseFilter_EnumPins(filter, &enum_pins);
588 hr = IBaseFilter_FindPin(filter, L"input pin", &pin);
589 ok(hr == VFW_E_NOT_FOUND, "Got hr %#x.\n", hr);
591 hr = IBaseFilter_FindPin(filter, L"In", &pin);
592 ok(hr == VFW_E_NOT_FOUND, "Got hr %#x.\n", hr);
594 hr = IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
595 ok(hr == S_OK, "Got hr %#x.\n", hr);
596 hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL);
597 ok(hr == S_OK, "Got hr %#x.\n", hr);
598 ok(pin == pin2, "Pins did not match.\n");
599 IPin_Release(pin);
600 IPin_Release(pin2);
602 hr = IBaseFilter_FindPin(filter, L"VMR Input1", &pin);
603 ok(hr == VFW_E_NOT_FOUND, "Got hr %#x.\n", hr);
605 if (SUCCEEDED(set_mixing_mode(filter, 2)))
607 IEnumPins_Reset(enum_pins);
609 hr = IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
610 ok(hr == S_OK, "Got hr %#x.\n", hr);
611 hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL);
612 ok(hr == S_OK, "Got hr %#x.\n", hr);
613 ok(pin == pin2, "Pins did not match.\n");
614 IPin_Release(pin);
615 IPin_Release(pin2);
617 hr = IBaseFilter_FindPin(filter, L"VMR Input1", &pin);
618 ok(hr == S_OK, "Got hr %#x.\n", hr);
619 hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL);
620 ok(hr == S_OK, "Got hr %#x.\n", hr);
621 ok(pin == pin2, "Pins did not match.\n");
622 IPin_Release(pin);
623 IPin_Release(pin2);
625 hr = IBaseFilter_FindPin(filter, L"VMR Input2", &pin);
626 ok(hr == VFW_E_NOT_FOUND, "Got hr %#x.\n", hr);
629 IEnumPins_Release(enum_pins);
630 ref = IBaseFilter_Release(filter);
631 ok(!ref, "Got outstanding refcount %d.\n", ref);
634 static void test_pin_info(void)
636 IBaseFilter *filter = create_vmr9(0);
637 PIN_DIRECTION dir;
638 ULONG count, ref;
639 PIN_INFO info;
640 HRESULT hr;
641 WCHAR *id;
642 IPin *pin;
644 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
645 hr = IPin_QueryPinInfo(pin, &info);
646 ok(info.pFilter == filter, "Expected filter %p, got %p.\n", filter, info.pFilter);
647 ok(info.dir == PINDIR_INPUT, "Got direction %d.\n", info.dir);
648 ok(!wcscmp(info.achName, L"VMR Input0"), "Got name %s.\n", wine_dbgstr_w(info.achName));
649 IBaseFilter_Release(info.pFilter);
651 hr = IPin_QueryDirection(pin, &dir);
652 ok(hr == S_OK, "Got hr %#x.\n", hr);
653 ok(dir == PINDIR_INPUT, "Got direction %d.\n", dir);
655 hr = IPin_QueryId(pin, &id);
656 ok(hr == S_OK, "Got hr %#x.\n", hr);
657 ok(!wcscmp(id, L"VMR Input0"), "Got id %s.\n", wine_dbgstr_w(id));
658 CoTaskMemFree(id);
660 hr = IPin_QueryInternalConnections(pin, NULL, &count);
661 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
663 IPin_Release(pin);
665 if (SUCCEEDED(set_mixing_mode(filter, 2)))
667 IBaseFilter_FindPin(filter, L"VMR Input1", &pin);
668 hr = IPin_QueryPinInfo(pin, &info);
669 ok(info.pFilter == filter, "Expected filter %p, got %p.\n", filter, info.pFilter);
670 ok(info.dir == PINDIR_INPUT, "Got direction %d.\n", info.dir);
671 ok(!wcscmp(info.achName, L"VMR Input1"), "Got name %s.\n", wine_dbgstr_w(info.achName));
672 IBaseFilter_Release(info.pFilter);
674 hr = IPin_QueryDirection(pin, &dir);
675 ok(hr == S_OK, "Got hr %#x.\n", hr);
676 ok(dir == PINDIR_INPUT, "Got direction %d.\n", dir);
678 hr = IPin_QueryId(pin, &id);
679 ok(hr == S_OK, "Got hr %#x.\n", hr);
680 ok(!wcscmp(id, L"VMR Input1"), "Got id %s.\n", wine_dbgstr_w(id));
681 CoTaskMemFree(id);
683 hr = IPin_QueryInternalConnections(pin, NULL, &count);
684 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
686 IPin_Release(pin);
689 ref = IBaseFilter_Release(filter);
690 ok(!ref, "Got outstanding refcount %d.\n", ref);
693 static void test_media_types(void)
695 IBaseFilter *filter = create_vmr9(0);
696 AM_MEDIA_TYPE *mt, req_mt = {{0}};
697 VIDEOINFOHEADER vih =
699 {0}, {0}, 0, 0, 0,
700 {sizeof(BITMAPINFOHEADER), 32, 24, 1, 0, BI_RGB}
702 IEnumMediaTypes *enummt;
703 unsigned int i;
704 HRESULT hr;
705 ULONG ref;
706 IPin *pin;
708 static const GUID *subtype_tests[] =
710 &MEDIASUBTYPE_RGB565,
711 &MEDIASUBTYPE_RGB24,
712 &MEDIASUBTYPE_RGB32,
715 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
717 hr = IPin_EnumMediaTypes(pin, &enummt);
718 ok(hr == S_OK, "Got hr %#x.\n", hr);
720 hr = IEnumMediaTypes_Next(enummt, 1, &mt, NULL);
721 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
723 IEnumMediaTypes_Release(enummt);
725 req_mt.majortype = MEDIATYPE_Video;
726 req_mt.formattype = FORMAT_VideoInfo;
727 req_mt.cbFormat = sizeof(VIDEOINFOHEADER);
728 req_mt.pbFormat = (BYTE *)&vih;
730 for (i = 0; i < ARRAY_SIZE(subtype_tests); ++i)
732 req_mt.subtype = *subtype_tests[i];
733 hr = IPin_QueryAccept(pin, &req_mt);
734 ok(hr == S_OK, "Got hr %#x for subtype %s.\n", hr, wine_dbgstr_guid(subtype_tests[i]));
737 req_mt.subtype = MEDIASUBTYPE_RGB8;
738 hr = IPin_QueryAccept(pin, &req_mt);
739 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
740 req_mt.subtype = MEDIASUBTYPE_NULL;
741 hr = IPin_QueryAccept(pin, &req_mt);
742 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
743 req_mt.subtype = MEDIASUBTYPE_RGB24;
745 req_mt.majortype = MEDIATYPE_NULL;
746 hr = IPin_QueryAccept(pin, &req_mt);
747 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
748 req_mt.majortype = MEDIATYPE_Video;
750 req_mt.formattype = FORMAT_None;
751 hr = IPin_QueryAccept(pin, &req_mt);
752 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
754 req_mt.formattype = GUID_NULL;
755 hr = IPin_QueryAccept(pin, &req_mt);
756 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
758 IPin_Release(pin);
759 ref = IBaseFilter_Release(filter);
760 ok(!ref, "Got outstanding refcount %d.\n", ref);
763 static void test_enum_media_types(void)
765 IBaseFilter *filter = create_vmr9(0);
766 IEnumMediaTypes *enum1, *enum2;
767 AM_MEDIA_TYPE *mts[2];
768 ULONG ref, count;
769 HRESULT hr;
770 IPin *pin;
772 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
774 hr = IPin_EnumMediaTypes(pin, &enum1);
775 ok(hr == S_OK, "Got hr %#x.\n", hr);
777 hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL);
778 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
780 hr = IEnumMediaTypes_Next(enum1, 1, mts, &count);
781 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
782 ok(!count, "Got count %u.\n", count);
784 hr = IEnumMediaTypes_Reset(enum1);
785 ok(hr == S_OK, "Got hr %#x.\n", hr);
787 hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL);
788 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
790 hr = IEnumMediaTypes_Clone(enum1, &enum2);
791 ok(hr == S_OK, "Got hr %#x.\n", hr);
793 hr = IEnumMediaTypes_Skip(enum1, 1);
794 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
796 hr = IEnumMediaTypes_Next(enum2, 1, mts, NULL);
797 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
799 IEnumMediaTypes_Release(enum1);
800 IEnumMediaTypes_Release(enum2);
801 IPin_Release(pin);
803 ref = IBaseFilter_Release(filter);
804 ok(!ref, "Got outstanding refcount %d.\n", ref);
807 static void test_unconnected_filter_state(void)
809 IBaseFilter *filter = create_vmr9(0);
810 FILTER_STATE state;
811 HRESULT hr;
812 ULONG ref;
814 hr = IBaseFilter_GetState(filter, 0, &state);
815 ok(hr == S_OK, "Got hr %#x.\n", hr);
816 ok(state == State_Stopped, "Got state %u.\n", state);
818 hr = IBaseFilter_Pause(filter);
819 ok(hr == S_OK, "Got hr %#x.\n", hr);
821 hr = IBaseFilter_GetState(filter, 0, &state);
822 ok(hr == S_OK, "Got hr %#x.\n", hr);
823 ok(state == State_Paused, "Got state %u.\n", state);
825 hr = IBaseFilter_Run(filter, 0);
826 ok(hr == S_OK, "Got hr %#x.\n", hr);
828 hr = IBaseFilter_GetState(filter, 0, &state);
829 ok(hr == S_OK, "Got hr %#x.\n", hr);
830 ok(state == State_Running, "Got state %u.\n", state);
832 hr = IBaseFilter_Pause(filter);
833 ok(hr == S_OK, "Got hr %#x.\n", hr);
835 hr = IBaseFilter_GetState(filter, 0, &state);
836 ok(hr == S_OK, "Got hr %#x.\n", hr);
837 ok(state == State_Paused, "Got state %u.\n", state);
839 hr = IBaseFilter_Stop(filter);
840 ok(hr == S_OK, "Got hr %#x.\n", hr);
842 hr = IBaseFilter_GetState(filter, 0, &state);
843 ok(hr == S_OK, "Got hr %#x.\n", hr);
844 ok(state == State_Stopped, "Got state %u.\n", state);
846 hr = IBaseFilter_Run(filter, 0);
847 ok(hr == S_OK, "Got hr %#x.\n", hr);
849 hr = IBaseFilter_GetState(filter, 0, &state);
850 ok(hr == S_OK, "Got hr %#x.\n", hr);
851 ok(state == State_Running, "Got state %u.\n", state);
853 hr = IBaseFilter_Stop(filter);
854 ok(hr == S_OK, "Got hr %#x.\n", hr);
856 hr = IBaseFilter_GetState(filter, 0, &state);
857 ok(hr == S_OK, "Got hr %#x.\n", hr);
858 ok(state == State_Stopped, "Got state %u.\n", state);
860 ref = IBaseFilter_Release(filter);
861 ok(!ref, "Got outstanding refcount %d.\n", ref);
864 struct testfilter
866 struct strmbase_filter filter;
867 struct strmbase_source source;
870 static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface)
872 return CONTAINING_RECORD(iface, struct testfilter, filter);
875 static struct strmbase_pin *testfilter_get_pin(struct strmbase_filter *iface, unsigned int index)
877 struct testfilter *filter = impl_from_strmbase_filter(iface);
878 if (!index)
879 return &filter->source.pin;
880 return NULL;
883 static void testfilter_destroy(struct strmbase_filter *iface)
885 struct testfilter *filter = impl_from_strmbase_filter(iface);
886 strmbase_source_cleanup(&filter->source);
887 strmbase_filter_cleanup(&filter->filter);
890 static const struct strmbase_filter_ops testfilter_ops =
892 .filter_get_pin = testfilter_get_pin,
893 .filter_destroy = testfilter_destroy,
896 static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface,
897 IMemInputPin *peer, IMemAllocator **allocator)
899 return S_OK;
902 static const struct strmbase_source_ops testsource_ops =
904 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
905 .pfnDecideAllocator = testsource_DecideAllocator,
908 static void testfilter_init(struct testfilter *filter)
910 static const GUID clsid = {0xabacab};
911 strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops);
912 strmbase_source_init(&filter->source, &filter->filter, L"", &testsource_ops);
915 static void test_allocator(IMemInputPin *input)
917 IMemAllocator *req_allocator, *ret_allocator;
918 ALLOCATOR_PROPERTIES props, req_props;
919 HRESULT hr;
921 hr = IMemInputPin_GetAllocatorRequirements(input, &props);
922 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
924 hr = IMemInputPin_GetAllocator(input, &ret_allocator);
925 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
927 if (hr == S_OK)
929 hr = IMemAllocator_GetProperties(ret_allocator, &props);
930 ok(hr == S_OK, "Got hr %#x.\n", hr);
931 ok(!props.cBuffers, "Got %d buffers.\n", props.cBuffers);
932 ok(!props.cbBuffer, "Got size %d.\n", props.cbBuffer);
933 ok(!props.cbAlign, "Got alignment %d.\n", props.cbAlign);
934 ok(!props.cbPrefix, "Got prefix %d.\n", props.cbPrefix);
936 hr = IMemInputPin_NotifyAllocator(input, ret_allocator, TRUE);
937 ok(hr == S_OK, "Got hr %#x.\n", hr);
939 req_props.cBuffers = 1;
940 req_props.cbBuffer = 32 * 16 * 4;
941 req_props.cbAlign = 1;
942 req_props.cbPrefix = 0;
943 hr = IMemAllocator_SetProperties(ret_allocator, &req_props, &props);
944 ok(hr == S_OK, "Got hr %#x.\n", hr);
945 ok(props.cBuffers == 1, "Got %d buffers.\n", props.cBuffers);
946 ok(props.cbBuffer == 32 * 16 * 4, "Got size %d.\n", props.cbBuffer);
947 ok(props.cbAlign == 1, "Got alignment %d.\n", props.cbAlign);
948 ok(!props.cbPrefix, "Got prefix %d.\n", props.cbPrefix);
950 IMemAllocator_Release(ret_allocator);
953 hr = IMemInputPin_NotifyAllocator(input, NULL, TRUE);
954 todo_wine ok(hr == E_FAIL, "Got hr %#x.\n", hr);
956 CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
957 &IID_IMemAllocator, (void **)&req_allocator);
959 hr = IMemInputPin_NotifyAllocator(input, req_allocator, TRUE);
960 todo_wine ok(hr == E_FAIL, "Got hr %#x.\n", hr);
962 IMemAllocator_Release(req_allocator);
965 struct frame_thread_params
967 IMemInputPin *sink;
968 IMediaSample *sample;
971 static DWORD WINAPI frame_thread(void *arg)
973 struct frame_thread_params *params = arg;
974 HRESULT hr;
976 if (winetest_debug > 1) trace("%04x: Sending frame.\n", GetCurrentThreadId());
977 hr = IMemInputPin_Receive(params->sink, params->sample);
978 if (winetest_debug > 1) trace("%04x: Returned %#x.\n", GetCurrentThreadId(), hr);
979 IMediaSample_Release(params->sample);
980 heap_free(params);
981 return hr;
984 static HANDLE send_frame_time(IMemInputPin *sink, REFERENCE_TIME start_time, DWORD color)
986 struct frame_thread_params *params = heap_alloc(sizeof(*params));
987 IMemAllocator *allocator;
988 REFERENCE_TIME end_time;
989 IMediaSample *sample;
990 HANDLE thread;
991 LONG size, i;
992 HRESULT hr;
993 BYTE *data;
995 hr = IMemInputPin_GetAllocator(sink, &allocator);
996 ok(hr == S_OK, "Got hr %#x.\n", hr);
998 hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
999 ok(hr == S_OK, "Got hr %#x.\n", hr);
1001 size = IMediaSample_GetSize(sample);
1002 hr = IMediaSample_GetPointer(sample, &data);
1003 ok(hr == S_OK, "Got hr %#x.\n", hr);
1004 for (i = 0; i < size / sizeof(DWORD); ++i)
1005 ((DWORD *)data)[i] = color;
1007 hr = IMediaSample_SetActualDataLength(sample, size);
1008 ok(hr == S_OK, "Got hr %#x.\n", hr);
1010 start_time *= 10000000;
1011 end_time = start_time + 10000000;
1012 hr = IMediaSample_SetTime(sample, &start_time, &end_time);
1013 ok(hr == S_OK, "Got hr %#x.\n", hr);
1015 params->sink = sink;
1016 params->sample = sample;
1017 thread = CreateThread(NULL, 0, frame_thread, params, 0, NULL);
1019 IMemAllocator_Release(allocator);
1020 return thread;
1023 static HANDLE send_frame(IMemInputPin *sink)
1025 return send_frame_time(sink, 0, 0x007f007f);
1028 static HRESULT join_thread_(int line, HANDLE thread)
1030 DWORD ret;
1031 ok_(__FILE__, line)(!WaitForSingleObject(thread, 1000), "Wait failed.\n");
1032 GetExitCodeThread(thread, &ret);
1033 CloseHandle(thread);
1034 return ret;
1036 #define join_thread(a) join_thread_(__LINE__, a)
1038 static void commit_allocator(IMemInputPin *input)
1040 IMemAllocator *allocator;
1041 HRESULT hr;
1043 hr = IMemInputPin_GetAllocator(input, &allocator);
1044 ok(hr == S_OK, "Got hr %#x.\n", hr);
1045 hr = IMemAllocator_Commit(allocator);
1046 ok(hr == S_OK, "Got hr %#x.\n", hr);
1047 IMemAllocator_Release(allocator);
1050 static void test_filter_state(IMemInputPin *input, IMediaControl *control)
1052 IMemAllocator *allocator;
1053 IMediaSample *sample;
1054 OAFilterState state;
1055 HANDLE thread;
1056 HRESULT hr;
1058 thread = send_frame(input);
1059 hr = join_thread(thread);
1060 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
1062 /* The renderer is not fully paused until it receives a sample. The thread
1063 * sending the sample blocks in IMemInputPin_Receive() until the filter is
1064 * stopped or run. */
1066 hr = IMediaControl_Pause(control);
1067 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1069 hr = IMediaControl_GetState(control, 0, &state);
1070 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1072 thread = send_frame(input);
1074 hr = IMediaControl_GetState(control, 1000, &state);
1075 ok(hr == S_OK, "Got hr %#x.\n", hr);
1077 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1079 hr = IMediaControl_Stop(control);
1080 ok(hr == S_OK, "Got hr %#x.\n", hr);
1082 hr = join_thread(thread);
1083 ok(hr == S_OK, "Got hr %#x.\n", hr);
1085 /* The sink will decommit our allocator for us when stopping, however it
1086 * will not recommit it when pausing. */
1087 hr = IMemInputPin_GetAllocator(input, &allocator);
1088 ok(hr == S_OK, "Got hr %#x.\n", hr);
1089 hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
1090 todo_wine ok(hr == VFW_E_NOT_COMMITTED, "Got hr %#x.\n", hr);
1091 if (hr == S_OK) IMediaSample_Release(sample);
1093 hr = IMemAllocator_Commit(allocator);
1094 ok(hr == S_OK, "Got hr %#x.\n", hr);
1095 thread = send_frame(input);
1096 hr = join_thread(thread);
1097 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
1099 hr = IMediaControl_Pause(control);
1100 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1102 hr = IMediaControl_GetState(control, 0, &state);
1103 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1105 thread = send_frame(input);
1107 hr = IMediaControl_GetState(control, 1000, &state);
1108 ok(hr == S_OK, "Got hr %#x.\n", hr);
1110 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1112 hr = IMediaControl_Run(control);
1113 ok(hr == S_OK, "Got hr %#x.\n", hr);
1115 hr = IMediaControl_GetState(control, 0, &state);
1116 ok(hr == S_OK, "Got hr %#x.\n", hr);
1118 hr = join_thread(thread);
1119 ok(hr == S_OK, "Got hr %#x.\n", hr);
1121 thread = send_frame(input);
1122 hr = join_thread(thread);
1123 ok(hr == S_OK, "Got hr %#x.\n", hr);
1125 hr = IMediaControl_Pause(control);
1126 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1128 hr = IMediaControl_GetState(control, 0, &state);
1129 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1131 thread = send_frame(input);
1133 hr = IMediaControl_GetState(control, 1000, &state);
1134 ok(hr == S_OK, "Got hr %#x.\n", hr);
1136 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1138 hr = IMediaControl_Run(control);
1139 ok(hr == S_OK, "Got hr %#x.\n", hr);
1141 hr = IMediaControl_GetState(control, 0, &state);
1142 ok(hr == S_OK, "Got hr %#x.\n", hr);
1144 hr = join_thread(thread);
1145 ok(hr == S_OK, "Got hr %#x.\n", hr);
1147 hr = IMediaControl_Pause(control);
1148 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1150 hr = IMediaControl_GetState(control, 0, &state);
1151 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1153 hr = IMediaControl_Stop(control);
1154 ok(hr == S_OK, "Got hr %#x.\n", hr);
1156 hr = IMediaControl_GetState(control, 0, &state);
1157 ok(hr == S_OK, "Got hr %#x.\n", hr);
1159 commit_allocator(input);
1160 hr = IMediaControl_Pause(control);
1161 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1163 hr = IMediaControl_GetState(control, 0, &state);
1164 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1166 hr = IMediaControl_Run(control);
1167 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1169 hr = IMediaControl_GetState(control, 0, &state);
1170 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1172 thread = send_frame(input);
1173 hr = join_thread(thread);
1174 ok(hr == S_OK, "Got hr %#x.\n", hr);
1176 hr = IMediaControl_GetState(control, 0, &state);
1177 ok(hr == S_OK, "Got hr %#x.\n", hr);
1179 hr = IMediaControl_Stop(control);
1180 ok(hr == S_OK, "Got hr %#x.\n", hr);
1182 hr = IMediaControl_GetState(control, 0, &state);
1183 ok(hr == S_OK, "Got hr %#x.\n", hr);
1185 IMemAllocator_Release(allocator);
1188 static void test_flushing(IPin *pin, IMemInputPin *input, IMediaControl *control)
1190 OAFilterState state;
1191 HANDLE thread;
1192 HRESULT hr;
1194 commit_allocator(input);
1195 hr = IMediaControl_Pause(control);
1196 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1198 thread = send_frame(input);
1199 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1201 hr = IMediaControl_GetState(control, 0, &state);
1202 ok(hr == S_OK, "Got hr %#x.\n", hr);
1204 hr = IPin_BeginFlush(pin);
1205 ok(hr == S_OK, "Got hr %#x.\n", hr);
1207 hr = join_thread(thread);
1208 ok(hr == S_OK, "Got hr %#x.\n", hr);
1210 thread = send_frame(input);
1211 hr = join_thread(thread);
1212 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1214 hr = IPin_EndFlush(pin);
1215 ok(hr == S_OK, "Got hr %#x.\n", hr);
1217 /* We dropped the sample we were holding, so now we need a new one... */
1219 hr = IMediaControl_GetState(control, 0, &state);
1220 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1222 thread = send_frame(input);
1223 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1225 hr = IMediaControl_Run(control);
1226 ok(hr == S_OK, "Got hr %#x.\n", hr);
1227 hr = join_thread(thread);
1228 ok(hr == S_OK, "Got hr %#x.\n", hr);
1230 hr = IPin_BeginFlush(pin);
1231 ok(hr == S_OK, "Got hr %#x.\n", hr);
1233 thread = send_frame(input);
1234 hr = join_thread(thread);
1235 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1237 hr = IPin_EndFlush(pin);
1238 ok(hr == S_OK, "Got hr %#x.\n", hr);
1240 thread = send_frame(input);
1241 hr = join_thread(thread);
1242 ok(hr == S_OK, "Got hr %#x.\n", hr);
1244 hr = IMediaControl_Stop(control);
1245 ok(hr == S_OK, "Got hr %#x.\n", hr);
1248 static unsigned int check_ec_complete(IMediaEvent *eventsrc, DWORD timeout)
1250 LONG_PTR param1, param2;
1251 unsigned int ret = 0;
1252 HRESULT hr;
1253 LONG code;
1255 while ((hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, timeout)) == S_OK)
1257 if (code == EC_COMPLETE)
1259 ok(param1 == S_OK, "Got param1 %#lx.\n", param1);
1260 ok(!param2, "Got param2 %#lx.\n", param2);
1261 ret++;
1263 IMediaEvent_FreeEventParams(eventsrc, code, param1, param2);
1264 timeout = 0;
1266 ok(hr == E_ABORT, "Got hr %#x.\n", hr);
1268 return ret;
1271 static void test_eos(IPin *pin, IMemInputPin *input, IMediaControl *control)
1273 IMediaEvent *eventsrc;
1274 OAFilterState state;
1275 HRESULT hr;
1276 BOOL ret;
1278 IMediaControl_QueryInterface(control, &IID_IMediaEvent, (void **)&eventsrc);
1280 commit_allocator(input);
1281 hr = IMediaControl_Pause(control);
1282 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1283 ret = check_ec_complete(eventsrc, 0);
1284 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1286 hr = IPin_EndOfStream(pin);
1287 ok(hr == S_OK, "Got hr %#x.\n", hr);
1289 hr = IMediaControl_GetState(control, 1000, &state);
1290 ok(hr == S_OK, "Got hr %#x.\n", hr);
1291 ret = check_ec_complete(eventsrc, 0);
1292 todo_wine ok(!ret, "Got unexpected EC_COMPLETE.\n");
1294 hr = join_thread(send_frame(input));
1295 todo_wine ok(hr == E_UNEXPECTED, "Got hr %#x.\n", hr);
1297 hr = IMediaControl_Run(control);
1298 ok(hr == S_OK, "Got hr %#x.\n", hr);
1299 ret = check_ec_complete(eventsrc, 0);
1300 todo_wine ok(ret == 1, "Expected EC_COMPLETE.\n");
1302 hr = IMediaControl_Stop(control);
1303 ok(hr == S_OK, "Got hr %#x.\n", hr);
1304 ret = check_ec_complete(eventsrc, 0);
1305 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1307 /* We do not receive an EC_COMPLETE notification until the last sample is
1308 * done rendering. */
1310 commit_allocator(input);
1311 hr = IMediaControl_Run(control);
1312 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1313 hr = join_thread(send_frame(input));
1314 ok(hr == S_OK, "Got hr %#x.\n", hr);
1315 hr = IMediaControl_GetState(control, 1000, &state);
1316 ok(hr == S_OK, "Got hr %#x.\n", hr);
1317 ret = check_ec_complete(eventsrc, 0);
1318 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1320 hr = IPin_EndOfStream(pin);
1321 ok(hr == S_OK, "Got hr %#x.\n", hr);
1322 ret = check_ec_complete(eventsrc, 0);
1323 todo_wine ok(!ret, "Got unexpected EC_COMPLETE.\n");
1324 ret = check_ec_complete(eventsrc, 1600);
1325 todo_wine ok(ret == 1, "Expected EC_COMPLETE.\n");
1327 hr = IMediaControl_Stop(control);
1328 ok(hr == S_OK, "Got hr %#x.\n", hr);
1329 ret = check_ec_complete(eventsrc, 0);
1330 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1332 /* Test sending EOS while flushing. */
1334 commit_allocator(input);
1335 hr = IMediaControl_Run(control);
1336 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1337 hr = join_thread(send_frame(input));
1338 ok(hr == S_OK, "Got hr %#x.\n", hr);
1340 hr = IPin_BeginFlush(pin);
1341 ok(hr == S_OK, "Got hr %#x.\n", hr);
1342 hr = IPin_EndOfStream(pin);
1343 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1344 hr = IPin_EndFlush(pin);
1345 ok(hr == S_OK, "Got hr %#x.\n", hr);
1347 hr = IMediaControl_Stop(control);
1348 ok(hr == S_OK, "Got hr %#x.\n", hr);
1349 ret = check_ec_complete(eventsrc, 0);
1350 todo_wine ok(!ret, "Got unexpected EC_COMPLETE.\n");
1352 /* Test sending EOS and then flushing or stopping. */
1354 commit_allocator(input);
1355 hr = IMediaControl_Run(control);
1356 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1357 hr = join_thread(send_frame(input));
1358 ok(hr == S_OK, "Got hr %#x.\n", hr);
1359 hr = IMediaControl_GetState(control, 1000, &state);
1360 ok(hr == S_OK, "Got hr %#x.\n", hr);
1362 hr = IPin_EndOfStream(pin);
1363 ok(hr == S_OK, "Got hr %#x.\n", hr);
1364 ret = check_ec_complete(eventsrc, 0);
1365 todo_wine ok(!ret, "Got unexpected EC_COMPLETE.\n");
1367 hr = IPin_BeginFlush(pin);
1368 ok(hr == S_OK, "Got hr %#x.\n", hr);
1369 hr = IPin_EndFlush(pin);
1370 ok(hr == S_OK, "Got hr %#x.\n", hr);
1372 hr = join_thread(send_frame(input));
1373 ok(hr == S_OK, "Got hr %#x.\n", hr);
1374 hr = IPin_EndOfStream(pin);
1375 ok(hr == S_OK, "Got hr %#x.\n", hr);
1376 ret = check_ec_complete(eventsrc, 0);
1377 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1379 hr = IMediaControl_Stop(control);
1380 ok(hr == S_OK, "Got hr %#x.\n", hr);
1381 ret = check_ec_complete(eventsrc, 0);
1382 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1384 IMediaEvent_Release(eventsrc);
1387 static void test_sample_time(IPin *pin, IMemInputPin *input, IMediaControl *control)
1389 OAFilterState state;
1390 HANDLE thread;
1391 HRESULT hr;
1393 commit_allocator(input);
1394 hr = IMediaControl_Pause(control);
1395 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1397 hr = IMediaControl_GetState(control, 0, &state);
1398 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1400 thread = send_frame_time(input, 1, 0x000000ff); /* blue */
1402 hr = IMediaControl_GetState(control, 1000, &state);
1403 ok(hr == S_OK, "Got hr %#x.\n", hr);
1405 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1407 hr = IMediaControl_Run(control);
1408 ok(hr == S_OK, "Got hr %#x.\n", hr);
1410 ok(WaitForSingleObject(thread, 500) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1412 hr = join_thread(thread);
1413 ok(hr == S_OK, "Got hr %#x.\n", hr);
1415 /* Sample time is relative to the time passed to Run(). Thus a sample
1416 * stamped at or earlier than 1s will now be displayed immediately, because
1417 * that time has already passed.
1418 * One may manually verify that all of the frames in this function are
1419 * rendered, including (by adding a Sleep() after sending the frame) the
1420 * cyan and green frames. Thus the VMR does not attempt to drop any frames
1421 * that it considers late. This remains true if the frames are marked as
1422 * discontinuous. */
1424 hr = join_thread(send_frame_time(input, 1, 0x0000ffff)); /* cyan */
1425 ok(hr == S_OK, "Got hr %#x.\n", hr);
1427 hr = join_thread(send_frame_time(input, 0, 0x0000ff00)); /* green */
1428 ok(hr == S_OK, "Got hr %#x.\n", hr);
1430 hr = join_thread(send_frame_time(input, -2, 0x00ff0000)); /* red */
1431 ok(hr == S_OK, "Got hr %#x.\n", hr);
1433 thread = send_frame_time(input, 2, 0x00ff00ff); /* magenta */
1434 ok(WaitForSingleObject(thread, 800) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1435 hr = join_thread(thread);
1436 ok(hr == S_OK, "Got hr %#x.\n", hr);
1438 thread = send_frame_time(input, 1000000, 0x00ffffff); /* white */
1439 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1441 hr = IPin_BeginFlush(pin);
1442 ok(hr == S_OK, "Got hr %#x.\n", hr);
1443 hr = join_thread(thread);
1444 ok(hr == S_OK, "Got hr %#x.\n", hr);
1445 hr = IPin_EndFlush(pin);
1446 ok(hr == S_OK, "Got hr %#x.\n", hr);
1448 thread = send_frame_time(input, 1000000, 0x00ffff00); /* yellow */
1449 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1451 hr = IMediaControl_Stop(control);
1452 ok(hr == S_OK, "Got hr %#x.\n", hr);
1453 hr = join_thread(thread);
1454 ok(hr == S_OK, "Got hr %#x.\n", hr);
1457 static void test_current_image(IBaseFilter *filter, IMemInputPin *input,
1458 IMediaControl *control, const BITMAPINFOHEADER *req_bih)
1460 LONG buffer[(sizeof(BITMAPINFOHEADER) + 32 * 16 * 4) / 4];
1461 const BITMAPINFOHEADER *bih = (BITMAPINFOHEADER *)buffer;
1462 const DWORD *data = (DWORD *)((char *)buffer + sizeof(BITMAPINFOHEADER));
1463 BITMAPINFOHEADER expect_bih = *req_bih;
1464 OAFilterState state;
1465 IBasicVideo *video;
1466 unsigned int i;
1467 HANDLE thread;
1468 HRESULT hr;
1469 LONG size;
1471 expect_bih.biSizeImage = 32 * 16 * 4;
1473 IBaseFilter_QueryInterface(filter, &IID_IBasicVideo, (void **)&video);
1475 hr = IBasicVideo_GetCurrentImage(video, NULL, NULL);
1476 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
1478 hr = IBasicVideo_GetCurrentImage(video, NULL, buffer);
1479 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
1481 size = 0xdeadbeef;
1482 hr = IBasicVideo_GetCurrentImage(video, &size, NULL);
1483 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
1484 todo_wine ok(size == sizeof(BITMAPINFOHEADER) + 32 * 16 * 4, "Got size %d.\n", size);
1486 size = sizeof(buffer);
1487 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1488 ok(hr == S_OK, "Got hr %#x.\n", hr);
1489 ok(size == sizeof(buffer), "Got size %d.\n", size);
1490 ok(!memcmp(bih, &expect_bih, sizeof(BITMAPINFOHEADER)), "Bitmap headers didn't match.\n");
1491 /* The contents seem to reflect the last frame rendered. */
1493 commit_allocator(input);
1494 hr = IMediaControl_Pause(control);
1495 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1497 size = sizeof(buffer);
1498 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1499 ok(hr == S_OK, "Got hr %#x.\n", hr);
1500 ok(size == sizeof(buffer), "Got size %d.\n", size);
1501 ok(!memcmp(bih, &expect_bih, sizeof(BITMAPINFOHEADER)), "Bitmap headers didn't match.\n");
1502 /* The contents seem to reflect the last frame rendered. */
1504 thread = send_frame(input);
1505 hr = IMediaControl_GetState(control, 1000, &state);
1506 ok(hr == S_OK, "Got hr %#x.\n", hr);
1508 size = 1;
1509 memset(buffer, 0xcc, sizeof(buffer));
1510 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1511 ok(hr == S_OK, "Got hr %#x.\n", hr);
1512 ok(size == 1, "Got size %d.\n", size);
1514 size = sizeof(buffer);
1515 memset(buffer, 0xcc, sizeof(buffer));
1516 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1517 ok(hr == S_OK, "Got hr %#x.\n", hr);
1518 ok(size == sizeof(buffer), "Got size %d.\n", size);
1519 ok(!memcmp(bih, &expect_bih, sizeof(BITMAPINFOHEADER)), "Bitmap headers didn't match.\n");
1520 for (i = 0; i < 32 * 16; ++i)
1521 ok((data[i] & 0xffffff) == 0x7f007f, "Got unexpected color %08x at %u.\n", data[i], i);
1523 hr = IMediaControl_Run(control);
1524 ok(hr == S_OK, "Got hr %#x.\n", hr);
1525 join_thread(thread);
1527 size = sizeof(buffer);
1528 memset(buffer, 0xcc, sizeof(buffer));
1529 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1530 ok(hr == S_OK, "Got hr %#x.\n", hr);
1531 ok(size == sizeof(buffer), "Got size %d.\n", size);
1532 ok(!memcmp(bih, &expect_bih, sizeof(BITMAPINFOHEADER)), "Bitmap headers didn't match.\n");
1533 for (i = 0; i < 32 * 16; ++i)
1534 ok((data[i] & 0xffffff) == 0x7f007f, "Got unexpected color %08x at %u.\n", data[i], i);
1536 hr = IMediaControl_Stop(control);
1537 ok(hr == S_OK, "Got hr %#x.\n", hr);
1539 IBasicVideo_Release(video);
1542 static void test_connect_pin(void)
1544 VIDEOINFOHEADER vih =
1546 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
1547 .bmiHeader.biBitCount = 32,
1548 .bmiHeader.biWidth = 32,
1549 .bmiHeader.biHeight = 16,
1550 .bmiHeader.biPlanes = 1,
1551 .bmiHeader.biCompression = BI_RGB,
1553 AM_MEDIA_TYPE req_mt =
1555 .majortype = MEDIATYPE_Video,
1556 .formattype = FORMAT_VideoInfo,
1557 .cbFormat = sizeof(vih),
1558 .pbFormat = (BYTE *)&vih,
1560 ALLOCATOR_PROPERTIES req_props = {1, 32 * 16 * 4, 1, 0}, ret_props;
1561 IBaseFilter *filter = create_vmr9(VMR9Mode_Windowed);
1562 IFilterGraph2 *graph = create_graph();
1563 struct testfilter source;
1564 IMemAllocator *allocator;
1565 IMediaControl *control;
1566 IMemInputPin *input;
1567 unsigned int i, j;
1568 AM_MEDIA_TYPE mt;
1569 IPin *pin, *peer;
1570 HRESULT hr;
1571 ULONG ref;
1573 static const GUID *subtype_tests[] =
1575 &MEDIASUBTYPE_RGB555,
1576 &MEDIASUBTYPE_RGB565,
1577 &MEDIASUBTYPE_RGB24,
1578 &MEDIASUBTYPE_RGB32,
1580 static const WORD bpp_tests[] = {15, 16, 24, 32};
1582 testfilter_init(&source);
1584 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL);
1585 IFilterGraph2_AddFilter(graph, filter, NULL);
1586 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
1588 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
1589 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
1591 for (i = 0; i < ARRAY_SIZE(subtype_tests); ++i)
1593 req_mt.subtype = *subtype_tests[i];
1595 for (j = 0; j < ARRAY_SIZE(bpp_tests); ++j)
1597 vih.bmiHeader.biBitCount = bpp_tests[j];
1599 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1600 if (hr == E_FAIL)
1602 skip("Got E_FAIL when connecting.\n");
1603 goto out;
1605 ok(hr == S_OK, "Got hr %#x for subtype %s and bpp %u.\n", hr,
1606 wine_dbgstr_guid(subtype_tests[i]), bpp_tests[j]);
1608 hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
1609 ok(hr == S_OK, "Got hr %#x.\n", hr);
1610 hr = IFilterGraph2_Disconnect(graph, pin);
1611 ok(hr == S_OK, "Got hr %#x.\n", hr);
1615 req_mt.formattype = FORMAT_None;
1616 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1617 ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr);
1618 req_mt.formattype = FORMAT_VideoInfo;
1620 req_mt.subtype = MEDIASUBTYPE_RGB8;
1621 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1622 todo_wine ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr);
1623 if (hr == S_OK)
1625 IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
1626 IFilterGraph2_Disconnect(graph, pin);
1628 req_mt.subtype = MEDIASUBTYPE_WAVE;
1629 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1630 todo_wine ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr);
1631 if (hr == S_OK)
1633 IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
1634 IFilterGraph2_Disconnect(graph, pin);
1636 req_mt.subtype = MEDIASUBTYPE_RGB32;
1638 peer = (IPin *)0xdeadbeef;
1639 hr = IPin_ConnectedTo(pin, &peer);
1640 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
1641 ok(!peer, "Got peer %p.\n", peer);
1643 hr = IPin_ConnectionMediaType(pin, &mt);
1644 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
1646 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1647 ok(hr == S_OK, "Got hr %#x.\n", hr);
1649 hr = IPin_ConnectedTo(pin, &peer);
1650 ok(hr == S_OK, "Got hr %#x.\n", hr);
1651 ok(peer == &source.source.pin.IPin_iface, "Got peer %p.\n", peer);
1652 IPin_Release(peer);
1654 hr = IPin_ConnectionMediaType(pin, &mt);
1655 ok(hr == S_OK, "Got hr %#x.\n", hr);
1656 ok(compare_media_types(&mt, &req_mt), "Media types didn't match.\n");
1658 test_allocator(input);
1660 hr = IMemInputPin_GetAllocator(input, &allocator);
1661 ok(hr == S_OK, "Got hr %#x.\n", hr);
1662 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
1663 ok(hr == S_OK, "Got hr %#x.\n", hr);
1664 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
1665 hr = IMemAllocator_Commit(allocator);
1666 ok(hr == S_OK, "Got hr %#x.\n", hr);
1667 IMemAllocator_Release(allocator);
1669 hr = IMemInputPin_ReceiveCanBlock(input);
1670 ok(hr == S_OK, "Got hr %#x.\n", hr);
1672 test_filter_state(input, control);
1673 test_flushing(pin, input, control);
1674 test_eos(pin, input, control);
1675 test_sample_time(pin, input, control);
1676 test_current_image(filter, input, control, &vih.bmiHeader);
1678 hr = IFilterGraph2_Disconnect(graph, pin);
1679 ok(hr == S_OK, "Got hr %#x.\n", hr);
1680 hr = IFilterGraph2_Disconnect(graph, pin);
1681 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1682 ok(source.source.pin.peer == pin, "Got peer %p.\n", source.source.pin.peer);
1683 IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
1685 peer = (IPin *)0xdeadbeef;
1686 hr = IPin_ConnectedTo(pin, &peer);
1687 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
1688 ok(!peer, "Got peer %p.\n", peer);
1690 hr = IPin_ConnectionMediaType(pin, &mt);
1691 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
1693 out:
1694 IMediaControl_Release(control);
1695 ref = IFilterGraph2_Release(graph);
1696 ok(!ref, "Got outstanding refcount %d.\n", ref);
1697 IMemInputPin_Release(input);
1698 IPin_Release(pin);
1699 ref = IBaseFilter_Release(filter);
1700 ok(!ref, "Got outstanding refcount %d.\n", ref);
1701 ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface);
1702 ok(!ref, "Got outstanding refcount %d.\n", ref);
1705 static void test_overlay(void)
1707 IBaseFilter *filter = create_vmr9(0);
1708 IOverlay *overlay;
1709 HRESULT hr;
1710 ULONG ref;
1711 IPin *pin;
1712 HWND hwnd;
1714 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
1716 hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay);
1717 ok(hr == S_OK, "Got hr %#x.\n", hr);
1719 hwnd = (HWND)0xdeadbeef;
1720 hr = IOverlay_GetWindowHandle(overlay, &hwnd);
1721 ok(hr == S_OK, "Got hr %#x.\n", hr);
1722 ok(hwnd && hwnd != (HWND)0xdeadbeef, "Got invalid window %p.\n", hwnd);
1724 IOverlay_Release(overlay);
1725 IPin_Release(pin);
1726 ref = IBaseFilter_Release(filter);
1727 ok(!ref, "Got outstanding refcount %d.\n", ref);
1729 filter = create_vmr9(VMR9Mode_Windowless);
1730 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
1732 hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay);
1733 ok(hr == S_OK, "Got hr %#x.\n", hr);
1735 hwnd = (HWND)0xdeadbeef;
1736 hr = IOverlay_GetWindowHandle(overlay, &hwnd);
1737 todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
1738 todo_wine ok(hwnd == (HWND)0xdeadbeef, "Got invalid window %p.\n", hwnd);
1740 IOverlay_Release(overlay);
1741 IPin_Release(pin);
1742 ref = IBaseFilter_Release(filter);
1743 ok(!ref, "Got outstanding refcount %d.\n", ref);
1745 filter = create_vmr9(VMR9Mode_Renderless);
1746 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
1748 hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay);
1749 ok(hr == S_OK, "Got hr %#x.\n", hr);
1751 hwnd = (HWND)0xdeadbeef;
1752 hr = IOverlay_GetWindowHandle(overlay, &hwnd);
1753 todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
1754 todo_wine ok(hwnd == (HWND)0xdeadbeef, "Got invalid window %p.\n", hwnd);
1756 IOverlay_Release(overlay);
1757 IPin_Release(pin);
1758 ref = IBaseFilter_Release(filter);
1759 ok(!ref, "Got outstanding refcount %d.\n", ref);
1762 /* try to make sure pending X events have been processed before continuing */
1763 static void flush_events(void)
1765 int diff = 200;
1766 DWORD time;
1767 MSG msg;
1769 time = GetTickCount() + diff;
1770 while (diff > 0)
1772 if (MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT) == WAIT_TIMEOUT)
1773 break;
1774 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
1775 DispatchMessageA(&msg);
1776 diff = time - GetTickCount();
1780 static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1782 if (winetest_debug > 1)
1783 trace("hwnd %p, msg %#x, wparam %#lx, lparam %#lx.\n", hwnd, msg, wparam, lparam);
1785 if (wparam == 0xdeadbeef)
1786 return 0;
1788 return DefWindowProcA(hwnd, msg, wparam, lparam);
1791 static void test_video_window_caption(IVideoWindow *window, HWND hwnd)
1793 WCHAR text[50];
1794 BSTR caption;
1795 HRESULT hr;
1797 hr = IVideoWindow_get_Caption(window, &caption);
1798 ok(hr == S_OK, "Got hr %#x.\n", hr);
1799 ok(!wcscmp(caption, L"ActiveMovie Window"), "Got caption %s.\n", wine_dbgstr_w(caption));
1800 SysFreeString(caption);
1802 GetWindowTextW(hwnd, text, ARRAY_SIZE(text));
1803 ok(!wcscmp(text, L"ActiveMovie Window"), "Got caption %s.\n", wine_dbgstr_w(text));
1805 caption = SysAllocString(L"foo");
1806 hr = IVideoWindow_put_Caption(window, caption);
1807 ok(hr == S_OK, "Got hr %#x.\n", hr);
1808 SysFreeString(caption);
1810 hr = IVideoWindow_get_Caption(window, &caption);
1811 ok(hr == S_OK, "Got hr %#x.\n", hr);
1812 ok(!wcscmp(caption, L"foo"), "Got caption %s.\n", wine_dbgstr_w(caption));
1813 SysFreeString(caption);
1815 GetWindowTextW(hwnd, text, ARRAY_SIZE(text));
1816 ok(!wcscmp(text, L"foo"), "Got caption %s.\n", wine_dbgstr_w(text));
1819 static void test_video_window_style(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
1821 HRESULT hr;
1822 LONG style;
1824 hr = IVideoWindow_get_WindowStyle(window, &style);
1825 ok(hr == S_OK, "Got hr %#x.\n", hr);
1826 ok(style == (WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW),
1827 "Got style %#x.\n", style);
1829 style = GetWindowLongA(hwnd, GWL_STYLE);
1830 ok(style == (WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW),
1831 "Got style %#x.\n", style);
1833 hr = IVideoWindow_put_WindowStyle(window, style | WS_DISABLED);
1834 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
1835 hr = IVideoWindow_put_WindowStyle(window, style | WS_HSCROLL);
1836 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
1837 hr = IVideoWindow_put_WindowStyle(window, style | WS_VSCROLL);
1838 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
1839 hr = IVideoWindow_put_WindowStyle(window, style | WS_MAXIMIZE);
1840 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
1841 hr = IVideoWindow_put_WindowStyle(window, style | WS_MINIMIZE);
1842 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
1844 hr = IVideoWindow_put_WindowStyle(window, style & ~WS_CLIPCHILDREN);
1845 ok(hr == S_OK, "Got hr %#x.\n", hr);
1847 hr = IVideoWindow_get_WindowStyle(window, &style);
1848 ok(hr == S_OK, "Got hr %#x.\n", hr);
1849 ok(style == (WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW), "Got style %#x.\n", style);
1851 style = GetWindowLongA(hwnd, GWL_STYLE);
1852 ok(style == (WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW), "Got style %#x.\n", style);
1854 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
1856 hr = IVideoWindow_get_WindowStyleEx(window, &style);
1857 ok(hr == S_OK, "Got hr %#x.\n", hr);
1858 ok(style == WS_EX_WINDOWEDGE, "Got style %#x.\n", style);
1860 style = GetWindowLongA(hwnd, GWL_EXSTYLE);
1861 ok(style == WS_EX_WINDOWEDGE, "Got style %#x.\n", style);
1863 hr = IVideoWindow_put_WindowStyleEx(window, style | WS_EX_TRANSPARENT);
1864 ok(hr == S_OK, "Got hr %#x.\n", hr);
1866 hr = IVideoWindow_get_WindowStyleEx(window, &style);
1867 ok(hr == S_OK, "Got hr %#x.\n", hr);
1868 ok(style == (WS_EX_WINDOWEDGE | WS_EX_TRANSPARENT), "Got style %#x.\n", style);
1870 style = GetWindowLongA(hwnd, GWL_EXSTYLE);
1871 ok(style == (WS_EX_WINDOWEDGE | WS_EX_TRANSPARENT), "Got style %#x.\n", style);
1874 static BOOL CALLBACK top_window_cb(HWND hwnd, LPARAM ctx)
1876 DWORD pid;
1877 GetWindowThreadProcessId(hwnd, &pid);
1878 if (pid == GetCurrentProcessId() && (GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE))
1880 *(HWND *)ctx = hwnd;
1881 return FALSE;
1883 return TRUE;
1886 static HWND get_top_window(void)
1888 HWND hwnd;
1889 EnumWindows(top_window_cb, (LPARAM)&hwnd);
1890 return hwnd;
1893 static void test_video_window_state(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
1895 HRESULT hr;
1896 LONG state;
1897 HWND top;
1899 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
1901 hr = IVideoWindow_get_WindowState(window, &state);
1902 ok(hr == S_OK, "Got hr %#x.\n", hr);
1903 ok(state == SW_HIDE, "Got state %d.\n", state);
1905 hr = IVideoWindow_get_Visible(window, &state);
1906 ok(state == OAFALSE, "Got state %d.\n", state);
1908 ok(!IsWindowVisible(hwnd), "Window should not be visible.\n");
1909 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
1910 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
1912 hr = IVideoWindow_put_WindowState(window, SW_SHOWNA);
1913 ok(hr == S_OK, "Got hr %#x.\n", hr);
1915 hr = IVideoWindow_get_WindowState(window, &state);
1916 ok(hr == S_OK, "Got hr %#x.\n", hr);
1917 ok(state == SW_SHOW, "Got state %d.\n", state);
1919 hr = IVideoWindow_get_Visible(window, &state);
1920 ok(state == OATRUE, "Got state %d.\n", state);
1922 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
1923 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
1924 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
1925 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
1926 top = get_top_window();
1927 ok(top == hwnd, "Got top window %p.\n", top);
1929 hr = IVideoWindow_put_WindowState(window, SW_MINIMIZE);
1930 ok(hr == S_OK, "Got hr %#x.\n", hr);
1932 hr = IVideoWindow_get_WindowState(window, &state);
1933 ok(hr == S_OK, "Got hr %#x.\n", hr);
1934 ok(state == SW_MINIMIZE, "Got state %d.\n", state);
1936 hr = IVideoWindow_get_Visible(window, &state);
1937 ok(state == OATRUE, "Got state %d.\n", state);
1939 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
1940 ok(IsIconic(hwnd), "Window should be minimized.\n");
1941 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
1942 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
1944 hr = IVideoWindow_put_WindowState(window, SW_RESTORE);
1945 ok(hr == S_OK, "Got hr %#x.\n", hr);
1947 hr = IVideoWindow_get_WindowState(window, &state);
1948 ok(hr == S_OK, "Got hr %#x.\n", hr);
1949 ok(state == SW_SHOW, "Got state %d.\n", state);
1951 hr = IVideoWindow_get_Visible(window, &state);
1952 ok(state == OATRUE, "Got state %d.\n", state);
1954 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
1955 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
1956 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
1957 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
1959 hr = IVideoWindow_put_WindowState(window, SW_MAXIMIZE);
1960 ok(hr == S_OK, "Got hr %#x.\n", hr);
1962 hr = IVideoWindow_get_WindowState(window, &state);
1963 ok(hr == S_OK, "Got hr %#x.\n", hr);
1964 ok(state == SW_MAXIMIZE, "Got state %d.\n", state);
1966 hr = IVideoWindow_get_Visible(window, &state);
1967 ok(state == OATRUE, "Got state %d.\n", state);
1969 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
1970 ok(!IsIconic(hwnd), "Window should be minimized.\n");
1971 ok(IsZoomed(hwnd), "Window should not be maximized.\n");
1972 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
1974 hr = IVideoWindow_put_WindowState(window, SW_RESTORE);
1975 ok(hr == S_OK, "Got hr %#x.\n", hr);
1977 hr = IVideoWindow_put_WindowState(window, SW_HIDE);
1978 ok(hr == S_OK, "Got hr %#x.\n", hr);
1980 hr = IVideoWindow_get_WindowState(window, &state);
1981 ok(hr == S_OK, "Got hr %#x.\n", hr);
1982 ok(state == SW_HIDE, "Got state %d.\n", state);
1984 hr = IVideoWindow_get_Visible(window, &state);
1985 ok(state == OAFALSE, "Got state %d.\n", state);
1987 ok(!IsWindowVisible(hwnd), "Window should not be visible.\n");
1988 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
1989 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
1990 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
1992 hr = IVideoWindow_put_Visible(window, OATRUE);
1993 ok(hr == S_OK, "Got hr %#x.\n", hr);
1995 hr = IVideoWindow_get_WindowState(window, &state);
1996 ok(hr == S_OK, "Got hr %#x.\n", hr);
1997 ok(state == SW_SHOW, "Got state %d.\n", state);
1999 hr = IVideoWindow_get_Visible(window, &state);
2000 ok(state == OATRUE, "Got state %d.\n", state);
2002 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
2003 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
2004 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
2005 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
2007 hr = IVideoWindow_put_Visible(window, OAFALSE);
2008 ok(hr == S_OK, "Got hr %#x.\n", hr);
2010 hr = IVideoWindow_get_WindowState(window, &state);
2011 ok(hr == S_OK, "Got hr %#x.\n", hr);
2012 ok(state == SW_HIDE, "Got state %d.\n", state);
2014 hr = IVideoWindow_get_Visible(window, &state);
2015 ok(state == OAFALSE, "Got state %d.\n", state);
2017 ok(!IsWindowVisible(hwnd), "Window should not be visible.\n");
2018 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
2019 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
2020 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2022 hr = IVideoWindow_put_WindowState(window, SW_SHOWNA);
2023 ok(hr == S_OK, "Got hr %#x.\n", hr);
2025 hr = IVideoWindow_SetWindowForeground(window, TRUE);
2026 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
2028 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2029 hr = IVideoWindow_SetWindowForeground(window, OATRUE);
2030 ok(hr == S_OK, "Got hr %#x.\n", hr);
2031 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
2032 ok(GetFocus() == hwnd, "Got focus window %p.\n", GetFocus());
2033 ok(GetForegroundWindow() == hwnd, "Got foreground window %p.\n", GetForegroundWindow());
2034 top = get_top_window();
2035 ok(top == hwnd, "Got top window %p.\n", top);
2037 hr = IVideoWindow_SetWindowForeground(window, OAFALSE);
2038 ok(hr == S_OK, "Got hr %#x.\n", hr);
2039 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
2040 ok(GetFocus() == hwnd, "Got focus window %p.\n", GetFocus());
2041 ok(GetForegroundWindow() == hwnd, "Got foreground window %p.\n", GetForegroundWindow());
2042 top = get_top_window();
2043 ok(top == hwnd, "Got top window %p.\n", top);
2045 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2046 hr = IVideoWindow_SetWindowForeground(window, OAFALSE);
2047 ok(hr == S_OK, "Got hr %#x.\n", hr);
2048 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2049 ok(GetFocus() == our_hwnd, "Got focus window %p.\n", GetFocus());
2050 ok(GetForegroundWindow() == our_hwnd, "Got foreground window %p.\n", GetForegroundWindow());
2051 top = get_top_window();
2052 ok(top == hwnd, "Got top window %p.\n", top);
2055 static void test_video_window_position(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
2057 LONG left, width, top, height, expect_width, expect_height;
2058 RECT rect = {0, 0, 600, 400};
2059 HWND top_hwnd;
2060 HRESULT hr;
2062 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2064 AdjustWindowRect(&rect, GetWindowLongA(hwnd, GWL_STYLE), FALSE);
2065 expect_width = rect.right - rect.left;
2066 expect_height = rect.bottom - rect.top;
2068 hr = IVideoWindow_put_Left(window, 0);
2069 ok(hr == S_OK, "Got hr %#x.\n", hr);
2070 hr = IVideoWindow_put_Top(window, 0);
2071 ok(hr == S_OK, "Got hr %#x.\n", hr);
2073 hr = IVideoWindow_get_Left(window, &left);
2074 ok(hr == S_OK, "Got hr %#x.\n", hr);
2075 ok(left == 0, "Got left %d.\n", left);
2076 hr = IVideoWindow_get_Top(window, &top);
2077 ok(hr == S_OK, "Got hr %#x.\n", hr);
2078 ok(top == 0, "Got top %d.\n", top);
2079 hr = IVideoWindow_get_Width(window, &width);
2080 ok(hr == S_OK, "Got hr %#x.\n", hr);
2081 ok(width == expect_width, "Got width %d.\n", width);
2082 hr = IVideoWindow_get_Height(window, &height);
2083 ok(hr == S_OK, "Got hr %#x.\n", hr);
2084 ok(height == expect_height, "Got height %d.\n", height);
2085 hr = IVideoWindow_GetWindowPosition(window, &left, &top, &width, &height);
2086 ok(hr == S_OK, "Got hr %#x.\n", hr);
2087 ok(left == 0, "Got left %d.\n", left);
2088 ok(top == 0, "Got top %d.\n", top);
2089 ok(width == expect_width, "Got width %d.\n", width);
2090 ok(height == expect_height, "Got height %d.\n", height);
2091 GetWindowRect(hwnd, &rect);
2092 ok(rect.left == 0, "Got window left %d.\n", rect.left);
2093 ok(rect.top == 0, "Got window top %d.\n", rect.top);
2094 ok(rect.right == expect_width, "Got window right %d.\n", rect.right);
2095 ok(rect.bottom == expect_height, "Got window bottom %d.\n", rect.bottom);
2097 hr = IVideoWindow_put_Left(window, 10);
2098 ok(hr == S_OK, "Got hr %#x.\n", hr);
2100 hr = IVideoWindow_get_Left(window, &left);
2101 ok(hr == S_OK, "Got hr %#x.\n", hr);
2102 ok(left == 10, "Got left %d.\n", left);
2103 hr = IVideoWindow_get_Top(window, &top);
2104 ok(hr == S_OK, "Got hr %#x.\n", hr);
2105 ok(top == 0, "Got top %d.\n", top);
2106 hr = IVideoWindow_get_Width(window, &width);
2107 ok(hr == S_OK, "Got hr %#x.\n", hr);
2108 ok(width == expect_width, "Got width %d.\n", width);
2109 hr = IVideoWindow_get_Height(window, &height);
2110 ok(hr == S_OK, "Got hr %#x.\n", hr);
2111 ok(height == expect_height, "Got height %d.\n", height);
2112 hr = IVideoWindow_GetWindowPosition(window, &left, &top, &width, &height);
2113 ok(hr == S_OK, "Got hr %#x.\n", hr);
2114 ok(left == 10, "Got left %d.\n", left);
2115 ok(top == 0, "Got top %d.\n", top);
2116 ok(width == expect_width, "Got width %d.\n", width);
2117 ok(height == expect_height, "Got height %d.\n", height);
2118 GetWindowRect(hwnd, &rect);
2119 ok(rect.left == 10, "Got window left %d.\n", rect.left);
2120 ok(rect.top == 0, "Got window top %d.\n", rect.top);
2121 ok(rect.right == 10 + expect_width, "Got window right %d.\n", rect.right);
2122 ok(rect.bottom == expect_height, "Got window bottom %d.\n", rect.bottom);
2124 hr = IVideoWindow_put_Height(window, 200);
2125 ok(hr == S_OK, "Got hr %#x.\n", hr);
2127 hr = IVideoWindow_get_Left(window, &left);
2128 ok(hr == S_OK, "Got hr %#x.\n", hr);
2129 ok(left == 10, "Got left %d.\n", left);
2130 hr = IVideoWindow_get_Top(window, &top);
2131 ok(hr == S_OK, "Got hr %#x.\n", hr);
2132 ok(top == 0, "Got top %d.\n", top);
2133 hr = IVideoWindow_get_Width(window, &width);
2134 ok(hr == S_OK, "Got hr %#x.\n", hr);
2135 ok(width == expect_width, "Got width %d.\n", width);
2136 hr = IVideoWindow_get_Height(window, &height);
2137 ok(hr == S_OK, "Got hr %#x.\n", hr);
2138 ok(height == 200, "Got height %d.\n", height);
2139 hr = IVideoWindow_GetWindowPosition(window, &left, &top, &width, &height);
2140 ok(hr == S_OK, "Got hr %#x.\n", hr);
2141 ok(left == 10, "Got left %d.\n", left);
2142 ok(top == 0, "Got top %d.\n", top);
2143 ok(width == expect_width, "Got width %d.\n", width);
2144 ok(height == 200, "Got height %d.\n", height);
2145 GetWindowRect(hwnd, &rect);
2146 ok(rect.left == 10, "Got window left %d.\n", rect.left);
2147 ok(rect.top == 0, "Got window top %d.\n", rect.top);
2148 ok(rect.right == 10 + expect_width, "Got window right %d.\n", rect.right);
2149 ok(rect.bottom == 200, "Got window bottom %d.\n", rect.bottom);
2151 hr = IVideoWindow_SetWindowPosition(window, 100, 200, 300, 400);
2152 ok(hr == S_OK, "Got hr %#x.\n", hr);
2154 hr = IVideoWindow_get_Left(window, &left);
2155 ok(hr == S_OK, "Got hr %#x.\n", hr);
2156 ok(left == 100, "Got left %d.\n", left);
2157 hr = IVideoWindow_get_Top(window, &top);
2158 ok(hr == S_OK, "Got hr %#x.\n", hr);
2159 ok(top == 200, "Got top %d.\n", top);
2160 hr = IVideoWindow_get_Width(window, &width);
2161 ok(hr == S_OK, "Got hr %#x.\n", hr);
2162 ok(width == 300, "Got width %d.\n", width);
2163 hr = IVideoWindow_get_Height(window, &height);
2164 ok(hr == S_OK, "Got hr %#x.\n", hr);
2165 ok(height == 400, "Got height %d.\n", height);
2166 hr = IVideoWindow_GetWindowPosition(window, &left, &top, &width, &height);
2167 ok(hr == S_OK, "Got hr %#x.\n", hr);
2168 ok(left == 100, "Got left %d.\n", left);
2169 ok(top == 200, "Got top %d.\n", top);
2170 ok(width == 300, "Got width %d.\n", width);
2171 ok(height == 400, "Got height %d.\n", height);
2172 GetWindowRect(hwnd, &rect);
2173 ok(rect.left == 100, "Got window left %d.\n", rect.left);
2174 ok(rect.top == 200, "Got window top %d.\n", rect.top);
2175 ok(rect.right == 400, "Got window right %d.\n", rect.right);
2176 ok(rect.bottom == 600, "Got window bottom %d.\n", rect.bottom);
2178 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2179 top_hwnd = get_top_window();
2180 ok(top_hwnd == our_hwnd, "Got top window %p.\n", top_hwnd);
2183 static void test_video_window_owner(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
2185 HWND parent, top_hwnd;
2186 LONG style, state;
2187 OAHWND oahwnd;
2188 HRESULT hr;
2190 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2192 hr = IVideoWindow_get_Owner(window, &oahwnd);
2193 ok(hr == S_OK, "Got hr %#x.\n", hr);
2194 ok(!oahwnd, "Got owner %#lx.\n", oahwnd);
2196 parent = GetAncestor(hwnd, GA_PARENT);
2197 ok(parent == GetDesktopWindow(), "Got parent %p.\n", parent);
2198 style = GetWindowLongA(hwnd, GWL_STYLE);
2199 ok(!(style & WS_CHILD), "Got style %#x.\n", style);
2201 hr = IVideoWindow_put_Owner(window, (OAHWND)our_hwnd);
2202 ok(hr == S_OK, "Got hr %#x.\n", hr);
2204 hr = IVideoWindow_get_Owner(window, &oahwnd);
2205 ok(hr == S_OK, "Got hr %#x.\n", hr);
2206 ok(oahwnd == (OAHWND)our_hwnd, "Got owner %#lx.\n", oahwnd);
2208 parent = GetAncestor(hwnd, GA_PARENT);
2209 ok(parent == our_hwnd, "Got parent %p.\n", parent);
2210 style = GetWindowLongA(hwnd, GWL_STYLE);
2211 ok((style & WS_CHILD), "Got style %#x.\n", style);
2213 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2214 top_hwnd = get_top_window();
2215 ok(top_hwnd == our_hwnd, "Got top window %p.\n", top_hwnd);
2217 ShowWindow(our_hwnd, SW_HIDE);
2219 hr = IVideoWindow_put_Visible(window, OATRUE);
2220 ok(hr == S_OK, "Got hr %#x.\n", hr);
2222 hr = IVideoWindow_get_Visible(window, &state);
2223 ok(hr == S_OK, "Got hr %#x.\n", hr);
2224 ok(state == OAFALSE, "Got state %d.\n", state);
2226 hr = IVideoWindow_put_Owner(window, 0);
2227 ok(hr == S_OK, "Got hr %#x.\n", hr);
2229 hr = IVideoWindow_get_Owner(window, &oahwnd);
2230 ok(hr == S_OK, "Got hr %#x.\n", hr);
2231 ok(!oahwnd, "Got owner %#lx.\n", oahwnd);
2233 parent = GetAncestor(hwnd, GA_PARENT);
2234 ok(parent == GetDesktopWindow(), "Got parent %p.\n", parent);
2235 style = GetWindowLongA(hwnd, GWL_STYLE);
2236 ok(!(style & WS_CHILD), "Got style %#x.\n", style);
2238 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
2239 top_hwnd = get_top_window();
2240 ok(top_hwnd == hwnd, "Got top window %p.\n", top_hwnd);
2242 hr = IVideoWindow_get_Visible(window, &state);
2243 ok(hr == S_OK, "Got hr %#x.\n", hr);
2244 ok(state == OATRUE, "Got state %d.\n", state);
2247 struct notify_message_params
2249 IVideoWindow *window;
2250 HWND hwnd;
2251 UINT message;
2254 static DWORD CALLBACK notify_message_proc(void *arg)
2256 const struct notify_message_params *params = arg;
2257 HRESULT hr = IVideoWindow_NotifyOwnerMessage(params->window, (OAHWND)params->hwnd, params->message, 0, 0);
2258 ok(hr == S_OK, "Got hr %#x.\n", hr);
2259 return 0;
2262 static void test_video_window_messages(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
2264 struct notify_message_params params;
2265 unsigned int i;
2266 OAHWND oahwnd;
2267 HANDLE thread;
2268 HRESULT hr;
2269 BOOL ret;
2270 MSG msg;
2272 static UINT drain_tests[] =
2274 WM_MOUSEACTIVATE,
2275 WM_NCLBUTTONDOWN,
2276 WM_NCLBUTTONUP,
2277 WM_NCLBUTTONDBLCLK,
2278 WM_NCRBUTTONDOWN,
2279 WM_NCRBUTTONUP,
2280 WM_NCRBUTTONDBLCLK,
2281 WM_NCMBUTTONDOWN,
2282 WM_NCMBUTTONUP,
2283 WM_NCMBUTTONDBLCLK,
2284 WM_KEYDOWN,
2285 WM_KEYUP,
2286 WM_MOUSEMOVE,
2287 WM_LBUTTONDOWN,
2288 WM_LBUTTONUP,
2289 WM_LBUTTONDBLCLK,
2290 WM_RBUTTONDOWN,
2291 WM_RBUTTONUP,
2292 WM_RBUTTONDBLCLK,
2293 WM_MBUTTONDOWN,
2294 WM_MBUTTONUP,
2295 WM_MBUTTONDBLCLK,
2298 flush_events();
2300 hr = IVideoWindow_get_MessageDrain(window, &oahwnd);
2301 ok(hr == S_OK, "Got hr %#x.\n", hr);
2302 ok(!oahwnd, "Got window %#lx.\n", oahwnd);
2304 hr = IVideoWindow_put_MessageDrain(window, (OAHWND)our_hwnd);
2305 ok(hr == S_OK, "Got hr %#x.\n", hr);
2307 hr = IVideoWindow_get_MessageDrain(window, &oahwnd);
2308 ok(hr == S_OK, "Got hr %#x.\n", hr);
2309 ok(oahwnd == (OAHWND)our_hwnd, "Got window %#lx.\n", oahwnd);
2311 for (i = 0; i < ARRAY_SIZE(drain_tests); ++i)
2313 SendMessageA(hwnd, drain_tests[i], 0xdeadbeef, 0);
2314 ret = PeekMessageA(&msg, 0, drain_tests[i], drain_tests[i], PM_REMOVE);
2315 ok(ret, "Expected a message.\n");
2316 ok(msg.hwnd == our_hwnd, "Got hwnd %p.\n", msg.hwnd);
2317 ok(msg.message == drain_tests[i], "Got message %#x.\n", msg.message);
2318 ok(msg.wParam == 0xdeadbeef, "Got wparam %#lx.\n", msg.wParam);
2319 ok(!msg.lParam, "Got lparam %#lx.\n", msg.lParam);
2320 DispatchMessageA(&msg);
2322 ret = PeekMessageA(&msg, 0, drain_tests[i], drain_tests[i], PM_REMOVE);
2323 ok(!ret, "Got unexpected message %#x.\n", msg.message);
2326 hr = IVideoWindow_put_MessageDrain(window, 0);
2327 ok(hr == S_OK, "Got hr %#x.\n", hr);
2329 hr = IVideoWindow_put_Owner(window, (OAHWND)our_hwnd);
2330 ok(hr == S_OK, "Got hr %#x.\n", hr);
2332 flush_events();
2334 hr = IVideoWindow_NotifyOwnerMessage(window, (OAHWND)our_hwnd, WM_SYSCOLORCHANGE, 0, 0);
2335 ok(hr == S_OK, "Got hr %#x.\n", hr);
2337 ret = GetQueueStatus(QS_SENDMESSAGE | QS_POSTMESSAGE);
2338 ok(!ret, "Got unexpected status %#x.\n", ret);
2340 hr = IVideoWindow_NotifyOwnerMessage(window, (OAHWND)our_hwnd, WM_SETCURSOR,
2341 (WPARAM)hwnd, MAKELONG(HTCLIENT, WM_MOUSEMOVE));
2342 ok(hr == S_OK, "Got hr %#x.\n", hr);
2344 ret = GetQueueStatus(QS_SENDMESSAGE | QS_POSTMESSAGE);
2345 ok(!ret, "Got unexpected status %#x.\n", ret);
2347 params.window = window;
2348 params.hwnd = our_hwnd;
2349 params.message = WM_SYSCOLORCHANGE;
2350 thread = CreateThread(NULL, 0, notify_message_proc, &params, 0, NULL);
2351 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block.\n");
2352 ret = GetQueueStatus(QS_SENDMESSAGE | QS_POSTMESSAGE);
2353 ok(ret == ((QS_SENDMESSAGE << 16) | QS_SENDMESSAGE), "Got unexpected status %#x.\n", ret);
2355 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
2356 ok(!WaitForSingleObject(thread, 1000), "Wait timed out.\n");
2357 CloseHandle(thread);
2359 params.message = WM_SETCURSOR;
2360 thread = CreateThread(NULL, 0, notify_message_proc, &params, 0, NULL);
2361 ok(!WaitForSingleObject(thread, 1000), "Thread should not block.\n");
2362 CloseHandle(thread);
2363 ret = GetQueueStatus(QS_SENDMESSAGE | QS_POSTMESSAGE);
2364 ok(!ret, "Got unexpected status %#x.\n", ret);
2366 hr = IVideoWindow_put_Owner(window, 0);
2367 ok(hr == S_OK, "Got hr %#x.\n", hr);
2370 static void test_video_window_autoshow(IVideoWindow *window, IFilterGraph2 *graph, HWND hwnd)
2372 IMediaControl *control;
2373 HRESULT hr;
2374 LONG l;
2376 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
2378 hr = IVideoWindow_get_AutoShow(window, &l);
2379 ok(hr == S_OK, "Got hr %#x.\n", hr);
2380 ok(l == OATRUE, "Got %d.\n", l);
2382 hr = IVideoWindow_put_Visible(window, OAFALSE);
2383 ok(hr == S_OK, "Got hr %#x.\n", hr);
2385 hr = IMediaControl_Pause(control);
2386 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
2388 hr = IVideoWindow_get_Visible(window, &l);
2389 ok(hr == S_OK, "Got hr %#x.\n", hr);
2390 todo_wine ok(l == OATRUE, "Got %d.\n", l);
2392 hr = IMediaControl_Stop(control);
2393 ok(hr == S_OK, "Got hr %#x.\n", hr);
2395 hr = IVideoWindow_get_Visible(window, &l);
2396 ok(hr == S_OK, "Got hr %#x.\n", hr);
2397 todo_wine ok(l == OATRUE, "Got %d.\n", l);
2399 hr = IVideoWindow_put_AutoShow(window, OAFALSE);
2400 ok(hr == S_OK, "Got hr %#x.\n", hr);
2402 hr = IVideoWindow_put_Visible(window, OAFALSE);
2403 ok(hr == S_OK, "Got hr %#x.\n", hr);
2405 hr = IMediaControl_Pause(control);
2406 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
2408 hr = IVideoWindow_get_Visible(window, &l);
2409 ok(hr == S_OK, "Got hr %#x.\n", hr);
2410 ok(l == OAFALSE, "Got %d.\n", l);
2412 hr = IMediaControl_Stop(control);
2413 ok(hr == S_OK, "Got hr %#x.\n", hr);
2415 IMediaControl_Release(control);
2418 static void test_video_window(void)
2420 ALLOCATOR_PROPERTIES req_props = {1, 600 * 400 * 4, 1, 0}, ret_props;
2421 VIDEOINFOHEADER vih =
2423 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
2424 .bmiHeader.biBitCount = 32,
2425 .bmiHeader.biWidth = 600,
2426 .bmiHeader.biHeight = 400,
2427 .bmiHeader.biPlanes = 1,
2428 .bmiHeader.biCompression = BI_RGB,
2430 AM_MEDIA_TYPE req_mt =
2432 .majortype = MEDIATYPE_Video,
2433 .subtype = MEDIASUBTYPE_RGB32,
2434 .formattype = FORMAT_VideoInfo,
2435 .cbFormat = sizeof(vih),
2436 .pbFormat = (BYTE *)&vih,
2438 IFilterGraph2 *graph = create_graph();
2439 WNDCLASSA window_class = {0};
2440 struct testfilter source;
2441 IMemAllocator *allocator;
2442 MONITORINFO monitorinfo;
2443 IMediaControl *control;
2444 LONG width, height, l;
2445 IVideoWindow *window;
2446 IMemInputPin *input;
2447 IBaseFilter *filter;
2448 HWND hwnd, our_hwnd;
2449 IOverlay *overlay;
2450 BSTR caption;
2451 HRESULT hr;
2452 DWORD tid;
2453 ULONG ref;
2454 IPin *pin;
2455 RECT rect;
2457 window_class.lpszClassName = "wine_test_class";
2458 window_class.lpfnWndProc = window_proc;
2459 RegisterClassA(&window_class);
2460 our_hwnd = CreateWindowA("wine_test_class", "test window", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
2461 100, 200, 300, 400, NULL, NULL, NULL, NULL);
2462 flush_events();
2464 filter = create_vmr9(VMR9Mode_Windowed);
2465 flush_events();
2467 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2469 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
2470 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
2472 hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay);
2473 ok(hr == S_OK, "Got hr %#x.\n", hr);
2475 hr = IOverlay_GetWindowHandle(overlay, &hwnd);
2476 ok(hr == S_OK, "Got hr %#x.\n", hr);
2477 if (winetest_debug > 1) trace("ours %p, theirs %p\n", our_hwnd, hwnd);
2478 GetWindowRect(hwnd, &rect);
2480 tid = GetWindowThreadProcessId(hwnd, NULL);
2481 ok(tid == GetCurrentThreadId(), "Expected tid %#x, got %#x.\n", GetCurrentThreadId(), tid);
2483 hr = IBaseFilter_QueryInterface(filter, &IID_IVideoWindow, (void **)&window);
2484 ok(hr == S_OK, "Got hr %#x.\n", hr);
2486 hr = IVideoWindow_get_Caption(window, &caption);
2487 todo_wine ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
2489 hr = IVideoWindow_get_WindowStyle(window, &l);
2490 todo_wine ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
2492 hr = IVideoWindow_get_AutoShow(window, &l);
2493 todo_wine ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
2495 testfilter_init(&source);
2496 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL);
2497 IFilterGraph2_AddFilter(graph, filter, NULL);
2498 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
2499 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
2500 if (hr == E_FAIL)
2502 skip("Got E_FAIL when connecting.\n");
2503 goto out;
2505 ok(hr == S_OK, "Got hr %#x.\n", hr);
2507 hr = IMemInputPin_GetAllocator(input, &allocator);
2508 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
2509 if (hr == S_OK)
2511 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
2512 ok(hr == S_OK, "Got hr %#x.\n", hr);
2513 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
2514 hr = IMemAllocator_Commit(allocator);
2515 ok(hr == S_OK, "Got hr %#x.\n", hr);
2516 IMemAllocator_Release(allocator);
2519 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2521 test_video_window_caption(window, hwnd);
2522 test_video_window_style(window, hwnd, our_hwnd);
2523 test_video_window_state(window, hwnd, our_hwnd);
2524 test_video_window_position(window, hwnd, our_hwnd);
2525 test_video_window_autoshow(window, graph, hwnd);
2526 test_video_window_owner(window, hwnd, our_hwnd);
2527 test_video_window_messages(window, hwnd, our_hwnd);
2529 hr = IVideoWindow_put_FullScreenMode(window, OATRUE);
2530 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
2531 hr = IVideoWindow_get_FullScreenMode(window, &l);
2532 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
2534 hr = IVideoWindow_GetMinIdealImageSize(window, &width, &height);
2535 todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
2536 hr = IVideoWindow_GetMaxIdealImageSize(window, &width, &height);
2537 todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
2539 hr = IMediaControl_Pause(control);
2540 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
2542 monitorinfo.cbSize = sizeof(monitorinfo);
2543 GetMonitorInfoW(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &monitorinfo);
2545 hr = IVideoWindow_GetMinIdealImageSize(window, &width, &height);
2546 ok(hr == S_OK, "Got hr %#x.\n", hr);
2547 todo_wine ok(width == 1, "Got width %d.\n", width);
2548 todo_wine ok(height == 1, "Got height %d.\n", height);
2549 hr = IVideoWindow_GetMaxIdealImageSize(window, &width, &height);
2550 ok(hr == S_OK, "Got hr %#x.\n", hr);
2551 todo_wine ok(width == monitorinfo.rcMonitor.right + 1, "Expected width %d, got %d.\n",
2552 monitorinfo.rcMonitor.right + 1, width);
2553 todo_wine ok(height == monitorinfo.rcMonitor.bottom + 1, "Expected height %d, got %d.\n",
2554 monitorinfo.rcMonitor.bottom + 1, height);
2556 hr = IMediaControl_Stop(control);
2557 ok(hr == S_OK, "Got hr %#x.\n", hr);
2559 out:
2560 IMediaControl_Release(control);
2561 IFilterGraph2_Release(graph);
2562 IVideoWindow_Release(window);
2563 IOverlay_Release(overlay);
2564 IMemInputPin_Release(input);
2565 IPin_Release(pin);
2566 ref = IBaseFilter_Release(filter);
2567 ok(!ref, "Got outstanding refcount %d.\n", ref);
2568 ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface);
2569 ok(!ref, "Got outstanding refcount %d.\n", ref);
2570 DestroyWindow(our_hwnd);
2573 static IDirect3DDevice9 *create_device(HWND window)
2575 D3DPRESENT_PARAMETERS present_parameters =
2577 .Windowed = TRUE,
2578 .hDeviceWindow = window,
2579 .SwapEffect = D3DSWAPEFFECT_DISCARD,
2580 .BackBufferWidth = 640,
2581 .BackBufferHeight = 480,
2582 .BackBufferFormat = D3DFMT_A8R8G8B8,
2584 IDirect3DDevice9 *device;
2585 IDirect3D9 *d3d;
2586 HRESULT hr;
2588 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2589 ok(!!d3d, "Failed to create a D3D object.\n");
2591 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,
2592 D3DCREATE_HARDWARE_VERTEXPROCESSING, &present_parameters, &device);
2593 IDirect3D9_Release(d3d);
2594 if (FAILED(hr))
2596 skip("Failed to create a 3D device, hr %#x.\n", hr);
2597 return NULL;
2599 return device;
2602 static void test_allocate_surface_helper(void)
2604 VMR9AllocationInfo info =
2606 .dwFlags = VMR9AllocFlag_OffscreenSurface,
2607 .dwWidth = 32,
2608 .dwHeight = 16,
2609 .Format = D3DFMT_X8R8G8B8,
2610 .Pool = D3DPOOL_DEFAULT,
2611 .MinBuffers = 2,
2612 .szAspectRatio = {32, 16},
2613 .szNativeSize = {32, 16},
2615 IBaseFilter *filter = create_vmr9(VMR9Mode_Renderless);
2616 IVMRSurfaceAllocatorNotify9 *notify;
2617 IDirect3DSurface9 *surfaces[2] = {};
2618 IDirect3DDevice9 *device, *device2;
2619 RECT rect = {0, 0, 640, 480};
2620 IDirect3DTexture9 *container;
2621 D3DSURFACE_DESC desc;
2622 DWORD count;
2623 HWND window;
2624 HRESULT hr;
2625 ULONG ref;
2627 IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)&notify);
2629 count = 2;
2630 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2631 todo_wine ok(hr == E_FAIL, "Got hr %#x.\n", hr);
2633 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
2634 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0,
2635 rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, NULL, NULL);
2636 if (!(device = create_device(window)))
2637 goto out;
2639 hr = IVMRSurfaceAllocatorNotify9_SetD3DDevice(notify, device, MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY));
2640 if (hr == E_NOINTERFACE)
2642 win_skip("Direct3D does not support video rendering.\n");
2643 goto out;
2645 ok(hr == S_OK, "Got hr %#x.\n", hr);
2647 if (0) /* crashes on Windows */
2649 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, NULL, &count, surfaces);
2650 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
2652 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, NULL, surfaces);
2653 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
2656 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, NULL);
2657 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
2659 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2660 ok(hr == S_OK, "Got hr %#x.\n", hr);
2661 ok(count == 2, "Got count %u.\n", count);
2662 ok(!!surfaces[0], "Surface 0 was not allocated.\n");
2663 ok(!!surfaces[1], "Surface 1 was not allocated.\n");
2665 hr = IDirect3DSurface9_GetDevice(surfaces[0], &device2);
2666 ok(hr == D3D_OK, "Got hr %#x.\n", hr);
2667 ok(device2 == device, "Devices did not match.\n");
2668 IDirect3DDevice9_Release(device2);
2670 hr = IDirect3DSurface9_GetContainer(surfaces[0], &IID_IDirect3DTexture9, (void **)&container);
2671 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
2673 hr = IDirect3DSurface9_GetDesc(surfaces[0], &desc);
2674 ok(hr == D3D_OK, "Got hr %#x.\n", hr);
2675 ok(desc.Format == info.Format, "Got format %#x.\n", desc.Format);
2676 ok(desc.Type == D3DRTYPE_SURFACE, "Got type %u.\n", desc.Type);
2677 ok(!desc.Usage, "Got usage %#x.\n", desc.Usage);
2678 ok(desc.Pool == D3DPOOL_DEFAULT, "Got pool %u.\n", desc.Pool);
2679 ok(desc.MultiSampleType == D3DMULTISAMPLE_NONE, "Got multisample type %u.\n", desc.MultiSampleType);
2680 ok(!desc.MultiSampleQuality, "Got multisample quality %u.\n", desc.MultiSampleQuality);
2681 ok(desc.Width == 32, "Got width %u.\n", desc.Width);
2682 ok(desc.Height == 16, "Got height %u.\n", desc.Height);
2684 IDirect3DSurface9_Release(surfaces[0]);
2685 IDirect3DSurface9_Release(surfaces[1]);
2687 surfaces[0] = surfaces[1] = NULL;
2688 count = 1;
2689 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2690 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
2691 todo_wine ok(!count, "Got count %u.\n", count);
2692 ok(!surfaces[0], "Surface 0 was allocated.\n");
2693 ok(!surfaces[1], "Surface 1 was allocated.\n");
2695 count = 2;
2696 info.MinBuffers = 1;
2697 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2698 ok(hr == S_OK, "Got hr %#x.\n", hr);
2699 ok(count == 2, "Got count %u.\n", count);
2700 ok(!!surfaces[0], "Surface 0 was not allocated.\n");
2701 ok(!!surfaces[1], "Surface 1 was not allocated.\n");
2702 IDirect3DSurface9_Release(surfaces[0]);
2703 IDirect3DSurface9_Release(surfaces[1]);
2705 count = 2;
2706 info.dwFlags = VMR9AllocFlag_TextureSurface;
2707 surfaces[0] = surfaces[1] = NULL;
2708 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2709 ok(hr == S_OK, "Got hr %#x.\n", hr);
2710 ok(count == 2, "Got count %u.\n", count);
2711 ok(!!surfaces[0], "Surface 0 was not allocated.\n");
2712 ok(!!surfaces[1], "Surface 1 was not allocated.\n");
2714 hr = IDirect3DSurface9_GetDevice(surfaces[0], &device2);
2715 ok(hr == D3D_OK, "Got hr %#x.\n", hr);
2716 ok(device2 == device, "Devices did not match.\n");
2717 IDirect3DDevice9_Release(device2);
2719 hr = IDirect3DSurface9_GetContainer(surfaces[0], &IID_IDirect3DTexture9, (void **)&container);
2720 ok(hr == D3D_OK, "Got hr %#x.\n", hr);
2721 IDirect3DTexture9_Release(container);
2723 hr = IDirect3DSurface9_GetDesc(surfaces[1], &desc);
2724 ok(hr == D3D_OK, "Got hr %#x.\n", hr);
2725 ok(desc.Format == info.Format, "Got format %#x.\n", desc.Format);
2726 ok(desc.Type == D3DRTYPE_SURFACE, "Got type %u.\n", desc.Type);
2727 ok(desc.Usage == D3DUSAGE_DYNAMIC, "Got usage %#x.\n", desc.Usage);
2728 ok(desc.Pool == D3DPOOL_DEFAULT, "Got pool %u.\n", desc.Pool);
2729 ok(desc.MultiSampleType == D3DMULTISAMPLE_NONE, "Got multisample type %u.\n", desc.MultiSampleType);
2730 ok(!desc.MultiSampleQuality, "Got multisample quality %u.\n", desc.MultiSampleQuality);
2731 ok(desc.Width == 32, "Got width %u.\n", desc.Width);
2732 ok(desc.Height == 16, "Got height %u.\n", desc.Height);
2734 IDirect3DSurface9_Release(surfaces[0]);
2735 IDirect3DSurface9_Release(surfaces[1]);
2737 info.Format = D3DFMT_R8G8B8;
2738 surfaces[0] = surfaces[1] = NULL;
2739 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2740 ok(hr == D3DERR_INVALIDCALL, "Got hr %#x.\n", hr);
2741 ok(!count, "Got count %u.\n", count);
2742 ok(!surfaces[0], "Surface 0 was allocated.\n");
2743 ok(!surfaces[1], "Surface 1 was allocated.\n");
2745 info.Format = 0;
2746 info.dwFlags = VMR9AllocFlag_3DRenderTarget;
2747 count = 1;
2748 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2749 ok(hr == S_OK, "Got hr %#x.\n", hr);
2750 ok(count == 1, "Got count %u.\n", count);
2751 ok(!!surfaces[0], "Surface 0 was not allocated.\n");
2752 ok(info.Format != 0, "Expected a format.\n");
2754 hr = IDirect3DSurface9_GetDesc(surfaces[0], &desc);
2755 ok(hr == D3D_OK, "Got hr %#x.\n", hr);
2756 ok(desc.Format == info.Format, "Expected format %#x, got %#x.\n", info.Format, desc.Format);
2757 ok(desc.Type == D3DRTYPE_SURFACE, "Got type %u.\n", desc.Type);
2758 ok(desc.Usage == D3DUSAGE_RENDERTARGET, "Got usage %#x.\n", desc.Usage);
2759 ok(desc.Pool == D3DPOOL_DEFAULT, "Got pool %u.\n", desc.Pool);
2760 ok(desc.MultiSampleType == D3DMULTISAMPLE_NONE, "Got multisample type %u.\n", desc.MultiSampleType);
2761 ok(!desc.MultiSampleQuality, "Got multisample quality %u.\n", desc.MultiSampleQuality);
2762 ok(desc.Width == 32, "Got width %u.\n", desc.Width);
2763 ok(desc.Height == 16, "Got height %u.\n", desc.Height);
2765 IDirect3DSurface9_Release(surfaces[0]);
2767 out:
2768 IVMRSurfaceAllocatorNotify9_Release(notify);
2769 ref = IBaseFilter_Release(filter);
2770 ok(!ref, "Got outstanding refcount %d.\n", ref);
2771 ref = IDirect3DDevice9_Release(device);
2772 ok(!ref, "Got outstanding refcount %d.\n", ref);
2773 DestroyWindow(window);
2776 static IVMRSurfaceAllocator9 allocator_iface;
2777 static IVMRImagePresenter9 presenter_iface;
2778 static LONG allocator_refcount = 1;
2779 static D3DFORMAT allocator_format;
2780 static DWORD allocator_accept_flags;
2781 static IDirect3DSurface9 *allocator_surfaces[5];
2782 static IVMRSurfaceAllocatorNotify9 *allocator_notify;
2783 static unsigned int allocator_got_PresentImage, allocator_got_TerminateDevice;
2785 static HRESULT WINAPI presenter_QueryInterface(IVMRImagePresenter9 *iface, REFIID iid, void **out)
2787 return IVMRSurfaceAllocator9_QueryInterface(&allocator_iface, iid, out);
2790 static ULONG WINAPI presenter_AddRef(IVMRImagePresenter9 *iface)
2792 return IVMRSurfaceAllocator9_AddRef(&allocator_iface);
2795 static ULONG WINAPI presenter_Release(IVMRImagePresenter9 *iface)
2797 return IVMRSurfaceAllocator9_Release(&allocator_iface);
2800 static HRESULT WINAPI presenter_StartPresenting(IVMRImagePresenter9 *iface, DWORD_PTR cookie)
2802 if (winetest_debug > 1) trace("StartPresenting()\n");
2803 ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
2804 return E_NOTIMPL;
2807 static HRESULT WINAPI presenter_StopPresenting(IVMRImagePresenter9 *iface, DWORD_PTR cookie)
2809 if (winetest_debug > 1) trace("StopPresenting()\n");
2810 ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
2811 return E_NOTIMPL;
2814 static HRESULT WINAPI presenter_PresentImage(IVMRImagePresenter9 *iface, DWORD_PTR cookie, VMR9PresentationInfo *info)
2816 static const RECT rect;
2817 if (winetest_debug > 1) trace("PresentImage()\n");
2818 ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
2819 todo_wine ok(info->dwFlags == VMR9Sample_TimeValid, "Got flags %#x.\n", info->dwFlags);
2820 ok(!info->rtStart, "Got start time %s.\n", wine_dbgstr_longlong(info->rtStart));
2821 ok(info->rtEnd == 10000000, "Got end time %s.\n", wine_dbgstr_longlong(info->rtEnd));
2822 todo_wine ok(info->szAspectRatio.cx == 120, "Got aspect ratio width %d.\n", info->szAspectRatio.cx);
2823 todo_wine ok(info->szAspectRatio.cy == 60, "Got aspect ratio height %d.\n", info->szAspectRatio.cy);
2824 ok(EqualRect(&info->rcSrc, &rect), "Got source rect %s.\n", wine_dbgstr_rect(&info->rcSrc));
2825 ok(EqualRect(&info->rcDst, &rect), "Got dest rect %s.\n", wine_dbgstr_rect(&info->rcDst));
2826 ok(!info->dwReserved1, "Got dwReserved1 %#x.\n", info->dwReserved1);
2827 ok(!info->dwReserved2, "Got dwReserved2 %#x.\n", info->dwReserved2);
2829 ++allocator_got_PresentImage;
2830 return S_OK;
2833 static const IVMRImagePresenter9Vtbl presenter_vtbl =
2835 presenter_QueryInterface,
2836 presenter_AddRef,
2837 presenter_Release,
2838 presenter_StartPresenting,
2839 presenter_StopPresenting,
2840 presenter_PresentImage,
2843 static HRESULT WINAPI allocator_QueryInterface(IVMRSurfaceAllocator9 *iface, REFIID iid, void **out)
2845 if (winetest_debug > 1) trace("QueryInterface(%s)\n", wine_dbgstr_guid(iid));
2847 if (IsEqualGUID(iid, &IID_IVMRImagePresenter9))
2849 *out = &presenter_iface;
2850 IVMRImagePresenter9_AddRef(&presenter_iface);
2851 return S_OK;
2853 *out = NULL;
2854 return E_NOTIMPL;
2857 static ULONG WINAPI allocator_AddRef(IVMRSurfaceAllocator9 *iface)
2859 return InterlockedIncrement(&allocator_refcount);
2862 static ULONG WINAPI allocator_Release(IVMRSurfaceAllocator9 *iface)
2864 return InterlockedDecrement(&allocator_refcount);
2867 static HRESULT WINAPI allocator_InitializeDevice(IVMRSurfaceAllocator9 *iface,
2868 DWORD_PTR cookie, VMR9AllocationInfo *info, DWORD *buffer_count)
2870 if (winetest_debug > 1) trace("InitializeDevice(flags %#x, format %u)\n",
2871 info->dwFlags, info->Format);
2872 ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
2873 ok(info->dwWidth == 32, "Got width %u.\n", info->dwWidth);
2874 ok(info->dwHeight == 16, "Got height %u.\n", info->dwHeight);
2875 todo_wine ok(info->MinBuffers == 5, "Got buffer count %u.\n", info->MinBuffers);
2876 ok(info->Pool == D3DPOOL_DEFAULT, "Got pool %u\n", info->Pool);
2877 todo_wine ok(info->szAspectRatio.cx == 120, "Got aspect ratio width %d.\n", info->szAspectRatio.cx);
2878 todo_wine ok(info->szAspectRatio.cy == 60, "Got aspect ratio height %d.\n", info->szAspectRatio.cy);
2879 ok(info->szNativeSize.cx == 32, "Got native width %d.\n", info->szNativeSize.cx);
2880 ok(info->szNativeSize.cy == 16, "Got native height %d.\n", info->szNativeSize.cy);
2881 todo_wine ok(*buffer_count == 5, "Got buffer count %u.\n", *buffer_count);
2883 allocator_format = info->Format;
2885 if (info->dwFlags != allocator_accept_flags)
2886 return 0xdeadbeef;
2887 return IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(allocator_notify,
2888 info, buffer_count, allocator_surfaces);
2891 static HRESULT WINAPI allocator_TerminateDevice(IVMRSurfaceAllocator9 *iface, DWORD_PTR cookie)
2893 if (winetest_debug > 1) trace("TerminateDevice()\n");
2894 ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
2895 /* Don't dereference the surfaces here, to mimic How to Survive. */
2896 ++allocator_got_TerminateDevice;
2897 return E_NOTIMPL;
2900 static HRESULT WINAPI allocator_GetSurface(IVMRSurfaceAllocator9 *iface,
2901 DWORD_PTR cookie, DWORD index, DWORD flags, IDirect3DSurface9 **surface)
2903 if (winetest_debug > 1) trace("GetSurface(index %u)\n", index);
2904 ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
2905 ok(!flags, "Got flags %#x.\n", flags);
2906 ok(index < 5, "Got index %u.\n", index);
2908 /* Don't reference the surface here, to mimic How to Survive. */
2909 *surface = allocator_surfaces[index];
2910 return S_OK;
2913 static HRESULT WINAPI allocator_AdviseNotify(IVMRSurfaceAllocator9 *iface, IVMRSurfaceAllocatorNotify9 *notify)
2915 ok(0, "Unexpected call.\n");
2916 return E_NOTIMPL;
2919 static const IVMRSurfaceAllocator9Vtbl allocator_vtbl =
2921 allocator_QueryInterface,
2922 allocator_AddRef,
2923 allocator_Release,
2924 allocator_InitializeDevice,
2925 allocator_TerminateDevice,
2926 allocator_GetSurface,
2927 allocator_AdviseNotify,
2930 static IVMRSurfaceAllocator9 allocator_iface = {&allocator_vtbl};
2931 static IVMRImagePresenter9 presenter_iface = {&presenter_vtbl};
2933 static void test_renderless_present(IFilterGraph2 *graph, IMemInputPin *input)
2935 IMediaControl *control;
2936 OAFilterState state;
2937 HANDLE thread;
2938 HRESULT hr;
2940 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
2942 allocator_got_PresentImage = 0;
2944 hr = IMediaControl_Pause(control);
2945 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
2946 thread = send_frame(input);
2947 hr = IMediaControl_GetState(control, 1000, &state);
2948 ok(hr == S_OK, "Got hr %#x.\n", hr);
2950 hr = IMediaControl_Run(control);
2951 ok(hr == S_OK, "Got hr %#x.\n", hr);
2952 hr = join_thread(thread);
2953 ok(hr == S_OK, "Got hr %#x.\n", hr);
2954 ok(allocator_got_PresentImage == 1, "Got %u calls to PresentImage().\n", allocator_got_PresentImage);
2956 hr = IMediaControl_Stop(control);
2957 ok(hr == S_OK, "Got hr %#x.\n", hr);
2959 IMediaControl_Release(control);
2962 static void test_renderless_formats(void)
2964 VIDEOINFOHEADER vih =
2966 .rcSource = {4, 6, 16, 12},
2967 .rcTarget = {40, 60, 160, 120},
2968 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
2969 .bmiHeader.biWidth = 32,
2970 .bmiHeader.biHeight = 16,
2972 AM_MEDIA_TYPE req_mt =
2974 .majortype = MEDIATYPE_Video,
2975 .formattype = FORMAT_VideoInfo,
2976 .cbFormat = sizeof(vih),
2977 .pbFormat = (BYTE *)&vih,
2979 ALLOCATOR_PROPERTIES req_props = {5, 32 * 16 * 4, 1, 0}, ret_props;
2980 IBaseFilter *filter = create_vmr9(VMR9Mode_Renderless);
2981 IFilterGraph2 *graph = create_graph();
2982 IVMRSurfaceAllocatorNotify9 *notify;
2983 RECT rect = {0, 0, 640, 480};
2984 struct testfilter source;
2985 IDirect3DDevice9 *device;
2986 IMemAllocator *allocator;
2987 IMemInputPin *input;
2988 unsigned int i;
2989 HWND window;
2990 HRESULT hr;
2991 ULONG ref;
2992 IPin *pin;
2994 static const struct
2996 const GUID *subtype;
2997 D3DFORMAT format;
2998 DWORD flags;
3000 tests[] =
3002 {&MEDIASUBTYPE_ARGB1555, D3DFMT_A1R5G5B5, VMR9AllocFlag_TextureSurface},
3003 {&MEDIASUBTYPE_ARGB32, D3DFMT_A8R8G8B8, VMR9AllocFlag_TextureSurface},
3004 {&MEDIASUBTYPE_ARGB4444, D3DFMT_A4R4G4B4, VMR9AllocFlag_TextureSurface},
3006 {&MEDIASUBTYPE_RGB555, D3DFMT_X1R5G5B5, VMR9AllocFlag_OffscreenSurface},
3007 {&MEDIASUBTYPE_RGB555, D3DFMT_X1R5G5B5, VMR9AllocFlag_TextureSurface},
3008 {&MEDIASUBTYPE_RGB565, D3DFMT_R5G6B5, VMR9AllocFlag_OffscreenSurface},
3009 {&MEDIASUBTYPE_RGB565, D3DFMT_R5G6B5, VMR9AllocFlag_TextureSurface},
3010 {&MEDIASUBTYPE_RGB24, D3DFMT_R8G8B8, VMR9AllocFlag_OffscreenSurface},
3011 {&MEDIASUBTYPE_RGB24, D3DFMT_R8G8B8, VMR9AllocFlag_TextureSurface},
3012 {&MEDIASUBTYPE_RGB32, D3DFMT_X8R8G8B8, VMR9AllocFlag_OffscreenSurface},
3013 {&MEDIASUBTYPE_RGB32, D3DFMT_X8R8G8B8, VMR9AllocFlag_TextureSurface},
3015 {&MEDIASUBTYPE_NV12, MAKEFOURCC('N','V','1','2'), VMR9AllocFlag_OffscreenSurface},
3016 {&MEDIASUBTYPE_UYVY, D3DFMT_UYVY, VMR9AllocFlag_OffscreenSurface},
3017 {&MEDIASUBTYPE_YUY2, D3DFMT_YUY2, VMR9AllocFlag_OffscreenSurface},
3018 {&MEDIASUBTYPE_YV12, MAKEFOURCC('Y','V','1','2'), VMR9AllocFlag_OffscreenSurface},
3021 IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)&notify);
3023 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
3024 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0,
3025 rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, NULL, NULL);
3026 if (!(device = create_device(window)))
3027 goto out;
3029 hr = IVMRSurfaceAllocatorNotify9_SetD3DDevice(notify, device, MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY));
3030 if (hr == E_NOINTERFACE)
3032 win_skip("Direct3D does not support video rendering.\n");
3033 goto out;
3035 ok(hr == S_OK, "Got hr %#x.\n", hr);
3037 hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab, &allocator_iface);
3038 ok(hr == S_OK, "Got hr %#x.\n", hr);
3040 allocator_notify = notify;
3042 testfilter_init(&source);
3043 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL);
3044 IFilterGraph2_AddFilter(graph, filter, NULL);
3045 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
3046 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
3048 for (i = 0; i < ARRAY_SIZE(tests); ++i)
3050 req_mt.subtype = *tests[i].subtype;
3051 allocator_accept_flags = tests[i].flags;
3053 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
3054 /* Connection never fails on Native, but Wine currently creates D3D
3055 * surfaces during IPin::ReceiveConnection() instead of
3056 * IMemAllocator::SetProperties(), so let that fail here for now. */
3057 if (hr != S_OK)
3059 skip("Format %u (%#x), flags %#x are not supported, hr %#x.\n",
3060 tests[i].format, tests[i].format, tests[i].flags, hr);
3061 continue;
3063 ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3065 hr = IMemInputPin_GetAllocator(input, &allocator);
3066 todo_wine_if (i == 0) ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3067 if (hr != S_OK)
3069 test_allocator(input);
3070 hr = IMemInputPin_GetAllocator(input, &allocator);
3073 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
3074 if (hr != S_OK)
3076 skip("Format %u (%#x), flags %#x are not supported, hr %#x.\n",
3077 tests[i].format, tests[i].format, tests[i].flags, hr);
3078 IMemAllocator_Release(allocator);
3079 hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
3080 ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3081 hr = IFilterGraph2_Disconnect(graph, pin);
3082 ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3083 continue;
3085 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
3086 hr = IMemAllocator_Commit(allocator);
3087 ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3089 ok(allocator_format == tests[i].format, "Test %u: Got format %u (%#x).\n",
3090 i, allocator_format, allocator_format);
3092 test_renderless_present(graph, input);
3094 hr = IMemAllocator_Decommit(allocator);
3095 ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3096 IMemAllocator_Release(allocator);
3098 hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
3099 ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3100 hr = IFilterGraph2_Disconnect(graph, pin);
3101 ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3104 ref = IFilterGraph2_Release(graph);
3105 ok(!ref, "Got outstanding refcount %d.\n", ref);
3106 IMemInputPin_Release(input);
3107 IPin_Release(pin);
3109 out:
3110 IVMRSurfaceAllocatorNotify9_Release(notify);
3111 ref = IBaseFilter_Release(filter);
3112 ok(!ref, "Got outstanding refcount %d.\n", ref);
3113 ok(allocator_refcount == 1, "Got outstanding refcount %d.\n", allocator_refcount);
3114 ref = IDirect3DDevice9_Release(device);
3115 ok(!ref, "Got outstanding refcount %d.\n", ref);
3116 DestroyWindow(window);
3119 static void test_mixing_mode(void)
3121 IVMRWindowlessControl9 *windowless_control;
3122 IVMRMixerControl9 *mixer_control;
3123 IVMRFilterConfig9 *config;
3124 DWORD stream_count = 0;
3125 IBaseFilter *filter;
3126 unsigned int i;
3127 HWND window;
3128 HRESULT hr;
3129 ULONG ref;
3131 static const VMR9Mode modes[] =
3134 VMR9Mode_Windowed,
3135 VMR9Mode_Windowless,
3136 VMR9Mode_Renderless,
3139 for (i = 0; i < ARRAY_SIZE(modes); ++i)
3141 filter = create_vmr9(modes[i]);
3142 IBaseFilter_QueryInterface(filter, &IID_IVMRFilterConfig9, (void **)&config);
3144 hr = IBaseFilter_QueryInterface(filter, &IID_IVMRMixerControl9, (void **)&mixer_control);
3145 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
3147 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3148 todo_wine ok(hr == VFW_E_VMR_NOT_IN_MIXER_MODE, "Got hr %#x.\n", hr);
3150 hr = IVMRFilterConfig9_SetNumberOfStreams(config, 1);
3151 ok(hr == S_OK, "Got hr %#x.\n", hr);
3153 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3154 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
3155 todo_wine ok(stream_count == 1, "Got %u streams.\n", stream_count);
3157 hr = IBaseFilter_QueryInterface(filter, &IID_IVMRMixerControl9, (void **)&mixer_control);
3158 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
3159 if (hr == S_OK)
3160 IVMRMixerControl9_Release(mixer_control);
3162 hr = IVMRFilterConfig9_SetNumberOfStreams(config, 2);
3163 todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
3165 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3166 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
3167 todo_wine ok(stream_count == 1, "Got %u streams.\n", stream_count);
3169 IVMRFilterConfig9_Release(config);
3170 ref = IBaseFilter_Release(filter);
3171 ok(!ref, "Got outstanding refcount %d.\n", ref);
3174 filter = create_vmr9(VMR9Mode_Windowless);
3175 IBaseFilter_QueryInterface(filter, &IID_IVMRFilterConfig9, (void **)&config);
3176 IBaseFilter_QueryInterface(filter, &IID_IVMRWindowlessControl9, (void **)&windowless_control);
3178 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
3179 ok(!!window, "Failed to create a window.\n");
3180 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, window);
3181 ok(hr == S_OK, "Got hr %#x.\n", hr);
3183 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3184 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
3185 todo_wine ok(stream_count == 4, "Got %u streams.\n", stream_count);
3187 hr = IBaseFilter_QueryInterface(filter, &IID_IVMRMixerControl9, (void **)&mixer_control);
3188 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
3189 if (hr == S_OK)
3190 IVMRMixerControl9_Release(mixer_control);
3192 hr = IVMRFilterConfig9_SetNumberOfStreams(config, 2);
3193 todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
3195 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3196 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
3197 todo_wine ok(stream_count == 4, "Got %u streams.\n", stream_count);
3199 IVMRWindowlessControl9_Release(windowless_control);
3200 IVMRFilterConfig9_Release(config);
3201 ref = IBaseFilter_Release(filter);
3202 ok(!ref, "Got outstanding refcount %d.\n", ref);
3203 DestroyWindow(window);
3206 static void test_clipping_window(void)
3208 VIDEOINFOHEADER vih =
3210 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
3211 .bmiHeader.biWidth = 32,
3212 .bmiHeader.biHeight = 16,
3213 .bmiHeader.biBitCount = 32,
3215 AM_MEDIA_TYPE mt =
3217 .majortype = MEDIATYPE_Video,
3218 .subtype = MEDIASUBTYPE_RGB32,
3219 .formattype = FORMAT_VideoInfo,
3220 .cbFormat = sizeof(vih),
3221 .pbFormat = (BYTE *)&vih,
3223 IBaseFilter *filter = create_vmr9(VMR9Mode_Windowless);
3224 IVMRWindowlessControl9 *windowless_control;
3225 IFilterGraph2 *graph = create_graph();
3226 struct testfilter source;
3227 HWND window;
3228 HRESULT hr;
3229 ULONG ref;
3230 IPin *pin;
3232 IBaseFilter_QueryInterface(filter, &IID_IVMRWindowlessControl9, (void **)&windowless_control);
3233 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
3234 testfilter_init(&source);
3235 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, L"source");
3236 IFilterGraph2_AddFilter(graph, filter, L"vmr9");
3237 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
3238 ok(!!window, "Failed to create a window.\n");
3240 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, NULL);
3241 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3242 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, (HWND)0xdeadbeef);
3243 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3245 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &mt);
3246 ok(hr == S_OK, "Got hr %#x.\n", hr);
3248 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, window);
3249 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
3251 hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
3252 ok(hr == S_OK, "Got hr %#x.\n", hr);
3253 hr = IFilterGraph2_Disconnect(graph, pin);
3254 ok(hr == S_OK, "Got hr %#x.\n", hr);
3256 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, window);
3257 ok(hr == S_OK, "Got hr %#x.\n", hr);
3259 ref = IFilterGraph2_Release(graph);
3260 ok(!ref, "Got outstanding refcount %d.\n", ref);
3261 IPin_Release(pin);
3262 IVMRWindowlessControl9_Release(windowless_control);
3263 ref = IBaseFilter_Release(filter);
3264 ok(!ref, "Got outstanding refcount %d.\n", ref);
3265 DestroyWindow(window);
3268 static void test_surface_allocator_notify_refcount(void)
3270 IBaseFilter *filter = create_vmr9(VMR9Mode_Renderless);
3271 IVMRSurfaceAllocatorNotify9 *notify;
3272 HRESULT hr;
3273 ULONG ref;
3275 allocator_got_TerminateDevice = 0;
3277 set_mixing_mode(filter, 2);
3279 IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)&notify);
3281 hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab, &allocator_iface);
3282 ok(hr == S_OK, "Got hr %#x.\n", hr);
3284 ref = IBaseFilter_Release(filter);
3285 ok(!ref, "Got outstanding refcount %d.\n", ref);
3286 ok(allocator_got_TerminateDevice == 1, "Got %u calls to TerminateDevice().\n",
3287 allocator_got_TerminateDevice);
3288 ok(allocator_refcount == 1, "Got outstanding refcount %d.\n", allocator_refcount);
3290 ref = IVMRSurfaceAllocatorNotify9_Release(notify);
3291 ok(!ref, "Got outstanding refcount %d.\n", ref);
3294 static void check_source_position_(int line, IBasicVideo *video,
3295 LONG expect_left, LONG expect_top, LONG expect_width, LONG expect_height)
3297 LONG left, top, width, height, l;
3298 HRESULT hr;
3300 left = top = width = height = 0xdeadbeef;
3301 hr = IBasicVideo_GetSourcePosition(video, &left, &top, &width, &height);
3302 ok_(__FILE__,line)(hr == S_OK, "Got hr %#x.\n", hr);
3303 ok_(__FILE__,line)(left == expect_left, "Got left %d.\n", left);
3304 ok_(__FILE__,line)(top == expect_top, "Got top %d.\n", top);
3305 ok_(__FILE__,line)(width == expect_width, "Got width %d.\n", width);
3306 ok_(__FILE__,line)(height == expect_height, "Got height %d.\n", height);
3308 l = 0xdeadbeef;
3309 hr = IBasicVideo_get_SourceLeft(video, &l);
3310 ok_(__FILE__,line)(hr == S_OK, "Failed to get left, hr %#x.\n", hr);
3311 ok_(__FILE__,line)(l == left, "Got left %d.\n", l);
3313 l = 0xdeadbeef;
3314 hr = IBasicVideo_get_SourceTop(video, &l);
3315 ok_(__FILE__,line)(hr == S_OK, "Failed to get top, hr %#x.\n", hr);
3316 ok_(__FILE__,line)(l == top, "Got top %d.\n", l);
3318 l = 0xdeadbeef;
3319 hr = IBasicVideo_get_SourceWidth(video, &l);
3320 ok_(__FILE__,line)(hr == S_OK, "Failed to get width, hr %#x.\n", hr);
3321 ok_(__FILE__,line)(l == width, "Got width %d.\n", l);
3323 l = 0xdeadbeef;
3324 hr = IBasicVideo_get_SourceHeight(video, &l);
3325 ok_(__FILE__,line)(hr == S_OK, "Failed to get height, hr %#x.\n", hr);
3326 ok_(__FILE__,line)(l == height, "Got height %d.\n", l);
3328 #define check_source_position(a,b,c,d,e) check_source_position_(__LINE__,a,b,c,d,e)
3330 static void test_basic_video_source(IBasicVideo *video)
3332 HRESULT hr;
3334 check_source_position(video, 0, 0, 600, 400);
3335 hr = IBasicVideo_IsUsingDefaultSource(video);
3336 ok(hr == S_OK, "Got hr %#x.\n", hr);
3338 hr = IBasicVideo_put_SourceLeft(video, -10);
3339 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3340 hr = IBasicVideo_put_SourceLeft(video, 10);
3341 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3343 hr = IBasicVideo_put_SourceTop(video, -10);
3344 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3345 hr = IBasicVideo_put_SourceTop(video, 10);
3346 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3348 hr = IBasicVideo_put_SourceWidth(video, -500);
3349 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3350 hr = IBasicVideo_put_SourceWidth(video, 0);
3351 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3352 hr = IBasicVideo_put_SourceWidth(video, 700);
3353 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3354 hr = IBasicVideo_put_SourceWidth(video, 500);
3355 ok(hr == S_OK, "Got hr %#x.\n", hr);
3356 check_source_position(video, 0, 0, 500, 400);
3357 hr = IBasicVideo_IsUsingDefaultSource(video);
3358 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3360 hr = IBasicVideo_put_SourceHeight(video, -300);
3361 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3362 hr = IBasicVideo_put_SourceHeight(video, 0);
3363 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3364 hr = IBasicVideo_put_SourceHeight(video, 600);
3365 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3366 hr = IBasicVideo_put_SourceHeight(video, 300);
3367 ok(hr == S_OK, "Got hr %#x.\n", hr);
3368 check_source_position(video, 0, 0, 500, 300);
3369 hr = IBasicVideo_IsUsingDefaultSource(video);
3370 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3372 hr = IBasicVideo_put_SourceLeft(video, -10);
3373 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3374 hr = IBasicVideo_put_SourceLeft(video, 10);
3375 ok(hr == S_OK, "Got hr %#x.\n", hr);
3376 check_source_position(video, 10, 0, 500, 300);
3377 hr = IBasicVideo_IsUsingDefaultSource(video);
3378 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3380 hr = IBasicVideo_put_SourceTop(video, -10);
3381 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3382 hr = IBasicVideo_put_SourceTop(video, 20);
3383 ok(hr == S_OK, "Got hr %#x.\n", hr);
3384 check_source_position(video, 10, 20, 500, 300);
3385 hr = IBasicVideo_IsUsingDefaultSource(video);
3386 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3388 hr = IBasicVideo_SetSourcePosition(video, 4, 5, 60, 40);
3389 ok(hr == S_OK, "Got hr %#x.\n", hr);
3390 check_source_position(video, 4, 5, 60, 40);
3391 hr = IBasicVideo_IsUsingDefaultSource(video);
3392 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3394 hr = IBasicVideo_SetSourcePosition(video, 0, 0, 600, 400);
3395 ok(hr == S_OK, "Got hr %#x.\n", hr);
3396 check_source_position(video, 0, 0, 600, 400);
3397 hr = IBasicVideo_IsUsingDefaultSource(video);
3398 ok(hr == S_OK, "Got hr %#x.\n", hr);
3400 hr = IBasicVideo_SetSourcePosition(video, 4, 5, 60, 40);
3401 ok(hr == S_OK, "Got hr %#x.\n", hr);
3402 hr = IBasicVideo_SetDefaultSourcePosition(video);
3403 ok(hr == S_OK, "Got hr %#x.\n", hr);
3404 check_source_position(video, 0, 0, 600, 400);
3405 hr = IBasicVideo_IsUsingDefaultSource(video);
3406 ok(hr == S_OK, "Got hr %#x.\n", hr);
3409 static void check_destination_position_(int line, IBasicVideo *video,
3410 LONG expect_left, LONG expect_top, LONG expect_width, LONG expect_height)
3412 LONG left, top, width, height, l;
3413 HRESULT hr;
3415 left = top = width = height = 0xdeadbeef;
3416 hr = IBasicVideo_GetDestinationPosition(video, &left, &top, &width, &height);
3417 ok_(__FILE__,line)(hr == S_OK, "Failed to get position, hr %#x.\n", hr);
3418 ok_(__FILE__,line)(left == expect_left, "Got left %d.\n", left);
3419 ok_(__FILE__,line)(top == expect_top, "Got top %d.\n", top);
3420 ok_(__FILE__,line)(width == expect_width, "Got width %d.\n", width);
3421 ok_(__FILE__,line)(height == expect_height, "Got height %d.\n", height);
3423 l = 0xdeadbeef;
3424 hr = IBasicVideo_get_DestinationLeft(video, &l);
3425 ok_(__FILE__,line)(hr == S_OK, "Failed to get left, hr %#x.\n", hr);
3426 ok_(__FILE__,line)(l == left, "Got left %d.\n", l);
3428 l = 0xdeadbeef;
3429 hr = IBasicVideo_get_DestinationTop(video, &l);
3430 ok_(__FILE__,line)(hr == S_OK, "Failed to get top, hr %#x.\n", hr);
3431 ok_(__FILE__,line)(l == top, "Got top %d.\n", l);
3433 l = 0xdeadbeef;
3434 hr = IBasicVideo_get_DestinationWidth(video, &l);
3435 ok_(__FILE__,line)(hr == S_OK, "Failed to get width, hr %#x.\n", hr);
3436 ok_(__FILE__,line)(l == width, "Got width %d.\n", l);
3438 l = 0xdeadbeef;
3439 hr = IBasicVideo_get_DestinationHeight(video, &l);
3440 ok_(__FILE__,line)(hr == S_OK, "Failed to get height, hr %#x.\n", hr);
3441 ok_(__FILE__,line)(l == height, "Got height %d.\n", l);
3443 #define check_destination_position(a,b,c,d,e) check_destination_position_(__LINE__,a,b,c,d,e)
3445 static void test_basic_video_destination(IBasicVideo *video)
3447 IVideoWindow *window;
3448 HRESULT hr;
3449 RECT rect;
3451 IBasicVideo_QueryInterface(video, &IID_IVideoWindow, (void **)&window);
3453 check_destination_position(video, 0, 0, 600, 400);
3454 hr = IBasicVideo_IsUsingDefaultDestination(video);
3455 ok(hr == S_OK, "Got hr %#x.\n", hr);
3457 hr = IBasicVideo_put_DestinationLeft(video, -10);
3458 ok(hr == S_OK, "Got hr %#x.\n", hr);
3459 check_destination_position(video, -10, 0, 600, 400);
3460 hr = IBasicVideo_IsUsingDefaultDestination(video);
3461 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3463 hr = IBasicVideo_put_DestinationLeft(video, 10);
3464 ok(hr == S_OK, "Got hr %#x.\n", hr);
3465 check_destination_position(video, 10, 0, 600, 400);
3466 hr = IBasicVideo_IsUsingDefaultDestination(video);
3467 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3469 hr = IBasicVideo_put_DestinationTop(video, -20);
3470 ok(hr == S_OK, "Got hr %#x.\n", hr);
3471 check_destination_position(video, 10, -20, 600, 400);
3472 hr = IBasicVideo_IsUsingDefaultDestination(video);
3473 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3475 hr = IBasicVideo_put_DestinationTop(video, 20);
3476 ok(hr == S_OK, "Got hr %#x.\n", hr);
3477 check_destination_position(video, 10, 20, 600, 400);
3478 hr = IBasicVideo_IsUsingDefaultDestination(video);
3479 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3481 hr = IBasicVideo_put_DestinationWidth(video, -700);
3482 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3483 hr = IBasicVideo_put_DestinationWidth(video, 0);
3484 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3485 hr = IBasicVideo_put_DestinationWidth(video, 700);
3486 ok(hr == S_OK, "Got hr %#x.\n", hr);
3487 check_destination_position(video, 10, 20, 700, 400);
3488 hr = IBasicVideo_IsUsingDefaultDestination(video);
3489 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3491 hr = IBasicVideo_put_DestinationWidth(video, 500);
3492 ok(hr == S_OK, "Got hr %#x.\n", hr);
3493 check_destination_position(video, 10, 20, 500, 400);
3494 hr = IBasicVideo_IsUsingDefaultDestination(video);
3495 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3497 hr = IBasicVideo_put_DestinationHeight(video, -500);
3498 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3499 hr = IBasicVideo_put_DestinationHeight(video, 0);
3500 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3501 hr = IBasicVideo_put_DestinationHeight(video, 500);
3502 ok(hr == S_OK, "Got hr %#x.\n", hr);
3503 check_destination_position(video, 10, 20, 500, 500);
3504 hr = IBasicVideo_IsUsingDefaultDestination(video);
3505 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3507 hr = IBasicVideo_put_DestinationHeight(video, 300);
3508 ok(hr == S_OK, "Got hr %#x.\n", hr);
3509 check_destination_position(video, 10, 20, 500, 300);
3510 hr = IBasicVideo_IsUsingDefaultDestination(video);
3511 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3513 hr = IBasicVideo_SetDestinationPosition(video, 4, 5, 60, 40);
3514 ok(hr == S_OK, "Got hr %#x.\n", hr);
3515 check_destination_position(video, 4, 5, 60, 40);
3516 hr = IBasicVideo_IsUsingDefaultDestination(video);
3517 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3519 hr = IBasicVideo_SetDestinationPosition(video, 0, 0, 600, 400);
3520 ok(hr == S_OK, "Got hr %#x.\n", hr);
3521 check_destination_position(video, 0, 0, 600, 400);
3522 hr = IBasicVideo_IsUsingDefaultDestination(video);
3523 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3525 hr = IBasicVideo_SetDestinationPosition(video, 4, 5, 60, 40);
3526 ok(hr == S_OK, "Got hr %#x.\n", hr);
3527 hr = IBasicVideo_SetDefaultDestinationPosition(video);
3528 ok(hr == S_OK, "Got hr %#x.\n", hr);
3529 check_destination_position(video, 0, 0, 600, 400);
3530 hr = IBasicVideo_IsUsingDefaultDestination(video);
3531 ok(hr == S_OK, "Got hr %#x.\n", hr);
3533 SetRect(&rect, 100, 200, 500, 500);
3534 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
3535 hr = IVideoWindow_SetWindowPosition(window, rect.left, rect.top,
3536 rect.right - rect.left, rect.bottom - rect.top);
3537 ok(hr == S_OK, "Got hr %#x.\n", hr);
3538 check_destination_position(video, 0, 0, 400, 300);
3539 hr = IBasicVideo_IsUsingDefaultDestination(video);
3540 ok(hr == S_OK, "Got hr %#x.\n", hr);
3542 hr = IBasicVideo_SetDestinationPosition(video, 0, 0, 400, 300);
3543 ok(hr == S_OK, "Got hr %#x.\n", hr);
3544 check_destination_position(video, 0, 0, 400, 300);
3545 hr = IBasicVideo_IsUsingDefaultDestination(video);
3546 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3548 SetRect(&rect, 100, 200, 600, 600);
3549 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
3550 hr = IVideoWindow_SetWindowPosition(window, rect.left, rect.top,
3551 rect.right - rect.left, rect.bottom - rect.top);
3552 ok(hr == S_OK, "Got hr %#x.\n", hr);
3553 check_destination_position(video, 0, 0, 400, 300);
3554 hr = IBasicVideo_IsUsingDefaultDestination(video);
3555 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3557 IVideoWindow_Release(window);
3560 static void test_basic_video(void)
3562 ALLOCATOR_PROPERTIES req_props = {1, 600 * 400 * 4, 1, 0}, ret_props;
3563 VIDEOINFOHEADER vih =
3565 .AvgTimePerFrame = 200000,
3566 .rcSource = {4, 6, 16, 12},
3567 .rcTarget = {40, 60, 120, 160},
3568 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
3569 .bmiHeader.biBitCount = 32,
3570 .bmiHeader.biWidth = 600,
3571 .bmiHeader.biHeight = 400,
3572 .bmiHeader.biPlanes = 1,
3573 .bmiHeader.biCompression = BI_RGB,
3575 AM_MEDIA_TYPE req_mt =
3577 .majortype = MEDIATYPE_Video,
3578 .subtype = MEDIASUBTYPE_RGB32,
3579 .formattype = FORMAT_VideoInfo,
3580 .cbFormat = sizeof(vih),
3581 .pbFormat = (BYTE *)&vih,
3583 IBaseFilter *filter = create_vmr9(VMR9Mode_Windowed);
3584 IFilterGraph2 *graph = create_graph();
3585 LONG left, top, width, height, l;
3586 struct testfilter source;
3587 IMemAllocator *allocator;
3588 IMemInputPin *input;
3589 ITypeInfo *typeinfo;
3590 IBasicVideo *video;
3591 TYPEATTR *typeattr;
3592 REFTIME reftime;
3593 HRESULT hr;
3594 UINT count;
3595 ULONG ref;
3596 IPin *pin;
3598 IBaseFilter_QueryInterface(filter, &IID_IBasicVideo, (void **)&video);
3599 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
3600 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
3602 hr = IBasicVideo_GetTypeInfoCount(video, &count);
3603 ok(hr == S_OK, "Got hr %#x.\n", hr);
3604 ok(count == 1, "Got count %u.\n", count);
3606 hr = IBasicVideo_GetTypeInfo(video, 0, 0, &typeinfo);
3607 ok(hr == S_OK, "Got hr %#x.\n", hr);
3608 hr = ITypeInfo_GetTypeAttr(typeinfo, &typeattr);
3609 ok(hr == S_OK, "Got hr %#x.\n", hr);
3610 ok(typeattr->typekind == TKIND_DISPATCH, "Got kind %u.\n", typeattr->typekind);
3611 ok(IsEqualGUID(&typeattr->guid, &IID_IBasicVideo), "Got IID %s.\n", wine_dbgstr_guid(&typeattr->guid));
3612 ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr);
3613 ITypeInfo_Release(typeinfo);
3615 hr = IBasicVideo_get_AvgTimePerFrame(video, NULL);
3616 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3617 hr = IBasicVideo_get_AvgTimePerFrame(video, &reftime);
3618 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
3620 hr = IBasicVideo_get_BitRate(video, NULL);
3621 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3622 hr = IBasicVideo_get_BitRate(video, &l);
3623 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
3625 hr = IBasicVideo_get_BitErrorRate(video, NULL);
3626 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3627 hr = IBasicVideo_get_BitErrorRate(video, &l);
3628 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
3630 hr = IBasicVideo_get_VideoWidth(video, NULL);
3631 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3632 hr = IBasicVideo_get_VideoHeight(video, NULL);
3633 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3635 hr = IBasicVideo_get_SourceLeft(video, NULL);
3636 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3637 hr = IBasicVideo_get_SourceWidth(video, NULL);
3638 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3639 hr = IBasicVideo_get_SourceTop(video, NULL);
3640 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3641 hr = IBasicVideo_get_SourceHeight(video, NULL);
3642 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3644 hr = IBasicVideo_get_DestinationLeft(video, NULL);
3645 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3646 hr = IBasicVideo_get_DestinationWidth(video, NULL);
3647 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3648 hr = IBasicVideo_get_DestinationTop(video, NULL);
3649 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3650 hr = IBasicVideo_get_DestinationHeight(video, NULL);
3651 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3653 hr = IBasicVideo_GetSourcePosition(video, NULL, &top, &width, &height);
3654 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3655 hr = IBasicVideo_GetSourcePosition(video, &left, NULL, &width, &height);
3656 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3657 hr = IBasicVideo_GetSourcePosition(video, &left, &top, NULL, &height);
3658 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3659 hr = IBasicVideo_GetSourcePosition(video, &left, &top, &width, NULL);
3660 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3662 hr = IBasicVideo_GetDestinationPosition(video, NULL, &top, &width, &height);
3663 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3664 hr = IBasicVideo_GetDestinationPosition(video, &left, NULL, &width, &height);
3665 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3666 hr = IBasicVideo_GetDestinationPosition(video, &left, &top, NULL, &height);
3667 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3668 hr = IBasicVideo_GetDestinationPosition(video, &left, &top, &width, NULL);
3669 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3671 hr = IBasicVideo_GetVideoSize(video, &width, NULL);
3672 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3673 hr = IBasicVideo_GetVideoSize(video, NULL, &height);
3674 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3676 hr = IBasicVideo_GetVideoPaletteEntries(video, 0, 1, NULL, &l);
3677 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3678 hr = IBasicVideo_GetVideoPaletteEntries(video, 0, 1, &l, NULL);
3679 todo_wine ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
3681 testfilter_init(&source);
3682 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, L"vmr9");
3683 IFilterGraph2_AddFilter(graph, filter, L"source");
3684 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
3685 if (hr == E_FAIL)
3687 skip("Got E_FAIL when connecting.\n");
3688 goto out;
3690 ok(hr == S_OK, "Got hr %#x.\n", hr);
3692 hr = IMemInputPin_GetAllocator(input, &allocator);
3693 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
3694 if (hr == S_OK)
3696 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
3697 ok(hr == S_OK, "Got hr %#x.\n", hr);
3698 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
3699 hr = IMemAllocator_Commit(allocator);
3700 ok(hr == S_OK, "Got hr %#x.\n", hr);
3701 IMemAllocator_Release(allocator);
3704 reftime = 0.0;
3705 hr = IBasicVideo_get_AvgTimePerFrame(video, &reftime);
3706 ok(hr == S_OK, "Got hr %#x.\n", hr);
3707 todo_wine ok(compare_double(reftime, 0.02, 1 << 28), "Got frame rate %.16e.\n", reftime);
3709 l = 0xdeadbeef;
3710 hr = IBasicVideo_get_BitRate(video, &l);
3711 ok(hr == S_OK, "Got hr %#x.\n", hr);
3712 ok(!l, "Got bit rate %d.\n", l);
3714 l = 0xdeadbeef;
3715 hr = IBasicVideo_get_BitErrorRate(video, &l);
3716 ok(hr == S_OK, "Got hr %#x.\n", hr);
3717 ok(!l, "Got bit rate %d.\n", l);
3719 hr = IBasicVideo_GetVideoPaletteEntries(video, 0, 1, &l, NULL);
3720 todo_wine ok(hr == VFW_E_NO_PALETTE_AVAILABLE, "Got hr %#x.\n", hr);
3722 width = height = 0xdeadbeef;
3723 hr = IBasicVideo_GetVideoSize(video, &width, &height);
3724 ok(hr == S_OK, "Got hr %#x.\n", hr);
3725 ok(width == 600, "Got width %d.\n", width);
3726 ok(height == 400, "Got height %d.\n", height);
3728 test_basic_video_source(video);
3729 test_basic_video_destination(video);
3731 out:
3732 ref = IFilterGraph2_Release(graph);
3733 ok(!ref, "Got outstanding refcount %d.\n", ref);
3734 IBasicVideo_Release(video);
3735 IMemInputPin_Release(input);
3736 IPin_Release(pin);
3737 ref = IBaseFilter_Release(filter);
3738 ok(!ref, "Got outstanding refcount %d.\n", ref);
3739 ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface);
3740 ok(!ref, "Got outstanding refcount %d.\n", ref);
3743 static void test_windowless_size(void)
3745 ALLOCATOR_PROPERTIES req_props = {1, 32 * 16 * 4, 1, 0}, ret_props;
3746 VIDEOINFOHEADER vih =
3748 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
3749 .bmiHeader.biWidth = 32,
3750 .bmiHeader.biHeight = 16,
3751 .bmiHeader.biBitCount = 32,
3752 .bmiHeader.biPlanes = 1,
3754 AM_MEDIA_TYPE mt =
3756 .majortype = MEDIATYPE_Video,
3757 .subtype = MEDIASUBTYPE_RGB32,
3758 .formattype = FORMAT_VideoInfo,
3759 .cbFormat = sizeof(vih),
3760 .pbFormat = (BYTE *)&vih,
3762 IBaseFilter *filter = create_vmr9(VMR9Mode_Windowless);
3763 LONG width, height, aspect_width, aspect_height;
3764 IVMRWindowlessControl9 *windowless_control;
3765 IFilterGraph2 *graph = create_graph();
3766 struct testfilter source;
3767 IMemAllocator *allocator;
3768 RECT src, dst, expect;
3769 IMemInputPin *input;
3770 HWND window;
3771 HRESULT hr;
3772 ULONG ref;
3773 IPin *pin;
3775 IBaseFilter_QueryInterface(filter, &IID_IVMRWindowlessControl9, (void **)&windowless_control);
3776 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
3777 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
3778 testfilter_init(&source);
3779 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, L"source");
3780 IFilterGraph2_AddFilter(graph, filter, L"vmr9");
3781 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
3782 ok(!!window, "Failed to create a window.\n");
3784 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, window);
3785 ok(hr == S_OK, "Got hr %#x.\n", hr);
3787 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &mt);
3788 ok(hr == S_OK, "Got hr %#x.\n", hr);
3789 hr = IMemInputPin_GetAllocator(input, &allocator);
3790 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
3791 if (hr == S_OK)
3793 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
3794 IMemAllocator_Release(allocator);
3795 if (hr == E_FAIL)
3797 skip("Got E_FAIL when setting allocator properties.\n");
3798 goto out;
3800 ok(hr == S_OK, "Got hr %#x.\n", hr);
3801 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
3804 hr = IVMRWindowlessControl9_GetNativeVideoSize(windowless_control, NULL, &height, &aspect_width, &aspect_height);
3805 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3806 hr = IVMRWindowlessControl9_GetNativeVideoSize(windowless_control, &width, NULL, &aspect_width, &aspect_height);
3807 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3809 width = height = 0xdeadbeef;
3810 hr = IVMRWindowlessControl9_GetNativeVideoSize(windowless_control, &width, &height, NULL, NULL);
3811 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
3812 todo_wine ok(width == 32, "Got width %d.\n", width);
3813 todo_wine ok(height == 16, "Got height %d.\n", height);
3815 aspect_width = aspect_height = 0xdeadbeef;
3816 hr = IVMRWindowlessControl9_GetNativeVideoSize(windowless_control, &width, &height, &aspect_width, &aspect_height);
3817 ok(hr == S_OK, "Got hr %#x.\n", hr);
3818 ok(aspect_width == 32, "Got width %d.\n", aspect_width);
3819 ok(aspect_height == 16, "Got height %d.\n", aspect_height);
3821 memset(&src, 0xcc, sizeof(src));
3822 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, &src, NULL);
3823 ok(hr == S_OK, "Got hr %#x.\n", hr);
3824 SetRect(&expect, 0, 0, 32, 16);
3825 ok(EqualRect(&src, &expect), "Got source rect %s.\n", wine_dbgstr_rect(&src));
3827 memset(&dst, 0xcc, sizeof(dst));
3828 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, NULL, &dst);
3829 ok(hr == S_OK, "Got hr %#x.\n", hr);
3830 SetRect(&expect, 0, 0, 0, 0);
3831 todo_wine ok(EqualRect(&dst, &expect), "Got dest rect %s.\n", wine_dbgstr_rect(&dst));
3833 SetRect(&src, 4, 6, 16, 12);
3834 hr = IVMRWindowlessControl9_SetVideoPosition(windowless_control, &src, NULL);
3835 ok(hr == S_OK, "Got hr %#x.\n", hr);
3837 memset(&src, 0xcc, sizeof(src));
3838 memset(&dst, 0xcc, sizeof(dst));
3839 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, &src, &dst);
3840 ok(hr == S_OK, "Got hr %#x.\n", hr);
3841 SetRect(&expect, 4, 6, 16, 12);
3842 ok(EqualRect(&src, &expect), "Got source rect %s.\n", wine_dbgstr_rect(&src));
3843 SetRect(&expect, 0, 0, 0, 0);
3844 todo_wine ok(EqualRect(&dst, &expect), "Got dest rect %s.\n", wine_dbgstr_rect(&dst));
3846 SetRect(&dst, 40, 60, 120, 160);
3847 hr = IVMRWindowlessControl9_SetVideoPosition(windowless_control, NULL, &dst);
3848 ok(hr == S_OK, "Got hr %#x.\n", hr);
3850 memset(&src, 0xcc, sizeof(src));
3851 memset(&dst, 0xcc, sizeof(dst));
3852 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, &src, &dst);
3853 ok(hr == S_OK, "Got hr %#x.\n", hr);
3854 SetRect(&expect, 4, 6, 16, 12);
3855 ok(EqualRect(&src, &expect), "Got source rect %s.\n", wine_dbgstr_rect(&src));
3856 SetRect(&expect, 40, 60, 120, 160);
3857 todo_wine ok(EqualRect(&dst, &expect), "Got dest rect %s.\n", wine_dbgstr_rect(&dst));
3859 GetWindowRect(window, &src);
3860 SetRect(&expect, 0, 0, 640, 480);
3861 ok(EqualRect(&src, &expect), "Got window rect %s.\n", wine_dbgstr_rect(&src));
3863 out:
3864 ref = IFilterGraph2_Release(graph);
3865 ok(!ref, "Got outstanding refcount %d.\n", ref);
3866 IMemInputPin_Release(input);
3867 IPin_Release(pin);
3868 IVMRWindowlessControl9_Release(windowless_control);
3869 ref = IBaseFilter_Release(filter);
3870 ok(!ref, "Got outstanding refcount %d.\n", ref);
3871 DestroyWindow(window);
3874 START_TEST(vmr9)
3876 IBaseFilter *filter;
3877 HRESULT hr;
3879 CoInitialize(NULL);
3881 if (FAILED(hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL,
3882 CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void **)&filter)))
3884 skip("Failed to create VMR9, hr %#x.\n", hr);
3885 return;
3887 IBaseFilter_Release(filter);
3889 test_filter_config();
3890 test_interfaces();
3891 test_aggregation();
3892 test_enum_pins();
3893 test_find_pin();
3894 test_pin_info();
3895 test_media_types();
3896 test_enum_media_types();
3897 test_unconnected_filter_state();
3898 test_connect_pin();
3899 test_overlay();
3900 test_video_window();
3901 test_allocate_surface_helper();
3902 test_renderless_formats();
3903 test_mixing_mode();
3904 test_clipping_window();
3905 test_surface_allocator_notify_refcount();
3906 test_basic_video();
3907 test_windowless_size();
3909 CoUninitialize();