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
21 #include "strmbase_private.h"
23 static const WCHAR wcsInputPinName
[] = {'i','n','p','u','t',' ','p','i','n',0};
24 static const WCHAR wcsAltInputPinName
[] = {'I','n',0};
26 static inline BaseInputPin
*impl_BaseInputPin_from_IPin( IPin
*iface
)
28 return CONTAINING_RECORD(iface
, BaseInputPin
, pin
.IPin_iface
);
31 static inline BaseRenderer
*impl_from_IBaseFilter(IBaseFilter
*iface
)
33 return CONTAINING_RECORD(iface
, BaseRenderer
, filter
.IBaseFilter_iface
);
36 static inline BaseRenderer
*impl_from_BaseFilter(BaseFilter
*iface
)
38 return CONTAINING_RECORD(iface
, BaseRenderer
, filter
);
41 static const IQualityControlVtbl Renderer_QualityControl_Vtbl
= {
42 QualityControlImpl_QueryInterface
,
43 QualityControlImpl_AddRef
,
44 QualityControlImpl_Release
,
45 QualityControlImpl_Notify
,
46 QualityControlImpl_SetSink
49 static HRESULT WINAPI
BaseRenderer_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
51 BaseInputPin
*This
= impl_BaseInputPin_from_IPin(iface
);
52 BaseRenderer
*renderer
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
55 TRACE("(%p/%p)->(%p, %p)\n", This
, renderer
, pReceivePin
, pmt
);
57 EnterCriticalSection(This
->pin
.pCritSec
);
58 hr
= BaseInputPinImpl_ReceiveConnection(iface
, pReceivePin
, pmt
);
61 if (renderer
->pFuncsTable
->pfnCompleteConnect
)
62 hr
= renderer
->pFuncsTable
->pfnCompleteConnect(renderer
, pReceivePin
);
64 LeaveCriticalSection(This
->pin
.pCritSec
);
69 static HRESULT WINAPI
BaseRenderer_InputPin_Disconnect(IPin
* iface
)
71 BaseInputPin
*This
= impl_BaseInputPin_from_IPin(iface
);
72 BaseRenderer
*renderer
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
75 TRACE("(%p/%p)\n", This
, renderer
);
77 EnterCriticalSection(This
->pin
.pCritSec
);
78 hr
= BasePinImpl_Disconnect(iface
);
81 if (renderer
->pFuncsTable
->pfnBreakConnect
)
82 hr
= renderer
->pFuncsTable
->pfnBreakConnect(renderer
);
84 BaseRendererImpl_ClearPendingSample(renderer
);
85 LeaveCriticalSection(This
->pin
.pCritSec
);
90 static HRESULT WINAPI
BaseRenderer_InputPin_EndOfStream(IPin
* iface
)
93 BaseInputPin
* This
= impl_BaseInputPin_from_IPin(iface
);
94 BaseRenderer
*pFilter
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
96 TRACE("(%p/%p)->()\n", This
, pFilter
);
98 EnterCriticalSection(&pFilter
->csRenderLock
);
99 EnterCriticalSection(&pFilter
->filter
.csFilter
);
100 hr
= BaseInputPinImpl_EndOfStream(iface
);
101 EnterCriticalSection(This
->pin
.pCritSec
);
104 if (pFilter
->pFuncsTable
->pfnEndOfStream
)
105 hr
= pFilter
->pFuncsTable
->pfnEndOfStream(pFilter
);
107 hr
= BaseRendererImpl_EndOfStream(pFilter
);
109 LeaveCriticalSection(This
->pin
.pCritSec
);
110 LeaveCriticalSection(&pFilter
->filter
.csFilter
);
111 LeaveCriticalSection(&pFilter
->csRenderLock
);
115 static HRESULT WINAPI
BaseRenderer_InputPin_BeginFlush(IPin
* iface
)
117 BaseInputPin
* This
= impl_BaseInputPin_from_IPin(iface
);
118 BaseRenderer
*pFilter
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
121 TRACE("(%p/%p)->()\n", This
, iface
);
123 EnterCriticalSection(&pFilter
->csRenderLock
);
124 EnterCriticalSection(&pFilter
->filter
.csFilter
);
125 EnterCriticalSection(This
->pin
.pCritSec
);
126 hr
= BaseInputPinImpl_BeginFlush(iface
);
129 if (pFilter
->pFuncsTable
->pfnBeginFlush
)
130 hr
= pFilter
->pFuncsTable
->pfnBeginFlush(pFilter
);
132 hr
= BaseRendererImpl_BeginFlush(pFilter
);
134 LeaveCriticalSection(This
->pin
.pCritSec
);
135 LeaveCriticalSection(&pFilter
->filter
.csFilter
);
136 LeaveCriticalSection(&pFilter
->csRenderLock
);
140 static HRESULT WINAPI
BaseRenderer_InputPin_EndFlush(IPin
* iface
)
142 BaseInputPin
* This
= impl_BaseInputPin_from_IPin(iface
);
143 BaseRenderer
*pFilter
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
146 TRACE("(%p/%p)->()\n", This
, pFilter
);
148 EnterCriticalSection(&pFilter
->csRenderLock
);
149 EnterCriticalSection(&pFilter
->filter
.csFilter
);
150 EnterCriticalSection(This
->pin
.pCritSec
);
151 hr
= BaseInputPinImpl_EndFlush(iface
);
154 if (pFilter
->pFuncsTable
->pfnEndFlush
)
155 hr
= pFilter
->pFuncsTable
->pfnEndFlush(pFilter
);
157 hr
= BaseRendererImpl_EndFlush(pFilter
);
159 LeaveCriticalSection(This
->pin
.pCritSec
);
160 LeaveCriticalSection(&pFilter
->filter
.csFilter
);
161 LeaveCriticalSection(&pFilter
->csRenderLock
);
165 static const IPinVtbl BaseRenderer_InputPin_Vtbl
=
167 BaseInputPinImpl_QueryInterface
,
169 BaseInputPinImpl_Release
,
170 BaseInputPinImpl_Connect
,
171 BaseRenderer_InputPin_ReceiveConnection
,
172 BaseRenderer_InputPin_Disconnect
,
173 BasePinImpl_ConnectedTo
,
174 BasePinImpl_ConnectionMediaType
,
175 BasePinImpl_QueryPinInfo
,
176 BasePinImpl_QueryDirection
,
178 BaseInputPinImpl_QueryAccept
,
179 BasePinImpl_EnumMediaTypes
,
180 BasePinImpl_QueryInternalConnections
,
181 BaseRenderer_InputPin_EndOfStream
,
182 BaseRenderer_InputPin_BeginFlush
,
183 BaseRenderer_InputPin_EndFlush
,
184 BaseInputPinImpl_NewSegment
187 static IPin
* WINAPI
BaseRenderer_GetPin(BaseFilter
*iface
, int pos
)
189 BaseRenderer
*This
= impl_from_BaseFilter(iface
);
191 if (pos
>= 1 || pos
< 0)
194 IPin_AddRef(&This
->pInputPin
->pin
.IPin_iface
);
195 return &This
->pInputPin
->pin
.IPin_iface
;
198 static LONG WINAPI
BaseRenderer_GetPinCount(BaseFilter
*iface
)
203 static HRESULT WINAPI
BaseRenderer_Input_CheckMediaType(BasePin
*pin
, const AM_MEDIA_TYPE
* pmt
)
205 BaseRenderer
*This
= impl_from_IBaseFilter(pin
->pinInfo
.pFilter
);
206 return This
->pFuncsTable
->pfnCheckMediaType(This
, pmt
);
209 static HRESULT WINAPI
BaseRenderer_Receive(BaseInputPin
*pin
, IMediaSample
* pSample
)
211 BaseRenderer
*This
= impl_from_IBaseFilter(pin
->pin
.pinInfo
.pFilter
);
212 return BaseRendererImpl_Receive(This
, pSample
);
215 static const BaseFilterFuncTable RendererBaseFilterFuncTable
= {
217 BaseRenderer_GetPinCount
220 static const BaseInputPinFuncTable input_BaseInputFuncTable
= {
222 BaseRenderer_Input_CheckMediaType
,
224 BasePinImpl_GetMediaTypeVersion
,
225 BasePinImpl_GetMediaType
231 HRESULT WINAPI
BaseRenderer_Init(BaseRenderer
* This
, const IBaseFilterVtbl
*Vtbl
, IUnknown
*pUnkOuter
, const CLSID
*pClsid
, DWORD_PTR DebugInfo
, const BaseRendererFuncTable
* pBaseFuncsTable
)
236 BaseFilter_Init(&This
->filter
, Vtbl
, pClsid
, DebugInfo
, &RendererBaseFilterFuncTable
);
238 This
->pFuncsTable
= pBaseFuncsTable
;
240 /* construct input pin */
241 piInput
.dir
= PINDIR_INPUT
;
242 piInput
.pFilter
= &This
->filter
.IBaseFilter_iface
;
243 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
245 hr
= BaseInputPin_Construct(&BaseRenderer_InputPin_Vtbl
, sizeof(BaseInputPin
), &piInput
,
246 &input_BaseInputFuncTable
, &This
->filter
.csFilter
, NULL
, (IPin
**)&This
->pInputPin
);
250 hr
= CreatePosPassThru(pUnkOuter
? pUnkOuter
: (IUnknown
*)This
, TRUE
, &This
->pInputPin
->pin
.IPin_iface
, &This
->pPosition
);
254 InitializeCriticalSection(&This
->csRenderLock
);
255 This
->csRenderLock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BaseRenderer.csRenderLock");
256 This
->evComplete
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
257 This
->ThreadSignal
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
258 This
->RenderEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
259 This
->pMediaSample
= NULL
;
261 QualityControlImpl_Create(&This
->pInputPin
->pin
.IPin_iface
, &This
->filter
.IBaseFilter_iface
, &This
->qcimpl
);
262 This
->qcimpl
->IQualityControl_iface
.lpVtbl
= &Renderer_QualityControl_Vtbl
;
268 HRESULT WINAPI
BaseRendererImpl_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
270 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
272 if (IsEqualIID(riid
, &IID_IMediaSeeking
) || IsEqualIID(riid
, &IID_IMediaPosition
))
273 return IUnknown_QueryInterface(This
->pPosition
, riid
, ppv
);
274 else if (IsEqualIID(riid
, &IID_IQualityControl
))
276 *ppv
= &This
->qcimpl
->IQualityControl_iface
;
277 IUnknown_AddRef((IUnknown
*)(*ppv
));
281 return BaseFilterImpl_QueryInterface(iface
, riid
, ppv
);
284 ULONG WINAPI
BaseRendererImpl_Release(IBaseFilter
* iface
)
286 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
287 ULONG refCount
= InterlockedDecrement(&This
->filter
.refCount
);
293 if (SUCCEEDED(IPin_ConnectedTo(&This
->pInputPin
->pin
.IPin_iface
, &pConnectedTo
)))
295 IPin_Disconnect(pConnectedTo
);
296 IPin_Release(pConnectedTo
);
298 IPin_Disconnect(&This
->pInputPin
->pin
.IPin_iface
);
299 IPin_Release(&This
->pInputPin
->pin
.IPin_iface
);
302 IUnknown_Release(This
->pPosition
);
304 This
->csRenderLock
.DebugInfo
->Spare
[0] = 0;
305 DeleteCriticalSection(&This
->csRenderLock
);
307 BaseRendererImpl_ClearPendingSample(This
);
308 CloseHandle(This
->evComplete
);
309 CloseHandle(This
->ThreadSignal
);
310 CloseHandle(This
->RenderEvent
);
311 QualityControlImpl_Destroy(This
->qcimpl
);
312 BaseFilter_Destroy(&This
->filter
);
317 HRESULT WINAPI
BaseRendererImpl_Receive(BaseRenderer
*This
, IMediaSample
* pSample
)
320 REFERENCE_TIME start
, stop
;
323 TRACE("(%p)->%p\n", This
, pSample
);
325 if (This
->pInputPin
->end_of_stream
|| This
->pInputPin
->flushing
)
328 if (This
->filter
.state
== State_Stopped
)
329 return VFW_E_WRONG_STATE
;
331 if (IMediaSample_GetMediaType(pSample
, &pmt
) == S_OK
)
333 if (FAILED(This
->pFuncsTable
->pfnCheckMediaType(This
, pmt
)))
335 return VFW_E_TYPE_NOT_ACCEPTED
;
339 This
->pMediaSample
= pSample
;
340 IMediaSample_AddRef(pSample
);
342 if (This
->pFuncsTable
->pfnPrepareReceive
)
343 hr
= This
->pFuncsTable
->pfnPrepareReceive(This
, pSample
);
346 if (hr
== VFW_E_SAMPLE_REJECTED
)
352 if (This
->pFuncsTable
->pfnPrepareRender
)
353 This
->pFuncsTable
->pfnPrepareRender(This
);
355 EnterCriticalSection(&This
->csRenderLock
);
356 if ( This
->filter
.state
== State_Paused
)
358 if (This
->pFuncsTable
->pfnOnReceiveFirstSample
)
359 This
->pFuncsTable
->pfnOnReceiveFirstSample(This
, pSample
);
361 SetEvent(This
->evComplete
);
364 /* Wait for render Time */
365 if (SUCCEEDED(IMediaSample_GetTime(pSample
, &start
, &stop
)))
368 RendererPosPassThru_RegisterMediaTime(This
->pPosition
, start
);
369 if (This
->pFuncsTable
->pfnShouldDrawSampleNow
)
370 hr
= This
->pFuncsTable
->pfnShouldDrawSampleNow(This
, pSample
, &start
, &stop
);
373 ;/* Do not wait: drop through */
374 else if (hr
== S_FALSE
)
376 if (This
->pFuncsTable
->pfnOnWaitStart
)
377 This
->pFuncsTable
->pfnOnWaitStart(This
);
379 LeaveCriticalSection(&This
->csRenderLock
);
380 hr
= QualityControlRender_WaitFor(This
->qcimpl
, pSample
, This
->RenderEvent
);
381 EnterCriticalSection(&This
->csRenderLock
);
383 if (This
->pFuncsTable
->pfnOnWaitEnd
)
384 This
->pFuncsTable
->pfnOnWaitEnd(This
);
388 LeaveCriticalSection(&This
->csRenderLock
);
396 QualityControlRender_BeginRender(This
->qcimpl
);
397 hr
= This
->pFuncsTable
->pfnDoRenderSample(This
, pSample
);
398 QualityControlRender_EndRender(This
->qcimpl
);
401 QualityControlRender_DoQOS(This
->qcimpl
);
403 BaseRendererImpl_ClearPendingSample(This
);
404 LeaveCriticalSection(&This
->csRenderLock
);
409 HRESULT WINAPI
BaseRendererImpl_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
411 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
413 TRACE("(%p)->(%s,%p)\n", This
, debugstr_w(Id
), ppPin
);
418 if (!lstrcmpiW(Id
,wcsInputPinName
) || !lstrcmpiW(Id
,wcsAltInputPinName
))
420 *ppPin
= &This
->pInputPin
->pin
.IPin_iface
;
425 return VFW_E_NOT_FOUND
;
428 HRESULT WINAPI
BaseRendererImpl_Stop(IBaseFilter
* iface
)
430 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
432 TRACE("(%p)->()\n", This
);
434 EnterCriticalSection(&This
->csRenderLock
);
436 RendererPosPassThru_ResetMediaTime(This
->pPosition
);
437 if (This
->pFuncsTable
->pfnOnStopStreaming
)
438 This
->pFuncsTable
->pfnOnStopStreaming(This
);
439 This
->filter
.state
= State_Stopped
;
440 SetEvent(This
->evComplete
);
441 SetEvent(This
->ThreadSignal
);
442 SetEvent(This
->RenderEvent
);
444 LeaveCriticalSection(&This
->csRenderLock
);
449 HRESULT WINAPI
BaseRendererImpl_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
452 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
453 TRACE("(%p)->(%s)\n", This
, wine_dbgstr_longlong(tStart
));
455 EnterCriticalSection(&This
->csRenderLock
);
456 This
->filter
.rtStreamStart
= tStart
;
457 if (This
->filter
.state
== State_Running
)
460 SetEvent(This
->evComplete
);
461 ResetEvent(This
->ThreadSignal
);
463 if (This
->pInputPin
->pin
.pConnectedTo
)
465 This
->pInputPin
->end_of_stream
= FALSE
;
467 else if (This
->filter
.filterInfo
.pGraph
)
469 IMediaEventSink
*pEventSink
;
470 hr
= IFilterGraph_QueryInterface(This
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
473 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)This
);
474 IMediaEventSink_Release(pEventSink
);
480 QualityControlRender_Start(This
->qcimpl
, This
->filter
.rtStreamStart
);
481 if (This
->pFuncsTable
->pfnOnStartStreaming
)
482 This
->pFuncsTable
->pfnOnStartStreaming(This
);
483 if (This
->filter
.state
== State_Stopped
)
484 BaseRendererImpl_ClearPendingSample(This
);
485 SetEvent(This
->RenderEvent
);
486 This
->filter
.state
= State_Running
;
489 LeaveCriticalSection(&This
->csRenderLock
);
494 HRESULT WINAPI
BaseRendererImpl_Pause(IBaseFilter
* iface
)
496 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
498 TRACE("(%p)->()\n", This
);
500 EnterCriticalSection(&This
->csRenderLock
);
502 if (This
->filter
.state
!= State_Paused
)
504 if (This
->filter
.state
== State_Stopped
)
506 if (This
->pInputPin
->pin
.pConnectedTo
)
507 ResetEvent(This
->evComplete
);
508 This
->pInputPin
->end_of_stream
= FALSE
;
510 else if (This
->pFuncsTable
->pfnOnStopStreaming
)
511 This
->pFuncsTable
->pfnOnStopStreaming(This
);
513 if (This
->filter
.state
== State_Stopped
)
514 BaseRendererImpl_ClearPendingSample(This
);
515 ResetEvent(This
->RenderEvent
);
516 This
->filter
.state
= State_Paused
;
519 ResetEvent(This
->ThreadSignal
);
520 LeaveCriticalSection(&This
->csRenderLock
);
525 HRESULT WINAPI
BaseRendererImpl_SetSyncSource(IBaseFilter
*iface
, IReferenceClock
*clock
)
527 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
530 EnterCriticalSection(&This
->filter
.csFilter
);
531 QualityControlRender_SetClock(This
->qcimpl
, clock
);
532 hr
= BaseFilterImpl_SetSyncSource(iface
, clock
);
533 LeaveCriticalSection(&This
->filter
.csFilter
);
538 HRESULT WINAPI
BaseRendererImpl_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
541 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
543 TRACE("(%p)->(%d, %p)\n", This
, dwMilliSecsTimeout
, pState
);
545 if (WaitForSingleObject(This
->evComplete
, dwMilliSecsTimeout
) == WAIT_TIMEOUT
)
546 hr
= VFW_S_STATE_INTERMEDIATE
;
550 BaseFilterImpl_GetState(iface
, dwMilliSecsTimeout
, pState
);
555 HRESULT WINAPI
BaseRendererImpl_EndOfStream(BaseRenderer
* iface
)
557 IMediaEventSink
* pEventSink
;
561 TRACE("(%p)\n", iface
);
563 graph
= iface
->filter
.filterInfo
.pGraph
;
565 { hr
= IFilterGraph_QueryInterface(iface
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
568 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)iface
);
569 IMediaEventSink_Release(pEventSink
);
572 RendererPosPassThru_EOS(iface
->pPosition
);
573 SetEvent(iface
->evComplete
);
578 HRESULT WINAPI
BaseRendererImpl_BeginFlush(BaseRenderer
* iface
)
580 TRACE("(%p)\n", iface
);
581 BaseRendererImpl_ClearPendingSample(iface
);
582 SetEvent(iface
->ThreadSignal
);
583 SetEvent(iface
->RenderEvent
);
587 HRESULT WINAPI
BaseRendererImpl_EndFlush(BaseRenderer
* iface
)
589 TRACE("(%p)\n", iface
);
590 QualityControlRender_Start(iface
->qcimpl
, iface
->filter
.rtStreamStart
);
591 RendererPosPassThru_ResetMediaTime(iface
->pPosition
);
592 ResetEvent(iface
->ThreadSignal
);
593 ResetEvent(iface
->RenderEvent
);
597 HRESULT WINAPI
BaseRendererImpl_ClearPendingSample(BaseRenderer
*iface
)
599 if (iface
->pMediaSample
)
601 IMediaSample_Release(iface
->pMediaSample
);
602 iface
->pMediaSample
= NULL
;