xref: /reactos/dll/directx/wine/quartz/vmr9.c (revision 8a978a17)
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 #include "quartz_private.h"
26 
27 #include "uuids.h"
28 #include "vfwmsgs.h"
29 #include "amvideo.h"
30 #include "windef.h"
31 #include "winbase.h"
32 #include "dshow.h"
33 #include "evcode.h"
34 #include "strmif.h"
35 #include "ddraw.h"
36 #include "dvdmedia.h"
37 #include "d3d9.h"
38 #include "vmr9.h"
39 #include "pin.h"
40 
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
43 
44 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
45 
46 struct quartz_vmr
47 {
48     BaseRenderer renderer;
49     BaseControlWindow baseControlWindow;
50     BaseControlVideo baseControlVideo;
51 
52     IUnknown IUnknown_inner;
53     IAMCertifiedOutputProtection IAMCertifiedOutputProtection_iface;
54     IAMFilterMiscFlags IAMFilterMiscFlags_iface;
55     IVMRFilterConfig IVMRFilterConfig_iface;
56     IVMRFilterConfig9 IVMRFilterConfig9_iface;
57     IVMRMonitorConfig IVMRMonitorConfig_iface;
58     IVMRMonitorConfig9 IVMRMonitorConfig9_iface;
59     IVMRSurfaceAllocatorNotify IVMRSurfaceAllocatorNotify_iface;
60     IVMRSurfaceAllocatorNotify9 IVMRSurfaceAllocatorNotify9_iface;
61     IVMRWindowlessControl IVMRWindowlessControl_iface;
62     IVMRWindowlessControl9 IVMRWindowlessControl9_iface;
63 
64     IVMRSurfaceAllocatorEx9 *allocator;
65     IVMRImagePresenter9 *presenter;
66     BOOL allocator_is_ex;
67 
68     /*
69      * The Video Mixing Renderer supports 3 modes, renderless, windowless and windowed
70      * What I do is implement windowless as a special case of renderless, and then
71      * windowed also as a special case of windowless. This is probably the easiest way.
72      */
73     VMR9Mode mode;
74     BITMAPINFOHEADER bmiheader;
75     IUnknown * outer_unk;
76     BOOL bUnkOuterValid;
77     BOOL bAggregatable;
78 
79     HMODULE hD3d9;
80 
81     /* Presentation related members */
82     IDirect3DDevice9 *allocator_d3d9_dev;
83     HMONITOR allocator_mon;
84     DWORD num_surfaces;
85     DWORD cur_surface;
86     DWORD_PTR cookie;
87 
88     /* for Windowless Mode */
89     HWND hWndClippingWindow;
90 
91     RECT source_rect;
92     RECT target_rect;
93     LONG VideoWidth;
94     LONG VideoHeight;
95 };
96 
97 static inline struct quartz_vmr *impl_from_inner_IUnknown(IUnknown *iface)
98 {
99     return CONTAINING_RECORD(iface, struct quartz_vmr, IUnknown_inner);
100 }
101 
102 static inline struct quartz_vmr *impl_from_BaseWindow(BaseWindow *wnd)
103 {
104     return CONTAINING_RECORD(wnd, struct quartz_vmr, baseControlWindow.baseWindow);
105 }
106 
107 static inline struct quartz_vmr *impl_from_IVideoWindow(IVideoWindow *iface)
108 {
109     return CONTAINING_RECORD(iface, struct quartz_vmr, baseControlWindow.IVideoWindow_iface);
110 }
111 
112 static inline struct quartz_vmr *impl_from_BaseControlVideo(BaseControlVideo *cvid)
113 {
114     return CONTAINING_RECORD(cvid, struct quartz_vmr, baseControlVideo);
115 }
116 
117 static inline struct quartz_vmr *impl_from_IBasicVideo(IBasicVideo *iface)
118 {
119     return CONTAINING_RECORD(iface, struct quartz_vmr, baseControlVideo.IBasicVideo_iface);
120 }
121 
122 static inline struct quartz_vmr *impl_from_IAMCertifiedOutputProtection(IAMCertifiedOutputProtection *iface)
123 {
124     return CONTAINING_RECORD(iface, struct quartz_vmr, IAMCertifiedOutputProtection_iface);
125 }
126 
127 static inline struct quartz_vmr *impl_from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface)
128 {
129     return CONTAINING_RECORD(iface, struct quartz_vmr, IAMFilterMiscFlags_iface);
130 }
131 
132 static inline struct quartz_vmr *impl_from_IVMRFilterConfig(IVMRFilterConfig *iface)
133 {
134     return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRFilterConfig_iface);
135 }
136 
137 static inline struct quartz_vmr *impl_from_IVMRFilterConfig9(IVMRFilterConfig9 *iface)
138 {
139     return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRFilterConfig9_iface);
140 }
141 
142 static inline struct quartz_vmr *impl_from_IVMRMonitorConfig(IVMRMonitorConfig *iface)
143 {
144     return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRMonitorConfig_iface);
145 }
146 
147 static inline struct quartz_vmr *impl_from_IVMRMonitorConfig9(IVMRMonitorConfig9 *iface)
148 {
149     return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRMonitorConfig9_iface);
150 }
151 
152 static inline struct quartz_vmr *impl_from_IVMRSurfaceAllocatorNotify(IVMRSurfaceAllocatorNotify *iface)
153 {
154     return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRSurfaceAllocatorNotify_iface);
155 }
156 
157 static inline struct quartz_vmr *impl_from_IVMRSurfaceAllocatorNotify9(IVMRSurfaceAllocatorNotify9 *iface)
158 {
159     return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRSurfaceAllocatorNotify9_iface);
160 }
161 
162 static inline struct quartz_vmr *impl_from_IVMRWindowlessControl(IVMRWindowlessControl *iface)
163 {
164     return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRWindowlessControl_iface);
165 }
166 
167 static inline struct quartz_vmr *impl_from_IVMRWindowlessControl9(IVMRWindowlessControl9 *iface)
168 {
169     return CONTAINING_RECORD(iface, struct quartz_vmr, IVMRWindowlessControl9_iface);
170 }
171 
172 typedef struct
173 {
174     IVMRImagePresenter9 IVMRImagePresenter9_iface;
175     IVMRSurfaceAllocatorEx9 IVMRSurfaceAllocatorEx9_iface;
176 
177     LONG refCount;
178 
179     HANDLE ack;
180     DWORD tid;
181     HANDLE hWndThread;
182 
183     IDirect3DDevice9 *d3d9_dev;
184     IDirect3D9 *d3d9_ptr;
185     IDirect3DSurface9 **d3d9_surfaces;
186     IDirect3DVertexBuffer9 *d3d9_vertex;
187     HMONITOR hMon;
188     DWORD num_surfaces;
189 
190     BOOL reset;
191     VMR9AllocationInfo info;
192 
193     struct quartz_vmr* pVMR9;
194     IVMRSurfaceAllocatorNotify9 *SurfaceAllocatorNotify;
195 } VMR9DefaultAllocatorPresenterImpl;
196 
197 static inline VMR9DefaultAllocatorPresenterImpl *impl_from_IVMRImagePresenter9( IVMRImagePresenter9 *iface)
198 {
199     return CONTAINING_RECORD(iface, VMR9DefaultAllocatorPresenterImpl, IVMRImagePresenter9_iface);
200 }
201 
202 static inline VMR9DefaultAllocatorPresenterImpl *impl_from_IVMRSurfaceAllocatorEx9( IVMRSurfaceAllocatorEx9 *iface)
203 {
204     return CONTAINING_RECORD(iface, VMR9DefaultAllocatorPresenterImpl, IVMRSurfaceAllocatorEx9_iface);
205 }
206 
207 static HRESULT VMR9DefaultAllocatorPresenterImpl_create(struct quartz_vmr *parent, LPVOID * ppv);
208 
209 static DWORD VMR9_SendSampleData(struct quartz_vmr *This, VMR9PresentationInfo *info, LPBYTE data,
210                                  DWORD size)
211 {
212     AM_MEDIA_TYPE *amt;
213     HRESULT hr = S_OK;
214     int width;
215     int height;
216     BITMAPINFOHEADER *bmiHeader;
217     D3DLOCKED_RECT lock;
218 
219     TRACE("%p %p %d\n", This, data, size);
220 
221     amt = &This->renderer.pInputPin->pin.mtCurrent;
222 
223     if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo))
224     {
225         bmiHeader = &((VIDEOINFOHEADER *)amt->pbFormat)->bmiHeader;
226     }
227     else if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo2))
228     {
229         bmiHeader = &((VIDEOINFOHEADER2 *)amt->pbFormat)->bmiHeader;
230     }
231     else
232     {
233         FIXME("Unknown type %s\n", debugstr_guid(&amt->subtype));
234         return VFW_E_RUNTIME_ERROR;
235     }
236 
237     TRACE("biSize = %d\n", bmiHeader->biSize);
238     TRACE("biWidth = %d\n", bmiHeader->biWidth);
239     TRACE("biHeight = %d\n", bmiHeader->biHeight);
240     TRACE("biPlanes = %d\n", bmiHeader->biPlanes);
241     TRACE("biBitCount = %d\n", bmiHeader->biBitCount);
242     TRACE("biCompression = %s\n", debugstr_an((LPSTR)&(bmiHeader->biCompression), 4));
243     TRACE("biSizeImage = %d\n", bmiHeader->biSizeImage);
244 
245     width = bmiHeader->biWidth;
246     height = bmiHeader->biHeight;
247 
248     TRACE("Src Rect: %s\n", wine_dbgstr_rect(&This->source_rect));
249     TRACE("Dst Rect: %s\n", wine_dbgstr_rect(&This->target_rect));
250 
251     hr = IDirect3DSurface9_LockRect(info->lpSurf, &lock, NULL, D3DLOCK_DISCARD);
252     if (FAILED(hr))
253     {
254         ERR("IDirect3DSurface9_LockRect failed (%x)\n",hr);
255         return hr;
256     }
257 
258     if (height > 0) {
259         /* Bottom up image needs inverting */
260         lock.pBits = (char *)lock.pBits + (height * lock.Pitch);
261         while (height--)
262         {
263             lock.pBits = (char *)lock.pBits - lock.Pitch;
264             memcpy(lock.pBits, data, width * bmiHeader->biBitCount / 8);
265             data = data + width * bmiHeader->biBitCount / 8;
266         }
267     }
268     else if (lock.Pitch != width * bmiHeader->biBitCount / 8)
269     {
270         WARN("Slow path! %u/%u\n", lock.Pitch, width * bmiHeader->biBitCount/8);
271 
272         while (height--)
273         {
274             memcpy(lock.pBits, data, width * bmiHeader->biBitCount / 8);
275             data = data + width * bmiHeader->biBitCount / 8;
276             lock.pBits = (char *)lock.pBits + lock.Pitch;
277         }
278     }
279     else memcpy(lock.pBits, data, size);
280 
281     IDirect3DSurface9_UnlockRect(info->lpSurf);
282 
283     hr = IVMRImagePresenter9_PresentImage(This->presenter, This->cookie, info);
284     return hr;
285 }
286 
287 static HRESULT WINAPI VMR9_DoRenderSample(BaseRenderer *iface, IMediaSample * pSample)
288 {
289     struct quartz_vmr *This = (struct quartz_vmr*)iface;
290     LPBYTE pbSrcStream = NULL;
291     long cbSrcStream = 0;
292     REFERENCE_TIME tStart, tStop;
293     VMR9PresentationInfo info;
294     HRESULT hr;
295 
296     TRACE("%p %p\n", iface, pSample);
297 
298     /* It is possible that there is no device at this point */
299 
300     if (!This->allocator || !This->presenter)
301     {
302         ERR("NO PRESENTER!!\n");
303         return S_FALSE;
304     }
305 
306     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
307     if (FAILED(hr))
308         info.dwFlags = VMR9Sample_SrcDstRectsValid;
309     else
310         info.dwFlags = VMR9Sample_SrcDstRectsValid | VMR9Sample_TimeValid;
311 
312     if (IMediaSample_IsDiscontinuity(pSample) == S_OK)
313         info.dwFlags |= VMR9Sample_Discontinuity;
314 
315     if (IMediaSample_IsPreroll(pSample) == S_OK)
316         info.dwFlags |= VMR9Sample_Preroll;
317 
318     if (IMediaSample_IsSyncPoint(pSample) == S_OK)
319         info.dwFlags |= VMR9Sample_SyncPoint;
320 
321     /* If we render ourselves, and this is a preroll sample, discard it */
322     if (This->baseControlWindow.baseWindow.hWnd && (info.dwFlags & VMR9Sample_Preroll))
323     {
324         return S_OK;
325     }
326 
327     hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
328     if (FAILED(hr))
329     {
330         ERR("Cannot get pointer to sample data (%x)\n", hr);
331         return hr;
332     }
333 
334     cbSrcStream = IMediaSample_GetActualDataLength(pSample);
335 
336     info.rtStart = tStart;
337     info.rtEnd = tStop;
338     info.szAspectRatio.cx = This->bmiheader.biWidth;
339     info.szAspectRatio.cy = This->bmiheader.biHeight;
340 
341     hr = IVMRSurfaceAllocatorEx9_GetSurface(This->allocator, This->cookie, (++This->cur_surface)%This->num_surfaces, 0, &info.lpSurf);
342 
343     if (FAILED(hr))
344         return hr;
345 
346     VMR9_SendSampleData(This, &info, pbSrcStream, cbSrcStream);
347     IDirect3DSurface9_Release(info.lpSurf);
348 
349     return hr;
350 }
351 
352 static HRESULT WINAPI VMR9_CheckMediaType(BaseRenderer *iface, const AM_MEDIA_TYPE * pmt)
353 {
354     struct quartz_vmr *This = (struct quartz_vmr*)iface;
355 
356     if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) || !pmt->pbFormat)
357         return S_FALSE;
358 
359     /* Ignore subtype, test for bicompression instead */
360     if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo))
361     {
362         VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)pmt->pbFormat;
363 
364         This->bmiheader = format->bmiHeader;
365         TRACE("Resolution: %dx%d\n", format->bmiHeader.biWidth, format->bmiHeader.biHeight);
366         This->VideoWidth = format->bmiHeader.biWidth;
367         This->VideoHeight = format->bmiHeader.biHeight;
368         SetRect(&This->source_rect, 0, 0, This->VideoWidth, This->VideoHeight);
369     }
370     else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2))
371     {
372         VIDEOINFOHEADER2 *format = (VIDEOINFOHEADER2 *)pmt->pbFormat;
373 
374         This->bmiheader = format->bmiHeader;
375 
376         TRACE("Resolution: %dx%d\n", format->bmiHeader.biWidth, format->bmiHeader.biHeight);
377         This->VideoWidth = format->bmiHeader.biWidth;
378         This->VideoHeight = format->bmiHeader.biHeight;
379         SetRect(&This->source_rect, 0, 0, This->VideoWidth, This->VideoHeight);
380     }
381     else
382     {
383         ERR("Format type %s not supported\n", debugstr_guid(&pmt->formattype));
384         return S_FALSE;
385     }
386     if (This->bmiheader.biCompression != BI_RGB)
387         return S_FALSE;
388     return S_OK;
389 }
390 
391 static HRESULT VMR9_maybe_init(struct quartz_vmr *This, BOOL force)
392 {
393     VMR9AllocationInfo info;
394     DWORD buffers;
395     HRESULT hr;
396 
397     TRACE("my mode: %u, my window: %p, my last window: %p\n", This->mode, This->baseControlWindow.baseWindow.hWnd, This->hWndClippingWindow);
398     if (This->baseControlWindow.baseWindow.hWnd || !This->renderer.pInputPin->pin.pConnectedTo)
399         return S_OK;
400 
401     if (This->mode == VMR9Mode_Windowless && !This->hWndClippingWindow)
402         return (force ? VFW_E_RUNTIME_ERROR : S_OK);
403 
404     TRACE("Initializing\n");
405     info.dwFlags = VMR9AllocFlag_TextureSurface;
406     info.dwHeight = This->source_rect.bottom;
407     info.dwWidth = This->source_rect.right;
408     info.Pool = D3DPOOL_DEFAULT;
409     info.MinBuffers = 2;
410     FIXME("Reduce ratio to least common denominator\n");
411     info.szAspectRatio.cx = info.dwWidth;
412     info.szAspectRatio.cy = info.dwHeight;
413     info.szNativeSize.cx = This->bmiheader.biWidth;
414     info.szNativeSize.cy = This->bmiheader.biHeight;
415     buffers = 2;
416 
417     switch (This->bmiheader.biBitCount)
418     {
419     case 8:  info.Format = D3DFMT_R3G3B2; break;
420     case 15: info.Format = D3DFMT_X1R5G5B5; break;
421     case 16: info.Format = D3DFMT_R5G6B5; break;
422     case 24: info.Format = D3DFMT_R8G8B8; break;
423     case 32: info.Format = D3DFMT_X8R8G8B8; break;
424     default:
425         FIXME("Unknown bpp %u\n", This->bmiheader.biBitCount);
426         hr = E_INVALIDARG;
427     }
428 
429     This->cur_surface = 0;
430     if (This->num_surfaces)
431     {
432         ERR("num_surfaces or d3d9_surfaces not 0\n");
433         return E_FAIL;
434     }
435 
436     hr = IVMRSurfaceAllocatorEx9_InitializeDevice(This->allocator, This->cookie, &info, &buffers);
437     if (SUCCEEDED(hr))
438     {
439         SetRect(&This->source_rect, 0, 0, This->bmiheader.biWidth, This->bmiheader.biHeight);
440 
441         This->num_surfaces = buffers;
442     }
443     return hr;
444 }
445 
446 static VOID WINAPI VMR9_OnStartStreaming(BaseRenderer* iface)
447 {
448     struct quartz_vmr *This = (struct quartz_vmr*)iface;
449 
450     TRACE("(%p)\n", This);
451 
452     VMR9_maybe_init(This, TRUE);
453     IVMRImagePresenter9_StartPresenting(This->presenter, This->cookie);
454     SetWindowPos(This->baseControlWindow.baseWindow.hWnd, NULL,
455         This->source_rect.left,
456         This->source_rect.top,
457         This->source_rect.right - This->source_rect.left,
458         This->source_rect.bottom - This->source_rect.top,
459         SWP_NOZORDER|SWP_NOMOVE|SWP_DEFERERASE);
460     ShowWindow(This->baseControlWindow.baseWindow.hWnd, SW_SHOW);
461     GetClientRect(This->baseControlWindow.baseWindow.hWnd, &This->target_rect);
462 }
463 
464 static VOID WINAPI VMR9_OnStopStreaming(BaseRenderer* iface)
465 {
466     struct quartz_vmr *This = (struct quartz_vmr*)iface;
467 
468     TRACE("(%p)\n", This);
469 
470     if (This->renderer.filter.state == State_Running)
471         IVMRImagePresenter9_StopPresenting(This->presenter, This->cookie);
472 }
473 
474 static HRESULT WINAPI VMR9_ShouldDrawSampleNow(BaseRenderer *This, IMediaSample *pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime)
475 {
476     /* Preroll means the sample isn't shown, this is used for key frames and things like that */
477     if (IMediaSample_IsPreroll(pSample) == S_OK)
478         return E_FAIL;
479     return S_FALSE;
480 }
481 
482 static HRESULT WINAPI VMR9_CompleteConnect(BaseRenderer *This, IPin *pReceivePin)
483 {
484     struct quartz_vmr *pVMR9 = (struct quartz_vmr*)This;
485     HRESULT hr;
486 
487     TRACE("(%p)\n", This);
488 
489     if (pVMR9->mode ||
490             SUCCEEDED(hr = IVMRFilterConfig9_SetRenderingMode(&pVMR9->IVMRFilterConfig9_iface, VMR9Mode_Windowed)))
491         hr = VMR9_maybe_init(pVMR9, FALSE);
492 
493     return hr;
494 }
495 
496 static HRESULT WINAPI VMR9_BreakConnect(BaseRenderer *This)
497 {
498     struct quartz_vmr *pVMR9 = (struct quartz_vmr*)This;
499     HRESULT hr = S_OK;
500 
501     if (!pVMR9->mode)
502         return S_FALSE;
503      if (This->pInputPin->pin.pConnectedTo && pVMR9->allocator && pVMR9->presenter)
504     {
505         if (pVMR9->renderer.filter.state != State_Stopped)
506         {
507             ERR("Disconnecting while not stopped! UNTESTED!!\n");
508         }
509         if (pVMR9->renderer.filter.state == State_Running)
510             hr = IVMRImagePresenter9_StopPresenting(pVMR9->presenter, pVMR9->cookie);
511         IVMRSurfaceAllocatorEx9_TerminateDevice(pVMR9->allocator, pVMR9->cookie);
512         pVMR9->num_surfaces = 0;
513     }
514     return hr;
515 }
516 
517 static const BaseRendererFuncTable BaseFuncTable = {
518     VMR9_CheckMediaType,
519     VMR9_DoRenderSample,
520     /**/
521     NULL,
522     NULL,
523     NULL,
524     VMR9_OnStartStreaming,
525     VMR9_OnStopStreaming,
526     NULL,
527     NULL,
528     NULL,
529     VMR9_ShouldDrawSampleNow,
530     NULL,
531     /**/
532     VMR9_CompleteConnect,
533     VMR9_BreakConnect,
534     NULL,
535     NULL,
536     NULL,
537 };
538 
539 static LPWSTR WINAPI VMR9_GetClassWindowStyles(BaseWindow *This, DWORD *pClassStyles, DWORD *pWindowStyles, DWORD *pWindowStylesEx)
540 {
541     static WCHAR classnameW[] = { 'I','V','M','R','9',' ','C','l','a','s','s', 0 };
542 
543     *pClassStyles = 0;
544     *pWindowStyles = WS_SIZEBOX;
545     *pWindowStylesEx = 0;
546 
547     return classnameW;
548 }
549 
550 static RECT WINAPI VMR9_GetDefaultRect(BaseWindow *This)
551 {
552     struct quartz_vmr* pVMR9 = impl_from_BaseWindow(This);
553     static RECT defRect;
554 
555     SetRect(&defRect, 0, 0, pVMR9->VideoWidth, pVMR9->VideoHeight);
556 
557     return defRect;
558 }
559 
560 static BOOL WINAPI VMR9_OnSize(BaseWindow *This, LONG Width, LONG Height)
561 {
562     struct quartz_vmr* pVMR9 = impl_from_BaseWindow(This);
563 
564     TRACE("WM_SIZE %d %d\n", Width, Height);
565     GetClientRect(This->hWnd, &pVMR9->target_rect);
566     TRACE("WM_SIZING: DestRect=(%d,%d),(%d,%d)\n",
567         pVMR9->target_rect.left,
568         pVMR9->target_rect.top,
569         pVMR9->target_rect.right - pVMR9->target_rect.left,
570         pVMR9->target_rect.bottom - pVMR9->target_rect.top);
571     return BaseWindowImpl_OnSize(This, Width, Height);
572 }
573 
574 static const BaseWindowFuncTable renderer_BaseWindowFuncTable = {
575     VMR9_GetClassWindowStyles,
576     VMR9_GetDefaultRect,
577     NULL,
578     BaseControlWindowImpl_PossiblyEatMessage,
579     VMR9_OnSize,
580 };
581 
582 static HRESULT WINAPI VMR9_GetSourceRect(BaseControlVideo* This, RECT *pSourceRect)
583 {
584     struct quartz_vmr* pVMR9 = impl_from_BaseControlVideo(This);
585     CopyRect(pSourceRect,&pVMR9->source_rect);
586     return S_OK;
587 }
588 
589 static HRESULT WINAPI VMR9_GetStaticImage(BaseControlVideo* This, LONG *pBufferSize, LONG *pDIBImage)
590 {
591     struct quartz_vmr* pVMR9 = impl_from_BaseControlVideo(This);
592     BITMAPINFOHEADER *bmiHeader;
593     LONG needed_size;
594     AM_MEDIA_TYPE *amt = &pVMR9->renderer.pInputPin->pin.mtCurrent;
595     char *ptr;
596 
597     FIXME("(%p/%p)->(%p, %p): partial stub\n", pVMR9, This, pBufferSize, pDIBImage);
598 
599     EnterCriticalSection(&pVMR9->renderer.filter.csFilter);
600 
601     if (!pVMR9->renderer.pMediaSample)
602     {
603          LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
604          return (pVMR9->renderer.filter.state == State_Paused ? E_UNEXPECTED : VFW_E_NOT_PAUSED);
605     }
606 
607     if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo))
608     {
609         bmiHeader = &((VIDEOINFOHEADER *)amt->pbFormat)->bmiHeader;
610     }
611     else if (IsEqualIID(&amt->formattype, &FORMAT_VideoInfo2))
612     {
613         bmiHeader = &((VIDEOINFOHEADER2 *)amt->pbFormat)->bmiHeader;
614     }
615     else
616     {
617         FIXME("Unknown type %s\n", debugstr_guid(&amt->subtype));
618         LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
619         return VFW_E_RUNTIME_ERROR;
620     }
621 
622     needed_size = bmiHeader->biSize;
623     needed_size += IMediaSample_GetActualDataLength(pVMR9->renderer.pMediaSample);
624 
625     if (!pDIBImage)
626     {
627         *pBufferSize = needed_size;
628         LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
629         return S_OK;
630     }
631 
632     if (needed_size < *pBufferSize)
633     {
634         ERR("Buffer too small %u/%u\n", needed_size, *pBufferSize);
635         LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
636         return E_FAIL;
637     }
638     *pBufferSize = needed_size;
639 
640     memcpy(pDIBImage, bmiHeader, bmiHeader->biSize);
641     IMediaSample_GetPointer(pVMR9->renderer.pMediaSample, (BYTE **)&ptr);
642     memcpy((char *)pDIBImage + bmiHeader->biSize, ptr, IMediaSample_GetActualDataLength(pVMR9->renderer.pMediaSample));
643 
644     LeaveCriticalSection(&pVMR9->renderer.filter.csFilter);
645     return S_OK;
646 }
647 
648 static HRESULT WINAPI VMR9_GetTargetRect(BaseControlVideo* This, RECT *pTargetRect)
649 {
650     struct quartz_vmr* pVMR9 = impl_from_BaseControlVideo(This);
651     CopyRect(pTargetRect,&pVMR9->target_rect);
652     return S_OK;
653 }
654 
655 static VIDEOINFOHEADER* WINAPI VMR9_GetVideoFormat(BaseControlVideo* This)
656 {
657     struct quartz_vmr* pVMR9 = impl_from_BaseControlVideo(This);
658     AM_MEDIA_TYPE *pmt;
659 
660     TRACE("(%p/%p)\n", pVMR9, This);
661 
662     pmt = &pVMR9->renderer.pInputPin->pin.mtCurrent;
663     if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) {
664         return (VIDEOINFOHEADER*)pmt->pbFormat;
665     } else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2)) {
666         static VIDEOINFOHEADER vih;
667         VIDEOINFOHEADER2 *vih2 = (VIDEOINFOHEADER2*)pmt->pbFormat;
668         memcpy(&vih,vih2,sizeof(VIDEOINFOHEADER));
669         memcpy(&vih.bmiHeader, &vih2->bmiHeader, sizeof(BITMAPINFOHEADER));
670         return &vih;
671     } else {
672         ERR("Unknown format type %s\n", qzdebugstr_guid(&pmt->formattype));
673         return NULL;
674     }
675 }
676 
677 static HRESULT WINAPI VMR9_IsDefaultSourceRect(BaseControlVideo* This)
678 {
679     struct quartz_vmr* pVMR9 = impl_from_BaseControlVideo(This);
680     FIXME("(%p/%p)->(): stub !!!\n", pVMR9, This);
681 
682     return S_OK;
683 }
684 
685 static HRESULT WINAPI VMR9_IsDefaultTargetRect(BaseControlVideo* This)
686 {
687     struct quartz_vmr* pVMR9 = impl_from_BaseControlVideo(This);
688     FIXME("(%p/%p)->(): stub !!!\n", pVMR9, This);
689 
690     return S_OK;
691 }
692 
693 static HRESULT WINAPI VMR9_SetDefaultSourceRect(BaseControlVideo* This)
694 {
695     struct quartz_vmr* pVMR9 = impl_from_BaseControlVideo(This);
696 
697     SetRect(&pVMR9->source_rect, 0, 0, pVMR9->VideoWidth, pVMR9->VideoHeight);
698 
699     return S_OK;
700 }
701 
702 static HRESULT WINAPI VMR9_SetDefaultTargetRect(BaseControlVideo* This)
703 {
704     RECT rect;
705     struct quartz_vmr* pVMR9 = impl_from_BaseControlVideo(This);
706 
707     if (!GetClientRect(pVMR9->baseControlWindow.baseWindow.hWnd, &rect))
708         return E_FAIL;
709 
710     SetRect(&pVMR9->target_rect, 0, 0, rect.right, rect.bottom);
711 
712     return S_OK;
713 }
714 
715 static HRESULT WINAPI VMR9_SetSourceRect(BaseControlVideo* This, RECT *pSourceRect)
716 {
717     struct quartz_vmr* pVMR9 = impl_from_BaseControlVideo(This);
718     CopyRect(&pVMR9->source_rect,pSourceRect);
719     return S_OK;
720 }
721 
722 static HRESULT WINAPI VMR9_SetTargetRect(BaseControlVideo* This, RECT *pTargetRect)
723 {
724     struct quartz_vmr* pVMR9 = impl_from_BaseControlVideo(This);
725     CopyRect(&pVMR9->target_rect,pTargetRect);
726     return S_OK;
727 }
728 
729 static const BaseControlVideoFuncTable renderer_BaseControlVideoFuncTable = {
730     VMR9_GetSourceRect,
731     VMR9_GetStaticImage,
732     VMR9_GetTargetRect,
733     VMR9_GetVideoFormat,
734     VMR9_IsDefaultSourceRect,
735     VMR9_IsDefaultTargetRect,
736     VMR9_SetDefaultSourceRect,
737     VMR9_SetDefaultTargetRect,
738     VMR9_SetSourceRect,
739     VMR9_SetTargetRect
740 };
741 
742 static HRESULT WINAPI VMR9Inner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
743 {
744     struct quartz_vmr *This = impl_from_inner_IUnknown(iface);
745     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
746 
747     if (This->bAggregatable)
748         This->bUnkOuterValid = TRUE;
749 
750     *ppv = NULL;
751 
752     if (IsEqualIID(riid, &IID_IUnknown))
753         *ppv = &This->IUnknown_inner;
754     else if (IsEqualIID(riid, &IID_IVideoWindow))
755         *ppv = &This->baseControlWindow.IVideoWindow_iface;
756     else if (IsEqualIID(riid, &IID_IBasicVideo))
757         *ppv = &This->baseControlVideo.IBasicVideo_iface;
758     else if (IsEqualIID(riid, &IID_IAMCertifiedOutputProtection))
759         *ppv = &This->IAMCertifiedOutputProtection_iface;
760     else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags))
761         *ppv = &This->IAMFilterMiscFlags_iface;
762     else if (IsEqualIID(riid, &IID_IVMRFilterConfig))
763         *ppv = &This->IVMRFilterConfig_iface;
764     else if (IsEqualIID(riid, &IID_IVMRFilterConfig9))
765         *ppv = &This->IVMRFilterConfig9_iface;
766     else if (IsEqualIID(riid, &IID_IVMRMonitorConfig))
767         *ppv = &This->IVMRMonitorConfig_iface;
768     else if (IsEqualIID(riid, &IID_IVMRMonitorConfig9))
769         *ppv = &This->IVMRMonitorConfig9_iface;
770     else if (IsEqualIID(riid, &IID_IVMRSurfaceAllocatorNotify) && This->mode == (VMR9Mode)VMRMode_Renderless)
771         *ppv = &This->IVMRSurfaceAllocatorNotify_iface;
772     else if (IsEqualIID(riid, &IID_IVMRSurfaceAllocatorNotify9) && This->mode == VMR9Mode_Renderless)
773         *ppv = &This->IVMRSurfaceAllocatorNotify9_iface;
774     else if (IsEqualIID(riid, &IID_IVMRWindowlessControl) && This->mode == (VMR9Mode)VMRMode_Windowless)
775         *ppv = &This->IVMRWindowlessControl_iface;
776     else if (IsEqualIID(riid, &IID_IVMRWindowlessControl9) && This->mode == VMR9Mode_Windowless)
777         *ppv = &This->IVMRWindowlessControl9_iface;
778     else
779     {
780         HRESULT hr;
781         hr = BaseRendererImpl_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
782         if (SUCCEEDED(hr))
783             return hr;
784     }
785 
786     if (*ppv)
787     {
788         IUnknown_AddRef((IUnknown *)(*ppv));
789         return S_OK;
790     }
791 
792     else if (IsEqualIID(riid, &IID_IBasicVideo2))
793         FIXME("No interface for IID_IBasicVideo2\n");
794     else if (IsEqualIID(riid, &IID_IVMRWindowlessControl9))
795         ;
796     else if (IsEqualIID(riid, &IID_IVMRSurfaceAllocatorNotify9))
797         ;
798     else if (IsEqualIID(riid, &IID_IMediaPosition))
799         FIXME("No interface for IID_IMediaPosition\n");
800     else if (IsEqualIID(riid, &IID_IQualProp))
801         FIXME("No interface for IID_IQualProp\n");
802     else if (IsEqualIID(riid, &IID_IVMRAspectRatioControl9))
803         FIXME("No interface for IID_IVMRAspectRatioControl9\n");
804     else if (IsEqualIID(riid, &IID_IVMRDeinterlaceControl9))
805         FIXME("No interface for IID_IVMRDeinterlaceControl9\n");
806     else if (IsEqualIID(riid, &IID_IVMRMixerBitmap9))
807         FIXME("No interface for IID_IVMRMixerBitmap9\n");
808     else if (IsEqualIID(riid, &IID_IVMRMixerControl9))
809         FIXME("No interface for IID_IVMRMixerControl9\n");
810     else
811         FIXME("No interface for %s\n", debugstr_guid(riid));
812 
813     return E_NOINTERFACE;
814 }
815 
816 static ULONG WINAPI VMR9Inner_AddRef(IUnknown * iface)
817 {
818     struct quartz_vmr *This = impl_from_inner_IUnknown(iface);
819     ULONG refCount = BaseFilterImpl_AddRef(&This->renderer.filter.IBaseFilter_iface);
820 
821     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
822 
823     return refCount;
824 }
825 
826 static ULONG WINAPI VMR9Inner_Release(IUnknown * iface)
827 {
828     struct quartz_vmr *This = impl_from_inner_IUnknown(iface);
829     ULONG refCount = BaseRendererImpl_Release(&This->renderer.filter.IBaseFilter_iface);
830 
831     TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
832 
833     if (!refCount)
834     {
835         TRACE("Destroying\n");
836         BaseControlWindow_Destroy(&This->baseControlWindow);
837         FreeLibrary(This->hD3d9);
838 
839         if (This->allocator)
840             IVMRSurfaceAllocatorEx9_Release(This->allocator);
841         if (This->presenter)
842             IVMRImagePresenter9_Release(This->presenter);
843 
844         This->num_surfaces = 0;
845         if (This->allocator_d3d9_dev)
846         {
847             IDirect3DDevice9_Release(This->allocator_d3d9_dev);
848             This->allocator_d3d9_dev = NULL;
849         }
850 
851         CoTaskMemFree(This);
852     }
853     return refCount;
854 }
855 
856 static const IUnknownVtbl IInner_VTable =
857 {
858     VMR9Inner_QueryInterface,
859     VMR9Inner_AddRef,
860     VMR9Inner_Release
861 };
862 
863 static HRESULT WINAPI VMR9_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
864 {
865     struct quartz_vmr *This = (struct quartz_vmr*)iface;
866 
867     if (This->bAggregatable)
868         This->bUnkOuterValid = TRUE;
869 
870     if (This->outer_unk)
871     {
872         if (This->bAggregatable)
873             return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
874 
875         if (IsEqualIID(riid, &IID_IUnknown))
876         {
877             HRESULT hr;
878 
879             IUnknown_AddRef(&This->IUnknown_inner);
880             hr = IUnknown_QueryInterface(&This->IUnknown_inner, riid, ppv);
881             IUnknown_Release(&This->IUnknown_inner);
882             This->bAggregatable = TRUE;
883             return hr;
884         }
885 
886         *ppv = NULL;
887         return E_NOINTERFACE;
888     }
889 
890     return IUnknown_QueryInterface(&This->IUnknown_inner, riid, ppv);
891 }
892 
893 static ULONG WINAPI VMR9_AddRef(IBaseFilter * iface)
894 {
895     struct quartz_vmr *This = (struct quartz_vmr*)iface;
896     LONG ret;
897 
898     if (This->outer_unk && This->bUnkOuterValid)
899         ret = IUnknown_AddRef(This->outer_unk);
900     else
901         ret = IUnknown_AddRef(&This->IUnknown_inner);
902 
903     TRACE("(%p)->AddRef from %d\n", iface, ret - 1);
904 
905     return ret;
906 }
907 
908 static ULONG WINAPI VMR9_Release(IBaseFilter * iface)
909 {
910     struct quartz_vmr *This = (struct quartz_vmr*)iface;
911     LONG ret;
912 
913     if (This->outer_unk && This->bUnkOuterValid)
914         ret = IUnknown_Release(This->outer_unk);
915     else
916         ret = IUnknown_Release(&This->IUnknown_inner);
917 
918     TRACE("(%p)->Release from %d\n", iface, ret + 1);
919 
920     if (ret)
921         return ret;
922     return 0;
923 }
924 
925 static const IBaseFilterVtbl VMR_Vtbl =
926 {
927     VMR9_QueryInterface,
928     VMR9_AddRef,
929     VMR9_Release,
930     BaseFilterImpl_GetClassID,
931     BaseRendererImpl_Stop,
932     BaseRendererImpl_Pause,
933     BaseRendererImpl_Run,
934     BaseRendererImpl_GetState,
935     BaseRendererImpl_SetSyncSource,
936     BaseFilterImpl_GetSyncSource,
937     BaseFilterImpl_EnumPins,
938     BaseRendererImpl_FindPin,
939     BaseFilterImpl_QueryFilterInfo,
940     BaseFilterImpl_JoinFilterGraph,
941     BaseFilterImpl_QueryVendorInfo
942 };
943 
944 /*** IUnknown methods ***/
945 static HRESULT WINAPI Videowindow_QueryInterface(IVideoWindow *iface, REFIID riid, LPVOID*ppvObj)
946 {
947     struct quartz_vmr *This = impl_from_IVideoWindow(iface);
948 
949     TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
950 
951     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppvObj);
952 }
953 
954 static ULONG WINAPI Videowindow_AddRef(IVideoWindow *iface)
955 {
956     struct quartz_vmr *This = impl_from_IVideoWindow(iface);
957 
958     TRACE("(%p/%p)->()\n", This, iface);
959 
960     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
961 }
962 
963 static ULONG WINAPI Videowindow_Release(IVideoWindow *iface)
964 {
965     struct quartz_vmr *This = impl_from_IVideoWindow(iface);
966 
967     TRACE("(%p/%p)->()\n", This, iface);
968 
969     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
970 }
971 
972 static const IVideoWindowVtbl IVideoWindow_VTable =
973 {
974     Videowindow_QueryInterface,
975     Videowindow_AddRef,
976     Videowindow_Release,
977     BaseControlWindowImpl_GetTypeInfoCount,
978     BaseControlWindowImpl_GetTypeInfo,
979     BaseControlWindowImpl_GetIDsOfNames,
980     BaseControlWindowImpl_Invoke,
981     BaseControlWindowImpl_put_Caption,
982     BaseControlWindowImpl_get_Caption,
983     BaseControlWindowImpl_put_WindowStyle,
984     BaseControlWindowImpl_get_WindowStyle,
985     BaseControlWindowImpl_put_WindowStyleEx,
986     BaseControlWindowImpl_get_WindowStyleEx,
987     BaseControlWindowImpl_put_AutoShow,
988     BaseControlWindowImpl_get_AutoShow,
989     BaseControlWindowImpl_put_WindowState,
990     BaseControlWindowImpl_get_WindowState,
991     BaseControlWindowImpl_put_BackgroundPalette,
992     BaseControlWindowImpl_get_BackgroundPalette,
993     BaseControlWindowImpl_put_Visible,
994     BaseControlWindowImpl_get_Visible,
995     BaseControlWindowImpl_put_Left,
996     BaseControlWindowImpl_get_Left,
997     BaseControlWindowImpl_put_Width,
998     BaseControlWindowImpl_get_Width,
999     BaseControlWindowImpl_put_Top,
1000     BaseControlWindowImpl_get_Top,
1001     BaseControlWindowImpl_put_Height,
1002     BaseControlWindowImpl_get_Height,
1003     BaseControlWindowImpl_put_Owner,
1004     BaseControlWindowImpl_get_Owner,
1005     BaseControlWindowImpl_put_MessageDrain,
1006     BaseControlWindowImpl_get_MessageDrain,
1007     BaseControlWindowImpl_get_BorderColor,
1008     BaseControlWindowImpl_put_BorderColor,
1009     BaseControlWindowImpl_get_FullScreenMode,
1010     BaseControlWindowImpl_put_FullScreenMode,
1011     BaseControlWindowImpl_SetWindowForeground,
1012     BaseControlWindowImpl_NotifyOwnerMessage,
1013     BaseControlWindowImpl_SetWindowPosition,
1014     BaseControlWindowImpl_GetWindowPosition,
1015     BaseControlWindowImpl_GetMinIdealImageSize,
1016     BaseControlWindowImpl_GetMaxIdealImageSize,
1017     BaseControlWindowImpl_GetRestorePosition,
1018     BaseControlWindowImpl_HideCursor,
1019     BaseControlWindowImpl_IsCursorHidden
1020 };
1021 
1022 /*** IUnknown methods ***/
1023 static HRESULT WINAPI Basicvideo_QueryInterface(IBasicVideo *iface, REFIID riid, LPVOID * ppvObj)
1024 {
1025     struct quartz_vmr *This = impl_from_IBasicVideo(iface);
1026 
1027     TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
1028 
1029     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppvObj);
1030 }
1031 
1032 static ULONG WINAPI Basicvideo_AddRef(IBasicVideo *iface)
1033 {
1034     struct quartz_vmr *This = impl_from_IBasicVideo(iface);
1035 
1036     TRACE("(%p/%p)->()\n", This, iface);
1037 
1038     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
1039 }
1040 
1041 static ULONG WINAPI Basicvideo_Release(IBasicVideo *iface)
1042 {
1043     struct quartz_vmr *This = impl_from_IBasicVideo(iface);
1044 
1045     TRACE("(%p/%p)->()\n", This, iface);
1046 
1047     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
1048 }
1049 
1050 static const IBasicVideoVtbl IBasicVideo_VTable =
1051 {
1052     Basicvideo_QueryInterface,
1053     Basicvideo_AddRef,
1054     Basicvideo_Release,
1055     BaseControlVideoImpl_GetTypeInfoCount,
1056     BaseControlVideoImpl_GetTypeInfo,
1057     BaseControlVideoImpl_GetIDsOfNames,
1058     BaseControlVideoImpl_Invoke,
1059     BaseControlVideoImpl_get_AvgTimePerFrame,
1060     BaseControlVideoImpl_get_BitRate,
1061     BaseControlVideoImpl_get_BitErrorRate,
1062     BaseControlVideoImpl_get_VideoWidth,
1063     BaseControlVideoImpl_get_VideoHeight,
1064     BaseControlVideoImpl_put_SourceLeft,
1065     BaseControlVideoImpl_get_SourceLeft,
1066     BaseControlVideoImpl_put_SourceWidth,
1067     BaseControlVideoImpl_get_SourceWidth,
1068     BaseControlVideoImpl_put_SourceTop,
1069     BaseControlVideoImpl_get_SourceTop,
1070     BaseControlVideoImpl_put_SourceHeight,
1071     BaseControlVideoImpl_get_SourceHeight,
1072     BaseControlVideoImpl_put_DestinationLeft,
1073     BaseControlVideoImpl_get_DestinationLeft,
1074     BaseControlVideoImpl_put_DestinationWidth,
1075     BaseControlVideoImpl_get_DestinationWidth,
1076     BaseControlVideoImpl_put_DestinationTop,
1077     BaseControlVideoImpl_get_DestinationTop,
1078     BaseControlVideoImpl_put_DestinationHeight,
1079     BaseControlVideoImpl_get_DestinationHeight,
1080     BaseControlVideoImpl_SetSourcePosition,
1081     BaseControlVideoImpl_GetSourcePosition,
1082     BaseControlVideoImpl_SetDefaultSourcePosition,
1083     BaseControlVideoImpl_SetDestinationPosition,
1084     BaseControlVideoImpl_GetDestinationPosition,
1085     BaseControlVideoImpl_SetDefaultDestinationPosition,
1086     BaseControlVideoImpl_GetVideoSize,
1087     BaseControlVideoImpl_GetVideoPaletteEntries,
1088     BaseControlVideoImpl_GetCurrentImage,
1089     BaseControlVideoImpl_IsUsingDefaultSource,
1090     BaseControlVideoImpl_IsUsingDefaultDestination
1091 };
1092 
1093 static HRESULT WINAPI AMCertifiedOutputProtection_QueryInterface(IAMCertifiedOutputProtection *iface,
1094                                                                  REFIID riid, void **ppv)
1095 {
1096     struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface);
1097     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
1098 }
1099 
1100 static ULONG WINAPI AMCertifiedOutputProtection_AddRef(IAMCertifiedOutputProtection *iface)
1101 {
1102     struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface);
1103     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
1104 }
1105 
1106 static ULONG WINAPI AMCertifiedOutputProtection_Release(IAMCertifiedOutputProtection *iface)
1107 {
1108     struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface);
1109     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
1110 }
1111 
1112 static HRESULT WINAPI AMCertifiedOutputProtection_KeyExchange(IAMCertifiedOutputProtection *iface,
1113                                                               GUID* pRandom, BYTE** VarLenCertGH,
1114                                                               DWORD* pdwLengthCertGH)
1115 {
1116     struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface);
1117 
1118     FIXME("(%p/%p)->(%p, %p, %p) stub\n", iface, This, pRandom, VarLenCertGH, pdwLengthCertGH);
1119     return VFW_E_NO_COPP_HW;
1120 }
1121 
1122 static HRESULT WINAPI AMCertifiedOutputProtection_SessionSequenceStart(IAMCertifiedOutputProtection *iface,
1123                                                                        AMCOPPSignature* pSig)
1124 {
1125     struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface);
1126 
1127     FIXME("(%p/%p)->(%p) stub\n", iface, This, pSig);
1128     return VFW_E_NO_COPP_HW;
1129 }
1130 
1131 static HRESULT WINAPI AMCertifiedOutputProtection_ProtectionCommand(IAMCertifiedOutputProtection *iface,
1132                                                                     const AMCOPPCommand* cmd)
1133 {
1134     struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface);
1135 
1136     FIXME("(%p/%p)->(%p) stub\n", iface, This, cmd);
1137     return VFW_E_NO_COPP_HW;
1138 }
1139 
1140 static HRESULT WINAPI AMCertifiedOutputProtection_ProtectionStatus(IAMCertifiedOutputProtection *iface,
1141                                                                    const AMCOPPStatusInput* pStatusInput,
1142                                                                    AMCOPPStatusOutput* pStatusOutput)
1143 {
1144     struct quartz_vmr *This = impl_from_IAMCertifiedOutputProtection(iface);
1145 
1146     FIXME("(%p/%p)->(%p, %p) stub\n", iface, This, pStatusInput, pStatusOutput);
1147     return VFW_E_NO_COPP_HW;
1148 }
1149 
1150 static const IAMCertifiedOutputProtectionVtbl IAMCertifiedOutputProtection_Vtbl =
1151 {
1152     AMCertifiedOutputProtection_QueryInterface,
1153     AMCertifiedOutputProtection_AddRef,
1154     AMCertifiedOutputProtection_Release,
1155     AMCertifiedOutputProtection_KeyExchange,
1156     AMCertifiedOutputProtection_SessionSequenceStart,
1157     AMCertifiedOutputProtection_ProtectionCommand,
1158     AMCertifiedOutputProtection_ProtectionStatus
1159 };
1160 
1161 static HRESULT WINAPI AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, void **ppv) {
1162     struct quartz_vmr *This = impl_from_IAMFilterMiscFlags(iface);
1163     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
1164 }
1165 
1166 static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface) {
1167     struct quartz_vmr *This = impl_from_IAMFilterMiscFlags(iface);
1168     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
1169 }
1170 
1171 static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface) {
1172     struct quartz_vmr *This = impl_from_IAMFilterMiscFlags(iface);
1173     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
1174 }
1175 
1176 static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface) {
1177     return AM_FILTER_MISC_FLAGS_IS_RENDERER;
1178 }
1179 
1180 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = {
1181     AMFilterMiscFlags_QueryInterface,
1182     AMFilterMiscFlags_AddRef,
1183     AMFilterMiscFlags_Release,
1184     AMFilterMiscFlags_GetMiscFlags
1185 };
1186 
1187 static HRESULT WINAPI VMR7FilterConfig_QueryInterface(IVMRFilterConfig *iface, REFIID riid,
1188                                                       void** ppv)
1189 {
1190     struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface);
1191     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
1192 }
1193 
1194 static ULONG WINAPI VMR7FilterConfig_AddRef(IVMRFilterConfig *iface)
1195 {
1196     struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface);
1197     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
1198 }
1199 
1200 static ULONG WINAPI VMR7FilterConfig_Release(IVMRFilterConfig *iface)
1201 {
1202     struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface);
1203     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
1204 }
1205 
1206 static HRESULT WINAPI VMR7FilterConfig_SetImageCompositor(IVMRFilterConfig *iface,
1207                                                           IVMRImageCompositor *compositor)
1208 {
1209     struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface);
1210 
1211     FIXME("(%p/%p)->(%p) stub\n", iface, This, compositor);
1212     return E_NOTIMPL;
1213 }
1214 
1215 static HRESULT WINAPI VMR7FilterConfig_SetNumberOfStreams(IVMRFilterConfig *iface, DWORD max)
1216 {
1217     struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface);
1218 
1219     FIXME("(%p/%p)->(%u) stub\n", iface, This, max);
1220     return E_NOTIMPL;
1221 }
1222 
1223 static HRESULT WINAPI VMR7FilterConfig_GetNumberOfStreams(IVMRFilterConfig *iface, DWORD *max)
1224 {
1225     struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface);
1226 
1227     FIXME("(%p/%p)->(%p) stub\n", iface, This, max);
1228     return E_NOTIMPL;
1229 }
1230 
1231 static HRESULT WINAPI VMR7FilterConfig_SetRenderingPrefs(IVMRFilterConfig *iface, DWORD renderflags)
1232 {
1233     struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface);
1234 
1235     FIXME("(%p/%p)->(%u) stub\n", iface, This, renderflags);
1236     return E_NOTIMPL;
1237 }
1238 
1239 static HRESULT WINAPI VMR7FilterConfig_GetRenderingPrefs(IVMRFilterConfig *iface, DWORD *renderflags)
1240 {
1241     struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface);
1242 
1243     FIXME("(%p/%p)->(%p) stub\n", iface, This, renderflags);
1244     return E_NOTIMPL;
1245 }
1246 
1247 static HRESULT WINAPI VMR7FilterConfig_SetRenderingMode(IVMRFilterConfig *iface, DWORD mode)
1248 {
1249     struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface);
1250 
1251     FIXME("(%p/%p)->(%u) stub\n", iface, This, mode);
1252     return E_NOTIMPL;
1253 }
1254 
1255 static HRESULT WINAPI VMR7FilterConfig_GetRenderingMode(IVMRFilterConfig *iface, DWORD *mode)
1256 {
1257     struct quartz_vmr *This = impl_from_IVMRFilterConfig(iface);
1258 
1259     TRACE("(%p/%p)->(%p)\n", iface, This, mode);
1260     if (!mode) return E_POINTER;
1261 
1262     if (This->mode)
1263         *mode = This->mode;
1264     else
1265         *mode = VMRMode_Windowed;
1266 
1267     return S_OK;
1268 }
1269 
1270 static const IVMRFilterConfigVtbl VMR7_FilterConfig_Vtbl =
1271 {
1272     VMR7FilterConfig_QueryInterface,
1273     VMR7FilterConfig_AddRef,
1274     VMR7FilterConfig_Release,
1275     VMR7FilterConfig_SetImageCompositor,
1276     VMR7FilterConfig_SetNumberOfStreams,
1277     VMR7FilterConfig_GetNumberOfStreams,
1278     VMR7FilterConfig_SetRenderingPrefs,
1279     VMR7FilterConfig_GetRenderingPrefs,
1280     VMR7FilterConfig_SetRenderingMode,
1281     VMR7FilterConfig_GetRenderingMode
1282 };
1283 
1284 struct get_available_monitors_args
1285 {
1286     VMRMONITORINFO *info7;
1287     VMR9MonitorInfo *info9;
1288     DWORD arraysize;
1289     DWORD numdev;
1290 };
1291 
1292 static BOOL CALLBACK get_available_monitors_proc(HMONITOR hmon, HDC hdc, LPRECT lprc, LPARAM lparam)
1293 {
1294     struct get_available_monitors_args *args = (struct get_available_monitors_args *)lparam;
1295     MONITORINFOEXW mi;
1296 
1297     if (args->info7 || args->info9)
1298     {
1299 
1300         if (!args->arraysize)
1301             return FALSE;
1302 
1303         mi.cbSize = sizeof(mi);
1304         if (!GetMonitorInfoW(hmon, (MONITORINFO*)&mi))
1305             return TRUE;
1306 
1307         /* fill VMRMONITORINFO struct */
1308         if (args->info7)
1309         {
1310             VMRMONITORINFO *info = args->info7++;
1311             memset(info, 0, sizeof(*info));
1312 
1313             if (args->numdev > 0)
1314             {
1315                 info->guid.pGUID = &info->guid.GUID;
1316                 info->guid.GUID.Data4[7] = args->numdev;
1317             }
1318             else
1319                 info->guid.pGUID = NULL;
1320 
1321             info->rcMonitor     = mi.rcMonitor;
1322             info->hMon          = hmon;
1323             info->dwFlags       = mi.dwFlags;
1324 
1325             lstrcpynW(info->szDevice, mi.szDevice, sizeof(info->szDevice)/sizeof(WCHAR));
1326 
1327             /* FIXME: how to get these values? */
1328             info->szDescription[0] = 0;
1329         }
1330 
1331         /* fill VMR9MonitorInfo struct */
1332         if (args->info9)
1333         {
1334             VMR9MonitorInfo *info = args->info9++;
1335             memset(info, 0, sizeof(*info));
1336 
1337             info->uDevID        = 0; /* FIXME */
1338             info->rcMonitor     = mi.rcMonitor;
1339             info->hMon          = hmon;
1340             info->dwFlags       = mi.dwFlags;
1341 
1342             lstrcpynW(info->szDevice, mi.szDevice, sizeof(info->szDevice)/sizeof(WCHAR));
1343 
1344             /* FIXME: how to get these values? */
1345             info->szDescription[0] = 0;
1346             info->dwVendorId    = 0;
1347             info->dwDeviceId    = 0;
1348             info->dwSubSysId    = 0;
1349             info->dwRevision    = 0;
1350         }
1351 
1352         args->arraysize--;
1353     }
1354 
1355     args->numdev++;
1356     return TRUE;
1357 }
1358 
1359 static HRESULT WINAPI VMR7MonitorConfig_QueryInterface(IVMRMonitorConfig *iface, REFIID riid,
1360                                                        LPVOID * ppv)
1361 {
1362     struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface);
1363     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
1364 }
1365 
1366 static ULONG WINAPI VMR7MonitorConfig_AddRef(IVMRMonitorConfig *iface)
1367 {
1368     struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface);
1369     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
1370 }
1371 
1372 static ULONG WINAPI VMR7MonitorConfig_Release(IVMRMonitorConfig *iface)
1373 {
1374     struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface);
1375     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
1376 }
1377 
1378 static HRESULT WINAPI VMR7MonitorConfig_SetMonitor(IVMRMonitorConfig *iface, const VMRGUID *pGUID)
1379 {
1380     struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface);
1381 
1382     FIXME("(%p/%p)->(%p) stub\n", iface, This, pGUID);
1383 
1384     if (!pGUID)
1385         return E_POINTER;
1386 
1387     return S_OK;
1388 }
1389 
1390 static HRESULT WINAPI VMR7MonitorConfig_GetMonitor(IVMRMonitorConfig *iface, VMRGUID *pGUID)
1391 {
1392     struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface);
1393 
1394     FIXME("(%p/%p)->(%p) stub\n", iface, This, pGUID);
1395 
1396     if (!pGUID)
1397         return E_POINTER;
1398 
1399     pGUID->pGUID = NULL; /* default DirectDraw device */
1400     return S_OK;
1401 }
1402 
1403 static HRESULT WINAPI VMR7MonitorConfig_SetDefaultMonitor(IVMRMonitorConfig *iface,
1404                                                           const VMRGUID *pGUID)
1405 {
1406     struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface);
1407 
1408     FIXME("(%p/%p)->(%p) stub\n", iface, This, pGUID);
1409 
1410     if (!pGUID)
1411         return E_POINTER;
1412 
1413     return S_OK;
1414 }
1415 
1416 static HRESULT WINAPI VMR7MonitorConfig_GetDefaultMonitor(IVMRMonitorConfig *iface, VMRGUID *pGUID)
1417 {
1418     struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface);
1419 
1420     FIXME("(%p/%p)->(%p) stub\n", iface, This, pGUID);
1421 
1422     if (!pGUID)
1423         return E_POINTER;
1424 
1425     pGUID->pGUID = NULL; /* default DirectDraw device */
1426     return S_OK;
1427 }
1428 
1429 static HRESULT WINAPI VMR7MonitorConfig_GetAvailableMonitors(IVMRMonitorConfig *iface,
1430                                                              VMRMONITORINFO *info, DWORD arraysize,
1431                                                              DWORD *numdev)
1432 {
1433     struct quartz_vmr *This = impl_from_IVMRMonitorConfig(iface);
1434     struct get_available_monitors_args args;
1435 
1436     FIXME("(%p/%p)->(%p, %u, %p) semi-stub\n", iface, This, info, arraysize, numdev);
1437 
1438     if (!numdev)
1439         return E_POINTER;
1440 
1441     if (info && arraysize == 0)
1442         return E_INVALIDARG;
1443 
1444     args.info7      = info;
1445     args.info9      = NULL;
1446     args.arraysize  = arraysize;
1447     args.numdev     = 0;
1448     EnumDisplayMonitors(NULL, NULL, get_available_monitors_proc, (LPARAM)&args);
1449 
1450     *numdev = args.numdev;
1451     return S_OK;
1452 }
1453 
1454 static const IVMRMonitorConfigVtbl VMR7_MonitorConfig_Vtbl =
1455 {
1456     VMR7MonitorConfig_QueryInterface,
1457     VMR7MonitorConfig_AddRef,
1458     VMR7MonitorConfig_Release,
1459     VMR7MonitorConfig_SetMonitor,
1460     VMR7MonitorConfig_GetMonitor,
1461     VMR7MonitorConfig_SetDefaultMonitor,
1462     VMR7MonitorConfig_GetDefaultMonitor,
1463     VMR7MonitorConfig_GetAvailableMonitors
1464 };
1465 
1466 static HRESULT WINAPI VMR9MonitorConfig_QueryInterface(IVMRMonitorConfig9 *iface, REFIID riid,
1467                                                        LPVOID * ppv)
1468 {
1469     struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface);
1470     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
1471 }
1472 
1473 static ULONG WINAPI VMR9MonitorConfig_AddRef(IVMRMonitorConfig9 *iface)
1474 {
1475     struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface);
1476     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
1477 }
1478 
1479 static ULONG WINAPI VMR9MonitorConfig_Release(IVMRMonitorConfig9 *iface)
1480 {
1481     struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface);
1482     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
1483 }
1484 
1485 static HRESULT WINAPI VMR9MonitorConfig_SetMonitor(IVMRMonitorConfig9 *iface, UINT uDev)
1486 {
1487     struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface);
1488 
1489     FIXME("(%p/%p)->(%u) stub\n", iface, This, uDev);
1490 
1491     return S_OK;
1492 }
1493 
1494 static HRESULT WINAPI VMR9MonitorConfig_GetMonitor(IVMRMonitorConfig9 *iface, UINT *uDev)
1495 {
1496     struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface);
1497 
1498     FIXME("(%p/%p)->(%p) stub\n", iface, This, uDev);
1499 
1500     if (!uDev)
1501         return E_POINTER;
1502 
1503     *uDev = 0;
1504     return S_OK;
1505 }
1506 
1507 static HRESULT WINAPI VMR9MonitorConfig_SetDefaultMonitor(IVMRMonitorConfig9 *iface, UINT uDev)
1508 {
1509     struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface);
1510 
1511     FIXME("(%p/%p)->(%u) stub\n", iface, This, uDev);
1512 
1513     return S_OK;
1514 }
1515 
1516 static HRESULT WINAPI VMR9MonitorConfig_GetDefaultMonitor(IVMRMonitorConfig9 *iface, UINT *uDev)
1517 {
1518     struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface);
1519 
1520     FIXME("(%p/%p)->(%p) stub\n", iface, This, uDev);
1521 
1522     if (!uDev)
1523         return E_POINTER;
1524 
1525     *uDev = 0;
1526     return S_OK;
1527 }
1528 
1529 static HRESULT WINAPI VMR9MonitorConfig_GetAvailableMonitors(IVMRMonitorConfig9 *iface,
1530                                                              VMR9MonitorInfo *info, DWORD arraysize,
1531                                                              DWORD *numdev)
1532 {
1533     struct quartz_vmr *This = impl_from_IVMRMonitorConfig9(iface);
1534     struct get_available_monitors_args args;
1535 
1536     FIXME("(%p/%p)->(%p, %u, %p) semi-stub\n", iface, This, info, arraysize, numdev);
1537 
1538     if (!numdev)
1539         return E_POINTER;
1540 
1541     if (info && arraysize == 0)
1542         return E_INVALIDARG;
1543 
1544     args.info7      = NULL;
1545     args.info9      = info;
1546     args.arraysize  = arraysize;
1547     args.numdev     = 0;
1548     EnumDisplayMonitors(NULL, NULL, get_available_monitors_proc, (LPARAM)&args);
1549 
1550     *numdev = args.numdev;
1551     return S_OK;
1552 }
1553 
1554 static const IVMRMonitorConfig9Vtbl VMR9_MonitorConfig_Vtbl =
1555 {
1556     VMR9MonitorConfig_QueryInterface,
1557     VMR9MonitorConfig_AddRef,
1558     VMR9MonitorConfig_Release,
1559     VMR9MonitorConfig_SetMonitor,
1560     VMR9MonitorConfig_GetMonitor,
1561     VMR9MonitorConfig_SetDefaultMonitor,
1562     VMR9MonitorConfig_GetDefaultMonitor,
1563     VMR9MonitorConfig_GetAvailableMonitors
1564 };
1565 
1566 static HRESULT WINAPI VMR9FilterConfig_QueryInterface(IVMRFilterConfig9 *iface, REFIID riid, LPVOID * ppv)
1567 {
1568     struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface);
1569     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
1570 }
1571 
1572 static ULONG WINAPI VMR9FilterConfig_AddRef(IVMRFilterConfig9 *iface)
1573 {
1574     struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface);
1575     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
1576 }
1577 
1578 static ULONG WINAPI VMR9FilterConfig_Release(IVMRFilterConfig9 *iface)
1579 {
1580     struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface);
1581     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
1582 }
1583 
1584 static HRESULT WINAPI VMR9FilterConfig_SetImageCompositor(IVMRFilterConfig9 *iface, IVMRImageCompositor9 *compositor)
1585 {
1586     struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface);
1587 
1588     FIXME("(%p/%p)->(%p) stub\n", iface, This, compositor);
1589     return E_NOTIMPL;
1590 }
1591 
1592 static HRESULT WINAPI VMR9FilterConfig_SetNumberOfStreams(IVMRFilterConfig9 *iface, DWORD max)
1593 {
1594     struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface);
1595 
1596     FIXME("(%p/%p)->(%u) stub\n", iface, This, max);
1597     return E_NOTIMPL;
1598 }
1599 
1600 static HRESULT WINAPI VMR9FilterConfig_GetNumberOfStreams(IVMRFilterConfig9 *iface, DWORD *max)
1601 {
1602     struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface);
1603 
1604     FIXME("(%p/%p)->(%p) stub\n", iface, This, max);
1605     return E_NOTIMPL;
1606 }
1607 
1608 static HRESULT WINAPI VMR9FilterConfig_SetRenderingPrefs(IVMRFilterConfig9 *iface, DWORD renderflags)
1609 {
1610     struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface);
1611 
1612     FIXME("(%p/%p)->(%u) stub\n", iface, This, renderflags);
1613     return E_NOTIMPL;
1614 }
1615 
1616 static HRESULT WINAPI VMR9FilterConfig_GetRenderingPrefs(IVMRFilterConfig9 *iface, DWORD *renderflags)
1617 {
1618     struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface);
1619 
1620     FIXME("(%p/%p)->(%p) stub\n", iface, This, renderflags);
1621     return E_NOTIMPL;
1622 }
1623 
1624 static HRESULT WINAPI VMR9FilterConfig_SetRenderingMode(IVMRFilterConfig9 *iface, DWORD mode)
1625 {
1626     HRESULT hr = S_OK;
1627     struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface);
1628 
1629     TRACE("(%p/%p)->(%u)\n", iface, This, mode);
1630 
1631     EnterCriticalSection(&This->renderer.filter.csFilter);
1632     if (This->mode)
1633     {
1634         LeaveCriticalSection(&This->renderer.filter.csFilter);
1635         return VFW_E_WRONG_STATE;
1636     }
1637 
1638     if (This->allocator)
1639         IVMRSurfaceAllocatorEx9_Release(This->allocator);
1640     if (This->presenter)
1641         IVMRImagePresenter9_Release(This->presenter);
1642 
1643     This->allocator = NULL;
1644     This->presenter = NULL;
1645 
1646     switch (mode)
1647     {
1648     case VMR9Mode_Windowed:
1649     case VMR9Mode_Windowless:
1650         This->allocator_is_ex = 0;
1651         This->cookie = ~0;
1652 
1653         hr = VMR9DefaultAllocatorPresenterImpl_create(This, (LPVOID*)&This->presenter);
1654         if (SUCCEEDED(hr))
1655             hr = IVMRImagePresenter9_QueryInterface(This->presenter, &IID_IVMRSurfaceAllocatorEx9, (LPVOID*)&This->allocator);
1656         if (FAILED(hr))
1657         {
1658             ERR("Unable to find Presenter interface\n");
1659             IVMRImagePresenter9_Release(This->presenter);
1660             This->allocator = NULL;
1661             This->presenter = NULL;
1662         }
1663         else
1664             hr = IVMRSurfaceAllocatorEx9_AdviseNotify(This->allocator, &This->IVMRSurfaceAllocatorNotify9_iface);
1665         break;
1666     case VMR9Mode_Renderless:
1667         break;
1668     default:
1669         LeaveCriticalSection(&This->renderer.filter.csFilter);
1670         return E_INVALIDARG;
1671     }
1672 
1673     This->mode = mode;
1674     LeaveCriticalSection(&This->renderer.filter.csFilter);
1675     return hr;
1676 }
1677 
1678 static HRESULT WINAPI VMR9FilterConfig_GetRenderingMode(IVMRFilterConfig9 *iface, DWORD *mode)
1679 {
1680     struct quartz_vmr *This = impl_from_IVMRFilterConfig9(iface);
1681 
1682     TRACE("(%p/%p)->(%p)\n", iface, This, mode);
1683     if (!mode)
1684         return E_POINTER;
1685 
1686     if (This->mode)
1687         *mode = This->mode;
1688     else
1689         *mode = VMR9Mode_Windowed;
1690 
1691     return S_OK;
1692 }
1693 
1694 static const IVMRFilterConfig9Vtbl VMR9_FilterConfig_Vtbl =
1695 {
1696     VMR9FilterConfig_QueryInterface,
1697     VMR9FilterConfig_AddRef,
1698     VMR9FilterConfig_Release,
1699     VMR9FilterConfig_SetImageCompositor,
1700     VMR9FilterConfig_SetNumberOfStreams,
1701     VMR9FilterConfig_GetNumberOfStreams,
1702     VMR9FilterConfig_SetRenderingPrefs,
1703     VMR9FilterConfig_GetRenderingPrefs,
1704     VMR9FilterConfig_SetRenderingMode,
1705     VMR9FilterConfig_GetRenderingMode
1706 };
1707 
1708 static HRESULT WINAPI VMR7WindowlessControl_QueryInterface(IVMRWindowlessControl *iface, REFIID riid,
1709                                                            LPVOID * ppv)
1710 {
1711     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1712     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
1713 }
1714 
1715 static ULONG WINAPI VMR7WindowlessControl_AddRef(IVMRWindowlessControl *iface)
1716 {
1717     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1718     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
1719 }
1720 
1721 static ULONG WINAPI VMR7WindowlessControl_Release(IVMRWindowlessControl *iface)
1722 {
1723     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1724     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
1725 }
1726 
1727 static HRESULT WINAPI VMR7WindowlessControl_GetNativeVideoSize(IVMRWindowlessControl *iface,
1728                                                                LONG *width, LONG *height,
1729                                                                LONG *arwidth, LONG *arheight)
1730 {
1731     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1732     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", iface, This, width, height, arwidth, arheight);
1733 
1734     if (!width || !height || !arwidth || !arheight)
1735     {
1736         ERR("Got no pointer\n");
1737         return E_POINTER;
1738     }
1739 
1740     *width = This->bmiheader.biWidth;
1741     *height = This->bmiheader.biHeight;
1742     *arwidth = This->bmiheader.biWidth;
1743     *arheight = This->bmiheader.biHeight;
1744 
1745     return S_OK;
1746 }
1747 
1748 static HRESULT WINAPI VMR7WindowlessControl_GetMinIdealVideoSize(IVMRWindowlessControl *iface,
1749                                                                  LONG *width, LONG *height)
1750 {
1751     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1752 
1753     FIXME("(%p/%p)->(...) stub\n", iface, This);
1754     return E_NOTIMPL;
1755 }
1756 
1757 static HRESULT WINAPI VMR7WindowlessControl_GetMaxIdealVideoSize(IVMRWindowlessControl *iface,
1758                                                                  LONG *width, LONG *height)
1759 {
1760     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1761 
1762     FIXME("(%p/%p)->(...) stub\n", iface, This);
1763     return E_NOTIMPL;
1764 }
1765 
1766 static HRESULT WINAPI VMR7WindowlessControl_SetVideoPosition(IVMRWindowlessControl *iface,
1767                                                              const RECT *source, const RECT *dest)
1768 {
1769     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1770 
1771     TRACE("(%p/%p)->(%p, %p)\n", iface, This, source, dest);
1772 
1773     EnterCriticalSection(&This->renderer.filter.csFilter);
1774 
1775     if (source)
1776         This->source_rect = *source;
1777     if (dest)
1778     {
1779         This->target_rect = *dest;
1780         if (This->baseControlWindow.baseWindow.hWnd)
1781         {
1782             FIXME("Output rectangle: %s\n", wine_dbgstr_rect(dest));
1783             SetWindowPos(This->baseControlWindow.baseWindow.hWnd, NULL,
1784                          dest->left, dest->top, dest->right - dest->left, dest->bottom-dest->top,
1785                          SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOOWNERZORDER|SWP_NOREDRAW);
1786         }
1787     }
1788 
1789     LeaveCriticalSection(&This->renderer.filter.csFilter);
1790 
1791     return S_OK;
1792 }
1793 
1794 static HRESULT WINAPI VMR7WindowlessControl_GetVideoPosition(IVMRWindowlessControl *iface,
1795                                                              RECT *source, RECT *dest)
1796 {
1797     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1798 
1799     if (source)
1800         *source = This->source_rect;
1801 
1802     if (dest)
1803         *dest = This->target_rect;
1804 
1805     FIXME("(%p/%p)->(%p/%p) stub\n", iface, This, source, dest);
1806     return S_OK;
1807 }
1808 
1809 static HRESULT WINAPI VMR7WindowlessControl_GetAspectRatioMode(IVMRWindowlessControl *iface,
1810                                                                DWORD *mode)
1811 {
1812     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1813 
1814     FIXME("(%p/%p)->(...) stub\n", iface, This);
1815     return E_NOTIMPL;
1816 }
1817 
1818 static HRESULT WINAPI VMR7WindowlessControl_SetAspectRatioMode(IVMRWindowlessControl *iface,
1819                                                                DWORD mode)
1820 {
1821     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1822 
1823     FIXME("(%p/%p)->(...) stub\n", iface, This);
1824     return E_NOTIMPL;
1825 }
1826 
1827 static HRESULT WINAPI VMR7WindowlessControl_SetVideoClippingWindow(IVMRWindowlessControl *iface,
1828                                                                    HWND hwnd)
1829 {
1830     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1831 
1832     FIXME("(%p/%p)->(...) stub\n", iface, This);
1833     return E_NOTIMPL;
1834 }
1835 
1836 static HRESULT WINAPI VMR7WindowlessControl_RepaintVideo(IVMRWindowlessControl *iface,
1837                                                          HWND hwnd, HDC hdc)
1838 {
1839     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1840 
1841     FIXME("(%p/%p)->(...) stub\n", iface, This);
1842     return E_NOTIMPL;
1843 }
1844 
1845 static HRESULT WINAPI VMR7WindowlessControl_DisplayModeChanged(IVMRWindowlessControl *iface)
1846 {
1847     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1848 
1849     FIXME("(%p/%p)->(...) stub\n", iface, This);
1850     return E_NOTIMPL;
1851 }
1852 
1853 static HRESULT WINAPI VMR7WindowlessControl_GetCurrentImage(IVMRWindowlessControl *iface,
1854                                                             BYTE **dib)
1855 {
1856     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1857 
1858     FIXME("(%p/%p)->(...) stub\n", iface, This);
1859     return E_NOTIMPL;
1860 }
1861 
1862 static HRESULT WINAPI VMR7WindowlessControl_SetBorderColor(IVMRWindowlessControl *iface,
1863                                                            COLORREF color)
1864 {
1865     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1866 
1867     FIXME("(%p/%p)->(...) stub\n", iface, This);
1868     return E_NOTIMPL;
1869 }
1870 
1871 static HRESULT WINAPI VMR7WindowlessControl_GetBorderColor(IVMRWindowlessControl *iface,
1872                                                            COLORREF *color)
1873 {
1874     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1875 
1876     FIXME("(%p/%p)->(...) stub\n", iface, This);
1877     return E_NOTIMPL;
1878 }
1879 
1880 static HRESULT WINAPI VMR7WindowlessControl_SetColorKey(IVMRWindowlessControl *iface, COLORREF color)
1881 {
1882     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1883 
1884     FIXME("(%p/%p)->(...) stub\n", iface, This);
1885     return E_NOTIMPL;
1886 }
1887 
1888 static HRESULT WINAPI VMR7WindowlessControl_GetColorKey(IVMRWindowlessControl *iface, COLORREF *color)
1889 {
1890     struct quartz_vmr *This = impl_from_IVMRWindowlessControl(iface);
1891 
1892     FIXME("(%p/%p)->(...) stub\n", iface, This);
1893     return E_NOTIMPL;
1894 }
1895 
1896 static const IVMRWindowlessControlVtbl VMR7_WindowlessControl_Vtbl =
1897 {
1898     VMR7WindowlessControl_QueryInterface,
1899     VMR7WindowlessControl_AddRef,
1900     VMR7WindowlessControl_Release,
1901     VMR7WindowlessControl_GetNativeVideoSize,
1902     VMR7WindowlessControl_GetMinIdealVideoSize,
1903     VMR7WindowlessControl_GetMaxIdealVideoSize,
1904     VMR7WindowlessControl_SetVideoPosition,
1905     VMR7WindowlessControl_GetVideoPosition,
1906     VMR7WindowlessControl_GetAspectRatioMode,
1907     VMR7WindowlessControl_SetAspectRatioMode,
1908     VMR7WindowlessControl_SetVideoClippingWindow,
1909     VMR7WindowlessControl_RepaintVideo,
1910     VMR7WindowlessControl_DisplayModeChanged,
1911     VMR7WindowlessControl_GetCurrentImage,
1912     VMR7WindowlessControl_SetBorderColor,
1913     VMR7WindowlessControl_GetBorderColor,
1914     VMR7WindowlessControl_SetColorKey,
1915     VMR7WindowlessControl_GetColorKey
1916 };
1917 
1918 static HRESULT WINAPI VMR9WindowlessControl_QueryInterface(IVMRWindowlessControl9 *iface, REFIID riid, LPVOID * ppv)
1919 {
1920     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
1921     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
1922 }
1923 
1924 static ULONG WINAPI VMR9WindowlessControl_AddRef(IVMRWindowlessControl9 *iface)
1925 {
1926     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
1927     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
1928 }
1929 
1930 static ULONG WINAPI VMR9WindowlessControl_Release(IVMRWindowlessControl9 *iface)
1931 {
1932     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
1933     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
1934 }
1935 
1936 static HRESULT WINAPI VMR9WindowlessControl_GetNativeVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height, LONG *arwidth, LONG *arheight)
1937 {
1938     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
1939     TRACE("(%p/%p)->(%p, %p, %p, %p)\n", iface, This, width, height, arwidth, arheight);
1940 
1941     if (!width || !height || !arwidth || !arheight)
1942     {
1943         ERR("Got no pointer\n");
1944         return E_POINTER;
1945     }
1946 
1947     *width = This->bmiheader.biWidth;
1948     *height = This->bmiheader.biHeight;
1949     *arwidth = This->bmiheader.biWidth;
1950     *arheight = This->bmiheader.biHeight;
1951 
1952     return S_OK;
1953 }
1954 
1955 static HRESULT WINAPI VMR9WindowlessControl_GetMinIdealVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height)
1956 {
1957     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
1958 
1959     FIXME("(%p/%p)->(...) stub\n", iface, This);
1960     return E_NOTIMPL;
1961 }
1962 
1963 static HRESULT WINAPI VMR9WindowlessControl_GetMaxIdealVideoSize(IVMRWindowlessControl9 *iface, LONG *width, LONG *height)
1964 {
1965     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
1966 
1967     FIXME("(%p/%p)->(...) stub\n", iface, This);
1968     return E_NOTIMPL;
1969 }
1970 
1971 static HRESULT WINAPI VMR9WindowlessControl_SetVideoPosition(IVMRWindowlessControl9 *iface, const RECT *source, const RECT *dest)
1972 {
1973     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
1974 
1975     TRACE("(%p/%p)->(%p, %p)\n", iface, This, source, dest);
1976 
1977     EnterCriticalSection(&This->renderer.filter.csFilter);
1978 
1979     if (source)
1980         This->source_rect = *source;
1981     if (dest)
1982     {
1983         This->target_rect = *dest;
1984         if (This->baseControlWindow.baseWindow.hWnd)
1985         {
1986             FIXME("Output rectangle: %s\n", wine_dbgstr_rect(dest));
1987             SetWindowPos(This->baseControlWindow.baseWindow.hWnd, NULL, dest->left, dest->top, dest->right - dest->left,
1988                          dest->bottom-dest->top, SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOOWNERZORDER|SWP_NOREDRAW);
1989         }
1990     }
1991 
1992     LeaveCriticalSection(&This->renderer.filter.csFilter);
1993 
1994     return S_OK;
1995 }
1996 
1997 static HRESULT WINAPI VMR9WindowlessControl_GetVideoPosition(IVMRWindowlessControl9 *iface, RECT *source, RECT *dest)
1998 {
1999     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
2000 
2001     if (source)
2002         *source = This->source_rect;
2003 
2004     if (dest)
2005         *dest = This->target_rect;
2006 
2007     FIXME("(%p/%p)->(%p/%p) stub\n", iface, This, source, dest);
2008     return S_OK;
2009 }
2010 
2011 static HRESULT WINAPI VMR9WindowlessControl_GetAspectRatioMode(IVMRWindowlessControl9 *iface, DWORD *mode)
2012 {
2013     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
2014 
2015     FIXME("(%p/%p)->(...) stub\n", iface, This);
2016     return E_NOTIMPL;
2017 }
2018 
2019 static HRESULT WINAPI VMR9WindowlessControl_SetAspectRatioMode(IVMRWindowlessControl9 *iface, DWORD mode)
2020 {
2021     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
2022 
2023     FIXME("(%p/%p)->(...) stub\n", iface, This);
2024     return E_NOTIMPL;
2025 }
2026 
2027 static HRESULT WINAPI VMR9WindowlessControl_SetVideoClippingWindow(IVMRWindowlessControl9 *iface, HWND hwnd)
2028 {
2029     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
2030 
2031     TRACE("(%p/%p)->(%p)\n", iface, This, hwnd);
2032 
2033     EnterCriticalSection(&This->renderer.filter.csFilter);
2034     This->hWndClippingWindow = hwnd;
2035     VMR9_maybe_init(This, FALSE);
2036     if (!hwnd)
2037         IVMRSurfaceAllocatorEx9_TerminateDevice(This->allocator, This->cookie);
2038     LeaveCriticalSection(&This->renderer.filter.csFilter);
2039     return S_OK;
2040 }
2041 
2042 static HRESULT WINAPI VMR9WindowlessControl_RepaintVideo(IVMRWindowlessControl9 *iface, HWND hwnd, HDC hdc)
2043 {
2044     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
2045     HRESULT hr;
2046 
2047     FIXME("(%p/%p)->(...) semi-stub\n", iface, This);
2048 
2049     EnterCriticalSection(&This->renderer.filter.csFilter);
2050     if (hwnd != This->hWndClippingWindow && hwnd != This->baseControlWindow.baseWindow.hWnd)
2051     {
2052         ERR("Not handling changing windows yet!!!\n");
2053         LeaveCriticalSection(&This->renderer.filter.csFilter);
2054         return S_OK;
2055     }
2056 
2057     if (!This->allocator_d3d9_dev)
2058     {
2059         ERR("No d3d9 device!\n");
2060         LeaveCriticalSection(&This->renderer.filter.csFilter);
2061         return VFW_E_WRONG_STATE;
2062     }
2063 
2064     /* Windowless extension */
2065     hr = IDirect3DDevice9_Present(This->allocator_d3d9_dev, NULL, NULL, This->baseControlWindow.baseWindow.hWnd, NULL);
2066     LeaveCriticalSection(&This->renderer.filter.csFilter);
2067 
2068     return hr;
2069 }
2070 
2071 static HRESULT WINAPI VMR9WindowlessControl_DisplayModeChanged(IVMRWindowlessControl9 *iface)
2072 {
2073     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
2074 
2075     FIXME("(%p/%p)->(...) stub\n", iface, This);
2076     return E_NOTIMPL;
2077 }
2078 
2079 static HRESULT WINAPI VMR9WindowlessControl_GetCurrentImage(IVMRWindowlessControl9 *iface, BYTE **dib)
2080 {
2081     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
2082 
2083     FIXME("(%p/%p)->(...) stub\n", iface, This);
2084     return E_NOTIMPL;
2085 }
2086 
2087 static HRESULT WINAPI VMR9WindowlessControl_SetBorderColor(IVMRWindowlessControl9 *iface, COLORREF color)
2088 {
2089     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
2090 
2091     FIXME("(%p/%p)->(...) stub\n", iface, This);
2092     return E_NOTIMPL;
2093 }
2094 
2095 static HRESULT WINAPI VMR9WindowlessControl_GetBorderColor(IVMRWindowlessControl9 *iface, COLORREF *color)
2096 {
2097     struct quartz_vmr *This = impl_from_IVMRWindowlessControl9(iface);
2098 
2099     FIXME("(%p/%p)->(...) stub\n", iface, This);
2100     return E_NOTIMPL;
2101 }
2102 
2103 static const IVMRWindowlessControl9Vtbl VMR9_WindowlessControl_Vtbl =
2104 {
2105     VMR9WindowlessControl_QueryInterface,
2106     VMR9WindowlessControl_AddRef,
2107     VMR9WindowlessControl_Release,
2108     VMR9WindowlessControl_GetNativeVideoSize,
2109     VMR9WindowlessControl_GetMinIdealVideoSize,
2110     VMR9WindowlessControl_GetMaxIdealVideoSize,
2111     VMR9WindowlessControl_SetVideoPosition,
2112     VMR9WindowlessControl_GetVideoPosition,
2113     VMR9WindowlessControl_GetAspectRatioMode,
2114     VMR9WindowlessControl_SetAspectRatioMode,
2115     VMR9WindowlessControl_SetVideoClippingWindow,
2116     VMR9WindowlessControl_RepaintVideo,
2117     VMR9WindowlessControl_DisplayModeChanged,
2118     VMR9WindowlessControl_GetCurrentImage,
2119     VMR9WindowlessControl_SetBorderColor,
2120     VMR9WindowlessControl_GetBorderColor
2121 };
2122 
2123 static HRESULT WINAPI VMR7SurfaceAllocatorNotify_QueryInterface(IVMRSurfaceAllocatorNotify *iface,
2124                                                                 REFIID riid, LPVOID * ppv)
2125 {
2126     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface);
2127     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
2128 }
2129 
2130 static ULONG WINAPI VMR7SurfaceAllocatorNotify_AddRef(IVMRSurfaceAllocatorNotify *iface)
2131 {
2132     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface);
2133     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
2134 }
2135 
2136 static ULONG WINAPI VMR7SurfaceAllocatorNotify_Release(IVMRSurfaceAllocatorNotify *iface)
2137 {
2138     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface);
2139     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
2140 }
2141 
2142 static HRESULT WINAPI VMR7SurfaceAllocatorNotify_AdviseSurfaceAllocator(IVMRSurfaceAllocatorNotify *iface,
2143                                                                         DWORD_PTR id,
2144                                                                         IVMRSurfaceAllocator *alloc)
2145 {
2146     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface);
2147 
2148     FIXME("(%p/%p)->(...) stub\n", iface, This);
2149     return E_NOTIMPL;
2150 }
2151 
2152 static HRESULT WINAPI VMR7SurfaceAllocatorNotify_SetDDrawDevice(IVMRSurfaceAllocatorNotify *iface,
2153                                                                 IDirectDraw7 *device, HMONITOR monitor)
2154 {
2155     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface);
2156 
2157     FIXME("(%p/%p)->(...) stub\n", iface, This);
2158     return E_NOTIMPL;
2159 }
2160 
2161 static HRESULT WINAPI VMR7SurfaceAllocatorNotify_ChangeDDrawDevice(IVMRSurfaceAllocatorNotify *iface,
2162                                                                    IDirectDraw7 *device, HMONITOR monitor)
2163 {
2164     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface);
2165 
2166     FIXME("(%p/%p)->(...) stub\n", iface, This);
2167     return E_NOTIMPL;
2168 }
2169 
2170 static HRESULT WINAPI VMR7SurfaceAllocatorNotify_RestoreDDrawSurfaces(IVMRSurfaceAllocatorNotify *iface)
2171 {
2172     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface);
2173 
2174     FIXME("(%p/%p)->(...) stub\n", iface, This);
2175     return E_NOTIMPL;
2176 }
2177 
2178 static HRESULT WINAPI VMR7SurfaceAllocatorNotify_NotifyEvent(IVMRSurfaceAllocatorNotify *iface, LONG code,
2179                                                              LONG_PTR param1, LONG_PTR param2)
2180 {
2181     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface);
2182 
2183     FIXME("(%p/%p)->(...) stub\n", iface, This);
2184     return E_NOTIMPL;
2185 }
2186 
2187 static HRESULT WINAPI VMR7SurfaceAllocatorNotify_SetBorderColor(IVMRSurfaceAllocatorNotify *iface,
2188                                                                 COLORREF clrBorder)
2189 {
2190     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify(iface);
2191 
2192     FIXME("(%p/%p)->(...) stub\n", iface, This);
2193     return E_NOTIMPL;
2194 }
2195 
2196 static const IVMRSurfaceAllocatorNotifyVtbl VMR7_SurfaceAllocatorNotify_Vtbl =
2197 {
2198     VMR7SurfaceAllocatorNotify_QueryInterface,
2199     VMR7SurfaceAllocatorNotify_AddRef,
2200     VMR7SurfaceAllocatorNotify_Release,
2201     VMR7SurfaceAllocatorNotify_AdviseSurfaceAllocator,
2202     VMR7SurfaceAllocatorNotify_SetDDrawDevice,
2203     VMR7SurfaceAllocatorNotify_ChangeDDrawDevice,
2204     VMR7SurfaceAllocatorNotify_RestoreDDrawSurfaces,
2205     VMR7SurfaceAllocatorNotify_NotifyEvent,
2206     VMR7SurfaceAllocatorNotify_SetBorderColor
2207 };
2208 
2209 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_QueryInterface(IVMRSurfaceAllocatorNotify9 *iface, REFIID riid, LPVOID * ppv)
2210 {
2211     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
2212     return VMR9_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
2213 }
2214 
2215 static ULONG WINAPI VMR9SurfaceAllocatorNotify_AddRef(IVMRSurfaceAllocatorNotify9 *iface)
2216 {
2217     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
2218     return VMR9_AddRef(&This->renderer.filter.IBaseFilter_iface);
2219 }
2220 
2221 static ULONG WINAPI VMR9SurfaceAllocatorNotify_Release(IVMRSurfaceAllocatorNotify9 *iface)
2222 {
2223     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
2224     return VMR9_Release(&This->renderer.filter.IBaseFilter_iface);
2225 }
2226 
2227 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AdviseSurfaceAllocator(IVMRSurfaceAllocatorNotify9 *iface, DWORD_PTR id, IVMRSurfaceAllocator9 *alloc)
2228 {
2229     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
2230 
2231     /* FIXME: This code is not tested!!! */
2232     FIXME("(%p/%p)->(...) stub\n", iface, This);
2233     This->cookie = id;
2234 
2235     if (This->presenter)
2236         return VFW_E_WRONG_STATE;
2237 
2238     if (FAILED(IVMRSurfaceAllocator9_QueryInterface(alloc, &IID_IVMRImagePresenter9, (void **)&This->presenter)))
2239         return E_NOINTERFACE;
2240 
2241     if (SUCCEEDED(IVMRSurfaceAllocator9_QueryInterface(alloc, &IID_IVMRSurfaceAllocatorEx9, (void **)&This->allocator)))
2242         This->allocator_is_ex = 1;
2243     else
2244     {
2245         This->allocator = (IVMRSurfaceAllocatorEx9 *)alloc;
2246         IVMRSurfaceAllocator9_AddRef(alloc);
2247         This->allocator_is_ex = 0;
2248     }
2249 
2250     return S_OK;
2251 }
2252 
2253 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_SetD3DDevice(IVMRSurfaceAllocatorNotify9 *iface, IDirect3DDevice9 *device, HMONITOR monitor)
2254 {
2255     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
2256 
2257     FIXME("(%p/%p)->(...) semi-stub\n", iface, This);
2258     if (This->allocator_d3d9_dev)
2259         IDirect3DDevice9_Release(This->allocator_d3d9_dev);
2260     This->allocator_d3d9_dev = device;
2261     IDirect3DDevice9_AddRef(This->allocator_d3d9_dev);
2262     This->allocator_mon = monitor;
2263 
2264     return S_OK;
2265 }
2266 
2267 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_ChangeD3DDevice(IVMRSurfaceAllocatorNotify9 *iface, IDirect3DDevice9 *device, HMONITOR monitor)
2268 {
2269     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
2270 
2271     FIXME("(%p/%p)->(...) semi-stub\n", iface, This);
2272     if (This->allocator_d3d9_dev)
2273         IDirect3DDevice9_Release(This->allocator_d3d9_dev);
2274     This->allocator_d3d9_dev = device;
2275     IDirect3DDevice9_AddRef(This->allocator_d3d9_dev);
2276     This->allocator_mon = monitor;
2277 
2278     return S_OK;
2279 }
2280 
2281 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_AllocateSurfaceHelper(IVMRSurfaceAllocatorNotify9 *iface, VMR9AllocationInfo *allocinfo, DWORD *numbuffers, IDirect3DSurface9 **surface)
2282 {
2283     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
2284     DWORD i;
2285     HRESULT hr = S_OK;
2286 
2287     FIXME("(%p/%p)->(%p, %p => %u, %p) semi-stub\n", iface, This, allocinfo, numbuffers, (numbuffers ? *numbuffers : 0), surface);
2288 
2289     if (!allocinfo || !numbuffers || !surface)
2290         return E_POINTER;
2291 
2292     if (!*numbuffers || *numbuffers < allocinfo->MinBuffers)
2293     {
2294         ERR("Invalid number of buffers?\n");
2295         return E_INVALIDARG;
2296     }
2297 
2298     if (!This->allocator_d3d9_dev)
2299     {
2300         ERR("No direct3d device when requested to allocate a surface!\n");
2301         return VFW_E_WRONG_STATE;
2302     }
2303 
2304     if (allocinfo->dwFlags & VMR9AllocFlag_OffscreenSurface)
2305     {
2306         ERR("Creating offscreen surface\n");
2307         for (i = 0; i < *numbuffers; ++i)
2308         {
2309             hr = IDirect3DDevice9_CreateOffscreenPlainSurface(This->allocator_d3d9_dev,  allocinfo->dwWidth, allocinfo->dwHeight,
2310                                                              allocinfo->Format, allocinfo->Pool, &surface[i], NULL);
2311             if (FAILED(hr))
2312                 break;
2313         }
2314     }
2315     else if (allocinfo->dwFlags & VMR9AllocFlag_TextureSurface)
2316     {
2317         TRACE("Creating texture surface\n");
2318         for (i = 0; i < *numbuffers; ++i)
2319         {
2320             IDirect3DTexture9 *texture;
2321 
2322             hr = IDirect3DDevice9_CreateTexture(This->allocator_d3d9_dev, allocinfo->dwWidth, allocinfo->dwHeight, 1, 0,
2323                                                 allocinfo->Format, allocinfo->Pool, &texture, NULL);
2324             if (FAILED(hr))
2325                 break;
2326             IDirect3DTexture9_GetSurfaceLevel(texture, 0, &surface[i]);
2327             IDirect3DTexture9_Release(texture);
2328         }
2329     }
2330     else
2331     {
2332          FIXME("Could not allocate for type %08x\n", allocinfo->dwFlags);
2333          return E_NOTIMPL;
2334     }
2335 
2336     if (i >= allocinfo->MinBuffers)
2337     {
2338         hr = S_OK;
2339         *numbuffers = i;
2340     }
2341     else
2342     {
2343         for ( ; i > 0; --i) IDirect3DSurface9_Release(surface[i - 1]);
2344         *numbuffers = 0;
2345     }
2346     return hr;
2347 }
2348 
2349 static HRESULT WINAPI VMR9SurfaceAllocatorNotify_NotifyEvent(IVMRSurfaceAllocatorNotify9 *iface, LONG code, LONG_PTR param1, LONG_PTR param2)
2350 {
2351     struct quartz_vmr *This = impl_from_IVMRSurfaceAllocatorNotify9(iface);
2352 
2353     FIXME("(%p/%p)->(...) stub\n", iface, This);
2354     return E_NOTIMPL;
2355 }
2356 
2357 static const IVMRSurfaceAllocatorNotify9Vtbl VMR9_SurfaceAllocatorNotify_Vtbl =
2358 {
2359     VMR9SurfaceAllocatorNotify_QueryInterface,
2360     VMR9SurfaceAllocatorNotify_AddRef,
2361     VMR9SurfaceAllocatorNotify_Release,
2362     VMR9SurfaceAllocatorNotify_AdviseSurfaceAllocator,
2363     VMR9SurfaceAllocatorNotify_SetD3DDevice,
2364     VMR9SurfaceAllocatorNotify_ChangeD3DDevice,
2365     VMR9SurfaceAllocatorNotify_AllocateSurfaceHelper,
2366     VMR9SurfaceAllocatorNotify_NotifyEvent
2367 };
2368 
2369 static HRESULT vmr_create(IUnknown *outer_unk, LPVOID *ppv, const CLSID *clsid)
2370 {
2371     HRESULT hr;
2372     struct quartz_vmr* pVMR;
2373 
2374     TRACE("(%p, %p)\n", outer_unk, ppv);
2375 
2376     *ppv = NULL;
2377 
2378     pVMR = CoTaskMemAlloc(sizeof(struct quartz_vmr));
2379 
2380     pVMR->hD3d9 = LoadLibraryA("d3d9.dll");
2381     if (!pVMR->hD3d9 )
2382     {
2383         WARN("Could not load d3d9.dll\n");
2384         CoTaskMemFree(pVMR);
2385         return VFW_E_DDRAW_CAPS_NOT_SUITABLE;
2386     }
2387 
2388     pVMR->outer_unk = outer_unk;
2389     pVMR->bUnkOuterValid = FALSE;
2390     pVMR->bAggregatable = FALSE;
2391     pVMR->IUnknown_inner.lpVtbl = &IInner_VTable;
2392     pVMR->IAMCertifiedOutputProtection_iface.lpVtbl = &IAMCertifiedOutputProtection_Vtbl;
2393     pVMR->IAMFilterMiscFlags_iface.lpVtbl = &IAMFilterMiscFlags_Vtbl;
2394 
2395     pVMR->mode = 0;
2396     pVMR->allocator_d3d9_dev = NULL;
2397     pVMR->allocator_mon= NULL;
2398     pVMR->num_surfaces = pVMR->cur_surface = 0;
2399     pVMR->allocator = NULL;
2400     pVMR->presenter = NULL;
2401     pVMR->hWndClippingWindow = NULL;
2402     pVMR->IVMRFilterConfig_iface.lpVtbl = &VMR7_FilterConfig_Vtbl;
2403     pVMR->IVMRFilterConfig9_iface.lpVtbl = &VMR9_FilterConfig_Vtbl;
2404     pVMR->IVMRMonitorConfig_iface.lpVtbl = &VMR7_MonitorConfig_Vtbl;
2405     pVMR->IVMRMonitorConfig9_iface.lpVtbl = &VMR9_MonitorConfig_Vtbl;
2406     pVMR->IVMRSurfaceAllocatorNotify_iface.lpVtbl = &VMR7_SurfaceAllocatorNotify_Vtbl;
2407     pVMR->IVMRSurfaceAllocatorNotify9_iface.lpVtbl = &VMR9_SurfaceAllocatorNotify_Vtbl;
2408     pVMR->IVMRWindowlessControl_iface.lpVtbl = &VMR7_WindowlessControl_Vtbl;
2409     pVMR->IVMRWindowlessControl9_iface.lpVtbl = &VMR9_WindowlessControl_Vtbl;
2410 
2411     if (IsEqualGUID(clsid, &CLSID_VideoMixingRenderer))
2412         hr = BaseRenderer_Init(&pVMR->renderer, &VMR_Vtbl, outer_unk, &CLSID_VideoMixingRenderer,
2413                                (DWORD_PTR)(__FILE__ ": VMR7Impl.csFilter"), &BaseFuncTable);
2414     else
2415         hr = BaseRenderer_Init(&pVMR->renderer, &VMR_Vtbl, outer_unk, &CLSID_VideoMixingRenderer9,
2416                                (DWORD_PTR)(__FILE__ ": VMR9Impl.csFilter"), &BaseFuncTable);
2417 
2418     if (FAILED(hr))
2419         goto fail;
2420 
2421     hr = BaseControlWindow_Init(&pVMR->baseControlWindow, &IVideoWindow_VTable, &pVMR->renderer.filter,
2422                                 &pVMR->renderer.filter.csFilter, &pVMR->renderer.pInputPin->pin,
2423                                 &renderer_BaseWindowFuncTable);
2424     if (FAILED(hr))
2425         goto fail;
2426 
2427     hr = BaseControlVideo_Init(&pVMR->baseControlVideo, &IBasicVideo_VTable, &pVMR->renderer.filter,
2428                                &pVMR->renderer.filter.csFilter, &pVMR->renderer.pInputPin->pin,
2429                                &renderer_BaseControlVideoFuncTable);
2430     if (FAILED(hr))
2431         goto fail;
2432 
2433     *ppv = (LPVOID)pVMR;
2434     ZeroMemory(&pVMR->source_rect, sizeof(RECT));
2435     ZeroMemory(&pVMR->target_rect, sizeof(RECT));
2436     TRACE("Created at %p\n", pVMR);
2437     return hr;
2438 
2439 fail:
2440     BaseRendererImpl_Release(&pVMR->renderer.filter.IBaseFilter_iface);
2441     FreeLibrary(pVMR->hD3d9);
2442     CoTaskMemFree(pVMR);
2443     return hr;
2444 }
2445 
2446 HRESULT VMR7Impl_create(IUnknown *outer_unk, LPVOID *ppv)
2447 {
2448     return vmr_create(outer_unk, ppv, &CLSID_VideoMixingRenderer);
2449 }
2450 
2451 HRESULT VMR9Impl_create(IUnknown *outer_unk, LPVOID *ppv)
2452 {
2453     return vmr_create(outer_unk, ppv, &CLSID_VideoMixingRenderer9);
2454 }
2455 
2456 
2457 static HRESULT WINAPI VMR9_ImagePresenter_QueryInterface(IVMRImagePresenter9 *iface, REFIID riid, LPVOID * ppv)
2458 {
2459     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
2460     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
2461 
2462     *ppv = NULL;
2463 
2464     if (IsEqualIID(riid, &IID_IUnknown))
2465         *ppv = (LPVOID)&(This->IVMRImagePresenter9_iface);
2466     else if (IsEqualIID(riid, &IID_IVMRImagePresenter9))
2467         *ppv = &This->IVMRImagePresenter9_iface;
2468     else if (IsEqualIID(riid, &IID_IVMRSurfaceAllocatorEx9))
2469         *ppv = &This->IVMRSurfaceAllocatorEx9_iface;
2470 
2471     if (*ppv)
2472     {
2473         IUnknown_AddRef((IUnknown *)(*ppv));
2474         return S_OK;
2475     }
2476 
2477     FIXME("No interface for %s\n", debugstr_guid(riid));
2478 
2479     return E_NOINTERFACE;
2480 }
2481 
2482 static ULONG WINAPI VMR9_ImagePresenter_AddRef(IVMRImagePresenter9 *iface)
2483 {
2484     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
2485     ULONG refCount = InterlockedIncrement(&This->refCount);
2486 
2487     TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1);
2488 
2489     return refCount;
2490 }
2491 
2492 static ULONG WINAPI VMR9_ImagePresenter_Release(IVMRImagePresenter9 *iface)
2493 {
2494     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
2495     ULONG refCount = InterlockedDecrement(&This->refCount);
2496 
2497     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
2498 
2499     if (!refCount)
2500     {
2501         DWORD i;
2502         TRACE("Destroying\n");
2503         CloseHandle(This->ack);
2504         IDirect3D9_Release(This->d3d9_ptr);
2505 
2506         TRACE("Number of surfaces: %u\n", This->num_surfaces);
2507         for (i = 0; i < This->num_surfaces; ++i)
2508         {
2509             IDirect3DSurface9 *surface = This->d3d9_surfaces[i];
2510             TRACE("Releasing surface %p\n", surface);
2511             if (surface)
2512                 IDirect3DSurface9_Release(surface);
2513         }
2514 
2515         CoTaskMemFree(This->d3d9_surfaces);
2516         This->d3d9_surfaces = NULL;
2517         This->num_surfaces = 0;
2518         if (This->d3d9_vertex)
2519         {
2520             IDirect3DVertexBuffer9_Release(This->d3d9_vertex);
2521             This->d3d9_vertex = NULL;
2522         }
2523         CoTaskMemFree(This);
2524         return 0;
2525     }
2526     return refCount;
2527 }
2528 
2529 static HRESULT WINAPI VMR9_ImagePresenter_StartPresenting(IVMRImagePresenter9 *iface, DWORD_PTR id)
2530 {
2531     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
2532 
2533     TRACE("(%p/%p/%p)->(...) stub\n", iface, This,This->pVMR9);
2534     return S_OK;
2535 }
2536 
2537 static HRESULT WINAPI VMR9_ImagePresenter_StopPresenting(IVMRImagePresenter9 *iface, DWORD_PTR id)
2538 {
2539     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
2540 
2541     TRACE("(%p/%p/%p)->(...) stub\n", iface, This,This->pVMR9);
2542     return S_OK;
2543 }
2544 
2545 #define USED_FVF (D3DFVF_XYZRHW | D3DFVF_TEX1)
2546 struct VERTEX { float x, y, z, rhw, u, v; };
2547 
2548 static HRESULT VMR9_ImagePresenter_PresentTexture(VMR9DefaultAllocatorPresenterImpl *This, IDirect3DSurface9 *surface)
2549 {
2550     IDirect3DTexture9 *texture = NULL;
2551     HRESULT hr;
2552 
2553     hr = IDirect3DDevice9_SetFVF(This->d3d9_dev, USED_FVF);
2554     if (FAILED(hr))
2555     {
2556         FIXME("SetFVF: %08x\n", hr);
2557         return hr;
2558     }
2559 
2560     hr = IDirect3DDevice9_SetStreamSource(This->d3d9_dev, 0, This->d3d9_vertex, 0, sizeof(struct VERTEX));
2561     if (FAILED(hr))
2562     {
2563         FIXME("SetStreamSource: %08x\n", hr);
2564         return hr;
2565     }
2566 
2567     hr = IDirect3DSurface9_GetContainer(surface, &IID_IDirect3DTexture9, (void **) &texture);
2568     if (FAILED(hr))
2569     {
2570         FIXME("IDirect3DSurface9_GetContainer failed\n");
2571         return hr;
2572     }
2573     hr = IDirect3DDevice9_SetTexture(This->d3d9_dev, 0, (IDirect3DBaseTexture9 *)texture);
2574     IDirect3DTexture9_Release(texture);
2575     if (FAILED(hr))
2576     {
2577         FIXME("SetTexture: %08x\n", hr);
2578         return hr;
2579     }
2580 
2581     hr = IDirect3DDevice9_DrawPrimitive(This->d3d9_dev, D3DPT_TRIANGLESTRIP, 0, 2);
2582     if (FAILED(hr))
2583     {
2584         FIXME("DrawPrimitive: %08x\n", hr);
2585         return hr;
2586     }
2587 
2588     return S_OK;
2589 }
2590 
2591 static HRESULT VMR9_ImagePresenter_PresentOffscreenSurface(VMR9DefaultAllocatorPresenterImpl *This, IDirect3DSurface9 *surface)
2592 {
2593     HRESULT hr;
2594     IDirect3DSurface9 *target = NULL;
2595     RECT target_rect;
2596 
2597     hr = IDirect3DDevice9_GetBackBuffer(This->d3d9_dev, 0, 0, D3DBACKBUFFER_TYPE_MONO, &target);
2598     if (FAILED(hr))
2599     {
2600         ERR("IDirect3DDevice9_GetBackBuffer -- %08x\n", hr);
2601         return hr;
2602     }
2603 
2604     /* Move rect to origin and flip it */
2605     SetRect(&target_rect, 0, This->pVMR9->target_rect.bottom - This->pVMR9->target_rect.top,
2606             This->pVMR9->target_rect.right - This->pVMR9->target_rect.left, 0);
2607 
2608     hr = IDirect3DDevice9_StretchRect(This->d3d9_dev, surface, &This->pVMR9->source_rect, target, &target_rect, D3DTEXF_LINEAR);
2609     if (FAILED(hr))
2610         ERR("IDirect3DDevice9_StretchRect -- %08x\n", hr);
2611     IDirect3DSurface9_Release(target);
2612 
2613     return hr;
2614 }
2615 
2616 static HRESULT WINAPI VMR9_ImagePresenter_PresentImage(IVMRImagePresenter9 *iface, DWORD_PTR id, VMR9PresentationInfo *info)
2617 {
2618     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRImagePresenter9(iface);
2619     HRESULT hr;
2620     RECT output;
2621     BOOL render = FALSE;
2622 
2623     TRACE("(%p/%p/%p)->(...) stub\n", iface, This, This->pVMR9);
2624     GetWindowRect(This->pVMR9->baseControlWindow.baseWindow.hWnd, &output);
2625     TRACE("Output rectangle: %s\n", wine_dbgstr_rect(&output));
2626 
2627     /* This might happen if we don't have active focus (eg on a different virtual desktop) */
2628     if (!This->d3d9_dev)
2629         return S_OK;
2630 
2631     /* Display image here */
2632     hr = IDirect3DDevice9_Clear(This->d3d9_dev, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
2633     if (FAILED(hr))
2634         FIXME("hr: %08x\n", hr);
2635     hr = IDirect3DDevice9_BeginScene(This->d3d9_dev);
2636     if (SUCCEEDED(hr))
2637     {
2638         if (This->d3d9_vertex)
2639             hr = VMR9_ImagePresenter_PresentTexture(This, info->lpSurf);
2640         else
2641             hr = VMR9_ImagePresenter_PresentOffscreenSurface(This, info->lpSurf);
2642         render = SUCCEEDED(hr);
2643     }
2644     else
2645         FIXME("BeginScene: %08x\n", hr);
2646     hr = IDirect3DDevice9_EndScene(This->d3d9_dev);
2647     if (render && SUCCEEDED(hr))
2648     {
2649         hr = IDirect3DDevice9_Present(This->d3d9_dev, NULL, NULL, This->pVMR9->baseControlWindow.baseWindow.hWnd, NULL);
2650         if (FAILED(hr))
2651             FIXME("Presenting image: %08x\n", hr);
2652     }
2653 
2654     return S_OK;
2655 }
2656 
2657 static const IVMRImagePresenter9Vtbl VMR9_ImagePresenter =
2658 {
2659     VMR9_ImagePresenter_QueryInterface,
2660     VMR9_ImagePresenter_AddRef,
2661     VMR9_ImagePresenter_Release,
2662     VMR9_ImagePresenter_StartPresenting,
2663     VMR9_ImagePresenter_StopPresenting,
2664     VMR9_ImagePresenter_PresentImage
2665 };
2666 
2667 static HRESULT WINAPI VMR9_SurfaceAllocator_QueryInterface(IVMRSurfaceAllocatorEx9 *iface, REFIID riid, LPVOID * ppv)
2668 {
2669     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
2670 
2671     return VMR9_ImagePresenter_QueryInterface(&This->IVMRImagePresenter9_iface, riid, ppv);
2672 }
2673 
2674 static ULONG WINAPI VMR9_SurfaceAllocator_AddRef(IVMRSurfaceAllocatorEx9 *iface)
2675 {
2676     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
2677 
2678     return VMR9_ImagePresenter_AddRef(&This->IVMRImagePresenter9_iface);
2679 }
2680 
2681 static ULONG WINAPI VMR9_SurfaceAllocator_Release(IVMRSurfaceAllocatorEx9 *iface)
2682 {
2683     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
2684 
2685     return VMR9_ImagePresenter_Release(&This->IVMRImagePresenter9_iface);
2686 }
2687 
2688 static HRESULT VMR9_SurfaceAllocator_SetAllocationSettings(VMR9DefaultAllocatorPresenterImpl *This, VMR9AllocationInfo *allocinfo)
2689 {
2690     D3DCAPS9 caps;
2691     UINT width, height;
2692     HRESULT hr;
2693 
2694     if (!(allocinfo->dwFlags & VMR9AllocFlag_TextureSurface))
2695         /* Only needed for texture surfaces */
2696         return S_OK;
2697 
2698     hr = IDirect3DDevice9_GetDeviceCaps(This->d3d9_dev, &caps);
2699     if (FAILED(hr))
2700         return hr;
2701 
2702     if (!(caps.TextureCaps & D3DPTEXTURECAPS_POW2) || (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY))
2703     {
2704         width = allocinfo->dwWidth;
2705         height = allocinfo->dwHeight;
2706     }
2707     else
2708     {
2709         width = height = 1;
2710         while (width < allocinfo->dwWidth)
2711             width *= 2;
2712 
2713         while (height < allocinfo->dwHeight)
2714             height *= 2;
2715         FIXME("NPOW2 support missing, not using proper surfaces!\n");
2716     }
2717 
2718     if (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY)
2719     {
2720         if (height > width)
2721             width = height;
2722         else
2723             height = width;
2724         FIXME("Square texture support required..\n");
2725     }
2726 
2727     hr = IDirect3DDevice9_CreateVertexBuffer(This->d3d9_dev, 4 * sizeof(struct VERTEX), D3DUSAGE_WRITEONLY, USED_FVF, allocinfo->Pool, &This->d3d9_vertex, NULL);
2728     if (FAILED(hr))
2729     {
2730         ERR("Couldn't create vertex buffer: %08x\n", hr);
2731         return hr;
2732     }
2733 
2734     This->reset = TRUE;
2735     allocinfo->dwHeight = height;
2736     allocinfo->dwWidth = width;
2737 
2738     return hr;
2739 }
2740 
2741 static DWORD WINAPI MessageLoop(LPVOID lpParameter)
2742 {
2743     MSG msg;
2744     BOOL fGotMessage;
2745     VMR9DefaultAllocatorPresenterImpl *This = lpParameter;
2746 
2747     TRACE("Starting message loop\n");
2748 
2749     if (FAILED(BaseWindowImpl_PrepareWindow(&This->pVMR9->baseControlWindow.baseWindow)))
2750     {
2751         FIXME("Failed to prepare window\n");
2752         return FALSE;
2753     }
2754 
2755     SetEvent(This->ack);
2756     while ((fGotMessage = GetMessageW(&msg, NULL, 0, 0)) != 0 && fGotMessage != -1)
2757     {
2758         TranslateMessage(&msg);
2759         DispatchMessageW(&msg);
2760     }
2761 
2762     TRACE("End of message loop\n");
2763 
2764     return 0;
2765 }
2766 
2767 static UINT d3d9_adapter_from_hwnd(IDirect3D9 *d3d9, HWND hwnd, HMONITOR *mon_out)
2768 {
2769     UINT d3d9_adapter;
2770     HMONITOR mon;
2771 
2772     mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL);
2773     if (!mon)
2774         d3d9_adapter = 0;
2775     else
2776     {
2777         for (d3d9_adapter = 0; d3d9_adapter < IDirect3D9_GetAdapterCount(d3d9); ++d3d9_adapter)
2778         {
2779             if (mon == IDirect3D9_GetAdapterMonitor(d3d9, d3d9_adapter))
2780                 break;
2781         }
2782         if (d3d9_adapter >= IDirect3D9_GetAdapterCount(d3d9))
2783             d3d9_adapter = 0;
2784     }
2785     if (mon_out)
2786         *mon_out = mon;
2787     return d3d9_adapter;
2788 }
2789 
2790 static BOOL CreateRenderingWindow(VMR9DefaultAllocatorPresenterImpl *This, VMR9AllocationInfo *info, DWORD *numbuffers)
2791 {
2792     D3DPRESENT_PARAMETERS d3dpp;
2793     DWORD d3d9_adapter;
2794     HRESULT hr;
2795 
2796     TRACE("(%p)->()\n", This);
2797 
2798     This->hWndThread = CreateThread(NULL, 0, MessageLoop, This, 0, &This->tid);
2799     if (!This->hWndThread)
2800         return FALSE;
2801 
2802     WaitForSingleObject(This->ack, INFINITE);
2803 
2804     if (!This->pVMR9->baseControlWindow.baseWindow.hWnd) return FALSE;
2805 
2806     /* Obtain a monitor and d3d9 device */
2807     d3d9_adapter = d3d9_adapter_from_hwnd(This->d3d9_ptr, This->pVMR9->baseControlWindow.baseWindow.hWnd, &This->hMon);
2808 
2809     /* Now try to create the d3d9 device */
2810     ZeroMemory(&d3dpp, sizeof(d3dpp));
2811     d3dpp.Windowed = TRUE;
2812     d3dpp.hDeviceWindow = This->pVMR9->baseControlWindow.baseWindow.hWnd;
2813     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2814     d3dpp.BackBufferHeight = This->pVMR9->target_rect.bottom - This->pVMR9->target_rect.top;
2815     d3dpp.BackBufferWidth = This->pVMR9->target_rect.right - This->pVMR9->target_rect.left;
2816 
2817     hr = IDirect3D9_CreateDevice(This->d3d9_ptr, d3d9_adapter, D3DDEVTYPE_HAL, NULL, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &This->d3d9_dev);
2818     if (FAILED(hr))
2819     {
2820         ERR("Could not create device: %08x\n", hr);
2821         BaseWindowImpl_DoneWithWindow(&This->pVMR9->baseControlWindow.baseWindow);
2822         return FALSE;
2823     }
2824     IVMRSurfaceAllocatorNotify9_SetD3DDevice(This->SurfaceAllocatorNotify, This->d3d9_dev, This->hMon);
2825 
2826     This->d3d9_surfaces = CoTaskMemAlloc(*numbuffers * sizeof(IDirect3DSurface9 *));
2827     ZeroMemory(This->d3d9_surfaces, *numbuffers * sizeof(IDirect3DSurface9 *));
2828 
2829     hr = VMR9_SurfaceAllocator_SetAllocationSettings(This, info);
2830     if (FAILED(hr))
2831         ERR("Setting allocation settings failed: %08x\n", hr);
2832 
2833     if (SUCCEEDED(hr))
2834     {
2835         hr = IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(This->SurfaceAllocatorNotify, info, numbuffers, This->d3d9_surfaces);
2836         if (FAILED(hr))
2837             ERR("Allocating surfaces failed: %08x\n", hr);
2838     }
2839 
2840     if (FAILED(hr))
2841     {
2842         IVMRSurfaceAllocatorEx9_TerminateDevice(This->pVMR9->allocator, This->pVMR9->cookie);
2843         BaseWindowImpl_DoneWithWindow(&This->pVMR9->baseControlWindow.baseWindow);
2844         return FALSE;
2845     }
2846 
2847     This->num_surfaces = *numbuffers;
2848 
2849     return TRUE;
2850 }
2851 
2852 static HRESULT WINAPI VMR9_SurfaceAllocator_InitializeDevice(IVMRSurfaceAllocatorEx9 *iface, DWORD_PTR id, VMR9AllocationInfo *allocinfo, DWORD *numbuffers)
2853 {
2854     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
2855 
2856     if (This->pVMR9->mode != VMR9Mode_Windowed && !This->pVMR9->hWndClippingWindow)
2857     {
2858         ERR("No window set\n");
2859         return VFW_E_WRONG_STATE;
2860     }
2861 
2862     This->info = *allocinfo;
2863 
2864     if (!CreateRenderingWindow(This, allocinfo, numbuffers))
2865     {
2866         ERR("Failed to create rendering window, expect no output!\n");
2867         return VFW_E_WRONG_STATE;
2868     }
2869 
2870     return S_OK;
2871 }
2872 
2873 static HRESULT WINAPI VMR9_SurfaceAllocator_TerminateDevice(IVMRSurfaceAllocatorEx9 *iface, DWORD_PTR id)
2874 {
2875     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
2876 
2877     if (!This->pVMR9->baseControlWindow.baseWindow.hWnd)
2878     {
2879         return S_OK;
2880     }
2881 
2882     SendMessageW(This->pVMR9->baseControlWindow.baseWindow.hWnd, WM_CLOSE, 0, 0);
2883     PostThreadMessageW(This->tid, WM_QUIT, 0, 0);
2884     WaitForSingleObject(This->hWndThread, INFINITE);
2885     This->hWndThread = NULL;
2886     BaseWindowImpl_DoneWithWindow(&This->pVMR9->baseControlWindow.baseWindow);
2887 
2888     return S_OK;
2889 }
2890 
2891 /* Recreate all surfaces (If allocated as D3DPOOL_DEFAULT) and survive! */
2892 static HRESULT VMR9_SurfaceAllocator_UpdateDeviceReset(VMR9DefaultAllocatorPresenterImpl *This)
2893 {
2894     struct VERTEX t_vert[4];
2895     UINT width, height;
2896     unsigned int i;
2897     void *bits = NULL;
2898     D3DPRESENT_PARAMETERS d3dpp;
2899     HRESULT hr;
2900 
2901     if (!This->pVMR9->baseControlWindow.baseWindow.hWnd)
2902     {
2903         ERR("No window\n");
2904         return E_FAIL;
2905     }
2906 
2907     if (!This->d3d9_surfaces || !This->reset)
2908         return S_OK;
2909 
2910     This->reset = FALSE;
2911     TRACE("RESETTING\n");
2912     if (This->d3d9_vertex)
2913     {
2914         IDirect3DVertexBuffer9_Release(This->d3d9_vertex);
2915         This->d3d9_vertex = NULL;
2916     }
2917 
2918     for (i = 0; i < This->num_surfaces; ++i)
2919     {
2920         IDirect3DSurface9 *surface = This->d3d9_surfaces[i];
2921         TRACE("Releasing surface %p\n", surface);
2922         if (surface)
2923             IDirect3DSurface9_Release(surface);
2924     }
2925     ZeroMemory(This->d3d9_surfaces, sizeof(IDirect3DSurface9 *) * This->num_surfaces);
2926 
2927     /* Now try to create the d3d9 device */
2928     ZeroMemory(&d3dpp, sizeof(d3dpp));
2929     d3dpp.Windowed = TRUE;
2930     d3dpp.hDeviceWindow = This->pVMR9->baseControlWindow.baseWindow.hWnd;
2931     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
2932 
2933     if (This->d3d9_dev)
2934         IDirect3DDevice9_Release(This->d3d9_dev);
2935     This->d3d9_dev = NULL;
2936     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);
2937     if (FAILED(hr))
2938     {
2939         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);
2940         if (FAILED(hr))
2941         {
2942             ERR("--> Creating device: %08x\n", hr);
2943             return S_OK;
2944         }
2945     }
2946     IVMRSurfaceAllocatorNotify9_ChangeD3DDevice(This->SurfaceAllocatorNotify, This->d3d9_dev, This->hMon);
2947 
2948     IVMRSurfaceAllocatorNotify9_AllocateSurfaceHelper(This->SurfaceAllocatorNotify, &This->info, &This->num_surfaces, This->d3d9_surfaces);
2949 
2950     This->reset = FALSE;
2951 
2952     if (!(This->info.dwFlags & VMR9AllocFlag_TextureSurface))
2953         return S_OK;
2954 
2955     hr = IDirect3DDevice9_CreateVertexBuffer(This->d3d9_dev, 4 * sizeof(struct VERTEX), D3DUSAGE_WRITEONLY, USED_FVF,
2956                                              This->info.Pool, &This->d3d9_vertex, NULL);
2957 
2958     width = This->info.dwWidth;
2959     height = This->info.dwHeight;
2960 
2961     for (i = 0; i < sizeof(t_vert) / sizeof(t_vert[0]); ++i)
2962     {
2963         if (i % 2)
2964         {
2965             t_vert[i].x = (float)This->pVMR9->target_rect.right - (float)This->pVMR9->target_rect.left - 0.5f;
2966             t_vert[i].u = (float)This->pVMR9->source_rect.right / (float)width;
2967         }
2968         else
2969         {
2970             t_vert[i].x = -0.5f;
2971             t_vert[i].u = (float)This->pVMR9->source_rect.left / (float)width;
2972         }
2973 
2974         if (i % 4 < 2)
2975         {
2976             t_vert[i].y = -0.5f;
2977             t_vert[i].v = (float)This->pVMR9->source_rect.bottom / (float)height;
2978         }
2979         else
2980         {
2981             t_vert[i].y = (float)This->pVMR9->target_rect.bottom - (float)This->pVMR9->target_rect.top - 0.5f;
2982             t_vert[i].v = (float)This->pVMR9->source_rect.top / (float)height;
2983         }
2984         t_vert[i].z = 0.0f;
2985         t_vert[i].rhw = 1.0f;
2986     }
2987 
2988     FIXME("Vertex rectangle:\n");
2989     FIXME("X, Y: %f, %f\n", t_vert[0].x, t_vert[0].y);
2990     FIXME("X, Y: %f, %f\n", t_vert[3].x, t_vert[3].y);
2991     FIXME("TOP, LEFT: %f, %f\n", t_vert[0].u, t_vert[0].v);
2992     FIXME("DOWN, BOTTOM: %f, %f\n", t_vert[3].u, t_vert[3].v);
2993 
2994     IDirect3DVertexBuffer9_Lock(This->d3d9_vertex, 0, sizeof(t_vert), &bits, 0);
2995     memcpy(bits, t_vert, sizeof(t_vert));
2996     IDirect3DVertexBuffer9_Unlock(This->d3d9_vertex);
2997 
2998     return S_OK;
2999 }
3000 
3001 static HRESULT WINAPI VMR9_SurfaceAllocator_GetSurface(IVMRSurfaceAllocatorEx9 *iface, DWORD_PTR id, DWORD surfaceindex, DWORD flags, IDirect3DSurface9 **surface)
3002 {
3003     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
3004 
3005     /* Update everything first, this is needed because the surface might be destroyed in the reset */
3006     if (!This->d3d9_dev)
3007     {
3008         TRACE("Device has left me!\n");
3009         return E_FAIL;
3010     }
3011 
3012     VMR9_SurfaceAllocator_UpdateDeviceReset(This);
3013 
3014     if (surfaceindex >= This->num_surfaces)
3015     {
3016         ERR("surfaceindex is greater than num_surfaces\n");
3017         return E_FAIL;
3018     }
3019     *surface = This->d3d9_surfaces[surfaceindex];
3020     IDirect3DSurface9_AddRef(*surface);
3021 
3022     return S_OK;
3023 }
3024 
3025 static HRESULT WINAPI VMR9_SurfaceAllocator_AdviseNotify(IVMRSurfaceAllocatorEx9 *iface, IVMRSurfaceAllocatorNotify9 *allocnotify)
3026 {
3027     VMR9DefaultAllocatorPresenterImpl *This = impl_from_IVMRSurfaceAllocatorEx9(iface);
3028 
3029     TRACE("(%p/%p)->(...)\n", iface, This);
3030 
3031     /* No AddRef taken here or the base VMR9 filter would never be destroyed */
3032     This->SurfaceAllocatorNotify = allocnotify;
3033     return S_OK;
3034 }
3035 
3036 static const IVMRSurfaceAllocatorEx9Vtbl VMR9_SurfaceAllocator =
3037 {
3038     VMR9_SurfaceAllocator_QueryInterface,
3039     VMR9_SurfaceAllocator_AddRef,
3040     VMR9_SurfaceAllocator_Release,
3041     VMR9_SurfaceAllocator_InitializeDevice,
3042     VMR9_SurfaceAllocator_TerminateDevice,
3043     VMR9_SurfaceAllocator_GetSurface,
3044     VMR9_SurfaceAllocator_AdviseNotify,
3045     NULL /* This isn't the SurfaceAllocatorEx type yet, working on it */
3046 };
3047 
3048 static IDirect3D9 *init_d3d9(HMODULE d3d9_handle)
3049 {
3050     IDirect3D9 * (__stdcall * d3d9_create)(UINT SDKVersion);
3051 
3052     d3d9_create = (void *)GetProcAddress(d3d9_handle, "Direct3DCreate9");
3053     if (!d3d9_create) return NULL;
3054 
3055     return d3d9_create(D3D_SDK_VERSION);
3056 }
3057 
3058 static HRESULT VMR9DefaultAllocatorPresenterImpl_create(struct quartz_vmr *parent, LPVOID * ppv)
3059 {
3060     HRESULT hr = S_OK;
3061     int i;
3062     VMR9DefaultAllocatorPresenterImpl* This;
3063 
3064     This = CoTaskMemAlloc(sizeof(VMR9DefaultAllocatorPresenterImpl));
3065     if (!This)
3066         return E_OUTOFMEMORY;
3067 
3068     This->d3d9_ptr = init_d3d9(parent->hD3d9);
3069     if (!This->d3d9_ptr)
3070     {
3071         WARN("Could not initialize d3d9.dll\n");
3072         CoTaskMemFree(This);
3073         return VFW_E_DDRAW_CAPS_NOT_SUITABLE;
3074     }
3075 
3076     i = 0;
3077     do
3078     {
3079         D3DDISPLAYMODE mode;
3080 
3081         hr = IDirect3D9_EnumAdapterModes(This->d3d9_ptr, i++, D3DFMT_X8R8G8B8, 0, &mode);
3082 	if (hr == D3DERR_INVALIDCALL) break; /* out of adapters */
3083     } while (FAILED(hr));
3084     if (FAILED(hr))
3085         ERR("HR: %08x\n", hr);
3086     if (hr == D3DERR_NOTAVAILABLE)
3087     {
3088         ERR("Format not supported\n");
3089         IDirect3D9_Release(This->d3d9_ptr);
3090         CoTaskMemFree(This);
3091         return VFW_E_DDRAW_CAPS_NOT_SUITABLE;
3092     }
3093 
3094     This->IVMRImagePresenter9_iface.lpVtbl = &VMR9_ImagePresenter;
3095     This->IVMRSurfaceAllocatorEx9_iface.lpVtbl = &VMR9_SurfaceAllocator;
3096 
3097     This->refCount = 1;
3098     This->pVMR9 = parent;
3099     This->d3d9_surfaces = NULL;
3100     This->d3d9_dev = NULL;
3101     This->hMon = 0;
3102     This->d3d9_vertex = NULL;
3103     This->num_surfaces = 0;
3104     This->hWndThread = NULL;
3105     This->ack = CreateEventW(NULL, 0, 0, NULL);
3106     This->SurfaceAllocatorNotify = NULL;
3107     This->reset = FALSE;
3108 
3109     *ppv = &This->IVMRImagePresenter9_iface;
3110     return S_OK;
3111 }
3112