Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/wmvcore/tests/wmvcore.c | 265 +++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index dd1e3027d57..df55c2d3198 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -24,11 +24,20 @@ #include "initguid.h" #include "wmsdk.h" #include "wmsecure.h" +#include "amvideo.h" +#include "uuids.h" +#include "wmcodecdsp.h"
#include "wine/test.h"
HRESULT WINAPI WMCreateWriterPriv(IWMWriter **writer);
+static BOOL compare_media_types(const WM_MEDIA_TYPE *a, const WM_MEDIA_TYPE *b) +{ + return !memcmp(a, b, offsetof(WM_MEDIA_TYPE, pbFormat)) + && !memcmp(a->pbFormat, b->pbFormat, a->cbFormat); +} + static WCHAR *load_resource(const WCHAR *name) { static WCHAR pathW[MAX_PATH]; @@ -616,6 +625,261 @@ static void test_sync_reader_streaming(void) ok(ret, "Failed to delete %s, error %u.\n", debugstr_w(filename), GetLastError()); }
+static void check_video_type(const WM_MEDIA_TYPE *mt) +{ + const VIDEOINFOHEADER *video_info = (const VIDEOINFOHEADER *)mt->pbFormat; + static const RECT rect = {.right = 64, .bottom = 48}; + + ok(IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo), "Got format %s.\n", debugstr_guid(&mt->formattype)); + todo_wine ok(mt->bFixedSizeSamples == TRUE, "Got fixed size %d.\n", mt->bFixedSizeSamples); + todo_wine ok(!mt->bTemporalCompression, "Got temporal compression %d.\n", mt->bTemporalCompression); + ok(!mt->pUnk, "Got pUnk %p.\n", mt->pUnk); + + todo_wine ok(EqualRect(&video_info->rcSource, &rect), "Got source rect %s.\n", wine_dbgstr_rect(&rect)); + todo_wine ok(EqualRect(&video_info->rcTarget, &rect), "Got target rect %s.\n", wine_dbgstr_rect(&rect)); + ok(!video_info->dwBitRate, "Got bit rate %u.\n", video_info->dwBitRate); + ok(!video_info->dwBitErrorRate, "Got bit error rate %u.\n", video_info->dwBitErrorRate); + ok(video_info->bmiHeader.biSize == sizeof(video_info->bmiHeader), + "Got size %u.\n", video_info->bmiHeader.biSize); + ok(video_info->bmiHeader.biWidth == 64, "Got width %d.\n", video_info->bmiHeader.biWidth); + ok(video_info->bmiHeader.biHeight == 48, "Got height %d.\n", video_info->bmiHeader.biHeight); + ok(video_info->bmiHeader.biPlanes == 1, "Got planes %d.\n", video_info->bmiHeader.biPlanes); +} + +static void check_audio_type(const WM_MEDIA_TYPE *mt) +{ + const WAVEFORMATEX *wave_format = (const WAVEFORMATEX *)mt->pbFormat; + + ok(IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_PCM), "Got subtype %s.\n", debugstr_guid(&mt->subtype)); + ok(IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx), "Got format %s.\n", debugstr_guid(&mt->formattype)); + ok(mt->bFixedSizeSamples == TRUE, "Got fixed size %d.\n", mt->bFixedSizeSamples); + ok(!mt->bTemporalCompression, "Got temporal compression %d.\n", mt->bTemporalCompression); + ok(!mt->pUnk, "Got pUnk %p.\n", mt->pUnk); + + ok(wave_format->wFormatTag == WAVE_FORMAT_PCM, "Got tag %#x.\n", wave_format->wFormatTag); +} + +static void test_sync_reader_types(void) +{ + char mt_buffer[2000], mt2_buffer[2000]; + const WCHAR *filename = load_resource(L"test.wmv"); + IWMOutputMediaProps *output_props, *output_props2; + WM_MEDIA_TYPE *mt2 = (WM_MEDIA_TYPE *)mt2_buffer; + WM_MEDIA_TYPE *mt = (WM_MEDIA_TYPE *)mt_buffer; + bool got_video = false, got_audio = false; + DWORD size, ret_size, output_number; + WORD stream_number, stream_number2; + struct teststream stream = {0}; + IWMStreamConfig *config; + ULONG count, ref, i, j; + IWMSyncReader *reader; + IWMProfile *profile; + GUID majortype; + HANDLE file; + HRESULT hr; + BOOL ret; + + file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "Failed to open %s, error %u.\n", debugstr_w(file), GetLastError()); + + stream.IStream_iface.lpVtbl = &stream_vtbl; + stream.refcount = 1; + stream.file = file; + + hr = WMCreateSyncReader(NULL, 0, &reader); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IWMSyncReader_QueryInterface(reader, &IID_IWMProfile, (void **)&profile); + + hr = IWMSyncReader_OpenStream(reader, &stream.IStream_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(stream.refcount > 1, "Got refcount %d.\n", stream.refcount); + + for (i = 0; i < 2; ++i) + { + winetest_push_context("Stream %u", i); + + hr = IWMProfile_GetStream(profile, i, &config); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr != S_OK) + { + winetest_pop_context(); + continue; + } + + stream_number = 0xdead; + hr = IWMStreamConfig_GetStreamNumber(config, &stream_number); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(stream_number == i + 1, "Got stream number %u.\n", stream_number); + + hr = IWMStreamConfig_GetStreamType(config, &majortype); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (!i) + todo_wine ok(IsEqualGUID(&majortype, &MEDIATYPE_Video), "Got major type %s.\n", debugstr_guid(&majortype)); + else + todo_wine ok(IsEqualGUID(&majortype, &MEDIATYPE_Audio), "Got major type %s.\n", debugstr_guid(&majortype)); + + ref = IWMStreamConfig_Release(config); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + output_number = 0xdeadbeef; + hr = IWMSyncReader_GetOutputNumberForStream(reader, stream_number, &output_number); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(output_number == 1 - i, "Got output number %u.\n", output_number); + + stream_number2 = 0xdead; + hr = IWMSyncReader_GetStreamNumberForOutput(reader, output_number, &stream_number2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(stream_number2 == stream_number, "Expected stream number %u, got %u.\n", stream_number, stream_number2); + + hr = IWMSyncReader_GetOutputProps(reader, output_number, &output_props); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + + ret_size = sizeof(mt_buffer); + hr = IWMOutputMediaProps_GetMediaType(output_props, mt, &ret_size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ref = IWMOutputMediaProps_Release(output_props); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + if (IsEqualGUID(&majortype, &MEDIATYPE_Audio)) + { + got_audio = true; + check_audio_type(mt); + } + else + { + ok(IsEqualGUID(&majortype, &MEDIATYPE_Video), "Got major type %s.\n", debugstr_guid(&majortype)); + got_video = true; + check_video_type(mt); + } + + count = 0; + hr = IWMSyncReader_GetOutputFormatCount(reader, output_number, &count); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(count > 0, "Got count %u.\n", count); + + for (j = 0; j < count; ++j) + { + winetest_push_context("Format %u", j); + + hr = IWMSyncReader_GetOutputFormat(reader, output_number, j, &output_props); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_GetOutputFormat(reader, output_number, j, &output_props2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(output_props2 != output_props, "Expected different objects.\n"); + ref = IWMOutputMediaProps_Release(output_props2); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + size = 0xdeadbeef; + hr = IWMOutputMediaProps_GetMediaType(output_props, NULL, &size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(size != 0xdeadbeef && size >= sizeof(WM_MEDIA_TYPE), "Got size %u.\n", size); + + ret_size = size - 1; + hr = IWMOutputMediaProps_GetMediaType(output_props, mt, &ret_size); + ok(hr == ASF_E_BUFFERTOOSMALL, "Got hr %#x.\n", hr); + ok(ret_size == size, "Expected size %u, got %u.\n", size, ret_size); + + ret_size = sizeof(mt_buffer); + memset(mt_buffer, 0xcc, sizeof(mt_buffer)); + hr = IWMOutputMediaProps_GetMediaType(output_props, mt, &ret_size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(ret_size == size, "Expected size %u, got %u.\n", size, ret_size); + ok(size == sizeof(WM_MEDIA_TYPE) + mt->cbFormat, "Expected size %u, got %u.\n", + sizeof(WM_MEDIA_TYPE) + mt->cbFormat, size); + + ok(IsEqualGUID(&mt->majortype, &majortype), "Got major type %s.\n", debugstr_guid(&mt->majortype)); + + if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio)) + check_audio_type(mt); + else + check_video_type(mt); + + hr = IWMSyncReader_SetOutputProps(reader, output_number, output_props); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + if (hr != S_OK) + { + ref = IWMOutputMediaProps_Release(output_props); + ok(!ref, "Got outstanding refcount %d.\n", ref); + winetest_pop_context(); + continue; + } + hr = IWMSyncReader_SetOutputProps(reader, 1 - output_number, output_props); + if (!i) + todo_wine ok(hr == ASF_E_BADMEDIATYPE, "Got hr %#x.\n", hr); + else + ok(hr == NS_E_INCOMPATIBLE_FORMAT + || hr == NS_E_INVALID_OUTPUT_FORMAT /* win10 */, "Got hr %#x.\n", hr); + hr = IWMSyncReader_SetOutputProps(reader, 2, output_props); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_GetOutputProps(reader, output_number, &output_props2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(output_props2 != output_props, "Expected different objects.\n"); + + ret_size = sizeof(mt2_buffer); + hr = IWMOutputMediaProps_GetMediaType(output_props2, mt2, &ret_size); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(compare_media_types(mt, mt2), "Media types didn't match.\n"); + + ref = IWMOutputMediaProps_Release(output_props2); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IWMOutputMediaProps_Release(output_props); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + winetest_pop_context(); + } + + hr = IWMSyncReader_GetOutputFormat(reader, output_number, count, &output_props); + todo_wine ok(hr == NS_E_INVALID_OUTPUT_FORMAT, "Got hr %#x.\n", hr); + + hr = IWMSyncReader_GetOutputProps(reader, output_number, &output_props); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + + if (hr == S_OK) + { + hr = IWMSyncReader_GetOutputProps(reader, output_number, &output_props2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(output_props2 != output_props, "Expected different objects.\n"); + + ref = IWMOutputMediaProps_Release(output_props2); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IWMOutputMediaProps_Release(output_props); + ok(!ref, "Got outstanding refcount %d.\n", ref); + } + + winetest_pop_context(); + } + + todo_wine ok(got_audio, "No audio stream was enumerated.\n"); + todo_wine ok(got_video, "No video stream was enumerated.\n"); + + count = 0xdeadbeef; + hr = IWMSyncReader_GetOutputFormatCount(reader, 2, &count); + todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(count == 0xdeadbeef, "Got count %#x.\n", count); + + output_props = (void *)0xdeadbeef; + hr = IWMSyncReader_GetOutputProps(reader, 2, &output_props); + todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(output_props == (void *)0xdeadbeef, "Got output props %p.\n", output_props); + + output_props = (void *)0xdeadbeef; + hr = IWMSyncReader_GetOutputFormat(reader, 2, 0, &output_props); + todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(output_props == (void *)0xdeadbeef, "Got output props %p.\n", output_props); + + IWMProfile_Release(profile); + ref = IWMSyncReader_Release(reader); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + ok(stream.refcount == 1, "Got outstanding refcount %d.\n", stream.refcount); + CloseHandle(stream.file); + ret = DeleteFileW(filename); + ok(ret, "Failed to delete %s, error %u.\n", debugstr_w(filename), GetLastError()); +} + START_TEST(wmvcore) { HRESULT hr; @@ -633,6 +897,7 @@ START_TEST(wmvcore) test_urlextension(); test_iscontentprotected(); test_sync_reader_streaming(); + test_sync_reader_types();
CoUninitialize(); }
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/gst_private.h | 6 +++++ dlls/winegstreamer/wm_asyncreader.c | 2 ++ dlls/winegstreamer/wm_reader.c | 37 +++++++++++++++++++++++++++++ dlls/winegstreamer/wm_syncreader.c | 18 +++++++++----- dlls/wmvcore/tests/wmvcore.c | 10 ++++---- 5 files changed, 62 insertions(+), 11 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index c757dfbefd8..a07195a4a1e 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -122,6 +122,9 @@ struct wm_reader IWMReaderPlaylistBurn IWMReaderPlaylistBurn_iface; IWMReaderTimecode IWMReaderTimecode_iface; LONG refcount; + CRITICAL_SECTION cs; + + IStream *source_stream;
const struct wm_reader_ops *ops; }; @@ -132,6 +135,9 @@ struct wm_reader_ops void (*destroy)(struct wm_reader *reader); };
+void wm_reader_cleanup(struct wm_reader *reader); +HRESULT wm_reader_close(struct wm_reader *reader); 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);
#endif /* __GST_PRIVATE_INCLUDED__ */ diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c index 12b96245707..4fec89a2100 100644 --- a/dlls/winegstreamer/wm_asyncreader.c +++ b/dlls/winegstreamer/wm_asyncreader.c @@ -1255,6 +1255,8 @@ static void async_reader_destroy(struct wm_reader *iface)
TRACE("reader %p.\n", reader);
+ wm_reader_close(&reader->reader); + wm_reader_cleanup(&reader->reader); free(reader); }
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 963d33afe0f..e5c2d2a9789 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -759,6 +759,34 @@ static const IWMReaderTimecodeVtbl timecode_vtbl = timecode_GetTimecodeRangeBounds, };
+HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream) +{ + EnterCriticalSection(&reader->cs); + + IStream_AddRef(reader->source_stream = stream); + + LeaveCriticalSection(&reader->cs); + + return S_OK; +} + +HRESULT wm_reader_close(struct wm_reader *reader) +{ + EnterCriticalSection(&reader->cs); + + if (!reader->source_stream) + { + LeaveCriticalSection(&reader->cs); + return NS_E_INVALID_REQUEST; + } + + IStream_Release(reader->source_stream); + reader->source_stream = NULL; + + LeaveCriticalSection(&reader->cs); + return S_OK; +} + void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops) { reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl; @@ -769,4 +797,13 @@ void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops) reader->IWMReaderTimecode_iface.lpVtbl = &timecode_vtbl; reader->refcount = 1; reader->ops = ops; + + InitializeCriticalSection(&reader->cs); + reader->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": wm_reader.cs"); +} + +void wm_reader_cleanup(struct wm_reader *reader) +{ + reader->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&reader->cs); } diff --git a/dlls/winegstreamer/wm_syncreader.c b/dlls/winegstreamer/wm_syncreader.c index 0113ced1730..bb98a60ad48 100644 --- a/dlls/winegstreamer/wm_syncreader.c +++ b/dlls/winegstreamer/wm_syncreader.c @@ -55,9 +55,11 @@ static ULONG WINAPI WMSyncReader_Release(IWMSyncReader2 *iface)
static HRESULT WINAPI WMSyncReader_Close(IWMSyncReader2 *iface) { - struct sync_reader *This = impl_from_IWMSyncReader2(iface); - FIXME("(%p): stub!\n", This); - return E_NOTIMPL; + struct sync_reader *reader = impl_from_IWMSyncReader2(iface); + + TRACE("reader %p.\n", reader); + + return wm_reader_close(&reader->reader); }
static HRESULT WINAPI WMSyncReader_GetMaxOutputSampleSize(IWMSyncReader2 *iface, DWORD output, DWORD *max) @@ -157,9 +159,11 @@ static HRESULT WINAPI WMSyncReader_Open(IWMSyncReader2 *iface, const WCHAR *file
static HRESULT WINAPI WMSyncReader_OpenStream(IWMSyncReader2 *iface, IStream *stream) { - struct sync_reader *This = impl_from_IWMSyncReader2(iface); - FIXME("(%p)->(%p): stub!\n", This, stream); - return S_OK; + struct sync_reader *reader = impl_from_IWMSyncReader2(iface); + + TRACE("reader %p, stream %p.\n", reader, stream); + + return wm_reader_open_stream(&reader->reader, stream); }
static HRESULT WINAPI WMSyncReader_SetOutputProps(IWMSyncReader2 *iface, DWORD output_num, IWMOutputMediaProps *output) @@ -309,6 +313,8 @@ static void sync_reader_destroy(struct wm_reader *iface)
TRACE("reader %p.\n", reader);
+ wm_reader_close(&reader->reader); + wm_reader_cleanup(&reader->reader); free(reader); }
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index df55c2d3198..89a6640af2d 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -451,7 +451,7 @@ static void test_sync_reader_streaming(void)
hr = IWMSyncReader_OpenStream(reader, &stream.IStream_iface); ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(stream.refcount > 1, "Got refcount %d.\n", stream.refcount); + ok(stream.refcount > 1, "Got refcount %d.\n", stream.refcount);
hr = IWMProfile_GetStreamCount(profile, NULL); ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); @@ -603,17 +603,17 @@ static void test_sync_reader_streaming(void) todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
hr = IWMSyncReader_Close(reader); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IWMSyncReader_Close(reader); - todo_wine ok(hr == NS_E_INVALID_REQUEST, "Got hr %#x.\n", hr); + ok(hr == NS_E_INVALID_REQUEST, "Got hr %#x.\n", hr);
ok(stream.refcount == 1, "Got outstanding refcount %d.\n", stream.refcount);
SetFilePointer(stream.file, 0, NULL, FILE_BEGIN); hr = IWMSyncReader_OpenStream(reader, &stream.IStream_iface); ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(stream.refcount > 1, "Got refcount %d.\n", stream.refcount); + ok(stream.refcount > 1, "Got refcount %d.\n", stream.refcount);
IWMProfile_Release(profile); ref = IWMSyncReader_Release(reader); @@ -692,7 +692,7 @@ static void test_sync_reader_types(void)
hr = IWMSyncReader_OpenStream(reader, &stream.IStream_iface); ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(stream.refcount > 1, "Got refcount %d.\n", stream.refcount); + ok(stream.refcount > 1, "Got refcount %d.\n", stream.refcount);
for (i = 0; i < 2; ++i) {
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/gst_private.h | 3 + dlls/winegstreamer/wm_reader.c | 113 ++++++++++++++++++++++++++++++- 2 files changed, 115 insertions(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index a07195a4a1e..caa449956bf 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -125,6 +125,9 @@ struct wm_reader CRITICAL_SECTION cs;
IStream *source_stream; + HANDLE read_thread; + bool read_thread_shutdown; + struct wg_parser *wg_parser;
const struct wm_reader_ops *ops; }; diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index e5c2d2a9789..163eebf8c55 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -20,6 +20,68 @@
WINE_DEFAULT_DEBUG_CHANNEL(wmvcore);
+static DWORD CALLBACK read_thread(void *arg) +{ + struct wm_reader *reader = arg; + IStream *stream = reader->source_stream; + 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; + + TRACE("Starting read thread for reader %p.\n", reader); + + while (!reader->read_thread_shutdown) + { + LARGE_INTEGER stream_offset; + uint64_t offset; + ULONG ret_size; + uint32_t size; + HRESULT hr; + + if (!wg_parser_get_next_read_offset(reader->wg_parser, &offset, &size)) + continue; + + if (offset >= file_size) + size = 0; + else if (offset + size >= file_size) + size = file_size - offset; + + if (!size) + { + wg_parser_push_data(reader->wg_parser, data, 0); + continue; + } + + if (!array_reserve(&data, &buffer_size, size, 1)) + { + free(data); + return 0; + } + + 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) + 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); + } + + free(data); + TRACE("Reader is shutting down; exiting.\n"); + return 0; +} + static struct wm_reader *impl_from_IWMProfile3(IWMProfile3 *iface) { return CONTAINING_RECORD(iface, struct wm_reader, IWMProfile3_iface); @@ -761,13 +823,53 @@ static const IWMReaderTimecodeVtbl timecode_vtbl =
HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream) { + struct wg_parser *wg_parser; + STATSTG stat; + HRESULT hr; + + 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))) + { + hr = E_OUTOFMEMORY; + goto out_destroy_parser; + } + + if (FAILED(hr = wg_parser_connect(reader->wg_parser, stat.cbSize.QuadPart))) + { + ERR("Failed to connect parser, hr %#x.\n", hr); + goto out_shutdown_thread; + }
LeaveCriticalSection(&reader->cs); - return S_OK; + +out_shutdown_thread: + reader->read_thread_shutdown = true; + WaitForSingleObject(reader->read_thread, INFINITE); + CloseHandle(reader->read_thread); + reader->read_thread = NULL; + +out_destroy_parser: + wg_parser_destroy(reader->wg_parser); + reader->wg_parser = NULL; + IStream_Release(reader->source_stream); + reader->source_stream = NULL; + + LeaveCriticalSection(&reader->cs); + return hr; }
HRESULT wm_reader_close(struct wm_reader *reader) @@ -780,6 +882,15 @@ HRESULT wm_reader_close(struct wm_reader *reader) return NS_E_INVALID_REQUEST; }
+ wg_parser_disconnect(reader->wg_parser); + + reader->read_thread_shutdown = true; + WaitForSingleObject(reader->read_thread, INFINITE); + CloseHandle(reader->read_thread); + reader->read_thread = NULL; + + wg_parser_destroy(reader->wg_parser); + reader->wg_parser = NULL; IStream_Release(reader->source_stream); reader->source_stream = NULL;
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/gst_private.h | 2 ++ dlls/winegstreamer/wm_reader.c | 10 ++++++++-- dlls/wmvcore/tests/wmvcore.c | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index caa449956bf..86ddc3c85c8 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -129,6 +129,8 @@ struct wm_reader bool read_thread_shutdown; struct wg_parser *wg_parser;
+ WORD stream_count; + const struct wm_reader_ops *ops; };
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 163eebf8c55..689d2232b73 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -188,12 +188,16 @@ static HRESULT WINAPI profile_SetDescription(IWMProfile3 *iface, const WCHAR *de
static HRESULT WINAPI profile_GetStreamCount(IWMProfile3 *iface, DWORD *count) { - FIXME("iface %p, count %p, stub!\n", iface, count); + struct wm_reader *reader = impl_from_IWMProfile3(iface); + + TRACE("reader %p, count %p.\n", reader, count);
if (!count) return E_INVALIDARG;
- *count = 0; + EnterCriticalSection(&reader->cs); + *count = reader->stream_count; + LeaveCriticalSection(&reader->cs); return S_OK; }
@@ -853,6 +857,8 @@ HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream) goto out_shutdown_thread; }
+ reader->stream_count = wg_parser_get_stream_count(reader->wg_parser); + LeaveCriticalSection(&reader->cs); return S_OK;
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 89a6640af2d..efcadc7f7a6 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -459,7 +459,7 @@ static void test_sync_reader_streaming(void) count = 0xdeadbeef; hr = IWMProfile_GetStreamCount(profile, &count); ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(count == 2, "Got count %u.\n", count); + ok(count == 2, "Got count %u.\n", count);
count = 0xdeadbeef; hr = IWMSyncReader_GetOutputCount(reader, &count);