mfmediaengine/tests: Test IMFMediaEngine::GetSeekable().

This commit is contained in:
Zhiyi Zhang 2023-07-25 17:20:12 +08:00 committed by Alexandre Julliard
parent 3893db0a20
commit 4f0a7cd89a

View file

@ -1970,6 +1970,412 @@ static void test_GetDuration(void)
IMFMediaEngineNotify_Release(&notify->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(&notify->refcount);
}
static ULONG WINAPI test_seek_notify_Release(IMFMediaEngineNotify *iface)
{
struct test_seek_notify *notify = impl_from_test_seek_notify(iface);
ULONG refcount = InterlockedDecrement(&notify->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;
ULONG refcount;
DWORD count;
HRESULT hr;
DWORD res;
BSTR url;
notify = create_seek_notify();
media_engine = create_media_engine_ex(&notify->IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_B8G8R8X8_UNORM);
IMFMediaEngineNotify_Release(&notify->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);
refcount = IMFMediaTimeRange_Release(time_range);
ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
}
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);
refcount = IMFMediaTimeRange_Release(time_range);
ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
}
/* Media engine is shut down */
hr = IMFMediaEngineEx_Shutdown(media_engine);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
time_range = (IMFMediaTimeRange *)0xdeadbeef;
hr = IMFMediaEngineEx_GetSeekable(media_engine, &time_range);
ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
todo_wine
ok(time_range == NULL || broken(time_range == (IMFMediaTimeRange *)0xdeadbeef) /* <= Win10 1507 */,
"Got unexpected pointer.\n");
refcount = IMFMediaEngineEx_Release(media_engine);
todo_wine
ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
/* Unseekable bytestreams */
notify = create_seek_notify();
media_engine = create_media_engine_ex(&notify->IMFMediaEngineNotify_iface, NULL, DXGI_FORMAT_B8G8R8X8_UNORM);
IMFMediaEngineNotify_Release(&notify->IMFMediaEngineNotify_iface);
unseekable_stream = create_unseekable_stream(stream);
hr = IMFMediaEngineEx_SetSourceFromByteStream(media_engine, unseekable_stream, url);
todo_wine
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);
refcount = IMFMediaTimeRange_Release(time_range);
ok(!refcount, "Got unexpected refcount %lu.\n", refcount);
}
done:
hr = IMFMediaEngineEx_Shutdown(media_engine);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
IMFMediaEngineEx_Release(media_engine);
if (unseekable_stream) IMFByteStream_Release(unseekable_stream);
SysFreeString(url);
IMFByteStream_Release(stream);
}
START_TEST(mfmediaengine)
{
HRESULT hr;
@ -2003,6 +2409,7 @@ START_TEST(mfmediaengine)
test_TransferVideoFrame();
test_effect();
test_GetDuration();
test_GetSeekable();
IMFMediaEngineClassFactory_Release(factory);