[PATCH] mfreadwrite/tests: Add some tests for "any"-stream requests.

Nikolay Sivov nsivov at codeweavers.com
Mon Nov 4 14:02:45 CST 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfreadwrite/tests/mfplat.c | 511 ++++++++++++++++++++++++++++++++
 1 file changed, 511 insertions(+)

diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c
index b86fb060fd..ba9023b289 100644
--- a/dlls/mfreadwrite/tests/mfplat.c
+++ b/dlls/mfreadwrite/tests/mfplat.c
@@ -52,6 +52,412 @@ static void init_functions(void)
 #undef X
 }
 
+enum source_state
+{
+    SOURCE_STOPPED = 0,
+    SOURCE_RUNNING,
+};
+
+struct test_media_stream
+{
+    IMFMediaStream IMFMediaStream_iface;
+    LONG refcount;
+    IMFMediaSource *source;
+    IMFStreamDescriptor *sd;
+    IMFMediaEventQueue *event_queue;
+    BOOL is_new;
+};
+
+static struct test_media_stream *impl_from_IMFMediaStream(IMFMediaStream *iface)
+{
+    return CONTAINING_RECORD(iface, struct test_media_stream, IMFMediaStream_iface);
+}
+
+static HRESULT WINAPI test_media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out)
+{
+    if (IsEqualIID(riid, &IID_IMFMediaStream)
+            || IsEqualIID(riid, &IID_IMFMediaEventGenerator)
+            || IsEqualIID(riid, &IID_IUnknown))
+    {
+        *out = iface;
+    }
+    else
+    {
+        *out = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IMFMediaStream_AddRef(iface);
+    return S_OK;
+}
+
+static ULONG WINAPI test_media_stream_AddRef(IMFMediaStream *iface)
+{
+    struct test_media_stream *stream = impl_from_IMFMediaStream(iface);
+    return InterlockedIncrement(&stream->refcount);
+}
+
+static ULONG WINAPI test_media_stream_Release(IMFMediaStream *iface)
+{
+    struct test_media_stream *stream = impl_from_IMFMediaStream(iface);
+    ULONG refcount = InterlockedDecrement(&stream->refcount);
+
+    if (!refcount)
+    {
+        IMFMediaEventQueue_Release(stream->event_queue);
+        heap_free(stream);
+    }
+
+    return refcount;
+}
+
+static HRESULT WINAPI test_media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event)
+{
+    struct test_media_stream *stream = impl_from_IMFMediaStream(iface);
+    return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event);
+}
+
+static HRESULT WINAPI test_media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state)
+{
+    struct test_media_stream *stream = impl_from_IMFMediaStream(iface);
+    ok(callback != NULL && state == (IUnknown *)iface, "Unexpected arguments.\n");
+    return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state);
+}
+
+static HRESULT WINAPI test_media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event)
+{
+    struct test_media_stream *stream = impl_from_IMFMediaStream(iface);
+    ok(!!result && !!event, "Unexpected arguments.\n");
+    return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event);
+}
+
+static HRESULT WINAPI test_media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type,
+        HRESULT hr, const PROPVARIANT *value)
+{
+    struct test_media_stream *stream = impl_from_IMFMediaStream(iface);
+    return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value);
+}
+
+static HRESULT WINAPI test_media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **source)
+{
+    struct test_media_stream *stream = impl_from_IMFMediaStream(iface);
+
+    *source = stream->source;
+    IMFMediaSource_AddRef(*source);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI test_media_stream_GetStreamDescriptor(IMFMediaStream *iface, IMFStreamDescriptor **sd)
+{
+    struct test_media_stream *stream = impl_from_IMFMediaStream(iface);
+
+    *sd = stream->sd;
+    IMFStreamDescriptor_AddRef(*sd);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI test_media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
+{
+    struct test_media_stream *stream = impl_from_IMFMediaStream(iface);
+    IMFMediaBuffer *buffer;
+    IMFSample *sample;
+    HRESULT hr;
+
+    hr = MFCreateSample(&sample);
+    ok(hr == S_OK, "Failed to create a sample, hr %#x.\n", hr);
+    hr = IMFSample_SetSampleTime(sample, 123);
+    ok(hr == S_OK, "Failed to set sample time, hr %#x.\n", hr);
+    if (token)
+        IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token);
+
+    /* Reader expects buffers, empty samples are considered an error. */
+    hr = MFCreateMemoryBuffer(8, &buffer);
+    ok(hr == S_OK, "Failed to create a buffer, hr %#x.\n", hr);
+    hr = IMFSample_AddBuffer(sample, buffer);
+    ok(hr == S_OK, "Failed to add a buffer, hr %#x.\n", hr);
+    IMFMediaBuffer_Release(buffer);
+
+    hr = IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample, &GUID_NULL, S_OK, 
+            (IUnknown *)sample);
+    ok(hr == S_OK, "Failed to submit event, hr %#x.\n", hr);
+    IMFSample_Release(sample);
+
+    return S_OK;
+}
+
+static const IMFMediaStreamVtbl test_media_stream_vtbl =
+{
+    test_media_stream_QueryInterface,
+    test_media_stream_AddRef,
+    test_media_stream_Release,
+    test_media_stream_GetEvent,
+    test_media_stream_BeginGetEvent,
+    test_media_stream_EndGetEvent,
+    test_media_stream_QueueEvent,
+    test_media_stream_GetMediaSource,
+    test_media_stream_GetStreamDescriptor,
+    test_media_stream_RequestSample,
+};
+
+#define TEST_SOURCE_NUM_STREAMS 3
+
+struct test_source
+{
+    IMFMediaSource IMFMediaSource_iface;
+    LONG refcount;
+    IMFMediaEventQueue *event_queue;
+    IMFPresentationDescriptor *pd;
+    struct test_media_stream *streams[TEST_SOURCE_NUM_STREAMS];
+    enum source_state state;
+    CRITICAL_SECTION cs;
+};
+
+static struct test_source *impl_from_IMFMediaSource(IMFMediaSource *iface)
+{
+    return CONTAINING_RECORD(iface, struct test_source, IMFMediaSource_iface);
+}
+
+static HRESULT WINAPI test_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
+{
+    if (IsEqualIID(riid, &IID_IMFMediaSource)
+            || IsEqualIID(riid, &IID_IMFMediaEventGenerator)
+            || IsEqualIID(riid, &IID_IUnknown))
+    {
+        *out = iface;
+    }
+    else
+    {
+        *out = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IMFMediaSource_AddRef(iface);
+    return S_OK;
+}
+
+static ULONG WINAPI test_source_AddRef(IMFMediaSource *iface)
+{
+    struct test_source *source = impl_from_IMFMediaSource(iface);
+    return InterlockedIncrement(&source->refcount);
+}
+
+static ULONG WINAPI test_source_Release(IMFMediaSource *iface)
+{
+    struct test_source *source = impl_from_IMFMediaSource(iface);
+    ULONG refcount = InterlockedDecrement(&source->refcount);
+
+    if (!refcount)
+    {
+        IMFMediaEventQueue_Release(source->event_queue);
+        heap_free(source);
+    }
+
+    return refcount;
+}
+
+static HRESULT WINAPI test_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event)
+{
+    struct test_source *source = impl_from_IMFMediaSource(iface);
+    return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event);
+}
+
+static HRESULT WINAPI test_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
+{
+    struct test_source *source = impl_from_IMFMediaSource(iface);
+    ok(callback != NULL && state == (IUnknown *)iface, "Unexpected arguments source %p, %p, state %p.\n", iface, callback, state);
+    return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state);
+}
+
+static HRESULT WINAPI test_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event)
+{
+    struct test_source *source = impl_from_IMFMediaSource(iface);
+    return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event);
+}
+
+static HRESULT WINAPI test_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
+        HRESULT hr, const PROPVARIANT *value)
+{
+    struct test_source *source = impl_from_IMFMediaSource(iface);
+    return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value);
+}
+
+static HRESULT WINAPI test_source_GetCharacteristics(IMFMediaSource *iface, DWORD *flags)
+{
+    *flags = MFMEDIASOURCE_CAN_SEEK;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI test_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **pd)
+{
+    struct test_source *source = impl_from_IMFMediaSource(iface);
+    IMFStreamDescriptor *sds[ARRAY_SIZE(source->streams)];
+    IMFMediaType *media_type;
+    HRESULT hr = S_OK;
+    int i;
+
+    EnterCriticalSection(&source->cs);
+
+    if (source->pd)
+    {
+        *pd = source->pd;
+        IMFPresentationDescriptor_AddRef(*pd);
+    }
+    else
+    {
+        for (i = 0; i < ARRAY_SIZE(source->streams); ++i)
+        {
+            MFCreateMediaType(&media_type);
+
+            IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
+            IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
+
+            MFCreateStreamDescriptor(i, 1, &media_type, &sds[i]);
+
+            IMFMediaType_Release(media_type);
+        }
+
+        MFCreatePresentationDescriptor(ARRAY_SIZE(sds), sds, &source->pd);
+        for (i = 0; i < ARRAY_SIZE(sds); ++i)
+            IMFStreamDescriptor_Release(sds[i]);
+
+        *pd = source->pd;
+        IMFPresentationDescriptor_AddRef(*pd);
+    }
+
+    LeaveCriticalSection(&source->cs);
+
+    return hr;
+}
+
+static BOOL is_stream_selected(IMFPresentationDescriptor *pd, DWORD index)
+{
+    IMFStreamDescriptor *sd;
+    BOOL selected = FALSE;
+
+    if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, index, &selected, &sd)))
+        IMFStreamDescriptor_Release(sd);
+
+    return selected;
+}
+
+static HRESULT WINAPI test_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *pd, const GUID *time_format,
+        const PROPVARIANT *start_position)
+{
+    struct test_source *source = impl_from_IMFMediaSource(iface);
+    MediaEventType event_type;
+    PROPVARIANT var;
+    int i;
+
+todo_wine {
+    ok(time_format && IsEqualGUID(time_format, &GUID_NULL), "Unexpected time format %s.\n", wine_dbgstr_guid(time_format));
+    ok(start_position && (start_position->vt == VT_I8 || start_position->vt == VT_EMPTY), "Unexpected position type.\n");
+}
+    EnterCriticalSection(&source->cs);
+
+    event_type = source->state == SOURCE_RUNNING ? MESourceSeeked : MESourceStarted;
+    IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, &GUID_NULL, S_OK, NULL);
+
+    for (i = 0; i < ARRAY_SIZE(source->streams); ++i)
+    {
+        if (!is_stream_selected(pd, i))
+            continue;
+
+        var.vt = VT_UNKNOWN;
+        var.punkVal = (IUnknown *)&source->streams[i]->IMFMediaStream_iface;
+        event_type = source->streams[i]->is_new ? MENewStream : MEUpdatedStream;
+        source->streams[i]->is_new = FALSE;
+        IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, &GUID_NULL, S_OK, &var);
+
+        event_type = source->state == SOURCE_RUNNING ? MEStreamSeeked : MEStreamStarted;
+        IMFMediaEventQueue_QueueEventParamVar(source->streams[i]->event_queue, event_type, &GUID_NULL,
+                S_OK, NULL);
+    }
+
+    source->state = SOURCE_RUNNING;
+
+    LeaveCriticalSection(&source->cs);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI test_source_Stop(IMFMediaSource *iface)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_source_Pause(IMFMediaSource *iface)
+{
+    ok(0, "Unexpected call.\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI test_source_Shutdown(IMFMediaSource *iface)
+{
+    struct test_source *source = impl_from_IMFMediaSource(iface);
+
+    IMFMediaEventQueue_Shutdown(source->event_queue);
+
+    return S_OK;
+}
+
+static const IMFMediaSourceVtbl test_source_vtbl =
+{
+    test_source_QueryInterface,
+    test_source_AddRef,
+    test_source_Release,
+    test_source_GetEvent,
+    test_source_BeginGetEvent,
+    test_source_EndGetEvent,
+    test_source_QueueEvent,
+    test_source_GetCharacteristics,
+    test_source_CreatePresentationDescriptor,
+    test_source_Start,
+    test_source_Stop,
+    test_source_Pause,
+    test_source_Shutdown,
+};
+
+static struct test_media_stream *create_test_stream(DWORD stream_index, IMFMediaSource *source)
+{
+    struct test_media_stream *stream;
+    IMFPresentationDescriptor *pd;
+    BOOL selected;
+
+    stream = heap_alloc_zero(sizeof(*stream));
+    stream->IMFMediaStream_iface.lpVtbl = &test_media_stream_vtbl;
+    stream->refcount = 1;
+    MFCreateEventQueue(&stream->event_queue);
+    stream->source = source;
+    IMFMediaSource_AddRef(stream->source);
+    stream->is_new = TRUE;
+
+    IMFMediaSource_CreatePresentationDescriptor(source, &pd);
+    IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, stream_index, &selected, &stream->sd);
+    IMFPresentationDescriptor_Release(pd);
+
+    return stream;
+}
+
+static IMFMediaSource *create_test_source(void)
+{
+    struct test_source *source;
+    int i;
+
+    source = heap_alloc_zero(sizeof(*source));
+    source->IMFMediaSource_iface.lpVtbl = &test_source_vtbl;
+    source->refcount = 1;
+    MFCreateEventQueue(&source->event_queue);
+    InitializeCriticalSection(&source->cs);
+    for (i = 0; i < ARRAY_SIZE(source->streams); ++i)
+        source->streams[i] = create_test_stream(i, &source->IMFMediaSource_iface);
+
+    return &source->IMFMediaSource_iface;
+}
+
 static IMFByteStream *get_resource_stream(const char *name)
 {
     IMFByteStream *bytestream;
@@ -402,6 +808,110 @@ todo_wine
     IMFByteStream_Release(stream);
 }
 
+static void test_source_reader_from_media_source(void)
+{
+    struct async_callback *callback;
+    IMFSourceReader *reader;
+    IMFMediaSource *source;
+    HRESULT hr;
+    DWORD actual_index, stream_flags;
+    IMFSample *sample;
+    LONGLONG timestamp;
+    IMFAttributes *attributes;
+    int i;
+
+    source = create_test_source();
+    ok(!!source, "Failed to create test source.\n");
+
+    callback = create_async_callback();
+
+    hr = MFCreateAttributes(&attributes, 1);
+    ok(hr == S_OK, "Failed to create attributes object, hr %#x.\n", hr);
+
+    hr = IMFAttributes_SetUnknown(attributes, &MF_SOURCE_READER_ASYNC_CALLBACK,
+            (IUnknown *)&callback->IMFSourceReaderCallback_iface);
+    ok(hr == S_OK, "Failed to set attribute value, hr %#x.\n", hr);
+    IMFSourceReaderCallback_Release(&callback->IMFSourceReaderCallback_iface);
+
+    hr = MFCreateSourceReaderFromMediaSource(source, NULL, &reader);
+    ok(hr == S_OK, "Failed to create source reader, hr %#x.\n", hr);
+
+    /* MF_SOURCE_READER_ANY_STREAM */
+    hr = IMFSourceReader_SetStreamSelection(reader, 0, FALSE);
+    ok(hr == S_OK, "Failed to select a stream, hr %#x.\n", hr);
+
+    hr = IMFSourceReader_SetStreamSelection(reader, 1, TRUE);
+    ok(hr == S_OK, "Failed to select a stream, hr %#x.\n", hr);
+
+    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)
+    {
+        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);
+        }
+    }
+
+    IMFSourceReader_Release(reader);
+    IMFMediaSource_Release(source);
+
+    /* Async mode. */
+    source = create_test_source();
+    ok(!!source, "Failed to create test source.\n");
+
+    hr = MFCreateSourceReaderFromMediaSource(source, attributes, &reader);
+    ok(hr == S_OK, "Failed to create source reader, hr %#x.\n", hr);
+
+    hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE);
+    ok(hr == S_OK, "Failed to select a stream, hr %#x.\n", hr);
+
+    /* Return values are delivered to callback only. */
+    hr = IMFSourceReader_ReadSample(reader, 0, 0, &actual_index, &stream_flags, &timestamp, &sample);
+todo_wine
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+    hr = IMFSourceReader_ReadSample(reader, 0, 0, NULL, &stream_flags, &timestamp, &sample);
+todo_wine
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+    hr = IMFSourceReader_ReadSample(reader, 0, 0, NULL, NULL, &timestamp, &sample);
+todo_wine
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+    hr = IMFSourceReader_ReadSample(reader, 0, 0, NULL, NULL, NULL, &sample);
+todo_wine
+    ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
+
+    IMFSourceReader_Release(reader);
+}
+
 START_TEST(mfplat)
 {
     HRESULT hr;
@@ -413,6 +923,7 @@ START_TEST(mfplat)
 
     test_factory();
     test_source_reader();
+    test_source_reader_from_media_source();
 
     hr = MFShutdown();
     ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
-- 
2.24.0.rc1




More information about the wine-devel mailing list