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