quartz: Fix EC_COMPLETE handling on null renderer.
[wine/multimedia.git] / dlls / quartz / nullrenderer.c
blobcab2090a25ebf5df6c142a3b4b5d15fbaf3201cc
1 /*
2 * Null Renderer (Promiscuous, not rendering anything at all!)
4 * Copyright 2004 Christian Costa
5 * Copyright 2008 Maarten Lankhorst
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.
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.
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
22 #include "config.h"
24 #define NONAMELESSSTRUCT
25 #define NONAMELESSUNION
26 #include "quartz_private.h"
27 #include "control_private.h"
28 #include "pin.h"
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"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
45 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
46 static const WCHAR wcsAltInputPinName[] = {'I','n',0};
48 static const IBaseFilterVtbl NullRenderer_Vtbl;
49 static const IUnknownVtbl IInner_VTable;
50 static const IPinVtbl NullRenderer_InputPin_Vtbl;
52 typedef struct NullRendererImpl
54 BaseFilter filter;
55 const IUnknownVtbl * IInner_vtbl;
56 IUnknown *seekthru_unk;
58 BaseInputPin *pInputPin;
59 IUnknown * pUnkOuter;
60 BOOL bUnkOuterValid;
61 BOOL bAggregatable;
62 } NullRendererImpl;
64 static HRESULT WINAPI NullRenderer_Receive(BaseInputPin *pin, IMediaSample * pSample)
66 NullRendererImpl *This = ((NullRendererImpl*)pin->pin.pinInfo.pFilter);
67 HRESULT hr = S_OK;
68 REFERENCE_TIME start, stop;
70 TRACE("%p %p\n", pin, pSample);
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);
79 return hr;
82 static HRESULT WINAPI NullRenderer_CheckMediaType(BasePin *iface, const AM_MEDIA_TYPE * pmt)
84 TRACE("Not a stub!\n");
85 return S_OK;
88 static IPin* WINAPI NullRenderer_GetPin(BaseFilter *iface, int pos)
90 NullRendererImpl *This = (NullRendererImpl *)iface;
92 if (pos >= 1 || pos < 0)
93 return NULL;
95 IPin_AddRef((IPin *)This->pInputPin);
96 return (IPin *)This->pInputPin;
99 static LONG WINAPI NullRenderer_GetPinCount(BaseFilter *iface)
101 return 1;
104 static const BaseFilterFuncTable BaseFuncTable = {
105 NullRenderer_GetPin,
106 NullRenderer_GetPinCount
109 static const BasePinFuncTable input_BaseFuncTable = {
110 NullRenderer_CheckMediaType,
111 NULL,
112 BasePinImpl_GetMediaTypeVersion,
113 BasePinImpl_GetMediaType
116 static const BaseInputPinFuncTable input_BaseInputFuncTable = {
117 NullRenderer_Receive
121 HRESULT NullRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv)
123 HRESULT hr;
124 PIN_INFO piInput;
125 NullRendererImpl * pNullRenderer;
127 TRACE("(%p, %p)\n", pUnkOuter, ppv);
129 *ppv = NULL;
131 pNullRenderer = CoTaskMemAlloc(sizeof(NullRendererImpl));
132 pNullRenderer->pUnkOuter = pUnkOuter;
133 pNullRenderer->bUnkOuterValid = FALSE;
134 pNullRenderer->bAggregatable = FALSE;
135 pNullRenderer->IInner_vtbl = &IInner_VTable;
137 BaseFilter_Init(&pNullRenderer->filter, &NullRenderer_Vtbl, &CLSID_NullRenderer, (DWORD_PTR)(__FILE__ ": NullRendererImpl.csFilter"), &BaseFuncTable);
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]));
144 hr = BaseInputPin_Construct(&NullRenderer_InputPin_Vtbl, &piInput, &input_BaseFuncTable, &input_BaseInputFuncTable, &pNullRenderer->filter.csFilter, NULL, (IPin **)&pNullRenderer->pInputPin);
146 if (SUCCEEDED(hr))
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;
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;
159 else
161 BaseFilterImpl_Release((IBaseFilter*)pNullRenderer);
162 CoTaskMemFree(pNullRenderer);
165 return hr;
168 static HRESULT WINAPI NullRendererInner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
170 ICOM_THIS_MULTI(NullRendererImpl, IInner_vtbl, iface);
171 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
173 if (This->bAggregatable)
174 This->bUnkOuterValid = TRUE;
176 *ppv = NULL;
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);
189 if (*ppv)
191 IUnknown_AddRef((IUnknown *)(*ppv));
192 return S_OK;
195 if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
196 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
198 return E_NOINTERFACE;
201 static ULONG WINAPI NullRendererInner_AddRef(IUnknown * iface)
203 ICOM_THIS_MULTI(NullRendererImpl, IInner_vtbl, iface);
204 ULONG refCount = InterlockedIncrement(&This->filter.refCount);
206 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
208 return refCount;
211 static ULONG WINAPI NullRendererInner_Release(IUnknown * iface)
213 ICOM_THIS_MULTI(NullRendererImpl, IInner_vtbl, iface);
214 ULONG refCount = InterlockedDecrement(&This->filter.refCount);
216 TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
218 if (!refCount)
220 IPin *pConnectedTo;
222 if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
224 IPin_Disconnect(pConnectedTo);
225 IPin_Release(pConnectedTo);
227 IPin_Disconnect((IPin *)This->pInputPin);
228 IPin_Release((IPin *)This->pInputPin);
230 This->filter.lpVtbl = NULL;
231 if (This->seekthru_unk)
232 IUnknown_Release(This->seekthru_unk);
234 This->filter.csFilter.DebugInfo->Spare[0] = 0;
235 DeleteCriticalSection(&This->filter.csFilter);
237 TRACE("Destroying Null Renderer\n");
238 CoTaskMemFree(This);
239 return 0;
241 else
242 return refCount;
245 static const IUnknownVtbl IInner_VTable =
247 NullRendererInner_QueryInterface,
248 NullRendererInner_AddRef,
249 NullRendererInner_Release
252 static HRESULT WINAPI NullRenderer_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
254 NullRendererImpl *This = (NullRendererImpl *)iface;
256 if (This->bAggregatable)
257 This->bUnkOuterValid = TRUE;
259 if (This->pUnkOuter)
261 if (This->bAggregatable)
262 return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
264 if (IsEqualIID(riid, &IID_IUnknown))
266 HRESULT hr;
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;
275 *ppv = NULL;
276 return E_NOINTERFACE;
279 return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
282 static ULONG WINAPI NullRenderer_AddRef(IBaseFilter * iface)
284 NullRendererImpl *This = (NullRendererImpl *)iface;
286 if (This->pUnkOuter && This->bUnkOuterValid)
287 return IUnknown_AddRef(This->pUnkOuter);
288 return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
291 static ULONG WINAPI NullRenderer_Release(IBaseFilter * iface)
293 NullRendererImpl *This = (NullRendererImpl *)iface;
295 if (This->pUnkOuter && This->bUnkOuterValid)
296 return IUnknown_Release(This->pUnkOuter);
297 return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
300 /** IMediaFilter methods **/
302 static HRESULT WINAPI NullRenderer_Stop(IBaseFilter * iface)
304 NullRendererImpl *This = (NullRendererImpl *)iface;
306 TRACE("(%p/%p)->()\n", This, iface);
308 EnterCriticalSection(&This->filter.csFilter);
310 This->filter.state = State_Stopped;
311 MediaSeekingPassThru_ResetMediaTime(This->seekthru_unk);
313 LeaveCriticalSection(&This->filter.csFilter);
315 return S_OK;
318 static HRESULT WINAPI NullRenderer_Pause(IBaseFilter * iface)
320 NullRendererImpl *This = (NullRendererImpl *)iface;
322 TRACE("(%p/%p)->()\n", This, iface);
324 EnterCriticalSection(&This->filter.csFilter);
326 if (This->filter.state == State_Stopped)
327 This->pInputPin->end_of_stream = 0;
328 This->filter.state = State_Paused;
330 LeaveCriticalSection(&This->filter.csFilter);
332 return S_OK;
335 static HRESULT WINAPI NullRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
337 HRESULT hr = S_OK;
338 NullRendererImpl *This = (NullRendererImpl *)iface;
340 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
342 EnterCriticalSection(&This->filter.csFilter);
343 if (This->filter.state == State_Running)
344 goto out;
345 if (This->pInputPin->pin.pConnectedTo)
347 This->filter.rtStreamStart = tStart;
348 This->pInputPin->end_of_stream = 0;
350 else if (This->filter.filterInfo.pGraph)
352 IMediaEventSink *pEventSink;
353 hr = IFilterGraph_QueryInterface(This->filter.filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
354 if (SUCCEEDED(hr))
356 hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, (LONG_PTR)This);
357 IMediaEventSink_Release(pEventSink);
359 hr = S_OK;
361 if (SUCCEEDED(hr))
362 This->filter.state = State_Running;
363 out:
364 LeaveCriticalSection(&This->filter.csFilter);
366 return hr;
369 /** IBaseFilter implementation **/
371 static HRESULT WINAPI NullRenderer_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
373 NullRendererImpl *This = (NullRendererImpl *)iface;
375 TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
377 if (!Id || !ppPin)
378 return E_POINTER;
380 if (!lstrcmpiW(Id,wcsInputPinName) || !lstrcmpiW(Id,wcsAltInputPinName))
382 *ppPin = (IPin *)This->pInputPin;
383 IPin_AddRef(*ppPin);
384 return S_OK;
386 *ppPin = NULL;
387 return VFW_E_NOT_FOUND;
390 static const IBaseFilterVtbl NullRenderer_Vtbl =
392 NullRenderer_QueryInterface,
393 NullRenderer_AddRef,
394 NullRenderer_Release,
395 BaseFilterImpl_GetClassID,
396 NullRenderer_Stop,
397 NullRenderer_Pause,
398 NullRenderer_Run,
399 BaseFilterImpl_GetState,
400 BaseFilterImpl_SetSyncSource,
401 BaseFilterImpl_GetSyncSource,
402 BaseFilterImpl_EnumPins,
403 NullRenderer_FindPin,
404 BaseFilterImpl_QueryFilterInfo,
405 BaseFilterImpl_JoinFilterGraph,
406 BaseFilterImpl_QueryVendorInfo
409 static HRESULT WINAPI NullRenderer_InputPin_EndOfStream(IPin * iface)
411 BaseInputPin* This = (BaseInputPin*)iface;
412 IMediaEventSink* pEventSink;
413 NullRendererImpl *pNull;
414 IFilterGraph *graph;
415 HRESULT hr = S_OK;
417 TRACE("(%p/%p)->()\n", This, iface);
419 BaseInputPinImpl_EndOfStream(iface);
420 pNull = (NullRendererImpl*)This->pin.pinInfo.pFilter;
421 graph = pNull->filter.filterInfo.pGraph;
422 if (graph)
424 hr = IFilterGraph_QueryInterface(pNull->filter.filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
425 if (SUCCEEDED(hr))
427 hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, (LONG_PTR)pNull);
428 IMediaEventSink_Release(pEventSink);
431 MediaSeekingPassThru_EOS(pNull->seekthru_unk);
433 return hr;
436 static HRESULT WINAPI NullRenderer_InputPin_EndFlush(IPin * iface)
438 BaseInputPin* This = (BaseInputPin*)iface;
439 NullRendererImpl *pNull;
440 HRESULT hr = S_OK;
442 TRACE("(%p/%p)->()\n", This, iface);
444 hr = BaseInputPinImpl_EndOfStream(iface);
445 pNull = (NullRendererImpl*)This->pin.pinInfo.pFilter;
446 MediaSeekingPassThru_ResetMediaTime(pNull->seekthru_unk);
447 return hr;
450 static const IPinVtbl NullRenderer_InputPin_Vtbl =
452 BaseInputPinImpl_QueryInterface,
453 BasePinImpl_AddRef,
454 BaseInputPinImpl_Release,
455 BaseInputPinImpl_Connect,
456 BaseInputPinImpl_ReceiveConnection,
457 BasePinImpl_Disconnect,
458 BasePinImpl_ConnectedTo,
459 BasePinImpl_ConnectionMediaType,
460 BasePinImpl_QueryPinInfo,
461 BasePinImpl_QueryDirection,
462 BasePinImpl_QueryId,
463 BaseInputPinImpl_QueryAccept,
464 BasePinImpl_EnumMediaTypes,
465 BasePinImpl_QueryInternalConnections,
466 NullRenderer_InputPin_EndOfStream,
467 BaseInputPinImpl_BeginFlush,
468 NullRenderer_InputPin_EndFlush,
469 BaseInputPinImpl_NewSegment