[PATCH 2/2] mfreadwrite: Add support for seeking in Source Reader.

Nikolay Sivov nsivov at codeweavers.com
Mon Apr 6 09:19:30 CDT 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfreadwrite/reader.c | 147 +++++++++++++++++++++++++++++---------
 1 file changed, 115 insertions(+), 32 deletions(-)

diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c
index c4a5981ea7..e66eb03135 100644
--- a/dlls/mfreadwrite/reader.c
+++ b/dlls/mfreadwrite/reader.c
@@ -119,6 +119,7 @@ struct media_stream
 enum source_reader_async_op
 {
     SOURCE_READER_ASYNC_READ,
+    SOURCE_READER_ASYNC_SEEK,
     SOURCE_READER_ASYNC_FLUSH,
     SOURCE_READER_ASYNC_SAMPLE_READY,
 };
@@ -128,14 +129,34 @@ struct source_reader_async_command
     IUnknown IUnknown_iface;
     LONG refcount;
     enum source_reader_async_op op;
-    unsigned int flags;
-    unsigned int stream_index;
+    union
+    {
+        struct
+        {
+            unsigned int flags;
+            unsigned int stream_index;
+        } read;
+        struct
+        {
+            GUID format;
+            PROPVARIANT position;
+        } seek;
+        struct
+        {
+            unsigned int stream_index;
+        } flush;
+        struct
+        {
+            unsigned int stream_index;
+        } sample;
+    } u;
 };
 
 enum source_reader_flags
 {
     SOURCE_READER_FLUSHING = 0x1,
-    SOURCE_READER_SHUTDOWN_ON_RELEASE = 0x2,
+    SOURCE_READER_SEEKING = 0x2,
+    SOURCE_READER_SHUTDOWN_ON_RELEASE = 0x4,
 };
 
 struct source_reader
@@ -157,6 +178,7 @@ struct source_reader
     struct list responses;
     CRITICAL_SECTION cs;
     CONDITION_VARIABLE sample_event;
+    CONDITION_VARIABLE state_event;
 };
 
 static inline struct source_reader *impl_from_IMFSourceReader(IMFSourceReader *iface)
@@ -210,7 +232,11 @@ static ULONG WINAPI source_reader_async_command_Release(IUnknown *iface)
     ULONG refcount = InterlockedIncrement(&command->refcount);
 
     if (!refcount)
+    {
+        if (command->op == SOURCE_READER_ASYNC_SEEK)
+            PropVariantClear(&command->u.seek.position);
         heap_free(command);
+    }
 
     return refcount;
 }
@@ -341,7 +367,7 @@ static void source_reader_queue_response(struct source_reader *reader, struct me
         {
             if (SUCCEEDED(source_reader_create_async_op(SOURCE_READER_ASYNC_SAMPLE_READY, &command)))
             {
-                command->stream_index = stream->index;
+                command->u.sample.stream_index = stream->index;
                 if (FAILED(hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &reader->async_commands_callback,
                         &command->IUnknown_iface)))
                     WARN("Failed to submit async result, hr %#x.\n", hr);
@@ -429,25 +455,27 @@ static HRESULT source_reader_new_stream_handler(struct source_reader *reader, IM
 
 static HRESULT source_reader_source_state_handler(struct source_reader *reader, MediaEventType event_type)
 {
-    enum media_source_state state;
+    EnterCriticalSection(&reader->cs);
 
     switch (event_type)
     {
         case MESourceStarted:
-            state = SOURCE_STATE_STARTED;
+            reader->source_state = SOURCE_STATE_STARTED;
             break;
         case MESourceStopped:
-            state = SOURCE_STATE_STOPPED;
+            reader->source_state = SOURCE_STATE_STOPPED;
+            break;
+        case MESourceSeeked:
+            reader->flags &= ~SOURCE_READER_SEEKING;
             break;
         default:
-            WARN("Unhandled state %d.\n", event_type);
-            return E_FAIL;
+            WARN("Unhandled event %d.\n", event_type);
     }
 
-    EnterCriticalSection(&reader->cs);
-    reader->source_state = state;
     LeaveCriticalSection(&reader->cs);
 
+    WakeAllConditionVariable(&reader->state_event);
+
     return S_OK;
 }
 
@@ -478,6 +506,7 @@ static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallba
         case MESourceStarted:
         case MESourcePaused:
         case MESourceStopped:
+        case MESourceSeeked:
             hr = source_reader_source_state_handler(reader, event_type);
             break;
         case MEBufferingStarted:
@@ -1089,12 +1118,12 @@ static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallb
 
             if (SUCCEEDED(hr = source_reader_start_source(reader)))
             {
-                if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, command->stream_index, &stream_index)))
+                if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, command->u.read.stream_index, &stream_index)))
                 {
                     stream = &reader->streams[stream_index];
 
-                    if (!(report_sample = source_reader_get_read_result(reader, stream, command->flags, &status, &stream_index,
-                            &stream_flags, &timestamp, &sample)))
+                    if (!(report_sample = source_reader_get_read_result(reader, stream, command->u.read.flags, &status,
+                            &stream_index, &stream_flags, &timestamp, &sample)))
                     {
                         stream->requests++;
                         source_reader_request_sample(reader, stream);
@@ -1103,7 +1132,7 @@ static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallb
                 }
                 else
                 {
-                    stub_stream.index = command->stream_index;
+                    stub_stream.index = command->u.read.stream_index;
                     source_reader_queue_response(reader, &stub_stream, hr, MF_SOURCE_READERF_ERROR, 0, NULL);
                 }
             }
@@ -1119,6 +1148,18 @@ static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallb
 
             break;
 
+        case SOURCE_READER_ASYNC_SEEK:
+
+            EnterCriticalSection(&reader->cs);
+            if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, &command->u.seek.format,
+                    &command->u.seek.position)))
+            {
+                reader->flags |= SOURCE_READER_SEEKING;
+            }
+            LeaveCriticalSection(&reader->cs);
+
+            break;
+
         case SOURCE_READER_ASYNC_SAMPLE_READY:
 
             EnterCriticalSection(&reader->cs);
@@ -1135,11 +1176,11 @@ static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallb
             break;
         case SOURCE_READER_ASYNC_FLUSH:
             EnterCriticalSection(&reader->cs);
-            source_reader_flush(reader, command->stream_index);
+            source_reader_flush(reader, command->u.flush.stream_index);
             reader->flags &= ~SOURCE_READER_FLUSHING;
             LeaveCriticalSection(&reader->cs);
 
-            IMFSourceReaderCallback_OnFlush(reader->async_callback, command->stream_index);
+            IMFSourceReaderCallback_OnFlush(reader->async_callback, command->u.flush.stream_index);
             break;
         default:
             ;
@@ -1620,20 +1661,60 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWO
 static HRESULT WINAPI src_reader_SetCurrentPosition(IMFSourceReader *iface, REFGUID format, REFPROPVARIANT position)
 {
     struct source_reader *reader = impl_from_IMFSourceReader(iface);
-    DWORD flags;
+    struct source_reader_async_command *command;
+    unsigned int i, flags;
     HRESULT hr;
 
     TRACE("%p, %s, %p.\n", iface, debugstr_guid(format), position);
 
-    /* FIXME: fail if we got pending samples. */
-
     if (FAILED(hr = IMFMediaSource_GetCharacteristics(reader->source, &flags)))
         return hr;
 
     if (!(flags & MFMEDIASOURCE_CAN_SEEK))
         return MF_E_INVALIDREQUEST;
 
-    return IMFMediaSource_Start(reader->source, reader->descriptor, format, position);
+    EnterCriticalSection(&reader->cs);
+
+    /* Check if we got pending requests. */
+    for (i = 0; i < reader->stream_count; ++i)
+    {
+        if (reader->streams[i].requests)
+        {
+            hr = MF_E_INVALIDREQUEST;
+            break;
+        }
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        if (reader->async_callback)
+        {
+            if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_SEEK, &command)))
+            {
+                command->u.seek.format = *format;
+                PropVariantCopy(&command->u.seek.position, position);
+
+                hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, &reader->async_commands_callback,
+                        &command->IUnknown_iface);
+                IUnknown_Release(&command->IUnknown_iface);
+            }
+        }
+        else
+        {
+            if (SUCCEEDED(IMFMediaSource_Start(reader->source, reader->descriptor, format, position)))
+            {
+                reader->flags |= SOURCE_READER_SEEKING;
+                while (reader->flags & SOURCE_READER_SEEKING)
+                {
+                    SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
+                }
+            }
+        }
+    }
+
+    LeaveCriticalSection(&reader->cs);
+
+    return hr;
 }
 
 static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD index, DWORD flags, DWORD *actual_index,
@@ -1656,8 +1737,6 @@ static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD ind
     if (!actual_index)
         actual_index = &actual_index_tmp;
 
-    EnterCriticalSection(&reader->cs);
-
     if (SUCCEEDED(hr = source_reader_start_source(reader)))
     {
         if (SUCCEEDED(hr = source_reader_get_stream_read_index(reader, index, &stream_index)))
@@ -1689,8 +1768,6 @@ static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD ind
         }
     }
 
-    LeaveCriticalSection(&reader->cs);
-
     TRACE("Stream %u, got sample %p, flags %#x.\n", *actual_index, *sample, *stream_flags);
 
     return hr;
@@ -1705,24 +1782,20 @@ static HRESULT source_reader_read_sample_async(struct source_reader *reader, uns
     if (actual_index || stream_flags || timestamp || sample)
         return E_INVALIDARG;
 
-    EnterCriticalSection(&reader->cs);
-
     if (reader->flags & SOURCE_READER_FLUSHING)
         hr = MF_E_NOTACCEPTING;
     else
     {
         if (SUCCEEDED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_READ, &command)))
         {
-            command->stream_index = index;
-            command->flags = flags;
+            command->u.read.stream_index = index;
+            command->u.read.flags = flags;
 
             hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &reader->async_commands_callback, &command->IUnknown_iface);
             IUnknown_Release(&command->IUnknown_iface);
         }
     }
 
-    LeaveCriticalSection(&reader->cs);
-
     return hr;
 }
 
@@ -1734,11 +1807,20 @@ static HRESULT WINAPI src_reader_ReadSample(IMFSourceReader *iface, DWORD index,
 
     TRACE("%p, %#x, %#x, %p, %p, %p, %p\n", iface, index, flags, actual_index, stream_flags, timestamp, sample);
 
+    EnterCriticalSection(&reader->cs);
+
+    while (reader->flags & SOURCE_READER_SEEKING)
+    {
+        SleepConditionVariableCS(&reader->state_event, &reader->cs, INFINITE);
+    }
+
     if (reader->async_callback)
         hr = source_reader_read_sample_async(reader, index, flags, actual_index, stream_flags, timestamp, sample);
     else
         hr = source_reader_read_sample(reader, index, flags, actual_index, stream_flags, timestamp, sample);
 
+    LeaveCriticalSection(&reader->cs);
+
     return hr;
 }
 
@@ -1771,7 +1853,7 @@ static HRESULT source_reader_flush_async(struct source_reader *reader, unsigned
     if (FAILED(hr = source_reader_create_async_op(SOURCE_READER_ASYNC_FLUSH, &command)))
         return hr;
 
-    command->stream_index = stream_index;
+    command->u.flush.stream_index = stream_index;
 
     hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &reader->async_commands_callback, &command->IUnknown_iface);
     IUnknown_Release(&command->IUnknown_iface);
@@ -1964,6 +2046,7 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri
     IMFMediaSource_AddRef(object->source);
     InitializeCriticalSection(&object->cs);
     InitializeConditionVariable(&object->sample_event);
+    InitializeConditionVariable(&object->state_event);
 
     if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(object->source, &object->descriptor)))
         goto failed;
-- 
2.25.1




More information about the wine-devel mailing list