quartz/tests: Fix test failures on Windows XP without upgraded DirectX.
[wine.git] / dlls / quartz / tests / filtergraph.c
blob6d5f8d11076141279ccfbf6344a8a19cf209044b
1 /*
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
22 #define COBJMACROS
23 #define CONST_VTABLE
25 #include "wine/test.h"
26 #include "dshow.h"
27 #include "control.h"
29 typedef struct TestFilterImpl
31 IBaseFilter IBaseFilter_iface;
33 LONG refCount;
34 CRITICAL_SECTION csFilter;
35 FILTER_STATE state;
36 FILTER_INFO filterInfo;
37 CLSID clsid;
38 IPin **ppPins;
39 UINT nPins;
40 } TestFilterImpl;
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 IGraphBuilder *pgraph;
47 static int createfiltergraph(void)
49 return S_OK == CoCreateInstance(
50 &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&pgraph);
53 static void test_basic_video(void)
55 IBasicVideo* pbv;
56 LONG video_width, video_height;
57 LONG left, top, width, height;
58 HRESULT hr;
60 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IBasicVideo, (LPVOID*)&pbv);
61 ok(hr==S_OK, "Cannot get IBasicVideo interface returned: %x\n", hr);
63 /* test get video size */
64 hr = IBasicVideo_GetVideoSize(pbv, NULL, NULL);
65 ok(hr==E_POINTER, "IBasicVideo_GetVideoSize returned: %x\n", hr);
66 hr = IBasicVideo_GetVideoSize(pbv, &video_width, NULL);
67 ok(hr==E_POINTER, "IBasicVideo_GetVideoSize returned: %x\n", hr);
68 hr = IBasicVideo_GetVideoSize(pbv, NULL, &video_height);
69 ok(hr==E_POINTER, "IBasicVideo_GetVideoSize returned: %x\n", hr);
70 hr = IBasicVideo_GetVideoSize(pbv, &video_width, &video_height);
71 ok(hr==S_OK, "Cannot get video size returned: %x\n", hr);
73 /* test source position */
74 hr = IBasicVideo_GetSourcePosition(pbv, NULL, NULL, NULL, NULL);
75 ok(hr == E_POINTER, "IBasicVideo_GetSourcePosition returned: %x\n", hr);
76 hr = IBasicVideo_GetSourcePosition(pbv, &left, &top, NULL, NULL);
77 ok(hr == E_POINTER, "IBasicVideo_GetSourcePosition returned: %x\n", hr);
78 hr = IBasicVideo_GetSourcePosition(pbv, NULL, NULL, &width, &height);
79 ok(hr == E_POINTER, "IBasicVideo_GetSourcePosition returned: %x\n", hr);
80 hr = IBasicVideo_GetSourcePosition(pbv, &left, &top, &width, &height);
81 ok(hr == S_OK, "Cannot get source position returned: %x\n", hr);
82 ok(left == 0, "expected 0, got %d\n", left);
83 ok(top == 0, "expected 0, got %d\n", top);
84 ok(width == video_width, "expected %d, got %d\n", video_width, width);
85 ok(height == video_height, "expected %d, got %d\n", video_height, height);
87 hr = IBasicVideo_SetSourcePosition(pbv, 0, 0, 0, 0);
88 ok(hr==E_INVALIDARG, "IBasicVideo_SetSourcePosition returned: %x\n", hr);
89 hr = IBasicVideo_SetSourcePosition(pbv, 0, 0, video_width*2, video_height*2);
90 ok(hr==E_INVALIDARG, "IBasicVideo_SetSourcePosition returned: %x\n", hr);
91 hr = IBasicVideo_put_SourceTop(pbv, -1);
92 ok(hr==E_INVALIDARG, "IBasicVideo_put_SourceTop returned: %x\n", hr);
93 hr = IBasicVideo_put_SourceTop(pbv, 0);
94 ok(hr==S_OK, "Cannot put source top returned: %x\n", hr);
95 hr = IBasicVideo_put_SourceTop(pbv, 1);
96 ok(hr==E_INVALIDARG, "IBasicVideo_put_SourceTop returned: %x\n", hr);
98 hr = IBasicVideo_SetSourcePosition(pbv, video_width, 0, video_width, video_height);
99 ok(hr==E_INVALIDARG, "IBasicVideo_SetSourcePosition returned: %x\n", hr);
100 hr = IBasicVideo_SetSourcePosition(pbv, 0, video_height, video_width, video_height);
101 ok(hr==E_INVALIDARG, "IBasicVideo_SetSourcePosition returned: %x\n", hr);
102 hr = IBasicVideo_SetSourcePosition(pbv, -1, 0, video_width, video_height);
103 ok(hr==E_INVALIDARG, "IBasicVideo_SetSourcePosition returned: %x\n", hr);
104 hr = IBasicVideo_SetSourcePosition(pbv, 0, -1, video_width, video_height);
105 ok(hr==E_INVALIDARG, "IBasicVideo_SetSourcePosition returned: %x\n", hr);
106 hr = IBasicVideo_SetSourcePosition(pbv, video_width/2, video_height/2, video_width, video_height);
107 ok(hr==E_INVALIDARG, "IBasicVideo_SetSourcePosition returned: %x\n", hr);
108 hr = IBasicVideo_SetSourcePosition(pbv, video_width/2, video_height/2, video_width, video_height);
109 ok(hr==E_INVALIDARG, "IBasicVideo_SetSourcePosition returned: %x\n", hr);
111 hr = IBasicVideo_SetSourcePosition(pbv, 0, 0, video_width, video_height+1);
112 ok(hr==E_INVALIDARG, "IBasicVideo_SetSourcePosition returned: %x\n", hr);
113 hr = IBasicVideo_SetSourcePosition(pbv, 0, 0, video_width+1, video_height);
114 ok(hr==E_INVALIDARG, "IBasicVideo_SetSourcePosition returned: %x\n", hr);
116 hr = IBasicVideo_SetSourcePosition(pbv, video_width/2, video_height/2, video_width/3+1, video_height/3+1);
117 ok(hr==S_OK, "Cannot set source position returned: %x\n", hr);
119 hr = IBasicVideo_get_SourceLeft(pbv, &left);
120 ok(hr==S_OK, "Cannot get source left returned: %x\n", hr);
121 ok(left==video_width/2, "expected %d, got %d\n", video_width/2, left);
122 hr = IBasicVideo_get_SourceTop(pbv, &top);
123 ok(hr==S_OK, "Cannot get source top returned: %x\n", hr);
124 ok(top==video_height/2, "expected %d, got %d\n", video_height/2, top);
125 hr = IBasicVideo_get_SourceWidth(pbv, &width);
126 ok(hr==S_OK, "Cannot get source width returned: %x\n", hr);
127 ok(width==video_width/3+1, "expected %d, got %d\n", video_width/3+1, width);
128 hr = IBasicVideo_get_SourceHeight(pbv, &height);
129 ok(hr==S_OK, "Cannot get source height returned: %x\n", hr);
130 ok(height==video_height/3+1, "expected %d, got %d\n", video_height/3+1, height);
132 hr = IBasicVideo_put_SourceLeft(pbv, video_width/3);
133 ok(hr==S_OK, "Cannot put source left returned: %x\n", hr);
134 hr = IBasicVideo_GetSourcePosition(pbv, &left, &top, &width, &height);
135 ok(hr == S_OK, "Cannot get source position returned: %x\n", hr);
136 ok(left == video_width/3, "expected %d, got %d\n", video_width/3, left);
137 ok(width == video_width/3+1, "expected %d, got %d\n", video_width/3+1, width);
139 hr = IBasicVideo_put_SourceTop(pbv, video_height/3);
140 ok(hr==S_OK, "Cannot put source top returned: %x\n", hr);
141 hr = IBasicVideo_GetSourcePosition(pbv, &left, &top, &width, &height);
142 ok(hr == S_OK, "Cannot get source position returned: %x\n", hr);
143 ok(top == video_height/3, "expected %d, got %d\n", video_height/3, top);
144 ok(height == video_height/3+1, "expected %d, got %d\n", video_height/3+1, height);
146 hr = IBasicVideo_put_SourceWidth(pbv, video_width/4+1);
147 ok(hr==S_OK, "Cannot put source width returned: %x\n", hr);
148 hr = IBasicVideo_GetSourcePosition(pbv, &left, &top, &width, &height);
149 ok(hr == S_OK, "Cannot get source position returned: %x\n", hr);
150 ok(left == video_width/3, "expected %d, got %d\n", video_width/3, left);
151 ok(width == video_width/4+1, "expected %d, got %d\n", video_width/4+1, width);
153 hr = IBasicVideo_put_SourceHeight(pbv, video_height/4+1);
154 ok(hr==S_OK, "Cannot put source height returned: %x\n", hr);
155 hr = IBasicVideo_GetSourcePosition(pbv, &left, &top, &width, &height);
156 ok(hr == S_OK, "Cannot get source position returned: %x\n", hr);
157 ok(top == video_height/3, "expected %d, got %d\n", video_height/3, top);
158 ok(height == video_height/4+1, "expected %d, got %d\n", video_height/4+1, height);
160 /* test destination rectangle */
161 hr = IBasicVideo_GetDestinationPosition(pbv, NULL, NULL, NULL, NULL);
162 ok(hr == E_POINTER, "IBasicVideo_GetDestinationPosition returned: %x\n", hr);
163 hr = IBasicVideo_GetDestinationPosition(pbv, &left, &top, NULL, NULL);
164 ok(hr == E_POINTER, "IBasicVideo_GetDestinationPosition returned: %x\n", hr);
165 hr = IBasicVideo_GetDestinationPosition(pbv, NULL, NULL, &width, &height);
166 ok(hr == E_POINTER, "IBasicVideo_GetDestinationPosition returned: %x\n", hr);
167 hr = IBasicVideo_GetDestinationPosition(pbv, &left, &top, &width, &height);
168 ok(hr == S_OK, "Cannot get destination position returned: %x\n", hr);
169 ok(left == 0, "expected 0, got %d\n", left);
170 ok(top == 0, "expected 0, got %d\n", top);
171 todo_wine ok(width == video_width, "expected %d, got %d\n", video_width, width);
172 todo_wine ok(height == video_height, "expected %d, got %d\n", video_height, height);
174 hr = IBasicVideo_SetDestinationPosition(pbv, 0, 0, 0, 0);
175 ok(hr==E_INVALIDARG, "IBasicVideo_SetDestinationPosition returned: %x\n", hr);
176 hr = IBasicVideo_SetDestinationPosition(pbv, 0, 0, video_width*2, video_height*2);
177 ok(hr==S_OK, "Cannot put destination position returned: %x\n", hr);
179 hr = IBasicVideo_put_DestinationLeft(pbv, -1);
180 ok(hr==S_OK, "Cannot put destination left returned: %x\n", hr);
181 hr = IBasicVideo_put_DestinationLeft(pbv, 0);
182 ok(hr==S_OK, "Cannot put destination left returned: %x\n", hr);
183 hr = IBasicVideo_put_DestinationLeft(pbv, 1);
184 ok(hr==S_OK, "Cannot put destination left returned: %x\n", hr);
186 hr = IBasicVideo_SetDestinationPosition(pbv, video_width, 0, video_width, video_height);
187 ok(hr==S_OK, "Cannot set destinaiton position returned: %x\n", hr);
188 hr = IBasicVideo_SetDestinationPosition(pbv, 0, video_height, video_width, video_height);
189 ok(hr==S_OK, "Cannot set destinaiton position returned: %x\n", hr);
190 hr = IBasicVideo_SetDestinationPosition(pbv, -1, 0, video_width, video_height);
191 ok(hr==S_OK, "Cannot set destination position returned: %x\n", hr);
192 hr = IBasicVideo_SetDestinationPosition(pbv, 0, -1, video_width, video_height);
193 ok(hr==S_OK, "Cannot set destination position returned: %x\n", hr);
194 hr = IBasicVideo_SetDestinationPosition(pbv, video_width/2, video_height/2, video_width, video_height);
195 ok(hr==S_OK, "Cannot set destination position returned: %x\n", hr);
196 hr = IBasicVideo_SetDestinationPosition(pbv, video_width/2, video_height/2, video_width, video_height);
197 ok(hr==S_OK, "Cannot set destination position returned: %x\n", hr);
199 hr = IBasicVideo_SetDestinationPosition(pbv, 0, 0, video_width, video_height+1);
200 ok(hr==S_OK, "Cannot set destination position returned: %x\n", hr);
201 hr = IBasicVideo_SetDestinationPosition(pbv, 0, 0, video_width+1, video_height);
202 ok(hr==S_OK, "Cannot set destination position returned: %x\n", hr);
204 hr = IBasicVideo_SetDestinationPosition(pbv, video_width/2, video_height/2, video_width/3+1, video_height/3+1);
205 ok(hr==S_OK, "Cannot set destination position returned: %x\n", hr);
207 hr = IBasicVideo_get_DestinationLeft(pbv, &left);
208 ok(hr==S_OK, "Cannot get destination left returned: %x\n", hr);
209 ok(left==video_width/2, "expected %d, got %d\n", video_width/2, left);
210 hr = IBasicVideo_get_DestinationTop(pbv, &top);
211 ok(hr==S_OK, "Cannot get destination top returned: %x\n", hr);
212 ok(top==video_height/2, "expected %d, got %d\n", video_height/2, top);
213 hr = IBasicVideo_get_DestinationWidth(pbv, &width);
214 ok(hr==S_OK, "Cannot get destination width returned: %x\n", hr);
215 ok(width==video_width/3+1, "expected %d, got %d\n", video_width/3+1, width);
216 hr = IBasicVideo_get_DestinationHeight(pbv, &height);
217 ok(hr==S_OK, "Cannot get destination height returned: %x\n", hr);
218 ok(height==video_height/3+1, "expected %d, got %d\n", video_height/3+1, height);
220 hr = IBasicVideo_put_DestinationLeft(pbv, video_width/3);
221 ok(hr==S_OK, "Cannot put destination left returned: %x\n", hr);
222 hr = IBasicVideo_GetDestinationPosition(pbv, &left, &top, &width, &height);
223 ok(hr == S_OK, "Cannot get source position returned: %x\n", hr);
224 ok(left == video_width/3, "expected %d, got %d\n", video_width/3, left);
225 ok(width == video_width/3+1, "expected %d, got %d\n", video_width/3+1, width);
227 hr = IBasicVideo_put_DestinationTop(pbv, video_height/3);
228 ok(hr==S_OK, "Cannot put destination top returned: %x\n", hr);
229 hr = IBasicVideo_GetDestinationPosition(pbv, &left, &top, &width, &height);
230 ok(hr == S_OK, "Cannot get source position returned: %x\n", hr);
231 ok(top == video_height/3, "expected %d, got %d\n", video_height/3, top);
232 ok(height == video_height/3+1, "expected %d, got %d\n", video_height/3+1, height);
234 hr = IBasicVideo_put_DestinationWidth(pbv, video_width/4+1);
235 ok(hr==S_OK, "Cannot put destination width returned: %x\n", hr);
236 hr = IBasicVideo_GetDestinationPosition(pbv, &left, &top, &width, &height);
237 ok(hr == S_OK, "Cannot get source position returned: %x\n", hr);
238 ok(left == video_width/3, "expected %d, got %d\n", video_width/3, left);
239 ok(width == video_width/4+1, "expected %d, got %d\n", video_width/4+1, width);
241 hr = IBasicVideo_put_DestinationHeight(pbv, video_height/4+1);
242 ok(hr==S_OK, "Cannot put destination height returned: %x\n", hr);
243 hr = IBasicVideo_GetDestinationPosition(pbv, &left, &top, &width, &height);
244 ok(hr == S_OK, "Cannot get source position returned: %x\n", hr);
245 ok(top == video_height/3, "expected %d, got %d\n", video_height/3, top);
246 ok(height == video_height/4+1, "expected %d, got %d\n", video_height/4+1, height);
248 /* reset source rectangle */
249 hr = IBasicVideo_SetDefaultSourcePosition(pbv);
250 ok(hr==S_OK, "IBasicVideo_SetDefaultSourcePosition returned: %x\n", hr);
252 /* reset destination position */
253 hr = IBasicVideo_SetDestinationPosition(pbv, 0, 0, video_width, video_height);
254 ok(hr==S_OK, "Cannot set destination position returned: %x\n", hr);
256 IBasicVideo_Release(pbv);
259 static void rungraph(void)
261 HRESULT hr;
262 IMediaControl* pmc;
263 IMediaEvent* pme;
264 IMediaFilter* pmf;
265 HANDLE hEvent;
267 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (LPVOID*)&pmc);
268 ok(hr==S_OK, "Cannot get IMediaControl interface returned: %x\n", hr);
270 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (LPVOID*)&pmf);
271 ok(hr==S_OK, "Cannot get IMediaFilter interface returned: %x\n", hr);
273 IMediaControl_Stop(pmc);
275 IMediaFilter_SetSyncSource(pmf, NULL);
277 IMediaFilter_Release(pmf);
279 test_basic_video();
281 hr = IMediaControl_Run(pmc);
282 ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr);
284 Sleep(10);
285 /* Crash fun */
286 trace("run -> stop\n");
287 hr = IMediaControl_Stop(pmc);
288 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
290 IGraphBuilder_SetDefaultSyncSource(pgraph);
292 Sleep(10);
293 trace("stop -> pause\n");
294 hr = IMediaControl_Pause(pmc);
295 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
297 Sleep(10);
298 trace("pause -> run\n");
299 hr = IMediaControl_Run(pmc);
300 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
302 Sleep(10);
303 trace("run -> pause\n");
304 hr = IMediaControl_Pause(pmc);
305 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
307 Sleep(10);
308 trace("pause -> stop\n");
309 hr = IMediaControl_Stop(pmc);
310 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
312 Sleep(10);
313 trace("pause -> run\n");
314 hr = IMediaControl_Run(pmc);
315 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
317 trace("run -> stop\n");
318 hr = IMediaControl_Stop(pmc);
319 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
321 trace("stop -> run\n");
322 hr = IMediaControl_Run(pmc);
323 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
325 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaEvent, (LPVOID*)&pme);
326 ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr);
328 hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent);
329 ok(hr==S_OK, "Cannot get event handle returned: %x\n", hr);
331 /* WaitForSingleObject(hEvent, INFINITE); */
332 Sleep(20000);
334 hr = IMediaEvent_Release(pme);
335 ok(hr==2, "Releasing mediaevent returned: %x\n", hr);
337 hr = IMediaControl_Stop(pmc);
338 ok(hr==S_OK, "Cannot stop the graph returned: %x\n", hr);
340 hr = IMediaControl_Release(pmc);
341 ok(hr==1, "Releasing mediacontrol returned: %x\n", hr);
344 static void releasefiltergraph(void)
346 HRESULT hr;
348 hr = IGraphBuilder_Release(pgraph);
349 ok(hr==0, "Releasing filtergraph returned: %x\n", hr);
352 static void test_render_run(const WCHAR *file)
354 HANDLE h;
355 HRESULT hr;
357 h = CreateFileW(file, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
358 if (h == INVALID_HANDLE_VALUE) {
359 skip("Could not read test file %s, skipping test\n", wine_dbgstr_w(file));
360 return;
362 CloseHandle(h);
364 if (!createfiltergraph())
365 return;
367 hr = IGraphBuilder_RenderFile(pgraph, file, NULL);
368 ok(hr == S_OK, "RenderFile returned: %x\n", hr);
369 rungraph();
371 releasefiltergraph();
373 /* check reference leaks */
374 h = CreateFileW(file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
375 ok(h != INVALID_HANDLE_VALUE, "CreateFile failed: err=%d\n", GetLastError());
376 CloseHandle(h);
379 static DWORD WINAPI call_RenderFile_multithread(LPVOID lParam)
381 IFilterGraph2 *filter_graph = lParam;
382 HRESULT hr;
383 WCHAR mp3file[] = {'t','e','s','t','.','m','p','3',0};
384 HANDLE handle;
386 handle = CreateFileW(mp3file, 0, 0, NULL, CREATE_ALWAYS, 0, NULL);
387 if (handle == INVALID_HANDLE_VALUE)
389 skip("Could not read test file %s, skipping test\n", wine_dbgstr_w(mp3file));
390 return 1;
392 CloseHandle(handle);
394 hr = IFilterGraph2_RenderFile(filter_graph, mp3file, NULL);
395 todo_wine ok(hr == VFW_E_CANNOT_RENDER || /* xp or older + DirectX 9 */
396 hr == VFW_E_NO_TRANSPORT || /* win7 or newer */
397 broken(hr == CLASS_E_CLASSNOTAVAILABLE), /* xp or older + DirectX 8 or older */
398 "Expected 0x%08x or 0x%08x, returned 0x%08x\n", VFW_E_CANNOT_RENDER, VFW_E_NO_TRANSPORT, hr);
400 DeleteFileW(mp3file);
401 return 0;
404 static void test_render_with_multithread(void)
406 HRESULT hr;
407 HMODULE hmod;
408 static HRESULT (WINAPI *pDllGetClassObject)(REFCLSID rclsid, REFIID riid, void **out);
409 IClassFactory *classfactory = NULL;
410 static IGraphBuilder *graph_builder;
411 static IFilterGraph2 *filter_graph;
412 HANDLE thread;
414 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
416 hmod = LoadLibraryA("quartz.dll");
417 if (!hmod)
419 skip("Fail to load quartz.dll.\n");
420 return;
423 pDllGetClassObject = (void*)GetProcAddress(hmod, "DllGetClassObject");
424 if (!pDllGetClassObject)
426 skip("Fail to get DllGetClassObject.\n");
427 return;
430 hr = pDllGetClassObject(&CLSID_FilterGraph, &IID_IClassFactory, (void **)&classfactory);
431 ok(hr == S_OK, "DllGetClassObject failed 0x%08x\n", hr);
432 if (FAILED(hr))
434 skip("Can't create IClassFactory 0x%08x.\n", hr);
435 return;
438 hr = IClassFactory_CreateInstance(classfactory, NULL, &IID_IUnknown, (LPVOID*)&graph_builder);
439 ok(hr == S_OK, "IClassFactory_CreateInstance failed 0x%08x\n", hr);
441 hr = IGraphBuilder_QueryInterface(graph_builder, &IID_IFilterGraph2, (void**)&filter_graph);
442 ok(hr == S_OK, "IGraphBuilder_QueryInterface failed 0x%08x\n", hr);
444 thread = CreateThread(NULL, 0, call_RenderFile_multithread, filter_graph, 0, NULL);
446 WaitForSingleObject(thread, 1000);
447 IFilterGraph2_Release(filter_graph);
448 IGraphBuilder_Release(graph_builder);
449 IClassFactory_Release(classfactory);
450 CoUninitialize();
451 return;
454 static void test_graph_builder(void)
456 HRESULT hr;
457 IBaseFilter *pF = NULL;
458 IBaseFilter *pF2 = NULL;
459 IPin *pIn = NULL;
460 IEnumPins *pEnum = NULL;
461 PIN_DIRECTION dir;
462 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
463 static const WCHAR fooBarW[] = {'f','o','o','B','a','r',0};
465 if (!createfiltergraph())
466 return;
468 /* create video filter */
469 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
470 &IID_IBaseFilter, (LPVOID*)&pF);
471 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
472 ok(pF != NULL, "pF is NULL\n");
474 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
475 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned %x\n", hr);
477 /* add the two filters to the graph */
478 hr = IGraphBuilder_AddFilter(pgraph, pF, testFilterW);
479 ok(hr == S_OK, "failed to add pF to the graph: %x\n", hr);
481 /* find the pins */
482 hr = IBaseFilter_EnumPins(pF, &pEnum);
483 ok(hr == S_OK, "IBaseFilter_EnumPins failed for pF: %x\n", hr);
484 ok(pEnum != NULL, "pEnum is NULL\n");
485 hr = IEnumPins_Next(pEnum, 1, &pIn, NULL);
486 ok(hr == S_OK, "IEnumPins_Next failed for pF: %x\n", hr);
487 ok(pIn != NULL, "pIn is NULL\n");
488 hr = IPin_QueryDirection(pIn, &dir);
489 ok(hr == S_OK, "IPin_QueryDirection failed: %x\n", hr);
490 ok(dir == PINDIR_INPUT, "pin has wrong direction\n");
492 hr = IGraphBuilder_FindFilterByName(pgraph, fooBarW, &pF2);
493 ok(hr == VFW_E_NOT_FOUND, "IGraphBuilder_FindFilterByName returned %x\n", hr);
494 ok(pF2 == NULL, "IGraphBuilder_FindFilterByName returned %p\n", pF2);
495 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, &pF2);
496 ok(hr == S_OK, "IGraphBuilder_FindFilterByName returned %x\n", hr);
497 ok(pF2 != NULL, "IGraphBuilder_FindFilterByName returned NULL\n");
498 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, NULL);
499 ok(hr == E_POINTER, "IGraphBuilder_FindFilterByName returned %x\n", hr);
501 hr = IGraphBuilder_Connect(pgraph, NULL, pIn);
502 ok(hr == E_POINTER, "IGraphBuilder_Connect returned %x\n", hr);
504 hr = IGraphBuilder_Connect(pgraph, pIn, NULL);
505 ok(hr == E_POINTER, "IGraphBuilder_Connect returned %x\n", hr);
507 hr = IGraphBuilder_Connect(pgraph, pIn, pIn);
508 ok(hr == VFW_E_CANNOT_CONNECT, "IGraphBuilder_Connect returned %x\n", hr);
510 if (pIn) IPin_Release(pIn);
511 if (pEnum) IEnumPins_Release(pEnum);
512 if (pF) IBaseFilter_Release(pF);
513 if (pF2) IBaseFilter_Release(pF2);
515 releasefiltergraph();
518 static void test_graph_builder_addfilter(void)
520 HRESULT hr;
521 IBaseFilter *pF = NULL;
522 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
524 if (!createfiltergraph())
525 return;
527 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
528 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr);
530 /* create video filter */
531 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
532 &IID_IBaseFilter, (LPVOID*)&pF);
533 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
534 ok(pF != NULL, "pF is NULL\n");
535 if (!pF) {
536 skip("failed to created filter, skipping\n");
537 return;
540 hr = IGraphBuilder_AddFilter(pgraph, pF, NULL);
541 ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr);
542 IBaseFilter_Release(pF);
545 static void test_mediacontrol(void)
547 HRESULT hr;
548 LONGLONG pos = 0xdeadbeef;
549 GUID format = GUID_NULL;
550 IMediaSeeking *seeking = NULL;
551 IMediaFilter *filter = NULL;
552 IMediaControl *control = NULL;
554 IGraphBuilder_SetDefaultSyncSource(pgraph);
555 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking);
556 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
557 if (FAILED(hr))
558 return;
560 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
561 ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
562 if (FAILED(hr))
564 IMediaSeeking_Release(seeking);
565 return;
568 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
569 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
570 if (FAILED(hr))
572 IMediaSeeking_Release(seeking);
573 IMediaFilter_Release(filter);
574 return;
577 format = GUID_NULL;
578 hr = IMediaSeeking_GetTimeFormat(seeking, &format);
579 ok(hr == S_OK, "GetTimeFormat failed: %08x\n", hr);
580 ok(IsEqualGUID(&format, &TIME_FORMAT_MEDIA_TIME), "GetTimeFormat: unexpected format %s\n", wine_dbgstr_guid(&format));
582 pos = 0xdeadbeef;
583 hr = IMediaSeeking_ConvertTimeFormat(seeking, &pos, NULL, 0x123456789a, NULL);
584 ok(hr == S_OK, "ConvertTimeFormat failed: %08x\n", hr);
585 ok(pos == 0x123456789a, "ConvertTimeFormat: expected 123456789a, got (%s)\n", wine_dbgstr_longlong(pos));
587 pos = 0xdeadbeef;
588 hr = IMediaSeeking_ConvertTimeFormat(seeking, &pos, &TIME_FORMAT_MEDIA_TIME, 0x123456789a, NULL);
589 ok(hr == S_OK, "ConvertTimeFormat failed: %08x\n", hr);
590 ok(pos == 0x123456789a, "ConvertTimeFormat: expected 123456789a, got (%s)\n", wine_dbgstr_longlong(pos));
592 pos = 0xdeadbeef;
593 hr = IMediaSeeking_ConvertTimeFormat(seeking, &pos, NULL, 0x123456789a, &TIME_FORMAT_MEDIA_TIME);
594 ok(hr == S_OK, "ConvertTimeFormat failed: %08x\n", hr);
595 ok(pos == 0x123456789a, "ConvertTimeFormat: expected 123456789a, got (%s)\n", wine_dbgstr_longlong(pos));
597 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
598 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
599 ok(pos == 0, "Position != 0 (%s)\n", wine_dbgstr_longlong(pos));
601 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_ReturnTime, NULL, AM_SEEKING_NoPositioning);
602 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
603 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_NoPositioning, NULL, AM_SEEKING_ReturnTime);
604 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
606 IMediaFilter_SetSyncSource(filter, NULL);
607 pos = 0xdeadbeef;
608 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
609 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
610 ok(pos == 0, "Position != 0 (%s)\n", wine_dbgstr_longlong(pos));
612 hr = IMediaControl_GetState(control, 1000, NULL);
613 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
615 IMediaControl_Release(control);
616 IMediaSeeking_Release(seeking);
617 IMediaFilter_Release(filter);
618 releasefiltergraph();
621 static void test_filter_graph2(void)
623 HRESULT hr;
624 IFilterGraph2 *pF = NULL;
626 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
627 &IID_IFilterGraph2, (LPVOID*)&pF);
628 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
629 ok(pF != NULL, "pF is NULL\n");
631 hr = IFilterGraph2_Release(pF);
632 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
635 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
636 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
638 if (pMediaType->pbFormat)
640 CoTaskMemFree(pMediaType->pbFormat);
641 pMediaType->pbFormat = NULL;
643 if (pMediaType->pUnk)
645 IUnknown_Release(pMediaType->pUnk);
646 pMediaType->pUnk = NULL;
650 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
652 *pDest = *pSrc;
653 if (!pSrc->pbFormat) return S_OK;
654 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
655 return E_OUTOFMEMORY;
656 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
657 if (pDest->pUnk)
658 IUnknown_AddRef(pDest->pUnk);
659 return S_OK;
662 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
664 AM_MEDIA_TYPE * pDest;
666 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
667 if (!pDest)
668 return NULL;
670 if (FAILED(CopyMediaType(pDest, pSrc)))
672 CoTaskMemFree(pDest);
673 return NULL;
676 return pDest;
679 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
681 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
682 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
685 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
687 FreeMediaType(pMediaType);
688 CoTaskMemFree(pMediaType);
691 typedef struct IEnumMediaTypesImpl
693 IEnumMediaTypes IEnumMediaTypes_iface;
694 LONG refCount;
695 AM_MEDIA_TYPE *pMediaTypes;
696 ULONG cMediaTypes;
697 ULONG uIndex;
698 } IEnumMediaTypesImpl;
700 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
702 static inline IEnumMediaTypesImpl *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
704 return CONTAINING_RECORD(iface, IEnumMediaTypesImpl, IEnumMediaTypes_iface);
707 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
709 ULONG i;
710 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
712 if (!pEnumMediaTypes)
714 *ppEnum = NULL;
715 return E_OUTOFMEMORY;
717 pEnumMediaTypes->IEnumMediaTypes_iface.lpVtbl = &IEnumMediaTypesImpl_Vtbl;
718 pEnumMediaTypes->refCount = 1;
719 pEnumMediaTypes->uIndex = 0;
720 pEnumMediaTypes->cMediaTypes = cMediaTypes;
721 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
722 for (i = 0; i < cMediaTypes; i++)
723 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
725 while (i--)
726 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
727 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
728 return E_OUTOFMEMORY;
730 *ppEnum = &pEnumMediaTypes->IEnumMediaTypes_iface;
731 return S_OK;
734 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
736 *ppv = NULL;
738 if (IsEqualIID(riid, &IID_IUnknown))
739 *ppv = iface;
740 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
741 *ppv = iface;
743 if (*ppv)
745 IUnknown_AddRef((IUnknown *)(*ppv));
746 return S_OK;
749 return E_NOINTERFACE;
752 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
754 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
755 ULONG refCount = InterlockedIncrement(&This->refCount);
757 return refCount;
760 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
762 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
763 ULONG refCount = InterlockedDecrement(&This->refCount);
765 if (!refCount)
767 int i;
768 for (i = 0; i < This->cMediaTypes; i++)
769 FreeMediaType(&This->pMediaTypes[i]);
770 CoTaskMemFree(This->pMediaTypes);
771 CoTaskMemFree(This);
773 return refCount;
776 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
778 ULONG cFetched;
779 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
781 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
783 if (cFetched > 0)
785 ULONG i;
786 for (i = 0; i < cFetched; i++)
787 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
789 while (i--)
790 DeleteMediaType(ppMediaTypes[i]);
791 *pcFetched = 0;
792 return E_OUTOFMEMORY;
796 if ((cMediaTypes != 1) || pcFetched)
797 *pcFetched = cFetched;
799 This->uIndex += cFetched;
801 if (cFetched != cMediaTypes)
802 return S_FALSE;
803 return S_OK;
806 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
808 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
810 if (This->uIndex + cMediaTypes < This->cMediaTypes)
812 This->uIndex += cMediaTypes;
813 return S_OK;
815 return S_FALSE;
818 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
820 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
822 This->uIndex = 0;
823 return S_OK;
826 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
828 HRESULT hr;
829 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
831 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
832 if (FAILED(hr))
833 return hr;
834 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
837 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
839 IEnumMediaTypesImpl_QueryInterface,
840 IEnumMediaTypesImpl_AddRef,
841 IEnumMediaTypesImpl_Release,
842 IEnumMediaTypesImpl_Next,
843 IEnumMediaTypesImpl_Skip,
844 IEnumMediaTypesImpl_Reset,
845 IEnumMediaTypesImpl_Clone
848 /* Implementation of a very stripped down pin for the test filter. Just enough
849 functionality for connecting and Render() to work. */
851 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
853 lstrcpyW(pDest->achName, pSrc->achName);
854 pDest->dir = pSrc->dir;
855 pDest->pFilter = pSrc->pFilter;
858 typedef struct ITestPinImpl
860 IPin IPin_iface;
861 LONG refCount;
862 LPCRITICAL_SECTION pCritSec;
863 PIN_INFO pinInfo;
864 IPin * pConnectedTo;
865 AM_MEDIA_TYPE mtCurrent;
866 LPVOID pUserData;
867 } ITestPinImpl;
869 static inline ITestPinImpl *impl_from_IPin(IPin *iface)
871 return CONTAINING_RECORD(iface, ITestPinImpl, IPin_iface);
874 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
876 *ppv = NULL;
878 if (IsEqualIID(riid, &IID_IUnknown))
879 *ppv = iface;
880 else if (IsEqualIID(riid, &IID_IPin))
881 *ppv = iface;
883 if (*ppv)
885 IUnknown_AddRef((IUnknown *)(*ppv));
886 return S_OK;
889 return E_NOINTERFACE;
892 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
894 ITestPinImpl *This = impl_from_IPin(iface);
895 ULONG refCount = InterlockedIncrement(&This->refCount);
896 return refCount;
899 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
901 ITestPinImpl *This = impl_from_IPin(iface);
902 ULONG refCount = InterlockedDecrement(&This->refCount);
904 if (!refCount)
906 FreeMediaType(&This->mtCurrent);
907 CoTaskMemFree(This);
908 return 0;
910 else
911 return refCount;
914 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
916 return E_UNEXPECTED;
919 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
921 ITestPinImpl *This = impl_from_IPin(iface);
922 PIN_DIRECTION pindirReceive;
923 HRESULT hr = S_OK;
925 EnterCriticalSection(This->pCritSec);
927 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
928 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
929 hr = VFW_E_TYPE_NOT_ACCEPTED;
931 if (This->pConnectedTo)
932 hr = VFW_E_ALREADY_CONNECTED;
934 if (SUCCEEDED(hr))
936 IPin_QueryDirection(pReceivePin, &pindirReceive);
938 if (pindirReceive != PINDIR_OUTPUT)
940 hr = VFW_E_INVALID_DIRECTION;
944 if (SUCCEEDED(hr))
946 CopyMediaType(&This->mtCurrent, pmt);
947 This->pConnectedTo = pReceivePin;
948 IPin_AddRef(pReceivePin);
951 LeaveCriticalSection(This->pCritSec);
953 return hr;
956 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
958 HRESULT hr;
959 ITestPinImpl *This = impl_from_IPin(iface);
961 EnterCriticalSection(This->pCritSec);
963 if (This->pConnectedTo)
965 IPin_Release(This->pConnectedTo);
966 This->pConnectedTo = NULL;
967 hr = S_OK;
969 else
970 hr = S_FALSE;
972 LeaveCriticalSection(This->pCritSec);
974 return hr;
977 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
979 HRESULT hr;
980 ITestPinImpl *This = impl_from_IPin(iface);
982 EnterCriticalSection(This->pCritSec);
984 if (This->pConnectedTo)
986 *ppPin = This->pConnectedTo;
987 IPin_AddRef(*ppPin);
988 hr = S_OK;
990 else
992 hr = VFW_E_NOT_CONNECTED;
993 *ppPin = NULL;
996 LeaveCriticalSection(This->pCritSec);
998 return hr;
1001 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
1003 HRESULT hr;
1004 ITestPinImpl *This = impl_from_IPin(iface);
1006 EnterCriticalSection(This->pCritSec);
1008 if (This->pConnectedTo)
1010 CopyMediaType(pmt, &This->mtCurrent);
1011 hr = S_OK;
1013 else
1015 ZeroMemory(pmt, sizeof(*pmt));
1016 hr = VFW_E_NOT_CONNECTED;
1019 LeaveCriticalSection(This->pCritSec);
1021 return hr;
1024 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
1026 ITestPinImpl *This = impl_from_IPin(iface);
1028 Copy_PinInfo(pInfo, &This->pinInfo);
1029 IBaseFilter_AddRef(pInfo->pFilter);
1031 return S_OK;
1034 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
1036 ITestPinImpl *This = impl_from_IPin(iface);
1038 *pPinDir = This->pinInfo.dir;
1040 return S_OK;
1043 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
1045 return E_NOTIMPL;
1048 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
1050 ITestPinImpl *This = impl_from_IPin(iface);
1052 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
1053 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
1054 return S_OK;
1055 else
1056 return VFW_E_TYPE_NOT_ACCEPTED;
1059 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
1061 ITestPinImpl *This = impl_from_IPin(iface);
1063 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
1066 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
1068 return E_NOTIMPL;
1071 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
1073 return E_NOTIMPL;
1076 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
1078 return E_NOTIMPL;
1081 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1083 return E_NOTIMPL;
1086 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
1088 return E_NOTIMPL;
1091 static const IPinVtbl TestFilter_InputPin_Vtbl =
1093 TestFilter_Pin_QueryInterface,
1094 TestFilter_Pin_AddRef,
1095 TestFilter_Pin_Release,
1096 TestFilter_InputPin_Connect,
1097 TestFilter_InputPin_ReceiveConnection,
1098 TestFilter_Pin_Disconnect,
1099 TestFilter_Pin_ConnectedTo,
1100 TestFilter_Pin_ConnectionMediaType,
1101 TestFilter_Pin_QueryPinInfo,
1102 TestFilter_Pin_QueryDirection,
1103 TestFilter_Pin_QueryId,
1104 TestFilter_Pin_QueryAccept,
1105 TestFilter_Pin_EnumMediaTypes,
1106 TestFilter_Pin_QueryInternalConnections,
1107 TestFilter_Pin_EndOfStream,
1108 TestFilter_Pin_BeginFlush,
1109 TestFilter_Pin_EndFlush,
1110 TestFilter_Pin_NewSegment
1113 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
1115 return E_UNEXPECTED;
1118 /* Private helper function */
1119 static HRESULT TestFilter_OutputPin_ConnectSpecific(ITestPinImpl * This, IPin * pReceivePin,
1120 const AM_MEDIA_TYPE * pmt)
1122 HRESULT hr;
1124 This->pConnectedTo = pReceivePin;
1125 IPin_AddRef(pReceivePin);
1127 hr = IPin_ReceiveConnection(pReceivePin, &This->IPin_iface, pmt);
1129 if (FAILED(hr))
1131 IPin_Release(This->pConnectedTo);
1132 This->pConnectedTo = NULL;
1135 return hr;
1138 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
1140 ITestPinImpl *This = impl_from_IPin(iface);
1141 HRESULT hr;
1143 EnterCriticalSection(This->pCritSec);
1145 /* if we have been a specific type to connect with, then we can either connect
1146 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
1147 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
1148 hr = TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, pmt);
1149 else
1151 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
1152 (TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, &This->mtCurrent) == S_OK))
1153 hr = S_OK;
1154 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
1155 } /* if negotiate media type */
1156 } /* if succeeded */
1157 LeaveCriticalSection(This->pCritSec);
1159 return hr;
1162 static const IPinVtbl TestFilter_OutputPin_Vtbl =
1164 TestFilter_Pin_QueryInterface,
1165 TestFilter_Pin_AddRef,
1166 TestFilter_Pin_Release,
1167 TestFilter_OutputPin_Connect,
1168 TestFilter_OutputPin_ReceiveConnection,
1169 TestFilter_Pin_Disconnect,
1170 TestFilter_Pin_ConnectedTo,
1171 TestFilter_Pin_ConnectionMediaType,
1172 TestFilter_Pin_QueryPinInfo,
1173 TestFilter_Pin_QueryDirection,
1174 TestFilter_Pin_QueryId,
1175 TestFilter_Pin_QueryAccept,
1176 TestFilter_Pin_EnumMediaTypes,
1177 TestFilter_Pin_QueryInternalConnections,
1178 TestFilter_Pin_EndOfStream,
1179 TestFilter_Pin_BeginFlush,
1180 TestFilter_Pin_EndFlush,
1181 TestFilter_Pin_NewSegment
1184 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
1185 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
1187 ITestPinImpl * pPinImpl;
1189 *ppPin = NULL;
1191 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
1193 if (!pPinImpl)
1194 return E_OUTOFMEMORY;
1196 pPinImpl->refCount = 1;
1197 pPinImpl->pConnectedTo = NULL;
1198 pPinImpl->pCritSec = pCritSec;
1199 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
1200 pPinImpl->mtCurrent = *pinmt;
1202 pPinImpl->IPin_iface.lpVtbl = Pin_Vtbl;
1204 *ppPin = &pPinImpl->IPin_iface;
1205 return S_OK;
1208 /* IEnumPins implementation */
1210 typedef HRESULT (* FNOBTAINPIN)(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick);
1212 typedef struct IEnumPinsImpl
1214 IEnumPins IEnumPins_iface;
1215 LONG refCount;
1216 ULONG uIndex;
1217 TestFilterImpl *base;
1218 FNOBTAINPIN receive_pin;
1219 DWORD synctime;
1220 } IEnumPinsImpl;
1222 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
1224 static inline IEnumPinsImpl *impl_from_IEnumPins(IEnumPins *iface)
1226 return CONTAINING_RECORD(iface, IEnumPinsImpl, IEnumPins_iface);
1229 static HRESULT createenumpins(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, TestFilterImpl *base)
1231 IEnumPinsImpl * pEnumPins;
1233 if (!ppEnum)
1234 return E_POINTER;
1236 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
1237 if (!pEnumPins)
1239 *ppEnum = NULL;
1240 return E_OUTOFMEMORY;
1242 pEnumPins->IEnumPins_iface.lpVtbl = &IEnumPinsImpl_Vtbl;
1243 pEnumPins->refCount = 1;
1244 pEnumPins->uIndex = 0;
1245 pEnumPins->receive_pin = receive_pin;
1246 pEnumPins->base = base;
1247 IBaseFilter_AddRef(&base->IBaseFilter_iface);
1248 *ppEnum = &pEnumPins->IEnumPins_iface;
1250 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
1252 return S_OK;
1255 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
1257 *ppv = NULL;
1259 if (IsEqualIID(riid, &IID_IUnknown))
1260 *ppv = iface;
1261 else if (IsEqualIID(riid, &IID_IEnumPins))
1262 *ppv = iface;
1264 if (*ppv)
1266 IUnknown_AddRef((IUnknown *)(*ppv));
1267 return S_OK;
1270 return E_NOINTERFACE;
1273 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
1275 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1276 ULONG refCount = InterlockedIncrement(&This->refCount);
1278 return refCount;
1281 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
1283 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1284 ULONG refCount = InterlockedDecrement(&This->refCount);
1286 if (!refCount)
1288 IBaseFilter_Release(&This->base->IBaseFilter_iface);
1289 CoTaskMemFree(This);
1290 return 0;
1292 else
1293 return refCount;
1296 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
1298 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1299 DWORD synctime = This->synctime;
1300 HRESULT hr = S_OK;
1301 ULONG i = 0;
1303 if (!ppPins)
1304 return E_POINTER;
1306 if (cPins > 1 && !pcFetched)
1307 return E_INVALIDARG;
1309 if (pcFetched)
1310 *pcFetched = 0;
1312 while (i < cPins && hr == S_OK)
1314 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
1316 if (hr == S_OK)
1317 ++i;
1319 if (synctime != This->synctime)
1320 break;
1323 if (!i && synctime != This->synctime)
1324 return VFW_E_ENUM_OUT_OF_SYNC;
1326 if (pcFetched)
1327 *pcFetched = i;
1328 This->uIndex += i;
1330 if (i < cPins)
1331 return S_FALSE;
1332 return S_OK;
1335 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
1337 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1338 DWORD synctime = This->synctime;
1339 HRESULT hr;
1340 IPin *pin = NULL;
1342 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
1343 if (pin)
1344 IPin_Release(pin);
1346 if (synctime != This->synctime)
1347 return VFW_E_ENUM_OUT_OF_SYNC;
1349 if (hr == S_OK)
1350 This->uIndex += cPins;
1352 return hr;
1355 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1357 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1359 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1361 This->uIndex = 0;
1362 return S_OK;
1365 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1367 HRESULT hr;
1368 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1370 hr = createenumpins(ppEnum, This->receive_pin, This->base);
1371 if (FAILED(hr))
1372 return hr;
1373 return IEnumPins_Skip(*ppEnum, This->uIndex);
1376 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1378 IEnumPinsImpl_QueryInterface,
1379 IEnumPinsImpl_AddRef,
1380 IEnumPinsImpl_Release,
1381 IEnumPinsImpl_Next,
1382 IEnumPinsImpl_Skip,
1383 IEnumPinsImpl_Reset,
1384 IEnumPinsImpl_Clone
1387 /* Test filter implementation - a filter that has few predefined pins with single media type
1388 * that accept only this single media type. Enough for Render(). */
1390 typedef struct TestFilterPinData
1392 PIN_DIRECTION pinDir;
1393 const GUID *mediasubtype;
1394 } TestFilterPinData;
1396 static const IBaseFilterVtbl TestFilter_Vtbl;
1398 static inline TestFilterImpl *impl_from_IBaseFilter(IBaseFilter *iface)
1400 return CONTAINING_RECORD(iface, TestFilterImpl, IBaseFilter_iface);
1403 static HRESULT createtestfilter(const CLSID* pClsid, const TestFilterPinData *pinData,
1404 TestFilterImpl **tf)
1406 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1407 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1408 HRESULT hr;
1409 PIN_INFO pinInfo;
1410 TestFilterImpl* pTestFilter = NULL;
1411 UINT nPins, i;
1412 AM_MEDIA_TYPE mt;
1414 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1415 if (!pTestFilter) return E_OUTOFMEMORY;
1417 pTestFilter->clsid = *pClsid;
1418 pTestFilter->IBaseFilter_iface.lpVtbl = &TestFilter_Vtbl;
1419 pTestFilter->refCount = 1;
1420 InitializeCriticalSection(&pTestFilter->csFilter);
1421 pTestFilter->state = State_Stopped;
1423 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1425 nPins = 0;
1426 while(pinData[nPins].mediasubtype) ++nPins;
1428 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1429 if (!pTestFilter->ppPins)
1431 hr = E_OUTOFMEMORY;
1432 goto error;
1434 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1436 for (i = 0; i < nPins; i++)
1438 ZeroMemory(&mt, sizeof(mt));
1439 mt.majortype = MEDIATYPE_Video;
1440 mt.formattype = FORMAT_None;
1441 mt.subtype = *pinData[i].mediasubtype;
1443 pinInfo.dir = pinData[i].pinDir;
1444 pinInfo.pFilter = &pTestFilter->IBaseFilter_iface;
1445 if (pinInfo.dir == PINDIR_INPUT)
1447 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1448 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1449 &pTestFilter->ppPins[i]);
1452 else
1454 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1455 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1456 &pTestFilter->ppPins[i]);
1458 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1461 pTestFilter->nPins = nPins;
1462 *tf = pTestFilter;
1463 return S_OK;
1465 error:
1467 if (pTestFilter->ppPins)
1469 for (i = 0; i < nPins; i++)
1471 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1474 CoTaskMemFree(pTestFilter->ppPins);
1475 DeleteCriticalSection(&pTestFilter->csFilter);
1476 CoTaskMemFree(pTestFilter);
1478 return hr;
1481 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1483 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1485 *ppv = NULL;
1487 if (IsEqualIID(riid, &IID_IUnknown))
1488 *ppv = This;
1489 else if (IsEqualIID(riid, &IID_IPersist))
1490 *ppv = This;
1491 else if (IsEqualIID(riid, &IID_IMediaFilter))
1492 *ppv = This;
1493 else if (IsEqualIID(riid, &IID_IBaseFilter))
1494 *ppv = This;
1496 if (*ppv)
1498 IUnknown_AddRef((IUnknown *)(*ppv));
1499 return S_OK;
1502 return E_NOINTERFACE;
1505 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1507 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1508 ULONG refCount = InterlockedIncrement(&This->refCount);
1510 return refCount;
1513 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1515 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1516 ULONG refCount = InterlockedDecrement(&This->refCount);
1518 if (!refCount)
1520 ULONG i;
1522 for (i = 0; i < This->nPins; i++)
1524 IPin *pConnectedTo;
1526 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1528 IPin_Disconnect(pConnectedTo);
1529 IPin_Release(pConnectedTo);
1531 IPin_Disconnect(This->ppPins[i]);
1533 IPin_Release(This->ppPins[i]);
1536 CoTaskMemFree(This->ppPins);
1538 DeleteCriticalSection(&This->csFilter);
1540 CoTaskMemFree(This);
1542 return 0;
1544 else
1545 return refCount;
1547 /** IPersist methods **/
1549 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1551 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1553 *pClsid = This->clsid;
1555 return S_OK;
1558 /** IMediaFilter methods **/
1560 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1562 return E_NOTIMPL;
1565 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1567 return E_NOTIMPL;
1570 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1572 return E_NOTIMPL;
1575 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1577 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1579 EnterCriticalSection(&This->csFilter);
1581 *pState = This->state;
1583 LeaveCriticalSection(&This->csFilter);
1585 return S_OK;
1588 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1590 return E_NOTIMPL;
1593 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1595 return E_NOTIMPL;
1598 /** IBaseFilter implementation **/
1600 static HRESULT getpin_callback(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick)
1602 /* Our pins are static, not changing so setting static tick count is ok */
1603 *lastsynctick = 0;
1605 if (pos >= tf->nPins)
1606 return S_FALSE;
1608 *pin = tf->ppPins[pos];
1609 IPin_AddRef(*pin);
1610 return S_OK;
1613 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1615 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1617 return createenumpins(ppEnum, getpin_callback, This);
1620 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1622 return E_NOTIMPL;
1625 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1627 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1629 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1630 pInfo->pGraph = This->filterInfo.pGraph;
1632 if (pInfo->pGraph)
1633 IFilterGraph_AddRef(pInfo->pGraph);
1635 return S_OK;
1638 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1640 HRESULT hr = S_OK;
1641 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1643 EnterCriticalSection(&This->csFilter);
1645 if (pName)
1646 lstrcpyW(This->filterInfo.achName, pName);
1647 else
1648 *This->filterInfo.achName = '\0';
1649 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1651 LeaveCriticalSection(&This->csFilter);
1653 return hr;
1656 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1658 return E_NOTIMPL;
1661 static const IBaseFilterVtbl TestFilter_Vtbl =
1663 TestFilter_QueryInterface,
1664 TestFilter_AddRef,
1665 TestFilter_Release,
1666 TestFilter_GetClassID,
1667 TestFilter_Stop,
1668 TestFilter_Pause,
1669 TestFilter_Run,
1670 TestFilter_GetState,
1671 TestFilter_SetSyncSource,
1672 TestFilter_GetSyncSource,
1673 TestFilter_EnumPins,
1674 TestFilter_FindPin,
1675 TestFilter_QueryFilterInfo,
1676 TestFilter_JoinFilterGraph,
1677 TestFilter_QueryVendorInfo
1680 /* IClassFactory implementation */
1682 typedef struct TestClassFactoryImpl
1684 IClassFactory IClassFactory_iface;
1685 const TestFilterPinData *filterPinData;
1686 const CLSID *clsid;
1687 } TestClassFactoryImpl;
1689 static inline TestClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
1691 return CONTAINING_RECORD(iface, TestClassFactoryImpl, IClassFactory_iface);
1694 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1695 LPCLASSFACTORY iface,
1696 REFIID riid,
1697 LPVOID *ppvObj)
1699 if (ppvObj == NULL) return E_POINTER;
1701 if (IsEqualGUID(riid, &IID_IUnknown) ||
1702 IsEqualGUID(riid, &IID_IClassFactory))
1704 *ppvObj = iface;
1705 IClassFactory_AddRef(iface);
1706 return S_OK;
1709 *ppvObj = NULL;
1710 return E_NOINTERFACE;
1713 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1715 return 2; /* non-heap-based object */
1718 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1720 return 1; /* non-heap-based object */
1723 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1724 LPCLASSFACTORY iface,
1725 LPUNKNOWN pUnkOuter,
1726 REFIID riid,
1727 LPVOID *ppvObj)
1729 TestClassFactoryImpl *This = impl_from_IClassFactory(iface);
1730 HRESULT hr;
1731 TestFilterImpl *testfilter;
1733 *ppvObj = NULL;
1735 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1737 hr = createtestfilter(This->clsid, This->filterPinData, &testfilter);
1738 if (SUCCEEDED(hr)) {
1739 hr = IBaseFilter_QueryInterface(&testfilter->IBaseFilter_iface, riid, ppvObj);
1740 IBaseFilter_Release(&testfilter->IBaseFilter_iface);
1742 return hr;
1745 static HRESULT WINAPI Test_IClassFactory_LockServer(
1746 LPCLASSFACTORY iface,
1747 BOOL fLock)
1749 return S_OK;
1752 static IClassFactoryVtbl TestClassFactory_Vtbl =
1754 Test_IClassFactory_QueryInterface,
1755 Test_IClassFactory_AddRef,
1756 Test_IClassFactory_Release,
1757 Test_IClassFactory_CreateInstance,
1758 Test_IClassFactory_LockServer
1761 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1763 IPin *pin = NULL;
1764 PIN_INFO pinInfo;
1765 FILTER_INFO filterInfo;
1766 HRESULT hr;
1768 FilterName[0] = 0;
1770 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1771 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1772 if (FAILED(hr)) return hr;
1774 hr = IPin_QueryPinInfo(pin, &pinInfo);
1775 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1776 IPin_Release(pin);
1777 if (FAILED(hr)) return hr;
1779 SetLastError(0xdeadbeef);
1780 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1781 if (hr == S_OK && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1783 IBaseFilter_Release(pinInfo.pFilter);
1784 return E_NOTIMPL;
1786 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1787 IBaseFilter_Release(pinInfo.pFilter);
1788 if (FAILED(hr)) return hr;
1790 IFilterGraph_Release(filterInfo.pGraph);
1792 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1794 return S_OK;
1797 static void test_render_filter_priority(void)
1799 /* Tests filter choice priorities in Render(). */
1800 DWORD cookie1 = 0, cookie2 = 0, cookie3 = 0;
1801 HRESULT hr;
1802 IFilterGraph2* pgraph2 = NULL;
1803 IFilterMapper2 *pMapper2 = NULL;
1804 TestFilterImpl *ptestfilter = NULL;
1805 TestFilterImpl *ptestfilter2 = NULL;
1806 static const CLSID CLSID_TestFilter2 = {
1807 0x37a4edb0,
1808 0x4d13,
1809 0x11dd,
1810 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1812 static const CLSID CLSID_TestFilter3 = {
1813 0x37a4f2d8,
1814 0x4d13,
1815 0x11dd,
1816 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1818 static const CLSID CLSID_TestFilter4 = {
1819 0x37a4f3b4,
1820 0x4d13,
1821 0x11dd,
1822 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1824 static const GUID mediasubtype1 = {
1825 0x37a4f51c,
1826 0x4d13,
1827 0x11dd,
1828 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1830 static const GUID mediasubtype2 = {
1831 0x37a4f5c6,
1832 0x4d13,
1833 0x11dd,
1834 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1836 static const TestFilterPinData PinData1[] = {
1837 { PINDIR_OUTPUT, &mediasubtype1 },
1838 { 0, 0 }
1840 static const TestFilterPinData PinData2[] = {
1841 { PINDIR_INPUT, &mediasubtype1 },
1842 { 0, 0 }
1844 static const TestFilterPinData PinData3[] = {
1845 { PINDIR_INPUT, &GUID_NULL },
1846 { 0, 0 }
1848 static const TestFilterPinData PinData4[] = {
1849 { PINDIR_INPUT, &mediasubtype1 },
1850 { PINDIR_OUTPUT, &mediasubtype2 },
1851 { 0, 0 }
1853 static const TestFilterPinData PinData5[] = {
1854 { PINDIR_INPUT, &mediasubtype2 },
1855 { 0, 0 }
1857 TestClassFactoryImpl Filter1ClassFactory = {
1858 { &TestClassFactory_Vtbl },
1859 PinData2, &CLSID_TestFilter2
1861 TestClassFactoryImpl Filter2ClassFactory = {
1862 { &TestClassFactory_Vtbl },
1863 PinData4, &CLSID_TestFilter3
1865 TestClassFactoryImpl Filter3ClassFactory = {
1866 { &TestClassFactory_Vtbl },
1867 PinData5, &CLSID_TestFilter4
1869 char ConnectedFilterName1[MAX_FILTER_NAME];
1870 char ConnectedFilterName2[MAX_FILTER_NAME];
1871 REGFILTER2 rgf2;
1872 REGFILTERPINS2 rgPins2[2];
1873 REGPINTYPES rgPinType[2];
1874 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1875 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1876 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1877 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1878 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1879 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1880 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1881 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1883 /* Test which renderer of two already added to the graph will be chosen
1884 * (one is "exact" match, other is "wildcard" match. Seems to depend
1885 * on the order in which filters are added to the graph, thus indicating
1886 * no preference given to exact match. */
1887 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1888 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1889 if (!pgraph2) return;
1891 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1892 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1893 if (FAILED(hr)) goto out;
1895 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1896 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1898 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1899 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1900 if (FAILED(hr)) goto out;
1902 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1903 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1905 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1906 ptestfilter2 = NULL;
1908 hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1909 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1910 if (FAILED(hr)) goto out;
1912 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1913 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1915 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1916 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1918 hr = get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1920 IFilterGraph2_Release(pgraph2);
1921 pgraph2 = NULL;
1922 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1923 ptestfilter = NULL;
1924 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1925 ptestfilter2 = NULL;
1927 if (hr == E_NOTIMPL)
1929 win_skip("Needed functions are not implemented\n");
1930 return;
1933 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1934 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1935 if (!pgraph2) goto out;
1937 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1938 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1939 if (FAILED(hr)) goto out;
1941 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1942 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1944 hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1945 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1946 if (FAILED(hr)) goto out;
1948 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1949 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1951 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1952 ptestfilter2 = NULL;
1954 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1955 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1956 if (FAILED(hr)) goto out;
1958 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1959 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1961 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1962 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1964 hr = IFilterGraph2_Disconnect(pgraph2, NULL);
1965 ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr);
1967 get_connected_filter_name(ptestfilter, ConnectedFilterName2);
1968 ok(strcmp(ConnectedFilterName1, ConnectedFilterName2),
1969 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1971 IFilterGraph2_Release(pgraph2);
1972 pgraph2 = NULL;
1973 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1974 ptestfilter = NULL;
1975 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1976 ptestfilter2 = NULL;
1978 /* Test if any preference is given to existing renderer which renders the pin directly vs
1979 an existing renderer which renders the pin indirectly, through an additional middle filter,
1980 again trying different orders of creation. Native appears not to give a preference. */
1982 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1983 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1984 if (!pgraph2) goto out;
1986 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1987 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1988 if (FAILED(hr)) goto out;
1990 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1991 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1993 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1994 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1995 if (FAILED(hr)) goto out;
1997 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1998 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
2000 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
2001 ptestfilter2 = NULL;
2003 hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
2004 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
2005 if (FAILED(hr)) goto out;
2007 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
2008 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
2010 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
2011 ptestfilter2 = NULL;
2013 hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2);
2014 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
2015 if (FAILED(hr)) goto out;
2017 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4);
2018 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
2020 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
2021 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
2023 get_connected_filter_name(ptestfilter, ConnectedFilterName1);
2024 ok(!strcmp(ConnectedFilterName1, "TestfilterInstance3") || !strcmp(ConnectedFilterName1, "TestfilterInstance2"),
2025 "unexpected connected filter: %s\n", ConnectedFilterName1);
2027 IFilterGraph2_Release(pgraph2);
2028 pgraph2 = NULL;
2029 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
2030 ptestfilter = NULL;
2031 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
2032 ptestfilter2 = NULL;
2034 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
2035 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
2036 if (!pgraph2) goto out;
2038 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
2039 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
2040 if (FAILED(hr)) goto out;
2042 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
2043 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
2045 hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
2046 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
2047 if (FAILED(hr)) goto out;
2049 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
2050 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
2052 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
2053 ptestfilter2 = NULL;
2055 hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2);
2056 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
2057 if (FAILED(hr)) goto out;
2059 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4);
2060 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
2062 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
2063 ptestfilter2 = NULL;
2065 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
2066 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
2067 if (FAILED(hr)) goto out;
2069 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
2070 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
2072 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
2073 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
2075 get_connected_filter_name(ptestfilter, ConnectedFilterName2);
2076 ok(!strcmp(ConnectedFilterName2, "TestfilterInstance3") || !strcmp(ConnectedFilterName2, "TestfilterInstance2"),
2077 "unexpected connected filter: %s\n", ConnectedFilterName2);
2078 ok(strcmp(ConnectedFilterName1, ConnectedFilterName2),
2079 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
2081 IFilterGraph2_Release(pgraph2);
2082 pgraph2 = NULL;
2083 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
2084 ptestfilter = NULL;
2085 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
2086 ptestfilter2 = NULL;
2088 /* Test if renderers are tried before non-renderers (intermediary filters). */
2089 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
2090 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
2091 if (!pgraph2) goto out;
2093 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
2094 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
2095 if (!pMapper2) goto out;
2097 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
2098 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
2099 if (FAILED(hr)) goto out;
2101 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
2102 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
2104 /* Register our filters with COM and with Filtermapper. */
2105 hr = CoRegisterClassObject(Filter1ClassFactory.clsid,
2106 (IUnknown *)&Filter1ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
2107 REGCLS_MULTIPLEUSE, &cookie1);
2108 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
2109 if (FAILED(hr)) goto out;
2110 hr = CoRegisterClassObject(Filter2ClassFactory.clsid,
2111 (IUnknown *)&Filter2ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
2112 REGCLS_MULTIPLEUSE, &cookie2);
2113 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
2114 if (FAILED(hr)) goto out;
2115 hr = CoRegisterClassObject(Filter3ClassFactory.clsid,
2116 (IUnknown *)&Filter3ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
2117 REGCLS_MULTIPLEUSE, &cookie3);
2118 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
2119 if (FAILED(hr)) goto out;
2121 rgf2.dwVersion = 2;
2122 rgf2.dwMerit = MERIT_UNLIKELY;
2123 S2(U(rgf2)).cPins2 = 1;
2124 S2(U(rgf2)).rgPins2 = rgPins2;
2125 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
2126 rgPins2[0].cInstances = 1;
2127 rgPins2[0].nMediaTypes = 1;
2128 rgPins2[0].lpMediaType = &rgPinType[0];
2129 rgPins2[0].nMediums = 0;
2130 rgPins2[0].lpMedium = NULL;
2131 rgPins2[0].clsPinCategory = NULL;
2132 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
2133 rgPinType[0].clsMinorType = &mediasubtype1;
2135 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
2136 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
2137 if (hr == E_ACCESSDENIED)
2138 skip("Not authorized to register filters\n");
2139 else
2141 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
2143 rgf2.dwMerit = MERIT_PREFERRED;
2144 rgPinType[0].clsMinorType = &mediasubtype2;
2146 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
2147 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
2148 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
2150 S2(U(rgf2)).cPins2 = 2;
2151 rgPins2[0].dwFlags = 0;
2152 rgPinType[0].clsMinorType = &mediasubtype1;
2154 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
2155 rgPins2[1].cInstances = 1;
2156 rgPins2[1].nMediaTypes = 1;
2157 rgPins2[1].lpMediaType = &rgPinType[1];
2158 rgPins2[1].nMediums = 0;
2159 rgPins2[1].lpMedium = NULL;
2160 rgPins2[1].clsPinCategory = NULL;
2161 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
2162 rgPinType[1].clsMinorType = &mediasubtype2;
2164 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
2165 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
2166 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
2168 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
2169 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
2171 get_connected_filter_name(ptestfilter, ConnectedFilterName1);
2172 ok(!strcmp(ConnectedFilterName1, "TestfilterInstance3"),
2173 "unexpected connected filter: %s\n", ConnectedFilterName1);
2175 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
2176 &CLSID_TestFilter2);
2177 ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
2178 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
2179 &CLSID_TestFilter3);
2180 ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
2181 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
2182 &CLSID_TestFilter4);
2183 ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
2186 out:
2188 if (ptestfilter) IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
2189 if (ptestfilter2) IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
2190 if (pgraph2) IFilterGraph2_Release(pgraph2);
2191 if (pMapper2) IFilterMapper2_Release(pMapper2);
2193 hr = CoRevokeClassObject(cookie1);
2194 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
2195 hr = CoRevokeClassObject(cookie2);
2196 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
2197 hr = CoRevokeClassObject(cookie3);
2198 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
2201 typedef struct IUnknownImpl
2203 IUnknown IUnknown_iface;
2204 int AddRef_called;
2205 int Release_called;
2206 } IUnknownImpl;
2208 static IUnknownImpl *IUnknownImpl_from_iface(IUnknown * iface)
2210 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
2213 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
2215 ok(0, "QueryInterface should not be called for %s\n", wine_dbgstr_guid(riid));
2216 return E_NOINTERFACE;
2219 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown * iface)
2221 IUnknownImpl *This = IUnknownImpl_from_iface(iface);
2222 This->AddRef_called++;
2223 return 2;
2226 static ULONG WINAPI IUnknownImpl_Release(IUnknown * iface)
2228 IUnknownImpl *This = IUnknownImpl_from_iface(iface);
2229 This->Release_called++;
2230 return 1;
2233 static CONST_VTBL IUnknownVtbl IUnknownImpl_Vtbl =
2235 IUnknownImpl_QueryInterface,
2236 IUnknownImpl_AddRef,
2237 IUnknownImpl_Release
2240 static void test_aggregate_filter_graph(void)
2242 HRESULT hr;
2243 IUnknown *pgraph;
2244 IUnknown *punk;
2245 IUnknownImpl unk_outer = { { &IUnknownImpl_Vtbl }, 0, 0 };
2247 hr = CoCreateInstance(&CLSID_FilterGraph, &unk_outer.IUnknown_iface, CLSCTX_INPROC_SERVER,
2248 &IID_IUnknown, (void **)&pgraph);
2249 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
2250 ok(pgraph != &unk_outer.IUnknown_iface, "pgraph = %p, expected not %p\n", pgraph, &unk_outer.IUnknown_iface);
2252 hr = IUnknown_QueryInterface(pgraph, &IID_IUnknown, (void **)&punk);
2253 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
2254 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
2255 IUnknown_Release(punk);
2257 ok(unk_outer.AddRef_called == 0, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
2258 ok(unk_outer.Release_called == 0, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
2259 unk_outer.AddRef_called = 0;
2260 unk_outer.Release_called = 0;
2262 hr = IUnknown_QueryInterface(pgraph, &IID_IFilterMapper, (void **)&punk);
2263 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
2264 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
2265 IUnknown_Release(punk);
2267 ok(unk_outer.AddRef_called == 1, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
2268 ok(unk_outer.Release_called == 1, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
2269 unk_outer.AddRef_called = 0;
2270 unk_outer.Release_called = 0;
2272 hr = IUnknown_QueryInterface(pgraph, &IID_IFilterMapper2, (void **)&punk);
2273 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
2274 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
2275 IUnknown_Release(punk);
2277 ok(unk_outer.AddRef_called == 1, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
2278 ok(unk_outer.Release_called == 1, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
2279 unk_outer.AddRef_called = 0;
2280 unk_outer.Release_called = 0;
2282 hr = IUnknown_QueryInterface(pgraph, &IID_IFilterMapper3, (void **)&punk);
2283 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
2284 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
2285 IUnknown_Release(punk);
2287 ok(unk_outer.AddRef_called == 1, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
2288 ok(unk_outer.Release_called == 1, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
2290 IUnknown_Release(pgraph);
2293 START_TEST(filtergraph)
2295 HRESULT hr;
2296 CoInitializeEx(NULL, COINIT_MULTITHREADED);
2297 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
2298 &IID_IGraphBuilder, (LPVOID*)&pgraph);
2299 if (FAILED(hr)) {
2300 skip("Creating filtergraph returned %08x, skipping tests\n", hr);
2301 return;
2303 IGraphBuilder_Release(pgraph);
2304 test_render_run(avifile);
2305 test_render_run(mpegfile);
2306 test_graph_builder();
2307 test_graph_builder_addfilter();
2308 test_mediacontrol();
2309 test_filter_graph2();
2310 test_render_filter_priority();
2311 test_aggregate_filter_graph();
2312 CoUninitialize();
2313 test_render_with_multithread();