Signed-off-by: Zebediah Figura zfigura@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(); }