Qcap implementation
Maarten Lankhorst
m.b.lankhorst at gmail.com
Thu May 5 08:35:20 CDT 2005
This patch implements a very stubby capturegraphbuilder interface and
the vfwcapture interface,
a few notes:
- Had to copy media.c, enumpins.c and some functions from pin.c, I
didn't know a cleaner way..
- v4l.c is still very broken, it is recommended to change the #ifdef
HAVE_VIDEODEV_H to #if 0, and in null.c, change #ifndef HAVE_VIDEODEV_H
to #if 1 -- or something similar
- It is possible to write drivers for non-v4l devices and integrate it
easily into qcap, just implement all methods from capture.c
- That v4l.c is still very broken doesn't mean the whole vfw capture
interface is, the interface itself is implemented very good..
- VfwCapture does *NOT* work with builtin quartz, it's too broken, I
sent some patches before, with them it works, but they never got
committed, *NOT* going to fix quartz myself any more..
- VfwCapture should work with native devenum and native quartz (As part
of the IE installation)
- VfwCapture should also work with builtin devenum and native quartz
- If quartz is fixed, I think it will work with native devenum and
builtin quartz, and quartz and devenum both builtin
- I haven't figured out why native devenum asks IPersistentPropertyBag
for IBaseFilter.. and should we do the same? So I made it return IBaseFilter
Just wanted to get this stuff committed :), well apart from v4l.c perhaps
The devenum patch I sent is required to get multiple video input devices
to work properly, except mediacatenum.c, it was broken when
initialisation failed. A working patch for mediacatenum.c is attached..
-------------- next part --------------
diff -Nru wine-old/dlls/qcap/capturegraph.c wine-new/dlls/qcap/capturegraph.c
--- wine-old/dlls/qcap/capturegraph.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/capturegraph.c 2005-04-29 00:31:34.000000000 +0200
@@ -0,0 +1,196 @@
+/* Capture Graph Builder, Minimal edition..
+ * 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
+ *
+ * TODO: Implement CaptureGraphBuilder2, and make all calls from
+ * CaptureGraphBuilder forward to it..
+ */
+
+#include "config.h"
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "qcap_private.h"
+
+#include "uuids.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+#include "windef.h"
+#include "winbase.h"
+#include "dshow.h"
+#include "evcode.h"
+#include "strmif.h"
+#include "ddraw.h"
+
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+static const ICaptureGraphBuilderVtbl Builder_Vtbl;
+
+typedef struct CaptureGraphImpl
+{
+ const ICaptureGraphBuilderVtbl * lpVtbl;
+ IGraphBuilder *mygraph;
+
+ ULONG refCount;
+ CRITICAL_SECTION csFilter;
+} CaptureGraphImpl;
+
+HRESULT CaptureGraphBuilder_create(IUnknown * pUnkOuter, LPVOID * ppv)
+{
+ CaptureGraphImpl * pCapture;
+ TRACE("(%p, %p)\n", pUnkOuter, ppv);
+ *ppv = NULL;
+ if (pUnkOuter) return CLASS_E_NOAGGREGATION;
+ pCapture = CoTaskMemAlloc(sizeof(CaptureGraphImpl));
+ pCapture->lpVtbl = &Builder_Vtbl;
+ pCapture->refCount = 1;
+ pCapture->mygraph = NULL;
+ InitializeCriticalSection(&pCapture->csFilter);
+ *ppv = (LPVOID)pCapture;
+ return S_OK;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_QueryInterface(ICaptureGraphBuilder * iface, REFIID riid, LPVOID * ppv)
+{
+ struct CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+ TRACE("(%p/%p)->(%s, %p)\n", This, iface, qcdebugstr_guid(riid), ppv);
+ *ppv = NULL;
+ if (IsEqualIID(riid, &IID_IUnknown))
+ *ppv = (LPVOID)This;
+ else if (IsEqualIID(riid, &IID_ICaptureGraphBuilder))
+ *ppv = (LPVOID)This;
+
+ if (*ppv)
+ {
+ IUnknown_AddRef((IUnknown *)(*ppv));
+ return S_OK;
+ }
+
+ FIXME("No interface for %s!\n", qcdebugstr_guid(riid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI CaptureGraphBuilder_AddRef(ICaptureGraphBuilder * iface)
+{
+ CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+ ULONG refCount = InterlockedIncrement(&This->refCount);
+
+ TRACE("(%p/%p)->() AddRef from %ld\n", This, iface, refCount - 1);
+ return refCount;
+}
+
+static ULONG WINAPI CaptureGraphBuilder_Release(ICaptureGraphBuilder * iface)
+{
+ CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+ ULONG refCount = InterlockedDecrement(&This->refCount);
+
+ TRACE("(%p/%p)->() Release from %ld\n", This, iface, refCount + 1);
+
+ if (!refCount) {
+ TRACE("Destroying everything..\n");
+ DeleteCriticalSection(&This->csFilter);
+ if (This->mygraph != NULL)
+ IGraphBuilder_Release((IGraphBuilder *)This->mygraph);
+ CoTaskMemFree(This);
+ return 0;
+ }
+ else return refCount;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_SetFilterGraph(ICaptureGraphBuilder * iface, IGraphBuilder *pfg)
+{
+/* The graph builder will automatically create a filter graph if you don't call this method. If you call this method after the graph builder has created its own filter graph, the call will fail. */
+ struct CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+ if (This->mygraph != NULL) return E_NOTIMPL;
+ This->mygraph = pfg;
+ IGraphBuilder_AddRef((IGraphBuilder *)This->mygraph);
+ TRACE("%p: %p\n", iface, pfg);
+ return S_OK;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_GetFilterGraph(ICaptureGraphBuilder * iface, IGraphBuilder **pfg)
+{
+ struct CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+ FIXME("%p: Make our own filtergraph if we haven't got one already - stub\n", iface);
+ if (This->mygraph == NULL) return E_NOTIMPL;
+
+ *pfg = This->mygraph;
+ IGraphBuilder_AddRef((IGraphBuilder *)This->mygraph);
+
+ TRACE("%p: %p\n", iface, *pfg);
+ return S_OK;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_SetOutputFileName(ICaptureGraphBuilder * iface, const GUID *pType, LPCOLESTR lpstrFile,IBaseFilter **ppf, IFileSinkFilter **ppSink)
+{
+ FIXME("%p: %p, %p, %p, %p - stub\n", iface, pType, lpstrFile, *ppf, *ppSink);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_FindInterface(ICaptureGraphBuilder * iface, const GUID *pCategory, IBaseFilter *pf, REFIID riid, void **ppint)
+{
+ struct CaptureGraphImpl *This = (CaptureGraphImpl *)iface;
+ FIXME("%p: %s %p %s %p - unwanted partial stub!\n", This, qcdebugstr_guid(pCategory), pf, qcdebugstr_guid(riid), *ppint);
+ return IBaseFilter_QueryInterface(pf, riid, ppint);
+ /* Looks for the specified interface on the filter, upstream and
+ * downstream from the filter, and, optionally, only on the output
+ * pin of the given category.
+ */
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_RenderStream(ICaptureGraphBuilder * iface, const GUID *pCategory, IUnknown *pSource, IBaseFilter *pfCompressor, IBaseFilter *pfRenderer)
+{
+ FIXME("%p: stub\n", iface);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_ControlStream(ICaptureGraphBuilder * iface, const GUID *pCategory, IBaseFilter *pFilter, REFERENCE_TIME *pstart, REFERENCE_TIME *pstop, WORD wStartCookie, WORD wStopCookie)
+{
+ FIXME("%p: stub\n", iface);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_AllocCapFile(ICaptureGraphBuilder * iface, LPCOLESTR lpstr, DWORDLONG dwlSize)
+{
+ FIXME("%p: stub\n", iface);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CaptureGraphBuilder_CopyCaptureFile(ICaptureGraphBuilder * iface, LPOLESTR lpwstrOld, LPOLESTR lpwstrNew, int fAllowEscAbort, IAMCopyCaptureFileProgress *pCallback)
+{
+ FIXME("%p: stub\n", iface);
+ return E_NOTIMPL;
+}
+
+static const ICaptureGraphBuilderVtbl Builder_Vtbl =
+{
+ CaptureGraphBuilder_QueryInterface,
+ CaptureGraphBuilder_AddRef,
+ CaptureGraphBuilder_Release,
+ CaptureGraphBuilder_SetFilterGraph,
+ CaptureGraphBuilder_GetFilterGraph,
+ CaptureGraphBuilder_SetOutputFileName,
+ CaptureGraphBuilder_FindInterface,
+ CaptureGraphBuilder_RenderStream,
+ CaptureGraphBuilder_ControlStream,
+ CaptureGraphBuilder_AllocCapFile,
+ CaptureGraphBuilder_CopyCaptureFile
+};
+
diff -Nru wine-old/dlls/qcap/capture.h wine-new/dlls/qcap/capture.h
--- wine-old/dlls/qcap/capture.h 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/capture.h 2005-05-02 13:07:38.000000000 +0200
@@ -0,0 +1,45 @@
+/* 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 __CAPTURE_H__
+#define __CAPTURE_H__
+
+/* Initialisation */
+HRESULT Capture_Initialise(void ** pointer, IPin *pOut, USHORT card);
+
+/* Control */
+HRESULT Capture_GetMediaType(void * pBox, AM_MEDIA_TYPE ** mT);
+HRESULT Capture_SetMediaType(void * pBox, AM_MEDIA_TYPE * mT);
+HRESULT Capture_GetPropRange(void * pBox, long Property, long *pMin, long *pMax, long *pSteppingDelta, long *pDefault, long *pCapsFlags);
+HRESULT Capture_GetProp(void *pBox, long Property, long *lValue, long *Flags);
+HRESULT Capture_SetProp(void *pBox, long Property, long lValue, long Flags);
+
+/* Stream control */
+HRESULT Capture_Run(void * pBox, FILTER_STATE *state);
+HRESULT Capture_Stop(void * pBox, FILTER_STATE *state);
+HRESULT Capture_Pause(void * pBox, FILTER_STATE *state);
+
+/* Destruction */
+HRESULT Capture_Destroy(void * pBox, BOOL destroyall);
+
+#endif /* __CAPTURE_H__ */
+
diff -Nru wine-old/dlls/qcap/enumpins.c wine-new/dlls/qcap/enumpins.c
--- wine-old/dlls/qcap/enumpins.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/enumpins.c 2005-04-29 13:40:15.000000000 +0200
@@ -0,0 +1,183 @@
+/*
+ * Generic Implementation of IPin Interface
+ *
+ * Copyright 2003 Robert Shearman
+ *
+ * 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
+ */
+
+#include "qcap_private.h"
+#include "pin.h"
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "uuids.h"
+#include "vfwmsgs.h"
+#include <assert.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+typedef struct IEnumPinsImpl
+{
+ const IEnumPinsVtbl * lpVtbl;
+ ULONG refCount;
+ ENUMPINDETAILS enumPinDetails;
+ ULONG uIndex;
+} IEnumPinsImpl;
+
+static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl;
+
+HRESULT IEnumPinsImpl_Construct(const ENUMPINDETAILS * pDetails, IEnumPins ** ppEnum)
+{
+ IEnumPinsImpl * pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl));
+ TRACE("()\n");
+ if (!pEnumPins)
+ {
+ *ppEnum = NULL;
+ return E_OUTOFMEMORY;
+ }
+ pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl;
+ pEnumPins->refCount = 1;
+ pEnumPins->uIndex = 0;
+ CopyMemory(&pEnumPins->enumPinDetails, pDetails, sizeof(ENUMPINDETAILS));
+ *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl);
+ return S_OK;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv)
+{
+ TRACE("(%s, %p)\n", qcdebugstr_guid(riid), ppv);
+
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, &IID_IUnknown))
+ *ppv = (LPVOID)iface;
+ else if (IsEqualIID(riid, &IID_IEnumPins))
+ *ppv = (LPVOID)iface;
+
+ if (*ppv)
+ {
+ IUnknown_AddRef((IUnknown *)(*ppv));
+ return S_OK;
+ }
+
+ FIXME("No interface for %s!\n", qcdebugstr_guid(riid));
+
+ return E_NOINTERFACE;
+}
+static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface)
+{
+ IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+ ULONG refCount = InterlockedIncrement(&This->refCount);
+
+ TRACE("() -> %lu\n", refCount);
+
+ return refCount;
+}
+
+static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface)
+{
+ IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+ ULONG refCount = InterlockedDecrement(&This->refCount);
+
+ TRACE("() -> %lu\n", refCount);
+
+ if (!refCount)
+ {
+ CoTaskMemFree(This);
+ return 0;
+ }
+ else
+ return refCount;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched)
+{
+ ULONG cFetched;
+ IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+
+ TRACE("()\n");
+
+ cFetched = min(This->enumPinDetails.cPins, This->uIndex + cPins) - This->uIndex;
+
+ TRACE("(%lu, %p, %p)\n", cPins, ppPins, pcFetched);
+
+ if (cFetched > 0)
+ {
+ ULONG i;
+ for (i = 0; i < cFetched; i++) {
+ IPin_AddRef(This->enumPinDetails.ppPins[This->uIndex + i]);
+ ppPins[i] = This->enumPinDetails.ppPins[This->uIndex + i];
+ }
+ }
+
+ if ((cPins != 1) || pcFetched)
+ *pcFetched = cFetched;
+
+ This->uIndex += cFetched;
+
+ if (cFetched != cPins)
+ return S_FALSE;
+ return S_OK;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins)
+{
+ IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+
+ TRACE("(%lu)\n", cPins);
+
+ if (This->uIndex + cPins < This->enumPinDetails.cPins)
+ {
+ This->uIndex += cPins;
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface)
+{
+ IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+
+ TRACE("IEnumPinsImpl::Reset()\n");
+
+ This->uIndex = 0;
+ return S_OK;
+}
+
+static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum)
+{
+ HRESULT hr;
+ IEnumPinsImpl *This = (IEnumPinsImpl *)iface;
+
+ TRACE("(%p)\n", ppEnum);
+
+ hr = IEnumPinsImpl_Construct(&This->enumPinDetails, ppEnum);
+ if (FAILED(hr))
+ return hr;
+ return IEnumPins_Skip(*ppEnum, This->uIndex);
+}
+
+static const IEnumPinsVtbl IEnumPinsImpl_Vtbl =
+{
+ IEnumPinsImpl_QueryInterface,
+ IEnumPinsImpl_AddRef,
+ IEnumPinsImpl_Release,
+ IEnumPinsImpl_Next,
+ IEnumPinsImpl_Skip,
+ IEnumPinsImpl_Reset,
+ IEnumPinsImpl_Clone
+};
+
diff -Nru wine-old/dlls/qcap/Makefile.in wine-new/dlls/qcap/Makefile.in
--- wine-old/dlls/qcap/Makefile.in 2004-05-14 23:37:32.000000000 +0200
+++ wine-new/dlls/qcap/Makefile.in 2005-05-01 01:56:42.000000000 +0200
@@ -3,8 +3,19 @@
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = qcap.dll
+IMPORTS = ole32 kernel32 advapi32 user32
+EXTRALIBS = -lstrmiids -luuid $(LIBUNICODE)
-C_SRCS = qcap_main.c
+C_SRCS = \
+ capturegraph.c \
+ enumpins.c \
+ media.c \
+ null.c \
+ pin.c \
+ qcap_main.c \
+ regsvr.c \
+ v4l.c \
+ vfwcapture.c
RC_SRCS = version.rc
diff -Nru wine-old/dlls/qcap/media.c wine-new/dlls/qcap/media.c
--- wine-old/dlls/qcap/media.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/media.c 2005-05-01 01:48:09.000000000 +0200
@@ -0,0 +1,229 @@
+/*
+ * Implementation of IEnumMediaTypes Interface
+ *
+ * Copyright 2003 Robert Shearman
+ * 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
+ */
+
+#include "qcap_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc)
+{
+ memcpy(pDest, pSrc, sizeof(AM_MEDIA_TYPE));
+ if (!pDest->pbFormat) return S_OK;
+ if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat)))
+ return E_OUTOFMEMORY;
+ memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat);
+ return S_OK;
+}
+
+void DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
+{
+ if (pMediaType->pbFormat)
+ {
+ CoTaskMemFree(pMediaType->pbFormat);
+ pMediaType->pbFormat = NULL;
+ }
+ if (pMediaType->pUnk)
+ {
+ IUnknown_Release(pMediaType->pUnk);
+ pMediaType->pUnk = NULL;
+ }
+ CoTaskMemFree(pMediaType);
+}
+
+BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
+{
+ TRACE("pmt1: ");
+ dump_AM_MEDIA_TYPE(pmt1);
+ TRACE("pmt2: ");
+ dump_AM_MEDIA_TYPE(pmt2);
+ return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
+ ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
+}
+
+void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt)
+{
+ if (!pmt)
+ return;
+ TRACE("\t%s\n\t%s\n\t...\n\t%s\n", qcdebugstr_guid(&pmt->majortype), qcdebugstr_guid(&pmt->subtype), qcdebugstr_guid(&pmt->formattype));
+}
+
+typedef struct IEnumMediaTypesImpl
+{
+ const IEnumMediaTypesVtbl * lpVtbl;
+ ULONG refCount;
+ ENUMMEDIADETAILS enumMediaDetails;
+ ULONG uIndex;
+} IEnumMediaTypesImpl;
+
+static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
+
+HRESULT IEnumMediaTypesImpl_Construct(const ENUMMEDIADETAILS * pDetails, IEnumMediaTypes ** ppEnum)
+{
+ ULONG i;
+ IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
+
+ if (!pEnumMediaTypes)
+ {
+ *ppEnum = NULL;
+ return E_OUTOFMEMORY;
+ }
+ pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl;
+ pEnumMediaTypes->refCount = 1;
+ pEnumMediaTypes->uIndex = 0;
+ pEnumMediaTypes->enumMediaDetails.cMediaTypes = pDetails->cMediaTypes;
+ pEnumMediaTypes->enumMediaDetails.pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * pDetails->cMediaTypes);
+ for (i = 0; i < pDetails->cMediaTypes; i++)
+ CopyMediaType(&pEnumMediaTypes->enumMediaDetails.pMediaTypes[i], &pDetails->pMediaTypes[i]);
+ *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl);
+ return S_OK;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv)
+{
+ TRACE("(%s, %p)\n", qcdebugstr_guid(riid), ppv);
+
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, &IID_IUnknown))
+ *ppv = (LPVOID)iface;
+ else if (IsEqualIID(riid, &IID_IEnumMediaTypes))
+ *ppv = (LPVOID)iface;
+
+ if (*ppv)
+ {
+ IUnknown_AddRef((IUnknown *)(*ppv));
+ return S_OK;
+ }
+
+ FIXME("No interface for %s!\n", qcdebugstr_guid(riid));
+
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
+{
+ IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+ ULONG refCount = InterlockedIncrement(&This->refCount);
+
+ TRACE("()\n");
+
+ return refCount;
+}
+
+static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
+{
+ IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+ ULONG refCount = InterlockedDecrement(&This->refCount);
+
+ TRACE("()\n");
+
+ if (!refCount)
+ {
+ int i;
+ for (i = 0; i < This->enumMediaDetails.cMediaTypes; i++)
+ if (This->enumMediaDetails.pMediaTypes[i].pbFormat)
+ CoTaskMemFree(This->enumMediaDetails.pMediaTypes[i].pbFormat);
+ CoTaskMemFree(This->enumMediaDetails.pMediaTypes);
+ CoTaskMemFree(This);
+ return 0;
+ }
+ else
+ return refCount;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
+{
+ ULONG cFetched;
+ IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+
+ cFetched = min(This->enumMediaDetails.cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
+
+ TRACE("(%lu, %p, %p)\n", cMediaTypes, ppMediaTypes, pcFetched);
+ TRACE("Next uIndex: %lu, cFetched: %lu\n", This->uIndex, cFetched);
+
+ if (cFetched > 0)
+ {
+ ULONG i;
+ *ppMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * cFetched);
+ for (i = 0; i < cFetched; i++)
+ CopyMediaType(&(*ppMediaTypes)[i], &This->enumMediaDetails.pMediaTypes[This->uIndex + i]);
+ }
+
+ if ((cMediaTypes != 1) || pcFetched)
+ *pcFetched = cFetched;
+
+ This->uIndex += cFetched;
+
+ if (cFetched != cMediaTypes)
+ return S_FALSE;
+ return S_OK;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
+{
+ IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+
+ TRACE("(%lu)\n", cMediaTypes);
+
+ if (This->uIndex + cMediaTypes < This->enumMediaDetails.cMediaTypes)
+ {
+ This->uIndex += cMediaTypes;
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
+{
+ IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+
+ TRACE("()\n");
+
+ This->uIndex = 0;
+ return S_OK;
+}
+
+static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
+{
+ HRESULT hr;
+ IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface;
+
+ TRACE("(%p)\n", ppEnum);
+ hr = IEnumMediaTypesImpl_Construct(&This->enumMediaDetails, ppEnum);
+
+ if (FAILED(hr))
+ return hr;
+ return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
+}
+
+static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
+{
+ IEnumMediaTypesImpl_QueryInterface,
+ IEnumMediaTypesImpl_AddRef,
+ IEnumMediaTypesImpl_Release,
+ IEnumMediaTypesImpl_Next,
+ IEnumMediaTypesImpl_Skip,
+ IEnumMediaTypesImpl_Reset,
+ IEnumMediaTypesImpl_Clone
+};
+
diff -Nru wine-old/dlls/qcap/null.c wine-new/dlls/qcap/null.c
--- wine-old/dlls/qcap/null.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/null.c 2005-05-05 14:54:42.000000000 +0200
@@ -0,0 +1,89 @@
+/* DirectShow capture services (QCAP.DLL)
+ *
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This file contains the part of the vfw capture interface that
+ * does the actual capturing stuff required for capturing
+ * and setting/getting media format..
+ *
+ * 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
+ *
+ * Why on earth am I writing a copyright notice for a NULL renderer???
+ */
+
+#include "config.h"
+#ifndef HAVE_LINUX_VIDEODEV_H
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "qcap_private.h"
+#include "pin.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+HRESULT Capture_Initialise(void ** pointer, IPin *pOut, USHORT card)
+{
+ ERR("No DirectShow Video for Wine Capture support compiled\n");
+ return E_FAIL;
+}
+
+HRESULT Capture_GetMediaType(void * pBox, AM_MEDIA_TYPE ** mT)
+{
+ return E_FAIL;
+}
+
+HRESULT Capture_SetMediaType(void * pBox, AM_MEDIA_TYPE * mT)
+{
+ return E_FAIL;
+}
+
+HRESULT Capture_GetPropRange(void * pBox, long Property, long *pMin, long *pMax, long *pSteppingDelta, long *pDefault, long *pCapsFlags)
+{
+ return E_FAIL;
+}
+
+HRESULT Capture_GetProp(void *pBox, long Property, long *lValue, long *Flags)
+{
+ return E_FAIL;
+}
+
+HRESULT Capture_SetProp(void *pBox, long Property, long lValue, long Flags)
+{
+ return E_FAIL;
+}
+
+HRESULT Capture_Run(void * pBox, FILTER_STATE *state)
+{
+ return E_FAIL;
+}
+
+HRESULT Capture_Stop(void * pBox, FILTER_STATE *state)
+{
+ return E_FAIL;
+}
+
+HRESULT Capture_Pause(void * pBox, FILTER_STATE *state)
+{
+ return E_FAIL;
+}
+
+HRESULT Capture_Destroy(void * pBox, BOOL destroyall)
+{
+ return E_FAIL;
+}
+
+#endif
+
diff -Nru wine-old/dlls/qcap/pin.c wine-new/dlls/qcap/pin.c
--- wine-old/dlls/qcap/pin.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/pin.c 2005-04-30 18:44:10.000000000 +0200
@@ -0,0 +1,411 @@
+/*
+ * Generic Implementation of IPin Interface
+ *
+ * Copyright 2003 Robert Shearman
+ *
+ * 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
+ */
+
+#include "qcap_private.h"
+#include "pin.h"
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "uuids.h"
+#include "vfwmsgs.h"
+#include <assert.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+#define ALIGNDOWN(value,boundary) ((value) & ~(boundary-1))
+#define ALIGNUP(value,boundary) (ALIGNDOWN(value - 1, boundary) + boundary)
+
+static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
+{
+ /* Tempting to just do a memcpy, but the name field is
+ 128 characters long! We will probably never exceed 10
+ most of the time, so we are better off copying
+ each field manually */
+ strcpyW(pDest->achName, pSrc->achName);
+ pDest->dir = pSrc->dir;
+ pDest->pFilter = pSrc->pFilter;
+}
+
+HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin)
+{
+ HRESULT hr;
+ IPinImpl *This = (IPinImpl *)iface;
+
+/* TRACE("(%p)\n", ppPin);*/
+
+ EnterCriticalSection(This->pCritSec);
+ {
+ if (This->pConnectedTo)
+ {
+ *ppPin = This->pConnectedTo;
+ IPin_AddRef(*ppPin);
+ hr = S_OK;
+ }
+ else
+ hr = VFW_E_NOT_CONNECTED;
+ }
+ LeaveCriticalSection(This->pCritSec);
+
+ return hr;
+}
+
+HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
+{
+ HRESULT hr;
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
+
+ EnterCriticalSection(This->pCritSec);
+ {
+ if (This->pConnectedTo)
+ {
+ CopyMediaType(pmt, &This->mtCurrent);
+ hr = S_OK;
+ }
+ else
+ {
+ ZeroMemory(pmt, sizeof(*pmt));
+ hr = VFW_E_NOT_CONNECTED;
+ }
+ }
+ LeaveCriticalSection(This->pCritSec);
+
+ return hr;
+}
+
+HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
+
+ Copy_PinInfo(pInfo, &This->pinInfo);
+ IBaseFilter_AddRef(pInfo->pFilter);
+
+ return S_OK;
+}
+
+HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, pPinDir);
+
+ *pPinDir = This->pinInfo.dir;
+
+ return S_OK;
+}
+
+HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, Id);
+
+ *Id = CoTaskMemAlloc((strlenW(This->pinInfo.achName) + 1) * sizeof(WCHAR));
+ if (!Id)
+ return E_OUTOFMEMORY;
+
+ strcpyW(*Id, This->pinInfo.achName);
+
+ return S_OK;
+}
+
+HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
+
+ if (!This->fnQueryAccept) return S_OK;
+
+ return (This->fnQueryAccept(This->pUserData, pmt) == S_OK ? S_OK : S_FALSE);
+}
+
+HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p, %p)\n", This, iface, apPin, cPin);
+
+ return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */
+}
+
+/* Function called as a helper to IPin_Connect */
+/* specific AM_MEDIA_TYPE - it cannot be NULL */
+/* NOTE: not part of standard interface */
+static HRESULT OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
+{
+ OutputPin *This = (OutputPin *)iface;
+ HRESULT hr;
+ IMemAllocator * pMemAlloc = NULL;
+ ALLOCATOR_PROPERTIES actual; /* FIXME: should we put the actual props back in to This? */
+
+ TRACE("(%p, %p)\n", pReceivePin, pmt);
+ dump_AM_MEDIA_TYPE(pmt);
+
+ /* FIXME: call queryacceptproc */
+
+ This->pin.pConnectedTo = pReceivePin;
+ IPin_AddRef(pReceivePin);
+ CopyMediaType(&This->pin.mtCurrent, pmt);
+
+ hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
+
+ /* get the IMemInputPin interface we will use to deliver samples to the
+ * connected pin */
+ if (SUCCEEDED(hr))
+ {
+ hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin);
+
+ if (SUCCEEDED(hr))
+ hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pMemAlloc);
+
+ if (hr == VFW_E_NO_ALLOCATOR)
+ {
+ /* Input pin provides no allocator, use standard memory allocator */
+ hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAlloc);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, pMemAlloc, FALSE);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ hr = IMemAllocator_SetProperties(pMemAlloc, &This->allocProps, &actual);
+
+ if (pMemAlloc)
+ IMemAllocator_Release(pMemAlloc);
+
+ /* break connection if we couldn't get the allocator */
+ if (FAILED(hr))
+ IPin_Disconnect(pReceivePin);
+ }
+
+ if (FAILED(hr))
+ {
+ IPin_Release(This->pin.pConnectedTo);
+ This->pin.pConnectedTo = NULL;
+ DeleteMediaType(&This->pin.mtCurrent);
+ }
+
+ TRACE(" -- %lx\n", hr);
+ return hr;
+}
+
+HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES * props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl)
+{
+ TRACE("\n");
+
+ /* Common attributes */
+ pPinImpl->pin.refCount = 1;
+ pPinImpl->pin.pConnectedTo = NULL;
+ pPinImpl->pin.fnQueryAccept = pQueryAccept;
+ pPinImpl->pin.pUserData = pUserData;
+ pPinImpl->pin.pCritSec = pCritSec;
+ Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
+
+ /* Output pin attributes */
+ pPinImpl->pMemInputPin = NULL;
+ pPinImpl->pConnectSpecific = OutputPin_ConnectSpecific;
+ if (props)
+ {
+ memcpy(&pPinImpl->allocProps, props, sizeof(pPinImpl->allocProps));
+ if (pPinImpl->allocProps.cbAlign == 0)
+ pPinImpl->allocProps.cbAlign = 1;
+ }
+ else
+ ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps));
+
+ return S_OK;
+}
+
+HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
+{
+ HRESULT hr;
+ OutputPin *This = (OutputPin *)iface;
+
+ TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
+ dump_AM_MEDIA_TYPE(pmt);
+
+ /* If we try to connect to ourself, we will definitely deadlock.
+ * There are other cases where we could deadlock too, but this
+ * catches the obvious case */
+ assert(pReceivePin != iface);
+
+ EnterCriticalSection(This->pin.pCritSec);
+ {
+ /* if we have been a specific type to connect with, then we can either connect
+ * with that or fail. We cannot choose different AM_MEDIA_TYPE */
+ if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
+ hr = This->pConnectSpecific(iface, pReceivePin, pmt);
+ else
+ {
+ /* negotiate media type */
+
+ IEnumMediaTypes * pEnumCandidates;
+ AM_MEDIA_TYPE * pmtCandidate; /* Candidate media type */
+
+ if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates)))
+ {
+ hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
+
+ /* try this filter's media types first */
+ while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
+ {
+ if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) &&
+ (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
+ {
+ hr = S_OK;
+ TRACE("o_o\n");
+ DeleteMediaType(pmtCandidate);
+ break;
+ }
+ DeleteMediaType(pmtCandidate);
+ }
+ IEnumMediaTypes_Release(pEnumCandidates);
+ }
+
+ /* then try receiver filter's media types */
+ if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */
+ {
+ hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
+
+ while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
+ {
+ if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) &&
+ (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
+ {
+ hr = S_OK;
+ DeleteMediaType(pmtCandidate);
+ break;
+ }
+ DeleteMediaType(pmtCandidate);
+ } /* while */
+ IEnumMediaTypes_Release(pEnumCandidates);
+ } /* if not found */
+ } /* if negotiate media type */
+ } /* if succeeded */
+ LeaveCriticalSection(This->pin.pCritSec);
+
+ TRACE(" -- %lx\n", hr);
+ return hr;
+}
+
+HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
+{
+ ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt);
+
+ return E_UNEXPECTED;
+}
+
+HRESULT WINAPI OutputPin_Disconnect(IPin * iface)
+{
+ HRESULT hr;
+ OutputPin *This = (OutputPin *)iface;
+
+ TRACE("()\n");
+
+ EnterCriticalSection(This->pin.pCritSec);
+ {
+ if (This->pMemInputPin)
+ {
+ IMemInputPin_Release(This->pMemInputPin);
+ This->pMemInputPin = NULL;
+ }
+ if (This->pin.pConnectedTo)
+ {
+ IPin_Release(This->pin.pConnectedTo);
+ This->pin.pConnectedTo = NULL;
+ hr = S_OK;
+ }
+ else
+ hr = S_FALSE;
+ }
+ LeaveCriticalSection(This->pin.pCritSec);
+
+ return hr;
+}
+
+HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, const REFERENCE_TIME * tStart, const REFERENCE_TIME * tStop, DWORD dwFlags)
+{
+ HRESULT hr;
+
+ TRACE("(%p, %p, %p, %lx)\n", ppSample, tStart, tStop, dwFlags);
+
+ EnterCriticalSection(This->pin.pCritSec);
+ {
+ if (!This->pin.pConnectedTo)
+ hr = VFW_E_NOT_CONNECTED;
+ else
+ {
+ IMemAllocator * pAlloc = NULL;
+
+ hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
+
+ if (SUCCEEDED(hr))
+ hr = IMemAllocator_GetBuffer(pAlloc, ppSample, (REFERENCE_TIME *)tStart, (REFERENCE_TIME *)tStop, dwFlags);
+
+ if (SUCCEEDED(hr))
+ hr = IMediaSample_SetTime(*ppSample, (REFERENCE_TIME *)tStart, (REFERENCE_TIME *)tStop);
+
+ if (pAlloc)
+ IMemAllocator_Release(pAlloc);
+ }
+ }
+ LeaveCriticalSection(This->pin.pCritSec);
+
+ return hr;
+}
+
+HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample)
+{
+ HRESULT hr = S_OK;
+ IMemInputPin * pMemConnected = NULL;
+
+ EnterCriticalSection(This->pin.pCritSec);
+ {
+ if (!This->pin.pConnectedTo || !This->pMemInputPin)
+ hr = VFW_E_NOT_CONNECTED;
+ else
+ {
+ /* we don't have the lock held when using This->pMemInputPin,
+ * so we need to AddRef it to stop it being deleted while we are
+ * using it. */
+ pMemConnected = This->pMemInputPin;
+ IMemInputPin_AddRef(pMemConnected);
+ }
+ }
+ LeaveCriticalSection(This->pin.pCritSec);
+
+ if (SUCCEEDED(hr))
+ {
+ /* NOTE: if we are in a critical section when Receive is called
+ * then it causes some problems (most notably with the native Video
+ * Renderer) if we are re-entered for whatever reason */
+ hr = IMemInputPin_Receive(pMemConnected, pSample);
+ IMemInputPin_Release(pMemConnected);
+ }
+
+ return hr;
+}
+
diff -Nru wine-old/dlls/qcap/pin.h wine-new/dlls/qcap/pin.h
--- wine-old/dlls/qcap/pin.h 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/pin.h 2005-04-29 14:01:43.000000000 +0200
@@ -0,0 +1,81 @@
+/*
+ * IPin function declarations to allow inheritance
+ *
+ * Copyright 2003 Robert Shearman
+ *
+ * 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
+ */
+
+/* This function will process incoming samples to the pin.
+ * Any return value valid in IMemInputPin::Receive is allowed here
+ */
+typedef HRESULT (* SAMPLEPROC)(LPVOID userdata, IMediaSample * pSample);
+
+/* This function will determine whether a type is supported or not.
+ * It is allowed to return any error value (within reason), as opposed
+ * to IPin::QueryAccept which is only allowed to return S_OK or S_FALSE.
+ */
+typedef HRESULT (* QUERYACCEPTPROC)(LPVOID userdata, const AM_MEDIA_TYPE * pmt);
+
+/* This function is called prior to finalizing a connection with
+ * another pin and can be used to get things from the other pin
+ * like IMemInput interfaces.
+ */
+typedef HRESULT (* PRECONNECTPROC)(IPin * iface, IPin * pConnectPin);
+
+typedef struct IPinImpl
+{
+ const struct IPinVtbl * lpVtbl;
+ ULONG refCount;
+ LPCRITICAL_SECTION pCritSec;
+ PIN_INFO pinInfo;
+ IPin * pConnectedTo;
+ AM_MEDIA_TYPE mtCurrent;
+ ENUMMEDIADETAILS enumMediaDetails;
+ QUERYACCEPTPROC fnQueryAccept;
+ LPVOID pUserData;
+} IPinImpl;
+
+typedef struct OutputPin
+{
+ /* inheritance C style! */
+ IPinImpl pin;
+
+ IMemInputPin * pMemInputPin;
+ HRESULT (* pConnectSpecific)(IPin * iface, IPin * pReceiver, const AM_MEDIA_TYPE * pmt);
+ ALLOCATOR_PROPERTIES allocProps;
+} OutputPin;
+
+/*** Initializers ***/
+HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl);
+
+/* Common */
+HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin);
+HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt);
+HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo);
+HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir);
+HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id);
+HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt);
+HRESULT WINAPI IPinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum);
+HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin);
+
+/* Output Pin */
+HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt);
+HRESULT WINAPI OutputPin_Disconnect(IPin * iface);
+HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt);
+
+HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, const REFERENCE_TIME * tStart, const REFERENCE_TIME * tStop, DWORD dwFlags);
+HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample);
+
diff -Nru wine-old/dlls/qcap/qcap_main.c wine-new/dlls/qcap/qcap_main.c
--- wine-old/dlls/qcap/qcap_main.c 2004-05-21 22:54:48.000000000 +0200
+++ wine-new/dlls/qcap/qcap_main.c 2005-05-05 09:50:10.000000000 +0200
@@ -1,7 +1,10 @@
-/*
- * Qcap implementation
+/* DirectShow Capture Base Functions (QCAP.DLL)
*
- * Copyright (C) 2003 Dominik Strasser
+ * Copyright 2002 Lionel Ulmer
+ * 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
@@ -18,26 +21,226 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include "config.h"
#include "wine/debug.h"
-#include "winerror.h"
+#include "qcap_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+/* Currently (partial) supported:
+ - Vfw Capture Filter
+ - CaptureGraphBuilder1 (Should be forwarded to CaptureGraphBuilder2)
+
+ Native qcap also supports:
+ - Avi Mux Property Page 1
+ - Vfw Capture Filter property page
+ - Audio input mixer property page
+ - File writer
+ - Avi mux property page
+ - Audio Capture Filter
+ * Smart tee filter
+ * Infinite pin tee filter
+ * CaptureGraphBuilder2
+
+ a "*" means important, we should work on implementing it..
+ */
+static DWORD dll_ref = 0;
+
+/* For the moment, do nothing here. */
+BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
+{
+ switch(fdwReason) {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls(hInstDLL);
+ break;
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+/******************************************************************************
+ * DirectShow ClassFactory
+ */
+typedef struct {
+ IClassFactory ITF_IClassFactory;
+
+ DWORD ref;
+ HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
+} IClassFactoryImpl;
+
+struct object_creation_info
+{
+ const CLSID *clsid;
+ HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
+};
+
+static const struct object_creation_info object_creation[] =
+{
+/* Keep VfwCapture as first, since I did a dirty trick in the class factory,
+ * which would really break if VfwCapture wasn't first..
+ */
+ { &CLSID_VfwCapture, &VfwCapture_create },
+ { &CLSID_CaptureGraphBuilder, &CaptureGraphBuilder_create }
+};
+
+static HRESULT WINAPI
+DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
+{
+ IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+
+ if (IsEqualGUID(riid, &IID_IUnknown)
+ || IsEqualGUID(riid, &IID_IClassFactory))
+ {
+ IClassFactory_AddRef(iface);
+ *ppobj = This;
+ return S_OK;
+ }
+
+ WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI DSCF_AddRef(LPCLASSFACTORY iface)
+{
+ IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+ return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface)
+{
+ IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ if (ref == 0)
+ HeapFree(GetProcessHeap(), 0, This);
+
+ return ref;
+}
+
+
+static HRESULT WINAPI DSCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter,
+ REFIID riid, LPVOID *ppobj)
+{
+ IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+ HRESULT hres;
+ LPUNKNOWN punk;
+
+ TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
+
+ *ppobj = NULL;
+ hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk);
+ if (SUCCEEDED(hres)) {
+ hres = IUnknown_QueryInterface(punk, riid, ppobj);
+ IUnknown_Release(punk);
+ }
+ return hres;
+}
+
+static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
+{
+ IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+ FIXME("(%p)->(%d),stub!\n",This,dolock);
+ return S_OK;
+}
+
+static IClassFactoryVtbl DSCF_Vtbl =
+{
+ DSCF_QueryInterface,
+ DSCF_AddRef,
+ DSCF_Release,
+ DSCF_CreateInstance,
+ DSCF_LockServer
+};
+
+/*******************************************************************************
+ * DllGetClassObject [QCAP.@]
+ * Retrieves class object from a DLL object
+ *
+ * NOTES
+ * Docs say returns STDAPI
+ *
+ * PARAMS
+ * rclsid [I] CLSID for the class object
+ * riid [I] Reference to identifier of interface for class object
+ * ppv [O] Address of variable to receive interface pointer for riid
+ *
+ * RETURNS
+ * Success: S_OK
+ * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG,
+ * E_UNEXPECTED
+ */
+DWORD WINAPI QCAP_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
+{
+ unsigned int i;
+ IClassFactoryImpl *factory;
+
+ TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
+
+ if ( !IsEqualGUID( &IID_IClassFactory, riid )
+ && ! IsEqualGUID( &IID_IUnknown, riid) )
+ return E_NOINTERFACE;
+
+ for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++)
+ {
+ if (IsEqualGUID(object_creation[i].clsid, rclsid))
+ break;
+ }
+
+ if (i == sizeof(object_creation)/sizeof(object_creation[0]))
+ {
+ FIXME("%s: no class found.\n", debugstr_guid(rclsid));
+ return CLASS_E_CLASSNOTAVAILABLE;
+ }
+
+ factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory));
+ if (factory == NULL) return E_OUTOFMEMORY;
+
+ factory->ITF_IClassFactory.lpVtbl = &DSCF_Vtbl;
+ factory->ref = 1;
+
+ factory->pfnCreateInstance = object_creation[i].pfnCreateInstance;
+
+ *ppv = &(factory->ITF_IClassFactory);
+ return S_OK;
+}
+
/***********************************************************************
- * DllRegisterServer (QCAP.@)
+ * DllCanUnloadNow (QCAP.@)
*/
-HRESULT WINAPI QCAP_DllRegisterServer()
+HRESULT WINAPI QCAP_DllCanUnloadNow()
{
- FIXME("(): stub\n");
- return 0;
+ return dll_ref != 0 ? S_FALSE : S_OK;
}
+
+#define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } , #name },
+
+static struct {
+ const GUID riid;
+ const char *name;
+} InterfaceDesc[] =
+{
+#include "uuids.h"
+ { { 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} }, NULL }
+};
+
/***********************************************************************
- * DllGetClassObject (QCAP.@)
+ * qcdebugstr_guid (internal)
+ *
+ * Gives a text version of QCap Guids
*/
-HRESULT WINAPI QCAP_DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
+const char * qcdebugstr_guid( const GUID * id )
{
- FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid));
- return CLASS_E_CLASSNOTAVAILABLE;
+ int i;
+ char * name = NULL;
+
+ for (i=0;InterfaceDesc[i].name && !name;i++) {
+ if (IsEqualGUID(&InterfaceDesc[i].riid, id)) return InterfaceDesc[i].name;
+ }
+ return debugstr_guid(id);
}
+
diff -Nru wine-old/dlls/qcap/qcap_private.h wine-new/dlls/qcap/qcap_private.h
--- wine-old/dlls/qcap/qcap_private.h 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/qcap_private.h 2005-04-29 00:27:34.000000000 +0200
@@ -0,0 +1,64 @@
+/* Quartz Capture private interfaces (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_PRIVATE_INCLUDED__
+#define __QCAP_PRIVATE_INCLUDED__
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "wtypes.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "dshow.h"
+
+#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
+
+HRESULT VfwCapture_create(IUnknown * pUnkOuter, LPVOID * ppv);
+HRESULT CaptureGraphBuilder_create(IUnknown * pUnkOuter, LPVOID * ppv);
+
+typedef struct tagENUMPINDETAILS
+{
+ ULONG cPins;
+ IPin ** ppPins;
+} ENUMPINDETAILS;
+
+typedef struct tagENUMEDIADETAILS
+{
+ ULONG cMediaTypes;
+ AM_MEDIA_TYPE * pMediaTypes;
+} ENUMMEDIADETAILS;
+
+HRESULT IEnumPinsImpl_Construct(const ENUMPINDETAILS * pDetails, IEnumPins ** ppEnum);
+HRESULT IEnumMediaTypesImpl_Construct(const ENUMMEDIADETAILS * pDetails, IEnumMediaTypes ** ppEnum);
+
+extern const char * qcdebugstr_guid(const GUID * id);
+
+HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc);
+void DeleteMediaType(AM_MEDIA_TYPE * pmt);
+BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards);
+void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt);
+
+#endif /* __QCAP_PRIVATE_INCLUDED__ */
diff -Nru wine-old/dlls/qcap/qcap.spec wine-new/dlls/qcap/qcap.spec
--- wine-old/dlls/qcap/qcap.spec 2003-07-30 05:48:55.000000000 +0200
+++ wine-new/dlls/qcap/qcap.spec 2005-04-28 23:07:08.000000000 +0200
@@ -1,4 +1,4 @@
-@ stub DllCanUnloadNow
+@ stdcall -private DllCanUnloadNow() QCAP_DllCanUnloadNow
@ stdcall -private DllGetClassObject(ptr ptr ptr) QCAP_DllGetClassObject
@ stdcall -private DllRegisterServer() QCAP_DllRegisterServer
-@ stub DllUnregisterServer
+@ stdcall -private DllUnregisterServer() QCAP_DllUnregisterServer
diff -Nru wine-old/dlls/qcap/regsvr.c wine-new/dlls/qcap/regsvr.c
--- wine-old/dlls/qcap/regsvr.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/regsvr.c 2005-05-05 09:22:03.000000000 +0200
@@ -0,0 +1,934 @@
+/*
+ * self-registerable dll functions for qcap.dll
+ *
+ * Copyright (C) 2003 John K. Hohm
+ *
+ * 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 NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#define COBJMACROS
+#define COM_NO_WINDOWS_H
+#include <stdarg.h>
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "winerror.h"
+
+#include "ole2.h"
+#include "uuids.h"
+#include "strmif.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+/*
+ * Near the bottom of this file are the exported DllRegisterServer and
+ * DllUnregisterServer, which make all this worthwhile.
+ */
+
+/***********************************************************************
+ * interface for self-registering
+ */
+struct regsvr_interface
+{
+ IID const *iid; /* NULL for end of list */
+ LPCSTR name; /* can be NULL to omit */
+ IID const *base_iid; /* can be NULL to omit */
+ int num_methods; /* can be <0 to omit */
+ CLSID const *ps_clsid; /* can be NULL to omit */
+ CLSID const *ps_clsid32; /* can be NULL to omit */
+};
+
+static HRESULT register_interfaces(struct regsvr_interface const *list);
+static HRESULT unregister_interfaces(struct regsvr_interface const *list);
+
+struct regsvr_coclass
+{
+ CLSID const *clsid; /* NULL for end of list */
+ LPCSTR name; /* can be NULL to omit */
+ LPCSTR ips; /* can be NULL to omit */
+ LPCSTR ips32; /* can be NULL to omit */
+ LPCSTR ips32_tmodel; /* can be NULL to omit */
+ LPCSTR progid; /* can be NULL to omit */
+ LPCSTR viprogid; /* can be NULL to omit */
+ LPCSTR progid_extra; /* can be NULL to omit */
+};
+
+static HRESULT register_coclasses(struct regsvr_coclass const *list);
+static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
+
+struct regsvr_mediatype_parsing
+{
+ CLSID const *majortype; /* NULL for end of list */
+ CLSID const *subtype;
+ LPCSTR line[11]; /* NULL for end of list */
+};
+
+static HRESULT register_mediatypes_parsing(struct regsvr_mediatype_parsing const *list);
+static HRESULT unregister_mediatypes_parsing(struct regsvr_mediatype_parsing const *list);
+
+struct regsvr_mediatype_extension
+{
+ CLSID const *majortype; /* NULL for end of list */
+ CLSID const *subtype;
+ LPCSTR extension;
+};
+
+struct mediatype
+{
+ CLSID const *majortype; /* NULL for end of list */
+ CLSID const *subtype;
+ DWORD fourcc;
+};
+
+struct pin
+{
+ DWORD flags; /* 0xFFFFFFFF for end of list */
+ struct mediatype mediatypes[11];
+};
+
+struct regsvr_filter
+{
+ CLSID const *clsid; /* NULL for end of list */
+ CLSID const *category;
+ WCHAR name[50];
+ DWORD merit;
+ struct pin pins[11];
+};
+
+static HRESULT register_mediatypes_extension(struct regsvr_mediatype_extension const *list);
+static HRESULT unregister_mediatypes_extension(struct regsvr_mediatype_extension const *list);
+
+static HRESULT register_filters(struct regsvr_filter const *list);
+static HRESULT unregister_filters(struct regsvr_filter const *list);
+
+/***********************************************************************
+ * static string constants
+ */
+static WCHAR const interface_keyname[10] = {
+ 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
+static WCHAR const base_ifa_keyname[14] = {
+ 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
+ 'e', 0 };
+static WCHAR const num_methods_keyname[11] = {
+ 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
+static WCHAR const ps_clsid_keyname[15] = {
+ 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
+ 'i', 'd', 0 };
+static WCHAR const ps_clsid32_keyname[17] = {
+ 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
+ 'i', 'd', '3', '2', 0 };
+static WCHAR const clsid_keyname[6] = {
+ 'C', 'L', 'S', 'I', 'D', 0 };
+static WCHAR const curver_keyname[7] = {
+ 'C', 'u', 'r', 'V', 'e', 'r', 0 };
+static WCHAR const ips_keyname[13] = {
+ 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
+ 0 };
+static WCHAR const ips32_keyname[15] = {
+ 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
+ '3', '2', 0 };
+static WCHAR const progid_keyname[7] = {
+ 'P', 'r', 'o', 'g', 'I', 'D', 0 };
+static WCHAR const viprogid_keyname[25] = {
+ 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
+ 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
+ 0 };
+static char const tmodel_valuename[] = "ThreadingModel";
+static WCHAR const mediatype_name[11] = {
+ 'M', 'e', 'd', 'i', 'a', ' ', 'T', 'y', 'p', 'e', 0 };
+static WCHAR const subtype_valuename[8] = {
+ 'S', 'u', 'b', 't', 'y', 'p', 'e', 0 };
+static WCHAR const sourcefilter_valuename[14] = {
+ 'S', 'o', 'u', 'r', 'c', 'e', ' ', 'F', 'i', 'l', 't', 'e', 'r', 0 };
+static WCHAR const extensions_keyname[11] = {
+ 'E', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's', 0 };
+
+/***********************************************************************
+ * static helper functions
+ */
+static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
+static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
+ WCHAR const *value);
+static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
+ char const *value);
+static LONG register_progid(WCHAR const *clsid,
+ char const *progid, char const *curver_progid,
+ char const *name, char const *extra);
+static LONG recursive_delete_key(HKEY key);
+static LONG recursive_delete_keyA(HKEY base, char const *name);
+static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
+
+/***********************************************************************
+ * register_interfaces
+ */
+static HRESULT register_interfaces(struct regsvr_interface const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY interface_key;
+
+ res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->iid; ++list) {
+ WCHAR buf[39];
+ HKEY iid_key;
+
+ StringFromGUID2(list->iid, buf, 39);
+ res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_interface_key;
+
+ if (list->name) {
+ res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)(list->name),
+ strlen(list->name) + 1);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (list->base_iid) {
+ register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (0 <= list->num_methods) {
+ static WCHAR const fmt[3] = { '%', 'd', 0 };
+ HKEY key;
+
+ res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+
+ wsprintfW(buf, fmt, list->num_methods);
+ res = RegSetValueExW(key, NULL, 0, REG_SZ,
+ (CONST BYTE*)buf,
+ (lstrlenW(buf) + 1) * sizeof(WCHAR));
+ RegCloseKey(key);
+
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (list->ps_clsid) {
+ register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (list->ps_clsid32) {
+ register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ error_close_iid_key:
+ RegCloseKey(iid_key);
+ }
+
+error_close_interface_key:
+ RegCloseKey(interface_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * unregister_interfaces
+ */
+static HRESULT unregister_interfaces(struct regsvr_interface const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY interface_key;
+
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
+ KEY_READ | KEY_WRITE, &interface_key);
+ if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->iid; ++list) {
+ WCHAR buf[39];
+
+ StringFromGUID2(list->iid, buf, 39);
+ res = recursive_delete_keyW(interface_key, buf);
+ }
+
+ RegCloseKey(interface_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * register_coclasses
+ */
+static HRESULT register_coclasses(struct regsvr_coclass const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY coclass_key;
+
+ res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+ WCHAR buf[39];
+ HKEY clsid_key;
+
+ StringFromGUID2(list->clsid, buf, 39);
+ res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+ if (list->name) {
+ res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)(list->name),
+ strlen(list->name) + 1);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->ips) {
+ res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->ips32) {
+ HKEY ips32_key;
+
+ res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL,
+ &ips32_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+ res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)list->ips32,
+ lstrlenA(list->ips32) + 1);
+ if (res == ERROR_SUCCESS && list->ips32_tmodel)
+ res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
+ (CONST BYTE*)list->ips32_tmodel,
+ strlen(list->ips32_tmodel) + 1);
+ RegCloseKey(ips32_key);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->progid) {
+ res = register_key_defvalueA(clsid_key, progid_keyname,
+ list->progid);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+ res = register_progid(buf, list->progid, NULL,
+ list->name, list->progid_extra);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->viprogid) {
+ res = register_key_defvalueA(clsid_key, viprogid_keyname,
+ list->viprogid);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+ res = register_progid(buf, list->viprogid, list->progid,
+ list->name, list->progid_extra);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ error_close_clsid_key:
+ RegCloseKey(clsid_key);
+ }
+
+error_close_coclass_key:
+ RegCloseKey(coclass_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * unregister_coclasses
+ */
+static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY coclass_key;
+
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
+ KEY_READ | KEY_WRITE, &coclass_key);
+ if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+ WCHAR buf[39];
+
+ StringFromGUID2(list->clsid, buf, 39);
+ res = recursive_delete_keyW(coclass_key, buf);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+ if (list->progid) {
+ res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+ }
+
+ if (list->viprogid) {
+ res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+ }
+ }
+
+error_close_coclass_key:
+ RegCloseKey(coclass_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * register_mediatypes_parsing
+ */
+static HRESULT register_mediatypes_parsing(struct regsvr_mediatype_parsing const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY mediatype_key;
+ WCHAR buf[39];
+ int i;
+
+ res = RegCreateKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &mediatype_key, NULL);
+ if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+ for (; res == ERROR_SUCCESS && list->majortype; ++list) {
+ HKEY majortype_key = NULL;
+ HKEY subtype_key = NULL;
+
+ StringFromGUID2(list->majortype, buf, 39);
+ res = RegCreateKeyExW(mediatype_key, buf, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &majortype_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_keys;
+
+ StringFromGUID2(list->subtype, buf, 39);
+ res = RegCreateKeyExW(majortype_key, buf, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &subtype_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_keys;
+
+ StringFromGUID2(&CLSID_AsyncReader, buf, 39);
+ res = RegSetValueExW(subtype_key, sourcefilter_valuename, 0, REG_SZ, (CONST BYTE*)buf,
+ (lstrlenW(buf) + 1) * sizeof(WCHAR));
+ if (res != ERROR_SUCCESS) goto error_close_keys;
+
+ for(i = 0; list->line[i]; i++) {
+ char buffer[3];
+ wsprintfA(buffer, "%d", i);
+ res = RegSetValueExA(subtype_key, buffer, 0, REG_SZ, (CONST BYTE*)list->line[i],
+ lstrlenA(list->line[i]));
+ if (res != ERROR_SUCCESS) goto error_close_keys;
+ }
+
+error_close_keys:
+ if (majortype_key)
+ RegCloseKey(majortype_key);
+ if (subtype_key)
+ RegCloseKey(subtype_key);
+ }
+
+ RegCloseKey(mediatype_key);
+
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * register_mediatypes_extension
+ */
+static HRESULT register_mediatypes_extension(struct regsvr_mediatype_extension const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY mediatype_key;
+ HKEY extensions_root_key = NULL;
+ WCHAR buf[39];
+
+ res = RegCreateKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &mediatype_key, NULL);
+ if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+ res = RegCreateKeyExW(mediatype_key, extensions_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &extensions_root_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->majortype; ++list) {
+ HKEY extension_key;
+
+ res = RegCreateKeyExA(extensions_root_key, list->extension, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &extension_key, NULL);
+ if (res != ERROR_SUCCESS) break;
+
+ StringFromGUID2(list->majortype, buf, 39);
+ res = RegSetValueExW(extension_key, mediatype_name, 0, REG_SZ, (CONST BYTE*)buf,
+ (lstrlenW(buf) + 1) * sizeof(WCHAR));
+ if (res != ERROR_SUCCESS) goto error_close_key;
+
+ StringFromGUID2(list->subtype, buf, 39);
+ res = RegSetValueExW(extension_key, subtype_valuename, 0, REG_SZ, (CONST BYTE*)buf,
+ (lstrlenW(buf) + 1) * sizeof(WCHAR));
+ if (res != ERROR_SUCCESS) goto error_close_key;
+
+ StringFromGUID2(&CLSID_AsyncReader, buf, 39);
+ res = RegSetValueExW(extension_key, sourcefilter_valuename, 0, REG_SZ, (CONST BYTE*)buf,
+ (lstrlenW(buf) + 1) * sizeof(WCHAR));
+ if (res != ERROR_SUCCESS) goto error_close_key;
+
+error_close_key:
+ RegCloseKey(extension_key);
+ }
+
+error_return:
+ RegCloseKey(mediatype_key);
+ if (extensions_root_key)
+ RegCloseKey(extensions_root_key);
+
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * unregister_mediatypes_parsing
+ */
+static HRESULT unregister_mediatypes_parsing(struct regsvr_mediatype_parsing const *list)
+{
+ LONG res;
+ HKEY mediatype_key;
+ HKEY majortype_key;
+ WCHAR buf[39];
+
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0,
+ KEY_READ | KEY_WRITE, &mediatype_key);
+ if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+ if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+ for (; res == ERROR_SUCCESS && list->majortype; ++list) {
+ StringFromGUID2(list->majortype, buf, 39);
+ res = RegOpenKeyExW(mediatype_key, buf, 0,
+ KEY_READ | KEY_WRITE, &majortype_key);
+ if (res == ERROR_FILE_NOT_FOUND) {
+ res = ERROR_SUCCESS;
+ continue;
+ }
+ if (res != ERROR_SUCCESS) break;
+
+ StringFromGUID2(list->subtype, buf, 39);
+ res = recursive_delete_keyW(majortype_key, buf);
+ if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+
+ /* Removed majortype key if there is no more subtype key */
+ res = RegDeleteKeyW(majortype_key, 0);
+ if (res == ERROR_ACCESS_DENIED) res = ERROR_SUCCESS;
+
+ RegCloseKey(majortype_key);
+ }
+
+ RegCloseKey(mediatype_key);
+
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * unregister_mediatypes_extension
+ */
+static HRESULT unregister_mediatypes_extension(struct regsvr_mediatype_extension const *list)
+{
+ LONG res;
+ HKEY mediatype_key;
+ HKEY extensions_root_key = NULL;
+
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, mediatype_name, 0,
+ KEY_READ | KEY_WRITE, &mediatype_key);
+ if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+ if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+ res = RegOpenKeyExW(mediatype_key, extensions_keyname, 0,
+ KEY_READ | KEY_WRITE, &extensions_root_key);
+ if (res == ERROR_FILE_NOT_FOUND)
+ res = ERROR_SUCCESS;
+ else if (res == ERROR_SUCCESS)
+ for (; res == ERROR_SUCCESS && list->majortype; ++list) {
+ res = recursive_delete_keyA(extensions_root_key, list->extension);
+ if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+ }
+
+ RegCloseKey(mediatype_key);
+ if (extensions_root_key)
+ RegCloseKey(extensions_root_key);
+
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * register_filters
+ */
+static HRESULT register_filters(struct regsvr_filter const *list)
+{
+ HRESULT hr;
+ IFilterMapper2* pFM2 = NULL;
+
+ CoInitialize(NULL);
+ hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pFM2);
+
+ if (SUCCEEDED(hr)) {
+ for (; SUCCEEDED(hr) && list->clsid; ++list) {
+ REGFILTER2 rf2;
+ REGFILTERPINS2* prfp2;
+ int i;
+
+ for (i = 0; list->pins[i].flags != 0xFFFFFFFF; i++) ;
+ rf2.dwVersion = 2;
+ rf2.dwMerit = list->merit;
+ rf2.u.s1.cPins2 = i;
+ rf2.u.s1.rgPins2 = prfp2 = (REGFILTERPINS2*) CoTaskMemAlloc(i*sizeof(REGFILTERPINS2));
+ if (!prfp2) {
+ hr = E_OUTOFMEMORY;
+ break;
+ }
+ for (i = 0; list->pins[i].flags != 0xFFFFFFFF; i++) {
+ REGPINTYPES* lpMediatype;
+ CLSID* lpClsid;
+ int j, nbmt;
+
+ for (nbmt = 0; list->pins[i].mediatypes[nbmt].majortype; nbmt++) ;
+ /* Allocate a single buffer for regpintypes struct and clsids */
+ lpMediatype = (REGPINTYPES*) CoTaskMemAlloc(nbmt*(sizeof(REGPINTYPES) + 2*sizeof(CLSID)));
+ if (!lpMediatype) {
+ hr = E_OUTOFMEMORY;
+ break;
+ }
+ lpClsid = (CLSID*) (lpMediatype + nbmt);
+ for (j = 0; j < nbmt; j++) {
+ (lpMediatype + j)->clsMajorType = lpClsid + j*2;
+ memcpy(lpClsid + j*2, list->pins[i].mediatypes[j].majortype, sizeof(CLSID));
+ (lpMediatype + j)->clsMinorType = lpClsid + j*2 + 1;
+ if (list->pins[i].mediatypes[j].subtype)
+ memcpy(lpClsid + j*2 + 1, list->pins[i].mediatypes[j].subtype, sizeof(CLSID));
+ else {
+ /* Subtype are often a combination of major type + fourcc/tag */
+ memcpy(lpClsid + j*2 + 1, list->pins[i].mediatypes[j].majortype, sizeof(CLSID));
+ *(DWORD*)(lpClsid + j*2 + 1) = list->pins[i].mediatypes[j].fourcc;
+ }
+ }
+ prfp2[i].dwFlags = list->pins[i].flags;
+ prfp2[i].cInstances = 0;
+ prfp2[i].nMediaTypes = j;
+ prfp2[i].lpMediaType = lpMediatype;
+ prfp2[i].nMediums = 0;
+ prfp2[i].lpMedium = NULL;
+ prfp2[i].clsPinCategory = NULL;
+ }
+
+ if (FAILED(hr)) {
+ ERR("failed to register with hresult 0x%lx\n", hr);
+ CoTaskMemFree(prfp2);
+ break;
+ }
+
+ hr = IFilterMapper2_RegisterFilter(pFM2, list->clsid, list->name, NULL, list->category, NULL, &rf2);
+
+ while (i) {
+ CoTaskMemFree((REGPINTYPES*)prfp2[i-1].lpMediaType);
+ i--;
+ }
+ CoTaskMemFree(prfp2);
+ }
+ }
+
+ if (pFM2)
+ IFilterMapper2_Release(pFM2);
+
+ CoUninitialize();
+
+ return hr;
+}
+
+/***********************************************************************
+ * unregister_filters
+ */
+static HRESULT unregister_filters(struct regsvr_filter const *list)
+{
+ HRESULT hr;
+ IFilterMapper2* pFM2;
+
+ CoInitialize(NULL);
+
+ hr = CoCreateInstance(&CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterMapper2, (LPVOID*)&pFM2);
+
+ if (SUCCEEDED(hr)) {
+ for (; SUCCEEDED(hr) && list->clsid; ++list)
+ hr = IFilterMapper2_UnregisterFilter(pFM2, list->category, NULL, list->clsid);
+ IFilterMapper2_Release(pFM2);
+ }
+
+ CoUninitialize();
+
+ return hr;
+}
+
+/***********************************************************************
+ * regsvr_key_guid
+ */
+static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
+{
+ WCHAR buf[39];
+
+ StringFromGUID2(guid, buf, 39);
+ return register_key_defvalueW(base, name, buf);
+}
+
+/***********************************************************************
+ * regsvr_key_defvalueW
+ */
+static LONG register_key_defvalueW(
+ HKEY base,
+ WCHAR const *name,
+ WCHAR const *value)
+{
+ LONG res;
+ HKEY key;
+
+ res = RegCreateKeyExW(base, name, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &key, NULL);
+ if (res != ERROR_SUCCESS) return res;
+ res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
+ (lstrlenW(value) + 1) * sizeof(WCHAR));
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * regsvr_key_defvalueA
+ */
+static LONG register_key_defvalueA(
+ HKEY base,
+ WCHAR const *name,
+ char const *value)
+{
+ LONG res;
+ HKEY key;
+
+ res = RegCreateKeyExW(base, name, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &key, NULL);
+ if (res != ERROR_SUCCESS) return res;
+ res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
+ lstrlenA(value) + 1);
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * regsvr_progid
+ */
+static LONG register_progid(
+ WCHAR const *clsid,
+ char const *progid,
+ char const *curver_progid,
+ char const *name,
+ char const *extra)
+{
+ LONG res;
+ HKEY progid_key;
+
+ res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
+ NULL, 0, KEY_READ | KEY_WRITE, NULL,
+ &progid_key, NULL);
+ if (res != ERROR_SUCCESS) return res;
+
+ if (name) {
+ res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)name, strlen(name) + 1);
+ if (res != ERROR_SUCCESS) goto error_close_progid_key;
+ }
+
+ if (clsid) {
+ res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
+ if (res != ERROR_SUCCESS) goto error_close_progid_key;
+ }
+
+ if (curver_progid) {
+ res = register_key_defvalueA(progid_key, curver_keyname,
+ curver_progid);
+ if (res != ERROR_SUCCESS) goto error_close_progid_key;
+ }
+
+ if (extra) {
+ HKEY extra_key;
+
+ res = RegCreateKeyExA(progid_key, extra, 0,
+ NULL, 0, KEY_READ | KEY_WRITE, NULL,
+ &extra_key, NULL);
+ if (res == ERROR_SUCCESS)
+ RegCloseKey(extra_key);
+ }
+
+error_close_progid_key:
+ RegCloseKey(progid_key);
+ return res;
+}
+
+/***********************************************************************
+ * recursive_delete_key
+ */
+static LONG recursive_delete_key(HKEY key)
+{
+ LONG res;
+ WCHAR subkey_name[MAX_PATH];
+ DWORD cName;
+ HKEY subkey;
+
+ for (;;) {
+ cName = sizeof(subkey_name) / sizeof(WCHAR);
+ res = RegEnumKeyExW(key, 0, subkey_name, &cName,
+ NULL, NULL, NULL, NULL);
+ if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
+ res = ERROR_SUCCESS; /* presumably we're done enumerating */
+ break;
+ }
+ res = RegOpenKeyExW(key, subkey_name, 0,
+ KEY_READ | KEY_WRITE, &subkey);
+ if (res == ERROR_FILE_NOT_FOUND) continue;
+ if (res != ERROR_SUCCESS) break;
+
+ res = recursive_delete_key(subkey);
+ RegCloseKey(subkey);
+ if (res != ERROR_SUCCESS) break;
+ }
+
+ if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
+ return res;
+}
+
+/***********************************************************************
+ * recursive_delete_keyA
+ */
+static LONG recursive_delete_keyA(HKEY base, char const *name)
+{
+ LONG res;
+ HKEY key;
+
+ res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
+ if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
+ if (res != ERROR_SUCCESS) return res;
+ res = recursive_delete_key(key);
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * recursive_delete_keyW
+ */
+static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
+{
+ LONG res;
+ HKEY key;
+
+ res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
+ if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
+ if (res != ERROR_SUCCESS) return res;
+ res = recursive_delete_key(key);
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * coclass list
+ */
+static struct regsvr_coclass const coclass_list[] = {
+ { &CLSID_CaptureGraphBuilder,
+ "Capture Graph Builder",
+ NULL,
+ "qcap.dll",
+ "Both"
+ },
+ { &CLSID_VfwCapture,
+ "Video for wine capture",
+ NULL,
+ "qcap.dll",
+ "Both"
+ },
+ { NULL } /* list terminator */
+};
+
+/***********************************************************************
+ * interface list
+ */
+
+static struct regsvr_interface const interface_list[] = {
+ { NULL } /* list terminator */
+};
+
+/***********************************************************************
+ * mediatype list
+ */
+
+static struct regsvr_mediatype_parsing const mediatype_parsing_list[] = {
+ { NULL } /* list terminator */
+};
+
+/***********************************************************************
+ * mediatype list
+ */
+
+static struct regsvr_mediatype_extension const mediatype_extension_list[] = {
+ { NULL } /* list terminator */
+};
+
+/***********************************************************************
+ * filter list
+ */
+
+static struct regsvr_filter const filter_list[] = {
+ { NULL } /* list terminator */
+};
+
+/***********************************************************************
+ * DllRegisterServer (QCAP.@)
+ */
+HRESULT WINAPI QCAP_DllRegisterServer(void)
+{
+ HRESULT hr;
+
+ TRACE("\n");
+
+ hr = register_coclasses(coclass_list);
+ if (SUCCEEDED(hr))
+ hr = register_interfaces(interface_list);
+ if (SUCCEEDED(hr))
+ hr = register_mediatypes_parsing(mediatype_parsing_list);
+ if (SUCCEEDED(hr))
+ hr = register_mediatypes_extension(mediatype_extension_list);
+ if (SUCCEEDED(hr))
+ hr = register_filters(filter_list);
+ return hr;
+}
+
+/***********************************************************************
+ * DllUnregisterServer (QCAP.@)
+ */
+HRESULT WINAPI QCAP_DllUnregisterServer(void)
+{
+ HRESULT hr;
+
+ TRACE("\n");
+
+ hr = unregister_filters(filter_list);
+ if (SUCCEEDED(hr))
+ hr = unregister_coclasses(coclass_list);
+ if (SUCCEEDED(hr))
+ hr = unregister_interfaces(interface_list);
+ if (SUCCEEDED(hr))
+ hr = unregister_mediatypes_parsing(mediatype_parsing_list);
+ if (SUCCEEDED(hr))
+ hr = unregister_mediatypes_extension(mediatype_extension_list);
+ return hr;
+}
diff -Nru wine-old/dlls/qcap/v4l.c wine-new/dlls/qcap/v4l.c
--- wine-old/dlls/qcap/v4l.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/v4l.c 2005-05-05 15:00:36.000000000 +0200
@@ -0,0 +1,799 @@
+/* DirectShow capture services (QCAP.DLL)
+ *
+ * Copyright 2005 Maarten Lankhorst
+ *
+ * This file contains the part of the vfw capture interface that
+ * does the actual Video4Linux(1/2) stuff required for capturing
+ * and setting/getting media format..
+ *
+ * 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
+ */
+
+#include "config.h"
+#ifdef HAVE_LINUX_VIDEODEV_H
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "qcap_private.h"
+#include "pin.h"
+
+#include "uuids.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+#include "windef.h"
+#include "winbase.h"
+#include "dshow.h"
+#include "strmif.h"
+#include "ddraw.h"
+
+#include "wine/debug.h"
+
+#include <stdio.h>
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#ifdef HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+
+/* We have videodev.h else we wouldn't be here, I included all code
+ * in this block, so I could use null.c for the no device renderer,
+ * and if someone digs into the specs, a new qcap interface can be written
+ * by modifying avicap, null.c (for ifdef change) and adding a new file
+ */
+
+#include <linux/videodev.h>
+#include <fcntl.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "winnls.h"
+#include "capture.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap_v4l);
+
+/* NOTE: Currently the V4L2 is unsupported and I'm not working on it,
+ * I have undefined HAVE_V4L2 so that I could leave the if's in place..
+ * in Capture initialisation I explained why..
+ */
+#undef HAVE_V4L2
+
+struct CaptureBox;
+typedef void (* Renderer)(struct CaptureBox *, LPBYTE bufferin, LPBYTE stream);
+
+typedef struct CaptureBox {
+/* Dunno what to put in here? */
+ UINT width, height, bitDepth, fps;
+
+ CRITICAL_SECTION CritSect;
+
+ IPin *pOut;
+ int fd, mmap;
+ int iscommitted, stopped;
+ struct video_picture pict;
+ int dbrightness, dhue, dcolour, dcontrast;
+
+#ifdef HAVE_V4L2
+ int isV4l2;
+#endif
+
+/* mmap (V4l1) */
+ struct video_mmap *grab_buf;
+ struct video_mbuf gb_buffers;
+ void *pmap;
+ int buffers;
+
+/* read (V4l1) */
+ int imagesize;
+ char * grab_data;
+
+ int curframe;
+
+ HANDLE thread;
+ Renderer renderer;
+} CaptureBox;
+
+struct renderlist {
+ int depth;
+ char* name;
+ Renderer renderer;
+};
+
+static void renderer_RGB24(CaptureBox *capBox, LPBYTE bufferin, LPBYTE stream);
+static void renderer_RGB32(CaptureBox *capBox, LPBYTE bufferin, LPBYTE stream);
+
+static const struct renderlist renderlist_V4l[] = {
+ { 0, "NULL renderer", NULL },
+ { 8, "Gray scales", NULL }, /* 1, Don't support */
+ { 0, "High 240 cube (BT848)", NULL }, /* 2, Don't support */
+ { 16, "16 bit RGB (565)", NULL }, /* 3, Don't support */
+ { 24, "24 bit RGB values", renderer_RGB24 }, /* 4, Supported, */
+ { 32, "32 bit RGB values", renderer_RGB32 }, /* 5, Supported */
+ { 16, "15 bit RGB (555)", NULL }, /* 6, Don't support */
+ { 16, "YUV 422 (Not P)", NULL }, /* 7, Should support */
+ { 16, "YUYV (Not P)", NULL }, /* 8, Should support */
+ { 16, "UYVY (Not P)", NULL }, /* 9, Should support */
+ { 12, "YUV 420 (Not P)", NULL }, /* 10, Should support */
+ { 0, "Raw capturing (BT848)", NULL }, /* 11, Don't support */
+ { 16, "YUV 422 (Planar)", NULL }, /* 12, Should support */
+ { 12, "YUV 411 (Planar)", NULL }, /* 13, Should support */
+ { 12, "YUV 420 (Planar)", NULL }, /* 14, Should support */
+ { 10, "YUV 410 (Planar)", NULL }, /* 15, Should support */
+ { 0, NULL, NULL },
+};
+
+const int fallback_V4l[] = { 4, 5, 7, 8, 9, 12, 13, 14, 15, 10 };
+/* Fallback: First try raw formats, then yuv, then yuv with a color channel missing */
+
+static int xioctl(int fd, int request, void * arg)
+{
+ int r;
+
+ do r = ioctl (fd, request, arg);
+ while (-1 == r && EINTR == errno);
+
+ return r;
+}
+
+/* Prepare the capture buffers */
+static HRESULT Capture_Prepare(CaptureBox *capBox)
+{
+ TRACE("%p: Preparing for %dx%d resolution\n", capBox, capBox->width, capBox->height);
+#ifdef HAVE_V4L2
+ if (xioctl(capBox->fd, VIDIOC_QUERYCAP, &caps) >= 0) {
+ capBox->isV4l2 = 1;
+ } else
+#endif /* HAVE_V4L2 */
+ {
+/* Try mmap */
+ capBox->mmap = 0;
+ if (xioctl(capBox->fd, VIDIOCGMBUF, &capBox->gb_buffers) != -1 && capBox->gb_buffers.frames) {
+ capBox->buffers = capBox->gb_buffers.frames;
+ if (capBox->gb_buffers.frames > 1) {
+ TRACE("%p: %d buffers granted, but only using 1 anyway\n", capBox, capBox->gb_buffers.frames);
+ capBox->buffers = 1;
+ } else {
+ TRACE("%p: Using %d buffers\n", capBox, capBox->gb_buffers.frames);
+ }
+ capBox->pmap = mmap(0, capBox->gb_buffers.size, PROT_READ|PROT_WRITE, MAP_SHARED, capBox->fd, 0);
+ if (capBox->pmap != MAP_FAILED) {
+ int i;
+ capBox->grab_buf = CoTaskMemAlloc(sizeof(struct video_mmap) * capBox->buffers);
+ if(!capBox->grab_buf) {
+ ERR("Out of memory?\n");
+ munmap(capBox->pmap, capBox->gb_buffers.size);
+ return E_OUTOFMEMORY;
+ }
+
+ /* Setup mmap capture buffers. */
+ for (i = 0; i < capBox->buffers; i++) {
+ capBox->grab_buf[i].format = capBox->pict.palette;
+ capBox->grab_buf[i].frame = i;
+ capBox->grab_buf[i].width = capBox->width;
+ capBox->grab_buf[i].height = capBox->height;
+ }
+ capBox->mmap = 1;
+ }
+ }
+ if (!capBox->mmap) {
+ capBox->buffers = 1;
+ capBox->imagesize = renderlist_V4l[capBox->pict.palette].depth * capBox->height * capBox->width / 8;
+ capBox->grab_data = CoTaskMemAlloc(capBox->imagesize);
+ if (!capBox->grab_data)
+ {
+ ERR("%p: Out of memory?\n", capBox);
+ return E_OUTOFMEMORY;
+ }
+ }
+ TRACE("Using mmap: %d\n", capBox->mmap);
+ }
+ return S_OK;
+}
+
+HRESULT Capture_Initialise(void ** pointer, IPin * pOut, USHORT card)
+{
+ CaptureBox * capBox = CoTaskMemAlloc(sizeof(CaptureBox));
+ char device[128];
+ struct stat st;
+#ifdef HAVE_V4L2
+ struct v4l2_capability caps;
+#endif
+ struct video_capability capa;
+ struct video_picture pict;
+ struct video_window window;
+ HRESULT hr;
+
+ /* Because I don't want to change every return failure,
+ I'll let VfwCapture clean up if *pointer != NULL
+ and the call failed..
+ */
+
+ *pointer = NULL; /* Until we're succesful */
+
+ if (!capBox) {
+ ERR("Out of memory\n");
+ return E_OUTOFMEMORY;
+ }
+
+ sprintf(device, "/dev/video%i", card);
+
+ if (stat (device, &st) == -1) {
+ ERR("%s: %s\n", device, strerror(errno));
+ CoTaskMemFree(capBox);
+ return E_FAIL;
+ }
+
+ if (!S_ISCHR (st.st_mode)) {
+ ERR("%s: Not a device\n", device);
+ CoTaskMemFree(capBox);
+ return E_FAIL;
+ }
+
+ capBox->fd = open(device, O_RDWR | O_NONBLOCK);
+ if (capBox->fd == -1) {
+ ERR("%s: Failed to open: %s\n", device, strerror(errno));
+ CoTaskMemFree(capBox);
+ return E_FAIL;
+ }
+
+#ifdef HAVE_V4L2
+ capBox->isV4l2 = 0;
+ if (xioctl(capBox->fd, VIDIOC_QUERYCAP, &caps) >= 0) {
+ capBox->isV4l2 = 1;
+/* There are 5 reasons I don't add V4l2 support
+ * 1. Webcams don't use it
+ * 2. It is more complicated then V4l and more complicated then it needs to be
+ * 3. V4l2 devices can fall back to V4l
+ * 4. No one really misses it if I leave it out..
+ * 5. (MAIN REASON) *I* don't miss it, if you do, write V4l2 support yourself!
+ */
+ ERR("Tinkerer detected? Thou shalt not define HAVE_V4L2\n");
+ CoTaskMemFree(capBox);
+ close(capBox->fd);
+ return E_FAIL;
+ } else
+#endif /* HAVE_V4L2 */
+ {
+ memset(&capa, 0, sizeof(capa));
+
+ if (xioctl(capBox->fd, VIDIOCGCAP, &capa) == -1) {
+ if (errno != EINVAL && errno != 515) ERR("%s: Querying failed: %s\n", device, strerror(errno));
+ else ERR("%s: Querying failed: Not a V4L compatible device", device);
+ close(capBox->fd);
+ CoTaskMemFree(capBox);
+ return E_FAIL;
+ }
+
+ if (!(capa.type & VID_TYPE_CAPTURE)) {
+ ERR("%s: This is not a video capture device\n", device);
+ close(capBox->fd);
+ CoTaskMemFree(capBox);
+ return E_FAIL;
+ }
+ TRACE("Amount of inputs on %s: %d\n", capa.name, capa.channels);
+
+ if (xioctl(capBox->fd, VIDIOCGPICT, &pict) == -1) {
+ ERR("%s: Acquiring picture properties failed, this shouldn't happen..\n", device);
+ close(capBox->fd);
+ CoTaskMemFree(capBox);
+ return E_FAIL;
+ }
+
+ TRACE("%s: Suggested picture depth: %d, suggested picture palette: %d\n", device, pict.depth, pict.palette);
+ TRACE("%s: Hue %d, Color %d, Contrast %d\n", device, pict.hue,pict.colour,pict.contrast);
+ capBox->dbrightness = pict.brightness;
+ capBox->dcolour = pict.colour;
+ capBox->dhue = pict.hue;
+ capBox->dcontrast = pict.contrast;
+/* This will most likely fail, and if it does we will fall back to 32 bits,
+ of which each first bit will be nothing but rubble, waste of bandwidth */
+ TRACE("%s: Suggested format: \"%s\"\n", device, renderlist_V4l[pict.palette].name);
+ if (!renderlist_V4l[pict.palette].renderer)
+ {
+ int palet = pict.palette, formatenum;
+ WARN("No renderer available for \"%s\", trying to fall back to defaults\n", renderlist_V4l[pict.palette].name);
+ capBox->renderer = NULL;
+ for (formatenum = 0; formatenum < (sizeof(fallback_V4l) / sizeof(int)); formatenum++) {
+ int currentrender = fallback_V4l[formatenum];
+ if (renderlist_V4l[currentrender].renderer == NULL) continue;
+ pict.depth = renderlist_V4l[currentrender].depth;
+ pict.palette = currentrender;
+ if (xioctl(capBox->fd, VIDIOCSPICT, &pict) == -1) {
+ TRACE("%s: Could not render with \"%s\"\n (%d)", device, renderlist_V4l[currentrender].name, currentrender);
+ continue;
+ }
+ TRACE("%s: Found a suitable renderer: \"%s\" (%d)\n", device, renderlist_V4l[currentrender].name, currentrender);
+ capBox->renderer = renderlist_V4l[currentrender].renderer;
+ break;
+ }
+ if (!capBox->renderer) {
+ close(capBox->fd);
+ CoTaskMemFree(capBox);
+ ERR("%s: This device wants to use \"%s\", but this format isn't available, and it didn't accept one of our other formats, GIVING UP!\n\n", device, renderlist_V4l[palet].name);
+ return E_FAIL;
+ }
+ } else {
+ TRACE("Using the suggested format\n");
+ capBox->renderer = renderlist_V4l[pict.palette].renderer;
+ }
+ memcpy(&capBox->pict, &pict, sizeof(struct video_picture));
+
+ memset(&window, 0, sizeof(window));
+ if (xioctl(capBox->fd, VIDIOCGWIN, &window) == -1) {
+ ERR("%s: Getting resolution failed.. (%s), giving up\n", device, strerror(errno));
+ return E_FAIL;
+ }
+
+ capBox->height = window.height;
+ capBox->width = window.width;
+ capBox->bitDepth = 24;
+ }
+
+ hr = Capture_Prepare(capBox);
+ if (FAILED(hr)) {
+ close(capBox->fd);
+ CoTaskMemFree(capBox);
+ return hr;
+ }
+
+ capBox->pOut = pOut;
+ capBox->fps = 3;
+ capBox->stopped = 0;
+ capBox->curframe = 0;
+ InitializeCriticalSection(&capBox->CritSect);
+ *pointer = capBox;
+
+ capBox->iscommitted = 0;
+ TRACE("Using format: %d bits - %d x %d\n", capBox->bitDepth, capBox->width, capBox->height);
+ return S_OK;
+}
+
+HRESULT Capture_Destroy(void * pBox, BOOL destroyall)
+{
+ CaptureBox *capBox = (CaptureBox *)pBox;
+ TRACE("%p\n", capBox);
+/* Destroy file handlers etc? This function can't fail.. */
+#ifdef HAVE_V4L2
+ if (capBox->isV4l2) {
+/* We should destroy V4l2 stuff here but we don't use it */
+ } else
+#endif
+ if (capBox->mmap) {
+ for (capBox->curframe = 0; capBox->curframe < capBox->buffers; capBox->curframe++)
+ xioctl(capBox->fd, VIDIOCSYNC, &capBox->grab_buf[capBox->curframe]);
+ munmap(capBox->pmap, capBox->gb_buffers.size);
+ CoTaskMemFree(capBox->grab_buf);
+ } else CoTaskMemFree(capBox->grab_data);
+ if (destroyall) {
+ ERR("Destroying all\n");
+ close(capBox->fd);
+ DeleteCriticalSection(&capBox->CritSect);
+ CoTaskMemFree(capBox);
+ }
+ TRACE("Finito\n");
+ return S_OK;
+}
+
+HRESULT Capture_SetMediaType(void * pBox, AM_MEDIA_TYPE * mT)
+{
+ CaptureBox *capBox = (CaptureBox *)pBox;
+ TRACE("%p\n", capBox);
+ if (((VIDEOINFOHEADER *)mT->pbFormat)->bmiHeader.biBitCount != 24 ||
+ ((VIDEOINFOHEADER *)mT->pbFormat)->bmiHeader.biCompression != BI_RGB)
+ {
+ ERR("Invalid media type suggested\n");
+ return VFW_E_INVALIDMEDIATYPE;
+ }
+
+ TRACE("%p -> (%p) - %ld %ld\n", capBox, mT, ((VIDEOINFOHEADER *)mT->pbFormat)->bmiHeader.biWidth, ((VIDEOINFOHEADER *)mT->pbFormat)->bmiHeader.biHeight);
+
+#ifdef HAVE_V4L2
+ if (capBox->isV4l2) {
+/* We should do V4l2 resizing here but V4l2 is not really supported.. */
+ } else
+#endif
+#if 0 /* This crashes on my pc when resizing is succesful (bttv driver) */
+ {
+ struct video_window window;
+ memset(&window, 0, sizeof(struct video_window));
+ window.width = ((VIDEOINFOHEADER *)mT->pbFormat)->bmiHeader.biWidth;
+ window.height = ((VIDEOINFOHEADER *)mT->pbFormat)->bmiHeader.biHeight;
+ if (xioctl(capBox->fd, VIDIOCSWIN, &window) == -1) {
+ ERR("Can not use the format %dx%d\n", window.width, window.height);
+ /* We return S_OK anyway to please MSN messenger, doesn't really matter, it will resize for us, it's just really slow with resizing.. we should return VFW_E_INVALIDMEDIATYPE, but msn doesn't like that.. */
+ return S_OK;
+ }
+ if (capBox->height == window.height && capBox->width == window.width)
+ return S_OK; /* Why on EARTH should we resize? */
+ capBox->height = window.height;
+ capBox->width = window.width;
+ }
+ Capture_Destroy(capBox, FALSE);
+ Capture_Prepare(capBox);
+#endif /* Return S_OK anyway, msn doesn't seem to care */
+ return S_OK;
+}
+
+HRESULT Capture_GetMediaType(void * pBox, AM_MEDIA_TYPE ** mT)
+{
+ CaptureBox *capBox = (CaptureBox *)pBox;
+ TRACE("%p\n", capBox);
+ VIDEOINFOHEADER *vi;
+ mT[0] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
+ if (!mT[0]) return E_OUTOFMEMORY;
+ vi = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER));
+ mT[0]->cbFormat = sizeof(VIDEOINFOHEADER);
+ if (!vi)
+ {
+ CoTaskMemFree(mT[0]);
+ return E_OUTOFMEMORY;
+ }
+ memcpy(&mT[0]->majortype, &MEDIATYPE_Video, sizeof(GUID));
+ memcpy(&mT[0]->subtype, &MEDIASUBTYPE_RGB24, sizeof(GUID));
+ memcpy(&mT[0]->formattype, &FORMAT_VideoInfo, sizeof(GUID));
+ mT[0]->bFixedSizeSamples = TRUE;
+ mT[0]->bTemporalCompression = FALSE;
+ mT[0]->pUnk = NULL;
+ mT[0]->lSampleSize = capBox->width * capBox->height * capBox->bitDepth / 8;
+ TRACE("Output format: %d x %d - %d bits = %lu KB\n", capBox->width, capBox->height, capBox->bitDepth, mT[0]->lSampleSize/1024);
+ vi->rcSource.left = 0; vi->rcSource.top = 0;
+ vi->rcTarget.left = 0; vi->rcTarget.top = 0;
+ vi->rcSource.right = capBox->width; vi->rcSource.bottom = capBox->height;
+ vi->rcTarget.right = capBox->width; vi->rcTarget.bottom = capBox->height;
+ vi->dwBitRate = capBox->fps * mT[0]->lSampleSize;
+ vi->dwBitErrorRate = 0;
+ vi->AvgTimePerFrame = (LONGLONG)10000000.0 / (LONGLONG)capBox->fps;
+ vi->bmiHeader.biSize = 40;
+ vi->bmiHeader.biWidth = capBox->width;
+ vi->bmiHeader.biHeight = capBox->height;
+ vi->bmiHeader.biPlanes = 1;
+ vi->bmiHeader.biBitCount = 24;
+ vi->bmiHeader.biCompression = BI_RGB;
+ vi->bmiHeader.biSizeImage = mT[0]->lSampleSize;
+ vi->bmiHeader.biClrUsed = vi->bmiHeader.biClrImportant = 0;
+ vi->bmiHeader.biXPelsPerMeter = 100;
+ vi->bmiHeader.biYPelsPerMeter = 100;
+ mT[0]->pbFormat = (void *)vi;
+ dump_AM_MEDIA_TYPE(mT[0]);
+ return S_OK;
+}
+
+HRESULT Capture_GetPropRange(void * pBox, long Property, long *pMin, long *pMax, long *pSteppingDelta, long *pDefault, long *pCapsFlags)
+{
+ CaptureBox * capBox = (CaptureBox *)pBox;
+ TRACE("%p -> %ld %p %p %p %p %p\n", pBox, Property, pMin, pMax, pSteppingDelta, pDefault, pCapsFlags);
+#ifdef HAVE_V4L2
+ if (capBox->isV4l2) {
+ } else
+#endif
+ {
+ switch (Property) {
+ case VideoProcAmp_Brightness: *pDefault = capBox->dbrightness; break;
+ case VideoProcAmp_Contrast: *pDefault = capBox->dcontrast; break;
+ case VideoProcAmp_Hue: *pDefault = capBox->dhue; break;
+ case VideoProcAmp_Saturation: *pDefault = capBox->dcolour; break;
+ default: FIXME("Not implemented %ld\n", Property); return E_NOTIMPL;
+ }
+ *pMin = 0;
+ *pMax = 65535;
+ *pSteppingDelta = 65536/256;
+ *pCapsFlags = VideoProcAmp_Flags_Manual;
+ return S_OK;
+ }
+}
+
+HRESULT Capture_GetProp(void *pBox, long Property, long *lValue, long *Flags)
+{
+ CaptureBox * capBox = (CaptureBox *)pBox;
+ TRACE("%p -> %ld %p %p\n", pBox, Property, lValue, Flags);
+#ifdef HAVE_V4L2
+ if (capBox->isV4l2) {
+ } else
+#endif
+ {
+ switch (Property) {
+ case VideoProcAmp_Brightness: *lValue = capBox->pict.brightness; break;
+ case VideoProcAmp_Contrast: *lValue = capBox->pict.contrast; break;
+ case VideoProcAmp_Hue: *lValue = capBox->pict.hue; break;
+ case VideoProcAmp_Saturation: *lValue = capBox->pict.colour; break;
+ default: FIXME("Not implemented %ld\n", Property); return E_NOTIMPL;
+ }
+ *Flags = VideoProcAmp_Flags_Manual;
+ return S_OK;
+ }
+}
+
+HRESULT Capture_SetProp(void *pBox, long Property, long lValue, long Flags)
+{
+ CaptureBox *capBox = (CaptureBox *)pBox;
+ TRACE("%p -> %ld %ld %ld\n", pBox, Property, lValue, Flags);
+#ifdef HAVE_V4L2
+ if (capBox->isV4l2) {
+ } else
+#endif
+ {
+ switch (Property) {
+ case VideoProcAmp_Brightness: capBox->pict.brightness = lValue; break;
+ case VideoProcAmp_Contrast: capBox->pict.contrast = lValue; break;
+ case VideoProcAmp_Hue: capBox->pict.hue = lValue; break;
+ case VideoProcAmp_Saturation: capBox->pict.colour = lValue; break;
+ default: FIXME("Not implemented %ld\n", Property); return E_NOTIMPL;
+ }
+
+ if (xioctl(capBox->fd, VIDIOCSPICT, &capBox->pict) == -1) {
+ ERR("Adjusting picture properties failed..\n");
+ return E_FAIL;
+ }
+ return S_OK;
+ }
+}
+
+static void renderer_RGB24(CaptureBox *capBox, LPBYTE bufferin, LPBYTE stream)
+{
+ int size = capBox->height * capBox->width * 3;
+ TRACE("%p\n", capBox);
+ memcpy(bufferin, stream, size);
+}
+
+static void renderer_RGB32(CaptureBox *capBox, LPBYTE bufferin, LPBYTE stream)
+{
+ int size = capBox->height * capBox->width * 4;
+ int pointer = 0, offset = 1;
+ TRACE("()\n");
+
+ /* I guess it's easier - but slower to do this per byte.. */
+
+ while (pointer + offset <= size) {
+ bufferin[pointer] = stream[pointer + offset];
+ pointer++;
+ bufferin[pointer] = stream[pointer + offset];
+ pointer++;
+ bufferin[pointer] = stream[pointer + offset];
+ pointer++;
+ offset++;
+ }
+}
+
+static void Resize(CaptureBox * capBox, LPBYTE output, LPBYTE input)
+{
+ int depth = capBox->bitDepth / 8;
+ int inoffset = 0, outoffset = (capBox->height-1) * capBox->width * depth;
+ int ow = capBox->width * depth;
+ TRACE("\n");
+ while (outoffset) {
+ int x;
+ outoffset -= ow;
+ for (x = 0; x < ow; x++)
+ output[outoffset + x] = input[inoffset + x];
+ inoffset += ow;
+ }
+}
+
+static void Capture_GetFrame(CaptureBox * capBox, LPBYTE * pInput)
+{
+#ifdef HAVE_V4L2
+ if (capBox->isV4l2) {
+ } else
+#endif
+ if (capBox->mmap) {
+ if (xioctl(capBox->fd, VIDIOCSYNC, &capBox->grab_buf[capBox->curframe]) == -1)
+ ERR("Syncing ioctl failed: %s\n", strerror(errno));
+ *pInput = ((char *)capBox->pmap) + capBox->gb_buffers.offsets[capBox->curframe];
+ } else {
+ int retval;
+ while ((retval = read(capBox->fd, capBox->grab_data, capBox->imagesize)) == -1)
+ if (errno != EAGAIN) break;
+ if (retval == -1)
+ ERR("Error occured while reading from device: %s\n", strerror(errno));
+ *pInput = capBox->grab_data;
+ }
+}
+
+static void Capture_FreeFrame(CaptureBox * capBox)
+{
+ TRACE("\n");
+#ifdef HAVE_V4L2
+ if (capBox->isV4l2) {
+ } else
+#endif
+ if (capBox->mmap) {
+ if (xioctl(capBox->fd, VIDIOCMCAPTURE, &capBox->grab_buf[capBox->curframe]) == -1)
+ ERR("Freeing frame for capture failed: %s\n", strerror(errno));
+ }
+ if (++capBox->curframe == capBox->buffers) capBox->curframe = 0;
+}
+
+static DWORD WINAPI ReadThread(LPVOID lParam) {
+ CaptureBox * capBox = lParam;
+ HRESULT hr;
+ IMediaSample *pSample = NULL;
+ unsigned long framecount = 0;
+ LPBYTE pTarget, pInput, pOutput;
+ pOutput = CoTaskMemAlloc(capBox->width * capBox->height * 3);
+ capBox->curframe = 0;
+ do Capture_FreeFrame(capBox); while (capBox->curframe != 0);
+
+ while (1) {
+ EnterCriticalSection(&capBox->CritSect);
+ if (capBox->stopped) break;
+ hr = OutputPin_GetDeliveryBuffer((OutputPin *)capBox->pOut, &pSample, NULL, NULL, 0);
+ if (SUCCEEDED(hr)) {
+ IMediaSample_SetActualDataLength(pSample, capBox->height * capBox->width * capBox->bitDepth / 8);
+ TRACE("Data length: %d KB\n", capBox->height * capBox->width * capBox->bitDepth / 8 / 1024);
+ IMediaSample_GetPointer(pSample, &pTarget);
+ /* TODO: Check return values.. */
+ Capture_GetFrame(capBox, &pInput);
+ capBox->renderer(capBox, pOutput, pInput);
+ Resize(capBox, pTarget, pOutput);
+ hr = OutputPin_SendSample((OutputPin *)capBox->pOut, pSample);
+ FIXME("%p -> Frame %lu: %lx\n", capBox, ++framecount, hr);
+ IMediaSample_Release(pSample);
+ Capture_FreeFrame(capBox);
+ }
+ LeaveCriticalSection(&capBox->CritSect);
+ if (FAILED(hr) && hr != VFW_E_NOT_CONNECTED) {
+ ERR("Received error: %lx\n", hr);
+ }
+ }
+ LeaveCriticalSection(&capBox->CritSect);
+ CoTaskMemFree(pOutput);
+
+ return 0x0;
+}
+
+HRESULT Capture_Run(void * pBox, FILTER_STATE *state)
+{
+ CaptureBox *capBox = (CaptureBox *)pBox;
+ HANDLE thread;
+ HRESULT hr;
+
+ TRACE("%p -> (%p)\n", capBox, state);
+
+ if (*state == State_Running) return S_OK;
+
+ EnterCriticalSection(&capBox->CritSect);
+
+ capBox->stopped = 0;
+
+ if (*state == State_Stopped)
+ {
+ *state = State_Running;
+ if (!capBox->iscommitted++) {
+ IMemAllocator * pAlloc = NULL;
+ ALLOCATOR_PROPERTIES ap, actual;
+ ap.cBuffers = 3;
+ ap.cbBuffer = capBox->width * capBox->height * capBox->bitDepth / 8;
+ ap.cbAlign = 1;
+ ap.cbPrefix = 0;
+
+ hr = IMemInputPin_GetAllocator(((OutputPin *)capBox->pOut)->pMemInputPin, &pAlloc);
+
+ if (SUCCEEDED(hr))
+ hr = IMemAllocator_SetProperties(pAlloc, &ap, &actual);
+
+ if (SUCCEEDED(hr))
+ hr = IMemAllocator_Commit(pAlloc);
+
+ if (pAlloc)
+ IMemAllocator_Release(pAlloc);
+
+ TRACE("Committing allocator: %lx\n", hr);
+ }
+
+ thread = CreateThread(NULL, 0, ReadThread, capBox, 0, NULL);
+ if (thread) {
+ capBox->thread = thread;
+ SetThreadPriority(thread, THREAD_PRIORITY_LOWEST);
+ LeaveCriticalSection(&capBox->CritSect);
+ return S_OK;
+ }
+ ERR("Creating thread failed.. %lx\n", GetLastError());
+ LeaveCriticalSection(&capBox->CritSect);
+ return E_FAIL;
+ }
+
+ ResumeThread(capBox->thread);
+ *state = State_Running;
+ LeaveCriticalSection(&capBox->CritSect);
+ return S_OK;
+}
+
+HRESULT Capture_Pause(void * pBox, FILTER_STATE *state)
+{
+ CaptureBox *capBox = (CaptureBox *)pBox;
+ TRACE("%p -> (%p)\n", capBox, state);
+ if (*state == State_Paused) return S_OK;
+ if (*state == State_Stopped) Capture_Run(pBox, state);
+ EnterCriticalSection(&capBox->CritSect);
+ *state = State_Paused;
+ SuspendThread(capBox->thread);
+ LeaveCriticalSection(&capBox->CritSect);
+ return S_OK;
+}
+
+HRESULT Capture_Stop(void * pBox, FILTER_STATE *state)
+{
+ CaptureBox *capBox = (CaptureBox *)pBox;
+ TRACE("%p -> (%p)\n", capBox, state);
+ if (*state == State_Stopped) return S_OK;
+
+ EnterCriticalSection(&capBox->CritSect);
+
+ if (capBox->thread) {
+ if (*state == State_Paused)
+ ResumeThread(capBox->thread);
+ *state = State_Stopped;
+ capBox->stopped = 1;
+ capBox->thread = 0;
+ if (capBox->iscommitted) {
+ HRESULT hr;
+ IMemInputPin *pMem = NULL;
+ IMemAllocator * pAlloc = NULL;
+ IPin *pConnect = NULL;
+
+ capBox->iscommitted = 0;
+
+ hr = IPin_ConnectedTo(capBox->pOut, &pConnect);
+
+ if (SUCCEEDED(hr))
+ hr = IPin_QueryInterface(pConnect, &IID_IMemInputPin, (void **) &pMem);
+
+ if (SUCCEEDED(hr))
+ hr = IMemInputPin_GetAllocator(pMem, &pAlloc);
+
+ if (SUCCEEDED(hr))
+ hr = IMemAllocator_Decommit(pAlloc);
+
+ if (pAlloc)
+ IMemAllocator_Release(pAlloc);
+
+ if (pMem)
+ IMemInputPin_Release(pMem);
+
+ if (pConnect)
+ IPin_Release(pConnect);
+
+ if (hr != S_OK && hr != VFW_E_NOT_COMMITTED)
+ ERR("Decommitting allocator: %lx\n", hr);
+ }
+ }
+
+ LeaveCriticalSection(&capBox->CritSect);
+ return S_OK;
+}
+
+#endif /* HAVE_LINUX_VIDEODEV_H */
+
diff -Nru wine-old/dlls/qcap/vfwcapture.c wine-new/dlls/qcap/vfwcapture.c
--- wine-old/dlls/qcap/vfwcapture.c 1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/qcap/vfwcapture.c 2005-05-05 14:49:51.000000000 +0200
@@ -0,0 +1,777 @@
+/* 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
+ *
+ * Ugh, Now I can't tell what's worser, COM or the bugs in filtergraph, pins, enummedia and devenum..
+ * This file is only compiled if we found a working videodev.h
+ * If it doesn't exist, null.c will be compiled instead
+ */
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "config.h"
+#include "qcap_private.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(qcap);
+
+#include "pin.h"
+#include "capture.h"
+#include "uuids.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+#include "windef.h"
+#include "winbase.h"
+#include "dshow.h"
+#include "strmif.h"
+#include "ddraw.h"
+#include "ocidl.h"
+#include "oleauto.h"
+
+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 * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
+static const WCHAR wszOutputPinName[] = { 'O','u','t','p','u','t',0 };
+
+typedef struct VfwCapture
+{
+ const struct IBaseFilterVtbl * lpVtbl;
+ const struct IAMStreamConfigVtbl * IAMStreamConfig_vtbl;
+ const struct IAMVideoProcAmpVtbl * IAMVideoProcAmp_vtbl;
+ const struct IPersistPropertyBagVtbl * IPersistPropertyBag_vtbl;
+
+ BOOL init;
+ LPVOID myCap;
+ ULONG refCount;
+ FILTER_INFO filterInfo;
+ FILTER_STATE state;
+ CRITICAL_SECTION csFilter;
+
+ IPin * pOutputPin;
+} VfwCapture;
+
+/* VfwPin implementation */
+typedef struct VfwPinImpl
+{
+ OutputPin pin;
+
+ LPVOID myCap;
+ IKsPropertySetVtbl * KSP_VT;
+} VfwPinImpl;
+
+HRESULT VfwCapture_create(IUnknown * pUnkOuter, LPVOID * ppv)
+{
+ VfwCapture *pVfwCapture;
+ HRESULT hr;
+
+ TRACE("%p - %p\n", pUnkOuter, ppv);
+
+ if (pUnkOuter)
+ return CLASS_E_NOAGGREGATION;
+
+ pVfwCapture = CoTaskMemAlloc(sizeof(VfwCapture));
+
+ if (!pVfwCapture)
+ return E_OUTOFMEMORY;
+
+ 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 E_OUTOFMEMORY;
+ }
+ *ppv = (LPVOID)pVfwCapture;
+ TRACE("-- created at %p\n", pVfwCapture);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI VfwCapture_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
+{
+ VfwCapture *This = (VfwCapture *)iface;
+ TRACE("(%s, %p)\n", qcdebugstr_guid(riid), ppv);
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, &IID_IUnknown))
+ *ppv = (LPVOID)This;
+ else if (IsEqualIID(riid, &IID_IPersist))
+ *ppv = (LPVOID)This;
+ else if (IsEqualIID(riid, &IID_IMediaFilter))
+ *ppv = (LPVOID)This;
+ else if (IsEqualIID(riid, &IID_IBaseFilter))
+ *ppv = (LPVOID)This;
+ else if (IsEqualIID(riid, &IID_IAMStreamConfig))
+ *ppv = (LPVOID)&(This->IAMStreamConfig_vtbl);
+ else if (IsEqualIID(riid, &IID_IAMVideoProcAmp))
+ *ppv = (LPVOID)&(This->IAMVideoProcAmp_vtbl);
+ else if (IsEqualIID(riid, &IID_IPersistPropertyBag))
+ *ppv = (LPVOID)&(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", qcdebugstr_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", qcdebugstr_guid(riid));
+ IUnknown_AddRef((IUnknown *)(*ppv));
+ return S_OK;
+ }
+
+ FIXME("No interface for %s!\n", qcdebugstr_guid(riid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI VfwCapture_AddRef(IBaseFilter * iface)
+{
+ VfwCapture *This = (VfwCapture *)iface;
+ ULONG refCount = InterlockedIncrement(&This->refCount);
+
+ TRACE("(%p/%p)->() New refcount: %ld\n", This, iface, refCount);
+
+ return refCount;
+}
+
+static ULONG WINAPI VfwCapture_Release(IBaseFilter * iface)
+{
+ VfwCapture *This = (VfwCapture *)iface;
+ ULONG refCount = InterlockedDecrement(&This->refCount);
+ TRACE("(%p/%p)->() New refcount: %ld\n", This, iface, refCount);
+
+ if (!refCount)
+ {
+ TRACE("(): Destroying everything!\n");
+ if (This->init) {
+ if (This->state != State_Stopped)
+ Capture_Stop(This->myCap, &This->state);
+ Capture_Destroy(This->myCap, TRUE);
+ }
+ if (((IPinImpl *)This->pOutputPin)->pConnectedTo != NULL)
+ {
+ IPin_Disconnect(((IPinImpl *)This->pOutputPin)->pConnectedTo);
+ IPin_Disconnect(This->pOutputPin);
+ }
+ IPin_Release(This->pOutputPin);
+ DeleteCriticalSection(&This->csFilter);
+ This->lpVtbl = NULL;
+ CoTaskMemFree(This);
+ }
+ 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 Capture_Stop(This->myCap, &This->state);
+}
+
+static HRESULT WINAPI VfwCapture_Pause(IBaseFilter * iface)
+{
+ VfwCapture *This = (VfwCapture *)iface;
+ TRACE("()\n");
+ return Capture_Pause(This->myCap, &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 Capture_Run(This->myCap, &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);
+
+ strcpyW(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)
+ strcpyW(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, qcdebugstr_guid(riid));
+ if (IsEqualIID(riid, &IID_IUnknown) ||
+ IsEqualIID(riid, &IID_IAMStreamConfig))
+ {
+ *ppv = (LPVOID)iface;
+ return S_OK;
+ }
+
+ FIXME("No interface for iid %s\n", qcdebugstr_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);
+
+ 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);
+
+ if (((IPinImpl *)This->pOutputPin)->pConnectedTo != NULL) {
+ hr = IPin_QueryAccept(((IPinImpl *)This->pOutputPin)->pConnectedTo, pmt);
+ TRACE("Would accept: %ld\n", hr);
+ if (hr == S_FALSE)
+ return VFW_E_INVALIDMEDIATYPE;
+ }
+
+ hr = Capture_SetMediaType(This->myCap, pmt);
+ if (SUCCEEDED(hr) && hr == S_OK && This->filterInfo.pGraph != NULL &&
+ ((IPinImpl *)This->pOutputPin)->pConnectedTo != NULL) {
+ 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 Capture_GetMediaType(This->myCap, 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 = (LPVOID)iface;
+ return S_OK;
+ }
+
+ FIXME("No interface for iid %s\n", qcdebugstr_guid(riid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI AMVideoProcAmp_AddRef(IAMVideoProcAmp * iface)
+{
+ ICOM_THIS_MULTI(VfwCapture, IAMVideoProcAmp_vtbl, iface);
+ TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This);
+ return IUnknown_AddRef((IUnknown *)This);
+}
+
+static ULONG WINAPI AMVideoProcAmp_Release(IAMVideoProcAmp * iface)
+{
+ ICOM_THIS_MULTI(VfwCapture, IAMVideoProcAmp_vtbl, iface);
+ TRACE("%p --> Forwarding to VfwCapture (%p)\n", iface, This);
+ 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 Capture_GetPropRange(This->myCap, 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 Capture_SetProp(This->myCap, Property, lValue, Flags);
+}
+
+static HRESULT WINAPI AMVideoProcAmp_Get(IAMVideoProcAmp * iface, long Property, long *lValue, long *Flags)
+{
+ ICOM_THIS_MULTI(VfwCapture, IAMVideoProcAmp_vtbl, iface);
+ return Capture_GetProp(This->myCap, 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)
+{
+ ICOM_THIS_MULTI(VfwCapture, IPersistPropertyBag_vtbl, iface);
+ if (IsEqualIID(riid, &IID_IUnknown) ||
+ IsEqualIID(riid, &IID_IPersist) ||
+ IsEqualIID(riid, &IID_IPersistPropertyBag))
+ {
+ *ppv = (LPVOID)iface;
+ return S_OK;
+ }
+ if (IsEqualIID(riid, &IID_IBaseFilter)) {
+ FIXME("Native devenum asks for IBaseFilter, should I do this?\n");
+ *ppv = (LPVOID)This;
+ IUnknown_AddRef((IUnknown *)This);
+ return S_OK;
+ }
+
+ FIXME("No interface for iid %s\n", qcdebugstr_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};
+ V_VT(&var) = VT_I4;
+
+ TRACE("%p/%p-> (%p, %p)\n", iface, This, pPropBag, pErrorLog);
+
+ hr = IPropertyBag_Read(pPropBag, (LPCOLESTR)VFWIndex, &var, pErrorLog);
+
+ if (SUCCEEDED(hr)) {
+ hr = Capture_Initialise(&This->myCap, This->pOutputPin, (USHORT)var.__VARIANT_NAME_1.__VARIANT_NAME_2.__VARIANT_NAME_3.ulVal);
+ ((VfwPinImpl *)This->pOutputPin)->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;
+ return S_OK;
+ }
+
+ FIXME("No interface for iid %s\n", qcdebugstr_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)
+{
+ 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;
+ *(GUID *)pPropData = PIN_CATEGORY_PREVIEW;
+ FIXME("() Not adding a pin with PIN_CATEGORY_CAPTURE for a reason..\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)
+{
+ ALLOCATOR_PROPERTIES ap;
+ VfwPinImpl * pPinImpl;
+ PIN_INFO piOutput;
+
+ pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
+ if (!pPinImpl)
+ return E_OUTOFMEMORY;
+
+/*What we put here for props is overridden by the Capture_Run when committing*/
+ ap.cBuffers = 3;
+ ap.cbBuffer = 230400;
+ ap.cbAlign = 1;
+ ap.cbPrefix = 0;
+
+ piOutput.dir = PINDIR_OUTPUT;
+ piOutput.pFilter = pBaseFilter;
+ strcpyW(piOutput.achName, wszOutputPinName);
+
+ if (SUCCEEDED(OutputPin_Init(&piOutput, &ap, pBaseFilter, NULL, pCritSec, &pPinImpl->pin)))
+ {
+ 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", qcdebugstr_guid(riid), ppv);
+ *ppv = NULL;
+ if (IsEqualIID(riid, &IID_IUnknown))
+ *ppv = (LPVOID)This;
+ else if (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", qcdebugstr_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);
+ return 0;
+ }
+ 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 = Capture_GetMediaType(This->myCap, &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)->(%lx%08lx, %lx%08lx, %e)\n", iface, (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)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
+};
+
-------------- next part --------------
Index: dlls/devenum/mediacatenum.c
===================================================================
RCS file: /home/wine/wine/dlls/devenum/mediacatenum.c,v
retrieving revision 1.15
diff -u -p -r1.15 mediacatenum.c
--- dlls/devenum/mediacatenum.c 26 Apr 2005 08:15:38 -0000 1.15
+++ dlls/devenum/mediacatenum.c 5 May 2005 13:32:41 -0000
@@ -25,6 +25,7 @@
#include "devenum_private.h"
#include "vfwmsgs.h"
#include "oleauto.h"
+#include "ocidl.h"
#include "wine/debug.h"
@@ -431,7 +432,18 @@ static HRESULT WINAPI DEVENUM_IMediaCatM
if (pObj!=NULL)
{
/* get the requested interface from the loaded class */
- res= IUnknown_QueryInterface(pObj,riidResult,ppvResult);
+ res = S_OK;
+ if (pProp) {
+ HRESULT res2;
+ LPVOID ppv = NULL;
+ res2 = IUnknown_QueryInterface(pObj, &IID_IPersistPropertyBag, &ppv);
+ if (SUCCEEDED(res2)) {
+ res = IPersistPropertyBag_Load((IPersistPropertyBag *) ppv, pProp, NULL);
+ IPersistPropertyBag_Release((IPersistPropertyBag *) ppv);
+ }
+ }
+ if (SUCCEEDED(res))
+ res= IUnknown_QueryInterface(pObj,riidResult,ppvResult);
IUnknown_Release(pObj);
}
More information about the wine-patches
mailing list