2 * Unit tests for Direct Show functions
4 * Copyright (C) 2004 Christian Costa
5 * Copyright (C) 2008 Alexander Dorofeyev
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/test.h"
30 static const WCHAR file[] = {'t','e','s','t','.','a','v','i',0};
32 IGraphBuilder* pgraph;
34 static int createfiltergraph(void)
36 return S_OK == CoCreateInstance(
37 &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&pgraph);
40 static void renderfile(void)
44 hr = IGraphBuilder_RenderFile(pgraph, file, NULL);
45 ok(hr==S_OK, "RenderFile returned: %x\n", hr);
48 static void rungraph(void)
56 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (LPVOID*)&pmc);
57 ok(hr==S_OK, "Cannot get IMediaControl interface returned: %x\n", hr);
59 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (LPVOID*)&pmf);
60 ok(hr==S_OK, "Cannot get IMediaFilter interface returned: %x\n", hr);
62 IMediaControl_Stop(pmc);
64 IMediaFilter_SetSyncSource(pmf, NULL);
66 IMediaFilter_Release(pmf);
68 hr = IMediaControl_Run(pmc);
69 ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr);
73 trace("run -> stop\n");
74 hr = IMediaControl_Stop(pmc);
75 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
77 IGraphBuilder_SetDefaultSyncSource(pgraph);
80 trace("stop -> pause\n");
81 hr = IMediaControl_Pause(pmc);
82 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
85 trace("pause -> run\n");
86 hr = IMediaControl_Run(pmc);
87 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
90 trace("run -> pause\n");
91 hr = IMediaControl_Pause(pmc);
92 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
95 trace("pause -> stop\n");
96 hr = IMediaControl_Stop(pmc);
97 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
100 trace("pause -> run\n");
101 hr = IMediaControl_Run(pmc);
102 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
104 trace("run -> stop\n");
105 hr = IMediaControl_Stop(pmc);
106 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
108 trace("stop -> run\n");
109 hr = IMediaControl_Run(pmc);
110 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
112 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaEvent, (LPVOID*)&pme);
113 ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr);
115 hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent);
116 ok(hr==S_OK, "Cannot get event handle returned: %x\n", hr);
118 /* WaitForSingleObject(hEvent, INFINITE); */
121 hr = IMediaEvent_Release(pme);
122 ok(hr==2, "Releasing mediaevent returned: %x\n", hr);
124 hr = IMediaControl_Stop(pmc);
125 ok(hr==S_OK, "Cannot stop the graph returned: %x\n", hr);
127 hr = IMediaControl_Release(pmc);
128 ok(hr==1, "Releasing mediacontrol returned: %x\n", hr);
131 static void releasefiltergraph(void)
135 hr = IGraphBuilder_Release(pgraph);
136 ok(hr==0, "Releasing filtergraph returned: %x\n", hr);
139 static void test_render_run(void)
143 if (!createfiltergraph())
146 h = CreateFileW(file, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
147 if (h != INVALID_HANDLE_VALUE) {
153 releasefiltergraph();
156 static void test_graph_builder(void)
159 IBaseFilter *pF = NULL;
160 IBaseFilter *pF2 = NULL;
162 IEnumPins *pEnum = NULL;
164 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
165 static const WCHAR fooBarW[] = {'f','o','o','B','a','r',0};
167 if (!createfiltergraph())
170 /* create video filter */
171 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
172 &IID_IBaseFilter, (LPVOID*)&pF);
173 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
174 ok(pF != NULL, "pF is NULL\n");
176 /* add the two filters to the graph */
177 hr = IGraphBuilder_AddFilter(pgraph, pF, testFilterW);
178 ok(hr == S_OK, "failed to add pF to the graph: %x\n", hr);
181 hr = IBaseFilter_EnumPins(pF, &pEnum);
182 ok(hr == S_OK, "IBaseFilter_EnumPins failed for pF: %x\n", hr);
183 ok(pEnum != NULL, "pEnum is NULL\n");
184 hr = IEnumPins_Next(pEnum, 1, &pIn, NULL);
185 ok(hr == S_OK, "IEnumPins_Next failed for pF: %x\n", hr);
186 ok(pIn != NULL, "pIn is NULL\n");
187 hr = IPin_QueryDirection(pIn, &dir);
188 ok(hr == S_OK, "IPin_QueryDirection failed: %x\n", hr);
189 ok(dir == PINDIR_INPUT, "pin has wrong direction\n");
191 hr = IGraphBuilder_FindFilterByName(pgraph, fooBarW, &pF2);
192 ok(hr == VFW_E_NOT_FOUND, "IGraphBuilder_FindFilterByName returned %x\n", hr);
193 ok(pF2 == NULL, "IGraphBuilder_FindFilterByName returned %p\n", pF2);
194 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, &pF2);
195 ok(hr == S_OK, "IGraphBuilder_FindFilterByName returned %x\n", hr);
196 ok(pF2 != NULL, "IGraphBuilder_FindFilterByName returned NULL\n");
197 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, NULL);
198 ok(hr == E_POINTER, "IGraphBuilder_FindFilterByName returned %x\n", hr);
199 releasefiltergraph();
202 static void test_graph_builder_addfilter(void)
205 IBaseFilter *pF = NULL;
206 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
208 if (!createfiltergraph())
211 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
212 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr);
214 /* create video filter */
215 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
216 &IID_IBaseFilter, (LPVOID*)&pF);
217 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
218 ok(pF != NULL, "pF is NULL\n");
220 skip("failed to created filter, skipping\n");
224 hr = IGraphBuilder_AddFilter(pgraph, pF, NULL);
225 ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr);
226 IMediaFilter_Release(pF);
229 static void test_mediacontrol(void)
232 LONGLONG pos = 0xdeadbeef;
233 IMediaSeeking *seeking = NULL;
234 IMediaFilter *filter = NULL;
235 IMediaControl *control = NULL;
237 IFilterGraph2_SetDefaultSyncSource(pgraph);
238 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking);
239 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
243 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
244 ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
247 IUnknown_Release(seeking);
251 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
252 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
255 IUnknown_Release(seeking);
256 IUnknown_Release(filter);
260 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
261 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
262 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
264 IMediaFilter_SetSyncSource(filter, NULL);
266 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
267 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
268 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
270 hr = IMediaControl_GetState(control, 1000, NULL);
271 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
273 IUnknown_Release(control);
274 IUnknown_Release(seeking);
275 IUnknown_Release(filter);
276 releasefiltergraph();
279 static void test_filter_graph2(void)
282 IFilterGraph2 *pF = NULL;
284 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
285 &IID_IFilterGraph2, (LPVOID*)&pF);
286 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
287 ok(pF != NULL, "pF is NULL\n");
289 hr = IFilterGraph2_Release(pF);
290 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
293 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
294 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
296 if (pMediaType->pbFormat)
298 CoTaskMemFree(pMediaType->pbFormat);
299 pMediaType->pbFormat = NULL;
301 if (pMediaType->pUnk)
303 IUnknown_Release(pMediaType->pUnk);
304 pMediaType->pUnk = NULL;
308 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
311 if (!pSrc->pbFormat) return S_OK;
312 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
313 return E_OUTOFMEMORY;
314 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
316 IUnknown_AddRef(pDest->pUnk);
320 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
322 AM_MEDIA_TYPE * pDest;
324 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
328 if (FAILED(CopyMediaType(pDest, pSrc)))
330 CoTaskMemFree(pDest);
337 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
339 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
340 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
343 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
345 FreeMediaType(pMediaType);
346 CoTaskMemFree(pMediaType);
349 typedef struct IEnumMediaTypesImpl
351 const IEnumMediaTypesVtbl * lpVtbl;
353 AM_MEDIA_TYPE *pMediaTypes;
356 } IEnumMediaTypesImpl;
358 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
360 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
363 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
365 if (!pEnumMediaTypes)
368 return E_OUTOFMEMORY;
370 pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl;
371 pEnumMediaTypes->refCount = 1;
372 pEnumMediaTypes->uIndex = 0;
373 pEnumMediaTypes->cMediaTypes = cMediaTypes;
374 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
375 for (i = 0; i < cMediaTypes; i++)
376 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
379 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
380 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
381 return E_OUTOFMEMORY;
383 *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl);
387 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
391 if (IsEqualIID(riid, &IID_IUnknown))
392 *ppv = (LPVOID)iface;
393 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
394 *ppv = (LPVOID)iface;
398 IUnknown_AddRef((IUnknown *)(*ppv));
402 return E_NOINTERFACE;
405 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
407 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
408 ULONG refCount = InterlockedIncrement(&This->refCount);
413 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
415 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
416 ULONG refCount = InterlockedDecrement(&This->refCount);
421 for (i = 0; i < This->cMediaTypes; i++)
422 FreeMediaType(&This->pMediaTypes[i]);
423 CoTaskMemFree(This->pMediaTypes);
429 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
432 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
434 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
439 for (i = 0; i < cFetched; i++)
440 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
443 DeleteMediaType(ppMediaTypes[i]);
445 return E_OUTOFMEMORY;
449 if ((cMediaTypes != 1) || pcFetched)
450 *pcFetched = cFetched;
452 This->uIndex += cFetched;
454 if (cFetched != cMediaTypes)
459 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
461 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
463 if (This->uIndex + cMediaTypes < This->cMediaTypes)
465 This->uIndex += cMediaTypes;
471 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
473 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
479 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
482 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
484 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
487 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
490 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
492 IEnumMediaTypesImpl_QueryInterface,
493 IEnumMediaTypesImpl_AddRef,
494 IEnumMediaTypesImpl_Release,
495 IEnumMediaTypesImpl_Next,
496 IEnumMediaTypesImpl_Skip,
497 IEnumMediaTypesImpl_Reset,
498 IEnumMediaTypesImpl_Clone
501 /* Implementation of a very stripped down pin for the test filter. Just enough
502 functionality for connecting and Render() to work. */
504 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
506 lstrcpyW(pDest->achName, pSrc->achName);
507 pDest->dir = pSrc->dir;
508 pDest->pFilter = pSrc->pFilter;
511 typedef struct ITestPinImpl
513 const struct IPinVtbl * lpVtbl;
515 LPCRITICAL_SECTION pCritSec;
518 AM_MEDIA_TYPE mtCurrent;
522 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
526 if (IsEqualIID(riid, &IID_IUnknown))
527 *ppv = (LPVOID)iface;
528 else if (IsEqualIID(riid, &IID_IPin))
529 *ppv = (LPVOID)iface;
533 IUnknown_AddRef((IUnknown *)(*ppv));
537 return E_NOINTERFACE;
540 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
542 ITestPinImpl *This = (ITestPinImpl *)iface;
543 ULONG refCount = InterlockedIncrement(&This->refCount);
547 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
549 ITestPinImpl *This = (ITestPinImpl *)iface;
550 ULONG refCount = InterlockedDecrement(&This->refCount);
554 FreeMediaType(&This->mtCurrent);
563 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
568 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
570 ITestPinImpl *This = (ITestPinImpl *)iface;
571 PIN_DIRECTION pindirReceive;
574 EnterCriticalSection(This->pCritSec);
576 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
577 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
578 hr = VFW_E_TYPE_NOT_ACCEPTED;
580 if (This->pConnectedTo)
581 hr = VFW_E_ALREADY_CONNECTED;
585 IPin_QueryDirection(pReceivePin, &pindirReceive);
587 if (pindirReceive != PINDIR_OUTPUT)
589 hr = VFW_E_INVALID_DIRECTION;
595 CopyMediaType(&This->mtCurrent, pmt);
596 This->pConnectedTo = pReceivePin;
597 IPin_AddRef(pReceivePin);
600 LeaveCriticalSection(This->pCritSec);
605 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
608 ITestPinImpl *This = (ITestPinImpl *)iface;
610 EnterCriticalSection(This->pCritSec);
612 if (This->pConnectedTo)
614 IPin_Release(This->pConnectedTo);
615 This->pConnectedTo = NULL;
621 LeaveCriticalSection(This->pCritSec);
626 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
629 ITestPinImpl *This = (ITestPinImpl *)iface;
631 EnterCriticalSection(This->pCritSec);
633 if (This->pConnectedTo)
635 *ppPin = This->pConnectedTo;
641 hr = VFW_E_NOT_CONNECTED;
645 LeaveCriticalSection(This->pCritSec);
650 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
653 ITestPinImpl *This = (ITestPinImpl *)iface;
655 EnterCriticalSection(This->pCritSec);
657 if (This->pConnectedTo)
659 CopyMediaType(pmt, &This->mtCurrent);
664 ZeroMemory(pmt, sizeof(*pmt));
665 hr = VFW_E_NOT_CONNECTED;
668 LeaveCriticalSection(This->pCritSec);
673 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
675 ITestPinImpl *This = (ITestPinImpl *)iface;
677 Copy_PinInfo(pInfo, &This->pinInfo);
678 IBaseFilter_AddRef(pInfo->pFilter);
683 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
685 ITestPinImpl *This = (ITestPinImpl *)iface;
687 *pPinDir = This->pinInfo.dir;
692 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
697 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
699 ITestPinImpl *This = (ITestPinImpl *)iface;
701 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
702 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
705 return VFW_E_TYPE_NOT_ACCEPTED;
708 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
710 ITestPinImpl *This = (ITestPinImpl *)iface;
712 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
715 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
720 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
725 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
730 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
735 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
740 static const IPinVtbl TestFilter_InputPin_Vtbl =
742 TestFilter_Pin_QueryInterface,
743 TestFilter_Pin_AddRef,
744 TestFilter_Pin_Release,
745 TestFilter_InputPin_Connect,
746 TestFilter_InputPin_ReceiveConnection,
747 TestFilter_Pin_Disconnect,
748 TestFilter_Pin_ConnectedTo,
749 TestFilter_Pin_ConnectionMediaType,
750 TestFilter_Pin_QueryPinInfo,
751 TestFilter_Pin_QueryDirection,
752 TestFilter_Pin_QueryId,
753 TestFilter_Pin_QueryAccept,
754 TestFilter_Pin_EnumMediaTypes,
755 TestFilter_Pin_QueryInternalConnections,
756 TestFilter_Pin_EndOfStream,
757 TestFilter_Pin_BeginFlush,
758 TestFilter_Pin_EndFlush,
759 TestFilter_Pin_NewSegment
762 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
767 /* Private helper function */
768 static HRESULT WINAPI TestFilter_OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
770 ITestPinImpl *This = (ITestPinImpl *)iface;
773 This->pConnectedTo = pReceivePin;
774 IPin_AddRef(pReceivePin);
776 hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
780 IPin_Release(This->pConnectedTo);
781 This->pConnectedTo = NULL;
787 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
789 ITestPinImpl *This = (ITestPinImpl *)iface;
792 EnterCriticalSection(This->pCritSec);
794 /* if we have been a specific type to connect with, then we can either connect
795 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
796 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
797 hr = TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, pmt);
800 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
801 (TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, &This->mtCurrent) == S_OK))
803 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
804 } /* if negotiate media type */
806 LeaveCriticalSection(This->pCritSec);
811 static const IPinVtbl TestFilter_OutputPin_Vtbl =
813 TestFilter_Pin_QueryInterface,
814 TestFilter_Pin_AddRef,
815 TestFilter_Pin_Release,
816 TestFilter_OutputPin_Connect,
817 TestFilter_OutputPin_ReceiveConnection,
818 TestFilter_Pin_Disconnect,
819 TestFilter_Pin_ConnectedTo,
820 TestFilter_Pin_ConnectionMediaType,
821 TestFilter_Pin_QueryPinInfo,
822 TestFilter_Pin_QueryDirection,
823 TestFilter_Pin_QueryId,
824 TestFilter_Pin_QueryAccept,
825 TestFilter_Pin_EnumMediaTypes,
826 TestFilter_Pin_QueryInternalConnections,
827 TestFilter_Pin_EndOfStream,
828 TestFilter_Pin_BeginFlush,
829 TestFilter_Pin_EndFlush,
830 TestFilter_Pin_NewSegment
833 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
834 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
836 ITestPinImpl * pPinImpl;
840 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
843 return E_OUTOFMEMORY;
845 pPinImpl->refCount = 1;
846 pPinImpl->pConnectedTo = NULL;
847 pPinImpl->pCritSec = pCritSec;
848 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
849 pPinImpl->mtCurrent = *pinmt;
851 pPinImpl->lpVtbl = Pin_Vtbl;
853 *ppPin = (IPin *)pPinImpl;
857 /* IEnumPins implementation */
859 typedef HRESULT (* FNOBTAINPIN)(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick);
861 typedef struct IEnumPinsImpl
863 const IEnumPinsVtbl * lpVtbl;
867 FNOBTAINPIN receive_pin;
871 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
873 static HRESULT IEnumPinsImpl_Construct(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, IBaseFilter *base)
875 IEnumPinsImpl * pEnumPins;
880 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
884 return E_OUTOFMEMORY;
886 pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl;
887 pEnumPins->refCount = 1;
888 pEnumPins->uIndex = 0;
889 pEnumPins->receive_pin = receive_pin;
890 pEnumPins->base = base;
891 IBaseFilter_AddRef(base);
892 *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl);
894 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
899 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
903 if (IsEqualIID(riid, &IID_IUnknown))
904 *ppv = (LPVOID)iface;
905 else if (IsEqualIID(riid, &IID_IEnumPins))
906 *ppv = (LPVOID)iface;
910 IUnknown_AddRef((IUnknown *)(*ppv));
914 return E_NOINTERFACE;
917 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
919 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
920 ULONG refCount = InterlockedIncrement(&This->refCount);
925 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
927 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
928 ULONG refCount = InterlockedDecrement(&This->refCount);
932 IBaseFilter_Release(This->base);
940 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
942 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
943 DWORD synctime = This->synctime;
950 if (cPins > 1 && !pcFetched)
956 while (i < cPins && hr == S_OK)
958 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
963 if (synctime != This->synctime)
967 if (!i && synctime != This->synctime)
968 return VFW_E_ENUM_OUT_OF_SYNC;
979 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
981 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
982 DWORD synctime = This->synctime;
986 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
990 if (synctime != This->synctime)
991 return VFW_E_ENUM_OUT_OF_SYNC;
994 This->uIndex += cPins;
999 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1001 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1003 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1009 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1012 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1014 hr = IEnumPinsImpl_Construct(ppEnum, This->receive_pin, This->base);
1017 return IEnumPins_Skip(*ppEnum, This->uIndex);
1020 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1022 IEnumPinsImpl_QueryInterface,
1023 IEnumPinsImpl_AddRef,
1024 IEnumPinsImpl_Release,
1027 IEnumPinsImpl_Reset,
1031 /* Test filter implementation - a filter that has few predefined pins with single media type
1032 * that accept only this single media type. Enough for Render(). */
1034 typedef struct TestFilterPinData
1036 PIN_DIRECTION pinDir;
1037 const GUID *mediasubtype;
1038 } TestFilterPinData;
1040 typedef struct TestFilterImpl
1042 const IBaseFilterVtbl * lpVtbl;
1045 CRITICAL_SECTION csFilter;
1047 FILTER_INFO filterInfo;
1053 static const IBaseFilterVtbl TestFilter_Vtbl;
1055 static HRESULT TestFilter_Create(const CLSID* pClsid, const TestFilterPinData *pinData, LPVOID * ppv)
1057 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1058 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1061 TestFilterImpl* pTestFilter = NULL;
1065 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1066 if (!pTestFilter) return E_OUTOFMEMORY;
1068 pTestFilter->clsid = *pClsid;
1069 pTestFilter->lpVtbl = &TestFilter_Vtbl;
1070 pTestFilter->refCount = 1;
1071 InitializeCriticalSection(&pTestFilter->csFilter);
1072 pTestFilter->state = State_Stopped;
1074 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1077 while(pinData[nPins].mediasubtype) ++nPins;
1079 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1080 if (!pTestFilter->ppPins)
1085 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1087 for (i = 0; i < nPins; i++)
1089 ZeroMemory(&mt, sizeof(mt));
1090 mt.majortype = MEDIATYPE_Video;
1091 mt.formattype = FORMAT_None;
1092 mt.subtype = *pinData[i].mediasubtype;
1094 pinInfo.dir = pinData[i].pinDir;
1095 pinInfo.pFilter = (IBaseFilter *)pTestFilter;
1096 if (pinInfo.dir == PINDIR_INPUT)
1098 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1099 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1100 &pTestFilter->ppPins[i]);
1105 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1106 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1107 &pTestFilter->ppPins[i]);
1109 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1112 pTestFilter->nPins = nPins;
1113 *ppv = (LPVOID)pTestFilter;
1118 for (i = 0; i < nPins; i++)
1120 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1122 CoTaskMemFree(pTestFilter->ppPins);
1123 DeleteCriticalSection(&pTestFilter->csFilter);
1124 CoTaskMemFree(pTestFilter);
1129 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1131 TestFilterImpl *This = (TestFilterImpl *)iface;
1135 if (IsEqualIID(riid, &IID_IUnknown))
1136 *ppv = (LPVOID)This;
1137 else if (IsEqualIID(riid, &IID_IPersist))
1138 *ppv = (LPVOID)This;
1139 else if (IsEqualIID(riid, &IID_IMediaFilter))
1140 *ppv = (LPVOID)This;
1141 else if (IsEqualIID(riid, &IID_IBaseFilter))
1142 *ppv = (LPVOID)This;
1146 IUnknown_AddRef((IUnknown *)(*ppv));
1150 return E_NOINTERFACE;
1153 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1155 TestFilterImpl *This = (TestFilterImpl *)iface;
1156 ULONG refCount = InterlockedIncrement(&This->refCount);
1161 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1163 TestFilterImpl *This = (TestFilterImpl *)iface;
1164 ULONG refCount = InterlockedDecrement(&This->refCount);
1170 for (i = 0; i < This->nPins; i++)
1174 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1176 IPin_Disconnect(pConnectedTo);
1177 IPin_Release(pConnectedTo);
1179 IPin_Disconnect(This->ppPins[i]);
1181 IPin_Release(This->ppPins[i]);
1184 CoTaskMemFree(This->ppPins);
1185 This->lpVtbl = NULL;
1187 DeleteCriticalSection(&This->csFilter);
1189 CoTaskMemFree(This);
1196 /** IPersist methods **/
1198 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1200 TestFilterImpl *This = (TestFilterImpl *)iface;
1202 *pClsid = This->clsid;
1207 /** IMediaFilter methods **/
1209 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1214 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1219 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1224 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1226 TestFilterImpl *This = (TestFilterImpl *)iface;
1228 EnterCriticalSection(&This->csFilter);
1230 *pState = This->state;
1232 LeaveCriticalSection(&This->csFilter);
1237 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1242 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1247 /** IBaseFilter implementation **/
1249 static HRESULT TestFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
1251 TestFilterImpl *This = (TestFilterImpl *)iface;
1253 /* Our pins are static, not changing so setting static tick count is ok */
1256 if (pos >= This->nPins)
1259 *pin = This->ppPins[pos];
1264 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1266 return IEnumPinsImpl_Construct(ppEnum, TestFilter_GetPin, iface);
1269 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1274 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1276 TestFilterImpl *This = (TestFilterImpl *)iface;
1278 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1279 pInfo->pGraph = This->filterInfo.pGraph;
1282 IFilterGraph_AddRef(pInfo->pGraph);
1287 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1290 TestFilterImpl *This = (TestFilterImpl *)iface;
1292 EnterCriticalSection(&This->csFilter);
1295 lstrcpyW(This->filterInfo.achName, pName);
1297 *This->filterInfo.achName = '\0';
1298 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1300 LeaveCriticalSection(&This->csFilter);
1305 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1310 static const IBaseFilterVtbl TestFilter_Vtbl =
1312 TestFilter_QueryInterface,
1315 TestFilter_GetClassID,
1319 TestFilter_GetState,
1320 TestFilter_SetSyncSource,
1321 TestFilter_GetSyncSource,
1322 TestFilter_EnumPins,
1324 TestFilter_QueryFilterInfo,
1325 TestFilter_JoinFilterGraph,
1326 TestFilter_QueryVendorInfo
1329 /* IClassFactory implementation */
1331 typedef struct TestClassFactoryImpl
1333 IClassFactoryVtbl *lpVtbl;
1334 const TestFilterPinData *filterPinData;
1336 } TestClassFactoryImpl;
1338 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1339 LPCLASSFACTORY iface,
1343 if (ppvObj == NULL) return E_POINTER;
1345 if (IsEqualGUID(riid, &IID_IUnknown) ||
1346 IsEqualGUID(riid, &IID_IClassFactory))
1348 *ppvObj = (LPVOID)iface;
1349 IClassFactory_AddRef(iface);
1354 return E_NOINTERFACE;
1357 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1359 return 2; /* non-heap-based object */
1362 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1364 return 1; /* non-heap-based object */
1367 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1368 LPCLASSFACTORY iface,
1369 LPUNKNOWN pUnkOuter,
1373 TestClassFactoryImpl *This = (TestClassFactoryImpl *)iface;
1375 IUnknown *punk = NULL;
1379 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1381 hr = TestFilter_Create(This->clsid, This->filterPinData, (LPVOID *) &punk);
1382 if (SUCCEEDED(hr)) {
1383 hr = IUnknown_QueryInterface(punk, riid, ppvObj);
1384 IUnknown_Release(punk);
1389 static HRESULT WINAPI Test_IClassFactory_LockServer(
1390 LPCLASSFACTORY iface,
1396 static IClassFactoryVtbl TestClassFactory_Vtbl =
1398 Test_IClassFactory_QueryInterface,
1399 Test_IClassFactory_AddRef,
1400 Test_IClassFactory_Release,
1401 Test_IClassFactory_CreateInstance,
1402 Test_IClassFactory_LockServer
1405 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1409 FILTER_INFO filterInfo;
1414 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1415 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1416 if (FAILED(hr)) return hr;
1418 hr = IPin_QueryPinInfo(pin, &pinInfo);
1419 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1421 if (FAILED(hr)) return hr;
1423 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1424 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1425 IBaseFilter_Release(pinInfo.pFilter);
1426 if (FAILED(hr)) return hr;
1428 IFilterGraph_Release(filterInfo.pGraph);
1430 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1435 static void test_render_filter_priority(void)
1437 /* Tests filter choice priorities in Render(). */
1438 DWORD cookie1, cookie2, cookie3;
1440 IFilterGraph2* pgraph2 = NULL;
1441 IFilterMapper2 *pMapper2 = NULL;
1442 IBaseFilter* ptestfilter = NULL;
1443 IBaseFilter* ptestfilter2 = NULL;
1444 static const CLSID CLSID_TestFilter2 = {
1448 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1450 static const CLSID CLSID_TestFilter3 = {
1454 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1456 static const CLSID CLSID_TestFilter4 = {
1460 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1462 static const GUID mediasubtype1 = {
1466 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1468 static const GUID mediasubtype2 = {
1472 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1474 static const TestFilterPinData PinData1[] = {
1475 { PINDIR_OUTPUT, &mediasubtype1 },
1478 static const TestFilterPinData PinData2[] = {
1479 { PINDIR_INPUT, &mediasubtype1 },
1482 static const TestFilterPinData PinData3[] = {
1483 { PINDIR_INPUT, &GUID_NULL },
1486 static const TestFilterPinData PinData4[] = {
1487 { PINDIR_INPUT, &mediasubtype1 },
1488 { PINDIR_OUTPUT, &mediasubtype2 },
1491 static const TestFilterPinData PinData5[] = {
1492 { PINDIR_INPUT, &mediasubtype2 },
1495 TestClassFactoryImpl Filter1ClassFactory = { &TestClassFactory_Vtbl, PinData2, &CLSID_TestFilter2 };
1496 TestClassFactoryImpl Filter2ClassFactory = { &TestClassFactory_Vtbl, PinData4, &CLSID_TestFilter3 };
1497 TestClassFactoryImpl Filter3ClassFactory = { &TestClassFactory_Vtbl, PinData5, &CLSID_TestFilter4 };
1498 char ConnectedFilterName1[MAX_FILTER_NAME];
1499 char ConnectedFilterName2[MAX_FILTER_NAME];
1501 REGFILTERPINS2 rgPins2[2];
1502 REGPINTYPES rgPinType[2];
1503 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1504 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1505 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1506 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1507 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1508 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1509 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1510 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1512 /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is
1513 "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating
1514 no preference given to exact match. */
1515 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1516 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1517 if (!pgraph2) goto out;
1519 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1520 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1521 if (FAILED(hr)) goto out;
1523 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1524 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1526 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1527 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1528 if (FAILED(hr)) goto out;
1530 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1531 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1533 IBaseFilter_Release(ptestfilter2);
1534 ptestfilter2 = NULL;
1536 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1537 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1538 if (FAILED(hr)) goto out;
1540 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1541 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1543 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1544 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1546 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1548 IFilterGraph2_Release(pgraph2);
1550 IBaseFilter_Release(ptestfilter);
1552 IBaseFilter_Release(ptestfilter2);
1553 ptestfilter2 = NULL;
1555 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1556 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1557 if (!pgraph2) goto out;
1559 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1560 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1561 if (FAILED(hr)) goto out;
1563 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1564 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1566 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1567 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1568 if (FAILED(hr)) goto out;
1570 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1571 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1573 IBaseFilter_Release(ptestfilter2);
1574 ptestfilter2 = NULL;
1576 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1577 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1578 if (FAILED(hr)) goto out;
1580 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1581 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1583 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1584 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1586 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1587 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1588 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1590 IFilterGraph2_Release(pgraph2);
1592 IBaseFilter_Release(ptestfilter);
1594 IBaseFilter_Release(ptestfilter2);
1595 ptestfilter2 = NULL;
1597 /* Test if any preference is given to existing renderer which renders the pin directly vs
1598 an existing renderer which renders the pin indirectly, through an additional middle filter,
1599 again trying different orders of creation. Native appears not to give a preference. */
1601 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1602 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1603 if (!pgraph2) goto out;
1605 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1606 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1607 if (FAILED(hr)) goto out;
1609 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1610 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1612 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1613 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1614 if (FAILED(hr)) goto out;
1616 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1617 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1619 IBaseFilter_Release(ptestfilter2);
1620 ptestfilter2 = NULL;
1622 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1623 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1624 if (FAILED(hr)) goto out;
1626 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1627 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1629 IBaseFilter_Release(ptestfilter2);
1630 ptestfilter2 = NULL;
1632 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1633 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1634 if (FAILED(hr)) goto out;
1636 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1637 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1639 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1640 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1642 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1643 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1, "TestfilterInstance2"),
1644 "unexpected connected filter: %s\n", ConnectedFilterName1);
1646 IFilterGraph2_Release(pgraph2);
1648 IBaseFilter_Release(ptestfilter);
1650 IBaseFilter_Release(ptestfilter2);
1651 ptestfilter2 = NULL;
1653 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1654 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1655 if (!pgraph2) goto out;
1657 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1658 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1659 if (FAILED(hr)) goto out;
1661 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1662 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1664 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1665 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1666 if (FAILED(hr)) goto out;
1668 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1669 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1671 IBaseFilter_Release(ptestfilter2);
1672 ptestfilter2 = NULL;
1674 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1675 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1676 if (FAILED(hr)) goto out;
1678 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1679 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1681 IBaseFilter_Release(ptestfilter2);
1682 ptestfilter2 = NULL;
1684 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1685 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1686 if (FAILED(hr)) goto out;
1688 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1689 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1691 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1692 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1694 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1695 ok(!lstrcmp(ConnectedFilterName2, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2, "TestfilterInstance2"),
1696 "unexpected connected filter: %s\n", ConnectedFilterName2);
1697 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1698 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1700 IFilterGraph2_Release(pgraph2);
1702 IBaseFilter_Release(ptestfilter);
1704 IBaseFilter_Release(ptestfilter2);
1705 ptestfilter2 = NULL;
1707 /* Test if renderers are tried before non-renderers (intermediary filters). */
1708 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1709 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1710 if (!pgraph2) goto out;
1712 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
1713 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1714 if (!pMapper2) goto out;
1716 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1717 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1718 if (FAILED(hr)) goto out;
1720 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1721 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1723 /* Register our filters with COM and with Filtermapper. */
1724 hr = CoRegisterClassObject(Filter1ClassFactory.clsid, (IUnknown *)&Filter1ClassFactory,
1725 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie1);
1726 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1727 hr = CoRegisterClassObject(Filter2ClassFactory.clsid, (IUnknown *)&Filter2ClassFactory,
1728 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie2);
1729 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1730 hr = CoRegisterClassObject(Filter3ClassFactory.clsid, (IUnknown *)&Filter3ClassFactory,
1731 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie3);
1732 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1735 rgf2.dwMerit = MERIT_UNLIKELY;
1736 S1(U(rgf2)).cPins2 = 1;
1737 S1(U(rgf2)).rgPins2 = rgPins2;
1738 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
1739 rgPins2[0].cInstances = 1;
1740 rgPins2[0].nMediaTypes = 1;
1741 rgPins2[0].lpMediaType = &rgPinType[0];
1742 rgPins2[0].nMediums = 0;
1743 rgPins2[0].lpMedium = NULL;
1744 rgPins2[0].clsPinCategory = NULL;
1745 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
1746 rgPinType[0].clsMinorType = &mediasubtype1;
1748 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
1749 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1750 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1752 rgf2.dwMerit = MERIT_PREFERRED;
1753 rgPinType[0].clsMinorType = &mediasubtype2;
1755 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
1756 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1757 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1759 S1(U(rgf2)).cPins2 = 2;
1760 rgPins2[0].dwFlags = 0;
1761 rgPinType[0].clsMinorType = &mediasubtype1;
1763 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
1764 rgPins2[1].cInstances = 1;
1765 rgPins2[1].nMediaTypes = 1;
1766 rgPins2[1].lpMediaType = &rgPinType[1];
1767 rgPins2[1].nMediums = 0;
1768 rgPins2[1].lpMedium = NULL;
1769 rgPins2[1].clsPinCategory = NULL;
1770 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
1771 rgPinType[1].clsMinorType = &mediasubtype2;
1773 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
1774 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1775 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1777 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1778 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1780 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1781 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3"),
1782 "unexpected connected filter: %s\n", ConnectedFilterName1);
1784 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1785 &CLSID_TestFilter2);
1786 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1787 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1788 &CLSID_TestFilter3);
1789 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1790 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1791 &CLSID_TestFilter4);
1792 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1796 if (ptestfilter) IBaseFilter_Release(ptestfilter);
1797 if (ptestfilter2) IBaseFilter_Release(ptestfilter2);
1798 if (pgraph2) IFilterGraph2_Release(pgraph2);
1799 if (pMapper2) IFilterMapper2_Release(pMapper2);
1801 hr = CoRevokeClassObject(cookie1);
1802 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1803 hr = CoRevokeClassObject(cookie2);
1804 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1805 hr = CoRevokeClassObject(cookie3);
1806 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1809 START_TEST(filtergraph)
1811 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1813 test_graph_builder();
1814 test_graph_builder_addfilter();
1815 test_mediacontrol();
1816 test_filter_graph2();
1817 test_render_filter_priority();