attrib: Use WINAPIV calling convention for variadic functions.
[wine.git] / dlls / qcap / smartteefilter.c
blob27aee4705ac4e550cc60106c19459082a39d1a76
1 /*
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
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wtypes.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "dshow.h"
32 #include "qcap_main.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(qcap);
38 typedef struct {
39 IUnknown IUnknown_iface;
40 IUnknown *outerUnknown;
41 BaseFilter filter;
42 BaseInputPin *input;
43 BaseOutputPin *capture;
44 BaseOutputPin *preview;
45 } SmartTeeFilter;
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;
89 } else {
90 FIXME("(%p): no interface for %s\n", This, debugstr_guid(riid));
91 *ppv = NULL;
92 return E_NOINTERFACE;
94 IUnknown_AddRef((IUnknown*)*ppv);
95 return S_OK;
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);
111 if (!ref) {
112 if(This->input)
113 BaseInputPinImpl_Release(&This->input->pin.IPin_iface);
114 if(This->capture)
115 BaseOutputPinImpl_Release(&This->capture->pin.IPin_iface);
116 if(This->preview)
117 BaseOutputPinImpl_Release(&This->preview->pin.IPin_iface);
118 CoTaskMemFree(This);
120 return ref;
123 static const IUnknownVtbl UnknownVtbl = {
124 Unknown_QueryInterface,
125 Unknown_AddRef,
126 Unknown_Release
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);
154 return S_OK;
157 static HRESULT WINAPI SmartTeeFilter_Pause(IBaseFilter *iface)
159 SmartTeeFilter *This = impl_from_IBaseFilter(iface);
160 FIXME("(%p): stub\n", This);
161 return E_NOTIMPL;
164 static HRESULT WINAPI SmartTeeFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
166 SmartTeeFilter *This = impl_from_IBaseFilter(iface);
167 HRESULT hr = S_OK;
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;
176 else
177 hr = VFW_E_NOT_CONNECTED;
179 LeaveCriticalSection(&This->filter.csFilter);
180 return hr;
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;
189 IPin_AddRef(*ppPin);
190 return S_OK;
191 } else if (lstrcmpW(Id, This->capture->pin.pinInfo.achName) == 0) {
192 *ppPin = &This->capture->pin.IPin_iface;
193 IPin_AddRef(*ppPin);
194 return S_OK;
195 } else if (lstrcmpW(Id, This->preview->pin.pinInfo.achName) == 0) {
196 *ppPin = &This->preview->pin.IPin_iface;
197 IPin_AddRef(*ppPin);
198 return S_OK;
200 return VFW_E_NOT_FOUND;
203 static const IBaseFilterVtbl SmartTeeFilterVtbl = {
204 SmartTeeFilter_QueryInterface,
205 SmartTeeFilter_AddRef,
206 SmartTeeFilter_Release,
207 BaseFilterImpl_GetClassID,
208 SmartTeeFilter_Stop,
209 SmartTeeFilter_Pause,
210 SmartTeeFilter_Run,
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);
224 IPin *ret;
226 TRACE("(%p)->(%d)\n", This, pos);
228 switch(pos) {
229 case 0:
230 ret = &This->input->pin.IPin_iface;
231 break;
232 case 1:
233 ret = &This->capture->pin.IPin_iface;
234 break;
235 case 2:
236 ret = &This->preview->pin.IPin_iface;
237 break;
238 default:
239 TRACE("No pin %d\n", pos);
240 return NULL;
243 IPin_AddRef(ret);
244 return ret;
247 static LONG WINAPI SmartTeeFilter_GetPinCount(BaseFilter *iface)
249 return 3;
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,
280 BasePinImpl_QueryId,
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);
295 if (!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. */
299 return S_OK;
302 static LONG WINAPI SmartTeeFilterInput_GetMediaTypeVersion(BasePin *base)
304 return 0;
307 static HRESULT WINAPI SmartTeeFilterInput_GetMediaType(BasePin *base, int iPosition, AM_MEDIA_TYPE *amt)
309 SmartTeeFilter *This = impl_from_BasePin(base);
310 HRESULT hr;
311 TRACE("(%p)->(%d, %p)\n", This, iPosition, amt);
312 if (iPosition)
313 return S_FALSE;
314 EnterCriticalSection(&This->filter.csFilter);
315 if (This->input->pin.pConnectedTo) {
316 CopyMediaType(amt, &This->input->pin.mtCurrent);
317 hr = S_OK;
318 } else
319 hr = S_FALSE;
320 LeaveCriticalSection(&This->filter.csFilter);
321 return hr;
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;
331 HRESULT hr;
333 hr = IMediaSample_GetTime(inputSample, &startTime, &endTime);
334 if (hr == S_OK)
336 else if (hr == VFW_S_NO_STOP_TIME)
337 haveEndTime = FALSE;
338 else if (hr == VFW_E_SAMPLE_TIME_NOT_SET)
339 haveStartTime = haveEndTime = FALSE;
340 else
341 goto end;
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;
349 goto end;
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);
367 if (hr == S_OK)
369 else if (hr == VFW_S_NO_STOP_TIME)
370 haveEndTime = FALSE;
371 else if (hr == VFW_E_MEDIA_TIME_NOT_SET)
372 haveStartTime = haveEndTime = FALSE;
373 else
374 goto end;
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;
380 if (hr == S_OK) {
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;
391 end:
392 if (mediaType)
393 DeleteMediaType(mediaType);
394 if (FAILED(hr) && outputSample) {
395 IMediaSample_Release(outputSample);
396 outputSample = NULL;
398 *pOutputSample = outputSample;
399 return hr;
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);
423 if (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);
435 if (previewSample)
436 IMediaSample_Release(previewSample);
438 /* FIXME: how to merge the HRESULTs from the 2 pins? */
439 if (SUCCEEDED(hrCapture))
440 return hrCapture;
441 else
442 return hrPreview;
445 static const BaseInputPinFuncTable SmartTeeFilterInputFuncs = {
447 SmartTeeFilterInput_CheckMediaType,
448 NULL,
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);
470 HRESULT hr;
471 TRACE("(%p)->(%p)\n", This, ppEnum);
472 EnterCriticalSection(&This->filter.csFilter);
473 if (This->input->pin.pConnectedTo) {
474 hr = BasePinImpl_EnumMediaTypes(iface, ppEnum);
475 } else
476 hr = VFW_E_NOT_CONNECTED;
477 LeaveCriticalSection(&This->filter.csFilter);
478 return hr;
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,
492 BasePinImpl_QueryId,
493 BasePinImpl_QueryAccept,
494 SmartTeeFilterCapture_EnumMediaTypes,
495 BasePinImpl_QueryInternalConnections,
496 BaseOutputPinImpl_EndOfStream,
497 BaseOutputPinImpl_BeginFlush,
498 BaseOutputPinImpl_EndFlush,
499 BasePinImpl_NewSegment
502 static LONG WINAPI SmartTeeFilterCapture_GetMediaTypeVersion(BasePin *base)
504 SmartTeeFilter *This = impl_from_BasePin(base);
505 TRACE("(%p)\n", This);
506 return 0;
509 static HRESULT WINAPI SmartTeeFilterCapture_GetMediaType(BasePin *base, int iPosition, AM_MEDIA_TYPE *amt)
511 SmartTeeFilter *This = impl_from_BasePin(base);
512 TRACE("(%p, %d, %p)\n", This, iPosition, amt);
513 if (iPosition == 0) {
514 CopyMediaType(amt, &This->input->pin.mtCurrent);
515 return S_OK;
516 } else
517 return S_FALSE;
520 static HRESULT WINAPI SmartTeeFilterCapture_DecideAllocator(BaseOutputPin *base, IMemInputPin *pPin, IMemAllocator **pAlloc)
522 SmartTeeFilter *This = impl_from_BasePin(&base->pin);
523 TRACE("(%p, %p, %p)\n", This, pPin, pAlloc);
524 *pAlloc = This->input->pAllocator;
525 IMemAllocator_AddRef(This->input->pAllocator);
526 return IMemInputPin_NotifyAllocator(pPin, This->input->pAllocator, TRUE);
529 static HRESULT WINAPI SmartTeeFilterCapture_BreakConnect(BaseOutputPin *base)
531 SmartTeeFilter *This = impl_from_BasePin(&base->pin);
532 FIXME("(%p): stub\n", This);
533 return E_NOTIMPL;
536 static const BaseOutputPinFuncTable SmartTeeFilterCaptureFuncs = {
538 NULL,
539 BaseOutputPinImpl_AttemptConnection,
540 SmartTeeFilterCapture_GetMediaTypeVersion,
541 SmartTeeFilterCapture_GetMediaType
543 NULL,
544 SmartTeeFilterCapture_DecideAllocator,
545 SmartTeeFilterCapture_BreakConnect
548 static ULONG WINAPI SmartTeeFilterPreview_AddRef(IPin *iface)
550 SmartTeeFilter *This = impl_from_IPin(iface);
551 return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface);
554 static ULONG WINAPI SmartTeeFilterPreview_Release(IPin *iface)
556 SmartTeeFilter *This = impl_from_IPin(iface);
557 return IBaseFilter_Release(&This->filter.IBaseFilter_iface);
560 static HRESULT WINAPI SmartTeeFilterPreview_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum)
562 SmartTeeFilter *This = impl_from_IPin(iface);
563 HRESULT hr;
564 TRACE("(%p)->(%p)\n", This, ppEnum);
565 EnterCriticalSection(&This->filter.csFilter);
566 if (This->input->pin.pConnectedTo) {
567 hr = BasePinImpl_EnumMediaTypes(iface, ppEnum);
568 } else
569 hr = VFW_E_NOT_CONNECTED;
570 LeaveCriticalSection(&This->filter.csFilter);
571 return hr;
574 static const IPinVtbl SmartTeeFilterPreviewVtbl = {
575 BaseOutputPinImpl_QueryInterface,
576 SmartTeeFilterPreview_AddRef,
577 SmartTeeFilterPreview_Release,
578 BaseOutputPinImpl_Connect,
579 BaseOutputPinImpl_ReceiveConnection,
580 BaseOutputPinImpl_Disconnect,
581 BasePinImpl_ConnectedTo,
582 BasePinImpl_ConnectionMediaType,
583 BasePinImpl_QueryPinInfo,
584 BasePinImpl_QueryDirection,
585 BasePinImpl_QueryId,
586 BasePinImpl_QueryAccept,
587 SmartTeeFilterPreview_EnumMediaTypes,
588 BasePinImpl_QueryInternalConnections,
589 BaseOutputPinImpl_EndOfStream,
590 BaseOutputPinImpl_BeginFlush,
591 BaseOutputPinImpl_EndFlush,
592 BasePinImpl_NewSegment
595 static LONG WINAPI SmartTeeFilterPreview_GetMediaTypeVersion(BasePin *base)
597 SmartTeeFilter *This = impl_from_BasePin(base);
598 TRACE("(%p)\n", This);
599 return 0;
602 static HRESULT WINAPI SmartTeeFilterPreview_GetMediaType(BasePin *base, int iPosition, AM_MEDIA_TYPE *amt)
604 SmartTeeFilter *This = impl_from_BasePin(base);
605 TRACE("(%p, %d, %p)\n", This, iPosition, amt);
606 if (iPosition == 0) {
607 CopyMediaType(amt, &This->input->pin.mtCurrent);
608 return S_OK;
609 } else
610 return S_FALSE;
613 static HRESULT WINAPI SmartTeeFilterPreview_DecideAllocator(BaseOutputPin *base, IMemInputPin *pPin, IMemAllocator **pAlloc)
615 SmartTeeFilter *This = impl_from_BasePin(&base->pin);
616 TRACE("(%p, %p, %p)\n", This, pPin, pAlloc);
617 *pAlloc = This->input->pAllocator;
618 IMemAllocator_AddRef(This->input->pAllocator);
619 return IMemInputPin_NotifyAllocator(pPin, This->input->pAllocator, TRUE);
622 static HRESULT WINAPI SmartTeeFilterPreview_BreakConnect(BaseOutputPin *base)
624 SmartTeeFilter *This = impl_from_BasePin(&base->pin);
625 FIXME("(%p): stub\n", This);
626 return E_NOTIMPL;
629 static const BaseOutputPinFuncTable SmartTeeFilterPreviewFuncs = {
631 NULL,
632 BaseOutputPinImpl_AttemptConnection,
633 SmartTeeFilterPreview_GetMediaTypeVersion,
634 SmartTeeFilterPreview_GetMediaType
636 NULL,
637 SmartTeeFilterPreview_DecideAllocator,
638 SmartTeeFilterPreview_BreakConnect
640 IUnknown* WINAPI QCAP_createSmartTeeFilter(IUnknown *outer, HRESULT *phr)
642 PIN_INFO inputPinInfo = {NULL, PINDIR_INPUT, {'I','n','p','u','t',0}};
643 PIN_INFO capturePinInfo = {NULL, PINDIR_OUTPUT, {'C','a','p','t','u','r','e',0}};
644 PIN_INFO previewPinInfo = {NULL, PINDIR_OUTPUT, {'P','r','e','v','i','e','w',0}};
645 HRESULT hr;
646 SmartTeeFilter *This = NULL;
648 TRACE("(%p, %p)\n", outer, phr);
650 This = CoTaskMemAlloc(sizeof(*This));
651 if (This == NULL) {
652 hr = E_OUTOFMEMORY;
653 goto end;
655 memset(This, 0, sizeof(*This));
656 This->IUnknown_iface.lpVtbl = &UnknownVtbl;
657 if (outer)
658 This->outerUnknown = outer;
659 else
660 This->outerUnknown = &This->IUnknown_iface;
662 BaseFilter_Init(&This->filter, &SmartTeeFilterVtbl, &CLSID_SmartTee,
663 (DWORD_PTR)(__FILE__ ": SmartTeeFilter.csFilter"), &SmartTeeFilterFuncs);
665 inputPinInfo.pFilter = &This->filter.IBaseFilter_iface;
666 hr = BaseInputPin_Construct(&SmartTeeFilterInputVtbl, sizeof(BaseInputPin), &inputPinInfo,
667 &SmartTeeFilterInputFuncs, &This->filter.csFilter, NULL, (IPin**)&This->input);
668 if (FAILED(hr))
669 goto end;
670 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
671 &IID_IMemAllocator, (void**)&This->input->pAllocator);
672 if (FAILED(hr))
673 goto end;
675 capturePinInfo.pFilter = &This->filter.IBaseFilter_iface;
676 hr = BaseOutputPin_Construct(&SmartTeeFilterCaptureVtbl, sizeof(BaseOutputPin), &capturePinInfo,
677 &SmartTeeFilterCaptureFuncs, &This->filter.csFilter, (IPin**)&This->capture);
678 if (FAILED(hr))
679 goto end;
681 previewPinInfo.pFilter = &This->filter.IBaseFilter_iface;
682 hr = BaseOutputPin_Construct(&SmartTeeFilterPreviewVtbl, sizeof(BaseOutputPin), &previewPinInfo,
683 &SmartTeeFilterPreviewFuncs, &This->filter.csFilter, (IPin**)&This->preview);
685 end:
686 *phr = hr;
687 if (SUCCEEDED(hr)) {
688 if (outer)
689 return &This->IUnknown_iface;
690 else
691 return (IUnknown*)&This->filter.IBaseFilter_iface;
692 } else {
693 if (This)
694 IBaseFilter_Release(&This->filter.IBaseFilter_iface);
695 return NULL;