quartz: Add initial VMR9 stub.
[wine] / dlls / quartz / vmr9.c
1 /*
2  * Video Mixing Renderer for dx9
3  *
4  * Copyright 2004 Christian Costa
5  * Copyright 2008 Maarten Lankhorst
6  * Copyright 2012 Aric Stewart
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24
25 #define NONAMELESSSTRUCT
26 #define NONAMELESSUNION
27 #include "quartz_private.h"
28
29 #include "uuids.h"
30 #include "vfwmsgs.h"
31 #include "amvideo.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "dshow.h"
35 #include "evcode.h"
36 #include "strmif.h"
37 #include "ddraw.h"
38 #include "dvdmedia.h"
39 #include "d3d9.h"
40 #include "vmr9.h"
41 #include "pin.h"
42
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
47
48 typedef struct
49 {
50     BaseRenderer renderer;
51     IUnknown IUnknown_inner;
52
53     BITMAPINFOHEADER bmiheader;
54     IUnknown * outer_unk;
55     BOOL bUnkOuterValid;
56     BOOL bAggregatable;
57 } VMR9Impl;
58
59 static inline VMR9Impl *impl_from_inner_IUnknown(IUnknown *iface)
60 {
61     return CONTAINING_RECORD(iface, VMR9Impl, IUnknown_inner);
62 }
63
64 static HRESULT WINAPI VMR9_DoRenderSample(BaseRenderer *iface, IMediaSample * pSample)
65 {
66     VMR9Impl *This = (VMR9Impl *)iface;
67     LPBYTE pbSrcStream = NULL;
68     REFERENCE_TIME tStart, tStop;
69     VMR9PresentationInfo info;
70     HRESULT hr;
71
72     TRACE("%p %p\n", iface, pSample);
73
74     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
75     if (FAILED(hr))
76         info.dwFlags = VMR9Sample_SrcDstRectsValid;
77     else
78         info.dwFlags = VMR9Sample_SrcDstRectsValid | VMR9Sample_TimeValid;
79
80     if (IMediaSample_IsDiscontinuity(pSample) == S_OK)
81         info.dwFlags |= VMR9Sample_Discontinuity;
82
83     if (IMediaSample_IsPreroll(pSample) == S_OK)
84         info.dwFlags |= VMR9Sample_Preroll;
85
86     if (IMediaSample_IsSyncPoint(pSample) == S_OK)
87         info.dwFlags |= VMR9Sample_SyncPoint;
88
89     hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
90     if (FAILED(hr))
91     {
92         ERR("Cannot get pointer to sample data (%x)\n", hr);
93         return hr;
94     }
95
96     info.rtStart = tStart;
97     info.rtEnd = tStop;
98     info.szAspectRatio.cx = This->bmiheader.biWidth;
99     info.szAspectRatio.cy = This->bmiheader.biHeight;
100
101     return hr;
102 }
103
104 static HRESULT WINAPI VMR9_CheckMediaType(BaseRenderer *iface, const AM_MEDIA_TYPE * pmt)
105 {
106     VMR9Impl *This = (VMR9Impl*)iface;
107
108     if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Video) || !pmt->pbFormat)
109         return S_FALSE;
110
111     /* Ignore subtype, test for bicompression instead */
112     if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo))
113     {
114         VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)pmt->pbFormat;
115
116         This->bmiheader = format->bmiHeader;
117         TRACE("Resolution: %dx%d\n", format->bmiHeader.biWidth, format->bmiHeader.biHeight);
118     }
119     else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2))
120     {
121         VIDEOINFOHEADER2 *format = (VIDEOINFOHEADER2 *)pmt->pbFormat;
122
123         This->bmiheader = format->bmiHeader;
124
125         TRACE("Resolution: %dx%d\n", format->bmiHeader.biWidth, format->bmiHeader.biHeight);
126     }
127     else
128     {
129         ERR("Format type %s not supported\n", debugstr_guid(&pmt->formattype));
130         return S_FALSE;
131     }
132     if (This->bmiheader.biCompression)
133         return S_FALSE;
134     return S_OK;
135 }
136
137 HRESULT WINAPI VMR9_ShouldDrawSampleNow(BaseRenderer *This, IMediaSample *pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime)
138 {
139     /* Preroll means the sample isn't shown, this is used for key frames and things like that */
140     if (IMediaSample_IsPreroll(pSample) == S_OK)
141         return E_FAIL;
142     return S_FALSE;
143 }
144
145 static const BaseRendererFuncTable BaseFuncTable = {
146     VMR9_CheckMediaType,
147     VMR9_DoRenderSample,
148     /**/
149     NULL,
150     NULL,
151     NULL,
152     NULL,
153     NULL,
154     NULL,
155     NULL,
156     NULL,
157     VMR9_ShouldDrawSampleNow,
158     NULL,
159     /**/
160     NULL,
161     NULL,
162     NULL,
163     NULL,
164     NULL,
165 };
166
167 static HRESULT WINAPI VMR9Inner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
168 {
169     VMR9Impl *This = impl_from_inner_IUnknown(iface);
170     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
171
172     if (This->bAggregatable)
173         This->bUnkOuterValid = TRUE;
174
175     *ppv = NULL;
176
177     if (IsEqualIID(riid, &IID_IUnknown))
178         *ppv = &This->IUnknown_inner;
179     else
180     {
181         HRESULT hr;
182         hr = BaseRendererImpl_QueryInterface(&This->renderer.filter.IBaseFilter_iface, riid, ppv);
183         if (SUCCEEDED(hr))
184             return hr;
185     }
186
187     if (*ppv)
188     {
189         IUnknown_AddRef((IUnknown *)(*ppv));
190         return S_OK;
191     }
192
193     else if (IsEqualIID(riid, &IID_IBasicVideo))
194         FIXME("No interface for IID_IBasicVideo\n");
195     else if (IsEqualIID(riid, &IID_IBasicVideo2))
196         FIXME("No interface for IID_IBasicVideo2\n");
197     else if (IsEqualIID(riid, &IID_IVideoWindow))
198         FIXME("No interface for IID_IVideoWindow\n");
199     else if (IsEqualIID(riid, &IID_IVMRWindowlessControl9))
200         ;
201     else if (IsEqualIID(riid, &IID_IVMRSurfaceAllocatorNotify9))
202         ;
203     else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags))
204         FIXME("No interface for IID_IAMFilterMiscFlags\n");
205     else if (IsEqualIID(riid, &IID_IMediaPosition))
206         FIXME("No interface for IID_IMediaPosition\n");
207     else if (IsEqualIID(riid, &IID_IQualProp))
208         FIXME("No interface for IID_IQualProp\n");
209     else if (IsEqualIID(riid, &IID_IVMRAspectRatioControl9))
210         FIXME("No interface for IID_IVMRAspectRatioControl9\n");
211     else if (IsEqualIID(riid, &IID_IVMRDeinterlaceControl9))
212         FIXME("No interface for IID_IVMRDeinterlaceControl9\n");
213     else if (IsEqualIID(riid, &IID_IVMRMixerBitmap9))
214         FIXME("No interface for IID_IVMRMixerBitmap9\n");
215     else if (IsEqualIID(riid, &IID_IVMRMonitorConfig9))
216         FIXME("No interface for IID_IVMRMonitorConfig9\n");
217     else if (IsEqualIID(riid, &IID_IVMRMixerControl9))
218         FIXME("No interface for IID_IVMRMixerControl9\n");
219     else
220         FIXME("No interface for %s\n", debugstr_guid(riid));
221
222     return E_NOINTERFACE;
223 }
224
225 static ULONG WINAPI VMR9Inner_AddRef(IUnknown * iface)
226 {
227     VMR9Impl *This = impl_from_inner_IUnknown(iface);
228     ULONG refCount = BaseFilterImpl_AddRef(&This->renderer.filter.IBaseFilter_iface);
229
230     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
231
232     return refCount;
233 }
234
235 static ULONG WINAPI VMR9Inner_Release(IUnknown * iface)
236 {
237     VMR9Impl *This = impl_from_inner_IUnknown(iface);
238     ULONG refCount = BaseRendererImpl_Release(&This->renderer.filter.IBaseFilter_iface);
239
240     TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
241
242     if (!refCount)
243     {
244         TRACE("Destroying\n");
245
246         CoTaskMemFree(This);
247     }
248     return refCount;
249 }
250
251 static const IUnknownVtbl IInner_VTable =
252 {
253     VMR9Inner_QueryInterface,
254     VMR9Inner_AddRef,
255     VMR9Inner_Release
256 };
257
258 static HRESULT WINAPI VMR9_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
259 {
260     VMR9Impl *This = (VMR9Impl *)iface;
261
262     if (This->bAggregatable)
263         This->bUnkOuterValid = TRUE;
264
265     if (This->outer_unk)
266     {
267         if (This->bAggregatable)
268             return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
269
270         if (IsEqualIID(riid, &IID_IUnknown))
271         {
272             HRESULT hr;
273
274             IUnknown_AddRef(&This->IUnknown_inner);
275             hr = IUnknown_QueryInterface(&This->IUnknown_inner, riid, ppv);
276             IUnknown_Release(&This->IUnknown_inner);
277             This->bAggregatable = TRUE;
278             return hr;
279         }
280
281         *ppv = NULL;
282         return E_NOINTERFACE;
283     }
284
285     return IUnknown_QueryInterface(&This->IUnknown_inner, riid, ppv);
286 }
287
288 static ULONG WINAPI VMR9_AddRef(IBaseFilter * iface)
289 {
290     VMR9Impl *This = (VMR9Impl *)iface;
291     LONG ret;
292
293     if (This->outer_unk && This->bUnkOuterValid)
294         ret = IUnknown_AddRef(This->outer_unk);
295     else
296         ret = IUnknown_AddRef(&This->IUnknown_inner);
297
298     TRACE("(%p)->AddRef from %d\n", iface, ret - 1);
299
300     return ret;
301 }
302
303 static ULONG WINAPI VMR9_Release(IBaseFilter * iface)
304 {
305     VMR9Impl *This = (VMR9Impl *)iface;
306     LONG ret;
307
308     if (This->outer_unk && This->bUnkOuterValid)
309         ret = IUnknown_Release(This->outer_unk);
310     else
311         ret = IUnknown_Release(&This->IUnknown_inner);
312
313     TRACE("(%p)->Release from %d\n", iface, ret + 1);
314
315     if (ret)
316         return ret;
317     return 0;
318 }
319
320 static const IBaseFilterVtbl VMR9_Vtbl =
321 {
322     VMR9_QueryInterface,
323     VMR9_AddRef,
324     VMR9_Release,
325     BaseFilterImpl_GetClassID,
326     BaseRendererImpl_Stop,
327     BaseRendererImpl_Pause,
328     BaseRendererImpl_Run,
329     BaseRendererImpl_GetState,
330     BaseRendererImpl_SetSyncSource,
331     BaseFilterImpl_GetSyncSource,
332     BaseFilterImpl_EnumPins,
333     BaseRendererImpl_FindPin,
334     BaseFilterImpl_QueryFilterInfo,
335     BaseFilterImpl_JoinFilterGraph,
336     BaseFilterImpl_QueryVendorInfo
337 };
338
339 HRESULT VMR9Impl_create(IUnknown * outer_unk, LPVOID * ppv)
340 {
341     HRESULT hr;
342     VMR9Impl * pVMR9;
343
344     TRACE("(%p, %p)\n", outer_unk, ppv);
345
346     *ppv = NULL;
347
348     pVMR9 = CoTaskMemAlloc(sizeof(VMR9Impl));
349
350     pVMR9->outer_unk = outer_unk;
351     pVMR9->bUnkOuterValid = FALSE;
352     pVMR9->bAggregatable = FALSE;
353     pVMR9->IUnknown_inner.lpVtbl = &IInner_VTable;
354
355     hr = BaseRenderer_Init(&pVMR9->renderer, &VMR9_Vtbl, outer_unk, &CLSID_VideoMixingRenderer9, (DWORD_PTR)(__FILE__ ": VMR9Impl.csFilter"), &BaseFuncTable);
356
357     if (SUCCEEDED(hr))
358     {
359         *ppv = (LPVOID)pVMR9;
360         TRACE("Created at %p\n", pVMR9);
361     }
362     else
363     {
364         BaseRendererImpl_Release(&pVMR9->renderer.filter.IBaseFilter_iface);
365         CoTaskMemFree(pVMR9);
366     }
367
368     return hr;
369 }