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