[PATCH 3/6] amstream: Implement AMAudioStream::EndOfStream.

Zebediah Figura zfigura at codeweavers.com
Sun Apr 19 17:12:10 CDT 2020


On 4/18/20 9:34 AM, Anton Baskanov wrote:
> Signed-off-by: Anton Baskanov <baskanov at gmail.com>
> ---
>  dlls/amstream/audiostream.c    | 66 ++++++++++++++++++++++-
>  dlls/amstream/tests/amstream.c | 99 ++++++++++++++++++++++++++++++++--
>  2 files changed, 159 insertions(+), 6 deletions(-)
> 
> diff --git a/dlls/amstream/audiostream.c b/dlls/amstream/audiostream.c
> index 26d615ebf4..81cd2975c8 100644
> --- a/dlls/amstream/audiostream.c
> +++ b/dlls/amstream/audiostream.c
> @@ -166,6 +166,17 @@ static HRESULT audiostreamsample_create(IAudioMediaStream *parent, IAudioData *a
>      return S_OK;
>  }
>  
> +enum queued_event_type
> +{
> +    QET_END_OF_STREAM
> +};
> +
> +struct queued_event
> +{
> +    struct list entry;
> +    enum queued_event_type type;
> +};
> +
>  struct audio_stream
>  {
>      IAMMediaStream IAMMediaStream_iface;
> @@ -185,8 +196,27 @@ struct audio_stream
>      AM_MEDIA_TYPE mt;
>      WAVEFORMATEX format;
>      FILTER_STATE state;
> +    BOOL eos;
> +    struct list event_queue;
>  };
>  
> +static void remove_queued_event(struct queued_event *event)
> +{
> +    list_remove(&event->entry);
> +    HeapFree(GetProcessHeap(), 0, event);
> +}
> +
> +static void flush_event_queue(struct audio_stream *stream)
> +{
> +    while (!list_empty(&stream->event_queue))
> +    {
> +        struct queued_event *event =
> +            LIST_ENTRY(list_head(&stream->event_queue), struct queued_event, entry);
> +
> +        remove_queued_event(event);
> +    }
> +}
> +
>  static inline struct audio_stream *impl_from_IAMMediaStream(IAMMediaStream *iface)
>  {
>      return CONTAINING_RECORD(iface, struct audio_stream, IAMMediaStream_iface);
> @@ -347,6 +377,11 @@ static HRESULT WINAPI audio_IAMMediaStream_SetState(IAMMediaStream *iface, FILTE
>  
>      EnterCriticalSection(&This->cs);
>  
> +    if (State_Stopped == state)
> +        flush_event_queue(This);
> +    if (State_Stopped == This->state)
> +        This->eos = FALSE;

This works, but it feels a little clearer to me to have

if (state == State_Stopped)
{
    flush_event_queue(This);
    This->eos = FALSE;
}

>      This->state = state;
>  
>      LeaveCriticalSection(&This->cs);
> @@ -919,8 +954,34 @@ static HRESULT WINAPI audio_sink_QueryInternalConnections(IPin *iface, IPin **pi
>  
>  static HRESULT WINAPI audio_sink_EndOfStream(IPin *iface)
>  {
> -    FIXME("iface %p, stub!\n", iface);
> -    return E_NOTIMPL;
> +    struct audio_stream *stream = impl_from_IPin(iface);
> +    struct queued_event *event;
> +
> +    TRACE("(%p/%p)->()\n", iface, stream);
> +
> +    EnterCriticalSection(&stream->cs);
> +
> +    if (stream->eos)
> +    {
> +        LeaveCriticalSection(&stream->cs);
> +        return E_FAIL;
> +    }
> +
> +    event = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*event));

amstream is compiled with msvcrt, so this can be calloc().

> +    if (!event)
> +    {
> +        LeaveCriticalSection(&stream->cs);
> +        return E_OUTOFMEMORY;
> +    }
> +
> +    event->type = QET_END_OF_STREAM;
> +    list_add_tail(&stream->event_queue, &event->entry);
> +
> +    stream->eos = TRUE;
> +
> +    LeaveCriticalSection(&stream->cs);
> +
> +    return S_OK;
>  }
>  
>  static HRESULT WINAPI audio_sink_BeginFlush(IPin *iface)
> @@ -1083,6 +1144,7 @@ HRESULT audio_stream_create(IMultiMediaStream *parent, const MSPID *purpose_id,
>      object->parent = parent;
>      object->purpose_id = *purpose_id;
>      object->stream_type = stream_type;
> +    list_init(&object->event_queue);
>  
>      *media_stream = &object->IAMMediaStream_iface;
>  
> diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c
> index 472c6558fc..2ac492bc3c 100644
> --- a/dlls/amstream/tests/amstream.c
> +++ b/dlls/amstream/tests/amstream.c
> @@ -2381,10 +2381,21 @@ static HRESULT testsource_query_accept(struct strmbase_pin *iface, const AM_MEDI
>      return S_OK;
>  }
>  
> -static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface,
> -        IMemInputPin *peer, IMemAllocator **allocator)
> +static HRESULT WINAPI testsource_decide_buffer_size(struct strmbase_source *iface,
> +        IMemAllocator *alloc, ALLOCATOR_PROPERTIES *requested)
>  {
> -    return S_OK;
> +    ALLOCATOR_PROPERTIES actual;
> +
> +    if (!requested->cbAlign)
> +        requested->cbAlign = 1;
> +
> +    if (requested->cbBuffer < 4096)
> +        requested->cbBuffer = 4096;
> +
> +    if (!requested->cBuffers)
> +        requested->cBuffers = 2;
> +
> +    return IMemAllocator_SetProperties(alloc, requested, &actual);
>  }
>  
>  static const struct strmbase_source_ops testsource_ops =
> @@ -2392,7 +2403,8 @@ static const struct strmbase_source_ops testsource_ops =
>      .base.pin_query_accept = testsource_query_accept,
>      .base.pin_get_media_type = strmbase_pin_get_media_type,
>      .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
> -    .pfnDecideAllocator = testsource_DecideAllocator,
> +    .pfnDecideBufferSize = testsource_decide_buffer_size,
> +    .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator,
>  };
>  
>  static void testfilter_init(struct testfilter *filter)
> @@ -2814,6 +2826,84 @@ static void test_audiostream_set_state(void)
>      ok(!ref, "Got outstanding refcount %d.\n", ref);
>  }
>  
> +void test_audiostream_end_of_stream(void)
> +{
> +    static const WAVEFORMATEX format =
> +    {
> +        .wFormatTag = WAVE_FORMAT_PCM,
> +        .nChannels = 1,
> +        .nSamplesPerSec = 11025,
> +        .wBitsPerSample = 16,
> +        .nBlockAlign = 2,
> +        .nAvgBytesPerSec = 2 * 11025,
> +    };
> +
> +    const AM_MEDIA_TYPE mt =
> +    {
> +        .majortype = MEDIATYPE_Audio,
> +        .subtype = MEDIASUBTYPE_PCM,
> +        .formattype = FORMAT_WaveFormatEx,
> +        .cbFormat = sizeof(WAVEFORMATEX),
> +        .pbFormat = (BYTE *)&format,
> +    };
> +
> +    IAMMultiMediaStream *mmstream = create_ammultimediastream();
> +    struct testfilter source;
> +    IGraphBuilder *graph;
> +    IMediaStream *stream;
> +    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_PrimaryAudio, 0, &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");
> +    testfilter_init(&source);
> +    hr = IGraphBuilder_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    hr = IGraphBuilder_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &mt);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    hr = IPin_EndOfStream(pin);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    hr = IPin_EndOfStream(pin);
> +    ok(hr == E_FAIL, "Got hr %#x.\n", hr);
> +
> +    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    hr = IPin_EndOfStream(pin);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    hr = IPin_EndOfStream(pin);
> +    ok(hr == E_FAIL, "Got hr %#x.\n", hr);
> +
> +    hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP);
> +    ok(hr == S_OK, "Got hr %#x.\n", hr);
> +
> +    hr = IPin_EndOfStream(pin);
> +    ok(hr == E_FAIL, "Got hr %#x.\n", hr);
> +
> +    IGraphBuilder_Disconnect(graph, pin);
> +    IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface);
> +
> +    ref = IAMMultiMediaStream_Release(mmstream);
> +    ok(!ref, "Got outstanding refcount %d.\n", ref);
> +    ref = IGraphBuilder_Release(graph);
> +    ok(!ref, "Got outstanding refcount %d.\n", ref);
> +    IPin_Release(pin);
> +    ref = IMediaStream_Release(stream);
> +    ok(!ref, "Got outstanding refcount %d.\n", ref);
> +}
> +
>  void test_mediastreamfilter_get_state(void)
>  {
>      IAMMultiMediaStream *mmstream = create_ammultimediastream();
> @@ -2986,6 +3076,7 @@ START_TEST(amstream)
>      test_audiostream_set_format();
>      test_audiostream_receive_connection();
>      test_audiostream_set_state();
> +    test_audiostream_end_of_stream();
>  
>      test_mediastreamfilter_get_state();
>      test_mediastreamfilter_stop_pause_run();
> 



More information about the wine-devel mailing list