Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/mf.spec | 2 +-
dlls/mf/session.c | 381 +++++++++++++++++++++++++++++++++++++++++++++
dlls/mf/tests/mf.c | 63 ++++++++
include/mferror.h | 2 +
include/mfidl.idl | 58 ++++++-
5 files changed, 504 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/mf.spec b/dlls/mf/mf.spec
index 7ec8e57c1f..2d02ef8fec 100644
--- a/dlls/mf/mf.spec
+++ b/dlls/mf/mf.spec
@@ -45,7 +45,7 @@
@ stub MFCreatePMPHost
@ stub MFCreatePMPMediaSession
@ stub MFCreatePMPServer
-@ stub MFCreatePresentationClock
+@ stdcall MFCreatePresentationClock(ptr)
@ stub MFCreatePresentationDescriptorFromASFProfile
@ stub MFCreateProxyLocator
@ stub MFCreateRemoteDesktopPlugin
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index b576a0f184..2961abe879 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -25,6 +25,7 @@
#include "winbase.h"
#include "mfidl.h"
#include "mfapi.h"
+#include "mferror.h"
#include "wine/debug.h"
#include "wine/heap.h"
@@ -38,11 +39,43 @@ struct media_session
IMFMediaEventQueue *event_queue;
};
+struct presentation_clock
+{
+ IMFPresentationClock IMFPresentationClock_iface;
+ IMFRateControl IMFRateControl_iface;
+ IMFTimer IMFTimer_iface;
+ IMFShutdown IMFShutdown_iface;
+ LONG refcount;
+ IMFPresentationTimeSource *time_source;
+ MFCLOCK_STATE state;
+ CRITICAL_SECTION cs;
+};
+
static inline struct media_session *impl_from_IMFMediaSession(IMFMediaSession *iface)
{
return CONTAINING_RECORD(iface, struct media_session, IMFMediaSession_iface);
}
+static struct presentation_clock *impl_from_IMFPresentationClock(IMFPresentationClock *iface)
+{
+ return CONTAINING_RECORD(iface, struct presentation_clock, IMFPresentationClock_iface);
+}
+
+static struct presentation_clock *impl_from_IMFRateControl(IMFRateControl *iface)
+{
+ return CONTAINING_RECORD(iface, struct presentation_clock, IMFRateControl_iface);
+}
+
+static struct presentation_clock *impl_from_IMFTimer(IMFTimer *iface)
+{
+ return CONTAINING_RECORD(iface, struct presentation_clock, IMFTimer_iface);
+}
+
+static struct presentation_clock *impl_from_IMFShutdown(IMFShutdown *iface)
+{
+ return CONTAINING_RECORD(iface, struct presentation_clock, IMFShutdown_iface);
+}
+
static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out)
{
struct media_session *session = impl_from_IMFMediaSession(iface);
@@ -251,3 +284,351 @@ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **ses
return S_OK;
}
+
+static HRESULT WINAPI present_clock_QueryInterface(IMFPresentationClock *iface, REFIID riid, void **out)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+
+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
+
+ if (IsEqualIID(riid, &IID_IMFPresentationClock) ||
+ IsEqualIID(riid, &IID_IMFClock) ||
+ IsEqualIID(riid, &IID_IUnknown))
+ {
+ *out = &clock->IMFPresentationClock_iface;
+ }
+ else if (IsEqualIID(riid, &IID_IMFRateControl))
+ {
+ *out = &clock->IMFRateControl_iface;
+ }
+ else if (IsEqualIID(riid, &IID_IMFTimer))
+ {
+ *out = &clock->IMFTimer_iface;
+ }
+ else if (IsEqualIID(riid, &IID_IMFShutdown))
+ {
+ *out = &clock->IMFShutdown_iface;
+ }
+ else
+ {
+ WARN("Unsupported %s.\n", debugstr_guid(riid));
+ *out = NULL;
+ return E_NOINTERFACE;
+ }
+
+ IUnknown_AddRef((IUnknown *)*out);
+ return S_OK;
+}
+
+static ULONG WINAPI present_clock_AddRef(IMFPresentationClock *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ ULONG refcount = InterlockedIncrement(&clock->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI present_clock_Release(IMFPresentationClock *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ ULONG refcount = InterlockedDecrement(&clock->refcount);
+
+ TRACE("%p, refcount %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ if (clock->time_source)
+ IMFPresentationTimeSource_Release(clock->time_source);
+ DeleteCriticalSection(&clock->cs);
+ heap_free(clock);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI present_clock_GetClockCharacteristics(IMFPresentationClock *iface, DWORD *flags)
+{
+ FIXME("%p, %p.\n", iface, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI present_clock_GetCorrelatedTime(IMFPresentationClock *iface, DWORD reserved,
+ LONGLONG *clock_time, MFTIME *system_time)
+{
+ FIXME("%p, %#x, %p, %p.\n", iface, reserved, clock_time, system_time);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI present_clock_GetContinuityKey(IMFPresentationClock *iface, DWORD *key)
+{
+ TRACE("%p, %p.\n", iface, key);
+
+ *key = 0;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI present_clock_GetState(IMFPresentationClock *iface, DWORD reserved, MFCLOCK_STATE *state)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+
+ TRACE("%p, %#x, %p.\n", iface, reserved, state);
+
+ EnterCriticalSection(&clock->cs);
+ *state = clock->state;
+ LeaveCriticalSection(&clock->cs);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI present_clock_GetProperties(IMFPresentationClock *iface, MFCLOCK_PROPERTIES *props)
+{
+ FIXME("%p, %p.\n", iface, props);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI present_clock_SetTimeSource(IMFPresentationClock *iface,
+ IMFPresentationTimeSource *time_source)
+{
+ FIXME("%p, %p.\n", iface, time_source);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI present_clock_GetTimeSource(IMFPresentationClock *iface,
+ IMFPresentationTimeSource **time_source)
+{
+ struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
+ HRESULT hr = S_OK;
+
+ TRACE("%p, %p.\n", iface, time_source);
+
+ EnterCriticalSection(&clock->cs);
+ if (clock->time_source)
+ {
+ *time_source = clock->time_source;
+ IMFPresentationTimeSource_AddRef(*time_source);
+ }
+ else
+ hr = MF_E_CLOCK_NO_TIME_SOURCE;
+ LeaveCriticalSection(&clock->cs);
+
+ return hr;
+}
+
+static HRESULT WINAPI present_clock_GetTime(IMFPresentationClock *iface, MFTIME *time)
+{
+ FIXME("%p, %p.\n", iface, time);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI present_clock_AddClockStateSink(IMFPresentationClock *iface, IMFClockStateSink *state_sink)
+{
+ FIXME("%p, %p.\n", iface, state_sink);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI present_clock_RemoveClockStateSink(IMFPresentationClock *iface,
+ IMFClockStateSink *state_sink)
+{
+ FIXME("%p, %p.\n", iface, state_sink);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI present_clock_Start(IMFPresentationClock *iface, LONGLONG start_offset)
+{
+ FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(start_offset));
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI present_clock_Stop(IMFPresentationClock *iface)
+{
+ FIXME("%p.\n", iface);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI present_clock_Pause(IMFPresentationClock *iface)
+{
+ FIXME("%p.\n", iface);
+
+ return E_NOTIMPL;
+}
+
+static const IMFPresentationClockVtbl presentationclockvtbl =
+{
+ present_clock_QueryInterface,
+ present_clock_AddRef,
+ present_clock_Release,
+ present_clock_GetClockCharacteristics,
+ present_clock_GetCorrelatedTime,
+ present_clock_GetContinuityKey,
+ present_clock_GetState,
+ present_clock_GetProperties,
+ present_clock_SetTimeSource,
+ present_clock_GetTimeSource,
+ present_clock_GetTime,
+ present_clock_AddClockStateSink,
+ present_clock_RemoveClockStateSink,
+ present_clock_Start,
+ present_clock_Stop,
+ present_clock_Pause,
+};
+
+static HRESULT WINAPI present_clock_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **out)
+{
+ struct presentation_clock *clock = impl_from_IMFRateControl(iface);
+ return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
+}
+
+static ULONG WINAPI present_clock_rate_control_AddRef(IMFRateControl *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFRateControl(iface);
+ return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
+}
+
+static ULONG WINAPI present_clock_rate_control_Release(IMFRateControl *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFRateControl(iface);
+ return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
+}
+
+static HRESULT WINAPI present_clock_rate_SetRate(IMFRateControl *iface, BOOL thin, float rate)
+{
+ FIXME("%p, %d, %f.\n", iface, thin, rate);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI present_clock_rate_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
+{
+ FIXME("%p, %p, %p.\n", iface, thin, rate);
+
+ return E_NOTIMPL;
+}
+
+static const IMFRateControlVtbl presentclockratecontrolvtbl =
+{
+ present_clock_rate_control_QueryInterface,
+ present_clock_rate_control_AddRef,
+ present_clock_rate_control_Release,
+ present_clock_rate_SetRate,
+ present_clock_rate_GetRate,
+};
+
+static HRESULT WINAPI present_clock_timer_QueryInterface(IMFTimer *iface, REFIID riid, void **out)
+{
+ struct presentation_clock *clock = impl_from_IMFTimer(iface);
+ return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
+}
+
+static ULONG WINAPI present_clock_timer_AddRef(IMFTimer *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFTimer(iface);
+ return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
+}
+
+static ULONG WINAPI present_clock_timer_Release(IMFTimer *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFTimer(iface);
+ return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
+}
+
+static HRESULT WINAPI present_clock_timer_SetTimer(IMFTimer *iface, DWORD flags, LONGLONG time,
+ IMFAsyncCallback *callback, IUnknown *state, IUnknown **cancel_key)
+{
+ FIXME("%p, %#x, %s, %p, %p, %p.\n", iface, flags, wine_dbgstr_longlong(time), callback, state, cancel_key);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI present_clock_timer_CancelTimer(IMFTimer *iface, IUnknown *cancel_key)
+{
+ FIXME("%p, %p.\n", iface, cancel_key);
+
+ return E_NOTIMPL;
+}
+
+static const IMFTimerVtbl presentclocktimervtbl =
+{
+ present_clock_timer_QueryInterface,
+ present_clock_timer_AddRef,
+ present_clock_timer_Release,
+ present_clock_timer_SetTimer,
+ present_clock_timer_CancelTimer,
+};
+
+static HRESULT WINAPI present_clock_shutdown_QueryInterface(IMFShutdown *iface, REFIID riid, void **out)
+{
+ struct presentation_clock *clock = impl_from_IMFShutdown(iface);
+ return IMFPresentationClock_QueryInterface(&clock->IMFPresentationClock_iface, riid, out);
+}
+
+static ULONG WINAPI present_clock_shutdown_AddRef(IMFShutdown *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFShutdown(iface);
+ return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface);
+}
+
+static ULONG WINAPI present_clock_shutdown_Release(IMFShutdown *iface)
+{
+ struct presentation_clock *clock = impl_from_IMFShutdown(iface);
+ return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface);
+}
+
+static HRESULT WINAPI present_clock_shutdown_Shutdown(IMFShutdown *iface)
+{
+ FIXME("%p.\n", iface);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI present_clock_shutdown_GetShutdownStatus(IMFShutdown *iface, MFSHUTDOWN_STATUS *status)
+{
+ FIXME("%p, %p.\n", iface, status);
+
+ return E_NOTIMPL;
+}
+
+static const IMFShutdownVtbl presentclockshutdownvtbl =
+{
+ present_clock_shutdown_QueryInterface,
+ present_clock_shutdown_AddRef,
+ present_clock_shutdown_Release,
+ present_clock_shutdown_Shutdown,
+ present_clock_shutdown_GetShutdownStatus,
+};
+
+/***********************************************************************
+ * MFCreatePresentationClock (mf.@)
+ */
+HRESULT WINAPI MFCreatePresentationClock(IMFPresentationClock **clock)
+{
+ struct presentation_clock *object;
+
+ TRACE("%p.\n", clock);
+
+ object = heap_alloc_zero(sizeof(*object));
+ if (!object)
+ return E_OUTOFMEMORY;
+
+ object->IMFPresentationClock_iface.lpVtbl = &presentationclockvtbl;
+ object->IMFRateControl_iface.lpVtbl = &presentclockratecontrolvtbl;
+ object->IMFTimer_iface.lpVtbl = &presentclocktimervtbl;
+ object->IMFShutdown_iface.lpVtbl = &presentclockshutdownvtbl;
+ object->refcount = 1;
+ InitializeCriticalSection(&object->cs);
+
+ *clock = &object->IMFPresentationClock_iface;
+
+ return S_OK;
+}
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 2d005547b7..9fa0bda839 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -735,6 +735,68 @@ static void test_MFShutdownObject(void)
ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
}
+static void test_presentation_clock(void)
+{
+ IMFPresentationTimeSource *time_source;
+ IMFRateControl *rate_control;
+ IMFPresentationClock *clock;
+ MFCLOCK_PROPERTIES props;
+ IMFShutdown *shutdown;
+ LONGLONG clock_time;
+ MFCLOCK_STATE state;
+ IMFTimer *timer;
+ MFTIME systime;
+ DWORD value;
+ HRESULT hr;
+
+ hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
+ ok(hr == S_OK, "Failed to start up, hr %#x.\n", hr);
+
+ hr = MFCreatePresentationClock(&clock);
+ ok(hr == S_OK, "Failed to create presentation clock, hr %#x.\n", hr);
+
+ hr = IMFPresentationClock_GetTimeSource(clock, &time_source);
+ ok(hr == MF_E_CLOCK_NO_TIME_SOURCE, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFPresentationClock_GetClockCharacteristics(clock, &value);
+todo_wine
+ ok(hr == MF_E_CLOCK_NO_TIME_SOURCE, "Unexpected hr %#x.\n", hr);
+
+ value = 1;
+ hr = IMFPresentationClock_GetContinuityKey(clock, &value);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(value == 0, "Unexpected value %u.\n", value);
+
+ hr = IMFPresentationClock_GetProperties(clock, &props);
+todo_wine
+ ok(hr == MF_E_CLOCK_NO_TIME_SOURCE, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFPresentationClock_GetState(clock, 0, &state);
+ ok(hr == S_OK, "Failed to get state, hr %#x.\n", hr);
+ ok(state == MFCLOCK_STATE_INVALID, "Unexpected state %d.\n", state);
+
+ hr = IMFPresentationClock_GetCorrelatedTime(clock, 0, &clock_time, &systime);
+todo_wine
+ ok(hr == MF_E_CLOCK_NO_TIME_SOURCE, "Unexpected hr %#x.\n", hr);
+
+ hr = IMFPresentationClock_QueryInterface(clock, &IID_IMFRateControl, (void **)&rate_control);
+ ok(hr == S_OK, "Failed to get rate control interface, hr %#x.\n", hr);
+ IMFRateControl_Release(rate_control);
+
+ hr = IMFPresentationClock_QueryInterface(clock, &IID_IMFTimer, (void **)&timer);
+ ok(hr == S_OK, "Failed to get timer interface, hr %#x.\n", hr);
+ IMFTimer_Release(timer);
+
+ hr = IMFPresentationClock_QueryInterface(clock, &IID_IMFShutdown, (void **)&shutdown);
+ ok(hr == S_OK, "Failed to get shutdown interface, hr %#x.\n", hr);
+ IMFShutdown_Release(shutdown);
+
+ IMFPresentationClock_Release(clock);
+
+ hr = MFShutdown();
+ ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
+}
+
START_TEST(mf)
{
test_topology();
@@ -743,4 +805,5 @@ START_TEST(mf)
test_MFCreateSequencerSource();
test_media_session();
test_MFShutdownObject();
+ test_presentation_clock();
}
diff --git a/include/mferror.h b/include/mferror.h
index 54f09fefdc..be35e6e20f 100644
--- a/include/mferror.h
+++ b/include/mferror.h
@@ -82,4 +82,6 @@
#define MF_E_TOPO_MISSING_SOURCE _HRESULT_TYPEDEF_(0xc00d521a)
#define MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED _HRESULT_TYPEDEF_(0xc00d521b)
+#define MF_E_CLOCK_NO_TIME_SOURCE _HRESULT_TYPEDEF_(0xc00d9c41)
+
#endif /* __WINE_MFERROR_H */
diff --git a/include/mfidl.idl b/include/mfidl.idl
index be8795c854..48d7c8e501 100644
--- a/include/mfidl.idl
+++ b/include/mfidl.idl
@@ -70,6 +70,37 @@ interface IMFClock : IUnknown
HRESULT GetProperties([out] MFCLOCK_PROPERTIES *props);
}
+[
+ object,
+ uuid(88ddcd21-03c3-4275-91ed-55ee3929328f)
+]
+interface IMFRateControl : IUnknown
+{
+ HRESULT SetRate(
+ [in] BOOL thin,
+ [in] float rate);
+ HRESULT GetRate(
+ [in, out, unique] BOOL *thin,
+ [in, out, unique] float *rate);
+}
+
+[
+ object,
+ uuid(e56e4cbd-8f70-49d8-a0f8-edb3d6ab9bf2),
+ local
+]
+interface IMFTimer : IUnknown
+{
+ HRESULT SetTimer(
+ [in] DWORD flags,
+ [in] LONGLONG time,
+ [in] IMFAsyncCallback *callback,
+ [in] IUnknown *state,
+ [out] IUnknown **key);
+ HRESULT CancelTimer(
+ [in] IUnknown *key);
+}
+
[
object,
uuid(83cf873a-f6da-4bc8-823f-bacfd55dc430),
@@ -319,6 +350,7 @@ interface IMFSequencerSource : IUnknown
cpp_quote("HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session);")
cpp_quote("HRESULT WINAPI MFCreateMFByteStreamOnStream(IStream *stream, IMFByteStream **bytestream);" )
cpp_quote("HRESULT WINAPI MFCreateMFByteStreamOnStreamEx(IUnknown *stream, IMFByteStream **bytestream);")
+cpp_quote("HRESULT WINAPI MFCreatePresentationClock(IMFPresentationClock **clock);")
cpp_quote("HRESULT WINAPI MFCreateSequencerSource(IUnknown *reserved, IMFSequencerSource **seq_source);" )
cpp_quote("HRESULT WINAPI MFCreateSourceResolver(IMFSourceResolver **resolver);")
cpp_quote("HRESULT WINAPI MFCreateStreamDescriptor(DWORD identifier, DWORD cMediaTypes,")
@@ -360,7 +392,31 @@ interface IMFMediaSource : IMFMediaEventGenerator
}
interface IMFStreamSink;
-interface IMFPresentationClock;
+
+[
+ object,
+ uuid(7ff12cce-f76f-41c2-863b-1666c8e5e139)
+]
+interface IMFPresentationTimeSource : IMFClock
+{
+ HRESULT GetUnderlyingClock([out] IMFClock **clock);
+}
+
+[
+ object,
+ uuid(868ce85c-8ea9-4f55-ab82-b009a910a805)
+]
+interface IMFPresentationClock : IMFClock
+{
+ HRESULT SetTimeSource([in] IMFPresentationTimeSource *time_source);
+ HRESULT GetTimeSource([out] IMFPresentationTimeSource **time_source);
+ HRESULT GetTime([out] MFTIME *time);
+ HRESULT AddClockStateSink([in] IMFClockStateSink *state_sink);
+ HRESULT RemoveClockStateSink([in] IMFClockStateSink *state_sink);
+ HRESULT Start([in] LONGLONG start_offset);
+ HRESULT Stop();
+ HRESULT Pause();
+}
[
object,
--
2.20.1