RIght now I'm working on a patch so I can use my webcam under wine without having to switch to unix or use non-working solutions..

Right now there are 2 patches needed to get MSN to connect to the internet: first is to disable SSL, second strcpy's a value at urlmon getuseragent or something

To get this to work, a few modifications to existing files are needed:
First of all, if the catagory exists, let devenum return all from videoinput catagory:
diff -Nru /root/wine-20050211/dlls/devenum/createdevenum.c wine-20050211/dlls/devenum/createdevenum.c
--- /root/wine-20050211/dlls/devenum/createdevenum.c 2005-01-25 11:56:39.000000000 +0100
+++ wine-20050211/dlls/devenum/createdevenum.c 2005-03-15 00:15:47.000000000 +0100
@@ -117,7 +117,8 @@

    if (IsEqualGUID(clsidDeviceClass, &CLSID_AudioRendererCategory) ||
        IsEqualGUID(clsidDeviceClass, &CLSID_AudioInputDeviceCategory) ||
-        IsEqualGUID(clsidDeviceClass, &CLSID_MidiRendererCategory))
+        IsEqualGUID(clsidDeviceClass, &CLSID_MidiRendererCategory) ||
+        IsEqualGUID(clsidDeviceClass, &CLSID_VideoInputDeviceCategory))
    {
        hbasekey = HKEY_CURRENT_USER;
        strcpyW(wszRegKey, wszActiveMovieKey);

and a few other patches to devenum main (Not sure if those are needed)
diff -Nru /root/wine-20050211/dlls/devenum/devenum_main.c wine-20050211/dlls/devenum/devenum_main.c
--- /root/wine-20050211/dlls/devenum/devenum_main.c 2004-12-07 15:37:11.000000000 +0100
+++ wine-20050211/dlls/devenum/devenum_main.c 2005-03-15 00:15:47.000000000 +0100
@@ -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);

I wanted to put all custom code into qcap, but because of the pins that's not possible.
I wrote a basic stub for CaptureGraphBuilder and added it and regsvr calls to qcap.
There s no current implementation of qcap, so therefore I added my gzipped qcap.tgz as an attachment (To keep things simple)

My current implementation of the actual interface was based on filesource.c, so i made some functions and struct defs global in quartz:

diff -Nru /root/wine-20050211/dlls/quartz/filesource.c wine-20050211/dlls/quartz/filesource.c
--- /root/wine-20050211/dlls/quartz/filesource.c 2005-01-06 20:36:47.000000000 +0100
+++ wine-20050211/dlls/quartz/filesource.c 2005-03-15 00:15:47.000000000 +0100
@@ -663,17 +663,6 @@
FileSource_GetCurFile
};

-
-/* the dwUserData passed back to user */
-typedef struct DATAREQUEST
-{
-    IMediaSample * pSample; /* sample passed to us by user */
-    DWORD_PTR dwUserData; /* user data passed to us */
-    OVERLAPPED ovl; /* our overlapped structure */
-
-    struct DATAREQUEST * pNext; /* next data request in list */
-} DATAREQUEST;
-
void queue(DATAREQUEST * pHead, DATAREQUEST * pItem)
{
    DATAREQUEST * pCurrent;

diff -Nru /root/wine-20050211/dlls/quartz/quartz_private.h wine-20050211/dlls/quartz/quartz_private.h
--- /root/wine-20050211/dlls/quartz/quartz_private.h 2005-02-10 18:13:18.000000000 +0100
+++ wine-20050211/dlls/quartz/quartz_private.h 2005-03-15 00:15:47.000000000 +0100
@@ -52,8 +52,8 @@
HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv);
HRESULT ACMWrapper_create(IUnknown * pUnkOuter, LPVOID * ppv);
HRESULT WAVEParser_create(IUnknown * pUnkOuter, LPVOID * ppv);
-
HRESULT EnumMonikerImpl_Create(IMoniker ** ppMoniker, ULONG nMonikerCount, IEnumMoniker ** ppEnum);
+HRESULT VfwCapture_create(IUnknown * pUnkOuter, LPVOID * ppv);

typedef struct tagENUMPINDETAILS
{
@@ -80,4 +80,14 @@
BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards);
void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt);

+typedef struct DATAREQUEST
+{
+    IMediaSample * pSample; /* sample passed to us by user */
+    DWORD_PTR dwUserData; /* user data passed to us */
+    OVERLAPPED ovl; /* our overlapped structure */
+
+    struct DATAREQUEST * pNext; /* next data request in list */
+} DATAREQUEST;
+
+void queue(DATAREQUEST * pHead, DATAREQUEST * pItem);
#endif /* __QUARTZ_PRIVATE_INCLUDED__ */

As you can see here, a VfwCapture class is being created
to use it, we must register it and qcap with regsvr32

diff -Nru /root/wine-20050211/dlls/quartz/regsvr.c wine-20050211/dlls/quartz/regsvr.c
--- /root/wine-20050211/dlls/quartz/regsvr.c 2005-02-10 18:13:18.000000000 +0100
+++ wine-20050211/dlls/quartz/regsvr.c 2005-03-15 00:15:47.000000000 +0100
@@ -922,6 +922,12 @@
"quartz.dll",
"Both"
},
+ { &CLSID_VfwCapture,
+ "Video for wine capture interface",
+ NULL,
+ "quartz.dll",
+ "Both"
+ },
{ NULL } /* list terminator */
};

@@ -1112,6 +1118,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 */
};

Also, main.c needs to be informed of a new class:
diff -Nru /root/wine-20050211/dlls/quartz/main.c wine-20050211/dlls/quartz/main.c
--- /root/wine-20050211/dlls/quartz/main.c 2005-03-14 23:47:05.000000000 +0100
+++ wine-20050211/dlls/quartz/main.c 2005-03-15 00:15:47.000000000 +0100
@@ -71,7 +71,8 @@
{ &CLSID_AVIDec, AVIDec_create },
{ &CLSID_SystemClock, &QUARTZ_CreateSystemClock },
{ &CLSID_ACMWrapper, &ACMWrapper_create },
- { &CLSID_WAVEParser, &WAVEParser_create }
+ { &CLSID_WAVEParser, &WAVEParser_create },
+ { &CLSID_VfwCapture, &VfwCapture_create }
};
static HRESULT WINAPI


And at last, we need the interface of course:
diff -Nru /root/wine-20050211/dlls/quartz/Makefile.in wine-20050211/dlls/quartz/Makefile.in
--- /root/wine-20050211/dlls/quartz/Makefile.in 2005-02-10 18:13:18.000000000 +0100
+++ wine-20050211/dlls/quartz/Makefile.in 2005-03-15 00:15:47.000000000 +0100
@@ -28,7 +28,8 @@
systemclock.c \
transform.c \
videorenderer.c \
- waveparser.c
+ waveparser.c \
+ v4wsource.c

(v4wsource.c added as attachment)

Before you think 'yey i can use a webcam now', I have to warn you, you won't
What did is made from figuring out what MSN did at every step, for this to work and keeping it debuggable I ONLY used builtin dlls

minimum required overrides in wine config:
"quartz"       = "builtin";FUCKING WORK!!!!
"amstream"     = "builtin"
"qcap"         = "builtin";You go girl.....
"ole32"        = "builtin";Not really needed, but makes debugging easier

Currently this is NOT working, and MSN crashes for a reason I do not understand,
Iif you want to help me continue working on webcam support i would greatly appreciate it if you could help me pinpoint the source of the crash..
WINEDEBUG=+quartz,+qcap is recommended.. and for now I'm only
Currently the code mostly exists out of ugly hacks, what I was working on before msn crashed were the video formats (IKSPropertySet and IAMStreamConfig capabilities), if someone can help me figure out why and were it crashes, I could continue on my webcam project :=). You could try to get it to work through 'Extra' 'Configure webcam' (Or something like that, since I'm using Dutch version), and it crashes for a reason unknown to me..

PS: I accidentally deleted my first patch file, you need to add IAMStreamConfig and perhaps some other class into the include/*.idl files, I'll release a patch when I'm at least 1% awake again :/

Attachment: qcap.tgz
Description: application/compressed-tar

/* 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 "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 IAMStreamConfigVtbl IAMStreamConfig_VTable;
static const IPinVtbl VfwPin_Vtbl;

static HRESULT VfwPin_Construct(IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
static const WCHAR wszOutputPinName[] = { 'V','4','W','i','n','e',0 };

typedef struct VfwCapture
{
   const struct IBaseFilterVtbl * lpVtbl;
   const struct IAMStreamConfigVtbl * IAMStreamConfig_vtbl;

   ULONG refCount;
   FILTER_INFO filterInfo;
   FILTER_STATE state;
   CRITICAL_SECTION csFilter;

   IPin * pOutputPin;
   AM_MEDIA_TYPE * pmt;
} VfwCapture;

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;
   }

   pVfwCapture->pmt = NULL;

   *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)
   {
      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)
   {
      if (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");
   This->state = State_Stopped;
   return S_OK;
}

static HRESULT WINAPI VfwCapture_Pause(IBaseFilter * iface)
{
   VfwCapture *This = (VfwCapture *)iface;
   TRACE("()\n");
   This->state = State_Paused;
   return S_OK;
}

static HRESULT WINAPI VfwCapture_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
{
   VfwCapture *This = (VfwCapture *)iface;
   TRACE("(%lx%08lx)\n", (ULONG)(tStart >> 32), (ULONG)tStart);
   This->state = State_Running;
   return S_OK;
}

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)
{
/* VfwCapture *This = (VfwCapture *)iface; */
   TRACE("(%p)\n", pClock);
   return S_OK;
}

static HRESULT WINAPI VfwCapture_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
{
/* VfwCapture *This = (VfwCapture *)iface; */
   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 = This->pOutputPin ? 1 : 0;
   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) {
   ERR("%p: %p stub !!\n", iface, pmt);
   return E_NOTIMPL;
}

static HRESULT WINAPI AMStreamConfig_GetFormat(IAMStreamConfig *iface,
                                              AM_MEDIA_TYPE **pmt) {
   ERR("%p: %p stub !!\n", iface, pmt);
   return E_NOTIMPL;
}

typedef struct _VIDEO_STREAM_CONFIG_CAPS {
   GUID guid;
   ULONG VideoStandard;
   SIZE InputSize;
   SIZE MinCroppingSize;
   SIZE MaxCroppingSize;
   int CropGranularityX;
   int CropGranularityY;
   int CropAlignX;
   int CropAlignY;
   SIZE MinOutputSize;
   SIZE MaxOutputSize;
   int OutputGranularityX;
   int OutputGranularityY;
   int StretchTapsX;
   int StretchTapsY;
   int ShrinkTapsX;
   int ShrinkTapsY;
   LONGLONG MinFrameInterval;
   LONGLONG MaxFrameInterval;
   LONG MinBitsPerSecond;
   LONG MaxBitsPerSecond;
} VIDEO_STREAM_CONFIG_CAPS;

static HRESULT WINAPI AMStreamConfig_GetNumberOfCapabilities(IAMStreamConfig *iface, int *piCount, int *piSize)
{
   TRACE("%p: %p %p - stub! Should be harmless\n", iface, piCount, piSize);
   *piCount = 1;
   *piSize = sizeof(VIDEO_STREAM_CONFIG_CAPS);
   return S_OK; /* Not implemented for this interface, but who cares =) */
}

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);

   VIDEOINFOHEADER *pvi;
   VIDEO_STREAM_CONFIG_CAPS *vsc;

   pmt[0] = CoTaskMemAlloc(sizeof (AM_MEDIA_TYPE));
   memcpy (&pmt[0]->formattype, &FORMAT_VideoInfo, sizeof (GUID));
   memcpy (&pmt[0]->majortype, &MEDIATYPE_Video, sizeof (GUID));
   memcpy (&pmt[0]->subtype, &MEDIASUBTYPE_RGB24, sizeof (GUID));
   pmt[0]->bTemporalCompression = 0;
   pmt[0]->bFixedSizeSamples = 1;
   pmt[0]->lSampleSize = 1;

   // FIXME: The stuff below is just there so it contains something

   pmt[0]->cbFormat = sizeof(VIDEOINFOHEADER);
   pmt[0]->pbFormat = CoTaskMemAlloc(pmt[0]->cbFormat);
   ZeroMemory(pmt[0]->pbFormat, pmt[0]->cbFormat);
   pvi = (VIDEOINFOHEADER *)pmt[0]->pbFormat;
   pvi->rcSource.right = 640; pvi->rcSource.bottom = 480;
   pvi->rcTarget.right = 640; pvi->rcTarget.bottom = 480;
   pvi->dwBitRate = 10;
   pvi->dwBitErrorRate = 0;
   pvi->AvgTimePerFrame = (LONGLONG)(10000000.0 / 25); // 25 is hardcoded

   // FIXME: The stuff below is just there so it contains something

   pvi->bmiHeader.biWidth = 640;
   pvi->bmiHeader.biHeight = 480;
   pvi->bmiHeader.biBitCount = 24;
   pvi->bmiHeader.biCompression = BI_RGB;
   pvi->bmiHeader.biSizeImage = 0;
   pvi->bmiHeader.biXPelsPerMeter = 640;
   pvi->bmiHeader.biYPelsPerMeter = 480;
   pvi->bmiHeader.biClrUsed = 0;
   pvi->bmiHeader.biClrImportant = 0;

   // FIXME: Blahblahblah

   vsc = (VIDEO_STREAM_CONFIG_CAPS *)pSCC;
   memcpy (&vsc->guid, &FORMAT_VideoInfo, sizeof (GUID));
   vsc->VideoStandard = 0;
   vsc->InputSize.cx = 640; vsc->InputSize.cy = 480;
   vsc->MinCroppingSize.cx = 320; vsc->MinCroppingSize.cy = 240;
   vsc->MaxCroppingSize.cx = 640; vsc->MaxCroppingSize.cy = 480;
   vsc->CropGranularityX = 10;
   vsc->CropGranularityY = 10;
   vsc->CropAlignX = 0;
   vsc->CropAlignY = 0;
   vsc->MinOutputSize.cx = 320; vsc->MinOutputSize.cy = 240;
   vsc->MaxOutputSize.cx = 640; vsc->MaxOutputSize.cy = 480;
   vsc->OutputGranularityX = 10;
   vsc->OutputGranularityY = 10;
   vsc->StretchTapsX = 1;
   vsc->StretchTapsY = 1;
   vsc->ShrinkTapsX = 1;
   vsc->ShrinkTapsY = 1;
   vsc->MinFrameInterval = (LONGLONG)(10000000.0 / 25);
   vsc->MaxFrameInterval = (LONGLONG)(10000000.0 / 25);
   vsc->MinBitsPerSecond = 24;
   vsc->MaxBitsPerSecond = 24;

   return S_OK; /* Not implemented for this interface */
}

static 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 (dwPropID != AMPROPERTY_PIN_CATEGORY)
      return E_PROP_ID_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
};

/* VfwPin implementation */
typedef struct VfwPinImpl
{
   OutputPin pin;

   IKsPropertySetVtbl * KSP_VT;
   HANDLE hEvent;
   BOOL bFlushing;
   DATAREQUEST * pHead; /* head of data request list */
   CRITICAL_SECTION csList; /* critical section to protect operations on list */
} VfwPinImpl;

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_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
{
   OutputPin *This = (OutputPin *)iface;
   HRESULT hr;

   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);
   TRACE(" -- %lx\n", hr);

   if (FAILED(hr))
   {
      ERR("Failed!");
      IPin_Release(This->pin.pConnectedTo);
      This->pin.pConnectedTo = NULL;
   }

   FIXME(" -- %lx\n", hr);
   return hr;
}

static HRESULT VfwPin_Construct(IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
{
   VfwPinImpl * pPinImpl;
   PIN_INFO piOutput;
   *ppPin = NULL;
   pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
   if (!pPinImpl)
      return E_OUTOFMEMORY;

   piOutput.dir = PINDIR_OUTPUT;
   piOutput.pFilter = pBaseFilter;
   strcpyW(piOutput.achName, wszOutputPinName);

   if (SUCCEEDED(OutputPin_Init(&piOutput, NULL, pBaseFilter, AcceptProcAFR, pCritSec, &pPinImpl->pin)))
   {
      ERR("Success\n");
      pPinImpl->KSP_VT = &KSP_VTable;
      pPinImpl->pin.pin.lpVtbl = &VfwPin_Vtbl;
      pPinImpl->hEvent = CreateEventW(NULL, 0, 0, NULL);
      pPinImpl->bFlushing = FALSE;
      pPinImpl->pHead = NULL;
      pPinImpl->pin.pConnectSpecific = VfwPin_ConnectSpecific;
      InitializeCriticalSection(&pPinImpl->csList);
      *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];
   int x = 0;

   VfwPinImpl *This = (VfwPinImpl *)iface;
   FIXME("(%p) - stub!\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 = 0;
      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.right = 640; pvi->rcSource.bottom = 480;
      pvi->rcTarget.right = 640; pvi->rcTarget.bottom = 480;
      pvi->dwBitRate = 10;
      pvi->dwBitErrorRate = 0;
      pvi->AvgTimePerFrame = (LONGLONG)(10000000.0 / 25);
      pvi->bmiHeader.biWidth = 640;
      pvi->bmiHeader.biHeight = 480;
      pvi->bmiHeader.biBitCount = 24;
      pvi->bmiHeader.biCompression = BI_RGB;
      pvi->bmiHeader.biSizeImage = 0;
      pvi->bmiHeader.biXPelsPerMeter = 640;
      pvi->bmiHeader.biYPelsPerMeter = 480;
      pvi->bmiHeader.biClrUsed = 0;
      pvi->bmiHeader.biClrImportant = 0;
   }
   emd.pMediaTypes = q;
   return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
}

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
};  

Reply via email to