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