wineqtdecoder: Recreate audio extraction session when we run out of frames.
[wine.git] / dlls / quartz / videorenderer.c
blob87f3ea9800108d1c807b657f8fc4256467357e01
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 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;
51 typedef struct VideoRendererImpl
53 BaseRenderer renderer;
54 BaseControlWindow baseControlWindow;
55 BaseControlVideo baseControlVideo;
57 const IUnknownVtbl * IInner_vtbl;
58 const IAMFilterMiscFlagsVtbl *IAMFilterMiscFlags_vtbl;
60 BOOL init;
61 HANDLE hThread;
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;
77 static inline VideoRendererImpl *impl_from_BaseWindow(BaseWindow *iface)
79 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlWindow.baseWindow);
82 static inline VideoRendererImpl *impl_from_BaseRenderer(BaseRenderer *iface)
84 return CONTAINING_RECORD(iface, VideoRendererImpl, renderer);
87 static inline VideoRendererImpl *impl_from_IBaseFilter(IBaseFilter *iface)
89 return CONTAINING_RECORD(iface, VideoRendererImpl, renderer.filter.IBaseFilter_iface);
92 static inline VideoRendererImpl *impl_from_IVideoWindow(IVideoWindow *iface)
94 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlWindow.IVideoWindow_iface);
97 static inline VideoRendererImpl *impl_from_BaseControlVideo(BaseControlVideo *iface)
99 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlVideo);
102 static inline VideoRendererImpl *impl_from_IBasicVideo(IBasicVideo *iface)
104 return CONTAINING_RECORD(iface, VideoRendererImpl, baseControlVideo.IBasicVideo_iface);
107 static DWORD WINAPI MessageLoop(LPVOID lpParameter)
109 VideoRendererImpl* This = lpParameter;
110 MSG msg;
111 BOOL fGotMessage;
113 TRACE("Starting message loop\n");
115 if (FAILED(BaseWindowImpl_PrepareWindow(&This->baseControlWindow.baseWindow)))
117 This->ThreadResult = FALSE;
118 SetEvent(This->hEvent);
119 return 0;
122 This->ThreadResult = TRUE;
123 SetEvent(This->hEvent);
125 while ((fGotMessage = GetMessageW(&msg, NULL, 0, 0)) != 0 && fGotMessage != -1)
127 TranslateMessage(&msg);
128 DispatchMessageW(&msg);
131 TRACE("End of message loop\n");
133 return msg.wParam;
136 static BOOL CreateRenderingSubsystem(VideoRendererImpl* This)
138 This->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
139 if (!This->hEvent)
140 return FALSE;
142 This->hThread = CreateThread(NULL, 0, MessageLoop, This, 0, &This->ThreadID);
143 if (!This->hThread)
145 CloseHandle(This->hEvent);
146 return FALSE;
149 WaitForSingleObject(This->hEvent, INFINITE);
151 if (!This->ThreadResult)
153 CloseHandle(This->hEvent);
154 CloseHandle(This->hThread);
155 return FALSE;
158 return TRUE;
161 static void VideoRenderer_AutoShowWindow(VideoRendererImpl *This) {
162 if (!This->init && (!This->WindowPos.right || !This->WindowPos.top))
164 DWORD style = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_STYLE);
165 DWORD style_ex = GetWindowLongW(This->baseControlWindow.baseWindow.hWnd, GWL_EXSTYLE);
167 if (!This->WindowPos.right)
169 This->WindowPos.left = This->SourceRect.left;
170 This->WindowPos.right = This->SourceRect.right;
172 if (!This->WindowPos.bottom)
174 This->WindowPos.top = This->SourceRect.top;
175 This->WindowPos.bottom = This->SourceRect.bottom;
178 AdjustWindowRectEx(&This->WindowPos, style, TRUE, style_ex);
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);
188 GetClientRect(This->baseControlWindow.baseWindow.hWnd, &This->DestRect);
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);
197 static DWORD VideoRenderer_SendSampleData(VideoRendererImpl* This, LPBYTE data, DWORD size)
199 AM_MEDIA_TYPE amt;
200 HRESULT hr = S_OK;
201 DDSURFACEDESC sdesc;
202 BITMAPINFOHEADER *bmiHeader;
204 TRACE("(%p)->(%p, %d)\n", This, data, size);
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;
213 if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo))
215 bmiHeader = &((VIDEOINFOHEADER *)amt.pbFormat)->bmiHeader;
217 else if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo2))
219 bmiHeader = &((VIDEOINFOHEADER2 *)amt.pbFormat)->bmiHeader;
221 else
223 FIXME("Unknown type %s\n", debugstr_guid(&amt.subtype));
224 return VFW_E_RUNTIME_ERROR;
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);
235 if (!This->baseControlWindow.baseWindow.hDC) {
236 ERR("Cannot get DC from window!\n");
237 return E_FAIL;
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);
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);
248 return S_OK;
251 static HRESULT WINAPI VideoRenderer_ShouldDrawSampleNow(BaseRenderer *This, IMediaSample *pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime)
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;
259 static HRESULT WINAPI VideoRenderer_DoRenderSample(BaseRenderer* iface, IMediaSample * pSample)
261 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
262 LPBYTE pbSrcStream = NULL;
263 LONG cbSrcStream = 0;
264 HRESULT hr;
266 TRACE("(%p)->(%p)\n", This, pSample);
268 hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
269 if (FAILED(hr))
271 ERR("Cannot get pointer to sample data (%x)\n", hr);
272 return hr;
275 cbSrcStream = IMediaSample_GetActualDataLength(pSample);
277 TRACE("val %p %d\n", pbSrcStream, cbSrcStream);
279 #if 0 /* For debugging purpose */
281 int i;
282 for(i = 0; i < cbSrcStream; i++)
284 if ((i!=0) && !(i%16))
285 TRACE("\n");
286 TRACE("%02x ", pbSrcStream[i]);
288 TRACE("\n");
290 #endif
292 SetEvent(This->hEvent);
293 if (This->renderer.filter.state == State_Paused)
295 VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream);
296 SetEvent(This->hEvent);
297 if (This->renderer.filter.state == State_Paused)
299 /* Flushing */
300 return S_OK;
302 if (This->renderer.filter.state == State_Stopped)
304 return VFW_E_WRONG_STATE;
306 } else {
307 VideoRenderer_SendSampleData(This, pbSrcStream, cbSrcStream);
309 return S_OK;
312 static HRESULT WINAPI VideoRenderer_CheckMediaType(BaseRenderer *iface, const AM_MEDIA_TYPE * pmt)
314 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
316 if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Video))
317 return S_FALSE;
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))
324 LONG height;
326 if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo))
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;
338 else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2))
340 VIDEOINFOHEADER2 *format2 = (VIDEOINFOHEADER2 *)pmt->pbFormat;
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;
351 else
353 WARN("Format type %s not supported\n", debugstr_guid(&pmt->formattype));
354 return S_FALSE;
356 return S_OK;
358 return S_FALSE;
361 static HRESULT WINAPI VideoRenderer_EndFlush(BaseRenderer* iface)
363 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
365 TRACE("(%p)->()\n", iface);
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);
377 if (This->renderer.filter.state == State_Paused) {
378 ResetEvent(This->hEvent);
381 return BaseRendererImpl_EndFlush(iface);
384 static VOID WINAPI VideoRenderer_OnStopStreaming(BaseRenderer* iface)
386 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
388 TRACE("(%p)->()\n", This);
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);
396 static VOID WINAPI VideoRenderer_OnStartStreaming(BaseRenderer* iface)
398 VideoRendererImpl *This = impl_from_BaseRenderer(iface);
400 TRACE("(%p)\n", This);
402 if (This->renderer.pInputPin->pin.pConnectedTo && (This->renderer.filter.state == State_Stopped || !This->renderer.pInputPin->end_of_stream))
404 if (This->renderer.filter.state == State_Stopped)
406 ResetEvent(This->hEvent);
407 VideoRenderer_AutoShowWindow(This);
412 static LPWSTR WINAPI VideoRenderer_GetClassWindowStyles(BaseWindow *This, DWORD *pClassStyles, DWORD *pWindowStyles, DWORD *pWindowStylesEx)
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 };
416 *pClassStyles = 0;
417 *pWindowStyles = WS_SIZEBOX;
418 *pWindowStylesEx = 0;
420 return (LPWSTR)classnameW;
423 static RECT WINAPI VideoRenderer_GetDefaultRect(BaseWindow *iface)
425 VideoRendererImpl *This = impl_from_BaseWindow(iface);
426 static RECT defRect;
428 defRect.left = defRect.top = 0;
429 defRect.right = This->VideoWidth;
430 defRect.bottom = This->VideoHeight;
432 return defRect;
435 static BOOL WINAPI VideoRenderer_OnSize(BaseWindow *iface, LONG Width, LONG Height)
437 VideoRendererImpl *This = impl_from_BaseWindow(iface);
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);
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,
471 static const BaseWindowFuncTable renderer_BaseWindowFuncTable = {
472 VideoRenderer_GetClassWindowStyles,
473 VideoRenderer_GetDefaultRect,
474 NULL,
475 BaseControlWindowImpl_PossiblyEatMessage,
476 VideoRenderer_OnSize
479 static HRESULT WINAPI VideoRenderer_GetSourceRect(BaseControlVideo* iface, RECT *pSourceRect)
481 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
482 CopyRect(pSourceRect,&This->SourceRect);
483 return S_OK;
486 static HRESULT WINAPI VideoRenderer_GetStaticImage(BaseControlVideo* iface, LONG *pBufferSize, LONG *pDIBImage)
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;
494 FIXME("(%p/%p)->(%p, %p): partial stub\n", This, iface, pBufferSize, pDIBImage);
496 EnterCriticalSection(&This->renderer.filter.csFilter);
498 if (!This->renderer.pMediaSample)
500 LeaveCriticalSection(&This->renderer.filter.csFilter);
501 return (This->renderer.filter.state == State_Paused ? E_UNEXPECTED : VFW_E_NOT_PAUSED);
504 if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo))
506 bmiHeader = &((VIDEOINFOHEADER *)amt->pbFormat)->bmiHeader;
508 else if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo2))
510 bmiHeader = &((VIDEOINFOHEADER2 *)amt->pbFormat)->bmiHeader;
512 else
514 FIXME("Unknown type %s\n", debugstr_guid(&amt->subtype));
515 LeaveCriticalSection(&This->renderer.filter.csFilter);
516 return VFW_E_RUNTIME_ERROR;
519 needed_size = bmiHeader->biSize;
520 needed_size += IMediaSample_GetActualDataLength(This->renderer.pMediaSample);
522 if (!pDIBImage)
524 *pBufferSize = needed_size;
525 LeaveCriticalSection(&This->renderer.filter.csFilter);
526 return S_OK;
529 if (needed_size < *pBufferSize)
531 ERR("Buffer too small %u/%u\n", needed_size, *pBufferSize);
532 LeaveCriticalSection(&This->renderer.filter.csFilter);
533 return E_FAIL;
535 *pBufferSize = needed_size;
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));
541 LeaveCriticalSection(&This->renderer.filter.csFilter);
542 return S_OK;
545 static HRESULT WINAPI VideoRenderer_GetTargetRect(BaseControlVideo* iface, RECT *pTargetRect)
547 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
548 CopyRect(pTargetRect,&This->DestRect);
549 return S_OK;
552 static VIDEOINFOHEADER* WINAPI VideoRenderer_GetVideoFormat(BaseControlVideo* iface)
554 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
555 AM_MEDIA_TYPE *pmt;
557 TRACE("(%p/%p)\n", This, iface);
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;
574 static HRESULT WINAPI VideoRenderer_IsDefaultSourceRect(BaseControlVideo* iface)
576 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
577 FIXME("(%p/%p)->(): stub !!!\n", This, iface);
579 return S_OK;
582 static HRESULT WINAPI VideoRenderer_IsDefaultTargetRect(BaseControlVideo* iface)
584 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
585 FIXME("(%p/%p)->(): stub !!!\n", This, iface);
587 return S_OK;
590 static HRESULT WINAPI VideoRenderer_SetDefaultSourceRect(BaseControlVideo* iface)
592 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
594 This->SourceRect.left = 0;
595 This->SourceRect.top = 0;
596 This->SourceRect.right = This->VideoWidth;
597 This->SourceRect.bottom = This->VideoHeight;
599 return S_OK;
602 static HRESULT WINAPI VideoRenderer_SetDefaultTargetRect(BaseControlVideo* iface)
604 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
605 RECT rect;
607 if (!GetClientRect(This->baseControlWindow.baseWindow.hWnd, &rect))
608 return E_FAIL;
610 This->SourceRect.left = 0;
611 This->SourceRect.top = 0;
612 This->SourceRect.right = rect.right;
613 This->SourceRect.bottom = rect.bottom;
615 return S_OK;
618 static HRESULT WINAPI VideoRenderer_SetSourceRect(BaseControlVideo* iface, RECT *pSourceRect)
620 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
621 CopyRect(&This->SourceRect,pSourceRect);
622 return S_OK;
625 static HRESULT WINAPI VideoRenderer_SetTargetRect(BaseControlVideo* iface, RECT *pTargetRect)
627 VideoRendererImpl *This = impl_from_BaseControlVideo(iface);
628 CopyRect(&This->DestRect,pTargetRect);
629 return S_OK;
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
645 HRESULT VideoRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv)
647 HRESULT hr;
648 VideoRendererImpl * pVideoRenderer;
650 TRACE("(%p, %p)\n", pUnkOuter, ppv);
652 *ppv = NULL;
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;
661 pVideoRenderer->init = 0;
662 ZeroMemory(&pVideoRenderer->SourceRect, sizeof(RECT));
663 ZeroMemory(&pVideoRenderer->DestRect, sizeof(RECT));
664 ZeroMemory(&pVideoRenderer->WindowPos, sizeof(RECT));
666 hr = BaseRenderer_Init(&pVideoRenderer->renderer, &VideoRenderer_Vtbl, pUnkOuter, &CLSID_VideoRenderer, (DWORD_PTR)(__FILE__ ": VideoRendererImpl.csFilter"), &BaseFuncTable);
668 if (FAILED(hr))
669 goto fail;
671 *ppv = pVideoRenderer;
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;
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;
681 if (!CreateRenderingSubsystem(pVideoRenderer))
682 return E_FAIL;
684 return hr;
685 fail:
686 BaseRendererImpl_Release(&pVideoRenderer->renderer.filter.IBaseFilter_iface);
687 CoTaskMemFree(pVideoRenderer);
688 return hr;
691 HRESULT VideoRendererDefault_create(IUnknown * pUnkOuter, LPVOID * ppv)
693 /* TODO: Attempt to use the VMR-7 renderer instead when possible */
694 return VideoRenderer_create(pUnkOuter, ppv);
697 static HRESULT WINAPI VideoRendererInner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
699 ICOM_THIS_MULTI(VideoRendererImpl, IInner_vtbl, iface);
700 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
702 if (This->bAggregatable)
703 This->bUnkOuterValid = TRUE;
705 *ppv = NULL;
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
717 HRESULT hr;
718 hr = BaseRendererImpl_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
719 if (SUCCEEDED(hr))
720 return hr;
723 if (*ppv)
725 IUnknown_AddRef((IUnknown *)(*ppv));
726 return S_OK;
729 if (!IsEqualIID(riid, &IID_IPin))
730 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
732 return E_NOINTERFACE;
735 static ULONG WINAPI VideoRendererInner_AddRef(IUnknown * iface)
737 ICOM_THIS_MULTI(VideoRendererImpl, IInner_vtbl, iface);
738 ULONG refCount = BaseFilterImpl_AddRef(&This->renderer.filter.IBaseFilter_iface);
740 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
742 return refCount;
745 static ULONG WINAPI VideoRendererInner_Release(IUnknown * iface)
747 ICOM_THIS_MULTI(VideoRendererImpl, IInner_vtbl, iface);
748 ULONG refCount = BaseRendererImpl_Release(&This->renderer.filter.IBaseFilter_iface);
750 TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
752 if (!refCount)
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);
761 TRACE("Destroying Video Renderer\n");
762 CoTaskMemFree(This);
764 return 0;
766 else
767 return refCount;
770 static const IUnknownVtbl IInner_VTable =
772 VideoRendererInner_QueryInterface,
773 VideoRendererInner_AddRef,
774 VideoRendererInner_Release
777 static HRESULT WINAPI VideoRenderer_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
779 VideoRendererImpl *This = impl_from_IBaseFilter(iface);
781 if (This->bAggregatable)
782 This->bUnkOuterValid = TRUE;
784 if (This->pUnkOuter)
786 if (This->bAggregatable)
787 return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
789 if (IsEqualIID(riid, &IID_IUnknown))
791 HRESULT hr;
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;
800 *ppv = NULL;
801 return E_NOINTERFACE;
804 return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
807 static ULONG WINAPI VideoRenderer_AddRef(IBaseFilter * iface)
809 VideoRendererImpl *This = impl_from_IBaseFilter(iface);
811 if (This->pUnkOuter && This->bUnkOuterValid)
812 return IUnknown_AddRef(This->pUnkOuter);
813 return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
816 static ULONG WINAPI VideoRenderer_Release(IBaseFilter * iface)
818 VideoRendererImpl *This = impl_from_IBaseFilter(iface);
820 if (This->pUnkOuter && This->bUnkOuterValid)
821 return IUnknown_Release(This->pUnkOuter);
822 return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
825 /** IMediaFilter methods **/
827 static HRESULT WINAPI VideoRenderer_Pause(IBaseFilter * iface)
829 VideoRendererImpl *This = impl_from_IBaseFilter(iface);
831 TRACE("(%p/%p)->()\n", This, iface);
833 EnterCriticalSection(&This->renderer.csRenderLock);
834 if (This->renderer.filter.state != State_Paused)
836 if (This->renderer.filter.state == State_Stopped)
838 This->renderer.pInputPin->end_of_stream = 0;
839 ResetEvent(This->hEvent);
840 VideoRenderer_AutoShowWindow(This);
843 ResetEvent(This->renderer.RenderEvent);
844 This->renderer.filter.state = State_Paused;
846 LeaveCriticalSection(&This->renderer.csRenderLock);
848 return S_OK;
851 static const IBaseFilterVtbl VideoRenderer_Vtbl =
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
870 /*** IUnknown methods ***/
871 static HRESULT WINAPI Basicvideo_QueryInterface(IBasicVideo *iface,
872 REFIID riid,
873 LPVOID*ppvObj) {
874 VideoRendererImpl *This = impl_from_IBasicVideo(iface);
876 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
878 return VideoRenderer_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppvObj);
881 static ULONG WINAPI Basicvideo_AddRef(IBasicVideo *iface) {
882 VideoRendererImpl *This = impl_from_IBasicVideo(iface);
884 TRACE("(%p/%p)->()\n", This, iface);
886 return VideoRenderer_AddRef(&This->renderer.filter.IBaseFilter_iface);
889 static ULONG WINAPI Basicvideo_Release(IBasicVideo *iface) {
890 VideoRendererImpl *This = impl_from_IBasicVideo(iface);
892 TRACE("(%p/%p)->()\n", This, iface);
894 return VideoRenderer_Release(&This->renderer.filter.IBaseFilter_iface);
897 static const IBasicVideoVtbl IBasicVideo_VTable =
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
941 /*** IUnknown methods ***/
942 static HRESULT WINAPI Videowindow_QueryInterface(IVideoWindow *iface,
943 REFIID riid,
944 LPVOID*ppvObj) {
945 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
947 TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
949 return VideoRenderer_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppvObj);
952 static ULONG WINAPI Videowindow_AddRef(IVideoWindow *iface) {
953 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
955 TRACE("(%p/%p)->()\n", This, iface);
957 return VideoRenderer_AddRef(&This->renderer.filter.IBaseFilter_iface);
960 static ULONG WINAPI Videowindow_Release(IVideoWindow *iface) {
961 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
963 TRACE("(%p/%p)->()\n", This, iface);
965 return VideoRenderer_Release(&This->renderer.filter.IBaseFilter_iface);
968 static HRESULT WINAPI Videowindow_get_FullScreenMode(IVideoWindow *iface,
969 LONG *FullScreenMode) {
970 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
972 FIXME("(%p/%p)->(%p): stub !!!\n", This, iface, FullScreenMode);
974 return S_OK;
977 static HRESULT WINAPI Videowindow_put_FullScreenMode(IVideoWindow *iface,
978 LONG FullScreenMode) {
979 VideoRendererImpl *This = impl_from_IVideoWindow(iface);
981 FIXME("(%p/%p)->(%d): stub !!!\n", This, iface, FullScreenMode);
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;
1000 return S_OK;
1003 static const IVideoWindowVtbl IVideoWindow_VTable =
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
1053 static VideoRendererImpl *from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface) {
1054 return (VideoRendererImpl*)((char*)iface - offsetof(VideoRendererImpl, IAMFilterMiscFlags_vtbl));
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);
1062 static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface) {
1063 VideoRendererImpl *This = from_IAMFilterMiscFlags(iface);
1064 return IUnknown_AddRef((IUnknown*)This);
1067 static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface) {
1068 VideoRendererImpl *This = from_IAMFilterMiscFlags(iface);
1069 return IUnknown_Release((IUnknown*)This);
1072 static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface) {
1073 return AM_FILTER_MISC_FLAGS_IS_RENDERER;
1076 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = {
1077 AMFilterMiscFlags_QueryInterface,
1078 AMFilterMiscFlags_AddRef,
1079 AMFilterMiscFlags_Release,
1080 AMFilterMiscFlags_GetMiscFlags