wined3d: IWineD3DBuffer_Unmap() can't fail.
[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
52 typedef struct NullRendererImpl
53 {
54     BaseFilter filter;
55     const IUnknownVtbl * IInner_vtbl;
56     IUnknown *seekthru_unk;
57
58     BaseInputPin *pInputPin;
59     IUnknown * pUnkOuter;
60     BOOL bUnkOuterValid;
61     BOOL bAggregatable;
62 } NullRendererImpl;
63
64 static HRESULT WINAPI NullRenderer_Receive(BaseInputPin *pin, IMediaSample * pSample)
65 {
66     NullRendererImpl *This = ((NullRendererImpl*)pin->pin.pinInfo.pFilter);
67     HRESULT hr = S_OK;
68     REFERENCE_TIME start, stop;
69
70     TRACE("%p %p\n", pin, pSample);
71
72     if (SUCCEEDED(IMediaSample_GetTime(pSample, &start, &stop)))
73         MediaSeekingPassThru_RegisterMediaTime(This->seekthru_unk, start);
74     EnterCriticalSection(&This->filter.csFilter);
75     if (This->pInputPin->flushing || This->pInputPin->end_of_stream)
76         hr = S_FALSE;
77     LeaveCriticalSection(&This->filter.csFilter);
78
79     return hr;
80 }
81
82 static HRESULT WINAPI NullRenderer_CheckMediaType(BasePin *iface, const AM_MEDIA_TYPE * pmt)
83 {
84     TRACE("Not a stub!\n");
85     return S_OK;
86 }
87
88 static IPin* WINAPI NullRenderer_GetPin(BaseFilter *iface, int pos)
89 {
90     NullRendererImpl *This = (NullRendererImpl *)iface;
91
92     if (pos >= 1 || pos < 0)
93         return NULL;
94
95     IPin_AddRef((IPin *)This->pInputPin);
96     return (IPin *)This->pInputPin;
97 }
98
99 static LONG WINAPI NullRenderer_GetPinCount(BaseFilter *iface)
100 {
101     return 1;
102 }
103
104 static const BaseFilterFuncTable BaseFuncTable = {
105     NullRenderer_GetPin,
106     NullRenderer_GetPinCount
107 };
108
109 static const  BasePinFuncTable input_BaseFuncTable = {
110     NullRenderer_CheckMediaType,
111     NULL,
112     BasePinImpl_GetMediaTypeVersion,
113     BasePinImpl_GetMediaType
114 };
115
116 static const BaseInputPinFuncTable input_BaseInputFuncTable = {
117    NullRenderer_Receive
118 };
119
120
121 HRESULT NullRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv)
122 {
123     HRESULT hr;
124     PIN_INFO piInput;
125     NullRendererImpl * pNullRenderer;
126
127     TRACE("(%p, %p)\n", pUnkOuter, ppv);
128
129     *ppv = NULL;
130
131     pNullRenderer = CoTaskMemAlloc(sizeof(NullRendererImpl));
132     pNullRenderer->pUnkOuter = pUnkOuter;
133     pNullRenderer->bUnkOuterValid = FALSE;
134     pNullRenderer->bAggregatable = FALSE;
135     pNullRenderer->IInner_vtbl = &IInner_VTable;
136
137     BaseFilter_Init(&pNullRenderer->filter, &NullRenderer_Vtbl, &CLSID_NullRenderer, (DWORD_PTR)(__FILE__ ": NullRendererImpl.csFilter"), &BaseFuncTable);
138
139     /* construct input pin */
140     piInput.dir = PINDIR_INPUT;
141     piInput.pFilter = (IBaseFilter *)pNullRenderer;
142     lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
143
144     hr = BaseInputPin_Construct(&NullRenderer_InputPin_Vtbl, &piInput, &input_BaseFuncTable, &input_BaseInputFuncTable, &pNullRenderer->filter.csFilter, NULL, (IPin **)&pNullRenderer->pInputPin);
145
146     if (SUCCEEDED(hr))
147     {
148         ISeekingPassThru *passthru;
149         hr = CoCreateInstance(&CLSID_SeekingPassThru, pUnkOuter ? pUnkOuter : (IUnknown*)&pNullRenderer->IInner_vtbl, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&pNullRenderer->seekthru_unk);
150         if (FAILED(hr)) {
151             IUnknown_Release((IUnknown*)pNullRenderer);
152             return hr;
153         }
154         IUnknown_QueryInterface(pNullRenderer->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
155         ISeekingPassThru_Init(passthru, TRUE, (IPin*)pNullRenderer->pInputPin);
156         ISeekingPassThru_Release(passthru);
157         *ppv = pNullRenderer;
158     }
159     else
160     {
161         BaseFilterImpl_Release((IBaseFilter*)pNullRenderer);
162         CoTaskMemFree(pNullRenderer);
163     }
164
165     return hr;
166 }
167
168 static HRESULT WINAPI NullRendererInner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
169 {
170     ICOM_THIS_MULTI(NullRendererImpl, IInner_vtbl, iface);
171     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
172
173     if (This->bAggregatable)
174         This->bUnkOuterValid = TRUE;
175
176     *ppv = NULL;
177
178     if (IsEqualIID(riid, &IID_IUnknown))
179         *ppv = &This->IInner_vtbl;
180     else if (IsEqualIID(riid, &IID_IPersist))
181         *ppv = This;
182     else if (IsEqualIID(riid, &IID_IMediaFilter))
183         *ppv = This;
184     else if (IsEqualIID(riid, &IID_IBaseFilter))
185         *ppv = This;
186     else if (IsEqualIID(riid, &IID_IMediaSeeking))
187         return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
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         This->filter.lpVtbl = NULL;
231         if (This->seekthru_unk)
232             IUnknown_Release(This->seekthru_unk);
233
234         This->filter.csFilter.DebugInfo->Spare[0] = 0;
235         DeleteCriticalSection(&This->filter.csFilter);
236
237         TRACE("Destroying Null Renderer\n");
238         CoTaskMemFree(This);
239         return 0;
240     }
241     else
242         return refCount;
243 }
244
245 static const IUnknownVtbl IInner_VTable =
246 {
247     NullRendererInner_QueryInterface,
248     NullRendererInner_AddRef,
249     NullRendererInner_Release
250 };
251
252 static HRESULT WINAPI NullRenderer_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
253 {
254     NullRendererImpl *This = (NullRendererImpl *)iface;
255
256     if (This->bAggregatable)
257         This->bUnkOuterValid = TRUE;
258
259     if (This->pUnkOuter)
260     {
261         if (This->bAggregatable)
262             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
263
264         if (IsEqualIID(riid, &IID_IUnknown))
265         {
266             HRESULT hr;
267
268             IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
269             hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
270             IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
271             This->bAggregatable = TRUE;
272             return hr;
273         }
274
275         *ppv = NULL;
276         return E_NOINTERFACE;
277     }
278
279     return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
280 }
281
282 static ULONG WINAPI NullRenderer_AddRef(IBaseFilter * iface)
283 {
284     NullRendererImpl *This = (NullRendererImpl *)iface;
285
286     if (This->pUnkOuter && This->bUnkOuterValid)
287         return IUnknown_AddRef(This->pUnkOuter);
288     return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
289 }
290
291 static ULONG WINAPI NullRenderer_Release(IBaseFilter * iface)
292 {
293     NullRendererImpl *This = (NullRendererImpl *)iface;
294
295     if (This->pUnkOuter && This->bUnkOuterValid)
296         return IUnknown_Release(This->pUnkOuter);
297     return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
298 }
299
300 /** IMediaFilter methods **/
301
302 static HRESULT WINAPI NullRenderer_Stop(IBaseFilter * iface)
303 {
304     NullRendererImpl *This = (NullRendererImpl *)iface;
305
306     TRACE("(%p/%p)->()\n", This, iface);
307
308     EnterCriticalSection(&This->filter.csFilter);
309     {
310         This->filter.state = State_Stopped;
311         MediaSeekingPassThru_ResetMediaTime(This->seekthru_unk);
312     }
313     LeaveCriticalSection(&This->filter.csFilter);
314
315     return S_OK;
316 }
317
318 static HRESULT WINAPI NullRenderer_Pause(IBaseFilter * iface)
319 {
320     NullRendererImpl *This = (NullRendererImpl *)iface;
321
322     TRACE("(%p/%p)->()\n", This, iface);
323
324     EnterCriticalSection(&This->filter.csFilter);
325     {
326         if (This->filter.state == State_Stopped)
327             This->pInputPin->end_of_stream = 0;
328         This->filter.state = State_Paused;
329     }
330     LeaveCriticalSection(&This->filter.csFilter);
331
332     return S_OK;
333 }
334
335 static HRESULT WINAPI NullRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
336 {
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     {
343         This->filter.rtStreamStart = tStart;
344         This->filter.state = State_Running;
345         This->pInputPin->end_of_stream = 0;
346     }
347     LeaveCriticalSection(&This->filter.csFilter);
348
349     return S_OK;
350 }
351
352 /** IBaseFilter implementation **/
353
354 static HRESULT WINAPI NullRenderer_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
355 {
356     NullRendererImpl *This = (NullRendererImpl *)iface;
357
358     TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
359
360     if (!Id || !ppPin)
361         return E_POINTER;
362
363     if (!lstrcmpiW(Id,wcsInputPinName) || !lstrcmpiW(Id,wcsAltInputPinName))
364     {
365         *ppPin = (IPin *)This->pInputPin;
366         IPin_AddRef(*ppPin);
367         return S_OK;
368     }
369     *ppPin = NULL;
370     return VFW_E_NOT_FOUND;
371 }
372
373 static const IBaseFilterVtbl NullRenderer_Vtbl =
374 {
375     NullRenderer_QueryInterface,
376     NullRenderer_AddRef,
377     NullRenderer_Release,
378     BaseFilterImpl_GetClassID,
379     NullRenderer_Stop,
380     NullRenderer_Pause,
381     NullRenderer_Run,
382     BaseFilterImpl_GetState,
383     BaseFilterImpl_SetSyncSource,
384     BaseFilterImpl_GetSyncSource,
385     BaseFilterImpl_EnumPins,
386     NullRenderer_FindPin,
387     BaseFilterImpl_QueryFilterInfo,
388     BaseFilterImpl_JoinFilterGraph,
389     BaseFilterImpl_QueryVendorInfo
390 };
391
392 static HRESULT WINAPI NullRenderer_InputPin_EndOfStream(IPin * iface)
393 {
394     BaseInputPin* This = (BaseInputPin*)iface;
395     IMediaEventSink* pEventSink;
396     NullRendererImpl *pNull;
397     IFilterGraph *graph;
398     HRESULT hr = S_OK;
399
400     TRACE("(%p/%p)->()\n", This, iface);
401
402     BaseInputPinImpl_EndOfStream(iface);
403     pNull = (NullRendererImpl*)This->pin.pinInfo.pFilter;
404     graph = pNull->filter.filterInfo.pGraph;
405     if (graph)
406     {
407         hr = IFilterGraph_QueryInterface(((NullRendererImpl*)This->pin.pinInfo.pFilter)->filter.filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
408         if (SUCCEEDED(hr))
409         {
410             hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
411             IMediaEventSink_Release(pEventSink);
412         }
413     }
414     MediaSeekingPassThru_EOS(pNull->seekthru_unk);
415
416     return hr;
417 }
418
419 static HRESULT WINAPI NullRenderer_InputPin_EndFlush(IPin * iface)
420 {
421     BaseInputPin* This = (BaseInputPin*)iface;
422     NullRendererImpl *pNull;
423     HRESULT hr = S_OK;
424
425     TRACE("(%p/%p)->()\n", This, iface);
426
427     hr = BaseInputPinImpl_EndOfStream(iface);
428     pNull = (NullRendererImpl*)This->pin.pinInfo.pFilter;
429     MediaSeekingPassThru_ResetMediaTime(pNull->seekthru_unk);
430     return hr;
431 }
432
433 static const IPinVtbl NullRenderer_InputPin_Vtbl =
434 {
435     BaseInputPinImpl_QueryInterface,
436     BasePinImpl_AddRef,
437     BaseInputPinImpl_Release,
438     BaseInputPinImpl_Connect,
439     BaseInputPinImpl_ReceiveConnection,
440     BasePinImpl_Disconnect,
441     BasePinImpl_ConnectedTo,
442     BasePinImpl_ConnectionMediaType,
443     BasePinImpl_QueryPinInfo,
444     BasePinImpl_QueryDirection,
445     BasePinImpl_QueryId,
446     BaseInputPinImpl_QueryAccept,
447     BasePinImpl_EnumMediaTypes,
448     BasePinImpl_QueryInternalConnections,
449     NullRenderer_InputPin_EndOfStream,
450     BaseInputPinImpl_BeginFlush,
451     NullRenderer_InputPin_EndFlush,
452     BaseInputPinImpl_NewSegment
453 };