Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/strmbase/renderer.c | 142 ++++++++++++++++++--------------------- include/wine/strmbase.h | 2 - 2 files changed, 66 insertions(+), 78 deletions(-)
diff --git a/dlls/strmbase/renderer.c b/dlls/strmbase/renderer.c index 1f0a747a2ce..bc2d0551fe3 100644 --- a/dlls/strmbase/renderer.c +++ b/dlls/strmbase/renderer.c @@ -169,7 +169,72 @@ static HRESULT sink_query_interface(struct strmbase_pin *iface, REFIID iid, void static HRESULT WINAPI BaseRenderer_Receive(struct strmbase_sink *pin, IMediaSample *sample) { struct strmbase_renderer *filter = impl_from_IPin(&pin->pin.IPin_iface); - return BaseRendererImpl_Receive(filter, sample); + REFERENCE_TIME start, stop; + AM_MEDIA_TYPE *mt; + HRESULT hr; + + if (filter->eos || filter->sink.flushing) + return S_FALSE; + + if (filter->filter.state == State_Stopped) + return VFW_E_WRONG_STATE; + + if (IMediaSample_GetMediaType(sample, &mt) == S_OK) + { + TRACE("Format change.\n"); + strmbase_dump_media_type(mt); + + if (FAILED(filter->pFuncsTable->pfnCheckMediaType(filter, mt))) + return VFW_E_TYPE_NOT_ACCEPTED; + DeleteMediaType(mt); + } + + EnterCriticalSection(&filter->csRenderLock); + if (filter->filter.state == State_Paused) + SetEvent(filter->state_event); + + if (filter->filter.clock && SUCCEEDED(IMediaSample_GetTime(sample, &start, &stop))) + { + REFERENCE_TIME now; + DWORD_PTR cookie; + + strmbase_passthrough_update_time(&filter->passthrough, start); + + IReferenceClock_GetTime(filter->filter.clock, &now); + + if (now - filter->stream_start - start <= -10000) + { + HANDLE handles[2] = {filter->advise_event, filter->flush_event}; + DWORD ret; + + IReferenceClock_AdviseTime(filter->filter.clock, filter->stream_start, + start, (HEVENT)filter->advise_event, &cookie); + + LeaveCriticalSection(&filter->csRenderLock); + + ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE); + IReferenceClock_Unadvise(filter->filter.clock, cookie); + + if (ret == 1) + { + TRACE("Flush signaled; discarding current sample.\n"); + return S_OK; + } + + EnterCriticalSection(&filter->csRenderLock); + } + } + else + start = stop = -1; + + QualityControlRender_BeginRender(&filter->qc, start, stop); + hr = filter->pFuncsTable->pfnDoRenderSample(filter, sample); + QualityControlRender_EndRender(&filter->qc); + QualityControlRender_DoQOS(&filter->qc); + + LeaveCriticalSection(&filter->csRenderLock); + + return hr; }
static HRESULT sink_connect(struct strmbase_sink *iface, IPin *peer, const AM_MEDIA_TYPE *mt) @@ -267,81 +332,6 @@ void strmbase_renderer_cleanup(struct strmbase_renderer *filter) strmbase_filter_cleanup(&filter->filter); }
-HRESULT WINAPI BaseRendererImpl_Receive(struct strmbase_renderer *This, IMediaSample *pSample) -{ - REFERENCE_TIME start, stop; - AM_MEDIA_TYPE *pmt; - HRESULT hr; - - TRACE("(%p)->%p\n", This, pSample); - - if (This->eos || This->sink.flushing) - return S_FALSE; - - if (This->filter.state == State_Stopped) - return VFW_E_WRONG_STATE; - - if (IMediaSample_GetMediaType(pSample, &pmt) == S_OK) - { - TRACE("Format change.\n"); - strmbase_dump_media_type(pmt); - - if (FAILED(This->pFuncsTable->pfnCheckMediaType(This, pmt))) - { - return VFW_E_TYPE_NOT_ACCEPTED; - } - DeleteMediaType(pmt); - } - - EnterCriticalSection(&This->csRenderLock); - if (This->filter.state == State_Paused) - SetEvent(This->state_event); - - /* Wait for render Time */ - if (This->filter.clock && SUCCEEDED(IMediaSample_GetTime(pSample, &start, &stop))) - { - REFERENCE_TIME now; - DWORD_PTR cookie; - - strmbase_passthrough_update_time(&This->passthrough, start); - - IReferenceClock_GetTime(This->filter.clock, &now); - - if (now - This->stream_start - start <= -10000) - { - HANDLE handles[2] = {This->advise_event, This->flush_event}; - DWORD ret; - - IReferenceClock_AdviseTime(This->filter.clock, This->stream_start, - start, (HEVENT)This->advise_event, &cookie); - - LeaveCriticalSection(&This->csRenderLock); - - ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE); - IReferenceClock_Unadvise(This->filter.clock, cookie); - - if (ret == 1) - { - TRACE("Flush signaled, discarding current sample.\n"); - return S_OK; - } - - EnterCriticalSection(&This->csRenderLock); - } - } - else - start = stop = -1; - - QualityControlRender_BeginRender(&This->qc, start, stop); - hr = This->pFuncsTable->pfnDoRenderSample(This, pSample); - QualityControlRender_EndRender(&This->qc); - QualityControlRender_DoQOS(&This->qc); - - LeaveCriticalSection(&This->csRenderLock); - - return hr; -} - void strmbase_renderer_init(struct strmbase_renderer *filter, IUnknown *outer, const CLSID *clsid, const WCHAR *sink_name, const struct strmbase_renderer_ops *ops) { diff --git a/include/wine/strmbase.h b/include/wine/strmbase.h index 9e0d4e7d479..24bb97702b5 100644 --- a/include/wine/strmbase.h +++ b/include/wine/strmbase.h @@ -334,8 +334,6 @@ struct strmbase_renderer_ops HRESULT (*renderer_pin_query_interface)(struct strmbase_renderer *iface, REFIID iid, void **out); };
-HRESULT WINAPI BaseRendererImpl_Receive(struct strmbase_renderer *filter, IMediaSample *sample); - void strmbase_renderer_init(struct strmbase_renderer *filter, IUnknown *outer, const CLSID *clsid, const WCHAR *sink_name, const struct strmbase_renderer_ops *ops); void strmbase_renderer_cleanup(struct strmbase_renderer *filter);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/strmbase/renderer.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-)
diff --git a/dlls/strmbase/renderer.c b/dlls/strmbase/renderer.c index bc2d0551fe3..b6d552b3b0a 100644 --- a/dlls/strmbase/renderer.c +++ b/dlls/strmbase/renderer.c @@ -170,13 +170,16 @@ static HRESULT WINAPI BaseRenderer_Receive(struct strmbase_sink *pin, IMediaSamp { struct strmbase_renderer *filter = impl_from_IPin(&pin->pin.IPin_iface); REFERENCE_TIME start, stop; + BOOL need_wait = FALSE; + FILTER_STATE state; + HRESULT hr = S_OK; AM_MEDIA_TYPE *mt; - HRESULT hr;
if (filter->eos || filter->sink.flushing) return S_FALSE;
- if (filter->filter.state == State_Stopped) + state = filter->filter.state; + if (state == State_Stopped) return VFW_E_WRONG_STATE;
if (IMediaSample_GetMediaType(sample, &mt) == S_OK) @@ -194,12 +197,25 @@ static HRESULT WINAPI BaseRenderer_Receive(struct strmbase_sink *pin, IMediaSamp SetEvent(filter->state_event);
if (filter->filter.clock && SUCCEEDED(IMediaSample_GetTime(sample, &start, &stop))) + { + strmbase_passthrough_update_time(&filter->passthrough, start); + need_wait = TRUE; + } + else + start = stop = -1; + + if (state == State_Paused) + { + QualityControlRender_BeginRender(&filter->qc, start, stop); + hr = filter->pFuncsTable->pfnDoRenderSample(filter, sample); + QualityControlRender_EndRender(&filter->qc); + } + + if (need_wait) { REFERENCE_TIME now; DWORD_PTR cookie;
- strmbase_passthrough_update_time(&filter->passthrough, start); - IReferenceClock_GetTime(filter->filter.clock, &now);
if (now - filter->stream_start - start <= -10000) @@ -224,12 +240,14 @@ static HRESULT WINAPI BaseRenderer_Receive(struct strmbase_sink *pin, IMediaSamp EnterCriticalSection(&filter->csRenderLock); } } - else - start = stop = -1;
- QualityControlRender_BeginRender(&filter->qc, start, stop); - hr = filter->pFuncsTable->pfnDoRenderSample(filter, sample); - QualityControlRender_EndRender(&filter->qc); + if (state == State_Running) + { + QualityControlRender_BeginRender(&filter->qc, start, stop); + hr = filter->pFuncsTable->pfnDoRenderSample(filter, sample); + QualityControlRender_EndRender(&filter->qc); + } + QualityControlRender_DoQOS(&filter->qc);
LeaveCriticalSection(&filter->csRenderLock);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/qedit/nullrenderer.c | 5 +++++ dlls/quartz/tests/vmr9.c | 5 +++++ dlls/quartz/videorenderer.c | 1 + dlls/quartz/vmr9.c | 1 + dlls/strmbase/renderer.c | 2 -- 5 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/dlls/qedit/nullrenderer.c b/dlls/qedit/nullrenderer.c index e703ea24305..c64d5e2987c 100644 --- a/dlls/qedit/nullrenderer.c +++ b/dlls/qedit/nullrenderer.c @@ -38,6 +38,11 @@ static struct null_renderer *impl_from_strmbase_renderer(struct strmbase_rendere
static HRESULT WINAPI NullRenderer_DoRenderSample(struct strmbase_renderer *iface, IMediaSample *sample) { + struct null_renderer *filter = impl_from_strmbase_renderer(iface); + + if (filter->renderer.filter.state == State_Paused) + SetEvent(filter->renderer.state_event); + return S_OK; }
diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index e630deb8d74..a2fd5b76861 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -2943,6 +2943,11 @@ static void test_renderless_present(IFilterGraph2 *graph, IMemInputPin *input) thread = send_frame(input); hr = IMediaControl_GetState(control, 1000, &state); ok(hr == S_OK, "Got hr %#x.\n", hr); + /* Atelier Sophie uses the VMR in renderless mode, calls + * IMediaControl::Run() from a stopped state and expects that + * IMediaControl::GetState() returns S_OK only after PresentImage() has + * been called. */ + ok(allocator_got_PresentImage == 1, "Got %u calls to PresentImage().\n", allocator_got_PresentImage);
hr = IMediaControl_Run(control); ok(hr == S_OK, "Got hr %#x.\n", hr); diff --git a/dlls/quartz/videorenderer.c b/dlls/quartz/videorenderer.c index eb6accf2d34..2ad479a6301 100644 --- a/dlls/quartz/videorenderer.c +++ b/dlls/quartz/videorenderer.c @@ -111,6 +111,7 @@ static HRESULT WINAPI VideoRenderer_DoRenderSample(struct strmbase_renderer *ifa
filter->current_sample = pSample;
+ SetEvent(filter->renderer.state_event); LeaveCriticalSection(&filter->renderer.csRenderLock); WaitForMultipleObjects(2, events, FALSE, INFINITE); EnterCriticalSection(&filter->renderer.csRenderLock); diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index a3f55011062..00cd6bbce84 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -315,6 +315,7 @@ static HRESULT WINAPI VMR9_DoRenderSample(struct strmbase_renderer *iface, IMedi
if (filter->renderer.filter.state == State_Paused) { + SetEvent(filter->renderer.state_event); LeaveCriticalSection(&filter->renderer.csRenderLock); WaitForMultipleObjects(2, events, FALSE, INFINITE); EnterCriticalSection(&filter->renderer.csRenderLock); diff --git a/dlls/strmbase/renderer.c b/dlls/strmbase/renderer.c index b6d552b3b0a..dde56b7a346 100644 --- a/dlls/strmbase/renderer.c +++ b/dlls/strmbase/renderer.c @@ -193,8 +193,6 @@ static HRESULT WINAPI BaseRenderer_Receive(struct strmbase_sink *pin, IMediaSamp }
EnterCriticalSection(&filter->csRenderLock); - if (filter->filter.state == State_Paused) - SetEvent(filter->state_event);
if (filter->filter.clock && SUCCEEDED(IMediaSample_GetTime(sample, &start, &stop))) {
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/tests/filtergraph.c | 59 +++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+)
diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c index bd6562b0ed5..1eecd0483b2 100644 --- a/dlls/quartz/tests/filtergraph.c +++ b/dlls/quartz/tests/filtergraph.c @@ -3939,6 +3939,7 @@ static void test_graph_seeking(void)
LONGLONG time, current, stop, earliest, latest; IFilterGraph2 *graph = create_graph(); + IMediaEventSink *eventsink; IMediaControl *control; IMediaSeeking *seeking; IMediaFilter *filter; @@ -3976,6 +3977,7 @@ static void test_graph_seeking(void) IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control); IFilterGraph2_QueryInterface(graph, &IID_IMediaSeeking, (void **)&seeking); IFilterGraph2_QueryInterface(graph, &IID_IMediaFilter, (void **)&filter); + IFilterGraph2_QueryInterface(graph, &IID_IMediaEventSink, (void **)&eventsink);
hr = IMediaSeeking_GetCapabilities(seeking, &caps); todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); @@ -4482,9 +4484,66 @@ static void test_graph_seeking(void) hr = IMediaControl_Stop(control); ok(hr == S_OK, "Got hr %#x.\n", hr);
+ /* GetCurrentPositions() will return the stop position once all renderers + * report EC_COMPLETE. Atelier Sophie depends on this behaviour. */ + + hr = IFilterGraph2_SetDefaultSyncSource(graph); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + filter1.seek_stop = 5000 * 10000; + filter2.seek_stop = 6000 * 10000; + + hr = IMediaControl_Run(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMediaSeeking_GetCurrentPosition(seeking, &time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(time < 5000 * 10000, "Got time %s.\n", wine_dbgstr_longlong(time)); + + hr = IMediaEventSink_Notify(eventsink, EC_COMPLETE, S_OK, (LONG_PTR)&filter1.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMediaSeeking_GetCurrentPosition(seeking, &time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(time < 5000 * 10000, "Got time %s.\n", wine_dbgstr_longlong(time)); + + hr = IMediaEventSink_Notify(eventsink, EC_COMPLETE, S_OK, (LONG_PTR)&filter2.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMediaSeeking_GetCurrentPosition(seeking, &time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(time == 6000 * 10000, "Got time %s.\n", wine_dbgstr_longlong(time)); + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + filter1.seek_hr = filter2.seek_hr = E_NOTIMPL; + filter1.seek_stop = filter2.seek_stop = 0xdeadbeef; + + hr = IMediaControl_Run(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMediaSeeking_GetCurrentPosition(seeking, &time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(time < 5000 * 10000, "Got time %s.\n", wine_dbgstr_longlong(time)); + + hr = IMediaEventSink_Notify(eventsink, EC_COMPLETE, S_OK, (LONG_PTR)&filter1.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMediaEventSink_Notify(eventsink, EC_COMPLETE, S_OK, (LONG_PTR)&filter2.IBaseFilter_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMediaSeeking_GetCurrentPosition(seeking, &time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(time == 6000 * 10000, "Got time %s.\n", wine_dbgstr_longlong(time)); + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IMediaFilter_Release(filter); IMediaControl_Release(control); IMediaSeeking_Release(seeking); + IMediaEventSink_Release(eventsink);
ok(filter1.seeking_ref > 0, "Unexpected seeking refcount %d.\n", filter1.seeking_ref); ok(filter2.seeking_ref > 0, "Unexpected seeking refcount %d.\n", filter2.seeking_ref);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=75807
Your paranoid android.
=== debiant (32 bit WoW report) ===
quartz: dsoundrender.c:810: Test failed: Got hr 0x103.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/filtergraph.c | 15 +++++++++++++-- dlls/quartz/tests/filtergraph.c | 5 ++--- 2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index 22d7f7b4450..7d6463c1f37 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -219,10 +219,11 @@ struct filter_graph /* Respectively: the last timestamp at which we started streaming, and the * current offset within the stream. */ REFERENCE_TIME stream_start, stream_elapsed; - + REFERENCE_TIME stream_stop; LONGLONG current_pos;
unsigned int needs_async_run : 1; + unsigned int got_ec_complete : 1; };
struct enum_filters @@ -1739,6 +1740,7 @@ static void update_render_count(struct filter_graph *graph) /* Perform the paused -> running transition. The caller must hold graph->cs. */ static HRESULT graph_start(struct filter_graph *graph, REFERENCE_TIME stream_start) { + REFERENCE_TIME stream_stop; struct filter *filter; HRESULT hr = S_OK;
@@ -1757,6 +1759,9 @@ static HRESULT graph_start(struct filter_graph *graph, REFERENCE_TIME stream_sta stream_start += 200 * 10000; }
+ if (SUCCEEDED(IMediaSeeking_GetStopPosition(&graph->IMediaSeeking_iface, &stream_stop))) + graph->stream_stop = stream_stop; + LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry) { HRESULT filter_hr = IBaseFilter_Run(filter->filter, stream_start); @@ -2322,7 +2327,11 @@ static HRESULT WINAPI MediaSeeking_GetCurrentPosition(IMediaSeeking *iface, LONG
EnterCriticalSection(&graph->cs);
- if (graph->state == State_Running && graph->refClock) + if (graph->got_ec_complete) + { + ret = graph->stream_stop; + } + else if (graph->state == State_Running && graph->refClock) { REFERENCE_TIME time; IReferenceClock_GetTime(graph->refClock, &time); @@ -4982,6 +4991,7 @@ static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface) graph->state = State_Stopped; graph->needs_async_run = 0; work = graph->async_run_work; + graph->got_ec_complete = 0;
/* Update the current position, probably to synchronize multiple streams. */ IMediaSeeking_SetPositions(&graph->IMediaSeeking_iface, &graph->current_pos, @@ -5281,6 +5291,7 @@ static HRESULT WINAPI MediaEventSink_Notify(IMediaEventSink *iface, LONG EventCo PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance); } This->CompletionStatus = EC_COMPLETE; + This->got_ec_complete = 1; SetEvent(This->hEventCompletion); } } diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c index 1eecd0483b2..9219b30cec7 100644 --- a/dlls/quartz/tests/filtergraph.c +++ b/dlls/quartz/tests/filtergraph.c @@ -530,7 +530,6 @@ static void test_media_event(IFilterGraph2 *graph)
hr = IMediaSeeking_GetCurrentPosition(seeking, ¤t); ok(hr == S_OK, "GetCurrentPosition() failed: %#x\n", hr); -todo_wine ok(current == stop, "expected %s, got %s\n", wine_dbgstr_longlong(stop), wine_dbgstr_longlong(current));
hr = IMediaControl_Stop(control); @@ -4512,7 +4511,7 @@ static void test_graph_seeking(void)
hr = IMediaSeeking_GetCurrentPosition(seeking, &time); ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(time == 6000 * 10000, "Got time %s.\n", wine_dbgstr_longlong(time)); + ok(time == 6000 * 10000, "Got time %s.\n", wine_dbgstr_longlong(time));
hr = IMediaControl_Stop(control); ok(hr == S_OK, "Got hr %#x.\n", hr); @@ -4535,7 +4534,7 @@ static void test_graph_seeking(void)
hr = IMediaSeeking_GetCurrentPosition(seeking, &time); ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(time == 6000 * 10000, "Got time %s.\n", wine_dbgstr_longlong(time)); + ok(time == 6000 * 10000, "Got time %s.\n", wine_dbgstr_longlong(time));
hr = IMediaControl_Stop(control); ok(hr == S_OK, "Got hr %#x.\n", hr);