quartz: Check whether the pin is connected in IVideoWindow::SetWindowPosition().
[wine.git] / dlls / quartz / tests / vmr9.c
blob9d88afb295d21a56f173787408446431fa61430e
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 "videoacc.h"
31 #include "wmcodecdsp.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 %#lx.\n", hr);
42 if (mode)
44 hr = IBaseFilter_QueryInterface(filter, &IID_IVMRFilterConfig9, (void **)&config);
45 ok(hr == S_OK, "Got hr %#lx.\n", hr);
46 hr = IVMRFilterConfig9_SetRenderingMode(config, mode);
47 ok(hr == S_OK || broken(hr == E_FAIL), "Got hr %#lx.\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 %#lx.\n", hr);
61 hr = IVMRFilterConfig9_SetNumberOfStreams(config, count);
62 ok(hr == S_OK, "Got hr %#lx.\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, "Got hr %#lx.\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 %#lx.\n", hr);
118 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
119 ok(hr == S_OK, "Got hr %#lx.\n", hr);
120 ok(mode == VMRMode_Windowed, "Got mode %#lx.\n", mode);
122 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowed);
123 ok(hr == S_OK || broken(hr == E_FAIL), "Got hr %#lx.\n", hr);
125 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
126 ok(hr == S_OK, "Got hr %#lx.\n", hr);
127 ok(mode == VMR9Mode_Windowed, "Got mode %#lx.\n", mode);
129 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowed);
130 ok(hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr);
132 ref = IVMRFilterConfig9_Release(config);
133 ok(!ref, "Got outstanding refcount %ld.\n", ref);
135 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
136 &IID_IVMRFilterConfig9, (void **)&config);
137 ok(hr == S_OK, "Got hr %#lx.\n", hr);
139 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowless);
140 ok(hr == S_OK || broken(hr == E_FAIL), "Got hr %#lx.\n", hr);
142 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
143 ok(hr == S_OK, "Got hr %#lx.\n", hr);
144 ok(mode == VMR9Mode_Windowless, "Got mode %#lx.\n", mode);
146 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowed);
147 ok(hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr);
149 ref = IVMRFilterConfig9_Release(config);
150 ok(!ref, "Got outstanding refcount %ld.\n", ref);
152 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
153 &IID_IVMRFilterConfig9, (void **)&config);
154 ok(hr == S_OK, "Got hr %#lx.\n", hr);
156 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Renderless);
157 ok(hr == S_OK, "Got hr %#lx.\n", hr);
159 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
160 ok(hr == S_OK, "Got hr %#lx.\n", hr);
161 ok(mode == VMR9Mode_Renderless, "Got mode %#lx.\n", mode);
163 hr = IVMRFilterConfig9_SetRenderingMode(config, VMR9Mode_Windowless);
164 ok(hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr);
166 ref = IVMRFilterConfig9_Release(config);
167 ok(!ref, "Got outstanding refcount %ld.\n", ref);
169 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC_SERVER,
170 &IID_IVMRFilterConfig9, (void **)&config);
171 ok(hr == S_OK, "Got hr %#lx.\n", hr);
173 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &count);
174 ok(hr == VFW_E_VMR_NOT_IN_MIXER_MODE, "Got hr %#lx.\n", hr);
176 hr = IVMRFilterConfig9_SetNumberOfStreams(config, 3);
177 ok(hr == S_OK, "Got hr %#lx.\n", hr);
179 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &count);
180 ok(hr == S_OK, "Got hr %#lx.\n", hr);
181 ok(count == 3, "Got count %lu.\n", count);
183 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
184 ok(hr == S_OK, "Got hr %#lx.\n", hr);
185 ok(mode == VMR9Mode_Windowed, "Got mode %#lx.\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 %#lx.\n", hr);
192 hr = IVMRFilterConfig9_GetRenderingMode(config, &mode);
193 ok(hr == S_OK, "Got hr %#lx.\n", hr);
194 ok(mode == VMR9Mode_Windowless, "Got mode %#lx.\n", mode);
196 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &count);
197 ok(hr == S_OK, "Got hr %#lx.\n", hr);
198 ok(count == 3, "Got count %lu.\n", count);
200 ref = IVMRFilterConfig9_Release(config);
201 ok(!ref, "Got outstanding refcount %ld.\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 %#lx, expected %#lx.\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_IAMVideoAccelerator, FALSE);
251 check_interface(filter, &IID_IBasicAudio, FALSE);
252 check_interface(filter, &IID_IDirectDrawVideo, FALSE);
253 check_interface(filter, &IID_IPersistPropertyBag, FALSE);
254 check_interface(filter, &IID_IPin, FALSE);
255 check_interface(filter, &IID_IReferenceClock, FALSE);
256 check_interface(filter, &IID_IVMRAspectRatioControl, FALSE);
257 check_interface(filter, &IID_IVMRDeinterlaceControl, FALSE);
258 check_interface(filter, &IID_IVMRFilterConfig, FALSE);
259 check_interface(filter, &IID_IVMRMixerBitmap, FALSE);
260 check_interface(filter, &IID_IVMRMixerControl, FALSE);
261 check_interface(filter, &IID_IVMRMonitorConfig, FALSE);
262 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify, FALSE);
263 check_interface(filter, &IID_IVMRWindowlessControl, FALSE);
265 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
267 check_interface(pin, &IID_IAMVideoAccelerator, TRUE);
268 check_interface(pin, &IID_IMemInputPin, TRUE);
269 check_interface(pin, &IID_IOverlay, TRUE);
270 check_interface(pin, &IID_IPin, TRUE);
271 todo_wine check_interface(pin, &IID_IQualityControl, TRUE);
272 check_interface(pin, &IID_IUnknown, TRUE);
274 check_interface(pin, &IID_IKsPropertySet, FALSE);
275 check_interface(pin, &IID_IMediaPosition, FALSE);
276 check_interface(pin, &IID_IMediaSeeking, FALSE);
278 IPin_Release(pin);
281 static void test_interfaces(void)
283 IBaseFilter *filter = create_vmr9(0);
284 ULONG ref;
286 test_common_interfaces(filter);
288 check_interface(filter, &IID_IBasicVideo, TRUE);
289 todo_wine check_interface(filter, &IID_IBasicVideo2, TRUE);
290 check_interface(filter, &IID_IVideoWindow, TRUE);
291 /* IVMRMonitorConfig9 may not be available if the d3d9 device has
292 * insufficient support. */
293 check_interface_broken(filter, &IID_IVMRMonitorConfig9, TRUE);
295 check_interface(filter, &IID_IVMRMixerControl9, FALSE);
296 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify9, FALSE);
297 check_interface(filter, &IID_IVMRWindowlessControl9, FALSE);
299 ref = IBaseFilter_Release(filter);
300 ok(!ref, "Got outstanding refcount %ld.\n", ref);
302 filter = create_vmr9(VMR9Mode_Windowless);
303 test_common_interfaces(filter);
305 /* IVMRMonitorConfig9 may not be available if the d3d9 device has
306 * insufficient support. */
307 check_interface_broken(filter, &IID_IVMRMonitorConfig9, TRUE);
308 check_interface(filter, &IID_IVMRWindowlessControl9, TRUE);
310 todo_wine check_interface(filter, &IID_IBasicVideo, FALSE);
311 check_interface(filter, &IID_IBasicVideo2, FALSE);
312 todo_wine check_interface(filter, &IID_IVideoWindow, FALSE);
313 check_interface(filter, &IID_IVMRMixerControl9, FALSE);
314 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify9, FALSE);
316 ref = IBaseFilter_Release(filter);
317 ok(!ref, "Got outstanding refcount %ld.\n", ref);
319 filter = create_vmr9(VMR9Mode_Renderless);
320 test_common_interfaces(filter);
322 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify9, TRUE);
324 todo_wine check_interface(filter, &IID_IBasicVideo, FALSE);
325 check_interface(filter, &IID_IBasicVideo2, FALSE);
326 todo_wine check_interface(filter, &IID_IVideoWindow, FALSE);
327 check_interface(filter, &IID_IVMRMonitorConfig9, FALSE);
328 check_interface(filter, &IID_IVMRWindowlessControl9, FALSE);
330 ref = IBaseFilter_Release(filter);
331 ok(!ref, "Got outstanding refcount %ld.\n", ref);
333 filter = create_vmr9(VMR9Mode_Windowed);
334 set_mixing_mode(filter, 1);
335 test_common_interfaces(filter);
337 check_interface(filter, &IID_IBasicVideo, TRUE);
338 todo_wine check_interface(filter, &IID_IBasicVideo2, TRUE);
339 check_interface(filter, &IID_IVideoWindow, TRUE);
340 check_interface(filter, &IID_IVMRMixerControl9, TRUE);
341 /* IVMRMonitorConfig9 may not be available if the d3d9 device has
342 * insufficient support. */
343 check_interface_broken(filter, &IID_IVMRMonitorConfig9, TRUE);
345 check_interface(filter, &IID_IVMRSurfaceAllocatorNotify9, FALSE);
346 check_interface(filter, &IID_IVMRWindowlessControl9, FALSE);
348 ref = IBaseFilter_Release(filter);
349 ok(!ref, "Got outstanding refcount %ld.\n", ref);
352 static const GUID test_iid = {0x33333333};
353 static LONG outer_ref = 1;
355 static HRESULT WINAPI outer_QueryInterface(IUnknown *iface, REFIID iid, void **out)
357 if (IsEqualGUID(iid, &IID_IUnknown)
358 || IsEqualGUID(iid, &IID_IBaseFilter)
359 || IsEqualGUID(iid, &test_iid))
361 *out = (IUnknown *)0xdeadbeef;
362 return S_OK;
364 ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid));
365 return E_NOINTERFACE;
368 static ULONG WINAPI outer_AddRef(IUnknown *iface)
370 return InterlockedIncrement(&outer_ref);
373 static ULONG WINAPI outer_Release(IUnknown *iface)
375 return InterlockedDecrement(&outer_ref);
378 static const IUnknownVtbl outer_vtbl =
380 outer_QueryInterface,
381 outer_AddRef,
382 outer_Release,
385 static IUnknown test_outer = {&outer_vtbl};
387 static void test_aggregation(void)
389 IBaseFilter *filter, *filter2;
390 IUnknown *unk, *unk2;
391 HRESULT hr;
392 ULONG ref;
394 filter = (IBaseFilter *)0xdeadbeef;
395 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, &test_outer, CLSCTX_INPROC_SERVER,
396 &IID_IBaseFilter, (void **)&filter);
397 ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr);
398 ok(!filter, "Got interface %p.\n", filter);
400 hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, &test_outer, CLSCTX_INPROC_SERVER,
401 &IID_IUnknown, (void **)&unk);
402 ok(hr == S_OK, "Got hr %#lx.\n", hr);
403 ok(outer_ref == 1, "Got unexpected refcount %ld.\n", outer_ref);
404 ok(unk != &test_outer, "Returned IUnknown should not be outer IUnknown.\n");
405 ref = get_refcount(unk);
406 ok(ref == 1, "Got unexpected refcount %ld.\n", ref);
408 ref = IUnknown_AddRef(unk);
409 ok(ref == 2, "Got unexpected refcount %ld.\n", ref);
410 ok(outer_ref == 1, "Got unexpected refcount %ld.\n", outer_ref);
412 ref = IUnknown_Release(unk);
413 ok(ref == 1, "Got unexpected refcount %ld.\n", ref);
414 ok(outer_ref == 1, "Got unexpected refcount %ld.\n", outer_ref);
416 hr = IUnknown_QueryInterface(unk, &IID_IUnknown, (void **)&unk2);
417 ok(hr == S_OK, "Got hr %#lx.\n", hr);
418 ok(unk2 == unk, "Got unexpected IUnknown %p.\n", unk2);
419 IUnknown_Release(unk2);
421 hr = IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void **)&filter);
422 ok(hr == S_OK, "Got hr %#lx.\n", hr);
424 hr = IBaseFilter_QueryInterface(filter, &IID_IUnknown, (void **)&unk2);
425 ok(hr == S_OK, "Got hr %#lx.\n", hr);
426 ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
428 hr = IBaseFilter_QueryInterface(filter, &IID_IBaseFilter, (void **)&filter2);
429 ok(hr == S_OK, "Got hr %#lx.\n", hr);
430 ok(filter2 == (IBaseFilter *)0xdeadbeef, "Got unexpected IBaseFilter %p.\n", filter2);
432 hr = IUnknown_QueryInterface(unk, &test_iid, (void **)&unk2);
433 ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr);
434 ok(!unk2, "Got unexpected IUnknown %p.\n", unk2);
436 hr = IBaseFilter_QueryInterface(filter, &test_iid, (void **)&unk2);
437 ok(hr == S_OK, "Got hr %#lx.\n", hr);
438 ok(unk2 == (IUnknown *)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2);
440 IBaseFilter_Release(filter);
441 ref = IUnknown_Release(unk);
442 ok(!ref, "Got unexpected refcount %ld.\n", ref);
443 ok(outer_ref == 1, "Got unexpected refcount %ld.\n", outer_ref);
446 static void test_enum_pins(void)
448 IBaseFilter *filter = create_vmr9(0);
449 IEnumPins *enum1, *enum2;
450 ULONG count, ref;
451 IPin *pins[3];
452 HRESULT hr;
454 ref = get_refcount(filter);
455 ok(ref == 1, "Got unexpected refcount %ld.\n", ref);
457 hr = IBaseFilter_EnumPins(filter, NULL);
458 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
460 hr = IBaseFilter_EnumPins(filter, &enum1);
461 ok(hr == S_OK, "Got hr %#lx.\n", hr);
462 ref = get_refcount(filter);
463 ok(ref == 2, "Got unexpected refcount %ld.\n", ref);
464 ref = get_refcount(enum1);
465 ok(ref == 1, "Got unexpected refcount %ld.\n", ref);
467 hr = IEnumPins_Next(enum1, 1, NULL, NULL);
468 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
470 hr = IEnumPins_Next(enum1, 1, pins, NULL);
471 ok(hr == S_OK, "Got hr %#lx.\n", hr);
472 ref = get_refcount(filter);
473 ok(ref == 3, "Got unexpected refcount %ld.\n", ref);
474 ref = get_refcount(pins[0]);
475 ok(ref == 3, "Got unexpected refcount %ld.\n", ref);
476 ref = get_refcount(enum1);
477 ok(ref == 1, "Got unexpected refcount %ld.\n", ref);
478 IPin_Release(pins[0]);
479 ref = get_refcount(filter);
480 ok(ref == 2, "Got unexpected refcount %ld.\n", ref);
482 hr = IEnumPins_Next(enum1, 1, pins, NULL);
483 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
485 hr = IEnumPins_Reset(enum1);
486 ok(hr == S_OK, "Got hr %#lx.\n", hr);
488 hr = IEnumPins_Next(enum1, 1, pins, &count);
489 ok(hr == S_OK, "Got hr %#lx.\n", hr);
490 ok(count == 1, "Got count %lu.\n", count);
491 IPin_Release(pins[0]);
493 hr = IEnumPins_Next(enum1, 1, pins, &count);
494 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
495 ok(!count, "Got count %lu.\n", count);
497 hr = IEnumPins_Reset(enum1);
498 ok(hr == S_OK, "Got hr %#lx.\n", hr);
500 hr = IEnumPins_Next(enum1, 2, pins, NULL);
501 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
503 hr = IEnumPins_Next(enum1, 2, pins, &count);
504 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
505 ok(count == 1, "Got count %lu.\n", count);
506 IPin_Release(pins[0]);
508 hr = IEnumPins_Reset(enum1);
509 ok(hr == S_OK, "Got hr %#lx.\n", hr);
511 hr = IEnumPins_Clone(enum1, &enum2);
512 ok(hr == S_OK, "Got hr %#lx.\n", hr);
514 hr = IEnumPins_Skip(enum1, 2);
515 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
517 hr = IEnumPins_Skip(enum1, 1);
518 ok(hr == S_OK, "Got hr %#lx.\n", hr);
520 hr = IEnumPins_Skip(enum1, 1);
521 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
523 hr = IEnumPins_Next(enum1, 1, pins, NULL);
524 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
526 hr = IEnumPins_Next(enum2, 1, pins, NULL);
527 ok(hr == S_OK, "Got hr %#lx.\n", hr);
528 IPin_Release(pins[0]);
530 IEnumPins_Release(enum2);
532 set_mixing_mode(filter, 2);
534 hr = IEnumPins_Next(enum1, 1, pins, NULL);
535 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
537 hr = IEnumPins_Reset(enum1);
538 ok(hr == S_OK, "Got hr %#lx.\n", hr);
540 hr = IEnumPins_Next(enum1, 1, pins, NULL);
541 ok(hr == S_OK, "Got hr %#lx.\n", hr);
542 IPin_Release(pins[0]);
544 hr = IEnumPins_Next(enum1, 1, pins, NULL);
545 todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr);
546 if (hr == S_OK) IPin_Release(pins[0]);
548 hr = IEnumPins_Next(enum1, 1, pins, NULL);
549 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
551 hr = IEnumPins_Reset(enum1);
552 ok(hr == S_OK, "Got hr %#lx.\n", hr);
554 hr = IEnumPins_Next(enum1, 2, pins, &count);
555 todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr);
556 todo_wine ok(count == 2, "Got count %lu.\n", count);
557 IPin_Release(pins[0]);
558 if (count > 1) IPin_Release(pins[1]);
560 hr = IEnumPins_Reset(enum1);
561 ok(hr == S_OK, "Got hr %#lx.\n", hr);
563 hr = IEnumPins_Next(enum1, 3, pins, &count);
564 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
565 todo_wine ok(count == 2, "Got count %lu.\n", count);
566 IPin_Release(pins[0]);
567 if (count > 1) IPin_Release(pins[1]);
569 IEnumPins_Release(enum1);
570 ref = IBaseFilter_Release(filter);
571 ok(!ref, "Got outstanding refcount %ld.\n", ref);
574 static void test_find_pin(void)
576 IBaseFilter *filter = create_vmr9(0);
577 IEnumPins *enum_pins;
578 IPin *pin, *pin2;
579 HRESULT hr;
580 ULONG ref;
582 IBaseFilter_EnumPins(filter, &enum_pins);
584 hr = IBaseFilter_FindPin(filter, L"input pin", &pin);
585 ok(hr == VFW_E_NOT_FOUND, "Got hr %#lx.\n", hr);
587 hr = IBaseFilter_FindPin(filter, L"In", &pin);
588 ok(hr == VFW_E_NOT_FOUND, "Got hr %#lx.\n", hr);
590 hr = IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
591 ok(hr == S_OK, "Got hr %#lx.\n", hr);
592 hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL);
593 ok(hr == S_OK, "Got hr %#lx.\n", hr);
594 ok(pin == pin2, "Pins did not match.\n");
595 IPin_Release(pin);
596 IPin_Release(pin2);
598 hr = IBaseFilter_FindPin(filter, L"VMR Input1", &pin);
599 ok(hr == VFW_E_NOT_FOUND, "Got hr %#lx.\n", hr);
601 set_mixing_mode(filter, 2);
603 IEnumPins_Reset(enum_pins);
605 hr = IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
606 ok(hr == S_OK, "Got hr %#lx.\n", hr);
607 hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL);
608 ok(hr == S_OK, "Got hr %#lx.\n", hr);
609 ok(pin == pin2, "Pins did not match.\n");
610 IPin_Release(pin);
611 IPin_Release(pin2);
613 hr = IBaseFilter_FindPin(filter, L"VMR Input1", &pin);
614 todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr);
615 if (hr == S_OK)
617 hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL);
618 ok(hr == S_OK, "Got hr %#lx.\n", hr);
619 ok(pin == pin2, "Pins did not match.\n");
620 IPin_Release(pin);
621 IPin_Release(pin2);
624 hr = IBaseFilter_FindPin(filter, L"VMR Input2", &pin);
625 ok(hr == VFW_E_NOT_FOUND, "Got hr %#lx.\n", hr);
627 IEnumPins_Release(enum_pins);
628 ref = IBaseFilter_Release(filter);
629 ok(!ref, "Got outstanding refcount %ld.\n", ref);
632 static void test_pin_info(void)
634 IBaseFilter *filter = create_vmr9(0);
635 PIN_DIRECTION dir;
636 ULONG count, ref;
637 PIN_INFO info;
638 HRESULT hr;
639 WCHAR *id;
640 IPin *pin;
642 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
643 hr = IPin_QueryPinInfo(pin, &info);
644 ok(info.pFilter == filter, "Expected filter %p, got %p.\n", filter, info.pFilter);
645 ok(info.dir == PINDIR_INPUT, "Got direction %d.\n", info.dir);
646 ok(!wcscmp(info.achName, L"VMR Input0"), "Got name %s.\n", wine_dbgstr_w(info.achName));
647 IBaseFilter_Release(info.pFilter);
649 hr = IPin_QueryDirection(pin, &dir);
650 ok(hr == S_OK, "Got hr %#lx.\n", hr);
651 ok(dir == PINDIR_INPUT, "Got direction %d.\n", dir);
653 hr = IPin_QueryId(pin, &id);
654 ok(hr == S_OK, "Got hr %#lx.\n", hr);
655 ok(!wcscmp(id, L"VMR Input0"), "Got id %s.\n", wine_dbgstr_w(id));
656 CoTaskMemFree(id);
658 hr = IPin_QueryInternalConnections(pin, NULL, &count);
659 ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
661 IPin_Release(pin);
663 set_mixing_mode(filter, 2);
665 hr = IBaseFilter_FindPin(filter, L"VMR Input1", &pin);
666 todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr);
667 if (hr == S_OK)
669 hr = IPin_QueryPinInfo(pin, &info);
670 ok(info.pFilter == filter, "Expected filter %p, got %p.\n", filter, info.pFilter);
671 ok(info.dir == PINDIR_INPUT, "Got direction %d.\n", info.dir);
672 ok(!wcscmp(info.achName, L"VMR Input1"), "Got name %s.\n", wine_dbgstr_w(info.achName));
673 IBaseFilter_Release(info.pFilter);
675 hr = IPin_QueryDirection(pin, &dir);
676 ok(hr == S_OK, "Got hr %#lx.\n", hr);
677 ok(dir == PINDIR_INPUT, "Got direction %d.\n", dir);
679 hr = IPin_QueryId(pin, &id);
680 ok(hr == S_OK, "Got hr %#lx.\n", hr);
681 ok(!wcscmp(id, L"VMR Input1"), "Got id %s.\n", wine_dbgstr_w(id));
682 CoTaskMemFree(id);
684 hr = IPin_QueryInternalConnections(pin, NULL, &count);
685 ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
687 IPin_Release(pin);
690 ref = IBaseFilter_Release(filter);
691 ok(!ref, "Got outstanding refcount %ld.\n", ref);
694 static void test_media_types(void)
696 IBaseFilter *filter = create_vmr9(0);
697 AM_MEDIA_TYPE *mt, req_mt = {{0}};
698 VIDEOINFOHEADER vih =
700 {0}, {0}, 0, 0, 0,
701 {sizeof(BITMAPINFOHEADER), 32, 24, 1, 0, 0xdeadbeef}
703 IEnumMediaTypes *enummt;
704 unsigned int i;
705 HRESULT hr;
706 ULONG ref;
707 IPin *pin;
709 static const GUID *subtype_tests[] =
711 &MEDIASUBTYPE_RGB565,
712 &MEDIASUBTYPE_RGB24,
713 &MEDIASUBTYPE_RGB32,
716 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
718 hr = IPin_EnumMediaTypes(pin, &enummt);
719 ok(hr == S_OK, "Got hr %#lx.\n", hr);
721 hr = IEnumMediaTypes_Next(enummt, 1, &mt, NULL);
722 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
724 IEnumMediaTypes_Release(enummt);
726 req_mt.majortype = MEDIATYPE_Video;
727 req_mt.formattype = FORMAT_VideoInfo;
728 req_mt.cbFormat = sizeof(VIDEOINFOHEADER);
729 req_mt.pbFormat = (BYTE *)&vih;
731 for (i = 0; i < ARRAY_SIZE(subtype_tests); ++i)
733 req_mt.subtype = *subtype_tests[i];
734 hr = IPin_QueryAccept(pin, &req_mt);
735 ok(hr == S_OK, "Got hr %#lx for subtype %s.\n", hr, wine_dbgstr_guid(subtype_tests[i]));
738 req_mt.subtype = MEDIASUBTYPE_RGB8;
739 hr = IPin_QueryAccept(pin, &req_mt);
740 todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
741 req_mt.subtype = MEDIASUBTYPE_NULL;
742 hr = IPin_QueryAccept(pin, &req_mt);
743 todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
744 req_mt.subtype = MEDIASUBTYPE_RGB24;
746 req_mt.majortype = MEDIATYPE_NULL;
747 hr = IPin_QueryAccept(pin, &req_mt);
748 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
749 req_mt.majortype = MEDIATYPE_Video;
751 req_mt.formattype = FORMAT_None;
752 hr = IPin_QueryAccept(pin, &req_mt);
753 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
755 req_mt.formattype = GUID_NULL;
756 hr = IPin_QueryAccept(pin, &req_mt);
757 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
759 IPin_Release(pin);
760 ref = IBaseFilter_Release(filter);
761 ok(!ref, "Got outstanding refcount %ld.\n", ref);
764 static void test_enum_media_types(void)
766 IBaseFilter *filter = create_vmr9(0);
767 IEnumMediaTypes *enum1, *enum2;
768 AM_MEDIA_TYPE *mts[2];
769 ULONG ref, count;
770 HRESULT hr;
771 IPin *pin;
773 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
775 hr = IPin_EnumMediaTypes(pin, &enum1);
776 ok(hr == S_OK, "Got hr %#lx.\n", hr);
778 hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL);
779 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
781 hr = IEnumMediaTypes_Next(enum1, 1, mts, &count);
782 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
783 ok(!count, "Got count %lu.\n", count);
785 hr = IEnumMediaTypes_Reset(enum1);
786 ok(hr == S_OK, "Got hr %#lx.\n", hr);
788 hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL);
789 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
791 hr = IEnumMediaTypes_Clone(enum1, &enum2);
792 ok(hr == S_OK, "Got hr %#lx.\n", hr);
794 hr = IEnumMediaTypes_Skip(enum1, 1);
795 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
797 hr = IEnumMediaTypes_Next(enum2, 1, mts, NULL);
798 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
800 IEnumMediaTypes_Release(enum1);
801 IEnumMediaTypes_Release(enum2);
802 IPin_Release(pin);
804 ref = IBaseFilter_Release(filter);
805 ok(!ref, "Got outstanding refcount %ld.\n", ref);
808 static void test_unconnected_filter_state(void)
810 IBaseFilter *filter = create_vmr9(0);
811 FILTER_STATE state;
812 HRESULT hr;
813 ULONG ref;
815 hr = IBaseFilter_GetState(filter, 0, &state);
816 ok(hr == S_OK, "Got hr %#lx.\n", hr);
817 ok(state == State_Stopped, "Got state %u.\n", state);
819 hr = IBaseFilter_Pause(filter);
820 ok(hr == S_OK, "Got hr %#lx.\n", hr);
822 hr = IBaseFilter_GetState(filter, 0, &state);
823 ok(hr == S_OK, "Got hr %#lx.\n", hr);
824 ok(state == State_Paused, "Got state %u.\n", state);
826 hr = IBaseFilter_Run(filter, 0);
827 ok(hr == S_OK, "Got hr %#lx.\n", hr);
829 hr = IBaseFilter_GetState(filter, 0, &state);
830 ok(hr == S_OK, "Got hr %#lx.\n", hr);
831 ok(state == State_Running, "Got state %u.\n", state);
833 hr = IBaseFilter_Pause(filter);
834 ok(hr == S_OK, "Got hr %#lx.\n", hr);
836 hr = IBaseFilter_GetState(filter, 0, &state);
837 ok(hr == S_OK, "Got hr %#lx.\n", hr);
838 ok(state == State_Paused, "Got state %u.\n", state);
840 hr = IBaseFilter_Stop(filter);
841 ok(hr == S_OK, "Got hr %#lx.\n", hr);
843 hr = IBaseFilter_GetState(filter, 0, &state);
844 ok(hr == S_OK, "Got hr %#lx.\n", hr);
845 ok(state == State_Stopped, "Got state %u.\n", state);
847 hr = IBaseFilter_Run(filter, 0);
848 ok(hr == S_OK, "Got hr %#lx.\n", hr);
850 hr = IBaseFilter_GetState(filter, 0, &state);
851 ok(hr == S_OK, "Got hr %#lx.\n", hr);
852 ok(state == State_Running, "Got state %u.\n", state);
854 hr = IBaseFilter_Stop(filter);
855 ok(hr == S_OK, "Got hr %#lx.\n", hr);
857 hr = IBaseFilter_GetState(filter, 0, &state);
858 ok(hr == S_OK, "Got hr %#lx.\n", hr);
859 ok(state == State_Stopped, "Got state %u.\n", state);
861 ref = IBaseFilter_Release(filter);
862 ok(!ref, "Got outstanding refcount %ld.\n", ref);
865 struct testfilter
867 struct strmbase_filter filter;
868 struct strmbase_source source;
871 static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface)
873 return CONTAINING_RECORD(iface, struct testfilter, filter);
876 static struct strmbase_pin *testfilter_get_pin(struct strmbase_filter *iface, unsigned int index)
878 struct testfilter *filter = impl_from_strmbase_filter(iface);
879 if (!index)
880 return &filter->source.pin;
881 return NULL;
884 static void testfilter_destroy(struct strmbase_filter *iface)
886 struct testfilter *filter = impl_from_strmbase_filter(iface);
887 strmbase_source_cleanup(&filter->source);
888 strmbase_filter_cleanup(&filter->filter);
891 static const struct strmbase_filter_ops testfilter_ops =
893 .filter_get_pin = testfilter_get_pin,
894 .filter_destroy = testfilter_destroy,
897 static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface,
898 IMemInputPin *peer, IMemAllocator **allocator)
900 return S_OK;
903 static const struct strmbase_source_ops testsource_ops =
905 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
906 .pfnDecideAllocator = testsource_DecideAllocator,
909 static void testfilter_init(struct testfilter *filter)
911 static const GUID clsid = {0xabacab};
912 strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops);
913 strmbase_source_init(&filter->source, &filter->filter, L"", &testsource_ops);
916 static void test_allocator(IMemInputPin *input)
918 IMemAllocator *req_allocator, *ret_allocator;
919 ALLOCATOR_PROPERTIES props, req_props;
920 HRESULT hr;
922 hr = IMemInputPin_GetAllocatorRequirements(input, &props);
923 ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
925 hr = IMemInputPin_GetAllocator(input, &ret_allocator);
926 todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr);
928 if (hr == S_OK)
930 hr = IMemAllocator_GetProperties(ret_allocator, &props);
931 ok(hr == S_OK, "Got hr %#lx.\n", hr);
932 ok(!props.cBuffers, "Got %ld buffers.\n", props.cBuffers);
933 ok(!props.cbBuffer, "Got size %ld.\n", props.cbBuffer);
934 ok(!props.cbAlign, "Got alignment %ld.\n", props.cbAlign);
935 ok(!props.cbPrefix, "Got prefix %ld.\n", props.cbPrefix);
937 hr = IMemInputPin_NotifyAllocator(input, ret_allocator, TRUE);
938 ok(hr == S_OK, "Got hr %#lx.\n", hr);
940 req_props.cBuffers = 1;
941 req_props.cbBuffer = 32 * 16 * 4;
942 req_props.cbAlign = 1;
943 req_props.cbPrefix = 0;
944 hr = IMemAllocator_SetProperties(ret_allocator, &req_props, &props);
945 ok(hr == S_OK, "Got hr %#lx.\n", hr);
946 ok(props.cBuffers == 1, "Got %ld buffers.\n", props.cBuffers);
947 ok(props.cbBuffer == 32 * 16 * 4, "Got size %ld.\n", props.cbBuffer);
948 ok(props.cbAlign == 1, "Got alignment %ld.\n", props.cbAlign);
949 ok(!props.cbPrefix, "Got prefix %ld.\n", props.cbPrefix);
951 IMemAllocator_Release(ret_allocator);
954 hr = IMemInputPin_NotifyAllocator(input, NULL, TRUE);
955 todo_wine ok(hr == E_FAIL, "Got hr %#lx.\n", hr);
957 CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
958 &IID_IMemAllocator, (void **)&req_allocator);
960 hr = IMemInputPin_NotifyAllocator(input, req_allocator, TRUE);
961 todo_wine ok(hr == E_FAIL, "Got hr %#lx.\n", hr);
963 IMemAllocator_Release(req_allocator);
966 struct frame_thread_params
968 IMemInputPin *sink;
969 IMediaSample *sample;
972 static DWORD WINAPI frame_thread(void *arg)
974 struct frame_thread_params *params = arg;
975 HRESULT hr;
977 if (winetest_debug > 1) trace("%04lx: Sending frame.\n", GetCurrentThreadId());
978 hr = IMemInputPin_Receive(params->sink, params->sample);
979 if (winetest_debug > 1) trace("%04lx: Returned %#lx.\n", GetCurrentThreadId(), hr);
980 IMediaSample_Release(params->sample);
981 free(params);
982 return hr;
985 static HANDLE send_frame_time(IMemInputPin *sink, REFERENCE_TIME start_time, DWORD color)
987 struct frame_thread_params *params = malloc(sizeof(*params));
988 IMemAllocator *allocator;
989 REFERENCE_TIME end_time;
990 IMediaSample *sample;
991 HANDLE thread;
992 LONG size, i;
993 HRESULT hr;
994 BYTE *data;
996 hr = IMemInputPin_GetAllocator(sink, &allocator);
997 ok(hr == S_OK, "Got hr %#lx.\n", hr);
999 hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
1000 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1002 size = IMediaSample_GetSize(sample);
1003 hr = IMediaSample_GetPointer(sample, &data);
1004 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1005 for (i = 0; i < size / sizeof(DWORD); ++i)
1006 ((DWORD *)data)[i] = color;
1008 hr = IMediaSample_SetActualDataLength(sample, size);
1009 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1011 start_time *= 10000000;
1012 end_time = start_time + 10000000;
1013 hr = IMediaSample_SetTime(sample, &start_time, &end_time);
1014 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1016 hr = IMediaSample_SetPreroll(sample, TRUE);
1017 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1019 params->sink = sink;
1020 params->sample = sample;
1021 thread = CreateThread(NULL, 0, frame_thread, params, 0, NULL);
1023 IMemAllocator_Release(allocator);
1024 return thread;
1027 static HANDLE send_frame(IMemInputPin *sink)
1029 return send_frame_time(sink, 0, 0x007f007f);
1032 static HRESULT join_thread_(int line, HANDLE thread)
1034 DWORD ret;
1035 ok_(__FILE__, line)(!WaitForSingleObject(thread, 1000), "Wait failed.\n");
1036 GetExitCodeThread(thread, &ret);
1037 CloseHandle(thread);
1038 return ret;
1040 #define join_thread(a) join_thread_(__LINE__, a)
1042 static void commit_allocator(IMemInputPin *input)
1044 IMemAllocator *allocator;
1045 HRESULT hr;
1047 hr = IMemInputPin_GetAllocator(input, &allocator);
1048 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1049 hr = IMemAllocator_Commit(allocator);
1050 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1051 IMemAllocator_Release(allocator);
1054 static void test_filter_state(IMemInputPin *input, IMediaControl *control)
1056 IMemAllocator *allocator;
1057 IMediaSample *sample;
1058 OAFilterState state;
1059 HANDLE thread;
1060 HRESULT hr;
1062 thread = send_frame(input);
1063 hr = join_thread(thread);
1064 ok(hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr);
1066 /* The renderer is not fully paused until it receives a sample. The thread
1067 * sending the sample blocks in IMemInputPin_Receive() until the filter is
1068 * stopped or run. */
1070 hr = IMediaControl_Pause(control);
1071 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1073 hr = IMediaControl_GetState(control, 0, &state);
1074 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
1076 thread = send_frame(input);
1078 hr = IMediaControl_GetState(control, 1000, &state);
1079 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1081 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1083 hr = IMediaControl_Stop(control);
1084 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1086 hr = join_thread(thread);
1087 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1089 /* The sink will decommit our allocator for us when stopping, however it
1090 * will not recommit it when pausing. */
1091 hr = IMemInputPin_GetAllocator(input, &allocator);
1092 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1093 hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
1094 todo_wine ok(hr == VFW_E_NOT_COMMITTED, "Got hr %#lx.\n", hr);
1095 if (hr == S_OK) IMediaSample_Release(sample);
1097 hr = IMemAllocator_Commit(allocator);
1098 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1099 thread = send_frame(input);
1100 hr = join_thread(thread);
1101 ok(hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr);
1103 hr = IMediaControl_Pause(control);
1104 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1106 hr = IMediaControl_GetState(control, 0, &state);
1107 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
1109 thread = send_frame(input);
1111 hr = IMediaControl_GetState(control, 1000, &state);
1112 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1114 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1116 hr = IMediaControl_Run(control);
1117 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1119 hr = IMediaControl_GetState(control, 0, &state);
1120 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1122 hr = join_thread(thread);
1123 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1125 thread = send_frame(input);
1126 hr = join_thread(thread);
1127 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1129 hr = IMediaControl_Pause(control);
1130 todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1132 hr = IMediaControl_GetState(control, 0, &state);
1133 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
1135 thread = send_frame(input);
1137 hr = IMediaControl_GetState(control, 1000, &state);
1138 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1140 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1142 hr = IMediaControl_Run(control);
1143 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1145 hr = IMediaControl_GetState(control, 0, &state);
1146 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1148 hr = join_thread(thread);
1149 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1151 hr = IMediaControl_Pause(control);
1152 todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1154 hr = IMediaControl_GetState(control, 0, &state);
1155 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
1157 hr = IMediaControl_Stop(control);
1158 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1160 hr = IMediaControl_GetState(control, 0, &state);
1161 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1163 commit_allocator(input);
1164 hr = IMediaControl_Pause(control);
1165 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1167 hr = IMediaControl_GetState(control, 0, &state);
1168 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
1170 hr = IMediaControl_Run(control);
1171 todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1173 hr = IMediaControl_GetState(control, 0, &state);
1174 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
1176 thread = send_frame(input);
1177 hr = join_thread(thread);
1178 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1180 hr = IMediaControl_GetState(control, 0, &state);
1181 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1183 hr = IMediaControl_Stop(control);
1184 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1186 hr = IMediaControl_GetState(control, 0, &state);
1187 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1189 IMemAllocator_Release(allocator);
1192 static void test_flushing(IPin *pin, IMemInputPin *input, IMediaControl *control)
1194 OAFilterState state;
1195 HANDLE thread;
1196 HRESULT hr;
1198 commit_allocator(input);
1199 hr = IMediaControl_Pause(control);
1200 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1202 thread = send_frame(input);
1203 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1205 hr = IMediaControl_GetState(control, 1000, &state);
1206 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1208 hr = IPin_BeginFlush(pin);
1209 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1211 hr = join_thread(thread);
1212 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1214 thread = send_frame(input);
1215 hr = join_thread(thread);
1216 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1218 hr = IPin_EndFlush(pin);
1219 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1221 /* We dropped the sample we were holding, so now we need a new one... */
1223 hr = IMediaControl_GetState(control, 0, &state);
1224 todo_wine ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
1225 ok(state == State_Paused, "Got state %#lx.\n", state);
1227 thread = send_frame(input);
1228 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1230 hr = IMediaControl_GetState(control, 1000, &state);
1231 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1232 ok(state == State_Paused, "Got state %#lx.\n", state);
1234 hr = IMediaControl_Run(control);
1235 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1236 hr = join_thread(thread);
1237 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1239 hr = IPin_BeginFlush(pin);
1240 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1242 thread = send_frame(input);
1243 hr = join_thread(thread);
1244 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1246 hr = IPin_EndFlush(pin);
1247 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1249 thread = send_frame(input);
1250 hr = join_thread(thread);
1251 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1253 hr = IMediaControl_Stop(control);
1254 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1257 static unsigned int check_event_code(IMediaEvent *eventsrc, DWORD timeout, LONG expected_code, LONG_PTR expected1, LONG_PTR expected2)
1259 LONG_PTR param1, param2;
1260 unsigned int ret = 0;
1261 HRESULT hr;
1262 LONG code;
1264 while ((hr = IMediaEvent_GetEvent(eventsrc, &code, &param1, &param2, timeout)) == S_OK)
1266 if (code == expected_code)
1268 ok(param1 == expected1, "Got param1 %#Ix.\n", param1);
1269 ok(param2 == expected2, "Got param2 %#Ix.\n", param2);
1270 ret++;
1272 IMediaEvent_FreeEventParams(eventsrc, code, param1, param2);
1273 timeout = 0;
1275 ok(hr == E_ABORT, "Got hr %#lx.\n", hr);
1277 return ret;
1280 static inline unsigned int check_ec_complete(IMediaEvent *eventsrc, DWORD timeout)
1282 return check_event_code(eventsrc, timeout, EC_COMPLETE, S_OK, 0);
1285 static void test_eos(IPin *pin, IMemInputPin *input, IMediaControl *control)
1287 IMediaEvent *eventsrc;
1288 OAFilterState state;
1289 HRESULT hr;
1290 BOOL ret;
1292 IMediaControl_QueryInterface(control, &IID_IMediaEvent, (void **)&eventsrc);
1294 commit_allocator(input);
1295 hr = IMediaControl_Pause(control);
1296 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1297 ret = check_ec_complete(eventsrc, 0);
1298 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1300 hr = IPin_EndOfStream(pin);
1301 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1303 hr = IMediaControl_GetState(control, 1000, &state);
1304 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1305 ret = check_ec_complete(eventsrc, 0);
1306 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1308 hr = join_thread(send_frame(input));
1309 todo_wine ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr);
1311 hr = IMediaControl_Run(control);
1312 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1313 ret = check_ec_complete(eventsrc, 0);
1314 ok(ret == 1, "Expected EC_COMPLETE.\n");
1316 hr = IMediaControl_Stop(control);
1317 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1318 ret = check_ec_complete(eventsrc, 0);
1319 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1321 /* We do not receive an EC_COMPLETE notification until the last sample is
1322 * done rendering. */
1324 commit_allocator(input);
1325 hr = IMediaControl_Run(control);
1326 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1327 hr = join_thread(send_frame(input));
1328 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1329 hr = IMediaControl_GetState(control, 1000, &state);
1330 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1331 ret = check_ec_complete(eventsrc, 0);
1332 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1334 hr = IPin_EndOfStream(pin);
1335 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1336 ret = check_ec_complete(eventsrc, 0);
1337 todo_wine ok(!ret, "Got unexpected EC_COMPLETE.\n");
1338 ret = check_ec_complete(eventsrc, 1600);
1339 todo_wine ok(ret == 1, "Expected EC_COMPLETE.\n");
1341 hr = IMediaControl_Stop(control);
1342 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1343 ret = check_ec_complete(eventsrc, 0);
1344 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1346 /* Test sending EOS while flushing. */
1348 commit_allocator(input);
1349 hr = IMediaControl_Run(control);
1350 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1351 hr = join_thread(send_frame(input));
1352 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1354 hr = IPin_BeginFlush(pin);
1355 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1356 hr = IPin_EndOfStream(pin);
1357 todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1358 hr = IPin_EndFlush(pin);
1359 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1361 hr = IMediaControl_Stop(control);
1362 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1363 ret = check_ec_complete(eventsrc, 0);
1364 todo_wine ok(!ret, "Got unexpected EC_COMPLETE.\n");
1366 /* Test sending EOS and then flushing or stopping. */
1368 commit_allocator(input);
1369 hr = IMediaControl_Run(control);
1370 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1371 hr = join_thread(send_frame(input));
1372 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1373 hr = IMediaControl_GetState(control, 1000, &state);
1374 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1376 hr = IPin_EndOfStream(pin);
1377 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1378 ret = check_ec_complete(eventsrc, 0);
1379 todo_wine ok(!ret, "Got unexpected EC_COMPLETE.\n");
1381 hr = IPin_BeginFlush(pin);
1382 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1383 hr = IPin_EndFlush(pin);
1384 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1386 hr = join_thread(send_frame(input));
1387 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1388 hr = IPin_EndOfStream(pin);
1389 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1390 ret = check_ec_complete(eventsrc, 0);
1391 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1393 hr = IMediaControl_Stop(control);
1394 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1395 ret = check_ec_complete(eventsrc, 0);
1396 ok(!ret, "Got unexpected EC_COMPLETE.\n");
1398 IMediaEvent_Release(eventsrc);
1401 static void test_sample_time(IPin *pin, IMemInputPin *input, IMediaControl *control)
1403 OAFilterState state;
1404 HANDLE thread;
1405 HRESULT hr;
1407 commit_allocator(input);
1408 hr = IMediaControl_Pause(control);
1409 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1411 hr = IMediaControl_GetState(control, 0, &state);
1412 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
1414 thread = send_frame_time(input, 1, 0x000000ff); /* blue */
1416 hr = IMediaControl_GetState(control, 1000, &state);
1417 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1419 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1421 hr = IMediaControl_Run(control);
1422 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1424 ok(WaitForSingleObject(thread, 500) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1426 hr = join_thread(thread);
1427 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1429 /* Sample time is relative to the time passed to Run(). Thus a sample
1430 * stamped at or earlier than 1s will now be displayed immediately, because
1431 * that time has already passed.
1432 * One may manually verify that all of the frames in this function are
1433 * rendered, including (by adding a Sleep() after sending the frame) the
1434 * cyan and green frames. Thus the VMR does not attempt to drop any frames
1435 * that it considers late. This remains true if the frames are marked as
1436 * discontinuous. */
1438 hr = join_thread(send_frame_time(input, 1, 0x0000ffff)); /* cyan */
1439 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1441 hr = join_thread(send_frame_time(input, 0, 0x0000ff00)); /* green */
1442 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1444 hr = join_thread(send_frame_time(input, -2, 0x00ff0000)); /* red */
1445 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1447 thread = send_frame_time(input, 1000000, 0x00ffffff); /* white */
1448 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1450 hr = IPin_BeginFlush(pin);
1451 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1452 hr = join_thread(thread);
1453 /* If the frame makes it to Receive() in time to be rendered, we get S_OK. */
1454 ok(hr == S_OK || hr == S_FALSE, "Got hr %#lx.\n", hr);
1455 hr = IPin_EndFlush(pin);
1456 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1458 thread = send_frame_time(input, 1000000, 0x00ffff00); /* yellow */
1459 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block in Receive().\n");
1461 hr = IMediaControl_Stop(control);
1462 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1463 hr = join_thread(thread);
1464 /* If the frame makes it to Receive() in time to be rendered, we get S_OK. */
1465 ok(hr == S_OK || hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr);
1468 static void test_current_image(IBaseFilter *filter, IMemInputPin *input,
1469 IMediaControl *control, const BITMAPINFOHEADER *req_bih)
1471 LONG buffer[(sizeof(BITMAPINFOHEADER) + 32 * 16 * 4) / 4];
1472 const BITMAPINFOHEADER *bih = (BITMAPINFOHEADER *)buffer;
1473 const DWORD *data = (DWORD *)((char *)buffer + sizeof(BITMAPINFOHEADER));
1474 BITMAPINFOHEADER expect_bih = *req_bih;
1475 OAFilterState state;
1476 IBasicVideo *video;
1477 unsigned int i;
1478 HANDLE thread;
1479 HRESULT hr;
1480 LONG size;
1482 expect_bih.biSizeImage = 32 * 16 * 4;
1484 IBaseFilter_QueryInterface(filter, &IID_IBasicVideo, (void **)&video);
1486 hr = IBasicVideo_GetCurrentImage(video, NULL, NULL);
1487 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
1489 hr = IBasicVideo_GetCurrentImage(video, NULL, buffer);
1490 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
1492 size = 0xdeadbeef;
1493 hr = IBasicVideo_GetCurrentImage(video, &size, NULL);
1494 todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr);
1495 todo_wine ok(size == sizeof(BITMAPINFOHEADER) + 32 * 16 * 4, "Got size %ld.\n", size);
1497 size = sizeof(buffer);
1498 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1499 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1500 ok(size == sizeof(buffer), "Got size %ld.\n", size);
1501 ok(!memcmp(bih, &expect_bih, sizeof(BITMAPINFOHEADER)), "Bitmap headers didn't match.\n");
1502 /* The contents seem to reflect the last frame rendered. */
1504 commit_allocator(input);
1505 hr = IMediaControl_Pause(control);
1506 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1508 size = sizeof(buffer);
1509 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1510 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1511 ok(size == sizeof(buffer), "Got size %ld.\n", size);
1512 ok(!memcmp(bih, &expect_bih, sizeof(BITMAPINFOHEADER)), "Bitmap headers didn't match.\n");
1513 /* The contents seem to reflect the last frame rendered. */
1515 thread = send_frame(input);
1516 hr = IMediaControl_GetState(control, 1000, &state);
1517 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1519 size = 1;
1520 memset(buffer, 0xcc, sizeof(buffer));
1521 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1522 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1523 ok(size == 1, "Got size %ld.\n", size);
1525 size = sizeof(buffer);
1526 memset(buffer, 0xcc, sizeof(buffer));
1527 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1528 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1529 ok(size == sizeof(buffer), "Got size %ld.\n", size);
1530 ok(!memcmp(bih, &expect_bih, sizeof(BITMAPINFOHEADER)), "Bitmap headers didn't match.\n");
1531 for (i = 0; i < 32 * 16; ++i)
1532 ok((data[i] & 0xffffff) == 0x7f007f, "Got unexpected color %08lx at %u.\n", data[i], i);
1534 hr = IMediaControl_Run(control);
1535 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1536 join_thread(thread);
1538 size = sizeof(buffer);
1539 memset(buffer, 0xcc, sizeof(buffer));
1540 hr = IBasicVideo_GetCurrentImage(video, &size, buffer);
1541 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1542 ok(size == sizeof(buffer), "Got size %ld.\n", size);
1543 ok(!memcmp(bih, &expect_bih, sizeof(BITMAPINFOHEADER)), "Bitmap headers didn't match.\n");
1544 for (i = 0; i < 32 * 16; ++i)
1545 ok((data[i] & 0xffffff) == 0x7f007f, "Got unexpected color %08lx at %u.\n", data[i], i);
1547 hr = IMediaControl_Stop(control);
1548 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1550 IBasicVideo_Release(video);
1553 static inline unsigned int check_ec_userabort(IMediaEvent *eventsrc, DWORD timeout)
1555 return check_event_code(eventsrc, timeout, EC_USERABORT, 0, 0);
1558 static void test_window_close(IPin *pin, IMemInputPin *input, IMediaControl *control)
1560 IMediaEvent *eventsrc;
1561 OAFilterState state;
1562 IOverlay *overlay;
1563 HANDLE thread;
1564 HRESULT hr;
1565 HWND hwnd;
1566 BOOL ret;
1568 IMediaControl_QueryInterface(control, &IID_IMediaEvent, (void **)&eventsrc);
1569 IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay);
1571 hr = IOverlay_GetWindowHandle(overlay, &hwnd);
1572 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1573 IOverlay_Release(overlay);
1575 commit_allocator(input);
1576 hr = IMediaControl_Pause(control);
1577 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1578 ret = check_ec_userabort(eventsrc, 0);
1579 ok(!ret, "Got unexpected EC_USERABORT.\n");
1581 SendMessageW(hwnd, WM_CLOSE, 0, 0);
1583 hr = IMediaControl_GetState(control, 1000, &state);
1584 ok(hr == VFW_S_STATE_INTERMEDIATE, "Got hr %#lx.\n", hr);
1585 ret = check_ec_userabort(eventsrc, 0);
1586 ok(ret == 1, "Expected EC_USERABORT.\n");
1588 ok(IsWindow(hwnd), "Window should exist.\n");
1589 ok(!IsWindowVisible(hwnd), "Window should be visible.\n");
1591 thread = send_frame(input);
1592 ret = WaitForSingleObject(thread, 1000);
1593 todo_wine ok(ret == WAIT_OBJECT_0, "Wait failed\n");
1594 if (ret == WAIT_OBJECT_0)
1596 GetExitCodeThread(thread, (DWORD *)&hr);
1597 ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr);
1599 CloseHandle(thread);
1601 hr = IMediaControl_Run(control);
1602 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1603 ret = check_ec_userabort(eventsrc, 0);
1604 ok(!ret, "Got unexpected EC_USERABORT.\n");
1606 hr = IMediaControl_Stop(control);
1607 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1608 ret = check_ec_userabort(eventsrc, 0);
1609 ok(!ret, "Got unexpected EC_USERABORT.\n");
1611 /* We receive an EC_USERABORT notification immediately. */
1613 commit_allocator(input);
1614 hr = IMediaControl_Run(control);
1615 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1616 hr = join_thread(send_frame(input));
1617 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1618 hr = IMediaControl_GetState(control, 1000, &state);
1619 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1620 ret = check_ec_userabort(eventsrc, 0);
1621 ok(!ret, "Got unexpected EC_USERABORT.\n");
1623 SendMessageW(hwnd, WM_CLOSE, 0, 0);
1625 ret = check_ec_userabort(eventsrc, 0);
1626 ok(ret == 1, "Expected EC_USERABORT.\n");
1628 ok(IsWindow(hwnd), "Window should exist.\n");
1629 ok(!IsWindowVisible(hwnd), "Window should be visible.\n");
1631 hr = IMediaControl_Stop(control);
1632 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1633 ret = check_ec_userabort(eventsrc, 0);
1634 ok(!ret, "Got unexpected EC_USERABORT.\n");
1636 IMediaEvent_Release(eventsrc);
1639 static void test_connect_pin(void)
1641 VIDEOINFOHEADER vih =
1643 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
1644 .bmiHeader.biBitCount = 32,
1645 .bmiHeader.biWidth = 32,
1646 .bmiHeader.biHeight = 16,
1647 .bmiHeader.biPlanes = 1,
1648 .bmiHeader.biCompression = BI_RGB,
1650 AM_MEDIA_TYPE req_mt =
1652 .majortype = MEDIATYPE_Video,
1653 .formattype = FORMAT_VideoInfo,
1654 .cbFormat = sizeof(vih),
1655 .pbFormat = (BYTE *)&vih,
1657 ALLOCATOR_PROPERTIES req_props = {1, 32 * 16 * 4, 1, 0}, ret_props;
1658 IBaseFilter *filter = create_vmr9(VMR9Mode_Windowed);
1659 IFilterGraph2 *graph = create_graph();
1660 struct testfilter source;
1661 IMemAllocator *allocator;
1662 IMediaControl *control;
1663 IMemInputPin *input;
1664 unsigned int i, j;
1665 AM_MEDIA_TYPE mt;
1666 IPin *pin, *peer;
1667 HRESULT hr;
1668 ULONG ref;
1670 static const GUID *subtype_tests[] =
1672 &MEDIASUBTYPE_RGB555,
1673 &MEDIASUBTYPE_RGB565,
1674 &MEDIASUBTYPE_RGB24,
1675 &MEDIASUBTYPE_RGB32,
1677 static const WORD bpp_tests[] = {15, 16, 24, 32};
1679 testfilter_init(&source);
1681 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL);
1682 IFilterGraph2_AddFilter(graph, filter, NULL);
1683 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
1685 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
1686 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
1688 for (i = 0; i < ARRAY_SIZE(subtype_tests); ++i)
1690 req_mt.subtype = *subtype_tests[i];
1692 for (j = 0; j < ARRAY_SIZE(bpp_tests); ++j)
1694 vih.bmiHeader.biBitCount = bpp_tests[j];
1696 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1697 if (hr == E_FAIL)
1699 skip("Got E_FAIL when connecting.\n");
1700 goto out;
1702 ok(hr == S_OK, "Got hr %#lx for subtype %s and bpp %u.\n", hr,
1703 wine_dbgstr_guid(subtype_tests[i]), bpp_tests[j]);
1705 hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
1706 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1707 hr = IFilterGraph2_Disconnect(graph, pin);
1708 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1712 req_mt.formattype = FORMAT_None;
1713 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1714 ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#lx.\n", hr);
1715 req_mt.formattype = FORMAT_VideoInfo;
1717 req_mt.subtype = MEDIASUBTYPE_RGB8;
1718 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1719 ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#lx.\n", hr);
1720 req_mt.subtype = MEDIASUBTYPE_WAVE;
1721 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1722 ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#lx.\n", hr);
1723 req_mt.subtype = MEDIASUBTYPE_RGB32;
1725 peer = (IPin *)0xdeadbeef;
1726 hr = IPin_ConnectedTo(pin, &peer);
1727 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
1728 ok(!peer, "Got peer %p.\n", peer);
1730 hr = IPin_ConnectionMediaType(pin, &mt);
1731 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
1733 hr = IMediaControl_Pause(control);
1734 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1735 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1736 ok(hr == VFW_E_NOT_STOPPED, "Got hr %#lx.\n", hr);
1737 hr = IMediaControl_Stop(control);
1738 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1740 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
1741 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1743 hr = IPin_ConnectedTo(pin, &peer);
1744 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1745 ok(peer == &source.source.pin.IPin_iface, "Got peer %p.\n", peer);
1746 IPin_Release(peer);
1748 hr = IPin_ConnectionMediaType(pin, &mt);
1749 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1750 ok(compare_media_types(&mt, &req_mt), "Media types didn't match.\n");
1752 /* Disconnecting while not stopped is broken: it returns S_OK, but
1753 * subsequent attempts to connect return VFW_E_ALREADY_CONNECTED. */
1755 test_allocator(input);
1757 hr = IMemInputPin_GetAllocator(input, &allocator);
1758 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1759 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
1760 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1761 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
1762 hr = IMemAllocator_Commit(allocator);
1763 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1764 IMemAllocator_Release(allocator);
1766 hr = IMemInputPin_ReceiveCanBlock(input);
1767 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1769 test_filter_state(input, control);
1770 test_flushing(pin, input, control);
1771 test_eos(pin, input, control);
1772 test_sample_time(pin, input, control);
1773 test_current_image(filter, input, control, &vih.bmiHeader);
1774 test_window_close(pin, input, control);
1776 hr = IFilterGraph2_Disconnect(graph, pin);
1777 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1778 hr = IFilterGraph2_Disconnect(graph, pin);
1779 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
1780 ok(source.source.pin.peer == pin, "Got peer %p.\n", source.source.pin.peer);
1781 IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
1783 peer = (IPin *)0xdeadbeef;
1784 hr = IPin_ConnectedTo(pin, &peer);
1785 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
1786 ok(!peer, "Got peer %p.\n", peer);
1788 hr = IPin_ConnectionMediaType(pin, &mt);
1789 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
1791 out:
1792 IMediaControl_Release(control);
1793 ref = IFilterGraph2_Release(graph);
1794 ok(!ref, "Got outstanding refcount %ld.\n", ref);
1795 IMemInputPin_Release(input);
1796 IPin_Release(pin);
1797 ref = IBaseFilter_Release(filter);
1798 ok(!ref, "Got outstanding refcount %ld.\n", ref);
1799 ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface);
1800 ok(!ref, "Got outstanding refcount %ld.\n", ref);
1803 static void test_overlay(void)
1805 IBaseFilter *filter = create_vmr9(0);
1806 IOverlay *overlay;
1807 HRESULT hr;
1808 ULONG ref;
1809 IPin *pin;
1810 HWND hwnd;
1812 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
1814 hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay);
1815 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1817 hwnd = (HWND)0xdeadbeef;
1818 hr = IOverlay_GetWindowHandle(overlay, &hwnd);
1819 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1820 ok(hwnd && hwnd != (HWND)0xdeadbeef, "Got invalid window %p.\n", hwnd);
1822 IOverlay_Release(overlay);
1823 IPin_Release(pin);
1824 ref = IBaseFilter_Release(filter);
1825 ok(!ref, "Got outstanding refcount %ld.\n", ref);
1827 filter = create_vmr9(VMR9Mode_Windowless);
1828 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
1830 hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay);
1831 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1833 hwnd = (HWND)0xdeadbeef;
1834 hr = IOverlay_GetWindowHandle(overlay, &hwnd);
1835 ok(hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr);
1836 ok(hwnd == (HWND)0xdeadbeef, "Got window %p.\n", hwnd);
1838 IOverlay_Release(overlay);
1839 IPin_Release(pin);
1840 ref = IBaseFilter_Release(filter);
1841 ok(!ref, "Got outstanding refcount %ld.\n", ref);
1843 filter = create_vmr9(VMR9Mode_Renderless);
1844 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
1846 hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay);
1847 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1849 hwnd = (HWND)0xdeadbeef;
1850 hr = IOverlay_GetWindowHandle(overlay, &hwnd);
1851 ok(hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr);
1852 ok(hwnd == (HWND)0xdeadbeef, "Got window %p.\n", hwnd);
1854 IOverlay_Release(overlay);
1855 IPin_Release(pin);
1856 ref = IBaseFilter_Release(filter);
1857 ok(!ref, "Got outstanding refcount %ld.\n", ref);
1860 /* try to make sure pending X events have been processed before continuing */
1861 static void flush_events(void)
1863 int diff = 200;
1864 DWORD time;
1865 MSG msg;
1867 time = GetTickCount() + diff;
1868 while (diff > 0)
1870 if (MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT) == WAIT_TIMEOUT)
1871 break;
1872 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
1873 DispatchMessageA(&msg);
1874 diff = time - GetTickCount();
1878 static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1880 if (winetest_debug > 1)
1881 trace("hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix.\n", hwnd, msg, wparam, lparam);
1883 if (wparam == 0xdeadbeef)
1884 return 0;
1886 return DefWindowProcA(hwnd, msg, wparam, lparam);
1889 static void test_video_window_caption(IVideoWindow *window, HWND hwnd)
1891 WCHAR text[50];
1892 BSTR caption;
1893 HRESULT hr;
1895 hr = IVideoWindow_get_Caption(window, &caption);
1896 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1897 ok(!wcscmp(caption, L"ActiveMovie Window"), "Got caption %s.\n", wine_dbgstr_w(caption));
1898 SysFreeString(caption);
1900 GetWindowTextW(hwnd, text, ARRAY_SIZE(text));
1901 ok(!wcscmp(text, L"ActiveMovie Window"), "Got caption %s.\n", wine_dbgstr_w(text));
1903 caption = SysAllocString(L"foo");
1904 hr = IVideoWindow_put_Caption(window, caption);
1905 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1906 SysFreeString(caption);
1908 hr = IVideoWindow_get_Caption(window, &caption);
1909 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1910 ok(!wcscmp(caption, L"foo"), "Got caption %s.\n", wine_dbgstr_w(caption));
1911 SysFreeString(caption);
1913 GetWindowTextW(hwnd, text, ARRAY_SIZE(text));
1914 ok(!wcscmp(text, L"foo"), "Got caption %s.\n", wine_dbgstr_w(text));
1917 static void test_video_window_style(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
1919 HRESULT hr;
1920 LONG style;
1922 hr = IVideoWindow_get_WindowStyle(window, &style);
1923 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1924 ok(style == (WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW),
1925 "Got style %#lx.\n", style);
1927 style = GetWindowLongA(hwnd, GWL_STYLE);
1928 ok(style == (WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW),
1929 "Got style %#lx.\n", style);
1931 hr = IVideoWindow_put_WindowStyle(window, style | WS_DISABLED);
1932 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
1933 hr = IVideoWindow_put_WindowStyle(window, style | WS_HSCROLL);
1934 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
1935 hr = IVideoWindow_put_WindowStyle(window, style | WS_VSCROLL);
1936 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
1937 hr = IVideoWindow_put_WindowStyle(window, style | WS_MAXIMIZE);
1938 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
1939 hr = IVideoWindow_put_WindowStyle(window, style | WS_MINIMIZE);
1940 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
1942 hr = IVideoWindow_put_WindowStyle(window, style & ~WS_CLIPCHILDREN);
1943 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1945 hr = IVideoWindow_get_WindowStyle(window, &style);
1946 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1947 ok(style == (WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW), "Got style %#lx.\n", style);
1949 style = GetWindowLongA(hwnd, GWL_STYLE);
1950 ok(style == (WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW), "Got style %#lx.\n", style);
1952 flaky_wine
1953 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
1955 hr = IVideoWindow_get_WindowStyleEx(window, &style);
1956 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1957 ok(style == WS_EX_WINDOWEDGE, "Got style %#lx.\n", style);
1959 style = GetWindowLongA(hwnd, GWL_EXSTYLE);
1960 ok(style == WS_EX_WINDOWEDGE, "Got style %#lx.\n", style);
1962 hr = IVideoWindow_put_WindowStyleEx(window, style | WS_EX_TRANSPARENT);
1963 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1965 hr = IVideoWindow_get_WindowStyleEx(window, &style);
1966 ok(hr == S_OK, "Got hr %#lx.\n", hr);
1967 ok(style == (WS_EX_WINDOWEDGE | WS_EX_TRANSPARENT), "Got style %#lx.\n", style);
1969 style = GetWindowLongA(hwnd, GWL_EXSTYLE);
1970 ok(style == (WS_EX_WINDOWEDGE | WS_EX_TRANSPARENT), "Got style %#lx.\n", style);
1973 static BOOL CALLBACK top_window_cb(HWND hwnd, LPARAM ctx)
1975 DWORD pid;
1976 GetWindowThreadProcessId(hwnd, &pid);
1977 if (pid == GetCurrentProcessId() && (GetWindowLongW(hwnd, GWL_STYLE) & WS_VISIBLE))
1979 *(HWND *)ctx = hwnd;
1980 return FALSE;
1982 return TRUE;
1985 static HWND get_top_window(void)
1987 HWND hwnd;
1988 EnumWindows(top_window_cb, (LPARAM)&hwnd);
1989 return hwnd;
1992 static void test_video_window_state(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
1994 HRESULT hr;
1995 LONG state;
1996 HWND top;
1998 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2000 hr = IVideoWindow_get_WindowState(window, &state);
2001 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2002 ok(state == SW_HIDE, "Got state %ld.\n", state);
2004 hr = IVideoWindow_get_Visible(window, &state);
2005 ok(state == OAFALSE, "Got state %ld.\n", state);
2007 ok(!IsWindowVisible(hwnd), "Window should not be visible.\n");
2008 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
2009 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
2011 hr = IVideoWindow_put_WindowState(window, SW_SHOWNA);
2012 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2014 hr = IVideoWindow_get_WindowState(window, &state);
2015 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2016 ok(state == SW_SHOW, "Got state %ld.\n", state);
2018 hr = IVideoWindow_get_Visible(window, &state);
2019 ok(state == OATRUE, "Got state %ld.\n", state);
2021 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
2022 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
2023 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
2024 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2025 top = get_top_window();
2026 ok(top == hwnd, "Got top window %p.\n", top);
2028 hr = IVideoWindow_put_WindowState(window, SW_MINIMIZE);
2029 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2031 hr = IVideoWindow_get_WindowState(window, &state);
2032 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2033 ok(state == SW_MINIMIZE, "Got state %ld.\n", state);
2035 hr = IVideoWindow_get_Visible(window, &state);
2036 ok(state == OATRUE, "Got state %ld.\n", state);
2038 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
2039 ok(IsIconic(hwnd), "Window should be minimized.\n");
2040 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
2041 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2043 hr = IVideoWindow_put_WindowState(window, SW_RESTORE);
2044 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2046 hr = IVideoWindow_get_WindowState(window, &state);
2047 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2048 ok(state == SW_SHOW, "Got state %ld.\n", state);
2050 hr = IVideoWindow_get_Visible(window, &state);
2051 ok(state == OATRUE, "Got state %ld.\n", state);
2053 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
2054 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
2055 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
2056 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
2058 hr = IVideoWindow_put_WindowState(window, SW_MAXIMIZE);
2059 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2061 hr = IVideoWindow_get_WindowState(window, &state);
2062 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2063 ok(state == SW_MAXIMIZE, "Got state %ld.\n", state);
2065 hr = IVideoWindow_get_Visible(window, &state);
2066 ok(state == OATRUE, "Got state %ld.\n", state);
2068 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
2069 ok(!IsIconic(hwnd), "Window should be minimized.\n");
2070 ok(IsZoomed(hwnd), "Window should not be maximized.\n");
2071 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
2073 hr = IVideoWindow_put_WindowState(window, SW_RESTORE);
2074 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2076 hr = IVideoWindow_put_WindowState(window, SW_HIDE);
2077 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2079 hr = IVideoWindow_get_WindowState(window, &state);
2080 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2081 ok(state == SW_HIDE, "Got state %ld.\n", state);
2083 hr = IVideoWindow_get_Visible(window, &state);
2084 ok(state == OAFALSE, "Got state %ld.\n", state);
2086 ok(!IsWindowVisible(hwnd), "Window should not be visible.\n");
2087 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
2088 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
2089 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2091 hr = IVideoWindow_put_Visible(window, OATRUE);
2092 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2094 hr = IVideoWindow_get_WindowState(window, &state);
2095 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2096 ok(state == SW_SHOW, "Got state %ld.\n", state);
2098 hr = IVideoWindow_get_Visible(window, &state);
2099 ok(state == OATRUE, "Got state %ld.\n", state);
2101 ok(IsWindowVisible(hwnd), "Window should be visible.\n");
2102 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
2103 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
2104 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
2106 hr = IVideoWindow_put_Visible(window, OAFALSE);
2107 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2109 hr = IVideoWindow_get_WindowState(window, &state);
2110 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2111 ok(state == SW_HIDE, "Got state %ld.\n", state);
2113 hr = IVideoWindow_get_Visible(window, &state);
2114 ok(state == OAFALSE, "Got state %ld.\n", state);
2116 ok(!IsWindowVisible(hwnd), "Window should not be visible.\n");
2117 ok(!IsIconic(hwnd), "Window should not be minimized.\n");
2118 ok(!IsZoomed(hwnd), "Window should not be maximized.\n");
2119 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2121 hr = IVideoWindow_put_WindowState(window, SW_SHOWNA);
2122 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2124 hr = IVideoWindow_SetWindowForeground(window, TRUE);
2125 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
2127 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2128 hr = IVideoWindow_SetWindowForeground(window, OATRUE);
2129 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2130 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
2131 ok(GetFocus() == hwnd, "Got focus window %p.\n", GetFocus());
2132 ok(GetForegroundWindow() == hwnd, "Got foreground window %p.\n", GetForegroundWindow());
2133 top = get_top_window();
2134 ok(top == hwnd, "Got top window %p.\n", top);
2136 hr = IVideoWindow_SetWindowForeground(window, OAFALSE);
2137 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2138 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
2139 ok(GetFocus() == hwnd, "Got focus window %p.\n", GetFocus());
2140 ok(GetForegroundWindow() == hwnd, "Got foreground window %p.\n", GetForegroundWindow());
2141 top = get_top_window();
2142 ok(top == hwnd, "Got top window %p.\n", top);
2144 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2145 hr = IVideoWindow_SetWindowForeground(window, OAFALSE);
2146 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2147 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2148 ok(GetFocus() == our_hwnd, "Got focus window %p.\n", GetFocus());
2149 ok(GetForegroundWindow() == our_hwnd, "Got foreground window %p.\n", GetForegroundWindow());
2150 top = get_top_window();
2151 ok(top == hwnd, "Got top window %p.\n", top);
2154 static void test_video_window_position(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
2156 LONG left, width, top, height, expect_width, expect_height;
2157 RECT rect = {0, 0, 600, 400};
2158 HWND top_hwnd;
2159 HRESULT hr;
2161 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2163 AdjustWindowRect(&rect, GetWindowLongA(hwnd, GWL_STYLE), FALSE);
2164 expect_width = rect.right - rect.left;
2165 expect_height = rect.bottom - rect.top;
2167 hr = IVideoWindow_put_Left(window, 0);
2168 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2169 hr = IVideoWindow_put_Top(window, 0);
2170 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2172 hr = IVideoWindow_get_Left(window, &left);
2173 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2174 ok(left == 0, "Got left %ld.\n", left);
2175 hr = IVideoWindow_get_Top(window, &top);
2176 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2177 ok(top == 0, "Got top %ld.\n", top);
2178 hr = IVideoWindow_get_Width(window, &width);
2179 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2180 ok(width == expect_width, "Got width %ld.\n", width);
2181 hr = IVideoWindow_get_Height(window, &height);
2182 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2183 ok(height == expect_height, "Got height %ld.\n", height);
2184 hr = IVideoWindow_GetWindowPosition(window, &left, &top, &width, &height);
2185 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2186 ok(left == 0, "Got left %ld.\n", left);
2187 ok(top == 0, "Got top %ld.\n", top);
2188 ok(width == expect_width, "Got width %ld.\n", width);
2189 ok(height == expect_height, "Got height %ld.\n", height);
2190 GetWindowRect(hwnd, &rect);
2191 ok(rect.left == 0, "Got window left %ld.\n", rect.left);
2192 ok(rect.top == 0, "Got window top %ld.\n", rect.top);
2193 ok(rect.right == expect_width, "Got window right %ld.\n", rect.right);
2194 ok(rect.bottom == expect_height, "Got window bottom %ld.\n", rect.bottom);
2196 hr = IVideoWindow_put_Left(window, 10);
2197 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2199 hr = IVideoWindow_get_Left(window, &left);
2200 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2201 ok(left == 10, "Got left %ld.\n", left);
2202 hr = IVideoWindow_get_Top(window, &top);
2203 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2204 ok(top == 0, "Got top %ld.\n", top);
2205 hr = IVideoWindow_get_Width(window, &width);
2206 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2207 ok(width == expect_width, "Got width %ld.\n", width);
2208 hr = IVideoWindow_get_Height(window, &height);
2209 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2210 ok(height == expect_height, "Got height %ld.\n", height);
2211 hr = IVideoWindow_GetWindowPosition(window, &left, &top, &width, &height);
2212 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2213 ok(left == 10, "Got left %ld.\n", left);
2214 ok(top == 0, "Got top %ld.\n", top);
2215 ok(width == expect_width, "Got width %ld.\n", width);
2216 ok(height == expect_height, "Got height %ld.\n", height);
2217 GetWindowRect(hwnd, &rect);
2218 ok(rect.left == 10, "Got window left %ld.\n", rect.left);
2219 ok(rect.top == 0, "Got window top %ld.\n", rect.top);
2220 ok(rect.right == 10 + expect_width, "Got window right %ld.\n", rect.right);
2221 ok(rect.bottom == expect_height, "Got window bottom %ld.\n", rect.bottom);
2223 hr = IVideoWindow_put_Height(window, 200);
2224 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2226 hr = IVideoWindow_get_Left(window, &left);
2227 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2228 ok(left == 10, "Got left %ld.\n", left);
2229 hr = IVideoWindow_get_Top(window, &top);
2230 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2231 ok(top == 0, "Got top %ld.\n", top);
2232 hr = IVideoWindow_get_Width(window, &width);
2233 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2234 ok(width == expect_width, "Got width %ld.\n", width);
2235 hr = IVideoWindow_get_Height(window, &height);
2236 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2237 ok(height == 200, "Got height %ld.\n", height);
2238 hr = IVideoWindow_GetWindowPosition(window, &left, &top, &width, &height);
2239 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2240 ok(left == 10, "Got left %ld.\n", left);
2241 ok(top == 0, "Got top %ld.\n", top);
2242 ok(width == expect_width, "Got width %ld.\n", width);
2243 ok(height == 200, "Got height %ld.\n", height);
2244 GetWindowRect(hwnd, &rect);
2245 ok(rect.left == 10, "Got window left %ld.\n", rect.left);
2246 ok(rect.top == 0, "Got window top %ld.\n", rect.top);
2247 ok(rect.right == 10 + expect_width, "Got window right %ld.\n", rect.right);
2248 ok(rect.bottom == 200, "Got window bottom %ld.\n", rect.bottom);
2250 hr = IVideoWindow_SetWindowPosition(window, 100, 200, 300, 400);
2251 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2253 hr = IVideoWindow_get_Left(window, &left);
2254 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2255 ok(left == 100, "Got left %ld.\n", left);
2256 hr = IVideoWindow_get_Top(window, &top);
2257 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2258 ok(top == 200, "Got top %ld.\n", top);
2259 hr = IVideoWindow_get_Width(window, &width);
2260 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2261 ok(width == 300, "Got width %ld.\n", width);
2262 hr = IVideoWindow_get_Height(window, &height);
2263 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2264 ok(height == 400, "Got height %ld.\n", height);
2265 hr = IVideoWindow_GetWindowPosition(window, &left, &top, &width, &height);
2266 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2267 ok(left == 100, "Got left %ld.\n", left);
2268 ok(top == 200, "Got top %ld.\n", top);
2269 ok(width == 300, "Got width %ld.\n", width);
2270 ok(height == 400, "Got height %ld.\n", height);
2271 GetWindowRect(hwnd, &rect);
2272 ok(rect.left == 100, "Got window left %ld.\n", rect.left);
2273 ok(rect.top == 200, "Got window top %ld.\n", rect.top);
2274 ok(rect.right == 400, "Got window right %ld.\n", rect.right);
2275 ok(rect.bottom == 600, "Got window bottom %ld.\n", rect.bottom);
2277 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2278 top_hwnd = get_top_window();
2279 ok(top_hwnd == our_hwnd, "Got top window %p.\n", top_hwnd);
2282 static void test_video_window_owner(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
2284 HWND parent, top_hwnd;
2285 LONG style, state;
2286 OAHWND oahwnd;
2287 HRESULT hr;
2289 SetWindowPos(our_hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2291 hr = IVideoWindow_get_Owner(window, &oahwnd);
2292 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2293 ok(!oahwnd, "Got owner %#Ix.\n", oahwnd);
2295 parent = GetAncestor(hwnd, GA_PARENT);
2296 ok(parent == GetDesktopWindow(), "Got parent %p.\n", parent);
2297 style = GetWindowLongA(hwnd, GWL_STYLE);
2298 ok(!(style & WS_CHILD), "Got style %#lx.\n", style);
2300 hr = IVideoWindow_put_Owner(window, (OAHWND)our_hwnd);
2301 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2303 hr = IVideoWindow_get_Owner(window, &oahwnd);
2304 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2305 ok(oahwnd == (OAHWND)our_hwnd, "Got owner %#Ix.\n", oahwnd);
2307 parent = GetAncestor(hwnd, GA_PARENT);
2308 ok(parent == our_hwnd, "Got parent %p.\n", parent);
2309 style = GetWindowLongA(hwnd, GWL_STYLE);
2310 ok((style & WS_CHILD), "Got style %#lx.\n", style);
2312 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2313 top_hwnd = get_top_window();
2314 ok(top_hwnd == our_hwnd, "Got top window %p.\n", top_hwnd);
2316 ShowWindow(our_hwnd, SW_HIDE);
2318 hr = IVideoWindow_put_Visible(window, OATRUE);
2319 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2321 hr = IVideoWindow_get_Visible(window, &state);
2322 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2323 ok(state == OAFALSE, "Got state %ld.\n", state);
2325 hr = IVideoWindow_put_Owner(window, 0);
2326 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2328 hr = IVideoWindow_get_Owner(window, &oahwnd);
2329 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2330 ok(!oahwnd, "Got owner %#Ix.\n", oahwnd);
2332 parent = GetAncestor(hwnd, GA_PARENT);
2333 ok(parent == GetDesktopWindow(), "Got parent %p.\n", parent);
2334 style = GetWindowLongA(hwnd, GWL_STYLE);
2335 ok(!(style & WS_CHILD), "Got style %#lx.\n", style);
2337 ok(GetActiveWindow() == hwnd, "Got active window %p.\n", GetActiveWindow());
2338 top_hwnd = get_top_window();
2339 ok(top_hwnd == hwnd, "Got top window %p.\n", top_hwnd);
2341 hr = IVideoWindow_get_Visible(window, &state);
2342 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2343 ok(state == OATRUE, "Got state %ld.\n", state);
2346 struct notify_message_params
2348 IVideoWindow *window;
2349 HWND hwnd;
2350 UINT message;
2353 static DWORD CALLBACK notify_message_proc(void *arg)
2355 const struct notify_message_params *params = arg;
2356 HRESULT hr = IVideoWindow_NotifyOwnerMessage(params->window, (OAHWND)params->hwnd, params->message, 0, 0);
2357 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2358 return 0;
2361 static void test_video_window_messages(IVideoWindow *window, HWND hwnd, HWND our_hwnd)
2363 struct notify_message_params params;
2364 unsigned int i;
2365 OAHWND oahwnd;
2366 HANDLE thread;
2367 HRESULT hr;
2368 BOOL ret;
2369 MSG msg;
2371 static UINT drain_tests[] =
2373 WM_MOUSEACTIVATE,
2374 WM_NCLBUTTONDOWN,
2375 WM_NCLBUTTONUP,
2376 WM_NCLBUTTONDBLCLK,
2377 WM_NCRBUTTONDOWN,
2378 WM_NCRBUTTONUP,
2379 WM_NCRBUTTONDBLCLK,
2380 WM_NCMBUTTONDOWN,
2381 WM_NCMBUTTONUP,
2382 WM_NCMBUTTONDBLCLK,
2383 WM_KEYDOWN,
2384 WM_KEYUP,
2385 WM_MOUSEMOVE,
2386 WM_LBUTTONDOWN,
2387 WM_LBUTTONUP,
2388 WM_LBUTTONDBLCLK,
2389 WM_RBUTTONDOWN,
2390 WM_RBUTTONUP,
2391 WM_RBUTTONDBLCLK,
2392 WM_MBUTTONDOWN,
2393 WM_MBUTTONUP,
2394 WM_MBUTTONDBLCLK,
2397 flush_events();
2399 hr = IVideoWindow_get_MessageDrain(window, &oahwnd);
2400 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2401 ok(!oahwnd, "Got window %#Ix.\n", oahwnd);
2403 hr = IVideoWindow_put_MessageDrain(window, (OAHWND)our_hwnd);
2404 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2406 hr = IVideoWindow_get_MessageDrain(window, &oahwnd);
2407 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2408 ok(oahwnd == (OAHWND)our_hwnd, "Got window %#Ix.\n", oahwnd);
2410 for (i = 0; i < ARRAY_SIZE(drain_tests); ++i)
2412 SendMessageA(hwnd, drain_tests[i], 0xdeadbeef, 0);
2413 ret = PeekMessageA(&msg, 0, drain_tests[i], drain_tests[i], PM_REMOVE);
2414 ok(ret, "Expected a message.\n");
2415 ok(msg.hwnd == our_hwnd, "Got hwnd %p.\n", msg.hwnd);
2416 ok(msg.message == drain_tests[i], "Got message %#x.\n", msg.message);
2417 ok(msg.wParam == 0xdeadbeef, "Got wparam %#Ix.\n", msg.wParam);
2418 ok(!msg.lParam, "Got lparam %#Ix.\n", msg.lParam);
2419 DispatchMessageA(&msg);
2421 ret = PeekMessageA(&msg, 0, drain_tests[i], drain_tests[i], PM_REMOVE);
2422 ok(!ret, "Got unexpected message %#x.\n", msg.message);
2425 hr = IVideoWindow_put_MessageDrain(window, 0);
2426 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2428 hr = IVideoWindow_put_Owner(window, (OAHWND)our_hwnd);
2429 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2431 flush_events();
2433 /* Demonstrate that messages should be sent, not posted, and that only some
2434 * messages should be forwarded. A previous implementation unconditionally
2435 * posted all messages. */
2437 hr = IVideoWindow_NotifyOwnerMessage(window, (OAHWND)our_hwnd, WM_SYSCOLORCHANGE, 0, 0);
2438 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2440 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
2442 ok(msg.message != WM_SYSCOLORCHANGE, "WM_SYSCOLORCHANGE should not be posted.\n");
2443 DispatchMessageA(&msg);
2446 hr = IVideoWindow_NotifyOwnerMessage(window, (OAHWND)our_hwnd, WM_FONTCHANGE, 0, 0);
2447 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2449 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
2451 ok(msg.message != WM_FONTCHANGE, "WM_FONTCHANGE should not be posted.\n");
2452 DispatchMessageA(&msg);
2455 params.window = window;
2456 params.hwnd = our_hwnd;
2457 params.message = WM_SYSCOLORCHANGE;
2458 thread = CreateThread(NULL, 0, notify_message_proc, &params, 0, NULL);
2459 ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Thread should block.\n");
2461 while ((ret = MsgWaitForMultipleObjects(1, &thread, FALSE, 1000, QS_ALLINPUT)) == 1)
2463 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
2465 ok(msg.message != WM_SYSCOLORCHANGE, "WM_SYSCOLORCHANGE should not be posted.\n");
2466 DispatchMessageA(&msg);
2469 ok(!ret, "Wait timed out.\n");
2470 CloseHandle(thread);
2472 params.message = WM_FONTCHANGE;
2473 thread = CreateThread(NULL, 0, notify_message_proc, &params, 0, NULL);
2474 ok(!WaitForSingleObject(thread, 1000), "Thread should not block.\n");
2475 CloseHandle(thread);
2477 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
2479 ok(msg.message != WM_FONTCHANGE, "WM_FONTCHANGE should not be posted.\n");
2480 DispatchMessageA(&msg);
2483 hr = IVideoWindow_put_Owner(window, 0);
2484 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2487 static void test_video_window_autoshow(IVideoWindow *window, IFilterGraph2 *graph, HWND hwnd)
2489 IMediaControl *control;
2490 HRESULT hr;
2491 LONG l;
2493 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
2495 hr = IVideoWindow_get_AutoShow(window, &l);
2496 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2497 ok(l == OATRUE, "Got %ld.\n", l);
2499 hr = IVideoWindow_put_Visible(window, OAFALSE);
2500 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2502 hr = IMediaControl_Pause(control);
2503 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
2505 hr = IVideoWindow_get_Visible(window, &l);
2506 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2507 ok(l == OATRUE, "Got %ld.\n", l);
2509 hr = IMediaControl_Stop(control);
2510 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2512 hr = IVideoWindow_get_Visible(window, &l);
2513 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2514 ok(l == OATRUE, "Got %ld.\n", l);
2516 hr = IVideoWindow_put_AutoShow(window, OAFALSE);
2517 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2519 hr = IVideoWindow_put_Visible(window, OAFALSE);
2520 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2522 hr = IMediaControl_Pause(control);
2523 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
2525 hr = IVideoWindow_get_Visible(window, &l);
2526 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2527 ok(l == OAFALSE, "Got %ld.\n", l);
2529 hr = IMediaControl_Stop(control);
2530 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2532 IMediaControl_Release(control);
2535 static void test_video_window(void)
2537 ALLOCATOR_PROPERTIES req_props = {1, 600 * 400 * 4, 1, 0}, ret_props;
2538 VIDEOINFOHEADER vih =
2540 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
2541 .bmiHeader.biBitCount = 32,
2542 .bmiHeader.biWidth = 600,
2543 .bmiHeader.biHeight = 400,
2544 .bmiHeader.biPlanes = 1,
2545 .bmiHeader.biCompression = BI_RGB,
2547 AM_MEDIA_TYPE req_mt =
2549 .majortype = MEDIATYPE_Video,
2550 .subtype = MEDIASUBTYPE_RGB32,
2551 .formattype = FORMAT_VideoInfo,
2552 .cbFormat = sizeof(vih),
2553 .pbFormat = (BYTE *)&vih,
2555 IFilterGraph2 *graph = create_graph();
2556 WNDCLASSA window_class = {0};
2557 struct testfilter source;
2558 IMemAllocator *allocator;
2559 MONITORINFO monitorinfo;
2560 IMediaControl *control;
2561 LONG width, height, l;
2562 IVideoWindow *window;
2563 IMemInputPin *input;
2564 IBaseFilter *filter;
2565 HWND hwnd, our_hwnd;
2566 IOverlay *overlay;
2567 BSTR caption;
2568 HRESULT hr;
2569 DWORD tid;
2570 ULONG ref;
2571 IPin *pin;
2572 RECT rect;
2574 window_class.lpszClassName = "wine_test_class";
2575 window_class.lpfnWndProc = window_proc;
2576 RegisterClassA(&window_class);
2577 our_hwnd = CreateWindowA("wine_test_class", "test window", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
2578 100, 200, 300, 400, NULL, NULL, NULL, NULL);
2579 flush_events();
2581 filter = create_vmr9(VMR9Mode_Windowed);
2582 flush_events();
2584 flaky_wine
2585 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2587 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
2588 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
2590 hr = IPin_QueryInterface(pin, &IID_IOverlay, (void **)&overlay);
2591 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2593 hr = IOverlay_GetWindowHandle(overlay, &hwnd);
2594 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2595 if (winetest_debug > 1) trace("ours %p, theirs %p\n", our_hwnd, hwnd);
2596 GetWindowRect(hwnd, &rect);
2598 tid = GetWindowThreadProcessId(hwnd, NULL);
2599 ok(tid == GetCurrentThreadId(), "Expected tid %#lx, got %#lx.\n", GetCurrentThreadId(), tid);
2601 hr = IBaseFilter_QueryInterface(filter, &IID_IVideoWindow, (void **)&window);
2602 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2604 hr = IVideoWindow_get_Caption(window, &caption);
2605 todo_wine ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
2607 caption = SysAllocString(L"foo");
2608 hr = IVideoWindow_put_Caption(window, caption);
2609 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
2610 SysFreeString(caption);
2612 hr = IVideoWindow_get_WindowStyle(window, &l);
2613 todo_wine ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
2615 hr = IVideoWindow_put_WindowStyle(window, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
2616 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
2618 hr = IVideoWindow_get_AutoShow(window, &l);
2619 todo_wine ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
2621 hr = IVideoWindow_put_AutoShow(window, OAFALSE);
2622 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
2624 hr = IVideoWindow_put_Owner(window, (OAHWND)our_hwnd);
2625 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
2627 hr = IVideoWindow_put_MessageDrain(window, (OAHWND)our_hwnd);
2628 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
2630 hr = IVideoWindow_put_Visible(window, OATRUE);
2631 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
2633 hr = IVideoWindow_SetWindowPosition(window, 100, 200, 300, 400);
2634 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
2636 testfilter_init(&source);
2637 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL);
2638 IFilterGraph2_AddFilter(graph, filter, NULL);
2639 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
2640 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
2641 if (hr == E_FAIL)
2643 skip("Got E_FAIL when connecting.\n");
2644 goto out;
2646 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2648 hr = IMemInputPin_GetAllocator(input, &allocator);
2649 todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr);
2650 if (hr == S_OK)
2652 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
2653 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2654 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
2655 hr = IMemAllocator_Commit(allocator);
2656 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2657 IMemAllocator_Release(allocator);
2660 flaky_wine
2661 ok(GetActiveWindow() == our_hwnd, "Got active window %p.\n", GetActiveWindow());
2663 test_video_window_caption(window, hwnd);
2664 test_video_window_style(window, hwnd, our_hwnd);
2665 test_video_window_state(window, hwnd, our_hwnd);
2666 test_video_window_position(window, hwnd, our_hwnd);
2667 test_video_window_autoshow(window, graph, hwnd);
2668 test_video_window_owner(window, hwnd, our_hwnd);
2669 test_video_window_messages(window, hwnd, our_hwnd);
2671 hr = IVideoWindow_put_FullScreenMode(window, OATRUE);
2672 ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
2673 hr = IVideoWindow_get_FullScreenMode(window, &l);
2674 ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
2676 hr = IVideoWindow_GetMinIdealImageSize(window, &width, &height);
2677 todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr);
2678 hr = IVideoWindow_GetMaxIdealImageSize(window, &width, &height);
2679 todo_wine ok(hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr);
2681 hr = IMediaControl_Pause(control);
2682 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
2684 monitorinfo.cbSize = sizeof(monitorinfo);
2685 GetMonitorInfoW(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &monitorinfo);
2687 hr = IVideoWindow_GetMinIdealImageSize(window, &width, &height);
2688 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2689 todo_wine ok(width == 1, "Got width %ld.\n", width);
2690 todo_wine ok(height == 1, "Got height %ld.\n", height);
2691 hr = IVideoWindow_GetMaxIdealImageSize(window, &width, &height);
2692 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2693 todo_wine ok(width == monitorinfo.rcMonitor.right + 1, "Expected width %ld, got %ld.\n",
2694 monitorinfo.rcMonitor.right + 1, width);
2695 todo_wine ok(height == monitorinfo.rcMonitor.bottom + 1, "Expected height %ld, got %ld.\n",
2696 monitorinfo.rcMonitor.bottom + 1, height);
2698 hr = IMediaControl_Stop(control);
2699 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2701 out:
2702 IMediaControl_Release(control);
2703 IFilterGraph2_Release(graph);
2704 IVideoWindow_Release(window);
2705 IOverlay_Release(overlay);
2706 IMemInputPin_Release(input);
2707 IPin_Release(pin);
2708 ref = IBaseFilter_Release(filter);
2709 ok(!ref, "Got outstanding refcount %ld.\n", ref);
2710 ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface);
2711 ok(!ref, "Got outstanding refcount %ld.\n", ref);
2712 DestroyWindow(our_hwnd);
2715 static IDirect3DDevice9 *create_device(HWND window)
2717 D3DPRESENT_PARAMETERS present_parameters =
2719 .Windowed = TRUE,
2720 .hDeviceWindow = window,
2721 .SwapEffect = D3DSWAPEFFECT_DISCARD,
2722 .BackBufferWidth = 640,
2723 .BackBufferHeight = 480,
2724 .BackBufferFormat = D3DFMT_A8R8G8B8,
2726 IDirect3DDevice9 *device;
2727 IDirect3D9 *d3d;
2728 HRESULT hr;
2730 d3d = Direct3DCreate9(D3D_SDK_VERSION);
2731 ok(!!d3d, "Failed to create a D3D object.\n");
2733 hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,
2734 D3DCREATE_HARDWARE_VERTEXPROCESSING, &present_parameters, &device);
2735 IDirect3D9_Release(d3d);
2736 if (FAILED(hr))
2738 skip("Failed to create a 3D device, hr %#lx.\n", hr);
2739 return NULL;
2741 return device;
2744 static void test_allocate_surface_helper(void)
2746 VMR9AllocationInfo info =
2748 .dwFlags = VMR9AllocFlag_OffscreenSurface,
2749 .dwWidth = 32,
2750 .dwHeight = 16,
2751 .Format = D3DFMT_X8R8G8B8,
2752 .Pool = D3DPOOL_DEFAULT,
2753 .MinBuffers = 2,
2754 .szAspectRatio = {32, 16},
2755 .szNativeSize = {32, 16},
2757 IBaseFilter *filter = create_vmr9(VMR9Mode_Renderless);
2758 IVMRSurfaceAllocatorNotify9 *notify;
2759 IDirect3DSurface9 *surfaces[2] = {};
2760 IDirect3DDevice9 *device, *device2;
2761 RECT rect = {0, 0, 640, 480};
2762 IDirect3DTexture9 *container;
2763 D3DSURFACE_DESC desc;
2764 DWORD count;
2765 HWND window;
2766 HRESULT hr;
2767 ULONG ref;
2769 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
2770 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0,
2771 rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, NULL, NULL);
2772 if (!(device = create_device(window)))
2774 IBaseFilter_Release(filter);
2775 DestroyWindow(window);
2776 return;
2779 IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)&notify);
2781 count = 2;
2782 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2783 todo_wine ok(hr == E_FAIL, "Got hr %#lx.\n", hr);
2785 hr = IVMRSurfaceAllocatorNotify9_SetD3DDevice(notify, device, MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY));
2786 if (hr == E_NOINTERFACE)
2788 win_skip("Direct3D does not support video rendering.\n");
2789 goto out;
2791 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2793 if (0) /* crashes on Windows */
2795 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, NULL, &count, surfaces);
2796 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
2798 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, NULL, surfaces);
2799 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
2802 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, NULL);
2803 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
2805 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2806 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2807 ok(count == 2, "Got count %lu.\n", count);
2808 ok(!!surfaces[0], "Surface 0 was not allocated.\n");
2809 ok(!!surfaces[1], "Surface 1 was not allocated.\n");
2811 hr = IDirect3DSurface9_GetDevice(surfaces[0], &device2);
2812 ok(hr == D3D_OK, "Got hr %#lx.\n", hr);
2813 ok(device2 == device, "Devices did not match.\n");
2814 IDirect3DDevice9_Release(device2);
2816 hr = IDirect3DSurface9_GetContainer(surfaces[0], &IID_IDirect3DTexture9, (void **)&container);
2817 ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr);
2819 hr = IDirect3DSurface9_GetDesc(surfaces[0], &desc);
2820 ok(hr == D3D_OK, "Got hr %#lx.\n", hr);
2821 ok(desc.Format == info.Format, "Got format %#x.\n", desc.Format);
2822 ok(desc.Type == D3DRTYPE_SURFACE, "Got type %u.\n", desc.Type);
2823 ok(!desc.Usage, "Got usage %#lx.\n", desc.Usage);
2824 ok(desc.Pool == D3DPOOL_DEFAULT, "Got pool %u.\n", desc.Pool);
2825 ok(desc.MultiSampleType == D3DMULTISAMPLE_NONE, "Got multisample type %u.\n", desc.MultiSampleType);
2826 ok(!desc.MultiSampleQuality, "Got multisample quality %lu.\n", desc.MultiSampleQuality);
2827 ok(desc.Width == 32, "Got width %u.\n", desc.Width);
2828 ok(desc.Height == 16, "Got height %u.\n", desc.Height);
2830 IDirect3DSurface9_Release(surfaces[0]);
2831 IDirect3DSurface9_Release(surfaces[1]);
2833 surfaces[0] = surfaces[1] = NULL;
2834 count = 1;
2835 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2836 todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr);
2837 todo_wine ok(!count, "Got count %lu.\n", count);
2838 ok(!surfaces[0], "Surface 0 was allocated.\n");
2839 ok(!surfaces[1], "Surface 1 was allocated.\n");
2841 count = 2;
2842 info.MinBuffers = 1;
2843 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2844 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2845 ok(count == 2, "Got count %lu.\n", count);
2846 ok(!!surfaces[0], "Surface 0 was not allocated.\n");
2847 ok(!!surfaces[1], "Surface 1 was not allocated.\n");
2848 IDirect3DSurface9_Release(surfaces[0]);
2849 IDirect3DSurface9_Release(surfaces[1]);
2851 count = 2;
2852 info.dwFlags = VMR9AllocFlag_TextureSurface;
2853 surfaces[0] = surfaces[1] = NULL;
2854 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2855 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2856 ok(count == 2, "Got count %lu.\n", count);
2857 ok(!!surfaces[0], "Surface 0 was not allocated.\n");
2858 ok(!!surfaces[1], "Surface 1 was not allocated.\n");
2860 hr = IDirect3DSurface9_GetDevice(surfaces[0], &device2);
2861 ok(hr == D3D_OK, "Got hr %#lx.\n", hr);
2862 ok(device2 == device, "Devices did not match.\n");
2863 IDirect3DDevice9_Release(device2);
2865 hr = IDirect3DSurface9_GetContainer(surfaces[0], &IID_IDirect3DTexture9, (void **)&container);
2866 ok(hr == D3D_OK, "Got hr %#lx.\n", hr);
2867 IDirect3DTexture9_Release(container);
2869 hr = IDirect3DSurface9_GetDesc(surfaces[1], &desc);
2870 ok(hr == D3D_OK, "Got hr %#lx.\n", hr);
2871 ok(desc.Format == info.Format, "Got format %#x.\n", desc.Format);
2872 ok(desc.Type == D3DRTYPE_SURFACE, "Got type %u.\n", desc.Type);
2873 ok(desc.Usage == D3DUSAGE_DYNAMIC, "Got usage %#lx.\n", desc.Usage);
2874 ok(desc.Pool == D3DPOOL_DEFAULT, "Got pool %u.\n", desc.Pool);
2875 ok(desc.MultiSampleType == D3DMULTISAMPLE_NONE, "Got multisample type %u.\n", desc.MultiSampleType);
2876 ok(!desc.MultiSampleQuality, "Got multisample quality %lu.\n", desc.MultiSampleQuality);
2877 ok(desc.Width == 32, "Got width %u.\n", desc.Width);
2878 ok(desc.Height == 16, "Got height %u.\n", desc.Height);
2880 IDirect3DSurface9_Release(surfaces[0]);
2881 IDirect3DSurface9_Release(surfaces[1]);
2883 info.Format = D3DFMT_R8G8B8;
2884 surfaces[0] = surfaces[1] = NULL;
2885 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2886 ok(hr == D3DERR_INVALIDCALL, "Got hr %#lx.\n", hr);
2887 ok(!count, "Got count %lu.\n", count);
2888 ok(!surfaces[0], "Surface 0 was allocated.\n");
2889 ok(!surfaces[1], "Surface 1 was allocated.\n");
2891 info.Format = 0;
2892 info.dwFlags = VMR9AllocFlag_3DRenderTarget;
2893 count = 1;
2894 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2895 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2896 ok(count == 1, "Got count %lu.\n", count);
2897 ok(!!surfaces[0], "Surface 0 was not allocated.\n");
2898 ok(info.Format != 0, "Expected a format.\n");
2900 hr = IDirect3DSurface9_GetDesc(surfaces[0], &desc);
2901 ok(hr == D3D_OK, "Got hr %#lx.\n", hr);
2902 ok(desc.Format == info.Format, "Expected format %#x, got %#x.\n", info.Format, desc.Format);
2903 ok(desc.Type == D3DRTYPE_SURFACE, "Got type %u.\n", desc.Type);
2904 ok(desc.Usage == D3DUSAGE_RENDERTARGET, "Got usage %#lx.\n", desc.Usage);
2905 ok(desc.Pool == D3DPOOL_DEFAULT, "Got pool %u.\n", desc.Pool);
2906 ok(desc.MultiSampleType == D3DMULTISAMPLE_NONE, "Got multisample type %u.\n", desc.MultiSampleType);
2907 ok(!desc.MultiSampleQuality, "Got multisample quality %lu.\n", desc.MultiSampleQuality);
2908 ok(desc.Width == 32, "Got width %u.\n", desc.Width);
2909 ok(desc.Height == 16, "Got height %u.\n", desc.Height);
2911 IDirect3DSurface9_Release(surfaces[0]);
2913 info.Format = D3DFMT_A8R8G8B8;
2914 info.dwFlags = VMR9AllocFlag_OffscreenSurface | VMR9AllocFlag_TextureSurface;
2915 count = 1;
2916 hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(notify, &info, &count, surfaces);
2917 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
2918 ok(count == 1, "Got count %lu.\n", count);
2920 out:
2921 IVMRSurfaceAllocatorNotify9_Release(notify);
2922 ref = IBaseFilter_Release(filter);
2923 ok(!ref, "Got outstanding refcount %ld.\n", ref);
2924 ref = IDirect3DDevice9_Release(device);
2925 ok(!ref, "Got outstanding refcount %ld.\n", ref);
2926 DestroyWindow(window);
2929 struct presenter
2931 IVMRSurfaceAllocator9 IVMRSurfaceAllocator9_iface;
2932 IVMRImagePresenter9 IVMRImagePresenter9_iface;
2933 LONG refcount;
2935 D3DFORMAT format;
2936 DWORD accept_flags;
2937 IDirect3DSurface9 *surfaces[5];
2938 IVMRSurfaceAllocatorNotify9 *notify;
2939 unsigned int got_PresentImage, got_TerminateDevice;
2942 static struct presenter *impl_from_IVMRImagePresenter9(IVMRImagePresenter9 *iface)
2944 return CONTAINING_RECORD(iface, struct presenter, IVMRImagePresenter9_iface);
2947 static HRESULT WINAPI presenter_QueryInterface(IVMRImagePresenter9 *iface, REFIID iid, void **out)
2949 struct presenter *presenter = impl_from_IVMRImagePresenter9(iface);
2950 return IVMRSurfaceAllocator9_QueryInterface(&presenter->IVMRSurfaceAllocator9_iface, iid, out);
2953 static ULONG WINAPI presenter_AddRef(IVMRImagePresenter9 *iface)
2955 struct presenter *presenter = impl_from_IVMRImagePresenter9(iface);
2956 return IVMRSurfaceAllocator9_AddRef(&presenter->IVMRSurfaceAllocator9_iface);
2959 static ULONG WINAPI presenter_Release(IVMRImagePresenter9 *iface)
2961 struct presenter *presenter = impl_from_IVMRImagePresenter9(iface);
2962 return IVMRSurfaceAllocator9_Release(&presenter->IVMRSurfaceAllocator9_iface);
2965 static HRESULT WINAPI presenter_StartPresenting(IVMRImagePresenter9 *iface, DWORD_PTR cookie)
2967 if (winetest_debug > 1) trace("StartPresenting()\n");
2968 ok(cookie == 0xabacab, "Got cookie %#Ix.\n", cookie);
2969 return E_NOTIMPL;
2972 static HRESULT WINAPI presenter_StopPresenting(IVMRImagePresenter9 *iface, DWORD_PTR cookie)
2974 if (winetest_debug > 1) trace("StopPresenting()\n");
2975 ok(cookie == 0xabacab, "Got cookie %#Ix.\n", cookie);
2976 return E_NOTIMPL;
2979 static HRESULT WINAPI presenter_PresentImage(IVMRImagePresenter9 *iface, DWORD_PTR cookie, VMR9PresentationInfo *info)
2981 struct presenter *presenter = impl_from_IVMRImagePresenter9(iface);
2982 static const RECT rect;
2984 if (winetest_debug > 1) trace("PresentImage()\n");
2985 ok(cookie == 0xabacab, "Got cookie %#Ix.\n", cookie);
2986 todo_wine ok(info->dwFlags == VMR9Sample_TimeValid, "Got flags %#lx.\n", info->dwFlags);
2987 ok(!info->rtStart, "Got start time %s.\n", wine_dbgstr_longlong(info->rtStart));
2988 ok(info->rtEnd == 10000000, "Got end time %s.\n", wine_dbgstr_longlong(info->rtEnd));
2989 todo_wine ok(info->szAspectRatio.cx == 120, "Got aspect ratio width %ld.\n", info->szAspectRatio.cx);
2990 todo_wine ok(info->szAspectRatio.cy == 60, "Got aspect ratio height %ld.\n", info->szAspectRatio.cy);
2991 ok(EqualRect(&info->rcSrc, &rect), "Got source rect %s.\n", wine_dbgstr_rect(&info->rcSrc));
2992 ok(EqualRect(&info->rcDst, &rect), "Got dest rect %s.\n", wine_dbgstr_rect(&info->rcDst));
2993 ok(!info->dwReserved1, "Got dwReserved1 %#lx.\n", info->dwReserved1);
2994 ok(!info->dwReserved2, "Got dwReserved2 %#lx.\n", info->dwReserved2);
2996 ++presenter->got_PresentImage;
2997 return S_OK;
3000 static const IVMRImagePresenter9Vtbl presenter_vtbl =
3002 presenter_QueryInterface,
3003 presenter_AddRef,
3004 presenter_Release,
3005 presenter_StartPresenting,
3006 presenter_StopPresenting,
3007 presenter_PresentImage,
3010 static struct presenter *impl_from_IVMRSurfaceAllocator9(IVMRSurfaceAllocator9 *iface)
3012 return CONTAINING_RECORD(iface, struct presenter, IVMRSurfaceAllocator9_iface);
3015 static HRESULT WINAPI allocator_QueryInterface(IVMRSurfaceAllocator9 *iface, REFIID iid, void **out)
3017 struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
3019 if (winetest_debug > 1) trace("QueryInterface(%s)\n", wine_dbgstr_guid(iid));
3021 if (IsEqualGUID(iid, &IID_IVMRImagePresenter9))
3023 *out = &presenter->IVMRImagePresenter9_iface;
3024 IVMRImagePresenter9_AddRef(&presenter->IVMRImagePresenter9_iface);
3025 return S_OK;
3027 ok(!IsEqualGUID(iid, &IID_IVMRSurfaceAllocatorEx9), "Unexpected query for IVMRSurfaceAllocatorEx9.\n");
3028 *out = NULL;
3029 return E_NOTIMPL;
3032 static ULONG WINAPI allocator_AddRef(IVMRSurfaceAllocator9 *iface)
3034 struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
3035 return InterlockedIncrement(&presenter->refcount);
3038 static ULONG WINAPI allocator_Release(IVMRSurfaceAllocator9 *iface)
3040 struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
3041 return InterlockedDecrement(&presenter->refcount);
3044 static HRESULT WINAPI allocator_InitializeDevice(IVMRSurfaceAllocator9 *iface,
3045 DWORD_PTR cookie, VMR9AllocationInfo *info, DWORD *buffer_count)
3047 struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
3049 if (winetest_debug > 1) trace("InitializeDevice(flags %#lx, format %u)\n",
3050 info->dwFlags, info->Format);
3051 ok(cookie == 0xabacab, "Got cookie %#Ix.\n", cookie);
3052 ok(info->dwWidth == 32, "Got width %lu.\n", info->dwWidth);
3053 ok(info->dwHeight == 16, "Got height %lu.\n", info->dwHeight);
3054 todo_wine ok(info->MinBuffers == 5, "Got buffer count %lu.\n", info->MinBuffers);
3055 ok(info->Pool == D3DPOOL_DEFAULT, "Got pool %u\n", info->Pool);
3056 todo_wine ok(info->szAspectRatio.cx == 120, "Got aspect ratio width %ld.\n", info->szAspectRatio.cx);
3057 todo_wine ok(info->szAspectRatio.cy == 60, "Got aspect ratio height %ld.\n", info->szAspectRatio.cy);
3058 ok(info->szNativeSize.cx == 32, "Got native width %ld.\n", info->szNativeSize.cx);
3059 ok(info->szNativeSize.cy == 16, "Got native height %ld.\n", info->szNativeSize.cy);
3060 todo_wine ok(*buffer_count == 5, "Got buffer count %lu.\n", *buffer_count);
3062 presenter->format = info->Format;
3064 if (info->dwFlags != presenter->accept_flags)
3065 return 0xdeadbeef;
3066 return IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(presenter->notify,
3067 info, buffer_count, presenter->surfaces);
3070 static HRESULT WINAPI allocator_TerminateDevice(IVMRSurfaceAllocator9 *iface, DWORD_PTR cookie)
3072 struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
3074 if (winetest_debug > 1) trace("TerminateDevice()\n");
3075 ok(cookie == 0xabacab, "Got cookie %#Ix.\n", cookie);
3076 /* Don't dereference the surfaces here, to mimic How to Survive. */
3077 ++presenter->got_TerminateDevice;
3078 return E_NOTIMPL;
3081 static HRESULT WINAPI allocator_GetSurface(IVMRSurfaceAllocator9 *iface,
3082 DWORD_PTR cookie, DWORD index, DWORD flags, IDirect3DSurface9 **surface)
3084 struct presenter *presenter = impl_from_IVMRSurfaceAllocator9(iface);
3086 if (winetest_debug > 1) trace("GetSurface(index %lu)\n", index);
3087 ok(cookie == 0xabacab, "Got cookie %#Ix.\n", cookie);
3088 ok(!flags, "Got flags %#lx.\n", flags);
3089 ok(index < 5, "Got index %lu.\n", index);
3091 /* Don't reference the surface here, to mimic How to Survive. */
3092 *surface = presenter->surfaces[index];
3093 return S_OK;
3096 static HRESULT WINAPI allocator_AdviseNotify(IVMRSurfaceAllocator9 *iface, IVMRSurfaceAllocatorNotify9 *notify)
3098 ok(0, "Unexpected call.\n");
3099 return E_NOTIMPL;
3102 static const IVMRSurfaceAllocator9Vtbl allocator_vtbl =
3104 allocator_QueryInterface,
3105 allocator_AddRef,
3106 allocator_Release,
3107 allocator_InitializeDevice,
3108 allocator_TerminateDevice,
3109 allocator_GetSurface,
3110 allocator_AdviseNotify,
3113 static void test_renderless_present(struct presenter *presenter,
3114 IFilterGraph2 *graph, IMemInputPin *input)
3116 IMediaControl *control;
3117 OAFilterState state;
3118 HANDLE thread;
3119 HRESULT hr;
3121 IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
3123 presenter->got_PresentImage = 0;
3125 hr = IMediaControl_Pause(control);
3126 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3127 thread = send_frame(input);
3128 hr = IMediaControl_GetState(control, 1000, &state);
3129 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3130 /* Atelier Sophie uses the VMR in renderless mode, calls
3131 * IMediaControl::Run() from a stopped state and expects that
3132 * IMediaControl::GetState() returns S_OK only after PresentImage() has
3133 * been called. */
3134 ok(presenter->got_PresentImage == 1, "Got %u calls to PresentImage().\n", presenter->got_PresentImage);
3136 hr = IMediaControl_Run(control);
3137 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3138 hr = join_thread(thread);
3139 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3140 ok(presenter->got_PresentImage == 1, "Got %u calls to PresentImage().\n", presenter->got_PresentImage);
3142 hr = IMediaControl_Stop(control);
3143 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3145 IMediaControl_Release(control);
3148 static void test_renderless_formats(void)
3150 VIDEOINFOHEADER vih =
3152 .rcSource = {4, 6, 16, 12},
3153 .rcTarget = {40, 60, 160, 120},
3154 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
3155 .bmiHeader.biWidth = 32,
3156 .bmiHeader.biHeight = 16,
3158 AM_MEDIA_TYPE req_mt =
3160 .majortype = MEDIATYPE_Video,
3161 .formattype = FORMAT_VideoInfo,
3162 .cbFormat = sizeof(vih),
3163 .pbFormat = (BYTE *)&vih,
3165 ALLOCATOR_PROPERTIES req_props = {5, 32 * 16 * 4, 1, 0}, ret_props;
3166 struct presenter presenter =
3168 .IVMRSurfaceAllocator9_iface.lpVtbl = &allocator_vtbl,
3169 .IVMRImagePresenter9_iface.lpVtbl = &presenter_vtbl,
3170 .refcount = 1,
3172 struct presenter presenter2 = presenter;
3173 IVMRSurfaceAllocatorNotify9 *notify;
3174 RECT rect = {0, 0, 640, 480};
3175 struct testfilter source;
3176 IDirect3DDevice9 *device;
3177 IMemAllocator *allocator;
3178 IFilterGraph2 *graph;
3179 IMemInputPin *input;
3180 IBaseFilter *filter;
3181 unsigned int i;
3182 HWND window;
3183 HRESULT hr;
3184 ULONG ref;
3185 IPin *pin;
3187 static const struct
3189 const GUID *subtype;
3190 D3DFORMAT format;
3191 DWORD flags;
3193 tests[] =
3195 {&MEDIASUBTYPE_ARGB1555, D3DFMT_A1R5G5B5, VMR9AllocFlag_TextureSurface},
3196 {&MEDIASUBTYPE_ARGB32, D3DFMT_A8R8G8B8, VMR9AllocFlag_TextureSurface},
3197 {&MEDIASUBTYPE_ARGB4444, D3DFMT_A4R4G4B4, VMR9AllocFlag_TextureSurface},
3199 {&MEDIASUBTYPE_RGB555, D3DFMT_X1R5G5B5, VMR9AllocFlag_OffscreenSurface},
3200 {&MEDIASUBTYPE_RGB555, D3DFMT_X1R5G5B5, VMR9AllocFlag_TextureSurface},
3201 {&MEDIASUBTYPE_RGB565, D3DFMT_R5G6B5, VMR9AllocFlag_OffscreenSurface},
3202 {&MEDIASUBTYPE_RGB565, D3DFMT_R5G6B5, VMR9AllocFlag_TextureSurface},
3203 {&MEDIASUBTYPE_RGB24, D3DFMT_R8G8B8, VMR9AllocFlag_OffscreenSurface},
3204 {&MEDIASUBTYPE_RGB24, D3DFMT_R8G8B8, VMR9AllocFlag_TextureSurface},
3205 {&MEDIASUBTYPE_RGB32, D3DFMT_X8R8G8B8, VMR9AllocFlag_OffscreenSurface},
3206 {&MEDIASUBTYPE_RGB32, D3DFMT_X8R8G8B8, VMR9AllocFlag_TextureSurface},
3208 {&MEDIASUBTYPE_NV12, MAKEFOURCC('N','V','1','2'), VMR9AllocFlag_OffscreenSurface},
3209 {&MEDIASUBTYPE_UYVY, D3DFMT_UYVY, VMR9AllocFlag_OffscreenSurface},
3210 {&MEDIASUBTYPE_YUY2, D3DFMT_YUY2, VMR9AllocFlag_OffscreenSurface},
3211 {&MEDIASUBTYPE_YV12, MAKEFOURCC('Y','V','1','2'), VMR9AllocFlag_OffscreenSurface},
3214 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
3215 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0,
3216 rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, NULL, NULL);
3217 if (!(device = create_device(window)))
3219 DestroyWindow(window);
3220 return;
3223 filter = create_vmr9(VMR9Mode_Renderless);
3224 IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)&notify);
3226 hr = IVMRSurfaceAllocatorNotify9_SetD3DDevice(notify, device, MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY));
3227 if (hr == E_NOINTERFACE)
3229 win_skip("Direct3D does not support video rendering.\n");
3230 goto out;
3232 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3234 hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab,
3235 &presenter.IVMRSurfaceAllocator9_iface);
3236 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3238 presenter.notify = notify;
3240 testfilter_init(&source);
3241 graph = create_graph();
3242 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL);
3243 IFilterGraph2_AddFilter(graph, filter, NULL);
3244 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
3245 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
3247 for (i = 0; i < ARRAY_SIZE(tests); ++i)
3249 req_mt.subtype = *tests[i].subtype;
3250 presenter.accept_flags = tests[i].flags;
3252 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
3253 /* Connection never fails on Native, but Wine currently creates D3D
3254 * surfaces during IPin::ReceiveConnection() instead of
3255 * IMemAllocator::SetProperties(), so let that fail here for now. */
3256 if (hr != S_OK)
3258 skip("Format %u (%#x), flags %#lx are not supported, hr %#lx.\n",
3259 tests[i].format, tests[i].format, tests[i].flags, hr);
3260 continue;
3262 ok(hr == S_OK, "Test %u: Got hr %#lx.\n", i, hr);
3264 hr = IMemInputPin_GetAllocator(input, &allocator);
3265 todo_wine ok(hr == S_OK, "Test %u: Got hr %#lx.\n", i, hr);
3266 if (hr != S_OK)
3268 test_allocator(input);
3269 hr = IMemInputPin_GetAllocator(input, &allocator);
3272 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
3273 if (hr != S_OK)
3275 skip("Format %u (%#x), flags %#lx are not supported, hr %#lx.\n",
3276 tests[i].format, tests[i].format, tests[i].flags, hr);
3277 IMemAllocator_Release(allocator);
3278 hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
3279 ok(hr == S_OK, "Test %u: Got hr %#lx.\n", i, hr);
3280 hr = IFilterGraph2_Disconnect(graph, pin);
3281 ok(hr == S_OK, "Test %u: Got hr %#lx.\n", i, hr);
3282 continue;
3284 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
3285 hr = IMemAllocator_Commit(allocator);
3286 ok(hr == S_OK, "Test %u: Got hr %#lx.\n", i, hr);
3288 hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab,
3289 &presenter2.IVMRSurfaceAllocator9_iface);
3290 ok(hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr);
3292 ok(presenter.format == tests[i].format, "Test %u: Got format %u (%#x).\n",
3293 i, presenter.format, presenter.format);
3295 test_renderless_present(&presenter, graph, input);
3297 hr = IMemAllocator_Decommit(allocator);
3298 ok(hr == S_OK, "Test %u: Got hr %#lx.\n", i, hr);
3299 IMemAllocator_Release(allocator);
3301 hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
3302 ok(hr == S_OK, "Test %u: Got hr %#lx.\n", i, hr);
3303 hr = IFilterGraph2_Disconnect(graph, pin);
3304 ok(hr == S_OK, "Test %u: Got hr %#lx.\n", i, hr);
3307 hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab, &presenter2.IVMRSurfaceAllocator9_iface);
3308 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3310 ref = IFilterGraph2_Release(graph);
3311 ok(!ref, "Got outstanding refcount %ld.\n", ref);
3312 IMemInputPin_Release(input);
3313 IPin_Release(pin);
3315 out:
3316 IVMRSurfaceAllocatorNotify9_Release(notify);
3317 ref = IBaseFilter_Release(filter);
3318 ok(!ref, "Got outstanding refcount %ld.\n", ref);
3319 ok(presenter.refcount == 1, "Got outstanding refcount %ld.\n", presenter.refcount);
3320 ok(presenter2.refcount == 1, "Got outstanding refcount %ld.\n", presenter2.refcount);
3321 ref = IDirect3DDevice9_Release(device);
3322 ok(!ref, "Got outstanding refcount %ld.\n", ref);
3323 DestroyWindow(window);
3326 static void test_mixing_mode(void)
3328 IVMRWindowlessControl9 *windowless_control;
3329 IVMRMixerControl9 *mixer_control;
3330 IVMRFilterConfig9 *config;
3331 DWORD stream_count = 0;
3332 IBaseFilter *filter;
3333 unsigned int i;
3334 HWND window;
3335 HRESULT hr;
3336 ULONG ref;
3338 static const VMR9Mode modes[] =
3341 VMR9Mode_Windowed,
3342 VMR9Mode_Windowless,
3343 VMR9Mode_Renderless,
3346 for (i = 0; i < ARRAY_SIZE(modes); ++i)
3348 filter = create_vmr9(modes[i]);
3349 IBaseFilter_QueryInterface(filter, &IID_IVMRFilterConfig9, (void **)&config);
3351 hr = IBaseFilter_QueryInterface(filter, &IID_IVMRMixerControl9, (void **)&mixer_control);
3352 ok(hr == E_NOINTERFACE, "Got hr %#lx.\n", hr);
3354 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3355 ok(hr == VFW_E_VMR_NOT_IN_MIXER_MODE, "Got hr %#lx.\n", hr);
3357 hr = IVMRFilterConfig9_SetNumberOfStreams(config, 1);
3358 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3360 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3361 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3362 ok(stream_count == 1, "Got %lu streams.\n", stream_count);
3364 hr = IBaseFilter_QueryInterface(filter, &IID_IVMRMixerControl9, (void **)&mixer_control);
3365 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3366 IVMRMixerControl9_Release(mixer_control);
3368 hr = IVMRFilterConfig9_SetNumberOfStreams(config, 2);
3369 ok(hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr);
3371 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3372 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3373 ok(stream_count == 1, "Got %lu streams.\n", stream_count);
3375 IVMRFilterConfig9_Release(config);
3376 ref = IBaseFilter_Release(filter);
3377 ok(!ref, "Got outstanding refcount %ld.\n", ref);
3380 filter = create_vmr9(VMR9Mode_Windowless);
3381 IBaseFilter_QueryInterface(filter, &IID_IVMRFilterConfig9, (void **)&config);
3382 IBaseFilter_QueryInterface(filter, &IID_IVMRWindowlessControl9, (void **)&windowless_control);
3384 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
3385 ok(!!window, "Failed to create a window.\n");
3386 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, window);
3387 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3389 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3390 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3391 ok(stream_count == 4, "Got %lu streams.\n", stream_count);
3393 hr = IBaseFilter_QueryInterface(filter, &IID_IVMRMixerControl9, (void **)&mixer_control);
3394 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3395 IVMRMixerControl9_Release(mixer_control);
3397 hr = IVMRFilterConfig9_SetNumberOfStreams(config, 2);
3398 ok(hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr);
3400 hr = IVMRFilterConfig9_GetNumberOfStreams(config, &stream_count);
3401 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3402 ok(stream_count == 4, "Got %lu streams.\n", stream_count);
3404 IVMRWindowlessControl9_Release(windowless_control);
3405 IVMRFilterConfig9_Release(config);
3406 ref = IBaseFilter_Release(filter);
3407 ok(!ref, "Got outstanding refcount %ld.\n", ref);
3408 DestroyWindow(window);
3411 static void test_clipping_window(void)
3413 VIDEOINFOHEADER vih =
3415 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
3416 .bmiHeader.biWidth = 32,
3417 .bmiHeader.biHeight = 16,
3418 .bmiHeader.biBitCount = 32,
3420 AM_MEDIA_TYPE mt =
3422 .majortype = MEDIATYPE_Video,
3423 .subtype = MEDIASUBTYPE_RGB32,
3424 .formattype = FORMAT_VideoInfo,
3425 .cbFormat = sizeof(vih),
3426 .pbFormat = (BYTE *)&vih,
3428 IBaseFilter *filter = create_vmr9(VMR9Mode_Windowless);
3429 IVMRWindowlessControl9 *windowless_control;
3430 IFilterGraph2 *graph = create_graph();
3431 struct testfilter source;
3432 HWND window;
3433 HRESULT hr;
3434 ULONG ref;
3435 IPin *pin;
3437 IBaseFilter_QueryInterface(filter, &IID_IVMRWindowlessControl9, (void **)&windowless_control);
3438 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
3439 testfilter_init(&source);
3440 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, L"source");
3441 IFilterGraph2_AddFilter(graph, filter, L"vmr9");
3442 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
3443 ok(!!window, "Failed to create a window.\n");
3445 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, NULL);
3446 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3447 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, (HWND)0xdeadbeef);
3448 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3450 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &mt);
3451 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3453 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, window);
3454 ok(hr == VFW_E_WRONG_STATE, "Got hr %#lx.\n", hr);
3456 hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
3457 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3458 hr = IFilterGraph2_Disconnect(graph, pin);
3459 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3461 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, window);
3462 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3464 ref = IFilterGraph2_Release(graph);
3465 ok(!ref, "Got outstanding refcount %ld.\n", ref);
3466 IPin_Release(pin);
3467 IVMRWindowlessControl9_Release(windowless_control);
3468 ref = IBaseFilter_Release(filter);
3469 ok(!ref, "Got outstanding refcount %ld.\n", ref);
3470 DestroyWindow(window);
3473 static void test_surface_allocator_notify_refcount(void)
3475 struct presenter presenter =
3477 .IVMRSurfaceAllocator9_iface.lpVtbl = &allocator_vtbl,
3478 .IVMRImagePresenter9_iface.lpVtbl = &presenter_vtbl,
3479 .refcount = 1,
3481 IBaseFilter *filter = create_vmr9(VMR9Mode_Renderless);
3482 IVMRSurfaceAllocatorNotify9 *notify;
3483 HRESULT hr;
3484 ULONG ref;
3486 set_mixing_mode(filter, 2);
3488 IBaseFilter_QueryInterface(filter, &IID_IVMRSurfaceAllocatorNotify9, (void **)&notify);
3490 hr = IVMRSurfaceAllocatorNotify9_AdviseSurfaceAllocator(notify, 0xabacab,
3491 &presenter.IVMRSurfaceAllocator9_iface);
3492 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3494 ref = IBaseFilter_Release(filter);
3495 ok(!ref, "Got outstanding refcount %ld.\n", ref);
3496 ok(presenter.got_TerminateDevice == 1, "Got %u calls to TerminateDevice().\n",
3497 presenter.got_TerminateDevice);
3498 ok(presenter.refcount == 1, "Got outstanding refcount %ld.\n", presenter.refcount);
3500 ref = IVMRSurfaceAllocatorNotify9_Release(notify);
3501 ok(!ref, "Got outstanding refcount %ld.\n", ref);
3504 static void check_source_position_(int line, IBasicVideo *video,
3505 LONG expect_left, LONG expect_top, LONG expect_width, LONG expect_height)
3507 LONG left, top, width, height, l;
3508 HRESULT hr;
3510 left = top = width = height = 0xdeadbeef;
3511 hr = IBasicVideo_GetSourcePosition(video, &left, &top, &width, &height);
3512 ok_(__FILE__,line)(hr == S_OK, "Got hr %#lx.\n", hr);
3513 ok_(__FILE__,line)(left == expect_left, "Got left %ld.\n", left);
3514 ok_(__FILE__,line)(top == expect_top, "Got top %ld.\n", top);
3515 ok_(__FILE__,line)(width == expect_width, "Got width %ld.\n", width);
3516 ok_(__FILE__,line)(height == expect_height, "Got height %ld.\n", height);
3518 l = 0xdeadbeef;
3519 hr = IBasicVideo_get_SourceLeft(video, &l);
3520 ok_(__FILE__,line)(hr == S_OK, "Failed to get left, hr %#lx.\n", hr);
3521 ok_(__FILE__,line)(l == left, "Got left %ld.\n", l);
3523 l = 0xdeadbeef;
3524 hr = IBasicVideo_get_SourceTop(video, &l);
3525 ok_(__FILE__,line)(hr == S_OK, "Failed to get top, hr %#lx.\n", hr);
3526 ok_(__FILE__,line)(l == top, "Got top %ld.\n", l);
3528 l = 0xdeadbeef;
3529 hr = IBasicVideo_get_SourceWidth(video, &l);
3530 ok_(__FILE__,line)(hr == S_OK, "Failed to get width, hr %#lx.\n", hr);
3531 ok_(__FILE__,line)(l == width, "Got width %ld.\n", l);
3533 l = 0xdeadbeef;
3534 hr = IBasicVideo_get_SourceHeight(video, &l);
3535 ok_(__FILE__,line)(hr == S_OK, "Failed to get height, hr %#lx.\n", hr);
3536 ok_(__FILE__,line)(l == height, "Got height %ld.\n", l);
3538 #define check_source_position(a,b,c,d,e) check_source_position_(__LINE__,a,b,c,d,e)
3540 static void test_basic_video_source(IBasicVideo *video)
3542 HRESULT hr;
3544 check_source_position(video, 0, 0, 600, 400);
3545 hr = IBasicVideo_IsUsingDefaultSource(video);
3546 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3548 hr = IBasicVideo_put_SourceLeft(video, -10);
3549 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3550 hr = IBasicVideo_put_SourceLeft(video, 10);
3551 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3553 hr = IBasicVideo_put_SourceTop(video, -10);
3554 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3555 hr = IBasicVideo_put_SourceTop(video, 10);
3556 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3558 hr = IBasicVideo_put_SourceWidth(video, -500);
3559 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3560 hr = IBasicVideo_put_SourceWidth(video, 0);
3561 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3562 hr = IBasicVideo_put_SourceWidth(video, 700);
3563 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3564 hr = IBasicVideo_put_SourceWidth(video, 500);
3565 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3566 check_source_position(video, 0, 0, 500, 400);
3567 hr = IBasicVideo_IsUsingDefaultSource(video);
3568 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3570 hr = IBasicVideo_put_SourceHeight(video, -300);
3571 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3572 hr = IBasicVideo_put_SourceHeight(video, 0);
3573 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3574 hr = IBasicVideo_put_SourceHeight(video, 600);
3575 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3576 hr = IBasicVideo_put_SourceHeight(video, 300);
3577 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3578 check_source_position(video, 0, 0, 500, 300);
3579 hr = IBasicVideo_IsUsingDefaultSource(video);
3580 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3582 hr = IBasicVideo_put_SourceLeft(video, -10);
3583 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3584 hr = IBasicVideo_put_SourceLeft(video, 10);
3585 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3586 check_source_position(video, 10, 0, 500, 300);
3587 hr = IBasicVideo_IsUsingDefaultSource(video);
3588 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3590 hr = IBasicVideo_put_SourceTop(video, -10);
3591 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3592 hr = IBasicVideo_put_SourceTop(video, 20);
3593 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3594 check_source_position(video, 10, 20, 500, 300);
3595 hr = IBasicVideo_IsUsingDefaultSource(video);
3596 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3598 hr = IBasicVideo_SetSourcePosition(video, 4, 5, 60, 40);
3599 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3600 check_source_position(video, 4, 5, 60, 40);
3601 hr = IBasicVideo_IsUsingDefaultSource(video);
3602 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3604 hr = IBasicVideo_SetSourcePosition(video, 0, 0, 600, 400);
3605 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3606 check_source_position(video, 0, 0, 600, 400);
3607 hr = IBasicVideo_IsUsingDefaultSource(video);
3608 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3610 hr = IBasicVideo_SetSourcePosition(video, 4, 5, 60, 40);
3611 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3612 hr = IBasicVideo_SetDefaultSourcePosition(video);
3613 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3614 check_source_position(video, 0, 0, 600, 400);
3615 hr = IBasicVideo_IsUsingDefaultSource(video);
3616 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3619 static void check_destination_position_(int line, IBasicVideo *video,
3620 LONG expect_left, LONG expect_top, LONG expect_width, LONG expect_height)
3622 LONG left, top, width, height, l;
3623 HRESULT hr;
3625 left = top = width = height = 0xdeadbeef;
3626 hr = IBasicVideo_GetDestinationPosition(video, &left, &top, &width, &height);
3627 ok_(__FILE__,line)(hr == S_OK, "Failed to get position, hr %#lx.\n", hr);
3628 ok_(__FILE__,line)(left == expect_left, "Got left %ld.\n", left);
3629 ok_(__FILE__,line)(top == expect_top, "Got top %ld.\n", top);
3630 ok_(__FILE__,line)(width == expect_width, "Got width %ld.\n", width);
3631 ok_(__FILE__,line)(height == expect_height, "Got height %ld.\n", height);
3633 l = 0xdeadbeef;
3634 hr = IBasicVideo_get_DestinationLeft(video, &l);
3635 ok_(__FILE__,line)(hr == S_OK, "Failed to get left, hr %#lx.\n", hr);
3636 ok_(__FILE__,line)(l == left, "Got left %ld.\n", l);
3638 l = 0xdeadbeef;
3639 hr = IBasicVideo_get_DestinationTop(video, &l);
3640 ok_(__FILE__,line)(hr == S_OK, "Failed to get top, hr %#lx.\n", hr);
3641 ok_(__FILE__,line)(l == top, "Got top %ld.\n", l);
3643 l = 0xdeadbeef;
3644 hr = IBasicVideo_get_DestinationWidth(video, &l);
3645 ok_(__FILE__,line)(hr == S_OK, "Failed to get width, hr %#lx.\n", hr);
3646 ok_(__FILE__,line)(l == width, "Got width %ld.\n", l);
3648 l = 0xdeadbeef;
3649 hr = IBasicVideo_get_DestinationHeight(video, &l);
3650 ok_(__FILE__,line)(hr == S_OK, "Failed to get height, hr %#lx.\n", hr);
3651 ok_(__FILE__,line)(l == height, "Got height %ld.\n", l);
3653 #define check_destination_position(a,b,c,d,e) check_destination_position_(__LINE__,a,b,c,d,e)
3655 static void test_basic_video_destination(IBasicVideo *video)
3657 IVideoWindow *window;
3658 HRESULT hr;
3659 RECT rect;
3661 IBasicVideo_QueryInterface(video, &IID_IVideoWindow, (void **)&window);
3663 check_destination_position(video, 0, 0, 600, 400);
3664 hr = IBasicVideo_IsUsingDefaultDestination(video);
3665 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3667 hr = IBasicVideo_put_DestinationLeft(video, -10);
3668 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3669 check_destination_position(video, -10, 0, 600, 400);
3670 hr = IBasicVideo_IsUsingDefaultDestination(video);
3671 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3673 hr = IBasicVideo_put_DestinationLeft(video, 10);
3674 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3675 check_destination_position(video, 10, 0, 600, 400);
3676 hr = IBasicVideo_IsUsingDefaultDestination(video);
3677 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3679 hr = IBasicVideo_put_DestinationTop(video, -20);
3680 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3681 check_destination_position(video, 10, -20, 600, 400);
3682 hr = IBasicVideo_IsUsingDefaultDestination(video);
3683 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3685 hr = IBasicVideo_put_DestinationTop(video, 20);
3686 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3687 check_destination_position(video, 10, 20, 600, 400);
3688 hr = IBasicVideo_IsUsingDefaultDestination(video);
3689 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3691 hr = IBasicVideo_put_DestinationWidth(video, -700);
3692 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3693 hr = IBasicVideo_put_DestinationWidth(video, 0);
3694 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3695 hr = IBasicVideo_put_DestinationWidth(video, 700);
3696 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3697 check_destination_position(video, 10, 20, 700, 400);
3698 hr = IBasicVideo_IsUsingDefaultDestination(video);
3699 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3701 hr = IBasicVideo_put_DestinationWidth(video, 500);
3702 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3703 check_destination_position(video, 10, 20, 500, 400);
3704 hr = IBasicVideo_IsUsingDefaultDestination(video);
3705 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3707 hr = IBasicVideo_put_DestinationHeight(video, -500);
3708 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3709 hr = IBasicVideo_put_DestinationHeight(video, 0);
3710 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
3711 hr = IBasicVideo_put_DestinationHeight(video, 500);
3712 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3713 check_destination_position(video, 10, 20, 500, 500);
3714 hr = IBasicVideo_IsUsingDefaultDestination(video);
3715 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3717 hr = IBasicVideo_put_DestinationHeight(video, 300);
3718 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3719 check_destination_position(video, 10, 20, 500, 300);
3720 hr = IBasicVideo_IsUsingDefaultDestination(video);
3721 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3723 hr = IBasicVideo_SetDestinationPosition(video, 4, 5, 60, 40);
3724 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3725 check_destination_position(video, 4, 5, 60, 40);
3726 hr = IBasicVideo_IsUsingDefaultDestination(video);
3727 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3729 hr = IBasicVideo_SetDestinationPosition(video, 0, 0, 600, 400);
3730 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3731 check_destination_position(video, 0, 0, 600, 400);
3732 hr = IBasicVideo_IsUsingDefaultDestination(video);
3733 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3735 hr = IBasicVideo_SetDestinationPosition(video, 4, 5, 60, 40);
3736 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3737 hr = IBasicVideo_SetDefaultDestinationPosition(video);
3738 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3739 check_destination_position(video, 0, 0, 600, 400);
3740 hr = IBasicVideo_IsUsingDefaultDestination(video);
3741 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3743 SetRect(&rect, 100, 200, 500, 500);
3744 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
3745 hr = IVideoWindow_SetWindowPosition(window, rect.left, rect.top,
3746 rect.right - rect.left, rect.bottom - rect.top);
3747 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3748 check_destination_position(video, 0, 0, 400, 300);
3749 hr = IBasicVideo_IsUsingDefaultDestination(video);
3750 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3752 hr = IBasicVideo_SetDestinationPosition(video, 0, 0, 400, 300);
3753 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3754 check_destination_position(video, 0, 0, 400, 300);
3755 hr = IBasicVideo_IsUsingDefaultDestination(video);
3756 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3758 SetRect(&rect, 100, 200, 600, 600);
3759 AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
3760 hr = IVideoWindow_SetWindowPosition(window, rect.left, rect.top,
3761 rect.right - rect.left, rect.bottom - rect.top);
3762 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3763 check_destination_position(video, 0, 0, 400, 300);
3764 hr = IBasicVideo_IsUsingDefaultDestination(video);
3765 ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
3767 IVideoWindow_Release(window);
3770 static void test_basic_video(void)
3772 ALLOCATOR_PROPERTIES req_props = {1, 600 * 400 * 4, 1, 0}, ret_props;
3773 VIDEOINFOHEADER vih =
3775 .AvgTimePerFrame = 200000,
3776 .rcSource = {4, 6, 16, 12},
3777 .rcTarget = {40, 60, 120, 160},
3778 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
3779 .bmiHeader.biBitCount = 32,
3780 .bmiHeader.biWidth = 600,
3781 .bmiHeader.biHeight = 400,
3782 .bmiHeader.biPlanes = 1,
3783 .bmiHeader.biCompression = BI_RGB,
3785 AM_MEDIA_TYPE req_mt =
3787 .majortype = MEDIATYPE_Video,
3788 .subtype = MEDIASUBTYPE_RGB32,
3789 .formattype = FORMAT_VideoInfo,
3790 .cbFormat = sizeof(vih),
3791 .pbFormat = (BYTE *)&vih,
3793 IBaseFilter *filter = create_vmr9(VMR9Mode_Windowed);
3794 IFilterGraph2 *graph = create_graph();
3795 LONG left, top, width, height, l;
3796 struct testfilter source;
3797 IMemAllocator *allocator;
3798 IMemInputPin *input;
3799 ITypeInfo *typeinfo;
3800 IBasicVideo *video;
3801 TYPEATTR *typeattr;
3802 REFTIME reftime;
3803 HRESULT hr;
3804 UINT count;
3805 ULONG ref;
3806 IPin *pin;
3807 RECT rect;
3809 IBaseFilter_QueryInterface(filter, &IID_IBasicVideo, (void **)&video);
3810 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
3811 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
3813 hr = IBasicVideo_GetTypeInfoCount(video, &count);
3814 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3815 ok(count == 1, "Got count %u.\n", count);
3817 hr = IBasicVideo_GetTypeInfo(video, 0, 0, &typeinfo);
3818 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3819 hr = ITypeInfo_GetTypeAttr(typeinfo, &typeattr);
3820 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3821 ok(typeattr->typekind == TKIND_DISPATCH, "Got kind %u.\n", typeattr->typekind);
3822 ok(IsEqualGUID(&typeattr->guid, &IID_IBasicVideo), "Got IID %s.\n", wine_dbgstr_guid(&typeattr->guid));
3823 ITypeInfo_ReleaseTypeAttr(typeinfo, typeattr);
3824 ITypeInfo_Release(typeinfo);
3826 hr = IBasicVideo_get_AvgTimePerFrame(video, NULL);
3827 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3828 hr = IBasicVideo_get_AvgTimePerFrame(video, &reftime);
3829 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
3831 hr = IBasicVideo_get_BitRate(video, NULL);
3832 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3833 hr = IBasicVideo_get_BitRate(video, &l);
3834 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
3836 hr = IBasicVideo_get_BitErrorRate(video, NULL);
3837 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3838 hr = IBasicVideo_get_BitErrorRate(video, &l);
3839 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
3841 hr = IBasicVideo_get_VideoWidth(video, NULL);
3842 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3843 hr = IBasicVideo_get_VideoHeight(video, NULL);
3844 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3846 hr = IBasicVideo_get_SourceLeft(video, NULL);
3847 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3848 hr = IBasicVideo_get_SourceWidth(video, NULL);
3849 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3850 hr = IBasicVideo_get_SourceTop(video, NULL);
3851 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3852 hr = IBasicVideo_get_SourceHeight(video, NULL);
3853 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3855 hr = IBasicVideo_get_DestinationLeft(video, NULL);
3856 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3857 hr = IBasicVideo_get_DestinationWidth(video, NULL);
3858 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3859 hr = IBasicVideo_get_DestinationTop(video, NULL);
3860 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3861 hr = IBasicVideo_get_DestinationHeight(video, NULL);
3862 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3864 hr = IBasicVideo_GetSourcePosition(video, NULL, &top, &width, &height);
3865 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3866 hr = IBasicVideo_GetSourcePosition(video, &left, NULL, &width, &height);
3867 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3868 hr = IBasicVideo_GetSourcePosition(video, &left, &top, NULL, &height);
3869 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3870 hr = IBasicVideo_GetSourcePosition(video, &left, &top, &width, NULL);
3871 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3873 hr = IBasicVideo_GetDestinationPosition(video, NULL, &top, &width, &height);
3874 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3875 hr = IBasicVideo_GetDestinationPosition(video, &left, NULL, &width, &height);
3876 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3877 hr = IBasicVideo_GetDestinationPosition(video, &left, &top, NULL, &height);
3878 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3879 hr = IBasicVideo_GetDestinationPosition(video, &left, &top, &width, NULL);
3880 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3882 hr = IBasicVideo_GetVideoSize(video, &width, NULL);
3883 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3884 hr = IBasicVideo_GetVideoSize(video, NULL, &height);
3885 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3886 hr = IBasicVideo_GetVideoSize(video, &width, &height);
3887 ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
3889 hr = IBasicVideo_GetVideoPaletteEntries(video, 0, 1, NULL, &l);
3890 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
3891 hr = IBasicVideo_GetVideoPaletteEntries(video, 0, 1, &l, NULL);
3892 todo_wine ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr);
3894 testfilter_init(&source);
3895 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, L"vmr9");
3896 IFilterGraph2_AddFilter(graph, filter, L"source");
3897 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
3898 if (hr == E_FAIL)
3900 skip("Got E_FAIL when connecting.\n");
3901 goto out;
3903 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3905 hr = IMemInputPin_GetAllocator(input, &allocator);
3906 todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr);
3907 if (hr == S_OK)
3909 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
3910 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3911 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
3912 hr = IMemAllocator_Commit(allocator);
3913 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3914 IMemAllocator_Release(allocator);
3917 reftime = 0.0;
3918 hr = IBasicVideo_get_AvgTimePerFrame(video, &reftime);
3919 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3920 ok(compare_double(reftime, 0.02, 1 << 28), "Got frame rate %.16e.\n", reftime);
3922 l = 0xdeadbeef;
3923 hr = IBasicVideo_get_BitRate(video, &l);
3924 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3925 ok(!l, "Got bit rate %ld.\n", l);
3927 l = 0xdeadbeef;
3928 hr = IBasicVideo_get_BitErrorRate(video, &l);
3929 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3930 ok(!l, "Got bit rate %ld.\n", l);
3932 hr = IBasicVideo_GetVideoPaletteEntries(video, 0, 1, &l, NULL);
3933 todo_wine ok(hr == VFW_E_NO_PALETTE_AVAILABLE, "Got hr %#lx.\n", hr);
3935 width = height = 0xdeadbeef;
3936 hr = IBasicVideo_GetVideoSize(video, &width, &height);
3937 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3938 ok(width == 600, "Got width %ld.\n", width);
3939 ok(height == 400, "Got height %ld.\n", height);
3941 test_basic_video_source(video);
3942 test_basic_video_destination(video);
3944 hr = IFilterGraph2_Disconnect(graph, &source.source.pin.IPin_iface);
3945 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3946 hr = IFilterGraph2_Disconnect(graph, pin);
3947 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3949 vih.bmiHeader.biWidth = 16;
3950 vih.bmiHeader.biHeight = 16;
3951 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &req_mt);
3952 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3954 hr = IMemInputPin_GetAllocator(input, &allocator);
3955 todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr);
3956 if (hr == S_OK)
3958 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
3959 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3960 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
3961 hr = IMemAllocator_Commit(allocator);
3962 ok(hr == S_OK, "Got hr %#lx.\n", hr);
3963 IMemAllocator_Release(allocator);
3966 check_source_position(video, 0, 0, 16, 16);
3968 SetRect(&rect, 0, 0, 0, 0);
3969 AdjustWindowRectEx(&rect, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, FALSE, 0);
3970 check_destination_position(video, 0, 0, max(16, GetSystemMetrics(SM_CXMIN) - (rect.right - rect.left)),
3971 max(16, GetSystemMetrics(SM_CYMIN) - (rect.bottom - rect.top)));
3973 out:
3974 ref = IFilterGraph2_Release(graph);
3975 ok(!ref, "Got outstanding refcount %ld.\n", ref);
3976 IBasicVideo_Release(video);
3977 IMemInputPin_Release(input);
3978 IPin_Release(pin);
3979 ref = IBaseFilter_Release(filter);
3980 ok(!ref, "Got outstanding refcount %ld.\n", ref);
3981 ref = IBaseFilter_Release(&source.filter.IBaseFilter_iface);
3982 ok(!ref, "Got outstanding refcount %ld.\n", ref);
3985 static void test_windowless_size(void)
3987 ALLOCATOR_PROPERTIES req_props = {1, 32 * 16 * 4, 1, 0}, ret_props;
3988 VIDEOINFOHEADER vih =
3990 .bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
3991 .bmiHeader.biWidth = 32,
3992 .bmiHeader.biHeight = 16,
3993 .bmiHeader.biBitCount = 32,
3994 .bmiHeader.biPlanes = 1,
3996 AM_MEDIA_TYPE mt =
3998 .majortype = MEDIATYPE_Video,
3999 .subtype = MEDIASUBTYPE_RGB32,
4000 .formattype = FORMAT_VideoInfo,
4001 .cbFormat = sizeof(vih),
4002 .pbFormat = (BYTE *)&vih,
4004 IBaseFilter *filter = create_vmr9(VMR9Mode_Windowless);
4005 LONG width, height, aspect_width, aspect_height;
4006 IVMRAspectRatioControl9 *aspect_ratio_control;
4007 IVMRWindowlessControl9 *windowless_control;
4008 IFilterGraph2 *graph = create_graph();
4009 struct testfilter source;
4010 IMemAllocator *allocator;
4011 RECT src, dst, expect;
4012 IMemInputPin *input;
4013 DWORD aspect_mode;
4014 HWND window;
4015 HRESULT hr;
4016 ULONG ref;
4017 IPin *pin;
4019 IBaseFilter_QueryInterface(filter, &IID_IVMRWindowlessControl9, (void **)&windowless_control);
4020 IBaseFilter_QueryInterface(filter, &IID_IVMRAspectRatioControl9, (void **)&aspect_ratio_control);
4021 IBaseFilter_FindPin(filter, L"VMR Input0", &pin);
4022 IPin_QueryInterface(pin, &IID_IMemInputPin, (void **)&input);
4023 testfilter_init(&source);
4024 IFilterGraph2_AddFilter(graph, &source.filter.IBaseFilter_iface, L"source");
4025 IFilterGraph2_AddFilter(graph, filter, L"vmr9");
4026 window = CreateWindowA("static", "quartz_test", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0);
4027 ok(!!window, "Failed to create a window.\n");
4029 hr = IVMRWindowlessControl9_SetVideoClippingWindow(windowless_control, window);
4030 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4032 hr = IFilterGraph2_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &mt);
4033 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4034 hr = IMemInputPin_GetAllocator(input, &allocator);
4035 todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr);
4036 if (hr == S_OK)
4038 hr = IMemAllocator_SetProperties(allocator, &req_props, &ret_props);
4039 IMemAllocator_Release(allocator);
4040 if (hr == E_FAIL)
4042 skip("Got E_FAIL when setting allocator properties.\n");
4043 goto out;
4045 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4046 ok(!memcmp(&ret_props, &req_props, sizeof(req_props)), "Properties did not match.\n");
4049 hr = IVMRWindowlessControl9_GetNativeVideoSize(windowless_control, NULL, &height, &aspect_width, &aspect_height);
4050 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
4051 hr = IVMRWindowlessControl9_GetNativeVideoSize(windowless_control, &width, NULL, &aspect_width, &aspect_height);
4052 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
4054 aspect_mode = 0xdeadbeef;
4055 hr = IVMRWindowlessControl9_GetAspectRatioMode(windowless_control, &aspect_mode);
4056 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4057 ok(aspect_mode == VMR9ARMode_None, "Got mode %lu.\n", aspect_mode);
4059 aspect_mode = 0xdeadbeef;
4060 hr = IVMRAspectRatioControl9_GetAspectRatioMode(aspect_ratio_control, &aspect_mode);
4061 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4062 ok(aspect_mode == VMR9ARMode_None, "Got mode %lu.\n", aspect_mode);
4064 width = height = 0xdeadbeef;
4065 hr = IVMRWindowlessControl9_GetNativeVideoSize(windowless_control, &width, &height, NULL, NULL);
4066 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4067 ok(width == 32, "Got width %ld.\n", width);
4068 ok(height == 16, "Got height %ld.\n", height);
4070 aspect_width = aspect_height = 0xdeadbeef;
4071 hr = IVMRWindowlessControl9_GetNativeVideoSize(windowless_control, &width, &height, &aspect_width, &aspect_height);
4072 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4073 ok(aspect_width == 32, "Got width %ld.\n", aspect_width);
4074 ok(aspect_height == 16, "Got height %ld.\n", aspect_height);
4076 memset(&src, 0xcc, sizeof(src));
4077 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, &src, NULL);
4078 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4079 SetRect(&expect, 0, 0, 32, 16);
4080 ok(EqualRect(&src, &expect), "Got source rect %s.\n", wine_dbgstr_rect(&src));
4082 memset(&dst, 0xcc, sizeof(dst));
4083 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, NULL, &dst);
4084 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4085 SetRect(&expect, 0, 0, 0, 0);
4086 ok(EqualRect(&dst, &expect), "Got dest rect %s.\n", wine_dbgstr_rect(&dst));
4088 SetRect(&src, 4, 6, 16, 12);
4089 hr = IVMRWindowlessControl9_SetVideoPosition(windowless_control, &src, NULL);
4090 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4092 memset(&src, 0xcc, sizeof(src));
4093 memset(&dst, 0xcc, sizeof(dst));
4094 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, &src, &dst);
4095 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4096 SetRect(&expect, 4, 6, 16, 12);
4097 ok(EqualRect(&src, &expect), "Got source rect %s.\n", wine_dbgstr_rect(&src));
4098 SetRect(&expect, 0, 0, 0, 0);
4099 ok(EqualRect(&dst, &expect), "Got dest rect %s.\n", wine_dbgstr_rect(&dst));
4101 SetRect(&dst, 40, 60, 120, 160);
4102 hr = IVMRWindowlessControl9_SetVideoPosition(windowless_control, NULL, &dst);
4103 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4105 memset(&src, 0xcc, sizeof(src));
4106 memset(&dst, 0xcc, sizeof(dst));
4107 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, &src, &dst);
4108 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4109 SetRect(&expect, 4, 6, 16, 12);
4110 ok(EqualRect(&src, &expect), "Got source rect %s.\n", wine_dbgstr_rect(&src));
4111 SetRect(&expect, 40, 60, 120, 160);
4112 ok(EqualRect(&dst, &expect), "Got dest rect %s.\n", wine_dbgstr_rect(&dst));
4114 GetWindowRect(window, &src);
4115 SetRect(&expect, 0, 0, 640, 480);
4116 ok(EqualRect(&src, &expect), "Got window rect %s.\n", wine_dbgstr_rect(&src));
4118 hr = IVMRAspectRatioControl9_SetAspectRatioMode(aspect_ratio_control, VMR9ARMode_LetterBox);
4119 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4121 aspect_mode = 0xdeadbeef;
4122 hr = IVMRWindowlessControl9_GetAspectRatioMode(windowless_control, &aspect_mode);
4123 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4124 ok(aspect_mode == VMR9ARMode_LetterBox, "Got mode %lu.\n", aspect_mode);
4126 hr = IVMRWindowlessControl9_SetAspectRatioMode(windowless_control, VMR9ARMode_None);
4127 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4129 aspect_mode = 0xdeadbeef;
4130 hr = IVMRAspectRatioControl9_GetAspectRatioMode(aspect_ratio_control, &aspect_mode);
4131 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4132 ok(aspect_mode == VMR9ARMode_None, "Got mode %lu.\n", aspect_mode);
4134 hr = IVMRWindowlessControl9_SetAspectRatioMode(windowless_control, VMR9ARMode_LetterBox);
4135 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4137 memset(&src, 0xcc, sizeof(src));
4138 memset(&dst, 0xcc, sizeof(dst));
4139 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, &src, &dst);
4140 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4141 SetRect(&expect, 4, 6, 16, 12);
4142 ok(EqualRect(&src, &expect), "Got source rect %s.\n", wine_dbgstr_rect(&src));
4143 SetRect(&expect, 40, 60, 120, 160);
4144 ok(EqualRect(&dst, &expect), "Got dest rect %s.\n", wine_dbgstr_rect(&dst));
4146 SetRect(&src, 0, 0, 32, 16);
4147 SetRect(&dst, 0, 0, 640, 480);
4148 hr = IVMRWindowlessControl9_SetVideoPosition(windowless_control, &src, &dst);
4149 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4151 memset(&src, 0xcc, sizeof(src));
4152 memset(&dst, 0xcc, sizeof(dst));
4153 hr = IVMRWindowlessControl9_GetVideoPosition(windowless_control, &src, &dst);
4154 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4155 SetRect(&expect, 0, 0, 32, 16);
4156 ok(EqualRect(&src, &expect), "Got source rect %s.\n", wine_dbgstr_rect(&src));
4157 SetRect(&expect, 0, 0, 640, 480);
4158 ok(EqualRect(&dst, &expect), "Got dest rect %s.\n", wine_dbgstr_rect(&dst));
4160 out:
4161 ref = IFilterGraph2_Release(graph);
4162 ok(!ref, "Got outstanding refcount %ld.\n", ref);
4163 IMemInputPin_Release(input);
4164 IPin_Release(pin);
4165 IVMRWindowlessControl9_Release(windowless_control);
4166 IVMRAspectRatioControl9_Release(aspect_ratio_control);
4167 ref = IBaseFilter_Release(filter);
4168 ok(!ref, "Got outstanding refcount %ld.\n", ref);
4169 DestroyWindow(window);
4172 static void test_mixing_prefs(void)
4174 IBaseFilter *filter = create_vmr9(VMR9Mode_Windowed);
4175 IVMRMixerControl9 *mixer_control;
4176 DWORD flags;
4177 HRESULT hr;
4178 ULONG ref;
4180 set_mixing_mode(filter, 1);
4182 hr = IBaseFilter_QueryInterface(filter, &IID_IVMRMixerControl9, (void **)&mixer_control);
4183 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4185 hr = IVMRMixerControl9_GetMixingPrefs(mixer_control, &flags);
4186 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4187 ok(flags == (MixerPref9_NoDecimation | MixerPref9_ARAdjustXorY | MixerPref9_BiLinearFiltering
4188 | MixerPref9_RenderTargetRGB), "Got flags %#lx.\n", flags);
4190 hr = IVMRMixerControl9_SetMixingPrefs(mixer_control, MixerPref9_NoDecimation
4191 | MixerPref9_ARAdjustXorY | MixerPref9_PointFiltering | MixerPref9_RenderTargetRGB);
4192 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4194 hr = IVMRMixerControl9_GetMixingPrefs(mixer_control, &flags);
4195 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4196 ok(flags == (MixerPref9_NoDecimation | MixerPref9_ARAdjustXorY | MixerPref9_PointFiltering
4197 | MixerPref9_RenderTargetRGB), "Got flags %#lx.\n", flags);
4199 IVMRMixerControl9_Release(mixer_control);
4200 ref = IBaseFilter_Release(filter);
4201 ok(!ref, "Got outstanding refcount %ld.\n", ref);
4204 static void test_unconnected_eos(void)
4206 IFilterGraph2 *graph = create_graph();
4207 IBaseFilter *filter = create_vmr9(0);
4208 IMediaControl *control;
4209 IMediaEvent *eventsrc;
4210 unsigned int ret;
4211 HRESULT hr;
4212 ULONG ref;
4214 hr = IFilterGraph2_AddFilter(graph, filter, L"renderer");
4215 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4217 hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control);
4218 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4220 hr = IFilterGraph2_QueryInterface(graph, &IID_IMediaEvent, (void **)&eventsrc);
4221 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4223 ret = check_ec_complete(eventsrc, 0);
4224 ok(!ret, "Got %u EC_COMPLETE events.\n", ret);
4226 hr = IMediaControl_Pause(control);
4227 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4229 ret = check_ec_complete(eventsrc, 0);
4230 ok(!ret, "Got %u EC_COMPLETE events.\n", ret);
4232 hr = IMediaControl_Run(control);
4233 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4235 ret = check_ec_complete(eventsrc, 0);
4236 ok(ret == 1, "Got %u EC_COMPLETE events.\n", ret);
4238 hr = IMediaControl_Pause(control);
4239 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4241 ret = check_ec_complete(eventsrc, 0);
4242 ok(!ret, "Got %u EC_COMPLETE events.\n", ret);
4244 hr = IMediaControl_Run(control);
4245 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4247 ret = check_ec_complete(eventsrc, 0);
4248 ok(ret == 1, "Got %u EC_COMPLETE events.\n", ret);
4250 hr = IMediaControl_Stop(control);
4251 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4253 ret = check_ec_complete(eventsrc, 0);
4254 ok(!ret, "Got %u EC_COMPLETE events.\n", ret);
4256 hr = IMediaControl_Run(control);
4257 ok(hr == S_OK, "Got hr %#lx.\n", hr);
4259 ret = check_ec_complete(eventsrc, 0);
4260 ok(ret == 1, "Got %u EC_COMPLETE events.\n", ret);
4262 IMediaControl_Release(control);
4263 IMediaEvent_Release(eventsrc);
4264 ref = IFilterGraph2_Release(graph);
4265 ok(!ref, "Got outstanding refcount %ld.\n", ref);
4266 ref = IBaseFilter_Release(filter);
4267 ok(!ref, "Got outstanding refcount %ld.\n", ref);
4270 START_TEST(vmr9)
4272 IBaseFilter *filter;
4273 HRESULT hr;
4275 CoInitialize(NULL);
4277 if (FAILED(hr = CoCreateInstance(&CLSID_VideoMixingRenderer9, NULL,
4278 CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void **)&filter)))
4280 skip("Failed to create VMR9, hr %#lx.\n", hr);
4281 return;
4283 IBaseFilter_Release(filter);
4285 test_filter_config();
4286 test_interfaces();
4287 test_aggregation();
4288 test_enum_pins();
4289 test_find_pin();
4290 test_pin_info();
4291 test_media_types();
4292 test_enum_media_types();
4293 test_unconnected_filter_state();
4294 test_connect_pin();
4295 test_overlay();
4296 test_video_window();
4297 test_allocate_surface_helper();
4298 test_renderless_formats();
4299 test_mixing_mode();
4300 test_clipping_window();
4301 test_surface_allocator_notify_refcount();
4302 test_basic_video();
4303 test_windowless_size();
4304 test_mixing_prefs();
4305 test_unconnected_eos();
4307 CoUninitialize();