From: RĂ©mi Bernon rbernon@codeweavers.com
This resolves circular dependency, with source and streams holding references to the callbacks, subscribed to their event queues.
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com ---
Replaces 226173.
dlls/mfreadwrite/reader.c | 91 ++++++++++++++++++++------------- dlls/mfreadwrite/tests/mfplat.c | 3 +- 2 files changed, 58 insertions(+), 36 deletions(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 6d35a59f3a8..0b6c6fa8583 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -154,6 +154,7 @@ struct source_reader IMFAsyncCallback stream_events_callback; IMFAsyncCallback async_commands_callback; LONG refcount; + LONG public_refcount; IMFMediaSource *source; IMFPresentationDescriptor *descriptor; IMFSourceReaderCallback *async_callback; @@ -203,6 +204,51 @@ static struct media_stream *impl_stream_from_IMFVideoSampleAllocatorNotify(IMFVi return CONTAINING_RECORD(iface, struct media_stream, notify_cb); }
+static void source_reader_release_responses(struct source_reader *reader, struct media_stream *stream); + +static ULONG source_reader_addref(struct source_reader *reader) +{ + return InterlockedIncrement(&reader->refcount); +} + +static ULONG source_reader_release(struct source_reader *reader) +{ + ULONG refcount = InterlockedDecrement(&reader->refcount); + unsigned int i; + + if (!refcount) + { + if (reader->async_callback) + IMFSourceReaderCallback_Release(reader->async_callback); + if (reader->descriptor) + IMFPresentationDescriptor_Release(reader->descriptor); + if (reader->attributes) + IMFAttributes_Release(reader->attributes); + IMFMediaSource_Release(reader->source); + + for (i = 0; i < reader->stream_count; ++i) + { + struct media_stream *stream = &reader->streams[i]; + + if (stream->stream) + IMFMediaStream_Release(stream->stream); + if (stream->current) + IMFMediaType_Release(stream->current); + if (stream->decoder.transform) + IMFTransform_Release(stream->decoder.transform); + if (stream->allocator) + IMFVideoSampleAllocatorEx_Release(stream->allocator); + } + source_reader_release_responses(reader, NULL); + free(reader->streams); + MFUnlockWorkQueue(reader->queue); + DeleteCriticalSection(&reader->cs); + free(reader); + } + + return refcount; +} + static HRESULT WINAPI source_reader_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IUnknown)) @@ -325,13 +371,13 @@ static HRESULT WINAPI source_reader_callback_QueryInterface(IMFAsyncCallback *if static ULONG WINAPI source_reader_source_events_callback_AddRef(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface); - return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface); + return source_reader_addref(reader); }
static ULONG WINAPI source_reader_source_events_callback_Release(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface); - return IMFSourceReader_Release(&reader->IMFSourceReader_iface); + return source_reader_release(reader); }
static HRESULT WINAPI source_reader_callback_GetParameters(IMFAsyncCallback *iface, @@ -611,13 +657,13 @@ static const IMFAsyncCallbackVtbl source_events_callback_vtbl = static ULONG WINAPI source_reader_stream_events_callback_AddRef(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface); - return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface); + return source_reader_addref(reader); }
static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface); - return IMFSourceReader_Release(&reader->IMFSourceReader_iface); + return source_reader_release(reader); }
static HRESULT source_reader_pull_stream_samples(struct source_reader *reader, struct media_stream *stream) @@ -888,13 +934,13 @@ static const IMFAsyncCallbackVtbl stream_events_callback_vtbl = static ULONG WINAPI source_reader_async_commands_callback_AddRef(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface); - return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface); + return source_reader_addref(reader); }
static ULONG WINAPI source_reader_async_commands_callback_Release(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface); - return IMFSourceReader_Release(&reader->IMFSourceReader_iface); + return source_reader_release(reader); }
static struct stream_response * media_stream_detach_response(struct source_reader *reader, struct stream_response *response) @@ -1326,7 +1372,7 @@ static HRESULT WINAPI src_reader_QueryInterface(IMFSourceReader *iface, REFIID r static ULONG WINAPI src_reader_AddRef(IMFSourceReader *iface) { struct source_reader *reader = impl_from_IMFSourceReader(iface); - ULONG refcount = InterlockedIncrement(&reader->refcount); + ULONG refcount = InterlockedIncrement(&reader->public_refcount);
TRACE("%p, refcount %u.\n", iface, refcount);
@@ -1336,41 +1382,15 @@ static ULONG WINAPI src_reader_AddRef(IMFSourceReader *iface) static ULONG WINAPI src_reader_Release(IMFSourceReader *iface) { struct source_reader *reader = impl_from_IMFSourceReader(iface); - ULONG refcount = InterlockedDecrement(&reader->refcount); - unsigned int i; + ULONG refcount = InterlockedDecrement(&reader->public_refcount);
TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount) { - if (reader->async_callback) - IMFSourceReaderCallback_Release(reader->async_callback); if (reader->flags & SOURCE_READER_SHUTDOWN_ON_RELEASE) IMFMediaSource_Shutdown(reader->source); - if (reader->descriptor) - IMFPresentationDescriptor_Release(reader->descriptor); - if (reader->attributes) - IMFAttributes_Release(reader->attributes); - IMFMediaSource_Release(reader->source); - - for (i = 0; i < reader->stream_count; ++i) - { - struct media_stream *stream = &reader->streams[i]; - - if (stream->stream) - IMFMediaStream_Release(stream->stream); - if (stream->current) - IMFMediaType_Release(stream->current); - if (stream->decoder.transform) - IMFTransform_Release(stream->decoder.transform); - if (stream->allocator) - IMFVideoSampleAllocatorEx_Release(stream->allocator); - } - source_reader_release_responses(reader, NULL); - free(reader->streams); - MFUnlockWorkQueue(reader->queue); - DeleteCriticalSection(&reader->cs); - free(reader); + source_reader_release(reader); }
return refcount; @@ -2268,6 +2288,7 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri object->source_events_callback.lpVtbl = &source_events_callback_vtbl; object->stream_events_callback.lpVtbl = &stream_events_callback_vtbl; object->async_commands_callback.lpVtbl = &async_commands_callback_vtbl; + object->public_refcount = 1; object->refcount = 1; list_init(&object->responses); if (shutdown_on_release) diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index f484925b28a..8417a0d37b7 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -862,7 +862,8 @@ skip_read_sample: hr = IMFSourceReader_Flush(reader, MF_SOURCE_READER_ALL_STREAMS); ok(hr == S_OK, "Failed to flush all streams, hr %#x.\n", hr);
- IMFSourceReader_Release(reader); + refcount = IMFSourceReader_Release(reader); + ok(!refcount, "Unexpected refcount %u.\n", refcount);
/* Async mode. */ callback = create_async_callback();
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfreadwrite/reader.c | 45 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 0b6c6fa8583..13fcc4278cc 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -72,6 +72,7 @@ enum media_stream_flags STREAM_FLAG_SAMPLE_REQUESTED = 0x1, /* Protects from making multiple sample requests. */ STREAM_FLAG_SELECTED = 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */ STREAM_FLAG_PRESENTED = 0x4, /* Set if stream was selected last time Start() was called. */ + STREAM_FLAG_STOPPED = 0x8, /* Received MEStreamStopped */ };
struct stream_transform @@ -172,6 +173,7 @@ struct source_reader CRITICAL_SECTION cs; CONDITION_VARIABLE sample_event; CONDITION_VARIABLE state_event; + CONDITION_VARIABLE stop_event; };
static inline struct source_reader *impl_from_IMFSourceReader(IMFSourceReader *iface) @@ -585,6 +587,8 @@ static HRESULT source_reader_source_state_handler(struct source_reader *reader, LeaveCriticalSection(&reader->cs);
WakeAllConditionVariable(&reader->state_event); + if (event_type == MESourceStopped) + WakeAllConditionVariable(&reader->stop_event);
return S_OK; } @@ -640,7 +644,8 @@ static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallba
IMFMediaEvent_Release(event);
- IMFMediaSource_BeginGetEvent(source, iface, (IUnknown *)source); + if (event_type != MESourceStopped) + IMFMediaSource_BeginGetEvent(source, iface, (IUnknown *)source);
return S_OK; } @@ -856,6 +861,9 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re case MEStreamStarted: stream->state = STREAM_STATE_READY; break; + case MEStreamStopped: + stream->flags |= STREAM_FLAG_STOPPED; + break; case MEStreamTick: value.vt = VT_EMPTY; hr = SUCCEEDED(IMFMediaEvent_GetValue(event, &value)) && value.vt == VT_I8 ? S_OK : E_UNEXPECTED; @@ -875,6 +883,9 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re
LeaveCriticalSection(&reader->cs);
+ if (event_type == MEStreamStopped) + WakeAllConditionVariable(&reader->stop_event); + return S_OK; }
@@ -904,6 +915,7 @@ static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallba break; case MEStreamSeeked: case MEStreamStarted: + case MEStreamStopped: case MEStreamTick: case MEEndOfStream: hr = source_reader_media_stream_state_handler(reader, stream, event); @@ -917,7 +929,8 @@ static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallba
IMFMediaEvent_Release(event);
- IMFMediaStream_BeginGetEvent(stream, iface, (IUnknown *)stream); + if (event_type != MEStreamStopped) + IMFMediaStream_BeginGetEvent(stream, iface, (IUnknown *)stream);
return S_OK; } @@ -1379,6 +1392,22 @@ static ULONG WINAPI src_reader_AddRef(IMFSourceReader *iface) return refcount; }
+static BOOL source_reader_is_source_stopped(const struct source_reader *reader) +{ + unsigned int i; + + if (reader->source_state != SOURCE_STATE_STOPPED) + return FALSE; + + for (i = 0; i < reader->stream_count; ++i) + { + if (reader->streams[i].stream && !(reader->streams[i].flags & STREAM_FLAG_STOPPED)) + return FALSE; + } + + return TRUE; +} + static ULONG WINAPI src_reader_Release(IMFSourceReader *iface) { struct source_reader *reader = impl_from_IMFSourceReader(iface); @@ -1390,6 +1419,17 @@ static ULONG WINAPI src_reader_Release(IMFSourceReader *iface) { if (reader->flags & SOURCE_READER_SHUTDOWN_ON_RELEASE) IMFMediaSource_Shutdown(reader->source); + else if (SUCCEEDED(IMFMediaSource_Stop(reader->source))) + { + EnterCriticalSection(&reader->cs); + + while (!source_reader_is_source_stopped(reader)) + { + SleepConditionVariableCS(&reader->stop_event, &reader->cs, INFINITE); + } + + LeaveCriticalSection(&reader->cs); + } source_reader_release(reader); }
@@ -2298,6 +2338,7 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri InitializeCriticalSection(&object->cs); InitializeConditionVariable(&object->sample_event); InitializeConditionVariable(&object->state_event); + InitializeConditionVariable(&object->stop_event);
if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(object->source, &object->descriptor))) goto failed;