[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