[PATCH 1/2] winegstreamer: Implement pausing the media source.
Derek Lesho
dlesho at codeweavers.com
Thu Jun 10 11:12:23 CDT 2021
On 6/10/21 11:33 AM, Giovanni Mascellani wrote:
> Signed-off-by: Giovanni Mascellani <gmascellani at codeweavers.com>
> ---
> dlls/winegstreamer/media_source.c | 95 +++++++++++++++++++++++++++----
> 1 file changed, 85 insertions(+), 10 deletions(-)
This patch probably warrants a few tests. I would test at least
- what happens to ::RequestSample calls when a stream is paused.
- whether MESourcePaused or the MEStreamPaused events come first.
>
> 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);
Since our media source outputs uncompressed samples, if it's common
behavior for an application to request a significant amount of samples
while the source is paused, we might instead want to add a separate
sample request queue. (Lest we use too much memory) I think this is
what I was referring to in my old comment.
> + }
> + 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)
More information about the wine-devel
mailing list