Signed-off-by: Anton Baskanov <baskanov(a)gmail.com>
---
dlls/amstream/ddrawstream.c | 31 +++-
dlls/amstream/tests/amstream.c | 280 +++++++++++++++++++++++++++++++++
2 files changed, 308 insertions(+), 3 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c
index 972c2b9f4d0..9020828f578 100644
--- a/dlls/amstream/ddrawstream.c
+++ b/dlls/amstream/ddrawstream.c
@@ -1491,6 +1491,7 @@ static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface,
}
if (!sample->parent->peer || sample->parent->eos)
{
+ sample->update_hr = MS_S_ENDOFSTREAM;
LeaveCriticalSection(&sample->parent->cs);
return MS_S_ENDOFSTREAM;
}
@@ -1517,9 +1518,33 @@ static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface,
static HRESULT WINAPI ddraw_sample_CompletionStatus(IDirectDrawStreamSample *iface, DWORD flags, DWORD milliseconds)
{
- FIXME("(%p)->(%x,%u): stub\n", iface, flags, milliseconds);
+ struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
+ HRESULT hr;
- return E_NOTIMPL;
+ TRACE("sample %p, flags %#x, milliseconds %u.\n", sample, flags, milliseconds);
+
+ EnterCriticalSection(&sample->parent->cs);
+
+ if (sample->update_hr == MS_S_PENDING)
+ {
+ if (flags & (COMPSTAT_NOUPDATEOK | COMPSTAT_ABORT))
+ {
+ sample->update_hr = MS_S_NOUPDATE;
+ remove_queued_update(sample);
+ }
+ else if (flags & COMPSTAT_WAIT)
+ {
+ LeaveCriticalSection(&sample->parent->cs);
+ WaitForSingleObject(sample->update_event, milliseconds);
+ EnterCriticalSection(&sample->parent->cs);
+ }
+ }
+
+ hr = sample->update_hr;
+
+ LeaveCriticalSection(&sample->parent->cs);
+
+ return hr;
}
/*** IDirectDrawStreamSample methods ***/
@@ -1583,7 +1608,7 @@ static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDraw
object->IDirectDrawStreamSample_iface.lpVtbl = &DirectDrawStreamSample_Vtbl;
object->ref = 1;
object->parent = parent;
- object->update_event = CreateEventW(NULL, FALSE, FALSE, NULL);
+ object->update_event = CreateEventW(NULL, TRUE, TRUE, NULL);
IAMMediaStream_AddRef(&parent->IAMMediaStream_iface);
++parent->sample_refs;
diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c
index e5d1dd621f3..44debac2333 100644
--- a/dlls/amstream/tests/amstream.c
+++ b/dlls/amstream/tests/amstream.c
@@ -4028,6 +4028,21 @@ static DWORD CALLBACK ammediastream_receive(void *param)
return 0;
}
+static IStreamSample *streamsample_sample;
+static DWORD streamsample_flags;
+static DWORD streamsample_timeout;
+static HRESULT streamsample_expected_hr;
+
+static DWORD CALLBACK streamsample_completion_status(void *param)
+{
+ HRESULT hr;
+
+ hr = IStreamSample_CompletionStatus(streamsample_sample, streamsample_flags, streamsample_timeout);
+ ok(hr == streamsample_expected_hr, "Got hr %#x.\n", hr);
+
+ return 0;
+}
+
static void test_audiostreamsample_update(void)
{
static const BYTE test_data[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
@@ -7221,6 +7236,270 @@ static void test_ddrawstreamsample_update(void)
ok(!ref, "Got outstanding refcount %d.\n", ref);
}
+static void test_ddrawstreamsample_completion_status(void)
+{
+ static const BYTE test_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+ IAMMultiMediaStream *mmstream = create_ammultimediastream();
+ IDirectDrawStreamSample *stream_sample1;
+ IDirectDrawStreamSample *stream_sample2;
+ IDirectDrawMediaStream *ddraw_stream;
+ IMediaSample *media_sample;
+ IMediaFilter *media_filter;
+ struct testfilter source;
+ VIDEOINFO video_info;
+ IGraphBuilder *graph;
+ IMediaStream *stream;
+ AM_MEDIA_TYPE mt;
+ HANDLE thread;
+ HRESULT hr;
+ ULONG ref;
+ IPin *pin;
+
+ hr = IAMMultiMediaStream_Initialize(mmstream, STREAMTYPE_READ, 0, NULL);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IAMMultiMediaStream_AddMediaStream(mmstream, NULL, &MSPID_PrimaryVideo, 0, &stream);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IMediaStream_QueryInterface(stream, &IID_IDirectDrawMediaStream, (void **)&ddraw_stream);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IMediaStream_QueryInterface(stream, &IID_IPin, (void **)&pin);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IAMMultiMediaStream_GetFilterGraph(mmstream, &graph);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(graph != NULL, "Expected non-NULL graph.\n");
+ hr = IGraphBuilder_QueryInterface(graph, &IID_IMediaFilter, (void **)&media_filter);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ testfilter_init(&source);
+ hr = IGraphBuilder_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaFilter_SetSyncSource(media_filter, NULL);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ video_info = rgb32_video_info;
+ video_info.bmiHeader.biWidth = 3;
+ video_info.bmiHeader.biHeight = 1;
+ mt = rgb32_mt;
+ mt.pbFormat = (BYTE *)&video_info;
+ hr = IGraphBuilder_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &mt);
+ 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 = IDirectDrawMediaStream_CreateSample(ddraw_stream, NULL, NULL, 0, &stream_sample1);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IDirectDrawMediaStream_CreateSample(ddraw_stream, NULL, NULL, 0, &stream_sample2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_WAIT, INFINITE);
+ 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);
+
+ hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
+ ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
+
+ hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_WAIT, 100);
+ ok(hr == MS_S_PENDING, "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_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 == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_WAIT, INFINITE);
+ ok(hr == S_OK, "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_sample2, 0, 0);
+ 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);
+
+ 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, COMPSTAT_NOUPDATEOK, 0);
+ ok(hr == MS_S_NOUPDATE, "Got hr %#x.\n", hr);
+
+ hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_WAIT, INFINITE);
+ ok(hr == MS_S_NOUPDATE, "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_NOUPDATE, "Got hr %#x.\n", hr);
+
+ hr = IDirectDrawStreamSample_CompletionStatus(stream_sample2, 0, 0);
+ 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);
+
+ 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, COMPSTAT_ABORT, 0);
+ ok(hr == MS_S_NOUPDATE, "Got hr %#x.\n", hr);
+
+ hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_WAIT, INFINITE);
+ ok(hr == MS_S_NOUPDATE, "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_NOUPDATE, "Got hr %#x.\n", hr);
+
+ hr = IDirectDrawStreamSample_CompletionStatus(stream_sample2, 0, 0);
+ 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);
+
+ 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 = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_WAIT, INFINITE);
+ ok(hr == MS_S_ENDOFSTREAM, "Got hr %#x.\n", hr);
+
+ hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC, NULL, NULL, 0);
+ ok(hr == MS_S_ENDOFSTREAM, "Got hr %#x.\n", hr);
+
+ hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
+ ok(hr == MS_S_ENDOFSTREAM, "Got hr %#x.\n", hr);
+
+ hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_WAIT, INFINITE);
+ 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, 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_Update(stream_sample1, SSUPDATE_ASYNC, 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 = MS_S_ENDOFSTREAM;
+ thread = CreateThread(NULL, 0, streamsample_completion_status, NULL, 0, NULL);
+ ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "CompletionStatus returned prematurely.\n");
+
+ hr = IPin_EndOfStream(pin);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ ok(!WaitForSingleObject(thread, 2000), "Wait timed out.\n");
+ CloseHandle(thread);
+
+ 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);
+
+ 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);
+
+ media_sample = ammediastream_allocate_sample(&source, test_data, 6);
+ 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 = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC, NULL, NULL, 0);
+ ok(hr == MS_E_NOTRUNNING, "Got hr %#x.\n", hr);
+
+ hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_WAIT, INFINITE);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ IGraphBuilder_Disconnect(graph, pin);
+ IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface);
+
+ ref = IDirectDrawStreamSample_Release(stream_sample1);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ ref = IDirectDrawStreamSample_Release(stream_sample2);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ ref = IAMMultiMediaStream_Release(mmstream);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ IMediaFilter_Release(media_filter);
+ ref = IGraphBuilder_Release(graph);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ IPin_Release(pin);
+ IDirectDrawMediaStream_Release(ddraw_stream);
+ ref = IMediaStream_Release(stream);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+}
+
START_TEST(amstream)
{
const WCHAR *test_avi_path;
@@ -7276,6 +7555,7 @@ START_TEST(amstream)
test_ddrawstreamsample_get_media_stream();
test_ddrawstreamsample_update();
+ test_ddrawstreamsample_completion_status();
test_ammediastream_join_am_multi_media_stream();
test_ammediastream_join_filter();
--
2.17.1