[PATCH 7/7] winegstreamer: Implement IWMSyncReader::Open().

Zebediah Figura zfigura at codeweavers.com
Tue Nov 2 00:13:04 CDT 2021


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/winegstreamer/gst_private.h   |   2 +
 dlls/winegstreamer/wm_reader.c     | 132 +++++++++++++++++++++++------
 dlls/winegstreamer/wm_syncreader.c |   8 +-
 dlls/wmvcore/tests/wmvcore.c       |  40 +++++++++
 4 files changed, 151 insertions(+), 31 deletions(-)

diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index f11543d7fb2..9674ee35052 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -139,6 +139,7 @@ struct wm_reader
     QWORD start_time;
 
     IStream *source_stream;
+    HANDLE file;
     HANDLE read_thread;
     bool read_thread_shutdown;
     struct wg_parser *wg_parser;
@@ -167,6 +168,7 @@ struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader
 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_file(struct wm_reader *reader, const WCHAR *filename);
 HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream);
 void wm_reader_seek(struct wm_reader *reader, QWORD start, LONGLONG duration);
 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 bd7fcd06bd3..2f5659608a9 100644
--- a/dlls/winegstreamer/wm_reader.c
+++ b/dlls/winegstreamer/wm_reader.c
@@ -438,22 +438,34 @@ static DWORD CALLBACK read_thread(void *arg)
 {
     struct wm_reader *reader = arg;
     IStream *stream = reader->source_stream;
+    HANDLE file = reader->file;
     size_t buffer_size = 4096;
     uint64_t file_size;
-    STATSTG stat;
     void *data;
 
     if (!(data = malloc(buffer_size)))
         return 0;
 
-    IStream_Stat(stream, &stat, STATFLAG_NONAME);
-    file_size = stat.cbSize.QuadPart;
+    if (file)
+    {
+        LARGE_INTEGER size;
+
+        GetFileSizeEx(file, &size);
+        file_size = size.QuadPart;
+    }
+    else
+    {
+        STATSTG stat;
+
+        IStream_Stat(stream, &stat, STATFLAG_NONAME);
+        file_size = stat.cbSize.QuadPart;
+    }
 
     TRACE("Starting read thread for reader %p.\n", reader);
 
     while (!reader->read_thread_shutdown)
     {
-        LARGE_INTEGER stream_offset;
+        LARGE_INTEGER large_offset;
         uint64_t offset;
         ULONG ret_size;
         uint32_t size;
@@ -481,14 +493,32 @@ static DWORD CALLBACK read_thread(void *arg)
 
         ret_size = 0;
 
-        stream_offset.QuadPart = offset;
-        if (SUCCEEDED(hr = IStream_Seek(stream, stream_offset, STREAM_SEEK_SET, NULL)))
-            hr = IStream_Read(stream, data, size, &ret_size);
-        if (FAILED(hr))
-            ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr);
-        else if (ret_size != size)
+        large_offset.QuadPart = offset;
+        if (file)
+        {
+            if (!SetFilePointerEx(file, large_offset, NULL, FILE_BEGIN)
+                    || !ReadFile(file, data, size, &ret_size, NULL))
+            {
+                ERR("Failed to read %u bytes at offset %I64u, error %u.\n", size, offset, GetLastError());
+                wg_parser_push_data(reader->wg_parser, NULL, 0);
+                continue;
+            }
+        }
+        else
+        {
+            if (SUCCEEDED(hr = IStream_Seek(stream, large_offset, STREAM_SEEK_SET, NULL)))
+                hr = IStream_Read(stream, data, size, &ret_size);
+            if (FAILED(hr))
+            {
+                ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr);
+                wg_parser_push_data(reader->wg_parser, NULL, 0);
+                continue;
+            }
+        }
+
+        if (ret_size != size)
             ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size);
-        wg_parser_push_data(reader->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size);
+        wg_parser_push_data(reader->wg_parser, data, ret_size);
     }
 
     free(data);
@@ -1326,26 +1356,16 @@ static const IWMReaderTimecodeVtbl timecode_vtbl =
     timecode_GetTimecodeRangeBounds,
 };
 
-HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream)
+static HRESULT init_stream(struct wm_reader *reader, QWORD file_size)
 {
     struct wg_parser *wg_parser;
-    STATSTG stat;
     HRESULT hr;
     WORD i;
 
-    if (FAILED(hr = IStream_Stat(stream, &stat, STATFLAG_NONAME)))
-    {
-        ERR("Failed to stat stream, hr %#x.\n", hr);
-        return hr;
-    }
-
     if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, false)))
         return E_OUTOFMEMORY;
 
-    EnterCriticalSection(&reader->cs);
-
     reader->wg_parser = wg_parser;
-    IStream_AddRef(reader->source_stream = stream);
     reader->read_thread_shutdown = false;
     if (!(reader->read_thread = CreateThread(NULL, 0, read_thread, reader, 0, NULL)))
     {
@@ -1353,7 +1373,7 @@ HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream)
         goto out_destroy_parser;
     }
 
-    if (FAILED(hr = wg_parser_connect(reader->wg_parser, stat.cbSize.QuadPart)))
+    if (FAILED(hr = wg_parser_connect(reader->wg_parser, file_size)))
     {
         ERR("Failed to connect parser, hr %#x.\n", hr);
         goto out_shutdown_thread;
@@ -1402,7 +1422,6 @@ HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream)
     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;
 
 out_disconnect_parser:
@@ -1417,8 +1436,60 @@ out_shutdown_thread:
 out_destroy_parser:
     wg_parser_destroy(reader->wg_parser);
     reader->wg_parser = NULL;
-    IStream_Release(reader->source_stream);
-    reader->source_stream = NULL;
+
+    return hr;
+}
+
+HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream)
+{
+    STATSTG stat;
+    HRESULT hr;
+
+    if (FAILED(hr = IStream_Stat(stream, &stat, STATFLAG_NONAME)))
+    {
+        ERR("Failed to stat stream, hr %#x.\n", hr);
+        return hr;
+    }
+
+    EnterCriticalSection(&reader->cs);
+
+    IStream_AddRef(reader->source_stream = stream);
+    if (FAILED(hr = init_stream(reader, stat.cbSize.QuadPart)))
+    {
+        IStream_Release(stream);
+        reader->source_stream = NULL;
+    }
+
+    LeaveCriticalSection(&reader->cs);
+    return hr;
+}
+
+HRESULT wm_reader_open_file(struct wm_reader *reader, const WCHAR *filename)
+{
+    LARGE_INTEGER size;
+    HANDLE file;
+    HRESULT hr;
+
+    if ((file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
+            OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
+    {
+        ERR("Failed to open %s, error %u.\n", debugstr_w(filename), GetLastError());
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    if (!GetFileSizeEx(file, &size))
+    {
+        ERR("Failed to get the size of %s, error %u.\n", debugstr_w(filename), GetLastError());
+        CloseHandle(file);
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    EnterCriticalSection(&reader->cs);
+
+    reader->file = file;
+
+    if (FAILED(hr = init_stream(reader, size.QuadPart)))
+        reader->file = NULL;
 
     LeaveCriticalSection(&reader->cs);
     return hr;
@@ -1428,7 +1499,7 @@ HRESULT wm_reader_close(struct wm_reader *reader)
 {
     EnterCriticalSection(&reader->cs);
 
-    if (!reader->source_stream)
+    if (!reader->wg_parser)
     {
         LeaveCriticalSection(&reader->cs);
         return NS_E_INVALID_REQUEST;
@@ -1443,8 +1514,13 @@ HRESULT wm_reader_close(struct wm_reader *reader)
 
     wg_parser_destroy(reader->wg_parser);
     reader->wg_parser = NULL;
-    IStream_Release(reader->source_stream);
+
+    if (reader->source_stream)
+        IStream_Release(reader->source_stream);
     reader->source_stream = NULL;
+    if (reader->file)
+        CloseHandle(reader->file);
+    reader->file = NULL;
 
     LeaveCriticalSection(&reader->cs);
     return S_OK;
diff --git a/dlls/winegstreamer/wm_syncreader.c b/dlls/winegstreamer/wm_syncreader.c
index 2c65f652cdb..fff048df06e 100644
--- a/dlls/winegstreamer/wm_syncreader.c
+++ b/dlls/winegstreamer/wm_syncreader.c
@@ -226,9 +226,11 @@ static HRESULT WINAPI WMSyncReader_GetStreamSelected(IWMSyncReader2 *iface, WORD
 
 static HRESULT WINAPI WMSyncReader_Open(IWMSyncReader2 *iface, const WCHAR *filename)
 {
-    struct sync_reader *This = impl_from_IWMSyncReader2(iface);
-    FIXME("(%p)->(%s): stub!\n", This, debugstr_w(filename));
-    return E_NOTIMPL;
+    struct sync_reader *reader = impl_from_IWMSyncReader2(iface);
+
+    TRACE("reader %p, filename %s.\n", reader, debugstr_w(filename));
+
+    return wm_reader_open_file(&reader->reader, filename);
 }
 
 static HRESULT WINAPI WMSyncReader_OpenStream(IWMSyncReader2 *iface, IStream *stream)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index 92208c0b8a3..eae320c4d2e 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -1012,6 +1012,45 @@ static void test_sync_reader_types(void)
     ok(ret, "Failed to delete %s, error %u.\n", debugstr_w(filename), GetLastError());
 }
 
+static void test_sync_reader_file(void)
+{
+    const WCHAR *filename = load_resource(L"test.wmv");
+    IWMSyncReader *reader;
+    IWMProfile *profile;
+    DWORD count;
+    HRESULT hr;
+    ULONG ref;
+    BOOL ret;
+
+    hr = WMCreateSyncReader(NULL, 0, &reader);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    IWMSyncReader_QueryInterface(reader, &IID_IWMProfile, (void **)&profile);
+
+    hr = IWMSyncReader_Open(reader, filename);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    count = 0xdeadbeef;
+    hr = IWMSyncReader_GetOutputCount(reader, &count);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(count == 2, "Got count %u.\n", count);
+
+    hr = IWMSyncReader_Close(reader);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IWMSyncReader_Close(reader);
+    ok(hr == NS_E_INVALID_REQUEST, "Got hr %#x.\n", hr);
+
+    hr = IWMSyncReader_Open(reader, filename);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    IWMProfile_Release(profile);
+    ref = IWMSyncReader_Release(reader);
+    ok(!ref, "Got outstanding refcount %d.\n", ref);
+
+    ret = DeleteFileW(filename);
+    ok(ret, "Failed to delete %s, error %u.\n", debugstr_w(filename), GetLastError());
+}
+
 START_TEST(wmvcore)
 {
     HRESULT hr;
@@ -1030,6 +1069,7 @@ START_TEST(wmvcore)
     test_iscontentprotected();
     test_sync_reader_streaming();
     test_sync_reader_types();
+    test_sync_reader_file();
 
     CoUninitialize();
 }
-- 
2.33.0




More information about the wine-devel mailing list