[PATCH 1/2] mfreadwrite: Implement MF_SOURCE_READER_ANY_STREAM for synchronous case.

Nikolay Sivov nsivov at codeweavers.com
Mon Apr 6 09:19:29 CDT 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfreadwrite/reader.c       | 146 ++++++++++++++++++++------------
 dlls/mfreadwrite/tests/mfplat.c |  43 ++++++----
 2 files changed, 119 insertions(+), 70 deletions(-)

diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c
index e46b6003eb..c4a5981ea7 100644
--- a/dlls/mfreadwrite/reader.c
+++ b/dlls/mfreadwrite/reader.c
@@ -98,9 +98,10 @@ enum media_source_state
 
 enum media_stream_flags
 {
-    STREAM_FLAG_SAMPLE_REQUESTED = 0x1,
-    STREAM_FLAG_SELECTED = 0x2,
-    STREAM_FLAG_PRESENTED = 0x4,
+    STREAM_FLAG_SAMPLE_REQUESTED = 0x1, /* Protects from making multiple sample requests. */
+    STREAM_FLAG_SELECTED = 0x2,         /* Mirrors descriptor, used to simplify tests when starting the source. */
+    STREAM_FLAG_PRESENTED = 0x4,        /* Set if stream was selected last time Start() was called. */
+    STREAM_FLAG_REQUESTED_ONCE = 0x8,   /* Used for MF_SOURCE_READER_ANY_STREAM in synchronous mode. */
 };
 
 struct media_stream
@@ -363,7 +364,9 @@ static HRESULT source_reader_request_sample(struct source_reader *reader, struct
         if (FAILED(hr = IMFMediaStream_RequestSample(stream->stream, NULL)))
             WARN("Sample request failed, hr %#x.\n", hr);
         else
-            stream->flags |= STREAM_FLAG_SAMPLE_REQUESTED;
+        {
+            stream->flags |= (STREAM_FLAG_SAMPLE_REQUESTED | STREAM_FLAG_REQUESTED_ONCE);
+        }
     }
 
     return hr;
@@ -852,16 +855,19 @@ static HRESULT source_reader_start_source(struct source_reader *reader)
     HRESULT hr = S_OK;
     unsigned int i;
 
+    for (i = 0; i < reader->stream_count; ++i)
+    {
+        source_reader_get_stream_selection(reader, i, &selected);
+        if (selected)
+            reader->streams[i].flags |= STREAM_FLAG_SELECTED;
+        else
+            reader->streams[i].flags &= ~STREAM_FLAG_SELECTED;
+    }
+
     if (reader->source_state == SOURCE_STATE_STARTED)
     {
         for (i = 0; i < reader->stream_count; ++i)
         {
-            if (FAILED(hr = source_reader_get_stream_selection(reader, i, &selected)))
-                return hr;
-            if (selected)
-                reader->streams[i].flags |= STREAM_FLAG_SELECTED;
-            else
-                reader->streams[i].flags &= ~STREAM_FLAG_SELECTED;
             selection_changed = !!(reader->streams[i].flags & STREAM_FLAG_SELECTED) ^
                     !!(reader->streams[i].flags & STREAM_FLAG_PRESENTED);
             if (selection_changed)
@@ -940,10 +946,29 @@ static BOOL source_reader_get_read_result(struct source_reader *reader, struct m
     return !request_sample;
 }
 
-static HRESULT source_reader_get_stream_read_index(struct source_reader *reader, unsigned int index, unsigned int *stream_index)
+static HRESULT source_reader_get_first_selected_stream(struct source_reader *reader, unsigned int flags,
+        unsigned int *stream_index)
 {
     unsigned int i;
     BOOL selected;
+
+    for (i = 0; i < reader->stream_count; ++i)
+    {
+        source_reader_get_stream_selection(reader, i, &selected);
+        if (SUCCEEDED(source_reader_get_stream_selection(reader, i, &selected)) && selected &&
+                !(reader->streams[i].flags & flags))
+        {
+            *stream_index = i;
+            break;
+        }
+    }
+
+    return i == reader->stream_count ? MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED : S_OK;
+}
+
+static HRESULT source_reader_get_stream_read_index(struct source_reader *reader, unsigned int index, unsigned int *stream_index)
+{
+    BOOL selected;
     HRESULT hr;
 
     switch (index)
@@ -958,23 +983,15 @@ static HRESULT source_reader_get_stream_read_index(struct source_reader *reader,
             if (reader->async_callback)
             {
                 /* Pick first selected stream. */
-                for (i = 0; i < reader->stream_count; ++i)
-                {
-                    if (SUCCEEDED(source_reader_get_stream_selection(reader, i, &selected)) && selected)
-                    {
-                        *stream_index = i;
-                        break;
-                    }
-                }
-
-                if (i == reader->stream_count)
-                    return MF_E_MEDIA_SOURCE_NO_STREAMS_SELECTED;
+                hr = source_reader_get_first_selected_stream(reader, 0, stream_index);
             }
             else
             {
-                FIXME("Non-specific requests are not supported.\n");
-                return E_NOTIMPL;
+                /* Cycle through all selected streams once, next pick first selected. */
+                if (FAILED(hr = source_reader_get_first_selected_stream(reader, STREAM_FLAG_REQUESTED_ONCE, stream_index)))
+                    hr = source_reader_get_first_selected_stream(reader, 0, stream_index);
             }
+            return hr;
         default:
             *stream_index = index;
     }
@@ -1233,48 +1250,69 @@ static HRESULT WINAPI src_reader_GetStreamSelection(IMFSourceReader *iface, DWOR
     return source_reader_get_stream_selection(reader, index, selected);
 }
 
-static HRESULT WINAPI src_reader_SetStreamSelection(IMFSourceReader *iface, DWORD index, BOOL selected)
+static HRESULT WINAPI src_reader_SetStreamSelection(IMFSourceReader *iface, DWORD index, BOOL selection)
 {
     struct source_reader *reader = impl_from_IMFSourceReader(iface);
-    unsigned int count;
-    HRESULT hr;
+    HRESULT hr = S_OK;
+    BOOL selection_changed = FALSE, selected;
+    unsigned int i;
 
-    TRACE("%p, %#x, %d.\n", iface, index, selected);
+    TRACE("%p, %#x, %d.\n", iface, index, selection);
 
-    switch (index)
-    {
-        case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
-            index = reader->first_video_stream_index;
-            break;
-        case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
-            index = reader->first_audio_stream_index;
-            break;
-        case MF_SOURCE_READER_ALL_STREAMS:
-            if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(reader->descriptor, &count)))
-                return hr;
+    selection = !!selection;
 
-            for (index = 0; index < count; ++index)
+    EnterCriticalSection(&reader->cs);
+
+    if (index == MF_SOURCE_READER_ALL_STREAMS)
+    {
+        for (i = 0; i < reader->stream_count; ++i)
+        {
+            if (!selection_changed)
             {
-                if (selected)
-                    IMFPresentationDescriptor_SelectStream(reader->descriptor, index);
-                else
-                    IMFPresentationDescriptor_DeselectStream(reader->descriptor, index);
+                source_reader_get_stream_selection(reader, i, &selected);
+                if (selected ^ selection)
+                    selection_changed = TRUE;
             }
 
-            return S_OK;
-        default:
-            ;
+            if (selection)
+                IMFPresentationDescriptor_SelectStream(reader->descriptor, i);
+            else
+                IMFPresentationDescriptor_DeselectStream(reader->descriptor, i);
+        }
     }
-
-    if (selected)
-        hr = IMFPresentationDescriptor_SelectStream(reader->descriptor, index);
     else
-        hr = IMFPresentationDescriptor_DeselectStream(reader->descriptor, index);
+    {
+        switch (index)
+        {
+            case MF_SOURCE_READER_FIRST_VIDEO_STREAM:
+                index = reader->first_video_stream_index;
+                break;
+            case MF_SOURCE_READER_FIRST_AUDIO_STREAM:
+                index = reader->first_audio_stream_index;
+                break;
+            default:
+                ;
+        }
 
-    if (FAILED(hr))
-        return MF_E_INVALIDSTREAMNUMBER;
+        source_reader_get_stream_selection(reader, index, &selected);
+        if (selected ^ selection)
+            selection_changed = TRUE;
 
-    return S_OK;
+        if (selection)
+            hr = IMFPresentationDescriptor_SelectStream(reader->descriptor, index);
+        else
+            hr = IMFPresentationDescriptor_DeselectStream(reader->descriptor, index);
+    }
+
+    if (SUCCEEDED(hr) && selection_changed)
+    {
+        for (i = 0; i < reader->stream_count; ++i)
+            reader->streams[i].flags &= ~STREAM_FLAG_REQUESTED_ONCE;
+    }
+
+    LeaveCriticalSection(&reader->cs);
+
+    return SUCCEEDED(hr) ? S_OK : MF_E_INVALIDSTREAMNUMBER;
 }
 
 static HRESULT source_reader_get_native_media_type(struct source_reader *reader, DWORD index, DWORD type_index,
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c
index c35cfa3c0c..8ed9428970 100644
--- a/dlls/mfreadwrite/tests/mfplat.c
+++ b/dlls/mfreadwrite/tests/mfplat.c
@@ -847,38 +847,49 @@ static void test_source_reader_from_media_source(void)
 
     hr = IMFSourceReader_ReadSample(reader, MF_SOURCE_READER_ANY_STREAM, 0, &actual_index, &stream_flags,
             &timestamp, &sample);
-todo_wine {
     ok(hr == S_OK, "Failed to get a sample, hr %#x.\n", hr);
-    if (SUCCEEDED(hr))
+    ok(actual_index == 1, "Unexpected stream index %u\n", actual_index);
+    ok(!stream_flags, "Unexpected stream flags %#x.\n", stream_flags);
+    ok(timestamp == 123, "Unexpected timestamp.\n");
+    ok(!!sample, "Expected sample object.\n");
+    IMFSample_Release(sample);
+
+    hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE);
+    ok(hr == S_OK, "Failed to select a stream, hr %#x.\n", hr);
+
+    hr = IMFSourceReader_SetStreamSelection(reader, 2, TRUE);
+    ok(hr == S_OK, "Failed to select a stream, hr %#x.\n", hr);
+
+    for (i = 0; i < 2 * TEST_SOURCE_NUM_STREAMS; ++i)
     {
-        ok(actual_index == 1, "Unexpected stream index %u\n", actual_index);
+        hr = IMFSourceReader_ReadSample(reader, MF_SOURCE_READER_ANY_STREAM, 0, &actual_index, &stream_flags,
+                &timestamp, &sample);
+        ok(hr == S_OK, "Failed to get a sample, hr %#x.\n", hr);
+        ok(actual_index == (i < TEST_SOURCE_NUM_STREAMS ? i : 0), "%d: Unexpected stream index %u\n",
+                i, actual_index);
         ok(!stream_flags, "Unexpected stream flags %#x.\n", stream_flags);
         ok(timestamp == 123, "Unexpected timestamp.\n");
         ok(!!sample, "Expected sample object.\n");
         IMFSample_Release(sample);
     }
-}
-    hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE);
+
+    hr = IMFSourceReader_SetStreamSelection(reader, 0, FALSE);
     ok(hr == S_OK, "Failed to select a stream, hr %#x.\n", hr);
 
-    hr = IMFSourceReader_SetStreamSelection(reader, 2, TRUE);
+    hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE);
     ok(hr == S_OK, "Failed to select a stream, hr %#x.\n", hr);
 
     for (i = 0; i < 2 * TEST_SOURCE_NUM_STREAMS; ++i)
     {
         hr = IMFSourceReader_ReadSample(reader, MF_SOURCE_READER_ANY_STREAM, 0, &actual_index, &stream_flags,
                 &timestamp, &sample);
-todo_wine
         ok(hr == S_OK, "Failed to get a sample, hr %#x.\n", hr);
-        if (SUCCEEDED(hr))
-        {
-            ok(actual_index == (i < TEST_SOURCE_NUM_STREAMS ? i : 0), "%d: Unexpected stream index %u\n",
-                    i, actual_index);
-            ok(!stream_flags, "Unexpected stream flags %#x.\n", stream_flags);
-            ok(timestamp == 123, "Unexpected timestamp.\n");
-            ok(!!sample, "Expected sample object.\n");
-            IMFSample_Release(sample);
-        }
+        ok(actual_index == (i < TEST_SOURCE_NUM_STREAMS ? i : 0), "%d: Unexpected stream index %u\n",
+                i, actual_index);
+        ok(!stream_flags, "Unexpected stream flags %#x.\n", stream_flags);
+        ok(timestamp == 123, "Unexpected timestamp.\n");
+        ok(!!sample, "Expected sample object.\n");
+        IMFSample_Release(sample);
     }
 
     IMFSourceReader_Release(reader);
-- 
2.25.1




More information about the wine-devel mailing list