[QUARTZ]
[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 #include <assert.h>
23
24 #define COBJMACROS
25
26 #include "wine/test.h"
27 #include "dshow.h"
28 #include "control.h"
29
30 #define FILE_LEN 9
31 static const char avifileA[FILE_LEN] = "test.avi";
32 static const char mpegfileA[FILE_LEN] = "test.mpg";
33
34 IGraphBuilder* pgraph;
35
36 static int createfiltergraph(void)
37 {
38 return S_OK == CoCreateInstance(
39 &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&pgraph);
40 }
41
42 static void renderfile(const char * fileA)
43 {
44 HRESULT hr;
45 WCHAR fileW[FILE_LEN];
46
47 MultiByteToWideChar(CP_ACP, 0, fileA, -1, fileW, FILE_LEN);
48
49 hr = IGraphBuilder_RenderFile(pgraph, fileW, NULL);
50 ok(hr==S_OK, "RenderFile returned: %x\n", hr);
51 }
52
53 static void rungraph(void)
54 {
55 HRESULT hr;
56 IMediaControl* pmc;
57 IMediaEvent* pme;
58 IMediaFilter* pmf;
59 HANDLE hEvent;
60
61 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (LPVOID*)&pmc);
62 ok(hr==S_OK, "Cannot get IMediaControl interface returned: %x\n", hr);
63
64 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (LPVOID*)&pmf);
65 ok(hr==S_OK, "Cannot get IMediaFilter interface returned: %x\n", hr);
66
67 IMediaControl_Stop(pmc);
68
69 IMediaFilter_SetSyncSource(pmf, NULL);
70
71 IMediaFilter_Release(pmf);
72
73 hr = IMediaControl_Run(pmc);
74 ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr);
75
76 Sleep(10);
77 /* Crash fun */
78 trace("run -> stop\n");
79 hr = IMediaControl_Stop(pmc);
80 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
81
82 IGraphBuilder_SetDefaultSyncSource(pgraph);
83
84 Sleep(10);
85 trace("stop -> pause\n");
86 hr = IMediaControl_Pause(pmc);
87 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
88
89 Sleep(10);
90 trace("pause -> run\n");
91 hr = IMediaControl_Run(pmc);
92 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
93
94 Sleep(10);
95 trace("run -> pause\n");
96 hr = IMediaControl_Pause(pmc);
97 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
98
99 Sleep(10);
100 trace("pause -> stop\n");
101 hr = IMediaControl_Stop(pmc);
102 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
103
104 Sleep(10);
105 trace("pause -> run\n");
106 hr = IMediaControl_Run(pmc);
107 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
108
109 trace("run -> stop\n");
110 hr = IMediaControl_Stop(pmc);
111 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
112
113 trace("stop -> run\n");
114 hr = IMediaControl_Run(pmc);
115 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
116
117 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaEvent, (LPVOID*)&pme);
118 ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr);
119
120 hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent);
121 ok(hr==S_OK, "Cannot get event handle returned: %x\n", hr);
122
123 /* WaitForSingleObject(hEvent, INFINITE); */
124 Sleep(20000);
125
126 hr = IMediaEvent_Release(pme);
127 ok(hr==2, "Releasing mediaevent returned: %x\n", hr);
128
129 hr = IMediaControl_Stop(pmc);
130 ok(hr==S_OK, "Cannot stop the graph returned: %x\n", hr);
131
132 hr = IMediaControl_Release(pmc);
133 ok(hr==1, "Releasing mediacontrol returned: %x\n", hr);
134 }
135
136 static void releasefiltergraph(void)
137 {
138 HRESULT hr;
139
140 hr = IGraphBuilder_Release(pgraph);
141 ok(hr==0, "Releasing filtergraph returned: %x\n", hr);
142 }
143
144 static void test_render_run(const char * fileA)
145 {
146 HANDLE h;
147
148 if (!createfiltergraph())
149 return;
150
151 h = CreateFileA(fileA, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
152 if (h != INVALID_HANDLE_VALUE) {
153 CloseHandle(h);
154 renderfile(fileA);
155 rungraph();
156 }
157
158 releasefiltergraph();
159 }
160
161 static void test_graph_builder(void)
162 {
163 HRESULT hr;
164 IBaseFilter *pF = NULL;
165 IBaseFilter *pF2 = NULL;
166 IPin *pIn = NULL;
167 IEnumPins *pEnum = NULL;
168 PIN_DIRECTION dir;
169 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
170 static const WCHAR fooBarW[] = {'f','o','o','B','a','r',0};
171
172 if (!createfiltergraph())
173 return;
174
175 /* create video filter */
176 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
177 &IID_IBaseFilter, (LPVOID*)&pF);
178 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
179 ok(pF != NULL, "pF is NULL\n");
180
181 /* add the two filters to the graph */
182 hr = IGraphBuilder_AddFilter(pgraph, pF, testFilterW);
183 ok(hr == S_OK, "failed to add pF to the graph: %x\n", hr);
184
185 /* find the pins */
186 hr = IBaseFilter_EnumPins(pF, &pEnum);
187 ok(hr == S_OK, "IBaseFilter_EnumPins failed for pF: %x\n", hr);
188 ok(pEnum != NULL, "pEnum is NULL\n");
189 hr = IEnumPins_Next(pEnum, 1, &pIn, NULL);
190 ok(hr == S_OK, "IEnumPins_Next failed for pF: %x\n", hr);
191 ok(pIn != NULL, "pIn is NULL\n");
192 hr = IPin_QueryDirection(pIn, &dir);
193 ok(hr == S_OK, "IPin_QueryDirection failed: %x\n", hr);
194 ok(dir == PINDIR_INPUT, "pin has wrong direction\n");
195
196 hr = IGraphBuilder_FindFilterByName(pgraph, fooBarW, &pF2);
197 ok(hr == VFW_E_NOT_FOUND, "IGraphBuilder_FindFilterByName returned %x\n", hr);
198 ok(pF2 == NULL, "IGraphBuilder_FindFilterByName returned %p\n", pF2);
199 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, &pF2);
200 ok(hr == S_OK, "IGraphBuilder_FindFilterByName returned %x\n", hr);
201 ok(pF2 != NULL, "IGraphBuilder_FindFilterByName returned NULL\n");
202 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, NULL);
203 ok(hr == E_POINTER, "IGraphBuilder_FindFilterByName returned %x\n", hr);
204
205 if (pIn) IPin_Release(pIn);
206 if (pEnum) IEnumPins_Release(pEnum);
207 if (pF) IBaseFilter_Release(pF);
208 if (pF2) IBaseFilter_Release(pF2);
209
210 releasefiltergraph();
211 }
212
213 static void test_graph_builder_addfilter(void)
214 {
215 HRESULT hr;
216 IBaseFilter *pF = NULL;
217 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
218
219 if (!createfiltergraph())
220 return;
221
222 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
223 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr);
224
225 /* create video filter */
226 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
227 &IID_IBaseFilter, (LPVOID*)&pF);
228 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
229 ok(pF != NULL, "pF is NULL\n");
230 if (!pF) {
231 skip("failed to created filter, skipping\n");
232 return;
233 }
234
235 hr = IGraphBuilder_AddFilter(pgraph, pF, NULL);
236 ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr);
237 IMediaFilter_Release(pF);
238 }
239
240 static void test_mediacontrol(void)
241 {
242 HRESULT hr;
243 LONGLONG pos = 0xdeadbeef;
244 IMediaSeeking *seeking = NULL;
245 IMediaFilter *filter = NULL;
246 IMediaControl *control = NULL;
247
248 IFilterGraph2_SetDefaultSyncSource(pgraph);
249 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking);
250 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
251 if (FAILED(hr))
252 return;
253
254 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
255 ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
256 if (FAILED(hr))
257 {
258 IUnknown_Release(seeking);
259 return;
260 }
261
262 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
263 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
264 if (FAILED(hr))
265 {
266 IUnknown_Release(seeking);
267 IUnknown_Release(filter);
268 return;
269 }
270
271 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
272 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
273 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
274
275 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_ReturnTime, NULL, AM_SEEKING_NoPositioning);
276 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
277 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_NoPositioning, NULL, AM_SEEKING_ReturnTime);
278 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
279
280 IMediaFilter_SetSyncSource(filter, NULL);
281 pos = 0xdeadbeef;
282 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
283 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
284 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
285
286 hr = IMediaControl_GetState(control, 1000, NULL);
287 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
288
289 IUnknown_Release(control);
290 IUnknown_Release(seeking);
291 IUnknown_Release(filter);
292 releasefiltergraph();
293 }
294
295 static void test_filter_graph2(void)
296 {
297 HRESULT hr;
298 IFilterGraph2 *pF = NULL;
299
300 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
301 &IID_IFilterGraph2, (LPVOID*)&pF);
302 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
303 ok(pF != NULL, "pF is NULL\n");
304
305 hr = IFilterGraph2_Release(pF);
306 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
307 }
308
309 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
310 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
311 {
312 if (pMediaType->pbFormat)
313 {
314 CoTaskMemFree(pMediaType->pbFormat);
315 pMediaType->pbFormat = NULL;
316 }
317 if (pMediaType->pUnk)
318 {
319 IUnknown_Release(pMediaType->pUnk);
320 pMediaType->pUnk = NULL;
321 }
322 }
323
324 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
325 {
326 *pDest = *pSrc;
327 if (!pSrc->pbFormat) return S_OK;
328 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
329 return E_OUTOFMEMORY;
330 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
331 if (pDest->pUnk)
332 IUnknown_AddRef(pDest->pUnk);
333 return S_OK;
334 }
335
336 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
337 {
338 AM_MEDIA_TYPE * pDest;
339
340 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
341 if (!pDest)
342 return NULL;
343
344 if (FAILED(CopyMediaType(pDest, pSrc)))
345 {
346 CoTaskMemFree(pDest);
347 return NULL;
348 }
349
350 return pDest;
351 }
352
353 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
354 {
355 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
356 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
357 }
358
359 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
360 {
361 FreeMediaType(pMediaType);
362 CoTaskMemFree(pMediaType);
363 }
364
365 typedef struct IEnumMediaTypesImpl
366 {
367 const IEnumMediaTypesVtbl * lpVtbl;
368 LONG refCount;
369 AM_MEDIA_TYPE *pMediaTypes;
370 ULONG cMediaTypes;
371 ULONG uIndex;
372 } IEnumMediaTypesImpl;
373
374 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
375
376 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
377 {
378 ULONG i;
379 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
380
381 if (!pEnumMediaTypes)
382 {
383 *ppEnum = NULL;
384 return E_OUTOFMEMORY;
385 }
386 pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl;
387 pEnumMediaTypes->refCount = 1;
388 pEnumMediaTypes->uIndex = 0;
389 pEnumMediaTypes->cMediaTypes = cMediaTypes;
390 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
391 for (i = 0; i < cMediaTypes; i++)
392 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
393 {
394 while (i--)
395 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
396 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
397 return E_OUTOFMEMORY;
398 }
399 *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl);
400 return S_OK;
401 }
402
403 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
404 {
405 *ppv = NULL;
406
407 if (IsEqualIID(riid, &IID_IUnknown))
408 *ppv = iface;
409 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
410 *ppv = iface;
411
412 if (*ppv)
413 {
414 IUnknown_AddRef((IUnknown *)(*ppv));
415 return S_OK;
416 }
417
418 return E_NOINTERFACE;
419 }
420
421 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
422 {
423 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
424 ULONG refCount = InterlockedIncrement(&This->refCount);
425
426 return refCount;
427 }
428
429 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
430 {
431 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
432 ULONG refCount = InterlockedDecrement(&This->refCount);
433
434 if (!refCount)
435 {
436 int i;
437 for (i = 0; i < This->cMediaTypes; i++)
438 FreeMediaType(&This->pMediaTypes[i]);
439 CoTaskMemFree(This->pMediaTypes);
440 CoTaskMemFree(This);
441 }
442 return refCount;
443 }
444
445 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
446 {
447 ULONG cFetched;
448 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
449
450 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
451
452 if (cFetched > 0)
453 {
454 ULONG i;
455 for (i = 0; i < cFetched; i++)
456 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
457 {
458 while (i--)
459 DeleteMediaType(ppMediaTypes[i]);
460 *pcFetched = 0;
461 return E_OUTOFMEMORY;
462 }
463 }
464
465 if ((cMediaTypes != 1) || pcFetched)
466 *pcFetched = cFetched;
467
468 This->uIndex += cFetched;
469
470 if (cFetched != cMediaTypes)
471 return S_FALSE;
472 return S_OK;
473 }
474
475 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
476 {
477 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
478
479 if (This->uIndex + cMediaTypes < This->cMediaTypes)
480 {
481 This->uIndex += cMediaTypes;
482 return S_OK;
483 }
484 return S_FALSE;
485 }
486
487 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
488 {
489 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
490
491 This->uIndex = 0;
492 return S_OK;
493 }
494
495 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
496 {
497 HRESULT hr;
498 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
499
500 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
501 if (FAILED(hr))
502 return hr;
503 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
504 }
505
506 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
507 {
508 IEnumMediaTypesImpl_QueryInterface,
509 IEnumMediaTypesImpl_AddRef,
510 IEnumMediaTypesImpl_Release,
511 IEnumMediaTypesImpl_Next,
512 IEnumMediaTypesImpl_Skip,
513 IEnumMediaTypesImpl_Reset,
514 IEnumMediaTypesImpl_Clone
515 };
516
517 /* Implementation of a very stripped down pin for the test filter. Just enough
518 functionality for connecting and Render() to work. */
519
520 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
521 {
522 lstrcpyW(pDest->achName, pSrc->achName);
523 pDest->dir = pSrc->dir;
524 pDest->pFilter = pSrc->pFilter;
525 }
526
527 typedef struct ITestPinImpl
528 {
529 const struct IPinVtbl * lpVtbl;
530 LONG refCount;
531 LPCRITICAL_SECTION pCritSec;
532 PIN_INFO pinInfo;
533 IPin * pConnectedTo;
534 AM_MEDIA_TYPE mtCurrent;
535 LPVOID pUserData;
536 } ITestPinImpl;
537
538 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
539 {
540 *ppv = NULL;
541
542 if (IsEqualIID(riid, &IID_IUnknown))
543 *ppv = iface;
544 else if (IsEqualIID(riid, &IID_IPin))
545 *ppv = iface;
546
547 if (*ppv)
548 {
549 IUnknown_AddRef((IUnknown *)(*ppv));
550 return S_OK;
551 }
552
553 return E_NOINTERFACE;
554 }
555
556 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
557 {
558 ITestPinImpl *This = (ITestPinImpl *)iface;
559 ULONG refCount = InterlockedIncrement(&This->refCount);
560 return refCount;
561 }
562
563 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
564 {
565 ITestPinImpl *This = (ITestPinImpl *)iface;
566 ULONG refCount = InterlockedDecrement(&This->refCount);
567
568 if (!refCount)
569 {
570 FreeMediaType(&This->mtCurrent);
571 This->lpVtbl = NULL;
572 CoTaskMemFree(This);
573 return 0;
574 }
575 else
576 return refCount;
577 }
578
579 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
580 {
581 return E_UNEXPECTED;
582 }
583
584 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
585 {
586 ITestPinImpl *This = (ITestPinImpl *)iface;
587 PIN_DIRECTION pindirReceive;
588 HRESULT hr = S_OK;
589
590 EnterCriticalSection(This->pCritSec);
591 {
592 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
593 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
594 hr = VFW_E_TYPE_NOT_ACCEPTED;
595
596 if (This->pConnectedTo)
597 hr = VFW_E_ALREADY_CONNECTED;
598
599 if (SUCCEEDED(hr))
600 {
601 IPin_QueryDirection(pReceivePin, &pindirReceive);
602
603 if (pindirReceive != PINDIR_OUTPUT)
604 {
605 hr = VFW_E_INVALID_DIRECTION;
606 }
607 }
608
609 if (SUCCEEDED(hr))
610 {
611 CopyMediaType(&This->mtCurrent, pmt);
612 This->pConnectedTo = pReceivePin;
613 IPin_AddRef(pReceivePin);
614 }
615 }
616 LeaveCriticalSection(This->pCritSec);
617
618 return hr;
619 }
620
621 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
622 {
623 HRESULT hr;
624 ITestPinImpl *This = (ITestPinImpl *)iface;
625
626 EnterCriticalSection(This->pCritSec);
627 {
628 if (This->pConnectedTo)
629 {
630 IPin_Release(This->pConnectedTo);
631 This->pConnectedTo = NULL;
632 hr = S_OK;
633 }
634 else
635 hr = S_FALSE;
636 }
637 LeaveCriticalSection(This->pCritSec);
638
639 return hr;
640 }
641
642 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
643 {
644 HRESULT hr;
645 ITestPinImpl *This = (ITestPinImpl *)iface;
646
647 EnterCriticalSection(This->pCritSec);
648 {
649 if (This->pConnectedTo)
650 {
651 *ppPin = This->pConnectedTo;
652 IPin_AddRef(*ppPin);
653 hr = S_OK;
654 }
655 else
656 {
657 hr = VFW_E_NOT_CONNECTED;
658 *ppPin = NULL;
659 }
660 }
661 LeaveCriticalSection(This->pCritSec);
662
663 return hr;
664 }
665
666 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
667 {
668 HRESULT hr;
669 ITestPinImpl *This = (ITestPinImpl *)iface;
670
671 EnterCriticalSection(This->pCritSec);
672 {
673 if (This->pConnectedTo)
674 {
675 CopyMediaType(pmt, &This->mtCurrent);
676 hr = S_OK;
677 }
678 else
679 {
680 ZeroMemory(pmt, sizeof(*pmt));
681 hr = VFW_E_NOT_CONNECTED;
682 }
683 }
684 LeaveCriticalSection(This->pCritSec);
685
686 return hr;
687 }
688
689 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
690 {
691 ITestPinImpl *This = (ITestPinImpl *)iface;
692
693 Copy_PinInfo(pInfo, &This->pinInfo);
694 IBaseFilter_AddRef(pInfo->pFilter);
695
696 return S_OK;
697 }
698
699 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
700 {
701 ITestPinImpl *This = (ITestPinImpl *)iface;
702
703 *pPinDir = This->pinInfo.dir;
704
705 return S_OK;
706 }
707
708 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
709 {
710 return E_NOTIMPL;
711 }
712
713 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
714 {
715 ITestPinImpl *This = (ITestPinImpl *)iface;
716
717 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
718 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
719 return S_OK;
720 else
721 return VFW_E_TYPE_NOT_ACCEPTED;
722 }
723
724 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
725 {
726 ITestPinImpl *This = (ITestPinImpl *)iface;
727
728 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
729 }
730
731 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
732 {
733 return E_NOTIMPL;
734 }
735
736 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
737 {
738 return E_NOTIMPL;
739 }
740
741 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
742 {
743 return E_NOTIMPL;
744 }
745
746 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
747 {
748 return E_NOTIMPL;
749 }
750
751 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
752 {
753 return E_NOTIMPL;
754 }
755
756 static const IPinVtbl TestFilter_InputPin_Vtbl =
757 {
758 TestFilter_Pin_QueryInterface,
759 TestFilter_Pin_AddRef,
760 TestFilter_Pin_Release,
761 TestFilter_InputPin_Connect,
762 TestFilter_InputPin_ReceiveConnection,
763 TestFilter_Pin_Disconnect,
764 TestFilter_Pin_ConnectedTo,
765 TestFilter_Pin_ConnectionMediaType,
766 TestFilter_Pin_QueryPinInfo,
767 TestFilter_Pin_QueryDirection,
768 TestFilter_Pin_QueryId,
769 TestFilter_Pin_QueryAccept,
770 TestFilter_Pin_EnumMediaTypes,
771 TestFilter_Pin_QueryInternalConnections,
772 TestFilter_Pin_EndOfStream,
773 TestFilter_Pin_BeginFlush,
774 TestFilter_Pin_EndFlush,
775 TestFilter_Pin_NewSegment
776 };
777
778 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
779 {
780 return E_UNEXPECTED;
781 }
782
783 /* Private helper function */
784 static HRESULT TestFilter_OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
785 {
786 ITestPinImpl *This = (ITestPinImpl *)iface;
787 HRESULT hr;
788
789 This->pConnectedTo = pReceivePin;
790 IPin_AddRef(pReceivePin);
791
792 hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
793
794 if (FAILED(hr))
795 {
796 IPin_Release(This->pConnectedTo);
797 This->pConnectedTo = NULL;
798 }
799
800 return hr;
801 }
802
803 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
804 {
805 ITestPinImpl *This = (ITestPinImpl *)iface;
806 HRESULT hr;
807
808 EnterCriticalSection(This->pCritSec);
809 {
810 /* if we have been a specific type to connect with, then we can either connect
811 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
812 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
813 hr = TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, pmt);
814 else
815 {
816 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
817 (TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, &This->mtCurrent) == S_OK))
818 hr = S_OK;
819 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
820 } /* if negotiate media type */
821 } /* if succeeded */
822 LeaveCriticalSection(This->pCritSec);
823
824 return hr;
825 }
826
827 static const IPinVtbl TestFilter_OutputPin_Vtbl =
828 {
829 TestFilter_Pin_QueryInterface,
830 TestFilter_Pin_AddRef,
831 TestFilter_Pin_Release,
832 TestFilter_OutputPin_Connect,
833 TestFilter_OutputPin_ReceiveConnection,
834 TestFilter_Pin_Disconnect,
835 TestFilter_Pin_ConnectedTo,
836 TestFilter_Pin_ConnectionMediaType,
837 TestFilter_Pin_QueryPinInfo,
838 TestFilter_Pin_QueryDirection,
839 TestFilter_Pin_QueryId,
840 TestFilter_Pin_QueryAccept,
841 TestFilter_Pin_EnumMediaTypes,
842 TestFilter_Pin_QueryInternalConnections,
843 TestFilter_Pin_EndOfStream,
844 TestFilter_Pin_BeginFlush,
845 TestFilter_Pin_EndFlush,
846 TestFilter_Pin_NewSegment
847 };
848
849 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
850 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
851 {
852 ITestPinImpl * pPinImpl;
853
854 *ppPin = NULL;
855
856 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
857
858 if (!pPinImpl)
859 return E_OUTOFMEMORY;
860
861 pPinImpl->refCount = 1;
862 pPinImpl->pConnectedTo = NULL;
863 pPinImpl->pCritSec = pCritSec;
864 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
865 pPinImpl->mtCurrent = *pinmt;
866
867 pPinImpl->lpVtbl = Pin_Vtbl;
868
869 *ppPin = (IPin *)pPinImpl;
870 return S_OK;
871 }
872
873 /* IEnumPins implementation */
874
875 typedef HRESULT (* FNOBTAINPIN)(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick);
876
877 typedef struct IEnumPinsImpl
878 {
879 const IEnumPinsVtbl * lpVtbl;
880 LONG refCount;
881 ULONG uIndex;
882 IBaseFilter *base;
883 FNOBTAINPIN receive_pin;
884 DWORD synctime;
885 } IEnumPinsImpl;
886
887 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
888
889 static HRESULT IEnumPinsImpl_Construct(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, IBaseFilter *base)
890 {
891 IEnumPinsImpl * pEnumPins;
892
893 if (!ppEnum)
894 return E_POINTER;
895
896 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
897 if (!pEnumPins)
898 {
899 *ppEnum = NULL;
900 return E_OUTOFMEMORY;
901 }
902 pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl;
903 pEnumPins->refCount = 1;
904 pEnumPins->uIndex = 0;
905 pEnumPins->receive_pin = receive_pin;
906 pEnumPins->base = base;
907 IBaseFilter_AddRef(base);
908 *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl);
909
910 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
911
912 return S_OK;
913 }
914
915 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
916 {
917 *ppv = NULL;
918
919 if (IsEqualIID(riid, &IID_IUnknown))
920 *ppv = iface;
921 else if (IsEqualIID(riid, &IID_IEnumPins))
922 *ppv = iface;
923
924 if (*ppv)
925 {
926 IUnknown_AddRef((IUnknown *)(*ppv));
927 return S_OK;
928 }
929
930 return E_NOINTERFACE;
931 }
932
933 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
934 {
935 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
936 ULONG refCount = InterlockedIncrement(&This->refCount);
937
938 return refCount;
939 }
940
941 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
942 {
943 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
944 ULONG refCount = InterlockedDecrement(&This->refCount);
945
946 if (!refCount)
947 {
948 IBaseFilter_Release(This->base);
949 CoTaskMemFree(This);
950 return 0;
951 }
952 else
953 return refCount;
954 }
955
956 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
957 {
958 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
959 DWORD synctime = This->synctime;
960 HRESULT hr = S_OK;
961 ULONG i = 0;
962
963 if (!ppPins)
964 return E_POINTER;
965
966 if (cPins > 1 && !pcFetched)
967 return E_INVALIDARG;
968
969 if (pcFetched)
970 *pcFetched = 0;
971
972 while (i < cPins && hr == S_OK)
973 {
974 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
975
976 if (hr == S_OK)
977 ++i;
978
979 if (synctime != This->synctime)
980 break;
981 }
982
983 if (!i && synctime != This->synctime)
984 return VFW_E_ENUM_OUT_OF_SYNC;
985
986 if (pcFetched)
987 *pcFetched = i;
988 This->uIndex += i;
989
990 if (i < cPins)
991 return S_FALSE;
992 return S_OK;
993 }
994
995 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
996 {
997 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
998 DWORD synctime = This->synctime;
999 HRESULT hr;
1000 IPin *pin = NULL;
1001
1002 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
1003 if (pin)
1004 IPin_Release(pin);
1005
1006 if (synctime != This->synctime)
1007 return VFW_E_ENUM_OUT_OF_SYNC;
1008
1009 if (hr == S_OK)
1010 This->uIndex += cPins;
1011
1012 return hr;
1013 }
1014
1015 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1016 {
1017 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1018
1019 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1020
1021 This->uIndex = 0;
1022 return S_OK;
1023 }
1024
1025 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1026 {
1027 HRESULT hr;
1028 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1029
1030 hr = IEnumPinsImpl_Construct(ppEnum, This->receive_pin, This->base);
1031 if (FAILED(hr))
1032 return hr;
1033 return IEnumPins_Skip(*ppEnum, This->uIndex);
1034 }
1035
1036 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1037 {
1038 IEnumPinsImpl_QueryInterface,
1039 IEnumPinsImpl_AddRef,
1040 IEnumPinsImpl_Release,
1041 IEnumPinsImpl_Next,
1042 IEnumPinsImpl_Skip,
1043 IEnumPinsImpl_Reset,
1044 IEnumPinsImpl_Clone
1045 };
1046
1047 /* Test filter implementation - a filter that has few predefined pins with single media type
1048 * that accept only this single media type. Enough for Render(). */
1049
1050 typedef struct TestFilterPinData
1051 {
1052 PIN_DIRECTION pinDir;
1053 const GUID *mediasubtype;
1054 } TestFilterPinData;
1055
1056 typedef struct TestFilterImpl
1057 {
1058 const IBaseFilterVtbl * lpVtbl;
1059
1060 LONG refCount;
1061 CRITICAL_SECTION csFilter;
1062 FILTER_STATE state;
1063 FILTER_INFO filterInfo;
1064 CLSID clsid;
1065 IPin ** ppPins;
1066 UINT nPins;
1067 } TestFilterImpl;
1068
1069 static const IBaseFilterVtbl TestFilter_Vtbl;
1070
1071 static HRESULT TestFilter_Create(const CLSID* pClsid, const TestFilterPinData *pinData, LPVOID * ppv)
1072 {
1073 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1074 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1075 HRESULT hr;
1076 PIN_INFO pinInfo;
1077 TestFilterImpl* pTestFilter = NULL;
1078 UINT nPins, i;
1079 AM_MEDIA_TYPE mt;
1080
1081 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1082 if (!pTestFilter) return E_OUTOFMEMORY;
1083
1084 pTestFilter->clsid = *pClsid;
1085 pTestFilter->lpVtbl = &TestFilter_Vtbl;
1086 pTestFilter->refCount = 1;
1087 InitializeCriticalSection(&pTestFilter->csFilter);
1088 pTestFilter->state = State_Stopped;
1089
1090 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1091
1092 nPins = 0;
1093 while(pinData[nPins].mediasubtype) ++nPins;
1094
1095 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1096 if (!pTestFilter->ppPins)
1097 {
1098 hr = E_OUTOFMEMORY;
1099 goto error;
1100 }
1101 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1102
1103 for (i = 0; i < nPins; i++)
1104 {
1105 ZeroMemory(&mt, sizeof(mt));
1106 mt.majortype = MEDIATYPE_Video;
1107 mt.formattype = FORMAT_None;
1108 mt.subtype = *pinData[i].mediasubtype;
1109
1110 pinInfo.dir = pinData[i].pinDir;
1111 pinInfo.pFilter = (IBaseFilter *)pTestFilter;
1112 if (pinInfo.dir == PINDIR_INPUT)
1113 {
1114 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1115 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1116 &pTestFilter->ppPins[i]);
1117
1118 }
1119 else
1120 {
1121 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1122 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1123 &pTestFilter->ppPins[i]);
1124 }
1125 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1126 }
1127
1128 pTestFilter->nPins = nPins;
1129 *ppv = pTestFilter;
1130 return S_OK;
1131
1132 error:
1133
1134 if (pTestFilter->ppPins)
1135 {
1136 for (i = 0; i < nPins; i++)
1137 {
1138 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1139 }
1140 }
1141 CoTaskMemFree(pTestFilter->ppPins);
1142 DeleteCriticalSection(&pTestFilter->csFilter);
1143 CoTaskMemFree(pTestFilter);
1144
1145 return hr;
1146 }
1147
1148 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1149 {
1150 TestFilterImpl *This = (TestFilterImpl *)iface;
1151
1152 *ppv = NULL;
1153
1154 if (IsEqualIID(riid, &IID_IUnknown))
1155 *ppv = This;
1156 else if (IsEqualIID(riid, &IID_IPersist))
1157 *ppv = This;
1158 else if (IsEqualIID(riid, &IID_IMediaFilter))
1159 *ppv = This;
1160 else if (IsEqualIID(riid, &IID_IBaseFilter))
1161 *ppv = This;
1162
1163 if (*ppv)
1164 {
1165 IUnknown_AddRef((IUnknown *)(*ppv));
1166 return S_OK;
1167 }
1168
1169 return E_NOINTERFACE;
1170 }
1171
1172 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1173 {
1174 TestFilterImpl *This = (TestFilterImpl *)iface;
1175 ULONG refCount = InterlockedIncrement(&This->refCount);
1176
1177 return refCount;
1178 }
1179
1180 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1181 {
1182 TestFilterImpl *This = (TestFilterImpl *)iface;
1183 ULONG refCount = InterlockedDecrement(&This->refCount);
1184
1185 if (!refCount)
1186 {
1187 ULONG i;
1188
1189 for (i = 0; i < This->nPins; i++)
1190 {
1191 IPin *pConnectedTo;
1192
1193 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1194 {
1195 IPin_Disconnect(pConnectedTo);
1196 IPin_Release(pConnectedTo);
1197 }
1198 IPin_Disconnect(This->ppPins[i]);
1199
1200 IPin_Release(This->ppPins[i]);
1201 }
1202
1203 CoTaskMemFree(This->ppPins);
1204 This->lpVtbl = NULL;
1205
1206 DeleteCriticalSection(&This->csFilter);
1207
1208 CoTaskMemFree(This);
1209
1210 return 0;
1211 }
1212 else
1213 return refCount;
1214 }
1215 /** IPersist methods **/
1216
1217 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1218 {
1219 TestFilterImpl *This = (TestFilterImpl *)iface;
1220
1221 *pClsid = This->clsid;
1222
1223 return S_OK;
1224 }
1225
1226 /** IMediaFilter methods **/
1227
1228 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1229 {
1230 return E_NOTIMPL;
1231 }
1232
1233 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1234 {
1235 return E_NOTIMPL;
1236 }
1237
1238 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1239 {
1240 return E_NOTIMPL;
1241 }
1242
1243 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1244 {
1245 TestFilterImpl *This = (TestFilterImpl *)iface;
1246
1247 EnterCriticalSection(&This->csFilter);
1248 {
1249 *pState = This->state;
1250 }
1251 LeaveCriticalSection(&This->csFilter);
1252
1253 return S_OK;
1254 }
1255
1256 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1257 {
1258 return E_NOTIMPL;
1259 }
1260
1261 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1262 {
1263 return E_NOTIMPL;
1264 }
1265
1266 /** IBaseFilter implementation **/
1267
1268 static HRESULT TestFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
1269 {
1270 TestFilterImpl *This = (TestFilterImpl *)iface;
1271
1272 /* Our pins are static, not changing so setting static tick count is ok */
1273 *lastsynctick = 0;
1274
1275 if (pos >= This->nPins)
1276 return S_FALSE;
1277
1278 *pin = This->ppPins[pos];
1279 IPin_AddRef(*pin);
1280 return S_OK;
1281 }
1282
1283 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1284 {
1285 return IEnumPinsImpl_Construct(ppEnum, TestFilter_GetPin, iface);
1286 }
1287
1288 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1289 {
1290 return E_NOTIMPL;
1291 }
1292
1293 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1294 {
1295 TestFilterImpl *This = (TestFilterImpl *)iface;
1296
1297 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1298 pInfo->pGraph = This->filterInfo.pGraph;
1299
1300 if (pInfo->pGraph)
1301 IFilterGraph_AddRef(pInfo->pGraph);
1302
1303 return S_OK;
1304 }
1305
1306 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1307 {
1308 HRESULT hr = S_OK;
1309 TestFilterImpl *This = (TestFilterImpl *)iface;
1310
1311 EnterCriticalSection(&This->csFilter);
1312 {
1313 if (pName)
1314 lstrcpyW(This->filterInfo.achName, pName);
1315 else
1316 *This->filterInfo.achName = '\0';
1317 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1318 }
1319 LeaveCriticalSection(&This->csFilter);
1320
1321 return hr;
1322 }
1323
1324 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1325 {
1326 return E_NOTIMPL;
1327 }
1328
1329 static const IBaseFilterVtbl TestFilter_Vtbl =
1330 {
1331 TestFilter_QueryInterface,
1332 TestFilter_AddRef,
1333 TestFilter_Release,
1334 TestFilter_GetClassID,
1335 TestFilter_Stop,
1336 TestFilter_Pause,
1337 TestFilter_Run,
1338 TestFilter_GetState,
1339 TestFilter_SetSyncSource,
1340 TestFilter_GetSyncSource,
1341 TestFilter_EnumPins,
1342 TestFilter_FindPin,
1343 TestFilter_QueryFilterInfo,
1344 TestFilter_JoinFilterGraph,
1345 TestFilter_QueryVendorInfo
1346 };
1347
1348 /* IClassFactory implementation */
1349
1350 typedef struct TestClassFactoryImpl
1351 {
1352 IClassFactoryVtbl *lpVtbl;
1353 const TestFilterPinData *filterPinData;
1354 const CLSID *clsid;
1355 } TestClassFactoryImpl;
1356
1357 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1358 LPCLASSFACTORY iface,
1359 REFIID riid,
1360 LPVOID *ppvObj)
1361 {
1362 if (ppvObj == NULL) return E_POINTER;
1363
1364 if (IsEqualGUID(riid, &IID_IUnknown) ||
1365 IsEqualGUID(riid, &IID_IClassFactory))
1366 {
1367 *ppvObj = iface;
1368 IClassFactory_AddRef(iface);
1369 return S_OK;
1370 }
1371
1372 *ppvObj = NULL;
1373 return E_NOINTERFACE;
1374 }
1375
1376 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1377 {
1378 return 2; /* non-heap-based object */
1379 }
1380
1381 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1382 {
1383 return 1; /* non-heap-based object */
1384 }
1385
1386 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1387 LPCLASSFACTORY iface,
1388 LPUNKNOWN pUnkOuter,
1389 REFIID riid,
1390 LPVOID *ppvObj)
1391 {
1392 TestClassFactoryImpl *This = (TestClassFactoryImpl *)iface;
1393 HRESULT hr;
1394 IUnknown *punk = NULL;
1395
1396 *ppvObj = NULL;
1397
1398 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1399
1400 hr = TestFilter_Create(This->clsid, This->filterPinData, (LPVOID *) &punk);
1401 if (SUCCEEDED(hr)) {
1402 hr = IUnknown_QueryInterface(punk, riid, ppvObj);
1403 IUnknown_Release(punk);
1404 }
1405 return hr;
1406 }
1407
1408 static HRESULT WINAPI Test_IClassFactory_LockServer(
1409 LPCLASSFACTORY iface,
1410 BOOL fLock)
1411 {
1412 return S_OK;
1413 }
1414
1415 static IClassFactoryVtbl TestClassFactory_Vtbl =
1416 {
1417 Test_IClassFactory_QueryInterface,
1418 Test_IClassFactory_AddRef,
1419 Test_IClassFactory_Release,
1420 Test_IClassFactory_CreateInstance,
1421 Test_IClassFactory_LockServer
1422 };
1423
1424 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1425 {
1426 IPin *pin = NULL;
1427 PIN_INFO pinInfo;
1428 FILTER_INFO filterInfo;
1429 HRESULT hr;
1430
1431 FilterName[0] = 0;
1432
1433 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1434 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1435 if (FAILED(hr)) return hr;
1436
1437 hr = IPin_QueryPinInfo(pin, &pinInfo);
1438 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1439 IPin_Release(pin);
1440 if (FAILED(hr)) return hr;
1441
1442 SetLastError(0xdeadbeef);
1443 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1444 if (hr == S_OK && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1445 {
1446 IBaseFilter_Release(pinInfo.pFilter);
1447 return E_NOTIMPL;
1448 }
1449 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1450 IBaseFilter_Release(pinInfo.pFilter);
1451 if (FAILED(hr)) return hr;
1452
1453 IFilterGraph_Release(filterInfo.pGraph);
1454
1455 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1456
1457 return S_OK;
1458 }
1459
1460 static void test_render_filter_priority(void)
1461 {
1462 /* Tests filter choice priorities in Render(). */
1463 DWORD cookie1 = 0, cookie2 = 0, cookie3 = 0;
1464 HRESULT hr;
1465 IFilterGraph2* pgraph2 = NULL;
1466 IFilterMapper2 *pMapper2 = NULL;
1467 IBaseFilter* ptestfilter = NULL;
1468 IBaseFilter* ptestfilter2 = NULL;
1469 static const CLSID CLSID_TestFilter2 = {
1470 0x37a4edb0,
1471 0x4d13,
1472 0x11dd,
1473 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1474 };
1475 static const CLSID CLSID_TestFilter3 = {
1476 0x37a4f2d8,
1477 0x4d13,
1478 0x11dd,
1479 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1480 };
1481 static const CLSID CLSID_TestFilter4 = {
1482 0x37a4f3b4,
1483 0x4d13,
1484 0x11dd,
1485 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1486 };
1487 static const GUID mediasubtype1 = {
1488 0x37a4f51c,
1489 0x4d13,
1490 0x11dd,
1491 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1492 };
1493 static const GUID mediasubtype2 = {
1494 0x37a4f5c6,
1495 0x4d13,
1496 0x11dd,
1497 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1498 };
1499 static const TestFilterPinData PinData1[] = {
1500 { PINDIR_OUTPUT, &mediasubtype1 },
1501 { 0, 0 }
1502 };
1503 static const TestFilterPinData PinData2[] = {
1504 { PINDIR_INPUT, &mediasubtype1 },
1505 { 0, 0 }
1506 };
1507 static const TestFilterPinData PinData3[] = {
1508 { PINDIR_INPUT, &GUID_NULL },
1509 { 0, 0 }
1510 };
1511 static const TestFilterPinData PinData4[] = {
1512 { PINDIR_INPUT, &mediasubtype1 },
1513 { PINDIR_OUTPUT, &mediasubtype2 },
1514 { 0, 0 }
1515 };
1516 static const TestFilterPinData PinData5[] = {
1517 { PINDIR_INPUT, &mediasubtype2 },
1518 { 0, 0 }
1519 };
1520 TestClassFactoryImpl Filter1ClassFactory = { &TestClassFactory_Vtbl, PinData2, &CLSID_TestFilter2 };
1521 TestClassFactoryImpl Filter2ClassFactory = { &TestClassFactory_Vtbl, PinData4, &CLSID_TestFilter3 };
1522 TestClassFactoryImpl Filter3ClassFactory = { &TestClassFactory_Vtbl, PinData5, &CLSID_TestFilter4 };
1523 char ConnectedFilterName1[MAX_FILTER_NAME];
1524 char ConnectedFilterName2[MAX_FILTER_NAME];
1525 REGFILTER2 rgf2;
1526 REGFILTERPINS2 rgPins2[2];
1527 REGPINTYPES rgPinType[2];
1528 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1529 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1530 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1531 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1532 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1533 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1534 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1535 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1536
1537 /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is
1538 "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating
1539 no preference given to exact match. */
1540 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1541 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1542 if (!pgraph2) return;
1543
1544 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1545 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1546 if (FAILED(hr)) goto out;
1547
1548 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1549 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1550
1551 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1552 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1553 if (FAILED(hr)) goto out;
1554
1555 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1556 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1557
1558 IBaseFilter_Release(ptestfilter2);
1559 ptestfilter2 = NULL;
1560
1561 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1562 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1563 if (FAILED(hr)) goto out;
1564
1565 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1566 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1567
1568 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1569 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1570
1571 hr = get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1572
1573 IFilterGraph2_Release(pgraph2);
1574 pgraph2 = NULL;
1575 IBaseFilter_Release(ptestfilter);
1576 ptestfilter = NULL;
1577 IBaseFilter_Release(ptestfilter2);
1578 ptestfilter2 = NULL;
1579
1580 if (hr == E_NOTIMPL)
1581 {
1582 win_skip("Needed functions are not implemented\n");
1583 return;
1584 }
1585
1586 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1587 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1588 if (!pgraph2) goto out;
1589
1590 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1591 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1592 if (FAILED(hr)) goto out;
1593
1594 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1595 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1596
1597 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1598 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1599 if (FAILED(hr)) goto out;
1600
1601 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1602 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1603
1604 IBaseFilter_Release(ptestfilter2);
1605 ptestfilter2 = NULL;
1606
1607 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1608 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1609 if (FAILED(hr)) goto out;
1610
1611 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1612 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1613
1614 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1615 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1616
1617 hr = IFilterGraph2_Disconnect(pgraph2, NULL);
1618 ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr);
1619
1620 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1621 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1622 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1623
1624 IFilterGraph2_Release(pgraph2);
1625 pgraph2 = NULL;
1626 IBaseFilter_Release(ptestfilter);
1627 ptestfilter = NULL;
1628 IBaseFilter_Release(ptestfilter2);
1629 ptestfilter2 = NULL;
1630
1631 /* Test if any preference is given to existing renderer which renders the pin directly vs
1632 an existing renderer which renders the pin indirectly, through an additional middle filter,
1633 again trying different orders of creation. Native appears not to give a preference. */
1634
1635 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1636 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1637 if (!pgraph2) goto out;
1638
1639 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1640 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1641 if (FAILED(hr)) goto out;
1642
1643 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1644 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1645
1646 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1647 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1648 if (FAILED(hr)) goto out;
1649
1650 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1651 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1652
1653 IBaseFilter_Release(ptestfilter2);
1654 ptestfilter2 = NULL;
1655
1656 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1657 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1658 if (FAILED(hr)) goto out;
1659
1660 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1661 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1662
1663 IBaseFilter_Release(ptestfilter2);
1664 ptestfilter2 = NULL;
1665
1666 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1667 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1668 if (FAILED(hr)) goto out;
1669
1670 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1671 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1672
1673 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1674 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1675
1676 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1677 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1, "TestfilterInstance2"),
1678 "unexpected connected filter: %s\n", ConnectedFilterName1);
1679
1680 IFilterGraph2_Release(pgraph2);
1681 pgraph2 = NULL;
1682 IBaseFilter_Release(ptestfilter);
1683 ptestfilter = NULL;
1684 IBaseFilter_Release(ptestfilter2);
1685 ptestfilter2 = NULL;
1686
1687 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1688 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1689 if (!pgraph2) goto out;
1690
1691 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1692 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1693 if (FAILED(hr)) goto out;
1694
1695 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1696 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1697
1698 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1699 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1700 if (FAILED(hr)) goto out;
1701
1702 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1703 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1704
1705 IBaseFilter_Release(ptestfilter2);
1706 ptestfilter2 = NULL;
1707
1708 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1709 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1710 if (FAILED(hr)) goto out;
1711
1712 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1713 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1714
1715 IBaseFilter_Release(ptestfilter2);
1716 ptestfilter2 = NULL;
1717
1718 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1719 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1720 if (FAILED(hr)) goto out;
1721
1722 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1723 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1724
1725 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1726 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1727
1728 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1729 ok(!lstrcmp(ConnectedFilterName2, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2, "TestfilterInstance2"),
1730 "unexpected connected filter: %s\n", ConnectedFilterName2);
1731 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1732 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1733
1734 IFilterGraph2_Release(pgraph2);
1735 pgraph2 = NULL;
1736 IBaseFilter_Release(ptestfilter);
1737 ptestfilter = NULL;
1738 IBaseFilter_Release(ptestfilter2);
1739 ptestfilter2 = NULL;
1740
1741 /* Test if renderers are tried before non-renderers (intermediary filters). */
1742 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1743 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1744 if (!pgraph2) goto out;
1745
1746 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
1747 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1748 if (!pMapper2) goto out;
1749
1750 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1751 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1752 if (FAILED(hr)) goto out;
1753
1754 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1755 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1756
1757 /* Register our filters with COM and with Filtermapper. */
1758 hr = CoRegisterClassObject(Filter1ClassFactory.clsid, (IUnknown *)&Filter1ClassFactory,
1759 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie1);
1760 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1761 if (FAILED(hr)) goto out;
1762 hr = CoRegisterClassObject(Filter2ClassFactory.clsid, (IUnknown *)&Filter2ClassFactory,
1763 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie2);
1764 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1765 if (FAILED(hr)) goto out;
1766 hr = CoRegisterClassObject(Filter3ClassFactory.clsid, (IUnknown *)&Filter3ClassFactory,
1767 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie3);
1768 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1769 if (FAILED(hr)) goto out;
1770
1771 rgf2.dwVersion = 2;
1772 rgf2.dwMerit = MERIT_UNLIKELY;
1773 S1(U(rgf2)).cPins2 = 1;
1774 S1(U(rgf2)).rgPins2 = rgPins2;
1775 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
1776 rgPins2[0].cInstances = 1;
1777 rgPins2[0].nMediaTypes = 1;
1778 rgPins2[0].lpMediaType = &rgPinType[0];
1779 rgPins2[0].nMediums = 0;
1780 rgPins2[0].lpMedium = NULL;
1781 rgPins2[0].clsPinCategory = NULL;
1782 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
1783 rgPinType[0].clsMinorType = &mediasubtype1;
1784
1785 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
1786 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1787 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1788
1789 rgf2.dwMerit = MERIT_PREFERRED;
1790 rgPinType[0].clsMinorType = &mediasubtype2;
1791
1792 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
1793 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1794 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1795
1796 S1(U(rgf2)).cPins2 = 2;
1797 rgPins2[0].dwFlags = 0;
1798 rgPinType[0].clsMinorType = &mediasubtype1;
1799
1800 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
1801 rgPins2[1].cInstances = 1;
1802 rgPins2[1].nMediaTypes = 1;
1803 rgPins2[1].lpMediaType = &rgPinType[1];
1804 rgPins2[1].nMediums = 0;
1805 rgPins2[1].lpMedium = NULL;
1806 rgPins2[1].clsPinCategory = NULL;
1807 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
1808 rgPinType[1].clsMinorType = &mediasubtype2;
1809
1810 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
1811 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1812 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1813
1814 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1815 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1816
1817 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1818 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3"),
1819 "unexpected connected filter: %s\n", ConnectedFilterName1);
1820
1821 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1822 &CLSID_TestFilter2);
1823 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1824 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1825 &CLSID_TestFilter3);
1826 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1827 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1828 &CLSID_TestFilter4);
1829 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1830
1831 out:
1832
1833 if (ptestfilter) IBaseFilter_Release(ptestfilter);
1834 if (ptestfilter2) IBaseFilter_Release(ptestfilter2);
1835 if (pgraph2) IFilterGraph2_Release(pgraph2);
1836 if (pMapper2) IFilterMapper2_Release(pMapper2);
1837
1838 hr = CoRevokeClassObject(cookie1);
1839 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1840 hr = CoRevokeClassObject(cookie2);
1841 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1842 hr = CoRevokeClassObject(cookie3);
1843 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1844 }
1845
1846 START_TEST(filtergraph)
1847 {
1848 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1849 if(!winetest_interactive)
1850 {
1851 skip("Skipping filtergraph test, see ROSTESTS_116\n");
1852 return;
1853 }
1854 else{
1855 test_render_run(avifileA);
1856 test_render_run(mpegfileA);
1857 test_graph_builder();
1858 test_graph_builder_addfilter();
1859 test_mediacontrol();
1860 test_filter_graph2();
1861 test_render_filter_priority();
1862 }
1863 CoUninitialize();
1864 }