From: Alfred Agrell floating@muncher.se
--- dlls/winegstreamer/wm_reader.c | 88 ++++++++++++++++++++++++++++++++-- dlls/wmvcore/tests/wmvcore.c | 61 ++++++++++++++--------- 2 files changed, 121 insertions(+), 28 deletions(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index a92556e9aec..4751cc9da2e 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -30,10 +30,6 @@ struct wm_stream WMT_STREAM_SELECTION selection; WORD index; bool eos; - /* Note that we only pretend to read compressed samples, and instead output - * uncompressed samples regardless of whether we are configured to read - * compressed samples. Rather, the behaviour of the reader objects differs - * in nontrivial ways depending on this field. */ bool read_compressed;
IWMReaderAllocatorEx *output_allocator; @@ -1541,6 +1537,78 @@ out_destroy_parser: return hr; }
+static HRESULT reinit_stream(struct wm_reader *reader, bool read_compressed) +{ + wg_parser_t wg_parser; + HRESULT hr; + WORD i; + + wg_parser_disconnect(reader->wg_parser); + + EnterCriticalSection(&reader->shutdown_cs); + reader->read_thread_shutdown = true; + LeaveCriticalSection(&reader->shutdown_cs); + WaitForSingleObject(reader->read_thread, INFINITE); + CloseHandle(reader->read_thread); + reader->read_thread = NULL; + + wg_parser_destroy(reader->wg_parser); + reader->wg_parser = 0; + + if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, read_compressed))) + return E_OUTOFMEMORY; + + reader->wg_parser = wg_parser; + 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, reader->file_size))) + { + ERR("Failed to connect parser, hr %#lx.\n", hr); + goto out_shutdown_thread; + } + + assert(reader->stream_count == wg_parser_get_stream_count(reader->wg_parser)); + + for (i = 0; i < reader->stream_count; ++i) + { + struct wm_stream *stream = &reader->streams[i]; + struct wg_format format; + + stream->wg_stream = wg_parser_get_stream(reader->wg_parser, i); + stream->reader = reader; + wg_parser_stream_get_preferred_format(stream->wg_stream, &format); + if (stream->selection == WMT_ON) + wg_parser_stream_enable(stream->wg_stream, read_compressed ? &format : &stream->format); + } + + /* 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); + + return S_OK; + +out_shutdown_thread: + EnterCriticalSection(&reader->shutdown_cs); + reader->read_thread_shutdown = true; + LeaveCriticalSection(&reader->shutdown_cs); + 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 = 0; + + return hr; +} + static 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) @@ -2352,6 +2420,7 @@ static HRESULT WINAPI reader_SetReadStreamSamples(IWMSyncReader2 *iface, WORD st }
stream->read_compressed = compressed; + reinit_stream(reader, compressed);
LeaveCriticalSection(&reader->cs); return S_OK; @@ -2397,7 +2466,16 @@ static HRESULT WINAPI reader_SetStreamsSelected(IWMSyncReader2 *iface, FIXME("Ignoring selection %#x for stream %u; treating as enabled.\n", selections[i], stream_numbers[i]); TRACE("Enabling stream %u.\n", stream_numbers[i]); - wg_parser_stream_enable(stream->wg_stream, &stream->format); + if (stream->read_compressed) + { + struct wg_format format; + wg_parser_stream_get_preferred_format(stream->wg_stream, &format); + wg_parser_stream_enable(stream->wg_stream, &format); + } + else + { + wg_parser_stream_enable(stream->wg_stream, &stream->format); + } } }
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 1741299e654..c1114b711f9 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -455,6 +455,7 @@ struct teststream HANDLE file; DWORD input_tid; DWORD main_tid; + DWORD input_tid_changes; };
static struct teststream *impl_from_IStream(IStream *iface) @@ -494,12 +495,10 @@ static HRESULT WINAPI stream_Read(IStream *iface, void *data, ULONG size, ULONG if (winetest_debug > 2) trace("%04lx: IStream::Read(size %lu)\n", GetCurrentThreadId(), size);
- if (!stream->input_tid) - stream->input_tid = GetCurrentThreadId(); - else + if (stream->input_tid != GetCurrentThreadId()) { - todo_wine_if(stream->input_tid == stream->main_tid) - ok(stream->input_tid == GetCurrentThreadId(), "got wrong thread\n"); + ++stream->input_tid_changes; + stream->input_tid = GetCurrentThreadId(); }
ok(size > 0, "Got zero size.\n"); @@ -523,12 +522,10 @@ static HRESULT WINAPI stream_Seek(IStream *iface, LARGE_INTEGER offset, DWORD me if (winetest_debug > 2) trace("%04lx: IStream::Seek(offset %I64u, method %#lx)\n", GetCurrentThreadId(), offset.QuadPart, method);
- if (!stream->input_tid) - stream->input_tid = GetCurrentThreadId(); - else + if (stream->input_tid != GetCurrentThreadId()) { - todo_wine_if(stream->input_tid == stream->main_tid) - ok(stream->input_tid == GetCurrentThreadId(), "got wrong thread\n"); + ++stream->input_tid_changes; + stream->input_tid = GetCurrentThreadId(); }
GetFileSizeEx(stream->file, &size); @@ -588,12 +585,10 @@ static HRESULT WINAPI stream_Stat(IStream *iface, STATSTG *stat, DWORD flags) if (winetest_debug > 1) trace("%04lx: IStream::Stat(flags %#lx)\n", GetCurrentThreadId(), flags);
- if (!stream->input_tid) - stream->input_tid = GetCurrentThreadId(); - else + if (stream->input_tid != GetCurrentThreadId()) { - todo_wine_if(stream->input_tid == stream->main_tid) - ok(stream->input_tid == GetCurrentThreadId(), "got wrong thread\n"); + ++stream->input_tid_changes; + stream->input_tid = GetCurrentThreadId(); }
ok(flags == STATFLAG_NONAME, "Got flags %#lx.\n", flags); @@ -1173,6 +1168,7 @@ static void test_sync_reader_settings(void) IWMSyncReader_Release(reader);
ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount); + todo_wine ok(stream.input_tid_changes == 1, "Changed thread %ld times.\n", stream.input_tid_changes); CloseHandle(stream.file); ret = DeleteFileW(filename); ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError()); @@ -1404,7 +1400,6 @@ static void test_sync_reader_streaming(void)
ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount);
- stream.input_tid = 0; /* FIXME: currently required as Wine calls IStream_Stat synchronously in OpenStream */ SetFilePointer(stream.file, 0, NULL, FILE_BEGIN); hr = IWMSyncReader_OpenStream(reader, &stream.IStream_iface); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1415,6 +1410,7 @@ static void test_sync_reader_streaming(void) ok(!ref, "Got outstanding refcount %ld.\n", ref);
ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount); + todo_wine ok(stream.input_tid_changes == 1, "Changed thread %ld times.\n", stream.input_tid_changes); CloseHandle(stream.file); ret = DeleteFileW(filename); ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError()); @@ -1775,6 +1771,7 @@ static void test_sync_reader_types(void) ok(!ref, "Got outstanding refcount %ld.\n", ref);
ok(stream.refcount == 1, "Got outstanding refcount %ld.\n", stream.refcount); + todo_wine ok(stream.input_tid_changes == 1, "Changed thread %ld times.\n", stream.input_tid_changes); CloseHandle(stream.file); ret = DeleteFileW(filename); ok(ret, "Failed to delete %s, error %lu.\n", debugstr_w(filename), GetLastError()); @@ -2053,7 +2050,7 @@ static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output, GetTickCount(), GetCurrentThreadId(), output, time, duration, flags);
/* uncompressed samples are slightly out of order because of decoding delay */ - ok(callback->last_pts[output] <= time, "got time %I64d\n", time); + ok(callback->last_pts[output] <= time, "expected %I64d <= %I64d\n", callback->last_pts[output], time); callback->last_pts[output] = time; callback->next_pts[output] = time + duration;
@@ -2134,7 +2131,7 @@ static HRESULT WINAPI callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced trace("%lu: %04lx: IWMReaderCallbackAdvanced::OnStreamSample(stream %u, pts %I64u, duration %I64u, flags %#lx)\n", GetTickCount(), GetCurrentThreadId(), stream_number, pts, duration, flags);
- ok(callback->last_pts[output] <= pts, "got pts %I64d\n", pts); + ok(callback->last_pts[output] <= pts, "expected %I64d <= %I64d\n", callback->last_pts[output], pts); callback->last_pts[output] = pts; callback->next_pts[output] = pts + duration;
@@ -2146,7 +2143,7 @@ static HRESULT WINAPI callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced else { ok(callback->callback_tid == GetCurrentThreadId(), "got wrong thread\n"); - ok(callback->last_pts[1 - output] <= pts, "got pts %I64d\n", pts); + ok(callback->last_pts[1 - output] <= pts, "expected %I64d <= %I64d\n", callback->last_pts[1 - output], pts); }
if (!callback->output_tid[output]) @@ -2572,8 +2569,6 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st callback->last_pts[1] = 0; callback->next_pts[1] = 0; memset(callback->output_tid, 0, sizeof(callback->output_tid)); - if (callback->stream) - callback->stream->input_tid = 0;
check_async_set_output_setting(advanced, 0, L"DedicatedDeliveryThread", WMT_TYPE_BOOL, callback->dedicated_threads, S_OK); @@ -2709,6 +2704,17 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st todo_wine ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr);
+ /* FIXME: native can switch mode without rewinding, but Wine can't */ + IWMReader_Stop(reader); + wait_stopped_callback(callback); + callback->last_pts[0] = 0; + callback->next_pts[0] = 0; + callback->last_pts[1] = 0; + callback->next_pts[1] = 0; + hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + wait_started_callback(callback); + callback->expect_time = 13460000; hr = IWMReaderAdvanced2_DeliverTime(advanced, 13460000); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -2716,7 +2722,7 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st todo_wine ok(callback->last_pts[0] == 13460000, "Got pts %I64d.\n", callback->last_pts[0]); todo_wine - ok(callback->next_pts[0] == 13930000, "Got pts %I64d.\n", callback->next_pts[0]); + ok(callback->next_pts[0] == 13920000, "Got pts %I64d.\n", callback->next_pts[0]); todo_wine ok(callback->last_pts[1] == 13260000, "Got pts %I64d.\n", callback->last_pts[1]); todo_wine @@ -2729,6 +2735,16 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 2, TRUE); ok(hr == S_OK, "Got hr %#lx.\n", hr); + + IWMReader_Stop(reader); + wait_stopped_callback(callback); + callback->last_pts[0] = 0; + callback->next_pts[0] = 0; + callback->last_pts[1] = 0; + callback->next_pts[1] = 0; + hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + wait_started_callback(callback); }
callback->expect_time = test_wmv_duration * 2; @@ -3233,7 +3249,6 @@ static void test_async_reader_streaming(void) ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount); wait_opened_callback(&callback);
- stream.input_tid = 0; /* FIXME: currently required as Wine calls IStream_Stat synchronously in OpenStream */ hr = IWMReaderAdvanced2_OpenStream(advanced, &stream.IStream_iface, &callback.IWMReaderCallback_iface, (void **)0xdeadbee0); ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr);