2 * Generic Implementation of strmbase Base Renderer classes
4 * Copyright 2012 Aric Stewart, CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/debug.h"
25 #include "wine/unicode.h"
26 #include "wine/strmbase.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(strmbase
);
32 static const WCHAR wcsInputPinName
[] = {'i','n','p','u','t',' ','p','i','n',0};
33 static const WCHAR wcsAltInputPinName
[] = {'I','n',0};
35 static inline BaseInputPin
*impl_BaseInputPin_from_IPin( IPin
*iface
)
37 return CONTAINING_RECORD(iface
, BaseInputPin
, pin
.IPin_iface
);
40 static inline BaseRenderer
*impl_from_IBaseFilter(IBaseFilter
*iface
)
42 return CONTAINING_RECORD(iface
, BaseRenderer
, filter
.IBaseFilter_iface
);
45 static inline BaseRenderer
*impl_from_BaseFilter(BaseFilter
*iface
)
47 return CONTAINING_RECORD(iface
, BaseRenderer
, filter
);
50 static HRESULT WINAPI
BaseRenderer_InputPin_EndOfStream(IPin
* iface
)
53 BaseInputPin
* This
= impl_BaseInputPin_from_IPin(iface
);
54 BaseRenderer
*pFilter
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
56 TRACE("(%p/%p)->()\n", This
, pFilter
);
58 EnterCriticalSection(&pFilter
->filter
.csFilter
);
59 EnterCriticalSection(&pFilter
->csRenderLock
);
60 hr
= BaseInputPinImpl_EndOfStream(iface
);
61 EnterCriticalSection(This
->pin
.pCritSec
);
64 if (pFilter
->pFuncsTable
->pfnEndOfStream
)
65 hr
= pFilter
->pFuncsTable
->pfnEndOfStream(pFilter
);
67 hr
= BaseRendererImpl_EndOfStream(pFilter
);
69 LeaveCriticalSection(This
->pin
.pCritSec
);
70 LeaveCriticalSection(&pFilter
->csRenderLock
);
71 LeaveCriticalSection(&pFilter
->filter
.csFilter
);
75 static HRESULT WINAPI
BaseRenderer_InputPin_EndFlush(IPin
* iface
)
77 BaseInputPin
* This
= impl_BaseInputPin_from_IPin(iface
);
78 BaseRenderer
*pFilter
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
81 TRACE("(%p/%p)->()\n", This
, pFilter
);
83 EnterCriticalSection(&pFilter
->filter
.csFilter
);
84 EnterCriticalSection(&pFilter
->csRenderLock
);
85 EnterCriticalSection(This
->pin
.pCritSec
);
86 hr
= BaseInputPinImpl_EndFlush(iface
);
89 if (pFilter
->pFuncsTable
->pfnEndFlush
)
90 hr
= pFilter
->pFuncsTable
->pfnEndFlush(pFilter
);
92 hr
= BaseRendererImpl_EndFlush(pFilter
);
94 LeaveCriticalSection(This
->pin
.pCritSec
);
95 LeaveCriticalSection(&pFilter
->csRenderLock
);
96 LeaveCriticalSection(&pFilter
->filter
.csFilter
);
100 static const IPinVtbl BaseRenderer_InputPin_Vtbl
=
102 BaseInputPinImpl_QueryInterface
,
104 BaseInputPinImpl_Release
,
105 BaseInputPinImpl_Connect
,
106 BaseInputPinImpl_ReceiveConnection
,
107 BasePinImpl_Disconnect
,
108 BasePinImpl_ConnectedTo
,
109 BasePinImpl_ConnectionMediaType
,
110 BasePinImpl_QueryPinInfo
,
111 BasePinImpl_QueryDirection
,
113 BaseInputPinImpl_QueryAccept
,
114 BasePinImpl_EnumMediaTypes
,
115 BasePinImpl_QueryInternalConnections
,
116 BaseRenderer_InputPin_EndOfStream
,
117 BaseInputPinImpl_BeginFlush
,
118 BaseRenderer_InputPin_EndFlush
,
119 BaseInputPinImpl_NewSegment
122 static IPin
* WINAPI
BaseRenderer_GetPin(BaseFilter
*iface
, int pos
)
124 BaseRenderer
*This
= impl_from_BaseFilter(iface
);
126 if (pos
>= 1 || pos
< 0)
129 IPin_AddRef(&This
->pInputPin
->pin
.IPin_iface
);
130 return &This
->pInputPin
->pin
.IPin_iface
;
133 static LONG WINAPI
BaseRenderer_GetPinCount(BaseFilter
*iface
)
138 static HRESULT WINAPI
BaseRenderer_Input_CheckMediaType(BasePin
*pin
, const AM_MEDIA_TYPE
* pmt
)
140 BaseRenderer
*This
= impl_from_IBaseFilter(pin
->pinInfo
.pFilter
);
141 return This
->pFuncsTable
->pfnCheckMediaType(This
, pmt
);
144 static HRESULT WINAPI
BaseRenderer_Receive(BaseInputPin
*pin
, IMediaSample
* pSample
)
146 BaseRenderer
*This
= impl_from_IBaseFilter(pin
->pin
.pinInfo
.pFilter
);
147 return BaseRendererImpl_Receive(This
, pSample
);
150 static const BaseFilterFuncTable RendererBaseFilterFuncTable
= {
152 BaseRenderer_GetPinCount
155 static const BasePinFuncTable input_BaseFuncTable
= {
156 BaseRenderer_Input_CheckMediaType
,
158 BasePinImpl_GetMediaTypeVersion
,
159 BasePinImpl_GetMediaType
162 static const BaseInputPinFuncTable input_BaseInputFuncTable
= {
167 HRESULT WINAPI
BaseRenderer_Init(BaseRenderer
* This
, const IBaseFilterVtbl
*Vtbl
, IUnknown
*pUnkOuter
, const CLSID
*pClsid
, DWORD_PTR DebugInfo
, const BaseRendererFuncTable
* pBaseFuncsTable
)
172 BaseFilter_Init(&This
->filter
, Vtbl
, pClsid
, DebugInfo
, &RendererBaseFilterFuncTable
);
174 This
->pFuncsTable
= pBaseFuncsTable
;
176 /* construct input pin */
177 piInput
.dir
= PINDIR_INPUT
;
178 piInput
.pFilter
= &This
->filter
.IBaseFilter_iface
;
179 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
181 hr
= BaseInputPin_Construct(&BaseRenderer_InputPin_Vtbl
, &piInput
, &input_BaseFuncTable
, &input_BaseInputFuncTable
, &This
->filter
.csFilter
, NULL
, (IPin
**)&This
->pInputPin
);
185 hr
= CreatePosPassThru(pUnkOuter
? pUnkOuter
: (IUnknown
*)This
, TRUE
, &This
->pInputPin
->pin
.IPin_iface
, &This
->pPosition
);
189 InitializeCriticalSection(&This
->csRenderLock
);
190 This
->csRenderLock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BaseRenderer.csRenderLock");
196 HRESULT WINAPI
BaseRendererImpl_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
198 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
200 if (IsEqualIID(riid
, &IID_IMediaSeeking
))
201 return IUnknown_QueryInterface(This
->pPosition
, riid
, ppv
);
203 return BaseFilterImpl_QueryInterface(iface
, riid
, ppv
);
206 ULONG WINAPI
BaseRendererImpl_Release(IBaseFilter
* iface
)
208 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
209 ULONG refCount
= BaseFilterImpl_Release(iface
);
215 if (SUCCEEDED(IPin_ConnectedTo(&This
->pInputPin
->pin
.IPin_iface
, &pConnectedTo
)))
217 IPin_Disconnect(pConnectedTo
);
218 IPin_Release(pConnectedTo
);
220 IPin_Disconnect(&This
->pInputPin
->pin
.IPin_iface
);
221 IPin_Release(&This
->pInputPin
->pin
.IPin_iface
);
224 IUnknown_Release(This
->pPosition
);
226 This
->csRenderLock
.DebugInfo
->Spare
[0] = 0;
227 DeleteCriticalSection(&This
->csRenderLock
);
232 HRESULT WINAPI
BaseRendererImpl_Receive(BaseRenderer
*This
, IMediaSample
* pSample
)
235 REFERENCE_TIME start
, stop
;
237 TRACE("(%p)->%p\n", This
, pSample
);
239 if (This
->pFuncsTable
->pfnPrepareReceive
)
240 hr
= This
->pFuncsTable
->pfnPrepareReceive(This
, pSample
);
243 if (hr
== VFW_E_SAMPLE_REJECTED
)
249 if (This
->pFuncsTable
->pfnPrepareRender
)
250 This
->pFuncsTable
->pfnPrepareRender(This
);
252 EnterCriticalSection(&This
->csRenderLock
);
253 if ( This
->filter
.state
== State_Paused
)
255 if (This
->pFuncsTable
->pfnOnReceiveFirstSample
)
256 This
->pFuncsTable
->pfnOnReceiveFirstSample(This
, pSample
);
259 /* Wait for render Time */
260 if (SUCCEEDED(IMediaSample_GetMediaTime(pSample
, &start
, &stop
)))
263 RendererPosPassThru_RegisterMediaTime(This
->pPosition
, start
);
264 if (This
->pFuncsTable
->pfnShouldDrawSampleNow
)
265 hr
= This
->pFuncsTable
->pfnShouldDrawSampleNow(This
, pSample
, &start
, &stop
);
268 ;/* Do not wait: drop through */
269 else if (hr
== S_FALSE
)
271 if (This
->pFuncsTable
->pfnOnWaitStart
)
272 This
->pFuncsTable
->pfnOnWaitStart(This
);
274 if (This
->pFuncsTable
->pfnOnWaitEnd
)
275 This
->pFuncsTable
->pfnOnWaitEnd(This
);
279 LeaveCriticalSection(&This
->csRenderLock
);
284 if (This
->pInputPin
->flushing
|| This
->pInputPin
->end_of_stream
)
288 hr
= This
->pFuncsTable
->pfnDoRenderSample(This
, pSample
);
289 LeaveCriticalSection(&This
->csRenderLock
);
294 HRESULT WINAPI
BaseRendererImpl_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
296 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
298 TRACE("(%p)->(%p,%p)\n", This
, debugstr_w(Id
), ppPin
);
303 if (!lstrcmpiW(Id
,wcsInputPinName
) || !lstrcmpiW(Id
,wcsAltInputPinName
))
305 *ppPin
= &This
->pInputPin
->pin
.IPin_iface
;
310 return VFW_E_NOT_FOUND
;
313 HRESULT WINAPI
BaseRendererImpl_Stop(IBaseFilter
* iface
)
315 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
317 TRACE("(%p)->()\n", This
);
319 EnterCriticalSection(&This
->csRenderLock
);
321 RendererPosPassThru_ResetMediaTime(This
->pPosition
);
322 if (This
->pFuncsTable
->pfnOnStopStreaming
)
323 This
->pFuncsTable
->pfnOnStopStreaming(This
);
324 This
->filter
.state
= State_Stopped
;
326 LeaveCriticalSection(&This
->csRenderLock
);
331 HRESULT WINAPI
BaseRendererImpl_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
334 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
335 TRACE("(%p)->(%s)\n", This
, wine_dbgstr_longlong(tStart
));
337 EnterCriticalSection(&This
->csRenderLock
);
338 This
->filter
.rtStreamStart
= tStart
;
339 if (This
->filter
.state
== State_Running
)
341 if (This
->pInputPin
->pin
.pConnectedTo
)
343 This
->pInputPin
->end_of_stream
= 0;
345 else if (This
->filter
.filterInfo
.pGraph
)
347 IMediaEventSink
*pEventSink
;
348 hr
= IFilterGraph_QueryInterface(This
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
351 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)This
);
352 IMediaEventSink_Release(pEventSink
);
358 if (This
->pFuncsTable
->pfnOnStartStreaming
)
359 This
->pFuncsTable
->pfnOnStartStreaming(This
);
360 This
->filter
.state
= State_Running
;
363 LeaveCriticalSection(&This
->csRenderLock
);
368 HRESULT WINAPI
BaseRendererImpl_Pause(IBaseFilter
* iface
)
370 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
372 TRACE("(%p)->()\n", This
);
374 EnterCriticalSection(&This
->csRenderLock
);
376 if (This
->filter
.state
!= State_Paused
)
378 if (This
->filter
.state
== State_Stopped
)
379 This
->pInputPin
->end_of_stream
= 0;
380 This
->filter
.state
= State_Paused
;
383 LeaveCriticalSection(&This
->csRenderLock
);
388 HRESULT WINAPI
BaseRendererImpl_EndOfStream(BaseRenderer
* iface
)
390 IMediaEventSink
* pEventSink
;
394 TRACE("(%p)\n", iface
);
396 graph
= iface
->filter
.filterInfo
.pGraph
;
398 { hr
= IFilterGraph_QueryInterface(iface
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
401 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)iface
);
402 IMediaEventSink_Release(pEventSink
);
405 RendererPosPassThru_EOS(iface
->pPosition
);
410 HRESULT WINAPI
BaseRendererImpl_EndFlush(BaseRenderer
* iface
)
412 TRACE("(%p)\n", iface
);
413 RendererPosPassThru_ResetMediaTime(iface
->pPosition
);