mirror of
git://source.winehq.org/git/wine.git
synced 2024-07-21 13:24:10 +00:00
mfmediaengine/tests: Test IMFMediaEngine::GetSeekable().
This commit is contained in:
parent
3893db0a20
commit
4f0a7cd89a
|
@ -1970,6 +1970,412 @@ 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;
|
||||
ULONG refcount;
|
||||
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);
|
||||
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(¬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
|
||||
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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue