2 * Implementation of the SmartTee filter
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 "qcap_main.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(qcap
);
39 IUnknown IUnknown_iface
;
40 IUnknown
*outerUnknown
;
43 BaseOutputPin
*capture
;
44 BaseOutputPin
*preview
;
47 static inline SmartTeeFilter
*impl_from_IUnknown(IUnknown
*iface
)
49 return CONTAINING_RECORD(iface
, SmartTeeFilter
, IUnknown_iface
);
52 static inline SmartTeeFilter
*impl_from_BaseFilter(BaseFilter
*filter
)
54 return CONTAINING_RECORD(filter
, SmartTeeFilter
, filter
);
57 static inline SmartTeeFilter
*impl_from_IBaseFilter(IBaseFilter
*iface
)
59 BaseFilter
*filter
= CONTAINING_RECORD(iface
, BaseFilter
, IBaseFilter_iface
);
60 return impl_from_BaseFilter(filter
);
63 static inline SmartTeeFilter
*impl_from_BasePin(BasePin
*pin
)
65 return impl_from_IBaseFilter(pin
->pinInfo
.pFilter
);
68 static inline SmartTeeFilter
*impl_from_IPin(IPin
*iface
)
70 BasePin
*bp
= CONTAINING_RECORD(iface
, BasePin
, IPin_iface
);
71 return impl_from_IBaseFilter(bp
->pinInfo
.pFilter
);
74 static HRESULT WINAPI
Unknown_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
76 SmartTeeFilter
*This
= impl_from_IUnknown(iface
);
77 if (IsEqualIID(riid
, &IID_IUnknown
)) {
78 TRACE("(%p)->(IID_IUnknown, %p)\n", This
, ppv
);
79 *ppv
= &This
->IUnknown_iface
;
80 } else if (IsEqualIID(riid
, &IID_IPersist
)) {
81 TRACE("(%p)->(IID_IPersist, %p)\n", This
, ppv
);
82 *ppv
= &This
->filter
.IBaseFilter_iface
;
83 } else if (IsEqualIID(riid
, &IID_IMediaFilter
)) {
84 TRACE("(%p)->(IID_IMediaFilter, %p)\n", This
, ppv
);
85 *ppv
= &This
->filter
.IBaseFilter_iface
;
86 } else if (IsEqualIID(riid
, &IID_IBaseFilter
)) {
87 TRACE("(%p)->(IID_IBaseFilter, %p)\n", This
, ppv
);
88 *ppv
= &This
->filter
.IBaseFilter_iface
;
90 FIXME("(%p): no interface for %s\n", This
, debugstr_guid(riid
));
94 IUnknown_AddRef((IUnknown
*)*ppv
);
98 static ULONG WINAPI
Unknown_AddRef(IUnknown
*iface
)
100 SmartTeeFilter
*This
= impl_from_IUnknown(iface
);
101 return BaseFilterImpl_AddRef(&This
->filter
.IBaseFilter_iface
);
104 static ULONG WINAPI
Unknown_Release(IUnknown
*iface
)
106 SmartTeeFilter
*This
= impl_from_IUnknown(iface
);
107 ULONG ref
= BaseFilterImpl_Release(&This
->filter
.IBaseFilter_iface
);
109 TRACE("(%p)->() ref=%d\n", This
, ref
);
113 BaseInputPinImpl_Release(&This
->input
->pin
.IPin_iface
);
115 BaseOutputPinImpl_Release(&This
->capture
->pin
.IPin_iface
);
117 BaseOutputPinImpl_Release(&This
->preview
->pin
.IPin_iface
);
123 static const IUnknownVtbl UnknownVtbl
= {
124 Unknown_QueryInterface
,
129 static HRESULT WINAPI
SmartTeeFilter_QueryInterface(IBaseFilter
*iface
, REFIID riid
, void **ppv
)
131 SmartTeeFilter
*This
= impl_from_IBaseFilter(iface
);
132 return IUnknown_QueryInterface(This
->outerUnknown
, riid
, ppv
);
135 static ULONG WINAPI
SmartTeeFilter_AddRef(IBaseFilter
*iface
)
137 SmartTeeFilter
*This
= impl_from_IBaseFilter(iface
);
138 return IUnknown_AddRef(This
->outerUnknown
);
141 static ULONG WINAPI
SmartTeeFilter_Release(IBaseFilter
*iface
)
143 SmartTeeFilter
*This
= impl_from_IBaseFilter(iface
);
144 return IUnknown_Release(This
->outerUnknown
);
147 static HRESULT WINAPI
SmartTeeFilter_Stop(IBaseFilter
*iface
)
149 SmartTeeFilter
*This
= impl_from_IBaseFilter(iface
);
150 TRACE("(%p)\n", This
);
151 EnterCriticalSection(&This
->filter
.csFilter
);
152 This
->filter
.state
= State_Stopped
;
153 LeaveCriticalSection(&This
->filter
.csFilter
);
157 static HRESULT WINAPI
SmartTeeFilter_Pause(IBaseFilter
*iface
)
159 SmartTeeFilter
*This
= impl_from_IBaseFilter(iface
);
160 FIXME("(%p): stub\n", This
);
164 static HRESULT WINAPI
SmartTeeFilter_Run(IBaseFilter
*iface
, REFERENCE_TIME tStart
)
166 SmartTeeFilter
*This
= impl_from_IBaseFilter(iface
);
168 TRACE("(%p, %s)\n", This
, wine_dbgstr_longlong(tStart
));
169 EnterCriticalSection(&This
->filter
.csFilter
);
170 if(This
->filter
.state
!= State_Running
) {
171 /* We share an allocator among all pins, an allocator can only get committed
172 * once, state transitions occur in upstream order, and only output pins
173 * commit allocators, so let the filter attached to the input pin worry about it. */
174 if (This
->input
->pin
.pConnectedTo
)
175 This
->filter
.state
= State_Running
;
177 hr
= VFW_E_NOT_CONNECTED
;
179 LeaveCriticalSection(&This
->filter
.csFilter
);
183 static const IBaseFilterVtbl SmartTeeFilterVtbl
= {
184 SmartTeeFilter_QueryInterface
,
185 SmartTeeFilter_AddRef
,
186 SmartTeeFilter_Release
,
187 BaseFilterImpl_GetClassID
,
189 SmartTeeFilter_Pause
,
191 BaseFilterImpl_GetState
,
192 BaseFilterImpl_SetSyncSource
,
193 BaseFilterImpl_GetSyncSource
,
194 BaseFilterImpl_EnumPins
,
195 BaseFilterImpl_FindPin
,
196 BaseFilterImpl_QueryFilterInfo
,
197 BaseFilterImpl_JoinFilterGraph
,
198 BaseFilterImpl_QueryVendorInfo
201 static IPin
* WINAPI
SmartTeeFilter_GetPin(BaseFilter
*iface
, int pos
)
203 SmartTeeFilter
*This
= impl_from_BaseFilter(iface
);
206 TRACE("(%p)->(%d)\n", This
, pos
);
210 ret
= &This
->input
->pin
.IPin_iface
;
213 ret
= &This
->capture
->pin
.IPin_iface
;
216 ret
= &This
->preview
->pin
.IPin_iface
;
219 TRACE("No pin %d\n", pos
);
227 static LONG WINAPI
SmartTeeFilter_GetPinCount(BaseFilter
*iface
)
231 static const BaseFilterFuncTable SmartTeeFilterFuncs
= {
232 SmartTeeFilter_GetPin
,
233 SmartTeeFilter_GetPinCount
236 static ULONG WINAPI
SmartTeeFilterInput_AddRef(IPin
*iface
)
238 SmartTeeFilter
*This
= impl_from_IPin(iface
);
239 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
242 static ULONG WINAPI
SmartTeeFilterInput_Release(IPin
*iface
)
244 SmartTeeFilter
*This
= impl_from_IPin(iface
);
245 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
249 static const IPinVtbl SmartTeeFilterInputVtbl
= {
250 BaseInputPinImpl_QueryInterface
,
251 SmartTeeFilterInput_AddRef
,
252 SmartTeeFilterInput_Release
,
253 BaseInputPinImpl_Connect
,
254 BaseInputPinImpl_ReceiveConnection
,
255 BasePinImpl_Disconnect
,
256 BasePinImpl_ConnectedTo
,
257 BasePinImpl_ConnectionMediaType
,
258 BasePinImpl_QueryPinInfo
,
259 BasePinImpl_QueryDirection
,
261 BasePinImpl_QueryAccept
,
262 BasePinImpl_EnumMediaTypes
,
263 BasePinImpl_QueryInternalConnections
,
264 BaseInputPinImpl_EndOfStream
,
265 BaseInputPinImpl_BeginFlush
,
266 BaseInputPinImpl_EndFlush
,
267 BaseInputPinImpl_NewSegment
270 static HRESULT WINAPI
SmartTeeFilterInput_CheckMediaType(BasePin
*base
, const AM_MEDIA_TYPE
*pmt
)
272 SmartTeeFilter
*This
= impl_from_BasePin(base
);
273 TRACE("(%p, AM_MEDIA_TYPE(%p))\n", This
, pmt
);
274 dump_AM_MEDIA_TYPE(pmt
);
276 return VFW_E_TYPE_NOT_ACCEPTED
;
277 /* We'll take any media type, but the output pins will later
278 * struggle to connect downstream. */
282 static LONG WINAPI
SmartTeeFilterInput_GetMediaTypeVersion(BasePin
*base
)
287 static HRESULT WINAPI
SmartTeeFilterInput_GetMediaType(BasePin
*base
, int iPosition
, AM_MEDIA_TYPE
*amt
)
289 SmartTeeFilter
*This
= impl_from_BasePin(base
);
291 TRACE("(%p)->(%d, %p)\n", This
, iPosition
, amt
);
294 EnterCriticalSection(&This
->filter
.csFilter
);
295 if (This
->input
->pin
.pConnectedTo
) {
296 CopyMediaType(amt
, &This
->input
->pin
.mtCurrent
);
300 LeaveCriticalSection(&This
->filter
.csFilter
);
304 static HRESULT
copy_sample(IMediaSample
*inputSample
, IMemAllocator
*allocator
, IMediaSample
**pOutputSample
)
306 REFERENCE_TIME startTime
, endTime
;
307 BOOL haveStartTime
= TRUE
, haveEndTime
= TRUE
;
308 IMediaSample
*outputSample
= NULL
;
309 BYTE
*ptrIn
, *ptrOut
;
310 AM_MEDIA_TYPE
*mediaType
= NULL
;
313 hr
= IMediaSample_GetTime(inputSample
, &startTime
, &endTime
);
316 else if (hr
== VFW_S_NO_STOP_TIME
)
318 else if (hr
== VFW_E_SAMPLE_TIME_NOT_SET
)
319 haveStartTime
= haveEndTime
= FALSE
;
323 hr
= IMemAllocator_GetBuffer(allocator
, &outputSample
,
324 haveStartTime
? &startTime
: NULL
, haveEndTime
? &endTime
: NULL
, 0);
325 if (FAILED(hr
)) goto end
;
326 if (IMediaSample_GetSize(outputSample
) < IMediaSample_GetActualDataLength(inputSample
)) {
327 ERR("insufficient space in sample\n");
328 hr
= VFW_E_BUFFER_OVERFLOW
;
332 hr
= IMediaSample_SetTime(outputSample
, haveStartTime
? &startTime
: NULL
, haveEndTime
? &endTime
: NULL
);
333 if (FAILED(hr
)) goto end
;
335 hr
= IMediaSample_GetPointer(inputSample
, &ptrIn
);
336 if (FAILED(hr
)) goto end
;
337 hr
= IMediaSample_GetPointer(outputSample
, &ptrOut
);
338 if (FAILED(hr
)) goto end
;
339 memcpy(ptrOut
, ptrIn
, IMediaSample_GetActualDataLength(inputSample
));
340 IMediaSample_SetActualDataLength(outputSample
, IMediaSample_GetActualDataLength(inputSample
));
342 hr
= IMediaSample_SetDiscontinuity(outputSample
, IMediaSample_IsDiscontinuity(inputSample
) == S_OK
);
343 if (FAILED(hr
)) goto end
;
345 haveStartTime
= haveEndTime
= TRUE
;
346 hr
= IMediaSample_GetMediaTime(inputSample
, &startTime
, &endTime
);
349 else if (hr
== VFW_S_NO_STOP_TIME
)
351 else if (hr
== VFW_E_MEDIA_TIME_NOT_SET
)
352 haveStartTime
= haveEndTime
= FALSE
;
355 hr
= IMediaSample_SetMediaTime(outputSample
, haveStartTime
? &startTime
: NULL
, haveEndTime
? &endTime
: NULL
);
356 if (FAILED(hr
)) goto end
;
358 hr
= IMediaSample_GetMediaType(inputSample
, &mediaType
);
359 if (FAILED(hr
)) goto end
;
361 hr
= IMediaSample_SetMediaType(outputSample
, mediaType
);
362 if (FAILED(hr
)) goto end
;
365 hr
= IMediaSample_SetPreroll(outputSample
, IMediaSample_IsPreroll(inputSample
) == S_OK
);
366 if (FAILED(hr
)) goto end
;
368 hr
= IMediaSample_SetSyncPoint(outputSample
, IMediaSample_IsSyncPoint(inputSample
) == S_OK
);
369 if (FAILED(hr
)) goto end
;
373 DeleteMediaType(mediaType
);
374 if (FAILED(hr
) && outputSample
) {
375 IMediaSample_Release(outputSample
);
378 *pOutputSample
= outputSample
;
382 static HRESULT WINAPI
SmartTeeFilterInput_Receive(BaseInputPin
*base
, IMediaSample
*inputSample
)
384 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
385 IMediaSample
*captureSample
= NULL
;
386 IMediaSample
*previewSample
= NULL
;
387 HRESULT hrCapture
= VFW_E_NOT_CONNECTED
, hrPreview
= VFW_E_NOT_CONNECTED
;
389 TRACE("(%p)->(%p)\n", This
, inputSample
);
391 /* Modifying the image coming out of one pin doesn't modify the image
392 * coming out of the other. MSDN claims the filter doesn't copy,
393 * but unless it somehow uses copy-on-write, I just don't see how
394 * that's possible. */
396 /* FIXME: we should ideally do each of these in a separate thread */
397 EnterCriticalSection(&This
->filter
.csFilter
);
398 if (This
->capture
->pin
.pConnectedTo
)
399 hrCapture
= copy_sample(inputSample
, This
->capture
->pAllocator
, &captureSample
);
400 LeaveCriticalSection(&This
->filter
.csFilter
);
401 if (SUCCEEDED(hrCapture
))
402 hrCapture
= BaseOutputPinImpl_Deliver(This
->capture
, captureSample
);
404 IMediaSample_Release(captureSample
);
406 EnterCriticalSection(&This
->filter
.csFilter
);
407 if (This
->preview
->pin
.pConnectedTo
)
408 hrPreview
= copy_sample(inputSample
, This
->preview
->pAllocator
, &previewSample
);
409 LeaveCriticalSection(&This
->filter
.csFilter
);
410 /* No timestamps on preview stream: */
411 if (SUCCEEDED(hrPreview
))
412 hrPreview
= IMediaSample_SetTime(previewSample
, NULL
, NULL
);
413 if (SUCCEEDED(hrPreview
))
414 hrPreview
= BaseOutputPinImpl_Deliver(This
->preview
, previewSample
);
416 IMediaSample_Release(previewSample
);
418 /* FIXME: how to merge the HRESULTs from the 2 pins? */
419 if (SUCCEEDED(hrCapture
))
425 static const BaseInputPinFuncTable SmartTeeFilterInputFuncs
= {
427 SmartTeeFilterInput_CheckMediaType
,
429 SmartTeeFilterInput_GetMediaTypeVersion
,
430 SmartTeeFilterInput_GetMediaType
432 SmartTeeFilterInput_Receive
435 static ULONG WINAPI
SmartTeeFilterCapture_AddRef(IPin
*iface
)
437 SmartTeeFilter
*This
= impl_from_IPin(iface
);
438 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
441 static ULONG WINAPI
SmartTeeFilterCapture_Release(IPin
*iface
)
443 SmartTeeFilter
*This
= impl_from_IPin(iface
);
444 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
447 static HRESULT WINAPI
SmartTeeFilterCapture_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**ppEnum
)
449 SmartTeeFilter
*This
= impl_from_IPin(iface
);
451 TRACE("(%p)->(%p)\n", This
, ppEnum
);
452 EnterCriticalSection(&This
->filter
.csFilter
);
453 if (This
->input
->pin
.pConnectedTo
) {
454 hr
= BasePinImpl_EnumMediaTypes(iface
, ppEnum
);
456 hr
= VFW_E_NOT_CONNECTED
;
457 LeaveCriticalSection(&This
->filter
.csFilter
);
461 static const IPinVtbl SmartTeeFilterCaptureVtbl
= {
462 BaseOutputPinImpl_QueryInterface
,
463 SmartTeeFilterCapture_AddRef
,
464 SmartTeeFilterCapture_Release
,
465 BaseOutputPinImpl_Connect
,
466 BaseOutputPinImpl_ReceiveConnection
,
467 BaseOutputPinImpl_Disconnect
,
468 BasePinImpl_ConnectedTo
,
469 BasePinImpl_ConnectionMediaType
,
470 BasePinImpl_QueryPinInfo
,
471 BasePinImpl_QueryDirection
,
473 BasePinImpl_QueryAccept
,
474 SmartTeeFilterCapture_EnumMediaTypes
,
475 BasePinImpl_QueryInternalConnections
,
476 BaseOutputPinImpl_EndOfStream
,
477 BaseOutputPinImpl_BeginFlush
,
478 BaseOutputPinImpl_EndFlush
,
479 BasePinImpl_NewSegment
482 static HRESULT WINAPI
SmartTeeFilterCapture_CheckMediaType(BasePin
*base
, const AM_MEDIA_TYPE
*amt
)
484 FIXME("(%p) stub\n", base
);
488 static LONG WINAPI
SmartTeeFilterCapture_GetMediaTypeVersion(BasePin
*base
)
490 SmartTeeFilter
*This
= impl_from_BasePin(base
);
491 TRACE("(%p)\n", This
);
495 static HRESULT WINAPI
SmartTeeFilterCapture_GetMediaType(BasePin
*base
, int iPosition
, AM_MEDIA_TYPE
*amt
)
497 SmartTeeFilter
*This
= impl_from_BasePin(base
);
498 TRACE("(%p, %d, %p)\n", This
, iPosition
, amt
);
499 if (iPosition
== 0) {
500 CopyMediaType(amt
, &This
->input
->pin
.mtCurrent
);
506 static HRESULT WINAPI
SmartTeeFilterCapture_DecideAllocator(BaseOutputPin
*base
, IMemInputPin
*pPin
, IMemAllocator
**pAlloc
)
508 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
509 TRACE("(%p, %p, %p)\n", This
, pPin
, pAlloc
);
510 *pAlloc
= This
->input
->pAllocator
;
511 IMemAllocator_AddRef(This
->input
->pAllocator
);
512 return IMemInputPin_NotifyAllocator(pPin
, This
->input
->pAllocator
, TRUE
);
515 static HRESULT WINAPI
SmartTeeFilterCapture_BreakConnect(BaseOutputPin
*base
)
517 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
518 FIXME("(%p): stub\n", This
);
522 static const BaseOutputPinFuncTable SmartTeeFilterCaptureFuncs
= {
524 SmartTeeFilterCapture_CheckMediaType
,
525 BaseOutputPinImpl_AttemptConnection
,
526 SmartTeeFilterCapture_GetMediaTypeVersion
,
527 SmartTeeFilterCapture_GetMediaType
530 SmartTeeFilterCapture_DecideAllocator
,
531 SmartTeeFilterCapture_BreakConnect
534 static ULONG WINAPI
SmartTeeFilterPreview_AddRef(IPin
*iface
)
536 SmartTeeFilter
*This
= impl_from_IPin(iface
);
537 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
540 static ULONG WINAPI
SmartTeeFilterPreview_Release(IPin
*iface
)
542 SmartTeeFilter
*This
= impl_from_IPin(iface
);
543 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
546 static HRESULT WINAPI
SmartTeeFilterPreview_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**ppEnum
)
548 SmartTeeFilter
*This
= impl_from_IPin(iface
);
550 TRACE("(%p)->(%p)\n", This
, ppEnum
);
551 EnterCriticalSection(&This
->filter
.csFilter
);
552 if (This
->input
->pin
.pConnectedTo
) {
553 hr
= BasePinImpl_EnumMediaTypes(iface
, ppEnum
);
555 hr
= VFW_E_NOT_CONNECTED
;
556 LeaveCriticalSection(&This
->filter
.csFilter
);
560 static const IPinVtbl SmartTeeFilterPreviewVtbl
= {
561 BaseOutputPinImpl_QueryInterface
,
562 SmartTeeFilterPreview_AddRef
,
563 SmartTeeFilterPreview_Release
,
564 BaseOutputPinImpl_Connect
,
565 BaseOutputPinImpl_ReceiveConnection
,
566 BaseOutputPinImpl_Disconnect
,
567 BasePinImpl_ConnectedTo
,
568 BasePinImpl_ConnectionMediaType
,
569 BasePinImpl_QueryPinInfo
,
570 BasePinImpl_QueryDirection
,
572 BasePinImpl_QueryAccept
,
573 SmartTeeFilterPreview_EnumMediaTypes
,
574 BasePinImpl_QueryInternalConnections
,
575 BaseOutputPinImpl_EndOfStream
,
576 BaseOutputPinImpl_BeginFlush
,
577 BaseOutputPinImpl_EndFlush
,
578 BasePinImpl_NewSegment
581 static HRESULT WINAPI
SmartTeeFilterPreview_CheckMediaType(BasePin
*base
, const AM_MEDIA_TYPE
*amt
)
583 FIXME("(%p) stub\n", base
);
587 static LONG WINAPI
SmartTeeFilterPreview_GetMediaTypeVersion(BasePin
*base
)
589 SmartTeeFilter
*This
= impl_from_BasePin(base
);
590 TRACE("(%p)\n", This
);
594 static HRESULT WINAPI
SmartTeeFilterPreview_GetMediaType(BasePin
*base
, int iPosition
, AM_MEDIA_TYPE
*amt
)
596 SmartTeeFilter
*This
= impl_from_BasePin(base
);
597 TRACE("(%p, %d, %p)\n", This
, iPosition
, amt
);
598 if (iPosition
== 0) {
599 CopyMediaType(amt
, &This
->input
->pin
.mtCurrent
);
605 static HRESULT WINAPI
SmartTeeFilterPreview_DecideAllocator(BaseOutputPin
*base
, IMemInputPin
*pPin
, IMemAllocator
**pAlloc
)
607 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
608 TRACE("(%p, %p, %p)\n", This
, pPin
, pAlloc
);
609 *pAlloc
= This
->input
->pAllocator
;
610 IMemAllocator_AddRef(This
->input
->pAllocator
);
611 return IMemInputPin_NotifyAllocator(pPin
, This
->input
->pAllocator
, TRUE
);
614 static HRESULT WINAPI
SmartTeeFilterPreview_BreakConnect(BaseOutputPin
*base
)
616 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
617 FIXME("(%p): stub\n", This
);
621 static const BaseOutputPinFuncTable SmartTeeFilterPreviewFuncs
= {
623 SmartTeeFilterPreview_CheckMediaType
,
624 BaseOutputPinImpl_AttemptConnection
,
625 SmartTeeFilterPreview_GetMediaTypeVersion
,
626 SmartTeeFilterPreview_GetMediaType
629 SmartTeeFilterPreview_DecideAllocator
,
630 SmartTeeFilterPreview_BreakConnect
632 IUnknown
* WINAPI
QCAP_createSmartTeeFilter(IUnknown
*outer
, HRESULT
*phr
)
634 PIN_INFO inputPinInfo
= {NULL
, PINDIR_INPUT
, {'I','n','p','u','t',0}};
635 PIN_INFO capturePinInfo
= {NULL
, PINDIR_OUTPUT
, {'C','a','p','t','u','r','e',0}};
636 PIN_INFO previewPinInfo
= {NULL
, PINDIR_OUTPUT
, {'P','r','e','v','i','e','w',0}};
638 SmartTeeFilter
*This
= NULL
;
640 TRACE("(%p, %p)\n", outer
, phr
);
642 This
= CoTaskMemAlloc(sizeof(*This
));
647 memset(This
, 0, sizeof(*This
));
648 This
->IUnknown_iface
.lpVtbl
= &UnknownVtbl
;
650 This
->outerUnknown
= outer
;
652 This
->outerUnknown
= &This
->IUnknown_iface
;
654 BaseFilter_Init(&This
->filter
, &SmartTeeFilterVtbl
, &CLSID_SmartTee
,
655 (DWORD_PTR
)(__FILE__
": SmartTeeFilter.csFilter"), &SmartTeeFilterFuncs
);
657 inputPinInfo
.pFilter
= &This
->filter
.IBaseFilter_iface
;
658 hr
= BaseInputPin_Construct(&SmartTeeFilterInputVtbl
, sizeof(BaseInputPin
), &inputPinInfo
,
659 &SmartTeeFilterInputFuncs
, &This
->filter
.csFilter
, NULL
, (IPin
**)&This
->input
);
662 hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
,
663 &IID_IMemAllocator
, (void**)&This
->input
->pAllocator
);
667 capturePinInfo
.pFilter
= &This
->filter
.IBaseFilter_iface
;
668 hr
= BaseOutputPin_Construct(&SmartTeeFilterCaptureVtbl
, sizeof(BaseOutputPin
), &capturePinInfo
,
669 &SmartTeeFilterCaptureFuncs
, &This
->filter
.csFilter
, (IPin
**)&This
->capture
);
673 previewPinInfo
.pFilter
= &This
->filter
.IBaseFilter_iface
;
674 hr
= BaseOutputPin_Construct(&SmartTeeFilterPreviewVtbl
, sizeof(BaseOutputPin
), &previewPinInfo
,
675 &SmartTeeFilterPreviewFuncs
, &This
->filter
.csFilter
, (IPin
**)&This
->preview
);
681 return &This
->IUnknown_iface
;
683 return (IUnknown
*)&This
->filter
.IBaseFilter_iface
;
686 IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);