[PATCH 2/6] winegstreamer: Implement IWMSyncReader::GetNextSample().

Zebediah Figura zfigura at codeweavers.com
Sun Oct 31 19:03:33 CDT 2021


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/winegstreamer/gst_private.h   |   5 +
 dlls/winegstreamer/wm_reader.c     | 192 +++++++++++++++++++++++++++++
 dlls/winegstreamer/wm_syncreader.c |  41 +++++-
 dlls/wmvcore/tests/wmvcore.c       |  12 +-
 include/wmsdkidl.idl               |   7 ++
 5 files changed, 245 insertions(+), 12 deletions(-)

diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 278fc132ccf..a9c361366b3 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -121,6 +121,7 @@ struct wm_stream
     struct wm_reader *reader;
     struct wg_parser_stream *wg_stream;
     WORD index;
+    bool eos;
     struct wg_format format;
 };
 
@@ -159,6 +160,10 @@ HRESULT wm_reader_get_output_format(struct wm_reader *reader, DWORD output,
 HRESULT wm_reader_get_output_format_count(struct wm_reader *reader, DWORD output, DWORD *count);
 HRESULT wm_reader_get_output_props(struct wm_reader *reader, DWORD output,
         IWMOutputMediaProps **props);
+struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader,
+        WORD stream_number);
+HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
+        INSSBuffer **sample, QWORD *pts, QWORD *duration, DWORD *flags);
 void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops);
 HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream);
 HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output,
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c
index 21e08b5834f..71adfac5a42 100644
--- a/dlls/winegstreamer/wm_reader.c
+++ b/dlls/winegstreamer/wm_reader.c
@@ -167,6 +167,101 @@ static IWMOutputMediaProps *output_props_create(const struct wg_format *format)
     return &object->IWMOutputMediaProps_iface;
 }
 
+struct buffer
+{
+    INSSBuffer INSSBuffer_iface;
+    LONG refcount;
+};
+
+static struct buffer *impl_from_INSSBuffer(INSSBuffer *iface)
+{
+    return CONTAINING_RECORD(iface, struct buffer, INSSBuffer_iface);
+}
+
+static HRESULT WINAPI buffer_QueryInterface(INSSBuffer *iface, REFIID iid, void **out)
+{
+    struct buffer *buffer = impl_from_INSSBuffer(iface);
+
+    TRACE("buffer %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
+
+    if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_INSSBuffer))
+        *out = &buffer->INSSBuffer_iface;
+    else
+    {
+        *out = NULL;
+        WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown *)*out);
+    return S_OK;
+}
+
+static ULONG WINAPI buffer_AddRef(INSSBuffer *iface)
+{
+    struct buffer *buffer = impl_from_INSSBuffer(iface);
+    ULONG refcount = InterlockedIncrement(&buffer->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", buffer, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI buffer_Release(INSSBuffer *iface)
+{
+    struct buffer *buffer = impl_from_INSSBuffer(iface);
+    ULONG refcount = InterlockedDecrement(&buffer->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", buffer, refcount);
+
+    if (!refcount)
+        free(buffer);
+
+    return refcount;
+}
+
+static HRESULT WINAPI buffer_GetLength(INSSBuffer *iface, DWORD *size)
+{
+    FIXME("iface %p, size %p, stub!\n", iface, size);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI buffer_SetLength(INSSBuffer *iface, DWORD size)
+{
+    FIXME("iface %p, size %u, stub!\n", iface, size);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI buffer_GetMaxLength(INSSBuffer *iface, DWORD *size)
+{
+    FIXME("iface %p, size %p, stub!\n", iface, size);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI buffer_GetBuffer(INSSBuffer *iface, BYTE **data)
+{
+    FIXME("iface %p, data %p, stub!\n", iface, data);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI buffer_GetBufferAndLength(INSSBuffer *iface, BYTE **data, DWORD *size)
+{
+    FIXME("iface %p, data %p, size %p, stub!\n", iface, data, size);
+    return E_NOTIMPL;
+}
+
+static const INSSBufferVtbl buffer_vtbl =
+{
+    buffer_QueryInterface,
+    buffer_AddRef,
+    buffer_Release,
+    buffer_GetLength,
+    buffer_SetLength,
+    buffer_GetMaxLength,
+    buffer_GetBuffer,
+    buffer_GetBufferAndLength,
+};
+
 struct stream_config
 {
     IWMStreamConfig IWMStreamConfig_iface;
@@ -1231,8 +1326,15 @@ HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream)
             if (stream->format.u.video.format == WG_VIDEO_FORMAT_I420)
                 stream->format.u.video.format = WG_VIDEO_FORMAT_YV12;
         }
+        wg_parser_stream_enable(stream->wg_stream, &stream->format);
     }
 
+    wg_parser_end_flush(reader->wg_parser);
+    /* We probably discarded events because streams weren't enabled yet.
+     * Now that they're all enabled seek back to the start again. */
+    wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, 0, 0,
+            AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
+
     LeaveCriticalSection(&reader->cs);
     return S_OK;
 
@@ -1281,6 +1383,14 @@ HRESULT wm_reader_close(struct wm_reader *reader)
     return S_OK;
 }
 
+struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader, WORD stream_number)
+{
+    if (stream_number && stream_number <= reader->stream_count)
+        return &reader->streams[stream_number - 1];
+    WARN("Invalid stream number %u.\n", stream_number);
+    return NULL;
+}
+
 HRESULT wm_reader_get_output_props(struct wm_reader *reader, DWORD output, IWMOutputMediaProps **props)
 {
     struct wm_stream *stream;
@@ -1429,6 +1539,88 @@ HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output,
     return S_OK;
 }
 
+static const char *get_major_type_string(enum wg_major_type type)
+{
+    switch (type)
+    {
+        case WG_MAJOR_TYPE_AUDIO:
+            return "audio";
+        case WG_MAJOR_TYPE_VIDEO:
+            return "video";
+        case WG_MAJOR_TYPE_UNKNOWN:
+            return "unknown";
+    }
+    assert(0);
+    return NULL;
+}
+
+HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
+        INSSBuffer **ret_sample, QWORD *pts, QWORD *duration, DWORD *flags)
+{
+    struct wg_parser_stream *wg_stream = stream->wg_stream;
+    struct wg_parser_event event;
+    struct buffer *object;
+
+    if (stream->eos)
+        return NS_E_NO_MORE_SAMPLES;
+
+    for (;;)
+    {
+        if (!wg_parser_stream_get_event(wg_stream, &event))
+        {
+            FIXME("Stream is flushing.\n");
+            return E_NOTIMPL;
+        }
+
+        TRACE("Got event of type %#x for %s stream %p.\n", event.type,
+                get_major_type_string(stream->format.major_type), stream);
+
+        switch (event.type)
+        {
+            case WG_PARSER_EVENT_BUFFER:
+                /* FIXME: Should these be pooled? */
+                if (!(object = calloc(1, sizeof(*object))))
+                {
+                    wg_parser_stream_release_buffer(wg_stream);
+                    return E_OUTOFMEMORY;
+                }
+
+                object->INSSBuffer_iface.lpVtbl = &buffer_vtbl;
+                object->refcount = 1;
+
+                wg_parser_stream_release_buffer(wg_stream);
+
+                if (!event.u.buffer.has_pts)
+                    FIXME("Missing PTS.\n");
+                if (!event.u.buffer.has_duration)
+                    FIXME("Missing duration.\n");
+
+                *pts = event.u.buffer.pts;
+                *duration = event.u.buffer.duration;
+                *flags = 0;
+                if (event.u.buffer.discontinuity)
+                    *flags |= WM_SF_DISCONTINUITY;
+                if (!event.u.buffer.delta)
+                    *flags |= WM_SF_CLEANPOINT;
+
+                TRACE("Created buffer %p.\n", object);
+                *ret_sample = &object->INSSBuffer_iface;
+                return S_OK;
+
+            case WG_PARSER_EVENT_EOS:
+                stream->eos = true;
+                TRACE("End of stream.\n");
+                return NS_E_NO_MORE_SAMPLES;
+
+            case WG_PARSER_EVENT_SEGMENT:
+                break;
+
+            case WG_PARSER_EVENT_NONE:
+                assert(0);
+        }
+    }
+}
+
 void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops)
 {
     reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl;
diff --git a/dlls/winegstreamer/wm_syncreader.c b/dlls/winegstreamer/wm_syncreader.c
index f9728211661..a2cc747e9bf 100644
--- a/dlls/winegstreamer/wm_syncreader.c
+++ b/dlls/winegstreamer/wm_syncreader.c
@@ -76,13 +76,42 @@ static HRESULT WINAPI WMSyncReader_GetMaxStreamSampleSize(IWMSyncReader2 *iface,
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI WMSyncReader_GetNextSample(IWMSyncReader2 *iface, WORD stream, INSSBuffer **sample,
-        QWORD *sample_time, QWORD *sample_duration, DWORD *flags, DWORD *output_num, WORD *stream_num)
+static HRESULT WINAPI WMSyncReader_GetNextSample(IWMSyncReader2 *iface,
+        WORD stream_number, INSSBuffer **sample, QWORD *pts, QWORD *duration,
+        DWORD *flags, DWORD *output_number, WORD *ret_stream_number)
 {
-    struct sync_reader *This = impl_from_IWMSyncReader2(iface);
-    FIXME("(%p)->(%d %p %p %p %p %p %p): stub!\n", This, stream, sample, sample_time,
-          sample_duration, flags, output_num, stream_num);
-    return E_NOTIMPL;
+    struct sync_reader *reader = impl_from_IWMSyncReader2(iface);
+    struct wm_stream *stream;
+    HRESULT hr;
+
+    TRACE("reader %p, stream_number %u, sample %p, pts %p, duration %p,"
+            " flags %p, output_number %p, ret_stream_number %p.\n",
+            reader, stream_number, sample, pts, duration, flags, output_number, ret_stream_number);
+
+    EnterCriticalSection(&reader->reader.cs);
+
+    if (!stream_number)
+    {
+        FIXME("Reading from all streams is not implemented yet.\n");
+        hr = E_NOTIMPL;
+    }
+    else
+    {
+        if (!(stream = wm_reader_get_stream_by_stream_number(&reader->reader, stream_number)))
+        {
+            LeaveCriticalSection(&reader->reader.cs);
+            return E_INVALIDARG;
+        }
+
+        hr = wm_reader_get_stream_sample(stream, sample, pts, duration, flags);
+        if (hr == S_OK && output_number)
+            *output_number = stream->index;
+        if (ret_stream_number)
+            *ret_stream_number = stream->index + 1;
+    }
+
+    LeaveCriticalSection(&reader->reader.cs);
+    return hr;
 }
 
 static HRESULT WINAPI WMSyncReader_GetOutputCount(IWMSyncReader2 *iface, DWORD *count)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index e07e6241a4c..dabeb054530 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -500,7 +500,7 @@ static void test_sync_reader_streaming(void)
             hr = IWMSyncReader_GetNextSample(reader, stream_numbers[j], &sample,
                     &pts, &duration, &flags, &output_number, &stream_number);
             if (first)
-                todo_wine ok(hr == S_OK, "Expected at least one valid sample; got hr %#x.\n", hr);
+                ok(hr == S_OK, "Expected at least one valid sample; got hr %#x.\n", hr);
             else if (eos[j])
                 ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
             else
@@ -527,7 +527,7 @@ static void test_sync_reader_streaming(void)
                 eos[j] = true;
             }
 
-            todo_wine ok(stream_number == stream_numbers[j], "Expected stream number %u, got %u.\n",
+            ok(stream_number == stream_numbers[j], "Expected stream number %u, got %u.\n",
                     stream_numbers[j], stream_number);
         }
         first = false;
@@ -535,11 +535,11 @@ static void test_sync_reader_streaming(void)
 
     hr = IWMSyncReader_GetNextSample(reader, stream_numbers[0], &sample,
             &pts, &duration, &flags, NULL, NULL);
-    todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
+    ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
 
     hr = IWMSyncReader_GetNextSample(reader, stream_numbers[1], &sample,
             &pts, &duration, &flags, NULL, NULL);
-    todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
+    ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
 
     hr = IWMSyncReader_SetRange(reader, 0, 0);
     todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
@@ -593,11 +593,11 @@ static void test_sync_reader_streaming(void)
 
     hr = IWMSyncReader_GetNextSample(reader, stream_numbers[0], &sample,
             &pts, &duration, &flags, NULL, NULL);
-    todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
+    ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
 
     hr = IWMSyncReader_GetNextSample(reader, stream_numbers[1], &sample,
             &pts, &duration, &flags, NULL, NULL);
-    todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
+    ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
 
     hr = IWMSyncReader_Close(reader);
     ok(hr == S_OK, "Got hr %#x.\n", hr);
diff --git a/include/wmsdkidl.idl b/include/wmsdkidl.idl
index f276d642a03..55142f47e93 100644
--- a/include/wmsdkidl.idl
+++ b/include/wmsdkidl.idl
@@ -81,6 +81,13 @@ typedef struct _WMReaderClientInfo
     WCHAR *wszPlayerUserAgent;
 } WM_READER_CLIENTINFO;
 
+enum
+{
+    WM_SF_CLEANPOINT    = 0x1,
+    WM_SF_DISCONTINUITY = 0x2,
+    WM_SF_DATALOSS      = 0x4,
+};
+
 typedef enum WMT_ATTR_DATATYPE
 {
     WMT_TYPE_DWORD      = 0,
-- 
2.33.0




More information about the wine-devel mailing list