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};
47 static const IBaseFilterVtbl NullRenderer_Vtbl
;
48 static const IUnknownVtbl IInner_VTable
;
49 static const IPinVtbl NullRenderer_InputPin_Vtbl
;
51 typedef struct NullRendererImpl
53 const IBaseFilterVtbl
* lpVtbl
;
54 const IUnknownVtbl
* IInner_vtbl
;
57 CRITICAL_SECTION csFilter
;
59 REFERENCE_TIME rtStreamStart
;
60 IReferenceClock
* pClock
;
61 FILTER_INFO filterInfo
;
67 MediaSeekingImpl mediaSeeking
;
70 static const IMemInputPinVtbl MemInputPin_Vtbl
=
72 MemInputPin_QueryInterface
,
75 MemInputPin_GetAllocator
,
76 MemInputPin_NotifyAllocator
,
77 MemInputPin_GetAllocatorRequirements
,
79 MemInputPin_ReceiveMultiple
,
80 MemInputPin_ReceiveCanBlock
83 static HRESULT
NullRenderer_Sample(LPVOID iface
, IMediaSample
* pSample
)
85 LPBYTE pbSrcStream
= NULL
;
87 REFERENCE_TIME tStart
, tStop
;
90 TRACE("%p %p\n", iface
, pSample
);
92 hr
= IMediaSample_GetPointer(pSample
, &pbSrcStream
);
95 ERR("Cannot get pointer to sample data (%x)\n", hr
);
99 hr
= IMediaSample_GetTime(pSample
, &tStart
, &tStop
);
101 ERR("Cannot get sample time (%x)\n", hr
);
103 cbSrcStream
= IMediaSample_GetActualDataLength(pSample
);
105 TRACE("val %p %ld\n", pbSrcStream
, cbSrcStream
);
110 static HRESULT
NullRenderer_QueryAccept(LPVOID iface
, const AM_MEDIA_TYPE
* pmt
)
112 TRACE("Not a stub!\n");
116 static inline NullRendererImpl
*impl_from_IMediaSeeking( IMediaSeeking
*iface
)
118 return (NullRendererImpl
*)((char*)iface
- FIELD_OFFSET(NullRendererImpl
, mediaSeeking
.lpVtbl
));
121 static HRESULT WINAPI
NullRendererImpl_Seeking_QueryInterface(IMediaSeeking
* iface
, REFIID riid
, LPVOID
* ppv
)
123 NullRendererImpl
*This
= impl_from_IMediaSeeking(iface
);
125 return IUnknown_QueryInterface((IUnknown
*)This
, riid
, ppv
);
128 static ULONG WINAPI
NullRendererImpl_Seeking_AddRef(IMediaSeeking
* iface
)
130 NullRendererImpl
*This
= impl_from_IMediaSeeking(iface
);
132 return IUnknown_AddRef((IUnknown
*)This
);
135 static ULONG WINAPI
NullRendererImpl_Seeking_Release(IMediaSeeking
* iface
)
137 NullRendererImpl
*This
= impl_from_IMediaSeeking(iface
);
139 return IUnknown_Release((IUnknown
*)This
);
142 static const IMediaSeekingVtbl TransformFilter_Seeking_Vtbl
=
144 NullRendererImpl_Seeking_QueryInterface
,
145 NullRendererImpl_Seeking_AddRef
,
146 NullRendererImpl_Seeking_Release
,
147 MediaSeekingImpl_GetCapabilities
,
148 MediaSeekingImpl_CheckCapabilities
,
149 MediaSeekingImpl_IsFormatSupported
,
150 MediaSeekingImpl_QueryPreferredFormat
,
151 MediaSeekingImpl_GetTimeFormat
,
152 MediaSeekingImpl_IsUsingTimeFormat
,
153 MediaSeekingImpl_SetTimeFormat
,
154 MediaSeekingImpl_GetDuration
,
155 MediaSeekingImpl_GetStopPosition
,
156 MediaSeekingImpl_GetCurrentPosition
,
157 MediaSeekingImpl_ConvertTimeFormat
,
158 MediaSeekingImpl_SetPositions
,
159 MediaSeekingImpl_GetPositions
,
160 MediaSeekingImpl_GetAvailable
,
161 MediaSeekingImpl_SetRate
,
162 MediaSeekingImpl_GetRate
,
163 MediaSeekingImpl_GetPreroll
166 static HRESULT
NullRendererImpl_Change(IBaseFilter
*iface
)
168 TRACE("(%p)\n", iface
);
172 HRESULT
NullRenderer_create(IUnknown
* pUnkOuter
, LPVOID
* ppv
)
176 NullRendererImpl
* pNullRenderer
;
178 TRACE("(%p, %p)\n", pUnkOuter
, ppv
);
182 pNullRenderer
= CoTaskMemAlloc(sizeof(NullRendererImpl
));
183 pNullRenderer
->pUnkOuter
= pUnkOuter
;
184 pNullRenderer
->bUnkOuterValid
= FALSE
;
185 pNullRenderer
->bAggregatable
= FALSE
;
186 pNullRenderer
->IInner_vtbl
= &IInner_VTable
;
188 pNullRenderer
->lpVtbl
= &NullRenderer_Vtbl
;
189 pNullRenderer
->refCount
= 1;
190 InitializeCriticalSection(&pNullRenderer
->csFilter
);
191 pNullRenderer
->csFilter
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": NullRendererImpl.csFilter");
192 pNullRenderer
->state
= State_Stopped
;
193 pNullRenderer
->pClock
= NULL
;
194 ZeroMemory(&pNullRenderer
->filterInfo
, sizeof(FILTER_INFO
));
196 /* construct input pin */
197 piInput
.dir
= PINDIR_INPUT
;
198 piInput
.pFilter
= (IBaseFilter
*)pNullRenderer
;
199 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
201 hr
= InputPin_Construct(&NullRenderer_InputPin_Vtbl
, &piInput
, NullRenderer_Sample
, (LPVOID
)pNullRenderer
, NullRenderer_QueryAccept
, NULL
, &pNullRenderer
->csFilter
, NULL
, (IPin
**)&pNullRenderer
->pInputPin
);
205 MediaSeekingImpl_Init((IBaseFilter
*)pNullRenderer
, NullRendererImpl_Change
, NullRendererImpl_Change
, NullRendererImpl_Change
, &pNullRenderer
->mediaSeeking
, &pNullRenderer
->csFilter
);
206 pNullRenderer
->mediaSeeking
.lpVtbl
= &TransformFilter_Seeking_Vtbl
;
208 *ppv
= (LPVOID
)pNullRenderer
;
212 pNullRenderer
->csFilter
.DebugInfo
->Spare
[0] = 0;
213 DeleteCriticalSection(&pNullRenderer
->csFilter
);
214 CoTaskMemFree(pNullRenderer
);
220 static HRESULT WINAPI
NullRendererInner_QueryInterface(IUnknown
* iface
, REFIID riid
, LPVOID
* ppv
)
222 ICOM_THIS_MULTI(NullRendererImpl
, IInner_vtbl
, iface
);
223 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, qzdebugstr_guid(riid
), ppv
);
225 if (This
->bAggregatable
)
226 This
->bUnkOuterValid
= TRUE
;
230 if (IsEqualIID(riid
, &IID_IUnknown
))
231 *ppv
= (LPVOID
)&(This
->IInner_vtbl
);
232 else if (IsEqualIID(riid
, &IID_IPersist
))
234 else if (IsEqualIID(riid
, &IID_IMediaFilter
))
236 else if (IsEqualIID(riid
, &IID_IBaseFilter
))
238 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
239 *ppv
= &This
->mediaSeeking
;
243 IUnknown_AddRef((IUnknown
*)(*ppv
));
247 if (!IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
))
248 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
250 return E_NOINTERFACE
;
253 static ULONG WINAPI
NullRendererInner_AddRef(IUnknown
* iface
)
255 ICOM_THIS_MULTI(NullRendererImpl
, IInner_vtbl
, iface
);
256 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
258 TRACE("(%p/%p)->() AddRef from %d\n", This
, iface
, refCount
- 1);
263 static ULONG WINAPI
NullRendererInner_Release(IUnknown
* iface
)
265 ICOM_THIS_MULTI(NullRendererImpl
, IInner_vtbl
, iface
);
266 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
268 TRACE("(%p/%p)->() Release from %d\n", This
, iface
, refCount
+ 1);
275 IReferenceClock_Release(This
->pClock
);
277 if (SUCCEEDED(IPin_ConnectedTo((IPin
*)This
->pInputPin
, &pConnectedTo
)))
279 IPin_Disconnect(pConnectedTo
);
280 IPin_Release(pConnectedTo
);
282 IPin_Disconnect((IPin
*)This
->pInputPin
);
283 IPin_Release((IPin
*)This
->pInputPin
);
287 This
->csFilter
.DebugInfo
->Spare
[0] = 0;
288 DeleteCriticalSection(&This
->csFilter
);
290 TRACE("Destroying Null Renderer\n");
298 static const IUnknownVtbl IInner_VTable
=
300 NullRendererInner_QueryInterface
,
301 NullRendererInner_AddRef
,
302 NullRendererInner_Release
305 static HRESULT WINAPI
NullRenderer_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
307 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
309 if (This
->bAggregatable
)
310 This
->bUnkOuterValid
= TRUE
;
314 if (This
->bAggregatable
)
315 return IUnknown_QueryInterface(This
->pUnkOuter
, riid
, ppv
);
317 if (IsEqualIID(riid
, &IID_IUnknown
))
321 IUnknown_AddRef((IUnknown
*)&(This
->IInner_vtbl
));
322 hr
= IUnknown_QueryInterface((IUnknown
*)&(This
->IInner_vtbl
), riid
, ppv
);
323 IUnknown_Release((IUnknown
*)&(This
->IInner_vtbl
));
324 This
->bAggregatable
= TRUE
;
329 return E_NOINTERFACE
;
332 return IUnknown_QueryInterface((IUnknown
*)&(This
->IInner_vtbl
), riid
, ppv
);
335 static ULONG WINAPI
NullRenderer_AddRef(IBaseFilter
* iface
)
337 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
339 if (This
->pUnkOuter
&& This
->bUnkOuterValid
)
340 return IUnknown_AddRef(This
->pUnkOuter
);
341 return IUnknown_AddRef((IUnknown
*)&(This
->IInner_vtbl
));
344 static ULONG WINAPI
NullRenderer_Release(IBaseFilter
* iface
)
346 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
348 if (This
->pUnkOuter
&& This
->bUnkOuterValid
)
349 return IUnknown_Release(This
->pUnkOuter
);
350 return IUnknown_Release((IUnknown
*)&(This
->IInner_vtbl
));
353 /** IPersist methods **/
355 static HRESULT WINAPI
NullRenderer_GetClassID(IBaseFilter
* iface
, CLSID
* pClsid
)
357 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
359 TRACE("(%p/%p)->(%p)\n", This
, iface
, pClsid
);
361 *pClsid
= CLSID_NullRenderer
;
366 /** IMediaFilter methods **/
368 static HRESULT WINAPI
NullRenderer_Stop(IBaseFilter
* iface
)
370 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
372 TRACE("(%p/%p)->()\n", This
, iface
);
374 EnterCriticalSection(&This
->csFilter
);
376 This
->state
= State_Stopped
;
378 LeaveCriticalSection(&This
->csFilter
);
383 static HRESULT WINAPI
NullRenderer_Pause(IBaseFilter
* iface
)
385 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
387 TRACE("(%p/%p)->()\n", This
, iface
);
389 EnterCriticalSection(&This
->csFilter
);
391 if (This
->state
== State_Stopped
)
392 This
->pInputPin
->end_of_stream
= 0;
393 This
->state
= State_Paused
;
395 LeaveCriticalSection(&This
->csFilter
);
400 static HRESULT WINAPI
NullRenderer_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
402 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
404 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
406 EnterCriticalSection(&This
->csFilter
);
408 This
->rtStreamStart
= tStart
;
409 This
->state
= State_Running
;
410 This
->pInputPin
->end_of_stream
= 0;
412 LeaveCriticalSection(&This
->csFilter
);
417 static HRESULT WINAPI
NullRenderer_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
419 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
421 TRACE("(%p/%p)->(%d, %p)\n", This
, iface
, dwMilliSecsTimeout
, pState
);
423 EnterCriticalSection(&This
->csFilter
);
425 *pState
= This
->state
;
427 LeaveCriticalSection(&This
->csFilter
);
432 static HRESULT WINAPI
NullRenderer_SetSyncSource(IBaseFilter
* iface
, IReferenceClock
*pClock
)
434 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
436 TRACE("(%p/%p)->(%p)\n", This
, iface
, pClock
);
438 EnterCriticalSection(&This
->csFilter
);
441 IReferenceClock_Release(This
->pClock
);
442 This
->pClock
= pClock
;
444 IReferenceClock_AddRef(This
->pClock
);
446 LeaveCriticalSection(&This
->csFilter
);
451 static HRESULT WINAPI
NullRenderer_GetSyncSource(IBaseFilter
* iface
, IReferenceClock
**ppClock
)
453 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
455 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppClock
);
457 EnterCriticalSection(&This
->csFilter
);
459 *ppClock
= This
->pClock
;
461 IReferenceClock_AddRef(This
->pClock
);
463 LeaveCriticalSection(&This
->csFilter
);
468 /** IBaseFilter implementation **/
470 static HRESULT
NullRenderer_GetPin(IBaseFilter
*iface
, ULONG pos
, IPin
**pin
, DWORD
*lastsynctick
)
472 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
474 /* Our pins are static, not changing so setting static tick count is ok */
480 *pin
= (IPin
*)This
->pInputPin
;
485 static HRESULT WINAPI
NullRenderer_EnumPins(IBaseFilter
* iface
, IEnumPins
**ppEnum
)
487 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
489 TRACE("(%p/%p)->(%p)\n", This
, iface
, ppEnum
);
491 return IEnumPinsImpl_Construct(ppEnum
, NullRenderer_GetPin
, iface
);
494 static HRESULT WINAPI
NullRenderer_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
496 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
498 TRACE("(%p/%p)->(%p,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
500 FIXME("NullRenderer::FindPin(...)\n");
502 /* FIXME: critical section */
507 static HRESULT WINAPI
NullRenderer_QueryFilterInfo(IBaseFilter
* iface
, FILTER_INFO
*pInfo
)
509 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
511 TRACE("(%p/%p)->(%p)\n", This
, iface
, pInfo
);
513 strcpyW(pInfo
->achName
, This
->filterInfo
.achName
);
514 pInfo
->pGraph
= This
->filterInfo
.pGraph
;
517 IFilterGraph_AddRef(pInfo
->pGraph
);
522 static HRESULT WINAPI
NullRenderer_JoinFilterGraph(IBaseFilter
* iface
, IFilterGraph
*pGraph
, LPCWSTR pName
)
524 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
526 TRACE("(%p/%p)->(%p, %s)\n", This
, iface
, pGraph
, debugstr_w(pName
));
528 EnterCriticalSection(&This
->csFilter
);
531 strcpyW(This
->filterInfo
.achName
, pName
);
533 *This
->filterInfo
.achName
= '\0';
534 This
->filterInfo
.pGraph
= pGraph
; /* NOTE: do NOT increase ref. count */
536 LeaveCriticalSection(&This
->csFilter
);
541 static HRESULT WINAPI
NullRenderer_QueryVendorInfo(IBaseFilter
* iface
, LPWSTR
*pVendorInfo
)
543 NullRendererImpl
*This
= (NullRendererImpl
*)iface
;
544 TRACE("(%p/%p)->(%p)\n", This
, iface
, pVendorInfo
);
548 static const IBaseFilterVtbl NullRenderer_Vtbl
=
550 NullRenderer_QueryInterface
,
552 NullRenderer_Release
,
553 NullRenderer_GetClassID
,
557 NullRenderer_GetState
,
558 NullRenderer_SetSyncSource
,
559 NullRenderer_GetSyncSource
,
560 NullRenderer_EnumPins
,
561 NullRenderer_FindPin
,
562 NullRenderer_QueryFilterInfo
,
563 NullRenderer_JoinFilterGraph
,
564 NullRenderer_QueryVendorInfo
567 static HRESULT WINAPI
NullRenderer_InputPin_EndOfStream(IPin
* iface
)
569 InputPin
* This
= (InputPin
*)iface
;
570 IMediaEventSink
* pEventSink
;
574 TRACE("(%p/%p)->()\n", This
, iface
);
576 InputPin_EndOfStream(iface
);
577 graph
= ((NullRendererImpl
*)This
->pin
.pinInfo
.pFilter
)->filterInfo
.pGraph
;
580 hr
= IFilterGraph_QueryInterface(((NullRendererImpl
*)This
->pin
.pinInfo
.pFilter
)->filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
583 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, 0);
584 IMediaEventSink_Release(pEventSink
);
591 static const IPinVtbl NullRenderer_InputPin_Vtbl
=
593 InputPin_QueryInterface
,
597 InputPin_ReceiveConnection
,
599 IPinImpl_ConnectedTo
,
600 IPinImpl_ConnectionMediaType
,
601 IPinImpl_QueryPinInfo
,
602 IPinImpl_QueryDirection
,
604 IPinImpl_QueryAccept
,
605 IPinImpl_EnumMediaTypes
,
606 IPinImpl_QueryInternalConnections
,
607 NullRenderer_InputPin_EndOfStream
,