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