[PATCH 1/5] amstream: Wait for the state transition to complete in AMMultiMediaStream::SetState.
Zebediah Figura
zfigura at codeweavers.com
Fri Oct 23 11:12:27 CDT 2020
On 10/22/20 2:06 PM, Anton Baskanov wrote:
> Signed-off-by: Anton Baskanov <baskanov at gmail.com>
> ---
> dlls/amstream/multimedia.c | 4 ++
> dlls/amstream/tests/amstream.c | 84 ++++++++++++++++++++++++++++++++++
> 2 files changed, 88 insertions(+)
>
> diff --git a/dlls/amstream/multimedia.c b/dlls/amstream/multimedia.c
> index 82ef4822344..967baacb747 100644
> --- a/dlls/amstream/multimedia.c
> +++ b/dlls/amstream/multimedia.c
> @@ -156,7 +156,11 @@ static HRESULT WINAPI multimedia_stream_SetState(IAMMultiMediaStream *iface, STR
> {
> hr = IMediaControl_Run(This->media_control);
> if (SUCCEEDED(hr))
> + {
> + FILTER_STATE state;
> + IMediaControl_GetState(This->media_control, INFINITE, (OAFilterState *)&state);
> hr = S_OK;
> + }
> }
> else if (new_state == STREAMSTATE_STOP)
> hr = IMediaControl_Stop(This->media_control);
> diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c
> index b436840e407..cb2b3dd76db 100644
> --- a/dlls/amstream/tests/amstream.c
> +++ b/dlls/amstream/tests/amstream.c
> @@ -924,11 +924,13 @@ struct testfilter
> LONGLONG current_position;
> LONGLONG stop_position;
> const AM_MEDIA_TYPE *preferred_mt;
> + CONDITION_VARIABLE wait_state_cv;
> HRESULT get_duration_hr;
> HRESULT get_stop_position_hr;
> HRESULT set_positions_hr;
> HRESULT init_stream_hr;
> HRESULT cleanup_stream_hr;
> + HRESULT wait_state_hr;
> };
>
> static inline struct testfilter *impl_from_BaseFilter(struct strmbase_filter *iface)
> @@ -971,12 +973,37 @@ static HRESULT testfilter_cleanup_stream(struct strmbase_filter *iface)
> return filter->cleanup_stream_hr;
> }
>
> +static HRESULT testfilter_wait_state(struct strmbase_filter *iface, DWORD timeout)
> +{
> + struct testfilter *filter = impl_from_BaseFilter(iface);
> + DWORD start_time = GetTickCount();
> + DWORD elapsed = 0;
> + HRESULT hr;
> +
> + EnterCriticalSection(&filter->filter.csFilter);
strmbase actually already grabs this.
> +
> + while (filter->wait_state_hr == VFW_S_STATE_INTERMEDIATE && elapsed < timeout)
> + {
> + DWORD sleep_time = timeout - elapsed;
> + if (!SleepConditionVariableCS(&filter->wait_state_cv, &filter->filter.csFilter, sleep_time))
> + break;
> + elapsed = GetTickCount() - start_time;
> + }
This is fine, though it'd also be fine, and perhaps a little simpler, to
use an event.
(I know I may sound inconsistent. I do think that the usage patterns in
prior patches are ideal for condition variables, where the condition
needs to be rechecked *anyway*, and there may be multiple threads trying
to use the same resource. The fact that condition variables are "fast"
in Wine, at least on some platforms, is also a benefit for
implementation code. Here the usage pattern is a little different, i.e.
much more linear and controlled, so using an event gets a little easier,
and of course speed doesn't matter as much.)
> +
> + hr = filter->wait_state_hr;
> +
> + LeaveCriticalSection(&filter->filter.csFilter);
> +
> + return hr;
> +}
> +
> static const struct strmbase_filter_ops testfilter_ops =
> {
> .filter_get_pin = testfilter_get_pin,
> .filter_destroy = testfilter_destroy,
> .filter_init_stream = testfilter_init_stream,
> .filter_cleanup_stream = testfilter_cleanup_stream,
> + .filter_wait_state = testfilter_wait_state,
> };
>
> static inline struct testfilter *impl_from_base_pin(struct strmbase_pin *iface)
> @@ -1060,6 +1087,7 @@ static void testfilter_init(struct testfilter *filter)
> strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops);
> strmbase_source_init(&filter->source, &filter->filter, L"", &testsource_ops);
> filter->stop_position = 0x8000000000000000ULL;
> + InitializeConditionVariable(&filter->wait_state_cv);
> }
>
> static inline struct testfilter *impl_from_IMediaSeeking(IMediaSeeking *iface)
> @@ -2319,11 +2347,25 @@ static void test_initialize(void)
> IUnknown_Release(graph_inner_unk);
> }
>
> +static IAMMultiMediaStream *mmstream_mmstream;
> +static STREAM_STATE mmstream_state;
> +
> +static DWORD CALLBACK mmstream_set_state(void *param)
> +{
> + HRESULT hr;
> +
> + hr = IAMMultiMediaStream_SetState(mmstream_mmstream, mmstream_state);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> + return 0;
> +}
> +
> static void test_set_state(void)
> {
> IAMMultiMediaStream *mmstream = create_ammultimediastream();
> struct testfilter source;
> IGraphBuilder *graph;
> + HANDLE thread;
> HRESULT hr;
> ULONG ref;
>
> @@ -2353,6 +2395,41 @@ static void test_set_state(void)
> hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
> ok(hr == S_OK, "Got hr %#x.\n", hr);
>
> + source.wait_state_hr = E_FAIL;
> + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> + source.wait_state_hr = S_OK;
> + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> + source.wait_state_hr = VFW_S_STATE_INTERMEDIATE;
> +
> + mmstream_mmstream = mmstream;
> + mmstream_state = STREAMSTATE_RUN;
> + thread = CreateThread(NULL, 0, mmstream_set_state, NULL, 0, NULL);
> +
> + ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "SetState returned prematurely.\n");
> +
> + EnterCriticalSection(&source.filter.csFilter);
> + source.wait_state_hr = S_OK;
> + WakeAllConditionVariable(&source.wait_state_cv);
> + LeaveCriticalSection(&source.filter.csFilter);
> +
> + 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);
> +
> + source.init_stream_hr = E_FAIL;
> + source.wait_state_hr = VFW_S_STATE_INTERMEDIATE;
> + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
> + ok(hr == E_FAIL, "Got hr %#x.\n", hr);
> + source.init_stream_hr = S_OK;
> + source.wait_state_hr = S_OK;
> + 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);
> source.cleanup_stream_hr = E_FAIL;
> @@ -2369,6 +2446,13 @@ static void test_set_state(void)
> ok(hr == S_FALSE, "Got hr %#x.\n", hr);
> source.cleanup_stream_hr = S_OK;
>
> + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> + source.wait_state_hr = VFW_S_STATE_INTERMEDIATE;
> + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
> + ok(hr == S_OK, "Got hr %#x.\n", hr);
> + source.wait_state_hr = S_OK;
> +
> ref = IAMMultiMediaStream_Release(mmstream);
> ok(!ref, "Got outstanding refcount %d.\n", ref);
> ref = IGraphBuilder_Release(graph);
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20201023/d930eeb6/attachment-0001.sig>
More information about the wine-devel
mailing list