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