quartz: Destroy BaseRenderer in NullRendererInner_Release.
[wine.git] / dlls / quartz / videorenderer.c
blob4e8f359dc7406221fd0edc8796b2d963d25de837
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 #define NONAMELESSSTRUCT
24 #define NONAMELESSUNION
25 #include "quartz_private.h"
26 #include "pin.h"
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"
39 #include <assert.h>
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
45 typedef struct VideoRendererImpl
47 BaseRenderer renderer;
48 BaseControlWindow baseControlWindow;
49 BaseControlVideo baseControlVideo;
51 IUnknown IUnknown_inner;
52 IAMFilterMiscFlags IAMFilterMiscFlags_iface;
53 IUnknown *outer_unk;
55 BOOL init;
56 HANDLE hThread;
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;
69 static inline VideoRendererImpl *impl_from_BaseWindow(BaseWindow *iface)
71 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlWindow.baseWindow);
74 static inline VideoRendererImpl *impl_from_BaseRenderer(BaseRenderer *iface)
76 return CONTAINING_RECORD(iface, VideoRendererImpl, renderer);
79 static inline VideoRendererImpl *impl_from_IBaseFilter(IBaseFilter *iface)
81 return CONTAINING_RECORD(iface, VideoRendererImpl, renderer.filter.IBaseFilter_iface);
84 static inline VideoRendererImpl *impl_from_IVideoWindow(IVideoWindow *iface)
86 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlWindow.IVideoWindow_iface);
89 static inline VideoRendererImpl *impl_from_BaseControlVideo(BaseControlVideo *iface)
91 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlVideo);
94 static inline VideoRendererImpl *impl_from_IBasicVideo(IBasicVideo *iface)
96 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlVideo.IBasicVideo_iface);
99 static DWORD WINAPI MessageLoop(LPVOID lpParameter)
101 VideoRendererImpl* This = lpParameter;
102 MSG msg;
103 BOOL fGotMessage;
105 TRACE("Starting message loop\n");
107 if (FAILED(BaseWindowImpl_PrepareWindow(&This->baseControlWindow.baseWindow)))
109 This->ThreadResult = FALSE;
110 SetEvent(This->hEvent);
111 return 0;
114 This->ThreadResult = TRUE;
115 SetEvent(This->hEvent);
117 while ((fGotMessage = GetMessageW(&msg, NULL, 0, 0)) != 0 && fGotMessage != -1)
119 TranslateMessage(&msg);
120 DispatchMessageW(&msg);
123 TRACE("End of message loop\n");
125 return msg.wParam;
128 static BOOL CreateRenderingSubsystem(VideoRendererImpl* This)
130 This->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
131 if (!This->hEvent)
132 return FALSE;
134 This->hThread = CreateThread(NULL, 0, MessageLoop, This, 0, &This->ThreadID);
135 if (!This->hThread)
137 CloseHandle(This->hEvent);
138 return FALSE;
141 WaitForSingleObject(This->hEvent, INFINITE);
143 if (!This->ThreadResult)
145 CloseHandle(This->hEvent);
146 CloseHandle(This->hThread);
147 return FALSE;
150 return TRUE;
153 static void VideoRenderer_AutoShowWindow(VideoRendererImpl *This)
155 if (!This->init && (!This->WindowPos.right || !This->WindowPos.top))
157 DWORD style = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE);
158 DWORD style_ex = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_EXSTYLE);
160 if (!This->WindowPos.right)
162 if (This->DestRect.right)
164 This->WindowPos.left = This->DestRect.left;
165 This->WindowPos.right = This->DestRect.right;
167 else
169 This->WindowPos.left = This->SourceRect.left;
170 This->WindowPos.right = This->SourceRect.right;
173 if (!This->WindowPos.bottom)
175 if (This->DestRect.bottom)
177 This->WindowPos.top = This->DestRect.top;
178 This->WindowPos.bottom = This->DestRect.bottom;
180 else
182 This->WindowPos.top = This->SourceRect.top;
183 This->WindowPos.bottom = This->SourceRect.bottom;
187 AdjustWindowRectEx(&This->WindowPos, style, FALSE, style_ex);
189 TRACE("WindowPos: %d %d %d %d\n", This->WindowPos.left, This->WindowPos.top, This->WindowPos.right, This->WindowPos.bottom);
190 SetWindowPos(This->baseControlWindow.baseWindow.hWnd, NULL,
191 This->WindowPos.left,
192 This->WindowPos.top,
193 This->WindowPos.right - This->WindowPos.left,
194 This->WindowPos.bottom - This->WindowPos.top,
195 SWP_NOZORDER|SWP_NOMOVE|SWP_DEFERERASE);
197 GetClientRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect);
199 else if (!This->init)
200 This->DestRect = This->WindowPos;
201 This->init = TRUE;
202 if (This->baseControlWindow.AutoShow)
203 ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_SHOW);
206 static DWORD VideoRenderer_SendSampleData(VideoRendererImpl* This, LPBYTE data, DWORD size)
208 AM_MEDIA_TYPE amt;
209 HRESULT hr = S_OK;
210 BITMAPINFOHEADER *bmiHeader;
212 TRACE("(%p)->(%p, %d)\n", This, data, size);
214 hr = IPin_ConnectionMediaType(&This->renderer.pInputPin->pin.IPin_iface, &amt);
215 if (FAILED(hr)) {
216 ERR("Unable to retrieve media type\n");
217 return hr;
220 if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo))
222 bmiHeader = &((VIDEOINFOHEADER *)amt.pbFormat)->bmiHeader;
224 else if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo2))
226 bmiHeader = &((VIDEOINFOHEADER2 *)amt.pbFormat)->bmiHeader;
228 else
230 FIXME("Unknown type %s\n", debugstr_guid(&amt.subtype));
231 return VFW_E_RUNTIME_ERROR;
234 TRACE("biSize = %d\n", bmiHeader->biSize);
235 TRACE("biWidth = %d\n", bmiHeader->biWidth);
236 TRACE("biHeight = %d\n", bmiHeader->biHeight);
237 TRACE("biPlanes = %d\n", bmiHeader->biPlanes);
238 TRACE("biBitCount = %d\n", bmiHeader->biBitCount);
239 TRACE("biCompression = %s\n", debugstr_an((LPSTR)&(bmiHeader->biCompression), 4));
240 TRACE("biSizeImage = %d\n", bmiHeader->biSizeImage);
242 if (!This->baseControlWindow.baseWindow.hDC) {
243 ERR("Cannot get DC from window!\n");
244 return E_FAIL;
247 TRACE("Src Rect: %d %d %d %d\n", This->SourceRect.left, This->SourceRect.top, This->SourceRect.right, This->SourceRect.bottom);
248 TRACE("Dst Rect: %d %d %d %d\n", This->DestRect.left, This->DestRect.top, This->DestRect.right, This->DestRect.bottom);
250 StretchDIBits(This->baseControlWindow.baseWindow.hDC, This->DestRect.left, This->DestRect.top, This->DestRect.right -This->DestRect.left,
251 This->DestRect.bottom - This->DestRect.top, This->SourceRect.left, This->SourceRect.top,
252 This->SourceRect.right - This->SourceRect.left, This->SourceRect.bottom - This->SourceRect.top,
253 data, (BITMAPINFO *)bmiHeader, DIB_RGB_COLORS, SRCCOPY);
255 return S_OK;
258 static HRESULT WINAPI VideoRenderer_ShouldDrawSampleNow(BaseRenderer *This, IMediaSample *pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime)
260 /* Preroll means the sample isn't shown, this is used for key frames and things like that */
261 if (IMediaSample_IsPreroll(pSample) == S_OK)
262 return E_FAIL;
263 return S_FALSE;
266 static HRESULT WINAPI VideoRenderer_DoRenderSample(BaseRenderer* iface, IMediaSample * pSample)
268 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
269 LPBYTE pbSrcStream = NULL;
270 LONG cbSrcStream = 0;
271 HRESULT hr;
273 TRACE("(%p)->(%p)\n", This, pSample);
275 hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
276 if (FAILED(hr))
278 ERR("Cannot get pointer to sample data (%x)\n", hr);
279 return hr;
282 cbSrcStream = IMediaSample_GetActualDataLength(pSample);
284 TRACE("val %p %d\n", pbSrcStream, cbSrcStream);
286 #if 0 /* For debugging purpose */
288 int i;
289 for(i = 0; i < cbSrcStream; i++)
291 if ((i!=0) && !(i%16))
292 TRACE("\n");
293 TRACE("%02x ", pbSrcStream[i]);
295 TRACE("\n");
297 #endif
299 SetEvent(This->hEvent);
300 if (This->renderer.filter.state == State_Paused)
302 VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream);
303 SetEvent(This->hEvent);
304 if (This->renderer.filter.state == State_Paused)
306 /* Flushing */
307 return S_OK;
309 if (This->renderer.filter.state == State_Stopped)
311 return VFW_E_WRONG_STATE;
313 } else {
314 VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream);
316 return S_OK;
319 static HRESULT WINAPI VideoRenderer_CheckMediaType(BaseRenderer *iface, const AM_MEDIA_TYPE * pmt)
321 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
323 if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Video))
324 return S_FALSE;
326 if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB32) ||
327 IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB24) ||
328 IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB565) ||
329 IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_RGB8))
331 LONG height;
333 if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo))
335 VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)pmt->pbFormat;
336 This->SourceRect.left = 0;
337 This->SourceRect.top = 0;
338 This->SourceRect.right = This->VideoWidth = format->bmiHeader.biWidth;
339 height = format->bmiHeader.biHeight;
340 if (height < 0)
341 This->SourceRect.bottom = This->VideoHeight = -height;
342 else
343 This->SourceRect.bottom = This->VideoHeight = height;
345 else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2))
347 VIDEOINFOHEADER2 *format2 = (VIDEOINFOHEADER2 *)pmt->pbFormat;
349 This->SourceRect.left = 0;
350 This->SourceRect.top = 0;
351 This->SourceRect.right = This->VideoWidth = format2->bmiHeader.biWidth;
352 height = format2->bmiHeader.biHeight;
353 if (height < 0)
354 This->SourceRect.bottom = This->VideoHeight = -height;
355 else
356 This->SourceRect.bottom = This->VideoHeight = height;
358 else
360 WARN("Format type %s not supported\n", debugstr_guid(&pmt->formattype));
361 return S_FALSE;
363 return S_OK;
365 return S_FALSE;
368 static HRESULT WINAPI VideoRenderer_EndFlush(BaseRenderer* iface)
370 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
372 TRACE("(%p)->()\n", iface);
374 if (This->renderer.pMediaSample) {
375 ResetEvent(This->hEvent);
376 LeaveCriticalSection(iface->pInputPin->pin.pCritSec);
377 LeaveCriticalSection(&iface->csRenderLock);
378 LeaveCriticalSection(&iface->filter.csFilter);
379 WaitForSingleObject(This->hEvent, INFINITE);
380 EnterCriticalSection(&iface->filter.csFilter);
381 EnterCriticalSection(&iface->csRenderLock);
382 EnterCriticalSection(iface->pInputPin->pin.pCritSec);
384 if (This->renderer.filter.state == State_Paused) {
385 ResetEvent(This->hEvent);
388 return BaseRendererImpl_EndFlush(iface);
391 static VOID WINAPI VideoRenderer_OnStopStreaming(BaseRenderer* iface)
393 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
395 TRACE("(%p)->()\n", This);
397 SetEvent(This->hEvent);
398 if (This->baseControlWindow.AutoShow)
399 /* Black it out */
400 RedrawWindow(This->baseControlWindow.baseWindow.hWnd, NULL, NULL, RDW_INVALIDATE|RDW_ERASE);
403 static VOID WINAPI VideoRenderer_OnStartStreaming(BaseRenderer* iface)
405 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
407 TRACE("(%p)\n", This);
409 if (This->renderer.pInputPin->pin.pConnectedTo && (This->renderer.filter.state == State_Stopped || !This->renderer.pInputPin->end_of_stream))
411 if (This->renderer.filter.state == State_Stopped)
413 ResetEvent(This->hEvent);
414 VideoRenderer_AutoShowWindow(This);
419 static LPWSTR WINAPI VideoRenderer_GetClassWindowStyles(BaseWindow *This, DWORD *pClassStyles, DWORD *pWindowStyles, DWORD *pWindowStylesEx)
421 static const WCHAR classnameW[] = { 'W','i','n','e',' ','A','c','t','i','v','e','M','o','v','i','e',' ','C','l','a','s','s',0 };
423 *pClassStyles = 0;
424 *pWindowStyles = WS_SIZEBOX;
425 *pWindowStylesEx = 0;
427 return (LPWSTR)classnameW;
430 static RECT WINAPI VideoRenderer_GetDefaultRect(BaseWindow *iface)
432 VideoRendererImpl *This = impl_from_BaseWindow(iface);
433 static RECT defRect;
435 defRect.left = defRect.top = 0;
436 defRect.right = This->VideoWidth;
437 defRect.bottom = This->VideoHeight;
439 return defRect;
442 static BOOL WINAPI VideoRenderer_OnSize(BaseWindow *iface, LONG Width, LONG Height)
444 VideoRendererImpl *This = impl_from_BaseWindow(iface);
446 TRACE("WM_SIZE %d %d\n", Width, Height);
447 GetClientRect(iface->hWnd, &This->DestRect);
448 TRACE("WM_SIZING: DestRect=(%d,%d),(%d,%d)\n",
449 This->DestRect.left,
450 This->DestRect.top,
451 This->DestRect.right - This->DestRect.left,
452 This->DestRect.bottom - This->DestRect.top);
453 return BaseWindowImpl_OnSize(iface, Width, Height);
456 static const BaseRendererFuncTable BaseFuncTable = {
457 VideoRenderer_CheckMediaType,
458 VideoRenderer_DoRenderSample,
459 /**/
460 NULL,
461 NULL,
462 NULL,
463 VideoRenderer_OnStartStreaming,
464 VideoRenderer_OnStopStreaming,
465 NULL,
466 NULL,
467 NULL,
468 VideoRenderer_ShouldDrawSampleNow,
469 NULL,
470 /**/
471 NULL,
472 NULL,
473 NULL,
474 NULL,
475 VideoRenderer_EndFlush,
478 static const BaseWindowFuncTable renderer_BaseWindowFuncTable = {
479 VideoRenderer_GetClassWindowStyles,
480 VideoRenderer_GetDefaultRect,
481 NULL,
482 BaseControlWindowImpl_PossiblyEatMessage,
483 VideoRenderer_OnSize
486 static HRESULT WINAPI VideoRenderer_GetSourceRect(BaseControlVideo* iface, RECT *pSourceRect)
488 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
489 CopyRect(pSourceRect,&This->SourceRect);
490 return S_OK;
493 static HRESULT WINAPI VideoRenderer_GetStaticImage(BaseControlVideo* iface, LONG *pBufferSize, LONG *pDIBImage)
495 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
496 BITMAPINFOHEADER *bmiHeader;
497 LONG needed_size;
498 AM_MEDIA_TYPE *amt = &This->renderer.pInputPin->pin.mtCurrent;
499 char *ptr;
501 FIXME("(%p/%p)->(%p, %p): partial stub\n", This, iface, pBufferSize, pDIBImage);
503 EnterCriticalSection(&This->renderer.filter.csFilter);
505 if (!This->renderer.pMediaSample)
507 LeaveCriticalSection(&This->renderer.filter.csFilter);
508 return (This->renderer.filter.state == State_Paused ? E_UNEXPECTED : VFW_E_NOT_PAUSED);
511 if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo))
513 bmiHeader = &((VIDEOINFOHEADER *)amt->pbFormat)->bmiHeader;
515 else if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo2))
517 bmiHeader = &((VIDEOINFOHEADER2 *)amt->pbFormat)->bmiHeader;
519 else
521 FIXME("Unknown type %s\n", debugstr_guid(&amt->subtype));
522 LeaveCriticalSection(&This->renderer.filter.csFilter);
523 return VFW_E_RUNTIME_ERROR;
526 needed_size = bmiHeader->biSize;
527 needed_size += IMediaSample_GetActualDataLength(This->renderer.pMediaSample);
529 if (!pDIBImage)
531 *pBufferSize = needed_size;
532 LeaveCriticalSection(&This->renderer.filter.csFilter);
533 return S_OK;
536 if (needed_size < *pBufferSize)
538 ERR("Buffer too small %u/%u\n", needed_size, *pBufferSize);
539 LeaveCriticalSection(&This->renderer.filter.csFilter);
540 return E_FAIL;
542 *pBufferSize = needed_size;
544 memcpy(pDIBImage, bmiHeader, bmiHeader->biSize);
545 IMediaSample_GetPointer(This->renderer.pMediaSample, (BYTE **)&ptr);
546 memcpy((char *)pDIBImage + bmiHeader->biSize, ptr, IMediaSample_GetActualDataLength(This->renderer.pMediaSample));
548 LeaveCriticalSection(&This->renderer.filter.csFilter);
549 return S_OK;
552 static HRESULT WINAPI VideoRenderer_GetTargetRect(BaseControlVideo* iface, RECT *pTargetRect)
554 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
555 CopyRect(pTargetRect,&This->DestRect);
556 return S_OK;
559 static VIDEOINFOHEADER* WINAPI VideoRenderer_GetVideoFormat(BaseControlVideo* iface)
561 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
562 AM_MEDIA_TYPE *pmt;
564 TRACE("(%p/%p)\n", This, iface);
566 pmt = &This->renderer.pInputPin->pin.mtCurrent;
567 if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) {
568 return (VIDEOINFOHEADER*)pmt->pbFormat;
569 } else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2)) {
570 static VIDEOINFOHEADER vih;
571 VIDEOINFOHEADER2 *vih2 = (VIDEOINFOHEADER2*)pmt->pbFormat;
572 memcpy(&vih,vih2,sizeof(VIDEOINFOHEADER));
573 memcpy(&vih.bmiHeader, &vih2->bmiHeader, sizeof(BITMAPINFOHEADER));
574 return &vih;
575 } else {
576 ERR("Unknown format type %s\n", qzdebugstr_guid(&pmt->formattype));
577 return NULL;
581 static HRESULT WINAPI VideoRenderer_IsDefaultSourceRect(BaseControlVideo* iface)
583 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
584 FIXME("(%p/%p)->(): stub !!!\n", This, iface);
586 return S_OK;
589 static HRESULT WINAPI VideoRenderer_IsDefaultTargetRect(BaseControlVideo* iface)
591 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
592 FIXME("(%p/%p)->(): stub !!!\n", This, iface);
594 return S_OK;
597 static HRESULT WINAPI VideoRenderer_SetDefaultSourceRect(BaseControlVideo* iface)
599 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
601 This->SourceRect.left = 0;
602 This->SourceRect.top = 0;
603 This->SourceRect.right = This->VideoWidth;
604 This->SourceRect.bottom = This->VideoHeight;
606 return S_OK;
609 static HRESULT WINAPI VideoRenderer_SetDefaultTargetRect(BaseControlVideo* iface)
611 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
612 RECT rect;
614 if (!GetClientRect(This->baseControlWindow.baseWindow.hWnd, &rect))
615 return E_FAIL;
617 This->DestRect.left = 0;
618 This->DestRect.top = 0;
619 This->DestRect.right = rect.right;
620 This->DestRect.bottom = rect.bottom;
622 return S_OK;
625 static HRESULT WINAPI VideoRenderer_SetSourceRect(BaseControlVideo* iface, RECT *pSourceRect)
627 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
628 CopyRect(&This->SourceRect,pSourceRect);
629 return S_OK;
632 static HRESULT WINAPI VideoRenderer_SetTargetRect(BaseControlVideo* iface, RECT *pTargetRect)
634 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
635 CopyRect(&This->DestRect,pTargetRect);
636 return S_OK;
639 static const BaseControlVideoFuncTable renderer_BaseControlVideoFuncTable = {
640 VideoRenderer_GetSourceRect,
641 VideoRenderer_GetStaticImage,
642 VideoRenderer_GetTargetRect,
643 VideoRenderer_GetVideoFormat,
644 VideoRenderer_IsDefaultSourceRect,
645 VideoRenderer_IsDefaultTargetRect,
646 VideoRenderer_SetDefaultSourceRect,
647 VideoRenderer_SetDefaultTargetRect,
648 VideoRenderer_SetSourceRect,
649 VideoRenderer_SetTargetRect
652 static inline VideoRendererImpl *impl_from_IUnknown(IUnknown *iface)
654 return CONTAINING_RECORD(iface, VideoRendererImpl, IUnknown_inner);
657 static HRESULT WINAPI VideoRendererInner_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
659 VideoRendererImpl *This = impl_from_IUnknown(iface);
661 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
663 *ppv = NULL;
665 if (IsEqualIID(riid, &IID_IUnknown))
666 *ppv = &This->IUnknown_inner;
667 else if (IsEqualIID(riid, &IID_IBasicVideo))
668 *ppv = &This->baseControlVideo.IBasicVideo_iface;
669 else if (IsEqualIID(riid, &IID_IVideoWindow))
670 *ppv = &This->baseControlWindow.IVideoWindow_iface;
671 else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags))
672 *ppv = &This->IAMFilterMiscFlags_iface;
673 else
675 HRESULT hr;
676 hr = BaseRendererImpl_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
677 if (SUCCEEDED(hr))
678 return hr;
681 if (*ppv)
683 IUnknown_AddRef((IUnknown *)*ppv);
684 return S_OK;
687 if (!IsEqualIID(riid, &IID_IPin))
688 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
690 return E_NOINTERFACE;
693 static ULONG WINAPI VideoRendererInner_AddRef(IUnknown *iface)
695 VideoRendererImpl *This = impl_from_IUnknown(iface);
696 ULONG refCount = BaseFilterImpl_AddRef(&This->renderer.filter.IBaseFilter_iface);
698 TRACE("(%p)->(): new ref = %d\n", This, refCount);
700 return refCount;
703 static ULONG WINAPI VideoRendererInner_Release(IUnknown *iface)
705 VideoRendererImpl *This = impl_from_IUnknown(iface);
706 ULONG refCount = BaseRendererImpl_Release(&This->renderer.filter.IBaseFilter_iface);
708 TRACE("(%p)->(): new ref = %d\n", This, refCount);
710 if (!refCount)
712 BaseControlWindow_Destroy(&This->baseControlWindow);
713 BaseControlVideo_Destroy(&This->baseControlVideo);
714 PostThreadMessageW(This->ThreadID, WM_QUIT, 0, 0);
715 WaitForSingleObject(This->hThread, INFINITE);
716 CloseHandle(This->hThread);
717 CloseHandle(This->hEvent);
719 TRACE("Destroying Video Renderer\n");
720 CoTaskMemFree(This);
722 return 0;
724 else
725 return refCount;
728 static const IUnknownVtbl IInner_VTable =
730 VideoRendererInner_QueryInterface,
731 VideoRendererInner_AddRef,
732 VideoRendererInner_Release
735 static HRESULT WINAPI VideoRenderer_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
737 VideoRendererImpl *This = impl_from_IBaseFilter(iface);
738 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
741 static ULONG WINAPI VideoRenderer_AddRef(IBaseFilter * iface)
743 VideoRendererImpl *This = impl_from_IBaseFilter(iface);
744 return IUnknown_AddRef(This->outer_unk);
747 static ULONG WINAPI VideoRenderer_Release(IBaseFilter * iface)
749 VideoRendererImpl *This = impl_from_IBaseFilter(iface);
750 return IUnknown_Release(This->outer_unk);
753 /** IMediaFilter methods **/
755 static HRESULT WINAPI VideoRenderer_Pause(IBaseFilter * iface)
757 VideoRendererImpl *This = impl_from_IBaseFilter(iface);
759 TRACE("(%p/%p)->()\n", This, iface);
761 EnterCriticalSection(&This->renderer.csRenderLock);
762 if (This->renderer.filter.state != State_Paused)
764 if (This->renderer.filter.state == State_Stopped)
766 This->renderer.pInputPin->end_of_stream = 0;
767 ResetEvent(This->hEvent);
768 VideoRenderer_AutoShowWindow(This);
771 ResetEvent(This->renderer.RenderEvent);
772 This->renderer.filter.state = State_Paused;
774 LeaveCriticalSection(&This->renderer.csRenderLock);
776 return S_OK;
779 static const IBaseFilterVtbl VideoRenderer_Vtbl =
781 VideoRenderer_QueryInterface,
782 VideoRenderer_AddRef,
783 VideoRenderer_Release,
784 BaseFilterImpl_GetClassID,
785 BaseRendererImpl_Stop,
786 VideoRenderer_Pause,
787 BaseRendererImpl_Run,
788 BaseRendererImpl_GetState,
789 BaseRendererImpl_SetSyncSource,
790 BaseFilterImpl_GetSyncSource,
791 BaseFilterImpl_EnumPins,
792 BaseRendererImpl_FindPin,
793 BaseFilterImpl_QueryFilterInfo,
794 BaseFilterImpl_JoinFilterGraph,
795 BaseFilterImpl_QueryVendorInfo
798 /*** IUnknown methods ***/
799 static HRESULT WINAPI BasicVideo_QueryInterface(IBasicVideo *iface, REFIID riid, LPVOID *ppvObj)
801 VideoRendererImpl *This = impl_from_IBasicVideo(iface);
803 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
805 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
808 static ULONG WINAPI BasicVideo_AddRef(IBasicVideo *iface)
810 VideoRendererImpl *This = impl_from_IBasicVideo(iface);
812 TRACE("(%p/%p)->()\n", This, iface);
814 return IUnknown_AddRef(This->outer_unk);
817 static ULONG WINAPI BasicVideo_Release(IBasicVideo *iface)
819 VideoRendererImpl *This = impl_from_IBasicVideo(iface);
821 TRACE("(%p/%p)->()\n", This, iface);
823 return IUnknown_Release(This->outer_unk);
826 static const IBasicVideoVtbl IBasicVideo_VTable =
828 BasicVideo_QueryInterface,
829 BasicVideo_AddRef,
830 BasicVideo_Release,
831 BaseControlVideoImpl_GetTypeInfoCount,
832 BaseControlVideoImpl_GetTypeInfo,
833 BaseControlVideoImpl_GetIDsOfNames,
834 BaseControlVideoImpl_Invoke,
835 BaseControlVideoImpl_get_AvgTimePerFrame,
836 BaseControlVideoImpl_get_BitRate,
837 BaseControlVideoImpl_get_BitErrorRate,
838 BaseControlVideoImpl_get_VideoWidth,
839 BaseControlVideoImpl_get_VideoHeight,
840 BaseControlVideoImpl_put_SourceLeft,
841 BaseControlVideoImpl_get_SourceLeft,
842 BaseControlVideoImpl_put_SourceWidth,
843 BaseControlVideoImpl_get_SourceWidth,
844 BaseControlVideoImpl_put_SourceTop,
845 BaseControlVideoImpl_get_SourceTop,
846 BaseControlVideoImpl_put_SourceHeight,
847 BaseControlVideoImpl_get_SourceHeight,
848 BaseControlVideoImpl_put_DestinationLeft,
849 BaseControlVideoImpl_get_DestinationLeft,
850 BaseControlVideoImpl_put_DestinationWidth,
851 BaseControlVideoImpl_get_DestinationWidth,
852 BaseControlVideoImpl_put_DestinationTop,
853 BaseControlVideoImpl_get_DestinationTop,
854 BaseControlVideoImpl_put_DestinationHeight,
855 BaseControlVideoImpl_get_DestinationHeight,
856 BaseControlVideoImpl_SetSourcePosition,
857 BaseControlVideoImpl_GetSourcePosition,
858 BaseControlVideoImpl_SetDefaultSourcePosition,
859 BaseControlVideoImpl_SetDestinationPosition,
860 BaseControlVideoImpl_GetDestinationPosition,
861 BaseControlVideoImpl_SetDefaultDestinationPosition,
862 BaseControlVideoImpl_GetVideoSize,
863 BaseControlVideoImpl_GetVideoPaletteEntries,
864 BaseControlVideoImpl_GetCurrentImage,
865 BaseControlVideoImpl_IsUsingDefaultSource,
866 BaseControlVideoImpl_IsUsingDefaultDestination
870 /*** IUnknown methods ***/
871 static HRESULT WINAPI VideoWindow_QueryInterface(IVideoWindow *iface, REFIID riid, LPVOID *ppvObj)
873 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
875 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
877 return IUnknown_QueryInterface(This->outer_unk, riid, ppvObj);
880 static ULONG WINAPI VideoWindow_AddRef(IVideoWindow *iface)
882 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
884 TRACE("(%p/%p)->()\n", This, iface);
886 return IUnknown_AddRef(This->outer_unk);
889 static ULONG WINAPI VideoWindow_Release(IVideoWindow *iface)
891 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
893 TRACE("(%p/%p)->()\n", This, iface);
895 return IUnknown_Release(This->outer_unk);
898 static HRESULT WINAPI VideoWindow_get_FullScreenMode(IVideoWindow *iface,
899 LONG *FullScreenMode)
901 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
903 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, FullScreenMode);
905 return S_OK;
908 static HRESULT WINAPI VideoWindow_put_FullScreenMode(IVideoWindow *iface,
909 LONG FullScreenMode)
911 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
913 FIXME("(%p/%p)->(%d): stub !!!\n", This, iface, FullScreenMode);
915 if (FullScreenMode) {
916 This->baseControlWindow.baseWindow.WindowStyles = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE);
917 ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_HIDE);
918 SetParent(This->baseControlWindow.baseWindow.hWnd, 0);
919 SetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE, WS_POPUP);
920 SetWindowPos(This->baseControlWindow.baseWindow.hWnd,HWND_TOP,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN),SWP_SHOWWINDOW);
921 GetWindowRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect);
922 This->WindowPos = This->DestRect;
923 } else {
924 ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_HIDE);
925 SetParent(This->baseControlWindow.baseWindow.hWnd, This->baseControlWindow.hwndOwner);
926 SetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE, This->baseControlWindow.baseWindow.WindowStyles);
927 GetClientRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect);
928 SetWindowPos(This->baseControlWindow.baseWindow.hWnd,0,This->DestRect.left,This->DestRect.top,This->DestRect.right,This->DestRect.bottom,SWP_NOZORDER|SWP_SHOWWINDOW);
929 This->WindowPos = This->DestRect;
932 return S_OK;
935 static const IVideoWindowVtbl IVideoWindow_VTable =
937 VideoWindow_QueryInterface,
938 VideoWindow_AddRef,
939 VideoWindow_Release,
940 BaseControlWindowImpl_GetTypeInfoCount,
941 BaseControlWindowImpl_GetTypeInfo,
942 BaseControlWindowImpl_GetIDsOfNames,
943 BaseControlWindowImpl_Invoke,
944 BaseControlWindowImpl_put_Caption,
945 BaseControlWindowImpl_get_Caption,
946 BaseControlWindowImpl_put_WindowStyle,
947 BaseControlWindowImpl_get_WindowStyle,
948 BaseControlWindowImpl_put_WindowStyleEx,
949 BaseControlWindowImpl_get_WindowStyleEx,
950 BaseControlWindowImpl_put_AutoShow,
951 BaseControlWindowImpl_get_AutoShow,
952 BaseControlWindowImpl_put_WindowState,
953 BaseControlWindowImpl_get_WindowState,
954 BaseControlWindowImpl_put_BackgroundPalette,
955 BaseControlWindowImpl_get_BackgroundPalette,
956 BaseControlWindowImpl_put_Visible,
957 BaseControlWindowImpl_get_Visible,
958 BaseControlWindowImpl_put_Left,
959 BaseControlWindowImpl_get_Left,
960 BaseControlWindowImpl_put_Width,
961 BaseControlWindowImpl_get_Width,
962 BaseControlWindowImpl_put_Top,
963 BaseControlWindowImpl_get_Top,
964 BaseControlWindowImpl_put_Height,
965 BaseControlWindowImpl_get_Height,
966 BaseControlWindowImpl_put_Owner,
967 BaseControlWindowImpl_get_Owner,
968 BaseControlWindowImpl_put_MessageDrain,
969 BaseControlWindowImpl_get_MessageDrain,
970 BaseControlWindowImpl_get_BorderColor,
971 BaseControlWindowImpl_put_BorderColor,
972 VideoWindow_get_FullScreenMode,
973 VideoWindow_put_FullScreenMode,
974 BaseControlWindowImpl_SetWindowForeground,
975 BaseControlWindowImpl_NotifyOwnerMessage,
976 BaseControlWindowImpl_SetWindowPosition,
977 BaseControlWindowImpl_GetWindowPosition,
978 BaseControlWindowImpl_GetMinIdealImageSize,
979 BaseControlWindowImpl_GetMaxIdealImageSize,
980 BaseControlWindowImpl_GetRestorePosition,
981 BaseControlWindowImpl_HideCursor,
982 BaseControlWindowImpl_IsCursorHidden
985 static VideoRendererImpl *impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface)
987 return CONTAINING_RECORD(iface, VideoRendererImpl, IAMFilterMiscFlags_iface);
990 static HRESULT WINAPI AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid,
991 void **ppv)
993 VideoRendererImpl *This = impl_from_IAMFilterMiscFlags(iface);
994 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
997 static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface)
999 VideoRendererImpl *This = impl_from_IAMFilterMiscFlags(iface);
1000 return IUnknown_AddRef(This->outer_unk);
1003 static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface)
1005 VideoRendererImpl *This = impl_from_IAMFilterMiscFlags(iface);
1006 return IUnknown_Release(This->outer_unk);
1009 static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface)
1011 return AM_FILTER_MISC_FLAGS_IS_RENDERER;
1014 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = {
1015 AMFilterMiscFlags_QueryInterface,
1016 AMFilterMiscFlags_AddRef,
1017 AMFilterMiscFlags_Release,
1018 AMFilterMiscFlags_GetMiscFlags
1021 HRESULT VideoRenderer_create(IUnknown *pUnkOuter, void **ppv)
1023 HRESULT hr;
1024 VideoRendererImpl * pVideoRenderer;
1026 TRACE("(%p, %p)\n", pUnkOuter, ppv);
1028 *ppv = NULL;
1030 pVideoRenderer = CoTaskMemAlloc(sizeof(VideoRendererImpl));
1031 pVideoRenderer->IUnknown_inner.lpVtbl = &IInner_VTable;
1032 pVideoRenderer->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_Vtbl;
1034 pVideoRenderer->init = FALSE;
1035 ZeroMemory(&pVideoRenderer->SourceRect, sizeof(RECT));
1036 ZeroMemory(&pVideoRenderer->DestRect, sizeof(RECT));
1037 ZeroMemory(&pVideoRenderer->WindowPos, sizeof(RECT));
1039 if (pUnkOuter)
1040 pVideoRenderer->outer_unk = pUnkOuter;
1041 else
1042 pVideoRenderer->outer_unk = &pVideoRenderer->IUnknown_inner;
1044 hr = BaseRenderer_Init(&pVideoRenderer->renderer, &VideoRenderer_Vtbl, pUnkOuter,
1045 &CLSID_VideoRenderer, (DWORD_PTR)(__FILE__ ": VideoRendererImpl.csFilter"),
1046 &BaseFuncTable);
1048 if (FAILED(hr))
1049 goto fail;
1051 hr = BaseControlWindow_Init(&pVideoRenderer->baseControlWindow, &IVideoWindow_VTable,
1052 &pVideoRenderer->renderer.filter, &pVideoRenderer->renderer.filter.csFilter,
1053 &pVideoRenderer->renderer.pInputPin->pin, &renderer_BaseWindowFuncTable);
1054 if (FAILED(hr))
1055 goto fail;
1057 hr = BaseControlVideo_Init(&pVideoRenderer->baseControlVideo, &IBasicVideo_VTable,
1058 &pVideoRenderer->renderer.filter, &pVideoRenderer->renderer.filter.csFilter,
1059 &pVideoRenderer->renderer.pInputPin->pin, &renderer_BaseControlVideoFuncTable);
1060 if (FAILED(hr))
1061 goto fail;
1063 if (!CreateRenderingSubsystem(pVideoRenderer)) {
1064 hr = E_FAIL;
1065 goto fail;
1068 *ppv = &pVideoRenderer->IUnknown_inner;
1069 return S_OK;
1071 fail:
1072 BaseRendererImpl_Release(&pVideoRenderer->renderer.filter.IBaseFilter_iface);
1073 CoTaskMemFree(pVideoRenderer);
1074 return hr;
1077 HRESULT VideoRendererDefault_create(IUnknown * pUnkOuter, LPVOID * ppv)
1079 /* TODO: Attempt to use the VMR-7 renderer instead when possible */
1080 return VideoRenderer_create(pUnkOuter, ppv);