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 :/
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, &ROPSETID_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
};
