quartz/tests: Fix some test failures on Win95.
[wine/multimedia.git] / dlls / quartz / tests / filtergraph.c
blob6f9e4c8a96fd58af2b0f3143a76df3bd07f57a07
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 #define FILE_LEN 9
31 static const char avifileA[FILE_LEN] = "test.avi";
32 static const char mpegfileA[FILE_LEN] = "test.mpg";
34 IGraphBuilder* pgraph;
36 static int createfiltergraph(void)
38 return S_OK == CoCreateInstance(
39 &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&pgraph);
42 static void renderfile(const char * fileA)
44 HRESULT hr;
45 WCHAR fileW[FILE_LEN];
47 MultiByteToWideChar(CP_ACP, 0, fileA, -1, fileW, FILE_LEN);
49 hr = IGraphBuilder_RenderFile(pgraph, fileW, NULL);
50 ok(hr==S_OK, "RenderFile returned: %x\n", hr);
53 static void rungraph(void)
55 HRESULT hr;
56 IMediaControl* pmc;
57 IMediaEvent* pme;
58 IMediaFilter* pmf;
59 HANDLE hEvent;
61 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (LPVOID*)&pmc);
62 ok(hr==S_OK, "Cannot get IMediaControl interface returned: %x\n", hr);
64 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (LPVOID*)&pmf);
65 ok(hr==S_OK, "Cannot get IMediaFilter interface returned: %x\n", hr);
67 IMediaControl_Stop(pmc);
69 IMediaFilter_SetSyncSource(pmf, NULL);
71 IMediaFilter_Release(pmf);
73 hr = IMediaControl_Run(pmc);
74 ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr);
76 Sleep(10);
77 /* Crash fun */
78 trace("run -> stop\n");
79 hr = IMediaControl_Stop(pmc);
80 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
82 IGraphBuilder_SetDefaultSyncSource(pgraph);
84 Sleep(10);
85 trace("stop -> pause\n");
86 hr = IMediaControl_Pause(pmc);
87 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
89 Sleep(10);
90 trace("pause -> run\n");
91 hr = IMediaControl_Run(pmc);
92 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
94 Sleep(10);
95 trace("run -> pause\n");
96 hr = IMediaControl_Pause(pmc);
97 ok(hr==S_OK || hr == S_FALSE, "Cannot pause the graph returned: %x\n", hr);
99 Sleep(10);
100 trace("pause -> stop\n");
101 hr = IMediaControl_Stop(pmc);
102 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
104 Sleep(10);
105 trace("pause -> run\n");
106 hr = IMediaControl_Run(pmc);
107 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
109 trace("run -> stop\n");
110 hr = IMediaControl_Stop(pmc);
111 ok(hr==S_OK || hr == S_FALSE, "Cannot stop the graph returned: %x\n", hr);
113 trace("stop -> run\n");
114 hr = IMediaControl_Run(pmc);
115 ok(hr==S_OK || hr == S_FALSE, "Cannot start the graph returned: %x\n", hr);
117 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaEvent, (LPVOID*)&pme);
118 ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr);
120 hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent);
121 ok(hr==S_OK, "Cannot get event handle returned: %x\n", hr);
123 /* WaitForSingleObject(hEvent, INFINITE); */
124 Sleep(20000);
126 hr = IMediaEvent_Release(pme);
127 ok(hr==2, "Releasing mediaevent returned: %x\n", hr);
129 hr = IMediaControl_Stop(pmc);
130 ok(hr==S_OK, "Cannot stop the graph returned: %x\n", hr);
132 hr = IMediaControl_Release(pmc);
133 ok(hr==1, "Releasing mediacontrol returned: %x\n", hr);
136 static void releasefiltergraph(void)
138 HRESULT hr;
140 hr = IGraphBuilder_Release(pgraph);
141 ok(hr==0, "Releasing filtergraph returned: %x\n", hr);
144 static void test_render_run(const char * fileA)
146 HANDLE h;
148 if (!createfiltergraph())
149 return;
151 h = CreateFileA(fileA, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
152 if (h != INVALID_HANDLE_VALUE) {
153 CloseHandle(h);
154 renderfile(fileA);
155 rungraph();
158 releasefiltergraph();
161 static void test_graph_builder(void)
163 HRESULT hr;
164 IBaseFilter *pF = NULL;
165 IBaseFilter *pF2 = NULL;
166 IPin *pIn = NULL;
167 IEnumPins *pEnum = NULL;
168 PIN_DIRECTION dir;
169 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
170 static const WCHAR fooBarW[] = {'f','o','o','B','a','r',0};
172 if (!createfiltergraph())
173 return;
175 /* create video filter */
176 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
177 &IID_IBaseFilter, (LPVOID*)&pF);
178 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
179 ok(pF != NULL, "pF is NULL\n");
181 /* add the two filters to the graph */
182 hr = IGraphBuilder_AddFilter(pgraph, pF, testFilterW);
183 ok(hr == S_OK, "failed to add pF to the graph: %x\n", hr);
185 /* find the pins */
186 hr = IBaseFilter_EnumPins(pF, &pEnum);
187 ok(hr == S_OK, "IBaseFilter_EnumPins failed for pF: %x\n", hr);
188 ok(pEnum != NULL, "pEnum is NULL\n");
189 hr = IEnumPins_Next(pEnum, 1, &pIn, NULL);
190 ok(hr == S_OK, "IEnumPins_Next failed for pF: %x\n", hr);
191 ok(pIn != NULL, "pIn is NULL\n");
192 hr = IPin_QueryDirection(pIn, &dir);
193 ok(hr == S_OK, "IPin_QueryDirection failed: %x\n", hr);
194 ok(dir == PINDIR_INPUT, "pin has wrong direction\n");
196 hr = IGraphBuilder_FindFilterByName(pgraph, fooBarW, &pF2);
197 ok(hr == VFW_E_NOT_FOUND, "IGraphBuilder_FindFilterByName returned %x\n", hr);
198 ok(pF2 == NULL, "IGraphBuilder_FindFilterByName returned %p\n", pF2);
199 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, &pF2);
200 ok(hr == S_OK, "IGraphBuilder_FindFilterByName returned %x\n", hr);
201 ok(pF2 != NULL, "IGraphBuilder_FindFilterByName returned NULL\n");
202 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, NULL);
203 ok(hr == E_POINTER, "IGraphBuilder_FindFilterByName returned %x\n", hr);
205 if (pIn) IPin_Release(pIn);
206 if (pEnum) IEnumPins_Release(pEnum);
207 if (pF) IBaseFilter_Release(pF);
208 if (pF2) IBaseFilter_Release(pF2);
210 releasefiltergraph();
213 static void test_graph_builder_addfilter(void)
215 HRESULT hr;
216 IBaseFilter *pF = NULL;
217 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
219 if (!createfiltergraph())
220 return;
222 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
223 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr);
225 /* create video filter */
226 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
227 &IID_IBaseFilter, (LPVOID*)&pF);
228 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
229 ok(pF != NULL, "pF is NULL\n");
230 if (!pF) {
231 skip("failed to created filter, skipping\n");
232 return;
235 hr = IGraphBuilder_AddFilter(pgraph, pF, NULL);
236 ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr);
237 IMediaFilter_Release(pF);
240 static void test_mediacontrol(void)
242 HRESULT hr;
243 LONGLONG pos = 0xdeadbeef;
244 IMediaSeeking *seeking = NULL;
245 IMediaFilter *filter = NULL;
246 IMediaControl *control = NULL;
248 IFilterGraph2_SetDefaultSyncSource(pgraph);
249 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking);
250 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
251 if (FAILED(hr))
252 return;
254 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
255 ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
256 if (FAILED(hr))
258 IUnknown_Release(seeking);
259 return;
262 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
263 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
264 if (FAILED(hr))
266 IUnknown_Release(seeking);
267 IUnknown_Release(filter);
268 return;
271 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
272 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
273 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
275 IMediaFilter_SetSyncSource(filter, NULL);
276 pos = 0xdeadbeef;
277 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
278 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
279 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
281 hr = IMediaControl_GetState(control, 1000, NULL);
282 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
284 IUnknown_Release(control);
285 IUnknown_Release(seeking);
286 IUnknown_Release(filter);
287 releasefiltergraph();
290 static void test_filter_graph2(void)
292 HRESULT hr;
293 IFilterGraph2 *pF = NULL;
295 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
296 &IID_IFilterGraph2, (LPVOID*)&pF);
297 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
298 ok(pF != NULL, "pF is NULL\n");
300 hr = IFilterGraph2_Release(pF);
301 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
304 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
305 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
307 if (pMediaType->pbFormat)
309 CoTaskMemFree(pMediaType->pbFormat);
310 pMediaType->pbFormat = NULL;
312 if (pMediaType->pUnk)
314 IUnknown_Release(pMediaType->pUnk);
315 pMediaType->pUnk = NULL;
319 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
321 *pDest = *pSrc;
322 if (!pSrc->pbFormat) return S_OK;
323 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
324 return E_OUTOFMEMORY;
325 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
326 if (pDest->pUnk)
327 IUnknown_AddRef(pDest->pUnk);
328 return S_OK;
331 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
333 AM_MEDIA_TYPE * pDest;
335 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
336 if (!pDest)
337 return NULL;
339 if (FAILED(CopyMediaType(pDest, pSrc)))
341 CoTaskMemFree(pDest);
342 return NULL;
345 return pDest;
348 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
350 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
351 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
354 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
356 FreeMediaType(pMediaType);
357 CoTaskMemFree(pMediaType);
360 typedef struct IEnumMediaTypesImpl
362 const IEnumMediaTypesVtbl * lpVtbl;
363 LONG refCount;
364 AM_MEDIA_TYPE *pMediaTypes;
365 ULONG cMediaTypes;
366 ULONG uIndex;
367 } IEnumMediaTypesImpl;
369 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
371 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
373 ULONG i;
374 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
376 if (!pEnumMediaTypes)
378 *ppEnum = NULL;
379 return E_OUTOFMEMORY;
381 pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl;
382 pEnumMediaTypes->refCount = 1;
383 pEnumMediaTypes->uIndex = 0;
384 pEnumMediaTypes->cMediaTypes = cMediaTypes;
385 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
386 for (i = 0; i < cMediaTypes; i++)
387 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
389 while (i--)
390 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
391 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
392 return E_OUTOFMEMORY;
394 *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl);
395 return S_OK;
398 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
400 *ppv = NULL;
402 if (IsEqualIID(riid, &IID_IUnknown))
403 *ppv = iface;
404 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
405 *ppv = iface;
407 if (*ppv)
409 IUnknown_AddRef((IUnknown *)(*ppv));
410 return S_OK;
413 return E_NOINTERFACE;
416 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
418 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
419 ULONG refCount = InterlockedIncrement(&This->refCount);
421 return refCount;
424 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
426 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
427 ULONG refCount = InterlockedDecrement(&This->refCount);
429 if (!refCount)
431 int i;
432 for (i = 0; i < This->cMediaTypes; i++)
433 FreeMediaType(&This->pMediaTypes[i]);
434 CoTaskMemFree(This->pMediaTypes);
435 CoTaskMemFree(This);
437 return refCount;
440 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
442 ULONG cFetched;
443 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
445 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
447 if (cFetched > 0)
449 ULONG i;
450 for (i = 0; i < cFetched; i++)
451 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
453 while (i--)
454 DeleteMediaType(ppMediaTypes[i]);
455 *pcFetched = 0;
456 return E_OUTOFMEMORY;
460 if ((cMediaTypes != 1) || pcFetched)
461 *pcFetched = cFetched;
463 This->uIndex += cFetched;
465 if (cFetched != cMediaTypes)
466 return S_FALSE;
467 return S_OK;
470 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
472 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
474 if (This->uIndex + cMediaTypes < This->cMediaTypes)
476 This->uIndex += cMediaTypes;
477 return S_OK;
479 return S_FALSE;
482 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
484 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
486 This->uIndex = 0;
487 return S_OK;
490 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
492 HRESULT hr;
493 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
495 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
496 if (FAILED(hr))
497 return hr;
498 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
501 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
503 IEnumMediaTypesImpl_QueryInterface,
504 IEnumMediaTypesImpl_AddRef,
505 IEnumMediaTypesImpl_Release,
506 IEnumMediaTypesImpl_Next,
507 IEnumMediaTypesImpl_Skip,
508 IEnumMediaTypesImpl_Reset,
509 IEnumMediaTypesImpl_Clone
512 /* Implementation of a very stripped down pin for the test filter. Just enough
513 functionality for connecting and Render() to work. */
515 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
517 lstrcpyW(pDest->achName, pSrc->achName);
518 pDest->dir = pSrc->dir;
519 pDest->pFilter = pSrc->pFilter;
522 typedef struct ITestPinImpl
524 const struct IPinVtbl * lpVtbl;
525 LONG refCount;
526 LPCRITICAL_SECTION pCritSec;
527 PIN_INFO pinInfo;
528 IPin * pConnectedTo;
529 AM_MEDIA_TYPE mtCurrent;
530 LPVOID pUserData;
531 } ITestPinImpl;
533 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
535 *ppv = NULL;
537 if (IsEqualIID(riid, &IID_IUnknown))
538 *ppv = iface;
539 else if (IsEqualIID(riid, &IID_IPin))
540 *ppv = iface;
542 if (*ppv)
544 IUnknown_AddRef((IUnknown *)(*ppv));
545 return S_OK;
548 return E_NOINTERFACE;
551 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
553 ITestPinImpl *This = (ITestPinImpl *)iface;
554 ULONG refCount = InterlockedIncrement(&This->refCount);
555 return refCount;
558 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
560 ITestPinImpl *This = (ITestPinImpl *)iface;
561 ULONG refCount = InterlockedDecrement(&This->refCount);
563 if (!refCount)
565 FreeMediaType(&This->mtCurrent);
566 This->lpVtbl = NULL;
567 CoTaskMemFree(This);
568 return 0;
570 else
571 return refCount;
574 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
576 return E_UNEXPECTED;
579 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
581 ITestPinImpl *This = (ITestPinImpl *)iface;
582 PIN_DIRECTION pindirReceive;
583 HRESULT hr = S_OK;
585 EnterCriticalSection(This->pCritSec);
587 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
588 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
589 hr = VFW_E_TYPE_NOT_ACCEPTED;
591 if (This->pConnectedTo)
592 hr = VFW_E_ALREADY_CONNECTED;
594 if (SUCCEEDED(hr))
596 IPin_QueryDirection(pReceivePin, &pindirReceive);
598 if (pindirReceive != PINDIR_OUTPUT)
600 hr = VFW_E_INVALID_DIRECTION;
604 if (SUCCEEDED(hr))
606 CopyMediaType(&This->mtCurrent, pmt);
607 This->pConnectedTo = pReceivePin;
608 IPin_AddRef(pReceivePin);
611 LeaveCriticalSection(This->pCritSec);
613 return hr;
616 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
618 HRESULT hr;
619 ITestPinImpl *This = (ITestPinImpl *)iface;
621 EnterCriticalSection(This->pCritSec);
623 if (This->pConnectedTo)
625 IPin_Release(This->pConnectedTo);
626 This->pConnectedTo = NULL;
627 hr = S_OK;
629 else
630 hr = S_FALSE;
632 LeaveCriticalSection(This->pCritSec);
634 return hr;
637 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
639 HRESULT hr;
640 ITestPinImpl *This = (ITestPinImpl *)iface;
642 EnterCriticalSection(This->pCritSec);
644 if (This->pConnectedTo)
646 *ppPin = This->pConnectedTo;
647 IPin_AddRef(*ppPin);
648 hr = S_OK;
650 else
652 hr = VFW_E_NOT_CONNECTED;
653 *ppPin = NULL;
656 LeaveCriticalSection(This->pCritSec);
658 return hr;
661 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
663 HRESULT hr;
664 ITestPinImpl *This = (ITestPinImpl *)iface;
666 EnterCriticalSection(This->pCritSec);
668 if (This->pConnectedTo)
670 CopyMediaType(pmt, &This->mtCurrent);
671 hr = S_OK;
673 else
675 ZeroMemory(pmt, sizeof(*pmt));
676 hr = VFW_E_NOT_CONNECTED;
679 LeaveCriticalSection(This->pCritSec);
681 return hr;
684 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
686 ITestPinImpl *This = (ITestPinImpl *)iface;
688 Copy_PinInfo(pInfo, &This->pinInfo);
689 IBaseFilter_AddRef(pInfo->pFilter);
691 return S_OK;
694 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
696 ITestPinImpl *This = (ITestPinImpl *)iface;
698 *pPinDir = This->pinInfo.dir;
700 return S_OK;
703 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
705 return E_NOTIMPL;
708 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
710 ITestPinImpl *This = (ITestPinImpl *)iface;
712 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
713 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
714 return S_OK;
715 else
716 return VFW_E_TYPE_NOT_ACCEPTED;
719 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
721 ITestPinImpl *This = (ITestPinImpl *)iface;
723 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
726 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
728 return E_NOTIMPL;
731 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
733 return E_NOTIMPL;
736 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
738 return E_NOTIMPL;
741 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
743 return E_NOTIMPL;
746 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
748 return E_NOTIMPL;
751 static const IPinVtbl TestFilter_InputPin_Vtbl =
753 TestFilter_Pin_QueryInterface,
754 TestFilter_Pin_AddRef,
755 TestFilter_Pin_Release,
756 TestFilter_InputPin_Connect,
757 TestFilter_InputPin_ReceiveConnection,
758 TestFilter_Pin_Disconnect,
759 TestFilter_Pin_ConnectedTo,
760 TestFilter_Pin_ConnectionMediaType,
761 TestFilter_Pin_QueryPinInfo,
762 TestFilter_Pin_QueryDirection,
763 TestFilter_Pin_QueryId,
764 TestFilter_Pin_QueryAccept,
765 TestFilter_Pin_EnumMediaTypes,
766 TestFilter_Pin_QueryInternalConnections,
767 TestFilter_Pin_EndOfStream,
768 TestFilter_Pin_BeginFlush,
769 TestFilter_Pin_EndFlush,
770 TestFilter_Pin_NewSegment
773 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
775 return E_UNEXPECTED;
778 /* Private helper function */
779 static HRESULT TestFilter_OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
781 ITestPinImpl *This = (ITestPinImpl *)iface;
782 HRESULT hr;
784 This->pConnectedTo = pReceivePin;
785 IPin_AddRef(pReceivePin);
787 hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
789 if (FAILED(hr))
791 IPin_Release(This->pConnectedTo);
792 This->pConnectedTo = NULL;
795 return hr;
798 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
800 ITestPinImpl *This = (ITestPinImpl *)iface;
801 HRESULT hr;
803 EnterCriticalSection(This->pCritSec);
805 /* if we have been a specific type to connect with, then we can either connect
806 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
807 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
808 hr = TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, pmt);
809 else
811 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
812 (TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, &This->mtCurrent) == S_OK))
813 hr = S_OK;
814 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
815 } /* if negotiate media type */
816 } /* if succeeded */
817 LeaveCriticalSection(This->pCritSec);
819 return hr;
822 static const IPinVtbl TestFilter_OutputPin_Vtbl =
824 TestFilter_Pin_QueryInterface,
825 TestFilter_Pin_AddRef,
826 TestFilter_Pin_Release,
827 TestFilter_OutputPin_Connect,
828 TestFilter_OutputPin_ReceiveConnection,
829 TestFilter_Pin_Disconnect,
830 TestFilter_Pin_ConnectedTo,
831 TestFilter_Pin_ConnectionMediaType,
832 TestFilter_Pin_QueryPinInfo,
833 TestFilter_Pin_QueryDirection,
834 TestFilter_Pin_QueryId,
835 TestFilter_Pin_QueryAccept,
836 TestFilter_Pin_EnumMediaTypes,
837 TestFilter_Pin_QueryInternalConnections,
838 TestFilter_Pin_EndOfStream,
839 TestFilter_Pin_BeginFlush,
840 TestFilter_Pin_EndFlush,
841 TestFilter_Pin_NewSegment
844 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
845 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
847 ITestPinImpl * pPinImpl;
849 *ppPin = NULL;
851 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
853 if (!pPinImpl)
854 return E_OUTOFMEMORY;
856 pPinImpl->refCount = 1;
857 pPinImpl->pConnectedTo = NULL;
858 pPinImpl->pCritSec = pCritSec;
859 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
860 pPinImpl->mtCurrent = *pinmt;
862 pPinImpl->lpVtbl = Pin_Vtbl;
864 *ppPin = (IPin *)pPinImpl;
865 return S_OK;
868 /* IEnumPins implementation */
870 typedef HRESULT (* FNOBTAINPIN)(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick);
872 typedef struct IEnumPinsImpl
874 const IEnumPinsVtbl * lpVtbl;
875 LONG refCount;
876 ULONG uIndex;
877 IBaseFilter *base;
878 FNOBTAINPIN receive_pin;
879 DWORD synctime;
880 } IEnumPinsImpl;
882 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
884 static HRESULT IEnumPinsImpl_Construct(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, IBaseFilter *base)
886 IEnumPinsImpl * pEnumPins;
888 if (!ppEnum)
889 return E_POINTER;
891 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
892 if (!pEnumPins)
894 *ppEnum = NULL;
895 return E_OUTOFMEMORY;
897 pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl;
898 pEnumPins->refCount = 1;
899 pEnumPins->uIndex = 0;
900 pEnumPins->receive_pin = receive_pin;
901 pEnumPins->base = base;
902 IBaseFilter_AddRef(base);
903 *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl);
905 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
907 return S_OK;
910 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
912 *ppv = NULL;
914 if (IsEqualIID(riid, &IID_IUnknown))
915 *ppv = iface;
916 else if (IsEqualIID(riid, &IID_IEnumPins))
917 *ppv = iface;
919 if (*ppv)
921 IUnknown_AddRef((IUnknown *)(*ppv));
922 return S_OK;
925 return E_NOINTERFACE;
928 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
930 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
931 ULONG refCount = InterlockedIncrement(&This->refCount);
933 return refCount;
936 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
938 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
939 ULONG refCount = InterlockedDecrement(&This->refCount);
941 if (!refCount)
943 IBaseFilter_Release(This->base);
944 CoTaskMemFree(This);
945 return 0;
947 else
948 return refCount;
951 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
953 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
954 DWORD synctime = This->synctime;
955 HRESULT hr = S_OK;
956 ULONG i = 0;
958 if (!ppPins)
959 return E_POINTER;
961 if (cPins > 1 && !pcFetched)
962 return E_INVALIDARG;
964 if (pcFetched)
965 *pcFetched = 0;
967 while (i < cPins && hr == S_OK)
969 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
971 if (hr == S_OK)
972 ++i;
974 if (synctime != This->synctime)
975 break;
978 if (!i && synctime != This->synctime)
979 return VFW_E_ENUM_OUT_OF_SYNC;
981 if (pcFetched)
982 *pcFetched = i;
983 This->uIndex += i;
985 if (i < cPins)
986 return S_FALSE;
987 return S_OK;
990 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
992 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
993 DWORD synctime = This->synctime;
994 HRESULT hr;
995 IPin *pin = NULL;
997 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
998 if (pin)
999 IPin_Release(pin);
1001 if (synctime != This->synctime)
1002 return VFW_E_ENUM_OUT_OF_SYNC;
1004 if (hr == S_OK)
1005 This->uIndex += cPins;
1007 return hr;
1010 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1012 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1014 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1016 This->uIndex = 0;
1017 return S_OK;
1020 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1022 HRESULT hr;
1023 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1025 hr = IEnumPinsImpl_Construct(ppEnum, This->receive_pin, This->base);
1026 if (FAILED(hr))
1027 return hr;
1028 return IEnumPins_Skip(*ppEnum, This->uIndex);
1031 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1033 IEnumPinsImpl_QueryInterface,
1034 IEnumPinsImpl_AddRef,
1035 IEnumPinsImpl_Release,
1036 IEnumPinsImpl_Next,
1037 IEnumPinsImpl_Skip,
1038 IEnumPinsImpl_Reset,
1039 IEnumPinsImpl_Clone
1042 /* Test filter implementation - a filter that has few predefined pins with single media type
1043 * that accept only this single media type. Enough for Render(). */
1045 typedef struct TestFilterPinData
1047 PIN_DIRECTION pinDir;
1048 const GUID *mediasubtype;
1049 } TestFilterPinData;
1051 typedef struct TestFilterImpl
1053 const IBaseFilterVtbl * lpVtbl;
1055 LONG refCount;
1056 CRITICAL_SECTION csFilter;
1057 FILTER_STATE state;
1058 FILTER_INFO filterInfo;
1059 CLSID clsid;
1060 IPin ** ppPins;
1061 UINT nPins;
1062 } TestFilterImpl;
1064 static const IBaseFilterVtbl TestFilter_Vtbl;
1066 static HRESULT TestFilter_Create(const CLSID* pClsid, const TestFilterPinData *pinData, LPVOID * ppv)
1068 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1069 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1070 HRESULT hr;
1071 PIN_INFO pinInfo;
1072 TestFilterImpl* pTestFilter = NULL;
1073 UINT nPins, i;
1074 AM_MEDIA_TYPE mt;
1076 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1077 if (!pTestFilter) return E_OUTOFMEMORY;
1079 pTestFilter->clsid = *pClsid;
1080 pTestFilter->lpVtbl = &TestFilter_Vtbl;
1081 pTestFilter->refCount = 1;
1082 InitializeCriticalSection(&pTestFilter->csFilter);
1083 pTestFilter->state = State_Stopped;
1085 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1087 nPins = 0;
1088 while(pinData[nPins].mediasubtype) ++nPins;
1090 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1091 if (!pTestFilter->ppPins)
1093 hr = E_OUTOFMEMORY;
1094 goto error;
1096 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1098 for (i = 0; i < nPins; i++)
1100 ZeroMemory(&mt, sizeof(mt));
1101 mt.majortype = MEDIATYPE_Video;
1102 mt.formattype = FORMAT_None;
1103 mt.subtype = *pinData[i].mediasubtype;
1105 pinInfo.dir = pinData[i].pinDir;
1106 pinInfo.pFilter = (IBaseFilter *)pTestFilter;
1107 if (pinInfo.dir == PINDIR_INPUT)
1109 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1110 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1111 &pTestFilter->ppPins[i]);
1114 else
1116 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1117 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1118 &pTestFilter->ppPins[i]);
1120 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1123 pTestFilter->nPins = nPins;
1124 *ppv = pTestFilter;
1125 return S_OK;
1127 error:
1129 if (pTestFilter->ppPins)
1131 for (i = 0; i < nPins; i++)
1133 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1136 CoTaskMemFree(pTestFilter->ppPins);
1137 DeleteCriticalSection(&pTestFilter->csFilter);
1138 CoTaskMemFree(pTestFilter);
1140 return hr;
1143 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1145 TestFilterImpl *This = (TestFilterImpl *)iface;
1147 *ppv = NULL;
1149 if (IsEqualIID(riid, &IID_IUnknown))
1150 *ppv = This;
1151 else if (IsEqualIID(riid, &IID_IPersist))
1152 *ppv = This;
1153 else if (IsEqualIID(riid, &IID_IMediaFilter))
1154 *ppv = This;
1155 else if (IsEqualIID(riid, &IID_IBaseFilter))
1156 *ppv = This;
1158 if (*ppv)
1160 IUnknown_AddRef((IUnknown *)(*ppv));
1161 return S_OK;
1164 return E_NOINTERFACE;
1167 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1169 TestFilterImpl *This = (TestFilterImpl *)iface;
1170 ULONG refCount = InterlockedIncrement(&This->refCount);
1172 return refCount;
1175 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1177 TestFilterImpl *This = (TestFilterImpl *)iface;
1178 ULONG refCount = InterlockedDecrement(&This->refCount);
1180 if (!refCount)
1182 ULONG i;
1184 for (i = 0; i < This->nPins; i++)
1186 IPin *pConnectedTo;
1188 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1190 IPin_Disconnect(pConnectedTo);
1191 IPin_Release(pConnectedTo);
1193 IPin_Disconnect(This->ppPins[i]);
1195 IPin_Release(This->ppPins[i]);
1198 CoTaskMemFree(This->ppPins);
1199 This->lpVtbl = NULL;
1201 DeleteCriticalSection(&This->csFilter);
1203 CoTaskMemFree(This);
1205 return 0;
1207 else
1208 return refCount;
1210 /** IPersist methods **/
1212 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1214 TestFilterImpl *This = (TestFilterImpl *)iface;
1216 *pClsid = This->clsid;
1218 return S_OK;
1221 /** IMediaFilter methods **/
1223 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1225 return E_NOTIMPL;
1228 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1230 return E_NOTIMPL;
1233 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1235 return E_NOTIMPL;
1238 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1240 TestFilterImpl *This = (TestFilterImpl *)iface;
1242 EnterCriticalSection(&This->csFilter);
1244 *pState = This->state;
1246 LeaveCriticalSection(&This->csFilter);
1248 return S_OK;
1251 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1253 return E_NOTIMPL;
1256 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1258 return E_NOTIMPL;
1261 /** IBaseFilter implementation **/
1263 static HRESULT TestFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
1265 TestFilterImpl *This = (TestFilterImpl *)iface;
1267 /* Our pins are static, not changing so setting static tick count is ok */
1268 *lastsynctick = 0;
1270 if (pos >= This->nPins)
1271 return S_FALSE;
1273 *pin = This->ppPins[pos];
1274 IPin_AddRef(*pin);
1275 return S_OK;
1278 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1280 return IEnumPinsImpl_Construct(ppEnum, TestFilter_GetPin, iface);
1283 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1285 return E_NOTIMPL;
1288 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1290 TestFilterImpl *This = (TestFilterImpl *)iface;
1292 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1293 pInfo->pGraph = This->filterInfo.pGraph;
1295 if (pInfo->pGraph)
1296 IFilterGraph_AddRef(pInfo->pGraph);
1298 return S_OK;
1301 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1303 HRESULT hr = S_OK;
1304 TestFilterImpl *This = (TestFilterImpl *)iface;
1306 EnterCriticalSection(&This->csFilter);
1308 if (pName)
1309 lstrcpyW(This->filterInfo.achName, pName);
1310 else
1311 *This->filterInfo.achName = '\0';
1312 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1314 LeaveCriticalSection(&This->csFilter);
1316 return hr;
1319 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1321 return E_NOTIMPL;
1324 static const IBaseFilterVtbl TestFilter_Vtbl =
1326 TestFilter_QueryInterface,
1327 TestFilter_AddRef,
1328 TestFilter_Release,
1329 TestFilter_GetClassID,
1330 TestFilter_Stop,
1331 TestFilter_Pause,
1332 TestFilter_Run,
1333 TestFilter_GetState,
1334 TestFilter_SetSyncSource,
1335 TestFilter_GetSyncSource,
1336 TestFilter_EnumPins,
1337 TestFilter_FindPin,
1338 TestFilter_QueryFilterInfo,
1339 TestFilter_JoinFilterGraph,
1340 TestFilter_QueryVendorInfo
1343 /* IClassFactory implementation */
1345 typedef struct TestClassFactoryImpl
1347 IClassFactoryVtbl *lpVtbl;
1348 const TestFilterPinData *filterPinData;
1349 const CLSID *clsid;
1350 } TestClassFactoryImpl;
1352 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1353 LPCLASSFACTORY iface,
1354 REFIID riid,
1355 LPVOID *ppvObj)
1357 if (ppvObj == NULL) return E_POINTER;
1359 if (IsEqualGUID(riid, &IID_IUnknown) ||
1360 IsEqualGUID(riid, &IID_IClassFactory))
1362 *ppvObj = iface;
1363 IClassFactory_AddRef(iface);
1364 return S_OK;
1367 *ppvObj = NULL;
1368 return E_NOINTERFACE;
1371 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1373 return 2; /* non-heap-based object */
1376 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1378 return 1; /* non-heap-based object */
1381 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1382 LPCLASSFACTORY iface,
1383 LPUNKNOWN pUnkOuter,
1384 REFIID riid,
1385 LPVOID *ppvObj)
1387 TestClassFactoryImpl *This = (TestClassFactoryImpl *)iface;
1388 HRESULT hr;
1389 IUnknown *punk = NULL;
1391 *ppvObj = NULL;
1393 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1395 hr = TestFilter_Create(This->clsid, This->filterPinData, (LPVOID *) &punk);
1396 if (SUCCEEDED(hr)) {
1397 hr = IUnknown_QueryInterface(punk, riid, ppvObj);
1398 IUnknown_Release(punk);
1400 return hr;
1403 static HRESULT WINAPI Test_IClassFactory_LockServer(
1404 LPCLASSFACTORY iface,
1405 BOOL fLock)
1407 return S_OK;
1410 static IClassFactoryVtbl TestClassFactory_Vtbl =
1412 Test_IClassFactory_QueryInterface,
1413 Test_IClassFactory_AddRef,
1414 Test_IClassFactory_Release,
1415 Test_IClassFactory_CreateInstance,
1416 Test_IClassFactory_LockServer
1419 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1421 IPin *pin = NULL;
1422 PIN_INFO pinInfo;
1423 FILTER_INFO filterInfo;
1424 HRESULT hr;
1426 FilterName[0] = 0;
1428 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1429 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1430 if (FAILED(hr)) return hr;
1432 hr = IPin_QueryPinInfo(pin, &pinInfo);
1433 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1434 IPin_Release(pin);
1435 if (FAILED(hr)) return hr;
1437 SetLastError(0xdeadbeef);
1438 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1439 if (hr == S_OK && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1441 IBaseFilter_Release(pinInfo.pFilter);
1442 return E_NOTIMPL;
1444 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1445 IBaseFilter_Release(pinInfo.pFilter);
1446 if (FAILED(hr)) return hr;
1448 IFilterGraph_Release(filterInfo.pGraph);
1450 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1452 return S_OK;
1455 static void test_render_filter_priority(void)
1457 /* Tests filter choice priorities in Render(). */
1458 DWORD cookie1, cookie2, cookie3;
1459 HRESULT hr;
1460 IFilterGraph2* pgraph2 = NULL;
1461 IFilterMapper2 *pMapper2 = NULL;
1462 IBaseFilter* ptestfilter = NULL;
1463 IBaseFilter* ptestfilter2 = NULL;
1464 static const CLSID CLSID_TestFilter2 = {
1465 0x37a4edb0,
1466 0x4d13,
1467 0x11dd,
1468 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1470 static const CLSID CLSID_TestFilter3 = {
1471 0x37a4f2d8,
1472 0x4d13,
1473 0x11dd,
1474 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1476 static const CLSID CLSID_TestFilter4 = {
1477 0x37a4f3b4,
1478 0x4d13,
1479 0x11dd,
1480 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1482 static const GUID mediasubtype1 = {
1483 0x37a4f51c,
1484 0x4d13,
1485 0x11dd,
1486 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1488 static const GUID mediasubtype2 = {
1489 0x37a4f5c6,
1490 0x4d13,
1491 0x11dd,
1492 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1494 static const TestFilterPinData PinData1[] = {
1495 { PINDIR_OUTPUT, &mediasubtype1 },
1496 { 0, 0 }
1498 static const TestFilterPinData PinData2[] = {
1499 { PINDIR_INPUT, &mediasubtype1 },
1500 { 0, 0 }
1502 static const TestFilterPinData PinData3[] = {
1503 { PINDIR_INPUT, &GUID_NULL },
1504 { 0, 0 }
1506 static const TestFilterPinData PinData4[] = {
1507 { PINDIR_INPUT, &mediasubtype1 },
1508 { PINDIR_OUTPUT, &mediasubtype2 },
1509 { 0, 0 }
1511 static const TestFilterPinData PinData5[] = {
1512 { PINDIR_INPUT, &mediasubtype2 },
1513 { 0, 0 }
1515 TestClassFactoryImpl Filter1ClassFactory = { &TestClassFactory_Vtbl, PinData2, &CLSID_TestFilter2 };
1516 TestClassFactoryImpl Filter2ClassFactory = { &TestClassFactory_Vtbl, PinData4, &CLSID_TestFilter3 };
1517 TestClassFactoryImpl Filter3ClassFactory = { &TestClassFactory_Vtbl, PinData5, &CLSID_TestFilter4 };
1518 char ConnectedFilterName1[MAX_FILTER_NAME];
1519 char ConnectedFilterName2[MAX_FILTER_NAME];
1520 REGFILTER2 rgf2;
1521 REGFILTERPINS2 rgPins2[2];
1522 REGPINTYPES rgPinType[2];
1523 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1524 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1525 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1526 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1527 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1528 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1529 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1530 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1532 /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is
1533 "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating
1534 no preference given to exact match. */
1535 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1536 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1537 if (!pgraph2) goto out;
1539 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1540 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1541 if (FAILED(hr)) goto out;
1543 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1544 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1546 hr = TestFilter_Create(&GUID_NULL, PinData2, (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, wszFilterInstanceName2);
1551 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1553 IBaseFilter_Release(ptestfilter2);
1554 ptestfilter2 = NULL;
1556 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1557 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1558 if (FAILED(hr)) goto out;
1560 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1561 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1563 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1564 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1566 hr = get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1568 IFilterGraph2_Release(pgraph2);
1569 pgraph2 = NULL;
1570 IBaseFilter_Release(ptestfilter);
1571 ptestfilter = NULL;
1572 IBaseFilter_Release(ptestfilter2);
1573 ptestfilter2 = NULL;
1575 if (hr == E_NOTIMPL)
1577 win_skip("Needed functions are not implemented\n");
1578 return;
1581 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1582 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1583 if (!pgraph2) goto out;
1585 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1586 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1587 if (FAILED(hr)) goto out;
1589 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1590 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1592 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1593 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1594 if (FAILED(hr)) goto out;
1596 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1597 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1599 IBaseFilter_Release(ptestfilter2);
1600 ptestfilter2 = NULL;
1602 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1603 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1604 if (FAILED(hr)) goto out;
1606 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1607 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1609 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1610 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1612 hr = IFilterGraph2_Disconnect(pgraph2, NULL);
1613 ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr);
1615 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1616 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1617 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1619 IFilterGraph2_Release(pgraph2);
1620 pgraph2 = NULL;
1621 IBaseFilter_Release(ptestfilter);
1622 ptestfilter = NULL;
1623 IBaseFilter_Release(ptestfilter2);
1624 ptestfilter2 = NULL;
1626 /* Test if any preference is given to existing renderer which renders the pin directly vs
1627 an existing renderer which renders the pin indirectly, through an additional middle filter,
1628 again trying different orders of creation. Native appears not to give a preference. */
1630 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1631 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1632 if (!pgraph2) goto out;
1634 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1635 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1636 if (FAILED(hr)) goto out;
1638 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1639 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1641 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1642 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1643 if (FAILED(hr)) goto out;
1645 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1646 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1648 IBaseFilter_Release(ptestfilter2);
1649 ptestfilter2 = NULL;
1651 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1652 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1653 if (FAILED(hr)) goto out;
1655 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1656 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1658 IBaseFilter_Release(ptestfilter2);
1659 ptestfilter2 = NULL;
1661 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1662 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1663 if (FAILED(hr)) goto out;
1665 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1666 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1668 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1669 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1671 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1672 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1, "TestfilterInstance2"),
1673 "unexpected connected filter: %s\n", ConnectedFilterName1);
1675 IFilterGraph2_Release(pgraph2);
1676 pgraph2 = NULL;
1677 IBaseFilter_Release(ptestfilter);
1678 ptestfilter = NULL;
1679 IBaseFilter_Release(ptestfilter2);
1680 ptestfilter2 = NULL;
1682 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1683 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1684 if (!pgraph2) goto out;
1686 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1687 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1688 if (FAILED(hr)) goto out;
1690 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1691 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1693 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1694 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1695 if (FAILED(hr)) goto out;
1697 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1698 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1700 IBaseFilter_Release(ptestfilter2);
1701 ptestfilter2 = NULL;
1703 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1704 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1705 if (FAILED(hr)) goto out;
1707 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1708 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1710 IBaseFilter_Release(ptestfilter2);
1711 ptestfilter2 = NULL;
1713 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1714 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1715 if (FAILED(hr)) goto out;
1717 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1718 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1720 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1721 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1723 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1724 ok(!lstrcmp(ConnectedFilterName2, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2, "TestfilterInstance2"),
1725 "unexpected connected filter: %s\n", ConnectedFilterName2);
1726 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1727 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1729 IFilterGraph2_Release(pgraph2);
1730 pgraph2 = NULL;
1731 IBaseFilter_Release(ptestfilter);
1732 ptestfilter = NULL;
1733 IBaseFilter_Release(ptestfilter2);
1734 ptestfilter2 = NULL;
1736 /* Test if renderers are tried before non-renderers (intermediary filters). */
1737 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1738 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1739 if (!pgraph2) goto out;
1741 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
1742 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1743 if (!pMapper2) goto out;
1745 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1746 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1747 if (FAILED(hr)) goto out;
1749 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1750 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1752 /* Register our filters with COM and with Filtermapper. */
1753 hr = CoRegisterClassObject(Filter1ClassFactory.clsid, (IUnknown *)&Filter1ClassFactory,
1754 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie1);
1755 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1756 hr = CoRegisterClassObject(Filter2ClassFactory.clsid, (IUnknown *)&Filter2ClassFactory,
1757 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie2);
1758 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1759 hr = CoRegisterClassObject(Filter3ClassFactory.clsid, (IUnknown *)&Filter3ClassFactory,
1760 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie3);
1761 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1763 rgf2.dwVersion = 2;
1764 rgf2.dwMerit = MERIT_UNLIKELY;
1765 S1(U(rgf2)).cPins2 = 1;
1766 S1(U(rgf2)).rgPins2 = rgPins2;
1767 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
1768 rgPins2[0].cInstances = 1;
1769 rgPins2[0].nMediaTypes = 1;
1770 rgPins2[0].lpMediaType = &rgPinType[0];
1771 rgPins2[0].nMediums = 0;
1772 rgPins2[0].lpMedium = NULL;
1773 rgPins2[0].clsPinCategory = NULL;
1774 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
1775 rgPinType[0].clsMinorType = &mediasubtype1;
1777 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
1778 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1779 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1781 rgf2.dwMerit = MERIT_PREFERRED;
1782 rgPinType[0].clsMinorType = &mediasubtype2;
1784 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
1785 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1786 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1788 S1(U(rgf2)).cPins2 = 2;
1789 rgPins2[0].dwFlags = 0;
1790 rgPinType[0].clsMinorType = &mediasubtype1;
1792 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
1793 rgPins2[1].cInstances = 1;
1794 rgPins2[1].nMediaTypes = 1;
1795 rgPins2[1].lpMediaType = &rgPinType[1];
1796 rgPins2[1].nMediums = 0;
1797 rgPins2[1].lpMedium = NULL;
1798 rgPins2[1].clsPinCategory = NULL;
1799 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
1800 rgPinType[1].clsMinorType = &mediasubtype2;
1802 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
1803 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1804 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1806 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1807 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1809 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1810 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3"),
1811 "unexpected connected filter: %s\n", ConnectedFilterName1);
1813 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1814 &CLSID_TestFilter2);
1815 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1816 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1817 &CLSID_TestFilter3);
1818 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1819 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1820 &CLSID_TestFilter4);
1821 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1823 out:
1825 if (ptestfilter) IBaseFilter_Release(ptestfilter);
1826 if (ptestfilter2) IBaseFilter_Release(ptestfilter2);
1827 if (pgraph2) IFilterGraph2_Release(pgraph2);
1828 if (pMapper2) IFilterMapper2_Release(pMapper2);
1830 hr = CoRevokeClassObject(cookie1);
1831 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1832 hr = CoRevokeClassObject(cookie2);
1833 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1834 hr = CoRevokeClassObject(cookie3);
1835 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1838 START_TEST(filtergraph)
1840 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1841 test_render_run(avifileA);
1842 test_render_run(mpegfileA);
1843 test_graph_builder();
1844 test_graph_builder_addfilter();
1845 test_mediacontrol();
1846 test_filter_graph2();
1847 test_render_filter_priority();
1848 CoUninitialize();