diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index e46b6003ebc..c4a5981ea72 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) + selection = !!selection; + + EnterCriticalSection(&reader->cs); + + if (index == MF_SOURCE_READER_ALL_STREAMS) { - 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; - - for (index = 0; index < count; ++index) + 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); + } + } + else + { + 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: + ; + } + + source_reader_get_stream_selection(reader, index, &selected); + if (selected ^ selection) + selection_changed = TRUE; + + if (selection) + hr = IMFPresentationDescriptor_SelectStream(reader->descriptor, index); + else + hr = IMFPresentationDescriptor_DeselectStream(reader->descriptor, index); } - if (selected) - 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; + } - if (FAILED(hr)) - return MF_E_INVALIDSTREAMNUMBER; + LeaveCriticalSection(&reader->cs); - return S_OK; + 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 c35cfa3c0c4..8ed94289703 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -847,17 +847,13 @@ 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); - } -} + 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); @@ -868,17 +864,32 @@ todo_wine { { 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); + } + + hr = IMFSourceReader_SetStreamSelection(reader, 0, FALSE); + ok(hr == S_OK, "Failed to select a stream, hr %#x.\n", hr); + + 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); + 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); } IMFSourceReader_Release(reader);