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"
29 #include "strmbase_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(strmbase
);
33 static const WCHAR wcsInputPinName
[] = {'i','n','p','u','t',' ','p','i','n',0};
34 static const WCHAR wcsAltInputPinName
[] = {'I','n',0};
36 static inline BaseInputPin
*impl_BaseInputPin_from_IPin( IPin
*iface
)
38 return CONTAINING_RECORD(iface
, BaseInputPin
, pin
.IPin_iface
);
41 static inline BaseRenderer
*impl_from_IBaseFilter(IBaseFilter
*iface
)
43 return CONTAINING_RECORD(iface
, BaseRenderer
, filter
.IBaseFilter_iface
);
46 static inline BaseRenderer
*impl_from_BaseFilter(BaseFilter
*iface
)
48 return CONTAINING_RECORD(iface
, BaseRenderer
, filter
);
51 static const IQualityControlVtbl Renderer_QualityControl_Vtbl
= {
52 QualityControlImpl_QueryInterface
,
53 QualityControlImpl_AddRef
,
54 QualityControlImpl_Release
,
55 QualityControlImpl_Notify
,
56 QualityControlImpl_SetSink
59 static HRESULT WINAPI
BaseRenderer_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
61 BaseInputPin
*This
= impl_BaseInputPin_from_IPin(iface
);
62 BaseRenderer
*renderer
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
65 TRACE("(%p/%p)->(%p, %p)\n", This
, renderer
, pReceivePin
, pmt
);
67 EnterCriticalSection(This
->pin
.pCritSec
);
68 hr
= BaseInputPinImpl_ReceiveConnection(iface
, pReceivePin
, pmt
);
71 if (renderer
->pFuncsTable
->pfnCompleteConnect
)
72 hr
= renderer
->pFuncsTable
->pfnCompleteConnect(renderer
, pReceivePin
);
74 LeaveCriticalSection(This
->pin
.pCritSec
);
79 static HRESULT WINAPI
BaseRenderer_InputPin_Disconnect(IPin
* iface
)
81 BaseInputPin
*This
= impl_BaseInputPin_from_IPin(iface
);
82 BaseRenderer
*renderer
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
85 TRACE("(%p/%p)\n", This
, renderer
);
87 EnterCriticalSection(This
->pin
.pCritSec
);
88 hr
= BasePinImpl_Disconnect(iface
);
91 if (renderer
->pFuncsTable
->pfnBreakConnect
)
92 hr
= renderer
->pFuncsTable
->pfnBreakConnect(renderer
);
94 BaseRendererImpl_ClearPendingSample(renderer
);
95 LeaveCriticalSection(This
->pin
.pCritSec
);
100 static HRESULT WINAPI
BaseRenderer_InputPin_EndOfStream(IPin
* iface
)
103 BaseInputPin
* This
= impl_BaseInputPin_from_IPin(iface
);
104 BaseRenderer
*pFilter
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
106 TRACE("(%p/%p)->()\n", This
, pFilter
);
108 EnterCriticalSection(&pFilter
->csRenderLock
);
109 EnterCriticalSection(&pFilter
->filter
.csFilter
);
110 hr
= BaseInputPinImpl_EndOfStream(iface
);
111 EnterCriticalSection(This
->pin
.pCritSec
);
114 if (pFilter
->pFuncsTable
->pfnEndOfStream
)
115 hr
= pFilter
->pFuncsTable
->pfnEndOfStream(pFilter
);
117 hr
= BaseRendererImpl_EndOfStream(pFilter
);
119 LeaveCriticalSection(This
->pin
.pCritSec
);
120 LeaveCriticalSection(&pFilter
->filter
.csFilter
);
121 LeaveCriticalSection(&pFilter
->csRenderLock
);
125 static HRESULT WINAPI
BaseRenderer_InputPin_BeginFlush(IPin
* iface
)
127 BaseInputPin
* This
= impl_BaseInputPin_from_IPin(iface
);
128 BaseRenderer
*pFilter
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
131 TRACE("(%p/%p)->()\n", This
, iface
);
133 EnterCriticalSection(&pFilter
->csRenderLock
);
134 EnterCriticalSection(&pFilter
->filter
.csFilter
);
135 EnterCriticalSection(This
->pin
.pCritSec
);
136 hr
= BaseInputPinImpl_BeginFlush(iface
);
139 if (pFilter
->pFuncsTable
->pfnBeginFlush
)
140 hr
= pFilter
->pFuncsTable
->pfnBeginFlush(pFilter
);
142 hr
= BaseRendererImpl_BeginFlush(pFilter
);
144 LeaveCriticalSection(This
->pin
.pCritSec
);
145 LeaveCriticalSection(&pFilter
->filter
.csFilter
);
146 LeaveCriticalSection(&pFilter
->csRenderLock
);
150 static HRESULT WINAPI
BaseRenderer_InputPin_EndFlush(IPin
* iface
)
152 BaseInputPin
* This
= impl_BaseInputPin_from_IPin(iface
);
153 BaseRenderer
*pFilter
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
156 TRACE("(%p/%p)->()\n", This
, pFilter
);
158 EnterCriticalSection(&pFilter
->csRenderLock
);
159 EnterCriticalSection(&pFilter
->filter
.csFilter
);
160 EnterCriticalSection(This
->pin
.pCritSec
);
161 hr
= BaseInputPinImpl_EndFlush(iface
);
164 if (pFilter
->pFuncsTable
->pfnEndFlush
)
165 hr
= pFilter
->pFuncsTable
->pfnEndFlush(pFilter
);
167 hr
= BaseRendererImpl_EndFlush(pFilter
);
169 LeaveCriticalSection(This
->pin
.pCritSec
);
170 LeaveCriticalSection(&pFilter
->filter
.csFilter
);
171 LeaveCriticalSection(&pFilter
->csRenderLock
);
175 static const IPinVtbl BaseRenderer_InputPin_Vtbl
=
177 BaseInputPinImpl_QueryInterface
,
179 BaseInputPinImpl_Release
,
180 BaseInputPinImpl_Connect
,
181 BaseRenderer_InputPin_ReceiveConnection
,
182 BaseRenderer_InputPin_Disconnect
,
183 BasePinImpl_ConnectedTo
,
184 BasePinImpl_ConnectionMediaType
,
185 BasePinImpl_QueryPinInfo
,
186 BasePinImpl_QueryDirection
,
188 BaseInputPinImpl_QueryAccept
,
189 BasePinImpl_EnumMediaTypes
,
190 BasePinImpl_QueryInternalConnections
,
191 BaseRenderer_InputPin_EndOfStream
,
192 BaseRenderer_InputPin_BeginFlush
,
193 BaseRenderer_InputPin_EndFlush
,
194 BaseInputPinImpl_NewSegment
197 static IPin
* WINAPI
BaseRenderer_GetPin(BaseFilter
*iface
, int pos
)
199 BaseRenderer
*This
= impl_from_BaseFilter(iface
);
201 if (pos
>= 1 || pos
< 0)
204 IPin_AddRef(&This
->pInputPin
->pin
.IPin_iface
);
205 return &This
->pInputPin
->pin
.IPin_iface
;
208 static LONG WINAPI
BaseRenderer_GetPinCount(BaseFilter
*iface
)
213 static HRESULT WINAPI
BaseRenderer_Input_CheckMediaType(BasePin
*pin
, const AM_MEDIA_TYPE
* pmt
)
215 BaseRenderer
*This
= impl_from_IBaseFilter(pin
->pinInfo
.pFilter
);
216 return This
->pFuncsTable
->pfnCheckMediaType(This
, pmt
);
219 static HRESULT WINAPI
BaseRenderer_Receive(BaseInputPin
*pin
, IMediaSample
* pSample
)
221 BaseRenderer
*This
= impl_from_IBaseFilter(pin
->pin
.pinInfo
.pFilter
);
222 return BaseRendererImpl_Receive(This
, pSample
);
225 static const BaseFilterFuncTable RendererBaseFilterFuncTable
= {
227 BaseRenderer_GetPinCount
230 static const BaseInputPinFuncTable input_BaseInputFuncTable
= {
232 BaseRenderer_Input_CheckMediaType
,
234 BasePinImpl_GetMediaTypeVersion
,
235 BasePinImpl_GetMediaType
241 HRESULT WINAPI
BaseRenderer_Init(BaseRenderer
* This
, const IBaseFilterVtbl
*Vtbl
, IUnknown
*pUnkOuter
, const CLSID
*pClsid
, DWORD_PTR DebugInfo
, const BaseRendererFuncTable
* pBaseFuncsTable
)
246 BaseFilter_Init(&This
->filter
, Vtbl
, pClsid
, DebugInfo
, &RendererBaseFilterFuncTable
);
248 This
->pFuncsTable
= pBaseFuncsTable
;
250 /* construct input pin */
251 piInput
.dir
= PINDIR_INPUT
;
252 piInput
.pFilter
= &This
->filter
.IBaseFilter_iface
;
253 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
255 hr
= BaseInputPin_Construct(&BaseRenderer_InputPin_Vtbl
, sizeof(BaseInputPin
), &piInput
,
256 &input_BaseInputFuncTable
, &This
->filter
.csFilter
, NULL
, (IPin
**)&This
->pInputPin
);
260 hr
= CreatePosPassThru(pUnkOuter
? pUnkOuter
: (IUnknown
*)This
, TRUE
, &This
->pInputPin
->pin
.IPin_iface
, &This
->pPosition
);
264 InitializeCriticalSection(&This
->csRenderLock
);
265 This
->csRenderLock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BaseRenderer.csRenderLock");
266 This
->evComplete
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
267 This
->ThreadSignal
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
268 This
->RenderEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
269 This
->pMediaSample
= NULL
;
271 QualityControlImpl_Create(&This
->pInputPin
->pin
.IPin_iface
, &This
->filter
.IBaseFilter_iface
, &This
->qcimpl
);
272 This
->qcimpl
->IQualityControl_iface
.lpVtbl
= &Renderer_QualityControl_Vtbl
;
278 HRESULT WINAPI
BaseRendererImpl_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
280 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
282 if (IsEqualIID(riid
, &IID_IMediaSeeking
) || IsEqualIID(riid
, &IID_IMediaPosition
))
283 return IUnknown_QueryInterface(This
->pPosition
, riid
, ppv
);
284 else if (IsEqualIID(riid
, &IID_IQualityControl
))
286 *ppv
= &This
->qcimpl
->IQualityControl_iface
;
287 IUnknown_AddRef((IUnknown
*)(*ppv
));
291 return BaseFilterImpl_QueryInterface(iface
, riid
, ppv
);
294 ULONG WINAPI
BaseRendererImpl_Release(IBaseFilter
* iface
)
296 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
297 ULONG refCount
= InterlockedDecrement(&This
->filter
.refCount
);
303 if (SUCCEEDED(IPin_ConnectedTo(&This
->pInputPin
->pin
.IPin_iface
, &pConnectedTo
)))
305 IPin_Disconnect(pConnectedTo
);
306 IPin_Release(pConnectedTo
);
308 IPin_Disconnect(&This
->pInputPin
->pin
.IPin_iface
);
309 IPin_Release(&This
->pInputPin
->pin
.IPin_iface
);
312 IUnknown_Release(This
->pPosition
);
314 This
->csRenderLock
.DebugInfo
->Spare
[0] = 0;
315 DeleteCriticalSection(&This
->csRenderLock
);
317 BaseRendererImpl_ClearPendingSample(This
);
318 CloseHandle(This
->evComplete
);
319 CloseHandle(This
->ThreadSignal
);
320 CloseHandle(This
->RenderEvent
);
321 QualityControlImpl_Destroy(This
->qcimpl
);
322 BaseFilter_Destroy(&This
->filter
);
327 HRESULT WINAPI
BaseRendererImpl_Receive(BaseRenderer
*This
, IMediaSample
* pSample
)
330 REFERENCE_TIME start
, stop
;
333 TRACE("(%p)->%p\n", This
, pSample
);
335 if (This
->pInputPin
->end_of_stream
|| This
->pInputPin
->flushing
)
338 if (This
->filter
.state
== State_Stopped
)
339 return VFW_E_WRONG_STATE
;
341 if (IMediaSample_GetMediaType(pSample
, &pmt
) == S_OK
)
343 if (FAILED(This
->pFuncsTable
->pfnCheckMediaType(This
, pmt
)))
345 return VFW_E_TYPE_NOT_ACCEPTED
;
349 This
->pMediaSample
= pSample
;
350 IMediaSample_AddRef(pSample
);
352 if (This
->pFuncsTable
->pfnPrepareReceive
)
353 hr
= This
->pFuncsTable
->pfnPrepareReceive(This
, pSample
);
356 if (hr
== VFW_E_SAMPLE_REJECTED
)
362 if (This
->pFuncsTable
->pfnPrepareRender
)
363 This
->pFuncsTable
->pfnPrepareRender(This
);
365 EnterCriticalSection(&This
->csRenderLock
);
366 if ( This
->filter
.state
== State_Paused
)
368 if (This
->pFuncsTable
->pfnOnReceiveFirstSample
)
369 This
->pFuncsTable
->pfnOnReceiveFirstSample(This
, pSample
);
371 SetEvent(This
->evComplete
);
374 /* Wait for render Time */
375 if (SUCCEEDED(IMediaSample_GetTime(pSample
, &start
, &stop
)))
378 RendererPosPassThru_RegisterMediaTime(This
->pPosition
, start
);
379 if (This
->pFuncsTable
->pfnShouldDrawSampleNow
)
380 hr
= This
->pFuncsTable
->pfnShouldDrawSampleNow(This
, pSample
, &start
, &stop
);
383 ;/* Do not wait: drop through */
384 else if (hr
== S_FALSE
)
386 if (This
->pFuncsTable
->pfnOnWaitStart
)
387 This
->pFuncsTable
->pfnOnWaitStart(This
);
389 LeaveCriticalSection(&This
->csRenderLock
);
390 hr
= QualityControlRender_WaitFor(This
->qcimpl
, pSample
, This
->RenderEvent
);
391 EnterCriticalSection(&This
->csRenderLock
);
393 if (This
->pFuncsTable
->pfnOnWaitEnd
)
394 This
->pFuncsTable
->pfnOnWaitEnd(This
);
398 LeaveCriticalSection(&This
->csRenderLock
);
406 QualityControlRender_BeginRender(This
->qcimpl
);
407 hr
= This
->pFuncsTable
->pfnDoRenderSample(This
, pSample
);
408 QualityControlRender_EndRender(This
->qcimpl
);
411 QualityControlRender_DoQOS(This
->qcimpl
);
413 BaseRendererImpl_ClearPendingSample(This
);
414 LeaveCriticalSection(&This
->csRenderLock
);
419 HRESULT WINAPI
BaseRendererImpl_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
421 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
423 TRACE("(%p)->(%s,%p)\n", This
, debugstr_w(Id
), ppPin
);
428 if (!lstrcmpiW(Id
,wcsInputPinName
) || !lstrcmpiW(Id
,wcsAltInputPinName
))
430 *ppPin
= &This
->pInputPin
->pin
.IPin_iface
;
435 return VFW_E_NOT_FOUND
;
438 HRESULT WINAPI
BaseRendererImpl_Stop(IBaseFilter
* iface
)
440 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
442 TRACE("(%p)->()\n", This
);
444 EnterCriticalSection(&This
->csRenderLock
);
446 RendererPosPassThru_ResetMediaTime(This
->pPosition
);
447 if (This
->pFuncsTable
->pfnOnStopStreaming
)
448 This
->pFuncsTable
->pfnOnStopStreaming(This
);
449 This
->filter
.state
= State_Stopped
;
450 SetEvent(This
->evComplete
);
451 SetEvent(This
->ThreadSignal
);
452 SetEvent(This
->RenderEvent
);
454 LeaveCriticalSection(&This
->csRenderLock
);
459 HRESULT WINAPI
BaseRendererImpl_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
462 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
463 TRACE("(%p)->(%s)\n", This
, wine_dbgstr_longlong(tStart
));
465 EnterCriticalSection(&This
->csRenderLock
);
466 This
->filter
.rtStreamStart
= tStart
;
467 if (This
->filter
.state
== State_Running
)
470 SetEvent(This
->evComplete
);
471 ResetEvent(This
->ThreadSignal
);
473 if (This
->pInputPin
->pin
.pConnectedTo
)
475 This
->pInputPin
->end_of_stream
= FALSE
;
477 else if (This
->filter
.filterInfo
.pGraph
)
479 IMediaEventSink
*pEventSink
;
480 hr
= IFilterGraph_QueryInterface(This
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
483 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)This
);
484 IMediaEventSink_Release(pEventSink
);
490 QualityControlRender_Start(This
->qcimpl
, This
->filter
.rtStreamStart
);
491 if (This
->pFuncsTable
->pfnOnStartStreaming
)
492 This
->pFuncsTable
->pfnOnStartStreaming(This
);
493 if (This
->filter
.state
== State_Stopped
)
494 BaseRendererImpl_ClearPendingSample(This
);
495 SetEvent(This
->RenderEvent
);
496 This
->filter
.state
= State_Running
;
499 LeaveCriticalSection(&This
->csRenderLock
);
504 HRESULT WINAPI
BaseRendererImpl_Pause(IBaseFilter
* iface
)
506 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
508 TRACE("(%p)->()\n", This
);
510 EnterCriticalSection(&This
->csRenderLock
);
512 if (This
->filter
.state
!= State_Paused
)
514 if (This
->filter
.state
== State_Stopped
)
516 if (This
->pInputPin
->pin
.pConnectedTo
)
517 ResetEvent(This
->evComplete
);
518 This
->pInputPin
->end_of_stream
= FALSE
;
520 else if (This
->pFuncsTable
->pfnOnStopStreaming
)
521 This
->pFuncsTable
->pfnOnStopStreaming(This
);
523 if (This
->filter
.state
== State_Stopped
)
524 BaseRendererImpl_ClearPendingSample(This
);
525 ResetEvent(This
->RenderEvent
);
526 This
->filter
.state
= State_Paused
;
529 ResetEvent(This
->ThreadSignal
);
530 LeaveCriticalSection(&This
->csRenderLock
);
535 HRESULT WINAPI
BaseRendererImpl_SetSyncSource(IBaseFilter
*iface
, IReferenceClock
*clock
)
537 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
540 EnterCriticalSection(&This
->filter
.csFilter
);
541 QualityControlRender_SetClock(This
->qcimpl
, clock
);
542 hr
= BaseFilterImpl_SetSyncSource(iface
, clock
);
543 LeaveCriticalSection(&This
->filter
.csFilter
);
548 HRESULT WINAPI
BaseRendererImpl_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
551 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
553 TRACE("(%p)->(%d, %p)\n", This
, dwMilliSecsTimeout
, pState
);
555 if (WaitForSingleObject(This
->evComplete
, dwMilliSecsTimeout
) == WAIT_TIMEOUT
)
556 hr
= VFW_S_STATE_INTERMEDIATE
;
560 BaseFilterImpl_GetState(iface
, dwMilliSecsTimeout
, pState
);
565 HRESULT WINAPI
BaseRendererImpl_EndOfStream(BaseRenderer
* iface
)
567 IMediaEventSink
* pEventSink
;
571 TRACE("(%p)\n", iface
);
573 graph
= iface
->filter
.filterInfo
.pGraph
;
575 { hr
= IFilterGraph_QueryInterface(iface
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
578 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)iface
);
579 IMediaEventSink_Release(pEventSink
);
582 RendererPosPassThru_EOS(iface
->pPosition
);
583 SetEvent(iface
->evComplete
);
588 HRESULT WINAPI
BaseRendererImpl_BeginFlush(BaseRenderer
* iface
)
590 TRACE("(%p)\n", iface
);
591 BaseRendererImpl_ClearPendingSample(iface
);
592 SetEvent(iface
->ThreadSignal
);
593 SetEvent(iface
->RenderEvent
);
597 HRESULT WINAPI
BaseRendererImpl_EndFlush(BaseRenderer
* iface
)
599 TRACE("(%p)\n", iface
);
600 QualityControlRender_Start(iface
->qcimpl
, iface
->filter
.rtStreamStart
);
601 RendererPosPassThru_ResetMediaTime(iface
->pPosition
);
602 ResetEvent(iface
->ThreadSignal
);
603 ResetEvent(iface
->RenderEvent
);
607 HRESULT WINAPI
BaseRendererImpl_ClearPendingSample(BaseRenderer
*iface
)
609 if (iface
->pMediaSample
)
611 IMediaSample_Release(iface
->pMediaSample
);
612 iface
->pMediaSample
= NULL
;