diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 27b2c4cce61..d2d1d495a0a 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -29,6 +29,7 @@ #include "wine/debug.h" #include "wine/heap.h" +#include "wine/list.h" WINE_DEFAULT_DEBUG_CHANNEL(mfplat); @@ -39,6 +40,12 @@ struct media_session IMFMediaEventQueue *event_queue; }; +struct clock_sink +{ + struct list entry; + IMFClockStateSink *state_sink; +}; + struct presentation_clock { IMFPresentationClock IMFPresentationClock_iface; @@ -49,6 +56,7 @@ struct presentation_clock IMFPresentationTimeSource *time_source; IMFClockStateSink *time_source_sink; MFCLOCK_STATE state; + struct list sinks; CRITICAL_SECTION cs; }; @@ -335,6 +343,7 @@ static ULONG WINAPI present_clock_Release(IMFPresentationClock *iface) { struct presentation_clock *clock = impl_from_IMFPresentationClock(iface); ULONG refcount = InterlockedDecrement(&clock->refcount); + struct clock_sink *sink, *sink2; TRACE("%p, refcount %u.\n", iface, refcount); @@ -344,6 +353,12 @@ static ULONG WINAPI present_clock_Release(IMFPresentationClock *iface) IMFPresentationTimeSource_Release(clock->time_source); if (clock->time_source_sink) IMFClockStateSink_Release(clock->time_source_sink); + LIST_FOR_EACH_ENTRY_SAFE(sink, sink2, &clock->sinks, struct clock_sink, entry) + { + list_remove(&sink->entry); + IMFClockStateSink_Release(sink->state_sink); + heap_free(sink); + } DeleteCriticalSection(&clock->cs); heap_free(clock); } @@ -453,17 +468,69 @@ static HRESULT WINAPI present_clock_GetTime(IMFPresentationClock *iface, MFTIME static HRESULT WINAPI present_clock_AddClockStateSink(IMFPresentationClock *iface, IMFClockStateSink *state_sink) { - FIXME("%p, %p.\n", iface, state_sink); + struct presentation_clock *clock = impl_from_IMFPresentationClock(iface); + struct clock_sink *sink, *cur; + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("%p, %p.\n", iface, state_sink); + + if (!state_sink) + return E_INVALIDARG; + + sink = heap_alloc(sizeof(*sink)); + if (!sink) + return E_OUTOFMEMORY; + + sink->state_sink = state_sink; + IMFClockStateSink_AddRef(sink->state_sink); + + EnterCriticalSection(&clock->cs); + LIST_FOR_EACH_ENTRY(cur, &clock->sinks, struct clock_sink, entry) + { + if (cur->state_sink == state_sink) + { + hr = E_INVALIDARG; + break; + } + } + if (SUCCEEDED(hr)) + list_add_tail(&clock->sinks, &sink->entry); + LeaveCriticalSection(&clock->cs); + + if (FAILED(hr)) + { + IMFClockStateSink_Release(sink->state_sink); + heap_free(sink); + } + + return hr; } static HRESULT WINAPI present_clock_RemoveClockStateSink(IMFPresentationClock *iface, IMFClockStateSink *state_sink) { - FIXME("%p, %p.\n", iface, state_sink); + struct presentation_clock *clock = impl_from_IMFPresentationClock(iface); + struct clock_sink *sink; - return E_NOTIMPL; + TRACE("%p, %p.\n", iface, state_sink); + + if (!state_sink) + return E_INVALIDARG; + + EnterCriticalSection(&clock->cs); + LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct clock_sink, entry) + { + if (sink->state_sink == state_sink) + { + IMFClockStateSink_Release(sink->state_sink); + list_remove(&sink->entry); + heap_free(sink); + break; + } + } + LeaveCriticalSection(&clock->cs); + + return S_OK; } enum clock_command @@ -731,6 +798,7 @@ HRESULT WINAPI MFCreatePresentationClock(IMFPresentationClock **clock) object->IMFTimer_iface.lpVtbl = &presentclocktimervtbl; object->IMFShutdown_iface.lpVtbl = &presentclockshutdownvtbl; object->refcount = 1; + list_init(&object->sinks); InitializeCriticalSection(&object->cs); *clock = &object->IMFPresentationClock_iface; diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index bae674d7fa9..42b23d6c3e5 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -742,6 +742,67 @@ enum clock_action CLOCK_PAUSE, }; +static HRESULT WINAPI test_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFClockStateSink) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFClockStateSink_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_clock_sink_AddRef(IMFClockStateSink *iface) +{ + return 2; +} + +static ULONG WINAPI test_clock_sink_Release(IMFClockStateSink *iface) +{ + return 1; +} + +static HRESULT WINAPI test_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME system_time, LONGLONG offset) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME system_time) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME system_time) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME system_time) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME system_time, float rate) +{ + return E_NOTIMPL; +} + +static const IMFClockStateSinkVtbl test_clock_sink_vtbl = +{ + test_clock_sink_QueryInterface, + test_clock_sink_AddRef, + test_clock_sink_Release, + test_clock_sink_OnClockStart, + test_clock_sink_OnClockStop, + test_clock_sink_OnClockPause, + test_clock_sink_OnClockRestart, + test_clock_sink_OnClockSetRate, +}; + static void test_presentation_clock(void) { static const struct clock_state_test @@ -766,6 +827,7 @@ static void test_presentation_clock(void) { CLOCK_STOP, MFCLOCK_STATE_STOPPED, MFCLOCK_STATE_STOPPED, MF_E_CLOCK_STATE_ALREADY_SET }, { CLOCK_PAUSE, MFCLOCK_STATE_STOPPED, MFCLOCK_STATE_STOPPED, MF_E_INVALIDREQUEST }, }; + IMFClockStateSink test_sink = { &test_clock_sink_vtbl }; IMFPresentationTimeSource *time_source; IMFRateControl *rate_control; IMFPresentationClock *clock; @@ -809,6 +871,25 @@ todo_wine todo_wine ok(hr == MF_E_CLOCK_NO_TIME_SOURCE, "Unexpected hr %#x.\n", hr); + /* Sinks. */ + hr = IMFPresentationClock_AddClockStateSink(clock, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IMFPresentationClock_AddClockStateSink(clock, &test_sink); + ok(hr == S_OK, "Failed to add a sink, hr %#x.\n", hr); + + hr = IMFPresentationClock_AddClockStateSink(clock, &test_sink); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IMFPresentationClock_RemoveClockStateSink(clock, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = IMFPresentationClock_RemoveClockStateSink(clock, &test_sink); + ok(hr == S_OK, "Failed to remove sink, hr %#x.\n", hr); + + hr = IMFPresentationClock_RemoveClockStateSink(clock, &test_sink); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + /* Set default time source. */ hr = MFCreateSystemTimeSource(&time_source); ok(hr == S_OK, "Failed to create time source, hr %#x.\n", hr);