~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/quartz/tests/filtergraph.c

Version: ~ [ wine-1.5.4 ] ~ [ wine-1.5.3 ] ~ [ wine-1.5.2 ] ~ [ wine-1.5.1 ] ~ [ wine-1.5.0 ] ~ [ wine-1.4 ] ~ [ wine-1.4-rc6 ] ~ [ wine-1.4-rc5 ] ~ [ wine-1.4-rc4 ] ~ [ wine-1.4-rc3 ] ~ [ wine-1.4-rc2 ] ~ [ wine-1.4-rc1 ] ~ [ wine-1.3.37 ] ~ [ wine-1.3.36 ] ~ [ wine-1.3.35 ] ~ [ wine-1.3.34 ] ~ [ wine-1.3.33 ] ~ [ wine-1.3.32 ] ~ [ wine-1.3.31 ] ~ [ wine-1.3.30 ] ~ [ wine-1.3.29 ] ~ [ wine-1.3.28 ] ~ [ wine-1.3.27 ] ~ [ wine-1.3.26 ] ~ [ wine-1.3.25 ] ~ [ wine-1.3.24 ] ~ [ wine-1.3.23 ] ~ [ wine-1.3.22 ] ~ [ wine-1.3.21 ] ~ [ wine-1.3.20 ] ~ [ wine-1.3.19 ] ~ [ wine-1.3.18 ] ~ [ wine-1.2.3 ] ~ [ wine-1.3.17 ] ~ [ wine-1.3.16 ] ~ [ wine-1.3.15 ] ~ [ wine-1.3.14 ] ~ [ wine-1.3.13 ] ~ [ wine-1.3.12 ] ~ [ wine-1.3.11 ] ~ [ wine-1.3.10 ] ~ [ wine-1.3.9 ] ~ [ wine-1.2.2 ] ~ [ wine-1.3.8 ] ~ [ wine-1.3.7 ] ~ [ wine-1.3.6 ] ~ [ wine-1.3.5 ] ~ [ wine-1.2.1 ] ~ [ wine-1.3.4 ] ~ [ wine-1.3.3 ] ~ [ wine-1.3.2 ] ~ [ wine-1.3.1 ] ~ [ wine-1.3.0 ] ~ [ wine-1.2 ] ~ [ wine-1.2-rc7 ] ~ [ wine-1.2-rc6 ] ~ [ wine-1.2-rc5 ] ~ [ wine-1.2-rc4 ] ~ [ wine-1.2-rc3 ] ~ [ wine-1.2-rc2 ] ~ [ wine-1.2-rc1 ] ~ [ wine-1.1.44 ] ~ [ wine-1.1.43 ] ~ [ wine-1.1.42 ] ~ [ wine-1.1.41 ] ~ [ wine-1.1.40 ] ~ [ wine-1.1.39 ] ~ [ wine-1.1.38 ] ~ [ wine-1.1.37 ] ~ [ wine-1.1.36 ] ~ [ wine-1.1.35 ] ~ [ wine-1.1.34 ] ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /*
  2  * Unit tests for Direct Show functions
  3  *
  4  * Copyright (C) 2004 Christian Costa
  5  * Copyright (C) 2008 Alexander Dorofeyev
  6  *
  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.
 11  *
 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.
 16  *
 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
 20  */
 21 
 22 #define COBJMACROS
 23 #define CONST_VTABLE
 24 
 25 #include "wine/test.h"
 26 #include "dshow.h"
 27 #include "control.h"
 28 
 29 typedef struct TestFilterImpl
 30 {
 31     IBaseFilter IBaseFilter_iface;
 32 
 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;
 41 
 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};
 44 
 45 static IGraphBuilder *pgraph;
 46 
 47 static int createfiltergraph(void)
 48 {
 49     return S_OK == CoCreateInstance(
 50         &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&pgraph);
 51 }
 52 
 53 static void rungraph(void)
 54 {
 55     HRESULT hr;
 56     IMediaControl* pmc;
 57     IMediaEvent* pme;
 58     IMediaFilter* pmf;
 59     HANDLE hEvent;
 60 
 61     hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaControl, (LPVOID*)&pmc);
 62     ok(hr==S_OK, "Cannot get IMediaControl interface returned: %x\n", hr);
 63 
 64     hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaFilter, (LPVOID*)&pmf);
 65     ok(hr==S_OK, "Cannot get IMediaFilter interface returned: %x\n", hr);
 66 
 67     IMediaControl_Stop(pmc);
 68 
 69     IMediaFilter_SetSyncSource(pmf, NULL);
 70 
 71     IMediaFilter_Release(pmf);
 72 
 73     hr = IMediaControl_Run(pmc);
 74     ok(hr==S_FALSE, "Cannot run the graph returned: %x\n", hr);
 75 
 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);
 81 
 82     IGraphBuilder_SetDefaultSyncSource(pgraph);
 83 
 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);
 88 
 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);
 93 
 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);
 98 
 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);
103 
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);
108 
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);
112 
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);
116 
117     hr = IGraphBuilder_QueryInterface(pgraph, &IID_IMediaEvent, (LPVOID*)&pme);
118     ok(hr==S_OK, "Cannot get IMediaEvent interface returned: %x\n", hr);
119 
120     hr = IMediaEvent_GetEventHandle(pme, (OAEVENT*)&hEvent);
121     ok(hr==S_OK, "Cannot get event handle returned: %x\n", hr);
122 
123     /* WaitForSingleObject(hEvent, INFINITE); */
124     Sleep(20000);
125 
126     hr = IMediaEvent_Release(pme);
127     ok(hr==2, "Releasing mediaevent returned: %x\n", hr);
128 
129     hr = IMediaControl_Stop(pmc);
130     ok(hr==S_OK, "Cannot stop the graph returned: %x\n", hr);
131     
132     hr = IMediaControl_Release(pmc);
133     ok(hr==1, "Releasing mediacontrol returned: %x\n", hr);
134 }
135 
136 static void releasefiltergraph(void)
137 {
138     HRESULT hr;
139 
140     hr = IGraphBuilder_Release(pgraph);
141     ok(hr==0, "Releasing filtergraph returned: %x\n", hr);
142 }
143 
144 static void test_render_run(const WCHAR *file)
145 {
146     HANDLE h;
147     HRESULT hr;
148 
149     if (!createfiltergraph())
150         return;
151 
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();
158     }
159 
160     releasefiltergraph();
161 }
162 
163 static void test_graph_builder(void)
164 {
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};
173 
174     if (!createfiltergraph())
175         return;
176 
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");
182 
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);
186 
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");
197 
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);
206 
207     if (pIn) IPin_Release(pIn);
208     if (pEnum) IEnumPins_Release(pEnum);
209     if (pF) IBaseFilter_Release(pF);
210     if (pF2) IBaseFilter_Release(pF2);
211 
212     releasefiltergraph();
213 }
214 
215 static void test_graph_builder_addfilter(void)
216 {
217     HRESULT hr;
218     IBaseFilter *pF = NULL;
219     static const WCHAR testFilterW[] = {'t','e','s','t','F','i','l','t','e','r',0};
220 
221     if (!createfiltergraph())
222         return;
223 
224     hr = IGraphBuilder_AddFilter(pgraph, NULL, testFilterW);
225     ok(hr == E_POINTER, "IGraphBuilder_AddFilter returned: %x\n", hr);
226 
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;
235     }
236 
237     hr = IGraphBuilder_AddFilter(pgraph, pF, NULL);
238     ok(hr == S_OK, "IGraphBuilder_AddFilter returned: %x\n", hr);
239     IMediaFilter_Release(pF);
240 }
241 
242 static void test_mediacontrol(void)
243 {
244     HRESULT hr;
245     LONGLONG pos = 0xdeadbeef;
246     IMediaSeeking *seeking = NULL;
247     IMediaFilter *filter = NULL;
248     IMediaControl *control = NULL;
249 
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;
255 
256     hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaFilter, (void**) &filter);
257     ok(hr == S_OK, "QueryInterface IMediaFilter failed: %08x\n", hr);
258     if (FAILED(hr))
259     {
260         IUnknown_Release(seeking);
261         return;
262     }
263 
264     hr = IFilterGraph2_QueryInterface(pgraph, &IID_IMediaControl, (void**) &control);
265     ok(hr == S_OK, "QueryInterface IMediaControl failed: %08x\n", hr);
266     if (FAILED(hr))
267     {
268         IUnknown_Release(seeking);
269         IUnknown_Release(filter);
270         return;
271     }
272 
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);
276 
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);
281 
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);
287 
288     hr = IMediaControl_GetState(control, 1000, NULL);
289     ok(hr == E_POINTER, "GetState expected %08x, got %08x\n", E_POINTER, hr);
290 
291     IUnknown_Release(control);
292     IUnknown_Release(seeking);
293     IUnknown_Release(filter);
294     releasefiltergraph();
295 }
296 
297 static void test_filter_graph2(void)
298 {
299     HRESULT hr;
300     IFilterGraph2 *pF = NULL;
301 
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");
306 
307     hr = IFilterGraph2_Release(pF);
308     ok(hr == 0, "IFilterGraph2_Release returned: %x\n", hr);
309 }
310 
311 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
312 static void FreeMediaType(AM_MEDIA_TYPE * pMediaType)
313 {
314     if (pMediaType->pbFormat)
315     {
316         CoTaskMemFree(pMediaType->pbFormat);
317         pMediaType->pbFormat = NULL;
318     }
319     if (pMediaType->pUnk)
320     {
321         IUnknown_Release(pMediaType->pUnk);
322         pMediaType->pUnk = NULL;
323     }
324 }
325 
326 static HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
327 {
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;
336 }
337 
338 static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc)
339 {
340     AM_MEDIA_TYPE * pDest;
341 
342     pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
343     if (!pDest)
344         return NULL;
345 
346     if (FAILED(CopyMediaType(pDest, pSrc)))
347     {
348         CoTaskMemFree(pDest);
349         return NULL;
350     }
351 
352     return pDest;
353 }
354 
355 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
356 {
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)));
359 }
360 
361 static void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
362 {
363     FreeMediaType(pMediaType);
364     CoTaskMemFree(pMediaType);
365 }
366 
367 typedef struct IEnumMediaTypesImpl
368 {
369     IEnumMediaTypes IEnumMediaTypes_iface;
370     LONG refCount;
371     AM_MEDIA_TYPE *pMediaTypes;
372     ULONG cMediaTypes;
373     ULONG uIndex;
374 } IEnumMediaTypesImpl;
375 
376 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
377 
378 static inline IEnumMediaTypesImpl *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
379 {
380     return CONTAINING_RECORD(iface, IEnumMediaTypesImpl, IEnumMediaTypes_iface);
381 }
382 
383 static HRESULT IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE * pMediaTypes, ULONG cMediaTypes, IEnumMediaTypes ** ppEnum)
384 {
385     ULONG i;
386     IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
387 
388     if (!pEnumMediaTypes)
389     {
390         *ppEnum = NULL;
391         return E_OUTOFMEMORY;
392     }
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])))
400         {
401            while (i--)
402               FreeMediaType(&pEnumMediaTypes->pMediaTypes[i]);
403            CoTaskMemFree(pEnumMediaTypes->pMediaTypes);
404            return E_OUTOFMEMORY;
405         }
406     *ppEnum = &pEnumMediaTypes->IEnumMediaTypes_iface;
407     return S_OK;
408 }
409 
410 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
411 {
412     *ppv = NULL;
413 
414     if (IsEqualIID(riid, &IID_IUnknown))
415         *ppv = iface;
416     else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
417         *ppv = iface;
418 
419     if (*ppv)
420     {
421         IUnknown_AddRef((IUnknown *)(*ppv));
422         return S_OK;
423     }
424 
425     return E_NOINTERFACE;
426 }
427 
428 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
429 {
430     IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
431     ULONG refCount = InterlockedIncrement(&This->refCount);
432 
433     return refCount;
434 }
435 
436 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
437 {
438     IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
439     ULONG refCount = InterlockedDecrement(&This->refCount);
440 
441     if (!refCount)
442     {
443         int i;
444         for (i = 0; i < This->cMediaTypes; i++)
445             FreeMediaType(&This->pMediaTypes[i]);
446         CoTaskMemFree(This->pMediaTypes);
447         CoTaskMemFree(This);
448     }
449     return refCount;
450 }
451 
452 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
453 {
454     ULONG cFetched;
455     IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
456 
457     cFetched = min(This->cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
458 
459     if (cFetched > 0)
460     {
461         ULONG i;
462         for (i = 0; i < cFetched; i++)
463             if (!(ppMediaTypes[i] = CreateMediaType(&This->pMediaTypes[This->uIndex + i])))
464             {
465                 while (i--)
466                     DeleteMediaType(ppMediaTypes[i]);
467                 *pcFetched = 0;
468                 return E_OUTOFMEMORY;
469             }
470     }
471 
472     if ((cMediaTypes != 1) || pcFetched)
473         *pcFetched = cFetched;
474 
475     This->uIndex += cFetched;
476 
477     if (cFetched != cMediaTypes)
478         return S_FALSE;
479     return S_OK;
480 }
481 
482 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
483 {
484     IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
485 
486     if (This->uIndex + cMediaTypes < This->cMediaTypes)
487     {
488         This->uIndex += cMediaTypes;
489         return S_OK;
490     }
491     return S_FALSE;
492 }
493 
494 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
495 {
496     IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
497 
498     This->uIndex = 0;
499     return S_OK;
500 }
501 
502 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
503 {
504     HRESULT hr;
505     IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
506 
507     hr = IEnumMediaTypesImpl_Construct(This->pMediaTypes, This->cMediaTypes, ppEnum);
508     if (FAILED(hr))
509         return hr;
510     return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
511 }
512 
513 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
514 {
515     IEnumMediaTypesImpl_QueryInterface,
516     IEnumMediaTypesImpl_AddRef,
517     IEnumMediaTypesImpl_Release,
518     IEnumMediaTypesImpl_Next,
519     IEnumMediaTypesImpl_Skip,
520     IEnumMediaTypesImpl_Reset,
521     IEnumMediaTypesImpl_Clone
522 };
523 
524 /* Implementation of a very stripped down pin for the test filter. Just enough
525    functionality for connecting and Render() to work. */
526 
527 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
528 {
529     lstrcpyW(pDest->achName, pSrc->achName);
530     pDest->dir = pSrc->dir;
531     pDest->pFilter = pSrc->pFilter;
532 }
533 
534 typedef struct ITestPinImpl
535 {
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;
544 
545 static inline ITestPinImpl *impl_from_IPin(IPin *iface)
546 {
547     return CONTAINING_RECORD(iface, ITestPinImpl, IPin_iface);
548 }
549 
550 static HRESULT WINAPI  TestFilter_Pin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
551 {
552     *ppv = NULL;
553 
554     if (IsEqualIID(riid, &IID_IUnknown))
555         *ppv = iface;
556     else if (IsEqualIID(riid, &IID_IPin))
557         *ppv = iface;
558 
559     if (*ppv)
560     {
561         IUnknown_AddRef((IUnknown *)(*ppv));
562         return S_OK;
563     }
564 
565     return E_NOINTERFACE;
566 }
567 
568 static ULONG WINAPI TestFilter_Pin_AddRef(IPin * iface)
569 {
570     ITestPinImpl *This = impl_from_IPin(iface);
571     ULONG refCount = InterlockedIncrement(&This->refCount);
572     return refCount;
573 }
574 
575 static ULONG WINAPI TestFilter_Pin_Release(IPin * iface)
576 {
577     ITestPinImpl *This = impl_from_IPin(iface);
578     ULONG refCount = InterlockedDecrement(&This->refCount);
579 
580     if (!refCount)
581     {
582         FreeMediaType(&This->mtCurrent);
583         CoTaskMemFree(This);
584         return 0;
585     }
586     else
587         return refCount;
588 }
589 
590 static HRESULT WINAPI TestFilter_InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
591 {
592     return E_UNEXPECTED;
593 }
594 
595 static HRESULT WINAPI TestFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
596 {
597     ITestPinImpl *This = impl_from_IPin(iface);
598     PIN_DIRECTION pindirReceive;
599     HRESULT hr = S_OK;
600 
601     EnterCriticalSection(This->pCritSec);
602     {
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;
606 
607         if (This->pConnectedTo)
608             hr = VFW_E_ALREADY_CONNECTED;
609 
610         if (SUCCEEDED(hr))
611         {
612             IPin_QueryDirection(pReceivePin, &pindirReceive);
613 
614             if (pindirReceive != PINDIR_OUTPUT)
615             {
616                 hr = VFW_E_INVALID_DIRECTION;
617             }
618         }
619 
620         if (SUCCEEDED(hr))
621         {
622             CopyMediaType(&This->mtCurrent, pmt);
623             This->pConnectedTo = pReceivePin;
624             IPin_AddRef(pReceivePin);
625         }
626     }
627     LeaveCriticalSection(This->pCritSec);
628 
629     return hr;
630 }
631 
632 static HRESULT WINAPI TestFilter_Pin_Disconnect(IPin * iface)
633 {
634     HRESULT hr;
635     ITestPinImpl *This = impl_from_IPin(iface);
636 
637     EnterCriticalSection(This->pCritSec);
638     {
639         if (This->pConnectedTo)
640         {
641             IPin_Release(This->pConnectedTo);
642             This->pConnectedTo = NULL;
643             hr = S_OK;
644         }
645         else
646             hr = S_FALSE;
647     }
648     LeaveCriticalSection(This->pCritSec);
649 
650     return hr;
651 }
652 
653 static HRESULT WINAPI TestFilter_Pin_ConnectedTo(IPin * iface, IPin ** ppPin)
654 {
655     HRESULT hr;
656     ITestPinImpl *This = impl_from_IPin(iface);
657 
658     EnterCriticalSection(This->pCritSec);
659     {
660         if (This->pConnectedTo)
661         {
662             *ppPin = This->pConnectedTo;
663             IPin_AddRef(*ppPin);
664             hr = S_OK;
665         }
666         else
667         {
668             hr = VFW_E_NOT_CONNECTED;
669             *ppPin = NULL;
670         }
671     }
672     LeaveCriticalSection(This->pCritSec);
673 
674     return hr;
675 }
676 
677 static HRESULT WINAPI TestFilter_Pin_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
678 {
679     HRESULT hr;
680     ITestPinImpl *This = impl_from_IPin(iface);
681 
682     EnterCriticalSection(This->pCritSec);
683     {
684         if (This->pConnectedTo)
685         {
686             CopyMediaType(pmt, &This->mtCurrent);
687             hr = S_OK;
688         }
689         else
690         {
691             ZeroMemory(pmt, sizeof(*pmt));
692             hr = VFW_E_NOT_CONNECTED;
693         }
694     }
695     LeaveCriticalSection(This->pCritSec);
696 
697     return hr;
698 }
699 
700 static HRESULT WINAPI TestFilter_Pin_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
701 {
702     ITestPinImpl *This = impl_from_IPin(iface);
703 
704     Copy_PinInfo(pInfo, &This->pinInfo);
705     IBaseFilter_AddRef(pInfo->pFilter);
706 
707     return S_OK;
708 }
709 
710 static HRESULT WINAPI TestFilter_Pin_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
711 {
712     ITestPinImpl *This = impl_from_IPin(iface);
713 
714     *pPinDir = This->pinInfo.dir;
715 
716     return S_OK;
717 }
718 
719 static HRESULT WINAPI TestFilter_Pin_QueryId(IPin * iface, LPWSTR * Id)
720 {
721     return E_NOTIMPL;
722 }
723 
724 static HRESULT WINAPI TestFilter_Pin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
725 {
726     ITestPinImpl *This = impl_from_IPin(iface);
727 
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;
733 }
734 
735 static HRESULT WINAPI TestFilter_Pin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
736 {
737     ITestPinImpl *This = impl_from_IPin(iface);
738 
739     return IEnumMediaTypesImpl_Construct(&This->mtCurrent, 1, ppEnum);
740 }
741 
742 static HRESULT WINAPI  TestFilter_Pin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
743 {
744     return E_NOTIMPL;
745 }
746 
747 static HRESULT WINAPI TestFilter_Pin_BeginFlush(IPin * iface)
748 {
749     return E_NOTIMPL;
750 }
751 
752 static HRESULT WINAPI TestFilter_Pin_EndFlush(IPin * iface)
753 {
754     return E_NOTIMPL;
755 }
756 
757 static HRESULT WINAPI TestFilter_Pin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
758 {
759     return E_NOTIMPL;
760 }
761 
762 static HRESULT WINAPI TestFilter_Pin_EndOfStream(IPin * iface)
763 {
764     return E_NOTIMPL;
765 }
766 
767 static const IPinVtbl TestFilter_InputPin_Vtbl =
768 {
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
787 };
788 
789 static HRESULT WINAPI TestFilter_OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
790 {
791     return E_UNEXPECTED;
792 }
793 
794 /* Private helper function */
795 static HRESULT TestFilter_OutputPin_ConnectSpecific(ITestPinImpl * This, IPin * pReceivePin,
796         const AM_MEDIA_TYPE * pmt)
797 {
798     HRESULT hr;
799 
800     This->pConnectedTo = pReceivePin;
801     IPin_AddRef(pReceivePin);
802 
803     hr = IPin_ReceiveConnection(pReceivePin, &This->IPin_iface, pmt);
804 
805     if (FAILED(hr))
806     {
807         IPin_Release(This->pConnectedTo);
808         This->pConnectedTo = NULL;
809     }
810 
811     return hr;
812 }
813 
814 static HRESULT WINAPI TestFilter_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
815 {
816     ITestPinImpl *This = impl_from_IPin(iface);
817     HRESULT hr;
818 
819     EnterCriticalSection(This->pCritSec);
820     {
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
826         {
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);
834 
835     return hr;
836 }
837 
838 static const IPinVtbl TestFilter_OutputPin_Vtbl =
839 {
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
858 };
859 
860 static HRESULT TestFilter_Pin_Construct(const IPinVtbl *Pin_Vtbl, const PIN_INFO * pPinInfo, AM_MEDIA_TYPE *pinmt,
861                                         LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
862 {
863     ITestPinImpl * pPinImpl;
864 
865     *ppPin = NULL;
866 
867     pPinImpl = CoTaskMemAlloc(sizeof(ITestPinImpl));
868 
869     if (!pPinImpl)
870         return E_OUTOFMEMORY;
871 
872     pPinImpl->refCount = 1;
873     pPinImpl->pConnectedTo = NULL;
874     pPinImpl->pCritSec = pCritSec;
875     Copy_PinInfo(&pPinImpl->pinInfo, pPinInfo);
876     pPinImpl->mtCurrent = *pinmt;
877 
878     pPinImpl->IPin_iface.lpVtbl = Pin_Vtbl;
879 
880     *ppPin = &pPinImpl->IPin_iface;
881     return S_OK;
882 }
883 
884 /* IEnumPins implementation */
885 
886 typedef HRESULT (* FNOBTAINPIN)(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick);
887 
888 typedef struct IEnumPinsImpl
889 {
890     IEnumPins IEnumPins_iface;
891     LONG refCount;
892     ULONG uIndex;
893     TestFilterImpl *base;
894     FNOBTAINPIN receive_pin;
895     DWORD synctime;
896 } IEnumPinsImpl;
897 
898 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
899 
900 static inline IEnumPinsImpl *impl_from_IEnumPins(IEnumPins *iface)
901 {
902     return CONTAINING_RECORD(iface, IEnumPinsImpl, IEnumPins_iface);
903 }
904 
905 static HRESULT createenumpins(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, TestFilterImpl *base)
906 {
907     IEnumPinsImpl * pEnumPins;
908 
909     if (!ppEnum)
910         return E_POINTER;
911 
912     pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
913     if (!pEnumPins)
914     {
915         *ppEnum = NULL;
916         return E_OUTOFMEMORY;
917     }
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;
925 
926     receive_pin(base, ~0, NULL, &pEnumPins->synctime);
927 
928     return S_OK;
929 }
930 
931 static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
932 {
933     *ppv = NULL;
934 
935     if (IsEqualIID(riid, &IID_IUnknown))
936         *ppv = iface;
937     else if (IsEqualIID(riid, &IID_IEnumPins))
938         *ppv = iface;
939 
940     if (*ppv)
941     {
942         IUnknown_AddRef((IUnknown *)(*ppv));
943         return S_OK;
944     }
945 
946     return E_NOINTERFACE;
947 }
948 
949 static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
950 {
951     IEnumPinsImpl *This = impl_from_IEnumPins(iface);
952     ULONG refCount = InterlockedIncrement(&This->refCount);
953 
954     return refCount;
955 }
956 
957 static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
958 {
959     IEnumPinsImpl *This = impl_from_IEnumPins(iface);
960     ULONG refCount = InterlockedDecrement(&This->refCount);
961 
962     if (!refCount)
963     {
964         IBaseFilter_Release(&This->base->IBaseFilter_iface);
965         CoTaskMemFree(This);
966         return 0;
967     }
968     else
969         return refCount;
970 }
971 
972 static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
973 {
974     IEnumPinsImpl *This = impl_from_IEnumPins(iface);
975     DWORD synctime = This->synctime;
976     HRESULT hr = S_OK;
977     ULONG i = 0;
978 
979     if (!ppPins)
980         return E_POINTER;
981 
982     if (cPins > 1 && !pcFetched)
983         return E_INVALIDARG;
984 
985     if (pcFetched)
986         *pcFetched = 0;
987 
988     while (i < cPins && hr == S_OK)
989     {
990         hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime);
991 
992         if (hr == S_OK)
993             ++i;
994 
995         if (synctime != This->synctime)
996             break;
997     }
998 
999     if (!i && synctime != This->synctime)
1000         return VFW_E_ENUM_OUT_OF_SYNC;
1001 
1002     if (pcFetched)
1003         *pcFetched = i;
1004     This->uIndex += i;
1005 
1006     if (i < cPins)
1007         return S_FALSE;
1008     return S_OK;
1009 }
1010 
1011 static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
1012 {
1013     IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1014     DWORD synctime = This->synctime;
1015     HRESULT hr;
1016     IPin *pin = NULL;
1017 
1018     hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime);
1019     if (pin)
1020         IPin_Release(pin);
1021 
1022     if (synctime != This->synctime)
1023         return VFW_E_ENUM_OUT_OF_SYNC;
1024 
1025     if (hr == S_OK)
1026         This->uIndex += cPins;
1027 
1028     return hr;
1029 }
1030 
1031 static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
1032 {
1033     IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1034 
1035     This->receive_pin(This->base, ~0, NULL, &This->synctime);
1036 
1037     This->uIndex = 0;
1038     return S_OK;
1039 }
1040 
1041 static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
1042 {
1043     HRESULT hr;
1044     IEnumPinsImpl *This = impl_from_IEnumPins(iface);
1045 
1046     hr = createenumpins(ppEnum, This->receive_pin, This->base);
1047     if (FAILED(hr))
1048         return hr;
1049     return IEnumPins_Skip(*ppEnum, This->uIndex);
1050 }
1051 
1052 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
1053 {
1054     IEnumPinsImpl_QueryInterface,
1055     IEnumPinsImpl_AddRef,
1056     IEnumPinsImpl_Release,
1057     IEnumPinsImpl_Next,
1058     IEnumPinsImpl_Skip,
1059     IEnumPinsImpl_Reset,
1060     IEnumPinsImpl_Clone
1061 };
1062 
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(). */
1065 
1066 typedef struct TestFilterPinData
1067 {
1068 PIN_DIRECTION pinDir;
1069 const GUID *mediasubtype;
1070 } TestFilterPinData;
1071 
1072 static const IBaseFilterVtbl TestFilter_Vtbl;
1073 
1074 static inline TestFilterImpl *impl_from_IBaseFilter(IBaseFilter *iface)
1075 {
1076     return CONTAINING_RECORD(iface, TestFilterImpl, IBaseFilter_iface);
1077 }
1078 
1079 static HRESULT createtestfilter(const CLSID* pClsid, const TestFilterPinData *pinData,
1080         TestFilterImpl **tf)
1081 {
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;
1089 
1090     pTestFilter = CoTaskMemAlloc(sizeof(TestFilterImpl));
1091     if (!pTestFilter) return E_OUTOFMEMORY;
1092 
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;
1099 
1100     ZeroMemory(&pTestFilter->filterInfo, sizeof(FILTER_INFO));
1101 
1102     nPins = 0;
1103     while(pinData[nPins].mediasubtype) ++nPins;
1104 
1105     pTestFilter->ppPins = CoTaskMemAlloc(nPins * sizeof(IPin *));
1106     if (!pTestFilter->ppPins)
1107     {
1108         hr = E_OUTOFMEMORY;
1109         goto error;
1110     }
1111     ZeroMemory(pTestFilter->ppPins, nPins * sizeof(IPin *));
1112 
1113     for (i = 0; i < nPins; i++)
1114     {
1115         ZeroMemory(&mt, sizeof(mt));
1116         mt.majortype = MEDIATYPE_Video;
1117         mt.formattype = FORMAT_None;
1118         mt.subtype = *pinData[i].mediasubtype;
1119 
1120         pinInfo.dir = pinData[i].pinDir;
1121         pinInfo.pFilter = &pTestFilter->IBaseFilter_iface;
1122         if (pinInfo.dir == PINDIR_INPUT)
1123         {
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]);
1127 
1128         }
1129         else
1130         {
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]);
1134         }
1135         if (FAILED(hr) || !pTestFilter->ppPins[i]) goto error;
1136     }
1137 
1138     pTestFilter->nPins = nPins;
1139     *tf = pTestFilter;
1140     return S_OK;
1141 
1142     error:
1143 
1144     if (pTestFilter->ppPins)
1145     {
1146         for (i = 0; i < nPins; i++)
1147         {
1148             if (pTestFilter->ppPins[i]) IPin_Release(pTestFilter->ppPins[i]);
1149         }
1150     }
1151     CoTaskMemFree(pTestFilter->ppPins);
1152     pTestFilter->csFilter.DebugInfo->Spare[0] = 0;
1153     DeleteCriticalSection(&pTestFilter->csFilter);
1154     CoTaskMemFree(pTestFilter);
1155 
1156     return hr;
1157 }
1158 
1159 static HRESULT WINAPI TestFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
1160 {
1161     TestFilterImpl *This = impl_from_IBaseFilter(iface);
1162 
1163     *ppv = NULL;
1164 
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;
1173 
1174     if (*ppv)
1175     {
1176         IUnknown_AddRef((IUnknown *)(*ppv));
1177         return S_OK;
1178     }
1179 
1180     return E_NOINTERFACE;
1181 }
1182 
1183 static ULONG WINAPI TestFilter_AddRef(IBaseFilter * iface)
1184 {
1185     TestFilterImpl *This = impl_from_IBaseFilter(iface);
1186     ULONG refCount = InterlockedIncrement(&This->refCount);
1187 
1188     return refCount;
1189 }
1190 
1191 static ULONG WINAPI TestFilter_Release(IBaseFilter * iface)
1192 {
1193     TestFilterImpl *This = impl_from_IBaseFilter(iface);
1194     ULONG refCount = InterlockedDecrement(&This->refCount);
1195 
1196     if (!refCount)
1197     {
1198         ULONG i;
1199 
1200         for (i = 0; i < This->nPins; i++)
1201         {
1202             IPin *pConnectedTo;
1203 
1204             if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
1205             {
1206                 IPin_Disconnect(pConnectedTo);
1207                 IPin_Release(pConnectedTo);
1208             }
1209             IPin_Disconnect(This->ppPins[i]);
1210 
1211             IPin_Release(This->ppPins[i]);
1212         }
1213 
1214         CoTaskMemFree(This->ppPins);
1215 
1216         This->csFilter.DebugInfo->Spare[0] = 0;
1217         DeleteCriticalSection(&This->csFilter);
1218 
1219         CoTaskMemFree(This);
1220 
1221         return 0;
1222     }
1223     else
1224         return refCount;
1225 }
1226 /** IPersist methods **/
1227 
1228 static HRESULT WINAPI TestFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
1229 {
1230     TestFilterImpl *This = impl_from_IBaseFilter(iface);
1231 
1232     *pClsid = This->clsid;
1233 
1234     return S_OK;
1235 }
1236 
1237 /** IMediaFilter methods **/
1238 
1239 static HRESULT WINAPI TestFilter_Stop(IBaseFilter * iface)
1240 {
1241     return E_NOTIMPL;
1242 }
1243 
1244 static HRESULT WINAPI TestFilter_Pause(IBaseFilter * iface)
1245 {
1246     return E_NOTIMPL;
1247 }
1248 
1249 static HRESULT WINAPI TestFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
1250 {
1251     return E_NOTIMPL;
1252 }
1253 
1254 static HRESULT WINAPI TestFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
1255 {
1256     TestFilterImpl *This = impl_from_IBaseFilter(iface);
1257 
1258     EnterCriticalSection(&This->csFilter);
1259     {
1260         *pState = This->state;
1261     }
1262     LeaveCriticalSection(&This->csFilter);
1263 
1264     return S_OK;
1265 }
1266 
1267 static HRESULT WINAPI TestFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
1268 {
1269     return E_NOTIMPL;
1270 }
1271 
1272 static HRESULT WINAPI TestFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
1273 {
1274     return E_NOTIMPL;
1275 }
1276 
1277 /** IBaseFilter implementation **/
1278 
1279 static HRESULT getpin_callback(TestFilterImpl *tf, ULONG pos, IPin **pin, DWORD *lastsynctick)
1280 {
1281     /* Our pins are static, not changing so setting static tick count is ok */
1282     *lastsynctick = 0;
1283 
1284     if (pos >= tf->nPins)
1285         return S_FALSE;
1286 
1287     *pin = tf->ppPins[pos];
1288     IPin_AddRef(*pin);
1289     return S_OK;
1290 }
1291 
1292 static HRESULT WINAPI TestFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
1293 {
1294     TestFilterImpl *This = impl_from_IBaseFilter(iface);
1295 
1296     return createenumpins(ppEnum, getpin_callback, This);
1297 }
1298 
1299 static HRESULT WINAPI TestFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
1300 {
1301     return E_NOTIMPL;
1302 }
1303 
1304 static HRESULT WINAPI TestFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
1305 {
1306     TestFilterImpl *This = impl_from_IBaseFilter(iface);
1307 
1308     lstrcpyW(pInfo->achName, This->filterInfo.achName);
1309     pInfo->pGraph = This->filterInfo.pGraph;
1310 
1311     if (pInfo->pGraph)
1312         IFilterGraph_AddRef(pInfo->pGraph);
1313 
1314     return S_OK;
1315 }
1316 
1317 static HRESULT WINAPI TestFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
1318 {
1319     HRESULT hr = S_OK;
1320     TestFilterImpl *This = impl_from_IBaseFilter(iface);
1321 
1322     EnterCriticalSection(&This->csFilter);
1323     {
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 */
1329     }
1330     LeaveCriticalSection(&This->csFilter);
1331 
1332     return hr;
1333 }
1334 
1335 static HRESULT WINAPI TestFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1336 {
1337     return E_NOTIMPL;
1338 }
1339 
1340 static const IBaseFilterVtbl TestFilter_Vtbl =
1341 {
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
1357 };
1358 
1359 /* IClassFactory implementation */
1360 
1361 typedef struct TestClassFactoryImpl
1362 {
1363     IClassFactory IClassFactory_iface;
1364     const TestFilterPinData *filterPinData;
1365     const CLSID *clsid;
1366 } TestClassFactoryImpl;
1367 
1368 static inline TestClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
1369 {
1370     return CONTAINING_RECORD(iface, TestClassFactoryImpl, IClassFactory_iface);
1371 }
1372 
1373 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
1374     LPCLASSFACTORY iface,
1375     REFIID riid,
1376     LPVOID *ppvObj)
1377 {
1378     if (ppvObj == NULL) return E_POINTER;
1379 
1380     if (IsEqualGUID(riid, &IID_IUnknown) ||
1381         IsEqualGUID(riid, &IID_IClassFactory))
1382     {
1383         *ppvObj = iface;
1384         IClassFactory_AddRef(iface);
1385         return S_OK;
1386     }
1387 
1388     *ppvObj = NULL;
1389     return E_NOINTERFACE;
1390 }
1391 
1392 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
1393 {
1394     return 2; /* non-heap-based object */
1395 }
1396 
1397 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
1398 {
1399     return 1; /* non-heap-based object */
1400 }
1401 
1402 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
1403     LPCLASSFACTORY iface,
1404     LPUNKNOWN pUnkOuter,
1405     REFIID riid,
1406     LPVOID *ppvObj)
1407 {
1408     TestClassFactoryImpl *This = impl_from_IClassFactory(iface);
1409     HRESULT hr;
1410     TestFilterImpl *testfilter;
1411 
1412     *ppvObj = NULL;
1413 
1414     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1415 
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);
1420     }
1421     return hr;
1422 }
1423 
1424 static HRESULT WINAPI Test_IClassFactory_LockServer(
1425     LPCLASSFACTORY iface,
1426     BOOL fLock)
1427 {
1428     return S_OK;
1429 }
1430 
1431 static IClassFactoryVtbl TestClassFactory_Vtbl =
1432 {
1433     Test_IClassFactory_QueryInterface,
1434     Test_IClassFactory_AddRef,
1435     Test_IClassFactory_Release,
1436     Test_IClassFactory_CreateInstance,
1437     Test_IClassFactory_LockServer
1438 };
1439 
1440 static HRESULT get_connected_filter_name(TestFilterImpl *pFilter, char *FilterName)
1441 {
1442     IPin *pin = NULL;
1443     PIN_INFO pinInfo;
1444     FILTER_INFO filterInfo;
1445     HRESULT hr;
1446 
1447     FilterName[0] = 0;
1448 
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;
1452 
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;
1457 
1458     SetLastError(0xdeadbeef);
1459     hr = IBaseFilter_QueryFilterInfo(pinInfo.pFilter, &filterInfo);
1460     if (hr == S_OK && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1461     {
1462         IBaseFilter_Release(pinInfo.pFilter);
1463         return E_NOTIMPL;
1464     }
1465     ok(hr == S_OK, "IBaseFilter_QueryFilterInfo failed with %x\n", hr);
1466     IBaseFilter_Release(pinInfo.pFilter);
1467     if (FAILED(hr)) return hr;
1468 
1469     IFilterGraph_Release(filterInfo.pGraph);
1470 
1471     WideCharToMultiByte(CP_ACP, 0, filterInfo.achName, -1, FilterName, MAX_FILTER_NAME, NULL, NULL);
1472 
1473     return S_OK;
1474 }
1475 
1476 static void test_render_filter_priority(void)
1477 {
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}
1490     };
1491     static const CLSID CLSID_TestFilter3 = {
1492         0x37a4f2d8,
1493         0x4d13,
1494         0x11dd,
1495         {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1496     };
1497     static const CLSID CLSID_TestFilter4 = {
1498         0x37a4f3b4,
1499         0x4d13,
1500         0x11dd,
1501         {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1502     };
1503     static const GUID mediasubtype1 = {
1504         0x37a4f51c,
1505         0x4d13,
1506         0x11dd,
1507         {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1508     };
1509     static const GUID mediasubtype2 = {
1510         0x37a4f5c6,
1511         0x4d13,
1512         0x11dd,
1513         {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1514     };
1515     static const TestFilterPinData PinData1[] = {
1516             { PINDIR_OUTPUT, &mediasubtype1 },
1517             { 0, 0 }
1518         };
1519     static const TestFilterPinData PinData2[] = {
1520             { PINDIR_INPUT,  &mediasubtype1 },
1521             { 0, 0 }
1522         };
1523     static const TestFilterPinData PinData3[] = {
1524             { PINDIR_INPUT,  &GUID_NULL },
1525             { 0, 0 }
1526         };
1527     static const TestFilterPinData PinData4[] = {
1528             { PINDIR_INPUT,  &mediasubtype1 },
1529             { PINDIR_OUTPUT, &mediasubtype2 },
1530             { 0, 0 }
1531         };
1532     static const TestFilterPinData PinData5[] = {
1533             { PINDIR_INPUT,  &mediasubtype2 },
1534             { 0, 0 }
1535         };
1536     TestClassFactoryImpl Filter1ClassFactory = {
1537             { &TestClassFactory_Vtbl },
1538             PinData2, &CLSID_TestFilter2
1539         };
1540     TestClassFactoryImpl Filter2ClassFactory = {
1541             { &TestClassFactory_Vtbl },
1542             PinData4, &CLSID_TestFilter3
1543         };
1544     TestClassFactoryImpl Filter3ClassFactory = {
1545             { &TestClassFactory_Vtbl },
1546             PinData5, &CLSID_TestFilter4
1547         };
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 };
1561 
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;
1568 
1569     hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1570     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1571     if (FAILED(hr)) goto out;
1572 
1573     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1574     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1575 
1576     hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1577     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1578     if (FAILED(hr)) goto out;
1579 
1580     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1581     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1582 
1583     IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1584     ptestfilter2 = NULL;
1585 
1586     hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1587     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1588     if (FAILED(hr)) goto out;
1589 
1590     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1591     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1592 
1593     hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1594     ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1595 
1596     hr = get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1597 
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;
1604 
1605     if (hr == E_NOTIMPL)
1606     {
1607         win_skip("Needed functions are not implemented\n");
1608         return;
1609     }
1610 
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;
1614 
1615     hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1616     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1617     if (FAILED(hr)) goto out;
1618 
1619     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1620     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1621 
1622     hr = createtestfilter(&GUID_NULL, PinData3, &ptestfilter2);
1623     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1624     if (FAILED(hr)) goto out;
1625 
1626     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1627     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1628 
1629     IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1630     ptestfilter2 = NULL;
1631 
1632     hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1633     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1634     if (FAILED(hr)) goto out;
1635 
1636     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1637     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1638 
1639     hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1640     ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1641 
1642     hr = IFilterGraph2_Disconnect(pgraph2, NULL);
1643     ok(hr == E_POINTER, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr);
1644 
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);
1648 
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;
1655 
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. */
1659 
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;
1663 
1664     hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1665     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1666     if (FAILED(hr)) goto out;
1667 
1668     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1669     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1670 
1671     hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1672     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1673     if (FAILED(hr)) goto out;
1674 
1675     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1676     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1677 
1678     IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1679     ptestfilter2 = NULL;
1680 
1681     hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
1682     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1683     if (FAILED(hr)) goto out;
1684 
1685     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1686     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1687 
1688     IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1689     ptestfilter2 = NULL;
1690 
1691     hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2);
1692     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1693     if (FAILED(hr)) goto out;
1694 
1695     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4);
1696     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1697 
1698     hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1699     ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1700 
1701     get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1702     ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1, "TestfilterInstance2"),
1703             "unexpected connected filter: %s\n", ConnectedFilterName1);
1704 
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;
1711 
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;
1715 
1716     hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1717     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1718     if (FAILED(hr)) goto out;
1719 
1720     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1721     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1722 
1723     hr = createtestfilter(&GUID_NULL, PinData4, &ptestfilter2);
1724     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1725     if (FAILED(hr)) goto out;
1726 
1727     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName3);
1728     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1729 
1730     IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1731     ptestfilter2 = NULL;
1732 
1733     hr = createtestfilter(&GUID_NULL, PinData5, &ptestfilter2);
1734     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1735     if (FAILED(hr)) goto out;
1736 
1737     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName4);
1738     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1739 
1740     IBaseFilter_Release(&ptestfilter2->IBaseFilter_iface);
1741     ptestfilter2 = NULL;
1742 
1743     hr = createtestfilter(&GUID_NULL, PinData2, &ptestfilter2);
1744     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1745     if (FAILED(hr)) goto out;
1746 
1747     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter2->IBaseFilter_iface, wszFilterInstanceName2);
1748     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1749 
1750     hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1751     ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1752 
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);
1758 
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;
1765 
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;
1770 
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;
1774 
1775     hr = createtestfilter(&GUID_NULL, PinData1, &ptestfilter);
1776     ok(hr == S_OK, "createtestfilter failed with %08x\n", hr);
1777     if (FAILED(hr)) goto out;
1778 
1779     hr = IFilterGraph2_AddFilter(pgraph2, &ptestfilter->IBaseFilter_iface, wszFilterInstanceName1);
1780     ok(hr == S_OK, "IFilterGraph2_AddFilter failed with %08x\n", hr);
1781 
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;
1798 
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;
1812 
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
1818     {
1819         ok(hr == S_OK, "IFilterMapper2_RegisterFilter failed with %x\n", hr);
1820 
1821         rgf2.dwMerit = MERIT_PREFERRED;
1822         rgPinType[0].clsMinorType = &mediasubtype2;
1823 
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);
1827 
1828         S1(U(rgf2)).cPins2 = 2;
1829         rgPins2[0].dwFlags = 0;
1830         rgPinType[0].clsMinorType = &mediasubtype1;
1831 
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;
1841 
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);
1845 
1846         hr = IFilterGraph2_Render(pgraph2, ptestfilter->ppPins[0]);
1847         ok(hr == S_OK, "IFilterGraph2_Render failed with %08x\n", hr);
1848 
1849         get_connected_filter_name(ptestfilter, ConnectedFilterName1);
1850         ok(!lstrcmp(ConnectedFilterName1, "TestfilterInstance3"),
1851            "unexpected connected filter: %s\n", ConnectedFilterName1);
1852     }
1853 
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);
1863 
1864     out:
1865 
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);
1870 
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);
1877 }
1878 
1879 START_TEST(filtergraph)
1880 {
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;
1888     }
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();
1897 }
1898 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.