ntdll: Implement support for AT_ROUND_TO_PAGE flag in NtMapViewOfSection.
[wine.git] / dlls / quartz / videorenderer.c
blob7bc26201ff28c2e1ce3dcb5f566ea7cbc985c4bf
1 /*
2 * Video Renderer (Fullscreen and Windowed using Direct Draw)
4 * Copyright 2004 Christian Costa
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.
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.
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
21 #include "config.h"
23 #include "quartz_private.h"
24 #include "pin.h"
26 #include "uuids.h"
27 #include "vfwmsgs.h"
28 #include "amvideo.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "dshow.h"
32 #include "evcode.h"
33 #include "strmif.h"
34 #include "ddraw.h"
35 #include "dvdmedia.h"
37 #include <assert.h>
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
43 typedef struct VideoRendererImpl
45 BaseRenderer renderer;
46 BaseControlWindow baseControlWindow;
47 BaseControlVideo baseControlVideo;
49 IUnknown IUnknown_inner;
50 IAMFilterMiscFlags IAMFilterMiscFlags_iface;
51 IUnknown *outer_unk;
53 BOOL init;
54 HANDLE hThread;
56 DWORD ThreadID;
57 HANDLE hEvent;
58 /* hEvent == evComplete? */
59 BOOL ThreadResult;
60 RECT SourceRect;
61 RECT DestRect;
62 RECT WindowPos;
63 LONG VideoWidth;
64 LONG VideoHeight;
65 } VideoRendererImpl;
67 static inline VideoRendererImpl *impl_from_BaseWindow(BaseWindow *iface)
69 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlWindow.baseWindow);
72 static inline VideoRendererImpl *impl_from_BaseRenderer(BaseRenderer *iface)
74 return CONTAINING_RECORD(iface, VideoRendererImpl, renderer);
77 static inline VideoRendererImpl *impl_from_IBaseFilter(IBaseFilter *iface)
79 return CONTAINING_RECORD(iface, VideoRendererImpl, renderer.filter.IBaseFilter_iface);
82 static inline VideoRendererImpl *impl_from_IVideoWindow(IVideoWindow *iface)
84 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlWindow.IVideoWindow_iface);
87 static inline VideoRendererImpl *impl_from_BaseControlVideo(BaseControlVideo *iface)
89 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlVideo);
92 static inline VideoRendererImpl *impl_from_IBasicVideo(IBasicVideo *iface)
94 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlVideo.IBasicVideo_iface);
97 static DWORD WINAPI MessageLoop(LPVOID lpParameter)
99 VideoRendererImpl* This = lpParameter;
100 MSG msg;
101 BOOL fGotMessage;
103 TRACE("Starting message loop\n");
105 if (FAILED(BaseWindowImpl_PrepareWindow(&This->baseControlWindow.baseWindow)))
107 This->ThreadResult = FALSE;
108 SetEvent(This->hEvent);
109 return 0;
112 This->ThreadResult = TRUE;
113 SetEvent(This->hEvent);
115 while ((fGotMessage = GetMessageW(&msg, NULL, 0, 0)) != 0 && fGotMessage != -1)
117 TranslateMessage(&msg);
118 DispatchMessageW(&msg);
121 TRACE("End of message loop\n");
123 return msg.wParam;
126 static BOOL CreateRenderingSubsystem(VideoRendererImpl* This)
128 This->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
129 if (!This->hEvent)
130 return FALSE;
132 This->hThread = CreateThread(NULL, 0, MessageLoop, This, 0, &This->ThreadID);
133 if (!This->hThread)
135 CloseHandle(This->hEvent);
136 return FALSE;
139 WaitForSingleObject(This->hEvent, INFINITE);
141 if (!This->ThreadResult)
143 CloseHandle(This->hEvent);
144 CloseHandle(This->hThread);
145 return FALSE;
148 return TRUE;
151 static void VideoRenderer_AutoShowWindow(VideoRendererImpl *This)
153 if (!This->init && (!This->WindowPos.right || !This->WindowPos.top))
155 DWORD style = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE);
156 DWORD style_ex = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_EXSTYLE);
158 if (!This->WindowPos.right)
160 if (This->DestRect.right)
162 This->WindowPos.left = This->DestRect.left;
163 This->WindowPos.right = This->DestRect.right;
165 else
167 This->WindowPos.left = This->SourceRect.left;
168 This->WindowPos.right = This->SourceRect.right;
171 if (!This->WindowPos.bottom)
173 if (This->DestRect.bottom)
175 This->WindowPos.top = This->DestRect.top;
176 This->WindowPos.bottom = This->DestRect.bottom;
178 else
180 This->WindowPos.top = This->SourceRect.top;
181 This->WindowPos.bottom = This->SourceRect.bottom;
185 AdjustWindowRectEx(&This->WindowPos, style, FALSE, style_ex);
187 TRACE("WindowPos: %d %d %d %d\n", This->WindowPos.left, This->WindowPos.top, This->WindowPos.right, This->WindowPos.bottom);
188 SetWindowPos(This->baseControlWindow.baseWindow.hWnd, NULL,
189 This->WindowPos.left,
190 This->WindowPos.top,
191 This->WindowPos.right - This->WindowPos.left,
192 This->WindowPos.bottom - This->WindowPos.top,
193 SWP_NOZORDER|SWP_NOMOVE|SWP_DEFERERASE);
195 GetClientRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect);
197 else if (!This->init)
198 This->DestRect = This->WindowPos;
199 This->init = TRUE;
200 if (This->baseControlWindow.AutoShow)
201 ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_SHOW);
204 static DWORD VideoRenderer_SendSampleData(VideoRendererImpl* This, LPBYTE data, DWORD size)
206 AM_MEDIA_TYPE amt;
207 HRESULT hr = S_OK;
208 BITMAPINFOHEADER *bmiHeader;
210 TRACE("(%p)->(%p, %d)\n", This, data, size);
212 hr = IPin_ConnectionMediaType(&This->renderer.pInputPin->pin.IPin_iface, &amt);
213 if (FAILED(hr)) {
214 ERR("Unable to retrieve media type\n");
215 return hr;
218 if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo))
220 bmiHeader = &((VIDEOINFOHEADER *)amt.pbFormat)->bmiHeader;
222 else if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo2))
224 bmiHeader = &((VIDEOINFOHEADER2 *)amt.pbFormat)->bmiHeader;
226 else
228 FIXME("Unknown type %s\n", debugstr_guid(&amt.subtype));
229 return VFW_E_RUNTIME_ERROR;
232 TRACE("biSize = %d\n", bmiHeader->biSize);
233 TRACE("biWidth = %d\n", bmiHeader->biWidth);
234 TRACE("biHeight = %d\n", bmiHeader->biHeight);
235 TRACE("biPlanes = %d\n", bmiHeader->biPlanes);
236 TRACE("biBitCount = %d\n", bmiHeader->biBitCount);
237 TRACE("biCompression = %s\n", debugstr_an((LPSTR)&(bmiHeader->biCompression), 4));
238 TRACE("biSizeImage = %d\n", bmiHeader->biSizeImage);
240 if (!This->baseControlWindow.baseWindow.hDC) {
241 ERR("Cannot get DC from window!\n");
242 return E_FAIL;
245 TRACE("Src Rect: %d %d %d %d\n", This->SourceRect.left, This->SourceRect.top, This->SourceRect.right, This->SourceRect.bottom);
246 TRACE("Dst Rect: %d %d %d %d\n", This->DestRect.left, This->DestRect.top, This->DestRect.right, This->DestRect.bottom);
248 StretchDIBits(This->baseControlWindow.baseWindow.hDC, This->DestRect.left, This->DestRect.top, This->DestRect.right -This->DestRect.left,
249 This->DestRect.bottom - This->DestRect.top, This->SourceRect.left, This->SourceRect.top,
250 This->SourceRect.right - This->SourceRect.left, This->SourceRect.bottom - This->SourceRect.top,
251 data, (BITMAPINFO *)bmiHeader, DIB_RGB_COLORS, SRCCOPY);
253 return S_OK;
256 static HRESULT WINAPI VideoRenderer_ShouldDrawSampleNow(BaseRenderer *This, IMediaSample *pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime)
258 /* Preroll means the sample isn't shown, this is used for key frames and things like that */
259 if (IMediaSample_IsPreroll(pSample) == S_OK)
260 return E_FAIL;
261 return S_FALSE;
264 static HRESULT WINAPI VideoRenderer_DoRenderSample(BaseRenderer* iface, IMediaSample * pSample)
266 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
267 LPBYTE pbSrcStream = NULL;
268 LONG cbSrcStream = 0;
269 HRESULT hr;
271 TRACE("(%p)->(%p)\n", This, pSample);
273 hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
274 if (FAILED(hr))
276 ERR("Cannot get pointer to sample data (%x)\n", hr);
277 return hr;
280 cbSrcStream = IMediaSample_GetActualDataLength(pSample);
282 TRACE("val %p %d\n", pbSrcStream, cbSrcStream);
284 #if 0 /* For debugging purpose */
286 int i;
287 for(i = 0; i < cbSrcStream; i++)
289 if ((i!=0) && !(i%16))
290 TRACE("\n");
291 TRACE("%02x ", pbSrcStream[i]);
293 TRACE("\n");
295 #endif
297 SetEvent(This->hEvent);
298 if (This->renderer.filter.state == State_Paused)
300 VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream);
301 SetEvent(This->hEvent);
302 if (This->renderer.filter.state == State_Paused)
304 /* Flushing */
305 return S_OK;
307 if (This->renderer.filter.state == State_Stopped)
309 return VFW_E_WRONG_STATE;
311 } else {
312 VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream);
314 return S_OK;
317 static HRESULT WINAPI VideoRenderer_CheckMediaType(BaseRenderer *iface, const AM_MEDIA_TYPE * pmt)
319 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
321 if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Video))
322 return S_FALSE;
324 if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB32) ||
325 IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB24) ||
326 IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB565) ||
327 IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB8))
329 LONG height;
331 if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo))
333 VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)pmt->pbFormat;
334 This->SourceRect.left = 0;
335 This->SourceRect.top = 0;
336 This->SourceRect.right = This->VideoWidth = format->bmiHeader.biWidth;
337 height = format->bmiHeader.biHeight;
338 if (height < 0)
339 This->SourceRect.bottom = This->VideoHeight = -height;
340 else
341 This->SourceRect.bottom = This->VideoHeight = height;
343 else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2))
345 VIDEOINFOHEADER2 *format2 = (VIDEOINFOHEADER2 *)pmt->pbFormat;
347 This->SourceRect.left = 0;
348 This->SourceRect.top = 0;
349 This->SourceRect.right = This->VideoWidth = format2->bmiHeader.biWidth;
350 height = format2->bmiHeader.biHeight;
351 if (height < 0)
352 This->SourceRect.bottom = This->VideoHeight = -height;
353 else
354 This->SourceRect.bottom = This->VideoHeight = height;
356 else
358 WARN("Format type %s not supported\n", debugstr_guid(&pmt->formattype));
359 return S_FALSE;
361 return S_OK;
363 return S_FALSE;
366 static HRESULT WINAPI VideoRenderer_EndFlush(BaseRenderer* iface)
368 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
370 TRACE("(%p)->()\n", iface);
372 if (This->renderer.pMediaSample) {
373 ResetEvent(This->hEvent);
374 LeaveCriticalSection(iface->pInputPin->pin.pCritSec);
375 LeaveCriticalSection(&iface->filter.csFilter);
376 LeaveCriticalSection(&iface->csRenderLock);
377 WaitForSingleObject(This->hEvent, INFINITE);
378 EnterCriticalSection(&iface->csRenderLock);
379 EnterCriticalSection(&iface->filter.csFilter);
380 EnterCriticalSection(iface->pInputPin->pin.pCritSec);
382 if (This->renderer.filter.state == State_Paused) {
383 ResetEvent(This->hEvent);
386 return BaseRendererImpl_EndFlush(iface);
389 static VOID WINAPI VideoRenderer_OnStopStreaming(BaseRenderer* iface)
391 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
393 TRACE("(%p)->()\n", This);
395 SetEvent(This->hEvent);
396 if (This->baseControlWindow.AutoShow)
397 /* Black it out */
398 RedrawWindow(This->baseControlWindow.baseWindow.hWnd, NULL, NULL, RDW_INVALIDATE|RDW_ERASE);
401 static VOID WINAPI VideoRenderer_OnStartStreaming(BaseRenderer* iface)
403 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
405 TRACE("(%p)\n", This);
407 if (This->renderer.pInputPin->pin.pConnectedTo && (This->renderer.filter.state == State_Stopped || !This->renderer.pInputPin->end_of_stream))
409 if (This->renderer.filter.state == State_Stopped)
411 ResetEvent(This->hEvent);
412 VideoRenderer_AutoShowWindow(This);
417 static LPWSTR WINAPI VideoRenderer_GetClassWindowStyles(BaseWindow *This, DWORD *pClassStyles, DWORD *pWindowStyles, DWORD *pWindowStylesEx)
419 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 };
421 *pClassStyles = 0;
422 *pWindowStyles = WS_SIZEBOX;
423 *pWindowStylesEx = 0;
425 return (LPWSTR)classnameW;
428 static RECT WINAPI VideoRenderer_GetDefaultRect(BaseWindow *iface)
430 VideoRendererImpl *This = impl_from_BaseWindow(iface);
431 static RECT defRect;
433 defRect.left = defRect.top = 0;
434 defRect.right = This->VideoWidth;
435 defRect.bottom = This->VideoHeight;
437 return defRect;
440 static BOOL WINAPI VideoRenderer_OnSize(BaseWindow *iface, LONG Width, LONG Height)
442 VideoRendererImpl *This = impl_from_BaseWindow(iface);
444 TRACE("WM_SIZE %d %d\n", Width, Height);
445 GetClientRect(iface->hWnd, &This->DestRect);
446 TRACE("WM_SIZING: DestRect=(%d,%d),(%d,%d)\n",
447 This->DestRect.left,
448 This->DestRect.top,
449 This->DestRect.right - This->DestRect.left,
450 This->DestRect.bottom - This->DestRect.top);
451 return BaseWindowImpl_OnSize(iface, Width, Height);
454 static const BaseRendererFuncTable BaseFuncTable = {
455 VideoRenderer_CheckMediaType,
456 VideoRenderer_DoRenderSample,
457 /**/
458 NULL,
459 NULL,
460 NULL,
461 VideoRenderer_OnStartStreaming,
462 VideoRenderer_OnStopStreaming,
463 NULL,
464 NULL,
465 NULL,
466 VideoRenderer_ShouldDrawSampleNow,
467 NULL,
468 /**/
469 NULL,
470 NULL,
471 NULL,
472 NULL,
473 VideoRenderer_EndFlush,
476 static const BaseWindowFuncTable renderer_BaseWindowFuncTable = {
477 VideoRenderer_GetClassWindowStyles,
478 VideoRenderer_GetDefaultRect,
479 NULL,
480 BaseControlWindowImpl_PossiblyEatMessage,
481 VideoRenderer_OnSize
484 static HRESULT WINAPI VideoRenderer_GetSourceRect(BaseControlVideo* iface, RECT *pSourceRect)
486 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
487 CopyRect(pSourceRect,&This->SourceRect);
488 return S_OK;
491 static HRESULT WINAPI VideoRenderer_GetStaticImage(BaseControlVideo* iface, LONG *pBufferSize, LONG *pDIBImage)
493 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
494 BITMAPINFOHEADER *bmiHeader;
495 LONG needed_size;
496 AM_MEDIA_TYPE *amt = &This->renderer.pInputPin->pin.mtCurrent;
497 char *ptr;
499 FIXME("(%p/%p)->(%p, %p): partial stub\n", This, iface, pBufferSize, pDIBImage);
501 EnterCriticalSection(&This->renderer.filter.csFilter);
503 if (!This->renderer.pMediaSample)
505 LeaveCriticalSection(&This->renderer.filter.csFilter);
506 return (This->renderer.filter.state == State_Paused ? E_UNEXPECTED : VFW_E_NOT_PAUSED);
509 if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo))
511 bmiHeader = &((VIDEOINFOHEADER *)amt->pbFormat)->bmiHeader;
513 else if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo2))
515 bmiHeader = &((VIDEOINFOHEADER2 *)amt->pbFormat)->bmiHeader;
517 else
519 FIXME("Unknown type %s\n", debugstr_guid(&amt->subtype));
520 LeaveCriticalSection(&This->renderer.filter.csFilter);
521 return VFW_E_RUNTIME_ERROR;
524 needed_size = bmiHeader->biSize;
525 needed_size += IMediaSample_GetActualDataLength(This->renderer.pMediaSample);
527 if (!pDIBImage)
529 *pBufferSize = needed_size;
530 LeaveCriticalSection(&This->renderer.filter.csFilter);
531 return S_OK;
534 if (needed_size < *pBufferSize)
536 ERR("Buffer too small %u/%u\n", needed_size, *pBufferSize);
537 LeaveCriticalSection(&This->renderer.filter.csFilter);
538 return E_FAIL;
540 *pBufferSize = needed_size;
542 memcpy(pDIBImage, bmiHeader, bmiHeader->biSize);
543 IMediaSample_GetPointer(This->renderer.pMediaSample, (BYTE **)&ptr);
544 memcpy((char *)pDIBImage + bmiHeader->biSize, ptr, IMediaSample_GetActualDataLength(This->renderer.pMediaSample));
546 LeaveCriticalSection(&This->renderer.filter.csFilter);
547 return S_OK;
550 static HRESULT WINAPI VideoRenderer_GetTargetRect(BaseControlVideo* iface, RECT *pTargetRect)
552 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
553 CopyRect(pTargetRect,&This->DestRect);
554 return S_OK;
557 static VIDEOINFOHEADER* WINAPI VideoRenderer_GetVideoFormat(BaseControlVideo* iface)
559 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
560 AM_MEDIA_TYPE *pmt;
562 TRACE("(%p/%p)\n", This, iface);
564 pmt = &This->renderer.pInputPin->pin.mtCurrent;
565 if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) {
566 return (VIDEOINFOHEADER*)pmt->pbFormat;
567 } else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2)) {
568 static VIDEOINFOHEADER vih;
569 VIDEOINFOHEADER2 *vih2 = (VIDEOINFOHEADER2*)pmt->pbFormat;
570 memcpy(&vih,vih2,sizeof(VIDEOINFOHEADER));
571 memcpy(&vih.bmiHeader, &vih2->bmiHeader, sizeof(BITMAPINFOHEADER));
572 return &vih;
573 } else {
574 ERR("Unknown format type %s\n", qzdebugstr_guid(&pmt->formattype));
575 return NULL;
579 static HRESULT WINAPI VideoRenderer_IsDefaultSourceRect(BaseControlVideo* iface)
581 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
582 FIXME("(%p/%p)->(): stub !!!\n", This, iface);
584 return S_OK;
587 static HRESULT WINAPI VideoRenderer_IsDefaultTargetRect(BaseControlVideo* iface)
589 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
590 FIXME("(%p/%p)->(): stub !!!\n", This, iface);
592 return S_OK;
595 static HRESULT WINAPI VideoRenderer_SetDefaultSourceRect(BaseControlVideo* iface)
597 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
599 This->SourceRect.left = 0;
600 This->SourceRect.top = 0;
601 This->SourceRect.right = This->VideoWidth;
602 This->SourceRect.bottom = This->VideoHeight;
604 return S_OK;
607 static HRESULT WINAPI VideoRenderer_SetDefaultTargetRect(BaseControlVideo* iface)
609 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
610 RECT rect;
612 if (!GetClientRect(This->baseControlWindow.baseWindow.hWnd, &rect))
613 return E_FAIL;
615 This->DestRect.left = 0;
616 This->DestRect.top = 0;
617 This->DestRect.right = rect.right;
618 This->DestRect.bottom = rect.bottom;
620 return S_OK;
623 static HRESULT WINAPI VideoRenderer_SetSourceRect(BaseControlVideo* iface, RECT *pSourceRect)
625 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
626 CopyRect(&This->SourceRect,pSourceRect);
627 return S_OK;
630 static HRESULT WINAPI VideoRenderer_SetTargetRect(BaseControlVideo* iface, RECT *pTargetRect)
632 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
633 CopyRect(&This->DestRect,pTargetRect);
634 return S_OK;
637 static const BaseControlVideoFuncTable renderer_BaseControlVideoFuncTable = {
638 VideoRenderer_GetSourceRect,
639 VideoRenderer_GetStaticImage,
640 VideoRenderer_GetTargetRect,
641 VideoRenderer_GetVideoFormat,
642 VideoRenderer_IsDefaultSourceRect,
643 VideoRenderer_IsDefaultTargetRect,
644 VideoRenderer_SetDefaultSourceRect,
645 VideoRenderer_SetDefaultTargetRect,
646 VideoRenderer_SetSourceRect,
647 VideoRenderer_SetTargetRect
650 static inline VideoRendererImpl *impl_from_IUnknown(IUnknown *iface)
652 return CONTAINING_RECORD(iface, VideoRendererImpl, IUnknown_inner);
655 static HRESULT WINAPI VideoRendererInner_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
657 VideoRendererImpl *This = impl_from_IUnknown(iface);
659 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
661 *ppv = NULL;
663 if (IsEqualIID(riid, &IID_IUnknown))
664 *ppv = &This->IUnknown_inner;
665 else if (IsEqualIID(riid, &IID_IBasicVideo))
666 *ppv = &This->baseControlVideo.IBasicVideo_iface;
667 else if (IsEqualIID(riid, &IID_IVideoWindow))
668 *ppv = &This->baseControlWindow.IVideoWindow_iface;
669 else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags))
670 *ppv = &This->IAMFilterMiscFlags_iface;
671 else
673 HRESULT hr;
674 hr = BaseRendererImpl_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
675 if (SUCCEEDED(hr))
676 return hr;
679 if (*ppv)
681 IUnknown_AddRef((IUnknown *)*ppv);
682 return S_OK;
685 if (!IsEqualIID(riid, &IID_IPin))
686 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
688 return E_NOINTERFACE;
691 static ULONG WINAPI VideoRendererInner_AddRef(IUnknown *iface)
693 VideoRendererImpl *This = impl_from_IUnknown(iface);
694 ULONG refCount = BaseFilterImpl_AddRef(&This->renderer.filter.IBaseFilter_iface);
696 TRACE("(%p)->(): new ref = %d\n", This, refCount);
698 return refCount;
701 static ULONG WINAPI VideoRendererInner_Release(IUnknown *iface)
703 VideoRendererImpl *This = impl_from_IUnknown(iface);
704 ULONG refCount = BaseRendererImpl_Release(&This->renderer.filter.IBaseFilter_iface);
706 TRACE("(%p)->(): new ref = %d\n", This, refCount);
708 if (!refCount)
710 BaseControlWindow_Destroy(&This->baseControlWindow);
711 BaseControlVideo_Destroy(&This->baseControlVideo);
712 PostThreadMessageW(This->ThreadID, WM_QUIT, 0, 0);
713 WaitForSingleObject(This->hThread, INFINITE);
714 CloseHandle(This->hThread);
715 CloseHandle(This->hEvent);
717 TRACE("Destroying Video Renderer\n");
718 CoTaskMemFree(This);
720 return 0;
722 else
723 return refCount;
726 static const IUnknownVtbl IInner_VTable =
728 VideoRendererInner_QueryInterface,
729 VideoRendererInner_AddRef,
730 VideoRendererInner_Release
733 static HRESULT WINAPI VideoRenderer_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
735 VideoRendererImpl *This = impl_from_IBaseFilter(iface);
736 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
739 static ULONG WINAPI VideoRenderer_AddRef(IBaseFilter * iface)
741 VideoRendererImpl *This = impl_from_IBaseFilter(iface);
742 return IUnknown_AddRef(This->outer_unk);
745 static ULONG WINAPI VideoRenderer_Release(IBaseFilter * iface)
747 VideoRendererImpl *This = impl_from_IBaseFilter(iface);
748 return IUnknown_Release(This->outer_unk);
751 /** IMediaFilter methods **/
753 static HRESULT WINAPI VideoRenderer_Pause(IBaseFilter * iface)
755 VideoRendererImpl *This = impl_from_IBaseFilter(iface);
757 TRACE("(%p/%p)->()\n", This, iface);
759 EnterCriticalSection(&This->renderer.csRenderLock);
760 if (This->renderer.filter.state != State_Paused)
762 if (This->renderer.filter.state == State_Stopped)
764 This->renderer.pInputPin->end_of_stream = 0;
765 ResetEvent(This->hEvent);
766 VideoRenderer_AutoShowWindow(This);
769 ResetEvent(This->renderer.RenderEvent);
770 This->renderer.filter.state = State_Paused;
772 LeaveCriticalSection(&This->renderer.csRenderLock);
774 return S_OK;
777 static const IBaseFilterVtbl VideoRenderer_Vtbl =
779 VideoRenderer_QueryInterface,
780 VideoRenderer_AddRef,
781 VideoRenderer_Release,
782 BaseFilterImpl_GetClassID,
783 BaseRendererImpl_Stop,
784 VideoRenderer_Pause,
785 BaseRendererImpl_Run,
786 BaseRendererImpl_GetState,
787 BaseRendererImpl_SetSyncSource,
788 BaseFilterImpl_GetSyncSource,
789 BaseFilterImpl_EnumPins,
790 BaseRendererImpl_FindPin,
791 BaseFilterImpl_QueryFilterInfo,
792 BaseFilterImpl_JoinFilterGraph,
793 BaseFilterImpl_QueryVendorInfo
796 /*** IUnknown methods ***/
797 static HRESULT WINAPI BasicVideo_QueryInterface(IBasicVideo *iface, REFIID riid, LPVOID *ppvObj)
799 VideoRendererImpl *This = impl_from_IBasicVideo(iface);
801 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
803 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
806 static ULONG WINAPI BasicVideo_AddRef(IBasicVideo *iface)
808 VideoRendererImpl *This = impl_from_IBasicVideo(iface);
810 TRACE("(%p/%p)->()\n", This, iface);
812 return IUnknown_AddRef(This->outer_unk);
815 static ULONG WINAPI BasicVideo_Release(IBasicVideo *iface)
817 VideoRendererImpl *This = impl_from_IBasicVideo(iface);
819 TRACE("(%p/%p)->()\n", This, iface);
821 return IUnknown_Release(This->outer_unk);
824 static const IBasicVideoVtbl IBasicVideo_VTable =
826 BasicVideo_QueryInterface,
827 BasicVideo_AddRef,
828 BasicVideo_Release,
829 BaseControlVideoImpl_GetTypeInfoCount,
830 BaseControlVideoImpl_GetTypeInfo,
831 BaseControlVideoImpl_GetIDsOfNames,
832 BaseControlVideoImpl_Invoke,
833 BaseControlVideoImpl_get_AvgTimePerFrame,
834 BaseControlVideoImpl_get_BitRate,
835 BaseControlVideoImpl_get_BitErrorRate,
836 BaseControlVideoImpl_get_VideoWidth,
837 BaseControlVideoImpl_get_VideoHeight,
838 BaseControlVideoImpl_put_SourceLeft,
839 BaseControlVideoImpl_get_SourceLeft,
840 BaseControlVideoImpl_put_SourceWidth,
841 BaseControlVideoImpl_get_SourceWidth,
842 BaseControlVideoImpl_put_SourceTop,
843 BaseControlVideoImpl_get_SourceTop,
844 BaseControlVideoImpl_put_SourceHeight,
845 BaseControlVideoImpl_get_SourceHeight,
846 BaseControlVideoImpl_put_DestinationLeft,
847 BaseControlVideoImpl_get_DestinationLeft,
848 BaseControlVideoImpl_put_DestinationWidth,
849 BaseControlVideoImpl_get_DestinationWidth,
850 BaseControlVideoImpl_put_DestinationTop,
851 BaseControlVideoImpl_get_DestinationTop,
852 BaseControlVideoImpl_put_DestinationHeight,
853 BaseControlVideoImpl_get_DestinationHeight,
854 BaseControlVideoImpl_SetSourcePosition,
855 BaseControlVideoImpl_GetSourcePosition,
856 BaseControlVideoImpl_SetDefaultSourcePosition,
857 BaseControlVideoImpl_SetDestinationPosition,
858 BaseControlVideoImpl_GetDestinationPosition,
859 BaseControlVideoImpl_SetDefaultDestinationPosition,
860 BaseControlVideoImpl_GetVideoSize,
861 BaseControlVideoImpl_GetVideoPaletteEntries,
862 BaseControlVideoImpl_GetCurrentImage,
863 BaseControlVideoImpl_IsUsingDefaultSource,
864 BaseControlVideoImpl_IsUsingDefaultDestination
868 /*** IUnknown methods ***/
869 static HRESULT WINAPI VideoWindow_QueryInterface(IVideoWindow *iface, REFIID riid, LPVOID *ppvObj)
871 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
873 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
875 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
878 static ULONG WINAPI VideoWindow_AddRef(IVideoWindow *iface)
880 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
882 TRACE("(%p/%p)->()\n", This, iface);
884 return IUnknown_AddRef(This->outer_unk);
887 static ULONG WINAPI VideoWindow_Release(IVideoWindow *iface)
889 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
891 TRACE("(%p/%p)->()\n", This, iface);
893 return IUnknown_Release(This->outer_unk);
896 static HRESULT WINAPI VideoWindow_get_FullScreenMode(IVideoWindow *iface,
897 LONG *FullScreenMode)
899 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
901 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, FullScreenMode);
903 return S_OK;
906 static HRESULT WINAPI VideoWindow_put_FullScreenMode(IVideoWindow *iface,
907 LONG FullScreenMode)
909 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
911 FIXME("(%p/%p)->(%d): stub !!!\n", This, iface, FullScreenMode);
913 if (FullScreenMode) {
914 This->baseControlWindow.baseWindow.WindowStyles = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE);
915 ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_HIDE);
916 SetParent(This->baseControlWindow.baseWindow.hWnd, 0);
917 SetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE, WS_POPUP);
918 SetWindowPos(This->baseControlWindow.baseWindow.hWnd,HWND_TOP,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN),SWP_SHOWWINDOW);
919 GetWindowRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect);
920 This->WindowPos = This->DestRect;
921 } else {
922 ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_HIDE);
923 SetParent(This->baseControlWindow.baseWindow.hWnd, This->baseControlWindow.hwndOwner);
924 SetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE, This->baseControlWindow.baseWindow.WindowStyles);
925 GetClientRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect);
926 SetWindowPos(This->baseControlWindow.baseWindow.hWnd,0,This->DestRect.left,This->DestRect.top,This->DestRect.right,This->DestRect.bottom,SWP_NOZORDER|SWP_SHOWWINDOW);
927 This->WindowPos = This->DestRect;
930 return S_OK;
933 static const IVideoWindowVtbl IVideoWindow_VTable =
935 VideoWindow_QueryInterface,
936 VideoWindow_AddRef,
937 VideoWindow_Release,
938 BaseControlWindowImpl_GetTypeInfoCount,
939 BaseControlWindowImpl_GetTypeInfo,
940 BaseControlWindowImpl_GetIDsOfNames,
941 BaseControlWindowImpl_Invoke,
942 BaseControlWindowImpl_put_Caption,
943 BaseControlWindowImpl_get_Caption,
944 BaseControlWindowImpl_put_WindowStyle,
945 BaseControlWindowImpl_get_WindowStyle,
946 BaseControlWindowImpl_put_WindowStyleEx,
947 BaseControlWindowImpl_get_WindowStyleEx,
948 BaseControlWindowImpl_put_AutoShow,
949 BaseControlWindowImpl_get_AutoShow,
950 BaseControlWindowImpl_put_WindowState,
951 BaseControlWindowImpl_get_WindowState,
952 BaseControlWindowImpl_put_BackgroundPalette,
953 BaseControlWindowImpl_get_BackgroundPalette,
954 BaseControlWindowImpl_put_Visible,
955 BaseControlWindowImpl_get_Visible,
956 BaseControlWindowImpl_put_Left,
957 BaseControlWindowImpl_get_Left,
958 BaseControlWindowImpl_put_Width,
959 BaseControlWindowImpl_get_Width,
960 BaseControlWindowImpl_put_Top,
961 BaseControlWindowImpl_get_Top,
962 BaseControlWindowImpl_put_Height,
963 BaseControlWindowImpl_get_Height,
964 BaseControlWindowImpl_put_Owner,
965 BaseControlWindowImpl_get_Owner,
966 BaseControlWindowImpl_put_MessageDrain,
967 BaseControlWindowImpl_get_MessageDrain,
968 BaseControlWindowImpl_get_BorderColor,
969 BaseControlWindowImpl_put_BorderColor,
970 VideoWindow_get_FullScreenMode,
971 VideoWindow_put_FullScreenMode,
972 BaseControlWindowImpl_SetWindowForeground,
973 BaseControlWindowImpl_NotifyOwnerMessage,
974 BaseControlWindowImpl_SetWindowPosition,
975 BaseControlWindowImpl_GetWindowPosition,
976 BaseControlWindowImpl_GetMinIdealImageSize,
977 BaseControlWindowImpl_GetMaxIdealImageSize,
978 BaseControlWindowImpl_GetRestorePosition,
979 BaseControlWindowImpl_HideCursor,
980 BaseControlWindowImpl_IsCursorHidden
983 static VideoRendererImpl *impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface)
985 return CONTAINING_RECORD(iface, VideoRendererImpl, IAMFilterMiscFlags_iface);
988 static HRESULT WINAPI AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid,
989 void **ppv)
991 VideoRendererImpl *This = impl_from_IAMFilterMiscFlags(iface);
992 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
995 static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface)
997 VideoRendererImpl *This = impl_from_IAMFilterMiscFlags(iface);
998 return IUnknown_AddRef(This->outer_unk);
1001 static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface)
1003 VideoRendererImpl *This = impl_from_IAMFilterMiscFlags(iface);
1004 return IUnknown_Release(This->outer_unk);
1007 static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface)
1009 return AM_FILTER_MISC_FLAGS_IS_RENDERER;
1012 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = {
1013 AMFilterMiscFlags_QueryInterface,
1014 AMFilterMiscFlags_AddRef,
1015 AMFilterMiscFlags_Release,
1016 AMFilterMiscFlags_GetMiscFlags
1019 HRESULT VideoRenderer_create(IUnknown *pUnkOuter, void **ppv)
1021 HRESULT hr;
1022 VideoRendererImpl * pVideoRenderer;
1024 TRACE("(%p, %p)\n", pUnkOuter, ppv);
1026 *ppv = NULL;
1028 pVideoRenderer = CoTaskMemAlloc(sizeof(VideoRendererImpl));
1029 pVideoRenderer->IUnknown_inner.lpVtbl = &IInner_VTable;
1030 pVideoRenderer->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_Vtbl;
1032 pVideoRenderer->init = FALSE;
1033 ZeroMemory(&pVideoRenderer->SourceRect, sizeof(RECT));
1034 ZeroMemory(&pVideoRenderer->DestRect, sizeof(RECT));
1035 ZeroMemory(&pVideoRenderer->WindowPos, sizeof(RECT));
1037 if (pUnkOuter)
1038 pVideoRenderer->outer_unk = pUnkOuter;
1039 else
1040 pVideoRenderer->outer_unk = &pVideoRenderer->IUnknown_inner;
1042 hr = BaseRenderer_Init(&pVideoRenderer->renderer, &VideoRenderer_Vtbl, pUnkOuter,
1043 &CLSID_VideoRenderer, (DWORD_PTR)(__FILE__ ": VideoRendererImpl.csFilter"),
1044 &BaseFuncTable);
1046 if (FAILED(hr))
1047 goto fail;
1049 hr = BaseControlWindow_Init(&pVideoRenderer->baseControlWindow, &IVideoWindow_VTable,
1050 &pVideoRenderer->renderer.filter, &pVideoRenderer->renderer.filter.csFilter,
1051 &pVideoRenderer->renderer.pInputPin->pin, &renderer_BaseWindowFuncTable);
1052 if (FAILED(hr))
1053 goto fail;
1055 hr = BaseControlVideo_Init(&pVideoRenderer->baseControlVideo, &IBasicVideo_VTable,
1056 &pVideoRenderer->renderer.filter, &pVideoRenderer->renderer.filter.csFilter,
1057 &pVideoRenderer->renderer.pInputPin->pin, &renderer_BaseControlVideoFuncTable);
1058 if (FAILED(hr))
1059 goto fail;
1061 if (!CreateRenderingSubsystem(pVideoRenderer)) {
1062 hr = E_FAIL;
1063 goto fail;
1066 *ppv = &pVideoRenderer->IUnknown_inner;
1067 return S_OK;
1069 fail:
1070 BaseRendererImpl_Release(&pVideoRenderer->renderer.filter.IBaseFilter_iface);
1071 CoTaskMemFree(pVideoRenderer);
1072 return hr;
1075 HRESULT VideoRendererDefault_create(IUnknown * pUnkOuter, LPVOID * ppv)
1077 /* TODO: Attempt to use the VMR-7 renderer instead when possible */
1078 return VideoRenderer_create(pUnkOuter, ppv);