push e263afdf8dbf9f9408e8594e045d25c4af1d55cd
[wine/hacks.git] / dlls / quartz / tests / filtergraph.c
blobe39097baef9e51bae65f9491d60c5d488f085f8d
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 WCHAR file[] = {'t','e','s','t','.','a','v','i',0};
32 IGraphBuilder* pgraph;
34 static int createfiltergraph(void)
36 return S_OK == CoCreateInstance(
37 &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&pgraph);
40 static void renderfile(void)
42 HRESULT hr;
44 hr = IGraphBuilder_RenderFile(pgraph, file, NULL);
45 ok(hr==S_OK, "RenderFile returned: %x\n", hr);
48 static void rungraph(void)
50 HRESULT hr;
51 IMediaControl* pmc;
52 IMediaEvent* pme;
53 IMediaFilter* pmf;
54 HANDLE hEvent;
56 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (LPVOID*)&pmc);
57 ok(hr==S_OK, "Cannot get IMediaControl interface returned: %x\n", hr);
59 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (LPVOID*)&pmf);
60 ok(hr==S_OK, "Cannot get IMediaFilter interface returned: %x\n", hr);
62 IMediaControl_Stop(pmc);
64 IMediaFilter_SetSyncSource(pmf, NULL);
66 IMediaFilter_Release(pmf);
68 hr = IMediaControl_Run(pmc);
69 ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr);
71 Sleep(10);
72 /* Crash fun */
73 trace("run -> stop\n");
74 hr = IMediaControl_Stop(pmc);
75 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
77 IGraphBuilder_SetDefaultSyncSource(pgraph);
79 Sleep(10);
80 trace("stop -> pause\n");
81 hr = IMediaControl_Pause(pmc);
82 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
84 Sleep(10);
85 trace("pause -> run\n");
86 hr = IMediaControl_Run(pmc);
87 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
89 Sleep(10);
90 trace("run -> pause\n");
91 hr = IMediaControl_Pause(pmc);
92 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
94 Sleep(10);
95 trace("pause -> stop\n");
96 hr = IMediaControl_Stop(pmc);
97 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
99 Sleep(10);
100 trace("pause -> run\n");
101 hr = IMediaControl_Run(pmc);
102 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
104 trace("run -> stop\n");
105 hr = IMediaControl_Stop(pmc);
106 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
108 trace("stop -> run\n");
109 hr = IMediaControl_Run(pmc);
110 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
112 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaEvent, (LPVOID*)&pme);
113 ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr);
115 hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent);
116 ok(hr==S_OK, "Cannot get event handle returned: %x\n", hr);
118 /* WaitForSingleObject(hEvent, INFINITE); */
119 Sleep(20000);
121 hr = IMediaEvent_Release(pme);
122 ok(hr==2, "Releasing mediaevent returned: %x\n", hr);
124 hr = IMediaControl_Stop(pmc);
125 ok(hr==S_OK, "Cannot stop the graph returned: %x\n", hr);
127 hr = IMediaControl_Release(pmc);
128 ok(hr==1, "Releasing mediacontrol returned: %x\n", hr);
131 static void releasefiltergraph(void)
133 HRESULT hr;
135 hr = IGraphBuilder_Release(pgraph);
136 ok(hr==0, "Releasing filtergraph returned: %x\n", hr);
139 static void test_render_run(void)
141 HANDLE h;
143 if (!createfiltergraph())
144 return;
146 h = CreateFileW(file, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
147 if (h != INVALID_HANDLE_VALUE) {
148 CloseHandle(h);
149 renderfile();
150 rungraph();
153 releasefiltergraph();
156 static void test_graph_builder(void)
158 HRESULT hr;
159 IBaseFilter *pF = NULL;
160 IBaseFilter *pF2 = NULL;
161 IPin *pIn = NULL;
162 IEnumPins *pEnum = NULL;
163 PIN_DIRECTION dir;
164 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
165 static const WCHAR fooBarW[] = {'f','o','o','B','a','r',0};
167 if (!createfiltergraph())
168 return;
170 /* create video filter */
171 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
172 &IID_IBaseFilter, (LPVOID*)&pF);
173 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
174 ok(pF != NULL, "pF is NULL\n");
176 /* add the two filters to the graph */
177 hr = IGraphBuilder_AddFilter(pgraph, pF, testFilterW);
178 ok(hr == S_OK, "failed to add pF to the graph: %x\n", hr);
180 /* find the pins */
181 hr = IBaseFilter_EnumPins(pF, &pEnum);
182 ok(hr == S_OK, "IBaseFilter_EnumPins failed for pF: %x\n", hr);
183 ok(pEnum != NULL, "pEnum is NULL\n");
184 hr = IEnumPins_Next(pEnum, 1, &pIn, NULL);
185 ok(hr == S_OK, "IEnumPins_Next failed for pF: %x\n", hr);
186 ok(pIn != NULL, "pIn is NULL\n");
187 hr = IPin_QueryDirection(pIn, &dir);
188 ok(hr == S_OK, "IPin_QueryDirection failed: %x\n", hr);
189 ok(dir == PINDIR_INPUT, "pin has wrong direction\n");
191 hr = IGraphBuilder_FindFilterByName(pgraph, fooBarW, &pF2);
192 ok(hr == VFW_E_NOT_FOUND, "IGraphBuilder_FindFilterByName returned %x\n", hr);
193 ok(pF2 == NULL, "IGraphBuilder_FindFilterByName returned %p\n", pF2);
194 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, &pF2);
195 ok(hr == S_OK, "IGraphBuilder_FindFilterByName returned %x\n", hr);
196 ok(pF2 != NULL, "IGraphBuilder_FindFilterByName returned NULL\n");
197 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, NULL);
198 ok(hr == E_POINTER, "IGraphBuilder_FindFilterByName returned %x\n", hr);
200 if (pIn) IPin_Release(pIn);
201 if (pEnum) IEnumPins_Release(pEnum);
202 if (pF) IBaseFilter_Release(pF);
203 if (pF2) IBaseFilter_Release(pF2);
205 releasefiltergraph();
208 static void test_graph_builder_addfilter(void)
210 HRESULT hr;
211 IBaseFilter *pF = NULL;
212 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
214 if (!createfiltergraph())
215 return;
217 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
218 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr);
220 /* create video filter */
221 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
222 &IID_IBaseFilter, (LPVOID*)&pF);
223 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
224 ok(pF != NULL, "pF is NULL\n");
225 if (!pF) {
226 skip("failed to created filter, skipping\n");
227 return;
230 hr = IGraphBuilder_AddFilter(pgraph, pF, NULL);
231 ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr);
232 IMediaFilter_Release(pF);
235 static void test_mediacontrol(void)
237 HRESULT hr;
238 LONGLONG pos = 0xdeadbeef;
239 IMediaSeeking *seeking = NULL;
240 IMediaFilter *filter = NULL;
241 IMediaControl *control = NULL;
243 IFilterGraph2_SetDefaultSyncSource(pgraph);
244 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking);
245 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
246 if (FAILED(hr))
247 return;
249 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
250 ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
251 if (FAILED(hr))
253 IUnknown_Release(seeking);
254 return;
257 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
258 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
259 if (FAILED(hr))
261 IUnknown_Release(seeking);
262 IUnknown_Release(filter);
263 return;
266 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
267 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
268 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
270 IMediaFilter_SetSyncSource(filter, NULL);
271 pos = 0xdeadbeef;
272 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
273 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
274 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
276 hr = IMediaControl_GetState(control, 1000, NULL);
277 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
279 IUnknown_Release(control);
280 IUnknown_Release(seeking);
281 IUnknown_Release(filter);
282 releasefiltergraph();
285 static void test_filter_graph2(void)
287 HRESULT hr;
288 IFilterGraph2 *pF = NULL;
290 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
291 &IID_IFilterGraph2, (LPVOID*)&pF);
292 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
293 ok(pF != NULL, "pF is NULL\n");
295 hr = IFilterGraph2_Release(pF);
296 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
299 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
300 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
302 if (pMediaType->pbFormat)
304 CoTaskMemFree(pMediaType->pbFormat);
305 pMediaType->pbFormat = NULL;
307 if (pMediaType->pUnk)
309 IUnknown_Release(pMediaType->pUnk);
310 pMediaType->pUnk = NULL;
314 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
316 *pDest = *pSrc;
317 if (!pSrc->pbFormat) return S_OK;
318 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
319 return E_OUTOFMEMORY;
320 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
321 if (pDest->pUnk)
322 IUnknown_AddRef(pDest->pUnk);
323 return S_OK;
326 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
328 AM_MEDIA_TYPE * pDest;
330 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
331 if (!pDest)
332 return NULL;
334 if (FAILED(CopyMediaType(pDest, pSrc)))
336 CoTaskMemFree(pDest);
337 return NULL;
340 return pDest;
343 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
345 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
346 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
349 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
351 FreeMediaType(pMediaType);
352 CoTaskMemFree(pMediaType);
355 typedef struct IEnumMediaTypesImpl
357 const IEnumMediaTypesVtbl * lpVtbl;
358 LONG refCount;
359 AM_MEDIA_TYPE *pMediaTypes;
360 ULONG cMediaTypes;
361 ULONG uIndex;
362 } IEnumMediaTypesImpl;
364 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
366 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
368 ULONG i;
369 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
371 if (!pEnumMediaTypes)
373 *ppEnum = NULL;
374 return E_OUTOFMEMORY;
376 pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl;
377 pEnumMediaTypes->refCount = 1;
378 pEnumMediaTypes->uIndex = 0;
379 pEnumMediaTypes->cMediaTypes = cMediaTypes;
380 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
381 for (i = 0; i < cMediaTypes; i++)
382 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
384 while (i--)
385 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
386 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
387 return E_OUTOFMEMORY;
389 *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl);
390 return S_OK;
393 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
395 *ppv = NULL;
397 if (IsEqualIID(riid, &IID_IUnknown))
398 *ppv = (LPVOID)iface;
399 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
400 *ppv = (LPVOID)iface;
402 if (*ppv)
404 IUnknown_AddRef((IUnknown *)(*ppv));
405 return S_OK;
408 return E_NOINTERFACE;
411 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
413 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
414 ULONG refCount = InterlockedIncrement(&This->refCount);
416 return refCount;
419 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
421 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
422 ULONG refCount = InterlockedDecrement(&This->refCount);
424 if (!refCount)
426 int i;
427 for (i = 0; i < This->cMediaTypes; i++)
428 FreeMediaType(&This->pMediaTypes[i]);
429 CoTaskMemFree(This->pMediaTypes);
430 CoTaskMemFree(This);
432 return refCount;
435 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
437 ULONG cFetched;
438 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
440 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
442 if (cFetched > 0)
444 ULONG i;
445 for (i = 0; i < cFetched; i++)
446 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
448 while (i--)
449 DeleteMediaType(ppMediaTypes[i]);
450 *pcFetched = 0;
451 return E_OUTOFMEMORY;
455 if ((cMediaTypes != 1) || pcFetched)
456 *pcFetched = cFetched;
458 This->uIndex += cFetched;
460 if (cFetched != cMediaTypes)
461 return S_FALSE;
462 return S_OK;
465 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
467 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
469 if (This->uIndex + cMediaTypes < This->cMediaTypes)
471 This->uIndex += cMediaTypes;
472 return S_OK;
474 return S_FALSE;
477 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
479 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
481 This->uIndex = 0;
482 return S_OK;
485 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
487 HRESULT hr;
488 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
490 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
491 if (FAILED(hr))
492 return hr;
493 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
496 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
498 IEnumMediaTypesImpl_QueryInterface,
499 IEnumMediaTypesImpl_AddRef,
500 IEnumMediaTypesImpl_Release,
501 IEnumMediaTypesImpl_Next,
502 IEnumMediaTypesImpl_Skip,
503 IEnumMediaTypesImpl_Reset,
504 IEnumMediaTypesImpl_Clone
507 /* Implementation of a very stripped down pin for the test filter. Just enough
508 functionality for connecting and Render() to work. */
510 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
512 lstrcpyW(pDest->achName, pSrc->achName);
513 pDest->dir = pSrc->dir;
514 pDest->pFilter = pSrc->pFilter;
517 typedef struct ITestPinImpl
519 const struct IPinVtbl * lpVtbl;
520 LONG refCount;
521 LPCRITICAL_SECTION pCritSec;
522 PIN_INFO pinInfo;
523 IPin * pConnectedTo;
524 AM_MEDIA_TYPE mtCurrent;
525 LPVOID pUserData;
526 } ITestPinImpl;
528 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
530 *ppv = NULL;
532 if (IsEqualIID(riid, &IID_IUnknown))
533 *ppv = (LPVOID)iface;
534 else if (IsEqualIID(riid, &IID_IPin))
535 *ppv = (LPVOID)iface;
537 if (*ppv)
539 IUnknown_AddRef((IUnknown *)(*ppv));
540 return S_OK;
543 return E_NOINTERFACE;
546 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
548 ITestPinImpl *This = (ITestPinImpl *)iface;
549 ULONG refCount = InterlockedIncrement(&This->refCount);
550 return refCount;
553 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
555 ITestPinImpl *This = (ITestPinImpl *)iface;
556 ULONG refCount = InterlockedDecrement(&This->refCount);
558 if (!refCount)
560 FreeMediaType(&This->mtCurrent);
561 This->lpVtbl = NULL;
562 CoTaskMemFree(This);
563 return 0;
565 else
566 return refCount;
569 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
571 return E_UNEXPECTED;
574 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
576 ITestPinImpl *This = (ITestPinImpl *)iface;
577 PIN_DIRECTION pindirReceive;
578 HRESULT hr = S_OK;
580 EnterCriticalSection(This->pCritSec);
582 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
583 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
584 hr = VFW_E_TYPE_NOT_ACCEPTED;
586 if (This->pConnectedTo)
587 hr = VFW_E_ALREADY_CONNECTED;
589 if (SUCCEEDED(hr))
591 IPin_QueryDirection(pReceivePin, &pindirReceive);
593 if (pindirReceive != PINDIR_OUTPUT)
595 hr = VFW_E_INVALID_DIRECTION;
599 if (SUCCEEDED(hr))
601 CopyMediaType(&This->mtCurrent, pmt);
602 This->pConnectedTo = pReceivePin;
603 IPin_AddRef(pReceivePin);
606 LeaveCriticalSection(This->pCritSec);
608 return hr;
611 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
613 HRESULT hr;
614 ITestPinImpl *This = (ITestPinImpl *)iface;
616 EnterCriticalSection(This->pCritSec);
618 if (This->pConnectedTo)
620 IPin_Release(This->pConnectedTo);
621 This->pConnectedTo = NULL;
622 hr = S_OK;
624 else
625 hr = S_FALSE;
627 LeaveCriticalSection(This->pCritSec);
629 return hr;
632 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
634 HRESULT hr;
635 ITestPinImpl *This = (ITestPinImpl *)iface;
637 EnterCriticalSection(This->pCritSec);
639 if (This->pConnectedTo)
641 *ppPin = This->pConnectedTo;
642 IPin_AddRef(*ppPin);
643 hr = S_OK;
645 else
647 hr = VFW_E_NOT_CONNECTED;
648 *ppPin = NULL;
651 LeaveCriticalSection(This->pCritSec);
653 return hr;
656 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
658 HRESULT hr;
659 ITestPinImpl *This = (ITestPinImpl *)iface;
661 EnterCriticalSection(This->pCritSec);
663 if (This->pConnectedTo)
665 CopyMediaType(pmt, &This->mtCurrent);
666 hr = S_OK;
668 else
670 ZeroMemory(pmt, sizeof(*pmt));
671 hr = VFW_E_NOT_CONNECTED;
674 LeaveCriticalSection(This->pCritSec);
676 return hr;
679 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
681 ITestPinImpl *This = (ITestPinImpl *)iface;
683 Copy_PinInfo(pInfo, &This->pinInfo);
684 IBaseFilter_AddRef(pInfo->pFilter);
686 return S_OK;
689 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
691 ITestPinImpl *This = (ITestPinImpl *)iface;
693 *pPinDir = This->pinInfo.dir;
695 return S_OK;
698 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
700 return E_NOTIMPL;
703 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
705 ITestPinImpl *This = (ITestPinImpl *)iface;
707 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
708 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
709 return S_OK;
710 else
711 return VFW_E_TYPE_NOT_ACCEPTED;
714 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
716 ITestPinImpl *This = (ITestPinImpl *)iface;
718 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
721 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
723 return E_NOTIMPL;
726 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
728 return E_NOTIMPL;
731 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
733 return E_NOTIMPL;
736 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
738 return E_NOTIMPL;
741 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
743 return E_NOTIMPL;
746 static const IPinVtbl TestFilter_InputPin_Vtbl =
748 TestFilter_Pin_QueryInterface,
749 TestFilter_Pin_AddRef,
750 TestFilter_Pin_Release,
751 TestFilter_InputPin_Connect,
752 TestFilter_InputPin_ReceiveConnection,
753 TestFilter_Pin_Disconnect,
754 TestFilter_Pin_ConnectedTo,
755 TestFilter_Pin_ConnectionMediaType,
756 TestFilter_Pin_QueryPinInfo,
757 TestFilter_Pin_QueryDirection,
758 TestFilter_Pin_QueryId,
759 TestFilter_Pin_QueryAccept,
760 TestFilter_Pin_EnumMediaTypes,
761 TestFilter_Pin_QueryInternalConnections,
762 TestFilter_Pin_EndOfStream,
763 TestFilter_Pin_BeginFlush,
764 TestFilter_Pin_EndFlush,
765 TestFilter_Pin_NewSegment
768 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
770 return E_UNEXPECTED;
773 /* Private helper function */
774 static HRESULT WINAPI TestFilter_OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
776 ITestPinImpl *This = (ITestPinImpl *)iface;
777 HRESULT hr;
779 This->pConnectedTo = pReceivePin;
780 IPin_AddRef(pReceivePin);
782 hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
784 if (FAILED(hr))
786 IPin_Release(This->pConnectedTo);
787 This->pConnectedTo = NULL;
790 return hr;
793 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
795 ITestPinImpl *This = (ITestPinImpl *)iface;
796 HRESULT hr;
798 EnterCriticalSection(This->pCritSec);
800 /* if we have been a specific type to connect with, then we can either connect
801 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
802 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
803 hr = TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, pmt);
804 else
806 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
807 (TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, &This->mtCurrent) == S_OK))
808 hr = S_OK;
809 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
810 } /* if negotiate media type */
811 } /* if succeeded */
812 LeaveCriticalSection(This->pCritSec);
814 return hr;
817 static const IPinVtbl TestFilter_OutputPin_Vtbl =
819 TestFilter_Pin_QueryInterface,
820 TestFilter_Pin_AddRef,
821 TestFilter_Pin_Release,
822 TestFilter_OutputPin_Connect,
823 TestFilter_OutputPin_ReceiveConnection,
824 TestFilter_Pin_Disconnect,
825 TestFilter_Pin_ConnectedTo,
826 TestFilter_Pin_ConnectionMediaType,
827 TestFilter_Pin_QueryPinInfo,
828 TestFilter_Pin_QueryDirection,
829 TestFilter_Pin_QueryId,
830 TestFilter_Pin_QueryAccept,
831 TestFilter_Pin_EnumMediaTypes,
832 TestFilter_Pin_QueryInternalConnections,
833 TestFilter_Pin_EndOfStream,
834 TestFilter_Pin_BeginFlush,
835 TestFilter_Pin_EndFlush,
836 TestFilter_Pin_NewSegment
839 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
840 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
842 ITestPinImpl * pPinImpl;
844 *ppPin = NULL;
846 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
848 if (!pPinImpl)
849 return E_OUTOFMEMORY;
851 pPinImpl->refCount = 1;
852 pPinImpl->pConnectedTo = NULL;
853 pPinImpl->pCritSec = pCritSec;
854 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
855 pPinImpl->mtCurrent = *pinmt;
857 pPinImpl->lpVtbl = Pin_Vtbl;
859 *ppPin = (IPin *)pPinImpl;
860 return S_OK;
863 /* IEnumPins implementation */
865 typedef HRESULT (* FNOBTAINPIN)(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick);
867 typedef struct IEnumPinsImpl
869 const IEnumPinsVtbl * lpVtbl;
870 LONG refCount;
871 ULONG uIndex;
872 IBaseFilter *base;
873 FNOBTAINPIN receive_pin;
874 DWORD synctime;
875 } IEnumPinsImpl;
877 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
879 static HRESULT IEnumPinsImpl_Construct(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, IBaseFilter *base)
881 IEnumPinsImpl * pEnumPins;
883 if (!ppEnum)
884 return E_POINTER;
886 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
887 if (!pEnumPins)
889 *ppEnum = NULL;
890 return E_OUTOFMEMORY;
892 pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl;
893 pEnumPins->refCount = 1;
894 pEnumPins->uIndex = 0;
895 pEnumPins->receive_pin = receive_pin;
896 pEnumPins->base = base;
897 IBaseFilter_AddRef(base);
898 *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl);
900 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
902 return S_OK;
905 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
907 *ppv = NULL;
909 if (IsEqualIID(riid, &IID_IUnknown))
910 *ppv = (LPVOID)iface;
911 else if (IsEqualIID(riid, &IID_IEnumPins))
912 *ppv = (LPVOID)iface;
914 if (*ppv)
916 IUnknown_AddRef((IUnknown *)(*ppv));
917 return S_OK;
920 return E_NOINTERFACE;
923 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
925 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
926 ULONG refCount = InterlockedIncrement(&This->refCount);
928 return refCount;
931 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
933 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
934 ULONG refCount = InterlockedDecrement(&This->refCount);
936 if (!refCount)
938 IBaseFilter_Release(This->base);
939 CoTaskMemFree(This);
940 return 0;
942 else
943 return refCount;
946 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
948 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
949 DWORD synctime = This->synctime;
950 HRESULT hr = S_OK;
951 ULONG i = 0;
953 if (!ppPins)
954 return E_POINTER;
956 if (cPins > 1 && !pcFetched)
957 return E_INVALIDARG;
959 if (pcFetched)
960 *pcFetched = 0;
962 while (i < cPins && hr == S_OK)
964 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
966 if (hr == S_OK)
967 ++i;
969 if (synctime != This->synctime)
970 break;
973 if (!i && synctime != This->synctime)
974 return VFW_E_ENUM_OUT_OF_SYNC;
976 if (pcFetched)
977 *pcFetched = i;
978 This->uIndex += i;
980 if (i < cPins)
981 return S_FALSE;
982 return S_OK;
985 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
987 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
988 DWORD synctime = This->synctime;
989 HRESULT hr;
990 IPin *pin = NULL;
992 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
993 if (pin)
994 IPin_Release(pin);
996 if (synctime != This->synctime)
997 return VFW_E_ENUM_OUT_OF_SYNC;
999 if (hr == S_OK)
1000 This->uIndex += cPins;
1002 return hr;
1005 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1007 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1009 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1011 This->uIndex = 0;
1012 return S_OK;
1015 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1017 HRESULT hr;
1018 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1020 hr = IEnumPinsImpl_Construct(ppEnum, This->receive_pin, This->base);
1021 if (FAILED(hr))
1022 return hr;
1023 return IEnumPins_Skip(*ppEnum, This->uIndex);
1026 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1028 IEnumPinsImpl_QueryInterface,
1029 IEnumPinsImpl_AddRef,
1030 IEnumPinsImpl_Release,
1031 IEnumPinsImpl_Next,
1032 IEnumPinsImpl_Skip,
1033 IEnumPinsImpl_Reset,
1034 IEnumPinsImpl_Clone
1037 /* Test filter implementation - a filter that has few predefined pins with single media type
1038 * that accept only this single media type. Enough for Render(). */
1040 typedef struct TestFilterPinData
1042 PIN_DIRECTION pinDir;
1043 const GUID *mediasubtype;
1044 } TestFilterPinData;
1046 typedef struct TestFilterImpl
1048 const IBaseFilterVtbl * lpVtbl;
1050 LONG refCount;
1051 CRITICAL_SECTION csFilter;
1052 FILTER_STATE state;
1053 FILTER_INFO filterInfo;
1054 CLSID clsid;
1055 IPin ** ppPins;
1056 UINT nPins;
1057 } TestFilterImpl;
1059 static const IBaseFilterVtbl TestFilter_Vtbl;
1061 static HRESULT TestFilter_Create(const CLSID* pClsid, const TestFilterPinData *pinData, LPVOID * ppv)
1063 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1064 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1065 HRESULT hr;
1066 PIN_INFO pinInfo;
1067 TestFilterImpl* pTestFilter = NULL;
1068 UINT nPins, i;
1069 AM_MEDIA_TYPE mt;
1071 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1072 if (!pTestFilter) return E_OUTOFMEMORY;
1074 pTestFilter->clsid = *pClsid;
1075 pTestFilter->lpVtbl = &TestFilter_Vtbl;
1076 pTestFilter->refCount = 1;
1077 InitializeCriticalSection(&pTestFilter->csFilter);
1078 pTestFilter->state = State_Stopped;
1080 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1082 nPins = 0;
1083 while(pinData[nPins].mediasubtype) ++nPins;
1085 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1086 if (!pTestFilter->ppPins)
1088 hr = E_OUTOFMEMORY;
1089 goto error;
1091 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1093 for (i = 0; i < nPins; i++)
1095 ZeroMemory(&mt, sizeof(mt));
1096 mt.majortype = MEDIATYPE_Video;
1097 mt.formattype = FORMAT_None;
1098 mt.subtype = *pinData[i].mediasubtype;
1100 pinInfo.dir = pinData[i].pinDir;
1101 pinInfo.pFilter = (IBaseFilter *)pTestFilter;
1102 if (pinInfo.dir == PINDIR_INPUT)
1104 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1105 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1106 &pTestFilter->ppPins[i]);
1109 else
1111 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1112 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1113 &pTestFilter->ppPins[i]);
1115 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1118 pTestFilter->nPins = nPins;
1119 *ppv = (LPVOID)pTestFilter;
1120 return S_OK;
1122 error:
1124 for (i = 0; i < nPins; i++)
1126 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1128 CoTaskMemFree(pTestFilter->ppPins);
1129 DeleteCriticalSection(&pTestFilter->csFilter);
1130 CoTaskMemFree(pTestFilter);
1132 return hr;
1135 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1137 TestFilterImpl *This = (TestFilterImpl *)iface;
1139 *ppv = NULL;
1141 if (IsEqualIID(riid, &IID_IUnknown))
1142 *ppv = (LPVOID)This;
1143 else if (IsEqualIID(riid, &IID_IPersist))
1144 *ppv = (LPVOID)This;
1145 else if (IsEqualIID(riid, &IID_IMediaFilter))
1146 *ppv = (LPVOID)This;
1147 else if (IsEqualIID(riid, &IID_IBaseFilter))
1148 *ppv = (LPVOID)This;
1150 if (*ppv)
1152 IUnknown_AddRef((IUnknown *)(*ppv));
1153 return S_OK;
1156 return E_NOINTERFACE;
1159 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1161 TestFilterImpl *This = (TestFilterImpl *)iface;
1162 ULONG refCount = InterlockedIncrement(&This->refCount);
1164 return refCount;
1167 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1169 TestFilterImpl *This = (TestFilterImpl *)iface;
1170 ULONG refCount = InterlockedDecrement(&This->refCount);
1172 if (!refCount)
1174 ULONG i;
1176 for (i = 0; i < This->nPins; i++)
1178 IPin *pConnectedTo;
1180 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1182 IPin_Disconnect(pConnectedTo);
1183 IPin_Release(pConnectedTo);
1185 IPin_Disconnect(This->ppPins[i]);
1187 IPin_Release(This->ppPins[i]);
1190 CoTaskMemFree(This->ppPins);
1191 This->lpVtbl = NULL;
1193 DeleteCriticalSection(&This->csFilter);
1195 CoTaskMemFree(This);
1197 return 0;
1199 else
1200 return refCount;
1202 /** IPersist methods **/
1204 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1206 TestFilterImpl *This = (TestFilterImpl *)iface;
1208 *pClsid = This->clsid;
1210 return S_OK;
1213 /** IMediaFilter methods **/
1215 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1217 return E_NOTIMPL;
1220 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1222 return E_NOTIMPL;
1225 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1227 return E_NOTIMPL;
1230 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1232 TestFilterImpl *This = (TestFilterImpl *)iface;
1234 EnterCriticalSection(&This->csFilter);
1236 *pState = This->state;
1238 LeaveCriticalSection(&This->csFilter);
1240 return S_OK;
1243 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1245 return E_NOTIMPL;
1248 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1250 return E_NOTIMPL;
1253 /** IBaseFilter implementation **/
1255 static HRESULT TestFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
1257 TestFilterImpl *This = (TestFilterImpl *)iface;
1259 /* Our pins are static, not changing so setting static tick count is ok */
1260 *lastsynctick = 0;
1262 if (pos >= This->nPins)
1263 return S_FALSE;
1265 *pin = This->ppPins[pos];
1266 IPin_AddRef(*pin);
1267 return S_OK;
1270 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1272 return IEnumPinsImpl_Construct(ppEnum, TestFilter_GetPin, iface);
1275 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1277 return E_NOTIMPL;
1280 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1282 TestFilterImpl *This = (TestFilterImpl *)iface;
1284 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1285 pInfo->pGraph = This->filterInfo.pGraph;
1287 if (pInfo->pGraph)
1288 IFilterGraph_AddRef(pInfo->pGraph);
1290 return S_OK;
1293 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1295 HRESULT hr = S_OK;
1296 TestFilterImpl *This = (TestFilterImpl *)iface;
1298 EnterCriticalSection(&This->csFilter);
1300 if (pName)
1301 lstrcpyW(This->filterInfo.achName, pName);
1302 else
1303 *This->filterInfo.achName = '\0';
1304 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1306 LeaveCriticalSection(&This->csFilter);
1308 return hr;
1311 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1313 return E_NOTIMPL;
1316 static const IBaseFilterVtbl TestFilter_Vtbl =
1318 TestFilter_QueryInterface,
1319 TestFilter_AddRef,
1320 TestFilter_Release,
1321 TestFilter_GetClassID,
1322 TestFilter_Stop,
1323 TestFilter_Pause,
1324 TestFilter_Run,
1325 TestFilter_GetState,
1326 TestFilter_SetSyncSource,
1327 TestFilter_GetSyncSource,
1328 TestFilter_EnumPins,
1329 TestFilter_FindPin,
1330 TestFilter_QueryFilterInfo,
1331 TestFilter_JoinFilterGraph,
1332 TestFilter_QueryVendorInfo
1335 /* IClassFactory implementation */
1337 typedef struct TestClassFactoryImpl
1339 IClassFactoryVtbl *lpVtbl;
1340 const TestFilterPinData *filterPinData;
1341 const CLSID *clsid;
1342 } TestClassFactoryImpl;
1344 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1345 LPCLASSFACTORY iface,
1346 REFIID riid,
1347 LPVOID *ppvObj)
1349 if (ppvObj == NULL) return E_POINTER;
1351 if (IsEqualGUID(riid, &IID_IUnknown) ||
1352 IsEqualGUID(riid, &IID_IClassFactory))
1354 *ppvObj = (LPVOID)iface;
1355 IClassFactory_AddRef(iface);
1356 return S_OK;
1359 *ppvObj = NULL;
1360 return E_NOINTERFACE;
1363 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1365 return 2; /* non-heap-based object */
1368 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1370 return 1; /* non-heap-based object */
1373 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1374 LPCLASSFACTORY iface,
1375 LPUNKNOWN pUnkOuter,
1376 REFIID riid,
1377 LPVOID *ppvObj)
1379 TestClassFactoryImpl *This = (TestClassFactoryImpl *)iface;
1380 HRESULT hr;
1381 IUnknown *punk = NULL;
1383 *ppvObj = NULL;
1385 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1387 hr = TestFilter_Create(This->clsid, This->filterPinData, (LPVOID *) &punk);
1388 if (SUCCEEDED(hr)) {
1389 hr = IUnknown_QueryInterface(punk, riid, ppvObj);
1390 IUnknown_Release(punk);
1392 return hr;
1395 static HRESULT WINAPI Test_IClassFactory_LockServer(
1396 LPCLASSFACTORY iface,
1397 BOOL fLock)
1399 return S_OK;
1402 static IClassFactoryVtbl TestClassFactory_Vtbl =
1404 Test_IClassFactory_QueryInterface,
1405 Test_IClassFactory_AddRef,
1406 Test_IClassFactory_Release,
1407 Test_IClassFactory_CreateInstance,
1408 Test_IClassFactory_LockServer
1411 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1413 IPin *pin = NULL;
1414 PIN_INFO pinInfo;
1415 FILTER_INFO filterInfo;
1416 HRESULT hr;
1418 FilterName[0] = 0;
1420 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1421 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1422 if (FAILED(hr)) return hr;
1424 hr = IPin_QueryPinInfo(pin, &pinInfo);
1425 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1426 IPin_Release(pin);
1427 if (FAILED(hr)) return hr;
1429 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1430 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1431 IBaseFilter_Release(pinInfo.pFilter);
1432 if (FAILED(hr)) return hr;
1434 IFilterGraph_Release(filterInfo.pGraph);
1436 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1438 return S_OK;
1441 static void test_render_filter_priority(void)
1443 /* Tests filter choice priorities in Render(). */
1444 DWORD cookie1, cookie2, cookie3;
1445 HRESULT hr;
1446 IFilterGraph2* pgraph2 = NULL;
1447 IFilterMapper2 *pMapper2 = NULL;
1448 IBaseFilter* ptestfilter = NULL;
1449 IBaseFilter* ptestfilter2 = NULL;
1450 static const CLSID CLSID_TestFilter2 = {
1451 0x37a4edb0,
1452 0x4d13,
1453 0x11dd,
1454 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1456 static const CLSID CLSID_TestFilter3 = {
1457 0x37a4f2d8,
1458 0x4d13,
1459 0x11dd,
1460 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1462 static const CLSID CLSID_TestFilter4 = {
1463 0x37a4f3b4,
1464 0x4d13,
1465 0x11dd,
1466 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1468 static const GUID mediasubtype1 = {
1469 0x37a4f51c,
1470 0x4d13,
1471 0x11dd,
1472 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1474 static const GUID mediasubtype2 = {
1475 0x37a4f5c6,
1476 0x4d13,
1477 0x11dd,
1478 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1480 static const TestFilterPinData PinData1[] = {
1481 { PINDIR_OUTPUT, &mediasubtype1 },
1482 { 0, 0 }
1484 static const TestFilterPinData PinData2[] = {
1485 { PINDIR_INPUT, &mediasubtype1 },
1486 { 0, 0 }
1488 static const TestFilterPinData PinData3[] = {
1489 { PINDIR_INPUT, &GUID_NULL },
1490 { 0, 0 }
1492 static const TestFilterPinData PinData4[] = {
1493 { PINDIR_INPUT, &mediasubtype1 },
1494 { PINDIR_OUTPUT, &mediasubtype2 },
1495 { 0, 0 }
1497 static const TestFilterPinData PinData5[] = {
1498 { PINDIR_INPUT, &mediasubtype2 },
1499 { 0, 0 }
1501 TestClassFactoryImpl Filter1ClassFactory = { &TestClassFactory_Vtbl, PinData2, &CLSID_TestFilter2 };
1502 TestClassFactoryImpl Filter2ClassFactory = { &TestClassFactory_Vtbl, PinData4, &CLSID_TestFilter3 };
1503 TestClassFactoryImpl Filter3ClassFactory = { &TestClassFactory_Vtbl, PinData5, &CLSID_TestFilter4 };
1504 char ConnectedFilterName1[MAX_FILTER_NAME];
1505 char ConnectedFilterName2[MAX_FILTER_NAME];
1506 REGFILTER2 rgf2;
1507 REGFILTERPINS2 rgPins2[2];
1508 REGPINTYPES rgPinType[2];
1509 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1510 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1511 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1512 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1513 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1514 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1515 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1516 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1518 /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is
1519 "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating
1520 no preference given to exact match. */
1521 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1522 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1523 if (!pgraph2) goto out;
1525 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1526 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1527 if (FAILED(hr)) goto out;
1529 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1530 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1532 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1533 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1534 if (FAILED(hr)) goto out;
1536 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1537 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1539 IBaseFilter_Release(ptestfilter2);
1540 ptestfilter2 = NULL;
1542 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1543 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1544 if (FAILED(hr)) goto out;
1546 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1547 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1549 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1550 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1552 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1554 IFilterGraph2_Release(pgraph2);
1555 pgraph2 = NULL;
1556 IBaseFilter_Release(ptestfilter);
1557 ptestfilter = NULL;
1558 IBaseFilter_Release(ptestfilter2);
1559 ptestfilter2 = NULL;
1561 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1562 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1563 if (!pgraph2) goto out;
1565 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1566 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1567 if (FAILED(hr)) goto out;
1569 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1570 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1572 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1573 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1574 if (FAILED(hr)) goto out;
1576 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1577 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1579 IBaseFilter_Release(ptestfilter2);
1580 ptestfilter2 = NULL;
1582 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1583 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1584 if (FAILED(hr)) goto out;
1586 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1587 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1589 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1590 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1592 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1593 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1594 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1596 IFilterGraph2_Release(pgraph2);
1597 pgraph2 = NULL;
1598 IBaseFilter_Release(ptestfilter);
1599 ptestfilter = NULL;
1600 IBaseFilter_Release(ptestfilter2);
1601 ptestfilter2 = NULL;
1603 /* Test if any preference is given to existing renderer which renders the pin directly vs
1604 an existing renderer which renders the pin indirectly, through an additional middle filter,
1605 again trying different orders of creation. Native appears not to give a preference. */
1607 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1608 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1609 if (!pgraph2) goto out;
1611 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1612 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1613 if (FAILED(hr)) goto out;
1615 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1616 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1618 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1619 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1620 if (FAILED(hr)) goto out;
1622 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1623 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1625 IBaseFilter_Release(ptestfilter2);
1626 ptestfilter2 = NULL;
1628 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1629 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1630 if (FAILED(hr)) goto out;
1632 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1633 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1635 IBaseFilter_Release(ptestfilter2);
1636 ptestfilter2 = NULL;
1638 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1639 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1640 if (FAILED(hr)) goto out;
1642 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1643 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1645 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1646 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1648 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1649 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1, "TestfilterInstance2"),
1650 "unexpected connected filter: %s\n", ConnectedFilterName1);
1652 IFilterGraph2_Release(pgraph2);
1653 pgraph2 = NULL;
1654 IBaseFilter_Release(ptestfilter);
1655 ptestfilter = NULL;
1656 IBaseFilter_Release(ptestfilter2);
1657 ptestfilter2 = NULL;
1659 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1660 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1661 if (!pgraph2) goto out;
1663 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1664 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1665 if (FAILED(hr)) goto out;
1667 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1668 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1670 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1671 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1672 if (FAILED(hr)) goto out;
1674 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1675 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1677 IBaseFilter_Release(ptestfilter2);
1678 ptestfilter2 = NULL;
1680 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1681 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1682 if (FAILED(hr)) goto out;
1684 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1685 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1687 IBaseFilter_Release(ptestfilter2);
1688 ptestfilter2 = NULL;
1690 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1691 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1692 if (FAILED(hr)) goto out;
1694 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1695 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1697 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1698 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1700 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1701 ok(!lstrcmp(ConnectedFilterName2, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2, "TestfilterInstance2"),
1702 "unexpected connected filter: %s\n", ConnectedFilterName2);
1703 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1704 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1706 IFilterGraph2_Release(pgraph2);
1707 pgraph2 = NULL;
1708 IBaseFilter_Release(ptestfilter);
1709 ptestfilter = NULL;
1710 IBaseFilter_Release(ptestfilter2);
1711 ptestfilter2 = NULL;
1713 /* Test if renderers are tried before non-renderers (intermediary filters). */
1714 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1715 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1716 if (!pgraph2) goto out;
1718 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
1719 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1720 if (!pMapper2) goto out;
1722 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1723 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1724 if (FAILED(hr)) goto out;
1726 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1727 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1729 /* Register our filters with COM and with Filtermapper. */
1730 hr = CoRegisterClassObject(Filter1ClassFactory.clsid, (IUnknown *)&Filter1ClassFactory,
1731 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie1);
1732 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1733 hr = CoRegisterClassObject(Filter2ClassFactory.clsid, (IUnknown *)&Filter2ClassFactory,
1734 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie2);
1735 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1736 hr = CoRegisterClassObject(Filter3ClassFactory.clsid, (IUnknown *)&Filter3ClassFactory,
1737 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie3);
1738 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1740 rgf2.dwVersion = 2;
1741 rgf2.dwMerit = MERIT_UNLIKELY;
1742 S1(U(rgf2)).cPins2 = 1;
1743 S1(U(rgf2)).rgPins2 = rgPins2;
1744 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
1745 rgPins2[0].cInstances = 1;
1746 rgPins2[0].nMediaTypes = 1;
1747 rgPins2[0].lpMediaType = &rgPinType[0];
1748 rgPins2[0].nMediums = 0;
1749 rgPins2[0].lpMedium = NULL;
1750 rgPins2[0].clsPinCategory = NULL;
1751 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
1752 rgPinType[0].clsMinorType = &mediasubtype1;
1754 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
1755 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1756 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1758 rgf2.dwMerit = MERIT_PREFERRED;
1759 rgPinType[0].clsMinorType = &mediasubtype2;
1761 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
1762 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1763 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1765 S1(U(rgf2)).cPins2 = 2;
1766 rgPins2[0].dwFlags = 0;
1767 rgPinType[0].clsMinorType = &mediasubtype1;
1769 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
1770 rgPins2[1].cInstances = 1;
1771 rgPins2[1].nMediaTypes = 1;
1772 rgPins2[1].lpMediaType = &rgPinType[1];
1773 rgPins2[1].nMediums = 0;
1774 rgPins2[1].lpMedium = NULL;
1775 rgPins2[1].clsPinCategory = NULL;
1776 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
1777 rgPinType[1].clsMinorType = &mediasubtype2;
1779 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
1780 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1781 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1783 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1784 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1786 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1787 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3"),
1788 "unexpected connected filter: %s\n", ConnectedFilterName1);
1790 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1791 &CLSID_TestFilter2);
1792 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1793 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1794 &CLSID_TestFilter3);
1795 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1796 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1797 &CLSID_TestFilter4);
1798 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1800 out:
1802 if (ptestfilter) IBaseFilter_Release(ptestfilter);
1803 if (ptestfilter2) IBaseFilter_Release(ptestfilter2);
1804 if (pgraph2) IFilterGraph2_Release(pgraph2);
1805 if (pMapper2) IFilterMapper2_Release(pMapper2);
1807 hr = CoRevokeClassObject(cookie1);
1808 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1809 hr = CoRevokeClassObject(cookie2);
1810 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1811 hr = CoRevokeClassObject(cookie3);
1812 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1815 START_TEST(filtergraph)
1817 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1818 test_render_run();
1819 test_graph_builder();
1820 test_graph_builder_addfilter();
1821 test_mediacontrol();
1822 test_filter_graph2();
1823 test_render_filter_priority();
1824 CoUninitialize();