ntdll: Move the plaform-independent thread data to the GdiTebBatch TEB field.
[wine.git] / dlls / qcap / smartteefilter.c
blob31915779b541f05087f73f58cf41c136bc659e5c
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 if(This->filter.state != State_Stopped) {
153 This->filter.state = State_Stopped;
155 LeaveCriticalSection(&This->filter.csFilter);
156 return S_OK;
159 static HRESULT WINAPI SmartTeeFilter_Pause(IBaseFilter *iface)
161 SmartTeeFilter *This = impl_from_IBaseFilter(iface);
162 FIXME("(%p): stub\n", This);
163 return E_NOTIMPL;
166 static HRESULT WINAPI SmartTeeFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
168 SmartTeeFilter *This = impl_from_IBaseFilter(iface);
169 HRESULT hr = S_OK;
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;
178 else
179 hr = VFW_E_NOT_CONNECTED;
181 LeaveCriticalSection(&This->filter.csFilter);
182 return hr;
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;
191 IPin_AddRef(*ppPin);
192 return S_OK;
193 } else if (lstrcmpW(Id, This->capture->pin.pinInfo.achName) == 0) {
194 *ppPin = &This->capture->pin.IPin_iface;
195 IPin_AddRef(*ppPin);
196 return S_OK;
197 } else if (lstrcmpW(Id, This->preview->pin.pinInfo.achName) == 0) {
198 *ppPin = &This->preview->pin.IPin_iface;
199 IPin_AddRef(*ppPin);
200 return S_OK;
202 return VFW_E_NOT_FOUND;
205 static const IBaseFilterVtbl SmartTeeFilterVtbl = {
206 SmartTeeFilter_QueryInterface,
207 SmartTeeFilter_AddRef,
208 SmartTeeFilter_Release,
209 BaseFilterImpl_GetClassID,
210 SmartTeeFilter_Stop,
211 SmartTeeFilter_Pause,
212 SmartTeeFilter_Run,
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);
226 IPin *ret;
228 TRACE("(%p)->(%d)\n", This, pos);
230 switch(pos) {
231 case 0:
232 ret = &This->input->pin.IPin_iface;
233 break;
234 case 1:
235 ret = &This->capture->pin.IPin_iface;
236 break;
237 case 2:
238 ret = &This->preview->pin.IPin_iface;
239 break;
240 default:
241 TRACE("No pin %d\n", pos);
242 return NULL;
245 IPin_AddRef(ret);
246 return ret;
249 static LONG WINAPI SmartTeeFilter_GetPinCount(BaseFilter *iface)
251 return 3;
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,
282 BasePinImpl_QueryId,
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);
297 if (!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. */
301 return S_OK;
304 static LONG WINAPI SmartTeeFilterInput_GetMediaTypeVersion(BasePin *base)
306 return 0;
309 static HRESULT WINAPI SmartTeeFilterInput_GetMediaType(BasePin *base, int iPosition, AM_MEDIA_TYPE *amt)
311 SmartTeeFilter *This = impl_from_BasePin(base);
312 HRESULT hr;
313 TRACE("(%p)->(%d, %p)\n", This, iPosition, amt);
314 if (iPosition)
315 return S_FALSE;
316 EnterCriticalSection(&This->filter.csFilter);
317 if (This->input->pin.pConnectedTo) {
318 CopyMediaType(amt, &This->input->pin.mtCurrent);
319 hr = S_OK;
320 } else
321 hr = S_FALSE;
322 LeaveCriticalSection(&This->filter.csFilter);
323 return hr;
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;
333 HRESULT hr;
335 hr = IMediaSample_GetTime(inputSample, &startTime, &endTime);
336 if (hr == S_OK)
338 else if (hr == VFW_S_NO_STOP_TIME)
339 haveEndTime = FALSE;
340 else if (hr == VFW_E_SAMPLE_TIME_NOT_SET)
341 haveStartTime = haveEndTime = FALSE;
342 else
343 goto end;
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;
351 goto end;
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);
369 if (hr == S_OK)
371 else if (hr == VFW_S_NO_STOP_TIME)
372 haveEndTime = FALSE;
373 else if (hr == VFW_E_MEDIA_TIME_NOT_SET)
374 haveStartTime = haveEndTime = FALSE;
375 else
376 goto end;
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;
382 if (hr == S_OK) {
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;
393 end:
394 if (mediaType)
395 DeleteMediaType(mediaType);
396 if (FAILED(hr) && outputSample) {
397 IMediaSample_Release(outputSample);
398 outputSample = NULL;
400 *pOutputSample = outputSample;
401 return hr;
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);
425 if (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);
437 if (previewSample)
438 IMediaSample_Release(previewSample);
440 /* FIXME: how to merge the HRESULTs from the 2 pins? */
441 if (SUCCEEDED(hrCapture))
442 return hrCapture;
443 else
444 return hrPreview;
447 static const BaseInputPinFuncTable SmartTeeFilterInputFuncs = {
449 SmartTeeFilterInput_CheckMediaType,
450 NULL,
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);
472 HRESULT hr;
473 TRACE("(%p)->(%p)\n", This, ppEnum);
474 EnterCriticalSection(&This->filter.csFilter);
475 if (This->input->pin.pConnectedTo) {
476 hr = BasePinImpl_EnumMediaTypes(iface, ppEnum);
477 } else
478 hr = VFW_E_NOT_CONNECTED;
479 LeaveCriticalSection(&This->filter.csFilter);
480 return hr;
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,
494 BasePinImpl_QueryId,
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);
508 return 0;
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);
517 return S_OK;
518 } else
519 return S_FALSE;
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);
535 return E_NOTIMPL;
538 static const BaseOutputPinFuncTable SmartTeeFilterCaptureFuncs = {
540 NULL,
541 BaseOutputPinImpl_AttemptConnection,
542 SmartTeeFilterCapture_GetMediaTypeVersion,
543 SmartTeeFilterCapture_GetMediaType
545 NULL,
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);
565 HRESULT hr;
566 TRACE("(%p)->(%p)\n", This, ppEnum);
567 EnterCriticalSection(&This->filter.csFilter);
568 if (This->input->pin.pConnectedTo) {
569 hr = BasePinImpl_EnumMediaTypes(iface, ppEnum);
570 } else
571 hr = VFW_E_NOT_CONNECTED;
572 LeaveCriticalSection(&This->filter.csFilter);
573 return hr;
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,
587 BasePinImpl_QueryId,
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);
601 return 0;
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);
610 return S_OK;
611 } else
612 return S_FALSE;
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);
628 return E_NOTIMPL;
631 static const BaseOutputPinFuncTable SmartTeeFilterPreviewFuncs = {
633 NULL,
634 BaseOutputPinImpl_AttemptConnection,
635 SmartTeeFilterPreview_GetMediaTypeVersion,
636 SmartTeeFilterPreview_GetMediaType
638 NULL,
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}};
647 HRESULT hr;
648 SmartTeeFilter *This = NULL;
650 TRACE("(%p, %p)\n", outer, phr);
652 This = CoTaskMemAlloc(sizeof(*This));
653 if (This == NULL) {
654 hr = E_OUTOFMEMORY;
655 goto end;
657 memset(This, 0, sizeof(*This));
658 This->IUnknown_iface.lpVtbl = &UnknownVtbl;
659 if (outer)
660 This->outerUnknown = outer;
661 else
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);
670 if (FAILED(hr))
671 goto end;
672 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
673 &IID_IMemAllocator, (void**)&This->input->pAllocator);
674 if (FAILED(hr))
675 goto end;
677 capturePinInfo.pFilter = &This->filter.IBaseFilter_iface;
678 hr = BaseOutputPin_Construct(&SmartTeeFilterCaptureVtbl, sizeof(BaseOutputPin), &capturePinInfo,
679 &SmartTeeFilterCaptureFuncs, &This->filter.csFilter, (IPin**)&This->capture);
680 if (FAILED(hr))
681 goto end;
683 previewPinInfo.pFilter = &This->filter.IBaseFilter_iface;
684 hr = BaseOutputPin_Construct(&SmartTeeFilterPreviewVtbl, sizeof(BaseOutputPin), &previewPinInfo,
685 &SmartTeeFilterPreviewFuncs, &This->filter.csFilter, (IPin**)&This->preview);
687 end:
688 *phr = hr;
689 if (SUCCEEDED(hr)) {
690 if (outer)
691 return &This->IUnknown_iface;
692 else
693 return (IUnknown*)&This->filter.IBaseFilter_iface;
694 } else {
695 if (This)
696 IBaseFilter_Release(&This->filter.IBaseFilter_iface);
697 return NULL;