Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/mfreadwrite/main.c | 143 +++++++++++++++++++++++++++++++- dlls/mfreadwrite/tests/mfplat.c | 20 ++++- 2 files changed, 159 insertions(+), 4 deletions(-)
diff --git a/dlls/mfreadwrite/main.c b/dlls/mfreadwrite/main.c index 7ebfa0cc21..2a0a1287d6 100644 --- a/dlls/mfreadwrite/main.c +++ b/dlls/mfreadwrite/main.c @@ -102,6 +102,7 @@ struct media_stream enum media_stream_state state; BOOL selected; BOOL presented; + DWORD read_samples_queue; };
struct source_reader @@ -109,6 +110,7 @@ struct source_reader IMFSourceReader IMFSourceReader_iface; IMFAsyncCallback source_events_callback; IMFAsyncCallback stream_events_callback; + IMFAsyncCallback read_samples_callback; LONG refcount; IMFMediaSource *source; IMFPresentationDescriptor *descriptor; @@ -143,6 +145,11 @@ static struct source_reader *impl_from_stream_callback_IMFAsyncCallback(IMFAsync return CONTAINING_RECORD(iface, struct source_reader, stream_events_callback); }
+static struct source_reader *impl_from_read_samples_callback_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct source_reader, read_samples_callback); +} + static inline struct sink_writer *impl_from_IMFSinkWriter(IMFSinkWriter *iface) { return CONTAINING_RECORD(iface, struct sink_writer, IMFSinkWriter_iface); @@ -587,6 +594,8 @@ static ULONG WINAPI src_reader_Release(IMFSourceReader *iface) list_remove(&ptr->entry); heap_free(ptr); } + + MFUnlockWorkQueue(stream->read_samples_queue); } heap_free(reader->streams); DeleteCriticalSection(&reader->cs); @@ -1187,13 +1196,138 @@ static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD ind return hr; }
-static HRESULT source_reader_read_sample_async(struct source_reader *reader, DWORD index, DWORD flags) +static HRESULT WINAPI source_reader_read_samples_callback_QueryInterface(IMFAsyncCallback *iface, + REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFAsyncCallback) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI source_reader_read_samples_callback_AddRef(IMFAsyncCallback *iface) +{ + struct source_reader *reader = impl_from_read_samples_callback_IMFAsyncCallback(iface); + return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface); +} + +static ULONG WINAPI source_reader_read_samples_callback_Release(IMFAsyncCallback *iface) { - FIXME("Async mode is not implemented.\n"); + struct source_reader *reader = impl_from_read_samples_callback_IMFAsyncCallback(iface); + return IMFSourceReader_Release(&reader->IMFSourceReader_iface); +}
+static HRESULT WINAPI source_reader_read_samples_callback_GetParameters(IMFAsyncCallback *iface, + DWORD *flags, DWORD *queue) +{ return E_NOTIMPL; }
+static HRESULT WINAPI source_reader_read_samples_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct source_reader *reader = impl_from_read_samples_callback_IMFAsyncCallback(iface); + IMFMediaStream *state = (IMFMediaStream *) IMFAsyncResult_GetStateNoAddRef(result); + DWORD id = 0; + HRESULT hr; + + TRACE("%p, %p\n", iface, result); + + if (FAILED(hr = media_stream_get_id(state, &id))) + { + WARN("Bad stream %p, hr %#x.\n", state, hr); + } + + for (unsigned int i = 0; i < reader->stream_count; ++i) + { + if (id == reader->streams[i].id) + { + struct media_stream *stream = &reader->streams[i]; + IMFSample *sample = NULL; + DWORD stream_flags; + LONGLONG timestamp = 0; + + hr = next_sample(stream, &sample, &stream_flags, FALSE); + if (sample) + { + IMFSample_GetSampleTime(sample, ×tamp); + } + + TRACE("Invoking read sample callback %p with (hr = %#x, stream_idx = %u, flags = %#x, timestamp %lu, sample %p)\n", reader->async_callback, hr, i, stream_flags, timestamp, sample); + hr = IMFSourceReaderCallback_OnReadSample(reader->async_callback, hr, i, stream_flags, timestamp, sample); + IMFSample_Release(sample); + return hr; + } + } + + return S_OK; +} + +static const IMFAsyncCallbackVtbl read_samples_callback_vtbl = +{ + source_reader_read_samples_callback_QueryInterface, + source_reader_read_samples_callback_AddRef, + source_reader_read_samples_callback_Release, + source_reader_read_samples_callback_GetParameters, + source_reader_read_samples_callback_Invoke, +}; + +static HRESULT source_reader_read_sample_async(struct source_reader *reader, DWORD index, DWORD flags) +{ + struct media_stream *stream; + DWORD stream_index; + HRESULT hr = S_OK; + BOOL selected; + + switch (index) + { + case MF_SOURCE_READER_FIRST_VIDEO_STREAM: + stream_index = reader->first_video_stream_index; + break; + case MF_SOURCE_READER_FIRST_AUDIO_STREAM: + stream_index = reader->first_audio_stream_index; + break; + case MF_SOURCE_READER_ANY_STREAM: + FIXME("Non-specific requests are not supported.\n"); + return E_NOTIMPL; + default: + stream_index = index; + } + + /* Can't read from deselected streams. */ + if (FAILED(hr = source_reader_get_stream_selection(reader, stream_index, &selected)) && !selected) + return hr; + + stream = &reader->streams[stream_index]; + + if (FAILED(hr = source_reader_start_source(reader))) + return hr; + + EnterCriticalSection(&stream->cs); + while(!stream->stream) + { + SleepConditionVariableCS(&stream->sample_event, &stream->cs, INFINITE); + } + LeaveCriticalSection(&stream->cs); + + TRACE("Dispatching read sample callback for stream %p\n", stream->stream); + if (FAILED(hr = MFPutWorkItem(stream->read_samples_queue, &reader->read_samples_callback, (IUnknown*)stream->stream))) + { + WARN("Failed to submit item hr = %#x\n", hr); + return E_FAIL; + } + + return S_OK; +} + static HRESULT WINAPI src_reader_ReadSample(IMFSourceReader *iface, DWORD index, DWORD flags, DWORD *actual_index, DWORD *stream_flags, LONGLONG *timestamp, IMFSample **sample) { @@ -1379,6 +1513,7 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri object->IMFSourceReader_iface.lpVtbl = &srcreader_vtbl; object->source_events_callback.lpVtbl = &source_events_callback_vtbl; object->stream_events_callback.lpVtbl = &stream_events_callback_vtbl; + object->read_samples_callback.lpVtbl = &read_samples_callback_vtbl; object->refcount = 1; object->source = source; IMFMediaSource_AddRef(object->source); @@ -1404,6 +1539,10 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri IMFMediaType *src_type; BOOL selected;
+ + if (FAILED(hr = MFAllocateWorkQueue(&object->streams[i].read_samples_queue))) + break; + if (FAILED(hr = MFCreateMediaType(&object->streams[i].current))) break;
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index e03d74981a..2bc9e2c40f 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -562,11 +562,18 @@ static ULONG WINAPI async_callback_Release(IMFSourceReaderCallback *iface) return refcount; }
+static HANDLE on_read_sample_event = INVALID_HANDLE_VALUE; + static HRESULT WINAPI async_callback_OnReadSample(IMFSourceReaderCallback *iface, HRESULT hr, DWORD stream_index, DWORD stream_flags, LONGLONG timestamp, IMFSample *sample) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + ok(hr == S_OK, "Unexpected hr %#x\n", hr); + ok(!stream_flags, "Unexpected stream flags %#x.\n", stream_flags); + ok(!!sample, "Didn't receive sample.\n"); + + SetEvent(on_read_sample_event); + + return S_OK; }
static HRESULT WINAPI async_callback_OnFlush(IMFSourceReaderCallback *iface, DWORD stream_index) @@ -951,6 +958,15 @@ todo_wine hr = IMFSourceReader_ReadSample(reader, 0, 0, NULL, NULL, NULL, &sample); ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+ on_read_sample_event = CreateEventA(NULL, FALSE, FALSE, NULL); + + hr = IMFSourceReader_ReadSample(reader, 0, 0, NULL, NULL, NULL, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + ok(WaitForSingleObject(on_read_sample_event, 3000) == WAIT_OBJECT_0, "Sample never triggered.\n"); + + CloseHandle(on_read_sample_event); + IMFSourceReader_Release(reader); }