QCAP: Implemented VfwCapture interface

Mike McCormack mike at codeweavers.com
Thu May 26 21:40:17 CDT 2005


I've attempted to clean this up a little by making sure all the 
QueryInterface calls do an AddRef, removing lvalue casts, rewriting bits 
and changing the output of some messages.

Mike


ChangeLog:
Maarten Lankhorst <m.b.lankhorst at gmail.com>
* Implemented VfwCapture interface

-------------- next part --------------
? dlls/qcap/capture.h
? dlls/qcap/vfwcapture.c
Index: dlls/qcap/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/qcap/Makefile.in,v
retrieving revision 1.14
diff -u -p -r1.14 Makefile.in
--- dlls/qcap/Makefile.in	24 May 2005 12:51:01 -0000	1.14
+++ dlls/qcap/Makefile.in	27 May 2005 02:28:38 -0000
@@ -14,6 +14,7 @@ C_SRCS = \
 	enumpins.c \
 	pin.c \
 	qcap_main.c \
+	vfwcapture.c \
 	yuv.c
 
 RC_SRCS = version.rc
Index: dlls/qcap/qcap_main.c
===================================================================
RCS file: /home/wine/wine/dlls/qcap/qcap_main.c,v
retrieving revision 1.6
diff -u -p -r1.6 qcap_main.c
--- dlls/qcap/qcap_main.c	18 May 2005 15:31:24 -0000	1.6
+++ dlls/qcap/qcap_main.c	27 May 2005 02:28:38 -0000
@@ -89,12 +89,12 @@ static CFactoryTemplate const g_cTemplat
         &CLSID_AVICompressor, 
         QCAP_createAVICompressor,
         NULL
-    },{
+    },*/{
         wVFWCaptFilter,
-        &CLSID_VFWCaptureFilter,
+        &CLSID_VfwCapture,
         QCAP_createVFWCaptureFilter,
         NULL
-    },{
+    },/*{
         wVFWCaptFilterProp,
         &CLSID_VFWCaptureFilterPropertyPage,
         QCAP_createVFWCaptureFilterPropertyPage,
--- /dev/null	2005-04-04 08:07:08.000000000 +0900
+++ dlls/qcap/capture.h	2005-05-27 11:25:29.000000000 +0900
@@ -0,0 +1,51 @@
+/* DirectShow private capture header (QCAP.DLL)
+ *
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This file contains the (internal) driver registration functions,
+ * driver enumeration APIs and DirectDraw creation functions.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __QCAP_CAPTURE_H__
+#define __QCAP_CAPTURE_H__
+
+typedef HRESULT (* Video_Destroy)(void *pBox);
+typedef HRESULT (* Video_SetMediaType)(void *pBox, AM_MEDIA_TYPE * mT);
+typedef HRESULT (* Video_GetMediaType)(void *pBox, AM_MEDIA_TYPE ** mT);
+typedef HRESULT (* Video_GetPropRange)(void *pBox, long Property, long *pMin, long *pMax, long *pSteppingDelta, long *pDefault, long *pCapsFlags);
+typedef HRESULT (* Video_GetProp)(void *pBox, long Property, long *lValue, long *Flags);
+typedef HRESULT (* Video_SetProp)(void *pBox, long Property, long lValue, long Flags);
+typedef HRESULT (* Video_Control)(void *pBox, FILTER_STATE *state);
+
+typedef struct capturefunctions {
+    Video_Destroy Destroy;
+    Video_SetMediaType SetFormat;
+    Video_GetMediaType GetFormat;
+    Video_GetPropRange GetPropRange;
+    Video_GetProp Get_Prop;
+    Video_SetProp Set_Prop;
+    Video_Control Run, Pause, Stop;
+    void *pMine;
+} Capture;
+
+typedef HRESULT (* Video_Init)(Capture *pBox, IPin *pOut, USHORT card);
+HRESULT V4l_Init(Capture *pBox, IPin *pOut, USHORT card);
+
+#define INVOKE(from, func, para...) from->func(from->pMine, para)
+#define INVOKENP(from, func) from->func(from->pMine)
+
+#endif /* __QCAP_CAPTURE_H__ */
--- /dev/null	2005-04-04 08:07:08.000000000 +0900
+++ dlls/qcap/vfwcapture.c	2005-05-27 11:35:15.000000000 +0900
@@ -0,0 +1,914 @@
+/* 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "mmreg.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 struct IBaseFilterVtbl * lpVtbl;
+    const struct IAMStreamConfigVtbl * IAMStreamConfig_vtbl;
+    const struct IAMVideoProcAmpVtbl * IAMVideoProcAmp_vtbl;
+    const struct IPersistPropertyBagVtbl * IPersistPropertyBag_vtbl;
+
+    BOOL init;
+    Capture *myCap;
+    ULONG refCount;
+    FILTER_INFO filterInfo;
+    FILTER_STATE state;
+    CRITICAL_SECTION csFilter;
+
+    IPin * pOutputPin;
+} VfwCapture;
+
+/* VfwPin implementation */
+typedef struct VfwPinImpl
+{
+    OutputPin pin;
+    Capture *myCap;
+    IKsPropertySetVtbl * KSP_VT;
+} VfwPinImpl;
+
+static const Video_Init Constructors[] =
+{
+    /* V4l_Init, */
+    NULL
+};
+
+static HRESULT Capture_Initialise(Capture **dimi, IPin *pOut, USHORT card)
+{
+    HRESULT r = E_FAIL;
+    Capture *driver;
+    int i;
+
+    TRACE("%p %p %hu\n", dimi, pOut, card);
+
+    driver = CoTaskMemAlloc( sizeof(Capture) );
+    if (!driver)
+        return E_OUTOFMEMORY;
+
+    for( i=0; FAILED(r) && Constructors[i]; i++ )
+        r = Constructors[i]( driver, pOut, card );
+
+    if( SUCCEEDED(r) )
+        *dimi = driver;
+    else
+        CoTaskMemFree( driver );
+
+    return r;
+}
+
+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);
+    hr = VfwPin_Construct((IBaseFilter *)&pVfwCapture->lpVtbl,
+                   &pVfwCapture->csFilter, &pVfwCapture->pOutputPin);
+    if (!SUCCEEDED(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\n"
+              "\t trying it on primary device now\n", debugstr_guid(riid));
+        if (FAILED(Capture_Initialise(&This->myCap, (IPin *)This->pOutputPin, 0)))
+        {
+            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: %ld\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: %ld\n", This, refCount);
+
+    if (!refCount)
+    {
+        IPinImpl *pin;
+
+        TRACE("destroying everything\n");
+        if (This->init)
+        {
+            if (This->state != State_Stopped)
+                INVOKE(This->myCap, Stop, &This->state);
+            INVOKENP(This->myCap, Destroy);
+        }
+        pin = (IPinImpl*) This->pOutputPin;
+        if (pin->pConnectedTo != NULL)
+        {
+            IPin_Disconnect(pin->pConnectedTo);
+            IPin_Disconnect(This->pOutputPin);
+        }
+        IPin_Release(This->pOutputPin);
+        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 INVOKE(This->myCap, Stop, &This->state);
+}
+
+static HRESULT WINAPI VfwCapture_Pause(IBaseFilter * iface)
+{
+    VfwCapture *This = (VfwCapture *)iface;
+
+    TRACE("()\n");
+    return INVOKE(This->myCap, Pause, &This->state);
+}
+
+static HRESULT WINAPI VfwCapture_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
+{
+    VfwCapture *This = (VfwCapture *)iface;
+    TRACE("(%lx%08lx)\n", (ULONG)(tStart >> 32), (ULONG)tStart);
+    return INVOKE(This->myCap, Run, &This->state);
+}
+
+static HRESULT WINAPI
+VfwCapture_GetState( IBaseFilter * iface, DWORD dwMilliSecsTimeout,
+                     FILTER_STATE *pState )
+{
+    VfwCapture *This = (VfwCapture *)iface;
+
+    TRACE("(%lu, %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 HRESULT WINAPI
+VfwCapture_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
+{
+    ENUMPINDETAILS epd;
+    VfwCapture *This = (VfwCapture *)iface;
+
+    TRACE("(%p)\n", ppEnum);
+
+    epd.cPins = 1;
+    epd.ppPins = &This->pOutputPin;
+    return IEnumPinsImpl_Construct(&epd, 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);
+    IPinImpl *pin;
+
+    TRACE("(%p): %p->%p\n", iface, pmt, pmt->pbFormat);
+
+    if (This->state != State_Stopped)
+    {
+        TRACE("Returning not stopped error\n");
+        return VFW_E_NOT_STOPPED;
+    }
+
+    dump_AM_MEDIA_TYPE(pmt);
+
+    pin = (IPinImpl *)This->pOutputPin;
+    if (pin->pConnectedTo != NULL)
+    {
+        hr = IPin_QueryAccept(pin->pConnectedTo, pmt);
+        TRACE("Would accept: %ld\n", hr);
+        if (hr == S_FALSE)
+            return VFW_E_INVALIDMEDIATYPE;
+    }
+
+    hr = INVOKE(This->myCap, SetFormat, 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: %ld\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 INVOKE(This->myCap, GetFormat, 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 INVOKE( This->myCap, GetPropRange, 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 INVOKE(This->myCap, Set_Prop, Property, lValue, Flags);
+}
+
+static HRESULT WINAPI
+AMVideoProcAmp_Get( IAMVideoProcAmp * iface, long Property, long *lValue,
+                    long *Flags )
+{
+    ICOM_THIS_MULTI(VfwCapture, IAMVideoProcAmp_vtbl, iface);
+
+    return INVOKE(This->myCap, Get_Prop, 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, (LPCOLESTR)VFWIndex, &var, pErrorLog);
+
+    if (SUCCEEDED(hr))
+    {
+        VfwPinImpl *pin;
+
+        hr = Capture_Initialise(&This->myCap, This->pOutputPin,
+               (USHORT)var.__VARIANT_NAME_1.__VARIANT_NAME_2.__VARIANT_NAME_3.ulVal);
+        pin = (VfwPinImpl *)This->pOutputPin;
+        pin->myCap = This->myCap;
+        if (SUCCEEDED(hr))
+            This->init = TRUE;
+    }
+
+    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 = (LPVOID)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, &AMPROPSETID_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 IKsPropertySetVtbl KSP_VTable =
+{
+   KSP_QueryInterface,
+   KSP_AddRef,
+   KSP_Release,
+   KSP_Set,
+   KSP_Get,
+   KSP_QuerySupported
+};
+
+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, pBaseFilter, NULL, 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;
+    }
+    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 = (LPVOID)This;
+    else if (IsEqualIID(riid, &IID_IKsPropertySet))
+        *ppv = (LPVOID)&(This->KSP_VT);
+
+    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: %lu\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: %lu\n", refCount);
+
+   if (!refCount)
+   {
+      CoTaskMemFree(This);
+      ObjectRefCount(FALSE);
+   }
+   return refCount;
+}
+
+static HRESULT WINAPI
+VfwPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
+{
+    ENUMMEDIADETAILS emd;
+    AM_MEDIA_TYPE *pmt;
+    HRESULT hr;
+
+    VfwPinImpl *This = (VfwPinImpl *)iface;
+    emd.cMediaTypes = 1;
+    hr = INVOKE(This->myCap, GetFormat, &pmt);
+    emd.pMediaTypes = pmt;
+    if (SUCCEEDED(hr))
+        hr = IEnumMediaTypesImpl_Construct(&emd, ppEnum);
+    TRACE("%p -- %lx\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,
+    IPinImpl_ConnectedTo,
+    IPinImpl_ConnectionMediaType,
+    IPinImpl_QueryPinInfo,
+    IPinImpl_QueryDirection,
+    IPinImpl_QueryId,
+    IPinImpl_QueryAccept,
+    VfwPin_EnumMediaTypes,
+    VfwPin_QueryInternalConnections,
+    VfwPin_EndOfStream, 
+    VfwPin_BeginFlush,
+    VfwPin_EndFlush,
+    VfwPin_NewSegment
+};  


More information about the wine-patches mailing list