quartz/tests: Test aggregation with CLSID_FilterGraph.
[wine.git] / dlls / quartz / tests / filtergraph.c
blobf3af03e895d7d076c9daa72f083799e0265b1823
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 #define COBJMACROS
23 #define CONST_VTABLE
25 #include "wine/test.h"
26 #include "dshow.h"
27 #include "control.h"
29 typedef struct TestFilterImpl
31 IBaseFilter IBaseFilter_iface;
33 LONG refCount;
34 CRITICAL_SECTION csFilter;
35 FILTER_STATE state;
36 FILTER_INFO filterInfo;
37 CLSID clsid;
38 IPin **ppPins;
39 UINT nPins;
40 } TestFilterImpl;
42 static const WCHAR avifile[] = {'t','e','s','t','.','a','v','i',0};
43 static const WCHAR mpegfile[] = {'t','e','s','t','.','m','p','g',0};
45 static IGraphBuilder *pgraph;
47 static int createfiltergraph(void)
49 return S_OK == CoCreateInstance(
50 &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&pgraph);
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 WCHAR *file)
146 HANDLE h;
147 HRESULT hr;
149 if (!createfiltergraph())
150 return;
152 h = CreateFileW(file, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
153 if (h != INVALID_HANDLE_VALUE) {
154 CloseHandle(h);
155 hr = IGraphBuilder_RenderFile(pgraph, file, NULL);
156 ok(hr==S_OK, "RenderFile returned: %x\n", hr);
157 rungraph();
160 releasefiltergraph();
163 static void test_graph_builder(void)
165 HRESULT hr;
166 IBaseFilter *pF = NULL;
167 IBaseFilter *pF2 = NULL;
168 IPin *pIn = NULL;
169 IEnumPins *pEnum = NULL;
170 PIN_DIRECTION dir;
171 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
172 static const WCHAR fooBarW[] = {'f','o','o','B','a','r',0};
174 if (!createfiltergraph())
175 return;
177 /* create video filter */
178 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
179 &IID_IBaseFilter, (LPVOID*)&pF);
180 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
181 ok(pF != NULL, "pF is NULL\n");
183 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
184 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned %x\n", hr);
186 /* add the two filters to the graph */
187 hr = IGraphBuilder_AddFilter(pgraph, pF, testFilterW);
188 ok(hr == S_OK, "failed to add pF to the graph: %x\n", hr);
190 /* find the pins */
191 hr = IBaseFilter_EnumPins(pF, &pEnum);
192 ok(hr == S_OK, "IBaseFilter_EnumPins failed for pF: %x\n", hr);
193 ok(pEnum != NULL, "pEnum is NULL\n");
194 hr = IEnumPins_Next(pEnum, 1, &pIn, NULL);
195 ok(hr == S_OK, "IEnumPins_Next failed for pF: %x\n", hr);
196 ok(pIn != NULL, "pIn is NULL\n");
197 hr = IPin_QueryDirection(pIn, &dir);
198 ok(hr == S_OK, "IPin_QueryDirection failed: %x\n", hr);
199 ok(dir == PINDIR_INPUT, "pin has wrong direction\n");
201 hr = IGraphBuilder_FindFilterByName(pgraph, fooBarW, &pF2);
202 ok(hr == VFW_E_NOT_FOUND, "IGraphBuilder_FindFilterByName returned %x\n", hr);
203 ok(pF2 == NULL, "IGraphBuilder_FindFilterByName returned %p\n", pF2);
204 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, &pF2);
205 ok(hr == S_OK, "IGraphBuilder_FindFilterByName returned %x\n", hr);
206 ok(pF2 != NULL, "IGraphBuilder_FindFilterByName returned NULL\n");
207 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, NULL);
208 ok(hr == E_POINTER, "IGraphBuilder_FindFilterByName returned %x\n", hr);
210 hr = IGraphBuilder_Connect(pgraph, NULL, pIn);
211 ok(hr == E_POINTER, "IGraphBuilder_Connect returned %x\n", hr);
213 hr = IGraphBuilder_Connect(pgraph, pIn, NULL);
214 ok(hr == E_POINTER, "IGraphBuilder_Connect returned %x\n", hr);
216 hr = IGraphBuilder_Connect(pgraph, pIn, pIn);
217 ok(hr == VFW_E_CANNOT_CONNECT, "IGraphBuilder_Connect returned %x\n", hr);
219 if (pIn) IPin_Release(pIn);
220 if (pEnum) IEnumPins_Release(pEnum);
221 if (pF) IBaseFilter_Release(pF);
222 if (pF2) IBaseFilter_Release(pF2);
224 releasefiltergraph();
227 static void test_graph_builder_addfilter(void)
229 HRESULT hr;
230 IBaseFilter *pF = NULL;
231 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
233 if (!createfiltergraph())
234 return;
236 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
237 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr);
239 /* create video filter */
240 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
241 &IID_IBaseFilter, (LPVOID*)&pF);
242 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
243 ok(pF != NULL, "pF is NULL\n");
244 if (!pF) {
245 skip("failed to created filter, skipping\n");
246 return;
249 hr = IGraphBuilder_AddFilter(pgraph, pF, NULL);
250 ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr);
251 IBaseFilter_Release(pF);
254 static void test_mediacontrol(void)
256 HRESULT hr;
257 LONGLONG pos = 0xdeadbeef;
258 IMediaSeeking *seeking = NULL;
259 IMediaFilter *filter = NULL;
260 IMediaControl *control = NULL;
262 IGraphBuilder_SetDefaultSyncSource(pgraph);
263 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking);
264 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
265 if (FAILED(hr))
266 return;
268 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
269 ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
270 if (FAILED(hr))
272 IMediaSeeking_Release(seeking);
273 return;
276 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
277 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
278 if (FAILED(hr))
280 IMediaSeeking_Release(seeking);
281 IMediaFilter_Release(filter);
282 return;
285 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
286 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
287 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
289 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_ReturnTime, NULL, AM_SEEKING_NoPositioning);
290 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
291 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_NoPositioning, NULL, AM_SEEKING_ReturnTime);
292 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
294 IMediaFilter_SetSyncSource(filter, NULL);
295 pos = 0xdeadbeef;
296 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
297 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
298 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
300 hr = IMediaControl_GetState(control, 1000, NULL);
301 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
303 IMediaControl_Release(control);
304 IMediaSeeking_Release(seeking);
305 IMediaFilter_Release(filter);
306 releasefiltergraph();
309 static void test_filter_graph2(void)
311 HRESULT hr;
312 IFilterGraph2 *pF = NULL;
314 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
315 &IID_IFilterGraph2, (LPVOID*)&pF);
316 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
317 ok(pF != NULL, "pF is NULL\n");
319 hr = IFilterGraph2_Release(pF);
320 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
323 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
324 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
326 if (pMediaType->pbFormat)
328 CoTaskMemFree(pMediaType->pbFormat);
329 pMediaType->pbFormat = NULL;
331 if (pMediaType->pUnk)
333 IUnknown_Release(pMediaType->pUnk);
334 pMediaType->pUnk = NULL;
338 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
340 *pDest = *pSrc;
341 if (!pSrc->pbFormat) return S_OK;
342 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
343 return E_OUTOFMEMORY;
344 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
345 if (pDest->pUnk)
346 IUnknown_AddRef(pDest->pUnk);
347 return S_OK;
350 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
352 AM_MEDIA_TYPE * pDest;
354 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
355 if (!pDest)
356 return NULL;
358 if (FAILED(CopyMediaType(pDest, pSrc)))
360 CoTaskMemFree(pDest);
361 return NULL;
364 return pDest;
367 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
369 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
370 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
373 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
375 FreeMediaType(pMediaType);
376 CoTaskMemFree(pMediaType);
379 typedef struct IEnumMediaTypesImpl
381 IEnumMediaTypes IEnumMediaTypes_iface;
382 LONG refCount;
383 AM_MEDIA_TYPE *pMediaTypes;
384 ULONG cMediaTypes;
385 ULONG uIndex;
386 } IEnumMediaTypesImpl;
388 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
390 static inline IEnumMediaTypesImpl *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
392 return CONTAINING_RECORD(iface, IEnumMediaTypesImpl, IEnumMediaTypes_iface);
395 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
397 ULONG i;
398 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
400 if (!pEnumMediaTypes)
402 *ppEnum = NULL;
403 return E_OUTOFMEMORY;
405 pEnumMediaTypes->IEnumMediaTypes_iface.lpVtbl = &IEnumMediaTypesImpl_Vtbl;
406 pEnumMediaTypes->refCount = 1;
407 pEnumMediaTypes->uIndex = 0;
408 pEnumMediaTypes->cMediaTypes = cMediaTypes;
409 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
410 for (i = 0; i < cMediaTypes; i++)
411 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
413 while (i--)
414 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
415 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
416 return E_OUTOFMEMORY;
418 *ppEnum = &pEnumMediaTypes->IEnumMediaTypes_iface;
419 return S_OK;
422 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
424 *ppv = NULL;
426 if (IsEqualIID(riid, &IID_IUnknown))
427 *ppv = iface;
428 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
429 *ppv = iface;
431 if (*ppv)
433 IUnknown_AddRef((IUnknown *)(*ppv));
434 return S_OK;
437 return E_NOINTERFACE;
440 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
442 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
443 ULONG refCount = InterlockedIncrement(&This->refCount);
445 return refCount;
448 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
450 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
451 ULONG refCount = InterlockedDecrement(&This->refCount);
453 if (!refCount)
455 int i;
456 for (i = 0; i < This->cMediaTypes; i++)
457 FreeMediaType(&This->pMediaTypes[i]);
458 CoTaskMemFree(This->pMediaTypes);
459 CoTaskMemFree(This);
461 return refCount;
464 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
466 ULONG cFetched;
467 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
469 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
471 if (cFetched > 0)
473 ULONG i;
474 for (i = 0; i < cFetched; i++)
475 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
477 while (i--)
478 DeleteMediaType(ppMediaTypes[i]);
479 *pcFetched = 0;
480 return E_OUTOFMEMORY;
484 if ((cMediaTypes != 1) || pcFetched)
485 *pcFetched = cFetched;
487 This->uIndex += cFetched;
489 if (cFetched != cMediaTypes)
490 return S_FALSE;
491 return S_OK;
494 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
496 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
498 if (This->uIndex + cMediaTypes < This->cMediaTypes)
500 This->uIndex += cMediaTypes;
501 return S_OK;
503 return S_FALSE;
506 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
508 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
510 This->uIndex = 0;
511 return S_OK;
514 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
516 HRESULT hr;
517 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
519 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
520 if (FAILED(hr))
521 return hr;
522 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
525 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
527 IEnumMediaTypesImpl_QueryInterface,
528 IEnumMediaTypesImpl_AddRef,
529 IEnumMediaTypesImpl_Release,
530 IEnumMediaTypesImpl_Next,
531 IEnumMediaTypesImpl_Skip,
532 IEnumMediaTypesImpl_Reset,
533 IEnumMediaTypesImpl_Clone
536 /* Implementation of a very stripped down pin for the test filter. Just enough
537 functionality for connecting and Render() to work. */
539 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
541 lstrcpyW(pDest->achName, pSrc->achName);
542 pDest->dir = pSrc->dir;
543 pDest->pFilter = pSrc->pFilter;
546 typedef struct ITestPinImpl
548 IPin IPin_iface;
549 LONG refCount;
550 LPCRITICAL_SECTION pCritSec;
551 PIN_INFO pinInfo;
552 IPin * pConnectedTo;
553 AM_MEDIA_TYPE mtCurrent;
554 LPVOID pUserData;
555 } ITestPinImpl;
557 static inline ITestPinImpl *impl_from_IPin(IPin *iface)
559 return CONTAINING_RECORD(iface, ITestPinImpl, IPin_iface);
562 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
564 *ppv = NULL;
566 if (IsEqualIID(riid, &IID_IUnknown))
567 *ppv = iface;
568 else if (IsEqualIID(riid, &IID_IPin))
569 *ppv = iface;
571 if (*ppv)
573 IUnknown_AddRef((IUnknown *)(*ppv));
574 return S_OK;
577 return E_NOINTERFACE;
580 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
582 ITestPinImpl *This = impl_from_IPin(iface);
583 ULONG refCount = InterlockedIncrement(&This->refCount);
584 return refCount;
587 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
589 ITestPinImpl *This = impl_from_IPin(iface);
590 ULONG refCount = InterlockedDecrement(&This->refCount);
592 if (!refCount)
594 FreeMediaType(&This->mtCurrent);
595 CoTaskMemFree(This);
596 return 0;
598 else
599 return refCount;
602 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
604 return E_UNEXPECTED;
607 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
609 ITestPinImpl *This = impl_from_IPin(iface);
610 PIN_DIRECTION pindirReceive;
611 HRESULT hr = S_OK;
613 EnterCriticalSection(This->pCritSec);
615 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
616 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
617 hr = VFW_E_TYPE_NOT_ACCEPTED;
619 if (This->pConnectedTo)
620 hr = VFW_E_ALREADY_CONNECTED;
622 if (SUCCEEDED(hr))
624 IPin_QueryDirection(pReceivePin, &pindirReceive);
626 if (pindirReceive != PINDIR_OUTPUT)
628 hr = VFW_E_INVALID_DIRECTION;
632 if (SUCCEEDED(hr))
634 CopyMediaType(&This->mtCurrent, pmt);
635 This->pConnectedTo = pReceivePin;
636 IPin_AddRef(pReceivePin);
639 LeaveCriticalSection(This->pCritSec);
641 return hr;
644 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
646 HRESULT hr;
647 ITestPinImpl *This = impl_from_IPin(iface);
649 EnterCriticalSection(This->pCritSec);
651 if (This->pConnectedTo)
653 IPin_Release(This->pConnectedTo);
654 This->pConnectedTo = NULL;
655 hr = S_OK;
657 else
658 hr = S_FALSE;
660 LeaveCriticalSection(This->pCritSec);
662 return hr;
665 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
667 HRESULT hr;
668 ITestPinImpl *This = impl_from_IPin(iface);
670 EnterCriticalSection(This->pCritSec);
672 if (This->pConnectedTo)
674 *ppPin = This->pConnectedTo;
675 IPin_AddRef(*ppPin);
676 hr = S_OK;
678 else
680 hr = VFW_E_NOT_CONNECTED;
681 *ppPin = NULL;
684 LeaveCriticalSection(This->pCritSec);
686 return hr;
689 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
691 HRESULT hr;
692 ITestPinImpl *This = impl_from_IPin(iface);
694 EnterCriticalSection(This->pCritSec);
696 if (This->pConnectedTo)
698 CopyMediaType(pmt, &This->mtCurrent);
699 hr = S_OK;
701 else
703 ZeroMemory(pmt, sizeof(*pmt));
704 hr = VFW_E_NOT_CONNECTED;
707 LeaveCriticalSection(This->pCritSec);
709 return hr;
712 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
714 ITestPinImpl *This = impl_from_IPin(iface);
716 Copy_PinInfo(pInfo, &This->pinInfo);
717 IBaseFilter_AddRef(pInfo->pFilter);
719 return S_OK;
722 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
724 ITestPinImpl *This = impl_from_IPin(iface);
726 *pPinDir = This->pinInfo.dir;
728 return S_OK;
731 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
733 return E_NOTIMPL;
736 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
738 ITestPinImpl *This = impl_from_IPin(iface);
740 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
741 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
742 return S_OK;
743 else
744 return VFW_E_TYPE_NOT_ACCEPTED;
747 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
749 ITestPinImpl *This = impl_from_IPin(iface);
751 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
754 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
756 return E_NOTIMPL;
759 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
761 return E_NOTIMPL;
764 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
766 return E_NOTIMPL;
769 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
771 return E_NOTIMPL;
774 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
776 return E_NOTIMPL;
779 static const IPinVtbl TestFilter_InputPin_Vtbl =
781 TestFilter_Pin_QueryInterface,
782 TestFilter_Pin_AddRef,
783 TestFilter_Pin_Release,
784 TestFilter_InputPin_Connect,
785 TestFilter_InputPin_ReceiveConnection,
786 TestFilter_Pin_Disconnect,
787 TestFilter_Pin_ConnectedTo,
788 TestFilter_Pin_ConnectionMediaType,
789 TestFilter_Pin_QueryPinInfo,
790 TestFilter_Pin_QueryDirection,
791 TestFilter_Pin_QueryId,
792 TestFilter_Pin_QueryAccept,
793 TestFilter_Pin_EnumMediaTypes,
794 TestFilter_Pin_QueryInternalConnections,
795 TestFilter_Pin_EndOfStream,
796 TestFilter_Pin_BeginFlush,
797 TestFilter_Pin_EndFlush,
798 TestFilter_Pin_NewSegment
801 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
803 return E_UNEXPECTED;
806 /* Private helper function */
807 static HRESULT TestFilter_OutputPin_ConnectSpecific(ITestPinImpl * This, IPin * pReceivePin,
808 const AM_MEDIA_TYPE * pmt)
810 HRESULT hr;
812 This->pConnectedTo = pReceivePin;
813 IPin_AddRef(pReceivePin);
815 hr = IPin_ReceiveConnection(pReceivePin, &This->IPin_iface, pmt);
817 if (FAILED(hr))
819 IPin_Release(This->pConnectedTo);
820 This->pConnectedTo = NULL;
823 return hr;
826 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
828 ITestPinImpl *This = impl_from_IPin(iface);
829 HRESULT hr;
831 EnterCriticalSection(This->pCritSec);
833 /* if we have been a specific type to connect with, then we can either connect
834 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
835 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
836 hr = TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, pmt);
837 else
839 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
840 (TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, &This->mtCurrent) == S_OK))
841 hr = S_OK;
842 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
843 } /* if negotiate media type */
844 } /* if succeeded */
845 LeaveCriticalSection(This->pCritSec);
847 return hr;
850 static const IPinVtbl TestFilter_OutputPin_Vtbl =
852 TestFilter_Pin_QueryInterface,
853 TestFilter_Pin_AddRef,
854 TestFilter_Pin_Release,
855 TestFilter_OutputPin_Connect,
856 TestFilter_OutputPin_ReceiveConnection,
857 TestFilter_Pin_Disconnect,
858 TestFilter_Pin_ConnectedTo,
859 TestFilter_Pin_ConnectionMediaType,
860 TestFilter_Pin_QueryPinInfo,
861 TestFilter_Pin_QueryDirection,
862 TestFilter_Pin_QueryId,
863 TestFilter_Pin_QueryAccept,
864 TestFilter_Pin_EnumMediaTypes,
865 TestFilter_Pin_QueryInternalConnections,
866 TestFilter_Pin_EndOfStream,
867 TestFilter_Pin_BeginFlush,
868 TestFilter_Pin_EndFlush,
869 TestFilter_Pin_NewSegment
872 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
873 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
875 ITestPinImpl * pPinImpl;
877 *ppPin = NULL;
879 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
881 if (!pPinImpl)
882 return E_OUTOFMEMORY;
884 pPinImpl->refCount = 1;
885 pPinImpl->pConnectedTo = NULL;
886 pPinImpl->pCritSec = pCritSec;
887 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
888 pPinImpl->mtCurrent = *pinmt;
890 pPinImpl->IPin_iface.lpVtbl = Pin_Vtbl;
892 *ppPin = &pPinImpl->IPin_iface;
893 return S_OK;
896 /* IEnumPins implementation */
898 typedef HRESULT (* FNOBTAINPIN)(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick);
900 typedef struct IEnumPinsImpl
902 IEnumPins IEnumPins_iface;
903 LONG refCount;
904 ULONG uIndex;
905 TestFilterImpl *base;
906 FNOBTAINPIN receive_pin;
907 DWORD synctime;
908 } IEnumPinsImpl;
910 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
912 static inline IEnumPinsImpl *impl_from_IEnumPins(IEnumPins *iface)
914 return CONTAINING_RECORD(iface, IEnumPinsImpl, IEnumPins_iface);
917 static HRESULT createenumpins(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, TestFilterImpl *base)
919 IEnumPinsImpl * pEnumPins;
921 if (!ppEnum)
922 return E_POINTER;
924 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
925 if (!pEnumPins)
927 *ppEnum = NULL;
928 return E_OUTOFMEMORY;
930 pEnumPins->IEnumPins_iface.lpVtbl = &IEnumPinsImpl_Vtbl;
931 pEnumPins->refCount = 1;
932 pEnumPins->uIndex = 0;
933 pEnumPins->receive_pin = receive_pin;
934 pEnumPins->base = base;
935 IBaseFilter_AddRef(&base->IBaseFilter_iface);
936 *ppEnum = &pEnumPins->IEnumPins_iface;
938 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
940 return S_OK;
943 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
945 *ppv = NULL;
947 if (IsEqualIID(riid, &IID_IUnknown))
948 *ppv = iface;
949 else if (IsEqualIID(riid, &IID_IEnumPins))
950 *ppv = iface;
952 if (*ppv)
954 IUnknown_AddRef((IUnknown *)(*ppv));
955 return S_OK;
958 return E_NOINTERFACE;
961 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
963 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
964 ULONG refCount = InterlockedIncrement(&This->refCount);
966 return refCount;
969 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
971 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
972 ULONG refCount = InterlockedDecrement(&This->refCount);
974 if (!refCount)
976 IBaseFilter_Release(&This->base->IBaseFilter_iface);
977 CoTaskMemFree(This);
978 return 0;
980 else
981 return refCount;
984 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
986 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
987 DWORD synctime = This->synctime;
988 HRESULT hr = S_OK;
989 ULONG i = 0;
991 if (!ppPins)
992 return E_POINTER;
994 if (cPins > 1 && !pcFetched)
995 return E_INVALIDARG;
997 if (pcFetched)
998 *pcFetched = 0;
1000 while (i < cPins && hr == S_OK)
1002 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
1004 if (hr == S_OK)
1005 ++i;
1007 if (synctime != This->synctime)
1008 break;
1011 if (!i && synctime != This->synctime)
1012 return VFW_E_ENUM_OUT_OF_SYNC;
1014 if (pcFetched)
1015 *pcFetched = i;
1016 This->uIndex += i;
1018 if (i < cPins)
1019 return S_FALSE;
1020 return S_OK;
1023 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
1025 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1026 DWORD synctime = This->synctime;
1027 HRESULT hr;
1028 IPin *pin = NULL;
1030 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
1031 if (pin)
1032 IPin_Release(pin);
1034 if (synctime != This->synctime)
1035 return VFW_E_ENUM_OUT_OF_SYNC;
1037 if (hr == S_OK)
1038 This->uIndex += cPins;
1040 return hr;
1043 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1045 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1047 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1049 This->uIndex = 0;
1050 return S_OK;
1053 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1055 HRESULT hr;
1056 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1058 hr = createenumpins(ppEnum, This->receive_pin, This->base);
1059 if (FAILED(hr))
1060 return hr;
1061 return IEnumPins_Skip(*ppEnum, This->uIndex);
1064 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1066 IEnumPinsImpl_QueryInterface,
1067 IEnumPinsImpl_AddRef,
1068 IEnumPinsImpl_Release,
1069 IEnumPinsImpl_Next,
1070 IEnumPinsImpl_Skip,
1071 IEnumPinsImpl_Reset,
1072 IEnumPinsImpl_Clone
1075 /* Test filter implementation - a filter that has few predefined pins with single media type
1076 * that accept only this single media type. Enough for Render(). */
1078 typedef struct TestFilterPinData
1080 PIN_DIRECTION pinDir;
1081 const GUID *mediasubtype;
1082 } TestFilterPinData;
1084 static const IBaseFilterVtbl TestFilter_Vtbl;
1086 static inline TestFilterImpl *impl_from_IBaseFilter(IBaseFilter *iface)
1088 return CONTAINING_RECORD(iface, TestFilterImpl, IBaseFilter_iface);
1091 static HRESULT createtestfilter(const CLSID* pClsid, const TestFilterPinData *pinData,
1092 TestFilterImpl **tf)
1094 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1095 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1096 HRESULT hr;
1097 PIN_INFO pinInfo;
1098 TestFilterImpl* pTestFilter = NULL;
1099 UINT nPins, i;
1100 AM_MEDIA_TYPE mt;
1102 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1103 if (!pTestFilter) return E_OUTOFMEMORY;
1105 pTestFilter->clsid = *pClsid;
1106 pTestFilter->IBaseFilter_iface.lpVtbl = &TestFilter_Vtbl;
1107 pTestFilter->refCount = 1;
1108 InitializeCriticalSection(&pTestFilter->csFilter);
1109 pTestFilter->state = State_Stopped;
1111 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1113 nPins = 0;
1114 while(pinData[nPins].mediasubtype) ++nPins;
1116 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1117 if (!pTestFilter->ppPins)
1119 hr = E_OUTOFMEMORY;
1120 goto error;
1122 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1124 for (i = 0; i < nPins; i++)
1126 ZeroMemory(&mt, sizeof(mt));
1127 mt.majortype = MEDIATYPE_Video;
1128 mt.formattype = FORMAT_None;
1129 mt.subtype = *pinData[i].mediasubtype;
1131 pinInfo.dir = pinData[i].pinDir;
1132 pinInfo.pFilter = &pTestFilter->IBaseFilter_iface;
1133 if (pinInfo.dir == PINDIR_INPUT)
1135 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1136 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1137 &pTestFilter->ppPins[i]);
1140 else
1142 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1143 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1144 &pTestFilter->ppPins[i]);
1146 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1149 pTestFilter->nPins = nPins;
1150 *tf = pTestFilter;
1151 return S_OK;
1153 error:
1155 if (pTestFilter->ppPins)
1157 for (i = 0; i < nPins; i++)
1159 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1162 CoTaskMemFree(pTestFilter->ppPins);
1163 DeleteCriticalSection(&pTestFilter->csFilter);
1164 CoTaskMemFree(pTestFilter);
1166 return hr;
1169 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1171 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1173 *ppv = NULL;
1175 if (IsEqualIID(riid, &IID_IUnknown))
1176 *ppv = This;
1177 else if (IsEqualIID(riid, &IID_IPersist))
1178 *ppv = This;
1179 else if (IsEqualIID(riid, &IID_IMediaFilter))
1180 *ppv = This;
1181 else if (IsEqualIID(riid, &IID_IBaseFilter))
1182 *ppv = This;
1184 if (*ppv)
1186 IUnknown_AddRef((IUnknown *)(*ppv));
1187 return S_OK;
1190 return E_NOINTERFACE;
1193 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1195 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1196 ULONG refCount = InterlockedIncrement(&This->refCount);
1198 return refCount;
1201 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1203 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1204 ULONG refCount = InterlockedDecrement(&This->refCount);
1206 if (!refCount)
1208 ULONG i;
1210 for (i = 0; i < This->nPins; i++)
1212 IPin *pConnectedTo;
1214 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1216 IPin_Disconnect(pConnectedTo);
1217 IPin_Release(pConnectedTo);
1219 IPin_Disconnect(This->ppPins[i]);
1221 IPin_Release(This->ppPins[i]);
1224 CoTaskMemFree(This->ppPins);
1226 DeleteCriticalSection(&This->csFilter);
1228 CoTaskMemFree(This);
1230 return 0;
1232 else
1233 return refCount;
1235 /** IPersist methods **/
1237 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1239 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1241 *pClsid = This->clsid;
1243 return S_OK;
1246 /** IMediaFilter methods **/
1248 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1250 return E_NOTIMPL;
1253 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1255 return E_NOTIMPL;
1258 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1260 return E_NOTIMPL;
1263 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1265 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1267 EnterCriticalSection(&This->csFilter);
1269 *pState = This->state;
1271 LeaveCriticalSection(&This->csFilter);
1273 return S_OK;
1276 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1278 return E_NOTIMPL;
1281 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1283 return E_NOTIMPL;
1286 /** IBaseFilter implementation **/
1288 static HRESULT getpin_callback(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick)
1290 /* Our pins are static, not changing so setting static tick count is ok */
1291 *lastsynctick = 0;
1293 if (pos >= tf->nPins)
1294 return S_FALSE;
1296 *pin = tf->ppPins[pos];
1297 IPin_AddRef(*pin);
1298 return S_OK;
1301 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1303 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1305 return createenumpins(ppEnum, getpin_callback, This);
1308 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1310 return E_NOTIMPL;
1313 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1315 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1317 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1318 pInfo->pGraph = This->filterInfo.pGraph;
1320 if (pInfo->pGraph)
1321 IFilterGraph_AddRef(pInfo->pGraph);
1323 return S_OK;
1326 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1328 HRESULT hr = S_OK;
1329 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1331 EnterCriticalSection(&This->csFilter);
1333 if (pName)
1334 lstrcpyW(This->filterInfo.achName, pName);
1335 else
1336 *This->filterInfo.achName = '\0';
1337 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1339 LeaveCriticalSection(&This->csFilter);
1341 return hr;
1344 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1346 return E_NOTIMPL;
1349 static const IBaseFilterVtbl TestFilter_Vtbl =
1351 TestFilter_QueryInterface,
1352 TestFilter_AddRef,
1353 TestFilter_Release,
1354 TestFilter_GetClassID,
1355 TestFilter_Stop,
1356 TestFilter_Pause,
1357 TestFilter_Run,
1358 TestFilter_GetState,
1359 TestFilter_SetSyncSource,
1360 TestFilter_GetSyncSource,
1361 TestFilter_EnumPins,
1362 TestFilter_FindPin,
1363 TestFilter_QueryFilterInfo,
1364 TestFilter_JoinFilterGraph,
1365 TestFilter_QueryVendorInfo
1368 /* IClassFactory implementation */
1370 typedef struct TestClassFactoryImpl
1372 IClassFactory IClassFactory_iface;
1373 const TestFilterPinData *filterPinData;
1374 const CLSID *clsid;
1375 } TestClassFactoryImpl;
1377 static inline TestClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
1379 return CONTAINING_RECORD(iface, TestClassFactoryImpl, IClassFactory_iface);
1382 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1383 LPCLASSFACTORY iface,
1384 REFIID riid,
1385 LPVOID *ppvObj)
1387 if (ppvObj == NULL) return E_POINTER;
1389 if (IsEqualGUID(riid, &IID_IUnknown) ||
1390 IsEqualGUID(riid, &IID_IClassFactory))
1392 *ppvObj = iface;
1393 IClassFactory_AddRef(iface);
1394 return S_OK;
1397 *ppvObj = NULL;
1398 return E_NOINTERFACE;
1401 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1403 return 2; /* non-heap-based object */
1406 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1408 return 1; /* non-heap-based object */
1411 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1412 LPCLASSFACTORY iface,
1413 LPUNKNOWN pUnkOuter,
1414 REFIID riid,
1415 LPVOID *ppvObj)
1417 TestClassFactoryImpl *This = impl_from_IClassFactory(iface);
1418 HRESULT hr;
1419 TestFilterImpl *testfilter;
1421 *ppvObj = NULL;
1423 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1425 hr = createtestfilter(This->clsid, This->filterPinData, &testfilter);
1426 if (SUCCEEDED(hr)) {
1427 hr = IBaseFilter_QueryInterface(&testfilter->IBaseFilter_iface, riid, ppvObj);
1428 IBaseFilter_Release(&testfilter->IBaseFilter_iface);
1430 return hr;
1433 static HRESULT WINAPI Test_IClassFactory_LockServer(
1434 LPCLASSFACTORY iface,
1435 BOOL fLock)
1437 return S_OK;
1440 static IClassFactoryVtbl TestClassFactory_Vtbl =
1442 Test_IClassFactory_QueryInterface,
1443 Test_IClassFactory_AddRef,
1444 Test_IClassFactory_Release,
1445 Test_IClassFactory_CreateInstance,
1446 Test_IClassFactory_LockServer
1449 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1451 IPin *pin = NULL;
1452 PIN_INFO pinInfo;
1453 FILTER_INFO filterInfo;
1454 HRESULT hr;
1456 FilterName[0] = 0;
1458 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1459 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1460 if (FAILED(hr)) return hr;
1462 hr = IPin_QueryPinInfo(pin, &pinInfo);
1463 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1464 IPin_Release(pin);
1465 if (FAILED(hr)) return hr;
1467 SetLastError(0xdeadbeef);
1468 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1469 if (hr == S_OK && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1471 IBaseFilter_Release(pinInfo.pFilter);
1472 return E_NOTIMPL;
1474 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1475 IBaseFilter_Release(pinInfo.pFilter);
1476 if (FAILED(hr)) return hr;
1478 IFilterGraph_Release(filterInfo.pGraph);
1480 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1482 return S_OK;
1485 static void test_render_filter_priority(void)
1487 /* Tests filter choice priorities in Render(). */
1488 DWORD cookie1 = 0, cookie2 = 0, cookie3 = 0;
1489 HRESULT hr;
1490 IFilterGraph2* pgraph2 = NULL;
1491 IFilterMapper2 *pMapper2 = NULL;
1492 TestFilterImpl *ptestfilter = NULL;
1493 TestFilterImpl *ptestfilter2 = NULL;
1494 static const CLSID CLSID_TestFilter2 = {
1495 0x37a4edb0,
1496 0x4d13,
1497 0x11dd,
1498 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1500 static const CLSID CLSID_TestFilter3 = {
1501 0x37a4f2d8,
1502 0x4d13,
1503 0x11dd,
1504 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1506 static const CLSID CLSID_TestFilter4 = {
1507 0x37a4f3b4,
1508 0x4d13,
1509 0x11dd,
1510 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1512 static const GUID mediasubtype1 = {
1513 0x37a4f51c,
1514 0x4d13,
1515 0x11dd,
1516 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1518 static const GUID mediasubtype2 = {
1519 0x37a4f5c6,
1520 0x4d13,
1521 0x11dd,
1522 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1524 static const TestFilterPinData PinData1[] = {
1525 { PINDIR_OUTPUT, &mediasubtype1 },
1526 { 0, 0 }
1528 static const TestFilterPinData PinData2[] = {
1529 { PINDIR_INPUT, &mediasubtype1 },
1530 { 0, 0 }
1532 static const TestFilterPinData PinData3[] = {
1533 { PINDIR_INPUT, &GUID_NULL },
1534 { 0, 0 }
1536 static const TestFilterPinData PinData4[] = {
1537 { PINDIR_INPUT, &mediasubtype1 },
1538 { PINDIR_OUTPUT, &mediasubtype2 },
1539 { 0, 0 }
1541 static const TestFilterPinData PinData5[] = {
1542 { PINDIR_INPUT, &mediasubtype2 },
1543 { 0, 0 }
1545 TestClassFactoryImpl Filter1ClassFactory = {
1546 { &TestClassFactory_Vtbl },
1547 PinData2, &CLSID_TestFilter2
1549 TestClassFactoryImpl Filter2ClassFactory = {
1550 { &TestClassFactory_Vtbl },
1551 PinData4, &CLSID_TestFilter3
1553 TestClassFactoryImpl Filter3ClassFactory = {
1554 { &TestClassFactory_Vtbl },
1555 PinData5, &CLSID_TestFilter4
1557 char ConnectedFilterName1[MAX_FILTER_NAME];
1558 char ConnectedFilterName2[MAX_FILTER_NAME];
1559 REGFILTER2 rgf2;
1560 REGFILTERPINS2 rgPins2[2];
1561 REGPINTYPES rgPinType[2];
1562 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1563 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1564 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1565 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1566 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1567 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1568 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1569 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1571 /* Test which renderer of two already added to the graph will be chosen
1572 * (one is "exact" match, other is "wildcard" match. Seems to depend
1573 * on the order in which filters are added to the graph, thus indicating
1574 * no preference given to exact match. */
1575 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1576 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1577 if (!pgraph2) return;
1579 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1580 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1581 if (FAILED(hr)) goto out;
1583 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1584 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1586 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1587 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1588 if (FAILED(hr)) goto out;
1590 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1591 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1593 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1594 ptestfilter2 = NULL;
1596 hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1597 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1598 if (FAILED(hr)) goto out;
1600 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1601 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1603 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1604 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1606 hr = get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1608 IFilterGraph2_Release(pgraph2);
1609 pgraph2 = NULL;
1610 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1611 ptestfilter = NULL;
1612 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1613 ptestfilter2 = NULL;
1615 if (hr == E_NOTIMPL)
1617 win_skip("Needed functions are not implemented\n");
1618 return;
1621 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1622 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1623 if (!pgraph2) goto out;
1625 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1626 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1627 if (FAILED(hr)) goto out;
1629 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1630 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1632 hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1633 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1634 if (FAILED(hr)) goto out;
1636 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1637 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1639 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1640 ptestfilter2 = NULL;
1642 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1643 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1644 if (FAILED(hr)) goto out;
1646 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1647 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1649 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1650 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1652 hr = IFilterGraph2_Disconnect(pgraph2, NULL);
1653 ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr);
1655 get_connected_filter_name(ptestfilter, ConnectedFilterName2);
1656 ok(strcmp(ConnectedFilterName1, ConnectedFilterName2),
1657 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1659 IFilterGraph2_Release(pgraph2);
1660 pgraph2 = NULL;
1661 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1662 ptestfilter = NULL;
1663 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1664 ptestfilter2 = NULL;
1666 /* Test if any preference is given to existing renderer which renders the pin directly vs
1667 an existing renderer which renders the pin indirectly, through an additional middle filter,
1668 again trying different orders of creation. Native appears not to give a preference. */
1670 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1671 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1672 if (!pgraph2) goto out;
1674 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1675 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1676 if (FAILED(hr)) goto out;
1678 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1679 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1681 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1682 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1683 if (FAILED(hr)) goto out;
1685 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1686 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1688 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1689 ptestfilter2 = NULL;
1691 hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
1692 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1693 if (FAILED(hr)) goto out;
1695 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1696 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1698 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1699 ptestfilter2 = NULL;
1701 hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2);
1702 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1703 if (FAILED(hr)) goto out;
1705 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4);
1706 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1708 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1709 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1711 get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1712 ok(!strcmp(ConnectedFilterName1, "TestfilterInstance3") || !strcmp(ConnectedFilterName1, "TestfilterInstance2"),
1713 "unexpected connected filter: %s\n", ConnectedFilterName1);
1715 IFilterGraph2_Release(pgraph2);
1716 pgraph2 = NULL;
1717 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1718 ptestfilter = NULL;
1719 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1720 ptestfilter2 = NULL;
1722 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1723 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1724 if (!pgraph2) goto out;
1726 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1727 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1728 if (FAILED(hr)) goto out;
1730 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1731 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1733 hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
1734 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1735 if (FAILED(hr)) goto out;
1737 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1738 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1740 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1741 ptestfilter2 = NULL;
1743 hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2);
1744 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1745 if (FAILED(hr)) goto out;
1747 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4);
1748 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1750 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1751 ptestfilter2 = NULL;
1753 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1754 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1755 if (FAILED(hr)) goto out;
1757 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1758 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1760 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1761 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1763 get_connected_filter_name(ptestfilter, ConnectedFilterName2);
1764 ok(!strcmp(ConnectedFilterName2, "TestfilterInstance3") || !strcmp(ConnectedFilterName2, "TestfilterInstance2"),
1765 "unexpected connected filter: %s\n", ConnectedFilterName2);
1766 ok(strcmp(ConnectedFilterName1, ConnectedFilterName2),
1767 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1769 IFilterGraph2_Release(pgraph2);
1770 pgraph2 = NULL;
1771 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1772 ptestfilter = NULL;
1773 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1774 ptestfilter2 = NULL;
1776 /* Test if renderers are tried before non-renderers (intermediary filters). */
1777 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1778 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1779 if (!pgraph2) goto out;
1781 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
1782 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1783 if (!pMapper2) goto out;
1785 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1786 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1787 if (FAILED(hr)) goto out;
1789 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1790 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1792 /* Register our filters with COM and with Filtermapper. */
1793 hr = CoRegisterClassObject(Filter1ClassFactory.clsid,
1794 (IUnknown *)&Filter1ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1795 REGCLS_MULTIPLEUSE, &cookie1);
1796 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1797 if (FAILED(hr)) goto out;
1798 hr = CoRegisterClassObject(Filter2ClassFactory.clsid,
1799 (IUnknown *)&Filter2ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1800 REGCLS_MULTIPLEUSE, &cookie2);
1801 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1802 if (FAILED(hr)) goto out;
1803 hr = CoRegisterClassObject(Filter3ClassFactory.clsid,
1804 (IUnknown *)&Filter3ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1805 REGCLS_MULTIPLEUSE, &cookie3);
1806 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1807 if (FAILED(hr)) goto out;
1809 rgf2.dwVersion = 2;
1810 rgf2.dwMerit = MERIT_UNLIKELY;
1811 S2(U(rgf2)).cPins2 = 1;
1812 S2(U(rgf2)).rgPins2 = rgPins2;
1813 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
1814 rgPins2[0].cInstances = 1;
1815 rgPins2[0].nMediaTypes = 1;
1816 rgPins2[0].lpMediaType = &rgPinType[0];
1817 rgPins2[0].nMediums = 0;
1818 rgPins2[0].lpMedium = NULL;
1819 rgPins2[0].clsPinCategory = NULL;
1820 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
1821 rgPinType[0].clsMinorType = &mediasubtype1;
1823 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
1824 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1825 if (hr == E_ACCESSDENIED)
1826 skip("Not authorized to register filters\n");
1827 else
1829 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1831 rgf2.dwMerit = MERIT_PREFERRED;
1832 rgPinType[0].clsMinorType = &mediasubtype2;
1834 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
1835 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1836 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1838 S2(U(rgf2)).cPins2 = 2;
1839 rgPins2[0].dwFlags = 0;
1840 rgPinType[0].clsMinorType = &mediasubtype1;
1842 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
1843 rgPins2[1].cInstances = 1;
1844 rgPins2[1].nMediaTypes = 1;
1845 rgPins2[1].lpMediaType = &rgPinType[1];
1846 rgPins2[1].nMediums = 0;
1847 rgPins2[1].lpMedium = NULL;
1848 rgPins2[1].clsPinCategory = NULL;
1849 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
1850 rgPinType[1].clsMinorType = &mediasubtype2;
1852 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
1853 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1854 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1856 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1857 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1859 get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1860 ok(!strcmp(ConnectedFilterName1, "TestfilterInstance3"),
1861 "unexpected connected filter: %s\n", ConnectedFilterName1);
1863 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1864 &CLSID_TestFilter2);
1865 ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1866 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1867 &CLSID_TestFilter3);
1868 ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1869 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1870 &CLSID_TestFilter4);
1871 ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1874 out:
1876 if (ptestfilter) IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1877 if (ptestfilter2) IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1878 if (pgraph2) IFilterGraph2_Release(pgraph2);
1879 if (pMapper2) IFilterMapper2_Release(pMapper2);
1881 hr = CoRevokeClassObject(cookie1);
1882 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1883 hr = CoRevokeClassObject(cookie2);
1884 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1885 hr = CoRevokeClassObject(cookie3);
1886 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1889 typedef struct IUnknownImpl
1891 IUnknown IUnknown_iface;
1892 int AddRef_called;
1893 int Release_called;
1894 } IUnknownImpl;
1896 static IUnknownImpl *IUnknownImpl_from_iface(IUnknown * iface)
1898 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
1901 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
1903 ok(0, "QueryInterface should not be called for %s\n", wine_dbgstr_guid(riid));
1904 return E_NOINTERFACE;
1907 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown * iface)
1909 IUnknownImpl *This = IUnknownImpl_from_iface(iface);
1910 This->AddRef_called++;
1911 return 2;
1914 static ULONG WINAPI IUnknownImpl_Release(IUnknown * iface)
1916 IUnknownImpl *This = IUnknownImpl_from_iface(iface);
1917 This->Release_called++;
1918 return 1;
1921 static CONST_VTBL IUnknownVtbl IUnknownImpl_Vtbl =
1923 IUnknownImpl_QueryInterface,
1924 IUnknownImpl_AddRef,
1925 IUnknownImpl_Release
1928 static void test_aggregate_filter_graph(void)
1930 HRESULT hr;
1931 IUnknown *pgraph;
1932 IUnknown *punk;
1933 IUnknownImpl unk_outer = { { &IUnknownImpl_Vtbl }, 0, 0 };
1935 hr = CoCreateInstance(&CLSID_FilterGraph, &unk_outer.IUnknown_iface, CLSCTX_INPROC_SERVER,
1936 &IID_IUnknown, (void **)&pgraph);
1937 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
1938 ok(pgraph != &unk_outer.IUnknown_iface, "pgraph = %p, expected not %p\n", pgraph, &unk_outer.IUnknown_iface);
1940 hr = IUnknown_QueryInterface(pgraph, &IID_IUnknown, (void **)&punk);
1941 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
1942 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
1943 IUnknown_Release(punk);
1945 todo_wine
1946 ok(unk_outer.AddRef_called == 0, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
1947 todo_wine
1948 ok(unk_outer.Release_called == 0, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
1949 unk_outer.AddRef_called = 0;
1950 unk_outer.Release_called = 0;
1952 hr = IUnknown_QueryInterface(pgraph, &IID_IFilterMapper, (void **)&punk);
1953 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
1954 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
1955 IUnknown_Release(punk);
1957 ok(unk_outer.AddRef_called == 1, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
1958 ok(unk_outer.Release_called == 1, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
1959 unk_outer.AddRef_called = 0;
1960 unk_outer.Release_called = 0;
1962 hr = IUnknown_QueryInterface(pgraph, &IID_IFilterMapper2, (void **)&punk);
1963 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
1964 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
1965 IUnknown_Release(punk);
1967 ok(unk_outer.AddRef_called == 1, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
1968 ok(unk_outer.Release_called == 1, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
1969 unk_outer.AddRef_called = 0;
1970 unk_outer.Release_called = 0;
1972 hr = IUnknown_QueryInterface(pgraph, &IID_IFilterMapper3, (void **)&punk);
1973 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
1974 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
1975 IUnknown_Release(punk);
1977 ok(unk_outer.AddRef_called == 1, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
1978 ok(unk_outer.Release_called == 1, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
1980 IUnknown_Release(pgraph);
1983 START_TEST(filtergraph)
1985 HRESULT hr;
1986 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1987 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
1988 &IID_IGraphBuilder, (LPVOID*)&pgraph);
1989 if (FAILED(hr)) {
1990 skip("Creating filtergraph returned %08x, skipping tests\n", hr);
1991 return;
1993 IGraphBuilder_Release(pgraph);
1994 test_render_run(avifile);
1995 test_render_run(mpegfile);
1996 test_graph_builder();
1997 test_graph_builder_addfilter();
1998 test_mediacontrol();
1999 test_filter_graph2();
2000 test_render_filter_priority();
2001 test_aggregate_filter_graph();
2002 CoUninitialize();