From: Torge Matthies openglfreak@googlemail.com
--- dlls/winegstreamer/media_source.c | 175 +++++++++++++++++++++++++----- 1 file changed, 145 insertions(+), 30 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index ecfa94dcfa1..772ac1e8db1 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -119,9 +119,29 @@ static HRESULT object_context_create(DWORD flags, IMFByteStream *stream, const W return S_OK; }
+enum stream_async_op +{ + STREAM_ASYNC_REQUEST_SAMPLE, +}; + +struct stream_async_command +{ + IUnknown IUnknown_iface; + LONG refcount; + enum stream_async_op op; + union + { + struct + { + IUnknown *token; + } request_sample; + } u; +}; + struct media_stream { IMFMediaStream IMFMediaStream_iface; + IMFAsyncCallback async_commands_callback; LONG ref;
IMFMediaSource *media_source; @@ -130,6 +150,8 @@ struct media_stream
wg_parser_stream_t wg_stream;
+ DWORD async_commands_queue; + IUnknown **token_queue; LONG token_queue_count; LONG token_queue_cap; @@ -144,7 +166,6 @@ enum source_async_op SOURCE_ASYNC_START, SOURCE_ASYNC_PAUSE, SOURCE_ASYNC_STOP, - SOURCE_ASYNC_REQUEST_SAMPLE, };
struct source_async_command @@ -160,11 +181,6 @@ struct source_async_command GUID format; PROPVARIANT position; } start; - struct - { - struct media_stream *stream; - IUnknown *token; - } request_sample; } u; };
@@ -209,6 +225,16 @@ static inline struct media_stream *impl_from_IMFMediaStream(IMFMediaStream *ifac return CONTAINING_RECORD(iface, struct media_stream, IMFMediaStream_iface); }
+static inline struct media_stream *impl_from_stream_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct media_stream, async_commands_callback); +} + +static inline struct stream_async_command *impl_from_stream_async_command_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct stream_async_command, IUnknown_iface); +} + static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface) { return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface); @@ -239,7 +265,7 @@ static inline struct source_async_command *impl_from_async_command_IUnknown(IUnk return CONTAINING_RECORD(iface, struct source_async_command, IUnknown_iface); }
-static HRESULT WINAPI source_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj) +static HRESULT WINAPI async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IUnknown)) { @@ -253,6 +279,52 @@ static HRESULT WINAPI source_async_command_QueryInterface(IUnknown *iface, REFII return E_NOINTERFACE; }
+static ULONG WINAPI stream_async_command_AddRef(IUnknown *iface) +{ + struct stream_async_command *command = impl_from_stream_async_command_IUnknown(iface); + return InterlockedIncrement(&command->refcount); +} + +static ULONG WINAPI stream_async_command_Release(IUnknown *iface) +{ + struct stream_async_command *command = impl_from_stream_async_command_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&command->refcount); + + if (!refcount) + { + if (command->op == STREAM_ASYNC_REQUEST_SAMPLE) + { + if (command->u.request_sample.token) + IUnknown_Release(command->u.request_sample.token); + } + free(command); + } + + return refcount; +} + +static const IUnknownVtbl stream_async_command_vtbl = +{ + async_command_QueryInterface, + stream_async_command_AddRef, + stream_async_command_Release, +}; + +static HRESULT stream_create_async_op(enum stream_async_op op, IUnknown **out) +{ + struct stream_async_command *command; + + if (!(command = calloc(1, sizeof(*command)))) + return E_OUTOFMEMORY; + + command->IUnknown_iface.lpVtbl = &stream_async_command_vtbl; + command->refcount = 1; + command->op = op; + + *out = &command->IUnknown_iface; + return S_OK; +} + static ULONG WINAPI source_async_command_AddRef(IUnknown *iface) { struct source_async_command *command = impl_from_async_command_IUnknown(iface); @@ -271,11 +343,6 @@ static ULONG WINAPI source_async_command_Release(IUnknown *iface) IMFPresentationDescriptor_Release(command->u.start.descriptor); PropVariantClear(&command->u.start.position); } - else if (command->op == SOURCE_ASYNC_REQUEST_SAMPLE) - { - if (command->u.request_sample.token) - IUnknown_Release(command->u.request_sample.token); - } free(command); }
@@ -284,7 +351,7 @@ static ULONG WINAPI source_async_command_Release(IUnknown *iface)
static const IUnknownVtbl source_async_command_vtbl = { - source_async_command_QueryInterface, + async_command_QueryInterface, source_async_command_AddRef, source_async_command_Release, }; @@ -532,7 +599,6 @@ static BOOL enqueue_token(struct media_stream *stream, IUnknown *token)
static void flush_token_queue(struct media_stream *stream, BOOL send) { - struct media_source *source = impl_from_IMFMediaSource(stream->media_source); LONG i;
for (i = 0; i < stream->token_queue_count; i++) @@ -542,13 +608,12 @@ static void flush_token_queue(struct media_stream *stream, BOOL send) IUnknown *op; HRESULT hr;
- if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &op))) + if (SUCCEEDED(hr = stream_create_async_op(STREAM_ASYNC_REQUEST_SAMPLE, &op))) { - struct source_async_command *command = impl_from_async_command_IUnknown(op); - command->u.request_sample.stream = stream; + struct stream_async_command *command = impl_from_stream_async_command_IUnknown(op); command->u.request_sample.token = stream->token_queue[i];
- hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); + hr = MFPutWorkItem(stream->async_commands_queue, &stream->async_commands_callback, op); IUnknown_Release(op); } if (FAILED(hr)) @@ -833,12 +898,58 @@ static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFA if (FAILED(hr = media_source_stop(source))) WARN("Failed to stop source %p, hr %#lx\n", source, hr); break; - case SOURCE_ASYNC_REQUEST_SAMPLE: + } + + LeaveCriticalSection(&source->cs); + + IUnknown_Release(state); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl = +{ + callback_QueryInterface, + source_async_commands_callback_AddRef, + source_async_commands_callback_Release, + callback_GetParameters, + source_async_commands_Invoke, +}; + +static ULONG WINAPI stream_async_commands_callback_AddRef(IMFAsyncCallback *iface) +{ + struct media_stream *stream = impl_from_stream_async_commands_callback_IMFAsyncCallback(iface); + return IMFMediaStream_AddRef(&stream->IMFMediaStream_iface); +} + +static ULONG WINAPI stream_async_commands_callback_Release(IMFAsyncCallback *iface) +{ + struct media_stream *stream = impl_from_stream_async_commands_callback_IMFAsyncCallback(iface); + return IMFMediaStream_Release(&stream->IMFMediaStream_iface); +} + +static HRESULT WINAPI stream_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct media_stream *stream = impl_from_stream_async_commands_callback_IMFAsyncCallback(iface); + struct media_source *source = impl_from_IMFMediaSource(stream->media_source); + struct stream_async_command *command; + IUnknown *state; + HRESULT hr; + + if (FAILED(hr = IMFAsyncResult_GetState(result, &state))) + return hr; + + EnterCriticalSection(&source->cs); + + command = impl_from_stream_async_command_IUnknown(state); + switch (command->op) + { + case STREAM_ASYNC_REQUEST_SAMPLE: if (source->state == SOURCE_PAUSED) - enqueue_token(command->u.request_sample.stream, command->u.request_sample.token); + enqueue_token(stream, command->u.request_sample.token); else if (source->state == SOURCE_RUNNING) { - if (FAILED(hr = wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token))) + if (FAILED(hr = wait_on_sample(stream, command->u.request_sample.token))) WARN("Failed to request sample, hr %#lx\n", hr); } break; @@ -851,13 +962,13 @@ static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFA return S_OK; }
-static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl = +static const IMFAsyncCallbackVtbl stream_async_commands_callback_vtbl = { callback_QueryInterface, - source_async_commands_callback_AddRef, - source_async_commands_callback_Release, + stream_async_commands_callback_AddRef, + stream_async_commands_callback_Release, callback_GetParameters, - source_async_commands_Invoke, + stream_async_commands_Invoke, };
static DWORD CALLBACK read_thread(void *arg) @@ -1072,15 +1183,14 @@ static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown hr = MF_E_MEDIA_SOURCE_WRONGSTATE; else if (stream->eos) hr = MF_E_END_OF_STREAM; - else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &op))) + else if (SUCCEEDED(hr = stream_create_async_op(STREAM_ASYNC_REQUEST_SAMPLE, &op))) { - struct source_async_command *command = impl_from_async_command_IUnknown(op); - command->u.request_sample.stream = stream; + struct stream_async_command *command = impl_from_stream_async_command_IUnknown(op); if (token) IUnknown_AddRef(token); command->u.request_sample.token = token;
- hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); + hr = MFPutWorkItem(stream->async_commands_queue, &stream->async_commands_callback, op); IUnknown_Release(op); }
@@ -1115,9 +1225,11 @@ static HRESULT media_stream_create(IMFMediaSource *source, IMFStreamDescriptor * return E_OUTOFMEMORY;
object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl; + object->async_commands_callback.lpVtbl = &stream_async_commands_callback_vtbl; object->ref = 1;
- if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) + if (FAILED(hr = MFCreateEventQueue(&object->event_queue)) || + FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue))) { free(object); return hr; @@ -1570,6 +1682,7 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) struct media_stream *stream = source->streams[source->stream_count]; IMFStreamDescriptor_Release(source->descriptors[source->stream_count]); IMFMediaEventQueue_Shutdown(stream->event_queue); + MFUnlockWorkQueue(stream->async_commands_queue); IMFMediaStream_Release(&stream->IMFMediaStream_iface); } free(source->descriptors); @@ -1708,6 +1821,8 @@ fail: { struct media_stream *stream = object->streams[object->stream_count]; IMFStreamDescriptor_Release(object->descriptors[object->stream_count]); + if (stream->async_commands_queue) + MFUnlockWorkQueue(stream->async_commands_queue); IMFMediaStream_Release(&stream->IMFMediaStream_iface); } free(object->descriptors);