2 * Unit tests for Direct Show functions
4 * Copyright (C) 2004 Christian Costa
5 * Copyright (C) 2008 Alexander Dorofeyev
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/heap.h"
27 #include "wine/test.h"
29 static const GUID testguid
= {0xabbccdde};
31 typedef struct TestFilterImpl
33 IBaseFilter IBaseFilter_iface
;
36 CRITICAL_SECTION csFilter
;
38 FILTER_INFO filterInfo
;
44 static BOOL
compare_time(ULONGLONG x
, ULONGLONG y
, unsigned int max_diff
)
46 ULONGLONG diff
= x
> y
? x
- y
: y
- x
;
47 return diff
<= max_diff
;
50 static WCHAR
*create_file(const WCHAR
*name
, const char *data
, DWORD size
)
52 static WCHAR pathW
[MAX_PATH
];
56 GetTempPathW(ARRAY_SIZE(pathW
), pathW
);
58 file
= CreateFileW(pathW
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
59 ok(file
!= INVALID_HANDLE_VALUE
, "Failed to create file %s, error %u.\n",
60 wine_dbgstr_w(pathW
), GetLastError());
61 WriteFile(file
, data
, size
, &written
, NULL
);
62 ok(written
= size
, "Failed to write file data, error %u.\n", GetLastError());
68 static WCHAR
*load_resource(const WCHAR
*name
)
73 res
= FindResourceW(NULL
, name
, (const WCHAR
*)RT_RCDATA
);
74 ok(!!res
, "Failed to find resource %s, error %u.\n", wine_dbgstr_w(name
), GetLastError());
75 ptr
= LockResource(LoadResource(GetModuleHandleA(NULL
), res
));
76 return create_file(name
, ptr
, SizeofResource(GetModuleHandleA(NULL
), res
));
79 static IFilterGraph2
*create_graph(void)
83 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterGraph2
, (void **)&ret
);
84 ok(hr
== S_OK
, "Failed to create FilterGraph: %#x\n", hr
);
88 static ULONG
get_refcount(void *iface
)
90 IUnknown
*unknown
= iface
;
91 IUnknown_AddRef(unknown
);
92 return IUnknown_Release(unknown
);
95 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
96 static void check_interface_(unsigned int line
, void *iface_ptr
, REFIID iid
, BOOL supported
)
98 IUnknown
*iface
= iface_ptr
;
99 HRESULT hr
, expected_hr
;
102 expected_hr
= supported
? S_OK
: E_NOINTERFACE
;
104 hr
= IUnknown_QueryInterface(iface
, iid
, (void **)&unk
);
105 ok_(__FILE__
, line
)(hr
== expected_hr
, "Got hr %#x, expected %#x.\n", hr
, expected_hr
);
107 IUnknown_Release(unk
);
110 static void test_interfaces(void)
112 IFilterGraph2
*graph
= create_graph();
114 check_interface(graph
, &IID_IBasicAudio
, TRUE
);
115 check_interface(graph
, &IID_IBasicVideo2
, TRUE
);
116 check_interface(graph
, &IID_IFilterGraph2
, TRUE
);
117 check_interface(graph
, &IID_IFilterMapper
, TRUE
);
118 check_interface(graph
, &IID_IFilterMapper3
, TRUE
);
119 check_interface(graph
, &IID_IGraphConfig
, TRUE
);
120 check_interface(graph
, &IID_IGraphVersion
, TRUE
);
121 check_interface(graph
, &IID_IMediaControl
, TRUE
);
122 check_interface(graph
, &IID_IMediaEvent
, TRUE
);
123 check_interface(graph
, &IID_IMediaFilter
, TRUE
);
124 check_interface(graph
, &IID_IMediaEventSink
, TRUE
);
125 check_interface(graph
, &IID_IMediaPosition
, TRUE
);
126 check_interface(graph
, &IID_IMediaSeeking
, TRUE
);
127 check_interface(graph
, &IID_IObjectWithSite
, TRUE
);
128 check_interface(graph
, &IID_IVideoFrameStep
, TRUE
);
129 check_interface(graph
, &IID_IVideoWindow
, TRUE
);
131 check_interface(graph
, &IID_IBaseFilter
, FALSE
);
133 IFilterGraph2_Release(graph
);
136 static void test_basic_video(IFilterGraph2
*graph
)
139 LONG video_width
, video_height
, window_width
;
140 LONG left
, top
, width
, height
;
143 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IBasicVideo
, (void **)&pbv
);
144 ok(hr
==S_OK
, "Cannot get IBasicVideo interface returned: %x\n", hr
);
146 /* test get video size */
147 hr
= IBasicVideo_GetVideoSize(pbv
, NULL
, NULL
);
148 ok(hr
==E_POINTER
, "IBasicVideo_GetVideoSize returned: %x\n", hr
);
149 hr
= IBasicVideo_GetVideoSize(pbv
, &video_width
, NULL
);
150 ok(hr
==E_POINTER
, "IBasicVideo_GetVideoSize returned: %x\n", hr
);
151 hr
= IBasicVideo_GetVideoSize(pbv
, NULL
, &video_height
);
152 ok(hr
==E_POINTER
, "IBasicVideo_GetVideoSize returned: %x\n", hr
);
153 hr
= IBasicVideo_GetVideoSize(pbv
, &video_width
, &video_height
);
154 ok(hr
==S_OK
, "Cannot get video size returned: %x\n", hr
);
156 /* test source position */
157 hr
= IBasicVideo_GetSourcePosition(pbv
, NULL
, NULL
, NULL
, NULL
);
158 ok(hr
== E_POINTER
, "IBasicVideo_GetSourcePosition returned: %x\n", hr
);
159 hr
= IBasicVideo_GetSourcePosition(pbv
, &left
, &top
, NULL
, NULL
);
160 ok(hr
== E_POINTER
, "IBasicVideo_GetSourcePosition returned: %x\n", hr
);
161 hr
= IBasicVideo_GetSourcePosition(pbv
, NULL
, NULL
, &width
, &height
);
162 ok(hr
== E_POINTER
, "IBasicVideo_GetSourcePosition returned: %x\n", hr
);
163 hr
= IBasicVideo_GetSourcePosition(pbv
, &left
, &top
, &width
, &height
);
164 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
165 ok(left
== 0, "expected 0, got %d\n", left
);
166 ok(top
== 0, "expected 0, got %d\n", top
);
167 ok(width
== video_width
, "expected %d, got %d\n", video_width
, width
);
168 ok(height
== video_height
, "expected %d, got %d\n", video_height
, height
);
170 hr
= IBasicVideo_SetSourcePosition(pbv
, 0, 0, 0, 0);
171 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
172 hr
= IBasicVideo_SetSourcePosition(pbv
, 0, 0, video_width
*2, video_height
*2);
173 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
174 hr
= IBasicVideo_put_SourceTop(pbv
, -1);
175 ok(hr
==E_INVALIDARG
, "IBasicVideo_put_SourceTop returned: %x\n", hr
);
176 hr
= IBasicVideo_put_SourceTop(pbv
, 0);
177 ok(hr
==S_OK
, "Cannot put source top returned: %x\n", hr
);
178 hr
= IBasicVideo_put_SourceTop(pbv
, 1);
179 ok(hr
==E_INVALIDARG
, "IBasicVideo_put_SourceTop returned: %x\n", hr
);
181 hr
= IBasicVideo_SetSourcePosition(pbv
, video_width
, 0, video_width
, video_height
);
182 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
183 hr
= IBasicVideo_SetSourcePosition(pbv
, 0, video_height
, video_width
, video_height
);
184 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
185 hr
= IBasicVideo_SetSourcePosition(pbv
, -1, 0, video_width
, video_height
);
186 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
187 hr
= IBasicVideo_SetSourcePosition(pbv
, 0, -1, video_width
, video_height
);
188 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
189 hr
= IBasicVideo_SetSourcePosition(pbv
, video_width
/2, video_height
/2, video_width
, video_height
);
190 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
191 hr
= IBasicVideo_SetSourcePosition(pbv
, video_width
/2, video_height
/2, video_width
, video_height
);
192 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
194 hr
= IBasicVideo_SetSourcePosition(pbv
, 0, 0, video_width
, video_height
+1);
195 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
196 hr
= IBasicVideo_SetSourcePosition(pbv
, 0, 0, video_width
+1, video_height
);
197 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
199 hr
= IBasicVideo_SetSourcePosition(pbv
, video_width
/2, video_height
/2, video_width
/3+1, video_height
/3+1);
200 ok(hr
==S_OK
, "Cannot set source position returned: %x\n", hr
);
202 hr
= IBasicVideo_get_SourceLeft(pbv
, &left
);
203 ok(hr
==S_OK
, "Cannot get source left returned: %x\n", hr
);
204 ok(left
==video_width
/2, "expected %d, got %d\n", video_width
/2, left
);
205 hr
= IBasicVideo_get_SourceTop(pbv
, &top
);
206 ok(hr
==S_OK
, "Cannot get source top returned: %x\n", hr
);
207 ok(top
==video_height
/2, "expected %d, got %d\n", video_height
/2, top
);
208 hr
= IBasicVideo_get_SourceWidth(pbv
, &width
);
209 ok(hr
==S_OK
, "Cannot get source width returned: %x\n", hr
);
210 ok(width
==video_width
/3+1, "expected %d, got %d\n", video_width
/3+1, width
);
211 hr
= IBasicVideo_get_SourceHeight(pbv
, &height
);
212 ok(hr
==S_OK
, "Cannot get source height returned: %x\n", hr
);
213 ok(height
==video_height
/3+1, "expected %d, got %d\n", video_height
/3+1, height
);
215 hr
= IBasicVideo_put_SourceLeft(pbv
, video_width
/3);
216 ok(hr
==S_OK
, "Cannot put source left returned: %x\n", hr
);
217 hr
= IBasicVideo_GetSourcePosition(pbv
, &left
, &top
, &width
, &height
);
218 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
219 ok(left
== video_width
/3, "expected %d, got %d\n", video_width
/3, left
);
220 ok(width
== video_width
/3+1, "expected %d, got %d\n", video_width
/3+1, width
);
222 hr
= IBasicVideo_put_SourceTop(pbv
, video_height
/3);
223 ok(hr
==S_OK
, "Cannot put source top returned: %x\n", hr
);
224 hr
= IBasicVideo_GetSourcePosition(pbv
, &left
, &top
, &width
, &height
);
225 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
226 ok(top
== video_height
/3, "expected %d, got %d\n", video_height
/3, top
);
227 ok(height
== video_height
/3+1, "expected %d, got %d\n", video_height
/3+1, height
);
229 hr
= IBasicVideo_put_SourceWidth(pbv
, video_width
/4+1);
230 ok(hr
==S_OK
, "Cannot put source width returned: %x\n", hr
);
231 hr
= IBasicVideo_GetSourcePosition(pbv
, &left
, &top
, &width
, &height
);
232 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
233 ok(left
== video_width
/3, "expected %d, got %d\n", video_width
/3, left
);
234 ok(width
== video_width
/4+1, "expected %d, got %d\n", video_width
/4+1, width
);
236 hr
= IBasicVideo_put_SourceHeight(pbv
, video_height
/4+1);
237 ok(hr
==S_OK
, "Cannot put source height returned: %x\n", hr
);
238 hr
= IBasicVideo_GetSourcePosition(pbv
, &left
, &top
, &width
, &height
);
239 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
240 ok(top
== video_height
/3, "expected %d, got %d\n", video_height
/3, top
);
241 ok(height
== video_height
/4+1, "expected %d, got %d\n", video_height
/4+1, height
);
243 /* test destination rectangle */
244 window_width
= max(video_width
, GetSystemMetrics(SM_CXMIN
) - 2 * GetSystemMetrics(SM_CXFRAME
));
246 hr
= IBasicVideo_GetDestinationPosition(pbv
, NULL
, NULL
, NULL
, NULL
);
247 ok(hr
== E_POINTER
, "IBasicVideo_GetDestinationPosition returned: %x\n", hr
);
248 hr
= IBasicVideo_GetDestinationPosition(pbv
, &left
, &top
, NULL
, NULL
);
249 ok(hr
== E_POINTER
, "IBasicVideo_GetDestinationPosition returned: %x\n", hr
);
250 hr
= IBasicVideo_GetDestinationPosition(pbv
, NULL
, NULL
, &width
, &height
);
251 ok(hr
== E_POINTER
, "IBasicVideo_GetDestinationPosition returned: %x\n", hr
);
252 hr
= IBasicVideo_GetDestinationPosition(pbv
, &left
, &top
, &width
, &height
);
253 ok(hr
== S_OK
, "Cannot get destination position returned: %x\n", hr
);
254 ok(left
== 0, "expected 0, got %d\n", left
);
255 ok(top
== 0, "expected 0, got %d\n", top
);
256 ok(width
== window_width
, "expected %d, got %d\n", window_width
, width
);
257 ok(height
== video_height
, "expected %d, got %d\n", video_height
, height
);
259 hr
= IBasicVideo_SetDestinationPosition(pbv
, 0, 0, 0, 0);
260 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetDestinationPosition returned: %x\n", hr
);
261 hr
= IBasicVideo_SetDestinationPosition(pbv
, 0, 0, video_width
*2, video_height
*2);
262 ok(hr
==S_OK
, "Cannot put destination position returned: %x\n", hr
);
264 hr
= IBasicVideo_put_DestinationLeft(pbv
, -1);
265 ok(hr
==S_OK
, "Cannot put destination left returned: %x\n", hr
);
266 hr
= IBasicVideo_put_DestinationLeft(pbv
, 0);
267 ok(hr
==S_OK
, "Cannot put destination left returned: %x\n", hr
);
268 hr
= IBasicVideo_put_DestinationLeft(pbv
, 1);
269 ok(hr
==S_OK
, "Cannot put destination left returned: %x\n", hr
);
271 hr
= IBasicVideo_SetDestinationPosition(pbv
, video_width
, 0, video_width
, video_height
);
272 ok(hr
==S_OK
, "Cannot set destinaiton position returned: %x\n", hr
);
273 hr
= IBasicVideo_SetDestinationPosition(pbv
, 0, video_height
, video_width
, video_height
);
274 ok(hr
==S_OK
, "Cannot set destinaiton position returned: %x\n", hr
);
275 hr
= IBasicVideo_SetDestinationPosition(pbv
, -1, 0, video_width
, video_height
);
276 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
277 hr
= IBasicVideo_SetDestinationPosition(pbv
, 0, -1, video_width
, video_height
);
278 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
279 hr
= IBasicVideo_SetDestinationPosition(pbv
, video_width
/2, video_height
/2, video_width
, video_height
);
280 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
281 hr
= IBasicVideo_SetDestinationPosition(pbv
, video_width
/2, video_height
/2, video_width
, video_height
);
282 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
284 hr
= IBasicVideo_SetDestinationPosition(pbv
, 0, 0, video_width
, video_height
+1);
285 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
286 hr
= IBasicVideo_SetDestinationPosition(pbv
, 0, 0, video_width
+1, video_height
);
287 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
289 hr
= IBasicVideo_SetDestinationPosition(pbv
, video_width
/2, video_height
/2, video_width
/3+1, video_height
/3+1);
290 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
292 hr
= IBasicVideo_get_DestinationLeft(pbv
, &left
);
293 ok(hr
==S_OK
, "Cannot get destination left returned: %x\n", hr
);
294 ok(left
==video_width
/2, "expected %d, got %d\n", video_width
/2, left
);
295 hr
= IBasicVideo_get_DestinationTop(pbv
, &top
);
296 ok(hr
==S_OK
, "Cannot get destination top returned: %x\n", hr
);
297 ok(top
==video_height
/2, "expected %d, got %d\n", video_height
/2, top
);
298 hr
= IBasicVideo_get_DestinationWidth(pbv
, &width
);
299 ok(hr
==S_OK
, "Cannot get destination width returned: %x\n", hr
);
300 ok(width
==video_width
/3+1, "expected %d, got %d\n", video_width
/3+1, width
);
301 hr
= IBasicVideo_get_DestinationHeight(pbv
, &height
);
302 ok(hr
==S_OK
, "Cannot get destination height returned: %x\n", hr
);
303 ok(height
==video_height
/3+1, "expected %d, got %d\n", video_height
/3+1, height
);
305 hr
= IBasicVideo_put_DestinationLeft(pbv
, video_width
/3);
306 ok(hr
==S_OK
, "Cannot put destination left returned: %x\n", hr
);
307 hr
= IBasicVideo_GetDestinationPosition(pbv
, &left
, &top
, &width
, &height
);
308 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
309 ok(left
== video_width
/3, "expected %d, got %d\n", video_width
/3, left
);
310 ok(width
== video_width
/3+1, "expected %d, got %d\n", video_width
/3+1, width
);
312 hr
= IBasicVideo_put_DestinationTop(pbv
, video_height
/3);
313 ok(hr
==S_OK
, "Cannot put destination top returned: %x\n", hr
);
314 hr
= IBasicVideo_GetDestinationPosition(pbv
, &left
, &top
, &width
, &height
);
315 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
316 ok(top
== video_height
/3, "expected %d, got %d\n", video_height
/3, top
);
317 ok(height
== video_height
/3+1, "expected %d, got %d\n", video_height
/3+1, height
);
319 hr
= IBasicVideo_put_DestinationWidth(pbv
, video_width
/4+1);
320 ok(hr
==S_OK
, "Cannot put destination width returned: %x\n", hr
);
321 hr
= IBasicVideo_GetDestinationPosition(pbv
, &left
, &top
, &width
, &height
);
322 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
323 ok(left
== video_width
/3, "expected %d, got %d\n", video_width
/3, left
);
324 ok(width
== video_width
/4+1, "expected %d, got %d\n", video_width
/4+1, width
);
326 hr
= IBasicVideo_put_DestinationHeight(pbv
, video_height
/4+1);
327 ok(hr
==S_OK
, "Cannot put destination height returned: %x\n", hr
);
328 hr
= IBasicVideo_GetDestinationPosition(pbv
, &left
, &top
, &width
, &height
);
329 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
330 ok(top
== video_height
/3, "expected %d, got %d\n", video_height
/3, top
);
331 ok(height
== video_height
/4+1, "expected %d, got %d\n", video_height
/4+1, height
);
333 /* reset source rectangle */
334 hr
= IBasicVideo_SetDefaultSourcePosition(pbv
);
335 ok(hr
==S_OK
, "IBasicVideo_SetDefaultSourcePosition returned: %x\n", hr
);
337 /* reset destination position */
338 hr
= IBasicVideo_SetDestinationPosition(pbv
, 0, 0, video_width
, video_height
);
339 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
341 IBasicVideo_Release(pbv
);
344 static void test_media_seeking(IFilterGraph2
*graph
)
346 IMediaSeeking
*seeking
;
347 IMediaFilter
*filter
;
348 LONGLONG pos
, stop
, duration
;
352 IFilterGraph2_SetDefaultSyncSource(graph
);
353 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IMediaSeeking
, (void **)&seeking
);
354 ok(hr
== S_OK
, "QueryInterface(IMediaControl) failed: %08x\n", hr
);
356 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IMediaFilter
, (void **)&filter
);
357 ok(hr
== S_OK
, "QueryInterface(IMediaFilter) failed: %08x\n", hr
);
360 hr
= IMediaSeeking_GetTimeFormat(seeking
, &format
);
361 ok(hr
== S_OK
, "GetTimeFormat failed: %#x\n", hr
);
362 ok(IsEqualGUID(&format
, &TIME_FORMAT_MEDIA_TIME
), "got %s\n", wine_dbgstr_guid(&format
));
365 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &pos
, NULL
, 0x123456789a, NULL
);
366 ok(hr
== S_OK
, "ConvertTimeFormat failed: %#x\n", hr
);
367 ok(pos
== 0x123456789a, "got %s\n", wine_dbgstr_longlong(pos
));
370 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &pos
, &TIME_FORMAT_MEDIA_TIME
, 0x123456789a, NULL
);
371 ok(hr
== S_OK
, "ConvertTimeFormat failed: %#x\n", hr
);
372 ok(pos
== 0x123456789a, "got %s\n", wine_dbgstr_longlong(pos
));
375 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &pos
, NULL
, 0x123456789a, &TIME_FORMAT_MEDIA_TIME
);
376 ok(hr
== S_OK
, "ConvertTimeFormat failed: %#x\n", hr
);
377 ok(pos
== 0x123456789a, "got %s\n", wine_dbgstr_longlong(pos
));
379 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &pos
);
380 ok(hr
== S_OK
, "GetCurrentPosition failed: %#x\n", hr
);
381 ok(pos
== 0, "got %s\n", wine_dbgstr_longlong(pos
));
383 hr
= IMediaSeeking_GetDuration(seeking
, &duration
);
384 ok(hr
== S_OK
, "GetDuration failed: %#x\n", hr
);
385 ok(duration
> 0, "got %s\n", wine_dbgstr_longlong(duration
));
387 hr
= IMediaSeeking_GetStopPosition(seeking
, &stop
);
388 ok(hr
== S_OK
, "GetCurrentPosition failed: %08x\n", hr
);
389 ok(stop
== duration
|| stop
== duration
+ 1, "expected %s, got %s\n",
390 wine_dbgstr_longlong(duration
), wine_dbgstr_longlong(stop
));
392 hr
= IMediaSeeking_SetPositions(seeking
, NULL
, AM_SEEKING_ReturnTime
, NULL
, AM_SEEKING_NoPositioning
);
393 ok(hr
== S_OK
, "SetPositions failed: %#x\n", hr
);
394 hr
= IMediaSeeking_SetPositions(seeking
, NULL
, AM_SEEKING_NoPositioning
, NULL
, AM_SEEKING_ReturnTime
);
395 ok(hr
== S_OK
, "SetPositions failed: %#x\n", hr
);
398 hr
= IMediaSeeking_SetPositions(seeking
, &pos
, AM_SEEKING_AbsolutePositioning
, NULL
, AM_SEEKING_NoPositioning
);
399 ok(hr
== S_OK
, "SetPositions failed: %08x\n", hr
);
401 IMediaFilter_SetSyncSource(filter
, NULL
);
403 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &pos
);
404 ok(hr
== S_OK
, "GetCurrentPosition failed: %08x\n", hr
);
405 ok(pos
== 0, "Position != 0 (%s)\n", wine_dbgstr_longlong(pos
));
406 IFilterGraph2_SetDefaultSyncSource(graph
);
408 IMediaSeeking_Release(seeking
);
409 IMediaFilter_Release(filter
);
412 static void test_state_change(IFilterGraph2
*graph
)
414 IMediaControl
*control
;
418 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IMediaControl
, (void **)&control
);
419 ok(hr
== S_OK
, "QueryInterface(IMediaControl) failed: %x\n", hr
);
421 hr
= IMediaControl_GetState(control
, 1000, &state
);
422 ok(hr
== S_OK
, "GetState() failed: %x\n", hr
);
423 ok(state
== State_Stopped
, "wrong state %d\n", state
);
425 hr
= IMediaControl_Run(control
);
426 ok(SUCCEEDED(hr
), "Run() failed: %x\n", hr
);
427 hr
= IMediaControl_GetState(control
, INFINITE
, &state
);
428 ok(SUCCEEDED(hr
), "GetState() failed: %x\n", hr
);
429 ok(state
== State_Running
, "wrong state %d\n", state
);
431 hr
= IMediaControl_Stop(control
);
432 ok(SUCCEEDED(hr
), "Stop() failed: %x\n", hr
);
433 hr
= IMediaControl_GetState(control
, 1000, &state
);
434 ok(hr
== S_OK
, "GetState() failed: %x\n", hr
);
435 ok(state
== State_Stopped
, "wrong state %d\n", state
);
437 hr
= IMediaControl_Pause(control
);
438 ok(SUCCEEDED(hr
), "Pause() failed: %x\n", hr
);
439 hr
= IMediaControl_GetState(control
, 1000, &state
);
440 ok(hr
== S_OK
, "GetState() failed: %x\n", hr
);
441 ok(state
== State_Paused
, "wrong state %d\n", state
);
443 hr
= IMediaControl_Run(control
);
444 ok(SUCCEEDED(hr
), "Run() failed: %x\n", hr
);
445 hr
= IMediaControl_GetState(control
, 1000, &state
);
446 ok(hr
== S_OK
, "GetState() failed: %x\n", hr
);
447 ok(state
== State_Running
, "wrong state %d\n", state
);
449 hr
= IMediaControl_Pause(control
);
450 ok(SUCCEEDED(hr
), "Pause() failed: %x\n", hr
);
451 hr
= IMediaControl_GetState(control
, 1000, &state
);
452 ok(hr
== S_OK
, "GetState() failed: %x\n", hr
);
453 ok(state
== State_Paused
, "wrong state %d\n", state
);
455 hr
= IMediaControl_Stop(control
);
456 ok(SUCCEEDED(hr
), "Stop() failed: %x\n", hr
);
457 hr
= IMediaControl_GetState(control
, 1000, &state
);
458 ok(hr
== S_OK
, "GetState() failed: %x\n", hr
);
459 ok(state
== State_Stopped
, "wrong state %d\n", state
);
461 IMediaControl_Release(control
);
464 static void test_media_event(IFilterGraph2
*graph
)
466 IMediaEvent
*media_event
;
467 IMediaSeeking
*seeking
;
468 IMediaControl
*control
;
469 IMediaFilter
*filter
;
470 LONG_PTR lparam1
, lparam2
;
471 LONGLONG current
, stop
;
478 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IMediaFilter
, (void **)&filter
);
479 ok(hr
== S_OK
, "QueryInterface(IMediaFilter) failed: %#x\n", hr
);
481 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IMediaControl
, (void **)&control
);
482 ok(hr
== S_OK
, "QueryInterface(IMediaControl) failed: %#x\n", hr
);
484 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IMediaEvent
, (void **)&media_event
);
485 ok(hr
== S_OK
, "QueryInterface(IMediaEvent) failed: %#x\n", hr
);
487 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IMediaSeeking
, (void **)&seeking
);
488 ok(hr
== S_OK
, "QueryInterface(IMediaEvent) failed: %#x\n", hr
);
490 hr
= IMediaControl_Stop(control
);
491 ok(SUCCEEDED(hr
), "Stop() failed: %#x\n", hr
);
492 hr
= IMediaControl_GetState(control
, 1000, &state
);
493 ok(hr
== S_OK
, "GetState() timed out\n");
495 hr
= IMediaSeeking_GetDuration(seeking
, &stop
);
496 ok(hr
== S_OK
, "GetDuration() failed: %#x\n", hr
);
498 hr
= IMediaSeeking_SetPositions(seeking
, ¤t
, AM_SEEKING_AbsolutePositioning
, &stop
, AM_SEEKING_AbsolutePositioning
);
499 ok(hr
== S_OK
, "SetPositions() failed: %#x\n", hr
);
501 hr
= IMediaFilter_SetSyncSource(filter
, NULL
);
502 ok(hr
== S_OK
, "SetSyncSource() failed: %#x\n", hr
);
504 hr
= IMediaEvent_GetEventHandle(media_event
, (OAEVENT
*)&event
);
505 ok(hr
== S_OK
, "GetEventHandle() failed: %#x\n", hr
);
507 /* flush existing events */
508 while ((hr
= IMediaEvent_GetEvent(media_event
, &code
, &lparam1
, &lparam2
, 0)) == S_OK
);
510 ok(WaitForSingleObject(event
, 0) == WAIT_TIMEOUT
, "event should not be signaled\n");
512 hr
= IMediaControl_Run(control
);
513 ok(SUCCEEDED(hr
), "Run() failed: %#x\n", hr
);
517 if (WaitForSingleObject(event
, 5000) == WAIT_TIMEOUT
)
520 while ((hr
= IMediaEvent_GetEvent(media_event
, &code
, &lparam1
, &lparam2
, 0)) == S_OK
)
522 if (code
== EC_COMPLETE
)
529 ok(got_eos
, "didn't get EOS\n");
531 hr
= IMediaSeeking_GetCurrentPosition(seeking
, ¤t
);
532 ok(hr
== S_OK
, "GetCurrentPosition() failed: %#x\n", hr
);
534 ok(current
== stop
, "expected %s, got %s\n", wine_dbgstr_longlong(stop
), wine_dbgstr_longlong(current
));
536 hr
= IMediaControl_Stop(control
);
537 ok(SUCCEEDED(hr
), "Run() failed: %#x\n", hr
);
538 hr
= IMediaControl_GetState(control
, 1000, &state
);
539 ok(hr
== S_OK
, "GetState() timed out\n");
541 hr
= IFilterGraph2_SetDefaultSyncSource(graph
);
542 ok(hr
== S_OK
, "SetDefaultSinkSource() failed: %#x\n", hr
);
544 IMediaSeeking_Release(seeking
);
545 IMediaEvent_Release(media_event
);
546 IMediaControl_Release(control
);
547 IMediaFilter_Release(filter
);
550 static void rungraph(IFilterGraph2
*graph
, BOOL video
)
553 test_basic_video(graph
);
554 test_media_seeking(graph
);
555 test_state_change(graph
);
556 test_media_event(graph
);
559 static HRESULT
test_graph_builder_connect_file(WCHAR
*filename
, BOOL audio
, BOOL video
)
561 IBaseFilter
*source_filter
, *renderer
;
562 IPin
*pin_in
, *pin_out
;
563 IFilterGraph2
*graph
;
568 hr
= CoCreateInstance(&CLSID_VideoRenderer
, NULL
, CLSCTX_INPROC_SERVER
,
569 &IID_IBaseFilter
, (void **)&renderer
);
571 hr
= CoCreateInstance(&CLSID_AudioRender
, NULL
, CLSCTX_INPROC_SERVER
,
572 &IID_IBaseFilter
, (void **)&renderer
);
573 if (hr
== VFW_E_NO_AUDIO_HARDWARE
)
574 return VFW_E_CANNOT_CONNECT
;
575 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
577 graph
= create_graph();
579 IBaseFilter_EnumPins(renderer
, &enumpins
);
580 IEnumPins_Next(enumpins
, 1, &pin_in
, NULL
);
581 IEnumPins_Release(enumpins
);
583 hr
= IFilterGraph2_AddSourceFilter(graph
, filename
, NULL
, &source_filter
);
584 ok(hr
== S_OK
, "AddSourceFilter failed: %#x\n", hr
);
586 hr
= IFilterGraph2_AddFilter(graph
, renderer
, NULL
);
587 ok(hr
== S_OK
, "AddFilter failed: %#x\n", hr
);
589 hr
= IBaseFilter_FindPin(source_filter
, L
"Output", &pin_out
);
590 ok(hr
== S_OK
, "FindPin failed: %#x\n", hr
);
591 hr
= IFilterGraph2_Connect(graph
, pin_out
, pin_in
);
594 rungraph(graph
, video
);
596 IPin_Release(pin_in
);
597 IPin_Release(pin_out
);
598 IBaseFilter_Release(source_filter
);
599 IBaseFilter_Release(renderer
);
600 IFilterGraph2_Release(graph
);
605 static void test_render_run(const WCHAR
*file
, BOOL audio
, BOOL video
)
607 IFilterGraph2
*graph
;
611 WCHAR
*filename
= load_resource(file
);
613 h
= CreateFileW(filename
, 0, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
614 if (h
== INVALID_HANDLE_VALUE
) {
615 skip("Could not read test file %s, skipping test\n", wine_dbgstr_w(file
));
616 DeleteFileW(filename
);
621 trace("running %s\n", wine_dbgstr_w(file
));
623 graph
= create_graph();
625 hr
= IFilterGraph2_RenderFile(graph
, filename
, NULL
);
628 skip("%s: codec not supported; skipping test\n", wine_dbgstr_w(file
));
630 refs
= IFilterGraph2_Release(graph
);
631 ok(!refs
, "Graph has %u references\n", refs
);
633 hr
= test_graph_builder_connect_file(filename
, audio
, video
);
634 ok(hr
== VFW_E_CANNOT_CONNECT
, "got %#x\n", hr
);
639 ok(hr
== S_OK
|| hr
== VFW_S_AUDIO_NOT_RENDERED
, "Got hr %#x.\n", hr
);
641 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
642 rungraph(graph
, video
);
644 refs
= IFilterGraph2_Release(graph
);
645 ok(!refs
, "Graph has %u references\n", refs
);
647 hr
= test_graph_builder_connect_file(filename
, audio
, video
);
649 todo_wine
ok(hr
== VFW_S_PARTIAL_RENDER
, "Got hr %#x.\n", hr
);
651 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
654 /* check reference leaks */
655 h
= CreateFileW(filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
656 ok(h
!= INVALID_HANDLE_VALUE
, "CreateFile failed: err=%d\n", GetLastError());
659 DeleteFileW(filename
);
662 static void test_enum_filters(void)
664 IBaseFilter
*filter1
, *filter2
, *filters
[2];
665 IFilterGraph2
*graph
= create_graph();
666 IEnumFilters
*enum1
, *enum2
;
670 CoCreateInstance(&CLSID_AsyncReader
, NULL
, CLSCTX_INPROC_SERVER
,
671 &IID_IBaseFilter
, (void **)&filter1
);
672 CoCreateInstance(&CLSID_AsyncReader
, NULL
, CLSCTX_INPROC_SERVER
,
673 &IID_IBaseFilter
, (void **)&filter2
);
675 hr
= IFilterGraph2_EnumFilters(graph
, &enum1
);
676 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
678 hr
= IEnumFilters_Next(enum1
, 1, filters
, NULL
);
679 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
681 IFilterGraph2_AddFilter(graph
, filter1
, NULL
);
682 IFilterGraph2_AddFilter(graph
, filter2
, NULL
);
684 hr
= IEnumFilters_Next(enum1
, 1, filters
, NULL
);
685 ok(hr
== VFW_E_ENUM_OUT_OF_SYNC
, "Got hr %#x.\n", hr
);
687 hr
= IEnumFilters_Reset(enum1
);
688 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
690 hr
= IEnumFilters_Next(enum1
, 1, filters
, NULL
);
691 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
692 ok(filters
[0] == filter2
, "Got filter %p.\n", filters
[0]);
693 IBaseFilter_Release(filters
[0]);
695 hr
= IEnumFilters_Next(enum1
, 1, filters
, &count
);
696 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
697 ok(count
== 1, "Got count %u.\n", count
);
698 ok(filters
[0] == filter1
, "Got filter %p.\n", filters
[0]);
699 IBaseFilter_Release(filters
[0]);
701 hr
= IEnumFilters_Next(enum1
, 1, filters
, &count
);
702 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
703 ok(count
== 0, "Got count %u.\n", count
);
705 hr
= IEnumFilters_Reset(enum1
);
706 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
708 hr
= IEnumFilters_Next(enum1
, 2, filters
, &count
);
709 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
710 ok(count
== 2, "Got count %u.\n", count
);
711 ok(filters
[0] == filter2
, "Got filter %p.\n", filters
[0]);
712 ok(filters
[1] == filter1
, "Got filter %p.\n", filters
[1]);
713 IBaseFilter_Release(filters
[0]);
714 IBaseFilter_Release(filters
[1]);
716 IFilterGraph2_RemoveFilter(graph
, filter1
);
717 IFilterGraph2_AddFilter(graph
, filter1
, NULL
);
719 hr
= IEnumFilters_Next(enum1
, 2, filters
, &count
);
720 ok(hr
== VFW_E_ENUM_OUT_OF_SYNC
, "Got hr %#x.\n", hr
);
722 hr
= IEnumFilters_Reset(enum1
);
723 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
725 hr
= IEnumFilters_Next(enum1
, 2, filters
, &count
);
726 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
727 ok(count
== 2, "Got count %u.\n", count
);
728 ok(filters
[0] == filter1
, "Got filter %p.\n", filters
[0]);
729 ok(filters
[1] == filter2
, "Got filter %p.\n", filters
[1]);
730 IBaseFilter_Release(filters
[0]);
731 IBaseFilter_Release(filters
[1]);
733 hr
= IEnumFilters_Reset(enum1
);
734 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
736 hr
= IEnumFilters_Clone(enum1
, &enum2
);
737 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
739 hr
= IEnumFilters_Skip(enum2
, 1);
740 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
742 hr
= IEnumFilters_Next(enum2
, 2, filters
, &count
);
743 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
744 ok(count
== 1, "Got count %u.\n", count
);
745 ok(filters
[0] == filter2
, "Got filter %p.\n", filters
[0]);
746 IBaseFilter_Release(filters
[0]);
748 hr
= IEnumFilters_Skip(enum1
, 3);
749 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
751 IEnumFilters_Release(enum2
);
752 IEnumFilters_Release(enum1
);
753 ref
= IFilterGraph2_Release(graph
);
754 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
757 static DWORD WINAPI
call_RenderFile_multithread(LPVOID lParam
)
759 WCHAR
*filename
= load_resource(L
"test.avi");
760 IFilterGraph2
*graph
= lParam
;
763 hr
= IFilterGraph2_RenderFile(graph
, filename
, NULL
);
764 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
766 rungraph(graph
, TRUE
);
771 static void test_render_with_multithread(void)
773 IFilterGraph2
*graph
;
776 CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
778 graph
= create_graph();
780 thread
= CreateThread(NULL
, 0, call_RenderFile_multithread
, graph
, 0, NULL
);
782 ok(!WaitForSingleObject(thread
, 10000), "Wait timed out.\n");
783 IFilterGraph2_Release(graph
);
799 IEnumMediaTypes IEnumMediaTypes_iface
;
800 const AM_MEDIA_TYPE
*types
;
801 unsigned int type_count
, enum_idx
;
802 AM_MEDIA_TYPE
*request_mt
, *accept_mt
;
805 HRESULT EnumMediaTypes_hr
;
806 HRESULT QueryInternalConnections_hr
;
809 static inline struct testpin
*impl_from_IEnumMediaTypes(IEnumMediaTypes
*iface
)
811 return CONTAINING_RECORD(iface
, struct testpin
, IEnumMediaTypes_iface
);
814 static HRESULT WINAPI
testenummt_QueryInterface(IEnumMediaTypes
*iface
, REFIID iid
, void **out
)
816 struct testpin
*pin
= impl_from_IEnumMediaTypes(iface
);
817 if (winetest_debug
> 1) trace("%p->QueryInterface(%s)\n", pin
, wine_dbgstr_guid(iid
));
820 return E_NOINTERFACE
;
823 static ULONG WINAPI
testenummt_AddRef(IEnumMediaTypes
*iface
)
825 struct testpin
*pin
= impl_from_IEnumMediaTypes(iface
);
826 return InterlockedIncrement(&pin
->ref
);
829 static ULONG WINAPI
testenummt_Release(IEnumMediaTypes
*iface
)
831 struct testpin
*pin
= impl_from_IEnumMediaTypes(iface
);
832 return InterlockedDecrement(&pin
->ref
);
835 static HRESULT WINAPI
testenummt_Next(IEnumMediaTypes
*iface
, ULONG count
, AM_MEDIA_TYPE
**out
, ULONG
*fetched
)
837 struct testpin
*pin
= impl_from_IEnumMediaTypes(iface
);
840 for (i
= 0; i
< count
; ++i
)
842 if (pin
->enum_idx
+ i
>= pin
->type_count
)
845 out
[i
] = CoTaskMemAlloc(sizeof(*out
[i
]));
846 *out
[i
] = pin
->types
[pin
->enum_idx
+ i
];
853 return (i
== count
) ? S_OK
: S_FALSE
;
856 static HRESULT WINAPI
testenummt_Skip(IEnumMediaTypes
*iface
, ULONG count
)
858 ok(0, "Unexpected call.\n");
862 static HRESULT WINAPI
testenummt_Reset(IEnumMediaTypes
*iface
)
864 struct testpin
*pin
= impl_from_IEnumMediaTypes(iface
);
869 static HRESULT WINAPI
testenummt_Clone(IEnumMediaTypes
*iface
, IEnumMediaTypes
**out
)
871 ok(0, "Unexpected call.\n");
875 static const IEnumMediaTypesVtbl testenummt_vtbl
=
877 testenummt_QueryInterface
,
886 static inline struct testpin
*impl_from_IPin(IPin
*iface
)
888 return CONTAINING_RECORD(iface
, struct testpin
, IPin_iface
);
891 static HRESULT WINAPI
testpin_QueryInterface(IPin
*iface
, REFIID iid
, void **out
)
893 struct testpin
*pin
= impl_from_IPin(iface
);
894 if (winetest_debug
> 1) trace("%p->QueryInterface(%s)\n", pin
, wine_dbgstr_guid(iid
));
896 if (IsEqualGUID(iid
, &IID_IUnknown
) || IsEqualGUID(iid
, &IID_IPin
))
898 *out
= &pin
->IPin_iface
;
904 return E_NOINTERFACE
;
907 static ULONG WINAPI
testpin_AddRef(IPin
*iface
)
909 struct testpin
*pin
= impl_from_IPin(iface
);
910 return InterlockedIncrement(&pin
->ref
);
913 static ULONG WINAPI
testpin_Release(IPin
*iface
)
915 struct testpin
*pin
= impl_from_IPin(iface
);
916 return InterlockedDecrement(&pin
->ref
);
919 static HRESULT WINAPI
testpin_Disconnect(IPin
*iface
)
921 struct testpin
*pin
= impl_from_IPin(iface
);
922 if (winetest_debug
> 1) trace("%p->Disconnect()\n", pin
);
927 IPin_Release(pin
->peer
);
932 static HRESULT WINAPI
testpin_ConnectedTo(IPin
*iface
, IPin
**peer
)
934 struct testpin
*pin
= impl_from_IPin(iface
);
935 if (winetest_debug
> 1) trace("%p->ConnectedTo()\n", pin
);
943 return VFW_E_NOT_CONNECTED
;
946 static HRESULT WINAPI
testpin_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*mt
)
948 ok(0, "Unexpected call.\n");
952 static HRESULT WINAPI
testpin_QueryPinInfo(IPin
*iface
, PIN_INFO
*info
)
954 struct testpin
*pin
= impl_from_IPin(iface
);
955 if (winetest_debug
> 1) trace("%p->QueryPinInfo()\n", pin
);
957 info
->pFilter
= pin
->filter
;
958 IBaseFilter_AddRef(pin
->filter
);
959 info
->dir
= pin
->dir
;
960 wcscpy(info
->achName
, pin
->name
);
965 static HRESULT WINAPI
testpin_QueryDirection(IPin
*iface
, PIN_DIRECTION
*dir
)
967 struct testpin
*pin
= impl_from_IPin(iface
);
968 if (winetest_debug
> 1) trace("%p->QueryDirection()\n", pin
);
974 static HRESULT WINAPI
testpin_QueryId(IPin
*iface
, WCHAR
**id
)
976 struct testpin
*pin
= impl_from_IPin(iface
);
977 if (winetest_debug
> 1) trace("%p->QueryId()\n", iface
);
978 *id
= CoTaskMemAlloc(11);
979 wcscpy(*id
, pin
->id
);
983 static HRESULT WINAPI
testpin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*mt
)
985 ok(0, "Unexpected call.\n");
989 static HRESULT WINAPI
testpin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**out
)
991 struct testpin
*pin
= impl_from_IPin(iface
);
992 if (winetest_debug
> 1) trace("%p->EnumMediaTypes()\n", pin
);
994 if (FAILED(pin
->EnumMediaTypes_hr
))
995 return pin
->EnumMediaTypes_hr
;
997 *out
= &pin
->IEnumMediaTypes_iface
;
998 IEnumMediaTypes_AddRef(*out
);
1003 static HRESULT WINAPI
testpin_QueryInternalConnections(IPin
*iface
, IPin
**out
, ULONG
*count
)
1005 struct testpin
*pin
= impl_from_IPin(iface
);
1006 if (winetest_debug
> 1) trace("%p->QueryInternalConnections()\n", pin
);
1009 return pin
->QueryInternalConnections_hr
;
1012 static HRESULT WINAPI
testpin_BeginFlush(IPin
*iface
)
1014 ok(0, "Unexpected call.\n");
1018 static HRESULT WINAPI
testpin_EndFlush(IPin
* iface
)
1020 ok(0, "Unexpected call.\n");
1024 static HRESULT WINAPI
testpin_NewSegment(IPin
*iface
, REFERENCE_TIME start
, REFERENCE_TIME stop
, double rate
)
1026 ok(0, "Unexpected call.\n");
1030 static HRESULT WINAPI
testpin_EndOfStream(IPin
*iface
)
1032 ok(0, "Unexpected call.\n");
1036 static HRESULT WINAPI
no_Connect(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
1038 ok(0, "Unexpected call.\n");
1042 static HRESULT WINAPI
no_ReceiveConnection(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
1044 ok(0, "Unexpected call.\n");
1048 static HRESULT WINAPI
no_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**out
)
1050 ok(0, "Unexpected call.\n");
1054 static HRESULT WINAPI
testsink_ReceiveConnection(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
1056 struct testpin
*pin
= impl_from_IPin(iface
);
1057 if (winetest_debug
> 1) trace("%p->ReceiveConnection(%p)\n", pin
, peer
);
1059 if (pin
->accept_mt
&& memcmp(pin
->accept_mt
, mt
, sizeof(*mt
)))
1060 return VFW_E_TYPE_NOT_ACCEPTED
;
1067 static const IPinVtbl testsink_vtbl
=
1069 testpin_QueryInterface
,
1073 testsink_ReceiveConnection
,
1075 testpin_ConnectedTo
,
1076 testpin_ConnectionMediaType
,
1077 testpin_QueryPinInfo
,
1078 testpin_QueryDirection
,
1080 testpin_QueryAccept
,
1082 testpin_QueryInternalConnections
,
1083 testpin_EndOfStream
,
1089 static void testpin_init(struct testpin
*pin
, const IPinVtbl
*vtbl
, PIN_DIRECTION dir
)
1091 memset(pin
, 0, sizeof(*pin
));
1092 pin
->IPin_iface
.lpVtbl
= vtbl
;
1093 pin
->IEnumMediaTypes_iface
.lpVtbl
= &testenummt_vtbl
;
1096 pin
->Connect_hr
= S_OK
;
1097 pin
->EnumMediaTypes_hr
= S_OK
;
1098 pin
->QueryInternalConnections_hr
= E_NOTIMPL
;
1101 static void testsink_init(struct testpin
*pin
)
1103 testpin_init(pin
, &testsink_vtbl
, PINDIR_INPUT
);
1106 static HRESULT WINAPI
testsource_Connect(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
1108 struct testpin
*pin
= impl_from_IPin(iface
);
1110 if (winetest_debug
> 1) trace("%p->Connect(%p)\n", pin
, peer
);
1112 if (FAILED(pin
->Connect_hr
))
1113 return pin
->Connect_hr
;
1115 ok(!mt
, "Got media type %p.\n", mt
);
1117 if (SUCCEEDED(hr
= IPin_ReceiveConnection(peer
, &pin
->IPin_iface
, pin
->request_mt
)))
1121 return pin
->Connect_hr
;
1126 static const IPinVtbl testsource_vtbl
=
1128 testpin_QueryInterface
,
1132 no_ReceiveConnection
,
1134 testpin_ConnectedTo
,
1135 testpin_ConnectionMediaType
,
1136 testpin_QueryPinInfo
,
1137 testpin_QueryDirection
,
1139 testpin_QueryAccept
,
1140 testpin_EnumMediaTypes
,
1141 testpin_QueryInternalConnections
,
1142 testpin_EndOfStream
,
1148 static void testsource_init(struct testpin
*pin
, const AM_MEDIA_TYPE
*types
, int type_count
)
1150 testpin_init(pin
, &testsource_vtbl
, PINDIR_OUTPUT
);
1152 pin
->type_count
= type_count
;
1157 IBaseFilter IBaseFilter_iface
;
1159 IFilterGraph
*graph
;
1161 IReferenceClock
*clock
;
1163 REFERENCE_TIME start_time
;
1165 IEnumPins IEnumPins_iface
;
1166 struct testpin
*pins
;
1167 unsigned int pin_count
, enum_idx
;
1169 HRESULT state_hr
, seek_hr
;
1171 IAMFilterMiscFlags IAMFilterMiscFlags_iface
;
1174 IMediaSeeking IMediaSeeking_iface
;
1177 BOOL support_testguid
;
1178 LONGLONG seek_duration
, seek_current
, seek_stop
;
1181 IReferenceClock IReferenceClock_iface
;
1183 IFileSourceFilter IFileSourceFilter_iface
;
1184 WCHAR filename
[MAX_PATH
];
1187 static inline struct testfilter
*impl_from_IEnumPins(IEnumPins
*iface
)
1189 return CONTAINING_RECORD(iface
, struct testfilter
, IEnumPins_iface
);
1192 static HRESULT WINAPI
testenumpins_QueryInterface(IEnumPins
*iface
, REFIID iid
, void **out
)
1194 ok(0, "Unexpected iid %s.\n", wine_dbgstr_guid(iid
));
1195 return E_NOINTERFACE
;
1198 static ULONG WINAPI
testenumpins_AddRef(IEnumPins
* iface
)
1200 struct testfilter
*filter
= impl_from_IEnumPins(iface
);
1201 return InterlockedIncrement(&filter
->ref
);
1204 static ULONG WINAPI
testenumpins_Release(IEnumPins
* iface
)
1206 struct testfilter
*filter
= impl_from_IEnumPins(iface
);
1207 return InterlockedDecrement(&filter
->ref
);
1210 static HRESULT WINAPI
testenumpins_Next(IEnumPins
*iface
, ULONG count
, IPin
**out
, ULONG
*fetched
)
1212 struct testfilter
*filter
= impl_from_IEnumPins(iface
);
1215 for (i
= 0; i
< count
; ++i
)
1217 if (filter
->enum_idx
+ i
>= filter
->pin_count
)
1220 out
[i
] = &filter
->pins
[filter
->enum_idx
+ i
].IPin_iface
;
1221 IPin_AddRef(out
[i
]);
1226 filter
->enum_idx
+= i
;
1228 return (i
== count
) ? S_OK
: S_FALSE
;
1231 static HRESULT WINAPI
testenumpins_Skip(IEnumPins
*iface
, ULONG count
)
1233 ok(0, "Unexpected call.\n");
1237 static HRESULT WINAPI
testenumpins_Reset(IEnumPins
*iface
)
1239 struct testfilter
*filter
= impl_from_IEnumPins(iface
);
1240 filter
->enum_idx
= 0;
1244 static HRESULT WINAPI
testenumpins_Clone(IEnumPins
*iface
, IEnumPins
**out
)
1246 ok(0, "Unexpected call.\n");
1250 static const IEnumPinsVtbl testenumpins_vtbl
=
1252 testenumpins_QueryInterface
,
1253 testenumpins_AddRef
,
1254 testenumpins_Release
,
1261 static inline struct testfilter
*impl_from_IBaseFilter(IBaseFilter
*iface
)
1263 return CONTAINING_RECORD(iface
, struct testfilter
, IBaseFilter_iface
);
1266 static HRESULT WINAPI
testfilter_QueryInterface(IBaseFilter
*iface
, REFIID iid
, void **out
)
1268 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1269 if (winetest_debug
> 1) trace("%p->QueryInterface(%s)\n", filter
, wine_dbgstr_guid(iid
));
1271 if (IsEqualGUID(iid
, &IID_IUnknown
)
1272 || IsEqualGUID(iid
, &IID_IPersist
)
1273 || IsEqualGUID(iid
, &IID_IMediaFilter
)
1274 || IsEqualGUID(iid
, &IID_IBaseFilter
))
1276 *out
= &filter
->IBaseFilter_iface
;
1278 else if (IsEqualGUID(iid
, &IID_IAMFilterMiscFlags
) && filter
->IAMFilterMiscFlags_iface
.lpVtbl
)
1280 *out
= &filter
->IAMFilterMiscFlags_iface
;
1282 else if (IsEqualGUID(iid
, &IID_IMediaSeeking
) && filter
->IMediaSeeking_iface
.lpVtbl
)
1284 *out
= &filter
->IMediaSeeking_iface
;
1286 else if (IsEqualGUID(iid
, &IID_IReferenceClock
) && filter
->IReferenceClock_iface
.lpVtbl
)
1288 *out
= &filter
->IReferenceClock_iface
;
1290 else if (IsEqualGUID(iid
, &IID_IFileSourceFilter
) && filter
->IFileSourceFilter_iface
.lpVtbl
)
1292 *out
= &filter
->IFileSourceFilter_iface
;
1297 return E_NOINTERFACE
;
1300 IUnknown_AddRef((IUnknown
*)*out
);
1304 static ULONG WINAPI
testfilter_AddRef(IBaseFilter
*iface
)
1306 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1307 return InterlockedIncrement(&filter
->ref
);
1310 static ULONG WINAPI
testfilter_Release(IBaseFilter
*iface
)
1312 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1313 return InterlockedDecrement(&filter
->ref
);
1316 static HRESULT WINAPI
testfilter_GetClassID(IBaseFilter
*iface
, CLSID
*clsid
)
1318 if (winetest_debug
> 1) trace("%p->GetClassID()\n", iface
);
1319 memset(clsid
, 0xde, sizeof(*clsid
));
1323 /* Downstream filters are always stopped before any filters they are connected
1324 * to upstream. Native actually implements this by topologically sorting filters
1325 * as they are connected. */
1326 static void check_state_transition(struct testfilter
*filter
, FILTER_STATE expect
)
1332 for (i
= 0; i
< filter
->pin_count
; ++i
)
1334 if (filter
->pins
[i
].peer
)
1336 IPin_QueryPinInfo(filter
->pins
[i
].peer
, &info
);
1337 IBaseFilter_GetState(info
.pFilter
, 0, &state
);
1338 if (filter
->pins
[i
].dir
== PINDIR_OUTPUT
)
1339 ok(state
== expect
, "Expected state %d for downstream filter %p, got %d.\n",
1340 expect
, info
.pFilter
, state
);
1342 ok(state
== filter
->state
, "Expected state %d for upstream filter %p, got %d.\n",
1343 filter
->state
, info
.pFilter
, state
);
1344 IBaseFilter_Release(info
.pFilter
);
1349 static HRESULT WINAPI
testfilter_Stop(IBaseFilter
*iface
)
1351 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1352 if (winetest_debug
> 1) trace("%p->Stop()\n", filter
);
1354 check_state_transition(filter
, State_Stopped
);
1356 filter
->state
= State_Stopped
;
1357 return filter
->state_hr
;
1360 static HRESULT WINAPI
testfilter_Pause(IBaseFilter
*iface
)
1362 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1363 if (winetest_debug
> 1) trace("%p->Pause()\n", filter
);
1365 check_state_transition(filter
, State_Paused
);
1367 filter
->state
= State_Paused
;
1368 return filter
->state_hr
;
1371 static HRESULT WINAPI
testfilter_Run(IBaseFilter
*iface
, REFERENCE_TIME start
)
1373 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1374 if (winetest_debug
> 1) trace("%p->Run(%s)\n", filter
, wine_dbgstr_longlong(start
));
1376 check_state_transition(filter
, State_Running
);
1378 filter
->state
= State_Running
;
1379 filter
->start_time
= start
;
1380 return filter
->state_hr
;
1383 static HRESULT WINAPI
testfilter_GetState(IBaseFilter
*iface
, DWORD timeout
, FILTER_STATE
*state
)
1385 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1386 if (winetest_debug
> 1) trace("%p->GetState(%u)\n", filter
, timeout
);
1388 *state
= filter
->state
;
1389 return filter
->state_hr
;
1392 static HRESULT WINAPI
testfilter_SetSyncSource(IBaseFilter
*iface
, IReferenceClock
*clock
)
1394 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1395 if (winetest_debug
> 1) trace("%p->SetSyncSource(%p)\n", filter
, clock
);
1398 IReferenceClock_Release(filter
->clock
);
1400 IReferenceClock_AddRef(clock
);
1401 filter
->clock
= clock
;
1405 static HRESULT WINAPI
testfilter_GetSyncSource(IBaseFilter
*iface
, IReferenceClock
**clock
)
1407 ok(0, "Unexpected call.\n");
1411 static HRESULT WINAPI
testfilter_EnumPins(IBaseFilter
*iface
, IEnumPins
**out
)
1413 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1414 if (winetest_debug
> 1) trace("%p->EnumPins()\n", filter
);
1416 *out
= &filter
->IEnumPins_iface
;
1417 IEnumPins_AddRef(*out
);
1418 filter
->enum_idx
= 0;
1422 static HRESULT WINAPI
testfilter_FindPin(IBaseFilter
*iface
, const WCHAR
*id
, IPin
**pin
)
1424 ok(0, "Unexpected call.\n");
1428 static HRESULT WINAPI
testfilter_QueryFilterInfo(IBaseFilter
*iface
, FILTER_INFO
*info
)
1430 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1431 if (winetest_debug
> 1) trace("%p->QueryFilterInfo()\n", filter
);
1433 info
->pGraph
= filter
->graph
;
1435 IFilterGraph_AddRef(filter
->graph
);
1437 wcscpy(info
->achName
, filter
->name
);
1439 info
->achName
[0] = 0;
1443 static HRESULT WINAPI
testfilter_JoinFilterGraph(IBaseFilter
*iface
, IFilterGraph
*graph
, const WCHAR
*name
)
1445 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1446 if (winetest_debug
> 1) trace("%p->JoinFilterGraph(%p, %s)\n", filter
, graph
, wine_dbgstr_w(name
));
1448 filter
->graph
= graph
;
1449 heap_free(filter
->name
);
1452 filter
->name
= heap_alloc((wcslen(name
) + 1) * sizeof(WCHAR
));
1453 wcscpy(filter
->name
, name
);
1456 filter
->name
= NULL
;
1460 static HRESULT WINAPI
testfilter_QueryVendorInfo(IBaseFilter
* iface
, WCHAR
**info
)
1465 static const IBaseFilterVtbl testfilter_vtbl
=
1467 testfilter_QueryInterface
,
1470 testfilter_GetClassID
,
1474 testfilter_GetState
,
1475 testfilter_SetSyncSource
,
1476 testfilter_GetSyncSource
,
1477 testfilter_EnumPins
,
1479 testfilter_QueryFilterInfo
,
1480 testfilter_JoinFilterGraph
,
1481 testfilter_QueryVendorInfo
1484 static struct testfilter
*impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags
*iface
)
1486 return CONTAINING_RECORD(iface
, struct testfilter
, IAMFilterMiscFlags_iface
);
1489 static HRESULT WINAPI
testmiscflags_QueryInterface(IAMFilterMiscFlags
*iface
, REFIID iid
, void **out
)
1491 struct testfilter
*filter
= impl_from_IAMFilterMiscFlags(iface
);
1492 return IBaseFilter_QueryInterface(&filter
->IBaseFilter_iface
, iid
, out
);
1495 static ULONG WINAPI
testmiscflags_AddRef(IAMFilterMiscFlags
*iface
)
1497 struct testfilter
*filter
= impl_from_IAMFilterMiscFlags(iface
);
1498 return InterlockedIncrement(&filter
->ref
);
1501 static ULONG WINAPI
testmiscflags_Release(IAMFilterMiscFlags
*iface
)
1503 struct testfilter
*filter
= impl_from_IAMFilterMiscFlags(iface
);
1504 return InterlockedDecrement(&filter
->ref
);
1507 static ULONG WINAPI
testmiscflags_GetMiscFlags(IAMFilterMiscFlags
*iface
)
1509 struct testfilter
*filter
= impl_from_IAMFilterMiscFlags(iface
);
1510 if (winetest_debug
> 1) trace("%p->GetMiscFlags()\n", filter
);
1511 return filter
->misc_flags
;
1514 static const IAMFilterMiscFlagsVtbl testmiscflags_vtbl
=
1516 testmiscflags_QueryInterface
,
1517 testmiscflags_AddRef
,
1518 testmiscflags_Release
,
1519 testmiscflags_GetMiscFlags
,
1522 static struct testfilter
*impl_from_IMediaSeeking(IMediaSeeking
*iface
)
1524 return CONTAINING_RECORD(iface
, struct testfilter
, IMediaSeeking_iface
);
1527 static HRESULT WINAPI
testseek_QueryInterface(IMediaSeeking
*iface
, REFIID iid
, void **out
)
1529 struct testfilter
*filter
= impl_from_IMediaSeeking(iface
);
1530 return IBaseFilter_QueryInterface(&filter
->IBaseFilter_iface
, iid
, out
);
1533 static ULONG WINAPI
testseek_AddRef(IMediaSeeking
*iface
)
1535 struct testfilter
*filter
= impl_from_IMediaSeeking(iface
);
1536 InterlockedIncrement(&filter
->seeking_ref
);
1537 return InterlockedIncrement(&filter
->ref
);
1540 static ULONG WINAPI
testseek_Release(IMediaSeeking
*iface
)
1542 struct testfilter
*filter
= impl_from_IMediaSeeking(iface
);
1543 InterlockedDecrement(&filter
->seeking_ref
);
1544 return InterlockedDecrement(&filter
->ref
);
1547 static HRESULT WINAPI
testseek_GetCapabilities(IMediaSeeking
*iface
, DWORD
*caps
)
1549 struct testfilter
*filter
= impl_from_IMediaSeeking(iface
);
1550 if (winetest_debug
> 1) trace("%p->GetCapabilities()\n", iface
);
1551 *caps
= filter
->seek_caps
;
1555 static HRESULT WINAPI
testseek_CheckCapabilities(IMediaSeeking
*iface
, DWORD
*caps
)
1557 ok(0, "Unexpected call.\n");
1561 static HRESULT WINAPI
testseek_IsFormatSupported(IMediaSeeking
*iface
, const GUID
*format
)
1563 struct testfilter
*filter
= impl_from_IMediaSeeking(iface
);
1564 if (winetest_debug
> 1) trace("%p->IsFormatSupported(%s)\n", iface
, wine_dbgstr_guid(format
));
1565 if (IsEqualGUID(format
, &testguid
) && !filter
->support_testguid
)
1570 static HRESULT WINAPI
testseek_QueryPreferredFormat(IMediaSeeking
*iface
, GUID
*format
)
1572 if (winetest_debug
> 1) trace("%p->QueryPreferredFormat()\n", iface
);
1576 static HRESULT WINAPI
testseek_GetTimeFormat(IMediaSeeking
*iface
, GUID
*format
)
1578 ok(0, "Unexpected call.\n");
1582 static HRESULT WINAPI
testseek_IsUsingTimeFormat(IMediaSeeking
*iface
, const GUID
*format
)
1584 if (winetest_debug
> 1) trace("%p->IsUsingTimeFormat(%s)\n", iface
, wine_dbgstr_guid(format
));
1588 static HRESULT WINAPI
testseek_SetTimeFormat(IMediaSeeking
*iface
, const GUID
*format
)
1590 struct testfilter
*filter
= impl_from_IMediaSeeking(iface
);
1591 if (winetest_debug
> 1) trace("%p->SetTimeFormat(%s)\n", iface
, wine_dbgstr_guid(format
));
1592 if (IsEqualGUID(format
, &testguid
) && !filter
->support_testguid
)
1593 return E_INVALIDARG
;
1597 static HRESULT WINAPI
testseek_GetDuration(IMediaSeeking
*iface
, LONGLONG
*duration
)
1599 struct testfilter
*filter
= impl_from_IMediaSeeking(iface
);
1600 if (winetest_debug
> 1) trace("%p->GetDuration()\n", iface
);
1601 *duration
= filter
->seek_duration
;
1605 static HRESULT WINAPI
testseek_GetStopPosition(IMediaSeeking
*iface
, LONGLONG
*stop
)
1607 struct testfilter
*filter
= impl_from_IMediaSeeking(iface
);
1608 if (winetest_debug
> 1) trace("%p->GetStopPosition()\n", iface
);
1609 *stop
= filter
->seek_stop
;
1610 return filter
->seek_hr
;
1613 static HRESULT WINAPI
testseek_GetCurrentPosition(IMediaSeeking
*iface
, LONGLONG
*current
)
1615 struct testfilter
*filter
= impl_from_IMediaSeeking(iface
);
1616 if (winetest_debug
> 1) trace("%p->GetCurrentPosition()\n", iface
);
1617 ok(!filter
->clock
, "GetCurrentPosition() should only be called if there is no sync source.\n");
1618 *current
= 0xdeadbeef;
1622 static HRESULT WINAPI
testseek_ConvertTimeFormat(IMediaSeeking
*iface
, LONGLONG
*target
,
1623 const GUID
*target_format
, LONGLONG source
, const GUID
*source_format
)
1625 ok(0, "Unexpected call.\n");
1629 static HRESULT WINAPI
testseek_SetPositions(IMediaSeeking
*iface
, LONGLONG
*current
,
1630 DWORD current_flags
, LONGLONG
*stop
, DWORD stop_flags
)
1632 struct testfilter
*filter
= impl_from_IMediaSeeking(iface
);
1633 if (winetest_debug
> 1) trace("%p->SetPositions(%s, %#x, %s, %#x)\n",
1634 iface
, wine_dbgstr_longlong(*current
), current_flags
, wine_dbgstr_longlong(*stop
), stop_flags
);
1635 ok(filter
->state
!= State_Running
, "Filter should be paused or stopped while seeking.\n");
1636 filter
->seek_current
= *current
;
1637 filter
->seek_stop
= *stop
;
1638 *current
= 12340000;
1640 return filter
->seek_hr
;
1643 static HRESULT WINAPI
testseek_GetPositions(IMediaSeeking
*iface
, LONGLONG
*current
, LONGLONG
*stop
)
1645 ok(0, "Unexpected call.\n");
1649 static HRESULT WINAPI
testseek_GetAvailable(IMediaSeeking
*iface
, LONGLONG
*earliest
, LONGLONG
*latest
)
1651 ok(0, "Unexpected call.\n");
1655 static HRESULT WINAPI
testseek_SetRate(IMediaSeeking
*iface
, double rate
)
1657 struct testfilter
*filter
= impl_from_IMediaSeeking(iface
);
1658 if (winetest_debug
> 1) trace("%p->SetRate(%.16e)\n", iface
, rate
);
1659 filter
->seek_rate
= rate
;
1663 static HRESULT WINAPI
testseek_GetRate(IMediaSeeking
*iface
, double *rate
)
1665 ok(0, "Unexpected call.\n");
1669 static HRESULT WINAPI
testseek_GetPreroll(IMediaSeeking
*iface
, LONGLONG
*preroll
)
1671 if (winetest_debug
> 1) trace("%p->GetPreroll()\n", iface
);
1675 static const IMediaSeekingVtbl testseek_vtbl
=
1677 testseek_QueryInterface
,
1680 testseek_GetCapabilities
,
1681 testseek_CheckCapabilities
,
1682 testseek_IsFormatSupported
,
1683 testseek_QueryPreferredFormat
,
1684 testseek_GetTimeFormat
,
1685 testseek_IsUsingTimeFormat
,
1686 testseek_SetTimeFormat
,
1687 testseek_GetDuration
,
1688 testseek_GetStopPosition
,
1689 testseek_GetCurrentPosition
,
1690 testseek_ConvertTimeFormat
,
1691 testseek_SetPositions
,
1692 testseek_GetPositions
,
1693 testseek_GetAvailable
,
1696 testseek_GetPreroll
,
1699 static struct testfilter
*impl_from_IReferenceClock(IReferenceClock
*iface
)
1701 return CONTAINING_RECORD(iface
, struct testfilter
, IReferenceClock_iface
);
1704 static HRESULT WINAPI
testclock_QueryInterface(IReferenceClock
*iface
, REFIID iid
, void **out
)
1706 struct testfilter
*filter
= impl_from_IReferenceClock(iface
);
1707 return IBaseFilter_QueryInterface(&filter
->IBaseFilter_iface
, iid
, out
);
1710 static ULONG WINAPI
testclock_AddRef(IReferenceClock
*iface
)
1712 struct testfilter
*filter
= impl_from_IReferenceClock(iface
);
1713 return InterlockedIncrement(&filter
->ref
);
1716 static ULONG WINAPI
testclock_Release(IReferenceClock
*iface
)
1718 struct testfilter
*filter
= impl_from_IReferenceClock(iface
);
1719 return InterlockedDecrement(&filter
->ref
);
1722 static HRESULT WINAPI
testclock_GetTime(IReferenceClock
*iface
, REFERENCE_TIME
*time
)
1724 ok(0, "Unexpected call.\n");
1728 static HRESULT WINAPI
testclock_AdviseTime(IReferenceClock
*iface
,
1729 REFERENCE_TIME base
, REFERENCE_TIME offset
, HEVENT event
, DWORD_PTR
*cookie
)
1731 ok(0, "Unexpected call.\n");
1735 static HRESULT WINAPI
testclock_AdvisePeriodic(IReferenceClock
*iface
,
1736 REFERENCE_TIME start
, REFERENCE_TIME period
, HSEMAPHORE semaphore
, DWORD_PTR
*cookie
)
1738 ok(0, "Unexpected call.\n");
1742 static HRESULT WINAPI
testclock_Unadvise(IReferenceClock
*iface
, DWORD_PTR cookie
)
1744 ok(0, "Unexpected call.\n");
1748 static const IReferenceClockVtbl testclock_vtbl
=
1750 testclock_QueryInterface
,
1754 testclock_AdviseTime
,
1755 testclock_AdvisePeriodic
,
1759 static struct testfilter
*impl_from_IFileSourceFilter(IFileSourceFilter
*iface
)
1761 return CONTAINING_RECORD(iface
, struct testfilter
, IFileSourceFilter_iface
);
1764 static HRESULT WINAPI
testfilesource_QueryInterface(IFileSourceFilter
*iface
, REFIID iid
, void **out
)
1766 struct testfilter
*filter
= impl_from_IFileSourceFilter(iface
);
1767 return IBaseFilter_QueryInterface(&filter
->IBaseFilter_iface
, iid
, out
);
1770 static ULONG WINAPI
testfilesource_AddRef(IFileSourceFilter
*iface
)
1772 struct testfilter
*filter
= impl_from_IFileSourceFilter(iface
);
1773 return InterlockedIncrement(&filter
->ref
);
1776 static ULONG WINAPI
testfilesource_Release(IFileSourceFilter
*iface
)
1778 struct testfilter
*filter
= impl_from_IFileSourceFilter(iface
);
1779 return InterlockedDecrement(&filter
->ref
);
1782 static HRESULT WINAPI
testfilesource_Load(IFileSourceFilter
*iface
,
1783 const WCHAR
*filename
, const AM_MEDIA_TYPE
*mt
)
1785 struct testfilter
*filter
= impl_from_IFileSourceFilter(iface
);
1786 if (winetest_debug
> 1) trace("%p->Load()\n", iface
);
1788 wcscpy(filter
->filename
, filename
);
1793 static HRESULT WINAPI
testfilesource_GetCurFile(IFileSourceFilter
*iface
,
1794 WCHAR
**filename
, AM_MEDIA_TYPE
*mt
)
1796 ok(0, "Unexpected call.\n");
1800 static const IFileSourceFilterVtbl testfilesource_vtbl
=
1802 testfilesource_QueryInterface
,
1803 testfilesource_AddRef
,
1804 testfilesource_Release
,
1805 testfilesource_Load
,
1806 testfilesource_GetCurFile
,
1809 struct testfilter_cf
1811 IClassFactory IClassFactory_iface
;
1812 struct testfilter
*filter
;
1815 static void testfilter_init(struct testfilter
*filter
, struct testpin
*pins
, int pin_count
)
1819 memset(filter
, 0, sizeof(*filter
));
1820 filter
->IBaseFilter_iface
.lpVtbl
= &testfilter_vtbl
;
1821 filter
->IEnumPins_iface
.lpVtbl
= &testenumpins_vtbl
;
1823 filter
->pins
= pins
;
1824 filter
->pin_count
= pin_count
;
1825 for (i
= 0; i
< pin_count
; i
++)
1826 pins
[i
].filter
= &filter
->IBaseFilter_iface
;
1827 filter
->state
= State_Stopped
;
1830 static HRESULT WINAPI
testfilter_cf_QueryInterface(IClassFactory
*iface
, REFIID iid
, void **out
)
1832 if (IsEqualGUID(iid
, &IID_IUnknown
) || IsEqualGUID(iid
, &IID_IClassFactory
))
1839 return E_NOINTERFACE
;
1842 static ULONG WINAPI
testfilter_cf_AddRef(IClassFactory
*iface
)
1847 static ULONG WINAPI
testfilter_cf_Release(IClassFactory
*iface
)
1852 static HRESULT WINAPI
testfilter_cf_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID iid
, void **out
)
1854 struct testfilter_cf
*factory
= CONTAINING_RECORD(iface
, struct testfilter_cf
, IClassFactory_iface
);
1856 return IBaseFilter_QueryInterface(&factory
->filter
->IBaseFilter_iface
, iid
, out
);
1859 static HRESULT WINAPI
testfilter_cf_LockServer(IClassFactory
*iface
, BOOL lock
)
1864 static IClassFactoryVtbl testfilter_cf_vtbl
=
1866 testfilter_cf_QueryInterface
,
1867 testfilter_cf_AddRef
,
1868 testfilter_cf_Release
,
1869 testfilter_cf_CreateInstance
,
1870 testfilter_cf_LockServer
,
1873 static void test_graph_builder_render(void)
1875 static const GUID sink1_clsid
= {0x12345678};
1876 static const GUID sink2_clsid
= {0x87654321};
1877 AM_MEDIA_TYPE source_type
= {{0}};
1878 struct testpin source_pin
, sink1_pin
, sink2_pin
, parser_pins
[2];
1879 struct testfilter source
, sink1
, sink2
, parser
;
1880 struct testfilter_cf sink1_cf
= { {&testfilter_cf_vtbl
}, &sink1
};
1881 struct testfilter_cf sink2_cf
= { {&testfilter_cf_vtbl
}, &sink2
};
1883 IFilterGraph2
*graph
= create_graph();
1884 REGFILTERPINS2 regpins
= {0};
1885 REGPINTYPES regtypes
= {0};
1886 REGFILTER2 regfilter
= {0};
1887 IFilterMapper2
*mapper
;
1888 DWORD cookie1
, cookie2
;
1892 memset(&source_type
.majortype
, 0xcc, sizeof(GUID
));
1893 testsource_init(&source_pin
, &source_type
, 1);
1894 testfilter_init(&source
, &source_pin
, 1);
1895 testsink_init(&sink1_pin
);
1896 testfilter_init(&sink1
, &sink1_pin
, 1);
1897 testsink_init(&sink2_pin
);
1898 testfilter_init(&sink2
, &sink2_pin
, 1);
1899 testsink_init(&parser_pins
[0]);
1900 testsource_init(&parser_pins
[1], &source_type
, 1);
1901 testfilter_init(&parser
, parser_pins
, 2);
1903 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
1904 IFilterGraph2_AddFilter(graph
, &sink1
.IBaseFilter_iface
, NULL
);
1905 IFilterGraph2_AddFilter(graph
, &sink2
.IBaseFilter_iface
, NULL
);
1907 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1908 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1909 ok(source_pin
.peer
== &sink2_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1910 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
1911 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1913 IFilterGraph2_RemoveFilter(graph
, &sink1
.IBaseFilter_iface
);
1914 IFilterGraph2_AddFilter(graph
, &sink1
.IBaseFilter_iface
, NULL
);
1916 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1917 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1918 ok(source_pin
.peer
== &sink1_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1920 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1921 IFilterGraph2_Disconnect(graph
, &sink1_pin
.IPin_iface
);
1923 /* No preference is given to smaller chains. */
1925 IFilterGraph2_AddFilter(graph
, &parser
.IBaseFilter_iface
, NULL
);
1927 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1928 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1929 ok(source_pin
.peer
== &parser_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1930 ok(parser_pins
[1].peer
== &sink1_pin
.IPin_iface
, "Got peer %p.\n", parser_pins
[1].peer
);
1931 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
1932 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1933 IFilterGraph2_Disconnect(graph
, parser_pins
[0].peer
);
1934 IFilterGraph2_Disconnect(graph
, &parser_pins
[0].IPin_iface
);
1936 IFilterGraph2_RemoveFilter(graph
, &sink1
.IBaseFilter_iface
);
1937 IFilterGraph2_AddFilter(graph
, &sink1
.IBaseFilter_iface
, NULL
);
1939 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1940 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1941 ok(source_pin
.peer
== &sink1_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1942 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
1943 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1945 /* A pin whose name (not ID) begins with a tilde is not rendered. */
1947 IFilterGraph2_RemoveFilter(graph
, &sink2
.IBaseFilter_iface
);
1948 IFilterGraph2_RemoveFilter(graph
, &parser
.IBaseFilter_iface
);
1949 IFilterGraph2_AddFilter(graph
, &parser
.IBaseFilter_iface
, NULL
);
1951 parser_pins
[1].name
[0] = '~';
1952 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1953 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1954 ok(source_pin
.peer
== &parser_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1955 ok(!parser_pins
[1].peer
, "Got peer %p.\n", parser_pins
[1].peer
);
1956 ok(!sink1_pin
.peer
, "Got peer %p.\n", sink1_pin
.peer
);
1957 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
1958 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1960 parser_pins
[1].name
[0] = 0;
1961 parser_pins
[1].id
[0] = '~';
1962 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1963 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1964 ok(source_pin
.peer
== &parser_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1965 ok(parser_pins
[1].peer
== &sink1_pin
.IPin_iface
, "Got peer %p.\n", parser_pins
[1].peer
);
1966 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
1967 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1969 ref
= IFilterGraph2_Release(graph
);
1970 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1972 /* Test enumeration of filters from the registry. */
1974 graph
= create_graph();
1975 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
1977 CoRegisterClassObject(&sink1_clsid
, (IUnknown
*)&sink1_cf
.IClassFactory_iface
,
1978 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie1
);
1979 CoRegisterClassObject(&sink2_clsid
, (IUnknown
*)&sink2_cf
.IClassFactory_iface
,
1980 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie2
);
1982 CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
,
1983 &IID_IFilterMapper2
, (void **)&mapper
);
1985 regfilter
.dwVersion
= 2;
1986 regfilter
.dwMerit
= MERIT_UNLIKELY
;
1987 regfilter
.cPins2
= 1;
1988 regfilter
.rgPins2
= ®pins
;
1989 regpins
.dwFlags
= 0;
1990 regpins
.cInstances
= 1;
1991 regpins
.nMediaTypes
= 1;
1992 regpins
.lpMediaType
= ®types
;
1993 regtypes
.clsMajorType
= &source_type
.majortype
;
1994 regtypes
.clsMinorType
= &MEDIASUBTYPE_NULL
;
1995 hr
= IFilterMapper2_RegisterFilter(mapper
, &sink1_clsid
, L
"test", NULL
, NULL
, NULL
, ®filter
);
1996 if (hr
== E_ACCESSDENIED
)
1998 skip("Not enough permission to register filters.\n");
2001 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2003 regpins
.dwFlags
= REG_PINFLAG_B_RENDERER
;
2004 IFilterMapper2_RegisterFilter(mapper
, &sink2_clsid
, L
"test", NULL
, NULL
, NULL
, ®filter
);
2006 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
2007 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2008 ok(source_pin
.peer
== &sink2_pin
.IPin_iface
|| source_pin
.peer
== &sink1_pin
.IPin_iface
,
2009 "Got peer %p.\n", source_pin
.peer
);
2011 ref
= IFilterGraph2_Release(graph
);
2012 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2014 /* Preference is given to filters already in the graph. */
2016 graph
= create_graph();
2017 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
2018 IFilterGraph2_AddFilter(graph
, &sink2
.IBaseFilter_iface
, NULL
);
2020 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
2021 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2022 ok(source_pin
.peer
== &sink2_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2024 ref
= IFilterGraph2_Release(graph
);
2025 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2027 /* No preference is given to renderer filters. */
2029 graph
= create_graph();
2030 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
2032 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink1_clsid
);
2033 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink2_clsid
);
2035 IFilterMapper2_RegisterFilter(mapper
, &sink1_clsid
, L
"test", NULL
, NULL
, NULL
, ®filter
);
2036 regpins
.dwFlags
= 0;
2037 IFilterMapper2_RegisterFilter(mapper
, &sink2_clsid
, L
"test", NULL
, NULL
, NULL
, ®filter
);
2039 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
2040 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2041 ok(source_pin
.peer
== &sink2_pin
.IPin_iface
|| source_pin
.peer
== &sink1_pin
.IPin_iface
,
2042 "Got peer %p.\n", source_pin
.peer
);
2044 ref
= IFilterGraph2_Release(graph
);
2045 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2047 /* Preference is given to filters with higher merit. */
2049 graph
= create_graph();
2050 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
2052 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink1_clsid
);
2053 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink2_clsid
);
2055 regfilter
.dwMerit
= MERIT_UNLIKELY
;
2056 IFilterMapper2_RegisterFilter(mapper
, &sink1_clsid
, L
"test", NULL
, NULL
, NULL
, ®filter
);
2057 regfilter
.dwMerit
= MERIT_PREFERRED
;
2058 IFilterMapper2_RegisterFilter(mapper
, &sink2_clsid
, L
"test", NULL
, NULL
, NULL
, ®filter
);
2060 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
2061 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2062 ok(source_pin
.peer
== &sink2_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2064 ref
= IFilterGraph2_Release(graph
);
2065 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2067 graph
= create_graph();
2068 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
2070 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink1_clsid
);
2071 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink2_clsid
);
2073 regfilter
.dwMerit
= MERIT_PREFERRED
;
2074 IFilterMapper2_RegisterFilter(mapper
, &sink1_clsid
, L
"test", NULL
, NULL
, NULL
, ®filter
);
2075 regfilter
.dwMerit
= MERIT_UNLIKELY
;
2076 IFilterMapper2_RegisterFilter(mapper
, &sink2_clsid
, L
"test", NULL
, NULL
, NULL
, ®filter
);
2078 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
2079 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2080 ok(source_pin
.peer
== &sink1_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2082 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink1_clsid
);
2083 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink2_clsid
);
2086 CoRevokeClassObject(cookie1
);
2087 CoRevokeClassObject(cookie2
);
2088 IFilterMapper2_Release(mapper
);
2089 ref
= IFilterGraph2_Release(graph
);
2090 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2091 ok(source
.ref
== 1, "Got outstanding refcount %d.\n", source
.ref
);
2092 ok(source_pin
.ref
== 1, "Got outstanding refcount %d.\n", source_pin
.ref
);
2093 ok(sink1
.ref
== 1, "Got outstanding refcount %d.\n", sink1
.ref
);
2094 ok(sink1_pin
.ref
== 1, "Got outstanding refcount %d.\n", sink1_pin
.ref
);
2095 ok(sink2
.ref
== 1, "Got outstanding refcount %d.\n", sink2
.ref
);
2096 ok(sink2_pin
.ref
== 1, "Got outstanding refcount %d.\n", sink2_pin
.ref
);
2097 ok(parser
.ref
== 1, "Got outstanding refcount %d.\n", parser
.ref
);
2098 ok(parser_pins
[0].ref
== 1, "Got outstanding refcount %d.\n", parser_pins
[0].ref
);
2099 ok(parser_pins
[1].ref
== 1, "Got outstanding refcount %d.\n", parser_pins
[1].ref
);
2102 static void test_graph_builder_connect(void)
2104 static const GUID parser1_clsid
= {0x12345678};
2105 static const GUID parser2_clsid
= {0x87654321};
2106 AM_MEDIA_TYPE source_type
= {{0}}, sink_type
= {{0}}, parser3_type
= {{0}};
2107 struct testpin source_pin
, sink_pin
, sink2_pin
, parser1_pins
[3], parser2_pins
[2], parser3_pins
[2];
2108 struct testfilter source
, sink
, sink2
, parser1
, parser2
, parser3
;
2109 struct testfilter_cf parser1_cf
= { {&testfilter_cf_vtbl
}, &parser1
};
2110 struct testfilter_cf parser2_cf
= { {&testfilter_cf_vtbl
}, &parser2
};
2112 IFilterGraph2
*graph
= create_graph();
2113 REGFILTERPINS2 regpins
[2] = {{0}};
2114 REGPINTYPES regtypes
= {0};
2115 REGFILTER2 regfilter
= {0};
2116 IFilterMapper2
*mapper
;
2117 DWORD cookie1
, cookie2
;
2121 memset(&source_type
.majortype
, 0xcc, sizeof(GUID
));
2122 memset(&sink_type
.majortype
, 0x66, sizeof(GUID
));
2123 testsource_init(&source_pin
, &source_type
, 1);
2124 source_pin
.request_mt
= &source_type
;
2125 testfilter_init(&source
, &source_pin
, 1);
2126 testsink_init(&sink_pin
);
2127 testfilter_init(&sink
, &sink_pin
, 1);
2128 testsink_init(&sink2_pin
);
2129 testfilter_init(&sink2
, &sink2_pin
, 1);
2131 testsink_init(&parser1_pins
[0]);
2132 testsource_init(&parser1_pins
[1], &sink_type
, 1);
2133 parser1_pins
[1].request_mt
= &sink_type
;
2134 testsource_init(&parser1_pins
[2], &sink_type
, 1);
2135 parser1_pins
[2].request_mt
= &sink_type
;
2136 testfilter_init(&parser1
, parser1_pins
, 3);
2137 parser1
.pin_count
= 2;
2139 testsink_init(&parser2_pins
[0]);
2140 testsource_init(&parser2_pins
[1], &sink_type
, 1);
2141 parser2_pins
[1].request_mt
= &sink_type
;
2142 testfilter_init(&parser2
, parser2_pins
, 2);
2144 testsink_init(&parser3_pins
[0]);
2145 testsource_init(&parser3_pins
[1], &sink_type
, 1);
2146 parser3_pins
[1].request_mt
= &parser3_type
;
2147 testfilter_init(&parser3
, parser3_pins
, 2);
2149 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
2150 IFilterGraph2_AddFilter(graph
, &sink
.IBaseFilter_iface
, NULL
);
2152 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2153 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2154 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2155 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
2156 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2158 for (source_pin
.Connect_hr
= 0x00040200; source_pin
.Connect_hr
<= 0x000402ff;
2159 ++source_pin
.Connect_hr
)
2161 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2162 ok(hr
== source_pin
.Connect_hr
, "Got hr %#x for Connect() hr %#x.\n",
2163 hr
, source_pin
.Connect_hr
);
2164 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2165 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
2166 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2168 source_pin
.Connect_hr
= S_OK
;
2170 sink_pin
.accept_mt
= &sink_type
;
2171 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2172 ok(hr
== VFW_E_CANNOT_CONNECT
, "Got hr %#x.\n", hr
);
2173 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2175 for (source_pin
.Connect_hr
= 0x80040200; source_pin
.Connect_hr
<= 0x800402ff;
2176 ++source_pin
.Connect_hr
)
2178 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2179 if (source_pin
.Connect_hr
== VFW_E_NOT_CONNECTED
2180 || source_pin
.Connect_hr
== VFW_E_NO_AUDIO_HARDWARE
)
2181 ok(hr
== source_pin
.Connect_hr
, "Got hr %#x for Connect() hr %#x.\n",
2182 hr
, source_pin
.Connect_hr
);
2184 ok(hr
== VFW_E_CANNOT_CONNECT
, "Got hr %#x for Connect() hr %#x.\n",
2185 hr
, source_pin
.Connect_hr
);
2186 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2187 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2189 source_pin
.Connect_hr
= S_OK
;
2191 for (source_pin
.EnumMediaTypes_hr
= 0x80040200; source_pin
.EnumMediaTypes_hr
<= 0x800402ff;
2192 ++source_pin
.EnumMediaTypes_hr
)
2194 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2195 ok(hr
== source_pin
.EnumMediaTypes_hr
, "Got hr %#x for EnumMediaTypes() hr %#x.\n",
2196 hr
, source_pin
.EnumMediaTypes_hr
);
2197 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2198 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2200 source_pin
.EnumMediaTypes_hr
= S_OK
;
2202 /* Test usage of intermediate filters. Similarly to Render(), filters are
2203 * simply tried in enumeration order. */
2205 IFilterGraph2_AddFilter(graph
, &parser1
.IBaseFilter_iface
, NULL
);
2206 IFilterGraph2_AddFilter(graph
, &parser2
.IBaseFilter_iface
, NULL
);
2208 sink_pin
.accept_mt
= NULL
;
2209 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2210 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2211 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2212 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
2213 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2215 sink_pin
.accept_mt
= &sink_type
;
2216 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2217 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2218 ok(source_pin
.peer
== &parser2_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2219 ok(sink_pin
.peer
== &parser2_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2220 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
2221 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2222 IFilterGraph2_Disconnect(graph
, sink_pin
.peer
);
2223 IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2225 for (source_pin
.Connect_hr
= 0x00040200; source_pin
.Connect_hr
<= 0x000402ff;
2226 ++source_pin
.Connect_hr
)
2228 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2229 ok(hr
== S_OK
, "Got hr %#x for Connect() hr %#x.\n", hr
, source_pin
.Connect_hr
);
2230 ok(source_pin
.peer
== &parser2_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2231 ok(sink_pin
.peer
== &parser2_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2232 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
2233 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2234 IFilterGraph2_Disconnect(graph
, sink_pin
.peer
);
2235 IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2237 source_pin
.Connect_hr
= S_OK
;
2239 IFilterGraph2_RemoveFilter(graph
, &parser1
.IBaseFilter_iface
);
2240 IFilterGraph2_AddFilter(graph
, &parser1
.IBaseFilter_iface
, NULL
);
2242 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2243 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2244 ok(source_pin
.peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2245 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2246 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
2247 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2248 IFilterGraph2_Disconnect(graph
, sink_pin
.peer
);
2249 IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2251 /* No preference is given to smaller chains. */
2253 IFilterGraph2_AddFilter(graph
, &parser3
.IBaseFilter_iface
, NULL
);
2254 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2255 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2256 ok(source_pin
.peer
== &parser3_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2257 ok(parser3_pins
[1].peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", parser3_pins
[1].peer
);
2258 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2259 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
2260 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2261 IFilterGraph2_Disconnect(graph
, parser3_pins
[0].peer
);
2262 IFilterGraph2_Disconnect(graph
, &parser3_pins
[0].IPin_iface
);
2263 IFilterGraph2_Disconnect(graph
, sink_pin
.peer
);
2264 IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2266 IFilterGraph2_RemoveFilter(graph
, &parser3
.IBaseFilter_iface
);
2267 IFilterGraph2_RemoveFilter(graph
, &parser2
.IBaseFilter_iface
);
2269 /* Extra source pins on an intermediate filter are not rendered. */
2271 IFilterGraph2_RemoveFilter(graph
, &parser1
.IBaseFilter_iface
);
2272 parser1
.pin_count
= 3;
2273 IFilterGraph2_AddFilter(graph
, &parser1
.IBaseFilter_iface
, NULL
);
2274 IFilterGraph2_AddFilter(graph
, &sink2
.IBaseFilter_iface
, NULL
);
2276 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2278 ok(hr
== VFW_S_PARTIAL_RENDER
, "Got hr %#x.\n", hr
);
2279 ok(source_pin
.peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2280 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2281 ok(!parser1_pins
[2].peer
, "Got peer %p.\n", parser1_pins
[2].peer
);
2282 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
2283 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2284 IFilterGraph2_Disconnect(graph
, sink_pin
.peer
);
2285 IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2286 parser1
.pin_count
= 2;
2288 /* QueryInternalConnections is not used to find output pins. */
2290 parser1_pins
[1].QueryInternalConnections_hr
= S_OK
;
2291 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2292 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2293 ok(source_pin
.peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2294 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2295 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
2296 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2297 IFilterGraph2_Disconnect(graph
, sink_pin
.peer
);
2298 IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2299 parser1_pins
[1].QueryInternalConnections_hr
= E_NOTIMPL
;
2301 /* A pin whose name (not ID) begins with a tilde is not connected. */
2303 parser1_pins
[1].name
[0] = '~';
2304 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2305 ok(hr
== VFW_E_CANNOT_CONNECT
, "Got hr %#x.\n", hr
);
2306 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2308 parser1
.pin_count
= 3;
2309 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2310 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2311 ok(source_pin
.peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2312 ok(sink_pin
.peer
== &parser1_pins
[2].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2313 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
2314 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2315 IFilterGraph2_Disconnect(graph
, sink_pin
.peer
);
2316 IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2317 parser1
.pin_count
= 2;
2319 parser1_pins
[1].name
[0] = 0;
2320 parser1_pins
[1].id
[0] = '~';
2321 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2322 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2323 ok(source_pin
.peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2324 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2325 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
2326 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2327 IFilterGraph2_Disconnect(graph
, sink_pin
.peer
);
2328 IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2330 hr
= IFilterGraph2_Connect(graph
, &parser1_pins
[1].IPin_iface
, &parser1_pins
[0].IPin_iface
);
2331 ok(hr
== VFW_E_CANNOT_CONNECT
, "Got hr %#x.\n", hr
);
2333 parser1_pins
[0].QueryInternalConnections_hr
= S_OK
;
2334 hr
= IFilterGraph2_Connect(graph
, &parser1_pins
[1].IPin_iface
, &parser1_pins
[0].IPin_iface
);
2335 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2336 parser1_pins
[0].QueryInternalConnections_hr
= E_NOTIMPL
;
2338 ref
= IFilterGraph2_Release(graph
);
2339 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2341 /* Test enumeration of filters from the registry. */
2343 graph
= create_graph();
2344 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
2345 IFilterGraph2_AddFilter(graph
, &sink
.IBaseFilter_iface
, NULL
);
2347 CoRegisterClassObject(&parser1_clsid
, (IUnknown
*)&parser1_cf
.IClassFactory_iface
,
2348 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie1
);
2349 CoRegisterClassObject(&parser2_clsid
, (IUnknown
*)&parser2_cf
.IClassFactory_iface
,
2350 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie2
);
2352 CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
,
2353 &IID_IFilterMapper2
, (void **)&mapper
);
2355 regfilter
.dwVersion
= 2;
2356 regfilter
.dwMerit
= MERIT_UNLIKELY
;
2357 regfilter
.cPins2
= 2;
2358 regfilter
.rgPins2
= regpins
;
2359 regpins
[0].dwFlags
= 0;
2360 regpins
[0].cInstances
= 1;
2361 regpins
[0].nMediaTypes
= 1;
2362 regpins
[0].lpMediaType
= ®types
;
2363 regpins
[1].dwFlags
= REG_PINFLAG_B_OUTPUT
;
2364 regpins
[1].cInstances
= 1;
2365 regpins
[1].nMediaTypes
= 1;
2366 regpins
[1].lpMediaType
= ®types
;
2367 regtypes
.clsMajorType
= &source_type
.majortype
;
2368 regtypes
.clsMinorType
= &MEDIASUBTYPE_NULL
;
2369 hr
= IFilterMapper2_RegisterFilter(mapper
, &parser1_clsid
, L
"test", NULL
, NULL
, NULL
, ®filter
);
2370 if (hr
== E_ACCESSDENIED
)
2372 skip("Not enough permission to register filters.\n");
2375 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2377 IFilterMapper2_RegisterFilter(mapper
, &parser2_clsid
, L
"test", NULL
, NULL
, NULL
, ®filter
);
2379 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2380 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2381 ok(source_pin
.peer
== &parser1_pins
[0].IPin_iface
2382 || source_pin
.peer
== &parser2_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2383 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
2384 || sink_pin
.peer
== &parser2_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2386 ref
= IFilterGraph2_Release(graph
);
2387 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2389 /* Preference is given to filters already in the graph. */
2391 graph
= create_graph();
2392 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
2393 IFilterGraph2_AddFilter(graph
, &sink
.IBaseFilter_iface
, NULL
);
2394 IFilterGraph2_AddFilter(graph
, &parser1
.IBaseFilter_iface
, NULL
);
2396 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2397 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2398 ok(source_pin
.peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2399 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2401 ref
= IFilterGraph2_Release(graph
);
2402 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2404 /* Preference is given to filters with higher merit. */
2406 graph
= create_graph();
2407 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
2408 IFilterGraph2_AddFilter(graph
, &sink
.IBaseFilter_iface
, NULL
);
2410 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &parser1_clsid
);
2411 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &parser2_clsid
);
2413 regfilter
.dwMerit
= MERIT_UNLIKELY
;
2414 IFilterMapper2_RegisterFilter(mapper
, &parser1_clsid
, L
"test", NULL
, NULL
, NULL
, ®filter
);
2415 regfilter
.dwMerit
= MERIT_PREFERRED
;
2416 IFilterMapper2_RegisterFilter(mapper
, &parser2_clsid
, L
"test", NULL
, NULL
, NULL
, ®filter
);
2418 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2419 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2420 ok(source_pin
.peer
== &parser2_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2421 ok(sink_pin
.peer
== &parser2_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2423 ref
= IFilterGraph2_Release(graph
);
2424 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2426 graph
= create_graph();
2427 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
2428 IFilterGraph2_AddFilter(graph
, &sink
.IBaseFilter_iface
, NULL
);
2430 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &parser1_clsid
);
2431 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &parser2_clsid
);
2433 regfilter
.dwMerit
= MERIT_PREFERRED
;
2434 IFilterMapper2_RegisterFilter(mapper
, &parser1_clsid
, L
"test", NULL
, NULL
, NULL
, ®filter
);
2435 regfilter
.dwMerit
= MERIT_UNLIKELY
;
2436 IFilterMapper2_RegisterFilter(mapper
, &parser2_clsid
, L
"test", NULL
, NULL
, NULL
, ®filter
);
2438 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2439 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2440 ok(source_pin
.peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2441 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2443 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &parser1_clsid
);
2444 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &parser2_clsid
);
2447 CoRevokeClassObject(cookie1
);
2448 CoRevokeClassObject(cookie2
);
2449 IFilterMapper2_Release(mapper
);
2450 ref
= IFilterGraph2_Release(graph
);
2451 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
2452 ok(source
.ref
== 1, "Got outstanding refcount %d.\n", source
.ref
);
2453 ok(source_pin
.ref
== 1, "Got outstanding refcount %d.\n", source_pin
.ref
);
2454 ok(sink
.ref
== 1, "Got outstanding refcount %d.\n", sink
.ref
);
2455 ok(sink_pin
.ref
== 1, "Got outstanding refcount %d.\n", sink_pin
.ref
);
2456 ok(parser1
.ref
== 1, "Got outstanding refcount %d.\n", parser1
.ref
);
2457 ok(parser1_pins
[0].ref
== 1, "Got outstanding refcount %d.\n", parser1_pins
[0].ref
);
2458 ok(parser1_pins
[1].ref
== 1, "Got outstanding refcount %d.\n", parser1_pins
[1].ref
);
2459 ok(parser1_pins
[2].ref
== 1, "Got outstanding refcount %d.\n", parser1_pins
[2].ref
);
2460 ok(parser2
.ref
== 1, "Got outstanding refcount %d.\n", parser2
.ref
);
2461 ok(parser2_pins
[0].ref
== 1, "Got outstanding refcount %d.\n", parser2_pins
[0].ref
);
2462 ok(parser2_pins
[1].ref
== 1, "Got outstanding refcount %d.\n", parser2_pins
[1].ref
);
2463 ok(parser3
.ref
== 1, "Got outstanding refcount %d.\n", parser3
.ref
);
2464 ok(parser3_pins
[0].ref
== 1, "Got outstanding refcount %d.\n", parser3_pins
[0].ref
);
2465 ok(parser3_pins
[1].ref
== 1, "Got outstanding refcount %d.\n", parser3_pins
[1].ref
);
2468 static const GUID test_iid
= {0x33333333};
2469 static LONG outer_ref
= 1;
2471 static HRESULT WINAPI
outer_QueryInterface(IUnknown
*iface
, REFIID iid
, void **out
)
2473 if (IsEqualGUID(iid
, &IID_IUnknown
)
2474 || IsEqualGUID(iid
, &IID_IFilterGraph2
)
2475 || IsEqualGUID(iid
, &test_iid
))
2477 *out
= (IUnknown
*)0xdeadbeef;
2480 ok(0, "unexpected call %s\n", wine_dbgstr_guid(iid
));
2481 return E_NOINTERFACE
;
2484 static ULONG WINAPI
outer_AddRef(IUnknown
*iface
)
2486 return InterlockedIncrement(&outer_ref
);
2489 static ULONG WINAPI
outer_Release(IUnknown
*iface
)
2491 return InterlockedDecrement(&outer_ref
);
2494 static const IUnknownVtbl outer_vtbl
=
2496 outer_QueryInterface
,
2501 static IUnknown test_outer
= {&outer_vtbl
};
2503 static void test_aggregation(void)
2505 IFilterGraph2
*graph
, *graph2
;
2506 IFilterMapper2
*mapper
;
2507 IUnknown
*unk
, *unk2
;
2511 graph
= (IFilterGraph2
*)0xdeadbeef;
2512 hr
= CoCreateInstance(&CLSID_FilterGraph
, &test_outer
, CLSCTX_INPROC_SERVER
,
2513 &IID_IFilterGraph2
, (void **)&graph
);
2514 ok(hr
== E_NOINTERFACE
, "Got hr %#x.\n", hr
);
2515 ok(!graph
, "Got interface %p.\n", graph
);
2517 hr
= CoCreateInstance(&CLSID_FilterGraph
, &test_outer
, CLSCTX_INPROC_SERVER
,
2518 &IID_IUnknown
, (void **)&unk
);
2519 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2520 ok(outer_ref
== 1, "Got unexpected refcount %d.\n", outer_ref
);
2521 ok(unk
!= &test_outer
, "Returned IUnknown should not be outer IUnknown.\n");
2522 ref
= get_refcount(unk
);
2523 ok(ref
== 1, "Got unexpected refcount %d.\n", ref
);
2525 ref
= IUnknown_AddRef(unk
);
2526 ok(ref
== 2, "Got unexpected refcount %d.\n", ref
);
2527 ok(outer_ref
== 1, "Got unexpected refcount %d.\n", outer_ref
);
2529 ref
= IUnknown_Release(unk
);
2530 ok(ref
== 1, "Got unexpected refcount %d.\n", ref
);
2531 ok(outer_ref
== 1, "Got unexpected refcount %d.\n", outer_ref
);
2533 hr
= IUnknown_QueryInterface(unk
, &IID_IUnknown
, (void **)&unk2
);
2534 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2535 ok(unk2
== unk
, "Got unexpected IUnknown %p.\n", unk2
);
2536 IUnknown_Release(unk2
);
2538 hr
= IUnknown_QueryInterface(unk
, &IID_IFilterGraph2
, (void **)&graph
);
2539 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2541 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IUnknown
, (void **)&unk2
);
2542 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2543 ok(unk2
== (IUnknown
*)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2
);
2545 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IFilterGraph2
, (void **)&graph2
);
2546 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2547 ok(graph2
== (IFilterGraph2
*)0xdeadbeef, "Got unexpected IFilterGraph2 %p.\n", graph2
);
2549 hr
= IUnknown_QueryInterface(unk
, &test_iid
, (void **)&unk2
);
2550 ok(hr
== E_NOINTERFACE
, "Got hr %#x.\n", hr
);
2551 ok(!unk2
, "Got unexpected IUnknown %p.\n", unk2
);
2553 hr
= IFilterGraph2_QueryInterface(graph
, &test_iid
, (void **)&unk2
);
2554 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2555 ok(unk2
== (IUnknown
*)0xdeadbeef, "Got unexpected IUnknown %p.\n", unk2
);
2557 IFilterGraph2_Release(graph
);
2558 ref
= IUnknown_Release(unk
);
2559 ok(!ref
, "Got unexpected refcount %d.\n", ref
);
2560 ok(outer_ref
== 1, "Got unexpected refcount %d.\n", outer_ref
);
2562 /* Test the aggregated filter mapper. */
2564 graph
= create_graph();
2566 ref
= get_refcount(graph
);
2567 ok(ref
== 1, "Got unexpected refcount %d.\n", ref
);
2569 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IFilterMapper2
, (void **)&mapper
);
2570 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2572 ref
= get_refcount(graph
);
2573 ok(ref
== 2, "Got unexpected refcount %d.\n", ref
);
2574 ref
= get_refcount(mapper
);
2575 ok(ref
== 2, "Got unexpected refcount %d.\n", ref
);
2577 hr
= IFilterMapper2_QueryInterface(mapper
, &IID_IFilterGraph2
, (void **)&graph2
);
2578 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2579 ok(graph2
== graph
, "Got unexpected IFilterGraph2 %p.\n", graph2
);
2580 IFilterGraph2_Release(graph2
);
2582 IFilterMapper2_Release(mapper
);
2583 ref
= IFilterGraph2_Release(graph
);
2584 ok(!ref
, "Got unexpected refcount %d.\n", ref
);
2587 /* Test how methods from "control" interfaces (IBasicAudio, IBasicVideo,
2588 * IVideoWindow) are delegated to filters exposing those interfaces. */
2589 static void test_control_delegation(void)
2591 IFilterGraph2
*graph
= create_graph();
2592 IBasicAudio
*audio
, *filter_audio
;
2593 IBaseFilter
*renderer
;
2594 IVideoWindow
*window
;
2595 IBasicVideo2
*video
;
2596 ITypeInfo
*typeinfo
;
2604 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IBasicAudio
, (void **)&audio
);
2605 ok(hr
== S_OK
, "got %#x\n", hr
);
2607 hr
= IBasicAudio_GetTypeInfoCount(audio
, &count
);
2608 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2609 ok(count
== 1, "Got count %u.\n", count
);
2611 hr
= IBasicAudio_put_Volume(audio
, -10);
2612 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2613 hr
= IBasicAudio_get_Volume(audio
, &val
);
2614 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2615 hr
= IBasicAudio_put_Balance(audio
, 10);
2616 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2617 hr
= IBasicAudio_get_Balance(audio
, &val
);
2618 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2620 hr
= CoCreateInstance(&CLSID_DSoundRender
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
, (void **)&renderer
);
2621 if (hr
!= VFW_E_NO_AUDIO_HARDWARE
)
2623 ok(hr
== S_OK
, "got %#x\n", hr
);
2625 hr
= IFilterGraph2_AddFilter(graph
, renderer
, NULL
);
2626 ok(hr
== S_OK
, "got %#x\n", hr
);
2628 hr
= IBasicAudio_put_Volume(audio
, -10);
2629 ok(hr
== S_OK
, "got %#x\n", hr
);
2630 hr
= IBasicAudio_get_Volume(audio
, &val
);
2631 ok(hr
== S_OK
, "got %#x\n", hr
);
2632 ok(val
== -10, "got %d\n", val
);
2633 hr
= IBasicAudio_put_Balance(audio
, 10);
2634 ok(hr
== S_OK
|| hr
== VFW_E_MONO_AUDIO_HW
, "got %#x\n", hr
);
2635 hr
= IBasicAudio_get_Balance(audio
, &val
);
2636 ok(hr
== S_OK
|| hr
== VFW_E_MONO_AUDIO_HW
, "got %#x\n", hr
);
2638 ok(val
== 10, "got balance %d\n", val
);
2640 hr
= IBaseFilter_QueryInterface(renderer
, &IID_IBasicAudio
, (void **)&filter_audio
);
2641 ok(hr
== S_OK
, "got %#x\n", hr
);
2643 hr
= IBasicAudio_get_Volume(filter_audio
, &val
);
2644 ok(hr
== S_OK
, "got %#x\n", hr
);
2645 ok(val
== -10, "got volume %d\n", val
);
2647 hr
= IFilterGraph2_RemoveFilter(graph
, renderer
);
2648 ok(hr
== S_OK
, "got %#x\n", hr
);
2650 IBaseFilter_Release(renderer
);
2651 IBasicAudio_Release(filter_audio
);
2654 hr
= IBasicAudio_put_Volume(audio
, -10);
2655 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2656 hr
= IBasicAudio_get_Volume(audio
, &val
);
2657 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2658 hr
= IBasicAudio_put_Balance(audio
, 10);
2659 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2660 hr
= IBasicAudio_get_Balance(audio
, &val
);
2661 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2663 IBasicAudio_Release(audio
);
2665 /* IBasicVideo and IVideoWindow */
2667 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IBasicVideo2
, (void **)&video
);
2668 ok(hr
== S_OK
, "got %#x\n", hr
);
2669 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IVideoWindow
, (void **)&window
);
2670 ok(hr
== S_OK
, "got %#x\n", hr
);
2672 /* Unlike IBasicAudio, these return E_NOINTERFACE. */
2673 hr
= IBasicVideo2_get_BitRate(video
, &val
);
2674 ok(hr
== E_NOINTERFACE
, "got %#x\n", hr
);
2676 hr
= IBasicVideo2_GetTypeInfoCount(video
, &count
);
2677 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2678 ok(count
== 1, "Got count %u.\n", count
);
2680 hr
= IBasicVideo2_GetTypeInfo(video
, 0, 0, &typeinfo
);
2681 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2682 hr
= ITypeInfo_GetTypeAttr(typeinfo
, &typeattr
);
2683 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2684 ok(typeattr
->typekind
== TKIND_DISPATCH
, "Got kind %u.\n", typeattr
->typekind
);
2685 ok(IsEqualGUID(&typeattr
->guid
, &IID_IBasicVideo
), "Got IID %s.\n", wine_dbgstr_guid(&typeattr
->guid
));
2686 ITypeInfo_ReleaseTypeAttr(typeinfo
, typeattr
);
2687 ITypeInfo_Release(typeinfo
);
2689 hr
= IVideoWindow_SetWindowForeground(window
, OAFALSE
);
2690 ok(hr
== E_NOINTERFACE
, "got %#x\n", hr
);
2692 hr
= IVideoWindow_GetTypeInfoCount(window
, &count
);
2693 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2694 ok(count
== 1, "Got count %u.\n", count
);
2696 hr
= CoCreateInstance(&CLSID_VideoRenderer
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
, (void **)&renderer
);
2697 ok(hr
== S_OK
, "got %#x\n", hr
);
2699 hr
= IFilterGraph2_AddFilter(graph
, renderer
, NULL
);
2700 ok(hr
== S_OK
, "got %#x\n", hr
);
2702 hr
= IBasicVideo2_get_BitRate(video
, &val
);
2703 ok(hr
== VFW_E_NOT_CONNECTED
, "got %#x\n", hr
);
2704 hr
= IVideoWindow_SetWindowForeground(window
, OAFALSE
);
2705 ok(hr
== VFW_E_NOT_CONNECTED
, "got %#x\n", hr
);
2707 hr
= IFilterGraph2_RemoveFilter(graph
, renderer
);
2708 ok(hr
== S_OK
, "got %#x\n", hr
);
2710 hr
= IBasicVideo2_get_BitRate(video
, &val
);
2711 ok(hr
== E_NOINTERFACE
, "got %#x\n", hr
);
2712 hr
= IVideoWindow_SetWindowForeground(window
, OAFALSE
);
2713 ok(hr
== E_NOINTERFACE
, "got %#x\n", hr
);
2715 IBaseFilter_Release(renderer
);
2716 IBasicVideo2_Release(video
);
2717 IVideoWindow_Release(window
);
2718 IFilterGraph2_Release(graph
);
2721 static void test_add_remove_filter(void)
2723 struct testfilter filter
;
2725 IFilterGraph2
*graph
= create_graph();
2726 IBaseFilter
*ret_filter
;
2729 testfilter_init(&filter
, NULL
, 0);
2731 hr
= IFilterGraph2_FindFilterByName(graph
, L
"testid", &ret_filter
);
2732 ok(hr
== VFW_E_NOT_FOUND
, "Got hr %#x.\n", hr
);
2733 ok(!ret_filter
, "Got filter %p.\n", ret_filter
);
2735 hr
= IFilterGraph2_AddFilter(graph
, &filter
.IBaseFilter_iface
, L
"testid");
2736 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2737 ok(filter
.graph
== (IFilterGraph
*)graph
, "Got graph %p.\n", filter
.graph
);
2738 ok(!wcscmp(filter
.name
, L
"testid"), "Got name %s.\n", wine_dbgstr_w(filter
.name
));
2740 hr
= IFilterGraph2_FindFilterByName(graph
, L
"testid", &ret_filter
);
2741 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2742 ok(ret_filter
== &filter
.IBaseFilter_iface
, "Got filter %p.\n", ret_filter
);
2743 IBaseFilter_Release(ret_filter
);
2745 hr
= IFilterGraph2_RemoveFilter(graph
, &filter
.IBaseFilter_iface
);
2746 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2747 ok(!filter
.graph
, "Got graph %p.\n", filter
.graph
);
2748 ok(!filter
.name
, "Got name %s.\n", wine_dbgstr_w(filter
.name
));
2749 ok(!filter
.clock
, "Got clock %p,\n", filter
.clock
);
2750 ok(filter
.ref
== 1, "Got outstanding refcount %d.\n", filter
.ref
);
2752 hr
= IFilterGraph2_FindFilterByName(graph
, L
"testid", &ret_filter
);
2753 ok(hr
== VFW_E_NOT_FOUND
, "Got hr %#x.\n", hr
);
2754 ok(!ret_filter
, "Got filter %p.\n", ret_filter
);
2756 hr
= IFilterGraph2_AddFilter(graph
, &filter
.IBaseFilter_iface
, NULL
);
2757 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2758 ok(filter
.graph
== (IFilterGraph
*)graph
, "Got graph %p.\n", filter
.graph
);
2759 ok(!wcscmp(filter
.name
, L
"0001"), "Got name %s.\n", wine_dbgstr_w(filter
.name
));
2761 hr
= IFilterGraph2_FindFilterByName(graph
, L
"0001", &ret_filter
);
2762 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2763 ok(ret_filter
== &filter
.IBaseFilter_iface
, "Got filter %p.\n", ret_filter
);
2764 IBaseFilter_Release(ret_filter
);
2766 /* test releasing the filter graph while filters are still connected */
2767 hr
= IFilterGraph2_Release(graph
);
2768 ok(!hr
, "Got outstanding refcount %d.\n", hr
);
2769 ok(!filter
.graph
, "Got graph %p.\n", filter
.graph
);
2770 ok(!filter
.name
, "Got name %s.\n", wine_dbgstr_w(filter
.name
));
2771 ok(!filter
.clock
, "Got clock %p.\n", filter
.clock
);
2772 ok(filter
.ref
== 1, "Got outstanding refcount %d.\n", filter
.ref
);
2775 static HRESULT WINAPI
test_connect_direct_Connect(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
2777 struct testpin
*pin
= impl_from_IPin(iface
);
2778 if (winetest_debug
> 1) trace("%p->Connect()\n", pin
);
2782 pin
->mt
= (AM_MEDIA_TYPE
*)mt
;
2786 static const IPinVtbl test_connect_direct_vtbl
=
2788 testpin_QueryInterface
,
2791 test_connect_direct_Connect
,
2792 no_ReceiveConnection
,
2794 testpin_ConnectedTo
,
2795 testpin_ConnectionMediaType
,
2796 testpin_QueryPinInfo
,
2797 testpin_QueryDirection
,
2799 testpin_QueryAccept
,
2801 testpin_QueryInternalConnections
,
2802 testpin_EndOfStream
,
2808 static void test_connect_direct_init(struct testpin
*pin
, PIN_DIRECTION dir
)
2810 testpin_init(pin
, &test_connect_direct_vtbl
, dir
);
2813 static void test_connect_direct(void)
2815 struct testpin source_pin
, sink_pin
, parser1_pins
[2], parser2_pins
[2];
2816 struct testfilter source
, sink
, parser1
, parser2
;
2818 IFilterGraph2
*graph
= create_graph();
2822 test_connect_direct_init(&source_pin
, PINDIR_OUTPUT
);
2823 testfilter_init(&source
, &source_pin
, 1);
2824 test_connect_direct_init(&sink_pin
, PINDIR_INPUT
);
2825 testfilter_init(&sink
, &sink_pin
, 1);
2826 test_connect_direct_init(&parser1_pins
[0], PINDIR_INPUT
);
2827 test_connect_direct_init(&parser1_pins
[1], PINDIR_OUTPUT
);
2828 testfilter_init(&parser1
, parser1_pins
, 2);
2829 test_connect_direct_init(&parser2_pins
[0], PINDIR_INPUT
);
2830 test_connect_direct_init(&parser2_pins
[1], PINDIR_OUTPUT
);
2831 testfilter_init(&parser2
, parser2_pins
, 2);
2833 hr
= IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
2834 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2836 hr
= IFilterGraph2_AddFilter(graph
, &sink
.IBaseFilter_iface
, NULL
);
2837 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2839 hr
= IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, NULL
);
2840 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2841 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2842 ok(!source_pin
.mt
, "Got mt %p.\n", source_pin
.mt
);
2843 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2845 hr
= IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2846 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2847 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2848 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2850 hr
= IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2851 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2852 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2853 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2855 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2856 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2857 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2858 ok(!source_pin
.mt
, "Got mt %p.\n", source_pin
.mt
);
2859 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2861 hr
= IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2862 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2863 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2864 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2866 hr
= IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2867 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2868 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2869 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2871 /* Swap the pins when connecting. */
2872 hr
= IFilterGraph2_ConnectDirect(graph
, &sink_pin
.IPin_iface
, &source_pin
.IPin_iface
, NULL
);
2873 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2875 ok(sink_pin
.peer
== &source_pin
.IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2876 ok(!sink_pin
.mt
, "Got mt %p.\n", sink_pin
.mt
);
2878 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2880 hr
= IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2882 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2884 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2885 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2887 hr
= IFilterGraph2_Connect(graph
, &sink_pin
.IPin_iface
, &source_pin
.IPin_iface
);
2888 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2890 ok(sink_pin
.peer
== &source_pin
.IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2891 ok(!sink_pin
.mt
, "Got mt %p.\n", sink_pin
.mt
);
2893 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2895 hr
= IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2897 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2899 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2900 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2902 /* Disconnect() does not disconnect the peer. */
2903 hr
= IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, NULL
);
2904 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2905 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2906 ok(!source_pin
.mt
, "Got mt %p.\n", source_pin
.mt
);
2907 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2909 sink_pin
.peer
= &source_pin
.IPin_iface
;
2910 IPin_AddRef(sink_pin
.peer
);
2912 hr
= IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2913 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2914 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2915 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2917 hr
= IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2918 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2919 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2920 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2922 /* Test specifying the media type. */
2923 hr
= IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, &mt
);
2924 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2925 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2926 ok(source_pin
.mt
== &mt
, "Got mt %p.\n", source_pin
.mt
);
2927 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2928 hr
= IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2929 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2931 /* Test Reconnect[Ex](). */
2933 hr
= IFilterGraph2_Reconnect(graph
, &source_pin
.IPin_iface
);
2934 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
2935 hr
= IFilterGraph2_Reconnect(graph
, &sink_pin
.IPin_iface
);
2936 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
2938 hr
= IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, &mt
);
2939 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2940 hr
= IFilterGraph2_Reconnect(graph
, &source_pin
.IPin_iface
);
2941 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2942 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2943 ok(!source_pin
.mt
, "Got mt %p.\n", source_pin
.mt
);
2944 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2945 hr
= IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2946 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2948 hr
= IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, &mt
);
2949 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2950 sink_pin
.peer
= &source_pin
.IPin_iface
;
2951 IPin_AddRef(sink_pin
.peer
);
2952 hr
= IFilterGraph2_Reconnect(graph
, &sink_pin
.IPin_iface
);
2953 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2954 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2955 ok(!source_pin
.mt
, "Got mt %p.\n", source_pin
.mt
);
2956 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2957 hr
= IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2958 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2960 hr
= IFilterGraph2_ReconnectEx(graph
, &source_pin
.IPin_iface
, NULL
);
2961 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
2962 hr
= IFilterGraph2_ReconnectEx(graph
, &sink_pin
.IPin_iface
, NULL
);
2963 ok(hr
== VFW_E_NOT_CONNECTED
, "Got hr %#x.\n", hr
);
2965 hr
= IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, &mt
);
2966 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2967 hr
= IFilterGraph2_ReconnectEx(graph
, &source_pin
.IPin_iface
, NULL
);
2968 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2969 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2970 ok(!source_pin
.mt
, "Got mt %p.\n", source_pin
.mt
);
2971 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2972 hr
= IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2973 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2975 hr
= IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, &mt
);
2976 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2977 hr
= IFilterGraph2_ReconnectEx(graph
, &source_pin
.IPin_iface
, &mt
);
2978 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2979 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2980 ok(source_pin
.mt
== &mt
, "Got mt %p.\n", source_pin
.mt
);
2981 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2982 hr
= IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2983 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2985 /* ConnectDirect() protects against cyclical connections. */
2986 hr
= IFilterGraph2_AddFilter(graph
, &parser1
.IBaseFilter_iface
, NULL
);
2987 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2988 hr
= IFilterGraph2_AddFilter(graph
, &parser2
.IBaseFilter_iface
, NULL
);
2989 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2991 hr
= IFilterGraph2_ConnectDirect(graph
, &parser1_pins
[1].IPin_iface
, &parser1_pins
[0].IPin_iface
, NULL
);
2992 ok(hr
== VFW_E_CIRCULAR_GRAPH
, "Got hr %#x.\n", hr
);
2994 hr
= IFilterGraph2_ConnectDirect(graph
, &parser1_pins
[1].IPin_iface
, &parser2_pins
[0].IPin_iface
, NULL
);
2995 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2996 hr
= IFilterGraph2_ConnectDirect(graph
, &parser2_pins
[1].IPin_iface
, &parser1_pins
[0].IPin_iface
, NULL
);
2997 todo_wine
ok(hr
== VFW_E_CIRCULAR_GRAPH
, "Got hr %#x.\n", hr
);
2998 IFilterGraph2_Disconnect(graph
, &parser1_pins
[1].IPin_iface
);
2999 IFilterGraph2_Disconnect(graph
, &parser2_pins
[0].IPin_iface
);
3001 parser1_pins
[0].QueryInternalConnections_hr
= S_OK
;
3002 hr
= IFilterGraph2_ConnectDirect(graph
, &parser1_pins
[1].IPin_iface
, &parser1_pins
[0].IPin_iface
, NULL
);
3003 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3004 ok(!parser1_pins
[0].peer
, "Got peer %p.\n", parser1_pins
[0].peer
);
3005 todo_wine
ok(parser1_pins
[1].peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", parser1_pins
[1].peer
);
3006 IFilterGraph2_Disconnect(graph
, &parser1_pins
[0].IPin_iface
);
3007 IFilterGraph2_Disconnect(graph
, &parser1_pins
[1].IPin_iface
);
3009 hr
= IFilterGraph2_ConnectDirect(graph
, &parser1_pins
[1].IPin_iface
, &parser2_pins
[0].IPin_iface
, NULL
);
3010 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3011 hr
= IFilterGraph2_ConnectDirect(graph
, &parser2_pins
[1].IPin_iface
, &parser1_pins
[0].IPin_iface
, NULL
);
3012 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3013 IFilterGraph2_Disconnect(graph
, &parser1_pins
[1].IPin_iface
);
3014 IFilterGraph2_Disconnect(graph
, &parser2_pins
[0].IPin_iface
);
3016 hr
= IFilterGraph2_RemoveFilter(graph
, &parser1
.IBaseFilter_iface
);
3017 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3018 hr
= IFilterGraph2_RemoveFilter(graph
, &parser2
.IBaseFilter_iface
);
3019 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3021 /* Both pins are disconnected when a filter is removed. */
3022 hr
= IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, &mt
);
3023 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3024 sink_pin
.peer
= &source_pin
.IPin_iface
;
3025 IPin_AddRef(sink_pin
.peer
);
3026 hr
= IFilterGraph2_RemoveFilter(graph
, &source
.IBaseFilter_iface
);
3027 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3028 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
3029 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
3031 /* Or when the graph is destroyed. */
3032 hr
= IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
3033 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3035 hr
= IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, NULL
);
3036 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3037 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
3038 ok(!source_pin
.mt
, "Got mt %p.\n", source_pin
.mt
);
3039 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
3040 IPin_AddRef(sink_pin
.peer
= &source_pin
.IPin_iface
);
3042 hr
= IFilterGraph2_Release(graph
);
3043 ok(!hr
, "Got outstanding refcount %d.\n", hr
);
3044 ok(source
.ref
== 1, "Got outstanding refcount %d.\n", source
.ref
);
3045 ok(sink
.ref
== 1, "Got outstanding refcount %d.\n", sink
.ref
);
3046 ok(source_pin
.ref
== 1, "Got outstanding refcount %d.\n", source_pin
.ref
);
3048 ok(sink_pin
.ref
== 1, "Got outstanding refcount %d.\n", sink_pin
.ref
);
3049 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
3050 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
3053 static void test_sync_source(void)
3055 struct testfilter filter1
, filter2
;
3057 IFilterGraph2
*graph
= create_graph();
3058 IReferenceClock
*systemclock
, *clock
;
3059 IMediaFilter
*filter
;
3063 IFilterGraph2_QueryInterface(graph
, &IID_IMediaFilter
, (void **)&filter
);
3065 testfilter_init(&filter1
, NULL
, 0);
3066 testfilter_init(&filter2
, NULL
, 0);
3068 IFilterGraph2_AddFilter(graph
, &filter1
.IBaseFilter_iface
, NULL
);
3069 IFilterGraph2_AddFilter(graph
, &filter2
.IBaseFilter_iface
, NULL
);
3071 ok(!filter1
.clock
, "Got clock %p.\n", filter1
.clock
);
3072 ok(!filter2
.clock
, "Got clock %p.\n", filter2
.clock
);
3074 CoCreateInstance(&CLSID_SystemClock
, NULL
, CLSCTX_INPROC_SERVER
,
3075 &IID_IReferenceClock
, (void **)&systemclock
);
3077 hr
= IMediaFilter_SetSyncSource(filter
, systemclock
);
3078 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3079 ok(filter1
.clock
== systemclock
, "Got clock %p.\n", filter1
.clock
);
3080 ok(filter2
.clock
== systemclock
, "Got clock %p.\n", filter2
.clock
);
3082 hr
= IMediaFilter_GetSyncSource(filter
, &clock
);
3083 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3084 ok(clock
== systemclock
, "Got clock %p.\n", clock
);
3085 IReferenceClock_Release(clock
);
3087 hr
= IMediaFilter_SetSyncSource(filter
, NULL
);
3088 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3089 ok(!filter1
.clock
, "Got clock %p.\n", filter1
.clock
);
3090 ok(!filter2
.clock
, "Got clock %p.\n", filter2
.clock
);
3092 hr
= IMediaFilter_GetSyncSource(filter
, &clock
);
3094 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
3095 ok(!clock
, "Got clock %p.\n", clock
);
3097 IReferenceClock_Release(systemclock
);
3098 IMediaFilter_Release(filter
);
3099 ref
= IFilterGraph2_Release(graph
);
3100 ok(!ref
, "Got outstanding refcount %d\n", ref
);
3101 ok(filter1
.ref
== 1, "Got outstanding refcount %d.\n", filter1
.ref
);
3102 ok(filter2
.ref
== 1, "Got outstanding refcount %d.\n", filter2
.ref
);
3105 #define check_filter_state(a, b) check_filter_state_(__LINE__, a, b)
3106 static void check_filter_state_(unsigned int line
, IFilterGraph2
*graph
, FILTER_STATE expect
)
3108 IMediaFilter
*mediafilter
;
3109 IEnumFilters
*filterenum
;
3110 IMediaControl
*control
;
3111 OAFilterState oastate
;
3112 IBaseFilter
*filter
;
3116 IFilterGraph2_QueryInterface(graph
, &IID_IMediaFilter
, (void **)&mediafilter
);
3117 hr
= IMediaFilter_GetState(mediafilter
, 1000, &state
);
3118 ok_(__FILE__
, line
)(hr
== S_OK
, "IMediaFilter_GetState() returned %#x.\n", hr
);
3119 ok_(__FILE__
, line
)(state
== expect
, "Expected state %u, got %u.\n", expect
, state
);
3120 IMediaFilter_Release(mediafilter
);
3122 IFilterGraph2_QueryInterface(graph
, &IID_IMediaControl
, (void **)&control
);
3123 hr
= IMediaControl_GetState(control
, 1000, &oastate
);
3124 ok_(__FILE__
, line
)(hr
== S_OK
, "IMediaControl_GetState() returned %#x.\n", hr
);
3125 ok_(__FILE__
, line
)(state
== expect
, "Expected state %u, got %u.\n", expect
, state
);
3126 IMediaControl_Release(control
);
3128 IFilterGraph2_EnumFilters(graph
, &filterenum
);
3129 while (IEnumFilters_Next(filterenum
, 1, &filter
, NULL
) == S_OK
)
3131 hr
= IBaseFilter_GetState(filter
, 1000, &state
);
3132 ok_(__FILE__
, line
)(hr
== S_OK
, "IBaseFilter_GetState() returned %#x.\n", hr
);
3133 ok_(__FILE__
, line
)(state
== expect
, "Expected state %u, got %u.\n", expect
, state
);
3134 IBaseFilter_Release(filter
);
3136 IEnumFilters_Release(filterenum
);
3140 static void test_filter_state(void)
3142 struct testfilter source
, sink
, dummy
;
3143 struct testpin source_pin
, sink_pin
;
3145 IFilterGraph2
*graph
= create_graph();
3146 REFERENCE_TIME start_time
;
3147 IReferenceClock
*clock
;
3148 IMediaControl
*control
;
3149 IMediaFilter
*filter
;
3150 OAFilterState state
;
3154 testsource_init(&source_pin
, NULL
, 0);
3155 testsink_init(&sink_pin
);
3156 testfilter_init(&source
, &source_pin
, 1);
3157 testfilter_init(&sink
, &sink_pin
, 1);
3158 testfilter_init(&dummy
, NULL
, 0);
3160 IFilterGraph2_QueryInterface(graph
, &IID_IMediaFilter
, (void **)&filter
);
3161 IFilterGraph2_QueryInterface(graph
, &IID_IMediaControl
, (void **)&control
);
3163 source_pin
.filter
= &source
.IBaseFilter_iface
;
3164 sink_pin
.filter
= &sink
.IBaseFilter_iface
;
3166 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
3167 IFilterGraph2_AddFilter(graph
, &sink
.IBaseFilter_iface
, NULL
);
3168 IFilterGraph2_AddFilter(graph
, &dummy
.IBaseFilter_iface
, NULL
);
3169 IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, NULL
);
3171 check_filter_state(graph
, State_Stopped
);
3173 hr
= IMediaControl_Pause(control
);
3174 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3175 check_filter_state(graph
, State_Paused
);
3177 /* Pausing sets the default sync source, if it's not already set. */
3179 hr
= IMediaFilter_GetSyncSource(filter
, &clock
);
3180 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3181 ok(!!clock
, "Reference clock not set.\n");
3182 ok(source
.clock
== clock
, "Expected %p, got %p.\n", clock
, source
.clock
);
3183 ok(sink
.clock
== clock
, "Expected %p, got %p.\n", clock
, sink
.clock
);
3185 hr
= IReferenceClock_GetTime(clock
, &start_time
);
3186 ok(SUCCEEDED(hr
), "Got hr %#x.\n", hr
);
3187 hr
= IMediaControl_Run(control
);
3188 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3189 check_filter_state(graph
, State_Running
);
3190 if (winetest_interactive
) /* Timing problems make this test too liable to fail. */
3191 ok(source
.start_time
>= start_time
&& source
.start_time
< start_time
+ 500 * 10000,
3192 "Expected time near %s, got %s.\n",
3193 wine_dbgstr_longlong(start_time
), wine_dbgstr_longlong(source
.start_time
));
3194 ok(sink
.start_time
== source
.start_time
, "Expected time %s, got %s.\n",
3195 wine_dbgstr_longlong(source
.start_time
), wine_dbgstr_longlong(sink
.start_time
));
3197 hr
= IMediaControl_Pause(control
);
3198 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3199 check_filter_state(graph
, State_Paused
);
3201 hr
= IMediaControl_Stop(control
);
3202 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3203 check_filter_state(graph
, State_Stopped
);
3205 hr
= IMediaControl_Run(control
);
3206 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3207 check_filter_state(graph
, State_Running
);
3209 hr
= IMediaControl_Stop(control
);
3210 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3211 check_filter_state(graph
, State_Stopped
);
3213 hr
= IMediaControl_Pause(control
);
3214 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3215 check_filter_state(graph
, State_Paused
);
3217 hr
= IMediaControl_StopWhenReady(control
);
3218 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3219 check_filter_state(graph
, State_Stopped
);
3221 hr
= IMediaControl_Run(control
);
3222 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3223 check_filter_state(graph
, State_Running
);
3225 hr
= IMediaControl_StopWhenReady(control
);
3226 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3227 check_filter_state(graph
, State_Stopped
);
3229 hr
= IMediaControl_StopWhenReady(control
);
3230 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3231 check_filter_state(graph
, State_Stopped
);
3233 IReferenceClock_Release(clock
);
3234 IMediaFilter_Release(filter
);
3235 IMediaControl_Release(control
);
3236 IFilterGraph2_Release(graph
);
3238 /* Test same methods using IMediaFilter. */
3240 graph
= create_graph();
3241 IFilterGraph2_QueryInterface(graph
, &IID_IMediaFilter
, (void **)&filter
);
3242 IFilterGraph2_QueryInterface(graph
, &IID_IMediaControl
, (void **)&control
);
3244 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
3245 IFilterGraph2_AddFilter(graph
, &sink
.IBaseFilter_iface
, NULL
);
3246 IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, NULL
);
3248 hr
= IMediaFilter_Pause(filter
);
3249 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3250 check_filter_state(graph
, State_Paused
);
3252 hr
= IMediaFilter_GetSyncSource(filter
, &clock
);
3253 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3254 ok(!!clock
, "Reference clock not set.\n");
3255 ok(source
.clock
== clock
, "Expected %p, got %p.\n", clock
, source
.clock
);
3256 ok(sink
.clock
== clock
, "Expected %p, got %p.\n", clock
, sink
.clock
);
3258 hr
= IMediaFilter_Run(filter
, 0xdeadbeef);
3259 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3260 check_filter_state(graph
, State_Running
);
3261 ok(source
.start_time
== 0xdeadbeef, "Got time %s.\n", wine_dbgstr_longlong(source
.start_time
));
3262 ok(sink
.start_time
== 0xdeadbeef, "Got time %s.\n", wine_dbgstr_longlong(sink
.start_time
));
3264 hr
= IMediaFilter_Pause(filter
);
3265 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3266 check_filter_state(graph
, State_Paused
);
3268 hr
= IMediaFilter_Run(filter
, 0xdeadf00d);
3269 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3270 check_filter_state(graph
, State_Running
);
3271 ok(source
.start_time
== 0xdeadf00d, "Got time %s.\n", wine_dbgstr_longlong(source
.start_time
));
3272 ok(sink
.start_time
== 0xdeadf00d, "Got time %s.\n", wine_dbgstr_longlong(sink
.start_time
));
3274 hr
= IMediaFilter_Pause(filter
);
3275 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3276 check_filter_state(graph
, State_Paused
);
3278 hr
= IMediaFilter_Stop(filter
);
3279 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3280 check_filter_state(graph
, State_Stopped
);
3282 hr
= IReferenceClock_GetTime(clock
, &start_time
);
3283 ok(SUCCEEDED(hr
), "Got hr %#x.\n", hr
);
3284 hr
= IMediaFilter_Run(filter
, 0);
3285 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3286 check_filter_state(graph
, State_Running
);
3287 if (winetest_interactive
) /* Timing problems make this test too liable to fail. */
3288 ok(source
.start_time
>= start_time
&& source
.start_time
< start_time
+ 500 * 10000,
3289 "Expected time near %s, got %s.\n",
3290 wine_dbgstr_longlong(start_time
), wine_dbgstr_longlong(source
.start_time
));
3291 ok(sink
.start_time
== source
.start_time
, "Expected time %s, got %s.\n",
3292 wine_dbgstr_longlong(source
.start_time
), wine_dbgstr_longlong(sink
.start_time
));
3295 hr
= IMediaFilter_Pause(filter
);
3296 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3297 check_filter_state(graph
, State_Paused
);
3299 hr
= IMediaFilter_Run(filter
, 0);
3300 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3301 check_filter_state(graph
, State_Running
);
3302 if (winetest_interactive
) /* Timing problems make this test too liable to fail. */
3303 ok(source
.start_time
>= start_time
&& source
.start_time
< start_time
+ 500 * 10000,
3304 "Expected time near %s, got %s.\n",
3305 wine_dbgstr_longlong(start_time
), wine_dbgstr_longlong(source
.start_time
));
3306 ok(sink
.start_time
== source
.start_time
, "Expected time %s, got %s.\n",
3307 wine_dbgstr_longlong(source
.start_time
), wine_dbgstr_longlong(sink
.start_time
));
3309 hr
= IMediaFilter_Pause(filter
);
3310 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3311 check_filter_state(graph
, State_Paused
);
3314 start_time
+= 550 * 10000;
3315 hr
= IMediaFilter_Run(filter
, 0);
3316 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3317 check_filter_state(graph
, State_Running
);
3318 if (winetest_interactive
) /* Timing problems make this test too liable to fail. */
3319 ok(source
.start_time
>= start_time
&& source
.start_time
< start_time
+ 500 * 10000,
3320 "Expected time near %s, got %s.\n",
3321 wine_dbgstr_longlong(start_time
), wine_dbgstr_longlong(source
.start_time
));
3322 ok(sink
.start_time
== source
.start_time
, "Expected time %s, got %s.\n",
3323 wine_dbgstr_longlong(source
.start_time
), wine_dbgstr_longlong(sink
.start_time
));
3325 hr
= IMediaFilter_Stop(filter
);
3326 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3327 check_filter_state(graph
, State_Stopped
);
3329 /* Test removing the sync source. */
3331 IReferenceClock_Release(clock
);
3332 IMediaFilter_SetSyncSource(filter
, NULL
);
3334 hr
= IMediaControl_Run(control
);
3335 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3336 check_filter_state(graph
, State_Running
);
3338 ok(source
.start_time
> 0 && source
.start_time
< 500 * 10000,
3339 "Got time %s.\n", wine_dbgstr_longlong(source
.start_time
));
3340 ok(sink
.start_time
== source
.start_time
, "Expected time %s, got %s.\n",
3341 wine_dbgstr_longlong(source
.start_time
), wine_dbgstr_longlong(sink
.start_time
));
3343 hr
= IMediaControl_Stop(control
);
3344 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3345 check_filter_state(graph
, State_Stopped
);
3347 sink
.state_hr
= S_FALSE
;
3348 hr
= IMediaControl_Pause(control
);
3349 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
3351 sink
.state_hr
= VFW_S_STATE_INTERMEDIATE
;
3352 hr
= IMediaControl_GetState(control
, 0, &state
);
3353 ok(hr
== VFW_S_STATE_INTERMEDIATE
, "Got hr %#x.\n", hr
);
3354 ok(state
== State_Paused
, "Got state %u.\n", state
);
3356 sink
.state_hr
= VFW_S_CANT_CUE
;
3357 hr
= IMediaControl_GetState(control
, 0, &state
);
3358 ok(hr
== VFW_S_CANT_CUE
, "Got hr %#x.\n", hr
);
3359 ok(state
== State_Paused
, "Got state %u.\n", state
);
3361 sink
.state_hr
= VFW_S_STATE_INTERMEDIATE
;
3362 source
.state_hr
= VFW_S_CANT_CUE
;
3363 hr
= IMediaControl_GetState(control
, 0, &state
);
3364 ok(hr
== VFW_S_CANT_CUE
, "Got hr %#x.\n", hr
);
3365 ok(state
== State_Paused
, "Got state %u.\n", state
);
3367 sink
.state_hr
= VFW_S_CANT_CUE
;
3368 source
.state_hr
= VFW_S_STATE_INTERMEDIATE
;
3369 hr
= IMediaControl_GetState(control
, 0, &state
);
3370 ok(hr
== VFW_S_CANT_CUE
, "Got hr %#x.\n", hr
);
3371 ok(state
== State_Paused
, "Got state %u.\n", state
);
3373 sink
.state_hr
= source
.state_hr
= S_OK
;
3375 /* Destroying the graph while it's running stops all filters. */
3377 hr
= IMediaFilter_Run(filter
, 0);
3378 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3379 check_filter_state(graph
, State_Running
);
3381 ok(source
.start_time
> 0 && source
.start_time
< 500 * 10000,
3382 "Got time %s.\n", wine_dbgstr_longlong(source
.start_time
));
3383 ok(sink
.start_time
== source
.start_time
, "Expected time %s, got %s.\n",
3384 wine_dbgstr_longlong(source
.start_time
), wine_dbgstr_longlong(sink
.start_time
));
3386 IMediaFilter_Release(filter
);
3387 IMediaControl_Release(control
);
3388 ref
= IFilterGraph2_Release(graph
);
3389 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
3390 ok(source
.ref
== 1, "Got outstanding refcount %d.\n", source
.ref
);
3391 ok(sink
.ref
== 1, "Got outstanding refcount %d.\n", sink
.ref
);
3392 ok(source_pin
.ref
== 1, "Got outstanding refcount %d.\n", source_pin
.ref
);
3393 ok(sink_pin
.ref
== 1, "Got outstanding refcount %d.\n", sink_pin
.ref
);
3394 ok(source
.state
== State_Stopped
, "Got state %u.\n", source
.state
);
3395 ok(sink
.state
== State_Stopped
, "Got state %u.\n", sink
.state
);
3398 /* Helper function to check whether a filter is considered a renderer, i.e.
3399 * whether its EC_COMPLETE notification will be passed on to the application. */
3400 static HRESULT
check_ec_complete(IFilterGraph2
*graph
, IBaseFilter
*filter
)
3402 IMediaEventSink
*eventsink
;
3403 LONG_PTR param1
, param2
;
3404 IMediaControl
*control
;
3405 IMediaEvent
*eventsrc
;
3409 IFilterGraph2_QueryInterface(graph
, &IID_IMediaControl
, (void **)&control
);
3410 IFilterGraph2_QueryInterface(graph
, &IID_IMediaEvent
, (void **)&eventsrc
);
3411 IFilterGraph2_QueryInterface(graph
, &IID_IMediaEventSink
, (void **)&eventsink
);
3413 IMediaControl_Run(control
);
3415 hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, 0);
3416 ok(hr
== E_ABORT
, "Got hr %#x.\n", hr
);
3418 hr
= IMediaEventSink_Notify(eventsink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)filter
);
3419 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3421 ret_hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, 0);
3424 ok(code
== EC_COMPLETE
, "Got code %#x.\n", code
);
3425 ok(param1
== S_OK
, "Got param1 %#lx.\n", param1
);
3426 ok(!param2
, "Got param2 %#lx.\n", param2
);
3427 hr
= IMediaEvent_FreeEventParams(eventsrc
, code
, param1
, param2
);
3428 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3430 hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, 0);
3431 ok(hr
== E_ABORT
, "Got hr %#x.\n", hr
);
3434 IMediaControl_Stop(control
);
3436 IMediaControl_Release(control
);
3437 IMediaEvent_Release(eventsrc
);
3438 IMediaEventSink_Release(eventsink
);
3442 static void test_ec_complete(void)
3444 struct testpin filter1_pin
, filter2_pin
, filter3_pin
, source_pins
[3];
3445 struct testfilter filter1
, filter2
, filter3
, source
;
3447 IFilterGraph2
*graph
= create_graph();
3448 IMediaEventSink
*eventsink
;
3449 LONG_PTR param1
, param2
;
3450 IMediaControl
*control
;
3451 IMediaEvent
*eventsrc
;
3455 testsink_init(&filter1_pin
);
3456 testsink_init(&filter2_pin
);
3457 testsink_init(&filter3_pin
);
3458 testfilter_init(&filter1
, &filter1_pin
, 1);
3459 testfilter_init(&filter2
, &filter2_pin
, 1);
3460 testfilter_init(&filter3
, &filter3_pin
, 1);
3461 testsource_init(&source_pins
[0], NULL
, 0);
3462 testsource_init(&source_pins
[1], NULL
, 0);
3463 testsource_init(&source_pins
[2], NULL
, 0);
3464 testfilter_init(&source
, source_pins
, 3);
3466 filter1
.IAMFilterMiscFlags_iface
.lpVtbl
= &testmiscflags_vtbl
;
3467 filter2
.IAMFilterMiscFlags_iface
.lpVtbl
= &testmiscflags_vtbl
;
3468 filter1
.misc_flags
= filter2
.misc_flags
= AM_FILTER_MISC_FLAGS_IS_RENDERER
;
3470 IFilterGraph2_QueryInterface(graph
, &IID_IMediaControl
, (void **)&control
);
3471 IFilterGraph2_QueryInterface(graph
, &IID_IMediaEvent
, (void **)&eventsrc
);
3472 IFilterGraph2_QueryInterface(graph
, &IID_IMediaEventSink
, (void **)&eventsink
);
3474 IFilterGraph2_AddFilter(graph
, &filter1
.IBaseFilter_iface
, NULL
);
3475 IFilterGraph2_AddFilter(graph
, &filter2
.IBaseFilter_iface
, NULL
);
3476 IFilterGraph2_AddFilter(graph
, &filter3
.IBaseFilter_iface
, NULL
);
3477 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
3478 IFilterGraph2_ConnectDirect(graph
, &source_pins
[0].IPin_iface
, &filter1_pin
.IPin_iface
, NULL
);
3479 IFilterGraph2_ConnectDirect(graph
, &source_pins
[1].IPin_iface
, &filter2_pin
.IPin_iface
, NULL
);
3480 IFilterGraph2_ConnectDirect(graph
, &source_pins
[2].IPin_iface
, &filter3_pin
.IPin_iface
, NULL
);
3482 /* EC_COMPLETE is only delivered to the user after all renderers deliver it. */
3484 IMediaControl_Run(control
);
3486 while ((hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, 0)) == S_OK
)
3488 ok(code
!= EC_COMPLETE
, "Got unexpected EC_COMPLETE.\n");
3489 IMediaEvent_FreeEventParams(eventsrc
, code
, param1
, param2
);
3491 ok(hr
== E_ABORT
, "Got hr %#x.\n", hr
);
3493 hr
= IMediaEventSink_Notify(eventsink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)&filter1
.IBaseFilter_iface
);
3494 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3496 hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, 50);
3497 ok(hr
== E_ABORT
, "Got hr %#x.\n", hr
);
3499 hr
= IMediaEventSink_Notify(eventsink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)&filter2
.IBaseFilter_iface
);
3500 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3502 hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, 0);
3503 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3504 ok(code
== EC_COMPLETE
, "Got code %#x.\n", code
);
3505 ok(param1
== S_OK
, "Got param1 %#lx.\n", param1
);
3506 ok(!param2
, "Got param2 %#lx.\n", param2
);
3507 hr
= IMediaEvent_FreeEventParams(eventsrc
, code
, param1
, param2
);
3508 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3510 hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, 50);
3511 ok(hr
== E_ABORT
, "Got hr %#x.\n", hr
);
3513 hr
= IMediaEventSink_Notify(eventsink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)&filter3
.IBaseFilter_iface
);
3514 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3516 hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, 50);
3517 ok(hr
== E_ABORT
, "Got hr %#x.\n", hr
);
3519 IMediaControl_Stop(control
);
3521 /* Test CancelDefaultHandling(). */
3523 IMediaControl_Run(control
);
3525 hr
= IMediaEvent_CancelDefaultHandling(eventsrc
, EC_COMPLETE
);
3526 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3528 hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, 50);
3529 ok(hr
== E_ABORT
, "Got hr %#x.\n", hr
);
3531 hr
= IMediaEventSink_Notify(eventsink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)&filter1
.IBaseFilter_iface
);
3532 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3534 hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, 0);
3535 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3536 ok(code
== EC_COMPLETE
, "Got code %#x.\n", code
);
3537 ok(param1
== S_OK
, "Got param1 %#lx.\n", param1
);
3538 ok(param2
== (LONG_PTR
)&filter1
.IBaseFilter_iface
, "Got param2 %#lx.\n", param2
);
3539 hr
= IMediaEvent_FreeEventParams(eventsrc
, code
, param1
, param2
);
3540 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3542 hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, 50);
3543 ok(hr
== E_ABORT
, "Got hr %#x.\n", hr
);
3545 hr
= IMediaEventSink_Notify(eventsink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)&filter3
.IBaseFilter_iface
);
3546 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3548 hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, 0);
3549 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3550 ok(code
== EC_COMPLETE
, "Got code %#x.\n", code
);
3551 ok(param1
== S_OK
, "Got param1 %#lx.\n", param1
);
3552 ok(param2
== (LONG_PTR
)&filter3
.IBaseFilter_iface
, "Got param2 %#lx.\n", param2
);
3553 hr
= IMediaEvent_FreeEventParams(eventsrc
, code
, param1
, param2
);
3554 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3556 hr
= IMediaEvent_GetEvent(eventsrc
, &code
, ¶m1
, ¶m2
, 50);
3557 ok(hr
== E_ABORT
, "Got hr %#x.\n", hr
);
3559 IMediaControl_Stop(control
);
3560 hr
= IMediaEvent_RestoreDefaultHandling(eventsrc
, EC_COMPLETE
);
3561 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3563 /* A filter counts as a renderer if it (1) exposes IAMFilterMiscFlags and
3564 * reports itself as a renderer, or (2) exposes IMediaSeeking and has no
3565 * output pins. Despite MSDN, QueryInternalConnections() does not seem to
3568 IFilterGraph2_RemoveFilter(graph
, &filter1
.IBaseFilter_iface
);
3569 IFilterGraph2_RemoveFilter(graph
, &filter2
.IBaseFilter_iface
);
3570 IFilterGraph2_RemoveFilter(graph
, &filter3
.IBaseFilter_iface
);
3571 filter1
.misc_flags
= 0;
3572 IFilterGraph2_AddFilter(graph
, &filter1
.IBaseFilter_iface
, NULL
);
3573 IFilterGraph2_ConnectDirect(graph
, &source_pins
[0].IPin_iface
, &filter1_pin
.IPin_iface
, NULL
);
3575 hr
= check_ec_complete(graph
, &filter1
.IBaseFilter_iface
);
3576 ok(hr
== E_ABORT
, "Got hr %#x.\n", hr
);
3578 IFilterGraph2_RemoveFilter(graph
, &filter1
.IBaseFilter_iface
);
3579 filter1_pin
.dir
= PINDIR_INPUT
;
3580 filter1
.IAMFilterMiscFlags_iface
.lpVtbl
= NULL
;
3581 filter1
.IMediaSeeking_iface
.lpVtbl
= &testseek_vtbl
;
3582 IFilterGraph2_AddFilter(graph
, &filter1
.IBaseFilter_iface
, NULL
);
3583 IFilterGraph2_ConnectDirect(graph
, &source_pins
[0].IPin_iface
, &filter1_pin
.IPin_iface
, NULL
);
3585 hr
= check_ec_complete(graph
, &filter1
.IBaseFilter_iface
);
3586 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3588 ok(filter1
.seeking_ref
> 0, "Unexpected seeking refcount %d.\n", filter1
.seeking_ref
);
3589 IFilterGraph2_RemoveFilter(graph
, &filter1
.IBaseFilter_iface
);
3590 ok(filter1
.seeking_ref
== 0, "Unexpected seeking refcount %d.\n", filter1
.seeking_ref
);
3592 filter1_pin
.dir
= PINDIR_OUTPUT
;
3593 IFilterGraph2_AddFilter(graph
, &filter1
.IBaseFilter_iface
, NULL
);
3595 hr
= check_ec_complete(graph
, &filter1
.IBaseFilter_iface
);
3596 ok(hr
== E_ABORT
, "Got hr %#x.\n", hr
);
3598 ok(filter1
.seeking_ref
> 0, "Unexpected seeking refcount %d.\n", filter1
.seeking_ref
);
3599 IFilterGraph2_RemoveFilter(graph
, &filter1
.IBaseFilter_iface
);
3600 ok(filter1
.seeking_ref
== 0, "Unexpected seeking refcount %d.\n", filter1
.seeking_ref
);
3602 filter1
.IMediaSeeking_iface
.lpVtbl
= NULL
;
3603 filter1_pin
.dir
= PINDIR_INPUT
;
3604 filter1
.pin_count
= 1;
3605 filter1_pin
.QueryInternalConnections_hr
= S_OK
;
3606 IFilterGraph2_AddFilter(graph
, &filter1
.IBaseFilter_iface
, NULL
);
3607 IFilterGraph2_ConnectDirect(graph
, &source_pins
[0].IPin_iface
, &filter1_pin
.IPin_iface
, NULL
);
3609 hr
= check_ec_complete(graph
, &filter1
.IBaseFilter_iface
);
3610 ok(hr
== E_ABORT
, "Got hr %#x.\n", hr
);
3612 IMediaControl_Release(control
);
3613 IMediaEvent_Release(eventsrc
);
3614 IMediaEventSink_Release(eventsink
);
3615 hr
= IFilterGraph2_Release(graph
);
3616 ok(!hr
, "Got outstanding refcount %d.\n", hr
);
3617 ok(filter1
.ref
== 1, "Got outstanding refcount %d.\n", filter1
.ref
);
3618 ok(filter2
.ref
== 1, "Got outstanding refcount %d.\n", filter2
.ref
);
3619 ok(filter3
.ref
== 1, "Got outstanding refcount %d.\n", filter3
.ref
);
3622 /* Remove and re-add the filter, to flush the graph's internal
3623 * IMediaSeeking cache. Don't expose IMediaSeeking when adding, to show
3624 * that it's only queried when needed. */
3625 static void flush_cached_seeking(IFilterGraph2
*graph
, struct testfilter
*filter
)
3627 IFilterGraph2_RemoveFilter(graph
, &filter
->IBaseFilter_iface
);
3628 filter
->IMediaSeeking_iface
.lpVtbl
= NULL
;
3629 IFilterGraph2_AddFilter(graph
, &filter
->IBaseFilter_iface
, NULL
);
3630 filter
->IMediaSeeking_iface
.lpVtbl
= &testseek_vtbl
;
3633 static void test_graph_seeking(void)
3635 struct testfilter filter1
, filter2
;
3637 LONGLONG time
, current
, stop
, earliest
, latest
;
3638 IFilterGraph2
*graph
= create_graph();
3639 IMediaControl
*control
;
3640 IMediaSeeking
*seeking
;
3641 IMediaFilter
*filter
;
3649 static const GUID
*const all_formats
[] =
3654 &TIME_FORMAT_SAMPLE
,
3657 &TIME_FORMAT_MEDIA_TIME
,
3661 static const GUID
*const unsupported_formats
[] =
3664 &TIME_FORMAT_SAMPLE
,
3670 testfilter_init(&filter1
, NULL
, 0);
3671 testfilter_init(&filter2
, NULL
, 0);
3673 IFilterGraph2_QueryInterface(graph
, &IID_IMediaControl
, (void **)&control
);
3674 IFilterGraph2_QueryInterface(graph
, &IID_IMediaSeeking
, (void **)&seeking
);
3675 IFilterGraph2_QueryInterface(graph
, &IID_IMediaFilter
, (void **)&filter
);
3677 hr
= IMediaSeeking_GetCapabilities(seeking
, &caps
);
3678 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3679 todo_wine
ok(!caps
, "Got caps %#x.\n", caps
);
3682 hr
= IMediaSeeking_CheckCapabilities(seeking
, &caps
);
3683 todo_wine
ok(hr
== E_FAIL
, "Got hr %#x.\n", hr
);
3684 ok(!caps
, "Got caps %#x.\n", caps
);
3686 caps
= AM_SEEKING_CanSeekAbsolute
;
3687 hr
= IMediaSeeking_CheckCapabilities(seeking
, &caps
);
3688 todo_wine
ok(hr
== E_FAIL
, "Got hr %#x.\n", hr
);
3689 todo_wine
ok(!caps
, "Got caps %#x.\n", caps
);
3691 hr
= IMediaSeeking_IsFormatSupported(seeking
, NULL
);
3692 todo_wine
ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3694 for (i
= 0; i
< ARRAY_SIZE(all_formats
); ++i
)
3696 hr
= IMediaSeeking_IsFormatSupported(seeking
, all_formats
[i
]);
3697 todo_wine
ok(hr
== E_NOTIMPL
, "Got hr %#x for format %s.\n", hr
, wine_dbgstr_guid(all_formats
[i
]));
3700 hr
= IMediaSeeking_QueryPreferredFormat(seeking
, NULL
);
3701 ok(hr
== E_POINTER
, "Got hr %#x.\n", hr
);
3702 hr
= IMediaSeeking_QueryPreferredFormat(seeking
, &format
);
3703 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3704 ok(IsEqualGUID(&format
, &TIME_FORMAT_MEDIA_TIME
), "Got format %s.\n", wine_dbgstr_guid(&format
));
3706 hr
= IMediaSeeking_GetTimeFormat(seeking
, NULL
);
3707 ok(hr
== E_POINTER
, "Got hr %#x.\n", hr
);
3708 hr
= IMediaSeeking_GetTimeFormat(seeking
, &format
);
3709 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3710 ok(IsEqualGUID(&format
, &TIME_FORMAT_MEDIA_TIME
), "Got format %s.\n", wine_dbgstr_guid(&format
));
3712 hr
= IMediaSeeking_IsUsingTimeFormat(seeking
, NULL
);
3713 ok(hr
== E_POINTER
, "Got hr %#x.\n", hr
);
3714 hr
= IMediaSeeking_IsUsingTimeFormat(seeking
, &TIME_FORMAT_MEDIA_TIME
);
3715 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3716 hr
= IMediaSeeking_IsUsingTimeFormat(seeking
, &TIME_FORMAT_NONE
);
3717 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
3719 hr
= IMediaSeeking_SetTimeFormat(seeking
, &TIME_FORMAT_NONE
);
3720 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3722 hr
= IMediaSeeking_QueryPreferredFormat(seeking
, &format
);
3723 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3724 ok(IsEqualGUID(&format
, &TIME_FORMAT_MEDIA_TIME
), "Got format %s.\n", wine_dbgstr_guid(&format
));
3726 hr
= IMediaSeeking_IsUsingTimeFormat(seeking
, &TIME_FORMAT_MEDIA_TIME
);
3727 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3728 hr
= IMediaSeeking_IsUsingTimeFormat(seeking
, &TIME_FORMAT_NONE
);
3729 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
3731 hr
= IMediaSeeking_GetTimeFormat(seeking
, &format
);
3732 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3733 ok(IsEqualGUID(&format
, &TIME_FORMAT_MEDIA_TIME
), "Got format %s.\n", wine_dbgstr_guid(&format
));
3735 hr
= IMediaSeeking_SetTimeFormat(seeking
, &TIME_FORMAT_MEDIA_TIME
);
3736 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3738 for (i
= 0; i
< ARRAY_SIZE(unsupported_formats
); ++i
)
3740 hr
= IMediaSeeking_SetTimeFormat(seeking
, unsupported_formats
[i
]);
3741 todo_wine
ok(hr
== E_NOTIMPL
, "Got hr %#x for format %s.\n", hr
, wine_dbgstr_guid(unsupported_formats
[i
]));
3745 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &time
, NULL
, 0x123456789a, NULL
);
3746 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3747 ok(time
== 0x123456789a, "Got time %s.\n", wine_dbgstr_longlong(time
));
3750 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &time
, &TIME_FORMAT_MEDIA_TIME
, 0x123456789a, NULL
);
3751 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3752 ok(time
== 0x123456789a, "Got time %s.\n", wine_dbgstr_longlong(time
));
3755 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &time
, NULL
, 0x123456789a, &TIME_FORMAT_MEDIA_TIME
);
3756 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3757 ok(time
== 0x123456789a, "Got time %s.\n", wine_dbgstr_longlong(time
));
3760 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &time
, &TIME_FORMAT_MEDIA_TIME
, 0x123456789a, &TIME_FORMAT_MEDIA_TIME
);
3761 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3762 ok(time
== 0x123456789a, "Got time %s.\n", wine_dbgstr_longlong(time
));
3764 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &time
, &TIME_FORMAT_NONE
, 0x123456789a, &TIME_FORMAT_MEDIA_TIME
);
3765 todo_wine
ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3766 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &time
, &TIME_FORMAT_NONE
, 0x123456789a, NULL
);
3767 todo_wine
ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3768 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &time
, &TIME_FORMAT_MEDIA_TIME
, 0x123456789a, &TIME_FORMAT_NONE
);
3769 todo_wine
ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3770 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &time
, NULL
, 0x123456789a, &TIME_FORMAT_NONE
);
3771 todo_wine
ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3774 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &time
, &TIME_FORMAT_NONE
, 0x123456789a, &TIME_FORMAT_NONE
);
3775 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3776 ok(time
== 0x123456789a, "Got time %s.\n", wine_dbgstr_longlong(time
));
3779 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &time
, &testguid
, 0x123456789a, &testguid
);
3780 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3781 ok(time
== 0x123456789a, "Got time %s.\n", wine_dbgstr_longlong(time
));
3783 hr
= IMediaSeeking_GetDuration(seeking
, NULL
);
3784 ok(hr
== E_POINTER
, "Got hr %#x.\n", hr
);
3785 hr
= IMediaSeeking_GetDuration(seeking
, &time
);
3786 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3788 hr
= IMediaSeeking_GetStopPosition(seeking
, NULL
);
3789 ok(hr
== E_POINTER
, "Got hr %#x.\n", hr
);
3790 hr
= IMediaSeeking_GetStopPosition(seeking
, &time
);
3791 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3793 hr
= IMediaSeeking_SetPositions(seeking
, ¤t
, 0, &stop
, 0);
3794 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3796 hr
= IMediaSeeking_GetPositions(seeking
, NULL
, NULL
);
3797 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3798 hr
= IMediaSeeking_GetPositions(seeking
, NULL
, &stop
);
3799 todo_wine
ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3800 hr
= IMediaSeeking_GetPositions(seeking
, ¤t
, &stop
);
3801 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3802 current
= 0xdeadbeef;
3803 hr
= IMediaSeeking_GetPositions(seeking
, ¤t
, NULL
);
3804 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3805 ok(!current
, "Got time %s.\n", wine_dbgstr_longlong(time
));
3807 hr
= IMediaSeeking_GetCurrentPosition(seeking
, NULL
);
3808 ok(hr
== E_POINTER
, "Got hr %#x.\n", hr
);
3809 current
= 0xdeadbeef;
3810 hr
= IMediaSeeking_GetCurrentPosition(seeking
, ¤t
);
3811 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3812 ok(!current
, "Got time %s.\n", wine_dbgstr_longlong(time
));
3814 hr
= IMediaSeeking_GetAvailable(seeking
, &earliest
, &latest
);
3815 todo_wine
ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3817 hr
= IMediaSeeking_SetRate(seeking
, 1.0);
3818 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3819 hr
= IMediaSeeking_SetRate(seeking
, 2.0);
3820 todo_wine
ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3822 hr
= IMediaSeeking_GetRate(seeking
, &rate
);
3823 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3824 ok(rate
== 1.0, "Got rate %.16e.\n", rate
);
3826 hr
= IMediaSeeking_GetPreroll(seeking
, &time
);
3827 todo_wine
ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3829 /* Try with filters added. Note that a filter need only expose
3830 * IMediaSeeking—no other heuristics are used to determine if it is a
3833 IFilterGraph2_AddFilter(graph
, &filter1
.IBaseFilter_iface
, NULL
);
3834 IFilterGraph2_AddFilter(graph
, &filter2
.IBaseFilter_iface
, NULL
);
3835 filter1
.IMediaSeeking_iface
.lpVtbl
= &testseek_vtbl
;
3836 filter2
.IMediaSeeking_iface
.lpVtbl
= &testseek_vtbl
;
3838 filter1
.seek_caps
= AM_SEEKING_CanDoSegments
| AM_SEEKING_CanGetCurrentPos
;
3839 filter2
.seek_caps
= AM_SEEKING_CanDoSegments
| AM_SEEKING_CanGetDuration
;
3840 hr
= IMediaSeeking_GetCapabilities(seeking
, &caps
);
3841 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3842 ok(caps
== AM_SEEKING_CanDoSegments
, "Got caps %#x.\n", caps
);
3843 ok(filter1
.seeking_ref
> 0, "Unexpected seeking refcount %d.\n", filter1
.seeking_ref
);
3844 ok(filter2
.seeking_ref
> 0, "Unexpected seeking refcount %d.\n", filter2
.seeking_ref
);
3846 flush_cached_seeking(graph
, &filter1
);
3847 flush_cached_seeking(graph
, &filter2
);
3849 caps
= AM_SEEKING_CanDoSegments
| AM_SEEKING_CanGetCurrentPos
;
3850 hr
= IMediaSeeking_CheckCapabilities(seeking
, &caps
);
3851 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
3852 ok(caps
== AM_SEEKING_CanDoSegments
, "Got caps %#x.\n", caps
);
3854 caps
= AM_SEEKING_CanDoSegments
;
3855 hr
= IMediaSeeking_CheckCapabilities(seeking
, &caps
);
3856 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3857 ok(caps
== AM_SEEKING_CanDoSegments
, "Got caps %#x.\n", caps
);
3859 caps
= AM_SEEKING_CanGetCurrentPos
;
3860 hr
= IMediaSeeking_CheckCapabilities(seeking
, &caps
);
3861 ok(hr
== E_FAIL
, "Got hr %#x.\n", hr
);
3862 ok(!caps
, "Got caps %#x.\n", caps
);
3864 flush_cached_seeking(graph
, &filter1
);
3865 flush_cached_seeking(graph
, &filter2
);
3867 hr
= IMediaSeeking_IsFormatSupported(seeking
, &testguid
);
3868 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
3870 filter1
.support_testguid
= TRUE
;
3871 hr
= IMediaSeeking_IsFormatSupported(seeking
, &testguid
);
3872 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3874 filter1
.support_testguid
= FALSE
;
3875 filter2
.support_testguid
= TRUE
;
3876 hr
= IMediaSeeking_IsFormatSupported(seeking
, &testguid
);
3877 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3879 /* Filters are not consulted about preferred formats. */
3880 hr
= IMediaSeeking_QueryPreferredFormat(seeking
, &format
);
3881 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3882 ok(IsEqualGUID(&format
, &TIME_FORMAT_MEDIA_TIME
), "Got format %s.\n", wine_dbgstr_guid(&format
));
3884 hr
= IMediaSeeking_GetTimeFormat(seeking
, &format
);
3885 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3886 ok(IsEqualGUID(&format
, &TIME_FORMAT_MEDIA_TIME
), "Got format %s.\n", wine_dbgstr_guid(&format
));
3888 filter2
.support_testguid
= FALSE
;
3889 hr
= IMediaSeeking_SetTimeFormat(seeking
, &testguid
);
3890 todo_wine
ok(hr
== E_FAIL
, "Got hr %#x.\n", hr
);
3892 hr
= IMediaSeeking_GetTimeFormat(seeking
, &format
);
3893 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3894 ok(IsEqualGUID(&format
, &TIME_FORMAT_MEDIA_TIME
), "Got format %s.\n", wine_dbgstr_guid(&format
));
3896 filter1
.support_testguid
= TRUE
;
3897 hr
= IMediaSeeking_SetTimeFormat(seeking
, &testguid
);
3898 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3900 hr
= IMediaSeeking_GetTimeFormat(seeking
, &format
);
3901 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3902 todo_wine
ok(IsEqualGUID(&format
, &testguid
), "Got format %s.\n", wine_dbgstr_guid(&format
));
3904 hr
= IMediaSeeking_QueryPreferredFormat(seeking
, &format
);
3905 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3906 ok(IsEqualGUID(&format
, &TIME_FORMAT_MEDIA_TIME
), "Got format %s.\n", wine_dbgstr_guid(&format
));
3908 hr
= IMediaSeeking_IsUsingTimeFormat(seeking
, &TIME_FORMAT_MEDIA_TIME
);
3909 todo_wine
ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
3910 hr
= IMediaSeeking_IsUsingTimeFormat(seeking
, &testguid
);
3911 todo_wine
ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3913 hr
= IMediaSeeking_SetTimeFormat(seeking
, &TIME_FORMAT_MEDIA_TIME
);
3914 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3917 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &time
, &testguid
, 0x123456789a, &testguid
);
3918 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3919 ok(time
== 0x123456789a, "Got time %s.\n", wine_dbgstr_longlong(time
));
3921 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &time
, &testguid
, 0x123456789a, &TIME_FORMAT_NONE
);
3922 todo_wine
ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3924 flush_cached_seeking(graph
, &filter1
);
3925 flush_cached_seeking(graph
, &filter2
);
3927 filter1
.seek_duration
= 0x12345;
3928 filter2
.seek_duration
= 0x23456;
3929 hr
= IMediaSeeking_GetDuration(seeking
, &time
);
3930 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3931 ok(time
== 0x23456, "Got time %s.\n", wine_dbgstr_longlong(time
));
3933 filter2
.seek_duration
= 0x12345;
3934 filter1
.seek_duration
= 0x23456;
3935 hr
= IMediaSeeking_GetDuration(seeking
, &time
);
3936 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3937 ok(time
== 0x23456, "Got time %s.\n", wine_dbgstr_longlong(time
));
3939 flush_cached_seeking(graph
, &filter1
);
3940 flush_cached_seeking(graph
, &filter2
);
3942 filter1
.seek_stop
= 0x54321;
3943 filter2
.seek_stop
= 0x65432;
3944 hr
= IMediaSeeking_GetStopPosition(seeking
, &time
);
3945 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3946 ok(time
== 0x65432, "Got time %s.\n", wine_dbgstr_longlong(time
));
3948 filter2
.seek_stop
= 0x54321;
3949 filter1
.seek_stop
= 0x65432;
3950 hr
= IMediaSeeking_GetStopPosition(seeking
, &time
);
3951 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3952 ok(time
== 0x65432, "Got time %s.\n", wine_dbgstr_longlong(time
));
3954 filter1
.seek_hr
= filter2
.seek_hr
= 0xbeef;
3955 hr
= IMediaSeeking_GetStopPosition(seeking
, &time
);
3956 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3957 ok(time
== 0x65432, "Got time %s.\n", wine_dbgstr_longlong(time
));
3959 filter1
.seek_hr
= E_NOTIMPL
;
3960 hr
= IMediaSeeking_GetStopPosition(seeking
, &time
);
3961 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3962 ok(time
== 0x54321, "Got time %s.\n", wine_dbgstr_longlong(time
));
3964 filter1
.seek_hr
= 0xdeadbeef;
3965 hr
= IMediaSeeking_GetStopPosition(seeking
, &time
);
3966 ok(hr
== 0xdeadbeef, "Got hr %#x.\n", hr
);
3968 filter1
.seek_hr
= filter2
.seek_hr
= E_NOTIMPL
;
3969 hr
= IMediaSeeking_GetStopPosition(seeking
, &time
);
3970 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
3971 filter1
.seek_hr
= filter2
.seek_hr
= S_OK
;
3973 flush_cached_seeking(graph
, &filter1
);
3974 flush_cached_seeking(graph
, &filter2
);
3976 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &time
);
3977 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3978 ok(!time
, "Got time %s.\n", wine_dbgstr_longlong(time
));
3980 flush_cached_seeking(graph
, &filter1
);
3981 flush_cached_seeking(graph
, &filter2
);
3983 current
= stop
= 0xdeadbeef;
3984 hr
= IMediaSeeking_GetPositions(seeking
, ¤t
, &stop
);
3985 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3986 ok(!current
, "Got time %s.\n", wine_dbgstr_longlong(current
));
3987 ok(stop
== 0x65432, "Got time %s.\n", wine_dbgstr_longlong(stop
));
3989 flush_cached_seeking(graph
, &filter1
);
3990 flush_cached_seeking(graph
, &filter2
);
3994 hr
= IMediaSeeking_SetPositions(seeking
, ¤t
, AM_SEEKING_AbsolutePositioning
,
3995 &stop
, AM_SEEKING_AbsolutePositioning
);
3996 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
3997 ok(current
== 0x123, "Got time %s.\n", wine_dbgstr_longlong(current
));
3998 ok(stop
== 0x321, "Got time %s.\n", wine_dbgstr_longlong(stop
));
3999 ok(filter1
.seek_current
== 0x123, "Got time %s.\n", wine_dbgstr_longlong(filter1
.seek_current
));
4000 ok(filter1
.seek_stop
== 0x321, "Got time %s.\n", wine_dbgstr_longlong(filter1
.seek_stop
));
4001 ok(filter2
.seek_current
== 0x123, "Got time %s.\n", wine_dbgstr_longlong(filter2
.seek_current
));
4002 ok(filter2
.seek_stop
== 0x321, "Got time %s.\n", wine_dbgstr_longlong(filter2
.seek_stop
));
4004 filter1
.seek_hr
= filter2
.seek_hr
= 0xbeef;
4005 hr
= IMediaSeeking_SetPositions(seeking
, ¤t
, AM_SEEKING_AbsolutePositioning
,
4006 &stop
, AM_SEEKING_AbsolutePositioning
);
4007 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4009 filter1
.seek_hr
= E_NOTIMPL
;
4010 hr
= IMediaSeeking_SetPositions(seeking
, ¤t
, AM_SEEKING_AbsolutePositioning
,
4011 &stop
, AM_SEEKING_AbsolutePositioning
);
4012 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4014 filter1
.seek_hr
= 0xdeadbeef;
4015 hr
= IMediaSeeking_SetPositions(seeking
, ¤t
, AM_SEEKING_AbsolutePositioning
,
4016 &stop
, AM_SEEKING_AbsolutePositioning
);
4017 ok(hr
== 0xdeadbeef, "Got hr %#x.\n", hr
);
4019 filter1
.seek_hr
= filter2
.seek_hr
= E_NOTIMPL
;
4020 hr
= IMediaSeeking_SetPositions(seeking
, ¤t
, AM_SEEKING_AbsolutePositioning
,
4021 &stop
, AM_SEEKING_AbsolutePositioning
);
4022 ok(hr
== E_NOTIMPL
, "Got hr %#x.\n", hr
);
4023 filter1
.seek_hr
= filter2
.seek_hr
= S_OK
;
4025 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &time
);
4026 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4027 ok(time
== 12340000, "Got time %s.\n", wine_dbgstr_longlong(time
));
4029 current
= stop
= 0xdeadbeef;
4030 hr
= IMediaSeeking_GetPositions(seeking
, ¤t
, &stop
);
4031 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4032 ok(current
== 12340000, "Got time %s.\n", wine_dbgstr_longlong(current
));
4033 ok(stop
== 0x321, "Got time %s.\n", wine_dbgstr_longlong(stop
));
4037 hr
= IMediaSeeking_SetPositions(seeking
, ¤t
, AM_SEEKING_AbsolutePositioning
| AM_SEEKING_ReturnTime
,
4038 &stop
, AM_SEEKING_AbsolutePositioning
);
4039 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4040 ok(current
== 12340000, "Got time %s.\n", wine_dbgstr_longlong(current
));
4041 ok(stop
== 0x321, "Got time %s.\n", wine_dbgstr_longlong(stop
));
4042 ok(filter1
.seek_current
== 12340000, "Got time %s.\n", wine_dbgstr_longlong(filter1
.seek_current
));
4043 ok(filter1
.seek_stop
== 0x321, "Got time %s.\n", wine_dbgstr_longlong(filter1
.seek_stop
));
4044 ok(filter2
.seek_current
== 0x123, "Got time %s.\n", wine_dbgstr_longlong(filter2
.seek_current
));
4045 ok(filter2
.seek_stop
== 0x321, "Got time %s.\n", wine_dbgstr_longlong(filter2
.seek_stop
));
4049 hr
= IMediaSeeking_SetPositions(seeking
, ¤t
, AM_SEEKING_AbsolutePositioning
,
4050 &stop
, AM_SEEKING_AbsolutePositioning
| AM_SEEKING_ReturnTime
);
4051 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4052 ok(current
== 0x123, "Got time %s.\n", wine_dbgstr_longlong(current
));
4053 ok(stop
== 43210000, "Got time %s.\n", wine_dbgstr_longlong(stop
));
4054 ok(filter1
.seek_current
== 0x123, "Got time %s.\n", wine_dbgstr_longlong(filter1
.seek_current
));
4055 ok(filter1
.seek_stop
== 43210000, "Got time %s.\n", wine_dbgstr_longlong(filter1
.seek_stop
));
4056 ok(filter2
.seek_current
== 0x123, "Got time %s.\n", wine_dbgstr_longlong(filter2
.seek_current
));
4057 ok(filter2
.seek_stop
== 0x321, "Got time %s.\n", wine_dbgstr_longlong(filter2
.seek_stop
));
4059 flush_cached_seeking(graph
, &filter1
);
4060 flush_cached_seeking(graph
, &filter2
);
4062 hr
= IMediaSeeking_SetRate(seeking
, 2.0);
4063 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4064 todo_wine
ok(filter1
.seek_rate
== 2.0, "Got rate %.16e.\n", filter1
.seek_rate
);
4065 todo_wine
ok(filter2
.seek_rate
== 2.0, "Got rate %.16e.\n", filter2
.seek_rate
);
4067 hr
= IMediaSeeking_SetRate(seeking
, 1.0);
4068 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4069 todo_wine
ok(filter1
.seek_rate
== 1.0, "Got rate %.16e.\n", filter1
.seek_rate
);
4070 todo_wine
ok(filter2
.seek_rate
== 1.0, "Got rate %.16e.\n", filter2
.seek_rate
);
4072 hr
= IMediaSeeking_SetRate(seeking
, -1.0);
4073 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4074 todo_wine
ok(filter1
.seek_rate
== -1.0, "Got rate %.16e.\n", filter1
.seek_rate
);
4075 todo_wine
ok(filter2
.seek_rate
== -1.0, "Got rate %.16e.\n", filter2
.seek_rate
);
4077 flush_cached_seeking(graph
, &filter1
);
4078 flush_cached_seeking(graph
, &filter2
);
4080 hr
= IMediaSeeking_GetRate(seeking
, &rate
);
4081 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4082 todo_wine
ok(rate
== -1.0, "Got rate %.16e.\n", rate
);
4084 hr
= IMediaSeeking_SetRate(seeking
, 1.0);
4085 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4087 /* Test how retrieving the current position behaves while the graph is
4088 * running. Apparently the graph caches the last position returned by
4089 * SetPositions() and then adds the clock offset to the stream start. */
4091 hr
= IMediaControl_Run(control
);
4092 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4094 /* Note that if the graph is running, it is paused while seeking. */
4096 stop
= 9000 * 10000;
4097 hr
= IMediaSeeking_SetPositions(seeking
, ¤t
, AM_SEEKING_AbsolutePositioning
,
4098 &stop
, AM_SEEKING_AbsolutePositioning
);
4099 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4101 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &time
);
4102 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4103 if (winetest_interactive
) /* Timing problems make this test too liable to fail. */
4104 ok(compare_time(time
, 1234 * 10000, 40 * 10000),
4105 "Expected about 1234ms, got %s.\n", wine_dbgstr_longlong(time
));
4106 current
= stop
= 0xdeadbeef;
4107 hr
= IMediaSeeking_GetPositions(seeking
, ¤t
, &stop
);
4108 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4109 if (winetest_interactive
) /* Timing problems make this test too liable to fail. */
4110 ok(compare_time(current
, 1234 * 10000, 40 * 10000),
4111 "Expected about 1234ms, got %s.\n", wine_dbgstr_longlong(current
));
4112 ok(stop
== 9000 * 10000, "Got time %s.\n", wine_dbgstr_longlong(stop
));
4114 /* This remains true even if NoFlush is specified. */
4115 current
= 1000 * 10000;
4116 stop
= 8000 * 10000;
4117 hr
= IMediaSeeking_SetPositions(seeking
, ¤t
,
4118 AM_SEEKING_AbsolutePositioning
| AM_SEEKING_NoFlush
,
4119 &stop
, AM_SEEKING_AbsolutePositioning
| AM_SEEKING_NoFlush
);
4120 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4124 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &time
);
4125 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4126 if (winetest_interactive
) /* Timing problems make this test too liable to fail. */
4127 ok(compare_time(time
, 1334 * 10000, 80 * 10000),
4128 "Expected about 1334ms, got %s.\n", wine_dbgstr_longlong(time
));
4129 current
= stop
= 0xdeadbeef;
4130 hr
= IMediaSeeking_GetPositions(seeking
, ¤t
, &stop
);
4131 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4132 if (winetest_interactive
) /* Timing problems make this test too liable to fail. */
4133 ok(compare_time(current
, 1334 * 10000, 80 * 10000),
4134 "Expected about 1334ms, got %s.\n", wine_dbgstr_longlong(current
));
4135 ok(stop
== 8000 * 10000, "Got time %s.\n", wine_dbgstr_longlong(stop
));
4137 hr
= IMediaControl_Pause(control
);
4138 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4141 hr
= IMediaControl_Run(control
);
4142 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4144 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &time
);
4145 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4146 if (winetest_interactive
) /* Timing problems make this test too liable to fail. */
4147 ok(compare_time(time
, 1334 * 10000, 80 * 10000),
4148 "Expected about 1334ms, got %s.\n", wine_dbgstr_longlong(time
));
4149 current
= stop
= 0xdeadbeef;
4150 hr
= IMediaSeeking_GetPositions(seeking
, ¤t
, &stop
);
4151 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4152 if (winetest_interactive
) /* Timing problems make this test too liable to fail. */
4153 ok(compare_time(current
, 1334 * 10000, 80 * 10000),
4154 "Expected about 1334ms, got %s.\n", wine_dbgstr_longlong(current
));
4155 ok(stop
== 8000 * 10000, "Got time %s.\n", wine_dbgstr_longlong(stop
));
4157 hr
= IMediaControl_Stop(control
);
4158 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4159 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &time
);
4160 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4161 ok(time
== 12340000, "Got time %s.\n", wine_dbgstr_longlong(time
));
4163 hr
= IMediaFilter_SetSyncSource(filter
, NULL
);
4164 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4166 hr
= IMediaControl_Run(control
);
4167 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4170 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &time
);
4171 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4172 todo_wine
ok(!time
, "Got time %s.\n", wine_dbgstr_longlong(time
));
4173 current
= stop
= 0xdeadbeef;
4174 hr
= IMediaSeeking_GetPositions(seeking
, ¤t
, &stop
);
4175 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4176 todo_wine
ok(!current
, "Got time %s.\n", wine_dbgstr_longlong(current
));
4177 ok(!stop
, "Got time %s.\n", wine_dbgstr_longlong(stop
));
4179 hr
= IMediaControl_Stop(control
);
4180 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4182 IMediaFilter_Release(filter
);
4183 IMediaControl_Release(control
);
4184 IMediaSeeking_Release(seeking
);
4186 ok(filter1
.seeking_ref
> 0, "Unexpected seeking refcount %d.\n", filter1
.seeking_ref
);
4187 ok(filter2
.seeking_ref
> 0, "Unexpected seeking refcount %d.\n", filter2
.seeking_ref
);
4189 ref
= IFilterGraph2_Release(graph
);
4190 ok(!ref
, "Got outstanding refcount %d.\n", hr
);
4191 ok(filter1
.ref
== 1, "Got outstanding refcount %d.\n", filter1
.ref
);
4192 ok(filter2
.ref
== 1, "Got outstanding refcount %d.\n", filter2
.ref
);
4193 ok(filter1
.seeking_ref
== 0, "Unexpected seeking refcount %d.\n", filter1
.seeking_ref
);
4194 ok(filter2
.seeking_ref
== 0, "Unexpected seeking refcount %d.\n", filter2
.seeking_ref
);
4197 static void test_default_sync_source(void)
4199 struct testpin source_pin
, sink1_pin
, sink2_pin
;
4200 struct testfilter source
, sink1
, sink2
;
4202 IFilterGraph2
*graph
= create_graph();
4203 IReferenceClock
*clock
;
4204 IMediaFilter
*filter
;
4208 testsink_init(&sink1_pin
);
4209 testsink_init(&sink2_pin
);
4210 testsource_init(&source_pin
, NULL
, 0);
4211 testfilter_init(&source
, &source_pin
, 1);
4212 testfilter_init(&sink1
, &sink1_pin
, 1);
4213 testfilter_init(&sink2
, &sink2_pin
, 1);
4215 IFilterGraph2_AddFilter(graph
, &sink1
.IBaseFilter_iface
, NULL
);
4216 IFilterGraph2_AddFilter(graph
, &sink2
.IBaseFilter_iface
, NULL
);
4217 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
4218 IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink1_pin
.IPin_iface
, NULL
);
4220 IFilterGraph2_QueryInterface(graph
, &IID_IMediaFilter
, (void **)&filter
);
4222 hr
= IFilterGraph2_SetDefaultSyncSource(graph
);
4223 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4225 hr
= IMediaFilter_GetSyncSource(filter
, &clock
);
4226 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4227 ok(!!clock
, "Reference clock not set.\n");
4228 IReferenceClock_Release(clock
);
4230 source
.IReferenceClock_iface
.lpVtbl
= &testclock_vtbl
;
4232 hr
= IFilterGraph2_SetDefaultSyncSource(graph
);
4233 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4235 hr
= IMediaFilter_GetSyncSource(filter
, &clock
);
4236 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4237 ok(clock
== &source
.IReferenceClock_iface
, "Got unexpected clock.\n");
4238 IReferenceClock_Release(clock
);
4240 /* The documentation says that connected filters are preferred, but this
4241 * does not in fact seem to be the case. */
4243 sink2
.IReferenceClock_iface
.lpVtbl
= &testclock_vtbl
;
4245 hr
= IFilterGraph2_SetDefaultSyncSource(graph
);
4246 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4248 hr
= IMediaFilter_GetSyncSource(filter
, &clock
);
4249 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4250 todo_wine
ok(clock
== &sink2
.IReferenceClock_iface
, "Got unexpected clock.\n");
4251 IReferenceClock_Release(clock
);
4253 sink1
.IReferenceClock_iface
.lpVtbl
= &testclock_vtbl
;
4255 hr
= IFilterGraph2_SetDefaultSyncSource(graph
);
4256 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4258 hr
= IMediaFilter_GetSyncSource(filter
, &clock
);
4259 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4260 todo_wine
ok(clock
== &sink1
.IReferenceClock_iface
, "Got unexpected clock.\n");
4261 IReferenceClock_Release(clock
);
4263 IMediaFilter_Release(filter
);
4264 ref
= IFilterGraph2_Release(graph
);
4265 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
4266 ok(sink1
.ref
== 1, "Got outstanding refcount %d.\n", sink1
.ref
);
4267 ok(sink2
.ref
== 1, "Got outstanding refcount %d.\n", sink2
.ref
);
4268 ok(source
.ref
== 1, "Got outstanding refcount %d.\n", source
.ref
);
4271 static void test_add_source_filter(void)
4273 static const char bogus_data
[20] = {0xde, 0xad, 0xbe, 0xef};
4274 static const char midi_data
[20] = {'M','T','h','d'};
4276 IFilterGraph2
*graph
= create_graph();
4277 IFileSourceFilter
*filesource
;
4278 IBaseFilter
*filter
, *filter2
;
4279 FILTER_INFO filter_info
;
4280 const WCHAR
*filename
;
4281 WCHAR
*ret_filename
;
4289 /* Test a file which should be registered by extension. */
4291 filename
= create_file(L
"test.mp3", midi_data
, sizeof(midi_data
));
4292 hr
= IFilterGraph2_AddSourceFilter(graph
, filename
, L
"test", &filter
);
4293 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4295 hr
= IBaseFilter_GetClassID(filter
, &clsid
);
4296 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4297 ok(IsEqualGUID(&clsid
, &CLSID_AsyncReader
), "Got filter %s.\n", wine_dbgstr_guid(&clsid
));
4298 hr
= IBaseFilter_QueryFilterInfo(filter
, &filter_info
);
4299 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4300 ok(!wcscmp(filter_info
.achName
, L
"test"), "Got unexpected name %s.\n", wine_dbgstr_w(filter_info
.achName
));
4301 IFilterGraph_Release(filter_info
.pGraph
);
4303 hr
= IBaseFilter_QueryInterface(filter
, &IID_IFileSourceFilter
, (void **)&filesource
);
4304 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4305 hr
= IFileSourceFilter_GetCurFile(filesource
, &ret_filename
, &mt
);
4306 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4307 ok(!wcscmp(ret_filename
, filename
), "Expected filename %s, got %s.\n",
4308 wine_dbgstr_w(filename
), wine_dbgstr_w(ret_filename
));
4309 ok(IsEqualGUID(&mt
.majortype
, &MEDIATYPE_Stream
), "Got major type %s.\n", wine_dbgstr_guid(&mt
.majortype
));
4310 ok(IsEqualGUID(&mt
.subtype
, &MEDIASUBTYPE_MPEG1Audio
), "Got subtype %s.\n", wine_dbgstr_guid(&mt
.subtype
));
4311 IFileSourceFilter_Release(filesource
);
4313 hr
= IFilterGraph2_AddSourceFilter(graph
, filename
, L
"test", &filter2
);
4314 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4315 ok(filter2
!= filter
, "Filters shouldn't match.\n");
4316 hr
= IFilterGraph2_RemoveFilter(graph
, filter2
);
4317 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4318 ref
= IBaseFilter_Release(filter2
);
4319 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
4321 hr
= IFilterGraph2_RemoveFilter(graph
, filter
);
4322 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4323 ref
= IBaseFilter_Release(filter
);
4324 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
4325 ret
= DeleteFileW(filename
);
4326 ok(ret
, "Failed to delete %s, error %u.\n", wine_dbgstr_w(filename
), GetLastError());
4328 /* Test a file which should be registered by signature. */
4330 filename
= create_file(L
"test.avi", midi_data
, sizeof(midi_data
));
4331 hr
= IFilterGraph2_AddSourceFilter(graph
, filename
, NULL
, &filter
);
4332 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4334 hr
= IBaseFilter_GetClassID(filter
, &clsid
);
4335 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4336 ok(IsEqualGUID(&clsid
, &CLSID_AsyncReader
), "Got filter %s.\n", wine_dbgstr_guid(&clsid
));
4337 hr
= IBaseFilter_QueryFilterInfo(filter
, &filter_info
);
4338 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4339 todo_wine
ok(!wcscmp(filter_info
.achName
, filename
), "Got unexpected name %s.\n", wine_dbgstr_w(filter_info
.achName
));
4340 IFilterGraph_Release(filter_info
.pGraph
);
4342 hr
= IBaseFilter_QueryInterface(filter
, &IID_IFileSourceFilter
, (void **)&filesource
);
4343 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4344 hr
= IFileSourceFilter_GetCurFile(filesource
, &ret_filename
, &mt
);
4345 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4346 ok(!wcscmp(ret_filename
, filename
), "Expected filename %s, got %s.\n",
4347 wine_dbgstr_w(filename
), wine_dbgstr_w(ret_filename
));
4348 ok(IsEqualGUID(&mt
.majortype
, &MEDIATYPE_Stream
), "Got major type %s.\n", wine_dbgstr_guid(&mt
.majortype
));
4349 ok(IsEqualGUID(&mt
.subtype
, &MEDIATYPE_Midi
), "Got subtype %s.\n", wine_dbgstr_guid(&mt
.subtype
));
4350 IFileSourceFilter_Release(filesource
);
4352 hr
= IFilterGraph2_RemoveFilter(graph
, filter
);
4353 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4354 ref
= IBaseFilter_Release(filter
);
4355 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
4356 ret
= DeleteFileW(filename
);
4357 ok(ret
, "Failed to delete %s, error %u.\n", wine_dbgstr_w(filename
), GetLastError());
4359 if (!RegCreateKeyA(HKEY_CLASSES_ROOT
, "Media Type\\{abbccdde-0000-0000-0000-000000000000}"
4360 "\\{bccddeef-0000-0000-0000-000000000000}", &key
))
4362 static const GUID testfilter_clsid
= {0x12345678};
4363 struct testpin testfilter_pin
;
4364 struct testfilter testfilter
;
4365 struct testfilter_cf cf
= {{&testfilter_cf_vtbl
}, &testfilter
};
4368 testsource_init(&testfilter_pin
, NULL
, 0);
4369 testfilter_init(&testfilter
, &testfilter_pin
, 1);
4370 testfilter
.IFileSourceFilter_iface
.lpVtbl
= &testfilesource_vtbl
;
4372 CoRegisterClassObject(&testfilter_clsid
, (IUnknown
*)&cf
.IClassFactory_iface
,
4373 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie
);
4374 RegSetValueExA(key
, "0", 0, REG_SZ
, (const BYTE
*)"0,4,,deadbeef", 14);
4375 RegSetValueExA(key
, "Source Filter", 0, REG_SZ
, (const BYTE
*)"{12345678-0000-0000-0000-000000000000}", 39);
4377 filename
= create_file(L
"test.avi", bogus_data
, sizeof(bogus_data
));
4378 hr
= IFilterGraph2_AddSourceFilter(graph
, filename
, NULL
, &filter
);
4379 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4380 ok(filter
== &testfilter
.IBaseFilter_iface
, "Got unexpected filter %p.\n", filter
);
4382 hr
= IFilterGraph2_RemoveFilter(graph
, filter
);
4383 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4384 IBaseFilter_Release(filter
);
4385 ref
= IBaseFilter_Release(&testfilter
.IBaseFilter_iface
);
4386 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
4387 ret
= DeleteFileW(filename
);
4388 ok(ret
, "Failed to delete %s, error %u.\n", wine_dbgstr_w(filename
), GetLastError());
4389 RegDeleteKeyA(HKEY_CLASSES_ROOT
, "Media Type\\{abbccdde-0000-0000-0000-000000000000}"
4390 "\\{bccddeef-0000-0000-0000-000000000000}");
4391 RegDeleteKeyA(HKEY_CLASSES_ROOT
, "Media Type\\{abbccdde-0000-0000-0000-000000000000}");
4392 CoRevokeClassObject(cookie
);
4395 skip("Not enough permission to register media types.\n");
4397 ref
= IFilterGraph2_Release(graph
);
4398 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
4401 static HWND
get_renderer_hwnd(IFilterGraph2
*graph
)
4403 IEnumFilters
*enum_filters
;
4404 IEnumPins
*enum_pins
;
4405 IBaseFilter
*filter
;
4411 hr
= IFilterGraph2_EnumFilters(graph
, &enum_filters
);
4412 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4414 while (IEnumFilters_Next(enum_filters
, 1, &filter
, NULL
) == S_OK
)
4416 hr
= IBaseFilter_EnumPins(filter
, &enum_pins
);
4417 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4418 hr
= IEnumPins_Next(enum_pins
, 1, &pin
, NULL
);
4419 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4420 IEnumPins_Release(enum_pins
);
4422 if (SUCCEEDED(IPin_QueryInterface(pin
, &IID_IOverlay
, (void **)&overlay
)))
4424 hr
= IOverlay_GetWindowHandle(overlay
, &hwnd
);
4425 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4426 IOverlay_Release(overlay
);
4430 IBaseFilter_Release(filter
);
4433 IEnumFilters_Release(enum_filters
);
4438 static BOOL expect_parent_message
= TRUE
;
4440 static LRESULT CALLBACK
parent_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
4442 ok(expect_parent_message
, "Got unexpected message %#x.\n", msg
);
4443 return DefWindowProcA(hwnd
, msg
, wparam
, lparam
);
4446 static void test_window_threading(void)
4448 static const WNDCLASSA
class =
4450 .lpfnWndProc
= parent_proc
,
4451 .lpszClassName
= "quartz_test_parent",
4453 WCHAR
*filename
= load_resource(L
"test.avi");
4454 IFilterGraph2
*graph
= create_graph();
4455 IVideoWindow
*window
;
4462 RegisterClassA(&class);
4464 parent
= CreateWindowA("quartz_test_parent", NULL
, WS_OVERLAPPEDWINDOW
,
4465 50, 50, 150, 150, NULL
, NULL
, NULL
, NULL
);
4466 ok(!!parent
, "Failed to create parent window.\n");
4468 hr
= IFilterGraph2_RenderFile(graph
, filename
, NULL
);
4471 skip("Cannot render test file, hr %#x.\n", hr
);
4472 IFilterGraph2_Release(graph
);
4473 DeleteFileW(filename
);
4476 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4478 if ((hwnd
= get_renderer_hwnd(graph
)))
4480 tid
= GetWindowThreadProcessId(hwnd
, NULL
);
4481 ok(tid
!= GetCurrentThreadId(), "Window should have been created on a separate thread.\n");
4483 /* The thread should be processing messages, or this will hang. */
4484 SendMessageA(hwnd
, WM_NULL
, 0, 0);
4486 /* Media Player Classic deadlocks if the parent is sent any messages
4487 * while the video window is released. In particular, we must not send
4488 * WM_PARENTNOTIFY. This is not achieved through window styles. */
4489 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IVideoWindow
, (void **)&window
);
4490 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4491 hr
= IVideoWindow_put_Owner(window
, (OAHWND
)parent
);
4492 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4493 IVideoWindow_Release(window
);
4494 ok(!(GetWindowLongW(hwnd
, GWL_EXSTYLE
) & WS_EX_NOPARENTNOTIFY
), "Window has WS_EX_NOPARENTNOTIFY.\n");
4497 skip("Could not find renderer window.\n");
4499 SetActiveWindow(parent
);
4500 expect_parent_message
= FALSE
;
4501 ref
= IFilterGraph2_Release(graph
);
4502 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
4503 expect_parent_message
= TRUE
;
4505 hwnd
= GetActiveWindow();
4506 ok(hwnd
== parent
, "Parent window lost focus, active window %p.\n", hwnd
);
4508 hr
= CoCreateInstance(&CLSID_FilterGraphNoThread
, NULL
, CLSCTX_INPROC_SERVER
,
4509 &IID_IFilterGraph2
, (void **)&graph
);
4510 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4512 hr
= IFilterGraph2_RenderFile(graph
, filename
, NULL
);
4513 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
4515 if ((hwnd
= get_renderer_hwnd(graph
)))
4517 tid
= GetWindowThreadProcessId(hwnd
, NULL
);
4518 ok(tid
== GetCurrentThreadId(), "Window should be created on main thread.\n");
4521 skip("Could not find renderer window.\n");
4523 ref
= IFilterGraph2_Release(graph
);
4524 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
4526 DestroyWindow(parent
);
4527 UnregisterClassA("quartz_test_parent", GetModuleHandleA(NULL
));
4528 ret
= DeleteFileW(filename
);
4529 ok(ret
, "Failed to delete file, error %u.\n", GetLastError());
4532 /* Hyperdevotion Noire needs to be able to Render() from UYVY. */
4533 static void test_autoplug_uyvy(void)
4535 static const VIDEOINFOHEADER source_format
=
4537 .bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
),
4538 .bmiHeader
.biWidth
= 600,
4539 .bmiHeader
.biHeight
= 400,
4540 .bmiHeader
.biCompression
= mmioFOURCC('U','Y','V','Y'),
4541 .bmiHeader
.biBitCount
= 16,
4543 AM_MEDIA_TYPE source_type
=
4545 .majortype
= MEDIATYPE_Video
,
4546 .subtype
= MEDIASUBTYPE_UYVY
,
4547 .formattype
= FORMAT_VideoInfo
,
4548 .cbFormat
= sizeof(source_format
),
4549 .pbFormat
= (BYTE
*)&source_format
,
4552 IFilterGraph2
*graph
= create_graph();
4553 struct testpin source_pin
;
4554 struct testfilter source
;
4558 testsource_init(&source_pin
, NULL
, 0);
4559 testfilter_init(&source
, &source_pin
, 1);
4560 source_pin
.request_mt
= &source_type
;
4562 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, L
"source");
4564 /* Windows 2008 doesn't seem to have an UYVY decoder, and the testbot chalks
4565 * failure to decode up to missing audio hardware, even though we're not
4566 * trying to render audio. */
4567 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
4568 todo_wine
ok(hr
== S_OK
|| hr
== VFW_E_NO_AUDIO_HARDWARE
, "Got hr %#x.\n", hr
);
4570 ref
= IFilterGraph2_Release(graph
);
4571 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
4572 ok(source
.ref
== 1, "Got outstanding refcount %d.\n", source
.ref
);
4573 ok(source_pin
.ref
== 1, "Got outstanding refcount %d.\n", source_pin
.ref
);
4576 START_TEST(filtergraph
)
4578 CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
4581 test_render_run(L
"test.avi", FALSE
, TRUE
);
4582 test_render_run(L
"test.mpg", TRUE
, TRUE
);
4583 test_render_run(L
"test.mp3", TRUE
, FALSE
);
4584 test_render_run(L
"test.wav", TRUE
, FALSE
);
4585 test_enum_filters();
4586 test_graph_builder_render();
4587 test_graph_builder_connect();
4589 test_control_delegation();
4590 test_add_remove_filter();
4591 test_connect_direct();
4593 test_filter_state();
4595 test_graph_seeking();
4596 test_default_sync_source();
4597 test_add_source_filter();
4598 test_window_threading();
4599 test_autoplug_uyvy();
4602 test_render_with_multithread();