[PATCH] mfreadwrite: Simplify iteration through streams.

Nikolay Sivov nsivov at codeweavers.com
Thu Mar 25 11:05:23 CDT 2021



On 3/25/21 6:41 PM, Giovanni Mascellani wrote:
> This also fixes a bug happening when the reader has only one stream,
> in which case the iteration body was not even executed once.
>
> Signed-off-by: Giovanni Mascellani <gmascellani at codeweavers.com>
> ---
>  dlls/mfreadwrite/reader.c       |  14 ++--
>  dlls/mfreadwrite/tests/mfplat.c | 142 ++++++++++++++++++++++++++++++++
>  2 files changed, 149 insertions(+), 7 deletions(-)
>
> diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c
> index 2819b800eb9..ab9f6c83674 100644
> --- a/dlls/mfreadwrite/reader.c
> +++ b/dlls/mfreadwrite/reader.c
> @@ -1087,13 +1087,10 @@ static BOOL source_reader_get_read_result(struct source_reader *reader, struct m
>  
>  static HRESULT source_reader_get_next_selected_stream(struct source_reader *reader, unsigned int *stream_index)
>  {
> -    unsigned int i, start_idx, stop_idx, first_selected = ~0u, requests = ~0u;
> +    unsigned int i, first_selected = ~0u, requests = ~0u;
>      BOOL selected, stream_drained;
>  
> -    start_idx = (reader->last_read_index + 1) % reader->stream_count;
> -    stop_idx = reader->last_read_index == ~0u ? reader->stream_count : reader->last_read_index;
> -
> -    for (i = start_idx; i < reader->stream_count && i != stop_idx; i = (i + 1) % (reader->stream_count + 1))
> +    for (i = (reader->last_read_index + 1) % reader->stream_count; ; i = (i + 1) % reader->stream_count)
>      {
>          stream_drained = reader->streams[i].state == STREAM_STATE_EOS && !reader->streams[i].responses;
>          selected = SUCCEEDED(source_reader_get_stream_selection(reader, i, &selected)) && selected;
> @@ -1110,6 +1107,9 @@ static HRESULT source_reader_get_next_selected_stream(struct source_reader *read
>                  *stream_index = i;
>              }
>          }
> +
> +        if (i == reader->last_read_index)
> +            break;
>      }
This looks good.
>  
>      /* If all selected streams reached EOS, use first selected. */
> @@ -1477,7 +1477,7 @@ static HRESULT WINAPI src_reader_SetStreamSelection(IMFSourceReader *iface, DWOR
>      }
>  
>      if (selection_changed)
> -        reader->last_read_index = ~0u;
> +        reader->last_read_index = reader->stream_count - 1;
>  
>      LeaveCriticalSection(&reader->cs);
>  
> @@ -2360,7 +2360,7 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri
>      /* At least one major type has to be set. */
>      object->first_audio_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Audio);
>      object->first_video_stream_index = reader_get_first_stream_index(object->descriptor, &MFMediaType_Video);
> -    object->last_read_index = ~0u;
> +    object->last_read_index = object->stream_count - 1;
>  
>      if (object->first_audio_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX &&
>              object->first_video_stream_index == MF_SOURCE_READER_INVALID_STREAM_INDEX)
> diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c
> index 25aa29ac272..e3ac0ae8006 100644
> --- a/dlls/mfreadwrite/tests/mfplat.c
> +++ b/dlls/mfreadwrite/tests/mfplat.c
> @@ -564,6 +564,105 @@ static void test_factory(void)
>      CoUninitialize();
>  }
>  
> +struct read_all_async_callback
> +{
> +    IMFSourceReaderCallback IMFSourceReaderCallback_iface;
> +    LONG refcount;
> +    HANDLE event;
> +    IMFSourceReader *reader;
> +};
> +
> +static struct read_all_async_callback *impl_read_all_async_callback_from_IMFSourceReaderCallback(IMFSourceReaderCallback *iface)
> +{
> +    return CONTAINING_RECORD(iface, struct read_all_async_callback, IMFSourceReaderCallback_iface);
> +}
> +
> +static HRESULT WINAPI read_all_async_callback_QueryInterface(IMFSourceReaderCallback *iface, REFIID riid, void **out)
> +{
> +    if (IsEqualIID(riid, &IID_IMFSourceReaderCallback) ||
> +            IsEqualIID(riid, &IID_IUnknown))
> +    {
> +        *out = iface;
> +        IMFSourceReaderCallback_AddRef(iface);
> +        return S_OK;
> +    }
> +
> +    *out = NULL;
> +    return E_NOINTERFACE;
> +}
> +
> +static ULONG WINAPI read_all_async_callback_AddRef(IMFSourceReaderCallback *iface)
> +{
> +    struct read_all_async_callback *callback = impl_read_all_async_callback_from_IMFSourceReaderCallback(iface);
> +    return InterlockedIncrement(&callback->refcount);
> +}
> +
> +static ULONG WINAPI read_all_async_callback_Release(IMFSourceReaderCallback *iface)
> +{
> +    struct read_all_async_callback *callback = impl_read_all_async_callback_from_IMFSourceReaderCallback(iface);
> +    ULONG refcount = InterlockedDecrement(&callback->refcount);
> +
> +    if (!refcount)
> +    {
> +        CloseHandle(callback->event);
> +        heap_free(callback);
> +    }
> +
> +    return refcount;
> +}
> +
> +static HRESULT WINAPI read_all_async_callback_OnReadSample(IMFSourceReaderCallback *iface, HRESULT hr, DWORD stream_index,
> +        DWORD stream_flags, LONGLONG timestamp, IMFSample *sample)
> +{
> +    struct read_all_async_callback *callback = impl_read_all_async_callback_from_IMFSourceReaderCallback(iface);
> +
> +    ok(hr == S_OK, "Failed to read sample, hr %#x.\n", hr);
> +
> +    if (stream_flags & MF_SOURCE_READERF_ENDOFSTREAM)
> +        SetEvent(callback->event);
> +    else
> +    {
> +        hr = IMFSourceReader_ReadSample(callback->reader, MF_SOURCE_READER_ANY_STREAM, 0, NULL, NULL, NULL, NULL);
> +        ok(hr == S_OK, "Failed to read sample, hr %#x.\n", hr);
> +    }
> +
> +    return S_OK;
> +}
> +
> +static HRESULT WINAPI read_all_async_callback_OnFlush(IMFSourceReaderCallback *iface, DWORD stream_index)
> +{
> +    ok(0, "Unexpected call.\n");
> +    return E_NOTIMPL;
> +}
> +
> +static HRESULT WINAPI read_all_async_callback_OnEvent(IMFSourceReaderCallback *iface, DWORD stream_index, IMFMediaEvent *event)
> +{
> +    ok(0, "Unexpected call.\n");
> +    return E_NOTIMPL;
> +}
> +
> +static const IMFSourceReaderCallbackVtbl read_all_async_callback_vtbl =
> +{
> +    read_all_async_callback_QueryInterface,
> +    read_all_async_callback_AddRef,
> +    read_all_async_callback_Release,
> +    read_all_async_callback_OnReadSample,
> +    read_all_async_callback_OnFlush,
> +    read_all_async_callback_OnEvent,
> +};
> +
> +static struct read_all_async_callback *create_read_all_async_callback(void)
> +{
> +    struct read_all_async_callback *callback;
> +
> +    callback = heap_alloc(sizeof(*callback));
> +    callback->IMFSourceReaderCallback_iface.lpVtbl = &read_all_async_callback_vtbl;
> +    callback->refcount = 1;
> +    callback->event = CreateEventW(NULL, FALSE, FALSE, NULL);
> +
> +    return callback;
> +}
> +
>  struct async_callback
>  {
>      IMFSourceReaderCallback IMFSourceReaderCallback_iface;
> @@ -1144,6 +1243,48 @@ done:
>      DestroyWindow(window);
>  }
>  
> +static void test_read_all(void)
> +{
> +    IMFByteStream *stream;
> +    IMFSourceReader *reader;
> +    IMFAttributes *attributes;
> +    struct read_all_async_callback *callback;
> +    HRESULT hr;
> +
> +    if (!pMFCreateMFByteStreamOnStream)
> +    {
> +        win_skip("MFCreateMFByteStreamOnStream() not found\n");
> +        return;
> +    }
> +
> +    stream = get_resource_stream("test.wav");
> +    callback = create_read_all_async_callback();
> +
> +    hr = MFCreateAttributes(&attributes, 1);
> +    ok(hr == S_OK, "Failed to create attributes object, hr %#x.\n", hr);
> +
> +    hr = IMFAttributes_SetUnknown(attributes, &MF_SOURCE_READER_ASYNC_CALLBACK,
> +                                  (IUnknown*)&callback->IMFSourceReaderCallback_iface);
> +    ok(hr == S_OK, "Failed to set attribute value, hr %#x.\n", hr);
> +
> +    hr = MFCreateSourceReaderFromByteStream(stream, attributes, &reader);
> +    ok(hr == S_OK, "Failed to create source reader, hr %#x.\n", hr);
> +    callback->reader = reader;
> +
> +    hr = IMFSourceReader_SetStreamSelection(reader, MF_SOURCE_READER_ALL_STREAMS, TRUE);
> +    ok(hr == S_OK, "Failed to select streams, hr %#x.\n", hr);
> +
> +    hr = IMFSourceReader_ReadSample(reader, MF_SOURCE_READER_ANY_STREAM, 0, NULL, NULL, NULL, NULL);
> +    ok(hr == S_OK, "Failed to read sample, hr %#x.\n", hr);
> +
> +    WaitForSingleObject(callback->event, INFINITE);
> +
> +    IMFSourceReader_Release(reader);
> +    IMFAttributes_Release(attributes);
> +    IMFSourceReaderCallback_Release(&callback->IMFSourceReaderCallback_iface);
> +    IMFByteStream_Release(stream);
> +}
> +
>  START_TEST(mfplat)
>  {
>      HRESULT hr;
> @@ -1157,6 +1298,7 @@ START_TEST(mfplat)
>      test_source_reader();
>      test_source_reader_from_media_source();
>      test_reader_d3d9();
> +    test_read_all();
>  
>      hr = MFShutdown();
>      ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
I don't see why such test complexity is necessary.We have some tests for
ANY_STREAM already, with a simple loop. It will be enough to extend
create_test_source() to have a limit of total number of streams, 1 for
this test, 3 otherwise.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20210325/951d5d7d/attachment-0001.htm>


More information about the wine-devel mailing list