2 * Copyright 2017 Nikolay Sivov
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "wine/debug.h"
22 #include "wine/list.h"
24 #include "mf_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
31 IMFClockStateSink
*state_sink
;
43 enum clock_notification
49 CLOCK_NOTIFY_SET_RATE
,
52 struct clock_state_change_param
61 struct sink_notification
63 IUnknown IUnknown_iface
;
66 struct clock_state_change_param param
;
67 enum clock_notification notification
;
68 IMFClockStateSink
*sink
;
73 IUnknown IUnknown_iface
;
75 IMFAsyncResult
*result
;
76 IMFAsyncCallback
*callback
;
81 struct presentation_clock
83 IMFPresentationClock IMFPresentationClock_iface
;
84 IMFRateControl IMFRateControl_iface
;
85 IMFTimer IMFTimer_iface
;
86 IMFShutdown IMFShutdown_iface
;
87 IMFAsyncCallback sink_callback
;
88 IMFAsyncCallback timer_callback
;
90 IMFPresentationTimeSource
*time_source
;
91 IMFClockStateSink
*time_source_sink
;
93 LONGLONG start_offset
;
102 static struct presentation_clock
*impl_from_IMFPresentationClock(IMFPresentationClock
*iface
)
104 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFPresentationClock_iface
);
107 static struct presentation_clock
*impl_from_IMFRateControl(IMFRateControl
*iface
)
109 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFRateControl_iface
);
112 static struct presentation_clock
*impl_from_IMFTimer(IMFTimer
*iface
)
114 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFTimer_iface
);
117 static struct presentation_clock
*impl_from_IMFShutdown(IMFShutdown
*iface
)
119 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFShutdown_iface
);
122 static struct presentation_clock
*impl_from_sink_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
124 return CONTAINING_RECORD(iface
, struct presentation_clock
, sink_callback
);
127 static struct presentation_clock
*impl_from_timer_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
129 return CONTAINING_RECORD(iface
, struct presentation_clock
, timer_callback
);
132 static struct clock_timer
*impl_clock_timer_from_IUnknown(IUnknown
*iface
)
134 return CONTAINING_RECORD(iface
, struct clock_timer
, IUnknown_iface
);
137 static struct sink_notification
*impl_sink_notification_from_IUnknown(IUnknown
*iface
)
139 return CONTAINING_RECORD(iface
, struct sink_notification
, IUnknown_iface
);
142 static HRESULT WINAPI
sink_notification_QueryInterface(IUnknown
*iface
, REFIID riid
, void **out
)
144 if (IsEqualIID(riid
, &IID_IUnknown
))
147 IUnknown_AddRef(iface
);
151 WARN("Unsupported %s.\n", debugstr_guid(riid
));
153 return E_NOINTERFACE
;
156 static ULONG WINAPI
sink_notification_AddRef(IUnknown
*iface
)
158 struct sink_notification
*notification
= impl_sink_notification_from_IUnknown(iface
);
159 ULONG refcount
= InterlockedIncrement(¬ification
->refcount
);
161 TRACE("%p, refcount %u.\n", iface
, refcount
);
166 static ULONG WINAPI
sink_notification_Release(IUnknown
*iface
)
168 struct sink_notification
*notification
= impl_sink_notification_from_IUnknown(iface
);
169 ULONG refcount
= InterlockedDecrement(¬ification
->refcount
);
171 TRACE("%p, refcount %u.\n", iface
, refcount
);
175 IMFClockStateSink_Release(notification
->sink
);
182 static const IUnknownVtbl sinknotificationvtbl
=
184 sink_notification_QueryInterface
,
185 sink_notification_AddRef
,
186 sink_notification_Release
,
189 static void clock_notify_async_sink(struct presentation_clock
*clock
, MFTIME system_time
,
190 struct clock_state_change_param param
, enum clock_notification notification
, IMFClockStateSink
*sink
)
192 struct sink_notification
*object
;
193 IMFAsyncResult
*result
;
196 if (!(object
= malloc(sizeof(*object
))))
199 object
->IUnknown_iface
.lpVtbl
= &sinknotificationvtbl
;
200 object
->refcount
= 1;
201 object
->system_time
= system_time
;
202 object
->param
= param
;
203 object
->notification
= notification
;
205 IMFClockStateSink_AddRef(object
->sink
);
207 hr
= MFCreateAsyncResult(&object
->IUnknown_iface
, &clock
->sink_callback
, NULL
, &result
);
208 IUnknown_Release(&object
->IUnknown_iface
);
211 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD
, result
);
212 IMFAsyncResult_Release(result
);
216 static HRESULT WINAPI
present_clock_QueryInterface(IMFPresentationClock
*iface
, REFIID riid
, void **out
)
218 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
220 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
222 if (IsEqualIID(riid
, &IID_IMFPresentationClock
) ||
223 IsEqualIID(riid
, &IID_IMFClock
) ||
224 IsEqualIID(riid
, &IID_IUnknown
))
226 *out
= &clock
->IMFPresentationClock_iface
;
228 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
230 *out
= &clock
->IMFRateControl_iface
;
232 else if (IsEqualIID(riid
, &IID_IMFTimer
))
234 *out
= &clock
->IMFTimer_iface
;
236 else if (IsEqualIID(riid
, &IID_IMFShutdown
))
238 *out
= &clock
->IMFShutdown_iface
;
242 WARN("Unsupported %s.\n", debugstr_guid(riid
));
244 return E_NOINTERFACE
;
247 IUnknown_AddRef((IUnknown
*)*out
);
251 static ULONG WINAPI
present_clock_AddRef(IMFPresentationClock
*iface
)
253 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
254 ULONG refcount
= InterlockedIncrement(&clock
->refcount
);
256 TRACE("%p, refcount %u.\n", iface
, refcount
);
261 static ULONG WINAPI
present_clock_Release(IMFPresentationClock
*iface
)
263 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
264 ULONG refcount
= InterlockedDecrement(&clock
->refcount
);
265 struct clock_timer
*timer
, *timer2
;
266 struct clock_sink
*sink
, *sink2
;
268 TRACE("%p, refcount %u.\n", iface
, refcount
);
272 if (clock
->time_source
)
273 IMFPresentationTimeSource_Release(clock
->time_source
);
274 if (clock
->time_source_sink
)
275 IMFClockStateSink_Release(clock
->time_source_sink
);
276 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &clock
->sinks
, struct clock_sink
, entry
)
278 list_remove(&sink
->entry
);
279 IMFClockStateSink_Release(sink
->state_sink
);
282 LIST_FOR_EACH_ENTRY_SAFE(timer
, timer2
, &clock
->timers
, struct clock_timer
, entry
)
284 list_remove(&timer
->entry
);
285 IUnknown_Release(&timer
->IUnknown_iface
);
287 DeleteCriticalSection(&clock
->cs
);
294 static HRESULT WINAPI
present_clock_GetClockCharacteristics(IMFPresentationClock
*iface
, DWORD
*flags
)
296 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
297 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
299 TRACE("%p, %p.\n", iface
, flags
);
301 EnterCriticalSection(&clock
->cs
);
302 if (clock
->time_source
)
303 hr
= IMFPresentationTimeSource_GetClockCharacteristics(clock
->time_source
, flags
);
304 LeaveCriticalSection(&clock
->cs
);
309 static HRESULT WINAPI
present_clock_GetCorrelatedTime(IMFPresentationClock
*iface
, DWORD reserved
,
310 LONGLONG
*clock_time
, MFTIME
*system_time
)
312 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
313 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
315 TRACE("%p, %#x, %p, %p.\n", iface
, reserved
, clock_time
, system_time
);
317 EnterCriticalSection(&clock
->cs
);
318 if (clock
->time_source
)
319 hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, reserved
, clock_time
, system_time
);
320 LeaveCriticalSection(&clock
->cs
);
325 static HRESULT WINAPI
present_clock_GetContinuityKey(IMFPresentationClock
*iface
, DWORD
*key
)
327 TRACE("%p, %p.\n", iface
, key
);
334 static HRESULT WINAPI
present_clock_GetState(IMFPresentationClock
*iface
, DWORD reserved
, MFCLOCK_STATE
*state
)
336 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
338 TRACE("%p, %#x, %p.\n", iface
, reserved
, state
);
340 EnterCriticalSection(&clock
->cs
);
341 *state
= clock
->state
;
342 LeaveCriticalSection(&clock
->cs
);
347 static HRESULT WINAPI
present_clock_GetProperties(IMFPresentationClock
*iface
, MFCLOCK_PROPERTIES
*props
)
349 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
350 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
352 TRACE("%p, %p.\n", iface
, props
);
354 EnterCriticalSection(&clock
->cs
);
355 if (clock
->time_source
)
356 hr
= IMFPresentationTimeSource_GetProperties(clock
->time_source
, props
);
357 LeaveCriticalSection(&clock
->cs
);
362 static HRESULT WINAPI
present_clock_SetTimeSource(IMFPresentationClock
*iface
,
363 IMFPresentationTimeSource
*time_source
)
365 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
366 MFCLOCK_PROPERTIES props
;
367 IMFClock
*source_clock
;
370 TRACE("%p, %p.\n", iface
, time_source
);
372 EnterCriticalSection(&clock
->cs
);
374 if (clock
->time_source
)
375 IMFPresentationTimeSource_Release(clock
->time_source
);
376 if (clock
->time_source_sink
)
377 IMFClockStateSink_Release(clock
->time_source_sink
);
378 clock
->time_source
= NULL
;
379 clock
->time_source_sink
= NULL
;
381 hr
= IMFPresentationTimeSource_QueryInterface(time_source
, &IID_IMFClockStateSink
, (void **)&clock
->time_source_sink
);
384 clock
->time_source
= time_source
;
385 IMFPresentationTimeSource_AddRef(clock
->time_source
);
388 if (SUCCEEDED(IMFPresentationTimeSource_GetUnderlyingClock(time_source
, &source_clock
)))
390 if (SUCCEEDED(IMFClock_GetProperties(source_clock
, &props
)))
391 clock
->frequency
= props
.qwClockFrequency
;
392 IMFClock_Release(source_clock
);
395 if (!clock
->frequency
)
396 clock
->frequency
= MFCLOCK_FREQUENCY_HNS
;
398 LeaveCriticalSection(&clock
->cs
);
403 static HRESULT WINAPI
present_clock_GetTimeSource(IMFPresentationClock
*iface
,
404 IMFPresentationTimeSource
**time_source
)
406 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
409 TRACE("%p, %p.\n", iface
, time_source
);
414 EnterCriticalSection(&clock
->cs
);
415 if (clock
->time_source
)
417 *time_source
= clock
->time_source
;
418 IMFPresentationTimeSource_AddRef(*time_source
);
421 hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
422 LeaveCriticalSection(&clock
->cs
);
427 static HRESULT WINAPI
present_clock_GetTime(IMFPresentationClock
*iface
, MFTIME
*time
)
429 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
430 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
433 TRACE("%p, %p.\n", iface
, time
);
438 EnterCriticalSection(&clock
->cs
);
439 if (clock
->time_source
)
440 hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, 0, time
, &systime
);
441 LeaveCriticalSection(&clock
->cs
);
446 static HRESULT WINAPI
present_clock_AddClockStateSink(IMFPresentationClock
*iface
, IMFClockStateSink
*state_sink
)
448 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
449 struct clock_sink
*sink
, *cur
;
452 TRACE("%p, %p.\n", iface
, state_sink
);
457 if (!(sink
= malloc(sizeof(*sink
))))
458 return E_OUTOFMEMORY
;
460 sink
->state_sink
= state_sink
;
461 IMFClockStateSink_AddRef(sink
->state_sink
);
463 EnterCriticalSection(&clock
->cs
);
464 LIST_FOR_EACH_ENTRY(cur
, &clock
->sinks
, struct clock_sink
, entry
)
466 if (cur
->state_sink
== state_sink
)
474 static const enum clock_notification notifications
[MFCLOCK_STATE_PAUSED
+ 1] =
476 /* MFCLOCK_STATE_INVALID */ 0, /* Does not apply */
477 /* MFCLOCK_STATE_RUNNING */ CLOCK_NOTIFY_START
,
478 /* MFCLOCK_STATE_STOPPED */ CLOCK_NOTIFY_STOP
,
479 /* MFCLOCK_STATE_PAUSED */ CLOCK_NOTIFY_PAUSE
,
481 struct clock_state_change_param param
;
483 if (!clock
->is_shut_down
&& clock
->state
!= MFCLOCK_STATE_INVALID
)
485 param
.u
.offset
= clock
->start_offset
;
486 clock_notify_async_sink(clock
, MFGetSystemTime(), param
, notifications
[clock
->state
], sink
->state_sink
);
489 list_add_tail(&clock
->sinks
, &sink
->entry
);
491 LeaveCriticalSection(&clock
->cs
);
495 IMFClockStateSink_Release(sink
->state_sink
);
502 static HRESULT WINAPI
present_clock_RemoveClockStateSink(IMFPresentationClock
*iface
,
503 IMFClockStateSink
*state_sink
)
505 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
506 struct clock_sink
*sink
;
508 TRACE("%p, %p.\n", iface
, state_sink
);
513 EnterCriticalSection(&clock
->cs
);
514 LIST_FOR_EACH_ENTRY(sink
, &clock
->sinks
, struct clock_sink
, entry
)
516 if (sink
->state_sink
== state_sink
)
518 IMFClockStateSink_Release(sink
->state_sink
);
519 list_remove(&sink
->entry
);
524 LeaveCriticalSection(&clock
->cs
);
529 static HRESULT
clock_call_state_change(MFTIME system_time
, struct clock_state_change_param param
,
530 enum clock_notification notification
, IMFClockStateSink
*sink
)
534 switch (notification
)
536 case CLOCK_NOTIFY_START
:
537 hr
= IMFClockStateSink_OnClockStart(sink
, system_time
, param
.u
.offset
);
539 case CLOCK_NOTIFY_STOP
:
540 hr
= IMFClockStateSink_OnClockStop(sink
, system_time
);
542 case CLOCK_NOTIFY_PAUSE
:
543 hr
= IMFClockStateSink_OnClockPause(sink
, system_time
);
545 case CLOCK_NOTIFY_RESTART
:
546 hr
= IMFClockStateSink_OnClockRestart(sink
, system_time
);
548 case CLOCK_NOTIFY_SET_RATE
:
549 /* System time source does not allow 0.0 rate, presentation clock allows it without raising errors. */
550 IMFClockStateSink_OnClockSetRate(sink
, system_time
, param
.u
.rate
);
559 static HRESULT
clock_change_state(struct presentation_clock
*clock
, enum clock_command command
,
560 struct clock_state_change_param param
)
562 static const BYTE state_change_is_allowed
[MFCLOCK_STATE_PAUSED
+1][CLOCK_CMD_MAX
] =
564 /* INVALID */ { 1, 1, 1, 1 },
565 /* RUNNING */ { 1, 1, 1, 1 },
566 /* STOPPED */ { 1, 1, 0, 1 },
567 /* PAUSED */ { 1, 1, 0, 1 },
569 static const MFCLOCK_STATE states
[CLOCK_CMD_MAX
] =
571 /* CLOCK_CMD_START */ MFCLOCK_STATE_RUNNING
,
572 /* CLOCK_CMD_STOP */ MFCLOCK_STATE_STOPPED
,
573 /* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED
,
574 /* CLOCK_CMD_SET_RATE */ 0, /* Unused */
576 static const enum clock_notification notifications
[CLOCK_CMD_MAX
] =
578 /* CLOCK_CMD_START */ CLOCK_NOTIFY_START
,
579 /* CLOCK_CMD_STOP */ CLOCK_NOTIFY_STOP
,
580 /* CLOCK_CMD_PAUSE */ CLOCK_NOTIFY_PAUSE
,
581 /* CLOCK_CMD_SET_RATE */ CLOCK_NOTIFY_SET_RATE
,
583 enum clock_notification notification
;
584 struct clock_sink
*sink
;
585 MFCLOCK_STATE old_state
;
586 IMFAsyncResult
*result
;
590 if (!clock
->time_source
)
591 return MF_E_CLOCK_NO_TIME_SOURCE
;
593 if (command
!= CLOCK_CMD_SET_RATE
&& clock
->state
== states
[command
] && clock
->state
!= MFCLOCK_STATE_RUNNING
)
594 return MF_E_CLOCK_STATE_ALREADY_SET
;
596 if (!state_change_is_allowed
[clock
->state
][command
])
597 return MF_E_INVALIDREQUEST
;
599 system_time
= MFGetSystemTime();
601 if (command
== CLOCK_CMD_START
&& clock
->state
== MFCLOCK_STATE_PAUSED
&&
602 param
.u
.offset
== PRESENTATION_CURRENT_POSITION
)
604 notification
= CLOCK_NOTIFY_RESTART
;
607 notification
= notifications
[command
];
609 if (FAILED(hr
= clock_call_state_change(system_time
, param
, notification
, clock
->time_source_sink
)))
612 old_state
= clock
->state
;
613 if (command
!= CLOCK_CMD_SET_RATE
)
614 clock
->state
= states
[command
];
616 /* Dump all pending timer requests immediately on start; otherwise try to cancel scheduled items when
617 transitioning from running state. */
618 if ((clock
->state
== MFCLOCK_STATE_RUNNING
) ^ (old_state
== MFCLOCK_STATE_RUNNING
))
620 struct clock_timer
*timer
, *timer2
;
622 if (clock
->state
== MFCLOCK_STATE_RUNNING
)
624 LIST_FOR_EACH_ENTRY_SAFE(timer
, timer2
, &clock
->timers
, struct clock_timer
, entry
)
626 list_remove(&timer
->entry
);
627 hr
= MFCreateAsyncResult(&timer
->IUnknown_iface
, &clock
->timer_callback
, NULL
, &result
);
628 IUnknown_Release(&timer
->IUnknown_iface
);
631 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_TIMER
, result
);
632 IMFAsyncResult_Release(result
);
638 LIST_FOR_EACH_ENTRY(timer
, &clock
->timers
, struct clock_timer
, entry
)
642 MFCancelWorkItem(timer
->key
);
649 LIST_FOR_EACH_ENTRY(sink
, &clock
->sinks
, struct clock_sink
, entry
)
651 clock_notify_async_sink(clock
, system_time
, param
, notification
, sink
->state_sink
);
657 static HRESULT WINAPI
present_clock_Start(IMFPresentationClock
*iface
, LONGLONG start_offset
)
659 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
660 struct clock_state_change_param param
= {{0}};
663 TRACE("%p, %s.\n", iface
, debugstr_time(start_offset
));
665 EnterCriticalSection(&clock
->cs
);
666 clock
->start_offset
= param
.u
.offset
= start_offset
;
667 hr
= clock_change_state(clock
, CLOCK_CMD_START
, param
);
668 LeaveCriticalSection(&clock
->cs
);
673 static HRESULT WINAPI
present_clock_Stop(IMFPresentationClock
*iface
)
675 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
676 struct clock_state_change_param param
= {{0}};
679 TRACE("%p.\n", iface
);
681 EnterCriticalSection(&clock
->cs
);
682 hr
= clock_change_state(clock
, CLOCK_CMD_STOP
, param
);
683 LeaveCriticalSection(&clock
->cs
);
688 static HRESULT WINAPI
present_clock_Pause(IMFPresentationClock
*iface
)
690 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
691 struct clock_state_change_param param
= {{0}};
694 TRACE("%p.\n", iface
);
696 EnterCriticalSection(&clock
->cs
);
697 hr
= clock_change_state(clock
, CLOCK_CMD_PAUSE
, param
);
698 LeaveCriticalSection(&clock
->cs
);
703 static const IMFPresentationClockVtbl presentationclockvtbl
=
705 present_clock_QueryInterface
,
706 present_clock_AddRef
,
707 present_clock_Release
,
708 present_clock_GetClockCharacteristics
,
709 present_clock_GetCorrelatedTime
,
710 present_clock_GetContinuityKey
,
711 present_clock_GetState
,
712 present_clock_GetProperties
,
713 present_clock_SetTimeSource
,
714 present_clock_GetTimeSource
,
715 present_clock_GetTime
,
716 present_clock_AddClockStateSink
,
717 present_clock_RemoveClockStateSink
,
723 static HRESULT WINAPI
present_clock_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **out
)
725 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
726 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
729 static ULONG WINAPI
present_clock_rate_control_AddRef(IMFRateControl
*iface
)
731 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
732 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
735 static ULONG WINAPI
present_clock_rate_control_Release(IMFRateControl
*iface
)
737 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
738 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
741 static HRESULT WINAPI
present_clock_rate_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
743 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
744 struct clock_state_change_param param
;
747 TRACE("%p, %d, %f.\n", iface
, thin
, rate
);
750 return MF_E_THINNING_UNSUPPORTED
;
752 EnterCriticalSection(&clock
->cs
);
754 if (SUCCEEDED(hr
= clock_change_state(clock
, CLOCK_CMD_SET_RATE
, param
)))
756 LeaveCriticalSection(&clock
->cs
);
761 static HRESULT WINAPI
present_clock_rate_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
763 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
765 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
773 EnterCriticalSection(&clock
->cs
);
775 LeaveCriticalSection(&clock
->cs
);
780 static const IMFRateControlVtbl presentclockratecontrolvtbl
=
782 present_clock_rate_control_QueryInterface
,
783 present_clock_rate_control_AddRef
,
784 present_clock_rate_control_Release
,
785 present_clock_rate_SetRate
,
786 present_clock_rate_GetRate
,
789 static HRESULT WINAPI
present_clock_timer_QueryInterface(IMFTimer
*iface
, REFIID riid
, void **out
)
791 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
792 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
795 static ULONG WINAPI
present_clock_timer_AddRef(IMFTimer
*iface
)
797 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
798 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
801 static ULONG WINAPI
present_clock_timer_Release(IMFTimer
*iface
)
803 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
804 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
807 static HRESULT
present_clock_schedule_timer(struct presentation_clock
*clock
, DWORD flags
, LONGLONG time
,
808 struct clock_timer
*timer
)
810 IMFAsyncResult
*result
;
811 MFTIME systime
, clocktime
;
815 if (!(flags
& MFTIMER_RELATIVE
))
817 if (FAILED(hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, 0, &clocktime
, &systime
)))
819 WARN("Failed to get clock time, hr %#x.\n", hr
);
825 frequency
= clock
->frequency
/ 1000;
828 /* Scheduled item is using clock instance callback, with timer instance as an object. Clock callback will
829 call user callback and cleanup timer list. */
831 if (FAILED(hr
= MFCreateAsyncResult(&timer
->IUnknown_iface
, &clock
->timer_callback
, NULL
, &result
)))
834 hr
= MFScheduleWorkItemEx(result
, -time
, &timer
->key
);
835 IMFAsyncResult_Release(result
);
840 static HRESULT WINAPI
clock_timer_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
842 if (IsEqualIID(riid
, &IID_IUnknown
))
845 IUnknown_AddRef(iface
);
850 return E_NOINTERFACE
;
853 static ULONG WINAPI
clock_timer_AddRef(IUnknown
*iface
)
855 struct clock_timer
*timer
= impl_clock_timer_from_IUnknown(iface
);
856 return InterlockedIncrement(&timer
->refcount
);
859 static ULONG WINAPI
clock_timer_Release(IUnknown
*iface
)
861 struct clock_timer
*timer
= impl_clock_timer_from_IUnknown(iface
);
862 ULONG refcount
= InterlockedDecrement(&timer
->refcount
);
866 IMFAsyncResult_Release(timer
->result
);
867 IMFAsyncCallback_Release(timer
->callback
);
874 static const IUnknownVtbl clock_timer_vtbl
=
876 clock_timer_QueryInterface
,
881 static HRESULT WINAPI
present_clock_timer_SetTimer(IMFTimer
*iface
, DWORD flags
, LONGLONG time
,
882 IMFAsyncCallback
*callback
, IUnknown
*state
, IUnknown
**cancel_key
)
884 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
885 struct clock_timer
*clock_timer
;
888 TRACE("%p, %#x, %s, %p, %p, %p.\n", iface
, flags
, debugstr_time(time
), callback
, state
, cancel_key
);
890 if (!(clock_timer
= calloc(1, sizeof(*clock_timer
))))
891 return E_OUTOFMEMORY
;
893 if (FAILED(hr
= MFCreateAsyncResult(NULL
, NULL
, state
, &clock_timer
->result
)))
899 clock_timer
->IUnknown_iface
.lpVtbl
= &clock_timer_vtbl
;
900 clock_timer
->refcount
= 1;
901 clock_timer
->callback
= callback
;
902 IMFAsyncCallback_AddRef(clock_timer
->callback
);
904 EnterCriticalSection(&clock
->cs
);
906 if (clock
->state
== MFCLOCK_STATE_RUNNING
)
907 hr
= present_clock_schedule_timer(clock
, flags
, time
, clock_timer
);
908 else if (clock
->state
== MFCLOCK_STATE_STOPPED
)
909 hr
= MF_S_CLOCK_STOPPED
;
913 list_add_tail(&clock
->timers
, &clock_timer
->entry
);
916 *cancel_key
= &clock_timer
->IUnknown_iface
;
917 IUnknown_AddRef(*cancel_key
);
921 LeaveCriticalSection(&clock
->cs
);
924 IUnknown_Release(&clock_timer
->IUnknown_iface
);
929 static HRESULT WINAPI
present_clock_timer_CancelTimer(IMFTimer
*iface
, IUnknown
*cancel_key
)
931 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
932 struct clock_timer
*timer
;
934 TRACE("%p, %p.\n", iface
, cancel_key
);
936 EnterCriticalSection(&clock
->cs
);
938 LIST_FOR_EACH_ENTRY(timer
, &clock
->timers
, struct clock_timer
, entry
)
940 if (&timer
->IUnknown_iface
== cancel_key
)
942 list_remove(&timer
->entry
);
945 MFCancelWorkItem(timer
->key
);
948 IUnknown_Release(&timer
->IUnknown_iface
);
953 LeaveCriticalSection(&clock
->cs
);
958 static const IMFTimerVtbl presentclocktimervtbl
=
960 present_clock_timer_QueryInterface
,
961 present_clock_timer_AddRef
,
962 present_clock_timer_Release
,
963 present_clock_timer_SetTimer
,
964 present_clock_timer_CancelTimer
,
967 static HRESULT WINAPI
present_clock_shutdown_QueryInterface(IMFShutdown
*iface
, REFIID riid
, void **out
)
969 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
970 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
973 static ULONG WINAPI
present_clock_shutdown_AddRef(IMFShutdown
*iface
)
975 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
976 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
979 static ULONG WINAPI
present_clock_shutdown_Release(IMFShutdown
*iface
)
981 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
982 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
985 static HRESULT WINAPI
present_clock_shutdown_Shutdown(IMFShutdown
*iface
)
987 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
989 TRACE("%p.\n", iface
);
991 EnterCriticalSection(&clock
->cs
);
992 clock
->is_shut_down
= TRUE
;
993 LeaveCriticalSection(&clock
->cs
);
998 static HRESULT WINAPI
present_clock_shutdown_GetShutdownStatus(IMFShutdown
*iface
, MFSHUTDOWN_STATUS
*status
)
1000 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
1003 TRACE("%p, %p.\n", iface
, status
);
1006 return E_INVALIDARG
;
1008 EnterCriticalSection(&clock
->cs
);
1009 if (clock
->is_shut_down
)
1010 *status
= MFSHUTDOWN_COMPLETED
;
1012 hr
= MF_E_INVALIDREQUEST
;
1013 LeaveCriticalSection(&clock
->cs
);
1018 static const IMFShutdownVtbl presentclockshutdownvtbl
=
1020 present_clock_shutdown_QueryInterface
,
1021 present_clock_shutdown_AddRef
,
1022 present_clock_shutdown_Release
,
1023 present_clock_shutdown_Shutdown
,
1024 present_clock_shutdown_GetShutdownStatus
,
1027 static HRESULT WINAPI
present_clock_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **out
)
1029 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
1030 IsEqualIID(riid
, &IID_IUnknown
))
1033 IMFAsyncCallback_AddRef(iface
);
1037 WARN("Unsupported %s.\n", wine_dbgstr_guid(riid
));
1039 return E_NOINTERFACE
;
1042 static ULONG WINAPI
present_clock_sink_callback_AddRef(IMFAsyncCallback
*iface
)
1044 struct presentation_clock
*clock
= impl_from_sink_callback_IMFAsyncCallback(iface
);
1045 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
1048 static ULONG WINAPI
present_clock_sink_callback_Release(IMFAsyncCallback
*iface
)
1050 struct presentation_clock
*clock
= impl_from_sink_callback_IMFAsyncCallback(iface
);
1051 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
1054 static HRESULT WINAPI
present_clock_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
1059 static HRESULT WINAPI
present_clock_sink_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1061 struct sink_notification
*data
;
1065 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &object
)))
1068 data
= impl_sink_notification_from_IUnknown(object
);
1070 clock_call_state_change(data
->system_time
, data
->param
, data
->notification
, data
->sink
);
1072 IUnknown_Release(object
);
1077 static const IMFAsyncCallbackVtbl presentclocksinkcallbackvtbl
=
1079 present_clock_callback_QueryInterface
,
1080 present_clock_sink_callback_AddRef
,
1081 present_clock_sink_callback_Release
,
1082 present_clock_callback_GetParameters
,
1083 present_clock_sink_callback_Invoke
,
1086 static ULONG WINAPI
present_clock_timer_callback_AddRef(IMFAsyncCallback
*iface
)
1088 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
1089 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
1092 static ULONG WINAPI
present_clock_timer_callback_Release(IMFAsyncCallback
*iface
)
1094 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
1095 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
1098 static HRESULT WINAPI
present_clock_timer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1100 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
1101 struct clock_timer
*timer
;
1105 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &object
)))
1108 timer
= impl_clock_timer_from_IUnknown(object
);
1110 EnterCriticalSection(&clock
->cs
);
1111 list_remove(&timer
->entry
);
1112 IUnknown_Release(&timer
->IUnknown_iface
);
1113 LeaveCriticalSection(&clock
->cs
);
1115 IMFAsyncCallback_Invoke(timer
->callback
, timer
->result
);
1117 IUnknown_Release(object
);
1122 static const IMFAsyncCallbackVtbl presentclocktimercallbackvtbl
=
1124 present_clock_callback_QueryInterface
,
1125 present_clock_timer_callback_AddRef
,
1126 present_clock_timer_callback_Release
,
1127 present_clock_callback_GetParameters
,
1128 present_clock_timer_callback_Invoke
,
1131 /***********************************************************************
1132 * MFCreatePresentationClock (mf.@)
1134 HRESULT WINAPI
MFCreatePresentationClock(IMFPresentationClock
**clock
)
1136 struct presentation_clock
*object
;
1138 TRACE("%p.\n", clock
);
1140 if (!(object
= calloc(1, sizeof(*object
))))
1141 return E_OUTOFMEMORY
;
1143 object
->IMFPresentationClock_iface
.lpVtbl
= &presentationclockvtbl
;
1144 object
->IMFRateControl_iface
.lpVtbl
= &presentclockratecontrolvtbl
;
1145 object
->IMFTimer_iface
.lpVtbl
= &presentclocktimervtbl
;
1146 object
->IMFShutdown_iface
.lpVtbl
= &presentclockshutdownvtbl
;
1147 object
->sink_callback
.lpVtbl
= &presentclocksinkcallbackvtbl
;
1148 object
->timer_callback
.lpVtbl
= &presentclocktimercallbackvtbl
;
1149 object
->refcount
= 1;
1150 list_init(&object
->sinks
);
1151 list_init(&object
->timers
);
1152 object
->rate
= 1.0f
;
1153 InitializeCriticalSection(&object
->cs
);
1155 *clock
= &object
->IMFPresentationClock_iface
;