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 CHAR fileA[] = "test.avi";
31 static const WCHAR file[] = {'t','e','s','t','.','a','v','i',0};
33 IGraphBuilder* pgraph;
35 static int createfiltergraph(void)
37 return S_OK == CoCreateInstance(
38 &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&pgraph);
41 static void renderfile(void)
45 hr = IGraphBuilder_RenderFile(pgraph, file, NULL);
46 ok(hr==S_OK, "RenderFile returned: %x\n", hr);
49 static void rungraph(void)
57 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (LPVOID*)&pmc);
58 ok(hr==S_OK, "Cannot get IMediaControl interface returned: %x\n", hr);
60 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (LPVOID*)&pmf);
61 ok(hr==S_OK, "Cannot get IMediaFilter interface returned: %x\n", hr);
63 IMediaControl_Stop(pmc);
65 IMediaFilter_SetSyncSource(pmf, NULL);
67 IMediaFilter_Release(pmf);
69 hr = IMediaControl_Run(pmc);
70 ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr);
74 trace("run -> stop\n");
75 hr = IMediaControl_Stop(pmc);
76 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
78 IGraphBuilder_SetDefaultSyncSource(pgraph);
81 trace("stop -> pause\n");
82 hr = IMediaControl_Pause(pmc);
83 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
86 trace("pause -> run\n");
87 hr = IMediaControl_Run(pmc);
88 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
91 trace("run -> pause\n");
92 hr = IMediaControl_Pause(pmc);
93 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
96 trace("pause -> stop\n");
97 hr = IMediaControl_Stop(pmc);
98 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
101 trace("pause -> run\n");
102 hr = IMediaControl_Run(pmc);
103 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
105 trace("run -> stop\n");
106 hr = IMediaControl_Stop(pmc);
107 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
109 trace("stop -> run\n");
110 hr = IMediaControl_Run(pmc);
111 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
113 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaEvent, (LPVOID*)&pme);
114 ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr);
116 hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent);
117 ok(hr==S_OK, "Cannot get event handle returned: %x\n", hr);
119 /* WaitForSingleObject(hEvent, INFINITE); */
122 hr = IMediaEvent_Release(pme);
123 ok(hr==2, "Releasing mediaevent returned: %x\n", hr);
125 hr = IMediaControl_Stop(pmc);
126 ok(hr==S_OK, "Cannot stop the graph returned: %x\n", hr);
128 hr = IMediaControl_Release(pmc);
129 ok(hr==1, "Releasing mediacontrol returned: %x\n", hr);
132 static void releasefiltergraph(void)
136 hr = IGraphBuilder_Release(pgraph);
137 ok(hr==0, "Releasing filtergraph returned: %x\n", hr);
140 static void test_render_run(void)
144 if (!createfiltergraph())
147 h = CreateFileA(fileA, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
148 if (h != INVALID_HANDLE_VALUE) {
154 releasefiltergraph();
157 static void test_graph_builder(void)
160 IBaseFilter *pF = NULL;
161 IBaseFilter *pF2 = NULL;
163 IEnumPins *pEnum = NULL;
165 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
166 static const WCHAR fooBarW[] = {'f','o','o','B','a','r',0};
168 if (!createfiltergraph())
171 /* create video filter */
172 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
173 &IID_IBaseFilter, (LPVOID*)&pF);
174 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
175 ok(pF != NULL, "pF is NULL\n");
177 /* add the two filters to the graph */
178 hr = IGraphBuilder_AddFilter(pgraph, pF, testFilterW);
179 ok(hr == S_OK, "failed to add pF to the graph: %x\n", hr);
182 hr = IBaseFilter_EnumPins(pF, &pEnum);
183 ok(hr == S_OK, "IBaseFilter_EnumPins failed for pF: %x\n", hr);
184 ok(pEnum != NULL, "pEnum is NULL\n");
185 hr = IEnumPins_Next(pEnum, 1, &pIn, NULL);
186 ok(hr == S_OK, "IEnumPins_Next failed for pF: %x\n", hr);
187 ok(pIn != NULL, "pIn is NULL\n");
188 hr = IPin_QueryDirection(pIn, &dir);
189 ok(hr == S_OK, "IPin_QueryDirection failed: %x\n", hr);
190 ok(dir == PINDIR_INPUT, "pin has wrong direction\n");
192 hr = IGraphBuilder_FindFilterByName(pgraph, fooBarW, &pF2);
193 ok(hr == VFW_E_NOT_FOUND, "IGraphBuilder_FindFilterByName returned %x\n", hr);
194 ok(pF2 == NULL, "IGraphBuilder_FindFilterByName returned %p\n", pF2);
195 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, &pF2);
196 ok(hr == S_OK, "IGraphBuilder_FindFilterByName returned %x\n", hr);
197 ok(pF2 != NULL, "IGraphBuilder_FindFilterByName returned NULL\n");
198 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, NULL);
199 ok(hr == E_POINTER, "IGraphBuilder_FindFilterByName returned %x\n", hr);
201 if (pIn) IPin_Release(pIn);
202 if (pEnum) IEnumPins_Release(pEnum);
203 if (pF) IBaseFilter_Release(pF);
204 if (pF2) IBaseFilter_Release(pF2);
206 releasefiltergraph();
209 static void test_graph_builder_addfilter(void)
212 IBaseFilter *pF = NULL;
213 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
215 if (!createfiltergraph())
218 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
219 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr);
221 /* create video filter */
222 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
223 &IID_IBaseFilter, (LPVOID*)&pF);
224 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
225 ok(pF != NULL, "pF is NULL\n");
227 skip("failed to created filter, skipping\n");
231 hr = IGraphBuilder_AddFilter(pgraph, pF, NULL);
232 ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr);
233 IMediaFilter_Release(pF);
236 static void test_mediacontrol(void)
239 LONGLONG pos = 0xdeadbeef;
240 IMediaSeeking *seeking = NULL;
241 IMediaFilter *filter = NULL;
242 IMediaControl *control = NULL;
244 IFilterGraph2_SetDefaultSyncSource(pgraph);
245 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking);
246 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
250 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
251 ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
254 IUnknown_Release(seeking);
258 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
259 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
262 IUnknown_Release(seeking);
263 IUnknown_Release(filter);
267 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
268 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
269 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
271 IMediaFilter_SetSyncSource(filter, NULL);
273 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
274 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
275 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
277 hr = IMediaControl_GetState(control, 1000, NULL);
278 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
280 IUnknown_Release(control);
281 IUnknown_Release(seeking);
282 IUnknown_Release(filter);
283 releasefiltergraph();
286 static void test_filter_graph2(void)
289 IFilterGraph2 *pF = NULL;
291 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
292 &IID_IFilterGraph2, (LPVOID*)&pF);
293 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
294 ok(pF != NULL, "pF is NULL\n");
296 hr = IFilterGraph2_Release(pF);
297 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
300 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
301 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
303 if (pMediaType->pbFormat)
305 CoTaskMemFree(pMediaType->pbFormat);
306 pMediaType->pbFormat = NULL;
308 if (pMediaType->pUnk)
310 IUnknown_Release(pMediaType->pUnk);
311 pMediaType->pUnk = NULL;
315 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
318 if (!pSrc->pbFormat) return S_OK;
319 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
320 return E_OUTOFMEMORY;
321 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
323 IUnknown_AddRef(pDest->pUnk);
327 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
329 AM_MEDIA_TYPE * pDest;
331 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
335 if (FAILED(CopyMediaType(pDest, pSrc)))
337 CoTaskMemFree(pDest);
344 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
346 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
347 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
350 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
352 FreeMediaType(pMediaType);
353 CoTaskMemFree(pMediaType);
356 typedef struct IEnumMediaTypesImpl
358 const IEnumMediaTypesVtbl * lpVtbl;
360 AM_MEDIA_TYPE *pMediaTypes;
363 } IEnumMediaTypesImpl;
365 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
367 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
370 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
372 if (!pEnumMediaTypes)
375 return E_OUTOFMEMORY;
377 pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl;
378 pEnumMediaTypes->refCount = 1;
379 pEnumMediaTypes->uIndex = 0;
380 pEnumMediaTypes->cMediaTypes = cMediaTypes;
381 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
382 for (i = 0; i < cMediaTypes; i++)
383 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
386 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
387 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
388 return E_OUTOFMEMORY;
390 *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl);
394 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
398 if (IsEqualIID(riid, &IID_IUnknown))
399 *ppv = (LPVOID)iface;
400 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
401 *ppv = (LPVOID)iface;
405 IUnknown_AddRef((IUnknown *)(*ppv));
409 return E_NOINTERFACE;
412 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
414 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
415 ULONG refCount = InterlockedIncrement(&This->refCount);
420 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
422 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
423 ULONG refCount = InterlockedDecrement(&This->refCount);
428 for (i = 0; i < This->cMediaTypes; i++)
429 FreeMediaType(&This->pMediaTypes[i]);
430 CoTaskMemFree(This->pMediaTypes);
436 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
439 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
441 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
446 for (i = 0; i < cFetched; i++)
447 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
450 DeleteMediaType(ppMediaTypes[i]);
452 return E_OUTOFMEMORY;
456 if ((cMediaTypes != 1) || pcFetched)
457 *pcFetched = cFetched;
459 This->uIndex += cFetched;
461 if (cFetched != cMediaTypes)
466 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
468 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
470 if (This->uIndex + cMediaTypes < This->cMediaTypes)
472 This->uIndex += cMediaTypes;
478 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
480 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
486 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
489 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
491 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
494 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
497 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
499 IEnumMediaTypesImpl_QueryInterface,
500 IEnumMediaTypesImpl_AddRef,
501 IEnumMediaTypesImpl_Release,
502 IEnumMediaTypesImpl_Next,
503 IEnumMediaTypesImpl_Skip,
504 IEnumMediaTypesImpl_Reset,
505 IEnumMediaTypesImpl_Clone
508 /* Implementation of a very stripped down pin for the test filter. Just enough
509 functionality for connecting and Render() to work. */
511 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
513 lstrcpyW(pDest->achName, pSrc->achName);
514 pDest->dir = pSrc->dir;
515 pDest->pFilter = pSrc->pFilter;
518 typedef struct ITestPinImpl
520 const struct IPinVtbl * lpVtbl;
522 LPCRITICAL_SECTION pCritSec;
525 AM_MEDIA_TYPE mtCurrent;
529 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
533 if (IsEqualIID(riid, &IID_IUnknown))
534 *ppv = (LPVOID)iface;
535 else if (IsEqualIID(riid, &IID_IPin))
536 *ppv = (LPVOID)iface;
540 IUnknown_AddRef((IUnknown *)(*ppv));
544 return E_NOINTERFACE;
547 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
549 ITestPinImpl *This = (ITestPinImpl *)iface;
550 ULONG refCount = InterlockedIncrement(&This->refCount);
554 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
556 ITestPinImpl *This = (ITestPinImpl *)iface;
557 ULONG refCount = InterlockedDecrement(&This->refCount);
561 FreeMediaType(&This->mtCurrent);
570 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
575 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
577 ITestPinImpl *This = (ITestPinImpl *)iface;
578 PIN_DIRECTION pindirReceive;
581 EnterCriticalSection(This->pCritSec);
583 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
584 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
585 hr = VFW_E_TYPE_NOT_ACCEPTED;
587 if (This->pConnectedTo)
588 hr = VFW_E_ALREADY_CONNECTED;
592 IPin_QueryDirection(pReceivePin, &pindirReceive);
594 if (pindirReceive != PINDIR_OUTPUT)
596 hr = VFW_E_INVALID_DIRECTION;
602 CopyMediaType(&This->mtCurrent, pmt);
603 This->pConnectedTo = pReceivePin;
604 IPin_AddRef(pReceivePin);
607 LeaveCriticalSection(This->pCritSec);
612 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
615 ITestPinImpl *This = (ITestPinImpl *)iface;
617 EnterCriticalSection(This->pCritSec);
619 if (This->pConnectedTo)
621 IPin_Release(This->pConnectedTo);
622 This->pConnectedTo = NULL;
628 LeaveCriticalSection(This->pCritSec);
633 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
636 ITestPinImpl *This = (ITestPinImpl *)iface;
638 EnterCriticalSection(This->pCritSec);
640 if (This->pConnectedTo)
642 *ppPin = This->pConnectedTo;
648 hr = VFW_E_NOT_CONNECTED;
652 LeaveCriticalSection(This->pCritSec);
657 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
660 ITestPinImpl *This = (ITestPinImpl *)iface;
662 EnterCriticalSection(This->pCritSec);
664 if (This->pConnectedTo)
666 CopyMediaType(pmt, &This->mtCurrent);
671 ZeroMemory(pmt, sizeof(*pmt));
672 hr = VFW_E_NOT_CONNECTED;
675 LeaveCriticalSection(This->pCritSec);
680 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
682 ITestPinImpl *This = (ITestPinImpl *)iface;
684 Copy_PinInfo(pInfo, &This->pinInfo);
685 IBaseFilter_AddRef(pInfo->pFilter);
690 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
692 ITestPinImpl *This = (ITestPinImpl *)iface;
694 *pPinDir = This->pinInfo.dir;
699 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
704 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
706 ITestPinImpl *This = (ITestPinImpl *)iface;
708 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
709 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
712 return VFW_E_TYPE_NOT_ACCEPTED;
715 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
717 ITestPinImpl *This = (ITestPinImpl *)iface;
719 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
722 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
727 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
732 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
737 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
742 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
747 static const IPinVtbl TestFilter_InputPin_Vtbl =
749 TestFilter_Pin_QueryInterface,
750 TestFilter_Pin_AddRef,
751 TestFilter_Pin_Release,
752 TestFilter_InputPin_Connect,
753 TestFilter_InputPin_ReceiveConnection,
754 TestFilter_Pin_Disconnect,
755 TestFilter_Pin_ConnectedTo,
756 TestFilter_Pin_ConnectionMediaType,
757 TestFilter_Pin_QueryPinInfo,
758 TestFilter_Pin_QueryDirection,
759 TestFilter_Pin_QueryId,
760 TestFilter_Pin_QueryAccept,
761 TestFilter_Pin_EnumMediaTypes,
762 TestFilter_Pin_QueryInternalConnections,
763 TestFilter_Pin_EndOfStream,
764 TestFilter_Pin_BeginFlush,
765 TestFilter_Pin_EndFlush,
766 TestFilter_Pin_NewSegment
769 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
774 /* Private helper function */
775 static HRESULT TestFilter_OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
777 ITestPinImpl *This = (ITestPinImpl *)iface;
780 This->pConnectedTo = pReceivePin;
781 IPin_AddRef(pReceivePin);
783 hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
787 IPin_Release(This->pConnectedTo);
788 This->pConnectedTo = NULL;
794 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
796 ITestPinImpl *This = (ITestPinImpl *)iface;
799 EnterCriticalSection(This->pCritSec);
801 /* if we have been a specific type to connect with, then we can either connect
802 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
803 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
804 hr = TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, pmt);
807 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
808 (TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, &This->mtCurrent) == S_OK))
810 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
811 } /* if negotiate media type */
813 LeaveCriticalSection(This->pCritSec);
818 static const IPinVtbl TestFilter_OutputPin_Vtbl =
820 TestFilter_Pin_QueryInterface,
821 TestFilter_Pin_AddRef,
822 TestFilter_Pin_Release,
823 TestFilter_OutputPin_Connect,
824 TestFilter_OutputPin_ReceiveConnection,
825 TestFilter_Pin_Disconnect,
826 TestFilter_Pin_ConnectedTo,
827 TestFilter_Pin_ConnectionMediaType,
828 TestFilter_Pin_QueryPinInfo,
829 TestFilter_Pin_QueryDirection,
830 TestFilter_Pin_QueryId,
831 TestFilter_Pin_QueryAccept,
832 TestFilter_Pin_EnumMediaTypes,
833 TestFilter_Pin_QueryInternalConnections,
834 TestFilter_Pin_EndOfStream,
835 TestFilter_Pin_BeginFlush,
836 TestFilter_Pin_EndFlush,
837 TestFilter_Pin_NewSegment
840 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
841 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
843 ITestPinImpl * pPinImpl;
847 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
850 return E_OUTOFMEMORY;
852 pPinImpl->refCount = 1;
853 pPinImpl->pConnectedTo = NULL;
854 pPinImpl->pCritSec = pCritSec;
855 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
856 pPinImpl->mtCurrent = *pinmt;
858 pPinImpl->lpVtbl = Pin_Vtbl;
860 *ppPin = (IPin *)pPinImpl;
864 /* IEnumPins implementation */
866 typedef HRESULT (* FNOBTAINPIN)(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick);
868 typedef struct IEnumPinsImpl
870 const IEnumPinsVtbl * lpVtbl;
874 FNOBTAINPIN receive_pin;
878 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
880 static HRESULT IEnumPinsImpl_Construct(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, IBaseFilter *base)
882 IEnumPinsImpl * pEnumPins;
887 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
891 return E_OUTOFMEMORY;
893 pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl;
894 pEnumPins->refCount = 1;
895 pEnumPins->uIndex = 0;
896 pEnumPins->receive_pin = receive_pin;
897 pEnumPins->base = base;
898 IBaseFilter_AddRef(base);
899 *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl);
901 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
906 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
910 if (IsEqualIID(riid, &IID_IUnknown))
911 *ppv = (LPVOID)iface;
912 else if (IsEqualIID(riid, &IID_IEnumPins))
913 *ppv = (LPVOID)iface;
917 IUnknown_AddRef((IUnknown *)(*ppv));
921 return E_NOINTERFACE;
924 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
926 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
927 ULONG refCount = InterlockedIncrement(&This->refCount);
932 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
934 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
935 ULONG refCount = InterlockedDecrement(&This->refCount);
939 IBaseFilter_Release(This->base);
947 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
949 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
950 DWORD synctime = This->synctime;
957 if (cPins > 1 && !pcFetched)
963 while (i < cPins && hr == S_OK)
965 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
970 if (synctime != This->synctime)
974 if (!i && synctime != This->synctime)
975 return VFW_E_ENUM_OUT_OF_SYNC;
986 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
988 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
989 DWORD synctime = This->synctime;
993 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
997 if (synctime != This->synctime)
998 return VFW_E_ENUM_OUT_OF_SYNC;
1001 This->uIndex += cPins;
1006 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1008 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1010 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1016 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1019 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1021 hr = IEnumPinsImpl_Construct(ppEnum, This->receive_pin, This->base);
1024 return IEnumPins_Skip(*ppEnum, This->uIndex);
1027 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1029 IEnumPinsImpl_QueryInterface,
1030 IEnumPinsImpl_AddRef,
1031 IEnumPinsImpl_Release,
1034 IEnumPinsImpl_Reset,
1038 /* Test filter implementation - a filter that has few predefined pins with single media type
1039 * that accept only this single media type. Enough for Render(). */
1041 typedef struct TestFilterPinData
1043 PIN_DIRECTION pinDir;
1044 const GUID *mediasubtype;
1045 } TestFilterPinData;
1047 typedef struct TestFilterImpl
1049 const IBaseFilterVtbl * lpVtbl;
1052 CRITICAL_SECTION csFilter;
1054 FILTER_INFO filterInfo;
1060 static const IBaseFilterVtbl TestFilter_Vtbl;
1062 static HRESULT TestFilter_Create(const CLSID* pClsid, const TestFilterPinData *pinData, LPVOID * ppv)
1064 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1065 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1068 TestFilterImpl* pTestFilter = NULL;
1072 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1073 if (!pTestFilter) return E_OUTOFMEMORY;
1075 pTestFilter->clsid = *pClsid;
1076 pTestFilter->lpVtbl = &TestFilter_Vtbl;
1077 pTestFilter->refCount = 1;
1078 InitializeCriticalSection(&pTestFilter->csFilter);
1079 pTestFilter->state = State_Stopped;
1081 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1084 while(pinData[nPins].mediasubtype) ++nPins;
1086 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1087 if (!pTestFilter->ppPins)
1092 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1094 for (i = 0; i < nPins; i++)
1096 ZeroMemory(&mt, sizeof(mt));
1097 mt.majortype = MEDIATYPE_Video;
1098 mt.formattype = FORMAT_None;
1099 mt.subtype = *pinData[i].mediasubtype;
1101 pinInfo.dir = pinData[i].pinDir;
1102 pinInfo.pFilter = (IBaseFilter *)pTestFilter;
1103 if (pinInfo.dir == PINDIR_INPUT)
1105 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1106 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1107 &pTestFilter->ppPins[i]);
1112 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1113 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1114 &pTestFilter->ppPins[i]);
1116 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1119 pTestFilter->nPins = nPins;
1120 *ppv = (LPVOID)pTestFilter;
1125 if (pTestFilter->ppPins)
1127 for (i = 0; i < nPins; i++)
1129 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1132 CoTaskMemFree(pTestFilter->ppPins);
1133 DeleteCriticalSection(&pTestFilter->csFilter);
1134 CoTaskMemFree(pTestFilter);
1139 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1141 TestFilterImpl *This = (TestFilterImpl *)iface;
1145 if (IsEqualIID(riid, &IID_IUnknown))
1146 *ppv = (LPVOID)This;
1147 else if (IsEqualIID(riid, &IID_IPersist))
1148 *ppv = (LPVOID)This;
1149 else if (IsEqualIID(riid, &IID_IMediaFilter))
1150 *ppv = (LPVOID)This;
1151 else if (IsEqualIID(riid, &IID_IBaseFilter))
1152 *ppv = (LPVOID)This;
1156 IUnknown_AddRef((IUnknown *)(*ppv));
1160 return E_NOINTERFACE;
1163 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1165 TestFilterImpl *This = (TestFilterImpl *)iface;
1166 ULONG refCount = InterlockedIncrement(&This->refCount);
1171 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1173 TestFilterImpl *This = (TestFilterImpl *)iface;
1174 ULONG refCount = InterlockedDecrement(&This->refCount);
1180 for (i = 0; i < This->nPins; i++)
1184 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1186 IPin_Disconnect(pConnectedTo);
1187 IPin_Release(pConnectedTo);
1189 IPin_Disconnect(This->ppPins[i]);
1191 IPin_Release(This->ppPins[i]);
1194 CoTaskMemFree(This->ppPins);
1195 This->lpVtbl = NULL;
1197 DeleteCriticalSection(&This->csFilter);
1199 CoTaskMemFree(This);
1206 /** IPersist methods **/
1208 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1210 TestFilterImpl *This = (TestFilterImpl *)iface;
1212 *pClsid = This->clsid;
1217 /** IMediaFilter methods **/
1219 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1224 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1229 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1234 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1236 TestFilterImpl *This = (TestFilterImpl *)iface;
1238 EnterCriticalSection(&This->csFilter);
1240 *pState = This->state;
1242 LeaveCriticalSection(&This->csFilter);
1247 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1252 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1257 /** IBaseFilter implementation **/
1259 static HRESULT TestFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
1261 TestFilterImpl *This = (TestFilterImpl *)iface;
1263 /* Our pins are static, not changing so setting static tick count is ok */
1266 if (pos >= This->nPins)
1269 *pin = This->ppPins[pos];
1274 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1276 return IEnumPinsImpl_Construct(ppEnum, TestFilter_GetPin, iface);
1279 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1284 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1286 TestFilterImpl *This = (TestFilterImpl *)iface;
1288 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1289 pInfo->pGraph = This->filterInfo.pGraph;
1292 IFilterGraph_AddRef(pInfo->pGraph);
1297 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1300 TestFilterImpl *This = (TestFilterImpl *)iface;
1302 EnterCriticalSection(&This->csFilter);
1305 lstrcpyW(This->filterInfo.achName, pName);
1307 *This->filterInfo.achName = '\0';
1308 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1310 LeaveCriticalSection(&This->csFilter);
1315 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1320 static const IBaseFilterVtbl TestFilter_Vtbl =
1322 TestFilter_QueryInterface,
1325 TestFilter_GetClassID,
1329 TestFilter_GetState,
1330 TestFilter_SetSyncSource,
1331 TestFilter_GetSyncSource,
1332 TestFilter_EnumPins,
1334 TestFilter_QueryFilterInfo,
1335 TestFilter_JoinFilterGraph,
1336 TestFilter_QueryVendorInfo
1339 /* IClassFactory implementation */
1341 typedef struct TestClassFactoryImpl
1343 IClassFactoryVtbl *lpVtbl;
1344 const TestFilterPinData *filterPinData;
1346 } TestClassFactoryImpl;
1348 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1349 LPCLASSFACTORY iface,
1353 if (ppvObj == NULL) return E_POINTER;
1355 if (IsEqualGUID(riid, &IID_IUnknown) ||
1356 IsEqualGUID(riid, &IID_IClassFactory))
1358 *ppvObj = (LPVOID)iface;
1359 IClassFactory_AddRef(iface);
1364 return E_NOINTERFACE;
1367 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1369 return 2; /* non-heap-based object */
1372 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1374 return 1; /* non-heap-based object */
1377 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1378 LPCLASSFACTORY iface,
1379 LPUNKNOWN pUnkOuter,
1383 TestClassFactoryImpl *This = (TestClassFactoryImpl *)iface;
1385 IUnknown *punk = NULL;
1389 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1391 hr = TestFilter_Create(This->clsid, This->filterPinData, (LPVOID *) &punk);
1392 if (SUCCEEDED(hr)) {
1393 hr = IUnknown_QueryInterface(punk, riid, ppvObj);
1394 IUnknown_Release(punk);
1399 static HRESULT WINAPI Test_IClassFactory_LockServer(
1400 LPCLASSFACTORY iface,
1406 static IClassFactoryVtbl TestClassFactory_Vtbl =
1408 Test_IClassFactory_QueryInterface,
1409 Test_IClassFactory_AddRef,
1410 Test_IClassFactory_Release,
1411 Test_IClassFactory_CreateInstance,
1412 Test_IClassFactory_LockServer
1415 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1419 FILTER_INFO filterInfo;
1424 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1425 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1426 if (FAILED(hr)) return hr;
1428 hr = IPin_QueryPinInfo(pin, &pinInfo);
1429 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1431 if (FAILED(hr)) return hr;
1433 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1434 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1435 IBaseFilter_Release(pinInfo.pFilter);
1436 if (FAILED(hr)) return hr;
1438 IFilterGraph_Release(filterInfo.pGraph);
1440 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1445 static void test_render_filter_priority(void)
1447 /* Tests filter choice priorities in Render(). */
1448 DWORD cookie1, cookie2, cookie3;
1450 IFilterGraph2* pgraph2 = NULL;
1451 IFilterMapper2 *pMapper2 = NULL;
1452 IBaseFilter* ptestfilter = NULL;
1453 IBaseFilter* ptestfilter2 = NULL;
1454 static const CLSID CLSID_TestFilter2 = {
1458 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1460 static const CLSID CLSID_TestFilter3 = {
1464 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1466 static const CLSID CLSID_TestFilter4 = {
1470 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1472 static const GUID mediasubtype1 = {
1476 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1478 static const GUID mediasubtype2 = {
1482 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1484 static const TestFilterPinData PinData1[] = {
1485 { PINDIR_OUTPUT, &mediasubtype1 },
1488 static const TestFilterPinData PinData2[] = {
1489 { PINDIR_INPUT, &mediasubtype1 },
1492 static const TestFilterPinData PinData3[] = {
1493 { PINDIR_INPUT, &GUID_NULL },
1496 static const TestFilterPinData PinData4[] = {
1497 { PINDIR_INPUT, &mediasubtype1 },
1498 { PINDIR_OUTPUT, &mediasubtype2 },
1501 static const TestFilterPinData PinData5[] = {
1502 { PINDIR_INPUT, &mediasubtype2 },
1505 TestClassFactoryImpl Filter1ClassFactory = { &TestClassFactory_Vtbl, PinData2, &CLSID_TestFilter2 };
1506 TestClassFactoryImpl Filter2ClassFactory = { &TestClassFactory_Vtbl, PinData4, &CLSID_TestFilter3 };
1507 TestClassFactoryImpl Filter3ClassFactory = { &TestClassFactory_Vtbl, PinData5, &CLSID_TestFilter4 };
1508 char ConnectedFilterName1[MAX_FILTER_NAME];
1509 char ConnectedFilterName2[MAX_FILTER_NAME];
1511 REGFILTERPINS2 rgPins2[2];
1512 REGPINTYPES rgPinType[2];
1513 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1514 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1515 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1516 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1517 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1518 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1519 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1520 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1522 /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is
1523 "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating
1524 no preference given to exact match. */
1525 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1526 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1527 if (!pgraph2) goto out;
1529 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1530 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1531 if (FAILED(hr)) goto out;
1533 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1534 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1536 hr = TestFilter_Create(&GUID_NULL, PinData2, (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, wszFilterInstanceName2);
1541 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1543 IBaseFilter_Release(ptestfilter2);
1544 ptestfilter2 = NULL;
1546 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1547 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1548 if (FAILED(hr)) goto out;
1550 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1551 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1553 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1554 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1556 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1558 IFilterGraph2_Release(pgraph2);
1560 IBaseFilter_Release(ptestfilter);
1562 IBaseFilter_Release(ptestfilter2);
1563 ptestfilter2 = NULL;
1565 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1566 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1567 if (!pgraph2) goto out;
1569 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1570 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1571 if (FAILED(hr)) goto out;
1573 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1574 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1576 hr = TestFilter_Create(&GUID_NULL, PinData3, (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, wszFilterInstanceName3);
1581 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1583 IBaseFilter_Release(ptestfilter2);
1584 ptestfilter2 = NULL;
1586 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1587 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1588 if (FAILED(hr)) goto out;
1590 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1591 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1593 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1594 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1596 hr = IFilterGraph2_Disconnect(pgraph2, NULL);
1597 ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr);
1599 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1600 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1601 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1603 IFilterGraph2_Release(pgraph2);
1605 IBaseFilter_Release(ptestfilter);
1607 IBaseFilter_Release(ptestfilter2);
1608 ptestfilter2 = NULL;
1610 /* Test if any preference is given to existing renderer which renders the pin directly vs
1611 an existing renderer which renders the pin indirectly, through an additional middle filter,
1612 again trying different orders of creation. Native appears not to give a preference. */
1614 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1615 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1616 if (!pgraph2) goto out;
1618 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1619 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1620 if (FAILED(hr)) goto out;
1622 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1623 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1625 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1626 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1627 if (FAILED(hr)) goto out;
1629 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1630 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1632 IBaseFilter_Release(ptestfilter2);
1633 ptestfilter2 = NULL;
1635 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1636 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1637 if (FAILED(hr)) goto out;
1639 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1640 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1642 IBaseFilter_Release(ptestfilter2);
1643 ptestfilter2 = NULL;
1645 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1646 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1647 if (FAILED(hr)) goto out;
1649 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1650 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1652 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1653 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1655 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1656 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1, "TestfilterInstance2"),
1657 "unexpected connected filter: %s\n", ConnectedFilterName1);
1659 IFilterGraph2_Release(pgraph2);
1661 IBaseFilter_Release(ptestfilter);
1663 IBaseFilter_Release(ptestfilter2);
1664 ptestfilter2 = NULL;
1666 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1667 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1668 if (!pgraph2) goto out;
1670 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1671 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1672 if (FAILED(hr)) goto out;
1674 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1675 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1677 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1678 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1679 if (FAILED(hr)) goto out;
1681 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1682 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1684 IBaseFilter_Release(ptestfilter2);
1685 ptestfilter2 = NULL;
1687 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1688 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1689 if (FAILED(hr)) goto out;
1691 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1692 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1694 IBaseFilter_Release(ptestfilter2);
1695 ptestfilter2 = NULL;
1697 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1698 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1699 if (FAILED(hr)) goto out;
1701 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1702 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1704 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1705 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1707 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1708 ok(!lstrcmp(ConnectedFilterName2, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2, "TestfilterInstance2"),
1709 "unexpected connected filter: %s\n", ConnectedFilterName2);
1710 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1711 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1713 IFilterGraph2_Release(pgraph2);
1715 IBaseFilter_Release(ptestfilter);
1717 IBaseFilter_Release(ptestfilter2);
1718 ptestfilter2 = NULL;
1720 /* Test if renderers are tried before non-renderers (intermediary filters). */
1721 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1722 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1723 if (!pgraph2) goto out;
1725 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
1726 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1727 if (!pMapper2) goto out;
1729 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1730 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1731 if (FAILED(hr)) goto out;
1733 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1734 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1736 /* Register our filters with COM and with Filtermapper. */
1737 hr = CoRegisterClassObject(Filter1ClassFactory.clsid, (IUnknown *)&Filter1ClassFactory,
1738 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie1);
1739 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1740 hr = CoRegisterClassObject(Filter2ClassFactory.clsid, (IUnknown *)&Filter2ClassFactory,
1741 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie2);
1742 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1743 hr = CoRegisterClassObject(Filter3ClassFactory.clsid, (IUnknown *)&Filter3ClassFactory,
1744 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie3);
1745 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1748 rgf2.dwMerit = MERIT_UNLIKELY;
1749 S1(U(rgf2)).cPins2 = 1;
1750 S1(U(rgf2)).rgPins2 = rgPins2;
1751 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
1752 rgPins2[0].cInstances = 1;
1753 rgPins2[0].nMediaTypes = 1;
1754 rgPins2[0].lpMediaType = &rgPinType[0];
1755 rgPins2[0].nMediums = 0;
1756 rgPins2[0].lpMedium = NULL;
1757 rgPins2[0].clsPinCategory = NULL;
1758 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
1759 rgPinType[0].clsMinorType = &mediasubtype1;
1761 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
1762 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1763 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1765 rgf2.dwMerit = MERIT_PREFERRED;
1766 rgPinType[0].clsMinorType = &mediasubtype2;
1768 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
1769 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1770 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1772 S1(U(rgf2)).cPins2 = 2;
1773 rgPins2[0].dwFlags = 0;
1774 rgPinType[0].clsMinorType = &mediasubtype1;
1776 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
1777 rgPins2[1].cInstances = 1;
1778 rgPins2[1].nMediaTypes = 1;
1779 rgPins2[1].lpMediaType = &rgPinType[1];
1780 rgPins2[1].nMediums = 0;
1781 rgPins2[1].lpMedium = NULL;
1782 rgPins2[1].clsPinCategory = NULL;
1783 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
1784 rgPinType[1].clsMinorType = &mediasubtype2;
1786 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
1787 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1788 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1790 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1791 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1793 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1794 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3"),
1795 "unexpected connected filter: %s\n", ConnectedFilterName1);
1797 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1798 &CLSID_TestFilter2);
1799 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1800 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1801 &CLSID_TestFilter3);
1802 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1803 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1804 &CLSID_TestFilter4);
1805 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1809 if (ptestfilter) IBaseFilter_Release(ptestfilter);
1810 if (ptestfilter2) IBaseFilter_Release(ptestfilter2);
1811 if (pgraph2) IFilterGraph2_Release(pgraph2);
1812 if (pMapper2) IFilterMapper2_Release(pMapper2);
1814 hr = CoRevokeClassObject(cookie1);
1815 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1816 hr = CoRevokeClassObject(cookie2);
1817 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1818 hr = CoRevokeClassObject(cookie3);
1819 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1822 START_TEST(filtergraph)
1824 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1826 test_graph_builder();
1827 test_graph_builder_addfilter();
1828 test_mediacontrol();
1829 test_filter_graph2();
1830 test_render_filter_priority();