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 HRESULT WINAPI
SmartTeeFilter_FindPin(IBaseFilter
*iface
, LPCWSTR Id
, IPin
**ppPin
)
185 SmartTeeFilter
*This
= impl_from_IBaseFilter(iface
);
186 TRACE("(%p)->(%s, %p)\n", This
, debugstr_w(Id
), ppPin
);
187 if (lstrcmpW(Id
, This
->input
->pin
.pinInfo
.achName
) == 0) {
188 *ppPin
= &This
->input
->pin
.IPin_iface
;
191 } else if (lstrcmpW(Id
, This
->capture
->pin
.pinInfo
.achName
) == 0) {
192 *ppPin
= &This
->capture
->pin
.IPin_iface
;
195 } else if (lstrcmpW(Id
, This
->preview
->pin
.pinInfo
.achName
) == 0) {
196 *ppPin
= &This
->preview
->pin
.IPin_iface
;
200 return VFW_E_NOT_FOUND
;
203 static const IBaseFilterVtbl SmartTeeFilterVtbl
= {
204 SmartTeeFilter_QueryInterface
,
205 SmartTeeFilter_AddRef
,
206 SmartTeeFilter_Release
,
207 BaseFilterImpl_GetClassID
,
209 SmartTeeFilter_Pause
,
211 BaseFilterImpl_GetState
,
212 BaseFilterImpl_SetSyncSource
,
213 BaseFilterImpl_GetSyncSource
,
214 BaseFilterImpl_EnumPins
,
215 SmartTeeFilter_FindPin
,
216 BaseFilterImpl_QueryFilterInfo
,
217 BaseFilterImpl_JoinFilterGraph
,
218 BaseFilterImpl_QueryVendorInfo
221 static IPin
* WINAPI
SmartTeeFilter_GetPin(BaseFilter
*iface
, int pos
)
223 SmartTeeFilter
*This
= impl_from_BaseFilter(iface
);
226 TRACE("(%p)->(%d)\n", This
, pos
);
230 ret
= &This
->input
->pin
.IPin_iface
;
233 ret
= &This
->capture
->pin
.IPin_iface
;
236 ret
= &This
->preview
->pin
.IPin_iface
;
239 TRACE("No pin %d\n", pos
);
247 static LONG WINAPI
SmartTeeFilter_GetPinCount(BaseFilter
*iface
)
251 static const BaseFilterFuncTable SmartTeeFilterFuncs
= {
252 SmartTeeFilter_GetPin
,
253 SmartTeeFilter_GetPinCount
256 static ULONG WINAPI
SmartTeeFilterInput_AddRef(IPin
*iface
)
258 SmartTeeFilter
*This
= impl_from_IPin(iface
);
259 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
262 static ULONG WINAPI
SmartTeeFilterInput_Release(IPin
*iface
)
264 SmartTeeFilter
*This
= impl_from_IPin(iface
);
265 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
269 static const IPinVtbl SmartTeeFilterInputVtbl
= {
270 BaseInputPinImpl_QueryInterface
,
271 SmartTeeFilterInput_AddRef
,
272 SmartTeeFilterInput_Release
,
273 BaseInputPinImpl_Connect
,
274 BaseInputPinImpl_ReceiveConnection
,
275 BasePinImpl_Disconnect
,
276 BasePinImpl_ConnectedTo
,
277 BasePinImpl_ConnectionMediaType
,
278 BasePinImpl_QueryPinInfo
,
279 BasePinImpl_QueryDirection
,
281 BasePinImpl_QueryAccept
,
282 BasePinImpl_EnumMediaTypes
,
283 BasePinImpl_QueryInternalConnections
,
284 BaseInputPinImpl_EndOfStream
,
285 BaseInputPinImpl_BeginFlush
,
286 BaseInputPinImpl_EndFlush
,
287 BaseInputPinImpl_NewSegment
290 static HRESULT WINAPI
SmartTeeFilterInput_CheckMediaType(BasePin
*base
, const AM_MEDIA_TYPE
*pmt
)
292 SmartTeeFilter
*This
= impl_from_BasePin(base
);
293 TRACE("(%p, AM_MEDIA_TYPE(%p))\n", This
, pmt
);
294 dump_AM_MEDIA_TYPE(pmt
);
296 return VFW_E_TYPE_NOT_ACCEPTED
;
297 /* We'll take any media type, but the output pins will later
298 * struggle to connect downstream. */
302 static LONG WINAPI
SmartTeeFilterInput_GetMediaTypeVersion(BasePin
*base
)
307 static HRESULT WINAPI
SmartTeeFilterInput_GetMediaType(BasePin
*base
, int iPosition
, AM_MEDIA_TYPE
*amt
)
309 SmartTeeFilter
*This
= impl_from_BasePin(base
);
311 TRACE("(%p)->(%d, %p)\n", This
, iPosition
, amt
);
314 EnterCriticalSection(&This
->filter
.csFilter
);
315 if (This
->input
->pin
.pConnectedTo
) {
316 CopyMediaType(amt
, &This
->input
->pin
.mtCurrent
);
320 LeaveCriticalSection(&This
->filter
.csFilter
);
324 static HRESULT
copy_sample(IMediaSample
*inputSample
, IMemAllocator
*allocator
, IMediaSample
**pOutputSample
)
326 REFERENCE_TIME startTime
, endTime
;
327 BOOL haveStartTime
= TRUE
, haveEndTime
= TRUE
;
328 IMediaSample
*outputSample
= NULL
;
329 BYTE
*ptrIn
, *ptrOut
;
330 AM_MEDIA_TYPE
*mediaType
= NULL
;
333 hr
= IMediaSample_GetTime(inputSample
, &startTime
, &endTime
);
336 else if (hr
== VFW_S_NO_STOP_TIME
)
338 else if (hr
== VFW_E_SAMPLE_TIME_NOT_SET
)
339 haveStartTime
= haveEndTime
= FALSE
;
343 hr
= IMemAllocator_GetBuffer(allocator
, &outputSample
,
344 haveStartTime
? &startTime
: NULL
, haveEndTime
? &endTime
: NULL
, 0);
345 if (FAILED(hr
)) goto end
;
346 if (IMediaSample_GetSize(outputSample
) < IMediaSample_GetActualDataLength(inputSample
)) {
347 ERR("insufficient space in sample\n");
348 hr
= VFW_E_BUFFER_OVERFLOW
;
352 hr
= IMediaSample_SetTime(outputSample
, haveStartTime
? &startTime
: NULL
, haveEndTime
? &endTime
: NULL
);
353 if (FAILED(hr
)) goto end
;
355 hr
= IMediaSample_GetPointer(inputSample
, &ptrIn
);
356 if (FAILED(hr
)) goto end
;
357 hr
= IMediaSample_GetPointer(outputSample
, &ptrOut
);
358 if (FAILED(hr
)) goto end
;
359 memcpy(ptrOut
, ptrIn
, IMediaSample_GetActualDataLength(inputSample
));
360 IMediaSample_SetActualDataLength(outputSample
, IMediaSample_GetActualDataLength(inputSample
));
362 hr
= IMediaSample_SetDiscontinuity(outputSample
, IMediaSample_IsDiscontinuity(inputSample
) == S_OK
);
363 if (FAILED(hr
)) goto end
;
365 haveStartTime
= haveEndTime
= TRUE
;
366 hr
= IMediaSample_GetMediaTime(inputSample
, &startTime
, &endTime
);
369 else if (hr
== VFW_S_NO_STOP_TIME
)
371 else if (hr
== VFW_E_MEDIA_TIME_NOT_SET
)
372 haveStartTime
= haveEndTime
= FALSE
;
375 hr
= IMediaSample_SetMediaTime(outputSample
, haveStartTime
? &startTime
: NULL
, haveEndTime
? &endTime
: NULL
);
376 if (FAILED(hr
)) goto end
;
378 hr
= IMediaSample_GetMediaType(inputSample
, &mediaType
);
379 if (FAILED(hr
)) goto end
;
381 hr
= IMediaSample_SetMediaType(outputSample
, mediaType
);
382 if (FAILED(hr
)) goto end
;
385 hr
= IMediaSample_SetPreroll(outputSample
, IMediaSample_IsPreroll(inputSample
) == S_OK
);
386 if (FAILED(hr
)) goto end
;
388 hr
= IMediaSample_SetSyncPoint(outputSample
, IMediaSample_IsSyncPoint(inputSample
) == S_OK
);
389 if (FAILED(hr
)) goto end
;
393 DeleteMediaType(mediaType
);
394 if (FAILED(hr
) && outputSample
) {
395 IMediaSample_Release(outputSample
);
398 *pOutputSample
= outputSample
;
402 static HRESULT WINAPI
SmartTeeFilterInput_Receive(BaseInputPin
*base
, IMediaSample
*inputSample
)
404 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
405 IMediaSample
*captureSample
= NULL
;
406 IMediaSample
*previewSample
= NULL
;
407 HRESULT hrCapture
= VFW_E_NOT_CONNECTED
, hrPreview
= VFW_E_NOT_CONNECTED
;
409 TRACE("(%p)->(%p)\n", This
, inputSample
);
411 /* Modifying the image coming out of one pin doesn't modify the image
412 * coming out of the other. MSDN claims the filter doesn't copy,
413 * but unless it somehow uses copy-on-write, I just don't see how
414 * that's possible. */
416 /* FIXME: we should ideally do each of these in a separate thread */
417 EnterCriticalSection(&This
->filter
.csFilter
);
418 if (This
->capture
->pin
.pConnectedTo
)
419 hrCapture
= copy_sample(inputSample
, This
->capture
->pAllocator
, &captureSample
);
420 LeaveCriticalSection(&This
->filter
.csFilter
);
421 if (SUCCEEDED(hrCapture
))
422 hrCapture
= BaseOutputPinImpl_Deliver(This
->capture
, captureSample
);
424 IMediaSample_Release(captureSample
);
426 EnterCriticalSection(&This
->filter
.csFilter
);
427 if (This
->preview
->pin
.pConnectedTo
)
428 hrPreview
= copy_sample(inputSample
, This
->preview
->pAllocator
, &previewSample
);
429 LeaveCriticalSection(&This
->filter
.csFilter
);
430 /* No timestamps on preview stream: */
431 if (SUCCEEDED(hrPreview
))
432 hrPreview
= IMediaSample_SetTime(previewSample
, NULL
, NULL
);
433 if (SUCCEEDED(hrPreview
))
434 hrPreview
= BaseOutputPinImpl_Deliver(This
->preview
, previewSample
);
436 IMediaSample_Release(previewSample
);
438 /* FIXME: how to merge the HRESULTs from the 2 pins? */
439 if (SUCCEEDED(hrCapture
))
445 static const BaseInputPinFuncTable SmartTeeFilterInputFuncs
= {
447 SmartTeeFilterInput_CheckMediaType
,
449 SmartTeeFilterInput_GetMediaTypeVersion
,
450 SmartTeeFilterInput_GetMediaType
452 SmartTeeFilterInput_Receive
455 static ULONG WINAPI
SmartTeeFilterCapture_AddRef(IPin
*iface
)
457 SmartTeeFilter
*This
= impl_from_IPin(iface
);
458 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
461 static ULONG WINAPI
SmartTeeFilterCapture_Release(IPin
*iface
)
463 SmartTeeFilter
*This
= impl_from_IPin(iface
);
464 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
467 static HRESULT WINAPI
SmartTeeFilterCapture_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**ppEnum
)
469 SmartTeeFilter
*This
= impl_from_IPin(iface
);
471 TRACE("(%p)->(%p)\n", This
, ppEnum
);
472 EnterCriticalSection(&This
->filter
.csFilter
);
473 if (This
->input
->pin
.pConnectedTo
) {
474 hr
= BasePinImpl_EnumMediaTypes(iface
, ppEnum
);
476 hr
= VFW_E_NOT_CONNECTED
;
477 LeaveCriticalSection(&This
->filter
.csFilter
);
481 static const IPinVtbl SmartTeeFilterCaptureVtbl
= {
482 BaseOutputPinImpl_QueryInterface
,
483 SmartTeeFilterCapture_AddRef
,
484 SmartTeeFilterCapture_Release
,
485 BaseOutputPinImpl_Connect
,
486 BaseOutputPinImpl_ReceiveConnection
,
487 BaseOutputPinImpl_Disconnect
,
488 BasePinImpl_ConnectedTo
,
489 BasePinImpl_ConnectionMediaType
,
490 BasePinImpl_QueryPinInfo
,
491 BasePinImpl_QueryDirection
,
493 BasePinImpl_QueryAccept
,
494 SmartTeeFilterCapture_EnumMediaTypes
,
495 BasePinImpl_QueryInternalConnections
,
496 BaseOutputPinImpl_EndOfStream
,
497 BaseOutputPinImpl_BeginFlush
,
498 BaseOutputPinImpl_EndFlush
,
499 BasePinImpl_NewSegment
502 static HRESULT WINAPI
SmartTeeFilterCapture_CheckMediaType(BasePin
*base
, const AM_MEDIA_TYPE
*amt
)
504 FIXME("(%p) stub\n", base
);
508 static LONG WINAPI
SmartTeeFilterCapture_GetMediaTypeVersion(BasePin
*base
)
510 SmartTeeFilter
*This
= impl_from_BasePin(base
);
511 TRACE("(%p)\n", This
);
515 static HRESULT WINAPI
SmartTeeFilterCapture_GetMediaType(BasePin
*base
, int iPosition
, AM_MEDIA_TYPE
*amt
)
517 SmartTeeFilter
*This
= impl_from_BasePin(base
);
518 TRACE("(%p, %d, %p)\n", This
, iPosition
, amt
);
519 if (iPosition
== 0) {
520 CopyMediaType(amt
, &This
->input
->pin
.mtCurrent
);
526 static HRESULT WINAPI
SmartTeeFilterCapture_DecideAllocator(BaseOutputPin
*base
, IMemInputPin
*pPin
, IMemAllocator
**pAlloc
)
528 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
529 TRACE("(%p, %p, %p)\n", This
, pPin
, pAlloc
);
530 *pAlloc
= This
->input
->pAllocator
;
531 IMemAllocator_AddRef(This
->input
->pAllocator
);
532 return IMemInputPin_NotifyAllocator(pPin
, This
->input
->pAllocator
, TRUE
);
535 static HRESULT WINAPI
SmartTeeFilterCapture_BreakConnect(BaseOutputPin
*base
)
537 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
538 FIXME("(%p): stub\n", This
);
542 static const BaseOutputPinFuncTable SmartTeeFilterCaptureFuncs
= {
544 SmartTeeFilterCapture_CheckMediaType
,
545 BaseOutputPinImpl_AttemptConnection
,
546 SmartTeeFilterCapture_GetMediaTypeVersion
,
547 SmartTeeFilterCapture_GetMediaType
550 SmartTeeFilterCapture_DecideAllocator
,
551 SmartTeeFilterCapture_BreakConnect
554 static ULONG WINAPI
SmartTeeFilterPreview_AddRef(IPin
*iface
)
556 SmartTeeFilter
*This
= impl_from_IPin(iface
);
557 return IBaseFilter_AddRef(&This
->filter
.IBaseFilter_iface
);
560 static ULONG WINAPI
SmartTeeFilterPreview_Release(IPin
*iface
)
562 SmartTeeFilter
*This
= impl_from_IPin(iface
);
563 return IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);
566 static HRESULT WINAPI
SmartTeeFilterPreview_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**ppEnum
)
568 SmartTeeFilter
*This
= impl_from_IPin(iface
);
570 TRACE("(%p)->(%p)\n", This
, ppEnum
);
571 EnterCriticalSection(&This
->filter
.csFilter
);
572 if (This
->input
->pin
.pConnectedTo
) {
573 hr
= BasePinImpl_EnumMediaTypes(iface
, ppEnum
);
575 hr
= VFW_E_NOT_CONNECTED
;
576 LeaveCriticalSection(&This
->filter
.csFilter
);
580 static const IPinVtbl SmartTeeFilterPreviewVtbl
= {
581 BaseOutputPinImpl_QueryInterface
,
582 SmartTeeFilterPreview_AddRef
,
583 SmartTeeFilterPreview_Release
,
584 BaseOutputPinImpl_Connect
,
585 BaseOutputPinImpl_ReceiveConnection
,
586 BaseOutputPinImpl_Disconnect
,
587 BasePinImpl_ConnectedTo
,
588 BasePinImpl_ConnectionMediaType
,
589 BasePinImpl_QueryPinInfo
,
590 BasePinImpl_QueryDirection
,
592 BasePinImpl_QueryAccept
,
593 SmartTeeFilterPreview_EnumMediaTypes
,
594 BasePinImpl_QueryInternalConnections
,
595 BaseOutputPinImpl_EndOfStream
,
596 BaseOutputPinImpl_BeginFlush
,
597 BaseOutputPinImpl_EndFlush
,
598 BasePinImpl_NewSegment
601 static HRESULT WINAPI
SmartTeeFilterPreview_CheckMediaType(BasePin
*base
, const AM_MEDIA_TYPE
*amt
)
603 FIXME("(%p) stub\n", base
);
607 static LONG WINAPI
SmartTeeFilterPreview_GetMediaTypeVersion(BasePin
*base
)
609 SmartTeeFilter
*This
= impl_from_BasePin(base
);
610 TRACE("(%p)\n", This
);
614 static HRESULT WINAPI
SmartTeeFilterPreview_GetMediaType(BasePin
*base
, int iPosition
, AM_MEDIA_TYPE
*amt
)
616 SmartTeeFilter
*This
= impl_from_BasePin(base
);
617 TRACE("(%p, %d, %p)\n", This
, iPosition
, amt
);
618 if (iPosition
== 0) {
619 CopyMediaType(amt
, &This
->input
->pin
.mtCurrent
);
625 static HRESULT WINAPI
SmartTeeFilterPreview_DecideAllocator(BaseOutputPin
*base
, IMemInputPin
*pPin
, IMemAllocator
**pAlloc
)
627 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
628 TRACE("(%p, %p, %p)\n", This
, pPin
, pAlloc
);
629 *pAlloc
= This
->input
->pAllocator
;
630 IMemAllocator_AddRef(This
->input
->pAllocator
);
631 return IMemInputPin_NotifyAllocator(pPin
, This
->input
->pAllocator
, TRUE
);
634 static HRESULT WINAPI
SmartTeeFilterPreview_BreakConnect(BaseOutputPin
*base
)
636 SmartTeeFilter
*This
= impl_from_BasePin(&base
->pin
);
637 FIXME("(%p): stub\n", This
);
641 static const BaseOutputPinFuncTable SmartTeeFilterPreviewFuncs
= {
643 SmartTeeFilterPreview_CheckMediaType
,
644 BaseOutputPinImpl_AttemptConnection
,
645 SmartTeeFilterPreview_GetMediaTypeVersion
,
646 SmartTeeFilterPreview_GetMediaType
649 SmartTeeFilterPreview_DecideAllocator
,
650 SmartTeeFilterPreview_BreakConnect
652 IUnknown
* WINAPI
QCAP_createSmartTeeFilter(IUnknown
*outer
, HRESULT
*phr
)
654 PIN_INFO inputPinInfo
= {NULL
, PINDIR_INPUT
, {'I','n','p','u','t',0}};
655 PIN_INFO capturePinInfo
= {NULL
, PINDIR_OUTPUT
, {'C','a','p','t','u','r','e',0}};
656 PIN_INFO previewPinInfo
= {NULL
, PINDIR_OUTPUT
, {'P','r','e','v','i','e','w',0}};
658 SmartTeeFilter
*This
= NULL
;
660 TRACE("(%p, %p)\n", outer
, phr
);
662 This
= CoTaskMemAlloc(sizeof(*This
));
667 memset(This
, 0, sizeof(*This
));
668 This
->IUnknown_iface
.lpVtbl
= &UnknownVtbl
;
670 This
->outerUnknown
= outer
;
672 This
->outerUnknown
= &This
->IUnknown_iface
;
674 BaseFilter_Init(&This
->filter
, &SmartTeeFilterVtbl
, &CLSID_SmartTee
,
675 (DWORD_PTR
)(__FILE__
": SmartTeeFilter.csFilter"), &SmartTeeFilterFuncs
);
677 inputPinInfo
.pFilter
= &This
->filter
.IBaseFilter_iface
;
678 hr
= BaseInputPin_Construct(&SmartTeeFilterInputVtbl
, sizeof(BaseInputPin
), &inputPinInfo
,
679 &SmartTeeFilterInputFuncs
, &This
->filter
.csFilter
, NULL
, (IPin
**)&This
->input
);
682 hr
= CoCreateInstance(&CLSID_MemoryAllocator
, NULL
, CLSCTX_INPROC_SERVER
,
683 &IID_IMemAllocator
, (void**)&This
->input
->pAllocator
);
687 capturePinInfo
.pFilter
= &This
->filter
.IBaseFilter_iface
;
688 hr
= BaseOutputPin_Construct(&SmartTeeFilterCaptureVtbl
, sizeof(BaseOutputPin
), &capturePinInfo
,
689 &SmartTeeFilterCaptureFuncs
, &This
->filter
.csFilter
, (IPin
**)&This
->capture
);
693 previewPinInfo
.pFilter
= &This
->filter
.IBaseFilter_iface
;
694 hr
= BaseOutputPin_Construct(&SmartTeeFilterPreviewVtbl
, sizeof(BaseOutputPin
), &previewPinInfo
,
695 &SmartTeeFilterPreviewFuncs
, &This
->filter
.csFilter
, (IPin
**)&This
->preview
);
701 return &This
->IUnknown_iface
;
703 return (IUnknown
*)&This
->filter
.IBaseFilter_iface
;
706 IBaseFilter_Release(&This
->filter
.IBaseFilter_iface
);