wined3d: Use "depth_size"/"stencil_size" to check for depth/stencil formats in textur...
[wine.git] / dlls / strmbase / renderer.c
blobf1e74f64764ef3ee079cb6d73c8c3b7447702c5a
1 /*
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 const IQualityControlVtbl Renderer_QualityControl_Vtbl = {
31 QualityControlImpl_QueryInterface,
32 QualityControlImpl_AddRef,
33 QualityControlImpl_Release,
34 QualityControlImpl_Notify,
35 QualityControlImpl_SetSink
38 static inline struct strmbase_renderer *impl_from_IPin(IPin *iface)
40 return CONTAINING_RECORD(iface, struct strmbase_renderer, sink.pin.IPin_iface);
43 static struct strmbase_pin *renderer_get_pin(struct strmbase_filter *iface, unsigned int index)
45 struct strmbase_renderer *filter = impl_from_strmbase_filter(iface);
47 if (index == 0)
48 return &filter->sink.pin;
49 return NULL;
52 static void renderer_destroy(struct strmbase_filter *iface)
54 struct strmbase_renderer *filter = impl_from_strmbase_filter(iface);
55 filter->pFuncsTable->renderer_destroy(filter);
58 static HRESULT renderer_query_interface(struct strmbase_filter *iface, REFIID iid, void **out)
60 struct strmbase_renderer *filter = impl_from_strmbase_filter(iface);
61 HRESULT hr;
63 if (filter->pFuncsTable->renderer_query_interface
64 && SUCCEEDED(hr = filter->pFuncsTable->renderer_query_interface(filter, iid, out)))
66 return hr;
69 if (IsEqualGUID(iid, &IID_IMediaPosition))
70 *out = &filter->passthrough.IMediaPosition_iface;
71 else if (IsEqualGUID(iid, &IID_IMediaSeeking))
72 *out = &filter->passthrough.IMediaSeeking_iface;
73 else if (IsEqualGUID(iid, &IID_IQualityControl))
74 *out = &filter->qcimpl->IQualityControl_iface;
75 else
76 return E_NOINTERFACE;
78 IUnknown_AddRef((IUnknown *)*out);
79 return S_OK;
82 static HRESULT renderer_init_stream(struct strmbase_filter *iface)
84 struct strmbase_renderer *filter = impl_from_strmbase_filter(iface);
86 if (filter->sink.pin.peer)
87 ResetEvent(filter->state_event);
88 filter->eos = FALSE;
89 ResetEvent(filter->flush_event);
90 if (filter->pFuncsTable->renderer_init_stream)
91 filter->pFuncsTable->renderer_init_stream(filter);
93 return filter->sink.pin.peer ? S_FALSE : S_OK;
96 static HRESULT renderer_start_stream(struct strmbase_filter *iface, REFERENCE_TIME start)
98 struct strmbase_renderer *filter = impl_from_strmbase_filter(iface);
100 filter->stream_start = start;
101 SetEvent(filter->state_event);
102 if (filter->sink.pin.peer)
103 filter->eos = FALSE;
104 QualityControlRender_Start(filter->qcimpl, filter->stream_start);
105 if (filter->sink.pin.peer && filter->pFuncsTable->renderer_start_stream)
106 filter->pFuncsTable->renderer_start_stream(filter);
108 return S_OK;
111 static HRESULT renderer_stop_stream(struct strmbase_filter *iface)
113 struct strmbase_renderer *filter = impl_from_strmbase_filter(iface);
115 if (filter->sink.pin.peer && filter->pFuncsTable->renderer_stop_stream)
116 filter->pFuncsTable->renderer_stop_stream(filter);
118 return S_OK;
121 static HRESULT renderer_cleanup_stream(struct strmbase_filter *iface)
123 struct strmbase_renderer *filter = impl_from_strmbase_filter(iface);
125 strmbase_passthrough_invalidate_time(&filter->passthrough);
126 SetEvent(filter->state_event);
127 SetEvent(filter->flush_event);
129 return S_OK;
132 static HRESULT renderer_wait_state(struct strmbase_filter *iface, DWORD timeout)
134 struct strmbase_renderer *filter = impl_from_strmbase_filter(iface);
136 if (WaitForSingleObject(filter->state_event, timeout) == WAIT_TIMEOUT)
137 return VFW_S_STATE_INTERMEDIATE;
138 return S_OK;
141 static const struct strmbase_filter_ops filter_ops =
143 .filter_get_pin = renderer_get_pin,
144 .filter_destroy = renderer_destroy,
145 .filter_query_interface = renderer_query_interface,
146 .filter_init_stream = renderer_init_stream,
147 .filter_start_stream = renderer_start_stream,
148 .filter_stop_stream = renderer_stop_stream,
149 .filter_cleanup_stream = renderer_cleanup_stream,
150 .filter_wait_state = renderer_wait_state,
153 static HRESULT sink_query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt)
155 struct strmbase_renderer *filter = impl_from_IPin(&pin->IPin_iface);
156 return filter->pFuncsTable->pfnCheckMediaType(filter, mt);
159 static HRESULT sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
161 struct strmbase_renderer *filter = impl_from_IPin(&iface->IPin_iface);
162 HRESULT hr;
164 if (filter->pFuncsTable->renderer_pin_query_interface
165 && SUCCEEDED(hr = filter->pFuncsTable->renderer_pin_query_interface(filter, iid, out)))
166 return hr;
168 if (IsEqualGUID(iid, &IID_IMemInputPin))
169 *out = &filter->sink.IMemInputPin_iface;
170 else
171 return E_NOINTERFACE;
173 IUnknown_AddRef((IUnknown *)*out);
174 return S_OK;
177 static HRESULT WINAPI BaseRenderer_Receive(struct strmbase_sink *pin, IMediaSample *sample)
179 struct strmbase_renderer *filter = impl_from_IPin(&pin->pin.IPin_iface);
180 return BaseRendererImpl_Receive(filter, sample);
183 static HRESULT sink_connect(struct strmbase_sink *iface, IPin *peer, const AM_MEDIA_TYPE *mt)
185 struct strmbase_renderer *filter = impl_from_IPin(&iface->pin.IPin_iface);
187 if (filter->pFuncsTable->renderer_connect)
188 return filter->pFuncsTable->renderer_connect(filter, mt);
189 return S_OK;
192 static void sink_disconnect(struct strmbase_sink *iface)
194 struct strmbase_renderer *filter = impl_from_IPin(&iface->pin.IPin_iface);
196 if (filter->pFuncsTable->pfnBreakConnect)
197 filter->pFuncsTable->pfnBreakConnect(filter);
200 static HRESULT sink_eos(struct strmbase_sink *iface)
202 struct strmbase_renderer *filter = impl_from_IPin(&iface->pin.IPin_iface);
203 IFilterGraph *graph = filter->filter.graph;
204 IMediaEventSink *event_sink;
205 HRESULT hr = S_OK;
207 EnterCriticalSection(&filter->csRenderLock);
209 filter->eos = TRUE;
211 if (graph && SUCCEEDED(IFilterGraph_QueryInterface(graph,
212 &IID_IMediaEventSink, (void **)&event_sink)))
214 IMediaEventSink_Notify(event_sink, EC_COMPLETE, S_OK,
215 (LONG_PTR)&filter->filter.IBaseFilter_iface);
216 IMediaEventSink_Release(event_sink);
218 strmbase_passthrough_eos(&filter->passthrough);
219 SetEvent(filter->state_event);
221 if (filter->pFuncsTable->pfnEndOfStream)
222 hr = filter->pFuncsTable->pfnEndOfStream(filter);
224 LeaveCriticalSection(&filter->csRenderLock);
225 return hr;
228 static HRESULT sink_begin_flush(struct strmbase_sink *iface)
230 struct strmbase_renderer *filter = impl_from_IPin(&iface->pin.IPin_iface);
232 SetEvent(filter->flush_event);
234 return S_OK;
237 static HRESULT sink_end_flush(struct strmbase_sink *iface)
239 struct strmbase_renderer *filter = impl_from_IPin(&iface->pin.IPin_iface);
240 HRESULT hr = S_OK;
242 EnterCriticalSection(&filter->csRenderLock);
244 filter->eos = FALSE;
245 QualityControlRender_Start(filter->qcimpl, filter->stream_start);
246 strmbase_passthrough_invalidate_time(&filter->passthrough);
247 ResetEvent(filter->flush_event);
249 if (filter->pFuncsTable->pfnEndFlush)
250 hr = filter->pFuncsTable->pfnEndFlush(filter);
252 LeaveCriticalSection(&filter->csRenderLock);
253 return hr;
256 static const struct strmbase_sink_ops sink_ops =
258 .base.pin_query_accept = sink_query_accept,
259 .base.pin_query_interface = sink_query_interface,
260 .pfnReceive = BaseRenderer_Receive,
261 .sink_connect = sink_connect,
262 .sink_disconnect = sink_disconnect,
263 .sink_eos = sink_eos,
264 .sink_begin_flush = sink_begin_flush,
265 .sink_end_flush = sink_end_flush,
268 void strmbase_renderer_cleanup(struct strmbase_renderer *filter)
270 if (filter->sink.pin.peer)
271 IPin_Disconnect(filter->sink.pin.peer);
272 IPin_Disconnect(&filter->sink.pin.IPin_iface);
273 strmbase_sink_cleanup(&filter->sink);
275 strmbase_passthrough_cleanup(&filter->passthrough);
277 filter->csRenderLock.DebugInfo->Spare[0] = 0;
278 DeleteCriticalSection(&filter->csRenderLock);
280 CloseHandle(filter->state_event);
281 CloseHandle(filter->advise_event);
282 CloseHandle(filter->flush_event);
283 QualityControlImpl_Destroy(filter->qcimpl);
284 strmbase_filter_cleanup(&filter->filter);
287 HRESULT WINAPI BaseRendererImpl_Receive(struct strmbase_renderer *This, IMediaSample *pSample)
289 HRESULT hr = S_OK;
290 REFERENCE_TIME start, stop;
291 AM_MEDIA_TYPE *pmt;
293 TRACE("(%p)->%p\n", This, pSample);
295 if (This->eos || This->sink.flushing)
296 return S_FALSE;
298 if (This->filter.state == State_Stopped)
299 return VFW_E_WRONG_STATE;
301 if (IMediaSample_GetMediaType(pSample, &pmt) == S_OK)
303 TRACE("Format change.\n");
304 strmbase_dump_media_type(pmt);
306 if (FAILED(This->pFuncsTable->pfnCheckMediaType(This, pmt)))
308 return VFW_E_TYPE_NOT_ACCEPTED;
310 DeleteMediaType(pmt);
313 if (This->pFuncsTable->pfnPrepareReceive)
314 hr = This->pFuncsTable->pfnPrepareReceive(This, pSample);
315 if (FAILED(hr))
317 if (hr == VFW_E_SAMPLE_REJECTED)
318 return S_OK;
319 else
320 return hr;
323 EnterCriticalSection(&This->csRenderLock);
324 if (This->filter.state == State_Paused)
325 SetEvent(This->state_event);
327 /* Wait for render Time */
328 if (This->filter.clock && SUCCEEDED(IMediaSample_GetTime(pSample, &start, &stop)))
330 hr = S_FALSE;
331 strmbase_passthrough_update_time(&This->passthrough, start);
332 if (This->pFuncsTable->pfnShouldDrawSampleNow)
333 hr = This->pFuncsTable->pfnShouldDrawSampleNow(This, pSample, &start, &stop);
335 if (hr == S_OK)
336 ;/* Do not wait: drop through */
337 else if (hr == S_FALSE)
339 REFERENCE_TIME now;
340 DWORD_PTR cookie;
342 IReferenceClock_GetTime(This->filter.clock, &now);
344 if (now - This->stream_start - start <= -10000)
346 HANDLE handles[2] = {This->advise_event, This->flush_event};
347 DWORD ret;
349 IReferenceClock_AdviseTime(This->filter.clock, This->stream_start,
350 start, (HEVENT)This->advise_event, &cookie);
352 LeaveCriticalSection(&This->csRenderLock);
354 ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
355 IReferenceClock_Unadvise(This->filter.clock, cookie);
357 if (ret == 1)
359 TRACE("Flush signaled, discarding current sample.\n");
360 return S_OK;
363 EnterCriticalSection(&This->csRenderLock);
366 else
368 LeaveCriticalSection(&This->csRenderLock);
369 /* Drop Sample */
370 return S_OK;
373 else
374 start = stop = -1;
376 if (SUCCEEDED(hr))
378 QualityControlRender_BeginRender(This->qcimpl, start, stop);
379 hr = This->pFuncsTable->pfnDoRenderSample(This, pSample);
380 QualityControlRender_EndRender(This->qcimpl);
383 QualityControlRender_DoQOS(This->qcimpl);
385 LeaveCriticalSection(&This->csRenderLock);
387 return hr;
390 void strmbase_renderer_init(struct strmbase_renderer *filter, IUnknown *outer,
391 const CLSID *clsid, const WCHAR *sink_name, const struct strmbase_renderer_ops *ops)
393 memset(filter, 0, sizeof(*filter));
394 strmbase_filter_init(&filter->filter, outer, clsid, &filter_ops);
395 strmbase_passthrough_init(&filter->passthrough, (IUnknown *)&filter->filter.IBaseFilter_iface);
396 ISeekingPassThru_Init(&filter->passthrough.ISeekingPassThru_iface, TRUE, &filter->sink.pin.IPin_iface);
398 filter->pFuncsTable = ops;
400 strmbase_sink_init(&filter->sink, &filter->filter, sink_name, &sink_ops, NULL);
402 InitializeCriticalSection(&filter->csRenderLock);
403 filter->csRenderLock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": strmbase_renderer.csRenderLock");
404 filter->state_event = CreateEventW(NULL, TRUE, TRUE, NULL);
405 filter->advise_event = CreateEventW(NULL, FALSE, FALSE, NULL);
406 filter->flush_event = CreateEventW(NULL, TRUE, TRUE, NULL);
408 QualityControlImpl_Create(&filter->sink.pin, &filter->qcimpl);
409 filter->qcimpl->IQualityControl_iface.lpVtbl = &Renderer_QualityControl_Vtbl;