quartz: Mark a bunch of functions as static.
[wine] / dlls / quartz / videorenderer.c
1 /*
2  * Video Renderer (Fullscreen and Windowed using Direct Draw)
3  *
4  * Copyright 2004 Christian Costa
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #define NONAMELESSSTRUCT
24 #define NONAMELESSUNION
25 #include "quartz_private.h"
26 #include "pin.h"
27
28 #include "uuids.h"
29 #include "vfwmsgs.h"
30 #include "amvideo.h"
31 #include "windef.h"
32 #include "winbase.h"
33 #include "dshow.h"
34 #include "evcode.h"
35 #include "strmif.h"
36 #include "ddraw.h"
37 #include "dvdmedia.h"
38
39 #include <assert.h>
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
44
45 static const IBaseFilterVtbl VideoRenderer_Vtbl;
46 static const IUnknownVtbl IInner_VTable;
47 static const IBasicVideoVtbl IBasicVideo_VTable;
48 static const IVideoWindowVtbl IVideoWindow_VTable;
49 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl;
50
51 typedef struct VideoRendererImpl
52 {
53     BaseRenderer renderer;
54     BaseControlWindow baseControlWindow;
55     BaseControlVideo baseControlVideo;
56
57     const IUnknownVtbl * IInner_vtbl;
58     const IAMFilterMiscFlagsVtbl *IAMFilterMiscFlags_vtbl;
59
60     BOOL init;
61     HANDLE hThread;
62
63     DWORD ThreadID;
64     HANDLE hEvent;
65 /* hEvent == evComplete? */
66     BOOL ThreadResult;
67     RECT SourceRect;
68     RECT DestRect;
69     RECT WindowPos;
70     LONG VideoWidth;
71     LONG VideoHeight;
72     IUnknown * pUnkOuter;
73     BOOL bUnkOuterValid;
74     BOOL bAggregatable;
75     LONG WindowStyle;
76 } VideoRendererImpl;
77
78 static inline VideoRendererImpl *impl_from_BaseWindow(BaseWindow *iface)
79 {
80     return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlWindow.baseWindow);
81 }
82
83 static inline VideoRendererImpl *impl_from_BaseRenderer(BaseRenderer *iface)
84 {
85     return CONTAINING_RECORD(iface, VideoRendererImpl, renderer);
86 }
87
88 static inline VideoRendererImpl *impl_from_IBaseFilter(IBaseFilter *iface)
89 {
90     return CONTAINING_RECORD(iface, VideoRendererImpl, renderer.filter.IBaseFilter_iface);
91 }
92
93 static inline VideoRendererImpl *impl_from_IVideoWindow(IVideoWindow *iface)
94 {
95     return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlWindow.IVideoWindow_iface);
96 }
97
98 static inline VideoRendererImpl *impl_from_BaseControlVideo(BaseControlVideo *iface)
99 {
100     return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlVideo);
101 }
102
103 static inline VideoRendererImpl *impl_from_IBasicVideo(IBasicVideo *iface)
104 {
105     return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlVideo.IBasicVideo_iface);
106 }
107
108 static DWORD WINAPI MessageLoop(LPVOID lpParameter)
109 {
110     VideoRendererImpl* This = lpParameter;
111     MSG msg; 
112     BOOL fGotMessage;
113
114     TRACE("Starting message loop\n");
115
116     if (FAILED(BaseWindowImpl_PrepareWindow(&This->baseControlWindow.baseWindow)))
117     {
118         This->ThreadResult = FALSE;
119         SetEvent(This->hEvent);
120         return 0;
121     }
122
123     This->ThreadResult = TRUE;
124     SetEvent(This->hEvent);
125
126     while ((fGotMessage = GetMessageW(&msg, NULL, 0, 0)) != 0 && fGotMessage != -1)
127     {
128         TranslateMessage(&msg); 
129         DispatchMessageW(&msg);
130     }
131
132     TRACE("End of message loop\n");
133
134     return msg.wParam;
135 }
136
137 static BOOL CreateRenderingSubsystem(VideoRendererImpl* This)
138 {
139     This->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
140     if (!This->hEvent)
141         return FALSE;
142
143     This->hThread = CreateThread(NULL, 0, MessageLoop, This, 0, &This->ThreadID);
144     if (!This->hThread)
145     {
146         CloseHandle(This->hEvent);
147         return FALSE;
148     }
149
150     WaitForSingleObject(This->hEvent, INFINITE);
151
152     if (!This->ThreadResult)
153     {
154         CloseHandle(This->hEvent);
155         CloseHandle(This->hThread);
156         return FALSE;
157     }
158
159     return TRUE;
160 }
161
162 static void VideoRenderer_AutoShowWindow(VideoRendererImpl *This) {
163     if (!This->init && (!This->WindowPos.right || !This->WindowPos.top))
164     {
165         DWORD style = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE);
166         DWORD style_ex = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_EXSTYLE);
167
168         if (!This->WindowPos.right)
169         {
170             This->WindowPos.left = This->SourceRect.left;
171             This->WindowPos.right = This->SourceRect.right;
172         }
173         if (!This->WindowPos.bottom)
174         {
175             This->WindowPos.top = This->SourceRect.top;
176             This->WindowPos.bottom = This->SourceRect.bottom;
177         }
178
179         AdjustWindowRectEx(&This->WindowPos, style, TRUE, style_ex);
180
181         TRACE("WindowPos: %d %d %d %d\n", This->WindowPos.left, This->WindowPos.top, This->WindowPos.right, This->WindowPos.bottom);
182         SetWindowPos(This->baseControlWindow.baseWindow.hWnd, NULL,
183             This->WindowPos.left,
184             This->WindowPos.top,
185             This->WindowPos.right - This->WindowPos.left,
186             This->WindowPos.bottom - This->WindowPos.top,
187             SWP_NOZORDER|SWP_NOMOVE|SWP_DEFERERASE);
188
189         GetClientRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect);
190     }
191     else if (!This->init)
192         This->DestRect = This->WindowPos;
193     This->init = TRUE;
194     if (This->baseControlWindow.AutoShow)
195         ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_SHOW);
196 }
197
198 static DWORD VideoRenderer_SendSampleData(VideoRendererImpl* This, LPBYTE data, DWORD size)
199 {
200     AM_MEDIA_TYPE amt;
201     HRESULT hr = S_OK;
202     DDSURFACEDESC sdesc;
203     BITMAPINFOHEADER *bmiHeader;
204
205     TRACE("(%p)->(%p, %d)\n", This, data, size);
206
207     sdesc.dwSize = sizeof(sdesc);
208     hr = IPin_ConnectionMediaType(&This->renderer.pInputPin->pin.IPin_iface, &amt);
209     if (FAILED(hr)) {
210         ERR("Unable to retrieve media type\n");
211         return hr;
212     }
213
214     if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo))
215     {
216         bmiHeader = &((VIDEOINFOHEADER *)amt.pbFormat)->bmiHeader;
217     }
218     else if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo2))
219     {
220         bmiHeader = &((VIDEOINFOHEADER2 *)amt.pbFormat)->bmiHeader;
221     }
222     else
223     {
224         FIXME("Unknown type %s\n", debugstr_guid(&amt.subtype));
225         return VFW_E_RUNTIME_ERROR;
226     }
227
228     TRACE("biSize = %d\n", bmiHeader->biSize);
229     TRACE("biWidth = %d\n", bmiHeader->biWidth);
230     TRACE("biHeight = %d\n", bmiHeader->biHeight);
231     TRACE("biPlanes = %d\n", bmiHeader->biPlanes);
232     TRACE("biBitCount = %d\n", bmiHeader->biBitCount);
233     TRACE("biCompression = %s\n", debugstr_an((LPSTR)&(bmiHeader->biCompression), 4));
234     TRACE("biSizeImage = %d\n", bmiHeader->biSizeImage);
235
236     if (!This->baseControlWindow.baseWindow.hDC) {
237         ERR("Cannot get DC from window!\n");
238         return E_FAIL;
239     }
240
241     TRACE("Src Rect: %d %d %d %d\n", This->SourceRect.left, This->SourceRect.top, This->SourceRect.right, This->SourceRect.bottom);
242     TRACE("Dst Rect: %d %d %d %d\n", This->DestRect.left, This->DestRect.top, This->DestRect.right, This->DestRect.bottom);
243
244     StretchDIBits(This->baseControlWindow.baseWindow.hDC, This->DestRect.left, This->DestRect.top, This->DestRect.right -This->DestRect.left,
245                   This->DestRect.bottom - This->DestRect.top, This->SourceRect.left, This->SourceRect.top,
246                   This->SourceRect.right - This->SourceRect.left, This->SourceRect.bottom - This->SourceRect.top,
247                   data, (BITMAPINFO *)bmiHeader, DIB_RGB_COLORS, SRCCOPY);
248
249     return S_OK;
250 }
251
252 static HRESULT WINAPI VideoRenderer_ShouldDrawSampleNow(BaseRenderer *This, IMediaSample *pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime)
253 {
254     /* Preroll means the sample isn't shown, this is used for key frames and things like that */
255     if (IMediaSample_IsPreroll(pSample) == S_OK)
256         return E_FAIL;
257     return S_FALSE;
258 }
259
260 static HRESULT WINAPI VideoRenderer_DoRenderSample(BaseRenderer* iface, IMediaSample * pSample)
261 {
262     VideoRendererImpl *This = impl_from_BaseRenderer(iface);
263     LPBYTE pbSrcStream = NULL;
264     LONG cbSrcStream = 0;
265     HRESULT hr;
266
267     TRACE("(%p)->(%p)\n", This, pSample);
268
269     hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
270     if (FAILED(hr))
271     {
272         ERR("Cannot get pointer to sample data (%x)\n", hr);
273         return hr;
274     }
275
276     cbSrcStream = IMediaSample_GetActualDataLength(pSample);
277
278     TRACE("val %p %d\n", pbSrcStream, cbSrcStream);
279
280 #if 0 /* For debugging purpose */
281     {
282         int i;
283         for(i = 0; i < cbSrcStream; i++)
284         {
285             if ((i!=0) && !(i%16))
286                 TRACE("\n");
287                 TRACE("%02x ", pbSrcStream[i]);
288         }
289         TRACE("\n");
290     }
291 #endif
292
293     SetEvent(This->hEvent);
294     if (This->renderer.filter.state == State_Paused)
295     {
296         VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream);
297         SetEvent(This->hEvent);
298         if (This->renderer.filter.state == State_Paused)
299         {
300             /* Flushing */
301             return S_OK;
302         }
303         if (This->renderer.filter.state == State_Stopped)
304         {
305             return VFW_E_WRONG_STATE;
306         }
307     } else {
308         VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream);
309     }
310     return S_OK;
311 }
312
313 static HRESULT WINAPI VideoRenderer_CheckMediaType(BaseRenderer *iface, const AM_MEDIA_TYPE * pmt)
314 {
315     VideoRendererImpl *This = impl_from_BaseRenderer(iface);
316
317     if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Video))
318         return S_FALSE;
319
320     if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB32) ||
321         IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB24) ||
322         IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB565) ||
323         IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB8))
324     {
325         LONG height;
326
327         if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo))
328         {
329             VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)pmt->pbFormat;
330             This->SourceRect.left = 0;
331             This->SourceRect.top = 0;
332             This->SourceRect.right = This->VideoWidth = format->bmiHeader.biWidth;
333             height = format->bmiHeader.biHeight;
334             if (height < 0)
335                 This->SourceRect.bottom = This->VideoHeight = -height;
336             else
337                 This->SourceRect.bottom = This->VideoHeight = height;
338         }
339         else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2))
340         {
341             VIDEOINFOHEADER2 *format2 = (VIDEOINFOHEADER2 *)pmt->pbFormat;
342
343             This->SourceRect.left = 0;
344             This->SourceRect.top = 0;
345             This->SourceRect.right = This->VideoWidth = format2->bmiHeader.biWidth;
346             height = format2->bmiHeader.biHeight;
347             if (height < 0)
348                 This->SourceRect.bottom = This->VideoHeight = -height;
349             else
350                 This->SourceRect.bottom = This->VideoHeight = height;
351         }
352         else
353         {
354             WARN("Format type %s not supported\n", debugstr_guid(&pmt->formattype));
355             return S_FALSE;
356         }
357         return S_OK;
358     }
359     return S_FALSE;
360 }
361
362 static HRESULT WINAPI VideoRenderer_EndFlush(BaseRenderer* iface)
363 {
364     VideoRendererImpl *This = impl_from_BaseRenderer(iface);
365
366     TRACE("(%p)->()\n", iface);
367
368     if (This->renderer.pMediaSample) {
369         ResetEvent(This->hEvent);
370         LeaveCriticalSection(iface->pInputPin->pin.pCritSec);
371         LeaveCriticalSection(&iface->csRenderLock);
372         LeaveCriticalSection(&iface->filter.csFilter);
373         WaitForSingleObject(This->hEvent, INFINITE);
374         EnterCriticalSection(&iface->filter.csFilter);
375         EnterCriticalSection(&iface->csRenderLock);
376         EnterCriticalSection(iface->pInputPin->pin.pCritSec);
377     }
378     if (This->renderer.filter.state == State_Paused) {
379         ResetEvent(This->hEvent);
380     }
381
382     return BaseRendererImpl_EndFlush(iface);
383 }
384
385 static VOID WINAPI VideoRenderer_OnStopStreaming(BaseRenderer* iface)
386 {
387     VideoRendererImpl *This = impl_from_BaseRenderer(iface);
388
389     TRACE("(%p)->()\n", This);
390
391     SetEvent(This->hEvent);
392     if (This->baseControlWindow.AutoShow)
393         /* Black it out */
394         RedrawWindow(This->baseControlWindow.baseWindow.hWnd, NULL, NULL, RDW_INVALIDATE|RDW_ERASE);
395 }
396
397 static VOID WINAPI VideoRenderer_OnStartStreaming(BaseRenderer* iface)
398 {
399     VideoRendererImpl *This = impl_from_BaseRenderer(iface);
400
401     TRACE("(%p)\n", This);
402
403     if (This->renderer.pInputPin->pin.pConnectedTo && (This->renderer.filter.state == State_Stopped || !This->renderer.pInputPin->end_of_stream))
404     {
405         if (This->renderer.filter.state == State_Stopped)
406         {
407             ResetEvent(This->hEvent);
408             VideoRenderer_AutoShowWindow(This);
409         }
410     }
411 }
412
413 static LPWSTR WINAPI VideoRenderer_GetClassWindowStyles(BaseWindow *This, DWORD *pClassStyles, DWORD *pWindowStyles, DWORD *pWindowStylesEx)
414 {
415     static const WCHAR classnameW[] = { 'W','i','n','e',' ','A','c','t','i','v','e','M','o','v','i','e',' ','C','l','a','s','s',0 };
416
417     *pClassStyles = 0;
418     *pWindowStyles = WS_SIZEBOX;
419     *pWindowStylesEx = 0;
420
421     return (LPWSTR)classnameW;
422 }
423
424 static RECT WINAPI VideoRenderer_GetDefaultRect(BaseWindow *iface)
425 {
426     VideoRendererImpl *This = impl_from_BaseWindow(iface);
427     static RECT defRect;
428
429     defRect.left = defRect.top = 0;
430     defRect.right = This->VideoWidth;
431     defRect.bottom = This->VideoHeight;
432
433     return defRect;
434 }
435
436 static BOOL WINAPI VideoRenderer_OnSize(BaseWindow *iface, LONG Width, LONG Height)
437 {
438     VideoRendererImpl *This = impl_from_BaseWindow(iface);
439
440     TRACE("WM_SIZE %d %d\n", Width, Height);
441     GetClientRect(iface->hWnd, &This->DestRect);
442     TRACE("WM_SIZING: DestRect=(%d,%d),(%d,%d)\n",
443         This->DestRect.left,
444         This->DestRect.top,
445         This->DestRect.right - This->DestRect.left,
446         This->DestRect.bottom - This->DestRect.top);
447     return BaseWindowImpl_OnSize(iface, Width, Height);
448 }
449
450 static const BaseRendererFuncTable BaseFuncTable = {
451     VideoRenderer_CheckMediaType,
452     VideoRenderer_DoRenderSample,
453     /**/
454     NULL,
455     NULL,
456     NULL,
457     VideoRenderer_OnStartStreaming,
458     VideoRenderer_OnStopStreaming,
459     NULL,
460     NULL,
461     NULL,
462     VideoRenderer_ShouldDrawSampleNow,
463     NULL,
464     /**/
465     NULL,
466     NULL,
467     NULL,
468     NULL,
469     VideoRenderer_EndFlush,
470 };
471
472 static const BaseWindowFuncTable renderer_BaseWindowFuncTable = {
473     VideoRenderer_GetClassWindowStyles,
474     VideoRenderer_GetDefaultRect,
475     NULL,
476     BaseControlWindowImpl_PossiblyEatMessage,
477     VideoRenderer_OnSize
478 };
479
480 static HRESULT WINAPI VideoRenderer_GetSourceRect(BaseControlVideo* iface, RECT *pSourceRect)
481 {
482     VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
483     CopyRect(pSourceRect,&This->SourceRect);
484     return S_OK;
485 }
486
487 static HRESULT WINAPI VideoRenderer_GetStaticImage(BaseControlVideo* iface, LONG *pBufferSize, LONG *pDIBImage)
488 {
489     VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
490     BITMAPINFOHEADER *bmiHeader;
491     LONG needed_size;
492     AM_MEDIA_TYPE *amt = &This->renderer.pInputPin->pin.mtCurrent;
493     char *ptr;
494
495     FIXME("(%p/%p)->(%p, %p): partial stub\n", This, iface, pBufferSize, pDIBImage);
496
497     EnterCriticalSection(&This->renderer.filter.csFilter);
498
499     if (!This->renderer.pMediaSample)
500     {
501          LeaveCriticalSection(&This->renderer.filter.csFilter);
502          return (This->renderer.filter.state == State_Paused ? E_UNEXPECTED : VFW_E_NOT_PAUSED);
503     }
504
505     if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo))
506     {
507         bmiHeader = &((VIDEOINFOHEADER *)amt->pbFormat)->bmiHeader;
508     }
509     else if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo2))
510     {
511         bmiHeader = &((VIDEOINFOHEADER2 *)amt->pbFormat)->bmiHeader;
512     }
513     else
514     {
515         FIXME("Unknown type %s\n", debugstr_guid(&amt->subtype));
516         LeaveCriticalSection(&This->renderer.filter.csFilter);
517         return VFW_E_RUNTIME_ERROR;
518     }
519
520     needed_size = bmiHeader->biSize;
521     needed_size += IMediaSample_GetActualDataLength(This->renderer.pMediaSample);
522
523     if (!pDIBImage)
524     {
525         *pBufferSize = needed_size;
526         LeaveCriticalSection(&This->renderer.filter.csFilter);
527         return S_OK;
528     }
529
530     if (needed_size < *pBufferSize)
531     {
532         ERR("Buffer too small %u/%u\n", needed_size, *pBufferSize);
533         LeaveCriticalSection(&This->renderer.filter.csFilter);
534         return E_FAIL;
535     }
536     *pBufferSize = needed_size;
537
538     memcpy(pDIBImage, bmiHeader, bmiHeader->biSize);
539     IMediaSample_GetPointer(This->renderer.pMediaSample, (BYTE **)&ptr);
540     memcpy((char *)pDIBImage + bmiHeader->biSize, ptr, IMediaSample_GetActualDataLength(This->renderer.pMediaSample));
541
542     LeaveCriticalSection(&This->renderer.filter.csFilter);
543     return S_OK;
544 }
545
546 static HRESULT WINAPI VideoRenderer_GetTargetRect(BaseControlVideo* iface, RECT *pTargetRect)
547 {
548     VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
549     CopyRect(pTargetRect,&This->DestRect);
550     return S_OK;
551 }
552
553 static VIDEOINFOHEADER* WINAPI VideoRenderer_GetVideoFormat(BaseControlVideo* iface)
554 {
555     VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
556     AM_MEDIA_TYPE *pmt;
557
558     TRACE("(%p/%p)\n", This, iface);
559
560     pmt = &This->renderer.pInputPin->pin.mtCurrent;
561     if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) {
562         return (VIDEOINFOHEADER*)pmt->pbFormat;
563     } else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2)) {
564         static VIDEOINFOHEADER vih;
565         VIDEOINFOHEADER2 *vih2 = (VIDEOINFOHEADER2*)pmt->pbFormat;
566         memcpy(&vih,vih2,sizeof(VIDEOINFOHEADER));
567         memcpy(&vih.bmiHeader, &vih2->bmiHeader, sizeof(BITMAPINFOHEADER));
568         return &vih;
569     } else {
570         ERR("Unknown format type %s\n", qzdebugstr_guid(&pmt->formattype));
571         return NULL;
572     }
573 }
574
575 static HRESULT WINAPI VideoRenderer_IsDefaultSourceRect(BaseControlVideo* iface)
576 {
577     VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
578     FIXME("(%p/%p)->(): stub !!!\n", This, iface);
579
580     return S_OK;
581 }
582
583 static HRESULT WINAPI VideoRenderer_IsDefaultTargetRect(BaseControlVideo* iface)
584 {
585     VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
586     FIXME("(%p/%p)->(): stub !!!\n", This, iface);
587
588     return S_OK;
589 }
590
591 static HRESULT WINAPI VideoRenderer_SetDefaultSourceRect(BaseControlVideo* iface)
592 {
593     VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
594
595     This->SourceRect.left = 0;
596     This->SourceRect.top = 0;
597     This->SourceRect.right = This->VideoWidth;
598     This->SourceRect.bottom = This->VideoHeight;
599
600     return S_OK;
601 }
602
603 static HRESULT WINAPI VideoRenderer_SetDefaultTargetRect(BaseControlVideo* iface)
604 {
605     VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
606     RECT rect;
607
608     if (!GetClientRect(This->baseControlWindow.baseWindow.hWnd, &rect))
609         return E_FAIL;
610
611     This->SourceRect.left = 0;
612     This->SourceRect.top = 0;
613     This->SourceRect.right = rect.right;
614     This->SourceRect.bottom = rect.bottom;
615
616     return S_OK;
617 }
618
619 static HRESULT WINAPI VideoRenderer_SetSourceRect(BaseControlVideo* iface, RECT *pSourceRect)
620 {
621     VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
622     CopyRect(&This->SourceRect,pSourceRect);
623     return S_OK;
624 }
625
626 static HRESULT WINAPI VideoRenderer_SetTargetRect(BaseControlVideo* iface, RECT *pTargetRect)
627 {
628     VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
629     CopyRect(&This->DestRect,pTargetRect);
630     return S_OK;
631 }
632
633 static const BaseControlVideoFuncTable renderer_BaseControlVideoFuncTable = {
634     VideoRenderer_GetSourceRect,
635     VideoRenderer_GetStaticImage,
636     VideoRenderer_GetTargetRect,
637     VideoRenderer_GetVideoFormat,
638     VideoRenderer_IsDefaultSourceRect,
639     VideoRenderer_IsDefaultTargetRect,
640     VideoRenderer_SetDefaultSourceRect,
641     VideoRenderer_SetDefaultTargetRect,
642     VideoRenderer_SetSourceRect,
643     VideoRenderer_SetTargetRect
644 };
645
646 HRESULT VideoRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv)
647 {
648     HRESULT hr;
649     VideoRendererImpl * pVideoRenderer;
650
651     TRACE("(%p, %p)\n", pUnkOuter, ppv);
652
653     *ppv = NULL;
654
655     pVideoRenderer = CoTaskMemAlloc(sizeof(VideoRendererImpl));
656     pVideoRenderer->pUnkOuter = pUnkOuter;
657     pVideoRenderer->bUnkOuterValid = FALSE;
658     pVideoRenderer->bAggregatable = FALSE;
659     pVideoRenderer->IInner_vtbl = &IInner_VTable;
660     pVideoRenderer->IAMFilterMiscFlags_vtbl = &IAMFilterMiscFlags_Vtbl;
661
662     pVideoRenderer->init = 0;
663     ZeroMemory(&pVideoRenderer->SourceRect, sizeof(RECT));
664     ZeroMemory(&pVideoRenderer->DestRect, sizeof(RECT));
665     ZeroMemory(&pVideoRenderer->WindowPos, sizeof(RECT));
666
667     hr = BaseRenderer_Init(&pVideoRenderer->renderer, &VideoRenderer_Vtbl, pUnkOuter, &CLSID_VideoRenderer, (DWORD_PTR)(__FILE__ ": VideoRendererImpl.csFilter"), &BaseFuncTable);
668
669     if (FAILED(hr))
670         goto fail;
671
672     *ppv = pVideoRenderer;
673
674     hr = BaseControlWindow_Init(&pVideoRenderer->baseControlWindow, &IVideoWindow_VTable, &pVideoRenderer->renderer.filter, &pVideoRenderer->renderer.filter.csFilter, &pVideoRenderer->renderer.pInputPin->pin, &renderer_BaseWindowFuncTable);
675     if (FAILED(hr))
676         goto fail;
677
678     hr = BaseControlVideo_Init(&pVideoRenderer->baseControlVideo, &IBasicVideo_VTable, &pVideoRenderer->renderer.filter, &pVideoRenderer->renderer.filter.csFilter, &pVideoRenderer->renderer.pInputPin->pin, &renderer_BaseControlVideoFuncTable);
679     if (FAILED(hr))
680         goto fail;
681
682     if (!CreateRenderingSubsystem(pVideoRenderer))
683         return E_FAIL;
684
685     return hr;
686 fail:
687     BaseRendererImpl_Release(&pVideoRenderer->renderer.filter.IBaseFilter_iface);
688     CoTaskMemFree(pVideoRenderer);
689     return hr;
690 }
691
692 HRESULT VideoRendererDefault_create(IUnknown * pUnkOuter, LPVOID * ppv)
693 {
694     /* TODO: Attempt to use the VMR-7 renderer instead when possible */
695     return VideoRenderer_create(pUnkOuter, ppv);
696 }
697
698 static HRESULT WINAPI VideoRendererInner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
699 {
700     ICOM_THIS_MULTI(VideoRendererImpl, IInner_vtbl, iface);
701     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
702
703     if (This->bAggregatable)
704         This->bUnkOuterValid = TRUE;
705
706     *ppv = NULL;
707
708     if (IsEqualIID(riid, &IID_IUnknown))
709         *ppv = &This->IInner_vtbl;
710     else if (IsEqualIID(riid, &IID_IBasicVideo))
711         *ppv = &This->baseControlVideo.IBasicVideo_iface;
712     else if (IsEqualIID(riid, &IID_IVideoWindow))
713         *ppv = &This->baseControlWindow.IVideoWindow_iface;
714     else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags))
715         *ppv = &This->IAMFilterMiscFlags_vtbl;
716     else
717     {
718         HRESULT hr;
719         hr = BaseRendererImpl_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
720         if (SUCCEEDED(hr))
721             return hr;
722     }
723
724     if (*ppv)
725     {
726         IUnknown_AddRef((IUnknown *)(*ppv));
727         return S_OK;
728     }
729
730     if (!IsEqualIID(riid, &IID_IPin))
731         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
732
733     return E_NOINTERFACE;
734 }
735
736 static ULONG WINAPI VideoRendererInner_AddRef(IUnknown * iface)
737 {
738     ICOM_THIS_MULTI(VideoRendererImpl, IInner_vtbl, iface);
739     ULONG refCount = BaseFilterImpl_AddRef(&This->renderer.filter.IBaseFilter_iface);
740
741     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
742
743     return refCount;
744 }
745
746 static ULONG WINAPI VideoRendererInner_Release(IUnknown * iface)
747 {
748     ICOM_THIS_MULTI(VideoRendererImpl, IInner_vtbl, iface);
749     ULONG refCount = BaseRendererImpl_Release(&This->renderer.filter.IBaseFilter_iface);
750
751     TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
752
753     if (!refCount)
754     {
755         BaseWindowImpl_DoneWithWindow(&This->baseControlWindow.baseWindow);
756         PostThreadMessageW(This->ThreadID, WM_QUIT, 0, 0);
757         WaitForSingleObject(This->hThread, INFINITE);
758         CloseHandle(This->hThread);
759         CloseHandle(This->hEvent);
760
761         TRACE("Destroying Video Renderer\n");
762         CoTaskMemFree(This);
763
764         return 0;
765     }
766     else
767         return refCount;
768 }
769
770 static const IUnknownVtbl IInner_VTable =
771 {
772     VideoRendererInner_QueryInterface,
773     VideoRendererInner_AddRef,
774     VideoRendererInner_Release
775 };
776
777 static HRESULT WINAPI VideoRenderer_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
778 {
779     VideoRendererImpl *This = impl_from_IBaseFilter(iface);
780
781     if (This->bAggregatable)
782         This->bUnkOuterValid = TRUE;
783
784     if (This->pUnkOuter)
785     {
786         if (This->bAggregatable)
787             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
788
789         if (IsEqualIID(riid, &IID_IUnknown))
790         {
791             HRESULT hr;
792
793             IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
794             hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
795             IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
796             This->bAggregatable = TRUE;
797             return hr;
798         }
799
800         *ppv = NULL;
801         return E_NOINTERFACE;
802     }
803
804     return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
805 }
806
807 static ULONG WINAPI VideoRenderer_AddRef(IBaseFilter * iface)
808 {
809     VideoRendererImpl *This = impl_from_IBaseFilter(iface);
810
811     if (This->pUnkOuter && This->bUnkOuterValid)
812         return IUnknown_AddRef(This->pUnkOuter);
813     return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
814 }
815
816 static ULONG WINAPI VideoRenderer_Release(IBaseFilter * iface)
817 {
818     VideoRendererImpl *This = impl_from_IBaseFilter(iface);
819
820     if (This->pUnkOuter && This->bUnkOuterValid)
821         return IUnknown_Release(This->pUnkOuter);
822     return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
823 }
824
825 /** IMediaFilter methods **/
826
827 static HRESULT WINAPI VideoRenderer_Pause(IBaseFilter * iface)
828 {
829     VideoRendererImpl *This = impl_from_IBaseFilter(iface);
830     
831     TRACE("(%p/%p)->()\n", This, iface);
832
833     EnterCriticalSection(&This->renderer.csRenderLock);
834     if (This->renderer.filter.state != State_Paused)
835     {
836         if (This->renderer.filter.state == State_Stopped)
837         {
838             This->renderer.pInputPin->end_of_stream = 0;
839             ResetEvent(This->hEvent);
840             VideoRenderer_AutoShowWindow(This);
841         }
842
843         ResetEvent(This->renderer.RenderEvent);
844         This->renderer.filter.state = State_Paused;
845     }
846     LeaveCriticalSection(&This->renderer.csRenderLock);
847
848     return S_OK;
849 }
850
851 static const IBaseFilterVtbl VideoRenderer_Vtbl =
852 {
853     VideoRenderer_QueryInterface,
854     VideoRenderer_AddRef,
855     VideoRenderer_Release,
856     BaseFilterImpl_GetClassID,
857     BaseRendererImpl_Stop,
858     VideoRenderer_Pause,
859     BaseRendererImpl_Run,
860     BaseRendererImpl_GetState,
861     BaseRendererImpl_SetSyncSource,
862     BaseFilterImpl_GetSyncSource,
863     BaseFilterImpl_EnumPins,
864     BaseRendererImpl_FindPin,
865     BaseFilterImpl_QueryFilterInfo,
866     BaseFilterImpl_JoinFilterGraph,
867     BaseFilterImpl_QueryVendorInfo
868 };
869
870 /*** IUnknown methods ***/
871 static HRESULT WINAPI Basicvideo_QueryInterface(IBasicVideo *iface,
872                                                 REFIID riid,
873                                                 LPVOID*ppvObj) {
874     VideoRendererImpl *This = impl_from_IBasicVideo(iface);
875
876     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
877
878     return VideoRenderer_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppvObj);
879 }
880
881 static ULONG WINAPI Basicvideo_AddRef(IBasicVideo *iface) {
882     VideoRendererImpl *This = impl_from_IBasicVideo(iface);
883
884     TRACE("(%p/%p)->()\n", This, iface);
885
886     return VideoRenderer_AddRef(&This->renderer.filter.IBaseFilter_iface);
887 }
888
889 static ULONG WINAPI Basicvideo_Release(IBasicVideo *iface) {
890     VideoRendererImpl *This = impl_from_IBasicVideo(iface);
891
892     TRACE("(%p/%p)->()\n", This, iface);
893
894     return VideoRenderer_Release(&This->renderer.filter.IBaseFilter_iface);
895 }
896
897 static const IBasicVideoVtbl IBasicVideo_VTable =
898 {
899     Basicvideo_QueryInterface,
900     Basicvideo_AddRef,
901     Basicvideo_Release,
902     BaseControlVideoImpl_GetTypeInfoCount,
903     BaseControlVideoImpl_GetTypeInfo,
904     BaseControlVideoImpl_GetIDsOfNames,
905     BaseControlVideoImpl_Invoke,
906     BaseControlVideoImpl_get_AvgTimePerFrame,
907     BaseControlVideoImpl_get_BitRate,
908     BaseControlVideoImpl_get_BitErrorRate,
909     BaseControlVideoImpl_get_VideoWidth,
910     BaseControlVideoImpl_get_VideoHeight,
911     BaseControlVideoImpl_put_SourceLeft,
912     BaseControlVideoImpl_get_SourceLeft,
913     BaseControlVideoImpl_put_SourceWidth,
914     BaseControlVideoImpl_get_SourceWidth,
915     BaseControlVideoImpl_put_SourceTop,
916     BaseControlVideoImpl_get_SourceTop,
917     BaseControlVideoImpl_put_SourceHeight,
918     BaseControlVideoImpl_get_SourceHeight,
919     BaseControlVideoImpl_put_DestinationLeft,
920     BaseControlVideoImpl_get_DestinationLeft,
921     BaseControlVideoImpl_put_DestinationWidth,
922     BaseControlVideoImpl_get_DestinationWidth,
923     BaseControlVideoImpl_put_DestinationTop,
924     BaseControlVideoImpl_get_DestinationTop,
925     BaseControlVideoImpl_put_DestinationHeight,
926     BaseControlVideoImpl_get_DestinationHeight,
927     BaseControlVideoImpl_SetSourcePosition,
928     BaseControlVideoImpl_GetSourcePosition,
929     BaseControlVideoImpl_SetDefaultSourcePosition,
930     BaseControlVideoImpl_SetDestinationPosition,
931     BaseControlVideoImpl_GetDestinationPosition,
932     BaseControlVideoImpl_SetDefaultDestinationPosition,
933     BaseControlVideoImpl_GetVideoSize,
934     BaseControlVideoImpl_GetVideoPaletteEntries,
935     BaseControlVideoImpl_GetCurrentImage,
936     BaseControlVideoImpl_IsUsingDefaultSource,
937     BaseControlVideoImpl_IsUsingDefaultDestination
938 };
939
940
941 /*** IUnknown methods ***/
942 static HRESULT WINAPI Videowindow_QueryInterface(IVideoWindow *iface,
943                                                  REFIID riid,
944                                                  LPVOID*ppvObj) {
945     VideoRendererImpl *This = impl_from_IVideoWindow(iface);
946
947     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
948
949     return VideoRenderer_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppvObj);
950 }
951
952 static ULONG WINAPI Videowindow_AddRef(IVideoWindow *iface) {
953     VideoRendererImpl *This = impl_from_IVideoWindow(iface);
954
955     TRACE("(%p/%p)->()\n", This, iface);
956
957     return VideoRenderer_AddRef(&This->renderer.filter.IBaseFilter_iface);
958 }
959
960 static ULONG WINAPI Videowindow_Release(IVideoWindow *iface) {
961     VideoRendererImpl *This = impl_from_IVideoWindow(iface);
962
963     TRACE("(%p/%p)->()\n", This, iface);
964
965     return VideoRenderer_Release(&This->renderer.filter.IBaseFilter_iface);
966 }
967
968 static HRESULT WINAPI Videowindow_get_FullScreenMode(IVideoWindow *iface,
969                                                      LONG *FullScreenMode) {
970     VideoRendererImpl *This = impl_from_IVideoWindow(iface);
971
972     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, FullScreenMode);
973
974     return S_OK;
975 }
976
977 static HRESULT WINAPI Videowindow_put_FullScreenMode(IVideoWindow *iface,
978                                                      LONG FullScreenMode) {
979     VideoRendererImpl *This = impl_from_IVideoWindow(iface);
980
981     FIXME("(%p/%p)->(%d): stub !!!\n", This, iface, FullScreenMode);
982
983     if (FullScreenMode) {
984         This->WindowStyle = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE);
985         ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_HIDE);
986         SetParent(This->baseControlWindow.baseWindow.hWnd, 0);
987         SetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE, WS_POPUP);
988         SetWindowPos(This->baseControlWindow.baseWindow.hWnd,HWND_TOP,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN),SWP_SHOWWINDOW);
989         GetWindowRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect);
990         This->WindowPos = This->DestRect;
991     } else {
992         ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_HIDE);
993         SetParent(This->baseControlWindow.baseWindow.hWnd, This->baseControlWindow.hwndOwner);
994         SetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE, This->WindowStyle);
995         GetClientRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect);
996         SetWindowPos(This->baseControlWindow.baseWindow.hWnd,0,This->DestRect.left,This->DestRect.top,This->DestRect.right,This->DestRect.bottom,SWP_NOZORDER|SWP_SHOWWINDOW);
997         This->WindowPos = This->DestRect;
998     }
999
1000     return S_OK;
1001 }
1002
1003 static const IVideoWindowVtbl IVideoWindow_VTable =
1004 {
1005     Videowindow_QueryInterface,
1006     Videowindow_AddRef,
1007     Videowindow_Release,
1008     BaseControlWindowImpl_GetTypeInfoCount,
1009     BaseControlWindowImpl_GetTypeInfo,
1010     BaseControlWindowImpl_GetIDsOfNames,
1011     BaseControlWindowImpl_Invoke,
1012     BaseControlWindowImpl_put_Caption,
1013     BaseControlWindowImpl_get_Caption,
1014     BaseControlWindowImpl_put_WindowStyle,
1015     BaseControlWindowImpl_get_WindowStyle,
1016     BaseControlWindowImpl_put_WindowStyleEx,
1017     BaseControlWindowImpl_get_WindowStyleEx,
1018     BaseControlWindowImpl_put_AutoShow,
1019     BaseControlWindowImpl_get_AutoShow,
1020     BaseControlWindowImpl_put_WindowState,
1021     BaseControlWindowImpl_get_WindowState,
1022     BaseControlWindowImpl_put_BackgroundPalette,
1023     BaseControlWindowImpl_get_BackgroundPalette,
1024     BaseControlWindowImpl_put_Visible,
1025     BaseControlWindowImpl_get_Visible,
1026     BaseControlWindowImpl_put_Left,
1027     BaseControlWindowImpl_get_Left,
1028     BaseControlWindowImpl_put_Width,
1029     BaseControlWindowImpl_get_Width,
1030     BaseControlWindowImpl_put_Top,
1031     BaseControlWindowImpl_get_Top,
1032     BaseControlWindowImpl_put_Height,
1033     BaseControlWindowImpl_get_Height,
1034     BaseControlWindowImpl_put_Owner,
1035     BaseControlWindowImpl_get_Owner,
1036     BaseControlWindowImpl_put_MessageDrain,
1037     BaseControlWindowImpl_get_MessageDrain,
1038     BaseControlWindowImpl_get_BorderColor,
1039     BaseControlWindowImpl_put_BorderColor,
1040     Videowindow_get_FullScreenMode,
1041     Videowindow_put_FullScreenMode,
1042     BaseControlWindowImpl_SetWindowForeground,
1043     BaseControlWindowImpl_NotifyOwnerMessage,
1044     BaseControlWindowImpl_SetWindowPosition,
1045     BaseControlWindowImpl_GetWindowPosition,
1046     BaseControlWindowImpl_GetMinIdealImageSize,
1047     BaseControlWindowImpl_GetMaxIdealImageSize,
1048     BaseControlWindowImpl_GetRestorePosition,
1049     BaseControlWindowImpl_HideCursor,
1050     BaseControlWindowImpl_IsCursorHidden
1051 };
1052
1053 static VideoRendererImpl *from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface) {
1054     return (VideoRendererImpl*)((char*)iface - offsetof(VideoRendererImpl, IAMFilterMiscFlags_vtbl));
1055 }
1056
1057 static HRESULT WINAPI AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, void **ppv) {
1058     VideoRendererImpl *This = from_IAMFilterMiscFlags(iface);
1059     return IUnknown_QueryInterface((IUnknown*)This, riid, ppv);
1060 }
1061
1062 static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface) {
1063     VideoRendererImpl *This = from_IAMFilterMiscFlags(iface);
1064     return IUnknown_AddRef((IUnknown*)This);
1065 }
1066
1067 static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface) {
1068     VideoRendererImpl *This = from_IAMFilterMiscFlags(iface);
1069     return IUnknown_Release((IUnknown*)This);
1070 }
1071
1072 static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface) {
1073     return AM_FILTER_MISC_FLAGS_IS_RENDERER;
1074 }
1075
1076 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = {
1077     AMFilterMiscFlags_QueryInterface,
1078     AMFilterMiscFlags_AddRef,
1079     AMFilterMiscFlags_Release,
1080     AMFilterMiscFlags_GetMiscFlags
1081 };