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