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