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
29 #include "wine/debug.h"
30 #include "wine/heap.h"
31 #include "wine/list.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
37 SESSION_CMD_CLEAR_TOPOLOGIES
,
43 IUnknown IUnknown_iface
;
45 enum session_command command
;
48 struct queued_topology
51 IMFTopology
*topology
;
56 SESSION_STATE_STOPPED
= 0,
58 SESSION_STATE_SHUT_DOWN
,
63 IMFMediaSession IMFMediaSession_iface
;
64 IMFGetService IMFGetService_iface
;
65 IMFRateSupport IMFRateSupport_iface
;
66 IMFRateControl IMFRateControl_iface
;
67 IMFAsyncCallback commands_callback
;
69 IMFMediaEventQueue
*event_queue
;
70 IMFPresentationClock
*clock
;
71 struct list topologies
;
72 enum session_state state
;
79 IMFClockStateSink
*state_sink
;
91 enum clock_notification
97 CLOCK_NOTIFY_SET_RATE
,
100 struct clock_state_change_param
109 struct sink_notification
111 IUnknown IUnknown_iface
;
114 struct clock_state_change_param param
;
115 enum clock_notification notification
;
116 IMFClockStateSink
*sink
;
119 struct presentation_clock
121 IMFPresentationClock IMFPresentationClock_iface
;
122 IMFRateControl IMFRateControl_iface
;
123 IMFTimer IMFTimer_iface
;
124 IMFShutdown IMFShutdown_iface
;
125 IMFAsyncCallback IMFAsyncCallback_iface
;
127 IMFPresentationTimeSource
*time_source
;
128 IMFClockStateSink
*time_source_sink
;
135 static inline struct media_session
*impl_from_IMFMediaSession(IMFMediaSession
*iface
)
137 return CONTAINING_RECORD(iface
, struct media_session
, IMFMediaSession_iface
);
140 static struct media_session
*impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
142 return CONTAINING_RECORD(iface
, struct media_session
, commands_callback
);
145 static struct media_session
*impl_from_IMFGetService(IMFGetService
*iface
)
147 return CONTAINING_RECORD(iface
, struct media_session
, IMFGetService_iface
);
150 static struct media_session
*impl_session_from_IMFRateSupport(IMFRateSupport
*iface
)
152 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateSupport_iface
);
155 static struct media_session
*impl_session_from_IMFRateControl(IMFRateControl
*iface
)
157 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateControl_iface
);
160 static struct session_op
*impl_op_from_IUnknown(IUnknown
*iface
)
162 return CONTAINING_RECORD(iface
, struct session_op
, IUnknown_iface
);
165 static struct presentation_clock
*impl_from_IMFPresentationClock(IMFPresentationClock
*iface
)
167 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFPresentationClock_iface
);
170 static struct presentation_clock
*impl_from_IMFRateControl(IMFRateControl
*iface
)
172 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFRateControl_iface
);
175 static struct presentation_clock
*impl_from_IMFTimer(IMFTimer
*iface
)
177 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFTimer_iface
);
180 static struct presentation_clock
*impl_from_IMFShutdown(IMFShutdown
*iface
)
182 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFShutdown_iface
);
185 static struct presentation_clock
*impl_from_IMFAsyncCallback(IMFAsyncCallback
*iface
)
187 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFAsyncCallback_iface
);
190 static struct sink_notification
*impl_from_IUnknown(IUnknown
*iface
)
192 return CONTAINING_RECORD(iface
, struct sink_notification
, IUnknown_iface
);
195 static HRESULT WINAPI
session_op_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
197 if (IsEqualIID(riid
, &IID_IUnknown
))
200 IUnknown_AddRef(iface
);
205 return E_NOINTERFACE
;
208 static ULONG WINAPI
session_op_AddRef(IUnknown
*iface
)
210 struct session_op
*op
= impl_op_from_IUnknown(iface
);
211 ULONG refcount
= InterlockedIncrement(&op
->refcount
);
213 TRACE("%p, refcount %u.\n", iface
, refcount
);
218 static ULONG WINAPI
session_op_Release(IUnknown
*iface
)
220 struct session_op
*op
= impl_op_from_IUnknown(iface
);
221 ULONG refcount
= InterlockedDecrement(&op
->refcount
);
223 TRACE("%p, refcount %u.\n", iface
, refcount
);
233 static IUnknownVtbl session_op_vtbl
=
235 session_op_QueryInterface
,
240 static HRESULT
create_session_op(enum session_command command
, IUnknown
**ret
)
242 struct session_op
*op
;
244 if (!(op
= heap_alloc(sizeof(*op
))))
245 return E_OUTOFMEMORY
;
247 op
->IUnknown_iface
.lpVtbl
= &session_op_vtbl
;
249 op
->command
= command
;
251 *ret
= &op
->IUnknown_iface
;
256 static void session_clear_topologies(struct media_session
*session
)
258 struct queued_topology
*ptr
, *next
;
260 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &session
->topologies
, struct queued_topology
, entry
)
262 list_remove(&ptr
->entry
);
263 IMFTopology_Release(ptr
->topology
);
268 static HRESULT WINAPI
mfsession_QueryInterface(IMFMediaSession
*iface
, REFIID riid
, void **out
)
270 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
272 TRACE("(%p)->(%s %p)\n", iface
, debugstr_guid(riid
), out
);
274 if (IsEqualIID(riid
, &IID_IMFMediaSession
) ||
275 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
276 IsEqualIID(riid
, &IID_IUnknown
))
278 *out
= &session
->IMFMediaSession_iface
;
279 IMFMediaSession_AddRef(iface
);
282 else if (IsEqualIID(riid
, &IID_IMFGetService
))
284 *out
= &session
->IMFGetService_iface
;
285 IMFMediaSession_AddRef(iface
);
289 WARN("Unsupported %s.\n", debugstr_guid(riid
));
291 return E_NOINTERFACE
;
294 static ULONG WINAPI
mfsession_AddRef(IMFMediaSession
*iface
)
296 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
297 ULONG refcount
= InterlockedIncrement(&session
->refcount
);
299 TRACE("(%p) refcount=%u\n", iface
, refcount
);
304 static ULONG WINAPI
mfsession_Release(IMFMediaSession
*iface
)
306 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
307 ULONG refcount
= InterlockedDecrement(&session
->refcount
);
309 TRACE("(%p) refcount=%u\n", iface
, refcount
);
313 session_clear_topologies(session
);
314 if (session
->event_queue
)
315 IMFMediaEventQueue_Release(session
->event_queue
);
317 IMFPresentationClock_Release(session
->clock
);
318 DeleteCriticalSection(&session
->cs
);
325 static HRESULT WINAPI
mfsession_GetEvent(IMFMediaSession
*iface
, DWORD flags
, IMFMediaEvent
**event
)
327 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
329 TRACE("(%p)->(%#x, %p)\n", iface
, flags
, event
);
331 return IMFMediaEventQueue_GetEvent(session
->event_queue
, flags
, event
);
334 static HRESULT WINAPI
mfsession_BeginGetEvent(IMFMediaSession
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
336 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
338 TRACE("(%p)->(%p, %p)\n", iface
, callback
, state
);
340 return IMFMediaEventQueue_BeginGetEvent(session
->event_queue
, callback
, state
);
343 static HRESULT WINAPI
mfsession_EndGetEvent(IMFMediaSession
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
345 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
347 TRACE("(%p)->(%p, %p)\n", iface
, result
, event
);
349 return IMFMediaEventQueue_EndGetEvent(session
->event_queue
, result
, event
);
352 static HRESULT WINAPI
mfsession_QueueEvent(IMFMediaSession
*iface
, MediaEventType event_type
, REFGUID ext_type
,
353 HRESULT hr
, const PROPVARIANT
*value
)
355 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
357 TRACE("(%p)->(%d, %s, %#x, %p)\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
359 return IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, event_type
, ext_type
, hr
, value
);
362 static HRESULT WINAPI
mfsession_SetTopology(IMFMediaSession
*iface
, DWORD flags
, IMFTopology
*topology
)
364 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
365 struct queued_topology
*queued_topology
;
367 FIXME("%p, %#x, %p.\n", iface
, flags
, topology
);
369 if (!(queued_topology
= heap_alloc(sizeof(*queued_topology
))))
370 return E_OUTOFMEMORY
;
372 queued_topology
->topology
= topology
;
373 IMFTopology_AddRef(queued_topology
->topology
);
375 EnterCriticalSection(&session
->cs
);
376 list_add_tail(&session
->topologies
, &queued_topology
->entry
);
377 LeaveCriticalSection(&session
->cs
);
382 static HRESULT
session_submit_command(struct media_session
*session
, IUnknown
*op
)
386 EnterCriticalSection(&session
->cs
);
387 if (session
->state
== SESSION_STATE_SHUT_DOWN
)
390 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, op
);
391 LeaveCriticalSection(&session
->cs
);
396 static HRESULT WINAPI
mfsession_ClearTopologies(IMFMediaSession
*iface
)
398 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
402 TRACE("%p.\n", iface
);
404 if (FAILED(hr
= create_session_op(SESSION_CMD_CLEAR_TOPOLOGIES
, &op
)))
407 hr
= session_submit_command(session
, op
);
408 IUnknown_Release(op
);
413 static HRESULT WINAPI
mfsession_Start(IMFMediaSession
*iface
, const GUID
*format
, const PROPVARIANT
*start
)
415 FIXME("(%p)->(%s, %p)\n", iface
, debugstr_guid(format
), start
);
420 static HRESULT WINAPI
mfsession_Pause(IMFMediaSession
*iface
)
422 FIXME("(%p)\n", iface
);
427 static HRESULT WINAPI
mfsession_Stop(IMFMediaSession
*iface
)
429 FIXME("(%p)\n", iface
);
434 static HRESULT WINAPI
mfsession_Close(IMFMediaSession
*iface
)
436 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
440 TRACE("(%p)\n", iface
);
442 if (FAILED(hr
= create_session_op(SESSION_CMD_CLOSE
, &op
)))
445 hr
= session_submit_command(session
, op
);
446 IUnknown_Release(op
);
451 static HRESULT WINAPI
mfsession_Shutdown(IMFMediaSession
*iface
)
453 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
456 FIXME("(%p)\n", iface
);
458 EnterCriticalSection(&session
->cs
);
459 if (session
->state
== SESSION_STATE_SHUT_DOWN
)
463 session
->state
= SESSION_STATE_SHUT_DOWN
;
464 IMFMediaEventQueue_Shutdown(session
->event_queue
);
466 LeaveCriticalSection(&session
->cs
);
471 static HRESULT WINAPI
mfsession_GetClock(IMFMediaSession
*iface
, IMFClock
**clock
)
473 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
475 TRACE("%p, %p.\n", iface
, clock
);
477 *clock
= (IMFClock
*)session
->clock
;
478 IMFClock_AddRef(*clock
);
483 static HRESULT WINAPI
mfsession_GetSessionCapabilities(IMFMediaSession
*iface
, DWORD
*caps
)
485 FIXME("(%p)->(%p)\n", iface
, caps
);
490 static HRESULT WINAPI
mfsession_GetFullTopology(IMFMediaSession
*iface
, DWORD flags
, TOPOID id
, IMFTopology
**topology
)
492 FIXME("(%p)->(%#x, %s, %p)\n", iface
, flags
, wine_dbgstr_longlong(id
), topology
);
497 static const IMFMediaSessionVtbl mfmediasessionvtbl
=
499 mfsession_QueryInterface
,
503 mfsession_BeginGetEvent
,
504 mfsession_EndGetEvent
,
505 mfsession_QueueEvent
,
506 mfsession_SetTopology
,
507 mfsession_ClearTopologies
,
514 mfsession_GetSessionCapabilities
,
515 mfsession_GetFullTopology
,
518 static HRESULT WINAPI
session_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
520 struct media_session
*session
= impl_from_IMFGetService(iface
);
521 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
524 static ULONG WINAPI
session_get_service_AddRef(IMFGetService
*iface
)
526 struct media_session
*session
= impl_from_IMFGetService(iface
);
527 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
530 static ULONG WINAPI
session_get_service_Release(IMFGetService
*iface
)
532 struct media_session
*session
= impl_from_IMFGetService(iface
);
533 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
536 static HRESULT WINAPI
session_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
538 struct media_session
*session
= impl_from_IMFGetService(iface
);
540 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
544 if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
546 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
548 *obj
= &session
->IMFRateSupport_iface
;
550 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
552 *obj
= &session
->IMFRateControl_iface
;
556 IUnknown_AddRef((IUnknown
*)*obj
);
558 return *obj
? S_OK
: E_NOINTERFACE
;
561 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
566 static const IMFGetServiceVtbl session_get_service_vtbl
=
568 session_get_service_QueryInterface
,
569 session_get_service_AddRef
,
570 session_get_service_Release
,
571 session_get_service_GetService
,
574 static HRESULT WINAPI
session_commands_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
576 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
577 IsEqualIID(riid
, &IID_IUnknown
))
580 IMFAsyncCallback_AddRef(iface
);
584 WARN("Unsupported %s.\n", debugstr_guid(riid
));
586 return E_NOINTERFACE
;
589 static ULONG WINAPI
session_commands_callback_AddRef(IMFAsyncCallback
*iface
)
591 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
592 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
595 static ULONG WINAPI
session_commands_callback_Release(IMFAsyncCallback
*iface
)
597 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
598 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
601 static HRESULT WINAPI
session_commands_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
606 static HRESULT WINAPI
session_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
608 struct session_op
*op
= impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result
));
609 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
613 case SESSION_CMD_CLEAR_TOPOLOGIES
:
614 EnterCriticalSection(&session
->cs
);
615 session_clear_topologies(session
);
616 LeaveCriticalSection(&session
->cs
);
618 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologiesCleared
, &GUID_NULL
,
621 case SESSION_CMD_CLOSE
:
622 EnterCriticalSection(&session
->cs
);
623 if (session
->state
!= SESSION_STATE_CLOSED
)
625 /* FIXME: actually do something to presentation objects */
626 session
->state
= SESSION_STATE_CLOSED
;
627 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionClosed
, &GUID_NULL
, S_OK
, NULL
);
629 LeaveCriticalSection(&session
->cs
);
638 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl
=
640 session_commands_callback_QueryInterface
,
641 session_commands_callback_AddRef
,
642 session_commands_callback_Release
,
643 session_commands_callback_GetParameters
,
644 session_commands_callback_Invoke
,
647 static HRESULT WINAPI
session_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
649 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
650 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
653 static ULONG WINAPI
session_rate_support_AddRef(IMFRateSupport
*iface
)
655 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
656 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
659 static ULONG WINAPI
session_rate_support_Release(IMFRateSupport
*iface
)
661 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
662 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
665 static HRESULT WINAPI
session_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
666 BOOL thin
, float *rate
)
668 FIXME("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
673 static HRESULT WINAPI
session_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
674 BOOL thin
, float *rate
)
676 FIXME("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
681 static HRESULT WINAPI
session_rate_support_IsSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
682 float *nearest_supported_rate
)
684 FIXME("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_supported_rate
);
689 static const IMFRateSupportVtbl session_rate_support_vtbl
=
691 session_rate_support_QueryInterface
,
692 session_rate_support_AddRef
,
693 session_rate_support_Release
,
694 session_rate_support_GetSlowestRate
,
695 session_rate_support_GetFastestRate
,
696 session_rate_support_IsSupported
,
699 static HRESULT WINAPI
session_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
701 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
702 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
705 static ULONG WINAPI
session_rate_control_AddRef(IMFRateControl
*iface
)
707 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
708 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
711 static ULONG WINAPI
session_rate_control_Release(IMFRateControl
*iface
)
713 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
714 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
717 static HRESULT WINAPI
session_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
719 FIXME("%p, %d, %f.\n", iface
, thin
, rate
);
724 static HRESULT WINAPI
session_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
726 FIXME("%p, %p, %p.\n", iface
, thin
, rate
);
731 static const IMFRateControlVtbl session_rate_control_vtbl
=
733 session_rate_control_QueryInterface
,
734 session_rate_control_AddRef
,
735 session_rate_control_Release
,
736 session_rate_control_SetRate
,
737 session_rate_control_GetRate
,
740 /***********************************************************************
741 * MFCreateMediaSession (mf.@)
743 HRESULT WINAPI
MFCreateMediaSession(IMFAttributes
*config
, IMFMediaSession
**session
)
745 struct media_session
*object
;
748 TRACE("(%p, %p)\n", config
, session
);
751 FIXME("session configuration ignored\n");
753 object
= heap_alloc_zero(sizeof(*object
));
755 return E_OUTOFMEMORY
;
757 object
->IMFMediaSession_iface
.lpVtbl
= &mfmediasessionvtbl
;
758 object
->IMFGetService_iface
.lpVtbl
= &session_get_service_vtbl
;
759 object
->IMFRateSupport_iface
.lpVtbl
= &session_rate_support_vtbl
;
760 object
->IMFRateControl_iface
.lpVtbl
= &session_rate_control_vtbl
;
761 object
->commands_callback
.lpVtbl
= &session_commands_callback_vtbl
;
762 object
->refcount
= 1;
763 list_init(&object
->topologies
);
764 InitializeCriticalSection(&object
->cs
);
766 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
769 if (FAILED(hr
= MFCreatePresentationClock(&object
->clock
)))
772 *session
= &object
->IMFMediaSession_iface
;
777 IMFMediaSession_Release(&object
->IMFMediaSession_iface
);
781 static HRESULT WINAPI
present_clock_QueryInterface(IMFPresentationClock
*iface
, REFIID riid
, void **out
)
783 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
785 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
787 if (IsEqualIID(riid
, &IID_IMFPresentationClock
) ||
788 IsEqualIID(riid
, &IID_IMFClock
) ||
789 IsEqualIID(riid
, &IID_IUnknown
))
791 *out
= &clock
->IMFPresentationClock_iface
;
793 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
795 *out
= &clock
->IMFRateControl_iface
;
797 else if (IsEqualIID(riid
, &IID_IMFTimer
))
799 *out
= &clock
->IMFTimer_iface
;
801 else if (IsEqualIID(riid
, &IID_IMFShutdown
))
803 *out
= &clock
->IMFShutdown_iface
;
807 WARN("Unsupported %s.\n", debugstr_guid(riid
));
809 return E_NOINTERFACE
;
812 IUnknown_AddRef((IUnknown
*)*out
);
816 static ULONG WINAPI
present_clock_AddRef(IMFPresentationClock
*iface
)
818 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
819 ULONG refcount
= InterlockedIncrement(&clock
->refcount
);
821 TRACE("%p, refcount %u.\n", iface
, refcount
);
826 static ULONG WINAPI
present_clock_Release(IMFPresentationClock
*iface
)
828 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
829 ULONG refcount
= InterlockedDecrement(&clock
->refcount
);
830 struct clock_sink
*sink
, *sink2
;
832 TRACE("%p, refcount %u.\n", iface
, refcount
);
836 if (clock
->time_source
)
837 IMFPresentationTimeSource_Release(clock
->time_source
);
838 if (clock
->time_source_sink
)
839 IMFClockStateSink_Release(clock
->time_source_sink
);
840 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &clock
->sinks
, struct clock_sink
, entry
)
842 list_remove(&sink
->entry
);
843 IMFClockStateSink_Release(sink
->state_sink
);
846 DeleteCriticalSection(&clock
->cs
);
853 static HRESULT WINAPI
present_clock_GetClockCharacteristics(IMFPresentationClock
*iface
, DWORD
*flags
)
855 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
856 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
858 TRACE("%p, %p.\n", iface
, flags
);
860 EnterCriticalSection(&clock
->cs
);
861 if (clock
->time_source
)
862 hr
= IMFPresentationTimeSource_GetClockCharacteristics(clock
->time_source
, flags
);
863 LeaveCriticalSection(&clock
->cs
);
868 static HRESULT WINAPI
present_clock_GetCorrelatedTime(IMFPresentationClock
*iface
, DWORD reserved
,
869 LONGLONG
*clock_time
, MFTIME
*system_time
)
871 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
872 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
874 TRACE("%p, %#x, %p, %p.\n", iface
, reserved
, clock_time
, system_time
);
876 EnterCriticalSection(&clock
->cs
);
877 if (clock
->time_source
)
878 hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, reserved
, clock_time
, system_time
);
879 LeaveCriticalSection(&clock
->cs
);
884 static HRESULT WINAPI
present_clock_GetContinuityKey(IMFPresentationClock
*iface
, DWORD
*key
)
886 TRACE("%p, %p.\n", iface
, key
);
893 static HRESULT WINAPI
present_clock_GetState(IMFPresentationClock
*iface
, DWORD reserved
, MFCLOCK_STATE
*state
)
895 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
897 TRACE("%p, %#x, %p.\n", iface
, reserved
, state
);
899 EnterCriticalSection(&clock
->cs
);
900 *state
= clock
->state
;
901 LeaveCriticalSection(&clock
->cs
);
906 static HRESULT WINAPI
present_clock_GetProperties(IMFPresentationClock
*iface
, MFCLOCK_PROPERTIES
*props
)
908 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
909 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
911 TRACE("%p, %p.\n", iface
, props
);
913 EnterCriticalSection(&clock
->cs
);
914 if (clock
->time_source
)
915 hr
= IMFPresentationTimeSource_GetProperties(clock
->time_source
, props
);
916 LeaveCriticalSection(&clock
->cs
);
921 static HRESULT WINAPI
present_clock_SetTimeSource(IMFPresentationClock
*iface
,
922 IMFPresentationTimeSource
*time_source
)
924 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
927 TRACE("%p, %p.\n", iface
, time_source
);
929 EnterCriticalSection(&clock
->cs
);
930 if (clock
->time_source
)
931 IMFPresentationTimeSource_Release(clock
->time_source
);
932 if (clock
->time_source_sink
)
933 IMFClockStateSink_Release(clock
->time_source_sink
);
934 clock
->time_source
= NULL
;
935 clock
->time_source_sink
= NULL
;
937 hr
= IMFPresentationTimeSource_QueryInterface(time_source
, &IID_IMFClockStateSink
, (void **)&clock
->time_source_sink
);
940 clock
->time_source
= time_source
;
941 IMFPresentationTimeSource_AddRef(clock
->time_source
);
944 LeaveCriticalSection(&clock
->cs
);
949 static HRESULT WINAPI
present_clock_GetTimeSource(IMFPresentationClock
*iface
,
950 IMFPresentationTimeSource
**time_source
)
952 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
955 TRACE("%p, %p.\n", iface
, time_source
);
960 EnterCriticalSection(&clock
->cs
);
961 if (clock
->time_source
)
963 *time_source
= clock
->time_source
;
964 IMFPresentationTimeSource_AddRef(*time_source
);
967 hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
968 LeaveCriticalSection(&clock
->cs
);
973 static HRESULT WINAPI
present_clock_GetTime(IMFPresentationClock
*iface
, MFTIME
*time
)
975 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
976 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
979 TRACE("%p, %p.\n", iface
, time
);
984 EnterCriticalSection(&clock
->cs
);
985 if (clock
->time_source
)
986 hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, 0, time
, &systime
);
987 LeaveCriticalSection(&clock
->cs
);
992 static HRESULT WINAPI
present_clock_AddClockStateSink(IMFPresentationClock
*iface
, IMFClockStateSink
*state_sink
)
994 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
995 struct clock_sink
*sink
, *cur
;
998 TRACE("%p, %p.\n", iface
, state_sink
);
1001 return E_INVALIDARG
;
1003 sink
= heap_alloc(sizeof(*sink
));
1005 return E_OUTOFMEMORY
;
1007 sink
->state_sink
= state_sink
;
1008 IMFClockStateSink_AddRef(sink
->state_sink
);
1010 EnterCriticalSection(&clock
->cs
);
1011 LIST_FOR_EACH_ENTRY(cur
, &clock
->sinks
, struct clock_sink
, entry
)
1013 if (cur
->state_sink
== state_sink
)
1020 list_add_tail(&clock
->sinks
, &sink
->entry
);
1021 LeaveCriticalSection(&clock
->cs
);
1025 IMFClockStateSink_Release(sink
->state_sink
);
1032 static HRESULT WINAPI
present_clock_RemoveClockStateSink(IMFPresentationClock
*iface
,
1033 IMFClockStateSink
*state_sink
)
1035 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
1036 struct clock_sink
*sink
;
1038 TRACE("%p, %p.\n", iface
, state_sink
);
1041 return E_INVALIDARG
;
1043 EnterCriticalSection(&clock
->cs
);
1044 LIST_FOR_EACH_ENTRY(sink
, &clock
->sinks
, struct clock_sink
, entry
)
1046 if (sink
->state_sink
== state_sink
)
1048 IMFClockStateSink_Release(sink
->state_sink
);
1049 list_remove(&sink
->entry
);
1054 LeaveCriticalSection(&clock
->cs
);
1059 static HRESULT WINAPI
sink_notification_QueryInterface(IUnknown
*iface
, REFIID riid
, void **out
)
1061 if (IsEqualIID(riid
, &IID_IUnknown
))
1064 IUnknown_AddRef(iface
);
1068 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1070 return E_NOINTERFACE
;
1073 static ULONG WINAPI
sink_notification_AddRef(IUnknown
*iface
)
1075 struct sink_notification
*notification
= impl_from_IUnknown(iface
);
1076 ULONG refcount
= InterlockedIncrement(¬ification
->refcount
);
1078 TRACE("%p, refcount %u.\n", iface
, refcount
);
1083 static ULONG WINAPI
sink_notification_Release(IUnknown
*iface
)
1085 struct sink_notification
*notification
= impl_from_IUnknown(iface
);
1086 ULONG refcount
= InterlockedDecrement(¬ification
->refcount
);
1088 TRACE("%p, refcount %u.\n", iface
, refcount
);
1092 IMFClockStateSink_Release(notification
->sink
);
1093 heap_free(notification
);
1099 static const IUnknownVtbl sinknotificationvtbl
=
1101 sink_notification_QueryInterface
,
1102 sink_notification_AddRef
,
1103 sink_notification_Release
,
1106 static HRESULT
create_sink_notification(MFTIME system_time
, struct clock_state_change_param param
,
1107 enum clock_notification notification
, IMFClockStateSink
*sink
, IUnknown
**out
)
1109 struct sink_notification
*object
;
1111 object
= heap_alloc(sizeof(*object
));
1113 return E_OUTOFMEMORY
;
1115 object
->IUnknown_iface
.lpVtbl
= &sinknotificationvtbl
;
1116 object
->refcount
= 1;
1117 object
->system_time
= system_time
;
1118 object
->param
= param
;
1119 object
->notification
= notification
;
1120 object
->sink
= sink
;
1121 IMFClockStateSink_AddRef(object
->sink
);
1123 *out
= &object
->IUnknown_iface
;
1128 static HRESULT
clock_call_state_change(MFTIME system_time
, struct clock_state_change_param param
,
1129 enum clock_notification notification
, IMFClockStateSink
*sink
)
1133 switch (notification
)
1135 case CLOCK_NOTIFY_START
:
1136 hr
= IMFClockStateSink_OnClockStart(sink
, system_time
, param
.u
.offset
);
1138 case CLOCK_NOTIFY_STOP
:
1139 hr
= IMFClockStateSink_OnClockStop(sink
, system_time
);
1141 case CLOCK_NOTIFY_PAUSE
:
1142 hr
= IMFClockStateSink_OnClockPause(sink
, system_time
);
1144 case CLOCK_NOTIFY_RESTART
:
1145 hr
= IMFClockStateSink_OnClockRestart(sink
, system_time
);
1147 case CLOCK_NOTIFY_SET_RATE
:
1148 /* System time source does not allow 0.0 rate, presentation clock allows it without raising errors. */
1149 IMFClockStateSink_OnClockSetRate(sink
, system_time
, param
.u
.rate
);
1158 static HRESULT
clock_change_state(struct presentation_clock
*clock
, enum clock_command command
,
1159 struct clock_state_change_param param
)
1161 static const BYTE state_change_is_allowed
[MFCLOCK_STATE_PAUSED
+1][CLOCK_CMD_MAX
] =
1163 /* INVALID */ { 1, 1, 1, 1 },
1164 /* RUNNING */ { 1, 1, 1, 1 },
1165 /* STOPPED */ { 1, 1, 0, 1 },
1166 /* PAUSED */ { 1, 1, 0, 1 },
1168 static const MFCLOCK_STATE states
[CLOCK_CMD_MAX
] =
1170 /* CLOCK_CMD_START */ MFCLOCK_STATE_RUNNING
,
1171 /* CLOCK_CMD_STOP */ MFCLOCK_STATE_STOPPED
,
1172 /* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED
,
1173 /* CLOCK_CMD_SET_RATE */ 0, /* Unused */
1175 enum clock_notification notification
;
1176 struct clock_sink
*sink
;
1177 IUnknown
*notify_object
;
1178 IMFAsyncResult
*result
;
1182 if (command
!= CLOCK_CMD_SET_RATE
&& clock
->state
== states
[command
] && clock
->state
!= MFCLOCK_STATE_RUNNING
)
1183 return MF_E_CLOCK_STATE_ALREADY_SET
;
1185 if (!state_change_is_allowed
[clock
->state
][command
])
1186 return MF_E_INVALIDREQUEST
;
1188 system_time
= MFGetSystemTime();
1192 case CLOCK_CMD_START
:
1193 if (clock
->state
== MFCLOCK_STATE_PAUSED
&& param
.u
.offset
== PRESENTATION_CURRENT_POSITION
)
1194 notification
= CLOCK_NOTIFY_RESTART
;
1196 notification
= CLOCK_NOTIFY_START
;
1198 case CLOCK_CMD_STOP
:
1199 notification
= CLOCK_NOTIFY_STOP
;
1201 case CLOCK_CMD_PAUSE
:
1202 notification
= CLOCK_NOTIFY_PAUSE
;
1204 case CLOCK_CMD_SET_RATE
:
1205 notification
= CLOCK_NOTIFY_SET_RATE
;
1211 if (FAILED(hr
= clock_call_state_change(system_time
, param
, notification
, clock
->time_source_sink
)))
1214 clock
->state
= states
[command
];
1216 LIST_FOR_EACH_ENTRY(sink
, &clock
->sinks
, struct clock_sink
, entry
)
1218 if (SUCCEEDED(create_sink_notification(system_time
, param
, notification
, sink
->state_sink
, ¬ify_object
)))
1220 hr
= MFCreateAsyncResult(notify_object
, &clock
->IMFAsyncCallback_iface
, NULL
, &result
);
1221 IUnknown_Release(notify_object
);
1224 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD
, result
);
1225 IMFAsyncResult_Release(result
);
1233 static HRESULT WINAPI
present_clock_Start(IMFPresentationClock
*iface
, LONGLONG start_offset
)
1235 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
1236 struct clock_state_change_param param
= {{0}};
1239 TRACE("%p, %s.\n", iface
, wine_dbgstr_longlong(start_offset
));
1241 EnterCriticalSection(&clock
->cs
);
1242 param
.u
.offset
= start_offset
;
1243 hr
= clock_change_state(clock
, CLOCK_CMD_START
, param
);
1244 LeaveCriticalSection(&clock
->cs
);
1249 static HRESULT WINAPI
present_clock_Stop(IMFPresentationClock
*iface
)
1251 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
1252 struct clock_state_change_param param
= {{0}};
1255 TRACE("%p.\n", iface
);
1257 EnterCriticalSection(&clock
->cs
);
1258 hr
= clock_change_state(clock
, CLOCK_CMD_STOP
, param
);
1259 LeaveCriticalSection(&clock
->cs
);
1264 static HRESULT WINAPI
present_clock_Pause(IMFPresentationClock
*iface
)
1266 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
1267 struct clock_state_change_param param
= {{0}};
1270 TRACE("%p.\n", iface
);
1272 EnterCriticalSection(&clock
->cs
);
1273 hr
= clock_change_state(clock
, CLOCK_CMD_PAUSE
, param
);
1274 LeaveCriticalSection(&clock
->cs
);
1279 static const IMFPresentationClockVtbl presentationclockvtbl
=
1281 present_clock_QueryInterface
,
1282 present_clock_AddRef
,
1283 present_clock_Release
,
1284 present_clock_GetClockCharacteristics
,
1285 present_clock_GetCorrelatedTime
,
1286 present_clock_GetContinuityKey
,
1287 present_clock_GetState
,
1288 present_clock_GetProperties
,
1289 present_clock_SetTimeSource
,
1290 present_clock_GetTimeSource
,
1291 present_clock_GetTime
,
1292 present_clock_AddClockStateSink
,
1293 present_clock_RemoveClockStateSink
,
1294 present_clock_Start
,
1296 present_clock_Pause
,
1299 static HRESULT WINAPI
present_clock_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **out
)
1301 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
1302 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
1305 static ULONG WINAPI
present_clock_rate_control_AddRef(IMFRateControl
*iface
)
1307 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
1308 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
1311 static ULONG WINAPI
present_clock_rate_control_Release(IMFRateControl
*iface
)
1313 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
1314 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
1317 static HRESULT WINAPI
present_clock_rate_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
1319 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
1320 struct clock_state_change_param param
;
1323 TRACE("%p, %d, %f.\n", iface
, thin
, rate
);
1326 return MF_E_THINNING_UNSUPPORTED
;
1328 EnterCriticalSection(&clock
->cs
);
1329 param
.u
.rate
= rate
;
1330 if (SUCCEEDED(hr
= clock_change_state(clock
, CLOCK_CMD_SET_RATE
, param
)))
1332 LeaveCriticalSection(&clock
->cs
);
1337 static HRESULT WINAPI
present_clock_rate_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
1339 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
1341 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
1344 return E_INVALIDARG
;
1349 EnterCriticalSection(&clock
->cs
);
1350 *rate
= clock
->rate
;
1351 LeaveCriticalSection(&clock
->cs
);
1356 static const IMFRateControlVtbl presentclockratecontrolvtbl
=
1358 present_clock_rate_control_QueryInterface
,
1359 present_clock_rate_control_AddRef
,
1360 present_clock_rate_control_Release
,
1361 present_clock_rate_SetRate
,
1362 present_clock_rate_GetRate
,
1365 static HRESULT WINAPI
present_clock_timer_QueryInterface(IMFTimer
*iface
, REFIID riid
, void **out
)
1367 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
1368 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
1371 static ULONG WINAPI
present_clock_timer_AddRef(IMFTimer
*iface
)
1373 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
1374 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
1377 static ULONG WINAPI
present_clock_timer_Release(IMFTimer
*iface
)
1379 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
1380 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
1383 static HRESULT WINAPI
present_clock_timer_SetTimer(IMFTimer
*iface
, DWORD flags
, LONGLONG time
,
1384 IMFAsyncCallback
*callback
, IUnknown
*state
, IUnknown
**cancel_key
)
1386 FIXME("%p, %#x, %s, %p, %p, %p.\n", iface
, flags
, wine_dbgstr_longlong(time
), callback
, state
, cancel_key
);
1391 static HRESULT WINAPI
present_clock_timer_CancelTimer(IMFTimer
*iface
, IUnknown
*cancel_key
)
1393 FIXME("%p, %p.\n", iface
, cancel_key
);
1398 static const IMFTimerVtbl presentclocktimervtbl
=
1400 present_clock_timer_QueryInterface
,
1401 present_clock_timer_AddRef
,
1402 present_clock_timer_Release
,
1403 present_clock_timer_SetTimer
,
1404 present_clock_timer_CancelTimer
,
1407 static HRESULT WINAPI
present_clock_shutdown_QueryInterface(IMFShutdown
*iface
, REFIID riid
, void **out
)
1409 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
1410 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
1413 static ULONG WINAPI
present_clock_shutdown_AddRef(IMFShutdown
*iface
)
1415 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
1416 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
1419 static ULONG WINAPI
present_clock_shutdown_Release(IMFShutdown
*iface
)
1421 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
1422 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
1425 static HRESULT WINAPI
present_clock_shutdown_Shutdown(IMFShutdown
*iface
)
1427 FIXME("%p.\n", iface
);
1432 static HRESULT WINAPI
present_clock_shutdown_GetShutdownStatus(IMFShutdown
*iface
, MFSHUTDOWN_STATUS
*status
)
1434 FIXME("%p, %p.\n", iface
, status
);
1439 static const IMFShutdownVtbl presentclockshutdownvtbl
=
1441 present_clock_shutdown_QueryInterface
,
1442 present_clock_shutdown_AddRef
,
1443 present_clock_shutdown_Release
,
1444 present_clock_shutdown_Shutdown
,
1445 present_clock_shutdown_GetShutdownStatus
,
1448 static HRESULT WINAPI
present_clock_sink_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **out
)
1450 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
1451 IsEqualIID(riid
, &IID_IUnknown
))
1454 IMFAsyncCallback_AddRef(iface
);
1458 WARN("Unsupported %s.\n", wine_dbgstr_guid(riid
));
1460 return E_NOINTERFACE
;
1463 static ULONG WINAPI
present_clock_sink_callback_AddRef(IMFAsyncCallback
*iface
)
1465 struct presentation_clock
*clock
= impl_from_IMFAsyncCallback(iface
);
1466 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
1469 static ULONG WINAPI
present_clock_sink_callback_Release(IMFAsyncCallback
*iface
)
1471 struct presentation_clock
*clock
= impl_from_IMFAsyncCallback(iface
);
1472 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
1475 static HRESULT WINAPI
present_clock_sink_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
1480 static HRESULT WINAPI
present_clock_sink_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1482 struct sink_notification
*data
;
1486 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &object
)))
1489 data
= impl_from_IUnknown(object
);
1491 clock_call_state_change(data
->system_time
, data
->param
, data
->notification
, data
->sink
);
1493 IUnknown_Release(object
);
1498 static const IMFAsyncCallbackVtbl presentclocksinkcallbackvtbl
=
1500 present_clock_sink_callback_QueryInterface
,
1501 present_clock_sink_callback_AddRef
,
1502 present_clock_sink_callback_Release
,
1503 present_clock_sink_callback_GetParameters
,
1504 present_clock_sink_callback_Invoke
,
1507 /***********************************************************************
1508 * MFCreatePresentationClock (mf.@)
1510 HRESULT WINAPI
MFCreatePresentationClock(IMFPresentationClock
**clock
)
1512 struct presentation_clock
*object
;
1514 TRACE("%p.\n", clock
);
1516 object
= heap_alloc_zero(sizeof(*object
));
1518 return E_OUTOFMEMORY
;
1520 object
->IMFPresentationClock_iface
.lpVtbl
= &presentationclockvtbl
;
1521 object
->IMFRateControl_iface
.lpVtbl
= &presentclockratecontrolvtbl
;
1522 object
->IMFTimer_iface
.lpVtbl
= &presentclocktimervtbl
;
1523 object
->IMFShutdown_iface
.lpVtbl
= &presentclockshutdownvtbl
;
1524 object
->IMFAsyncCallback_iface
.lpVtbl
= &presentclocksinkcallbackvtbl
;
1525 object
->refcount
= 1;
1526 list_init(&object
->sinks
);
1527 object
->rate
= 1.0f
;
1528 InitializeCriticalSection(&object
->cs
);
1530 *clock
= &object
->IMFPresentationClock_iface
;