MSN Webcam patch (New: Now WITH Completely randomly transmitted images)

Maarten Lankhorst m.b.lankhorst at gmail.com
Sun Apr 17 14:08:47 CDT 2005


SInce stuff is missing from msvideo (ICSeqCompressFrame{Start,,Stop}) 
you have to use native MSVFW32.DLL

This will crash when you stop msn webcam (Because of the CreateThread 
continuing to run)
In general it is very unstable, but at least it proves you can use 
'webcam's under wine.

How does it work?
apply patch
set quartz, qcap and devenum to builtin (qcap just to be sure..)
set msvfw32 to native (and make sure you have a native msvfw32)
regsvr32 quartz.dll
Run msn messenger (I tested it with MSN 6.2, dutch version, not sure 
wether it will work under 7.0)
Now you can use the 'webcam'

If you want, you can even make some patterns by changing the following 
lines in capture.c ;)
      for (pl0ink = 0;pl0ink < 320*240*3;pl0ink++)
         myData[pl0ink] = (BYTE) (rand() % 256);

This patch is not very stable yet, but it's still a work in progress..
If anyone got some links to gstreamer tutorials that would help me with 
this, I would happily accept :)
-------------- next part --------------
diff -Nru wine-old/dlls/devenum/createdevenum.c wine-new/dlls/devenum/createdevenum.c
--- wine-old/dlls/devenum/createdevenum.c	2005-01-25 11:56:39.000000000 +0100
+++ wine-new/dlls/devenum/createdevenum.c	2005-04-15 21:23:47.000000000 +0200
@@ -117,6 +117,7 @@
 
     if (IsEqualGUID(clsidDeviceClass, &CLSID_AudioRendererCategory) ||
         IsEqualGUID(clsidDeviceClass, &CLSID_AudioInputDeviceCategory) ||
+        IsEqualGUID(clsidDeviceClass, &CLSID_VideoInputDeviceCategory) ||
         IsEqualGUID(clsidDeviceClass, &CLSID_MidiRendererCategory))
     {
         hbasekey = HKEY_CURRENT_USER;
@@ -142,6 +143,7 @@
     {
         if (IsEqualGUID(clsidDeviceClass, &CLSID_AudioRendererCategory) ||
             IsEqualGUID(clsidDeviceClass, &CLSID_AudioInputDeviceCategory) ||
+            IsEqualGUID(clsidDeviceClass, &CLSID_VideoInputDeviceCategory) ||
             IsEqualGUID(clsidDeviceClass, &CLSID_MidiRendererCategory))
         {
              HRESULT hr = DEVENUM_CreateSpecialCategories();
@@ -413,6 +415,7 @@
                 CoTaskMemFree(pTypes);
 	    }
 	}
+        res = DEVENUM_CreateAMCategoryKey(&CLSID_VideoInputDeviceCategory);
     }
 
     if (pMapper)
diff -Nru wine-old/dlls/devenum/devenum_main.c wine-new/dlls/devenum/devenum_main.c
--- wine-old/dlls/devenum/devenum_main.c	2004-12-07 15:37:11.000000000 +0100
+++ wine-new/dlls/devenum/devenum_main.c	2005-04-15 21:23:47.000000000 +0200
@@ -122,7 +122,7 @@
 	{&CLSID_AudioCompressorCategory, acmcat, TRUE},
 	{&CLSID_VideoCompressorCategory, vidcat, TRUE},
 	{&CLSID_LegacyAmFilterCategory, filtcat, TRUE},
-	{&CLSID_VideoInputDeviceCategory, vfwcat, FALSE},
+	{&CLSID_VideoInputDeviceCategory, vfwcat, TRUE},
 	{&CLSID_AudioInputDeviceCategory, wavein, FALSE},
 	{&CLSID_AudioRendererCategory, waveout, FALSE},
 	{&CLSID_MidiRendererCategory, midiout, FALSE},
@@ -156,7 +156,7 @@
 
         pMapper = (IFilterMapper2*)mapvptr;
 
-        IFilterMapper2_CreateCategory(pMapper, &CLSID_VideoInputDeviceCategory, MERIT_DO_NOT_USE, friendlyvidcap);
+        IFilterMapper2_CreateCategory(pMapper, &CLSID_VideoInputDeviceCategory, MERIT_NORMAL, friendlyvidcap);
         IFilterMapper2_CreateCategory(pMapper, &CLSID_LegacyAmFilterCategory, MERIT_NORMAL, friendlydshow);
         IFilterMapper2_CreateCategory(pMapper, &CLSID_VideoCompressorCategory, MERIT_DO_NOT_USE, friendlyvidcomp);
         IFilterMapper2_CreateCategory(pMapper, &CLSID_AudioInputDeviceCategory, MERIT_DO_NOT_USE, friendlyaudcap);
diff -Nru wine-old/dlls/msvideo/msvideo_main.c wine-new/dlls/msvideo/msvideo_main.c
--- wine-old/dlls/msvideo/msvideo_main.c	2005-02-17 12:51:01.000000000 +0100
+++ wine-new/dlls/msvideo/msvideo_main.c	2005-04-17 20:35:19.000000000 +0200
@@ -1132,7 +1132,7 @@
 }
 
 /***********************************************************************
- *      ICSeqCompressFrameEnd   [MSVFW32.@]
+ *      ICSeqCompressFrameStart [MSVFW32.@]
  */
 BOOL VFWAPI ICSeqCompressFrameStart(PCOMPVARS pc, LPBITMAPINFO lpbiIn)
 {
diff -Nru wine-old/dlls/quartz/capture.c wine-new/dlls/quartz/capture.c
--- wine-old/dlls/quartz/capture.c	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/quartz/capture.c	2005-04-17 17:32:58.000000000 +0200
@@ -0,0 +1,166 @@
+/* DirectShow capture services (QUARTZ.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
+ */
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "quartz_private.h"
+#include "control_private.h"
+#include "pin.h"
+#include "capture.h"
+
+#include "uuids.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+#include "fourcc.h"
+#include "windef.h"
+#include "winbase.h"
+#include "dshow.h"
+#include "strmif.h"
+#include "ddraw.h"
+
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(quartz);
+
+HRESULT Capture_Initialise(CaptureBox * capBox, IPin * pOut, USHORT card)
+{
+/* Connect to webcam through gstreamer or whatever source */
+  capBox->width = 320;
+  capBox->height = 240;
+  capBox->bitDepth = 24;
+  capBox->pOut = pOut;
+  capBox->fps = 30;
+  return S_OK;
+}
+
+HRESULT Capture_Destroy(CaptureBox * capBox)
+{
+/* Destroy file handlers etc? This function can't fail.. */
+   return S_OK;
+}
+
+HRESULT Capture_SetMediaType(CaptureBox * capBox, AM_MEDIA_TYPE * mT)
+{
+/* Only time I can imagine this doesn't return is with incompatible type */
+/* We should check rcTarget rectangle? */
+   FIXME("%p -> (%p)\n", capBox, mT);
+   capBox->width = ((BITMAPINFOHEADER *)mT->pbFormat)->biWidth;
+   capBox->height = ((BITMAPINFOHEADER *)mT->pbFormat)->biHeight;
+   capBox->bitDepth = ((BITMAPINFOHEADER *)mT->pbFormat)->biBitCount;
+   return S_OK;
+}
+
+HRESULT Capture_GetMediaType(CaptureBox * capBox, AM_MEDIA_TYPE ** mT)
+{
+   FIXME("%p\n", capBox);
+   VIDEOINFOHEADER *vi;
+   mT[0] = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
+   if (!mT[0]) return E_OUTOFMEMORY;
+   vi = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
+   mT[0]->cbFormat = sizeof(AM_MEDIA_TYPE);
+   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 = 1;
+   mT[0]->bTemporalCompression = 0;
+   ZeroMemory(&vi->rcSource, sizeof(RECT));
+   ZeroMemory(&vi->rcTarget, sizeof(RECT));
+   vi->dwBitRate = capBox->fps * capBox->width * capBox->height * capBox->bitDepth / 8;
+   vi->dwBitErrorRate = 0;
+   vi->AvgTimePerFrame = 10000000 / capBox->fps;
+   vi->bmiHeader.biSize = capBox->width * capBox->height * capBox->bitDepth / 8;
+   vi->bmiHeader.biWidth = capBox->width;
+   vi->bmiHeader.biHeight = capBox->height;
+   vi->bmiHeader.biPlanes = 1;
+   vi->bmiHeader.biBitCount = 24;
+   vi->bmiHeader.biCompression = vi->bmiHeader.biSizeImage = 0;
+   vi->bmiHeader.biClrUsed = vi->bmiHeader.biClrImportant = 0;
+   mT[0]->pbFormat = (void *)vi;
+   return S_OK;
+}
+
+DWORD WINAPI TestBed(LPVOID lParam) {
+   CaptureBox * capBox = lParam;
+   HRESULT hr;
+   long pl0ink; int m33p;
+   IMediaSample *pSample = NULL;
+   RGBTRIPLE * pData = NULL;
+
+   usleep(1000000);
+   hr = OutputPin_CommitAllocator((OutputPin *)capBox->pOut);
+   TRACE("Meat 0: %lx\n", hr);
+   hr = OutputPin_GetDeliveryBuffer((OutputPin *)capBox->pOut, &pSample, NULL, NULL, 0);
+   TRACE("Meat 1: %lx - %p\n", hr, pSample);
+   hr = IMediaSample_SetActualDataLength(pSample, 230400);
+   TRACE("Meat 2: %lx\n", hr);
+   hr = IMediaSample_GetPointer(pSample, (BYTE **)&pData);
+   TRACE("Meat 3: %lx\n", hr);
+   for (pl0ink = 0;pl0ink < 320*240;pl0ink++) {
+      pData[pl0ink].rgbtRed   = (BYTE) (rand() % 256);
+      pData[pl0ink].rgbtGreen = (BYTE) (rand() % 256);
+      pData[pl0ink].rgbtBlue  = (BYTE) (rand() % 256);
+   }
+   TRACE("Meat 4\n");
+   hr = OutputPin_SendSample((OutputPin *)capBox->pOut, pSample);
+   FIXME("%p -> stub: %lx\n", capBox, hr);
+   IMediaSample_Release(pSample);
+   if (SUCCEEDED(hr)) for (m33p = 0; m33p < 256; m33p++) {
+      BYTE * myData;
+      OutputPin_GetDeliveryBuffer((OutputPin *)capBox->pOut, &pSample, NULL, NULL, 0);
+      IMediaSample_SetActualDataLength(pSample, 230400);
+      IMediaSample_GetPointer(pSample, &myData);
+      for (pl0ink = 0;pl0ink < 320*240*3;pl0ink++)
+         myData[pl0ink] = (BYTE) (rand() % 256);
+      hr = OutputPin_SendSample((OutputPin *)capBox->pOut, pSample);
+      FIXME("%p -> Frame %d: %lx\n", capBox, m33p + 2, hr);
+      usleep(1000*1000);
+      IMediaSample_Release(pSample);
+   }
+   return 0x0;
+}
+
+HRESULT Capture_Run(CaptureBox * capBox, FILTER_STATE *state)
+{
+   DWORD dwThreadId = 0;
+   *state = State_Running;
+   return CreateThread(NULL, 0, TestBed, capBox, 0, &dwThreadId) ? S_OK : E_FAIL;
+}
+
+HRESULT Capture_Pause(CaptureBox *capBox, FILTER_STATE *state)
+{
+   FIXME("%p -> (%p) stub\n", capBox, state);
+   return S_OK;
+}
+
+HRESULT Capture_Stop(CaptureBox *capBox, FILTER_STATE *state)
+{
+   FIXME("%p -> (%p) stub\n", capBox, state);
+   return S_OK;
+}
+
diff -Nru wine-old/dlls/quartz/capturegraph.c wine-new/dlls/quartz/capturegraph.c
--- wine-old/dlls/quartz/capturegraph.c	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/quartz/capturegraph.c	2005-04-15 21:23:47.000000000 +0200
@@ -0,0 +1,209 @@
+/* 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 "quartz_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(quartz);
+
+static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
+
+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, qzdebugstr_guid(riid), ppv);
+   *ppv = NULL;
+   if (IsEqualIID(riid, &IID_IUnknown))
+      *ppv = (LPVOID)This;
+   else if (IsEqualIID(riid, &IID_ICaptureGraphBuilder))
+   {
+      *ppv = (LPVOID)This;
+      TRACE("Asking for myself?\n");
+   }
+
+   if (*ppv)
+   {
+       IUnknown_AddRef((IUnknown *)(*ppv));
+       return S_OK;
+   }
+
+   FIXME("No interface for %s!\n", qzdebugstr_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) {
+      FIXME("Release IGraphFilter or w/e\n");
+      DeleteCriticalSection(&This->csFilter);
+      This->lpVtbl = NULL;
+      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\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;
+   TRACE("%p: %s .. %p .. %s .. %p - unwanted stub workaround!\n", iface, qzdebugstr_guid(pCategory), pf, qzdebugstr_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.
+    */
+}
+
+/* [call_as(FindInterface)] HRESULT RemoteFindInterface(
+        [in, unique] const GUID *pCategory,
+        [in] IBaseFilter *pf,
+        [in] REFIID riid,
+        [out] IUnknown **ppint);
+   ^- What is this? */
+
+static HRESULT WINAPI CaptureGraphBuilder_RenderStream(ICaptureGraphBuilder * iface, const GUID *pCategory, IUnknown *pSource, IBaseFilter *pfCompressor, IBaseFilter *pfRenderer)
+{
+   FIXME("%p: .. Stub? !!! -- SHOULD NORMALLY WORK!!..\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/quartz/capture.h wine-new/dlls/quartz/capture.h
--- wine-old/dlls/quartz/capture.h	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/quartz/capture.h	2005-04-15 21:23:47.000000000 +0200
@@ -0,0 +1,37 @@
+/* DirectShow private capture header (QUARTZ.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
+ */
+
+typedef struct CaptureBox {
+/* Dunno what to put in here? */
+  UINT width, height, bitDepth, fps;
+  IPin *pOut;
+} CaptureBox;
+
+HRESULT Capture_Query(USHORT card);
+HRESULT Capture_Initialise(CaptureBox * capBox, IPin *pOut, USHORT card);
+HRESULT Capture_GetMediaType(CaptureBox * capBox, AM_MEDIA_TYPE ** mT);
+HRESULT Capture_SetMediaType(CaptureBox * capBox, AM_MEDIA_TYPE * mT);
+HRESULT Capture_Run(CaptureBox * capBox, FILTER_STATE *state);
+HRESULT Capture_Stop(CaptureBox * capBox, FILTER_STATE *state);
+HRESULT Capture_Pause(CaptureBox * capBox, FILTER_STATE *state);
+HRESULT Capture_Destroy(CaptureBox * capBox);
+
diff -Nru wine-old/dlls/quartz/enummedia.c wine-new/dlls/quartz/enummedia.c
--- wine-old/dlls/quartz/enummedia.c	2005-01-06 20:36:47.000000000 +0100
+++ wine-new/dlls/quartz/enummedia.c	2005-04-15 21:23:47.000000000 +0200
@@ -20,6 +20,17 @@
 
 #include "quartz_private.h"
 
+#include "uuids.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+#include "fourcc.h"
+#include "windef.h"
+#include "winbase.h"
+#include "dshow.h"
+#include "strmif.h"
+#include "ddraw.h"
+
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
@@ -61,7 +72,37 @@
 {
     if (!pmt)
         return;
-    TRACE("\t%s\n\t%s\n\t...\n\t%s\n", qzdebugstr_guid(&pmt->majortype), qzdebugstr_guid(&pmt->subtype), qzdebugstr_guid(&pmt->formattype));
+   TRACE("(): Printing out full format\n"
+         "\tMajor.Minor: %s.%s\n"
+         "\tFixedSize [%d] - Temporal [%d]\n"
+         "\tSample size [%lu] - Format type: %s\n"
+         "\tcb Format: %lu - Pointer: %p\n",
+         qzdebugstr_guid(&pmt->majortype), qzdebugstr_guid(&pmt->subtype),
+         pmt->bFixedSizeSamples, pmt->bTemporalCompression,
+         pmt->lSampleSize, qzdebugstr_guid(&pmt->formattype),
+         pmt->cbFormat, pmt->pbFormat);
+   if (!strcmp(qzdebugstr_guid(&pmt->formattype), qzdebugstr_guid(&FORMAT_VideoInfo))) {
+   BITMAPINFOHEADER *bmi;
+   VIDEOINFOHEADER *pvi;
+   pvi = (void *)pmt->pbFormat;
+
+   TRACE("(): Printing out whole video info header\n"
+         "\tSource rectangle: (%lu,%lu,%lu,%lu)\n"
+         "\tTarget rectangle: (%lu,%lu,%lu,%lu)\n"
+         "\tBitrate: %lu, Error rate: %lu\n"
+         "\tTime per frame: %lu\n",
+         pvi->rcSource.left, pvi->rcSource.right, pvi->rcSource.top, pvi->rcSource.bottom,
+         pvi->rcTarget.left, pvi->rcTarget.right, pvi->rcTarget.top, pvi->rcTarget.bottom,
+         pvi->dwBitRate, pvi->dwBitErrorRate,
+         (ulong) pvi->AvgTimePerFrame);
+   bmi = &pvi->bmiHeader;
+   TRACE("(): Printing out bmi header\n"
+         "\tSize, in pixels: %lu\n"
+         "\tFormat: %ldx%ld\n"
+         "\tBit count: %d\n"
+         "\tSize image: %lu\n",
+         bmi->biSize, bmi->biWidth, bmi->biHeight, bmi->biBitCount, bmi->biSizeImage);
+   }
 }
 
 typedef struct IEnumMediaTypesImpl
diff -Nru wine-old/dlls/quartz/main.c wine-new/dlls/quartz/main.c
--- wine-old/dlls/quartz/main.c	2005-03-02 13:23:22.000000000 +0100
+++ wine-new/dlls/quartz/main.c	2005-04-15 21:23:47.000000000 +0200
@@ -71,7 +71,9 @@
     { &CLSID_AVIDec, AVIDec_create },
     { &CLSID_SystemClock, &QUARTZ_CreateSystemClock },
     { &CLSID_ACMWrapper, &ACMWrapper_create },
-    { &CLSID_WAVEParser, &WAVEParser_create }
+    { &CLSID_VfwCapture, &VfwCapture_create },
+    { &CLSID_WAVEParser, &WAVEParser_create },
+    { &CLSID_CaptureGraphBuilder, &CaptureGraphBuilder_create }
 };
 
 static HRESULT WINAPI
diff -Nru wine-old/dlls/quartz/Makefile.in wine-new/dlls/quartz/Makefile.in
--- wine-old/dlls/quartz/Makefile.in	2005-02-10 18:13:18.000000000 +0100
+++ wine-new/dlls/quartz/Makefile.in	2005-04-17 19:15:20.000000000 +0200
@@ -10,6 +10,8 @@
 	acmwrapper.c \
 	avidec.c \
 	avisplit.c \
+	capture.c \
+	capturegraph.c \
 	control.c \
 	dsoundrender.c \
 	enumfilters.c \
@@ -27,6 +29,7 @@
 	regsvr.c \
 	systemclock.c \
 	transform.c \
+	v4wsource.c \
 	videorenderer.c \
 	waveparser.c
 
diff -Nru wine-old/dlls/quartz/pin.c wine-new/dlls/quartz/pin.c
--- wine-old/dlls/quartz/pin.c	2005-03-02 11:12:12.000000000 +0100
+++ wine-new/dlls/quartz/pin.c	2005-04-15 21:23:47.000000000 +0200
@@ -66,12 +66,17 @@
     dump_AM_MEDIA_TYPE(pmt);
 
     /* FIXME: call queryacceptproc */
+    wine_dbg_add_option("quartz", 15, 0);
 
     This->pin.pConnectedTo = pReceivePin;
     IPin_AddRef(pReceivePin);
     CopyMediaType(&This->pin.mtCurrent, pmt);
+    wine_dbg_add_option("quartz", 15, 0);
 
     hr = IPin_ReceiveConnection(pReceivePin, iface, pmt);
+    FIXME("(): MSN Crashes if quartz debug channel (TRACE & WARN somewhere before here\n"
+          "\t\tManually enabling full debug on quartz now -- %lx\n", hr);
+    wine_dbg_add_option("quartz", 15, 0);
 
     /* get the IMemInputPin interface we will use to deliver samples to the
      * connected pin */
diff -Nru wine-old/dlls/quartz/quartz_private.h wine-new/dlls/quartz/quartz_private.h
--- wine-old/dlls/quartz/quartz_private.h	2005-02-10 18:13:18.000000000 +0100
+++ wine-new/dlls/quartz/quartz_private.h	2005-04-15 21:23:47.000000000 +0200
@@ -52,6 +52,8 @@
 HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv);
 HRESULT ACMWrapper_create(IUnknown * pUnkOuter, LPVOID * ppv);
 HRESULT WAVEParser_create(IUnknown * pUnkOuter, LPVOID * ppv);
+HRESULT VfwCapture_create(IUnknown * pUnkOuter, LPVOID * ppv);
+HRESULT CaptureGraphBuilder_create(IUnknown * pUnkOuter, LPVOID * ppv);
 
 HRESULT EnumMonikerImpl_Create(IMoniker ** ppMoniker, ULONG nMonikerCount, IEnumMoniker ** ppEnum);
 
diff -Nru wine-old/dlls/quartz/regsvr.c wine-new/dlls/quartz/regsvr.c
--- wine-old/dlls/quartz/regsvr.c	2005-02-10 18:13:18.000000000 +0100
+++ wine-new/dlls/quartz/regsvr.c	2005-04-15 21:23:47.000000000 +0200
@@ -922,6 +922,18 @@
 	"quartz.dll",
 	"Both"
     },
+    {   &CLSID_VfwCapture,
+        "Video for wine capture interface",
+        NULL,
+        "quartz.dll",
+        "Both"
+    },
+    {   &CLSID_CaptureGraphBuilder,
+        "Capture Graph Builder",
+        NULL,
+        "quartz.dll",
+        "Both"
+    },
     { NULL }			/* list terminator */
 };
 
@@ -1112,6 +1124,18 @@
 	    { 0xFFFFFFFF },
 	}
     },
+    {   &CLSID_VfwCapture,
+        &CLSID_VideoInputDeviceCategory,
+        {'V','i','d','e','o',' ','F','o','r',' ','W','i','n','e',' ','(','V','4','W',')', 0},
+        0x800000,
+        {   {   REG_PINFLAG_B_OUTPUT,
+                {   { &MEDIATYPE_Stream, &GUID_NULL },
+                    { NULL }
+                },
+            },
+            { 0xFFFFFFFF },
+        }
+    }, /* This creates a fake device for us with an ugly name */
     { NULL }		/* list terminator */
 };
 
diff -Nru wine-old/dlls/quartz/v4wsource.c wine-new/dlls/quartz/v4wsource.c
--- wine-old/dlls/quartz/v4wsource.c	1970-01-01 01:00:00.000000000 +0100
+++ wine-new/dlls/quartz/v4wsource.c	2005-04-15 22:09:20.000000000 +0200
@@ -0,0 +1,600 @@
+/* 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
+ *
+ * LETS SING IT ALL TOGETHER NOW! ON MY MARK!
+ * COM SUCKS ASS!
+ */
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "quartz_private.h"
+#include "control_private.h"
+#include "pin.h"
+#include "capture.h"
+
+#include "uuids.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+#include "fourcc.h"
+#include "windef.h"
+#include "winbase.h"
+#include "dshow.h"
+#include "strmif.h"
+#include "ddraw.h"
+
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(quartz);
+
+static const IBaseFilterVtbl VfwCapture_Vtbl;
+static const IAMStreamConfigVtbl IAMStreamConfig_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;
+
+   CaptureBox myCap; /* Keep this as first, for FakeAMConfigImpl */
+   ULONG refCount;
+   FILTER_INFO filterInfo;
+   FILTER_STATE state;
+   CRITICAL_SECTION csFilter;
+
+   IPin * pOutputPin;
+} VfwCapture;
+
+typedef struct FakeAMConfigImpl {
+   const struct IAMStreamConfigVtbl * IAMStreamConfig_vtbl;
+   CaptureBox myCap;
+} FakeAMConfigImpl;
+
+/* VfwPin implementation */
+typedef struct VfwPinImpl
+{
+  OutputPin pin;
+
+  CaptureBox *myCap;
+  IKsPropertySetVtbl * KSP_VT;
+  HANDLE hEvent;
+  BOOL bFlushing;
+  DATAREQUEST * pHead; /* head of data request list */
+} VfwPinImpl;
+
+HRESULT VfwCapture_create(IUnknown * pUnkOuter, LPVOID * ppv)
+{
+   VfwCapture *pVfwCapture;
+   HRESULT hr;
+
+   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->refCount = 1;
+   pVfwCapture->filterInfo.achName[0] = '\0';
+   pVfwCapture->filterInfo.pGraph = NULL;
+   InitializeCriticalSection(&pVfwCapture->csFilter);
+   hr = VfwPin_Construct((IBaseFilter *)&pVfwCapture->lpVtbl, &pVfwCapture->csFilter, &pVfwCapture->pOutputPin);
+   if (!SUCCEEDED(hr))
+   {
+      CoTaskMemFree(pVfwCapture);
+      return E_OUTOFMEMORY;
+   } else {
+      ((VfwPinImpl *)pVfwCapture->pOutputPin)->myCap = &pVfwCapture->myCap;
+      hr = Capture_Initialise(&pVfwCapture->myCap, pVfwCapture->pOutputPin, 0);
+      if (FAILED(hr)) {
+         IPin_Release((IPin *)pVfwCapture->pOutputPin);
+         CoTaskMemFree(pVfwCapture);
+         return hr;
+      }
+   }
+   *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", qzdebugstr_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);
+
+   if (*ppv)
+   {
+      TRACE("Returning %s interface\n", qzdebugstr_guid(riid));
+      IUnknown_AddRef((IUnknown *)(*ppv));
+      return S_OK;
+   }
+
+   FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
+   return E_NOINTERFACE;
+}
+
+static ULONG WINAPI VfwCapture_AddRef(IBaseFilter * iface)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+   ULONG refCount = InterlockedIncrement(&This->refCount);
+
+   TRACE("(%p/%p)->() AddRef from %ld\n", This, iface, refCount - 1);
+
+   return refCount;
+}
+
+static ULONG WINAPI VfwCapture_Release(IBaseFilter * iface)
+{
+   VfwCapture *This = (VfwCapture *)iface;
+   ULONG refCount = InterlockedDecrement(&This->refCount);
+   TRACE("(%p/%p)->() Release from %ld\n", This, iface, refCount + 1);
+
+   if (!refCount)
+   {
+      TRACE("(): Destroying everything!\n");
+      if (This->state != State_Stopped)
+         Capture_Stop(&This->myCap, &This->state);
+      Capture_Destroy(&This->myCap);
+      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)\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)
+{
+   FIXME("%p: stub, not worth the effort\n", iface);
+   return S_OK;
+}
+
+static ULONG WINAPI AMStreamConfig_AddRef(IAMStreamConfig * iface)
+{
+   FIXME("%p: stub, not worth the effort\n", iface);
+   return 1;
+}
+
+static ULONG WINAPI AMStreamConfig_Release(IAMStreamConfig * iface)
+{
+   FIXME("%p: stub, not worth the effort\n", iface);
+   return 1;
+}
+
+static HRESULT WINAPI AMStreamConfig_SetFormat(IAMStreamConfig *iface,
+                                              AM_MEDIA_TYPE *pmt) {
+   FakeAMConfigImpl *This = (FakeAMConfigImpl *)iface;
+   BITMAPINFOHEADER *bmi;
+   VIDEOINFOHEADER *pvi;
+   TRACE("(): Printing out full format\n"
+         "\tMajor.Minor: %s.%s\n"
+         "\tFixedSize [%d] - Temporal [%d]\n"
+         "\tSample size [%lu] - Format type: %s\n"
+         "\tcb Format: %lu - Pointer: %p\n",
+         qzdebugstr_guid(&pmt->majortype), qzdebugstr_guid(&pmt->subtype),
+         pmt->bFixedSizeSamples, pmt->bTemporalCompression,
+         pmt->lSampleSize, qzdebugstr_guid(&pmt->formattype),
+         pmt->cbFormat, pmt->pbFormat);
+   // Presume pbFormat is a video
+   pvi = (void *)pmt->pbFormat;
+   TRACE("(): Printing out whole video info header\n"
+         "\tSource rectangle: (%lu,%lu,%lu,%lu)\n"
+         "\tTarget rectangle: (%lu,%lu,%lu,%lu)\n"
+         "\tBitrate: %lu, Error rate: %lu\n"
+         "\tTime per frame: %lu\n",
+         pvi->rcSource.left, pvi->rcSource.right, pvi->rcSource.top, pvi->rcSource.bottom,
+         pvi->rcTarget.left, pvi->rcTarget.right, pvi->rcTarget.top, pvi->rcTarget.bottom,
+         pvi->dwBitRate, pvi->dwBitErrorRate,
+         (ulong) pvi->AvgTimePerFrame);
+   bmi = &pvi->bmiHeader;
+   TRACE("(): Printing out bmi header\n"
+         "\tSize, in pixels: %lu\n"
+         "\tFormat: %ldx%ld\n"
+         "\tBit count: %d\n"
+         "\tSize image: %lu\n",
+         bmi->biSize, bmi->biWidth, bmi->biHeight, bmi->biBitCount, bmi->biSizeImage);
+   return Capture_SetMediaType(&This->myCap, pmt);
+}
+
+static HRESULT WINAPI AMStreamConfig_GetFormat(IAMStreamConfig *iface,
+                                              AM_MEDIA_TYPE **pmt) {
+   FakeAMConfigImpl *This = (FakeAMConfigImpl *)iface;
+   TRACE("%p -> (%p)\n", iface, pmt);
+   return Capture_GetMediaType(&This->myCap, pmt);
+}
+
+static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *iface, int *piCount, int *piSize)
+{
+   TRACE("%p: %p %p\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)
+{
+   TRACE("%p: %d %p %p\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
+};
+
+/* IKsPropertySet interface */
+static HRESULT WINAPI KSP_QueryInterface(IKsPropertySet * iface, REFIID riid, LPVOID * ppv)
+{
+   TRACE("%p: stub, not worth the effort\n", iface);
+   return S_OK;
+}
+
+static ULONG WINAPI KSP_AddRef(IKsPropertySet * iface)
+{
+   TRACE("%p: stub, not worth the effort\n", iface);
+   return 1;
+}
+
+static ULONG WINAPI KSP_Release(IKsPropertySet * iface)
+{
+   TRACE("%p: stub, not worth the effort\n", iface);
+   return 1;
+}
+
+static HRESULT WINAPI KSP_Set(IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData)
+{
+   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, &AMPROPSETID_Pin))
+      return E_PROP_SET_UNSUPPORTED;
+   if (pPropData == NULL && pcbReturned == NULL)
+      return E_POINTER;
+   if (pcbReturned)
+      *pcbReturned = sizeof(GUID);
+   if (pPropData == NULL)
+      return S_OK;
+   if (cbPropData < sizeof(GUID))
+      return E_UNEXPECTED;
+   *(GUID *)pPropData = PIN_CATEGORY_PREVIEW;
+   TRACE("() Returning CaP\n");
+   return S_OK;
+}
+
+static HRESULT WINAPI KSP_QuerySupported(IKsPropertySet * iface, REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport)
+{
+   TRACE("%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 AcceptProcAFR(LPVOID iface, const AM_MEDIA_TYPE *pmt)
+{
+   VfwPinImpl *This = (VfwPinImpl *)iface;
+   FIXME("%p: %p\n", This, pmt);
+   return S_FALSE;
+}
+
+static HRESULT VfwPin_Construct(IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
+{
+   VfwPinImpl * pPinImpl;
+   PIN_INFO piOutput;
+   ALLOCATOR_PROPERTIES ap;
+
+   pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
+   if (!pPinImpl)
+      return E_OUTOFMEMORY;
+
+   piOutput.dir = PINDIR_OUTPUT;
+   piOutput.pFilter = pBaseFilter;
+   strcpyW(piOutput.achName, wszOutputPinName);
+   ap.cBuffers = 8;
+   ap.cbBuffer = 256*1024;
+   ap.cbAlign = 0;
+   ap.cbPrefix = 0;
+
+   if (SUCCEEDED(OutputPin_Init(&piOutput, &ap, pBaseFilter, AcceptProcAFR, pCritSec, &pPinImpl->pin)))
+   {
+      pPinImpl->KSP_VT = &KSP_VTable;
+      pPinImpl->pin.pin.lpVtbl = &VfwPin_Vtbl;
+      pPinImpl->hEvent = CreateEventW(NULL, 0, 0, NULL);
+      pPinImpl->bFlushing = FALSE;
+      pPinImpl->pHead = NULL;
+      *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", qzdebugstr_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", qzdebugstr_guid(riid));
+   return E_NOINTERFACE;
+}
+
+static ULONG WINAPI VfwPin_Release(IPin * iface)
+{
+   VfwPinImpl *This = (VfwPinImpl *)iface;
+   ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
+   TRACE("()\n");
+
+   if (!refCount)
+   {
+      DATAREQUEST * pCurrent;
+      DATAREQUEST * pNext;
+      for (pCurrent = This->pHead; pCurrent; pCurrent = pNext)
+      {
+          pNext = pCurrent->pNext;
+          CoTaskMemFree(pCurrent);
+      }
+      CloseHandle(This->hEvent);
+      CoTaskMemFree(This);
+      return 0;
+   }
+   return refCount;
+}
+
+static HRESULT WINAPI VfwPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
+{
+   ENUMMEDIADETAILS emd;
+   AM_MEDIA_TYPE q[1];
+   HRESULT hr;
+   int x = 0;
+
+   VfwPinImpl *This = (VfwPinImpl *)iface;
+   FIXME("(%p) - stub Why does this work and other things don't?!\n", ppEnum);
+   emd.cMediaTypes = 1;
+   for (; x < 1; x++) {
+      VIDEOINFOHEADER *pvi;
+      CopyMemory(&q[x].majortype, &MEDIATYPE_Video, sizeof (GUID));
+      CopyMemory(&q[x].subtype, &MEDIASUBTYPE_RGB24, sizeof (GUID));
+      q[x].bFixedSizeSamples = TRUE;
+      q[x].bTemporalCompression = FALSE;
+      q[x].lSampleSize = 230400;
+      CopyMemory(&q[x].formattype, &FORMAT_VideoInfo, sizeof (GUID));
+      q[x].cbFormat = sizeof(VIDEOINFOHEADER);
+      q[x].pbFormat = CoTaskMemAlloc(q[x].cbFormat);
+      pvi = (VIDEOINFOHEADER *)q[x].pbFormat;
+      pvi->rcSource.left = 0; pvi->rcSource.top = 0;
+      pvi->rcTarget.left = 0; pvi->rcTarget.top = 0;
+      pvi->rcSource.right = 320; pvi->rcSource.bottom = 240;
+      pvi->rcTarget.right = 320; pvi->rcTarget.bottom = 240;
+      pvi->dwBitRate = 10;
+      pvi->dwBitErrorRate = 0;
+      pvi->AvgTimePerFrame = (LONGLONG)(10000000.0 / 25);
+      pvi->bmiHeader.biSize = 40;
+      pvi->bmiHeader.biWidth = 320;
+      pvi->bmiHeader.biHeight = 240;
+      pvi->bmiHeader.biBitCount = 24;
+      pvi->bmiHeader.biCompression = BI_RGB;
+      pvi->bmiHeader.biSizeImage = 320*240*3;
+      pvi->bmiHeader.biXPelsPerMeter = 320;
+      pvi->bmiHeader.biYPelsPerMeter = 240;
+      pvi->bmiHeader.biClrUsed = 0;
+      pvi->bmiHeader.biPlanes = 1;
+      pvi->bmiHeader.biClrImportant = 0;
+   }
+   emd.pMediaTypes = q;
+   hr = IEnumMediaTypesImpl_Construct(&emd, ppEnum);
+   TRACE("%p -- %lx\n", This, hr);
+   /* CoTaskMemFree(q[0].pbFormat); */
+   return hr;
+}
+
+static const IPinVtbl VfwPin_Vtbl =
+{
+   VfwPin_QueryInterface,
+   IPinImpl_AddRef,
+   VfwPin_Release,
+   OutputPin_Connect,
+   OutputPin_ReceiveConnection,
+   IPinImpl_Disconnect,
+   IPinImpl_ConnectedTo,
+   IPinImpl_ConnectionMediaType,
+   IPinImpl_QueryPinInfo,
+   IPinImpl_QueryDirection,
+   IPinImpl_QueryId,
+   IPinImpl_QueryAccept,
+   VfwPin_EnumMediaTypes,
+   IPinImpl_QueryInternalConnections,
+   OutputPin_EndOfStream, 
+   OutputPin_BeginFlush,
+   OutputPin_EndFlush,
+   OutputPin_NewSegment
+};  
+
diff -Nru wine-old/include/axextend.idl wine-new/include/axextend.idl
--- wine-old/include/axextend.idl	2003-07-01 06:33:35.000000000 +0200
+++ wine-new/include/axextend.idl	2005-04-15 21:23:47.000000000 +0200
@@ -69,6 +69,23 @@
 interface IQualityControl;
 interface ISeekingPassThru;
 
+/*****************************************************************************
+ * IAMStreamConfig interface
+ */
+[
+    object,
+    uuid(c6e13340-30ac-11d0-a18c-00a0c9118956),
+    pointer_default(unique)
+]
+interface IAMStreamConfig : IUnknown
+{
+    HRESULT SetFormat( [in] AM_MEDIA_TYPE *pmt);
+    HRESULT GetFormat( [in] AM_MEDIA_TYPE **pmt);
+    HRESULT GetNumberOfCapabilities( [out] int *piCount, [out] int *piSize);
+    HRESULT GetStreamCaps( [in] int iIndex, [out] AM_MEDIA_TYPE **pmt,
+                          [out] BYTE *pSCC);
+}
+
 typedef struct
 {
     CLSID Clsid;


More information about the wine-devel mailing list