oleaut32: Add a test for loading/saving an empty picture.
[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     VideoRendererImpl *This = impl_from_IBasicVideo(iface);
810
811     TRACE("(%p/%p)->()\n", This, iface);
812
813     return IUnknown_AddRef(This->outer_unk);
814 }
815
816 static ULONG WINAPI Basicvideo_Release(IBasicVideo *iface) {
817     VideoRendererImpl *This = impl_from_IBasicVideo(iface);
818
819     TRACE("(%p/%p)->()\n", This, iface);
820
821     return IUnknown_Release(This->outer_unk);
822 }
823
824 static const IBasicVideoVtbl IBasicVideo_VTable =
825 {
826     Basicvideo_QueryInterface,
827     Basicvideo_AddRef,
828     Basicvideo_Release,
829     BaseControlVideoImpl_GetTypeInfoCount,
830     BaseControlVideoImpl_GetTypeInfo,
831     BaseControlVideoImpl_GetIDsOfNames,
832     BaseControlVideoImpl_Invoke,
833     BaseControlVideoImpl_get_AvgTimePerFrame,
834     BaseControlVideoImpl_get_BitRate,
835     BaseControlVideoImpl_get_BitErrorRate,
836     BaseControlVideoImpl_get_VideoWidth,
837     BaseControlVideoImpl_get_VideoHeight,
838     BaseControlVideoImpl_put_SourceLeft,
839     BaseControlVideoImpl_get_SourceLeft,
840     BaseControlVideoImpl_put_SourceWidth,
841     BaseControlVideoImpl_get_SourceWidth,
842     BaseControlVideoImpl_put_SourceTop,
843     BaseControlVideoImpl_get_SourceTop,
844     BaseControlVideoImpl_put_SourceHeight,
845     BaseControlVideoImpl_get_SourceHeight,
846     BaseControlVideoImpl_put_DestinationLeft,
847     BaseControlVideoImpl_get_DestinationLeft,
848     BaseControlVideoImpl_put_DestinationWidth,
849     BaseControlVideoImpl_get_DestinationWidth,
850     BaseControlVideoImpl_put_DestinationTop,
851     BaseControlVideoImpl_get_DestinationTop,
852     BaseControlVideoImpl_put_DestinationHeight,
853     BaseControlVideoImpl_get_DestinationHeight,
854     BaseControlVideoImpl_SetSourcePosition,
855     BaseControlVideoImpl_GetSourcePosition,
856     BaseControlVideoImpl_SetDefaultSourcePosition,
857     BaseControlVideoImpl_SetDestinationPosition,
858     BaseControlVideoImpl_GetDestinationPosition,
859     BaseControlVideoImpl_SetDefaultDestinationPosition,
860     BaseControlVideoImpl_GetVideoSize,
861     BaseControlVideoImpl_GetVideoPaletteEntries,
862     BaseControlVideoImpl_GetCurrentImage,
863     BaseControlVideoImpl_IsUsingDefaultSource,
864     BaseControlVideoImpl_IsUsingDefaultDestination
865 };
866
867
868 /*** IUnknown methods ***/
869 static HRESULT WINAPI Videowindow_QueryInterface(IVideoWindow *iface, REFIID riid, LPVOID *ppvObj)
870 {
871     VideoRendererImpl *This = impl_from_IVideoWindow(iface);
872
873     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
874
875     return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
876 }
877
878 static ULONG WINAPI Videowindow_AddRef(IVideoWindow *iface) {
879     VideoRendererImpl *This = impl_from_IVideoWindow(iface);
880
881     TRACE("(%p/%p)->()\n", This, iface);
882
883     return IUnknown_AddRef(This->outer_unk);
884 }
885
886 static ULONG WINAPI Videowindow_Release(IVideoWindow *iface) {
887     VideoRendererImpl *This = impl_from_IVideoWindow(iface);
888
889     TRACE("(%p/%p)->()\n", This, iface);
890
891     return IUnknown_Release(This->outer_unk);
892 }
893
894 static HRESULT WINAPI Videowindow_get_FullScreenMode(IVideoWindow *iface,
895                                                      LONG *FullScreenMode) {
896     VideoRendererImpl *This = impl_from_IVideoWindow(iface);
897
898     FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, FullScreenMode);
899
900     return S_OK;
901 }
902
903 static HRESULT WINAPI Videowindow_put_FullScreenMode(IVideoWindow *iface,
904                                                      LONG FullScreenMode) {
905     VideoRendererImpl *This = impl_from_IVideoWindow(iface);
906
907     FIXME("(%p/%p)->(%d): stub !!!\n", This, iface, FullScreenMode);
908
909     if (FullScreenMode) {
910         This->baseControlWindow.baseWindow.WindowStyles = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE);
911         ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_HIDE);
912         SetParent(This->baseControlWindow.baseWindow.hWnd, 0);
913         SetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE, WS_POPUP);
914         SetWindowPos(This->baseControlWindow.baseWindow.hWnd,HWND_TOP,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN),SWP_SHOWWINDOW);
915         GetWindowRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect);
916         This->WindowPos = This->DestRect;
917     } else {
918         ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_HIDE);
919         SetParent(This->baseControlWindow.baseWindow.hWnd, This->baseControlWindow.hwndOwner);
920         SetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE, This->baseControlWindow.baseWindow.WindowStyles);
921         GetClientRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect);
922         SetWindowPos(This->baseControlWindow.baseWindow.hWnd,0,This->DestRect.left,This->DestRect.top,This->DestRect.right,This->DestRect.bottom,SWP_NOZORDER|SWP_SHOWWINDOW);
923         This->WindowPos = This->DestRect;
924     }
925
926     return S_OK;
927 }
928
929 static const IVideoWindowVtbl IVideoWindow_VTable =
930 {
931     Videowindow_QueryInterface,
932     Videowindow_AddRef,
933     Videowindow_Release,
934     BaseControlWindowImpl_GetTypeInfoCount,
935     BaseControlWindowImpl_GetTypeInfo,
936     BaseControlWindowImpl_GetIDsOfNames,
937     BaseControlWindowImpl_Invoke,
938     BaseControlWindowImpl_put_Caption,
939     BaseControlWindowImpl_get_Caption,
940     BaseControlWindowImpl_put_WindowStyle,
941     BaseControlWindowImpl_get_WindowStyle,
942     BaseControlWindowImpl_put_WindowStyleEx,
943     BaseControlWindowImpl_get_WindowStyleEx,
944     BaseControlWindowImpl_put_AutoShow,
945     BaseControlWindowImpl_get_AutoShow,
946     BaseControlWindowImpl_put_WindowState,
947     BaseControlWindowImpl_get_WindowState,
948     BaseControlWindowImpl_put_BackgroundPalette,
949     BaseControlWindowImpl_get_BackgroundPalette,
950     BaseControlWindowImpl_put_Visible,
951     BaseControlWindowImpl_get_Visible,
952     BaseControlWindowImpl_put_Left,
953     BaseControlWindowImpl_get_Left,
954     BaseControlWindowImpl_put_Width,
955     BaseControlWindowImpl_get_Width,
956     BaseControlWindowImpl_put_Top,
957     BaseControlWindowImpl_get_Top,
958     BaseControlWindowImpl_put_Height,
959     BaseControlWindowImpl_get_Height,
960     BaseControlWindowImpl_put_Owner,
961     BaseControlWindowImpl_get_Owner,
962     BaseControlWindowImpl_put_MessageDrain,
963     BaseControlWindowImpl_get_MessageDrain,
964     BaseControlWindowImpl_get_BorderColor,
965     BaseControlWindowImpl_put_BorderColor,
966     Videowindow_get_FullScreenMode,
967     Videowindow_put_FullScreenMode,
968     BaseControlWindowImpl_SetWindowForeground,
969     BaseControlWindowImpl_NotifyOwnerMessage,
970     BaseControlWindowImpl_SetWindowPosition,
971     BaseControlWindowImpl_GetWindowPosition,
972     BaseControlWindowImpl_GetMinIdealImageSize,
973     BaseControlWindowImpl_GetMaxIdealImageSize,
974     BaseControlWindowImpl_GetRestorePosition,
975     BaseControlWindowImpl_HideCursor,
976     BaseControlWindowImpl_IsCursorHidden
977 };
978
979 static VideoRendererImpl *impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface)
980 {
981     return CONTAINING_RECORD(iface, VideoRendererImpl, IAMFilterMiscFlags_iface);
982 }
983
984 static HRESULT WINAPI AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid,
985         void **ppv)
986 {
987     VideoRendererImpl *This = impl_from_IAMFilterMiscFlags(iface);
988     return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
989 }
990
991 static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface)
992 {
993     VideoRendererImpl *This = impl_from_IAMFilterMiscFlags(iface);
994     return IUnknown_AddRef(This->outer_unk);
995 }
996
997 static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface)
998 {
999     VideoRendererImpl *This = impl_from_IAMFilterMiscFlags(iface);
1000     return IUnknown_Release(This->outer_unk);
1001 }
1002
1003 static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface)
1004 {
1005     return AM_FILTER_MISC_FLAGS_IS_RENDERER;
1006 }
1007
1008 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = {
1009     AMFilterMiscFlags_QueryInterface,
1010     AMFilterMiscFlags_AddRef,
1011     AMFilterMiscFlags_Release,
1012     AMFilterMiscFlags_GetMiscFlags
1013 };
1014
1015 HRESULT VideoRenderer_create(IUnknown *pUnkOuter, void **ppv)
1016 {
1017     HRESULT hr;
1018     VideoRendererImpl * pVideoRenderer;
1019
1020     TRACE("(%p, %p)\n", pUnkOuter, ppv);
1021
1022     *ppv = NULL;
1023
1024     pVideoRenderer = CoTaskMemAlloc(sizeof(VideoRendererImpl));
1025     pVideoRenderer->IUnknown_inner.lpVtbl = &IInner_VTable;
1026     pVideoRenderer->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_Vtbl;
1027
1028     pVideoRenderer->init = 0;
1029     ZeroMemory(&pVideoRenderer->SourceRect, sizeof(RECT));
1030     ZeroMemory(&pVideoRenderer->DestRect, sizeof(RECT));
1031     ZeroMemory(&pVideoRenderer->WindowPos, sizeof(RECT));
1032
1033     if (pUnkOuter)
1034         pVideoRenderer->outer_unk = pUnkOuter;
1035     else
1036         pVideoRenderer->outer_unk = &pVideoRenderer->IUnknown_inner;
1037
1038     hr = BaseRenderer_Init(&pVideoRenderer->renderer, &VideoRenderer_Vtbl, pUnkOuter,
1039             &CLSID_VideoRenderer, (DWORD_PTR)(__FILE__ ": VideoRendererImpl.csFilter"),
1040             &BaseFuncTable);
1041
1042     if (FAILED(hr))
1043         goto fail;
1044
1045     hr = BaseControlWindow_Init(&pVideoRenderer->baseControlWindow, &IVideoWindow_VTable,
1046             &pVideoRenderer->renderer.filter, &pVideoRenderer->renderer.filter.csFilter,
1047             &pVideoRenderer->renderer.pInputPin->pin, &renderer_BaseWindowFuncTable);
1048     if (FAILED(hr))
1049         goto fail;
1050
1051     hr = BaseControlVideo_Init(&pVideoRenderer->baseControlVideo, &IBasicVideo_VTable,
1052             &pVideoRenderer->renderer.filter, &pVideoRenderer->renderer.filter.csFilter,
1053             &pVideoRenderer->renderer.pInputPin->pin, &renderer_BaseControlVideoFuncTable);
1054     if (FAILED(hr))
1055         goto fail;
1056
1057     if (!CreateRenderingSubsystem(pVideoRenderer)) {
1058         hr = E_FAIL;
1059         goto fail;
1060     }
1061
1062     *ppv = &pVideoRenderer->IUnknown_inner;
1063     return S_OK;
1064
1065 fail:
1066     BaseRendererImpl_Release(&pVideoRenderer->renderer.filter.IBaseFilter_iface);
1067     CoTaskMemFree(pVideoRenderer);
1068     return hr;
1069 }
1070
1071 HRESULT VideoRendererDefault_create(IUnknown * pUnkOuter, LPVOID * ppv)
1072 {
1073     /* TODO: Attempt to use the VMR-7 renderer instead when possible */
1074     return VideoRenderer_create(pUnkOuter, ppv);
1075 }