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 typedef struct TestFilterImpl
31 IBaseFilter IBaseFilter_iface
;
34 CRITICAL_SECTION csFilter
;
36 FILTER_INFO filterInfo
;
42 static const WCHAR avifile
[] = {'t','e','s','t','.','a','v','i',0};
43 static const WCHAR mpegfile
[] = {'t','e','s','t','.','m','p','g',0};
45 static WCHAR
*load_resource(const WCHAR
*name
)
47 static WCHAR pathW
[MAX_PATH
];
53 GetTempPathW(ARRAY_SIZE(pathW
), pathW
);
54 lstrcatW(pathW
, name
);
56 file
= CreateFileW(pathW
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, 0);
57 ok(file
!= INVALID_HANDLE_VALUE
, "file creation failed, at %s, error %d\n", wine_dbgstr_w(pathW
),
60 res
= FindResourceW(NULL
, name
, (LPCWSTR
)RT_RCDATA
);
61 ok( res
!= 0, "couldn't find resource\n" );
62 ptr
= LockResource( LoadResource( GetModuleHandleA(NULL
), res
));
63 WriteFile( file
, ptr
, SizeofResource( GetModuleHandleA(NULL
), res
), &written
, NULL
);
64 ok( written
== SizeofResource( GetModuleHandleA(NULL
), res
), "couldn't write resource\n" );
70 static IFilterGraph2
*create_graph(void)
74 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterGraph2
, (void **)&ret
);
75 ok(hr
== S_OK
, "Failed to create FilterGraph: %#x\n", hr
);
79 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
80 static void check_interface_(unsigned int line
, void *iface_ptr
, REFIID iid
, BOOL supported
)
82 IUnknown
*iface
= iface_ptr
;
83 HRESULT hr
, expected_hr
;
86 expected_hr
= supported
? S_OK
: E_NOINTERFACE
;
88 hr
= IUnknown_QueryInterface(iface
, iid
, (void **)&unk
);
89 ok_(__FILE__
, line
)(hr
== expected_hr
, "Got hr %#x, expected %#x.\n", hr
, expected_hr
);
91 IUnknown_Release(unk
);
94 static void test_interfaces(void)
96 IFilterGraph2
*graph
= create_graph();
98 check_interface(graph
, &IID_IBasicAudio
, TRUE
);
99 check_interface(graph
, &IID_IBasicVideo2
, TRUE
);
100 check_interface(graph
, &IID_IFilterGraph2
, TRUE
);
101 check_interface(graph
, &IID_IFilterMapper
, TRUE
);
102 check_interface(graph
, &IID_IFilterMapper3
, TRUE
);
103 check_interface(graph
, &IID_IGraphConfig
, TRUE
);
104 check_interface(graph
, &IID_IGraphVersion
, TRUE
);
105 check_interface(graph
, &IID_IMediaControl
, TRUE
);
106 check_interface(graph
, &IID_IMediaEvent
, TRUE
);
107 check_interface(graph
, &IID_IMediaFilter
, TRUE
);
108 check_interface(graph
, &IID_IMediaEventSink
, TRUE
);
109 check_interface(graph
, &IID_IMediaPosition
, TRUE
);
110 check_interface(graph
, &IID_IMediaSeeking
, TRUE
);
111 check_interface(graph
, &IID_IObjectWithSite
, TRUE
);
112 check_interface(graph
, &IID_IVideoWindow
, TRUE
);
114 check_interface(graph
, &IID_IBaseFilter
, FALSE
);
116 IFilterGraph2_Release(graph
);
119 static void test_basic_video(IFilterGraph2
*graph
)
122 LONG video_width
, video_height
, window_width
;
123 LONG left
, top
, width
, height
;
126 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IBasicVideo
, (void **)&pbv
);
127 ok(hr
==S_OK
, "Cannot get IBasicVideo interface returned: %x\n", hr
);
129 /* test get video size */
130 hr
= IBasicVideo_GetVideoSize(pbv
, NULL
, NULL
);
131 ok(hr
==E_POINTER
, "IBasicVideo_GetVideoSize returned: %x\n", hr
);
132 hr
= IBasicVideo_GetVideoSize(pbv
, &video_width
, NULL
);
133 ok(hr
==E_POINTER
, "IBasicVideo_GetVideoSize returned: %x\n", hr
);
134 hr
= IBasicVideo_GetVideoSize(pbv
, NULL
, &video_height
);
135 ok(hr
==E_POINTER
, "IBasicVideo_GetVideoSize returned: %x\n", hr
);
136 hr
= IBasicVideo_GetVideoSize(pbv
, &video_width
, &video_height
);
137 ok(hr
==S_OK
, "Cannot get video size returned: %x\n", hr
);
139 /* test source position */
140 hr
= IBasicVideo_GetSourcePosition(pbv
, NULL
, NULL
, NULL
, NULL
);
141 ok(hr
== E_POINTER
, "IBasicVideo_GetSourcePosition returned: %x\n", hr
);
142 hr
= IBasicVideo_GetSourcePosition(pbv
, &left
, &top
, NULL
, NULL
);
143 ok(hr
== E_POINTER
, "IBasicVideo_GetSourcePosition returned: %x\n", hr
);
144 hr
= IBasicVideo_GetSourcePosition(pbv
, NULL
, NULL
, &width
, &height
);
145 ok(hr
== E_POINTER
, "IBasicVideo_GetSourcePosition returned: %x\n", hr
);
146 hr
= IBasicVideo_GetSourcePosition(pbv
, &left
, &top
, &width
, &height
);
147 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
148 ok(left
== 0, "expected 0, got %d\n", left
);
149 ok(top
== 0, "expected 0, got %d\n", top
);
150 ok(width
== video_width
, "expected %d, got %d\n", video_width
, width
);
151 ok(height
== video_height
, "expected %d, got %d\n", video_height
, height
);
153 hr
= IBasicVideo_SetSourcePosition(pbv
, 0, 0, 0, 0);
154 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
155 hr
= IBasicVideo_SetSourcePosition(pbv
, 0, 0, video_width
*2, video_height
*2);
156 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
157 hr
= IBasicVideo_put_SourceTop(pbv
, -1);
158 ok(hr
==E_INVALIDARG
, "IBasicVideo_put_SourceTop returned: %x\n", hr
);
159 hr
= IBasicVideo_put_SourceTop(pbv
, 0);
160 ok(hr
==S_OK
, "Cannot put source top returned: %x\n", hr
);
161 hr
= IBasicVideo_put_SourceTop(pbv
, 1);
162 ok(hr
==E_INVALIDARG
, "IBasicVideo_put_SourceTop returned: %x\n", hr
);
164 hr
= IBasicVideo_SetSourcePosition(pbv
, video_width
, 0, video_width
, video_height
);
165 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
166 hr
= IBasicVideo_SetSourcePosition(pbv
, 0, video_height
, video_width
, video_height
);
167 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
168 hr
= IBasicVideo_SetSourcePosition(pbv
, -1, 0, video_width
, video_height
);
169 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
170 hr
= IBasicVideo_SetSourcePosition(pbv
, 0, -1, video_width
, video_height
);
171 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
172 hr
= IBasicVideo_SetSourcePosition(pbv
, video_width
/2, video_height
/2, video_width
, video_height
);
173 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
174 hr
= IBasicVideo_SetSourcePosition(pbv
, video_width
/2, video_height
/2, video_width
, video_height
);
175 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
177 hr
= IBasicVideo_SetSourcePosition(pbv
, 0, 0, video_width
, video_height
+1);
178 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
179 hr
= IBasicVideo_SetSourcePosition(pbv
, 0, 0, video_width
+1, video_height
);
180 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetSourcePosition returned: %x\n", hr
);
182 hr
= IBasicVideo_SetSourcePosition(pbv
, video_width
/2, video_height
/2, video_width
/3+1, video_height
/3+1);
183 ok(hr
==S_OK
, "Cannot set source position returned: %x\n", hr
);
185 hr
= IBasicVideo_get_SourceLeft(pbv
, &left
);
186 ok(hr
==S_OK
, "Cannot get source left returned: %x\n", hr
);
187 ok(left
==video_width
/2, "expected %d, got %d\n", video_width
/2, left
);
188 hr
= IBasicVideo_get_SourceTop(pbv
, &top
);
189 ok(hr
==S_OK
, "Cannot get source top returned: %x\n", hr
);
190 ok(top
==video_height
/2, "expected %d, got %d\n", video_height
/2, top
);
191 hr
= IBasicVideo_get_SourceWidth(pbv
, &width
);
192 ok(hr
==S_OK
, "Cannot get source width returned: %x\n", hr
);
193 ok(width
==video_width
/3+1, "expected %d, got %d\n", video_width
/3+1, width
);
194 hr
= IBasicVideo_get_SourceHeight(pbv
, &height
);
195 ok(hr
==S_OK
, "Cannot get source height returned: %x\n", hr
);
196 ok(height
==video_height
/3+1, "expected %d, got %d\n", video_height
/3+1, height
);
198 hr
= IBasicVideo_put_SourceLeft(pbv
, video_width
/3);
199 ok(hr
==S_OK
, "Cannot put source left returned: %x\n", hr
);
200 hr
= IBasicVideo_GetSourcePosition(pbv
, &left
, &top
, &width
, &height
);
201 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
202 ok(left
== video_width
/3, "expected %d, got %d\n", video_width
/3, left
);
203 ok(width
== video_width
/3+1, "expected %d, got %d\n", video_width
/3+1, width
);
205 hr
= IBasicVideo_put_SourceTop(pbv
, video_height
/3);
206 ok(hr
==S_OK
, "Cannot put source top returned: %x\n", hr
);
207 hr
= IBasicVideo_GetSourcePosition(pbv
, &left
, &top
, &width
, &height
);
208 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
209 ok(top
== video_height
/3, "expected %d, got %d\n", video_height
/3, top
);
210 ok(height
== video_height
/3+1, "expected %d, got %d\n", video_height
/3+1, height
);
212 hr
= IBasicVideo_put_SourceWidth(pbv
, video_width
/4+1);
213 ok(hr
==S_OK
, "Cannot put source width returned: %x\n", hr
);
214 hr
= IBasicVideo_GetSourcePosition(pbv
, &left
, &top
, &width
, &height
);
215 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
216 ok(left
== video_width
/3, "expected %d, got %d\n", video_width
/3, left
);
217 ok(width
== video_width
/4+1, "expected %d, got %d\n", video_width
/4+1, width
);
219 hr
= IBasicVideo_put_SourceHeight(pbv
, video_height
/4+1);
220 ok(hr
==S_OK
, "Cannot put source height returned: %x\n", hr
);
221 hr
= IBasicVideo_GetSourcePosition(pbv
, &left
, &top
, &width
, &height
);
222 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
223 ok(top
== video_height
/3, "expected %d, got %d\n", video_height
/3, top
);
224 ok(height
== video_height
/4+1, "expected %d, got %d\n", video_height
/4+1, height
);
226 /* test destination rectangle */
227 window_width
= max(video_width
, GetSystemMetrics(SM_CXMIN
) - 2 * GetSystemMetrics(SM_CXFRAME
));
229 hr
= IBasicVideo_GetDestinationPosition(pbv
, NULL
, NULL
, NULL
, NULL
);
230 ok(hr
== E_POINTER
, "IBasicVideo_GetDestinationPosition returned: %x\n", hr
);
231 hr
= IBasicVideo_GetDestinationPosition(pbv
, &left
, &top
, NULL
, NULL
);
232 ok(hr
== E_POINTER
, "IBasicVideo_GetDestinationPosition returned: %x\n", hr
);
233 hr
= IBasicVideo_GetDestinationPosition(pbv
, NULL
, NULL
, &width
, &height
);
234 ok(hr
== E_POINTER
, "IBasicVideo_GetDestinationPosition returned: %x\n", hr
);
235 hr
= IBasicVideo_GetDestinationPosition(pbv
, &left
, &top
, &width
, &height
);
236 ok(hr
== S_OK
, "Cannot get destination position returned: %x\n", hr
);
237 ok(left
== 0, "expected 0, got %d\n", left
);
238 ok(top
== 0, "expected 0, got %d\n", top
);
239 todo_wine
ok(width
== window_width
, "expected %d, got %d\n", window_width
, width
);
240 todo_wine
ok(height
== video_height
, "expected %d, got %d\n", video_height
, height
);
242 hr
= IBasicVideo_SetDestinationPosition(pbv
, 0, 0, 0, 0);
243 ok(hr
==E_INVALIDARG
, "IBasicVideo_SetDestinationPosition returned: %x\n", hr
);
244 hr
= IBasicVideo_SetDestinationPosition(pbv
, 0, 0, video_width
*2, video_height
*2);
245 ok(hr
==S_OK
, "Cannot put destination position returned: %x\n", hr
);
247 hr
= IBasicVideo_put_DestinationLeft(pbv
, -1);
248 ok(hr
==S_OK
, "Cannot put destination left returned: %x\n", hr
);
249 hr
= IBasicVideo_put_DestinationLeft(pbv
, 0);
250 ok(hr
==S_OK
, "Cannot put destination left returned: %x\n", hr
);
251 hr
= IBasicVideo_put_DestinationLeft(pbv
, 1);
252 ok(hr
==S_OK
, "Cannot put destination left returned: %x\n", hr
);
254 hr
= IBasicVideo_SetDestinationPosition(pbv
, video_width
, 0, video_width
, video_height
);
255 ok(hr
==S_OK
, "Cannot set destinaiton position returned: %x\n", hr
);
256 hr
= IBasicVideo_SetDestinationPosition(pbv
, 0, video_height
, video_width
, video_height
);
257 ok(hr
==S_OK
, "Cannot set destinaiton position returned: %x\n", hr
);
258 hr
= IBasicVideo_SetDestinationPosition(pbv
, -1, 0, video_width
, video_height
);
259 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
260 hr
= IBasicVideo_SetDestinationPosition(pbv
, 0, -1, video_width
, video_height
);
261 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
262 hr
= IBasicVideo_SetDestinationPosition(pbv
, video_width
/2, video_height
/2, video_width
, video_height
);
263 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
264 hr
= IBasicVideo_SetDestinationPosition(pbv
, video_width
/2, video_height
/2, video_width
, video_height
);
265 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
267 hr
= IBasicVideo_SetDestinationPosition(pbv
, 0, 0, video_width
, video_height
+1);
268 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
269 hr
= IBasicVideo_SetDestinationPosition(pbv
, 0, 0, video_width
+1, video_height
);
270 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
272 hr
= IBasicVideo_SetDestinationPosition(pbv
, video_width
/2, video_height
/2, video_width
/3+1, video_height
/3+1);
273 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
275 hr
= IBasicVideo_get_DestinationLeft(pbv
, &left
);
276 ok(hr
==S_OK
, "Cannot get destination left returned: %x\n", hr
);
277 ok(left
==video_width
/2, "expected %d, got %d\n", video_width
/2, left
);
278 hr
= IBasicVideo_get_DestinationTop(pbv
, &top
);
279 ok(hr
==S_OK
, "Cannot get destination top returned: %x\n", hr
);
280 ok(top
==video_height
/2, "expected %d, got %d\n", video_height
/2, top
);
281 hr
= IBasicVideo_get_DestinationWidth(pbv
, &width
);
282 ok(hr
==S_OK
, "Cannot get destination width returned: %x\n", hr
);
283 ok(width
==video_width
/3+1, "expected %d, got %d\n", video_width
/3+1, width
);
284 hr
= IBasicVideo_get_DestinationHeight(pbv
, &height
);
285 ok(hr
==S_OK
, "Cannot get destination height returned: %x\n", hr
);
286 ok(height
==video_height
/3+1, "expected %d, got %d\n", video_height
/3+1, height
);
288 hr
= IBasicVideo_put_DestinationLeft(pbv
, video_width
/3);
289 ok(hr
==S_OK
, "Cannot put destination left returned: %x\n", hr
);
290 hr
= IBasicVideo_GetDestinationPosition(pbv
, &left
, &top
, &width
, &height
);
291 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
292 ok(left
== video_width
/3, "expected %d, got %d\n", video_width
/3, left
);
293 ok(width
== video_width
/3+1, "expected %d, got %d\n", video_width
/3+1, width
);
295 hr
= IBasicVideo_put_DestinationTop(pbv
, video_height
/3);
296 ok(hr
==S_OK
, "Cannot put destination top returned: %x\n", hr
);
297 hr
= IBasicVideo_GetDestinationPosition(pbv
, &left
, &top
, &width
, &height
);
298 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
299 ok(top
== video_height
/3, "expected %d, got %d\n", video_height
/3, top
);
300 ok(height
== video_height
/3+1, "expected %d, got %d\n", video_height
/3+1, height
);
302 hr
= IBasicVideo_put_DestinationWidth(pbv
, video_width
/4+1);
303 ok(hr
==S_OK
, "Cannot put destination width returned: %x\n", hr
);
304 hr
= IBasicVideo_GetDestinationPosition(pbv
, &left
, &top
, &width
, &height
);
305 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
306 ok(left
== video_width
/3, "expected %d, got %d\n", video_width
/3, left
);
307 ok(width
== video_width
/4+1, "expected %d, got %d\n", video_width
/4+1, width
);
309 hr
= IBasicVideo_put_DestinationHeight(pbv
, video_height
/4+1);
310 ok(hr
==S_OK
, "Cannot put destination height returned: %x\n", hr
);
311 hr
= IBasicVideo_GetDestinationPosition(pbv
, &left
, &top
, &width
, &height
);
312 ok(hr
== S_OK
, "Cannot get source position returned: %x\n", hr
);
313 ok(top
== video_height
/3, "expected %d, got %d\n", video_height
/3, top
);
314 ok(height
== video_height
/4+1, "expected %d, got %d\n", video_height
/4+1, height
);
316 /* reset source rectangle */
317 hr
= IBasicVideo_SetDefaultSourcePosition(pbv
);
318 ok(hr
==S_OK
, "IBasicVideo_SetDefaultSourcePosition returned: %x\n", hr
);
320 /* reset destination position */
321 hr
= IBasicVideo_SetDestinationPosition(pbv
, 0, 0, video_width
, video_height
);
322 ok(hr
==S_OK
, "Cannot set destination position returned: %x\n", hr
);
324 IBasicVideo_Release(pbv
);
327 static void test_media_seeking(IFilterGraph2
*graph
)
329 IMediaSeeking
*seeking
;
330 IMediaFilter
*filter
;
331 LONGLONG pos
, stop
, duration
;
335 IFilterGraph2_SetDefaultSyncSource(graph
);
336 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IMediaSeeking
, (void **)&seeking
);
337 ok(hr
== S_OK
, "QueryInterface(IMediaControl) failed: %08x\n", hr
);
339 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IMediaFilter
, (void **)&filter
);
340 ok(hr
== S_OK
, "QueryInterface(IMediaFilter) failed: %08x\n", hr
);
343 hr
= IMediaSeeking_GetTimeFormat(seeking
, &format
);
344 ok(hr
== S_OK
, "GetTimeFormat failed: %#x\n", hr
);
345 ok(IsEqualGUID(&format
, &TIME_FORMAT_MEDIA_TIME
), "got %s\n", wine_dbgstr_guid(&format
));
348 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &pos
, NULL
, 0x123456789a, NULL
);
349 ok(hr
== S_OK
, "ConvertTimeFormat failed: %#x\n", hr
);
350 ok(pos
== 0x123456789a, "got %s\n", wine_dbgstr_longlong(pos
));
353 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &pos
, &TIME_FORMAT_MEDIA_TIME
, 0x123456789a, NULL
);
354 ok(hr
== S_OK
, "ConvertTimeFormat failed: %#x\n", hr
);
355 ok(pos
== 0x123456789a, "got %s\n", wine_dbgstr_longlong(pos
));
358 hr
= IMediaSeeking_ConvertTimeFormat(seeking
, &pos
, NULL
, 0x123456789a, &TIME_FORMAT_MEDIA_TIME
);
359 ok(hr
== S_OK
, "ConvertTimeFormat failed: %#x\n", hr
);
360 ok(pos
== 0x123456789a, "got %s\n", wine_dbgstr_longlong(pos
));
362 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &pos
);
363 ok(hr
== S_OK
, "GetCurrentPosition failed: %#x\n", hr
);
364 ok(pos
== 0, "got %s\n", wine_dbgstr_longlong(pos
));
366 hr
= IMediaSeeking_GetDuration(seeking
, &duration
);
367 ok(hr
== S_OK
, "GetDuration failed: %#x\n", hr
);
368 ok(duration
> 0, "got %s\n", wine_dbgstr_longlong(duration
));
370 hr
= IMediaSeeking_GetStopPosition(seeking
, &stop
);
371 ok(hr
== S_OK
, "GetCurrentPosition failed: %08x\n", hr
);
372 ok(stop
== duration
|| stop
== duration
+ 1, "expected %s, got %s\n",
373 wine_dbgstr_longlong(duration
), wine_dbgstr_longlong(stop
));
375 hr
= IMediaSeeking_SetPositions(seeking
, NULL
, AM_SEEKING_ReturnTime
, NULL
, AM_SEEKING_NoPositioning
);
376 ok(hr
== S_OK
, "SetPositions failed: %#x\n", hr
);
377 hr
= IMediaSeeking_SetPositions(seeking
, NULL
, AM_SEEKING_NoPositioning
, NULL
, AM_SEEKING_ReturnTime
);
378 ok(hr
== S_OK
, "SetPositions failed: %#x\n", hr
);
381 hr
= IMediaSeeking_SetPositions(seeking
, &pos
, AM_SEEKING_AbsolutePositioning
, NULL
, AM_SEEKING_NoPositioning
);
382 ok(hr
== S_OK
, "SetPositions failed: %08x\n", hr
);
384 IMediaFilter_SetSyncSource(filter
, NULL
);
386 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &pos
);
387 ok(hr
== S_OK
, "GetCurrentPosition failed: %08x\n", hr
);
388 ok(pos
== 0, "Position != 0 (%s)\n", wine_dbgstr_longlong(pos
));
389 IFilterGraph2_SetDefaultSyncSource(graph
);
391 IMediaSeeking_Release(seeking
);
392 IMediaFilter_Release(filter
);
395 static void test_state_change(IFilterGraph2
*graph
)
397 IMediaControl
*control
;
401 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IMediaControl
, (void **)&control
);
402 ok(hr
== S_OK
, "QueryInterface(IMediaControl) failed: %x\n", hr
);
404 hr
= IMediaControl_GetState(control
, 1000, &state
);
405 ok(hr
== S_OK
, "GetState() failed: %x\n", hr
);
406 ok(state
== State_Stopped
, "wrong state %d\n", state
);
408 hr
= IMediaControl_Run(control
);
409 ok(SUCCEEDED(hr
), "Run() failed: %x\n", hr
);
410 hr
= IMediaControl_GetState(control
, INFINITE
, &state
);
411 ok(SUCCEEDED(hr
), "GetState() failed: %x\n", hr
);
412 ok(state
== State_Running
, "wrong state %d\n", state
);
414 hr
= IMediaControl_Stop(control
);
415 ok(SUCCEEDED(hr
), "Stop() failed: %x\n", hr
);
416 hr
= IMediaControl_GetState(control
, 1000, &state
);
417 ok(hr
== S_OK
, "GetState() failed: %x\n", hr
);
418 ok(state
== State_Stopped
, "wrong state %d\n", state
);
420 hr
= IMediaControl_Pause(control
);
421 ok(SUCCEEDED(hr
), "Pause() failed: %x\n", hr
);
422 hr
= IMediaControl_GetState(control
, 1000, &state
);
423 ok(hr
== S_OK
, "GetState() failed: %x\n", hr
);
424 ok(state
== State_Paused
, "wrong state %d\n", state
);
426 hr
= IMediaControl_Run(control
);
427 ok(SUCCEEDED(hr
), "Run() failed: %x\n", hr
);
428 hr
= IMediaControl_GetState(control
, 1000, &state
);
429 ok(hr
== S_OK
, "GetState() failed: %x\n", hr
);
430 ok(state
== State_Running
, "wrong state %d\n", state
);
432 hr
= IMediaControl_Pause(control
);
433 ok(SUCCEEDED(hr
), "Pause() failed: %x\n", hr
);
434 hr
= IMediaControl_GetState(control
, 1000, &state
);
435 ok(hr
== S_OK
, "GetState() failed: %x\n", hr
);
436 ok(state
== State_Paused
, "wrong state %d\n", state
);
438 hr
= IMediaControl_Stop(control
);
439 ok(SUCCEEDED(hr
), "Stop() failed: %x\n", hr
);
440 hr
= IMediaControl_GetState(control
, 1000, &state
);
441 ok(hr
== S_OK
, "GetState() failed: %x\n", hr
);
442 ok(state
== State_Stopped
, "wrong state %d\n", state
);
444 IMediaControl_Release(control
);
447 static void test_media_event(IFilterGraph2
*graph
)
449 IMediaEvent
*media_event
;
450 IMediaSeeking
*seeking
;
451 IMediaControl
*control
;
452 IMediaFilter
*filter
;
453 LONG_PTR lparam1
, lparam2
;
454 LONGLONG current
, stop
;
461 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IMediaFilter
, (void **)&filter
);
462 ok(hr
== S_OK
, "QueryInterface(IMediaFilter) failed: %#x\n", hr
);
464 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IMediaControl
, (void **)&control
);
465 ok(hr
== S_OK
, "QueryInterface(IMediaControl) failed: %#x\n", hr
);
467 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IMediaEvent
, (void **)&media_event
);
468 ok(hr
== S_OK
, "QueryInterface(IMediaEvent) failed: %#x\n", hr
);
470 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IMediaSeeking
, (void **)&seeking
);
471 ok(hr
== S_OK
, "QueryInterface(IMediaEvent) failed: %#x\n", hr
);
473 hr
= IMediaControl_Stop(control
);
474 ok(SUCCEEDED(hr
), "Stop() failed: %#x\n", hr
);
475 hr
= IMediaControl_GetState(control
, 1000, &state
);
476 ok(hr
== S_OK
, "GetState() timed out\n");
478 hr
= IMediaSeeking_GetDuration(seeking
, &stop
);
479 ok(hr
== S_OK
, "GetDuration() failed: %#x\n", hr
);
481 hr
= IMediaSeeking_SetPositions(seeking
, ¤t
, AM_SEEKING_AbsolutePositioning
, &stop
, AM_SEEKING_AbsolutePositioning
);
482 ok(hr
== S_OK
, "SetPositions() failed: %#x\n", hr
);
484 hr
= IMediaFilter_SetSyncSource(filter
, NULL
);
485 ok(hr
== S_OK
, "SetSyncSource() failed: %#x\n", hr
);
487 hr
= IMediaEvent_GetEventHandle(media_event
, (OAEVENT
*)&event
);
488 ok(hr
== S_OK
, "GetEventHandle() failed: %#x\n", hr
);
490 /* flush existing events */
491 while ((hr
= IMediaEvent_GetEvent(media_event
, &code
, &lparam1
, &lparam2
, 0)) == S_OK
);
493 ok(WaitForSingleObject(event
, 0) == WAIT_TIMEOUT
, "event should not be signaled\n");
495 hr
= IMediaControl_Run(control
);
496 ok(SUCCEEDED(hr
), "Run() failed: %#x\n", hr
);
500 if (WaitForSingleObject(event
, 1000) == WAIT_TIMEOUT
)
503 while ((hr
= IMediaEvent_GetEvent(media_event
, &code
, &lparam1
, &lparam2
, 0)) == S_OK
)
505 if (code
== EC_COMPLETE
)
512 ok(got_eos
, "didn't get EOS\n");
514 hr
= IMediaSeeking_GetCurrentPosition(seeking
, ¤t
);
515 ok(hr
== S_OK
, "GetCurrentPosition() failed: %#x\n", hr
);
517 ok(current
== stop
, "expected %s, got %s\n", wine_dbgstr_longlong(stop
), wine_dbgstr_longlong(current
));
519 hr
= IMediaControl_Stop(control
);
520 ok(SUCCEEDED(hr
), "Run() failed: %#x\n", hr
);
521 hr
= IMediaControl_GetState(control
, 1000, &state
);
522 ok(hr
== S_OK
, "GetState() timed out\n");
524 hr
= IFilterGraph2_SetDefaultSyncSource(graph
);
525 ok(hr
== S_OK
, "SetDefaultSinkSource() failed: %#x\n", hr
);
527 IMediaSeeking_Release(seeking
);
528 IMediaEvent_Release(media_event
);
529 IMediaControl_Release(control
);
530 IMediaFilter_Release(filter
);
533 static void rungraph(IFilterGraph2
*graph
)
535 test_basic_video(graph
);
536 test_media_seeking(graph
);
537 test_state_change(graph
);
538 test_media_event(graph
);
541 static HRESULT
test_graph_builder_connect_file(WCHAR
*filename
)
543 static const WCHAR outputW
[] = {'O','u','t','p','u','t',0};
544 static const WCHAR inW
[] = {'I','n',0};
545 IBaseFilter
*source_filter
, *video_filter
;
546 IPin
*pin_in
, *pin_out
;
547 IFilterGraph2
*graph
;
548 IVideoWindow
*window
;
551 graph
= create_graph();
553 hr
= CoCreateInstance(&CLSID_VideoRenderer
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IVideoWindow
, (void **)&window
);
554 ok(hr
== S_OK
, "Failed to create VideoRenderer: %#x\n", hr
);
556 hr
= IFilterGraph2_AddSourceFilter(graph
, filename
, NULL
, &source_filter
);
557 ok(hr
== S_OK
, "AddSourceFilter failed: %#x\n", hr
);
559 hr
= IVideoWindow_QueryInterface(window
, &IID_IBaseFilter
, (void **)&video_filter
);
560 ok(hr
== S_OK
, "QueryInterface(IBaseFilter) failed: %#x\n", hr
);
561 hr
= IFilterGraph2_AddFilter(graph
, video_filter
, NULL
);
562 ok(hr
== S_OK
, "AddFilter failed: %#x\n", hr
);
564 hr
= IBaseFilter_FindPin(source_filter
, outputW
, &pin_out
);
565 ok(hr
== S_OK
, "FindPin failed: %#x\n", hr
);
566 hr
= IBaseFilter_FindPin(video_filter
, inW
, &pin_in
);
567 ok(hr
== S_OK
, "FindPin failed: %#x\n", hr
);
568 hr
= IFilterGraph2_Connect(graph
, pin_out
, pin_in
);
573 IPin_Release(pin_in
);
574 IPin_Release(pin_out
);
575 IBaseFilter_Release(source_filter
);
576 IBaseFilter_Release(video_filter
);
577 IVideoWindow_Release(window
);
578 IFilterGraph2_Release(graph
);
583 static void test_render_run(const WCHAR
*file
)
585 IFilterGraph2
*graph
;
589 WCHAR
*filename
= load_resource(file
);
591 h
= CreateFileW(filename
, 0, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
592 if (h
== INVALID_HANDLE_VALUE
) {
593 skip("Could not read test file %s, skipping test\n", wine_dbgstr_w(file
));
594 DeleteFileW(filename
);
599 trace("running %s\n", wine_dbgstr_w(file
));
601 graph
= create_graph();
603 hr
= IFilterGraph2_RenderFile(graph
, filename
, NULL
);
606 skip("%s: codec not supported; skipping test\n", wine_dbgstr_w(file
));
608 refs
= IFilterGraph2_Release(graph
);
609 ok(!refs
, "Graph has %u references\n", refs
);
611 hr
= test_graph_builder_connect_file(filename
);
613 ok(hr
== VFW_E_CANNOT_CONNECT
, "got %#x\n", hr
);
617 ok(hr
== S_OK
|| hr
== VFW_S_AUDIO_NOT_RENDERED
, "RenderFile failed: %x\n", hr
);
620 refs
= IFilterGraph2_Release(graph
);
621 ok(!refs
, "Graph has %u references\n", refs
);
623 hr
= test_graph_builder_connect_file(filename
);
624 ok(hr
== S_OK
|| hr
== VFW_S_PARTIAL_RENDER
, "got %#x\n", hr
);
627 /* check reference leaks */
628 h
= CreateFileW(filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
629 ok(h
!= INVALID_HANDLE_VALUE
, "CreateFile failed: err=%d\n", GetLastError());
632 DeleteFileW(filename
);
635 static void test_enum_filters(void)
637 IBaseFilter
*filter1
, *filter2
, *filters
[2];
638 IFilterGraph2
*graph
= create_graph();
639 IEnumFilters
*enum1
, *enum2
;
643 CoCreateInstance(&CLSID_AsyncReader
, NULL
, CLSCTX_INPROC_SERVER
,
644 &IID_IBaseFilter
, (void **)&filter1
);
645 CoCreateInstance(&CLSID_AsyncReader
, NULL
, CLSCTX_INPROC_SERVER
,
646 &IID_IBaseFilter
, (void **)&filter2
);
648 hr
= IFilterGraph2_EnumFilters(graph
, &enum1
);
649 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
651 hr
= IEnumFilters_Next(enum1
, 1, filters
, NULL
);
652 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
654 IFilterGraph2_AddFilter(graph
, filter1
, NULL
);
655 IFilterGraph2_AddFilter(graph
, filter2
, NULL
);
657 hr
= IEnumFilters_Next(enum1
, 1, filters
, NULL
);
658 ok(hr
== VFW_E_ENUM_OUT_OF_SYNC
, "Got hr %#x.\n", hr
);
660 hr
= IEnumFilters_Reset(enum1
);
661 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
663 hr
= IEnumFilters_Next(enum1
, 1, filters
, NULL
);
664 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
665 ok(filters
[0] == filter2
, "Got filter %p.\n", filters
[0]);
666 IBaseFilter_Release(filters
[0]);
668 hr
= IEnumFilters_Next(enum1
, 1, filters
, &count
);
669 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
670 ok(count
== 1, "Got count %u.\n", count
);
671 ok(filters
[0] == filter1
, "Got filter %p.\n", filters
[0]);
672 IBaseFilter_Release(filters
[0]);
674 hr
= IEnumFilters_Next(enum1
, 1, filters
, &count
);
675 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
676 ok(count
== 0, "Got count %u.\n", count
);
678 hr
= IEnumFilters_Reset(enum1
);
679 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
681 hr
= IEnumFilters_Next(enum1
, 2, filters
, &count
);
682 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
683 ok(count
== 2, "Got count %u.\n", count
);
684 ok(filters
[0] == filter2
, "Got filter %p.\n", filters
[0]);
685 ok(filters
[1] == filter1
, "Got filter %p.\n", filters
[1]);
686 IBaseFilter_Release(filters
[0]);
687 IBaseFilter_Release(filters
[1]);
689 IFilterGraph2_RemoveFilter(graph
, filter1
);
690 IFilterGraph2_AddFilter(graph
, filter1
, NULL
);
692 hr
= IEnumFilters_Next(enum1
, 2, filters
, &count
);
693 ok(hr
== VFW_E_ENUM_OUT_OF_SYNC
, "Got hr %#x.\n", hr
);
695 hr
= IEnumFilters_Reset(enum1
);
696 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
698 hr
= IEnumFilters_Next(enum1
, 2, filters
, &count
);
699 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
700 ok(count
== 2, "Got count %u.\n", count
);
701 ok(filters
[0] == filter1
, "Got filter %p.\n", filters
[0]);
702 ok(filters
[1] == filter2
, "Got filter %p.\n", filters
[1]);
703 IBaseFilter_Release(filters
[0]);
704 IBaseFilter_Release(filters
[1]);
706 hr
= IEnumFilters_Reset(enum1
);
707 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
709 hr
= IEnumFilters_Clone(enum1
, &enum2
);
710 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
712 hr
= IEnumFilters_Skip(enum2
, 1);
713 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
715 hr
= IEnumFilters_Next(enum2
, 2, filters
, &count
);
716 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
717 ok(count
== 1, "Got count %u.\n", count
);
718 ok(filters
[0] == filter2
, "Got filter %p.\n", filters
[0]);
719 IBaseFilter_Release(filters
[0]);
721 hr
= IEnumFilters_Skip(enum1
, 3);
722 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
724 IEnumFilters_Release(enum2
);
725 IEnumFilters_Release(enum1
);
726 ref
= IFilterGraph2_Release(graph
);
727 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
730 static DWORD WINAPI
call_RenderFile_multithread(LPVOID lParam
)
732 WCHAR
*filename
= load_resource(avifile
);
733 IFilterGraph2
*graph
= lParam
;
736 hr
= IFilterGraph2_RenderFile(graph
, filename
, NULL
);
738 ok(SUCCEEDED(hr
), "RenderFile failed: %x\n", hr
);
746 static void test_render_with_multithread(void)
748 IFilterGraph2
*graph
;
751 CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);
753 graph
= create_graph();
755 thread
= CreateThread(NULL
, 0, call_RenderFile_multithread
, graph
, 0, NULL
);
757 ok(WaitForSingleObject(thread
, 1000) == WAIT_OBJECT_0
, "wait failed\n");
758 IFilterGraph2_Release(graph
);
772 IEnumMediaTypes IEnumMediaTypes_iface
;
773 const AM_MEDIA_TYPE
*types
;
774 unsigned int type_count
, enum_idx
;
775 AM_MEDIA_TYPE
*request_mt
, *accept_mt
;
777 HRESULT QueryInternalConnections_hr
;
780 static inline struct testpin
*impl_from_IEnumMediaTypes(IEnumMediaTypes
*iface
)
782 return CONTAINING_RECORD(iface
, struct testpin
, IEnumMediaTypes_iface
);
785 static HRESULT WINAPI
testenummt_QueryInterface(IEnumMediaTypes
*iface
, REFIID iid
, void **out
)
787 struct testpin
*pin
= impl_from_IEnumMediaTypes(iface
);
788 if (winetest_debug
> 1) trace("%p->QueryInterface(%s)\n", pin
, wine_dbgstr_guid(iid
));
791 return E_NOINTERFACE
;
794 static ULONG WINAPI
testenummt_AddRef(IEnumMediaTypes
*iface
)
796 struct testpin
*pin
= impl_from_IEnumMediaTypes(iface
);
797 return InterlockedIncrement(&pin
->ref
);
800 static ULONG WINAPI
testenummt_Release(IEnumMediaTypes
*iface
)
802 struct testpin
*pin
= impl_from_IEnumMediaTypes(iface
);
803 return InterlockedDecrement(&pin
->ref
);
806 static HRESULT WINAPI
testenummt_Next(IEnumMediaTypes
*iface
, ULONG count
, AM_MEDIA_TYPE
**out
, ULONG
*fetched
)
808 struct testpin
*pin
= impl_from_IEnumMediaTypes(iface
);
811 for (i
= 0; i
< count
; ++i
)
813 if (pin
->enum_idx
+ i
>= pin
->type_count
)
816 out
[i
] = CoTaskMemAlloc(sizeof(*out
[i
]));
817 *out
[i
] = pin
->types
[pin
->enum_idx
+ i
];
824 return (i
== count
) ? S_OK
: S_FALSE
;
827 static HRESULT WINAPI
testenummt_Skip(IEnumMediaTypes
*iface
, ULONG count
)
829 ok(0, "Unexpected call.\n");
833 static HRESULT WINAPI
testenummt_Reset(IEnumMediaTypes
*iface
)
835 struct testpin
*pin
= impl_from_IEnumMediaTypes(iface
);
840 static HRESULT WINAPI
testenummt_Clone(IEnumMediaTypes
*iface
, IEnumMediaTypes
**out
)
842 ok(0, "Unexpected call.\n");
846 static const IEnumMediaTypesVtbl testenummt_vtbl
=
848 testenummt_QueryInterface
,
857 static inline struct testpin
*impl_from_IPin(IPin
*iface
)
859 return CONTAINING_RECORD(iface
, struct testpin
, IPin_iface
);
862 static HRESULT WINAPI
testpin_QueryInterface(IPin
*iface
, REFIID iid
, void **out
)
864 struct testpin
*pin
= impl_from_IPin(iface
);
865 if (winetest_debug
> 1) trace("%p->QueryInterface(%s)\n", pin
, wine_dbgstr_guid(iid
));
867 if (IsEqualGUID(iid
, &IID_IUnknown
) || IsEqualGUID(iid
, &IID_IPin
))
869 *out
= &pin
->IPin_iface
;
875 return E_NOINTERFACE
;
878 ULONG WINAPI
testpin_AddRef(IPin
*iface
)
880 struct testpin
*pin
= impl_from_IPin(iface
);
881 return InterlockedIncrement(&pin
->ref
);
884 ULONG WINAPI
testpin_Release(IPin
*iface
)
886 struct testpin
*pin
= impl_from_IPin(iface
);
887 return InterlockedDecrement(&pin
->ref
);
890 static HRESULT WINAPI
testpin_Disconnect(IPin
*iface
)
892 struct testpin
*pin
= impl_from_IPin(iface
);
893 if (winetest_debug
> 1) trace("%p->Disconnect()\n", pin
);
898 IPin_Release(pin
->peer
);
903 static HRESULT WINAPI
testpin_ConnectedTo(IPin
*iface
, IPin
**peer
)
905 struct testpin
*pin
= impl_from_IPin(iface
);
906 if (winetest_debug
> 1) trace("%p->ConnectedTo()\n", pin
);
914 return VFW_E_NOT_CONNECTED
;
917 static HRESULT WINAPI
testpin_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*mt
)
919 ok(0, "Unexpected call.\n");
923 static HRESULT WINAPI
testpin_QueryPinInfo(IPin
*iface
, PIN_INFO
*info
)
925 struct testpin
*pin
= impl_from_IPin(iface
);
926 if (winetest_debug
> 1) trace("%p->QueryPinInfo()\n", pin
);
928 info
->pFilter
= pin
->filter
;
929 IBaseFilter_AddRef(pin
->filter
);
930 info
->dir
= pin
->dir
;
931 info
->achName
[0] = 0;
936 static HRESULT WINAPI
testpin_QueryDirection(IPin
*iface
, PIN_DIRECTION
*dir
)
938 struct testpin
*pin
= impl_from_IPin(iface
);
939 if (winetest_debug
> 1) trace("%p->QueryDirection()\n", pin
);
945 static HRESULT WINAPI
testpin_QueryId(IPin
*iface
, WCHAR
**id
)
947 if (winetest_debug
> 1) trace("%p->QueryId()\n", iface
);
948 *id
= CoTaskMemAlloc(1);
953 static HRESULT WINAPI
testpin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*mt
)
955 ok(0, "Unexpected call.\n");
959 static HRESULT WINAPI
testpin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**out
)
961 struct testpin
*pin
= impl_from_IPin(iface
);
962 if (winetest_debug
> 1) trace("%p->EnumMediaTypes()\n", pin
);
964 *out
= &pin
->IEnumMediaTypes_iface
;
965 IEnumMediaTypes_AddRef(*out
);
970 static HRESULT WINAPI
testpin_QueryInternalConnections(IPin
*iface
, IPin
**out
, ULONG
*count
)
972 struct testpin
*pin
= impl_from_IPin(iface
);
973 if (winetest_debug
> 1) trace("%p->QueryInternalConnections()\n", pin
);
976 return pin
->QueryInternalConnections_hr
;
979 static HRESULT WINAPI
testpin_BeginFlush(IPin
*iface
)
981 ok(0, "Unexpected call.\n");
985 static HRESULT WINAPI
testpin_EndFlush(IPin
* iface
)
987 ok(0, "Unexpected call.\n");
991 static HRESULT WINAPI
testpin_NewSegment(IPin
*iface
, REFERENCE_TIME start
, REFERENCE_TIME stop
, double rate
)
993 ok(0, "Unexpected call.\n");
997 static HRESULT WINAPI
testpin_EndOfStream(IPin
*iface
)
999 ok(0, "Unexpected call.\n");
1003 static HRESULT WINAPI
no_Connect(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
1005 ok(0, "Unexpected call.\n");
1009 static HRESULT WINAPI
no_ReceiveConnection(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
1011 ok(0, "Unexpected call.\n");
1015 static HRESULT WINAPI
no_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**out
)
1017 ok(0, "Unexpected call.\n");
1021 static HRESULT WINAPI
testsink_ReceiveConnection(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
1023 struct testpin
*pin
= impl_from_IPin(iface
);
1024 if (winetest_debug
> 1) trace("%p->ReceiveConnection(%p)\n", pin
, peer
);
1026 if (pin
->accept_mt
&& memcmp(pin
->accept_mt
, mt
, sizeof(*mt
)))
1027 return VFW_E_TYPE_NOT_ACCEPTED
;
1034 static const IPinVtbl testsink_vtbl
=
1036 testpin_QueryInterface
,
1040 testsink_ReceiveConnection
,
1042 testpin_ConnectedTo
,
1043 testpin_ConnectionMediaType
,
1044 testpin_QueryPinInfo
,
1045 testpin_QueryDirection
,
1047 testpin_QueryAccept
,
1049 testpin_QueryInternalConnections
,
1050 testpin_EndOfStream
,
1056 static void testpin_init(struct testpin
*pin
, const IPinVtbl
*vtbl
, PIN_DIRECTION dir
)
1058 memset(pin
, 0, sizeof(*pin
));
1059 pin
->IPin_iface
.lpVtbl
= vtbl
;
1060 pin
->IEnumMediaTypes_iface
.lpVtbl
= &testenummt_vtbl
;
1063 pin
->QueryInternalConnections_hr
= E_NOTIMPL
;
1066 static void testsink_init(struct testpin
*pin
)
1068 testpin_init(pin
, &testsink_vtbl
, PINDIR_INPUT
);
1071 static HRESULT WINAPI
testsource_Connect(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
1073 struct testpin
*pin
= impl_from_IPin(iface
);
1075 if (winetest_debug
> 1) trace("%p->Connect(%p)\n", pin
, peer
);
1077 ok(!mt
, "Got media type %p.\n", mt
);
1079 if (SUCCEEDED(hr
= IPin_ReceiveConnection(peer
, &pin
->IPin_iface
, pin
->request_mt
)))
1087 static const IPinVtbl testsource_vtbl
=
1089 testpin_QueryInterface
,
1093 no_ReceiveConnection
,
1095 testpin_ConnectedTo
,
1096 testpin_ConnectionMediaType
,
1097 testpin_QueryPinInfo
,
1098 testpin_QueryDirection
,
1100 testpin_QueryAccept
,
1101 testpin_EnumMediaTypes
,
1102 testpin_QueryInternalConnections
,
1103 testpin_EndOfStream
,
1109 static void testsource_init(struct testpin
*pin
, const AM_MEDIA_TYPE
*types
, int type_count
)
1111 testpin_init(pin
, &testsource_vtbl
, PINDIR_OUTPUT
);
1113 pin
->type_count
= type_count
;
1118 IBaseFilter IBaseFilter_iface
;
1120 IFilterGraph
*graph
;
1122 IReferenceClock
*clock
;
1124 IEnumPins IEnumPins_iface
;
1125 struct testpin
*pins
;
1126 unsigned int pin_count
, enum_idx
;
1129 static inline struct testfilter
*impl_from_IEnumPins(IEnumPins
*iface
)
1131 return CONTAINING_RECORD(iface
, struct testfilter
, IEnumPins_iface
);
1134 static HRESULT WINAPI
testenumpins_QueryInterface(IEnumPins
*iface
, REFIID iid
, void **out
)
1136 ok(0, "Unexpected iid %s.\n", wine_dbgstr_guid(iid
));
1137 return E_NOINTERFACE
;
1140 static ULONG WINAPI
testenumpins_AddRef(IEnumPins
* iface
)
1142 struct testfilter
*filter
= impl_from_IEnumPins(iface
);
1143 return InterlockedIncrement(&filter
->ref
);
1146 static ULONG WINAPI
testenumpins_Release(IEnumPins
* iface
)
1148 struct testfilter
*filter
= impl_from_IEnumPins(iface
);
1149 return InterlockedDecrement(&filter
->ref
);
1152 static HRESULT WINAPI
testenumpins_Next(IEnumPins
*iface
, ULONG count
, IPin
**out
, ULONG
*fetched
)
1154 struct testfilter
*filter
= impl_from_IEnumPins(iface
);
1157 for (i
= 0; i
< count
; ++i
)
1159 if (filter
->enum_idx
+ i
>= filter
->pin_count
)
1162 out
[i
] = &filter
->pins
[filter
->enum_idx
+ i
].IPin_iface
;
1163 IPin_AddRef(out
[i
]);
1168 filter
->enum_idx
+= i
;
1170 return (i
== count
) ? S_OK
: S_FALSE
;
1173 static HRESULT WINAPI
testenumpins_Skip(IEnumPins
*iface
, ULONG count
)
1175 ok(0, "Unexpected call.\n");
1179 static HRESULT WINAPI
testenumpins_Reset(IEnumPins
*iface
)
1181 struct testfilter
*filter
= impl_from_IEnumPins(iface
);
1182 filter
->enum_idx
= 0;
1186 static HRESULT WINAPI
testenumpins_Clone(IEnumPins
*iface
, IEnumPins
**out
)
1188 ok(0, "Unexpected call.\n");
1192 static const IEnumPinsVtbl testenumpins_vtbl
=
1194 testenumpins_QueryInterface
,
1195 testenumpins_AddRef
,
1196 testenumpins_Release
,
1203 static inline struct testfilter
*impl_from_IBaseFilter(IBaseFilter
*iface
)
1205 return CONTAINING_RECORD(iface
, struct testfilter
, IBaseFilter_iface
);
1208 static HRESULT WINAPI
testfilter_QueryInterface(IBaseFilter
*iface
, REFIID iid
, void **out
)
1210 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1211 if (winetest_debug
> 1) trace("%p->QueryInterface(%s)\n", filter
, wine_dbgstr_guid(iid
));
1213 if (IsEqualGUID(iid
, &IID_IUnknown
)
1214 || IsEqualGUID(iid
, &IID_IPersist
)
1215 || IsEqualGUID(iid
, &IID_IMediaFilter
)
1216 || IsEqualGUID(iid
, &IID_IBaseFilter
))
1218 *out
= &filter
->IBaseFilter_iface
;
1219 IBaseFilter_AddRef(*out
);
1224 return E_NOINTERFACE
;
1227 static ULONG WINAPI
testfilter_AddRef(IBaseFilter
*iface
)
1229 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1230 return InterlockedIncrement(&filter
->ref
);
1233 static ULONG WINAPI
testfilter_Release(IBaseFilter
*iface
)
1235 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1236 return InterlockedDecrement(&filter
->ref
);
1239 static HRESULT WINAPI
testfilter_GetClassID(IBaseFilter
*iface
, CLSID
*clsid
)
1241 if (winetest_debug
> 1) trace("%p->GetClassID()\n", iface
);
1245 static HRESULT WINAPI
testfilter_Stop(IBaseFilter
*iface
)
1247 if (winetest_debug
> 1) trace("%p->Stop()\n", iface
);
1251 static HRESULT WINAPI
testfilter_Pause(IBaseFilter
*iface
)
1253 ok(0, "Unexpected call.\n");
1257 static HRESULT WINAPI
testfilter_Run(IBaseFilter
*iface
, REFERENCE_TIME start
)
1259 ok(0, "Unexpected call.\n");
1263 static HRESULT WINAPI
testfilter_GetState(IBaseFilter
*iface
, DWORD timeout
, FILTER_STATE
*state
)
1265 if (winetest_debug
> 1) trace("%p->GetState()\n", iface
);
1269 static HRESULT WINAPI
testfilter_SetSyncSource(IBaseFilter
*iface
, IReferenceClock
*clock
)
1271 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1272 if (winetest_debug
> 1) trace("%p->SetSyncSource(%p)\n", filter
, clock
);
1275 IReferenceClock_Release(filter
->clock
);
1277 IReferenceClock_AddRef(clock
);
1278 filter
->clock
= clock
;
1282 static HRESULT WINAPI
testfilter_GetSyncSource(IBaseFilter
*iface
, IReferenceClock
**clock
)
1284 ok(0, "Unexpected call.\n");
1288 static HRESULT WINAPI
testfilter_EnumPins(IBaseFilter
*iface
, IEnumPins
**out
)
1290 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1291 if (winetest_debug
> 1) trace("%p->EnumPins()\n", filter
);
1293 *out
= &filter
->IEnumPins_iface
;
1294 IEnumPins_AddRef(*out
);
1295 filter
->enum_idx
= 0;
1299 static HRESULT WINAPI
testfilter_FindPin(IBaseFilter
*iface
, const WCHAR
*id
, IPin
**pin
)
1301 ok(0, "Unexpected call.\n");
1305 static HRESULT WINAPI
testfilter_QueryFilterInfo(IBaseFilter
*iface
, FILTER_INFO
*info
)
1307 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1308 if (winetest_debug
> 1) trace("%p->QueryFilterInfo()\n", filter
);
1310 info
->pGraph
= filter
->graph
;
1312 IFilterGraph_AddRef(filter
->graph
);
1314 lstrcpyW(info
->achName
, filter
->name
);
1316 info
->achName
[0] = 0;
1320 static HRESULT WINAPI
testfilter_JoinFilterGraph(IBaseFilter
*iface
, IFilterGraph
*graph
, const WCHAR
*name
)
1322 struct testfilter
*filter
= impl_from_IBaseFilter(iface
);
1323 if (winetest_debug
> 1) trace("%p->JoinFilterGraph(%p, %s)\n", filter
, graph
, wine_dbgstr_w(name
));
1325 filter
->graph
= graph
;
1326 heap_free(filter
->name
);
1329 filter
->name
= heap_alloc((lstrlenW(name
)+1)*sizeof(WCHAR
));
1330 lstrcpyW(filter
->name
, name
);
1333 filter
->name
= NULL
;
1337 static HRESULT WINAPI
testfilter_QueryVendorInfo(IBaseFilter
* iface
, WCHAR
**info
)
1342 static const IBaseFilterVtbl testfilter_vtbl
=
1344 testfilter_QueryInterface
,
1347 testfilter_GetClassID
,
1351 testfilter_GetState
,
1352 testfilter_SetSyncSource
,
1353 testfilter_GetSyncSource
,
1354 testfilter_EnumPins
,
1356 testfilter_QueryFilterInfo
,
1357 testfilter_JoinFilterGraph
,
1358 testfilter_QueryVendorInfo
1361 struct testfilter_cf
1363 IClassFactory IClassFactory_iface
;
1364 struct testfilter
*filter
;
1367 static void testfilter_init(struct testfilter
*filter
, struct testpin
*pins
, int pin_count
)
1371 memset(filter
, 0, sizeof(*filter
));
1372 filter
->IBaseFilter_iface
.lpVtbl
= &testfilter_vtbl
;
1373 filter
->IEnumPins_iface
.lpVtbl
= &testenumpins_vtbl
;
1375 filter
->pins
= pins
;
1376 filter
->pin_count
= pin_count
;
1377 for (i
= 0; i
< pin_count
; i
++)
1378 pins
[i
].filter
= &filter
->IBaseFilter_iface
;
1381 static HRESULT WINAPI
testfilter_cf_QueryInterface(IClassFactory
*iface
, REFIID iid
, void **out
)
1383 if (IsEqualGUID(iid
, &IID_IUnknown
) || IsEqualGUID(iid
, &IID_IClassFactory
))
1390 return E_NOINTERFACE
;
1393 static ULONG WINAPI
testfilter_cf_AddRef(IClassFactory
*iface
)
1398 static ULONG WINAPI
testfilter_cf_Release(IClassFactory
*iface
)
1403 static HRESULT WINAPI
testfilter_cf_CreateInstance(IClassFactory
*iface
, IUnknown
*outer
, REFIID iid
, void **out
)
1405 struct testfilter_cf
*factory
= CONTAINING_RECORD(iface
, struct testfilter_cf
, IClassFactory_iface
);
1407 return IBaseFilter_QueryInterface(&factory
->filter
->IBaseFilter_iface
, iid
, out
);
1410 static HRESULT WINAPI
testfilter_cf_LockServer(IClassFactory
*iface
, BOOL lock
)
1415 static IClassFactoryVtbl testfilter_cf_vtbl
=
1417 testfilter_cf_QueryInterface
,
1418 testfilter_cf_AddRef
,
1419 testfilter_cf_Release
,
1420 testfilter_cf_CreateInstance
,
1421 testfilter_cf_LockServer
,
1424 static void test_graph_builder_render(void)
1426 static const WCHAR testW
[] = {'t','e','s','t',0};
1427 static const GUID sink1_clsid
= {0x12345678};
1428 static const GUID sink2_clsid
= {0x87654321};
1429 AM_MEDIA_TYPE source_type
= {{0}};
1430 struct testpin source_pin
, sink1_pin
, sink2_pin
, parser_pins
[2];
1431 struct testfilter source
, sink1
, sink2
, parser
;
1432 struct testfilter_cf sink1_cf
= { {&testfilter_cf_vtbl
}, &sink1
};
1433 struct testfilter_cf sink2_cf
= { {&testfilter_cf_vtbl
}, &sink2
};
1435 IFilterGraph2
*graph
= create_graph();
1436 REGFILTERPINS2 regpins
= {0};
1437 REGPINTYPES regtypes
= {0};
1438 REGFILTER2 regfilter
= {0};
1439 IFilterMapper2
*mapper
;
1440 DWORD cookie1
, cookie2
;
1444 memset(&source_type
.majortype
, 0xcc, sizeof(GUID
));
1445 testsource_init(&source_pin
, &source_type
, 1);
1446 testfilter_init(&source
, &source_pin
, 1);
1447 testsink_init(&sink1_pin
);
1448 testfilter_init(&sink1
, &sink1_pin
, 1);
1449 testsink_init(&sink2_pin
);
1450 testfilter_init(&sink2
, &sink2_pin
, 1);
1451 testsink_init(&parser_pins
[0]);
1452 testsource_init(&parser_pins
[1], &source_type
, 1);
1453 testfilter_init(&parser
, parser_pins
, 2);
1455 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
1456 IFilterGraph2_AddFilter(graph
, &sink1
.IBaseFilter_iface
, NULL
);
1457 IFilterGraph2_AddFilter(graph
, &sink2
.IBaseFilter_iface
, NULL
);
1459 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1460 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1461 ok(source_pin
.peer
== &sink2_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1462 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
1463 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1465 IFilterGraph2_RemoveFilter(graph
, &sink1
.IBaseFilter_iface
);
1466 IFilterGraph2_AddFilter(graph
, &sink1
.IBaseFilter_iface
, NULL
);
1468 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1469 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1470 ok(source_pin
.peer
== &sink1_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1472 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1473 IFilterGraph2_Disconnect(graph
, &sink1_pin
.IPin_iface
);
1475 /* No preference is given to smaller chains. */
1477 IFilterGraph2_AddFilter(graph
, &parser
.IBaseFilter_iface
, NULL
);
1479 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1480 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1481 ok(source_pin
.peer
== &parser_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1482 ok(parser_pins
[1].peer
== &sink1_pin
.IPin_iface
, "Got peer %p.\n", parser_pins
[1].peer
);
1483 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
1484 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1486 IFilterGraph2_RemoveFilter(graph
, &sink1
.IBaseFilter_iface
);
1487 IFilterGraph2_AddFilter(graph
, &sink1
.IBaseFilter_iface
, NULL
);
1489 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1490 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1491 ok(source_pin
.peer
== &sink1_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1493 ref
= IFilterGraph2_Release(graph
);
1494 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1496 /* Test enumeration of filters from the registry. */
1498 graph
= create_graph();
1499 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
1501 CoRegisterClassObject(&sink1_clsid
, (IUnknown
*)&sink1_cf
.IClassFactory_iface
,
1502 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie1
);
1503 CoRegisterClassObject(&sink2_clsid
, (IUnknown
*)&sink2_cf
.IClassFactory_iface
,
1504 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie2
);
1506 CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
,
1507 &IID_IFilterMapper2
, (void **)&mapper
);
1509 regfilter
.dwVersion
= 2;
1510 regfilter
.dwMerit
= MERIT_UNLIKELY
;
1511 regfilter
.cPins2
= 1;
1512 regfilter
.rgPins2
= ®pins
;
1513 regpins
.dwFlags
= 0;
1514 regpins
.cInstances
= 1;
1515 regpins
.nMediaTypes
= 1;
1516 regpins
.lpMediaType
= ®types
;
1517 regtypes
.clsMajorType
= &source_type
.majortype
;
1518 regtypes
.clsMinorType
= &MEDIASUBTYPE_NULL
;
1519 hr
= IFilterMapper2_RegisterFilter(mapper
, &sink1_clsid
, testW
, NULL
, NULL
, NULL
, ®filter
);
1520 if (hr
== E_ACCESSDENIED
)
1522 skip("Not enough permission to register filters.\n");
1525 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1527 regpins
.dwFlags
= REG_PINFLAG_B_RENDERER
;
1528 IFilterMapper2_RegisterFilter(mapper
, &sink2_clsid
, testW
, NULL
, NULL
, NULL
, ®filter
);
1530 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1531 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1532 ok(source_pin
.peer
== &sink2_pin
.IPin_iface
|| source_pin
.peer
== &sink1_pin
.IPin_iface
,
1533 "Got peer %p.\n", source_pin
.peer
);
1535 ref
= IFilterGraph2_Release(graph
);
1536 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1538 /* Preference is given to filters already in the graph. */
1540 graph
= create_graph();
1541 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
1542 IFilterGraph2_AddFilter(graph
, &sink2
.IBaseFilter_iface
, NULL
);
1544 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1545 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1546 ok(source_pin
.peer
== &sink2_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1548 ref
= IFilterGraph2_Release(graph
);
1549 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1551 /* No preference is given to renderer filters. */
1553 graph
= create_graph();
1554 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
1556 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink1_clsid
);
1557 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink2_clsid
);
1559 IFilterMapper2_RegisterFilter(mapper
, &sink1_clsid
, testW
, NULL
, NULL
, NULL
, ®filter
);
1560 regpins
.dwFlags
= 0;
1561 IFilterMapper2_RegisterFilter(mapper
, &sink2_clsid
, testW
, NULL
, NULL
, NULL
, ®filter
);
1563 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1564 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1565 ok(source_pin
.peer
== &sink2_pin
.IPin_iface
|| source_pin
.peer
== &sink1_pin
.IPin_iface
,
1566 "Got peer %p.\n", source_pin
.peer
);
1568 ref
= IFilterGraph2_Release(graph
);
1569 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1571 /* Preference is given to filters with higher merit. */
1573 graph
= create_graph();
1574 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
1576 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink1_clsid
);
1577 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink2_clsid
);
1579 regfilter
.dwMerit
= MERIT_UNLIKELY
;
1580 IFilterMapper2_RegisterFilter(mapper
, &sink1_clsid
, testW
, NULL
, NULL
, NULL
, ®filter
);
1581 regfilter
.dwMerit
= MERIT_PREFERRED
;
1582 IFilterMapper2_RegisterFilter(mapper
, &sink2_clsid
, testW
, NULL
, NULL
, NULL
, ®filter
);
1584 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1585 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1586 ok(source_pin
.peer
== &sink2_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1588 ref
= IFilterGraph2_Release(graph
);
1589 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1591 graph
= create_graph();
1592 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
1594 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink1_clsid
);
1595 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink2_clsid
);
1597 regfilter
.dwMerit
= MERIT_PREFERRED
;
1598 IFilterMapper2_RegisterFilter(mapper
, &sink1_clsid
, testW
, NULL
, NULL
, NULL
, ®filter
);
1599 regfilter
.dwMerit
= MERIT_UNLIKELY
;
1600 IFilterMapper2_RegisterFilter(mapper
, &sink2_clsid
, testW
, NULL
, NULL
, NULL
, ®filter
);
1602 hr
= IFilterGraph2_Render(graph
, &source_pin
.IPin_iface
);
1603 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1604 ok(source_pin
.peer
== &sink1_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1606 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink1_clsid
);
1607 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &sink2_clsid
);
1610 CoRevokeClassObject(cookie1
);
1611 CoRevokeClassObject(cookie2
);
1612 IFilterMapper2_Release(mapper
);
1613 ref
= IFilterGraph2_Release(graph
);
1614 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1615 ok(source
.ref
== 1, "Got outstanding refcount %d.\n", source
.ref
);
1616 ok(source_pin
.ref
== 1, "Got outstanding refcount %d.\n", source_pin
.ref
);
1617 ok(sink1
.ref
== 1, "Got outstanding refcount %d.\n", sink1
.ref
);
1618 ok(sink1_pin
.ref
== 1, "Got outstanding refcount %d.\n", sink1_pin
.ref
);
1619 ok(sink2
.ref
== 1, "Got outstanding refcount %d.\n", sink2
.ref
);
1620 ok(sink2_pin
.ref
== 1, "Got outstanding refcount %d.\n", sink2_pin
.ref
);
1621 ok(parser
.ref
== 1, "Got outstanding refcount %d.\n", parser
.ref
);
1622 ok(parser_pins
[0].ref
== 1, "Got outstanding refcount %d.\n", parser_pins
[0].ref
);
1623 ok(parser_pins
[1].ref
== 1, "Got outstanding refcount %d.\n", parser_pins
[1].ref
);
1626 static void test_graph_builder_connect(void)
1628 static const WCHAR testW
[] = {'t','e','s','t',0};
1629 static const GUID parser1_clsid
= {0x12345678};
1630 static const GUID parser2_clsid
= {0x87654321};
1631 AM_MEDIA_TYPE source_type
= {{0}}, sink_type
= {{0}}, parser3_type
= {{0}};
1632 struct testpin source_pin
, sink_pin
, sink2_pin
, parser1_pins
[3], parser2_pins
[2], parser3_pins
[2];
1633 struct testfilter source
, sink
, sink2
, parser1
, parser2
, parser3
;
1634 struct testfilter_cf parser1_cf
= { {&testfilter_cf_vtbl
}, &parser1
};
1635 struct testfilter_cf parser2_cf
= { {&testfilter_cf_vtbl
}, &parser2
};
1637 IFilterGraph2
*graph
= create_graph();
1638 REGFILTERPINS2 regpins
[2] = {{0}};
1639 REGPINTYPES regtypes
= {0};
1640 REGFILTER2 regfilter
= {0};
1641 IFilterMapper2
*mapper
;
1642 DWORD cookie1
, cookie2
;
1646 memset(&source_type
.majortype
, 0xcc, sizeof(GUID
));
1647 memset(&sink_type
.majortype
, 0x66, sizeof(GUID
));
1648 testsource_init(&source_pin
, &source_type
, 1);
1649 source_pin
.request_mt
= &source_type
;
1650 testfilter_init(&source
, &source_pin
, 1);
1651 testsink_init(&sink_pin
);
1652 testfilter_init(&sink
, &sink_pin
, 1);
1653 testsink_init(&sink2_pin
);
1654 testfilter_init(&sink2
, &sink2_pin
, 1);
1656 testsink_init(&parser1_pins
[0]);
1657 testsource_init(&parser1_pins
[1], &sink_type
, 1);
1658 parser1_pins
[1].request_mt
= &sink_type
;
1659 testsource_init(&parser1_pins
[2], &sink_type
, 1);
1660 parser1_pins
[2].request_mt
= &sink_type
;
1661 testfilter_init(&parser1
, parser1_pins
, 3);
1662 parser1
.pin_count
= 2;
1664 testsink_init(&parser2_pins
[0]);
1665 testsource_init(&parser2_pins
[1], &sink_type
, 1);
1666 parser2_pins
[1].request_mt
= &sink_type
;
1667 testfilter_init(&parser2
, parser2_pins
, 2);
1669 testsink_init(&parser3_pins
[0]);
1670 testsource_init(&parser3_pins
[1], &sink_type
, 1);
1671 parser3_pins
[1].request_mt
= &parser3_type
;
1672 testfilter_init(&parser3
, parser3_pins
, 2);
1674 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
1675 IFilterGraph2_AddFilter(graph
, &sink
.IBaseFilter_iface
, NULL
);
1677 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
1678 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1679 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1680 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
1681 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1683 sink_pin
.accept_mt
= &sink_type
;
1684 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
1686 ok(hr
== VFW_E_CANNOT_CONNECT
, "Got hr %#x.\n", hr
);
1687 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
1689 /* Test usage of intermediate filters. Similarly to Render(), filters are
1690 * simply tried in enumeration order. */
1692 IFilterGraph2_AddFilter(graph
, &parser1
.IBaseFilter_iface
, NULL
);
1693 IFilterGraph2_AddFilter(graph
, &parser2
.IBaseFilter_iface
, NULL
);
1695 sink_pin
.accept_mt
= NULL
;
1696 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
1697 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1698 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1699 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
1700 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1702 sink_pin
.accept_mt
= &sink_type
;
1703 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
1705 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1706 ok(source_pin
.peer
== &parser2_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1707 ok(sink_pin
.peer
== &parser2_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
1709 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
1710 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1711 IFilterGraph2_Disconnect(graph
, sink_pin
.peer
);
1712 IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
1714 IFilterGraph2_RemoveFilter(graph
, &parser1
.IBaseFilter_iface
);
1715 IFilterGraph2_AddFilter(graph
, &parser1
.IBaseFilter_iface
, NULL
);
1717 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
1719 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1720 ok(source_pin
.peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1721 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
1723 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
1724 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1725 IFilterGraph2_Disconnect(graph
, sink_pin
.peer
);
1726 IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
1728 /* No preference is given to smaller chains. */
1730 IFilterGraph2_AddFilter(graph
, &parser3
.IBaseFilter_iface
, NULL
);
1731 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
1733 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1734 ok(source_pin
.peer
== &parser3_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1735 ok(parser3_pins
[1].peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", parser3_pins
[1].peer
);
1736 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
1738 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
1739 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1740 IFilterGraph2_Disconnect(graph
, parser3_pins
[0].peer
);
1741 IFilterGraph2_Disconnect(graph
, &parser3_pins
[0].IPin_iface
);
1742 IFilterGraph2_Disconnect(graph
, sink_pin
.peer
);
1743 IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
1745 IFilterGraph2_RemoveFilter(graph
, &parser3
.IBaseFilter_iface
);
1746 IFilterGraph2_RemoveFilter(graph
, &parser2
.IBaseFilter_iface
);
1748 /* Extra source pins on an intermediate filter are not rendered. */
1750 IFilterGraph2_RemoveFilter(graph
, &parser1
.IBaseFilter_iface
);
1751 parser1
.pin_count
= 3;
1752 IFilterGraph2_AddFilter(graph
, &parser1
.IBaseFilter_iface
, NULL
);
1753 IFilterGraph2_AddFilter(graph
, &sink2
.IBaseFilter_iface
, NULL
);
1755 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
1757 ok(hr
== VFW_S_PARTIAL_RENDER
, "Got hr %#x.\n", hr
);
1758 ok(source_pin
.peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1759 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
1761 ok(!parser1_pins
[2].peer
, "Got peer %p.\n", parser1_pins
[2].peer
);
1762 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
1763 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1764 IFilterGraph2_Disconnect(graph
, sink_pin
.peer
);
1765 IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
1766 parser1
.pin_count
= 2;
1768 /* QueryInternalConnections is not used to find output pins. */
1770 parser1_pins
[1].QueryInternalConnections_hr
= S_OK
;
1771 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
1773 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1774 ok(source_pin
.peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1775 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
1777 IFilterGraph2_Disconnect(graph
, source_pin
.peer
);
1778 IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
1779 IFilterGraph2_Disconnect(graph
, sink_pin
.peer
);
1780 IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
1782 ref
= IFilterGraph2_Release(graph
);
1783 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1785 /* Test enumeration of filters from the registry. */
1787 graph
= create_graph();
1788 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
1789 IFilterGraph2_AddFilter(graph
, &sink
.IBaseFilter_iface
, NULL
);
1791 CoRegisterClassObject(&parser1_clsid
, (IUnknown
*)&parser1_cf
.IClassFactory_iface
,
1792 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie1
);
1793 CoRegisterClassObject(&parser2_clsid
, (IUnknown
*)&parser2_cf
.IClassFactory_iface
,
1794 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie2
);
1796 CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
,
1797 &IID_IFilterMapper2
, (void **)&mapper
);
1799 regfilter
.dwVersion
= 2;
1800 regfilter
.dwMerit
= MERIT_UNLIKELY
;
1801 regfilter
.cPins2
= 2;
1802 regfilter
.rgPins2
= regpins
;
1803 regpins
[0].dwFlags
= 0;
1804 regpins
[0].cInstances
= 1;
1805 regpins
[0].nMediaTypes
= 1;
1806 regpins
[0].lpMediaType
= ®types
;
1807 regpins
[1].dwFlags
= REG_PINFLAG_B_OUTPUT
;
1808 regpins
[1].cInstances
= 1;
1809 regpins
[1].nMediaTypes
= 1;
1810 regpins
[1].lpMediaType
= ®types
;
1811 regtypes
.clsMajorType
= &source_type
.majortype
;
1812 regtypes
.clsMinorType
= &MEDIASUBTYPE_NULL
;
1813 hr
= IFilterMapper2_RegisterFilter(mapper
, &parser1_clsid
, testW
, NULL
, NULL
, NULL
, ®filter
);
1814 if (hr
== E_ACCESSDENIED
)
1816 skip("Not enough permission to register filters.\n");
1819 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1821 IFilterMapper2_RegisterFilter(mapper
, &parser2_clsid
, testW
, NULL
, NULL
, NULL
, ®filter
);
1823 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
1824 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1825 ok(source_pin
.peer
== &parser1_pins
[0].IPin_iface
1826 || source_pin
.peer
== &parser2_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1827 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
1828 || sink_pin
.peer
== &parser2_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
1830 ref
= IFilterGraph2_Release(graph
);
1831 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1833 /* Preference is given to filters already in the graph. */
1835 graph
= create_graph();
1836 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
1837 IFilterGraph2_AddFilter(graph
, &sink
.IBaseFilter_iface
, NULL
);
1838 IFilterGraph2_AddFilter(graph
, &parser1
.IBaseFilter_iface
, NULL
);
1840 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
1841 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1842 ok(source_pin
.peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1843 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
1845 ref
= IFilterGraph2_Release(graph
);
1846 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1848 /* Preference is given to filters with higher merit. */
1850 graph
= create_graph();
1851 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
1852 IFilterGraph2_AddFilter(graph
, &sink
.IBaseFilter_iface
, NULL
);
1854 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &parser1_clsid
);
1855 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &parser2_clsid
);
1857 regfilter
.dwMerit
= MERIT_UNLIKELY
;
1858 IFilterMapper2_RegisterFilter(mapper
, &parser1_clsid
, testW
, NULL
, NULL
, NULL
, ®filter
);
1859 regfilter
.dwMerit
= MERIT_PREFERRED
;
1860 IFilterMapper2_RegisterFilter(mapper
, &parser2_clsid
, testW
, NULL
, NULL
, NULL
, ®filter
);
1862 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
1863 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1864 ok(source_pin
.peer
== &parser2_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1865 ok(sink_pin
.peer
== &parser2_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
1867 ref
= IFilterGraph2_Release(graph
);
1868 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1870 graph
= create_graph();
1871 IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
1872 IFilterGraph2_AddFilter(graph
, &sink
.IBaseFilter_iface
, NULL
);
1874 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &parser1_clsid
);
1875 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &parser2_clsid
);
1877 regfilter
.dwMerit
= MERIT_PREFERRED
;
1878 IFilterMapper2_RegisterFilter(mapper
, &parser1_clsid
, testW
, NULL
, NULL
, NULL
, ®filter
);
1879 regfilter
.dwMerit
= MERIT_UNLIKELY
;
1880 IFilterMapper2_RegisterFilter(mapper
, &parser2_clsid
, testW
, NULL
, NULL
, NULL
, ®filter
);
1882 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
1883 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
1884 ok(source_pin
.peer
== &parser1_pins
[0].IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
1885 ok(sink_pin
.peer
== &parser1_pins
[1].IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
1887 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &parser1_clsid
);
1888 IFilterMapper2_UnregisterFilter(mapper
, NULL
, NULL
, &parser2_clsid
);
1891 CoRevokeClassObject(cookie1
);
1892 CoRevokeClassObject(cookie2
);
1893 IFilterMapper2_Release(mapper
);
1894 ref
= IFilterGraph2_Release(graph
);
1895 ok(!ref
, "Got outstanding refcount %d.\n", ref
);
1896 ok(source
.ref
== 1, "Got outstanding refcount %d.\n", source
.ref
);
1897 ok(source_pin
.ref
== 1, "Got outstanding refcount %d.\n", source_pin
.ref
);
1898 ok(sink
.ref
== 1, "Got outstanding refcount %d.\n", sink
.ref
);
1899 ok(sink_pin
.ref
== 1, "Got outstanding refcount %d.\n", sink_pin
.ref
);
1900 ok(parser1
.ref
== 1, "Got outstanding refcount %d.\n", parser1
.ref
);
1901 ok(parser1_pins
[0].ref
== 1, "Got outstanding refcount %d.\n", parser1_pins
[0].ref
);
1902 ok(parser1_pins
[1].ref
== 1, "Got outstanding refcount %d.\n", parser1_pins
[1].ref
);
1903 ok(parser1_pins
[2].ref
== 1, "Got outstanding refcount %d.\n", parser1_pins
[2].ref
);
1904 ok(parser2
.ref
== 1, "Got outstanding refcount %d.\n", parser2
.ref
);
1905 ok(parser2_pins
[0].ref
== 1, "Got outstanding refcount %d.\n", parser2_pins
[0].ref
);
1906 ok(parser2_pins
[1].ref
== 1, "Got outstanding refcount %d.\n", parser2_pins
[1].ref
);
1907 ok(parser3
.ref
== 1, "Got outstanding refcount %d.\n", parser3
.ref
);
1908 ok(parser3_pins
[0].ref
== 1, "Got outstanding refcount %d.\n", parser3_pins
[0].ref
);
1909 ok(parser3_pins
[1].ref
== 1, "Got outstanding refcount %d.\n", parser3_pins
[1].ref
);
1912 typedef struct IUnknownImpl
1914 IUnknown IUnknown_iface
;
1919 static IUnknownImpl
*IUnknownImpl_from_iface(IUnknown
* iface
)
1921 return CONTAINING_RECORD(iface
, IUnknownImpl
, IUnknown_iface
);
1924 static HRESULT WINAPI
IUnknownImpl_QueryInterface(IUnknown
* iface
, REFIID riid
, LPVOID
* ppv
)
1926 ok(0, "QueryInterface should not be called for %s\n", wine_dbgstr_guid(riid
));
1927 return E_NOINTERFACE
;
1930 static ULONG WINAPI
IUnknownImpl_AddRef(IUnknown
* iface
)
1932 IUnknownImpl
*This
= IUnknownImpl_from_iface(iface
);
1933 This
->AddRef_called
++;
1937 static ULONG WINAPI
IUnknownImpl_Release(IUnknown
* iface
)
1939 IUnknownImpl
*This
= IUnknownImpl_from_iface(iface
);
1940 This
->Release_called
++;
1944 static CONST_VTBL IUnknownVtbl IUnknownImpl_Vtbl
=
1946 IUnknownImpl_QueryInterface
,
1947 IUnknownImpl_AddRef
,
1948 IUnknownImpl_Release
1951 static void test_aggregate_filter_graph(void)
1956 IUnknownImpl unk_outer
= { { &IUnknownImpl_Vtbl
}, 0, 0 };
1958 hr
= CoCreateInstance(&CLSID_FilterGraph
, &unk_outer
.IUnknown_iface
, CLSCTX_INPROC_SERVER
,
1959 &IID_IUnknown
, (void **)&pgraph
);
1960 ok(hr
== S_OK
, "CoCreateInstance returned %x\n", hr
);
1961 ok(pgraph
!= &unk_outer
.IUnknown_iface
, "pgraph = %p, expected not %p\n", pgraph
, &unk_outer
.IUnknown_iface
);
1963 hr
= IUnknown_QueryInterface(pgraph
, &IID_IUnknown
, (void **)&punk
);
1964 ok(hr
== S_OK
, "CoCreateInstance returned %x\n", hr
);
1965 ok(punk
!= &unk_outer
.IUnknown_iface
, "punk = %p, expected not %p\n", punk
, &unk_outer
.IUnknown_iface
);
1966 IUnknown_Release(punk
);
1968 ok(unk_outer
.AddRef_called
== 0, "IUnknownImpl_AddRef called %d times\n", unk_outer
.AddRef_called
);
1969 ok(unk_outer
.Release_called
== 0, "IUnknownImpl_Release called %d times\n", unk_outer
.Release_called
);
1970 unk_outer
.AddRef_called
= 0;
1971 unk_outer
.Release_called
= 0;
1973 hr
= IUnknown_QueryInterface(pgraph
, &IID_IFilterMapper
, (void **)&punk
);
1974 ok(hr
== S_OK
, "CoCreateInstance returned %x\n", hr
);
1975 ok(punk
!= &unk_outer
.IUnknown_iface
, "punk = %p, expected not %p\n", punk
, &unk_outer
.IUnknown_iface
);
1976 IUnknown_Release(punk
);
1978 ok(unk_outer
.AddRef_called
== 1, "IUnknownImpl_AddRef called %d times\n", unk_outer
.AddRef_called
);
1979 ok(unk_outer
.Release_called
== 1, "IUnknownImpl_Release called %d times\n", unk_outer
.Release_called
);
1980 unk_outer
.AddRef_called
= 0;
1981 unk_outer
.Release_called
= 0;
1983 hr
= IUnknown_QueryInterface(pgraph
, &IID_IFilterMapper2
, (void **)&punk
);
1984 ok(hr
== S_OK
, "CoCreateInstance returned %x\n", hr
);
1985 ok(punk
!= &unk_outer
.IUnknown_iface
, "punk = %p, expected not %p\n", punk
, &unk_outer
.IUnknown_iface
);
1986 IUnknown_Release(punk
);
1988 ok(unk_outer
.AddRef_called
== 1, "IUnknownImpl_AddRef called %d times\n", unk_outer
.AddRef_called
);
1989 ok(unk_outer
.Release_called
== 1, "IUnknownImpl_Release called %d times\n", unk_outer
.Release_called
);
1990 unk_outer
.AddRef_called
= 0;
1991 unk_outer
.Release_called
= 0;
1993 hr
= IUnknown_QueryInterface(pgraph
, &IID_IFilterMapper3
, (void **)&punk
);
1994 ok(hr
== S_OK
, "CoCreateInstance returned %x\n", hr
);
1995 ok(punk
!= &unk_outer
.IUnknown_iface
, "punk = %p, expected not %p\n", punk
, &unk_outer
.IUnknown_iface
);
1996 IUnknown_Release(punk
);
1998 ok(unk_outer
.AddRef_called
== 1, "IUnknownImpl_AddRef called %d times\n", unk_outer
.AddRef_called
);
1999 ok(unk_outer
.Release_called
== 1, "IUnknownImpl_Release called %d times\n", unk_outer
.Release_called
);
2001 IUnknown_Release(pgraph
);
2004 /* Test how methods from "control" interfaces (IBasicAudio, IBasicVideo,
2005 * IVideoWindow) are delegated to filters exposing those interfaces. */
2006 static void test_control_delegation(void)
2008 IFilterGraph2
*graph
= create_graph();
2009 IBasicAudio
*audio
, *filter_audio
;
2010 IBaseFilter
*renderer
;
2011 IVideoWindow
*window
;
2018 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IBasicAudio
, (void **)&audio
);
2019 ok(hr
== S_OK
, "got %#x\n", hr
);
2021 hr
= IBasicAudio_put_Volume(audio
, -10);
2022 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2023 hr
= IBasicAudio_get_Volume(audio
, &val
);
2024 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2025 hr
= IBasicAudio_put_Balance(audio
, 10);
2026 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2027 hr
= IBasicAudio_get_Balance(audio
, &val
);
2028 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2030 hr
= CoCreateInstance(&CLSID_DSoundRender
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
, (void **)&renderer
);
2031 if (hr
!= VFW_E_NO_AUDIO_HARDWARE
)
2033 ok(hr
== S_OK
, "got %#x\n", hr
);
2035 hr
= IFilterGraph2_AddFilter(graph
, renderer
, NULL
);
2036 ok(hr
== S_OK
, "got %#x\n", hr
);
2038 hr
= IBasicAudio_put_Volume(audio
, -10);
2039 ok(hr
== S_OK
, "got %#x\n", hr
);
2040 hr
= IBasicAudio_get_Volume(audio
, &val
);
2041 ok(hr
== S_OK
, "got %#x\n", hr
);
2042 ok(val
== -10, "got %d\n", val
);
2043 hr
= IBasicAudio_put_Balance(audio
, 10);
2044 ok(hr
== S_OK
|| hr
== VFW_E_MONO_AUDIO_HW
, "got %#x\n", hr
);
2045 hr
= IBasicAudio_get_Balance(audio
, &val
);
2046 ok(hr
== S_OK
|| hr
== VFW_E_MONO_AUDIO_HW
, "got %#x\n", hr
);
2048 ok(val
== 10, "got balance %d\n", val
);
2050 hr
= IBaseFilter_QueryInterface(renderer
, &IID_IBasicAudio
, (void **)&filter_audio
);
2051 ok(hr
== S_OK
, "got %#x\n", hr
);
2053 hr
= IBasicAudio_get_Volume(filter_audio
, &val
);
2054 ok(hr
== S_OK
, "got %#x\n", hr
);
2055 ok(val
== -10, "got volume %d\n", val
);
2057 hr
= IFilterGraph2_RemoveFilter(graph
, renderer
);
2058 ok(hr
== S_OK
, "got %#x\n", hr
);
2060 IBaseFilter_Release(renderer
);
2061 IBasicAudio_Release(filter_audio
);
2064 hr
= IBasicAudio_put_Volume(audio
, -10);
2065 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2066 hr
= IBasicAudio_get_Volume(audio
, &val
);
2067 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2068 hr
= IBasicAudio_put_Balance(audio
, 10);
2069 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2070 hr
= IBasicAudio_get_Balance(audio
, &val
);
2071 ok(hr
== E_NOTIMPL
, "got %#x\n", hr
);
2073 IBasicAudio_Release(audio
);
2075 /* IBasicVideo and IVideoWindow */
2077 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IBasicVideo
, (void **)&video
);
2078 ok(hr
== S_OK
, "got %#x\n", hr
);
2079 hr
= IFilterGraph2_QueryInterface(graph
, &IID_IVideoWindow
, (void **)&window
);
2080 ok(hr
== S_OK
, "got %#x\n", hr
);
2082 /* Unlike IBasicAudio, these return E_NOINTERFACE. */
2083 hr
= IBasicVideo_get_BitRate(video
, &val
);
2084 ok(hr
== E_NOINTERFACE
, "got %#x\n", hr
);
2085 hr
= IVideoWindow_SetWindowForeground(window
, OAFALSE
);
2086 ok(hr
== E_NOINTERFACE
, "got %#x\n", hr
);
2088 hr
= CoCreateInstance(&CLSID_VideoRenderer
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IBaseFilter
, (void **)&renderer
);
2089 ok(hr
== S_OK
, "got %#x\n", hr
);
2091 hr
= IFilterGraph2_AddFilter(graph
, renderer
, NULL
);
2092 ok(hr
== S_OK
, "got %#x\n", hr
);
2094 hr
= IBasicVideo_get_BitRate(video
, &val
);
2095 ok(hr
== VFW_E_NOT_CONNECTED
, "got %#x\n", hr
);
2096 hr
= IVideoWindow_SetWindowForeground(window
, OAFALSE
);
2097 ok(hr
== VFW_E_NOT_CONNECTED
, "got %#x\n", hr
);
2099 hr
= IFilterGraph2_RemoveFilter(graph
, renderer
);
2100 ok(hr
== S_OK
, "got %#x\n", hr
);
2102 hr
= IBasicVideo_get_BitRate(video
, &val
);
2103 ok(hr
== E_NOINTERFACE
, "got %#x\n", hr
);
2104 hr
= IVideoWindow_SetWindowForeground(window
, OAFALSE
);
2105 ok(hr
== E_NOINTERFACE
, "got %#x\n", hr
);
2107 IBaseFilter_Release(renderer
);
2108 IBasicVideo_Release(video
);
2109 IVideoWindow_Release(window
);
2110 IFilterGraph2_Release(graph
);
2113 static void test_add_remove_filter(void)
2115 static const WCHAR defaultid
[] = {'0','0','0','1',0};
2116 static const WCHAR testid
[] = {'t','e','s','t','i','d',0};
2117 struct testfilter filter
;
2119 IFilterGraph2
*graph
= create_graph();
2120 IBaseFilter
*ret_filter
;
2123 testfilter_init(&filter
, NULL
, 0);
2125 hr
= IFilterGraph2_FindFilterByName(graph
, testid
, &ret_filter
);
2126 ok(hr
== VFW_E_NOT_FOUND
, "Got hr %#x.\n", hr
);
2127 ok(!ret_filter
, "Got filter %p.\n", ret_filter
);
2129 hr
= IFilterGraph2_AddFilter(graph
, &filter
.IBaseFilter_iface
, testid
);
2130 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2131 ok(filter
.graph
== (IFilterGraph
*)graph
, "Got graph %p.\n", filter
.graph
);
2132 ok(!lstrcmpW(filter
.name
, testid
), "Got name %s.\n", wine_dbgstr_w(filter
.name
));
2134 hr
= IFilterGraph2_FindFilterByName(graph
, testid
, &ret_filter
);
2135 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2136 ok(ret_filter
== &filter
.IBaseFilter_iface
, "Got filter %p.\n", ret_filter
);
2137 IBaseFilter_Release(ret_filter
);
2139 hr
= IFilterGraph2_RemoveFilter(graph
, &filter
.IBaseFilter_iface
);
2140 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2141 ok(!filter
.graph
, "Got graph %p.\n", filter
.graph
);
2142 ok(!filter
.name
, "Got name %s.\n", wine_dbgstr_w(filter
.name
));
2143 ok(!filter
.clock
, "Got clock %p,\n", filter
.clock
);
2144 ok(filter
.ref
== 1, "Got outstanding refcount %d.\n", filter
.ref
);
2146 hr
= IFilterGraph2_FindFilterByName(graph
, testid
, &ret_filter
);
2147 ok(hr
== VFW_E_NOT_FOUND
, "Got hr %#x.\n", hr
);
2148 ok(!ret_filter
, "Got filter %p.\n", ret_filter
);
2150 hr
= IFilterGraph2_AddFilter(graph
, &filter
.IBaseFilter_iface
, NULL
);
2151 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2152 ok(filter
.graph
== (IFilterGraph
*)graph
, "Got graph %p.\n", filter
.graph
);
2153 ok(!lstrcmpW(filter
.name
, defaultid
), "Got name %s.\n", wine_dbgstr_w(filter
.name
));
2155 hr
= IFilterGraph2_FindFilterByName(graph
, defaultid
, &ret_filter
);
2156 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2157 ok(ret_filter
== &filter
.IBaseFilter_iface
, "Got filter %p.\n", ret_filter
);
2158 IBaseFilter_Release(ret_filter
);
2160 /* test releasing the filter graph while filters are still connected */
2161 hr
= IFilterGraph2_Release(graph
);
2162 ok(!hr
, "Got outstanding refcount %d.\n", hr
);
2163 ok(!filter
.graph
, "Got graph %p.\n", filter
.graph
);
2164 ok(!filter
.name
, "Got name %s.\n", wine_dbgstr_w(filter
.name
));
2165 ok(!filter
.clock
, "Got clock %p.\n", filter
.clock
);
2166 ok(filter
.ref
== 1, "Got outstanding refcount %d.\n", filter
.ref
);
2169 static HRESULT WINAPI
test_connect_direct_Connect(IPin
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
2171 struct testpin
*pin
= impl_from_IPin(iface
);
2172 if (winetest_debug
> 1) trace("%p->Connect()\n", pin
);
2176 pin
->mt
= (AM_MEDIA_TYPE
*)mt
;
2180 static const IPinVtbl test_connect_direct_vtbl
=
2182 testpin_QueryInterface
,
2185 test_connect_direct_Connect
,
2186 no_ReceiveConnection
,
2188 testpin_ConnectedTo
,
2189 testpin_ConnectionMediaType
,
2190 testpin_QueryPinInfo
,
2191 testpin_QueryDirection
,
2193 testpin_QueryAccept
,
2195 testpin_QueryInternalConnections
,
2196 testpin_EndOfStream
,
2202 static void test_connect_direct_init(struct testpin
*pin
, PIN_DIRECTION dir
)
2204 memset(pin
, 0, sizeof(*pin
));
2205 pin
->IPin_iface
.lpVtbl
= &test_connect_direct_vtbl
;
2210 static void test_connect_direct(void)
2212 struct testpin source_pin
, sink_pin
;
2213 struct testfilter source
, sink
;
2215 IFilterGraph2
*graph
= create_graph();
2219 test_connect_direct_init(&source_pin
, PINDIR_OUTPUT
);
2220 test_connect_direct_init(&sink_pin
, PINDIR_INPUT
);
2221 testfilter_init(&source
, &source_pin
, 1);
2222 testfilter_init(&sink
, &sink_pin
, 1);
2224 hr
= IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
2225 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2227 hr
= IFilterGraph2_AddFilter(graph
, &sink
.IBaseFilter_iface
, NULL
);
2228 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2230 hr
= IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, NULL
);
2231 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2232 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2233 ok(!source_pin
.mt
, "Got mt %p.\n", source_pin
.mt
);
2234 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2236 hr
= IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2237 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2238 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2239 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2241 hr
= IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2242 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2243 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2244 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2246 hr
= IFilterGraph2_Connect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
);
2247 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2248 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2249 ok(!source_pin
.mt
, "Got mt %p.\n", source_pin
.mt
);
2250 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2252 hr
= IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2253 ok(hr
== S_FALSE
, "Got hr %#x.\n", hr
);
2254 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2255 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2257 hr
= IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2258 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2259 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2260 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2262 /* Swap the pins when connecting. */
2263 hr
= IFilterGraph2_ConnectDirect(graph
, &sink_pin
.IPin_iface
, &source_pin
.IPin_iface
, NULL
);
2264 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2266 ok(sink_pin
.peer
== &source_pin
.IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2267 ok(!sink_pin
.mt
, "Got mt %p.\n", sink_pin
.mt
);
2269 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2271 hr
= IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2273 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2275 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2276 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2278 hr
= IFilterGraph2_Connect(graph
, &sink_pin
.IPin_iface
, &source_pin
.IPin_iface
);
2279 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2281 ok(sink_pin
.peer
== &source_pin
.IPin_iface
, "Got peer %p.\n", sink_pin
.peer
);
2282 ok(!sink_pin
.mt
, "Got mt %p.\n", sink_pin
.mt
);
2284 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2286 hr
= IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2288 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2290 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2291 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2293 /* Disconnect() does not disconnect the peer. */
2294 hr
= IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, NULL
);
2295 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2296 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2297 ok(!source_pin
.mt
, "Got mt %p.\n", source_pin
.mt
);
2298 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2300 sink_pin
.peer
= &source_pin
.IPin_iface
;
2301 IPin_AddRef(sink_pin
.peer
);
2303 hr
= IFilterGraph2_Disconnect(graph
, &sink_pin
.IPin_iface
);
2304 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2305 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2306 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2308 hr
= IFilterGraph2_Disconnect(graph
, &source_pin
.IPin_iface
);
2309 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2310 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2311 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2313 /* Test specifying the media type. */
2314 hr
= IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, &mt
);
2315 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2316 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2317 ok(source_pin
.mt
== &mt
, "Got mt %p.\n", source_pin
.mt
);
2318 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2320 /* Both pins are disconnected when a filter is removed. */
2321 sink_pin
.peer
= &source_pin
.IPin_iface
;
2322 IPin_AddRef(sink_pin
.peer
);
2323 hr
= IFilterGraph2_RemoveFilter(graph
, &source
.IBaseFilter_iface
);
2324 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2325 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2326 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2328 /* Or when the graph is destroyed. */
2329 hr
= IFilterGraph2_AddFilter(graph
, &source
.IBaseFilter_iface
, NULL
);
2330 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2332 hr
= IFilterGraph2_ConnectDirect(graph
, &source_pin
.IPin_iface
, &sink_pin
.IPin_iface
, NULL
);
2333 ok(hr
== S_OK
, "Got hr %#x.\n", hr
);
2334 ok(source_pin
.peer
== &sink_pin
.IPin_iface
, "Got peer %p.\n", source_pin
.peer
);
2335 ok(!source_pin
.mt
, "Got mt %p.\n", source_pin
.mt
);
2336 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2337 IPin_AddRef(sink_pin
.peer
= &source_pin
.IPin_iface
);
2339 hr
= IFilterGraph2_Release(graph
);
2340 ok(!hr
, "Got outstanding refcount %d.\n", hr
);
2341 ok(source
.ref
== 1, "Got outstanding refcount %d.\n", source
.ref
);
2342 ok(sink
.ref
== 1, "Got outstanding refcount %d.\n", sink
.ref
);
2343 ok(source_pin
.ref
== 1, "Got outstanding refcount %d.\n", source_pin
.ref
);
2345 ok(sink_pin
.ref
== 1, "Got outstanding refcount %d.\n", sink_pin
.ref
);
2346 ok(!source_pin
.peer
, "Got peer %p.\n", source_pin
.peer
);
2347 ok(!sink_pin
.peer
, "Got peer %p.\n", sink_pin
.peer
);
2350 START_TEST(filtergraph
)
2352 CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
2355 test_render_run(avifile
);
2356 test_render_run(mpegfile
);
2357 test_enum_filters();
2358 test_graph_builder_render();
2359 test_graph_builder_connect();
2360 test_aggregate_filter_graph();
2361 test_control_delegation();
2362 test_add_remove_filter();
2363 test_connect_direct();
2366 test_render_with_multithread();