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