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
54 const IBaseFilterVtbl
* lpVtbl
;
55 const IUnknownVtbl
* IInner_vtbl
;
56 IUnknown
*seekthru_unk
;
59 CRITICAL_SECTION csFilter
;
61 REFERENCE_TIME rtStreamStart
;
62 IReferenceClock
* pClock
;
63 FILTER_INFO filterInfo
;
65 BaseInputPin
*pInputPin
;
71 static HRESULT WINAPI
NullRenderer_Receive(IPin
*iface
, IMediaSample
* pSample
)
73 BaseInputPin
*pin
= (BaseInputPin
*)iface
;
74 NullRendererImpl
*This
= ((NullRendererImpl
*)pin
->pin
.pinInfo
.pFilter
);
76 REFERENCE_TIME start
, stop
;
78 TRACE("%p %p\n", iface
, pSample
);
80 if (SUCCEEDED(IMediaSample_GetTime(pSample
, &start
, &stop
)))
81 MediaSeekingPassThru_RegisterMediaTime(This
->seekthru_unk
, start
);
82 EnterCriticalSection(&This
->csFilter
);
83 if (This
->pInputPin
->flushing
|| This
->pInputPin
->end_of_stream
)
85 LeaveCriticalSection(&This
->csFilter
);
90 static HRESULT WINAPI
NullRenderer_CheckMediaType(IPin
*iface
, const AM_MEDIA_TYPE
* pmt
)
92 TRACE("Not a stub!\n");
96 HRESULT
NullRenderer_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
100 NullRendererImpl
* pNullRenderer
;
102 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
106 pNullRenderer
= CoTaskMemAlloc(sizeof(NullRendererImpl
));
107 pNullRenderer
->pUnkOuter
= pUnkOuter
;
108 pNullRenderer
->bUnkOuterValid
= FALSE
;
109 pNullRenderer
->bAggregatable
= FALSE
;
110 pNullRenderer
->IInner_vtbl
= &IInner_VTable
;
112 pNullRenderer
->lpVtbl
= &NullRenderer_Vtbl
;
113 pNullRenderer
->refCount
= 1;
114 InitializeCriticalSection(&pNullRenderer
->csFilter
);
115 pNullRenderer
->csFilter
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": NullRendererImpl.csFilter");
116 pNullRenderer
->state
= State_Stopped
;
117 pNullRenderer
->pClock
= NULL
;
118 ZeroMemory(&pNullRenderer
->filterInfo
, sizeof(FILTER_INFO
));
120 /* construct input pin */
121 piInput
.dir
= PINDIR_INPUT
;
122 piInput
.pFilter
= (IBaseFilter
*)pNullRenderer
;
123 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
125 hr
= BaseInputPin_Construct(&NullRenderer_InputPin_Vtbl
, &piInput
, NullRenderer_CheckMediaType
, NullRenderer_Receive
, &pNullRenderer
->csFilter
, NULL
, (IPin
**)&pNullRenderer
->pInputPin
);
129 ISeekingPassThru
*passthru
;
130 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, pUnkOuter
? pUnkOuter
: (IUnknown
*)&pNullRenderer
->IInner_vtbl
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)&pNullRenderer
->seekthru_unk
);
132 IUnknown_Release((IUnknown
*)pNullRenderer
);
135 IUnknown_QueryInterface(pNullRenderer
->seekthru_unk
, &IID_ISeekingPassThru
, (void**)&passthru
);
136 ISeekingPassThru_Init(passthru
, TRUE
, (IPin
*)pNullRenderer
->pInputPin
);
137 ISeekingPassThru_Release(passthru
);
138 *ppv
= pNullRenderer
;
142 pNullRenderer
->csFilter
.DebugInfo
->Spare
[0] = 0;
143 DeleteCriticalSection(&pNullRenderer
->csFilter
);
144 CoTaskMemFree(pNullRenderer
);
150 static HRESULT WINAPI
NullRendererInner_QueryInterface(IUnknown
* iface
, REFIID riid
, LPVOID
* ppv
)
152 ICOM_THIS_MULTI(NullRendererImpl
, IInner_vtbl
, iface
);
153 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
155 if (This
->bAggregatable
)
156 This
->bUnkOuterValid
= TRUE
;
160 if (IsEqualIID(riid
, &IID_IUnknown
))
161 *ppv
= &This
->IInner_vtbl
;
162 else if (IsEqualIID(riid
, &IID_IPersist
))
164 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
166 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
168 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
169 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
173 IUnknown_AddRef((IUnknown
*)(*ppv
));
177 if (!IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
))
178 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
180 return E_NOINTERFACE
;
183 static ULONG WINAPI
NullRendererInner_AddRef(IUnknown
* iface
)
185 ICOM_THIS_MULTI(NullRendererImpl
, IInner_vtbl
, iface
);
186 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
188 TRACE("(%p/%p)->() AddRef from %d\n", This
, iface
, refCount
- 1);
193 static ULONG WINAPI
NullRendererInner_Release(IUnknown
* iface
)
195 ICOM_THIS_MULTI(NullRendererImpl
, IInner_vtbl
, iface
);
196 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
198 TRACE("(%p/%p)->() Release from %d\n", This
, iface
, refCount
+ 1);
205 IReferenceClock_Release(This
->pClock
);
207 if (SUCCEEDED(IPin_ConnectedTo((IPin
*)This
->pInputPin
, &pConnectedTo
)))
209 IPin_Disconnect(pConnectedTo
);
210 IPin_Release(pConnectedTo
);
212 IPin_Disconnect((IPin
*)This
->pInputPin
);
213 IPin_Release((IPin
*)This
->pInputPin
);
216 if (This
->seekthru_unk
)
217 IUnknown_Release(This
->seekthru_unk
);
219 This
->csFilter
.DebugInfo
->Spare
[0] = 0;
220 DeleteCriticalSection(&This
->csFilter
);
222 TRACE("Destroying Null Renderer\n");
230 static const IUnknownVtbl IInner_VTable
=
232 NullRendererInner_QueryInterface
,
233 NullRendererInner_AddRef
,
234 NullRendererInner_Release
237 static HRESULT WINAPI
NullRenderer_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
239 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
241 if (This
->bAggregatable
)
242 This
->bUnkOuterValid
= TRUE
;
246 if (This
->bAggregatable
)
247 return IUnknown_QueryInterface(This
->pUnkOuter
, riid
, ppv
);
249 if (IsEqualIID(riid
, &IID_IUnknown
))
253 IUnknown_AddRef((IUnknown
*)&(This
->IInner_vtbl
));
254 hr
= IUnknown_QueryInterface((IUnknown
*)&(This
->IInner_vtbl
), riid
, ppv
);
255 IUnknown_Release((IUnknown
*)&(This
->IInner_vtbl
));
256 This
->bAggregatable
= TRUE
;
261 return E_NOINTERFACE
;
264 return IUnknown_QueryInterface((IUnknown
*)&(This
->IInner_vtbl
), riid
, ppv
);
267 static ULONG WINAPI
NullRenderer_AddRef(IBaseFilter
* iface
)
269 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
271 if (This
->pUnkOuter
&& This
->bUnkOuterValid
)
272 return IUnknown_AddRef(This
->pUnkOuter
);
273 return IUnknown_AddRef((IUnknown
*)&(This
->IInner_vtbl
));
276 static ULONG WINAPI
NullRenderer_Release(IBaseFilter
* iface
)
278 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
280 if (This
->pUnkOuter
&& This
->bUnkOuterValid
)
281 return IUnknown_Release(This
->pUnkOuter
);
282 return IUnknown_Release((IUnknown
*)&(This
->IInner_vtbl
));
285 /** IPersist methods **/
287 static HRESULT WINAPI
NullRenderer_GetClassID(IBaseFilter
* iface
, CLSID
* pClsid
)
289 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
291 TRACE("(%p/%p)->(%p)\n", This
, iface
, pClsid
);
293 *pClsid
= CLSID_NullRenderer
;
298 /** IMediaFilter methods **/
300 static HRESULT WINAPI
NullRenderer_Stop(IBaseFilter
* iface
)
302 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
304 TRACE("(%p/%p)->()\n", This
, iface
);
306 EnterCriticalSection(&This
->csFilter
);
308 This
->state
= State_Stopped
;
309 MediaSeekingPassThru_ResetMediaTime(This
->seekthru_unk
);
311 LeaveCriticalSection(&This
->csFilter
);
316 static HRESULT WINAPI
NullRenderer_Pause(IBaseFilter
* iface
)
318 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
320 TRACE("(%p/%p)->()\n", This
, iface
);
322 EnterCriticalSection(&This
->csFilter
);
324 if (This
->state
== State_Stopped
)
325 This
->pInputPin
->end_of_stream
= 0;
326 This
->state
= State_Paused
;
328 LeaveCriticalSection(&This
->csFilter
);
333 static HRESULT WINAPI
NullRenderer_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
335 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
337 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
339 EnterCriticalSection(&This
->csFilter
);
341 This
->rtStreamStart
= tStart
;
342 This
->state
= State_Running
;
343 This
->pInputPin
->end_of_stream
= 0;
345 LeaveCriticalSection(&This
->csFilter
);
350 static HRESULT WINAPI
NullRenderer_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
352 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
354 TRACE("(%p/%p)->(%d, %p)\n", This
, iface
, dwMilliSecsTimeout
, pState
);
356 EnterCriticalSection(&This
->csFilter
);
358 *pState
= This
->state
;
360 LeaveCriticalSection(&This
->csFilter
);
365 static HRESULT WINAPI
NullRenderer_SetSyncSource(IBaseFilter
* iface
, IReferenceClock
*pClock
)
367 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
369 TRACE("(%p/%p)->(%p)\n", This
, iface
, pClock
);
371 EnterCriticalSection(&This
->csFilter
);
374 IReferenceClock_Release(This
->pClock
);
375 This
->pClock
= pClock
;
377 IReferenceClock_AddRef(This
->pClock
);
379 LeaveCriticalSection(&This
->csFilter
);
384 static HRESULT WINAPI
NullRenderer_GetSyncSource(IBaseFilter
* iface
, IReferenceClock
**ppClock
)
386 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
388 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppClock
);
390 EnterCriticalSection(&This
->csFilter
);
392 *ppClock
= This
->pClock
;
394 IReferenceClock_AddRef(This
->pClock
);
396 LeaveCriticalSection(&This
->csFilter
);
401 /** IBaseFilter implementation **/
403 static IPin
* WINAPI
NullRenderer_GetPin(IBaseFilter
*iface
, int pos
)
405 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
407 if (pos
>= 1 || pos
< 0)
410 IPin_AddRef((IPin
*)This
->pInputPin
);
411 return (IPin
*)This
->pInputPin
;
414 static LONG WINAPI
NullRenderer_GetPinCount(IBaseFilter
*iface
)
419 static LONG WINAPI
NullRenderer_GetPinVersion(IBaseFilter
*iface
)
421 /* Our pins are static, not changing so setting static tick count is ok */
425 static HRESULT WINAPI
NullRenderer_EnumPins(IBaseFilter
* iface
, IEnumPins
**ppEnum
)
427 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
429 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppEnum
);
431 return EnumPins_Construct(iface
, NullRenderer_GetPin
, NullRenderer_GetPinCount
, NullRenderer_GetPinVersion
, ppEnum
);
434 static HRESULT WINAPI
NullRenderer_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
436 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
438 TRACE("(%p/%p)->(%p,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
443 if (!lstrcmpiW(Id
,wcsInputPinName
) || !lstrcmpiW(Id
,wcsAltInputPinName
))
445 *ppPin
= (IPin
*)This
->pInputPin
;
450 return VFW_E_NOT_FOUND
;
453 static HRESULT WINAPI
NullRenderer_QueryFilterInfo(IBaseFilter
* iface
, FILTER_INFO
*pInfo
)
455 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
457 TRACE("(%p/%p)->(%p)\n", This
, iface
, pInfo
);
459 strcpyW(pInfo
->achName
, This
->filterInfo
.achName
);
460 pInfo
->pGraph
= This
->filterInfo
.pGraph
;
463 IFilterGraph_AddRef(pInfo
->pGraph
);
468 static HRESULT WINAPI
NullRenderer_JoinFilterGraph(IBaseFilter
* iface
, IFilterGraph
*pGraph
, LPCWSTR pName
)
470 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
472 TRACE("(%p/%p)->(%p, %s)\n", This
, iface
, pGraph
, debugstr_w(pName
));
474 EnterCriticalSection(&This
->csFilter
);
477 strcpyW(This
->filterInfo
.achName
, pName
);
479 *This
->filterInfo
.achName
= '\0';
480 This
->filterInfo
.pGraph
= pGraph
; /* NOTE: do NOT increase ref. count */
482 LeaveCriticalSection(&This
->csFilter
);
487 static HRESULT WINAPI
NullRenderer_QueryVendorInfo(IBaseFilter
* iface
, LPWSTR
*pVendorInfo
)
489 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
490 TRACE("(%p/%p)->(%p)\n", This
, iface
, pVendorInfo
);
494 static const IBaseFilterVtbl NullRenderer_Vtbl
=
496 NullRenderer_QueryInterface
,
498 NullRenderer_Release
,
499 NullRenderer_GetClassID
,
503 NullRenderer_GetState
,
504 NullRenderer_SetSyncSource
,
505 NullRenderer_GetSyncSource
,
506 NullRenderer_EnumPins
,
507 NullRenderer_FindPin
,
508 NullRenderer_QueryFilterInfo
,
509 NullRenderer_JoinFilterGraph
,
510 NullRenderer_QueryVendorInfo
513 static HRESULT WINAPI
NullRenderer_InputPin_EndOfStream(IPin
* iface
)
515 BaseInputPin
* This
= (BaseInputPin
*)iface
;
516 IMediaEventSink
* pEventSink
;
517 NullRendererImpl
*pNull
;
521 TRACE("(%p/%p)->()\n", This
, iface
);
523 BaseInputPinImpl_EndOfStream(iface
);
524 pNull
= (NullRendererImpl
*)This
->pin
.pinInfo
.pFilter
;
525 graph
= pNull
->filterInfo
.pGraph
;
528 hr
= IFilterGraph_QueryInterface(((NullRendererImpl
*)This
->pin
.pinInfo
.pFilter
)->filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
531 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, 0);
532 IMediaEventSink_Release(pEventSink
);
535 MediaSeekingPassThru_EOS(pNull
->seekthru_unk
);
540 static HRESULT WINAPI
NullRenderer_InputPin_EndFlush(IPin
* iface
)
542 BaseInputPin
* This
= (BaseInputPin
*)iface
;
543 NullRendererImpl
*pNull
;
546 TRACE("(%p/%p)->()\n", This
, iface
);
548 hr
= BaseInputPinImpl_EndOfStream(iface
);
549 pNull
= (NullRendererImpl
*)This
->pin
.pinInfo
.pFilter
;
550 MediaSeekingPassThru_ResetMediaTime(pNull
->seekthru_unk
);
554 static const IPinVtbl NullRenderer_InputPin_Vtbl
=
556 BaseInputPinImpl_QueryInterface
,
558 BaseInputPinImpl_Release
,
559 BaseInputPinImpl_Connect
,
560 BaseInputPinImpl_ReceiveConnection
,
561 BasePinImpl_Disconnect
,
562 BasePinImpl_ConnectedTo
,
563 BasePinImpl_ConnectionMediaType
,
564 BasePinImpl_QueryPinInfo
,
565 BasePinImpl_QueryDirection
,
567 BaseInputPinImpl_QueryAccept
,
568 BasePinImpl_EnumMediaTypes
,
569 BasePinImpl_QueryInternalConnections
,
570 NullRenderer_InputPin_EndOfStream
,
571 BaseInputPinImpl_BeginFlush
,
572 NullRenderer_InputPin_EndFlush
,
573 BaseInputPinImpl_NewSegment