Signed-off-by: Anton Baskanov baskanov@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;