| /* | 
 |  * 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; | 
 | static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl; | 
 | static const IQualityControlVtbl VideoRenderer_QualityControl_Vtbl = { | 
 |     QualityControlImpl_QueryInterface, | 
 |     QualityControlImpl_AddRef, | 
 |     QualityControlImpl_Release, | 
 |     QualityControlImpl_Notify, | 
 |     QualityControlImpl_SetSink | 
 | }; | 
 |  | 
 | typedef struct VideoRendererImpl | 
 | { | 
 |     BaseFilter filter; | 
 |     const IBasicVideoVtbl * IBasicVideo_vtbl; | 
 |     const IVideoWindowVtbl * IVideoWindow_vtbl; | 
 |     const IUnknownVtbl * IInner_vtbl; | 
 |     const IAMFilterMiscFlagsVtbl *IAMFilterMiscFlags_vtbl; | 
 |     IUnknown *seekthru_unk; | 
 |     QualityControlImpl qcimpl; | 
 |  | 
 |     BaseInputPin *pInputPin; | 
 |  | 
 |     BOOL init; | 
 |     HANDLE hThread; | 
 |     HANDLE blocked; | 
 |  | 
 |     DWORD ThreadID; | 
 |     HANDLE hEvent; | 
 |     BOOL ThreadResult; | 
 |     HWND hWnd; | 
 |     HWND hWndMsgDrain; | 
 |     HWND hWndOwner; | 
 |     BOOL AutoShow; | 
 |     RECT SourceRect; | 
 |     RECT DestRect; | 
 |     RECT WindowPos; | 
 |     LONG VideoWidth; | 
 |     LONG VideoHeight; | 
 |     IUnknown * pUnkOuter; | 
 |     BOOL bUnkOuterValid; | 
 |     BOOL bAggregatable; | 
 |     LONG WindowStyle; | 
 |  | 
 |     /* During pause we can hold a single sample, for use in GetCurrentImage */ | 
 |     IMediaSample *sample_held; | 
 | } VideoRendererImpl; | 
 |  | 
 | static LRESULT CALLBACK VideoWndProcW(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: | 
 |                 PostMessageW(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 DefWindowProcW(hwnd, uMsg, wParam, lParam); | 
 |     } | 
 |     return 0; | 
 | } | 
 |  | 
 | static const WCHAR classnameW[] = { 'W','i','n','e',' ','A','c','t','i','v','e','M','o','v','i','e',' ','C','l','a','s','s',0 }; | 
 | static const WCHAR windownameW[] = { 'A','c','t','i','v','e','M','o','v','i','e',' ','W','i','n','d','o','w',0 }; | 
 |  | 
 | static BOOL video_register_windowclass(void) { | 
 |     WNDCLASSW winclass; | 
 |     if (wnd_class_registered) | 
 |         return 1; | 
 |  | 
 |     winclass.style = 0; | 
 |     winclass.lpfnWndProc = VideoWndProcW; | 
 |     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 = classnameW; | 
 |     if (!RegisterClassW(&winclass)) | 
 |     { | 
 |         ERR("Unable to register window class: %u\n", GetLastError()); | 
 |         return FALSE; | 
 |     } | 
 |     wnd_class_registered = 1; | 
 |     return 1; | 
 | } | 
 |  | 
 | void video_unregister_windowclass(void) { | 
 |     if (!wnd_class_registered) | 
 |         return; | 
 |     UnregisterClassW(classnameW, NULL); | 
 | } | 
 |  | 
 | static BOOL CreateRenderingWindow(VideoRendererImpl* This) | 
 | { | 
 |     TRACE("(%p)->()\n", This); | 
 |     if (!video_register_windowclass()) | 
 |         return FALSE; | 
 |     This->hWnd = CreateWindowExW(0, classnameW, windownameW, 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 = GetMessageW(&msg, NULL, 0, 0)) != 0 && fGotMessage != -1) | 
 |     { | 
 |         TranslateMessage(&msg);  | 
 |         DispatchMessageW(&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 void VideoRenderer_AutoShowWindow(VideoRendererImpl *This) { | 
 |     if (!This->init && (!This->WindowPos.right || !This->WindowPos.top)) | 
 |     { | 
 |         DWORD style = GetWindowLongW(This->hWnd, GWL_STYLE); | 
 |         DWORD style_ex = GetWindowLongW(This->hWnd, GWL_EXSTYLE); | 
 |  | 
 |         if (!This->WindowPos.right) | 
 |         { | 
 |             This->WindowPos.left = This->SourceRect.left; | 
 |             This->WindowPos.right = This->SourceRect.right; | 
 |         } | 
 |         if (!This->WindowPos.bottom) | 
 |         { | 
 |             This->WindowPos.top = This->SourceRect.top; | 
 |             This->WindowPos.bottom = This->SourceRect.bottom; | 
 |         } | 
 |  | 
 |         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|SWP_DEFERERASE); | 
 |  | 
 |         GetClientRect(This->hWnd, &This->DestRect); | 
 |     } | 
 |     else if (!This->init) | 
 |         This->DestRect = This->WindowPos; | 
 |     This->init = TRUE; | 
 |     if (This->AutoShow) | 
 |         ShowWindow(This->hWnd, SW_SHOW); | 
 | } | 
 |  | 
 | 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); | 
 |  | 
 |     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); | 
 |  | 
 |     return S_OK; | 
 | } | 
 |  | 
 | static HRESULT WINAPI VideoRenderer_Receive(BaseInputPin* pin, IMediaSample * pSample) | 
 | { | 
 |     VideoRendererImpl *This = (VideoRendererImpl *)pin->pin.pinInfo.pFilter; | 
 |     LPBYTE pbSrcStream = NULL; | 
 |     LONG cbSrcStream = 0; | 
 |     REFERENCE_TIME tStart, tStop; | 
 |     HRESULT hr; | 
 |  | 
 |     TRACE("(%p)->(%p)\n", pin, pSample); | 
 |  | 
 |     EnterCriticalSection(&This->filter.csFilter); | 
 |  | 
 |     if (This->pInputPin->flushing || This->pInputPin->end_of_stream) | 
 |     { | 
 |         LeaveCriticalSection(&This->filter.csFilter); | 
 |         return S_FALSE; | 
 |     } | 
 |  | 
 |     if (This->filter.state == State_Stopped) | 
 |     { | 
 |         LeaveCriticalSection(&This->filter.csFilter); | 
 |         return VFW_E_WRONG_STATE; | 
 |     } | 
 |  | 
 |     if (IMediaSample_GetMediaTime(pSample, &tStart, &tStop) == S_OK) | 
 |         MediaSeekingPassThru_RegisterMediaTime(This->seekthru_unk, tStart); | 
 |  | 
 |     /* Preroll means the sample isn't shown, this is used for key frames and things like that */ | 
 |     if (IMediaSample_IsPreroll(pSample) == S_OK) { | 
 |         LeaveCriticalSection(&This->filter.csFilter); | 
 |         return S_OK; | 
 |     } | 
 |  | 
 |     hr = IMediaSample_GetPointer(pSample, &pbSrcStream); | 
 |     if (FAILED(hr)) | 
 |     { | 
 |         ERR("Cannot get pointer to sample data (%x)\n", hr); | 
 |         LeaveCriticalSection(&This->filter.csFilter); | 
 |         return hr; | 
 |     } | 
 |  | 
 |     cbSrcStream = IMediaSample_GetActualDataLength(pSample); | 
 |  | 
 |     TRACE("val %p %d\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->filter.state == State_Paused) | 
 |     { | 
 |         VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream); | 
 |         This->sample_held = pSample; | 
 |         LeaveCriticalSection(&This->filter.csFilter); | 
 |         WaitForSingleObject(This->blocked, INFINITE); | 
 |         EnterCriticalSection(&This->filter.csFilter); | 
 |         SetEvent(This->hEvent); | 
 |         This->sample_held = NULL; | 
 |         if (This->filter.state == State_Paused) | 
 |         { | 
 |             /* Flushing */ | 
 |             LeaveCriticalSection(&This->filter.csFilter); | 
 |             return S_OK; | 
 |         } | 
 |         if (This->filter.state == State_Stopped) | 
 |         { | 
 |             LeaveCriticalSection(&This->filter.csFilter); | 
 |             return VFW_E_WRONG_STATE; | 
 |         } | 
 |     } else { | 
 |         hr = QualityControlRender_WaitFor(&This->qcimpl, pSample, This->blocked); | 
 |         if (hr == S_OK) { | 
 |             QualityControlRender_BeginRender(&This->qcimpl); | 
 |             VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream); | 
 |             QualityControlRender_EndRender(&This->qcimpl); | 
 |         } | 
 |         QualityControlRender_DoQOS(&This->qcimpl); | 
 |     } | 
 |     LeaveCriticalSection(&This->filter.csFilter); | 
 |     return S_OK; | 
 | } | 
 |  | 
 | static HRESULT WINAPI VideoRenderer_CheckMediaType(BasePin *iface, const AM_MEDIA_TYPE * pmt) | 
 | { | 
 |     BaseInputPin* pin = (BaseInputPin*)iface; | 
 |     VideoRendererImpl *This = (VideoRendererImpl *)pin->pin.pinInfo.pFilter; | 
 |  | 
 |     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)) | 
 |     { | 
 |         LONG height; | 
 |  | 
 |         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; | 
 |             height = format->bmiHeader.biHeight; | 
 |             if (height < 0) | 
 |                 This->SourceRect.bottom = This->VideoHeight = -height; | 
 |             else | 
 |                 This->SourceRect.bottom = This->VideoHeight = height; | 
 |         } | 
 |         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; | 
 |             height = format2->bmiHeader.biHeight; | 
 |             if (height < 0) | 
 |                 This->SourceRect.bottom = This->VideoHeight = -height; | 
 |             else | 
 |                 This->SourceRect.bottom = This->VideoHeight = height; | 
 |         } | 
 |         else | 
 |         { | 
 |             WARN("Format type %s not supported\n", debugstr_guid(&pmt->formattype)); | 
 |             return S_FALSE; | 
 |         } | 
 |         return S_OK; | 
 |     } | 
 |     return S_FALSE; | 
 | } | 
 |  | 
 | static IPin* WINAPI VideoRenderer_GetPin(BaseFilter *iface, int pos) | 
 | { | 
 |     VideoRendererImpl *This = (VideoRendererImpl *)iface; | 
 |  | 
 |     if (pos >= 1 || pos < 0) | 
 |         return NULL; | 
 |  | 
 |     IPin_AddRef((IPin *)This->pInputPin); | 
 |     return (IPin *)This->pInputPin; | 
 | } | 
 |  | 
 | static LONG WINAPI VideoRenderer_GetPinCount(BaseFilter *iface) | 
 | { | 
 |     return 1; | 
 | } | 
 |  | 
 | static const BaseFilterFuncTable BaseFuncTable = { | 
 |     VideoRenderer_GetPin, | 
 |     VideoRenderer_GetPinCount | 
 | }; | 
 |  | 
 | static const  BasePinFuncTable input_BaseFuncTable = { | 
 |     VideoRenderer_CheckMediaType, | 
 |     NULL, | 
 |     BasePinImpl_GetMediaTypeVersion, | 
 |     BasePinImpl_GetMediaType | 
 | }; | 
 |  | 
 | static const BaseInputPinFuncTable input_BaseInputFuncTable = { | 
 |     VideoRenderer_Receive | 
 | }; | 
 |  | 
 | HRESULT VideoRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv) | 
 | { | 
 |     HRESULT hr; | 
 |     PIN_INFO piInput; | 
 |     VideoRendererImpl * pVideoRenderer; | 
 |     ISeekingPassThru *passthru; | 
 |  | 
 |     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->IAMFilterMiscFlags_vtbl = &IAMFilterMiscFlags_Vtbl; | 
 |  | 
 |     BaseFilter_Init(&pVideoRenderer->filter, &VideoRenderer_Vtbl, &CLSID_VideoRenderer, (DWORD_PTR)(__FILE__ ": VideoRendererImpl.csFilter"), &BaseFuncTable); | 
 |  | 
 |     pVideoRenderer->IBasicVideo_vtbl = &IBasicVideo_VTable; | 
 |     pVideoRenderer->IVideoWindow_vtbl = &IVideoWindow_VTable; | 
 |  | 
 |     pVideoRenderer->init = 0; | 
 |     pVideoRenderer->AutoShow = 1; | 
 |     ZeroMemory(&pVideoRenderer->SourceRect, sizeof(RECT)); | 
 |     ZeroMemory(&pVideoRenderer->DestRect, sizeof(RECT)); | 
 |     ZeroMemory(&pVideoRenderer->WindowPos, sizeof(RECT)); | 
 |     pVideoRenderer->hWndMsgDrain = pVideoRenderer->hWndOwner = NULL; | 
 |     pVideoRenderer->WindowStyle = WS_OVERLAPPED; | 
 |  | 
 |     /* construct input pin */ | 
 |     piInput.dir = PINDIR_INPUT; | 
 |     piInput.pFilter = (IBaseFilter *)pVideoRenderer; | 
 |     lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0])); | 
 |  | 
 |     hr = BaseInputPin_Construct(&VideoRenderer_InputPin_Vtbl, &piInput, &input_BaseFuncTable, &input_BaseInputFuncTable, &pVideoRenderer->filter.csFilter, NULL, (IPin **)&pVideoRenderer->pInputPin); | 
 |  | 
 |     if (SUCCEEDED(hr)) | 
 |     { | 
 |         hr = CoCreateInstance(&CLSID_SeekingPassThru, pUnkOuter ? pUnkOuter : (IUnknown*)&pVideoRenderer->IInner_vtbl, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&pVideoRenderer->seekthru_unk); | 
 |         if (FAILED(hr)) { | 
 |             IPin_Release((IPin*)pVideoRenderer->pInputPin); | 
 |             goto fail; | 
 |         } | 
 |         IUnknown_QueryInterface(pVideoRenderer->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru); | 
 |         ISeekingPassThru_Init(passthru, TRUE, (IPin*)pVideoRenderer->pInputPin); | 
 |         ISeekingPassThru_Release(passthru); | 
 |         pVideoRenderer->sample_held = NULL; | 
 |         *ppv = pVideoRenderer; | 
 |     } | 
 |     if (FAILED(hr)) | 
 |         goto fail; | 
 |  | 
 |     QualityControlImpl_init(&pVideoRenderer->qcimpl, (IPin*)pVideoRenderer->pInputPin, (IBaseFilter*)pVideoRenderer); | 
 |     pVideoRenderer->qcimpl.lpVtbl = &VideoRenderer_QualityControl_Vtbl; | 
 |  | 
 |     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; | 
 | fail: | 
 |     BaseFilterImpl_Release((IBaseFilter*)pVideoRenderer); | 
 |     CoTaskMemFree(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)) | 
 |         return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv); | 
 |     else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags)) | 
 |         *ppv = &This->IAMFilterMiscFlags_vtbl; | 
 |     else if (IsEqualIID(riid, &IID_IQualityControl)) | 
 |         *ppv = &This->qcimpl; | 
 |  | 
 |     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->filter.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->filter.refCount); | 
 |  | 
 |     TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1); | 
 |  | 
 |     if (!refCount) | 
 |     { | 
 |         IPin *pConnectedTo; | 
 |  | 
 |         if (This->hWnd) | 
 |             SendMessageW(This->hWnd, WM_CLOSE, 0, 0); | 
 |         PostThreadMessageW(This->ThreadID, WM_QUIT, 0, 0); | 
 |         WaitForSingleObject(This->hThread, INFINITE); | 
 |         CloseHandle(This->hThread); | 
 |         CloseHandle(This->hEvent); | 
 |  | 
 |         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->filter.lpVtbl = NULL; | 
 |         IUnknown_Release(This->seekthru_unk); | 
 |         This->filter.csFilter.DebugInfo->Spare[0] = 0; | 
 |         DeleteCriticalSection(&This->filter.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)); | 
 | } | 
 |  | 
 | /** IMediaFilter methods **/ | 
 |  | 
 | static HRESULT WINAPI VideoRenderer_Stop(IBaseFilter * iface) | 
 | { | 
 |     VideoRendererImpl *This = (VideoRendererImpl *)iface; | 
 |  | 
 |     TRACE("(%p/%p)->()\n", This, iface); | 
 |  | 
 |     EnterCriticalSection(&This->filter.csFilter); | 
 |     { | 
 |         This->filter.state = State_Stopped; | 
 |         SetEvent(This->hEvent); | 
 |         SetEvent(This->blocked); | 
 |         MediaSeekingPassThru_ResetMediaTime(This->seekthru_unk); | 
 |         if (This->AutoShow) | 
 |             /* Black it out */ | 
 |             RedrawWindow(This->hWnd, NULL, NULL, RDW_INVALIDATE|RDW_ERASE); | 
 |     } | 
 |     LeaveCriticalSection(&This->filter.csFilter); | 
 |  | 
 |     return S_OK; | 
 | } | 
 |  | 
 | static HRESULT WINAPI VideoRenderer_Pause(IBaseFilter * iface) | 
 | { | 
 |     VideoRendererImpl *This = (VideoRendererImpl *)iface; | 
 |      | 
 |     TRACE("(%p/%p)->()\n", This, iface); | 
 |  | 
 |     EnterCriticalSection(&This->filter.csFilter); | 
 |     if (This->filter.state != State_Paused) | 
 |     { | 
 |         if (This->filter.state == State_Stopped) | 
 |         { | 
 |             This->pInputPin->end_of_stream = 0; | 
 |             ResetEvent(This->hEvent); | 
 |             VideoRenderer_AutoShowWindow(This); | 
 |         } | 
 |  | 
 |         This->filter.state = State_Paused; | 
 |         ResetEvent(This->blocked); | 
 |     } | 
 |     LeaveCriticalSection(&This->filter.csFilter); | 
 |  | 
 |     return S_OK; | 
 | } | 
 |  | 
 | static HRESULT WINAPI VideoRenderer_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock) { | 
 |     VideoRendererImpl *This = (VideoRendererImpl *)iface; | 
 |     HRESULT hr; | 
 |  | 
 |     EnterCriticalSection(&This->filter.csFilter); | 
 |     QualityControlRender_SetClock(&This->qcimpl, clock); | 
 |     hr = BaseFilterImpl_SetSyncSource(iface, clock); | 
 |     LeaveCriticalSection(&This->filter.csFilter); | 
 |     return hr; | 
 | } | 
 |  | 
 | static HRESULT WINAPI VideoRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tStart) | 
 | { | 
 |     HRESULT hr = S_OK; | 
 |     VideoRendererImpl *This = (VideoRendererImpl *)iface; | 
 |  | 
 |     TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart)); | 
 |  | 
 |     EnterCriticalSection(&This->filter.csFilter); | 
 |     This->filter.rtStreamStart = tStart; | 
 |     if (This->filter.state == State_Running) | 
 |         goto out; | 
 |     QualityControlRender_Start(&This->qcimpl, tStart); | 
 |     if (This->pInputPin->pin.pConnectedTo && (This->filter.state == State_Stopped || !This->pInputPin->end_of_stream)) | 
 |     { | 
 |         if (This->filter.state == State_Stopped) | 
 |         { | 
 |             ResetEvent(This->hEvent); | 
 |             VideoRenderer_AutoShowWindow(This); | 
 |             This->pInputPin->end_of_stream = 0; | 
 |         } | 
 |         SetEvent(This->blocked); | 
 |     } else if (This->filter.filterInfo.pGraph) { | 
 |         IMediaEventSink *pEventSink; | 
 |         hr = IFilterGraph_QueryInterface(This->filter.filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink); | 
 |         if (SUCCEEDED(hr)) | 
 |         { | 
 |             hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, (LONG_PTR)This); | 
 |             IMediaEventSink_Release(pEventSink); | 
 |         } | 
 |         hr = S_OK; | 
 |     } | 
 |     if (SUCCEEDED(hr)) | 
 |         This->filter.state = State_Running; | 
 | out: | 
 |     LeaveCriticalSection(&This->filter.csFilter); | 
 |  | 
 |     return hr; | 
 | } | 
 |  | 
 | 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; | 
 |  | 
 |     BaseFilterImpl_GetState(iface, dwMilliSecsTimeout, pState); | 
 |  | 
 |     return hr; | 
 | } | 
 |  | 
 | /** IBaseFilter implementation **/ | 
 |  | 
 | 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 const IBaseFilterVtbl VideoRenderer_Vtbl = | 
 | { | 
 |     VideoRenderer_QueryInterface, | 
 |     VideoRenderer_AddRef, | 
 |     VideoRenderer_Release, | 
 |     BaseFilterImpl_GetClassID, | 
 |     VideoRenderer_Stop, | 
 |     VideoRenderer_Pause, | 
 |     VideoRenderer_Run, | 
 |     VideoRenderer_GetState, | 
 |     VideoRenderer_SetSyncSource, | 
 |     BaseFilterImpl_GetSyncSource, | 
 |     BaseFilterImpl_EnumPins, | 
 |     VideoRenderer_FindPin, | 
 |     BaseFilterImpl_QueryFilterInfo, | 
 |     BaseFilterImpl_JoinFilterGraph, | 
 |     BaseFilterImpl_QueryVendorInfo | 
 | }; | 
 |  | 
 | static HRESULT WINAPI VideoRenderer_InputPin_EndOfStream(IPin * iface) | 
 | { | 
 |     BaseInputPin* This = (BaseInputPin*)iface; | 
 |     VideoRendererImpl *pFilter; | 
 |     IMediaEventSink* pEventSink; | 
 |     HRESULT hr = S_OK; | 
 |  | 
 |     TRACE("(%p/%p)->()\n", This, iface); | 
 |  | 
 |     EnterCriticalSection(This->pin.pCritSec); | 
 |     pFilter = (VideoRendererImpl*)This->pin.pinInfo.pFilter; | 
 |     if (This->flushing || This->end_of_stream) | 
 |         goto out; | 
 |     hr = IFilterGraph_QueryInterface(pFilter->filter.filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink); | 
 |     if (SUCCEEDED(hr)) | 
 |     { | 
 |         hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, (LONG_PTR)pFilter); | 
 |         IMediaEventSink_Release(pEventSink); | 
 |     } | 
 |     MediaSeekingPassThru_EOS(pFilter->seekthru_unk); | 
 |     This->end_of_stream = 1; | 
 | out: | 
 |     LeaveCriticalSection(This->pin.pCritSec); | 
 |  | 
 |     return hr; | 
 | } | 
 |  | 
 | static HRESULT WINAPI VideoRenderer_InputPin_BeginFlush(IPin * iface) | 
 | { | 
 |     BaseInputPin* This = (BaseInputPin*)iface; | 
 |     VideoRendererImpl *pVideoRenderer = (VideoRendererImpl *)This->pin.pinInfo.pFilter; | 
 |  | 
 |     TRACE("(%p/%p)->()\n", This, iface); | 
 |  | 
 |     SetEvent(pVideoRenderer->blocked); | 
 |     return BaseInputPinImpl_BeginFlush(iface); | 
 | } | 
 |  | 
 | static HRESULT WINAPI VideoRenderer_InputPin_EndFlush(IPin * iface) | 
 | { | 
 |     BaseInputPin* This = (BaseInputPin*)iface; | 
 |     VideoRendererImpl *pVideoRenderer = (VideoRendererImpl *)This->pin.pinInfo.pFilter; | 
 |     HRESULT hr; | 
 |  | 
 |     TRACE("(%p/%p)->()\n", This, iface); | 
 |  | 
 |     EnterCriticalSection(This->pin.pCritSec); | 
 |  | 
 |     if (pVideoRenderer->sample_held) { | 
 |         SetEvent(pVideoRenderer->blocked); | 
 |         ResetEvent(pVideoRenderer->hEvent); | 
 |         LeaveCriticalSection(This->pin.pCritSec); | 
 |         WaitForSingleObject(pVideoRenderer->hEvent, INFINITE); | 
 |         EnterCriticalSection(This->pin.pCritSec); | 
 |         ResetEvent(pVideoRenderer->blocked); | 
 |     } | 
 |     if (pVideoRenderer->filter.state == State_Paused) { | 
 |         ResetEvent(pVideoRenderer->blocked); | 
 |         ResetEvent(pVideoRenderer->hEvent); | 
 |     } | 
 |  | 
 |     QualityControlRender_Start(&pVideoRenderer->qcimpl, pVideoRenderer->filter.rtStreamStart); | 
 |     hr = BaseInputPinImpl_EndFlush(iface); | 
 |     LeaveCriticalSection(This->pin.pCritSec); | 
 |     MediaSeekingPassThru_ResetMediaTime(pVideoRenderer->seekthru_unk); | 
 |  | 
 |     return hr; | 
 | } | 
 |  | 
 | static const IPinVtbl VideoRenderer_InputPin_Vtbl =  | 
 | { | 
 |     BaseInputPinImpl_QueryInterface, | 
 |     BasePinImpl_AddRef, | 
 |     BaseInputPinImpl_Release, | 
 |     BaseInputPinImpl_Connect, | 
 |     BaseInputPinImpl_ReceiveConnection, | 
 |     BasePinImpl_Disconnect, | 
 |     BasePinImpl_ConnectedTo, | 
 |     BasePinImpl_ConnectionMediaType, | 
 |     BasePinImpl_QueryPinInfo, | 
 |     BasePinImpl_QueryDirection, | 
 |     BasePinImpl_QueryId, | 
 |     BaseInputPinImpl_QueryAccept, | 
 |     BasePinImpl_EnumMediaTypes, | 
 |     BasePinImpl_QueryInternalConnections, | 
 |     VideoRenderer_InputPin_EndOfStream, | 
 |     VideoRenderer_InputPin_BeginFlush, | 
 |     VideoRenderer_InputPin_EndFlush, | 
 |     BaseInputPinImpl_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) { | 
 |     AM_MEDIA_TYPE *pmt; | 
 |     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface); | 
 |  | 
 |     if (!This->pInputPin->pin.pConnectedTo) | 
 |         return VFW_E_NOT_CONNECTED; | 
 |  | 
 |     TRACE("(%p/%p)->(%p)\n", This, iface, pAvgTimePerFrame); | 
 |  | 
 |     pmt = &This->pInputPin->pin.mtCurrent; | 
 |     if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) { | 
 |         VIDEOINFOHEADER *vih = (VIDEOINFOHEADER*)pmt->pbFormat; | 
 |         *pAvgTimePerFrame = vih->AvgTimePerFrame; | 
 |     } else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2)) { | 
 |         VIDEOINFOHEADER2 *vih = (VIDEOINFOHEADER2*)pmt->pbFormat; | 
 |         *pAvgTimePerFrame = vih->AvgTimePerFrame; | 
 |     } else { | 
 |         ERR("Unknown format type %s\n", qzdebugstr_guid(&pmt->formattype)); | 
 |         *pAvgTimePerFrame = 0; | 
 |     } | 
 |     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); | 
 |  | 
 |     TRACE("(%p/%p)->(%d, %d, %p, %p)\n", This, iface, StartIndex, Entries, pRetrieved, pPalette); | 
 |  | 
 |     if (pRetrieved) | 
 |         *pRetrieved = 0; | 
 |     return VFW_E_NO_PALETTE_AVAILABLE; | 
 | } | 
 |  | 
 | 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->filter.csFilter); | 
 |  | 
 |     if (!This->sample_held) | 
 |     { | 
 |          LeaveCriticalSection(&This->filter.csFilter); | 
 |          return (This->filter.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->filter.csFilter); | 
 |         return VFW_E_RUNTIME_ERROR; | 
 |     } | 
 |  | 
 |     needed_size = bmiHeader->biSize; | 
 |     needed_size += IMediaSample_GetActualDataLength(This->sample_held); | 
 |  | 
 |     if (!pDIBImage) | 
 |     { | 
 |         *pBufferSize = needed_size; | 
 |         LeaveCriticalSection(&This->filter.csFilter); | 
 |         return S_OK; | 
 |     } | 
 |  | 
 |     if (needed_size < *pBufferSize) | 
 |     { | 
 |         ERR("Buffer too small %u/%u\n", needed_size, *pBufferSize); | 
 |         LeaveCriticalSection(&This->filter.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->filter.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 = GetWindowLongW(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; | 
 |  | 
 |     SetWindowLongW(This->hWnd, GWL_STYLE, WindowStyle); | 
 |     SetWindowPos(This->hWnd,0,0,0,0,0,SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOZORDER); | 
 |     This->WindowStyle = 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 = This->WindowStyle; | 
 |  | 
 |     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 (!SetWindowLongW(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 = GetWindowLongW(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 = 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); | 
 |  | 
 |     TRACE("(%p/%p)->(%d)\n", This, iface, WindowState); | 
 |     ShowWindow(This->hWnd, WindowState); | 
 |     return S_OK; | 
 | } | 
 |  | 
 | static HRESULT WINAPI Videowindow_get_WindowState(IVideoWindow *iface, | 
 |                                                   LONG *WindowState) { | 
 |     WINDOWPLACEMENT place; | 
 |     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface); | 
 |  | 
 |     place.length = sizeof(place); | 
 |     GetWindowPlacement(This->hWnd, &place); | 
 |     TRACE("(%p/%p)->(%p)\n", This, iface, WindowState); | 
 |     *WindowState = place.showCmd; | 
 |  | 
 |     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); | 
 |  | 
 |     This->hWndOwner = (HWND)Owner; | 
 |     SetParent(This->hWnd, This->hWndOwner); | 
 |     if (This->WindowStyle & WS_CHILD) | 
 |     { | 
 |         LONG old = GetWindowLongW(This->hWnd, GWL_STYLE); | 
 |         if (old != This->WindowStyle) | 
 |         { | 
 |             SetWindowLongW(This->hWnd, GWL_STYLE, This->WindowStyle); | 
 |             SetWindowPos(This->hWnd,0,0,0,0,0,SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOZORDER); | 
 |         } | 
 |     } | 
 |  | 
 |     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 = This->hWndOwner; | 
 |  | 
 |     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); | 
 |  | 
 |     if (FullScreenMode) { | 
 |         ShowWindow(This->hWnd, SW_HIDE); | 
 |         SetParent(This->hWnd, 0); | 
 |         SetWindowLongW(This->hWnd, GWL_STYLE, WS_POPUP); | 
 |         SetWindowPos(This->hWnd,HWND_TOP,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN),SWP_SHOWWINDOW); | 
 |         GetWindowRect(This->hWnd, &This->DestRect); | 
 |         This->WindowPos = This->DestRect; | 
 |     } else { | 
 |         ShowWindow(This->hWnd, SW_HIDE); | 
 |         SetParent(This->hWnd, This->hWndOwner); | 
 |         SetWindowLongW(This->hWnd, GWL_STYLE, This->WindowStyle); | 
 |         GetClientRect(This->hWnd, &This->DestRect); | 
 |         SetWindowPos(This->hWnd,0,This->DestRect.left,This->DestRect.top,This->DestRect.right,This->DestRect.bottom,SWP_NOZORDER|SWP_SHOWWINDOW); | 
 |         This->WindowPos = This->DestRect; | 
 |     } | 
 |  | 
 |     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 (!PostMessageW(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 | 
 | }; | 
 |  | 
 | static VideoRendererImpl *from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface) { | 
 |     return (VideoRendererImpl*)((char*)iface - offsetof(VideoRendererImpl, IAMFilterMiscFlags_vtbl)); | 
 | } | 
 |  | 
 | static HRESULT WINAPI AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, void **ppv) { | 
 |     VideoRendererImpl *This = from_IAMFilterMiscFlags(iface); | 
 |     return IUnknown_QueryInterface((IUnknown*)This, riid, ppv); | 
 | } | 
 |  | 
 | static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface) { | 
 |     VideoRendererImpl *This = from_IAMFilterMiscFlags(iface); | 
 |     return IUnknown_AddRef((IUnknown*)This); | 
 | } | 
 |  | 
 | static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface) { | 
 |     VideoRendererImpl *This = from_IAMFilterMiscFlags(iface); | 
 |     return IUnknown_Release((IUnknown*)This); | 
 | } | 
 |  | 
 | static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface) { | 
 |     return AM_FILTER_MISC_FLAGS_IS_RENDERER; | 
 | } | 
 |  | 
 | static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = { | 
 |     AMFilterMiscFlags_QueryInterface, | 
 |     AMFilterMiscFlags_AddRef, | 
 |     AMFilterMiscFlags_Release, | 
 |     AMFilterMiscFlags_GetMiscFlags | 
 | }; |