d3dx8: Add a few tests for MatrixStack.
[wine] / dlls / quartz / videorenderer.c
1 /*
2  * Video Renderer (Fullscreen and Windowed using Direct Draw)
3  *
4  * Copyright 2004 Christian Costa
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #define NONAMELESSSTRUCT
24 #define NONAMELESSUNION
25 #include "quartz_private.h"
26 #include "control_private.h"
27 #include "pin.h"
28
29 #include "uuids.h"
30 #include "vfwmsgs.h"
31 #include "amvideo.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "dshow.h"
35 #include "evcode.h"
36 #include "strmif.h"
37 #include "ddraw.h"
38 #include "dvdmedia.h"
39
40 #include <assert.h>
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
45
46 static BOOL wnd_class_registered = FALSE;
47
48 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
49
50 static const IBaseFilterVtbl VideoRenderer_Vtbl;
51 static const IUnknownVtbl IInner_VTable;
52 static const IBasicVideoVtbl IBasicVideo_VTable;
53 static const IVideoWindowVtbl IVideoWindow_VTable;
54 static const IPinVtbl VideoRenderer_InputPin_Vtbl;
55
56 typedef struct VideoRendererImpl
57 {
58     const IBaseFilterVtbl * lpVtbl;
59     const IBasicVideoVtbl * IBasicVideo_vtbl;
60     const IVideoWindowVtbl * IVideoWindow_vtbl;
61     const IUnknownVtbl * IInner_vtbl;
62
63     LONG refCount;
64     CRITICAL_SECTION csFilter;
65     FILTER_STATE state;
66     REFERENCE_TIME rtStreamStart;
67     IReferenceClock * pClock;
68     FILTER_INFO filterInfo;
69
70     InputPin *pInputPin;
71
72     BOOL init;
73     HANDLE hThread;
74     HANDLE blocked;
75
76     DWORD ThreadID;
77     HANDLE hEvent;
78     BOOL ThreadResult;
79     HWND hWnd;
80     HWND hWndMsgDrain;
81     BOOL AutoShow;
82     RECT SourceRect;
83     RECT DestRect;
84     RECT WindowPos;
85     long VideoWidth;
86     long VideoHeight;
87     IUnknown * pUnkOuter;
88     BOOL bUnkOuterValid;
89     BOOL bAggregatable;
90     REFERENCE_TIME rtLastStop;
91     MediaSeekingImpl mediaSeeking;
92
93     /* During pause we can hold a single sample, for use in GetCurrentImage */
94     IMediaSample *sample_held;
95 } VideoRendererImpl;
96
97 static LRESULT CALLBACK VideoWndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
98 {
99     VideoRendererImpl* pVideoRenderer = (VideoRendererImpl*)GetWindowLongA(hwnd, 0);
100     LPRECT lprect = (LPRECT)lParam;
101
102     if (pVideoRenderer && pVideoRenderer->hWndMsgDrain)
103     {
104         switch(uMsg)
105         {
106             case WM_KEYDOWN:
107             case WM_KEYUP:
108             case WM_LBUTTONDBLCLK:
109             case WM_LBUTTONDOWN:
110             case WM_LBUTTONUP:
111             case WM_MBUTTONDBLCLK:
112             case WM_MBUTTONDOWN:
113             case WM_MBUTTONUP:
114             case WM_MOUSEACTIVATE:
115             case WM_MOUSEMOVE:
116             case WM_NCLBUTTONDBLCLK:
117             case WM_NCLBUTTONDOWN:
118             case WM_NCLBUTTONUP:
119             case WM_NCMBUTTONDBLCLK:
120             case WM_NCMBUTTONDOWN:
121             case WM_NCMBUTTONUP:
122             case WM_NCMOUSEMOVE:
123             case WM_NCRBUTTONDBLCLK:
124             case WM_NCRBUTTONDOWN:
125             case WM_NCRBUTTONUP:
126             case WM_RBUTTONDBLCLK:
127             case WM_RBUTTONDOWN:
128             case WM_RBUTTONUP:
129                 PostMessageA(pVideoRenderer->hWndMsgDrain, uMsg, wParam, lParam);
130                 break;
131             default:
132                 break;
133         }
134     }
135
136     switch(uMsg)
137     {
138         case WM_SIZING:
139             /* TRACE("WM_SIZING %d %d %d %d\n", lprect->left, lprect->top, lprect->right, lprect->bottom); */
140             SetWindowPos(hwnd, NULL, lprect->left, lprect->top, lprect->right - lprect->left, lprect->bottom - lprect->top, SWP_NOZORDER);
141             GetClientRect(hwnd, &pVideoRenderer->DestRect);
142             TRACE("WM_SIZING: DestRect=(%d,%d),(%d,%d)\n",
143                 pVideoRenderer->DestRect.left,
144                 pVideoRenderer->DestRect.top,
145                 pVideoRenderer->DestRect.right - pVideoRenderer->DestRect.left,
146                 pVideoRenderer->DestRect.bottom - pVideoRenderer->DestRect.top);
147             return TRUE;
148         case WM_SIZE:
149             TRACE("WM_SIZE %d %d\n", LOWORD(lParam), HIWORD(lParam));
150             GetClientRect(hwnd, &pVideoRenderer->DestRect);
151             TRACE("WM_SIZING: DestRect=(%d,%d),(%d,%d)\n",
152                 pVideoRenderer->DestRect.left,
153                 pVideoRenderer->DestRect.top,
154                 pVideoRenderer->DestRect.right - pVideoRenderer->DestRect.left,
155                 pVideoRenderer->DestRect.bottom - pVideoRenderer->DestRect.top);
156             return TRUE;
157         default:
158             return DefWindowProcA(hwnd, uMsg, wParam, lParam);
159     }
160     return 0;
161 }
162
163 static BOOL CreateRenderingWindow(VideoRendererImpl* This)
164 {
165     WNDCLASSA winclass;
166
167     TRACE("(%p)->()\n", This);
168     
169     winclass.style = 0;
170     winclass.lpfnWndProc = VideoWndProcA;
171     winclass.cbClsExtra = 0;
172     winclass.cbWndExtra = sizeof(VideoRendererImpl*);
173     winclass.hInstance = NULL;
174     winclass.hIcon = NULL;
175     winclass.hCursor = NULL;
176     winclass.hbrBackground = GetStockObject(BLACK_BRUSH);
177     winclass.lpszMenuName = NULL;
178     winclass.lpszClassName = "Wine ActiveMovie Class";
179
180     if (!wnd_class_registered)
181     {
182         if (!RegisterClassA(&winclass))
183         {
184             ERR("Unable to register window %u\n", GetLastError());
185             return FALSE;
186         }
187         wnd_class_registered = TRUE;
188     }
189
190     This->hWnd = CreateWindowExA(0, "Wine ActiveMovie Class", "Wine ActiveMovie Window", WS_SIZEBOX,
191                                  CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,
192                                  NULL, NULL, NULL);
193
194     if (!This->hWnd)
195     {
196         ERR("Unable to create window\n");
197         return FALSE;
198     }
199
200     SetWindowLongA(This->hWnd, 0, (LONG)This);
201
202     return TRUE;
203 }
204
205 static DWORD WINAPI MessageLoop(LPVOID lpParameter)
206 {
207     VideoRendererImpl* This = (VideoRendererImpl*) lpParameter;
208     MSG msg; 
209     BOOL fGotMessage;
210
211     TRACE("Starting message loop\n");
212
213     if (!CreateRenderingWindow(This))
214     {
215         This->ThreadResult = FALSE;
216         SetEvent(This->hEvent);
217         return 0;
218     }
219
220     This->ThreadResult = TRUE;
221     SetEvent(This->hEvent);
222
223     while ((fGotMessage = GetMessageA(&msg, NULL, 0, 0)) != 0 && fGotMessage != -1) 
224     {
225         TranslateMessage(&msg); 
226         DispatchMessageA(&msg); 
227     }
228
229     TRACE("End of message loop\n");
230
231     return msg.wParam;
232 }
233
234 static BOOL CreateRenderingSubsystem(VideoRendererImpl* This)
235 {
236     This->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
237     if (!This->hEvent)
238         return FALSE;
239
240     This->hThread = CreateThread(NULL, 0, MessageLoop, (LPVOID)This, 0, &This->ThreadID);
241     if (!This->hThread)
242     {
243         CloseHandle(This->hEvent);
244         return FALSE;
245     }
246
247     WaitForSingleObject(This->hEvent, INFINITE);
248
249     if (!This->ThreadResult)
250     {
251         CloseHandle(This->hEvent);
252         CloseHandle(This->hThread);
253         return FALSE;
254     }
255
256     return TRUE;
257 }
258
259 static const IMemInputPinVtbl MemInputPin_Vtbl = 
260 {
261     MemInputPin_QueryInterface,
262     MemInputPin_AddRef,
263     MemInputPin_Release,
264     MemInputPin_GetAllocator,
265     MemInputPin_NotifyAllocator,
266     MemInputPin_GetAllocatorRequirements,
267     MemInputPin_Receive,
268     MemInputPin_ReceiveMultiple,
269     MemInputPin_ReceiveCanBlock
270 };
271
272 static DWORD VideoRenderer_SendSampleData(VideoRendererImpl* This, LPBYTE data, DWORD size)
273 {
274     AM_MEDIA_TYPE amt;
275     HRESULT hr = S_OK;
276     DDSURFACEDESC sdesc;
277     HDC hDC;
278     BITMAPINFOHEADER *bmiHeader;
279
280     TRACE("%p %p %d\n", This, data, size);
281
282     sdesc.dwSize = sizeof(sdesc);
283     hr = IPin_ConnectionMediaType((IPin *)This->pInputPin, &amt);
284     if (FAILED(hr)) {
285         ERR("Unable to retrieve media type\n");
286         return hr;
287     }
288
289     if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo))
290     {
291         bmiHeader = &((VIDEOINFOHEADER *)amt.pbFormat)->bmiHeader;
292     }
293     else if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo2))
294     {
295         bmiHeader = &((VIDEOINFOHEADER2 *)amt.pbFormat)->bmiHeader;
296     }
297     else
298     {
299         FIXME("Unknown type %s\n", debugstr_guid(&amt.subtype));
300         return VFW_E_RUNTIME_ERROR;
301     }
302
303
304     TRACE("biSize = %d\n", bmiHeader->biSize);
305     TRACE("biWidth = %d\n", bmiHeader->biWidth);
306     TRACE("biHeight = %d\n", bmiHeader->biHeight);
307     TRACE("biPlanes = %d\n", bmiHeader->biPlanes);
308     TRACE("biBitCount = %d\n", bmiHeader->biBitCount);
309     TRACE("biCompression = %s\n", debugstr_an((LPSTR)&(bmiHeader->biCompression), 4));
310     TRACE("biSizeImage = %d\n", bmiHeader->biSizeImage);
311
312     if (!This->init)
313     {
314         if (!This->WindowPos.right || !This->WindowPos.bottom)
315             This->WindowPos = This->SourceRect;
316
317         TRACE("WindowPos: %d %d %d %d\n", This->WindowPos.left, This->WindowPos.top, This->WindowPos.right, This->WindowPos.bottom);
318         SetWindowPos(This->hWnd, NULL,
319             This->WindowPos.left,
320             This->WindowPos.top,
321             This->WindowPos.right - This->WindowPos.left,
322             This->WindowPos.bottom - This->WindowPos.top,
323             SWP_NOZORDER|SWP_NOMOVE);
324
325         GetClientRect(This->hWnd, &This->DestRect);
326         This->init = TRUE;
327     }
328
329     hDC = GetDC(This->hWnd);
330
331     if (!hDC) {
332         ERR("Cannot get DC from window!\n");
333         return E_FAIL;
334     }
335
336     TRACE("Src Rect: %d %d %d %d\n", This->SourceRect.left, This->SourceRect.top, This->SourceRect.right, This->SourceRect.bottom);
337     TRACE("Dst Rect: %d %d %d %d\n", This->DestRect.left, This->DestRect.top, This->DestRect.right, This->DestRect.bottom);
338
339     StretchDIBits(hDC, This->DestRect.left, This->DestRect.top, This->DestRect.right -This->DestRect.left,
340                   This->DestRect.bottom - This->DestRect.top, This->SourceRect.left, This->SourceRect.top,
341                   This->SourceRect.right - This->SourceRect.left, This->SourceRect.bottom - This->SourceRect.top,
342                   data, (BITMAPINFO *)bmiHeader, DIB_RGB_COLORS, SRCCOPY);
343
344     ReleaseDC(This->hWnd, hDC);
345     if (This->AutoShow)
346         ShowWindow(This->hWnd, SW_SHOW);
347
348     return S_OK;
349 }
350
351 static HRESULT VideoRenderer_Sample(LPVOID iface, IMediaSample * pSample)
352 {
353     VideoRendererImpl *This = (VideoRendererImpl *)iface;
354     LPBYTE pbSrcStream = NULL;
355     long cbSrcStream = 0;
356     REFERENCE_TIME tStart, tStop;
357     HRESULT hr;
358     EnterCriticalSection(&This->csFilter);
359     if (This->pInputPin->flushing || This->pInputPin->end_of_stream)
360         hr = S_FALSE;
361
362     if (This->state == State_Stopped)
363     {
364         LeaveCriticalSection(&This->csFilter);
365         return VFW_E_WRONG_STATE;
366     }
367
368     TRACE("%p %p\n", iface, pSample);
369
370     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
371     if (FAILED(hr))
372         ERR("Cannot get sample time (%x)\n", hr);
373
374     if (This->rtLastStop != tStart)
375     {
376         if (IMediaSample_IsDiscontinuity(pSample) == S_FALSE)
377             ERR("Unexpected discontinuity: Last: %u.%03u, tStart: %u.%03u\n",
378                 (DWORD)(This->rtLastStop / 10000000),
379                 (DWORD)((This->rtLastStop / 10000)%1000),
380                 (DWORD)(tStart / 10000000), (DWORD)((tStart / 10000)%1000));
381         This->rtLastStop = tStart;
382     }
383
384     /* Preroll means the sample isn't shown, this is used for key frames and things like that */
385     if (IMediaSample_IsPreroll(pSample) == S_OK)
386     {
387         This->rtLastStop = tStop;
388         LeaveCriticalSection(&This->csFilter);
389         return S_OK;
390     }
391
392     hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
393     if (FAILED(hr))
394     {
395         ERR("Cannot get pointer to sample data (%x)\n", hr);
396         LeaveCriticalSection(&This->csFilter);
397         return hr;
398     }
399
400     cbSrcStream = IMediaSample_GetActualDataLength(pSample);
401
402     TRACE("val %p %ld\n", pbSrcStream, cbSrcStream);
403
404 #if 0 /* For debugging purpose */
405     {
406         int i;
407         for(i = 0; i < cbSrcStream; i++)
408         {
409             if ((i!=0) && !(i%16))
410                 TRACE("\n");
411                 TRACE("%02x ", pbSrcStream[i]);
412         }
413         TRACE("\n");
414     }
415 #endif
416
417     SetEvent(This->hEvent);
418     if (This->state == State_Paused)
419     {
420         This->sample_held = pSample;
421         LeaveCriticalSection(&This->csFilter);
422         WaitForSingleObject(This->blocked, INFINITE);
423         EnterCriticalSection(&This->csFilter);
424         This->sample_held = NULL;
425         if (This->state == State_Paused)
426         {
427             /* Flushing */
428             LeaveCriticalSection(&This->csFilter);
429             return S_OK;
430         }
431         if (This->state == State_Stopped)
432         {
433             LeaveCriticalSection(&This->csFilter);
434             return VFW_E_WRONG_STATE;
435         }
436     }
437
438     if (This->pClock && This->state == State_Running)
439     {
440         REFERENCE_TIME time, trefstart, trefstop;
441         LONG delta;
442
443         /* Perhaps I <SHOULD> use the reference clock AdviseTime function here
444          * I'm not going to! When I tried, it seemed to generate lag and
445          * it caused instability.
446          */
447         IReferenceClock_GetTime(This->pClock, &time);
448
449         trefstart = This->rtStreamStart;
450         trefstop = (REFERENCE_TIME)((double)(tStop - tStart) / This->pInputPin->dRate) + This->rtStreamStart;
451         delta = (LONG)((trefstart-time)/10000);
452         This->rtStreamStart = trefstop;
453         This->rtLastStop = tStop;
454
455         if (delta > 0)
456         {
457             TRACE("Sleeping for %u ms\n", delta);
458             Sleep(delta);
459         }
460         else if (time > trefstop)
461         {
462             TRACE("Dropping sample: Time: %u.%03u ms trefstop: %u.%03u ms!\n",
463                   (DWORD)(time / 10000000), (DWORD)((time / 10000)%1000),
464                   (DWORD)(trefstop / 10000000), (DWORD)((trefstop / 10000)%1000) );
465             This->rtLastStop = tStop;
466             LeaveCriticalSection(&This->csFilter);
467             return S_OK;
468         }
469     }
470     This->rtLastStop = tStop;
471
472     VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream);
473
474     LeaveCriticalSection(&This->csFilter);
475     return S_OK;
476 }
477
478 static HRESULT VideoRenderer_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
479 {
480     if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Video))
481         return S_FALSE;
482
483     if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB32) ||
484         IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB24) ||
485         IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB565) ||
486         IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB8))
487     {
488         VideoRendererImpl* This = (VideoRendererImpl*) iface;
489
490         if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo))
491         {
492             VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)pmt->pbFormat;
493             This->SourceRect.left = 0;
494             This->SourceRect.top = 0;
495             This->SourceRect.right = This->VideoWidth = format->bmiHeader.biWidth;
496             This->SourceRect.bottom = This->VideoHeight = format->bmiHeader.biHeight;
497         }
498         else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2))
499         {
500             VIDEOINFOHEADER2 *format2 = (VIDEOINFOHEADER2 *)pmt->pbFormat;
501
502             This->SourceRect.left = 0;
503             This->SourceRect.top = 0;
504             This->SourceRect.right = This->VideoWidth = format2->bmiHeader.biWidth;
505             This->SourceRect.bottom = This->VideoHeight = format2->bmiHeader.biHeight;
506         }
507         else
508         {
509             WARN("Format type %s not supported\n", debugstr_guid(&pmt->formattype));
510             return S_FALSE;
511         }
512         return S_OK;
513     }
514     return S_FALSE;
515 }
516
517 static inline VideoRendererImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
518 {
519     return (VideoRendererImpl *)((char*)iface - FIELD_OFFSET(VideoRendererImpl, mediaSeeking.lpVtbl));
520 }
521
522 static HRESULT WINAPI VideoRendererImpl_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
523 {
524     VideoRendererImpl *This = impl_from_IMediaSeeking(iface);
525
526     return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
527 }
528
529 static ULONG WINAPI VideoRendererImpl_Seeking_AddRef(IMediaSeeking * iface)
530 {
531     VideoRendererImpl *This = impl_from_IMediaSeeking(iface);
532
533     return IUnknown_AddRef((IUnknown *)This);
534 }
535
536 static ULONG WINAPI VideoRendererImpl_Seeking_Release(IMediaSeeking * iface)
537 {
538     VideoRendererImpl *This = impl_from_IMediaSeeking(iface);
539
540     return IUnknown_Release((IUnknown *)This);
541 }
542
543 static const IMediaSeekingVtbl VideoRendererImpl_Seeking_Vtbl =
544 {
545     VideoRendererImpl_Seeking_QueryInterface,
546     VideoRendererImpl_Seeking_AddRef,
547     VideoRendererImpl_Seeking_Release,
548     MediaSeekingImpl_GetCapabilities,
549     MediaSeekingImpl_CheckCapabilities,
550     MediaSeekingImpl_IsFormatSupported,
551     MediaSeekingImpl_QueryPreferredFormat,
552     MediaSeekingImpl_GetTimeFormat,
553     MediaSeekingImpl_IsUsingTimeFormat,
554     MediaSeekingImpl_SetTimeFormat,
555     MediaSeekingImpl_GetDuration,
556     MediaSeekingImpl_GetStopPosition,
557     MediaSeekingImpl_GetCurrentPosition,
558     MediaSeekingImpl_ConvertTimeFormat,
559     MediaSeekingImpl_SetPositions,
560     MediaSeekingImpl_GetPositions,
561     MediaSeekingImpl_GetAvailable,
562     MediaSeekingImpl_SetRate,
563     MediaSeekingImpl_GetRate,
564     MediaSeekingImpl_GetPreroll
565 };
566
567 static HRESULT VideoRendererImpl_Change(IBaseFilter *iface)
568 {
569     TRACE("(%p)\n", iface);
570     return S_OK;
571 }
572
573 HRESULT VideoRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv)
574 {
575     HRESULT hr;
576     PIN_INFO piInput;
577     VideoRendererImpl * pVideoRenderer;
578
579     TRACE("(%p, %p)\n", pUnkOuter, ppv);
580
581     *ppv = NULL;
582
583     pVideoRenderer = CoTaskMemAlloc(sizeof(VideoRendererImpl));
584     pVideoRenderer->pUnkOuter = pUnkOuter;
585     pVideoRenderer->bUnkOuterValid = FALSE;
586     pVideoRenderer->bAggregatable = FALSE;
587     pVideoRenderer->IInner_vtbl = &IInner_VTable;
588
589     pVideoRenderer->lpVtbl = &VideoRenderer_Vtbl;
590     pVideoRenderer->IBasicVideo_vtbl = &IBasicVideo_VTable;
591     pVideoRenderer->IVideoWindow_vtbl = &IVideoWindow_VTable;
592     
593     pVideoRenderer->refCount = 1;
594     InitializeCriticalSection(&pVideoRenderer->csFilter);
595     pVideoRenderer->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": VideoRendererImpl.csFilter");
596     pVideoRenderer->state = State_Stopped;
597     pVideoRenderer->pClock = NULL;
598     pVideoRenderer->init = 0;
599     pVideoRenderer->AutoShow = 1;
600     pVideoRenderer->rtLastStop = -1;
601     ZeroMemory(&pVideoRenderer->filterInfo, sizeof(FILTER_INFO));
602     ZeroMemory(&pVideoRenderer->SourceRect, sizeof(RECT));
603     ZeroMemory(&pVideoRenderer->DestRect, sizeof(RECT));
604     ZeroMemory(&pVideoRenderer->WindowPos, sizeof(RECT));
605     pVideoRenderer->hWndMsgDrain = NULL;
606
607     /* construct input pin */
608     piInput.dir = PINDIR_INPUT;
609     piInput.pFilter = (IBaseFilter *)pVideoRenderer;
610     lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
611
612     hr = InputPin_Construct(&VideoRenderer_InputPin_Vtbl, &piInput, VideoRenderer_Sample, (LPVOID)pVideoRenderer, VideoRenderer_QueryAccept, NULL, &pVideoRenderer->csFilter, NULL, (IPin **)&pVideoRenderer->pInputPin);
613
614     if (SUCCEEDED(hr))
615     {
616         MediaSeekingImpl_Init((IBaseFilter*)pVideoRenderer, VideoRendererImpl_Change, VideoRendererImpl_Change, VideoRendererImpl_Change, &pVideoRenderer->mediaSeeking, &pVideoRenderer->csFilter);
617         pVideoRenderer->mediaSeeking.lpVtbl = &VideoRendererImpl_Seeking_Vtbl;
618
619         pVideoRenderer->sample_held = NULL;
620         *ppv = (LPVOID)pVideoRenderer;
621     }
622     else
623     {
624         pVideoRenderer->csFilter.DebugInfo->Spare[0] = 0;
625         DeleteCriticalSection(&pVideoRenderer->csFilter);
626         CoTaskMemFree(pVideoRenderer);
627     }
628
629     if (!CreateRenderingSubsystem(pVideoRenderer))
630         return E_FAIL;
631
632     pVideoRenderer->blocked = CreateEventW(NULL, FALSE, FALSE, NULL);
633     if (!pVideoRenderer->blocked)
634     {
635         hr = HRESULT_FROM_WIN32(GetLastError());
636         IUnknown_Release((IUnknown *)pVideoRenderer);
637     }
638
639     return hr;
640 }
641
642 HRESULT VideoRendererDefault_create(IUnknown * pUnkOuter, LPVOID * ppv)
643 {
644     /* TODO: Attempt to use the VMR-7 renderer instead when possible */
645     return VideoRenderer_create(pUnkOuter, ppv);
646 }
647
648 static HRESULT WINAPI VideoRendererInner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
649 {
650     ICOM_THIS_MULTI(VideoRendererImpl, IInner_vtbl, iface);
651     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
652
653     if (This->bAggregatable)
654         This->bUnkOuterValid = TRUE;
655
656     *ppv = NULL;
657
658     if (IsEqualIID(riid, &IID_IUnknown))
659         *ppv = (LPVOID)&(This->IInner_vtbl);
660     else if (IsEqualIID(riid, &IID_IPersist))
661         *ppv = (LPVOID)This;
662     else if (IsEqualIID(riid, &IID_IMediaFilter))
663         *ppv = (LPVOID)This;
664     else if (IsEqualIID(riid, &IID_IBaseFilter))
665         *ppv = (LPVOID)This;
666     else if (IsEqualIID(riid, &IID_IBasicVideo))
667         *ppv = (LPVOID)&(This->IBasicVideo_vtbl);
668     else if (IsEqualIID(riid, &IID_IVideoWindow))
669         *ppv = (LPVOID)&(This->IVideoWindow_vtbl);
670     else if (IsEqualIID(riid, &IID_IMediaSeeking))
671         *ppv = &This->mediaSeeking;
672
673     if (*ppv)
674     {
675         IUnknown_AddRef((IUnknown *)(*ppv));
676         return S_OK;
677     }
678
679     if (!IsEqualIID(riid, &IID_IPin))
680         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
681
682     return E_NOINTERFACE;
683 }
684
685 static ULONG WINAPI VideoRendererInner_AddRef(IUnknown * iface)
686 {
687     ICOM_THIS_MULTI(VideoRendererImpl, IInner_vtbl, iface);
688     ULONG refCount = InterlockedIncrement(&This->refCount);
689
690     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
691
692     return refCount;
693 }
694
695 static ULONG WINAPI VideoRendererInner_Release(IUnknown * iface)
696 {
697     ICOM_THIS_MULTI(VideoRendererImpl, IInner_vtbl, iface);
698     ULONG refCount = InterlockedDecrement(&This->refCount);
699
700     TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
701
702     if (!refCount)
703     {
704         IPin *pConnectedTo;
705
706         DestroyWindow(This->hWnd);
707         PostThreadMessageA(This->ThreadID, WM_QUIT, 0, 0);
708         WaitForSingleObject(This->hThread, INFINITE);
709         CloseHandle(This->hThread);
710         CloseHandle(This->hEvent);
711
712         if (This->pClock)
713             IReferenceClock_Release(This->pClock);
714         
715         if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
716         {
717             IPin_Disconnect(pConnectedTo);
718             IPin_Release(pConnectedTo);
719         }
720         IPin_Disconnect((IPin *)This->pInputPin);
721
722         IPin_Release((IPin *)This->pInputPin);
723
724         This->lpVtbl = NULL;
725         
726         This->csFilter.DebugInfo->Spare[0] = 0;
727         DeleteCriticalSection(&This->csFilter);
728
729         TRACE("Destroying Video Renderer\n");
730         CoTaskMemFree(This);
731         
732         return 0;
733     }
734     else
735         return refCount;
736 }
737
738 static const IUnknownVtbl IInner_VTable =
739 {
740     VideoRendererInner_QueryInterface,
741     VideoRendererInner_AddRef,
742     VideoRendererInner_Release
743 };
744
745 static HRESULT WINAPI VideoRenderer_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
746 {
747     VideoRendererImpl *This = (VideoRendererImpl *)iface;
748
749     if (This->bAggregatable)
750         This->bUnkOuterValid = TRUE;
751
752     if (This->pUnkOuter)
753     {
754         if (This->bAggregatable)
755             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
756
757         if (IsEqualIID(riid, &IID_IUnknown))
758         {
759             HRESULT hr;
760
761             IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
762             hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
763             IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
764             This->bAggregatable = TRUE;
765             return hr;
766         }
767
768         *ppv = NULL;
769         return E_NOINTERFACE;
770     }
771
772     return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
773 }
774
775 static ULONG WINAPI VideoRenderer_AddRef(IBaseFilter * iface)
776 {
777     VideoRendererImpl *This = (VideoRendererImpl *)iface;
778
779     if (This->pUnkOuter && This->bUnkOuterValid)
780         return IUnknown_AddRef(This->pUnkOuter);
781     return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
782 }
783
784 static ULONG WINAPI VideoRenderer_Release(IBaseFilter * iface)
785 {
786     VideoRendererImpl *This = (VideoRendererImpl *)iface;
787
788     if (This->pUnkOuter && This->bUnkOuterValid)
789         return IUnknown_Release(This->pUnkOuter);
790     return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
791 }
792
793 /** IPersist methods **/
794
795 static HRESULT WINAPI VideoRenderer_GetClassID(IBaseFilter * iface, CLSID * pClsid)
796 {
797     VideoRendererImpl *This = (VideoRendererImpl *)iface;
798
799     TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
800
801     *pClsid = CLSID_VideoRenderer;
802
803     return S_OK;
804 }
805
806 /** IMediaFilter methods **/
807
808 static HRESULT WINAPI VideoRenderer_Stop(IBaseFilter * iface)
809 {
810     VideoRendererImpl *This = (VideoRendererImpl *)iface;
811
812     TRACE("(%p/%p)->()\n", This, iface);
813
814     EnterCriticalSection(&This->csFilter);
815     {
816         This->state = State_Stopped;
817         SetEvent(This->hEvent);
818         SetEvent(This->blocked);
819     }
820     LeaveCriticalSection(&This->csFilter);
821
822     return S_OK;
823 }
824
825 static HRESULT WINAPI VideoRenderer_Pause(IBaseFilter * iface)
826 {
827     VideoRendererImpl *This = (VideoRendererImpl *)iface;
828     
829     TRACE("(%p/%p)->()\n", This, iface);
830
831     EnterCriticalSection(&This->csFilter);
832     if (This->state != State_Paused)
833     {
834         if (This->state == State_Stopped)
835         {
836             This->pInputPin->end_of_stream = 0;
837             ResetEvent(This->hEvent);
838         }
839
840         This->state = State_Paused;
841         ResetEvent(This->blocked);
842     }
843     LeaveCriticalSection(&This->csFilter);
844
845     return S_OK;
846 }
847
848 static HRESULT WINAPI VideoRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
849 {
850     VideoRendererImpl *This = (VideoRendererImpl *)iface;
851
852     TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
853
854     EnterCriticalSection(&This->csFilter);
855     if (This->state != State_Running)
856     {
857         if (This->state == State_Stopped)
858         {
859             This->pInputPin->end_of_stream = 0;
860             ResetEvent(This->hEvent);
861         }
862         SetEvent(This->blocked);
863
864         This->rtStreamStart = tStart;
865         This->state = State_Running;
866     }
867     LeaveCriticalSection(&This->csFilter);
868
869     return S_OK;
870 }
871
872 static HRESULT WINAPI VideoRenderer_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
873 {
874     VideoRendererImpl *This = (VideoRendererImpl *)iface;
875     HRESULT hr;
876
877     TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
878
879     if (WaitForSingleObject(This->hEvent, dwMilliSecsTimeout) == WAIT_TIMEOUT)
880         hr = VFW_S_STATE_INTERMEDIATE;
881     else
882         hr = S_OK;
883
884     EnterCriticalSection(&This->csFilter);
885     {
886         *pState = This->state;
887     }
888     LeaveCriticalSection(&This->csFilter);
889
890     return hr;
891 }
892
893 static HRESULT WINAPI VideoRenderer_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
894 {
895     VideoRendererImpl *This = (VideoRendererImpl *)iface;
896
897     TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
898
899     EnterCriticalSection(&This->csFilter);
900     {
901         if (This->pClock)
902             IReferenceClock_Release(This->pClock);
903         This->pClock = pClock;
904         if (This->pClock)
905             IReferenceClock_AddRef(This->pClock);
906     }
907     LeaveCriticalSection(&This->csFilter);
908
909     return S_OK;
910 }
911
912 static HRESULT WINAPI VideoRenderer_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
913 {
914     VideoRendererImpl *This = (VideoRendererImpl *)iface;
915
916     TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
917
918     EnterCriticalSection(&This->csFilter);
919     {
920         *ppClock = This->pClock;
921         if (This->pClock)
922             IReferenceClock_AddRef(This->pClock);
923     }
924     LeaveCriticalSection(&This->csFilter);
925     
926     return S_OK;
927 }
928
929 /** IBaseFilter implementation **/
930
931 static HRESULT VideoRenderer_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
932 {
933     VideoRendererImpl *This = (VideoRendererImpl *)iface;
934
935     /* Our pins are static, not changing so setting static tick count is ok */
936     *lastsynctick = 0;
937
938     if (pos >= 1)
939         return S_FALSE;
940
941     *pin = (IPin *)This->pInputPin;
942     IPin_AddRef(*pin);
943     return S_OK;
944 }
945
946 static HRESULT WINAPI VideoRenderer_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
947 {
948     VideoRendererImpl *This = (VideoRendererImpl *)iface;
949
950     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
951
952     return IEnumPinsImpl_Construct(ppEnum, VideoRenderer_GetPin, iface);
953 }
954
955 static HRESULT WINAPI VideoRenderer_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
956 {
957     VideoRendererImpl *This = (VideoRendererImpl *)iface;
958
959     TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
960
961     FIXME("VideoRenderer::FindPin(...)\n");
962
963     /* FIXME: critical section */
964
965     return E_NOTIMPL;
966 }
967
968 static HRESULT WINAPI VideoRenderer_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
969 {
970     VideoRendererImpl *This = (VideoRendererImpl *)iface;
971
972     TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
973
974     strcpyW(pInfo->achName, This->filterInfo.achName);
975     pInfo->pGraph = This->filterInfo.pGraph;
976
977     if (pInfo->pGraph)
978         IFilterGraph_AddRef(pInfo->pGraph);
979     
980     return S_OK;
981 }
982
983 static HRESULT WINAPI VideoRenderer_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
984 {
985     VideoRendererImpl *This = (VideoRendererImpl *)iface;
986
987     TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
988
989     EnterCriticalSection(&This->csFilter);
990     {
991         if (pName)
992             strcpyW(This->filterInfo.achName, pName);
993         else
994             *This->filterInfo.achName = '\0';
995         This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
996     }
997     LeaveCriticalSection(&This->csFilter);
998
999     return S_OK;
1000 }
1001
1002 static HRESULT WINAPI VideoRenderer_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
1003 {
1004     VideoRendererImpl *This = (VideoRendererImpl *)iface;
1005     TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
1006     return E_NOTIMPL;
1007 }
1008
1009 static const IBaseFilterVtbl VideoRenderer_Vtbl =
1010 {
1011     VideoRenderer_QueryInterface,
1012     VideoRenderer_AddRef,
1013     VideoRenderer_Release,
1014     VideoRenderer_GetClassID,
1015     VideoRenderer_Stop,
1016     VideoRenderer_Pause,
1017     VideoRenderer_Run,
1018     VideoRenderer_GetState,
1019     VideoRenderer_SetSyncSource,
1020     VideoRenderer_GetSyncSource,
1021     VideoRenderer_EnumPins,
1022     VideoRenderer_FindPin,
1023     VideoRenderer_QueryFilterInfo,
1024     VideoRenderer_JoinFilterGraph,
1025     VideoRenderer_QueryVendorInfo
1026 };
1027
1028 static HRESULT WINAPI VideoRenderer_InputPin_EndOfStream(IPin * iface)
1029 {
1030     InputPin* This = (InputPin*)iface;
1031     IMediaEventSink* pEventSink;
1032     HRESULT hr;
1033
1034     TRACE("(%p/%p)->()\n", This, iface);
1035
1036     hr = IFilterGraph_QueryInterface(((VideoRendererImpl*)This->pin.pinInfo.pFilter)->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
1037     if (SUCCEEDED(hr))
1038     {
1039         hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
1040         IMediaEventSink_Release(pEventSink);
1041     }
1042
1043     return hr;
1044 }
1045
1046 static HRESULT WINAPI VideoRenderer_InputPin_BeginFlush(IPin * iface)
1047 {
1048     InputPin* This = (InputPin*)iface;
1049     VideoRendererImpl *pVideoRenderer = (VideoRendererImpl *)This->pin.pinInfo.pFilter;
1050     HRESULT hr;
1051
1052     TRACE("(%p/%p)->()\n", This, iface);
1053
1054     EnterCriticalSection(This->pin.pCritSec);
1055     if (pVideoRenderer->state == State_Paused)
1056         SetEvent(pVideoRenderer->blocked);
1057
1058     hr = InputPin_BeginFlush(iface);
1059     LeaveCriticalSection(This->pin.pCritSec);
1060
1061     return hr;
1062 }
1063
1064 static HRESULT WINAPI VideoRenderer_InputPin_EndFlush(IPin * iface)
1065 {
1066     InputPin* This = (InputPin*)iface;
1067     VideoRendererImpl *pVideoRenderer = (VideoRendererImpl *)This->pin.pinInfo.pFilter;
1068     HRESULT hr;
1069
1070     TRACE("(%p/%p)->()\n", This, iface);
1071
1072     EnterCriticalSection(This->pin.pCritSec);
1073     if (pVideoRenderer->state == State_Paused)
1074         ResetEvent(pVideoRenderer->blocked);
1075
1076     hr = InputPin_EndFlush(iface);
1077     LeaveCriticalSection(This->pin.pCritSec);
1078
1079     return hr;
1080 }
1081
1082 static const IPinVtbl VideoRenderer_InputPin_Vtbl = 
1083 {
1084     InputPin_QueryInterface,
1085     IPinImpl_AddRef,
1086     InputPin_Release,
1087     InputPin_Connect,
1088     InputPin_ReceiveConnection,
1089     IPinImpl_Disconnect,
1090     IPinImpl_ConnectedTo,
1091     IPinImpl_ConnectionMediaType,
1092     IPinImpl_QueryPinInfo,
1093     IPinImpl_QueryDirection,
1094     IPinImpl_QueryId,
1095     IPinImpl_QueryAccept,
1096     IPinImpl_EnumMediaTypes,
1097     IPinImpl_QueryInternalConnections,
1098     VideoRenderer_InputPin_EndOfStream,
1099     VideoRenderer_InputPin_BeginFlush,
1100     VideoRenderer_InputPin_EndFlush,
1101     InputPin_NewSegment
1102 };
1103
1104 /*** IUnknown methods ***/
1105 static HRESULT WINAPI Basicvideo_QueryInterface(IBasicVideo *iface,
1106                                                 REFIID riid,
1107                                                 LPVOID*ppvObj) {
1108     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1109
1110     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1111
1112     return VideoRenderer_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1113 }
1114
1115 static ULONG WINAPI Basicvideo_AddRef(IBasicVideo *iface) {
1116     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1117
1118     TRACE("(%p/%p)->()\n", This, iface);
1119
1120     return VideoRenderer_AddRef((IBaseFilter*)This);
1121 }
1122
1123 static ULONG WINAPI Basicvideo_Release(IBasicVideo *iface) {
1124     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1125
1126     TRACE("(%p/%p)->()\n", This, iface);
1127
1128     return VideoRenderer_Release((IBaseFilter*)This);
1129 }
1130
1131 /*** IDispatch methods ***/
1132 static HRESULT WINAPI Basicvideo_GetTypeInfoCount(IBasicVideo *iface,
1133                                                   UINT*pctinfo) {
1134     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1135
1136     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1137
1138     return S_OK;
1139 }
1140
1141 static HRESULT WINAPI Basicvideo_GetTypeInfo(IBasicVideo *iface,
1142                                              UINT iTInfo,
1143                                              LCID lcid,
1144                                              ITypeInfo**ppTInfo) {
1145     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1146
1147     FIXME("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1148
1149     return S_OK;
1150 }
1151
1152 static HRESULT WINAPI Basicvideo_GetIDsOfNames(IBasicVideo *iface,
1153                                                REFIID riid,
1154                                                LPOLESTR*rgszNames,
1155                                                UINT cNames,
1156                                                LCID lcid,
1157                                                DISPID*rgDispId) {
1158     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1159
1160     FIXME("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1161
1162     return S_OK;
1163 }
1164
1165 static HRESULT WINAPI Basicvideo_Invoke(IBasicVideo *iface,
1166                                         DISPID dispIdMember,
1167                                         REFIID riid,
1168                                         LCID lcid,
1169                                         WORD wFlags,
1170                                         DISPPARAMS*pDispParams,
1171                                         VARIANT*pVarResult,
1172                                         EXCEPINFO*pExepInfo,
1173                                         UINT*puArgErr) {
1174     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1175
1176     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);
1177
1178     return S_OK;
1179 }
1180
1181 /*** IBasicVideo methods ***/
1182 static HRESULT WINAPI Basicvideo_get_AvgTimePerFrame(IBasicVideo *iface,
1183                                                      REFTIME *pAvgTimePerFrame) {
1184     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1185
1186     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pAvgTimePerFrame);
1187
1188     return S_OK;
1189 }
1190
1191 static HRESULT WINAPI Basicvideo_get_BitRate(IBasicVideo *iface,
1192                                              long *pBitRate) {
1193     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1194
1195     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pBitRate);
1196
1197     return S_OK;
1198 }
1199
1200 static HRESULT WINAPI Basicvideo_get_BitErrorRate(IBasicVideo *iface,
1201                                                   long *pBitErrorRate) {
1202     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1203
1204     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pBitErrorRate);
1205
1206     return S_OK;
1207 }
1208
1209 static HRESULT WINAPI Basicvideo_get_VideoWidth(IBasicVideo *iface,
1210                                                 long *pVideoWidth) {
1211     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1212
1213     TRACE("(%p/%p)->(%p)\n", This, iface, pVideoWidth);
1214
1215     *pVideoWidth = This->VideoWidth;
1216
1217     return S_OK;
1218 }
1219
1220 static HRESULT WINAPI Basicvideo_get_VideoHeight(IBasicVideo *iface,
1221                                                  long *pVideoHeight) {
1222     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1223
1224     TRACE("(%p/%p)->(%p)\n", This, iface, pVideoHeight);
1225
1226     *pVideoHeight = This->VideoHeight;
1227
1228     return S_OK;
1229 }
1230
1231 static HRESULT WINAPI Basicvideo_put_SourceLeft(IBasicVideo *iface,
1232                                                 long SourceLeft) {
1233     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1234
1235     TRACE("(%p/%p)->(%ld)\n", This, iface, SourceLeft);
1236
1237     This->SourceRect.left = SourceLeft;
1238
1239     return S_OK;
1240 }
1241
1242 static HRESULT WINAPI Basicvideo_get_SourceLeft(IBasicVideo *iface,
1243                                                 long *pSourceLeft) {
1244     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1245
1246     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceLeft);
1247
1248     *pSourceLeft = This->SourceRect.left;
1249
1250     return S_OK;
1251 }
1252
1253 static HRESULT WINAPI Basicvideo_put_SourceWidth(IBasicVideo *iface,
1254                                                  long SourceWidth) {
1255     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1256
1257     TRACE("(%p/%p)->(%ld)\n", This, iface, SourceWidth);
1258
1259     This->SourceRect.right = This->SourceRect.left + SourceWidth;
1260
1261     return S_OK;
1262 }
1263
1264 static HRESULT WINAPI Basicvideo_get_SourceWidth(IBasicVideo *iface,
1265                                                  long *pSourceWidth) {
1266     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1267
1268     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceWidth);
1269
1270     *pSourceWidth = This->SourceRect.right - This->SourceRect.left;
1271     
1272     return S_OK;
1273 }
1274
1275 static HRESULT WINAPI Basicvideo_put_SourceTop(IBasicVideo *iface,
1276                                                long SourceTop) {
1277     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1278
1279     TRACE("(%p/%p)->(%ld)\n", This, iface, SourceTop);
1280
1281     This->SourceRect.top = SourceTop;
1282
1283     return S_OK;
1284 }
1285
1286 static HRESULT WINAPI Basicvideo_get_SourceTop(IBasicVideo *iface,
1287                                                long *pSourceTop) {
1288     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1289
1290     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceTop);
1291
1292     *pSourceTop = This->SourceRect.top;
1293
1294     return S_OK;
1295 }
1296
1297 static HRESULT WINAPI Basicvideo_put_SourceHeight(IBasicVideo *iface,
1298                                                   long SourceHeight) {
1299     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1300
1301     TRACE("(%p/%p)->(%ld)\n", This, iface, SourceHeight);
1302
1303     This->SourceRect.bottom = This->SourceRect.top + SourceHeight;
1304
1305     return S_OK;
1306 }
1307
1308 static HRESULT WINAPI Basicvideo_get_SourceHeight(IBasicVideo *iface,
1309                                                   long *pSourceHeight) {
1310     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1311
1312     TRACE("(%p/%p)->(%p)\n", This, iface, pSourceHeight);
1313
1314     *pSourceHeight = This->SourceRect.bottom - This->SourceRect.top;
1315
1316     return S_OK;
1317 }
1318
1319 static HRESULT WINAPI Basicvideo_put_DestinationLeft(IBasicVideo *iface,
1320                                                      long DestinationLeft) {
1321     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1322
1323     TRACE("(%p/%p)->(%ld)\n", This, iface, DestinationLeft);
1324
1325     This->DestRect.left = DestinationLeft;
1326
1327     return S_OK;
1328 }
1329
1330 static HRESULT WINAPI Basicvideo_get_DestinationLeft(IBasicVideo *iface,
1331                                                      long *pDestinationLeft) {
1332     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1333
1334     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationLeft);
1335
1336     *pDestinationLeft = This->DestRect.left;
1337
1338     return S_OK;
1339 }
1340
1341 static HRESULT WINAPI Basicvideo_put_DestinationWidth(IBasicVideo *iface,
1342                                                       long DestinationWidth) {
1343     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1344
1345     TRACE("(%p/%p)->(%ld)\n", This, iface, DestinationWidth);
1346
1347     This->DestRect.right = This->DestRect.left + DestinationWidth;
1348
1349     return S_OK;
1350 }
1351
1352 static HRESULT WINAPI Basicvideo_get_DestinationWidth(IBasicVideo *iface,
1353                                                       long *pDestinationWidth) {
1354     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1355
1356     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationWidth);
1357
1358     *pDestinationWidth = This->DestRect.right - This->DestRect.left;
1359
1360     return S_OK;
1361 }
1362
1363 static HRESULT WINAPI Basicvideo_put_DestinationTop(IBasicVideo *iface,
1364                                                     long DestinationTop) {
1365     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1366
1367     TRACE("(%p/%p)->(%ld)\n", This, iface, DestinationTop);
1368
1369     This->DestRect.top = DestinationTop;
1370     
1371     return S_OK;
1372 }
1373
1374 static HRESULT WINAPI Basicvideo_get_DestinationTop(IBasicVideo *iface,
1375                                                     long *pDestinationTop) {
1376     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1377
1378     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationTop);
1379
1380     *pDestinationTop = This->DestRect.top;
1381
1382     return S_OK;
1383 }
1384
1385 static HRESULT WINAPI Basicvideo_put_DestinationHeight(IBasicVideo *iface,
1386                                                        long DestinationHeight) {
1387     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1388
1389     TRACE("(%p/%p)->(%ld)\n", This, iface, DestinationHeight);
1390
1391     This->DestRect.right = This->DestRect.left + DestinationHeight;
1392
1393     return S_OK;
1394 }
1395
1396 static HRESULT WINAPI Basicvideo_get_DestinationHeight(IBasicVideo *iface,
1397                                                        long *pDestinationHeight) {
1398     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1399
1400     TRACE("(%p/%p)->(%p)\n", This, iface, pDestinationHeight);
1401
1402     *pDestinationHeight = This->DestRect.right - This->DestRect.left;
1403
1404     return S_OK;
1405 }
1406
1407 static HRESULT WINAPI Basicvideo_SetSourcePosition(IBasicVideo *iface,
1408                                                    long Left,
1409                                                    long Top,
1410                                                    long Width,
1411                                                    long Height) {
1412     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1413
1414     TRACE("(%p/%p)->(%ld, %ld, %ld, %ld)\n", This, iface, Left, Top, Width, Height);
1415
1416     This->SourceRect.left = Left;
1417     This->SourceRect.top = Top;
1418     This->SourceRect.right = Left + Width;
1419     This->SourceRect.bottom = Top + Height;
1420     
1421     return S_OK;
1422 }
1423
1424 static HRESULT WINAPI Basicvideo_GetSourcePosition(IBasicVideo *iface,
1425                                                    long *pLeft,
1426                                                    long *pTop,
1427                                                    long *pWidth,
1428                                                    long *pHeight) {
1429     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1430
1431     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
1432
1433     *pLeft = This->SourceRect.left;
1434     *pTop = This->SourceRect.top;
1435     *pWidth = This->SourceRect.right - This->SourceRect.left;
1436     *pHeight = This->SourceRect.bottom - This->SourceRect.top;
1437     
1438     return S_OK;
1439 }
1440
1441 static HRESULT WINAPI Basicvideo_SetDefaultSourcePosition(IBasicVideo *iface) {
1442     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1443
1444     TRACE("(%p/%p)->()\n", This, iface);
1445
1446     This->SourceRect.left = 0;
1447     This->SourceRect.top = 0;
1448     This->SourceRect.right = This->VideoWidth;
1449     This->SourceRect.bottom = This->VideoHeight;
1450
1451     return S_OK;
1452 }
1453
1454 static HRESULT WINAPI Basicvideo_SetDestinationPosition(IBasicVideo *iface,
1455                                                         long Left,
1456                                                         long Top,
1457                                                         long Width,
1458                                                         long Height) {
1459     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1460
1461     TRACE("(%p/%p)->(%ld, %ld, %ld, %ld)\n", This, iface, Left, Top, Width, Height);
1462
1463     This->DestRect.left = Left;
1464     This->DestRect.top = Top;
1465     This->DestRect.right = Left + Width;
1466     This->DestRect.bottom = Top + Height;
1467
1468     return S_OK;
1469 }
1470
1471 static HRESULT WINAPI Basicvideo_GetDestinationPosition(IBasicVideo *iface,
1472                                                         long *pLeft,
1473                                                         long *pTop,
1474                                                         long *pWidth,
1475                                                         long *pHeight) {
1476     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1477
1478     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
1479
1480     *pLeft = This->DestRect.left;
1481     *pTop = This->DestRect.top;
1482     *pWidth = This->DestRect.right - This->DestRect.left;
1483     *pHeight = This->DestRect.bottom - This->DestRect.top;
1484
1485     return S_OK;
1486 }
1487
1488 static HRESULT WINAPI Basicvideo_SetDefaultDestinationPosition(IBasicVideo *iface) {
1489     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1490     RECT rect;
1491
1492     TRACE("(%p/%p)->()\n", This, iface);
1493
1494     if (!GetClientRect(This->hWnd, &rect))
1495         return E_FAIL;
1496     
1497     This->SourceRect.left = 0;
1498     This->SourceRect.top = 0;
1499     This->SourceRect.right = rect.right;
1500     This->SourceRect.bottom = rect.bottom;
1501     
1502     return S_OK;
1503 }
1504
1505 static HRESULT WINAPI Basicvideo_GetVideoSize(IBasicVideo *iface,
1506                                               long *pWidth,
1507                                               long *pHeight) {
1508     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1509
1510     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pWidth, pHeight);
1511
1512     *pWidth = This->VideoWidth;
1513     *pHeight = This->VideoHeight;
1514     
1515     return S_OK;
1516 }
1517
1518 static HRESULT WINAPI Basicvideo_GetVideoPaletteEntries(IBasicVideo *iface,
1519                                                         long StartIndex,
1520                                                         long Entries,
1521                                                         long *pRetrieved,
1522                                                         long *pPalette) {
1523     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1524
1525     FIXME("(%p/%p)->(%ld, %ld, %p, %p): stub !!!\n", This, iface, StartIndex, Entries, pRetrieved, pPalette);
1526
1527     return S_OK;
1528 }
1529
1530 static HRESULT WINAPI Basicvideo_GetCurrentImage(IBasicVideo *iface,
1531                                                  long *pBufferSize,
1532                                                  long *pDIBImage) {
1533     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1534     BITMAPINFOHEADER *bmiHeader;
1535     LONG needed_size;
1536     AM_MEDIA_TYPE *amt = &This->pInputPin->pin.mtCurrent;
1537     char *ptr;
1538
1539     EnterCriticalSection(&This->csFilter);
1540
1541     if (!This->sample_held)
1542     {
1543          LeaveCriticalSection(&This->csFilter);
1544          return (This->state == State_Paused ? E_UNEXPECTED : VFW_E_NOT_PAUSED);
1545     }
1546
1547     FIXME("(%p/%p)->(%p, %p): partial stub\n", This, iface, pBufferSize, pDIBImage);
1548
1549     if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo))
1550     {
1551         bmiHeader = &((VIDEOINFOHEADER *)amt->pbFormat)->bmiHeader;
1552     }
1553     else if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo2))
1554     {
1555         bmiHeader = &((VIDEOINFOHEADER2 *)amt->pbFormat)->bmiHeader;
1556     }
1557     else
1558     {
1559         FIXME("Unknown type %s\n", debugstr_guid(&amt->subtype));
1560         LeaveCriticalSection(&This->csFilter);
1561         return VFW_E_RUNTIME_ERROR;
1562     }
1563
1564     needed_size = bmiHeader->biSize;
1565     needed_size += IMediaSample_GetActualDataLength(This->sample_held);
1566
1567     if (!pDIBImage)
1568     {
1569         *pBufferSize = needed_size;
1570         LeaveCriticalSection(&This->csFilter);
1571         return S_OK;
1572     }
1573
1574     if (needed_size < *pBufferSize)
1575     {
1576         ERR("Buffer too small %u/%lu\n", needed_size, *pBufferSize);
1577         LeaveCriticalSection(&This->csFilter);
1578         return E_FAIL;
1579     }
1580     *pBufferSize = needed_size;
1581
1582     memcpy(pDIBImage, bmiHeader, bmiHeader->biSize);
1583     IMediaSample_GetPointer(This->sample_held, (BYTE **)&ptr);
1584     memcpy((char *)pDIBImage + bmiHeader->biSize, ptr, IMediaSample_GetActualDataLength(This->sample_held));
1585
1586     LeaveCriticalSection(&This->csFilter);
1587
1588     return S_OK;
1589 }
1590
1591 static HRESULT WINAPI Basicvideo_IsUsingDefaultSource(IBasicVideo *iface) {
1592     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1593
1594     FIXME("(%p/%p)->(): stub !!!\n", This, iface);
1595
1596     return S_OK;
1597 }
1598
1599 static HRESULT WINAPI Basicvideo_IsUsingDefaultDestination(IBasicVideo *iface) {
1600     ICOM_THIS_MULTI(VideoRendererImpl, IBasicVideo_vtbl, iface);
1601
1602     FIXME("(%p/%p)->(): stub !!!\n", This, iface);
1603
1604     return S_OK;
1605 }
1606
1607
1608 static const IBasicVideoVtbl IBasicVideo_VTable =
1609 {
1610     Basicvideo_QueryInterface,
1611     Basicvideo_AddRef,
1612     Basicvideo_Release,
1613     Basicvideo_GetTypeInfoCount,
1614     Basicvideo_GetTypeInfo,
1615     Basicvideo_GetIDsOfNames,
1616     Basicvideo_Invoke,
1617     Basicvideo_get_AvgTimePerFrame,
1618     Basicvideo_get_BitRate,
1619     Basicvideo_get_BitErrorRate,
1620     Basicvideo_get_VideoWidth,
1621     Basicvideo_get_VideoHeight,
1622     Basicvideo_put_SourceLeft,
1623     Basicvideo_get_SourceLeft,
1624     Basicvideo_put_SourceWidth,
1625     Basicvideo_get_SourceWidth,
1626     Basicvideo_put_SourceTop,
1627     Basicvideo_get_SourceTop,
1628     Basicvideo_put_SourceHeight,
1629     Basicvideo_get_SourceHeight,
1630     Basicvideo_put_DestinationLeft,
1631     Basicvideo_get_DestinationLeft,
1632     Basicvideo_put_DestinationWidth,
1633     Basicvideo_get_DestinationWidth,
1634     Basicvideo_put_DestinationTop,
1635     Basicvideo_get_DestinationTop,
1636     Basicvideo_put_DestinationHeight,
1637     Basicvideo_get_DestinationHeight,
1638     Basicvideo_SetSourcePosition,
1639     Basicvideo_GetSourcePosition,
1640     Basicvideo_SetDefaultSourcePosition,
1641     Basicvideo_SetDestinationPosition,
1642     Basicvideo_GetDestinationPosition,
1643     Basicvideo_SetDefaultDestinationPosition,
1644     Basicvideo_GetVideoSize,
1645     Basicvideo_GetVideoPaletteEntries,
1646     Basicvideo_GetCurrentImage,
1647     Basicvideo_IsUsingDefaultSource,
1648     Basicvideo_IsUsingDefaultDestination
1649 };
1650
1651
1652 /*** IUnknown methods ***/
1653 static HRESULT WINAPI Videowindow_QueryInterface(IVideoWindow *iface,
1654                                                  REFIID riid,
1655                                                  LPVOID*ppvObj) {
1656     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1657
1658     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
1659
1660     return VideoRenderer_QueryInterface((IBaseFilter*)This, riid, ppvObj);
1661 }
1662
1663 static ULONG WINAPI Videowindow_AddRef(IVideoWindow *iface) {
1664     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1665
1666     TRACE("(%p/%p)->()\n", This, iface);
1667
1668     return VideoRenderer_AddRef((IBaseFilter*)This);
1669 }
1670
1671 static ULONG WINAPI Videowindow_Release(IVideoWindow *iface) {
1672     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1673
1674     TRACE("(%p/%p)->()\n", This, iface);
1675
1676     return VideoRenderer_Release((IBaseFilter*)This);
1677 }
1678
1679 /*** IDispatch methods ***/
1680 static HRESULT WINAPI Videowindow_GetTypeInfoCount(IVideoWindow *iface,
1681                                                    UINT*pctinfo) {
1682     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1683
1684     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pctinfo);
1685
1686     return S_OK;
1687 }
1688
1689 static HRESULT WINAPI Videowindow_GetTypeInfo(IVideoWindow *iface,
1690                                               UINT iTInfo,
1691                                               LCID lcid,
1692                                               ITypeInfo**ppTInfo) {
1693     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1694
1695     FIXME("(%p/%p)->(%d, %d, %p): stub !!!\n", This, iface, iTInfo, lcid, ppTInfo);
1696
1697     return S_OK;
1698 }
1699
1700 static HRESULT WINAPI Videowindow_GetIDsOfNames(IVideoWindow *iface,
1701                                                 REFIID riid,
1702                                                 LPOLESTR*rgszNames,
1703                                                 UINT cNames,
1704                                                 LCID lcid,
1705                                                 DISPID*rgDispId) {
1706     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1707
1708     FIXME("(%p/%p)->(%s (%p), %p, %d, %d, %p): stub !!!\n", This, iface, debugstr_guid(riid), riid, rgszNames, cNames, lcid, rgDispId);
1709
1710     return S_OK;
1711 }
1712
1713 static HRESULT WINAPI Videowindow_Invoke(IVideoWindow *iface,
1714                                          DISPID dispIdMember,
1715                                          REFIID riid,
1716                                          LCID lcid,
1717                                          WORD wFlags,
1718                                          DISPPARAMS*pDispParams,
1719                                          VARIANT*pVarResult,
1720                                          EXCEPINFO*pExepInfo,
1721                                          UINT*puArgErr) {
1722     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1723
1724     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);
1725
1726     return S_OK;
1727 }
1728
1729 /*** IVideoWindow methods ***/
1730 static HRESULT WINAPI Videowindow_put_Caption(IVideoWindow *iface,
1731                                               BSTR strCaption) {
1732     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1733
1734     TRACE("(%p/%p)->(%s (%p))\n", This, iface, debugstr_w(strCaption), strCaption);
1735
1736     if (!SetWindowTextW(This->hWnd, strCaption))
1737         return E_FAIL;
1738
1739     return S_OK;
1740 }
1741
1742 static HRESULT WINAPI Videowindow_get_Caption(IVideoWindow *iface,
1743                                               BSTR *strCaption) {
1744     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1745
1746     TRACE("(%p/%p)->(%p)\n", This, iface, strCaption);
1747
1748     GetWindowTextW(This->hWnd, (LPWSTR)strCaption, 100);
1749
1750     return S_OK;
1751 }
1752
1753 static HRESULT WINAPI Videowindow_put_WindowStyle(IVideoWindow *iface,
1754                                                   long WindowStyle) {
1755     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1756     LONG old;
1757
1758     old = GetWindowLongA(This->hWnd, GWL_STYLE);
1759     
1760     TRACE("(%p/%p)->(%x -> %lx)\n", This, iface, old, WindowStyle);
1761
1762     if (WindowStyle & (WS_DISABLED|WS_HSCROLL|WS_ICONIC|WS_MAXIMIZE|WS_MINIMIZE|WS_VSCROLL))
1763         return E_INVALIDARG;
1764     
1765     SetWindowLongA(This->hWnd, GWL_STYLE, WindowStyle);
1766
1767     return S_OK;
1768 }
1769
1770 static HRESULT WINAPI Videowindow_get_WindowStyle(IVideoWindow *iface,
1771                                                   long *WindowStyle) {
1772     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1773
1774     TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyle);
1775
1776     *WindowStyle = GetWindowLongA(This->hWnd, GWL_STYLE);
1777
1778     return S_OK;
1779 }
1780
1781 static HRESULT WINAPI Videowindow_put_WindowStyleEx(IVideoWindow *iface,
1782                                                     long WindowStyleEx) {
1783     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1784
1785     TRACE("(%p/%p)->(%ld)\n", This, iface, WindowStyleEx);
1786
1787     if (WindowStyleEx & (WS_DISABLED|WS_HSCROLL|WS_ICONIC|WS_MAXIMIZE|WS_MINIMIZE|WS_VSCROLL))
1788         return E_INVALIDARG;
1789
1790     if (!SetWindowLongA(This->hWnd, GWL_EXSTYLE, WindowStyleEx))
1791         return E_FAIL;
1792
1793     return S_OK;
1794 }
1795
1796 static HRESULT WINAPI Videowindow_get_WindowStyleEx(IVideoWindow *iface,
1797                                                     long *WindowStyleEx) {
1798     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1799
1800     TRACE("(%p/%p)->(%p)\n", This, iface, WindowStyleEx);
1801
1802     *WindowStyleEx = GetWindowLongA(This->hWnd, GWL_EXSTYLE);
1803
1804     return S_OK;
1805 }
1806
1807 static HRESULT WINAPI Videowindow_put_AutoShow(IVideoWindow *iface,
1808                                                long AutoShow) {
1809     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1810
1811     TRACE("(%p/%p)->(%ld)\n", This, iface, AutoShow);
1812
1813     This->AutoShow = 1; /* FXIME: Should be AutoShow */;
1814
1815     return S_OK;
1816 }
1817
1818 static HRESULT WINAPI Videowindow_get_AutoShow(IVideoWindow *iface,
1819                                                long *AutoShow) {
1820     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1821
1822     TRACE("(%p/%p)->(%p)\n", This, iface, AutoShow);
1823
1824     *AutoShow = This->AutoShow;
1825
1826     return S_OK;
1827 }
1828
1829 static HRESULT WINAPI Videowindow_put_WindowState(IVideoWindow *iface,
1830                                                   long WindowState) {
1831     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1832
1833     FIXME("(%p/%p)->(%ld): stub !!!\n", This, iface, WindowState);
1834
1835     return S_OK;
1836 }
1837
1838 static HRESULT WINAPI Videowindow_get_WindowState(IVideoWindow *iface,
1839                                                   long *WindowState) {
1840     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1841
1842     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, WindowState);
1843
1844     return S_OK;
1845 }
1846
1847 static HRESULT WINAPI Videowindow_put_BackgroundPalette(IVideoWindow *iface,
1848                                                         long BackgroundPalette) {
1849     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1850
1851     FIXME("(%p/%p)->(%ld): stub !!!\n", This, iface, BackgroundPalette);
1852
1853     return S_OK;
1854 }
1855
1856 static HRESULT WINAPI Videowindow_get_BackgroundPalette(IVideoWindow *iface,
1857                                                         long *pBackgroundPalette) {
1858     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1859
1860     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, pBackgroundPalette);
1861
1862     return S_OK;
1863 }
1864
1865 static HRESULT WINAPI Videowindow_put_Visible(IVideoWindow *iface,
1866                                               long Visible) {
1867     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1868
1869     TRACE("(%p/%p)->(%ld)\n", This, iface, Visible);
1870
1871     ShowWindow(This->hWnd, Visible ? SW_SHOW : SW_HIDE);
1872
1873     return S_OK;
1874 }
1875
1876 static HRESULT WINAPI Videowindow_get_Visible(IVideoWindow *iface,
1877                                               long *pVisible) {
1878     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1879
1880     TRACE("(%p/%p)->(%p)\n", This, iface, pVisible);
1881
1882     *pVisible = IsWindowVisible(This->hWnd);
1883
1884     return S_OK;
1885 }
1886
1887 static HRESULT WINAPI Videowindow_put_Left(IVideoWindow *iface,
1888                                            long Left) {
1889     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1890
1891     TRACE("(%p/%p)->(%ld)\n", This, iface, Left);
1892
1893     if (!SetWindowPos(This->hWnd, NULL, Left, This->WindowPos.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE))
1894         return E_FAIL;
1895
1896     This->WindowPos.left = Left;
1897
1898     return S_OK;
1899 }
1900
1901 static HRESULT WINAPI Videowindow_get_Left(IVideoWindow *iface,
1902                                            long *pLeft) {
1903     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1904
1905     TRACE("(%p/%p)->(%p)\n", This, iface, pLeft);
1906
1907     *pLeft = This->WindowPos.left;
1908
1909     return S_OK;
1910 }
1911
1912 static HRESULT WINAPI Videowindow_put_Width(IVideoWindow *iface,
1913                                             long Width) {
1914     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1915
1916     TRACE("(%p/%p)->(%ld)\n", This, iface, Width);
1917
1918     if (!SetWindowPos(This->hWnd, NULL, 0, 0, Width, This->WindowPos.bottom-This->WindowPos.top, SWP_NOZORDER|SWP_NOMOVE))
1919         return E_FAIL;
1920
1921     This->WindowPos.right = This->WindowPos.left + Width;
1922
1923     return S_OK;
1924 }
1925
1926 static HRESULT WINAPI Videowindow_get_Width(IVideoWindow *iface,
1927                                             long *pWidth) {
1928     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1929
1930     TRACE("(%p/%p)->(%p)\n", This, iface, pWidth);
1931
1932     *pWidth = This->WindowPos.right - This->WindowPos.left;
1933
1934     return S_OK;
1935 }
1936
1937 static HRESULT WINAPI Videowindow_put_Top(IVideoWindow *iface,
1938                                           long Top) {
1939     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1940
1941     TRACE("(%p/%p)->(%ld)\n", This, iface, Top);
1942
1943     if (!SetWindowPos(This->hWnd, NULL, This->WindowPos.left, Top, 0, 0, SWP_NOZORDER|SWP_NOSIZE))
1944         return E_FAIL;
1945
1946     This->WindowPos.top = Top;
1947
1948     return S_OK;
1949 }
1950
1951 static HRESULT WINAPI Videowindow_get_Top(IVideoWindow *iface,
1952                                           long *pTop) {
1953     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1954
1955     TRACE("(%p/%p)->(%p)\n", This, iface, pTop);
1956
1957     *pTop = This->WindowPos.top;
1958
1959     return S_OK;
1960 }
1961
1962 static HRESULT WINAPI Videowindow_put_Height(IVideoWindow *iface,
1963                                              long Height) {
1964     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1965
1966     TRACE("(%p/%p)->(%ld)\n", This, iface, Height);
1967
1968     if (!SetWindowPos(This->hWnd, NULL, 0, 0, This->WindowPos.right-This->WindowPos.left, Height, SWP_NOZORDER|SWP_NOMOVE))
1969         return E_FAIL;
1970
1971     This->WindowPos.bottom = This->WindowPos.top + Height;
1972
1973     return S_OK;
1974 }
1975
1976 static HRESULT WINAPI Videowindow_get_Height(IVideoWindow *iface,
1977                                              long *pHeight) {
1978     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1979
1980     TRACE("(%p/%p)->(%p)\n", This, iface, pHeight);
1981
1982     *pHeight = This->WindowPos.bottom - This->WindowPos.top;
1983
1984     return S_OK;
1985 }
1986
1987 static HRESULT WINAPI Videowindow_put_Owner(IVideoWindow *iface,
1988                                             OAHWND Owner) {
1989     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
1990
1991     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Owner);
1992
1993     SetParent(This->hWnd, (HWND)Owner);
1994
1995     return S_OK;
1996 }
1997
1998 static HRESULT WINAPI Videowindow_get_Owner(IVideoWindow *iface,
1999                                             OAHWND *Owner) {
2000     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2001
2002     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Owner);
2003
2004     *(HWND*)Owner = GetParent(This->hWnd);
2005
2006     return S_OK;
2007 }
2008
2009 static HRESULT WINAPI Videowindow_put_MessageDrain(IVideoWindow *iface,
2010                                                    OAHWND Drain) {
2011     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2012
2013     TRACE("(%p/%p)->(%08x)\n", This, iface, (DWORD) Drain);
2014
2015     This->hWndMsgDrain = (HWND)Drain;
2016
2017     return S_OK;
2018 }
2019
2020 static HRESULT WINAPI Videowindow_get_MessageDrain(IVideoWindow *iface,
2021                                                    OAHWND *Drain) {
2022     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2023
2024     TRACE("(%p/%p)->(%p)\n", This, iface, Drain);
2025
2026     *Drain = (OAHWND)This->hWndMsgDrain;
2027
2028     return S_OK;
2029 }
2030
2031 static HRESULT WINAPI Videowindow_get_BorderColor(IVideoWindow *iface,
2032                                                   long *Color) {
2033     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2034
2035     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, Color);
2036
2037     return S_OK;
2038 }
2039
2040 static HRESULT WINAPI Videowindow_put_BorderColor(IVideoWindow *iface,
2041                                                   long Color) {
2042     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2043
2044     FIXME("(%p/%p)->(%ld): stub !!!\n", This, iface, Color);
2045
2046     return S_OK;
2047 }
2048
2049 static HRESULT WINAPI Videowindow_get_FullScreenMode(IVideoWindow *iface,
2050                                                      long *FullScreenMode) {
2051     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2052
2053     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, FullScreenMode);
2054
2055     return S_OK;
2056 }
2057
2058 static HRESULT WINAPI Videowindow_put_FullScreenMode(IVideoWindow *iface,
2059                                                      long FullScreenMode) {
2060     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2061
2062     FIXME("(%p/%p)->(%ld): stub !!!\n", This, iface, FullScreenMode);
2063
2064     return S_OK;
2065 }
2066
2067 static HRESULT WINAPI Videowindow_SetWindowForeground(IVideoWindow *iface,
2068                                                       long Focus) {
2069     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2070     BOOL ret;
2071     IPin* pPin;
2072     HRESULT hr;
2073
2074     TRACE("(%p/%p)->(%ld)\n", This, iface, Focus);
2075
2076     if ((Focus != FALSE) && (Focus != TRUE))
2077         return E_INVALIDARG;
2078
2079     hr = IPin_ConnectedTo((IPin *)This->pInputPin, &pPin);
2080     if ((hr != S_OK) || !pPin)
2081         return VFW_E_NOT_CONNECTED;
2082
2083     if (Focus)
2084         ret = SetForegroundWindow(This->hWnd);
2085     else
2086         ret = SetWindowPos(This->hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
2087
2088     if (!ret)
2089         return E_FAIL;
2090
2091     return S_OK;
2092 }
2093
2094 static HRESULT WINAPI Videowindow_NotifyOwnerMessage(IVideoWindow *iface,
2095                                                      OAHWND hwnd,
2096                                                      long uMsg,
2097                                                      LONG_PTR wParam,
2098                                                      LONG_PTR lParam) {
2099     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2100
2101     TRACE("(%p/%p)->(%08x, %ld, %08lx, %08lx)\n", This, iface, (DWORD) hwnd, uMsg, wParam, lParam);
2102
2103     if (!PostMessageA(This->hWnd, uMsg, wParam, lParam))
2104         return E_FAIL;
2105     
2106     return S_OK;
2107 }
2108
2109 static HRESULT WINAPI Videowindow_SetWindowPosition(IVideoWindow *iface,
2110                                                     long Left,
2111                                                     long Top,
2112                                                     long Width,
2113                                                     long Height) {
2114     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2115     
2116     TRACE("(%p/%p)->(%ld, %ld, %ld, %ld)\n", This, iface, Left, Top, Width, Height);
2117
2118     if (!SetWindowPos(This->hWnd, NULL, Left, Top, Width, Height, SWP_NOZORDER))
2119         return E_FAIL;
2120
2121     This->WindowPos.left = Left;
2122     This->WindowPos.top = Top;
2123     This->WindowPos.right = Left + Width;
2124     This->WindowPos.bottom = Top + Height;
2125     
2126     return S_OK;
2127 }
2128
2129 static HRESULT WINAPI Videowindow_GetWindowPosition(IVideoWindow *iface,
2130                                                     long *pLeft,
2131                                                     long *pTop,
2132                                                     long *pWidth,
2133                                                     long *pHeight) {
2134     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2135
2136     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", This, iface, pLeft, pTop, pWidth, pHeight);
2137
2138     *pLeft = This->WindowPos.left;
2139     *pTop = This->WindowPos.top;
2140     *pWidth = This->WindowPos.right - This->WindowPos.left;
2141     *pHeight = This->WindowPos.bottom - This->WindowPos.top;
2142
2143     return S_OK;
2144 }
2145
2146 static HRESULT WINAPI Videowindow_GetMinIdealImageSize(IVideoWindow *iface,
2147                                                        long *pWidth,
2148                                                        long *pHeight) {
2149     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2150
2151     FIXME("(%p/%p)->(%p, %p): semi stub !!!\n", This, iface, pWidth, pHeight);
2152
2153     *pWidth = This->VideoWidth;
2154     *pHeight = This->VideoHeight;
2155
2156     return S_OK;
2157 }
2158
2159 static HRESULT WINAPI Videowindow_GetMaxIdealImageSize(IVideoWindow *iface,
2160                                                        long *pWidth,
2161                                                        long *pHeight) {
2162     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2163
2164     FIXME("(%p/%p)->(%p, %p): semi stub !!!\n", This, iface, pWidth, pHeight);
2165
2166     *pWidth = This->VideoWidth;
2167     *pHeight = This->VideoHeight;
2168
2169     return S_OK;
2170 }
2171
2172 static HRESULT WINAPI Videowindow_GetRestorePosition(IVideoWindow *iface,
2173                                                      long *pLeft,
2174                                                      long *pTop,
2175                                                      long *pWidth,
2176                                                      long *pHeight) {
2177     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2178
2179     FIXME("(%p/%p)->(%p, %p, %p, %p): stub !!!\n", This, iface, pLeft, pTop, pWidth, pHeight);
2180
2181     return S_OK;
2182 }
2183
2184 static HRESULT WINAPI Videowindow_HideCursor(IVideoWindow *iface,
2185                                              long HideCursor) {
2186     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2187
2188     FIXME("(%p/%p)->(%ld): stub !!!\n", This, iface, HideCursor);
2189
2190     return S_OK;
2191 }
2192
2193 static HRESULT WINAPI Videowindow_IsCursorHidden(IVideoWindow *iface,
2194                                                  long *CursorHidden) {
2195     ICOM_THIS_MULTI(VideoRendererImpl, IVideoWindow_vtbl, iface);
2196
2197     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, CursorHidden);
2198
2199     return S_OK;
2200 }
2201
2202 static const IVideoWindowVtbl IVideoWindow_VTable =
2203 {
2204     Videowindow_QueryInterface,
2205     Videowindow_AddRef,
2206     Videowindow_Release,
2207     Videowindow_GetTypeInfoCount,
2208     Videowindow_GetTypeInfo,
2209     Videowindow_GetIDsOfNames,
2210     Videowindow_Invoke,
2211     Videowindow_put_Caption,
2212     Videowindow_get_Caption,
2213     Videowindow_put_WindowStyle,
2214     Videowindow_get_WindowStyle,
2215     Videowindow_put_WindowStyleEx,
2216     Videowindow_get_WindowStyleEx,
2217     Videowindow_put_AutoShow,
2218     Videowindow_get_AutoShow,
2219     Videowindow_put_WindowState,
2220     Videowindow_get_WindowState,
2221     Videowindow_put_BackgroundPalette,
2222     Videowindow_get_BackgroundPalette,
2223     Videowindow_put_Visible,
2224     Videowindow_get_Visible,
2225     Videowindow_put_Left,
2226     Videowindow_get_Left,
2227     Videowindow_put_Width,
2228     Videowindow_get_Width,
2229     Videowindow_put_Top,
2230     Videowindow_get_Top,
2231     Videowindow_put_Height,
2232     Videowindow_get_Height,
2233     Videowindow_put_Owner,
2234     Videowindow_get_Owner,
2235     Videowindow_put_MessageDrain,
2236     Videowindow_get_MessageDrain,
2237     Videowindow_get_BorderColor,
2238     Videowindow_put_BorderColor,
2239     Videowindow_get_FullScreenMode,
2240     Videowindow_put_FullScreenMode,
2241     Videowindow_SetWindowForeground,
2242     Videowindow_NotifyOwnerMessage,
2243     Videowindow_SetWindowPosition,
2244     Videowindow_GetWindowPosition,
2245     Videowindow_GetMinIdealImageSize,
2246     Videowindow_GetMaxIdealImageSize,
2247     Videowindow_GetRestorePosition,
2248     Videowindow_HideCursor,
2249     Videowindow_IsCursorHidden
2250 };