wer: Add new stubbed wer.dll.
[wine/hramrach.git] / dlls / quartz / tests / filtergraph.c
blob26a72beef8d99ca33f2d37e0339b2fa907dbb534
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 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_ReturnTime, NULL, AM_SEEKING_NoPositioning);
276 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
277 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_NoPositioning, NULL, AM_SEEKING_ReturnTime);
278 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
280 IMediaFilter_SetSyncSource(filter, NULL);
281 pos = 0xdeadbeef;
282 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
283 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
284 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
286 hr = IMediaControl_GetState(control, 1000, NULL);
287 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
289 IUnknown_Release(control);
290 IUnknown_Release(seeking);
291 IUnknown_Release(filter);
292 releasefiltergraph();
295 static void test_filter_graph2(void)
297 HRESULT hr;
298 IFilterGraph2 *pF = NULL;
300 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
301 &IID_IFilterGraph2, (LPVOID*)&pF);
302 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
303 ok(pF != NULL, "pF is NULL\n");
305 hr = IFilterGraph2_Release(pF);
306 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
309 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
310 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
312 if (pMediaType->pbFormat)
314 CoTaskMemFree(pMediaType->pbFormat);
315 pMediaType->pbFormat = NULL;
317 if (pMediaType->pUnk)
319 IUnknown_Release(pMediaType->pUnk);
320 pMediaType->pUnk = NULL;
324 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
326 *pDest = *pSrc;
327 if (!pSrc->pbFormat) return S_OK;
328 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
329 return E_OUTOFMEMORY;
330 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
331 if (pDest->pUnk)
332 IUnknown_AddRef(pDest->pUnk);
333 return S_OK;
336 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
338 AM_MEDIA_TYPE * pDest;
340 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
341 if (!pDest)
342 return NULL;
344 if (FAILED(CopyMediaType(pDest, pSrc)))
346 CoTaskMemFree(pDest);
347 return NULL;
350 return pDest;
353 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
355 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
356 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
359 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
361 FreeMediaType(pMediaType);
362 CoTaskMemFree(pMediaType);
365 typedef struct IEnumMediaTypesImpl
367 const IEnumMediaTypesVtbl * lpVtbl;
368 LONG refCount;
369 AM_MEDIA_TYPE *pMediaTypes;
370 ULONG cMediaTypes;
371 ULONG uIndex;
372 } IEnumMediaTypesImpl;
374 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
376 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
378 ULONG i;
379 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
381 if (!pEnumMediaTypes)
383 *ppEnum = NULL;
384 return E_OUTOFMEMORY;
386 pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl;
387 pEnumMediaTypes->refCount = 1;
388 pEnumMediaTypes->uIndex = 0;
389 pEnumMediaTypes->cMediaTypes = cMediaTypes;
390 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
391 for (i = 0; i < cMediaTypes; i++)
392 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
394 while (i--)
395 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
396 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
397 return E_OUTOFMEMORY;
399 *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl);
400 return S_OK;
403 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
405 *ppv = NULL;
407 if (IsEqualIID(riid, &IID_IUnknown))
408 *ppv = iface;
409 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
410 *ppv = iface;
412 if (*ppv)
414 IUnknown_AddRef((IUnknown *)(*ppv));
415 return S_OK;
418 return E_NOINTERFACE;
421 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
423 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
424 ULONG refCount = InterlockedIncrement(&This->refCount);
426 return refCount;
429 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
431 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
432 ULONG refCount = InterlockedDecrement(&This->refCount);
434 if (!refCount)
436 int i;
437 for (i = 0; i < This->cMediaTypes; i++)
438 FreeMediaType(&This->pMediaTypes[i]);
439 CoTaskMemFree(This->pMediaTypes);
440 CoTaskMemFree(This);
442 return refCount;
445 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
447 ULONG cFetched;
448 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
450 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
452 if (cFetched > 0)
454 ULONG i;
455 for (i = 0; i < cFetched; i++)
456 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
458 while (i--)
459 DeleteMediaType(ppMediaTypes[i]);
460 *pcFetched = 0;
461 return E_OUTOFMEMORY;
465 if ((cMediaTypes != 1) || pcFetched)
466 *pcFetched = cFetched;
468 This->uIndex += cFetched;
470 if (cFetched != cMediaTypes)
471 return S_FALSE;
472 return S_OK;
475 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
477 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
479 if (This->uIndex + cMediaTypes < This->cMediaTypes)
481 This->uIndex += cMediaTypes;
482 return S_OK;
484 return S_FALSE;
487 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
489 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
491 This->uIndex = 0;
492 return S_OK;
495 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
497 HRESULT hr;
498 IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
500 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
501 if (FAILED(hr))
502 return hr;
503 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
506 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
508 IEnumMediaTypesImpl_QueryInterface,
509 IEnumMediaTypesImpl_AddRef,
510 IEnumMediaTypesImpl_Release,
511 IEnumMediaTypesImpl_Next,
512 IEnumMediaTypesImpl_Skip,
513 IEnumMediaTypesImpl_Reset,
514 IEnumMediaTypesImpl_Clone
517 /* Implementation of a very stripped down pin for the test filter. Just enough
518 functionality for connecting and Render() to work. */
520 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
522 lstrcpyW(pDest->achName, pSrc->achName);
523 pDest->dir = pSrc->dir;
524 pDest->pFilter = pSrc->pFilter;
527 typedef struct ITestPinImpl
529 const struct IPinVtbl * lpVtbl;
530 LONG refCount;
531 LPCRITICAL_SECTION pCritSec;
532 PIN_INFO pinInfo;
533 IPin * pConnectedTo;
534 AM_MEDIA_TYPE mtCurrent;
535 LPVOID pUserData;
536 } ITestPinImpl;
538 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
540 *ppv = NULL;
542 if (IsEqualIID(riid, &IID_IUnknown))
543 *ppv = iface;
544 else if (IsEqualIID(riid, &IID_IPin))
545 *ppv = iface;
547 if (*ppv)
549 IUnknown_AddRef((IUnknown *)(*ppv));
550 return S_OK;
553 return E_NOINTERFACE;
556 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
558 ITestPinImpl *This = (ITestPinImpl *)iface;
559 ULONG refCount = InterlockedIncrement(&This->refCount);
560 return refCount;
563 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
565 ITestPinImpl *This = (ITestPinImpl *)iface;
566 ULONG refCount = InterlockedDecrement(&This->refCount);
568 if (!refCount)
570 FreeMediaType(&This->mtCurrent);
571 This->lpVtbl = NULL;
572 CoTaskMemFree(This);
573 return 0;
575 else
576 return refCount;
579 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
581 return E_UNEXPECTED;
584 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
586 ITestPinImpl *This = (ITestPinImpl *)iface;
587 PIN_DIRECTION pindirReceive;
588 HRESULT hr = S_OK;
590 EnterCriticalSection(This->pCritSec);
592 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
593 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
594 hr = VFW_E_TYPE_NOT_ACCEPTED;
596 if (This->pConnectedTo)
597 hr = VFW_E_ALREADY_CONNECTED;
599 if (SUCCEEDED(hr))
601 IPin_QueryDirection(pReceivePin, &pindirReceive);
603 if (pindirReceive != PINDIR_OUTPUT)
605 hr = VFW_E_INVALID_DIRECTION;
609 if (SUCCEEDED(hr))
611 CopyMediaType(&This->mtCurrent, pmt);
612 This->pConnectedTo = pReceivePin;
613 IPin_AddRef(pReceivePin);
616 LeaveCriticalSection(This->pCritSec);
618 return hr;
621 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
623 HRESULT hr;
624 ITestPinImpl *This = (ITestPinImpl *)iface;
626 EnterCriticalSection(This->pCritSec);
628 if (This->pConnectedTo)
630 IPin_Release(This->pConnectedTo);
631 This->pConnectedTo = NULL;
632 hr = S_OK;
634 else
635 hr = S_FALSE;
637 LeaveCriticalSection(This->pCritSec);
639 return hr;
642 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
644 HRESULT hr;
645 ITestPinImpl *This = (ITestPinImpl *)iface;
647 EnterCriticalSection(This->pCritSec);
649 if (This->pConnectedTo)
651 *ppPin = This->pConnectedTo;
652 IPin_AddRef(*ppPin);
653 hr = S_OK;
655 else
657 hr = VFW_E_NOT_CONNECTED;
658 *ppPin = NULL;
661 LeaveCriticalSection(This->pCritSec);
663 return hr;
666 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
668 HRESULT hr;
669 ITestPinImpl *This = (ITestPinImpl *)iface;
671 EnterCriticalSection(This->pCritSec);
673 if (This->pConnectedTo)
675 CopyMediaType(pmt, &This->mtCurrent);
676 hr = S_OK;
678 else
680 ZeroMemory(pmt, sizeof(*pmt));
681 hr = VFW_E_NOT_CONNECTED;
684 LeaveCriticalSection(This->pCritSec);
686 return hr;
689 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
691 ITestPinImpl *This = (ITestPinImpl *)iface;
693 Copy_PinInfo(pInfo, &This->pinInfo);
694 IBaseFilter_AddRef(pInfo->pFilter);
696 return S_OK;
699 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
701 ITestPinImpl *This = (ITestPinImpl *)iface;
703 *pPinDir = This->pinInfo.dir;
705 return S_OK;
708 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
710 return E_NOTIMPL;
713 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
715 ITestPinImpl *This = (ITestPinImpl *)iface;
717 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
718 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
719 return S_OK;
720 else
721 return VFW_E_TYPE_NOT_ACCEPTED;
724 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
726 ITestPinImpl *This = (ITestPinImpl *)iface;
728 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
731 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
733 return E_NOTIMPL;
736 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
738 return E_NOTIMPL;
741 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
743 return E_NOTIMPL;
746 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
748 return E_NOTIMPL;
751 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
753 return E_NOTIMPL;
756 static const IPinVtbl TestFilter_InputPin_Vtbl =
758 TestFilter_Pin_QueryInterface,
759 TestFilter_Pin_AddRef,
760 TestFilter_Pin_Release,
761 TestFilter_InputPin_Connect,
762 TestFilter_InputPin_ReceiveConnection,
763 TestFilter_Pin_Disconnect,
764 TestFilter_Pin_ConnectedTo,
765 TestFilter_Pin_ConnectionMediaType,
766 TestFilter_Pin_QueryPinInfo,
767 TestFilter_Pin_QueryDirection,
768 TestFilter_Pin_QueryId,
769 TestFilter_Pin_QueryAccept,
770 TestFilter_Pin_EnumMediaTypes,
771 TestFilter_Pin_QueryInternalConnections,
772 TestFilter_Pin_EndOfStream,
773 TestFilter_Pin_BeginFlush,
774 TestFilter_Pin_EndFlush,
775 TestFilter_Pin_NewSegment
778 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
780 return E_UNEXPECTED;
783 /* Private helper function */
784 static HRESULT TestFilter_OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
786 ITestPinImpl *This = (ITestPinImpl *)iface;
787 HRESULT hr;
789 This->pConnectedTo = pReceivePin;
790 IPin_AddRef(pReceivePin);
792 hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
794 if (FAILED(hr))
796 IPin_Release(This->pConnectedTo);
797 This->pConnectedTo = NULL;
800 return hr;
803 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
805 ITestPinImpl *This = (ITestPinImpl *)iface;
806 HRESULT hr;
808 EnterCriticalSection(This->pCritSec);
810 /* if we have been a specific type to connect with, then we can either connect
811 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
812 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
813 hr = TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, pmt);
814 else
816 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
817 (TestFilter_OutputPin_ConnectSpecific(iface, pReceivePin, &This->mtCurrent) == S_OK))
818 hr = S_OK;
819 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
820 } /* if negotiate media type */
821 } /* if succeeded */
822 LeaveCriticalSection(This->pCritSec);
824 return hr;
827 static const IPinVtbl TestFilter_OutputPin_Vtbl =
829 TestFilter_Pin_QueryInterface,
830 TestFilter_Pin_AddRef,
831 TestFilter_Pin_Release,
832 TestFilter_OutputPin_Connect,
833 TestFilter_OutputPin_ReceiveConnection,
834 TestFilter_Pin_Disconnect,
835 TestFilter_Pin_ConnectedTo,
836 TestFilter_Pin_ConnectionMediaType,
837 TestFilter_Pin_QueryPinInfo,
838 TestFilter_Pin_QueryDirection,
839 TestFilter_Pin_QueryId,
840 TestFilter_Pin_QueryAccept,
841 TestFilter_Pin_EnumMediaTypes,
842 TestFilter_Pin_QueryInternalConnections,
843 TestFilter_Pin_EndOfStream,
844 TestFilter_Pin_BeginFlush,
845 TestFilter_Pin_EndFlush,
846 TestFilter_Pin_NewSegment
849 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
850 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
852 ITestPinImpl * pPinImpl;
854 *ppPin = NULL;
856 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
858 if (!pPinImpl)
859 return E_OUTOFMEMORY;
861 pPinImpl->refCount = 1;
862 pPinImpl->pConnectedTo = NULL;
863 pPinImpl->pCritSec = pCritSec;
864 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
865 pPinImpl->mtCurrent = *pinmt;
867 pPinImpl->lpVtbl = Pin_Vtbl;
869 *ppPin = (IPin *)pPinImpl;
870 return S_OK;
873 /* IEnumPins implementation */
875 typedef HRESULT (* FNOBTAINPIN)(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick);
877 typedef struct IEnumPinsImpl
879 const IEnumPinsVtbl * lpVtbl;
880 LONG refCount;
881 ULONG uIndex;
882 IBaseFilter *base;
883 FNOBTAINPIN receive_pin;
884 DWORD synctime;
885 } IEnumPinsImpl;
887 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
889 static HRESULT IEnumPinsImpl_Construct(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, IBaseFilter *base)
891 IEnumPinsImpl * pEnumPins;
893 if (!ppEnum)
894 return E_POINTER;
896 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
897 if (!pEnumPins)
899 *ppEnum = NULL;
900 return E_OUTOFMEMORY;
902 pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl;
903 pEnumPins->refCount = 1;
904 pEnumPins->uIndex = 0;
905 pEnumPins->receive_pin = receive_pin;
906 pEnumPins->base = base;
907 IBaseFilter_AddRef(base);
908 *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl);
910 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
912 return S_OK;
915 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
917 *ppv = NULL;
919 if (IsEqualIID(riid, &IID_IUnknown))
920 *ppv = iface;
921 else if (IsEqualIID(riid, &IID_IEnumPins))
922 *ppv = iface;
924 if (*ppv)
926 IUnknown_AddRef((IUnknown *)(*ppv));
927 return S_OK;
930 return E_NOINTERFACE;
933 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
935 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
936 ULONG refCount = InterlockedIncrement(&This->refCount);
938 return refCount;
941 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
943 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
944 ULONG refCount = InterlockedDecrement(&This->refCount);
946 if (!refCount)
948 IBaseFilter_Release(This->base);
949 CoTaskMemFree(This);
950 return 0;
952 else
953 return refCount;
956 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
958 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
959 DWORD synctime = This->synctime;
960 HRESULT hr = S_OK;
961 ULONG i = 0;
963 if (!ppPins)
964 return E_POINTER;
966 if (cPins > 1 && !pcFetched)
967 return E_INVALIDARG;
969 if (pcFetched)
970 *pcFetched = 0;
972 while (i < cPins && hr == S_OK)
974 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
976 if (hr == S_OK)
977 ++i;
979 if (synctime != This->synctime)
980 break;
983 if (!i && synctime != This->synctime)
984 return VFW_E_ENUM_OUT_OF_SYNC;
986 if (pcFetched)
987 *pcFetched = i;
988 This->uIndex += i;
990 if (i < cPins)
991 return S_FALSE;
992 return S_OK;
995 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
997 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
998 DWORD synctime = This->synctime;
999 HRESULT hr;
1000 IPin *pin = NULL;
1002 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
1003 if (pin)
1004 IPin_Release(pin);
1006 if (synctime != This->synctime)
1007 return VFW_E_ENUM_OUT_OF_SYNC;
1009 if (hr == S_OK)
1010 This->uIndex += cPins;
1012 return hr;
1015 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1017 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1019 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1021 This->uIndex = 0;
1022 return S_OK;
1025 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1027 HRESULT hr;
1028 IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
1030 hr = IEnumPinsImpl_Construct(ppEnum, This->receive_pin, This->base);
1031 if (FAILED(hr))
1032 return hr;
1033 return IEnumPins_Skip(*ppEnum, This->uIndex);
1036 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1038 IEnumPinsImpl_QueryInterface,
1039 IEnumPinsImpl_AddRef,
1040 IEnumPinsImpl_Release,
1041 IEnumPinsImpl_Next,
1042 IEnumPinsImpl_Skip,
1043 IEnumPinsImpl_Reset,
1044 IEnumPinsImpl_Clone
1047 /* Test filter implementation - a filter that has few predefined pins with single media type
1048 * that accept only this single media type. Enough for Render(). */
1050 typedef struct TestFilterPinData
1052 PIN_DIRECTION pinDir;
1053 const GUID *mediasubtype;
1054 } TestFilterPinData;
1056 typedef struct TestFilterImpl
1058 const IBaseFilterVtbl * lpVtbl;
1060 LONG refCount;
1061 CRITICAL_SECTION csFilter;
1062 FILTER_STATE state;
1063 FILTER_INFO filterInfo;
1064 CLSID clsid;
1065 IPin ** ppPins;
1066 UINT nPins;
1067 } TestFilterImpl;
1069 static const IBaseFilterVtbl TestFilter_Vtbl;
1071 static HRESULT TestFilter_Create(const CLSID* pClsid, const TestFilterPinData *pinData, LPVOID * ppv)
1073 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1074 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1075 HRESULT hr;
1076 PIN_INFO pinInfo;
1077 TestFilterImpl* pTestFilter = NULL;
1078 UINT nPins, i;
1079 AM_MEDIA_TYPE mt;
1081 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1082 if (!pTestFilter) return E_OUTOFMEMORY;
1084 pTestFilter->clsid = *pClsid;
1085 pTestFilter->lpVtbl = &TestFilter_Vtbl;
1086 pTestFilter->refCount = 1;
1087 InitializeCriticalSection(&pTestFilter->csFilter);
1088 pTestFilter->state = State_Stopped;
1090 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1092 nPins = 0;
1093 while(pinData[nPins].mediasubtype) ++nPins;
1095 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1096 if (!pTestFilter->ppPins)
1098 hr = E_OUTOFMEMORY;
1099 goto error;
1101 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1103 for (i = 0; i < nPins; i++)
1105 ZeroMemory(&mt, sizeof(mt));
1106 mt.majortype = MEDIATYPE_Video;
1107 mt.formattype = FORMAT_None;
1108 mt.subtype = *pinData[i].mediasubtype;
1110 pinInfo.dir = pinData[i].pinDir;
1111 pinInfo.pFilter = (IBaseFilter *)pTestFilter;
1112 if (pinInfo.dir == PINDIR_INPUT)
1114 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1115 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1116 &pTestFilter->ppPins[i]);
1119 else
1121 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1122 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1123 &pTestFilter->ppPins[i]);
1125 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1128 pTestFilter->nPins = nPins;
1129 *ppv = pTestFilter;
1130 return S_OK;
1132 error:
1134 if (pTestFilter->ppPins)
1136 for (i = 0; i < nPins; i++)
1138 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1141 CoTaskMemFree(pTestFilter->ppPins);
1142 DeleteCriticalSection(&pTestFilter->csFilter);
1143 CoTaskMemFree(pTestFilter);
1145 return hr;
1148 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1150 TestFilterImpl *This = (TestFilterImpl *)iface;
1152 *ppv = NULL;
1154 if (IsEqualIID(riid, &IID_IUnknown))
1155 *ppv = This;
1156 else if (IsEqualIID(riid, &IID_IPersist))
1157 *ppv = This;
1158 else if (IsEqualIID(riid, &IID_IMediaFilter))
1159 *ppv = This;
1160 else if (IsEqualIID(riid, &IID_IBaseFilter))
1161 *ppv = This;
1163 if (*ppv)
1165 IUnknown_AddRef((IUnknown *)(*ppv));
1166 return S_OK;
1169 return E_NOINTERFACE;
1172 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1174 TestFilterImpl *This = (TestFilterImpl *)iface;
1175 ULONG refCount = InterlockedIncrement(&This->refCount);
1177 return refCount;
1180 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1182 TestFilterImpl *This = (TestFilterImpl *)iface;
1183 ULONG refCount = InterlockedDecrement(&This->refCount);
1185 if (!refCount)
1187 ULONG i;
1189 for (i = 0; i < This->nPins; i++)
1191 IPin *pConnectedTo;
1193 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1195 IPin_Disconnect(pConnectedTo);
1196 IPin_Release(pConnectedTo);
1198 IPin_Disconnect(This->ppPins[i]);
1200 IPin_Release(This->ppPins[i]);
1203 CoTaskMemFree(This->ppPins);
1204 This->lpVtbl = NULL;
1206 DeleteCriticalSection(&This->csFilter);
1208 CoTaskMemFree(This);
1210 return 0;
1212 else
1213 return refCount;
1215 /** IPersist methods **/
1217 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1219 TestFilterImpl *This = (TestFilterImpl *)iface;
1221 *pClsid = This->clsid;
1223 return S_OK;
1226 /** IMediaFilter methods **/
1228 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1230 return E_NOTIMPL;
1233 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1235 return E_NOTIMPL;
1238 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1240 return E_NOTIMPL;
1243 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1245 TestFilterImpl *This = (TestFilterImpl *)iface;
1247 EnterCriticalSection(&This->csFilter);
1249 *pState = This->state;
1251 LeaveCriticalSection(&This->csFilter);
1253 return S_OK;
1256 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1258 return E_NOTIMPL;
1261 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1263 return E_NOTIMPL;
1266 /** IBaseFilter implementation **/
1268 static HRESULT TestFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
1270 TestFilterImpl *This = (TestFilterImpl *)iface;
1272 /* Our pins are static, not changing so setting static tick count is ok */
1273 *lastsynctick = 0;
1275 if (pos >= This->nPins)
1276 return S_FALSE;
1278 *pin = This->ppPins[pos];
1279 IPin_AddRef(*pin);
1280 return S_OK;
1283 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1285 return IEnumPinsImpl_Construct(ppEnum, TestFilter_GetPin, iface);
1288 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1290 return E_NOTIMPL;
1293 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1295 TestFilterImpl *This = (TestFilterImpl *)iface;
1297 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1298 pInfo->pGraph = This->filterInfo.pGraph;
1300 if (pInfo->pGraph)
1301 IFilterGraph_AddRef(pInfo->pGraph);
1303 return S_OK;
1306 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1308 HRESULT hr = S_OK;
1309 TestFilterImpl *This = (TestFilterImpl *)iface;
1311 EnterCriticalSection(&This->csFilter);
1313 if (pName)
1314 lstrcpyW(This->filterInfo.achName, pName);
1315 else
1316 *This->filterInfo.achName = '\0';
1317 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1319 LeaveCriticalSection(&This->csFilter);
1321 return hr;
1324 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1326 return E_NOTIMPL;
1329 static const IBaseFilterVtbl TestFilter_Vtbl =
1331 TestFilter_QueryInterface,
1332 TestFilter_AddRef,
1333 TestFilter_Release,
1334 TestFilter_GetClassID,
1335 TestFilter_Stop,
1336 TestFilter_Pause,
1337 TestFilter_Run,
1338 TestFilter_GetState,
1339 TestFilter_SetSyncSource,
1340 TestFilter_GetSyncSource,
1341 TestFilter_EnumPins,
1342 TestFilter_FindPin,
1343 TestFilter_QueryFilterInfo,
1344 TestFilter_JoinFilterGraph,
1345 TestFilter_QueryVendorInfo
1348 /* IClassFactory implementation */
1350 typedef struct TestClassFactoryImpl
1352 IClassFactoryVtbl *lpVtbl;
1353 const TestFilterPinData *filterPinData;
1354 const CLSID *clsid;
1355 } TestClassFactoryImpl;
1357 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1358 LPCLASSFACTORY iface,
1359 REFIID riid,
1360 LPVOID *ppvObj)
1362 if (ppvObj == NULL) return E_POINTER;
1364 if (IsEqualGUID(riid, &IID_IUnknown) ||
1365 IsEqualGUID(riid, &IID_IClassFactory))
1367 *ppvObj = iface;
1368 IClassFactory_AddRef(iface);
1369 return S_OK;
1372 *ppvObj = NULL;
1373 return E_NOINTERFACE;
1376 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1378 return 2; /* non-heap-based object */
1381 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1383 return 1; /* non-heap-based object */
1386 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1387 LPCLASSFACTORY iface,
1388 LPUNKNOWN pUnkOuter,
1389 REFIID riid,
1390 LPVOID *ppvObj)
1392 TestClassFactoryImpl *This = (TestClassFactoryImpl *)iface;
1393 HRESULT hr;
1394 IUnknown *punk = NULL;
1396 *ppvObj = NULL;
1398 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1400 hr = TestFilter_Create(This->clsid, This->filterPinData, (LPVOID *) &punk);
1401 if (SUCCEEDED(hr)) {
1402 hr = IUnknown_QueryInterface(punk, riid, ppvObj);
1403 IUnknown_Release(punk);
1405 return hr;
1408 static HRESULT WINAPI Test_IClassFactory_LockServer(
1409 LPCLASSFACTORY iface,
1410 BOOL fLock)
1412 return S_OK;
1415 static IClassFactoryVtbl TestClassFactory_Vtbl =
1417 Test_IClassFactory_QueryInterface,
1418 Test_IClassFactory_AddRef,
1419 Test_IClassFactory_Release,
1420 Test_IClassFactory_CreateInstance,
1421 Test_IClassFactory_LockServer
1424 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1426 IPin *pin = NULL;
1427 PIN_INFO pinInfo;
1428 FILTER_INFO filterInfo;
1429 HRESULT hr;
1431 FilterName[0] = 0;
1433 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1434 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1435 if (FAILED(hr)) return hr;
1437 hr = IPin_QueryPinInfo(pin, &pinInfo);
1438 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1439 IPin_Release(pin);
1440 if (FAILED(hr)) return hr;
1442 SetLastError(0xdeadbeef);
1443 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1444 if (hr == S_OK && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1446 IBaseFilter_Release(pinInfo.pFilter);
1447 return E_NOTIMPL;
1449 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1450 IBaseFilter_Release(pinInfo.pFilter);
1451 if (FAILED(hr)) return hr;
1453 IFilterGraph_Release(filterInfo.pGraph);
1455 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1457 return S_OK;
1460 static void test_render_filter_priority(void)
1462 /* Tests filter choice priorities in Render(). */
1463 DWORD cookie1 = 0, cookie2 = 0, cookie3 = 0;
1464 HRESULT hr;
1465 IFilterGraph2* pgraph2 = NULL;
1466 IFilterMapper2 *pMapper2 = NULL;
1467 IBaseFilter* ptestfilter = NULL;
1468 IBaseFilter* ptestfilter2 = NULL;
1469 static const CLSID CLSID_TestFilter2 = {
1470 0x37a4edb0,
1471 0x4d13,
1472 0x11dd,
1473 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1475 static const CLSID CLSID_TestFilter3 = {
1476 0x37a4f2d8,
1477 0x4d13,
1478 0x11dd,
1479 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1481 static const CLSID CLSID_TestFilter4 = {
1482 0x37a4f3b4,
1483 0x4d13,
1484 0x11dd,
1485 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1487 static const GUID mediasubtype1 = {
1488 0x37a4f51c,
1489 0x4d13,
1490 0x11dd,
1491 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1493 static const GUID mediasubtype2 = {
1494 0x37a4f5c6,
1495 0x4d13,
1496 0x11dd,
1497 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1499 static const TestFilterPinData PinData1[] = {
1500 { PINDIR_OUTPUT, &mediasubtype1 },
1501 { 0, 0 }
1503 static const TestFilterPinData PinData2[] = {
1504 { PINDIR_INPUT, &mediasubtype1 },
1505 { 0, 0 }
1507 static const TestFilterPinData PinData3[] = {
1508 { PINDIR_INPUT, &GUID_NULL },
1509 { 0, 0 }
1511 static const TestFilterPinData PinData4[] = {
1512 { PINDIR_INPUT, &mediasubtype1 },
1513 { PINDIR_OUTPUT, &mediasubtype2 },
1514 { 0, 0 }
1516 static const TestFilterPinData PinData5[] = {
1517 { PINDIR_INPUT, &mediasubtype2 },
1518 { 0, 0 }
1520 TestClassFactoryImpl Filter1ClassFactory = { &TestClassFactory_Vtbl, PinData2, &CLSID_TestFilter2 };
1521 TestClassFactoryImpl Filter2ClassFactory = { &TestClassFactory_Vtbl, PinData4, &CLSID_TestFilter3 };
1522 TestClassFactoryImpl Filter3ClassFactory = { &TestClassFactory_Vtbl, PinData5, &CLSID_TestFilter4 };
1523 char ConnectedFilterName1[MAX_FILTER_NAME];
1524 char ConnectedFilterName2[MAX_FILTER_NAME];
1525 REGFILTER2 rgf2;
1526 REGFILTERPINS2 rgPins2[2];
1527 REGPINTYPES rgPinType[2];
1528 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1529 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1530 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1531 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1532 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1533 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1534 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1535 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1537 /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is
1538 "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating
1539 no preference given to exact match. */
1540 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1541 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1542 if (!pgraph2) return;
1544 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1545 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1546 if (FAILED(hr)) goto out;
1548 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1549 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1551 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1552 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1553 if (FAILED(hr)) goto out;
1555 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1556 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1558 IBaseFilter_Release(ptestfilter2);
1559 ptestfilter2 = NULL;
1561 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1562 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1563 if (FAILED(hr)) goto out;
1565 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1566 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1568 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1569 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1571 hr = get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1573 IFilterGraph2_Release(pgraph2);
1574 pgraph2 = NULL;
1575 IBaseFilter_Release(ptestfilter);
1576 ptestfilter = NULL;
1577 IBaseFilter_Release(ptestfilter2);
1578 ptestfilter2 = NULL;
1580 if (hr == E_NOTIMPL)
1582 win_skip("Needed functions are not implemented\n");
1583 return;
1586 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1587 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1588 if (!pgraph2) goto out;
1590 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1591 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1592 if (FAILED(hr)) goto out;
1594 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1595 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1597 hr = TestFilter_Create(&GUID_NULL, PinData3, (LPVOID)&ptestfilter2);
1598 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1599 if (FAILED(hr)) goto out;
1601 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1602 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1604 IBaseFilter_Release(ptestfilter2);
1605 ptestfilter2 = NULL;
1607 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1608 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1609 if (FAILED(hr)) goto out;
1611 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1612 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1614 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1615 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1617 hr = IFilterGraph2_Disconnect(pgraph2, NULL);
1618 ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr);
1620 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1621 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1622 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1624 IFilterGraph2_Release(pgraph2);
1625 pgraph2 = NULL;
1626 IBaseFilter_Release(ptestfilter);
1627 ptestfilter = NULL;
1628 IBaseFilter_Release(ptestfilter2);
1629 ptestfilter2 = NULL;
1631 /* Test if any preference is given to existing renderer which renders the pin directly vs
1632 an existing renderer which renders the pin indirectly, through an additional middle filter,
1633 again trying different orders of creation. Native appears not to give a preference. */
1635 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1636 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1637 if (!pgraph2) goto out;
1639 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1640 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1641 if (FAILED(hr)) goto out;
1643 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1644 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1646 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1647 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1648 if (FAILED(hr)) goto out;
1650 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1651 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1653 IBaseFilter_Release(ptestfilter2);
1654 ptestfilter2 = NULL;
1656 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1657 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1658 if (FAILED(hr)) goto out;
1660 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1661 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1663 IBaseFilter_Release(ptestfilter2);
1664 ptestfilter2 = NULL;
1666 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1667 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1668 if (FAILED(hr)) goto out;
1670 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1671 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1673 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1674 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1676 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1677 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1, "TestfilterInstance2"),
1678 "unexpected connected filter: %s\n", ConnectedFilterName1);
1680 IFilterGraph2_Release(pgraph2);
1681 pgraph2 = NULL;
1682 IBaseFilter_Release(ptestfilter);
1683 ptestfilter = NULL;
1684 IBaseFilter_Release(ptestfilter2);
1685 ptestfilter2 = NULL;
1687 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1688 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1689 if (!pgraph2) goto out;
1691 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1692 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1693 if (FAILED(hr)) goto out;
1695 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1696 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1698 hr = TestFilter_Create(&GUID_NULL, PinData4, (LPVOID)&ptestfilter2);
1699 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1700 if (FAILED(hr)) goto out;
1702 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName3);
1703 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1705 IBaseFilter_Release(ptestfilter2);
1706 ptestfilter2 = NULL;
1708 hr = TestFilter_Create(&GUID_NULL, PinData5, (LPVOID)&ptestfilter2);
1709 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1710 if (FAILED(hr)) goto out;
1712 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName4);
1713 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1715 IBaseFilter_Release(ptestfilter2);
1716 ptestfilter2 = NULL;
1718 hr = TestFilter_Create(&GUID_NULL, PinData2, (LPVOID)&ptestfilter2);
1719 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1720 if (FAILED(hr)) goto out;
1722 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter2, wszFilterInstanceName2);
1723 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1725 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1726 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1728 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName2);
1729 ok(!lstrcmp(ConnectedFilterName2, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2, "TestfilterInstance2"),
1730 "unexpected connected filter: %s\n", ConnectedFilterName2);
1731 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1732 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1734 IFilterGraph2_Release(pgraph2);
1735 pgraph2 = NULL;
1736 IBaseFilter_Release(ptestfilter);
1737 ptestfilter = NULL;
1738 IBaseFilter_Release(ptestfilter2);
1739 ptestfilter2 = NULL;
1741 /* Test if renderers are tried before non-renderers (intermediary filters). */
1742 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1743 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1744 if (!pgraph2) goto out;
1746 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
1747 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1748 if (!pMapper2) goto out;
1750 hr = TestFilter_Create(&GUID_NULL, PinData1, (LPVOID)&ptestfilter);
1751 ok(hr == S_OK, "TestFilter_Create failed with %08x\n", hr);
1752 if (FAILED(hr)) goto out;
1754 hr = IFilterGraph2_AddFilter(pgraph2, ptestfilter, wszFilterInstanceName1);
1755 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1757 /* Register our filters with COM and with Filtermapper. */
1758 hr = CoRegisterClassObject(Filter1ClassFactory.clsid, (IUnknown *)&Filter1ClassFactory,
1759 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie1);
1760 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1761 if (FAILED(hr)) goto out;
1762 hr = CoRegisterClassObject(Filter2ClassFactory.clsid, (IUnknown *)&Filter2ClassFactory,
1763 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie2);
1764 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1765 if (FAILED(hr)) goto out;
1766 hr = CoRegisterClassObject(Filter3ClassFactory.clsid, (IUnknown *)&Filter3ClassFactory,
1767 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &cookie3);
1768 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1769 if (FAILED(hr)) goto out;
1771 rgf2.dwVersion = 2;
1772 rgf2.dwMerit = MERIT_UNLIKELY;
1773 S1(U(rgf2)).cPins2 = 1;
1774 S1(U(rgf2)).rgPins2 = rgPins2;
1775 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
1776 rgPins2[0].cInstances = 1;
1777 rgPins2[0].nMediaTypes = 1;
1778 rgPins2[0].lpMediaType = &rgPinType[0];
1779 rgPins2[0].nMediums = 0;
1780 rgPins2[0].lpMedium = NULL;
1781 rgPins2[0].clsPinCategory = NULL;
1782 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
1783 rgPinType[0].clsMinorType = &mediasubtype1;
1785 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
1786 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1787 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1789 rgf2.dwMerit = MERIT_PREFERRED;
1790 rgPinType[0].clsMinorType = &mediasubtype2;
1792 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
1793 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1794 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1796 S1(U(rgf2)).cPins2 = 2;
1797 rgPins2[0].dwFlags = 0;
1798 rgPinType[0].clsMinorType = &mediasubtype1;
1800 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
1801 rgPins2[1].cInstances = 1;
1802 rgPins2[1].nMediaTypes = 1;
1803 rgPins2[1].lpMediaType = &rgPinType[1];
1804 rgPins2[1].nMediums = 0;
1805 rgPins2[1].lpMedium = NULL;
1806 rgPins2[1].clsPinCategory = NULL;
1807 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
1808 rgPinType[1].clsMinorType = &mediasubtype2;
1810 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
1811 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1812 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1814 hr = IFilterGraph2_Render(pgraph2, ((TestFilterImpl*)ptestfilter)->ppPins[0]);
1815 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1817 get_connected_filter_name((TestFilterImpl*)ptestfilter, ConnectedFilterName1);
1818 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3"),
1819 "unexpected connected filter: %s\n", ConnectedFilterName1);
1821 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1822 &CLSID_TestFilter2);
1823 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1824 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1825 &CLSID_TestFilter3);
1826 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1827 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1828 &CLSID_TestFilter4);
1829 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1831 out:
1833 if (ptestfilter) IBaseFilter_Release(ptestfilter);
1834 if (ptestfilter2) IBaseFilter_Release(ptestfilter2);
1835 if (pgraph2) IFilterGraph2_Release(pgraph2);
1836 if (pMapper2) IFilterMapper2_Release(pMapper2);
1838 hr = CoRevokeClassObject(cookie1);
1839 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1840 hr = CoRevokeClassObject(cookie2);
1841 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1842 hr = CoRevokeClassObject(cookie3);
1843 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1846 START_TEST(filtergraph)
1848 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1849 test_render_run(avifileA);
1850 test_render_run(mpegfileA);
1851 test_graph_builder();
1852 test_graph_builder_addfilter();
1853 test_mediacontrol();
1854 test_filter_graph2();
1855 test_render_filter_priority();
1856 CoUninitialize();