| /* Video For Windows Steering structure |
| * |
| * Copyright 2005 Maarten Lankhorst |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| * |
| */ |
| |
| #define NONAMELESSSTRUCT |
| #define NONAMELESSUNION |
| #define COBJMACROS |
| |
| #include "config.h" |
| #include <stdarg.h> |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wtypes.h" |
| #include "wingdi.h" |
| #include "winuser.h" |
| #include "dshow.h" |
| |
| #include "qcap_main.h" |
| #include "wine/debug.h" |
| |
| #include "pin.h" |
| #include "capture.h" |
| #include "uuids.h" |
| #include "vfwmsgs.h" |
| #include "amvideo.h" |
| #include "strmif.h" |
| #include "ddraw.h" |
| #include "ocidl.h" |
| #include "oleauto.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(qcap); |
| |
| #define ICOM_THIS_MULTI(impl,field,iface) \ |
| impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) |
| |
| static const IBaseFilterVtbl VfwCapture_Vtbl; |
| static const IAMStreamConfigVtbl IAMStreamConfig_VTable; |
| static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable; |
| static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable; |
| static const IPinVtbl VfwPin_Vtbl; |
| |
| static HRESULT VfwPin_Construct( IBaseFilter *, LPCRITICAL_SECTION, IPin ** ); |
| |
| typedef struct VfwCapture |
| { |
| const IBaseFilterVtbl * lpVtbl; |
| const IAMStreamConfigVtbl * IAMStreamConfig_vtbl; |
| const IAMVideoProcAmpVtbl * IAMVideoProcAmp_vtbl; |
| const IPersistPropertyBagVtbl * IPersistPropertyBag_vtbl; |
| |
| BOOL init; |
| Capture *driver_info; |
| LONG refCount; |
| FILTER_INFO filterInfo; |
| FILTER_STATE state; |
| CRITICAL_SECTION csFilter; |
| |
| IPin * pOutputPin; |
| } VfwCapture; |
| |
| /* VfwPin implementation */ |
| typedef struct VfwPinImpl |
| { |
| OutputPin pin; |
| Capture *driver_info; |
| VfwCapture *parent; |
| const IKsPropertySetVtbl * KSP_VT; |
| } VfwPinImpl; |
| |
| |
| IUnknown * WINAPI QCAP_createVFWCaptureFilter(IUnknown *pUnkOuter, HRESULT *phr) |
| { |
| VfwCapture *pVfwCapture; |
| HRESULT hr; |
| |
| TRACE("%p - %p\n", pUnkOuter, phr); |
| |
| *phr = CLASS_E_NOAGGREGATION; |
| if (pUnkOuter) |
| return NULL; |
| *phr = E_OUTOFMEMORY; |
| |
| pVfwCapture = CoTaskMemAlloc( sizeof(VfwCapture) ); |
| |
| if (!pVfwCapture) |
| return NULL; |
| |
| pVfwCapture->lpVtbl = &VfwCapture_Vtbl; |
| pVfwCapture->IAMStreamConfig_vtbl = &IAMStreamConfig_VTable; |
| pVfwCapture->IAMVideoProcAmp_vtbl = &IAMVideoProcAmp_VTable; |
| pVfwCapture->IPersistPropertyBag_vtbl = &IPersistPropertyBag_VTable; |
| pVfwCapture->refCount = 1; |
| pVfwCapture->filterInfo.achName[0] = '\0'; |
| pVfwCapture->filterInfo.pGraph = NULL; |
| pVfwCapture->state = State_Stopped; |
| pVfwCapture->init = FALSE; |
| InitializeCriticalSection(&pVfwCapture->csFilter); |
| pVfwCapture->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": VfwCapture.csFilter"); |
| hr = VfwPin_Construct((IBaseFilter *)&pVfwCapture->lpVtbl, |
| &pVfwCapture->csFilter, &pVfwCapture->pOutputPin); |
| if (FAILED(hr)) |
| { |
| CoTaskMemFree(pVfwCapture); |
| return NULL; |
| } |
| TRACE("-- created at %p\n", pVfwCapture); |
| |
| ObjectRefCount(TRUE); |
| *phr = S_OK; |
| return (IUnknown *)pVfwCapture; |
| } |
| |
| static HRESULT WINAPI VfwCapture_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) |
| { |
| VfwCapture *This = (VfwCapture *)iface; |
| TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); |
| *ppv = NULL; |
| |
| if (IsEqualIID(riid, &IID_IUnknown) || |
| IsEqualIID(riid, &IID_IPersist) || |
| IsEqualIID(riid, &IID_IMediaFilter) || |
| IsEqualIID(riid, &IID_IBaseFilter)) |
| { |
| *ppv = This; |
| } |
| else if (IsEqualIID(riid, &IID_IAMStreamConfig)) |
| *ppv = &(This->IAMStreamConfig_vtbl); |
| else if (IsEqualIID(riid, &IID_IAMVideoProcAmp)) |
| *ppv = &(This->IAMVideoProcAmp_vtbl); |
| else if (IsEqualIID(riid, &IID_IPersistPropertyBag)) |
| *ppv = &(This->IPersistPropertyBag_vtbl); |
| |
| if (!IsEqualIID(riid, &IID_IUnknown) && |
| !IsEqualIID(riid, &IID_IPersist) && |
| !IsEqualIID(riid, &IID_IPersistPropertyBag) && |
| !This->init) |
| { |
| FIXME("Capture system not initialised when looking for %s, " |
| "trying it on primary device now\n", debugstr_guid(riid)); |
| This->driver_info = qcap_driver_init( This->pOutputPin, 0 ); |
| if (!This->driver_info) |
| { |
| ERR("VfwCapture initialisation failed\n"); |
| return E_UNEXPECTED; |
| } |
| This->init = TRUE; |
| } |
| |
| if (*ppv) |
| { |
| TRACE("Returning %s interface\n", debugstr_guid(riid)); |
| IUnknown_AddRef((IUnknown *)(*ppv)); |
| return S_OK; |
| } |
| |
| FIXME("No interface for %s!\n", debugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI VfwCapture_AddRef(IBaseFilter * iface) |
| { |
| VfwCapture *This = (VfwCapture *)iface; |
| ULONG refCount = InterlockedIncrement(&This->refCount); |
| |
| TRACE("%p->() New refcount: %d\n", This, refCount); |
| |
| return refCount; |
| } |
| |
| static ULONG WINAPI VfwCapture_Release(IBaseFilter * iface) |
| { |
| VfwCapture *This = (VfwCapture *)iface; |
| ULONG refCount = InterlockedDecrement(&This->refCount); |
| |
| TRACE("%p->() New refcount: %d\n", This, refCount); |
| |
| if (!refCount) |
| { |
| BasePin *pin; |
| |
| TRACE("destroying everything\n"); |
| if (This->init) |
| { |
| if (This->state != State_Stopped) |
| qcap_driver_stop(This->driver_info, &This->state); |
| qcap_driver_destroy(This->driver_info); |
| } |
| pin = (BasePin*) This->pOutputPin; |
| if (pin->pConnectedTo != NULL) |
| { |
| IPin_Disconnect(pin->pConnectedTo); |
| IPin_Disconnect(This->pOutputPin); |
| } |
| IPin_Release(This->pOutputPin); |
| This->csFilter.DebugInfo->Spare[0] = 0; |
| DeleteCriticalSection(&This->csFilter); |
| This->lpVtbl = NULL; |
| CoTaskMemFree(This); |
| ObjectRefCount(FALSE); |
| } |
| return refCount; |
| } |
| |
| /** IPersist methods **/ |
| |
| static HRESULT WINAPI VfwCapture_GetClassID(IBaseFilter * iface, CLSID * pClsid) |
| { |
| TRACE("(%p)\n", pClsid); |
| *pClsid = CLSID_VfwCapture; |
| return S_OK; |
| } |
| |
| /** IMediaFilter methods **/ |
| |
| static HRESULT WINAPI VfwCapture_Stop(IBaseFilter * iface) |
| { |
| VfwCapture *This = (VfwCapture *)iface; |
| |
| TRACE("()\n"); |
| return qcap_driver_stop(This->driver_info, &This->state); |
| } |
| |
| static HRESULT WINAPI VfwCapture_Pause(IBaseFilter * iface) |
| { |
| VfwCapture *This = (VfwCapture *)iface; |
| |
| TRACE("()\n"); |
| return qcap_driver_pause(This->driver_info, &This->state); |
| } |
| |
| static HRESULT WINAPI VfwCapture_Run(IBaseFilter * iface, REFERENCE_TIME tStart) |
| { |
| VfwCapture *This = (VfwCapture *)iface; |
| TRACE("(%x%08x)\n", (ULONG)(tStart >> 32), (ULONG)tStart); |
| return qcap_driver_run(This->driver_info, &This->state); |
| } |
| |
| static HRESULT WINAPI |
| VfwCapture_GetState( IBaseFilter * iface, DWORD dwMilliSecsTimeout, |
| FILTER_STATE *pState ) |
| { |
| VfwCapture *This = (VfwCapture *)iface; |
| |
| TRACE("(%u, %p)\n", dwMilliSecsTimeout, pState); |
| |
| *pState = This->state; |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI |
| VfwCapture_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) |
| { |
| TRACE("(%p)\n", pClock); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI |
| VfwCapture_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock) |
| { |
| TRACE("(%p)\n", ppClock); |
| |
| return S_OK; |
| } |
| |
| /** IBaseFilter methods **/ |
| static IPin* WINAPI VfwCapture_GetPin(IBaseFilter *iface, int pos) |
| { |
| VfwCapture *This = (VfwCapture *)iface; |
| |
| if (pos >= 1 || pos < 0) |
| return NULL; |
| |
| IPin_AddRef(This->pOutputPin); |
| return This->pOutputPin; |
| } |
| |
| static LONG WINAPI VfwCapture_GetPinCount(IBaseFilter *iface) |
| { |
| return 1; |
| } |
| |
| static LONG WINAPI VfwCapture_GetPinVersion(IBaseFilter *iface) |
| { |
| /* Our pins are static, not changing so setting static tick count is ok */ |
| return 0; |
| } |
| |
| static HRESULT WINAPI |
| VfwCapture_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum) |
| { |
| TRACE("(%p)\n", ppEnum); |
| |
| return EnumPins_Construct(iface, VfwCapture_GetPin, VfwCapture_GetPinCount, VfwCapture_GetPinVersion, ppEnum); |
| } |
| |
| static HRESULT WINAPI VfwCapture_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin) |
| { |
| FIXME("(%s, %p) - stub\n", debugstr_w(Id), ppPin); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI VfwCapture_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo) |
| { |
| VfwCapture *This = (VfwCapture *)iface; |
| |
| TRACE("(%p)\n", pInfo); |
| |
| lstrcpyW(pInfo->achName, This->filterInfo.achName); |
| pInfo->pGraph = This->filterInfo.pGraph; |
| |
| if (pInfo->pGraph) |
| IFilterGraph_AddRef(pInfo->pGraph); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI |
| VfwCapture_JoinFilterGraph( IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName ) |
| { |
| VfwCapture *This = (VfwCapture *)iface; |
| |
| TRACE("(%p, %s)\n", pGraph, debugstr_w(pName)); |
| |
| if (pName) |
| lstrcpyW(This->filterInfo.achName, pName); |
| else |
| *This->filterInfo.achName = 0; |
| This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */ |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI |
| VfwCapture_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo) |
| { |
| FIXME("(%p) - stub\n", pVendorInfo); |
| return E_NOTIMPL; |
| } |
| |
| static const IBaseFilterVtbl VfwCapture_Vtbl = |
| { |
| VfwCapture_QueryInterface, |
| VfwCapture_AddRef, |
| VfwCapture_Release, |
| VfwCapture_GetClassID, |
| VfwCapture_Stop, |
| VfwCapture_Pause, |
| VfwCapture_Run, |
| VfwCapture_GetState, |
| VfwCapture_SetSyncSource, |
| VfwCapture_GetSyncSource, |
| VfwCapture_EnumPins, |
| VfwCapture_FindPin, |
| VfwCapture_QueryFilterInfo, |
| VfwCapture_JoinFilterGraph, |
| VfwCapture_QueryVendorInfo |
| }; |
| |
| /* AMStreamConfig interface, we only need to implement {G,S}etFormat */ |
| static HRESULT WINAPI |
| AMStreamConfig_QueryInterface( IAMStreamConfig * iface, REFIID riid, LPVOID * ppv ) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IAMStreamConfig_vtbl, iface); |
| |
| TRACE("%p --> %s\n", This, debugstr_guid(riid)); |
| |
| if (IsEqualIID(riid, &IID_IUnknown) || |
| IsEqualIID(riid, &IID_IAMStreamConfig)) |
| { |
| IAMStreamConfig_AddRef(iface); |
| *ppv = iface; |
| return S_OK; |
| } |
| |
| FIXME("No interface for iid %s\n", debugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI AMStreamConfig_AddRef( IAMStreamConfig * iface ) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IAMStreamConfig_vtbl, iface); |
| |
| TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This); |
| return IUnknown_AddRef((IUnknown *)This); |
| } |
| |
| static ULONG WINAPI AMStreamConfig_Release( IAMStreamConfig * iface ) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IAMStreamConfig_vtbl, iface); |
| |
| TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This); |
| return IUnknown_Release((IUnknown *)This); |
| } |
| |
| static HRESULT WINAPI |
| AMStreamConfig_SetFormat(IAMStreamConfig *iface, AM_MEDIA_TYPE *pmt) |
| { |
| HRESULT hr; |
| ICOM_THIS_MULTI(VfwCapture, IAMStreamConfig_vtbl, iface); |
| BasePin *pin; |
| |
| TRACE("(%p): %p->%p\n", iface, pmt, pmt ? pmt->pbFormat : NULL); |
| |
| if (This->state != State_Stopped) |
| { |
| TRACE("Returning not stopped error\n"); |
| return VFW_E_NOT_STOPPED; |
| } |
| |
| if (!pmt) |
| { |
| TRACE("pmt is NULL\n"); |
| return E_POINTER; |
| } |
| |
| dump_AM_MEDIA_TYPE(pmt); |
| |
| pin = (BasePin *)This->pOutputPin; |
| if (pin->pConnectedTo != NULL) |
| { |
| hr = IPin_QueryAccept(pin->pConnectedTo, pmt); |
| TRACE("Would accept: %d\n", hr); |
| if (hr == S_FALSE) |
| return VFW_E_INVALIDMEDIATYPE; |
| } |
| |
| hr = qcap_driver_set_format(This->driver_info, pmt); |
| if (SUCCEEDED(hr) && This->filterInfo.pGraph && pin->pConnectedTo ) |
| { |
| hr = IFilterGraph_Reconnect(This->filterInfo.pGraph, This->pOutputPin); |
| if (SUCCEEDED(hr)) |
| TRACE("Reconnection completed, with new media format..\n"); |
| } |
| TRACE("Returning: %d\n", hr); |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| AMStreamConfig_GetFormat( IAMStreamConfig *iface, AM_MEDIA_TYPE **pmt ) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IAMStreamConfig_vtbl, iface); |
| |
| TRACE("%p -> (%p)\n", iface, pmt); |
| return qcap_driver_get_format(This->driver_info, pmt); |
| } |
| |
| static HRESULT WINAPI |
| AMStreamConfig_GetNumberOfCapabilities( IAMStreamConfig *iface, int *piCount, |
| int *piSize ) |
| { |
| FIXME("%p: %p %p - stub, intentional\n", iface, piCount, piSize); |
| return E_NOTIMPL; /* Not implemented for this interface */ |
| } |
| |
| static HRESULT WINAPI |
| AMStreamConfig_GetStreamCaps( IAMStreamConfig *iface, int iIndex, |
| AM_MEDIA_TYPE **pmt, BYTE *pSCC ) |
| { |
| FIXME("%p: %d %p %p - stub, intentional\n", iface, iIndex, pmt, pSCC); |
| return E_NOTIMPL; /* Not implemented for this interface */ |
| } |
| |
| static const IAMStreamConfigVtbl IAMStreamConfig_VTable = |
| { |
| AMStreamConfig_QueryInterface, |
| AMStreamConfig_AddRef, |
| AMStreamConfig_Release, |
| AMStreamConfig_SetFormat, |
| AMStreamConfig_GetFormat, |
| AMStreamConfig_GetNumberOfCapabilities, |
| AMStreamConfig_GetStreamCaps |
| }; |
| |
| static HRESULT WINAPI |
| AMVideoProcAmp_QueryInterface( IAMVideoProcAmp * iface, REFIID riid, |
| LPVOID * ppv ) |
| { |
| if (IsEqualIID(riid, &IID_IUnknown) || |
| IsEqualIID(riid, &IID_IAMVideoProcAmp)) |
| { |
| *ppv = iface; |
| IAMVideoProcAmp_AddRef( iface ); |
| return S_OK; |
| } |
| |
| FIXME("No interface for iid %s\n", debugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI AMVideoProcAmp_AddRef(IAMVideoProcAmp * iface) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IAMVideoProcAmp_vtbl, iface); |
| |
| return IUnknown_AddRef((IUnknown *)This); |
| } |
| |
| static ULONG WINAPI AMVideoProcAmp_Release(IAMVideoProcAmp * iface) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IAMVideoProcAmp_vtbl, iface); |
| |
| return IUnknown_Release((IUnknown *)This); |
| } |
| |
| static HRESULT WINAPI |
| AMVideoProcAmp_GetRange( IAMVideoProcAmp * iface, LONG Property, LONG *pMin, |
| LONG *pMax, LONG *pSteppingDelta, LONG *pDefault, LONG *pCapsFlags ) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IAMVideoProcAmp_vtbl, iface); |
| |
| return qcap_driver_get_prop_range( This->driver_info, Property, pMin, pMax, |
| pSteppingDelta, pDefault, pCapsFlags ); |
| } |
| |
| static HRESULT WINAPI |
| AMVideoProcAmp_Set( IAMVideoProcAmp * iface, LONG Property, LONG lValue, |
| LONG Flags ) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IAMVideoProcAmp_vtbl, iface); |
| |
| return qcap_driver_set_prop(This->driver_info, Property, lValue, Flags); |
| } |
| |
| static HRESULT WINAPI |
| AMVideoProcAmp_Get( IAMVideoProcAmp * iface, LONG Property, LONG *lValue, |
| LONG *Flags ) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IAMVideoProcAmp_vtbl, iface); |
| |
| return qcap_driver_get_prop(This->driver_info, Property, lValue, Flags); |
| } |
| |
| static const IAMVideoProcAmpVtbl IAMVideoProcAmp_VTable = |
| { |
| AMVideoProcAmp_QueryInterface, |
| AMVideoProcAmp_AddRef, |
| AMVideoProcAmp_Release, |
| AMVideoProcAmp_GetRange, |
| AMVideoProcAmp_Set, |
| AMVideoProcAmp_Get, |
| }; |
| |
| static HRESULT WINAPI |
| PPB_QueryInterface( IPersistPropertyBag * iface, REFIID riid, LPVOID * ppv ) |
| { |
| if (IsEqualIID(riid, &IID_IUnknown) || |
| IsEqualIID(riid, &IID_IPersist) || |
| IsEqualIID(riid, &IID_IPersistPropertyBag)) |
| { |
| IPersistPropertyBag_AddRef(iface); |
| *ppv = iface; |
| return S_OK; |
| } |
| if (IsEqualIID(riid, &IID_IBaseFilter)) |
| { |
| /* FIXME: native devenum asks for IBaseFilter, should we return it? */ |
| IPersistPropertyBag_AddRef(iface); |
| *ppv = iface; |
| return S_OK; |
| } |
| |
| FIXME("No interface for iid %s\n", debugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI PPB_AddRef(IPersistPropertyBag * iface) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IPersistPropertyBag_vtbl, iface); |
| |
| TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This); |
| |
| return IUnknown_AddRef((IUnknown *)This); |
| } |
| |
| static ULONG WINAPI PPB_Release(IPersistPropertyBag * iface) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IPersistPropertyBag_vtbl, iface); |
| |
| TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This); |
| |
| return IUnknown_Release((IUnknown *)This); |
| } |
| |
| static HRESULT WINAPI |
| PPB_GetClassID( IPersistPropertyBag * iface, CLSID * pClassID ) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IPersistPropertyBag_vtbl, iface); |
| |
| FIXME("%p - stub\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI PPB_InitNew(IPersistPropertyBag * iface) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IPersistPropertyBag_vtbl, iface); |
| |
| FIXME("%p - stub\n", This); |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI |
| PPB_Load( IPersistPropertyBag * iface, IPropertyBag *pPropBag, |
| IErrorLog *pErrorLog ) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IPersistPropertyBag_vtbl, iface); |
| HRESULT hr; |
| VARIANT var; |
| const OLECHAR VFWIndex[] = {'V','F','W','I','n','d','e','x',0}; |
| |
| TRACE("%p/%p-> (%p, %p)\n", iface, This, pPropBag, pErrorLog); |
| |
| V_VT(&var) = VT_I4; |
| hr = IPropertyBag_Read(pPropBag, VFWIndex, &var, pErrorLog); |
| |
| if (SUCCEEDED(hr)) |
| { |
| VfwPinImpl *pin; |
| |
| This->driver_info = qcap_driver_init( This->pOutputPin, |
| var.__VARIANT_NAME_1.__VARIANT_NAME_2.__VARIANT_NAME_3.ulVal ); |
| if (This->driver_info) |
| { |
| pin = (VfwPinImpl *)This->pOutputPin; |
| pin->driver_info = This->driver_info; |
| pin->parent = This; |
| This->init = TRUE; |
| hr = S_OK; |
| } |
| else |
| hr = E_FAIL; |
| } |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| PPB_Save( IPersistPropertyBag * iface, IPropertyBag *pPropBag, |
| BOOL fClearDirty, BOOL fSaveAllProperties ) |
| { |
| ICOM_THIS_MULTI(VfwCapture, IPersistPropertyBag_vtbl, iface); |
| FIXME("%p - stub\n", This); |
| return E_NOTIMPL; |
| } |
| |
| static const IPersistPropertyBagVtbl IPersistPropertyBag_VTable = |
| { |
| PPB_QueryInterface, |
| PPB_AddRef, |
| PPB_Release, |
| PPB_GetClassID, |
| PPB_InitNew, |
| PPB_Load, |
| PPB_Save |
| }; |
| |
| /* IKsPropertySet interface */ |
| static HRESULT WINAPI |
| KSP_QueryInterface( IKsPropertySet * iface, REFIID riid, LPVOID * ppv ) |
| { |
| if (IsEqualIID(riid, &IID_IUnknown) || |
| IsEqualIID(riid, &IID_IKsPropertySet)) |
| { |
| *ppv = iface; |
| IKsPropertySet_AddRef( iface ); |
| return S_OK; |
| } |
| |
| FIXME("No interface for iid %s\n", debugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI KSP_AddRef(IKsPropertySet * iface) |
| { |
| ICOM_THIS_MULTI(VfwPinImpl, KSP_VT, iface); |
| |
| TRACE("%p --> Forwarding to VfwPin (%p)\n", iface, This); |
| |
| return IUnknown_AddRef((IUnknown *)This); |
| } |
| |
| static ULONG WINAPI KSP_Release(IKsPropertySet * iface) |
| { |
| ICOM_THIS_MULTI(VfwPinImpl, KSP_VT, iface); |
| |
| TRACE("%p --> Forwarding to VfwPin (%p)\n", iface, This); |
| |
| return IUnknown_Release((IUnknown *)This); |
| } |
| |
| static HRESULT WINAPI |
| KSP_Set( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID, |
| LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, |
| DWORD cbPropData ) |
| { |
| FIXME("%p: stub\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI |
| KSP_Get( IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID, |
| LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, |
| DWORD cbPropData, DWORD *pcbReturned ) |
| { |
| LPGUID pGuid; |
| |
| TRACE("()\n"); |
| |
| if (!IsEqualIID(guidPropSet, &ROPSETID_Pin)) |
| return E_PROP_SET_UNSUPPORTED; |
| if (pPropData == NULL && pcbReturned == NULL) |
| return E_POINTER; |
| if (pcbReturned) |
| *pcbReturned = sizeof(GUID); |
| if (pPropData == NULL) |
| return S_OK; |
| if (cbPropData < sizeof(GUID)) |
| return E_UNEXPECTED; |
| pGuid = pPropData; |
| *pGuid = PIN_CATEGORY_PREVIEW; |
| FIXME("() Not adding a pin with PIN_CATEGORY_CAPTURE\n"); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI |
| KSP_QuerySupported( IKsPropertySet * iface, REFGUID guidPropSet, |
| DWORD dwPropID, DWORD *pTypeSupport ) |
| { |
| FIXME("%p: stub\n", iface); |
| return E_NOTIMPL; |
| } |
| |
| static const IKsPropertySetVtbl KSP_VTable = |
| { |
| KSP_QueryInterface, |
| KSP_AddRef, |
| KSP_Release, |
| KSP_Set, |
| KSP_Get, |
| KSP_QuerySupported |
| }; |
| |
| static HRESULT WINAPI VfwPin_GetMediaType(IPin *iface, int iPosition, AM_MEDIA_TYPE *pmt) |
| { |
| VfwPinImpl *This = (VfwPinImpl *)iface; |
| AM_MEDIA_TYPE *vfw_pmt; |
| HRESULT hr; |
| |
| if (iPosition < 0) |
| return E_INVALIDARG; |
| if (iPosition > 0) |
| return VFW_S_NO_MORE_ITEMS; |
| |
| hr = qcap_driver_get_format(This->driver_info, &vfw_pmt); |
| CopyMediaType(pmt, vfw_pmt); |
| DeleteMediaType(vfw_pmt); |
| |
| return hr; |
| } |
| |
| LONG WINAPI VfwPin_GetMediaTypeVersion(IPin *iface) |
| { |
| return 1; |
| } |
| |
| static HRESULT |
| VfwPin_Construct( IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, |
| IPin ** ppPin ) |
| { |
| static const WCHAR wszOutputPinName[] = { 'O','u','t','p','u','t',0 }; |
| ALLOCATOR_PROPERTIES ap; |
| VfwPinImpl * pPinImpl; |
| PIN_INFO piOutput; |
| HRESULT hr; |
| |
| pPinImpl = CoTaskMemAlloc( sizeof(*pPinImpl) ); |
| if (!pPinImpl) |
| return E_OUTOFMEMORY; |
| |
| /* What we put here doesn't matter, the |
| driver function should override it then commit */ |
| ap.cBuffers = 3; |
| ap.cbBuffer = 230400; |
| ap.cbAlign = 1; |
| ap.cbPrefix = 0; |
| |
| piOutput.dir = PINDIR_OUTPUT; |
| piOutput.pFilter = pBaseFilter; |
| lstrcpyW(piOutput.achName, wszOutputPinName); |
| ObjectRefCount(TRUE); |
| |
| hr = OutputPin_Init(&piOutput, &ap, pCritSec, &pPinImpl->pin); |
| if (SUCCEEDED(hr)) |
| { |
| pPinImpl->KSP_VT = &KSP_VTable; |
| pPinImpl->pin.pin.lpVtbl = &VfwPin_Vtbl; |
| *ppPin = (IPin *)(&pPinImpl->pin.pin.lpVtbl); |
| return S_OK; |
| } |
| |
| CoTaskMemFree(pPinImpl); |
| return E_FAIL; |
| } |
| |
| static HRESULT WINAPI VfwPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) |
| { |
| VfwPinImpl *This = (VfwPinImpl *)iface; |
| |
| TRACE("%s %p\n", debugstr_guid(riid), ppv); |
| |
| *ppv = NULL; |
| if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin)) |
| *ppv = This; |
| else if (IsEqualIID(riid, &IID_IKsPropertySet)) |
| *ppv = &(This->KSP_VT); |
| else if (IsEqualIID(riid, &IID_IAMStreamConfig)) |
| return IUnknown_QueryInterface((IUnknown *)This->parent, riid, ppv); |
| |
| if (*ppv) |
| { |
| IUnknown_AddRef((IUnknown *)(*ppv)); |
| return S_OK; |
| } |
| |
| FIXME("No interface for %s!\n", debugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI VfwPin_AddRef(IPin * iface) |
| { |
| VfwPinImpl *This = (VfwPinImpl *)iface; |
| ULONG refCount = InterlockedIncrement(&This->pin.pin.refCount); |
| |
| TRACE("() -> new refcount: %u\n", refCount); |
| |
| return refCount; |
| } |
| |
| static ULONG WINAPI |
| VfwPin_Release(IPin * iface) |
| { |
| VfwPinImpl *This = (VfwPinImpl *)iface; |
| ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount); |
| |
| TRACE("() -> new refcount: %u\n", refCount); |
| |
| if (!refCount) |
| { |
| CoTaskMemFree(This); |
| ObjectRefCount(FALSE); |
| } |
| return refCount; |
| } |
| |
| static HRESULT WINAPI |
| VfwPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum) |
| { |
| AM_MEDIA_TYPE *pmt; |
| HRESULT hr; |
| |
| VfwPinImpl *This = (VfwPinImpl *)iface; |
| hr = qcap_driver_get_format(This->driver_info, &pmt); |
| if (SUCCEEDED(hr)) |
| hr = EnumMediaTypes_Construct(iface, VfwPin_GetMediaType, VfwPin_GetMediaTypeVersion, ppEnum); |
| TRACE("%p -- %x\n", This, hr); |
| DeleteMediaType(pmt); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI |
| VfwPin_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin) |
| { |
| TRACE("(%p)->(%p, %p)\n", iface, apPin, cPin); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI VfwPin_EndOfStream(IPin * iface) |
| { |
| TRACE("()\n"); |
| return E_UNEXPECTED; |
| } |
| |
| static HRESULT WINAPI VfwPin_BeginFlush(IPin * iface) |
| { |
| TRACE("(%p)->()\n", iface); |
| return E_UNEXPECTED; |
| } |
| |
| static HRESULT WINAPI VfwPin_EndFlush(IPin * iface) |
| { |
| TRACE("(%p)->()\n", iface); |
| return E_UNEXPECTED; |
| } |
| |
| static HRESULT WINAPI |
| VfwPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, |
| REFERENCE_TIME tStop, double dRate) |
| { |
| TRACE("(%p)->(%s, %s, %e)\n", iface, wine_dbgstr_longlong(tStart), |
| wine_dbgstr_longlong(tStop), dRate); |
| return E_UNEXPECTED; |
| } |
| |
| static const IPinVtbl VfwPin_Vtbl = |
| { |
| VfwPin_QueryInterface, |
| VfwPin_AddRef, |
| VfwPin_Release, |
| OutputPin_Connect, |
| OutputPin_ReceiveConnection, |
| OutputPin_Disconnect, |
| BasePinImpl_ConnectedTo, |
| BasePinImpl_ConnectionMediaType, |
| BasePinImpl_QueryPinInfo, |
| BasePinImpl_QueryDirection, |
| BasePinImpl_QueryId, |
| BasePinImpl_QueryAccept, |
| VfwPin_EnumMediaTypes, |
| VfwPin_QueryInternalConnections, |
| VfwPin_EndOfStream, |
| VfwPin_BeginFlush, |
| VfwPin_EndFlush, |
| VfwPin_NewSegment |
| }; |