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