vbscript: 'property' may be both keyword and identifier.
[wine/multimedia.git] / dlls / quartz / tests / filtergraph.c
blob967a4ac2f9ae01837aeba4233722cd3749a71ae7
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 /* add the two filters to the graph */
184 hr = IGraphBuilder_AddFilter(pgraph, pF, testFilterW);
185 ok(hr == S_OK, "failed to add pF to the graph: %x\n", hr);
187 /* find the pins */
188 hr = IBaseFilter_EnumPins(pF, &pEnum);
189 ok(hr == S_OK, "IBaseFilter_EnumPins failed for pF: %x\n", hr);
190 ok(pEnum != NULL, "pEnum is NULL\n");
191 hr = IEnumPins_Next(pEnum, 1, &pIn, NULL);
192 ok(hr == S_OK, "IEnumPins_Next failed for pF: %x\n", hr);
193 ok(pIn != NULL, "pIn is NULL\n");
194 hr = IPin_QueryDirection(pIn, &dir);
195 ok(hr == S_OK, "IPin_QueryDirection failed: %x\n", hr);
196 ok(dir == PINDIR_INPUT, "pin has wrong direction\n");
198 hr = IGraphBuilder_FindFilterByName(pgraph, fooBarW, &pF2);
199 ok(hr == VFW_E_NOT_FOUND, "IGraphBuilder_FindFilterByName returned %x\n", hr);
200 ok(pF2 == NULL, "IGraphBuilder_FindFilterByName returned %p\n", pF2);
201 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, &pF2);
202 ok(hr == S_OK, "IGraphBuilder_FindFilterByName returned %x\n", hr);
203 ok(pF2 != NULL, "IGraphBuilder_FindFilterByName returned NULL\n");
204 hr = IGraphBuilder_FindFilterByName(pgraph, testFilterW, NULL);
205 ok(hr == E_POINTER, "IGraphBuilder_FindFilterByName returned %x\n", hr);
207 if (pIn) IPin_Release(pIn);
208 if (pEnum) IEnumPins_Release(pEnum);
209 if (pF) IBaseFilter_Release(pF);
210 if (pF2) IBaseFilter_Release(pF2);
212 releasefiltergraph();
215 static void test_graph_builder_addfilter(void)
217 HRESULT hr;
218 IBaseFilter *pF = NULL;
219 static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
221 if (!createfiltergraph())
222 return;
224 hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
225 ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr);
227 /* create video filter */
228 hr = CoCreateInstance(&CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER,
229 &IID_IBaseFilter, (LPVOID*)&pF);
230 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
231 ok(pF != NULL, "pF is NULL\n");
232 if (!pF) {
233 skip("failed to created filter, skipping\n");
234 return;
237 hr = IGraphBuilder_AddFilter(pgraph, pF, NULL);
238 ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr);
239 IMediaFilter_Release(pF);
242 static void test_mediacontrol(void)
244 HRESULT hr;
245 LONGLONG pos = 0xdeadbeef;
246 IMediaSeeking *seeking = NULL;
247 IMediaFilter *filter = NULL;
248 IMediaControl *control = NULL;
250 IFilterGraph2_SetDefaultSyncSource(pgraph);
251 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking);
252 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
253 if (FAILED(hr))
254 return;
256 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
257 ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
258 if (FAILED(hr))
260 IUnknown_Release(seeking);
261 return;
264 hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
265 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
266 if (FAILED(hr))
268 IUnknown_Release(seeking);
269 IUnknown_Release(filter);
270 return;
273 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
274 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
275 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
277 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_ReturnTime, NULL, AM_SEEKING_NoPositioning);
278 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
279 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_NoPositioning, NULL, AM_SEEKING_ReturnTime);
280 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
282 IMediaFilter_SetSyncSource(filter, NULL);
283 pos = 0xdeadbeef;
284 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
285 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
286 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
288 hr = IMediaControl_GetState(control, 1000, NULL);
289 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
291 IUnknown_Release(control);
292 IUnknown_Release(seeking);
293 IUnknown_Release(filter);
294 releasefiltergraph();
297 static void test_filter_graph2(void)
299 HRESULT hr;
300 IFilterGraph2 *pF = NULL;
302 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
303 &IID_IFilterGraph2, (LPVOID*)&pF);
304 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
305 ok(pF != NULL, "pF is NULL\n");
307 hr = IFilterGraph2_Release(pF);
308 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
311 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
312 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
314 if (pMediaType->pbFormat)
316 CoTaskMemFree(pMediaType->pbFormat);
317 pMediaType->pbFormat = NULL;
319 if (pMediaType->pUnk)
321 IUnknown_Release(pMediaType->pUnk);
322 pMediaType->pUnk = NULL;
326 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
328 *pDest = *pSrc;
329 if (!pSrc->pbFormat) return S_OK;
330 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
331 return E_OUTOFMEMORY;
332 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
333 if (pDest->pUnk)
334 IUnknown_AddRef(pDest->pUnk);
335 return S_OK;
338 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
340 AM_MEDIA_TYPE * pDest;
342 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
343 if (!pDest)
344 return NULL;
346 if (FAILED(CopyMediaType(pDest, pSrc)))
348 CoTaskMemFree(pDest);
349 return NULL;
352 return pDest;
355 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
357 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
358 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
361 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
363 FreeMediaType(pMediaType);
364 CoTaskMemFree(pMediaType);
367 typedef struct IEnumMediaTypesImpl
369 IEnumMediaTypes IEnumMediaTypes_iface;
370 LONG refCount;
371 AM_MEDIA_TYPE *pMediaTypes;
372 ULONG cMediaTypes;
373 ULONG uIndex;
374 } IEnumMediaTypesImpl;
376 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
378 static inline IEnumMediaTypesImpl *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
380 return CONTAINING_RECORD(iface, IEnumMediaTypesImpl, IEnumMediaTypes_iface);
383 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
385 ULONG i;
386 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
388 if (!pEnumMediaTypes)
390 *ppEnum = NULL;
391 return E_OUTOFMEMORY;
393 pEnumMediaTypes->IEnumMediaTypes_iface.lpVtbl = &IEnumMediaTypesImpl_Vtbl;
394 pEnumMediaTypes->refCount = 1;
395 pEnumMediaTypes->uIndex = 0;
396 pEnumMediaTypes->cMediaTypes = cMediaTypes;
397 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
398 for (i = 0; i < cMediaTypes; i++)
399 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
401 while (i--)
402 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
403 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
404 return E_OUTOFMEMORY;
406 *ppEnum = &pEnumMediaTypes->IEnumMediaTypes_iface;
407 return S_OK;
410 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
412 *ppv = NULL;
414 if (IsEqualIID(riid, &IID_IUnknown))
415 *ppv = iface;
416 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
417 *ppv = iface;
419 if (*ppv)
421 IUnknown_AddRef((IUnknown *)(*ppv));
422 return S_OK;
425 return E_NOINTERFACE;
428 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
430 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
431 ULONG refCount = InterlockedIncrement(&This->refCount);
433 return refCount;
436 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
438 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
439 ULONG refCount = InterlockedDecrement(&This->refCount);
441 if (!refCount)
443 int i;
444 for (i = 0; i < This->cMediaTypes; i++)
445 FreeMediaType(&This->pMediaTypes[i]);
446 CoTaskMemFree(This->pMediaTypes);
447 CoTaskMemFree(This);
449 return refCount;
452 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
454 ULONG cFetched;
455 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
457 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
459 if (cFetched > 0)
461 ULONG i;
462 for (i = 0; i < cFetched; i++)
463 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
465 while (i--)
466 DeleteMediaType(ppMediaTypes[i]);
467 *pcFetched = 0;
468 return E_OUTOFMEMORY;
472 if ((cMediaTypes != 1) || pcFetched)
473 *pcFetched = cFetched;
475 This->uIndex += cFetched;
477 if (cFetched != cMediaTypes)
478 return S_FALSE;
479 return S_OK;
482 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
484 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
486 if (This->uIndex + cMediaTypes < This->cMediaTypes)
488 This->uIndex += cMediaTypes;
489 return S_OK;
491 return S_FALSE;
494 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
496 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
498 This->uIndex = 0;
499 return S_OK;
502 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
504 HRESULT hr;
505 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
507 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
508 if (FAILED(hr))
509 return hr;
510 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
513 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
515 IEnumMediaTypesImpl_QueryInterface,
516 IEnumMediaTypesImpl_AddRef,
517 IEnumMediaTypesImpl_Release,
518 IEnumMediaTypesImpl_Next,
519 IEnumMediaTypesImpl_Skip,
520 IEnumMediaTypesImpl_Reset,
521 IEnumMediaTypesImpl_Clone
524 /* Implementation of a very stripped down pin for the test filter. Just enough
525 functionality for connecting and Render() to work. */
527 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
529 lstrcpyW(pDest->achName, pSrc->achName);
530 pDest->dir = pSrc->dir;
531 pDest->pFilter = pSrc->pFilter;
534 typedef struct ITestPinImpl
536 IPin IPin_iface;
537 LONG refCount;
538 LPCRITICAL_SECTION pCritSec;
539 PIN_INFO pinInfo;
540 IPin * pConnectedTo;
541 AM_MEDIA_TYPE mtCurrent;
542 LPVOID pUserData;
543 } ITestPinImpl;
545 static inline ITestPinImpl *impl_from_IPin(IPin *iface)
547 return CONTAINING_RECORD(iface, ITestPinImpl, IPin_iface);
550 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
552 *ppv = NULL;
554 if (IsEqualIID(riid, &IID_IUnknown))
555 *ppv = iface;
556 else if (IsEqualIID(riid, &IID_IPin))
557 *ppv = iface;
559 if (*ppv)
561 IUnknown_AddRef((IUnknown *)(*ppv));
562 return S_OK;
565 return E_NOINTERFACE;
568 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
570 ITestPinImpl *This = impl_from_IPin(iface);
571 ULONG refCount = InterlockedIncrement(&This->refCount);
572 return refCount;
575 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
577 ITestPinImpl *This = impl_from_IPin(iface);
578 ULONG refCount = InterlockedDecrement(&This->refCount);
580 if (!refCount)
582 FreeMediaType(&This->mtCurrent);
583 CoTaskMemFree(This);
584 return 0;
586 else
587 return refCount;
590 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
592 return E_UNEXPECTED;
595 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
597 ITestPinImpl *This = impl_from_IPin(iface);
598 PIN_DIRECTION pindirReceive;
599 HRESULT hr = S_OK;
601 EnterCriticalSection(This->pCritSec);
603 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
604 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
605 hr = VFW_E_TYPE_NOT_ACCEPTED;
607 if (This->pConnectedTo)
608 hr = VFW_E_ALREADY_CONNECTED;
610 if (SUCCEEDED(hr))
612 IPin_QueryDirection(pReceivePin, &pindirReceive);
614 if (pindirReceive != PINDIR_OUTPUT)
616 hr = VFW_E_INVALID_DIRECTION;
620 if (SUCCEEDED(hr))
622 CopyMediaType(&This->mtCurrent, pmt);
623 This->pConnectedTo = pReceivePin;
624 IPin_AddRef(pReceivePin);
627 LeaveCriticalSection(This->pCritSec);
629 return hr;
632 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
634 HRESULT hr;
635 ITestPinImpl *This = impl_from_IPin(iface);
637 EnterCriticalSection(This->pCritSec);
639 if (This->pConnectedTo)
641 IPin_Release(This->pConnectedTo);
642 This->pConnectedTo = NULL;
643 hr = S_OK;
645 else
646 hr = S_FALSE;
648 LeaveCriticalSection(This->pCritSec);
650 return hr;
653 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
655 HRESULT hr;
656 ITestPinImpl *This = impl_from_IPin(iface);
658 EnterCriticalSection(This->pCritSec);
660 if (This->pConnectedTo)
662 *ppPin = This->pConnectedTo;
663 IPin_AddRef(*ppPin);
664 hr = S_OK;
666 else
668 hr = VFW_E_NOT_CONNECTED;
669 *ppPin = NULL;
672 LeaveCriticalSection(This->pCritSec);
674 return hr;
677 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
679 HRESULT hr;
680 ITestPinImpl *This = impl_from_IPin(iface);
682 EnterCriticalSection(This->pCritSec);
684 if (This->pConnectedTo)
686 CopyMediaType(pmt, &This->mtCurrent);
687 hr = S_OK;
689 else
691 ZeroMemory(pmt, sizeof(*pmt));
692 hr = VFW_E_NOT_CONNECTED;
695 LeaveCriticalSection(This->pCritSec);
697 return hr;
700 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
702 ITestPinImpl *This = impl_from_IPin(iface);
704 Copy_PinInfo(pInfo, &This->pinInfo);
705 IBaseFilter_AddRef(pInfo->pFilter);
707 return S_OK;
710 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
712 ITestPinImpl *This = impl_from_IPin(iface);
714 *pPinDir = This->pinInfo.dir;
716 return S_OK;
719 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
721 return E_NOTIMPL;
724 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
726 ITestPinImpl *This = impl_from_IPin(iface);
728 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
729 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
730 return S_OK;
731 else
732 return VFW_E_TYPE_NOT_ACCEPTED;
735 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
737 ITestPinImpl *This = impl_from_IPin(iface);
739 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
742 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
744 return E_NOTIMPL;
747 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
749 return E_NOTIMPL;
752 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
754 return E_NOTIMPL;
757 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
759 return E_NOTIMPL;
762 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
764 return E_NOTIMPL;
767 static const IPinVtbl TestFilter_InputPin_Vtbl =
769 TestFilter_Pin_QueryInterface,
770 TestFilter_Pin_AddRef,
771 TestFilter_Pin_Release,
772 TestFilter_InputPin_Connect,
773 TestFilter_InputPin_ReceiveConnection,
774 TestFilter_Pin_Disconnect,
775 TestFilter_Pin_ConnectedTo,
776 TestFilter_Pin_ConnectionMediaType,
777 TestFilter_Pin_QueryPinInfo,
778 TestFilter_Pin_QueryDirection,
779 TestFilter_Pin_QueryId,
780 TestFilter_Pin_QueryAccept,
781 TestFilter_Pin_EnumMediaTypes,
782 TestFilter_Pin_QueryInternalConnections,
783 TestFilter_Pin_EndOfStream,
784 TestFilter_Pin_BeginFlush,
785 TestFilter_Pin_EndFlush,
786 TestFilter_Pin_NewSegment
789 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
791 return E_UNEXPECTED;
794 /* Private helper function */
795 static HRESULT TestFilter_OutputPin_ConnectSpecific(ITestPinImpl * This, IPin * pReceivePin,
796 const AM_MEDIA_TYPE * pmt)
798 HRESULT hr;
800 This->pConnectedTo = pReceivePin;
801 IPin_AddRef(pReceivePin);
803 hr = IPin_ReceiveConnection(pReceivePin, &This->IPin_iface, pmt);
805 if (FAILED(hr))
807 IPin_Release(This->pConnectedTo);
808 This->pConnectedTo = NULL;
811 return hr;
814 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
816 ITestPinImpl *This = impl_from_IPin(iface);
817 HRESULT hr;
819 EnterCriticalSection(This->pCritSec);
821 /* if we have been a specific type to connect with, then we can either connect
822 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
823 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
824 hr = TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, pmt);
825 else
827 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
828 (TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, &This->mtCurrent) == S_OK))
829 hr = S_OK;
830 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
831 } /* if negotiate media type */
832 } /* if succeeded */
833 LeaveCriticalSection(This->pCritSec);
835 return hr;
838 static const IPinVtbl TestFilter_OutputPin_Vtbl =
840 TestFilter_Pin_QueryInterface,
841 TestFilter_Pin_AddRef,
842 TestFilter_Pin_Release,
843 TestFilter_OutputPin_Connect,
844 TestFilter_OutputPin_ReceiveConnection,
845 TestFilter_Pin_Disconnect,
846 TestFilter_Pin_ConnectedTo,
847 TestFilter_Pin_ConnectionMediaType,
848 TestFilter_Pin_QueryPinInfo,
849 TestFilter_Pin_QueryDirection,
850 TestFilter_Pin_QueryId,
851 TestFilter_Pin_QueryAccept,
852 TestFilter_Pin_EnumMediaTypes,
853 TestFilter_Pin_QueryInternalConnections,
854 TestFilter_Pin_EndOfStream,
855 TestFilter_Pin_BeginFlush,
856 TestFilter_Pin_EndFlush,
857 TestFilter_Pin_NewSegment
860 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
861 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
863 ITestPinImpl * pPinImpl;
865 *ppPin = NULL;
867 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
869 if (!pPinImpl)
870 return E_OUTOFMEMORY;
872 pPinImpl->refCount = 1;
873 pPinImpl->pConnectedTo = NULL;
874 pPinImpl->pCritSec = pCritSec;
875 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
876 pPinImpl->mtCurrent = *pinmt;
878 pPinImpl->IPin_iface.lpVtbl = Pin_Vtbl;
880 *ppPin = &pPinImpl->IPin_iface;
881 return S_OK;
884 /* IEnumPins implementation */
886 typedef HRESULT (* FNOBTAINPIN)(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick);
888 typedef struct IEnumPinsImpl
890 IEnumPins IEnumPins_iface;
891 LONG refCount;
892 ULONG uIndex;
893 TestFilterImpl *base;
894 FNOBTAINPIN receive_pin;
895 DWORD synctime;
896 } IEnumPinsImpl;
898 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
900 static inline IEnumPinsImpl *impl_from_IEnumPins(IEnumPins *iface)
902 return CONTAINING_RECORD(iface, IEnumPinsImpl, IEnumPins_iface);
905 static HRESULT createenumpins(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, TestFilterImpl *base)
907 IEnumPinsImpl * pEnumPins;
909 if (!ppEnum)
910 return E_POINTER;
912 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
913 if (!pEnumPins)
915 *ppEnum = NULL;
916 return E_OUTOFMEMORY;
918 pEnumPins->IEnumPins_iface.lpVtbl = &IEnumPinsImpl_Vtbl;
919 pEnumPins->refCount = 1;
920 pEnumPins->uIndex = 0;
921 pEnumPins->receive_pin = receive_pin;
922 pEnumPins->base = base;
923 IBaseFilter_AddRef(&base->IBaseFilter_iface);
924 *ppEnum = &pEnumPins->IEnumPins_iface;
926 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
928 return S_OK;
931 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
933 *ppv = NULL;
935 if (IsEqualIID(riid, &IID_IUnknown))
936 *ppv = iface;
937 else if (IsEqualIID(riid, &IID_IEnumPins))
938 *ppv = iface;
940 if (*ppv)
942 IUnknown_AddRef((IUnknown *)(*ppv));
943 return S_OK;
946 return E_NOINTERFACE;
949 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
951 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
952 ULONG refCount = InterlockedIncrement(&This->refCount);
954 return refCount;
957 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
959 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
960 ULONG refCount = InterlockedDecrement(&This->refCount);
962 if (!refCount)
964 IBaseFilter_Release(&This->base->IBaseFilter_iface);
965 CoTaskMemFree(This);
966 return 0;
968 else
969 return refCount;
972 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
974 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
975 DWORD synctime = This->synctime;
976 HRESULT hr = S_OK;
977 ULONG i = 0;
979 if (!ppPins)
980 return E_POINTER;
982 if (cPins > 1 && !pcFetched)
983 return E_INVALIDARG;
985 if (pcFetched)
986 *pcFetched = 0;
988 while (i < cPins && hr == S_OK)
990 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
992 if (hr == S_OK)
993 ++i;
995 if (synctime != This->synctime)
996 break;
999 if (!i && synctime != This->synctime)
1000 return VFW_E_ENUM_OUT_OF_SYNC;
1002 if (pcFetched)
1003 *pcFetched = i;
1004 This->uIndex += i;
1006 if (i < cPins)
1007 return S_FALSE;
1008 return S_OK;
1011 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
1013 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1014 DWORD synctime = This->synctime;
1015 HRESULT hr;
1016 IPin *pin = NULL;
1018 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
1019 if (pin)
1020 IPin_Release(pin);
1022 if (synctime != This->synctime)
1023 return VFW_E_ENUM_OUT_OF_SYNC;
1025 if (hr == S_OK)
1026 This->uIndex += cPins;
1028 return hr;
1031 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1033 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1035 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1037 This->uIndex = 0;
1038 return S_OK;
1041 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1043 HRESULT hr;
1044 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1046 hr = createenumpins(ppEnum, This->receive_pin, This->base);
1047 if (FAILED(hr))
1048 return hr;
1049 return IEnumPins_Skip(*ppEnum, This->uIndex);
1052 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1054 IEnumPinsImpl_QueryInterface,
1055 IEnumPinsImpl_AddRef,
1056 IEnumPinsImpl_Release,
1057 IEnumPinsImpl_Next,
1058 IEnumPinsImpl_Skip,
1059 IEnumPinsImpl_Reset,
1060 IEnumPinsImpl_Clone
1063 /* Test filter implementation - a filter that has few predefined pins with single media type
1064 * that accept only this single media type. Enough for Render(). */
1066 typedef struct TestFilterPinData
1068 PIN_DIRECTION pinDir;
1069 const GUID *mediasubtype;
1070 } TestFilterPinData;
1072 static const IBaseFilterVtbl TestFilter_Vtbl;
1074 static inline TestFilterImpl *impl_from_IBaseFilter(IBaseFilter *iface)
1076 return CONTAINING_RECORD(iface, TestFilterImpl, IBaseFilter_iface);
1079 static HRESULT createtestfilter(const CLSID* pClsid, const TestFilterPinData *pinData,
1080 TestFilterImpl **tf)
1082 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1083 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1084 HRESULT hr;
1085 PIN_INFO pinInfo;
1086 TestFilterImpl* pTestFilter = NULL;
1087 UINT nPins, i;
1088 AM_MEDIA_TYPE mt;
1090 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1091 if (!pTestFilter) return E_OUTOFMEMORY;
1093 pTestFilter->clsid = *pClsid;
1094 pTestFilter->IBaseFilter_iface.lpVtbl = &TestFilter_Vtbl;
1095 pTestFilter->refCount = 1;
1096 InitializeCriticalSection(&pTestFilter->csFilter);
1097 pTestFilter->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TestFilterImpl.csFilter");
1098 pTestFilter->state = State_Stopped;
1100 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1102 nPins = 0;
1103 while(pinData[nPins].mediasubtype) ++nPins;
1105 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1106 if (!pTestFilter->ppPins)
1108 hr = E_OUTOFMEMORY;
1109 goto error;
1111 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1113 for (i = 0; i < nPins; i++)
1115 ZeroMemory(&mt, sizeof(mt));
1116 mt.majortype = MEDIATYPE_Video;
1117 mt.formattype = FORMAT_None;
1118 mt.subtype = *pinData[i].mediasubtype;
1120 pinInfo.dir = pinData[i].pinDir;
1121 pinInfo.pFilter = &pTestFilter->IBaseFilter_iface;
1122 if (pinInfo.dir == PINDIR_INPUT)
1124 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1125 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1126 &pTestFilter->ppPins[i]);
1129 else
1131 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1132 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1133 &pTestFilter->ppPins[i]);
1135 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1138 pTestFilter->nPins = nPins;
1139 *tf = pTestFilter;
1140 return S_OK;
1142 error:
1144 if (pTestFilter->ppPins)
1146 for (i = 0; i < nPins; i++)
1148 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1151 CoTaskMemFree(pTestFilter->ppPins);
1152 pTestFilter->csFilter.DebugInfo->Spare[0] = 0;
1153 DeleteCriticalSection(&pTestFilter->csFilter);
1154 CoTaskMemFree(pTestFilter);
1156 return hr;
1159 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1161 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1163 *ppv = NULL;
1165 if (IsEqualIID(riid, &IID_IUnknown))
1166 *ppv = This;
1167 else if (IsEqualIID(riid, &IID_IPersist))
1168 *ppv = This;
1169 else if (IsEqualIID(riid, &IID_IMediaFilter))
1170 *ppv = This;
1171 else if (IsEqualIID(riid, &IID_IBaseFilter))
1172 *ppv = This;
1174 if (*ppv)
1176 IUnknown_AddRef((IUnknown *)(*ppv));
1177 return S_OK;
1180 return E_NOINTERFACE;
1183 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1185 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1186 ULONG refCount = InterlockedIncrement(&This->refCount);
1188 return refCount;
1191 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1193 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1194 ULONG refCount = InterlockedDecrement(&This->refCount);
1196 if (!refCount)
1198 ULONG i;
1200 for (i = 0; i < This->nPins; i++)
1202 IPin *pConnectedTo;
1204 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1206 IPin_Disconnect(pConnectedTo);
1207 IPin_Release(pConnectedTo);
1209 IPin_Disconnect(This->ppPins[i]);
1211 IPin_Release(This->ppPins[i]);
1214 CoTaskMemFree(This->ppPins);
1216 This->csFilter.DebugInfo->Spare[0] = 0;
1217 DeleteCriticalSection(&This->csFilter);
1219 CoTaskMemFree(This);
1221 return 0;
1223 else
1224 return refCount;
1226 /** IPersist methods **/
1228 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1230 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1232 *pClsid = This->clsid;
1234 return S_OK;
1237 /** IMediaFilter methods **/
1239 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1241 return E_NOTIMPL;
1244 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1246 return E_NOTIMPL;
1249 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1251 return E_NOTIMPL;
1254 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1256 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1258 EnterCriticalSection(&This->csFilter);
1260 *pState = This->state;
1262 LeaveCriticalSection(&This->csFilter);
1264 return S_OK;
1267 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1269 return E_NOTIMPL;
1272 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1274 return E_NOTIMPL;
1277 /** IBaseFilter implementation **/
1279 static HRESULT getpin_callback(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick)
1281 /* Our pins are static, not changing so setting static tick count is ok */
1282 *lastsynctick = 0;
1284 if (pos >= tf->nPins)
1285 return S_FALSE;
1287 *pin = tf->ppPins[pos];
1288 IPin_AddRef(*pin);
1289 return S_OK;
1292 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1294 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1296 return createenumpins(ppEnum, getpin_callback, This);
1299 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1301 return E_NOTIMPL;
1304 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1306 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1308 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1309 pInfo->pGraph = This->filterInfo.pGraph;
1311 if (pInfo->pGraph)
1312 IFilterGraph_AddRef(pInfo->pGraph);
1314 return S_OK;
1317 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1319 HRESULT hr = S_OK;
1320 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1322 EnterCriticalSection(&This->csFilter);
1324 if (pName)
1325 lstrcpyW(This->filterInfo.achName, pName);
1326 else
1327 *This->filterInfo.achName = '\0';
1328 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1330 LeaveCriticalSection(&This->csFilter);
1332 return hr;
1335 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1337 return E_NOTIMPL;
1340 static const IBaseFilterVtbl TestFilter_Vtbl =
1342 TestFilter_QueryInterface,
1343 TestFilter_AddRef,
1344 TestFilter_Release,
1345 TestFilter_GetClassID,
1346 TestFilter_Stop,
1347 TestFilter_Pause,
1348 TestFilter_Run,
1349 TestFilter_GetState,
1350 TestFilter_SetSyncSource,
1351 TestFilter_GetSyncSource,
1352 TestFilter_EnumPins,
1353 TestFilter_FindPin,
1354 TestFilter_QueryFilterInfo,
1355 TestFilter_JoinFilterGraph,
1356 TestFilter_QueryVendorInfo
1359 /* IClassFactory implementation */
1361 typedef struct TestClassFactoryImpl
1363 IClassFactory IClassFactory_iface;
1364 const TestFilterPinData *filterPinData;
1365 const CLSID *clsid;
1366 } TestClassFactoryImpl;
1368 static inline TestClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
1370 return CONTAINING_RECORD(iface, TestClassFactoryImpl, IClassFactory_iface);
1373 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1374 LPCLASSFACTORY iface,
1375 REFIID riid,
1376 LPVOID *ppvObj)
1378 if (ppvObj == NULL) return E_POINTER;
1380 if (IsEqualGUID(riid, &IID_IUnknown) ||
1381 IsEqualGUID(riid, &IID_IClassFactory))
1383 *ppvObj = iface;
1384 IClassFactory_AddRef(iface);
1385 return S_OK;
1388 *ppvObj = NULL;
1389 return E_NOINTERFACE;
1392 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1394 return 2; /* non-heap-based object */
1397 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1399 return 1; /* non-heap-based object */
1402 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1403 LPCLASSFACTORY iface,
1404 LPUNKNOWN pUnkOuter,
1405 REFIID riid,
1406 LPVOID *ppvObj)
1408 TestClassFactoryImpl *This = impl_from_IClassFactory(iface);
1409 HRESULT hr;
1410 TestFilterImpl *testfilter;
1412 *ppvObj = NULL;
1414 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1416 hr = createtestfilter(This->clsid, This->filterPinData, &testfilter);
1417 if (SUCCEEDED(hr)) {
1418 hr = IBaseFilter_QueryInterface(&testfilter->IBaseFilter_iface, riid, ppvObj);
1419 IBaseFilter_Release(&testfilter->IBaseFilter_iface);
1421 return hr;
1424 static HRESULT WINAPI Test_IClassFactory_LockServer(
1425 LPCLASSFACTORY iface,
1426 BOOL fLock)
1428 return S_OK;
1431 static IClassFactoryVtbl TestClassFactory_Vtbl =
1433 Test_IClassFactory_QueryInterface,
1434 Test_IClassFactory_AddRef,
1435 Test_IClassFactory_Release,
1436 Test_IClassFactory_CreateInstance,
1437 Test_IClassFactory_LockServer
1440 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1442 IPin *pin = NULL;
1443 PIN_INFO pinInfo;
1444 FILTER_INFO filterInfo;
1445 HRESULT hr;
1447 FilterName[0] = 0;
1449 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1450 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1451 if (FAILED(hr)) return hr;
1453 hr = IPin_QueryPinInfo(pin, &pinInfo);
1454 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1455 IPin_Release(pin);
1456 if (FAILED(hr)) return hr;
1458 SetLastError(0xdeadbeef);
1459 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1460 if (hr == S_OK && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1462 IBaseFilter_Release(pinInfo.pFilter);
1463 return E_NOTIMPL;
1465 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1466 IBaseFilter_Release(pinInfo.pFilter);
1467 if (FAILED(hr)) return hr;
1469 IFilterGraph_Release(filterInfo.pGraph);
1471 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1473 return S_OK;
1476 static void test_render_filter_priority(void)
1478 /* Tests filter choice priorities in Render(). */
1479 DWORD cookie1 = 0, cookie2 = 0, cookie3 = 0;
1480 HRESULT hr;
1481 IFilterGraph2* pgraph2 = NULL;
1482 IFilterMapper2 *pMapper2 = NULL;
1483 TestFilterImpl *ptestfilter = NULL;
1484 TestFilterImpl *ptestfilter2 = NULL;
1485 static const CLSID CLSID_TestFilter2 = {
1486 0x37a4edb0,
1487 0x4d13,
1488 0x11dd,
1489 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1491 static const CLSID CLSID_TestFilter3 = {
1492 0x37a4f2d8,
1493 0x4d13,
1494 0x11dd,
1495 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1497 static const CLSID CLSID_TestFilter4 = {
1498 0x37a4f3b4,
1499 0x4d13,
1500 0x11dd,
1501 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1503 static const GUID mediasubtype1 = {
1504 0x37a4f51c,
1505 0x4d13,
1506 0x11dd,
1507 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1509 static const GUID mediasubtype2 = {
1510 0x37a4f5c6,
1511 0x4d13,
1512 0x11dd,
1513 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1515 static const TestFilterPinData PinData1[] = {
1516 { PINDIR_OUTPUT, &mediasubtype1 },
1517 { 0, 0 }
1519 static const TestFilterPinData PinData2[] = {
1520 { PINDIR_INPUT, &mediasubtype1 },
1521 { 0, 0 }
1523 static const TestFilterPinData PinData3[] = {
1524 { PINDIR_INPUT, &GUID_NULL },
1525 { 0, 0 }
1527 static const TestFilterPinData PinData4[] = {
1528 { PINDIR_INPUT, &mediasubtype1 },
1529 { PINDIR_OUTPUT, &mediasubtype2 },
1530 { 0, 0 }
1532 static const TestFilterPinData PinData5[] = {
1533 { PINDIR_INPUT, &mediasubtype2 },
1534 { 0, 0 }
1536 TestClassFactoryImpl Filter1ClassFactory = {
1537 { &TestClassFactory_Vtbl },
1538 PinData2, &CLSID_TestFilter2
1540 TestClassFactoryImpl Filter2ClassFactory = {
1541 { &TestClassFactory_Vtbl },
1542 PinData4, &CLSID_TestFilter3
1544 TestClassFactoryImpl Filter3ClassFactory = {
1545 { &TestClassFactory_Vtbl },
1546 PinData5, &CLSID_TestFilter4
1548 char ConnectedFilterName1[MAX_FILTER_NAME];
1549 char ConnectedFilterName2[MAX_FILTER_NAME];
1550 REGFILTER2 rgf2;
1551 REGFILTERPINS2 rgPins2[2];
1552 REGPINTYPES rgPinType[2];
1553 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1554 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1555 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1556 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1557 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1558 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1559 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1560 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1562 /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is
1563 "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating
1564 no preference given to exact match. */
1565 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1566 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1567 if (!pgraph2) return;
1569 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1570 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1571 if (FAILED(hr)) goto out;
1573 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1574 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1576 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1577 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1578 if (FAILED(hr)) goto out;
1580 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1581 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1583 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1584 ptestfilter2 = NULL;
1586 hr = createtestfilter(&GUID_NULL, PinData3, &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, wszFilterInstanceName3);
1591 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1593 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1594 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1596 hr = get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1598 IFilterGraph2_Release(pgraph2);
1599 pgraph2 = NULL;
1600 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1601 ptestfilter = NULL;
1602 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1603 ptestfilter2 = NULL;
1605 if (hr == E_NOTIMPL)
1607 win_skip("Needed functions are not implemented\n");
1608 return;
1611 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1612 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1613 if (!pgraph2) goto out;
1615 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1616 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1617 if (FAILED(hr)) goto out;
1619 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1620 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1622 hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1623 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1624 if (FAILED(hr)) goto out;
1626 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1627 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1629 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1630 ptestfilter2 = NULL;
1632 hr = createtestfilter(&GUID_NULL, PinData2, &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, wszFilterInstanceName2);
1637 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1639 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1640 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1642 hr = IFilterGraph2_Disconnect(pgraph2, NULL);
1643 ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr);
1645 get_connected_filter_name(ptestfilter, ConnectedFilterName2);
1646 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1647 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1649 IFilterGraph2_Release(pgraph2);
1650 pgraph2 = NULL;
1651 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1652 ptestfilter = NULL;
1653 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1654 ptestfilter2 = NULL;
1656 /* Test if any preference is given to existing renderer which renders the pin directly vs
1657 an existing renderer which renders the pin indirectly, through an additional middle filter,
1658 again trying different orders of creation. Native appears not to give a preference. */
1660 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1661 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1662 if (!pgraph2) goto out;
1664 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1665 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1666 if (FAILED(hr)) goto out;
1668 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1669 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1671 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1672 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1673 if (FAILED(hr)) goto out;
1675 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1676 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1678 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1679 ptestfilter2 = NULL;
1681 hr = createtestfilter(&GUID_NULL, PinData4, &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, wszFilterInstanceName3);
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, PinData5, &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, wszFilterInstanceName4);
1696 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1698 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1699 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1701 get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1702 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1, "TestfilterInstance2"),
1703 "unexpected connected filter: %s\n", ConnectedFilterName1);
1705 IFilterGraph2_Release(pgraph2);
1706 pgraph2 = NULL;
1707 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1708 ptestfilter = NULL;
1709 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1710 ptestfilter2 = NULL;
1712 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1713 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1714 if (!pgraph2) goto out;
1716 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1717 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1718 if (FAILED(hr)) goto out;
1720 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1721 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1723 hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
1724 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1725 if (FAILED(hr)) goto out;
1727 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1728 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1730 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1731 ptestfilter2 = NULL;
1733 hr = createtestfilter(&GUID_NULL, PinData5, &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, wszFilterInstanceName4);
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, PinData2, &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, wszFilterInstanceName2);
1748 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1750 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1751 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1753 get_connected_filter_name(ptestfilter, ConnectedFilterName2);
1754 ok(!lstrcmp(ConnectedFilterName2, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2, "TestfilterInstance2"),
1755 "unexpected connected filter: %s\n", ConnectedFilterName2);
1756 ok(lstrcmp(ConnectedFilterName1, ConnectedFilterName2),
1757 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1759 IFilterGraph2_Release(pgraph2);
1760 pgraph2 = NULL;
1761 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1762 ptestfilter = NULL;
1763 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1764 ptestfilter2 = NULL;
1766 /* Test if renderers are tried before non-renderers (intermediary filters). */
1767 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1768 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1769 if (!pgraph2) goto out;
1771 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
1772 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1773 if (!pMapper2) goto out;
1775 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1776 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1777 if (FAILED(hr)) goto out;
1779 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1780 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1782 /* Register our filters with COM and with Filtermapper. */
1783 hr = CoRegisterClassObject(Filter1ClassFactory.clsid,
1784 (IUnknown *)&Filter1ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1785 REGCLS_MULTIPLEUSE, &cookie1);
1786 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1787 if (FAILED(hr)) goto out;
1788 hr = CoRegisterClassObject(Filter2ClassFactory.clsid,
1789 (IUnknown *)&Filter2ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1790 REGCLS_MULTIPLEUSE, &cookie2);
1791 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1792 if (FAILED(hr)) goto out;
1793 hr = CoRegisterClassObject(Filter3ClassFactory.clsid,
1794 (IUnknown *)&Filter3ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1795 REGCLS_MULTIPLEUSE, &cookie3);
1796 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1797 if (FAILED(hr)) goto out;
1799 rgf2.dwVersion = 2;
1800 rgf2.dwMerit = MERIT_UNLIKELY;
1801 S1(U(rgf2)).cPins2 = 1;
1802 S1(U(rgf2)).rgPins2 = rgPins2;
1803 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
1804 rgPins2[0].cInstances = 1;
1805 rgPins2[0].nMediaTypes = 1;
1806 rgPins2[0].lpMediaType = &rgPinType[0];
1807 rgPins2[0].nMediums = 0;
1808 rgPins2[0].lpMedium = NULL;
1809 rgPins2[0].clsPinCategory = NULL;
1810 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
1811 rgPinType[0].clsMinorType = &mediasubtype1;
1813 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
1814 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1815 if (hr == E_ACCESSDENIED)
1816 skip("Not authorized to register filters\n");
1817 else
1819 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1821 rgf2.dwMerit = MERIT_PREFERRED;
1822 rgPinType[0].clsMinorType = &mediasubtype2;
1824 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
1825 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1826 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1828 S1(U(rgf2)).cPins2 = 2;
1829 rgPins2[0].dwFlags = 0;
1830 rgPinType[0].clsMinorType = &mediasubtype1;
1832 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
1833 rgPins2[1].cInstances = 1;
1834 rgPins2[1].nMediaTypes = 1;
1835 rgPins2[1].lpMediaType = &rgPinType[1];
1836 rgPins2[1].nMediums = 0;
1837 rgPins2[1].lpMedium = NULL;
1838 rgPins2[1].clsPinCategory = NULL;
1839 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
1840 rgPinType[1].clsMinorType = &mediasubtype2;
1842 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
1843 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1844 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1846 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1847 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1849 get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1850 ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3"),
1851 "unexpected connected filter: %s\n", ConnectedFilterName1);
1854 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1855 &CLSID_TestFilter2);
1856 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1857 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1858 &CLSID_TestFilter3);
1859 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1860 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1861 &CLSID_TestFilter4);
1862 ok(SUCCEEDED(hr), "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1864 out:
1866 if (ptestfilter) IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1867 if (ptestfilter2) IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1868 if (pgraph2) IFilterGraph2_Release(pgraph2);
1869 if (pMapper2) IFilterMapper2_Release(pMapper2);
1871 hr = CoRevokeClassObject(cookie1);
1872 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1873 hr = CoRevokeClassObject(cookie2);
1874 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1875 hr = CoRevokeClassObject(cookie3);
1876 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1879 START_TEST(filtergraph)
1881 HRESULT hr;
1882 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1883 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
1884 &IID_IGraphBuilder, (LPVOID*)&pgraph);
1885 if (FAILED(hr)) {
1886 skip("Creating filtergraph returned %08x, skipping tests\n", hr);
1887 return;
1889 test_render_run(avifile);
1890 test_render_run(mpegfile);
1891 test_graph_builder();
1892 test_graph_builder_addfilter();
1893 test_mediacontrol();
1894 test_filter_graph2();
1895 test_render_filter_priority();
1896 CoUninitialize();