[PATCH 4/5] winegstreamer: Implement IWMReader::Start().

Zebediah Figura zfigura at codeweavers.com
Thu Nov 4 15:46:27 CDT 2021


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/winegstreamer/wm_asyncreader.c | 167 ++++++++++++++++++++++++++--
 dlls/wmvcore/tests/wmvcore.c        |  25 +++--
 2 files changed, 178 insertions(+), 14 deletions(-)

diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c
index 860ec1cdd5e..d4bd8914dd6 100644
--- a/dlls/winegstreamer/wm_asyncreader.c
+++ b/dlls/winegstreamer/wm_asyncreader.c
@@ -34,8 +34,23 @@ struct async_reader
 
     IWMReaderCallback *callback;
     void *context;
+
+    LARGE_INTEGER clock_frequency;
+    HANDLE stream_thread;
+    CRITICAL_SECTION stream_cs;
+    CONDITION_VARIABLE stream_cv;
+
+    bool running;
 };
 
+static REFERENCE_TIME get_current_time(const struct async_reader *reader)
+{
+    LARGE_INTEGER time;
+
+    QueryPerformanceCounter(&time);
+    return (time.QuadPart * 1000) / reader->clock_frequency.QuadPart * 10000;
+}
+
 static void open_stream(struct async_reader *reader, IWMReaderCallback *callback, void *context)
 {
     static const DWORD zero;
@@ -45,6 +60,92 @@ static void open_stream(struct async_reader *reader, IWMReaderCallback *callback
     IWMReaderCallback_OnStatus(callback, WMT_OPENED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context);
 }
 
+static DWORD WINAPI stream_thread(void *arg)
+{
+    struct async_reader *reader = arg;
+    WORD i, stream_count = reader->reader.stream_count;
+    IWMReaderCallback *callback = reader->callback;
+    REFERENCE_TIME start_time;
+    static const DWORD zero;
+    QWORD pts, duration;
+    INSSBuffer *sample;
+    DWORD flags;
+    HRESULT hr;
+
+    start_time = get_current_time(reader);
+
+    EnterCriticalSection(&reader->stream_cs);
+
+    while (reader->running)
+    {
+        bool all_eos = true;
+
+        for (i = 0; i < stream_count; ++i)
+        {
+            hr = wm_reader_get_stream_sample(&reader->reader.streams[i], &sample, &pts, &duration, &flags);
+            if (hr == S_OK)
+            {
+                for (;;)
+                {
+                    REFERENCE_TIME current_time = get_current_time(reader);
+
+                    if (pts <= current_time - start_time)
+                        break;
+
+                    SleepConditionVariableCS(&reader->stream_cv, &reader->stream_cs,
+                            (pts - (current_time - start_time)) / 10000);
+
+                    if (!reader->running)
+                    {
+                        INSSBuffer_Release(sample);
+                        goto out;
+                    }
+                }
+
+                IWMReaderCallback_OnSample(callback, i, pts, duration, flags, sample, reader->context);
+                INSSBuffer_Release(sample);
+                all_eos = false;
+            }
+            else if (hr != NS_E_NO_MORE_SAMPLES)
+            {
+                ERR("Failed to get sample, hr %#x.\n", hr);
+                return 0;
+            }
+        }
+
+        if (all_eos)
+        {
+            IWMReaderCallback_OnStatus(callback, WMT_END_OF_STREAMING, S_OK,
+                    WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
+            IWMReaderCallback_OnStatus(callback, WMT_EOF, S_OK,
+                    WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
+            TRACE("Reached end of stream; exiting.\n");
+            LeaveCriticalSection(&reader->stream_cs);
+            return 0;
+        }
+    }
+
+out:
+    LeaveCriticalSection(&reader->stream_cs);
+
+    TRACE("Reader is stopping; exiting.\n");
+    return 0;
+}
+
+static void stop_streaming(struct async_reader *reader)
+{
+    if (reader->stream_thread)
+    {
+        EnterCriticalSection(&reader->stream_cs);
+        reader->running = false;
+        LeaveCriticalSection(&reader->stream_cs);
+        WakeConditionVariable(&reader->stream_cv);
+        WaitForSingleObject(reader->stream_thread, INFINITE);
+        CloseHandle(reader->stream_thread);
+        reader->stream_thread = NULL;
+    }
+}
+
 static struct async_reader *impl_from_IWMReader(IWMReader *iface)
 {
     return CONTAINING_RECORD(iface, struct async_reader, IWMReader_iface);
@@ -88,6 +189,8 @@ static HRESULT WINAPI WMReader_Close(IWMReader *iface)
 
     EnterCriticalSection(&reader->reader.cs);
 
+    stop_streaming(reader);
+
     hr = wm_reader_close(&reader->reader);
     if (reader->callback)
     {
@@ -151,18 +254,54 @@ static HRESULT WINAPI WMReader_GetOutputFormat(IWMReader *iface, DWORD output,
     return wm_reader_get_output_format(&reader->reader, output, index, props);
 }
 
-static HRESULT WINAPI WMReader_Start(IWMReader *iface, QWORD start, QWORD duration, float rate, void *context)
+static HRESULT WINAPI WMReader_Start(IWMReader *iface,
+        QWORD start, QWORD duration, float rate, void *context)
 {
-    struct async_reader *This = impl_from_IWMReader(iface);
-    FIXME("(%p)->(%s %s %f %p)\n", This, wine_dbgstr_longlong(start), wine_dbgstr_longlong(duration), rate, context);
-    return E_NOTIMPL;
+    struct async_reader *reader = impl_from_IWMReader(iface);
+    static const DWORD zero;
+
+    TRACE("reader %p, start %s, duration %s, rate %.8e, context %p.\n",
+            reader, debugstr_time(start), debugstr_time(duration), rate, context);
+
+    if (rate != 1.0f)
+        FIXME("Ignoring rate %.8e.\n", rate);
+
+    EnterCriticalSection(&reader->reader.cs);
+
+    stop_streaming(reader);
+
+    IWMReaderCallback_OnStatus(reader->callback, WMT_STARTED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context);
+    reader->context = context;
+
+    wm_reader_seek(&reader->reader, start, duration);
+
+    reader->running = true;
+
+    if (!(reader->stream_thread = CreateThread(NULL, 0, stream_thread, reader, 0, NULL)))
+    {
+        LeaveCriticalSection(&reader->reader.cs);
+        return E_OUTOFMEMORY;
+    }
+
+    LeaveCriticalSection(&reader->reader.cs);
+    WakeConditionVariable(&reader->stream_cv);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI WMReader_Stop(IWMReader *iface)
 {
-    struct async_reader *This = impl_from_IWMReader(iface);
-    FIXME("(%p)\n", This);
-    return E_NOTIMPL;
+    struct async_reader *reader = impl_from_IWMReader(iface);
+    static const DWORD zero;
+
+    TRACE("reader %p.\n", reader);
+
+    EnterCriticalSection(&reader->reader.cs);
+    stop_streaming(reader);
+    IWMReaderCallback_OnStatus(reader->callback, WMT_STOPPED, S_OK,
+            WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
+    LeaveCriticalSection(&reader->reader.cs);
+    return S_OK;
 }
 
 static HRESULT WINAPI WMReader_Pause(IWMReader *iface)
@@ -1302,6 +1441,15 @@ static void async_reader_destroy(struct wm_reader *iface)
 
     TRACE("reader %p.\n", reader);
 
+    if (reader->stream_thread)
+    {
+        WaitForSingleObject(reader->stream_thread, INFINITE);
+        CloseHandle(reader->stream_thread);
+    }
+
+    reader->stream_cs.DebugInfo->Spare[0] = 0;
+    DeleteCriticalSection(&reader->stream_cs);
+
     wm_reader_close(&reader->reader);
 
     if (reader->callback)
@@ -1336,6 +1484,11 @@ HRESULT WINAPI winegstreamer_create_wm_async_reader(IWMReader **reader)
     object->IWMReaderStreamClock_iface.lpVtbl = &WMReaderStreamClockVtbl;
     object->IWMReaderTypeNegotiation_iface.lpVtbl = &WMReaderTypeNegotiationVtbl;
 
+    InitializeCriticalSection(&object->stream_cs);
+    object->stream_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": async_reader.stream_cs");
+
+    QueryPerformanceFrequency(&object->clock_frequency);
+
     TRACE("Created async reader %p.\n", object);
     *reader = (IWMReader *)&object->IWMReader_iface;
     return S_OK;
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index c1972b29eb9..4cc285c2c73 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -1125,6 +1125,7 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta
             ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
             ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
             ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+            callback->got_end_of_streaming = callback->got_eof = callback->got_sample = 0;
             ++callback->got_started;
             break;
 
@@ -1138,7 +1139,7 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta
         case WMT_CLOSED:
             ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
             ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
-            todo_wine ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+            ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
             ++callback->got_closed;
             break;
 
@@ -1281,17 +1282,27 @@ static void test_async_reader_streaming(void)
     }
 
     hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade);
-    todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
 
+    /* By default the reader will time itself, and attempt to deliver samples
+     * according to their presentation time. Call DeliverTime with the file
+     * duration in order to request all samples as fast as possible. */
+    hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
+    todo_wine ok(hr == E_UNEXPECTED, "Got hr %#x.\n", hr);
+    hr = IWMReaderAdvanced2_SetUserProvidedClock(advanced, TRUE);
+    todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
     if (hr == S_OK)
     {
-        /* By default the reader will time itself, and attempt to deliver samples
-         * according to their presentation time. Call DeliverTime with the file
-         * duration in order to request all samples as fast as possible. */
         hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
-        ok(hr == E_UNEXPECTED, "Got hr %#x.\n", hr);
-        hr = IWMReaderAdvanced2_SetUserProvidedClock(advanced, TRUE);
         ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+        ret = WaitForSingleObject(callback.eof_event, 1000);
+        ok(!ret, "Wait timed out.\n");
+        ok(callback.got_eof == 1, "Got %u WMT_EOF callbacks.\n", callback.got_eof);
+
+        hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade);
+        ok(hr == S_OK, "Got hr %#x.\n", hr);
+
         hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
         ok(hr == S_OK, "Got hr %#x.\n", hr);
 
-- 
2.33.0




More information about the wine-devel mailing list