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"
31 static const char avifileA
[FILE_LEN
] = "test.avi";
32 static const char mpegfileA
[FILE_LEN
] = "test.mpg";
34 IGraphBuilder
* pgraph
;
36 static int createfiltergraph(void)
38 return S_OK
== CoCreateInstance(
39 &CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IGraphBuilder
, (LPVOID
*)&pgraph
);
42 static void renderfile(const char * fileA
)
45 WCHAR fileW
[FILE_LEN
];
47 MultiByteToWideChar(CP_ACP
, 0, fileA
, -1, fileW
, FILE_LEN
);
49 hr
= IGraphBuilder_RenderFile(pgraph
, fileW
, NULL
);
50 ok(hr
==S_OK
, "RenderFile returned: %x\n", hr
);
53 static void rungraph(void)
61 hr
= IGraphBuilder_QueryInterface(pgraph
, &IID_IMediaControl
, (LPVOID
*)&pmc
);
62 ok(hr
==S_OK
, "Cannot get IMediaControl interface returned: %x\n", hr
);
64 hr
= IGraphBuilder_QueryInterface(pgraph
, &IID_IMediaFilter
, (LPVOID
*)&pmf
);
65 ok(hr
==S_OK
, "Cannot get IMediaFilter interface returned: %x\n", hr
);
67 IMediaControl_Stop(pmc
);
69 IMediaFilter_SetSyncSource(pmf
, NULL
);
71 IMediaFilter_Release(pmf
);
73 hr
= IMediaControl_Run(pmc
);
74 ok(hr
==S_FALSE
, "Cannot run the graph returned: %x\n", hr
);
78 trace("run -> stop\n");
79 hr
= IMediaControl_Stop(pmc
);
80 ok(hr
==S_OK
|| hr
== S_FALSE
, "Cannot stop the graph returned: %x\n", hr
);
82 IGraphBuilder_SetDefaultSyncSource(pgraph
);
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
);
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
);
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
);
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
);
105 trace("pause -> run\n");
106 hr
= IMediaControl_Run(pmc
);
107 ok(hr
==S_OK
|| hr
== S_FALSE
, "Cannot start the graph returned: %x\n", hr
);
109 trace("run -> stop\n");
110 hr
= IMediaControl_Stop(pmc
);
111 ok(hr
==S_OK
|| hr
== S_FALSE
, "Cannot stop the graph returned: %x\n", hr
);
113 trace("stop -> run\n");
114 hr
= IMediaControl_Run(pmc
);
115 ok(hr
==S_OK
|| hr
== S_FALSE
, "Cannot start the graph returned: %x\n", hr
);
117 hr
= IGraphBuilder_QueryInterface(pgraph
, &IID_IMediaEvent
, (LPVOID
*)&pme
);
118 ok(hr
==S_OK
, "Cannot get IMediaEvent interface returned: %x\n", hr
);
120 hr
= IMediaEvent_GetEventHandle(pme
, (OAEVENT
*)&hEvent
);
121 ok(hr
==S_OK
, "Cannot get event handle returned: %x\n", hr
);
123 /* WaitForSingleObject(hEvent, INFINITE); */
126 hr
= IMediaEvent_Release(pme
);
127 ok(hr
==2, "Releasing mediaevent returned: %x\n", hr
);
129 hr
= IMediaControl_Stop(pmc
);
130 ok(hr
==S_OK
, "Cannot stop the graph returned: %x\n", hr
);
132 hr
= IMediaControl_Release(pmc
);
133 ok(hr
==1, "Releasing mediacontrol returned: %x\n", hr
);
136 static void releasefiltergraph(void)
140 hr
= IGraphBuilder_Release(pgraph
);
141 ok(hr
==0, "Releasing filtergraph returned: %x\n", hr
);
144 static void test_render_run(const char * fileA
)
148 if (!createfiltergraph())
151 h
= CreateFileA(fileA
, 0, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
152 if (h
!= INVALID_HANDLE_VALUE
) {
158 releasefiltergraph();
161 static void test_graph_builder(void)
164 IBaseFilter
*pF
= NULL
;
165 IBaseFilter
*pF2
= NULL
;
167 IEnumPins
*pEnum
= NULL
;
169 static const WCHAR testFilterW
[] = {'t','e','s','t','F','i','l','t','e','r',0};
170 static const WCHAR fooBarW
[] = {'f','o','o','B','a','r',0};
172 if (!createfiltergraph())
175 /* create video filter */
176 hr
= CoCreateInstance(&CLSID_VideoRenderer
, NULL
, CLSCTX_INPROC_SERVER
,
177 &IID_IBaseFilter
, (LPVOID
*)&pF
);
178 ok(hr
== S_OK
, "CoCreateInstance failed with %x\n", hr
);
179 ok(pF
!= NULL
, "pF is NULL\n");
181 /* add the two filters to the graph */
182 hr
= IGraphBuilder_AddFilter(pgraph
, pF
, testFilterW
);
183 ok(hr
== S_OK
, "failed to add pF to the graph: %x\n", hr
);
186 hr
= IBaseFilter_EnumPins(pF
, &pEnum
);
187 ok(hr
== S_OK
, "IBaseFilter_EnumPins failed for pF: %x\n", hr
);
188 ok(pEnum
!= NULL
, "pEnum is NULL\n");
189 hr
= IEnumPins_Next(pEnum
, 1, &pIn
, NULL
);
190 ok(hr
== S_OK
, "IEnumPins_Next failed for pF: %x\n", hr
);
191 ok(pIn
!= NULL
, "pIn is NULL\n");
192 hr
= IPin_QueryDirection(pIn
, &dir
);
193 ok(hr
== S_OK
, "IPin_QueryDirection failed: %x\n", hr
);
194 ok(dir
== PINDIR_INPUT
, "pin has wrong direction\n");
196 hr
= IGraphBuilder_FindFilterByName(pgraph
, fooBarW
, &pF2
);
197 ok(hr
== VFW_E_NOT_FOUND
, "IGraphBuilder_FindFilterByName returned %x\n", hr
);
198 ok(pF2
== NULL
, "IGraphBuilder_FindFilterByName returned %p\n", pF2
);
199 hr
= IGraphBuilder_FindFilterByName(pgraph
, testFilterW
, &pF2
);
200 ok(hr
== S_OK
, "IGraphBuilder_FindFilterByName returned %x\n", hr
);
201 ok(pF2
!= NULL
, "IGraphBuilder_FindFilterByName returned NULL\n");
202 hr
= IGraphBuilder_FindFilterByName(pgraph
, testFilterW
, NULL
);
203 ok(hr
== E_POINTER
, "IGraphBuilder_FindFilterByName returned %x\n", hr
);
205 if (pIn
) IPin_Release(pIn
);
206 if (pEnum
) IEnumPins_Release(pEnum
);
207 if (pF
) IBaseFilter_Release(pF
);
208 if (pF2
) IBaseFilter_Release(pF2
);
210 releasefiltergraph();
213 static void test_graph_builder_addfilter(void)
216 IBaseFilter
*pF
= NULL
;
217 static const WCHAR testFilterW
[] = {'t','e','s','t','F','i','l','t','e','r',0};
219 if (!createfiltergraph())
222 hr
= IGraphBuilder_AddFilter(pgraph
, NULL
, testFilterW
);
223 ok(hr
== E_POINTER
, "IGraphBuilder_AddFilter returned: %x\n", hr
);
225 /* create video filter */
226 hr
= CoCreateInstance(&CLSID_VideoRenderer
, NULL
, CLSCTX_INPROC_SERVER
,
227 &IID_IBaseFilter
, (LPVOID
*)&pF
);
228 ok(hr
== S_OK
, "CoCreateInstance failed with %x\n", hr
);
229 ok(pF
!= NULL
, "pF is NULL\n");
231 skip("failed to created filter, skipping\n");
235 hr
= IGraphBuilder_AddFilter(pgraph
, pF
, NULL
);
236 ok(hr
== S_OK
, "IGraphBuilder_AddFilter returned: %x\n", hr
);
237 IMediaFilter_Release(pF
);
240 static void test_mediacontrol(void)
243 LONGLONG pos
= 0xdeadbeef;
244 IMediaSeeking
*seeking
= NULL
;
245 IMediaFilter
*filter
= NULL
;
246 IMediaControl
*control
= NULL
;
248 IFilterGraph2_SetDefaultSyncSource(pgraph
);
249 hr
= IFilterGraph2_QueryInterface(pgraph
, &IID_IMediaSeeking
, (void**) &seeking
);
250 ok(hr
== S_OK
, "QueryInterface IMediaControl failed: %08x\n", hr
);
254 hr
= IFilterGraph2_QueryInterface(pgraph
, &IID_IMediaFilter
, (void**) &filter
);
255 ok(hr
== S_OK
, "QueryInterface IMediaFilter failed: %08x\n", hr
);
258 IUnknown_Release(seeking
);
262 hr
= IFilterGraph2_QueryInterface(pgraph
, &IID_IMediaControl
, (void**) &control
);
263 ok(hr
== S_OK
, "QueryInterface IMediaControl failed: %08x\n", hr
);
266 IUnknown_Release(seeking
);
267 IUnknown_Release(filter
);
271 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &pos
);
272 ok(hr
== S_OK
, "GetCurrentPosition failed: %08x\n", hr
);
273 ok(pos
== 0, "Position != 0 (%x%08x)\n", (DWORD
)(pos
>> 32), (DWORD
)pos
);
275 IMediaFilter_SetSyncSource(filter
, NULL
);
277 hr
= IMediaSeeking_GetCurrentPosition(seeking
, &pos
);
278 ok(hr
== S_OK
, "GetCurrentPosition failed: %08x\n", hr
);
279 ok(pos
== 0, "Position != 0 (%x%08x)\n", (DWORD
)(pos
>> 32), (DWORD
)pos
);
281 hr
= IMediaControl_GetState(control
, 1000, NULL
);
282 ok(hr
== E_POINTER
, "GetState expected %08x, got %08x\n", E_POINTER
, hr
);
284 IUnknown_Release(control
);
285 IUnknown_Release(seeking
);
286 IUnknown_Release(filter
);
287 releasefiltergraph();
290 static void test_filter_graph2(void)
293 IFilterGraph2
*pF
= NULL
;
295 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
296 &IID_IFilterGraph2
, (LPVOID
*)&pF
);
297 ok(hr
== S_OK
, "CoCreateInstance failed with %x\n", hr
);
298 ok(pF
!= NULL
, "pF is NULL\n");
300 hr
= IFilterGraph2_Release(pF
);
301 ok(hr
== 0, "IFilterGraph2_Release returned: %x\n", hr
);
304 /* IEnumMediaTypes implementation (supporting code for Render() test.) */
305 static void FreeMediaType(AM_MEDIA_TYPE
* pMediaType
)
307 if (pMediaType
->pbFormat
)
309 CoTaskMemFree(pMediaType
->pbFormat
);
310 pMediaType
->pbFormat
= NULL
;
312 if (pMediaType
->pUnk
)
314 IUnknown_Release(pMediaType
->pUnk
);
315 pMediaType
->pUnk
= NULL
;
319 static HRESULT
CopyMediaType(AM_MEDIA_TYPE
* pDest
, const AM_MEDIA_TYPE
*pSrc
)
322 if (!pSrc
->pbFormat
) return S_OK
;
323 if (!(pDest
->pbFormat
= CoTaskMemAlloc(pSrc
->cbFormat
)))
324 return E_OUTOFMEMORY
;
325 memcpy(pDest
->pbFormat
, pSrc
->pbFormat
, pSrc
->cbFormat
);
327 IUnknown_AddRef(pDest
->pUnk
);
331 static AM_MEDIA_TYPE
* CreateMediaType(AM_MEDIA_TYPE
const * pSrc
)
333 AM_MEDIA_TYPE
* pDest
;
335 pDest
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
));
339 if (FAILED(CopyMediaType(pDest
, pSrc
)))
341 CoTaskMemFree(pDest
);
348 static BOOL
CompareMediaTypes(const AM_MEDIA_TYPE
* pmt1
, const AM_MEDIA_TYPE
* pmt2
, BOOL bWildcards
)
350 return (((bWildcards
&& (IsEqualGUID(&pmt1
->majortype
, &GUID_NULL
) || IsEqualGUID(&pmt2
->majortype
, &GUID_NULL
))) || IsEqualGUID(&pmt1
->majortype
, &pmt2
->majortype
)) &&
351 ((bWildcards
&& (IsEqualGUID(&pmt1
->subtype
, &GUID_NULL
) || IsEqualGUID(&pmt2
->subtype
, &GUID_NULL
))) || IsEqualGUID(&pmt1
->subtype
, &pmt2
->subtype
)));
354 static void DeleteMediaType(AM_MEDIA_TYPE
* pMediaType
)
356 FreeMediaType(pMediaType
);
357 CoTaskMemFree(pMediaType
);
360 typedef struct IEnumMediaTypesImpl
362 const IEnumMediaTypesVtbl
* lpVtbl
;
364 AM_MEDIA_TYPE
*pMediaTypes
;
367 } IEnumMediaTypesImpl
;
369 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl
;
371 static HRESULT
IEnumMediaTypesImpl_Construct(const AM_MEDIA_TYPE
* pMediaTypes
, ULONG cMediaTypes
, IEnumMediaTypes
** ppEnum
)
374 IEnumMediaTypesImpl
* pEnumMediaTypes
= CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl
));
376 if (!pEnumMediaTypes
)
379 return E_OUTOFMEMORY
;
381 pEnumMediaTypes
->lpVtbl
= &IEnumMediaTypesImpl_Vtbl
;
382 pEnumMediaTypes
->refCount
= 1;
383 pEnumMediaTypes
->uIndex
= 0;
384 pEnumMediaTypes
->cMediaTypes
= cMediaTypes
;
385 pEnumMediaTypes
->pMediaTypes
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
) * cMediaTypes
);
386 for (i
= 0; i
< cMediaTypes
; i
++)
387 if (FAILED(CopyMediaType(&pEnumMediaTypes
->pMediaTypes
[i
], &pMediaTypes
[i
])))
390 FreeMediaType(&pEnumMediaTypes
->pMediaTypes
[i
]);
391 CoTaskMemFree(pEnumMediaTypes
->pMediaTypes
);
392 return E_OUTOFMEMORY
;
394 *ppEnum
= (IEnumMediaTypes
*)(&pEnumMediaTypes
->lpVtbl
);
398 static HRESULT WINAPI
IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes
* iface
, REFIID riid
, LPVOID
* ppv
)
402 if (IsEqualIID(riid
, &IID_IUnknown
))
404 else if (IsEqualIID(riid
, &IID_IEnumMediaTypes
))
409 IUnknown_AddRef((IUnknown
*)(*ppv
));
413 return E_NOINTERFACE
;
416 static ULONG WINAPI
IEnumMediaTypesImpl_AddRef(IEnumMediaTypes
* iface
)
418 IEnumMediaTypesImpl
*This
= (IEnumMediaTypesImpl
*)iface
;
419 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
424 static ULONG WINAPI
IEnumMediaTypesImpl_Release(IEnumMediaTypes
* iface
)
426 IEnumMediaTypesImpl
*This
= (IEnumMediaTypesImpl
*)iface
;
427 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
432 for (i
= 0; i
< This
->cMediaTypes
; i
++)
433 FreeMediaType(&This
->pMediaTypes
[i
]);
434 CoTaskMemFree(This
->pMediaTypes
);
440 static HRESULT WINAPI
IEnumMediaTypesImpl_Next(IEnumMediaTypes
* iface
, ULONG cMediaTypes
, AM_MEDIA_TYPE
** ppMediaTypes
, ULONG
* pcFetched
)
443 IEnumMediaTypesImpl
*This
= (IEnumMediaTypesImpl
*)iface
;
445 cFetched
= min(This
->cMediaTypes
, This
->uIndex
+ cMediaTypes
) - This
->uIndex
;
450 for (i
= 0; i
< cFetched
; i
++)
451 if (!(ppMediaTypes
[i
] = CreateMediaType(&This
->pMediaTypes
[This
->uIndex
+ i
])))
454 DeleteMediaType(ppMediaTypes
[i
]);
456 return E_OUTOFMEMORY
;
460 if ((cMediaTypes
!= 1) || pcFetched
)
461 *pcFetched
= cFetched
;
463 This
->uIndex
+= cFetched
;
465 if (cFetched
!= cMediaTypes
)
470 static HRESULT WINAPI
IEnumMediaTypesImpl_Skip(IEnumMediaTypes
* iface
, ULONG cMediaTypes
)
472 IEnumMediaTypesImpl
*This
= (IEnumMediaTypesImpl
*)iface
;
474 if (This
->uIndex
+ cMediaTypes
< This
->cMediaTypes
)
476 This
->uIndex
+= cMediaTypes
;
482 static HRESULT WINAPI
IEnumMediaTypesImpl_Reset(IEnumMediaTypes
* iface
)
484 IEnumMediaTypesImpl
*This
= (IEnumMediaTypesImpl
*)iface
;
490 static HRESULT WINAPI
IEnumMediaTypesImpl_Clone(IEnumMediaTypes
* iface
, IEnumMediaTypes
** ppEnum
)
493 IEnumMediaTypesImpl
*This
= (IEnumMediaTypesImpl
*)iface
;
495 hr
= IEnumMediaTypesImpl_Construct(This
->pMediaTypes
, This
->cMediaTypes
, ppEnum
);
498 return IEnumMediaTypes_Skip(*ppEnum
, This
->uIndex
);
501 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl
=
503 IEnumMediaTypesImpl_QueryInterface
,
504 IEnumMediaTypesImpl_AddRef
,
505 IEnumMediaTypesImpl_Release
,
506 IEnumMediaTypesImpl_Next
,
507 IEnumMediaTypesImpl_Skip
,
508 IEnumMediaTypesImpl_Reset
,
509 IEnumMediaTypesImpl_Clone
512 /* Implementation of a very stripped down pin for the test filter. Just enough
513 functionality for connecting and Render() to work. */
515 static void Copy_PinInfo(PIN_INFO
* pDest
, const PIN_INFO
* pSrc
)
517 lstrcpyW(pDest
->achName
, pSrc
->achName
);
518 pDest
->dir
= pSrc
->dir
;
519 pDest
->pFilter
= pSrc
->pFilter
;
522 typedef struct ITestPinImpl
524 const struct IPinVtbl
* lpVtbl
;
526 LPCRITICAL_SECTION pCritSec
;
529 AM_MEDIA_TYPE mtCurrent
;
533 static HRESULT WINAPI
TestFilter_Pin_QueryInterface(IPin
* iface
, REFIID riid
, LPVOID
* ppv
)
537 if (IsEqualIID(riid
, &IID_IUnknown
))
539 else if (IsEqualIID(riid
, &IID_IPin
))
544 IUnknown_AddRef((IUnknown
*)(*ppv
));
548 return E_NOINTERFACE
;
551 static ULONG WINAPI
TestFilter_Pin_AddRef(IPin
* iface
)
553 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
554 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
558 static ULONG WINAPI
TestFilter_Pin_Release(IPin
* iface
)
560 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
561 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
565 FreeMediaType(&This
->mtCurrent
);
574 static HRESULT WINAPI
TestFilter_InputPin_Connect(IPin
* iface
, IPin
* pConnector
, const AM_MEDIA_TYPE
* pmt
)
579 static HRESULT WINAPI
TestFilter_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
581 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
582 PIN_DIRECTION pindirReceive
;
585 EnterCriticalSection(This
->pCritSec
);
587 if (!(IsEqualIID(&pmt
->majortype
, &This
->mtCurrent
.majortype
) && (IsEqualIID(&pmt
->subtype
, &This
->mtCurrent
.subtype
) ||
588 IsEqualIID(&GUID_NULL
, &This
->mtCurrent
.subtype
))))
589 hr
= VFW_E_TYPE_NOT_ACCEPTED
;
591 if (This
->pConnectedTo
)
592 hr
= VFW_E_ALREADY_CONNECTED
;
596 IPin_QueryDirection(pReceivePin
, &pindirReceive
);
598 if (pindirReceive
!= PINDIR_OUTPUT
)
600 hr
= VFW_E_INVALID_DIRECTION
;
606 CopyMediaType(&This
->mtCurrent
, pmt
);
607 This
->pConnectedTo
= pReceivePin
;
608 IPin_AddRef(pReceivePin
);
611 LeaveCriticalSection(This
->pCritSec
);
616 static HRESULT WINAPI
TestFilter_Pin_Disconnect(IPin
* iface
)
619 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
621 EnterCriticalSection(This
->pCritSec
);
623 if (This
->pConnectedTo
)
625 IPin_Release(This
->pConnectedTo
);
626 This
->pConnectedTo
= NULL
;
632 LeaveCriticalSection(This
->pCritSec
);
637 static HRESULT WINAPI
TestFilter_Pin_ConnectedTo(IPin
* iface
, IPin
** ppPin
)
640 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
642 EnterCriticalSection(This
->pCritSec
);
644 if (This
->pConnectedTo
)
646 *ppPin
= This
->pConnectedTo
;
652 hr
= VFW_E_NOT_CONNECTED
;
656 LeaveCriticalSection(This
->pCritSec
);
661 static HRESULT WINAPI
TestFilter_Pin_ConnectionMediaType(IPin
* iface
, AM_MEDIA_TYPE
* pmt
)
664 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
666 EnterCriticalSection(This
->pCritSec
);
668 if (This
->pConnectedTo
)
670 CopyMediaType(pmt
, &This
->mtCurrent
);
675 ZeroMemory(pmt
, sizeof(*pmt
));
676 hr
= VFW_E_NOT_CONNECTED
;
679 LeaveCriticalSection(This
->pCritSec
);
684 static HRESULT WINAPI
TestFilter_Pin_QueryPinInfo(IPin
* iface
, PIN_INFO
* pInfo
)
686 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
688 Copy_PinInfo(pInfo
, &This
->pinInfo
);
689 IBaseFilter_AddRef(pInfo
->pFilter
);
694 static HRESULT WINAPI
TestFilter_Pin_QueryDirection(IPin
* iface
, PIN_DIRECTION
* pPinDir
)
696 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
698 *pPinDir
= This
->pinInfo
.dir
;
703 static HRESULT WINAPI
TestFilter_Pin_QueryId(IPin
* iface
, LPWSTR
* Id
)
708 static HRESULT WINAPI
TestFilter_Pin_QueryAccept(IPin
* iface
, const AM_MEDIA_TYPE
* pmt
)
710 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
712 if (IsEqualIID(&pmt
->majortype
, &This
->mtCurrent
.majortype
) && (IsEqualIID(&pmt
->subtype
, &This
->mtCurrent
.subtype
) ||
713 IsEqualIID(&GUID_NULL
, &This
->mtCurrent
.subtype
)))
716 return VFW_E_TYPE_NOT_ACCEPTED
;
719 static HRESULT WINAPI
TestFilter_Pin_EnumMediaTypes(IPin
* iface
, IEnumMediaTypes
** ppEnum
)
721 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
723 return IEnumMediaTypesImpl_Construct(&This
->mtCurrent
, 1, ppEnum
);
726 static HRESULT WINAPI
TestFilter_Pin_QueryInternalConnections(IPin
* iface
, IPin
** apPin
, ULONG
* cPin
)
731 static HRESULT WINAPI
TestFilter_Pin_BeginFlush(IPin
* iface
)
736 static HRESULT WINAPI
TestFilter_Pin_EndFlush(IPin
* iface
)
741 static HRESULT WINAPI
TestFilter_Pin_NewSegment(IPin
* iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double dRate
)
746 static HRESULT WINAPI
TestFilter_Pin_EndOfStream(IPin
* iface
)
751 static const IPinVtbl TestFilter_InputPin_Vtbl
=
753 TestFilter_Pin_QueryInterface
,
754 TestFilter_Pin_AddRef
,
755 TestFilter_Pin_Release
,
756 TestFilter_InputPin_Connect
,
757 TestFilter_InputPin_ReceiveConnection
,
758 TestFilter_Pin_Disconnect
,
759 TestFilter_Pin_ConnectedTo
,
760 TestFilter_Pin_ConnectionMediaType
,
761 TestFilter_Pin_QueryPinInfo
,
762 TestFilter_Pin_QueryDirection
,
763 TestFilter_Pin_QueryId
,
764 TestFilter_Pin_QueryAccept
,
765 TestFilter_Pin_EnumMediaTypes
,
766 TestFilter_Pin_QueryInternalConnections
,
767 TestFilter_Pin_EndOfStream
,
768 TestFilter_Pin_BeginFlush
,
769 TestFilter_Pin_EndFlush
,
770 TestFilter_Pin_NewSegment
773 static HRESULT WINAPI
TestFilter_OutputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
778 /* Private helper function */
779 static HRESULT
TestFilter_OutputPin_ConnectSpecific(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
781 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
784 This
->pConnectedTo
= pReceivePin
;
785 IPin_AddRef(pReceivePin
);
787 hr
= IPin_ReceiveConnection(pReceivePin
, iface
, pmt
);
791 IPin_Release(This
->pConnectedTo
);
792 This
->pConnectedTo
= NULL
;
798 static HRESULT WINAPI
TestFilter_OutputPin_Connect(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
800 ITestPinImpl
*This
= (ITestPinImpl
*)iface
;
803 EnterCriticalSection(This
->pCritSec
);
805 /* if we have been a specific type to connect with, then we can either connect
806 * with that or fail. We cannot choose different AM_MEDIA_TYPE */
807 if (pmt
&& !IsEqualGUID(&pmt
->majortype
, &GUID_NULL
) && !IsEqualGUID(&pmt
->subtype
, &GUID_NULL
))
808 hr
= TestFilter_OutputPin_ConnectSpecific(iface
, pReceivePin
, pmt
);
811 if (( !pmt
|| CompareMediaTypes(pmt
, &This
->mtCurrent
, TRUE
) ) &&
812 (TestFilter_OutputPin_ConnectSpecific(iface
, pReceivePin
, &This
->mtCurrent
) == S_OK
))
814 else hr
= VFW_E_NO_ACCEPTABLE_TYPES
;
815 } /* if negotiate media type */
817 LeaveCriticalSection(This
->pCritSec
);
822 static const IPinVtbl TestFilter_OutputPin_Vtbl
=
824 TestFilter_Pin_QueryInterface
,
825 TestFilter_Pin_AddRef
,
826 TestFilter_Pin_Release
,
827 TestFilter_OutputPin_Connect
,
828 TestFilter_OutputPin_ReceiveConnection
,
829 TestFilter_Pin_Disconnect
,
830 TestFilter_Pin_ConnectedTo
,
831 TestFilter_Pin_ConnectionMediaType
,
832 TestFilter_Pin_QueryPinInfo
,
833 TestFilter_Pin_QueryDirection
,
834 TestFilter_Pin_QueryId
,
835 TestFilter_Pin_QueryAccept
,
836 TestFilter_Pin_EnumMediaTypes
,
837 TestFilter_Pin_QueryInternalConnections
,
838 TestFilter_Pin_EndOfStream
,
839 TestFilter_Pin_BeginFlush
,
840 TestFilter_Pin_EndFlush
,
841 TestFilter_Pin_NewSegment
844 static HRESULT
TestFilter_Pin_Construct(const IPinVtbl
*Pin_Vtbl
, const PIN_INFO
* pPinInfo
, AM_MEDIA_TYPE
*pinmt
,
845 LPCRITICAL_SECTION pCritSec
, IPin
** ppPin
)
847 ITestPinImpl
* pPinImpl
;
851 pPinImpl
= CoTaskMemAlloc(sizeof(ITestPinImpl
));
854 return E_OUTOFMEMORY
;
856 pPinImpl
->refCount
= 1;
857 pPinImpl
->pConnectedTo
= NULL
;
858 pPinImpl
->pCritSec
= pCritSec
;
859 Copy_PinInfo(&pPinImpl
->pinInfo
, pPinInfo
);
860 pPinImpl
->mtCurrent
= *pinmt
;
862 pPinImpl
->lpVtbl
= Pin_Vtbl
;
864 *ppPin
= (IPin
*)pPinImpl
;
868 /* IEnumPins implementation */
870 typedef HRESULT (* FNOBTAINPIN
)(IBaseFilter
*iface
, ULONG pos
, IPin
**pin
, DWORD
*lastsynctick
);
872 typedef struct IEnumPinsImpl
874 const IEnumPinsVtbl
* lpVtbl
;
878 FNOBTAINPIN receive_pin
;
882 static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl
;
884 static HRESULT
IEnumPinsImpl_Construct(IEnumPins
** ppEnum
, FNOBTAINPIN receive_pin
, IBaseFilter
*base
)
886 IEnumPinsImpl
* pEnumPins
;
891 pEnumPins
= CoTaskMemAlloc(sizeof(IEnumPinsImpl
));
895 return E_OUTOFMEMORY
;
897 pEnumPins
->lpVtbl
= &IEnumPinsImpl_Vtbl
;
898 pEnumPins
->refCount
= 1;
899 pEnumPins
->uIndex
= 0;
900 pEnumPins
->receive_pin
= receive_pin
;
901 pEnumPins
->base
= base
;
902 IBaseFilter_AddRef(base
);
903 *ppEnum
= (IEnumPins
*)(&pEnumPins
->lpVtbl
);
905 receive_pin(base
, ~0, NULL
, &pEnumPins
->synctime
);
910 static HRESULT WINAPI
IEnumPinsImpl_QueryInterface(IEnumPins
* iface
, REFIID riid
, LPVOID
* ppv
)
914 if (IsEqualIID(riid
, &IID_IUnknown
))
916 else if (IsEqualIID(riid
, &IID_IEnumPins
))
921 IUnknown_AddRef((IUnknown
*)(*ppv
));
925 return E_NOINTERFACE
;
928 static ULONG WINAPI
IEnumPinsImpl_AddRef(IEnumPins
* iface
)
930 IEnumPinsImpl
*This
= (IEnumPinsImpl
*)iface
;
931 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
936 static ULONG WINAPI
IEnumPinsImpl_Release(IEnumPins
* iface
)
938 IEnumPinsImpl
*This
= (IEnumPinsImpl
*)iface
;
939 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
943 IBaseFilter_Release(This
->base
);
951 static HRESULT WINAPI
IEnumPinsImpl_Next(IEnumPins
* iface
, ULONG cPins
, IPin
** ppPins
, ULONG
* pcFetched
)
953 IEnumPinsImpl
*This
= (IEnumPinsImpl
*)iface
;
954 DWORD synctime
= This
->synctime
;
961 if (cPins
> 1 && !pcFetched
)
967 while (i
< cPins
&& hr
== S_OK
)
969 hr
= This
->receive_pin(This
->base
, This
->uIndex
+ i
, &ppPins
[i
], &synctime
);
974 if (synctime
!= This
->synctime
)
978 if (!i
&& synctime
!= This
->synctime
)
979 return VFW_E_ENUM_OUT_OF_SYNC
;
990 static HRESULT WINAPI
IEnumPinsImpl_Skip(IEnumPins
* iface
, ULONG cPins
)
992 IEnumPinsImpl
*This
= (IEnumPinsImpl
*)iface
;
993 DWORD synctime
= This
->synctime
;
997 hr
= This
->receive_pin(This
->base
, This
->uIndex
+ cPins
, &pin
, &synctime
);
1001 if (synctime
!= This
->synctime
)
1002 return VFW_E_ENUM_OUT_OF_SYNC
;
1005 This
->uIndex
+= cPins
;
1010 static HRESULT WINAPI
IEnumPinsImpl_Reset(IEnumPins
* iface
)
1012 IEnumPinsImpl
*This
= (IEnumPinsImpl
*)iface
;
1014 This
->receive_pin(This
->base
, ~0, NULL
, &This
->synctime
);
1020 static HRESULT WINAPI
IEnumPinsImpl_Clone(IEnumPins
* iface
, IEnumPins
** ppEnum
)
1023 IEnumPinsImpl
*This
= (IEnumPinsImpl
*)iface
;
1025 hr
= IEnumPinsImpl_Construct(ppEnum
, This
->receive_pin
, This
->base
);
1028 return IEnumPins_Skip(*ppEnum
, This
->uIndex
);
1031 static const IEnumPinsVtbl IEnumPinsImpl_Vtbl
=
1033 IEnumPinsImpl_QueryInterface
,
1034 IEnumPinsImpl_AddRef
,
1035 IEnumPinsImpl_Release
,
1038 IEnumPinsImpl_Reset
,
1042 /* Test filter implementation - a filter that has few predefined pins with single media type
1043 * that accept only this single media type. Enough for Render(). */
1045 typedef struct TestFilterPinData
1047 PIN_DIRECTION pinDir
;
1048 const GUID
*mediasubtype
;
1049 } TestFilterPinData
;
1051 typedef struct TestFilterImpl
1053 const IBaseFilterVtbl
* lpVtbl
;
1056 CRITICAL_SECTION csFilter
;
1058 FILTER_INFO filterInfo
;
1064 static const IBaseFilterVtbl TestFilter_Vtbl
;
1066 static HRESULT
TestFilter_Create(const CLSID
* pClsid
, const TestFilterPinData
*pinData
, LPVOID
* ppv
)
1068 static const WCHAR wcsInputPinName
[] = {'i','n','p','u','t',' ','p','i','n',0};
1069 static const WCHAR wcsOutputPinName
[] = {'o','u','t','p','u','t',' ','p','i','n',0};
1072 TestFilterImpl
* pTestFilter
= NULL
;
1076 pTestFilter
= CoTaskMemAlloc(sizeof(TestFilterImpl
));
1077 if (!pTestFilter
) return E_OUTOFMEMORY
;
1079 pTestFilter
->clsid
= *pClsid
;
1080 pTestFilter
->lpVtbl
= &TestFilter_Vtbl
;
1081 pTestFilter
->refCount
= 1;
1082 InitializeCriticalSection(&pTestFilter
->csFilter
);
1083 pTestFilter
->state
= State_Stopped
;
1085 ZeroMemory(&pTestFilter
->filterInfo
, sizeof(FILTER_INFO
));
1088 while(pinData
[nPins
].mediasubtype
) ++nPins
;
1090 pTestFilter
->ppPins
= CoTaskMemAlloc(nPins
* sizeof(IPin
*));
1091 if (!pTestFilter
->ppPins
)
1096 ZeroMemory(pTestFilter
->ppPins
, nPins
* sizeof(IPin
*));
1098 for (i
= 0; i
< nPins
; i
++)
1100 ZeroMemory(&mt
, sizeof(mt
));
1101 mt
.majortype
= MEDIATYPE_Video
;
1102 mt
.formattype
= FORMAT_None
;
1103 mt
.subtype
= *pinData
[i
].mediasubtype
;
1105 pinInfo
.dir
= pinData
[i
].pinDir
;
1106 pinInfo
.pFilter
= (IBaseFilter
*)pTestFilter
;
1107 if (pinInfo
.dir
== PINDIR_INPUT
)
1109 lstrcpynW(pinInfo
.achName
, wcsInputPinName
, sizeof(pinInfo
.achName
) / sizeof(pinInfo
.achName
[0]));
1110 hr
= TestFilter_Pin_Construct(&TestFilter_InputPin_Vtbl
, &pinInfo
, &mt
, &pTestFilter
->csFilter
,
1111 &pTestFilter
->ppPins
[i
]);
1116 lstrcpynW(pinInfo
.achName
, wcsOutputPinName
, sizeof(pinInfo
.achName
) / sizeof(pinInfo
.achName
[0]));
1117 hr
= TestFilter_Pin_Construct(&TestFilter_OutputPin_Vtbl
, &pinInfo
, &mt
, &pTestFilter
->csFilter
,
1118 &pTestFilter
->ppPins
[i
]);
1120 if (FAILED(hr
) || !pTestFilter
->ppPins
[i
]) goto error
;
1123 pTestFilter
->nPins
= nPins
;
1129 if (pTestFilter
->ppPins
)
1131 for (i
= 0; i
< nPins
; i
++)
1133 if (pTestFilter
->ppPins
[i
]) IPin_Release(pTestFilter
->ppPins
[i
]);
1136 CoTaskMemFree(pTestFilter
->ppPins
);
1137 DeleteCriticalSection(&pTestFilter
->csFilter
);
1138 CoTaskMemFree(pTestFilter
);
1143 static HRESULT WINAPI
TestFilter_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
1145 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1149 if (IsEqualIID(riid
, &IID_IUnknown
))
1151 else if (IsEqualIID(riid
, &IID_IPersist
))
1153 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
1155 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
1160 IUnknown_AddRef((IUnknown
*)(*ppv
));
1164 return E_NOINTERFACE
;
1167 static ULONG WINAPI
TestFilter_AddRef(IBaseFilter
* iface
)
1169 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1170 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
1175 static ULONG WINAPI
TestFilter_Release(IBaseFilter
* iface
)
1177 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1178 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
1184 for (i
= 0; i
< This
->nPins
; i
++)
1188 if (SUCCEEDED(IPin_ConnectedTo(This
->ppPins
[i
], &pConnectedTo
)))
1190 IPin_Disconnect(pConnectedTo
);
1191 IPin_Release(pConnectedTo
);
1193 IPin_Disconnect(This
->ppPins
[i
]);
1195 IPin_Release(This
->ppPins
[i
]);
1198 CoTaskMemFree(This
->ppPins
);
1199 This
->lpVtbl
= NULL
;
1201 DeleteCriticalSection(&This
->csFilter
);
1203 CoTaskMemFree(This
);
1210 /** IPersist methods **/
1212 static HRESULT WINAPI
TestFilter_GetClassID(IBaseFilter
* iface
, CLSID
* pClsid
)
1214 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1216 *pClsid
= This
->clsid
;
1221 /** IMediaFilter methods **/
1223 static HRESULT WINAPI
TestFilter_Stop(IBaseFilter
* iface
)
1228 static HRESULT WINAPI
TestFilter_Pause(IBaseFilter
* iface
)
1233 static HRESULT WINAPI
TestFilter_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
1238 static HRESULT WINAPI
TestFilter_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
1240 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1242 EnterCriticalSection(&This
->csFilter
);
1244 *pState
= This
->state
;
1246 LeaveCriticalSection(&This
->csFilter
);
1251 static HRESULT WINAPI
TestFilter_SetSyncSource(IBaseFilter
* iface
, IReferenceClock
*pClock
)
1256 static HRESULT WINAPI
TestFilter_GetSyncSource(IBaseFilter
* iface
, IReferenceClock
**ppClock
)
1261 /** IBaseFilter implementation **/
1263 static HRESULT
TestFilter_GetPin(IBaseFilter
*iface
, ULONG pos
, IPin
**pin
, DWORD
*lastsynctick
)
1265 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1267 /* Our pins are static, not changing so setting static tick count is ok */
1270 if (pos
>= This
->nPins
)
1273 *pin
= This
->ppPins
[pos
];
1278 static HRESULT WINAPI
TestFilter_EnumPins(IBaseFilter
* iface
, IEnumPins
**ppEnum
)
1280 return IEnumPinsImpl_Construct(ppEnum
, TestFilter_GetPin
, iface
);
1283 static HRESULT WINAPI
TestFilter_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
1288 static HRESULT WINAPI
TestFilter_QueryFilterInfo(IBaseFilter
* iface
, FILTER_INFO
*pInfo
)
1290 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1292 lstrcpyW(pInfo
->achName
, This
->filterInfo
.achName
);
1293 pInfo
->pGraph
= This
->filterInfo
.pGraph
;
1296 IFilterGraph_AddRef(pInfo
->pGraph
);
1301 static HRESULT WINAPI
TestFilter_JoinFilterGraph(IBaseFilter
* iface
, IFilterGraph
*pGraph
, LPCWSTR pName
)
1304 TestFilterImpl
*This
= (TestFilterImpl
*)iface
;
1306 EnterCriticalSection(&This
->csFilter
);
1309 lstrcpyW(This
->filterInfo
.achName
, pName
);
1311 *This
->filterInfo
.achName
= '\0';
1312 This
->filterInfo
.pGraph
= pGraph
; /* NOTE: do NOT increase ref. count */
1314 LeaveCriticalSection(&This
->csFilter
);
1319 static HRESULT WINAPI
TestFilter_QueryVendorInfo(IBaseFilter
* iface
, LPWSTR
*pVendorInfo
)
1324 static const IBaseFilterVtbl TestFilter_Vtbl
=
1326 TestFilter_QueryInterface
,
1329 TestFilter_GetClassID
,
1333 TestFilter_GetState
,
1334 TestFilter_SetSyncSource
,
1335 TestFilter_GetSyncSource
,
1336 TestFilter_EnumPins
,
1338 TestFilter_QueryFilterInfo
,
1339 TestFilter_JoinFilterGraph
,
1340 TestFilter_QueryVendorInfo
1343 /* IClassFactory implementation */
1345 typedef struct TestClassFactoryImpl
1347 IClassFactoryVtbl
*lpVtbl
;
1348 const TestFilterPinData
*filterPinData
;
1350 } TestClassFactoryImpl
;
1352 static HRESULT WINAPI
Test_IClassFactory_QueryInterface(
1353 LPCLASSFACTORY iface
,
1357 if (ppvObj
== NULL
) return E_POINTER
;
1359 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1360 IsEqualGUID(riid
, &IID_IClassFactory
))
1363 IClassFactory_AddRef(iface
);
1368 return E_NOINTERFACE
;
1371 static ULONG WINAPI
Test_IClassFactory_AddRef(LPCLASSFACTORY iface
)
1373 return 2; /* non-heap-based object */
1376 static ULONG WINAPI
Test_IClassFactory_Release(LPCLASSFACTORY iface
)
1378 return 1; /* non-heap-based object */
1381 static HRESULT WINAPI
Test_IClassFactory_CreateInstance(
1382 LPCLASSFACTORY iface
,
1383 LPUNKNOWN pUnkOuter
,
1387 TestClassFactoryImpl
*This
= (TestClassFactoryImpl
*)iface
;
1389 IUnknown
*punk
= NULL
;
1393 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1395 hr
= TestFilter_Create(This
->clsid
, This
->filterPinData
, (LPVOID
*) &punk
);
1396 if (SUCCEEDED(hr
)) {
1397 hr
= IUnknown_QueryInterface(punk
, riid
, ppvObj
);
1398 IUnknown_Release(punk
);
1403 static HRESULT WINAPI
Test_IClassFactory_LockServer(
1404 LPCLASSFACTORY iface
,
1410 static IClassFactoryVtbl TestClassFactory_Vtbl
=
1412 Test_IClassFactory_QueryInterface
,
1413 Test_IClassFactory_AddRef
,
1414 Test_IClassFactory_Release
,
1415 Test_IClassFactory_CreateInstance
,
1416 Test_IClassFactory_LockServer
1419 static HRESULT
get_connected_filter_name(TestFilterImpl
*pFilter
, char *FilterName
)
1423 FILTER_INFO filterInfo
;
1428 hr
= IPin_ConnectedTo(pFilter
->ppPins
[0], &pin
);
1429 ok(hr
== S_OK
, "IPin_ConnectedTo failed with %x\n", hr
);
1430 if (FAILED(hr
)) return hr
;
1432 hr
= IPin_QueryPinInfo(pin
, &pinInfo
);
1433 ok(hr
== S_OK
, "IPin_QueryPinInfo failed with %x\n", hr
);
1435 if (FAILED(hr
)) return hr
;
1437 SetLastError(0xdeadbeef);
1438 hr
= IBaseFilter_QueryFilterInfo(pinInfo
.pFilter
, &filterInfo
);
1439 if (hr
== S_OK
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1441 IBaseFilter_Release(pinInfo
.pFilter
);
1444 ok(hr
== S_OK
, "IBaseFilter_QueryFilterInfo failed with %x\n", hr
);
1445 IBaseFilter_Release(pinInfo
.pFilter
);
1446 if (FAILED(hr
)) return hr
;
1448 IFilterGraph_Release(filterInfo
.pGraph
);
1450 WideCharToMultiByte(CP_ACP
, 0, filterInfo
.achName
, -1, FilterName
, MAX_FILTER_NAME
, NULL
, NULL
);
1455 static void test_render_filter_priority(void)
1457 /* Tests filter choice priorities in Render(). */
1458 DWORD cookie1
, cookie2
, cookie3
;
1460 IFilterGraph2
* pgraph2
= NULL
;
1461 IFilterMapper2
*pMapper2
= NULL
;
1462 IBaseFilter
* ptestfilter
= NULL
;
1463 IBaseFilter
* ptestfilter2
= NULL
;
1464 static const CLSID CLSID_TestFilter2
= {
1468 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1470 static const CLSID CLSID_TestFilter3
= {
1474 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1476 static const CLSID CLSID_TestFilter4
= {
1480 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1482 static const GUID mediasubtype1
= {
1486 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1488 static const GUID mediasubtype2
= {
1492 {0xe8, 0x9b, 0x00, 0x19, 0x66, 0x2f, 0xf0, 0xce}
1494 static const TestFilterPinData PinData1
[] = {
1495 { PINDIR_OUTPUT
, &mediasubtype1
},
1498 static const TestFilterPinData PinData2
[] = {
1499 { PINDIR_INPUT
, &mediasubtype1
},
1502 static const TestFilterPinData PinData3
[] = {
1503 { PINDIR_INPUT
, &GUID_NULL
},
1506 static const TestFilterPinData PinData4
[] = {
1507 { PINDIR_INPUT
, &mediasubtype1
},
1508 { PINDIR_OUTPUT
, &mediasubtype2
},
1511 static const TestFilterPinData PinData5
[] = {
1512 { PINDIR_INPUT
, &mediasubtype2
},
1515 TestClassFactoryImpl Filter1ClassFactory
= { &TestClassFactory_Vtbl
, PinData2
, &CLSID_TestFilter2
};
1516 TestClassFactoryImpl Filter2ClassFactory
= { &TestClassFactory_Vtbl
, PinData4
, &CLSID_TestFilter3
};
1517 TestClassFactoryImpl Filter3ClassFactory
= { &TestClassFactory_Vtbl
, PinData5
, &CLSID_TestFilter4
};
1518 char ConnectedFilterName1
[MAX_FILTER_NAME
];
1519 char ConnectedFilterName2
[MAX_FILTER_NAME
];
1521 REGFILTERPINS2 rgPins2
[2];
1522 REGPINTYPES rgPinType
[2];
1523 static const WCHAR wszFilterInstanceName1
[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1524 'n', 's', 't', 'a', 'n', 'c', 'e', '1', 0 };
1525 static const WCHAR wszFilterInstanceName2
[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1526 'n', 's', 't', 'a', 'n', 'c', 'e', '2', 0 };
1527 static const WCHAR wszFilterInstanceName3
[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1528 'n', 's', 't', 'a', 'n', 'c', 'e', '3', 0 };
1529 static const WCHAR wszFilterInstanceName4
[] = {'T', 'e', 's', 't', 'f', 'i', 'l', 't', 'e', 'r', 'I',
1530 'n', 's', 't', 'a', 'n', 'c', 'e', '4', 0 };
1532 /* Test which renderer of two already added to the graph will be chosen (one is "exact" match, other is
1533 "wildcard" match. Seems to very by order in which filters are added to the graph, thus indicating
1534 no preference given to exact match. */
1535 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterGraph2
, (LPVOID
*)&pgraph2
);
1536 ok(hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
1537 if (!pgraph2
) goto out
;
1539 hr
= TestFilter_Create(&GUID_NULL
, PinData1
, (LPVOID
)&ptestfilter
);
1540 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1541 if (FAILED(hr
)) goto out
;
1543 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter
, wszFilterInstanceName1
);
1544 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1546 hr
= TestFilter_Create(&GUID_NULL
, PinData2
, (LPVOID
)&ptestfilter2
);
1547 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1548 if (FAILED(hr
)) goto out
;
1550 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName2
);
1551 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1553 IBaseFilter_Release(ptestfilter2
);
1554 ptestfilter2
= NULL
;
1556 hr
= TestFilter_Create(&GUID_NULL
, PinData3
, (LPVOID
)&ptestfilter2
);
1557 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1558 if (FAILED(hr
)) goto out
;
1560 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName3
);
1561 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1563 hr
= IFilterGraph2_Render(pgraph2
, ((TestFilterImpl
*)ptestfilter
)->ppPins
[0]);
1564 ok(hr
== S_OK
, "IFilterGraph2_Render failed with %08x\n", hr
);
1566 hr
= get_connected_filter_name((TestFilterImpl
*)ptestfilter
, ConnectedFilterName1
);
1568 IFilterGraph2_Release(pgraph2
);
1570 IBaseFilter_Release(ptestfilter
);
1572 IBaseFilter_Release(ptestfilter2
);
1573 ptestfilter2
= NULL
;
1575 if (hr
== E_NOTIMPL
)
1577 win_skip("Needed functions are not implemented\n");
1581 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterGraph2
, (LPVOID
*)&pgraph2
);
1582 ok(hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
1583 if (!pgraph2
) goto out
;
1585 hr
= TestFilter_Create(&GUID_NULL
, PinData1
, (LPVOID
)&ptestfilter
);
1586 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1587 if (FAILED(hr
)) goto out
;
1589 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter
, wszFilterInstanceName1
);
1590 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1592 hr
= TestFilter_Create(&GUID_NULL
, PinData3
, (LPVOID
)&ptestfilter2
);
1593 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1594 if (FAILED(hr
)) goto out
;
1596 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName3
);
1597 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1599 IBaseFilter_Release(ptestfilter2
);
1600 ptestfilter2
= NULL
;
1602 hr
= TestFilter_Create(&GUID_NULL
, PinData2
, (LPVOID
)&ptestfilter2
);
1603 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1604 if (FAILED(hr
)) goto out
;
1606 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName2
);
1607 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1609 hr
= IFilterGraph2_Render(pgraph2
, ((TestFilterImpl
*)ptestfilter
)->ppPins
[0]);
1610 ok(hr
== S_OK
, "IFilterGraph2_Render failed with %08x\n", hr
);
1612 hr
= IFilterGraph2_Disconnect(pgraph2
, NULL
);
1613 ok(hr
== E_POINTER
, "IFilterGraph2_Disconnect failed. Expected E_POINTER, received %08x\n", hr
);
1615 get_connected_filter_name((TestFilterImpl
*)ptestfilter
, ConnectedFilterName2
);
1616 ok(lstrcmp(ConnectedFilterName1
, ConnectedFilterName2
),
1617 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1
);
1619 IFilterGraph2_Release(pgraph2
);
1621 IBaseFilter_Release(ptestfilter
);
1623 IBaseFilter_Release(ptestfilter2
);
1624 ptestfilter2
= NULL
;
1626 /* Test if any preference is given to existing renderer which renders the pin directly vs
1627 an existing renderer which renders the pin indirectly, through an additional middle filter,
1628 again trying different orders of creation. Native appears not to give a preference. */
1630 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterGraph2
, (LPVOID
*)&pgraph2
);
1631 ok(hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
1632 if (!pgraph2
) goto out
;
1634 hr
= TestFilter_Create(&GUID_NULL
, PinData1
, (LPVOID
)&ptestfilter
);
1635 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1636 if (FAILED(hr
)) goto out
;
1638 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter
, wszFilterInstanceName1
);
1639 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1641 hr
= TestFilter_Create(&GUID_NULL
, PinData2
, (LPVOID
)&ptestfilter2
);
1642 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1643 if (FAILED(hr
)) goto out
;
1645 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName2
);
1646 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1648 IBaseFilter_Release(ptestfilter2
);
1649 ptestfilter2
= NULL
;
1651 hr
= TestFilter_Create(&GUID_NULL
, PinData4
, (LPVOID
)&ptestfilter2
);
1652 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1653 if (FAILED(hr
)) goto out
;
1655 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName3
);
1656 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1658 IBaseFilter_Release(ptestfilter2
);
1659 ptestfilter2
= NULL
;
1661 hr
= TestFilter_Create(&GUID_NULL
, PinData5
, (LPVOID
)&ptestfilter2
);
1662 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1663 if (FAILED(hr
)) goto out
;
1665 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName4
);
1666 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1668 hr
= IFilterGraph2_Render(pgraph2
, ((TestFilterImpl
*)ptestfilter
)->ppPins
[0]);
1669 ok(hr
== S_OK
, "IFilterGraph2_Render failed with %08x\n", hr
);
1671 get_connected_filter_name((TestFilterImpl
*)ptestfilter
, ConnectedFilterName1
);
1672 ok(!lstrcmp(ConnectedFilterName1
, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName1
, "TestfilterInstance2"),
1673 "unexpected connected filter: %s\n", ConnectedFilterName1
);
1675 IFilterGraph2_Release(pgraph2
);
1677 IBaseFilter_Release(ptestfilter
);
1679 IBaseFilter_Release(ptestfilter2
);
1680 ptestfilter2
= NULL
;
1682 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterGraph2
, (LPVOID
*)&pgraph2
);
1683 ok(hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
1684 if (!pgraph2
) goto out
;
1686 hr
= TestFilter_Create(&GUID_NULL
, PinData1
, (LPVOID
)&ptestfilter
);
1687 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1688 if (FAILED(hr
)) goto out
;
1690 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter
, wszFilterInstanceName1
);
1691 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1693 hr
= TestFilter_Create(&GUID_NULL
, PinData4
, (LPVOID
)&ptestfilter2
);
1694 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1695 if (FAILED(hr
)) goto out
;
1697 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName3
);
1698 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1700 IBaseFilter_Release(ptestfilter2
);
1701 ptestfilter2
= NULL
;
1703 hr
= TestFilter_Create(&GUID_NULL
, PinData5
, (LPVOID
)&ptestfilter2
);
1704 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1705 if (FAILED(hr
)) goto out
;
1707 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName4
);
1708 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1710 IBaseFilter_Release(ptestfilter2
);
1711 ptestfilter2
= NULL
;
1713 hr
= TestFilter_Create(&GUID_NULL
, PinData2
, (LPVOID
)&ptestfilter2
);
1714 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1715 if (FAILED(hr
)) goto out
;
1717 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter2
, wszFilterInstanceName2
);
1718 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1720 hr
= IFilterGraph2_Render(pgraph2
, ((TestFilterImpl
*)ptestfilter
)->ppPins
[0]);
1721 ok(hr
== S_OK
, "IFilterGraph2_Render failed with %08x\n", hr
);
1723 get_connected_filter_name((TestFilterImpl
*)ptestfilter
, ConnectedFilterName2
);
1724 ok(!lstrcmp(ConnectedFilterName2
, "TestfilterInstance3") || !lstrcmp(ConnectedFilterName2
, "TestfilterInstance2"),
1725 "unexpected connected filter: %s\n", ConnectedFilterName2
);
1726 ok(lstrcmp(ConnectedFilterName1
, ConnectedFilterName2
),
1727 "expected connected filters to be different but got %s both times\n", ConnectedFilterName1
);
1729 IFilterGraph2_Release(pgraph2
);
1731 IBaseFilter_Release(ptestfilter
);
1733 IBaseFilter_Release(ptestfilter2
);
1734 ptestfilter2
= NULL
;
1736 /* Test if renderers are tried before non-renderers (intermediary filters). */
1737 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterGraph2
, (LPVOID
*)&pgraph2
);
1738 ok(hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
1739 if (!pgraph2
) goto out
;
1741 hr
= CoCreateInstance(&CLSID_FilterMapper2
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IFilterMapper2
, (LPVOID
*)&pMapper2
);
1742 ok(hr
== S_OK
, "CoCreateInstance failed with %08x\n", hr
);
1743 if (!pMapper2
) goto out
;
1745 hr
= TestFilter_Create(&GUID_NULL
, PinData1
, (LPVOID
)&ptestfilter
);
1746 ok(hr
== S_OK
, "TestFilter_Create failed with %08x\n", hr
);
1747 if (FAILED(hr
)) goto out
;
1749 hr
= IFilterGraph2_AddFilter(pgraph2
, ptestfilter
, wszFilterInstanceName1
);
1750 ok(hr
== S_OK
, "IFilterGraph2_AddFilter failed with %08x\n", hr
);
1752 /* Register our filters with COM and with Filtermapper. */
1753 hr
= CoRegisterClassObject(Filter1ClassFactory
.clsid
, (IUnknown
*)&Filter1ClassFactory
,
1754 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie1
);
1755 ok(hr
== S_OK
, "CoRegisterClassObject failed with %08x\n", hr
);
1756 hr
= CoRegisterClassObject(Filter2ClassFactory
.clsid
, (IUnknown
*)&Filter2ClassFactory
,
1757 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie2
);
1758 ok(hr
== S_OK
, "CoRegisterClassObject failed with %08x\n", hr
);
1759 hr
= CoRegisterClassObject(Filter3ClassFactory
.clsid
, (IUnknown
*)&Filter3ClassFactory
,
1760 CLSCTX_INPROC_SERVER
, REGCLS_MULTIPLEUSE
, &cookie3
);
1761 ok(hr
== S_OK
, "CoRegisterClassObject failed with %08x\n", hr
);
1764 rgf2
.dwMerit
= MERIT_UNLIKELY
;
1765 S1(U(rgf2
)).cPins2
= 1;
1766 S1(U(rgf2
)).rgPins2
= rgPins2
;
1767 rgPins2
[0].dwFlags
= REG_PINFLAG_B_RENDERER
;
1768 rgPins2
[0].cInstances
= 1;
1769 rgPins2
[0].nMediaTypes
= 1;
1770 rgPins2
[0].lpMediaType
= &rgPinType
[0];
1771 rgPins2
[0].nMediums
= 0;
1772 rgPins2
[0].lpMedium
= NULL
;
1773 rgPins2
[0].clsPinCategory
= NULL
;
1774 rgPinType
[0].clsMajorType
= &MEDIATYPE_Video
;
1775 rgPinType
[0].clsMinorType
= &mediasubtype1
;
1777 hr
= IFilterMapper2_RegisterFilter(pMapper2
, &CLSID_TestFilter2
, wszFilterInstanceName2
, NULL
,
1778 &CLSID_LegacyAmFilterCategory
, NULL
, &rgf2
);
1779 ok(hr
== S_OK
, "IFilterMapper2_RegisterFilter failed with %x\n", hr
);
1781 rgf2
.dwMerit
= MERIT_PREFERRED
;
1782 rgPinType
[0].clsMinorType
= &mediasubtype2
;
1784 hr
= IFilterMapper2_RegisterFilter(pMapper2
, &CLSID_TestFilter4
, wszFilterInstanceName4
, NULL
,
1785 &CLSID_LegacyAmFilterCategory
, NULL
, &rgf2
);
1786 ok(hr
== S_OK
, "IFilterMapper2_RegisterFilter failed with %x\n", hr
);
1788 S1(U(rgf2
)).cPins2
= 2;
1789 rgPins2
[0].dwFlags
= 0;
1790 rgPinType
[0].clsMinorType
= &mediasubtype1
;
1792 rgPins2
[1].dwFlags
= REG_PINFLAG_B_OUTPUT
;
1793 rgPins2
[1].cInstances
= 1;
1794 rgPins2
[1].nMediaTypes
= 1;
1795 rgPins2
[1].lpMediaType
= &rgPinType
[1];
1796 rgPins2
[1].nMediums
= 0;
1797 rgPins2
[1].lpMedium
= NULL
;
1798 rgPins2
[1].clsPinCategory
= NULL
;
1799 rgPinType
[1].clsMajorType
= &MEDIATYPE_Video
;
1800 rgPinType
[1].clsMinorType
= &mediasubtype2
;
1802 hr
= IFilterMapper2_RegisterFilter(pMapper2
, &CLSID_TestFilter3
, wszFilterInstanceName3
, NULL
,
1803 &CLSID_LegacyAmFilterCategory
, NULL
, &rgf2
);
1804 ok(hr
== S_OK
, "IFilterMapper2_RegisterFilter failed with %x\n", hr
);
1806 hr
= IFilterGraph2_Render(pgraph2
, ((TestFilterImpl
*)ptestfilter
)->ppPins
[0]);
1807 ok(hr
== S_OK
, "IFilterGraph2_Render failed with %08x\n", hr
);
1809 get_connected_filter_name((TestFilterImpl
*)ptestfilter
, ConnectedFilterName1
);
1810 ok(!lstrcmp(ConnectedFilterName1
, "TestfilterInstance3"),
1811 "unexpected connected filter: %s\n", ConnectedFilterName1
);
1813 hr
= IFilterMapper2_UnregisterFilter(pMapper2
, &CLSID_LegacyAmFilterCategory
, NULL
,
1814 &CLSID_TestFilter2
);
1815 ok(SUCCEEDED(hr
), "IFilterMapper2_UnregisterFilter failed with %x\n", hr
);
1816 hr
= IFilterMapper2_UnregisterFilter(pMapper2
, &CLSID_LegacyAmFilterCategory
, NULL
,
1817 &CLSID_TestFilter3
);
1818 ok(SUCCEEDED(hr
), "IFilterMapper2_UnregisterFilter failed with %x\n", hr
);
1819 hr
= IFilterMapper2_UnregisterFilter(pMapper2
, &CLSID_LegacyAmFilterCategory
, NULL
,
1820 &CLSID_TestFilter4
);
1821 ok(SUCCEEDED(hr
), "IFilterMapper2_UnregisterFilter failed with %x\n", hr
);
1825 if (ptestfilter
) IBaseFilter_Release(ptestfilter
);
1826 if (ptestfilter2
) IBaseFilter_Release(ptestfilter2
);
1827 if (pgraph2
) IFilterGraph2_Release(pgraph2
);
1828 if (pMapper2
) IFilterMapper2_Release(pMapper2
);
1830 hr
= CoRevokeClassObject(cookie1
);
1831 ok(hr
== S_OK
, "CoRevokeClassObject failed with %08x\n", hr
);
1832 hr
= CoRevokeClassObject(cookie2
);
1833 ok(hr
== S_OK
, "CoRevokeClassObject failed with %08x\n", hr
);
1834 hr
= CoRevokeClassObject(cookie3
);
1835 ok(hr
== S_OK
, "CoRevokeClassObject failed with %08x\n", hr
);
1838 START_TEST(filtergraph
)
1840 CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
1841 test_render_run(avifileA
);
1842 test_render_run(mpegfileA
);
1843 test_graph_builder();
1844 test_graph_builder_addfilter();
1845 test_mediacontrol();
1846 test_filter_graph2();
1847 test_render_filter_priority();