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
27 #include "wine/test.h"
31 typedef struct TestFilterImpl
33 IBaseFilter IBaseFilter_iface;
36 CRITICAL_SECTION csFilter;
38 FILTER_INFO filterInfo;
44 static const WCHAR avifile[] = {'t','e','s','t','.','a','v','i',0};
45 static const WCHAR mpegfile[] = {'t','e','s','t','.','m','p','g',0};
47 static IGraphBuilder *pgraph;
49 static int createfiltergraph(void)
51 return S_OK == CoCreateInstance(
52 &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&pgraph);
55 static void rungraph(void)
63 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (LPVOID*)&pmc);
64 ok(hr==S_OK, "Cannot get IMediaControl interface returned: %x\n", hr);
66 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (LPVOID*)&pmf);
67 ok(hr==S_OK, "Cannot get IMediaFilter interface returned: %x\n", hr);
69 IMediaControl_Stop(pmc);
71 IMediaFilter_SetSyncSource(pmf, NULL);
73 IMediaFilter_Release(pmf);
75 hr = IMediaControl_Run(pmc);
76 ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr);
80 trace("run -> stop\n");
81 hr = IMediaControl_Stop(pmc);
82 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
84 IGraphBuilder_SetDefaultSyncSource(pgraph);
87 trace("stop -> pause\n");
88 hr = IMediaControl_Pause(pmc);
89 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
92 trace("pause -> run\n");
93 hr = IMediaControl_Run(pmc);
94 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
97 trace("run -> pause\n");
98 hr = IMediaControl_Pause(pmc);
99 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
102 trace("pause -> stop\n");
103 hr = IMediaControl_Stop(pmc);
104 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
107 trace("pause -> run\n");
108 hr = IMediaControl_Run(pmc);
109 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
111 trace("run -> stop\n");
112 hr = IMediaControl_Stop(pmc);
113 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
115 trace("stop -> run\n");
116 hr = IMediaControl_Run(pmc);
117 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
119 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaEvent, (LPVOID*)&pme);
120 ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr);
122 hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent);
123 ok(hr==S_OK, "Cannot get event handle returned: %x\n", hr);
125 /* WaitForSingleObject(hEvent, INFINITE); */
128 hr = IMediaEvent_Release(pme);
129 ok(hr==2, "Releasing mediaevent returned: %x\n", hr);
131 hr = IMediaControl_Stop(pmc);
132 ok(hr==S_OK, "Cannot stop the graph returned: %x\n", hr);
134 hr = IMediaControl_Release(pmc);
135 ok(hr==1, "Releasing mediacontrol returned: %x\n", hr);
138 static void releasefiltergraph(void)
142 hr = IGraphBuilder_Release(pgraph);
143 ok(hr==0, "Releasing filtergraph returned: %x\n", hr);
146 static void test_render_run(const WCHAR *file)
151 if (!createfiltergraph())
154 h = CreateFileW(file, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
155 if (h != INVALID_HANDLE_VALUE) {
157 hr = IGraphBuilder_RenderFile(pgraph, file, NULL);
158 ok(hr==S_OK, "RenderFile returned: %x\n", hr);
162 releasefiltergraph();
165 static void test_graph_builder(void)
168 IBaseFilter *pF = NULL;
169 IBaseFilter *pF2 = NULL;
171 IEnumPins *pEnum = NULL;
173 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
174 static const WCHAR fooBarW[] = {'f','o','o','B','a','r',0};
176 if (!createfiltergraph())
179 /* create video filter */
180 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
181 &IID_IBaseFilter, (LPVOID*)&pF);
182 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
183 ok(pF != NULL, "pF is NULL\n");
185 /* add the two filters to the graph */
186 hr = IGraphBuilder_AddFilter(pgraph, pF, testFilterW);
187 ok(hr == S_OK, "failed to add pF to the graph: %x\n", hr);
190 hr = IBaseFilter_EnumPins(pF, &pEnum);
191 ok(hr == S_OK, "IBaseFilter_EnumPins failed for pF: %x\n", hr);
192 ok(pEnum != NULL, "pEnum is NULL\n");
193 hr = IEnumPins_Next(pEnum, 1, &pIn, NULL);
194 ok(hr == S_OK, "IEnumPins_Next failed for pF: %x\n", hr);
195 ok(pIn != NULL, "pIn is NULL\n");
196 hr = IPin_QueryDirection(pIn, &dir);
197 ok(hr == S_OK, "IPin_QueryDirection failed: %x\n", hr);
198 ok(dir == PINDIR_INPUT, "pin has wrong direction\n");
200 hr = IGraphBuilder_FindFilterByName(pgraph, fooBarW, &pF2);
201 ok(hr == VFW_E_NOT_FOUND, "IGraphBuilder_FindFilterByName returned %x\n", hr);
202 ok(pF2 == NULL, "IGraphBuilder_FindFilterByName returned %p\n", pF2);
203 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, &pF2);
204 ok(hr == S_OK, "IGraphBuilder_FindFilterByName returned %x\n", hr);
205 ok(pF2 != NULL, "IGraphBuilder_FindFilterByName returned NULL\n");
206 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, NULL);
207 ok(hr == E_POINTER, "IGraphBuilder_FindFilterByName returned %x\n", hr);
209 if (pIn) IPin_Release(pIn);
210 if (pEnum) IEnumPins_Release(pEnum);
211 if (pF) IBaseFilter_Release(pF);
212 if (pF2) IBaseFilter_Release(pF2);
214 releasefiltergraph();
217 static void test_graph_builder_addfilter(void)
220 IBaseFilter *pF = NULL;
221 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
223 if (!createfiltergraph())
226 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
227 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr);
229 /* create video filter */
230 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
231 &IID_IBaseFilter, (LPVOID*)&pF);
232 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
233 ok(pF != NULL, "pF is NULL\n");
235 skip("failed to created filter, skipping\n");
239 hr = IGraphBuilder_AddFilter(pgraph, pF, NULL);
240 ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr);
241 IMediaFilter_Release(pF);
244 static void test_mediacontrol(void)
247 LONGLONG pos = 0xdeadbeef;
248 IMediaSeeking *seeking = NULL;
249 IMediaFilter *filter = NULL;
250 IMediaControl *control = NULL;
252 IFilterGraph2_SetDefaultSyncSource(pgraph);
253 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking);
254 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
258 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
259 ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
262 IUnknown_Release(seeking);
266 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
267 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
270 IUnknown_Release(seeking);
271 IUnknown_Release(filter);
275 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
276 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
277 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
279 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_ReturnTime, NULL, AM_SEEKING_NoPositioning);
280 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
281 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_NoPositioning, NULL, AM_SEEKING_ReturnTime);
282 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
284 IMediaFilter_SetSyncSource(filter, NULL);
286 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
287 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
288 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
290 hr = IMediaControl_GetState(control, 1000, NULL);
291 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
293 IUnknown_Release(control);
294 IUnknown_Release(seeking);
295 IUnknown_Release(filter);
296 releasefiltergraph();
299 static void test_filter_graph2(void)
302 IFilterGraph2 *pF = NULL;
304 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
305 &IID_IFilterGraph2, (LPVOID*)&pF);
306 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
307 ok(pF != NULL, "pF is NULL\n");
309 hr = IFilterGraph2_Release(pF);
310 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
313 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
314 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
316 if (pMediaType->pbFormat)
318 CoTaskMemFree(pMediaType->pbFormat);
319 pMediaType->pbFormat = NULL;
321 if (pMediaType->pUnk)
323 IUnknown_Release(pMediaType->pUnk);
324 pMediaType->pUnk = NULL;
328 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
331 if (!pSrc->pbFormat) return S_OK;
332 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
333 return E_OUTOFMEMORY;
334 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
336 IUnknown_AddRef(pDest->pUnk);
340 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
342 AM_MEDIA_TYPE * pDest;
344 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
348 if (FAILED(CopyMediaType(pDest, pSrc)))
350 CoTaskMemFree(pDest);
357 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
359 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
360 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
363 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
365 FreeMediaType(pMediaType);
366 CoTaskMemFree(pMediaType);
369 typedef struct IEnumMediaTypesImpl
371 IEnumMediaTypes IEnumMediaTypes_iface;
373 AM_MEDIA_TYPE *pMediaTypes;
376 } IEnumMediaTypesImpl;
378 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
380 static inline IEnumMediaTypesImpl *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
382 return CONTAINING_RECORD(iface, IEnumMediaTypesImpl, IEnumMediaTypes_iface);
385 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
388 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
390 if (!pEnumMediaTypes)
393 return E_OUTOFMEMORY;
395 pEnumMediaTypes->IEnumMediaTypes_iface.lpVtbl = &IEnumMediaTypesImpl_Vtbl;
396 pEnumMediaTypes->refCount = 1;
397 pEnumMediaTypes->uIndex = 0;
398 pEnumMediaTypes->cMediaTypes = cMediaTypes;
399 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
400 for (i = 0; i < cMediaTypes; i++)
401 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
404 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
405 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
406 return E_OUTOFMEMORY;
408 *ppEnum = &pEnumMediaTypes->IEnumMediaTypes_iface;
412 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
416 if (IsEqualIID(riid, &IID_IUnknown))
418 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
423 IUnknown_AddRef((IUnknown *)(*ppv));
427 return E_NOINTERFACE;
430 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
432 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
433 ULONG refCount = InterlockedIncrement(&This->refCount);
438 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
440 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
441 ULONG refCount = InterlockedDecrement(&This->refCount);
446 for (i = 0; i < This->cMediaTypes; i++)
447 FreeMediaType(&This->pMediaTypes[i]);
448 CoTaskMemFree(This->pMediaTypes);
454 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
457 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
459 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
464 for (i = 0; i < cFetched; i++)
465 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
468 DeleteMediaType(ppMediaTypes[i]);
470 return E_OUTOFMEMORY;
474 if ((cMediaTypes != 1) || pcFetched)
475 *pcFetched = cFetched;
477 This->uIndex += cFetched;
479 if (cFetched != cMediaTypes)
484 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
486 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
488 if (This->uIndex + cMediaTypes < This->cMediaTypes)
490 This->uIndex += cMediaTypes;
496 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
498 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
504 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
507 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
509 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
512 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
515 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
517 IEnumMediaTypesImpl_QueryInterface,
518 IEnumMediaTypesImpl_AddRef,
519 IEnumMediaTypesImpl_Release,
520 IEnumMediaTypesImpl_Next,
521 IEnumMediaTypesImpl_Skip,
522 IEnumMediaTypesImpl_Reset,
523 IEnumMediaTypesImpl_Clone
526 /* Implementation of a very stripped down pin for the test filter. Just enough
527 functionality for connecting and Render() to work. */
529 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
531 lstrcpyW(pDest->achName, pSrc->achName);
532 pDest->dir = pSrc->dir;
533 pDest->pFilter = pSrc->pFilter;
536 typedef struct ITestPinImpl
540 LPCRITICAL_SECTION pCritSec;
543 AM_MEDIA_TYPE mtCurrent;
547 static inline ITestPinImpl *impl_from_IPin(IPin *iface)
549 return CONTAINING_RECORD(iface, ITestPinImpl, IPin_iface);
552 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
556 if (IsEqualIID(riid, &IID_IUnknown))
558 else if (IsEqualIID(riid, &IID_IPin))
563 IUnknown_AddRef((IUnknown *)(*ppv));
567 return E_NOINTERFACE;
570 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
572 ITestPinImpl *This = impl_from_IPin(iface);
573 ULONG refCount = InterlockedIncrement(&This->refCount);
577 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
579 ITestPinImpl *This = impl_from_IPin(iface);
580 ULONG refCount = InterlockedDecrement(&This->refCount);
584 FreeMediaType(&This->mtCurrent);
592 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
597 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
599 ITestPinImpl *This = impl_from_IPin(iface);
600 PIN_DIRECTION pindirReceive;
603 EnterCriticalSection(This->pCritSec);
605 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
606 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
607 hr = VFW_E_TYPE_NOT_ACCEPTED;
609 if (This->pConnectedTo)
610 hr = VFW_E_ALREADY_CONNECTED;
614 IPin_QueryDirection(pReceivePin, &pindirReceive);
616 if (pindirReceive != PINDIR_OUTPUT)
618 hr = VFW_E_INVALID_DIRECTION;
624 CopyMediaType(&This->mtCurrent, pmt);
625 This->pConnectedTo = pReceivePin;
626 IPin_AddRef(pReceivePin);
629 LeaveCriticalSection(This->pCritSec);
634 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
637 ITestPinImpl *This = impl_from_IPin(iface);
639 EnterCriticalSection(This->pCritSec);
641 if (This->pConnectedTo)
643 IPin_Release(This->pConnectedTo);
644 This->pConnectedTo = NULL;
650 LeaveCriticalSection(This->pCritSec);
655 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
658 ITestPinImpl *This = impl_from_IPin(iface);
660 EnterCriticalSection(This->pCritSec);
662 if (This->pConnectedTo)
664 *ppPin = This->pConnectedTo;
670 hr = VFW_E_NOT_CONNECTED;
674 LeaveCriticalSection(This->pCritSec);
679 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
682 ITestPinImpl *This = impl_from_IPin(iface);
684 EnterCriticalSection(This->pCritSec);
686 if (This->pConnectedTo)
688 CopyMediaType(pmt, &This->mtCurrent);
693 ZeroMemory(pmt, sizeof(*pmt));
694 hr = VFW_E_NOT_CONNECTED;
697 LeaveCriticalSection(This->pCritSec);
702 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
704 ITestPinImpl *This = impl_from_IPin(iface);
706 Copy_PinInfo(pInfo, &This->pinInfo);
707 IBaseFilter_AddRef(pInfo->pFilter);
712 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
714 ITestPinImpl *This = impl_from_IPin(iface);
716 *pPinDir = This->pinInfo.dir;
721 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
726 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
728 ITestPinImpl *This = impl_from_IPin(iface);
730 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
731 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
734 return VFW_E_TYPE_NOT_ACCEPTED;
737 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
739 ITestPinImpl *This = impl_from_IPin(iface);
741 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
744 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
749 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
754 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
759 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
764 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
769 static const IPinVtbl TestFilter_InputPin_Vtbl =
771 TestFilter_Pin_QueryInterface,
772 TestFilter_Pin_AddRef,
773 TestFilter_Pin_Release,
774 TestFilter_InputPin_Connect,
775 TestFilter_InputPin_ReceiveConnection,
776 TestFilter_Pin_Disconnect,
777 TestFilter_Pin_ConnectedTo,
778 TestFilter_Pin_ConnectionMediaType,
779 TestFilter_Pin_QueryPinInfo,
780 TestFilter_Pin_QueryDirection,
781 TestFilter_Pin_QueryId,
782 TestFilter_Pin_QueryAccept,
783 TestFilter_Pin_EnumMediaTypes,
784 TestFilter_Pin_QueryInternalConnections,
785 TestFilter_Pin_EndOfStream,
786 TestFilter_Pin_BeginFlush,
787 TestFilter_Pin_EndFlush,
788 TestFilter_Pin_NewSegment
791 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
796 /* Private helper function */
797 static HRESULT TestFilter_OutputPin_ConnectSpecific(ITestPinImpl * This, IPin * pReceivePin,
798 const AM_MEDIA_TYPE * pmt)
802 This->pConnectedTo = pReceivePin;
803 IPin_AddRef(pReceivePin);
805 hr = IPin_ReceiveConnection(pReceivePin, &This->IPin_iface, pmt);
809 IPin_Release(This->pConnectedTo);
810 This->pConnectedTo = NULL;
816 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
818 ITestPinImpl *This = impl_from_IPin(iface);
821 EnterCriticalSection(This->pCritSec);
823 /* if we have been a specific type to connect with, then we can either connect
824 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
825 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
826 hr = TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, pmt);
829 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
830 (TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, &This->mtCurrent) == S_OK))
832 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
833 } /* if negotiate media type */
835 LeaveCriticalSection(This->pCritSec);
840 static const IPinVtbl TestFilter_OutputPin_Vtbl =
842 TestFilter_Pin_QueryInterface,
843 TestFilter_Pin_AddRef,
844 TestFilter_Pin_Release,
845 TestFilter_OutputPin_Connect,
846 TestFilter_OutputPin_ReceiveConnection,
847 TestFilter_Pin_Disconnect,
848 TestFilter_Pin_ConnectedTo,
849 TestFilter_Pin_ConnectionMediaType,
850 TestFilter_Pin_QueryPinInfo,
851 TestFilter_Pin_QueryDirection,
852 TestFilter_Pin_QueryId,
853 TestFilter_Pin_QueryAccept,
854 TestFilter_Pin_EnumMediaTypes,
855 TestFilter_Pin_QueryInternalConnections,
856 TestFilter_Pin_EndOfStream,
857 TestFilter_Pin_BeginFlush,
858 TestFilter_Pin_EndFlush,
859 TestFilter_Pin_NewSegment
862 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
863 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
865 ITestPinImpl * pPinImpl;
869 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
872 return E_OUTOFMEMORY;
874 pPinImpl->refCount = 1;
875 pPinImpl->pConnectedTo = NULL;
876 pPinImpl->pCritSec = pCritSec;
877 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
878 pPinImpl->mtCurrent = *pinmt;
880 pPinImpl->IPin_iface.lpVtbl = Pin_Vtbl;
882 *ppPin = &pPinImpl->IPin_iface;
886 /* IEnumPins implementation */
888 typedef HRESULT (* FNOBTAINPIN)(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick);
890 typedef struct IEnumPinsImpl
892 IEnumPins IEnumPins_iface;
895 TestFilterImpl *base;
896 FNOBTAINPIN receive_pin;
900 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
902 static inline IEnumPinsImpl *impl_from_IEnumPins(IEnumPins *iface)
904 return CONTAINING_RECORD(iface, IEnumPinsImpl, IEnumPins_iface);
907 static HRESULT createenumpins(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, TestFilterImpl *base)
909 IEnumPinsImpl * pEnumPins;
914 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
918 return E_OUTOFMEMORY;
920 pEnumPins->IEnumPins_iface.lpVtbl = &IEnumPinsImpl_Vtbl;
921 pEnumPins->refCount = 1;
922 pEnumPins->uIndex = 0;
923 pEnumPins->receive_pin = receive_pin;
924 pEnumPins->base = base;
925 IBaseFilter_AddRef(&base->IBaseFilter_iface);
926 *ppEnum = &pEnumPins->IEnumPins_iface;
928 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
933 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
937 if (IsEqualIID(riid, &IID_IUnknown))
939 else if (IsEqualIID(riid, &IID_IEnumPins))
944 IUnknown_AddRef((IUnknown *)(*ppv));
948 return E_NOINTERFACE;
951 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
953 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
954 ULONG refCount = InterlockedIncrement(&This->refCount);
959 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
961 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
962 ULONG refCount = InterlockedDecrement(&This->refCount);
966 IBaseFilter_Release(&This->base->IBaseFilter_iface);
974 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
976 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
977 DWORD synctime = This->synctime;
984 if (cPins > 1 && !pcFetched)
990 while (i < cPins && hr == S_OK)
992 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
997 if (synctime != This->synctime)
1001 if (!i && synctime != This->synctime)
1002 return VFW_E_ENUM_OUT_OF_SYNC;
1013 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
1015 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1016 DWORD synctime = This->synctime;
1020 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
1024 if (synctime != This->synctime)
1025 return VFW_E_ENUM_OUT_OF_SYNC;
1028 This->uIndex += cPins;
1033 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1035 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1037 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1043 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1046 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1048 hr = createenumpins(ppEnum, This->receive_pin, This->base);
1051 return IEnumPins_Skip(*ppEnum, This->uIndex);
1054 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1056 IEnumPinsImpl_QueryInterface,
1057 IEnumPinsImpl_AddRef,
1058 IEnumPinsImpl_Release,
1061 IEnumPinsImpl_Reset,
1065 /* Test filter implementation - a filter that has few predefined pins with single media type
1066 * that accept only this single media type. Enough for Render(). */
1068 typedef struct TestFilterPinData
1070 PIN_DIRECTION pinDir;
1071 const GUID *mediasubtype;
1072 } TestFilterPinData;
1074 static const IBaseFilterVtbl TestFilter_Vtbl;
1076 static inline TestFilterImpl *impl_from_IBaseFilter(IBaseFilter *iface)
1078 return CONTAINING_RECORD(iface, TestFilterImpl, IBaseFilter_iface);
1081 static HRESULT createtestfilter(const CLSID* pClsid, const TestFilterPinData *pinData,
1082 TestFilterImpl **tf)
1084 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1085 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1088 TestFilterImpl* pTestFilter = NULL;
1092 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1093 if (!pTestFilter) return E_OUTOFMEMORY;
1095 pTestFilter->clsid = *pClsid;
1096 pTestFilter->IBaseFilter_iface.lpVtbl = &TestFilter_Vtbl;
1097 pTestFilter->refCount = 1;
1098 InitializeCriticalSection(&pTestFilter->csFilter);
1099 pTestFilter->state = State_Stopped;
1101 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1104 while(pinData[nPins].mediasubtype) ++nPins;
1106 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1107 if (!pTestFilter->ppPins)
1112 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1114 for (i = 0; i < nPins; i++)
1116 ZeroMemory(&mt, sizeof(mt));
1117 mt.majortype = MEDIATYPE_Video;
1118 mt.formattype = FORMAT_None;
1119 mt.subtype = *pinData[i].mediasubtype;
1121 pinInfo.dir = pinData[i].pinDir;
1122 pinInfo.pFilter = &pTestFilter->IBaseFilter_iface;
1123 if (pinInfo.dir == PINDIR_INPUT)
1125 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1126 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1127 &pTestFilter->ppPins[i]);
1132 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1133 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1134 &pTestFilter->ppPins[i]);
1136 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1139 pTestFilter->nPins = nPins;
1145 if (pTestFilter->ppPins)
1147 for (i = 0; i < nPins; i++)
1149 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1152 CoTaskMemFree(pTestFilter->ppPins);
1153 DeleteCriticalSection(&pTestFilter->csFilter);
1154 CoTaskMemFree(pTestFilter);
1159 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1161 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1165 if (IsEqualIID(riid, &IID_IUnknown))
1167 else if (IsEqualIID(riid, &IID_IPersist))
1169 else if (IsEqualIID(riid, &IID_IMediaFilter))
1171 else if (IsEqualIID(riid, &IID_IBaseFilter))
1176 IUnknown_AddRef((IUnknown *)(*ppv));
1180 return E_NOINTERFACE;
1183 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1185 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1186 ULONG refCount = InterlockedIncrement(&This->refCount);
1191 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1193 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1194 ULONG refCount = InterlockedDecrement(&This->refCount);
1200 for (i = 0; i < This->nPins; i++)
1204 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1206 IPin_Disconnect(pConnectedTo);
1207 IPin_Release(pConnectedTo);
1209 IPin_Disconnect(This->ppPins[i]);
1211 IPin_Release(This->ppPins[i]);
1214 CoTaskMemFree(This->ppPins);
1216 DeleteCriticalSection(&This->csFilter);
1218 CoTaskMemFree(This);
1225 /** IPersist methods **/
1227 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1229 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1231 *pClsid = This->clsid;
1236 /** IMediaFilter methods **/
1238 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1243 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1248 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1253 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1255 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1257 EnterCriticalSection(&This->csFilter);
1259 *pState = This->state;
1261 LeaveCriticalSection(&This->csFilter);
1266 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1271 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1276 /** IBaseFilter implementation **/
1278 static HRESULT getpin_callback(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick)
1280 /* Our pins are static, not changing so setting static tick count is ok */
1283 if (pos >= tf->nPins)
1286 *pin = tf->ppPins[pos];
1291 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1293 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1295 return createenumpins(ppEnum, getpin_callback, This);
1298 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1303 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1305 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1307 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1308 pInfo->pGraph = This->filterInfo.pGraph;
1311 IFilterGraph_AddRef(pInfo->pGraph);
1316 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1319 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1321 EnterCriticalSection(&This->csFilter);
1324 lstrcpyW(This->filterInfo.achName, pName);
1326 *This->filterInfo.achName = '\0';
1327 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1329 LeaveCriticalSection(&This->csFilter);
1334 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1339 static const IBaseFilterVtbl TestFilter_Vtbl =
1341 TestFilter_QueryInterface,
1344 TestFilter_GetClassID,
1348 TestFilter_GetState,
1349 TestFilter_SetSyncSource,
1350 TestFilter_GetSyncSource,
1351 TestFilter_EnumPins,
1353 TestFilter_QueryFilterInfo,
1354 TestFilter_JoinFilterGraph,
1355 TestFilter_QueryVendorInfo
1358 /* IClassFactory implementation */
1360 typedef struct TestClassFactoryImpl
1362 IClassFactory IClassFactory_iface;
1363 const TestFilterPinData *filterPinData;
1365 } TestClassFactoryImpl;
1367 static inline TestClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
1369 return CONTAINING_RECORD(iface, TestClassFactoryImpl, IClassFactory_iface);
1372 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1373 LPCLASSFACTORY iface,
1377 if (ppvObj == NULL) return E_POINTER;
1379 if (IsEqualGUID(riid, &IID_IUnknown) ||
1380 IsEqualGUID(riid, &IID_IClassFactory))
1383 IClassFactory_AddRef(iface);
1388 return E_NOINTERFACE;
1391 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1393 return 2; /* non-heap-based object */
1396 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1398 return 1; /* non-heap-based object */
1401 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1402 LPCLASSFACTORY iface,
1403 LPUNKNOWN pUnkOuter,
1407 TestClassFactoryImpl *This = impl_from_IClassFactory(iface);
1409 TestFilterImpl *testfilter;
1413 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1415 hr = createtestfilter(This->clsid, This->filterPinData, &testfilter);
1416 if (SUCCEEDED(hr)) {
1417 hr = IBaseFilter_QueryInterface(&testfilter->IBaseFilter_iface, riid, ppvObj);
1418 IBaseFilter_Release(&testfilter->IBaseFilter_iface);
1423 static HRESULT WINAPI Test_IClassFactory_LockServer(
1424 LPCLASSFACTORY iface,
1430 static IClassFactoryVtbl TestClassFactory_Vtbl =
1432 Test_IClassFactory_QueryInterface,
1433 Test_IClassFactory_AddRef,
1434 Test_IClassFactory_Release,
1435 Test_IClassFactory_CreateInstance,
1436 Test_IClassFactory_LockServer
1439 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1443 FILTER_INFO filterInfo;
1448 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1449 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1450 if (FAILED(hr)) return hr;
1452 hr = IPin_QueryPinInfo(pin, &pinInfo);
1453 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1455 if (FAILED(hr)) return hr;
1457 SetLastError(0xdeadbeef);
1458 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1459 if (hr == S_OK && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1461 IBaseFilter_Release(pinInfo.pFilter);
1464 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1465 IBaseFilter_Release(pinInfo.pFilter);
1466 if (FAILED(hr)) return hr;
1468 IFilterGraph_Release(filterInfo.pGraph);
1470 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1475 static void test_render_filter_priority(void)
1477 /* Tests filter choice priorities in Render(). */
1478 DWORD cookie1 = 0, cookie2 = 0, cookie3 = 0;
1480 IFilterGraph2* pgraph2 = NULL;
1481 IFilterMapper2 *pMapper2 = NULL;
1482 TestFilterImpl *ptestfilter = NULL;
1483 TestFilterImpl *ptestfilter2 = NULL;
1484 static const CLSID CLSID_TestFilter2 = {
1488 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1490 static const CLSID CLSID_TestFilter3 = {
1494 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1496 static const CLSID CLSID_TestFilter4 = {
1500 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1502 static const GUID mediasubtype1 = {
1506 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1508 static const GUID mediasubtype2 = {
1512 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1514 static const TestFilterPinData PinData1[] = {
1515 { PINDIR_OUTPUT, &mediasubtype1 },
1518 static const TestFilterPinData PinData2[] = {
1519 { PINDIR_INPUT, &mediasubtype1 },
1522 static const TestFilterPinData PinData3[] = {
1523 { PINDIR_INPUT, &GUID_NULL },
1526 static const TestFilterPinData PinData4[] = {
1527 { PINDIR_INPUT, &mediasubtype1 },
1528 { PINDIR_OUTPUT, &mediasubtype2 },
1531 static const TestFilterPinData PinData5[] = {
1532 { PINDIR_INPUT, &mediasubtype2 },
1535 TestClassFactoryImpl Filter1ClassFactory = {
1536 { &TestClassFactory_Vtbl },
1537 PinData2, &CLSID_TestFilter2
1539 TestClassFactoryImpl Filter2ClassFactory = {
1540 { &TestClassFactory_Vtbl },
1541 PinData4, &CLSID_TestFilter3
1543 TestClassFactoryImpl Filter3ClassFactory = {
1544 { &TestClassFactory_Vtbl },
1545 PinData5, &CLSID_TestFilter4
1547 char ConnectedFilterName1[MAX_FILTER_NAME];
1548 char ConnectedFilterName2[MAX_FILTER_NAME];
1550 REGFILTERPINS2 rgPins2[2];
1551 REGPINTYPES rgPinType[2];
1552 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1553 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1554 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1555 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1556 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1557 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1558 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1559 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1561 /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is
1562 "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating
1563 no preference given to exact match. */
1564 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1565 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1566 if (!pgraph2) return;
1568 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1569 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1570 if (FAILED(hr)) goto out;
1572 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1573 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1575 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1576 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1577 if (FAILED(hr)) goto out;
1579 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1580 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1582 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1583 ptestfilter2 = NULL;
1585 hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1586 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1587 if (FAILED(hr)) goto out;
1589 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1590 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1592 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1593 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1595 hr = get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1597 IFilterGraph2_Release(pgraph2);
1599 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1601 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1602 ptestfilter2 = NULL;
1604 if (hr == E_NOTIMPL)
1606 win_skip("Needed functions are not implemented\n");
1610 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1611 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1612 if (!pgraph2) goto out;
1614 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1615 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1616 if (FAILED(hr)) goto out;
1618 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1619 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1621 hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1622 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1623 if (FAILED(hr)) goto out;
1625 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1626 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1628 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1629 ptestfilter2 = NULL;
1631 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1632 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1633 if (FAILED(hr)) goto out;
1635 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1636 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1638 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1639 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1641 hr = IFilterGraph2_Disconnect(pgraph2, NULL);
1642 ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr);
1644 get_connected_filter_name(ptestfilter, ConnectedFilterName2);
1645 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1646 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1648 IFilterGraph2_Release(pgraph2);
1650 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1652 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1653 ptestfilter2 = NULL;
1655 /* Test if any preference is given to existing renderer which renders the pin directly vs
1656 an existing renderer which renders the pin indirectly, through an additional middle filter,
1657 again trying different orders of creation. Native appears not to give a preference. */
1659 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1660 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1661 if (!pgraph2) goto out;
1663 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1664 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1665 if (FAILED(hr)) goto out;
1667 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1668 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1670 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1671 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1672 if (FAILED(hr)) goto out;
1674 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1675 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1677 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1678 ptestfilter2 = NULL;
1680 hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
1681 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1682 if (FAILED(hr)) goto out;
1684 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1685 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1687 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1688 ptestfilter2 = NULL;
1690 hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2);
1691 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1692 if (FAILED(hr)) goto out;
1694 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4);
1695 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1697 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1698 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1700 get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1701 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1, "TestfilterInstance2"),
1702 "unexpected connected filter: %s\n", ConnectedFilterName1);
1704 IFilterGraph2_Release(pgraph2);
1706 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1708 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1709 ptestfilter2 = NULL;
1711 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1712 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1713 if (!pgraph2) goto out;
1715 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1716 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1717 if (FAILED(hr)) goto out;
1719 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1720 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1722 hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
1723 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1724 if (FAILED(hr)) goto out;
1726 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1727 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1729 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1730 ptestfilter2 = NULL;
1732 hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2);
1733 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1734 if (FAILED(hr)) goto out;
1736 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4);
1737 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1739 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1740 ptestfilter2 = NULL;
1742 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1743 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1744 if (FAILED(hr)) goto out;
1746 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1747 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1749 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1750 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1752 get_connected_filter_name(ptestfilter, ConnectedFilterName2);
1753 ok(!lstrcmp(ConnectedFilterName2, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2, "TestfilterInstance2"),
1754 "unexpected connected filter: %s\n", ConnectedFilterName2);
1755 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1756 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1758 IFilterGraph2_Release(pgraph2);
1760 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1762 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1763 ptestfilter2 = NULL;
1765 /* Test if renderers are tried before non-renderers (intermediary filters). */
1766 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1767 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1768 if (!pgraph2) goto out;
1770 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
1771 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1772 if (!pMapper2) goto out;
1774 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1775 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1776 if (FAILED(hr)) goto out;
1778 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1779 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1781 /* Register our filters with COM and with Filtermapper. */
1782 hr = CoRegisterClassObject(Filter1ClassFactory.clsid,
1783 (IUnknown *)&Filter1ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1784 REGCLS_MULTIPLEUSE, &cookie1);
1785 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1786 if (FAILED(hr)) goto out;
1787 hr = CoRegisterClassObject(Filter2ClassFactory.clsid,
1788 (IUnknown *)&Filter2ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1789 REGCLS_MULTIPLEUSE, &cookie2);
1790 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1791 if (FAILED(hr)) goto out;
1792 hr = CoRegisterClassObject(Filter3ClassFactory.clsid,
1793 (IUnknown *)&Filter3ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1794 REGCLS_MULTIPLEUSE, &cookie3);
1795 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1796 if (FAILED(hr)) goto out;
1799 rgf2.dwMerit = MERIT_UNLIKELY;
1800 S1(U(rgf2)).cPins2 = 1;
1801 S1(U(rgf2)).rgPins2 = rgPins2;
1802 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
1803 rgPins2[0].cInstances = 1;
1804 rgPins2[0].nMediaTypes = 1;
1805 rgPins2[0].lpMediaType = &rgPinType[0];
1806 rgPins2[0].nMediums = 0;
1807 rgPins2[0].lpMedium = NULL;
1808 rgPins2[0].clsPinCategory = NULL;
1809 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
1810 rgPinType[0].clsMinorType = &mediasubtype1;
1812 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
1813 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1814 if (hr == E_ACCESSDENIED)
1815 skip("Not authorized to register filters\n");
1818 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1820 rgf2.dwMerit = MERIT_PREFERRED;
1821 rgPinType[0].clsMinorType = &mediasubtype2;
1823 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
1824 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1825 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1827 S1(U(rgf2)).cPins2 = 2;
1828 rgPins2[0].dwFlags = 0;
1829 rgPinType[0].clsMinorType = &mediasubtype1;
1831 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
1832 rgPins2[1].cInstances = 1;
1833 rgPins2[1].nMediaTypes = 1;
1834 rgPins2[1].lpMediaType = &rgPinType[1];
1835 rgPins2[1].nMediums = 0;
1836 rgPins2[1].lpMedium = NULL;
1837 rgPins2[1].clsPinCategory = NULL;
1838 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
1839 rgPinType[1].clsMinorType = &mediasubtype2;
1841 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
1842 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1843 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1845 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1846 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1848 get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1849 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3"),
1850 "unexpected connected filter: %s\n", ConnectedFilterName1);
1853 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1854 &CLSID_TestFilter2);
1855 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1856 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1857 &CLSID_TestFilter3);
1858 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1859 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1860 &CLSID_TestFilter4);
1861 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1865 if (ptestfilter) IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1866 if (ptestfilter2) IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1867 if (pgraph2) IFilterGraph2_Release(pgraph2);
1868 if (pMapper2) IFilterMapper2_Release(pMapper2);
1870 hr = CoRevokeClassObject(cookie1);
1871 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1872 hr = CoRevokeClassObject(cookie2);
1873 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1874 hr = CoRevokeClassObject(cookie3);
1875 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1878 START_TEST(filtergraph)
1881 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1882 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
1883 &IID_IGraphBuilder, (LPVOID*)&pgraph);
1885 skip("Creating filtergraph returned %08x, skipping tests\n", hr);
1888 test_render_run(avifile);
1889 test_render_run(mpegfile);
1890 test_graph_builder();
1891 test_graph_builder_addfilter();
1892 test_mediacontrol();
1893 test_filter_graph2();
1894 test_render_filter_priority();