TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / qcap / vfwcapture.c
blob372e2ee9d5092fedd41c71ef3e5388a7dd44dfa8
1 /* Video For Windows Steering structure
3 * Copyright 2005 Maarten Lankhorst
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include "config.h"
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wtypes.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "dshow.h"
33 #include "qcap_main.h"
34 #include "wine/debug.h"
36 #include "capture.h"
37 #include "uuids.h"
38 #include "vfwmsgs.h"
39 #include "amvideo.h"
40 #include "strmif.h"
41 #include "ddraw.h"
42 #include "ocidl.h"
43 #include "oleauto.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(qcap);
47 static const IBaseFilterVtbl VfwCapture_Vtbl;
48 static const IAMStreamConfigVtbl IAMStreamConfig_VTable;
49 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable;
50 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable;
51 static const IPinVtbl VfwPin_Vtbl;
53 static HRESULT VfwPin_Construct( IBaseFilter *, LPCRITICAL_SECTION, IPin ** );
55 typedef struct VfwCapture
57 IUnknown IUnknown_inner;
58 BaseFilter filter;
59 IAMStreamConfig IAMStreamConfig_iface;
60 IAMVideoProcAmp IAMVideoProcAmp_iface;
61 IPersistPropertyBag IPersistPropertyBag_iface;
62 IUnknown *outer_unk;
63 BOOL init;
64 Capture *driver_info;
66 IPin * pOutputPin;
67 } VfwCapture;
69 static inline VfwCapture *impl_from_IUnknown(IUnknown *iface)
71 return CONTAINING_RECORD(iface, VfwCapture, IUnknown_inner);
74 static inline VfwCapture *impl_from_BaseFilter(BaseFilter *iface)
76 return CONTAINING_RECORD(iface, VfwCapture, filter);
79 static inline VfwCapture *impl_from_IBaseFilter(IBaseFilter *iface)
81 return CONTAINING_RECORD(iface, VfwCapture, filter.IBaseFilter_iface);
84 static inline VfwCapture *impl_from_IAMStreamConfig(IAMStreamConfig *iface)
86 return CONTAINING_RECORD(iface, VfwCapture, IAMStreamConfig_iface);
89 static inline VfwCapture *impl_from_IAMVideoProcAmp(IAMVideoProcAmp *iface)
91 return CONTAINING_RECORD(iface, VfwCapture, IAMVideoProcAmp_iface);
94 static inline VfwCapture *impl_from_IPersistPropertyBag(IPersistPropertyBag *iface)
96 return CONTAINING_RECORD(iface, VfwCapture, IPersistPropertyBag_iface);
99 /* VfwPin implementation */
100 typedef struct VfwPinImpl
102 BaseOutputPin pin;
103 IKsPropertySet IKsPropertySet_iface;
104 VfwCapture *parent;
105 } VfwPinImpl;
108 /* VfwCapture inner IUnknown */
109 static HRESULT WINAPI unknown_inner_QueryInterface(IUnknown *iface, REFIID riid, void **ret_iface)
111 VfwCapture *This = impl_from_IUnknown(iface);
113 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ret_iface);
115 *ret_iface = NULL;
117 if (IsEqualIID(riid, &IID_IUnknown))
118 *ret_iface = &This->IUnknown_inner;
119 else if (IsEqualIID(riid, &IID_IPersist) || IsEqualIID(riid, &IID_IMediaFilter) ||
120 IsEqualIID(riid, &IID_IBaseFilter))
121 *ret_iface = &This->filter.IBaseFilter_iface;
122 else if (IsEqualIID(riid, &IID_IPersistPropertyBag))
123 *ret_iface = &This->IPersistPropertyBag_iface;
124 else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags))
125 FIXME("IAMFilterMiscFlags not supported yet!\n");
126 else if (IsEqualIID(riid, &IID_ISpecifyPropertyPages))
127 FIXME("ISpecifyPropertyPages not supported yet!\n");
128 else if (IsEqualIID(riid, &IID_IAMVfwCaptureDialogs))
129 FIXME("IAMVfwCaptureDialogs not supported yet!\n");
130 else if (IsEqualIID(riid, &IID_IAMStreamConfig))
131 *ret_iface = &This->IAMStreamConfig_iface;
132 else if (IsEqualIID(riid, &IID_IAMVideoProcAmp))
133 *ret_iface = &This->IAMVideoProcAmp_iface;
134 else
135 WARN("(%p, %s, %p): not found\n", This, debugstr_guid(riid), ret_iface);
137 if (!*ret_iface)
138 return E_NOINTERFACE;
140 IUnknown_AddRef((IUnknown*)*ret_iface);
141 return S_OK;
144 static ULONG WINAPI unknown_inner_AddRef(IUnknown *iface)
146 VfwCapture *This = impl_from_IUnknown(iface);
147 ULONG ref = BaseFilterImpl_AddRef(&This->filter.IBaseFilter_iface);
149 TRACE("(%p) ref=%d\n", This, ref);
151 return ref;
154 static ULONG WINAPI unknown_inner_Release(IUnknown *iface)
156 VfwCapture *This = impl_from_IUnknown(iface);
157 ULONG ref = InterlockedDecrement(&This->filter.refCount);
159 TRACE("(%p) ref=%d\n", This, ref);
161 if (!ref)
163 IPin *conn = NULL;
165 TRACE("destroying everything\n");
166 if (This->init)
168 if (This->filter.state != State_Stopped)
169 qcap_driver_stop(This->driver_info, &This->filter.state);
170 qcap_driver_destroy(This->driver_info);
172 IPin_ConnectedTo(This->pOutputPin, &conn);
173 if (conn)
175 IPin_Disconnect(conn);
176 IPin_Disconnect(This->pOutputPin);
177 IPin_Release(conn);
179 IPin_Release(This->pOutputPin);
180 BaseFilter_Destroy(&This->filter);
181 CoTaskMemFree(This);
182 ObjectRefCount(FALSE);
185 return ref;
188 static const IUnknownVtbl unknown_inner_vtbl =
190 unknown_inner_QueryInterface,
191 unknown_inner_AddRef,
192 unknown_inner_Release,
195 static IPin* WINAPI VfwCapture_GetPin(BaseFilter *iface, int pos)
197 VfwCapture *This = impl_from_BaseFilter(iface);
199 if (pos >= 1 || pos < 0)
200 return NULL;
202 IPin_AddRef(This->pOutputPin);
203 return This->pOutputPin;
206 static LONG WINAPI VfwCapture_GetPinCount(BaseFilter *iface)
208 return 1;
211 static const BaseFilterFuncTable BaseFuncTable = {
212 VfwCapture_GetPin,
213 VfwCapture_GetPinCount
216 IUnknown * WINAPI QCAP_createVFWCaptureFilter(IUnknown *pUnkOuter, HRESULT *phr)
218 VfwCapture *pVfwCapture;
219 HRESULT hr;
221 TRACE("%p - %p\n", pUnkOuter, phr);
223 *phr = E_OUTOFMEMORY;
224 pVfwCapture = CoTaskMemAlloc( sizeof(VfwCapture) );
225 if (!pVfwCapture)
226 return NULL;
228 BaseFilter_Init(&pVfwCapture->filter, &VfwCapture_Vtbl, &CLSID_VfwCapture, (DWORD_PTR)(__FILE__ ": VfwCapture.csFilter"), &BaseFuncTable);
230 pVfwCapture->IUnknown_inner.lpVtbl = &unknown_inner_vtbl;
231 pVfwCapture->IAMStreamConfig_iface.lpVtbl = &IAMStreamConfig_VTable;
232 pVfwCapture->IAMVideoProcAmp_iface.lpVtbl = &IAMVideoProcAmp_VTable;
233 pVfwCapture->IPersistPropertyBag_iface.lpVtbl = &IPersistPropertyBag_VTable;
234 pVfwCapture->init = FALSE;
236 if (pUnkOuter)
237 pVfwCapture->outer_unk = pUnkOuter;
238 else
239 pVfwCapture->outer_unk = &pVfwCapture->IUnknown_inner;
241 hr = VfwPin_Construct(&pVfwCapture->filter.IBaseFilter_iface,
242 &pVfwCapture->filter.csFilter, &pVfwCapture->pOutputPin);
243 if (FAILED(hr))
245 CoTaskMemFree(pVfwCapture);
246 return NULL;
248 TRACE("-- created at %p\n", pVfwCapture);
250 ObjectRefCount(TRUE);
251 *phr = S_OK;
252 return &pVfwCapture->IUnknown_inner;
255 static HRESULT WINAPI VfwCapture_QueryInterface(IBaseFilter *iface, REFIID riid, void **ret_iface)
257 VfwCapture *This = impl_from_IBaseFilter(iface);
259 return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface);
262 static ULONG WINAPI VfwCapture_AddRef(IBaseFilter *iface)
264 VfwCapture *This = impl_from_IBaseFilter(iface);
266 return IUnknown_AddRef(This->outer_unk);
269 static ULONG WINAPI VfwCapture_Release(IBaseFilter * iface)
271 VfwCapture *This = impl_from_IBaseFilter(iface);
273 return IUnknown_Release(This->outer_unk);
276 /** IMediaFilter methods **/
278 static HRESULT WINAPI VfwCapture_Stop(IBaseFilter * iface)
280 VfwCapture *This = impl_from_IBaseFilter(iface);
282 TRACE("()\n");
283 return qcap_driver_stop(This->driver_info, &This->filter.state);
286 static HRESULT WINAPI VfwCapture_Pause(IBaseFilter * iface)
288 VfwCapture *This = impl_from_IBaseFilter(iface);
290 TRACE("()\n");
291 return qcap_driver_pause(This->driver_info, &This->filter.state);
294 static HRESULT WINAPI VfwCapture_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
296 VfwCapture *This = impl_from_IBaseFilter(iface);
297 TRACE("(%x%08x)\n", (ULONG)(tStart >> 32), (ULONG)tStart);
298 return qcap_driver_run(This->driver_info, &This->filter.state);
301 /** IBaseFilter methods **/
302 static HRESULT WINAPI VfwCapture_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
304 FIXME("(%s, %p) - stub\n", debugstr_w(Id), ppPin);
305 return E_NOTIMPL;
308 static const IBaseFilterVtbl VfwCapture_Vtbl =
310 VfwCapture_QueryInterface,
311 VfwCapture_AddRef,
312 VfwCapture_Release,
313 BaseFilterImpl_GetClassID,
314 VfwCapture_Stop,
315 VfwCapture_Pause,
316 VfwCapture_Run,
317 BaseFilterImpl_GetState,
318 BaseFilterImpl_SetSyncSource,
319 BaseFilterImpl_GetSyncSource,
320 BaseFilterImpl_EnumPins,
321 VfwCapture_FindPin,
322 BaseFilterImpl_QueryFilterInfo,
323 BaseFilterImpl_JoinFilterGraph,
324 BaseFilterImpl_QueryVendorInfo
327 /* AMStreamConfig interface, we only need to implement {G,S}etFormat */
328 static HRESULT WINAPI AMStreamConfig_QueryInterface(IAMStreamConfig *iface, REFIID riid,
329 void **ret_iface)
331 VfwCapture *This = impl_from_IAMStreamConfig(iface);
333 return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface);
336 static ULONG WINAPI AMStreamConfig_AddRef( IAMStreamConfig * iface )
338 VfwCapture *This = impl_from_IAMStreamConfig(iface);
340 return IUnknown_AddRef(This->outer_unk);
343 static ULONG WINAPI AMStreamConfig_Release( IAMStreamConfig * iface )
345 VfwCapture *This = impl_from_IAMStreamConfig(iface);
347 return IUnknown_Release(This->outer_unk);
350 static HRESULT WINAPI
351 AMStreamConfig_SetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE *pmt)
353 HRESULT hr;
354 VfwCapture *This = impl_from_IAMStreamConfig(iface);
355 BasePin *pin;
357 TRACE("(%p): %p->%p\n", iface, pmt, pmt ? pmt->pbFormat : NULL);
359 if (This->filter.state != State_Stopped)
361 TRACE("Returning not stopped error\n");
362 return VFW_E_NOT_STOPPED;
365 if (!pmt)
367 TRACE("pmt is NULL\n");
368 return E_POINTER;
371 dump_AM_MEDIA_TYPE(pmt);
373 pin = (BasePin *)This->pOutputPin;
374 if (pin->pConnectedTo != NULL)
376 hr = IPin_QueryAccept(pin->pConnectedTo, pmt);
377 TRACE("Would accept: %d\n", hr);
378 if (hr == S_FALSE)
379 return VFW_E_INVALIDMEDIATYPE;
382 hr = qcap_driver_set_format(This->driver_info, pmt);
383 if (SUCCEEDED(hr) && This->filter.filterInfo.pGraph && pin->pConnectedTo )
385 hr = IFilterGraph_Reconnect(This->filter.filterInfo.pGraph, This->pOutputPin);
386 if (SUCCEEDED(hr))
387 TRACE("Reconnection completed, with new media format..\n");
389 TRACE("Returning: %d\n", hr);
390 return hr;
393 static HRESULT WINAPI
394 AMStreamConfig_GetFormat( IAMStreamConfig *iface, AM_MEDIA_TYPE **pmt )
396 VfwCapture *This = impl_from_IAMStreamConfig(iface);
398 TRACE("%p -> (%p)\n", iface, pmt);
399 return qcap_driver_get_format(This->driver_info, pmt);
402 static HRESULT WINAPI
403 AMStreamConfig_GetNumberOfCapabilities( IAMStreamConfig *iface, int *piCount,
404 int *piSize )
406 FIXME("%p: %p %p - stub, intentional\n", iface, piCount, piSize);
407 *piCount = 0;
408 return E_NOTIMPL; /* Not implemented for this interface */
411 static HRESULT WINAPI
412 AMStreamConfig_GetStreamCaps( IAMStreamConfig *iface, int iIndex,
413 AM_MEDIA_TYPE **pmt, BYTE *pSCC )
415 FIXME("%p: %d %p %p - stub, intentional\n", iface, iIndex, pmt, pSCC);
416 return E_NOTIMPL; /* Not implemented for this interface */
419 static const IAMStreamConfigVtbl IAMStreamConfig_VTable =
421 AMStreamConfig_QueryInterface,
422 AMStreamConfig_AddRef,
423 AMStreamConfig_Release,
424 AMStreamConfig_SetFormat,
425 AMStreamConfig_GetFormat,
426 AMStreamConfig_GetNumberOfCapabilities,
427 AMStreamConfig_GetStreamCaps
430 static HRESULT WINAPI AMVideoProcAmp_QueryInterface(IAMVideoProcAmp *iface, REFIID riid,
431 void **ret_iface)
433 VfwCapture *This = impl_from_IAMVideoProcAmp(iface);
435 return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface);
438 static ULONG WINAPI AMVideoProcAmp_AddRef(IAMVideoProcAmp * iface)
440 VfwCapture *This = impl_from_IAMVideoProcAmp(iface);
442 return IUnknown_AddRef(This->outer_unk);
445 static ULONG WINAPI AMVideoProcAmp_Release(IAMVideoProcAmp * iface)
447 VfwCapture *This = impl_from_IAMVideoProcAmp(iface);
449 return IUnknown_Release(This->outer_unk);
452 static HRESULT WINAPI
453 AMVideoProcAmp_GetRange( IAMVideoProcAmp * iface, LONG Property, LONG *pMin,
454 LONG *pMax, LONG *pSteppingDelta, LONG *pDefault, LONG *pCapsFlags )
456 VfwCapture *This = impl_from_IAMVideoProcAmp(iface);
458 return qcap_driver_get_prop_range( This->driver_info, Property, pMin, pMax,
459 pSteppingDelta, pDefault, pCapsFlags );
462 static HRESULT WINAPI
463 AMVideoProcAmp_Set( IAMVideoProcAmp * iface, LONG Property, LONG lValue,
464 LONG Flags )
466 VfwCapture *This = impl_from_IAMVideoProcAmp(iface);
468 return qcap_driver_set_prop(This->driver_info, Property, lValue, Flags);
471 static HRESULT WINAPI
472 AMVideoProcAmp_Get( IAMVideoProcAmp * iface, LONG Property, LONG *lValue,
473 LONG *Flags )
475 VfwCapture *This = impl_from_IAMVideoProcAmp(iface);
477 return qcap_driver_get_prop(This->driver_info, Property, lValue, Flags);
480 static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable =
482 AMVideoProcAmp_QueryInterface,
483 AMVideoProcAmp_AddRef,
484 AMVideoProcAmp_Release,
485 AMVideoProcAmp_GetRange,
486 AMVideoProcAmp_Set,
487 AMVideoProcAmp_Get,
490 static HRESULT WINAPI PPB_QueryInterface(IPersistPropertyBag *iface, REFIID riid, void **ret_iface)
492 VfwCapture *This = impl_from_IPersistPropertyBag(iface);
494 return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface);
497 static ULONG WINAPI PPB_AddRef(IPersistPropertyBag * iface)
499 VfwCapture *This = impl_from_IPersistPropertyBag(iface);
501 return IUnknown_AddRef(This->outer_unk);
504 static ULONG WINAPI PPB_Release(IPersistPropertyBag * iface)
506 VfwCapture *This = impl_from_IPersistPropertyBag(iface);
508 return IUnknown_Release(This->outer_unk);
511 static HRESULT WINAPI
512 PPB_GetClassID( IPersistPropertyBag * iface, CLSID * pClassID )
514 VfwCapture *This = impl_from_IPersistPropertyBag(iface);
516 FIXME("%p - stub\n", This);
518 return E_NOTIMPL;
521 static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag * iface)
523 VfwCapture *This = impl_from_IPersistPropertyBag(iface);
525 FIXME("%p - stub\n", This);
527 return E_NOTIMPL;
530 static HRESULT WINAPI
531 PPB_Load( IPersistPropertyBag * iface, IPropertyBag *pPropBag,
532 IErrorLog *pErrorLog )
534 VfwCapture *This = impl_from_IPersistPropertyBag(iface);
535 HRESULT hr;
536 VARIANT var;
537 const OLECHAR VFWIndex[] = {'V','F','W','I','n','d','e','x',0};
539 TRACE("%p/%p-> (%p, %p)\n", iface, This, pPropBag, pErrorLog);
541 V_VT(&var) = VT_I4;
542 hr = IPropertyBag_Read(pPropBag, VFWIndex, &var, pErrorLog);
544 if (SUCCEEDED(hr))
546 VfwPinImpl *pin;
548 This->driver_info = qcap_driver_init( This->pOutputPin,
549 var.__VARIANT_NAME_1.__VARIANT_NAME_2.__VARIANT_NAME_3.ulVal );
550 if (This->driver_info)
552 pin = (VfwPinImpl *)This->pOutputPin;
553 pin->parent = This;
554 This->init = TRUE;
555 hr = S_OK;
557 else
558 hr = E_FAIL;
561 return hr;
564 static HRESULT WINAPI
565 PPB_Save( IPersistPropertyBag * iface, IPropertyBag *pPropBag,
566 BOOL fClearDirty, BOOL fSaveAllProperties )
568 VfwCapture *This = impl_from_IPersistPropertyBag(iface);
569 FIXME("%p - stub\n", This);
570 return E_NOTIMPL;
573 static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable =
575 PPB_QueryInterface,
576 PPB_AddRef,
577 PPB_Release,
578 PPB_GetClassID,
579 PPB_InitNew,
580 PPB_Load,
581 PPB_Save
584 /* IKsPropertySet interface */
585 static inline VfwPinImpl *impl_from_IKsPropertySet(IKsPropertySet *iface)
587 return CONTAINING_RECORD(iface, VfwPinImpl, IKsPropertySet_iface);
590 static HRESULT WINAPI KSP_QueryInterface(IKsPropertySet * iface, REFIID riid, void **ret_iface)
592 VfwPinImpl *This = impl_from_IKsPropertySet(iface);
594 return IPin_QueryInterface(&This->pin.pin.IPin_iface, riid, ret_iface);
597 static ULONG WINAPI KSP_AddRef(IKsPropertySet * iface)
599 VfwPinImpl *This = impl_from_IKsPropertySet(iface);
601 return IPin_AddRef(&This->pin.pin.IPin_iface);
604 static ULONG WINAPI KSP_Release(IKsPropertySet * iface)
606 VfwPinImpl *This = impl_from_IKsPropertySet(iface);
608 return IPin_Release(&This->pin.pin.IPin_iface);
611 static HRESULT WINAPI
612 KSP_Set( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
613 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
614 DWORD cbPropData )
616 FIXME("%p: stub\n", iface);
617 return E_NOTIMPL;
620 static HRESULT WINAPI
621 KSP_Get( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID,
622 LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData,
623 DWORD cbPropData, DWORD *pcbReturned )
625 LPGUID pGuid;
627 TRACE("()\n");
629 if (!IsEqualIID(guidPropSet, &AMPROPSETID_Pin))
630 return E_PROP_SET_UNSUPPORTED;
631 if (pPropData == NULL && pcbReturned == NULL)
632 return E_POINTER;
633 if (pcbReturned)
634 *pcbReturned = sizeof(GUID);
635 if (pPropData == NULL)
636 return S_OK;
637 if (cbPropData < sizeof(GUID))
638 return E_UNEXPECTED;
639 pGuid = pPropData;
640 *pGuid = PIN_CATEGORY_CAPTURE;
641 FIXME("() Not adding a pin with PIN_CATEGORY_PREVIEW\n");
642 return S_OK;
645 static HRESULT WINAPI
646 KSP_QuerySupported( IKsPropertySet * iface, REFGUID guidPropSet,
647 DWORD dwPropID, DWORD *pTypeSupport )
649 FIXME("%p: stub\n", iface);
650 return E_NOTIMPL;
653 static const IKsPropertySetVtbl IKsPropertySet_VTable =
655 KSP_QueryInterface,
656 KSP_AddRef,
657 KSP_Release,
658 KSP_Set,
659 KSP_Get,
660 KSP_QuerySupported
663 static inline VfwPinImpl *impl_from_BasePin(BasePin *pin)
665 return CONTAINING_RECORD(pin, VfwPinImpl, pin.pin);
668 static HRESULT WINAPI VfwPin_GetMediaType(BasePin *pin, int iPosition, AM_MEDIA_TYPE *pmt)
670 VfwPinImpl *This = impl_from_BasePin(pin);
671 AM_MEDIA_TYPE *vfw_pmt;
672 HRESULT hr;
674 if (iPosition < 0)
675 return E_INVALIDARG;
676 if (iPosition > 0)
677 return VFW_S_NO_MORE_ITEMS;
679 hr = qcap_driver_get_format(This->parent->driver_info, &vfw_pmt);
680 if (SUCCEEDED(hr)) {
681 CopyMediaType(pmt, vfw_pmt);
682 DeleteMediaType(vfw_pmt);
684 return hr;
687 static LONG WINAPI VfwPin_GetMediaTypeVersion(BasePin *iface)
689 return 1;
692 static HRESULT WINAPI VfwPin_DecideBufferSize(BaseOutputPin *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
694 ALLOCATOR_PROPERTIES actual;
696 /* What we put here doesn't matter, the
697 driver function should override it then commit */
698 if (!ppropInputRequest->cBuffers)
699 ppropInputRequest->cBuffers = 3;
700 if (!ppropInputRequest->cbBuffer)
701 ppropInputRequest->cbBuffer = 230400;
702 if (!ppropInputRequest->cbAlign)
703 ppropInputRequest->cbAlign = 1;
705 return IMemAllocator_SetProperties(pAlloc, ppropInputRequest, &actual);
708 static const BaseOutputPinFuncTable output_BaseOutputFuncTable = {
710 NULL,
711 BaseOutputPinImpl_AttemptConnection,
712 VfwPin_GetMediaTypeVersion,
713 VfwPin_GetMediaType
715 VfwPin_DecideBufferSize,
716 BaseOutputPinImpl_DecideAllocator,
717 BaseOutputPinImpl_BreakConnect
720 static HRESULT
721 VfwPin_Construct( IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec,
722 IPin ** ppPin )
724 static const WCHAR wszOutputPinName[] = { 'O','u','t','p','u','t',0 };
725 PIN_INFO piOutput;
726 HRESULT hr;
728 *ppPin = NULL;
730 piOutput.dir = PINDIR_OUTPUT;
731 piOutput.pFilter = pBaseFilter;
732 lstrcpyW(piOutput.achName, wszOutputPinName);
734 hr = BaseOutputPin_Construct(&VfwPin_Vtbl, sizeof(VfwPinImpl), &piOutput, &output_BaseOutputFuncTable, pCritSec, ppPin);
736 if (SUCCEEDED(hr))
738 VfwPinImpl *pPinImpl = (VfwPinImpl*)*ppPin;
739 pPinImpl->IKsPropertySet_iface.lpVtbl = &IKsPropertySet_VTable;
740 ObjectRefCount(TRUE);
743 return hr;
746 static inline VfwPinImpl *impl_from_IPin(IPin *iface)
748 return CONTAINING_RECORD(iface, VfwPinImpl, pin.pin.IPin_iface);
751 static HRESULT WINAPI VfwPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
753 VfwPinImpl *This = impl_from_IPin(iface);
755 TRACE("%s %p\n", debugstr_guid(riid), ppv);
757 *ppv = NULL;
758 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin))
759 *ppv = This;
760 else if (IsEqualIID(riid, &IID_IKsPropertySet))
761 *ppv = &This->IKsPropertySet_iface;
762 else if (IsEqualIID(riid, &IID_IAMStreamConfig))
763 return IUnknown_QueryInterface((IUnknown *)This->parent, riid, ppv);
765 if (*ppv)
767 IUnknown_AddRef((IUnknown *)(*ppv));
768 return S_OK;
771 FIXME("No interface for %s!\n", debugstr_guid(riid));
772 return E_NOINTERFACE;
775 static ULONG WINAPI
776 VfwPin_Release(IPin * iface)
778 VfwPinImpl *This = impl_from_IPin(iface);
779 ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
781 TRACE("() -> new refcount: %u\n", refCount);
783 if (!refCount)
785 BaseOutputPin_Destroy(&This->pin);
786 ObjectRefCount(FALSE);
788 return refCount;
791 static HRESULT WINAPI
792 VfwPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
794 VfwPinImpl *This = impl_from_IPin(iface);
795 AM_MEDIA_TYPE *pmt;
796 HRESULT hr;
798 hr = qcap_driver_get_format(This->parent->driver_info, &pmt);
799 if (SUCCEEDED(hr)) {
800 hr = BasePinImpl_EnumMediaTypes(iface, ppEnum);
801 DeleteMediaType(pmt);
803 TRACE("%p -- %x\n", This, hr);
804 return hr;
807 static HRESULT WINAPI
808 VfwPin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
810 TRACE("(%p)->(%p, %p)\n", iface, apPin, cPin);
811 return E_NOTIMPL;
814 static const IPinVtbl VfwPin_Vtbl =
816 VfwPin_QueryInterface,
817 BasePinImpl_AddRef,
818 VfwPin_Release,
819 BaseOutputPinImpl_Connect,
820 BaseOutputPinImpl_ReceiveConnection,
821 BaseOutputPinImpl_Disconnect,
822 BasePinImpl_ConnectedTo,
823 BasePinImpl_ConnectionMediaType,
824 BasePinImpl_QueryPinInfo,
825 BasePinImpl_QueryDirection,
826 BasePinImpl_QueryId,
827 BasePinImpl_QueryAccept,
828 VfwPin_EnumMediaTypes,
829 VfwPin_QueryInternalConnections,
830 BaseOutputPinImpl_EndOfStream,
831 BaseOutputPinImpl_BeginFlush,
832 BaseOutputPinImpl_EndFlush,
833 BasePinImpl_NewSegment