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