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
25 #include "wine/test.h"
29 typedef struct TestFilterImpl
31 IBaseFilter IBaseFilter_iface;
34 CRITICAL_SECTION csFilter;
36 FILTER_INFO filterInfo;
42 static const WCHAR avifile[] = {'t','e','s','t','.','a','v','i',0};
43 static const WCHAR mpegfile[] = {'t','e','s','t','.','m','p','g',0};
45 static IGraphBuilder *pgraph;
47 static int createfiltergraph(void)
49 return S_OK == CoCreateInstance(
50 &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&pgraph);
53 static void rungraph(void)
61 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (LPVOID*)&pmc);
62 ok(hr==S_OK, "Cannot get IMediaControl interface returned: %x\n", hr);
64 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (LPVOID*)&pmf);
65 ok(hr==S_OK, "Cannot get IMediaFilter interface returned: %x\n", hr);
67 IMediaControl_Stop(pmc);
69 IMediaFilter_SetSyncSource(pmf, NULL);
71 IMediaFilter_Release(pmf);
73 hr = IMediaControl_Run(pmc);
74 ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr);
78 trace("run -> stop\n");
79 hr = IMediaControl_Stop(pmc);
80 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
82 IGraphBuilder_SetDefaultSyncSource(pgraph);
85 trace("stop -> pause\n");
86 hr = IMediaControl_Pause(pmc);
87 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
90 trace("pause -> run\n");
91 hr = IMediaControl_Run(pmc);
92 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
95 trace("run -> pause\n");
96 hr = IMediaControl_Pause(pmc);
97 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
100 trace("pause -> stop\n");
101 hr = IMediaControl_Stop(pmc);
102 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
105 trace("pause -> run\n");
106 hr = IMediaControl_Run(pmc);
107 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
109 trace("run -> stop\n");
110 hr = IMediaControl_Stop(pmc);
111 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
113 trace("stop -> run\n");
114 hr = IMediaControl_Run(pmc);
115 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
117 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaEvent, (LPVOID*)&pme);
118 ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr);
120 hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent);
121 ok(hr==S_OK, "Cannot get event handle returned: %x\n", hr);
123 /* WaitForSingleObject(hEvent, INFINITE); */
126 hr = IMediaEvent_Release(pme);
127 ok(hr==2, "Releasing mediaevent returned: %x\n", hr);
129 hr = IMediaControl_Stop(pmc);
130 ok(hr==S_OK, "Cannot stop the graph returned: %x\n", hr);
132 hr = IMediaControl_Release(pmc);
133 ok(hr==1, "Releasing mediacontrol returned: %x\n", hr);
136 static void releasefiltergraph(void)
140 hr = IGraphBuilder_Release(pgraph);
141 ok(hr==0, "Releasing filtergraph returned: %x\n", hr);
144 static void test_render_run(const WCHAR *file)
149 if (!createfiltergraph())
152 h = CreateFileW(file, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
153 if (h != INVALID_HANDLE_VALUE) {
155 hr = IGraphBuilder_RenderFile(pgraph, file, NULL);
156 ok(hr==S_OK, "RenderFile returned: %x\n", hr);
160 releasefiltergraph();
163 static void test_graph_builder(void)
166 IBaseFilter *pF = NULL;
167 IBaseFilter *pF2 = NULL;
169 IEnumPins *pEnum = NULL;
171 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
172 static const WCHAR fooBarW[] = {'f','o','o','B','a','r',0};
174 if (!createfiltergraph())
177 /* create video filter */
178 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
179 &IID_IBaseFilter, (LPVOID*)&pF);
180 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
181 ok(pF != NULL, "pF is NULL\n");
183 /* add the two filters to the graph */
184 hr = IGraphBuilder_AddFilter(pgraph, pF, testFilterW);
185 ok(hr == S_OK, "failed to add pF to the graph: %x\n", hr);
188 hr = IBaseFilter_EnumPins(pF, &pEnum);
189 ok(hr == S_OK, "IBaseFilter_EnumPins failed for pF: %x\n", hr);
190 ok(pEnum != NULL, "pEnum is NULL\n");
191 hr = IEnumPins_Next(pEnum, 1, &pIn, NULL);
192 ok(hr == S_OK, "IEnumPins_Next failed for pF: %x\n", hr);
193 ok(pIn != NULL, "pIn is NULL\n");
194 hr = IPin_QueryDirection(pIn, &dir);
195 ok(hr == S_OK, "IPin_QueryDirection failed: %x\n", hr);
196 ok(dir == PINDIR_INPUT, "pin has wrong direction\n");
198 hr = IGraphBuilder_FindFilterByName(pgraph, fooBarW, &pF2);
199 ok(hr == VFW_E_NOT_FOUND, "IGraphBuilder_FindFilterByName returned %x\n", hr);
200 ok(pF2 == NULL, "IGraphBuilder_FindFilterByName returned %p\n", pF2);
201 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, &pF2);
202 ok(hr == S_OK, "IGraphBuilder_FindFilterByName returned %x\n", hr);
203 ok(pF2 != NULL, "IGraphBuilder_FindFilterByName returned NULL\n");
204 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, NULL);
205 ok(hr == E_POINTER, "IGraphBuilder_FindFilterByName returned %x\n", hr);
207 if (pIn) IPin_Release(pIn);
208 if (pEnum) IEnumPins_Release(pEnum);
209 if (pF) IBaseFilter_Release(pF);
210 if (pF2) IBaseFilter_Release(pF2);
212 releasefiltergraph();
215 static void test_graph_builder_addfilter(void)
218 IBaseFilter *pF = NULL;
219 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
221 if (!createfiltergraph())
224 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
225 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr);
227 /* create video filter */
228 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
229 &IID_IBaseFilter, (LPVOID*)&pF);
230 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
231 ok(pF != NULL, "pF is NULL\n");
233 skip("failed to created filter, skipping\n");
237 hr = IGraphBuilder_AddFilter(pgraph, pF, NULL);
238 ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr);
239 IBaseFilter_Release(pF);
242 static void test_mediacontrol(void)
245 LONGLONG pos = 0xdeadbeef;
246 IMediaSeeking *seeking = NULL;
247 IMediaFilter *filter = NULL;
248 IMediaControl *control = NULL;
250 IGraphBuilder_SetDefaultSyncSource(pgraph);
251 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking);
252 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
256 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
257 ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
260 IMediaSeeking_Release(seeking);
264 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
265 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
268 IMediaSeeking_Release(seeking);
269 IMediaFilter_Release(filter);
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 = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_ReturnTime, NULL, AM_SEEKING_NoPositioning);
278 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
279 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_NoPositioning, NULL, AM_SEEKING_ReturnTime);
280 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
282 IMediaFilter_SetSyncSource(filter, NULL);
284 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
285 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
286 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
288 hr = IMediaControl_GetState(control, 1000, NULL);
289 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
291 IMediaControl_Release(control);
292 IMediaSeeking_Release(seeking);
293 IMediaFilter_Release(filter);
294 releasefiltergraph();
297 static void test_filter_graph2(void)
300 IFilterGraph2 *pF = NULL;
302 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
303 &IID_IFilterGraph2, (LPVOID*)&pF);
304 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
305 ok(pF != NULL, "pF is NULL\n");
307 hr = IFilterGraph2_Release(pF);
308 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
311 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
312 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
314 if (pMediaType->pbFormat)
316 CoTaskMemFree(pMediaType->pbFormat);
317 pMediaType->pbFormat = NULL;
319 if (pMediaType->pUnk)
321 IUnknown_Release(pMediaType->pUnk);
322 pMediaType->pUnk = NULL;
326 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
329 if (!pSrc->pbFormat) return S_OK;
330 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
331 return E_OUTOFMEMORY;
332 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
334 IUnknown_AddRef(pDest->pUnk);
338 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
340 AM_MEDIA_TYPE * pDest;
342 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
346 if (FAILED(CopyMediaType(pDest, pSrc)))
348 CoTaskMemFree(pDest);
355 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
357 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
358 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
361 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
363 FreeMediaType(pMediaType);
364 CoTaskMemFree(pMediaType);
367 typedef struct IEnumMediaTypesImpl
369 IEnumMediaTypes IEnumMediaTypes_iface;
371 AM_MEDIA_TYPE *pMediaTypes;
374 } IEnumMediaTypesImpl;
376 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
378 static inline IEnumMediaTypesImpl *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
380 return CONTAINING_RECORD(iface, IEnumMediaTypesImpl, IEnumMediaTypes_iface);
383 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
386 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
388 if (!pEnumMediaTypes)
391 return E_OUTOFMEMORY;
393 pEnumMediaTypes->IEnumMediaTypes_iface.lpVtbl = &IEnumMediaTypesImpl_Vtbl;
394 pEnumMediaTypes->refCount = 1;
395 pEnumMediaTypes->uIndex = 0;
396 pEnumMediaTypes->cMediaTypes = cMediaTypes;
397 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
398 for (i = 0; i < cMediaTypes; i++)
399 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
402 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
403 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
404 return E_OUTOFMEMORY;
406 *ppEnum = &pEnumMediaTypes->IEnumMediaTypes_iface;
410 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
414 if (IsEqualIID(riid, &IID_IUnknown))
416 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
421 IUnknown_AddRef((IUnknown *)(*ppv));
425 return E_NOINTERFACE;
428 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
430 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
431 ULONG refCount = InterlockedIncrement(&This->refCount);
436 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
438 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
439 ULONG refCount = InterlockedDecrement(&This->refCount);
444 for (i = 0; i < This->cMediaTypes; i++)
445 FreeMediaType(&This->pMediaTypes[i]);
446 CoTaskMemFree(This->pMediaTypes);
452 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
455 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
457 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
462 for (i = 0; i < cFetched; i++)
463 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
466 DeleteMediaType(ppMediaTypes[i]);
468 return E_OUTOFMEMORY;
472 if ((cMediaTypes != 1) || pcFetched)
473 *pcFetched = cFetched;
475 This->uIndex += cFetched;
477 if (cFetched != cMediaTypes)
482 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
484 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
486 if (This->uIndex + cMediaTypes < This->cMediaTypes)
488 This->uIndex += cMediaTypes;
494 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
496 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
502 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
505 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
507 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
510 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
513 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
515 IEnumMediaTypesImpl_QueryInterface,
516 IEnumMediaTypesImpl_AddRef,
517 IEnumMediaTypesImpl_Release,
518 IEnumMediaTypesImpl_Next,
519 IEnumMediaTypesImpl_Skip,
520 IEnumMediaTypesImpl_Reset,
521 IEnumMediaTypesImpl_Clone
524 /* Implementation of a very stripped down pin for the test filter. Just enough
525 functionality for connecting and Render() to work. */
527 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
529 lstrcpyW(pDest->achName, pSrc->achName);
530 pDest->dir = pSrc->dir;
531 pDest->pFilter = pSrc->pFilter;
534 typedef struct ITestPinImpl
538 LPCRITICAL_SECTION pCritSec;
541 AM_MEDIA_TYPE mtCurrent;
545 static inline ITestPinImpl *impl_from_IPin(IPin *iface)
547 return CONTAINING_RECORD(iface, ITestPinImpl, IPin_iface);
550 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
554 if (IsEqualIID(riid, &IID_IUnknown))
556 else if (IsEqualIID(riid, &IID_IPin))
561 IUnknown_AddRef((IUnknown *)(*ppv));
565 return E_NOINTERFACE;
568 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
570 ITestPinImpl *This = impl_from_IPin(iface);
571 ULONG refCount = InterlockedIncrement(&This->refCount);
575 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
577 ITestPinImpl *This = impl_from_IPin(iface);
578 ULONG refCount = InterlockedDecrement(&This->refCount);
582 FreeMediaType(&This->mtCurrent);
590 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
595 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
597 ITestPinImpl *This = impl_from_IPin(iface);
598 PIN_DIRECTION pindirReceive;
601 EnterCriticalSection(This->pCritSec);
603 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
604 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
605 hr = VFW_E_TYPE_NOT_ACCEPTED;
607 if (This->pConnectedTo)
608 hr = VFW_E_ALREADY_CONNECTED;
612 IPin_QueryDirection(pReceivePin, &pindirReceive);
614 if (pindirReceive != PINDIR_OUTPUT)
616 hr = VFW_E_INVALID_DIRECTION;
622 CopyMediaType(&This->mtCurrent, pmt);
623 This->pConnectedTo = pReceivePin;
624 IPin_AddRef(pReceivePin);
627 LeaveCriticalSection(This->pCritSec);
632 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
635 ITestPinImpl *This = impl_from_IPin(iface);
637 EnterCriticalSection(This->pCritSec);
639 if (This->pConnectedTo)
641 IPin_Release(This->pConnectedTo);
642 This->pConnectedTo = NULL;
648 LeaveCriticalSection(This->pCritSec);
653 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
656 ITestPinImpl *This = impl_from_IPin(iface);
658 EnterCriticalSection(This->pCritSec);
660 if (This->pConnectedTo)
662 *ppPin = This->pConnectedTo;
668 hr = VFW_E_NOT_CONNECTED;
672 LeaveCriticalSection(This->pCritSec);
677 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
680 ITestPinImpl *This = impl_from_IPin(iface);
682 EnterCriticalSection(This->pCritSec);
684 if (This->pConnectedTo)
686 CopyMediaType(pmt, &This->mtCurrent);
691 ZeroMemory(pmt, sizeof(*pmt));
692 hr = VFW_E_NOT_CONNECTED;
695 LeaveCriticalSection(This->pCritSec);
700 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
702 ITestPinImpl *This = impl_from_IPin(iface);
704 Copy_PinInfo(pInfo, &This->pinInfo);
705 IBaseFilter_AddRef(pInfo->pFilter);
710 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
712 ITestPinImpl *This = impl_from_IPin(iface);
714 *pPinDir = This->pinInfo.dir;
719 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
724 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
726 ITestPinImpl *This = impl_from_IPin(iface);
728 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
729 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
732 return VFW_E_TYPE_NOT_ACCEPTED;
735 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
737 ITestPinImpl *This = impl_from_IPin(iface);
739 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
742 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
747 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
752 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
757 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
762 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
767 static const IPinVtbl TestFilter_InputPin_Vtbl =
769 TestFilter_Pin_QueryInterface,
770 TestFilter_Pin_AddRef,
771 TestFilter_Pin_Release,
772 TestFilter_InputPin_Connect,
773 TestFilter_InputPin_ReceiveConnection,
774 TestFilter_Pin_Disconnect,
775 TestFilter_Pin_ConnectedTo,
776 TestFilter_Pin_ConnectionMediaType,
777 TestFilter_Pin_QueryPinInfo,
778 TestFilter_Pin_QueryDirection,
779 TestFilter_Pin_QueryId,
780 TestFilter_Pin_QueryAccept,
781 TestFilter_Pin_EnumMediaTypes,
782 TestFilter_Pin_QueryInternalConnections,
783 TestFilter_Pin_EndOfStream,
784 TestFilter_Pin_BeginFlush,
785 TestFilter_Pin_EndFlush,
786 TestFilter_Pin_NewSegment
789 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
794 /* Private helper function */
795 static HRESULT TestFilter_OutputPin_ConnectSpecific(ITestPinImpl * This, IPin * pReceivePin,
796 const AM_MEDIA_TYPE * pmt)
800 This->pConnectedTo = pReceivePin;
801 IPin_AddRef(pReceivePin);
803 hr = IPin_ReceiveConnection(pReceivePin, &This->IPin_iface, pmt);
807 IPin_Release(This->pConnectedTo);
808 This->pConnectedTo = NULL;
814 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
816 ITestPinImpl *This = impl_from_IPin(iface);
819 EnterCriticalSection(This->pCritSec);
821 /* if we have been a specific type to connect with, then we can either connect
822 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
823 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
824 hr = TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, pmt);
827 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
828 (TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, &This->mtCurrent) == S_OK))
830 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
831 } /* if negotiate media type */
833 LeaveCriticalSection(This->pCritSec);
838 static const IPinVtbl TestFilter_OutputPin_Vtbl =
840 TestFilter_Pin_QueryInterface,
841 TestFilter_Pin_AddRef,
842 TestFilter_Pin_Release,
843 TestFilter_OutputPin_Connect,
844 TestFilter_OutputPin_ReceiveConnection,
845 TestFilter_Pin_Disconnect,
846 TestFilter_Pin_ConnectedTo,
847 TestFilter_Pin_ConnectionMediaType,
848 TestFilter_Pin_QueryPinInfo,
849 TestFilter_Pin_QueryDirection,
850 TestFilter_Pin_QueryId,
851 TestFilter_Pin_QueryAccept,
852 TestFilter_Pin_EnumMediaTypes,
853 TestFilter_Pin_QueryInternalConnections,
854 TestFilter_Pin_EndOfStream,
855 TestFilter_Pin_BeginFlush,
856 TestFilter_Pin_EndFlush,
857 TestFilter_Pin_NewSegment
860 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
861 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
863 ITestPinImpl * pPinImpl;
867 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
870 return E_OUTOFMEMORY;
872 pPinImpl->refCount = 1;
873 pPinImpl->pConnectedTo = NULL;
874 pPinImpl->pCritSec = pCritSec;
875 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
876 pPinImpl->mtCurrent = *pinmt;
878 pPinImpl->IPin_iface.lpVtbl = Pin_Vtbl;
880 *ppPin = &pPinImpl->IPin_iface;
884 /* IEnumPins implementation */
886 typedef HRESULT (* FNOBTAINPIN)(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick);
888 typedef struct IEnumPinsImpl
890 IEnumPins IEnumPins_iface;
893 TestFilterImpl *base;
894 FNOBTAINPIN receive_pin;
898 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
900 static inline IEnumPinsImpl *impl_from_IEnumPins(IEnumPins *iface)
902 return CONTAINING_RECORD(iface, IEnumPinsImpl, IEnumPins_iface);
905 static HRESULT createenumpins(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, TestFilterImpl *base)
907 IEnumPinsImpl * pEnumPins;
912 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
916 return E_OUTOFMEMORY;
918 pEnumPins->IEnumPins_iface.lpVtbl = &IEnumPinsImpl_Vtbl;
919 pEnumPins->refCount = 1;
920 pEnumPins->uIndex = 0;
921 pEnumPins->receive_pin = receive_pin;
922 pEnumPins->base = base;
923 IBaseFilter_AddRef(&base->IBaseFilter_iface);
924 *ppEnum = &pEnumPins->IEnumPins_iface;
926 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
931 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
935 if (IsEqualIID(riid, &IID_IUnknown))
937 else if (IsEqualIID(riid, &IID_IEnumPins))
942 IUnknown_AddRef((IUnknown *)(*ppv));
946 return E_NOINTERFACE;
949 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
951 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
952 ULONG refCount = InterlockedIncrement(&This->refCount);
957 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
959 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
960 ULONG refCount = InterlockedDecrement(&This->refCount);
964 IBaseFilter_Release(&This->base->IBaseFilter_iface);
972 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
974 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
975 DWORD synctime = This->synctime;
982 if (cPins > 1 && !pcFetched)
988 while (i < cPins && hr == S_OK)
990 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
995 if (synctime != This->synctime)
999 if (!i && synctime != This->synctime)
1000 return VFW_E_ENUM_OUT_OF_SYNC;
1011 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
1013 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1014 DWORD synctime = This->synctime;
1018 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
1022 if (synctime != This->synctime)
1023 return VFW_E_ENUM_OUT_OF_SYNC;
1026 This->uIndex += cPins;
1031 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1033 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1035 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1041 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1044 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1046 hr = createenumpins(ppEnum, This->receive_pin, This->base);
1049 return IEnumPins_Skip(*ppEnum, This->uIndex);
1052 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1054 IEnumPinsImpl_QueryInterface,
1055 IEnumPinsImpl_AddRef,
1056 IEnumPinsImpl_Release,
1059 IEnumPinsImpl_Reset,
1063 /* Test filter implementation - a filter that has few predefined pins with single media type
1064 * that accept only this single media type. Enough for Render(). */
1066 typedef struct TestFilterPinData
1068 PIN_DIRECTION pinDir;
1069 const GUID *mediasubtype;
1070 } TestFilterPinData;
1072 static const IBaseFilterVtbl TestFilter_Vtbl;
1074 static inline TestFilterImpl *impl_from_IBaseFilter(IBaseFilter *iface)
1076 return CONTAINING_RECORD(iface, TestFilterImpl, IBaseFilter_iface);
1079 static HRESULT createtestfilter(const CLSID* pClsid, const TestFilterPinData *pinData,
1080 TestFilterImpl **tf)
1082 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1083 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1086 TestFilterImpl* pTestFilter = NULL;
1090 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1091 if (!pTestFilter) return E_OUTOFMEMORY;
1093 pTestFilter->clsid = *pClsid;
1094 pTestFilter->IBaseFilter_iface.lpVtbl = &TestFilter_Vtbl;
1095 pTestFilter->refCount = 1;
1096 InitializeCriticalSection(&pTestFilter->csFilter);
1097 pTestFilter->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TestFilterImpl.csFilter");
1098 pTestFilter->state = State_Stopped;
1100 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1103 while(pinData[nPins].mediasubtype) ++nPins;
1105 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1106 if (!pTestFilter->ppPins)
1111 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1113 for (i = 0; i < nPins; i++)
1115 ZeroMemory(&mt, sizeof(mt));
1116 mt.majortype = MEDIATYPE_Video;
1117 mt.formattype = FORMAT_None;
1118 mt.subtype = *pinData[i].mediasubtype;
1120 pinInfo.dir = pinData[i].pinDir;
1121 pinInfo.pFilter = &pTestFilter->IBaseFilter_iface;
1122 if (pinInfo.dir == PINDIR_INPUT)
1124 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1125 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1126 &pTestFilter->ppPins[i]);
1131 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1132 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1133 &pTestFilter->ppPins[i]);
1135 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1138 pTestFilter->nPins = nPins;
1144 if (pTestFilter->ppPins)
1146 for (i = 0; i < nPins; i++)
1148 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1151 CoTaskMemFree(pTestFilter->ppPins);
1152 pTestFilter->csFilter.DebugInfo->Spare[0] = 0;
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 This->csFilter.DebugInfo->Spare[0] = 0;
1217 DeleteCriticalSection(&This->csFilter);
1219 CoTaskMemFree(This);
1226 /** IPersist methods **/
1228 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1230 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1232 *pClsid = This->clsid;
1237 /** IMediaFilter methods **/
1239 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1244 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1249 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1254 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1256 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1258 EnterCriticalSection(&This->csFilter);
1260 *pState = This->state;
1262 LeaveCriticalSection(&This->csFilter);
1267 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1272 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1277 /** IBaseFilter implementation **/
1279 static HRESULT getpin_callback(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick)
1281 /* Our pins are static, not changing so setting static tick count is ok */
1284 if (pos >= tf->nPins)
1287 *pin = tf->ppPins[pos];
1292 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1294 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1296 return createenumpins(ppEnum, getpin_callback, This);
1299 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1304 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1306 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1308 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1309 pInfo->pGraph = This->filterInfo.pGraph;
1312 IFilterGraph_AddRef(pInfo->pGraph);
1317 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1320 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1322 EnterCriticalSection(&This->csFilter);
1325 lstrcpyW(This->filterInfo.achName, pName);
1327 *This->filterInfo.achName = '\0';
1328 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1330 LeaveCriticalSection(&This->csFilter);
1335 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1340 static const IBaseFilterVtbl TestFilter_Vtbl =
1342 TestFilter_QueryInterface,
1345 TestFilter_GetClassID,
1349 TestFilter_GetState,
1350 TestFilter_SetSyncSource,
1351 TestFilter_GetSyncSource,
1352 TestFilter_EnumPins,
1354 TestFilter_QueryFilterInfo,
1355 TestFilter_JoinFilterGraph,
1356 TestFilter_QueryVendorInfo
1359 /* IClassFactory implementation */
1361 typedef struct TestClassFactoryImpl
1363 IClassFactory IClassFactory_iface;
1364 const TestFilterPinData *filterPinData;
1366 } TestClassFactoryImpl;
1368 static inline TestClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
1370 return CONTAINING_RECORD(iface, TestClassFactoryImpl, IClassFactory_iface);
1373 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1374 LPCLASSFACTORY iface,
1378 if (ppvObj == NULL) return E_POINTER;
1380 if (IsEqualGUID(riid, &IID_IUnknown) ||
1381 IsEqualGUID(riid, &IID_IClassFactory))
1384 IClassFactory_AddRef(iface);
1389 return E_NOINTERFACE;
1392 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1394 return 2; /* non-heap-based object */
1397 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1399 return 1; /* non-heap-based object */
1402 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1403 LPCLASSFACTORY iface,
1404 LPUNKNOWN pUnkOuter,
1408 TestClassFactoryImpl *This = impl_from_IClassFactory(iface);
1410 TestFilterImpl *testfilter;
1414 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1416 hr = createtestfilter(This->clsid, This->filterPinData, &testfilter);
1417 if (SUCCEEDED(hr)) {
1418 hr = IBaseFilter_QueryInterface(&testfilter->IBaseFilter_iface, riid, ppvObj);
1419 IBaseFilter_Release(&testfilter->IBaseFilter_iface);
1424 static HRESULT WINAPI Test_IClassFactory_LockServer(
1425 LPCLASSFACTORY iface,
1431 static IClassFactoryVtbl TestClassFactory_Vtbl =
1433 Test_IClassFactory_QueryInterface,
1434 Test_IClassFactory_AddRef,
1435 Test_IClassFactory_Release,
1436 Test_IClassFactory_CreateInstance,
1437 Test_IClassFactory_LockServer
1440 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1444 FILTER_INFO filterInfo;
1449 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1450 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1451 if (FAILED(hr)) return hr;
1453 hr = IPin_QueryPinInfo(pin, &pinInfo);
1454 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1456 if (FAILED(hr)) return hr;
1458 SetLastError(0xdeadbeef);
1459 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1460 if (hr == S_OK && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1462 IBaseFilter_Release(pinInfo.pFilter);
1465 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1466 IBaseFilter_Release(pinInfo.pFilter);
1467 if (FAILED(hr)) return hr;
1469 IFilterGraph_Release(filterInfo.pGraph);
1471 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1476 static void test_render_filter_priority(void)
1478 /* Tests filter choice priorities in Render(). */
1479 DWORD cookie1 = 0, cookie2 = 0, cookie3 = 0;
1481 IFilterGraph2* pgraph2 = NULL;
1482 IFilterMapper2 *pMapper2 = NULL;
1483 TestFilterImpl *ptestfilter = NULL;
1484 TestFilterImpl *ptestfilter2 = NULL;
1485 static const CLSID CLSID_TestFilter2 = {
1489 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1491 static const CLSID CLSID_TestFilter3 = {
1495 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1497 static const CLSID CLSID_TestFilter4 = {
1501 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1503 static const GUID mediasubtype1 = {
1507 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1509 static const GUID mediasubtype2 = {
1513 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1515 static const TestFilterPinData PinData1[] = {
1516 { PINDIR_OUTPUT, &mediasubtype1 },
1519 static const TestFilterPinData PinData2[] = {
1520 { PINDIR_INPUT, &mediasubtype1 },
1523 static const TestFilterPinData PinData3[] = {
1524 { PINDIR_INPUT, &GUID_NULL },
1527 static const TestFilterPinData PinData4[] = {
1528 { PINDIR_INPUT, &mediasubtype1 },
1529 { PINDIR_OUTPUT, &mediasubtype2 },
1532 static const TestFilterPinData PinData5[] = {
1533 { PINDIR_INPUT, &mediasubtype2 },
1536 TestClassFactoryImpl Filter1ClassFactory = {
1537 { &TestClassFactory_Vtbl },
1538 PinData2, &CLSID_TestFilter2
1540 TestClassFactoryImpl Filter2ClassFactory = {
1541 { &TestClassFactory_Vtbl },
1542 PinData4, &CLSID_TestFilter3
1544 TestClassFactoryImpl Filter3ClassFactory = {
1545 { &TestClassFactory_Vtbl },
1546 PinData5, &CLSID_TestFilter4
1548 char ConnectedFilterName1[MAX_FILTER_NAME];
1549 char ConnectedFilterName2[MAX_FILTER_NAME];
1551 REGFILTERPINS2 rgPins2[2];
1552 REGPINTYPES rgPinType[2];
1553 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1554 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1555 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1556 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1557 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1558 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1559 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1560 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1562 /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is
1563 "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating
1564 no preference given to exact match. */
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) return;
1569 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1570 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1571 if (FAILED(hr)) goto out;
1573 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1574 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1576 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1577 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1578 if (FAILED(hr)) goto out;
1580 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1581 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1583 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1584 ptestfilter2 = NULL;
1586 hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1587 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1588 if (FAILED(hr)) goto out;
1590 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1591 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1593 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1594 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1596 hr = get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1598 IFilterGraph2_Release(pgraph2);
1600 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1602 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1603 ptestfilter2 = NULL;
1605 if (hr == E_NOTIMPL)
1607 win_skip("Needed functions are not implemented\n");
1611 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1612 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1613 if (!pgraph2) goto out;
1615 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1616 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1617 if (FAILED(hr)) goto out;
1619 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1620 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1622 hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1623 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1624 if (FAILED(hr)) goto out;
1626 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1627 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1629 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1630 ptestfilter2 = NULL;
1632 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1633 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1634 if (FAILED(hr)) goto out;
1636 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1637 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1639 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1640 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1642 hr = IFilterGraph2_Disconnect(pgraph2, NULL);
1643 ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr);
1645 get_connected_filter_name(ptestfilter, ConnectedFilterName2);
1646 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1647 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1649 IFilterGraph2_Release(pgraph2);
1651 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1653 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1654 ptestfilter2 = NULL;
1656 /* Test if any preference is given to existing renderer which renders the pin directly vs
1657 an existing renderer which renders the pin indirectly, through an additional middle filter,
1658 again trying different orders of creation. Native appears not to give a preference. */
1660 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1661 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1662 if (!pgraph2) goto out;
1664 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1665 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1666 if (FAILED(hr)) goto out;
1668 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1669 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1671 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1672 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1673 if (FAILED(hr)) goto out;
1675 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1676 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1678 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1679 ptestfilter2 = NULL;
1681 hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
1682 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1683 if (FAILED(hr)) goto out;
1685 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1686 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1688 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1689 ptestfilter2 = NULL;
1691 hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2);
1692 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1693 if (FAILED(hr)) goto out;
1695 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4);
1696 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1698 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1699 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1701 get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1702 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1, "TestfilterInstance2"),
1703 "unexpected connected filter: %s\n", ConnectedFilterName1);
1705 IFilterGraph2_Release(pgraph2);
1707 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1709 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1710 ptestfilter2 = NULL;
1712 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1713 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1714 if (!pgraph2) goto out;
1716 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1717 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1718 if (FAILED(hr)) goto out;
1720 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1721 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1723 hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
1724 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1725 if (FAILED(hr)) goto out;
1727 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1728 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1730 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1731 ptestfilter2 = NULL;
1733 hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2);
1734 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1735 if (FAILED(hr)) goto out;
1737 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4);
1738 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1740 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1741 ptestfilter2 = NULL;
1743 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1744 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1745 if (FAILED(hr)) goto out;
1747 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1748 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1750 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1751 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1753 get_connected_filter_name(ptestfilter, ConnectedFilterName2);
1754 ok(!lstrcmp(ConnectedFilterName2, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2, "TestfilterInstance2"),
1755 "unexpected connected filter: %s\n", ConnectedFilterName2);
1756 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1757 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1759 IFilterGraph2_Release(pgraph2);
1761 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1763 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1764 ptestfilter2 = NULL;
1766 /* Test if renderers are tried before non-renderers (intermediary filters). */
1767 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1768 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1769 if (!pgraph2) goto out;
1771 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
1772 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1773 if (!pMapper2) goto out;
1775 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1776 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1777 if (FAILED(hr)) goto out;
1779 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1780 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1782 /* Register our filters with COM and with Filtermapper. */
1783 hr = CoRegisterClassObject(Filter1ClassFactory.clsid,
1784 (IUnknown *)&Filter1ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1785 REGCLS_MULTIPLEUSE, &cookie1);
1786 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1787 if (FAILED(hr)) goto out;
1788 hr = CoRegisterClassObject(Filter2ClassFactory.clsid,
1789 (IUnknown *)&Filter2ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1790 REGCLS_MULTIPLEUSE, &cookie2);
1791 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1792 if (FAILED(hr)) goto out;
1793 hr = CoRegisterClassObject(Filter3ClassFactory.clsid,
1794 (IUnknown *)&Filter3ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1795 REGCLS_MULTIPLEUSE, &cookie3);
1796 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1797 if (FAILED(hr)) goto out;
1800 rgf2.dwMerit = MERIT_UNLIKELY;
1801 S2(U(rgf2)).cPins2 = 1;
1802 S2(U(rgf2)).rgPins2 = rgPins2;
1803 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
1804 rgPins2[0].cInstances = 1;
1805 rgPins2[0].nMediaTypes = 1;
1806 rgPins2[0].lpMediaType = &rgPinType[0];
1807 rgPins2[0].nMediums = 0;
1808 rgPins2[0].lpMedium = NULL;
1809 rgPins2[0].clsPinCategory = NULL;
1810 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
1811 rgPinType[0].clsMinorType = &mediasubtype1;
1813 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
1814 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1815 if (hr == E_ACCESSDENIED)
1816 skip("Not authorized to register filters\n");
1819 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1821 rgf2.dwMerit = MERIT_PREFERRED;
1822 rgPinType[0].clsMinorType = &mediasubtype2;
1824 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
1825 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1826 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1828 S2(U(rgf2)).cPins2 = 2;
1829 rgPins2[0].dwFlags = 0;
1830 rgPinType[0].clsMinorType = &mediasubtype1;
1832 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
1833 rgPins2[1].cInstances = 1;
1834 rgPins2[1].nMediaTypes = 1;
1835 rgPins2[1].lpMediaType = &rgPinType[1];
1836 rgPins2[1].nMediums = 0;
1837 rgPins2[1].lpMedium = NULL;
1838 rgPins2[1].clsPinCategory = NULL;
1839 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
1840 rgPinType[1].clsMinorType = &mediasubtype2;
1842 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
1843 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1844 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1846 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1847 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1849 get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1850 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3"),
1851 "unexpected connected filter: %s\n", ConnectedFilterName1);
1854 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1855 &CLSID_TestFilter2);
1856 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1857 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1858 &CLSID_TestFilter3);
1859 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1860 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1861 &CLSID_TestFilter4);
1862 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1866 if (ptestfilter) IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1867 if (ptestfilter2) IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1868 if (pgraph2) IFilterGraph2_Release(pgraph2);
1869 if (pMapper2) IFilterMapper2_Release(pMapper2);
1871 hr = CoRevokeClassObject(cookie1);
1872 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1873 hr = CoRevokeClassObject(cookie2);
1874 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1875 hr = CoRevokeClassObject(cookie3);
1876 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1879 START_TEST(filtergraph)
1882 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1883 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
1884 &IID_IGraphBuilder, (LPVOID*)&pgraph);
1886 skip("Creating filtergraph returned %08x, skipping tests\n", hr);
1889 test_render_run(avifile);
1890 test_render_run(mpegfile);
1891 test_graph_builder();
1892 test_graph_builder_addfilter();
1893 test_mediacontrol();
1894 test_filter_graph2();
1895 test_render_filter_priority();