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