Signed-off-by: Giovanni Mascellani gmascellani@codeweavers.com --- dlls/winegstreamer/media_source.c | 95 +++++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 10 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 3c87bbb2146..496aab545e7 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -27,6 +27,12 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+struct pending_sample +{ + struct list entry; + IMFSample *sample; +}; + struct media_stream { IMFMediaStream IMFMediaStream_iface; @@ -34,6 +40,7 @@ struct media_stream struct media_source *parent_source; IMFMediaEventQueue *event_queue; IMFStreamDescriptor *descriptor; + struct list pending_samples;
struct wg_parser_stream *wg_stream;
@@ -50,6 +57,7 @@ struct media_stream enum source_async_op { SOURCE_ASYNC_START, + SOURCE_ASYNC_PAUSE, SOURCE_ASYNC_STOP, SOURCE_ASYNC_REQUEST_SAMPLE, }; @@ -96,6 +104,7 @@ struct media_source { SOURCE_OPENING, SOURCE_STOPPED, + SOURCE_PAUSED, SOURCE_RUNNING, SOURCE_SHUTDOWN, } state; @@ -257,6 +266,23 @@ static IMFStreamDescriptor *stream_descriptor_from_id(IMFPresentationDescriptor return NULL; }
+static void flush_pending_queue(struct media_stream *stream, BOOL send_events) +{ + struct pending_sample *pending, *pending2; + + LIST_FOR_EACH_ENTRY_SAFE(pending, pending2, &stream->pending_samples, struct pending_sample, entry) + { + if (send_events) + { + IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample, + &GUID_NULL, S_OK, (IUnknown *)pending->sample); + } + IMFSample_Release(pending->sample); + list_remove(&pending->entry); + free(pending); + } +} + static void start_pipeline(struct media_source *source, struct source_async_command *command) { PROPVARIANT *position = &command->u.start.position; @@ -269,7 +295,8 @@ static void start_pipeline(struct media_source *source, struct source_async_comm position->vt = VT_I8; position->hVal.QuadPart = 0; } - source->start_time = position->hVal.QuadPart; + if (position->vt != VT_EMPTY) + source->start_time = position->hVal.QuadPart;
for (i = 0; i < source->stream_count; i++) { @@ -318,6 +345,8 @@ static void start_pipeline(struct media_source *source, struct source_async_comm
IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, seek_message ? MEStreamSeeked : MEStreamStarted, &GUID_NULL, S_OK, position); + + flush_pending_queue(stream, TRUE); } }
@@ -327,11 +356,30 @@ static void start_pipeline(struct media_source *source, struct source_async_comm
source->state = SOURCE_RUNNING;
- unix_funcs->wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0, - position->hVal.QuadPart, 0, AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning); + if (position->vt != VT_EMPTY) + unix_funcs->wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0, + position->hVal.QuadPart, 0, AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning); unix_funcs->wg_parser_end_flush(source->wg_parser); }
+static void pause_pipeline(struct media_source *source) +{ + unsigned int i; + + for (i = 0; i < source->stream_count; i++) + { + struct media_stream *stream = source->streams[i]; + if (stream->state != STREAM_INACTIVE) + { + IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamPaused, &GUID_NULL, S_OK, NULL); + } + } + + IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourcePaused, &GUID_NULL, S_OK, NULL); + + source->state = SOURCE_PAUSED; +} + static void stop_pipeline(struct media_source *source) { unsigned int i; @@ -343,6 +391,7 @@ static void stop_pipeline(struct media_source *source) struct media_stream *stream = source->streams[i]; if (stream->state != STREAM_INACTIVE) { + flush_pending_queue(stream, FALSE); IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped, &GUID_NULL, S_OK, NULL); unix_funcs->wg_parser_stream_disable(stream->wg_stream); } @@ -437,12 +486,26 @@ static void send_buffer(struct media_stream *stream, const struct wg_parser_even if (token) IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token);
- IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample, - &GUID_NULL, S_OK, (IUnknown *)sample); + if (stream->parent_source->state == SOURCE_PAUSED) + { + struct pending_sample *pending = malloc(sizeof(*pending)); + if (!pending) + { + ERR("Cannot allocate pending sample\n"); + goto out; + } + pending->sample = sample; + sample = NULL; + list_add_tail(&stream->pending_samples, &pending->entry); + } + else + IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample, + &GUID_NULL, S_OK, (IUnknown *)sample);
out: IMFMediaBuffer_Release(buffer); - IMFSample_Release(sample); + if (sample) + IMFSample_Release(sample); }
static void wait_on_sample(struct media_stream *stream, IUnknown *token) @@ -501,6 +564,9 @@ static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFA case SOURCE_ASYNC_START: start_pipeline(source, command); break; + case SOURCE_ASYNC_PAUSE: + pause_pipeline(source); + break; case SOURCE_ASYNC_STOP: stop_pipeline(source); break; @@ -597,6 +663,7 @@ static ULONG WINAPI media_stream_Release(IMFMediaStream *iface) { if (stream->event_queue) IMFMediaEventQueue_Release(stream->event_queue); + flush_pending_queue(stream, FALSE); free(stream); }
@@ -699,7 +766,6 @@ static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown IUnknown_AddRef(token); command->u.request_sample.token = token;
- /* Once pause support is added, this will need to put into a stream queue, and synchronization will need to be added*/ hr = MFPutWorkItem(stream->parent_source->async_commands_queue, &stream->parent_source->async_commands_callback, &command->IUnknown_iface); }
@@ -738,6 +804,7 @@ static HRESULT new_media_stream(struct media_source *source, object->state = STREAM_INACTIVE; object->eos = FALSE; object->wg_stream = wg_stream; + list_init(&object->pending_samples);
if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) goto fail; @@ -1123,7 +1190,7 @@ static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWO if (source->state == SOURCE_SHUTDOWN) return MF_E_SHUTDOWN;
- *characteristics = MFMEDIASOURCE_CAN_SEEK; + *characteristics = MFMEDIASOURCE_CAN_SEEK | MFMEDIASOURCE_CAN_PAUSE;
return S_OK; } @@ -1187,13 +1254,21 @@ static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface) static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) { struct media_source *source = impl_from_IMFMediaSource(iface); + struct source_async_command *command; + HRESULT hr;
- FIXME("(%p): stub\n", source); + TRACE("(%p)\n", source);
if (source->state == SOURCE_SHUTDOWN) return MF_E_SHUTDOWN;
- return E_NOTIMPL; + if (source->state != SOURCE_RUNNING) + return MF_E_INVALID_STATE_TRANSITION; + + if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_PAUSE, &command))) + hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface); + + return hr; }
static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)