makedep: Use an unsigned constant in hash_filename.
[wine.git] / dlls / quartz / tests / filtergraph.c
blob87b11233ba4af2512fa251880116a1b576b571df
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 GUID format = GUID_NULL;
259 IMediaSeeking *seeking = NULL;
260 IMediaFilter *filter = NULL;
261 IMediaControl *control = NULL;
263 IGraphBuilder_SetDefaultSyncSource(pgraph);
264 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaSeeking, (void**) &seeking);
265 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
266 if (FAILED(hr))
267 return;
269 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
270 ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
271 if (FAILED(hr))
273 IMediaSeeking_Release(seeking);
274 return;
277 hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
278 ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
279 if (FAILED(hr))
281 IMediaSeeking_Release(seeking);
282 IMediaFilter_Release(filter);
283 return;
286 format = GUID_NULL;
287 hr = IMediaSeeking_GetTimeFormat(seeking, &format);
288 ok(hr == S_OK, "GetTimeFormat failed: %08x\n", hr);
289 ok(IsEqualGUID(&format, &TIME_FORMAT_MEDIA_TIME), "GetTimeFormat: unexpected format %s\n", wine_dbgstr_guid(&format));
291 pos = 0xdeadbeef;
292 hr = IMediaSeeking_ConvertTimeFormat(seeking, &pos, NULL, 0x123456789a, NULL);
293 ok(hr == S_OK, "ConvertTimeFormat failed: %08x\n", hr);
294 ok(pos == 0x123456789a, "ConvertTimeFormat: expected 123456789a, got (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
296 pos = 0xdeadbeef;
297 hr = IMediaSeeking_ConvertTimeFormat(seeking, &pos, &TIME_FORMAT_MEDIA_TIME, 0x123456789a, NULL);
298 ok(hr == S_OK, "ConvertTimeFormat failed: %08x\n", hr);
299 ok(pos == 0x123456789a, "ConvertTimeFormat: expected 123456789a, got (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
301 pos = 0xdeadbeef;
302 hr = IMediaSeeking_ConvertTimeFormat(seeking, &pos, NULL, 0x123456789a, &TIME_FORMAT_MEDIA_TIME);
303 ok(hr == S_OK, "ConvertTimeFormat failed: %08x\n", hr);
304 ok(pos == 0x123456789a, "ConvertTimeFormat: expected 123456789a, got (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
306 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
307 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
308 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
310 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_ReturnTime, NULL, AM_SEEKING_NoPositioning);
311 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
312 hr = IMediaSeeking_SetPositions(seeking, NULL, AM_SEEKING_NoPositioning, NULL, AM_SEEKING_ReturnTime);
313 ok(hr == S_OK, "SetPositions failed: %08x\n", hr);
315 IMediaFilter_SetSyncSource(filter, NULL);
316 pos = 0xdeadbeef;
317 hr = IMediaSeeking_GetCurrentPosition(seeking, &pos);
318 ok(hr == S_OK, "GetCurrentPosition failed: %08x\n", hr);
319 ok(pos == 0, "Position != 0 (%x%08x)\n", (DWORD)(pos >> 32), (DWORD)pos);
321 hr = IMediaControl_GetState(control, 1000, NULL);
322 ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
324 IMediaControl_Release(control);
325 IMediaSeeking_Release(seeking);
326 IMediaFilter_Release(filter);
327 releasefiltergraph();
330 static void test_filter_graph2(void)
332 HRESULT hr;
333 IFilterGraph2 *pF = NULL;
335 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
336 &IID_IFilterGraph2, (LPVOID*)&pF);
337 ok(hr == S_OK, "CoCreateInstance failed with %x\n", hr);
338 ok(pF != NULL, "pF is NULL\n");
340 hr = IFilterGraph2_Release(pF);
341 ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
344 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
345 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
347 if (pMediaType->pbFormat)
349 CoTaskMemFree(pMediaType->pbFormat);
350 pMediaType->pbFormat = NULL;
352 if (pMediaType->pUnk)
354 IUnknown_Release(pMediaType->pUnk);
355 pMediaType->pUnk = NULL;
359 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
361 *pDest = *pSrc;
362 if (!pSrc->pbFormat) return S_OK;
363 if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
364 return E_OUTOFMEMORY;
365 memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
366 if (pDest->pUnk)
367 IUnknown_AddRef(pDest->pUnk);
368 return S_OK;
371 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
373 AM_MEDIA_TYPE * pDest;
375 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
376 if (!pDest)
377 return NULL;
379 if (FAILED(CopyMediaType(pDest, pSrc)))
381 CoTaskMemFree(pDest);
382 return NULL;
385 return pDest;
388 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
390 return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
391 ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
394 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
396 FreeMediaType(pMediaType);
397 CoTaskMemFree(pMediaType);
400 typedef struct IEnumMediaTypesImpl
402 IEnumMediaTypes IEnumMediaTypes_iface;
403 LONG refCount;
404 AM_MEDIA_TYPE *pMediaTypes;
405 ULONG cMediaTypes;
406 ULONG uIndex;
407 } IEnumMediaTypesImpl;
409 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
411 static inline IEnumMediaTypesImpl *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
413 return CONTAINING_RECORD(iface, IEnumMediaTypesImpl, IEnumMediaTypes_iface);
416 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
418 ULONG i;
419 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
421 if (!pEnumMediaTypes)
423 *ppEnum = NULL;
424 return E_OUTOFMEMORY;
426 pEnumMediaTypes->IEnumMediaTypes_iface.lpVtbl = &IEnumMediaTypesImpl_Vtbl;
427 pEnumMediaTypes->refCount = 1;
428 pEnumMediaTypes->uIndex = 0;
429 pEnumMediaTypes->cMediaTypes = cMediaTypes;
430 pEnumMediaTypes->pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cMediaTypes);
431 for (i = 0; i < cMediaTypes; i++)
432 if (FAILED(CopyMediaType(&pEnumMediaTypes->pMediaTypes[i], &pMediaTypes[i])))
434 while (i--)
435 FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
436 CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
437 return E_OUTOFMEMORY;
439 *ppEnum = &pEnumMediaTypes->IEnumMediaTypes_iface;
440 return S_OK;
443 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
445 *ppv = NULL;
447 if (IsEqualIID(riid, &IID_IUnknown))
448 *ppv = iface;
449 else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
450 *ppv = iface;
452 if (*ppv)
454 IUnknown_AddRef((IUnknown *)(*ppv));
455 return S_OK;
458 return E_NOINTERFACE;
461 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
463 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
464 ULONG refCount = InterlockedIncrement(&This->refCount);
466 return refCount;
469 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
471 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
472 ULONG refCount = InterlockedDecrement(&This->refCount);
474 if (!refCount)
476 int i;
477 for (i = 0; i < This->cMediaTypes; i++)
478 FreeMediaType(&This->pMediaTypes[i]);
479 CoTaskMemFree(This->pMediaTypes);
480 CoTaskMemFree(This);
482 return refCount;
485 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
487 ULONG cFetched;
488 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
490 cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
492 if (cFetched > 0)
494 ULONG i;
495 for (i = 0; i < cFetched; i++)
496 if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
498 while (i--)
499 DeleteMediaType(ppMediaTypes[i]);
500 *pcFetched = 0;
501 return E_OUTOFMEMORY;
505 if ((cMediaTypes != 1) || pcFetched)
506 *pcFetched = cFetched;
508 This->uIndex += cFetched;
510 if (cFetched != cMediaTypes)
511 return S_FALSE;
512 return S_OK;
515 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
517 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
519 if (This->uIndex + cMediaTypes < This->cMediaTypes)
521 This->uIndex += cMediaTypes;
522 return S_OK;
524 return S_FALSE;
527 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
529 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
531 This->uIndex = 0;
532 return S_OK;
535 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
537 HRESULT hr;
538 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
540 hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
541 if (FAILED(hr))
542 return hr;
543 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
546 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
548 IEnumMediaTypesImpl_QueryInterface,
549 IEnumMediaTypesImpl_AddRef,
550 IEnumMediaTypesImpl_Release,
551 IEnumMediaTypesImpl_Next,
552 IEnumMediaTypesImpl_Skip,
553 IEnumMediaTypesImpl_Reset,
554 IEnumMediaTypesImpl_Clone
557 /* Implementation of a very stripped down pin for the test filter. Just enough
558 functionality for connecting and Render() to work. */
560 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
562 lstrcpyW(pDest->achName, pSrc->achName);
563 pDest->dir = pSrc->dir;
564 pDest->pFilter = pSrc->pFilter;
567 typedef struct ITestPinImpl
569 IPin IPin_iface;
570 LONG refCount;
571 LPCRITICAL_SECTION pCritSec;
572 PIN_INFO pinInfo;
573 IPin * pConnectedTo;
574 AM_MEDIA_TYPE mtCurrent;
575 LPVOID pUserData;
576 } ITestPinImpl;
578 static inline ITestPinImpl *impl_from_IPin(IPin *iface)
580 return CONTAINING_RECORD(iface, ITestPinImpl, IPin_iface);
583 static HRESULT WINAPI TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
585 *ppv = NULL;
587 if (IsEqualIID(riid, &IID_IUnknown))
588 *ppv = iface;
589 else if (IsEqualIID(riid, &IID_IPin))
590 *ppv = iface;
592 if (*ppv)
594 IUnknown_AddRef((IUnknown *)(*ppv));
595 return S_OK;
598 return E_NOINTERFACE;
601 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
603 ITestPinImpl *This = impl_from_IPin(iface);
604 ULONG refCount = InterlockedIncrement(&This->refCount);
605 return refCount;
608 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
610 ITestPinImpl *This = impl_from_IPin(iface);
611 ULONG refCount = InterlockedDecrement(&This->refCount);
613 if (!refCount)
615 FreeMediaType(&This->mtCurrent);
616 CoTaskMemFree(This);
617 return 0;
619 else
620 return refCount;
623 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
625 return E_UNEXPECTED;
628 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
630 ITestPinImpl *This = impl_from_IPin(iface);
631 PIN_DIRECTION pindirReceive;
632 HRESULT hr = S_OK;
634 EnterCriticalSection(This->pCritSec);
636 if (!(IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
637 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype))))
638 hr = VFW_E_TYPE_NOT_ACCEPTED;
640 if (This->pConnectedTo)
641 hr = VFW_E_ALREADY_CONNECTED;
643 if (SUCCEEDED(hr))
645 IPin_QueryDirection(pReceivePin, &pindirReceive);
647 if (pindirReceive != PINDIR_OUTPUT)
649 hr = VFW_E_INVALID_DIRECTION;
653 if (SUCCEEDED(hr))
655 CopyMediaType(&This->mtCurrent, pmt);
656 This->pConnectedTo = pReceivePin;
657 IPin_AddRef(pReceivePin);
660 LeaveCriticalSection(This->pCritSec);
662 return hr;
665 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
667 HRESULT hr;
668 ITestPinImpl *This = impl_from_IPin(iface);
670 EnterCriticalSection(This->pCritSec);
672 if (This->pConnectedTo)
674 IPin_Release(This->pConnectedTo);
675 This->pConnectedTo = NULL;
676 hr = S_OK;
678 else
679 hr = S_FALSE;
681 LeaveCriticalSection(This->pCritSec);
683 return hr;
686 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
688 HRESULT hr;
689 ITestPinImpl *This = impl_from_IPin(iface);
691 EnterCriticalSection(This->pCritSec);
693 if (This->pConnectedTo)
695 *ppPin = This->pConnectedTo;
696 IPin_AddRef(*ppPin);
697 hr = S_OK;
699 else
701 hr = VFW_E_NOT_CONNECTED;
702 *ppPin = NULL;
705 LeaveCriticalSection(This->pCritSec);
707 return hr;
710 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
712 HRESULT hr;
713 ITestPinImpl *This = impl_from_IPin(iface);
715 EnterCriticalSection(This->pCritSec);
717 if (This->pConnectedTo)
719 CopyMediaType(pmt, &This->mtCurrent);
720 hr = S_OK;
722 else
724 ZeroMemory(pmt, sizeof(*pmt));
725 hr = VFW_E_NOT_CONNECTED;
728 LeaveCriticalSection(This->pCritSec);
730 return hr;
733 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
735 ITestPinImpl *This = impl_from_IPin(iface);
737 Copy_PinInfo(pInfo, &This->pinInfo);
738 IBaseFilter_AddRef(pInfo->pFilter);
740 return S_OK;
743 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
745 ITestPinImpl *This = impl_from_IPin(iface);
747 *pPinDir = This->pinInfo.dir;
749 return S_OK;
752 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
754 return E_NOTIMPL;
757 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
759 ITestPinImpl *This = impl_from_IPin(iface);
761 if (IsEqualIID(&pmt->majortype, &This->mtCurrent.majortype) && (IsEqualIID(&pmt->subtype, &This->mtCurrent.subtype) ||
762 IsEqualIID(&GUID_NULL, &This->mtCurrent.subtype)))
763 return S_OK;
764 else
765 return VFW_E_TYPE_NOT_ACCEPTED;
768 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
770 ITestPinImpl *This = impl_from_IPin(iface);
772 return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
775 static HRESULT WINAPI TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
777 return E_NOTIMPL;
780 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
782 return E_NOTIMPL;
785 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
787 return E_NOTIMPL;
790 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
792 return E_NOTIMPL;
795 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
797 return E_NOTIMPL;
800 static const IPinVtbl TestFilter_InputPin_Vtbl =
802 TestFilter_Pin_QueryInterface,
803 TestFilter_Pin_AddRef,
804 TestFilter_Pin_Release,
805 TestFilter_InputPin_Connect,
806 TestFilter_InputPin_ReceiveConnection,
807 TestFilter_Pin_Disconnect,
808 TestFilter_Pin_ConnectedTo,
809 TestFilter_Pin_ConnectionMediaType,
810 TestFilter_Pin_QueryPinInfo,
811 TestFilter_Pin_QueryDirection,
812 TestFilter_Pin_QueryId,
813 TestFilter_Pin_QueryAccept,
814 TestFilter_Pin_EnumMediaTypes,
815 TestFilter_Pin_QueryInternalConnections,
816 TestFilter_Pin_EndOfStream,
817 TestFilter_Pin_BeginFlush,
818 TestFilter_Pin_EndFlush,
819 TestFilter_Pin_NewSegment
822 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
824 return E_UNEXPECTED;
827 /* Private helper function */
828 static HRESULT TestFilter_OutputPin_ConnectSpecific(ITestPinImpl * This, IPin * pReceivePin,
829 const AM_MEDIA_TYPE * pmt)
831 HRESULT hr;
833 This->pConnectedTo = pReceivePin;
834 IPin_AddRef(pReceivePin);
836 hr = IPin_ReceiveConnection(pReceivePin, &This->IPin_iface, pmt);
838 if (FAILED(hr))
840 IPin_Release(This->pConnectedTo);
841 This->pConnectedTo = NULL;
844 return hr;
847 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
849 ITestPinImpl *This = impl_from_IPin(iface);
850 HRESULT hr;
852 EnterCriticalSection(This->pCritSec);
854 /* if we have been a specific type to connect with, then we can either connect
855 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
856 if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
857 hr = TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, pmt);
858 else
860 if (( !pmt || CompareMediaTypes(pmt, &This->mtCurrent, TRUE) ) &&
861 (TestFilter_OutputPin_ConnectSpecific(This, pReceivePin, &This->mtCurrent) == S_OK))
862 hr = S_OK;
863 else hr = VFW_E_NO_ACCEPTABLE_TYPES;
864 } /* if negotiate media type */
865 } /* if succeeded */
866 LeaveCriticalSection(This->pCritSec);
868 return hr;
871 static const IPinVtbl TestFilter_OutputPin_Vtbl =
873 TestFilter_Pin_QueryInterface,
874 TestFilter_Pin_AddRef,
875 TestFilter_Pin_Release,
876 TestFilter_OutputPin_Connect,
877 TestFilter_OutputPin_ReceiveConnection,
878 TestFilter_Pin_Disconnect,
879 TestFilter_Pin_ConnectedTo,
880 TestFilter_Pin_ConnectionMediaType,
881 TestFilter_Pin_QueryPinInfo,
882 TestFilter_Pin_QueryDirection,
883 TestFilter_Pin_QueryId,
884 TestFilter_Pin_QueryAccept,
885 TestFilter_Pin_EnumMediaTypes,
886 TestFilter_Pin_QueryInternalConnections,
887 TestFilter_Pin_EndOfStream,
888 TestFilter_Pin_BeginFlush,
889 TestFilter_Pin_EndFlush,
890 TestFilter_Pin_NewSegment
893 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
894 LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
896 ITestPinImpl * pPinImpl;
898 *ppPin = NULL;
900 pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
902 if (!pPinImpl)
903 return E_OUTOFMEMORY;
905 pPinImpl->refCount = 1;
906 pPinImpl->pConnectedTo = NULL;
907 pPinImpl->pCritSec = pCritSec;
908 Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
909 pPinImpl->mtCurrent = *pinmt;
911 pPinImpl->IPin_iface.lpVtbl = Pin_Vtbl;
913 *ppPin = &pPinImpl->IPin_iface;
914 return S_OK;
917 /* IEnumPins implementation */
919 typedef HRESULT (* FNOBTAINPIN)(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick);
921 typedef struct IEnumPinsImpl
923 IEnumPins IEnumPins_iface;
924 LONG refCount;
925 ULONG uIndex;
926 TestFilterImpl *base;
927 FNOBTAINPIN receive_pin;
928 DWORD synctime;
929 } IEnumPinsImpl;
931 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
933 static inline IEnumPinsImpl *impl_from_IEnumPins(IEnumPins *iface)
935 return CONTAINING_RECORD(iface, IEnumPinsImpl, IEnumPins_iface);
938 static HRESULT createenumpins(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, TestFilterImpl *base)
940 IEnumPinsImpl * pEnumPins;
942 if (!ppEnum)
943 return E_POINTER;
945 pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
946 if (!pEnumPins)
948 *ppEnum = NULL;
949 return E_OUTOFMEMORY;
951 pEnumPins->IEnumPins_iface.lpVtbl = &IEnumPinsImpl_Vtbl;
952 pEnumPins->refCount = 1;
953 pEnumPins->uIndex = 0;
954 pEnumPins->receive_pin = receive_pin;
955 pEnumPins->base = base;
956 IBaseFilter_AddRef(&base->IBaseFilter_iface);
957 *ppEnum = &pEnumPins->IEnumPins_iface;
959 receive_pin(base, ~0, NULL, &pEnumPins->synctime);
961 return S_OK;
964 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
966 *ppv = NULL;
968 if (IsEqualIID(riid, &IID_IUnknown))
969 *ppv = iface;
970 else if (IsEqualIID(riid, &IID_IEnumPins))
971 *ppv = iface;
973 if (*ppv)
975 IUnknown_AddRef((IUnknown *)(*ppv));
976 return S_OK;
979 return E_NOINTERFACE;
982 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
984 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
985 ULONG refCount = InterlockedIncrement(&This->refCount);
987 return refCount;
990 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
992 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
993 ULONG refCount = InterlockedDecrement(&This->refCount);
995 if (!refCount)
997 IBaseFilter_Release(&This->base->IBaseFilter_iface);
998 CoTaskMemFree(This);
999 return 0;
1001 else
1002 return refCount;
1005 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
1007 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1008 DWORD synctime = This->synctime;
1009 HRESULT hr = S_OK;
1010 ULONG i = 0;
1012 if (!ppPins)
1013 return E_POINTER;
1015 if (cPins > 1 && !pcFetched)
1016 return E_INVALIDARG;
1018 if (pcFetched)
1019 *pcFetched = 0;
1021 while (i < cPins && hr == S_OK)
1023 hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
1025 if (hr == S_OK)
1026 ++i;
1028 if (synctime != This->synctime)
1029 break;
1032 if (!i && synctime != This->synctime)
1033 return VFW_E_ENUM_OUT_OF_SYNC;
1035 if (pcFetched)
1036 *pcFetched = i;
1037 This->uIndex += i;
1039 if (i < cPins)
1040 return S_FALSE;
1041 return S_OK;
1044 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
1046 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1047 DWORD synctime = This->synctime;
1048 HRESULT hr;
1049 IPin *pin = NULL;
1051 hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
1052 if (pin)
1053 IPin_Release(pin);
1055 if (synctime != This->synctime)
1056 return VFW_E_ENUM_OUT_OF_SYNC;
1058 if (hr == S_OK)
1059 This->uIndex += cPins;
1061 return hr;
1064 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1066 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1068 This->receive_pin(This->base, ~0, NULL, &This->synctime);
1070 This->uIndex = 0;
1071 return S_OK;
1074 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1076 HRESULT hr;
1077 IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1079 hr = createenumpins(ppEnum, This->receive_pin, This->base);
1080 if (FAILED(hr))
1081 return hr;
1082 return IEnumPins_Skip(*ppEnum, This->uIndex);
1085 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1087 IEnumPinsImpl_QueryInterface,
1088 IEnumPinsImpl_AddRef,
1089 IEnumPinsImpl_Release,
1090 IEnumPinsImpl_Next,
1091 IEnumPinsImpl_Skip,
1092 IEnumPinsImpl_Reset,
1093 IEnumPinsImpl_Clone
1096 /* Test filter implementation - a filter that has few predefined pins with single media type
1097 * that accept only this single media type. Enough for Render(). */
1099 typedef struct TestFilterPinData
1101 PIN_DIRECTION pinDir;
1102 const GUID *mediasubtype;
1103 } TestFilterPinData;
1105 static const IBaseFilterVtbl TestFilter_Vtbl;
1107 static inline TestFilterImpl *impl_from_IBaseFilter(IBaseFilter *iface)
1109 return CONTAINING_RECORD(iface, TestFilterImpl, IBaseFilter_iface);
1112 static HRESULT createtestfilter(const CLSID* pClsid, const TestFilterPinData *pinData,
1113 TestFilterImpl **tf)
1115 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
1116 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1117 HRESULT hr;
1118 PIN_INFO pinInfo;
1119 TestFilterImpl* pTestFilter = NULL;
1120 UINT nPins, i;
1121 AM_MEDIA_TYPE mt;
1123 pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1124 if (!pTestFilter) return E_OUTOFMEMORY;
1126 pTestFilter->clsid = *pClsid;
1127 pTestFilter->IBaseFilter_iface.lpVtbl = &TestFilter_Vtbl;
1128 pTestFilter->refCount = 1;
1129 InitializeCriticalSection(&pTestFilter->csFilter);
1130 pTestFilter->state = State_Stopped;
1132 ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1134 nPins = 0;
1135 while(pinData[nPins].mediasubtype) ++nPins;
1137 pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1138 if (!pTestFilter->ppPins)
1140 hr = E_OUTOFMEMORY;
1141 goto error;
1143 ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1145 for (i = 0; i < nPins; i++)
1147 ZeroMemory(&mt, sizeof(mt));
1148 mt.majortype = MEDIATYPE_Video;
1149 mt.formattype = FORMAT_None;
1150 mt.subtype = *pinData[i].mediasubtype;
1152 pinInfo.dir = pinData[i].pinDir;
1153 pinInfo.pFilter = &pTestFilter->IBaseFilter_iface;
1154 if (pinInfo.dir == PINDIR_INPUT)
1156 lstrcpynW(pinInfo.achName, wcsInputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1157 hr = TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1158 &pTestFilter->ppPins[i]);
1161 else
1163 lstrcpynW(pinInfo.achName, wcsOutputPinName, sizeof(pinInfo.achName) / sizeof(pinInfo.achName[0]));
1164 hr = TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl, &pinInfo, &mt, &pTestFilter->csFilter,
1165 &pTestFilter->ppPins[i]);
1167 if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1170 pTestFilter->nPins = nPins;
1171 *tf = pTestFilter;
1172 return S_OK;
1174 error:
1176 if (pTestFilter->ppPins)
1178 for (i = 0; i < nPins; i++)
1180 if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1183 CoTaskMemFree(pTestFilter->ppPins);
1184 DeleteCriticalSection(&pTestFilter->csFilter);
1185 CoTaskMemFree(pTestFilter);
1187 return hr;
1190 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1192 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1194 *ppv = NULL;
1196 if (IsEqualIID(riid, &IID_IUnknown))
1197 *ppv = This;
1198 else if (IsEqualIID(riid, &IID_IPersist))
1199 *ppv = This;
1200 else if (IsEqualIID(riid, &IID_IMediaFilter))
1201 *ppv = This;
1202 else if (IsEqualIID(riid, &IID_IBaseFilter))
1203 *ppv = This;
1205 if (*ppv)
1207 IUnknown_AddRef((IUnknown *)(*ppv));
1208 return S_OK;
1211 return E_NOINTERFACE;
1214 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1216 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1217 ULONG refCount = InterlockedIncrement(&This->refCount);
1219 return refCount;
1222 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1224 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1225 ULONG refCount = InterlockedDecrement(&This->refCount);
1227 if (!refCount)
1229 ULONG i;
1231 for (i = 0; i < This->nPins; i++)
1233 IPin *pConnectedTo;
1235 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1237 IPin_Disconnect(pConnectedTo);
1238 IPin_Release(pConnectedTo);
1240 IPin_Disconnect(This->ppPins[i]);
1242 IPin_Release(This->ppPins[i]);
1245 CoTaskMemFree(This->ppPins);
1247 DeleteCriticalSection(&This->csFilter);
1249 CoTaskMemFree(This);
1251 return 0;
1253 else
1254 return refCount;
1256 /** IPersist methods **/
1258 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1260 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1262 *pClsid = This->clsid;
1264 return S_OK;
1267 /** IMediaFilter methods **/
1269 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1271 return E_NOTIMPL;
1274 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1276 return E_NOTIMPL;
1279 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1281 return E_NOTIMPL;
1284 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1286 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1288 EnterCriticalSection(&This->csFilter);
1290 *pState = This->state;
1292 LeaveCriticalSection(&This->csFilter);
1294 return S_OK;
1297 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1299 return E_NOTIMPL;
1302 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1304 return E_NOTIMPL;
1307 /** IBaseFilter implementation **/
1309 static HRESULT getpin_callback(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick)
1311 /* Our pins are static, not changing so setting static tick count is ok */
1312 *lastsynctick = 0;
1314 if (pos >= tf->nPins)
1315 return S_FALSE;
1317 *pin = tf->ppPins[pos];
1318 IPin_AddRef(*pin);
1319 return S_OK;
1322 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1324 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1326 return createenumpins(ppEnum, getpin_callback, This);
1329 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1331 return E_NOTIMPL;
1334 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1336 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1338 lstrcpyW(pInfo->achName, This->filterInfo.achName);
1339 pInfo->pGraph = This->filterInfo.pGraph;
1341 if (pInfo->pGraph)
1342 IFilterGraph_AddRef(pInfo->pGraph);
1344 return S_OK;
1347 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1349 HRESULT hr = S_OK;
1350 TestFilterImpl *This = impl_from_IBaseFilter(iface);
1352 EnterCriticalSection(&This->csFilter);
1354 if (pName)
1355 lstrcpyW(This->filterInfo.achName, pName);
1356 else
1357 *This->filterInfo.achName = '\0';
1358 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
1360 LeaveCriticalSection(&This->csFilter);
1362 return hr;
1365 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1367 return E_NOTIMPL;
1370 static const IBaseFilterVtbl TestFilter_Vtbl =
1372 TestFilter_QueryInterface,
1373 TestFilter_AddRef,
1374 TestFilter_Release,
1375 TestFilter_GetClassID,
1376 TestFilter_Stop,
1377 TestFilter_Pause,
1378 TestFilter_Run,
1379 TestFilter_GetState,
1380 TestFilter_SetSyncSource,
1381 TestFilter_GetSyncSource,
1382 TestFilter_EnumPins,
1383 TestFilter_FindPin,
1384 TestFilter_QueryFilterInfo,
1385 TestFilter_JoinFilterGraph,
1386 TestFilter_QueryVendorInfo
1389 /* IClassFactory implementation */
1391 typedef struct TestClassFactoryImpl
1393 IClassFactory IClassFactory_iface;
1394 const TestFilterPinData *filterPinData;
1395 const CLSID *clsid;
1396 } TestClassFactoryImpl;
1398 static inline TestClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
1400 return CONTAINING_RECORD(iface, TestClassFactoryImpl, IClassFactory_iface);
1403 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1404 LPCLASSFACTORY iface,
1405 REFIID riid,
1406 LPVOID *ppvObj)
1408 if (ppvObj == NULL) return E_POINTER;
1410 if (IsEqualGUID(riid, &IID_IUnknown) ||
1411 IsEqualGUID(riid, &IID_IClassFactory))
1413 *ppvObj = iface;
1414 IClassFactory_AddRef(iface);
1415 return S_OK;
1418 *ppvObj = NULL;
1419 return E_NOINTERFACE;
1422 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1424 return 2; /* non-heap-based object */
1427 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1429 return 1; /* non-heap-based object */
1432 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1433 LPCLASSFACTORY iface,
1434 LPUNKNOWN pUnkOuter,
1435 REFIID riid,
1436 LPVOID *ppvObj)
1438 TestClassFactoryImpl *This = impl_from_IClassFactory(iface);
1439 HRESULT hr;
1440 TestFilterImpl *testfilter;
1442 *ppvObj = NULL;
1444 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1446 hr = createtestfilter(This->clsid, This->filterPinData, &testfilter);
1447 if (SUCCEEDED(hr)) {
1448 hr = IBaseFilter_QueryInterface(&testfilter->IBaseFilter_iface, riid, ppvObj);
1449 IBaseFilter_Release(&testfilter->IBaseFilter_iface);
1451 return hr;
1454 static HRESULT WINAPI Test_IClassFactory_LockServer(
1455 LPCLASSFACTORY iface,
1456 BOOL fLock)
1458 return S_OK;
1461 static IClassFactoryVtbl TestClassFactory_Vtbl =
1463 Test_IClassFactory_QueryInterface,
1464 Test_IClassFactory_AddRef,
1465 Test_IClassFactory_Release,
1466 Test_IClassFactory_CreateInstance,
1467 Test_IClassFactory_LockServer
1470 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1472 IPin *pin = NULL;
1473 PIN_INFO pinInfo;
1474 FILTER_INFO filterInfo;
1475 HRESULT hr;
1477 FilterName[0] = 0;
1479 hr = IPin_ConnectedTo(pFilter->ppPins[0], &pin);
1480 ok(hr == S_OK, "IPin_ConnectedTo failed with %x\n", hr);
1481 if (FAILED(hr)) return hr;
1483 hr = IPin_QueryPinInfo(pin, &pinInfo);
1484 ok(hr == S_OK, "IPin_QueryPinInfo failed with %x\n", hr);
1485 IPin_Release(pin);
1486 if (FAILED(hr)) return hr;
1488 SetLastError(0xdeadbeef);
1489 hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1490 if (hr == S_OK && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1492 IBaseFilter_Release(pinInfo.pFilter);
1493 return E_NOTIMPL;
1495 ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1496 IBaseFilter_Release(pinInfo.pFilter);
1497 if (FAILED(hr)) return hr;
1499 IFilterGraph_Release(filterInfo.pGraph);
1501 WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1503 return S_OK;
1506 static void test_render_filter_priority(void)
1508 /* Tests filter choice priorities in Render(). */
1509 DWORD cookie1 = 0, cookie2 = 0, cookie3 = 0;
1510 HRESULT hr;
1511 IFilterGraph2* pgraph2 = NULL;
1512 IFilterMapper2 *pMapper2 = NULL;
1513 TestFilterImpl *ptestfilter = NULL;
1514 TestFilterImpl *ptestfilter2 = NULL;
1515 static const CLSID CLSID_TestFilter2 = {
1516 0x37a4edb0,
1517 0x4d13,
1518 0x11dd,
1519 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1521 static const CLSID CLSID_TestFilter3 = {
1522 0x37a4f2d8,
1523 0x4d13,
1524 0x11dd,
1525 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1527 static const CLSID CLSID_TestFilter4 = {
1528 0x37a4f3b4,
1529 0x4d13,
1530 0x11dd,
1531 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1533 static const GUID mediasubtype1 = {
1534 0x37a4f51c,
1535 0x4d13,
1536 0x11dd,
1537 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1539 static const GUID mediasubtype2 = {
1540 0x37a4f5c6,
1541 0x4d13,
1542 0x11dd,
1543 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1545 static const TestFilterPinData PinData1[] = {
1546 { PINDIR_OUTPUT, &mediasubtype1 },
1547 { 0, 0 }
1549 static const TestFilterPinData PinData2[] = {
1550 { PINDIR_INPUT, &mediasubtype1 },
1551 { 0, 0 }
1553 static const TestFilterPinData PinData3[] = {
1554 { PINDIR_INPUT, &GUID_NULL },
1555 { 0, 0 }
1557 static const TestFilterPinData PinData4[] = {
1558 { PINDIR_INPUT, &mediasubtype1 },
1559 { PINDIR_OUTPUT, &mediasubtype2 },
1560 { 0, 0 }
1562 static const TestFilterPinData PinData5[] = {
1563 { PINDIR_INPUT, &mediasubtype2 },
1564 { 0, 0 }
1566 TestClassFactoryImpl Filter1ClassFactory = {
1567 { &TestClassFactory_Vtbl },
1568 PinData2, &CLSID_TestFilter2
1570 TestClassFactoryImpl Filter2ClassFactory = {
1571 { &TestClassFactory_Vtbl },
1572 PinData4, &CLSID_TestFilter3
1574 TestClassFactoryImpl Filter3ClassFactory = {
1575 { &TestClassFactory_Vtbl },
1576 PinData5, &CLSID_TestFilter4
1578 char ConnectedFilterName1[MAX_FILTER_NAME];
1579 char ConnectedFilterName2[MAX_FILTER_NAME];
1580 REGFILTER2 rgf2;
1581 REGFILTERPINS2 rgPins2[2];
1582 REGPINTYPES rgPinType[2];
1583 static const WCHAR wszFilterInstanceName1[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1584 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1585 static const WCHAR wszFilterInstanceName2[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1586 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1587 static const WCHAR wszFilterInstanceName3[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1588 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1589 static const WCHAR wszFilterInstanceName4[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1590 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1592 /* Test which renderer of two already added to the graph will be chosen
1593 * (one is "exact" match, other is "wildcard" match. Seems to depend
1594 * on the order in which filters are added to the graph, thus indicating
1595 * no preference given to exact match. */
1596 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1597 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1598 if (!pgraph2) return;
1600 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1601 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1602 if (FAILED(hr)) goto out;
1604 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1605 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1607 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1608 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1609 if (FAILED(hr)) goto out;
1611 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1612 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1614 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1615 ptestfilter2 = NULL;
1617 hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1618 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1619 if (FAILED(hr)) goto out;
1621 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1622 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1624 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1625 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1627 hr = get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1629 IFilterGraph2_Release(pgraph2);
1630 pgraph2 = NULL;
1631 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1632 ptestfilter = NULL;
1633 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1634 ptestfilter2 = NULL;
1636 if (hr == E_NOTIMPL)
1638 win_skip("Needed functions are not implemented\n");
1639 return;
1642 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1643 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1644 if (!pgraph2) goto out;
1646 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1647 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1648 if (FAILED(hr)) goto out;
1650 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1651 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1653 hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1654 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1655 if (FAILED(hr)) goto out;
1657 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1658 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1660 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1661 ptestfilter2 = NULL;
1663 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1664 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1665 if (FAILED(hr)) goto out;
1667 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1668 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1670 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1671 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1673 hr = IFilterGraph2_Disconnect(pgraph2, NULL);
1674 ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr);
1676 get_connected_filter_name(ptestfilter, ConnectedFilterName2);
1677 ok(strcmp(ConnectedFilterName1, ConnectedFilterName2),
1678 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1680 IFilterGraph2_Release(pgraph2);
1681 pgraph2 = NULL;
1682 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1683 ptestfilter = NULL;
1684 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1685 ptestfilter2 = NULL;
1687 /* Test if any preference is given to existing renderer which renders the pin directly vs
1688 an existing renderer which renders the pin indirectly, through an additional middle filter,
1689 again trying different orders of creation. Native appears not to give a preference. */
1691 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1692 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1693 if (!pgraph2) goto out;
1695 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1696 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1697 if (FAILED(hr)) goto out;
1699 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1700 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1702 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1703 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1704 if (FAILED(hr)) goto out;
1706 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1707 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1709 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1710 ptestfilter2 = NULL;
1712 hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
1713 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1714 if (FAILED(hr)) goto out;
1716 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1717 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1719 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1720 ptestfilter2 = NULL;
1722 hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2);
1723 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1724 if (FAILED(hr)) goto out;
1726 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4);
1727 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1729 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1730 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1732 get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1733 ok(!strcmp(ConnectedFilterName1, "TestfilterInstance3") || !strcmp(ConnectedFilterName1, "TestfilterInstance2"),
1734 "unexpected connected filter: %s\n", ConnectedFilterName1);
1736 IFilterGraph2_Release(pgraph2);
1737 pgraph2 = NULL;
1738 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1739 ptestfilter = NULL;
1740 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1741 ptestfilter2 = NULL;
1743 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1744 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1745 if (!pgraph2) goto out;
1747 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1748 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1749 if (FAILED(hr)) goto out;
1751 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1752 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1754 hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
1755 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1756 if (FAILED(hr)) goto out;
1758 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1759 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1761 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1762 ptestfilter2 = NULL;
1764 hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2);
1765 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1766 if (FAILED(hr)) goto out;
1768 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4);
1769 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1771 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1772 ptestfilter2 = NULL;
1774 hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1775 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1776 if (FAILED(hr)) goto out;
1778 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1779 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1781 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1782 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1784 get_connected_filter_name(ptestfilter, ConnectedFilterName2);
1785 ok(!strcmp(ConnectedFilterName2, "TestfilterInstance3") || !strcmp(ConnectedFilterName2, "TestfilterInstance2"),
1786 "unexpected connected filter: %s\n", ConnectedFilterName2);
1787 ok(strcmp(ConnectedFilterName1, ConnectedFilterName2),
1788 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1);
1790 IFilterGraph2_Release(pgraph2);
1791 pgraph2 = NULL;
1792 IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1793 ptestfilter = NULL;
1794 IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1795 ptestfilter2 = NULL;
1797 /* Test if renderers are tried before non-renderers (intermediary filters). */
1798 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (LPVOID*)&pgraph2);
1799 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1800 if (!pgraph2) goto out;
1802 hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pMapper2);
1803 ok(hr == S_OK, "CoCreateInstance failed with %08x\n", hr);
1804 if (!pMapper2) goto out;
1806 hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1807 ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1808 if (FAILED(hr)) goto out;
1810 hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1811 ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1813 /* Register our filters with COM and with Filtermapper. */
1814 hr = CoRegisterClassObject(Filter1ClassFactory.clsid,
1815 (IUnknown *)&Filter1ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1816 REGCLS_MULTIPLEUSE, &cookie1);
1817 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1818 if (FAILED(hr)) goto out;
1819 hr = CoRegisterClassObject(Filter2ClassFactory.clsid,
1820 (IUnknown *)&Filter2ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1821 REGCLS_MULTIPLEUSE, &cookie2);
1822 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1823 if (FAILED(hr)) goto out;
1824 hr = CoRegisterClassObject(Filter3ClassFactory.clsid,
1825 (IUnknown *)&Filter3ClassFactory.IClassFactory_iface, CLSCTX_INPROC_SERVER,
1826 REGCLS_MULTIPLEUSE, &cookie3);
1827 ok(hr == S_OK, "CoRegisterClassObject failed with %08x\n", hr);
1828 if (FAILED(hr)) goto out;
1830 rgf2.dwVersion = 2;
1831 rgf2.dwMerit = MERIT_UNLIKELY;
1832 S2(U(rgf2)).cPins2 = 1;
1833 S2(U(rgf2)).rgPins2 = rgPins2;
1834 rgPins2[0].dwFlags = REG_PINFLAG_B_RENDERER;
1835 rgPins2[0].cInstances = 1;
1836 rgPins2[0].nMediaTypes = 1;
1837 rgPins2[0].lpMediaType = &rgPinType[0];
1838 rgPins2[0].nMediums = 0;
1839 rgPins2[0].lpMedium = NULL;
1840 rgPins2[0].clsPinCategory = NULL;
1841 rgPinType[0].clsMajorType = &MEDIATYPE_Video;
1842 rgPinType[0].clsMinorType = &mediasubtype1;
1844 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter2, wszFilterInstanceName2, NULL,
1845 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1846 if (hr == E_ACCESSDENIED)
1847 skip("Not authorized to register filters\n");
1848 else
1850 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1852 rgf2.dwMerit = MERIT_PREFERRED;
1853 rgPinType[0].clsMinorType = &mediasubtype2;
1855 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter4, wszFilterInstanceName4, NULL,
1856 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1857 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1859 S2(U(rgf2)).cPins2 = 2;
1860 rgPins2[0].dwFlags = 0;
1861 rgPinType[0].clsMinorType = &mediasubtype1;
1863 rgPins2[1].dwFlags = REG_PINFLAG_B_OUTPUT;
1864 rgPins2[1].cInstances = 1;
1865 rgPins2[1].nMediaTypes = 1;
1866 rgPins2[1].lpMediaType = &rgPinType[1];
1867 rgPins2[1].nMediums = 0;
1868 rgPins2[1].lpMedium = NULL;
1869 rgPins2[1].clsPinCategory = NULL;
1870 rgPinType[1].clsMajorType = &MEDIATYPE_Video;
1871 rgPinType[1].clsMinorType = &mediasubtype2;
1873 hr = IFilterMapper2_RegisterFilter(pMapper2, &CLSID_TestFilter3, wszFilterInstanceName3, NULL,
1874 &CLSID_LegacyAmFilterCategory, NULL, &rgf2);
1875 ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1877 hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1878 ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1880 get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1881 ok(!strcmp(ConnectedFilterName1, "TestfilterInstance3"),
1882 "unexpected connected filter: %s\n", ConnectedFilterName1);
1884 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1885 &CLSID_TestFilter2);
1886 ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1887 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1888 &CLSID_TestFilter3);
1889 ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1890 hr = IFilterMapper2_UnregisterFilter(pMapper2, &CLSID_LegacyAmFilterCategory, NULL,
1891 &CLSID_TestFilter4);
1892 ok(hr == S_OK, "IFilterMapper2_UnregisterFilter failed with %x\n", hr);
1895 out:
1897 if (ptestfilter) IBaseFilter_Release(&ptestfilter->IBaseFilter_iface);
1898 if (ptestfilter2) IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1899 if (pgraph2) IFilterGraph2_Release(pgraph2);
1900 if (pMapper2) IFilterMapper2_Release(pMapper2);
1902 hr = CoRevokeClassObject(cookie1);
1903 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1904 hr = CoRevokeClassObject(cookie2);
1905 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1906 hr = CoRevokeClassObject(cookie3);
1907 ok(hr == S_OK, "CoRevokeClassObject failed with %08x\n", hr);
1910 typedef struct IUnknownImpl
1912 IUnknown IUnknown_iface;
1913 int AddRef_called;
1914 int Release_called;
1915 } IUnknownImpl;
1917 static IUnknownImpl *IUnknownImpl_from_iface(IUnknown * iface)
1919 return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
1922 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
1924 ok(0, "QueryInterface should not be called for %s\n", wine_dbgstr_guid(riid));
1925 return E_NOINTERFACE;
1928 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown * iface)
1930 IUnknownImpl *This = IUnknownImpl_from_iface(iface);
1931 This->AddRef_called++;
1932 return 2;
1935 static ULONG WINAPI IUnknownImpl_Release(IUnknown * iface)
1937 IUnknownImpl *This = IUnknownImpl_from_iface(iface);
1938 This->Release_called++;
1939 return 1;
1942 static CONST_VTBL IUnknownVtbl IUnknownImpl_Vtbl =
1944 IUnknownImpl_QueryInterface,
1945 IUnknownImpl_AddRef,
1946 IUnknownImpl_Release
1949 static void test_aggregate_filter_graph(void)
1951 HRESULT hr;
1952 IUnknown *pgraph;
1953 IUnknown *punk;
1954 IUnknownImpl unk_outer = { { &IUnknownImpl_Vtbl }, 0, 0 };
1956 hr = CoCreateInstance(&CLSID_FilterGraph, &unk_outer.IUnknown_iface, CLSCTX_INPROC_SERVER,
1957 &IID_IUnknown, (void **)&pgraph);
1958 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
1959 ok(pgraph != &unk_outer.IUnknown_iface, "pgraph = %p, expected not %p\n", pgraph, &unk_outer.IUnknown_iface);
1961 hr = IUnknown_QueryInterface(pgraph, &IID_IUnknown, (void **)&punk);
1962 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
1963 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
1964 IUnknown_Release(punk);
1966 ok(unk_outer.AddRef_called == 0, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
1967 ok(unk_outer.Release_called == 0, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
1968 unk_outer.AddRef_called = 0;
1969 unk_outer.Release_called = 0;
1971 hr = IUnknown_QueryInterface(pgraph, &IID_IFilterMapper, (void **)&punk);
1972 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
1973 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
1974 IUnknown_Release(punk);
1976 ok(unk_outer.AddRef_called == 1, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
1977 ok(unk_outer.Release_called == 1, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
1978 unk_outer.AddRef_called = 0;
1979 unk_outer.Release_called = 0;
1981 hr = IUnknown_QueryInterface(pgraph, &IID_IFilterMapper2, (void **)&punk);
1982 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
1983 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
1984 IUnknown_Release(punk);
1986 ok(unk_outer.AddRef_called == 1, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
1987 ok(unk_outer.Release_called == 1, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
1988 unk_outer.AddRef_called = 0;
1989 unk_outer.Release_called = 0;
1991 hr = IUnknown_QueryInterface(pgraph, &IID_IFilterMapper3, (void **)&punk);
1992 ok(hr == S_OK, "CoCreateInstance returned %x\n", hr);
1993 ok(punk != &unk_outer.IUnknown_iface, "punk = %p, expected not %p\n", punk, &unk_outer.IUnknown_iface);
1994 IUnknown_Release(punk);
1996 ok(unk_outer.AddRef_called == 1, "IUnknownImpl_AddRef called %d times\n", unk_outer.AddRef_called);
1997 ok(unk_outer.Release_called == 1, "IUnknownImpl_Release called %d times\n", unk_outer.Release_called);
1999 IUnknown_Release(pgraph);
2002 START_TEST(filtergraph)
2004 HRESULT hr;
2005 CoInitializeEx(NULL, COINIT_MULTITHREADED);
2006 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
2007 &IID_IGraphBuilder, (LPVOID*)&pgraph);
2008 if (FAILED(hr)) {
2009 skip("Creating filtergraph returned %08x, skipping tests\n", hr);
2010 return;
2012 IGraphBuilder_Release(pgraph);
2013 test_render_run(avifile);
2014 test_render_run(mpegfile);
2015 test_graph_builder();
2016 test_graph_builder_addfilter();
2017 test_mediacontrol();
2018 test_filter_graph2();
2019 test_render_filter_priority();
2020 test_aggregate_filter_graph();
2021 CoUninitialize();