user32: Check the DpiScalingVer registry key to enable DPI scaling.
[wine.git] / dlls / qcap / smartteefilter.c
blob220f5eb6c133fa5b097d2c13cd8763f215fec4e6
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 HRESULT WINAPI SmartTeeFilterCapture_CheckMediaType(BasePin *base, const AM_MEDIA_TYPE *amt)
504 FIXME("(%p) stub\n", base);
505 return S_OK;
508 static LONG WINAPI SmartTeeFilterCapture_GetMediaTypeVersion(BasePin *base)
510 SmartTeeFilter *This = impl_from_BasePin(base);
511 TRACE("(%p)\n", This);
512 return 0;
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);
521 return S_OK;
522 } else
523 return S_FALSE;
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);
539 return E_NOTIMPL;
542 static const BaseOutputPinFuncTable SmartTeeFilterCaptureFuncs = {
544 SmartTeeFilterCapture_CheckMediaType,
545 BaseOutputPinImpl_AttemptConnection,
546 SmartTeeFilterCapture_GetMediaTypeVersion,
547 SmartTeeFilterCapture_GetMediaType
549 NULL,
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);
569 HRESULT hr;
570 TRACE("(%p)->(%p)\n", This, ppEnum);
571 EnterCriticalSection(&This->filter.csFilter);
572 if (This->input->pin.pConnectedTo) {
573 hr = BasePinImpl_EnumMediaTypes(iface, ppEnum);
574 } else
575 hr = VFW_E_NOT_CONNECTED;
576 LeaveCriticalSection(&This->filter.csFilter);
577 return hr;
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,
591 BasePinImpl_QueryId,
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);
604 return S_OK;
607 static LONG WINAPI SmartTeeFilterPreview_GetMediaTypeVersion(BasePin *base)
609 SmartTeeFilter *This = impl_from_BasePin(base);
610 TRACE("(%p)\n", This);
611 return 0;
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);
620 return S_OK;
621 } else
622 return S_FALSE;
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);
638 return E_NOTIMPL;
641 static const BaseOutputPinFuncTable SmartTeeFilterPreviewFuncs = {
643 SmartTeeFilterPreview_CheckMediaType,
644 BaseOutputPinImpl_AttemptConnection,
645 SmartTeeFilterPreview_GetMediaTypeVersion,
646 SmartTeeFilterPreview_GetMediaType
648 NULL,
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}};
657 HRESULT hr;
658 SmartTeeFilter *This = NULL;
660 TRACE("(%p, %p)\n", outer, phr);
662 This = CoTaskMemAlloc(sizeof(*This));
663 if (This == NULL) {
664 hr = E_OUTOFMEMORY;
665 goto end;
667 memset(This, 0, sizeof(*This));
668 This->IUnknown_iface.lpVtbl = &UnknownVtbl;
669 if (outer)
670 This->outerUnknown = outer;
671 else
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);
680 if (FAILED(hr))
681 goto end;
682 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
683 &IID_IMemAllocator, (void**)&This->input->pAllocator);
684 if (FAILED(hr))
685 goto end;
687 capturePinInfo.pFilter = &This->filter.IBaseFilter_iface;
688 hr = BaseOutputPin_Construct(&SmartTeeFilterCaptureVtbl, sizeof(BaseOutputPin), &capturePinInfo,
689 &SmartTeeFilterCaptureFuncs, &This->filter.csFilter, (IPin**)&This->capture);
690 if (FAILED(hr))
691 goto end;
693 previewPinInfo.pFilter = &This->filter.IBaseFilter_iface;
694 hr = BaseOutputPin_Construct(&SmartTeeFilterPreviewVtbl, sizeof(BaseOutputPin), &previewPinInfo,
695 &SmartTeeFilterPreviewFuncs, &This->filter.csFilter, (IPin**)&This->preview);
697 end:
698 *phr = hr;
699 if (SUCCEEDED(hr)) {
700 if (outer)
701 return &This->IUnknown_iface;
702 else
703 return (IUnknown*)&This->filter.IBaseFilter_iface;
704 } else {
705 if (This)
706 IBaseFilter_Release(&This->filter.IBaseFilter_iface);
707 return NULL;