quartz/tests: Test (dis)connecting while not stopped.
[wine.git] / dlls / quartz / tests / vmr9.c
blobf88c43b07b54d60ee3016a21bb63bd083ee135d4
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 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 uint64_t x = *(ULONGLONG *)&f;
77 uint64_t y = *(ULONGLONG *)&g;
79 if (f < 0)
80 x = ~x + 1;
81 else
82 x |= ((ULONGLONG)1)<<63;
83 if (g < 0)
84 y = ~y + 1;
85 else
86 y |= ((ULONGLONG)1)<<63;
88 return (x>y ? x-y : y-x) <= ulps;
91 static IFilterGraph2 *create_graph(void)
93 IFilterGraph2 *ret;
94 HRESULT hr;
95 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (void **)&ret);
96 ok(hr == S_OK, "Failed to create FilterGraph: %#x\n", hr);
97 return ret;
100 static ULONG get_refcount(void *iface)
102 IUnknown *unknown = iface;
103 IUnknown_AddRef(unknown);
104 return IUnknown_Release(unknown);
107 static void test_filter_config(void)
109 IVMRFilterConfig9 *config;
110 DWORD count, mode;
111 HRESULT hr;
112 ULONG ref;
114 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
115 &IID_IVMRFilterConfig9, (void **)&config);
116 ok(hr == S_OK, "Got hr %#x.\n", hr);
118 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
119 ok(hr == S_OK, "Got hr %#x.\n", hr);
120 ok(mode == VMRMode_Windowed, "Got mode %#x.\n", mode);
122 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowed);
123 ok(hr == S_OK || broken(hr == E_FAIL), "Got hr %#x.\n", hr);
125 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
126 ok(hr == S_OK, "Got hr %#x.\n", hr);
127 ok(mode == VMR9Mode_Windowed, "Got mode %#x.\n", mode);
129 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowed);
130 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
132 ref = IVMRFilterConfig9_Release(config);
133 ok(!ref, "Got outstanding refcount %d.\n", ref);
135 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
136 &IID_IVMRFilterConfig9, (void **)&config);
137 ok(hr == S_OK, "Got hr %#x.\n", hr);
139 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowless);
140 ok(hr == S_OK || broken(hr == E_FAIL), "Got hr %#x.\n", hr);
142 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
143 ok(hr == S_OK, "Got hr %#x.\n", hr);
144 ok(mode == VMR9Mode_Windowless, "Got mode %#x.\n", mode);
146 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowed);
147 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
149 ref = IVMRFilterConfig9_Release(config);
150 ok(!ref, "Got outstanding refcount %d.\n", ref);
152 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
153 &IID_IVMRFilterConfig9, (void **)&config);
154 ok(hr == S_OK, "Got hr %#x.\n", hr);
156 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Renderless);
157 ok(hr == S_OK, "Got hr %#x.\n", hr);
159 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
160 ok(hr == S_OK, "Got hr %#x.\n", hr);
161 ok(mode == VMR9Mode_Renderless, "Got mode %#x.\n", mode);
163 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowless);
164 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
166 ref = IVMRFilterConfig9_Release(config);
167 ok(!ref, "Got outstanding refcount %d.\n", ref);
169 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
170 &IID_IVMRFilterConfig9, (void **)&config);
171 ok(hr == S_OK, "Got hr %#x.\n", hr);
173 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &count);
174 ok(hr == VFW_E_VMR_NOT_IN_MIXER_MODE, "Got hr %#x.\n", hr);
176 hr = IVMRFilterConfig9_SetNumberOfStreams(config, 3);
177 ok(hr == S_OK, "Got hr %#x.\n", hr);
179 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &count);
180 ok(hr == S_OK, "Got hr %#x.\n", hr);
181 ok(count == 3, "Got count %u.\n", count);
183 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
184 ok(hr == S_OK, "Got hr %#x.\n", hr);
185 ok(mode == VMR9Mode_Windowed, "Got mode %#x.\n", mode);
187 /* Despite MSDN, you can still change the rendering mode after setting the
188 * stream count. */
189 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowless);
190 ok(hr == S_OK || broken(hr == E_FAIL), "Got hr %#x.\n", hr);
192 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
193 ok(hr == S_OK, "Got hr %#x.\n", hr);
194 ok(mode == VMR9Mode_Windowless, "Got mode %#x.\n", mode);
196 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &count);
197 ok(hr == S_OK, "Got hr %#x.\n", hr);
198 ok(count == 3, "Got count %u.\n", count);
200 ref = IVMRFilterConfig9_Release(config);
201 ok(!ref, "Got outstanding refcount %d.\n", ref);
204 #define check_interface_broken(a, b, c) check_interface_(__LINE__, a, b, c, TRUE)
205 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c, FALSE)
206 static HRESULT check_interface_(unsigned int line, void *iface, REFIID riid, BOOL supported, BOOL is_broken)
208 HRESULT hr, expected_hr, broken_hr;
209 IUnknown *unknown = iface, *out;
211 if (supported)
213 expected_hr = S_OK;
214 broken_hr = E_NOINTERFACE;
216 else
218 expected_hr = E_NOINTERFACE;
219 broken_hr = S_OK;
222 hr = IUnknown_QueryInterface(unknown, riid, (void **)&out);
223 ok_(__FILE__, line)(hr == expected_hr || broken(is_broken && hr == broken_hr),
224 "Got hr %#x, expected %#x.\n", hr, expected_hr);
225 if (SUCCEEDED(hr))
226 IUnknown_Release(out);
227 return hr;
230 static void test_common_interfaces(IBaseFilter *filter)
232 IPin *pin;
234 check_interface(filter, &IID_IAMCertifiedOutputProtection, TRUE);
235 check_interface(filter, &IID_IAMFilterMiscFlags, TRUE);
236 check_interface(filter, &IID_IBaseFilter, TRUE);
237 todo_wine check_interface(filter, &IID_IKsPropertySet, TRUE);
238 check_interface(filter, &IID_IMediaFilter, TRUE);
239 check_interface(filter, &IID_IMediaPosition, TRUE);
240 check_interface(filter, &IID_IMediaSeeking, TRUE);
241 check_interface(filter, &IID_IPersist, TRUE);
242 check_interface(filter, &IID_IQualityControl, TRUE);
243 todo_wine check_interface(filter, &IID_IQualProp, TRUE);
244 check_interface(filter, &IID_IUnknown, TRUE);
245 check_interface(filter, &IID_IVMRAspectRatioControl9, TRUE);
246 todo_wine check_interface(filter, &IID_IVMRDeinterlaceControl9, TRUE);
247 check_interface(filter, &IID_IVMRFilterConfig9, TRUE);
248 check_interface(filter, &IID_IVMRMixerBitmap9, TRUE);
250 check_interface(filter, &IID_IBasicAudio, FALSE);
251 check_interface(filter, &IID_IDirectDrawVideo, FALSE);
252 check_interface(filter, &IID_IPersistPropertyBag, FALSE);
253 check_interface(filter, &IID_IPin, FALSE);
254 check_interface(filter, &IID_IReferenceClock, FALSE);
255 check_interface(filter, &IID_IVMRAspectRatioControl, FALSE);
256 check_interface(filter, &IID_IVMRDeinterlaceControl, FALSE);
257 check_interface(filter, &IID_IVMRFilterConfig, FALSE);
258 check_interface(filter, &IID_IVMRMixerBitmap, FALSE);
259 check_interface(filter, &IID_IVMRMixerControl, FALSE);
260 check_interface(filter, &IID_IVMRMonitorConfig, FALSE);
261 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify, FALSE);
262 check_interface(filter, &IID_IVMRWindowlessControl, FALSE);
264 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
266 check_interface(pin, &IID_IMemInputPin, TRUE);
267 check_interface(pin, &IID_IOverlay, TRUE);
268 check_interface(pin, &IID_IPin, TRUE);
269 todo_wine check_interface(pin, &IID_IQualityControl, TRUE);
270 check_interface(pin, &IID_IUnknown, TRUE);
272 check_interface(pin, &IID_IKsPropertySet, FALSE);
273 check_interface(pin, &IID_IMediaPosition, FALSE);
274 check_interface(pin, &IID_IMediaSeeking, FALSE);
276 IPin_Release(pin);
279 static void test_interfaces(void)
281 IBaseFilter *filter = create_vmr9(0);
282 ULONG ref;
284 test_common_interfaces(filter);
286 check_interface(filter, &IID_IBasicVideo, TRUE);
287 todo_wine check_interface(filter, &IID_IBasicVideo2, TRUE);
288 check_interface(filter, &IID_IVideoWindow, TRUE);
289 /* IVMRMonitorConfig9 may not be available if the d3d9 device has
290 * insufficient support. */
291 check_interface_broken(filter, &IID_IVMRMonitorConfig9, TRUE);
293 check_interface(filter, &IID_IVMRMixerControl9, FALSE);
294 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify9, FALSE);
295 check_interface(filter, &IID_IVMRWindowlessControl9, FALSE);
297 ref = IBaseFilter_Release(filter);
298 ok(!ref, "Got outstanding refcount %d.\n", ref);
300 filter = create_vmr9(VMR9Mode_Windowless);
301 test_common_interfaces(filter);
303 /* IVMRMonitorConfig9 may not be available if the d3d9 device has
304 * insufficient support. */
305 check_interface_broken(filter, &IID_IVMRMonitorConfig9, TRUE);
306 check_interface(filter, &IID_IVMRWindowlessControl9, TRUE);
308 todo_wine check_interface(filter, &IID_IBasicVideo, FALSE);
309 check_interface(filter, &IID_IBasicVideo2, FALSE);
310 todo_wine check_interface(filter, &IID_IVideoWindow, FALSE);
311 check_interface(filter, &IID_IVMRMixerControl9, FALSE);
312 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify9, FALSE);
314 ref = IBaseFilter_Release(filter);
315 ok(!ref, "Got outstanding refcount %d.\n", ref);
317 filter = create_vmr9(VMR9Mode_Renderless);
318 test_common_interfaces(filter);
320 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify9, TRUE);
322 todo_wine check_interface(filter, &IID_IBasicVideo, FALSE);
323 check_interface(filter, &IID_IBasicVideo2, FALSE);
324 todo_wine check_interface(filter, &IID_IVideoWindow, FALSE);
325 check_interface(filter, &IID_IVMRMonitorConfig9, FALSE);
326 check_interface(filter, &IID_IVMRWindowlessControl9, FALSE);
328 ref = IBaseFilter_Release(filter);
329 ok(!ref, "Got outstanding refcount %d.\n", ref);
331 filter = create_vmr9(VMR9Mode_Windowed);
332 set_mixing_mode(filter, 1);
333 test_common_interfaces(filter);
335 check_interface(filter, &IID_IBasicVideo, TRUE);
336 todo_wine check_interface(filter, &IID_IBasicVideo2, TRUE);
337 check_interface(filter, &IID_IVideoWindow, TRUE);
338 check_interface(filter, &IID_IVMRMixerControl9, TRUE);
339 /* IVMRMonitorConfig9 may not be available if the d3d9 device has
340 * insufficient support. */
341 check_interface_broken(filter, &IID_IVMRMonitorConfig9, TRUE);
343 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify9, FALSE);
344 check_interface(filter, &IID_IVMRWindowlessControl9, FALSE);
346 ref = IBaseFilter_Release(filter);
347 ok(!ref, "Got outstanding refcount %d.\n", ref);
350 static const GUID test_iid = {0x33333333};
351 static LONG outer_ref = 1;
353 static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID iid, void **out)
355 if (IsEqualGUID(iid, &IID_IUnknown)
356 || IsEqualGUID(iid, &IID_IBaseFilter)
357 || IsEqualGUID(iid, &test_iid))
359 *out = (IUnknown *)0xdeadbeef;
360 return S_OK;
362 ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid));
363 return E_NOINTERFACE;
366 static ULONG WINAPI outer_AddRef(IUnknown *iface)
368 return InterlockedIncrement(&outer_ref);
371 static ULONG WINAPI outer_Release(IUnknown *iface)
373 return InterlockedDecrement(&outer_ref);
376 static const IUnknownVtbl outer_vtbl =
378 outer_QueryInterface,
379 outer_AddRef,
380 outer_Release,
383 static IUnknown test_outer = {&outer_vtbl};
385 static void test_aggregation(void)
387 IBaseFilter *filter, *filter2;
388 IUnknown *unk, *unk2;
389 HRESULT hr;
390 ULONG ref;
392 filter = (IBaseFilter *)0xdeadbeef;
393 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, &test_outer, CLSCTX_INPROC_SERVER,
394 &IID_IBaseFilter, (void **)&filter);
395 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
396 ok(!filter, "Got interface %p.\n", filter);
398 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, &test_outer, CLSCTX_INPROC_SERVER,
399 &IID_IUnknown, (void **)&unk);
400 ok(hr == S_OK, "Got hr %#x.\n", hr);
401 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
402 ok(unk != &test_outer, "Returned IUnknown should not be outer IUnknown.\n");
403 ref = get_refcount(unk);
404 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
406 ref = IUnknown_AddRef(unk);
407 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
408 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
410 ref = IUnknown_Release(unk);
411 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
412 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
414 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, (void **)&unk2);
415 ok(hr == S_OK, "Got hr %#x.\n", hr);
416 ok(unk2 == unk, "Got unexpected IUnknown %p.\n", unk2);
417 IUnknown_Release(unk2);
419 hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void **)&filter);
420 ok(hr == S_OK, "Got hr %#x.\n", hr);
422 hr = IBaseFilter_QueryInterface(filter, &IID_IUnknown, (void **)&unk2);
423 ok(hr == S_OK, "Got hr %#x.\n", hr);
424 ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
426 hr = IBaseFilter_QueryInterface(filter, &IID_IBaseFilter, (void **)&filter2);
427 ok(hr == S_OK, "Got hr %#x.\n", hr);
428 ok(filter2 == (IBaseFilter *)0xdeadbeef, "Got unexpected IBaseFilter %p.\n", filter2);
430 hr = IUnknown_QueryInterface(unk, &test_iid, (void **)&unk2);
431 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
432 ok(!unk2, "Got unexpected IUnknown %p.\n", unk2);
434 hr = IBaseFilter_QueryInterface(filter, &test_iid, (void **)&unk2);
435 ok(hr == S_OK, "Got hr %#x.\n", hr);
436 ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
438 IBaseFilter_Release(filter);
439 ref = IUnknown_Release(unk);
440 ok(!ref, "Got unexpected refcount %d.\n", ref);
441 ok(outer_ref == 1, "Got unexpected refcount %d.\n", outer_ref);
444 static void test_enum_pins(void)
446 IBaseFilter *filter = create_vmr9(0);
447 IEnumPins *enum1, *enum2;
448 ULONG count, ref;
449 IPin *pins[3];
450 HRESULT hr;
452 ref = get_refcount(filter);
453 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
455 hr = IBaseFilter_EnumPins(filter, NULL);
456 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
458 hr = IBaseFilter_EnumPins(filter, &enum1);
459 ok(hr == S_OK, "Got hr %#x.\n", hr);
460 ref = get_refcount(filter);
461 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
462 ref = get_refcount(enum1);
463 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
465 hr = IEnumPins_Next(enum1, 1, NULL, NULL);
466 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
468 hr = IEnumPins_Next(enum1, 1, pins, NULL);
469 ok(hr == S_OK, "Got hr %#x.\n", hr);
470 ref = get_refcount(filter);
471 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
472 ref = get_refcount(pins[0]);
473 ok(ref == 3, "Got unexpected refcount %d.\n", ref);
474 ref = get_refcount(enum1);
475 ok(ref == 1, "Got unexpected refcount %d.\n", ref);
476 IPin_Release(pins[0]);
477 ref = get_refcount(filter);
478 ok(ref == 2, "Got unexpected refcount %d.\n", ref);
480 hr = IEnumPins_Next(enum1, 1, pins, NULL);
481 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
483 hr = IEnumPins_Reset(enum1);
484 ok(hr == S_OK, "Got hr %#x.\n", hr);
486 hr = IEnumPins_Next(enum1, 1, pins, &count);
487 ok(hr == S_OK, "Got hr %#x.\n", hr);
488 ok(count == 1, "Got count %u.\n", count);
489 IPin_Release(pins[0]);
491 hr = IEnumPins_Next(enum1, 1, pins, &count);
492 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
493 ok(!count, "Got count %u.\n", count);
495 hr = IEnumPins_Reset(enum1);
496 ok(hr == S_OK, "Got hr %#x.\n", hr);
498 hr = IEnumPins_Next(enum1, 2, pins, NULL);
499 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
501 hr = IEnumPins_Next(enum1, 2, pins, &count);
502 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
503 ok(count == 1, "Got count %u.\n", count);
504 IPin_Release(pins[0]);
506 hr = IEnumPins_Reset(enum1);
507 ok(hr == S_OK, "Got hr %#x.\n", hr);
509 hr = IEnumPins_Clone(enum1, &enum2);
510 ok(hr == S_OK, "Got hr %#x.\n", hr);
512 hr = IEnumPins_Skip(enum1, 2);
513 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
515 hr = IEnumPins_Skip(enum1, 1);
516 ok(hr == S_OK, "Got hr %#x.\n", hr);
518 hr = IEnumPins_Skip(enum1, 1);
519 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
521 hr = IEnumPins_Next(enum1, 1, pins, NULL);
522 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
524 hr = IEnumPins_Next(enum2, 1, pins, NULL);
525 ok(hr == S_OK, "Got hr %#x.\n", hr);
526 IPin_Release(pins[0]);
528 IEnumPins_Release(enum2);
530 set_mixing_mode(filter, 2);
532 hr = IEnumPins_Next(enum1, 1, pins, NULL);
533 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
535 hr = IEnumPins_Reset(enum1);
536 ok(hr == S_OK, "Got hr %#x.\n", hr);
538 hr = IEnumPins_Next(enum1, 1, pins, NULL);
539 ok(hr == S_OK, "Got hr %#x.\n", hr);
540 IPin_Release(pins[0]);
542 hr = IEnumPins_Next(enum1, 1, pins, NULL);
543 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
544 if (hr == S_OK) IPin_Release(pins[0]);
546 hr = IEnumPins_Next(enum1, 1, pins, NULL);
547 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
549 hr = IEnumPins_Reset(enum1);
550 ok(hr == S_OK, "Got hr %#x.\n", hr);
552 hr = IEnumPins_Next(enum1, 2, pins, &count);
553 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
554 todo_wine ok(count == 2, "Got count %u.\n", count);
555 IPin_Release(pins[0]);
556 if (count > 1) IPin_Release(pins[1]);
558 hr = IEnumPins_Reset(enum1);
559 ok(hr == S_OK, "Got hr %#x.\n", hr);
561 hr = IEnumPins_Next(enum1, 3, pins, &count);
562 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
563 todo_wine ok(count == 2, "Got count %u.\n", count);
564 IPin_Release(pins[0]);
565 if (count > 1) IPin_Release(pins[1]);
567 IEnumPins_Release(enum1);
568 ref = IBaseFilter_Release(filter);
569 ok(!ref, "Got outstanding refcount %d.\n", ref);
572 static void test_find_pin(void)
574 IBaseFilter *filter = create_vmr9(0);
575 IEnumPins *enum_pins;
576 IPin *pin, *pin2;
577 HRESULT hr;
578 ULONG ref;
580 IBaseFilter_EnumPins(filter, &enum_pins);
582 hr = IBaseFilter_FindPin(filter, L"input pin", &pin);
583 ok(hr == VFW_E_NOT_FOUND, "Got hr %#x.\n", hr);
585 hr = IBaseFilter_FindPin(filter, L"In", &pin);
586 ok(hr == VFW_E_NOT_FOUND, "Got hr %#x.\n", hr);
588 hr = IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
589 ok(hr == S_OK, "Got hr %#x.\n", hr);
590 hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL);
591 ok(hr == S_OK, "Got hr %#x.\n", hr);
592 ok(pin == pin2, "Pins did not match.\n");
593 IPin_Release(pin);
594 IPin_Release(pin2);
596 hr = IBaseFilter_FindPin(filter, L"VMR Input1", &pin);
597 ok(hr == VFW_E_NOT_FOUND, "Got hr %#x.\n", hr);
599 set_mixing_mode(filter, 2);
601 IEnumPins_Reset(enum_pins);
603 hr = IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
604 ok(hr == S_OK, "Got hr %#x.\n", hr);
605 hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL);
606 ok(hr == S_OK, "Got hr %#x.\n", hr);
607 ok(pin == pin2, "Pins did not match.\n");
608 IPin_Release(pin);
609 IPin_Release(pin2);
611 hr = IBaseFilter_FindPin(filter, L"VMR Input1", &pin);
612 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
613 if (hr == S_OK)
615 hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL);
616 ok(hr == S_OK, "Got hr %#x.\n", hr);
617 ok(pin == pin2, "Pins did not match.\n");
618 IPin_Release(pin);
619 IPin_Release(pin2);
622 hr = IBaseFilter_FindPin(filter, L"VMR Input2", &pin);
623 ok(hr == VFW_E_NOT_FOUND, "Got hr %#x.\n", hr);
625 IEnumPins_Release(enum_pins);
626 ref = IBaseFilter_Release(filter);
627 ok(!ref, "Got outstanding refcount %d.\n", ref);
630 static void test_pin_info(void)
632 IBaseFilter *filter = create_vmr9(0);
633 PIN_DIRECTION dir;
634 ULONG count, ref;
635 PIN_INFO info;
636 HRESULT hr;
637 WCHAR *id;
638 IPin *pin;
640 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
641 hr = IPin_QueryPinInfo(pin, &info);
642 ok(info.pFilter == filter, "Expected filter %p, got %p.\n", filter, info.pFilter);
643 ok(info.dir == PINDIR_INPUT, "Got direction %d.\n", info.dir);
644 ok(!wcscmp(info.achName, L"VMR Input0"), "Got name %s.\n", wine_dbgstr_w(info.achName));
645 IBaseFilter_Release(info.pFilter);
647 hr = IPin_QueryDirection(pin, &dir);
648 ok(hr == S_OK, "Got hr %#x.\n", hr);
649 ok(dir == PINDIR_INPUT, "Got direction %d.\n", dir);
651 hr = IPin_QueryId(pin, &id);
652 ok(hr == S_OK, "Got hr %#x.\n", hr);
653 ok(!wcscmp(id, L"VMR Input0"), "Got id %s.\n", wine_dbgstr_w(id));
654 CoTaskMemFree(id);
656 hr = IPin_QueryInternalConnections(pin, NULL, &count);
657 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
659 IPin_Release(pin);
661 set_mixing_mode(filter, 2);
663 hr = IBaseFilter_FindPin(filter, L"VMR Input1", &pin);
664 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
665 if (hr == S_OK)
667 hr = IPin_QueryPinInfo(pin, &info);
668 ok(info.pFilter == filter, "Expected filter %p, got %p.\n", filter, info.pFilter);
669 ok(info.dir == PINDIR_INPUT, "Got direction %d.\n", info.dir);
670 ok(!wcscmp(info.achName, L"VMR Input1"), "Got name %s.\n", wine_dbgstr_w(info.achName));
671 IBaseFilter_Release(info.pFilter);
673 hr = IPin_QueryDirection(pin, &dir);
674 ok(hr == S_OK, "Got hr %#x.\n", hr);
675 ok(dir == PINDIR_INPUT, "Got direction %d.\n", dir);
677 hr = IPin_QueryId(pin, &id);
678 ok(hr == S_OK, "Got hr %#x.\n", hr);
679 ok(!wcscmp(id, L"VMR Input1"), "Got id %s.\n", wine_dbgstr_w(id));
680 CoTaskMemFree(id);
682 hr = IPin_QueryInternalConnections(pin, NULL, &count);
683 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
685 IPin_Release(pin);
688 ref = IBaseFilter_Release(filter);
689 ok(!ref, "Got outstanding refcount %d.\n", ref);
692 static void test_media_types(void)
694 IBaseFilter *filter = create_vmr9(0);
695 AM_MEDIA_TYPE *mt, req_mt = {{0}};
696 VIDEOINFOHEADER vih =
698 {0}, {0}, 0, 0, 0,
699 {sizeof(BITMAPINFOHEADER), 32, 24, 1, 0, 0xdeadbeef}
701 IEnumMediaTypes *enummt;
702 unsigned int i;
703 HRESULT hr;
704 ULONG ref;
705 IPin *pin;
707 static const GUID *subtype_tests[] =
709 &MEDIASUBTYPE_RGB565,
710 &MEDIASUBTYPE_RGB24,
711 &MEDIASUBTYPE_RGB32,
714 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
716 hr = IPin_EnumMediaTypes(pin, &enummt);
717 ok(hr == S_OK, "Got hr %#x.\n", hr);
719 hr = IEnumMediaTypes_Next(enummt, 1, &mt, NULL);
720 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
722 IEnumMediaTypes_Release(enummt);
724 req_mt.majortype = MEDIATYPE_Video;
725 req_mt.formattype = FORMAT_VideoInfo;
726 req_mt.cbFormat = sizeof(VIDEOINFOHEADER);
727 req_mt.pbFormat = (BYTE *)&vih;
729 for (i = 0; i < ARRAY_SIZE(subtype_tests); ++i)
731 req_mt.subtype = *subtype_tests[i];
732 hr = IPin_QueryAccept(pin, &req_mt);
733 ok(hr == S_OK, "Got hr %#x for subtype %s.\n", hr, wine_dbgstr_guid(subtype_tests[i]));
736 req_mt.subtype = MEDIASUBTYPE_RGB8;
737 hr = IPin_QueryAccept(pin, &req_mt);
738 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
739 req_mt.subtype = MEDIASUBTYPE_NULL;
740 hr = IPin_QueryAccept(pin, &req_mt);
741 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
742 req_mt.subtype = MEDIASUBTYPE_RGB24;
744 req_mt.majortype = MEDIATYPE_NULL;
745 hr = IPin_QueryAccept(pin, &req_mt);
746 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
747 req_mt.majortype = MEDIATYPE_Video;
749 req_mt.formattype = FORMAT_None;
750 hr = IPin_QueryAccept(pin, &req_mt);
751 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
753 req_mt.formattype = GUID_NULL;
754 hr = IPin_QueryAccept(pin, &req_mt);
755 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
757 IPin_Release(pin);
758 ref = IBaseFilter_Release(filter);
759 ok(!ref, "Got outstanding refcount %d.\n", ref);
762 static void test_enum_media_types(void)
764 IBaseFilter *filter = create_vmr9(0);
765 IEnumMediaTypes *enum1, *enum2;
766 AM_MEDIA_TYPE *mts[2];
767 ULONG ref, count;
768 HRESULT hr;
769 IPin *pin;
771 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
773 hr = IPin_EnumMediaTypes(pin, &enum1);
774 ok(hr == S_OK, "Got hr %#x.\n", hr);
776 hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL);
777 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
779 hr = IEnumMediaTypes_Next(enum1, 1, mts, &count);
780 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
781 ok(!count, "Got count %u.\n", count);
783 hr = IEnumMediaTypes_Reset(enum1);
784 ok(hr == S_OK, "Got hr %#x.\n", hr);
786 hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL);
787 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
789 hr = IEnumMediaTypes_Clone(enum1, &enum2);
790 ok(hr == S_OK, "Got hr %#x.\n", hr);
792 hr = IEnumMediaTypes_Skip(enum1, 1);
793 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
795 hr = IEnumMediaTypes_Next(enum2, 1, mts, NULL);
796 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
798 IEnumMediaTypes_Release(enum1);
799 IEnumMediaTypes_Release(enum2);
800 IPin_Release(pin);
802 ref = IBaseFilter_Release(filter);
803 ok(!ref, "Got outstanding refcount %d.\n", ref);
806 static void test_unconnected_filter_state(void)
808 IBaseFilter *filter = create_vmr9(0);
809 FILTER_STATE state;
810 HRESULT hr;
811 ULONG ref;
813 hr = IBaseFilter_GetState(filter, 0, &state);
814 ok(hr == S_OK, "Got hr %#x.\n", hr);
815 ok(state == State_Stopped, "Got state %u.\n", state);
817 hr = IBaseFilter_Pause(filter);
818 ok(hr == S_OK, "Got hr %#x.\n", hr);
820 hr = IBaseFilter_GetState(filter, 0, &state);
821 ok(hr == S_OK, "Got hr %#x.\n", hr);
822 ok(state == State_Paused, "Got state %u.\n", state);
824 hr = IBaseFilter_Run(filter, 0);
825 ok(hr == S_OK, "Got hr %#x.\n", hr);
827 hr = IBaseFilter_GetState(filter, 0, &state);
828 ok(hr == S_OK, "Got hr %#x.\n", hr);
829 ok(state == State_Running, "Got state %u.\n", state);
831 hr = IBaseFilter_Pause(filter);
832 ok(hr == S_OK, "Got hr %#x.\n", hr);
834 hr = IBaseFilter_GetState(filter, 0, &state);
835 ok(hr == S_OK, "Got hr %#x.\n", hr);
836 ok(state == State_Paused, "Got state %u.\n", state);
838 hr = IBaseFilter_Stop(filter);
839 ok(hr == S_OK, "Got hr %#x.\n", hr);
841 hr = IBaseFilter_GetState(filter, 0, &state);
842 ok(hr == S_OK, "Got hr %#x.\n", hr);
843 ok(state == State_Stopped, "Got state %u.\n", state);
845 hr = IBaseFilter_Run(filter, 0);
846 ok(hr == S_OK, "Got hr %#x.\n", hr);
848 hr = IBaseFilter_GetState(filter, 0, &state);
849 ok(hr == S_OK, "Got hr %#x.\n", hr);
850 ok(state == State_Running, "Got state %u.\n", state);
852 hr = IBaseFilter_Stop(filter);
853 ok(hr == S_OK, "Got hr %#x.\n", hr);
855 hr = IBaseFilter_GetState(filter, 0, &state);
856 ok(hr == S_OK, "Got hr %#x.\n", hr);
857 ok(state == State_Stopped, "Got state %u.\n", state);
859 ref = IBaseFilter_Release(filter);
860 ok(!ref, "Got outstanding refcount %d.\n", ref);
863 struct testfilter
865 struct strmbase_filter filter;
866 struct strmbase_source source;
869 static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface)
871 return CONTAINING_RECORD(iface, struct testfilter, filter);
874 static struct strmbase_pin *testfilter_get_pin(struct strmbase_filter *iface, unsigned int index)
876 struct testfilter *filter = impl_from_strmbase_filter(iface);
877 if (!index)
878 return &filter->source.pin;
879 return NULL;
882 static void testfilter_destroy(struct strmbase_filter *iface)
884 struct testfilter *filter = impl_from_strmbase_filter(iface);
885 strmbase_source_cleanup(&filter->source);
886 strmbase_filter_cleanup(&filter->filter);
889 static const struct strmbase_filter_ops testfilter_ops =
891 .filter_get_pin = testfilter_get_pin,
892 .filter_destroy = testfilter_destroy,
895 static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface,
896 IMemInputPin *peer, IMemAllocator **allocator)
898 return S_OK;
901 static const struct strmbase_source_ops testsource_ops =
903 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
904 .pfnDecideAllocator = testsource_DecideAllocator,
907 static void testfilter_init(struct testfilter *filter)
909 static const GUID clsid = {0xabacab};
910 strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops);
911 strmbase_source_init(&filter->source, &filter->filter, L"", &testsource_ops);
914 static void test_allocator(IMemInputPin *input)
916 IMemAllocator *req_allocator, *ret_allocator;
917 ALLOCATOR_PROPERTIES props, req_props;
918 HRESULT hr;
920 hr = IMemInputPin_GetAllocatorRequirements(input, &props);
921 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
923 hr = IMemInputPin_GetAllocator(input, &ret_allocator);
924 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
926 if (hr == S_OK)
928 hr = IMemAllocator_GetProperties(ret_allocator, &props);
929 ok(hr == S_OK, "Got hr %#x.\n", hr);
930 ok(!props.cBuffers, "Got %d buffers.\n", props.cBuffers);
931 ok(!props.cbBuffer, "Got size %d.\n", props.cbBuffer);
932 ok(!props.cbAlign, "Got alignment %d.\n", props.cbAlign);
933 ok(!props.cbPrefix, "Got prefix %d.\n", props.cbPrefix);
935 hr = IMemInputPin_NotifyAllocator(input, ret_allocator, TRUE);
936 ok(hr == S_OK, "Got hr %#x.\n", hr);
938 req_props.cBuffers = 1;
939 req_props.cbBuffer = 32 * 16 * 4;
940 req_props.cbAlign = 1;
941 req_props.cbPrefix = 0;
942 hr = IMemAllocator_SetProperties(ret_allocator, &req_props, &props);
943 ok(hr == S_OK, "Got hr %#x.\n", hr);
944 ok(props.cBuffers == 1, "Got %d buffers.\n", props.cBuffers);
945 ok(props.cbBuffer == 32 * 16 * 4, "Got size %d.\n", props.cbBuffer);
946 ok(props.cbAlign == 1, "Got alignment %d.\n", props.cbAlign);
947 ok(!props.cbPrefix, "Got prefix %d.\n", props.cbPrefix);
949 IMemAllocator_Release(ret_allocator);
952 hr = IMemInputPin_NotifyAllocator(input, NULL, TRUE);
953 todo_wine ok(hr == E_FAIL, "Got hr %#x.\n", hr);
955 CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
956 &IID_IMemAllocator, (void **)&req_allocator);
958 hr = IMemInputPin_NotifyAllocator(input, req_allocator, TRUE);
959 todo_wine ok(hr == E_FAIL, "Got hr %#x.\n", hr);
961 IMemAllocator_Release(req_allocator);
964 struct frame_thread_params
966 IMemInputPin *sink;
967 IMediaSample *sample;
970 static DWORD WINAPI frame_thread(void *arg)
972 struct frame_thread_params *params = arg;
973 HRESULT hr;
975 if (winetest_debug > 1) trace("%04x: Sending frame.\n", GetCurrentThreadId());
976 hr = IMemInputPin_Receive(params->sink, params->sample);
977 if (winetest_debug > 1) trace("%04x: Returned %#x.\n", GetCurrentThreadId(), hr);
978 IMediaSample_Release(params->sample);
979 heap_free(params);
980 return hr;
983 static HANDLE send_frame_time(IMemInputPin *sink, REFERENCE_TIME start_time, DWORD color)
985 struct frame_thread_params *params = heap_alloc(sizeof(*params));
986 IMemAllocator *allocator;
987 REFERENCE_TIME end_time;
988 IMediaSample *sample;
989 HANDLE thread;
990 LONG size, i;
991 HRESULT hr;
992 BYTE *data;
994 hr = IMemInputPin_GetAllocator(sink, &allocator);
995 ok(hr == S_OK, "Got hr %#x.\n", hr);
997 hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
998 ok(hr == S_OK, "Got hr %#x.\n", hr);
1000 size = IMediaSample_GetSize(sample);
1001 hr = IMediaSample_GetPointer(sample, &data);
1002 ok(hr == S_OK, "Got hr %#x.\n", hr);
1003 for (i = 0; i < size / sizeof(DWORD); ++i)
1004 ((DWORD *)data)[i] = color;
1006 hr = IMediaSample_SetActualDataLength(sample, size);
1007 ok(hr == S_OK, "Got hr %#x.\n", hr);
1009 start_time *= 10000000;
1010 end_time = start_time + 10000000;
1011 hr = IMediaSample_SetTime(sample, &start_time, &end_time);
1012 ok(hr == S_OK, "Got hr %#x.\n", hr);
1014 hr = IMediaSample_SetPreroll(sample, TRUE);
1015 ok(hr == S_OK, "Got hr %#x.\n", hr);
1017 params->sink = sink;
1018 params->sample = sample;
1019 thread = CreateThread(NULL, 0, frame_thread, params, 0, NULL);
1021 IMemAllocator_Release(allocator);
1022 return thread;
1025 static HANDLE send_frame(IMemInputPin *sink)
1027 return send_frame_time(sink, 0, 0x007f007f);
1030 static HRESULT join_thread_(int line, HANDLE thread)
1032 DWORD ret;
1033 ok_(__FILE__, line)(!WaitForSingleObject(thread, 1000), "Wait failed.\n");
1034 GetExitCodeThread(thread, &ret);
1035 CloseHandle(thread);
1036 return ret;
1038 #define join_thread(a) join_thread_(__LINE__, a)
1040 static void commit_allocator(IMemInputPin *input)
1042 IMemAllocator *allocator;
1043 HRESULT hr;
1045 hr = IMemInputPin_GetAllocator(input, &allocator);
1046 ok(hr == S_OK, "Got hr %#x.\n", hr);
1047 hr = IMemAllocator_Commit(allocator);
1048 ok(hr == S_OK, "Got hr %#x.\n", hr);
1049 IMemAllocator_Release(allocator);
1052 static void test_filter_state(IMemInputPin *input, IMediaControl *control)
1054 IMemAllocator *allocator;
1055 IMediaSample *sample;
1056 OAFilterState state;
1057 HANDLE thread;
1058 HRESULT hr;
1060 thread = send_frame(input);
1061 hr = join_thread(thread);
1062 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
1064 /* The renderer is not fully paused until it receives a sample. The thread
1065 * sending the sample blocks in IMemInputPin_Receive() until the filter is
1066 * stopped or run. */
1068 hr = IMediaControl_Pause(control);
1069 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1071 hr = IMediaControl_GetState(control, 0, &state);
1072 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1074 thread = send_frame(input);
1076 hr = IMediaControl_GetState(control, 1000, &state);
1077 ok(hr == S_OK, "Got hr %#x.\n", hr);
1079 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1081 hr = IMediaControl_Stop(control);
1082 ok(hr == S_OK, "Got hr %#x.\n", hr);
1084 hr = join_thread(thread);
1085 ok(hr == S_OK, "Got hr %#x.\n", hr);
1087 /* The sink will decommit our allocator for us when stopping, however it
1088 * will not recommit it when pausing. */
1089 hr = IMemInputPin_GetAllocator(input, &allocator);
1090 ok(hr == S_OK, "Got hr %#x.\n", hr);
1091 hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
1092 todo_wine ok(hr == VFW_E_NOT_COMMITTED, "Got hr %#x.\n", hr);
1093 if (hr == S_OK) IMediaSample_Release(sample);
1095 hr = IMemAllocator_Commit(allocator);
1096 ok(hr == S_OK, "Got hr %#x.\n", hr);
1097 thread = send_frame(input);
1098 hr = join_thread(thread);
1099 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
1101 hr = IMediaControl_Pause(control);
1102 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1104 hr = IMediaControl_GetState(control, 0, &state);
1105 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1107 thread = send_frame(input);
1109 hr = IMediaControl_GetState(control, 1000, &state);
1110 ok(hr == S_OK, "Got hr %#x.\n", hr);
1112 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1114 hr = IMediaControl_Run(control);
1115 ok(hr == S_OK, "Got hr %#x.\n", hr);
1117 hr = IMediaControl_GetState(control, 0, &state);
1118 ok(hr == S_OK, "Got hr %#x.\n", hr);
1120 hr = join_thread(thread);
1121 ok(hr == S_OK, "Got hr %#x.\n", hr);
1123 thread = send_frame(input);
1124 hr = join_thread(thread);
1125 ok(hr == S_OK, "Got hr %#x.\n", hr);
1127 hr = IMediaControl_Pause(control);
1128 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1130 hr = IMediaControl_GetState(control, 0, &state);
1131 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1133 thread = send_frame(input);
1135 hr = IMediaControl_GetState(control, 1000, &state);
1136 ok(hr == S_OK, "Got hr %#x.\n", hr);
1138 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1140 hr = IMediaControl_Run(control);
1141 ok(hr == S_OK, "Got hr %#x.\n", hr);
1143 hr = IMediaControl_GetState(control, 0, &state);
1144 ok(hr == S_OK, "Got hr %#x.\n", hr);
1146 hr = join_thread(thread);
1147 ok(hr == S_OK, "Got hr %#x.\n", hr);
1149 hr = IMediaControl_Pause(control);
1150 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1152 hr = IMediaControl_GetState(control, 0, &state);
1153 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1155 hr = IMediaControl_Stop(control);
1156 ok(hr == S_OK, "Got hr %#x.\n", hr);
1158 hr = IMediaControl_GetState(control, 0, &state);
1159 ok(hr == S_OK, "Got hr %#x.\n", hr);
1161 commit_allocator(input);
1162 hr = IMediaControl_Pause(control);
1163 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1165 hr = IMediaControl_GetState(control, 0, &state);
1166 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1168 hr = IMediaControl_Run(control);
1169 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1171 hr = IMediaControl_GetState(control, 0, &state);
1172 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1174 thread = send_frame(input);
1175 hr = join_thread(thread);
1176 ok(hr == S_OK, "Got hr %#x.\n", hr);
1178 hr = IMediaControl_GetState(control, 0, &state);
1179 ok(hr == S_OK, "Got hr %#x.\n", hr);
1181 hr = IMediaControl_Stop(control);
1182 ok(hr == S_OK, "Got hr %#x.\n", hr);
1184 hr = IMediaControl_GetState(control, 0, &state);
1185 ok(hr == S_OK, "Got hr %#x.\n", hr);
1187 IMemAllocator_Release(allocator);
1190 static void test_flushing(IPin *pin, IMemInputPin *input, IMediaControl *control)
1192 OAFilterState state;
1193 HANDLE thread;
1194 HRESULT hr;
1196 commit_allocator(input);
1197 hr = IMediaControl_Pause(control);
1198 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1200 thread = send_frame(input);
1201 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1203 hr = IMediaControl_GetState(control, 0, &state);
1204 ok(hr == S_OK, "Got hr %#x.\n", hr);
1206 hr = IPin_BeginFlush(pin);
1207 ok(hr == S_OK, "Got hr %#x.\n", hr);
1209 hr = join_thread(thread);
1210 ok(hr == S_OK, "Got hr %#x.\n", hr);
1212 thread = send_frame(input);
1213 hr = join_thread(thread);
1214 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1216 hr = IPin_EndFlush(pin);
1217 ok(hr == S_OK, "Got hr %#x.\n", hr);
1219 /* We dropped the sample we were holding, so now we need a new one... */
1221 hr = IMediaControl_GetState(control, 0, &state);
1222 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1224 thread = send_frame(input);
1225 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1227 hr = IMediaControl_Run(control);
1228 ok(hr == S_OK, "Got hr %#x.\n", hr);
1229 hr = join_thread(thread);
1230 ok(hr == S_OK, "Got hr %#x.\n", hr);
1232 hr = IPin_BeginFlush(pin);
1233 ok(hr == S_OK, "Got hr %#x.\n", hr);
1235 thread = send_frame(input);
1236 hr = join_thread(thread);
1237 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1239 hr = IPin_EndFlush(pin);
1240 ok(hr == S_OK, "Got hr %#x.\n", hr);
1242 thread = send_frame(input);
1243 hr = join_thread(thread);
1244 ok(hr == S_OK, "Got hr %#x.\n", hr);
1246 hr = IMediaControl_Stop(control);
1247 ok(hr == S_OK, "Got hr %#x.\n", hr);
1250 static unsigned int check_ec_complete(IMediaEvent *eventsrc, DWORD timeout)
1252 LONG_PTR param1, param2;
1253 unsigned int ret = 0;
1254 HRESULT hr;
1255 LONG code;
1257 while ((hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, timeout)) == S_OK)
1259 if (code == EC_COMPLETE)
1261 ok(param1 == S_OK, "Got param1 %#lx.\n", param1);
1262 ok(!param2, "Got param2 %#lx.\n", param2);
1263 ret++;
1265 IMediaEvent_FreeEventParams(eventsrc, code, param1, param2);
1266 timeout = 0;
1268 ok(hr == E_ABORT, "Got hr %#x.\n", hr);
1270 return ret;
1273 static void test_eos(IPin *pin, IMemInputPin *input, IMediaControl *control)
1275 IMediaEvent *eventsrc;
1276 OAFilterState state;
1277 HRESULT hr;
1278 BOOL ret;
1280 IMediaControl_QueryInterface(control, &IID_IMediaEvent, (void **)&eventsrc);
1282 commit_allocator(input);
1283 hr = IMediaControl_Pause(control);
1284 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1285 ret = check_ec_complete(eventsrc, 0);
1286 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1288 hr = IPin_EndOfStream(pin);
1289 ok(hr == S_OK, "Got hr %#x.\n", hr);
1291 hr = IMediaControl_GetState(control, 1000, &state);
1292 ok(hr == S_OK, "Got hr %#x.\n", hr);
1293 ret = check_ec_complete(eventsrc, 0);
1294 todo_wine ok(!ret, "Got unexpected EC_COMPLETE.\n");
1296 hr = join_thread(send_frame(input));
1297 todo_wine ok(hr == E_UNEXPECTED, "Got hr %#x.\n", hr);
1299 hr = IMediaControl_Run(control);
1300 ok(hr == S_OK, "Got hr %#x.\n", hr);
1301 ret = check_ec_complete(eventsrc, 0);
1302 todo_wine ok(ret == 1, "Expected EC_COMPLETE.\n");
1304 hr = IMediaControl_Stop(control);
1305 ok(hr == S_OK, "Got hr %#x.\n", hr);
1306 ret = check_ec_complete(eventsrc, 0);
1307 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1309 /* We do not receive an EC_COMPLETE notification until the last sample is
1310 * done rendering. */
1312 commit_allocator(input);
1313 hr = IMediaControl_Run(control);
1314 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1315 hr = join_thread(send_frame(input));
1316 ok(hr == S_OK, "Got hr %#x.\n", hr);
1317 hr = IMediaControl_GetState(control, 1000, &state);
1318 ok(hr == S_OK, "Got hr %#x.\n", hr);
1319 ret = check_ec_complete(eventsrc, 0);
1320 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1322 hr = IPin_EndOfStream(pin);
1323 ok(hr == S_OK, "Got hr %#x.\n", hr);
1324 ret = check_ec_complete(eventsrc, 0);
1325 todo_wine ok(!ret, "Got unexpected EC_COMPLETE.\n");
1326 ret = check_ec_complete(eventsrc, 1600);
1327 todo_wine ok(ret == 1, "Expected EC_COMPLETE.\n");
1329 hr = IMediaControl_Stop(control);
1330 ok(hr == S_OK, "Got hr %#x.\n", hr);
1331 ret = check_ec_complete(eventsrc, 0);
1332 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1334 /* Test sending EOS while flushing. */
1336 commit_allocator(input);
1337 hr = IMediaControl_Run(control);
1338 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1339 hr = join_thread(send_frame(input));
1340 ok(hr == S_OK, "Got hr %#x.\n", hr);
1342 hr = IPin_BeginFlush(pin);
1343 ok(hr == S_OK, "Got hr %#x.\n", hr);
1344 hr = IPin_EndOfStream(pin);
1345 todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1346 hr = IPin_EndFlush(pin);
1347 ok(hr == S_OK, "Got hr %#x.\n", hr);
1349 hr = IMediaControl_Stop(control);
1350 ok(hr == S_OK, "Got hr %#x.\n", hr);
1351 ret = check_ec_complete(eventsrc, 0);
1352 todo_wine ok(!ret, "Got unexpected EC_COMPLETE.\n");
1354 /* Test sending EOS and then flushing or stopping. */
1356 commit_allocator(input);
1357 hr = IMediaControl_Run(control);
1358 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1359 hr = join_thread(send_frame(input));
1360 ok(hr == S_OK, "Got hr %#x.\n", hr);
1361 hr = IMediaControl_GetState(control, 1000, &state);
1362 ok(hr == S_OK, "Got hr %#x.\n", hr);
1364 hr = IPin_EndOfStream(pin);
1365 ok(hr == S_OK, "Got hr %#x.\n", hr);
1366 ret = check_ec_complete(eventsrc, 0);
1367 todo_wine ok(!ret, "Got unexpected EC_COMPLETE.\n");
1369 hr = IPin_BeginFlush(pin);
1370 ok(hr == S_OK, "Got hr %#x.\n", hr);
1371 hr = IPin_EndFlush(pin);
1372 ok(hr == S_OK, "Got hr %#x.\n", hr);
1374 hr = join_thread(send_frame(input));
1375 ok(hr == S_OK, "Got hr %#x.\n", hr);
1376 hr = IPin_EndOfStream(pin);
1377 ok(hr == S_OK, "Got hr %#x.\n", hr);
1378 ret = check_ec_complete(eventsrc, 0);
1379 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1381 hr = IMediaControl_Stop(control);
1382 ok(hr == S_OK, "Got hr %#x.\n", hr);
1383 ret = check_ec_complete(eventsrc, 0);
1384 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1386 IMediaEvent_Release(eventsrc);
1389 static void test_sample_time(IPin *pin, IMemInputPin *input, IMediaControl *control)
1391 OAFilterState state;
1392 HANDLE thread;
1393 HRESULT hr;
1395 commit_allocator(input);
1396 hr = IMediaControl_Pause(control);
1397 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1399 hr = IMediaControl_GetState(control, 0, &state);
1400 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#x.\n", hr);
1402 thread = send_frame_time(input, 1, 0x000000ff); /* blue */
1404 hr = IMediaControl_GetState(control, 1000, &state);
1405 ok(hr == S_OK, "Got hr %#x.\n", hr);
1407 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1409 hr = IMediaControl_Run(control);
1410 ok(hr == S_OK, "Got hr %#x.\n", hr);
1412 ok(WaitForSingleObject(thread, 500) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1414 hr = join_thread(thread);
1415 ok(hr == S_OK, "Got hr %#x.\n", hr);
1417 /* Sample time is relative to the time passed to Run(). Thus a sample
1418 * stamped at or earlier than 1s will now be displayed immediately, because
1419 * that time has already passed.
1420 * One may manually verify that all of the frames in this function are
1421 * rendered, including (by adding a Sleep() after sending the frame) the
1422 * cyan and green frames. Thus the VMR does not attempt to drop any frames
1423 * that it considers late. This remains true if the frames are marked as
1424 * discontinuous. */
1426 hr = join_thread(send_frame_time(input, 1, 0x0000ffff)); /* cyan */
1427 ok(hr == S_OK, "Got hr %#x.\n", hr);
1429 hr = join_thread(send_frame_time(input, 0, 0x0000ff00)); /* green */
1430 ok(hr == S_OK, "Got hr %#x.\n", hr);
1432 hr = join_thread(send_frame_time(input, -2, 0x00ff0000)); /* red */
1433 ok(hr == S_OK, "Got hr %#x.\n", hr);
1435 thread = send_frame_time(input, 2, 0x00ff00ff); /* magenta */
1436 ok(WaitForSingleObject(thread, 500) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1437 hr = join_thread(thread);
1438 ok(hr == S_OK, "Got hr %#x.\n", hr);
1440 thread = send_frame_time(input, 1000000, 0x00ffffff); /* white */
1441 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1443 hr = IPin_BeginFlush(pin);
1444 ok(hr == S_OK, "Got hr %#x.\n", hr);
1445 hr = join_thread(thread);
1446 ok(hr == S_OK, "Got hr %#x.\n", hr);
1447 hr = IPin_EndFlush(pin);
1448 ok(hr == S_OK, "Got hr %#x.\n", hr);
1450 thread = send_frame_time(input, 1000000, 0x00ffff00); /* yellow */
1451 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1453 hr = IMediaControl_Stop(control);
1454 ok(hr == S_OK, "Got hr %#x.\n", hr);
1455 hr = join_thread(thread);
1456 ok(hr == S_OK, "Got hr %#x.\n", hr);
1459 static void test_current_image(IBaseFilter *filter, IMemInputPin *input,
1460 IMediaControl *control, const BITMAPINFOHEADER *req_bih)
1462 LONG buffer[(sizeof(BITMAPINFOHEADER) + 32 * 16 * 4) / 4];
1463 const BITMAPINFOHEADER *bih = (BITMAPINFOHEADER *)buffer;
1464 const DWORD *data = (DWORD *)((char *)buffer + sizeof(BITMAPINFOHEADER));
1465 BITMAPINFOHEADER expect_bih = *req_bih;
1466 OAFilterState state;
1467 IBasicVideo *video;
1468 unsigned int i;
1469 HANDLE thread;
1470 HRESULT hr;
1471 LONG size;
1473 expect_bih.biSizeImage = 32 * 16 * 4;
1475 IBaseFilter_QueryInterface(filter, &IID_IBasicVideo, (void **)&video);
1477 hr = IBasicVideo_GetCurrentImage(video, NULL, NULL);
1478 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
1480 hr = IBasicVideo_GetCurrentImage(video, NULL, buffer);
1481 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
1483 size = 0xdeadbeef;
1484 hr = IBasicVideo_GetCurrentImage(video, &size, NULL);
1485 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
1486 todo_wine ok(size == sizeof(BITMAPINFOHEADER) + 32 * 16 * 4, "Got size %d.\n", size);
1488 size = sizeof(buffer);
1489 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1490 ok(hr == S_OK, "Got hr %#x.\n", hr);
1491 ok(size == sizeof(buffer), "Got size %d.\n", size);
1492 ok(!memcmp(bih, &expect_bih, sizeof(BITMAPINFOHEADER)), "Bitmap headers didn't match.\n");
1493 /* The contents seem to reflect the last frame rendered. */
1495 commit_allocator(input);
1496 hr = IMediaControl_Pause(control);
1497 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1499 size = sizeof(buffer);
1500 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1501 ok(hr == S_OK, "Got hr %#x.\n", hr);
1502 ok(size == sizeof(buffer), "Got size %d.\n", size);
1503 ok(!memcmp(bih, &expect_bih, sizeof(BITMAPINFOHEADER)), "Bitmap headers didn't match.\n");
1504 /* The contents seem to reflect the last frame rendered. */
1506 thread = send_frame(input);
1507 hr = IMediaControl_GetState(control, 1000, &state);
1508 ok(hr == S_OK, "Got hr %#x.\n", hr);
1510 size = 1;
1511 memset(buffer, 0xcc, sizeof(buffer));
1512 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1513 ok(hr == S_OK, "Got hr %#x.\n", hr);
1514 ok(size == 1, "Got size %d.\n", size);
1516 size = sizeof(buffer);
1517 memset(buffer, 0xcc, sizeof(buffer));
1518 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1519 ok(hr == S_OK, "Got hr %#x.\n", hr);
1520 ok(size == sizeof(buffer), "Got size %d.\n", size);
1521 ok(!memcmp(bih, &expect_bih, sizeof(BITMAPINFOHEADER)), "Bitmap headers didn't match.\n");
1522 for (i = 0; i < 32 * 16; ++i)
1523 ok((data[i] & 0xffffff) == 0x7f007f, "Got unexpected color %08x at %u.\n", data[i], i);
1525 hr = IMediaControl_Run(control);
1526 ok(hr == S_OK, "Got hr %#x.\n", hr);
1527 join_thread(thread);
1529 size = sizeof(buffer);
1530 memset(buffer, 0xcc, sizeof(buffer));
1531 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1532 ok(hr == S_OK, "Got hr %#x.\n", hr);
1533 ok(size == sizeof(buffer), "Got size %d.\n", size);
1534 ok(!memcmp(bih, &expect_bih, sizeof(BITMAPINFOHEADER)), "Bitmap headers didn't match.\n");
1535 for (i = 0; i < 32 * 16; ++i)
1536 ok((data[i] & 0xffffff) == 0x7f007f, "Got unexpected color %08x at %u.\n", data[i], i);
1538 hr = IMediaControl_Stop(control);
1539 ok(hr == S_OK, "Got hr %#x.\n", hr);
1541 IBasicVideo_Release(video);
1544 static void test_connect_pin(void)
1546 VIDEOINFOHEADER vih =
1548 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
1549 .bmiHeader.biBitCount = 32,
1550 .bmiHeader.biWidth = 32,
1551 .bmiHeader.biHeight = 16,
1552 .bmiHeader.biPlanes = 1,
1553 .bmiHeader.biCompression = BI_RGB,
1555 AM_MEDIA_TYPE req_mt =
1557 .majortype = MEDIATYPE_Video,
1558 .formattype = FORMAT_VideoInfo,
1559 .cbFormat = sizeof(vih),
1560 .pbFormat = (BYTE *)&vih,
1562 ALLOCATOR_PROPERTIES req_props = {1, 32 * 16 * 4, 1, 0}, ret_props;
1563 IBaseFilter *filter = create_vmr9(VMR9Mode_Windowed);
1564 IFilterGraph2 *graph = create_graph();
1565 struct testfilter source;
1566 IMemAllocator *allocator;
1567 IMediaControl *control;
1568 IMemInputPin *input;
1569 unsigned int i, j;
1570 AM_MEDIA_TYPE mt;
1571 IPin *pin, *peer;
1572 HRESULT hr;
1573 ULONG ref;
1575 static const GUID *subtype_tests[] =
1577 &MEDIASUBTYPE_RGB555,
1578 &MEDIASUBTYPE_RGB565,
1579 &MEDIASUBTYPE_RGB24,
1580 &MEDIASUBTYPE_RGB32,
1582 static const WORD bpp_tests[] = {15, 16, 24, 32};
1584 testfilter_init(&source);
1586 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL);
1587 IFilterGraph2_AddFilter(graph, filter, NULL);
1588 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
1590 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
1591 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
1593 for (i = 0; i < ARRAY_SIZE(subtype_tests); ++i)
1595 req_mt.subtype = *subtype_tests[i];
1597 for (j = 0; j < ARRAY_SIZE(bpp_tests); ++j)
1599 vih.bmiHeader.biBitCount = bpp_tests[j];
1601 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1602 if (hr == E_FAIL)
1604 skip("Got E_FAIL when connecting.\n");
1605 goto out;
1607 ok(hr == S_OK, "Got hr %#x for subtype %s and bpp %u.\n", hr,
1608 wine_dbgstr_guid(subtype_tests[i]), bpp_tests[j]);
1610 hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
1611 ok(hr == S_OK, "Got hr %#x.\n", hr);
1612 hr = IFilterGraph2_Disconnect(graph, pin);
1613 ok(hr == S_OK, "Got hr %#x.\n", hr);
1617 req_mt.formattype = FORMAT_None;
1618 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1619 ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr);
1620 req_mt.formattype = FORMAT_VideoInfo;
1622 req_mt.subtype = MEDIASUBTYPE_RGB8;
1623 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1624 ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr);
1625 req_mt.subtype = MEDIASUBTYPE_WAVE;
1626 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1627 ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr);
1628 req_mt.subtype = MEDIASUBTYPE_RGB32;
1630 peer = (IPin *)0xdeadbeef;
1631 hr = IPin_ConnectedTo(pin, &peer);
1632 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
1633 ok(!peer, "Got peer %p.\n", peer);
1635 hr = IPin_ConnectionMediaType(pin, &mt);
1636 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
1638 hr = IMediaControl_Pause(control);
1639 ok(hr == S_OK, "Got hr %#x.\n", hr);
1640 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1641 ok(hr == VFW_E_NOT_STOPPED, "Got hr %#x.\n", hr);
1642 hr = IMediaControl_Stop(control);
1643 ok(hr == S_OK, "Got hr %#x.\n", hr);
1645 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1646 ok(hr == S_OK, "Got hr %#x.\n", hr);
1648 hr = IPin_ConnectedTo(pin, &peer);
1649 ok(hr == S_OK, "Got hr %#x.\n", hr);
1650 ok(peer == &source.source.pin.IPin_iface, "Got peer %p.\n", peer);
1651 IPin_Release(peer);
1653 hr = IPin_ConnectionMediaType(pin, &mt);
1654 ok(hr == S_OK, "Got hr %#x.\n", hr);
1655 ok(compare_media_types(&mt, &req_mt), "Media types didn't match.\n");
1657 /* Disconnecting while not stopped is broken: it returns S_OK, but
1658 * subsequent attempts to connect return VFW_E_ALREADY_CONNECTED. */
1660 test_allocator(input);
1662 hr = IMemInputPin_GetAllocator(input, &allocator);
1663 ok(hr == S_OK, "Got hr %#x.\n", hr);
1664 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
1665 ok(hr == S_OK, "Got hr %#x.\n", hr);
1666 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
1667 hr = IMemAllocator_Commit(allocator);
1668 ok(hr == S_OK, "Got hr %#x.\n", hr);
1669 IMemAllocator_Release(allocator);
1671 hr = IMemInputPin_ReceiveCanBlock(input);
1672 ok(hr == S_OK, "Got hr %#x.\n", hr);
1674 test_filter_state(input, control);
1675 test_flushing(pin, input, control);
1676 test_eos(pin, input, control);
1677 test_sample_time(pin, input, control);
1678 test_current_image(filter, input, control, &vih.bmiHeader);
1680 hr = IFilterGraph2_Disconnect(graph, pin);
1681 ok(hr == S_OK, "Got hr %#x.\n", hr);
1682 hr = IFilterGraph2_Disconnect(graph, pin);
1683 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
1684 ok(source.source.pin.peer == pin, "Got peer %p.\n", source.source.pin.peer);
1685 IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
1687 peer = (IPin *)0xdeadbeef;
1688 hr = IPin_ConnectedTo(pin, &peer);
1689 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
1690 ok(!peer, "Got peer %p.\n", peer);
1692 hr = IPin_ConnectionMediaType(pin, &mt);
1693 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
1695 out:
1696 IMediaControl_Release(control);
1697 ref = IFilterGraph2_Release(graph);
1698 ok(!ref, "Got outstanding refcount %d.\n", ref);
1699 IMemInputPin_Release(input);
1700 IPin_Release(pin);
1701 ref = IBaseFilter_Release(filter);
1702 ok(!ref, "Got outstanding refcount %d.\n", ref);
1703 ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface);
1704 ok(!ref, "Got outstanding refcount %d.\n", ref);
1707 static void test_overlay(void)
1709 IBaseFilter *filter = create_vmr9(0);
1710 IOverlay *overlay;
1711 HRESULT hr;
1712 ULONG ref;
1713 IPin *pin;
1714 HWND hwnd;
1716 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
1718 hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay);
1719 ok(hr == S_OK, "Got hr %#x.\n", hr);
1721 hwnd = (HWND)0xdeadbeef;
1722 hr = IOverlay_GetWindowHandle(overlay, &hwnd);
1723 ok(hr == S_OK, "Got hr %#x.\n", hr);
1724 ok(hwnd && hwnd != (HWND)0xdeadbeef, "Got invalid window %p.\n", hwnd);
1726 IOverlay_Release(overlay);
1727 IPin_Release(pin);
1728 ref = IBaseFilter_Release(filter);
1729 ok(!ref, "Got outstanding refcount %d.\n", ref);
1731 filter = create_vmr9(VMR9Mode_Windowless);
1732 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
1734 hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay);
1735 ok(hr == S_OK, "Got hr %#x.\n", hr);
1737 hwnd = (HWND)0xdeadbeef;
1738 hr = IOverlay_GetWindowHandle(overlay, &hwnd);
1739 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
1740 ok(hwnd == (HWND)0xdeadbeef, "Got window %p.\n", hwnd);
1742 IOverlay_Release(overlay);
1743 IPin_Release(pin);
1744 ref = IBaseFilter_Release(filter);
1745 ok(!ref, "Got outstanding refcount %d.\n", ref);
1747 filter = create_vmr9(VMR9Mode_Renderless);
1748 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
1750 hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay);
1751 ok(hr == S_OK, "Got hr %#x.\n", hr);
1753 hwnd = (HWND)0xdeadbeef;
1754 hr = IOverlay_GetWindowHandle(overlay, &hwnd);
1755 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
1756 ok(hwnd == (HWND)0xdeadbeef, "Got window %p.\n", hwnd);
1758 IOverlay_Release(overlay);
1759 IPin_Release(pin);
1760 ref = IBaseFilter_Release(filter);
1761 ok(!ref, "Got outstanding refcount %d.\n", ref);
1764 /* try to make sure pending X events have been processed before continuing */
1765 static void flush_events(void)
1767 int diff = 200;
1768 DWORD time;
1769 MSG msg;
1771 time = GetTickCount() + diff;
1772 while (diff > 0)
1774 if (MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT) == WAIT_TIMEOUT)
1775 break;
1776 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
1777 DispatchMessageA(&msg);
1778 diff = time - GetTickCount();
1782 static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1784 if (winetest_debug > 1)
1785 trace("hwnd %p, msg %#x, wparam %#lx, lparam %#lx.\n", hwnd, msg, wparam, lparam);
1787 if (wparam == 0xdeadbeef)
1788 return 0;
1790 return DefWindowProcA(hwnd, msg, wparam, lparam);
1793 static void test_video_window_caption(IVideoWindow *window, HWND hwnd)
1795 WCHAR text[50];
1796 BSTR caption;
1797 HRESULT hr;
1799 hr = IVideoWindow_get_Caption(window, &caption);
1800 ok(hr == S_OK, "Got hr %#x.\n", hr);
1801 ok(!wcscmp(caption, L"ActiveMovie Window"), "Got caption %s.\n", wine_dbgstr_w(caption));
1802 SysFreeString(caption);
1804 GetWindowTextW(hwnd, text, ARRAY_SIZE(text));
1805 ok(!wcscmp(text, L"ActiveMovie Window"), "Got caption %s.\n", wine_dbgstr_w(text));
1807 caption = SysAllocString(L"foo");
1808 hr = IVideoWindow_put_Caption(window, caption);
1809 ok(hr == S_OK, "Got hr %#x.\n", hr);
1810 SysFreeString(caption);
1812 hr = IVideoWindow_get_Caption(window, &caption);
1813 ok(hr == S_OK, "Got hr %#x.\n", hr);
1814 ok(!wcscmp(caption, L"foo"), "Got caption %s.\n", wine_dbgstr_w(caption));
1815 SysFreeString(caption);
1817 GetWindowTextW(hwnd, text, ARRAY_SIZE(text));
1818 ok(!wcscmp(text, L"foo"), "Got caption %s.\n", wine_dbgstr_w(text));
1821 static void test_video_window_style(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
1823 HRESULT hr;
1824 LONG style;
1826 hr = IVideoWindow_get_WindowStyle(window, &style);
1827 ok(hr == S_OK, "Got hr %#x.\n", hr);
1828 ok(style == (WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW),
1829 "Got style %#x.\n", style);
1831 style = GetWindowLongA(hwnd, GWL_STYLE);
1832 ok(style == (WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW),
1833 "Got style %#x.\n", style);
1835 hr = IVideoWindow_put_WindowStyle(window, style | WS_DISABLED);
1836 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
1837 hr = IVideoWindow_put_WindowStyle(window, style | WS_HSCROLL);
1838 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
1839 hr = IVideoWindow_put_WindowStyle(window, style | WS_VSCROLL);
1840 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
1841 hr = IVideoWindow_put_WindowStyle(window, style | WS_MAXIMIZE);
1842 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
1843 hr = IVideoWindow_put_WindowStyle(window, style | WS_MINIMIZE);
1844 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
1846 hr = IVideoWindow_put_WindowStyle(window, style & ~WS_CLIPCHILDREN);
1847 ok(hr == S_OK, "Got hr %#x.\n", hr);
1849 hr = IVideoWindow_get_WindowStyle(window, &style);
1850 ok(hr == S_OK, "Got hr %#x.\n", hr);
1851 ok(style == (WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW), "Got style %#x.\n", style);
1853 style = GetWindowLongA(hwnd, GWL_STYLE);
1854 ok(style == (WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW), "Got style %#x.\n", style);
1856 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
1858 hr = IVideoWindow_get_WindowStyleEx(window, &style);
1859 ok(hr == S_OK, "Got hr %#x.\n", hr);
1860 ok(style == WS_EX_WINDOWEDGE, "Got style %#x.\n", style);
1862 style = GetWindowLongA(hwnd, GWL_EXSTYLE);
1863 ok(style == WS_EX_WINDOWEDGE, "Got style %#x.\n", style);
1865 hr = IVideoWindow_put_WindowStyleEx(window, style | WS_EX_TRANSPARENT);
1866 ok(hr == S_OK, "Got hr %#x.\n", hr);
1868 hr = IVideoWindow_get_WindowStyleEx(window, &style);
1869 ok(hr == S_OK, "Got hr %#x.\n", hr);
1870 ok(style == (WS_EX_WINDOWEDGE | WS_EX_TRANSPARENT), "Got style %#x.\n", style);
1872 style = GetWindowLongA(hwnd, GWL_EXSTYLE);
1873 ok(style == (WS_EX_WINDOWEDGE | WS_EX_TRANSPARENT), "Got style %#x.\n", style);
1876 static BOOL CALLBACK top_window_cb(HWND hwnd, LPARAM ctx)
1878 DWORD pid;
1879 GetWindowThreadProcessId(hwnd, &pid);
1880 if (pid == GetCurrentProcessId() && (GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE))
1882 *(HWND *)ctx = hwnd;
1883 return FALSE;
1885 return TRUE;
1888 static HWND get_top_window(void)
1890 HWND hwnd;
1891 EnumWindows(top_window_cb, (LPARAM)&hwnd);
1892 return hwnd;
1895 static void test_video_window_state(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
1897 HRESULT hr;
1898 LONG state;
1899 HWND top;
1901 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
1903 hr = IVideoWindow_get_WindowState(window, &state);
1904 ok(hr == S_OK, "Got hr %#x.\n", hr);
1905 ok(state == SW_HIDE, "Got state %d.\n", state);
1907 hr = IVideoWindow_get_Visible(window, &state);
1908 ok(state == OAFALSE, "Got state %d.\n", state);
1910 ok(!IsWindowVisible(hwnd), "Window should not be visible.\n");
1911 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
1912 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
1914 hr = IVideoWindow_put_WindowState(window, SW_SHOWNA);
1915 ok(hr == S_OK, "Got hr %#x.\n", hr);
1917 hr = IVideoWindow_get_WindowState(window, &state);
1918 ok(hr == S_OK, "Got hr %#x.\n", hr);
1919 ok(state == SW_SHOW, "Got state %d.\n", state);
1921 hr = IVideoWindow_get_Visible(window, &state);
1922 ok(state == OATRUE, "Got state %d.\n", state);
1924 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
1925 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
1926 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
1927 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
1928 top = get_top_window();
1929 ok(top == hwnd, "Got top window %p.\n", top);
1931 hr = IVideoWindow_put_WindowState(window, SW_MINIMIZE);
1932 ok(hr == S_OK, "Got hr %#x.\n", hr);
1934 hr = IVideoWindow_get_WindowState(window, &state);
1935 ok(hr == S_OK, "Got hr %#x.\n", hr);
1936 ok(state == SW_MINIMIZE, "Got state %d.\n", state);
1938 hr = IVideoWindow_get_Visible(window, &state);
1939 ok(state == OATRUE, "Got state %d.\n", state);
1941 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
1942 ok(IsIconic(hwnd), "Window should be minimized.\n");
1943 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
1944 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
1946 hr = IVideoWindow_put_WindowState(window, SW_RESTORE);
1947 ok(hr == S_OK, "Got hr %#x.\n", hr);
1949 hr = IVideoWindow_get_WindowState(window, &state);
1950 ok(hr == S_OK, "Got hr %#x.\n", hr);
1951 ok(state == SW_SHOW, "Got state %d.\n", state);
1953 hr = IVideoWindow_get_Visible(window, &state);
1954 ok(state == OATRUE, "Got state %d.\n", state);
1956 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
1957 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
1958 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
1959 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
1961 hr = IVideoWindow_put_WindowState(window, SW_MAXIMIZE);
1962 ok(hr == S_OK, "Got hr %#x.\n", hr);
1964 hr = IVideoWindow_get_WindowState(window, &state);
1965 ok(hr == S_OK, "Got hr %#x.\n", hr);
1966 ok(state == SW_MAXIMIZE, "Got state %d.\n", state);
1968 hr = IVideoWindow_get_Visible(window, &state);
1969 ok(state == OATRUE, "Got state %d.\n", state);
1971 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
1972 ok(!IsIconic(hwnd), "Window should be minimized.\n");
1973 ok(IsZoomed(hwnd), "Window should not be maximized.\n");
1974 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
1976 hr = IVideoWindow_put_WindowState(window, SW_RESTORE);
1977 ok(hr == S_OK, "Got hr %#x.\n", hr);
1979 hr = IVideoWindow_put_WindowState(window, SW_HIDE);
1980 ok(hr == S_OK, "Got hr %#x.\n", hr);
1982 hr = IVideoWindow_get_WindowState(window, &state);
1983 ok(hr == S_OK, "Got hr %#x.\n", hr);
1984 ok(state == SW_HIDE, "Got state %d.\n", state);
1986 hr = IVideoWindow_get_Visible(window, &state);
1987 ok(state == OAFALSE, "Got state %d.\n", state);
1989 ok(!IsWindowVisible(hwnd), "Window should not be visible.\n");
1990 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
1991 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
1992 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
1994 hr = IVideoWindow_put_Visible(window, OATRUE);
1995 ok(hr == S_OK, "Got hr %#x.\n", hr);
1997 hr = IVideoWindow_get_WindowState(window, &state);
1998 ok(hr == S_OK, "Got hr %#x.\n", hr);
1999 ok(state == SW_SHOW, "Got state %d.\n", state);
2001 hr = IVideoWindow_get_Visible(window, &state);
2002 ok(state == OATRUE, "Got state %d.\n", state);
2004 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
2005 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
2006 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
2007 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
2009 hr = IVideoWindow_put_Visible(window, OAFALSE);
2010 ok(hr == S_OK, "Got hr %#x.\n", hr);
2012 hr = IVideoWindow_get_WindowState(window, &state);
2013 ok(hr == S_OK, "Got hr %#x.\n", hr);
2014 ok(state == SW_HIDE, "Got state %d.\n", state);
2016 hr = IVideoWindow_get_Visible(window, &state);
2017 ok(state == OAFALSE, "Got state %d.\n", state);
2019 ok(!IsWindowVisible(hwnd), "Window should not be visible.\n");
2020 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
2021 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
2022 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2024 hr = IVideoWindow_put_WindowState(window, SW_SHOWNA);
2025 ok(hr == S_OK, "Got hr %#x.\n", hr);
2027 hr = IVideoWindow_SetWindowForeground(window, TRUE);
2028 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
2030 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2031 hr = IVideoWindow_SetWindowForeground(window, OATRUE);
2032 ok(hr == S_OK, "Got hr %#x.\n", hr);
2033 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
2034 ok(GetFocus() == hwnd, "Got focus window %p.\n", GetFocus());
2035 ok(GetForegroundWindow() == hwnd, "Got foreground window %p.\n", GetForegroundWindow());
2036 top = get_top_window();
2037 ok(top == hwnd, "Got top window %p.\n", top);
2039 hr = IVideoWindow_SetWindowForeground(window, OAFALSE);
2040 ok(hr == S_OK, "Got hr %#x.\n", hr);
2041 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
2042 ok(GetFocus() == hwnd, "Got focus window %p.\n", GetFocus());
2043 ok(GetForegroundWindow() == hwnd, "Got foreground window %p.\n", GetForegroundWindow());
2044 top = get_top_window();
2045 ok(top == hwnd, "Got top window %p.\n", top);
2047 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2048 hr = IVideoWindow_SetWindowForeground(window, OAFALSE);
2049 ok(hr == S_OK, "Got hr %#x.\n", hr);
2050 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2051 ok(GetFocus() == our_hwnd, "Got focus window %p.\n", GetFocus());
2052 ok(GetForegroundWindow() == our_hwnd, "Got foreground window %p.\n", GetForegroundWindow());
2053 top = get_top_window();
2054 ok(top == hwnd, "Got top window %p.\n", top);
2057 static void test_video_window_position(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
2059 LONG left, width, top, height, expect_width, expect_height;
2060 RECT rect = {0, 0, 600, 400};
2061 HWND top_hwnd;
2062 HRESULT hr;
2064 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2066 AdjustWindowRect(&rect, GetWindowLongA(hwnd, GWL_STYLE), FALSE);
2067 expect_width = rect.right - rect.left;
2068 expect_height = rect.bottom - rect.top;
2070 hr = IVideoWindow_put_Left(window, 0);
2071 ok(hr == S_OK, "Got hr %#x.\n", hr);
2072 hr = IVideoWindow_put_Top(window, 0);
2073 ok(hr == S_OK, "Got hr %#x.\n", hr);
2075 hr = IVideoWindow_get_Left(window, &left);
2076 ok(hr == S_OK, "Got hr %#x.\n", hr);
2077 ok(left == 0, "Got left %d.\n", left);
2078 hr = IVideoWindow_get_Top(window, &top);
2079 ok(hr == S_OK, "Got hr %#x.\n", hr);
2080 ok(top == 0, "Got top %d.\n", top);
2081 hr = IVideoWindow_get_Width(window, &width);
2082 ok(hr == S_OK, "Got hr %#x.\n", hr);
2083 ok(width == expect_width, "Got width %d.\n", width);
2084 hr = IVideoWindow_get_Height(window, &height);
2085 ok(hr == S_OK, "Got hr %#x.\n", hr);
2086 ok(height == expect_height, "Got height %d.\n", height);
2087 hr = IVideoWindow_GetWindowPosition(window, &left, &top, &width, &height);
2088 ok(hr == S_OK, "Got hr %#x.\n", hr);
2089 ok(left == 0, "Got left %d.\n", left);
2090 ok(top == 0, "Got top %d.\n", top);
2091 ok(width == expect_width, "Got width %d.\n", width);
2092 ok(height == expect_height, "Got height %d.\n", height);
2093 GetWindowRect(hwnd, &rect);
2094 ok(rect.left == 0, "Got window left %d.\n", rect.left);
2095 ok(rect.top == 0, "Got window top %d.\n", rect.top);
2096 ok(rect.right == expect_width, "Got window right %d.\n", rect.right);
2097 ok(rect.bottom == expect_height, "Got window bottom %d.\n", rect.bottom);
2099 hr = IVideoWindow_put_Left(window, 10);
2100 ok(hr == S_OK, "Got hr %#x.\n", hr);
2102 hr = IVideoWindow_get_Left(window, &left);
2103 ok(hr == S_OK, "Got hr %#x.\n", hr);
2104 ok(left == 10, "Got left %d.\n", left);
2105 hr = IVideoWindow_get_Top(window, &top);
2106 ok(hr == S_OK, "Got hr %#x.\n", hr);
2107 ok(top == 0, "Got top %d.\n", top);
2108 hr = IVideoWindow_get_Width(window, &width);
2109 ok(hr == S_OK, "Got hr %#x.\n", hr);
2110 ok(width == expect_width, "Got width %d.\n", width);
2111 hr = IVideoWindow_get_Height(window, &height);
2112 ok(hr == S_OK, "Got hr %#x.\n", hr);
2113 ok(height == expect_height, "Got height %d.\n", height);
2114 hr = IVideoWindow_GetWindowPosition(window, &left, &top, &width, &height);
2115 ok(hr == S_OK, "Got hr %#x.\n", hr);
2116 ok(left == 10, "Got left %d.\n", left);
2117 ok(top == 0, "Got top %d.\n", top);
2118 ok(width == expect_width, "Got width %d.\n", width);
2119 ok(height == expect_height, "Got height %d.\n", height);
2120 GetWindowRect(hwnd, &rect);
2121 ok(rect.left == 10, "Got window left %d.\n", rect.left);
2122 ok(rect.top == 0, "Got window top %d.\n", rect.top);
2123 ok(rect.right == 10 + expect_width, "Got window right %d.\n", rect.right);
2124 ok(rect.bottom == expect_height, "Got window bottom %d.\n", rect.bottom);
2126 hr = IVideoWindow_put_Height(window, 200);
2127 ok(hr == S_OK, "Got hr %#x.\n", hr);
2129 hr = IVideoWindow_get_Left(window, &left);
2130 ok(hr == S_OK, "Got hr %#x.\n", hr);
2131 ok(left == 10, "Got left %d.\n", left);
2132 hr = IVideoWindow_get_Top(window, &top);
2133 ok(hr == S_OK, "Got hr %#x.\n", hr);
2134 ok(top == 0, "Got top %d.\n", top);
2135 hr = IVideoWindow_get_Width(window, &width);
2136 ok(hr == S_OK, "Got hr %#x.\n", hr);
2137 ok(width == expect_width, "Got width %d.\n", width);
2138 hr = IVideoWindow_get_Height(window, &height);
2139 ok(hr == S_OK, "Got hr %#x.\n", hr);
2140 ok(height == 200, "Got height %d.\n", height);
2141 hr = IVideoWindow_GetWindowPosition(window, &left, &top, &width, &height);
2142 ok(hr == S_OK, "Got hr %#x.\n", hr);
2143 ok(left == 10, "Got left %d.\n", left);
2144 ok(top == 0, "Got top %d.\n", top);
2145 ok(width == expect_width, "Got width %d.\n", width);
2146 ok(height == 200, "Got height %d.\n", height);
2147 GetWindowRect(hwnd, &rect);
2148 ok(rect.left == 10, "Got window left %d.\n", rect.left);
2149 ok(rect.top == 0, "Got window top %d.\n", rect.top);
2150 ok(rect.right == 10 + expect_width, "Got window right %d.\n", rect.right);
2151 ok(rect.bottom == 200, "Got window bottom %d.\n", rect.bottom);
2153 hr = IVideoWindow_SetWindowPosition(window, 100, 200, 300, 400);
2154 ok(hr == S_OK, "Got hr %#x.\n", hr);
2156 hr = IVideoWindow_get_Left(window, &left);
2157 ok(hr == S_OK, "Got hr %#x.\n", hr);
2158 ok(left == 100, "Got left %d.\n", left);
2159 hr = IVideoWindow_get_Top(window, &top);
2160 ok(hr == S_OK, "Got hr %#x.\n", hr);
2161 ok(top == 200, "Got top %d.\n", top);
2162 hr = IVideoWindow_get_Width(window, &width);
2163 ok(hr == S_OK, "Got hr %#x.\n", hr);
2164 ok(width == 300, "Got width %d.\n", width);
2165 hr = IVideoWindow_get_Height(window, &height);
2166 ok(hr == S_OK, "Got hr %#x.\n", hr);
2167 ok(height == 400, "Got height %d.\n", height);
2168 hr = IVideoWindow_GetWindowPosition(window, &left, &top, &width, &height);
2169 ok(hr == S_OK, "Got hr %#x.\n", hr);
2170 ok(left == 100, "Got left %d.\n", left);
2171 ok(top == 200, "Got top %d.\n", top);
2172 ok(width == 300, "Got width %d.\n", width);
2173 ok(height == 400, "Got height %d.\n", height);
2174 GetWindowRect(hwnd, &rect);
2175 ok(rect.left == 100, "Got window left %d.\n", rect.left);
2176 ok(rect.top == 200, "Got window top %d.\n", rect.top);
2177 ok(rect.right == 400, "Got window right %d.\n", rect.right);
2178 ok(rect.bottom == 600, "Got window bottom %d.\n", rect.bottom);
2180 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2181 top_hwnd = get_top_window();
2182 ok(top_hwnd == our_hwnd, "Got top window %p.\n", top_hwnd);
2185 static void test_video_window_owner(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
2187 HWND parent, top_hwnd;
2188 LONG style, state;
2189 OAHWND oahwnd;
2190 HRESULT hr;
2192 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2194 hr = IVideoWindow_get_Owner(window, &oahwnd);
2195 ok(hr == S_OK, "Got hr %#x.\n", hr);
2196 ok(!oahwnd, "Got owner %#lx.\n", oahwnd);
2198 parent = GetAncestor(hwnd, GA_PARENT);
2199 ok(parent == GetDesktopWindow(), "Got parent %p.\n", parent);
2200 style = GetWindowLongA(hwnd, GWL_STYLE);
2201 ok(!(style & WS_CHILD), "Got style %#x.\n", style);
2203 hr = IVideoWindow_put_Owner(window, (OAHWND)our_hwnd);
2204 ok(hr == S_OK, "Got hr %#x.\n", hr);
2206 hr = IVideoWindow_get_Owner(window, &oahwnd);
2207 ok(hr == S_OK, "Got hr %#x.\n", hr);
2208 ok(oahwnd == (OAHWND)our_hwnd, "Got owner %#lx.\n", oahwnd);
2210 parent = GetAncestor(hwnd, GA_PARENT);
2211 ok(parent == our_hwnd, "Got parent %p.\n", parent);
2212 style = GetWindowLongA(hwnd, GWL_STYLE);
2213 ok((style & WS_CHILD), "Got style %#x.\n", style);
2215 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2216 top_hwnd = get_top_window();
2217 ok(top_hwnd == our_hwnd, "Got top window %p.\n", top_hwnd);
2219 ShowWindow(our_hwnd, SW_HIDE);
2221 hr = IVideoWindow_put_Visible(window, OATRUE);
2222 ok(hr == S_OK, "Got hr %#x.\n", hr);
2224 hr = IVideoWindow_get_Visible(window, &state);
2225 ok(hr == S_OK, "Got hr %#x.\n", hr);
2226 ok(state == OAFALSE, "Got state %d.\n", state);
2228 hr = IVideoWindow_put_Owner(window, 0);
2229 ok(hr == S_OK, "Got hr %#x.\n", hr);
2231 hr = IVideoWindow_get_Owner(window, &oahwnd);
2232 ok(hr == S_OK, "Got hr %#x.\n", hr);
2233 ok(!oahwnd, "Got owner %#lx.\n", oahwnd);
2235 parent = GetAncestor(hwnd, GA_PARENT);
2236 ok(parent == GetDesktopWindow(), "Got parent %p.\n", parent);
2237 style = GetWindowLongA(hwnd, GWL_STYLE);
2238 ok(!(style & WS_CHILD), "Got style %#x.\n", style);
2240 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
2241 top_hwnd = get_top_window();
2242 ok(top_hwnd == hwnd, "Got top window %p.\n", top_hwnd);
2244 hr = IVideoWindow_get_Visible(window, &state);
2245 ok(hr == S_OK, "Got hr %#x.\n", hr);
2246 ok(state == OATRUE, "Got state %d.\n", state);
2249 struct notify_message_params
2251 IVideoWindow *window;
2252 HWND hwnd;
2253 UINT message;
2256 static DWORD CALLBACK notify_message_proc(void *arg)
2258 const struct notify_message_params *params = arg;
2259 HRESULT hr = IVideoWindow_NotifyOwnerMessage(params->window, (OAHWND)params->hwnd, params->message, 0, 0);
2260 ok(hr == S_OK, "Got hr %#x.\n", hr);
2261 return 0;
2264 static void test_video_window_messages(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
2266 struct notify_message_params params;
2267 unsigned int i;
2268 OAHWND oahwnd;
2269 HANDLE thread;
2270 HRESULT hr;
2271 BOOL ret;
2272 MSG msg;
2274 static UINT drain_tests[] =
2276 WM_MOUSEACTIVATE,
2277 WM_NCLBUTTONDOWN,
2278 WM_NCLBUTTONUP,
2279 WM_NCLBUTTONDBLCLK,
2280 WM_NCRBUTTONDOWN,
2281 WM_NCRBUTTONUP,
2282 WM_NCRBUTTONDBLCLK,
2283 WM_NCMBUTTONDOWN,
2284 WM_NCMBUTTONUP,
2285 WM_NCMBUTTONDBLCLK,
2286 WM_KEYDOWN,
2287 WM_KEYUP,
2288 WM_MOUSEMOVE,
2289 WM_LBUTTONDOWN,
2290 WM_LBUTTONUP,
2291 WM_LBUTTONDBLCLK,
2292 WM_RBUTTONDOWN,
2293 WM_RBUTTONUP,
2294 WM_RBUTTONDBLCLK,
2295 WM_MBUTTONDOWN,
2296 WM_MBUTTONUP,
2297 WM_MBUTTONDBLCLK,
2300 flush_events();
2302 hr = IVideoWindow_get_MessageDrain(window, &oahwnd);
2303 ok(hr == S_OK, "Got hr %#x.\n", hr);
2304 ok(!oahwnd, "Got window %#lx.\n", oahwnd);
2306 hr = IVideoWindow_put_MessageDrain(window, (OAHWND)our_hwnd);
2307 ok(hr == S_OK, "Got hr %#x.\n", hr);
2309 hr = IVideoWindow_get_MessageDrain(window, &oahwnd);
2310 ok(hr == S_OK, "Got hr %#x.\n", hr);
2311 ok(oahwnd == (OAHWND)our_hwnd, "Got window %#lx.\n", oahwnd);
2313 for (i = 0; i < ARRAY_SIZE(drain_tests); ++i)
2315 SendMessageA(hwnd, drain_tests[i], 0xdeadbeef, 0);
2316 ret = PeekMessageA(&msg, 0, drain_tests[i], drain_tests[i], PM_REMOVE);
2317 ok(ret, "Expected a message.\n");
2318 ok(msg.hwnd == our_hwnd, "Got hwnd %p.\n", msg.hwnd);
2319 ok(msg.message == drain_tests[i], "Got message %#x.\n", msg.message);
2320 ok(msg.wParam == 0xdeadbeef, "Got wparam %#lx.\n", msg.wParam);
2321 ok(!msg.lParam, "Got lparam %#lx.\n", msg.lParam);
2322 DispatchMessageA(&msg);
2324 ret = PeekMessageA(&msg, 0, drain_tests[i], drain_tests[i], PM_REMOVE);
2325 ok(!ret, "Got unexpected message %#x.\n", msg.message);
2328 hr = IVideoWindow_put_MessageDrain(window, 0);
2329 ok(hr == S_OK, "Got hr %#x.\n", hr);
2331 hr = IVideoWindow_put_Owner(window, (OAHWND)our_hwnd);
2332 ok(hr == S_OK, "Got hr %#x.\n", hr);
2334 flush_events();
2336 hr = IVideoWindow_NotifyOwnerMessage(window, (OAHWND)our_hwnd, WM_SYSCOLORCHANGE, 0, 0);
2337 ok(hr == S_OK, "Got hr %#x.\n", hr);
2339 ret = GetQueueStatus(QS_SENDMESSAGE | QS_POSTMESSAGE);
2340 ok(!ret, "Got unexpected status %#x.\n", ret);
2342 hr = IVideoWindow_NotifyOwnerMessage(window, (OAHWND)our_hwnd, WM_SETCURSOR,
2343 (WPARAM)hwnd, MAKELONG(HTCLIENT, WM_MOUSEMOVE));
2344 ok(hr == S_OK, "Got hr %#x.\n", hr);
2346 ret = GetQueueStatus(QS_SENDMESSAGE | QS_POSTMESSAGE);
2347 ok(!ret, "Got unexpected status %#x.\n", ret);
2349 params.window = window;
2350 params.hwnd = our_hwnd;
2351 params.message = WM_SYSCOLORCHANGE;
2352 thread = CreateThread(NULL, 0, notify_message_proc, &params, 0, NULL);
2353 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block.\n");
2354 ret = GetQueueStatus(QS_SENDMESSAGE | QS_POSTMESSAGE);
2355 ok(ret == ((QS_SENDMESSAGE << 16) | QS_SENDMESSAGE), "Got unexpected status %#x.\n", ret);
2357 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
2358 ok(!WaitForSingleObject(thread, 1000), "Wait timed out.\n");
2359 CloseHandle(thread);
2361 params.message = WM_SETCURSOR;
2362 thread = CreateThread(NULL, 0, notify_message_proc, &params, 0, NULL);
2363 ok(!WaitForSingleObject(thread, 1000), "Thread should not block.\n");
2364 CloseHandle(thread);
2365 ret = GetQueueStatus(QS_SENDMESSAGE | QS_POSTMESSAGE);
2366 ok(!ret, "Got unexpected status %#x.\n", ret);
2368 hr = IVideoWindow_put_Owner(window, 0);
2369 ok(hr == S_OK, "Got hr %#x.\n", hr);
2372 static void test_video_window_autoshow(IVideoWindow *window, IFilterGraph2 *graph, HWND hwnd)
2374 IMediaControl *control;
2375 HRESULT hr;
2376 LONG l;
2378 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
2380 hr = IVideoWindow_get_AutoShow(window, &l);
2381 ok(hr == S_OK, "Got hr %#x.\n", hr);
2382 ok(l == OATRUE, "Got %d.\n", l);
2384 hr = IVideoWindow_put_Visible(window, OAFALSE);
2385 ok(hr == S_OK, "Got hr %#x.\n", hr);
2387 hr = IMediaControl_Pause(control);
2388 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
2390 hr = IVideoWindow_get_Visible(window, &l);
2391 ok(hr == S_OK, "Got hr %#x.\n", hr);
2392 ok(l == OATRUE, "Got %d.\n", l);
2394 hr = IMediaControl_Stop(control);
2395 ok(hr == S_OK, "Got hr %#x.\n", hr);
2397 hr = IVideoWindow_get_Visible(window, &l);
2398 ok(hr == S_OK, "Got hr %#x.\n", hr);
2399 ok(l == OATRUE, "Got %d.\n", l);
2401 hr = IVideoWindow_put_AutoShow(window, OAFALSE);
2402 ok(hr == S_OK, "Got hr %#x.\n", hr);
2404 hr = IVideoWindow_put_Visible(window, OAFALSE);
2405 ok(hr == S_OK, "Got hr %#x.\n", hr);
2407 hr = IMediaControl_Pause(control);
2408 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
2410 hr = IVideoWindow_get_Visible(window, &l);
2411 ok(hr == S_OK, "Got hr %#x.\n", hr);
2412 ok(l == OAFALSE, "Got %d.\n", l);
2414 hr = IMediaControl_Stop(control);
2415 ok(hr == S_OK, "Got hr %#x.\n", hr);
2417 IMediaControl_Release(control);
2420 static void test_video_window(void)
2422 ALLOCATOR_PROPERTIES req_props = {1, 600 * 400 * 4, 1, 0}, ret_props;
2423 VIDEOINFOHEADER vih =
2425 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
2426 .bmiHeader.biBitCount = 32,
2427 .bmiHeader.biWidth = 600,
2428 .bmiHeader.biHeight = 400,
2429 .bmiHeader.biPlanes = 1,
2430 .bmiHeader.biCompression = BI_RGB,
2432 AM_MEDIA_TYPE req_mt =
2434 .majortype = MEDIATYPE_Video,
2435 .subtype = MEDIASUBTYPE_RGB32,
2436 .formattype = FORMAT_VideoInfo,
2437 .cbFormat = sizeof(vih),
2438 .pbFormat = (BYTE *)&vih,
2440 IFilterGraph2 *graph = create_graph();
2441 WNDCLASSA window_class = {0};
2442 struct testfilter source;
2443 IMemAllocator *allocator;
2444 MONITORINFO monitorinfo;
2445 IMediaControl *control;
2446 LONG width, height, l;
2447 IVideoWindow *window;
2448 IMemInputPin *input;
2449 IBaseFilter *filter;
2450 HWND hwnd, our_hwnd;
2451 IOverlay *overlay;
2452 BSTR caption;
2453 HRESULT hr;
2454 DWORD tid;
2455 ULONG ref;
2456 IPin *pin;
2457 RECT rect;
2459 window_class.lpszClassName = "wine_test_class";
2460 window_class.lpfnWndProc = window_proc;
2461 RegisterClassA(&window_class);
2462 our_hwnd = CreateWindowA("wine_test_class", "test window", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
2463 100, 200, 300, 400, NULL, NULL, NULL, NULL);
2464 flush_events();
2466 filter = create_vmr9(VMR9Mode_Windowed);
2467 flush_events();
2469 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2471 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
2472 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
2474 hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay);
2475 ok(hr == S_OK, "Got hr %#x.\n", hr);
2477 hr = IOverlay_GetWindowHandle(overlay, &hwnd);
2478 ok(hr == S_OK, "Got hr %#x.\n", hr);
2479 if (winetest_debug > 1) trace("ours %p, theirs %p\n", our_hwnd, hwnd);
2480 GetWindowRect(hwnd, &rect);
2482 tid = GetWindowThreadProcessId(hwnd, NULL);
2483 ok(tid == GetCurrentThreadId(), "Expected tid %#x, got %#x.\n", GetCurrentThreadId(), tid);
2485 hr = IBaseFilter_QueryInterface(filter, &IID_IVideoWindow, (void **)&window);
2486 ok(hr == S_OK, "Got hr %#x.\n", hr);
2488 hr = IVideoWindow_get_Caption(window, &caption);
2489 todo_wine ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
2491 hr = IVideoWindow_get_WindowStyle(window, &l);
2492 todo_wine ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
2494 hr = IVideoWindow_get_AutoShow(window, &l);
2495 todo_wine ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
2497 testfilter_init(&source);
2498 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL);
2499 IFilterGraph2_AddFilter(graph, filter, NULL);
2500 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
2501 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
2502 if (hr == E_FAIL)
2504 skip("Got E_FAIL when connecting.\n");
2505 goto out;
2507 ok(hr == S_OK, "Got hr %#x.\n", hr);
2509 hr = IMemInputPin_GetAllocator(input, &allocator);
2510 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
2511 if (hr == S_OK)
2513 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
2514 ok(hr == S_OK, "Got hr %#x.\n", hr);
2515 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
2516 hr = IMemAllocator_Commit(allocator);
2517 ok(hr == S_OK, "Got hr %#x.\n", hr);
2518 IMemAllocator_Release(allocator);
2521 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2523 test_video_window_caption(window, hwnd);
2524 test_video_window_style(window, hwnd, our_hwnd);
2525 test_video_window_state(window, hwnd, our_hwnd);
2526 test_video_window_position(window, hwnd, our_hwnd);
2527 test_video_window_autoshow(window, graph, hwnd);
2528 test_video_window_owner(window, hwnd, our_hwnd);
2529 test_video_window_messages(window, hwnd, our_hwnd);
2531 hr = IVideoWindow_put_FullScreenMode(window, OATRUE);
2532 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
2533 hr = IVideoWindow_get_FullScreenMode(window, &l);
2534 ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
2536 hr = IVideoWindow_GetMinIdealImageSize(window, &width, &height);
2537 todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
2538 hr = IVideoWindow_GetMaxIdealImageSize(window, &width, &height);
2539 todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
2541 hr = IMediaControl_Pause(control);
2542 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
2544 monitorinfo.cbSize = sizeof(monitorinfo);
2545 GetMonitorInfoW(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &monitorinfo);
2547 hr = IVideoWindow_GetMinIdealImageSize(window, &width, &height);
2548 ok(hr == S_OK, "Got hr %#x.\n", hr);
2549 todo_wine ok(width == 1, "Got width %d.\n", width);
2550 todo_wine ok(height == 1, "Got height %d.\n", height);
2551 hr = IVideoWindow_GetMaxIdealImageSize(window, &width, &height);
2552 ok(hr == S_OK, "Got hr %#x.\n", hr);
2553 todo_wine ok(width == monitorinfo.rcMonitor.right + 1, "Expected width %d, got %d.\n",
2554 monitorinfo.rcMonitor.right + 1, width);
2555 todo_wine ok(height == monitorinfo.rcMonitor.bottom + 1, "Expected height %d, got %d.\n",
2556 monitorinfo.rcMonitor.bottom + 1, height);
2558 hr = IMediaControl_Stop(control);
2559 ok(hr == S_OK, "Got hr %#x.\n", hr);
2561 out:
2562 IMediaControl_Release(control);
2563 IFilterGraph2_Release(graph);
2564 IVideoWindow_Release(window);
2565 IOverlay_Release(overlay);
2566 IMemInputPin_Release(input);
2567 IPin_Release(pin);
2568 ref = IBaseFilter_Release(filter);
2569 ok(!ref, "Got outstanding refcount %d.\n", ref);
2570 ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface);
2571 ok(!ref, "Got outstanding refcount %d.\n", ref);
2572 DestroyWindow(our_hwnd);
2575 static IDirect3DDevice9 *create_device(HWND window)
2577 D3DPRESENT_PARAMETERS present_parameters =
2579 .Windowed = TRUE,
2580 .hDeviceWindow = window,
2581 .SwapEffect = D3DSWAPEFFECT_DISCARD,
2582 .BackBufferWidth = 640,
2583 .BackBufferHeight = 480,
2584 .BackBufferFormat = D3DFMT_A8R8G8B8,
2586 IDirect3DDevice9 *device;
2587 IDirect3D9 *d3d;
2588 HRESULT hr;
2590 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2591 ok(!!d3d, "Failed to create a D3D object.\n");
2593 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,
2594 D3DCREATE_HARDWARE_VERTEXPROCESSING, &present_parameters, &device);
2595 IDirect3D9_Release(d3d);
2596 if (FAILED(hr))
2598 skip("Failed to create a 3D device, hr %#x.\n", hr);
2599 return NULL;
2601 return device;
2604 static void test_allocate_surface_helper(void)
2606 VMR9AllocationInfo info =
2608 .dwFlags = VMR9AllocFlag_OffscreenSurface,
2609 .dwWidth = 32,
2610 .dwHeight = 16,
2611 .Format = D3DFMT_X8R8G8B8,
2612 .Pool = D3DPOOL_DEFAULT,
2613 .MinBuffers = 2,
2614 .szAspectRatio = {32, 16},
2615 .szNativeSize = {32, 16},
2617 IBaseFilter *filter = create_vmr9(VMR9Mode_Renderless);
2618 IVMRSurfaceAllocatorNotify9 *notify;
2619 IDirect3DSurface9 *surfaces[2] = {};
2620 IDirect3DDevice9 *device, *device2;
2621 RECT rect = {0, 0, 640, 480};
2622 IDirect3DTexture9 *container;
2623 D3DSURFACE_DESC desc;
2624 DWORD count;
2625 HWND window;
2626 HRESULT hr;
2627 ULONG ref;
2629 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
2630 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0,
2631 rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, NULL, NULL);
2632 if (!(device = create_device(window)))
2634 IBaseFilter_Release(filter);
2635 DestroyWindow(window);
2636 return;
2639 IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)&notify);
2641 count = 2;
2642 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2643 todo_wine ok(hr == E_FAIL, "Got hr %#x.\n", hr);
2645 hr = IVMRSurfaceAllocatorNotify9_SetD3DDevice(notify, device, MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY));
2646 if (hr == E_NOINTERFACE)
2648 win_skip("Direct3D does not support video rendering.\n");
2649 goto out;
2651 ok(hr == S_OK, "Got hr %#x.\n", hr);
2653 if (0) /* crashes on Windows */
2655 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, NULL, &count, surfaces);
2656 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
2658 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, NULL, surfaces);
2659 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
2662 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, NULL);
2663 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
2665 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2666 ok(hr == S_OK, "Got hr %#x.\n", hr);
2667 ok(count == 2, "Got count %u.\n", count);
2668 ok(!!surfaces[0], "Surface 0 was not allocated.\n");
2669 ok(!!surfaces[1], "Surface 1 was not allocated.\n");
2671 hr = IDirect3DSurface9_GetDevice(surfaces[0], &device2);
2672 ok(hr == D3D_OK, "Got hr %#x.\n", hr);
2673 ok(device2 == device, "Devices did not match.\n");
2674 IDirect3DDevice9_Release(device2);
2676 hr = IDirect3DSurface9_GetContainer(surfaces[0], &IID_IDirect3DTexture9, (void **)&container);
2677 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
2679 hr = IDirect3DSurface9_GetDesc(surfaces[0], &desc);
2680 ok(hr == D3D_OK, "Got hr %#x.\n", hr);
2681 ok(desc.Format == info.Format, "Got format %#x.\n", desc.Format);
2682 ok(desc.Type == D3DRTYPE_SURFACE, "Got type %u.\n", desc.Type);
2683 ok(!desc.Usage, "Got usage %#x.\n", desc.Usage);
2684 ok(desc.Pool == D3DPOOL_DEFAULT, "Got pool %u.\n", desc.Pool);
2685 ok(desc.MultiSampleType == D3DMULTISAMPLE_NONE, "Got multisample type %u.\n", desc.MultiSampleType);
2686 ok(!desc.MultiSampleQuality, "Got multisample quality %u.\n", desc.MultiSampleQuality);
2687 ok(desc.Width == 32, "Got width %u.\n", desc.Width);
2688 ok(desc.Height == 16, "Got height %u.\n", desc.Height);
2690 IDirect3DSurface9_Release(surfaces[0]);
2691 IDirect3DSurface9_Release(surfaces[1]);
2693 surfaces[0] = surfaces[1] = NULL;
2694 count = 1;
2695 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2696 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
2697 todo_wine ok(!count, "Got count %u.\n", count);
2698 ok(!surfaces[0], "Surface 0 was allocated.\n");
2699 ok(!surfaces[1], "Surface 1 was allocated.\n");
2701 count = 2;
2702 info.MinBuffers = 1;
2703 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2704 ok(hr == S_OK, "Got hr %#x.\n", hr);
2705 ok(count == 2, "Got count %u.\n", count);
2706 ok(!!surfaces[0], "Surface 0 was not allocated.\n");
2707 ok(!!surfaces[1], "Surface 1 was not allocated.\n");
2708 IDirect3DSurface9_Release(surfaces[0]);
2709 IDirect3DSurface9_Release(surfaces[1]);
2711 count = 2;
2712 info.dwFlags = VMR9AllocFlag_TextureSurface;
2713 surfaces[0] = surfaces[1] = NULL;
2714 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2715 ok(hr == S_OK, "Got hr %#x.\n", hr);
2716 ok(count == 2, "Got count %u.\n", count);
2717 ok(!!surfaces[0], "Surface 0 was not allocated.\n");
2718 ok(!!surfaces[1], "Surface 1 was not allocated.\n");
2720 hr = IDirect3DSurface9_GetDevice(surfaces[0], &device2);
2721 ok(hr == D3D_OK, "Got hr %#x.\n", hr);
2722 ok(device2 == device, "Devices did not match.\n");
2723 IDirect3DDevice9_Release(device2);
2725 hr = IDirect3DSurface9_GetContainer(surfaces[0], &IID_IDirect3DTexture9, (void **)&container);
2726 ok(hr == D3D_OK, "Got hr %#x.\n", hr);
2727 IDirect3DTexture9_Release(container);
2729 hr = IDirect3DSurface9_GetDesc(surfaces[1], &desc);
2730 ok(hr == D3D_OK, "Got hr %#x.\n", hr);
2731 ok(desc.Format == info.Format, "Got format %#x.\n", desc.Format);
2732 ok(desc.Type == D3DRTYPE_SURFACE, "Got type %u.\n", desc.Type);
2733 ok(desc.Usage == D3DUSAGE_DYNAMIC, "Got usage %#x.\n", desc.Usage);
2734 ok(desc.Pool == D3DPOOL_DEFAULT, "Got pool %u.\n", desc.Pool);
2735 ok(desc.MultiSampleType == D3DMULTISAMPLE_NONE, "Got multisample type %u.\n", desc.MultiSampleType);
2736 ok(!desc.MultiSampleQuality, "Got multisample quality %u.\n", desc.MultiSampleQuality);
2737 ok(desc.Width == 32, "Got width %u.\n", desc.Width);
2738 ok(desc.Height == 16, "Got height %u.\n", desc.Height);
2740 IDirect3DSurface9_Release(surfaces[0]);
2741 IDirect3DSurface9_Release(surfaces[1]);
2743 info.Format = D3DFMT_R8G8B8;
2744 surfaces[0] = surfaces[1] = NULL;
2745 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2746 ok(hr == D3DERR_INVALIDCALL, "Got hr %#x.\n", hr);
2747 ok(!count, "Got count %u.\n", count);
2748 ok(!surfaces[0], "Surface 0 was allocated.\n");
2749 ok(!surfaces[1], "Surface 1 was allocated.\n");
2751 info.Format = 0;
2752 info.dwFlags = VMR9AllocFlag_3DRenderTarget;
2753 count = 1;
2754 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2755 ok(hr == S_OK, "Got hr %#x.\n", hr);
2756 ok(count == 1, "Got count %u.\n", count);
2757 ok(!!surfaces[0], "Surface 0 was not allocated.\n");
2758 ok(info.Format != 0, "Expected a format.\n");
2760 hr = IDirect3DSurface9_GetDesc(surfaces[0], &desc);
2761 ok(hr == D3D_OK, "Got hr %#x.\n", hr);
2762 ok(desc.Format == info.Format, "Expected format %#x, got %#x.\n", info.Format, desc.Format);
2763 ok(desc.Type == D3DRTYPE_SURFACE, "Got type %u.\n", desc.Type);
2764 ok(desc.Usage == D3DUSAGE_RENDERTARGET, "Got usage %#x.\n", desc.Usage);
2765 ok(desc.Pool == D3DPOOL_DEFAULT, "Got pool %u.\n", desc.Pool);
2766 ok(desc.MultiSampleType == D3DMULTISAMPLE_NONE, "Got multisample type %u.\n", desc.MultiSampleType);
2767 ok(!desc.MultiSampleQuality, "Got multisample quality %u.\n", desc.MultiSampleQuality);
2768 ok(desc.Width == 32, "Got width %u.\n", desc.Width);
2769 ok(desc.Height == 16, "Got height %u.\n", desc.Height);
2771 IDirect3DSurface9_Release(surfaces[0]);
2773 info.Format = D3DFMT_A8R8G8B8;
2774 info.dwFlags = VMR9AllocFlag_OffscreenSurface | VMR9AllocFlag_TextureSurface;
2775 count = 1;
2776 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2777 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
2778 ok(count == 1, "Got count %u.\n", count);
2780 out:
2781 IVMRSurfaceAllocatorNotify9_Release(notify);
2782 ref = IBaseFilter_Release(filter);
2783 ok(!ref, "Got outstanding refcount %d.\n", ref);
2784 ref = IDirect3DDevice9_Release(device);
2785 ok(!ref, "Got outstanding refcount %d.\n", ref);
2786 DestroyWindow(window);
2789 struct presenter
2791 IVMRSurfaceAllocator9 IVMRSurfaceAllocator9_iface;
2792 IVMRImagePresenter9 IVMRImagePresenter9_iface;
2793 LONG refcount;
2795 D3DFORMAT format;
2796 DWORD accept_flags;
2797 IDirect3DSurface9 *surfaces[5];
2798 IVMRSurfaceAllocatorNotify9 *notify;
2799 unsigned int got_PresentImage, got_TerminateDevice;
2802 static struct presenter *impl_from_IVMRImagePresenter9(IVMRImagePresenter9 *iface)
2804 return CONTAINING_RECORD(iface, struct presenter, IVMRImagePresenter9_iface);
2807 static HRESULT WINAPI presenter_QueryInterface(IVMRImagePresenter9 *iface, REFIID iid, void **out)
2809 struct presenter *presenter = impl_from_IVMRImagePresenter9(iface);
2810 return IVMRSurfaceAllocator9_QueryInterface(&presenter->IVMRSurfaceAllocator9_iface, iid, out);
2813 static ULONG WINAPI presenter_AddRef(IVMRImagePresenter9 *iface)
2815 struct presenter *presenter = impl_from_IVMRImagePresenter9(iface);
2816 return IVMRSurfaceAllocator9_AddRef(&presenter->IVMRSurfaceAllocator9_iface);
2819 static ULONG WINAPI presenter_Release(IVMRImagePresenter9 *iface)
2821 struct presenter *presenter = impl_from_IVMRImagePresenter9(iface);
2822 return IVMRSurfaceAllocator9_Release(&presenter->IVMRSurfaceAllocator9_iface);
2825 static HRESULT WINAPI presenter_StartPresenting(IVMRImagePresenter9 *iface, DWORD_PTR cookie)
2827 if (winetest_debug > 1) trace("StartPresenting()\n");
2828 ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
2829 return E_NOTIMPL;
2832 static HRESULT WINAPI presenter_StopPresenting(IVMRImagePresenter9 *iface, DWORD_PTR cookie)
2834 if (winetest_debug > 1) trace("StopPresenting()\n");
2835 ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
2836 return E_NOTIMPL;
2839 static HRESULT WINAPI presenter_PresentImage(IVMRImagePresenter9 *iface, DWORD_PTR cookie, VMR9PresentationInfo *info)
2841 struct presenter *presenter = impl_from_IVMRImagePresenter9(iface);
2842 static const RECT rect;
2844 if (winetest_debug > 1) trace("PresentImage()\n");
2845 ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
2846 todo_wine ok(info->dwFlags == VMR9Sample_TimeValid, "Got flags %#x.\n", info->dwFlags);
2847 ok(!info->rtStart, "Got start time %s.\n", wine_dbgstr_longlong(info->rtStart));
2848 ok(info->rtEnd == 10000000, "Got end time %s.\n", wine_dbgstr_longlong(info->rtEnd));
2849 todo_wine ok(info->szAspectRatio.cx == 120, "Got aspect ratio width %d.\n", info->szAspectRatio.cx);
2850 todo_wine ok(info->szAspectRatio.cy == 60, "Got aspect ratio height %d.\n", info->szAspectRatio.cy);
2851 ok(EqualRect(&info->rcSrc, &rect), "Got source rect %s.\n", wine_dbgstr_rect(&info->rcSrc));
2852 ok(EqualRect(&info->rcDst, &rect), "Got dest rect %s.\n", wine_dbgstr_rect(&info->rcDst));
2853 ok(!info->dwReserved1, "Got dwReserved1 %#x.\n", info->dwReserved1);
2854 ok(!info->dwReserved2, "Got dwReserved2 %#x.\n", info->dwReserved2);
2856 ++presenter->got_PresentImage;
2857 return S_OK;
2860 static const IVMRImagePresenter9Vtbl presenter_vtbl =
2862 presenter_QueryInterface,
2863 presenter_AddRef,
2864 presenter_Release,
2865 presenter_StartPresenting,
2866 presenter_StopPresenting,
2867 presenter_PresentImage,
2870 static struct presenter *impl_from_IVMRSurfaceAllocator9(IVMRSurfaceAllocator9 *iface)
2872 return CONTAINING_RECORD(iface, struct presenter, IVMRSurfaceAllocator9_iface);
2875 static HRESULT WINAPI allocator_QueryInterface(IVMRSurfaceAllocator9 *iface, REFIID iid, void **out)
2877 struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
2879 if (winetest_debug > 1) trace("QueryInterface(%s)\n", wine_dbgstr_guid(iid));
2881 if (IsEqualGUID(iid, &IID_IVMRImagePresenter9))
2883 *out = &presenter->IVMRImagePresenter9_iface;
2884 IVMRImagePresenter9_AddRef(&presenter->IVMRImagePresenter9_iface);
2885 return S_OK;
2887 ok(!IsEqualGUID(iid, &IID_IVMRSurfaceAllocatorEx9), "Unexpected query for IVMRSurfaceAllocatorEx9.\n");
2888 *out = NULL;
2889 return E_NOTIMPL;
2892 static ULONG WINAPI allocator_AddRef(IVMRSurfaceAllocator9 *iface)
2894 struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
2895 return InterlockedIncrement(&presenter->refcount);
2898 static ULONG WINAPI allocator_Release(IVMRSurfaceAllocator9 *iface)
2900 struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
2901 return InterlockedDecrement(&presenter->refcount);
2904 static HRESULT WINAPI allocator_InitializeDevice(IVMRSurfaceAllocator9 *iface,
2905 DWORD_PTR cookie, VMR9AllocationInfo *info, DWORD *buffer_count)
2907 struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
2909 if (winetest_debug > 1) trace("InitializeDevice(flags %#x, format %u)\n",
2910 info->dwFlags, info->Format);
2911 ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
2912 ok(info->dwWidth == 32, "Got width %u.\n", info->dwWidth);
2913 ok(info->dwHeight == 16, "Got height %u.\n", info->dwHeight);
2914 todo_wine ok(info->MinBuffers == 5, "Got buffer count %u.\n", info->MinBuffers);
2915 ok(info->Pool == D3DPOOL_DEFAULT, "Got pool %u\n", info->Pool);
2916 todo_wine ok(info->szAspectRatio.cx == 120, "Got aspect ratio width %d.\n", info->szAspectRatio.cx);
2917 todo_wine ok(info->szAspectRatio.cy == 60, "Got aspect ratio height %d.\n", info->szAspectRatio.cy);
2918 ok(info->szNativeSize.cx == 32, "Got native width %d.\n", info->szNativeSize.cx);
2919 ok(info->szNativeSize.cy == 16, "Got native height %d.\n", info->szNativeSize.cy);
2920 todo_wine ok(*buffer_count == 5, "Got buffer count %u.\n", *buffer_count);
2922 presenter->format = info->Format;
2924 if (info->dwFlags != presenter->accept_flags)
2925 return 0xdeadbeef;
2926 return IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(presenter->notify,
2927 info, buffer_count, presenter->surfaces);
2930 static HRESULT WINAPI allocator_TerminateDevice(IVMRSurfaceAllocator9 *iface, DWORD_PTR cookie)
2932 struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
2934 if (winetest_debug > 1) trace("TerminateDevice()\n");
2935 ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
2936 /* Don't dereference the surfaces here, to mimic How to Survive. */
2937 ++presenter->got_TerminateDevice;
2938 return E_NOTIMPL;
2941 static HRESULT WINAPI allocator_GetSurface(IVMRSurfaceAllocator9 *iface,
2942 DWORD_PTR cookie, DWORD index, DWORD flags, IDirect3DSurface9 **surface)
2944 struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
2946 if (winetest_debug > 1) trace("GetSurface(index %u)\n", index);
2947 ok(cookie == 0xabacab, "Got cookie %#lx.\n", cookie);
2948 ok(!flags, "Got flags %#x.\n", flags);
2949 ok(index < 5, "Got index %u.\n", index);
2951 /* Don't reference the surface here, to mimic How to Survive. */
2952 *surface = presenter->surfaces[index];
2953 return S_OK;
2956 static HRESULT WINAPI allocator_AdviseNotify(IVMRSurfaceAllocator9 *iface, IVMRSurfaceAllocatorNotify9 *notify)
2958 ok(0, "Unexpected call.\n");
2959 return E_NOTIMPL;
2962 static const IVMRSurfaceAllocator9Vtbl allocator_vtbl =
2964 allocator_QueryInterface,
2965 allocator_AddRef,
2966 allocator_Release,
2967 allocator_InitializeDevice,
2968 allocator_TerminateDevice,
2969 allocator_GetSurface,
2970 allocator_AdviseNotify,
2973 static void test_renderless_present(struct presenter *presenter,
2974 IFilterGraph2 *graph, IMemInputPin *input)
2976 IMediaControl *control;
2977 OAFilterState state;
2978 HANDLE thread;
2979 HRESULT hr;
2981 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
2983 presenter->got_PresentImage = 0;
2985 hr = IMediaControl_Pause(control);
2986 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
2987 thread = send_frame(input);
2988 hr = IMediaControl_GetState(control, 1000, &state);
2989 ok(hr == S_OK, "Got hr %#x.\n", hr);
2990 /* Atelier Sophie uses the VMR in renderless mode, calls
2991 * IMediaControl::Run() from a stopped state and expects that
2992 * IMediaControl::GetState() returns S_OK only after PresentImage() has
2993 * been called. */
2994 ok(presenter->got_PresentImage == 1, "Got %u calls to PresentImage().\n", presenter->got_PresentImage);
2996 hr = IMediaControl_Run(control);
2997 ok(hr == S_OK, "Got hr %#x.\n", hr);
2998 hr = join_thread(thread);
2999 ok(hr == S_OK, "Got hr %#x.\n", hr);
3000 ok(presenter->got_PresentImage == 1, "Got %u calls to PresentImage().\n", presenter->got_PresentImage);
3002 hr = IMediaControl_Stop(control);
3003 ok(hr == S_OK, "Got hr %#x.\n", hr);
3005 IMediaControl_Release(control);
3008 static void test_renderless_formats(void)
3010 VIDEOINFOHEADER vih =
3012 .rcSource = {4, 6, 16, 12},
3013 .rcTarget = {40, 60, 160, 120},
3014 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
3015 .bmiHeader.biWidth = 32,
3016 .bmiHeader.biHeight = 16,
3018 AM_MEDIA_TYPE req_mt =
3020 .majortype = MEDIATYPE_Video,
3021 .formattype = FORMAT_VideoInfo,
3022 .cbFormat = sizeof(vih),
3023 .pbFormat = (BYTE *)&vih,
3025 ALLOCATOR_PROPERTIES req_props = {5, 32 * 16 * 4, 1, 0}, ret_props;
3026 struct presenter presenter =
3028 .IVMRSurfaceAllocator9_iface.lpVtbl = &allocator_vtbl,
3029 .IVMRImagePresenter9_iface.lpVtbl = &presenter_vtbl,
3030 .refcount = 1,
3032 struct presenter presenter2 = presenter;
3033 IVMRSurfaceAllocatorNotify9 *notify;
3034 RECT rect = {0, 0, 640, 480};
3035 struct testfilter source;
3036 IDirect3DDevice9 *device;
3037 IMemAllocator *allocator;
3038 IFilterGraph2 *graph;
3039 IMemInputPin *input;
3040 IBaseFilter *filter;
3041 unsigned int i;
3042 HWND window;
3043 HRESULT hr;
3044 ULONG ref;
3045 IPin *pin;
3047 static const struct
3049 const GUID *subtype;
3050 D3DFORMAT format;
3051 DWORD flags;
3053 tests[] =
3055 {&MEDIASUBTYPE_ARGB1555, D3DFMT_A1R5G5B5, VMR9AllocFlag_TextureSurface},
3056 {&MEDIASUBTYPE_ARGB32, D3DFMT_A8R8G8B8, VMR9AllocFlag_TextureSurface},
3057 {&MEDIASUBTYPE_ARGB4444, D3DFMT_A4R4G4B4, VMR9AllocFlag_TextureSurface},
3059 {&MEDIASUBTYPE_RGB555, D3DFMT_X1R5G5B5, VMR9AllocFlag_OffscreenSurface},
3060 {&MEDIASUBTYPE_RGB555, D3DFMT_X1R5G5B5, VMR9AllocFlag_TextureSurface},
3061 {&MEDIASUBTYPE_RGB565, D3DFMT_R5G6B5, VMR9AllocFlag_OffscreenSurface},
3062 {&MEDIASUBTYPE_RGB565, D3DFMT_R5G6B5, VMR9AllocFlag_TextureSurface},
3063 {&MEDIASUBTYPE_RGB24, D3DFMT_R8G8B8, VMR9AllocFlag_OffscreenSurface},
3064 {&MEDIASUBTYPE_RGB24, D3DFMT_R8G8B8, VMR9AllocFlag_TextureSurface},
3065 {&MEDIASUBTYPE_RGB32, D3DFMT_X8R8G8B8, VMR9AllocFlag_OffscreenSurface},
3066 {&MEDIASUBTYPE_RGB32, D3DFMT_X8R8G8B8, VMR9AllocFlag_TextureSurface},
3068 {&MEDIASUBTYPE_NV12, MAKEFOURCC('N','V','1','2'), VMR9AllocFlag_OffscreenSurface},
3069 {&MEDIASUBTYPE_UYVY, D3DFMT_UYVY, VMR9AllocFlag_OffscreenSurface},
3070 {&MEDIASUBTYPE_YUY2, D3DFMT_YUY2, VMR9AllocFlag_OffscreenSurface},
3071 {&MEDIASUBTYPE_YV12, MAKEFOURCC('Y','V','1','2'), VMR9AllocFlag_OffscreenSurface},
3074 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
3075 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0,
3076 rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, NULL, NULL);
3077 if (!(device = create_device(window)))
3079 DestroyWindow(window);
3080 return;
3083 filter = create_vmr9(VMR9Mode_Renderless);
3084 IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)&notify);
3086 hr = IVMRSurfaceAllocatorNotify9_SetD3DDevice(notify, device, MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY));
3087 if (hr == E_NOINTERFACE)
3089 win_skip("Direct3D does not support video rendering.\n");
3090 goto out;
3092 ok(hr == S_OK, "Got hr %#x.\n", hr);
3094 hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab,
3095 &presenter.IVMRSurfaceAllocator9_iface);
3096 ok(hr == S_OK, "Got hr %#x.\n", hr);
3098 presenter.notify = notify;
3100 testfilter_init(&source);
3101 graph = create_graph();
3102 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL);
3103 IFilterGraph2_AddFilter(graph, filter, NULL);
3104 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
3105 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
3107 for (i = 0; i < ARRAY_SIZE(tests); ++i)
3109 req_mt.subtype = *tests[i].subtype;
3110 presenter.accept_flags = tests[i].flags;
3112 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
3113 /* Connection never fails on Native, but Wine currently creates D3D
3114 * surfaces during IPin::ReceiveConnection() instead of
3115 * IMemAllocator::SetProperties(), so let that fail here for now. */
3116 if (hr != S_OK)
3118 skip("Format %u (%#x), flags %#x are not supported, hr %#x.\n",
3119 tests[i].format, tests[i].format, tests[i].flags, hr);
3120 continue;
3122 ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3124 hr = IMemInputPin_GetAllocator(input, &allocator);
3125 todo_wine ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3126 if (hr != S_OK)
3128 test_allocator(input);
3129 hr = IMemInputPin_GetAllocator(input, &allocator);
3132 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
3133 if (hr != S_OK)
3135 skip("Format %u (%#x), flags %#x are not supported, hr %#x.\n",
3136 tests[i].format, tests[i].format, tests[i].flags, hr);
3137 IMemAllocator_Release(allocator);
3138 hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
3139 ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3140 hr = IFilterGraph2_Disconnect(graph, pin);
3141 ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3142 continue;
3144 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
3145 hr = IMemAllocator_Commit(allocator);
3146 ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3148 hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab,
3149 &presenter2.IVMRSurfaceAllocator9_iface);
3150 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
3152 ok(presenter.format == tests[i].format, "Test %u: Got format %u (%#x).\n",
3153 i, presenter.format, presenter.format);
3155 test_renderless_present(&presenter, graph, input);
3157 hr = IMemAllocator_Decommit(allocator);
3158 ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3159 IMemAllocator_Release(allocator);
3161 hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
3162 ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3163 hr = IFilterGraph2_Disconnect(graph, pin);
3164 ok(hr == S_OK, "Test %u: Got hr %#x.\n", i, hr);
3167 hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab, &presenter2.IVMRSurfaceAllocator9_iface);
3168 ok(hr == S_OK, "Got hr %#x.\n", hr);
3170 ref = IFilterGraph2_Release(graph);
3171 ok(!ref, "Got outstanding refcount %d.\n", ref);
3172 IMemInputPin_Release(input);
3173 IPin_Release(pin);
3175 out:
3176 IVMRSurfaceAllocatorNotify9_Release(notify);
3177 ref = IBaseFilter_Release(filter);
3178 ok(!ref, "Got outstanding refcount %d.\n", ref);
3179 ok(presenter.refcount == 1, "Got outstanding refcount %d.\n", presenter.refcount);
3180 ok(presenter2.refcount == 1, "Got outstanding refcount %d.\n", presenter2.refcount);
3181 ref = IDirect3DDevice9_Release(device);
3182 ok(!ref, "Got outstanding refcount %d.\n", ref);
3183 DestroyWindow(window);
3186 static void test_mixing_mode(void)
3188 IVMRWindowlessControl9 *windowless_control;
3189 IVMRMixerControl9 *mixer_control;
3190 IVMRFilterConfig9 *config;
3191 DWORD stream_count = 0;
3192 IBaseFilter *filter;
3193 unsigned int i;
3194 HWND window;
3195 HRESULT hr;
3196 ULONG ref;
3198 static const VMR9Mode modes[] =
3201 VMR9Mode_Windowed,
3202 VMR9Mode_Windowless,
3203 VMR9Mode_Renderless,
3206 for (i = 0; i < ARRAY_SIZE(modes); ++i)
3208 filter = create_vmr9(modes[i]);
3209 IBaseFilter_QueryInterface(filter, &IID_IVMRFilterConfig9, (void **)&config);
3211 hr = IBaseFilter_QueryInterface(filter, &IID_IVMRMixerControl9, (void **)&mixer_control);
3212 ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
3214 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3215 ok(hr == VFW_E_VMR_NOT_IN_MIXER_MODE, "Got hr %#x.\n", hr);
3217 hr = IVMRFilterConfig9_SetNumberOfStreams(config, 1);
3218 ok(hr == S_OK, "Got hr %#x.\n", hr);
3220 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3221 ok(hr == S_OK, "Got hr %#x.\n", hr);
3222 ok(stream_count == 1, "Got %u streams.\n", stream_count);
3224 hr = IBaseFilter_QueryInterface(filter, &IID_IVMRMixerControl9, (void **)&mixer_control);
3225 ok(hr == S_OK, "Got hr %#x.\n", hr);
3226 IVMRMixerControl9_Release(mixer_control);
3228 hr = IVMRFilterConfig9_SetNumberOfStreams(config, 2);
3229 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
3231 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3232 ok(hr == S_OK, "Got hr %#x.\n", hr);
3233 ok(stream_count == 1, "Got %u streams.\n", stream_count);
3235 IVMRFilterConfig9_Release(config);
3236 ref = IBaseFilter_Release(filter);
3237 ok(!ref, "Got outstanding refcount %d.\n", ref);
3240 filter = create_vmr9(VMR9Mode_Windowless);
3241 IBaseFilter_QueryInterface(filter, &IID_IVMRFilterConfig9, (void **)&config);
3242 IBaseFilter_QueryInterface(filter, &IID_IVMRWindowlessControl9, (void **)&windowless_control);
3244 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
3245 ok(!!window, "Failed to create a window.\n");
3246 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, window);
3247 ok(hr == S_OK, "Got hr %#x.\n", hr);
3249 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3250 ok(hr == S_OK, "Got hr %#x.\n", hr);
3251 ok(stream_count == 4, "Got %u streams.\n", stream_count);
3253 hr = IBaseFilter_QueryInterface(filter, &IID_IVMRMixerControl9, (void **)&mixer_control);
3254 ok(hr == S_OK, "Got hr %#x.\n", hr);
3255 IVMRMixerControl9_Release(mixer_control);
3257 hr = IVMRFilterConfig9_SetNumberOfStreams(config, 2);
3258 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
3260 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3261 ok(hr == S_OK, "Got hr %#x.\n", hr);
3262 ok(stream_count == 4, "Got %u streams.\n", stream_count);
3264 IVMRWindowlessControl9_Release(windowless_control);
3265 IVMRFilterConfig9_Release(config);
3266 ref = IBaseFilter_Release(filter);
3267 ok(!ref, "Got outstanding refcount %d.\n", ref);
3268 DestroyWindow(window);
3271 static void test_clipping_window(void)
3273 VIDEOINFOHEADER vih =
3275 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
3276 .bmiHeader.biWidth = 32,
3277 .bmiHeader.biHeight = 16,
3278 .bmiHeader.biBitCount = 32,
3280 AM_MEDIA_TYPE mt =
3282 .majortype = MEDIATYPE_Video,
3283 .subtype = MEDIASUBTYPE_RGB32,
3284 .formattype = FORMAT_VideoInfo,
3285 .cbFormat = sizeof(vih),
3286 .pbFormat = (BYTE *)&vih,
3288 IBaseFilter *filter = create_vmr9(VMR9Mode_Windowless);
3289 IVMRWindowlessControl9 *windowless_control;
3290 IFilterGraph2 *graph = create_graph();
3291 struct testfilter source;
3292 HWND window;
3293 HRESULT hr;
3294 ULONG ref;
3295 IPin *pin;
3297 IBaseFilter_QueryInterface(filter, &IID_IVMRWindowlessControl9, (void **)&windowless_control);
3298 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
3299 testfilter_init(&source);
3300 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, L"source");
3301 IFilterGraph2_AddFilter(graph, filter, L"vmr9");
3302 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
3303 ok(!!window, "Failed to create a window.\n");
3305 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, NULL);
3306 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3307 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, (HWND)0xdeadbeef);
3308 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3310 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &mt);
3311 ok(hr == S_OK, "Got hr %#x.\n", hr);
3313 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, window);
3314 ok(hr == VFW_E_WRONG_STATE, "Got hr %#x.\n", hr);
3316 hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
3317 ok(hr == S_OK, "Got hr %#x.\n", hr);
3318 hr = IFilterGraph2_Disconnect(graph, pin);
3319 ok(hr == S_OK, "Got hr %#x.\n", hr);
3321 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, window);
3322 ok(hr == S_OK, "Got hr %#x.\n", hr);
3324 ref = IFilterGraph2_Release(graph);
3325 ok(!ref, "Got outstanding refcount %d.\n", ref);
3326 IPin_Release(pin);
3327 IVMRWindowlessControl9_Release(windowless_control);
3328 ref = IBaseFilter_Release(filter);
3329 ok(!ref, "Got outstanding refcount %d.\n", ref);
3330 DestroyWindow(window);
3333 static void test_surface_allocator_notify_refcount(void)
3335 struct presenter presenter =
3337 .IVMRSurfaceAllocator9_iface.lpVtbl = &allocator_vtbl,
3338 .IVMRImagePresenter9_iface.lpVtbl = &presenter_vtbl,
3339 .refcount = 1,
3341 IBaseFilter *filter = create_vmr9(VMR9Mode_Renderless);
3342 IVMRSurfaceAllocatorNotify9 *notify;
3343 HRESULT hr;
3344 ULONG ref;
3346 set_mixing_mode(filter, 2);
3348 IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)&notify);
3350 hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab,
3351 &presenter.IVMRSurfaceAllocator9_iface);
3352 ok(hr == S_OK, "Got hr %#x.\n", hr);
3354 ref = IBaseFilter_Release(filter);
3355 ok(!ref, "Got outstanding refcount %d.\n", ref);
3356 ok(presenter.got_TerminateDevice == 1, "Got %u calls to TerminateDevice().\n",
3357 presenter.got_TerminateDevice);
3358 ok(presenter.refcount == 1, "Got outstanding refcount %d.\n", presenter.refcount);
3360 ref = IVMRSurfaceAllocatorNotify9_Release(notify);
3361 ok(!ref, "Got outstanding refcount %d.\n", ref);
3364 static void check_source_position_(int line, IBasicVideo *video,
3365 LONG expect_left, LONG expect_top, LONG expect_width, LONG expect_height)
3367 LONG left, top, width, height, l;
3368 HRESULT hr;
3370 left = top = width = height = 0xdeadbeef;
3371 hr = IBasicVideo_GetSourcePosition(video, &left, &top, &width, &height);
3372 ok_(__FILE__,line)(hr == S_OK, "Got hr %#x.\n", hr);
3373 ok_(__FILE__,line)(left == expect_left, "Got left %d.\n", left);
3374 ok_(__FILE__,line)(top == expect_top, "Got top %d.\n", top);
3375 ok_(__FILE__,line)(width == expect_width, "Got width %d.\n", width);
3376 ok_(__FILE__,line)(height == expect_height, "Got height %d.\n", height);
3378 l = 0xdeadbeef;
3379 hr = IBasicVideo_get_SourceLeft(video, &l);
3380 ok_(__FILE__,line)(hr == S_OK, "Failed to get left, hr %#x.\n", hr);
3381 ok_(__FILE__,line)(l == left, "Got left %d.\n", l);
3383 l = 0xdeadbeef;
3384 hr = IBasicVideo_get_SourceTop(video, &l);
3385 ok_(__FILE__,line)(hr == S_OK, "Failed to get top, hr %#x.\n", hr);
3386 ok_(__FILE__,line)(l == top, "Got top %d.\n", l);
3388 l = 0xdeadbeef;
3389 hr = IBasicVideo_get_SourceWidth(video, &l);
3390 ok_(__FILE__,line)(hr == S_OK, "Failed to get width, hr %#x.\n", hr);
3391 ok_(__FILE__,line)(l == width, "Got width %d.\n", l);
3393 l = 0xdeadbeef;
3394 hr = IBasicVideo_get_SourceHeight(video, &l);
3395 ok_(__FILE__,line)(hr == S_OK, "Failed to get height, hr %#x.\n", hr);
3396 ok_(__FILE__,line)(l == height, "Got height %d.\n", l);
3398 #define check_source_position(a,b,c,d,e) check_source_position_(__LINE__,a,b,c,d,e)
3400 static void test_basic_video_source(IBasicVideo *video)
3402 HRESULT 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);
3408 hr = IBasicVideo_put_SourceLeft(video, -10);
3409 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3410 hr = IBasicVideo_put_SourceLeft(video, 10);
3411 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3413 hr = IBasicVideo_put_SourceTop(video, -10);
3414 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3415 hr = IBasicVideo_put_SourceTop(video, 10);
3416 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3418 hr = IBasicVideo_put_SourceWidth(video, -500);
3419 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3420 hr = IBasicVideo_put_SourceWidth(video, 0);
3421 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3422 hr = IBasicVideo_put_SourceWidth(video, 700);
3423 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3424 hr = IBasicVideo_put_SourceWidth(video, 500);
3425 ok(hr == S_OK, "Got hr %#x.\n", hr);
3426 check_source_position(video, 0, 0, 500, 400);
3427 hr = IBasicVideo_IsUsingDefaultSource(video);
3428 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3430 hr = IBasicVideo_put_SourceHeight(video, -300);
3431 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3432 hr = IBasicVideo_put_SourceHeight(video, 0);
3433 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3434 hr = IBasicVideo_put_SourceHeight(video, 600);
3435 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3436 hr = IBasicVideo_put_SourceHeight(video, 300);
3437 ok(hr == S_OK, "Got hr %#x.\n", hr);
3438 check_source_position(video, 0, 0, 500, 300);
3439 hr = IBasicVideo_IsUsingDefaultSource(video);
3440 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3442 hr = IBasicVideo_put_SourceLeft(video, -10);
3443 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3444 hr = IBasicVideo_put_SourceLeft(video, 10);
3445 ok(hr == S_OK, "Got hr %#x.\n", hr);
3446 check_source_position(video, 10, 0, 500, 300);
3447 hr = IBasicVideo_IsUsingDefaultSource(video);
3448 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3450 hr = IBasicVideo_put_SourceTop(video, -10);
3451 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3452 hr = IBasicVideo_put_SourceTop(video, 20);
3453 ok(hr == S_OK, "Got hr %#x.\n", hr);
3454 check_source_position(video, 10, 20, 500, 300);
3455 hr = IBasicVideo_IsUsingDefaultSource(video);
3456 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3458 hr = IBasicVideo_SetSourcePosition(video, 4, 5, 60, 40);
3459 ok(hr == S_OK, "Got hr %#x.\n", hr);
3460 check_source_position(video, 4, 5, 60, 40);
3461 hr = IBasicVideo_IsUsingDefaultSource(video);
3462 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3464 hr = IBasicVideo_SetSourcePosition(video, 0, 0, 600, 400);
3465 ok(hr == S_OK, "Got hr %#x.\n", hr);
3466 check_source_position(video, 0, 0, 600, 400);
3467 hr = IBasicVideo_IsUsingDefaultSource(video);
3468 ok(hr == S_OK, "Got hr %#x.\n", hr);
3470 hr = IBasicVideo_SetSourcePosition(video, 4, 5, 60, 40);
3471 ok(hr == S_OK, "Got hr %#x.\n", hr);
3472 hr = IBasicVideo_SetDefaultSourcePosition(video);
3473 ok(hr == S_OK, "Got hr %#x.\n", hr);
3474 check_source_position(video, 0, 0, 600, 400);
3475 hr = IBasicVideo_IsUsingDefaultSource(video);
3476 ok(hr == S_OK, "Got hr %#x.\n", hr);
3479 static void check_destination_position_(int line, IBasicVideo *video,
3480 LONG expect_left, LONG expect_top, LONG expect_width, LONG expect_height)
3482 LONG left, top, width, height, l;
3483 HRESULT hr;
3485 left = top = width = height = 0xdeadbeef;
3486 hr = IBasicVideo_GetDestinationPosition(video, &left, &top, &width, &height);
3487 ok_(__FILE__,line)(hr == S_OK, "Failed to get position, hr %#x.\n", hr);
3488 ok_(__FILE__,line)(left == expect_left, "Got left %d.\n", left);
3489 ok_(__FILE__,line)(top == expect_top, "Got top %d.\n", top);
3490 ok_(__FILE__,line)(width == expect_width, "Got width %d.\n", width);
3491 ok_(__FILE__,line)(height == expect_height, "Got height %d.\n", height);
3493 l = 0xdeadbeef;
3494 hr = IBasicVideo_get_DestinationLeft(video, &l);
3495 ok_(__FILE__,line)(hr == S_OK, "Failed to get left, hr %#x.\n", hr);
3496 ok_(__FILE__,line)(l == left, "Got left %d.\n", l);
3498 l = 0xdeadbeef;
3499 hr = IBasicVideo_get_DestinationTop(video, &l);
3500 ok_(__FILE__,line)(hr == S_OK, "Failed to get top, hr %#x.\n", hr);
3501 ok_(__FILE__,line)(l == top, "Got top %d.\n", l);
3503 l = 0xdeadbeef;
3504 hr = IBasicVideo_get_DestinationWidth(video, &l);
3505 ok_(__FILE__,line)(hr == S_OK, "Failed to get width, hr %#x.\n", hr);
3506 ok_(__FILE__,line)(l == width, "Got width %d.\n", l);
3508 l = 0xdeadbeef;
3509 hr = IBasicVideo_get_DestinationHeight(video, &l);
3510 ok_(__FILE__,line)(hr == S_OK, "Failed to get height, hr %#x.\n", hr);
3511 ok_(__FILE__,line)(l == height, "Got height %d.\n", l);
3513 #define check_destination_position(a,b,c,d,e) check_destination_position_(__LINE__,a,b,c,d,e)
3515 static void test_basic_video_destination(IBasicVideo *video)
3517 IVideoWindow *window;
3518 HRESULT hr;
3519 RECT rect;
3521 IBasicVideo_QueryInterface(video, &IID_IVideoWindow, (void **)&window);
3523 check_destination_position(video, 0, 0, 600, 400);
3524 hr = IBasicVideo_IsUsingDefaultDestination(video);
3525 ok(hr == S_OK, "Got hr %#x.\n", hr);
3527 hr = IBasicVideo_put_DestinationLeft(video, -10);
3528 ok(hr == S_OK, "Got hr %#x.\n", hr);
3529 check_destination_position(video, -10, 0, 600, 400);
3530 hr = IBasicVideo_IsUsingDefaultDestination(video);
3531 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3533 hr = IBasicVideo_put_DestinationLeft(video, 10);
3534 ok(hr == S_OK, "Got hr %#x.\n", hr);
3535 check_destination_position(video, 10, 0, 600, 400);
3536 hr = IBasicVideo_IsUsingDefaultDestination(video);
3537 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3539 hr = IBasicVideo_put_DestinationTop(video, -20);
3540 ok(hr == S_OK, "Got hr %#x.\n", hr);
3541 check_destination_position(video, 10, -20, 600, 400);
3542 hr = IBasicVideo_IsUsingDefaultDestination(video);
3543 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3545 hr = IBasicVideo_put_DestinationTop(video, 20);
3546 ok(hr == S_OK, "Got hr %#x.\n", hr);
3547 check_destination_position(video, 10, 20, 600, 400);
3548 hr = IBasicVideo_IsUsingDefaultDestination(video);
3549 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3551 hr = IBasicVideo_put_DestinationWidth(video, -700);
3552 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3553 hr = IBasicVideo_put_DestinationWidth(video, 0);
3554 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3555 hr = IBasicVideo_put_DestinationWidth(video, 700);
3556 ok(hr == S_OK, "Got hr %#x.\n", hr);
3557 check_destination_position(video, 10, 20, 700, 400);
3558 hr = IBasicVideo_IsUsingDefaultDestination(video);
3559 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3561 hr = IBasicVideo_put_DestinationWidth(video, 500);
3562 ok(hr == S_OK, "Got hr %#x.\n", hr);
3563 check_destination_position(video, 10, 20, 500, 400);
3564 hr = IBasicVideo_IsUsingDefaultDestination(video);
3565 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3567 hr = IBasicVideo_put_DestinationHeight(video, -500);
3568 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3569 hr = IBasicVideo_put_DestinationHeight(video, 0);
3570 ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
3571 hr = IBasicVideo_put_DestinationHeight(video, 500);
3572 ok(hr == S_OK, "Got hr %#x.\n", hr);
3573 check_destination_position(video, 10, 20, 500, 500);
3574 hr = IBasicVideo_IsUsingDefaultDestination(video);
3575 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3577 hr = IBasicVideo_put_DestinationHeight(video, 300);
3578 ok(hr == S_OK, "Got hr %#x.\n", hr);
3579 check_destination_position(video, 10, 20, 500, 300);
3580 hr = IBasicVideo_IsUsingDefaultDestination(video);
3581 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3583 hr = IBasicVideo_SetDestinationPosition(video, 4, 5, 60, 40);
3584 ok(hr == S_OK, "Got hr %#x.\n", hr);
3585 check_destination_position(video, 4, 5, 60, 40);
3586 hr = IBasicVideo_IsUsingDefaultDestination(video);
3587 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3589 hr = IBasicVideo_SetDestinationPosition(video, 0, 0, 600, 400);
3590 ok(hr == S_OK, "Got hr %#x.\n", hr);
3591 check_destination_position(video, 0, 0, 600, 400);
3592 hr = IBasicVideo_IsUsingDefaultDestination(video);
3593 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3595 hr = IBasicVideo_SetDestinationPosition(video, 4, 5, 60, 40);
3596 ok(hr == S_OK, "Got hr %#x.\n", hr);
3597 hr = IBasicVideo_SetDefaultDestinationPosition(video);
3598 ok(hr == S_OK, "Got hr %#x.\n", hr);
3599 check_destination_position(video, 0, 0, 600, 400);
3600 hr = IBasicVideo_IsUsingDefaultDestination(video);
3601 ok(hr == S_OK, "Got hr %#x.\n", hr);
3603 SetRect(&rect, 100, 200, 500, 500);
3604 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
3605 hr = IVideoWindow_SetWindowPosition(window, rect.left, rect.top,
3606 rect.right - rect.left, rect.bottom - rect.top);
3607 ok(hr == S_OK, "Got hr %#x.\n", hr);
3608 check_destination_position(video, 0, 0, 400, 300);
3609 hr = IBasicVideo_IsUsingDefaultDestination(video);
3610 ok(hr == S_OK, "Got hr %#x.\n", hr);
3612 hr = IBasicVideo_SetDestinationPosition(video, 0, 0, 400, 300);
3613 ok(hr == S_OK, "Got hr %#x.\n", hr);
3614 check_destination_position(video, 0, 0, 400, 300);
3615 hr = IBasicVideo_IsUsingDefaultDestination(video);
3616 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3618 SetRect(&rect, 100, 200, 600, 600);
3619 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
3620 hr = IVideoWindow_SetWindowPosition(window, rect.left, rect.top,
3621 rect.right - rect.left, rect.bottom - rect.top);
3622 ok(hr == S_OK, "Got hr %#x.\n", hr);
3623 check_destination_position(video, 0, 0, 400, 300);
3624 hr = IBasicVideo_IsUsingDefaultDestination(video);
3625 ok(hr == S_FALSE, "Got hr %#x.\n", hr);
3627 IVideoWindow_Release(window);
3630 static void test_basic_video(void)
3632 ALLOCATOR_PROPERTIES req_props = {1, 600 * 400 * 4, 1, 0}, ret_props;
3633 VIDEOINFOHEADER vih =
3635 .AvgTimePerFrame = 200000,
3636 .rcSource = {4, 6, 16, 12},
3637 .rcTarget = {40, 60, 120, 160},
3638 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
3639 .bmiHeader.biBitCount = 32,
3640 .bmiHeader.biWidth = 600,
3641 .bmiHeader.biHeight = 400,
3642 .bmiHeader.biPlanes = 1,
3643 .bmiHeader.biCompression = BI_RGB,
3645 AM_MEDIA_TYPE req_mt =
3647 .majortype = MEDIATYPE_Video,
3648 .subtype = MEDIASUBTYPE_RGB32,
3649 .formattype = FORMAT_VideoInfo,
3650 .cbFormat = sizeof(vih),
3651 .pbFormat = (BYTE *)&vih,
3653 IBaseFilter *filter = create_vmr9(VMR9Mode_Windowed);
3654 IFilterGraph2 *graph = create_graph();
3655 LONG left, top, width, height, l;
3656 struct testfilter source;
3657 IMemAllocator *allocator;
3658 IMemInputPin *input;
3659 ITypeInfo *typeinfo;
3660 IBasicVideo *video;
3661 TYPEATTR *typeattr;
3662 REFTIME reftime;
3663 HRESULT hr;
3664 UINT count;
3665 ULONG ref;
3666 IPin *pin;
3667 RECT rect;
3669 IBaseFilter_QueryInterface(filter, &IID_IBasicVideo, (void **)&video);
3670 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
3671 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
3673 hr = IBasicVideo_GetTypeInfoCount(video, &count);
3674 ok(hr == S_OK, "Got hr %#x.\n", hr);
3675 ok(count == 1, "Got count %u.\n", count);
3677 hr = IBasicVideo_GetTypeInfo(video, 0, 0, &typeinfo);
3678 ok(hr == S_OK, "Got hr %#x.\n", hr);
3679 hr = ITypeInfo_GetTypeAttr(typeinfo, &typeattr);
3680 ok(hr == S_OK, "Got hr %#x.\n", hr);
3681 ok(typeattr->typekind == TKIND_DISPATCH, "Got kind %u.\n", typeattr->typekind);
3682 ok(IsEqualGUID(&typeattr->guid, &IID_IBasicVideo), "Got IID %s.\n", wine_dbgstr_guid(&typeattr->guid));
3683 ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr);
3684 ITypeInfo_Release(typeinfo);
3686 hr = IBasicVideo_get_AvgTimePerFrame(video, NULL);
3687 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3688 hr = IBasicVideo_get_AvgTimePerFrame(video, &reftime);
3689 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
3691 hr = IBasicVideo_get_BitRate(video, NULL);
3692 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3693 hr = IBasicVideo_get_BitRate(video, &l);
3694 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
3696 hr = IBasicVideo_get_BitErrorRate(video, NULL);
3697 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3698 hr = IBasicVideo_get_BitErrorRate(video, &l);
3699 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
3701 hr = IBasicVideo_get_VideoWidth(video, NULL);
3702 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3703 hr = IBasicVideo_get_VideoHeight(video, NULL);
3704 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3706 hr = IBasicVideo_get_SourceLeft(video, NULL);
3707 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3708 hr = IBasicVideo_get_SourceWidth(video, NULL);
3709 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3710 hr = IBasicVideo_get_SourceTop(video, NULL);
3711 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3712 hr = IBasicVideo_get_SourceHeight(video, NULL);
3713 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3715 hr = IBasicVideo_get_DestinationLeft(video, NULL);
3716 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3717 hr = IBasicVideo_get_DestinationWidth(video, NULL);
3718 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3719 hr = IBasicVideo_get_DestinationTop(video, NULL);
3720 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3721 hr = IBasicVideo_get_DestinationHeight(video, NULL);
3722 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3724 hr = IBasicVideo_GetSourcePosition(video, NULL, &top, &width, &height);
3725 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3726 hr = IBasicVideo_GetSourcePosition(video, &left, NULL, &width, &height);
3727 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3728 hr = IBasicVideo_GetSourcePosition(video, &left, &top, NULL, &height);
3729 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3730 hr = IBasicVideo_GetSourcePosition(video, &left, &top, &width, NULL);
3731 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3733 hr = IBasicVideo_GetDestinationPosition(video, NULL, &top, &width, &height);
3734 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3735 hr = IBasicVideo_GetDestinationPosition(video, &left, NULL, &width, &height);
3736 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3737 hr = IBasicVideo_GetDestinationPosition(video, &left, &top, NULL, &height);
3738 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3739 hr = IBasicVideo_GetDestinationPosition(video, &left, &top, &width, NULL);
3740 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3742 hr = IBasicVideo_GetVideoSize(video, &width, NULL);
3743 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3744 hr = IBasicVideo_GetVideoSize(video, NULL, &height);
3745 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3747 hr = IBasicVideo_GetVideoPaletteEntries(video, 0, 1, NULL, &l);
3748 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3749 hr = IBasicVideo_GetVideoPaletteEntries(video, 0, 1, &l, NULL);
3750 todo_wine ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
3752 testfilter_init(&source);
3753 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, L"vmr9");
3754 IFilterGraph2_AddFilter(graph, filter, L"source");
3755 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
3756 if (hr == E_FAIL)
3758 skip("Got E_FAIL when connecting.\n");
3759 goto out;
3761 ok(hr == S_OK, "Got hr %#x.\n", hr);
3763 hr = IMemInputPin_GetAllocator(input, &allocator);
3764 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
3765 if (hr == S_OK)
3767 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
3768 ok(hr == S_OK, "Got hr %#x.\n", hr);
3769 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
3770 hr = IMemAllocator_Commit(allocator);
3771 ok(hr == S_OK, "Got hr %#x.\n", hr);
3772 IMemAllocator_Release(allocator);
3775 reftime = 0.0;
3776 hr = IBasicVideo_get_AvgTimePerFrame(video, &reftime);
3777 ok(hr == S_OK, "Got hr %#x.\n", hr);
3778 ok(compare_double(reftime, 0.02, 1 << 28), "Got frame rate %.16e.\n", reftime);
3780 l = 0xdeadbeef;
3781 hr = IBasicVideo_get_BitRate(video, &l);
3782 ok(hr == S_OK, "Got hr %#x.\n", hr);
3783 ok(!l, "Got bit rate %d.\n", l);
3785 l = 0xdeadbeef;
3786 hr = IBasicVideo_get_BitErrorRate(video, &l);
3787 ok(hr == S_OK, "Got hr %#x.\n", hr);
3788 ok(!l, "Got bit rate %d.\n", l);
3790 hr = IBasicVideo_GetVideoPaletteEntries(video, 0, 1, &l, NULL);
3791 todo_wine ok(hr == VFW_E_NO_PALETTE_AVAILABLE, "Got hr %#x.\n", hr);
3793 width = height = 0xdeadbeef;
3794 hr = IBasicVideo_GetVideoSize(video, &width, &height);
3795 ok(hr == S_OK, "Got hr %#x.\n", hr);
3796 ok(width == 600, "Got width %d.\n", width);
3797 ok(height == 400, "Got height %d.\n", height);
3799 test_basic_video_source(video);
3800 test_basic_video_destination(video);
3802 hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
3803 ok(hr == S_OK, "Got hr %#x.\n", hr);
3804 hr = IFilterGraph2_Disconnect(graph, pin);
3805 ok(hr == S_OK, "Got hr %#x.\n", hr);
3807 vih.bmiHeader.biWidth = 16;
3808 vih.bmiHeader.biHeight = 16;
3809 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
3810 ok(hr == S_OK, "Got hr %#x.\n", hr);
3812 hr = IMemInputPin_GetAllocator(input, &allocator);
3813 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
3814 if (hr == S_OK)
3816 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
3817 ok(hr == S_OK, "Got hr %#x.\n", hr);
3818 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
3819 hr = IMemAllocator_Commit(allocator);
3820 ok(hr == S_OK, "Got hr %#x.\n", hr);
3821 IMemAllocator_Release(allocator);
3824 check_source_position(video, 0, 0, 16, 16);
3826 SetRect(&rect, 0, 0, 0, 0);
3827 AdjustWindowRectEx(&rect, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, FALSE, 0);
3828 check_destination_position(video, 0, 0, max(16, GetSystemMetrics(SM_CXMIN) - (rect.right - rect.left)),
3829 max(16, GetSystemMetrics(SM_CYMIN) - (rect.bottom - rect.top)));
3831 out:
3832 ref = IFilterGraph2_Release(graph);
3833 ok(!ref, "Got outstanding refcount %d.\n", ref);
3834 IBasicVideo_Release(video);
3835 IMemInputPin_Release(input);
3836 IPin_Release(pin);
3837 ref = IBaseFilter_Release(filter);
3838 ok(!ref, "Got outstanding refcount %d.\n", ref);
3839 ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface);
3840 ok(!ref, "Got outstanding refcount %d.\n", ref);
3843 static void test_windowless_size(void)
3845 ALLOCATOR_PROPERTIES req_props = {1, 32 * 16 * 4, 1, 0}, ret_props;
3846 VIDEOINFOHEADER vih =
3848 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
3849 .bmiHeader.biWidth = 32,
3850 .bmiHeader.biHeight = 16,
3851 .bmiHeader.biBitCount = 32,
3852 .bmiHeader.biPlanes = 1,
3854 AM_MEDIA_TYPE mt =
3856 .majortype = MEDIATYPE_Video,
3857 .subtype = MEDIASUBTYPE_RGB32,
3858 .formattype = FORMAT_VideoInfo,
3859 .cbFormat = sizeof(vih),
3860 .pbFormat = (BYTE *)&vih,
3862 IBaseFilter *filter = create_vmr9(VMR9Mode_Windowless);
3863 LONG width, height, aspect_width, aspect_height;
3864 IVMRAspectRatioControl9 *aspect_ratio_control;
3865 IVMRWindowlessControl9 *windowless_control;
3866 IFilterGraph2 *graph = create_graph();
3867 VMR9AspectRatioMode aspect_mode;
3868 struct testfilter source;
3869 IMemAllocator *allocator;
3870 RECT src, dst, expect;
3871 IMemInputPin *input;
3872 HWND window;
3873 HRESULT hr;
3874 ULONG ref;
3875 IPin *pin;
3877 IBaseFilter_QueryInterface(filter, &IID_IVMRWindowlessControl9, (void **)&windowless_control);
3878 IBaseFilter_QueryInterface(filter, &IID_IVMRAspectRatioControl9, (void **)&aspect_ratio_control);
3879 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
3880 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
3881 testfilter_init(&source);
3882 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, L"source");
3883 IFilterGraph2_AddFilter(graph, filter, L"vmr9");
3884 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
3885 ok(!!window, "Failed to create a window.\n");
3887 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, window);
3888 ok(hr == S_OK, "Got hr %#x.\n", hr);
3890 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &mt);
3891 ok(hr == S_OK, "Got hr %#x.\n", hr);
3892 hr = IMemInputPin_GetAllocator(input, &allocator);
3893 todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
3894 if (hr == S_OK)
3896 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
3897 IMemAllocator_Release(allocator);
3898 if (hr == E_FAIL)
3900 skip("Got E_FAIL when setting allocator properties.\n");
3901 goto out;
3903 ok(hr == S_OK, "Got hr %#x.\n", hr);
3904 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
3907 hr = IVMRWindowlessControl9_GetNativeVideoSize(windowless_control, NULL, &height, &aspect_width, &aspect_height);
3908 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3909 hr = IVMRWindowlessControl9_GetNativeVideoSize(windowless_control, &width, NULL, &aspect_width, &aspect_height);
3910 ok(hr == E_POINTER, "Got hr %#x.\n", hr);
3912 aspect_mode = 0xdeadbeef;
3913 hr = IVMRWindowlessControl9_GetAspectRatioMode(windowless_control, &aspect_mode);
3914 ok(hr == S_OK, "Got hr %#x.\n", hr);
3915 ok(aspect_mode == VMR9ARMode_None, "Got mode %u.\n", aspect_mode);
3917 aspect_mode = 0xdeadbeef;
3918 hr = IVMRAspectRatioControl9_GetAspectRatioMode(aspect_ratio_control, &aspect_mode);
3919 ok(hr == S_OK, "Got hr %#x.\n", hr);
3920 ok(aspect_mode == VMR9ARMode_None, "Got mode %u.\n", aspect_mode);
3922 width = height = 0xdeadbeef;
3923 hr = IVMRWindowlessControl9_GetNativeVideoSize(windowless_control, &width, &height, NULL, NULL);
3924 ok(hr == S_OK, "Got hr %#x.\n", hr);
3925 ok(width == 32, "Got width %d.\n", width);
3926 ok(height == 16, "Got height %d.\n", height);
3928 aspect_width = aspect_height = 0xdeadbeef;
3929 hr = IVMRWindowlessControl9_GetNativeVideoSize(windowless_control, &width, &height, &aspect_width, &aspect_height);
3930 ok(hr == S_OK, "Got hr %#x.\n", hr);
3931 ok(aspect_width == 32, "Got width %d.\n", aspect_width);
3932 ok(aspect_height == 16, "Got height %d.\n", aspect_height);
3934 memset(&src, 0xcc, sizeof(src));
3935 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, &src, NULL);
3936 ok(hr == S_OK, "Got hr %#x.\n", hr);
3937 SetRect(&expect, 0, 0, 32, 16);
3938 ok(EqualRect(&src, &expect), "Got source rect %s.\n", wine_dbgstr_rect(&src));
3940 memset(&dst, 0xcc, sizeof(dst));
3941 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, NULL, &dst);
3942 ok(hr == S_OK, "Got hr %#x.\n", hr);
3943 SetRect(&expect, 0, 0, 0, 0);
3944 ok(EqualRect(&dst, &expect), "Got dest rect %s.\n", wine_dbgstr_rect(&dst));
3946 SetRect(&src, 4, 6, 16, 12);
3947 hr = IVMRWindowlessControl9_SetVideoPosition(windowless_control, &src, NULL);
3948 ok(hr == S_OK, "Got hr %#x.\n", hr);
3950 memset(&src, 0xcc, sizeof(src));
3951 memset(&dst, 0xcc, sizeof(dst));
3952 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, &src, &dst);
3953 ok(hr == S_OK, "Got hr %#x.\n", hr);
3954 SetRect(&expect, 4, 6, 16, 12);
3955 ok(EqualRect(&src, &expect), "Got source rect %s.\n", wine_dbgstr_rect(&src));
3956 SetRect(&expect, 0, 0, 0, 0);
3957 ok(EqualRect(&dst, &expect), "Got dest rect %s.\n", wine_dbgstr_rect(&dst));
3959 SetRect(&dst, 40, 60, 120, 160);
3960 hr = IVMRWindowlessControl9_SetVideoPosition(windowless_control, NULL, &dst);
3961 ok(hr == S_OK, "Got hr %#x.\n", hr);
3963 memset(&src, 0xcc, sizeof(src));
3964 memset(&dst, 0xcc, sizeof(dst));
3965 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, &src, &dst);
3966 ok(hr == S_OK, "Got hr %#x.\n", hr);
3967 SetRect(&expect, 4, 6, 16, 12);
3968 ok(EqualRect(&src, &expect), "Got source rect %s.\n", wine_dbgstr_rect(&src));
3969 SetRect(&expect, 40, 60, 120, 160);
3970 ok(EqualRect(&dst, &expect), "Got dest rect %s.\n", wine_dbgstr_rect(&dst));
3972 GetWindowRect(window, &src);
3973 SetRect(&expect, 0, 0, 640, 480);
3974 ok(EqualRect(&src, &expect), "Got window rect %s.\n", wine_dbgstr_rect(&src));
3976 hr = IVMRAspectRatioControl9_SetAspectRatioMode(aspect_ratio_control, VMR9ARMode_LetterBox);
3977 ok(hr == S_OK, "Got hr %#x.\n", hr);
3979 aspect_mode = 0xdeadbeef;
3980 hr = IVMRWindowlessControl9_GetAspectRatioMode(windowless_control, &aspect_mode);
3981 ok(hr == S_OK, "Got hr %#x.\n", hr);
3982 ok(aspect_mode == VMR9ARMode_LetterBox, "Got mode %u.\n", aspect_mode);
3984 hr = IVMRWindowlessControl9_SetAspectRatioMode(windowless_control, VMR9ARMode_None);
3985 ok(hr == S_OK, "Got hr %#x.\n", hr);
3987 aspect_mode = 0xdeadbeef;
3988 hr = IVMRAspectRatioControl9_GetAspectRatioMode(aspect_ratio_control, &aspect_mode);
3989 ok(hr == S_OK, "Got hr %#x.\n", hr);
3990 ok(aspect_mode == VMR9ARMode_None, "Got mode %u.\n", aspect_mode);
3992 hr = IVMRWindowlessControl9_SetAspectRatioMode(windowless_control, VMR9ARMode_LetterBox);
3993 ok(hr == S_OK, "Got hr %#x.\n", hr);
3995 memset(&src, 0xcc, sizeof(src));
3996 memset(&dst, 0xcc, sizeof(dst));
3997 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, &src, &dst);
3998 ok(hr == S_OK, "Got hr %#x.\n", hr);
3999 SetRect(&expect, 4, 6, 16, 12);
4000 ok(EqualRect(&src, &expect), "Got source rect %s.\n", wine_dbgstr_rect(&src));
4001 SetRect(&expect, 40, 60, 120, 160);
4002 ok(EqualRect(&dst, &expect), "Got dest rect %s.\n", wine_dbgstr_rect(&dst));
4004 SetRect(&src, 0, 0, 32, 16);
4005 SetRect(&dst, 0, 0, 640, 480);
4006 hr = IVMRWindowlessControl9_SetVideoPosition(windowless_control, &src, &dst);
4007 ok(hr == S_OK, "Got hr %#x.\n", hr);
4009 memset(&src, 0xcc, sizeof(src));
4010 memset(&dst, 0xcc, sizeof(dst));
4011 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, &src, &dst);
4012 ok(hr == S_OK, "Got hr %#x.\n", hr);
4013 SetRect(&expect, 0, 0, 32, 16);
4014 ok(EqualRect(&src, &expect), "Got source rect %s.\n", wine_dbgstr_rect(&src));
4015 SetRect(&expect, 0, 0, 640, 480);
4016 ok(EqualRect(&dst, &expect), "Got dest rect %s.\n", wine_dbgstr_rect(&dst));
4018 out:
4019 ref = IFilterGraph2_Release(graph);
4020 ok(!ref, "Got outstanding refcount %d.\n", ref);
4021 IMemInputPin_Release(input);
4022 IPin_Release(pin);
4023 IVMRWindowlessControl9_Release(windowless_control);
4024 IVMRAspectRatioControl9_Release(aspect_ratio_control);
4025 ref = IBaseFilter_Release(filter);
4026 ok(!ref, "Got outstanding refcount %d.\n", ref);
4027 DestroyWindow(window);
4030 static void test_mixing_prefs(void)
4032 IBaseFilter *filter = create_vmr9(VMR9Mode_Windowed);
4033 IVMRMixerControl9 *mixer_control;
4034 DWORD flags;
4035 HRESULT hr;
4036 ULONG ref;
4038 set_mixing_mode(filter, 1);
4040 hr = IBaseFilter_QueryInterface(filter, &IID_IVMRMixerControl9, (void **)&mixer_control);
4041 ok(hr == S_OK, "Got hr %#x.\n", hr);
4043 hr = IVMRMixerControl9_GetMixingPrefs(mixer_control, &flags);
4044 ok(hr == S_OK, "Got hr %#x.\n", hr);
4045 ok(flags == (MixerPref9_NoDecimation | MixerPref9_ARAdjustXorY | MixerPref9_BiLinearFiltering
4046 | MixerPref9_RenderTargetRGB), "Got flags %#x.\n", flags);
4048 hr = IVMRMixerControl9_SetMixingPrefs(mixer_control, MixerPref9_NoDecimation
4049 | MixerPref9_ARAdjustXorY | MixerPref9_PointFiltering | MixerPref9_RenderTargetRGB);
4050 ok(hr == S_OK, "Got hr %#x.\n", hr);
4052 hr = IVMRMixerControl9_GetMixingPrefs(mixer_control, &flags);
4053 ok(hr == S_OK, "Got hr %#x.\n", hr);
4054 ok(flags == (MixerPref9_NoDecimation | MixerPref9_ARAdjustXorY | MixerPref9_PointFiltering
4055 | MixerPref9_RenderTargetRGB), "Got flags %#x.\n", flags);
4057 IVMRMixerControl9_Release(mixer_control);
4058 ref = IBaseFilter_Release(filter);
4059 ok(!ref, "Got outstanding refcount %d.\n", ref);
4062 START_TEST(vmr9)
4064 IBaseFilter *filter;
4065 HRESULT hr;
4067 CoInitialize(NULL);
4069 if (FAILED(hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL,
4070 CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void **)&filter)))
4072 skip("Failed to create VMR9, hr %#x.\n", hr);
4073 return;
4075 IBaseFilter_Release(filter);
4077 test_filter_config();
4078 test_interfaces();
4079 test_aggregation();
4080 test_enum_pins();
4081 test_find_pin();
4082 test_pin_info();
4083 test_media_types();
4084 test_enum_media_types();
4085 test_unconnected_filter_state();
4086 test_connect_pin();
4087 test_overlay();
4088 test_video_window();
4089 test_allocate_surface_helper();
4090 test_renderless_formats();
4091 test_mixing_mode();
4092 test_clipping_window();
4093 test_surface_allocator_notify_refcount();
4094 test_basic_video();
4095 test_windowless_size();
4096 test_mixing_prefs();
4098 CoUninitialize();