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