wined3d: Use wined3d_mask_from_size() in shader_glsl_gather4().
[wine.git] / dlls / mf / clock.c
blob4a3ad7ec7c16a990bcea1c94d1f12dbe3c498381
1 /*
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
19 #define COBJMACROS
21 #include "wine/debug.h"
22 #include "wine/list.h"
24 #include "mf_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
28 struct clock_sink
30 struct list entry;
31 IMFClockStateSink *state_sink;
34 enum clock_command
36 CLOCK_CMD_START = 0,
37 CLOCK_CMD_STOP,
38 CLOCK_CMD_PAUSE,
39 CLOCK_CMD_SET_RATE,
40 CLOCK_CMD_MAX,
43 enum clock_notification
45 CLOCK_NOTIFY_START,
46 CLOCK_NOTIFY_STOP,
47 CLOCK_NOTIFY_PAUSE,
48 CLOCK_NOTIFY_RESTART,
49 CLOCK_NOTIFY_SET_RATE,
52 struct clock_state_change_param
54 union
56 LONGLONG offset;
57 float rate;
58 } u;
61 struct sink_notification
63 IUnknown IUnknown_iface;
64 LONG refcount;
65 MFTIME system_time;
66 struct clock_state_change_param param;
67 enum clock_notification notification;
68 IMFClockStateSink *sink;
71 struct clock_timer
73 IUnknown IUnknown_iface;
74 LONG refcount;
75 IMFAsyncResult *result;
76 IMFAsyncCallback *callback;
77 MFWORKITEM_KEY key;
78 struct list entry;
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;
89 LONG refcount;
90 IMFPresentationTimeSource *time_source;
91 IMFClockStateSink *time_source_sink;
92 MFCLOCK_STATE state;
93 LONGLONG start_offset;
94 struct list sinks;
95 struct list timers;
96 float rate;
97 LONGLONG frequency;
98 CRITICAL_SECTION cs;
99 BOOL is_shut_down;
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))
146 *out = iface;
147 IUnknown_AddRef(iface);
148 return S_OK;
151 WARN("Unsupported %s.\n", debugstr_guid(riid));
152 *out = NULL;
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(&notification->refcount);
161 TRACE("%p, refcount %u.\n", iface, refcount);
163 return 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(&notification->refcount);
171 TRACE("%p, refcount %u.\n", iface, refcount);
173 if (!refcount)
175 IMFClockStateSink_Release(notification->sink);
176 free(notification);
179 return refcount;
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;
194 HRESULT hr;
196 if (!(object = malloc(sizeof(*object))))
197 return;
199 object->IUnknown_iface.lpVtbl = &sinknotificationvtbl;
200 object->refcount = 1;
201 object->system_time = system_time;
202 object->param = param;
203 object->notification = notification;
204 object->sink = sink;
205 IMFClockStateSink_AddRef(object->sink);
207 hr = MFCreateAsyncResult(&object->IUnknown_iface, &clock->sink_callback, NULL, &result);
208 IUnknown_Release(&object->IUnknown_iface);
209 if (SUCCEEDED(hr))
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;
240 else
242 WARN("Unsupported %s.\n", debugstr_guid(riid));
243 *out = NULL;
244 return E_NOINTERFACE;
247 IUnknown_AddRef((IUnknown *)*out);
248 return S_OK;
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);
258 return 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);
270 if (!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);
280 free(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);
288 free(clock);
291 return refcount;
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);
306 return hr;
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);
322 return hr;
325 static HRESULT WINAPI present_clock_GetContinuityKey(IMFPresentationClock *iface, DWORD *key)
327 TRACE("%p, %p.\n", iface, key);
329 *key = 0;
331 return S_OK;
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);
344 return S_OK;
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);
359 return hr;
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;
368 HRESULT hr;
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);
382 if (SUCCEEDED(hr))
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);
400 return hr;
403 static HRESULT WINAPI present_clock_GetTimeSource(IMFPresentationClock *iface,
404 IMFPresentationTimeSource **time_source)
406 struct presentation_clock *clock = impl_from_IMFPresentationClock(iface);
407 HRESULT hr = S_OK;
409 TRACE("%p, %p.\n", iface, time_source);
411 if (!time_source)
412 return E_INVALIDARG;
414 EnterCriticalSection(&clock->cs);
415 if (clock->time_source)
417 *time_source = clock->time_source;
418 IMFPresentationTimeSource_AddRef(*time_source);
420 else
421 hr = MF_E_CLOCK_NO_TIME_SOURCE;
422 LeaveCriticalSection(&clock->cs);
424 return hr;
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;
431 MFTIME systime;
433 TRACE("%p, %p.\n", iface, time);
435 if (!time)
436 return E_POINTER;
438 EnterCriticalSection(&clock->cs);
439 if (clock->time_source)
440 hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, 0, time, &systime);
441 LeaveCriticalSection(&clock->cs);
443 return hr;
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;
450 HRESULT hr = S_OK;
452 TRACE("%p, %p.\n", iface, state_sink);
454 if (!state_sink)
455 return E_INVALIDARG;
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)
468 hr = E_INVALIDARG;
469 break;
472 if (SUCCEEDED(hr))
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);
493 if (FAILED(hr))
495 IMFClockStateSink_Release(sink->state_sink);
496 free(sink);
499 return hr;
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);
510 if (!state_sink)
511 return E_INVALIDARG;
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);
520 free(sink);
521 break;
524 LeaveCriticalSection(&clock->cs);
526 return S_OK;
529 static HRESULT clock_call_state_change(MFTIME system_time, struct clock_state_change_param param,
530 enum clock_notification notification, IMFClockStateSink *sink)
532 HRESULT hr = S_OK;
534 switch (notification)
536 case CLOCK_NOTIFY_START:
537 hr = IMFClockStateSink_OnClockStart(sink, system_time, param.u.offset);
538 break;
539 case CLOCK_NOTIFY_STOP:
540 hr = IMFClockStateSink_OnClockStop(sink, system_time);
541 break;
542 case CLOCK_NOTIFY_PAUSE:
543 hr = IMFClockStateSink_OnClockPause(sink, system_time);
544 break;
545 case CLOCK_NOTIFY_RESTART:
546 hr = IMFClockStateSink_OnClockRestart(sink, system_time);
547 break;
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);
551 break;
552 default:
556 return hr;
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] =
563 { /* S S* P, R */
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;
587 MFTIME system_time;
588 HRESULT hr;
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;
606 else
607 notification = notifications[command];
609 if (FAILED(hr = clock_call_state_change(system_time, param, notification, clock->time_source_sink)))
610 return hr;
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);
629 if (SUCCEEDED(hr))
631 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_TIMER, result);
632 IMFAsyncResult_Release(result);
636 else
638 LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry)
640 if (timer->key)
642 MFCancelWorkItem(timer->key);
643 timer->key = 0;
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);
654 return S_OK;
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}};
661 HRESULT hr;
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);
670 return hr;
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}};
677 HRESULT hr;
679 TRACE("%p.\n", iface);
681 EnterCriticalSection(&clock->cs);
682 hr = clock_change_state(clock, CLOCK_CMD_STOP, param);
683 LeaveCriticalSection(&clock->cs);
685 return hr;
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}};
692 HRESULT hr;
694 TRACE("%p.\n", iface);
696 EnterCriticalSection(&clock->cs);
697 hr = clock_change_state(clock, CLOCK_CMD_PAUSE, param);
698 LeaveCriticalSection(&clock->cs);
700 return hr;
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,
718 present_clock_Start,
719 present_clock_Stop,
720 present_clock_Pause,
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;
745 HRESULT hr;
747 TRACE("%p, %d, %f.\n", iface, thin, rate);
749 if (thin)
750 return MF_E_THINNING_UNSUPPORTED;
752 EnterCriticalSection(&clock->cs);
753 param.u.rate = rate;
754 if (SUCCEEDED(hr = clock_change_state(clock, CLOCK_CMD_SET_RATE, param)))
755 clock->rate = rate;
756 LeaveCriticalSection(&clock->cs);
758 return hr;
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);
767 if (!rate)
768 return E_INVALIDARG;
770 if (thin)
771 *thin = FALSE;
773 EnterCriticalSection(&clock->cs);
774 *rate = clock->rate;
775 LeaveCriticalSection(&clock->cs);
777 return S_OK;
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;
812 LONGLONG frequency;
813 HRESULT hr;
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);
820 return hr;
822 time -= clocktime;
825 frequency = clock->frequency / 1000;
826 time /= frequency;
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)))
832 return hr;
834 hr = MFScheduleWorkItemEx(result, -time, &timer->key);
835 IMFAsyncResult_Release(result);
837 return hr;
840 static HRESULT WINAPI clock_timer_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
842 if (IsEqualIID(riid, &IID_IUnknown))
844 *obj = iface;
845 IUnknown_AddRef(iface);
846 return S_OK;
849 *obj = NULL;
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);
864 if (!refcount)
866 IMFAsyncResult_Release(timer->result);
867 IMFAsyncCallback_Release(timer->callback);
868 free(timer);
871 return refcount;
874 static const IUnknownVtbl clock_timer_vtbl =
876 clock_timer_QueryInterface,
877 clock_timer_AddRef,
878 clock_timer_Release,
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;
886 HRESULT hr;
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)))
895 free(clock_timer);
896 return hr;
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;
911 if (SUCCEEDED(hr))
913 list_add_tail(&clock->timers, &clock_timer->entry);
914 if (cancel_key)
916 *cancel_key = &clock_timer->IUnknown_iface;
917 IUnknown_AddRef(*cancel_key);
921 LeaveCriticalSection(&clock->cs);
923 if (FAILED(hr))
924 IUnknown_Release(&clock_timer->IUnknown_iface);
926 return hr;
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);
943 if (timer->key)
945 MFCancelWorkItem(timer->key);
946 timer->key = 0;
948 IUnknown_Release(&timer->IUnknown_iface);
949 break;
953 LeaveCriticalSection(&clock->cs);
955 return S_OK;
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);
995 return S_OK;
998 static HRESULT WINAPI present_clock_shutdown_GetShutdownStatus(IMFShutdown *iface, MFSHUTDOWN_STATUS *status)
1000 struct presentation_clock *clock = impl_from_IMFShutdown(iface);
1001 HRESULT hr = S_OK;
1003 TRACE("%p, %p.\n", iface, status);
1005 if (!status)
1006 return E_INVALIDARG;
1008 EnterCriticalSection(&clock->cs);
1009 if (clock->is_shut_down)
1010 *status = MFSHUTDOWN_COMPLETED;
1011 else
1012 hr = MF_E_INVALIDREQUEST;
1013 LeaveCriticalSection(&clock->cs);
1015 return hr;
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))
1032 *out = iface;
1033 IMFAsyncCallback_AddRef(iface);
1034 return S_OK;
1037 WARN("Unsupported %s.\n", wine_dbgstr_guid(riid));
1038 *out = NULL;
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)
1056 return E_NOTIMPL;
1059 static HRESULT WINAPI present_clock_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1061 struct sink_notification *data;
1062 IUnknown *object;
1063 HRESULT hr;
1065 if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
1066 return hr;
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);
1074 return S_OK;
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;
1102 IUnknown *object;
1103 HRESULT hr;
1105 if (FAILED(hr = IMFAsyncResult_GetObject(result, &object)))
1106 return hr;
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);
1119 return S_OK;
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;
1157 return S_OK;