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