d3drm: Implement IDirect3DRMMeshImpl_GetGroupMaterial.
[wine] / dlls / quartz / vmr9.c
1 /*
2  * Video Mixing Renderer for dx9
3  *
4  * Copyright 2004 Christian Costa
5  * Copyright 2008 Maarten Lankhorst
6  * Copyright 2012 Aric Stewart
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24
25 #define NONAMELESSSTRUCT
26 #define NONAMELESSUNION
27 #include "quartz_private.h"
28
29 #include "uuids.h"
30 #include "vfwmsgs.h"
31 #include "amvideo.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "dshow.h"
35 #include "evcode.h"
36 #include "strmif.h"
37 #include "ddraw.h"
38 #include "dvdmedia.h"
39 #include "d3d9.h"
40 #include "vmr9.h"
41 #include "pin.h"
42
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
47
48 typedef struct
49 {
50     BaseRenderer renderer;
51     BaseControlWindow baseControlWindow;
52     BaseControlVideo baseControlVideo;
53
54     IUnknown IUnknown_inner;
55     IAMFilterMiscFlags IAMFilterMiscFlags_iface;
56     IVMRFilterConfig9 IVMRFilterConfig9_iface;
57     IVMRWindowlessControl9 IVMRWindowlessControl9_iface;
58     IVMRSurfaceAllocatorNotify9 IVMRSurfaceAllocatorNotify9_iface;
59
60     IVMRSurfaceAllocatorEx9 *allocator;
61     IVMRImagePresenter9 *presenter;
62     BOOL allocator_is_ex;
63
64     VMR9Mode mode;
65     BITMAPINFOHEADER bmiheader;
66     IUnknown * outer_unk;
67     BOOL bUnkOuterValid;
68     BOOL bAggregatable;
69
70     DWORD_PTR cookie;
71
72     /* for Windowless Mode */
73     HWND hWndClippingWindow;
74
75     RECT source_rect;
76     RECT target_rect;
77     LONG VideoWidth;
78     LONG VideoHeight;
79 } VMR9Impl;
80
81 static inline VMR9Impl *impl_from_inner_IUnknown(IUnknown *iface)
82 {
83     return CONTAINING_RECORD(iface, VMR9Impl, IUnknown_inner);
84 }
85
86 static inline VMR9Impl *impl_from_BaseWindow( BaseWindow *wnd )
87 {
88     return CONTAINING_RECORD(wnd, VMR9Impl, baseControlWindow.baseWindow);
89 }
90
91 static inline VMR9Impl *impl_from_IVideoWindow( IVideoWindow *iface)
92 {
93     return CONTAINING_RECORD(iface, VMR9Impl, baseControlWindow.IVideoWindow_iface);
94 }
95
96 static inline VMR9Impl *impl_from_BaseControlVideo( BaseControlVideo *cvid )
97 {
98     return CONTAINING_RECORD(cvid, VMR9Impl, baseControlVideo);
99 }
100
101 static inline VMR9Impl *impl_from_IBasicVideo( IBasicVideo *iface)
102 {
103     return CONTAINING_RECORD(iface, VMR9Impl, baseControlVideo.IBasicVideo_iface);
104 }
105
106 static inline VMR9Impl *impl_from_IAMFilterMiscFlags( IAMFilterMiscFlags *iface)
107 {
108     return CONTAINING_RECORD(iface, VMR9Impl, IAMFilterMiscFlags_iface);
109 }
110
111 static inline VMR9Impl *impl_from_IVMRFilterConfig9( IVMRFilterConfig9 *iface)
112 {
113     return CONTAINING_RECORD(iface, VMR9Impl, IVMRFilterConfig9_iface);
114 }
115
116 static inline VMR9Impl *impl_from_IVMRWindowlessControl9( IVMRWindowlessControl9 *iface)
117 {
118     return CONTAINING_RECORD(iface, VMR9Impl, IVMRWindowlessControl9_iface);
119 }
120
121 static inline VMR9Impl *impl_from_IVMRSurfaceAllocatorNotify9( IVMRSurfaceAllocatorNotify9 *iface)
122 {
123     return CONTAINING_RECORD(iface, VMR9Impl, IVMRSurfaceAllocatorNotify9_iface);
124 }
125
126 typedef struct
127 {
128     IVMRImagePresenter9 IVMRImagePresenter9_iface;
129
130     LONG refCount;
131
132     IDirect3DDevice9 *d3d9_dev;
133     IDirect3D9 *d3d9_ptr;
134     IDirect3DVertexBuffer9 *d3d9_vertex;
135
136     VMR9AllocationInfo info;
137
138     VMR9Impl* pVMR9;
139 } VMR9DefaultAllocatorPresenterImpl;
140
141 static inline VMR9DefaultAllocatorPresenterImpl *impl_from_IVMRImagePresenter9( IVMRImagePresenter9 *iface)
142 {
143     return CONTAINING_RECORD(iface, VMR9DefaultAllocatorPresenterImpl, IVMRImagePresenter9_iface);
144 }
145
146 static HRESULT VMR9DefaultAllocatorPresenterImpl_create(VMR9Impl *parent, LPVOID * ppv);
147
148 static HRESULT WINAPI VMR9_DoRenderSample(BaseRenderer *iface, IMediaSample * pSample)
149 {
150     VMR9Impl *This = (VMR9Impl *)iface;
151     LPBYTE pbSrcStream = NULL;
152     REFERENCE_TIME tStart, tStop;
153     VMR9PresentationInfo info;
154     HRESULT hr;
155
156     TRACE("%p %p\n", iface, pSample);
157
158     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
159     if (FAILED(hr))
160         info.dwFlags = VMR9Sample_SrcDstRectsValid;
161     else
162         info.dwFlags = VMR9Sample_SrcDstRectsValid | VMR9Sample_TimeValid;
163
164     if (IMediaSample_IsDiscontinuity(pSample) == S_OK)
165         info.dwFlags |= VMR9Sample_Discontinuity;
166
167     if (IMediaSample_IsPreroll(pSample) == S_OK)
168         info.dwFlags |= VMR9Sample_Preroll;
169
170     if (IMediaSample_IsSyncPoint(pSample) == S_OK)
171         info.dwFlags |= VMR9Sample_SyncPoint;
172
173     hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
174     if (FAILED(hr))
175     {
176         ERR("Cannot get pointer to sample data (%x)\n", hr);
177         return hr;
178     }
179
180     info.rtStart = tStart;
181     info.rtEnd = tStop;
182     info.szAspectRatio.cx = This->bmiheader.biWidth;
183     info.szAspectRatio.cy = This->bmiheader.biHeight;
184
185     return hr;
186 }
187
188 static HRESULT WINAPI VMR9_CheckMediaType(BaseRenderer *iface, const AM_MEDIA_TYPE * pmt)
189 {
190     VMR9Impl *This = (VMR9Impl*)iface;
191
192     if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) || !pmt->pbFormat)
193         return S_FALSE;
194
195     /* Ignore subtype, test for bicompression instead */
196     if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo))
197     {
198         VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)pmt->pbFormat;
199
200         This->bmiheader = format->bmiHeader;
201         TRACE("Resolution: %dx%d\n", format->bmiHeader.biWidth, format->bmiHeader.biHeight);
202         This->source_rect.right = This->VideoWidth = format->bmiHeader.biWidth;
203         This->source_rect.bottom = This->VideoHeight = format->bmiHeader.biHeight;
204         This->source_rect.top = This->source_rect.left = 0;
205     }
206     else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2))
207     {
208         VIDEOINFOHEADER2 *format = (VIDEOINFOHEADER2 *)pmt->pbFormat;
209
210         This->bmiheader = format->bmiHeader;
211
212         TRACE("Resolution: %dx%d\n", format->bmiHeader.biWidth, format->bmiHeader.biHeight);
213         This->source_rect.right = This->VideoWidth = format->bmiHeader.biWidth;
214         This->source_rect.bottom = This->VideoHeight = format->bmiHeader.biHeight;
215         This->source_rect.top = This->source_rect.left = 0;
216     }
217     else
218     {
219         ERR("Format type %s not supported\n", debugstr_guid(&pmt->formattype));
220         return S_FALSE;
221     }
222     if (This->bmiheader.biCompression)
223         return S_FALSE;
224     return S_OK;
225 }
226
227 static HRESULT WINAPI VMR9_ShouldDrawSampleNow(BaseRenderer *This, IMediaSample *pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime)
228 {
229     /* Preroll means the sample isn't shown, this is used for key frames and things like that */
230     if (IMediaSample_IsPreroll(pSample) == S_OK)
231         return E_FAIL;
232     return S_FALSE;
233 }
234
235 static const BaseRendererFuncTable BaseFuncTable = {
236     VMR9_CheckMediaType,
237     VMR9_DoRenderSample,
238     /**/
239     NULL,
240     NULL,
241     NULL,
242     NULL,
243     NULL,
244     NULL,
245     NULL,
246     NULL,
247     VMR9_ShouldDrawSampleNow,
248     NULL,
249     /**/
250     NULL,
251     NULL,
252     NULL,
253     NULL,
254     NULL,
255 };
256
257 static LPWSTR WINAPI VMR9_GetClassWindowStyles(BaseWindow *This, DWORD *pClassStyles, DWORD *pWindowStyles, DWORD *pWindowStylesEx)
258 {
259     static WCHAR classnameW[] = { 'I','V','M','R','9',' ','C','l','a','s','s', 0 };
260
261     *pClassStyles = 0;
262     *pWindowStyles = WS_SIZEBOX;
263     *pWindowStylesEx = 0;
264
265     return classnameW;
266 }
267
268 static RECT WINAPI VMR9_GetDefaultRect(BaseWindow *This)
269 {
270     VMR9Impl* pVMR9 = impl_from_BaseWindow(This);
271     static RECT defRect;
272
273     defRect.left = defRect.top = 0;
274     defRect.right = pVMR9->VideoWidth;
275     defRect.bottom = pVMR9->VideoHeight;
276
277     return defRect;
278 }
279
280 static BOOL WINAPI VMR9_OnSize(BaseWindow *This, LONG Width, LONG Height)
281 {
282     VMR9Impl* pVMR9 = impl_from_BaseWindow(This);
283
284     TRACE("WM_SIZE %d %d\n", Width, Height);
285     GetClientRect(This->hWnd, &pVMR9->target_rect);
286     TRACE("WM_SIZING: DestRect=(%d,%d),(%d,%d)\n",
287         pVMR9->target_rect.left,
288         pVMR9->target_rect.top,
289         pVMR9->target_rect.right - pVMR9->target_rect.left,
290         pVMR9->target_rect.bottom - pVMR9->target_rect.top);
291     return BaseWindowImpl_OnSize(This, Width, Height);
292 }
293
294 static const BaseWindowFuncTable renderer_BaseWindowFuncTable = {
295     VMR9_GetClassWindowStyles,
296     VMR9_GetDefaultRect,
297     NULL,
298     BaseControlWindowImpl_PossiblyEatMessage,
299     VMR9_OnSize,
300 };
301
302 static HRESULT WINAPI VMR9_GetSourceRect(BaseControlVideo* This, RECT *pSourceRect)
303 {
304     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
305     CopyRect(pSourceRect,&pVMR9->source_rect);
306     return S_OK;
307 }
308
309 static HRESULT WINAPI VMR9_GetStaticImage(BaseControlVideo* This, LONG *pBufferSize, LONG *pDIBImage)
310 {
311     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
312     BITMAPINFOHEADER *bmiHeader;
313     LONG needed_size;
314     AM_MEDIA_TYPE *amt = &pVMR9->renderer.pInputPin->pin.mtCurrent;
315     char *ptr;
316
317     FIXME("(%p/%p)->(%p, %p): partial stub\n", pVMR9, This, pBufferSize, pDIBImage);
318
319     EnterCriticalSection(&pVMR9->renderer.filter.csFilter);
320
321     if (!pVMR9->renderer.pMediaSample)
322     {
323          LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
324          return (pVMR9->renderer.filter.state == State_Paused ? E_UNEXPECTED : VFW_E_NOT_PAUSED);
325     }
326
327     if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo))
328     {
329         bmiHeader = &((VIDEOINFOHEADER *)amt->pbFormat)->bmiHeader;
330     }
331     else if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo2))
332     {
333         bmiHeader = &((VIDEOINFOHEADER2 *)amt->pbFormat)->bmiHeader;
334     }
335     else
336     {
337         FIXME("Unknown type %s\n", debugstr_guid(&amt->subtype));
338         LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
339         return VFW_E_RUNTIME_ERROR;
340     }
341
342     needed_size = bmiHeader->biSize;
343     needed_size += IMediaSample_GetActualDataLength(pVMR9->renderer.pMediaSample);
344
345     if (!pDIBImage)
346     {
347         *pBufferSize = needed_size;
348         LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
349         return S_OK;
350     }
351
352     if (needed_size < *pBufferSize)
353     {
354         ERR("Buffer too small %u/%u\n", needed_size, *pBufferSize);
355         LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
356         return E_FAIL;
357     }
358     *pBufferSize = needed_size;
359
360     memcpy(pDIBImage, bmiHeader, bmiHeader->biSize);
361     IMediaSample_GetPointer(pVMR9->renderer.pMediaSample, (BYTE **)&ptr);
362     memcpy((char *)pDIBImage + bmiHeader->biSize, ptr, IMediaSample_GetActualDataLength(pVMR9->renderer.pMediaSample));
363
364     LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
365     return S_OK;
366 }
367
368 static HRESULT WINAPI VMR9_GetTargetRect(BaseControlVideo* This, RECT *pTargetRect)
369 {
370     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
371     CopyRect(pTargetRect,&pVMR9->target_rect);
372     return S_OK;
373 }
374
375 static VIDEOINFOHEADER* WINAPI VMR9_GetVideoFormat(BaseControlVideo* This)
376 {
377     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
378     AM_MEDIA_TYPE *pmt;
379
380     TRACE("(%p/%p)\n", pVMR9, This);
381
382     pmt = &pVMR9->renderer.pInputPin->pin.mtCurrent;
383     if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) {
384         return (VIDEOINFOHEADER*)pmt->pbFormat;
385     } else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2)) {
386         static VIDEOINFOHEADER vih;
387         VIDEOINFOHEADER2 *vih2 = (VIDEOINFOHEADER2*)pmt->pbFormat;
388         memcpy(&vih,vih2,sizeof(VIDEOINFOHEADER));
389         memcpy(&vih.bmiHeader, &vih2->bmiHeader, sizeof(BITMAPINFOHEADER));
390         return &vih;
391     } else {
392         ERR("Unknown format type %s\n", qzdebugstr_guid(&pmt->formattype));
393         return NULL;
394     }
395 }
396
397 static HRESULT WINAPI VMR9_IsDefaultSourceRect(BaseControlVideo* This)
398 {
399     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
400     FIXME("(%p/%p)->(): stub !!!\n", pVMR9, This);
401
402     return S_OK;
403 }
404
405 static HRESULT WINAPI VMR9_IsDefaultTargetRect(BaseControlVideo* This)
406 {
407     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
408     FIXME("(%p/%p)->(): stub !!!\n", pVMR9, This);
409
410     return S_OK;
411 }
412
413 static HRESULT WINAPI VMR9_SetDefaultSourceRect(BaseControlVideo* This)
414 {
415     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
416
417     pVMR9->source_rect.left = 0;
418     pVMR9->source_rect.top = 0;
419     pVMR9->source_rect.right = pVMR9->VideoWidth;
420     pVMR9->source_rect.bottom = pVMR9->VideoHeight;
421
422     return S_OK;
423 }
424
425 static HRESULT WINAPI VMR9_SetDefaultTargetRect(BaseControlVideo* This)
426 {
427     RECT rect;
428     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
429
430     if (!GetClientRect(pVMR9->baseControlWindow.baseWindow.hWnd, &rect))
431         return E_FAIL;
432
433     pVMR9->target_rect.left = 0;
434     pVMR9->target_rect.top = 0;
435     pVMR9->target_rect.right = rect.right;
436     pVMR9->target_rect.bottom = rect.bottom;
437
438     return S_OK;
439 }
440
441 static HRESULT WINAPI VMR9_SetSourceRect(BaseControlVideo* This, RECT *pSourceRect)
442 {
443     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
444     CopyRect(&pVMR9->source_rect,pSourceRect);
445     return S_OK;
446 }
447
448 static HRESULT WINAPI VMR9_SetTargetRect(BaseControlVideo* This, RECT *pTargetRect)
449 {
450     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
451     CopyRect(&pVMR9->target_rect,pTargetRect);
452     return S_OK;
453 }
454
455 static const BaseControlVideoFuncTable renderer_BaseControlVideoFuncTable = {
456     VMR9_GetSourceRect,
457     VMR9_GetStaticImage,
458     VMR9_GetTargetRect,
459     VMR9_GetVideoFormat,
460     VMR9_IsDefaultSourceRect,
461     VMR9_IsDefaultTargetRect,
462     VMR9_SetDefaultSourceRect,
463     VMR9_SetDefaultTargetRect,
464     VMR9_SetSourceRect,
465     VMR9_SetTargetRect
466 };
467
468 static HRESULT WINAPI VMR9Inner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
469 {
470     VMR9Impl *This = impl_from_inner_IUnknown(iface);
471     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
472
473     if (This->bAggregatable)
474         This->bUnkOuterValid = TRUE;
475
476     *ppv = NULL;
477
478     if (IsEqualIID(riid, &IID_IUnknown))
479         *ppv = &This->IUnknown_inner;
480     else if (IsEqualIID(riid, &IID_IVideoWindow))
481         *ppv = &This->baseControlWindow.IVideoWindow_iface;
482     else if (IsEqualIID(riid, &IID_IBasicVideo))
483         *ppv = &This->baseControlVideo.IBasicVideo_iface;
484     else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags))
485         *ppv = &This->IAMFilterMiscFlags_iface;
486     else if (IsEqualIID(riid, &IID_IVMRFilterConfig9))
487         *ppv = &This->IVMRFilterConfig9_iface;
488     else if (IsEqualIID(riid, &IID_IVMRWindowlessControl9) && This->mode == VMR9Mode_Windowless)
489         *ppv = &This->IVMRWindowlessControl9_iface;
490     else if (IsEqualIID(riid, &IID_IVMRSurfaceAllocatorNotify9) && This->mode == VMR9Mode_Renderless)
491         *ppv = &This->IVMRSurfaceAllocatorNotify9_iface;
492     else
493     {
494         HRESULT hr;
495         hr = BaseRendererImpl_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
496         if (SUCCEEDED(hr))
497             return hr;
498     }
499
500     if (*ppv)
501     {
502         IUnknown_AddRef((IUnknown *)(*ppv));
503         return S_OK;
504     }
505
506     else if (IsEqualIID(riid, &IID_IBasicVideo2))
507         FIXME("No interface for IID_IBasicVideo2\n");
508     else if (IsEqualIID(riid, &IID_IVMRWindowlessControl9))
509         ;
510     else if (IsEqualIID(riid, &IID_IVMRSurfaceAllocatorNotify9))
511         ;
512     else if (IsEqualIID(riid, &IID_IMediaPosition))
513         FIXME("No interface for IID_IMediaPosition\n");
514     else if (IsEqualIID(riid, &IID_IQualProp))
515         FIXME("No interface for IID_IQualProp\n");
516     else if (IsEqualIID(riid, &IID_IVMRAspectRatioControl9))
517         FIXME("No interface for IID_IVMRAspectRatioControl9\n");
518     else if (IsEqualIID(riid, &IID_IVMRDeinterlaceControl9))
519         FIXME("No interface for IID_IVMRDeinterlaceControl9\n");
520     else if (IsEqualIID(riid, &IID_IVMRMixerBitmap9))
521         FIXME("No interface for IID_IVMRMixerBitmap9\n");
522     else if (IsEqualIID(riid, &IID_IVMRMonitorConfig9))
523         FIXME("No interface for IID_IVMRMonitorConfig9\n");
524     else if (IsEqualIID(riid, &IID_IVMRMixerControl9))
525         FIXME("No interface for IID_IVMRMixerControl9\n");
526     else
527         FIXME("No interface for %s\n", debugstr_guid(riid));
528
529     return E_NOINTERFACE;
530 }
531
532 static ULONG WINAPI VMR9Inner_AddRef(IUnknown * iface)
533 {
534     VMR9Impl *This = impl_from_inner_IUnknown(iface);
535     ULONG refCount = BaseFilterImpl_AddRef(&This->renderer.filter.IBaseFilter_iface);
536
537     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
538
539     return refCount;
540 }
541
542 static ULONG WINAPI VMR9Inner_Release(IUnknown * iface)
543 {
544     VMR9Impl *This = impl_from_inner_IUnknown(iface);
545     ULONG refCount = BaseRendererImpl_Release(&This->renderer.filter.IBaseFilter_iface);
546
547     TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
548
549     if (!refCount)
550     {
551         TRACE("Destroying\n");
552         BaseControlWindow_Destroy(&This->baseControlWindow);
553
554         if (This->allocator)
555             IVMRSurfaceAllocator9_Release(This->allocator);
556         if (This->presenter)
557             IVMRImagePresenter9_Release(This->presenter);
558
559         CoTaskMemFree(This);
560     }
561     return refCount;
562 }
563
564 static const IUnknownVtbl IInner_VTable =
565 {
566     VMR9Inner_QueryInterface,
567     VMR9Inner_AddRef,
568     VMR9Inner_Release
569 };
570
571 static HRESULT WINAPI VMR9_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
572 {
573     VMR9Impl *This = (VMR9Impl *)iface;
574
575     if (This->bAggregatable)
576         This->bUnkOuterValid = TRUE;
577
578     if (This->outer_unk)
579     {
580         if (This->bAggregatable)
581             return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
582
583         if (IsEqualIID(riid, &IID_IUnknown))
584         {
585             HRESULT hr;
586
587             IUnknown_AddRef(&This->IUnknown_inner);
588             hr = IUnknown_QueryInterface(&This->IUnknown_inner, riid, ppv);
589             IUnknown_Release(&This->IUnknown_inner);
590             This->bAggregatable = TRUE;
591             return hr;
592         }
593
594         *ppv = NULL;
595         return E_NOINTERFACE;
596     }
597
598     return IUnknown_QueryInterface(&This->IUnknown_inner, riid, ppv);
599 }
600
601 static ULONG WINAPI VMR9_AddRef(IBaseFilter * iface)
602 {
603     VMR9Impl *This = (VMR9Impl *)iface;
604     LONG ret;
605
606     if (This->outer_unk && This->bUnkOuterValid)
607         ret = IUnknown_AddRef(This->outer_unk);
608     else
609         ret = IUnknown_AddRef(&This->IUnknown_inner);
610
611     TRACE("(%p)->AddRef from %d\n", iface, ret - 1);
612
613     return ret;
614 }
615
616 static ULONG WINAPI VMR9_Release(IBaseFilter * iface)
617 {
618     VMR9Impl *This = (VMR9Impl *)iface;
619     LONG ret;
620
621     if (This->outer_unk && This->bUnkOuterValid)
622         ret = IUnknown_Release(This->outer_unk);
623     else
624         ret = IUnknown_Release(&This->IUnknown_inner);
625
626     TRACE("(%p)->Release from %d\n", iface, ret + 1);
627
628     if (ret)
629         return ret;
630     return 0;
631 }
632
633 static const IBaseFilterVtbl VMR9_Vtbl =
634 {
635     VMR9_QueryInterface,
636     VMR9_AddRef,
637     VMR9_Release,
638     BaseFilterImpl_GetClassID,
639     BaseRendererImpl_Stop,
640     BaseRendererImpl_Pause,
641     BaseRendererImpl_Run,
642     BaseRendererImpl_GetState,
643     BaseRendererImpl_SetSyncSource,
644     BaseFilterImpl_GetSyncSource,
645     BaseFilterImpl_EnumPins,
646     BaseRendererImpl_FindPin,
647     BaseFilterImpl_QueryFilterInfo,
648     BaseFilterImpl_JoinFilterGraph,
649     BaseFilterImpl_QueryVendorInfo
650 };
651
652 /*** IUnknown methods ***/
653 static HRESULT WINAPI Videowindow_QueryInterface(IVideoWindow *iface, REFIID riid, LPVOID*ppvObj)
654 {
655     VMR9Impl *This = impl_from_IVideoWindow(iface);
656
657     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
658
659     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppvObj);
660 }
661
662 static ULONG WINAPI Videowindow_AddRef(IVideoWindow *iface)
663 {
664     VMR9Impl *This = impl_from_IVideoWindow(iface);
665
666     TRACE("(%p/%p)->()\n", This, iface);
667
668     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
669 }
670
671 static ULONG WINAPI Videowindow_Release(IVideoWindow *iface)
672 {
673     VMR9Impl *This = impl_from_IVideoWindow(iface);
674
675     TRACE("(%p/%p)->()\n", This, iface);
676
677     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
678 }
679
680 static const IVideoWindowVtbl IVideoWindow_VTable =
681 {
682     Videowindow_QueryInterface,
683     Videowindow_AddRef,
684     Videowindow_Release,
685     BaseControlWindowImpl_GetTypeInfoCount,
686     BaseControlWindowImpl_GetTypeInfo,
687     BaseControlWindowImpl_GetIDsOfNames,
688     BaseControlWindowImpl_Invoke,
689     BaseControlWindowImpl_put_Caption,
690     BaseControlWindowImpl_get_Caption,
691     BaseControlWindowImpl_put_WindowStyle,
692     BaseControlWindowImpl_get_WindowStyle,
693     BaseControlWindowImpl_put_WindowStyleEx,
694     BaseControlWindowImpl_get_WindowStyleEx,
695     BaseControlWindowImpl_put_AutoShow,
696     BaseControlWindowImpl_get_AutoShow,
697     BaseControlWindowImpl_put_WindowState,
698     BaseControlWindowImpl_get_WindowState,
699     BaseControlWindowImpl_put_BackgroundPalette,
700     BaseControlWindowImpl_get_BackgroundPalette,
701     BaseControlWindowImpl_put_Visible,
702     BaseControlWindowImpl_get_Visible,
703     BaseControlWindowImpl_put_Left,
704     BaseControlWindowImpl_get_Left,
705     BaseControlWindowImpl_put_Width,
706     BaseControlWindowImpl_get_Width,
707     BaseControlWindowImpl_put_Top,
708     BaseControlWindowImpl_get_Top,
709     BaseControlWindowImpl_put_Height,
710     BaseControlWindowImpl_get_Height,
711     BaseControlWindowImpl_put_Owner,
712     BaseControlWindowImpl_get_Owner,
713     BaseControlWindowImpl_put_MessageDrain,
714     BaseControlWindowImpl_get_MessageDrain,
715     BaseControlWindowImpl_get_BorderColor,
716     BaseControlWindowImpl_put_BorderColor,
717     BaseControlWindowImpl_get_FullScreenMode,
718     BaseControlWindowImpl_put_FullScreenMode,
719     BaseControlWindowImpl_SetWindowForeground,
720     BaseControlWindowImpl_NotifyOwnerMessage,
721     BaseControlWindowImpl_SetWindowPosition,
722     BaseControlWindowImpl_GetWindowPosition,
723     BaseControlWindowImpl_GetMinIdealImageSize,
724     BaseControlWindowImpl_GetMaxIdealImageSize,
725     BaseControlWindowImpl_GetRestorePosition,
726     BaseControlWindowImpl_HideCursor,
727     BaseControlWindowImpl_IsCursorHidden
728 };
729
730 /*** IUnknown methods ***/
731 static HRESULT WINAPI Basicvideo_QueryInterface(IBasicVideo *iface, REFIID riid, LPVOID * ppvObj)
732 {
733     VMR9Impl *This = impl_from_IBasicVideo(iface);
734
735     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
736
737     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppvObj);
738 }
739
740 static ULONG WINAPI Basicvideo_AddRef(IBasicVideo *iface)
741 {
742     VMR9Impl *This = impl_from_IBasicVideo(iface);
743
744     TRACE("(%p/%p)->()\n", This, iface);
745
746     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
747 }
748
749 static ULONG WINAPI Basicvideo_Release(IBasicVideo *iface)
750 {
751     VMR9Impl *This = impl_from_IBasicVideo(iface);
752
753     TRACE("(%p/%p)->()\n", This, iface);
754
755     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
756 }
757
758 static const IBasicVideoVtbl IBasicVideo_VTable =
759 {
760     Basicvideo_QueryInterface,
761     Basicvideo_AddRef,
762     Basicvideo_Release,
763     BaseControlVideoImpl_GetTypeInfoCount,
764     BaseControlVideoImpl_GetTypeInfo,
765     BaseControlVideoImpl_GetIDsOfNames,
766     BaseControlVideoImpl_Invoke,
767     BaseControlVideoImpl_get_AvgTimePerFrame,
768     BaseControlVideoImpl_get_BitRate,
769     BaseControlVideoImpl_get_BitErrorRate,
770     BaseControlVideoImpl_get_VideoWidth,
771     BaseControlVideoImpl_get_VideoHeight,
772     BaseControlVideoImpl_put_SourceLeft,
773     BaseControlVideoImpl_get_SourceLeft,
774     BaseControlVideoImpl_put_SourceWidth,
775     BaseControlVideoImpl_get_SourceWidth,
776     BaseControlVideoImpl_put_SourceTop,
777     BaseControlVideoImpl_get_SourceTop,
778     BaseControlVideoImpl_put_SourceHeight,
779     BaseControlVideoImpl_get_SourceHeight,
780     BaseControlVideoImpl_put_DestinationLeft,
781     BaseControlVideoImpl_get_DestinationLeft,
782     BaseControlVideoImpl_put_DestinationWidth,
783     BaseControlVideoImpl_get_DestinationWidth,
784     BaseControlVideoImpl_put_DestinationTop,
785     BaseControlVideoImpl_get_DestinationTop,
786     BaseControlVideoImpl_put_DestinationHeight,
787     BaseControlVideoImpl_get_DestinationHeight,
788     BaseControlVideoImpl_SetSourcePosition,
789     BaseControlVideoImpl_GetSourcePosition,
790     BaseControlVideoImpl_SetDefaultSourcePosition,
791     BaseControlVideoImpl_SetDestinationPosition,
792     BaseControlVideoImpl_GetDestinationPosition,
793     BaseControlVideoImpl_SetDefaultDestinationPosition,
794     BaseControlVideoImpl_GetVideoSize,
795     BaseControlVideoImpl_GetVideoPaletteEntries,
796     BaseControlVideoImpl_GetCurrentImage,
797     BaseControlVideoImpl_IsUsingDefaultSource,
798     BaseControlVideoImpl_IsUsingDefaultDestination
799 };
800
801 static HRESULT WINAPI AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, void **ppv) {
802     VMR9Impl *This = impl_from_IAMFilterMiscFlags(iface);
803     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
804 }
805
806 static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface) {
807     VMR9Impl *This = impl_from_IAMFilterMiscFlags(iface);
808     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
809 }
810
811 static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface) {
812     VMR9Impl *This = impl_from_IAMFilterMiscFlags(iface);
813     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
814 }
815
816 static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface) {
817     return AM_FILTER_MISC_FLAGS_IS_RENDERER;
818 }
819
820 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = {
821     AMFilterMiscFlags_QueryInterface,
822     AMFilterMiscFlags_AddRef,
823     AMFilterMiscFlags_Release,
824     AMFilterMiscFlags_GetMiscFlags
825 };
826
827 static HRESULT WINAPI VMR9FilterConfig_QueryInterface(IVMRFilterConfig9 *iface, REFIID riid, LPVOID * ppv)
828 {
829     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
830     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
831 }
832
833 static ULONG WINAPI VMR9FilterConfig_AddRef(IVMRFilterConfig9 *iface)
834 {
835     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
836     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
837 }
838
839 static ULONG WINAPI VMR9FilterConfig_Release(IVMRFilterConfig9 *iface)
840 {
841     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
842     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
843 }
844
845 static HRESULT WINAPI VMR9FilterConfig_SetImageCompositor(IVMRFilterConfig9 *iface, IVMRImageCompositor9 *compositor)
846 {
847     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
848
849     FIXME("(%p/%p)->(%p) stub\n", iface, This, compositor);
850     return E_NOTIMPL;
851 }
852
853 static HRESULT WINAPI VMR9FilterConfig_SetNumberOfStreams(IVMRFilterConfig9 *iface, DWORD max)
854 {
855     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
856
857     FIXME("(%p/%p)->(%u) stub\n", iface, This, max);
858     return E_NOTIMPL;
859 }
860
861 static HRESULT WINAPI VMR9FilterConfig_GetNumberOfStreams(IVMRFilterConfig9 *iface, DWORD *max)
862 {
863     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
864
865     FIXME("(%p/%p)->(%p) stub\n", iface, This, max);
866     return E_NOTIMPL;
867 }
868
869 static HRESULT WINAPI VMR9FilterConfig_SetRenderingPrefs(IVMRFilterConfig9 *iface, DWORD renderflags)
870 {
871     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
872
873     FIXME("(%p/%p)->(%u) stub\n", iface, This, renderflags);
874     return E_NOTIMPL;
875 }
876
877 static HRESULT WINAPI VMR9FilterConfig_GetRenderingPrefs(IVMRFilterConfig9 *iface, DWORD *renderflags)
878 {
879     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
880
881     FIXME("(%p/%p)->(%p) stub\n", iface, This, renderflags);
882     return E_NOTIMPL;
883 }
884
885 static HRESULT WINAPI VMR9FilterConfig_SetRenderingMode(IVMRFilterConfig9 *iface, DWORD mode)
886 {
887     HRESULT hr = S_OK;
888     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
889
890     TRACE("(%p/%p)->(%u)\n", iface, This, mode);
891
892     EnterCriticalSection(&This->renderer.filter.csFilter);
893     if (This->mode)
894     {
895         LeaveCriticalSection(&This->renderer.filter.csFilter);
896         return VFW_E_WRONG_STATE;
897     }
898
899     if (This->allocator)
900         IVMRSurfaceAllocator9_Release(This->allocator);
901     if (This->presenter)
902         IVMRImagePresenter9_Release(This->presenter);
903
904     This->allocator = NULL;
905     This->presenter = NULL;
906
907     switch (mode)
908     {
909     case VMR9Mode_Windowed:
910     case VMR9Mode_Windowless:
911         This->allocator_is_ex = 0;
912         This->cookie = ~0;
913
914         hr = VMR9DefaultAllocatorPresenterImpl_create(This, (LPVOID*)&This->presenter);
915         if (SUCCEEDED(hr))
916             hr = IVMRImagePresenter9_QueryInterface(This->presenter, &IID_IVMRSurfaceAllocatorEx9, (LPVOID*)&This->allocator);
917         if (FAILED(hr))
918         {
919             ERR("Unable to find Presenter interface\n");
920             IVMRSurfaceAllocatorEx9_Release(This->presenter);
921             This->allocator = NULL;
922             This->presenter = NULL;
923         }
924         else
925             hr = IVMRSurfaceAllocator9_AdviseNotify(This->allocator, &This->IVMRSurfaceAllocatorNotify9_iface);
926         break;
927     case VMR9Mode_Renderless:
928         break;
929     default:
930         LeaveCriticalSection(&This->renderer.filter.csFilter);
931         return E_INVALIDARG;
932     }
933
934     This->mode = mode;
935     LeaveCriticalSection(&This->renderer.filter.csFilter);
936     return hr;
937 }
938
939 static HRESULT WINAPI VMR9FilterConfig_GetRenderingMode(IVMRFilterConfig9 *iface, DWORD *mode)
940 {
941     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
942
943     TRACE("(%p/%p)->(%p) stub\n", iface, This, mode);
944     if (!mode)
945         return E_POINTER;
946
947     if (This->mode)
948         *mode = This->mode;
949     else
950         *mode = VMR9Mode_Windowed;
951
952     return S_OK;
953 }
954
955 static const IVMRFilterConfig9Vtbl VMR9_FilterConfig_Vtbl =
956 {
957     VMR9FilterConfig_QueryInterface,
958     VMR9FilterConfig_AddRef,
959     VMR9FilterConfig_Release,
960     VMR9FilterConfig_SetImageCompositor,
961     VMR9FilterConfig_SetNumberOfStreams,
962     VMR9FilterConfig_GetNumberOfStreams,
963     VMR9FilterConfig_SetRenderingPrefs,
964     VMR9FilterConfig_GetRenderingPrefs,
965     VMR9FilterConfig_SetRenderingMode,
966     VMR9FilterConfig_GetRenderingMode
967 };
968
969 static HRESULT WINAPI VMR9WindowlessControl_QueryInterface(IVMRWindowlessControl9 *iface, REFIID riid, LPVOID * ppv)
970 {
971     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
972     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
973 }
974
975 static ULONG WINAPI VMR9WindowlessControl_AddRef(IVMRWindowlessControl9 *iface)
976 {
977     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
978     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
979 }
980
981 static ULONG WINAPI VMR9WindowlessControl_Release(IVMRWindowlessControl9 *iface)
982 {
983     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
984     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
985 }
986
987 static HRESULT WINAPI VMR9WindowlessControl_GetNativeVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height, LONG *arwidth, LONG *arheight)
988 {
989     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
990     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", iface, This, width, height, arwidth, arheight);
991
992     if (!width || !height || !arwidth || !arheight)
993     {
994         ERR("Got no pointer\n");
995         return E_POINTER;
996     }
997
998     *width = This->bmiheader.biWidth;
999     *height = This->bmiheader.biHeight;
1000     *arwidth = This->bmiheader.biWidth;
1001     *arheight = This->bmiheader.biHeight;
1002
1003     return S_OK;
1004 }
1005
1006 static HRESULT WINAPI VMR9WindowlessControl_GetMinIdealVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height)
1007 {
1008     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1009
1010     FIXME("(%p/%p)->(...) stub\n", iface, This);
1011     return E_NOTIMPL;
1012 }
1013
1014 static HRESULT WINAPI VMR9WindowlessControl_GetMaxIdealVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height)
1015 {
1016     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1017
1018     FIXME("(%p/%p)->(...) stub\n", iface, This);
1019     return E_NOTIMPL;
1020 }
1021
1022 static HRESULT WINAPI VMR9WindowlessControl_SetVideoPosition(IVMRWindowlessControl9 *iface, const RECT *source, const RECT *dest)
1023 {
1024     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1025
1026     TRACE("(%p/%p)->(%p, %p)\n", iface, This, source, dest);
1027
1028     EnterCriticalSection(&This->renderer.filter.csFilter);
1029
1030     if (source)
1031         This->source_rect = *source;
1032     if (dest)
1033     {
1034         This->target_rect = *dest;
1035         if (This->baseControlWindow.baseWindow.hWnd)
1036         {
1037             FIXME("Output rectangle: starting at %dx%d, up to point %dx%d\n", dest->left, dest->top, dest->right, dest->bottom);
1038             SetWindowPos(This->baseControlWindow.baseWindow.hWnd, NULL, dest->left, dest->top, dest->right - dest->left,
1039                          dest->bottom-dest->top, SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOOWNERZORDER|SWP_NOREDRAW);
1040         }
1041     }
1042
1043     LeaveCriticalSection(&This->renderer.filter.csFilter);
1044
1045     return S_OK;
1046 }
1047
1048 static HRESULT WINAPI VMR9WindowlessControl_GetVideoPosition(IVMRWindowlessControl9 *iface, RECT *source, RECT *dest)
1049 {
1050     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1051
1052     if (source)
1053         *source = This->source_rect;
1054
1055     if (dest)
1056         *dest = This->target_rect;
1057
1058     FIXME("(%p/%p)->(%p/%p) stub\n", iface, This, source, dest);
1059     return S_OK;
1060 }
1061
1062 static HRESULT WINAPI VMR9WindowlessControl_GetAspectRatioMode(IVMRWindowlessControl9 *iface, DWORD *mode)
1063 {
1064     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1065
1066     FIXME("(%p/%p)->(...) stub\n", iface, This);
1067     return E_NOTIMPL;
1068 }
1069
1070 static HRESULT WINAPI VMR9WindowlessControl_SetAspectRatioMode(IVMRWindowlessControl9 *iface, DWORD mode)
1071 {
1072     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1073
1074     FIXME("(%p/%p)->(...) stub\n", iface, This);
1075     return E_NOTIMPL;
1076 }
1077
1078 static HRESULT WINAPI VMR9WindowlessControl_SetVideoClippingWindow(IVMRWindowlessControl9 *iface, HWND hwnd)
1079 {
1080     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1081
1082     TRACE("(%p/%p)->(%p)\n", iface, This, hwnd);
1083
1084     EnterCriticalSection(&This->renderer.filter.csFilter);
1085     This->hWndClippingWindow = hwnd;
1086     if (!hwnd)
1087         IVMRSurfaceAllocatorEx9_TerminateDevice(This->allocator, This->cookie);
1088     LeaveCriticalSection(&This->renderer.filter.csFilter);
1089     return S_OK;
1090 }
1091
1092 static HRESULT WINAPI VMR9WindowlessControl_RepaintVideo(IVMRWindowlessControl9 *iface, HWND hwnd, HDC hdc)
1093 {
1094     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1095
1096     FIXME("(%p/%p)->(...) stub\n", iface, This);
1097     return E_NOTIMPL;
1098 }
1099
1100 static HRESULT WINAPI VMR9WindowlessControl_DisplayModeChanged(IVMRWindowlessControl9 *iface)
1101 {
1102     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1103
1104     FIXME("(%p/%p)->(...) stub\n", iface, This);
1105     return E_NOTIMPL;
1106 }
1107
1108 static HRESULT WINAPI VMR9WindowlessControl_GetCurrentImage(IVMRWindowlessControl9 *iface, BYTE **dib)
1109 {
1110     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1111
1112     FIXME("(%p/%p)->(...) stub\n", iface, This);
1113     return E_NOTIMPL;
1114 }
1115
1116 static HRESULT WINAPI VMR9WindowlessControl_SetBorderColor(IVMRWindowlessControl9 *iface, COLORREF color)
1117 {
1118     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1119
1120     FIXME("(%p/%p)->(...) stub\n", iface, This);
1121     return E_NOTIMPL;
1122 }
1123
1124 static HRESULT WINAPI VMR9WindowlessControl_GetBorderColor(IVMRWindowlessControl9 *iface, COLORREF *color)
1125 {
1126     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1127
1128     FIXME("(%p/%p)->(...) stub\n", iface, This);
1129     return E_NOTIMPL;
1130 }
1131
1132 static const IVMRWindowlessControl9Vtbl VMR9_WindowlessControl_Vtbl =
1133 {
1134     VMR9WindowlessControl_QueryInterface,
1135     VMR9WindowlessControl_AddRef,
1136     VMR9WindowlessControl_Release,
1137     VMR9WindowlessControl_GetNativeVideoSize,
1138     VMR9WindowlessControl_GetMinIdealVideoSize,
1139     VMR9WindowlessControl_GetMaxIdealVideoSize,
1140     VMR9WindowlessControl_SetVideoPosition,
1141     VMR9WindowlessControl_GetVideoPosition,
1142     VMR9WindowlessControl_GetAspectRatioMode,
1143     VMR9WindowlessControl_SetAspectRatioMode,
1144     VMR9WindowlessControl_SetVideoClippingWindow,
1145     VMR9WindowlessControl_RepaintVideo,
1146     VMR9WindowlessControl_DisplayModeChanged,
1147     VMR9WindowlessControl_GetCurrentImage,
1148     VMR9WindowlessControl_SetBorderColor,
1149     VMR9WindowlessControl_GetBorderColor
1150 };
1151
1152 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_QueryInterface(IVMRSurfaceAllocatorNotify9 *iface, REFIID riid, LPVOID * ppv)
1153 {
1154     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1155     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
1156 }
1157
1158 static ULONG WINAPI VMR9SurfaceAllocatorNotify_AddRef(IVMRSurfaceAllocatorNotify9 *iface)
1159 {
1160     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1161     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
1162 }
1163
1164 static ULONG WINAPI VMR9SurfaceAllocatorNotify_Release(IVMRSurfaceAllocatorNotify9 *iface)
1165 {
1166     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1167     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
1168 }
1169
1170 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AdviseSurfaceAllocator(IVMRSurfaceAllocatorNotify9 *iface, DWORD_PTR id, IVMRSurfaceAllocator9 *alloc)
1171 {
1172     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1173
1174     /* FIXME: This code is not tested!!! */
1175     FIXME("(%p/%p)->(...) stub\n", iface, This);
1176     This->cookie = id;
1177
1178     if (This->presenter)
1179         return VFW_E_WRONG_STATE;
1180
1181     if (FAILED(IUnknown_QueryInterface(alloc, &IID_IVMRImagePresenter9, (void **)&This->presenter)))
1182         return E_NOINTERFACE;
1183
1184     if (SUCCEEDED(IUnknown_QueryInterface(alloc, &IID_IVMRSurfaceAllocatorEx9, (void **)&This->allocator)))
1185         This->allocator_is_ex = 1;
1186     else
1187     {
1188         This->allocator = (IVMRSurfaceAllocatorEx9 *)alloc;
1189         IUnknown_AddRef(alloc);
1190         This->allocator_is_ex = 0;
1191     }
1192
1193     return S_OK;
1194 }
1195
1196 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_SetD3DDevice(IVMRSurfaceAllocatorNotify9 *iface, IDirect3DDevice9 *device, HMONITOR monitor)
1197 {
1198     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1199
1200     FIXME("(%p/%p)->(...) stub\n", iface, This);
1201     return E_NOTIMPL;
1202 }
1203
1204 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_ChangeD3DDevice(IVMRSurfaceAllocatorNotify9 *iface, IDirect3DDevice9 *device, HMONITOR monitor)
1205 {
1206     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1207
1208     FIXME("(%p/%p)->(...) stub\n", iface, This);
1209     return E_NOTIMPL;
1210 }
1211
1212 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AllocateSurfaceHelper(IVMRSurfaceAllocatorNotify9 *iface, VMR9AllocationInfo *allocinfo, DWORD *numbuffers, IDirect3DSurface9 **surface)
1213 {
1214     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1215
1216     FIXME("(%p/%p)->(%p, %p => %u, %p) semi-stub\n", iface, This, allocinfo, numbuffers, (numbuffers ? *numbuffers : 0), surface);
1217
1218     if (!allocinfo || !numbuffers || !surface)
1219         return E_POINTER;
1220
1221     if (!*numbuffers || *numbuffers < allocinfo->MinBuffers)
1222     {
1223         ERR("Invalid number of buffers?\n");
1224         return E_INVALIDARG;
1225     }
1226
1227     return E_NOTIMPL;
1228 }
1229
1230 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_NotifyEvent(IVMRSurfaceAllocatorNotify9 *iface, LONG code, LONG_PTR param1, LONG_PTR param2)
1231 {
1232     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1233
1234     FIXME("(%p/%p)->(...) stub\n", iface, This);
1235     return E_NOTIMPL;
1236 }
1237
1238 static const IVMRSurfaceAllocatorNotify9Vtbl IVMRSurfaceAllocatorNotify9_Vtbl =
1239 {
1240     VMR9SurfaceAllocatorNotify_QueryInterface,
1241     VMR9SurfaceAllocatorNotify_AddRef,
1242     VMR9SurfaceAllocatorNotify_Release,
1243     VMR9SurfaceAllocatorNotify_AdviseSurfaceAllocator,
1244     VMR9SurfaceAllocatorNotify_SetD3DDevice,
1245     VMR9SurfaceAllocatorNotify_ChangeD3DDevice,
1246     VMR9SurfaceAllocatorNotify_AllocateSurfaceHelper,
1247     VMR9SurfaceAllocatorNotify_NotifyEvent
1248 };
1249
1250 HRESULT VMR9Impl_create(IUnknown * outer_unk, LPVOID * ppv)
1251 {
1252     HRESULT hr;
1253     VMR9Impl * pVMR9;
1254
1255     TRACE("(%p, %p)\n", outer_unk, ppv);
1256
1257     *ppv = NULL;
1258
1259     pVMR9 = CoTaskMemAlloc(sizeof(VMR9Impl));
1260
1261     pVMR9->outer_unk = outer_unk;
1262     pVMR9->bUnkOuterValid = FALSE;
1263     pVMR9->bAggregatable = FALSE;
1264     pVMR9->IUnknown_inner.lpVtbl = &IInner_VTable;
1265     pVMR9->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_Vtbl;
1266
1267     pVMR9->mode = 0;
1268     pVMR9->allocator = NULL;
1269     pVMR9->presenter = NULL;
1270     pVMR9->hWndClippingWindow = NULL;
1271     pVMR9->IVMRFilterConfig9_iface.lpVtbl = &VMR9_FilterConfig_Vtbl;
1272     pVMR9->IVMRWindowlessControl9_iface.lpVtbl = &VMR9_WindowlessControl_Vtbl;
1273     pVMR9->IVMRSurfaceAllocatorNotify9_iface.lpVtbl = &IVMRSurfaceAllocatorNotify9_Vtbl;
1274
1275     hr = BaseRenderer_Init(&pVMR9->renderer, &VMR9_Vtbl, outer_unk, &CLSID_VideoMixingRenderer9, (DWORD_PTR)(__FILE__ ": VMR9Impl.csFilter"), &BaseFuncTable);
1276     if (FAILED(hr))
1277         goto fail;
1278
1279     hr = BaseControlWindow_Init(&pVMR9->baseControlWindow, &IVideoWindow_VTable, &pVMR9->renderer.filter, &pVMR9->renderer.filter.csFilter, &pVMR9->renderer.pInputPin->pin, &renderer_BaseWindowFuncTable);
1280     if (FAILED(hr))
1281         goto fail;
1282
1283     hr = BaseControlVideo_Init(&pVMR9->baseControlVideo, &IBasicVideo_VTable, &pVMR9->renderer.filter, &pVMR9->renderer.filter.csFilter, &pVMR9->renderer.pInputPin->pin, &renderer_BaseControlVideoFuncTable);
1284     if (FAILED(hr))
1285         goto fail;
1286
1287     *ppv = (LPVOID)pVMR9;
1288     ZeroMemory(&pVMR9->source_rect, sizeof(RECT));
1289     ZeroMemory(&pVMR9->target_rect, sizeof(RECT));
1290     TRACE("Created at %p\n", pVMR9);
1291     return hr;
1292
1293 fail:
1294     BaseRendererImpl_Release(&pVMR9->renderer.filter.IBaseFilter_iface);
1295     CoTaskMemFree(pVMR9);
1296     return hr;
1297 }
1298
1299
1300
1301 static HRESULT WINAPI VMR9_ImagePresenter_QueryInterface(IVMRImagePresenter9 *iface, REFIID riid, LPVOID * ppv)
1302 {
1303     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
1304     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
1305
1306     *ppv = NULL;
1307
1308     if (IsEqualIID(riid, &IID_IUnknown))
1309         *ppv = (LPVOID)&(This->IVMRImagePresenter9_iface);
1310     else if (IsEqualIID(riid, &IID_IVMRImagePresenter9))
1311         *ppv = &This->IVMRImagePresenter9_iface;
1312
1313     if (*ppv)
1314     {
1315         IUnknown_AddRef((IUnknown *)(*ppv));
1316         return S_OK;
1317     }
1318
1319     FIXME("No interface for %s\n", debugstr_guid(riid));
1320
1321     return E_NOINTERFACE;
1322 }
1323
1324 static ULONG WINAPI VMR9_ImagePresenter_AddRef(IVMRImagePresenter9 *iface)
1325 {
1326     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
1327     ULONG refCount = InterlockedIncrement(&This->refCount);
1328
1329     TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1);
1330
1331     return refCount;
1332 }
1333
1334 static ULONG WINAPI VMR9_ImagePresenter_Release(IVMRImagePresenter9 *iface)
1335 {
1336     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
1337     ULONG refCount = InterlockedDecrement(&This->refCount);
1338
1339     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
1340
1341     if (!refCount)
1342     {
1343         TRACE("Destroying\n");
1344         IUnknown_Release(This->d3d9_ptr);
1345
1346         if (This->d3d9_vertex)
1347         {
1348             IUnknown_Release(This->d3d9_vertex);
1349             This->d3d9_vertex = NULL;
1350         }
1351         CoTaskMemFree(This);
1352         return 0;
1353     }
1354     return refCount;
1355 }
1356
1357 static HRESULT WINAPI VMR9_ImagePresenter_StartPresenting(IVMRImagePresenter9 *iface, DWORD_PTR id)
1358 {
1359     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
1360
1361     TRACE("(%p/%p/%p)->(...) stub\n", iface, This,This->pVMR9);
1362     return S_OK;
1363 }
1364
1365 static HRESULT WINAPI VMR9_ImagePresenter_StopPresenting(IVMRImagePresenter9 *iface, DWORD_PTR id)
1366 {
1367     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
1368
1369     TRACE("(%p/%p/%p)->(...) stub\n", iface, This,This->pVMR9);
1370     return S_OK;
1371 }
1372
1373 #define USED_FVF (D3DFVF_XYZRHW | D3DFVF_TEX1)
1374 struct VERTEX { float x, y, z, rhw, u, v; };
1375
1376 static HRESULT VMR9_ImagePresenter_PresentTexture(VMR9DefaultAllocatorPresenterImpl *This, IDirect3DSurface9 *surface)
1377 {
1378     IDirect3DTexture9 *texture = NULL;
1379     HRESULT hr;
1380
1381     hr = IDirect3DDevice9_SetFVF(This->d3d9_dev, USED_FVF);
1382     if (FAILED(hr))
1383     {
1384         FIXME("SetFVF: %08x\n", hr);
1385         return hr;
1386     }
1387
1388     hr = IDirect3DDevice9_SetStreamSource(This->d3d9_dev, 0, This->d3d9_vertex, 0, sizeof(struct VERTEX));
1389     if (FAILED(hr))
1390     {
1391         FIXME("SetStreamSource: %08x\n", hr);
1392         return hr;
1393     }
1394
1395     hr = IDirect3DSurface9_GetContainer(surface, &IID_IDirect3DTexture9, (void **) &texture);
1396     if (FAILED(hr))
1397     {
1398         FIXME("IDirect3DSurface9_GetContainer failed\n");
1399         return hr;
1400     }
1401     hr = IDirect3DDevice9_SetTexture(This->d3d9_dev, 0, (IDirect3DBaseTexture9 *)texture);
1402     IDirect3DTexture9_Release(texture);
1403     if (FAILED(hr))
1404     {
1405         FIXME("SetTexture: %08x\n", hr);
1406         return hr;
1407     }
1408
1409     hr = IDirect3DDevice9_DrawPrimitive(This->d3d9_dev, D3DPT_TRIANGLESTRIP, 0, 2);
1410     if (FAILED(hr))
1411     {
1412         FIXME("DrawPrimitive: %08x\n", hr);
1413         return hr;
1414     }
1415
1416     return S_OK;
1417 }
1418
1419 static HRESULT VMR9_ImagePresenter_PresentOffscreenSurface(VMR9DefaultAllocatorPresenterImpl *This, IDirect3DSurface9 *surface)
1420 {
1421     HRESULT hr;
1422     IDirect3DSurface9 *target = NULL;
1423     RECT target_rect;
1424
1425     hr = IDirect3DDevice9_GetBackBuffer(This->d3d9_dev, 0, 0, D3DBACKBUFFER_TYPE_MONO, &target);
1426     if (FAILED(hr))
1427     {
1428         ERR("IDirect3DDevice9_GetBackBuffer -- %08x\n", hr);
1429         return hr;
1430     }
1431
1432     target_rect = This->pVMR9->target_rect;
1433     target_rect.right -= target_rect.left;
1434     target_rect.bottom -= target_rect.top;
1435     target_rect.left = target_rect.top = 0;
1436
1437     /* Flip */
1438     target_rect.top = target_rect.bottom;
1439     target_rect.bottom = 0;
1440
1441     hr = IDirect3DDevice9_StretchRect(This->d3d9_dev, surface, &This->pVMR9->source_rect, target, &target_rect, D3DTEXF_LINEAR);
1442     if (FAILED(hr))
1443         ERR("IDirect3DDevice9_StretchRect -- %08x\n", hr);
1444     IDirect3DSurface9_Release(target);
1445
1446     return hr;
1447 }
1448
1449 static HRESULT WINAPI VMR9_ImagePresenter_PresentImage(IVMRImagePresenter9 *iface, DWORD_PTR id, VMR9PresentationInfo *info)
1450 {
1451     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
1452     HRESULT hr;
1453     RECT output;
1454     BOOL render = FALSE;
1455
1456     TRACE("(%p/%p/%p)->(...) stub\n", iface, This, This->pVMR9);
1457     GetWindowRect(This->pVMR9->baseControlWindow.baseWindow.hWnd, &output);
1458     TRACE("Output rectangle: starting at %dx%d, up to point %dx%d\n", output.left, output.top, output.right, output.bottom);
1459
1460     /* This might happen if we don't have active focus (eg on a different virtual desktop) */
1461     if (!This->d3d9_dev)
1462         return S_OK;
1463
1464     /* Display image here */
1465     hr = IDirect3DDevice9_Clear(This->d3d9_dev, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
1466     if (FAILED(hr))
1467         FIXME("hr: %08x\n", hr);
1468     hr = IDirect3DDevice9_BeginScene(This->d3d9_dev);
1469     if (SUCCEEDED(hr))
1470     {
1471         if (This->d3d9_vertex)
1472             hr = VMR9_ImagePresenter_PresentTexture(This, info->lpSurf);
1473         else
1474             hr = VMR9_ImagePresenter_PresentOffscreenSurface(This, info->lpSurf);
1475         render = SUCCEEDED(hr);
1476     }
1477     else
1478         FIXME("BeginScene: %08x\n", hr);
1479     hr = IDirect3DDevice9_EndScene(This->d3d9_dev);
1480     if (render && SUCCEEDED(hr))
1481     {
1482         hr = IDirect3DDevice9_Present(This->d3d9_dev, NULL, NULL, This->pVMR9->baseControlWindow.baseWindow.hWnd, NULL);
1483         if (FAILED(hr))
1484             FIXME("Presenting image: %08x\n", hr);
1485     }
1486
1487     return S_OK;
1488 }
1489
1490 static const IVMRImagePresenter9Vtbl VMR9_ImagePresenter =
1491 {
1492     VMR9_ImagePresenter_QueryInterface,
1493     VMR9_ImagePresenter_AddRef,
1494     VMR9_ImagePresenter_Release,
1495     VMR9_ImagePresenter_StartPresenting,
1496     VMR9_ImagePresenter_StopPresenting,
1497     VMR9_ImagePresenter_PresentImage
1498 };
1499
1500 static HRESULT VMR9DefaultAllocatorPresenterImpl_create(VMR9Impl *parent, LPVOID * ppv)
1501 {
1502     HRESULT hr = S_OK;
1503     int i;
1504     VMR9DefaultAllocatorPresenterImpl* This;
1505
1506     This = CoTaskMemAlloc(sizeof(VMR9DefaultAllocatorPresenterImpl));
1507     if (!This)
1508         return E_OUTOFMEMORY;
1509
1510     This->d3d9_ptr = NULL;
1511     if (!This->d3d9_ptr)
1512     {
1513         WARN("Could not initialize d3d9.dll\n");
1514         CoTaskMemFree(This);
1515         return VFW_E_DDRAW_CAPS_NOT_SUITABLE;
1516     }
1517
1518     i = 0;
1519     do
1520     {
1521         D3DDISPLAYMODE mode;
1522
1523         hr = IDirect3D9_EnumAdapterModes(This->d3d9_ptr, i++, D3DFMT_X8R8G8B8, 0, &mode);
1524     } while (FAILED(hr));
1525     if (FAILED(hr))
1526         ERR("HR: %08x\n", hr);
1527     if (hr == D3DERR_NOTAVAILABLE)
1528     {
1529         ERR("Format not supported\n");
1530         IUnknown_Release(This->d3d9_ptr);
1531         CoTaskMemFree(This);
1532         return VFW_E_DDRAW_CAPS_NOT_SUITABLE;
1533     }
1534
1535     This->IVMRImagePresenter9_iface.lpVtbl = &VMR9_ImagePresenter;
1536
1537     This->refCount = 1;
1538     This->pVMR9 = parent;
1539     This->d3d9_dev = NULL;
1540     This->d3d9_vertex = NULL;
1541
1542     *ppv = This;
1543     return S_OK;
1544 }