[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