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
26 #include "wine/test.h"
30 static const WCHAR file
[] = {'t','e','s','t','.','a','v','i',0};
32 IGraphBuilder
* pgraph
;
34 static int createfiltergraph(void)
36 return S_OK
== CoCreateInstance(
37 &CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IGraphBuilder
, (LPVOID
*)&pgraph
);
40 static void renderfile(void)
44 hr
= IGraphBuilder_RenderFile(pgraph
, file
, NULL
);
45 ok(hr
==S_OK
, "RenderFile returned: %x\n", hr
);
48 static void rungraph(void)
56 hr
= IGraphBuilder_QueryInterface(pgraph
, &IID_IMediaControl
, (LPVOID
*)&pmc
);
57 ok(hr
==S_OK
, "Cannot get IMediaControl interface returned: %x\n", hr
);
59 hr
= IGraphBuilder_QueryInterface(pgraph
, &IID_IMediaFilter
, (LPVOID
*)&pmf
);
60 ok(hr
==S_OK
, "Cannot get IMediaFilter interface returned: %x\n", hr
);
62 IMediaControl_Stop(pmc
);
64 IMediaFilter_SetSyncSource(pmf
, NULL
);
66 IMediaFilter_Release(pmf
);
68 hr
= IMediaControl_Run(pmc
);
69 ok(hr
==S_FALSE
, "Cannot run the graph returned: %x\n", hr
);
73 trace("run -> stop\n");
74 hr
= IMediaControl_Stop(pmc
);
75 ok(hr
==S_OK
|| hr
== S_FALSE
, "Cannot stop the graph returned: %x\n", hr
);
77 IGraphBuilder_SetDefaultSyncSource(pgraph
);
80 trace("stop -> pause\n");
81 hr
= IMediaControl_Pause(pmc
);
82 ok(hr
==S_OK
|| hr
== S_FALSE
, "Cannot pause the graph returned: %x\n", hr
);
85 trace("pause -> run\n");
86 hr
= IMediaControl_Run(pmc
);
87 ok(hr
==S_OK
|| hr
== S_FALSE
, "Cannot start the graph returned: %x\n", hr
);
90 trace("run -> pause\n");
91 hr
= IMediaControl_Pause(pmc
);
92 ok(hr
==S_OK
|| hr
== S_FALSE
, "Cannot pause the graph returned: %x\n", hr
);
95 trace("pause -> stop\n");
96 hr
= IMediaControl_Stop(pmc
);
97 ok(hr
==S_OK
|| hr
== S_FALSE
, "Cannot stop the graph returned: %x\n", hr
);
100 trace("pause -> run\n");
101 hr
= IMediaControl_Run(pmc
);
102 ok(hr
==S_OK
|| hr
== S_FALSE
, "Cannot start the graph returned: %x\n", hr
);
104 trace("run -> stop\n");
105 hr
= IMediaControl_Stop(pmc
);
106 ok(hr
==S_OK
|| hr
== S_FALSE
, "Cannot stop the graph returned: %x\n", hr
);
108 trace("stop -> run\n");
109 hr
= IMediaControl_Run(pmc
);
110 ok(hr
==S_OK
|| hr
== S_FALSE
, "Cannot start the graph returned: %x\n", hr
);
112 hr
= IGraphBuilder_QueryInterface(pgraph
, &IID_IMediaEvent
, (LPVOID
*)&pme
);
113 ok(hr
==S_OK
, "Cannot get IMediaEvent interface returned: %x\n", hr
);
115 hr
= IMediaEvent_GetEventHandle(pme
, (OAEVENT
*)&hEvent
);
116 ok(hr
==S_OK
, "Cannot get event handle returned: %x\n", hr
);
118 /* WaitForSingleObject(hEvent, INFINITE); */
121 hr
= IMediaEvent_Release(pme
);
122 ok(hr
==2, "Releasing mediaevent returned: %x\n", hr
);
124 hr
= IMediaControl_Stop(pmc
);
125 ok(hr
==S_OK
, "Cannot stop the graph returned: %x\n", hr
);
127 hr
= IMediaControl_Release(pmc
);
128 ok(hr
==1, "Releasing mediacontrol returned: %x\n", hr
);
131 static void releasefiltergraph(void)
135 hr
= IGraphBuilder_Release(pgraph
);
136 ok(hr
==0, "Releasing filtergraph returned: %x\n", hr
);
139 static void test_render_run(void)
143 if (!createfiltergraph())
146 h
= CreateFileW(file
, 0, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
147 if (h
!= INVALID_HANDLE_VALUE
) {
153 releasefiltergraph();
156 static void test_graph_builder(void)
159 IBaseFilter
*pF
= NULL
;
160 IBaseFilter
*pF2
= NULL
;
162 IEnumPins
*pEnum
= NULL
;
164 static const WCHAR testFilterW
[] = {'t','e','s','t','F','i','l','t','e','r',0};
165 static const WCHAR fooBarW
[] = {'f','o','o','B','a','r',0};
167 if (!createfiltergraph())
170 /* create video filter */
171 hr
= CoCreateInstance(&CLSID_VideoRenderer
, NULL
, CLSCTX_INPROC_SERVER
,
172 &IID_IBaseFilter
, (LPVOID
*)&pF
);
173 ok(hr
== S_OK
, "CoCreateInstance failed with %x\n", hr
);
174 ok(pF
!= NULL
, "pF is NULL\n");
176 /* add the two filters to the graph */
177 hr
= IGraphBuilder_AddFilter(pgraph
, pF
, testFilterW
);
178 ok(hr
== S_OK
, "failed to add pF to the graph: %x\n", hr
);
181 hr
= IBaseFilter_EnumPins(pF
, &pEnum
);
182 ok(hr
== S_OK
, "IBaseFilter_EnumPins failed for pF: %x\n", hr
);
183 ok(pEnum
!= NULL
, "pEnum is NULL\n");
184 hr
= IEnumPins_Next(pEnum
, 1, &pIn
, NULL
);
185 ok(hr
== S_OK
, "IEnumPins_Next failed for pF: %x\n", hr
);
186 ok(pIn
!= NULL
, "pIn is NULL\n");
187 hr
= IPin_QueryDirection(pIn
, &dir
);
188 ok(hr
== S_OK
, "IPin_QueryDirection failed: %x\n", hr
);
189 ok(dir
== PINDIR_INPUT
, "pin has wrong direction\n");
191 hr
= IGraphBuilder_FindFilterByName(pgraph
, fooBarW
, &pF2
);
192 ok(hr
== VFW_E_NOT_FOUND
, "IGraphBuilder_FindFilterByName returned %x\n", hr
);
193 ok(pF2
== NULL
, "IGraphBuilder_FindFilterByName returned %p\n", pF2
);
194 hr
= IGraphBuilder_FindFilterByName(pgraph
, testFilterW
, &pF2
);
195 ok(hr
== S_OK
, "IGraphBuilder_FindFilterByName returned %x\n", hr
);
196 ok(pF2
!= NULL
, "IGraphBuilder_FindFilterByName returned NULL\n");
197 hr
= IGraphBuilder_FindFilterByName(pgraph
, testFilterW
, NULL
);
198 ok(hr
== E_POINTER
, "IGraphBuilder_FindFilterByName returned %x\n", hr
);
200 if (pIn
) IPin_Release(pIn
);
201 if (pEnum
) IEnumPins_Release(pEnum
);
202 if (pF
) IBaseFilter_Release(pF
);
203 if (pF2
) IBaseFilter_Release(pF2
);
205 releasefiltergraph();
208 static void test_graph_builder_addfilter(void)
211 IBaseFilter
*pF
= NULL
;
212 static const WCHAR testFilterW
[] = {'t','e','s','t','F','i','l','t','e','r',0};
214 if (!createfiltergraph())
217 hr
= IGraphBuilder_AddFilter(pgraph
, NULL
, testFilterW
);
218 ok(hr
== E_POINTER
, "IGraphBuilder_AddFilter returned: %x\n", hr
);
220 /* create video filter */
221 hr
= CoCreateInstance(&CLSID_VideoRenderer
, NULL
, CLSCTX_INPROC_SERVER
,
222 &IID_IBaseFilter
, (LPVOID
*)&pF
);
223 ok(hr
== S_OK
, "CoCreateInstance failed with %x\n", hr
);
224 ok(pF
!= NULL
, "pF is NULL\n");
226 skip("failed to created filter, skipping\n");
230 hr
= IGraphBuilder_AddFilter(pgraph
, pF
, NULL
);
231 ok(hr
== S_OK
, "IGraphBuilder_AddFilter returned: %x\n", hr
);
232 IMediaFilter_Release(pF
);
235 static void test_mediacontrol(void)
238 LONGLONG pos
= 0xdeadbeef;
239 IMediaSeeking
*seeking
= NULL
;
240 IMediaFilter
*filter
= NULL
;
241 IMediaControl
*control
= NULL
;
243 IFilterGraph2_SetDefaultSyncSource(pgraph
);
244 hr
= IFilterGraph2_QueryInterface(pgraph
, &IID_IMediaSeeking
, (void**) &seeking
);
245 ok(hr
== S_OK
, "QueryInterface IMediaControl failed: %08x\n", hr
);
249 hr
= IFilterGraph2_QueryInterface(pgraph
, &IID_IMediaFilter
, (void**) &filter
);
250 ok(hr
== S_OK
, "QueryInterface IMediaFilter failed: %08x\n", hr
);
253 IUnknown_Release(seeking
);
257 hr
= IFilterGraph2_QueryInterface(pgraph
, &IID_IMediaControl
, (void**) &control
);
258 ok(hr
== S_OK
, "QueryInterface IMediaControl failed: %08x\n", hr
);
261 IUnknown_Release(seeking
);
262 IUnknown_Release(filter
);
266 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &pos
);
267 ok(hr
== S_OK
, "GetCurrentPosition failed: %08x\n", hr
);
268 ok(pos
== 0, "Position != 0 (%x%08x)\n", (DWORD
)(pos
>> 32), (DWORD
)pos
);
270 IMediaFilter_SetSyncSource(filter
, NULL
);
272 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &pos
);
273 ok(hr
== S_OK
, "GetCurrentPosition failed: %08x\n", hr
);
274 ok(pos
== 0, "Position != 0 (%x%08x)\n", (DWORD
)(pos
>> 32), (DWORD
)pos
);
276 hr
= IMediaControl_GetState(control
, 1000, NULL
);
277 ok(hr
== E_POINTER
, "GetState expected %08x, got %08x\n", E_POINTER
, hr
);
279 IUnknown_Release(control
);
280 IUnknown_Release(seeking
);
281 IUnknown_Release(filter
);
282 releasefiltergraph();
285 static void test_filter_graph2(void)
288 IFilterGraph2
*pF
= NULL
;
290 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
291 &IID_IFilterGraph2
, (LPVOID
*)&pF
);
292 ok(hr
== S_OK
, "CoCreateInstance failed with %x\n", hr
);
293 ok(pF
!= NULL
, "pF is NULL\n");
295 hr
= IFilterGraph2_Release(pF
);
296 ok(hr
== 0, "IFilterGraph2_Release returned: %x\n", hr
);
299 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
300 static void FreeMediaType(AM_MEDIA_TYPE
* pMediaType
)
302 if (pMediaType
->pbFormat
)
304 CoTaskMemFree(pMediaType
->pbFormat
);
305 pMediaType
->pbFormat
= NULL
;
307 if (pMediaType
->pUnk
)
309 IUnknown_Release(pMediaType
->pUnk
);
310 pMediaType
->pUnk
= NULL
;
314 static HRESULT
CopyMediaType(AM_MEDIA_TYPE
* pDest
, const AM_MEDIA_TYPE
*pSrc
)
317 if (!pSrc
->pbFormat
) return S_OK
;
318 if (!(pDest
->pbFormat
= CoTaskMemAlloc(pSrc
->cbFormat
)))
319 return E_OUTOFMEMORY
;
320 memcpy(pDest
->pbFormat
, pSrc
->pbFormat
, pSrc
->cbFormat
);
322 IUnknown_AddRef(pDest
->pUnk
);
326 static AM_MEDIA_TYPE
* CreateMediaType(AM_MEDIA_TYPE
const * pSrc
)
328 AM_MEDIA_TYPE
* pDest
;
330 pDest
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
));
334 if (FAILED(CopyMediaType(pDest
, pSrc
)))
336 CoTaskMemFree(pDest
);
343 static BOOL
CompareMediaTypes(const AM_MEDIA_TYPE
* pmt1
, const AM_MEDIA_TYPE
* pmt2
, BOOL bWildcards
)
345 return (((bWildcards
&& (IsEqualGUID(&pmt1
->majortype
, &GUID_NULL
) || IsEqualGUID(&pmt2
->majortype
, &GUID_NULL
))) || IsEqualGUID(&pmt1
->majortype
, &pmt2
->majortype
)) &&
346 ((bWildcards
&& (IsEqualGUID(&pmt1
->subtype
, &GUID_NULL
) || IsEqualGUID(&pmt2
->subtype
, &GUID_NULL
))) || IsEqualGUID(&pmt1
->subtype
, &pmt2
->subtype
)));
349 static void DeleteMediaType(AM_MEDIA_TYPE
* pMediaType
)
351 FreeMediaType(pMediaType
);
352 CoTaskMemFree(pMediaType
);
355 typedef struct IEnumMediaTypesImpl
357 const IEnumMediaTypesVtbl
* lpVtbl
;
359 AM_MEDIA_TYPE
*pMediaTypes
;
362 } IEnumMediaTypesImpl
;
364 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl
;
366 static HRESULT
IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE
* pMediaTypes
, ULONG cMediaTypes
, IEnumMediaTypes
** ppEnum
)
369 IEnumMediaTypesImpl
* pEnumMediaTypes
= CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl
));
371 if (!pEnumMediaTypes
)
374 return E_OUTOFMEMORY
;
376 pEnumMediaTypes
->lpVtbl
= &IEnumMediaTypesImpl_Vtbl
;
377 pEnumMediaTypes
->refCount
= 1;
378 pEnumMediaTypes
->uIndex
= 0;
379 pEnumMediaTypes
->cMediaTypes
= cMediaTypes
;
380 pEnumMediaTypes
->pMediaTypes
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
) * cMediaTypes
);
381 for (i
= 0; i
< cMediaTypes
; i
++)
382 if (FAILED(CopyMediaType(&pEnumMediaTypes
->pMediaTypes
[i
], &pMediaTypes
[i
])))
385 FreeMediaType(&pEnumMediaTypes
->pMediaTypes
[i
]);
386 CoTaskMemFree(pEnumMediaTypes
->pMediaTypes
);
387 return E_OUTOFMEMORY
;
389 *ppEnum
= (IEnumMediaTypes
*)(&pEnumMediaTypes
->lpVtbl
);
393 static HRESULT WINAPI
IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes
* iface
, REFIID riid
, LPVOID
* ppv
)
397 if (IsEqualIID(riid
, &IID_IUnknown
))
398 *ppv
= (LPVOID
)iface
;
399 else if (IsEqualIID(riid
, &IID_IEnumMediaTypes
))
400 *ppv
= (LPVOID
)iface
;
404 IUnknown_AddRef((IUnknown
*)(*ppv
));
408 return E_NOINTERFACE
;
411 static ULONG WINAPI
IEnumMediaTypesImpl_AddRef(IEnumMediaTypes
* iface
)
413 IEnumMediaTypesImpl
*This
= (IEnumMediaTypesImpl
*)iface
;
414 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
419 static ULONG WINAPI
IEnumMediaTypesImpl_Release(IEnumMediaTypes
* iface
)
421 IEnumMediaTypesImpl
*This
= (IEnumMediaTypesImpl
*)iface
;
422 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
427 for (i
= 0; i
< This
->cMediaTypes
; i
++)
428 FreeMediaType(&This
->pMediaTypes
[i
]);
429 CoTaskMemFree(This
->pMediaTypes
);
435 static HRESULT WINAPI
IEnumMediaTypesImpl_Next(IEnumMediaTypes
* iface
, ULONG cMediaTypes
, AM_MEDIA_TYPE
** ppMediaTypes
, ULONG
* pcFetched
)
438 IEnumMediaTypesImpl
*This
= (IEnumMediaTypesImpl
*)iface
;
440 cFetched
= min(This
->cMediaTypes
, This
->uIndex
+ cMediaTypes
) - This
->uIndex
;
445 for (i
= 0; i
< cFetched
; i
++)
446 if (!(ppMediaTypes
[i
] = CreateMediaType(&This
->pMediaTypes
[This
->uIndex
+ i
])))
449 DeleteMediaType(ppMediaTypes
[i
]);
451 return E_OUTOFMEMORY
;
455 if ((cMediaTypes
!= 1) || pcFetched
)
456 *pcFetched
= cFetched
;
458 This
->uIndex
+= cFetched
;
460 if (cFetched
!= cMediaTypes
)
465 static HRESULT WINAPI
IEnumMediaTypesImpl_Skip(IEnumMediaTypes
* iface
, ULONG cMediaTypes
)
467 IEnumMediaTypesImpl
*This
= (IEnumMediaTypesImpl
*)iface
;
469 if (This
->uIndex
+ cMediaTypes
< This
->cMediaTypes
)
471 This
->uIndex
+= cMediaTypes
;
477 static HRESULT WINAPI
IEnumMediaTypesImpl_Reset(IEnumMediaTypes
* iface
)
479 IEnumMediaTypesImpl
*This
= (IEnumMediaTypesImpl
*)iface
;
485 static HRESULT WINAPI
IEnumMediaTypesImpl_Clone(IEnumMediaTypes
* iface
, IEnumMediaTypes
** ppEnum
)
488 IEnumMediaTypesImpl
*This
= (IEnumMediaTypesImpl
*)iface
;
490 hr
= IEnumMediaTypesImpl_Construct(This
->pMediaTypes
, This
->cMediaTypes
, ppEnum
);
493 return IEnumMediaTypes_Skip(*ppEnum
, This
->uIndex
);
496 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl
=
498 IEnumMediaTypesImpl_QueryInterface
,
499 IEnumMediaTypesImpl_AddRef
,
500 IEnumMediaTypesImpl_Release
,
501 IEnumMediaTypesImpl_Next
,
502 IEnumMediaTypesImpl_Skip
,
503 IEnumMediaTypesImpl_Reset
,
504 IEnumMediaTypesImpl_Clone
507 /* Implementation of a very stripped down pin for the test filter. Just enough
508 functionality for connecting and Render() to work. */
510 static void Copy_PinInfo(PIN_INFO
* pDest
, const PIN_INFO
* pSrc
)
512 lstrcpyW(pDest
->achName
, pSrc
->achName
);
513 pDest
->dir
= pSrc
->dir
;
514 pDest
->pFilter
= pSrc
->pFilter
;
517 typedef struct ITestPinImpl
519 const struct IPinVtbl
* lpVtbl
;
521 LPCRITICAL_SECTION pCritSec
;
524 AM_MEDIA_TYPE mtCurrent
;
528 static HRESULT WINAPI
TestFilter_Pin_QueryInterface(IPin
* iface
, REFIID riid
, LPVOID
* ppv
)
532 if (IsEqualIID(riid
, &IID_IUnknown
))
533 *ppv
= (LPVOID
)iface
;
534 else if (IsEqualIID(riid
, &IID_IPin
))
535 *ppv
= (LPVOID
)iface
;
539 IUnknown_AddRef((IUnknown
*)(*ppv
));
543 return E_NOINTERFACE
;
546 static ULONG WINAPI
TestFilter_Pin_AddRef(IPin
* iface
)
548 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
549 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
553 static ULONG WINAPI
TestFilter_Pin_Release(IPin
* iface
)
555 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
556 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
560 FreeMediaType(&This
->mtCurrent
);
569 static HRESULT WINAPI
TestFilter_InputPin_Connect(IPin
* iface
, IPin
* pConnector
, const AM_MEDIA_TYPE
* pmt
)
574 static HRESULT WINAPI
TestFilter_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
576 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
577 PIN_DIRECTION pindirReceive
;
580 EnterCriticalSection(This
->pCritSec
);
582 if (!(IsEqualIID(&pmt
->majortype
, &This
->mtCurrent
.majortype
) && (IsEqualIID(&pmt
->subtype
, &This
->mtCurrent
.subtype
) ||
583 IsEqualIID(&GUID_NULL
, &This
->mtCurrent
.subtype
))))
584 hr
= VFW_E_TYPE_NOT_ACCEPTED
;
586 if (This
->pConnectedTo
)
587 hr
= VFW_E_ALREADY_CONNECTED
;
591 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
593 if (pindirReceive
!= PINDIR_OUTPUT
)
595 hr
= VFW_E_INVALID_DIRECTION
;
601 CopyMediaType(&This
->mtCurrent
, pmt
);
602 This
->pConnectedTo
= pReceivePin
;
603 IPin_AddRef(pReceivePin
);
606 LeaveCriticalSection(This
->pCritSec
);
611 static HRESULT WINAPI
TestFilter_Pin_Disconnect(IPin
* iface
)
614 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
616 EnterCriticalSection(This
->pCritSec
);
618 if (This
->pConnectedTo
)
620 IPin_Release(This
->pConnectedTo
);
621 This
->pConnectedTo
= NULL
;
627 LeaveCriticalSection(This
->pCritSec
);
632 static HRESULT WINAPI
TestFilter_Pin_ConnectedTo(IPin
* iface
, IPin
** ppPin
)
635 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
637 EnterCriticalSection(This
->pCritSec
);
639 if (This
->pConnectedTo
)
641 *ppPin
= This
->pConnectedTo
;
647 hr
= VFW_E_NOT_CONNECTED
;
651 LeaveCriticalSection(This
->pCritSec
);
656 static HRESULT WINAPI
TestFilter_Pin_ConnectionMediaType(IPin
* iface
, AM_MEDIA_TYPE
* pmt
)
659 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
661 EnterCriticalSection(This
->pCritSec
);
663 if (This
->pConnectedTo
)
665 CopyMediaType(pmt
, &This
->mtCurrent
);
670 ZeroMemory(pmt
, sizeof(*pmt
));
671 hr
= VFW_E_NOT_CONNECTED
;
674 LeaveCriticalSection(This
->pCritSec
);
679 static HRESULT WINAPI
TestFilter_Pin_QueryPinInfo(IPin
* iface
, PIN_INFO
* pInfo
)
681 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
683 Copy_PinInfo(pInfo
, &This
->pinInfo
);
684 IBaseFilter_AddRef(pInfo
->pFilter
);
689 static HRESULT WINAPI
TestFilter_Pin_QueryDirection(IPin
* iface
, PIN_DIRECTION
* pPinDir
)
691 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
693 *pPinDir
= This
->pinInfo
.dir
;
698 static HRESULT WINAPI
TestFilter_Pin_QueryId(IPin
* iface
, LPWSTR
* Id
)
703 static HRESULT WINAPI
TestFilter_Pin_QueryAccept(IPin
* iface
, const AM_MEDIA_TYPE
* pmt
)
705 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
707 if (IsEqualIID(&pmt
->majortype
, &This
->mtCurrent
.majortype
) && (IsEqualIID(&pmt
->subtype
, &This
->mtCurrent
.subtype
) ||
708 IsEqualIID(&GUID_NULL
, &This
->mtCurrent
.subtype
)))
711 return VFW_E_TYPE_NOT_ACCEPTED
;
714 static HRESULT WINAPI
TestFilter_Pin_EnumMediaTypes(IPin
* iface
, IEnumMediaTypes
** ppEnum
)
716 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
718 return IEnumMediaTypesImpl_Construct(&This
->mtCurrent
, 1, ppEnum
);
721 static HRESULT WINAPI
TestFilter_Pin_QueryInternalConnections(IPin
* iface
, IPin
** apPin
, ULONG
* cPin
)
726 static HRESULT WINAPI
TestFilter_Pin_BeginFlush(IPin
* iface
)
731 static HRESULT WINAPI
TestFilter_Pin_EndFlush(IPin
* iface
)
736 static HRESULT WINAPI
TestFilter_Pin_NewSegment(IPin
* iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double dRate
)
741 static HRESULT WINAPI
TestFilter_Pin_EndOfStream(IPin
* iface
)
746 static const IPinVtbl TestFilter_InputPin_Vtbl
=
748 TestFilter_Pin_QueryInterface
,
749 TestFilter_Pin_AddRef
,
750 TestFilter_Pin_Release
,
751 TestFilter_InputPin_Connect
,
752 TestFilter_InputPin_ReceiveConnection
,
753 TestFilter_Pin_Disconnect
,
754 TestFilter_Pin_ConnectedTo
,
755 TestFilter_Pin_ConnectionMediaType
,
756 TestFilter_Pin_QueryPinInfo
,
757 TestFilter_Pin_QueryDirection
,
758 TestFilter_Pin_QueryId
,
759 TestFilter_Pin_QueryAccept
,
760 TestFilter_Pin_EnumMediaTypes
,
761 TestFilter_Pin_QueryInternalConnections
,
762 TestFilter_Pin_EndOfStream
,
763 TestFilter_Pin_BeginFlush
,
764 TestFilter_Pin_EndFlush
,
765 TestFilter_Pin_NewSegment
768 static HRESULT WINAPI
TestFilter_OutputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
773 /* Private helper function */
774 static HRESULT WINAPI
TestFilter_OutputPin_ConnectSpecific(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
776 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
779 This
->pConnectedTo
= pReceivePin
;
780 IPin_AddRef(pReceivePin
);
782 hr
= IPin_ReceiveConnection(pReceivePin
, iface
, pmt
);
786 IPin_Release(This
->pConnectedTo
);
787 This
->pConnectedTo
= NULL
;
793 static HRESULT WINAPI
TestFilter_OutputPin_Connect(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
795 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
798 EnterCriticalSection(This
->pCritSec
);
800 /* if we have been a specific type to connect with, then we can either connect
801 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
802 if (pmt
&& !IsEqualGUID(&pmt
->majortype
, &GUID_NULL
) && !IsEqualGUID(&pmt
->subtype
, &GUID_NULL
))
803 hr
= TestFilter_OutputPin_ConnectSpecific(iface
, pReceivePin
, pmt
);
806 if (( !pmt
|| CompareMediaTypes(pmt
, &This
->mtCurrent
, TRUE
) ) &&
807 (TestFilter_OutputPin_ConnectSpecific(iface
, pReceivePin
, &This
->mtCurrent
) == S_OK
))
809 else hr
= VFW_E_NO_ACCEPTABLE_TYPES
;
810 } /* if negotiate media type */
812 LeaveCriticalSection(This
->pCritSec
);
817 static const IPinVtbl TestFilter_OutputPin_Vtbl
=
819 TestFilter_Pin_QueryInterface
,
820 TestFilter_Pin_AddRef
,
821 TestFilter_Pin_Release
,
822 TestFilter_OutputPin_Connect
,
823 TestFilter_OutputPin_ReceiveConnection
,
824 TestFilter_Pin_Disconnect
,
825 TestFilter_Pin_ConnectedTo
,
826 TestFilter_Pin_ConnectionMediaType
,
827 TestFilter_Pin_QueryPinInfo
,
828 TestFilter_Pin_QueryDirection
,
829 TestFilter_Pin_QueryId
,
830 TestFilter_Pin_QueryAccept
,
831 TestFilter_Pin_EnumMediaTypes
,
832 TestFilter_Pin_QueryInternalConnections
,
833 TestFilter_Pin_EndOfStream
,
834 TestFilter_Pin_BeginFlush
,
835 TestFilter_Pin_EndFlush
,
836 TestFilter_Pin_NewSegment
839 static HRESULT
TestFilter_Pin_Construct(const IPinVtbl
*Pin_Vtbl
, const PIN_INFO
* pPinInfo
, AM_MEDIA_TYPE
*pinmt
,
840 LPCRITICAL_SECTION pCritSec
, IPin
** ppPin
)
842 ITestPinImpl
* pPinImpl
;
846 pPinImpl
= CoTaskMemAlloc(sizeof(ITestPinImpl
));
849 return E_OUTOFMEMORY
;
851 pPinImpl
->refCount
= 1;
852 pPinImpl
->pConnectedTo
= NULL
;
853 pPinImpl
->pCritSec
= pCritSec
;
854 Copy_PinInfo(&pPinImpl
->pinInfo
, pPinInfo
);
855 pPinImpl
->mtCurrent
= *pinmt
;
857 pPinImpl
->lpVtbl
= Pin_Vtbl
;
859 *ppPin
= (IPin
*)pPinImpl
;
863 /* IEnumPins implementation */
865 typedef HRESULT (* FNOBTAINPIN
)(IBaseFilter
*iface
, ULONG pos
, IPin
**pin
, DWORD
*lastsynctick
);
867 typedef struct IEnumPinsImpl
869 const IEnumPinsVtbl
* lpVtbl
;
873 FNOBTAINPIN receive_pin
;
877 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl
;
879 static HRESULT
IEnumPinsImpl_Construct(IEnumPins
** ppEnum
, FNOBTAINPIN receive_pin
, IBaseFilter
*base
)
881 IEnumPinsImpl
* pEnumPins
;
886 pEnumPins
= CoTaskMemAlloc(sizeof(IEnumPinsImpl
));
890 return E_OUTOFMEMORY
;
892 pEnumPins
->lpVtbl
= &IEnumPinsImpl_Vtbl
;
893 pEnumPins
->refCount
= 1;
894 pEnumPins
->uIndex
= 0;
895 pEnumPins
->receive_pin
= receive_pin
;
896 pEnumPins
->base
= base
;
897 IBaseFilter_AddRef(base
);
898 *ppEnum
= (IEnumPins
*)(&pEnumPins
->lpVtbl
);
900 receive_pin(base
, ~0, NULL
, &pEnumPins
->synctime
);
905 static HRESULT WINAPI
IEnumPinsImpl_QueryInterface(IEnumPins
* iface
, REFIID riid
, LPVOID
* ppv
)
909 if (IsEqualIID(riid
, &IID_IUnknown
))
910 *ppv
= (LPVOID
)iface
;
911 else if (IsEqualIID(riid
, &IID_IEnumPins
))
912 *ppv
= (LPVOID
)iface
;
916 IUnknown_AddRef((IUnknown
*)(*ppv
));
920 return E_NOINTERFACE
;
923 static ULONG WINAPI
IEnumPinsImpl_AddRef(IEnumPins
* iface
)
925 IEnumPinsImpl
*This
= (IEnumPinsImpl
*)iface
;
926 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
931 static ULONG WINAPI
IEnumPinsImpl_Release(IEnumPins
* iface
)
933 IEnumPinsImpl
*This
= (IEnumPinsImpl
*)iface
;
934 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
938 IBaseFilter_Release(This
->base
);
946 static HRESULT WINAPI
IEnumPinsImpl_Next(IEnumPins
* iface
, ULONG cPins
, IPin
** ppPins
, ULONG
* pcFetched
)
948 IEnumPinsImpl
*This
= (IEnumPinsImpl
*)iface
;
949 DWORD synctime
= This
->synctime
;
956 if (cPins
> 1 && !pcFetched
)
962 while (i
< cPins
&& hr
== S_OK
)
964 hr
= This
->receive_pin(This
->base
, This
->uIndex
+ i
, &ppPins
[i
], &synctime
);
969 if (synctime
!= This
->synctime
)
973 if (!i
&& synctime
!= This
->synctime
)
974 return VFW_E_ENUM_OUT_OF_SYNC
;
985 static HRESULT WINAPI
IEnumPinsImpl_Skip(IEnumPins
* iface
, ULONG cPins
)
987 IEnumPinsImpl
*This
= (IEnumPinsImpl
*)iface
;
988 DWORD synctime
= This
->synctime
;
992 hr
= This
->receive_pin(This
->base
, This
->uIndex
+ cPins
, &pin
, &synctime
);
996 if (synctime
!= This
->synctime
)
997 return VFW_E_ENUM_OUT_OF_SYNC
;
1000 This
->uIndex
+= cPins
;
1005 static HRESULT WINAPI
IEnumPinsImpl_Reset(IEnumPins
* iface
)
1007 IEnumPinsImpl
*This
= (IEnumPinsImpl
*)iface
;
1009 This
->receive_pin(This
->base
, ~0, NULL
, &This
->synctime
);
1015 static HRESULT WINAPI
IEnumPinsImpl_Clone(IEnumPins
* iface
, IEnumPins
** ppEnum
)
1018 IEnumPinsImpl
*This
= (IEnumPinsImpl
*)iface
;
1020 hr
= IEnumPinsImpl_Construct(ppEnum
, This
->receive_pin
, This
->base
);
1023 return IEnumPins_Skip(*ppEnum
, This
->uIndex
);
1026 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl
=
1028 IEnumPinsImpl_QueryInterface
,
1029 IEnumPinsImpl_AddRef
,
1030 IEnumPinsImpl_Release
,
1033 IEnumPinsImpl_Reset
,
1037 /* Test filter implementation - a filter that has few predefined pins with single media type
1038 * that accept only this single media type. Enough for Render(). */
1040 typedef struct TestFilterPinData
1042 PIN_DIRECTION pinDir
;
1043 const GUID
*mediasubtype
;
1044 } TestFilterPinData
;
1046 typedef struct TestFilterImpl
1048 const IBaseFilterVtbl
* lpVtbl
;
1051 CRITICAL_SECTION csFilter
;
1053 FILTER_INFO filterInfo
;
1059 static const IBaseFilterVtbl TestFilter_Vtbl
;
1061 static HRESULT
TestFilter_Create(const CLSID
* pClsid
, const TestFilterPinData
*pinData
, LPVOID
* ppv
)
1063 static const WCHAR wcsInputPinName
[] = {'i','n','p','u','t',' ','p','i','n',0};
1064 static const WCHAR wcsOutputPinName
[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1067 TestFilterImpl
* pTestFilter
= NULL
;
1071 pTestFilter
= CoTaskMemAlloc(sizeof(TestFilterImpl
));
1072 if (!pTestFilter
) return E_OUTOFMEMORY
;
1074 pTestFilter
->clsid
= *pClsid
;
1075 pTestFilter
->lpVtbl
= &TestFilter_Vtbl
;
1076 pTestFilter
->refCount
= 1;
1077 InitializeCriticalSection(&pTestFilter
->csFilter
);
1078 pTestFilter
->state
= State_Stopped
;
1080 ZeroMemory(&pTestFilter
->filterInfo
, sizeof(FILTER_INFO
));
1083 while(pinData
[nPins
].mediasubtype
) ++nPins
;
1085 pTestFilter
->ppPins
= CoTaskMemAlloc(nPins
* sizeof(IPin
*));
1086 if (!pTestFilter
->ppPins
)
1091 ZeroMemory(pTestFilter
->ppPins
, nPins
* sizeof(IPin
*));
1093 for (i
= 0; i
< nPins
; i
++)
1095 ZeroMemory(&mt
, sizeof(mt
));
1096 mt
.majortype
= MEDIATYPE_Video
;
1097 mt
.formattype
= FORMAT_None
;
1098 mt
.subtype
= *pinData
[i
].mediasubtype
;
1100 pinInfo
.dir
= pinData
[i
].pinDir
;
1101 pinInfo
.pFilter
= (IBaseFilter
*)pTestFilter
;
1102 if (pinInfo
.dir
== PINDIR_INPUT
)
1104 lstrcpynW(pinInfo
.achName
, wcsInputPinName
, sizeof(pinInfo
.achName
) / sizeof(pinInfo
.achName
[0]));
1105 hr
= TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl
, &pinInfo
, &mt
, &pTestFilter
->csFilter
,
1106 &pTestFilter
->ppPins
[i
]);
1111 lstrcpynW(pinInfo
.achName
, wcsOutputPinName
, sizeof(pinInfo
.achName
) / sizeof(pinInfo
.achName
[0]));
1112 hr
= TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl
, &pinInfo
, &mt
, &pTestFilter
->csFilter
,
1113 &pTestFilter
->ppPins
[i
]);
1115 if (FAILED(hr
) || !pTestFilter
->ppPins
[i
]) goto error
;
1118 pTestFilter
->nPins
= nPins
;
1119 *ppv
= (LPVOID
)pTestFilter
;
1124 for (i
= 0; i
< nPins
; i
++)
1126 if (pTestFilter
->ppPins
[i
]) IPin_Release(pTestFilter
->ppPins
[i
]);
1128 CoTaskMemFree(pTestFilter
->ppPins
);
1129 DeleteCriticalSection(&pTestFilter
->csFilter
);
1130 CoTaskMemFree(pTestFilter
);
1135 static HRESULT WINAPI
TestFilter_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
1137 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1141 if (IsEqualIID(riid
, &IID_IUnknown
))
1142 *ppv
= (LPVOID
)This
;
1143 else if (IsEqualIID(riid
, &IID_IPersist
))
1144 *ppv
= (LPVOID
)This
;
1145 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
1146 *ppv
= (LPVOID
)This
;
1147 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
1148 *ppv
= (LPVOID
)This
;
1152 IUnknown_AddRef((IUnknown
*)(*ppv
));
1156 return E_NOINTERFACE
;
1159 static ULONG WINAPI
TestFilter_AddRef(IBaseFilter
* iface
)
1161 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1162 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
1167 static ULONG WINAPI
TestFilter_Release(IBaseFilter
* iface
)
1169 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1170 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
1176 for (i
= 0; i
< This
->nPins
; i
++)
1180 if (SUCCEEDED(IPin_ConnectedTo(This
->ppPins
[i
], &pConnectedTo
)))
1182 IPin_Disconnect(pConnectedTo
);
1183 IPin_Release(pConnectedTo
);
1185 IPin_Disconnect(This
->ppPins
[i
]);
1187 IPin_Release(This
->ppPins
[i
]);
1190 CoTaskMemFree(This
->ppPins
);
1191 This
->lpVtbl
= NULL
;
1193 DeleteCriticalSection(&This
->csFilter
);
1195 CoTaskMemFree(This
);
1202 /** IPersist methods **/
1204 static HRESULT WINAPI
TestFilter_GetClassID(IBaseFilter
* iface
, CLSID
* pClsid
)
1206 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1208 *pClsid
= This
->clsid
;
1213 /** IMediaFilter methods **/
1215 static HRESULT WINAPI
TestFilter_Stop(IBaseFilter
* iface
)
1220 static HRESULT WINAPI
TestFilter_Pause(IBaseFilter
* iface
)
1225 static HRESULT WINAPI
TestFilter_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
1230 static HRESULT WINAPI
TestFilter_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
1232 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1234 EnterCriticalSection(&This
->csFilter
);
1236 *pState
= This
->state
;
1238 LeaveCriticalSection(&This
->csFilter
);
1243 static HRESULT WINAPI
TestFilter_SetSyncSource(IBaseFilter
* iface
, IReferenceClock
*pClock
)
1248 static HRESULT WINAPI
TestFilter_GetSyncSource(IBaseFilter
* iface
, IReferenceClock
**ppClock
)
1253 /** IBaseFilter implementation **/
1255 static HRESULT
TestFilter_GetPin(IBaseFilter
*iface
, ULONG pos
, IPin
**pin
, DWORD
*lastsynctick
)
1257 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1259 /* Our pins are static, not changing so setting static tick count is ok */
1262 if (pos
>= This
->nPins
)
1265 *pin
= This
->ppPins
[pos
];
1270 static HRESULT WINAPI
TestFilter_EnumPins(IBaseFilter
* iface
, IEnumPins
**ppEnum
)
1272 return IEnumPinsImpl_Construct(ppEnum
, TestFilter_GetPin
, iface
);
1275 static HRESULT WINAPI
TestFilter_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
1280 static HRESULT WINAPI
TestFilter_QueryFilterInfo(IBaseFilter
* iface
, FILTER_INFO
*pInfo
)
1282 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1284 lstrcpyW(pInfo
->achName
, This
->filterInfo
.achName
);
1285 pInfo
->pGraph
= This
->filterInfo
.pGraph
;
1288 IFilterGraph_AddRef(pInfo
->pGraph
);
1293 static HRESULT WINAPI
TestFilter_JoinFilterGraph(IBaseFilter
* iface
, IFilterGraph
*pGraph
, LPCWSTR pName
)
1296 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1298 EnterCriticalSection(&This
->csFilter
);
1301 lstrcpyW(This
->filterInfo
.achName
, pName
);
1303 *This
->filterInfo
.achName
= '\0';
1304 This
->filterInfo
.pGraph
= pGraph
; /* NOTE: do NOT increase ref. count */
1306 LeaveCriticalSection(&This
->csFilter
);
1311 static HRESULT WINAPI
TestFilter_QueryVendorInfo(IBaseFilter
* iface
, LPWSTR
*pVendorInfo
)
1316 static const IBaseFilterVtbl TestFilter_Vtbl
=
1318 TestFilter_QueryInterface
,
1321 TestFilter_GetClassID
,
1325 TestFilter_GetState
,
1326 TestFilter_SetSyncSource
,
1327 TestFilter_GetSyncSource
,
1328 TestFilter_EnumPins
,
1330 TestFilter_QueryFilterInfo
,
1331 TestFilter_JoinFilterGraph
,
1332 TestFilter_QueryVendorInfo
1335 /* IClassFactory implementation */
1337 typedef struct TestClassFactoryImpl
1339 IClassFactoryVtbl
*lpVtbl
;
1340 const TestFilterPinData
*filterPinData
;
1342 } TestClassFactoryImpl
;
1344 static HRESULT WINAPI
Test_IClassFactory_QueryInterface(
1345 LPCLASSFACTORY iface
,
1349 if (ppvObj
== NULL
) return E_POINTER
;
1351 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1352 IsEqualGUID(riid
, &IID_IClassFactory
))
1354 *ppvObj
= (LPVOID
)iface
;
1355 IClassFactory_AddRef(iface
);
1360 return E_NOINTERFACE
;
1363 static ULONG WINAPI
Test_IClassFactory_AddRef(LPCLASSFACTORY iface
)
1365 return 2; /* non-heap-based object */
1368 static ULONG WINAPI
Test_IClassFactory_Release(LPCLASSFACTORY iface
)
1370 return 1; /* non-heap-based object */
1373 static HRESULT WINAPI
Test_IClassFactory_CreateInstance(
1374 LPCLASSFACTORY iface
,
1375 LPUNKNOWN pUnkOuter
,
1379 TestClassFactoryImpl
*This
= (TestClassFactoryImpl
*)iface
;
1381 IUnknown
*punk
= NULL
;
1385 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1387 hr
= TestFilter_Create(This
->clsid
, This
->filterPinData
, (LPVOID
*) &punk
);
1388 if (SUCCEEDED(hr
)) {
1389 hr
= IUnknown_QueryInterface(punk
, riid
, ppvObj
);
1390 IUnknown_Release(punk
);
1395 static HRESULT WINAPI
Test_IClassFactory_LockServer(
1396 LPCLASSFACTORY iface
,
1402 static IClassFactoryVtbl TestClassFactory_Vtbl
=
1404 Test_IClassFactory_QueryInterface
,
1405 Test_IClassFactory_AddRef
,
1406 Test_IClassFactory_Release
,
1407 Test_IClassFactory_CreateInstance
,
1408 Test_IClassFactory_LockServer
1411 static HRESULT
get_connected_filter_name(TestFilterImpl
*pFilter
, char *FilterName
)
1415 FILTER_INFO filterInfo
;
1420 hr
= IPin_ConnectedTo(pFilter
->ppPins
[0], &pin
);
1421 ok(hr
== S_OK
, "IPin_ConnectedTo failed with %x\n", hr
);
1422 if (FAILED(hr
)) return hr
;
1424 hr
= IPin_QueryPinInfo(pin
, &pinInfo
);
1425 ok(hr
== S_OK
, "IPin_QueryPinInfo failed with %x\n", hr
);
1427 if (FAILED(hr
)) return hr
;
1429 hr
= IBaseFilter_QueryFilterInfo(pinInfo
.pFilter
, &filterInfo
);
1430 ok(hr
== S_OK
, "IBaseFilter_QueryFilterInfo failed with %x\n", hr
);
1431 IBaseFilter_Release(pinInfo
.pFilter
);
1432 if (FAILED(hr
)) return hr
;
1434 IFilterGraph_Release(filterInfo
.pGraph
);
1436 WideCharToMultiByte(CP_ACP
, 0, filterInfo
.achName
, -1, FilterName
, MAX_FILTER_NAME
, NULL
, NULL
);
1441 static void test_render_filter_priority(void)
1443 /* Tests filter choice priorities in Render(). */
1444 DWORD cookie1
, cookie2
, cookie3
;
1446 IFilterGraph2
* pgraph2
= NULL
;
1447 IFilterMapper2
*pMapper2
= NULL
;
1448 IBaseFilter
* ptestfilter
= NULL
;
1449 IBaseFilter
* ptestfilter2
= NULL
;
1450 static const CLSID CLSID_TestFilter2
= {
1454 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1456 static const CLSID CLSID_TestFilter3
= {
1460 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1462 static const CLSID CLSID_TestFilter4
= {
1466 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1468 static const GUID mediasubtype1
= {
1472 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1474 static const GUID mediasubtype2
= {
1478 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1480 static const TestFilterPinData PinData1
[] = {
1481 { PINDIR_OUTPUT
, &mediasubtype1
},
1484 static const TestFilterPinData PinData2
[] = {
1485 { PINDIR_INPUT
, &mediasubtype1
},
1488 static const TestFilterPinData PinData3
[] = {
1489 { PINDIR_INPUT
, &GUID_NULL
},
1492 static const TestFilterPinData PinData4
[] = {
1493 { PINDIR_INPUT
, &mediasubtype1
},
1494 { PINDIR_OUTPUT
, &mediasubtype2
},
1497 static const TestFilterPinData PinData5
[] = {
1498 { PINDIR_INPUT
, &mediasubtype2
},
1501 TestClassFactoryImpl Filter1ClassFactory
= { &TestClassFactory_Vtbl
, PinData2
, &CLSID_TestFilter2
};
1502 TestClassFactoryImpl Filter2ClassFactory
= { &TestClassFactory_Vtbl
, PinData4
, &CLSID_TestFilter3
};
1503 TestClassFactoryImpl Filter3ClassFactory
= { &TestClassFactory_Vtbl
, PinData5
, &CLSID_TestFilter4
};
1504 char ConnectedFilterName1
[MAX_FILTER_NAME
];
1505 char ConnectedFilterName2
[MAX_FILTER_NAME
];
1507 REGFILTERPINS2 rgPins2
[2];
1508 REGPINTYPES rgPinType
[2];
1509 static const WCHAR wszFilterInstanceName1
[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1510 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1511 static const WCHAR wszFilterInstanceName2
[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1512 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1513 static const WCHAR wszFilterInstanceName3
[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1514 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1515 static const WCHAR wszFilterInstanceName4
[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1516 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1518 /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is
1519 "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating
1520 no preference given to exact match. */
1521 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterGraph2
, (LPVOID
*)&pgraph2
);
1522 ok(hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
1523 if (!pgraph2
) goto out
;
1525 hr
= TestFilter_Create(&GUID_NULL
, PinData1
, (LPVOID
)&ptestfilter
);
1526 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1527 if (FAILED(hr
)) goto out
;
1529 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter
, wszFilterInstanceName1
);
1530 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1532 hr
= TestFilter_Create(&GUID_NULL
, PinData2
, (LPVOID
)&ptestfilter2
);
1533 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1534 if (FAILED(hr
)) goto out
;
1536 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName2
);
1537 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1539 IBaseFilter_Release(ptestfilter2
);
1540 ptestfilter2
= NULL
;
1542 hr
= TestFilter_Create(&GUID_NULL
, PinData3
, (LPVOID
)&ptestfilter2
);
1543 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1544 if (FAILED(hr
)) goto out
;
1546 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName3
);
1547 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1549 hr
= IFilterGraph2_Render(pgraph2
, ((TestFilterImpl
*)ptestfilter
)->ppPins
[0]);
1550 ok(hr
== S_OK
, "IFilterGraph2_Render failed with %08x\n", hr
);
1552 get_connected_filter_name((TestFilterImpl
*)ptestfilter
, ConnectedFilterName1
);
1554 IFilterGraph2_Release(pgraph2
);
1556 IBaseFilter_Release(ptestfilter
);
1558 IBaseFilter_Release(ptestfilter2
);
1559 ptestfilter2
= NULL
;
1561 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterGraph2
, (LPVOID
*)&pgraph2
);
1562 ok(hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
1563 if (!pgraph2
) goto out
;
1565 hr
= TestFilter_Create(&GUID_NULL
, PinData1
, (LPVOID
)&ptestfilter
);
1566 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1567 if (FAILED(hr
)) goto out
;
1569 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter
, wszFilterInstanceName1
);
1570 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1572 hr
= TestFilter_Create(&GUID_NULL
, PinData3
, (LPVOID
)&ptestfilter2
);
1573 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1574 if (FAILED(hr
)) goto out
;
1576 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName3
);
1577 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1579 IBaseFilter_Release(ptestfilter2
);
1580 ptestfilter2
= NULL
;
1582 hr
= TestFilter_Create(&GUID_NULL
, PinData2
, (LPVOID
)&ptestfilter2
);
1583 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1584 if (FAILED(hr
)) goto out
;
1586 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName2
);
1587 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1589 hr
= IFilterGraph2_Render(pgraph2
, ((TestFilterImpl
*)ptestfilter
)->ppPins
[0]);
1590 ok(hr
== S_OK
, "IFilterGraph2_Render failed with %08x\n", hr
);
1592 get_connected_filter_name((TestFilterImpl
*)ptestfilter
, ConnectedFilterName2
);
1593 ok(lstrcmp(ConnectedFilterName1
, ConnectedFilterName2
),
1594 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1
);
1596 IFilterGraph2_Release(pgraph2
);
1598 IBaseFilter_Release(ptestfilter
);
1600 IBaseFilter_Release(ptestfilter2
);
1601 ptestfilter2
= NULL
;
1603 /* Test if any preference is given to existing renderer which renders the pin directly vs
1604 an existing renderer which renders the pin indirectly, through an additional middle filter,
1605 again trying different orders of creation. Native appears not to give a preference. */
1607 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterGraph2
, (LPVOID
*)&pgraph2
);
1608 ok(hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
1609 if (!pgraph2
) goto out
;
1611 hr
= TestFilter_Create(&GUID_NULL
, PinData1
, (LPVOID
)&ptestfilter
);
1612 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1613 if (FAILED(hr
)) goto out
;
1615 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter
, wszFilterInstanceName1
);
1616 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1618 hr
= TestFilter_Create(&GUID_NULL
, PinData2
, (LPVOID
)&ptestfilter2
);
1619 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1620 if (FAILED(hr
)) goto out
;
1622 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName2
);
1623 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1625 IBaseFilter_Release(ptestfilter2
);
1626 ptestfilter2
= NULL
;
1628 hr
= TestFilter_Create(&GUID_NULL
, PinData4
, (LPVOID
)&ptestfilter2
);
1629 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1630 if (FAILED(hr
)) goto out
;
1632 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName3
);
1633 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1635 IBaseFilter_Release(ptestfilter2
);
1636 ptestfilter2
= NULL
;
1638 hr
= TestFilter_Create(&GUID_NULL
, PinData5
, (LPVOID
)&ptestfilter2
);
1639 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1640 if (FAILED(hr
)) goto out
;
1642 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName4
);
1643 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1645 hr
= IFilterGraph2_Render(pgraph2
, ((TestFilterImpl
*)ptestfilter
)->ppPins
[0]);
1646 ok(hr
== S_OK
, "IFilterGraph2_Render failed with %08x\n", hr
);
1648 get_connected_filter_name((TestFilterImpl
*)ptestfilter
, ConnectedFilterName1
);
1649 ok(!lstrcmp(ConnectedFilterName1
, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1
, "TestfilterInstance2"),
1650 "unexpected connected filter: %s\n", ConnectedFilterName1
);
1652 IFilterGraph2_Release(pgraph2
);
1654 IBaseFilter_Release(ptestfilter
);
1656 IBaseFilter_Release(ptestfilter2
);
1657 ptestfilter2
= NULL
;
1659 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterGraph2
, (LPVOID
*)&pgraph2
);
1660 ok(hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
1661 if (!pgraph2
) goto out
;
1663 hr
= TestFilter_Create(&GUID_NULL
, PinData1
, (LPVOID
)&ptestfilter
);
1664 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1665 if (FAILED(hr
)) goto out
;
1667 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter
, wszFilterInstanceName1
);
1668 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1670 hr
= TestFilter_Create(&GUID_NULL
, PinData4
, (LPVOID
)&ptestfilter2
);
1671 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1672 if (FAILED(hr
)) goto out
;
1674 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName3
);
1675 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1677 IBaseFilter_Release(ptestfilter2
);
1678 ptestfilter2
= NULL
;
1680 hr
= TestFilter_Create(&GUID_NULL
, PinData5
, (LPVOID
)&ptestfilter2
);
1681 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1682 if (FAILED(hr
)) goto out
;
1684 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName4
);
1685 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1687 IBaseFilter_Release(ptestfilter2
);
1688 ptestfilter2
= NULL
;
1690 hr
= TestFilter_Create(&GUID_NULL
, PinData2
, (LPVOID
)&ptestfilter2
);
1691 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1692 if (FAILED(hr
)) goto out
;
1694 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName2
);
1695 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1697 hr
= IFilterGraph2_Render(pgraph2
, ((TestFilterImpl
*)ptestfilter
)->ppPins
[0]);
1698 ok(hr
== S_OK
, "IFilterGraph2_Render failed with %08x\n", hr
);
1700 get_connected_filter_name((TestFilterImpl
*)ptestfilter
, ConnectedFilterName2
);
1701 ok(!lstrcmp(ConnectedFilterName2
, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2
, "TestfilterInstance2"),
1702 "unexpected connected filter: %s\n", ConnectedFilterName2
);
1703 ok(lstrcmp(ConnectedFilterName1
, ConnectedFilterName2
),
1704 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1
);
1706 IFilterGraph2_Release(pgraph2
);
1708 IBaseFilter_Release(ptestfilter
);
1710 IBaseFilter_Release(ptestfilter2
);
1711 ptestfilter2
= NULL
;
1713 /* Test if renderers are tried before non-renderers (intermediary filters). */
1714 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterGraph2
, (LPVOID
*)&pgraph2
);
1715 ok(hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
1716 if (!pgraph2
) goto out
;
1718 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterMapper2
, (LPVOID
*)&pMapper2
);
1719 ok(hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
1720 if (!pMapper2
) goto out
;
1722 hr
= TestFilter_Create(&GUID_NULL
, PinData1
, (LPVOID
)&ptestfilter
);
1723 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1724 if (FAILED(hr
)) goto out
;
1726 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter
, wszFilterInstanceName1
);
1727 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1729 /* Register our filters with COM and with Filtermapper. */
1730 hr
= CoRegisterClassObject(Filter1ClassFactory
.clsid
, (IUnknown
*)&Filter1ClassFactory
,
1731 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie1
);
1732 ok(hr
== S_OK
, "CoRegisterClassObject failed with %08x\n", hr
);
1733 hr
= CoRegisterClassObject(Filter2ClassFactory
.clsid
, (IUnknown
*)&Filter2ClassFactory
,
1734 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie2
);
1735 ok(hr
== S_OK
, "CoRegisterClassObject failed with %08x\n", hr
);
1736 hr
= CoRegisterClassObject(Filter3ClassFactory
.clsid
, (IUnknown
*)&Filter3ClassFactory
,
1737 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie3
);
1738 ok(hr
== S_OK
, "CoRegisterClassObject failed with %08x\n", hr
);
1741 rgf2
.dwMerit
= MERIT_UNLIKELY
;
1742 S1(U(rgf2
)).cPins2
= 1;
1743 S1(U(rgf2
)).rgPins2
= rgPins2
;
1744 rgPins2
[0].dwFlags
= REG_PINFLAG_B_RENDERER
;
1745 rgPins2
[0].cInstances
= 1;
1746 rgPins2
[0].nMediaTypes
= 1;
1747 rgPins2
[0].lpMediaType
= &rgPinType
[0];
1748 rgPins2
[0].nMediums
= 0;
1749 rgPins2
[0].lpMedium
= NULL
;
1750 rgPins2
[0].clsPinCategory
= NULL
;
1751 rgPinType
[0].clsMajorType
= &MEDIATYPE_Video
;
1752 rgPinType
[0].clsMinorType
= &mediasubtype1
;
1754 hr
= IFilterMapper2_RegisterFilter(pMapper2
, &CLSID_TestFilter2
, wszFilterInstanceName2
, NULL
,
1755 &CLSID_LegacyAmFilterCategory
, NULL
, &rgf2
);
1756 ok(hr
== S_OK
, "IFilterMapper2_RegisterFilter failed with %x\n", hr
);
1758 rgf2
.dwMerit
= MERIT_PREFERRED
;
1759 rgPinType
[0].clsMinorType
= &mediasubtype2
;
1761 hr
= IFilterMapper2_RegisterFilter(pMapper2
, &CLSID_TestFilter4
, wszFilterInstanceName4
, NULL
,
1762 &CLSID_LegacyAmFilterCategory
, NULL
, &rgf2
);
1763 ok(hr
== S_OK
, "IFilterMapper2_RegisterFilter failed with %x\n", hr
);
1765 S1(U(rgf2
)).cPins2
= 2;
1766 rgPins2
[0].dwFlags
= 0;
1767 rgPinType
[0].clsMinorType
= &mediasubtype1
;
1769 rgPins2
[1].dwFlags
= REG_PINFLAG_B_OUTPUT
;
1770 rgPins2
[1].cInstances
= 1;
1771 rgPins2
[1].nMediaTypes
= 1;
1772 rgPins2
[1].lpMediaType
= &rgPinType
[1];
1773 rgPins2
[1].nMediums
= 0;
1774 rgPins2
[1].lpMedium
= NULL
;
1775 rgPins2
[1].clsPinCategory
= NULL
;
1776 rgPinType
[1].clsMajorType
= &MEDIATYPE_Video
;
1777 rgPinType
[1].clsMinorType
= &mediasubtype2
;
1779 hr
= IFilterMapper2_RegisterFilter(pMapper2
, &CLSID_TestFilter3
, wszFilterInstanceName3
, NULL
,
1780 &CLSID_LegacyAmFilterCategory
, NULL
, &rgf2
);
1781 ok(hr
== S_OK
, "IFilterMapper2_RegisterFilter failed with %x\n", hr
);
1783 hr
= IFilterGraph2_Render(pgraph2
, ((TestFilterImpl
*)ptestfilter
)->ppPins
[0]);
1784 ok(hr
== S_OK
, "IFilterGraph2_Render failed with %08x\n", hr
);
1786 get_connected_filter_name((TestFilterImpl
*)ptestfilter
, ConnectedFilterName1
);
1787 ok(!lstrcmp(ConnectedFilterName1
, "TestfilterInstance3"),
1788 "unexpected connected filter: %s\n", ConnectedFilterName1
);
1790 hr
= IFilterMapper2_UnregisterFilter(pMapper2
, &CLSID_LegacyAmFilterCategory
, NULL
,
1791 &CLSID_TestFilter2
);
1792 ok(SUCCEEDED(hr
), "IFilterMapper2_UnregisterFilter failed with %x\n", hr
);
1793 hr
= IFilterMapper2_UnregisterFilter(pMapper2
, &CLSID_LegacyAmFilterCategory
, NULL
,
1794 &CLSID_TestFilter3
);
1795 ok(SUCCEEDED(hr
), "IFilterMapper2_UnregisterFilter failed with %x\n", hr
);
1796 hr
= IFilterMapper2_UnregisterFilter(pMapper2
, &CLSID_LegacyAmFilterCategory
, NULL
,
1797 &CLSID_TestFilter4
);
1798 ok(SUCCEEDED(hr
), "IFilterMapper2_UnregisterFilter failed with %x\n", hr
);
1802 if (ptestfilter
) IBaseFilter_Release(ptestfilter
);
1803 if (ptestfilter2
) IBaseFilter_Release(ptestfilter2
);
1804 if (pgraph2
) IFilterGraph2_Release(pgraph2
);
1805 if (pMapper2
) IFilterMapper2_Release(pMapper2
);
1807 hr
= CoRevokeClassObject(cookie1
);
1808 ok(hr
== S_OK
, "CoRevokeClassObject failed with %08x\n", hr
);
1809 hr
= CoRevokeClassObject(cookie2
);
1810 ok(hr
== S_OK
, "CoRevokeClassObject failed with %08x\n", hr
);
1811 hr
= CoRevokeClassObject(cookie3
);
1812 ok(hr
== S_OK
, "CoRevokeClassObject failed with %08x\n", hr
);
1815 START_TEST(filtergraph
)
1817 CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
1819 test_graph_builder();
1820 test_graph_builder_addfilter();
1821 test_mediacontrol();
1822 test_filter_graph2();
1823 test_render_filter_priority();