Signed-off-by: Anton Baskanov baskanov@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();
Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/amstream/ddrawstream.c | 28 +++++- dlls/amstream/tests/amstream.c | 155 ++++++++++++++++++++++++++++++++- 2 files changed, 177 insertions(+), 6 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index 9020828f578..4bd1aa230b4 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -70,6 +70,8 @@ struct ddraw_sample struct ddraw_stream *parent; IDirectDrawSurface *surface; RECT rect; + STREAM_TIME start_time; + STREAM_TIME end_time; HANDLE update_event;
struct list entry; @@ -96,7 +98,8 @@ static void flush_update_queue(struct ddraw_stream *stream, HRESULT update_hr) } }
-static HRESULT process_update(struct ddraw_sample *sample, int stride, BYTE *pointer) +static HRESULT process_update(struct ddraw_sample *sample, int stride, BYTE *pointer, + STREAM_TIME start_time, STREAM_TIME end_time) { DDSURFACEDESC desc; DWORD row_size; @@ -124,6 +127,9 @@ static HRESULT process_update(struct ddraw_sample *sample, int stride, BYTE *poi if (FAILED(hr)) return hr;
+ sample->start_time = start_time; + sample->end_time = end_time; + return S_OK; }
@@ -1259,6 +1265,8 @@ static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample * { struct ddraw_stream *stream = impl_from_IMemInputPin(iface); BITMAPINFOHEADER *bitmap_info; + REFERENCE_TIME start_time = 0; + REFERENCE_TIME end_time = 0; BYTE *top_down_pointer; int top_down_stride; BYTE *pointer; @@ -1272,6 +1280,8 @@ static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample * if (FAILED(hr)) return hr;
+ IMediaSample_GetTime(sample, &start_time, &end_time); + EnterCriticalSection(&stream->cs);
bitmap_info = &((VIDEOINFOHEADER *)stream->mt.pbFormat)->bmiHeader; @@ -1293,7 +1303,7 @@ static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample * { struct ddraw_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct ddraw_sample, entry);
- 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_time, end_time);
remove_queued_update(sample); LeaveCriticalSection(&stream->cs); @@ -1440,9 +1450,19 @@ static HRESULT WINAPI ddraw_sample_GetMediaStream(IDirectDrawStreamSample *iface static HRESULT WINAPI ddraw_sample_GetSampleTimes(IDirectDrawStreamSample *iface, STREAM_TIME *start_time, STREAM_TIME *end_time, STREAM_TIME *current_time) { - FIXME("(%p)->(%p,%p,%p): stub\n", iface, start_time, end_time, current_time); + struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
- return E_NOTIMPL; + TRACE("sample %p, start_time %p, end_time %p, current_time %p.\n", sample, start_time, end_time, current_time); + + if (current_time) + IMediaStreamFilter_GetCurrentStreamTime(sample->parent->filter, current_time); + + if (start_time) + *start_time = sample->start_time; + if (end_time) + *end_time = sample->end_time; + + return S_OK; }
static HRESULT WINAPI ddraw_sample_SetSampleTimes(IDirectDrawStreamSample *iface, const STREAM_TIME *start_time, diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index 44debac2333..19461d921f6 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -2986,8 +2986,8 @@ static HRESULT WINAPI testclock_GetTime(IReferenceClock *iface, REFERENCE_TIME *
static HRESULT WINAPI testclock_AdviseTime(IReferenceClock *iface, REFERENCE_TIME base, REFERENCE_TIME offset, HEVENT event, DWORD_PTR *cookie) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + SetEvent((HANDLE)event); + return S_OK; }
static HRESULT WINAPI testclock_AdvisePeriodic(IReferenceClock *iface, REFERENCE_TIME start, REFERENCE_TIME period, HSEMAPHORE semaphore, DWORD_PTR *cookie) @@ -7500,6 +7500,156 @@ static void test_ddrawstreamsample_completion_status(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
+static void test_ddrawstreamsample_get_sample_times(void) +{ + static const BYTE test_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + IAMMultiMediaStream *mmstream = create_ammultimediastream(); + IDirectDrawStreamSample *stream_sample; + IMediaFilter *graph_media_filter; + IDirectDrawMediaStream *ddraw_stream; + STREAM_TIME filter_start_time; + IMemInputPin *mem_input_pin; + IMediaStreamFilter *filter; + IMediaSample *media_sample; + struct testfilter source; + STREAM_TIME current_time; + struct testclock clock; + STREAM_TIME start_time; + STREAM_TIME end_time; + IGraphBuilder *graph; + IMediaStream *stream; + VIDEOINFO video_info; + AM_MEDIA_TYPE mt; + 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_GetFilter(mmstream, &filter); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!!filter, "Expected non-null filter.\n"); + 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 = IMediaStream_QueryInterface(stream, &IID_IMemInputPin, (void **)&mem_input_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 **)&graph_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); + testclock_init(&clock); + + 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 = IDirectDrawMediaStream_CreateSample(ddraw_stream, NULL, NULL, 0, &stream_sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + clock.time = 12345678; + + current_time = 0xdeadbeefdeadbeef; + hr = IDirectDrawStreamSample_GetSampleTimes(stream_sample, NULL, NULL, ¤t_time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(current_time == 0, "Got current time %s.\n", wine_dbgstr_longlong(current_time)); + + IMediaFilter_SetSyncSource(graph_media_filter, &clock.IReferenceClock_iface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + current_time = 0xdeadbeefdeadbeef; + hr = IDirectDrawStreamSample_GetSampleTimes(stream_sample, NULL, NULL, ¤t_time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(current_time == 0, "Got current time %s.\n", wine_dbgstr_longlong(current_time)); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMediaStreamFilter_GetCurrentStreamTime(filter, &filter_start_time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + clock.get_time_hr = E_FAIL; + + current_time = 0xdeadbeefdeadbeef; + hr = IDirectDrawStreamSample_GetSampleTimes(stream_sample, NULL, NULL, ¤t_time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(current_time == 0xdeadbeefddf15da1 + filter_start_time, "Expected current time %s, got %s.\n", + wine_dbgstr_longlong(0xdeadbeefddf15da1 + filter_start_time), wine_dbgstr_longlong(current_time)); + + clock.get_time_hr = S_OK; + + current_time = 0xdeadbeefdeadbeef; + hr = IDirectDrawStreamSample_GetSampleTimes(stream_sample, NULL, NULL, ¤t_time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(current_time == filter_start_time, "Expected current time %s, got %s.\n", + wine_dbgstr_longlong(filter_start_time), wine_dbgstr_longlong(current_time)); + + clock.time = 23456789; + + current_time = 0xdeadbeefdeadbeef; + hr = IDirectDrawStreamSample_GetSampleTimes(stream_sample, NULL, NULL, ¤t_time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(current_time == filter_start_time + 11111111, "Expected current time %s, got %s.\n", + wine_dbgstr_longlong(filter_start_time + 11111111), wine_dbgstr_longlong(current_time)); + + start_time = 0xdeadbeefdeadbeef; + end_time = 0xdeadbeefdeadbeef; + hr = IDirectDrawStreamSample_GetSampleTimes(stream_sample, &start_time, &end_time, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(start_time == 0, "Got start time %s.\n", wine_dbgstr_longlong(start_time)); + ok(end_time == 0, "Got end time %s.\n", wine_dbgstr_longlong(end_time)); + + hr = IDirectDrawStreamSample_Update(stream_sample, SSUPDATE_ASYNC, NULL, NULL, 0); + ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr); + + media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data)); + start_time = 12345678; + end_time = 23456789; + hr = IMediaSample_SetTime(media_sample, &start_time, &end_time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMemInputPin_Receive(mem_input_pin, media_sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IMediaSample_Release(media_sample); + + start_time = 0xdeadbeefdeadbeef; + end_time = 0xdeadbeefdeadbeef; + hr = IDirectDrawStreamSample_GetSampleTimes(stream_sample, &start_time, &end_time, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(start_time == 12345678, "Got start time %s.\n", wine_dbgstr_longlong(start_time)); + ok(end_time == 23456789, "Got end time %s.\n", wine_dbgstr_longlong(end_time)); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP); + 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_sample); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IAMMultiMediaStream_Release(mmstream); + ok(!ref, "Got outstanding refcount %d.\n", ref); + IMediaFilter_Release(graph_media_filter); + ref = IGraphBuilder_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IMediaStreamFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); + IPin_Release(pin); + IMemInputPin_Release(mem_input_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; @@ -7556,6 +7706,7 @@ START_TEST(amstream) test_ddrawstreamsample_get_media_stream(); test_ddrawstreamsample_update(); test_ddrawstreamsample_completion_status(); + test_ddrawstreamsample_get_sample_times();
test_ammediastream_join_am_multi_media_stream(); test_ammediastream_join_filter();
Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/amstream/ddrawstream.c | 36 ++++++++-- dlls/amstream/tests/amstream.c | 128 ++++++++++++++++++++++++++++++++- 2 files changed, 157 insertions(+), 7 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index 4bd1aa230b4..d940bf88cdc 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -59,6 +59,7 @@ struct ddraw_stream struct format format; FILTER_STATE state; BOOL eos; + BOOL flushing; CONDITION_VARIABLE update_queued_cv; struct list update_queue; }; @@ -1142,7 +1143,7 @@ static HRESULT WINAPI ddraw_sink_EndOfStream(IPin *iface)
EnterCriticalSection(&stream->cs);
- if (stream->eos) + if (stream->eos || stream->flushing) { LeaveCriticalSection(&stream->cs); return E_FAIL; @@ -1159,14 +1160,34 @@ static HRESULT WINAPI ddraw_sink_EndOfStream(IPin *iface)
static HRESULT WINAPI ddraw_sink_BeginFlush(IPin *iface) { - FIXME("iface %p, stub!\n", iface); - return E_NOTIMPL; + struct ddraw_stream *stream = impl_from_IPin(iface); + + TRACE("stream %p.\n", stream); + + EnterCriticalSection(&stream->cs); + + stream->flushing = TRUE; + stream->eos = FALSE; + WakeConditionVariable(&stream->update_queued_cv); + + LeaveCriticalSection(&stream->cs); + + return S_OK; }
static HRESULT WINAPI ddraw_sink_EndFlush(IPin *iface) { - FIXME("iface %p, stub!\n", iface); - return E_NOTIMPL; + struct ddraw_stream *stream = impl_from_IPin(iface); + + TRACE("stream %p.\n", stream); + + EnterCriticalSection(&stream->cs); + + stream->flushing = FALSE; + + LeaveCriticalSection(&stream->cs); + + return S_OK; }
static HRESULT WINAPI ddraw_sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate) @@ -1299,6 +1320,11 @@ static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample * LeaveCriticalSection(&stream->cs); return S_OK; } + if (stream->flushing) + { + LeaveCriticalSection(&stream->cs); + return S_FALSE; + } if (!list_empty(&stream->update_queue)) { struct ddraw_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct ddraw_sample, entry); diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index 19461d921f6..653c184f0b4 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -4005,6 +4005,7 @@ static IPin *ammediastream_pin; static IMemInputPin *ammediastream_mem_input_pin; static IMediaSample *ammediastream_media_sample; static DWORD ammediastream_sleep_time; +static HRESULT ammediastream_expected_hr;
static DWORD CALLBACK ammediastream_end_of_stream(void *param) { @@ -4012,7 +4013,7 @@ static DWORD CALLBACK ammediastream_end_of_stream(void *param)
Sleep(ammediastream_sleep_time); hr = IPin_EndOfStream(ammediastream_pin); - ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == ammediastream_expected_hr, "Got hr %#x.\n", hr);
return 0; } @@ -4023,7 +4024,7 @@ static DWORD CALLBACK ammediastream_receive(void *param)
Sleep(ammediastream_sleep_time); hr = IMemInputPin_Receive(ammediastream_mem_input_pin, ammediastream_media_sample); - ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == ammediastream_expected_hr, "Got hr %#x.\n", hr);
return 0; } @@ -4197,6 +4198,7 @@ static void test_audiostreamsample_update(void) ammediastream_mem_input_pin = mem_input_pin; ammediastream_media_sample = media_sample1; ammediastream_sleep_time = 100; + ammediastream_expected_hr = S_OK; thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
hr = IAudioStreamSample_Update(stream_sample, 0, NULL, NULL, 0); @@ -4216,6 +4218,7 @@ static void test_audiostreamsample_update(void)
ammediastream_pin = pin; ammediastream_sleep_time = 100; + ammediastream_expected_hr = S_OK; thread = CreateThread(NULL, 0, ammediastream_end_of_stream, NULL, 0, NULL);
hr = IAudioStreamSample_Update(stream_sample, 0, NULL, NULL, 0); @@ -5157,6 +5160,7 @@ static void test_ddrawstream_receive(void) ammediastream_mem_input_pin = source.source.pMemInputPin; ammediastream_media_sample = sample; ammediastream_sleep_time = 0; + ammediastream_expected_hr = S_OK; thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Receive returned prematurely.\n"); @@ -5196,6 +5200,121 @@ static void test_ddrawstream_receive(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
+static void test_ddrawstream_begin_flush_end_flush(void) +{ + IAMMultiMediaStream *mmstream = create_ammultimediastream(); + IDirectDrawStreamSample *stream_sample; + IDirectDrawMediaStream *ddraw_stream; + IMediaSample *media_sample; + IMediaFilter *media_filter; + struct testfilter source; + IGraphBuilder *graph; + IMediaStream *stream; + VIDEOINFO video_info; + 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 = IDirectDrawMediaStream_CreateSample(ddraw_stream, NULL, NULL, 0, &stream_sample); + 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 = BaseOutputPinImpl_GetDeliveryBuffer(&source.source, &media_sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ammediastream_mem_input_pin = source.source.pMemInputPin; + ammediastream_media_sample = media_sample; + ammediastream_sleep_time = 0; + ammediastream_expected_hr = S_FALSE; + thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL); + + hr = IPin_BeginFlush(pin); + 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 = BaseOutputPinImpl_GetDeliveryBuffer(&source.source, &media_sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + + ref = IMediaSample_Release(media_sample); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + hr = IDirectDrawStreamSample_Update(stream_sample, SSUPDATE_ASYNC, NULL, NULL, 0); + ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr); + + hr = IPin_EndOfStream(pin); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + + hr = IPin_EndFlush(pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = BaseOutputPinImpl_GetDeliveryBuffer(&source.source, &media_sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + 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 = 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); + + IGraphBuilder_Disconnect(graph, pin); + IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface); + + ref = IDirectDrawStreamSample_Release(stream_sample); + 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); +} + static void check_ammediastream_join_am_multi_media_stream(const CLSID *clsid) { IAMMultiMediaStream *mmstream = create_ammultimediastream(); @@ -7062,6 +7181,7 @@ static void test_ddrawstreamsample_update(void) ammediastream_mem_input_pin = mem_input_pin; ammediastream_media_sample = media_sample; ammediastream_sleep_time = 0; + ammediastream_expected_hr = S_OK; thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
Sleep(100); @@ -7109,6 +7229,7 @@ static void test_ddrawstreamsample_update(void) ammediastream_mem_input_pin = mem_input_pin; ammediastream_media_sample = media_sample; ammediastream_sleep_time = 0; + ammediastream_expected_hr = S_OK; thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
Sleep(100); @@ -7161,6 +7282,7 @@ static void test_ddrawstreamsample_update(void) 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, 0, NULL, NULL, 0); @@ -7183,6 +7305,7 @@ static void test_ddrawstreamsample_update(void)
ammediastream_pin = pin; ammediastream_sleep_time = 100; + ammediastream_expected_hr = S_OK; thread = CreateThread(NULL, 0, ammediastream_end_of_stream, NULL, 0, NULL);
hr = IDirectDrawStreamSample_Update(stream_sample, 0, NULL, NULL, 0); @@ -7702,6 +7825,7 @@ START_TEST(amstream) test_ddrawstream_get_format(); test_ddrawstream_set_format(); test_ddrawstream_receive(); + test_ddrawstream_begin_flush_end_flush();
test_ddrawstreamsample_get_media_stream(); test_ddrawstreamsample_update();
On 9/29/20 2:09 PM, Anton Baskanov wrote:
Signed-off-by: Anton Baskanov baskanov@gmail.com
dlls/amstream/ddrawstream.c | 36 ++++++++-- dlls/amstream/tests/amstream.c | 128 ++++++++++++++++++++++++++++++++- 2 files changed, 157 insertions(+), 7 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index 4bd1aa230b4..d940bf88cdc 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -59,6 +59,7 @@ struct ddraw_stream struct format format; FILTER_STATE state; BOOL eos;
- BOOL flushing; CONDITION_VARIABLE update_queued_cv; struct list update_queue;
}; @@ -1142,7 +1143,7 @@ static HRESULT WINAPI ddraw_sink_EndOfStream(IPin *iface)
EnterCriticalSection(&stream->cs);
- if (stream->eos)
- if (stream->eos || stream->flushing) { LeaveCriticalSection(&stream->cs); return E_FAIL;
@@ -1159,14 +1160,34 @@ static HRESULT WINAPI ddraw_sink_EndOfStream(IPin *iface)
static HRESULT WINAPI ddraw_sink_BeginFlush(IPin *iface) {
- FIXME("iface %p, stub!\n", iface);
- return E_NOTIMPL;
- struct ddraw_stream *stream = impl_from_IPin(iface);
- TRACE("stream %p.\n", stream);
- EnterCriticalSection(&stream->cs);
- stream->flushing = TRUE;
- stream->eos = FALSE;
- WakeConditionVariable(&stream->update_queued_cv);
- LeaveCriticalSection(&stream->cs);
- return S_OK;
}
static HRESULT WINAPI ddraw_sink_EndFlush(IPin *iface) {
- FIXME("iface %p, stub!\n", iface);
- return E_NOTIMPL;
- struct ddraw_stream *stream = impl_from_IPin(iface);
- TRACE("stream %p.\n", stream);
- EnterCriticalSection(&stream->cs);
- stream->flushing = FALSE;
- LeaveCriticalSection(&stream->cs);
- return S_OK;
}
This implementation worries me a bit (and, admittedly, is one of the drawbacks of using a condition variable), because it's vulnerable to an ABA problem. In particular, it's possible for a main thread to call BeginFlush() and EndFlush() in quick succession, while a thread sleeping in Receive() doesn't wake up until after EndFlush() and hence goes back to sleep. I don't know if Windows actually guarantees a wakeup here, but unless it demonstrably doesn't, we should probably make sure the queue is actually empty in either BeginFlush() or EndFlush(). I think we can use the same CV for that.
(Incidentally, patches 2 and 4 of this series look fine.)
static HRESULT WINAPI ddraw_sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate) @@ -1299,6 +1320,11 @@ static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample * LeaveCriticalSection(&stream->cs); return S_OK; }
if (stream->flushing)
{
LeaveCriticalSection(&stream->cs);
return S_FALSE;
} if (!list_empty(&stream->update_queue)) { struct ddraw_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct ddraw_sample, entry);
diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index 19461d921f6..653c184f0b4 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -4005,6 +4005,7 @@ static IPin *ammediastream_pin; static IMemInputPin *ammediastream_mem_input_pin; static IMediaSample *ammediastream_media_sample; static DWORD ammediastream_sleep_time; +static HRESULT ammediastream_expected_hr;
static DWORD CALLBACK ammediastream_end_of_stream(void *param) { @@ -4012,7 +4013,7 @@ static DWORD CALLBACK ammediastream_end_of_stream(void *param)
Sleep(ammediastream_sleep_time); hr = IPin_EndOfStream(ammediastream_pin);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(hr == ammediastream_expected_hr, "Got hr %#x.\n", hr);
return 0;
} @@ -4023,7 +4024,7 @@ static DWORD CALLBACK ammediastream_receive(void *param)
Sleep(ammediastream_sleep_time); hr = IMemInputPin_Receive(ammediastream_mem_input_pin, ammediastream_media_sample);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(hr == ammediastream_expected_hr, "Got hr %#x.\n", hr);
return 0;
} @@ -4197,6 +4198,7 @@ static void test_audiostreamsample_update(void) ammediastream_mem_input_pin = mem_input_pin; ammediastream_media_sample = media_sample1; ammediastream_sleep_time = 100;
ammediastream_expected_hr = S_OK; thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
hr = IAudioStreamSample_Update(stream_sample, 0, NULL, NULL, 0);
@@ -4216,6 +4218,7 @@ static void test_audiostreamsample_update(void)
ammediastream_pin = pin; ammediastream_sleep_time = 100;
ammediastream_expected_hr = S_OK; thread = CreateThread(NULL, 0, ammediastream_end_of_stream, NULL, 0, NULL);
hr = IAudioStreamSample_Update(stream_sample, 0, NULL, NULL, 0);
@@ -5157,6 +5160,7 @@ static void test_ddrawstream_receive(void) ammediastream_mem_input_pin = source.source.pMemInputPin; ammediastream_media_sample = sample; ammediastream_sleep_time = 0;
ammediastream_expected_hr = S_OK; thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Receive returned prematurely.\n");
@@ -5196,6 +5200,121 @@ static void test_ddrawstream_receive(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
+static void test_ddrawstream_begin_flush_end_flush(void) +{
- IAMMultiMediaStream *mmstream = create_ammultimediastream();
- IDirectDrawStreamSample *stream_sample;
- IDirectDrawMediaStream *ddraw_stream;
- IMediaSample *media_sample;
- IMediaFilter *media_filter;
- struct testfilter source;
- IGraphBuilder *graph;
- IMediaStream *stream;
- VIDEOINFO video_info;
- 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 = IDirectDrawMediaStream_CreateSample(ddraw_stream, NULL, NULL, 0, &stream_sample);
- 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 = BaseOutputPinImpl_GetDeliveryBuffer(&source.source, &media_sample, NULL, NULL, 0);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- ammediastream_mem_input_pin = source.source.pMemInputPin;
- ammediastream_media_sample = media_sample;
- ammediastream_sleep_time = 0;
- ammediastream_expected_hr = S_FALSE;
- thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
- hr = IPin_BeginFlush(pin);
- 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 = BaseOutputPinImpl_GetDeliveryBuffer(&source.source, &media_sample, NULL, NULL, 0);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample);
- ok(hr == S_FALSE, "Got hr %#x.\n", hr);
- ref = IMediaSample_Release(media_sample);
- ok(!ref, "Got outstanding refcount %d.\n", ref);
- hr = IDirectDrawStreamSample_Update(stream_sample, SSUPDATE_ASYNC, NULL, NULL, 0);
- ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
- hr = IPin_EndOfStream(pin);
- ok(hr == E_FAIL, "Got hr %#x.\n", hr);
- hr = IPin_EndFlush(pin);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = BaseOutputPinImpl_GetDeliveryBuffer(&source.source, &media_sample, NULL, NULL, 0);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- 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 = 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);
- IGraphBuilder_Disconnect(graph, pin);
- IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface);
- ref = IDirectDrawStreamSample_Release(stream_sample);
- 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);
+}
static void check_ammediastream_join_am_multi_media_stream(const CLSID *clsid) { IAMMultiMediaStream *mmstream = create_ammultimediastream(); @@ -7062,6 +7181,7 @@ static void test_ddrawstreamsample_update(void) ammediastream_mem_input_pin = mem_input_pin; ammediastream_media_sample = media_sample; ammediastream_sleep_time = 0;
ammediastream_expected_hr = S_OK; thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
Sleep(100);
@@ -7109,6 +7229,7 @@ static void test_ddrawstreamsample_update(void) ammediastream_mem_input_pin = mem_input_pin; ammediastream_media_sample = media_sample; ammediastream_sleep_time = 0;
ammediastream_expected_hr = S_OK; thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
Sleep(100);
@@ -7161,6 +7282,7 @@ static void test_ddrawstreamsample_update(void) 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, 0, NULL, NULL, 0);
@@ -7183,6 +7305,7 @@ static void test_ddrawstreamsample_update(void)
ammediastream_pin = pin; ammediastream_sleep_time = 100;
ammediastream_expected_hr = S_OK; thread = CreateThread(NULL, 0, ammediastream_end_of_stream, NULL, 0, NULL);
hr = IDirectDrawStreamSample_Update(stream_sample, 0, NULL, NULL, 0);
@@ -7702,6 +7825,7 @@ START_TEST(amstream) test_ddrawstream_get_format(); test_ddrawstream_set_format(); test_ddrawstream_receive();
test_ddrawstream_begin_flush_end_flush();
test_ddrawstreamsample_get_media_stream(); test_ddrawstreamsample_update();
On Thursday, 1 October 2020 00:06:48 +07 you wrote:
On 9/29/20 2:09 PM, Anton Baskanov wrote:
Signed-off-by: Anton Baskanov baskanov@gmail.com
dlls/amstream/ddrawstream.c | 36 ++++++++-- dlls/amstream/tests/amstream.c | 128 ++++++++++++++++++++++++++++++++- 2 files changed, 157 insertions(+), 7 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index 4bd1aa230b4..d940bf88cdc 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -59,6 +59,7 @@ struct ddraw_stream
struct format format; FILTER_STATE state; BOOL eos;
BOOL flushing;
CONDITION_VARIABLE update_queued_cv; struct list update_queue;
};
@@ -1142,7 +1143,7 @@ static HRESULT WINAPI ddraw_sink_EndOfStream(IPin *iface)> EnterCriticalSection(&stream->cs);
- if (stream->eos)
if (stream->eos || stream->flushing)
{
LeaveCriticalSection(&stream->cs); return E_FAIL;
@@ -1159,14 +1160,34 @@ static HRESULT WINAPI ddraw_sink_EndOfStream(IPin *iface)> static HRESULT WINAPI ddraw_sink_BeginFlush(IPin *iface) {
- FIXME("iface %p, stub!\n", iface);
- return E_NOTIMPL;
- struct ddraw_stream *stream = impl_from_IPin(iface);
- TRACE("stream %p.\n", stream);
- EnterCriticalSection(&stream->cs);
- stream->flushing = TRUE;
- stream->eos = FALSE;
- WakeConditionVariable(&stream->update_queued_cv);
- LeaveCriticalSection(&stream->cs);
- return S_OK;
}
static HRESULT WINAPI ddraw_sink_EndFlush(IPin *iface) {
- FIXME("iface %p, stub!\n", iface);
- return E_NOTIMPL;
- struct ddraw_stream *stream = impl_from_IPin(iface);
- TRACE("stream %p.\n", stream);
- EnterCriticalSection(&stream->cs);
- stream->flushing = FALSE;
- LeaveCriticalSection(&stream->cs);
- return S_OK;
}
This implementation worries me a bit (and, admittedly, is one of the drawbacks of using a condition variable), because it's vulnerable to an ABA problem. In particular, it's possible for a main thread to call BeginFlush() and EndFlush() in quick succession, while a thread sleeping in Receive() doesn't wake up until after EndFlush() and hence goes back to sleep. I don't know if Windows actually guarantees a wakeup here, but unless it demonstrably doesn't, we should probably make sure the queue is actually empty in either BeginFlush() or EndFlush(). I think we can use the same CV for that.
Fixed this with another CV and a boolean flag, which is kind of ugly, but I couldn't think of a better solution.
(Incidentally, patches 2 and 4 of this series look fine.)
static HRESULT WINAPI ddraw_sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)> @@ -1299,6 +1320,11 @@ static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample *> LeaveCriticalSection(&stream->cs); return S_OK;
}
if (stream->flushing)
{
LeaveCriticalSection(&stream->cs);
return S_FALSE;
} if (!list_empty(&stream->update_queue)) { struct ddraw_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct ddraw_sample, entry);>
diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index 19461d921f6..653c184f0b4 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -4005,6 +4005,7 @@ static IPin *ammediastream_pin;
static IMemInputPin *ammediastream_mem_input_pin; static IMediaSample *ammediastream_media_sample; static DWORD ammediastream_sleep_time;
+static HRESULT ammediastream_expected_hr;
static DWORD CALLBACK ammediastream_end_of_stream(void *param) {
@@ -4012,7 +4013,7 @@ static DWORD CALLBACK ammediastream_end_of_stream(void *param)> Sleep(ammediastream_sleep_time); hr = IPin_EndOfStream(ammediastream_pin);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(hr == ammediastream_expected_hr, "Got hr %#x.\n", hr);
return 0;
}
@@ -4023,7 +4024,7 @@ static DWORD CALLBACK ammediastream_receive(void *param)> Sleep(ammediastream_sleep_time); hr = IMemInputPin_Receive(ammediastream_mem_input_pin, ammediastream_media_sample);>
- ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(hr == ammediastream_expected_hr, "Got hr %#x.\n", hr);
return 0;
}
@@ -4197,6 +4198,7 @@ static void test_audiostreamsample_update(void)
ammediastream_mem_input_pin = mem_input_pin; ammediastream_media_sample = media_sample1; ammediastream_sleep_time = 100;
ammediastream_expected_hr = S_OK;
thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
hr = IAudioStreamSample_Update(stream_sample, 0, NULL, NULL, 0);
@@ -4216,6 +4218,7 @@ static void test_audiostreamsample_update(void)
ammediastream_pin = pin; ammediastream_sleep_time = 100;
ammediastream_expected_hr = S_OK;
thread = CreateThread(NULL, 0, ammediastream_end_of_stream, NULL, 0, NULL);
hr = IAudioStreamSample_Update(stream_sample, 0, NULL, NULL, 0);
@@ -5157,6 +5160,7 @@ static void test_ddrawstream_receive(void)
ammediastream_mem_input_pin = source.source.pMemInputPin; ammediastream_media_sample = sample; ammediastream_sleep_time = 0;
ammediastream_expected_hr = S_OK;
thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Receive returned prematurely.\n");>
@@ -5196,6 +5200,121 @@ static void test_ddrawstream_receive(void)
ok(!ref, "Got outstanding refcount %d.\n", ref);
}
+static void test_ddrawstream_begin_flush_end_flush(void) +{
- IAMMultiMediaStream *mmstream = create_ammultimediastream();
- IDirectDrawStreamSample *stream_sample;
- IDirectDrawMediaStream *ddraw_stream;
- IMediaSample *media_sample;
- IMediaFilter *media_filter;
- struct testfilter source;
- IGraphBuilder *graph;
- IMediaStream *stream;
- VIDEOINFO video_info;
- 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 = IDirectDrawMediaStream_CreateSample(ddraw_stream, NULL, NULL, 0,
&stream_sample); + 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 = BaseOutputPinImpl_GetDeliveryBuffer(&source.source,
&media_sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr);
- ammediastream_mem_input_pin = source.source.pMemInputPin;
- ammediastream_media_sample = media_sample;
- ammediastream_sleep_time = 0;
- ammediastream_expected_hr = S_FALSE;
- thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
- hr = IPin_BeginFlush(pin);
- 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 = BaseOutputPinImpl_GetDeliveryBuffer(&source.source,
&media_sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample);
- ok(hr == S_FALSE, "Got hr %#x.\n", hr);
- ref = IMediaSample_Release(media_sample);
- ok(!ref, "Got outstanding refcount %d.\n", ref);
- hr = IDirectDrawStreamSample_Update(stream_sample, SSUPDATE_ASYNC,
NULL, NULL, 0); + ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
- hr = IPin_EndOfStream(pin);
- ok(hr == E_FAIL, "Got hr %#x.\n", hr);
- hr = IPin_EndFlush(pin);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = BaseOutputPinImpl_GetDeliveryBuffer(&source.source,
&media_sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr);
- 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 = 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);
- IGraphBuilder_Disconnect(graph, pin);
- IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface);
- ref = IDirectDrawStreamSample_Release(stream_sample);
- 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);
+}
static void check_ammediastream_join_am_multi_media_stream(const CLSID *clsid) {
IAMMultiMediaStream *mmstream = create_ammultimediastream();
@@ -7062,6 +7181,7 @@ static void test_ddrawstreamsample_update(void)
ammediastream_mem_input_pin = mem_input_pin; ammediastream_media_sample = media_sample; ammediastream_sleep_time = 0;
ammediastream_expected_hr = S_OK;
thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
Sleep(100);
@@ -7109,6 +7229,7 @@ static void test_ddrawstreamsample_update(void)
ammediastream_mem_input_pin = mem_input_pin; ammediastream_media_sample = media_sample; ammediastream_sleep_time = 0;
ammediastream_expected_hr = S_OK;
thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
Sleep(100);
@@ -7161,6 +7282,7 @@ static void test_ddrawstreamsample_update(void)
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, 0, NULL, NULL, 0);
@@ -7183,6 +7305,7 @@ static void test_ddrawstreamsample_update(void)
ammediastream_pin = pin; ammediastream_sleep_time = 100;
ammediastream_expected_hr = S_OK;
thread = CreateThread(NULL, 0, ammediastream_end_of_stream, NULL, 0, NULL);
hr = IDirectDrawStreamSample_Update(stream_sample, 0, NULL, NULL, 0);
@@ -7702,6 +7825,7 @@ START_TEST(amstream)
test_ddrawstream_get_format(); test_ddrawstream_set_format(); test_ddrawstream_receive();
test_ddrawstream_begin_flush_end_flush();
test_ddrawstreamsample_get_media_stream(); test_ddrawstreamsample_update();
On 10/1/20 12:57 PM, Anton Baskanov wrote:
On Thursday, 1 October 2020 00:06:48 +07 you wrote:
On 9/29/20 2:09 PM, Anton Baskanov wrote:
Signed-off-by: Anton Baskanov baskanov@gmail.com
dlls/amstream/ddrawstream.c | 36 ++++++++-- dlls/amstream/tests/amstream.c | 128 ++++++++++++++++++++++++++++++++- 2 files changed, 157 insertions(+), 7 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index 4bd1aa230b4..d940bf88cdc 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -59,6 +59,7 @@ struct ddraw_stream
struct format format; FILTER_STATE state; BOOL eos;
BOOL flushing;
CONDITION_VARIABLE update_queued_cv; struct list update_queue;
};
@@ -1142,7 +1143,7 @@ static HRESULT WINAPI ddraw_sink_EndOfStream(IPin *iface)> EnterCriticalSection(&stream->cs);
- if (stream->eos)
if (stream->eos || stream->flushing)
{
LeaveCriticalSection(&stream->cs); return E_FAIL;
@@ -1159,14 +1160,34 @@ static HRESULT WINAPI ddraw_sink_EndOfStream(IPin *iface)> static HRESULT WINAPI ddraw_sink_BeginFlush(IPin *iface) {
- FIXME("iface %p, stub!\n", iface);
- return E_NOTIMPL;
- struct ddraw_stream *stream = impl_from_IPin(iface);
- TRACE("stream %p.\n", stream);
- EnterCriticalSection(&stream->cs);
- stream->flushing = TRUE;
- stream->eos = FALSE;
- WakeConditionVariable(&stream->update_queued_cv);
- LeaveCriticalSection(&stream->cs);
- return S_OK;
}
static HRESULT WINAPI ddraw_sink_EndFlush(IPin *iface) {
- FIXME("iface %p, stub!\n", iface);
- return E_NOTIMPL;
- struct ddraw_stream *stream = impl_from_IPin(iface);
- TRACE("stream %p.\n", stream);
- EnterCriticalSection(&stream->cs);
- stream->flushing = FALSE;
- LeaveCriticalSection(&stream->cs);
- return S_OK;
}
This implementation worries me a bit (and, admittedly, is one of the drawbacks of using a condition variable), because it's vulnerable to an ABA problem. In particular, it's possible for a main thread to call BeginFlush() and EndFlush() in quick succession, while a thread sleeping in Receive() doesn't wake up until after EndFlush() and hence goes back to sleep. I don't know if Windows actually guarantees a wakeup here, but unless it demonstrably doesn't, we should probably make sure the queue is actually empty in either BeginFlush() or EndFlush(). I think we can use the same CV for that.
Fixed this with another CV and a boolean flag, which is kind of ugly, but I couldn't think of a better solution.
Hmm.
On the one hand, I don't think the flag is particularly ugly, but.
On the other hand, I'm a little bothered now by that statement of mine; I'm not actually sure it's necessary. [In my defense, DirectShow synchronization is hard, and extremely underspecified.] I remember dealing with a similar problem when trying to improve synchronization in the base renderer a while ago, and I came to the conclusion that a patch like this wasn't necessary.
In particular, I think the actual requirements for flushing are that a filter cannot send old samples after EndFlush(), or allow them to be rendered. In practice, if a filter doesn't buffer, it can "pass the buck" up to the upstream filter. Put another way, if filters don't buffer, the only filter that actually needs to wait for the streaming thread to finish is the parser filter, and the parser filter basically always needs to wait *anyway*.
But, just in case, I tested, and surprisingly enough, native amstream's Receive() won't be unblocked if BeginFlush() and EndFlush() are called in quick succession, but if I add a small Sleep() between those, it will be unblocked. Quite surprising for several reasons, but I think that seals the case.
So I'd be perfectly happy to sign off on the original version of this patch, rebased on the other changes ;-)
(Incidentally, patches 2 and 4 of this series look fine.)
static HRESULT WINAPI ddraw_sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate)> @@ -1299,6 +1320,11 @@ static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample *> LeaveCriticalSection(&stream->cs); return S_OK;
}
if (stream->flushing)
{
LeaveCriticalSection(&stream->cs);
return S_FALSE;
} if (!list_empty(&stream->update_queue)) { struct ddraw_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct ddraw_sample, entry);>
diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index 19461d921f6..653c184f0b4 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -4005,6 +4005,7 @@ static IPin *ammediastream_pin;
static IMemInputPin *ammediastream_mem_input_pin; static IMediaSample *ammediastream_media_sample; static DWORD ammediastream_sleep_time;
+static HRESULT ammediastream_expected_hr;
static DWORD CALLBACK ammediastream_end_of_stream(void *param) {
@@ -4012,7 +4013,7 @@ static DWORD CALLBACK ammediastream_end_of_stream(void *param)> Sleep(ammediastream_sleep_time); hr = IPin_EndOfStream(ammediastream_pin);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(hr == ammediastream_expected_hr, "Got hr %#x.\n", hr);
return 0;
}
@@ -4023,7 +4024,7 @@ static DWORD CALLBACK ammediastream_receive(void *param)> Sleep(ammediastream_sleep_time); hr = IMemInputPin_Receive(ammediastream_mem_input_pin, ammediastream_media_sample);>
- ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(hr == ammediastream_expected_hr, "Got hr %#x.\n", hr);
return 0;
}
@@ -4197,6 +4198,7 @@ static void test_audiostreamsample_update(void)
ammediastream_mem_input_pin = mem_input_pin; ammediastream_media_sample = media_sample1; ammediastream_sleep_time = 100;
ammediastream_expected_hr = S_OK;
thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
hr = IAudioStreamSample_Update(stream_sample, 0, NULL, NULL, 0);
@@ -4216,6 +4218,7 @@ static void test_audiostreamsample_update(void)
ammediastream_pin = pin; ammediastream_sleep_time = 100;
ammediastream_expected_hr = S_OK;
thread = CreateThread(NULL, 0, ammediastream_end_of_stream, NULL, 0, NULL);
hr = IAudioStreamSample_Update(stream_sample, 0, NULL, NULL, 0);
@@ -5157,6 +5160,7 @@ static void test_ddrawstream_receive(void)
ammediastream_mem_input_pin = source.source.pMemInputPin; ammediastream_media_sample = sample; ammediastream_sleep_time = 0;
ammediastream_expected_hr = S_OK;
thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Receive returned prematurely.\n");>
@@ -5196,6 +5200,121 @@ static void test_ddrawstream_receive(void)
ok(!ref, "Got outstanding refcount %d.\n", ref);
}
+static void test_ddrawstream_begin_flush_end_flush(void) +{
- IAMMultiMediaStream *mmstream = create_ammultimediastream();
- IDirectDrawStreamSample *stream_sample;
- IDirectDrawMediaStream *ddraw_stream;
- IMediaSample *media_sample;
- IMediaFilter *media_filter;
- struct testfilter source;
- IGraphBuilder *graph;
- IMediaStream *stream;
- VIDEOINFO video_info;
- 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 = IDirectDrawMediaStream_CreateSample(ddraw_stream, NULL, NULL, 0,
&stream_sample); + 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 = BaseOutputPinImpl_GetDeliveryBuffer(&source.source,
&media_sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr);
- ammediastream_mem_input_pin = source.source.pMemInputPin;
- ammediastream_media_sample = media_sample;
- ammediastream_sleep_time = 0;
- ammediastream_expected_hr = S_FALSE;
- thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
- hr = IPin_BeginFlush(pin);
- 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 = BaseOutputPinImpl_GetDeliveryBuffer(&source.source,
&media_sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample);
- ok(hr == S_FALSE, "Got hr %#x.\n", hr);
- ref = IMediaSample_Release(media_sample);
- ok(!ref, "Got outstanding refcount %d.\n", ref);
- hr = IDirectDrawStreamSample_Update(stream_sample, SSUPDATE_ASYNC,
NULL, NULL, 0); + ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
- hr = IPin_EndOfStream(pin);
- ok(hr == E_FAIL, "Got hr %#x.\n", hr);
- hr = IPin_EndFlush(pin);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = BaseOutputPinImpl_GetDeliveryBuffer(&source.source,
&media_sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr);
- 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 = 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);
- IGraphBuilder_Disconnect(graph, pin);
- IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface);
- ref = IDirectDrawStreamSample_Release(stream_sample);
- 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);
+}
static void check_ammediastream_join_am_multi_media_stream(const CLSID *clsid) {
IAMMultiMediaStream *mmstream = create_ammultimediastream();
@@ -7062,6 +7181,7 @@ static void test_ddrawstreamsample_update(void)
ammediastream_mem_input_pin = mem_input_pin; ammediastream_media_sample = media_sample; ammediastream_sleep_time = 0;
ammediastream_expected_hr = S_OK;
thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
Sleep(100);
@@ -7109,6 +7229,7 @@ static void test_ddrawstreamsample_update(void)
ammediastream_mem_input_pin = mem_input_pin; ammediastream_media_sample = media_sample; ammediastream_sleep_time = 0;
ammediastream_expected_hr = S_OK;
thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
Sleep(100);
@@ -7161,6 +7282,7 @@ static void test_ddrawstreamsample_update(void)
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, 0, NULL, NULL, 0);
@@ -7183,6 +7305,7 @@ static void test_ddrawstreamsample_update(void)
ammediastream_pin = pin; ammediastream_sleep_time = 100;
ammediastream_expected_hr = S_OK;
thread = CreateThread(NULL, 0, ammediastream_end_of_stream, NULL, 0, NULL);
hr = IDirectDrawStreamSample_Update(stream_sample, 0, NULL, NULL, 0);
@@ -7702,6 +7825,7 @@ START_TEST(amstream)
test_ddrawstream_get_format(); test_ddrawstream_set_format(); test_ddrawstream_receive();
test_ddrawstream_begin_flush_end_flush();
test_ddrawstreamsample_get_media_stream(); test_ddrawstreamsample_update();
Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/amstream/ddrawstream.c | 24 +++++-- dlls/amstream/tests/amstream.c | 120 +++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 4 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index d940bf88cdc..940979db412 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -58,6 +58,7 @@ struct ddraw_stream AM_MEDIA_TYPE mt; struct format format; FILTER_STATE state; + REFERENCE_TIME segment_start; BOOL eos; BOOL flushing; CONDITION_VARIABLE update_queued_cv; @@ -1192,9 +1193,18 @@ static HRESULT WINAPI ddraw_sink_EndFlush(IPin *iface)
static HRESULT WINAPI ddraw_sink_NewSegment(IPin *iface, REFERENCE_TIME start, REFERENCE_TIME stop, double rate) { - FIXME("iface %p, start %s, stop %s, rate %0.16e, stub!\n", - iface, wine_dbgstr_longlong(start), wine_dbgstr_longlong(stop), rate); - return E_NOTIMPL; + struct ddraw_stream *stream = impl_from_IPin(iface); + + TRACE("stream %p, start %s, stop %s, rate %0.16e\n", + stream, wine_dbgstr_longlong(start), wine_dbgstr_longlong(stop), rate); + + EnterCriticalSection(&stream->cs); + + stream->segment_start = start; + + LeaveCriticalSection(&stream->cs); + + return S_OK; }
static const IPinVtbl ddraw_sink_vtbl = @@ -1288,6 +1298,8 @@ static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample * BITMAPINFOHEADER *bitmap_info; REFERENCE_TIME start_time = 0; REFERENCE_TIME end_time = 0; + STREAM_TIME start_stream_time; + STREAM_TIME end_stream_time; BYTE *top_down_pointer; int top_down_stride; BYTE *pointer; @@ -1313,6 +1325,9 @@ static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample * top_down_stride = top_down ? stride : -stride; top_down_pointer = top_down ? pointer : pointer + stride * (bitmap_info->biHeight - 1);
+ start_stream_time = start_time + stream->segment_start; + end_stream_time = end_time + stream->segment_start; + for (;;) { if (stream->state == State_Stopped) @@ -1329,7 +1344,8 @@ static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample * { struct ddraw_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct ddraw_sample, entry);
- sample->update_hr = process_update(sample, top_down_stride, top_down_pointer, start_time, end_time); + sample->update_hr = process_update(sample, top_down_stride, top_down_pointer, + start_stream_time, end_stream_time);
remove_queued_update(sample); LeaveCriticalSection(&stream->cs); diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index 653c184f0b4..b326a0f0254 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -5315,6 +5315,125 @@ static void test_ddrawstream_begin_flush_end_flush(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
+static void test_ddrawstream_new_segment(void) +{ + static const BYTE test_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + IAMMultiMediaStream *mmstream = create_ammultimediastream(); + IDirectDrawStreamSample *stream_sample; + IDirectDrawMediaStream *ddraw_stream; + IMemInputPin *mem_input_pin; + IMediaSample *media_sample; + IMediaFilter *media_filter; + struct testfilter source; + STREAM_TIME start_time; + STREAM_TIME end_time; + IGraphBuilder *graph; + IMediaStream *stream; + VIDEOINFO video_info; + AM_MEDIA_TYPE mt; + 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 = IMediaStream_QueryInterface(stream, &IID_IMemInputPin, (void **)&mem_input_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 = IDirectDrawMediaStream_CreateSample(ddraw_stream, NULL, NULL, 0, &stream_sample); + 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 = IPin_NewSegment(pin, 11111111, 22222222, 1.0); + 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); + + media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data)); + start_time = 12345678; + end_time = 23456789; + hr = IMediaSample_SetTime(media_sample, &start_time, &end_time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMemInputPin_Receive(mem_input_pin, media_sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IMediaSample_Release(media_sample); + + start_time = 0xdeadbeefdeadbeef; + end_time = 0xdeadbeefdeadbeef; + hr = IDirectDrawStreamSample_GetSampleTimes(stream_sample, &start_time, &end_time, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(start_time == 23456789, "Got start time %s.\n", wine_dbgstr_longlong(start_time)); + ok(end_time == 34567900, "Got end time %s.\n", wine_dbgstr_longlong(end_time)); + + hr = IPin_NewSegment(pin, 11111111, 22222222, 2.0); + 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); + + media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data)); + start_time = 12345678; + end_time = 23456789; + hr = IMediaSample_SetTime(media_sample, &start_time, &end_time); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMemInputPin_Receive(mem_input_pin, media_sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IMediaSample_Release(media_sample); + + start_time = 0xdeadbeefdeadbeef; + end_time = 0xdeadbeefdeadbeef; + hr = IDirectDrawStreamSample_GetSampleTimes(stream_sample, &start_time, &end_time, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(start_time == 23456789, "Got start time %s.\n", wine_dbgstr_longlong(start_time)); + ok(end_time == 34567900, "Got end time %s.\n", wine_dbgstr_longlong(end_time)); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP); + 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_sample); + 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); + IMemInputPin_Release(mem_input_pin); + IDirectDrawMediaStream_Release(ddraw_stream); + ref = IMediaStream_Release(stream); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + static void check_ammediastream_join_am_multi_media_stream(const CLSID *clsid) { IAMMultiMediaStream *mmstream = create_ammultimediastream(); @@ -7826,6 +7945,7 @@ START_TEST(amstream) test_ddrawstream_set_format(); test_ddrawstream_receive(); test_ddrawstream_begin_flush_end_flush(); + test_ddrawstream_new_segment();
test_ddrawstreamsample_get_media_stream(); test_ddrawstreamsample_update();
On 9/29/20 2:09 PM, Anton Baskanov wrote:
Signed-off-by: Anton Baskanov baskanov@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;
}
This is another place where I think it would be a good idea to use a condition variable.
Could you please add a test with (COMPSTAT_NOUPDATEOK | COMPSTAT_WAIT, INFINITE) and (COMPSTAT_ABORT | COMPSTAT_WAIT, INFINITE), to show that the WAIT flag doesn't matter?