quartz: Create the rendering window for VMR-9.
[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     IVMRSurfaceAllocatorEx9 IVMRSurfaceAllocatorEx9_iface;
130
131     LONG refCount;
132
133     HANDLE ack;
134     DWORD tid;
135     HANDLE hWndThread;
136
137     IDirect3DDevice9 *d3d9_dev;
138     IDirect3D9 *d3d9_ptr;
139     IDirect3DSurface9 **d3d9_surfaces;
140     IDirect3DVertexBuffer9 *d3d9_vertex;
141     HMONITOR hMon;
142     DWORD num_surfaces;
143
144     BOOL reset;
145     VMR9AllocationInfo info;
146
147     VMR9Impl* pVMR9;
148     IVMRSurfaceAllocatorNotify9 *SurfaceAllocatorNotify;
149 } VMR9DefaultAllocatorPresenterImpl;
150
151 static inline VMR9DefaultAllocatorPresenterImpl *impl_from_IVMRImagePresenter9( IVMRImagePresenter9 *iface)
152 {
153     return CONTAINING_RECORD(iface, VMR9DefaultAllocatorPresenterImpl, IVMRImagePresenter9_iface);
154 }
155
156 static inline VMR9DefaultAllocatorPresenterImpl *impl_from_IVMRSurfaceAllocatorEx9( IVMRSurfaceAllocatorEx9 *iface)
157 {
158     return CONTAINING_RECORD(iface, VMR9DefaultAllocatorPresenterImpl, IVMRSurfaceAllocatorEx9_iface);
159 }
160
161 static HRESULT VMR9DefaultAllocatorPresenterImpl_create(VMR9Impl *parent, LPVOID * ppv);
162
163 static HRESULT WINAPI VMR9_DoRenderSample(BaseRenderer *iface, IMediaSample * pSample)
164 {
165     VMR9Impl *This = (VMR9Impl *)iface;
166     LPBYTE pbSrcStream = NULL;
167     REFERENCE_TIME tStart, tStop;
168     VMR9PresentationInfo info;
169     HRESULT hr;
170
171     TRACE("%p %p\n", iface, pSample);
172
173     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
174     if (FAILED(hr))
175         info.dwFlags = VMR9Sample_SrcDstRectsValid;
176     else
177         info.dwFlags = VMR9Sample_SrcDstRectsValid | VMR9Sample_TimeValid;
178
179     if (IMediaSample_IsDiscontinuity(pSample) == S_OK)
180         info.dwFlags |= VMR9Sample_Discontinuity;
181
182     if (IMediaSample_IsPreroll(pSample) == S_OK)
183         info.dwFlags |= VMR9Sample_Preroll;
184
185     if (IMediaSample_IsSyncPoint(pSample) == S_OK)
186         info.dwFlags |= VMR9Sample_SyncPoint;
187
188     hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
189     if (FAILED(hr))
190     {
191         ERR("Cannot get pointer to sample data (%x)\n", hr);
192         return hr;
193     }
194
195     info.rtStart = tStart;
196     info.rtEnd = tStop;
197     info.szAspectRatio.cx = This->bmiheader.biWidth;
198     info.szAspectRatio.cy = This->bmiheader.biHeight;
199
200     return hr;
201 }
202
203 static HRESULT WINAPI VMR9_CheckMediaType(BaseRenderer *iface, const AM_MEDIA_TYPE * pmt)
204 {
205     VMR9Impl *This = (VMR9Impl*)iface;
206
207     if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) || !pmt->pbFormat)
208         return S_FALSE;
209
210     /* Ignore subtype, test for bicompression instead */
211     if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo))
212     {
213         VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)pmt->pbFormat;
214
215         This->bmiheader = format->bmiHeader;
216         TRACE("Resolution: %dx%d\n", format->bmiHeader.biWidth, format->bmiHeader.biHeight);
217         This->source_rect.right = This->VideoWidth = format->bmiHeader.biWidth;
218         This->source_rect.bottom = This->VideoHeight = format->bmiHeader.biHeight;
219         This->source_rect.top = This->source_rect.left = 0;
220     }
221     else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2))
222     {
223         VIDEOINFOHEADER2 *format = (VIDEOINFOHEADER2 *)pmt->pbFormat;
224
225         This->bmiheader = format->bmiHeader;
226
227         TRACE("Resolution: %dx%d\n", format->bmiHeader.biWidth, format->bmiHeader.biHeight);
228         This->source_rect.right = This->VideoWidth = format->bmiHeader.biWidth;
229         This->source_rect.bottom = This->VideoHeight = format->bmiHeader.biHeight;
230         This->source_rect.top = This->source_rect.left = 0;
231     }
232     else
233     {
234         ERR("Format type %s not supported\n", debugstr_guid(&pmt->formattype));
235         return S_FALSE;
236     }
237     if (This->bmiheader.biCompression)
238         return S_FALSE;
239     return S_OK;
240 }
241
242 static HRESULT WINAPI VMR9_ShouldDrawSampleNow(BaseRenderer *This, IMediaSample *pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime)
243 {
244     /* Preroll means the sample isn't shown, this is used for key frames and things like that */
245     if (IMediaSample_IsPreroll(pSample) == S_OK)
246         return E_FAIL;
247     return S_FALSE;
248 }
249
250 static const BaseRendererFuncTable BaseFuncTable = {
251     VMR9_CheckMediaType,
252     VMR9_DoRenderSample,
253     /**/
254     NULL,
255     NULL,
256     NULL,
257     NULL,
258     NULL,
259     NULL,
260     NULL,
261     NULL,
262     VMR9_ShouldDrawSampleNow,
263     NULL,
264     /**/
265     NULL,
266     NULL,
267     NULL,
268     NULL,
269     NULL,
270 };
271
272 static LPWSTR WINAPI VMR9_GetClassWindowStyles(BaseWindow *This, DWORD *pClassStyles, DWORD *pWindowStyles, DWORD *pWindowStylesEx)
273 {
274     static WCHAR classnameW[] = { 'I','V','M','R','9',' ','C','l','a','s','s', 0 };
275
276     *pClassStyles = 0;
277     *pWindowStyles = WS_SIZEBOX;
278     *pWindowStylesEx = 0;
279
280     return classnameW;
281 }
282
283 static RECT WINAPI VMR9_GetDefaultRect(BaseWindow *This)
284 {
285     VMR9Impl* pVMR9 = impl_from_BaseWindow(This);
286     static RECT defRect;
287
288     defRect.left = defRect.top = 0;
289     defRect.right = pVMR9->VideoWidth;
290     defRect.bottom = pVMR9->VideoHeight;
291
292     return defRect;
293 }
294
295 static BOOL WINAPI VMR9_OnSize(BaseWindow *This, LONG Width, LONG Height)
296 {
297     VMR9Impl* pVMR9 = impl_from_BaseWindow(This);
298
299     TRACE("WM_SIZE %d %d\n", Width, Height);
300     GetClientRect(This->hWnd, &pVMR9->target_rect);
301     TRACE("WM_SIZING: DestRect=(%d,%d),(%d,%d)\n",
302         pVMR9->target_rect.left,
303         pVMR9->target_rect.top,
304         pVMR9->target_rect.right - pVMR9->target_rect.left,
305         pVMR9->target_rect.bottom - pVMR9->target_rect.top);
306     return BaseWindowImpl_OnSize(This, Width, Height);
307 }
308
309 static const BaseWindowFuncTable renderer_BaseWindowFuncTable = {
310     VMR9_GetClassWindowStyles,
311     VMR9_GetDefaultRect,
312     NULL,
313     BaseControlWindowImpl_PossiblyEatMessage,
314     VMR9_OnSize,
315 };
316
317 static HRESULT WINAPI VMR9_GetSourceRect(BaseControlVideo* This, RECT *pSourceRect)
318 {
319     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
320     CopyRect(pSourceRect,&pVMR9->source_rect);
321     return S_OK;
322 }
323
324 static HRESULT WINAPI VMR9_GetStaticImage(BaseControlVideo* This, LONG *pBufferSize, LONG *pDIBImage)
325 {
326     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
327     BITMAPINFOHEADER *bmiHeader;
328     LONG needed_size;
329     AM_MEDIA_TYPE *amt = &pVMR9->renderer.pInputPin->pin.mtCurrent;
330     char *ptr;
331
332     FIXME("(%p/%p)->(%p, %p): partial stub\n", pVMR9, This, pBufferSize, pDIBImage);
333
334     EnterCriticalSection(&pVMR9->renderer.filter.csFilter);
335
336     if (!pVMR9->renderer.pMediaSample)
337     {
338          LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
339          return (pVMR9->renderer.filter.state == State_Paused ? E_UNEXPECTED : VFW_E_NOT_PAUSED);
340     }
341
342     if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo))
343     {
344         bmiHeader = &((VIDEOINFOHEADER *)amt->pbFormat)->bmiHeader;
345     }
346     else if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo2))
347     {
348         bmiHeader = &((VIDEOINFOHEADER2 *)amt->pbFormat)->bmiHeader;
349     }
350     else
351     {
352         FIXME("Unknown type %s\n", debugstr_guid(&amt->subtype));
353         LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
354         return VFW_E_RUNTIME_ERROR;
355     }
356
357     needed_size = bmiHeader->biSize;
358     needed_size += IMediaSample_GetActualDataLength(pVMR9->renderer.pMediaSample);
359
360     if (!pDIBImage)
361     {
362         *pBufferSize = needed_size;
363         LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
364         return S_OK;
365     }
366
367     if (needed_size < *pBufferSize)
368     {
369         ERR("Buffer too small %u/%u\n", needed_size, *pBufferSize);
370         LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
371         return E_FAIL;
372     }
373     *pBufferSize = needed_size;
374
375     memcpy(pDIBImage, bmiHeader, bmiHeader->biSize);
376     IMediaSample_GetPointer(pVMR9->renderer.pMediaSample, (BYTE **)&ptr);
377     memcpy((char *)pDIBImage + bmiHeader->biSize, ptr, IMediaSample_GetActualDataLength(pVMR9->renderer.pMediaSample));
378
379     LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
380     return S_OK;
381 }
382
383 static HRESULT WINAPI VMR9_GetTargetRect(BaseControlVideo* This, RECT *pTargetRect)
384 {
385     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
386     CopyRect(pTargetRect,&pVMR9->target_rect);
387     return S_OK;
388 }
389
390 static VIDEOINFOHEADER* WINAPI VMR9_GetVideoFormat(BaseControlVideo* This)
391 {
392     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
393     AM_MEDIA_TYPE *pmt;
394
395     TRACE("(%p/%p)\n", pVMR9, This);
396
397     pmt = &pVMR9->renderer.pInputPin->pin.mtCurrent;
398     if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) {
399         return (VIDEOINFOHEADER*)pmt->pbFormat;
400     } else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2)) {
401         static VIDEOINFOHEADER vih;
402         VIDEOINFOHEADER2 *vih2 = (VIDEOINFOHEADER2*)pmt->pbFormat;
403         memcpy(&vih,vih2,sizeof(VIDEOINFOHEADER));
404         memcpy(&vih.bmiHeader, &vih2->bmiHeader, sizeof(BITMAPINFOHEADER));
405         return &vih;
406     } else {
407         ERR("Unknown format type %s\n", qzdebugstr_guid(&pmt->formattype));
408         return NULL;
409     }
410 }
411
412 static HRESULT WINAPI VMR9_IsDefaultSourceRect(BaseControlVideo* This)
413 {
414     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
415     FIXME("(%p/%p)->(): stub !!!\n", pVMR9, This);
416
417     return S_OK;
418 }
419
420 static HRESULT WINAPI VMR9_IsDefaultTargetRect(BaseControlVideo* This)
421 {
422     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
423     FIXME("(%p/%p)->(): stub !!!\n", pVMR9, This);
424
425     return S_OK;
426 }
427
428 static HRESULT WINAPI VMR9_SetDefaultSourceRect(BaseControlVideo* This)
429 {
430     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
431
432     pVMR9->source_rect.left = 0;
433     pVMR9->source_rect.top = 0;
434     pVMR9->source_rect.right = pVMR9->VideoWidth;
435     pVMR9->source_rect.bottom = pVMR9->VideoHeight;
436
437     return S_OK;
438 }
439
440 static HRESULT WINAPI VMR9_SetDefaultTargetRect(BaseControlVideo* This)
441 {
442     RECT rect;
443     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
444
445     if (!GetClientRect(pVMR9->baseControlWindow.baseWindow.hWnd, &rect))
446         return E_FAIL;
447
448     pVMR9->target_rect.left = 0;
449     pVMR9->target_rect.top = 0;
450     pVMR9->target_rect.right = rect.right;
451     pVMR9->target_rect.bottom = rect.bottom;
452
453     return S_OK;
454 }
455
456 static HRESULT WINAPI VMR9_SetSourceRect(BaseControlVideo* This, RECT *pSourceRect)
457 {
458     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
459     CopyRect(&pVMR9->source_rect,pSourceRect);
460     return S_OK;
461 }
462
463 static HRESULT WINAPI VMR9_SetTargetRect(BaseControlVideo* This, RECT *pTargetRect)
464 {
465     VMR9Impl* pVMR9 = impl_from_BaseControlVideo(This);
466     CopyRect(&pVMR9->target_rect,pTargetRect);
467     return S_OK;
468 }
469
470 static const BaseControlVideoFuncTable renderer_BaseControlVideoFuncTable = {
471     VMR9_GetSourceRect,
472     VMR9_GetStaticImage,
473     VMR9_GetTargetRect,
474     VMR9_GetVideoFormat,
475     VMR9_IsDefaultSourceRect,
476     VMR9_IsDefaultTargetRect,
477     VMR9_SetDefaultSourceRect,
478     VMR9_SetDefaultTargetRect,
479     VMR9_SetSourceRect,
480     VMR9_SetTargetRect
481 };
482
483 static HRESULT WINAPI VMR9Inner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
484 {
485     VMR9Impl *This = impl_from_inner_IUnknown(iface);
486     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
487
488     if (This->bAggregatable)
489         This->bUnkOuterValid = TRUE;
490
491     *ppv = NULL;
492
493     if (IsEqualIID(riid, &IID_IUnknown))
494         *ppv = &This->IUnknown_inner;
495     else if (IsEqualIID(riid, &IID_IVideoWindow))
496         *ppv = &This->baseControlWindow.IVideoWindow_iface;
497     else if (IsEqualIID(riid, &IID_IBasicVideo))
498         *ppv = &This->baseControlVideo.IBasicVideo_iface;
499     else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags))
500         *ppv = &This->IAMFilterMiscFlags_iface;
501     else if (IsEqualIID(riid, &IID_IVMRFilterConfig9))
502         *ppv = &This->IVMRFilterConfig9_iface;
503     else if (IsEqualIID(riid, &IID_IVMRWindowlessControl9) && This->mode == VMR9Mode_Windowless)
504         *ppv = &This->IVMRWindowlessControl9_iface;
505     else if (IsEqualIID(riid, &IID_IVMRSurfaceAllocatorNotify9) && This->mode == VMR9Mode_Renderless)
506         *ppv = &This->IVMRSurfaceAllocatorNotify9_iface;
507     else
508     {
509         HRESULT hr;
510         hr = BaseRendererImpl_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
511         if (SUCCEEDED(hr))
512             return hr;
513     }
514
515     if (*ppv)
516     {
517         IUnknown_AddRef((IUnknown *)(*ppv));
518         return S_OK;
519     }
520
521     else if (IsEqualIID(riid, &IID_IBasicVideo2))
522         FIXME("No interface for IID_IBasicVideo2\n");
523     else if (IsEqualIID(riid, &IID_IVMRWindowlessControl9))
524         ;
525     else if (IsEqualIID(riid, &IID_IVMRSurfaceAllocatorNotify9))
526         ;
527     else if (IsEqualIID(riid, &IID_IMediaPosition))
528         FIXME("No interface for IID_IMediaPosition\n");
529     else if (IsEqualIID(riid, &IID_IQualProp))
530         FIXME("No interface for IID_IQualProp\n");
531     else if (IsEqualIID(riid, &IID_IVMRAspectRatioControl9))
532         FIXME("No interface for IID_IVMRAspectRatioControl9\n");
533     else if (IsEqualIID(riid, &IID_IVMRDeinterlaceControl9))
534         FIXME("No interface for IID_IVMRDeinterlaceControl9\n");
535     else if (IsEqualIID(riid, &IID_IVMRMixerBitmap9))
536         FIXME("No interface for IID_IVMRMixerBitmap9\n");
537     else if (IsEqualIID(riid, &IID_IVMRMonitorConfig9))
538         FIXME("No interface for IID_IVMRMonitorConfig9\n");
539     else if (IsEqualIID(riid, &IID_IVMRMixerControl9))
540         FIXME("No interface for IID_IVMRMixerControl9\n");
541     else
542         FIXME("No interface for %s\n", debugstr_guid(riid));
543
544     return E_NOINTERFACE;
545 }
546
547 static ULONG WINAPI VMR9Inner_AddRef(IUnknown * iface)
548 {
549     VMR9Impl *This = impl_from_inner_IUnknown(iface);
550     ULONG refCount = BaseFilterImpl_AddRef(&This->renderer.filter.IBaseFilter_iface);
551
552     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
553
554     return refCount;
555 }
556
557 static ULONG WINAPI VMR9Inner_Release(IUnknown * iface)
558 {
559     VMR9Impl *This = impl_from_inner_IUnknown(iface);
560     ULONG refCount = BaseRendererImpl_Release(&This->renderer.filter.IBaseFilter_iface);
561
562     TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
563
564     if (!refCount)
565     {
566         TRACE("Destroying\n");
567         BaseControlWindow_Destroy(&This->baseControlWindow);
568
569         if (This->allocator)
570             IVMRSurfaceAllocator9_Release(This->allocator);
571         if (This->presenter)
572             IVMRImagePresenter9_Release(This->presenter);
573
574         CoTaskMemFree(This);
575     }
576     return refCount;
577 }
578
579 static const IUnknownVtbl IInner_VTable =
580 {
581     VMR9Inner_QueryInterface,
582     VMR9Inner_AddRef,
583     VMR9Inner_Release
584 };
585
586 static HRESULT WINAPI VMR9_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
587 {
588     VMR9Impl *This = (VMR9Impl *)iface;
589
590     if (This->bAggregatable)
591         This->bUnkOuterValid = TRUE;
592
593     if (This->outer_unk)
594     {
595         if (This->bAggregatable)
596             return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
597
598         if (IsEqualIID(riid, &IID_IUnknown))
599         {
600             HRESULT hr;
601
602             IUnknown_AddRef(&This->IUnknown_inner);
603             hr = IUnknown_QueryInterface(&This->IUnknown_inner, riid, ppv);
604             IUnknown_Release(&This->IUnknown_inner);
605             This->bAggregatable = TRUE;
606             return hr;
607         }
608
609         *ppv = NULL;
610         return E_NOINTERFACE;
611     }
612
613     return IUnknown_QueryInterface(&This->IUnknown_inner, riid, ppv);
614 }
615
616 static ULONG WINAPI VMR9_AddRef(IBaseFilter * iface)
617 {
618     VMR9Impl *This = (VMR9Impl *)iface;
619     LONG ret;
620
621     if (This->outer_unk && This->bUnkOuterValid)
622         ret = IUnknown_AddRef(This->outer_unk);
623     else
624         ret = IUnknown_AddRef(&This->IUnknown_inner);
625
626     TRACE("(%p)->AddRef from %d\n", iface, ret - 1);
627
628     return ret;
629 }
630
631 static ULONG WINAPI VMR9_Release(IBaseFilter * iface)
632 {
633     VMR9Impl *This = (VMR9Impl *)iface;
634     LONG ret;
635
636     if (This->outer_unk && This->bUnkOuterValid)
637         ret = IUnknown_Release(This->outer_unk);
638     else
639         ret = IUnknown_Release(&This->IUnknown_inner);
640
641     TRACE("(%p)->Release from %d\n", iface, ret + 1);
642
643     if (ret)
644         return ret;
645     return 0;
646 }
647
648 static const IBaseFilterVtbl VMR9_Vtbl =
649 {
650     VMR9_QueryInterface,
651     VMR9_AddRef,
652     VMR9_Release,
653     BaseFilterImpl_GetClassID,
654     BaseRendererImpl_Stop,
655     BaseRendererImpl_Pause,
656     BaseRendererImpl_Run,
657     BaseRendererImpl_GetState,
658     BaseRendererImpl_SetSyncSource,
659     BaseFilterImpl_GetSyncSource,
660     BaseFilterImpl_EnumPins,
661     BaseRendererImpl_FindPin,
662     BaseFilterImpl_QueryFilterInfo,
663     BaseFilterImpl_JoinFilterGraph,
664     BaseFilterImpl_QueryVendorInfo
665 };
666
667 /*** IUnknown methods ***/
668 static HRESULT WINAPI Videowindow_QueryInterface(IVideoWindow *iface, REFIID riid, LPVOID*ppvObj)
669 {
670     VMR9Impl *This = impl_from_IVideoWindow(iface);
671
672     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
673
674     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppvObj);
675 }
676
677 static ULONG WINAPI Videowindow_AddRef(IVideoWindow *iface)
678 {
679     VMR9Impl *This = impl_from_IVideoWindow(iface);
680
681     TRACE("(%p/%p)->()\n", This, iface);
682
683     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
684 }
685
686 static ULONG WINAPI Videowindow_Release(IVideoWindow *iface)
687 {
688     VMR9Impl *This = impl_from_IVideoWindow(iface);
689
690     TRACE("(%p/%p)->()\n", This, iface);
691
692     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
693 }
694
695 static const IVideoWindowVtbl IVideoWindow_VTable =
696 {
697     Videowindow_QueryInterface,
698     Videowindow_AddRef,
699     Videowindow_Release,
700     BaseControlWindowImpl_GetTypeInfoCount,
701     BaseControlWindowImpl_GetTypeInfo,
702     BaseControlWindowImpl_GetIDsOfNames,
703     BaseControlWindowImpl_Invoke,
704     BaseControlWindowImpl_put_Caption,
705     BaseControlWindowImpl_get_Caption,
706     BaseControlWindowImpl_put_WindowStyle,
707     BaseControlWindowImpl_get_WindowStyle,
708     BaseControlWindowImpl_put_WindowStyleEx,
709     BaseControlWindowImpl_get_WindowStyleEx,
710     BaseControlWindowImpl_put_AutoShow,
711     BaseControlWindowImpl_get_AutoShow,
712     BaseControlWindowImpl_put_WindowState,
713     BaseControlWindowImpl_get_WindowState,
714     BaseControlWindowImpl_put_BackgroundPalette,
715     BaseControlWindowImpl_get_BackgroundPalette,
716     BaseControlWindowImpl_put_Visible,
717     BaseControlWindowImpl_get_Visible,
718     BaseControlWindowImpl_put_Left,
719     BaseControlWindowImpl_get_Left,
720     BaseControlWindowImpl_put_Width,
721     BaseControlWindowImpl_get_Width,
722     BaseControlWindowImpl_put_Top,
723     BaseControlWindowImpl_get_Top,
724     BaseControlWindowImpl_put_Height,
725     BaseControlWindowImpl_get_Height,
726     BaseControlWindowImpl_put_Owner,
727     BaseControlWindowImpl_get_Owner,
728     BaseControlWindowImpl_put_MessageDrain,
729     BaseControlWindowImpl_get_MessageDrain,
730     BaseControlWindowImpl_get_BorderColor,
731     BaseControlWindowImpl_put_BorderColor,
732     BaseControlWindowImpl_get_FullScreenMode,
733     BaseControlWindowImpl_put_FullScreenMode,
734     BaseControlWindowImpl_SetWindowForeground,
735     BaseControlWindowImpl_NotifyOwnerMessage,
736     BaseControlWindowImpl_SetWindowPosition,
737     BaseControlWindowImpl_GetWindowPosition,
738     BaseControlWindowImpl_GetMinIdealImageSize,
739     BaseControlWindowImpl_GetMaxIdealImageSize,
740     BaseControlWindowImpl_GetRestorePosition,
741     BaseControlWindowImpl_HideCursor,
742     BaseControlWindowImpl_IsCursorHidden
743 };
744
745 /*** IUnknown methods ***/
746 static HRESULT WINAPI Basicvideo_QueryInterface(IBasicVideo *iface, REFIID riid, LPVOID * ppvObj)
747 {
748     VMR9Impl *This = impl_from_IBasicVideo(iface);
749
750     TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj);
751
752     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppvObj);
753 }
754
755 static ULONG WINAPI Basicvideo_AddRef(IBasicVideo *iface)
756 {
757     VMR9Impl *This = impl_from_IBasicVideo(iface);
758
759     TRACE("(%p/%p)->()\n", This, iface);
760
761     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
762 }
763
764 static ULONG WINAPI Basicvideo_Release(IBasicVideo *iface)
765 {
766     VMR9Impl *This = impl_from_IBasicVideo(iface);
767
768     TRACE("(%p/%p)->()\n", This, iface);
769
770     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
771 }
772
773 static const IBasicVideoVtbl IBasicVideo_VTable =
774 {
775     Basicvideo_QueryInterface,
776     Basicvideo_AddRef,
777     Basicvideo_Release,
778     BaseControlVideoImpl_GetTypeInfoCount,
779     BaseControlVideoImpl_GetTypeInfo,
780     BaseControlVideoImpl_GetIDsOfNames,
781     BaseControlVideoImpl_Invoke,
782     BaseControlVideoImpl_get_AvgTimePerFrame,
783     BaseControlVideoImpl_get_BitRate,
784     BaseControlVideoImpl_get_BitErrorRate,
785     BaseControlVideoImpl_get_VideoWidth,
786     BaseControlVideoImpl_get_VideoHeight,
787     BaseControlVideoImpl_put_SourceLeft,
788     BaseControlVideoImpl_get_SourceLeft,
789     BaseControlVideoImpl_put_SourceWidth,
790     BaseControlVideoImpl_get_SourceWidth,
791     BaseControlVideoImpl_put_SourceTop,
792     BaseControlVideoImpl_get_SourceTop,
793     BaseControlVideoImpl_put_SourceHeight,
794     BaseControlVideoImpl_get_SourceHeight,
795     BaseControlVideoImpl_put_DestinationLeft,
796     BaseControlVideoImpl_get_DestinationLeft,
797     BaseControlVideoImpl_put_DestinationWidth,
798     BaseControlVideoImpl_get_DestinationWidth,
799     BaseControlVideoImpl_put_DestinationTop,
800     BaseControlVideoImpl_get_DestinationTop,
801     BaseControlVideoImpl_put_DestinationHeight,
802     BaseControlVideoImpl_get_DestinationHeight,
803     BaseControlVideoImpl_SetSourcePosition,
804     BaseControlVideoImpl_GetSourcePosition,
805     BaseControlVideoImpl_SetDefaultSourcePosition,
806     BaseControlVideoImpl_SetDestinationPosition,
807     BaseControlVideoImpl_GetDestinationPosition,
808     BaseControlVideoImpl_SetDefaultDestinationPosition,
809     BaseControlVideoImpl_GetVideoSize,
810     BaseControlVideoImpl_GetVideoPaletteEntries,
811     BaseControlVideoImpl_GetCurrentImage,
812     BaseControlVideoImpl_IsUsingDefaultSource,
813     BaseControlVideoImpl_IsUsingDefaultDestination
814 };
815
816 static HRESULT WINAPI AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, void **ppv) {
817     VMR9Impl *This = impl_from_IAMFilterMiscFlags(iface);
818     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
819 }
820
821 static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface) {
822     VMR9Impl *This = impl_from_IAMFilterMiscFlags(iface);
823     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
824 }
825
826 static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface) {
827     VMR9Impl *This = impl_from_IAMFilterMiscFlags(iface);
828     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
829 }
830
831 static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface) {
832     return AM_FILTER_MISC_FLAGS_IS_RENDERER;
833 }
834
835 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = {
836     AMFilterMiscFlags_QueryInterface,
837     AMFilterMiscFlags_AddRef,
838     AMFilterMiscFlags_Release,
839     AMFilterMiscFlags_GetMiscFlags
840 };
841
842 static HRESULT WINAPI VMR9FilterConfig_QueryInterface(IVMRFilterConfig9 *iface, REFIID riid, LPVOID * ppv)
843 {
844     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
845     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
846 }
847
848 static ULONG WINAPI VMR9FilterConfig_AddRef(IVMRFilterConfig9 *iface)
849 {
850     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
851     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
852 }
853
854 static ULONG WINAPI VMR9FilterConfig_Release(IVMRFilterConfig9 *iface)
855 {
856     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
857     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
858 }
859
860 static HRESULT WINAPI VMR9FilterConfig_SetImageCompositor(IVMRFilterConfig9 *iface, IVMRImageCompositor9 *compositor)
861 {
862     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
863
864     FIXME("(%p/%p)->(%p) stub\n", iface, This, compositor);
865     return E_NOTIMPL;
866 }
867
868 static HRESULT WINAPI VMR9FilterConfig_SetNumberOfStreams(IVMRFilterConfig9 *iface, DWORD max)
869 {
870     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
871
872     FIXME("(%p/%p)->(%u) stub\n", iface, This, max);
873     return E_NOTIMPL;
874 }
875
876 static HRESULT WINAPI VMR9FilterConfig_GetNumberOfStreams(IVMRFilterConfig9 *iface, DWORD *max)
877 {
878     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
879
880     FIXME("(%p/%p)->(%p) stub\n", iface, This, max);
881     return E_NOTIMPL;
882 }
883
884 static HRESULT WINAPI VMR9FilterConfig_SetRenderingPrefs(IVMRFilterConfig9 *iface, DWORD renderflags)
885 {
886     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
887
888     FIXME("(%p/%p)->(%u) stub\n", iface, This, renderflags);
889     return E_NOTIMPL;
890 }
891
892 static HRESULT WINAPI VMR9FilterConfig_GetRenderingPrefs(IVMRFilterConfig9 *iface, DWORD *renderflags)
893 {
894     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
895
896     FIXME("(%p/%p)->(%p) stub\n", iface, This, renderflags);
897     return E_NOTIMPL;
898 }
899
900 static HRESULT WINAPI VMR9FilterConfig_SetRenderingMode(IVMRFilterConfig9 *iface, DWORD mode)
901 {
902     HRESULT hr = S_OK;
903     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
904
905     TRACE("(%p/%p)->(%u)\n", iface, This, mode);
906
907     EnterCriticalSection(&This->renderer.filter.csFilter);
908     if (This->mode)
909     {
910         LeaveCriticalSection(&This->renderer.filter.csFilter);
911         return VFW_E_WRONG_STATE;
912     }
913
914     if (This->allocator)
915         IVMRSurfaceAllocator9_Release(This->allocator);
916     if (This->presenter)
917         IVMRImagePresenter9_Release(This->presenter);
918
919     This->allocator = NULL;
920     This->presenter = NULL;
921
922     switch (mode)
923     {
924     case VMR9Mode_Windowed:
925     case VMR9Mode_Windowless:
926         This->allocator_is_ex = 0;
927         This->cookie = ~0;
928
929         hr = VMR9DefaultAllocatorPresenterImpl_create(This, (LPVOID*)&This->presenter);
930         if (SUCCEEDED(hr))
931             hr = IVMRImagePresenter9_QueryInterface(This->presenter, &IID_IVMRSurfaceAllocatorEx9, (LPVOID*)&This->allocator);
932         if (FAILED(hr))
933         {
934             ERR("Unable to find Presenter interface\n");
935             IVMRSurfaceAllocatorEx9_Release(This->presenter);
936             This->allocator = NULL;
937             This->presenter = NULL;
938         }
939         else
940             hr = IVMRSurfaceAllocator9_AdviseNotify(This->allocator, &This->IVMRSurfaceAllocatorNotify9_iface);
941         break;
942     case VMR9Mode_Renderless:
943         break;
944     default:
945         LeaveCriticalSection(&This->renderer.filter.csFilter);
946         return E_INVALIDARG;
947     }
948
949     This->mode = mode;
950     LeaveCriticalSection(&This->renderer.filter.csFilter);
951     return hr;
952 }
953
954 static HRESULT WINAPI VMR9FilterConfig_GetRenderingMode(IVMRFilterConfig9 *iface, DWORD *mode)
955 {
956     VMR9Impl *This = impl_from_IVMRFilterConfig9(iface);
957
958     TRACE("(%p/%p)->(%p) stub\n", iface, This, mode);
959     if (!mode)
960         return E_POINTER;
961
962     if (This->mode)
963         *mode = This->mode;
964     else
965         *mode = VMR9Mode_Windowed;
966
967     return S_OK;
968 }
969
970 static const IVMRFilterConfig9Vtbl VMR9_FilterConfig_Vtbl =
971 {
972     VMR9FilterConfig_QueryInterface,
973     VMR9FilterConfig_AddRef,
974     VMR9FilterConfig_Release,
975     VMR9FilterConfig_SetImageCompositor,
976     VMR9FilterConfig_SetNumberOfStreams,
977     VMR9FilterConfig_GetNumberOfStreams,
978     VMR9FilterConfig_SetRenderingPrefs,
979     VMR9FilterConfig_GetRenderingPrefs,
980     VMR9FilterConfig_SetRenderingMode,
981     VMR9FilterConfig_GetRenderingMode
982 };
983
984 static HRESULT WINAPI VMR9WindowlessControl_QueryInterface(IVMRWindowlessControl9 *iface, REFIID riid, LPVOID * ppv)
985 {
986     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
987     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
988 }
989
990 static ULONG WINAPI VMR9WindowlessControl_AddRef(IVMRWindowlessControl9 *iface)
991 {
992     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
993     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
994 }
995
996 static ULONG WINAPI VMR9WindowlessControl_Release(IVMRWindowlessControl9 *iface)
997 {
998     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
999     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
1000 }
1001
1002 static HRESULT WINAPI VMR9WindowlessControl_GetNativeVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height, LONG *arwidth, LONG *arheight)
1003 {
1004     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1005     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", iface, This, width, height, arwidth, arheight);
1006
1007     if (!width || !height || !arwidth || !arheight)
1008     {
1009         ERR("Got no pointer\n");
1010         return E_POINTER;
1011     }
1012
1013     *width = This->bmiheader.biWidth;
1014     *height = This->bmiheader.biHeight;
1015     *arwidth = This->bmiheader.biWidth;
1016     *arheight = This->bmiheader.biHeight;
1017
1018     return S_OK;
1019 }
1020
1021 static HRESULT WINAPI VMR9WindowlessControl_GetMinIdealVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height)
1022 {
1023     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1024
1025     FIXME("(%p/%p)->(...) stub\n", iface, This);
1026     return E_NOTIMPL;
1027 }
1028
1029 static HRESULT WINAPI VMR9WindowlessControl_GetMaxIdealVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height)
1030 {
1031     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1032
1033     FIXME("(%p/%p)->(...) stub\n", iface, This);
1034     return E_NOTIMPL;
1035 }
1036
1037 static HRESULT WINAPI VMR9WindowlessControl_SetVideoPosition(IVMRWindowlessControl9 *iface, const RECT *source, const RECT *dest)
1038 {
1039     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1040
1041     TRACE("(%p/%p)->(%p, %p)\n", iface, This, source, dest);
1042
1043     EnterCriticalSection(&This->renderer.filter.csFilter);
1044
1045     if (source)
1046         This->source_rect = *source;
1047     if (dest)
1048     {
1049         This->target_rect = *dest;
1050         if (This->baseControlWindow.baseWindow.hWnd)
1051         {
1052             FIXME("Output rectangle: starting at %dx%d, up to point %dx%d\n", dest->left, dest->top, dest->right, dest->bottom);
1053             SetWindowPos(This->baseControlWindow.baseWindow.hWnd, NULL, dest->left, dest->top, dest->right - dest->left,
1054                          dest->bottom-dest->top, SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOOWNERZORDER|SWP_NOREDRAW);
1055         }
1056     }
1057
1058     LeaveCriticalSection(&This->renderer.filter.csFilter);
1059
1060     return S_OK;
1061 }
1062
1063 static HRESULT WINAPI VMR9WindowlessControl_GetVideoPosition(IVMRWindowlessControl9 *iface, RECT *source, RECT *dest)
1064 {
1065     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1066
1067     if (source)
1068         *source = This->source_rect;
1069
1070     if (dest)
1071         *dest = This->target_rect;
1072
1073     FIXME("(%p/%p)->(%p/%p) stub\n", iface, This, source, dest);
1074     return S_OK;
1075 }
1076
1077 static HRESULT WINAPI VMR9WindowlessControl_GetAspectRatioMode(IVMRWindowlessControl9 *iface, DWORD *mode)
1078 {
1079     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1080
1081     FIXME("(%p/%p)->(...) stub\n", iface, This);
1082     return E_NOTIMPL;
1083 }
1084
1085 static HRESULT WINAPI VMR9WindowlessControl_SetAspectRatioMode(IVMRWindowlessControl9 *iface, DWORD mode)
1086 {
1087     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1088
1089     FIXME("(%p/%p)->(...) stub\n", iface, This);
1090     return E_NOTIMPL;
1091 }
1092
1093 static HRESULT WINAPI VMR9WindowlessControl_SetVideoClippingWindow(IVMRWindowlessControl9 *iface, HWND hwnd)
1094 {
1095     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1096
1097     TRACE("(%p/%p)->(%p)\n", iface, This, hwnd);
1098
1099     EnterCriticalSection(&This->renderer.filter.csFilter);
1100     This->hWndClippingWindow = hwnd;
1101     if (!hwnd)
1102         IVMRSurfaceAllocatorEx9_TerminateDevice(This->allocator, This->cookie);
1103     LeaveCriticalSection(&This->renderer.filter.csFilter);
1104     return S_OK;
1105 }
1106
1107 static HRESULT WINAPI VMR9WindowlessControl_RepaintVideo(IVMRWindowlessControl9 *iface, HWND hwnd, HDC hdc)
1108 {
1109     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1110
1111     FIXME("(%p/%p)->(...) stub\n", iface, This);
1112     return E_NOTIMPL;
1113 }
1114
1115 static HRESULT WINAPI VMR9WindowlessControl_DisplayModeChanged(IVMRWindowlessControl9 *iface)
1116 {
1117     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1118
1119     FIXME("(%p/%p)->(...) stub\n", iface, This);
1120     return E_NOTIMPL;
1121 }
1122
1123 static HRESULT WINAPI VMR9WindowlessControl_GetCurrentImage(IVMRWindowlessControl9 *iface, BYTE **dib)
1124 {
1125     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1126
1127     FIXME("(%p/%p)->(...) stub\n", iface, This);
1128     return E_NOTIMPL;
1129 }
1130
1131 static HRESULT WINAPI VMR9WindowlessControl_SetBorderColor(IVMRWindowlessControl9 *iface, COLORREF color)
1132 {
1133     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1134
1135     FIXME("(%p/%p)->(...) stub\n", iface, This);
1136     return E_NOTIMPL;
1137 }
1138
1139 static HRESULT WINAPI VMR9WindowlessControl_GetBorderColor(IVMRWindowlessControl9 *iface, COLORREF *color)
1140 {
1141     VMR9Impl *This = impl_from_IVMRWindowlessControl9(iface);
1142
1143     FIXME("(%p/%p)->(...) stub\n", iface, This);
1144     return E_NOTIMPL;
1145 }
1146
1147 static const IVMRWindowlessControl9Vtbl VMR9_WindowlessControl_Vtbl =
1148 {
1149     VMR9WindowlessControl_QueryInterface,
1150     VMR9WindowlessControl_AddRef,
1151     VMR9WindowlessControl_Release,
1152     VMR9WindowlessControl_GetNativeVideoSize,
1153     VMR9WindowlessControl_GetMinIdealVideoSize,
1154     VMR9WindowlessControl_GetMaxIdealVideoSize,
1155     VMR9WindowlessControl_SetVideoPosition,
1156     VMR9WindowlessControl_GetVideoPosition,
1157     VMR9WindowlessControl_GetAspectRatioMode,
1158     VMR9WindowlessControl_SetAspectRatioMode,
1159     VMR9WindowlessControl_SetVideoClippingWindow,
1160     VMR9WindowlessControl_RepaintVideo,
1161     VMR9WindowlessControl_DisplayModeChanged,
1162     VMR9WindowlessControl_GetCurrentImage,
1163     VMR9WindowlessControl_SetBorderColor,
1164     VMR9WindowlessControl_GetBorderColor
1165 };
1166
1167 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_QueryInterface(IVMRSurfaceAllocatorNotify9 *iface, REFIID riid, LPVOID * ppv)
1168 {
1169     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1170     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
1171 }
1172
1173 static ULONG WINAPI VMR9SurfaceAllocatorNotify_AddRef(IVMRSurfaceAllocatorNotify9 *iface)
1174 {
1175     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1176     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
1177 }
1178
1179 static ULONG WINAPI VMR9SurfaceAllocatorNotify_Release(IVMRSurfaceAllocatorNotify9 *iface)
1180 {
1181     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1182     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
1183 }
1184
1185 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AdviseSurfaceAllocator(IVMRSurfaceAllocatorNotify9 *iface, DWORD_PTR id, IVMRSurfaceAllocator9 *alloc)
1186 {
1187     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1188
1189     /* FIXME: This code is not tested!!! */
1190     FIXME("(%p/%p)->(...) stub\n", iface, This);
1191     This->cookie = id;
1192
1193     if (This->presenter)
1194         return VFW_E_WRONG_STATE;
1195
1196     if (FAILED(IUnknown_QueryInterface(alloc, &IID_IVMRImagePresenter9, (void **)&This->presenter)))
1197         return E_NOINTERFACE;
1198
1199     if (SUCCEEDED(IUnknown_QueryInterface(alloc, &IID_IVMRSurfaceAllocatorEx9, (void **)&This->allocator)))
1200         This->allocator_is_ex = 1;
1201     else
1202     {
1203         This->allocator = (IVMRSurfaceAllocatorEx9 *)alloc;
1204         IUnknown_AddRef(alloc);
1205         This->allocator_is_ex = 0;
1206     }
1207
1208     return S_OK;
1209 }
1210
1211 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_SetD3DDevice(IVMRSurfaceAllocatorNotify9 *iface, IDirect3DDevice9 *device, HMONITOR monitor)
1212 {
1213     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1214
1215     FIXME("(%p/%p)->(...) stub\n", iface, This);
1216     return E_NOTIMPL;
1217 }
1218
1219 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_ChangeD3DDevice(IVMRSurfaceAllocatorNotify9 *iface, IDirect3DDevice9 *device, HMONITOR monitor)
1220 {
1221     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1222
1223     FIXME("(%p/%p)->(...) stub\n", iface, This);
1224     return E_NOTIMPL;
1225 }
1226
1227 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AllocateSurfaceHelper(IVMRSurfaceAllocatorNotify9 *iface, VMR9AllocationInfo *allocinfo, DWORD *numbuffers, IDirect3DSurface9 **surface)
1228 {
1229     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1230
1231     FIXME("(%p/%p)->(%p, %p => %u, %p) semi-stub\n", iface, This, allocinfo, numbuffers, (numbuffers ? *numbuffers : 0), surface);
1232
1233     if (!allocinfo || !numbuffers || !surface)
1234         return E_POINTER;
1235
1236     if (!*numbuffers || *numbuffers < allocinfo->MinBuffers)
1237     {
1238         ERR("Invalid number of buffers?\n");
1239         return E_INVALIDARG;
1240     }
1241
1242     return E_NOTIMPL;
1243 }
1244
1245 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_NotifyEvent(IVMRSurfaceAllocatorNotify9 *iface, LONG code, LONG_PTR param1, LONG_PTR param2)
1246 {
1247     VMR9Impl *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
1248
1249     FIXME("(%p/%p)->(...) stub\n", iface, This);
1250     return E_NOTIMPL;
1251 }
1252
1253 static const IVMRSurfaceAllocatorNotify9Vtbl IVMRSurfaceAllocatorNotify9_Vtbl =
1254 {
1255     VMR9SurfaceAllocatorNotify_QueryInterface,
1256     VMR9SurfaceAllocatorNotify_AddRef,
1257     VMR9SurfaceAllocatorNotify_Release,
1258     VMR9SurfaceAllocatorNotify_AdviseSurfaceAllocator,
1259     VMR9SurfaceAllocatorNotify_SetD3DDevice,
1260     VMR9SurfaceAllocatorNotify_ChangeD3DDevice,
1261     VMR9SurfaceAllocatorNotify_AllocateSurfaceHelper,
1262     VMR9SurfaceAllocatorNotify_NotifyEvent
1263 };
1264
1265 HRESULT VMR9Impl_create(IUnknown * outer_unk, LPVOID * ppv)
1266 {
1267     HRESULT hr;
1268     VMR9Impl * pVMR9;
1269
1270     TRACE("(%p, %p)\n", outer_unk, ppv);
1271
1272     *ppv = NULL;
1273
1274     pVMR9 = CoTaskMemAlloc(sizeof(VMR9Impl));
1275
1276     pVMR9->outer_unk = outer_unk;
1277     pVMR9->bUnkOuterValid = FALSE;
1278     pVMR9->bAggregatable = FALSE;
1279     pVMR9->IUnknown_inner.lpVtbl = &IInner_VTable;
1280     pVMR9->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_Vtbl;
1281
1282     pVMR9->mode = 0;
1283     pVMR9->allocator = NULL;
1284     pVMR9->presenter = NULL;
1285     pVMR9->hWndClippingWindow = NULL;
1286     pVMR9->IVMRFilterConfig9_iface.lpVtbl = &VMR9_FilterConfig_Vtbl;
1287     pVMR9->IVMRWindowlessControl9_iface.lpVtbl = &VMR9_WindowlessControl_Vtbl;
1288     pVMR9->IVMRSurfaceAllocatorNotify9_iface.lpVtbl = &IVMRSurfaceAllocatorNotify9_Vtbl;
1289
1290     hr = BaseRenderer_Init(&pVMR9->renderer, &VMR9_Vtbl, outer_unk, &CLSID_VideoMixingRenderer9, (DWORD_PTR)(__FILE__ ": VMR9Impl.csFilter"), &BaseFuncTable);
1291     if (FAILED(hr))
1292         goto fail;
1293
1294     hr = BaseControlWindow_Init(&pVMR9->baseControlWindow, &IVideoWindow_VTable, &pVMR9->renderer.filter, &pVMR9->renderer.filter.csFilter, &pVMR9->renderer.pInputPin->pin, &renderer_BaseWindowFuncTable);
1295     if (FAILED(hr))
1296         goto fail;
1297
1298     hr = BaseControlVideo_Init(&pVMR9->baseControlVideo, &IBasicVideo_VTable, &pVMR9->renderer.filter, &pVMR9->renderer.filter.csFilter, &pVMR9->renderer.pInputPin->pin, &renderer_BaseControlVideoFuncTable);
1299     if (FAILED(hr))
1300         goto fail;
1301
1302     *ppv = (LPVOID)pVMR9;
1303     ZeroMemory(&pVMR9->source_rect, sizeof(RECT));
1304     ZeroMemory(&pVMR9->target_rect, sizeof(RECT));
1305     TRACE("Created at %p\n", pVMR9);
1306     return hr;
1307
1308 fail:
1309     BaseRendererImpl_Release(&pVMR9->renderer.filter.IBaseFilter_iface);
1310     CoTaskMemFree(pVMR9);
1311     return hr;
1312 }
1313
1314
1315
1316 static HRESULT WINAPI VMR9_ImagePresenter_QueryInterface(IVMRImagePresenter9 *iface, REFIID riid, LPVOID * ppv)
1317 {
1318     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
1319     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
1320
1321     *ppv = NULL;
1322
1323     if (IsEqualIID(riid, &IID_IUnknown))
1324         *ppv = (LPVOID)&(This->IVMRImagePresenter9_iface);
1325     else if (IsEqualIID(riid, &IID_IVMRImagePresenter9))
1326         *ppv = &This->IVMRImagePresenter9_iface;
1327     else if (IsEqualIID(riid, &IID_IVMRSurfaceAllocatorEx9))
1328         *ppv = &This->IVMRSurfaceAllocatorEx9_iface;
1329
1330     if (*ppv)
1331     {
1332         IUnknown_AddRef((IUnknown *)(*ppv));
1333         return S_OK;
1334     }
1335
1336     FIXME("No interface for %s\n", debugstr_guid(riid));
1337
1338     return E_NOINTERFACE;
1339 }
1340
1341 static ULONG WINAPI VMR9_ImagePresenter_AddRef(IVMRImagePresenter9 *iface)
1342 {
1343     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
1344     ULONG refCount = InterlockedIncrement(&This->refCount);
1345
1346     TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1);
1347
1348     return refCount;
1349 }
1350
1351 static ULONG WINAPI VMR9_ImagePresenter_Release(IVMRImagePresenter9 *iface)
1352 {
1353     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
1354     ULONG refCount = InterlockedDecrement(&This->refCount);
1355
1356     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
1357
1358     if (!refCount)
1359     {
1360         int i;
1361         TRACE("Destroying\n");
1362         CloseHandle(This->ack);
1363         IUnknown_Release(This->d3d9_ptr);
1364
1365         TRACE("Number of surfaces: %u\n", This->num_surfaces);
1366         for (i = 0; i < This->num_surfaces; ++i)
1367         {
1368             IDirect3DSurface9 *surface = This->d3d9_surfaces[i];
1369             TRACE("Releasing surface %p\n", surface);
1370             if (surface)
1371                 IUnknown_Release(surface);
1372         }
1373
1374         CoTaskMemFree(This->d3d9_surfaces);
1375         This->d3d9_surfaces = NULL;
1376         This->num_surfaces = 0;
1377         if (This->d3d9_vertex)
1378         {
1379             IUnknown_Release(This->d3d9_vertex);
1380             This->d3d9_vertex = NULL;
1381         }
1382         CoTaskMemFree(This);
1383         return 0;
1384     }
1385     return refCount;
1386 }
1387
1388 static HRESULT WINAPI VMR9_ImagePresenter_StartPresenting(IVMRImagePresenter9 *iface, DWORD_PTR id)
1389 {
1390     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
1391
1392     TRACE("(%p/%p/%p)->(...) stub\n", iface, This,This->pVMR9);
1393     return S_OK;
1394 }
1395
1396 static HRESULT WINAPI VMR9_ImagePresenter_StopPresenting(IVMRImagePresenter9 *iface, DWORD_PTR id)
1397 {
1398     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
1399
1400     TRACE("(%p/%p/%p)->(...) stub\n", iface, This,This->pVMR9);
1401     return S_OK;
1402 }
1403
1404 #define USED_FVF (D3DFVF_XYZRHW | D3DFVF_TEX1)
1405 struct VERTEX { float x, y, z, rhw, u, v; };
1406
1407 static HRESULT VMR9_ImagePresenter_PresentTexture(VMR9DefaultAllocatorPresenterImpl *This, IDirect3DSurface9 *surface)
1408 {
1409     IDirect3DTexture9 *texture = NULL;
1410     HRESULT hr;
1411
1412     hr = IDirect3DDevice9_SetFVF(This->d3d9_dev, USED_FVF);
1413     if (FAILED(hr))
1414     {
1415         FIXME("SetFVF: %08x\n", hr);
1416         return hr;
1417     }
1418
1419     hr = IDirect3DDevice9_SetStreamSource(This->d3d9_dev, 0, This->d3d9_vertex, 0, sizeof(struct VERTEX));
1420     if (FAILED(hr))
1421     {
1422         FIXME("SetStreamSource: %08x\n", hr);
1423         return hr;
1424     }
1425
1426     hr = IDirect3DSurface9_GetContainer(surface, &IID_IDirect3DTexture9, (void **) &texture);
1427     if (FAILED(hr))
1428     {
1429         FIXME("IDirect3DSurface9_GetContainer failed\n");
1430         return hr;
1431     }
1432     hr = IDirect3DDevice9_SetTexture(This->d3d9_dev, 0, (IDirect3DBaseTexture9 *)texture);
1433     IDirect3DTexture9_Release(texture);
1434     if (FAILED(hr))
1435     {
1436         FIXME("SetTexture: %08x\n", hr);
1437         return hr;
1438     }
1439
1440     hr = IDirect3DDevice9_DrawPrimitive(This->d3d9_dev, D3DPT_TRIANGLESTRIP, 0, 2);
1441     if (FAILED(hr))
1442     {
1443         FIXME("DrawPrimitive: %08x\n", hr);
1444         return hr;
1445     }
1446
1447     return S_OK;
1448 }
1449
1450 static HRESULT VMR9_ImagePresenter_PresentOffscreenSurface(VMR9DefaultAllocatorPresenterImpl *This, IDirect3DSurface9 *surface)
1451 {
1452     HRESULT hr;
1453     IDirect3DSurface9 *target = NULL;
1454     RECT target_rect;
1455
1456     hr = IDirect3DDevice9_GetBackBuffer(This->d3d9_dev, 0, 0, D3DBACKBUFFER_TYPE_MONO, &target);
1457     if (FAILED(hr))
1458     {
1459         ERR("IDirect3DDevice9_GetBackBuffer -- %08x\n", hr);
1460         return hr;
1461     }
1462
1463     target_rect = This->pVMR9->target_rect;
1464     target_rect.right -= target_rect.left;
1465     target_rect.bottom -= target_rect.top;
1466     target_rect.left = target_rect.top = 0;
1467
1468     /* Flip */
1469     target_rect.top = target_rect.bottom;
1470     target_rect.bottom = 0;
1471
1472     hr = IDirect3DDevice9_StretchRect(This->d3d9_dev, surface, &This->pVMR9->source_rect, target, &target_rect, D3DTEXF_LINEAR);
1473     if (FAILED(hr))
1474         ERR("IDirect3DDevice9_StretchRect -- %08x\n", hr);
1475     IDirect3DSurface9_Release(target);
1476
1477     return hr;
1478 }
1479
1480 static HRESULT WINAPI VMR9_ImagePresenter_PresentImage(IVMRImagePresenter9 *iface, DWORD_PTR id, VMR9PresentationInfo *info)
1481 {
1482     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
1483     HRESULT hr;
1484     RECT output;
1485     BOOL render = FALSE;
1486
1487     TRACE("(%p/%p/%p)->(...) stub\n", iface, This, This->pVMR9);
1488     GetWindowRect(This->pVMR9->baseControlWindow.baseWindow.hWnd, &output);
1489     TRACE("Output rectangle: starting at %dx%d, up to point %dx%d\n", output.left, output.top, output.right, output.bottom);
1490
1491     /* This might happen if we don't have active focus (eg on a different virtual desktop) */
1492     if (!This->d3d9_dev)
1493         return S_OK;
1494
1495     /* Display image here */
1496     hr = IDirect3DDevice9_Clear(This->d3d9_dev, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
1497     if (FAILED(hr))
1498         FIXME("hr: %08x\n", hr);
1499     hr = IDirect3DDevice9_BeginScene(This->d3d9_dev);
1500     if (SUCCEEDED(hr))
1501     {
1502         if (This->d3d9_vertex)
1503             hr = VMR9_ImagePresenter_PresentTexture(This, info->lpSurf);
1504         else
1505             hr = VMR9_ImagePresenter_PresentOffscreenSurface(This, info->lpSurf);
1506         render = SUCCEEDED(hr);
1507     }
1508     else
1509         FIXME("BeginScene: %08x\n", hr);
1510     hr = IDirect3DDevice9_EndScene(This->d3d9_dev);
1511     if (render && SUCCEEDED(hr))
1512     {
1513         hr = IDirect3DDevice9_Present(This->d3d9_dev, NULL, NULL, This->pVMR9->baseControlWindow.baseWindow.hWnd, NULL);
1514         if (FAILED(hr))
1515             FIXME("Presenting image: %08x\n", hr);
1516     }
1517
1518     return S_OK;
1519 }
1520
1521 static const IVMRImagePresenter9Vtbl VMR9_ImagePresenter =
1522 {
1523     VMR9_ImagePresenter_QueryInterface,
1524     VMR9_ImagePresenter_AddRef,
1525     VMR9_ImagePresenter_Release,
1526     VMR9_ImagePresenter_StartPresenting,
1527     VMR9_ImagePresenter_StopPresenting,
1528     VMR9_ImagePresenter_PresentImage
1529 };
1530
1531 static HRESULT WINAPI VMR9_SurfaceAllocator_QueryInterface(IVMRSurfaceAllocatorEx9 *iface, REFIID riid, LPVOID * ppv)
1532 {
1533     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
1534
1535     return VMR9_ImagePresenter_QueryInterface(&This->IVMRImagePresenter9_iface, riid, ppv);
1536 }
1537
1538 static ULONG WINAPI VMR9_SurfaceAllocator_AddRef(IVMRSurfaceAllocatorEx9 *iface)
1539 {
1540     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
1541
1542     return VMR9_ImagePresenter_AddRef(&This->IVMRImagePresenter9_iface);
1543 }
1544
1545 static ULONG WINAPI VMR9_SurfaceAllocator_Release(IVMRSurfaceAllocatorEx9 *iface)
1546 {
1547     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
1548
1549     return VMR9_ImagePresenter_Release(&This->IVMRImagePresenter9_iface);
1550 }
1551
1552 static HRESULT VMR9_SurfaceAllocator_SetAllocationSettings(VMR9DefaultAllocatorPresenterImpl *This, VMR9AllocationInfo *allocinfo)
1553 {
1554     D3DCAPS9 caps;
1555     UINT width, height;
1556     HRESULT hr;
1557
1558     if (!(allocinfo->dwFlags & VMR9AllocFlag_TextureSurface))
1559         /* Only needed for texture surfaces */
1560         return S_OK;
1561
1562     hr = IDirect3DDevice9_GetDeviceCaps(This->d3d9_dev, &caps);
1563     if (FAILED(hr))
1564         return hr;
1565
1566     if (!(caps.TextureCaps & D3DPTEXTURECAPS_POW2) || (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY))
1567     {
1568         width = allocinfo->dwWidth;
1569         height = allocinfo->dwHeight;
1570     }
1571     else
1572     {
1573         width = height = 1;
1574         while (width < allocinfo->dwWidth)
1575             width *= 2;
1576
1577         while (height < allocinfo->dwHeight)
1578             height *= 2;
1579         FIXME("NPOW2 support missing, not using proper surfaces!\n");
1580     }
1581
1582     if (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY)
1583     {
1584         if (height > width)
1585             width = height;
1586         else
1587             height = width;
1588         FIXME("Square texture support required..\n");
1589     }
1590
1591     hr = IDirect3DDevice9_CreateVertexBuffer(This->d3d9_dev, 4 * sizeof(struct VERTEX), D3DUSAGE_WRITEONLY, USED_FVF, allocinfo->Pool, &This->d3d9_vertex, NULL);
1592     if (FAILED(hr))
1593     {
1594         ERR("Couldn't create vertex buffer: %08x\n", hr);
1595         return hr;
1596     }
1597
1598     This->reset = TRUE;
1599     allocinfo->dwHeight = height;
1600     allocinfo->dwWidth = width;
1601
1602     return hr;
1603 }
1604
1605 static DWORD WINAPI MessageLoop(LPVOID lpParameter)
1606 {
1607     MSG msg;
1608     BOOL fGotMessage;
1609     VMR9DefaultAllocatorPresenterImpl *This = lpParameter;
1610
1611     TRACE("Starting message loop\n");
1612
1613     if (FAILED(BaseWindowImpl_PrepareWindow(&This->pVMR9->baseControlWindow.baseWindow)))
1614     {
1615         FIXME("Failed to prepare window\n");
1616         return FALSE;
1617     }
1618
1619     SetEvent(This->ack);
1620     while ((fGotMessage = GetMessageW(&msg, NULL, 0, 0)) != 0 && fGotMessage != -1)
1621     {
1622         TranslateMessage(&msg);
1623         DispatchMessageW(&msg);
1624     }
1625
1626     TRACE("End of message loop\n");
1627
1628     return 0;
1629 }
1630
1631 static UINT d3d9_adapter_from_hwnd(IDirect3D9 *d3d9, HWND hwnd, HMONITOR *mon_out)
1632 {
1633     UINT d3d9_adapter;
1634     HMONITOR mon;
1635
1636     mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL);
1637     if (!mon)
1638         d3d9_adapter = 0;
1639     else
1640     {
1641         for (d3d9_adapter = 0; d3d9_adapter < IDirect3D9_GetAdapterCount(d3d9); ++d3d9_adapter)
1642         {
1643             if (mon == IDirect3D9_GetAdapterMonitor(d3d9, d3d9_adapter))
1644                 break;
1645         }
1646         if (d3d9_adapter >= IDirect3D9_GetAdapterCount(d3d9))
1647             d3d9_adapter = 0;
1648     }
1649     if (mon_out)
1650         *mon_out = mon;
1651     return d3d9_adapter;
1652 }
1653
1654 static BOOL CreateRenderingWindow(VMR9DefaultAllocatorPresenterImpl *This, VMR9AllocationInfo *info, DWORD *numbuffers)
1655 {
1656     D3DPRESENT_PARAMETERS d3dpp;
1657     DWORD d3d9_adapter;
1658     HRESULT hr;
1659
1660     TRACE("(%p)->()\n", This);
1661
1662     This->hWndThread = CreateThread(NULL, 0, MessageLoop, This, 0, &This->tid);
1663     if (!This->hWndThread)
1664         return FALSE;
1665
1666     WaitForSingleObject(This->ack, INFINITE);
1667
1668     if (!This->pVMR9->baseControlWindow.baseWindow.hWnd) return FALSE;
1669
1670     /* Obtain a monitor and d3d9 device */
1671     d3d9_adapter = d3d9_adapter_from_hwnd(This->d3d9_ptr, This->pVMR9->baseControlWindow.baseWindow.hWnd, &This->hMon);
1672
1673     /* Now try to create the d3d9 device */
1674     ZeroMemory(&d3dpp, sizeof(d3dpp));
1675     d3dpp.Windowed = TRUE;
1676     d3dpp.hDeviceWindow = This->pVMR9->baseControlWindow.baseWindow.hWnd;
1677     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1678     d3dpp.BackBufferHeight = This->pVMR9->target_rect.bottom - This->pVMR9->target_rect.top;
1679     d3dpp.BackBufferWidth = This->pVMR9->target_rect.right - This->pVMR9->target_rect.left;
1680
1681     hr = IDirect3D9_CreateDevice(This->d3d9_ptr, d3d9_adapter, D3DDEVTYPE_HAL, NULL, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &This->d3d9_dev);
1682     if (FAILED(hr))
1683     {
1684         ERR("Could not create device: %08x\n", hr);
1685         BaseWindowImpl_DoneWithWindow(&This->pVMR9->baseControlWindow.baseWindow);
1686         return FALSE;
1687     }
1688     IVMRSurfaceAllocatorNotify9_SetD3DDevice(This->SurfaceAllocatorNotify, This->d3d9_dev, This->hMon);
1689
1690     This->d3d9_surfaces = CoTaskMemAlloc(*numbuffers * sizeof(IDirect3DSurface9 *));
1691     ZeroMemory(This->d3d9_surfaces, *numbuffers * sizeof(IDirect3DSurface9 *));
1692
1693     hr = VMR9_SurfaceAllocator_SetAllocationSettings(This, info);
1694     if (FAILED(hr))
1695         ERR("Setting allocation settings failed: %08x\n", hr);
1696
1697     if (SUCCEEDED(hr))
1698     {
1699         hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(This->SurfaceAllocatorNotify, info, numbuffers, This->d3d9_surfaces);
1700         if (FAILED(hr))
1701             ERR("Allocating surfaces failed: %08x\n", hr);
1702     }
1703
1704     if (FAILED(hr))
1705     {
1706         IVMRSurfaceAllocatorEx9_TerminateDevice(This->pVMR9->allocator, This->pVMR9->cookie);
1707         BaseWindowImpl_DoneWithWindow(&This->pVMR9->baseControlWindow.baseWindow);
1708         return FALSE;
1709     }
1710
1711     This->num_surfaces = *numbuffers;
1712
1713     return TRUE;
1714 }
1715
1716 static HRESULT WINAPI VMR9_SurfaceAllocator_InitializeDevice(IVMRSurfaceAllocatorEx9 *iface, DWORD_PTR id, VMR9AllocationInfo *allocinfo, DWORD *numbuffers)
1717 {
1718     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
1719
1720     if (This->pVMR9->mode != VMR9Mode_Windowed && !This->pVMR9->hWndClippingWindow)
1721     {
1722         ERR("No window set\n");
1723         return VFW_E_WRONG_STATE;
1724     }
1725
1726     This->info = *allocinfo;
1727
1728     if (!CreateRenderingWindow(This, allocinfo, numbuffers))
1729     {
1730         ERR("Failed to create rendering window, expect no output!\n");
1731         return VFW_E_WRONG_STATE;
1732     }
1733
1734     return S_OK;
1735 }
1736
1737 static HRESULT WINAPI VMR9_SurfaceAllocator_TerminateDevice(IVMRSurfaceAllocatorEx9 *iface, DWORD_PTR id)
1738 {
1739     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
1740
1741     if (!This->pVMR9->baseControlWindow.baseWindow.hWnd)
1742     {
1743         return S_OK;
1744     }
1745
1746     SendMessageW(This->pVMR9->baseControlWindow.baseWindow.hWnd, WM_CLOSE, 0, 0);
1747     PostThreadMessageW(This->tid, WM_QUIT, 0, 0);
1748     WaitForSingleObject(This->hWndThread, INFINITE);
1749     This->hWndThread = NULL;
1750     BaseWindowImpl_DoneWithWindow(&This->pVMR9->baseControlWindow.baseWindow);
1751
1752     return S_OK;
1753 }
1754
1755 /* Recreate all surfaces (If allocated as D3DPOOL_DEFAULT) and survive! */
1756 static HRESULT VMR9_SurfaceAllocator_UpdateDeviceReset(VMR9DefaultAllocatorPresenterImpl *This)
1757 {
1758     struct VERTEX t_vert[4];
1759     UINT width, height;
1760     INT i;
1761     void *bits = NULL;
1762     D3DPRESENT_PARAMETERS d3dpp;
1763     HRESULT hr;
1764
1765     if (!This->pVMR9->baseControlWindow.baseWindow.hWnd)
1766     {
1767         ERR("No window\n");
1768         return E_FAIL;
1769     }
1770
1771     if (!This->d3d9_surfaces || !This->reset)
1772         return S_OK;
1773
1774     This->reset = FALSE;
1775     TRACE("RESETTING\n");
1776     if (This->d3d9_vertex)
1777     {
1778         IDirect3DVertexBuffer9_Release(This->d3d9_vertex);
1779         This->d3d9_vertex = NULL;
1780     }
1781
1782     for (i = 0; i < This->num_surfaces; ++i)
1783     {
1784         IDirect3DSurface9 *surface = This->d3d9_surfaces[i];
1785         TRACE("Releasing surface %p\n", surface);
1786         if (surface)
1787             IUnknown_Release(surface);
1788     }
1789     ZeroMemory(This->d3d9_surfaces, sizeof(IDirect3DSurface9 *) * This->num_surfaces);
1790
1791     /* Now try to create the d3d9 device */
1792     ZeroMemory(&d3dpp, sizeof(d3dpp));
1793     d3dpp.Windowed = TRUE;
1794     d3dpp.hDeviceWindow = This->pVMR9->baseControlWindow.baseWindow.hWnd;
1795     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1796
1797     if (This->d3d9_dev)
1798         IDirect3DDevice9_Release(This->d3d9_dev);
1799     This->d3d9_dev = NULL;
1800     hr = IDirect3D9_CreateDevice(This->d3d9_ptr, d3d9_adapter_from_hwnd(This->d3d9_ptr, This->pVMR9->baseControlWindow.baseWindow.hWnd, &This->hMon), D3DDEVTYPE_HAL, NULL, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &This->d3d9_dev);
1801     if (FAILED(hr))
1802     {
1803         hr = IDirect3D9_CreateDevice(This->d3d9_ptr, d3d9_adapter_from_hwnd(This->d3d9_ptr, This->pVMR9->baseControlWindow.baseWindow.hWnd, &This->hMon), D3DDEVTYPE_HAL, NULL, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &This->d3d9_dev);
1804         if (FAILED(hr))
1805         {
1806             ERR("--> Creating device: %08x\n", hr);
1807             return S_OK;
1808         }
1809     }
1810     IVMRSurfaceAllocatorNotify9_ChangeD3DDevice(This->SurfaceAllocatorNotify, This->d3d9_dev, This->hMon);
1811
1812     IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(This->SurfaceAllocatorNotify, &This->info, &This->num_surfaces, This->d3d9_surfaces);
1813
1814     This->reset = FALSE;
1815
1816     if (!(This->info.dwFlags & VMR9AllocFlag_TextureSurface))
1817         return S_OK;
1818
1819     hr = IDirect3DDevice9_CreateVertexBuffer(This->d3d9_dev, 4 * sizeof(struct VERTEX), D3DUSAGE_WRITEONLY, USED_FVF,
1820                                              This->info.Pool, &This->d3d9_vertex, NULL);
1821
1822     width = This->info.dwWidth;
1823     height = This->info.dwHeight;
1824
1825     for (i = 0; i < sizeof(t_vert) / sizeof(t_vert[0]); ++i)
1826     {
1827         if (i % 2)
1828         {
1829             t_vert[i].x = (float)This->pVMR9->target_rect.right - (float)This->pVMR9->target_rect.left - 0.5f;
1830             t_vert[i].u = (float)This->pVMR9->source_rect.right / (float)width;
1831         }
1832         else
1833         {
1834             t_vert[i].x = -0.5f;
1835             t_vert[i].u = (float)This->pVMR9->source_rect.left / (float)width;
1836         }
1837
1838         if (i % 4 < 2)
1839         {
1840             t_vert[i].y = -0.5f;
1841             t_vert[i].v = (float)This->pVMR9->source_rect.bottom / (float)height;
1842         }
1843         else
1844         {
1845             t_vert[i].y = (float)This->pVMR9->target_rect.bottom - (float)This->pVMR9->target_rect.top - 0.5f;
1846             t_vert[i].v = (float)This->pVMR9->source_rect.top / (float)height;
1847         }
1848         t_vert[i].z = 0.0f;
1849         t_vert[i].rhw = 1.0f;
1850     }
1851
1852     FIXME("Vertex rectangle:\n");
1853     FIXME("X, Y: %f, %f\n", t_vert[0].x, t_vert[0].y);
1854     FIXME("X, Y: %f, %f\n", t_vert[3].x, t_vert[3].y);
1855     FIXME("TOP, LEFT: %f, %f\n", t_vert[0].u, t_vert[0].v);
1856     FIXME("DOWN, BOTTOM: %f, %f\n", t_vert[3].u, t_vert[3].v);
1857
1858     IDirect3DVertexBuffer9_Lock(This->d3d9_vertex, 0, sizeof(t_vert), &bits, 0);
1859     memcpy(bits, t_vert, sizeof(t_vert));
1860     IDirect3DVertexBuffer9_Unlock(This->d3d9_vertex);
1861
1862     return S_OK;
1863 }
1864
1865 static HRESULT WINAPI VMR9_SurfaceAllocator_GetSurface(IVMRSurfaceAllocatorEx9 *iface, DWORD_PTR id, DWORD surfaceindex, DWORD flags, IDirect3DSurface9 **surface)
1866 {
1867     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
1868
1869     /* Update everything first, this is needed because the surface might be destroyed in the reset */
1870     if (!This->d3d9_dev)
1871     {
1872         TRACE("Device has left me!\n");
1873         return E_FAIL;
1874     }
1875
1876     VMR9_SurfaceAllocator_UpdateDeviceReset(This);
1877
1878     if (surfaceindex >= This->num_surfaces)
1879     {
1880         ERR("surfaceindex is greater than num_surfaces\n");
1881         return E_FAIL;
1882     }
1883     *surface = This->d3d9_surfaces[surfaceindex];
1884     IUnknown_AddRef(*surface);
1885
1886     return S_OK;
1887 }
1888
1889 static HRESULT WINAPI VMR9_SurfaceAllocator_AdviseNotify(IVMRSurfaceAllocatorEx9 *iface, IVMRSurfaceAllocatorNotify9 *allocnotify)
1890 {
1891     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
1892
1893     TRACE("(%p/%p)->(...)\n", iface, This);
1894
1895     /* No AddRef taken here or the base VMR9 filter would never be destroied */
1896     This->SurfaceAllocatorNotify = allocnotify;
1897     return S_OK;
1898 }
1899
1900 static const IVMRSurfaceAllocatorEx9Vtbl VMR9_SurfaceAllocator =
1901 {
1902     VMR9_SurfaceAllocator_QueryInterface,
1903     VMR9_SurfaceAllocator_AddRef,
1904     VMR9_SurfaceAllocator_Release,
1905     VMR9_SurfaceAllocator_InitializeDevice,
1906     VMR9_SurfaceAllocator_TerminateDevice,
1907     VMR9_SurfaceAllocator_GetSurface,
1908     VMR9_SurfaceAllocator_AdviseNotify,
1909     NULL /* This isn't the SurfaceAllocatorEx type yet, working on it */
1910 };
1911
1912 static HRESULT VMR9DefaultAllocatorPresenterImpl_create(VMR9Impl *parent, LPVOID * ppv)
1913 {
1914     HRESULT hr = S_OK;
1915     int i;
1916     VMR9DefaultAllocatorPresenterImpl* This;
1917
1918     This = CoTaskMemAlloc(sizeof(VMR9DefaultAllocatorPresenterImpl));
1919     if (!This)
1920         return E_OUTOFMEMORY;
1921
1922     This->d3d9_ptr = NULL;
1923     if (!This->d3d9_ptr)
1924     {
1925         WARN("Could not initialize d3d9.dll\n");
1926         CoTaskMemFree(This);
1927         return VFW_E_DDRAW_CAPS_NOT_SUITABLE;
1928     }
1929
1930     i = 0;
1931     do
1932     {
1933         D3DDISPLAYMODE mode;
1934
1935         hr = IDirect3D9_EnumAdapterModes(This->d3d9_ptr, i++, D3DFMT_X8R8G8B8, 0, &mode);
1936     } while (FAILED(hr));
1937     if (FAILED(hr))
1938         ERR("HR: %08x\n", hr);
1939     if (hr == D3DERR_NOTAVAILABLE)
1940     {
1941         ERR("Format not supported\n");
1942         IUnknown_Release(This->d3d9_ptr);
1943         CoTaskMemFree(This);
1944         return VFW_E_DDRAW_CAPS_NOT_SUITABLE;
1945     }
1946
1947     This->IVMRImagePresenter9_iface.lpVtbl = &VMR9_ImagePresenter;
1948     This->IVMRSurfaceAllocatorEx9_iface.lpVtbl = &VMR9_SurfaceAllocator;
1949
1950     This->refCount = 1;
1951     This->pVMR9 = parent;
1952     This->d3d9_surfaces = NULL;
1953     This->d3d9_dev = NULL;
1954     This->hMon = 0;
1955     This->d3d9_vertex = NULL;
1956     This->num_surfaces = 0;
1957     This->hWndThread = NULL;
1958     This->ack = CreateEventW(NULL, 0, 0, NULL);
1959     This->SurfaceAllocatorNotify = NULL;
1960     This->reset = FALSE;
1961
1962     *ppv = This;
1963     return S_OK;
1964 }