push c03b0bb7c67acf502e715114ece376179b90ac7c
[wine/hacks.git] / dlls / quartz / tests / filtergraph.c
blob37c1c1f2a17a23b6e1c41fbaf05705da3fb255a4
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 if (pTestFilter->ppPins)
1127 for (i = 0; i < nPins; i++)
1129 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1132 CoTaskMemFree(pTestFilter->ppPins);
1133 DeleteCriticalSection(&pTestFilter->csFilter);
1134 CoTaskMemFree(pTestFilter);
1136 return hr;
1139 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1141 TestFilterImpl *This = (TestFilterImpl *)iface;
1143 *ppv = NULL;
1145 if (IsEqualIID(riid, &IID_IUnknown))
1146 *ppv = (LPVOID)This;
1147 else if (IsEqualIID(riid, &IID_IPersist))
1148 *ppv = (LPVOID)This;
1149 else if (IsEqualIID(riid, &IID_IMediaFilter))
1150 *ppv = (LPVOID)This;
1151 else if (IsEqualIID(riid, &IID_IBaseFilter))
1152 *ppv = (LPVOID)This;
1154 if (*ppv)
1156 IUnknown_AddRef((IUnknown *)(*ppv));
1157 return S_OK;
1160 return E_NOINTERFACE;
1163 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1165 TestFilterImpl *This = (TestFilterImpl *)iface;
1166 ULONG refCount = InterlockedIncrement(&This->refCount);
1168 return refCount;
1171 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1173 TestFilterImpl *This = (TestFilterImpl *)iface;
1174 ULONG refCount = InterlockedDecrement(&This->refCount);
1176 if (!refCount)
1178 ULONG i;
1180 for (i = 0; i < This->nPins; i++)
1182 IPin *pConnectedTo;
1184 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1186 IPin_Disconnect(pConnectedTo);
1187 IPin_Release(pConnectedTo);
1189 IPin_Disconnect(This->ppPins[i]);
1191 IPin_Release(This->ppPins[i]);
1194 CoTaskMemFree(This->ppPins);
1195 This->lpVtbl = NULL;
1197 DeleteCriticalSection(&This->csFilter);
1199 CoTaskMemFree(This);
1201 return 0;
1203 else
1204 return refCount;
1206 /** IPersist methods **/
1208 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1210 TestFilterImpl *This = (TestFilterImpl *)iface;
1212 *pClsid = This->clsid;
1214 return S_OK;
1217 /** IMediaFilter methods **/
1219 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1221 return E_NOTIMPL;
1224 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1226 return E_NOTIMPL;
1229 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1231 return E_NOTIMPL;
1234 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1236 TestFilterImpl *This = (TestFilterImpl *)iface;
1238 EnterCriticalSection(&This->csFilter);
1240 *pState = This->state;
1242 LeaveCriticalSection(&This->csFilter);
1244 return S_OK;
1247 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1249 return E_NOTIMPL;
1252 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1254 return E_NOTIMPL;
1257 /** IBaseFilter implementation **/
1259 static HRESULT TestFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
1261 TestFilterImpl *This = (TestFilterImpl *)iface;
1263 /* Our pins are static, not changing so setting static tick count is ok */
1264 *lastsynctick = 0;
1266 if (pos >= This->nPins)
1267 return S_FALSE;
1269 *pin = This->ppPins[pos];
1270 IPin_AddRef(*pin);
1271 return S_OK;
1274 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1276 return IEnumPinsImpl_Construct(ppEnum, TestFilter_GetPin, iface);
1279 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1281 return E_NOTIMPL;
1284 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1286 TestFilterImpl *This = (TestFilterImpl *)iface;
1288 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1289 pInfo->pGraph = This->filterInfo.pGraph;
1291 if (pInfo->pGraph)
1292 IFilterGraph_AddRef(pInfo->pGraph);
1294 return S_OK;
1297 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1299 HRESULT hr = S_OK;
1300 TestFilterImpl *This = (TestFilterImpl *)iface;
1302 EnterCriticalSection(&This->csFilter);
1304 if (pName)
1305 lstrcpyW(This->filterInfo.achName, pName);
1306 else
1307 *This->filterInfo.achName = '\0';
1308 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1310 LeaveCriticalSection(&This->csFilter);
1312 return hr;
1315 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1317 return E_NOTIMPL;
1320 static const IBaseFilterVtbl TestFilter_Vtbl =
1322 TestFilter_QueryInterface,
1323 TestFilter_AddRef,
1324 TestFilter_Release,
1325 TestFilter_GetClassID,
1326 TestFilter_Stop,
1327 TestFilter_Pause,
1328 TestFilter_Run,
1329 TestFilter_GetState,
1330 TestFilter_SetSyncSource,
1331 TestFilter_GetSyncSource,
1332 TestFilter_EnumPins,
1333 TestFilter_FindPin,
1334 TestFilter_QueryFilterInfo,
1335 TestFilter_JoinFilterGraph,
1336 TestFilter_QueryVendorInfo
1339 /* IClassFactory implementation */
1341 typedef struct TestClassFactoryImpl
1343 IClassFactoryVtbl *lpVtbl;
1344 const TestFilterPinData *filterPinData;
1345 const CLSID *clsid;
1346 } TestClassFactoryImpl;
1348 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1349 LPCLASSFACTORY iface,
1350 REFIID riid,
1351 LPVOID *ppvObj)
1353 if (ppvObj == NULL) return E_POINTER;
1355 if (IsEqualGUID(riid, &IID_IUnknown) ||
1356 IsEqualGUID(riid, &IID_IClassFactory))
1358 *ppvObj = (LPVOID)iface;
1359 IClassFactory_AddRef(iface);
1360 return S_OK;
1363 *ppvObj = NULL;
1364 return E_NOINTERFACE;
1367 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1369 return 2; /* non-heap-based object */
1372 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1374 return 1; /* non-heap-based object */
1377 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1378 LPCLASSFACTORY iface,
1379 LPUNKNOWN pUnkOuter,
1380 REFIID riid,
1381 LPVOID *ppvObj)
1383 TestClassFactoryImpl *This = (TestClassFactoryImpl *)iface;
1384 HRESULT hr;
1385 IUnknown *punk = NULL;
1387 *ppvObj = NULL;
1389 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1391 hr = TestFilter_Create(This->clsid, This->filterPinData, (LPVOID *) &punk);
1392 if (SUCCEEDED(hr)) {
1393 hr = IUnknown_QueryInterface(punk, riid, ppvObj);
1394 IUnknown_Release(punk);
1396 return hr;
1399 static HRESULT WINAPI Test_IClassFactory_LockServer(
1400 LPCLASSFACTORY iface,
1401 BOOL fLock)
1403 return S_OK;
1406 static IClassFactoryVtbl TestClassFactory_Vtbl =
1408 Test_IClassFactory_QueryInterface,
1409 Test_IClassFactory_AddRef,
1410 Test_IClassFactory_Release,
1411 Test_IClassFactory_CreateInstance,
1412 Test_IClassFactory_LockServer
1415 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1417 IPin *pin = NULL;
1418 PIN_INFO pinInfo;
1419 FILTER_INFO filterInfo;
1420 HRESULT hr;
1422 FilterName[0] = 0;
1424 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1425 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1426 if (FAILED(hr)) return hr;
1428 hr = IPin_QueryPinInfo(pin, &pinInfo);
1429 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1430 IPin_Release(pin);
1431 if (FAILED(hr)) return hr;
1433 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1434 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1435 IBaseFilter_Release(pinInfo.pFilter);
1436 if (FAILED(hr)) return hr;
1438 IFilterGraph_Release(filterInfo.pGraph);
1440 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1442 return S_OK;
1445 static void test_render_filter_priority(void)
1447 /* Tests filter choice priorities in Render(). */
1448 DWORD cookie1, cookie2, cookie3;
1449 HRESULT hr;
1450 IFilterGraph2* pgraph2 = NULL;
1451 IFilterMapper2 *pMapper2 = NULL;
1452 IBaseFilter* ptestfilter = NULL;
1453 IBaseFilter* ptestfilter2 = NULL;
1454 static const CLSID CLSID_TestFilter2 = {
1455 0x37a4edb0,
1456 0x4d13,
1457 0x11dd,
1458 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1460 static const CLSID CLSID_TestFilter3 = {
1461 0x37a4f2d8,
1462 0x4d13,
1463 0x11dd,
1464 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1466 static const CLSID CLSID_TestFilter4 = {
1467 0x37a4f3b4,
1468 0x4d13,
1469 0x11dd,
1470 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1472 static const GUID mediasubtype1 = {
1473 0x37a4f51c,
1474 0x4d13,
1475 0x11dd,
1476 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1478 static const GUID mediasubtype2 = {
1479 0x37a4f5c6,
1480 0x4d13,
1481 0x11dd,
1482 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1484 static const TestFilterPinData PinData1[] = {
1485 { PINDIR_OUTPUT, &mediasubtype1 },
1486 { 0, 0 }
1488 static const TestFilterPinData PinData2[] = {
1489 { PINDIR_INPUT, &mediasubtype1 },
1490 { 0, 0 }
1492 static const TestFilterPinData PinData3[] = {
1493 { PINDIR_INPUT, &GUID_NULL },
1494 { 0, 0 }
1496 static const TestFilterPinData PinData4[] = {
1497 { PINDIR_INPUT, &mediasubtype1 },
1498 { PINDIR_OUTPUT, &mediasubtype2 },
1499 { 0, 0 }
1501 static const TestFilterPinData PinData5[] = {
1502 { PINDIR_INPUT, &mediasubtype2 },
1503 { 0, 0 }
1505 TestClassFactoryImpl Filter1ClassFactory = { &TestClassFactory_Vtbl, PinData2, &CLSID_TestFilter2 };
1506 TestClassFactoryImpl Filter2ClassFactory = { &TestClassFactory_Vtbl, PinData4, &CLSID_TestFilter3 };
1507 TestClassFactoryImpl Filter3ClassFactory = { &TestClassFactory_Vtbl, PinData5, &CLSID_TestFilter4 };
1508 char ConnectedFilterName1[MAX_FILTER_NAME];
1509 char ConnectedFilterName2[MAX_FILTER_NAME];
1510 REGFILTER2 rgf2;
1511 REGFILTERPINS2 rgPins2[2];
1512 REGPINTYPES rgPinType[2];
1513 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1514 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1515 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1516 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1517 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1518 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1519 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1520 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1522 /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is
1523 "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating
1524 no preference given to exact match. */
1525 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1526 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1527 if (!pgraph2) goto out;
1529 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1530 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1531 if (FAILED(hr)) goto out;
1533 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1534 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1536 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1537 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1538 if (FAILED(hr)) goto out;
1540 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1541 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1543 IBaseFilter_Release(ptestfilter2);
1544 ptestfilter2 = NULL;
1546 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1547 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1548 if (FAILED(hr)) goto out;
1550 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1551 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1553 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1554 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1556 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1558 IFilterGraph2_Release(pgraph2);
1559 pgraph2 = NULL;
1560 IBaseFilter_Release(ptestfilter);
1561 ptestfilter = NULL;
1562 IBaseFilter_Release(ptestfilter2);
1563 ptestfilter2 = NULL;
1565 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1566 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1567 if (!pgraph2) goto out;
1569 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1570 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1571 if (FAILED(hr)) goto out;
1573 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1574 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1576 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1577 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1578 if (FAILED(hr)) goto out;
1580 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1581 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1583 IBaseFilter_Release(ptestfilter2);
1584 ptestfilter2 = NULL;
1586 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1587 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1588 if (FAILED(hr)) goto out;
1590 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1591 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1593 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1594 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1596 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1597 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1598 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1600 IFilterGraph2_Release(pgraph2);
1601 pgraph2 = NULL;
1602 IBaseFilter_Release(ptestfilter);
1603 ptestfilter = NULL;
1604 IBaseFilter_Release(ptestfilter2);
1605 ptestfilter2 = NULL;
1607 /* Test if any preference is given to existing renderer which renders the pin directly vs
1608 an existing renderer which renders the pin indirectly, through an additional middle filter,
1609 again trying different orders of creation. Native appears not to give a preference. */
1611 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1612 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1613 if (!pgraph2) goto out;
1615 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1616 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1617 if (FAILED(hr)) goto out;
1619 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1620 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1622 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1623 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1624 if (FAILED(hr)) goto out;
1626 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1627 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1629 IBaseFilter_Release(ptestfilter2);
1630 ptestfilter2 = NULL;
1632 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1633 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1634 if (FAILED(hr)) goto out;
1636 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1637 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1639 IBaseFilter_Release(ptestfilter2);
1640 ptestfilter2 = NULL;
1642 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1643 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1644 if (FAILED(hr)) goto out;
1646 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1647 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1649 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1650 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1652 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1653 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1, "TestfilterInstance2"),
1654 "unexpected connected filter: %s\n", ConnectedFilterName1);
1656 IFilterGraph2_Release(pgraph2);
1657 pgraph2 = NULL;
1658 IBaseFilter_Release(ptestfilter);
1659 ptestfilter = NULL;
1660 IBaseFilter_Release(ptestfilter2);
1661 ptestfilter2 = NULL;
1663 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1664 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1665 if (!pgraph2) goto out;
1667 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1668 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1669 if (FAILED(hr)) goto out;
1671 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1672 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1674 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1675 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1676 if (FAILED(hr)) goto out;
1678 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1679 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1681 IBaseFilter_Release(ptestfilter2);
1682 ptestfilter2 = NULL;
1684 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1685 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1686 if (FAILED(hr)) goto out;
1688 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1689 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1691 IBaseFilter_Release(ptestfilter2);
1692 ptestfilter2 = NULL;
1694 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1695 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1696 if (FAILED(hr)) goto out;
1698 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1699 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1701 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1702 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1704 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1705 ok(!lstrcmp(ConnectedFilterName2, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2, "TestfilterInstance2"),
1706 "unexpected connected filter: %s\n", ConnectedFilterName2);
1707 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1708 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1710 IFilterGraph2_Release(pgraph2);
1711 pgraph2 = NULL;
1712 IBaseFilter_Release(ptestfilter);
1713 ptestfilter = NULL;
1714 IBaseFilter_Release(ptestfilter2);
1715 ptestfilter2 = NULL;
1717 /* Test if renderers are tried before non-renderers (intermediary filters). */
1718 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1719 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1720 if (!pgraph2) goto out;
1722 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
1723 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1724 if (!pMapper2) goto out;
1726 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1727 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1728 if (FAILED(hr)) goto out;
1730 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1731 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1733 /* Register our filters with COM and with Filtermapper. */
1734 hr = CoRegisterClassObject(Filter1ClassFactory.clsid, (IUnknown *)&Filter1ClassFactory,
1735 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie1);
1736 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1737 hr = CoRegisterClassObject(Filter2ClassFactory.clsid, (IUnknown *)&Filter2ClassFactory,
1738 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie2);
1739 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1740 hr = CoRegisterClassObject(Filter3ClassFactory.clsid, (IUnknown *)&Filter3ClassFactory,
1741 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie3);
1742 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1744 rgf2.dwVersion = 2;
1745 rgf2.dwMerit = MERIT_UNLIKELY;
1746 S1(U(rgf2)).cPins2 = 1;
1747 S1(U(rgf2)).rgPins2 = rgPins2;
1748 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
1749 rgPins2[0].cInstances = 1;
1750 rgPins2[0].nMediaTypes = 1;
1751 rgPins2[0].lpMediaType = &rgPinType[0];
1752 rgPins2[0].nMediums = 0;
1753 rgPins2[0].lpMedium = NULL;
1754 rgPins2[0].clsPinCategory = NULL;
1755 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
1756 rgPinType[0].clsMinorType = &mediasubtype1;
1758 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
1759 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1760 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1762 rgf2.dwMerit = MERIT_PREFERRED;
1763 rgPinType[0].clsMinorType = &mediasubtype2;
1765 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
1766 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1767 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1769 S1(U(rgf2)).cPins2 = 2;
1770 rgPins2[0].dwFlags = 0;
1771 rgPinType[0].clsMinorType = &mediasubtype1;
1773 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
1774 rgPins2[1].cInstances = 1;
1775 rgPins2[1].nMediaTypes = 1;
1776 rgPins2[1].lpMediaType = &rgPinType[1];
1777 rgPins2[1].nMediums = 0;
1778 rgPins2[1].lpMedium = NULL;
1779 rgPins2[1].clsPinCategory = NULL;
1780 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
1781 rgPinType[1].clsMinorType = &mediasubtype2;
1783 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
1784 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1785 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1787 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1788 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1790 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1791 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3"),
1792 "unexpected connected filter: %s\n", ConnectedFilterName1);
1794 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1795 &CLSID_TestFilter2);
1796 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1797 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1798 &CLSID_TestFilter3);
1799 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1800 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1801 &CLSID_TestFilter4);
1802 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1804 out:
1806 if (ptestfilter) IBaseFilter_Release(ptestfilter);
1807 if (ptestfilter2) IBaseFilter_Release(ptestfilter2);
1808 if (pgraph2) IFilterGraph2_Release(pgraph2);
1809 if (pMapper2) IFilterMapper2_Release(pMapper2);
1811 hr = CoRevokeClassObject(cookie1);
1812 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1813 hr = CoRevokeClassObject(cookie2);
1814 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1815 hr = CoRevokeClassObject(cookie3);
1816 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1819 START_TEST(filtergraph)
1821 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1822 test_render_run();
1823 test_graph_builder();
1824 test_graph_builder_addfilter();
1825 test_mediacontrol();
1826 test_filter_graph2();
1827 test_render_filter_priority();
1828 CoUninitialize();