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,