From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/mfmediaengine/tests/mfmediaengine.c | 395 +++++++++++++++++++++++ 1 file changed, 395 insertions(+)
diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 9490670cdf9..bd126f42235 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -1970,6 +1970,400 @@ static void test_GetDuration(void) IMFMediaEngineNotify_Release(¬ify->IMFMediaEngineNotify_iface); }
+struct unseekable_stream +{ + IMFByteStream IMFByteStream_iface; + IMFByteStream *original_stream; + LONG refcount; +}; + +static struct unseekable_stream *impl_unseekable_stream_from_IMFByteStream(IMFByteStream *iface) +{ + return CONTAINING_RECORD(iface, struct unseekable_stream, IMFByteStream_iface); +} + +static HRESULT WINAPI unseekable_stream_QueryInterface(IMFByteStream *iface, + REFIID riid, void **out) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IMFByteStream)) + { + IMFByteStream_AddRef(iface); + *out = iface; + return S_OK; + } + + return IMFByteStream_QueryInterface(stream->original_stream, riid, out); +} + +static ULONG WINAPI unseekable_stream_AddRef(IMFByteStream *iface) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return InterlockedIncrement(&stream->refcount); +} + +static ULONG WINAPI unseekable_stream_Release(IMFByteStream *iface) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + ULONG refcount = InterlockedDecrement(&stream->refcount); + + if (!refcount) + { + IMFByteStream_Release(stream->original_stream); + free(stream); + } + + return refcount; +} + +static HRESULT WINAPI unseekable_stream_GetCapabilities(IMFByteStream *iface, + DWORD *capabilities) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + HRESULT hr; + + hr = IMFByteStream_GetCapabilities(stream->original_stream, capabilities); + if (SUCCEEDED(hr)) + *capabilities &= ~(MFBYTESTREAM_IS_SEEKABLE | MFBYTESTREAM_HAS_SLOW_SEEK); + + return hr; +} + +static HRESULT WINAPI unseekable_stream_GetLength(IMFByteStream *iface, QWORD *length) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return IMFByteStream_GetLength(stream->original_stream, length); +} + +static HRESULT WINAPI unseekable_stream_SetLength(IMFByteStream *iface, QWORD length) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return IMFByteStream_SetLength(stream->original_stream, length); +} + +static HRESULT WINAPI unseekable_stream_GetCurrentPosition(IMFByteStream *iface, + QWORD *position) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return IMFByteStream_GetCurrentPosition(stream->original_stream, position); +} + +static HRESULT WINAPI unseekable_stream_SetCurrentPosition(IMFByteStream *iface, + QWORD position) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return IMFByteStream_SetCurrentPosition(stream->original_stream, position); +} + +static HRESULT WINAPI unseekable_stream_IsEndOfStream(IMFByteStream *iface, BOOL *eos) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return IMFByteStream_IsEndOfStream(stream->original_stream, eos); +} + +static HRESULT WINAPI unseekable_stream_Read(IMFByteStream *iface, BYTE *data, + ULONG count, ULONG *byte_read) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return IMFByteStream_Read(stream->original_stream, data, count, byte_read); +} + +static HRESULT WINAPI unseekable_stream_BeginRead(IMFByteStream *iface, BYTE *data, + ULONG size, IMFAsyncCallback *callback, IUnknown *state) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return IMFByteStream_BeginRead(stream->original_stream, data, size, callback, state); +} + +static HRESULT WINAPI unseekable_stream_EndRead(IMFByteStream *iface, + IMFAsyncResult *result, ULONG *byte_read) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return IMFByteStream_EndRead(stream->original_stream, result, byte_read); +} + +static HRESULT WINAPI unseekable_stream_Write(IMFByteStream *iface, const BYTE *data, + ULONG count, ULONG *written) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return IMFByteStream_Write(stream->original_stream, data, count, written); +} + +static HRESULT WINAPI unseekable_stream_BeginWrite(IMFByteStream *iface, + const BYTE *data, ULONG size, IMFAsyncCallback *callback, IUnknown *state) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return IMFByteStream_BeginWrite(stream->original_stream, data, size, callback, state); +} + +static HRESULT WINAPI unseekable_stream_EndWrite(IMFByteStream *iface, + IMFAsyncResult *result, ULONG *written) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return IMFByteStream_EndWrite(stream->original_stream, result, written); +} + +static HRESULT WINAPI unseekable_stream_Seek(IMFByteStream *iface, + MFBYTESTREAM_SEEK_ORIGIN seek, LONGLONG offset, DWORD flags, QWORD *current) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return IMFByteStream_Seek(stream->original_stream, seek, offset, flags, current); +} + +static HRESULT WINAPI unseekable_stream_Flush(IMFByteStream *iface) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return IMFByteStream_Flush(stream->original_stream); +} + +static HRESULT WINAPI unseekable_stream_Close(IMFByteStream *iface) +{ + struct unseekable_stream *stream = impl_unseekable_stream_from_IMFByteStream(iface); + + return IMFByteStream_Close(stream->original_stream); +} + +static const IMFByteStreamVtbl unseekable_stream_vtbl = +{ + unseekable_stream_QueryInterface, + unseekable_stream_AddRef, + unseekable_stream_Release, + unseekable_stream_GetCapabilities, + unseekable_stream_GetLength, + unseekable_stream_SetLength, + unseekable_stream_GetCurrentPosition, + unseekable_stream_SetCurrentPosition, + unseekable_stream_IsEndOfStream, + unseekable_stream_Read, + unseekable_stream_BeginRead, + unseekable_stream_EndRead, + unseekable_stream_Write, + unseekable_stream_BeginWrite, + unseekable_stream_EndWrite, + unseekable_stream_Seek, + unseekable_stream_Flush, + unseekable_stream_Close, +}; + +static IMFByteStream *create_unseekable_stream(IMFByteStream *stream) +{ + struct unseekable_stream *object; + + object = calloc(1, sizeof(*object)); + object->IMFByteStream_iface.lpVtbl = &unseekable_stream_vtbl; + object->original_stream = stream; + IMFByteStream_AddRef(stream); + object->refcount = 1; + + return &object->IMFByteStream_iface; +} + +struct test_seek_notify +{ + IMFMediaEngineNotify IMFMediaEngineNotify_iface; + HANDLE playing_event; + HRESULT expected_error; + HRESULT error; + LONG refcount; +}; + +static struct test_seek_notify *impl_from_test_seek_notify(IMFMediaEngineNotify *iface) +{ + return CONTAINING_RECORD(iface, struct test_seek_notify, IMFMediaEngineNotify_iface); +} + +static HRESULT WINAPI test_seek_notify_QueryInterface(IMFMediaEngineNotify *iface, REFIID riid, + void **obj) +{ + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMFMediaEngineNotify)) + { + *obj = iface; + IMFMediaEngineNotify_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_seek_notify_AddRef(IMFMediaEngineNotify *iface) +{ + struct test_seek_notify *notify = impl_from_test_seek_notify(iface); + + return InterlockedIncrement(¬ify->refcount); +} + +static ULONG WINAPI test_seek_notify_Release(IMFMediaEngineNotify *iface) +{ + struct test_seek_notify *notify = impl_from_test_seek_notify(iface); + ULONG refcount = InterlockedDecrement(¬ify->refcount); + + if (!refcount) + { + CloseHandle(notify->playing_event); + free(notify); + } + + return refcount; +} + +static HRESULT WINAPI test_seek_notify_EventNotify(IMFMediaEngineNotify *iface, DWORD event, + DWORD_PTR param1, DWORD param2) +{ + struct test_seek_notify *notify = impl_from_test_seek_notify(iface); + + switch (event) + { + case MF_MEDIA_ENGINE_EVENT_PLAYING: + SetEvent(notify->playing_event); + break; + case MF_MEDIA_ENGINE_EVENT_ERROR: + ok(param2 == notify->expected_error, "Unexpected error %#lx\n", param2); + notify->error = param2; + break; + } + + return S_OK; +} + +static IMFMediaEngineNotifyVtbl test_seek_notify_vtbl = +{ + test_seek_notify_QueryInterface, + test_seek_notify_AddRef, + test_seek_notify_Release, + test_seek_notify_EventNotify, +}; + +static struct test_seek_notify *create_seek_notify(void) +{ + struct test_seek_notify *object; + + object = calloc(1, sizeof(*object)); + object->IMFMediaEngineNotify_iface.lpVtbl = &test_seek_notify_vtbl; + object->playing_event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!object->playing_event, "Failed to create an event, error %lu.\n", GetLastError()); + object->refcount = 1; + return object; +} + +static void test_GetSeekable(void) +{ + IMFByteStream *stream, *unseekable_stream = NULL; + struct test_seek_notify *notify; + IMFMediaEngineEx *media_engine; + IMFMediaTimeRange *time_range; + double start, end, duration; + DWORD count; + HRESULT hr; + DWORD res; + BSTR url; + + notify = create_seek_notify(); + media_engine = create_media_engine_ex(¬ify->IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_B8G8R8X8_UNORM); + IMFMediaEngineNotify_Release(¬ify->IMFMediaEngineNotify_iface); + + stream = load_resource(L"i420-64x64.avi", L"video/avi"); + url = SysAllocString(L"i420-64x64.avi"); + hr = IMFMediaEngineEx_SetSourceFromByteStream(media_engine, stream, url); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Media engine is not ready */ + hr = IMFMediaEngineEx_GetSeekable(media_engine, &time_range); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + count = IMFMediaTimeRange_GetLength(time_range); + ok(!count, "Unexpected count %lu.\n", count); + IMFMediaTimeRange_Release(time_range); + } + + hr = IMFMediaEngineEx_Play(media_engine); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + res = WaitForSingleObject(notify->playing_event, 5000); + ok(!res, "Unexpected res %#lx.\n", res); + if (FAILED(notify->error)) + { + win_skip("Media engine reported error %#lx, skipping tests.\n", notify->error); + goto done; + } + + /* Media engine is ready */ + hr = IMFMediaEngineEx_GetSeekable(media_engine, &time_range); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + count = IMFMediaTimeRange_GetLength(time_range); + ok(count == 1, "Unexpected count %lu.\n", count); + hr = IMFMediaTimeRange_GetStart(time_range, 0, &start); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(start == 0, "Unexpected start %lf.\n", start); + hr = IMFMediaTimeRange_GetEnd(time_range, 0, &end); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + duration = IMFMediaEngineEx_GetDuration(media_engine); + ok(end == duration, "Unexpected end %lf.\n", end); + IMFMediaTimeRange_Release(time_range); + } + + /* Media engine is shut down */ + IMFMediaEngineEx_Shutdown(media_engine); + + hr = IMFMediaEngineEx_GetSeekable(media_engine, &time_range); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); + + IMFMediaEngineEx_Release(media_engine); + + /* Unseekable bytestreams */ + notify = create_seek_notify(); + media_engine = create_media_engine_ex(¬ify->IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_B8G8R8X8_UNORM); + IMFMediaEngineNotify_Release(¬ify->IMFMediaEngineNotify_iface); + unseekable_stream = create_unseekable_stream(stream); + hr = IMFMediaEngineEx_SetSourceFromByteStream(media_engine, unseekable_stream, url); + todo_wine_if(hr == MF_E_BYTESTREAM_NOT_SEEKABLE) + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (FAILED(hr)) + goto done; + + hr = IMFMediaEngineEx_Play(media_engine); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + notify->expected_error = MF_E_INVALIDREQUEST; + res = WaitForSingleObject(notify->playing_event, 5000); + ok(res == S_OK, "Unexpected res %#lx.\n", res); + + hr = IMFMediaEngineEx_GetSeekable(media_engine, &time_range); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + count = IMFMediaTimeRange_GetLength(time_range); + ok(!count, "Unexpected count %lu.\n", count); + IMFMediaTimeRange_Release(time_range); + } + +done: + IMFMediaEngineEx_Shutdown(media_engine); + IMFMediaEngineEx_Release(media_engine); + if (unseekable_stream) IMFByteStream_Release(unseekable_stream); + SysFreeString(url); + IMFByteStream_Release(stream); +} + START_TEST(mfmediaengine) { HRESULT hr; @@ -2003,6 +2397,7 @@ START_TEST(mfmediaengine) test_TransferVideoFrame(); test_effect(); test_GetDuration(); + test_GetSeekable();
IMFMediaEngineClassFactory_Release(factory);