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