From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winegstreamer/wm_asyncreader.c | 196 +++++++++++++++++++--------- dlls/wmvcore/tests/wmvcore.c | 103 +++++---------- 2 files changed, 166 insertions(+), 133 deletions(-)
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c index 9d8c2be45cb..033cda18dc4 100644 --- a/dlls/winegstreamer/wm_asyncreader.c +++ b/dlls/winegstreamer/wm_asyncreader.c @@ -40,7 +40,12 @@ struct async_reader CRITICAL_SECTION stream_cs; CONDITION_VARIABLE stream_cv;
- bool running; + enum async_reader_state + { + STATE_CLOSED = 1, + STATE_STOPPED = 2, + STATE_RUNNING = 3, + } state, next_state;
bool user_clock; QWORD user_time; @@ -54,20 +59,62 @@ static REFERENCE_TIME get_current_time(const struct async_reader *reader) return (time.QuadPart * 1000) / reader->clock_frequency.QuadPart * 10000; }
-static void open_stream(struct async_reader *reader, IWMReaderCallback *callback, void *context) +static void execute_state_transition(struct async_reader *reader) { static const DWORD zero;
- IWMReaderCallback_AddRef(reader->callback = callback); - reader->context = context; - IWMReaderCallback_OnStatus(callback, WMT_OPENED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context); + switch (MAKELONG(reader->state, reader->next_state)) + { + case MAKELONG(STATE_CLOSED, STATE_CLOSED): + break; + case MAKELONG(STATE_CLOSED, STATE_STOPPED): + IWMReaderCallback_OnStatus(reader->callback, WMT_OPENED, S_OK, + WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + break; + case MAKELONG(STATE_CLOSED, STATE_RUNNING): + break; + + case MAKELONG(STATE_STOPPED, STATE_CLOSED): + IWMReaderCallback_OnStatus(reader->callback, WMT_CLOSED, S_OK, + WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + break; + case MAKELONG(STATE_STOPPED, STATE_STOPPED): + IWMReaderCallback_OnStatus(reader->callback, WMT_STOPPED, S_OK, + WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + break; + case MAKELONG(STATE_STOPPED, STATE_RUNNING): + IWMReaderCallback_OnStatus(reader->callback, WMT_STARTED, S_OK, + WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + break; + + case MAKELONG(STATE_RUNNING, STATE_RUNNING): + break; + case MAKELONG(STATE_RUNNING, STATE_CLOSED): + IWMReaderCallback_OnStatus(reader->callback, WMT_CLOSED, S_OK, + WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + break; + case MAKELONG(STATE_RUNNING, STATE_STOPPED): + IWMReaderCallback_OnStatus(reader->callback, WMT_STOPPED, S_OK, + WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + break; + } + + reader->state = reader->next_state; + reader->next_state = 0; }
-static DWORD WINAPI stream_thread(void *arg) +static void request_state_transition(struct async_reader *reader, enum async_reader_state new_state) +{ + reader->next_state = new_state; + if (!reader->stream_thread) + execute_state_transition(reader); + else + WakeConditionVariable(&reader->stream_cv); +} + +static void stream_thread_running(struct async_reader *reader, IWMReaderCallbackAdvanced *callback_advanced) { - struct async_reader *reader = arg; IWMReaderCallback *callback = reader->callback; - IWMReaderCallbackAdvanced *callback_advanced; REFERENCE_TIME start_time; struct wm_stream *stream; static const DWORD zero; @@ -79,14 +126,7 @@ static DWORD WINAPI stream_thread(void *arg)
start_time = get_current_time(reader);
- EnterCriticalSection(&reader->stream_cs); - - if (FAILED(hr = IWMReaderCallback_QueryInterface(callback, - &IID_IWMReaderCallbackAdvanced, (void **)&callback_advanced))) - callback_advanced = NULL; - TRACE("Querying for IWMReaderCallbackAdvanced returned %#lx.\n", hr); - - while (reader->running) + while (reader->state == STATE_RUNNING) { hr = wm_reader_get_stream_sample(&reader->reader, callback_advanced, 0, &sample, &pts, &duration, &flags, &stream_number); if (hr != S_OK) @@ -105,12 +145,12 @@ static DWORD WINAPI stream_thread(void *arg) EnterCriticalSection(&reader->stream_cs); }
- while (pts > reader->user_time && reader->running) + while (pts > reader->user_time && reader->state == STATE_RUNNING) SleepConditionVariableCS(&reader->stream_cv, &reader->stream_cs, INFINITE); } else { - while (reader->running) + while (reader->state == STATE_RUNNING) { REFERENCE_TIME current_time = get_current_time(reader);
@@ -122,7 +162,7 @@ static DWORD WINAPI stream_thread(void *arg) } }
- if (reader->running) + if (reader->state == STATE_RUNNING) { LeaveCriticalSection(&reader->stream_cs); if (stream->read_compressed) @@ -139,8 +179,6 @@ static DWORD WINAPI stream_thread(void *arg) INSSBuffer_Release(sample); }
- LeaveCriticalSection(&reader->stream_cs); - if (hr == NS_E_NO_MORE_SAMPLES) { IWMReaderCallback_OnStatus(callback, WMT_END_OF_STREAMING, S_OK, @@ -163,22 +201,68 @@ static DWORD WINAPI stream_thread(void *arg) { ERR("Failed to get sample, hr %#lx.\n", hr); } +} + +static DWORD WINAPI stream_thread(void *arg) +{ + struct async_reader *reader = arg; + IWMReaderCallback *callback = reader->callback; + IWMReaderCallbackAdvanced *callback_advanced; + HRESULT hr = S_OK; + + EnterCriticalSection(&reader->stream_cs); + + if (FAILED(hr = IWMReaderCallback_QueryInterface(callback, + &IID_IWMReaderCallbackAdvanced, (void **)&callback_advanced))) + callback_advanced = NULL; + TRACE("Querying for IWMReaderCallbackAdvanced returned %#lx.\n", hr); + + while (reader->state != STATE_CLOSED || reader->next_state) + { + execute_state_transition(reader); + + if (reader->state == STATE_RUNNING) + { + stream_thread_running(reader, callback_advanced); + if (!reader->next_state) + reader->state = STATE_STOPPED; + } + + while (reader->state != STATE_CLOSED && !reader->next_state) + SleepConditionVariableCS(&reader->stream_cv, &reader->stream_cs, INFINITE); + }
if (callback_advanced) IWMReaderCallbackAdvanced_Release(callback_advanced);
+ LeaveCriticalSection(&reader->stream_cs); + TRACE("Reader is stopping; exiting.\n"); return 0; }
-static void stop_streaming(struct async_reader *reader) +static HRESULT open_stream(struct async_reader *reader, IWMReaderCallback *callback, void *context) +{ + IWMReaderCallback_AddRef((reader->callback = callback)); + reader->context = context; + reader->state = STATE_CLOSED; + reader->next_state = STATE_STOPPED; + + if (!(reader->stream_thread = CreateThread(NULL, 0, stream_thread, reader, 0, NULL))) + { + IWMReaderCallback_Release(reader->callback); + reader->callback = NULL; + reader->context = NULL; + return E_OUTOFMEMORY; + } + + return S_OK; +} + +static void close_stream(struct async_reader *reader) { if (reader->stream_thread) { - EnterCriticalSection(&reader->stream_cs); - reader->running = false; - LeaveCriticalSection(&reader->stream_cs); - WakeConditionVariable(&reader->stream_cv); WaitForSingleObject(reader->stream_thread, INFINITE); CloseHandle(reader->stream_thread); reader->stream_thread = NULL; @@ -229,8 +313,9 @@ static HRESULT WINAPI WMReader_Open(IWMReader *iface, const WCHAR *url, return E_UNEXPECTED; }
- if (SUCCEEDED(hr = wm_reader_open_file(&reader->reader, url))) - open_stream(reader, callback, context); + if (SUCCEEDED(hr = wm_reader_open_file(&reader->reader, url)) + && FAILED(hr = open_stream(reader, callback, context))) + wm_reader_close(&reader->reader);
LeaveCriticalSection(&reader->reader.cs); return hr; @@ -239,22 +324,21 @@ static HRESULT WINAPI WMReader_Open(IWMReader *iface, const WCHAR *url, static HRESULT WINAPI WMReader_Close(IWMReader *iface) { struct async_reader *reader = impl_from_IWMReader(iface); - static const DWORD zero; HRESULT hr;
TRACE("reader %p.\n", reader);
EnterCriticalSection(&reader->reader.cs);
- stop_streaming(reader); + EnterCriticalSection(&reader->stream_cs); + request_state_transition(reader, STATE_CLOSED); + LeaveCriticalSection(&reader->stream_cs); + + close_stream(reader);
hr = wm_reader_close(&reader->reader); if (reader->callback) - { - IWMReaderCallback_OnStatus(reader->callback, WMT_CLOSED, S_OK, - WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); IWMReaderCallback_Release(reader->callback); - } reader->callback = NULL;
LeaveCriticalSection(&reader->reader.cs); @@ -315,7 +399,6 @@ static HRESULT WINAPI WMReader_Start(IWMReader *iface, QWORD start, QWORD duration, float rate, void *context) { struct async_reader *reader = impl_from_IWMReader(iface); - static const DWORD zero;
TRACE("reader %p, start %s, duration %s, rate %.8e, context %p.\n", reader, debugstr_time(start), debugstr_time(duration), rate, context); @@ -332,24 +415,14 @@ static HRESULT WINAPI WMReader_Start(IWMReader *iface, return NS_E_INVALID_REQUEST; }
- stop_streaming(reader); - - IWMReaderCallback_OnStatus(reader->callback, WMT_STARTED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context); - reader->context = context; - + EnterCriticalSection(&reader->stream_cs); wm_reader_seek(&reader->reader, start, duration); - - reader->running = true; + reader->context = context; reader->user_time = 0; - - if (!(reader->stream_thread = CreateThread(NULL, 0, stream_thread, reader, 0, NULL))) - { - LeaveCriticalSection(&reader->reader.cs); - return E_OUTOFMEMORY; - } + request_state_transition(reader, STATE_RUNNING); + LeaveCriticalSection(&reader->stream_cs);
LeaveCriticalSection(&reader->reader.cs); - WakeConditionVariable(&reader->stream_cv);
return S_OK; } @@ -357,7 +430,6 @@ static HRESULT WINAPI WMReader_Start(IWMReader *iface, static HRESULT WINAPI WMReader_Stop(IWMReader *iface) { struct async_reader *reader = impl_from_IWMReader(iface); - static const DWORD zero;
TRACE("reader %p.\n", reader);
@@ -370,9 +442,10 @@ static HRESULT WINAPI WMReader_Stop(IWMReader *iface) return E_UNEXPECTED; }
- stop_streaming(reader); - IWMReaderCallback_OnStatus(reader->callback, WMT_STOPPED, S_OK, - WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + EnterCriticalSection(&reader->stream_cs); + request_state_transition(reader, STATE_STOPPED); + LeaveCriticalSection(&reader->stream_cs); + LeaveCriticalSection(&reader->reader.cs); return S_OK; } @@ -732,8 +805,9 @@ static HRESULT WINAPI WMReaderAdvanced2_OpenStream(IWMReaderAdvanced6 *iface, return E_UNEXPECTED; }
- if (SUCCEEDED(hr = wm_reader_open_stream(&reader->reader, stream))) - open_stream(reader, callback, context); + if (SUCCEEDED(hr = wm_reader_open_stream(&reader->reader, stream)) + && FAILED(hr = open_stream(reader, callback, context))) + wm_reader_close(&reader->reader);
LeaveCriticalSection(&reader->reader.cs); return hr; @@ -1588,11 +1662,13 @@ static void async_reader_destroy(struct wm_reader *iface)
TRACE("reader %p.\n", reader);
- if (reader->stream_thread) - { - WaitForSingleObject(reader->stream_thread, INFINITE); - CloseHandle(reader->stream_thread); - } + EnterCriticalSection(&reader->stream_cs); + reader->state = STATE_CLOSED; + reader->next_state = 0; + LeaveCriticalSection(&reader->stream_cs); + WakeConditionVariable(&reader->stream_cv); + + close_stream(reader);
reader->stream_cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&reader->stream_cs); diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 987f5def75a..510b9d0bb5a 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1496,7 +1496,6 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta ok(!*(DWORD *)value, "Got value %#lx.\n", *(DWORD *)value); ok(context == (void *)0xdeadbeef, "Got unexpected context %p.\n", context); ret = WaitForSingleObject(callback->expect_opened, 100); - todo_wine ok(!ret, "Wait timed out.\n"); SetEvent(callback->got_opened); break; @@ -1506,7 +1505,6 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta ok(!*(DWORD *)value, "Got value %#lx.\n", *(DWORD *)value); ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context); ret = WaitForSingleObject(callback->expect_started, 100); - todo_wine ok(!ret, "Wait timed out.\n"); callback->got_end_of_streaming = callback->got_eof = callback->got_sample = 0; SetEvent(callback->got_started); @@ -1518,7 +1516,6 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta ok(!*(DWORD *)value, "Got value %#lx.\n", *(DWORD *)value); ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context); ret = WaitForSingleObject(callback->expect_stopped, 100); - todo_wine ok(!ret, "Wait timed out.\n"); SetEvent(callback->got_stopped); break; @@ -1890,14 +1887,10 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback->got_started, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback->expect_started); - ret = WaitForSingleObject(callback->got_started, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback->expect_started); + ret = WaitForSingleObject(callback->got_started, 1000); + ok(!ret, "Wait timed out.\n");
hr = IWMReaderAdvanced2_SetUserProvidedClock(advanced, TRUE); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1911,14 +1904,10 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st hr = IWMReader_Stop(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback->got_stopped, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STOPPED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback->expect_stopped); - ret = WaitForSingleObject(callback->got_stopped, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback->expect_stopped); + ret = WaitForSingleObject(callback->got_stopped, 1000); + ok(!ret, "Wait timed out.\n");
ok(!outstanding_buffers, "Got %ld outstanding buffers.\n", outstanding_buffers); } @@ -2217,14 +2206,10 @@ static void test_async_reader_streaming(void) ok(stream.refcount > 1, "Got refcount %ld.\n", stream.refcount); ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount); ret = WaitForSingleObject(callback.got_opened, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_OPENED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_opened); - ret = WaitForSingleObject(callback.got_opened, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_opened); + ret = WaitForSingleObject(callback.got_opened, 1000); + ok(!ret, "Wait timed out.\n");
hr = IWMReaderAdvanced2_OpenStream(advanced, &stream.IStream_iface, &callback.IWMReaderCallback_iface, (void **)0xdeadbee0); ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr); @@ -2251,14 +2236,10 @@ static void test_async_reader_streaming(void) hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback.got_started, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_started); - ret = WaitForSingleObject(callback.got_started, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_started); + ret = WaitForSingleObject(callback.got_started, 1000); + ok(!ret, "Wait timed out.\n");
/* By default the reader will time itself, and attempt to deliver samples * according to their presentation time. Call DeliverTime with the file @@ -2290,14 +2271,10 @@ static void test_async_reader_streaming(void) hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback.got_started, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_started); - ret = WaitForSingleObject(callback.got_started, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_started); + ret = WaitForSingleObject(callback.got_started, 1000); + ok(!ret, "Wait timed out.\n");
hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -2309,26 +2286,18 @@ static void test_async_reader_streaming(void) hr = IWMReader_Stop(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback.got_stopped, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STOPPED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_stopped); - ret = WaitForSingleObject(callback.got_stopped, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_stopped); + ret = WaitForSingleObject(callback.got_stopped, 1000); + ok(!ret, "Wait timed out.\n");
hr = IWMReader_Stop(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback.got_stopped, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STOPPED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_stopped); - ret = WaitForSingleObject(callback.got_stopped, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_stopped); + ret = WaitForSingleObject(callback.got_stopped, 1000); + ok(!ret, "Wait timed out.\n");
test_reader_attributes(profile); test_async_reader_selection(reader, advanced, &callback); @@ -2397,14 +2366,10 @@ static void test_async_reader_types(void) ok(stream.refcount > 1, "Got refcount %ld.\n", stream.refcount); ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount); ret = WaitForSingleObject(callback.got_opened, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_OPENED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_opened); - ret = WaitForSingleObject(callback.got_opened, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_opened); + ret = WaitForSingleObject(callback.got_opened, 1000); + ok(!ret, "Wait timed out.\n");
for (i = 0; i < 2; ++i) { @@ -2627,14 +2592,10 @@ static void test_async_reader_file(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(callback.refcount > 1, "Got refcount %ld.\n", callback.refcount); ret = WaitForSingleObject(callback.got_opened, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_OPENED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_opened); - ret = WaitForSingleObject(callback.got_opened, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_opened); + ret = WaitForSingleObject(callback.got_opened, 1000); + ok(!ret, "Wait timed out.\n");
hr = IWMReader_Open(reader, filename, &callback.IWMReaderCallback_iface, (void **)0xdeadbee0); ok(hr == E_UNEXPECTED, "Got hr %#lx.\n", hr); @@ -2647,14 +2608,10 @@ static void test_async_reader_file(void) hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade); ok(hr == S_OK, "Got hr %#lx.\n", hr); ret = WaitForSingleObject(callback.got_started, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "Got unexpected WMT_STARTED.\n"); - if (ret == WAIT_TIMEOUT) - { - SetEvent(callback.expect_started); - ret = WaitForSingleObject(callback.got_started, 1000); - ok(!ret, "Wait timed out.\n"); - } + SetEvent(callback.expect_started); + ret = WaitForSingleObject(callback.got_started, 1000); + ok(!ret, "Wait timed out.\n");
hr = IWMReader_Close(reader); ok(hr == S_OK, "Got hr %#lx.\n", hr);