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);