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 if(This
->filter
.state
!= State_Stopped
) {
153 This
->filter
.state
= State_Stopped
;
155 LeaveCriticalSection(&This
->filter
.csFilter
);
159 static HRESULT WINAPI
SmartTeeFilter_Pause(IBaseFilter
*iface
)
161 SmartTeeFilter
*This
= impl_from_IBaseFilter(iface
);
162 FIXME("(%p): stub\n", This
);
166 static HRESULT WINAPI
SmartTeeFilter_Run(IBaseFilter
*iface
, REFERENCE_TIME tStart
)
168 SmartTeeFilter
*This
= impl_from_IBaseFilter(iface
);
170 TRACE("(%p, %x%08x)\n", This
, (ULONG
)(tStart
>> 32), (ULONG
)tStart
);
171 EnterCriticalSection(&This
->filter
.csFilter
);
172 if(This
->filter
.state
!= State_Running
) {
173 /* We share an allocator among all pins, an allocator can only get committed
174 * once, state transitions occur in upstream order, and only output pins
175 * commit allocators, so let the filter attached to the input pin worry about it. */
176 if (This
->input
->pin
.pConnectedTo
)
177 This
->filter
.state
= State_Running
;
179 hr
= VFW_E_NOT_CONNECTED
;
181 LeaveCriticalSection(&This
->filter
.csFilter
);
185 static HRESULT WINAPI
SmartTeeFilter_FindPin(IBaseFilter
*iface
, LPCWSTR Id
, IPin
**ppPin
)
187 SmartTeeFilter
*This
= impl_from_IBaseFilter(iface
);
188 TRACE("(%p)->(%s, %p)\n", This
, debugstr_w(Id
), ppPin
);
189 if (lstrcmpW(Id
, This
->input
->pin
.pinInfo
.achName
) == 0) {
190 *ppPin
= &This
->input
->pin
.IPin_iface
;
193 } else if (lstrcmpW(Id
, This
->capture
->pin
.pinInfo
.achName
) == 0) {
194 *ppPin
= &This
->capture
->pin
.IPin_iface
;
197 } else if (lstrcmpW(Id
, This
->preview
->pin
.pinInfo
.achName
) == 0) {
198 *ppPin
= &This
->preview
->pin
.IPin_iface
;
202 return VFW_E_NOT_FOUND
;
205 static const IBaseFilterVtbl SmartTeeFilterVtbl
= {
206 SmartTeeFilter_QueryInterface
,
207 SmartTeeFilter_AddRef
,
208 SmartTeeFilter_Release
,
209 BaseFilterImpl_GetClassID
,
211 SmartTeeFilter_Pause
,
213 BaseFilterImpl_GetState
,
214 BaseFilterImpl_SetSyncSource
,
215 BaseFilterImpl_GetSyncSource
,
216 BaseFilterImpl_EnumPins
,
217 SmartTeeFilter_FindPin
,
218 BaseFilterImpl_QueryFilterInfo
,
219 BaseFilterImpl_JoinFilterGraph
,
220 BaseFilterImpl_QueryVendorInfo
223 static IPin
* WINAPI
SmartTeeFilter_GetPin(BaseFilter
*iface
, int pos
)
225 SmartTeeFilter
*This
= impl_from_BaseFilter(iface
);
228 TRACE("(%p)->(%d)\n", This
, pos
);
232 ret
= &This
->input
->pin
.IPin_iface
;
235 ret
= &This
->capture
->pin
.IPin_iface
;
238 ret
= &This
->preview
->pin
.IPin_iface
;
241 TRACE("No pin %d\n", pos
);
249 static LONG WINAPI
SmartTeeFilter_GetPinCount(BaseFilter
*iface
)
253 static const BaseFilterFuncTable SmartTeeFilterFuncs
= {
254 SmartTeeFilter_GetPin
,
255 SmartTeeFilter_GetPinCount
258 static ULONG WINAPI
SmartTeeFilterInput_AddRef(IPin
*iface
)
260 SmartTeeFilter
*This
= impl_from_IPin(iface
);
261 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
264 static ULONG WINAPI
SmartTeeFilterInput_Release(IPin
*iface
)
266 SmartTeeFilter
*This
= impl_from_IPin(iface
);
267 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
271 static const IPinVtbl SmartTeeFilterInputVtbl
= {
272 BaseInputPinImpl_QueryInterface
,
273 SmartTeeFilterInput_AddRef
,
274 SmartTeeFilterInput_Release
,
275 BaseInputPinImpl_Connect
,
276 BaseInputPinImpl_ReceiveConnection
,
277 BasePinImpl_Disconnect
,
278 BasePinImpl_ConnectedTo
,
279 BasePinImpl_ConnectionMediaType
,
280 BasePinImpl_QueryPinInfo
,
281 BasePinImpl_QueryDirection
,
283 BasePinImpl_QueryAccept
,
284 BasePinImpl_EnumMediaTypes
,
285 BasePinImpl_QueryInternalConnections
,
286 BaseInputPinImpl_EndOfStream
,
287 BaseInputPinImpl_BeginFlush
,
288 BaseInputPinImpl_EndFlush
,
289 BaseInputPinImpl_NewSegment
292 static HRESULT WINAPI
SmartTeeFilterInput_CheckMediaType(BasePin
*base
, const AM_MEDIA_TYPE
*pmt
)
294 SmartTeeFilter
*This
= impl_from_BasePin(base
);
295 TRACE("(%p, AM_MEDIA_TYPE(%p))\n", This
, pmt
);
296 dump_AM_MEDIA_TYPE(pmt
);
298 return VFW_E_TYPE_NOT_ACCEPTED
;
299 /* We'll take any media type, but the output pins will later
300 * struggle to connect downstream. */
304 static LONG WINAPI
SmartTeeFilterInput_GetMediaTypeVersion(BasePin
*base
)
309 static HRESULT WINAPI
SmartTeeFilterInput_GetMediaType(BasePin
*base
, int iPosition
, AM_MEDIA_TYPE
*amt
)
311 SmartTeeFilter
*This
= impl_from_BasePin(base
);
313 TRACE("(%p)->(%d, %p)\n", This
, iPosition
, amt
);
316 EnterCriticalSection(&This
->filter
.csFilter
);
317 if (This
->input
->pin
.pConnectedTo
) {
318 CopyMediaType(amt
, &This
->input
->pin
.mtCurrent
);
322 LeaveCriticalSection(&This
->filter
.csFilter
);
326 static HRESULT
copy_sample(IMediaSample
*inputSample
, IMemAllocator
*allocator
, IMediaSample
**pOutputSample
)
328 REFERENCE_TIME startTime
, endTime
;
329 BOOL haveStartTime
= TRUE
, haveEndTime
= TRUE
;
330 IMediaSample
*outputSample
= NULL
;
331 BYTE
*ptrIn
, *ptrOut
;
332 AM_MEDIA_TYPE
*mediaType
= NULL
;
335 hr
= IMediaSample_GetTime(inputSample
, &startTime
, &endTime
);
338 else if (hr
== VFW_S_NO_STOP_TIME
)
340 else if (hr
== VFW_E_SAMPLE_TIME_NOT_SET
)
341 haveStartTime
= haveEndTime
= FALSE
;
345 hr
= IMemAllocator_GetBuffer(allocator
, &outputSample
,
346 haveStartTime
? &startTime
: NULL
, haveEndTime
? &endTime
: NULL
, 0);
347 if (FAILED(hr
)) goto end
;
348 if (IMediaSample_GetSize(outputSample
) < IMediaSample_GetActualDataLength(inputSample
)) {
349 ERR("insufficient space in sample\n");
350 hr
= VFW_E_BUFFER_OVERFLOW
;
354 hr
= IMediaSample_SetTime(outputSample
, haveStartTime
? &startTime
: NULL
, haveEndTime
? &endTime
: NULL
);
355 if (FAILED(hr
)) goto end
;
357 hr
= IMediaSample_GetPointer(inputSample
, &ptrIn
);
358 if (FAILED(hr
)) goto end
;
359 hr
= IMediaSample_GetPointer(outputSample
, &ptrOut
);
360 if (FAILED(hr
)) goto end
;
361 memcpy(ptrOut
, ptrIn
, IMediaSample_GetActualDataLength(inputSample
));
362 IMediaSample_SetActualDataLength(outputSample
, IMediaSample_GetActualDataLength(inputSample
));
364 hr
= IMediaSample_SetDiscontinuity(outputSample
, IMediaSample_IsDiscontinuity(inputSample
) == S_OK
);
365 if (FAILED(hr
)) goto end
;
367 haveStartTime
= haveEndTime
= TRUE
;
368 hr
= IMediaSample_GetMediaTime(inputSample
, &startTime
, &endTime
);
371 else if (hr
== VFW_S_NO_STOP_TIME
)
373 else if (hr
== VFW_E_MEDIA_TIME_NOT_SET
)
374 haveStartTime
= haveEndTime
= FALSE
;
377 hr
= IMediaSample_SetMediaTime(outputSample
, haveStartTime
? &startTime
: NULL
, haveEndTime
? &endTime
: NULL
);
378 if (FAILED(hr
)) goto end
;
380 hr
= IMediaSample_GetMediaType(inputSample
, &mediaType
);
381 if (FAILED(hr
)) goto end
;
383 hr
= IMediaSample_SetMediaType(outputSample
, mediaType
);
384 if (FAILED(hr
)) goto end
;
387 hr
= IMediaSample_SetPreroll(outputSample
, IMediaSample_IsPreroll(inputSample
) == S_OK
);
388 if (FAILED(hr
)) goto end
;
390 hr
= IMediaSample_SetSyncPoint(outputSample
, IMediaSample_IsSyncPoint(inputSample
) == S_OK
);
391 if (FAILED(hr
)) goto end
;
395 DeleteMediaType(mediaType
);
396 if (FAILED(hr
) && outputSample
) {
397 IMediaSample_Release(outputSample
);
400 *pOutputSample
= outputSample
;
404 static HRESULT WINAPI
SmartTeeFilterInput_Receive(BaseInputPin
*base
, IMediaSample
*inputSample
)
406 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
407 IMediaSample
*captureSample
= NULL
;
408 IMediaSample
*previewSample
= NULL
;
409 HRESULT hrCapture
= VFW_E_NOT_CONNECTED
, hrPreview
= VFW_E_NOT_CONNECTED
;
411 TRACE("(%p)->(%p)\n", This
, inputSample
);
413 /* Modifying the image coming out of one pin doesn't modify the image
414 * coming out of the other. MSDN claims the filter doesn't copy,
415 * but unless it somehow uses copy-on-write, I just don't see how
416 * that's possible. */
418 /* FIXME: we should ideally do each of these in a separate thread */
419 EnterCriticalSection(&This
->filter
.csFilter
);
420 if (This
->capture
->pin
.pConnectedTo
)
421 hrCapture
= copy_sample(inputSample
, This
->capture
->pAllocator
, &captureSample
);
422 LeaveCriticalSection(&This
->filter
.csFilter
);
423 if (SUCCEEDED(hrCapture
))
424 hrCapture
= BaseOutputPinImpl_Deliver(This
->capture
, captureSample
);
426 IMediaSample_Release(captureSample
);
428 EnterCriticalSection(&This
->filter
.csFilter
);
429 if (This
->preview
->pin
.pConnectedTo
)
430 hrPreview
= copy_sample(inputSample
, This
->preview
->pAllocator
, &previewSample
);
431 LeaveCriticalSection(&This
->filter
.csFilter
);
432 /* No timestamps on preview stream: */
433 if (SUCCEEDED(hrPreview
))
434 hrPreview
= IMediaSample_SetTime(previewSample
, NULL
, NULL
);
435 if (SUCCEEDED(hrPreview
))
436 hrPreview
= BaseOutputPinImpl_Deliver(This
->preview
, previewSample
);
438 IMediaSample_Release(previewSample
);
440 /* FIXME: how to merge the HRESULTs from the 2 pins? */
441 if (SUCCEEDED(hrCapture
))
447 static const BaseInputPinFuncTable SmartTeeFilterInputFuncs
= {
449 SmartTeeFilterInput_CheckMediaType
,
451 SmartTeeFilterInput_GetMediaTypeVersion
,
452 SmartTeeFilterInput_GetMediaType
454 SmartTeeFilterInput_Receive
457 static ULONG WINAPI
SmartTeeFilterCapture_AddRef(IPin
*iface
)
459 SmartTeeFilter
*This
= impl_from_IPin(iface
);
460 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
463 static ULONG WINAPI
SmartTeeFilterCapture_Release(IPin
*iface
)
465 SmartTeeFilter
*This
= impl_from_IPin(iface
);
466 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
469 static HRESULT WINAPI
SmartTeeFilterCapture_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**ppEnum
)
471 SmartTeeFilter
*This
= impl_from_IPin(iface
);
473 TRACE("(%p)->(%p)\n", This
, ppEnum
);
474 EnterCriticalSection(&This
->filter
.csFilter
);
475 if (This
->input
->pin
.pConnectedTo
) {
476 hr
= BasePinImpl_EnumMediaTypes(iface
, ppEnum
);
478 hr
= VFW_E_NOT_CONNECTED
;
479 LeaveCriticalSection(&This
->filter
.csFilter
);
483 static const IPinVtbl SmartTeeFilterCaptureVtbl
= {
484 BaseOutputPinImpl_QueryInterface
,
485 SmartTeeFilterCapture_AddRef
,
486 SmartTeeFilterCapture_Release
,
487 BaseOutputPinImpl_Connect
,
488 BaseOutputPinImpl_ReceiveConnection
,
489 BaseOutputPinImpl_Disconnect
,
490 BasePinImpl_ConnectedTo
,
491 BasePinImpl_ConnectionMediaType
,
492 BasePinImpl_QueryPinInfo
,
493 BasePinImpl_QueryDirection
,
495 BasePinImpl_QueryAccept
,
496 SmartTeeFilterCapture_EnumMediaTypes
,
497 BasePinImpl_QueryInternalConnections
,
498 BaseOutputPinImpl_EndOfStream
,
499 BaseOutputPinImpl_BeginFlush
,
500 BaseOutputPinImpl_EndFlush
,
501 BasePinImpl_NewSegment
504 static LONG WINAPI
SmartTeeFilterCapture_GetMediaTypeVersion(BasePin
*base
)
506 SmartTeeFilter
*This
= impl_from_BasePin(base
);
507 TRACE("(%p)\n", This
);
511 static HRESULT WINAPI
SmartTeeFilterCapture_GetMediaType(BasePin
*base
, int iPosition
, AM_MEDIA_TYPE
*amt
)
513 SmartTeeFilter
*This
= impl_from_BasePin(base
);
514 TRACE("(%p, %d, %p)\n", This
, iPosition
, amt
);
515 if (iPosition
== 0) {
516 CopyMediaType(amt
, &This
->input
->pin
.mtCurrent
);
522 static HRESULT WINAPI
SmartTeeFilterCapture_DecideAllocator(BaseOutputPin
*base
, IMemInputPin
*pPin
, IMemAllocator
**pAlloc
)
524 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
525 TRACE("(%p, %p, %p)\n", This
, pPin
, pAlloc
);
526 *pAlloc
= This
->input
->pAllocator
;
527 IMemAllocator_AddRef(This
->input
->pAllocator
);
528 return IMemInputPin_NotifyAllocator(pPin
, This
->input
->pAllocator
, TRUE
);
531 static HRESULT WINAPI
SmartTeeFilterCapture_BreakConnect(BaseOutputPin
*base
)
533 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
534 FIXME("(%p): stub\n", This
);
538 static const BaseOutputPinFuncTable SmartTeeFilterCaptureFuncs
= {
541 BaseOutputPinImpl_AttemptConnection
,
542 SmartTeeFilterCapture_GetMediaTypeVersion
,
543 SmartTeeFilterCapture_GetMediaType
546 SmartTeeFilterCapture_DecideAllocator
,
547 SmartTeeFilterCapture_BreakConnect
550 static ULONG WINAPI
SmartTeeFilterPreview_AddRef(IPin
*iface
)
552 SmartTeeFilter
*This
= impl_from_IPin(iface
);
553 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
556 static ULONG WINAPI
SmartTeeFilterPreview_Release(IPin
*iface
)
558 SmartTeeFilter
*This
= impl_from_IPin(iface
);
559 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
562 static HRESULT WINAPI
SmartTeeFilterPreview_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**ppEnum
)
564 SmartTeeFilter
*This
= impl_from_IPin(iface
);
566 TRACE("(%p)->(%p)\n", This
, ppEnum
);
567 EnterCriticalSection(&This
->filter
.csFilter
);
568 if (This
->input
->pin
.pConnectedTo
) {
569 hr
= BasePinImpl_EnumMediaTypes(iface
, ppEnum
);
571 hr
= VFW_E_NOT_CONNECTED
;
572 LeaveCriticalSection(&This
->filter
.csFilter
);
576 static const IPinVtbl SmartTeeFilterPreviewVtbl
= {
577 BaseOutputPinImpl_QueryInterface
,
578 SmartTeeFilterPreview_AddRef
,
579 SmartTeeFilterPreview_Release
,
580 BaseOutputPinImpl_Connect
,
581 BaseOutputPinImpl_ReceiveConnection
,
582 BaseOutputPinImpl_Disconnect
,
583 BasePinImpl_ConnectedTo
,
584 BasePinImpl_ConnectionMediaType
,
585 BasePinImpl_QueryPinInfo
,
586 BasePinImpl_QueryDirection
,
588 BasePinImpl_QueryAccept
,
589 SmartTeeFilterPreview_EnumMediaTypes
,
590 BasePinImpl_QueryInternalConnections
,
591 BaseOutputPinImpl_EndOfStream
,
592 BaseOutputPinImpl_BeginFlush
,
593 BaseOutputPinImpl_EndFlush
,
594 BasePinImpl_NewSegment
597 static LONG WINAPI
SmartTeeFilterPreview_GetMediaTypeVersion(BasePin
*base
)
599 SmartTeeFilter
*This
= impl_from_BasePin(base
);
600 TRACE("(%p)\n", This
);
604 static HRESULT WINAPI
SmartTeeFilterPreview_GetMediaType(BasePin
*base
, int iPosition
, AM_MEDIA_TYPE
*amt
)
606 SmartTeeFilter
*This
= impl_from_BasePin(base
);
607 TRACE("(%p, %d, %p)\n", This
, iPosition
, amt
);
608 if (iPosition
== 0) {
609 CopyMediaType(amt
, &This
->input
->pin
.mtCurrent
);
615 static HRESULT WINAPI
SmartTeeFilterPreview_DecideAllocator(BaseOutputPin
*base
, IMemInputPin
*pPin
, IMemAllocator
**pAlloc
)
617 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
618 TRACE("(%p, %p, %p)\n", This
, pPin
, pAlloc
);
619 *pAlloc
= This
->input
->pAllocator
;
620 IMemAllocator_AddRef(This
->input
->pAllocator
);
621 return IMemInputPin_NotifyAllocator(pPin
, This
->input
->pAllocator
, TRUE
);
624 static HRESULT WINAPI
SmartTeeFilterPreview_BreakConnect(BaseOutputPin
*base
)
626 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
627 FIXME("(%p): stub\n", This
);
631 static const BaseOutputPinFuncTable SmartTeeFilterPreviewFuncs
= {
634 BaseOutputPinImpl_AttemptConnection
,
635 SmartTeeFilterPreview_GetMediaTypeVersion
,
636 SmartTeeFilterPreview_GetMediaType
639 SmartTeeFilterPreview_DecideAllocator
,
640 SmartTeeFilterPreview_BreakConnect
642 IUnknown
* WINAPI
QCAP_createSmartTeeFilter(IUnknown
*outer
, HRESULT
*phr
)
644 PIN_INFO inputPinInfo
= {NULL
, PINDIR_INPUT
, {'I','n','p','u','t',0}};
645 PIN_INFO capturePinInfo
= {NULL
, PINDIR_OUTPUT
, {'C','a','p','t','u','r','e',0}};
646 PIN_INFO previewPinInfo
= {NULL
, PINDIR_OUTPUT
, {'P','r','e','v','i','e','w',0}};
648 SmartTeeFilter
*This
= NULL
;
650 TRACE("(%p, %p)\n", outer
, phr
);
652 This
= CoTaskMemAlloc(sizeof(*This
));
657 memset(This
, 0, sizeof(*This
));
658 This
->IUnknown_iface
.lpVtbl
= &UnknownVtbl
;
660 This
->outerUnknown
= outer
;
662 This
->outerUnknown
= &This
->IUnknown_iface
;
664 BaseFilter_Init(&This
->filter
, &SmartTeeFilterVtbl
, &CLSID_SmartTee
,
665 (DWORD_PTR
)(__FILE__
": SmartTeeFilter.csFilter"), &SmartTeeFilterFuncs
);
667 inputPinInfo
.pFilter
= &This
->filter
.IBaseFilter_iface
;
668 hr
= BaseInputPin_Construct(&SmartTeeFilterInputVtbl
, sizeof(BaseInputPin
), &inputPinInfo
,
669 &SmartTeeFilterInputFuncs
, &This
->filter
.csFilter
, NULL
, (IPin
**)&This
->input
);
672 hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
,
673 &IID_IMemAllocator
, (void**)&This
->input
->pAllocator
);
677 capturePinInfo
.pFilter
= &This
->filter
.IBaseFilter_iface
;
678 hr
= BaseOutputPin_Construct(&SmartTeeFilterCaptureVtbl
, sizeof(BaseOutputPin
), &capturePinInfo
,
679 &SmartTeeFilterCaptureFuncs
, &This
->filter
.csFilter
, (IPin
**)&This
->capture
);
683 previewPinInfo
.pFilter
= &This
->filter
.IBaseFilter_iface
;
684 hr
= BaseOutputPin_Construct(&SmartTeeFilterPreviewVtbl
, sizeof(BaseOutputPin
), &previewPinInfo
,
685 &SmartTeeFilterPreviewFuncs
, &This
->filter
.csFilter
, (IPin
**)&This
->preview
);
691 return &This
->IUnknown_iface
;
693 return (IUnknown
*)&This
->filter
.IBaseFilter_iface
;
696 IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);