[PATCH] mfreadwrite: Simplify iteration through streams.

Giovanni Mascellani gmascellani at codeweavers.com
Thu Mar 25 10:41:24 CDT 2021


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;
     }
 
     /* 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);
-- 
2.31.0




More information about the wine-devel mailing list