Signed-off-by: Nikolay Sivov <nsivov(a)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,
×tamp, &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,
+ ×tamp, &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,
×tamp, &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