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