Signed-off-by: Giovanni Mascellani <gmascellani(a)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) -- 2.32.0