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