From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mfreadwrite/reader.c | 175 +++++++++++++++++++++++--------- dlls/mfreadwrite/tests/mfplat.c | 6 +- 2 files changed, 129 insertions(+), 52 deletions(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 11eac81d2ca..9036919bdf6 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -146,6 +146,7 @@ enum source_reader_flags SOURCE_READER_D3D9_DEVICE_MANAGER = 0x8, SOURCE_READER_DXGI_DEVICE_MANAGER = 0x10, SOURCE_READER_HAS_DEVICE_MANAGER = SOURCE_READER_D3D9_DEVICE_MANAGER | SOURCE_READER_DXGI_DEVICE_MANAGER, + SOURCE_READER_SHUTDOWN = 0x20, };
struct source_reader @@ -234,26 +235,11 @@ static void media_stream_destroy(struct media_stream *stream) static ULONG source_reader_release(struct source_reader *reader) { ULONG refcount = InterlockedDecrement(&reader->refcount); - unsigned int i;
if (!refcount) { - if (reader->device_manager) - IUnknown_Release(reader->device_manager); 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]; - media_stream_destroy(stream); - } - source_reader_release_responses(reader, NULL); free(reader->streams); MFUnlockWorkQueue(reader->queue); DeleteCriticalSection(&reader->cs); @@ -394,6 +380,21 @@ static ULONG WINAPI source_reader_source_events_callback_Release(IMFAsyncCallbac return source_reader_release(reader); }
+static struct source_reader *source_reader_source_events_callback_lock(IMFAsyncCallback *iface) +{ + struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface); + + EnterCriticalSection(&reader->cs); + + if (reader->flags & SOURCE_READER_SHUTDOWN) + { + LeaveCriticalSection(&reader->cs); + return NULL; + } + + return reader; +} + static HRESULT WINAPI source_reader_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) { @@ -534,8 +535,6 @@ static HRESULT source_reader_new_stream_handler(struct source_reader *reader, IM return hr; }
- EnterCriticalSection(&reader->cs); - for (i = 0; i < reader->stream_count; ++i) { if (id == reader->streams[i].id) @@ -561,8 +560,6 @@ static HRESULT source_reader_new_stream_handler(struct source_reader *reader, IM if (i == reader->stream_count) WARN("Stream with id %#lx was not present in presentation descriptor.\n", id);
- LeaveCriticalSection(&reader->cs); - IMFMediaStream_Release(stream);
return hr; @@ -570,8 +567,6 @@ static HRESULT source_reader_new_stream_handler(struct source_reader *reader, IM
static HRESULT source_reader_source_state_handler(struct source_reader *reader, MediaEventType event_type) { - EnterCriticalSection(&reader->cs); - switch (event_type) { case MESourceStarted: @@ -589,18 +584,12 @@ static HRESULT source_reader_source_state_handler(struct source_reader *reader, WARN("Unhandled event %ld.\n", event_type); }
- LeaveCriticalSection(&reader->cs); - - WakeAllConditionVariable(&reader->state_event); - if (event_type == MESourceStopped) - WakeAllConditionVariable(&reader->stop_event); - return S_OK; }
static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { - struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface); + struct source_reader *reader; MediaEventType event_type; IMFMediaSource *source; IMFMediaEvent *event; @@ -620,13 +609,33 @@ static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallba switch (event_type) { case MENewStream: + { + if (!(reader = source_reader_source_events_callback_lock(iface))) + { + IMFMediaEvent_Release(event); + return MF_E_SHUTDOWN; + } + hr = source_reader_new_stream_handler(reader, event); + LeaveCriticalSection(&reader->cs); break; + } case MESourceStarted: case MESourcePaused: case MESourceStopped: case MESourceSeeked: + if (!(reader = source_reader_source_events_callback_lock(iface))) + { + IMFMediaEvent_Release(event); + return MF_E_SHUTDOWN; + } + hr = source_reader_source_state_handler(reader, event_type); + LeaveCriticalSection(&reader->cs); + + WakeAllConditionVariable(&reader->state_event); + if (event_type == MESourceStopped) + WakeAllConditionVariable(&reader->stop_event); break; case MEBufferingStarted: case MEBufferingStopped: @@ -637,6 +646,13 @@ static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallba case MESourceMetadataChanged: case MEContentProtectionMetadata: case MEDeviceThermalStateChanged: + if (!(reader = source_reader_source_events_callback_lock(iface))) + { + IMFMediaEvent_Release(event); + return MF_E_SHUTDOWN; + } + LeaveCriticalSection(&reader->cs); + if (reader->async_callback) IMFSourceReaderCallback_OnEvent(reader->async_callback, MF_SOURCE_READER_MEDIASOURCE, event); break; @@ -676,6 +692,21 @@ static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallbac return source_reader_release(reader); }
+static struct source_reader *source_reader_stream_events_callback_lock(IMFAsyncCallback *iface) +{ + struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface); + + EnterCriticalSection(&reader->cs); + + if (reader->flags & SOURCE_READER_SHUTDOWN) + { + LeaveCriticalSection(&reader->cs); + return NULL; + } + + return reader; +} + static HRESULT source_reader_allocate_stream_sample(MFT_OUTPUT_STREAM_INFO *info, IMFSample **out) { IMFMediaBuffer *buffer; @@ -962,8 +993,6 @@ static HRESULT source_reader_media_sample_handler(struct source_reader *reader, return hr; }
- EnterCriticalSection(&reader->cs); - for (i = 0; i < reader->stream_count; ++i) { if (id == reader->streams[i].id) @@ -978,8 +1007,6 @@ static HRESULT source_reader_media_sample_handler(struct source_reader *reader, if (i == reader->stream_count) WARN("Stream with id %#lx was not present in presentation descriptor.\n", id);
- LeaveCriticalSection(&reader->cs); - IMFSample_Release(sample);
return hr; @@ -1003,8 +1030,6 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re return hr; }
- EnterCriticalSection(&reader->cs); - for (i = 0; i < reader->stream_count; ++i) { struct media_stream *stream = &reader->streams[i]; @@ -1056,17 +1081,12 @@ 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; }
static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { - struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface); + struct source_reader *reader; MediaEventType event_type; IMFMediaStream *stream; IMFMediaEvent *event; @@ -1086,14 +1106,31 @@ static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallba switch (event_type) { case MEMediaSample: + if (!(reader = source_reader_stream_events_callback_lock(iface))) + { + IMFMediaEvent_Release(event); + return MF_E_SHUTDOWN; + } + hr = source_reader_media_sample_handler(reader, stream, event); + LeaveCriticalSection(&reader->cs); break; case MEStreamSeeked: case MEStreamStarted: case MEStreamStopped: case MEStreamTick: case MEEndOfStream: + if (!(reader = source_reader_stream_events_callback_lock(iface))) + { + IMFMediaEvent_Release(event); + return MF_E_SHUTDOWN; + } + hr = source_reader_media_stream_state_handler(reader, stream, event); + LeaveCriticalSection(&reader->cs); + + if (event_type == MEStreamStopped) + WakeAllConditionVariable(&reader->stop_event); break; default: ; @@ -1131,6 +1168,21 @@ static ULONG WINAPI source_reader_async_commands_callback_Release(IMFAsyncCallba return source_reader_release(reader); }
+static struct source_reader *source_reader_async_commands_callback_lock(IMFAsyncCallback *iface) +{ + struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface); + + EnterCriticalSection(&reader->cs); + + if (reader->flags & SOURCE_READER_SHUTDOWN) + { + LeaveCriticalSection(&reader->cs); + return NULL; + } + + return reader; +} + static struct stream_response * media_stream_detach_response(struct source_reader *reader, struct stream_response *response) { struct media_stream *stream; @@ -1434,7 +1486,7 @@ static HRESULT source_reader_flush(struct source_reader *reader, unsigned int in
static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { - struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface); + struct source_reader *reader; struct media_stream *stream, stub_stream = { .requests = 1 }; struct source_reader_async_command *command; struct stream_response *response; @@ -1445,15 +1497,16 @@ static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallb HRESULT hr, status; IUnknown *state;
- if (FAILED(hr = IMFAsyncResult_GetState(result, &state))) - return hr; + if (!(state = IMFAsyncResult_GetStateNoAddRef(result))) + return E_INVALIDARG;
command = impl_from_async_command_IUnknown(state);
switch (command->op) { case SOURCE_READER_ASYNC_READ: - EnterCriticalSection(&reader->cs); + if (!(reader = source_reader_async_commands_callback_lock(iface))) + return MF_E_SHUTDOWN;
if (SUCCEEDED(hr = source_reader_start_source(reader))) { @@ -1488,8 +1541,9 @@ static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallb break;
case SOURCE_READER_ASYNC_SEEK: + if (!(reader = source_reader_async_commands_callback_lock(iface))) + return MF_E_SHUTDOWN;
- EnterCriticalSection(&reader->cs); if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, &command->u.seek.format, &command->u.seek.position))) { @@ -1500,8 +1554,9 @@ static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallb break;
case SOURCE_READER_ASYNC_SAMPLE_READY: + if (!(reader = source_reader_async_commands_callback_lock(iface))) + return MF_E_SHUTDOWN;
- EnterCriticalSection(&reader->cs); response = media_stream_pop_response(reader, NULL); LeaveCriticalSection(&reader->cs);
@@ -1514,7 +1569,9 @@ static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallb
break; case SOURCE_READER_ASYNC_FLUSH: - EnterCriticalSection(&reader->cs); + if (!(reader = source_reader_async_commands_callback_lock(iface))) + return MF_E_SHUTDOWN; + source_reader_flush(reader, command->u.flush.stream_index); reader->flags &= ~SOURCE_READER_FLUSHING; LeaveCriticalSection(&reader->cs); @@ -1525,8 +1582,6 @@ static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallb ; }
- IUnknown_Release(state); - return S_OK; }
@@ -1598,6 +1653,10 @@ static ULONG WINAPI src_reader_Release(IMFSourceReaderEx *iface)
if (!refcount) { + EnterCriticalSection(&reader->cs); + reader->flags |= SOURCE_READER_SHUTDOWN; + LeaveCriticalSection(&reader->cs); + if (reader->flags & SOURCE_READER_SHUTDOWN_ON_RELEASE) IMFMediaSource_Shutdown(reader->source); else if (SUCCEEDED(IMFMediaSource_Stop(reader->source))) @@ -1626,8 +1685,26 @@ static ULONG WINAPI src_reader_Release(IMFSourceReaderEx *iface) IMFVideoSampleAllocatorCallback_SetCallback(callback, NULL); IMFVideoSampleAllocatorCallback_Release(callback); } + + IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(stream->allocator); + IMFVideoSampleAllocatorEx_SetDirectXManager(stream->allocator, NULL); }
+ if (reader->device_manager) + IUnknown_Release(reader->device_manager); + 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]; + media_stream_destroy(stream); + } + source_reader_release_responses(reader, NULL); + source_reader_release(reader); }
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 027aa45b1ea..ba1029a1e80 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -3099,7 +3099,7 @@ static void test_source_reader_transforms_d3d(void) ref = IMFSourceReader_Release(reader); ok(ref == 0, "got ref %ld\n", ref); ref = IMFTransform_Release(test_decoder); - todo_wine ok(ref == 0, "got ref %ld\n", ref); + ok(ref == 0, "got ref %ld\n", ref);
/* test d3d aware decoder that allocates buffers */ @@ -3176,7 +3176,7 @@ static void test_source_reader_transforms_d3d(void) ref = IMFSourceReader_Release(reader); ok(ref == 0, "got ref %ld\n", ref); ref = IMFTransform_Release(test_decoder); - todo_wine ok(ref == 0, "got ref %ld\n", ref); + ok(ref == 0, "got ref %ld\n", ref);
test_decoder_allocate_samples = FALSE;
@@ -3186,7 +3186,7 @@ skip_tests: ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ref = IDirect3DDeviceManager9_Release(d3d9_manager); - todo_wine ok(ref == 0, "got ref %ld\n", ref); + ok(ref == 0, "got ref %ld\n", ref); DestroyWindow(window);
test_decoder_d3d_aware = FALSE;