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