windowscodecs: Avoid an iface -> impl conversion from a non-method.
[wine] / dlls / quartz / nullrenderer.c
1 /*
2  * Null Renderer (Promiscuous, not rendering anything at all!)
3  *
4  * Copyright 2004 Christian Costa
5  * Copyright 2008 Maarten Lankhorst
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #define NONAMELESSSTRUCT
25 #define NONAMELESSUNION
26 #include "quartz_private.h"
27 #include "control_private.h"
28 #include "pin.h"
29
30 #include "uuids.h"
31 #include "vfwmsgs.h"
32 #include "amvideo.h"
33 #include "windef.h"
34 #include "winbase.h"
35 #include "dshow.h"
36 #include "evcode.h"
37 #include "strmif.h"
38 #include "ddraw.h"
39
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
44
45 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
46 static const WCHAR wcsAltInputPinName[] = {'I','n',0};
47
48 static const IBaseFilterVtbl NullRenderer_Vtbl;
49 static const IUnknownVtbl IInner_VTable;
50 static const IPinVtbl NullRenderer_InputPin_Vtbl;
51 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl;
52
53 typedef struct NullRendererImpl
54 {
55     BaseFilter filter;
56     const IUnknownVtbl * IInner_vtbl;
57     const IAMFilterMiscFlagsVtbl *IAMFilterMiscFlags_vtbl;
58     IUnknown *seekthru_unk;
59
60     BaseInputPin *pInputPin;
61     IUnknown * pUnkOuter;
62     BOOL bUnkOuterValid;
63     BOOL bAggregatable;
64 } NullRendererImpl;
65
66 static HRESULT WINAPI NullRenderer_Receive(BaseInputPin *pin, IMediaSample * pSample)
67 {
68     NullRendererImpl *This = ((NullRendererImpl*)pin->pin.pinInfo.pFilter);
69     HRESULT hr = S_OK;
70     REFERENCE_TIME start, stop;
71
72     TRACE("%p %p\n", pin, pSample);
73
74     if (SUCCEEDED(IMediaSample_GetMediaTime(pSample, &start, &stop)))
75         MediaSeekingPassThru_RegisterMediaTime(This->seekthru_unk, start);
76     EnterCriticalSection(&This->filter.csFilter);
77     if (This->pInputPin->flushing || This->pInputPin->end_of_stream)
78         hr = S_FALSE;
79     LeaveCriticalSection(&This->filter.csFilter);
80
81     return hr;
82 }
83
84 static HRESULT WINAPI NullRenderer_CheckMediaType(BasePin *iface, const AM_MEDIA_TYPE * pmt)
85 {
86     TRACE("Not a stub!\n");
87     return S_OK;
88 }
89
90 static IPin* WINAPI NullRenderer_GetPin(BaseFilter *iface, int pos)
91 {
92     NullRendererImpl *This = (NullRendererImpl *)iface;
93
94     if (pos >= 1 || pos < 0)
95         return NULL;
96
97     IPin_AddRef((IPin *)This->pInputPin);
98     return (IPin *)This->pInputPin;
99 }
100
101 static LONG WINAPI NullRenderer_GetPinCount(BaseFilter *iface)
102 {
103     return 1;
104 }
105
106 static const BaseFilterFuncTable BaseFuncTable = {
107     NullRenderer_GetPin,
108     NullRenderer_GetPinCount
109 };
110
111 static const  BasePinFuncTable input_BaseFuncTable = {
112     NullRenderer_CheckMediaType,
113     NULL,
114     BasePinImpl_GetMediaTypeVersion,
115     BasePinImpl_GetMediaType
116 };
117
118 static const BaseInputPinFuncTable input_BaseInputFuncTable = {
119    NullRenderer_Receive
120 };
121
122
123 HRESULT NullRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv)
124 {
125     HRESULT hr;
126     PIN_INFO piInput;
127     NullRendererImpl * pNullRenderer;
128
129     TRACE("(%p, %p)\n", pUnkOuter, ppv);
130
131     *ppv = NULL;
132
133     pNullRenderer = CoTaskMemAlloc(sizeof(NullRendererImpl));
134     pNullRenderer->pUnkOuter = pUnkOuter;
135     pNullRenderer->bUnkOuterValid = FALSE;
136     pNullRenderer->bAggregatable = FALSE;
137     pNullRenderer->IInner_vtbl = &IInner_VTable;
138     pNullRenderer->IAMFilterMiscFlags_vtbl = &IAMFilterMiscFlags_Vtbl;
139
140     BaseFilter_Init(&pNullRenderer->filter, &NullRenderer_Vtbl, &CLSID_NullRenderer, (DWORD_PTR)(__FILE__ ": NullRendererImpl.csFilter"), &BaseFuncTable);
141
142     /* construct input pin */
143     piInput.dir = PINDIR_INPUT;
144     piInput.pFilter = (IBaseFilter *)pNullRenderer;
145     lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
146
147     hr = BaseInputPin_Construct(&NullRenderer_InputPin_Vtbl, &piInput, &input_BaseFuncTable, &input_BaseInputFuncTable, &pNullRenderer->filter.csFilter, NULL, (IPin **)&pNullRenderer->pInputPin);
148
149     if (SUCCEEDED(hr))
150     {
151         ISeekingPassThru *passthru;
152         hr = CoCreateInstance(&CLSID_SeekingPassThru, pUnkOuter ? pUnkOuter : (IUnknown*)&pNullRenderer->IInner_vtbl, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&pNullRenderer->seekthru_unk);
153         if (FAILED(hr)) {
154             IUnknown_Release((IUnknown*)pNullRenderer);
155             return hr;
156         }
157         IUnknown_QueryInterface(pNullRenderer->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
158         ISeekingPassThru_Init(passthru, TRUE, (IPin*)pNullRenderer->pInputPin);
159         ISeekingPassThru_Release(passthru);
160         *ppv = pNullRenderer;
161     }
162     else
163     {
164         BaseFilterImpl_Release((IBaseFilter*)pNullRenderer);
165         CoTaskMemFree(pNullRenderer);
166     }
167
168     return hr;
169 }
170
171 static HRESULT WINAPI NullRendererInner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
172 {
173     ICOM_THIS_MULTI(NullRendererImpl, IInner_vtbl, iface);
174     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
175
176     if (This->bAggregatable)
177         This->bUnkOuterValid = TRUE;
178
179     *ppv = NULL;
180
181     if (IsEqualIID(riid, &IID_IUnknown))
182         *ppv = &This->IInner_vtbl;
183     else if (IsEqualIID(riid, &IID_IPersist))
184         *ppv = This;
185     else if (IsEqualIID(riid, &IID_IMediaFilter))
186         *ppv = This;
187     else if (IsEqualIID(riid, &IID_IBaseFilter))
188         *ppv = This;
189     else if (IsEqualIID(riid, &IID_IMediaSeeking))
190         return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
191     else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags))
192         *ppv = &This->IAMFilterMiscFlags_vtbl;
193
194     if (*ppv)
195     {
196         IUnknown_AddRef((IUnknown *)(*ppv));
197         return S_OK;
198     }
199
200     if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
201         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
202
203     return E_NOINTERFACE;
204 }
205
206 static ULONG WINAPI NullRendererInner_AddRef(IUnknown * iface)
207 {
208     ICOM_THIS_MULTI(NullRendererImpl, IInner_vtbl, iface);
209     ULONG refCount = InterlockedIncrement(&This->filter.refCount);
210
211     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
212
213     return refCount;
214 }
215
216 static ULONG WINAPI NullRendererInner_Release(IUnknown * iface)
217 {
218     ICOM_THIS_MULTI(NullRendererImpl, IInner_vtbl, iface);
219     ULONG refCount = InterlockedDecrement(&This->filter.refCount);
220
221     TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
222
223     if (!refCount)
224     {
225         IPin *pConnectedTo;
226
227         if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
228         {
229             IPin_Disconnect(pConnectedTo);
230             IPin_Release(pConnectedTo);
231         }
232         IPin_Disconnect((IPin *)This->pInputPin);
233         IPin_Release((IPin *)This->pInputPin);
234
235         This->filter.lpVtbl = NULL;
236         if (This->seekthru_unk)
237             IUnknown_Release(This->seekthru_unk);
238
239         This->filter.csFilter.DebugInfo->Spare[0] = 0;
240         DeleteCriticalSection(&This->filter.csFilter);
241
242         TRACE("Destroying Null Renderer\n");
243         CoTaskMemFree(This);
244         return 0;
245     }
246     else
247         return refCount;
248 }
249
250 static const IUnknownVtbl IInner_VTable =
251 {
252     NullRendererInner_QueryInterface,
253     NullRendererInner_AddRef,
254     NullRendererInner_Release
255 };
256
257 static HRESULT WINAPI NullRenderer_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
258 {
259     NullRendererImpl *This = (NullRendererImpl *)iface;
260
261     if (This->bAggregatable)
262         This->bUnkOuterValid = TRUE;
263
264     if (This->pUnkOuter)
265     {
266         if (This->bAggregatable)
267             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
268
269         if (IsEqualIID(riid, &IID_IUnknown))
270         {
271             HRESULT hr;
272
273             IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
274             hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
275             IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
276             This->bAggregatable = TRUE;
277             return hr;
278         }
279
280         *ppv = NULL;
281         return E_NOINTERFACE;
282     }
283
284     return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
285 }
286
287 static ULONG WINAPI NullRenderer_AddRef(IBaseFilter * iface)
288 {
289     NullRendererImpl *This = (NullRendererImpl *)iface;
290
291     if (This->pUnkOuter && This->bUnkOuterValid)
292         return IUnknown_AddRef(This->pUnkOuter);
293     return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
294 }
295
296 static ULONG WINAPI NullRenderer_Release(IBaseFilter * iface)
297 {
298     NullRendererImpl *This = (NullRendererImpl *)iface;
299
300     if (This->pUnkOuter && This->bUnkOuterValid)
301         return IUnknown_Release(This->pUnkOuter);
302     return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
303 }
304
305 /** IMediaFilter methods **/
306
307 static HRESULT WINAPI NullRenderer_Stop(IBaseFilter * iface)
308 {
309     NullRendererImpl *This = (NullRendererImpl *)iface;
310
311     TRACE("(%p/%p)->()\n", This, iface);
312
313     EnterCriticalSection(&This->filter.csFilter);
314     {
315         This->filter.state = State_Stopped;
316         MediaSeekingPassThru_ResetMediaTime(This->seekthru_unk);
317     }
318     LeaveCriticalSection(&This->filter.csFilter);
319
320     return S_OK;
321 }
322
323 static HRESULT WINAPI NullRenderer_Pause(IBaseFilter * iface)
324 {
325     NullRendererImpl *This = (NullRendererImpl *)iface;
326
327     TRACE("(%p/%p)->()\n", This, iface);
328
329     EnterCriticalSection(&This->filter.csFilter);
330     {
331         if (This->filter.state == State_Stopped)
332             This->pInputPin->end_of_stream = 0;
333         This->filter.state = State_Paused;
334     }
335     LeaveCriticalSection(&This->filter.csFilter);
336
337     return S_OK;
338 }
339
340 static HRESULT WINAPI NullRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
341 {
342     HRESULT hr = S_OK;
343     NullRendererImpl *This = (NullRendererImpl *)iface;
344
345     TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
346
347     EnterCriticalSection(&This->filter.csFilter);
348     This->filter.rtStreamStart = tStart;
349     if (This->filter.state == State_Running)
350         goto out;
351     if (This->pInputPin->pin.pConnectedTo)
352     {
353         This->pInputPin->end_of_stream = 0;
354     }
355     else if (This->filter.filterInfo.pGraph)
356     {
357         IMediaEventSink *pEventSink;
358         hr = IFilterGraph_QueryInterface(This->filter.filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
359         if (SUCCEEDED(hr))
360         {
361             hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, (LONG_PTR)This);
362             IMediaEventSink_Release(pEventSink);
363         }
364         hr = S_OK;
365     }
366     if (SUCCEEDED(hr))
367         This->filter.state = State_Running;
368 out:
369     LeaveCriticalSection(&This->filter.csFilter);
370
371     return hr;
372 }
373
374 /** IBaseFilter implementation **/
375
376 static HRESULT WINAPI NullRenderer_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
377 {
378     NullRendererImpl *This = (NullRendererImpl *)iface;
379
380     TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
381
382     if (!Id || !ppPin)
383         return E_POINTER;
384
385     if (!lstrcmpiW(Id,wcsInputPinName) || !lstrcmpiW(Id,wcsAltInputPinName))
386     {
387         *ppPin = (IPin *)This->pInputPin;
388         IPin_AddRef(*ppPin);
389         return S_OK;
390     }
391     *ppPin = NULL;
392     return VFW_E_NOT_FOUND;
393 }
394
395 static const IBaseFilterVtbl NullRenderer_Vtbl =
396 {
397     NullRenderer_QueryInterface,
398     NullRenderer_AddRef,
399     NullRenderer_Release,
400     BaseFilterImpl_GetClassID,
401     NullRenderer_Stop,
402     NullRenderer_Pause,
403     NullRenderer_Run,
404     BaseFilterImpl_GetState,
405     BaseFilterImpl_SetSyncSource,
406     BaseFilterImpl_GetSyncSource,
407     BaseFilterImpl_EnumPins,
408     NullRenderer_FindPin,
409     BaseFilterImpl_QueryFilterInfo,
410     BaseFilterImpl_JoinFilterGraph,
411     BaseFilterImpl_QueryVendorInfo
412 };
413
414 static HRESULT WINAPI NullRenderer_InputPin_EndOfStream(IPin * iface)
415 {
416     BaseInputPin* This = (BaseInputPin*)iface;
417     IMediaEventSink* pEventSink;
418     NullRendererImpl *pNull;
419     IFilterGraph *graph;
420     HRESULT hr = S_OK;
421
422     TRACE("(%p/%p)->()\n", This, iface);
423
424     BaseInputPinImpl_EndOfStream(iface);
425     pNull = (NullRendererImpl*)This->pin.pinInfo.pFilter;
426     graph = pNull->filter.filterInfo.pGraph;
427     if (graph)
428     {
429         hr = IFilterGraph_QueryInterface(pNull->filter.filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
430         if (SUCCEEDED(hr))
431         {
432             hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, (LONG_PTR)pNull);
433             IMediaEventSink_Release(pEventSink);
434         }
435     }
436     MediaSeekingPassThru_EOS(pNull->seekthru_unk);
437
438     return hr;
439 }
440
441 static HRESULT WINAPI NullRenderer_InputPin_EndFlush(IPin * iface)
442 {
443     BaseInputPin* This = (BaseInputPin*)iface;
444     NullRendererImpl *pNull;
445     HRESULT hr = S_OK;
446
447     TRACE("(%p/%p)->()\n", This, iface);
448
449     hr = BaseInputPinImpl_EndOfStream(iface);
450     pNull = (NullRendererImpl*)This->pin.pinInfo.pFilter;
451     MediaSeekingPassThru_ResetMediaTime(pNull->seekthru_unk);
452     return hr;
453 }
454
455 static const IPinVtbl NullRenderer_InputPin_Vtbl =
456 {
457     BaseInputPinImpl_QueryInterface,
458     BasePinImpl_AddRef,
459     BaseInputPinImpl_Release,
460     BaseInputPinImpl_Connect,
461     BaseInputPinImpl_ReceiveConnection,
462     BasePinImpl_Disconnect,
463     BasePinImpl_ConnectedTo,
464     BasePinImpl_ConnectionMediaType,
465     BasePinImpl_QueryPinInfo,
466     BasePinImpl_QueryDirection,
467     BasePinImpl_QueryId,
468     BaseInputPinImpl_QueryAccept,
469     BasePinImpl_EnumMediaTypes,
470     BasePinImpl_QueryInternalConnections,
471     NullRenderer_InputPin_EndOfStream,
472     BaseInputPinImpl_BeginFlush,
473     NullRenderer_InputPin_EndFlush,
474     BaseInputPinImpl_NewSegment
475 };
476
477 static NullRendererImpl *from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface) {
478     return (NullRendererImpl*)((char*)iface - offsetof(NullRendererImpl, IAMFilterMiscFlags_vtbl));
479 }
480
481 static HRESULT WINAPI AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags *iface, const REFIID riid, void **ppv) {
482     NullRendererImpl *This = from_IAMFilterMiscFlags(iface);
483     return IUnknown_QueryInterface((IUnknown*)This, riid, ppv);
484 }
485
486 static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface) {
487     NullRendererImpl *This = from_IAMFilterMiscFlags(iface);
488     return IUnknown_AddRef((IUnknown*)This);
489 }
490
491 static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface) {
492     NullRendererImpl *This = from_IAMFilterMiscFlags(iface);
493     return IUnknown_Release((IUnknown*)This);
494 }
495
496 static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface) {
497     return AM_FILTER_MISC_FLAGS_IS_RENDERER;
498 }
499
500 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = {
501     AMFilterMiscFlags_QueryInterface,
502     AMFilterMiscFlags_AddRef,
503     AMFilterMiscFlags_Release,
504     AMFilterMiscFlags_GetMiscFlags
505 };