amstream: Implement SSUPDATE_CONTINUOUS flag in IDirectDrawStreamSample::Update.

Signed-off-by: Anton Baskanov <baskanov@gmail.com>
Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Anton Baskanov 2020-10-10 03:57:54 +07:00 committed by Alexandre Julliard
parent 4ced409adb
commit aaf461b7d2
2 changed files with 247 additions and 14 deletions

View file

@ -75,10 +75,12 @@ struct ddraw_sample
RECT rect; RECT rect;
STREAM_TIME start_time; STREAM_TIME start_time;
STREAM_TIME end_time; STREAM_TIME end_time;
BOOL continuous_update;
CONDITION_VARIABLE update_cv; CONDITION_VARIABLE update_cv;
struct list entry; struct list entry;
HRESULT update_hr; HRESULT update_hr;
BOOL busy;
}; };
static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface, static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface,
@ -86,6 +88,7 @@ static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDraw
static void remove_queued_update(struct ddraw_sample *sample) static void remove_queued_update(struct ddraw_sample *sample)
{ {
sample->busy = FALSE;
list_remove(&sample->entry); list_remove(&sample->entry);
WakeConditionVariable(&sample->update_cv); WakeConditionVariable(&sample->update_cv);
} }
@ -1348,7 +1351,16 @@ static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample *
sample->update_hr = process_update(sample, top_down_stride, top_down_pointer, sample->update_hr = process_update(sample, top_down_stride, top_down_pointer,
start_stream_time, end_stream_time); start_stream_time, end_stream_time);
remove_queued_update(sample); if (sample->continuous_update && SUCCEEDED(sample->update_hr))
{
list_remove(&sample->entry);
list_add_tail(&sample->parent->update_queue, &sample->entry);
}
else
{
remove_queued_update(sample);
}
LeaveCriticalSection(&stream->cs); LeaveCriticalSection(&stream->cs);
return S_OK; return S_OK;
} }
@ -1540,12 +1552,6 @@ static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface,
return E_NOTIMPL; return E_NOTIMPL;
} }
if (flags & ~SSUPDATE_ASYNC)
{
FIXME("Unsupported flags %#x.\n", flags);
return E_NOTIMPL;
}
EnterCriticalSection(&sample->parent->cs); EnterCriticalSection(&sample->parent->cs);
if (sample->parent->state != State_Running) if (sample->parent->state != State_Running)
@ -1559,13 +1565,16 @@ static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface,
LeaveCriticalSection(&sample->parent->cs); LeaveCriticalSection(&sample->parent->cs);
return MS_S_ENDOFSTREAM; return MS_S_ENDOFSTREAM;
} }
if (MS_S_PENDING == sample->update_hr) if (sample->busy)
{ {
LeaveCriticalSection(&sample->parent->cs); LeaveCriticalSection(&sample->parent->cs);
return MS_E_BUSY; return MS_E_BUSY;
} }
sample->update_hr = MS_S_PENDING; sample->continuous_update = (flags & SSUPDATE_ASYNC) && (flags & SSUPDATE_CONTINUOUS);
sample->update_hr = MS_S_NOUPDATE;
sample->busy = TRUE;
list_add_tail(&sample->parent->update_queue, &sample->entry); list_add_tail(&sample->parent->update_queue, &sample->entry);
WakeConditionVariable(&sample->parent->update_queued_cv); WakeConditionVariable(&sample->parent->update_queued_cv);
@ -1575,7 +1584,7 @@ static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface,
return MS_S_PENDING; return MS_S_PENDING;
} }
while (sample->update_hr == MS_S_PENDING) while (sample->busy)
SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, INFINITE); SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, INFINITE);
LeaveCriticalSection(&sample->parent->cs); LeaveCriticalSection(&sample->parent->cs);
@ -1592,18 +1601,18 @@ static HRESULT WINAPI ddraw_sample_CompletionStatus(IDirectDrawStreamSample *ifa
EnterCriticalSection(&sample->parent->cs); EnterCriticalSection(&sample->parent->cs);
if (sample->update_hr == MS_S_PENDING) if (sample->busy)
{ {
if (flags & (COMPSTAT_NOUPDATEOK | COMPSTAT_ABORT)) if (flags & (COMPSTAT_NOUPDATEOK | COMPSTAT_ABORT))
{ {
sample->update_hr = MS_S_NOUPDATE;
remove_queued_update(sample); remove_queued_update(sample);
} }
else if (flags & COMPSTAT_WAIT) else if (flags & COMPSTAT_WAIT)
{ {
DWORD start_time = GetTickCount(); DWORD start_time = GetTickCount();
DWORD elapsed = 0; DWORD elapsed = 0;
while (sample->update_hr == MS_S_PENDING && elapsed < milliseconds) sample->continuous_update = FALSE;
while (sample->busy && elapsed < milliseconds)
{ {
DWORD sleep_time = milliseconds - elapsed; DWORD sleep_time = milliseconds - elapsed;
if (!SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, sleep_time)) if (!SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, sleep_time))
@ -1613,7 +1622,7 @@ static HRESULT WINAPI ddraw_sample_CompletionStatus(IDirectDrawStreamSample *ifa
} }
} }
hr = sample->update_hr; hr = sample->busy ? MS_S_PENDING : sample->update_hr;
LeaveCriticalSection(&sample->parent->cs); LeaveCriticalSection(&sample->parent->cs);

View file

@ -7440,6 +7440,96 @@ static void test_ddrawstreamsample_update(void)
hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
ok(hr == S_OK, "Got hr %#x.\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawSurface_Lock(surface, NULL, &desc, 0, NULL);
ok(hr == S_OK, "Got hr %#x.\n", hr);
for (i = 0; i < 5; ++i)
memcpy((BYTE *)desc.lpSurface + i * desc.lPitch, initial_data, 12);
hr = IDirectDrawSurface_Unlock(surface, desc.lpSurface);
ok(hr == S_OK, "Got hr %#x.\n", hr);
media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data));
ammediastream_mem_input_pin = mem_input_pin;
ammediastream_media_sample = media_sample;
ammediastream_sleep_time = 100;
ammediastream_expected_hr = S_OK;
thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
hr = IDirectDrawStreamSample_Update(stream_sample, SSUPDATE_CONTINUOUS, NULL, NULL, 0);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawSurface_Lock(surface, NULL, &desc, 0, NULL);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(memcmp((BYTE *)desc.lpSurface + 0 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n");
ok(memcmp((BYTE *)desc.lpSurface + 1 * desc.lPitch, &test_data[12], 12) == 0, "Sample data didn't match.\n");
ok(memcmp((BYTE *)desc.lpSurface + 2 * desc.lPitch, &test_data[0], 12) == 0, "Sample data didn't match.\n");
ok(memcmp((BYTE *)desc.lpSurface + 3 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n");
ok(memcmp((BYTE *)desc.lpSurface + 4 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n");
hr = IDirectDrawSurface_Unlock(surface, desc.lpSurface);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(!WaitForSingleObject(thread, 2000), "Wait timed out.\n");
CloseHandle(thread);
ref = IMediaSample_Release(media_sample);
ok(!ref, "Got outstanding refcount %d.\n", ref);
hr = IDirectDrawStreamSample_Update(stream_sample, SSUPDATE_ASYNC | SSUPDATE_CONTINUOUS, NULL, NULL, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
hr = IDirectDrawSurface_Lock(surface, NULL, &desc, 0, NULL);
ok(hr == S_OK, "Got hr %#x.\n", hr);
for (i = 0; i < 5; ++i)
memcpy((BYTE *)desc.lpSurface + i * desc.lPitch, initial_data, 12);
hr = IDirectDrawSurface_Unlock(surface, desc.lpSurface);
ok(hr == S_OK, "Got hr %#x.\n", hr);
media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data));
hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ref = IMediaSample_Release(media_sample);
ok(!ref, "Got outstanding refcount %d.\n", ref);
hr = IDirectDrawSurface_Lock(surface, NULL, &desc, 0, NULL);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(memcmp((BYTE *)desc.lpSurface + 0 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n");
ok(memcmp((BYTE *)desc.lpSurface + 1 * desc.lPitch, &test_data[12], 12) == 0, "Sample data didn't match.\n");
ok(memcmp((BYTE *)desc.lpSurface + 2 * desc.lPitch, &test_data[0], 12) == 0, "Sample data didn't match.\n");
ok(memcmp((BYTE *)desc.lpSurface + 3 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n");
ok(memcmp((BYTE *)desc.lpSurface + 4 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n");
hr = IDirectDrawSurface_Unlock(surface, desc.lpSurface);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawSurface_Lock(surface, NULL, &desc, 0, NULL);
ok(hr == S_OK, "Got hr %#x.\n", hr);
for (i = 0; i < 5; ++i)
memcpy((BYTE *)desc.lpSurface + i * desc.lPitch, initial_data, 12);
hr = IDirectDrawSurface_Unlock(surface, desc.lpSurface);
ok(hr == S_OK, "Got hr %#x.\n", hr);
media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data));
hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ref = IMediaSample_Release(media_sample);
ok(!ref, "Got outstanding refcount %d.\n", ref);
hr = IDirectDrawSurface_Lock(surface, NULL, &desc, 0, NULL);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(memcmp((BYTE *)desc.lpSurface + 0 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n");
ok(memcmp((BYTE *)desc.lpSurface + 1 * desc.lPitch, &test_data[12], 12) == 0, "Sample data didn't match.\n");
ok(memcmp((BYTE *)desc.lpSurface + 2 * desc.lPitch, &test_data[0], 12) == 0, "Sample data didn't match.\n");
ok(memcmp((BYTE *)desc.lpSurface + 3 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n");
ok(memcmp((BYTE *)desc.lpSurface + 4 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n");
hr = IDirectDrawSurface_Unlock(surface, desc.lpSurface);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IPin_EndOfStream(pin);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_Update(stream_sample, SSUPDATE_ASYNC, NULL, NULL, 0); hr = IDirectDrawStreamSample_Update(stream_sample, SSUPDATE_ASYNC, NULL, NULL, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr); ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
EXPECT_REF(stream_sample, 1); EXPECT_REF(stream_sample, 1);
@ -7665,6 +7755,140 @@ static void test_ddrawstreamsample_completion_status(void)
hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
ok(hr == S_OK, "Got hr %#x.\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC | SSUPDATE_CONTINUOUS, NULL, NULL, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_NOUPDATEOK, 0);
ok(hr == MS_S_NOUPDATE, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC | SSUPDATE_CONTINUOUS, NULL, NULL, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_ABORT, 0);
ok(hr == MS_S_NOUPDATE, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC | SSUPDATE_CONTINUOUS, NULL, NULL, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC | SSUPDATE_CONTINUOUS, NULL, NULL, 0);
ok(hr == MS_E_BUSY, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC, NULL, NULL, 0);
ok(hr == MS_E_BUSY, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_Update(stream_sample2, SSUPDATE_ASYNC, NULL, NULL, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data));
hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ref = IMediaSample_Release(media_sample);
ok(!ref, "Got outstanding refcount %d.\n", ref);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample2, 0, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data));
hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ref = IMediaSample_Release(media_sample);
ok(!ref, "Got outstanding refcount %d.\n", ref);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample2, 0, 0);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_NOUPDATEOK, 0);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC | SSUPDATE_CONTINUOUS, NULL, NULL, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
hr = IPin_BeginFlush(pin);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
hr = IPin_EndFlush(pin);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
hr = IPin_EndOfStream(pin);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
ok(hr == MS_S_ENDOFSTREAM, "Got hr %#x.\n", hr);
hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC | SSUPDATE_CONTINUOUS, NULL, NULL, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_WAIT, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data));
hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ref = IMediaSample_Release(media_sample);
ok(!ref, "Got outstanding refcount %d.\n", ref);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC | SSUPDATE_CONTINUOUS, NULL, NULL, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
streamsample_sample = (IStreamSample *)stream_sample1;
streamsample_flags = COMPSTAT_WAIT;
streamsample_timeout = INFINITE;
streamsample_expected_hr = S_OK;
thread = CreateThread(NULL, 0, streamsample_completion_status, NULL, 0, NULL);
ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "CompletionStatus returned prematurely.\n");
media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data));
hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample);
ok(hr == S_OK, "Got hr %#x.\n", hr);
ref = IMediaSample_Release(media_sample);
ok(!ref, "Got outstanding refcount %d.\n", ref);
ok(!WaitForSingleObject(thread, 2000), "Wait timed out.\n");
CloseHandle(thread);
hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC, NULL, NULL, 0); hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC, NULL, NULL, 0);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr); ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);