push b0b97fcd59eff07f047585692fa36859b459324f
[wine/hacks.git] / dlls / quartz / tests / filtergraph.c
blob0867d27d1c2fb7d664180e4871dac338b112ea99
1 /*
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
22 #include <assert.h>
24 #define COBJMACROS
26 #include "wine/test.h"
27 #include "dshow.h"
28 #include "control.h"
30 static const CHAR fileA[] = "test.avi";
31 static const WCHAR file[] = {'t','e','s','t','.','a','v','i',0};
33 IGraphBuilder* pgraph;
35 static int createfiltergraph(void)
37 return S_OK == CoCreateInstance(
38 &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&pgraph);
41 static void renderfile(void)
43 HRESULT hr;
45 hr = IGraphBuilder_RenderFile(pgraph, file, NULL);
46 ok(hr==S_OK, "RenderFile returned: %x\n", hr);
49 static void rungraph(void)
51 HRESULT hr;
52 IMediaControl* pmc;
53 IMediaEvent* pme;
54 IMediaFilter* pmf;
55 HANDLE hEvent;
57 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (LPVOID*)&pmc);
58 ok(hr==S_OK, "Cannot get IMediaControl interface returned: %x\n", hr);
60 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (LPVOID*)&pmf);
61 ok(hr==S_OK, "Cannot get IMediaFilter interface returned: %x\n", hr);
63 IMediaControl_Stop(pmc);
65 IMediaFilter_SetSyncSource(pmf, NULL);
67 IMediaFilter_Release(pmf);
69 hr = IMediaControl_Run(pmc);
70 ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr);
72 Sleep(10);
73 /* Crash fun */
74 trace("run -> stop\n");
75 hr = IMediaControl_Stop(pmc);
76 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
78 IGraphBuilder_SetDefaultSyncSource(pgraph);
80 Sleep(10);
81 trace("stop -> pause\n");
82 hr = IMediaControl_Pause(pmc);
83 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
85 Sleep(10);
86 trace("pause -> run\n");
87 hr = IMediaControl_Run(pmc);
88 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
90 Sleep(10);
91 trace("run -> pause\n");
92 hr = IMediaControl_Pause(pmc);
93 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
95 Sleep(10);
96 trace("pause -> stop\n");
97 hr = IMediaControl_Stop(pmc);
98 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
100 Sleep(10);
101 trace("pause -> run\n");
102 hr = IMediaControl_Run(pmc);
103 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
105 trace("run -> stop\n");
106 hr = IMediaControl_Stop(pmc);
107 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
109 trace("stop -> run\n");
110 hr = IMediaControl_Run(pmc);
111 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
113 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaEvent, (LPVOID*)&pme);
114 ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr);
116 hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent);
117 ok(hr==S_OK, "Cannot get event handle returned: %x\n", hr);
119 /* WaitForSingleObject(hEvent, INFINITE); */
120 Sleep(20000);
122 hr = IMediaEvent_Release(pme);
123 ok(hr==2, "Releasing mediaevent returned: %x\n", hr);
125 hr = IMediaControl_Stop(pmc);
126 ok(hr==S_OK, "Cannot stop the graph returned: %x\n", hr);
128 hr = IMediaControl_Release(pmc);
129 ok(hr==1, "Releasing mediacontrol returned: %x\n", hr);
132 static void releasefiltergraph(void)
134 HRESULT hr;
136 hr = IGraphBuilder_Release(pgraph);
137 ok(hr==0, "Releasing filtergraph returned: %x\n", hr);
140 static void test_render_run(void)
142 HANDLE h;
144 if (!createfiltergraph())
145 return;
147 h = CreateFileA(fileA, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
148 if (h != INVALID_HANDLE_VALUE) {
149 CloseHandle(h);
150 renderfile();
151 rungraph();
154 releasefiltergraph();
157 static void test_graph_builder(void)
159 HRESULT hr;
160 IBaseFilter *pF = NULL;
161 IBaseFilter *pF2 = NULL;
162 IPin *pIn = NULL;
163 IEnumPins *pEnum = NULL;
164 PIN_DIRECTION dir;
165 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
166 static const WCHAR fooBarW[] = {'f','o','o','B','a','r',0};
168 if (!createfiltergraph())
169 return;
171 /* create video filter */
172 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
173 &IID_IBaseFilter, (LPVOID*)&pF);
174 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
175 ok(pF != NULL, "pF is NULL\n");
177 /* add the two filters to the graph */
178 hr = IGraphBuilder_AddFilter(pgraph, pF, testFilterW);
179 ok(hr == S_OK, "failed to add pF to the graph: %x\n", hr);
181 /* find the pins */
182 hr = IBaseFilter_EnumPins(pF, &pEnum);
183 ok(hr == S_OK, "IBaseFilter_EnumPins failed for pF: %x\n", hr);
184 ok(pEnum != NULL, "pEnum is NULL\n");
185 hr = IEnumPins_Next(pEnum, 1, &pIn, NULL);
186 ok(hr == S_OK, "IEnumPins_Next failed for pF: %x\n", hr);
187 ok(pIn != NULL, "pIn is NULL\n");
188 hr = IPin_QueryDirection(pIn, &dir);
189 ok(hr == S_OK, "IPin_QueryDirection failed: %x\n", hr);
190 ok(dir == PINDIR_INPUT, "pin has wrong direction\n");
192 hr = IGraphBuilder_FindFilterByName(pgraph, fooBarW, &pF2);
193 ok(hr == VFW_E_NOT_FOUND, "IGraphBuilder_FindFilterByName returned %x\n", hr);
194 ok(pF2 == NULL, "IGraphBuilder_FindFilterByName returned %p\n", pF2);
195 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, &pF2);
196 ok(hr == S_OK, "IGraphBuilder_FindFilterByName returned %x\n", hr);
197 ok(pF2 != NULL, "IGraphBuilder_FindFilterByName returned NULL\n");
198 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, NULL);
199 ok(hr == E_POINTER, "IGraphBuilder_FindFilterByName returned %x\n", hr);
201 if (pIn) IPin_Release(pIn);
202 if (pEnum) IEnumPins_Release(pEnum);
203 if (pF) IBaseFilter_Release(pF);
204 if (pF2) IBaseFilter_Release(pF2);
206 releasefiltergraph();
209 static void test_graph_builder_addfilter(void)
211 HRESULT hr;
212 IBaseFilter *pF = NULL;
213 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
215 if (!createfiltergraph())
216 return;
218 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
219 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr);
221 /* create video filter */
222 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
223 &IID_IBaseFilter, (LPVOID*)&pF);
224 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
225 ok(pF != NULL, "pF is NULL\n");
226 if (!pF) {
227 skip("failed to created filter, skipping\n");
228 return;
231 hr = IGraphBuilder_AddFilter(pgraph, pF, NULL);
232 ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr);
233 IMediaFilter_Release(pF);
236 static void test_mediacontrol(void)
238 HRESULT hr;
239 LONGLONG pos = 0xdeadbeef;
240 IMediaSeeking *seeking = NULL;
241 IMediaFilter *filter = NULL;
242 IMediaControl *control = NULL;
244 IFilterGraph2_SetDefaultSyncSource(pgraph);
245 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking);
246 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
247 if (FAILED(hr))
248 return;
250 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
251 ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
252 if (FAILED(hr))
254 IUnknown_Release(seeking);
255 return;
258 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
259 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
260 if (FAILED(hr))
262 IUnknown_Release(seeking);
263 IUnknown_Release(filter);
264 return;
267 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
268 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
269 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
271 IMediaFilter_SetSyncSource(filter, NULL);
272 pos = 0xdeadbeef;
273 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
274 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
275 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
277 hr = IMediaControl_GetState(control, 1000, NULL);
278 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
280 IUnknown_Release(control);
281 IUnknown_Release(seeking);
282 IUnknown_Release(filter);
283 releasefiltergraph();
286 static void test_filter_graph2(void)
288 HRESULT hr;
289 IFilterGraph2 *pF = NULL;
291 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
292 &IID_IFilterGraph2, (LPVOID*)&pF);
293 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
294 ok(pF != NULL, "pF is NULL\n");
296 hr = IFilterGraph2_Release(pF);
297 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
300 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
301 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
303 if (pMediaType->pbFormat)
305 CoTaskMemFree(pMediaType->pbFormat);
306 pMediaType->pbFormat = NULL;
308 if (pMediaType->pUnk)
310 IUnknown_Release(pMediaType->pUnk);
311 pMediaType->pUnk = NULL;
315 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
317 *pDest = *pSrc;
318 if (!pSrc->pbFormat) return S_OK;
319 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
320 return E_OUTOFMEMORY;
321 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
322 if (pDest->pUnk)
323 IUnknown_AddRef(pDest->pUnk);
324 return S_OK;
327 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
329 AM_MEDIA_TYPE * pDest;
331 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
332 if (!pDest)
333 return NULL;
335 if (FAILED(CopyMediaType(pDest, pSrc)))
337 CoTaskMemFree(pDest);
338 return NULL;
341 return pDest;
344 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
346 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
347 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
350 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
352 FreeMediaType(pMediaType);
353 CoTaskMemFree(pMediaType);
356 typedef struct IEnumMediaTypesImpl
358 const IEnumMediaTypesVtbl * lpVtbl;
359 LONG refCount;
360 AM_MEDIA_TYPE *pMediaTypes;
361 ULONG cMediaTypes;
362 ULONG uIndex;
363 } IEnumMediaTypesImpl;
365 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
367 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
369 ULONG i;
370 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
372 if (!pEnumMediaTypes)
374 *ppEnum = NULL;
375 return E_OUTOFMEMORY;
377 pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl;
378 pEnumMediaTypes->refCount = 1;
379 pEnumMediaTypes->uIndex = 0;
380 pEnumMediaTypes->cMediaTypes = cMediaTypes;
381 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
382 for (i = 0; i < cMediaTypes; i++)
383 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
385 while (i--)
386 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
387 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
388 return E_OUTOFMEMORY;
390 *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl);
391 return S_OK;
394 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
396 *ppv = NULL;
398 if (IsEqualIID(riid, &IID_IUnknown))
399 *ppv = (LPVOID)iface;
400 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
401 *ppv = (LPVOID)iface;
403 if (*ppv)
405 IUnknown_AddRef((IUnknown *)(*ppv));
406 return S_OK;
409 return E_NOINTERFACE;
412 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
414 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
415 ULONG refCount = InterlockedIncrement(&This->refCount);
417 return refCount;
420 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
422 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
423 ULONG refCount = InterlockedDecrement(&This->refCount);
425 if (!refCount)
427 int i;
428 for (i = 0; i < This->cMediaTypes; i++)
429 FreeMediaType(&This->pMediaTypes[i]);
430 CoTaskMemFree(This->pMediaTypes);
431 CoTaskMemFree(This);
433 return refCount;
436 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
438 ULONG cFetched;
439 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
441 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
443 if (cFetched > 0)
445 ULONG i;
446 for (i = 0; i < cFetched; i++)
447 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
449 while (i--)
450 DeleteMediaType(ppMediaTypes[i]);
451 *pcFetched = 0;
452 return E_OUTOFMEMORY;
456 if ((cMediaTypes != 1) || pcFetched)
457 *pcFetched = cFetched;
459 This->uIndex += cFetched;
461 if (cFetched != cMediaTypes)
462 return S_FALSE;
463 return S_OK;
466 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
468 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
470 if (This->uIndex + cMediaTypes < This->cMediaTypes)
472 This->uIndex += cMediaTypes;
473 return S_OK;
475 return S_FALSE;
478 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
480 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
482 This->uIndex = 0;
483 return S_OK;
486 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
488 HRESULT hr;
489 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
491 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
492 if (FAILED(hr))
493 return hr;
494 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
497 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
499 IEnumMediaTypesImpl_QueryInterface,
500 IEnumMediaTypesImpl_AddRef,
501 IEnumMediaTypesImpl_Release,
502 IEnumMediaTypesImpl_Next,
503 IEnumMediaTypesImpl_Skip,
504 IEnumMediaTypesImpl_Reset,
505 IEnumMediaTypesImpl_Clone
508 /* Implementation of a very stripped down pin for the test filter. Just enough
509 functionality for connecting and Render() to work. */
511 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
513 lstrcpyW(pDest->achName, pSrc->achName);
514 pDest->dir = pSrc->dir;
515 pDest->pFilter = pSrc->pFilter;
518 typedef struct ITestPinImpl
520 const struct IPinVtbl * lpVtbl;
521 LONG refCount;
522 LPCRITICAL_SECTION pCritSec;
523 PIN_INFO pinInfo;
524 IPin * pConnectedTo;
525 AM_MEDIA_TYPE mtCurrent;
526 LPVOID pUserData;
527 } ITestPinImpl;
529 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
531 *ppv = NULL;
533 if (IsEqualIID(riid, &IID_IUnknown))
534 *ppv = (LPVOID)iface;
535 else if (IsEqualIID(riid, &IID_IPin))
536 *ppv = (LPVOID)iface;
538 if (*ppv)
540 IUnknown_AddRef((IUnknown *)(*ppv));
541 return S_OK;
544 return E_NOINTERFACE;
547 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
549 ITestPinImpl *This = (ITestPinImpl *)iface;
550 ULONG refCount = InterlockedIncrement(&This->refCount);
551 return refCount;
554 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
556 ITestPinImpl *This = (ITestPinImpl *)iface;
557 ULONG refCount = InterlockedDecrement(&This->refCount);
559 if (!refCount)
561 FreeMediaType(&This->mtCurrent);
562 This->lpVtbl = NULL;
563 CoTaskMemFree(This);
564 return 0;
566 else
567 return refCount;
570 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
572 return E_UNEXPECTED;
575 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
577 ITestPinImpl *This = (ITestPinImpl *)iface;
578 PIN_DIRECTION pindirReceive;
579 HRESULT hr = S_OK;
581 EnterCriticalSection(This->pCritSec);
583 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
584 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
585 hr = VFW_E_TYPE_NOT_ACCEPTED;
587 if (This->pConnectedTo)
588 hr = VFW_E_ALREADY_CONNECTED;
590 if (SUCCEEDED(hr))
592 IPin_QueryDirection(pReceivePin, &pindirReceive);
594 if (pindirReceive != PINDIR_OUTPUT)
596 hr = VFW_E_INVALID_DIRECTION;
600 if (SUCCEEDED(hr))
602 CopyMediaType(&This->mtCurrent, pmt);
603 This->pConnectedTo = pReceivePin;
604 IPin_AddRef(pReceivePin);
607 LeaveCriticalSection(This->pCritSec);
609 return hr;
612 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
614 HRESULT hr;
615 ITestPinImpl *This = (ITestPinImpl *)iface;
617 EnterCriticalSection(This->pCritSec);
619 if (This->pConnectedTo)
621 IPin_Release(This->pConnectedTo);
622 This->pConnectedTo = NULL;
623 hr = S_OK;
625 else
626 hr = S_FALSE;
628 LeaveCriticalSection(This->pCritSec);
630 return hr;
633 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
635 HRESULT hr;
636 ITestPinImpl *This = (ITestPinImpl *)iface;
638 EnterCriticalSection(This->pCritSec);
640 if (This->pConnectedTo)
642 *ppPin = This->pConnectedTo;
643 IPin_AddRef(*ppPin);
644 hr = S_OK;
646 else
648 hr = VFW_E_NOT_CONNECTED;
649 *ppPin = NULL;
652 LeaveCriticalSection(This->pCritSec);
654 return hr;
657 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
659 HRESULT hr;
660 ITestPinImpl *This = (ITestPinImpl *)iface;
662 EnterCriticalSection(This->pCritSec);
664 if (This->pConnectedTo)
666 CopyMediaType(pmt, &This->mtCurrent);
667 hr = S_OK;
669 else
671 ZeroMemory(pmt, sizeof(*pmt));
672 hr = VFW_E_NOT_CONNECTED;
675 LeaveCriticalSection(This->pCritSec);
677 return hr;
680 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
682 ITestPinImpl *This = (ITestPinImpl *)iface;
684 Copy_PinInfo(pInfo, &This->pinInfo);
685 IBaseFilter_AddRef(pInfo->pFilter);
687 return S_OK;
690 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
692 ITestPinImpl *This = (ITestPinImpl *)iface;
694 *pPinDir = This->pinInfo.dir;
696 return S_OK;
699 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
701 return E_NOTIMPL;
704 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
706 ITestPinImpl *This = (ITestPinImpl *)iface;
708 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
709 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
710 return S_OK;
711 else
712 return VFW_E_TYPE_NOT_ACCEPTED;
715 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
717 ITestPinImpl *This = (ITestPinImpl *)iface;
719 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
722 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
724 return E_NOTIMPL;
727 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
729 return E_NOTIMPL;
732 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
734 return E_NOTIMPL;
737 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
739 return E_NOTIMPL;
742 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
744 return E_NOTIMPL;
747 static const IPinVtbl TestFilter_InputPin_Vtbl =
749 TestFilter_Pin_QueryInterface,
750 TestFilter_Pin_AddRef,
751 TestFilter_Pin_Release,
752 TestFilter_InputPin_Connect,
753 TestFilter_InputPin_ReceiveConnection,
754 TestFilter_Pin_Disconnect,
755 TestFilter_Pin_ConnectedTo,
756 TestFilter_Pin_ConnectionMediaType,
757 TestFilter_Pin_QueryPinInfo,
758 TestFilter_Pin_QueryDirection,
759 TestFilter_Pin_QueryId,
760 TestFilter_Pin_QueryAccept,
761 TestFilter_Pin_EnumMediaTypes,
762 TestFilter_Pin_QueryInternalConnections,
763 TestFilter_Pin_EndOfStream,
764 TestFilter_Pin_BeginFlush,
765 TestFilter_Pin_EndFlush,
766 TestFilter_Pin_NewSegment
769 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
771 return E_UNEXPECTED;
774 /* Private helper function */
775 static HRESULT WINAPI TestFilter_OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
777 ITestPinImpl *This = (ITestPinImpl *)iface;
778 HRESULT hr;
780 This->pConnectedTo = pReceivePin;
781 IPin_AddRef(pReceivePin);
783 hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
785 if (FAILED(hr))
787 IPin_Release(This->pConnectedTo);
788 This->pConnectedTo = NULL;
791 return hr;
794 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
796 ITestPinImpl *This = (ITestPinImpl *)iface;
797 HRESULT hr;
799 EnterCriticalSection(This->pCritSec);
801 /* if we have been a specific type to connect with, then we can either connect
802 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
803 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
804 hr = TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, pmt);
805 else
807 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
808 (TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, &This->mtCurrent) == S_OK))
809 hr = S_OK;
810 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
811 } /* if negotiate media type */
812 } /* if succeeded */
813 LeaveCriticalSection(This->pCritSec);
815 return hr;
818 static const IPinVtbl TestFilter_OutputPin_Vtbl =
820 TestFilter_Pin_QueryInterface,
821 TestFilter_Pin_AddRef,
822 TestFilter_Pin_Release,
823 TestFilter_OutputPin_Connect,
824 TestFilter_OutputPin_ReceiveConnection,
825 TestFilter_Pin_Disconnect,
826 TestFilter_Pin_ConnectedTo,
827 TestFilter_Pin_ConnectionMediaType,
828 TestFilter_Pin_QueryPinInfo,
829 TestFilter_Pin_QueryDirection,
830 TestFilter_Pin_QueryId,
831 TestFilter_Pin_QueryAccept,
832 TestFilter_Pin_EnumMediaTypes,
833 TestFilter_Pin_QueryInternalConnections,
834 TestFilter_Pin_EndOfStream,
835 TestFilter_Pin_BeginFlush,
836 TestFilter_Pin_EndFlush,
837 TestFilter_Pin_NewSegment
840 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
841 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
843 ITestPinImpl * pPinImpl;
845 *ppPin = NULL;
847 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
849 if (!pPinImpl)
850 return E_OUTOFMEMORY;
852 pPinImpl->refCount = 1;
853 pPinImpl->pConnectedTo = NULL;
854 pPinImpl->pCritSec = pCritSec;
855 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
856 pPinImpl->mtCurrent = *pinmt;
858 pPinImpl->lpVtbl = Pin_Vtbl;
860 *ppPin = (IPin *)pPinImpl;
861 return S_OK;
864 /* IEnumPins implementation */
866 typedef HRESULT (* FNOBTAINPIN)(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick);
868 typedef struct IEnumPinsImpl
870 const IEnumPinsVtbl * lpVtbl;
871 LONG refCount;
872 ULONG uIndex;
873 IBaseFilter *base;
874 FNOBTAINPIN receive_pin;
875 DWORD synctime;
876 } IEnumPinsImpl;
878 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
880 static HRESULT IEnumPinsImpl_Construct(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, IBaseFilter *base)
882 IEnumPinsImpl * pEnumPins;
884 if (!ppEnum)
885 return E_POINTER;
887 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
888 if (!pEnumPins)
890 *ppEnum = NULL;
891 return E_OUTOFMEMORY;
893 pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl;
894 pEnumPins->refCount = 1;
895 pEnumPins->uIndex = 0;
896 pEnumPins->receive_pin = receive_pin;
897 pEnumPins->base = base;
898 IBaseFilter_AddRef(base);
899 *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl);
901 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
903 return S_OK;
906 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
908 *ppv = NULL;
910 if (IsEqualIID(riid, &IID_IUnknown))
911 *ppv = (LPVOID)iface;
912 else if (IsEqualIID(riid, &IID_IEnumPins))
913 *ppv = (LPVOID)iface;
915 if (*ppv)
917 IUnknown_AddRef((IUnknown *)(*ppv));
918 return S_OK;
921 return E_NOINTERFACE;
924 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
926 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
927 ULONG refCount = InterlockedIncrement(&This->refCount);
929 return refCount;
932 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
934 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
935 ULONG refCount = InterlockedDecrement(&This->refCount);
937 if (!refCount)
939 IBaseFilter_Release(This->base);
940 CoTaskMemFree(This);
941 return 0;
943 else
944 return refCount;
947 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
949 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
950 DWORD synctime = This->synctime;
951 HRESULT hr = S_OK;
952 ULONG i = 0;
954 if (!ppPins)
955 return E_POINTER;
957 if (cPins > 1 && !pcFetched)
958 return E_INVALIDARG;
960 if (pcFetched)
961 *pcFetched = 0;
963 while (i < cPins && hr == S_OK)
965 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
967 if (hr == S_OK)
968 ++i;
970 if (synctime != This->synctime)
971 break;
974 if (!i && synctime != This->synctime)
975 return VFW_E_ENUM_OUT_OF_SYNC;
977 if (pcFetched)
978 *pcFetched = i;
979 This->uIndex += i;
981 if (i < cPins)
982 return S_FALSE;
983 return S_OK;
986 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
988 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
989 DWORD synctime = This->synctime;
990 HRESULT hr;
991 IPin *pin = NULL;
993 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
994 if (pin)
995 IPin_Release(pin);
997 if (synctime != This->synctime)
998 return VFW_E_ENUM_OUT_OF_SYNC;
1000 if (hr == S_OK)
1001 This->uIndex += cPins;
1003 return hr;
1006 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1008 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1010 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1012 This->uIndex = 0;
1013 return S_OK;
1016 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1018 HRESULT hr;
1019 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1021 hr = IEnumPinsImpl_Construct(ppEnum, This->receive_pin, This->base);
1022 if (FAILED(hr))
1023 return hr;
1024 return IEnumPins_Skip(*ppEnum, This->uIndex);
1027 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1029 IEnumPinsImpl_QueryInterface,
1030 IEnumPinsImpl_AddRef,
1031 IEnumPinsImpl_Release,
1032 IEnumPinsImpl_Next,
1033 IEnumPinsImpl_Skip,
1034 IEnumPinsImpl_Reset,
1035 IEnumPinsImpl_Clone
1038 /* Test filter implementation - a filter that has few predefined pins with single media type
1039 * that accept only this single media type. Enough for Render(). */
1041 typedef struct TestFilterPinData
1043 PIN_DIRECTION pinDir;
1044 const GUID *mediasubtype;
1045 } TestFilterPinData;
1047 typedef struct TestFilterImpl
1049 const IBaseFilterVtbl * lpVtbl;
1051 LONG refCount;
1052 CRITICAL_SECTION csFilter;
1053 FILTER_STATE state;
1054 FILTER_INFO filterInfo;
1055 CLSID clsid;
1056 IPin ** ppPins;
1057 UINT nPins;
1058 } TestFilterImpl;
1060 static const IBaseFilterVtbl TestFilter_Vtbl;
1062 static HRESULT TestFilter_Create(const CLSID* pClsid, const TestFilterPinData *pinData, LPVOID * ppv)
1064 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1065 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1066 HRESULT hr;
1067 PIN_INFO pinInfo;
1068 TestFilterImpl* pTestFilter = NULL;
1069 UINT nPins, i;
1070 AM_MEDIA_TYPE mt;
1072 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1073 if (!pTestFilter) return E_OUTOFMEMORY;
1075 pTestFilter->clsid = *pClsid;
1076 pTestFilter->lpVtbl = &TestFilter_Vtbl;
1077 pTestFilter->refCount = 1;
1078 InitializeCriticalSection(&pTestFilter->csFilter);
1079 pTestFilter->state = State_Stopped;
1081 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1083 nPins = 0;
1084 while(pinData[nPins].mediasubtype) ++nPins;
1086 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1087 if (!pTestFilter->ppPins)
1089 hr = E_OUTOFMEMORY;
1090 goto error;
1092 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1094 for (i = 0; i < nPins; i++)
1096 ZeroMemory(&mt, sizeof(mt));
1097 mt.majortype = MEDIATYPE_Video;
1098 mt.formattype = FORMAT_None;
1099 mt.subtype = *pinData[i].mediasubtype;
1101 pinInfo.dir = pinData[i].pinDir;
1102 pinInfo.pFilter = (IBaseFilter *)pTestFilter;
1103 if (pinInfo.dir == PINDIR_INPUT)
1105 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1106 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1107 &pTestFilter->ppPins[i]);
1110 else
1112 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1113 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1114 &pTestFilter->ppPins[i]);
1116 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1119 pTestFilter->nPins = nPins;
1120 *ppv = (LPVOID)pTestFilter;
1121 return S_OK;
1123 error:
1125 for (i = 0; i < nPins; i++)
1127 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1129 CoTaskMemFree(pTestFilter->ppPins);
1130 DeleteCriticalSection(&pTestFilter->csFilter);
1131 CoTaskMemFree(pTestFilter);
1133 return hr;
1136 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1138 TestFilterImpl *This = (TestFilterImpl *)iface;
1140 *ppv = NULL;
1142 if (IsEqualIID(riid, &IID_IUnknown))
1143 *ppv = (LPVOID)This;
1144 else if (IsEqualIID(riid, &IID_IPersist))
1145 *ppv = (LPVOID)This;
1146 else if (IsEqualIID(riid, &IID_IMediaFilter))
1147 *ppv = (LPVOID)This;
1148 else if (IsEqualIID(riid, &IID_IBaseFilter))
1149 *ppv = (LPVOID)This;
1151 if (*ppv)
1153 IUnknown_AddRef((IUnknown *)(*ppv));
1154 return S_OK;
1157 return E_NOINTERFACE;
1160 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1162 TestFilterImpl *This = (TestFilterImpl *)iface;
1163 ULONG refCount = InterlockedIncrement(&This->refCount);
1165 return refCount;
1168 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1170 TestFilterImpl *This = (TestFilterImpl *)iface;
1171 ULONG refCount = InterlockedDecrement(&This->refCount);
1173 if (!refCount)
1175 ULONG i;
1177 for (i = 0; i < This->nPins; i++)
1179 IPin *pConnectedTo;
1181 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1183 IPin_Disconnect(pConnectedTo);
1184 IPin_Release(pConnectedTo);
1186 IPin_Disconnect(This->ppPins[i]);
1188 IPin_Release(This->ppPins[i]);
1191 CoTaskMemFree(This->ppPins);
1192 This->lpVtbl = NULL;
1194 DeleteCriticalSection(&This->csFilter);
1196 CoTaskMemFree(This);
1198 return 0;
1200 else
1201 return refCount;
1203 /** IPersist methods **/
1205 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1207 TestFilterImpl *This = (TestFilterImpl *)iface;
1209 *pClsid = This->clsid;
1211 return S_OK;
1214 /** IMediaFilter methods **/
1216 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1218 return E_NOTIMPL;
1221 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1223 return E_NOTIMPL;
1226 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1228 return E_NOTIMPL;
1231 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1233 TestFilterImpl *This = (TestFilterImpl *)iface;
1235 EnterCriticalSection(&This->csFilter);
1237 *pState = This->state;
1239 LeaveCriticalSection(&This->csFilter);
1241 return S_OK;
1244 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1246 return E_NOTIMPL;
1249 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1251 return E_NOTIMPL;
1254 /** IBaseFilter implementation **/
1256 static HRESULT TestFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
1258 TestFilterImpl *This = (TestFilterImpl *)iface;
1260 /* Our pins are static, not changing so setting static tick count is ok */
1261 *lastsynctick = 0;
1263 if (pos >= This->nPins)
1264 return S_FALSE;
1266 *pin = This->ppPins[pos];
1267 IPin_AddRef(*pin);
1268 return S_OK;
1271 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1273 return IEnumPinsImpl_Construct(ppEnum, TestFilter_GetPin, iface);
1276 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1278 return E_NOTIMPL;
1281 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1283 TestFilterImpl *This = (TestFilterImpl *)iface;
1285 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1286 pInfo->pGraph = This->filterInfo.pGraph;
1288 if (pInfo->pGraph)
1289 IFilterGraph_AddRef(pInfo->pGraph);
1291 return S_OK;
1294 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1296 HRESULT hr = S_OK;
1297 TestFilterImpl *This = (TestFilterImpl *)iface;
1299 EnterCriticalSection(&This->csFilter);
1301 if (pName)
1302 lstrcpyW(This->filterInfo.achName, pName);
1303 else
1304 *This->filterInfo.achName = '\0';
1305 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1307 LeaveCriticalSection(&This->csFilter);
1309 return hr;
1312 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1314 return E_NOTIMPL;
1317 static const IBaseFilterVtbl TestFilter_Vtbl =
1319 TestFilter_QueryInterface,
1320 TestFilter_AddRef,
1321 TestFilter_Release,
1322 TestFilter_GetClassID,
1323 TestFilter_Stop,
1324 TestFilter_Pause,
1325 TestFilter_Run,
1326 TestFilter_GetState,
1327 TestFilter_SetSyncSource,
1328 TestFilter_GetSyncSource,
1329 TestFilter_EnumPins,
1330 TestFilter_FindPin,
1331 TestFilter_QueryFilterInfo,
1332 TestFilter_JoinFilterGraph,
1333 TestFilter_QueryVendorInfo
1336 /* IClassFactory implementation */
1338 typedef struct TestClassFactoryImpl
1340 IClassFactoryVtbl *lpVtbl;
1341 const TestFilterPinData *filterPinData;
1342 const CLSID *clsid;
1343 } TestClassFactoryImpl;
1345 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1346 LPCLASSFACTORY iface,
1347 REFIID riid,
1348 LPVOID *ppvObj)
1350 if (ppvObj == NULL) return E_POINTER;
1352 if (IsEqualGUID(riid, &IID_IUnknown) ||
1353 IsEqualGUID(riid, &IID_IClassFactory))
1355 *ppvObj = (LPVOID)iface;
1356 IClassFactory_AddRef(iface);
1357 return S_OK;
1360 *ppvObj = NULL;
1361 return E_NOINTERFACE;
1364 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1366 return 2; /* non-heap-based object */
1369 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1371 return 1; /* non-heap-based object */
1374 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1375 LPCLASSFACTORY iface,
1376 LPUNKNOWN pUnkOuter,
1377 REFIID riid,
1378 LPVOID *ppvObj)
1380 TestClassFactoryImpl *This = (TestClassFactoryImpl *)iface;
1381 HRESULT hr;
1382 IUnknown *punk = NULL;
1384 *ppvObj = NULL;
1386 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1388 hr = TestFilter_Create(This->clsid, This->filterPinData, (LPVOID *) &punk);
1389 if (SUCCEEDED(hr)) {
1390 hr = IUnknown_QueryInterface(punk, riid, ppvObj);
1391 IUnknown_Release(punk);
1393 return hr;
1396 static HRESULT WINAPI Test_IClassFactory_LockServer(
1397 LPCLASSFACTORY iface,
1398 BOOL fLock)
1400 return S_OK;
1403 static IClassFactoryVtbl TestClassFactory_Vtbl =
1405 Test_IClassFactory_QueryInterface,
1406 Test_IClassFactory_AddRef,
1407 Test_IClassFactory_Release,
1408 Test_IClassFactory_CreateInstance,
1409 Test_IClassFactory_LockServer
1412 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1414 IPin *pin = NULL;
1415 PIN_INFO pinInfo;
1416 FILTER_INFO filterInfo;
1417 HRESULT hr;
1419 FilterName[0] = 0;
1421 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1422 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1423 if (FAILED(hr)) return hr;
1425 hr = IPin_QueryPinInfo(pin, &pinInfo);
1426 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1427 IPin_Release(pin);
1428 if (FAILED(hr)) return hr;
1430 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1431 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1432 IBaseFilter_Release(pinInfo.pFilter);
1433 if (FAILED(hr)) return hr;
1435 IFilterGraph_Release(filterInfo.pGraph);
1437 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1439 return S_OK;
1442 static void test_render_filter_priority(void)
1444 /* Tests filter choice priorities in Render(). */
1445 DWORD cookie1, cookie2, cookie3;
1446 HRESULT hr;
1447 IFilterGraph2* pgraph2 = NULL;
1448 IFilterMapper2 *pMapper2 = NULL;
1449 IBaseFilter* ptestfilter = NULL;
1450 IBaseFilter* ptestfilter2 = NULL;
1451 static const CLSID CLSID_TestFilter2 = {
1452 0x37a4edb0,
1453 0x4d13,
1454 0x11dd,
1455 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1457 static const CLSID CLSID_TestFilter3 = {
1458 0x37a4f2d8,
1459 0x4d13,
1460 0x11dd,
1461 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1463 static const CLSID CLSID_TestFilter4 = {
1464 0x37a4f3b4,
1465 0x4d13,
1466 0x11dd,
1467 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1469 static const GUID mediasubtype1 = {
1470 0x37a4f51c,
1471 0x4d13,
1472 0x11dd,
1473 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1475 static const GUID mediasubtype2 = {
1476 0x37a4f5c6,
1477 0x4d13,
1478 0x11dd,
1479 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1481 static const TestFilterPinData PinData1[] = {
1482 { PINDIR_OUTPUT, &mediasubtype1 },
1483 { 0, 0 }
1485 static const TestFilterPinData PinData2[] = {
1486 { PINDIR_INPUT, &mediasubtype1 },
1487 { 0, 0 }
1489 static const TestFilterPinData PinData3[] = {
1490 { PINDIR_INPUT, &GUID_NULL },
1491 { 0, 0 }
1493 static const TestFilterPinData PinData4[] = {
1494 { PINDIR_INPUT, &mediasubtype1 },
1495 { PINDIR_OUTPUT, &mediasubtype2 },
1496 { 0, 0 }
1498 static const TestFilterPinData PinData5[] = {
1499 { PINDIR_INPUT, &mediasubtype2 },
1500 { 0, 0 }
1502 TestClassFactoryImpl Filter1ClassFactory = { &TestClassFactory_Vtbl, PinData2, &CLSID_TestFilter2 };
1503 TestClassFactoryImpl Filter2ClassFactory = { &TestClassFactory_Vtbl, PinData4, &CLSID_TestFilter3 };
1504 TestClassFactoryImpl Filter3ClassFactory = { &TestClassFactory_Vtbl, PinData5, &CLSID_TestFilter4 };
1505 char ConnectedFilterName1[MAX_FILTER_NAME];
1506 char ConnectedFilterName2[MAX_FILTER_NAME];
1507 REGFILTER2 rgf2;
1508 REGFILTERPINS2 rgPins2[2];
1509 REGPINTYPES rgPinType[2];
1510 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1511 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1512 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1513 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1514 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1515 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1516 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1517 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1519 /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is
1520 "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating
1521 no preference given to exact match. */
1522 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1523 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1524 if (!pgraph2) goto out;
1526 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1527 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1528 if (FAILED(hr)) goto out;
1530 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1531 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1533 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1534 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1535 if (FAILED(hr)) goto out;
1537 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1538 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1540 IBaseFilter_Release(ptestfilter2);
1541 ptestfilter2 = NULL;
1543 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1544 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1545 if (FAILED(hr)) goto out;
1547 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1548 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1550 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1551 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1553 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1555 IFilterGraph2_Release(pgraph2);
1556 pgraph2 = NULL;
1557 IBaseFilter_Release(ptestfilter);
1558 ptestfilter = NULL;
1559 IBaseFilter_Release(ptestfilter2);
1560 ptestfilter2 = NULL;
1562 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1563 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1564 if (!pgraph2) goto out;
1566 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1567 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1568 if (FAILED(hr)) goto out;
1570 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1571 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1573 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1574 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1575 if (FAILED(hr)) goto out;
1577 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1578 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1580 IBaseFilter_Release(ptestfilter2);
1581 ptestfilter2 = NULL;
1583 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1584 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1585 if (FAILED(hr)) goto out;
1587 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1588 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1590 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1591 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1593 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1594 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1595 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1597 IFilterGraph2_Release(pgraph2);
1598 pgraph2 = NULL;
1599 IBaseFilter_Release(ptestfilter);
1600 ptestfilter = NULL;
1601 IBaseFilter_Release(ptestfilter2);
1602 ptestfilter2 = NULL;
1604 /* Test if any preference is given to existing renderer which renders the pin directly vs
1605 an existing renderer which renders the pin indirectly, through an additional middle filter,
1606 again trying different orders of creation. Native appears not to give a preference. */
1608 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1609 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1610 if (!pgraph2) goto out;
1612 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1613 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1614 if (FAILED(hr)) goto out;
1616 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1617 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1619 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1620 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1621 if (FAILED(hr)) goto out;
1623 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1624 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1626 IBaseFilter_Release(ptestfilter2);
1627 ptestfilter2 = NULL;
1629 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1630 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1631 if (FAILED(hr)) goto out;
1633 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1634 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1636 IBaseFilter_Release(ptestfilter2);
1637 ptestfilter2 = NULL;
1639 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1640 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1641 if (FAILED(hr)) goto out;
1643 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1644 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1646 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1647 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1649 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1650 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1, "TestfilterInstance2"),
1651 "unexpected connected filter: %s\n", ConnectedFilterName1);
1653 IFilterGraph2_Release(pgraph2);
1654 pgraph2 = NULL;
1655 IBaseFilter_Release(ptestfilter);
1656 ptestfilter = NULL;
1657 IBaseFilter_Release(ptestfilter2);
1658 ptestfilter2 = NULL;
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 = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1665 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1666 if (FAILED(hr)) goto out;
1668 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1669 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1671 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1672 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1673 if (FAILED(hr)) goto out;
1675 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1676 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1678 IBaseFilter_Release(ptestfilter2);
1679 ptestfilter2 = NULL;
1681 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1682 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1683 if (FAILED(hr)) goto out;
1685 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1686 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1688 IBaseFilter_Release(ptestfilter2);
1689 ptestfilter2 = NULL;
1691 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1692 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1693 if (FAILED(hr)) goto out;
1695 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1696 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1698 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1699 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1701 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1702 ok(!lstrcmp(ConnectedFilterName2, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2, "TestfilterInstance2"),
1703 "unexpected connected filter: %s\n", ConnectedFilterName2);
1704 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1705 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1707 IFilterGraph2_Release(pgraph2);
1708 pgraph2 = NULL;
1709 IBaseFilter_Release(ptestfilter);
1710 ptestfilter = NULL;
1711 IBaseFilter_Release(ptestfilter2);
1712 ptestfilter2 = NULL;
1714 /* Test if renderers are tried before non-renderers (intermediary filters). */
1715 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1716 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1717 if (!pgraph2) goto out;
1719 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
1720 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1721 if (!pMapper2) goto out;
1723 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1724 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1725 if (FAILED(hr)) goto out;
1727 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1728 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1730 /* Register our filters with COM and with Filtermapper. */
1731 hr = CoRegisterClassObject(Filter1ClassFactory.clsid, (IUnknown *)&Filter1ClassFactory,
1732 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie1);
1733 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1734 hr = CoRegisterClassObject(Filter2ClassFactory.clsid, (IUnknown *)&Filter2ClassFactory,
1735 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie2);
1736 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1737 hr = CoRegisterClassObject(Filter3ClassFactory.clsid, (IUnknown *)&Filter3ClassFactory,
1738 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie3);
1739 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1741 rgf2.dwVersion = 2;
1742 rgf2.dwMerit = MERIT_UNLIKELY;
1743 S1(U(rgf2)).cPins2 = 1;
1744 S1(U(rgf2)).rgPins2 = rgPins2;
1745 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
1746 rgPins2[0].cInstances = 1;
1747 rgPins2[0].nMediaTypes = 1;
1748 rgPins2[0].lpMediaType = &rgPinType[0];
1749 rgPins2[0].nMediums = 0;
1750 rgPins2[0].lpMedium = NULL;
1751 rgPins2[0].clsPinCategory = NULL;
1752 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
1753 rgPinType[0].clsMinorType = &mediasubtype1;
1755 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
1756 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1757 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1759 rgf2.dwMerit = MERIT_PREFERRED;
1760 rgPinType[0].clsMinorType = &mediasubtype2;
1762 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
1763 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1764 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1766 S1(U(rgf2)).cPins2 = 2;
1767 rgPins2[0].dwFlags = 0;
1768 rgPinType[0].clsMinorType = &mediasubtype1;
1770 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
1771 rgPins2[1].cInstances = 1;
1772 rgPins2[1].nMediaTypes = 1;
1773 rgPins2[1].lpMediaType = &rgPinType[1];
1774 rgPins2[1].nMediums = 0;
1775 rgPins2[1].lpMedium = NULL;
1776 rgPins2[1].clsPinCategory = NULL;
1777 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
1778 rgPinType[1].clsMinorType = &mediasubtype2;
1780 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
1781 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1782 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1784 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1785 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1787 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1788 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3"),
1789 "unexpected connected filter: %s\n", ConnectedFilterName1);
1791 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1792 &CLSID_TestFilter2);
1793 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1794 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1795 &CLSID_TestFilter3);
1796 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1797 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1798 &CLSID_TestFilter4);
1799 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1801 out:
1803 if (ptestfilter) IBaseFilter_Release(ptestfilter);
1804 if (ptestfilter2) IBaseFilter_Release(ptestfilter2);
1805 if (pgraph2) IFilterGraph2_Release(pgraph2);
1806 if (pMapper2) IFilterMapper2_Release(pMapper2);
1808 hr = CoRevokeClassObject(cookie1);
1809 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1810 hr = CoRevokeClassObject(cookie2);
1811 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1812 hr = CoRevokeClassObject(cookie3);
1813 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1816 START_TEST(filtergraph)
1818 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1819 test_render_run();
1820 test_graph_builder();
1821 test_graph_builder_addfilter();
1822 test_mediacontrol();
1823 test_filter_graph2();
1824 test_render_filter_priority();
1825 CoUninitialize();