[QUARTZ_WINETEST] Sync with Wine Staging 2.2. CORE-12823
[reactos.git] / rostests / winetests / quartz / filtergraph.c
1 /*
2 * Unit tests for Direct Show functions
3 *
4 * Copyright (C) 2004 Christian Costa
5 * Copyright (C) 2008 Alexander Dorofeyev
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #define COBJMACROS
23 #define CONST_VTABLE
24
25 #include "wine/test.h"
26 #include "dshow.h"
27 #include "control.h"
28
29 typedef struct TestFilterImpl
30 {
31 IBaseFilter IBaseFilter_iface;
32
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;
41
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};
44
45 static IGraphBuilder *pgraph;
46
47 static int createfiltergraph(void)
48 {
49 return S_OK == CoCreateInstance(
50 &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&pgraph);
51 }
52
53 static void test_basic_video(void)
54 {
55 IBasicVideo* pbv;
56 LONG video_width, video_height;
57 LONG left, top, width, height;
58 HRESULT hr;
59
60 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IBasicVideo, (LPVOID*)&pbv);
61 ok(hr==S_OK, "Cannot get IBasicVideo interface returned: %x\n", hr);
62
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);
72
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);
86
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);
97
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);
110
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);
115
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);
118
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);
131
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);
138
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);
145
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);
152
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);
159
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);
173
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);
178
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);
185
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);
198
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);
203
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);
206
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);
219
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);
226
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);
233
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);
240
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);
247
248 /* reset source rectangle */
249 hr = IBasicVideo_SetDefaultSourcePosition(pbv);
250 ok(hr==S_OK, "IBasicVideo_SetDefaultSourcePosition returned: %x\n", hr);
251
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);
255
256 IBasicVideo_Release(pbv);
257 }
258
259 static void rungraph(void)
260 {
261 HRESULT hr;
262 IMediaControl* pmc;
263 IMediaEvent* pme;
264 IMediaFilter* pmf;
265 HANDLE hEvent;
266
267 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (LPVOID*)&pmc);
268 ok(hr==S_OK, "Cannot get IMediaControl interface returned: %x\n", hr);
269
270 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (LPVOID*)&pmf);
271 ok(hr==S_OK, "Cannot get IMediaFilter interface returned: %x\n", hr);
272
273 IMediaControl_Stop(pmc);
274
275 IMediaFilter_SetSyncSource(pmf, NULL);
276
277 IMediaFilter_Release(pmf);
278
279 test_basic_video();
280
281 hr = IMediaControl_Run(pmc);
282 ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr);
283
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);
289
290 IGraphBuilder_SetDefaultSyncSource(pgraph);
291
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);
296
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);
301
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);
306
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);
311
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);
316
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);
320
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);
324
325 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaEvent, (LPVOID*)&pme);
326 ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr);
327
328 hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent);
329 ok(hr==S_OK, "Cannot get event handle returned: %x\n", hr);
330
331 /* WaitForSingleObject(hEvent, INFINITE); */
332 Sleep(20000);
333
334 hr = IMediaEvent_Release(pme);
335 ok(hr==2, "Releasing mediaevent returned: %x\n", hr);
336
337 hr = IMediaControl_Stop(pmc);
338 ok(hr==S_OK, "Cannot stop the graph returned: %x\n", hr);
339
340 hr = IMediaControl_Release(pmc);
341 ok(hr==1, "Releasing mediacontrol returned: %x\n", hr);
342 }
343
344 static void releasefiltergraph(void)
345 {
346 HRESULT hr;
347
348 hr = IGraphBuilder_Release(pgraph);
349 ok(hr==0, "Releasing filtergraph returned: %x\n", hr);
350 }
351
352 static void test_render_run(const WCHAR *file)
353 {
354 HANDLE h;
355 HRESULT hr;
356
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;
361 }
362 CloseHandle(h);
363
364 if (!createfiltergraph())
365 return;
366
367 hr = IGraphBuilder_RenderFile(pgraph, file, NULL);
368 ok(hr == S_OK, "RenderFile returned: %x\n", hr);
369 rungraph();
370
371 releasefiltergraph();
372
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);
377 }
378
379 static void test_graph_builder(void)
380 {
381 HRESULT hr;
382 IBaseFilter *pF = NULL;
383 IBaseFilter *pF2 = NULL;
384 IPin *pIn = NULL;
385 IEnumPins *pEnum = NULL;
386 PIN_DIRECTION dir;
387 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
388 static const WCHAR fooBarW[] = {'f','o','o','B','a','r',0};
389
390 if (!createfiltergraph())
391 return;
392
393 /* create video filter */
394 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
395 &IID_IBaseFilter, (LPVOID*)&pF);
396 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
397 ok(pF != NULL, "pF is NULL\n");
398
399 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
400 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned %x\n", hr);
401
402 /* add the two filters to the graph */
403 hr = IGraphBuilder_AddFilter(pgraph, pF, testFilterW);
404 ok(hr == S_OK, "failed to add pF to the graph: %x\n", hr);
405
406 /* find the pins */
407 hr = IBaseFilter_EnumPins(pF, &pEnum);
408 ok(hr == S_OK, "IBaseFilter_EnumPins failed for pF: %x\n", hr);
409 ok(pEnum != NULL, "pEnum is NULL\n");
410 hr = IEnumPins_Next(pEnum, 1, &pIn, NULL);
411 ok(hr == S_OK, "IEnumPins_Next failed for pF: %x\n", hr);
412 ok(pIn != NULL, "pIn is NULL\n");
413 hr = IPin_QueryDirection(pIn, &dir);
414 ok(hr == S_OK, "IPin_QueryDirection failed: %x\n", hr);
415 ok(dir == PINDIR_INPUT, "pin has wrong direction\n");
416
417 hr = IGraphBuilder_FindFilterByName(pgraph, fooBarW, &pF2);
418 ok(hr == VFW_E_NOT_FOUND, "IGraphBuilder_FindFilterByName returned %x\n", hr);
419 ok(pF2 == NULL, "IGraphBuilder_FindFilterByName returned %p\n", pF2);
420 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, &pF2);
421 ok(hr == S_OK, "IGraphBuilder_FindFilterByName returned %x\n", hr);
422 ok(pF2 != NULL, "IGraphBuilder_FindFilterByName returned NULL\n");
423 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, NULL);
424 ok(hr == E_POINTER, "IGraphBuilder_FindFilterByName returned %x\n", hr);
425
426 hr = IGraphBuilder_Connect(pgraph, NULL, pIn);
427 ok(hr == E_POINTER, "IGraphBuilder_Connect returned %x\n", hr);
428
429 hr = IGraphBuilder_Connect(pgraph, pIn, NULL);
430 ok(hr == E_POINTER, "IGraphBuilder_Connect returned %x\n", hr);
431
432 hr = IGraphBuilder_Connect(pgraph, pIn, pIn);
433 ok(hr == VFW_E_CANNOT_CONNECT, "IGraphBuilder_Connect returned %x\n", hr);
434
435 if (pIn) IPin_Release(pIn);
436 if (pEnum) IEnumPins_Release(pEnum);
437 if (pF) IBaseFilter_Release(pF);
438 if (pF2) IBaseFilter_Release(pF2);
439
440 releasefiltergraph();
441 }
442
443 static void test_graph_builder_addfilter(void)
444 {
445 HRESULT hr;
446 IBaseFilter *pF = NULL;
447 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
448
449 if (!createfiltergraph())
450 return;
451
452 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
453 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr);
454
455 /* create video filter */
456 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
457 &IID_IBaseFilter, (LPVOID*)&pF);
458 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
459 ok(pF != NULL, "pF is NULL\n");
460 if (!pF) {
461 skip("failed to created filter, skipping\n");
462 return;
463 }
464
465 hr = IGraphBuilder_AddFilter(pgraph, pF, NULL);
466 ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr);
467 IBaseFilter_Release(pF);
468 }
469
470 static void test_mediacontrol(void)
471 {
472 HRESULT hr;
473 LONGLONG pos = 0xdeadbeef;
474 GUID format = GUID_NULL;
475 IMediaSeeking *seeking = NULL;
476 IMediaFilter *filter = NULL;
477 IMediaControl *control = NULL;
478
479 IGraphBuilder_SetDefaultSyncSource(pgraph);
480 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking);
481 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
482 if (FAILED(hr))
483 return;
484
485 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
486 ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
487 if (FAILED(hr))
488 {
489 IMediaSeeking_Release(seeking);
490 return;
491 }
492
493 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
494 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
495 if (FAILED(hr))
496 {
497 IMediaSeeking_Release(seeking);
498 IMediaFilter_Release(filter);
499 return;
500 }
501
502 format = GUID_NULL;
503 hr = IMediaSeeking_GetTimeFormat(seeking, &format);
504 ok(hr == S_OK, "GetTimeFormat failed: %08x\n", hr);
505 ok(IsEqualGUID(&format, &TIME_FORMAT_MEDIA_TIME), "GetTimeFormat: unexpected format %s\n", wine_dbgstr_guid(&format));
506
507 pos = 0xdeadbeef;
508 hr = IMediaSeeking_ConvertTimeFormat(seeking, &pos, NULL, 0x123456789a, NULL);
509 ok(hr == S_OK, "ConvertTimeFormat failed: %08x\n", hr);
510 ok(pos == 0x123456789a, "ConvertTimeFormat: expected 123456789a, got (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
511
512 pos = 0xdeadbeef;
513 hr = IMediaSeeking_ConvertTimeFormat(seeking, &pos, &TIME_FORMAT_MEDIA_TIME, 0x123456789a, NULL);
514 ok(hr == S_OK, "ConvertTimeFormat failed: %08x\n", hr);
515 ok(pos == 0x123456789a, "ConvertTimeFormat: expected 123456789a, got (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
516
517 pos = 0xdeadbeef;
518 hr = IMediaSeeking_ConvertTimeFormat(seeking, &pos, NULL, 0x123456789a, &TIME_FORMAT_MEDIA_TIME);
519 ok(hr == S_OK, "ConvertTimeFormat failed: %08x\n", hr);
520 ok(pos == 0x123456789a, "ConvertTimeFormat: expected 123456789a, got (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
521
522 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
523 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
524 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
525
526 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_ReturnTime, NULL, AM_SEEKING_NoPositioning);
527 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
528 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_NoPositioning, NULL, AM_SEEKING_ReturnTime);
529 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
530
531 IMediaFilter_SetSyncSource(filter, NULL);
532 pos = 0xdeadbeef;
533 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
534 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
535 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
536
537 hr = IMediaControl_GetState(control, 1000, NULL);
538 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
539
540 IMediaControl_Release(control);
541 IMediaSeeking_Release(seeking);
542 IMediaFilter_Release(filter);
543 releasefiltergraph();
544 }
545
546 static void test_filter_graph2(void)
547 {
548 HRESULT hr;
549 IFilterGraph2 *pF = NULL;
550
551 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
552 &IID_IFilterGraph2, (LPVOID*)&pF);
553 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
554 ok(pF != NULL, "pF is NULL\n");
555
556 hr = IFilterGraph2_Release(pF);
557 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
558 }
559
560 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
561 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
562 {
563 if (pMediaType->pbFormat)
564 {
565 CoTaskMemFree(pMediaType->pbFormat);
566 pMediaType->pbFormat = NULL;
567 }
568 if (pMediaType->pUnk)
569 {
570 IUnknown_Release(pMediaType->pUnk);
571 pMediaType->pUnk = NULL;
572 }
573 }
574
575 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
576 {
577 *pDest = *pSrc;
578 if (!pSrc->pbFormat) return S_OK;
579 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
580 return E_OUTOFMEMORY;
581 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
582 if (pDest->pUnk)
583 IUnknown_AddRef(pDest->pUnk);
584 return S_OK;
585 }
586
587 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
588 {
589 AM_MEDIA_TYPE * pDest;
590
591 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
592 if (!pDest)
593 return NULL;
594
595 if (FAILED(CopyMediaType(pDest, pSrc)))
596 {
597 CoTaskMemFree(pDest);
598 return NULL;
599 }
600
601 return pDest;
602 }
603
604 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
605 {
606 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
607 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
608 }
609
610 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
611 {
612 FreeMediaType(pMediaType);
613 CoTaskMemFree(pMediaType);
614 }
615
616 typedef struct IEnumMediaTypesImpl
617 {
618 IEnumMediaTypes IEnumMediaTypes_iface;
619 LONG refCount;
620 AM_MEDIA_TYPE *pMediaTypes;
621 ULONG cMediaTypes;
622 ULONG uIndex;
623 } IEnumMediaTypesImpl;
624
625 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
626
627 static inline IEnumMediaTypesImpl *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
628 {
629 return CONTAINING_RECORD(iface, IEnumMediaTypesImpl, IEnumMediaTypes_iface);
630 }
631
632 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
633 {
634 ULONG i;
635 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
636
637 if (!pEnumMediaTypes)
638 {
639 *ppEnum = NULL;
640 return E_OUTOFMEMORY;
641 }
642 pEnumMediaTypes->IEnumMediaTypes_iface.lpVtbl = &IEnumMediaTypesImpl_Vtbl;
643 pEnumMediaTypes->refCount = 1;
644 pEnumMediaTypes->uIndex = 0;
645 pEnumMediaTypes->cMediaTypes = cMediaTypes;
646 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
647 for (i = 0; i < cMediaTypes; i++)
648 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
649 {
650 while (i--)
651 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
652 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
653 return E_OUTOFMEMORY;
654 }
655 *ppEnum = &pEnumMediaTypes->IEnumMediaTypes_iface;
656 return S_OK;
657 }
658
659 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
660 {
661 *ppv = NULL;
662
663 if (IsEqualIID(riid, &IID_IUnknown))
664 *ppv = iface;
665 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
666 *ppv = iface;
667
668 if (*ppv)
669 {
670 IUnknown_AddRef((IUnknown *)(*ppv));
671 return S_OK;
672 }
673
674 return E_NOINTERFACE;
675 }
676
677 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
678 {
679 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
680 ULONG refCount = InterlockedIncrement(&This->refCount);
681
682 return refCount;
683 }
684
685 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
686 {
687 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
688 ULONG refCount = InterlockedDecrement(&This->refCount);
689
690 if (!refCount)
691 {
692 int i;
693 for (i = 0; i < This->cMediaTypes; i++)
694 FreeMediaType(&This->pMediaTypes[i]);
695 CoTaskMemFree(This->pMediaTypes);
696 CoTaskMemFree(This);
697 }
698 return refCount;
699 }
700
701 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
702 {
703 ULONG cFetched;
704 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
705
706 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
707
708 if (cFetched > 0)
709 {
710 ULONG i;
711 for (i = 0; i < cFetched; i++)
712 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
713 {
714 while (i--)
715 DeleteMediaType(ppMediaTypes[i]);
716 *pcFetched = 0;
717 return E_OUTOFMEMORY;
718 }
719 }
720
721 if ((cMediaTypes != 1) || pcFetched)
722 *pcFetched = cFetched;
723
724 This->uIndex += cFetched;
725
726 if (cFetched != cMediaTypes)
727 return S_FALSE;
728 return S_OK;
729 }
730
731 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
732 {
733 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
734
735 if (This->uIndex + cMediaTypes < This->cMediaTypes)
736 {
737 This->uIndex += cMediaTypes;
738 return S_OK;
739 }
740 return S_FALSE;
741 }
742
743 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
744 {
745 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
746
747 This->uIndex = 0;
748 return S_OK;
749 }
750
751 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
752 {
753 HRESULT hr;
754 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
755
756 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
757 if (FAILED(hr))
758 return hr;
759 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
760 }
761
762 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
763 {
764 IEnumMediaTypesImpl_QueryInterface,
765 IEnumMediaTypesImpl_AddRef,
766 IEnumMediaTypesImpl_Release,
767 IEnumMediaTypesImpl_Next,
768 IEnumMediaTypesImpl_Skip,
769 IEnumMediaTypesImpl_Reset,
770 IEnumMediaTypesImpl_Clone
771 };
772
773 /* Implementation of a very stripped down pin for the test filter. Just enough
774 functionality for connecting and Render() to work. */
775
776 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
777 {
778 lstrcpyW(pDest->achName, pSrc->achName);
779 pDest->dir = pSrc->dir;
780 pDest->pFilter = pSrc->pFilter;
781 }
782
783 typedef struct ITestPinImpl
784 {
785 IPin IPin_iface;
786 LONG refCount;
787 LPCRITICAL_SECTION pCritSec;
788 PIN_INFO pinInfo;
789 IPin * pConnectedTo;
790 AM_MEDIA_TYPE mtCurrent;
791 LPVOID pUserData;
792 } ITestPinImpl;
793
794 static inline ITestPinImpl *impl_from_IPin(IPin *iface)
795 {
796 return CONTAINING_RECORD(iface, ITestPinImpl, IPin_iface);
797 }
798
799 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
800 {
801 *ppv = NULL;
802
803 if (IsEqualIID(riid, &IID_IUnknown))
804 *ppv = iface;
805 else if (IsEqualIID(riid, &IID_IPin))
806 *ppv = iface;
807
808 if (*ppv)
809 {
810 IUnknown_AddRef((IUnknown *)(*ppv));
811 return S_OK;
812 }
813
814 return E_NOINTERFACE;
815 }
816
817 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
818 {
819 ITestPinImpl *This = impl_from_IPin(iface);
820 ULONG refCount = InterlockedIncrement(&This->refCount);
821 return refCount;
822 }
823
824 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
825 {
826 ITestPinImpl *This = impl_from_IPin(iface);
827 ULONG refCount = InterlockedDecrement(&This->refCount);
828
829 if (!refCount)
830 {
831 FreeMediaType(&This->mtCurrent);
832 CoTaskMemFree(This);
833 return 0;
834 }
835 else
836 return refCount;
837 }
838
839 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
840 {
841 return E_UNEXPECTED;
842 }
843
844 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
845 {
846 ITestPinImpl *This = impl_from_IPin(iface);
847 PIN_DIRECTION pindirReceive;
848 HRESULT hr = S_OK;
849
850 EnterCriticalSection(This->pCritSec);
851 {
852 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
853 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
854 hr = VFW_E_TYPE_NOT_ACCEPTED;
855
856 if (This->pConnectedTo)
857 hr = VFW_E_ALREADY_CONNECTED;
858
859 if (SUCCEEDED(hr))
860 {
861 IPin_QueryDirection(pReceivePin, &pindirReceive);
862
863 if (pindirReceive != PINDIR_OUTPUT)
864 {
865 hr = VFW_E_INVALID_DIRECTION;
866 }
867 }
868
869 if (SUCCEEDED(hr))
870 {
871 CopyMediaType(&This->mtCurrent, pmt);
872 This->pConnectedTo = pReceivePin;
873 IPin_AddRef(pReceivePin);
874 }
875 }
876 LeaveCriticalSection(This->pCritSec);
877
878 return hr;
879 }
880
881 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
882 {
883 HRESULT hr;
884 ITestPinImpl *This = impl_from_IPin(iface);
885
886 EnterCriticalSection(This->pCritSec);
887 {
888 if (This->pConnectedTo)
889 {
890 IPin_Release(This->pConnectedTo);
891 This->pConnectedTo = NULL;
892 hr = S_OK;
893 }
894 else
895 hr = S_FALSE;
896 }
897 LeaveCriticalSection(This->pCritSec);
898
899 return hr;
900 }
901
902 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
903 {
904 HRESULT hr;
905 ITestPinImpl *This = impl_from_IPin(iface);
906
907 EnterCriticalSection(This->pCritSec);
908 {
909 if (This->pConnectedTo)
910 {
911 *ppPin = This->pConnectedTo;
912 IPin_AddRef(*ppPin);
913 hr = S_OK;
914 }
915 else
916 {
917 hr = VFW_E_NOT_CONNECTED;
918 *ppPin = NULL;
919 }
920 }
921 LeaveCriticalSection(This->pCritSec);
922
923 return hr;
924 }
925
926 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
927 {
928 HRESULT hr;
929 ITestPinImpl *This = impl_from_IPin(iface);
930
931 EnterCriticalSection(This->pCritSec);
932 {
933 if (This->pConnectedTo)
934 {
935 CopyMediaType(pmt, &This->mtCurrent);
936 hr = S_OK;
937 }
938 else
939 {
940 ZeroMemory(pmt, sizeof(*pmt));
941 hr = VFW_E_NOT_CONNECTED;
942 }
943 }
944 LeaveCriticalSection(This->pCritSec);
945
946 return hr;
947 }
948
949 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
950 {
951 ITestPinImpl *This = impl_from_IPin(iface);
952
953 Copy_PinInfo(pInfo, &This->pinInfo);
954 IBaseFilter_AddRef(pInfo->pFilter);
955
956 return S_OK;
957 }
958
959 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
960 {
961 ITestPinImpl *This = impl_from_IPin(iface);
962
963 *pPinDir = This->pinInfo.dir;
964
965 return S_OK;
966 }
967
968 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
969 {
970 return E_NOTIMPL;
971 }
972
973 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
974 {
975 ITestPinImpl *This = impl_from_IPin(iface);
976
977 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
978 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
979 return S_OK;
980 else
981 return VFW_E_TYPE_NOT_ACCEPTED;
982 }
983
984 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
985 {
986 ITestPinImpl *This = impl_from_IPin(iface);
987
988 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
989 }
990
991 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
992 {
993 return E_NOTIMPL;
994 }
995
996 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
997 {
998 return E_NOTIMPL;
999 }
1000
1001 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
1002 {
1003 return E_NOTIMPL;
1004 }
1005
1006 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1007 {
1008 return E_NOTIMPL;
1009 }
1010
1011 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
1012 {
1013 return E_NOTIMPL;
1014 }
1015
1016 static const IPinVtbl TestFilter_InputPin_Vtbl =
1017 {
1018 TestFilter_Pin_QueryInterface,
1019 TestFilter_Pin_AddRef,
1020 TestFilter_Pin_Release,
1021 TestFilter_InputPin_Connect,
1022 TestFilter_InputPin_ReceiveConnection,
1023 TestFilter_Pin_Disconnect,
1024 TestFilter_Pin_ConnectedTo,
1025 TestFilter_Pin_ConnectionMediaType,
1026 TestFilter_Pin_QueryPinInfo,
1027 TestFilter_Pin_QueryDirection,
1028 TestFilter_Pin_QueryId,
1029 TestFilter_Pin_QueryAccept,
1030 TestFilter_Pin_EnumMediaTypes,
1031 TestFilter_Pin_QueryInternalConnections,
1032 TestFilter_Pin_EndOfStream,
1033 TestFilter_Pin_BeginFlush,
1034 TestFilter_Pin_EndFlush,
1035 TestFilter_Pin_NewSegment
1036 };
1037
1038 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
1039 {
1040 return E_UNEXPECTED;
1041 }
1042
1043 /* Private helper function */
1044 static HRESULT TestFilter_OutputPin_ConnectSpecific(ITestPinImpl * This, IPin * pReceivePin,
1045 const AM_MEDIA_TYPE * pmt)
1046 {
1047 HRESULT hr;
1048
1049 This->pConnectedTo = pReceivePin;
1050 IPin_AddRef(pReceivePin);
1051
1052 hr = IPin_ReceiveConnection(pReceivePin, &This->IPin_iface, pmt);
1053
1054 if (FAILED(hr))
1055 {
1056 IPin_Release(This->pConnectedTo);
1057 This->pConnectedTo = NULL;
1058 }
1059
1060 return hr;
1061 }
1062
1063 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
1064 {
1065 ITestPinImpl *This = impl_from_IPin(iface);
1066 HRESULT hr;
1067
1068 EnterCriticalSection(This->pCritSec);
1069 {
1070 /* if we have been a specific type to connect with, then we can either connect
1071 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
1072 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
1073 hr = TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, pmt);
1074 else
1075 {
1076 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
1077 (TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, &This->mtCurrent) == S_OK))
1078 hr = S_OK;
1079 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
1080 } /* if negotiate media type */
1081 } /* if succeeded */
1082 LeaveCriticalSection(This->pCritSec);
1083
1084 return hr;
1085 }
1086
1087 static const IPinVtbl TestFilter_OutputPin_Vtbl =
1088 {
1089 TestFilter_Pin_QueryInterface,
1090 TestFilter_Pin_AddRef,
1091 TestFilter_Pin_Release,
1092 TestFilter_OutputPin_Connect,
1093 TestFilter_OutputPin_ReceiveConnection,
1094 TestFilter_Pin_Disconnect,
1095 TestFilter_Pin_ConnectedTo,
1096 TestFilter_Pin_ConnectionMediaType,
1097 TestFilter_Pin_QueryPinInfo,
1098 TestFilter_Pin_QueryDirection,
1099 TestFilter_Pin_QueryId,
1100 TestFilter_Pin_QueryAccept,
1101 TestFilter_Pin_EnumMediaTypes,
1102 TestFilter_Pin_QueryInternalConnections,
1103 TestFilter_Pin_EndOfStream,
1104 TestFilter_Pin_BeginFlush,
1105 TestFilter_Pin_EndFlush,
1106 TestFilter_Pin_NewSegment
1107 };
1108
1109 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
1110 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
1111 {
1112 ITestPinImpl * pPinImpl;
1113
1114 *ppPin = NULL;
1115
1116 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
1117
1118 if (!pPinImpl)
1119 return E_OUTOFMEMORY;
1120
1121 pPinImpl->refCount = 1;
1122 pPinImpl->pConnectedTo = NULL;
1123 pPinImpl->pCritSec = pCritSec;
1124 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
1125 pPinImpl->mtCurrent = *pinmt;
1126
1127 pPinImpl->IPin_iface.lpVtbl = Pin_Vtbl;
1128
1129 *ppPin = &pPinImpl->IPin_iface;
1130 return S_OK;
1131 }
1132
1133 /* IEnumPins implementation */
1134
1135 typedef HRESULT (* FNOBTAINPIN)(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick);
1136
1137 typedef struct IEnumPinsImpl
1138 {
1139 IEnumPins IEnumPins_iface;
1140 LONG refCount;
1141 ULONG uIndex;
1142 TestFilterImpl *base;
1143 FNOBTAINPIN receive_pin;
1144 DWORD synctime;
1145 } IEnumPinsImpl;
1146
1147 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
1148
1149 static inline IEnumPinsImpl *impl_from_IEnumPins(IEnumPins *iface)
1150 {
1151 return CONTAINING_RECORD(iface, IEnumPinsImpl, IEnumPins_iface);
1152 }
1153
1154 static HRESULT createenumpins(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, TestFilterImpl *base)
1155 {
1156 IEnumPinsImpl * pEnumPins;
1157
1158 if (!ppEnum)
1159 return E_POINTER;
1160
1161 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
1162 if (!pEnumPins)
1163 {
1164 *ppEnum = NULL;
1165 return E_OUTOFMEMORY;
1166 }
1167 pEnumPins->IEnumPins_iface.lpVtbl = &IEnumPinsImpl_Vtbl;
1168 pEnumPins->refCount = 1;
1169 pEnumPins->uIndex = 0;
1170 pEnumPins->receive_pin = receive_pin;
1171 pEnumPins->base = base;
1172 IBaseFilter_AddRef(&base->IBaseFilter_iface);
1173 *ppEnum = &pEnumPins->IEnumPins_iface;
1174
1175 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
1176
1177 return S_OK;
1178 }
1179
1180 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
1181 {
1182 *ppv = NULL;
1183
1184 if (IsEqualIID(riid, &IID_IUnknown))
1185 *ppv = iface;
1186 else if (IsEqualIID(riid, &IID_IEnumPins))
1187 *ppv = iface;
1188
1189 if (*ppv)
1190 {
1191 IUnknown_AddRef((IUnknown *)(*ppv));
1192 return S_OK;
1193 }
1194
1195 return E_NOINTERFACE;
1196 }
1197
1198 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
1199 {
1200 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1201 ULONG refCount = InterlockedIncrement(&This->refCount);
1202
1203 return refCount;
1204 }
1205
1206 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
1207 {
1208 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1209 ULONG refCount = InterlockedDecrement(&This->refCount);
1210
1211 if (!refCount)
1212 {
1213 IBaseFilter_Release(&This->base->IBaseFilter_iface);
1214 CoTaskMemFree(This);
1215 return 0;
1216 }
1217 else
1218 return refCount;
1219 }
1220
1221 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
1222 {
1223 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1224 DWORD synctime = This->synctime;
1225 HRESULT hr = S_OK;
1226 ULONG i = 0;
1227
1228 if (!ppPins)
1229 return E_POINTER;
1230
1231 if (cPins > 1 && !pcFetched)
1232 return E_INVALIDARG;
1233
1234 if (pcFetched)
1235 *pcFetched = 0;
1236
1237 while (i < cPins && hr == S_OK)
1238 {
1239 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
1240
1241 if (hr == S_OK)
1242 ++i;
1243
1244 if (synctime != This->synctime)
1245 break;
1246 }
1247
1248 if (!i && synctime != This->synctime)
1249 return VFW_E_ENUM_OUT_OF_SYNC;
1250
1251 if (pcFetched)
1252 *pcFetched = i;
1253 This->uIndex += i;
1254
1255 if (i < cPins)
1256 return S_FALSE;
1257 return S_OK;
1258 }
1259
1260 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
1261 {
1262 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1263 DWORD synctime = This->synctime;
1264 HRESULT hr;
1265 IPin *pin = NULL;
1266
1267 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
1268 if (pin)
1269 IPin_Release(pin);
1270
1271 if (synctime != This->synctime)
1272 return VFW_E_ENUM_OUT_OF_SYNC;
1273
1274 if (hr == S_OK)
1275 This->uIndex += cPins;
1276
1277 return hr;
1278 }
1279
1280 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1281 {
1282 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1283
1284 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1285
1286 This->uIndex = 0;
1287 return S_OK;
1288 }
1289
1290 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1291 {
1292 HRESULT hr;
1293 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1294
1295 hr = createenumpins(ppEnum, This->receive_pin, This->base);
1296 if (FAILED(hr))
1297 return hr;
1298 return IEnumPins_Skip(*ppEnum, This->uIndex);
1299 }
1300
1301 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1302 {
1303 IEnumPinsImpl_QueryInterface,
1304 IEnumPinsImpl_AddRef,
1305 IEnumPinsImpl_Release,
1306 IEnumPinsImpl_Next,
1307 IEnumPinsImpl_Skip,
1308 IEnumPinsImpl_Reset,
1309 IEnumPinsImpl_Clone
1310 };
1311
1312 /* Test filter implementation - a filter that has few predefined pins with single media type
1313 * that accept only this single media type. Enough for Render(). */
1314
1315 typedef struct TestFilterPinData
1316 {
1317 PIN_DIRECTION pinDir;
1318 const GUID *mediasubtype;
1319 } TestFilterPinData;
1320
1321 static const IBaseFilterVtbl TestFilter_Vtbl;
1322
1323 static inline TestFilterImpl *impl_from_IBaseFilter(IBaseFilter *iface)
1324 {
1325 return CONTAINING_RECORD(iface, TestFilterImpl, IBaseFilter_iface);
1326 }
1327
1328 static HRESULT createtestfilter(const CLSID* pClsid, const TestFilterPinData *pinData,
1329 TestFilterImpl **tf)
1330 {
1331 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1332 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1333 HRESULT hr;
1334 PIN_INFO pinInfo;
1335 TestFilterImpl* pTestFilter = NULL;
1336 UINT nPins, i;
1337 AM_MEDIA_TYPE mt;
1338
1339 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1340 if (!pTestFilter) return E_OUTOFMEMORY;
1341
1342 pTestFilter->clsid = *pClsid;
1343 pTestFilter->IBaseFilter_iface.lpVtbl = &TestFilter_Vtbl;
1344 pTestFilter->refCount = 1;
1345 InitializeCriticalSection(&pTestFilter->csFilter);
1346 pTestFilter->state = State_Stopped;
1347
1348 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1349
1350 nPins = 0;
1351 while(pinData[nPins].mediasubtype) ++nPins;
1352
1353 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1354 if (!pTestFilter->ppPins)
1355 {
1356 hr = E_OUTOFMEMORY;
1357 goto error;
1358 }
1359 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1360
1361 for (i = 0; i < nPins; i++)
1362 {
1363 ZeroMemory(&mt, sizeof(mt));
1364 mt.majortype = MEDIATYPE_Video;
1365 mt.formattype = FORMAT_None;
1366 mt.subtype = *pinData[i].mediasubtype;
1367
1368 pinInfo.dir = pinData[i].pinDir;
1369 pinInfo.pFilter = &pTestFilter->IBaseFilter_iface;
1370 if (pinInfo.dir == PINDIR_INPUT)
1371 {
1372 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1373 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1374 &pTestFilter->ppPins[i]);
1375
1376 }
1377 else
1378 {
1379 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1380 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1381 &pTestFilter->ppPins[i]);
1382 }
1383 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1384 }
1385
1386 pTestFilter->nPins = nPins;
1387 *tf = pTestFilter;
1388 return S_OK;
1389
1390 error:
1391
1392 if (pTestFilter->ppPins)
1393 {
1394 for (i = 0; i < nPins; i++)
1395 {
1396 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1397 }
1398 }
1399 CoTaskMemFree(pTestFilter->ppPins);
1400 DeleteCriticalSection(&pTestFilter->csFilter);
1401 CoTaskMemFree(pTestFilter);
1402
1403 return hr;
1404 }
1405
1406 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1407 {
1408 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1409
1410 *ppv = NULL;
1411
1412 if (IsEqualIID(riid, &IID_IUnknown))
1413 *ppv = This;
1414 else if (IsEqualIID(riid, &IID_IPersist))
1415 *ppv = This;
1416 else if (IsEqualIID(riid, &IID_IMediaFilter))
1417 *ppv = This;
1418 else if (IsEqualIID(riid, &IID_IBaseFilter))
1419 *ppv = This;
1420
1421 if (*ppv)
1422 {
1423 IUnknown_AddRef((IUnknown *)(*ppv));
1424 return S_OK;
1425 }
1426
1427 return E_NOINTERFACE;
1428 }
1429
1430 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1431 {
1432 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1433 ULONG refCount = InterlockedIncrement(&This->refCount);
1434
1435 return refCount;
1436 }
1437
1438 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1439 {
1440 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1441 ULONG refCount = InterlockedDecrement(&This->refCount);
1442
1443 if (!refCount)
1444 {
1445 ULONG i;
1446
1447 for (i = 0; i < This->nPins; i++)
1448 {
1449 IPin *pConnectedTo;
1450
1451 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1452 {
1453 IPin_Disconnect(pConnectedTo);
1454 IPin_Release(pConnectedTo);
1455 }
1456 IPin_Disconnect(This->ppPins[i]);
1457
1458 IPin_Release(This->ppPins[i]);
1459 }
1460
1461 CoTaskMemFree(This->ppPins);
1462
1463 DeleteCriticalSection(&This->csFilter);
1464
1465 CoTaskMemFree(This);
1466
1467 return 0;
1468 }
1469 else
1470 return refCount;
1471 }
1472 /** IPersist methods **/
1473
1474 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1475 {
1476 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1477
1478 *pClsid = This->clsid;
1479
1480 return S_OK;
1481 }
1482
1483 /** IMediaFilter methods **/
1484
1485 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1486 {
1487 return E_NOTIMPL;
1488 }
1489
1490 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1491 {
1492 return E_NOTIMPL;
1493 }
1494
1495 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1496 {
1497 return E_NOTIMPL;
1498 }
1499
1500 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1501 {
1502 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1503
1504 EnterCriticalSection(&This->csFilter);
1505 {
1506 *pState = This->state;
1507 }
1508 LeaveCriticalSection(&This->csFilter);
1509
1510 return S_OK;
1511 }
1512
1513 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1514 {
1515 return E_NOTIMPL;
1516 }
1517
1518 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1519 {
1520 return E_NOTIMPL;
1521 }
1522
1523 /** IBaseFilter implementation **/
1524
1525 static HRESULT getpin_callback(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick)
1526 {
1527 /* Our pins are static, not changing so setting static tick count is ok */
1528 *lastsynctick = 0;
1529
1530 if (pos >= tf->nPins)
1531 return S_FALSE;
1532
1533 *pin = tf->ppPins[pos];
1534 IPin_AddRef(*pin);
1535 return S_OK;
1536 }
1537
1538 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1539 {
1540 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1541
1542 return createenumpins(ppEnum, getpin_callback, This);
1543 }
1544
1545 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1546 {
1547 return E_NOTIMPL;
1548 }
1549
1550 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1551 {
1552 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1553
1554 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1555 pInfo->pGraph = This->filterInfo.pGraph;
1556
1557 if (pInfo->pGraph)
1558 IFilterGraph_AddRef(pInfo->pGraph);
1559
1560 return S_OK;
1561 }
1562
1563 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1564 {
1565 HRESULT hr = S_OK;
1566 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1567
1568 EnterCriticalSection(&This->csFilter);
1569 {
1570 if (pName)
1571 lstrcpyW(This->filterInfo.achName, pName);
1572 else
1573 *This->filterInfo.achName = '\0';
1574 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1575 }
1576 LeaveCriticalSection(&This->csFilter);
1577
1578 return hr;
1579 }
1580
1581 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1582 {
1583 return E_NOTIMPL;
1584 }
1585
1586 static const IBaseFilterVtbl TestFilter_Vtbl =
1587 {
1588 TestFilter_QueryInterface,
1589 TestFilter_AddRef,
1590 TestFilter_Release,
1591 TestFilter_GetClassID,
1592 TestFilter_Stop,
1593 TestFilter_Pause,
1594 TestFilter_Run,
1595 TestFilter_GetState,
1596 TestFilter_SetSyncSource,
1597 TestFilter_GetSyncSource,
1598 TestFilter_EnumPins,
1599 TestFilter_FindPin,
1600 TestFilter_QueryFilterInfo,
1601 TestFilter_JoinFilterGraph,
1602 TestFilter_QueryVendorInfo
1603 };
1604
1605 /* IClassFactory implementation */
1606
1607 typedef struct TestClassFactoryImpl
1608 {
1609 IClassFactory IClassFactory_iface;
1610 const TestFilterPinData *filterPinData;
1611 const CLSID *clsid;
1612 } TestClassFactoryImpl;
1613
1614 static inline TestClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
1615 {
1616 return CONTAINING_RECORD(iface, TestClassFactoryImpl, IClassFactory_iface);
1617 }
1618
1619 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1620 LPCLASSFACTORY iface,
1621 REFIID riid,
1622 LPVOID *ppvObj)
1623 {
1624 if (ppvObj == NULL) return E_POINTER;
1625
1626 if (IsEqualGUID(riid, &IID_IUnknown) ||
1627 IsEqualGUID(riid, &IID_IClassFactory))
1628 {
1629 *ppvObj = iface;
1630 IClassFactory_AddRef(iface);
1631 return S_OK;
1632 }
1633
1634 *ppvObj = NULL;
1635 return E_NOINTERFACE;
1636 }
1637
1638 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1639 {
1640 return 2; /* non-heap-based object */
1641 }
1642
1643 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1644 {
1645 return 1; /* non-heap-based object */
1646 }
1647
1648 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1649 LPCLASSFACTORY iface,
1650 LPUNKNOWN pUnkOuter,
1651 REFIID riid,
1652 LPVOID *ppvObj)
1653 {
1654 TestClassFactoryImpl *This = impl_from_IClassFactory(iface);
1655 HRESULT hr;
1656 TestFilterImpl *testfilter;
1657
1658 *ppvObj = NULL;
1659
1660 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1661
1662 hr = createtestfilter(This->clsid, This->filterPinData, &testfilter);
1663 if (SUCCEEDED(hr)) {
1664 hr = IBaseFilter_QueryInterface(&testfilter->IBaseFilter_iface, riid, ppvObj);
1665 IBaseFilter_Release(&testfilter->IBaseFilter_iface);
1666 }
1667 return hr;
1668 }
1669
1670 static HRESULT WINAPI Test_IClassFactory_LockServer(
1671 LPCLASSFACTORY iface,
1672 BOOL fLock)
1673 {
1674 return S_OK;
1675 }
1676
1677 static IClassFactoryVtbl TestClassFactory_Vtbl =
1678 {
1679 Test_IClassFactory_QueryInterface,
1680 Test_IClassFactory_AddRef,
1681 Test_IClassFactory_Release,
1682 Test_IClassFactory_CreateInstance,
1683 Test_IClassFactory_LockServer
1684 };
1685
1686 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1687 {
1688 IPin *pin = NULL;
1689 PIN_INFO pinInfo;
1690 FILTER_INFO filterInfo;
1691 HRESULT hr;
1692
1693 FilterName[0] = 0;
1694
1695 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1696 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1697 if (FAILED(hr)) return hr;
1698
1699 hr = IPin_QueryPinInfo(pin, &pinInfo);
1700 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1701 IPin_Release(pin);
1702 if (FAILED(hr)) return hr;
1703
1704 SetLastError(0xdeadbeef);
1705 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1706 if (hr == S_OK && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1707 {
1708 IBaseFilter_Release(pinInfo.pFilter);
1709 return E_NOTIMPL;
1710 }
1711 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1712 IBaseFilter_Release(pinInfo.pFilter);
1713 if (FAILED(hr)) return hr;
1714
1715 IFilterGraph_Release(filterInfo.pGraph);
1716
1717 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1718
1719 return S_OK;
1720 }
1721
1722 static void test_render_filter_priority(void)
1723 {
1724 /* Tests filter choice priorities in Render(). */
1725 DWORD cookie1 = 0, cookie2 = 0, cookie3 = 0;
1726 HRESULT hr;
1727 IFilterGraph2* pgraph2 = NULL;
1728 IFilterMapper2 *pMapper2 = NULL;
1729 TestFilterImpl *ptestfilter = NULL;
1730 TestFilterImpl *ptestfilter2 = NULL;
1731 static const CLSID CLSID_TestFilter2 = {
1732 0x37a4edb0,
1733 0x4d13,
1734 0x11dd,
1735 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1736 };
1737 static const CLSID CLSID_TestFilter3 = {
1738 0x37a4f2d8,
1739 0x4d13,
1740 0x11dd,
1741 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1742 };
1743 static const CLSID CLSID_TestFilter4 = {
1744 0x37a4f3b4,
1745 0x4d13,
1746 0x11dd,
1747 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1748 };
1749 static const GUID mediasubtype1 = {
1750 0x37a4f51c,
1751 0x4d13,
1752 0x11dd,
1753 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1754 };
1755 static const GUID mediasubtype2 = {
1756 0x37a4f5c6,
1757 0x4d13,
1758 0x11dd,
1759 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1760 };
1761 static const TestFilterPinData PinData1[] = {
1762 { PINDIR_OUTPUT, &mediasubtype1 },
1763 { 0, 0 }
1764 };
1765 static const TestFilterPinData PinData2[] = {
1766 { PINDIR_INPUT, &mediasubtype1 },
1767 { 0, 0 }
1768 };
1769 static const TestFilterPinData PinData3[] = {
1770 { PINDIR_INPUT, &GUID_NULL },
1771 { 0, 0 }
1772 };
1773 static const TestFilterPinData PinData4[] = {
1774 { PINDIR_INPUT, &mediasubtype1 },
1775 { PINDIR_OUTPUT, &mediasubtype2 },
1776 { 0, 0 }
1777 };
1778 static const TestFilterPinData PinData5[] = {
1779 { PINDIR_INPUT, &mediasubtype2 },
1780 { 0, 0 }
1781 };
1782 TestClassFactoryImpl Filter1ClassFactory = {
1783 { &TestClassFactory_Vtbl },
1784 PinData2, &CLSID_TestFilter2
1785 };
1786 TestClassFactoryImpl Filter2ClassFactory = {
1787 { &TestClassFactory_Vtbl },
1788 PinData4, &CLSID_TestFilter3
1789 };
1790 TestClassFactoryImpl Filter3ClassFactory = {
1791 { &TestClassFactory_Vtbl },
1792 PinData5, &CLSID_TestFilter4
1793 };
1794 char ConnectedFilterName1[MAX_FILTER_NAME];
1795 char ConnectedFilterName2[MAX_FILTER_NAME];
1796 REGFILTER2 rgf2;
1797 REGFILTERPINS2 rgPins2[2];
1798 REGPINTYPES rgPinType[2];
1799 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1800 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1801 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1802 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1803 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1804 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1805 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1806 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1807
1808 /* Test which renderer of two already added to the graph will be chosen
1809 * (one is "exact" match, other is "wildcard" match. Seems to depend
1810 * on the order in which filters are added to the graph, thus indicating
1811 * no preference given to exact match. */
1812 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1813 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1814 if (!pgraph2) return;
1815
1816 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1817 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1818 if (FAILED(hr)) goto out;
1819
1820 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1821 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1822
1823 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1824 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1825 if (FAILED(hr)) goto out;
1826
1827 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1828 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1829
1830 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1831 ptestfilter2 = NULL;
1832
1833 hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1834 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1835 if (FAILED(hr)) goto out;
1836
1837 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1838 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1839
1840 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1841 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1842
1843 hr = get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1844
1845 IFilterGraph2_Release(pgraph2);
1846 pgraph2 = NULL;
1847 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1848 ptestfilter = NULL;
1849 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1850 ptestfilter2 = NULL;
1851
1852 if (hr == E_NOTIMPL)
1853 {
1854 win_skip("Needed functions are not implemented\n");
1855 return;
1856 }
1857
1858 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1859 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1860 if (!pgraph2) goto out;
1861
1862 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1863 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1864 if (FAILED(hr)) goto out;
1865
1866 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1867 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1868
1869 hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1870 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1871 if (FAILED(hr)) goto out;
1872
1873 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1874 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1875
1876 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1877 ptestfilter2 = NULL;
1878
1879 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1880 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1881 if (FAILED(hr)) goto out;
1882
1883 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1884 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1885
1886 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1887 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1888
1889 hr = IFilterGraph2_Disconnect(pgraph2, NULL);
1890 ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr);
1891
1892 get_connected_filter_name(ptestfilter, ConnectedFilterName2);
1893 ok(strcmp(ConnectedFilterName1, ConnectedFilterName2),
1894 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1895
1896 IFilterGraph2_Release(pgraph2);
1897 pgraph2 = NULL;
1898 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1899 ptestfilter = NULL;
1900 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1901 ptestfilter2 = NULL;
1902
1903 /* Test if any preference is given to existing renderer which renders the pin directly vs
1904 an existing renderer which renders the pin indirectly, through an additional middle filter,
1905 again trying different orders of creation. Native appears not to give a preference. */
1906
1907 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1908 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1909 if (!pgraph2) goto out;
1910
1911 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1912 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1913 if (FAILED(hr)) goto out;
1914
1915 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1916 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1917
1918 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1919 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1920 if (FAILED(hr)) goto out;
1921
1922 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1923 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1924
1925 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1926 ptestfilter2 = NULL;
1927
1928 hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
1929 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1930 if (FAILED(hr)) goto out;
1931
1932 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1933 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1934
1935 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1936 ptestfilter2 = NULL;
1937
1938 hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2);
1939 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1940 if (FAILED(hr)) goto out;
1941
1942 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4);
1943 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1944
1945 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1946 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1947
1948 get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1949 ok(!strcmp(ConnectedFilterName1, "TestfilterInstance3") || !strcmp(ConnectedFilterName1, "TestfilterInstance2"),
1950 "unexpected connected filter: %s\n", ConnectedFilterName1);
1951
1952 IFilterGraph2_Release(pgraph2);
1953 pgraph2 = NULL;
1954 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1955 ptestfilter = NULL;
1956 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1957 ptestfilter2 = NULL;
1958
1959 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1960 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1961 if (!pgraph2) goto out;
1962
1963 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1964 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1965 if (FAILED(hr)) goto out;
1966
1967 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1968 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1969
1970 hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
1971 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1972 if (FAILED(hr)) goto out;
1973
1974 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1975 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1976
1977 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1978 ptestfilter2 = NULL;
1979
1980 hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2);
1981 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1982 if (FAILED(hr)) goto out;
1983
1984 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4);
1985 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1986
1987 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1988 ptestfilter2 = NULL;
1989
1990 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1991 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1992 if (FAILED(hr)) goto out;
1993
1994 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1995 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1996
1997 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1998 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1999
2000 get_connected_filter_name(ptestfilter, ConnectedFilterName2);
2001 ok(!strcmp(ConnectedFilterName2, "TestfilterInstance3") || !strcmp(ConnectedFilterName2, "TestfilterInstance2"),
2002 "unexpected connected filter: %s\n", ConnectedFilterName2);
2003 ok(strcmp(ConnectedFilterName1, ConnectedFilterName2),
2004 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
2005
2006 IFilterGraph2_Release(pgraph2);
2007 pgraph2 = NULL;
2008 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
2009 ptestfilter = NULL;
2010 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
2011 ptestfilter2 = NULL;
2012
2013 /* Test if renderers are tried before non-renderers (intermediary filters). */
2014 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
2015 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
2016 if (!pgraph2) goto out;
2017
2018 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
2019 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
2020 if (!pMapper2) goto out;
2021
2022 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
2023 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
2024 if (FAILED(hr)) goto out;
2025
2026 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
2027 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
2028
2029 /* Register our filters with COM and with Filtermapper. */
2030 hr = CoRegisterClassObject(Filter1ClassFactory.clsid,
2031 (IUnknown *)&Filter1ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
2032 REGCLS_MULTIPLEUSE, &cookie1);
2033 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
2034 if (FAILED(hr)) goto out;
2035 hr = CoRegisterClassObject(Filter2ClassFactory.clsid,
2036 (IUnknown *)&Filter2ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
2037 REGCLS_MULTIPLEUSE, &cookie2);
2038 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
2039 if (FAILED(hr)) goto out;
2040 hr = CoRegisterClassObject(Filter3ClassFactory.clsid,
2041 (IUnknown *)&Filter3ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
2042 REGCLS_MULTIPLEUSE, &cookie3);
2043 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
2044 if (FAILED(hr)) goto out;
2045
2046 rgf2.dwVersion = 2;
2047 rgf2.dwMerit = MERIT_UNLIKELY;
2048 S2(U(rgf2)).cPins2 = 1;
2049 S2(U(rgf2)).rgPins2 = rgPins2;
2050 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
2051 rgPins2[0].cInstances = 1;
2052 rgPins2[0].nMediaTypes = 1;
2053 rgPins2[0].lpMediaType = &rgPinType[0];
2054 rgPins2[0].nMediums = 0;
2055 rgPins2[0].lpMedium = NULL;
2056 rgPins2[0].clsPinCategory = NULL;
2057 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
2058 rgPinType[0].clsMinorType = &mediasubtype1;
2059
2060 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
2061 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
2062 if (hr == E_ACCESSDENIED)
2063 skip("Not authorized to register filters\n");
2064 else
2065 {
2066 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
2067
2068 rgf2.dwMerit = MERIT_PREFERRED;
2069 rgPinType[0].clsMinorType = &mediasubtype2;
2070
2071 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
2072 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
2073 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
2074
2075 S2(U(rgf2)).cPins2 = 2;
2076 rgPins2[0].dwFlags = 0;
2077 rgPinType[0].clsMinorType = &mediasubtype1;
2078
2079 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
2080 rgPins2[1].cInstances = 1;
2081 rgPins2[1].nMediaTypes = 1;
2082 rgPins2[1].lpMediaType = &rgPinType[1];
2083 rgPins2[1].nMediums = 0;
2084 rgPins2[1].lpMedium = NULL;
2085 rgPins2[1].clsPinCategory = NULL;
2086 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
2087 rgPinType[1].clsMinorType = &mediasubtype2;
2088
2089 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
2090 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
2091 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
2092
2093 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
2094 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
2095
2096 get_connected_filter_name(ptestfilter, ConnectedFilterName1);
2097 ok(!strcmp(ConnectedFilterName1, "TestfilterInstance3"),
2098 "unexpected connected filter: %s\n", ConnectedFilterName1);
2099
2100 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
2101 &CLSID_TestFilter2);
2102 ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
2103 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
2104 &CLSID_TestFilter3);
2105 ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
2106 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
2107 &CLSID_TestFilter4);
2108 ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
2109 }
2110
2111 out:
2112
2113 if (ptestfilter) IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
2114 if (ptestfilter2) IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
2115 if (pgraph2) IFilterGraph2_Release(pgraph2);
2116 if (pMapper2) IFilterMapper2_Release(pMapper2);
2117
2118 hr = CoRevokeClassObject(cookie1);
2119 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
2120 hr = CoRevokeClassObject(cookie2);
2121 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
2122 hr = CoRevokeClassObject(cookie3);
2123 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
2124 }
2125
2126 typedef struct IUnknownImpl
2127 {
2128 IUnknown IUnknown_iface;
2129 int AddRef_called;
2130 int Release_called;
2131 } IUnknownImpl;
2132
2133 static IUnknownImpl *IUnknownImpl_from_iface(IUnknown * iface)
2134 {
2135 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
2136 }
2137
2138 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
2139 {
2140 ok(0, "QueryInterface should not be called for %s\n", wine_dbgstr_guid(riid));
2141 return E_NOINTERFACE;
2142 }
2143
2144 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown * iface)
2145 {
2146 IUnknownImpl *This = IUnknownImpl_from_iface(iface);
2147 This->AddRef_called++;
2148 return 2;
2149 }
2150
2151 static ULONG WINAPI IUnknownImpl_Release(IUnknown * iface)
2152 {
2153 IUnknownImpl *This = IUnknownImpl_from_iface(iface);
2154 This->Release_called++;
2155 return 1;
2156 }
2157
2158 static CONST_VTBL IUnknownVtbl IUnknownImpl_Vtbl =
2159 {
2160 IUnknownImpl_QueryInterface,
2161 IUnknownImpl_AddRef,
2162 IUnknownImpl_Release
2163 };
2164
2165 static void test_aggregate_filter_graph(void)
2166 {
2167 HRESULT hr;
2168 IUnknown *pgraph;
2169 IUnknown *punk;
2170 IUnknownImpl unk_outer = { { &IUnknownImpl_Vtbl }, 0, 0 };
2171
2172 hr = CoCreateInstance(&CLSID_FilterGraph, &unk_outer.IUnknown_iface, CLSCTX_INPROC_SERVER,
2173 &IID_IUnknown, (void **)&pgraph);
2174 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
2175 ok(pgraph != &unk_outer.IUnknown_iface, "pgraph = %p, expected not %p\n", pgraph, &unk_outer.IUnknown_iface);
2176
2177 hr = IUnknown_QueryInterface(pgraph, &IID_IUnknown, (void **)&punk);
2178 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
2179 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
2180 IUnknown_Release(punk);
2181
2182 ok(unk_outer.AddRef_called == 0, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
2183 ok(unk_outer.Release_called == 0, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
2184 unk_outer.AddRef_called = 0;
2185 unk_outer.Release_called = 0;
2186
2187 hr = IUnknown_QueryInterface(pgraph, &IID_IFilterMapper, (void **)&punk);
2188 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
2189 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
2190 IUnknown_Release(punk);
2191
2192 ok(unk_outer.AddRef_called == 1, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
2193 ok(unk_outer.Release_called == 1, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
2194 unk_outer.AddRef_called = 0;
2195 unk_outer.Release_called = 0;
2196
2197 hr = IUnknown_QueryInterface(pgraph, &IID_IFilterMapper2, (void **)&punk);
2198 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
2199 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
2200 IUnknown_Release(punk);
2201
2202 ok(unk_outer.AddRef_called == 1, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
2203 ok(unk_outer.Release_called == 1, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
2204 unk_outer.AddRef_called = 0;
2205 unk_outer.Release_called = 0;
2206
2207 hr = IUnknown_QueryInterface(pgraph, &IID_IFilterMapper3, (void **)&punk);
2208 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
2209 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
2210 IUnknown_Release(punk);
2211
2212 ok(unk_outer.AddRef_called == 1, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
2213 ok(unk_outer.Release_called == 1, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
2214
2215 IUnknown_Release(pgraph);
2216 }
2217
2218 START_TEST(filtergraph)
2219 {
2220 HRESULT hr;
2221 CoInitializeEx(NULL, COINIT_MULTITHREADED);
2222 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
2223 &IID_IGraphBuilder, (LPVOID*)&pgraph);
2224 if (FAILED(hr)) {
2225 skip("Creating filtergraph returned %08x, skipping tests\n", hr);
2226 return;
2227 }
2228 IGraphBuilder_Release(pgraph);
2229 test_render_run(avifile);
2230 test_render_run(mpegfile);
2231 test_graph_builder();
2232 test_graph_builder_addfilter();
2233 test_mediacontrol();
2234 test_filter_graph2();
2235 test_render_filter_priority();
2236 test_aggregate_filter_graph();
2237 CoUninitialize();
2238 }