d3d10core/tests: Simplify test_cb_relative_addressing() a bit.
[wine.git] / dlls / qcap / smartteefilter.c
blobf052e2d0cd4df14e7535c3573f81945ea145c025
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 const IBaseFilterVtbl SmartTeeFilterVtbl = {
184 SmartTeeFilter_QueryInterface,
185 SmartTeeFilter_AddRef,
186 SmartTeeFilter_Release,
187 BaseFilterImpl_GetClassID,
188 SmartTeeFilter_Stop,
189 SmartTeeFilter_Pause,
190 SmartTeeFilter_Run,
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);
204 IPin *ret;
206 TRACE("(%p)->(%d)\n", This, pos);
208 switch(pos) {
209 case 0:
210 ret = &This->input->pin.IPin_iface;
211 break;
212 case 1:
213 ret = &This->capture->pin.IPin_iface;
214 break;
215 case 2:
216 ret = &This->preview->pin.IPin_iface;
217 break;
218 default:
219 TRACE("No pin %d\n", pos);
220 return NULL;
223 IPin_AddRef(ret);
224 return ret;
227 static LONG WINAPI SmartTeeFilter_GetPinCount(BaseFilter *iface)
229 return 3;
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,
260 BasePinImpl_QueryId,
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);
275 if (!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. */
279 return S_OK;
282 static LONG WINAPI SmartTeeFilterInput_GetMediaTypeVersion(BasePin *base)
284 return 0;
287 static HRESULT WINAPI SmartTeeFilterInput_GetMediaType(BasePin *base, int iPosition, AM_MEDIA_TYPE *amt)
289 SmartTeeFilter *This = impl_from_BasePin(base);
290 HRESULT hr;
291 TRACE("(%p)->(%d, %p)\n", This, iPosition, amt);
292 if (iPosition)
293 return S_FALSE;
294 EnterCriticalSection(&This->filter.csFilter);
295 if (This->input->pin.pConnectedTo) {
296 CopyMediaType(amt, &This->input->pin.mtCurrent);
297 hr = S_OK;
298 } else
299 hr = S_FALSE;
300 LeaveCriticalSection(&This->filter.csFilter);
301 return hr;
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;
311 HRESULT hr;
313 hr = IMediaSample_GetTime(inputSample, &startTime, &endTime);
314 if (hr == S_OK)
316 else if (hr == VFW_S_NO_STOP_TIME)
317 haveEndTime = FALSE;
318 else if (hr == VFW_E_SAMPLE_TIME_NOT_SET)
319 haveStartTime = haveEndTime = FALSE;
320 else
321 goto end;
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;
329 goto end;
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);
347 if (hr == S_OK)
349 else if (hr == VFW_S_NO_STOP_TIME)
350 haveEndTime = FALSE;
351 else if (hr == VFW_E_MEDIA_TIME_NOT_SET)
352 haveStartTime = haveEndTime = FALSE;
353 else
354 goto end;
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;
360 if (hr == S_OK) {
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;
371 end:
372 if (mediaType)
373 DeleteMediaType(mediaType);
374 if (FAILED(hr) && outputSample) {
375 IMediaSample_Release(outputSample);
376 outputSample = NULL;
378 *pOutputSample = outputSample;
379 return hr;
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);
403 if (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);
415 if (previewSample)
416 IMediaSample_Release(previewSample);
418 /* FIXME: how to merge the HRESULTs from the 2 pins? */
419 if (SUCCEEDED(hrCapture))
420 return hrCapture;
421 else
422 return hrPreview;
425 static const BaseInputPinFuncTable SmartTeeFilterInputFuncs = {
427 SmartTeeFilterInput_CheckMediaType,
428 NULL,
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);
450 HRESULT hr;
451 TRACE("(%p)->(%p)\n", This, ppEnum);
452 EnterCriticalSection(&This->filter.csFilter);
453 if (This->input->pin.pConnectedTo) {
454 hr = BasePinImpl_EnumMediaTypes(iface, ppEnum);
455 } else
456 hr = VFW_E_NOT_CONNECTED;
457 LeaveCriticalSection(&This->filter.csFilter);
458 return hr;
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,
472 BasePinImpl_QueryId,
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);
485 return S_OK;
488 static LONG WINAPI SmartTeeFilterCapture_GetMediaTypeVersion(BasePin *base)
490 SmartTeeFilter *This = impl_from_BasePin(base);
491 TRACE("(%p)\n", This);
492 return 0;
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);
501 return S_OK;
502 } else
503 return S_FALSE;
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);
519 return E_NOTIMPL;
522 static const BaseOutputPinFuncTable SmartTeeFilterCaptureFuncs = {
524 SmartTeeFilterCapture_CheckMediaType,
525 BaseOutputPinImpl_AttemptConnection,
526 SmartTeeFilterCapture_GetMediaTypeVersion,
527 SmartTeeFilterCapture_GetMediaType
529 NULL,
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);
549 HRESULT hr;
550 TRACE("(%p)->(%p)\n", This, ppEnum);
551 EnterCriticalSection(&This->filter.csFilter);
552 if (This->input->pin.pConnectedTo) {
553 hr = BasePinImpl_EnumMediaTypes(iface, ppEnum);
554 } else
555 hr = VFW_E_NOT_CONNECTED;
556 LeaveCriticalSection(&This->filter.csFilter);
557 return hr;
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,
571 BasePinImpl_QueryId,
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);
584 return S_OK;
587 static LONG WINAPI SmartTeeFilterPreview_GetMediaTypeVersion(BasePin *base)
589 SmartTeeFilter *This = impl_from_BasePin(base);
590 TRACE("(%p)\n", This);
591 return 0;
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);
600 return S_OK;
601 } else
602 return S_FALSE;
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);
618 return E_NOTIMPL;
621 static const BaseOutputPinFuncTable SmartTeeFilterPreviewFuncs = {
623 SmartTeeFilterPreview_CheckMediaType,
624 BaseOutputPinImpl_AttemptConnection,
625 SmartTeeFilterPreview_GetMediaTypeVersion,
626 SmartTeeFilterPreview_GetMediaType
628 NULL,
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}};
637 HRESULT hr;
638 SmartTeeFilter *This = NULL;
640 TRACE("(%p, %p)\n", outer, phr);
642 This = CoTaskMemAlloc(sizeof(*This));
643 if (This == NULL) {
644 hr = E_OUTOFMEMORY;
645 goto end;
647 memset(This, 0, sizeof(*This));
648 This->IUnknown_iface.lpVtbl = &UnknownVtbl;
649 if (outer)
650 This->outerUnknown = outer;
651 else
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);
660 if (FAILED(hr))
661 goto end;
662 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
663 &IID_IMemAllocator, (void**)&This->input->pAllocator);
664 if (FAILED(hr))
665 goto end;
667 capturePinInfo.pFilter = &This->filter.IBaseFilter_iface;
668 hr = BaseOutputPin_Construct(&SmartTeeFilterCaptureVtbl, sizeof(BaseOutputPin), &capturePinInfo,
669 &SmartTeeFilterCaptureFuncs, &This->filter.csFilter, (IPin**)&This->capture);
670 if (FAILED(hr))
671 goto end;
673 previewPinInfo.pFilter = &This->filter.IBaseFilter_iface;
674 hr = BaseOutputPin_Construct(&SmartTeeFilterPreviewVtbl, sizeof(BaseOutputPin), &previewPinInfo,
675 &SmartTeeFilterPreviewFuncs, &This->filter.csFilter, (IPin**)&This->preview);
677 end:
678 *phr = hr;
679 if (SUCCEEDED(hr)) {
680 if (outer)
681 return &This->IUnknown_iface;
682 else
683 return (IUnknown*)&This->filter.IBaseFilter_iface;
684 } else {
685 if (This)
686 IBaseFilter_Release(&This->filter.IBaseFilter_iface);
687 return NULL;