From f096fa3a0ea6d535616c790d8d3c6ac8f7106b9d Mon Sep 17 00:00:00 2001 From: Christian Costa Date: Tue, 24 Aug 2004 02:28:35 +0000 Subject: [PATCH] Added Video Renderer (based on Direct Draw). Added Direct Sound Audio Renderer. Added AVI Decompressor (VFW decompressors wrapper). --- dlls/quartz/Makefile.in | 7 +- dlls/quartz/avidec.c | 704 +++++++++++++++ dlls/quartz/dsoundrender.c | 768 +++++++++++++++++ dlls/quartz/main.c | 4 +- dlls/quartz/quartz_private.h | 3 + dlls/quartz/regsvr.c | 36 + dlls/quartz/videorenderer.c | 1558 ++++++++++++++++++++++++++++++++++ 7 files changed, 3077 insertions(+), 3 deletions(-) create mode 100644 dlls/quartz/avidec.c create mode 100644 dlls/quartz/dsoundrender.c create mode 100644 dlls/quartz/videorenderer.c diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in index cab4bfa4f24..8829d408d8e 100644 --- a/dlls/quartz/Makefile.in +++ b/dlls/quartz/Makefile.in @@ -3,12 +3,14 @@ TOPOBJDIR = ../.. SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = quartz.dll -IMPORTS = ole32 oleaut32 advapi32 kernel32 user32 +IMPORTS = dsound ddraw msvfw32 ole32 oleaut32 user32 advapi32 kernel32 EXTRALIBS = -lstrmiids -luuid $(LIBUNICODE) C_SRCS = \ + avidec.c \ avisplit.c \ control.c \ + dsoundrender.c \ enumfilters.c \ enummedia.c \ enummoniker.c \ @@ -21,7 +23,8 @@ C_SRCS = \ memallocator.c \ pin.c \ regsvr.c \ - systemclock.c + systemclock.c \ + videorenderer.c RC_SRCS = version.rc diff --git a/dlls/quartz/avidec.c b/dlls/quartz/avidec.c new file mode 100644 index 00000000000..3785c34f617 --- /dev/null +++ b/dlls/quartz/avidec.c @@ -0,0 +1,704 @@ +/* + * AVI Decompressor (VFW decompressors wrapper) + * + * Copyright 2004 Christian Costa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include "quartz_private.h" +#include "control_private.h" +#include "pin.h" + +#include "uuids.h" +#include "aviriff.h" +#include "mmreg.h" +#include "vfwmsgs.h" +#include "amvideo.h" +#include "windef.h" +#include "winbase.h" +#include "dshow.h" +#include "strmif.h" +#include "vfwmsgs.h" +#include "evcode.h" +#include "vfw.h" +/* #include "fourcc.h" */ +/* #include "avcodec.h" */ + +#include + +#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 WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0}; + +static const IBaseFilterVtbl AVIDec_Vtbl; +static const IPinVtbl AVIDec_InputPin_Vtbl; +static const IMemInputPinVtbl MemInputPin_Vtbl; +static const IPinVtbl AVIDec_OutputPin_Vtbl; + +typedef struct AVIDecImpl +{ + const IBaseFilterVtbl * lpVtbl; + + ULONG refCount; + CRITICAL_SECTION csFilter; + FILTER_STATE state; + REFERENCE_TIME rtStreamStart; + IReferenceClock * pClock; + FILTER_INFO filterInfo; + + IPin ** ppPins; + + HIC hvid; + int init; +} AVIDecImpl; + +static DWORD AVIDec_SendSampleData(AVIDecImpl* This, LPBYTE data, DWORD size) +{ + VIDEOINFOHEADER* format; + AM_MEDIA_TYPE amt; + BITMAPINFOHEADER bi; + HRESULT hr; + DWORD res; + IMediaSample* pSample = NULL; + DWORD cbDstStream; + LPBYTE pbDstStream; + + hr = IPin_ConnectionMediaType(This->ppPins[0], &amt); + if (FAILED(hr)) { + ERR("Unable to retreive media type\n"); + goto error; + } + format = (VIDEOINFOHEADER*)amt.pbFormat; + + /* Fill a bitmap header for output */ + bi.biSize = sizeof(bi); + bi.biWidth = format->bmiHeader.biWidth; + bi.biHeight = format->bmiHeader.biHeight; + bi.biPlanes = 1; + bi.biBitCount = format->bmiHeader.biBitCount; + bi.biCompression = 0; + bi.biSizeImage = bi.biWidth * bi.biHeight * bi.biBitCount / 8; + + hr = OutputPin_GetDeliveryBuffer((OutputPin*)This->ppPins[1], &pSample, NULL, NULL, 0); + if (FAILED(hr)) { + ERR("Unable to get delivery buffer (%lx)\n", hr); + goto error; + } + + hr = IMediaSample_SetActualDataLength(pSample, 0); + assert(hr == S_OK); + + hr = IMediaSample_GetPointer(pSample, &pbDstStream); + if (FAILED(hr)) { + ERR("Unable to get pointer to buffer (%lx)\n", hr); + goto error; + } + cbDstStream = IMediaSample_GetSize(pSample); + if (cbDstStream < bi.biSizeImage) { + ERR("Sample size is too small %ld < %ld\n", cbDstStream, bi.biSizeImage); + hr = E_FAIL; + goto error; + } + + res = ICDecompress(This->hvid, 0, &format->bmiHeader, data, &bi, pbDstStream); + if (res != ICERR_OK) + ERR("Error occured during the decompression (%lx)\n", res); + + hr = OutputPin_SendSample((OutputPin*)This->ppPins[1], pSample); + if (hr != S_OK && hr != VFW_E_NOT_CONNECTED) { + ERR("Error sending sample (%lx)\n", hr); + goto error; + } + + return S_OK; + +error: + /* If we have a sample that has not been delivered, release it */ + if (pSample) + IMediaSample_Release(pSample); + + return hr; +} + +static HRESULT AVIDec_Sample(LPVOID iface, IMediaSample * pSample) +{ + ICOM_THIS(AVIDecImpl, iface); + LPBYTE pbSrcStream = NULL; + long cbSrcStream = 0; + REFERENCE_TIME tStart, tStop; + HRESULT hr; + + TRACE("%p %p\n", iface, pSample); + + hr = IMediaSample_GetPointer(pSample, &pbSrcStream); + if (FAILED(hr)) + { + ERR("Cannot get pointer to sample data (%lx)\n", hr); + return hr; + } + + hr = IMediaSample_GetTime(pSample, &tStart, &tStop); + if (FAILED(hr)) + ERR("Cannot get sample time (%lx)\n", hr); + + cbSrcStream = IMediaSample_GetActualDataLength(pSample); + + TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream, cbSrcStream); + +#if 0 /* For debugging purpose */ + { + int i; + for(i = 0; i < cbSrcStream; i++) + { + if ((i!=0) && !(i%16)) + DPRINTF("\n"); + DPRINTF("%02x ", pbSrcStream[i]); + } + DPRINTF("\n"); + } +#endif + + AVIDec_SendSampleData(This, pbSrcStream, cbSrcStream); + + /* We have finished with the incoming sample, we must release it now */ + IMediaSample_Release(pSample); + + return S_OK; +} + +static HRESULT AVIDec_Input_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt) +{ + AVIDecImpl* pAVIDec = (AVIDecImpl*)iface; + TRACE("%p\n", iface); + dump_AM_MEDIA_TYPE(pmt); + + if ((IsEqualIID(&pmt->majortype, &MEDIATYPE_Video)) && + (!memcmp(((char*)&pmt->subtype)+4, ((char*)&MEDIATYPE_Video)+4, sizeof(GUID)-4)) && /* Check root (GUID w/o FOURCC) */ + (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo))) + { + HIC drv; + VIDEOINFOHEADER* format = (VIDEOINFOHEADER*)pmt->pbFormat; + drv = ICLocate(pmt->majortype.Data1, pmt->subtype.Data1, &format->bmiHeader, NULL, ICMODE_DECOMPRESS); + if (drv) + { + AM_MEDIA_TYPE* outpmt = &((OutputPin*)pAVIDec->ppPins[1])->pin.mtCurrent; + const CLSID* outsubtype; + switch(format->bmiHeader.biBitCount) + { + case 32: outsubtype = &MEDIATYPE_Video; break; + case 24: outsubtype = &MEDIASUBTYPE_RGB24; break; + case 16: outsubtype = &MEDIASUBTYPE_RGB565; break; + case 8: outsubtype = &MEDIASUBTYPE_RGB8; break; + default: + FIXME("Depth %d not supported\n", format->bmiHeader.biBitCount); + ICClose(drv); + return S_FALSE; + } + CopyMediaType( outpmt, pmt); + outpmt->subtype = *outsubtype; + pAVIDec->hvid = drv; + pAVIDec->init = 1; + TRACE("Connection accepted\n"); + return S_OK; + } + TRACE("Unable to find a suitable VFW decompressor\n"); + } + + TRACE("Connection refused\n"); + return S_FALSE; +} + + +static HRESULT AVIDec_Output_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt) +{ + AVIDecImpl* pAVIDec = (AVIDecImpl*)iface; + AM_MEDIA_TYPE* outpmt = &((OutputPin*)pAVIDec->ppPins[1])->pin.mtCurrent; + TRACE("%p\n", iface); + + if (IsEqualIID(&pmt->majortype, &outpmt->majortype) && IsEqualIID(&pmt->subtype, &outpmt->subtype)) + return S_OK; + return S_FALSE; +} + +static HRESULT AVIDec_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin) +{ + InputPin * pPinImpl; + + *ppPin = NULL; + + if (pPinInfo->dir != PINDIR_INPUT) + { + ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir); + return E_INVALIDARG; + } + + pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl)); + + if (!pPinImpl) + return E_OUTOFMEMORY; + TRACE("QA : %p %p\n", pQueryAccept, AVIDec_Input_QueryAccept); + if (SUCCEEDED(InputPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl))) + { + pPinImpl->pin.lpVtbl = &AVIDec_InputPin_Vtbl; + pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl; + + *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl); + return S_OK; + } + return E_FAIL; +} + +HRESULT AVIDec_OutputPin_Construct(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin) +{ + OutputPin * pPinImpl; + + *ppPin = NULL; + + if (pPinInfo->dir != PINDIR_OUTPUT) + { + ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir); + return E_INVALIDARG; + } + + pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl)); + + if (!pPinImpl) + return E_OUTOFMEMORY; + + if (SUCCEEDED(OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pCritSec, pPinImpl))) + { + pPinImpl->pin.lpVtbl = &AVIDec_OutputPin_Vtbl; + + *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl); + return S_OK; + } + return E_FAIL; +} + +HRESULT AVIDec_create(IUnknown * pUnkOuter, LPVOID * ppv) +{ + HRESULT hr; + PIN_INFO piInput; + PIN_INFO piOutput; + AVIDecImpl * pAVIDec; + + TRACE("(%p, %p)\n", pUnkOuter, ppv); + + *ppv = NULL; + + if (pUnkOuter) + return CLASS_E_NOAGGREGATION; + + pAVIDec = CoTaskMemAlloc(sizeof(AVIDecImpl)); + + pAVIDec->lpVtbl = &AVIDec_Vtbl; + + pAVIDec->refCount = 1; + InitializeCriticalSection(&pAVIDec->csFilter); + pAVIDec->state = State_Stopped; + pAVIDec->pClock = NULL; + pAVIDec->init = 0; + ZeroMemory(&pAVIDec->filterInfo, sizeof(FILTER_INFO)); + + pAVIDec->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *)); + + /* construct input pin */ + piInput.dir = PINDIR_INPUT; + piInput.pFilter = (IBaseFilter *)pAVIDec; + strncpyW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0])); + piOutput.dir = PINDIR_OUTPUT; + piOutput.pFilter = (IBaseFilter *)pAVIDec; + strncpyW(piOutput.achName, wcsOutputPinName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0])); + + hr = AVIDec_InputPin_Construct(&piInput, AVIDec_Sample, (LPVOID)pAVIDec, AVIDec_Input_QueryAccept, &pAVIDec->csFilter, &pAVIDec->ppPins[0]); + + if (SUCCEEDED(hr)) + { + hr = AVIDec_OutputPin_Construct(&piOutput, NULL, NULL, AVIDec_Output_QueryAccept, &pAVIDec->csFilter, &pAVIDec->ppPins[1]); + + if (FAILED(hr)) + ERR("Cannot create output pin (%lx)\n", hr); + + *ppv = (LPVOID)pAVIDec; + } + else + { + CoTaskMemFree(pAVIDec->ppPins); + DeleteCriticalSection(&pAVIDec->csFilter); + CoTaskMemFree(pAVIDec); + } + + return hr; +} + +static HRESULT WINAPI AVIDec_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) +{ + ICOM_THIS(AVIDecImpl, 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_IPersist)) + *ppv = (LPVOID)This; + else if (IsEqualIID(riid, &IID_IMediaFilter)) + *ppv = (LPVOID)This; + else if (IsEqualIID(riid, &IID_IBaseFilter)) + *ppv = (LPVOID)This; + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); + + return E_NOINTERFACE; +} + +static ULONG WINAPI AVIDec_AddRef(IBaseFilter * iface) +{ + ICOM_THIS(AVIDecImpl, iface); + TRACE("(%p/%p)->()\n", This, iface); + return InterlockedIncrement(&This->refCount); +} + +static ULONG WINAPI AVIDec_Release(IBaseFilter * iface) +{ + ICOM_THIS(AVIDecImpl, iface); + TRACE("(%p/%p)->()\n", This, iface); + if (!InterlockedDecrement(&This->refCount)) + { + ULONG i; + + DeleteCriticalSection(&This->csFilter); + IReferenceClock_Release(This->pClock); + + for (i = 0; i < 2; i++) + IPin_Release(This->ppPins[i]); + + HeapFree(GetProcessHeap(), 0, This->ppPins); + This->lpVtbl = NULL; + + if (This->hvid) + ICClose(This->hvid); + + TRACE("Destroying AVI Decompressor\n"); + CoTaskMemFree(This); + + return 0; + } + else + return This->refCount; +} + +/** IPersist methods **/ + +static HRESULT WINAPI AVIDec_GetClassID(IBaseFilter * iface, CLSID * pClsid) +{ + ICOM_THIS(AVIDecImpl, iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, pClsid); + + *pClsid = CLSID_AVIDec; + + return S_OK; +} + +/** IMediaFilter methods **/ + +static HRESULT WINAPI AVIDec_Stop(IBaseFilter * iface) +{ + ICOM_THIS(AVIDecImpl, iface); + + TRACE("(%p/%p)\n", This, iface); + + EnterCriticalSection(&This->csFilter); + { + This->state = State_Stopped; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI AVIDec_Pause(IBaseFilter * iface) +{ + ICOM_THIS(AVIDecImpl, iface); + + TRACE("(%p/%p)->()\n", This, iface); + + EnterCriticalSection(&This->csFilter); + { + This->state = State_Paused; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI AVIDec_Run(IBaseFilter * iface, REFERENCE_TIME tStart) +{ + HRESULT hr = S_OK; + ICOM_THIS(AVIDecImpl, iface); + + TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart)); + + EnterCriticalSection(&This->csFilter); + { + This->rtStreamStart = tStart; + + This->state = State_Running; + } + LeaveCriticalSection(&This->csFilter); + + return hr; +} + +static HRESULT WINAPI AVIDec_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) +{ + ICOM_THIS(AVIDecImpl, iface); + + TRACE("(%p/%p)->(%ld, %p)\n", This, iface, dwMilliSecsTimeout, pState); + + EnterCriticalSection(&This->csFilter); + { + *pState = This->state; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI AVIDec_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) +{ + ICOM_THIS(AVIDecImpl, iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, pClock); + + EnterCriticalSection(&This->csFilter); + { + if (This->pClock) + IReferenceClock_Release(This->pClock); + This->pClock = pClock; + if (This->pClock) + IReferenceClock_AddRef(This->pClock); + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI AVIDec_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock) +{ + ICOM_THIS(AVIDecImpl, iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, ppClock); + + EnterCriticalSection(&This->csFilter); + { + *ppClock = This->pClock; + IReferenceClock_AddRef(This->pClock); + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +/** IBaseFilter implementation **/ + +static HRESULT WINAPI AVIDec_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum) +{ + ENUMPINDETAILS epd; + ICOM_THIS(AVIDecImpl, iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); + + epd.cPins = 2; /* input and output pins */ + epd.ppPins = This->ppPins; + return IEnumPinsImpl_Construct(&epd, ppEnum); +} + +static HRESULT WINAPI AVIDec_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin) +{ + ICOM_THIS(AVIDecImpl, iface); + + TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin); + + FIXME("AVISplitter::FindPin(...)\n"); + + /* FIXME: critical section */ + + return E_NOTIMPL; +} + +static HRESULT WINAPI AVIDec_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo) +{ + ICOM_THIS(AVIDecImpl, iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, 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 AVIDec_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName) +{ + HRESULT hr = S_OK; + ICOM_THIS(AVIDecImpl, iface); + + TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName)); + + EnterCriticalSection(&This->csFilter); + { + if (pName) + strcpyW(This->filterInfo.achName, pName); + else + *This->filterInfo.achName = '\0'; + This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */ + } + LeaveCriticalSection(&This->csFilter); + + return hr; +} + +static HRESULT WINAPI AVIDec_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo) +{ + ICOM_THIS(AVIDecImpl, iface); + TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo); + return E_NOTIMPL; +} + +static const IBaseFilterVtbl AVIDec_Vtbl = +{ + AVIDec_QueryInterface, + AVIDec_AddRef, + AVIDec_Release, + AVIDec_GetClassID, + AVIDec_Stop, + AVIDec_Pause, + AVIDec_Run, + AVIDec_GetState, + AVIDec_SetSyncSource, + AVIDec_GetSyncSource, + AVIDec_EnumPins, + AVIDec_FindPin, + AVIDec_QueryFilterInfo, + AVIDec_JoinFilterGraph, + AVIDec_QueryVendorInfo +}; + +static const IPinVtbl AVIDec_InputPin_Vtbl = +{ + InputPin_QueryInterface, + IPinImpl_AddRef, + InputPin_Release, + InputPin_Connect, + InputPin_ReceiveConnection, + IPinImpl_Disconnect, + IPinImpl_ConnectedTo, + IPinImpl_ConnectionMediaType, + IPinImpl_QueryPinInfo, + IPinImpl_QueryDirection, + IPinImpl_QueryId, + IPinImpl_QueryAccept, + IPinImpl_EnumMediaTypes, + IPinImpl_QueryInternalConnections, + InputPin_EndOfStream, + InputPin_BeginFlush, + InputPin_EndFlush, + InputPin_NewSegment +}; + +HRESULT WINAPI AVIDec_Output_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum) +{ + ICOM_THIS(IPinImpl, iface); + ENUMMEDIADETAILS emd; + + TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); + + emd.cMediaTypes = 1; + emd.pMediaTypes = &This->mtCurrent; + + return IEnumMediaTypesImpl_Construct(&emd, ppEnum); +} + +HRESULT WINAPI AVIDec_Output_Disconnect(IPin * iface) +{ + OutputPin* This = (OutputPin*)iface; + HRESULT hr; + AVIDecImpl* pAVIDec = (AVIDecImpl*)This->pin.pinInfo.pFilter; + + TRACE("(%p/%p)->()\n", This, iface); + + hr = OutputPin_Disconnect(iface); + + if (hr == S_OK) + { + ICClose(pAVIDec->hvid); + pAVIDec->hvid = 0; + } + + return hr; +} + +static const IPinVtbl AVIDec_OutputPin_Vtbl = +{ + OutputPin_QueryInterface, + IPinImpl_AddRef, + OutputPin_Release, + OutputPin_Connect, + OutputPin_ReceiveConnection, + AVIDec_Output_Disconnect, + IPinImpl_ConnectedTo, + IPinImpl_ConnectionMediaType, + IPinImpl_QueryPinInfo, + IPinImpl_QueryDirection, + IPinImpl_QueryId, + IPinImpl_QueryAccept, + AVIDec_Output_EnumMediaTypes, + IPinImpl_QueryInternalConnections, + OutputPin_EndOfStream, + OutputPin_BeginFlush, + OutputPin_EndFlush, + OutputPin_NewSegment +}; + +static const IMemInputPinVtbl MemInputPin_Vtbl = +{ + MemInputPin_QueryInterface, + MemInputPin_AddRef, + MemInputPin_Release, + MemInputPin_GetAllocator, + MemInputPin_NotifyAllocator, + MemInputPin_GetAllocatorRequirements, + MemInputPin_Receive, + MemInputPin_ReceiveMultiple, + MemInputPin_ReceiveCanBlock +}; diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c new file mode 100644 index 00000000000..97043ddf58d --- /dev/null +++ b/dlls/quartz/dsoundrender.c @@ -0,0 +1,768 @@ +/* + * Direct Sound Audio Renderer + * + * Copyright 2004 Christian Costa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include "quartz_private.h" +#include "control_private.h" +#include "pin.h" + +#include "uuids.h" +#include "mmreg.h" +#include "vfwmsgs.h" +#include "fourcc.h" +#include "windef.h" +#include "winbase.h" +#include "dshow.h" +#include "evcode.h" +#include "strmif.h" +#include "dsound.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 IBaseFilterVtbl DSoundRender_Vtbl; +static const IPinVtbl DSoundRender_InputPin_Vtbl; +static const IMemInputPinVtbl MemInputPin_Vtbl; +static const IBasicAudioVtbl IBasicAudio_Vtbl; + +typedef struct DSoundRenderImpl +{ + const IBaseFilterVtbl * lpVtbl; + const IBasicAudioVtbl *IBasicAudio_vtbl; + + ULONG refCount; + CRITICAL_SECTION csFilter; + FILTER_STATE state; + REFERENCE_TIME rtStreamStart; + IReferenceClock * pClock; + FILTER_INFO filterInfo; + IMediaEventSink * pEventSink; + + InputPin * pInputPin; + IPin ** ppPins; + + LPDIRECTSOUND dsound; + LPDIRECTSOUNDBUFFER dsbuffer; + DWORD write_pos; + int init; +} DSoundRenderImpl; + +static HRESULT DSoundRender_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin) +{ + InputPin * pPinImpl; + + *ppPin = NULL; + + if (pPinInfo->dir != PINDIR_INPUT) + { + ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir); + return E_INVALIDARG; + } + + pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl)); + + if (!pPinImpl) + return E_OUTOFMEMORY; + + if (SUCCEEDED(InputPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl))) + { + pPinImpl->pin.lpVtbl = &DSoundRender_InputPin_Vtbl; + pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl; + + *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl); + return S_OK; + } + return E_FAIL; +} + + +#define DSBUFFERSIZE 8192 + +static HRESULT DSoundRender_CreateSoundBuffer(IBaseFilter * iface) +{ + HRESULT hr; + WAVEFORMATEX wav_fmt; + AM_MEDIA_TYPE amt; + WAVEFORMATEX* format; + DSBUFFERDESC buf_desc; + ICOM_THIS(DSoundRenderImpl, iface); + + hr = IPin_ConnectionMediaType(This->ppPins[0], &amt); + if (FAILED(hr)) { + ERR("Unable to retreive media type\n"); + return hr; + } + + TRACE("MajorType %s\n", debugstr_guid(&amt.majortype)); + TRACE("SubType %s\n", debugstr_guid(&amt.subtype)); + TRACE("Format %s\n", debugstr_guid(&amt.formattype)); + TRACE("Size %ld\n", amt.cbFormat); + + dump_AM_MEDIA_TYPE(&amt); + + format = (WAVEFORMATEX*)amt.pbFormat; + TRACE("wFormatTag = %x %x\n", format->wFormatTag, WAVE_FORMAT_PCM); + TRACE("nChannels = %d\n", format->nChannels); + TRACE("nSamplesPerSec = %lu\n", format->nSamplesPerSec); + TRACE("nAvgBytesPerSec = %lu\n", format->nAvgBytesPerSec); + TRACE("nBlockAlign = %d\n", format->nBlockAlign); + TRACE("wBitsPerSample = %d\n", format->wBitsPerSample); + TRACE("cbSize = %d\n", format->cbSize); + + hr = DirectSoundCreate(NULL, &This->dsound, NULL); + if (FAILED(hr)) { + ERR("Cannot create Direct Sound object\n"); + return hr; + } + + wav_fmt = *format; + wav_fmt.cbSize = 0; + + memset(&buf_desc,0,sizeof(DSBUFFERDESC)); + buf_desc.dwSize = sizeof(DSBUFFERDESC); + buf_desc.dwBufferBytes = DSBUFFERSIZE; + buf_desc.lpwfxFormat = &wav_fmt; + hr = IDirectSound_CreateSoundBuffer(This->dsound, &buf_desc, &This->dsbuffer, NULL); + if (FAILED(hr)) { + ERR("Can't create sound buffer !\n"); + return hr; + } + + This->write_pos = 0; + + return hr; +} + +static DWORD DSoundRender_SendSampleData(DSoundRenderImpl* This, LPBYTE data, DWORD size) +{ + HRESULT result; + LPBYTE lpbuf1 = NULL; + LPBYTE lpbuf2 = NULL; + DWORD dwsize1 = 0; + DWORD dwsize2 = 0; + static int init_; + DWORD size2; + DWORD play_pos,buf_free; + + while (1) + { + result=IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, &play_pos, NULL); + if (result != DS_OK) { + ERR("Error GetCurrentPosition: %lx\n", result); + break; + } + if (This->write_pos < play_pos) + buf_free = play_pos-This->write_pos; + else + buf_free = DSBUFFERSIZE - This->write_pos + play_pos; + + size2 = min(buf_free, size); + result = IDirectSoundBuffer_Lock(This->dsbuffer, This->write_pos, size2, &lpbuf1, &dwsize1, &lpbuf2, &dwsize2, 0); + if (result != DS_OK) { + ERR("Unable to lock sound buffer !\n"); + break; + } + TRACE("write_pos=%ld, size=%ld, sz1=%ld, sz2=%ld\n", This->write_pos, size2, dwsize1, dwsize2); + + memcpy(lpbuf1, data, dwsize1); + if (dwsize2) { + memcpy(lpbuf2, data + dwsize1, dwsize2); + } + + result = IDirectSoundBuffer_Unlock(This->dsbuffer, lpbuf1, dwsize1, lpbuf2, dwsize2); + if (result != DS_OK) + ERR("Unable to unlock sound buffer !\n"); + if (!init_) + { + result = IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING); + if (result != DS_OK) { + ERR("Can't start playing !\n"); + } + } + size -= dwsize1 + dwsize2; + data += dwsize1 + dwsize2; + This->write_pos = (This->write_pos + dwsize1 + dwsize2) % DSBUFFERSIZE; + + if (!size) + break; + Sleep(10); + } + return 0; +} + +static HRESULT DSoundRender_Sample(LPVOID iface, IMediaSample * pSample) +{ + ICOM_THIS(DSoundRenderImpl, iface); + LPBYTE pbSrcStream = NULL; + long cbSrcStream = 0; + REFERENCE_TIME tStart, tStop; + HRESULT hr; + + TRACE("%p %p\n", iface, pSample); + + hr = IMediaSample_GetPointer(pSample, &pbSrcStream); + if (FAILED(hr)) + { + ERR("Cannot get pointer to sample data (%lx)\n", hr); + return hr; + } + + hr = IMediaSample_GetTime(pSample, &tStart, &tStop); + if (FAILED(hr)) + ERR("Cannot get sample time (%lx)\n", hr); + + cbSrcStream = IMediaSample_GetActualDataLength(pSample); + + TRACE("Sample data ptr = %p, size = %ld\n", pbSrcStream, cbSrcStream); + +#if 0 /* For debugging purpose */ + { + int i; + for(i = 0; i < cbSrcStream; i++) + { + if ((i!=0) && !(i%16)) + DPRINTF("\n"); + DPRINTF("%02x ", pbSrcStream[i]); + } + DPRINTF("\n"); + } +#endif + + if (!This->init) + { + This->init = 1; + hr = DSoundRender_CreateSoundBuffer(iface); + if (FAILED(hr)) + { + ERR("Unable to create DSound buffer\n"); + } + } + DSoundRender_SendSampleData(This, pbSrcStream, cbSrcStream); + + /* We have finished with the incoming sample, we must release it now */ + IMediaSample_Release(pSample); + + return S_OK; +} + +static HRESULT DSoundRender_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt) +{ + WAVEFORMATEX* format = (WAVEFORMATEX*)pmt->pbFormat; + TRACE("wFormatTag = %x %x\n", format->wFormatTag, WAVE_FORMAT_PCM); + TRACE("nChannels = %d\n", format->nChannels); + TRACE("nSamplesPerSec = %ld\n", format->nAvgBytesPerSec); + TRACE("nAvgBytesPerSec = %ld\n", format->nAvgBytesPerSec); + TRACE("nBlockAlign = %d\n", format->nBlockAlign); + TRACE("wBitsPerSample = %d\n", format->wBitsPerSample); + + if (IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio) && IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_PCM)) + return S_OK; + return S_FALSE; +} + +HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv) +{ + HRESULT hr; + PIN_INFO piInput; + DSoundRenderImpl * pDSoundRender; + + TRACE("(%p, %p)\n", pUnkOuter, ppv); + + *ppv = NULL; + + if (pUnkOuter) + return CLASS_E_NOAGGREGATION; + + pDSoundRender = CoTaskMemAlloc(sizeof(DSoundRenderImpl)); + + pDSoundRender->lpVtbl = &DSoundRender_Vtbl; + pDSoundRender->IBasicAudio_vtbl = &IBasicAudio_Vtbl; + pDSoundRender->refCount = 1; + InitializeCriticalSection(&pDSoundRender->csFilter); + pDSoundRender->state = State_Stopped; + pDSoundRender->pClock = NULL; + pDSoundRender->init = 0; + ZeroMemory(&pDSoundRender->filterInfo, sizeof(FILTER_INFO)); + + pDSoundRender->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *)); + + /* construct input pin */ + piInput.dir = PINDIR_INPUT; + piInput.pFilter = (IBaseFilter *)pDSoundRender; + strncpyW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0])); + hr = DSoundRender_InputPin_Construct(&piInput, DSoundRender_Sample, (LPVOID)pDSoundRender, DSoundRender_QueryAccept, &pDSoundRender->csFilter, (IPin **)&pDSoundRender->pInputPin); + + if (SUCCEEDED(hr)) + { + pDSoundRender->ppPins[0] = (IPin *)pDSoundRender->pInputPin; + *ppv = (LPVOID)pDSoundRender; + } + else + { + CoTaskMemFree(pDSoundRender->ppPins); + DeleteCriticalSection(&pDSoundRender->csFilter); + CoTaskMemFree(pDSoundRender); + } + + return hr; +} + +static HRESULT WINAPI DSoundRender_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) +{ + ICOM_THIS(DSoundRenderImpl, 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_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_IBaseFilter)) + *ppv = (LPVOID)&(This->IBasicAudio_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 DSoundRender_AddRef(IBaseFilter * iface) +{ + ICOM_THIS(DSoundRenderImpl, iface); + TRACE("(%p/%p)->()\n", This, iface); + return InterlockedIncrement(&This->refCount); +} + +static ULONG WINAPI DSoundRender_Release(IBaseFilter * iface) +{ + ICOM_THIS(DSoundRenderImpl, iface); + TRACE("(%p/%p)->()\n", This, iface); + if (!InterlockedDecrement(&This->refCount)) + { + DeleteCriticalSection(&This->csFilter); + if (This->pClock) + IReferenceClock_Release(This->pClock); + + IPin_Release(This->ppPins[0]); + + HeapFree(GetProcessHeap(), 0, This->ppPins); + This->lpVtbl = NULL; + This->IBasicAudio_vtbl = NULL; + + TRACE("Destroying Audio Renderer\n"); + CoTaskMemFree(This); + + return 0; + } + else + return This->refCount; +} + +/** IPersist methods **/ + +static HRESULT WINAPI DSoundRender_GetClassID(IBaseFilter * iface, CLSID * pClsid) +{ + ICOM_THIS(DSoundRenderImpl, iface); + TRACE("(%p/%p)->(%p)\n", This, iface, pClsid); + + *pClsid = CLSID_DSoundRender; + + return S_OK; +} + +/** IMediaFilter methods **/ + +static HRESULT WINAPI DSoundRender_Stop(IBaseFilter * iface) +{ + HRESULT hr = S_OK; + ICOM_THIS(DSoundRenderImpl, iface); + + TRACE("(%p/%p)->()\n", This, iface); + + EnterCriticalSection(&This->csFilter); + { + This->state = State_Stopped; + } + LeaveCriticalSection(&This->csFilter); + + return hr; +} + +static HRESULT WINAPI DSoundRender_Pause(IBaseFilter * iface) +{ + HRESULT hr = S_OK; + ICOM_THIS(DSoundRenderImpl, iface); + + TRACE("(%p/%p)->()\n", This, iface); + + EnterCriticalSection(&This->csFilter); + { + This->state = State_Paused; + } + LeaveCriticalSection(&This->csFilter); + + return hr; +} + +static HRESULT WINAPI DSoundRender_Run(IBaseFilter * iface, REFERENCE_TIME tStart) +{ + HRESULT hr = S_OK; + ICOM_THIS(DSoundRenderImpl, iface); + + TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart)); + + EnterCriticalSection(&This->csFilter); + { + This->rtStreamStart = tStart; + This->state = State_Running; + } + LeaveCriticalSection(&This->csFilter); + + return hr; +} + +static HRESULT WINAPI DSoundRender_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) +{ + ICOM_THIS(DSoundRenderImpl, iface); + + TRACE("(%p/%p)->(%ld, %p)\n", This, iface, dwMilliSecsTimeout, pState); + + EnterCriticalSection(&This->csFilter); + { + *pState = This->state; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI DSoundRender_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) +{ + ICOM_THIS(DSoundRenderImpl, iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, pClock); + + EnterCriticalSection(&This->csFilter); + { + if (This->pClock) + IReferenceClock_Release(This->pClock); + This->pClock = pClock; + if (This->pClock) + IReferenceClock_AddRef(This->pClock); + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI DSoundRender_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock) +{ + ICOM_THIS(DSoundRenderImpl, iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, ppClock); + + EnterCriticalSection(&This->csFilter); + { + *ppClock = This->pClock; + IReferenceClock_AddRef(This->pClock); + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +/** IBaseFilter implementation **/ + +static HRESULT WINAPI DSoundRender_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum) +{ + ENUMPINDETAILS epd; + ICOM_THIS(DSoundRenderImpl, iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); + + epd.cPins = 1; /* input pin */ + epd.ppPins = This->ppPins; + return IEnumPinsImpl_Construct(&epd, ppEnum); +} + +static HRESULT WINAPI DSoundRender_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin) +{ + ICOM_THIS(DSoundRenderImpl, iface); + + TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin); + + FIXME("DSoundRender::FindPin(...)\n"); + + /* FIXME: critical section */ + + return E_NOTIMPL; +} + +static HRESULT WINAPI DSoundRender_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo) +{ + ICOM_THIS(DSoundRenderImpl, iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, 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 DSoundRender_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName) +{ + HRESULT hr; + ICOM_THIS(DSoundRenderImpl, iface); + + TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName)); + + EnterCriticalSection(&This->csFilter); + { + if (pName) + strcpyW(This->filterInfo.achName, pName); + else + *This->filterInfo.achName = '\0'; + This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */ + + hr = IFilterGraph_QueryInterface(pGraph, &IID_IMediaEventSink, (LPVOID*)&This->pEventSink); + } + LeaveCriticalSection(&This->csFilter); + + return hr; +} + +static HRESULT WINAPI DSoundRender_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo) +{ + ICOM_THIS(DSoundRenderImpl, iface); + TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo); + return E_NOTIMPL; +} + +static const IBaseFilterVtbl DSoundRender_Vtbl = +{ + DSoundRender_QueryInterface, + DSoundRender_AddRef, + DSoundRender_Release, + DSoundRender_GetClassID, + DSoundRender_Stop, + DSoundRender_Pause, + DSoundRender_Run, + DSoundRender_GetState, + DSoundRender_SetSyncSource, + DSoundRender_GetSyncSource, + DSoundRender_EnumPins, + DSoundRender_FindPin, + DSoundRender_QueryFilterInfo, + DSoundRender_JoinFilterGraph, + DSoundRender_QueryVendorInfo +}; + +static HRESULT WINAPI DSoundRender_InputPin_EndOfStream(IPin * iface) +{ + /* FIXME: critical section */ + InputPin* This = (InputPin*)iface; + + TRACE("(%p/%p)->()\n", This, iface); + + return IMediaEventSink_Notify(((DSoundRenderImpl*)This->pin.pinInfo.pFilter)->pEventSink, EC_COMPLETE, S_OK, 0); +} + +static const IPinVtbl DSoundRender_InputPin_Vtbl = +{ + InputPin_QueryInterface, + IPinImpl_AddRef, + InputPin_Release, + InputPin_Connect, + InputPin_ReceiveConnection, + IPinImpl_Disconnect, + IPinImpl_ConnectedTo, + IPinImpl_ConnectionMediaType, + IPinImpl_QueryPinInfo, + IPinImpl_QueryDirection, + IPinImpl_QueryId, + IPinImpl_QueryAccept, + IPinImpl_EnumMediaTypes, + IPinImpl_QueryInternalConnections, + DSoundRender_InputPin_EndOfStream, + InputPin_BeginFlush, + InputPin_EndFlush, + InputPin_NewSegment +}; + +static const IMemInputPinVtbl MemInputPin_Vtbl = +{ + MemInputPin_QueryInterface, + MemInputPin_AddRef, + MemInputPin_Release, + MemInputPin_GetAllocator, + MemInputPin_NotifyAllocator, + MemInputPin_GetAllocatorRequirements, + MemInputPin_Receive, + MemInputPin_ReceiveMultiple, + MemInputPin_ReceiveCanBlock +}; + +/*** IUnknown methods ***/ +static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface, + REFIID riid, + LPVOID*ppvObj) { + ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface); + + TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj); + + return DSoundRender_QueryInterface((IBaseFilter*)This, riid, ppvObj); +} + +static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) { + ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface); + + TRACE("(%p/%p)->()\n", This, iface); + + return DSoundRender_AddRef((IBaseFilter*)This); +} + +static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) { + ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface); + + TRACE("(%p/%p)->()\n", This, iface); + + return DSoundRender_Release((IBaseFilter*)This); +} + +/*** IDispatch methods ***/ +static HRESULT WINAPI Basicaudio_GetTypeInfoCount(IBasicAudio *iface, + UINT*pctinfo) { + ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo); + + return S_OK; +} + +static HRESULT WINAPI Basicaudio_GetTypeInfo(IBasicAudio *iface, + UINT iTInfo, + LCID lcid, + ITypeInfo**ppTInfo) { + ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface); + + TRACE("(%p/%p)->(%d, %ld, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo); + + return S_OK; +} + +static HRESULT WINAPI Basicaudio_GetIDsOfNames(IBasicAudio *iface, + REFIID riid, + LPOLESTR*rgszNames, + UINT cNames, + LCID lcid, + DISPID*rgDispId) { + ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface); + + TRACE("(%p/%p)->(%s (%p), %p, %d, %ld, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId); + + return S_OK; +} + +static HRESULT WINAPI Basicaudio_Invoke(IBasicAudio *iface, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS*pDispParams, + VARIANT*pVarResult, + EXCEPINFO*pExepInfo, + UINT*puArgErr) { + ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface); + + TRACE("(%p/%p)->(%ld, %s (%p), %ld, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr); + + return S_OK; +} + +/*** IBasicAudio methods ***/ +static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface, + long lVolume) { + ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, lVolume); + + return S_OK; +} + +static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface, + long *plVolume) { + ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, plVolume); + + return S_OK; +} + +static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface, + long lBalance) { + ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, lBalance); + + return S_OK; +} + +static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface, + long *plBalance) { + ICOM_THIS_MULTI(DSoundRenderImpl, IBasicAudio_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, plBalance); + + return S_OK; +} + +static const IBasicAudioVtbl IBasicAudio_Vtbl = +{ + Basicaudio_QueryInterface, + Basicaudio_AddRef, + Basicaudio_Release, + Basicaudio_GetTypeInfoCount, + Basicaudio_GetTypeInfo, + Basicaudio_GetIDsOfNames, + Basicaudio_Invoke, + Basicaudio_put_Volume, + Basicaudio_get_Volume, + Basicaudio_put_Balance, + Basicaudio_get_Balance +}; diff --git a/dlls/quartz/main.c b/dlls/quartz/main.c index 773d547444f..70bbf87e585 100644 --- a/dlls/quartz/main.c +++ b/dlls/quartz/main.c @@ -66,7 +66,9 @@ static const struct object_creation_info object_creation[] = { &CLSID_AsyncReader, AsyncReader_create }, { &CLSID_MemoryAllocator, StdMemAllocator_create }, { &CLSID_AviSplitter, AVISplitter_create }, - + { &CLSID_VideoRenderer, VideoRenderer_create }, + { &CLSID_DSoundRender, DSoundRender_create }, + { &CLSID_AVIDec, AVIDec_create }, { &CLSID_SystemClock, &QUARTZ_CreateSystemClock } }; diff --git a/dlls/quartz/quartz_private.h b/dlls/quartz/quartz_private.h index 1cdb59af4fd..52bc2848d22 100644 --- a/dlls/quartz/quartz_private.h +++ b/dlls/quartz/quartz_private.h @@ -44,6 +44,9 @@ HRESULT FilterMapper2_create(IUnknown *pUnkOuter, LPVOID *ppObj); HRESULT AsyncReader_create(IUnknown * pUnkOuter, LPVOID * ppv); HRESULT StdMemAllocator_create(IUnknown * pUnkOuter, LPVOID * ppv); HRESULT AVISplitter_create(IUnknown * pUnkOuter, LPVOID * ppv); +HRESULT AVIDec_create(IUnknown * pUnkOuter, LPVOID * ppv); +HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv); +HRESULT VideoRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv); HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv); HRESULT EnumMonikerImpl_Create(IMoniker ** ppMoniker, ULONG nMonikerCount, IEnumMoniker ** ppEnum); diff --git a/dlls/quartz/regsvr.c b/dlls/quartz/regsvr.c index 4e1fc1eca40..1c9a34f48bf 100644 --- a/dlls/quartz/regsvr.c +++ b/dlls/quartz/regsvr.c @@ -527,6 +527,42 @@ static struct regsvr_coclass const coclass_list[] = { "quartz.dll", "Both" }, + { &CLSID_MemoryAllocator, + "Memory Allocator", + NULL, + "quartz.dll", + "Both" + }, + { &CLSID_AsyncReader, + "File Source Filter", + NULL, + "quartz.dll", + "Both" + }, + { &CLSID_AviSplitter, + "AVI Splitter", + NULL, + "quartz.dll", + "Both" + }, + { &CLSID_AVIDec, + "AVI Decompressor", + NULL, + "quartz.dll", + "Both" + }, + { &CLSID_DSoundRender, + "Direct Sound Audio Renderer", + NULL, + "quartz.dll", + "Both" + }, + { &CLSID_VideoRenderer, + "Video Renderer", + NULL, + "quartz.dll", + "Both" + }, { NULL } /* list terminator */ }; diff --git a/dlls/quartz/videorenderer.c b/dlls/quartz/videorenderer.c new file mode 100644 index 00000000000..8490b65dd41 --- /dev/null +++ b/dlls/quartz/videorenderer.c @@ -0,0 +1,1558 @@ +/* + * Video Renderer (Fullscreen and Windowed using Direct Draw) + * + * Copyright 2004 Christian Costa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#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 WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0}; + +static const IBaseFilterVtbl VideoRenderer_Vtbl; +static IBasicVideoVtbl IBasicVideo_VTable; +static IVideoWindowVtbl IVideoWindow_VTable; +static const IPinVtbl VideoRenderer_InputPin_Vtbl; + +typedef struct VideoRendererImpl +{ + const IBaseFilterVtbl * lpVtbl; + IBasicVideoVtbl * IBasicVideo_vtbl; + IVideoWindowVtbl * IVideoWindow_vtbl; + + ULONG refCount; + CRITICAL_SECTION csFilter; + FILTER_STATE state; + REFERENCE_TIME rtStreamStart; + IReferenceClock * pClock; + FILTER_INFO filterInfo; + + InputPin * pInputPin; + IPin ** ppPins; + + LPDIRECTDRAW ddraw; + LPDIRECTDRAWSURFACE surface; + LPDIRECTDRAWSURFACE backbuffer; + int init; +} VideoRendererImpl; + +static const IMemInputPinVtbl MemInputPin_Vtbl = +{ + MemInputPin_QueryInterface, + MemInputPin_AddRef, + MemInputPin_Release, + MemInputPin_GetAllocator, + MemInputPin_NotifyAllocator, + MemInputPin_GetAllocatorRequirements, + MemInputPin_Receive, + MemInputPin_ReceiveMultiple, + MemInputPin_ReceiveCanBlock +}; + +static HRESULT VideoRenderer_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin) +{ + InputPin * pPinImpl; + + *ppPin = NULL; + + if (pPinInfo->dir != PINDIR_INPUT) + { + ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir); + return E_INVALIDARG; + } + + pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl)); + + if (!pPinImpl) + return E_OUTOFMEMORY; + + if (SUCCEEDED(InputPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl))) + { + pPinImpl->pin.lpVtbl = &VideoRenderer_InputPin_Vtbl; + pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl; + + *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl); + return S_OK; + } + return E_FAIL; +} + +static HRESULT VideoRenderer_CreatePrimarySurface(IBaseFilter * iface) +{ + HRESULT hr; + DDSURFACEDESC sdesc; + DDSCAPS ddscaps; + ICOM_THIS(VideoRendererImpl, iface); + + hr = DirectDrawCreate(NULL, &This->ddraw, NULL); + + if (FAILED(hr)) { + ERR("Cannot create Direct Draw object\n"); + return hr; + } + + hr = IDirectDraw_SetCooperativeLevel(This->ddraw, NULL, DDSCL_FULLSCREEN|DDSCL_EXCLUSIVE); + if (FAILED(hr)) { + ERR("Cannot set fulscreen mode\n"); + return hr; + } + + sdesc.dwSize = sizeof(sdesc); + sdesc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + sdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; + sdesc.dwBackBufferCount = 1; + + hr = IDirectDraw_CreateSurface(This->ddraw, &sdesc, &This->surface, NULL); + if (FAILED(hr)) { + ERR("Cannot create surface\n"); + return hr; + } + + hr = IDirectDrawSurface_GetSurfaceDesc(This->surface, &sdesc); + if (FAILED(hr)) { + ERR("Cannot get surface information\n"); + return hr; + } + TRACE("Width = %ld\n", sdesc.dwWidth); + TRACE("Height = %ld\n", sdesc.dwHeight); + TRACE("Pitch = %ld\n", sdesc.u1.lPitch); + TRACE("Depth = %ld\n", sdesc.ddpfPixelFormat.u1.dwRGBBitCount); + + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; + hr = IDirectDrawSurface_GetAttachedSurface(This->surface, &ddscaps, &This->backbuffer); + if (FAILED(hr)) { + ERR("Cannot get backbuffer\n"); + return hr; + } + + return S_OK; +} + +static DWORD VideoRenderer_SendSampleData(VideoRendererImpl* This, LPBYTE data, DWORD size) +{ + VIDEOINFOHEADER* format; + AM_MEDIA_TYPE amt; + HRESULT hr = S_OK; + int i = 0; + int j = 0; + LPBYTE ptr; + DDSURFACEDESC sdesc; + int width; + int height; + LPBYTE palette = NULL; + + TRACE("%p %p %ld\n", This, data, size); + + sdesc.dwSize = sizeof(sdesc); + hr = IPin_ConnectionMediaType(This->ppPins[0], &amt); + if (FAILED(hr)) { + ERR("Unable to retreive media type\n"); + return hr; + } + format = (VIDEOINFOHEADER*)amt.pbFormat; + + TRACE("biSize = %ld\n", format->bmiHeader.biSize); + TRACE("biWidth = %ld\n", format->bmiHeader.biWidth); + TRACE("biHeigth = %ld\n", format->bmiHeader.biHeight); + TRACE("biPlanes = %d\n", format->bmiHeader.biPlanes); + TRACE("biBitCount = %d\n", format->bmiHeader.biBitCount); + TRACE("biCompression = %s\n", debugstr_an((LPSTR)&(format->bmiHeader.biCompression), 4)); + TRACE("biSizeImage = %ld\n", format->bmiHeader.biSizeImage); + + width = format->bmiHeader.biWidth; + height = format->bmiHeader.biHeight; + palette = ((LPBYTE)&format->bmiHeader) + format->bmiHeader.biSize; + + hr = IDirectDrawSurface_Lock(This->backbuffer, NULL, &sdesc, DDLOCK_WRITEONLY, NULL); + if (FAILED(hr)) { + ERR("Cannot lock backbuffer\n"); + return hr; + } + + ptr = sdesc.lpSurface; + + /* FIXME: We may use Direct Draw services to do the conversion for us */ + if ((sdesc.ddpfPixelFormat.u1.dwRGBBitCount == 24) || (sdesc.ddpfPixelFormat.u1.dwRGBBitCount == 32)) + { + if (format->bmiHeader.biBitCount == 8) + { + int psz = sdesc.ddpfPixelFormat.u1.dwRGBBitCount == 32 ? 4 : 3; + for (j = 0; j < height; j++) + for (i = 0; i < width; i++) + { + *(ptr + i*psz + 0 + j * sdesc.u1.lPitch) = palette[*(data + i + 0 + (height-1-j) * width)*4 + 0]; + *(ptr + i*psz + 1 + j * sdesc.u1.lPitch) = palette[*(data + i + 0 + (height-1-j) * width)*4 + 1]; + *(ptr + i*psz + 2 + j * sdesc.u1.lPitch) = palette[*(data + i + 0 + (height-1-j) * width)*4 + 2]; + if (psz == 4) + *(ptr + i*psz + 3 + j * sdesc.u1.lPitch) = 0xFF; + } + } + else + FIXME("Source size with a depths other than paletted 8 bits are not yet supported\n"); + } + else + FIXME("Destination depths with a depth other than 24 or 32 bits are not yet supported\n"); + + hr = IDirectDrawSurface_Unlock(This->backbuffer, NULL); + if (FAILED(hr)) { + ERR("Cannot unlock backbuffer\n"); + return hr; + } + + hr = IDirectDrawSurface_Flip(This->surface, NULL, DDFLIP_WAIT); + if (FAILED(hr)) { + ERR("Cannot unlock backbuffer\n"); + return hr; + } + + return S_OK; +} + +static HRESULT VideoRenderer_Sample(LPVOID iface, IMediaSample * pSample) +{ + ICOM_THIS(VideoRendererImpl, iface); + LPBYTE pbSrcStream = NULL; + long cbSrcStream = 0; + REFERENCE_TIME tStart, tStop; + HRESULT hr; + + TRACE("%p %p\n", iface, pSample); + + hr = IMediaSample_GetPointer(pSample, &pbSrcStream); + if (FAILED(hr)) + { + ERR("Cannot get pointer to sample data (%lx)\n", hr); + return hr; + } + + hr = IMediaSample_GetTime(pSample, &tStart, &tStop); + if (FAILED(hr)) + ERR("Cannot get sample time (%lx)\n", hr); + + cbSrcStream = IMediaSample_GetActualDataLength(pSample); + + TRACE("val %p %ld\n", pbSrcStream, cbSrcStream); + +#if 0 /* For debugging purpose */ + { + int i; + for(i = 0; i < cbSrcStream; i++) + { + if ((i!=0) && !(i%16)) + DPRINTF("\n"); + DPRINTF("%02x ", pbSrcStream[i]); + } + DPRINTF("\n"); + } +#endif + + if (!This->init) + { + This->init = 1; + hr = VideoRenderer_CreatePrimarySurface(iface); + if (FAILED(hr)) + { + ERR("Unable to create primary surface\n"); + } + } + + VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream); + + /* We have finished with the incoming sample, we must release it now */ + IMediaSample_Release(pSample); + + return S_OK; +} + +static HRESULT VideoRenderer_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt) +{ + if ((IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) && IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB32)) || + (IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) && IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB24)) || + (IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) && IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB565)) || + (IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) && IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB8))) + return S_OK; + return S_FALSE; +} + +HRESULT VideoRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv) +{ + HRESULT hr; + PIN_INFO piInput; + VideoRendererImpl * pVideoRenderer; + + TRACE("(%p, %p)\n", pUnkOuter, ppv); + + *ppv = NULL; + + if (pUnkOuter) + return CLASS_E_NOAGGREGATION; + + pVideoRenderer = CoTaskMemAlloc(sizeof(VideoRendererImpl)); + + pVideoRenderer->lpVtbl = &VideoRenderer_Vtbl; + pVideoRenderer->IBasicVideo_vtbl = &IBasicVideo_VTable; + pVideoRenderer->IVideoWindow_vtbl = &IVideoWindow_VTable; + + pVideoRenderer->refCount = 1; + InitializeCriticalSection(&pVideoRenderer->csFilter); + pVideoRenderer->state = State_Stopped; + pVideoRenderer->pClock = NULL; + pVideoRenderer->init = 0; + ZeroMemory(&pVideoRenderer->filterInfo, sizeof(FILTER_INFO)); + + pVideoRenderer->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *)); + + /* construct input pin */ + piInput.dir = PINDIR_INPUT; + piInput.pFilter = (IBaseFilter *)pVideoRenderer; + strncpyW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0])); + + hr = VideoRenderer_InputPin_Construct(&piInput, VideoRenderer_Sample, (LPVOID)pVideoRenderer, VideoRenderer_QueryAccept, &pVideoRenderer->csFilter, (IPin **)&pVideoRenderer->pInputPin); + + if (SUCCEEDED(hr)) + { + pVideoRenderer->ppPins[0] = (IPin *)pVideoRenderer->pInputPin; + *ppv = (LPVOID)pVideoRenderer; + } + else + { + CoTaskMemFree(pVideoRenderer->ppPins); + DeleteCriticalSection(&pVideoRenderer->csFilter); + CoTaskMemFree(pVideoRenderer); + } + + return hr; +} + +static HRESULT WINAPI VideoRenderer_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) +{ + ICOM_THIS(VideoRendererImpl, 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_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_IBasicVideo)) + *ppv = (LPVOID)&(This->IBasicVideo_vtbl); + else if (IsEqualIID(riid, &IID_IVideoWindow)) + *ppv = (LPVOID)&(This->IVideoWindow_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 VideoRenderer_AddRef(IBaseFilter * iface) +{ + ICOM_THIS(VideoRendererImpl, iface); + TRACE("(%p/%p)->() AddRef from %ld\n", This, iface, This->refCount); + return InterlockedIncrement(&This->refCount); +} + +static ULONG WINAPI VideoRenderer_Release(IBaseFilter * iface) +{ + ICOM_THIS(VideoRendererImpl, iface); + TRACE("(%p/%p)->() Release from %ld\n", This, iface, This->refCount); + if (!InterlockedDecrement(&This->refCount)) + { + DeleteCriticalSection(&This->csFilter); + IReferenceClock_Release(This->pClock); + + IPin_Release(This->ppPins[0]); + + HeapFree(GetProcessHeap(), 0, This->ppPins); + This->lpVtbl = NULL; + + TRACE("Destroying Video Renderer\n"); + CoTaskMemFree(This); + + return 0; + } + else + return This->refCount; +} + +/** IPersist methods **/ + +static HRESULT WINAPI VideoRenderer_GetClassID(IBaseFilter * iface, CLSID * pClsid) +{ + ICOM_THIS(VideoRendererImpl, iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, pClsid); + + *pClsid = CLSID_VideoRenderer; + + return S_OK; +} + +/** IMediaFilter methods **/ + +static HRESULT WINAPI VideoRenderer_Stop(IBaseFilter * iface) +{ + ICOM_THIS(VideoRendererImpl, iface); + + TRACE("(%p/%p)->()\n", This, iface); + + EnterCriticalSection(&This->csFilter); + { + This->state = State_Stopped; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI VideoRenderer_Pause(IBaseFilter * iface) +{ + ICOM_THIS(VideoRendererImpl, iface); + + TRACE("(%p/%p)->()\n", This, iface); + + EnterCriticalSection(&This->csFilter); + { + This->state = State_Paused; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI VideoRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tStart) +{ + ICOM_THIS(VideoRendererImpl, iface); + + TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart)); + + EnterCriticalSection(&This->csFilter); + { + This->rtStreamStart = tStart; + This->state = State_Running; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI VideoRenderer_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) +{ + ICOM_THIS(VideoRendererImpl, iface); + + TRACE("(%p/%p)->(%ld, %p)\n", This, iface, dwMilliSecsTimeout, pState); + + EnterCriticalSection(&This->csFilter); + { + *pState = This->state; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI VideoRenderer_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) +{ + ICOM_THIS(VideoRendererImpl, iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, pClock); + + EnterCriticalSection(&This->csFilter); + { + if (This->pClock) + IReferenceClock_Release(This->pClock); + This->pClock = pClock; + if (This->pClock) + IReferenceClock_AddRef(This->pClock); + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI VideoRenderer_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock) +{ + ICOM_THIS(VideoRendererImpl, iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, ppClock); + + EnterCriticalSection(&This->csFilter); + { + *ppClock = This->pClock; + IReferenceClock_AddRef(This->pClock); + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +/** IBaseFilter implementation **/ + +static HRESULT WINAPI VideoRenderer_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum) +{ + ENUMPINDETAILS epd; + ICOM_THIS(VideoRendererImpl, iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); + + epd.cPins = 1; /* input pin */ + epd.ppPins = This->ppPins; + return IEnumPinsImpl_Construct(&epd, ppEnum); +} + +static HRESULT WINAPI VideoRenderer_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin) +{ + ICOM_THIS(VideoRendererImpl, iface); + + TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin); + + FIXME("VideoRenderer::FindPin(...)\n"); + + /* FIXME: critical section */ + + return E_NOTIMPL; +} + +static HRESULT WINAPI VideoRenderer_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo) +{ + ICOM_THIS(VideoRendererImpl, iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, 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 VideoRenderer_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName) +{ + ICOM_THIS(VideoRendererImpl, iface); + + TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName)); + + EnterCriticalSection(&This->csFilter); + { + if (pName) + strcpyW(This->filterInfo.achName, pName); + else + *This->filterInfo.achName = '\0'; + This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */ + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI VideoRenderer_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo) +{ + ICOM_THIS(VideoRendererImpl, iface); + TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo); + return E_NOTIMPL; +} + +static const IBaseFilterVtbl VideoRenderer_Vtbl = +{ + VideoRenderer_QueryInterface, + VideoRenderer_AddRef, + VideoRenderer_Release, + VideoRenderer_GetClassID, + VideoRenderer_Stop, + VideoRenderer_Pause, + VideoRenderer_Run, + VideoRenderer_GetState, + VideoRenderer_SetSyncSource, + VideoRenderer_GetSyncSource, + VideoRenderer_EnumPins, + VideoRenderer_FindPin, + VideoRenderer_QueryFilterInfo, + VideoRenderer_JoinFilterGraph, + VideoRenderer_QueryVendorInfo +}; + +static const IPinVtbl VideoRenderer_InputPin_Vtbl = +{ + InputPin_QueryInterface, + IPinImpl_AddRef, + InputPin_Release, + InputPin_Connect, + InputPin_ReceiveConnection, + IPinImpl_Disconnect, + IPinImpl_ConnectedTo, + IPinImpl_ConnectionMediaType, + IPinImpl_QueryPinInfo, + IPinImpl_QueryDirection, + IPinImpl_QueryId, + IPinImpl_QueryAccept, + IPinImpl_EnumMediaTypes, + IPinImpl_QueryInternalConnections, + InputPin_EndOfStream, + InputPin_BeginFlush, + InputPin_EndFlush, + InputPin_NewSegment +}; + +/*** IUnknown methods ***/ +static HRESULT WINAPI Basicvideo_QueryInterface(IBasicVideo *iface, + REFIID riid, + LPVOID*ppvObj) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj); + + return VideoRenderer_QueryInterface((IBaseFilter*)This, riid, ppvObj); +} + +static ULONG WINAPI Basicvideo_AddRef(IBasicVideo *iface) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->()\n", This, iface); + + return VideoRenderer_AddRef((IBaseFilter*)This); +} + +static ULONG WINAPI Basicvideo_Release(IBasicVideo *iface) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->()\n", This, iface); + + return VideoRenderer_Release((IBaseFilter*)This); +} + +/*** IDispatch methods ***/ +static HRESULT WINAPI Basicvideo_GetTypeInfoCount(IBasicVideo *iface, + UINT*pctinfo) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_GetTypeInfo(IBasicVideo *iface, + UINT iTInfo, + LCID lcid, + ITypeInfo**ppTInfo) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%d, %ld, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_GetIDsOfNames(IBasicVideo *iface, + REFIID riid, + LPOLESTR*rgszNames, + UINT cNames, + LCID lcid, + DISPID*rgDispId) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%s (%p), %p, %d, %ld, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_Invoke(IBasicVideo *iface, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS*pDispParams, + VARIANT*pVarResult, + EXCEPINFO*pExepInfo, + UINT*puArgErr) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%ld, %s (%p), %ld, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr); + + return S_OK; +} + +/*** IBasicVideo methods ***/ +static HRESULT WINAPI Basicvideo_get_AvgTimePerFrame(IBasicVideo *iface, + REFTIME *pAvgTimePerFrame) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pAvgTimePerFrame); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_get_BitRate(IBasicVideo *iface, + long *pBitRate) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pBitRate); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_get_BitErrorRate(IBasicVideo *iface, + long *pBitErrorRate) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pBitErrorRate); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_get_VideoWidth(IBasicVideo *iface, + long *pVideoWidth) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pVideoWidth); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_get_VideoHeight(IBasicVideo *iface, + long *pVideoHeight) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pVideoHeight); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_put_SourceLeft(IBasicVideo *iface, + long SourceLeft) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, SourceLeft); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_get_SourceLeft(IBasicVideo *iface, + long *pSourceLeft) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pSourceLeft); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_put_SourceWidth(IBasicVideo *iface, + long SourceWidth) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, SourceWidth); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_get_SourceWidth(IBasicVideo *iface, + long *pSourceWidth) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pSourceWidth); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_put_SourceTop(IBasicVideo *iface, + long SourceTop) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, SourceTop); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_get_SourceTop(IBasicVideo *iface, + long *pSourceTop) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pSourceTop); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_put_SourceHeight(IBasicVideo *iface, + long SourceHeight) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, SourceHeight); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_get_SourceHeight(IBasicVideo *iface, + long *pSourceHeight) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pSourceHeight); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_put_DestinationLeft(IBasicVideo *iface, + long DestinationLeft) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, DestinationLeft); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_get_DestinationLeft(IBasicVideo *iface, + long *pDestinationLeft) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pDestinationLeft); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_put_DestinationWidth(IBasicVideo *iface, + long DestinationWidth) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, DestinationWidth); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_get_DestinationWidth(IBasicVideo *iface, + long *pDestinationWidth) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pDestinationWidth); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_put_DestinationTop(IBasicVideo *iface, + long DestinationTop) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, DestinationTop); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_get_DestinationTop(IBasicVideo *iface, + long *pDestinationTop) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pDestinationTop); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_put_DestinationHeight(IBasicVideo *iface, + long DestinationHeight) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, DestinationHeight); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_get_DestinationHeight(IBasicVideo *iface, + long *pDestinationHeight) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pDestinationHeight); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_SetSourcePosition(IBasicVideo *iface, + long Left, + long Top, + long Width, + long Height) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%ld, %ld, %ld, %ld): stub !!!\n", This, iface, Left, Top, Width, Height); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_GetSourcePosition(IBasicVideo *iface, + long *pLeft, + long *pTop, + long *pWidth, + long *pHeight) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p, %p, %p, %p): stub !!!\n", This, iface, pLeft, pTop, pWidth, pHeight); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_SetDefaultSourcePosition(IBasicVideo *iface) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(): stub !!!\n", This, iface); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_SetDestinationPosition(IBasicVideo *iface, + long Left, + long Top, + long Width, + long Height) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%ld, %ld, %ld, %ld): stub !!!\n", This, iface, Left, Top, Width, Height); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_GetDestinationPosition(IBasicVideo *iface, + long *pLeft, + long *pTop, + long *pWidth, + long *pHeight) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p, %p, %p, %p): stub !!!\n", This, iface, pLeft, pTop, pWidth, pHeight); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_SetDefaultDestinationPosition(IBasicVideo *iface) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(): stub !!!\n", This, iface); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_GetVideoSize(IBasicVideo *iface, + long *pWidth, + long *pHeight) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pWidth, pHeight); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_GetVideoPaletteEntries(IBasicVideo *iface, + long StartIndex, + long Entries, + long *pRetrieved, + long *pPalette) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%ld, %ld, %p, %p): stub !!!\n", This, iface, StartIndex, Entries, pRetrieved, pPalette); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_GetCurrentImage(IBasicVideo *iface, + long *pBufferSize, + long *pDIBImage) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pBufferSize, pDIBImage); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_IsUsingDefaultSource(IBasicVideo *iface) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(): stub !!!\n", This, iface); + + return S_OK; +} + +static HRESULT WINAPI Basicvideo_IsUsingDefaultDestination(IBasicVideo *iface) { + ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); + + TRACE("(%p/%p)->(): stub !!!\n", This, iface); + + return S_OK; +} + + +static IBasicVideoVtbl IBasicVideo_VTable = +{ + Basicvideo_QueryInterface, + Basicvideo_AddRef, + Basicvideo_Release, + Basicvideo_GetTypeInfoCount, + Basicvideo_GetTypeInfo, + Basicvideo_GetIDsOfNames, + Basicvideo_Invoke, + Basicvideo_get_AvgTimePerFrame, + Basicvideo_get_BitRate, + Basicvideo_get_BitErrorRate, + Basicvideo_get_VideoWidth, + Basicvideo_get_VideoHeight, + Basicvideo_put_SourceLeft, + Basicvideo_get_SourceLeft, + Basicvideo_put_SourceWidth, + Basicvideo_get_SourceWidth, + Basicvideo_put_SourceTop, + Basicvideo_get_SourceTop, + Basicvideo_put_SourceHeight, + Basicvideo_get_SourceHeight, + Basicvideo_put_DestinationLeft, + Basicvideo_get_DestinationLeft, + Basicvideo_put_DestinationWidth, + Basicvideo_get_DestinationWidth, + Basicvideo_put_DestinationTop, + Basicvideo_get_DestinationTop, + Basicvideo_put_DestinationHeight, + Basicvideo_get_DestinationHeight, + Basicvideo_SetSourcePosition, + Basicvideo_GetSourcePosition, + Basicvideo_SetDefaultSourcePosition, + Basicvideo_SetDestinationPosition, + Basicvideo_GetDestinationPosition, + Basicvideo_SetDefaultDestinationPosition, + Basicvideo_GetVideoSize, + Basicvideo_GetVideoPaletteEntries, + Basicvideo_GetCurrentImage, + Basicvideo_IsUsingDefaultSource, + Basicvideo_IsUsingDefaultDestination +}; + + +/*** IUnknown methods ***/ +static HRESULT WINAPI Videowindow_QueryInterface(IVideoWindow *iface, + REFIID riid, + LPVOID*ppvObj) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj); + + return VideoRenderer_QueryInterface((IBaseFilter*)This, riid, ppvObj); +} + +static ULONG WINAPI Videowindow_AddRef(IVideoWindow *iface) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->()\n", This, iface); + + return VideoRenderer_AddRef((IBaseFilter*)This); +} + +static ULONG WINAPI Videowindow_Release(IVideoWindow *iface) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->()\n", This, iface); + + return VideoRenderer_Release((IBaseFilter*)This); +} + +/*** IDispatch methods ***/ +static HRESULT WINAPI Videowindow_GetTypeInfoCount(IVideoWindow *iface, + UINT*pctinfo) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_GetTypeInfo(IVideoWindow *iface, + UINT iTInfo, + LCID lcid, + ITypeInfo**ppTInfo) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%d, %ld, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_GetIDsOfNames(IVideoWindow *iface, + REFIID riid, + LPOLESTR*rgszNames, + UINT cNames, + LCID lcid, + DISPID*rgDispId) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%s (%p), %p, %d, %ld, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_Invoke(IVideoWindow *iface, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS*pDispParams, + VARIANT*pVarResult, + EXCEPINFO*pExepInfo, + UINT*puArgErr) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld, %s (%p), %ld, %04x, %p, %p, %p, %p): stub !!!\n", This, iface, dispIdMember, debugstr_guid(riid), riid, lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr); + + return S_OK; +} + +/*** IVideoWindow methods ***/ +static HRESULT WINAPI Videowindow_put_Caption(IVideoWindow *iface, + BSTR strCaption) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%s (%p)): stub !!!\n", This, iface, debugstr_w(strCaption), strCaption); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_Caption(IVideoWindow *iface, + BSTR *strCaption) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, strCaption); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_put_WindowStyle(IVideoWindow *iface, + long WindowStyle) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, WindowStyle); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_WindowStyle(IVideoWindow *iface, + long *WindowStyle) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, WindowStyle); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_put_WindowStyleEx(IVideoWindow *iface, + long WindowStyleEx) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, WindowStyleEx); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_WindowStyleEx(IVideoWindow *iface, + long *WindowStyleEx) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, WindowStyleEx); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_put_AutoShow(IVideoWindow *iface, + long AutoShow) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, AutoShow); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_AutoShow(IVideoWindow *iface, + long *AutoShow) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, AutoShow); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_put_WindowState(IVideoWindow *iface, + long WindowState) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, WindowState); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_WindowState(IVideoWindow *iface, + long *WindowState) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, WindowState); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_put_BackgroundPalette(IVideoWindow *iface, + long BackgroundPalette) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, BackgroundPalette); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_BackgroundPalette(IVideoWindow *iface, + long *pBackgroundPalette) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pBackgroundPalette); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_put_Visible(IVideoWindow *iface, + long Visible) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, Visible); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_Visible(IVideoWindow *iface, + long *pVisible) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pVisible); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_put_Left(IVideoWindow *iface, + long Left) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, Left); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_Left(IVideoWindow *iface, + long *pLeft) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pLeft); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_put_Width(IVideoWindow *iface, + long Width) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, Width); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_Width(IVideoWindow *iface, + long *pWidth) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pWidth); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_put_Top(IVideoWindow *iface, + long Top) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, Top); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_Top(IVideoWindow *iface, + long *pTop) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pTop); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_put_Height(IVideoWindow *iface, + long Height) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, Height); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_Height(IVideoWindow *iface, + long *pHeight) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, pHeight); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_put_Owner(IVideoWindow *iface, + OAHWND Owner) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%08lx): stub !!!\n", This, iface, (DWORD) Owner); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_Owner(IVideoWindow *iface, + OAHWND *Owner) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%08lx): stub !!!\n", This, iface, (DWORD) Owner); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_put_MessageDrain(IVideoWindow *iface, + OAHWND Drain) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%08lx): stub !!!\n", This, iface, (DWORD) Drain); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_MessageDrain(IVideoWindow *iface, + OAHWND *Drain) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, Drain); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_BorderColor(IVideoWindow *iface, + long *Color) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, Color); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_put_BorderColor(IVideoWindow *iface, + long Color) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, Color); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_get_FullScreenMode(IVideoWindow *iface, + long *FullScreenMode) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, FullScreenMode); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_put_FullScreenMode(IVideoWindow *iface, + long FullScreenMode) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, FullScreenMode); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_SetWindowForeground(IVideoWindow *iface, + long Focus) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, Focus); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_NotifyOwnerMessage(IVideoWindow *iface, + OAHWND hwnd, + long uMsg, + LONG_PTR wParam, + LONG_PTR lParam) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%08lx, %ld, %08lx, %08lx): stub !!!\n", This, iface, (DWORD) hwnd, uMsg, wParam, lParam); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_SetWindowPosition(IVideoWindow *iface, + long Left, + long Top, + long Width, + long Height) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld, %ld, %ld, %ld): stub !!!\n", This, iface, Left, Top, Width, Height); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_GetWindowPosition(IVideoWindow *iface, + long *pLeft, + long *pTop, + long *pWidth, + long *pHeight) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p, %p, %p, %p): stub !!!\n", This, iface, pLeft, pTop, pWidth, pHeight); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_GetMinIdealImageSize(IVideoWindow *iface, + long *pWidth, + long *pHeight) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pWidth, pHeight); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_GetMaxIdealImageSize(IVideoWindow *iface, + long *pWidth, + long *pHeight) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p, %p): stub !!!\n", This, iface, pWidth, pHeight); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_GetRestorePosition(IVideoWindow *iface, + long *pLeft, + long *pTop, + long *pWidth, + long *pHeight) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p, %p, %p, %p): stub !!!\n", This, iface, pLeft, pTop, pWidth, pHeight); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_HideCursor(IVideoWindow *iface, + long HideCursor) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, HideCursor); + + return S_OK; +} + +static HRESULT WINAPI Videowindow_IsCursorHidden(IVideoWindow *iface, + long *CursorHidden) { + ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); + + TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, CursorHidden); + + return S_OK; +} + +static IVideoWindowVtbl IVideoWindow_VTable = +{ + Videowindow_QueryInterface, + Videowindow_AddRef, + Videowindow_Release, + Videowindow_GetTypeInfoCount, + Videowindow_GetTypeInfo, + Videowindow_GetIDsOfNames, + Videowindow_Invoke, + Videowindow_put_Caption, + Videowindow_get_Caption, + Videowindow_put_WindowStyle, + Videowindow_get_WindowStyle, + Videowindow_put_WindowStyleEx, + Videowindow_get_WindowStyleEx, + Videowindow_put_AutoShow, + Videowindow_get_AutoShow, + Videowindow_put_WindowState, + Videowindow_get_WindowState, + Videowindow_put_BackgroundPalette, + Videowindow_get_BackgroundPalette, + Videowindow_put_Visible, + Videowindow_get_Visible, + Videowindow_put_Left, + Videowindow_get_Left, + Videowindow_put_Width, + Videowindow_get_Width, + Videowindow_put_Top, + Videowindow_get_Top, + Videowindow_put_Height, + Videowindow_get_Height, + Videowindow_put_Owner, + Videowindow_get_Owner, + Videowindow_put_MessageDrain, + Videowindow_get_MessageDrain, + Videowindow_get_BorderColor, + Videowindow_put_BorderColor, + Videowindow_get_FullScreenMode, + Videowindow_put_FullScreenMode, + Videowindow_SetWindowForeground, + Videowindow_NotifyOwnerMessage, + Videowindow_SetWindowPosition, + Videowindow_GetWindowPosition, + Videowindow_GetMinIdealImageSize, + Videowindow_GetMaxIdealImageSize, + Videowindow_GetRestorePosition, + Videowindow_HideCursor, + Videowindow_IsCursorHidden +};