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