[PATCH 5/5] amstream: Wait for presentation time in AMDirectDrawStream::Receive.

Zebediah Figura zfigura at codeweavers.com
Fri Oct 23 11:49:28 CDT 2020



On 10/22/20 2:06 PM, Anton Baskanov wrote:
> Signed-off-by: Anton Baskanov <baskanov at gmail.com>
> ---
>  dlls/amstream/ddrawstream.c    |  44 ++++++++---
>  dlls/amstream/tests/amstream.c | 137 +++++++++++++++++++++++++++++++++
>  2 files changed, 172 insertions(+), 9 deletions(-)
> 
> diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c
> index 190034fa008..da1d65ff170 100644
> --- a/dlls/amstream/ddrawstream.c
> +++ b/dlls/amstream/ddrawstream.c
> @@ -1344,25 +1344,51 @@ static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample *
>              LeaveCriticalSection(&stream->cs);
>              return S_FALSE;
>          }
> -        if (!list_empty(&stream->update_queue))
> +        while (!list_empty(&stream->update_queue))
>          {
>              struct ddraw_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct ddraw_sample, entry);
> +            struct ddraw_sample *sample2;
> +            IMediaStreamFilter *filter;
> +            HRESULT update_hr;
>  
> -            sample->update_hr = process_update(sample, top_down_stride, top_down_pointer,
> +            update_hr = process_update(sample, top_down_stride, top_down_pointer,
>                      start_stream_time, end_stream_time);
>  
> -            if (sample->continuous_update && SUCCEEDED(sample->update_hr))
> +            filter = stream->filter;
> +
> +            LeaveCriticalSection(&stream->cs);
> +            IMediaStreamFilter_WaitUntil(filter, start_time);
> +            EnterCriticalSection(&stream->cs);
> +
> +            if (stream->state == State_Stopped)
>              {
> -                list_remove(&sample->entry);
> -                list_add_tail(&sample->parent->update_queue, &sample->entry);
> +                LeaveCriticalSection(&stream->cs);
> +                return S_OK;
>              }
> -            else
> +            if (stream->flushing)
>              {
> -                remove_queued_update(sample);
> +                LeaveCriticalSection(&stream->cs);
> +                return S_FALSE;
>              }
>  
> -            LeaveCriticalSection(&stream->cs);
> -            return S_OK;
> +            LIST_FOR_EACH_ENTRY(sample2, &stream->update_queue, struct ddraw_sample, entry)
> +            {
> +                if (sample2 == sample)
> +                {
> +                    sample->update_hr = update_hr;
> +                    if (sample->continuous_update && SUCCEEDED(sample->update_hr))
> +                    {
> +                        list_remove(&sample->entry);
> +                        list_add_tail(&sample->parent->update_queue, &sample->entry);
> +                    }
> +                    else
> +                    {
> +                        remove_queued_update(sample);
> +                    }
> +                    LeaveCriticalSection(&stream->cs);
> +                    return S_OK;
> +                }
> +            }
>          }
>  
>          SleepConditionVariableCS(&stream->update_queued_cv, &stream->cs, INFINITE);

This implies that if you:

* queue sample 1
* queue sample 2
* call Receive
* remove sample 1
* signal presentation time

that Receive() won't return, and moreover that if you

* queue sample 1
* queue sample 2
* call Receive
* remove sample 1
* queue sample 1
* signal presentation time

that it will return (and fill sample 1). Which seems plausible, but also
not the simplest way to implement this behaviour—that seems to me to be
to just wait for presentation time and then pick the first sample queued
if there is one.

> diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c
> index d89f1ecb109..50e75fd0395 100644
> --- a/dlls/amstream/tests/amstream.c
> +++ b/dlls/amstream/tests/amstream.c
> @@ -7861,9 +7861,11 @@ static void test_ddrawstreamsample_completion_status(void)
>      IDirectDrawStreamSample *stream_sample1;
>      IDirectDrawStreamSample *stream_sample2;
>      IDirectDrawMediaStream *ddraw_stream;
> +    struct advise_time_cookie cookie = { 0 };
>      IMediaSample *media_sample;
>      IMediaFilter *media_filter;
>      struct testfilter source;
> +    struct testclock clock;
>      VIDEOINFO video_info;
>      IGraphBuilder *graph;
>      IMediaStream *stream;
> @@ -7889,6 +7891,8 @@ static void test_ddrawstreamsample_completion_status(void)
>      testfilter_init(&source);
>      hr = IGraphBuilder_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL);
>      ok(hr == S_OK, "Got hr %#x.\n", hr);
> +    testclock_init(&clock);
> +    cookie.advise_time_called_event = CreateEventW(NULL, FALSE, FALSE, NULL);
>  
>      hr = IMediaFilter_SetSyncSource(media_filter, NULL);
>      ok(hr == S_OK, "Got hr %#x.\n", hr);
> @@ -8246,9 +8250,142 @@ static void test_ddrawstreamsample_completion_status(void)
>      hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_WAIT, INFINITE);
>      ok(hr == S_OK, "Got hr %#x.\n", hr);
>  
> +    hr = IMediaFilter_SetSyncSource(media_filter, &clock.IReferenceClock_iface);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    clock.advise_time_cookie = &cookie;
> +
> +    hr = IDirectDrawStreamSample_Update(stream_sample1, 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));
> +
> +    ammediastream_mem_input_pin = source.source.pMemInputPin;
> +    ammediastream_media_sample = media_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");
> +
> +    hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, INFINITE);

Mildly weird to pass INFINITE without COMPSTAT_WAIT.

> +    ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
> +
> +    SetEvent(cookie.event);
> +
> +    ok(!WaitForSingleObject(thread, 2000), "Wait timed out.\n");
> +    CloseHandle(thread);
> +
> +    ref = IMediaSample_Release(media_sample);
> +    ok(!ref, "Got outstanding refcount %d.\n", ref);
> +
> +    hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 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);
> +
> +    media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data));
> +
> +    ammediastream_mem_input_pin = source.source.pMemInputPin;
> +    ammediastream_media_sample = media_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");
> +
> +    hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_NOUPDATEOK, INFINITE);
> +    ok(hr == MS_S_NOUPDATE, "Got hr %#x.\n", hr);
> +
> +    ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Receive returned prematurely.\n");
> +
> +    SetEvent(cookie.event);
> +
> +    ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Receive returned prematurely.\n");
> +
> +    hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC, NULL, NULL, 0);
> +    ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
> +
> +    ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Receive returned prematurely.\n");
> +
> +    SetEvent(cookie.event);
> +
> +    ok(!WaitForSingleObject(thread, 2000), "Wait timed out.\n");
> +    CloseHandle(thread);
> +
> +    hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, INFINITE);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    ref = IMediaSample_Release(media_sample);
> +    ok(!ref, "Got outstanding refcount %d.\n", ref);
> +
> +    hr = IDirectDrawStreamSample_Update(stream_sample1, 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));
> +
> +    ammediastream_mem_input_pin = source.source.pMemInputPin;
> +    ammediastream_media_sample = media_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");
> +
> +    hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_ABORT, INFINITE);
> +    ok(hr == MS_S_NOUPDATE, "Got hr %#x.\n", hr);
> +
> +    ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Receive returned prematurely.\n");
> +
> +    SetEvent(cookie.event);
> +
> +    ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Receive returned prematurely.\n");
> +
> +    hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC, NULL, NULL, 0);
> +    ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
> +
> +    ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Receive returned prematurely.\n");
> +
> +    SetEvent(cookie.event);
> +
> +    ok(!WaitForSingleObject(thread, 2000), "Wait timed out.\n");
> +    CloseHandle(thread);
> +
> +    hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, INFINITE);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    ref = IMediaSample_Release(media_sample);
> +    ok(!ref, "Got outstanding refcount %d.\n", ref);
> +
> +    hr = IDirectDrawStreamSample_Update(stream_sample1, 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));
> +
> +    ammediastream_mem_input_pin = source.source.pMemInputPin;
> +    ammediastream_media_sample = media_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");
> +
> +    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    ok(!WaitForSingleObject(thread, 2000), "Wait timed out.\n");
> +    CloseHandle(thread);
> +
> +    ref = IMediaSample_Release(media_sample);
> +    ok(!ref, "Got outstanding refcount %d.\n", ref);
> +
> +    hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, INFINITE);
> +    ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
> +
>      IGraphBuilder_Disconnect(graph, pin);
>      IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface);
>  
> +    CloseHandle(cookie.advise_time_called_event);
>      ref = IDirectDrawStreamSample_Release(stream_sample1);
>      ok(!ref, "Got outstanding refcount %d.\n", ref);
>      ref = IDirectDrawStreamSample_Release(stream_sample2);
> 

-------------- 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/f89a9729/attachment.sig>


More information about the wine-devel mailing list