From: Alfred Agrell floating@muncher.se
--- dlls/winegstreamer/wm_reader.c | 79 ++++++++++++++++++++++++++++------ dlls/wmvcore/tests/wmvcore.c | 29 +++++++++++-- 2 files changed, 91 insertions(+), 17 deletions(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 09d07ddfdb0..b649ddb06be 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; @@ -620,6 +616,12 @@ static DWORD CALLBACK read_thread(void *arg) parser = reader->wg_parser; LeaveCriticalSection(&reader->init_cs);
+ if (!parser) + { + Sleep(10); + continue; + } + if (!wg_parser_get_next_read_offset(parser, &offset, &size)) continue;
@@ -1450,6 +1452,8 @@ static const IWMReaderTimecodeVtbl timecode_vtbl = timecode_GetTimecodeRangeBounds, };
+static void setup_stream_formats(struct wm_reader *reader); + static HRESULT init_stream(struct wm_reader *reader) { wg_parser_t wg_parser; @@ -1475,13 +1479,40 @@ static HRESULT init_stream(struct wm_reader *reader) }
reader->stream_count = wg_parser_get_stream_count(reader->wg_parser); - if (!(reader->streams = calloc(reader->stream_count, sizeof(*reader->streams)))) { hr = E_OUTOFMEMORY; goto out_disconnect_parser; } + for (i = 0; i < reader->stream_count; ++i) + reader->streams[i].selection = WMT_ON; + + setup_stream_formats(reader); + return S_OK; + +out_disconnect_parser: + wg_parser_disconnect(reader->wg_parser);
+out_shutdown_thread: + EnterCriticalSection(&reader->init_cs); + reader->read_thread_shutdown = true; + LeaveCriticalSection(&reader->init_cs); + WaitForSingleObject(reader->read_thread, INFINITE); + CloseHandle(reader->read_thread); + reader->read_thread = NULL; + +out_destroy_parser: + EnterCriticalSection(&reader->init_cs); + wg_parser_destroy(reader->wg_parser); + reader->wg_parser = 0; + LeaveCriticalSection(&reader->init_cs); + + return hr; +} + +static void setup_stream_formats(struct wm_reader *reader) +{ + WORD i; for (i = 0; i < reader->stream_count; ++i) { struct wm_stream *stream = &reader->streams[i]; @@ -1489,7 +1520,6 @@ static HRESULT init_stream(struct wm_reader *reader) stream->wg_stream = wg_parser_get_stream(reader->wg_parser, i); stream->reader = reader; stream->index = i; - stream->selection = WMT_ON; wg_parser_stream_get_preferred_format(stream->wg_stream, &stream->format); if (stream->format.major_type == WG_MAJOR_TYPE_AUDIO) { @@ -1515,26 +1545,46 @@ static HRESULT init_stream(struct wm_reader *reader) if (stream->format.u.video.height > 0) stream->format.u.video.height = -stream->format.u.video.height; } - wg_parser_stream_enable(stream->wg_stream, &stream->format); + if (stream->selection == WMT_ON) + wg_parser_stream_enable(stream->wg_stream, &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; +static HRESULT reinit_stream(struct wm_reader *reader, bool read_compressed) +{ + wg_parser_t wg_parser; + HRESULT hr;
-out_disconnect_parser: wg_parser_disconnect(reader->wg_parser); + EnterCriticalSection(&reader->init_cs); + wg_parser_destroy(reader->wg_parser); + reader->wg_parser = 0; + LeaveCriticalSection(&reader->init_cs); + + if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, read_compressed))) + return E_OUTOFMEMORY;
-out_shutdown_thread: EnterCriticalSection(&reader->init_cs); - reader->read_thread_shutdown = true; + reader->wg_parser = wg_parser; + reader->read_thread_shutdown = false; LeaveCriticalSection(&reader->init_cs); - WaitForSingleObject(reader->read_thread, INFINITE); - CloseHandle(reader->read_thread); - reader->read_thread = NULL; + + if (FAILED(hr = wg_parser_connect(reader->wg_parser, reader->file_size))) + { + ERR("Failed to connect parser, hr %#lx.\n", hr); + goto out_destroy_parser; + } + + assert(reader->stream_count == wg_parser_get_stream_count(reader->wg_parser)); + + setup_stream_formats(reader); + + return S_OK;
out_destroy_parser: EnterCriticalSection(&reader->init_cs); @@ -2351,6 +2401,7 @@ static HRESULT WINAPI reader_SetReadStreamSamples(IWMSyncReader2 *iface, WORD st }
stream->read_compressed = compressed; + reinit_stream(reader, compressed);
LeaveCriticalSection(&reader->cs); return S_OK; diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 1741299e654..35688bd04e4 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1848,6 +1848,7 @@ struct callback QWORD next_pts[2]; QWORD expect_time; HANDLE expect_ontime, got_ontime; + bool todo_rewind; };
static struct callback *impl_from_IWMReaderCallback(IWMReaderCallback *iface) @@ -2052,8 +2053,16 @@ static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output, trace("%lu: %04lx: IWMReaderCallback::OnSample(output %lu, time %I64u, duration %I64u, flags %#lx)\n", GetTickCount(), GetCurrentThreadId(), output, time, duration, flags);
+ if (callback->last_pts[output] > time && callback->todo_rewind) + { + callback->todo_rewind = false; + todo_wine ok(0, "changing compression state in Wine rewinds the stream\n"); + callback->last_pts[0] = 0; + callback->last_pts[1] = 0; + } + /* 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 +2143,15 @@ 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); + if (callback->last_pts[output] > pts && callback->todo_rewind) + { + callback->todo_rewind = false; + todo_wine ok(0, "changing compression state in Wine rewinds the stream\n"); + callback->last_pts[0] = 0; + callback->last_pts[1] = 0; + } + + 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 +2163,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]) @@ -2709,6 +2726,8 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st todo_wine ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr);
+ if (winetest_platform_is_wine) + callback->todo_rewind = true; callback->expect_time = 13460000; hr = IWMReaderAdvanced2_DeliverTime(advanced, 13460000); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -2723,6 +2742,7 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st ok(callback->next_pts[1] == 13270000, "Got pts %I64d.\n", callback->next_pts[1]); ok(callback->sample_count > 0, "Got no samples.\n"); callback->sample_count = 0; + ok(!callback->todo_rewind, "Didn't rewind as expected\n");
callback->read_compressed = true; hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 1, TRUE); @@ -2731,6 +2751,8 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st ok(hr == S_OK, "Got hr %#lx.\n", hr); }
+ if (winetest_platform_is_wine && callback->read_compressed) + callback->todo_rewind = true; callback->expect_time = test_wmv_duration * 2; hr = IWMReaderAdvanced2_DeliverTime(advanced, test_wmv_duration * 2); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -2754,6 +2776,7 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st callback->next_pts[0] = 0; callback->last_pts[1] = 0; callback->next_pts[1] = 0; + ok(!callback->todo_rewind, "Didn't rewind as expected\n");
hr = IWMReader_Stop(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr);