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
,
242 DWORD_PTR DebugInfo
, const BaseRendererFuncTable
* pBaseFuncsTable
)
247 BaseFilter_Init(&This
->filter
, Vtbl
, pClsid
, DebugInfo
, &RendererBaseFilterFuncTable
);
249 This
->pFuncsTable
= pBaseFuncsTable
;
251 /* construct input pin */
252 piInput
.dir
= PINDIR_INPUT
;
253 piInput
.pFilter
= &This
->filter
.IBaseFilter_iface
;
254 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
256 hr
= BaseInputPin_Construct(&BaseRenderer_InputPin_Vtbl
, sizeof(BaseInputPin
), &piInput
,
257 &input_BaseInputFuncTable
, &This
->filter
.csFilter
, NULL
, (IPin
**)&This
->pInputPin
);
261 hr
= CreatePosPassThru(pUnkOuter
? pUnkOuter
: (IUnknown
*)&This
->filter
.IBaseFilter_iface
, TRUE
,
262 &This
->pInputPin
->pin
.IPin_iface
, &This
->pPosition
);
266 InitializeCriticalSection(&This
->csRenderLock
);
267 This
->csRenderLock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BaseRenderer.csRenderLock");
268 This
->evComplete
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
269 This
->ThreadSignal
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
270 This
->RenderEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
271 This
->pMediaSample
= NULL
;
273 QualityControlImpl_Create(&This
->pInputPin
->pin
.IPin_iface
, &This
->filter
.IBaseFilter_iface
, &This
->qcimpl
);
274 This
->qcimpl
->IQualityControl_iface
.lpVtbl
= &Renderer_QualityControl_Vtbl
;
280 HRESULT WINAPI
BaseRendererImpl_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
282 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
284 if (IsEqualIID(riid
, &IID_IMediaSeeking
) || IsEqualIID(riid
, &IID_IMediaPosition
))
285 return IUnknown_QueryInterface(This
->pPosition
, riid
, ppv
);
286 else if (IsEqualIID(riid
, &IID_IQualityControl
))
288 *ppv
= &This
->qcimpl
->IQualityControl_iface
;
289 IUnknown_AddRef((IUnknown
*)(*ppv
));
293 return BaseFilterImpl_QueryInterface(iface
, riid
, ppv
);
296 ULONG WINAPI
BaseRendererImpl_Release(IBaseFilter
* iface
)
298 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
299 ULONG refCount
= InterlockedDecrement(&This
->filter
.refCount
);
305 if (SUCCEEDED(IPin_ConnectedTo(&This
->pInputPin
->pin
.IPin_iface
, &pConnectedTo
)))
307 IPin_Disconnect(pConnectedTo
);
308 IPin_Release(pConnectedTo
);
310 IPin_Disconnect(&This
->pInputPin
->pin
.IPin_iface
);
311 IPin_Release(&This
->pInputPin
->pin
.IPin_iface
);
314 IUnknown_Release(This
->pPosition
);
316 This
->csRenderLock
.DebugInfo
->Spare
[0] = 0;
317 DeleteCriticalSection(&This
->csRenderLock
);
319 BaseRendererImpl_ClearPendingSample(This
);
320 CloseHandle(This
->evComplete
);
321 CloseHandle(This
->ThreadSignal
);
322 CloseHandle(This
->RenderEvent
);
323 QualityControlImpl_Destroy(This
->qcimpl
);
324 BaseFilter_Destroy(&This
->filter
);
329 HRESULT WINAPI
BaseRendererImpl_Receive(BaseRenderer
*This
, IMediaSample
* pSample
)
332 REFERENCE_TIME start
, stop
;
335 TRACE("(%p)->%p\n", This
, pSample
);
337 if (This
->pInputPin
->end_of_stream
|| This
->pInputPin
->flushing
)
340 if (This
->filter
.state
== State_Stopped
)
341 return VFW_E_WRONG_STATE
;
343 if (IMediaSample_GetMediaType(pSample
, &pmt
) == S_OK
)
345 if (FAILED(This
->pFuncsTable
->pfnCheckMediaType(This
, pmt
)))
347 return VFW_E_TYPE_NOT_ACCEPTED
;
351 This
->pMediaSample
= pSample
;
352 IMediaSample_AddRef(pSample
);
354 if (This
->pFuncsTable
->pfnPrepareReceive
)
355 hr
= This
->pFuncsTable
->pfnPrepareReceive(This
, pSample
);
358 if (hr
== VFW_E_SAMPLE_REJECTED
)
364 if (This
->pFuncsTable
->pfnPrepareRender
)
365 This
->pFuncsTable
->pfnPrepareRender(This
);
367 EnterCriticalSection(&This
->csRenderLock
);
368 if ( This
->filter
.state
== State_Paused
)
370 if (This
->pFuncsTable
->pfnOnReceiveFirstSample
)
371 This
->pFuncsTable
->pfnOnReceiveFirstSample(This
, pSample
);
373 SetEvent(This
->evComplete
);
376 /* Wait for render Time */
377 if (SUCCEEDED(IMediaSample_GetTime(pSample
, &start
, &stop
)))
380 RendererPosPassThru_RegisterMediaTime(This
->pPosition
, start
);
381 if (This
->pFuncsTable
->pfnShouldDrawSampleNow
)
382 hr
= This
->pFuncsTable
->pfnShouldDrawSampleNow(This
, pSample
, &start
, &stop
);
385 ;/* Do not wait: drop through */
386 else if (hr
== S_FALSE
)
388 if (This
->pFuncsTable
->pfnOnWaitStart
)
389 This
->pFuncsTable
->pfnOnWaitStart(This
);
391 LeaveCriticalSection(&This
->csRenderLock
);
392 hr
= QualityControlRender_WaitFor(This
->qcimpl
, pSample
, This
->RenderEvent
);
393 EnterCriticalSection(&This
->csRenderLock
);
395 if (This
->pFuncsTable
->pfnOnWaitEnd
)
396 This
->pFuncsTable
->pfnOnWaitEnd(This
);
400 LeaveCriticalSection(&This
->csRenderLock
);
408 QualityControlRender_BeginRender(This
->qcimpl
);
409 hr
= This
->pFuncsTable
->pfnDoRenderSample(This
, pSample
);
410 QualityControlRender_EndRender(This
->qcimpl
);
413 QualityControlRender_DoQOS(This
->qcimpl
);
415 BaseRendererImpl_ClearPendingSample(This
);
416 LeaveCriticalSection(&This
->csRenderLock
);
421 HRESULT WINAPI
BaseRendererImpl_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
423 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
425 TRACE("(%p)->(%s,%p)\n", This
, debugstr_w(Id
), ppPin
);
430 if (!lstrcmpiW(Id
,wcsInputPinName
) || !lstrcmpiW(Id
,wcsAltInputPinName
))
432 *ppPin
= &This
->pInputPin
->pin
.IPin_iface
;
437 return VFW_E_NOT_FOUND
;
440 HRESULT WINAPI
BaseRendererImpl_Stop(IBaseFilter
* iface
)
442 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
444 TRACE("(%p)->()\n", This
);
446 EnterCriticalSection(&This
->csRenderLock
);
448 RendererPosPassThru_ResetMediaTime(This
->pPosition
);
449 if (This
->pFuncsTable
->pfnOnStopStreaming
)
450 This
->pFuncsTable
->pfnOnStopStreaming(This
);
451 This
->filter
.state
= State_Stopped
;
452 SetEvent(This
->evComplete
);
453 SetEvent(This
->ThreadSignal
);
454 SetEvent(This
->RenderEvent
);
456 LeaveCriticalSection(&This
->csRenderLock
);
461 HRESULT WINAPI
BaseRendererImpl_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
464 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
465 TRACE("(%p)->(%s)\n", This
, wine_dbgstr_longlong(tStart
));
467 EnterCriticalSection(&This
->csRenderLock
);
468 This
->filter
.rtStreamStart
= tStart
;
469 if (This
->filter
.state
== State_Running
)
472 SetEvent(This
->evComplete
);
473 ResetEvent(This
->ThreadSignal
);
475 if (This
->pInputPin
->pin
.pConnectedTo
)
477 This
->pInputPin
->end_of_stream
= FALSE
;
479 else if (This
->filter
.filterInfo
.pGraph
)
481 IMediaEventSink
*pEventSink
;
482 hr
= IFilterGraph_QueryInterface(This
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
485 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)This
);
486 IMediaEventSink_Release(pEventSink
);
492 QualityControlRender_Start(This
->qcimpl
, This
->filter
.rtStreamStart
);
493 if (This
->pFuncsTable
->pfnOnStartStreaming
)
494 This
->pFuncsTable
->pfnOnStartStreaming(This
);
495 if (This
->filter
.state
== State_Stopped
)
496 BaseRendererImpl_ClearPendingSample(This
);
497 SetEvent(This
->RenderEvent
);
498 This
->filter
.state
= State_Running
;
501 LeaveCriticalSection(&This
->csRenderLock
);
506 HRESULT WINAPI
BaseRendererImpl_Pause(IBaseFilter
* iface
)
508 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
510 TRACE("(%p)->()\n", This
);
512 EnterCriticalSection(&This
->csRenderLock
);
514 if (This
->filter
.state
!= State_Paused
)
516 if (This
->filter
.state
== State_Stopped
)
518 if (This
->pInputPin
->pin
.pConnectedTo
)
519 ResetEvent(This
->evComplete
);
520 This
->pInputPin
->end_of_stream
= FALSE
;
522 else if (This
->pFuncsTable
->pfnOnStopStreaming
)
523 This
->pFuncsTable
->pfnOnStopStreaming(This
);
525 if (This
->filter
.state
== State_Stopped
)
526 BaseRendererImpl_ClearPendingSample(This
);
527 ResetEvent(This
->RenderEvent
);
528 This
->filter
.state
= State_Paused
;
531 ResetEvent(This
->ThreadSignal
);
532 LeaveCriticalSection(&This
->csRenderLock
);
537 HRESULT WINAPI
BaseRendererImpl_SetSyncSource(IBaseFilter
*iface
, IReferenceClock
*clock
)
539 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
542 EnterCriticalSection(&This
->filter
.csFilter
);
543 QualityControlRender_SetClock(This
->qcimpl
, clock
);
544 hr
= BaseFilterImpl_SetSyncSource(iface
, clock
);
545 LeaveCriticalSection(&This
->filter
.csFilter
);
550 HRESULT WINAPI
BaseRendererImpl_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
553 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
555 TRACE("(%p)->(%d, %p)\n", This
, dwMilliSecsTimeout
, pState
);
557 if (WaitForSingleObject(This
->evComplete
, dwMilliSecsTimeout
) == WAIT_TIMEOUT
)
558 hr
= VFW_S_STATE_INTERMEDIATE
;
562 BaseFilterImpl_GetState(iface
, dwMilliSecsTimeout
, pState
);
567 HRESULT WINAPI
BaseRendererImpl_EndOfStream(BaseRenderer
* iface
)
569 IMediaEventSink
* pEventSink
;
573 TRACE("(%p)\n", iface
);
575 graph
= iface
->filter
.filterInfo
.pGraph
;
577 { hr
= IFilterGraph_QueryInterface(iface
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
580 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)iface
);
581 IMediaEventSink_Release(pEventSink
);
584 RendererPosPassThru_EOS(iface
->pPosition
);
585 SetEvent(iface
->evComplete
);
590 HRESULT WINAPI
BaseRendererImpl_BeginFlush(BaseRenderer
* iface
)
592 TRACE("(%p)\n", iface
);
593 BaseRendererImpl_ClearPendingSample(iface
);
594 SetEvent(iface
->ThreadSignal
);
595 SetEvent(iface
->RenderEvent
);
599 HRESULT WINAPI
BaseRendererImpl_EndFlush(BaseRenderer
* iface
)
601 TRACE("(%p)\n", iface
);
602 QualityControlRender_Start(iface
->qcimpl
, iface
->filter
.rtStreamStart
);
603 RendererPosPassThru_ResetMediaTime(iface
->pPosition
);
604 ResetEvent(iface
->ThreadSignal
);
605 ResetEvent(iface
->RenderEvent
);
609 HRESULT WINAPI
BaseRendererImpl_ClearPendingSample(BaseRenderer
*iface
)
611 if (iface
->pMediaSample
)
613 IMediaSample_Release(iface
->pMediaSample
);
614 iface
->pMediaSample
= NULL
;