2 * Unit tests for Direct Show functions
4 * Copyright (C) 2004 Christian Costa
5 * Copyright (C) 2008 Alexander Dorofeyev
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/test.h"
31 static const char avifileA[FILE_LEN] = "test.avi";
32 static const char mpegfileA[FILE_LEN] = "test.mpg";
34 IGraphBuilder* pgraph;
36 static int createfiltergraph(void)
38 return S_OK == CoCreateInstance(
39 &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&pgraph);
42 static void renderfile(const char * fileA)
45 WCHAR fileW[FILE_LEN];
47 MultiByteToWideChar(CP_ACP, 0, fileA, -1, fileW, FILE_LEN);
49 hr = IGraphBuilder_RenderFile(pgraph, fileW, NULL);
50 ok(hr==S_OK, "RenderFile returned: %x\n", hr);
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 char * fileA)
148 if (!createfiltergraph())
151 h = CreateFileA(fileA, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
152 if (h != INVALID_HANDLE_VALUE) {
158 releasefiltergraph();
161 static void test_graph_builder(void)
164 IBaseFilter *pF = NULL;
165 IBaseFilter *pF2 = NULL;
167 IEnumPins *pEnum = NULL;
169 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
170 static const WCHAR fooBarW[] = {'f','o','o','B','a','r',0};
172 if (!createfiltergraph())
175 /* create video filter */
176 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
177 &IID_IBaseFilter, (LPVOID*)&pF);
178 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
179 ok(pF != NULL, "pF is NULL\n");
181 /* add the two filters to the graph */
182 hr = IGraphBuilder_AddFilter(pgraph, pF, testFilterW);
183 ok(hr == S_OK, "failed to add pF to the graph: %x\n", hr);
186 hr = IBaseFilter_EnumPins(pF, &pEnum);
187 ok(hr == S_OK, "IBaseFilter_EnumPins failed for pF: %x\n", hr);
188 ok(pEnum != NULL, "pEnum is NULL\n");
189 hr = IEnumPins_Next(pEnum, 1, &pIn, NULL);
190 ok(hr == S_OK, "IEnumPins_Next failed for pF: %x\n", hr);
191 ok(pIn != NULL, "pIn is NULL\n");
192 hr = IPin_QueryDirection(pIn, &dir);
193 ok(hr == S_OK, "IPin_QueryDirection failed: %x\n", hr);
194 ok(dir == PINDIR_INPUT, "pin has wrong direction\n");
196 hr = IGraphBuilder_FindFilterByName(pgraph, fooBarW, &pF2);
197 ok(hr == VFW_E_NOT_FOUND, "IGraphBuilder_FindFilterByName returned %x\n", hr);
198 ok(pF2 == NULL, "IGraphBuilder_FindFilterByName returned %p\n", pF2);
199 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, &pF2);
200 ok(hr == S_OK, "IGraphBuilder_FindFilterByName returned %x\n", hr);
201 ok(pF2 != NULL, "IGraphBuilder_FindFilterByName returned NULL\n");
202 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, NULL);
203 ok(hr == E_POINTER, "IGraphBuilder_FindFilterByName returned %x\n", hr);
205 if (pIn) IPin_Release(pIn);
206 if (pEnum) IEnumPins_Release(pEnum);
207 if (pF) IBaseFilter_Release(pF);
208 if (pF2) IBaseFilter_Release(pF2);
210 releasefiltergraph();
213 static void test_graph_builder_addfilter(void)
216 IBaseFilter *pF = NULL;
217 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
219 if (!createfiltergraph())
222 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
223 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr);
225 /* create video filter */
226 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
227 &IID_IBaseFilter, (LPVOID*)&pF);
228 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
229 ok(pF != NULL, "pF is NULL\n");
231 skip("failed to created filter, skipping\n");
235 hr = IGraphBuilder_AddFilter(pgraph, pF, NULL);
236 ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr);
237 IMediaFilter_Release(pF);
240 static void test_mediacontrol(void)
243 LONGLONG pos = 0xdeadbeef;
244 IMediaSeeking *seeking = NULL;
245 IMediaFilter *filter = NULL;
246 IMediaControl *control = NULL;
248 IFilterGraph2_SetDefaultSyncSource(pgraph);
249 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking);
250 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
254 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
255 ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
258 IUnknown_Release(seeking);
262 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
263 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
266 IUnknown_Release(seeking);
267 IUnknown_Release(filter);
271 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
272 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
273 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
275 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_ReturnTime, NULL, AM_SEEKING_NoPositioning);
276 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
277 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_NoPositioning, NULL, AM_SEEKING_ReturnTime);
278 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
280 IMediaFilter_SetSyncSource(filter, NULL);
282 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
283 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
284 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
286 hr = IMediaControl_GetState(control, 1000, NULL);
287 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
289 IUnknown_Release(control);
290 IUnknown_Release(seeking);
291 IUnknown_Release(filter);
292 releasefiltergraph();
295 static void test_filter_graph2(void)
298 IFilterGraph2 *pF = NULL;
300 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
301 &IID_IFilterGraph2, (LPVOID*)&pF);
302 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
303 ok(pF != NULL, "pF is NULL\n");
305 hr = IFilterGraph2_Release(pF);
306 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
309 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
310 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
312 if (pMediaType->pbFormat)
314 CoTaskMemFree(pMediaType->pbFormat);
315 pMediaType->pbFormat = NULL;
317 if (pMediaType->pUnk)
319 IUnknown_Release(pMediaType->pUnk);
320 pMediaType->pUnk = NULL;
324 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
327 if (!pSrc->pbFormat) return S_OK;
328 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
329 return E_OUTOFMEMORY;
330 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
332 IUnknown_AddRef(pDest->pUnk);
336 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
338 AM_MEDIA_TYPE * pDest;
340 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
344 if (FAILED(CopyMediaType(pDest, pSrc)))
346 CoTaskMemFree(pDest);
353 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
355 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
356 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
359 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
361 FreeMediaType(pMediaType);
362 CoTaskMemFree(pMediaType);
365 typedef struct IEnumMediaTypesImpl
367 const IEnumMediaTypesVtbl * lpVtbl;
369 AM_MEDIA_TYPE *pMediaTypes;
372 } IEnumMediaTypesImpl;
374 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
376 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
379 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
381 if (!pEnumMediaTypes)
384 return E_OUTOFMEMORY;
386 pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl;
387 pEnumMediaTypes->refCount = 1;
388 pEnumMediaTypes->uIndex = 0;
389 pEnumMediaTypes->cMediaTypes = cMediaTypes;
390 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
391 for (i = 0; i < cMediaTypes; i++)
392 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
395 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
396 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
397 return E_OUTOFMEMORY;
399 *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl);
403 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
407 if (IsEqualIID(riid, &IID_IUnknown))
409 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
414 IUnknown_AddRef((IUnknown *)(*ppv));
418 return E_NOINTERFACE;
421 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
423 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
424 ULONG refCount = InterlockedIncrement(&This->refCount);
429 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
431 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
432 ULONG refCount = InterlockedDecrement(&This->refCount);
437 for (i = 0; i < This->cMediaTypes; i++)
438 FreeMediaType(&This->pMediaTypes[i]);
439 CoTaskMemFree(This->pMediaTypes);
445 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
448 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
450 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
455 for (i = 0; i < cFetched; i++)
456 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
459 DeleteMediaType(ppMediaTypes[i]);
461 return E_OUTOFMEMORY;
465 if ((cMediaTypes != 1) || pcFetched)
466 *pcFetched = cFetched;
468 This->uIndex += cFetched;
470 if (cFetched != cMediaTypes)
475 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
477 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
479 if (This->uIndex + cMediaTypes < This->cMediaTypes)
481 This->uIndex += cMediaTypes;
487 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
489 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
495 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
498 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
500 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
503 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
506 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
508 IEnumMediaTypesImpl_QueryInterface,
509 IEnumMediaTypesImpl_AddRef,
510 IEnumMediaTypesImpl_Release,
511 IEnumMediaTypesImpl_Next,
512 IEnumMediaTypesImpl_Skip,
513 IEnumMediaTypesImpl_Reset,
514 IEnumMediaTypesImpl_Clone
517 /* Implementation of a very stripped down pin for the test filter. Just enough
518 functionality for connecting and Render() to work. */
520 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
522 lstrcpyW(pDest->achName, pSrc->achName);
523 pDest->dir = pSrc->dir;
524 pDest->pFilter = pSrc->pFilter;
527 typedef struct ITestPinImpl
529 const struct IPinVtbl * lpVtbl;
531 LPCRITICAL_SECTION pCritSec;
534 AM_MEDIA_TYPE mtCurrent;
538 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
542 if (IsEqualIID(riid, &IID_IUnknown))
544 else if (IsEqualIID(riid, &IID_IPin))
549 IUnknown_AddRef((IUnknown *)(*ppv));
553 return E_NOINTERFACE;
556 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
558 ITestPinImpl *This = (ITestPinImpl *)iface;
559 ULONG refCount = InterlockedIncrement(&This->refCount);
563 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
565 ITestPinImpl *This = (ITestPinImpl *)iface;
566 ULONG refCount = InterlockedDecrement(&This->refCount);
570 FreeMediaType(&This->mtCurrent);
579 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
584 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
586 ITestPinImpl *This = (ITestPinImpl *)iface;
587 PIN_DIRECTION pindirReceive;
590 EnterCriticalSection(This->pCritSec);
592 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
593 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
594 hr = VFW_E_TYPE_NOT_ACCEPTED;
596 if (This->pConnectedTo)
597 hr = VFW_E_ALREADY_CONNECTED;
601 IPin_QueryDirection(pReceivePin, &pindirReceive);
603 if (pindirReceive != PINDIR_OUTPUT)
605 hr = VFW_E_INVALID_DIRECTION;
611 CopyMediaType(&This->mtCurrent, pmt);
612 This->pConnectedTo = pReceivePin;
613 IPin_AddRef(pReceivePin);
616 LeaveCriticalSection(This->pCritSec);
621 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
624 ITestPinImpl *This = (ITestPinImpl *)iface;
626 EnterCriticalSection(This->pCritSec);
628 if (This->pConnectedTo)
630 IPin_Release(This->pConnectedTo);
631 This->pConnectedTo = NULL;
637 LeaveCriticalSection(This->pCritSec);
642 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
645 ITestPinImpl *This = (ITestPinImpl *)iface;
647 EnterCriticalSection(This->pCritSec);
649 if (This->pConnectedTo)
651 *ppPin = This->pConnectedTo;
657 hr = VFW_E_NOT_CONNECTED;
661 LeaveCriticalSection(This->pCritSec);
666 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
669 ITestPinImpl *This = (ITestPinImpl *)iface;
671 EnterCriticalSection(This->pCritSec);
673 if (This->pConnectedTo)
675 CopyMediaType(pmt, &This->mtCurrent);
680 ZeroMemory(pmt, sizeof(*pmt));
681 hr = VFW_E_NOT_CONNECTED;
684 LeaveCriticalSection(This->pCritSec);
689 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
691 ITestPinImpl *This = (ITestPinImpl *)iface;
693 Copy_PinInfo(pInfo, &This->pinInfo);
694 IBaseFilter_AddRef(pInfo->pFilter);
699 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
701 ITestPinImpl *This = (ITestPinImpl *)iface;
703 *pPinDir = This->pinInfo.dir;
708 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
713 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
715 ITestPinImpl *This = (ITestPinImpl *)iface;
717 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
718 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
721 return VFW_E_TYPE_NOT_ACCEPTED;
724 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
726 ITestPinImpl *This = (ITestPinImpl *)iface;
728 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
731 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
736 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
741 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
746 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
751 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
756 static const IPinVtbl TestFilter_InputPin_Vtbl =
758 TestFilter_Pin_QueryInterface,
759 TestFilter_Pin_AddRef,
760 TestFilter_Pin_Release,
761 TestFilter_InputPin_Connect,
762 TestFilter_InputPin_ReceiveConnection,
763 TestFilter_Pin_Disconnect,
764 TestFilter_Pin_ConnectedTo,
765 TestFilter_Pin_ConnectionMediaType,
766 TestFilter_Pin_QueryPinInfo,
767 TestFilter_Pin_QueryDirection,
768 TestFilter_Pin_QueryId,
769 TestFilter_Pin_QueryAccept,
770 TestFilter_Pin_EnumMediaTypes,
771 TestFilter_Pin_QueryInternalConnections,
772 TestFilter_Pin_EndOfStream,
773 TestFilter_Pin_BeginFlush,
774 TestFilter_Pin_EndFlush,
775 TestFilter_Pin_NewSegment
778 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
783 /* Private helper function */
784 static HRESULT TestFilter_OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
786 ITestPinImpl *This = (ITestPinImpl *)iface;
789 This->pConnectedTo = pReceivePin;
790 IPin_AddRef(pReceivePin);
792 hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
796 IPin_Release(This->pConnectedTo);
797 This->pConnectedTo = NULL;
803 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
805 ITestPinImpl *This = (ITestPinImpl *)iface;
808 EnterCriticalSection(This->pCritSec);
810 /* if we have been a specific type to connect with, then we can either connect
811 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
812 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
813 hr = TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, pmt);
816 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
817 (TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, &This->mtCurrent) == S_OK))
819 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
820 } /* if negotiate media type */
822 LeaveCriticalSection(This->pCritSec);
827 static const IPinVtbl TestFilter_OutputPin_Vtbl =
829 TestFilter_Pin_QueryInterface,
830 TestFilter_Pin_AddRef,
831 TestFilter_Pin_Release,
832 TestFilter_OutputPin_Connect,
833 TestFilter_OutputPin_ReceiveConnection,
834 TestFilter_Pin_Disconnect,
835 TestFilter_Pin_ConnectedTo,
836 TestFilter_Pin_ConnectionMediaType,
837 TestFilter_Pin_QueryPinInfo,
838 TestFilter_Pin_QueryDirection,
839 TestFilter_Pin_QueryId,
840 TestFilter_Pin_QueryAccept,
841 TestFilter_Pin_EnumMediaTypes,
842 TestFilter_Pin_QueryInternalConnections,
843 TestFilter_Pin_EndOfStream,
844 TestFilter_Pin_BeginFlush,
845 TestFilter_Pin_EndFlush,
846 TestFilter_Pin_NewSegment
849 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
850 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
852 ITestPinImpl * pPinImpl;
856 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
859 return E_OUTOFMEMORY;
861 pPinImpl->refCount = 1;
862 pPinImpl->pConnectedTo = NULL;
863 pPinImpl->pCritSec = pCritSec;
864 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
865 pPinImpl->mtCurrent = *pinmt;
867 pPinImpl->lpVtbl = Pin_Vtbl;
869 *ppPin = (IPin *)pPinImpl;
873 /* IEnumPins implementation */
875 typedef HRESULT (* FNOBTAINPIN)(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick);
877 typedef struct IEnumPinsImpl
879 const IEnumPinsVtbl * lpVtbl;
883 FNOBTAINPIN receive_pin;
887 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
889 static HRESULT IEnumPinsImpl_Construct(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, IBaseFilter *base)
891 IEnumPinsImpl * pEnumPins;
896 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
900 return E_OUTOFMEMORY;
902 pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl;
903 pEnumPins->refCount = 1;
904 pEnumPins->uIndex = 0;
905 pEnumPins->receive_pin = receive_pin;
906 pEnumPins->base = base;
907 IBaseFilter_AddRef(base);
908 *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl);
910 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
915 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
919 if (IsEqualIID(riid, &IID_IUnknown))
921 else if (IsEqualIID(riid, &IID_IEnumPins))
926 IUnknown_AddRef((IUnknown *)(*ppv));
930 return E_NOINTERFACE;
933 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
935 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
936 ULONG refCount = InterlockedIncrement(&This->refCount);
941 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
943 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
944 ULONG refCount = InterlockedDecrement(&This->refCount);
948 IBaseFilter_Release(This->base);
956 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
958 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
959 DWORD synctime = This->synctime;
966 if (cPins > 1 && !pcFetched)
972 while (i < cPins && hr == S_OK)
974 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
979 if (synctime != This->synctime)
983 if (!i && synctime != This->synctime)
984 return VFW_E_ENUM_OUT_OF_SYNC;
995 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
997 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
998 DWORD synctime = This->synctime;
1002 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
1006 if (synctime != This->synctime)
1007 return VFW_E_ENUM_OUT_OF_SYNC;
1010 This->uIndex += cPins;
1015 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1017 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1019 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1025 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1028 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1030 hr = IEnumPinsImpl_Construct(ppEnum, This->receive_pin, This->base);
1033 return IEnumPins_Skip(*ppEnum, This->uIndex);
1036 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1038 IEnumPinsImpl_QueryInterface,
1039 IEnumPinsImpl_AddRef,
1040 IEnumPinsImpl_Release,
1043 IEnumPinsImpl_Reset,
1047 /* Test filter implementation - a filter that has few predefined pins with single media type
1048 * that accept only this single media type. Enough for Render(). */
1050 typedef struct TestFilterPinData
1052 PIN_DIRECTION pinDir;
1053 const GUID *mediasubtype;
1054 } TestFilterPinData;
1056 typedef struct TestFilterImpl
1058 const IBaseFilterVtbl * lpVtbl;
1061 CRITICAL_SECTION csFilter;
1063 FILTER_INFO filterInfo;
1069 static const IBaseFilterVtbl TestFilter_Vtbl;
1071 static HRESULT TestFilter_Create(const CLSID* pClsid, const TestFilterPinData *pinData, LPVOID * ppv)
1073 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1074 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1077 TestFilterImpl* pTestFilter = NULL;
1081 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1082 if (!pTestFilter) return E_OUTOFMEMORY;
1084 pTestFilter->clsid = *pClsid;
1085 pTestFilter->lpVtbl = &TestFilter_Vtbl;
1086 pTestFilter->refCount = 1;
1087 InitializeCriticalSection(&pTestFilter->csFilter);
1088 pTestFilter->state = State_Stopped;
1090 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1093 while(pinData[nPins].mediasubtype) ++nPins;
1095 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1096 if (!pTestFilter->ppPins)
1101 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1103 for (i = 0; i < nPins; i++)
1105 ZeroMemory(&mt, sizeof(mt));
1106 mt.majortype = MEDIATYPE_Video;
1107 mt.formattype = FORMAT_None;
1108 mt.subtype = *pinData[i].mediasubtype;
1110 pinInfo.dir = pinData[i].pinDir;
1111 pinInfo.pFilter = (IBaseFilter *)pTestFilter;
1112 if (pinInfo.dir == PINDIR_INPUT)
1114 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1115 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1116 &pTestFilter->ppPins[i]);
1121 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1122 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1123 &pTestFilter->ppPins[i]);
1125 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1128 pTestFilter->nPins = nPins;
1134 if (pTestFilter->ppPins)
1136 for (i = 0; i < nPins; i++)
1138 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1141 CoTaskMemFree(pTestFilter->ppPins);
1142 DeleteCriticalSection(&pTestFilter->csFilter);
1143 CoTaskMemFree(pTestFilter);
1148 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1150 TestFilterImpl *This = (TestFilterImpl *)iface;
1154 if (IsEqualIID(riid, &IID_IUnknown))
1156 else if (IsEqualIID(riid, &IID_IPersist))
1158 else if (IsEqualIID(riid, &IID_IMediaFilter))
1160 else if (IsEqualIID(riid, &IID_IBaseFilter))
1165 IUnknown_AddRef((IUnknown *)(*ppv));
1169 return E_NOINTERFACE;
1172 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1174 TestFilterImpl *This = (TestFilterImpl *)iface;
1175 ULONG refCount = InterlockedIncrement(&This->refCount);
1180 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1182 TestFilterImpl *This = (TestFilterImpl *)iface;
1183 ULONG refCount = InterlockedDecrement(&This->refCount);
1189 for (i = 0; i < This->nPins; i++)
1193 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1195 IPin_Disconnect(pConnectedTo);
1196 IPin_Release(pConnectedTo);
1198 IPin_Disconnect(This->ppPins[i]);
1200 IPin_Release(This->ppPins[i]);
1203 CoTaskMemFree(This->ppPins);
1204 This->lpVtbl = NULL;
1206 DeleteCriticalSection(&This->csFilter);
1208 CoTaskMemFree(This);
1215 /** IPersist methods **/
1217 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1219 TestFilterImpl *This = (TestFilterImpl *)iface;
1221 *pClsid = This->clsid;
1226 /** IMediaFilter methods **/
1228 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1233 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1238 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1243 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1245 TestFilterImpl *This = (TestFilterImpl *)iface;
1247 EnterCriticalSection(&This->csFilter);
1249 *pState = This->state;
1251 LeaveCriticalSection(&This->csFilter);
1256 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1261 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1266 /** IBaseFilter implementation **/
1268 static HRESULT TestFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
1270 TestFilterImpl *This = (TestFilterImpl *)iface;
1272 /* Our pins are static, not changing so setting static tick count is ok */
1275 if (pos >= This->nPins)
1278 *pin = This->ppPins[pos];
1283 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1285 return IEnumPinsImpl_Construct(ppEnum, TestFilter_GetPin, iface);
1288 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1293 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1295 TestFilterImpl *This = (TestFilterImpl *)iface;
1297 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1298 pInfo->pGraph = This->filterInfo.pGraph;
1301 IFilterGraph_AddRef(pInfo->pGraph);
1306 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1309 TestFilterImpl *This = (TestFilterImpl *)iface;
1311 EnterCriticalSection(&This->csFilter);
1314 lstrcpyW(This->filterInfo.achName, pName);
1316 *This->filterInfo.achName = '\0';
1317 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1319 LeaveCriticalSection(&This->csFilter);
1324 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1329 static const IBaseFilterVtbl TestFilter_Vtbl =
1331 TestFilter_QueryInterface,
1334 TestFilter_GetClassID,
1338 TestFilter_GetState,
1339 TestFilter_SetSyncSource,
1340 TestFilter_GetSyncSource,
1341 TestFilter_EnumPins,
1343 TestFilter_QueryFilterInfo,
1344 TestFilter_JoinFilterGraph,
1345 TestFilter_QueryVendorInfo
1348 /* IClassFactory implementation */
1350 typedef struct TestClassFactoryImpl
1352 IClassFactoryVtbl *lpVtbl;
1353 const TestFilterPinData *filterPinData;
1355 } TestClassFactoryImpl;
1357 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1358 LPCLASSFACTORY iface,
1362 if (ppvObj == NULL) return E_POINTER;
1364 if (IsEqualGUID(riid, &IID_IUnknown) ||
1365 IsEqualGUID(riid, &IID_IClassFactory))
1368 IClassFactory_AddRef(iface);
1373 return E_NOINTERFACE;
1376 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1378 return 2; /* non-heap-based object */
1381 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1383 return 1; /* non-heap-based object */
1386 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1387 LPCLASSFACTORY iface,
1388 LPUNKNOWN pUnkOuter,
1392 TestClassFactoryImpl *This = (TestClassFactoryImpl *)iface;
1394 IUnknown *punk = NULL;
1398 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1400 hr = TestFilter_Create(This->clsid, This->filterPinData, (LPVOID *) &punk);
1401 if (SUCCEEDED(hr)) {
1402 hr = IUnknown_QueryInterface(punk, riid, ppvObj);
1403 IUnknown_Release(punk);
1408 static HRESULT WINAPI Test_IClassFactory_LockServer(
1409 LPCLASSFACTORY iface,
1415 static IClassFactoryVtbl TestClassFactory_Vtbl =
1417 Test_IClassFactory_QueryInterface,
1418 Test_IClassFactory_AddRef,
1419 Test_IClassFactory_Release,
1420 Test_IClassFactory_CreateInstance,
1421 Test_IClassFactory_LockServer
1424 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1428 FILTER_INFO filterInfo;
1433 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1434 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1435 if (FAILED(hr)) return hr;
1437 hr = IPin_QueryPinInfo(pin, &pinInfo);
1438 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1440 if (FAILED(hr)) return hr;
1442 SetLastError(0xdeadbeef);
1443 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1444 if (hr == S_OK && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1446 IBaseFilter_Release(pinInfo.pFilter);
1449 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1450 IBaseFilter_Release(pinInfo.pFilter);
1451 if (FAILED(hr)) return hr;
1453 IFilterGraph_Release(filterInfo.pGraph);
1455 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1460 static void test_render_filter_priority(void)
1462 /* Tests filter choice priorities in Render(). */
1463 DWORD cookie1 = 0, cookie2 = 0, cookie3 = 0;
1465 IFilterGraph2* pgraph2 = NULL;
1466 IFilterMapper2 *pMapper2 = NULL;
1467 IBaseFilter* ptestfilter = NULL;
1468 IBaseFilter* ptestfilter2 = NULL;
1469 static const CLSID CLSID_TestFilter2 = {
1473 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1475 static const CLSID CLSID_TestFilter3 = {
1479 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1481 static const CLSID CLSID_TestFilter4 = {
1485 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1487 static const GUID mediasubtype1 = {
1491 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1493 static const GUID mediasubtype2 = {
1497 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1499 static const TestFilterPinData PinData1[] = {
1500 { PINDIR_OUTPUT, &mediasubtype1 },
1503 static const TestFilterPinData PinData2[] = {
1504 { PINDIR_INPUT, &mediasubtype1 },
1507 static const TestFilterPinData PinData3[] = {
1508 { PINDIR_INPUT, &GUID_NULL },
1511 static const TestFilterPinData PinData4[] = {
1512 { PINDIR_INPUT, &mediasubtype1 },
1513 { PINDIR_OUTPUT, &mediasubtype2 },
1516 static const TestFilterPinData PinData5[] = {
1517 { PINDIR_INPUT, &mediasubtype2 },
1520 TestClassFactoryImpl Filter1ClassFactory = { &TestClassFactory_Vtbl, PinData2, &CLSID_TestFilter2 };
1521 TestClassFactoryImpl Filter2ClassFactory = { &TestClassFactory_Vtbl, PinData4, &CLSID_TestFilter3 };
1522 TestClassFactoryImpl Filter3ClassFactory = { &TestClassFactory_Vtbl, PinData5, &CLSID_TestFilter4 };
1523 char ConnectedFilterName1[MAX_FILTER_NAME];
1524 char ConnectedFilterName2[MAX_FILTER_NAME];
1526 REGFILTERPINS2 rgPins2[2];
1527 REGPINTYPES rgPinType[2];
1528 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1529 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1530 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1531 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1532 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1533 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1534 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1535 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1537 /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is
1538 "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating
1539 no preference given to exact match. */
1540 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1541 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1542 if (!pgraph2) return;
1544 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1545 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1546 if (FAILED(hr)) goto out;
1548 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1549 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1551 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1552 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1553 if (FAILED(hr)) goto out;
1555 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1556 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1558 IBaseFilter_Release(ptestfilter2);
1559 ptestfilter2 = NULL;
1561 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1562 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1563 if (FAILED(hr)) goto out;
1565 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1566 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1568 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1569 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1571 hr = get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1573 IFilterGraph2_Release(pgraph2);
1575 IBaseFilter_Release(ptestfilter);
1577 IBaseFilter_Release(ptestfilter2);
1578 ptestfilter2 = NULL;
1580 if (hr == E_NOTIMPL)
1582 win_skip("Needed functions are not implemented\n");
1586 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1587 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1588 if (!pgraph2) goto out;
1590 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1591 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1592 if (FAILED(hr)) goto out;
1594 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1595 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1597 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1598 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1599 if (FAILED(hr)) goto out;
1601 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1602 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1604 IBaseFilter_Release(ptestfilter2);
1605 ptestfilter2 = NULL;
1607 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1608 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1609 if (FAILED(hr)) goto out;
1611 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1612 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1614 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1615 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1617 hr = IFilterGraph2_Disconnect(pgraph2, NULL);
1618 ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr);
1620 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1621 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1622 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1624 IFilterGraph2_Release(pgraph2);
1626 IBaseFilter_Release(ptestfilter);
1628 IBaseFilter_Release(ptestfilter2);
1629 ptestfilter2 = NULL;
1631 /* Test if any preference is given to existing renderer which renders the pin directly vs
1632 an existing renderer which renders the pin indirectly, through an additional middle filter,
1633 again trying different orders of creation. Native appears not to give a preference. */
1635 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1636 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1637 if (!pgraph2) goto out;
1639 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1640 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1641 if (FAILED(hr)) goto out;
1643 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1644 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1646 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1647 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1648 if (FAILED(hr)) goto out;
1650 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1651 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1653 IBaseFilter_Release(ptestfilter2);
1654 ptestfilter2 = NULL;
1656 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1657 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1658 if (FAILED(hr)) goto out;
1660 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1661 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1663 IBaseFilter_Release(ptestfilter2);
1664 ptestfilter2 = NULL;
1666 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1667 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1668 if (FAILED(hr)) goto out;
1670 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1671 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1673 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1674 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1676 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1677 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1, "TestfilterInstance2"),
1678 "unexpected connected filter: %s\n", ConnectedFilterName1);
1680 IFilterGraph2_Release(pgraph2);
1682 IBaseFilter_Release(ptestfilter);
1684 IBaseFilter_Release(ptestfilter2);
1685 ptestfilter2 = NULL;
1687 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1688 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1689 if (!pgraph2) goto out;
1691 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1692 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1693 if (FAILED(hr)) goto out;
1695 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1696 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1698 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1699 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1700 if (FAILED(hr)) goto out;
1702 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1703 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1705 IBaseFilter_Release(ptestfilter2);
1706 ptestfilter2 = NULL;
1708 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1709 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1710 if (FAILED(hr)) goto out;
1712 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1713 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1715 IBaseFilter_Release(ptestfilter2);
1716 ptestfilter2 = NULL;
1718 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1719 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1720 if (FAILED(hr)) goto out;
1722 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1723 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1725 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1726 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1728 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1729 ok(!lstrcmp(ConnectedFilterName2, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2, "TestfilterInstance2"),
1730 "unexpected connected filter: %s\n", ConnectedFilterName2);
1731 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1732 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1734 IFilterGraph2_Release(pgraph2);
1736 IBaseFilter_Release(ptestfilter);
1738 IBaseFilter_Release(ptestfilter2);
1739 ptestfilter2 = NULL;
1741 /* Test if renderers are tried before non-renderers (intermediary filters). */
1742 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1743 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1744 if (!pgraph2) goto out;
1746 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
1747 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1748 if (!pMapper2) goto out;
1750 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1751 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1752 if (FAILED(hr)) goto out;
1754 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1755 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1757 /* Register our filters with COM and with Filtermapper. */
1758 hr = CoRegisterClassObject(Filter1ClassFactory.clsid, (IUnknown *)&Filter1ClassFactory,
1759 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie1);
1760 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1761 if (FAILED(hr)) goto out;
1762 hr = CoRegisterClassObject(Filter2ClassFactory.clsid, (IUnknown *)&Filter2ClassFactory,
1763 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie2);
1764 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1765 if (FAILED(hr)) goto out;
1766 hr = CoRegisterClassObject(Filter3ClassFactory.clsid, (IUnknown *)&Filter3ClassFactory,
1767 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie3);
1768 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1769 if (FAILED(hr)) goto out;
1772 rgf2.dwMerit = MERIT_UNLIKELY;
1773 S1(U(rgf2)).cPins2 = 1;
1774 S1(U(rgf2)).rgPins2 = rgPins2;
1775 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
1776 rgPins2[0].cInstances = 1;
1777 rgPins2[0].nMediaTypes = 1;
1778 rgPins2[0].lpMediaType = &rgPinType[0];
1779 rgPins2[0].nMediums = 0;
1780 rgPins2[0].lpMedium = NULL;
1781 rgPins2[0].clsPinCategory = NULL;
1782 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
1783 rgPinType[0].clsMinorType = &mediasubtype1;
1785 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
1786 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1787 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1789 rgf2.dwMerit = MERIT_PREFERRED;
1790 rgPinType[0].clsMinorType = &mediasubtype2;
1792 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
1793 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1794 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1796 S1(U(rgf2)).cPins2 = 2;
1797 rgPins2[0].dwFlags = 0;
1798 rgPinType[0].clsMinorType = &mediasubtype1;
1800 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
1801 rgPins2[1].cInstances = 1;
1802 rgPins2[1].nMediaTypes = 1;
1803 rgPins2[1].lpMediaType = &rgPinType[1];
1804 rgPins2[1].nMediums = 0;
1805 rgPins2[1].lpMedium = NULL;
1806 rgPins2[1].clsPinCategory = NULL;
1807 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
1808 rgPinType[1].clsMinorType = &mediasubtype2;
1810 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
1811 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1812 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1814 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1815 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1817 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1818 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3"),
1819 "unexpected connected filter: %s\n", ConnectedFilterName1);
1821 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1822 &CLSID_TestFilter2);
1823 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1824 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1825 &CLSID_TestFilter3);
1826 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1827 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1828 &CLSID_TestFilter4);
1829 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1833 if (ptestfilter) IBaseFilter_Release(ptestfilter);
1834 if (ptestfilter2) IBaseFilter_Release(ptestfilter2);
1835 if (pgraph2) IFilterGraph2_Release(pgraph2);
1836 if (pMapper2) IFilterMapper2_Release(pMapper2);
1838 hr = CoRevokeClassObject(cookie1);
1839 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1840 hr = CoRevokeClassObject(cookie2);
1841 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1842 hr = CoRevokeClassObject(cookie3);
1843 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1846 START_TEST(filtergraph)
1848 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1849 test_render_run(avifileA);
1850 test_render_run(mpegfileA);
1851 test_graph_builder();
1852 test_graph_builder_addfilter();
1853 test_mediacontrol();
1854 test_filter_graph2();
1855 test_render_filter_priority();