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
24 #define NONAMELESSSTRUCT
25 #define NONAMELESSUNION
26 #include "quartz_private.h"
27 #include "control_private.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
55 const IUnknownVtbl
* IInner_vtbl
;
56 IUnknown
*seekthru_unk
;
58 BaseInputPin
*pInputPin
;
64 static HRESULT WINAPI
NullRenderer_Receive(IPin
*iface
, IMediaSample
* pSample
)
66 BaseInputPin
*pin
= (BaseInputPin
*)iface
;
67 NullRendererImpl
*This
= ((NullRendererImpl
*)pin
->pin
.pinInfo
.pFilter
);
69 REFERENCE_TIME start
, stop
;
71 TRACE("%p %p\n", iface
, pSample
);
73 if (SUCCEEDED(IMediaSample_GetTime(pSample
, &start
, &stop
)))
74 MediaSeekingPassThru_RegisterMediaTime(This
->seekthru_unk
, start
);
75 EnterCriticalSection(&This
->filter
.csFilter
);
76 if (This
->pInputPin
->flushing
|| This
->pInputPin
->end_of_stream
)
78 LeaveCriticalSection(&This
->filter
.csFilter
);
83 static HRESULT WINAPI
NullRenderer_CheckMediaType(IPin
*iface
, const AM_MEDIA_TYPE
* pmt
)
85 TRACE("Not a stub!\n");
89 HRESULT
NullRenderer_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
93 NullRendererImpl
* pNullRenderer
;
95 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
99 pNullRenderer
= CoTaskMemAlloc(sizeof(NullRendererImpl
));
100 pNullRenderer
->pUnkOuter
= pUnkOuter
;
101 pNullRenderer
->bUnkOuterValid
= FALSE
;
102 pNullRenderer
->bAggregatable
= FALSE
;
103 pNullRenderer
->IInner_vtbl
= &IInner_VTable
;
105 BaseFilter_Init(&pNullRenderer
->filter
, &NullRenderer_Vtbl
, &CLSID_NullRenderer
, (DWORD_PTR
)(__FILE__
": NullRendererImpl.csFilter"));
107 /* construct input pin */
108 piInput
.dir
= PINDIR_INPUT
;
109 piInput
.pFilter
= (IBaseFilter
*)pNullRenderer
;
110 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
112 hr
= BaseInputPin_Construct(&NullRenderer_InputPin_Vtbl
, &piInput
, NullRenderer_CheckMediaType
, NullRenderer_Receive
, &pNullRenderer
->filter
.csFilter
, NULL
, (IPin
**)&pNullRenderer
->pInputPin
);
116 ISeekingPassThru
*passthru
;
117 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, pUnkOuter
? pUnkOuter
: (IUnknown
*)&pNullRenderer
->IInner_vtbl
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)&pNullRenderer
->seekthru_unk
);
119 IUnknown_Release((IUnknown
*)pNullRenderer
);
122 IUnknown_QueryInterface(pNullRenderer
->seekthru_unk
, &IID_ISeekingPassThru
, (void**)&passthru
);
123 ISeekingPassThru_Init(passthru
, TRUE
, (IPin
*)pNullRenderer
->pInputPin
);
124 ISeekingPassThru_Release(passthru
);
125 *ppv
= pNullRenderer
;
129 BaseFilterImpl_Release((IBaseFilter
*)pNullRenderer
);
130 CoTaskMemFree(pNullRenderer
);
136 static HRESULT WINAPI
NullRendererInner_QueryInterface(IUnknown
* iface
, REFIID riid
, LPVOID
* ppv
)
138 ICOM_THIS_MULTI(NullRendererImpl
, IInner_vtbl
, iface
);
139 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
141 if (This
->bAggregatable
)
142 This
->bUnkOuterValid
= TRUE
;
146 if (IsEqualIID(riid
, &IID_IUnknown
))
147 *ppv
= &This
->IInner_vtbl
;
148 else if (IsEqualIID(riid
, &IID_IPersist
))
150 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
152 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
154 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
155 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
159 IUnknown_AddRef((IUnknown
*)(*ppv
));
163 if (!IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
))
164 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
166 return E_NOINTERFACE
;
169 static ULONG WINAPI
NullRendererInner_AddRef(IUnknown
* iface
)
171 ICOM_THIS_MULTI(NullRendererImpl
, IInner_vtbl
, iface
);
172 ULONG refCount
= InterlockedIncrement(&This
->filter
.refCount
);
174 TRACE("(%p/%p)->() AddRef from %d\n", This
, iface
, refCount
- 1);
179 static ULONG WINAPI
NullRendererInner_Release(IUnknown
* iface
)
181 ICOM_THIS_MULTI(NullRendererImpl
, IInner_vtbl
, iface
);
182 ULONG refCount
= InterlockedDecrement(&This
->filter
.refCount
);
184 TRACE("(%p/%p)->() Release from %d\n", This
, iface
, refCount
+ 1);
190 if (SUCCEEDED(IPin_ConnectedTo((IPin
*)This
->pInputPin
, &pConnectedTo
)))
192 IPin_Disconnect(pConnectedTo
);
193 IPin_Release(pConnectedTo
);
195 IPin_Disconnect((IPin
*)This
->pInputPin
);
196 IPin_Release((IPin
*)This
->pInputPin
);
198 This
->filter
.lpVtbl
= NULL
;
199 if (This
->seekthru_unk
)
200 IUnknown_Release(This
->seekthru_unk
);
202 This
->filter
.csFilter
.DebugInfo
->Spare
[0] = 0;
203 DeleteCriticalSection(&This
->filter
.csFilter
);
205 TRACE("Destroying Null Renderer\n");
213 static const IUnknownVtbl IInner_VTable
=
215 NullRendererInner_QueryInterface
,
216 NullRendererInner_AddRef
,
217 NullRendererInner_Release
220 static HRESULT WINAPI
NullRenderer_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
222 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
224 if (This
->bAggregatable
)
225 This
->bUnkOuterValid
= TRUE
;
229 if (This
->bAggregatable
)
230 return IUnknown_QueryInterface(This
->pUnkOuter
, riid
, ppv
);
232 if (IsEqualIID(riid
, &IID_IUnknown
))
236 IUnknown_AddRef((IUnknown
*)&(This
->IInner_vtbl
));
237 hr
= IUnknown_QueryInterface((IUnknown
*)&(This
->IInner_vtbl
), riid
, ppv
);
238 IUnknown_Release((IUnknown
*)&(This
->IInner_vtbl
));
239 This
->bAggregatable
= TRUE
;
244 return E_NOINTERFACE
;
247 return IUnknown_QueryInterface((IUnknown
*)&(This
->IInner_vtbl
), riid
, ppv
);
250 static ULONG WINAPI
NullRenderer_AddRef(IBaseFilter
* iface
)
252 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
254 if (This
->pUnkOuter
&& This
->bUnkOuterValid
)
255 return IUnknown_AddRef(This
->pUnkOuter
);
256 return IUnknown_AddRef((IUnknown
*)&(This
->IInner_vtbl
));
259 static ULONG WINAPI
NullRenderer_Release(IBaseFilter
* iface
)
261 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
263 if (This
->pUnkOuter
&& This
->bUnkOuterValid
)
264 return IUnknown_Release(This
->pUnkOuter
);
265 return IUnknown_Release((IUnknown
*)&(This
->IInner_vtbl
));
268 /** IMediaFilter methods **/
270 static HRESULT WINAPI
NullRenderer_Stop(IBaseFilter
* iface
)
272 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
274 TRACE("(%p/%p)->()\n", This
, iface
);
276 EnterCriticalSection(&This
->filter
.csFilter
);
278 This
->filter
.state
= State_Stopped
;
279 MediaSeekingPassThru_ResetMediaTime(This
->seekthru_unk
);
281 LeaveCriticalSection(&This
->filter
.csFilter
);
286 static HRESULT WINAPI
NullRenderer_Pause(IBaseFilter
* iface
)
288 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
290 TRACE("(%p/%p)->()\n", This
, iface
);
292 EnterCriticalSection(&This
->filter
.csFilter
);
294 if (This
->filter
.state
== State_Stopped
)
295 This
->pInputPin
->end_of_stream
= 0;
296 This
->filter
.state
= State_Paused
;
298 LeaveCriticalSection(&This
->filter
.csFilter
);
303 static HRESULT WINAPI
NullRenderer_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
305 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
307 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
309 EnterCriticalSection(&This
->filter
.csFilter
);
311 This
->filter
.rtStreamStart
= tStart
;
312 This
->filter
.state
= State_Running
;
313 This
->pInputPin
->end_of_stream
= 0;
315 LeaveCriticalSection(&This
->filter
.csFilter
);
320 /** IBaseFilter implementation **/
322 static IPin
* WINAPI
NullRenderer_GetPin(IBaseFilter
*iface
, int pos
)
324 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
326 if (pos
>= 1 || pos
< 0)
329 IPin_AddRef((IPin
*)This
->pInputPin
);
330 return (IPin
*)This
->pInputPin
;
333 static LONG WINAPI
NullRenderer_GetPinCount(IBaseFilter
*iface
)
338 static LONG WINAPI
NullRenderer_GetPinVersion(IBaseFilter
*iface
)
340 /* Our pins are static, not changing so setting static tick count is ok */
344 static HRESULT WINAPI
NullRenderer_EnumPins(IBaseFilter
* iface
, IEnumPins
**ppEnum
)
346 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
348 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppEnum
);
350 return EnumPins_Construct(iface
, NullRenderer_GetPin
, NullRenderer_GetPinCount
, NullRenderer_GetPinVersion
, ppEnum
);
353 static HRESULT WINAPI
NullRenderer_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
355 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
357 TRACE("(%p/%p)->(%p,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
362 if (!lstrcmpiW(Id
,wcsInputPinName
) || !lstrcmpiW(Id
,wcsAltInputPinName
))
364 *ppPin
= (IPin
*)This
->pInputPin
;
369 return VFW_E_NOT_FOUND
;
372 static const IBaseFilterVtbl NullRenderer_Vtbl
=
374 NullRenderer_QueryInterface
,
376 NullRenderer_Release
,
377 BaseFilterImpl_GetClassID
,
381 BaseFilterImpl_GetState
,
382 BaseFilterImpl_SetSyncSource
,
383 BaseFilterImpl_GetSyncSource
,
384 NullRenderer_EnumPins
,
385 NullRenderer_FindPin
,
386 BaseFilterImpl_QueryFilterInfo
,
387 BaseFilterImpl_JoinFilterGraph
,
388 BaseFilterImpl_QueryVendorInfo
391 static HRESULT WINAPI
NullRenderer_InputPin_EndOfStream(IPin
* iface
)
393 BaseInputPin
* This
= (BaseInputPin
*)iface
;
394 IMediaEventSink
* pEventSink
;
395 NullRendererImpl
*pNull
;
399 TRACE("(%p/%p)->()\n", This
, iface
);
401 BaseInputPinImpl_EndOfStream(iface
);
402 pNull
= (NullRendererImpl
*)This
->pin
.pinInfo
.pFilter
;
403 graph
= pNull
->filter
.filterInfo
.pGraph
;
406 hr
= IFilterGraph_QueryInterface(((NullRendererImpl
*)This
->pin
.pinInfo
.pFilter
)->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
409 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, 0);
410 IMediaEventSink_Release(pEventSink
);
413 MediaSeekingPassThru_EOS(pNull
->seekthru_unk
);
418 static HRESULT WINAPI
NullRenderer_InputPin_EndFlush(IPin
* iface
)
420 BaseInputPin
* This
= (BaseInputPin
*)iface
;
421 NullRendererImpl
*pNull
;
424 TRACE("(%p/%p)->()\n", This
, iface
);
426 hr
= BaseInputPinImpl_EndOfStream(iface
);
427 pNull
= (NullRendererImpl
*)This
->pin
.pinInfo
.pFilter
;
428 MediaSeekingPassThru_ResetMediaTime(pNull
->seekthru_unk
);
432 static const IPinVtbl NullRenderer_InputPin_Vtbl
=
434 BaseInputPinImpl_QueryInterface
,
436 BaseInputPinImpl_Release
,
437 BaseInputPinImpl_Connect
,
438 BaseInputPinImpl_ReceiveConnection
,
439 BasePinImpl_Disconnect
,
440 BasePinImpl_ConnectedTo
,
441 BasePinImpl_ConnectionMediaType
,
442 BasePinImpl_QueryPinInfo
,
443 BasePinImpl_QueryDirection
,
445 BaseInputPinImpl_QueryAccept
,
446 BasePinImpl_EnumMediaTypes
,
447 BasePinImpl_QueryInternalConnections
,
448 NullRenderer_InputPin_EndOfStream
,
449 BaseInputPinImpl_BeginFlush
,
450 NullRenderer_InputPin_EndFlush
,
451 BaseInputPinImpl_NewSegment