4 * Copyright 2015 Damjan Jovanovic
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "wine/strmbase.h"
33 #include "wine/test.h"
38 IBaseFilter IBaseFilter_iface
;
41 DWORD receiveThreadId
;
43 IMemInputPin IMemInputPin_iface
;
44 IMemAllocator
*allocator
;
45 IBaseFilter
*nullRenderer
;
46 IPin
*nullRendererPin
;
47 IMemInputPin
*nullRendererMemInputPin
;
51 IEnumPins IEnumPins_iface
;
57 static SinkEnumPins
* create_SinkEnumPins(SinkFilter
*filter
);
59 static inline SinkFilter
* impl_from_SinkFilter_IBaseFilter(IBaseFilter
*iface
)
61 return CONTAINING_RECORD(iface
, SinkFilter
, IBaseFilter_iface
);
64 static inline SinkFilter
* impl_from_SinkFilter_IPin(IPin
*iface
)
66 return CONTAINING_RECORD(iface
, SinkFilter
, IPin_iface
);
69 static inline SinkFilter
* impl_from_SinkFilter_IMemInputPin(IMemInputPin
*iface
)
71 return CONTAINING_RECORD(iface
, SinkFilter
, IMemInputPin_iface
);
74 static inline SinkEnumPins
* impl_from_SinkFilter_IEnumPins(IEnumPins
*iface
)
76 return CONTAINING_RECORD(iface
, SinkEnumPins
, IEnumPins_iface
);
79 static HRESULT WINAPI
SinkFilter_QueryInterface(IBaseFilter
*iface
, REFIID riid
, void **ppv
)
81 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
82 if(IsEqualIID(riid
, &IID_IUnknown
)) {
83 *ppv
= &This
->IBaseFilter_iface
;
84 } else if(IsEqualIID(riid
, &IID_IPersist
)) {
85 *ppv
= &This
->IBaseFilter_iface
;
86 } else if(IsEqualIID(riid
, &IID_IMediaFilter
)) {
87 *ppv
= &This
->IBaseFilter_iface
;
88 } else if(IsEqualIID(riid
, &IID_IBaseFilter
)) {
89 *ppv
= &This
->IBaseFilter_iface
;
91 trace("no interface for %s\n", wine_dbgstr_guid(riid
));
95 IUnknown_AddRef((IUnknown
*)*ppv
);
99 static ULONG WINAPI
SinkFilter_AddRef(IBaseFilter
*iface
)
101 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
102 return InterlockedIncrement(&This
->ref
);
105 static ULONG WINAPI
SinkFilter_Release(IBaseFilter
*iface
)
107 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
108 ULONG ref
= InterlockedDecrement(&This
->ref
);
111 IMemAllocator_Release(This
->allocator
);
112 IMemInputPin_Release(This
->nullRendererMemInputPin
);
113 IPin_Release(This
->nullRendererPin
);
114 IBaseFilter_Release(This
->nullRenderer
);
120 static HRESULT WINAPI
SinkFilter_GetClassID(IBaseFilter
*iface
, CLSID
*pClassID
)
122 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
123 return IBaseFilter_GetClassID(This
->nullRenderer
, pClassID
);
126 static HRESULT WINAPI
SinkFilter_Stop(IBaseFilter
*iface
)
128 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
129 return IBaseFilter_Stop(This
->nullRenderer
);
132 static HRESULT WINAPI
SinkFilter_Pause(IBaseFilter
*iface
)
134 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
135 return IBaseFilter_Pause(This
->nullRenderer
);
138 static HRESULT WINAPI
SinkFilter_Run(IBaseFilter
*iface
, REFERENCE_TIME tStart
)
140 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
141 return IBaseFilter_Run(This
->nullRenderer
, tStart
);
144 static HRESULT WINAPI
SinkFilter_GetState(IBaseFilter
*iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*state
)
146 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
147 return IBaseFilter_GetState(This
->nullRenderer
, dwMilliSecsTimeout
, state
);
150 static HRESULT WINAPI
SinkFilter_SetSyncSource(IBaseFilter
*iface
, IReferenceClock
*pClock
)
152 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
153 return IBaseFilter_SetSyncSource(This
->nullRenderer
, pClock
);
156 static HRESULT WINAPI
SinkFilter_GetSyncSource(IBaseFilter
*iface
, IReferenceClock
**ppClock
)
158 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
159 return IBaseFilter_GetSyncSource(This
->nullRenderer
, ppClock
);
162 static HRESULT WINAPI
SinkFilter_EnumPins(IBaseFilter
*iface
, IEnumPins
**ppEnum
)
164 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
165 SinkEnumPins
*sinkEnumPins
= create_SinkEnumPins(This
);
167 *ppEnum
= &sinkEnumPins
->IEnumPins_iface
;
171 return E_OUTOFMEMORY
;
174 static HRESULT WINAPI
SinkFilter_FindPin(IBaseFilter
*iface
, LPCWSTR id
, IPin
**ppPin
)
176 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
177 HRESULT hr
= IBaseFilter_FindPin(This
->nullRenderer
, id
, ppPin
);
179 IPin_Release(*ppPin
);
180 *ppPin
= &This
->IPin_iface
;
181 IPin_AddRef(&This
->IPin_iface
);
186 static HRESULT WINAPI
SinkFilter_QueryFilterInfo(IBaseFilter
*iface
, FILTER_INFO
*pInfo
)
188 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
189 return IBaseFilter_QueryFilterInfo(This
->nullRenderer
, pInfo
);
192 static HRESULT WINAPI
SinkFilter_JoinFilterGraph(IBaseFilter
*iface
, IFilterGraph
*pGraph
, LPCWSTR pName
)
194 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
195 return IBaseFilter_JoinFilterGraph(This
->nullRenderer
, pGraph
, pName
);
198 static HRESULT WINAPI
SinkFilter_QueryVendorInfo(IBaseFilter
*iface
, LPWSTR
*pVendorInfo
)
200 SinkFilter
*This
= impl_from_SinkFilter_IBaseFilter(iface
);
201 return IBaseFilter_QueryVendorInfo(This
->nullRenderer
, pVendorInfo
);
204 static const IBaseFilterVtbl SinkFilterVtbl
= {
205 SinkFilter_QueryInterface
,
208 SinkFilter_GetClassID
,
213 SinkFilter_SetSyncSource
,
214 SinkFilter_GetSyncSource
,
217 SinkFilter_QueryFilterInfo
,
218 SinkFilter_JoinFilterGraph
,
219 SinkFilter_QueryVendorInfo
222 static HRESULT WINAPI
SinkEnumPins_QueryInterface(IEnumPins
*iface
, REFIID riid
, void **ppv
)
224 SinkEnumPins
*This
= impl_from_SinkFilter_IEnumPins(iface
);
225 if(IsEqualIID(riid
, &IID_IUnknown
)) {
226 *ppv
= &This
->IEnumPins_iface
;
227 } else if(IsEqualIID(riid
, &IID_IEnumPins
)) {
228 *ppv
= &This
->IEnumPins_iface
;
230 trace("no interface for %s\n", wine_dbgstr_guid(riid
));
232 return E_NOINTERFACE
;
234 IUnknown_AddRef((IUnknown
*)*ppv
);
238 static ULONG WINAPI
SinkEnumPins_AddRef(IEnumPins
*iface
)
240 SinkEnumPins
*This
= impl_from_SinkFilter_IEnumPins(iface
);
241 return InterlockedIncrement(&This
->ref
);
244 static ULONG WINAPI
SinkEnumPins_Release(IEnumPins
*iface
)
246 SinkEnumPins
*This
= impl_from_SinkFilter_IEnumPins(iface
);
248 ref
= InterlockedDecrement(&This
->ref
);
251 IBaseFilter_Release(&This
->filter
->IBaseFilter_iface
);
257 static HRESULT WINAPI
SinkEnumPins_Next(IEnumPins
*iface
, ULONG cPins
, IPin
**ppPins
, ULONG
*pcFetched
)
259 SinkEnumPins
*This
= impl_from_SinkFilter_IEnumPins(iface
);
262 if (cPins
> 1 && !pcFetched
)
268 if (This
->index
== 0) {
269 ppPins
[0] = &This
->filter
->IPin_iface
;
270 IPin_AddRef(&This
->filter
->IPin_iface
);
279 static HRESULT WINAPI
SinkEnumPins_Skip(IEnumPins
*iface
, ULONG cPins
)
281 SinkEnumPins
*This
= impl_from_SinkFilter_IEnumPins(iface
);
282 if (This
->index
+ cPins
>= 1)
284 This
->index
+= cPins
;
288 static HRESULT WINAPI
SinkEnumPins_Reset(IEnumPins
*iface
)
290 SinkEnumPins
*This
= impl_from_SinkFilter_IEnumPins(iface
);
295 static HRESULT WINAPI
SinkEnumPins_Clone(IEnumPins
*iface
, IEnumPins
**ppEnum
)
297 SinkEnumPins
*This
= impl_from_SinkFilter_IEnumPins(iface
);
298 SinkEnumPins
*clone
= create_SinkEnumPins(This
->filter
);
300 return E_OUTOFMEMORY
;
301 clone
->index
= This
->index
;
305 static const IEnumPinsVtbl SinkEnumPinsVtbl
= {
306 SinkEnumPins_QueryInterface
,
308 SinkEnumPins_Release
,
315 static SinkEnumPins
* create_SinkEnumPins(SinkFilter
*filter
)
318 This
= CoTaskMemAlloc(sizeof(*This
));
322 This
->IEnumPins_iface
.lpVtbl
= &SinkEnumPinsVtbl
;
325 This
->filter
= filter
;
326 IBaseFilter_AddRef(&filter
->IBaseFilter_iface
);
330 static HRESULT WINAPI
SinkPin_QueryInterface(IPin
*iface
, REFIID riid
, void **ppv
)
332 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
333 if(IsEqualIID(riid
, &IID_IUnknown
)) {
334 *ppv
= &This
->IPin_iface
;
335 } else if(IsEqualIID(riid
, &IID_IPin
)) {
336 *ppv
= &This
->IPin_iface
;
337 } else if(IsEqualIID(riid
, &IID_IMemInputPin
)) {
338 *ppv
= &This
->IMemInputPin_iface
;
340 trace("no interface for %s\n", wine_dbgstr_guid(riid
));
342 return E_NOINTERFACE
;
344 IUnknown_AddRef((IUnknown
*)*ppv
);
348 static ULONG WINAPI
SinkPin_AddRef(IPin
*iface
)
350 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
351 return IBaseFilter_AddRef(&This
->IBaseFilter_iface
);
354 static ULONG WINAPI
SinkPin_Release(IPin
*iface
)
356 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
357 return IBaseFilter_Release(&This
->IBaseFilter_iface
);
360 static HRESULT WINAPI
SinkPin_Connect(IPin
*iface
, IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
362 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
363 return IPin_Connect(This
->nullRendererPin
, pReceivePin
, pmt
);
366 static HRESULT WINAPI
SinkPin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*pmt
)
368 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
369 return IPin_ReceiveConnection(This
->nullRendererPin
, connector
, pmt
);
372 static HRESULT WINAPI
SinkPin_Disconnect(IPin
*iface
)
374 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
375 return IPin_Disconnect(This
->nullRendererPin
);
378 static HRESULT WINAPI
SinkPin_ConnectedTo(IPin
*iface
, IPin
**pPin
)
380 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
381 return IPin_ConnectedTo(This
->nullRendererPin
, pPin
);
384 static HRESULT WINAPI
SinkPin_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*pmt
)
386 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
387 return IPin_ConnectionMediaType(This
->nullRendererPin
, pmt
);
390 static HRESULT WINAPI
SinkPin_QueryPinInfo(IPin
*iface
, PIN_INFO
*pInfo
)
392 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
393 HRESULT hr
= IPin_QueryPinInfo(This
->nullRendererPin
, pInfo
);
395 IBaseFilter_Release(pInfo
->pFilter
);
396 pInfo
->pFilter
= &This
->IBaseFilter_iface
;
397 IBaseFilter_AddRef(&This
->IBaseFilter_iface
);
402 static HRESULT WINAPI
SinkPin_QueryDirection(IPin
*iface
, PIN_DIRECTION
*pPinDir
)
404 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
405 return IPin_QueryDirection(This
->nullRendererPin
, pPinDir
);
408 static HRESULT WINAPI
SinkPin_QueryId(IPin
*iface
, LPWSTR
*id
)
410 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
411 return IPin_QueryId(This
->nullRendererPin
, id
);
414 static HRESULT WINAPI
SinkPin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*pmt
)
416 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
417 return IPin_QueryAccept(This
->nullRendererPin
, pmt
);
420 static HRESULT WINAPI
SinkPin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**ppEnum
)
422 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
423 return IPin_EnumMediaTypes(This
->nullRendererPin
, ppEnum
);
426 static HRESULT WINAPI
SinkPin_QueryInternalConnections(IPin
*iface
, IPin
**apPin
, ULONG
*nPin
)
428 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
429 return IPin_QueryInternalConnections(This
->nullRendererPin
, apPin
, nPin
);
432 static HRESULT WINAPI
SinkPin_EndOfStream(IPin
*iface
)
434 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
435 return IPin_EndOfStream(This
->nullRendererPin
);
438 static HRESULT WINAPI
SinkPin_BeginFlush(IPin
*iface
)
440 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
441 return IPin_BeginFlush(This
->nullRendererPin
);
444 static HRESULT WINAPI
SinkPin_EndFlush(IPin
*iface
)
446 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
447 return IPin_EndFlush(This
->nullRendererPin
);
450 static HRESULT WINAPI
SinkPin_NewSegment(IPin
*iface
, REFERENCE_TIME tStart
,
451 REFERENCE_TIME tStop
, double dRate
)
453 SinkFilter
*This
= impl_from_SinkFilter_IPin(iface
);
454 return IPin_NewSegment(This
->nullRendererPin
, tStart
, tStop
, dRate
);
457 static const IPinVtbl SinkPinVtbl
= {
458 SinkPin_QueryInterface
,
462 SinkPin_ReceiveConnection
,
465 SinkPin_ConnectionMediaType
,
466 SinkPin_QueryPinInfo
,
467 SinkPin_QueryDirection
,
470 SinkPin_EnumMediaTypes
,
471 SinkPin_QueryInternalConnections
,
478 static HRESULT WINAPI
SinkMemInputPin_QueryInterface(IMemInputPin
*iface
, REFIID riid
, void **ppv
)
480 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
481 return IPin_QueryInterface(&This
->IPin_iface
, riid
, ppv
);
484 static ULONG WINAPI
SinkMemInputPin_AddRef(IMemInputPin
*iface
)
486 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
487 return IBaseFilter_AddRef(&This
->IBaseFilter_iface
);
490 static ULONG WINAPI
SinkMemInputPin_Release(IMemInputPin
*iface
)
492 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
493 return IBaseFilter_Release(&This
->IBaseFilter_iface
);
496 static HRESULT WINAPI
SinkMemInputPin_GetAllocator(IMemInputPin
*iface
, IMemAllocator
**ppAllocator
)
498 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
499 ok(0, "SmartTeeFilter never calls IMemInputPin_GetAllocator()\n");
500 return IMemInputPin_GetAllocator(This
->nullRendererMemInputPin
, ppAllocator
);
503 static HRESULT WINAPI
SinkMemInputPin_NotifyAllocator(IMemInputPin
*iface
, IMemAllocator
*pAllocator
,
506 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
507 This
->allocator
= pAllocator
;
508 IMemAllocator_AddRef(This
->allocator
);
509 ok(bReadOnly
, "bReadOnly isn't supposed to be FALSE\n");
510 return IMemInputPin_NotifyAllocator(This
->nullRendererMemInputPin
, pAllocator
, bReadOnly
);
513 static HRESULT WINAPI
SinkMemInputPin_GetAllocatorRequirements(IMemInputPin
*iface
,
514 ALLOCATOR_PROPERTIES
*pProps
)
516 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
517 ok(0, "SmartTeeFilter never calls IMemInputPin_GetAllocatorRequirements()\n");
518 return IMemInputPin_GetAllocatorRequirements(This
->nullRendererMemInputPin
, pProps
);
521 static HRESULT WINAPI
SinkMemInputPin_Receive(IMemInputPin
*iface
, IMediaSample
*pSample
)
523 LONG samplesProcessed
;
524 todo_wine
ok(0, "SmartTeeFilter never calls IMemInputPin_Receive(), only IMemInputPin_ReceiveMultiple()\n");
525 return IMemInputPin_ReceiveMultiple(iface
, &pSample
, 1, &samplesProcessed
);
528 static HRESULT WINAPI
SinkMemInputPin_ReceiveMultiple(IMemInputPin
*iface
, IMediaSample
**pSamples
,
529 LONG nSamples
, LONG
*nSamplesProcessed
)
531 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
532 IMediaSample
*pSample
;
533 REFERENCE_TIME startTime
, endTime
;
535 ok(nSamples
== 1, "expected 1 sample, got %d\n", nSamples
);
536 pSample
= pSamples
[0];
537 hr
= IMediaSample_GetTime(pSample
, &startTime
, &endTime
);
539 ok(SUCCEEDED(hr
), "IMediaSample_GetTime() from Capture pin failed, hr=0x%08x\n", hr
);
541 ok(hr
== VFW_E_SAMPLE_TIME_NOT_SET
, "IMediaSample_GetTime() from Preview pin returned hr=0x%08x\n", hr
);
542 This
->receiveThreadId
= GetCurrentThreadId();
544 return IMemInputPin_ReceiveMultiple(This
->nullRendererMemInputPin
, pSamples
,
545 nSamples
, nSamplesProcessed
);
548 static HRESULT WINAPI
SinkMemInputPin_ReceiveCanBlock(IMemInputPin
*iface
)
550 SinkFilter
*This
= impl_from_SinkFilter_IMemInputPin(iface
);
551 return IMemInputPin_ReceiveCanBlock(This
->nullRendererMemInputPin
);
554 static const IMemInputPinVtbl SinkMemInputPinVtbl
= {
555 SinkMemInputPin_QueryInterface
,
556 SinkMemInputPin_AddRef
,
557 SinkMemInputPin_Release
,
558 SinkMemInputPin_GetAllocator
,
559 SinkMemInputPin_NotifyAllocator
,
560 SinkMemInputPin_GetAllocatorRequirements
,
561 SinkMemInputPin_Receive
,
562 SinkMemInputPin_ReceiveMultiple
,
563 SinkMemInputPin_ReceiveCanBlock
566 static SinkFilter
* create_SinkFilter(BOOL isCapture
)
568 SinkFilter
*This
= NULL
;
570 This
= CoTaskMemAlloc(sizeof(*This
));
572 memset(This
, 0, sizeof(*This
));
573 This
->IBaseFilter_iface
.lpVtbl
= &SinkFilterVtbl
;
575 This
->isCapture
= isCapture
;
576 This
->IPin_iface
.lpVtbl
= &SinkPinVtbl
;
577 This
->IMemInputPin_iface
.lpVtbl
= &SinkMemInputPinVtbl
;
578 hr
= CoCreateInstance(&CLSID_NullRenderer
, NULL
, CLSCTX_INPROC_SERVER
,
579 &IID_IBaseFilter
, (LPVOID
*)&This
->nullRenderer
);
581 IEnumPins
*enumPins
= NULL
;
582 hr
= IBaseFilter_EnumPins(This
->nullRenderer
, &enumPins
);
584 hr
= IEnumPins_Next(enumPins
, 1, &This
->nullRendererPin
, NULL
);
585 IEnumPins_Release(enumPins
);
587 hr
= IPin_QueryInterface(This
->nullRendererPin
, &IID_IMemInputPin
,
588 (LPVOID
*)&This
->nullRendererMemInputPin
);
591 IPin_Release(This
->nullRendererPin
);
594 IBaseFilter_Release(This
->nullRenderer
);
602 IBaseFilter IBaseFilter_iface
;
607 IReferenceClock
*referenceClock
;
608 FILTER_INFO filterInfo
;
609 AM_MEDIA_TYPE mediaType
;
610 VIDEOINFOHEADER videoInfo
;
612 IMemInputPin
*memInputPin
;
613 IMemAllocator
*allocator
;
618 IEnumPins IEnumPins_iface
;
621 SourceFilter
*filter
;
624 static const WCHAR sourcePinName
[] = {'C','a','p','t','u','r','e',0};
626 static SourceEnumPins
* create_SourceEnumPins(SourceFilter
*filter
);
628 static inline SourceFilter
* impl_from_SourceFilter_IBaseFilter(IBaseFilter
*iface
)
630 return CONTAINING_RECORD(iface
, SourceFilter
, IBaseFilter_iface
);
633 static inline SourceFilter
* impl_from_SourceFilter_IPin(IPin
*iface
)
635 return CONTAINING_RECORD(iface
, SourceFilter
, IPin_iface
);
638 static inline SourceEnumPins
* impl_from_SourceFilter_IEnumPins(IEnumPins
*iface
)
640 return CONTAINING_RECORD(iface
, SourceEnumPins
, IEnumPins_iface
);
643 static HRESULT WINAPI
SourceFilter_QueryInterface(IBaseFilter
*iface
, REFIID riid
, void **ppv
)
645 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
646 if(IsEqualIID(riid
, &IID_IUnknown
)) {
647 *ppv
= &This
->IBaseFilter_iface
;
648 } else if(IsEqualIID(riid
, &IID_IPersist
)) {
649 *ppv
= &This
->IBaseFilter_iface
;
650 } else if(IsEqualIID(riid
, &IID_IMediaFilter
)) {
651 *ppv
= &This
->IBaseFilter_iface
;
652 } else if(IsEqualIID(riid
, &IID_IBaseFilter
)) {
653 *ppv
= &This
->IBaseFilter_iface
;
655 trace("no interface for %s\n", wine_dbgstr_guid(riid
));
657 return E_NOINTERFACE
;
659 IUnknown_AddRef((IUnknown
*)*ppv
);
663 static ULONG WINAPI
SourceFilter_AddRef(IBaseFilter
*iface
)
665 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
666 return InterlockedIncrement(&This
->ref
);
669 static ULONG WINAPI
SourceFilter_Release(IBaseFilter
*iface
)
671 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
672 ULONG ref
= InterlockedDecrement(&This
->ref
);
674 if (This
->referenceClock
)
675 IReferenceClock_Release(This
->referenceClock
);
676 if (This
->connectedTo
)
677 IPin_Disconnect(&This
->IPin_iface
);
678 DeleteCriticalSection(&This
->cs
);
684 static HRESULT WINAPI
SourceFilter_GetClassID(IBaseFilter
*iface
, CLSID
*pClassID
)
686 *pClassID
= CLSID_VfwCapture
;
690 static HRESULT WINAPI
SourceFilter_Stop(IBaseFilter
*iface
)
692 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
693 EnterCriticalSection(&This
->cs
);
694 IMemAllocator_Decommit(This
->allocator
);
695 This
->state
= State_Stopped
;
696 LeaveCriticalSection(&This
->cs
);
700 static HRESULT WINAPI
SourceFilter_Pause(IBaseFilter
*iface
)
702 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
703 EnterCriticalSection(&This
->cs
);
704 This
->state
= State_Paused
;
705 LeaveCriticalSection(&This
->cs
);
709 static DWORD WINAPI
media_thread(LPVOID param
)
711 SourceFilter
*This
= (SourceFilter
*) param
;
713 IMediaSample
*sample
= NULL
;
714 REFERENCE_TIME startTime
;
715 REFERENCE_TIME endTime
;
718 hr
= IMemAllocator_GetBuffer(This
->allocator
, &sample
, NULL
, NULL
, 0);
719 ok(SUCCEEDED(hr
), "IMemAllocator_GetBuffer() failed, hr=0x%08x\n", hr
);
723 hr
= IMediaSample_SetTime(sample
, &startTime
, &endTime
);
724 ok(SUCCEEDED(hr
), "IMediaSample_SetTime() failed, hr=0x%08x\n", hr
);
725 hr
= IMediaSample_SetMediaType(sample
, &This
->mediaType
);
726 ok(SUCCEEDED(hr
), "IMediaSample_SetMediaType() failed, hr=0x%08x\n", hr
);
728 hr
= IMediaSample_GetPointer(sample
, &buffer
);
729 ok(SUCCEEDED(hr
), "IMediaSample_GetPointer() failed, hr=0x%08x\n", hr
);
731 /* 10 by 10 pixel 32 RGB */
733 for (i
= 0; i
< 100; i
++)
737 hr
= IMemInputPin_Receive(This
->memInputPin
, sample
);
738 ok(SUCCEEDED(hr
), "delivering sample to SmartTeeFilter's Input pin failed, hr=0x%08x\n", hr
);
740 IMediaSample_Release(sample
);
745 static HRESULT WINAPI
SourceFilter_Run(IBaseFilter
*iface
, REFERENCE_TIME tStart
)
747 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
749 EnterCriticalSection(&This
->cs
);
750 hr
= IMemAllocator_Commit(This
->allocator
);
752 HANDLE thread
= CreateThread(NULL
, 0, media_thread
, This
, 0, &This
->mediaThreadId
);
753 ok(thread
!= NULL
, "couldn't create media thread, GetLastError()=%u\n", GetLastError());
754 if (thread
!= NULL
) {
756 This
->state
= State_Running
;
758 IMemAllocator_Decommit(This
->allocator
);
762 LeaveCriticalSection(&This
->cs
);
766 static HRESULT WINAPI
SourceFilter_GetState(IBaseFilter
*iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*state
)
768 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
769 EnterCriticalSection(&This
->cs
);
770 *state
= This
->state
;
771 LeaveCriticalSection(&This
->cs
);
775 static HRESULT WINAPI
SourceFilter_SetSyncSource(IBaseFilter
*iface
, IReferenceClock
*pClock
)
777 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
778 EnterCriticalSection(&This
->cs
);
779 if (This
->referenceClock
)
780 IReferenceClock_Release(This
->referenceClock
);
781 This
->referenceClock
= pClock
;
782 if (This
->referenceClock
)
783 IReferenceClock_AddRef(This
->referenceClock
);
784 LeaveCriticalSection(&This
->cs
);
788 static HRESULT WINAPI
SourceFilter_GetSyncSource(IBaseFilter
*iface
, IReferenceClock
**ppClock
)
790 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
791 EnterCriticalSection(&This
->cs
);
792 *ppClock
= This
->referenceClock
;
793 if (This
->referenceClock
)
794 IReferenceClock_AddRef(This
->referenceClock
);
795 LeaveCriticalSection(&This
->cs
);
799 static HRESULT WINAPI
SourceFilter_EnumPins(IBaseFilter
*iface
, IEnumPins
**ppEnum
)
801 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
802 SourceEnumPins
*sourceEnumPins
= create_SourceEnumPins(This
);
803 if (sourceEnumPins
) {
804 *ppEnum
= &sourceEnumPins
->IEnumPins_iface
;
808 return E_OUTOFMEMORY
;
811 static HRESULT WINAPI
SourceFilter_FindPin(IBaseFilter
*iface
, LPCWSTR id
, IPin
**ppPin
)
813 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
817 if (lstrcmpW(id
, sourcePinName
) == 0) {
818 *ppPin
= &This
->IPin_iface
;
819 IPin_AddRef(&This
->IPin_iface
);
822 return VFW_E_NOT_FOUND
;
825 static HRESULT WINAPI
SourceFilter_QueryFilterInfo(IBaseFilter
*iface
, FILTER_INFO
*pInfo
)
827 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
830 EnterCriticalSection(&This
->cs
);
831 *pInfo
= This
->filterInfo
;
832 if (This
->filterInfo
.pGraph
)
833 IFilterGraph_AddRef(This
->filterInfo
.pGraph
);
834 LeaveCriticalSection(&This
->cs
);
838 static HRESULT WINAPI
SourceFilter_JoinFilterGraph(IBaseFilter
*iface
, IFilterGraph
*pGraph
, LPCWSTR pName
)
840 SourceFilter
*This
= impl_from_SourceFilter_IBaseFilter(iface
);
841 EnterCriticalSection(&This
->cs
);
843 lstrcpyW(This
->filterInfo
.achName
, pName
);
845 This
->filterInfo
.achName
[0] = 0;
846 This
->filterInfo
.pGraph
= pGraph
;
847 LeaveCriticalSection(&This
->cs
);
851 static HRESULT WINAPI
SourceFilter_QueryVendorInfo(IBaseFilter
*iface
, LPWSTR
*pVendorInfo
)
856 static const IBaseFilterVtbl SourceFilterVtbl
= {
857 SourceFilter_QueryInterface
,
859 SourceFilter_Release
,
860 SourceFilter_GetClassID
,
864 SourceFilter_GetState
,
865 SourceFilter_SetSyncSource
,
866 SourceFilter_GetSyncSource
,
867 SourceFilter_EnumPins
,
868 SourceFilter_FindPin
,
869 SourceFilter_QueryFilterInfo
,
870 SourceFilter_JoinFilterGraph
,
871 SourceFilter_QueryVendorInfo
874 static HRESULT WINAPI
SourceEnumPins_QueryInterface(IEnumPins
*iface
, REFIID riid
, void **ppv
)
876 SourceEnumPins
*This
= impl_from_SourceFilter_IEnumPins(iface
);
877 if(IsEqualIID(riid
, &IID_IUnknown
)) {
878 *ppv
= &This
->IEnumPins_iface
;
879 } else if(IsEqualIID(riid
, &IID_IEnumPins
)) {
880 *ppv
= &This
->IEnumPins_iface
;
882 trace("no interface for %s\n", wine_dbgstr_guid(riid
));
884 return E_NOINTERFACE
;
886 IUnknown_AddRef((IUnknown
*)*ppv
);
890 static ULONG WINAPI
SourceEnumPins_AddRef(IEnumPins
*iface
)
892 SourceEnumPins
*This
= impl_from_SourceFilter_IEnumPins(iface
);
893 return InterlockedIncrement(&This
->ref
);
896 static ULONG WINAPI
SourceEnumPins_Release(IEnumPins
*iface
)
898 SourceEnumPins
*This
= impl_from_SourceFilter_IEnumPins(iface
);
900 ref
= InterlockedDecrement(&This
->ref
);
903 IBaseFilter_Release(&This
->filter
->IBaseFilter_iface
);
909 static HRESULT WINAPI
SourceEnumPins_Next(IEnumPins
*iface
, ULONG cPins
, IPin
**ppPins
, ULONG
*pcFetched
)
911 SourceEnumPins
*This
= impl_from_SourceFilter_IEnumPins(iface
);
914 if (cPins
> 1 && !pcFetched
)
920 if (This
->index
== 0) {
921 ppPins
[0] = &This
->filter
->IPin_iface
;
922 IPin_AddRef(&This
->filter
->IPin_iface
);
931 static HRESULT WINAPI
SourceEnumPins_Skip(IEnumPins
*iface
, ULONG cPins
)
933 SourceEnumPins
*This
= impl_from_SourceFilter_IEnumPins(iface
);
934 if (This
->index
+ cPins
>= 1)
936 This
->index
+= cPins
;
940 static HRESULT WINAPI
SourceEnumPins_Reset(IEnumPins
*iface
)
942 SourceEnumPins
*This
= impl_from_SourceFilter_IEnumPins(iface
);
947 static HRESULT WINAPI
SourceEnumPins_Clone(IEnumPins
*iface
, IEnumPins
**ppEnum
)
949 SourceEnumPins
*This
= impl_from_SourceFilter_IEnumPins(iface
);
950 SourceEnumPins
*clone
= create_SourceEnumPins(This
->filter
);
952 return E_OUTOFMEMORY
;
953 clone
->index
= This
->index
;
957 static const IEnumPinsVtbl SourceEnumPinsVtbl
= {
958 SourceEnumPins_QueryInterface
,
959 SourceEnumPins_AddRef
,
960 SourceEnumPins_Release
,
963 SourceEnumPins_Reset
,
967 static SourceEnumPins
* create_SourceEnumPins(SourceFilter
*filter
)
969 SourceEnumPins
*This
;
970 This
= CoTaskMemAlloc(sizeof(*This
));
974 This
->IEnumPins_iface
.lpVtbl
= &SourceEnumPinsVtbl
;
977 This
->filter
= filter
;
978 IBaseFilter_AddRef(&filter
->IBaseFilter_iface
);
982 static HRESULT WINAPI
SourcePin_QueryInterface(IPin
*iface
, REFIID riid
, void **ppv
)
984 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
985 if(IsEqualIID(riid
, &IID_IUnknown
)) {
986 *ppv
= &This
->IPin_iface
;
987 } else if(IsEqualIID(riid
, &IID_IPin
)) {
988 *ppv
= &This
->IPin_iface
;
990 trace("no interface for %s\n", wine_dbgstr_guid(riid
));
992 return E_NOINTERFACE
;
994 IUnknown_AddRef((IUnknown
*)*ppv
);
998 static ULONG WINAPI
SourcePin_AddRef(IPin
*iface
)
1000 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1001 return IBaseFilter_AddRef(&This
->IBaseFilter_iface
);
1004 static ULONG WINAPI
SourcePin_Release(IPin
*iface
)
1006 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1007 return IBaseFilter_Release(&This
->IBaseFilter_iface
);
1010 static HRESULT WINAPI
SourcePin_Connect(IPin
*iface
, IPin
*pReceivePin
, const AM_MEDIA_TYPE
*pmt
)
1012 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1014 if (pmt
&& !IsEqualGUID(&pmt
->majortype
, &GUID_NULL
) && !IsEqualGUID(&pmt
->majortype
, &MEDIATYPE_Video
))
1015 return VFW_E_TYPE_NOT_ACCEPTED
;
1016 if (pmt
&& !IsEqualGUID(&pmt
->subtype
, &GUID_NULL
) && !IsEqualGUID(&pmt
->subtype
, &MEDIASUBTYPE_RGB32
))
1017 return VFW_E_TYPE_NOT_ACCEPTED
;
1018 if (pmt
&& !IsEqualGUID(&pmt
->formattype
, &GUID_NULL
))
1019 return VFW_E_TYPE_NOT_ACCEPTED
;
1020 hr
= IPin_ReceiveConnection(pReceivePin
, &This
->IPin_iface
, &This
->mediaType
);
1021 ok(SUCCEEDED(hr
), "SmartTeeFilter's Input pin's IPin_ReceiveConnection() failed with 0x%08x\n", hr
);
1022 if (SUCCEEDED(hr
)) {
1023 EnterCriticalSection(&This
->cs
);
1024 hr
= IPin_QueryInterface(pReceivePin
, &IID_IMemInputPin
, (void**)&This
->memInputPin
);
1025 if (SUCCEEDED(hr
)) {
1026 hr
= IMemInputPin_GetAllocator(This
->memInputPin
, &This
->allocator
);
1027 ok(SUCCEEDED(hr
), "couldn't get allocator from SmartTeeFilter, hr=0x%08x\n", hr
);
1028 if (SUCCEEDED(hr
)) {
1029 ALLOCATOR_PROPERTIES requested
, actual
;
1030 ZeroMemory(&requested
, sizeof(ALLOCATOR_PROPERTIES
));
1031 IMemInputPin_GetAllocatorRequirements(This
->memInputPin
, &requested
);
1032 if (requested
.cBuffers
< 3) requested
.cBuffers
= 3;
1033 if (requested
.cbBuffer
< 4096) requested
.cbBuffer
= 4096;
1034 if (requested
.cbAlign
< 1) requested
.cbAlign
= 1;
1035 if (requested
.cbPrefix
< 0) requested
.cbPrefix
= 0;
1036 hr
= IMemAllocator_SetProperties(This
->allocator
, &requested
, &actual
);
1037 if (SUCCEEDED(hr
)) {
1038 hr
= IMemInputPin_NotifyAllocator(This
->memInputPin
, This
->allocator
, FALSE
);
1039 if (SUCCEEDED(hr
)) {
1040 This
->connectedTo
= pReceivePin
;
1041 IPin_AddRef(pReceivePin
);
1045 IMemAllocator_Release(This
->allocator
);
1046 This
->allocator
= NULL
;
1050 IMemInputPin_Release(This
->memInputPin
);
1051 This
->memInputPin
= NULL
;
1054 LeaveCriticalSection(&This
->cs
);
1057 IPin_Disconnect(pReceivePin
);
1062 static HRESULT WINAPI
SourcePin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*pmt
)
1064 return E_UNEXPECTED
;
1067 static HRESULT WINAPI
SourcePin_Disconnect(IPin
*iface
)
1069 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1071 EnterCriticalSection(&This
->cs
);
1072 if (This
->connectedTo
) {
1073 if (This
->state
== State_Stopped
) {
1074 IMemAllocator_Release(This
->allocator
);
1075 This
->allocator
= NULL
;
1076 IMemInputPin_Release(This
->memInputPin
);
1077 This
->memInputPin
= NULL
;
1078 IPin_Release(This
->connectedTo
);
1079 This
->connectedTo
= NULL
;
1083 hr
= VFW_E_NOT_STOPPED
;
1086 LeaveCriticalSection(&This
->cs
);
1090 static HRESULT WINAPI
SourcePin_ConnectedTo(IPin
*iface
, IPin
**pPin
)
1092 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1096 EnterCriticalSection(&This
->cs
);
1097 if (This
->connectedTo
) {
1098 *pPin
= This
->connectedTo
;
1099 IPin_AddRef(This
->connectedTo
);
1102 hr
= VFW_E_NOT_CONNECTED
;
1103 LeaveCriticalSection(&This
->cs
);
1107 static HRESULT WINAPI
SourcePin_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*pmt
)
1109 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1113 EnterCriticalSection(&This
->cs
);
1114 if (This
->connectedTo
) {
1115 *pmt
= This
->mediaType
;
1116 pmt
->pbFormat
= CoTaskMemAlloc(sizeof(This
->videoInfo
));
1117 if (pmt
->pbFormat
) {
1118 memcpy(pmt
->pbFormat
, &This
->videoInfo
, sizeof(This
->videoInfo
));
1121 memset(pmt
, 0, sizeof(*pmt
));
1125 memset(pmt
, 0, sizeof(*pmt
));
1126 hr
= VFW_E_NOT_CONNECTED
;
1128 LeaveCriticalSection(&This
->cs
);
1132 static HRESULT WINAPI
SourcePin_QueryPinInfo(IPin
*iface
, PIN_INFO
*pInfo
)
1134 SourceFilter
*This
= impl_from_SourceFilter_IPin(iface
);
1137 lstrcpyW(pInfo
->achName
, sourcePinName
);
1138 pInfo
->dir
= PINDIR_OUTPUT
;
1139 pInfo
->pFilter
= &This
->IBaseFilter_iface
;
1140 IBaseFilter_AddRef(&This
->IBaseFilter_iface
);
1144 static HRESULT WINAPI
SourcePin_QueryDirection(IPin
*iface
, PIN_DIRECTION
*pPinDir
)
1148 *pPinDir
= PINDIR_OUTPUT
;
1152 static HRESULT WINAPI
SourcePin_QueryId(IPin
*iface
, LPWSTR
*id
)
1156 *id
= CoTaskMemAlloc((lstrlenW(sourcePinName
) + 1)*sizeof(WCHAR
));
1158 lstrcpyW(*id
, sourcePinName
);
1161 return E_OUTOFMEMORY
;
1164 static HRESULT WINAPI
SourcePin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*pmt
)
1169 static HRESULT WINAPI
SourcePin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**ppEnum
)
1171 return VFW_E_NOT_CONNECTED
;
1174 static HRESULT WINAPI
SourcePin_QueryInternalConnections(IPin
*iface
, IPin
**apPin
, ULONG
*nPin
)
1179 static HRESULT WINAPI
SourcePin_EndOfStream(IPin
*iface
)
1181 return E_UNEXPECTED
;
1184 static HRESULT WINAPI
SourcePin_BeginFlush(IPin
*iface
)
1186 return E_UNEXPECTED
;
1189 static HRESULT WINAPI
SourcePin_EndFlush(IPin
*iface
)
1191 return E_UNEXPECTED
;
1194 static HRESULT WINAPI
SourcePin_NewSegment(IPin
*iface
, REFERENCE_TIME tStart
,
1195 REFERENCE_TIME tStop
, double dRate
)
1200 static const IPinVtbl SourcePinVtbl
= {
1201 SourcePin_QueryInterface
,
1205 SourcePin_ReceiveConnection
,
1206 SourcePin_Disconnect
,
1207 SourcePin_ConnectedTo
,
1208 SourcePin_ConnectionMediaType
,
1209 SourcePin_QueryPinInfo
,
1210 SourcePin_QueryDirection
,
1212 SourcePin_QueryAccept
,
1213 SourcePin_EnumMediaTypes
,
1214 SourcePin_QueryInternalConnections
,
1215 SourcePin_EndOfStream
,
1216 SourcePin_BeginFlush
,
1218 SourcePin_NewSegment
1221 static SourceFilter
* create_SourceFilter(void)
1223 SourceFilter
*This
= NULL
;
1224 This
= CoTaskMemAlloc(sizeof(*This
));
1226 memset(This
, 0, sizeof(*This
));
1227 This
->IBaseFilter_iface
.lpVtbl
= &SourceFilterVtbl
;
1229 This
->IPin_iface
.lpVtbl
= &SourcePinVtbl
;
1230 InitializeCriticalSection(&This
->cs
);
1231 This
->mediaType
.majortype
= MEDIATYPE_Video
;
1232 This
->mediaType
.subtype
= MEDIASUBTYPE_RGB32
;
1233 This
->mediaType
.bFixedSizeSamples
= FALSE
;
1234 This
->mediaType
.bTemporalCompression
= FALSE
;
1235 This
->mediaType
.lSampleSize
= 0;
1236 This
->mediaType
.formattype
= FORMAT_VideoInfo
;
1237 This
->mediaType
.pUnk
= NULL
;
1238 This
->mediaType
.cbFormat
= sizeof(VIDEOINFOHEADER
);
1239 This
->mediaType
.pbFormat
= (BYTE
*) &This
->videoInfo
;
1240 This
->videoInfo
.dwBitRate
= 1000000;
1241 This
->videoInfo
.dwBitErrorRate
= 0;
1242 This
->videoInfo
.AvgTimePerFrame
= 400000;
1243 This
->videoInfo
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1244 This
->videoInfo
.bmiHeader
.biWidth
= 10;
1245 This
->videoInfo
.bmiHeader
.biHeight
= 10;
1246 This
->videoInfo
.bmiHeader
.biPlanes
= 1;
1247 This
->videoInfo
.bmiHeader
.biBitCount
= 32;
1248 This
->videoInfo
.bmiHeader
.biCompression
= BI_RGB
;
1249 This
->videoInfo
.bmiHeader
.biSizeImage
= 0;
1250 This
->videoInfo
.bmiHeader
.biXPelsPerMeter
= 96;
1251 This
->videoInfo
.bmiHeader
.biYPelsPerMeter
= 96;
1252 This
->videoInfo
.bmiHeader
.biClrUsed
= 0;
1253 This
->videoInfo
.bmiHeader
.biClrImportant
= 0;
1259 static BOOL
has_interface(IUnknown
*unknown
, REFIID uuid
)
1262 IUnknown
*iface
= NULL
;
1264 hr
= IUnknown_QueryInterface(unknown
, uuid
, (void**)&iface
);
1267 IUnknown_Release(iface
);
1274 static void test_smart_tee_filter_in_graph(IBaseFilter
*smartTeeFilter
, IPin
*inputPin
,
1275 IPin
*capturePin
, IPin
*previewPin
)
1278 IGraphBuilder
*graphBuilder
= NULL
;
1279 IMediaControl
*mediaControl
= NULL
;
1280 SourceFilter
*sourceFilter
= NULL
;
1281 SinkFilter
*captureSinkFilter
= NULL
;
1282 SinkFilter
*previewSinkFilter
= NULL
;
1285 hr
= CoCreateInstance(&CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IGraphBuilder
,
1286 (LPVOID
*)&graphBuilder
);
1287 ok(SUCCEEDED(hr
), "couldn't create graph builder, hr=0x%08x\n", hr
);
1291 hr
= IGraphBuilder_AddFilter(graphBuilder
, smartTeeFilter
, NULL
);
1292 ok(SUCCEEDED(hr
), "couldn't add smart tee filter to graph, hr=0x%08x\n", hr
);
1296 captureSinkFilter
= create_SinkFilter(TRUE
);
1297 if (captureSinkFilter
== NULL
) {
1298 skip("couldn't create capture sink filter\n");
1301 hr
= IGraphBuilder_AddFilter(graphBuilder
, &captureSinkFilter
->IBaseFilter_iface
, NULL
);
1303 skip("couldn't add capture sink filter to graph, hr=0x%08x\n", hr
);
1307 previewSinkFilter
= create_SinkFilter(FALSE
);
1308 if (previewSinkFilter
== NULL
) {
1309 skip("couldn't create preview sink filter\n");
1312 hr
= IGraphBuilder_AddFilter(graphBuilder
, &previewSinkFilter
->IBaseFilter_iface
, NULL
);
1314 skip("couldn't add preview sink filter to graph, hr=0x%08x\n", hr
);
1318 hr
= IGraphBuilder_Connect(graphBuilder
, capturePin
, &captureSinkFilter
->IPin_iface
);
1319 ok(hr
== VFW_E_NOT_CONNECTED
, "connecting Capture pin without first connecting Input pin returned 0x%08x\n", hr
);
1320 hr
= IGraphBuilder_Connect(graphBuilder
, previewPin
, &previewSinkFilter
->IPin_iface
);
1321 ok(hr
== VFW_E_NOT_CONNECTED
, "connecting Preview pin without first connecting Input pin returned 0x%08x\n", hr
);
1323 sourceFilter
= create_SourceFilter();
1324 if (sourceFilter
== NULL
) {
1325 skip("couldn't create source filter\n");
1328 hr
= IGraphBuilder_AddFilter(graphBuilder
, &sourceFilter
->IBaseFilter_iface
, NULL
);
1329 ok(SUCCEEDED(hr
), "couldn't add source filter to graph, hr=0x%08x\n", hr
);
1333 hr
= IGraphBuilder_Connect(graphBuilder
, &sourceFilter
->IPin_iface
, inputPin
);
1334 ok(SUCCEEDED(hr
), "couldn't connect source filter to Input pin, hr=0x%08x\n", hr
);
1337 hr
= IGraphBuilder_Connect(graphBuilder
, capturePin
, &captureSinkFilter
->IPin_iface
);
1338 ok(SUCCEEDED(hr
), "couldn't connect Capture pin to sink, hr=0x%08x\n", hr
);
1341 hr
= IGraphBuilder_Connect(graphBuilder
, previewPin
, &previewSinkFilter
->IPin_iface
);
1342 ok(SUCCEEDED(hr
), "couldn't connect Preview pin to sink, hr=0x%08x\n", hr
);
1346 ok(sourceFilter
->allocator
== captureSinkFilter
->allocator
, "input and capture allocators don't match\n");
1347 ok(sourceFilter
->allocator
== previewSinkFilter
->allocator
, "input and preview allocators don't match\n");
1349 hr
= IGraphBuilder_QueryInterface(graphBuilder
, &IID_IMediaControl
, (void**)&mediaControl
);
1350 ok(SUCCEEDED(hr
), "couldn't get IMediaControl interface from IGraphBuilder, hr=0x%08x\n", hr
);
1353 hr
= IMediaControl_Run(mediaControl
);
1354 ok(SUCCEEDED(hr
), "IMediaControl_Run() failed, hr=0x%08x\n", hr
);
1358 endTime
= GetTickCount() + 5000;
1359 while (previewSinkFilter
->receiveThreadId
== 0 || captureSinkFilter
->receiveThreadId
== 0) {
1360 DWORD now
= GetTickCount();
1362 WaitForSingleObject(event
, endTime
- now
);
1366 if (previewSinkFilter
->receiveThreadId
!= 0 && captureSinkFilter
->receiveThreadId
!= 0) {
1367 todo_wine
ok(sourceFilter
->mediaThreadId
!= captureSinkFilter
->receiveThreadId
,
1368 "sending thread should != capture receiving thread\n");
1369 todo_wine
ok(sourceFilter
->mediaThreadId
!= previewSinkFilter
->receiveThreadId
,
1370 "sending thread should != preview receiving thread\n");
1371 todo_wine
ok(captureSinkFilter
->receiveThreadId
!= previewSinkFilter
->receiveThreadId
,
1372 "capture receiving thread should != preview receiving thread");
1374 ok(0, "timeout: threads did not receive sample in time\n");
1377 IMediaControl_Stop(mediaControl
);
1381 IMediaControl_Release(mediaControl
);
1383 IGraphBuilder_Release(graphBuilder
);
1385 IBaseFilter_Release(&sourceFilter
->IBaseFilter_iface
);
1386 if (captureSinkFilter
)
1387 IBaseFilter_Release(&captureSinkFilter
->IBaseFilter_iface
);
1388 if (previewSinkFilter
)
1389 IBaseFilter_Release(&previewSinkFilter
->IBaseFilter_iface
);
1392 static void test_smart_tee_filter(void)
1395 IBaseFilter
*smartTeeFilter
= NULL
;
1396 IEnumPins
*enumPins
= NULL
;
1398 IPin
*inputPin
= NULL
;
1399 IPin
*capturePin
= NULL
;
1400 IPin
*previewPin
= NULL
;
1401 FILTER_INFO filterInfo
;
1403 IMemInputPin
*memInputPin
= NULL
;
1404 IEnumMediaTypes
*enumMediaTypes
= NULL
;
1407 hr
= CoCreateInstance(&CLSID_SmartTee
, NULL
, CLSCTX_INPROC_SERVER
,
1408 &IID_IBaseFilter
, (void**)&smartTeeFilter
);
1409 ok(SUCCEEDED(hr
), "couldn't create smart tee filter, hr=0x%08x\n", hr
);
1413 hr
= IBaseFilter_QueryFilterInfo(smartTeeFilter
, &filterInfo
);
1414 ok(SUCCEEDED(hr
), "QueryFilterInfo failed, hr=0x%08x\n", hr
);
1418 ok(lstrlenW(filterInfo
.achName
) == 0,
1419 "filter's name is meant to be empty but it's %s\n", wine_dbgstr_w(filterInfo
.achName
));
1421 hr
= IBaseFilter_EnumPins(smartTeeFilter
, &enumPins
);
1422 ok(SUCCEEDED(hr
), "cannot enum filter pins, hr=0x%08x\n", hr
);
1426 while (IEnumPins_Next(enumPins
, 1, &pin
, NULL
) == S_OK
)
1430 memset(&pinInfo
, 0, sizeof(pinInfo
));
1431 hr
= IPin_QueryPinInfo(pin
, &pinInfo
);
1432 ok(SUCCEEDED(hr
), "QueryPinInfo failed, hr=0x%08x\n", hr
);
1436 ok(pinInfo
.pFilter
== smartTeeFilter
, "pin's filter isn't the filter owning the pin\n");
1439 static const WCHAR wszInput
[] = {'I','n','p','u','t',0};
1440 ok(pinInfo
.dir
== PINDIR_INPUT
, "pin 0 isn't an input pin\n");
1441 ok(!lstrcmpW(pinInfo
.achName
, wszInput
), "pin 0 is called %s, not 'Input'\n", wine_dbgstr_w(pinInfo
.achName
));
1442 hr
= IPin_QueryId(pin
, &id
);
1443 ok(SUCCEEDED(hr
), "IPin_QueryId() failed with 0x%08x\n", hr
);
1444 ok(!lstrcmpW(id
, wszInput
), "pin 0's id is %s, not 'Input'\n", wine_dbgstr_w(id
));
1446 IPin_AddRef(inputPin
);
1448 else if (pinNumber
== 1)
1450 static const WCHAR wszCapture
[] = {'C','a','p','t','u','r','e',0};
1451 ok(pinInfo
.dir
== PINDIR_OUTPUT
, "pin 1 isn't an output pin\n");
1452 ok(!lstrcmpW(pinInfo
.achName
, wszCapture
), "pin 1 is called %s, not 'Capture'\n", wine_dbgstr_w(pinInfo
.achName
));
1453 hr
= IPin_QueryId(pin
, &id
);
1454 ok(SUCCEEDED(hr
), "IPin_QueryId() failed with 0x%08x\n", hr
);
1455 ok(!lstrcmpW(id
, wszCapture
), "pin 1's id is %s, not 'Capture'\n", wine_dbgstr_w(id
));
1457 IPin_AddRef(capturePin
);
1459 else if (pinNumber
== 2)
1461 static const WCHAR wszPreview
[] = {'P','r','e','v','i','e','w',0};
1462 ok(pinInfo
.dir
== PINDIR_OUTPUT
, "pin 2 isn't an output pin\n");
1463 ok(!lstrcmpW(pinInfo
.achName
, wszPreview
), "pin 2 is called %s, not 'Preview'\n", wine_dbgstr_w(pinInfo
.achName
));
1464 hr
= IPin_QueryId(pin
, &id
);
1465 ok(SUCCEEDED(hr
), "IPin_QueryId() failed with 0x%08x\n", hr
);
1466 ok(!lstrcmpW(id
, wszPreview
), "pin 2's id is %s, not 'Preview'\n", wine_dbgstr_w(id
));
1468 IPin_AddRef(previewPin
);
1471 ok(0, "pin %d isn't supposed to exist\n", pinNumber
);
1474 if (pinInfo
.pFilter
)
1475 IBaseFilter_Release(pinInfo
.pFilter
);
1482 ok(inputPin
&& capturePin
&& previewPin
, "couldn't find all pins\n");
1483 if (!(inputPin
&& capturePin
&& previewPin
))
1486 ok(has_interface((IUnknown
*)inputPin
, &IID_IUnknown
), "IUnknown should exist on the input pin\n");
1487 ok(has_interface((IUnknown
*)inputPin
, &IID_IMemInputPin
), "IMemInputPin should exist the input pin\n");
1488 ok(!has_interface((IUnknown
*)inputPin
, &IID_IKsPropertySet
), "IKsPropertySet shouldn't eixst on the input pin\n");
1489 ok(!has_interface((IUnknown
*)inputPin
, &IID_IAMStreamConfig
), "IAMStreamConfig shouldn't exist on the input pin\n");
1490 ok(!has_interface((IUnknown
*)inputPin
, &IID_IAMStreamControl
), "IAMStreamControl shouldn't exist on the input pin\n");
1491 ok(!has_interface((IUnknown
*)inputPin
, &IID_IPropertyBag
), "IPropertyBag shouldn't exist on the input pin\n");
1492 todo_wine
ok(has_interface((IUnknown
*)inputPin
, &IID_IQualityControl
), "IQualityControl should exist on the input pin\n");
1494 ok(has_interface((IUnknown
*)capturePin
, &IID_IUnknown
), "IUnknown should exist on the capture pin\n");
1495 ok(!has_interface((IUnknown
*)capturePin
, &IID_IAsyncReader
), "IAsyncReader shouldn't exist on the capture pin\n");
1496 ok(!has_interface((IUnknown
*)capturePin
, &IID_IKsPropertySet
), "IKsPropertySet shouldn't exist on the capture pin\n");
1497 ok(!has_interface((IUnknown
*)capturePin
, &IID_IAMStreamConfig
), "IAMStreamConfig shouldn't exist on the capture pin\n");
1498 todo_wine
ok(has_interface((IUnknown
*)capturePin
, &IID_IAMStreamControl
), "IAMStreamControl should exist on the capture pin\n");
1499 ok(!has_interface((IUnknown
*)capturePin
, &IID_IPropertyBag
), "IPropertyBag shouldn't exist on the capture pin\n");
1500 todo_wine
ok(has_interface((IUnknown
*)capturePin
, &IID_IQualityControl
), "IQualityControl should exist on the capture pin\n");
1502 ok(has_interface((IUnknown
*)previewPin
, &IID_IUnknown
), "IUnknown should exist on the preview pin\n");
1503 ok(!has_interface((IUnknown
*)previewPin
, &IID_IAsyncReader
), "IAsyncReader shouldn't exist on the preview pin\n");
1504 ok(!has_interface((IUnknown
*)previewPin
, &IID_IKsPropertySet
), "IKsPropertySet shouldn't exist on the preview pin\n");
1505 ok(!has_interface((IUnknown
*)previewPin
, &IID_IAMStreamConfig
), "IAMStreamConfig shouldn't exist on the preview pin\n");
1506 todo_wine
ok(has_interface((IUnknown
*)capturePin
, &IID_IAMStreamControl
), "IAMStreamControl should exist on the preview pin\n");
1507 ok(!has_interface((IUnknown
*)previewPin
, &IID_IPropertyBag
), "IPropertyBag shouldn't exist on the preview pin\n");
1508 todo_wine
ok(has_interface((IUnknown
*)previewPin
, &IID_IQualityControl
), "IQualityControl should exist on the preview pin\n");
1510 hr
= IPin_QueryInterface(inputPin
, &IID_IMemInputPin
, (void**)&memInputPin
);
1511 ok(SUCCEEDED(hr
), "couldn't get mem input pin, hr=0x%08x\n", hr
);
1514 hr
= IMemInputPin_ReceiveCanBlock(memInputPin
);
1515 ok(hr
== S_OK
, "unexpected IMemInputPin_ReceiveCanBlock() = 0x%08x\n", hr
);
1517 hr
= IPin_EnumMediaTypes(inputPin
, &enumMediaTypes
);
1518 ok(SUCCEEDED(hr
), "IPin_EnumMediaTypes() failed, hr=0x%08x\n", hr
);
1519 if (SUCCEEDED(hr
)) {
1520 AM_MEDIA_TYPE
*mediaType
= NULL
;
1521 hr
= IEnumMediaTypes_Next(enumMediaTypes
, 1, &mediaType
, NULL
);
1522 ok(hr
== S_FALSE
, "the media types are non-empty\n");
1524 IEnumMediaTypes_Release(enumMediaTypes
);
1525 enumMediaTypes
= NULL
;
1526 hr
= IPin_EnumMediaTypes(capturePin
, &enumMediaTypes
);
1527 ok(hr
== VFW_E_NOT_CONNECTED
, "IPin_EnumMediaTypes() failed, hr=0x%08x\n", hr
);
1528 hr
= IPin_EnumMediaTypes(previewPin
, &enumMediaTypes
);
1529 ok(hr
== VFW_E_NOT_CONNECTED
, "IPin_EnumMediaTypes() failed, hr=0x%08x\n", hr
);
1531 hr
= IPin_QueryInternalConnections(inputPin
, NULL
, &nPin
);
1532 ok(hr
== E_NOTIMPL
, "IPin_QueryInternalConnections() returned hr=0x%08x\n", hr
);
1533 hr
= IPin_QueryInternalConnections(capturePin
, NULL
, &nPin
);
1534 ok(hr
== E_NOTIMPL
, "IPin_QueryInternalConnections() returned hr=0x%08x\n", hr
);
1535 hr
= IPin_QueryInternalConnections(previewPin
, NULL
, &nPin
);
1536 ok(hr
== E_NOTIMPL
, "IPin_QueryInternalConnections() returned hr=0x%08x\n", hr
);
1538 test_smart_tee_filter_in_graph(smartTeeFilter
, inputPin
, capturePin
, previewPin
);
1542 IPin_Release(inputPin
);
1544 IPin_Release(capturePin
);
1546 IPin_Release(previewPin
);
1548 IBaseFilter_Release(smartTeeFilter
);
1550 IEnumPins_Release(enumPins
);
1552 IMemInputPin_Release(memInputPin
);
1554 IEnumMediaTypes_Release(enumMediaTypes
);
1557 static void test_smart_tee_filter_aggregation(void)
1559 SourceFilter
*sourceFilter
= create_SourceFilter();
1561 IUnknown
*unknown
= NULL
;
1562 HRESULT hr
= CoCreateInstance(&CLSID_SmartTee
, (IUnknown
*)&sourceFilter
->IBaseFilter_iface
,
1563 CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)&unknown
);
1564 ok(SUCCEEDED(hr
), "SmartTee filter doesn't support aggregation, hr=0x%08x\n", hr
);
1566 IUnknown_Release(unknown
);
1567 IBaseFilter_Release(&sourceFilter
->IBaseFilter_iface
);
1569 ok(0, "out of memory allocating SourceFilter for test\n");
1572 START_TEST(smartteefilter
)
1574 if (SUCCEEDED(CoInitialize(NULL
)))
1576 event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
1578 test_smart_tee_filter_aggregation();
1579 test_smart_tee_filter();
1582 skip("CreateEvent failed, error=%u\n", GetLastError());
1587 skip("CoInitialize failed\n");