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