[PATCH v1 3/3] mfreadwrite: Implement MF_SOURCE_READER_ASYNC_CALLBACK.

Derek Lesho dlesho at codeweavers.com
Tue Mar 17 11:48:45 CDT 2020


Signed-off-by: Derek Lesho <dlesho at 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, &timestamp);
+            }
+
+            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);
 }
 
-- 
2.25.1




More information about the wine-devel mailing list