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 WINE_DEFAULT_DEBUG_CHANNEL(strmbase
);
25 static inline struct strmbase_renderer
*impl_from_strmbase_filter(struct strmbase_filter
*iface
)
27 return CONTAINING_RECORD(iface
, struct strmbase_renderer
, filter
);
30 static inline struct strmbase_renderer
*impl_from_IPin(IPin
*iface
)
32 return CONTAINING_RECORD(iface
, struct strmbase_renderer
, sink
.pin
.IPin_iface
);
35 static struct strmbase_pin
*renderer_get_pin(struct strmbase_filter
*iface
, unsigned int index
)
37 struct strmbase_renderer
*filter
= impl_from_strmbase_filter(iface
);
40 return &filter
->sink
.pin
;
44 static void renderer_destroy(struct strmbase_filter
*iface
)
46 struct strmbase_renderer
*filter
= impl_from_strmbase_filter(iface
);
47 filter
->pFuncsTable
->renderer_destroy(filter
);
50 static HRESULT
renderer_query_interface(struct strmbase_filter
*iface
, REFIID iid
, void **out
)
52 struct strmbase_renderer
*filter
= impl_from_strmbase_filter(iface
);
55 if (filter
->pFuncsTable
->renderer_query_interface
56 && SUCCEEDED(hr
= filter
->pFuncsTable
->renderer_query_interface(filter
, iid
, out
)))
61 if (IsEqualGUID(iid
, &IID_IMediaPosition
))
62 *out
= &filter
->passthrough
.IMediaPosition_iface
;
63 else if (IsEqualGUID(iid
, &IID_IMediaSeeking
))
64 *out
= &filter
->passthrough
.IMediaSeeking_iface
;
65 else if (IsEqualGUID(iid
, &IID_IQualityControl
))
66 *out
= &filter
->qc
.IQualityControl_iface
;
70 IUnknown_AddRef((IUnknown
*)*out
);
74 static HRESULT
renderer_init_stream(struct strmbase_filter
*iface
)
76 struct strmbase_renderer
*filter
= impl_from_strmbase_filter(iface
);
78 if (filter
->sink
.pin
.peer
)
79 ResetEvent(filter
->state_event
);
81 ResetEvent(filter
->flush_event
);
82 if (filter
->pFuncsTable
->renderer_init_stream
)
83 filter
->pFuncsTable
->renderer_init_stream(filter
);
85 return filter
->sink
.pin
.peer
? S_FALSE
: S_OK
;
88 static HRESULT
renderer_start_stream(struct strmbase_filter
*iface
, REFERENCE_TIME start
)
90 struct strmbase_renderer
*filter
= impl_from_strmbase_filter(iface
);
92 filter
->stream_start
= start
;
93 SetEvent(filter
->state_event
);
94 if (filter
->sink
.pin
.peer
)
96 QualityControlRender_Start(&filter
->qc
, filter
->stream_start
);
97 if (filter
->sink
.pin
.peer
&& filter
->pFuncsTable
->renderer_start_stream
)
98 filter
->pFuncsTable
->renderer_start_stream(filter
);
103 static HRESULT
renderer_stop_stream(struct strmbase_filter
*iface
)
105 struct strmbase_renderer
*filter
= impl_from_strmbase_filter(iface
);
107 if (filter
->sink
.pin
.peer
&& filter
->pFuncsTable
->renderer_stop_stream
)
108 filter
->pFuncsTable
->renderer_stop_stream(filter
);
113 static HRESULT
renderer_cleanup_stream(struct strmbase_filter
*iface
)
115 struct strmbase_renderer
*filter
= impl_from_strmbase_filter(iface
);
117 strmbase_passthrough_invalidate_time(&filter
->passthrough
);
118 SetEvent(filter
->state_event
);
119 SetEvent(filter
->flush_event
);
124 static HRESULT
renderer_wait_state(struct strmbase_filter
*iface
, DWORD timeout
)
126 struct strmbase_renderer
*filter
= impl_from_strmbase_filter(iface
);
128 if (WaitForSingleObject(filter
->state_event
, timeout
) == WAIT_TIMEOUT
)
129 return VFW_S_STATE_INTERMEDIATE
;
133 static const struct strmbase_filter_ops filter_ops
=
135 .filter_get_pin
= renderer_get_pin
,
136 .filter_destroy
= renderer_destroy
,
137 .filter_query_interface
= renderer_query_interface
,
138 .filter_init_stream
= renderer_init_stream
,
139 .filter_start_stream
= renderer_start_stream
,
140 .filter_stop_stream
= renderer_stop_stream
,
141 .filter_cleanup_stream
= renderer_cleanup_stream
,
142 .filter_wait_state
= renderer_wait_state
,
145 static HRESULT
sink_query_accept(struct strmbase_pin
*pin
, const AM_MEDIA_TYPE
*mt
)
147 struct strmbase_renderer
*filter
= impl_from_IPin(&pin
->IPin_iface
);
148 return filter
->pFuncsTable
->pfnCheckMediaType(filter
, mt
);
151 static HRESULT
sink_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
153 struct strmbase_renderer
*filter
= impl_from_IPin(&iface
->IPin_iface
);
156 if (filter
->pFuncsTable
->renderer_pin_query_interface
157 && SUCCEEDED(hr
= filter
->pFuncsTable
->renderer_pin_query_interface(filter
, iid
, out
)))
160 if (IsEqualGUID(iid
, &IID_IMemInputPin
))
161 *out
= &filter
->sink
.IMemInputPin_iface
;
163 return E_NOINTERFACE
;
165 IUnknown_AddRef((IUnknown
*)*out
);
169 static HRESULT WINAPI
BaseRenderer_Receive(struct strmbase_sink
*pin
, IMediaSample
*sample
)
171 struct strmbase_renderer
*filter
= impl_from_IPin(&pin
->pin
.IPin_iface
);
172 REFERENCE_TIME start
, stop
;
173 BOOL need_wait
= FALSE
;
178 if (filter
->eos
|| filter
->sink
.flushing
)
181 state
= filter
->filter
.state
;
182 if (state
== State_Stopped
)
183 return VFW_E_WRONG_STATE
;
185 if (IMediaSample_GetMediaType(sample
, &mt
) == S_OK
)
187 TRACE("Format change.\n");
188 strmbase_dump_media_type(mt
);
190 if (FAILED(filter
->pFuncsTable
->pfnCheckMediaType(filter
, mt
)))
191 return VFW_E_TYPE_NOT_ACCEPTED
;
195 EnterCriticalSection(&filter
->csRenderLock
);
197 if (filter
->filter
.clock
&& SUCCEEDED(IMediaSample_GetTime(sample
, &start
, &stop
)))
199 strmbase_passthrough_update_time(&filter
->passthrough
, start
);
205 if (state
== State_Paused
)
207 QualityControlRender_BeginRender(&filter
->qc
, start
, stop
);
208 hr
= filter
->pFuncsTable
->pfnDoRenderSample(filter
, sample
);
209 QualityControlRender_EndRender(&filter
->qc
);
217 IReferenceClock_GetTime(filter
->filter
.clock
, &now
);
219 if (now
- filter
->stream_start
- start
<= -10000)
221 HANDLE handles
[2] = {filter
->advise_event
, filter
->flush_event
};
224 IReferenceClock_AdviseTime(filter
->filter
.clock
, filter
->stream_start
,
225 start
, (HEVENT
)filter
->advise_event
, &cookie
);
227 LeaveCriticalSection(&filter
->csRenderLock
);
229 ret
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
230 IReferenceClock_Unadvise(filter
->filter
.clock
, cookie
);
234 TRACE("Flush signaled; discarding current sample.\n");
238 EnterCriticalSection(&filter
->csRenderLock
);
242 if (state
== State_Running
)
244 QualityControlRender_BeginRender(&filter
->qc
, start
, stop
);
245 hr
= filter
->pFuncsTable
->pfnDoRenderSample(filter
, sample
);
246 QualityControlRender_EndRender(&filter
->qc
);
249 QualityControlRender_DoQOS(&filter
->qc
);
251 LeaveCriticalSection(&filter
->csRenderLock
);
256 static HRESULT
sink_connect(struct strmbase_sink
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
258 struct strmbase_renderer
*filter
= impl_from_IPin(&iface
->pin
.IPin_iface
);
260 if (filter
->pFuncsTable
->renderer_connect
)
261 return filter
->pFuncsTable
->renderer_connect(filter
, mt
);
265 static void sink_disconnect(struct strmbase_sink
*iface
)
267 struct strmbase_renderer
*filter
= impl_from_IPin(&iface
->pin
.IPin_iface
);
269 if (filter
->pFuncsTable
->pfnBreakConnect
)
270 filter
->pFuncsTable
->pfnBreakConnect(filter
);
273 static HRESULT
sink_eos(struct strmbase_sink
*iface
)
275 struct strmbase_renderer
*filter
= impl_from_IPin(&iface
->pin
.IPin_iface
);
276 IFilterGraph
*graph
= filter
->filter
.graph
;
277 IMediaEventSink
*event_sink
;
279 EnterCriticalSection(&filter
->csRenderLock
);
283 if (graph
&& SUCCEEDED(IFilterGraph_QueryInterface(graph
,
284 &IID_IMediaEventSink
, (void **)&event_sink
)))
286 IMediaEventSink_Notify(event_sink
, EC_COMPLETE
, S_OK
,
287 (LONG_PTR
)&filter
->filter
.IBaseFilter_iface
);
288 IMediaEventSink_Release(event_sink
);
290 strmbase_passthrough_eos(&filter
->passthrough
);
291 SetEvent(filter
->state_event
);
293 LeaveCriticalSection(&filter
->csRenderLock
);
297 static HRESULT
sink_begin_flush(struct strmbase_sink
*iface
)
299 struct strmbase_renderer
*filter
= impl_from_IPin(&iface
->pin
.IPin_iface
);
301 SetEvent(filter
->flush_event
);
306 static HRESULT
sink_end_flush(struct strmbase_sink
*iface
)
308 struct strmbase_renderer
*filter
= impl_from_IPin(&iface
->pin
.IPin_iface
);
310 EnterCriticalSection(&filter
->csRenderLock
);
313 QualityControlRender_Start(&filter
->qc
, filter
->stream_start
);
314 strmbase_passthrough_invalidate_time(&filter
->passthrough
);
315 ResetEvent(filter
->flush_event
);
317 LeaveCriticalSection(&filter
->csRenderLock
);
321 static const struct strmbase_sink_ops sink_ops
=
323 .base
.pin_query_accept
= sink_query_accept
,
324 .base
.pin_query_interface
= sink_query_interface
,
325 .pfnReceive
= BaseRenderer_Receive
,
326 .sink_connect
= sink_connect
,
327 .sink_disconnect
= sink_disconnect
,
328 .sink_eos
= sink_eos
,
329 .sink_begin_flush
= sink_begin_flush
,
330 .sink_end_flush
= sink_end_flush
,
333 void strmbase_renderer_cleanup(struct strmbase_renderer
*filter
)
335 if (filter
->sink
.pin
.peer
)
336 IPin_Disconnect(filter
->sink
.pin
.peer
);
337 IPin_Disconnect(&filter
->sink
.pin
.IPin_iface
);
338 strmbase_sink_cleanup(&filter
->sink
);
340 strmbase_passthrough_cleanup(&filter
->passthrough
);
342 filter
->csRenderLock
.DebugInfo
->Spare
[0] = 0;
343 DeleteCriticalSection(&filter
->csRenderLock
);
345 CloseHandle(filter
->state_event
);
346 CloseHandle(filter
->advise_event
);
347 CloseHandle(filter
->flush_event
);
348 strmbase_filter_cleanup(&filter
->filter
);
351 void strmbase_renderer_init(struct strmbase_renderer
*filter
, IUnknown
*outer
,
352 const CLSID
*clsid
, const WCHAR
*sink_name
, const struct strmbase_renderer_ops
*ops
)
354 memset(filter
, 0, sizeof(*filter
));
355 strmbase_filter_init(&filter
->filter
, outer
, clsid
, &filter_ops
);
356 strmbase_passthrough_init(&filter
->passthrough
, (IUnknown
*)&filter
->filter
.IBaseFilter_iface
);
357 ISeekingPassThru_Init(&filter
->passthrough
.ISeekingPassThru_iface
, TRUE
, &filter
->sink
.pin
.IPin_iface
);
358 strmbase_qc_init(&filter
->qc
, &filter
->sink
.pin
);
360 filter
->pFuncsTable
= ops
;
362 strmbase_sink_init(&filter
->sink
, &filter
->filter
, sink_name
, &sink_ops
, NULL
);
364 InitializeCriticalSection(&filter
->csRenderLock
);
365 filter
->csRenderLock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": strmbase_renderer.csRenderLock");
366 filter
->state_event
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);
367 filter
->advise_event
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
368 filter
->flush_event
= CreateEventW(NULL
, TRUE
, TRUE
, NULL
);