Signed-off-by: Anton Baskanov <baskanov(a)gmail.com> --- This is required to avoid deadlocks, e.g. when the filter is stopped while EndOfStream is being called. --- dlls/amstream/filter.c | 88 +++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 23 deletions(-) diff --git a/dlls/amstream/filter.c b/dlls/amstream/filter.c index 3c0436a294f..6fac4b9b4b7 100644 --- a/dlls/amstream/filter.c +++ b/dlls/amstream/filter.c @@ -167,7 +167,9 @@ struct filter IMediaSeeking IMediaSeeking_iface; LONG refcount; CRITICAL_SECTION cs; + CRITICAL_SECTION stream_cs; + /* Protected either by cs or stream_cs, lock both when modifying. */ IReferenceClock *clock; WCHAR name[128]; IFilterGraph *graph; @@ -176,6 +178,8 @@ struct filter IAMMediaStream *seekable_stream; FILTER_STATE state; REFERENCE_TIME start_time; + + /* Protected by stream_cs. */ struct list free_events; struct list used_events; }; @@ -253,6 +257,7 @@ static ULONG WINAPI filter_Release(IMediaStreamFilter *iface) heap_free(filter->streams); if (filter->clock) IReferenceClock_Release(filter->clock); + DeleteCriticalSection(&filter->stream_cs); DeleteCriticalSection(&filter->cs); heap_free(filter); } @@ -266,28 +271,28 @@ static HRESULT WINAPI filter_GetClassID(IMediaStreamFilter *iface, CLSID *clsid) return S_OK; } -static void set_state(struct filter *filter, FILTER_STATE state) -{ - if (filter->state != state) - { - ULONG i; - - for (i = 0; i < filter->nb_streams; ++i) - IAMMediaStream_SetState(filter->streams[i], state); - filter->state = state; - } -} - static HRESULT WINAPI filter_Stop(IMediaStreamFilter *iface) { struct filter *filter = impl_from_IMediaStreamFilter(iface); struct event *event; + ULONG i; TRACE("iface %p.\n", iface); EnterCriticalSection(&filter->cs); - set_state(filter, State_Stopped); + if (filter->state == State_Stopped) + { + LeaveCriticalSection(&filter->cs); + return S_OK; + } + + for (i = 0; i < filter->nb_streams; ++i) + IAMMediaStream_SetState(filter->streams[i], State_Stopped); + + EnterCriticalSection(&filter->stream_cs); + + filter->state = State_Stopped; LIST_FOR_EACH_ENTRY(event, &filter->used_events, struct event, entry) { @@ -299,6 +304,7 @@ static HRESULT WINAPI filter_Stop(IMediaStreamFilter *iface) } } + LeaveCriticalSection(&filter->stream_cs); LeaveCriticalSection(&filter->cs); return S_OK; @@ -307,12 +313,24 @@ static HRESULT WINAPI filter_Stop(IMediaStreamFilter *iface) static HRESULT WINAPI filter_Pause(IMediaStreamFilter *iface) { struct filter *filter = impl_from_IMediaStreamFilter(iface); + ULONG i; TRACE("iface %p.\n", iface); EnterCriticalSection(&filter->cs); - set_state(filter, State_Paused); + if (filter->state == State_Paused) + { + LeaveCriticalSection(&filter->cs); + return S_OK; + } + + EnterCriticalSection(&filter->stream_cs); + filter->state = State_Paused; + LeaveCriticalSection(&filter->stream_cs); + + for (i = 0; i < filter->nb_streams; ++i) + IAMMediaStream_SetState(filter->streams[i], State_Paused); LeaveCriticalSection(&filter->cs); @@ -322,13 +340,27 @@ static HRESULT WINAPI filter_Pause(IMediaStreamFilter *iface) static HRESULT WINAPI filter_Run(IMediaStreamFilter *iface, REFERENCE_TIME start) { struct filter *filter = impl_from_IMediaStreamFilter(iface); + ULONG i; TRACE("iface %p, start %s.\n", iface, wine_dbgstr_longlong(start)); EnterCriticalSection(&filter->cs); + if (filter->state == State_Running) + { + LeaveCriticalSection(&filter->cs); + return S_OK; + } + + EnterCriticalSection(&filter->stream_cs); + + filter->state = State_Running; filter->start_time = start; - set_state(filter, State_Running); + + LeaveCriticalSection(&filter->stream_cs); + + for (i = 0; i < filter->nb_streams; ++i) + IAMMediaStream_SetState(filter->streams[i], State_Running); LeaveCriticalSection(&filter->cs); @@ -360,6 +392,7 @@ static HRESULT WINAPI filter_SetSyncSource(IMediaStreamFilter *iface, IReference TRACE("iface %p, clock %p.\n", iface, clock); EnterCriticalSection(&filter->cs); + EnterCriticalSection(&filter->stream_cs); if (clock) IReferenceClock_AddRef(clock); @@ -367,6 +400,7 @@ static HRESULT WINAPI filter_SetSyncSource(IMediaStreamFilter *iface, IReference IReferenceClock_Release(filter->clock); filter->clock = clock; + LeaveCriticalSection(&filter->stream_cs); LeaveCriticalSection(&filter->cs); return S_OK; @@ -491,6 +525,7 @@ static HRESULT WINAPI filter_JoinFilterGraph(IMediaStreamFilter *iface, TRACE("iface %p, graph %p, name.%s.\n", iface, graph, debugstr_w(name)); EnterCriticalSection(&filter->cs); + EnterCriticalSection(&filter->stream_cs); if (name) wcsncpy(filter->name, name, ARRAY_SIZE(filter->name)); @@ -498,6 +533,7 @@ static HRESULT WINAPI filter_JoinFilterGraph(IMediaStreamFilter *iface, filter->name[0] = 0; filter->graph = graph; + LeaveCriticalSection(&filter->stream_cs); LeaveCriticalSection(&filter->cs); return S_OK; @@ -624,6 +660,8 @@ static HRESULT WINAPI filter_SupportSeeking(IMediaStreamFilter *iface, BOOL rend return HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED); } + EnterCriticalSection(&filter->stream_cs); + for (i = 0; i < filter->nb_streams; ++i) { IMediaSeeking *seeking = get_seeking(filter->streams[i]); @@ -636,6 +674,7 @@ static HRESULT WINAPI filter_SupportSeeking(IMediaStreamFilter *iface, BOOL rend { filter->seekable_stream = filter->streams[i]; IMediaSeeking_Release(seeking); + LeaveCriticalSection(&filter->stream_cs); LeaveCriticalSection(&filter->cs); return S_OK; } @@ -643,6 +682,7 @@ static HRESULT WINAPI filter_SupportSeeking(IMediaStreamFilter *iface, BOOL rend IMediaSeeking_Release(seeking); } + LeaveCriticalSection(&filter->stream_cs); LeaveCriticalSection(&filter->cs); return E_NOINTERFACE; } @@ -704,11 +744,11 @@ static HRESULT WINAPI filter_WaitUntil(IMediaStreamFilter *iface, REFERENCE_TIME TRACE("filter %p, time %s.\n", iface, wine_dbgstr_longlong(time)); - EnterCriticalSection(&filter->cs); + EnterCriticalSection(&filter->stream_cs); if (!filter->clock) { - LeaveCriticalSection(&filter->cs); + LeaveCriticalSection(&filter->stream_cs); return E_FAIL; } @@ -729,23 +769,23 @@ static HRESULT WINAPI filter_WaitUntil(IMediaStreamFilter *iface, REFERENCE_TIME if (FAILED(hr)) { list_add_tail(&filter->free_events, entry); - LeaveCriticalSection(&filter->cs); + LeaveCriticalSection(&filter->stream_cs); return hr; } event->interrupted = FALSE; list_add_tail(&filter->used_events, entry); - LeaveCriticalSection(&filter->cs); + LeaveCriticalSection(&filter->stream_cs); WaitForSingleObject(event->event, INFINITE); - EnterCriticalSection(&filter->cs); + EnterCriticalSection(&filter->stream_cs); hr = event->interrupted ? S_FALSE : S_OK; list_remove(entry); list_add_tail(&filter->free_events, entry); - LeaveCriticalSection(&filter->cs); + LeaveCriticalSection(&filter->stream_cs); return hr; } @@ -757,7 +797,7 @@ static HRESULT WINAPI filter_Flush(IMediaStreamFilter *iface, BOOL cancel_eos) TRACE("filter %p, cancel_eos %d.\n", iface, cancel_eos); - EnterCriticalSection(&filter->cs); + EnterCriticalSection(&filter->stream_cs); LIST_FOR_EACH_ENTRY(event, &filter->used_events, struct event, entry) { @@ -769,7 +809,7 @@ static HRESULT WINAPI filter_Flush(IMediaStreamFilter *iface, BOOL cancel_eos) } } - LeaveCriticalSection(&filter->cs); + LeaveCriticalSection(&filter->stream_cs); return S_OK; } @@ -1064,6 +1104,8 @@ HRESULT filter_create(IUnknown *outer, void **out) list_init(&object->used_events); InitializeCriticalSection(&object->cs); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MediaStreamFilter.cs"); + InitializeCriticalSection(&object->stream_cs); + object->stream_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MediaStreamFilter.stream_cs"); TRACE("Created media stream filter %p.\n", object); *out = &object->IMediaStreamFilter_iface; -- 2.25.1