Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mferror/mferror.mc | 14 ++++++++++++++ include/mferror.h | 2 ++ 2 files changed, 16 insertions(+)
diff --git a/dlls/mferror/mferror.mc b/dlls/mferror/mferror.mc index 6934611ab4..61f01b6a2d 100644 --- a/dlls/mferror/mferror.mc +++ b/dlls/mferror/mferror.mc @@ -715,3 +715,17 @@ SymbolicName=MF_E_CLOCK_STATE_ALREADY_SET Language=ENU Clock state was already set. . +MessageId=40003 +Severity=Error +Facility=MF +SymbolicName=MF_E_CLOCK_NOT_SIMPLE +Language=ENU +Clock is not simple +. +MessageId=40004 +Severity=Success +Facility=MF +SymbolicName=MF_S_CLOCK_STOPPED +Language=ENU +Clock was stopped +. diff --git a/include/mferror.h b/include/mferror.h index 6d7031ecc8..6341d832ab 100644 --- a/include/mferror.h +++ b/include/mferror.h @@ -163,5 +163,7 @@
#define MF_E_CLOCK_NO_TIME_SOURCE _HRESULT_TYPEDEF_(0xc00d9c41) #define MF_E_CLOCK_STATE_ALREADY_SET _HRESULT_TYPEDEF_(0xc00d9c42) +#define MF_E_CLOCK_NOT_SIMPLE _HRESULT_TYPEDEF_(0xc00d9c43) +#define MF_S_CLOCK_STOPPED _HRESULT_TYPEDEF_(0x000d9c44)
#endif /* __WINE_MFERROR_H */
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/session.c | 285 +++++++++++++++++++++++++++++++++++++++++++--- include/mfidl.idl | 5 + 2 files changed, 275 insertions(+), 15 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 1f790a6ed3..b80499477c 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -173,19 +173,32 @@ struct sink_notification IMFClockStateSink *sink; };
+struct clock_timer +{ + IUnknown IUnknown_iface; + LONG refcount; + IMFAsyncResult *result; + IMFAsyncCallback *callback; + MFWORKITEM_KEY key; + struct list entry; +}; + struct presentation_clock { IMFPresentationClock IMFPresentationClock_iface; IMFRateControl IMFRateControl_iface; IMFTimer IMFTimer_iface; IMFShutdown IMFShutdown_iface; - IMFAsyncCallback IMFAsyncCallback_iface; + IMFAsyncCallback sink_callback; + IMFAsyncCallback timer_callback; LONG refcount; IMFPresentationTimeSource *time_source; IMFClockStateSink *time_source_sink; MFCLOCK_STATE state; struct list sinks; + struct list timers; float rate; + LONGLONG frequency; CRITICAL_SECTION cs; };
@@ -250,9 +263,19 @@ static struct presentation_clock *impl_from_IMFShutdown(IMFShutdown *iface) return CONTAINING_RECORD(iface, struct presentation_clock, IMFShutdown_iface); }
-static struct presentation_clock *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) +static struct presentation_clock *impl_from_sink_callback_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct presentation_clock, sink_callback); +} + +static struct presentation_clock *impl_from_timer_callback_IMFAsyncCallback(IMFAsyncCallback *iface) { - return CONTAINING_RECORD(iface, struct presentation_clock, IMFAsyncCallback_iface); + return CONTAINING_RECORD(iface, struct presentation_clock, timer_callback); +} + +static struct clock_timer *impl_clock_timer_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct clock_timer, IUnknown_iface); }
static struct sink_notification *impl_from_IUnknown(IUnknown *iface) @@ -1631,6 +1654,7 @@ static ULONG WINAPI present_clock_Release(IMFPresentationClock *iface) { struct presentation_clock *clock = impl_from_IMFPresentationClock(iface); ULONG refcount = InterlockedDecrement(&clock->refcount); + struct clock_timer *timer, *timer2; struct clock_sink *sink, *sink2;
TRACE("%p, refcount %u.\n", iface, refcount); @@ -1647,6 +1671,11 @@ static ULONG WINAPI present_clock_Release(IMFPresentationClock *iface) IMFClockStateSink_Release(sink->state_sink); heap_free(sink); } + LIST_FOR_EACH_ENTRY_SAFE(timer, timer2, &clock->timers, struct clock_timer, entry) + { + list_remove(&timer->entry); + IUnknown_Release(&timer->IUnknown_iface); + } DeleteCriticalSection(&clock->cs); heap_free(clock); } @@ -1726,11 +1755,14 @@ static HRESULT WINAPI present_clock_SetTimeSource(IMFPresentationClock *iface, IMFPresentationTimeSource *time_source) { struct presentation_clock *clock = impl_from_IMFPresentationClock(iface); + MFCLOCK_PROPERTIES props; + IMFClock *source_clock; HRESULT hr;
TRACE("%p, %p.\n", iface, time_source);
EnterCriticalSection(&clock->cs); + if (clock->time_source) IMFPresentationTimeSource_Release(clock->time_source); if (clock->time_source_sink) @@ -1745,6 +1777,16 @@ static HRESULT WINAPI present_clock_SetTimeSource(IMFPresentationClock *iface, IMFPresentationTimeSource_AddRef(clock->time_source); }
+ if (SUCCEEDED(IMFPresentationTimeSource_GetUnderlyingClock(time_source, &source_clock))) + { + if (SUCCEEDED(IMFClock_GetProperties(source_clock, &props))) + clock->frequency = props.qwClockFrequency; + IMFClock_Release(source_clock); + } + + if (!clock->frequency) + clock->frequency = MFCLOCK_FREQUENCY_HNS; + LeaveCriticalSection(&clock->cs);
return hr; @@ -1986,6 +2028,7 @@ static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_c enum clock_notification notification; struct clock_sink *sink; IUnknown *notify_object; + MFCLOCK_STATE old_state; IMFAsyncResult *result; MFTIME system_time; HRESULT hr; @@ -2012,13 +2055,47 @@ static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_c if (FAILED(hr = clock_call_state_change(system_time, param, notification, clock->time_source_sink))) return hr;
+ old_state = clock->state; clock->state = states[command];
+ /* Dump all pending timer requests immediately on start; otherwise try to cancel scheduled items when + transitioning from running state. */ + if ((clock->state == MFCLOCK_STATE_RUNNING) ^ (old_state == MFCLOCK_STATE_RUNNING)) + { + struct clock_timer *timer, *timer2; + + if (clock->state == MFCLOCK_STATE_RUNNING) + { + LIST_FOR_EACH_ENTRY_SAFE(timer, timer2, &clock->timers, struct clock_timer, entry) + { + list_remove(&timer->entry); + hr = MFCreateAsyncResult(&timer->IUnknown_iface, &clock->timer_callback, NULL, &result); + IUnknown_Release(&timer->IUnknown_iface); + if (SUCCEEDED(hr)) + { + MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_TIMER, result); + IMFAsyncResult_Release(result); + } + } + } + else + { + LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry) + { + if (timer->key) + { + MFCancelWorkItem(timer->key); + timer->key = 0; + } + } + } + } + LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct clock_sink, entry) { if (SUCCEEDED(create_sink_notification(system_time, param, notification, sink->state_sink, ¬ify_object))) { - hr = MFCreateAsyncResult(notify_object, &clock->IMFAsyncCallback_iface, NULL, &result); + hr = MFCreateAsyncResult(notify_object, &clock->sink_callback, NULL, &result); IUnknown_Release(notify_object); if (SUCCEEDED(hr)) { @@ -2181,19 +2258,151 @@ static ULONG WINAPI present_clock_timer_Release(IMFTimer *iface) return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface); }
+static HRESULT present_clock_schedule_timer(struct presentation_clock *clock, DWORD flags, LONGLONG time, + struct clock_timer *timer) +{ + IMFAsyncResult *result; + MFTIME systime, clocktime; + LONGLONG frequency; + HRESULT hr; + + if (!(flags & MFTIMER_RELATIVE)) + { + if (FAILED(hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, 0, &clocktime, &systime))) + { + WARN("Failed to get clock time, hr %#x.\n", hr); + return hr; + } + time -= clocktime; + } + + frequency = clock->frequency / 1000; + time /= frequency; + + /* Scheduled item is using clock instance callback, with timer instance as an object. Clock callback will + call user callback and cleanup timer list. */ + + if (FAILED(hr = MFCreateAsyncResult(&timer->IUnknown_iface, &clock->timer_callback, NULL, &result))) + return hr; + + hr = MFScheduleWorkItemEx(result, -time, &timer->key); + IMFAsyncResult_Release(result); + + return hr; +} + +static HRESULT WINAPI clock_timer_QueryInterface(IUnknown *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IUnknown_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI clock_timer_AddRef(IUnknown *iface) +{ + struct clock_timer *timer = impl_clock_timer_from_IUnknown(iface); + return InterlockedIncrement(&timer->refcount); +} + +static ULONG WINAPI clock_timer_Release(IUnknown *iface) +{ + struct clock_timer *timer = impl_clock_timer_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&timer->refcount); + + if (!refcount) + { + IMFAsyncResult_Release(timer->result); + IMFAsyncCallback_Release(timer->callback); + heap_free(timer); + } + + return refcount; +} + +static const IUnknownVtbl clock_timer_vtbl = +{ + clock_timer_QueryInterface, + clock_timer_AddRef, + clock_timer_Release, +}; + 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); + struct presentation_clock *clock = impl_from_IMFTimer(iface); + struct clock_timer *clock_timer; + HRESULT hr;
- return E_NOTIMPL; + TRACE("%p, %#x, %s, %p, %p, %p.\n", iface, flags, wine_dbgstr_longlong(time), callback, state, cancel_key); + + if (!(clock_timer = heap_alloc_zero(sizeof(*clock_timer)))) + return E_OUTOFMEMORY; + + if (FAILED(hr = MFCreateAsyncResult(NULL, NULL, state, &clock_timer->result))) + { + heap_free(clock_timer); + return hr; + } + + clock_timer->IUnknown_iface.lpVtbl = &clock_timer_vtbl; + clock_timer->refcount = 1; + clock_timer->callback = callback; + IMFAsyncCallback_AddRef(clock_timer->callback); + + EnterCriticalSection(&clock->cs); + + if (clock->state == MFCLOCK_STATE_RUNNING) + hr = present_clock_schedule_timer(clock, flags, time, clock_timer); + else if (clock->state == MFCLOCK_STATE_STOPPED) + hr = MF_S_CLOCK_STOPPED; + + if (SUCCEEDED(hr)) + list_add_tail(&clock->timers, &clock_timer->entry); + + LeaveCriticalSection(&clock->cs); + + if (SUCCEEDED(hr) && cancel_key) + { + *cancel_key = &clock_timer->IUnknown_iface; + IUnknown_AddRef(*cancel_key); + } + + return hr; }
static HRESULT WINAPI present_clock_timer_CancelTimer(IMFTimer *iface, IUnknown *cancel_key) { - FIXME("%p, %p.\n", iface, cancel_key); + struct presentation_clock *clock = impl_from_IMFTimer(iface); + struct clock_timer *timer;
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, cancel_key); + + EnterCriticalSection(&clock->cs); + + LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry) + { + if (&timer->IUnknown_iface == cancel_key) + { + list_remove(&timer->entry); + if (timer->key) + { + MFCancelWorkItem(timer->key); + timer->key = 0; + } + IUnknown_Release(&timer->IUnknown_iface); + break; + } + } + + LeaveCriticalSection(&clock->cs); + + return S_OK; }
static const IMFTimerVtbl presentclocktimervtbl = @@ -2246,7 +2455,7 @@ static const IMFShutdownVtbl presentclockshutdownvtbl = present_clock_shutdown_GetShutdownStatus, };
-static HRESULT WINAPI present_clock_sink_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **out) +static HRESULT WINAPI present_clock_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **out) { if (IsEqualIID(riid, &IID_IMFAsyncCallback) || IsEqualIID(riid, &IID_IUnknown)) @@ -2263,17 +2472,17 @@ static HRESULT WINAPI present_clock_sink_callback_QueryInterface(IMFAsyncCallbac
static ULONG WINAPI present_clock_sink_callback_AddRef(IMFAsyncCallback *iface) { - struct presentation_clock *clock = impl_from_IMFAsyncCallback(iface); + struct presentation_clock *clock = impl_from_sink_callback_IMFAsyncCallback(iface); return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface); }
static ULONG WINAPI present_clock_sink_callback_Release(IMFAsyncCallback *iface) { - struct presentation_clock *clock = impl_from_IMFAsyncCallback(iface); + struct presentation_clock *clock = impl_from_sink_callback_IMFAsyncCallback(iface); return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface); }
-static HRESULT WINAPI present_clock_sink_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +static HRESULT WINAPI present_clock_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) { return E_NOTIMPL; } @@ -2298,13 +2507,57 @@ static HRESULT WINAPI present_clock_sink_callback_Invoke(IMFAsyncCallback *iface
static const IMFAsyncCallbackVtbl presentclocksinkcallbackvtbl = { - present_clock_sink_callback_QueryInterface, + present_clock_callback_QueryInterface, present_clock_sink_callback_AddRef, present_clock_sink_callback_Release, - present_clock_sink_callback_GetParameters, + present_clock_callback_GetParameters, present_clock_sink_callback_Invoke, };
+static ULONG WINAPI present_clock_timer_callback_AddRef(IMFAsyncCallback *iface) +{ + struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface); + return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface); +} + +static ULONG WINAPI present_clock_timer_callback_Release(IMFAsyncCallback *iface) +{ + struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface); + return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface); +} + +static HRESULT WINAPI present_clock_timer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface); + struct clock_timer *timer; + IUnknown *object; + HRESULT hr; + + if (FAILED(hr = IMFAsyncResult_GetObject(result, &object))) + return hr; + + timer = impl_clock_timer_from_IUnknown(object); + + EnterCriticalSection(&clock->cs); + list_remove(&timer->entry); + LeaveCriticalSection(&clock->cs); + + IMFAsyncCallback_Invoke(timer->callback, timer->result); + + IUnknown_Release(object); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl presentclocktimercallbackvtbl = +{ + present_clock_callback_QueryInterface, + present_clock_timer_callback_AddRef, + present_clock_timer_callback_Release, + present_clock_callback_GetParameters, + present_clock_timer_callback_Invoke, +}; + /*********************************************************************** * MFCreatePresentationClock (mf.@) */ @@ -2322,9 +2575,11 @@ HRESULT WINAPI MFCreatePresentationClock(IMFPresentationClock **clock) object->IMFRateControl_iface.lpVtbl = &presentclockratecontrolvtbl; object->IMFTimer_iface.lpVtbl = &presentclocktimervtbl; object->IMFShutdown_iface.lpVtbl = &presentclockshutdownvtbl; - object->IMFAsyncCallback_iface.lpVtbl = &presentclocksinkcallbackvtbl; + object->sink_callback.lpVtbl = &presentclocksinkcallbackvtbl; + object->timer_callback.lpVtbl = &presentclocktimercallbackvtbl; object->refcount = 1; list_init(&object->sinks); + list_init(&object->timers); object->rate = 1.0f; InitializeCriticalSection(&object->cs);
diff --git a/include/mfidl.idl b/include/mfidl.idl index da43399828..b301edbbdd 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -152,6 +152,11 @@ interface IMFRateControl : IUnknown [in, out, unique] float *rate); }
+typedef enum MFTIMER_FLAGS +{ + MFTIMER_RELATIVE = 0x00000001, +} MFTIMER_FLAGS; + [ object, uuid(e56e4cbd-8f70-49d8-a0f8-edb3d6ab9bf2),
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/session.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index b80499477c..6b5d590a25 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -278,7 +278,7 @@ static struct clock_timer *impl_clock_timer_from_IUnknown(IUnknown *iface) return CONTAINING_RECORD(iface, struct clock_timer, IUnknown_iface); }
-static struct sink_notification *impl_from_IUnknown(IUnknown *iface) +static struct sink_notification *impl_sink_notification_from_IUnknown(IUnknown *iface) { return CONTAINING_RECORD(iface, struct sink_notification, IUnknown_iface); } @@ -1918,7 +1918,7 @@ static HRESULT WINAPI sink_notification_QueryInterface(IUnknown *iface, REFIID r
static ULONG WINAPI sink_notification_AddRef(IUnknown *iface) { - struct sink_notification *notification = impl_from_IUnknown(iface); + struct sink_notification *notification = impl_sink_notification_from_IUnknown(iface); ULONG refcount = InterlockedIncrement(¬ification->refcount);
TRACE("%p, refcount %u.\n", iface, refcount); @@ -1928,7 +1928,7 @@ static ULONG WINAPI sink_notification_AddRef(IUnknown *iface)
static ULONG WINAPI sink_notification_Release(IUnknown *iface) { - struct sink_notification *notification = impl_from_IUnknown(iface); + struct sink_notification *notification = impl_sink_notification_from_IUnknown(iface); ULONG refcount = InterlockedDecrement(¬ification->refcount);
TRACE("%p, refcount %u.\n", iface, refcount); @@ -2496,7 +2496,7 @@ static HRESULT WINAPI present_clock_sink_callback_Invoke(IMFAsyncCallback *iface if (FAILED(hr = IMFAsyncResult_GetObject(result, &object))) return hr;
- data = impl_from_IUnknown(object); + data = impl_sink_notification_from_IUnknown(object);
clock_call_state_change(data->system_time, data->param, data->notification, data->sink);