mfreadwrite/reader: Use separate refcount for events callbacks.

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>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2022-02-11 09:51:20 +03:00 committed by Alexandre Julliard
parent bbfb164e0a
commit be85638b5b
2 changed files with 58 additions and 36 deletions

View File

@ -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)

View File

@ -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();