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
->filter
.csFilter
);
109 EnterCriticalSection(&pFilter
->csRenderLock
);
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
->csRenderLock
);
121 LeaveCriticalSection(&pFilter
->filter
.csFilter
);
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
->filter
.csFilter
);
134 EnterCriticalSection(&pFilter
->csRenderLock
);
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
->filter
.csFilter
);
159 EnterCriticalSection(&pFilter
->csRenderLock
);
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
->csRenderLock
);
171 LeaveCriticalSection(&pFilter
->filter
.csFilter
);
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 BasePinFuncTable input_BaseFuncTable
= {
231 BaseRenderer_Input_CheckMediaType
,
233 BasePinImpl_GetMediaTypeVersion
,
234 BasePinImpl_GetMediaType
237 static const BaseInputPinFuncTable input_BaseInputFuncTable
= {
242 HRESULT WINAPI
BaseRenderer_Init(BaseRenderer
* This
, const IBaseFilterVtbl
*Vtbl
, IUnknown
*pUnkOuter
, const CLSID
*pClsid
, 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
, &piInput
, &input_BaseFuncTable
, &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
= BaseFilterImpl_Release(iface
);
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
);
326 HRESULT WINAPI
BaseRendererImpl_Receive(BaseRenderer
*This
, IMediaSample
* pSample
)
329 REFERENCE_TIME start
, stop
;
332 TRACE("(%p)->%p\n", This
, pSample
);
334 if (This
->pInputPin
->end_of_stream
|| This
->pInputPin
->flushing
)
337 if (This
->filter
.state
== State_Stopped
)
338 return VFW_E_WRONG_STATE
;
340 if (IMediaSample_GetMediaType(pSample
, &pmt
) == S_OK
)
342 if (FAILED(This
->pFuncsTable
->pfnCheckMediaType(This
, pmt
)))
344 return VFW_E_TYPE_NOT_ACCEPTED
;
348 This
->pMediaSample
= pSample
;
349 IMediaSample_AddRef(pSample
);
351 if (This
->pFuncsTable
->pfnPrepareReceive
)
352 hr
= This
->pFuncsTable
->pfnPrepareReceive(This
, pSample
);
355 if (hr
== VFW_E_SAMPLE_REJECTED
)
361 if (This
->pFuncsTable
->pfnPrepareRender
)
362 This
->pFuncsTable
->pfnPrepareRender(This
);
364 EnterCriticalSection(&This
->csRenderLock
);
365 if ( This
->filter
.state
== State_Paused
)
367 if (This
->pFuncsTable
->pfnOnReceiveFirstSample
)
368 This
->pFuncsTable
->pfnOnReceiveFirstSample(This
, pSample
);
370 SetEvent(This
->evComplete
);
373 /* Wait for render Time */
374 if (SUCCEEDED(IMediaSample_GetMediaTime(pSample
, &start
, &stop
)))
377 RendererPosPassThru_RegisterMediaTime(This
->pPosition
, start
);
378 if (This
->pFuncsTable
->pfnShouldDrawSampleNow
)
379 hr
= This
->pFuncsTable
->pfnShouldDrawSampleNow(This
, pSample
, &start
, &stop
);
382 ;/* Do not wait: drop through */
383 else if (hr
== S_FALSE
)
385 if (This
->pFuncsTable
->pfnOnWaitStart
)
386 This
->pFuncsTable
->pfnOnWaitStart(This
);
388 LeaveCriticalSection(&This
->csRenderLock
);
389 hr
= QualityControlRender_WaitFor(This
->qcimpl
, pSample
, This
->RenderEvent
);
390 EnterCriticalSection(&This
->csRenderLock
);
392 if (This
->pFuncsTable
->pfnOnWaitEnd
)
393 This
->pFuncsTable
->pfnOnWaitEnd(This
);
397 LeaveCriticalSection(&This
->csRenderLock
);
405 QualityControlRender_BeginRender(This
->qcimpl
);
406 hr
= This
->pFuncsTable
->pfnDoRenderSample(This
, pSample
);
407 QualityControlRender_EndRender(This
->qcimpl
);
410 QualityControlRender_DoQOS(This
->qcimpl
);
412 BaseRendererImpl_ClearPendingSample(This
);
413 LeaveCriticalSection(&This
->csRenderLock
);
418 HRESULT WINAPI
BaseRendererImpl_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
420 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
422 TRACE("(%p)->(%s,%p)\n", This
, debugstr_w(Id
), ppPin
);
427 if (!lstrcmpiW(Id
,wcsInputPinName
) || !lstrcmpiW(Id
,wcsAltInputPinName
))
429 *ppPin
= &This
->pInputPin
->pin
.IPin_iface
;
434 return VFW_E_NOT_FOUND
;
437 HRESULT WINAPI
BaseRendererImpl_Stop(IBaseFilter
* iface
)
439 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
441 TRACE("(%p)->()\n", This
);
443 EnterCriticalSection(&This
->csRenderLock
);
445 RendererPosPassThru_ResetMediaTime(This
->pPosition
);
446 if (This
->pFuncsTable
->pfnOnStopStreaming
)
447 This
->pFuncsTable
->pfnOnStopStreaming(This
);
448 This
->filter
.state
= State_Stopped
;
449 SetEvent(This
->evComplete
);
450 SetEvent(This
->ThreadSignal
);
451 SetEvent(This
->RenderEvent
);
453 LeaveCriticalSection(&This
->csRenderLock
);
458 HRESULT WINAPI
BaseRendererImpl_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
461 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
462 TRACE("(%p)->(%s)\n", This
, wine_dbgstr_longlong(tStart
));
464 EnterCriticalSection(&This
->csRenderLock
);
465 This
->filter
.rtStreamStart
= tStart
;
466 if (This
->filter
.state
== State_Running
)
469 SetEvent(This
->evComplete
);
470 ResetEvent(This
->ThreadSignal
);
472 if (This
->pInputPin
->pin
.pConnectedTo
)
474 This
->pInputPin
->end_of_stream
= 0;
476 else if (This
->filter
.filterInfo
.pGraph
)
478 IMediaEventSink
*pEventSink
;
479 hr
= IFilterGraph_QueryInterface(This
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
482 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)This
);
483 IMediaEventSink_Release(pEventSink
);
489 QualityControlRender_Start(This
->qcimpl
, This
->filter
.rtStreamStart
);
490 if (This
->pFuncsTable
->pfnOnStartStreaming
)
491 This
->pFuncsTable
->pfnOnStartStreaming(This
);
492 if (This
->filter
.state
== State_Stopped
)
493 BaseRendererImpl_ClearPendingSample(This
);
494 SetEvent(This
->RenderEvent
);
495 This
->filter
.state
= State_Running
;
498 LeaveCriticalSection(&This
->csRenderLock
);
503 HRESULT WINAPI
BaseRendererImpl_Pause(IBaseFilter
* iface
)
505 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
507 TRACE("(%p)->()\n", This
);
509 EnterCriticalSection(&This
->csRenderLock
);
511 if (This
->filter
.state
!= State_Paused
)
513 if (This
->filter
.state
== State_Stopped
)
515 if (This
->pInputPin
->pin
.pConnectedTo
)
516 ResetEvent(This
->evComplete
);
517 This
->pInputPin
->end_of_stream
= 0;
519 else if (This
->pFuncsTable
->pfnOnStopStreaming
)
520 This
->pFuncsTable
->pfnOnStopStreaming(This
);
522 if (This
->filter
.state
== State_Stopped
)
523 BaseRendererImpl_ClearPendingSample(This
);
524 ResetEvent(This
->RenderEvent
);
525 This
->filter
.state
= State_Paused
;
528 ResetEvent(This
->ThreadSignal
);
529 LeaveCriticalSection(&This
->csRenderLock
);
534 HRESULT WINAPI
BaseRendererImpl_SetSyncSource(IBaseFilter
*iface
, IReferenceClock
*clock
)
536 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
539 EnterCriticalSection(&This
->filter
.csFilter
);
540 QualityControlRender_SetClock(This
->qcimpl
, clock
);
541 hr
= BaseFilterImpl_SetSyncSource(iface
, clock
);
542 LeaveCriticalSection(&This
->filter
.csFilter
);
547 HRESULT WINAPI
BaseRendererImpl_GetState(IBaseFilter
* iface
, DWORD dwMilliSecsTimeout
, FILTER_STATE
*pState
)
550 BaseRenderer
*This
= impl_from_IBaseFilter(iface
);
552 TRACE("(%p)->(%d, %p)\n", This
, dwMilliSecsTimeout
, pState
);
554 if (WaitForSingleObject(This
->evComplete
, dwMilliSecsTimeout
) == WAIT_TIMEOUT
)
555 hr
= VFW_S_STATE_INTERMEDIATE
;
559 BaseFilterImpl_GetState(iface
, dwMilliSecsTimeout
, pState
);
564 HRESULT WINAPI
BaseRendererImpl_EndOfStream(BaseRenderer
* iface
)
566 IMediaEventSink
* pEventSink
;
570 TRACE("(%p)\n", iface
);
572 graph
= iface
->filter
.filterInfo
.pGraph
;
574 { hr
= IFilterGraph_QueryInterface(iface
->filter
.filterInfo
.pGraph
, &IID_IMediaEventSink
, (LPVOID
*)&pEventSink
);
577 hr
= IMediaEventSink_Notify(pEventSink
, EC_COMPLETE
, S_OK
, (LONG_PTR
)iface
);
578 IMediaEventSink_Release(pEventSink
);
581 RendererPosPassThru_EOS(iface
->pPosition
);
582 SetEvent(iface
->evComplete
);
587 HRESULT WINAPI
BaseRendererImpl_BeginFlush(BaseRenderer
* iface
)
589 TRACE("(%p)\n", iface
);
590 BaseRendererImpl_ClearPendingSample(iface
);
591 SetEvent(iface
->ThreadSignal
);
592 SetEvent(iface
->RenderEvent
);
596 HRESULT WINAPI
BaseRendererImpl_EndFlush(BaseRenderer
* iface
)
598 TRACE("(%p)\n", iface
);
599 QualityControlRender_Start(iface
->qcimpl
, iface
->filter
.rtStreamStart
);
600 RendererPosPassThru_ResetMediaTime(iface
->pPosition
);
601 ResetEvent(iface
->ThreadSignal
);
602 ResetEvent(iface
->RenderEvent
);
606 HRESULT WINAPI
BaseRendererImpl_ClearPendingSample(BaseRenderer
*iface
)
608 if (iface
->pMediaSample
)
610 IMediaSample_Release(iface
->pMediaSample
);
611 iface
->pMediaSample
= NULL
;