/* * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #define NONAMELESSSTRUCT #define NONAMELESSUNION #include "quartz_private.h" #include "control_private.h" #include "pin.h" #include "uuids.h" #include "vfwmsgs.h" #include "amvideo.h" #include "windef.h" #include "winbase.h" #include "dshow.h" #include "evcode.h" #include "strmif.h" #include "ddraw.h" #include "dvdmedia.h" #include <assert.h> #include "wine/unicode.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(quartz); static BOOL wnd_class_registered = FALSE; static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0}; static const IBaseFilterVtbl VideoRenderer_Vtbl; static const IUnknownVtbl IInner_VTable; static const IBasicVideoVtbl IBasicVideo_VTable; static const IVideoWindowVtbl IVideoWindow_VTable; static const IPinVtbl VideoRenderer_InputPin_Vtbl; typedef struct VideoRendererImpl { const IBaseFilterVtbl * lpVtbl; const IBasicVideoVtbl * IBasicVideo_vtbl; const IVideoWindowVtbl * IVideoWindow_vtbl; const IUnknownVtbl * IInner_vtbl; LONG refCount; CRITICAL_SECTION csFilter; FILTER_STATE state; REFERENCE_TIME rtStreamStart; IReferenceClock * pClock; FILTER_INFO filterInfo; InputPin *pInputPin; BOOL init; HANDLE hThread; HANDLE blocked; DWORD ThreadID; HANDLE hEvent; BOOL ThreadResult; HWND hWnd; HWND hWndMsgDrain; BOOL AutoShow; RECT SourceRect; RECT DestRect; RECT WindowPos; long VideoWidth; long VideoHeight; IUnknown * pUnkOuter; BOOL bUnkOuterValid; BOOL bAggregatable; REFERENCE_TIME rtLastStop; MediaSeekingImpl mediaSeeking; /* During pause we can hold a single sample, for use in GetCurrentImage */ IMediaSample *sample_held; } VideoRendererImpl; static LRESULT CALLBACK VideoWndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { VideoRendererImpl* pVideoRenderer = (VideoRendererImpl*)GetWindowLongPtrW(hwnd, 0); LPRECT lprect = (LPRECT)lParam; if (pVideoRenderer && pVideoRenderer->hWndMsgDrain) { switch(uMsg) { case WM_KEYDOWN: case WM_KEYUP: case WM_LBUTTONDBLCLK: case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_MBUTTONDBLCLK: case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MOUSEACTIVATE: case WM_MOUSEMOVE: case WM_NCLBUTTONDBLCLK: case WM_NCLBUTTONDOWN: case WM_NCLBUTTONUP: case WM_NCMBUTTONDBLCLK: case WM_NCMBUTTONDOWN: case WM_NCMBUTTONUP: case WM_NCMOUSEMOVE: case WM_NCRBUTTONDBLCLK: case WM_NCRBUTTONDOWN: case WM_NCRBUTTONUP: case WM_RBUTTONDBLCLK: case WM_RBUTTONDOWN: case WM_RBUTTONUP: PostMessageA(pVideoRenderer->hWndMsgDrain, uMsg, wParam, lParam); break; default: break; } } switch(uMsg) { case WM_SIZING: /* TRACE("WM_SIZING %d %d %d %d\n", lprect->left, lprect->top, lprect->right, lprect->bottom); */ SetWindowPos(hwnd, NULL, lprect->left, lprect->top, lprect->right - lprect->left, lprect->bottom - lprect->top, SWP_NOZORDER); GetClientRect(hwnd, &pVideoRenderer->DestRect); TRACE("WM_SIZING: DestRect=(%d,%d),(%d,%d)\n", pVideoRenderer->DestRect.left, pVideoRenderer->DestRect.top, pVideoRenderer->DestRect.right - pVideoRenderer->DestRect.left, pVideoRenderer->DestRect.bottom - pVideoRenderer->DestRect.top); return TRUE; case WM_SIZE: TRACE("WM_SIZE %d %d\n", LOWORD(lParam), HIWORD(lParam)); GetClientRect(hwnd, &pVideoRenderer->DestRect); TRACE("WM_SIZING: DestRect=(%d,%d),(%d,%d)\n", pVideoRenderer->DestRect.left, pVideoRenderer->DestRect.top, pVideoRenderer->DestRect.right - pVideoRenderer->DestRect.left, pVideoRenderer->DestRect.bottom - pVideoRenderer->DestRect.top); return TRUE; default: return DefWindowProcA(hwnd, uMsg, wParam, lParam); } return 0; } static BOOL CreateRenderingWindow(VideoRendererImpl* This) { WNDCLASSA winclass; TRACE("(%p)->()\n", This); winclass.style = 0; winclass.lpfnWndProc = VideoWndProcA; winclass.cbClsExtra = 0; winclass.cbWndExtra = sizeof(VideoRendererImpl*); winclass.hInstance = NULL; winclass.hIcon = NULL; winclass.hCursor = NULL; winclass.hbrBackground = GetStockObject(BLACK_BRUSH); winclass.lpszMenuName = NULL; winclass.lpszClassName = "Wine ActiveMovie Class"; if (!wnd_class_registered) { if (!RegisterClassA(&winclass)) { ERR("Unable to register window %u\n", GetLastError()); return FALSE; } wnd_class_registered = TRUE; } This->hWnd = CreateWindowExA(0, "Wine ActiveMovie Class", "Wine ActiveMovie Window", WS_SIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL); if (!This->hWnd) { ERR("Unable to create window\n"); return FALSE; } SetWindowLongPtrW(This->hWnd, 0, (LONG_PTR)This); return TRUE; } static DWORD WINAPI MessageLoop(LPVOID lpParameter) { VideoRendererImpl* This = lpParameter; MSG msg; BOOL fGotMessage; TRACE("Starting message loop\n"); if (!CreateRenderingWindow(This)) { This->ThreadResult = FALSE; SetEvent(This->hEvent); return 0; } This->ThreadResult = TRUE; SetEvent(This->hEvent); while ((fGotMessage = GetMessageA(&msg, NULL, 0, 0)) != 0 && fGotMessage != -1) { TranslateMessage(&msg); DispatchMessageA(&msg); } TRACE("End of message loop\n"); return msg.wParam; } static BOOL CreateRenderingSubsystem(VideoRendererImpl* This) { This->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); if (!This->hEvent) return FALSE; This->hThread = CreateThread(NULL, 0, MessageLoop, This, 0, &This->ThreadID); if (!This->hThread) { CloseHandle(This->hEvent); return FALSE; } WaitForSingleObject(This->hEvent, INFINITE); if (!This->ThreadResult) { CloseHandle(This->hEvent); CloseHandle(This->hThread); return FALSE; } return TRUE; } static DWORD VideoRenderer_SendSampleData(VideoRendererImpl* This, LPBYTE data, DWORD size) { AM_MEDIA_TYPE amt; HRESULT hr = S_OK; DDSURFACEDESC sdesc; HDC hDC; BITMAPINFOHEADER *bmiHeader; TRACE("(%p)->(%p, %d)\n", This, data, size); sdesc.dwSize = sizeof(sdesc); hr = IPin_ConnectionMediaType((IPin *)This->pInputPin, &amt); if (FAILED(hr)) { ERR("Unable to retrieve media type\n"); return hr; } if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo)) { bmiHeader = &((VIDEOINFOHEADER *)amt.pbFormat)->bmiHeader; } else if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo2)) { bmiHeader = &((VIDEOINFOHEADER2 *)amt.pbFormat)->bmiHeader; } else { FIXME("Unknown type %s\n", debugstr_guid(&amt.subtype)); return VFW_E_RUNTIME_ERROR; } TRACE("biSize = %d\n", bmiHeader->biSize); TRACE("biWidth = %d\n", bmiHeader->biWidth); TRACE("biHeight = %d\n", bmiHeader->biHeight); TRACE("biPlanes = %d\n", bmiHeader->biPlanes); TRACE("biBitCount = %d\n", bmiHeader->biBitCount); TRACE("biCompression = %s\n", debugstr_an((LPSTR)&(bmiHeader->biCompression), 4)); TRACE("biSizeImage = %d\n", bmiHeader->biSizeImage); if (!This->init) { DWORD style = GetWindowLongW(This->hWnd, GWL_STYLE); DWORD style_ex = GetWindowLongW(This->hWnd, GWL_EXSTYLE); if (!This->WindowPos.right || !This->WindowPos.bottom) This->WindowPos = This->SourceRect; AdjustWindowRectEx(&This->WindowPos, style, TRUE, style_ex); TRACE("WindowPos: %d %d %d %d\n", This->WindowPos.left, This->WindowPos.top, This->WindowPos.right, This->WindowPos.bottom); SetWindowPos(This->hWnd, NULL, This->WindowPos.left, This->WindowPos.top, This->WindowPos.right - This->WindowPos.left, This->WindowPos.bottom - This->WindowPos.top, SWP_NOZORDER|SWP_NOMOVE); GetClientRect(This->hWnd, &This->DestRect); This->init = TRUE; } hDC = GetDC(This->hWnd); if (!hDC) { ERR("Cannot get DC from window!\n"); return E_FAIL; } TRACE("Src Rect: %d %d %d %d\n", This->SourceRect.left, This->SourceRect.top, This->SourceRect.right, This->SourceRect.bottom); TRACE("Dst Rect: %d %d %d %d\n", This->DestRect.left, This->DestRect.top, This->DestRect.right, This->DestRect.bottom); StretchDIBits(hDC, This->DestRect.left, This->DestRect.top, This->DestRect.right -This->DestRect.left, This->DestRect.bottom - This->DestRect.top, This->SourceRect.left, This->SourceRect.top, This->SourceRect.right - This->SourceRect.left, This->SourceRect.bottom - This->SourceRect.top, data, (BITMAPINFO *)bmiHeader, DIB_RGB_COLORS, SRCCOPY); ReleaseDC(This->hWnd, hDC); if (This->AutoShow) ShowWindow(This->hWnd, SW_SHOW); return S_OK; } static HRESULT VideoRenderer_Sample(LPVOID iface, IMediaSample * pSample) { VideoRendererImpl *This = iface; LPBYTE pbSrcStream = NULL; long cbSrcStream = 0; REFERENCE_TIME tStart, tStop; HRESULT hr; TRACE("(%p)->(%p)\n", iface, pSample); EnterCriticalSection(&This->csFilter); if (This->pInputPin->flushing || This->pInputPin->end_of_stream) { LeaveCriticalSection(&This->csFilter); return S_FALSE; } if (This->state == State_Stopped) { LeaveCriticalSection(&This->csFilter); return VFW_E_WRONG_STATE; } hr = IMediaSample_GetTime(pSample, &tStart, &tStop); if (FAILED(hr)) ERR("Cannot get sample time (%x)\n", hr); if (This->rtLastStop != tStart) { if (IMediaSample_IsDiscontinuity(pSample) == S_FALSE) ERR("Unexpected discontinuity: Last: %u.%03u, tStart: %u.%03u\n", (DWORD)(This->rtLastStop / 10000000), (DWORD)((This->rtLastStop / 10000)%1000), (DWORD)(tStart / 10000000), (DWORD)((tStart / 10000)%1000)); This->rtLastStop = tStart; } /* Preroll means the sample isn't shown, this is used for key frames and things like that */ if (IMediaSample_IsPreroll(pSample) == S_OK) { This->rtLastStop = tStop; LeaveCriticalSection(&This->csFilter); return S_OK; } hr = IMediaSample_GetPointer(pSample, &pbSrcStream); if (FAILED(hr)) { ERR("Cannot get pointer to sample data (%x)\n", hr); LeaveCriticalSection(&This->csFilter); return 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)) TRACE("\n"); TRACE("%02x ", pbSrcStream[i]); } TRACE("\n"); } #endif SetEvent(This->hEvent); if (This->state == State_Paused) { This->sample_held = pSample; LeaveCriticalSection(&This->csFilter); WaitForSingleObject(This->blocked, INFINITE); EnterCriticalSection(&This->csFilter); This->sample_held = NULL; if (This->state == State_Paused) { /* Flushing */ LeaveCriticalSection(&This->csFilter); return S_OK; } if (This->state == State_Stopped) { LeaveCriticalSection(&This->csFilter); return VFW_E_WRONG_STATE; } } if (This->pClock && This->state == State_Running) { REFERENCE_TIME time, trefstart, trefstop; LONG delta; /* Perhaps I <SHOULD> use the reference clock AdviseTime function here * I'm not going to! When I tried, it seemed to generate lag and * it caused instability. */ IReferenceClock_GetTime(This->pClock, &time); trefstart = This->rtStreamStart; trefstop = (REFERENCE_TIME)((double)(tStop - tStart) / This->pInputPin->dRate) + This->rtStreamStart; delta = (LONG)((trefstart-time)/10000); This->rtStreamStart = trefstop; This->rtLastStop = tStop; if (delta > 0) { TRACE("Sleeping for %u ms\n", delta); Sleep(delta); } else if (time > trefstop) { TRACE("Dropping sample: Time: %u.%03u ms trefstop: %u.%03u ms!\n", (DWORD)(time / 10000000), (DWORD)((time / 10000)%1000), (DWORD)(trefstop / 10000000), (DWORD)((trefstop / 10000)%1000) ); This->rtLastStop = tStop; LeaveCriticalSection(&This->csFilter); return S_OK; } } This->rtLastStop = tStop; VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream); LeaveCriticalSection(&This->csFilter); return S_OK; } static HRESULT VideoRenderer_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt) { if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Video)) return S_FALSE; if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB32) || IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB24) || IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB565) || IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB8)) { VideoRendererImpl* This = iface; if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) { VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)pmt->pbFormat; This->SourceRect.left = 0; This->SourceRect.top = 0; This->SourceRect.right = This->VideoWidth = format->bmiHeader.biWidth; This->SourceRect.bottom = This->VideoHeight = format->bmiHeader.biHeight; } else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2)) { VIDEOINFOHEADER2 *format2 = (VIDEOINFOHEADER2 *)pmt->pbFormat; This->SourceRect.left = 0; This->SourceRect.top = 0; This->SourceRect.right = This->VideoWidth = format2->bmiHeader.biWidth; This->SourceRect.bottom = This->VideoHeight = format2->bmiHeader.biHeight; } else { WARN("Format type %s not supported\n", debugstr_guid(&pmt->formattype)); return S_FALSE; } return S_OK; } return S_FALSE; } static inline VideoRendererImpl *impl_from_IMediaSeeking( IMediaSeeking *iface ) { return (VideoRendererImpl *)((char*)iface - FIELD_OFFSET(VideoRendererImpl, mediaSeeking.lpVtbl)); } static HRESULT WINAPI VideoRendererImpl_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv) { VideoRendererImpl *This = impl_from_IMediaSeeking(iface); return IUnknown_QueryInterface((IUnknown *)This, riid, ppv); } static ULONG WINAPI VideoRendererImpl_Seeking_AddRef(IMediaSeeking * iface) { VideoRendererImpl *This = impl_from_IMediaSeeking(iface); return IUnknown_AddRef((IUnknown *)This); } static ULONG WINAPI VideoRendererImpl_Seeking_Release(IMediaSeeking * iface) { VideoRendererImpl *This = impl_from_IMediaSeeking(iface); return IUnknown_Release((IUnknown *)This); } static const IMediaSeekingVtbl VideoRendererImpl_Seeking_Vtbl = { VideoRendererImpl_Seeking_QueryInterface, VideoRendererImpl_Seeking_AddRef, VideoRendererImpl_Seeking_Release, MediaSeekingImpl_GetCapabilities, MediaSeekingImpl_CheckCapabilities, MediaSeekingImpl_IsFormatSupported, MediaSeekingImpl_QueryPreferredFormat, MediaSeekingImpl_GetTimeFormat, MediaSeekingImpl_IsUsingTimeFormat, MediaSeekingImpl_SetTimeFormat, MediaSeekingImpl_GetDuration, MediaSeekingImpl_GetStopPosition, MediaSeekingImpl_GetCurrentPosition, MediaSeekingImpl_ConvertTimeFormat, MediaSeekingImpl_SetPositions, MediaSeekingImpl_GetPositions, MediaSeekingImpl_GetAvailable, MediaSeekingImpl_SetRate, MediaSeekingImpl_GetRate, MediaSeekingImpl_GetPreroll }; static HRESULT VideoRendererImpl_Change(IBaseFilter *iface) { TRACE("(%p)->()\n", iface); return S_OK; } HRESULT VideoRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv) { HRESULT hr; PIN_INFO piInput; VideoRendererImpl * pVideoRenderer; TRACE("(%p, %p)\n", pUnkOuter, ppv); *ppv = NULL; pVideoRenderer = CoTaskMemAlloc(sizeof(VideoRendererImpl)); pVideoRenderer->pUnkOuter = pUnkOuter; pVideoRenderer->bUnkOuterValid = FALSE; pVideoRenderer->bAggregatable = FALSE; pVideoRenderer->IInner_vtbl = &IInner_VTable; pVideoRenderer->lpVtbl = &VideoRenderer_Vtbl; pVideoRenderer->IBasicVideo_vtbl = &IBasicVideo_VTable; pVideoRenderer->IVideoWindow_vtbl = &IVideoWindow_VTable; pVideoRenderer->refCount = 1; InitializeCriticalSection(&pVideoRenderer->csFilter); pVideoRenderer->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": VideoRendererImpl.csFilter"); pVideoRenderer->state = State_Stopped; pVideoRenderer->pClock = NULL; pVideoRenderer->init = 0; pVideoRenderer->AutoShow = 1; pVideoRenderer->rtLastStop = -1; ZeroMemory(&pVideoRenderer->filterInfo, sizeof(FILTER_INFO)); ZeroMemory(&pVideoRenderer->SourceRect, sizeof(RECT)); ZeroMemory(&pVideoRenderer->DestRect, sizeof(RECT)); ZeroMemory(&pVideoRenderer->WindowPos, sizeof(RECT)); pVideoRenderer->hWndMsgDrain = NULL; /* construct input pin */ piInput.dir = PINDIR_INPUT; piInput.pFilter = (IBaseFilter *)pVideoRenderer; lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0])); hr = InputPin_Construct(&VideoRenderer_InputPin_Vtbl, &piInput, VideoRenderer_Sample, (LPVOID)pVideoRenderer, VideoRenderer_QueryAccept, NULL, &pVideoRenderer->csFilter, NULL, (IPin **)&pVideoRenderer->pInputPin); if (SUCCEEDED(hr)) { MediaSeekingImpl_Init((IBaseFilter*)pVideoRenderer, VideoRendererImpl_Change, VideoRendererImpl_Change, VideoRendererImpl_Change, &pVideoRenderer->mediaSeeking, &pVideoRenderer->csFilter); pVideoRenderer->mediaSeeking.lpVtbl = &VideoRendererImpl_Seeking_Vtbl; pVideoRenderer->sample_held = NULL; *ppv = pVideoRenderer; } else { pVideoRenderer->csFilter.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&pVideoRenderer->csFilter); CoTaskMemFree(pVideoRenderer); } if (!CreateRenderingSubsystem(pVideoRenderer)) return E_FAIL; pVideoRenderer->blocked = CreateEventW(NULL, FALSE, FALSE, NULL); if (!pVideoRenderer->blocked) { hr = HRESULT_FROM_WIN32(GetLastError()); IUnknown_Release((IUnknown *)pVideoRenderer); } return hr; } HRESULT VideoRendererDefault_create(IUnknown * pUnkOuter, LPVOID * ppv) { /* TODO: Attempt to use the VMR-7 renderer instead when possible */ return VideoRenderer_create(pUnkOuter, ppv); } static HRESULT WINAPI VideoRendererInner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv) { ICOM_THIS_MULTI(VideoRendererImpl, IInner_vtbl, iface); TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv); if (This->bAggregatable) This->bUnkOuterValid = TRUE; *ppv = NULL; if (IsEqualIID(riid, &IID_IUnknown)) *ppv = &This->IInner_vtbl; else if (IsEqualIID(riid, &IID_IPersist)) *ppv = This; else if (IsEqualIID(riid, &IID_IMediaFilter)) *ppv = This; else if (IsEqualIID(riid, &IID_IBaseFilter)) *ppv = This; else if (IsEqualIID(riid, &IID_IBasicVideo)) *ppv = &This->IBasicVideo_vtbl; else if (IsEqualIID(riid, &IID_IVideoWindow)) *ppv = &This->IVideoWindow_vtbl; else if (IsEqualIID(riid, &IID_IMediaSeeking)) *ppv = &This->mediaSeeking; if (*ppv) { IUnknown_AddRef((IUnknown *)(*ppv)); return S_OK; } if (!IsEqualIID(riid, &IID_IPin)) FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); return E_NOINTERFACE; } static ULONG WINAPI VideoRendererInner_AddRef(IUnknown * iface) { ICOM_THIS_MULTI(VideoRendererImpl, IInner_vtbl, iface); ULONG refCount = InterlockedIncrement(&This->refCount); TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1); return refCount; } static ULONG WINAPI VideoRendererInner_Release(IUnknown * iface) { ICOM_THIS_MULTI(VideoRendererImpl, IInner_vtbl, iface); ULONG refCount = InterlockedDecrement(&This->refCount); TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1); if (!refCount) { IPin *pConnectedTo; DestroyWindow(This->hWnd); PostThreadMessageA(This->ThreadID, WM_QUIT, 0, 0); WaitForSingleObject(This->hThread, INFINITE); CloseHandle(This->hThread); CloseHandle(This->hEvent); if (This->pClock) IReferenceClock_Release(This->pClock); if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo))) { IPin_Disconnect(pConnectedTo); IPin_Release(pConnectedTo); } IPin_Disconnect((IPin *)This->pInputPin); IPin_Release((IPin *)This->pInputPin); This->lpVtbl = NULL; This->csFilter.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->csFilter); TRACE("Destroying Video Renderer\n"); CoTaskMemFree(This); return 0; } else return refCount; } static const IUnknownVtbl IInner_VTable = { VideoRendererInner_QueryInterface, VideoRendererInner_AddRef, VideoRendererInner_Release }; static HRESULT WINAPI VideoRenderer_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) { VideoRendererImpl *This = (VideoRendererImpl *)iface; if (This->bAggregatable) This->bUnkOuterValid = TRUE; if (This->pUnkOuter) { if (This->bAggregatable) return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv); if (IsEqualIID(riid, &IID_IUnknown)) { HRESULT hr; IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl)); hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv); IUnknown_Release((IUnknown *)&(This->IInner_vtbl)); This->bAggregatable = TRUE; return hr; } *ppv = NULL; return E_NOINTERFACE; } return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv); } static ULONG WINAPI VideoRenderer_AddRef(IBaseFilter * iface) { VideoRendererImpl *This = (VideoRendererImpl *)iface; if (This->pUnkOuter && This->bUnkOuterValid) return IUnknown_AddRef(This->pUnkOuter); return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl)); } static ULONG WINAPI VideoRenderer_Release(IBaseFilter * iface) { VideoRendererImpl *This = (VideoRendererImpl *)iface; if (This->pUnkOuter && This->bUnkOuterValid) return IUnknown_Release(This->pUnkOuter); return IUnknown_Release((IUnknown *)&(This->IInner_vtbl)); } /** IPersist methods **/ static HRESULT WINAPI VideoRenderer_GetClassID(IBaseFilter * iface, CLSID * pClsid) { VideoRendererImpl *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) { VideoRendererImpl *This = (VideoRendererImpl *)iface; TRACE("(%p/%p)->()\n", This, iface); EnterCriticalSection(&This->csFilter); { This->state = State_Stopped; SetEvent(This->hEvent); SetEvent(This->blocked); } LeaveCriticalSection(&This->csFilter); return S_OK; } static HRESULT WINAPI VideoRenderer_Pause(IBaseFilter * iface) { VideoRendererImpl *This = (VideoRendererImpl *)iface; TRACE("(%p/%p)->()\n", This, iface); EnterCriticalSection(&This->csFilter); if (This->state != State_Paused) { if (This->state == State_Stopped) { This->pInputPin->end_of_stream = 0; ResetEvent(This->hEvent); } This->state = State_Paused; ResetEvent(This->blocked); } LeaveCriticalSection(&This->csFilter); return S_OK; } static HRESULT WINAPI VideoRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tStart) { VideoRendererImpl *This = (VideoRendererImpl *)iface; TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart)); EnterCriticalSection(&This->csFilter); if (This->state != State_Running) { if (This->state == State_Stopped) { This->pInputPin->end_of_stream = 0; ResetEvent(This->hEvent); } SetEvent(This->blocked); 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) { VideoRendererImpl *This = (VideoRendererImpl *)iface; HRESULT hr; TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState); if (WaitForSingleObject(This->hEvent, dwMilliSecsTimeout) == WAIT_TIMEOUT) hr = VFW_S_STATE_INTERMEDIATE; else hr = S_OK; EnterCriticalSection(&This->csFilter); { *pState = This->state; } LeaveCriticalSection(&This->csFilter); return hr; } static HRESULT WINAPI VideoRenderer_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) { VideoRendererImpl *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) { VideoRendererImpl *This = (VideoRendererImpl *)iface; TRACE("(%p/%p)->(%p)\n", This, iface, ppClock); EnterCriticalSection(&This->csFilter); { *ppClock = This->pClock; if (This->pClock) IReferenceClock_AddRef(This->pClock); } LeaveCriticalSection(&This->csFilter); return S_OK; } /** IBaseFilter implementation **/ static HRESULT VideoRenderer_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick) { VideoRendererImpl *This = (VideoRendererImpl *)iface; /* Our pins are static, not changing so setting static tick count is ok */ *lastsynctick = 0; if (pos >= 1) return S_FALSE; *pin = (IPin *)This->pInputPin; IPin_AddRef(*pin); return S_OK; } static HRESULT WINAPI VideoRenderer_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum) { VideoRendererImpl *This = (VideoRendererImpl *)iface; TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); return IEnumPinsImpl_Construct(ppEnum, VideoRenderer_GetPin, iface); } static HRESULT WINAPI VideoRenderer_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin) { VideoRendererImpl *This = (VideoRendererImpl *)iface; FIXME("(%p/%p)->(%p,%p): stub !!!\n", This, iface, debugstr_w(Id), ppPin); /* FIXME: critical section */ return E_NOTIMPL; } static HRESULT WINAPI VideoRenderer_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo) { VideoRendererImpl *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) { VideoRendererImpl *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) { VideoRendererImpl *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 HRESULT WINAPI VideoRenderer_InputPin_EndOfStream(IPin * iface) { InputPin* This = (InputPin*)iface; IMediaEventSink* pEventSink; HRESULT hr; TRACE("(%p/%p)->()\n", This, iface); hr = IFilterGraph_QueryInterface(((VideoRendererImpl*)This->pin.pinInfo.pFilter)->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink); if (SUCCEEDED(hr)) { hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0); IMediaEventSink_Release(pEventSink); } return hr; } static HRESULT WINAPI VideoRenderer_InputPin_BeginFlush(IPin * iface) { InputPin* This = (InputPin*)iface; VideoRendererImpl *pVideoRenderer = (VideoRendererImpl *)This->pin.pinInfo.pFilter; HRESULT hr; TRACE("(%p/%p)->()\n", This, iface); EnterCriticalSection(This->pin.pCritSec); if (pVideoRenderer->state == State_Paused) SetEvent(pVideoRenderer->blocked); hr = InputPin_BeginFlush(iface); LeaveCriticalSection(This->pin.pCritSec); return hr; } static HRESULT WINAPI VideoRenderer_InputPin_EndFlush(IPin * iface) { InputPin* This = (InputPin*)iface; VideoRendererImpl *pVideoRenderer = (VideoRendererImpl *)This->pin.pinInfo.pFilter; HRESULT hr; TRACE("(%p/%p)->()\n", This, iface); EnterCriticalSection(This->pin.pCritSec); if (pVideoRenderer->state == State_Paused) ResetEvent(pVideoRenderer->blocked); hr = InputPin_EndFlush(iface); LeaveCriticalSection(This->pin.pCritSec); return hr; } 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, VideoRenderer_InputPin_EndOfStream, VideoRenderer_InputPin_BeginFlush, VideoRenderer_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); FIXME("(%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); FIXME("(%p/%p)->(%d, %d, %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); FIXME("(%p/%p)->(%s (%p), %p, %d, %d, %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); FIXME("(%p/%p)->(%d, %s (%p), %d, %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); FIXME("(%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); FIXME("(%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); FIXME("(%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)\n", This, iface, pVideoWidth); *pVideoWidth = This->VideoWidth; return S_OK; } static HRESULT WINAPI Basicvideo_get_VideoHeight(IBasicVideo *iface, LONG *pVideoHeight) { ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); TRACE("(%p/%p)->(%p)\n", This, iface, pVideoHeight); *pVideoHeight = This->VideoHeight; return S_OK; } static HRESULT WINAPI Basicvideo_put_SourceLeft(IBasicVideo *iface, LONG SourceLeft) { ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); TRACE("(%p/%p)->(%d)\n", This, iface, SourceLeft); This->SourceRect.left = 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)\n", This, iface, pSourceLeft); *pSourceLeft = This->SourceRect.left; return S_OK; } static HRESULT WINAPI Basicvideo_put_SourceWidth(IBasicVideo *iface, LONG SourceWidth) { ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); TRACE("(%p/%p)->(%d)\n", This, iface, SourceWidth); This->SourceRect.right = This->SourceRect.left + 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)\n", This, iface, pSourceWidth); *pSourceWidth = This->SourceRect.right - This->SourceRect.left; return S_OK; } static HRESULT WINAPI Basicvideo_put_SourceTop(IBasicVideo *iface, LONG SourceTop) { ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); TRACE("(%p/%p)->(%d)\n", This, iface, SourceTop); This->SourceRect.top = 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)\n", This, iface, pSourceTop); *pSourceTop = This->SourceRect.top; return S_OK; } static HRESULT WINAPI Basicvideo_put_SourceHeight(IBasicVideo *iface, LONG SourceHeight) { ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); TRACE("(%p/%p)->(%d)\n", This, iface, SourceHeight); This->SourceRect.bottom = This->SourceRect.top + 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)\n", This, iface, pSourceHeight); *pSourceHeight = This->SourceRect.bottom - This->SourceRect.top; return S_OK; } static HRESULT WINAPI Basicvideo_put_DestinationLeft(IBasicVideo *iface, LONG DestinationLeft) { ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); TRACE("(%p/%p)->(%d)\n", This, iface, DestinationLeft); This->DestRect.left = 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)\n", This, iface, pDestinationLeft); *pDestinationLeft = This->DestRect.left; return S_OK; } static HRESULT WINAPI Basicvideo_put_DestinationWidth(IBasicVideo *iface, LONG DestinationWidth) { ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); TRACE("(%p/%p)->(%d)\n", This, iface, DestinationWidth); This->DestRect.right = This->DestRect.left + 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)\n", This, iface, pDestinationWidth); *pDestinationWidth = This->DestRect.right - This->DestRect.left; return S_OK; } static HRESULT WINAPI Basicvideo_put_DestinationTop(IBasicVideo *iface, LONG DestinationTop) { ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); TRACE("(%p/%p)->(%d)\n", This, iface, DestinationTop); This->DestRect.top = 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)\n", This, iface, pDestinationTop); *pDestinationTop = This->DestRect.top; return S_OK; } static HRESULT WINAPI Basicvideo_put_DestinationHeight(IBasicVideo *iface, LONG DestinationHeight) { ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); TRACE("(%p/%p)->(%d)\n", This, iface, DestinationHeight); This->DestRect.right = This->DestRect.left + 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)\n", This, iface, pDestinationHeight); *pDestinationHeight = This->DestRect.right - This->DestRect.left; 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)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height); This->SourceRect.left = Left; This->SourceRect.top = Top; This->SourceRect.right = Left + Width; This->SourceRect.bottom = Top + 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)\n", This, iface, pLeft, pTop, pWidth, pHeight); *pLeft = This->SourceRect.left; *pTop = This->SourceRect.top; *pWidth = This->SourceRect.right - This->SourceRect.left; *pHeight = This->SourceRect.bottom - This->SourceRect.top; return S_OK; } static HRESULT WINAPI Basicvideo_SetDefaultSourcePosition(IBasicVideo *iface) { ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); TRACE("(%p/%p)->()\n", This, iface); This->SourceRect.left = 0; This->SourceRect.top = 0; This->SourceRect.right = This->VideoWidth; This->SourceRect.bottom = This->VideoHeight; 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)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height); This->DestRect.left = Left; This->DestRect.top = Top; This->DestRect.right = Left + Width; This->DestRect.bottom = Top + 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)\n", This, iface, pLeft, pTop, pWidth, pHeight); *pLeft = This->DestRect.left; *pTop = This->DestRect.top; *pWidth = This->DestRect.right - This->DestRect.left; *pHeight = This->DestRect.bottom - This->DestRect.top; return S_OK; } static HRESULT WINAPI Basicvideo_SetDefaultDestinationPosition(IBasicVideo *iface) { ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); RECT rect; TRACE("(%p/%p)->()\n", This, iface); if (!GetClientRect(This->hWnd, &rect)) return E_FAIL; This->SourceRect.left = 0; This->SourceRect.top = 0; This->SourceRect.right = rect.right; This->SourceRect.bottom = rect.bottom; 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)\n", This, iface, pWidth, pHeight); *pWidth = This->VideoWidth; *pHeight = This->VideoHeight; 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); FIXME("(%p/%p)->(%d, %d, %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); BITMAPINFOHEADER *bmiHeader; LONG needed_size; AM_MEDIA_TYPE *amt = &This->pInputPin->pin.mtCurrent; char *ptr; FIXME("(%p/%p)->(%p, %p): partial stub\n", This, iface, pBufferSize, pDIBImage); EnterCriticalSection(&This->csFilter); if (!This->sample_held) { LeaveCriticalSection(&This->csFilter); return (This->state == State_Paused ? E_UNEXPECTED : VFW_E_NOT_PAUSED); } if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo)) { bmiHeader = &((VIDEOINFOHEADER *)amt->pbFormat)->bmiHeader; } else if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo2)) { bmiHeader = &((VIDEOINFOHEADER2 *)amt->pbFormat)->bmiHeader; } else { FIXME("Unknown type %s\n", debugstr_guid(&amt->subtype)); LeaveCriticalSection(&This->csFilter); return VFW_E_RUNTIME_ERROR; } needed_size = bmiHeader->biSize; needed_size += IMediaSample_GetActualDataLength(This->sample_held); if (!pDIBImage) { *pBufferSize = needed_size; LeaveCriticalSection(&This->csFilter); return S_OK; } if (needed_size < *pBufferSize) { ERR("Buffer too small %u/%u\n", needed_size, *pBufferSize); LeaveCriticalSection(&This->csFilter); return E_FAIL; } *pBufferSize = needed_size; memcpy(pDIBImage, bmiHeader, bmiHeader->biSize); IMediaSample_GetPointer(This->sample_held, (BYTE **)&ptr); memcpy((char *)pDIBImage + bmiHeader->biSize, ptr, IMediaSample_GetActualDataLength(This->sample_held)); LeaveCriticalSection(&This->csFilter); return S_OK; } static HRESULT WINAPI Basicvideo_IsUsingDefaultSource(IBasicVideo *iface) { ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); FIXME("(%p/%p)->(): stub !!!\n", This, iface); return S_OK; } static HRESULT WINAPI Basicvideo_IsUsingDefaultDestination(IBasicVideo *iface) { ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); FIXME("(%p/%p)->(): stub !!!\n", This, iface); return S_OK; } static const 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); FIXME("(%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); FIXME("(%p/%p)->(%d, %d, %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); FIXME("(%p/%p)->(%s (%p), %p, %d, %d, %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); FIXME("(%p/%p)->(%d, %s (%p), %d, %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))\n", This, iface, debugstr_w(strCaption), strCaption); if (!SetWindowTextW(This->hWnd, strCaption)) return E_FAIL; return S_OK; } static HRESULT WINAPI Videowindow_get_Caption(IVideoWindow *iface, BSTR *strCaption) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); TRACE("(%p/%p)->(%p)\n", This, iface, strCaption); GetWindowTextW(This->hWnd, (LPWSTR)strCaption, 100); return S_OK; } static HRESULT WINAPI Videowindow_put_WindowStyle(IVideoWindow *iface, LONG WindowStyle) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); LONG old; old = GetWindowLongA(This->hWnd, GWL_STYLE); TRACE("(%p/%p)->(%x -> %x)\n", This, iface, old, WindowStyle); if (WindowStyle & (WS_DISABLED|WS_HSCROLL|WS_ICONIC|WS_MAXIMIZE|WS_MINIMIZE|WS_VSCROLL)) return E_INVALIDARG; SetWindowLongA(This->hWnd, GWL_STYLE, 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)\n", This, iface, WindowStyle); *WindowStyle = GetWindowLongA(This->hWnd, GWL_STYLE); return S_OK; } static HRESULT WINAPI Videowindow_put_WindowStyleEx(IVideoWindow *iface, LONG WindowStyleEx) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); TRACE("(%p/%p)->(%d)\n", This, iface, WindowStyleEx); if (WindowStyleEx & (WS_DISABLED|WS_HSCROLL|WS_ICONIC|WS_MAXIMIZE|WS_MINIMIZE|WS_VSCROLL)) return E_INVALIDARG; if (!SetWindowLongA(This->hWnd, GWL_EXSTYLE, WindowStyleEx)) return E_FAIL; return S_OK; } static HRESULT WINAPI Videowindow_get_WindowStyleEx(IVideoWindow *iface, LONG *WindowStyleEx) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyleEx); *WindowStyleEx = GetWindowLongA(This->hWnd, GWL_EXSTYLE); return S_OK; } static HRESULT WINAPI Videowindow_put_AutoShow(IVideoWindow *iface, LONG AutoShow) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); TRACE("(%p/%p)->(%d)\n", This, iface, AutoShow); This->AutoShow = 1; /* FIXME: Should be 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)\n", This, iface, AutoShow); *AutoShow = This->AutoShow; return S_OK; } static HRESULT WINAPI Videowindow_put_WindowState(IVideoWindow *iface, LONG WindowState) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); FIXME("(%p/%p)->(%d): 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); FIXME("(%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); FIXME("(%p/%p)->(%d): 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); FIXME("(%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)->(%d)\n", This, iface, Visible); ShowWindow(This->hWnd, Visible ? SW_SHOW : SW_HIDE); return S_OK; } static HRESULT WINAPI Videowindow_get_Visible(IVideoWindow *iface, LONG *pVisible) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); TRACE("(%p/%p)->(%p)\n", This, iface, pVisible); *pVisible = IsWindowVisible(This->hWnd); return S_OK; } static HRESULT WINAPI Videowindow_put_Left(IVideoWindow *iface, LONG Left) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); TRACE("(%p/%p)->(%d)\n", This, iface, Left); if (!SetWindowPos(This->hWnd, NULL, Left, This->WindowPos.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE)) return E_FAIL; This->WindowPos.left = 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)\n", This, iface, pLeft); *pLeft = This->WindowPos.left; return S_OK; } static HRESULT WINAPI Videowindow_put_Width(IVideoWindow *iface, LONG Width) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); TRACE("(%p/%p)->(%d)\n", This, iface, Width); if (!SetWindowPos(This->hWnd, NULL, 0, 0, Width, This->WindowPos.bottom-This->WindowPos.top, SWP_NOZORDER|SWP_NOMOVE)) return E_FAIL; This->WindowPos.right = This->WindowPos.left + 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)\n", This, iface, pWidth); *pWidth = This->WindowPos.right - This->WindowPos.left; return S_OK; } static HRESULT WINAPI Videowindow_put_Top(IVideoWindow *iface, LONG Top) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); TRACE("(%p/%p)->(%d)\n", This, iface, Top); if (!SetWindowPos(This->hWnd, NULL, This->WindowPos.left, Top, 0, 0, SWP_NOZORDER|SWP_NOSIZE)) return E_FAIL; This->WindowPos.top = 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)\n", This, iface, pTop); *pTop = This->WindowPos.top; return S_OK; } static HRESULT WINAPI Videowindow_put_Height(IVideoWindow *iface, LONG Height) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); TRACE("(%p/%p)->(%d)\n", This, iface, Height); if (!SetWindowPos(This->hWnd, NULL, 0, 0, This->WindowPos.right-This->WindowPos.left, Height, SWP_NOZORDER|SWP_NOMOVE)) return E_FAIL; This->WindowPos.bottom = This->WindowPos.top + 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)\n", This, iface, pHeight); *pHeight = This->WindowPos.bottom - This->WindowPos.top; return S_OK; } static HRESULT WINAPI Videowindow_put_Owner(IVideoWindow *iface, OAHWND Owner) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Owner); SetParent(This->hWnd, (HWND)Owner); return S_OK; } static HRESULT WINAPI Videowindow_get_Owner(IVideoWindow *iface, OAHWND *Owner) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); TRACE("(%p/%p)->(%p)\n", This, iface, Owner); *(HWND*)Owner = GetParent(This->hWnd); return S_OK; } static HRESULT WINAPI Videowindow_put_MessageDrain(IVideoWindow *iface, OAHWND Drain) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Drain); This->hWndMsgDrain = (HWND)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)\n", This, iface, Drain); *Drain = (OAHWND)This->hWndMsgDrain; return S_OK; } static HRESULT WINAPI Videowindow_get_BorderColor(IVideoWindow *iface, LONG *Color) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); FIXME("(%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); FIXME("(%p/%p)->(%d): 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); FIXME("(%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); FIXME("(%p/%p)->(%d): stub !!!\n", This, iface, FullScreenMode); return S_OK; } static HRESULT WINAPI Videowindow_SetWindowForeground(IVideoWindow *iface, LONG Focus) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); BOOL ret; IPin* pPin; HRESULT hr; TRACE("(%p/%p)->(%d)\n", This, iface, Focus); if ((Focus != FALSE) && (Focus != TRUE)) return E_INVALIDARG; hr = IPin_ConnectedTo((IPin *)This->pInputPin, &pPin); if ((hr != S_OK) || !pPin) return VFW_E_NOT_CONNECTED; if (Focus) ret = SetForegroundWindow(This->hWnd); else ret = SetWindowPos(This->hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); if (!ret) return E_FAIL; 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, %d, %08lx, %08lx)\n", This, iface, hwnd, uMsg, wParam, lParam); if (!PostMessageA(This->hWnd, uMsg, wParam, lParam)) return E_FAIL; 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)->(%d, %d, %d, %d)\n", This, iface, Left, Top, Width, Height); if (!SetWindowPos(This->hWnd, NULL, Left, Top, Width, Height, SWP_NOZORDER)) return E_FAIL; This->WindowPos.left = Left; This->WindowPos.top = Top; This->WindowPos.right = Left + Width; This->WindowPos.bottom = Top + 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)\n", This, iface, pLeft, pTop, pWidth, pHeight); *pLeft = This->WindowPos.left; *pTop = This->WindowPos.top; *pWidth = This->WindowPos.right - This->WindowPos.left; *pHeight = This->WindowPos.bottom - This->WindowPos.top; return S_OK; } static HRESULT WINAPI Videowindow_GetMinIdealImageSize(IVideoWindow *iface, LONG *pWidth, LONG *pHeight) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); FIXME("(%p/%p)->(%p, %p): semi stub !!!\n", This, iface, pWidth, pHeight); *pWidth = This->VideoWidth; *pHeight = This->VideoHeight; return S_OK; } static HRESULT WINAPI Videowindow_GetMaxIdealImageSize(IVideoWindow *iface, LONG *pWidth, LONG *pHeight) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); FIXME("(%p/%p)->(%p, %p): semi stub !!!\n", This, iface, pWidth, pHeight); *pWidth = This->VideoWidth; *pHeight = This->VideoHeight; 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); FIXME("(%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); FIXME("(%p/%p)->(%d): stub !!!\n", This, iface, HideCursor); return S_OK; } static HRESULT WINAPI Videowindow_IsCursorHidden(IVideoWindow *iface, LONG *CursorHidden) { ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, CursorHidden); return S_OK; } static const 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 };