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