Signed-off-by: Anton Baskanov <baskanov(a)gmail.com>
---
dlls/amstream/ddrawstream.c | 37 +++---
dlls/amstream/tests/amstream.c | 224 +++++++++++++++++++++++++++++++++
2 files changed, 247 insertions(+), 14 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c
index 5e6e1555d7c..190034fa008 100644
--- a/dlls/amstream/ddrawstream.c
+++ b/dlls/amstream/ddrawstream.c
@@ -75,10 +75,12 @@ struct ddraw_sample
RECT rect;
STREAM_TIME start_time;
STREAM_TIME end_time;
+ BOOL continuous_update;
CONDITION_VARIABLE update_cv;
struct list entry;
HRESULT update_hr;
+ BOOL busy;
};
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)
{
+ sample->busy = FALSE;
list_remove(&sample->entry);
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,
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);
return S_OK;
}
@@ -1540,12 +1552,6 @@ static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface,
return E_NOTIMPL;
}
- if (flags & ~SSUPDATE_ASYNC)
- {
- FIXME("Unsupported flags %#x.\n", flags);
- return E_NOTIMPL;
- }
-
EnterCriticalSection(&sample->parent->cs);
if (sample->parent->state != State_Running)
@@ -1559,13 +1565,16 @@ static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface,
LeaveCriticalSection(&sample->parent->cs);
return MS_S_ENDOFSTREAM;
}
- if (MS_S_PENDING == sample->update_hr)
+ if (sample->busy)
{
LeaveCriticalSection(&sample->parent->cs);
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);
WakeConditionVariable(&sample->parent->update_queued_cv);
@@ -1575,7 +1584,7 @@ static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface,
return MS_S_PENDING;
}
- while (sample->update_hr == MS_S_PENDING)
+ while (sample->busy)
SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, INFINITE);
LeaveCriticalSection(&sample->parent->cs);
@@ -1592,18 +1601,18 @@ static HRESULT WINAPI ddraw_sample_CompletionStatus(IDirectDrawStreamSample *ifa
EnterCriticalSection(&sample->parent->cs);
- if (sample->update_hr == MS_S_PENDING)
+ if (sample->busy)
{
if (flags & (COMPSTAT_NOUPDATEOK | COMPSTAT_ABORT))
{
- sample->update_hr = MS_S_NOUPDATE;
remove_queued_update(sample);
}
else if (flags & COMPSTAT_WAIT)
{
DWORD start_time = GetTickCount();
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;
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);
diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c
index 9dda5882a4f..b436840e407 100644
--- a/dlls/amstream/tests/amstream.c
+++ b/dlls/amstream/tests/amstream.c
@@ -7440,6 +7440,96 @@ static void test_ddrawstreamsample_update(void)
hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
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);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
EXPECT_REF(stream_sample, 1);
@@ -7665,6 +7755,140 @@ static void test_ddrawstreamsample_completion_status(void)
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_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);
ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
--
2.17.1