[PATCH 1/2] winegstreamer: Implement pausing the media source.

Giovanni Mascellani gmascellani at codeweavers.com
Thu Jun 10 10:33:56 CDT 2021


Signed-off-by: Giovanni Mascellani <gmascellani at 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




More information about the wine-devel mailing list