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 #include "mf_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
39 SESSION_CMD_CLEAR_TOPOLOGIES
,
41 SESSION_CMD_SET_TOPOLOGY
,
45 /* Internally used commands. */
47 SESSION_CMD_QM_NOTIFY_TOPOLOGY
,
53 IUnknown IUnknown_iface
;
55 enum session_command command
;
61 IMFTopology
*topology
;
66 PROPVARIANT start_position
;
70 IMFTopology
*topology
;
80 struct queued_topology
83 IMFTopology
*topology
;
89 SESSION_STATE_STOPPED
= 0,
90 SESSION_STATE_STARTING_SOURCES
,
91 SESSION_STATE_PREROLLING_SINKS
,
92 SESSION_STATE_STARTING_SINKS
,
93 SESSION_STATE_STARTED
,
94 SESSION_STATE_PAUSING_SINKS
,
95 SESSION_STATE_PAUSING_SOURCES
,
97 SESSION_STATE_STOPPING_SINKS
,
98 SESSION_STATE_STOPPING_SOURCES
,
99 SESSION_STATE_FINALIZING_SINKS
,
100 SESSION_STATE_CLOSED
,
101 SESSION_STATE_SHUT_DOWN
,
106 OBJ_STATE_STOPPED
= 0,
113 enum media_source_flags
115 SOURCE_FLAG_END_OF_PRESENTATION
= 0x1,
121 IMFMediaSource
*source
;
122 IMFPresentationDescriptor
*pd
;
123 enum object_state state
;
131 IMFMediaSinkPreroll
*preroll
;
132 IMFMediaEventGenerator
*event_generator
;
142 struct transform_stream
145 unsigned int requests
;
150 TOPO_NODE_END_OF_STREAM
= 0x1,
156 struct media_session
*session
;
157 MF_TOPOLOGY_TYPE type
;
159 IMFTopologyNode
*node
;
160 enum object_state state
;
164 IMFMediaStream
*source_stream
;
165 IMFStreamSink
*sink_stream
;
166 IMFTransform
*transform
;
174 IMFMediaSource
*source
;
175 unsigned int stream_id
;
179 unsigned int requests
;
180 IMFVideoSampleAllocatorNotify notify_cb
;
181 IMFVideoSampleAllocator
*allocator
;
182 IMFVideoSampleAllocatorCallback
*allocator_cb
;
186 struct transform_stream
*inputs
;
187 unsigned int *input_map
;
188 unsigned int input_count
;
190 struct transform_stream
*outputs
;
191 unsigned int *output_map
;
192 unsigned int output_count
;
197 enum presentation_flags
199 SESSION_FLAG_SOURCES_SUBSCRIBED
= 0x1,
200 SESSION_FLAG_PRESENTATION_CLOCK_SET
= 0x2,
201 SESSION_FLAG_FINALIZE_SINKS
= 0x4,
202 SESSION_FLAG_NEEDS_PREROLL
= 0x8,
203 SESSION_FLAG_END_OF_PRESENTATION
= 0x10,
208 IMFMediaSession IMFMediaSession_iface
;
209 IMFGetService IMFGetService_iface
;
210 IMFRateSupport IMFRateSupport_iface
;
211 IMFRateControl IMFRateControl_iface
;
212 IMFAsyncCallback commands_callback
;
213 IMFAsyncCallback events_callback
;
214 IMFAsyncCallback sink_finalizer_callback
;
216 IMFMediaEventQueue
*event_queue
;
217 IMFPresentationClock
*clock
;
218 IMFPresentationTimeSource
*system_time_source
;
219 IMFRateControl
*clock_rate_control
;
220 IMFTopoLoader
*topo_loader
;
221 IMFQualityManager
*quality_manager
;
224 IMFTopology
*current_topology
;
225 MF_TOPOSTATUS topo_status
;
226 MFTIME clock_stop_time
;
232 /* Latest Start() arguments. */
234 PROPVARIANT start_position
;
236 struct list topologies
;
237 struct list commands
;
238 enum session_state state
;
246 IMFClockStateSink
*state_sink
;
258 enum clock_notification
263 CLOCK_NOTIFY_RESTART
,
264 CLOCK_NOTIFY_SET_RATE
,
267 struct clock_state_change_param
276 struct sink_notification
278 IUnknown IUnknown_iface
;
281 struct clock_state_change_param param
;
282 enum clock_notification notification
;
283 IMFClockStateSink
*sink
;
288 IUnknown IUnknown_iface
;
290 IMFAsyncResult
*result
;
291 IMFAsyncCallback
*callback
;
296 struct presentation_clock
298 IMFPresentationClock IMFPresentationClock_iface
;
299 IMFRateControl IMFRateControl_iface
;
300 IMFTimer IMFTimer_iface
;
301 IMFShutdown IMFShutdown_iface
;
302 IMFAsyncCallback sink_callback
;
303 IMFAsyncCallback timer_callback
;
305 IMFPresentationTimeSource
*time_source
;
306 IMFClockStateSink
*time_source_sink
;
308 LONGLONG start_offset
;
317 struct quality_manager
319 IMFQualityManager IMFQualityManager_iface
;
322 IMFPresentationClock
*clock
;
326 static inline struct media_session
*impl_from_IMFMediaSession(IMFMediaSession
*iface
)
328 return CONTAINING_RECORD(iface
, struct media_session
, IMFMediaSession_iface
);
331 static struct media_session
*impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
333 return CONTAINING_RECORD(iface
, struct media_session
, commands_callback
);
336 static struct media_session
*impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
338 return CONTAINING_RECORD(iface
, struct media_session
, events_callback
);
341 static struct media_session
*impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
343 return CONTAINING_RECORD(iface
, struct media_session
, sink_finalizer_callback
);
346 static struct media_session
*impl_from_IMFGetService(IMFGetService
*iface
)
348 return CONTAINING_RECORD(iface
, struct media_session
, IMFGetService_iface
);
351 static struct media_session
*impl_session_from_IMFRateSupport(IMFRateSupport
*iface
)
353 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateSupport_iface
);
356 static struct media_session
*impl_session_from_IMFRateControl(IMFRateControl
*iface
)
358 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateControl_iface
);
361 static struct session_op
*impl_op_from_IUnknown(IUnknown
*iface
)
363 return CONTAINING_RECORD(iface
, struct session_op
, IUnknown_iface
);
366 static struct presentation_clock
*impl_from_IMFPresentationClock(IMFPresentationClock
*iface
)
368 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFPresentationClock_iface
);
371 static struct presentation_clock
*impl_from_IMFRateControl(IMFRateControl
*iface
)
373 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFRateControl_iface
);
376 static struct presentation_clock
*impl_from_IMFTimer(IMFTimer
*iface
)
378 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFTimer_iface
);
381 static struct presentation_clock
*impl_from_IMFShutdown(IMFShutdown
*iface
)
383 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFShutdown_iface
);
386 static struct presentation_clock
*impl_from_sink_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
388 return CONTAINING_RECORD(iface
, struct presentation_clock
, sink_callback
);
391 static struct presentation_clock
*impl_from_timer_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
393 return CONTAINING_RECORD(iface
, struct presentation_clock
, timer_callback
);
396 static struct clock_timer
*impl_clock_timer_from_IUnknown(IUnknown
*iface
)
398 return CONTAINING_RECORD(iface
, struct clock_timer
, IUnknown_iface
);
401 static struct sink_notification
*impl_sink_notification_from_IUnknown(IUnknown
*iface
)
403 return CONTAINING_RECORD(iface
, struct sink_notification
, IUnknown_iface
);
406 static struct quality_manager
*impl_from_IMFQualityManager(IMFQualityManager
*iface
)
408 return CONTAINING_RECORD(iface
, struct quality_manager
, IMFQualityManager_iface
);
411 static struct topo_node
*impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify
*iface
)
413 return CONTAINING_RECORD(iface
, struct topo_node
, u
.sink
.notify_cb
);
416 /* IMFLocalMFTRegistration */
417 static HRESULT WINAPI
local_mft_registration_QueryInterface(IMFLocalMFTRegistration
*iface
, REFIID riid
, void **obj
)
419 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
421 if (IsEqualIID(riid
, &IID_IMFLocalMFTRegistration
) ||
422 IsEqualIID(riid
, &IID_IUnknown
))
425 IMFLocalMFTRegistration_AddRef(iface
);
429 WARN("Unexpected %s.\n", debugstr_guid(riid
));
431 return E_NOINTERFACE
;
434 static ULONG WINAPI
local_mft_registration_AddRef(IMFLocalMFTRegistration
*iface
)
439 static ULONG WINAPI
local_mft_registration_Release(IMFLocalMFTRegistration
*iface
)
444 static HRESULT WINAPI
local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration
*iface
, MFT_REGISTRATION_INFO
*info
,
450 TRACE("%p, %p, %u.\n", iface
, info
, count
);
452 for (i
= 0; i
< count
; ++i
)
454 if (FAILED(hr
= MFTRegisterLocalByCLSID(&info
[i
].clsid
, &info
[i
].guidCategory
, info
[i
].pszName
,
455 info
[i
].uiFlags
, info
[i
].cInTypes
, info
[i
].pInTypes
, info
[i
].cOutTypes
, info
[i
].pOutTypes
)))
464 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl
=
466 local_mft_registration_QueryInterface
,
467 local_mft_registration_AddRef
,
468 local_mft_registration_Release
,
469 local_mft_registration_RegisterMFTs
,
472 static IMFLocalMFTRegistration local_mft_registration
= { &local_mft_registration_vtbl
};
474 static HRESULT WINAPI
session_op_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
476 if (IsEqualIID(riid
, &IID_IUnknown
))
479 IUnknown_AddRef(iface
);
484 return E_NOINTERFACE
;
487 static ULONG WINAPI
session_op_AddRef(IUnknown
*iface
)
489 struct session_op
*op
= impl_op_from_IUnknown(iface
);
490 ULONG refcount
= InterlockedIncrement(&op
->refcount
);
492 TRACE("%p, refcount %u.\n", iface
, refcount
);
497 static ULONG WINAPI
session_op_Release(IUnknown
*iface
)
499 struct session_op
*op
= impl_op_from_IUnknown(iface
);
500 ULONG refcount
= InterlockedDecrement(&op
->refcount
);
502 TRACE("%p, refcount %u.\n", iface
, refcount
);
508 case SESSION_CMD_SET_TOPOLOGY
:
509 if (op
->u
.set_topology
.topology
)
510 IMFTopology_Release(op
->u
.set_topology
.topology
);
512 case SESSION_CMD_START
:
513 PropVariantClear(&op
->u
.start
.start_position
);
515 case SESSION_CMD_QM_NOTIFY_TOPOLOGY
:
516 if (op
->u
.notify_topology
.topology
)
517 IMFTopology_Release(op
->u
.notify_topology
.topology
);
528 static IUnknownVtbl session_op_vtbl
=
530 session_op_QueryInterface
,
535 static HRESULT
create_session_op(enum session_command command
, struct session_op
**ret
)
537 struct session_op
*op
;
539 if (!(op
= heap_alloc_zero(sizeof(*op
))))
540 return E_OUTOFMEMORY
;
542 op
->IUnknown_iface
.lpVtbl
= &session_op_vtbl
;
544 op
->command
= command
;
551 static HRESULT
session_is_shut_down(struct media_session
*session
)
553 return session
->state
== SESSION_STATE_SHUT_DOWN
? MF_E_SHUTDOWN
: S_OK
;
556 static void session_push_back_command(struct media_session
*session
, enum session_command command
)
558 struct session_op
*op
;
560 if (SUCCEEDED(create_session_op(command
, &op
)))
561 list_add_head(&session
->commands
, &op
->entry
);
564 static HRESULT
session_submit_command(struct media_session
*session
, struct session_op
*op
)
568 EnterCriticalSection(&session
->cs
);
569 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
571 if (list_empty(&session
->commands
))
572 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
573 list_add_tail(&session
->commands
, &op
->entry
);
574 IUnknown_AddRef(&op
->IUnknown_iface
);
576 LeaveCriticalSection(&session
->cs
);
581 static HRESULT
session_submit_simple_command(struct media_session
*session
, enum session_command command
)
583 struct session_op
*op
;
586 if (FAILED(hr
= create_session_op(command
, &op
)))
589 hr
= session_submit_command(session
, op
);
590 IUnknown_Release(&op
->IUnknown_iface
);
594 static void session_clear_topologies(struct media_session
*session
)
596 struct queued_topology
*ptr
, *next
;
598 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &session
->topologies
, struct queued_topology
, entry
)
600 list_remove(&ptr
->entry
);
601 IMFTopology_Release(ptr
->topology
);
606 static void session_set_topo_status(struct media_session
*session
, HRESULT status
,
607 MF_TOPOSTATUS topo_status
)
609 IMFMediaEvent
*event
;
612 if (topo_status
== MF_TOPOSTATUS_INVALID
)
615 if (list_empty(&session
->topologies
))
617 FIXME("Unexpectedly empty topology queue.\n");
621 if (topo_status
> session
->presentation
.topo_status
)
623 struct queued_topology
*topology
= LIST_ENTRY(list_head(&session
->topologies
), struct queued_topology
, entry
);
625 param
.vt
= VT_UNKNOWN
;
626 param
.punkVal
= (IUnknown
*)topology
->topology
;
628 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus
, &GUID_NULL
, status
, ¶m
, &event
)))
631 session
->presentation
.topo_status
= topo_status
;
633 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_TOPOLOGY_STATUS
, topo_status
);
634 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
635 IMFMediaEvent_Release(event
);
639 static HRESULT
session_bind_output_nodes(IMFTopology
*topology
)
641 MF_TOPOLOGY_TYPE node_type
;
642 IMFStreamSink
*stream_sink
;
643 IMFMediaSink
*media_sink
;
644 WORD node_count
= 0, i
;
645 IMFTopologyNode
*node
;
646 IMFActivate
*activate
;
651 hr
= IMFTopology_GetNodeCount(topology
, &node_count
);
653 for (i
= 0; i
< node_count
; ++i
)
655 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
658 if (FAILED(hr
= IMFTopologyNode_GetNodeType(node
, &node_type
)) || node_type
!= MF_TOPOLOGY_OUTPUT_NODE
)
660 IMFTopologyNode_Release(node
);
664 if (SUCCEEDED(hr
= IMFTopologyNode_GetObject(node
, &object
)))
667 if (FAILED(IUnknown_QueryInterface(object
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
669 if (SUCCEEDED(hr
= IUnknown_QueryInterface(object
, &IID_IMFActivate
, (void **)&activate
)))
671 if (SUCCEEDED(hr
= IMFActivate_ActivateObject(activate
, &IID_IMFMediaSink
, (void **)&media_sink
)))
673 if (FAILED(IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_STREAMID
, &stream_id
)))
677 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink
, stream_id
, &stream_sink
)))
678 hr
= IMFMediaSink_AddStreamSink(media_sink
, stream_id
, NULL
, &stream_sink
);
681 hr
= IMFTopologyNode_SetObject(node
, (IUnknown
*)stream_sink
);
683 IMFMediaSink_Release(media_sink
);
686 IMFActivate_Release(activate
);
691 IMFStreamSink_Release(stream_sink
);
692 IUnknown_Release(object
);
695 IMFTopologyNode_Release(node
);
701 static void session_set_caps(struct media_session
*session
, DWORD caps
)
703 DWORD delta
= session
->caps
^ caps
;
704 IMFMediaEvent
*event
;
706 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
707 them to, since session always queries for current object rates. */
711 session
->caps
= caps
;
713 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged
, &GUID_NULL
, S_OK
, NULL
, &event
)))
716 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS
, caps
);
717 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS_DELTA
, delta
);
719 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
720 IMFMediaEvent_Release(event
);
723 static void transform_release_sample(struct sample
*sample
)
725 list_remove(&sample
->entry
);
727 IMFSample_Release(sample
->sample
);
731 static void transform_stream_drop_samples(struct transform_stream
*stream
)
733 struct sample
*sample
, *sample2
;
735 LIST_FOR_EACH_ENTRY_SAFE(sample
, sample2
, &stream
->samples
, struct sample
, entry
)
736 transform_release_sample(sample
);
739 static void release_topo_node(struct topo_node
*node
)
745 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
746 if (node
->u
.source
.source
)
747 IMFMediaSource_Release(node
->u
.source
.source
);
749 case MF_TOPOLOGY_TRANSFORM_NODE
:
750 for (i
= 0; i
< node
->u
.transform
.input_count
; ++i
)
751 transform_stream_drop_samples(&node
->u
.transform
.inputs
[i
]);
752 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
753 transform_stream_drop_samples(&node
->u
.transform
.outputs
[i
]);
754 heap_free(node
->u
.transform
.inputs
);
755 heap_free(node
->u
.transform
.outputs
);
756 heap_free(node
->u
.transform
.input_map
);
757 heap_free(node
->u
.transform
.output_map
);
759 case MF_TOPOLOGY_OUTPUT_NODE
:
760 if (node
->u
.sink
.allocator
)
761 IMFVideoSampleAllocator_Release(node
->u
.sink
.allocator
);
762 if (node
->u
.sink
.allocator_cb
)
764 IMFVideoSampleAllocatorCallback_SetCallback(node
->u
.sink
.allocator_cb
, NULL
);
765 IMFVideoSampleAllocatorCallback_Release(node
->u
.sink
.allocator_cb
);
772 if (node
->object
.object
)
773 IUnknown_Release(node
->object
.object
);
775 IMFTopologyNode_Release(node
->node
);
779 static void session_clear_presentation(struct media_session
*session
)
781 struct media_source
*source
, *source2
;
782 struct media_sink
*sink
, *sink2
;
783 struct topo_node
*node
, *node2
;
784 struct session_op
*op
, *op2
;
786 IMFTopology_Clear(session
->presentation
.current_topology
);
787 session
->presentation
.topo_status
= MF_TOPOSTATUS_INVALID
;
789 LIST_FOR_EACH_ENTRY_SAFE(source
, source2
, &session
->presentation
.sources
, struct media_source
, entry
)
791 list_remove(&source
->entry
);
793 IMFMediaSource_Release(source
->source
);
795 IMFPresentationDescriptor_Release(source
->pd
);
799 LIST_FOR_EACH_ENTRY_SAFE(node
, node2
, &session
->presentation
.nodes
, struct topo_node
, entry
)
801 list_remove(&node
->entry
);
802 release_topo_node(node
);
805 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &session
->presentation
.sinks
, struct media_sink
, entry
)
807 list_remove(&sink
->entry
);
810 IMFMediaSink_Release(sink
->sink
);
812 IMFMediaSinkPreroll_Release(sink
->preroll
);
813 if (sink
->event_generator
)
814 IMFMediaEventGenerator_Release(sink
->event_generator
);
818 LIST_FOR_EACH_ENTRY_SAFE(op
, op2
, &session
->commands
, struct session_op
, entry
)
820 list_remove(&op
->entry
);
821 IUnknown_Release(&op
->IUnknown_iface
);
825 static struct topo_node
*session_get_node_by_id(const struct media_session
*session
, TOPOID id
)
827 struct topo_node
*node
;
829 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
831 if (node
->node_id
== id
)
838 static void session_start(struct media_session
*session
, const GUID
*time_format
, const PROPVARIANT
*start_position
)
840 struct media_source
*source
;
843 switch (session
->state
)
845 case SESSION_STATE_STOPPED
:
846 case SESSION_STATE_PAUSED
:
848 session
->presentation
.time_format
= *time_format
;
849 session
->presentation
.start_position
.vt
= VT_EMPTY
;
850 PropVariantCopy(&session
->presentation
.start_position
, start_position
);
852 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
854 if (!(session
->presentation
.flags
& SESSION_FLAG_SOURCES_SUBSCRIBED
))
856 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(source
->source
, &session
->events_callback
,
857 (IUnknown
*)source
->source
)))
859 WARN("Failed to subscribe to source events, hr %#x.\n", hr
);
863 if (FAILED(hr
= IMFMediaSource_Start(source
->source
, source
->pd
, &GUID_NULL
, start_position
)))
864 WARN("Failed to start media source %p, hr %#x.\n", source
->source
, hr
);
867 session
->presentation
.flags
|= SESSION_FLAG_SOURCES_SUBSCRIBED
;
868 session
->state
= SESSION_STATE_STARTING_SOURCES
;
870 case SESSION_STATE_STARTED
:
871 FIXME("Seeking is not implemented.\n");
873 case SESSION_STATE_CLOSED
:
874 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionStarted
, &GUID_NULL
,
875 MF_E_INVALIDREQUEST
, NULL
);
882 static void session_command_complete(struct media_session
*session
)
884 struct session_op
*op
;
887 /* Pop current command, submit next. */
888 if ((e
= list_head(&session
->commands
)))
890 op
= LIST_ENTRY(e
, struct session_op
, entry
);
891 list_remove(&op
->entry
);
892 IUnknown_Release(&op
->IUnknown_iface
);
895 if ((e
= list_head(&session
->commands
)))
897 op
= LIST_ENTRY(e
, struct session_op
, entry
);
898 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
902 static void session_set_started(struct media_session
*session
)
904 struct media_source
*source
;
905 unsigned int caps
, flags
;
906 IMFMediaEvent
*event
;
908 session
->state
= SESSION_STATE_STARTED
;
910 caps
= session
->caps
| MFSESSIONCAP_PAUSE
;
912 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
914 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &flags
)))
916 if (!(flags
& MFMEDIASOURCE_CAN_PAUSE
))
918 caps
&= ~MFSESSIONCAP_PAUSE
;
924 session_set_caps(session
, caps
);
926 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted
, &GUID_NULL
, S_OK
, NULL
, &event
)))
928 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
929 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
930 IMFMediaEvent_Release(event
);
932 session_command_complete(session
);
935 static void session_set_paused(struct media_session
*session
, HRESULT status
)
937 session
->state
= SESSION_STATE_PAUSED
;
938 if (SUCCEEDED(status
))
939 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
940 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionPaused
, &GUID_NULL
, status
, NULL
);
941 session_command_complete(session
);
944 static void session_set_closed(struct media_session
*session
, HRESULT status
)
946 session
->state
= SESSION_STATE_CLOSED
;
947 if (SUCCEEDED(status
))
948 session_set_caps(session
, session
->caps
& ~(MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
));
949 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionClosed
, &GUID_NULL
, status
, NULL
);
950 session_command_complete(session
);
953 static void session_pause(struct media_session
*session
)
957 switch (session
->state
)
959 case SESSION_STATE_STARTED
:
961 /* Transition in two steps - pause clock, wait for sinks and pause sources. */
962 if (SUCCEEDED(hr
= IMFPresentationClock_Pause(session
->clock
)))
963 session
->state
= SESSION_STATE_PAUSING_SINKS
;
967 hr
= MF_E_INVALIDREQUEST
;
971 session_set_paused(session
, hr
);
974 static void session_set_stopped(struct media_session
*session
, HRESULT status
)
976 MediaEventType event_type
;
977 IMFMediaEvent
*event
;
979 session
->state
= SESSION_STATE_STOPPED
;
980 event_type
= session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
? MESessionEnded
: MESessionStopped
;
982 if (SUCCEEDED(MFCreateMediaEvent(event_type
, &GUID_NULL
, status
, NULL
, &event
)))
984 IMFMediaEvent_SetUINT64(event
, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME
, session
->presentation
.clock_stop_time
);
985 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
986 IMFMediaEvent_Release(event
);
988 session_command_complete(session
);
991 static void session_stop(struct media_session
*session
)
993 HRESULT hr
= MF_E_INVALIDREQUEST
;
995 switch (session
->state
)
997 case SESSION_STATE_STARTED
:
998 case SESSION_STATE_PAUSED
:
1000 /* Transition in two steps - pause clock, wait for sinks and pause sources. */
1001 IMFPresentationClock_GetTime(session
->clock
, &session
->presentation
.clock_stop_time
);
1002 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1003 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1005 session_set_stopped(session
, hr
);
1008 case SESSION_STATE_STOPPED
:
1012 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionStopped
, &GUID_NULL
, hr
, NULL
);
1013 session_command_complete(session
);
1018 static HRESULT
session_finalize_sinks(struct media_session
*session
)
1020 IMFFinalizableMediaSink
*fin_sink
;
1021 BOOL sinks_finalized
= TRUE
;
1022 struct media_sink
*sink
;
1025 session
->presentation
.flags
&= ~SESSION_FLAG_FINALIZE_SINKS
;
1026 session
->state
= SESSION_STATE_FINALIZING_SINKS
;
1028 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1030 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
1032 hr
= IMFFinalizableMediaSink_BeginFinalize(fin_sink
, &session
->sink_finalizer_callback
,
1033 (IUnknown
*)fin_sink
);
1034 IMFFinalizableMediaSink_Release(fin_sink
);
1037 sinks_finalized
= FALSE
;
1040 sink
->finalized
= TRUE
;
1043 if (sinks_finalized
)
1044 session_set_closed(session
, hr
);
1049 static void session_close(struct media_session
*session
)
1053 switch (session
->state
)
1055 case SESSION_STATE_STOPPED
:
1056 hr
= session_finalize_sinks(session
);
1058 case SESSION_STATE_STARTED
:
1059 case SESSION_STATE_PAUSED
:
1060 session
->presentation
.flags
|= SESSION_FLAG_FINALIZE_SINKS
;
1061 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1062 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1065 hr
= MF_E_INVALIDREQUEST
;
1070 session_set_closed(session
, hr
);
1073 static struct media_source
*session_get_media_source(struct media_session
*session
, IMFMediaSource
*source
)
1075 struct media_source
*cur
;
1077 LIST_FOR_EACH_ENTRY(cur
, &session
->presentation
.sources
, struct media_source
, entry
)
1079 if (source
== cur
->source
)
1086 static void session_release_media_source(struct media_source
*source
)
1088 IMFMediaSource_Release(source
->source
);
1090 IMFPresentationDescriptor_Release(source
->pd
);
1094 static HRESULT
session_add_media_source(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSource
*source
)
1096 struct media_source
*media_source
;
1099 if (session_get_media_source(session
, source
))
1102 if (!(media_source
= heap_alloc_zero(sizeof(*media_source
))))
1103 return E_OUTOFMEMORY
;
1105 media_source
->source
= source
;
1106 IMFMediaSource_AddRef(media_source
->source
);
1108 hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
, &IID_IMFPresentationDescriptor
,
1109 (void **)&media_source
->pd
);
1112 list_add_tail(&session
->presentation
.sources
, &media_source
->entry
);
1114 session_release_media_source(media_source
);
1119 static void session_raise_topology_set(struct media_session
*session
, IMFTopology
*topology
, HRESULT status
)
1123 param
.vt
= topology
? VT_UNKNOWN
: VT_EMPTY
;
1124 param
.punkVal
= (IUnknown
*)topology
;
1126 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologySet
, &GUID_NULL
, status
, ¶m
);
1129 static DWORD
session_get_object_rate_caps(IUnknown
*object
)
1131 IMFRateSupport
*rate_support
;
1135 if (SUCCEEDED(MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
1138 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_FORWARD
, TRUE
, &rate
)) && rate
!= 0.0f
)
1139 caps
|= MFSESSIONCAP_RATE_FORWARD
;
1142 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_REVERSE
, TRUE
, &rate
)) && rate
!= 0.0f
)
1143 caps
|= MFSESSIONCAP_RATE_REVERSE
;
1145 IMFRateSupport_Release(rate_support
);
1151 static HRESULT
session_add_media_sink(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSink
*sink
)
1153 struct media_sink
*media_sink
;
1156 LIST_FOR_EACH_ENTRY(media_sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1158 if (sink
== media_sink
->sink
)
1162 if (!(media_sink
= heap_alloc_zero(sizeof(*media_sink
))))
1163 return E_OUTOFMEMORY
;
1165 media_sink
->sink
= sink
;
1166 IMFMediaSink_AddRef(media_sink
->sink
);
1168 IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaEventGenerator
, (void **)&media_sink
->event_generator
);
1170 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
, &flags
)) && flags
& MEDIASINK_CAN_PREROLL
)
1172 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaSinkPreroll
, (void **)&media_sink
->preroll
)))
1173 session
->presentation
.flags
|= SESSION_FLAG_NEEDS_PREROLL
;
1176 list_add_tail(&session
->presentation
.sinks
, &media_sink
->entry
);
1181 static HRESULT
session_set_transform_stream_info(struct topo_node
*node
)
1183 unsigned int *input_map
= NULL
, *output_map
= NULL
;
1184 unsigned int i
, input_count
, output_count
;
1185 struct transform_stream
*streams
;
1188 hr
= IMFTransform_GetStreamCount(node
->object
.transform
, &input_count
, &output_count
);
1189 if (SUCCEEDED(hr
) && (input_count
> 1 || output_count
> 1))
1191 input_map
= heap_calloc(input_count
, sizeof(*input_map
));
1192 output_map
= heap_calloc(output_count
, sizeof(*output_map
));
1193 if (FAILED(IMFTransform_GetStreamIDs(node
->object
.transform
, input_count
, input_map
,
1194 output_count
, output_map
)))
1196 /* Assume sequential identifiers. */
1197 heap_free(input_map
);
1198 heap_free(output_map
);
1199 input_map
= output_map
= NULL
;
1205 streams
= heap_calloc(input_count
, sizeof(*streams
));
1206 for (i
= 0; i
< input_count
; ++i
)
1207 list_init(&streams
[i
].samples
);
1208 node
->u
.transform
.inputs
= streams
;
1210 streams
= heap_calloc(output_count
, sizeof(*streams
));
1211 for (i
= 0; i
< output_count
; ++i
)
1212 list_init(&streams
[i
].samples
);
1213 node
->u
.transform
.outputs
= streams
;
1215 node
->u
.transform
.input_count
= input_count
;
1216 node
->u
.transform
.output_count
= output_count
;
1217 node
->u
.transform
.input_map
= input_map
;
1218 node
->u
.transform
.output_map
= output_map
;
1224 static HRESULT
session_get_stream_sink_type(IMFStreamSink
*sink
, IMFMediaType
**media_type
)
1226 IMFMediaTypeHandler
*handler
;
1229 if (SUCCEEDED(hr
= IMFStreamSink_GetMediaTypeHandler(sink
, &handler
)))
1231 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, media_type
);
1232 IMFMediaTypeHandler_Release(handler
);
1238 static HRESULT WINAPI
node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify
*iface
,
1239 REFIID riid
, void **obj
)
1241 if (IsEqualIID(riid
, &IID_IMFVideoSampleAllocatorNotify
) ||
1242 IsEqualIID(riid
, &IID_IUnknown
))
1245 IMFVideoSampleAllocatorNotify_AddRef(iface
);
1250 return E_NOINTERFACE
;
1253 static ULONG WINAPI
node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify
*iface
)
1258 static ULONG WINAPI
node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify
*iface
)
1263 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
);
1265 static HRESULT WINAPI
node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify
*iface
)
1267 struct topo_node
*topo_node
= impl_node_from_IMFVideoSampleAllocatorNotify(iface
);
1268 struct session_op
*op
;
1270 if (SUCCEEDED(create_session_op(SESSION_CMD_SA_READY
, &op
)))
1272 op
->u
.sa_ready
.node_id
= topo_node
->node_id
;
1273 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &topo_node
->session
->commands_callback
, &op
->IUnknown_iface
);
1274 IUnknown_Release(&op
->IUnknown_iface
);
1280 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl
=
1282 node_sample_allocator_cb_QueryInterface
,
1283 node_sample_allocator_cb_AddRef
,
1284 node_sample_allocator_cb_Release
,
1285 node_sample_allocator_cb_NotifyRelease
,
1288 static HRESULT
session_append_node(struct media_session
*session
, IMFTopologyNode
*node
)
1290 struct topo_node
*topo_node
;
1291 IMFMediaSink
*media_sink
;
1292 IMFMediaType
*media_type
;
1293 IMFStreamDescriptor
*sd
;
1297 if (!(topo_node
= heap_alloc_zero(sizeof(*topo_node
))))
1298 return E_OUTOFMEMORY
;
1300 IMFTopologyNode_GetNodeType(node
, &topo_node
->type
);
1301 IMFTopologyNode_GetTopoNodeID(node
, &topo_node
->node_id
);
1302 topo_node
->node
= node
;
1303 IMFTopologyNode_AddRef(topo_node
->node
);
1304 topo_node
->session
= session
;
1306 switch (topo_node
->type
)
1308 case MF_TOPOLOGY_OUTPUT_NODE
:
1309 topo_node
->u
.sink
.notify_cb
.lpVtbl
= &node_sample_allocator_cb_vtbl
;
1311 if (FAILED(hr
= IMFTopologyNode_GetObject(node
, &object
)))
1313 WARN("Node %s does not have associated object.\n", wine_dbgstr_longlong(topo_node
->node_id
));
1316 hr
= IUnknown_QueryInterface(object
, &IID_IMFStreamSink
, (void **)&topo_node
->object
.object
);
1317 IUnknown_Release(object
);
1321 if (FAILED(hr
= IMFStreamSink_GetMediaSink(topo_node
->object
.sink_stream
, &media_sink
)))
1324 if (SUCCEEDED(hr
= session_add_media_sink(session
, node
, media_sink
)))
1326 if (SUCCEEDED(session_get_stream_sink_type(topo_node
->object
.sink_stream
, &media_type
)))
1328 if (SUCCEEDED(MFGetService(topo_node
->object
.object
, &MR_VIDEO_ACCELERATION_SERVICE
,
1329 &IID_IMFVideoSampleAllocator
, (void **)&topo_node
->u
.sink
.allocator
)))
1331 IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node
->u
.sink
.allocator
, 2, media_type
);
1332 IMFVideoSampleAllocator_QueryInterface(topo_node
->u
.sink
.allocator
,
1333 &IID_IMFVideoSampleAllocatorCallback
, (void **)&topo_node
->u
.sink
.allocator_cb
);
1334 IMFVideoSampleAllocatorCallback_SetCallback(topo_node
->u
.sink
.allocator_cb
,
1335 &topo_node
->u
.sink
.notify_cb
);
1337 IMFMediaType_Release(media_type
);
1340 IMFMediaSink_Release(media_sink
);
1343 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
1344 if (FAILED(IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_SOURCE
, &IID_IMFMediaSource
,
1345 (void **)&topo_node
->u
.source
.source
)))
1347 WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr
);
1351 if (FAILED(hr
= session_add_media_source(session
, node
, topo_node
->u
.source
.source
)))
1354 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
1355 &IID_IMFStreamDescriptor
, (void **)&sd
)))
1357 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr
);
1361 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &topo_node
->u
.source
.stream_id
);
1362 IMFStreamDescriptor_Release(sd
);
1365 case MF_TOPOLOGY_TRANSFORM_NODE
:
1366 if (SUCCEEDED(hr
= IMFTopologyNode_GetObject(node
, &object
)))
1368 hr
= IUnknown_QueryInterface(object
, &IID_IMFTransform
, (void **)&topo_node
->object
.transform
);
1369 IUnknown_Release(object
);
1373 hr
= session_set_transform_stream_info(topo_node
);
1375 WARN("Failed to get IMFTransform for MFT node, hr %#x.\n", hr
);
1378 case MF_TOPOLOGY_TEE_NODE
:
1379 FIXME("Unsupported node type %d.\n", topo_node
->type
);
1387 list_add_tail(&session
->presentation
.nodes
, &topo_node
->entry
);
1389 release_topo_node(topo_node
);
1394 static HRESULT
session_collect_nodes(struct media_session
*session
)
1396 IMFTopology
*topology
= session
->presentation
.current_topology
;
1397 IMFTopologyNode
*node
;
1401 if (!list_empty(&session
->presentation
.nodes
))
1404 if (FAILED(hr
= IMFTopology_GetNodeCount(topology
, &count
)))
1407 for (i
= 0; i
< count
; ++i
)
1409 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
1411 WARN("Failed to get node %u.\n", i
);
1415 hr
= session_append_node(session
, node
);
1416 IMFTopologyNode_Release(node
);
1419 WARN("Failed to add node %u.\n", i
);
1427 static HRESULT
session_set_current_topology(struct media_session
*session
, IMFTopology
*topology
)
1429 struct media_source
*source
;
1430 DWORD caps
, object_flags
;
1431 struct media_sink
*sink
;
1432 struct topo_node
*node
;
1433 struct session_op
*op
;
1434 IMFMediaEvent
*event
;
1437 if (session
->quality_manager
)
1439 if (SUCCEEDED(create_session_op(SESSION_CMD_QM_NOTIFY_TOPOLOGY
, &op
)))
1441 op
->u
.notify_topology
.topology
= topology
;
1442 IMFTopology_AddRef(op
->u
.notify_topology
.topology
);
1443 session_submit_command(session
, op
);
1444 IUnknown_Release(&op
->IUnknown_iface
);
1448 if (FAILED(hr
= IMFTopology_CloneFrom(session
->presentation
.current_topology
, topology
)))
1450 WARN("Failed to clone topology, hr %#x.\n", hr
);
1454 session_collect_nodes(session
);
1456 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1458 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
1460 if (FAILED(hr
= IMFTransform_ProcessMessage(node
->object
.transform
,
1461 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING
, 0)))
1466 /* FIXME: attributes are all zero for now */
1467 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime
, &GUID_NULL
, S_OK
, NULL
, &event
)))
1469 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME
, 0);
1470 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
1471 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT
, 0);
1473 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
1474 IMFMediaEvent_Release(event
);
1477 /* Update session caps. */
1478 caps
= MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
| MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
|
1479 MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1481 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1487 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &object_flags
)))
1489 if (!(object_flags
& MFMEDIASOURCE_DOES_NOT_USE_NETWORK
))
1490 caps
&= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1491 if (!(object_flags
& MFMEDIASOURCE_CAN_SEEK
))
1492 caps
&= ~MFSESSIONCAP_SEEK
;
1495 /* Mask unsupported rate caps. */
1497 caps
&= session_get_object_rate_caps((IUnknown
*)source
->source
)
1498 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1501 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1507 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
->sink
, &object_flags
)))
1509 if (!(object_flags
& MEDIASINK_RATELESS
))
1510 caps
&= session_get_object_rate_caps((IUnknown
*)sink
->sink
)
1511 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1515 session_set_caps(session
, caps
);
1520 static void session_set_topology(struct media_session
*session
, DWORD flags
, IMFTopology
*topology
)
1522 IMFTopology
*resolved_topology
= NULL
;
1525 /* Resolve unless claimed to be full. */
1526 if (!(flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
) && topology
)
1528 if (!(flags
& MFSESSION_SETTOPOLOGY_NORESOLUTION
))
1530 hr
= session_bind_output_nodes(topology
);
1533 hr
= IMFTopoLoader_Load(session
->topo_loader
, topology
, &resolved_topology
, NULL
/* FIXME? */);
1537 topology
= resolved_topology
;
1542 if (flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
)
1544 if ((topology
&& topology
== session
->presentation
.current_topology
) || !topology
)
1546 /* FIXME: stop current topology, queue next one. */
1547 session_clear_presentation(session
);
1554 else if (topology
&& flags
& MFSESSION_SETTOPOLOGY_IMMEDIATE
)
1556 session_clear_topologies(session
);
1557 session_clear_presentation(session
);
1560 session_raise_topology_set(session
, topology
, hr
);
1562 /* With no current topology set it right away, otherwise queue. */
1565 struct queued_topology
*queued_topology
;
1567 if ((queued_topology
= heap_alloc_zero(sizeof(*queued_topology
))))
1569 queued_topology
->topology
= topology
;
1570 IMFTopology_AddRef(queued_topology
->topology
);
1572 list_add_tail(&session
->topologies
, &queued_topology
->entry
);
1575 if (session
->presentation
.topo_status
== MF_TOPOSTATUS_INVALID
)
1577 hr
= session_set_current_topology(session
, topology
);
1578 session_set_topo_status(session
, hr
, MF_TOPOSTATUS_READY
);
1582 if (resolved_topology
)
1583 IMFTopology_Release(resolved_topology
);
1586 static HRESULT WINAPI
mfsession_QueryInterface(IMFMediaSession
*iface
, REFIID riid
, void **out
)
1588 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1590 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1592 if (IsEqualIID(riid
, &IID_IMFMediaSession
) ||
1593 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1594 IsEqualIID(riid
, &IID_IUnknown
))
1596 *out
= &session
->IMFMediaSession_iface
;
1597 IMFMediaSession_AddRef(iface
);
1600 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1602 *out
= &session
->IMFGetService_iface
;
1603 IMFMediaSession_AddRef(iface
);
1607 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1609 return E_NOINTERFACE
;
1612 static ULONG WINAPI
mfsession_AddRef(IMFMediaSession
*iface
)
1614 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1615 ULONG refcount
= InterlockedIncrement(&session
->refcount
);
1617 TRACE("%p, refcount %u.\n", iface
, refcount
);
1622 static ULONG WINAPI
mfsession_Release(IMFMediaSession
*iface
)
1624 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1625 ULONG refcount
= InterlockedDecrement(&session
->refcount
);
1627 TRACE("%p, refcount %u.\n", iface
, refcount
);
1631 session_clear_topologies(session
);
1632 session_clear_presentation(session
);
1633 if (session
->presentation
.current_topology
)
1634 IMFTopology_Release(session
->presentation
.current_topology
);
1635 if (session
->event_queue
)
1636 IMFMediaEventQueue_Release(session
->event_queue
);
1638 IMFPresentationClock_Release(session
->clock
);
1639 if (session
->system_time_source
)
1640 IMFPresentationTimeSource_Release(session
->system_time_source
);
1641 if (session
->clock_rate_control
)
1642 IMFRateControl_Release(session
->clock_rate_control
);
1643 if (session
->topo_loader
)
1644 IMFTopoLoader_Release(session
->topo_loader
);
1645 if (session
->quality_manager
)
1646 IMFQualityManager_Release(session
->quality_manager
);
1647 DeleteCriticalSection(&session
->cs
);
1654 static HRESULT WINAPI
mfsession_GetEvent(IMFMediaSession
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1656 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1658 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
1660 return IMFMediaEventQueue_GetEvent(session
->event_queue
, flags
, event
);
1663 static HRESULT WINAPI
mfsession_BeginGetEvent(IMFMediaSession
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1665 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1667 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1669 return IMFMediaEventQueue_BeginGetEvent(session
->event_queue
, callback
, state
);
1672 static HRESULT WINAPI
mfsession_EndGetEvent(IMFMediaSession
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
1674 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1676 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1678 return IMFMediaEventQueue_EndGetEvent(session
->event_queue
, result
, event
);
1681 static HRESULT WINAPI
mfsession_QueueEvent(IMFMediaSession
*iface
, MediaEventType event_type
, REFGUID ext_type
,
1682 HRESULT hr
, const PROPVARIANT
*value
)
1684 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1686 TRACE("%p, %d, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1688 return IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, event_type
, ext_type
, hr
, value
);
1691 static HRESULT WINAPI
mfsession_SetTopology(IMFMediaSession
*iface
, DWORD flags
, IMFTopology
*topology
)
1693 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1694 struct session_op
*op
;
1695 WORD node_count
= 0;
1698 TRACE("%p, %#x, %p.\n", iface
, flags
, topology
);
1702 if (FAILED(IMFTopology_GetNodeCount(topology
, &node_count
)) || node_count
== 0)
1703 return E_INVALIDARG
;
1706 if (FAILED(hr
= create_session_op(SESSION_CMD_SET_TOPOLOGY
, &op
)))
1709 op
->u
.set_topology
.flags
= flags
;
1710 op
->u
.set_topology
.topology
= topology
;
1711 if (op
->u
.set_topology
.topology
)
1712 IMFTopology_AddRef(op
->u
.set_topology
.topology
);
1714 hr
= session_submit_command(session
, op
);
1715 IUnknown_Release(&op
->IUnknown_iface
);
1720 static HRESULT WINAPI
mfsession_ClearTopologies(IMFMediaSession
*iface
)
1722 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1724 TRACE("%p.\n", iface
);
1726 return session_submit_simple_command(session
, SESSION_CMD_CLEAR_TOPOLOGIES
);
1729 static HRESULT WINAPI
mfsession_Start(IMFMediaSession
*iface
, const GUID
*format
, const PROPVARIANT
*start_position
)
1731 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1732 struct session_op
*op
;
1735 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), start_position
);
1737 if (!start_position
)
1740 if (FAILED(hr
= create_session_op(SESSION_CMD_START
, &op
)))
1743 op
->u
.start
.time_format
= format
? *format
: GUID_NULL
;
1744 hr
= PropVariantCopy(&op
->u
.start
.start_position
, start_position
);
1747 hr
= session_submit_command(session
, op
);
1749 IUnknown_Release(&op
->IUnknown_iface
);
1754 static HRESULT WINAPI
mfsession_Pause(IMFMediaSession
*iface
)
1756 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1758 TRACE("%p.\n", iface
);
1760 return session_submit_simple_command(session
, SESSION_CMD_PAUSE
);
1763 static HRESULT WINAPI
mfsession_Stop(IMFMediaSession
*iface
)
1765 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1767 TRACE("%p.\n", iface
);
1769 return session_submit_simple_command(session
, SESSION_CMD_STOP
);
1772 static HRESULT WINAPI
mfsession_Close(IMFMediaSession
*iface
)
1774 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1776 TRACE("%p.\n", iface
);
1778 return session_submit_simple_command(session
, SESSION_CMD_CLOSE
);
1781 static HRESULT WINAPI
mfsession_Shutdown(IMFMediaSession
*iface
)
1783 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1786 FIXME("%p.\n", iface
);
1788 EnterCriticalSection(&session
->cs
);
1789 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1791 session
->state
= SESSION_STATE_SHUT_DOWN
;
1792 IMFMediaEventQueue_Shutdown(session
->event_queue
);
1793 if (session
->quality_manager
)
1794 IMFQualityManager_Shutdown(session
->quality_manager
);
1795 MFShutdownObject((IUnknown
*)session
->clock
);
1796 IMFPresentationClock_Release(session
->clock
);
1797 session
->clock
= NULL
;
1799 LeaveCriticalSection(&session
->cs
);
1804 static HRESULT WINAPI
mfsession_GetClock(IMFMediaSession
*iface
, IMFClock
**clock
)
1806 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1809 TRACE("%p, %p.\n", iface
, clock
);
1811 EnterCriticalSection(&session
->cs
);
1812 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1814 *clock
= (IMFClock
*)session
->clock
;
1815 IMFClock_AddRef(*clock
);
1817 LeaveCriticalSection(&session
->cs
);
1822 static HRESULT WINAPI
mfsession_GetSessionCapabilities(IMFMediaSession
*iface
, DWORD
*caps
)
1824 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1827 TRACE("%p, %p.\n", iface
, caps
);
1832 EnterCriticalSection(&session
->cs
);
1833 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1834 *caps
= session
->caps
;
1835 LeaveCriticalSection(&session
->cs
);
1840 static HRESULT WINAPI
mfsession_GetFullTopology(IMFMediaSession
*iface
, DWORD flags
, TOPOID id
, IMFTopology
**topology
)
1842 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1843 struct queued_topology
*queued
;
1847 TRACE("%p, %#x, %s, %p.\n", iface
, flags
, wine_dbgstr_longlong(id
), topology
);
1851 EnterCriticalSection(&session
->cs
);
1853 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1855 if (flags
& MFSESSION_GETFULLTOPOLOGY_CURRENT
)
1857 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
1858 *topology
= session
->presentation
.current_topology
;
1860 hr
= MF_E_INVALIDREQUEST
;
1864 LIST_FOR_EACH_ENTRY(queued
, &session
->topologies
, struct queued_topology
, entry
)
1866 if (SUCCEEDED(IMFTopology_GetTopologyID(queued
->topology
, &topo_id
)) && topo_id
== id
)
1868 *topology
= queued
->topology
;
1875 IMFTopology_AddRef(*topology
);
1878 LeaveCriticalSection(&session
->cs
);
1883 static const IMFMediaSessionVtbl mfmediasessionvtbl
=
1885 mfsession_QueryInterface
,
1889 mfsession_BeginGetEvent
,
1890 mfsession_EndGetEvent
,
1891 mfsession_QueueEvent
,
1892 mfsession_SetTopology
,
1893 mfsession_ClearTopologies
,
1900 mfsession_GetSessionCapabilities
,
1901 mfsession_GetFullTopology
,
1904 static HRESULT WINAPI
session_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
1906 struct media_session
*session
= impl_from_IMFGetService(iface
);
1907 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
1910 static ULONG WINAPI
session_get_service_AddRef(IMFGetService
*iface
)
1912 struct media_session
*session
= impl_from_IMFGetService(iface
);
1913 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
1916 static ULONG WINAPI
session_get_service_Release(IMFGetService
*iface
)
1918 struct media_session
*session
= impl_from_IMFGetService(iface
);
1919 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
1922 static HRESULT WINAPI
session_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
1924 struct media_session
*session
= impl_from_IMFGetService(iface
);
1926 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
1930 if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
1932 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1934 *obj
= &session
->IMFRateSupport_iface
;
1936 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
1938 *obj
= &session
->IMFRateControl_iface
;
1941 else if (IsEqualGUID(service
, &MF_LOCAL_MFT_REGISTRATION_SERVICE
))
1943 return IMFLocalMFTRegistration_QueryInterface(&local_mft_registration
, riid
, obj
);
1945 else if (IsEqualGUID(service
, &MR_VIDEO_RENDER_SERVICE
))
1947 IMFStreamSink
*stream_sink
;
1948 IMFTopologyNode
*node
;
1949 IUnknown
*vr
, *object
;
1950 IMFCollection
*nodes
;
1955 EnterCriticalSection(&session
->cs
);
1957 /* Use first sink to support IMFVideoRenderer. */
1958 if (session
->presentation
.current_topology
)
1960 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session
->presentation
.current_topology
,
1963 while (IMFCollection_GetElement(nodes
, i
++, (IUnknown
**)&node
) == S_OK
)
1965 if (SUCCEEDED(IMFTopologyNode_GetObject(node
, &object
)))
1967 if (SUCCEEDED(IUnknown_QueryInterface(object
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
1969 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink
, &sink
)))
1971 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
, &IID_IMFVideoRenderer
, (void **)&vr
)))
1973 if (FAILED(hr
= MFGetService(vr
, service
, riid
, obj
)))
1974 WARN("Failed to get service from video renderer %#x.\n", hr
);
1975 IUnknown_Release(vr
);
1978 IMFStreamSink_Release(stream_sink
);
1981 IUnknown_Release(object
);
1984 IMFTopologyNode_Release(node
);
1990 IMFCollection_Release(nodes
);
1994 LeaveCriticalSection(&session
->cs
);
1997 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
2000 IUnknown_AddRef((IUnknown
*)*obj
);
2002 return *obj
? S_OK
: E_NOINTERFACE
;
2005 static const IMFGetServiceVtbl session_get_service_vtbl
=
2007 session_get_service_QueryInterface
,
2008 session_get_service_AddRef
,
2009 session_get_service_Release
,
2010 session_get_service_GetService
,
2013 static HRESULT WINAPI
session_commands_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2015 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2016 IsEqualIID(riid
, &IID_IUnknown
))
2019 IMFAsyncCallback_AddRef(iface
);
2023 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2025 return E_NOINTERFACE
;
2028 static ULONG WINAPI
session_commands_callback_AddRef(IMFAsyncCallback
*iface
)
2030 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2031 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2034 static ULONG WINAPI
session_commands_callback_Release(IMFAsyncCallback
*iface
)
2036 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2037 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2040 static HRESULT WINAPI
session_commands_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2045 static HRESULT WINAPI
session_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
2047 struct session_op
*op
= impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result
));
2048 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2049 struct topo_node
*topo_node
;
2050 IMFTopologyNode
*upstream_node
;
2051 unsigned int upstream_output
;
2053 EnterCriticalSection(&session
->cs
);
2055 switch (op
->command
)
2057 case SESSION_CMD_CLEAR_TOPOLOGIES
:
2058 session_clear_topologies(session
);
2059 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologiesCleared
, &GUID_NULL
,
2061 session_command_complete(session
);
2063 case SESSION_CMD_SET_TOPOLOGY
:
2064 session_set_topology(session
, op
->u
.set_topology
.flags
, op
->u
.set_topology
.topology
);
2065 session_command_complete(session
);
2067 case SESSION_CMD_START
:
2068 session_start(session
, &op
->u
.start
.time_format
, &op
->u
.start
.start_position
);
2070 case SESSION_CMD_PAUSE
:
2071 session_pause(session
);
2073 case SESSION_CMD_STOP
:
2074 session_stop(session
);
2076 case SESSION_CMD_CLOSE
:
2077 session_close(session
);
2079 case SESSION_CMD_QM_NOTIFY_TOPOLOGY
:
2080 IMFQualityManager_NotifyTopology(session
->quality_manager
, op
->u
.notify_topology
.topology
);
2081 session_command_complete(session
);
2083 case SESSION_CMD_SA_READY
:
2084 topo_node
= session_get_node_by_id(session
, op
->u
.sa_ready
.node_id
);
2086 if (topo_node
->u
.sink
.requests
)
2088 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node
->node
, 0, &upstream_node
, &upstream_output
)))
2090 session_request_sample_from_node(session
, upstream_node
, upstream_output
);
2091 IMFTopologyNode_Release(upstream_node
);
2099 LeaveCriticalSection(&session
->cs
);
2104 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl
=
2106 session_commands_callback_QueryInterface
,
2107 session_commands_callback_AddRef
,
2108 session_commands_callback_Release
,
2109 session_commands_callback_GetParameters
,
2110 session_commands_callback_Invoke
,
2113 static HRESULT WINAPI
session_events_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2115 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2116 IsEqualIID(riid
, &IID_IUnknown
))
2119 IMFAsyncCallback_AddRef(iface
);
2123 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2125 return E_NOINTERFACE
;
2128 static ULONG WINAPI
session_events_callback_AddRef(IMFAsyncCallback
*iface
)
2130 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2131 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2134 static ULONG WINAPI
session_events_callback_Release(IMFAsyncCallback
*iface
)
2136 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2137 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2140 static HRESULT WINAPI
session_events_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2145 static HRESULT
session_add_media_stream(struct media_session
*session
, IMFMediaSource
*source
, IMFMediaStream
*stream
)
2147 struct topo_node
*node
;
2148 IMFStreamDescriptor
*sd
;
2149 DWORD stream_id
= 0;
2152 if (FAILED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
2155 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &stream_id
);
2156 IMFStreamDescriptor_Release(sd
);
2160 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2162 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->u
.source
.source
== source
2163 && node
->u
.source
.stream_id
== stream_id
)
2165 if (node
->object
.source_stream
)
2167 WARN("Node already has stream set.\n");
2171 node
->object
.source_stream
= stream
;
2172 IMFMediaStream_AddRef(node
->object
.source_stream
);
2180 static BOOL
session_is_source_nodes_state(struct media_session
*session
, enum object_state state
)
2182 struct media_source
*source
;
2183 struct topo_node
*node
;
2185 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2187 if (source
->state
!= state
)
2191 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2193 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->state
!= state
)
2200 static BOOL
session_is_output_nodes_state(struct media_session
*session
, enum object_state state
)
2202 struct topo_node
*node
;
2204 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2206 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->state
!= state
)
2213 static enum object_state
session_get_object_state_for_event(MediaEventType event
)
2217 case MESourceStarted
:
2218 case MEStreamStarted
:
2219 case MEStreamSinkStarted
:
2220 return OBJ_STATE_STARTED
;
2221 case MESourcePaused
:
2222 case MEStreamPaused
:
2223 case MEStreamSinkPaused
:
2224 return OBJ_STATE_PAUSED
;
2225 case MESourceStopped
:
2226 case MEStreamStopped
:
2227 case MEStreamSinkStopped
:
2228 return OBJ_STATE_STOPPED
;
2229 case MEStreamSinkPrerolled
:
2230 return OBJ_STATE_PREROLLED
;
2232 return OBJ_STATE_INVALID
;
2236 static void session_set_consumed_clock(IUnknown
*object
, IMFPresentationClock
*clock
)
2238 IMFClockConsumer
*consumer
;
2240 if (SUCCEEDED(IUnknown_QueryInterface(object
, &IID_IMFClockConsumer
, (void **)&consumer
)))
2242 IMFClockConsumer_SetPresentationClock(consumer
, clock
);
2243 IMFClockConsumer_Release(consumer
);
2247 static void session_set_presentation_clock(struct media_session
*session
)
2249 IMFPresentationTimeSource
*time_source
= NULL
;
2250 struct media_source
*source
;
2251 struct media_sink
*sink
;
2252 struct topo_node
*node
;
2255 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2257 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
2258 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_NOTIFY_START_OF_STREAM
, 0);
2261 if (!(session
->presentation
.flags
& SESSION_FLAG_PRESENTATION_CLOCK_SET
))
2263 /* Attempt to get time source from the sinks. */
2264 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2266 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFPresentationTimeSource
,
2267 (void **)&time_source
)))
2273 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, time_source
);
2274 IMFPresentationTimeSource_Release(time_source
);
2277 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, session
->system_time_source
);
2280 WARN("Failed to set time source, hr %#x.\n", hr
);
2282 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2284 if (node
->type
!= MF_TOPOLOGY_OUTPUT_NODE
)
2287 if (FAILED(hr
= IMFStreamSink_BeginGetEvent(node
->object
.sink_stream
, &session
->events_callback
,
2288 node
->object
.object
)))
2290 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr
);
2294 /* Set clock for all topology nodes. */
2295 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2297 session_set_consumed_clock((IUnknown
*)source
->source
, session
->clock
);
2300 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2302 if (sink
->event_generator
&& FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(sink
->event_generator
,
2303 &session
->events_callback
, (IUnknown
*)sink
->event_generator
)))
2305 WARN("Failed to subscribe to sink events, hr %#x.\n", hr
);
2308 if (FAILED(hr
= IMFMediaSink_SetPresentationClock(sink
->sink
, session
->clock
)))
2309 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr
);
2312 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2314 if (node
->type
!= MF_TOPOLOGY_TRANSFORM_NODE
)
2317 session_set_consumed_clock(node
->object
.object
, session
->clock
);
2320 session
->presentation
.flags
|= SESSION_FLAG_PRESENTATION_CLOCK_SET
;
2324 static HRESULT
session_start_clock(struct media_session
*session
)
2326 LONGLONG start_offset
= 0;
2329 if (IsEqualGUID(&session
->presentation
.time_format
, &GUID_NULL
))
2331 if (session
->presentation
.start_position
.vt
== VT_EMPTY
)
2332 start_offset
= PRESENTATION_CURRENT_POSITION
;
2333 else if (session
->presentation
.start_position
.vt
== VT_I8
)
2334 start_offset
= session
->presentation
.start_position
.hVal
.QuadPart
;
2336 FIXME("Unhandled position type %d.\n", session
->presentation
.start_position
.vt
);
2339 FIXME("Unhandled time format %s.\n", debugstr_guid(&session
->presentation
.time_format
));
2341 if (FAILED(hr
= IMFPresentationClock_Start(session
->clock
, start_offset
)))
2342 WARN("Failed to start session clock, hr %#x.\n", hr
);
2347 static struct topo_node
*session_get_node_object(struct media_session
*session
, IUnknown
*object
,
2348 MF_TOPOLOGY_TYPE node_type
)
2350 struct topo_node
*node
= NULL
;
2352 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2354 if (node
->type
== node_type
&& object
== node
->object
.object
)
2361 static BOOL
session_set_node_object_state(struct media_session
*session
, IUnknown
*object
,
2362 MF_TOPOLOGY_TYPE node_type
, enum object_state state
)
2364 struct topo_node
*node
;
2365 BOOL changed
= FALSE
;
2367 if ((node
= session_get_node_object(session
, object
, node_type
)))
2369 changed
= node
->state
!= state
;
2370 node
->state
= state
;
2376 static void session_set_source_object_state(struct media_session
*session
, IUnknown
*object
,
2377 MediaEventType event_type
)
2379 IMFStreamSink
*stream_sink
;
2380 struct media_source
*src
;
2381 struct media_sink
*sink
;
2382 enum object_state state
;
2383 struct topo_node
*node
;
2384 unsigned int i
, count
;
2385 BOOL changed
= FALSE
;
2388 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2393 case MESourceStarted
:
2394 case MESourcePaused
:
2395 case MESourceStopped
:
2397 LIST_FOR_EACH_ENTRY(src
, &session
->presentation
.sources
, struct media_source
, entry
)
2399 if (object
== (IUnknown
*)src
->source
)
2401 changed
= src
->state
!= state
;
2407 case MEStreamStarted
:
2408 case MEStreamPaused
:
2409 case MEStreamStopped
:
2411 changed
= session_set_node_object_state(session
, object
, MF_TOPOLOGY_SOURCESTREAM_NODE
, state
);
2419 switch (session
->state
)
2421 case SESSION_STATE_STARTING_SOURCES
:
2422 if (!session_is_source_nodes_state(session
, OBJ_STATE_STARTED
))
2425 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_STARTED_SOURCE
);
2427 session_set_presentation_clock(session
);
2429 if (session
->presentation
.flags
& SESSION_FLAG_NEEDS_PREROLL
)
2431 MFTIME preroll_time
= 0;
2433 if (session
->presentation
.start_position
.vt
== VT_I8
)
2434 preroll_time
= session
->presentation
.start_position
.hVal
.QuadPart
;
2436 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2437 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2441 /* FIXME: abort and enter error state on failure. */
2442 if (FAILED(hr
= IMFMediaSinkPreroll_NotifyPreroll(sink
->preroll
, preroll_time
)))
2443 WARN("Preroll notification failed, hr %#x.\n", hr
);
2447 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink
->sink
, &count
)))
2449 for (i
= 0; i
< count
; ++i
)
2451 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink
->sink
, i
, &stream_sink
)))
2453 session_set_node_object_state(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
,
2454 OBJ_STATE_PREROLLED
);
2455 IMFStreamSink_Release(stream_sink
);
2461 session
->state
= SESSION_STATE_PREROLLING_SINKS
;
2463 else if (SUCCEEDED(session_start_clock(session
)))
2464 session
->state
= SESSION_STATE_STARTING_SINKS
;
2467 case SESSION_STATE_PAUSING_SOURCES
:
2468 if (!session_is_source_nodes_state(session
, OBJ_STATE_PAUSED
))
2471 session_set_paused(session
, S_OK
);
2473 case SESSION_STATE_STOPPING_SOURCES
:
2474 if (!session_is_source_nodes_state(session
, OBJ_STATE_STOPPED
))
2477 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2481 case MF_TOPOLOGY_OUTPUT_NODE
:
2482 IMFStreamSink_Flush(node
->object
.sink_stream
);
2484 case MF_TOPOLOGY_TRANSFORM_NODE
:
2485 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
2492 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
2494 if (session
->presentation
.flags
& SESSION_FLAG_FINALIZE_SINKS
)
2495 session_finalize_sinks(session
);
2497 session_set_stopped(session
, S_OK
);
2505 static void session_set_sink_stream_state(struct media_session
*session
, IMFStreamSink
*stream
,
2506 MediaEventType event_type
)
2508 struct media_source
*source
;
2509 enum object_state state
;
2513 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2516 if (!(changed
= session_set_node_object_state(session
, (IUnknown
*)stream
, MF_TOPOLOGY_OUTPUT_NODE
, state
)))
2519 switch (session
->state
)
2521 case SESSION_STATE_PREROLLING_SINKS
:
2522 if (!session_is_output_nodes_state(session
, OBJ_STATE_PREROLLED
))
2525 if (SUCCEEDED(session_start_clock(session
)))
2526 session
->state
= SESSION_STATE_STARTING_SINKS
;
2528 case SESSION_STATE_STARTING_SINKS
:
2529 if (!session_is_output_nodes_state(session
, OBJ_STATE_STARTED
))
2532 session_set_started(session
);
2534 case SESSION_STATE_PAUSING_SINKS
:
2535 if (!session_is_output_nodes_state(session
, OBJ_STATE_PAUSED
))
2538 session
->state
= SESSION_STATE_PAUSING_SOURCES
;
2540 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2542 if (FAILED(hr
= IMFMediaSource_Pause(source
->source
)))
2547 session_set_paused(session
, hr
);
2550 case SESSION_STATE_STOPPING_SINKS
:
2551 if (!session_is_output_nodes_state(session
, OBJ_STATE_STOPPED
))
2554 session
->state
= SESSION_STATE_STOPPING_SOURCES
;
2556 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2558 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
)
2559 IMFMediaSource_Stop(source
->source
);
2560 else if (FAILED(hr
= IMFMediaSource_Stop(source
->source
)))
2564 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
|| FAILED(hr
))
2565 session_set_stopped(session
, hr
);
2573 static DWORD
transform_node_get_stream_id(struct topo_node
*node
, BOOL output
, DWORD index
)
2575 unsigned int *map
= output
? node
->u
.transform
.output_map
: node
->u
.transform
.input_map
;
2576 return map
? map
[index
] : index
;
2579 static struct sample
*transform_create_sample(IMFSample
*sample
)
2581 struct sample
*sample_entry
= heap_alloc_zero(sizeof(*sample_entry
));
2585 sample_entry
->sample
= sample
;
2586 if (sample_entry
->sample
)
2587 IMFSample_AddRef(sample_entry
->sample
);
2590 return sample_entry
;
2593 static HRESULT
transform_get_external_output_sample(const struct media_session
*session
, struct topo_node
*transform
,
2594 unsigned int output_index
, const MFT_OUTPUT_STREAM_INFO
*stream_info
, IMFSample
**sample
)
2596 IMFTopologyNode
*downstream_node
;
2597 unsigned int downstream_input
;
2598 IMFMediaBuffer
*buffer
= NULL
;
2599 struct topo_node
*topo_node
;
2603 if (FAILED(IMFTopologyNode_GetOutput(transform
->node
, output_index
, &downstream_node
, &downstream_input
)))
2605 WARN("Failed to get connected node for output %u.\n", output_index
);
2606 return MF_E_UNEXPECTED
;
2609 IMFTopologyNode_GetTopoNodeID(downstream_node
, &node_id
);
2610 IMFTopologyNode_Release(downstream_node
);
2612 topo_node
= session_get_node_by_id(session
, node_id
);
2614 if (topo_node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& topo_node
->u
.sink
.allocator
)
2616 hr
= IMFVideoSampleAllocator_AllocateSample(topo_node
->u
.sink
.allocator
, sample
);
2620 hr
= MFCreateAlignedMemoryBuffer(stream_info
->cbSize
, stream_info
->cbAlignment
, &buffer
);
2622 hr
= MFCreateSample(sample
);
2625 hr
= IMFSample_AddBuffer(*sample
, buffer
);
2628 IMFMediaBuffer_Release(buffer
);
2634 static HRESULT
transform_node_pull_samples(const struct media_session
*session
, struct topo_node
*node
)
2636 MFT_OUTPUT_STREAM_INFO stream_info
;
2637 MFT_OUTPUT_DATA_BUFFER
*buffers
;
2638 struct sample
*queued_sample
;
2641 HRESULT hr
= E_UNEXPECTED
;
2643 if (!(buffers
= heap_calloc(node
->u
.transform
.output_count
, sizeof(*buffers
))))
2644 return E_OUTOFMEMORY
;
2646 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2648 buffers
[i
].dwStreamID
= transform_node_get_stream_id(node
, TRUE
, i
);
2649 buffers
[i
].pSample
= NULL
;
2650 buffers
[i
].dwStatus
= 0;
2651 buffers
[i
].pEvents
= NULL
;
2653 memset(&stream_info
, 0, sizeof(stream_info
));
2654 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(node
->object
.transform
, buffers
[i
].dwStreamID
, &stream_info
)))
2657 if (!(stream_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
))
2659 if (FAILED(hr
= transform_get_external_output_sample(session
, node
, i
, &stream_info
, &buffers
[i
].pSample
)))
2665 hr
= IMFTransform_ProcessOutput(node
->object
.transform
, 0, node
->u
.transform
.output_count
, buffers
, &status
);
2667 /* Collect returned samples for all streams. */
2668 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2670 if (buffers
[i
].pEvents
)
2671 IMFCollection_Release(buffers
[i
].pEvents
);
2673 if (SUCCEEDED(hr
) && !(buffers
[i
].dwStatus
& MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE
))
2675 if (session
->quality_manager
)
2676 IMFQualityManager_NotifyProcessOutput(session
->quality_manager
, node
->node
, i
, buffers
[i
].pSample
);
2678 queued_sample
= transform_create_sample(buffers
[i
].pSample
);
2679 list_add_tail(&node
->u
.transform
.outputs
[i
].samples
, &queued_sample
->entry
);
2682 if (buffers
[i
].pSample
)
2683 IMFSample_Release(buffers
[i
].pSample
);
2691 static void session_deliver_sample_to_node(struct media_session
*session
, IMFTopologyNode
*node
, unsigned int input
,
2694 struct sample
*sample_entry
, *sample_entry2
;
2695 DWORD stream_id
, downstream_input
;
2696 IMFTopologyNode
*downstream_node
;
2697 struct topo_node
*topo_node
;
2698 MF_TOPOLOGY_TYPE node_type
;
2704 if (session
->quality_manager
)
2705 IMFQualityManager_NotifyProcessInput(session
->quality_manager
, node
, input
, sample
);
2707 IMFTopologyNode_GetNodeType(node
, &node_type
);
2708 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2710 topo_node
= session_get_node_by_id(session
, node_id
);
2714 case MF_TOPOLOGY_OUTPUT_NODE
:
2717 if (topo_node
->u
.sink
.requests
)
2719 if (FAILED(hr
= IMFStreamSink_ProcessSample(topo_node
->object
.sink_stream
, sample
)))
2720 WARN("Stream sink failed to process sample, hr %#x.\n", hr
);
2721 topo_node
->u
.sink
.requests
--;
2724 else if (FAILED(hr
= IMFStreamSink_PlaceMarker(topo_node
->object
.sink_stream
, MFSTREAMSINK_MARKER_ENDOFSEGMENT
,
2727 WARN("Failed to place sink marker, hr %#x.\n", hr
);
2730 case MF_TOPOLOGY_TRANSFORM_NODE
:
2732 transform_node_pull_samples(session
, topo_node
);
2734 sample_entry
= transform_create_sample(sample
);
2735 list_add_tail(&topo_node
->u
.transform
.inputs
[input
].samples
, &sample_entry
->entry
);
2737 for (i
= 0; i
< topo_node
->u
.transform
.input_count
; ++i
)
2739 stream_id
= transform_node_get_stream_id(topo_node
, FALSE
, i
);
2740 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.inputs
[i
].samples
,
2741 struct sample
, entry
)
2743 if (sample_entry
->sample
)
2745 if ((hr
= IMFTransform_ProcessInput(topo_node
->object
.transform
, stream_id
,
2746 sample_entry
->sample
, 0)) == MF_E_NOTACCEPTING
)
2749 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i
, stream_id
, hr
);
2750 transform_release_sample(sample_entry
);
2754 transform_stream_drop_samples(&topo_node
->u
.transform
.inputs
[i
]);
2762 if (FAILED(hr
= IMFTransform_ProcessMessage(topo_node
->object
.transform
, MFT_MESSAGE_COMMAND_DRAIN
, 0)))
2763 WARN("Drain command failed for transform, hr %#x.\n", hr
);
2766 transform_node_pull_samples(session
, topo_node
);
2768 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2771 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2773 if ((sample_entry
= transform_create_sample(NULL
)))
2774 list_add_tail(&topo_node
->u
.transform
.outputs
[i
].samples
, &sample_entry
->entry
);
2778 /* Push down all available output. */
2779 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2781 if (FAILED(IMFTopologyNode_GetOutput(node
, i
, &downstream_node
, &downstream_input
)))
2783 WARN("Failed to get connected node for output %u.\n", i
);
2787 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.outputs
[i
].samples
,
2788 struct sample
, entry
)
2790 if (!topo_node
->u
.transform
.outputs
[i
].requests
)
2793 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample_entry
->sample
);
2794 topo_node
->u
.transform
.outputs
[i
].requests
--;
2796 transform_release_sample(sample_entry
);
2799 IMFTopologyNode_Release(downstream_node
);
2803 case MF_TOPOLOGY_TEE_NODE
:
2804 FIXME("Unhandled downstream node type %d.\n", node_type
);
2811 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
)
2813 IMFTopologyNode
*downstream_node
, *upstream_node
;
2814 unsigned int downstream_input
, upstream_output
;
2815 struct topo_node
*topo_node
;
2816 MF_TOPOLOGY_TYPE node_type
;
2817 struct sample
*sample
;
2821 IMFTopologyNode_GetNodeType(node
, &node_type
);
2822 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2824 topo_node
= session_get_node_by_id(session
, node_id
);
2828 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
2829 if (FAILED(hr
= IMFMediaStream_RequestSample(topo_node
->object
.source_stream
, NULL
)))
2830 WARN("Sample request failed, hr %#x.\n", hr
);
2832 case MF_TOPOLOGY_TRANSFORM_NODE
:
2834 if (list_empty(&topo_node
->u
.transform
.outputs
[output
].samples
))
2836 /* Forward request to upstream node. */
2837 if (SUCCEEDED(hr
= IMFTopologyNode_GetInput(node
, 0 /* FIXME */, &upstream_node
, &upstream_output
)))
2839 if (SUCCEEDED(hr
= session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2840 topo_node
->u
.transform
.outputs
[output
].requests
++;
2841 IMFTopologyNode_Release(upstream_node
);
2846 if (SUCCEEDED(hr
= IMFTopologyNode_GetOutput(node
, output
, &downstream_node
, &downstream_input
)))
2848 sample
= LIST_ENTRY(list_head(&topo_node
->u
.transform
.outputs
[output
].samples
), struct sample
, entry
);
2849 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample
->sample
);
2850 transform_release_sample(sample
);
2851 IMFTopologyNode_Release(downstream_node
);
2856 case MF_TOPOLOGY_TEE_NODE
:
2857 FIXME("Unhandled upstream node type %d.\n", node_type
);
2865 static void session_request_sample(struct media_session
*session
, IMFStreamSink
*sink_stream
)
2867 struct topo_node
*sink_node
= NULL
, *node
;
2868 IMFTopologyNode
*upstream_node
;
2869 DWORD upstream_output
;
2872 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2874 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink_stream
)
2884 if (FAILED(hr
= IMFTopologyNode_GetInput(sink_node
->node
, 0, &upstream_node
, &upstream_output
)))
2886 WARN("Failed to get upstream node connection, hr %#x.\n", hr
);
2890 if (SUCCEEDED(session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2891 sink_node
->u
.sink
.requests
++;
2892 IMFTopologyNode_Release(upstream_node
);
2895 static void session_deliver_sample(struct media_session
*session
, IMFMediaStream
*stream
, const PROPVARIANT
*value
)
2897 struct topo_node
*source_node
= NULL
, *node
;
2898 IMFTopologyNode
*downstream_node
;
2899 DWORD downstream_input
;
2902 if (value
&& (value
->vt
!= VT_UNKNOWN
|| !value
->punkVal
))
2904 WARN("Unexpected value type %d.\n", value
->vt
);
2908 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2910 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->object
.source_stream
== stream
)
2921 source_node
->flags
|= TOPO_NODE_END_OF_STREAM
;
2923 if (FAILED(hr
= IMFTopologyNode_GetOutput(source_node
->node
, 0, &downstream_node
, &downstream_input
)))
2925 WARN("Failed to get downstream node connection, hr %#x.\n", hr
);
2929 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, value
? (IMFSample
*)value
->punkVal
: NULL
);
2930 IMFTopologyNode_Release(downstream_node
);
2933 static void session_sink_invalidated(struct media_session
*session
, IMFMediaEvent
*event
, IMFStreamSink
*sink
)
2935 struct topo_node
*node
, *sink_node
= NULL
;
2938 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2940 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink
)
2952 if (FAILED(hr
= MFCreateMediaEvent(MESinkInvalidated
, &GUID_NULL
, S_OK
, NULL
, &event
)))
2953 WARN("Failed to create event, hr %#x.\n", hr
);
2959 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_OUTPUT_NODE
, sink_node
->node_id
);
2960 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
2962 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
2965 static BOOL
session_nodes_is_mask_set(struct media_session
*session
, MF_TOPOLOGY_TYPE node_type
, unsigned int flags
)
2967 struct media_source
*source
;
2968 struct topo_node
*node
;
2970 if (node_type
== MF_TOPOLOGY_MAX
)
2972 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2974 if ((source
->flags
& flags
) != flags
)
2980 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2982 if (node
->type
== node_type
&& (node
->flags
& flags
) != flags
)
2990 static void session_raise_end_of_presentation(struct media_session
*session
)
2992 if (!(session_nodes_is_mask_set(session
, MF_TOPOLOGY_SOURCESTREAM_NODE
, TOPO_NODE_END_OF_STREAM
)))
2995 if (!(session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
))
2997 if (session_nodes_is_mask_set(session
, MF_TOPOLOGY_MAX
, SOURCE_FLAG_END_OF_PRESENTATION
))
2999 session
->presentation
.flags
|= SESSION_FLAG_END_OF_PRESENTATION
;
3000 session_push_back_command(session
, SESSION_CMD_END
);
3001 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MEEndOfPresentation
, &GUID_NULL
, S_OK
, NULL
);
3006 static void session_handle_end_of_stream(struct media_session
*session
, IMFMediaStream
*stream
)
3008 struct topo_node
*node
;
3010 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream
, MF_TOPOLOGY_SOURCESTREAM_NODE
))
3011 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3016 session_deliver_sample(session
, stream
, NULL
);
3018 session_raise_end_of_presentation(session
);
3021 static void session_handle_end_of_presentation(struct media_session
*session
, IMFMediaSource
*object
)
3023 struct media_source
*source
;
3025 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3027 if (source
->source
== object
)
3029 if (!(source
->flags
& SOURCE_FLAG_END_OF_PRESENTATION
))
3031 source
->flags
|= SOURCE_FLAG_END_OF_PRESENTATION
;
3032 session_raise_end_of_presentation(session
);
3040 static void session_sink_stream_marker(struct media_session
*session
, IMFStreamSink
*stream_sink
)
3042 struct topo_node
*node
;
3044 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
))
3045 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3050 node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3052 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
&&
3053 session_nodes_is_mask_set(session
, MF_TOPOLOGY_OUTPUT_NODE
, TOPO_NODE_END_OF_STREAM
))
3055 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3056 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
3057 session_stop(session
);
3061 static HRESULT WINAPI
session_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3063 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
3064 IMFMediaEventGenerator
*event_source
;
3065 IMFMediaEvent
*event
= NULL
;
3066 MediaEventType event_type
;
3067 IUnknown
*object
= NULL
;
3068 IMFMediaSource
*source
;
3069 IMFMediaStream
*stream
;
3073 if (FAILED(hr
= IMFAsyncResult_GetState(result
, (IUnknown
**)&event_source
)))
3076 if (FAILED(hr
= IMFMediaEventGenerator_EndGetEvent(event_source
, result
, &event
)))
3078 WARN("Failed to get event from %p, hr %#x.\n", event_source
, hr
);
3082 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
3084 WARN("Failed to get event type, hr %#x.\n", hr
);
3088 value
.vt
= VT_EMPTY
;
3089 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
3091 WARN("Failed to get event value, hr %#x.\n", hr
);
3097 case MESourceStarted
:
3098 case MESourcePaused
:
3099 case MESourceStopped
:
3100 case MEStreamStarted
:
3101 case MEStreamPaused
:
3102 case MEStreamStopped
:
3104 EnterCriticalSection(&session
->cs
);
3105 session_set_source_object_state(session
, (IUnknown
*)event_source
, event_type
);
3106 LeaveCriticalSection(&session
->cs
);
3110 case MEBufferingStarted
:
3111 case MEBufferingStopped
:
3113 EnterCriticalSection(&session
->cs
);
3114 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3116 if (event_type
== MEBufferingStarted
)
3117 IMFPresentationClock_Pause(session
->clock
);
3119 IMFPresentationClock_Start(session
->clock
, PRESENTATION_CURRENT_POSITION
);
3121 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3123 LeaveCriticalSection(&session
->cs
);
3127 stream
= (IMFMediaStream
*)value
.punkVal
;
3129 if (value
.vt
!= VT_UNKNOWN
|| !stream
)
3131 WARN("Unexpected event value.\n");
3135 if (FAILED(hr
= IMFMediaStream_GetMediaSource(stream
, &source
)))
3138 EnterCriticalSection(&session
->cs
);
3139 if (SUCCEEDED(hr
= session_add_media_stream(session
, source
, stream
)))
3140 hr
= IMFMediaStream_BeginGetEvent(stream
, &session
->events_callback
, (IUnknown
*)stream
);
3141 LeaveCriticalSection(&session
->cs
);
3143 IMFMediaSource_Release(source
);
3146 case MEStreamSinkStarted
:
3147 case MEStreamSinkPaused
:
3148 case MEStreamSinkStopped
:
3149 case MEStreamSinkPrerolled
:
3151 EnterCriticalSection(&session
->cs
);
3152 session_set_sink_stream_state(session
, (IMFStreamSink
*)event_source
, event_type
);
3153 LeaveCriticalSection(&session
->cs
);
3156 case MEStreamSinkMarker
:
3158 EnterCriticalSection(&session
->cs
);
3159 session_sink_stream_marker(session
, (IMFStreamSink
*)event_source
);
3160 LeaveCriticalSection(&session
->cs
);
3163 case MEStreamSinkRequestSample
:
3165 EnterCriticalSection(&session
->cs
);
3166 session_request_sample(session
, (IMFStreamSink
*)event_source
);
3167 LeaveCriticalSection(&session
->cs
);
3172 EnterCriticalSection(&session
->cs
);
3173 session_deliver_sample(session
, (IMFMediaStream
*)event_source
, &value
);
3174 LeaveCriticalSection(&session
->cs
);
3179 EnterCriticalSection(&session
->cs
);
3180 session_handle_end_of_stream(session
, (IMFMediaStream
*)event_source
);
3181 LeaveCriticalSection(&session
->cs
);
3185 case MEEndOfPresentation
:
3187 EnterCriticalSection(&session
->cs
);
3188 session_handle_end_of_presentation(session
, (IMFMediaSource
*)event_source
);
3189 LeaveCriticalSection(&session
->cs
);
3192 case MEAudioSessionGroupingParamChanged
:
3193 case MEAudioSessionIconChanged
:
3194 case MEAudioSessionNameChanged
:
3195 case MEAudioSessionVolumeChanged
:
3197 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3200 case MEAudioSessionDeviceRemoved
:
3201 case MEAudioSessionDisconnected
:
3202 case MEAudioSessionExclusiveModeOverride
:
3203 case MEAudioSessionFormatChanged
:
3204 case MEAudioSessionServerShutdown
:
3206 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3208 case MESinkInvalidated
:
3210 EnterCriticalSection(&session
->cs
);
3211 session_sink_invalidated(session
, event_type
== MESinkInvalidated
? event
: NULL
,
3212 (IMFStreamSink
*)event_source
);
3213 LeaveCriticalSection(&session
->cs
);
3216 case MEQualityNotify
:
3218 if (session
->quality_manager
)
3220 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFStreamSink
, (void **)&object
)))
3221 IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFTransform
, (void **)&object
);
3225 IMFQualityManager_NotifyQualityEvent(session
->quality_manager
, object
, event
);
3226 IUnknown_Release(object
);
3235 PropVariantClear(&value
);
3239 IMFMediaEvent_Release(event
);
3241 if (FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(event_source
, iface
, (IUnknown
*)event_source
)))
3242 WARN("Failed to re-subscribe, hr %#x.\n", hr
);
3244 IMFMediaEventGenerator_Release(event_source
);
3249 static const IMFAsyncCallbackVtbl session_events_callback_vtbl
=
3251 session_events_callback_QueryInterface
,
3252 session_events_callback_AddRef
,
3253 session_events_callback_Release
,
3254 session_events_callback_GetParameters
,
3255 session_events_callback_Invoke
,
3258 static HRESULT WINAPI
session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
3260 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
3261 IsEqualIID(riid
, &IID_IUnknown
))
3264 IMFAsyncCallback_AddRef(iface
);
3268 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3270 return E_NOINTERFACE
;
3273 static ULONG WINAPI
session_sink_finalizer_callback_AddRef(IMFAsyncCallback
*iface
)
3275 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3276 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3279 static ULONG WINAPI
session_sink_finalizer_callback_Release(IMFAsyncCallback
*iface
)
3281 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3282 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3285 static HRESULT WINAPI
session_sink_finalizer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
3290 static HRESULT WINAPI
session_sink_finalizer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3292 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3293 IMFFinalizableMediaSink
*fin_sink
= NULL
;
3294 BOOL sinks_finalized
= TRUE
;
3295 struct media_sink
*sink
;
3299 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
3302 EnterCriticalSection(&session
->cs
);
3304 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3306 if (state
== (IUnknown
*)sink
->sink
)
3308 if (FAILED(hr
= IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
3309 WARN("Unexpected, missing IMFFinalizableSink, hr %#x.\n", hr
);
3313 sinks_finalized
&= sink
->finalized
;
3314 if (!sinks_finalized
)
3319 IUnknown_Release(state
);
3323 /* Complete session transition, or close prematurely on error. */
3324 if (SUCCEEDED(hr
= IMFFinalizableMediaSink_EndFinalize(fin_sink
, result
)))
3326 sink
->finalized
= TRUE
;
3327 if (sinks_finalized
)
3328 session_set_closed(session
, hr
);
3330 IMFFinalizableMediaSink_Release(fin_sink
);
3333 LeaveCriticalSection(&session
->cs
);
3338 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl
=
3340 session_sink_finalizer_callback_QueryInterface
,
3341 session_sink_finalizer_callback_AddRef
,
3342 session_sink_finalizer_callback_Release
,
3343 session_sink_finalizer_callback_GetParameters
,
3344 session_sink_finalizer_callback_Invoke
,
3347 static HRESULT WINAPI
session_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
3349 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3350 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3353 static ULONG WINAPI
session_rate_support_AddRef(IMFRateSupport
*iface
)
3355 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3356 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3359 static ULONG WINAPI
session_rate_support_Release(IMFRateSupport
*iface
)
3361 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3362 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3365 static HRESULT
session_presentation_object_get_rate(IUnknown
*object
, MFRATE_DIRECTION direction
,
3366 BOOL thin
, BOOL fastest
, float *result
)
3368 IMFRateSupport
*rate_support
;
3372 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3374 if (FAILED(hr
= MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
3376 if (direction
== MFRATE_FORWARD
)
3382 return MF_E_REVERSE_UNSUPPORTED
;
3388 if (SUCCEEDED(hr
= IMFRateSupport_GetFastestRate(rate_support
, direction
, thin
, &rate
)))
3389 *result
= min(fabsf(rate
), *result
);
3393 if (SUCCEEDED(hr
= IMFRateSupport_GetSlowestRate(rate_support
, direction
, thin
, &rate
)))
3394 *result
= max(fabsf(rate
), *result
);
3397 IMFRateSupport_Release(rate_support
);
3402 static HRESULT
session_get_presentation_rate(struct media_session
*session
, MFRATE_DIRECTION direction
,
3403 BOOL thin
, BOOL fastest
, float *result
)
3405 struct media_source
*source
;
3406 struct media_sink
*sink
;
3407 HRESULT hr
= E_POINTER
;
3411 EnterCriticalSection(&session
->cs
);
3413 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
3415 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3417 if (FAILED(hr
= session_presentation_object_get_rate((IUnknown
*)source
->source
, direction
, thin
, fastest
, result
)))
3423 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3425 if (FAILED(hr
= session_presentation_object_get_rate((IUnknown
*)sink
->sink
, direction
, thin
, fastest
, result
)))
3431 LeaveCriticalSection(&session
->cs
);
3436 static HRESULT WINAPI
session_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3437 BOOL thin
, float *rate
)
3439 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3441 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3443 return session_get_presentation_rate(session
, direction
, thin
, FALSE
, rate
);
3446 static HRESULT WINAPI
session_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3447 BOOL thin
, float *rate
)
3449 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3451 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3453 return session_get_presentation_rate(session
, direction
, thin
, TRUE
, rate
);
3456 static HRESULT WINAPI
session_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
3457 float *nearest_supported_rate
)
3459 FIXME("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_supported_rate
);
3464 static const IMFRateSupportVtbl session_rate_support_vtbl
=
3466 session_rate_support_QueryInterface
,
3467 session_rate_support_AddRef
,
3468 session_rate_support_Release
,
3469 session_rate_support_GetSlowestRate
,
3470 session_rate_support_GetFastestRate
,
3471 session_rate_support_IsRateSupported
,
3474 static HRESULT WINAPI
session_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
3476 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3477 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3480 static ULONG WINAPI
session_rate_control_AddRef(IMFRateControl
*iface
)
3482 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3483 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3486 static ULONG WINAPI
session_rate_control_Release(IMFRateControl
*iface
)
3488 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3489 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3492 static HRESULT WINAPI
session_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
3494 FIXME("%p, %d, %f.\n", iface
, thin
, rate
);
3499 static HRESULT WINAPI
session_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
3501 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3503 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
3505 return IMFRateControl_GetRate(session
->clock_rate_control
, thin
, rate
);
3508 static const IMFRateControlVtbl session_rate_control_vtbl
=
3510 session_rate_control_QueryInterface
,
3511 session_rate_control_AddRef
,
3512 session_rate_control_Release
,
3513 session_rate_control_SetRate
,
3514 session_rate_control_GetRate
,
3517 /***********************************************************************
3518 * MFCreateMediaSession (mf.@)
3520 HRESULT WINAPI
MFCreateMediaSession(IMFAttributes
*config
, IMFMediaSession
**session
)
3522 BOOL without_quality_manager
= FALSE
;
3523 struct media_session
*object
;
3526 TRACE("%p, %p.\n", config
, session
);
3528 object
= heap_alloc_zero(sizeof(*object
));
3530 return E_OUTOFMEMORY
;
3532 object
->IMFMediaSession_iface
.lpVtbl
= &mfmediasessionvtbl
;
3533 object
->IMFGetService_iface
.lpVtbl
= &session_get_service_vtbl
;
3534 object
->IMFRateSupport_iface
.lpVtbl
= &session_rate_support_vtbl
;
3535 object
->IMFRateControl_iface
.lpVtbl
= &session_rate_control_vtbl
;
3536 object
->commands_callback
.lpVtbl
= &session_commands_callback_vtbl
;
3537 object
->events_callback
.lpVtbl
= &session_events_callback_vtbl
;
3538 object
->sink_finalizer_callback
.lpVtbl
= &session_sink_finalizer_callback_vtbl
;
3539 object
->refcount
= 1;
3540 list_init(&object
->topologies
);
3541 list_init(&object
->commands
);
3542 list_init(&object
->presentation
.sources
);
3543 list_init(&object
->presentation
.sinks
);
3544 list_init(&object
->presentation
.nodes
);
3545 InitializeCriticalSection(&object
->cs
);
3547 if (FAILED(hr
= MFCreateTopology(&object
->presentation
.current_topology
)))
3550 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
3553 if (FAILED(hr
= MFCreatePresentationClock(&object
->clock
)))
3556 if (FAILED(hr
= MFCreateSystemTimeSource(&object
->system_time_source
)))
3559 if (FAILED(hr
= IMFPresentationClock_QueryInterface(object
->clock
, &IID_IMFRateControl
,
3560 (void **)&object
->clock_rate_control
)))
3569 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_TOPOLOADER
, &clsid
)))
3571 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTopoLoader
,
3572 (void **)&object
->topo_loader
)))
3574 WARN("Failed to create custom topology loader, hr %#x.\n", hr
);
3578 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_QUALITY_MANAGER
, &clsid
)))
3580 if (!(without_quality_manager
= IsEqualGUID(&clsid
, &GUID_NULL
)))
3582 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFQualityManager
,
3583 (void **)&object
->quality_manager
)))
3585 WARN("Failed to create custom quality manager, hr %#x.\n", hr
);
3591 if (!object
->topo_loader
&& FAILED(hr
= MFCreateTopoLoader(&object
->topo_loader
)))
3594 if (!object
->quality_manager
&& !without_quality_manager
&&
3595 FAILED(hr
= MFCreateStandardQualityManager(&object
->quality_manager
)))
3600 if (object
->quality_manager
&& FAILED(hr
= IMFQualityManager_NotifyPresentationClock(object
->quality_manager
,
3606 *session
= &object
->IMFMediaSession_iface
;
3611 IMFMediaSession_Release(&object
->IMFMediaSession_iface
);
3615 static HRESULT WINAPI
sink_notification_QueryInterface(IUnknown
*iface
, REFIID riid
, void **out
)
3617 if (IsEqualIID(riid
, &IID_IUnknown
))
3620 IUnknown_AddRef(iface
);
3624 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3626 return E_NOINTERFACE
;
3629 static ULONG WINAPI
sink_notification_AddRef(IUnknown
*iface
)
3631 struct sink_notification
*notification
= impl_sink_notification_from_IUnknown(iface
);
3632 ULONG refcount
= InterlockedIncrement(¬ification
->refcount
);
3634 TRACE("%p, refcount %u.\n", iface
, refcount
);
3639 static ULONG WINAPI
sink_notification_Release(IUnknown
*iface
)
3641 struct sink_notification
*notification
= impl_sink_notification_from_IUnknown(iface
);
3642 ULONG refcount
= InterlockedDecrement(¬ification
->refcount
);
3644 TRACE("%p, refcount %u.\n", iface
, refcount
);
3648 IMFClockStateSink_Release(notification
->sink
);
3649 heap_free(notification
);
3655 static const IUnknownVtbl sinknotificationvtbl
=
3657 sink_notification_QueryInterface
,
3658 sink_notification_AddRef
,
3659 sink_notification_Release
,
3662 static void clock_notify_async_sink(struct presentation_clock
*clock
, MFTIME system_time
,
3663 struct clock_state_change_param param
, enum clock_notification notification
, IMFClockStateSink
*sink
)
3665 struct sink_notification
*object
;
3666 IMFAsyncResult
*result
;
3669 object
= heap_alloc(sizeof(*object
));
3673 object
->IUnknown_iface
.lpVtbl
= &sinknotificationvtbl
;
3674 object
->refcount
= 1;
3675 object
->system_time
= system_time
;
3676 object
->param
= param
;
3677 object
->notification
= notification
;
3678 object
->sink
= sink
;
3679 IMFClockStateSink_AddRef(object
->sink
);
3681 hr
= MFCreateAsyncResult(&object
->IUnknown_iface
, &clock
->sink_callback
, NULL
, &result
);
3682 IUnknown_Release(&object
->IUnknown_iface
);
3685 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD
, result
);
3686 IMFAsyncResult_Release(result
);
3690 static HRESULT WINAPI
present_clock_QueryInterface(IMFPresentationClock
*iface
, REFIID riid
, void **out
)
3692 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3694 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
3696 if (IsEqualIID(riid
, &IID_IMFPresentationClock
) ||
3697 IsEqualIID(riid
, &IID_IMFClock
) ||
3698 IsEqualIID(riid
, &IID_IUnknown
))
3700 *out
= &clock
->IMFPresentationClock_iface
;
3702 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
3704 *out
= &clock
->IMFRateControl_iface
;
3706 else if (IsEqualIID(riid
, &IID_IMFTimer
))
3708 *out
= &clock
->IMFTimer_iface
;
3710 else if (IsEqualIID(riid
, &IID_IMFShutdown
))
3712 *out
= &clock
->IMFShutdown_iface
;
3716 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3718 return E_NOINTERFACE
;
3721 IUnknown_AddRef((IUnknown
*)*out
);
3725 static ULONG WINAPI
present_clock_AddRef(IMFPresentationClock
*iface
)
3727 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3728 ULONG refcount
= InterlockedIncrement(&clock
->refcount
);
3730 TRACE("%p, refcount %u.\n", iface
, refcount
);
3735 static ULONG WINAPI
present_clock_Release(IMFPresentationClock
*iface
)
3737 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3738 ULONG refcount
= InterlockedDecrement(&clock
->refcount
);
3739 struct clock_timer
*timer
, *timer2
;
3740 struct clock_sink
*sink
, *sink2
;
3742 TRACE("%p, refcount %u.\n", iface
, refcount
);
3746 if (clock
->time_source
)
3747 IMFPresentationTimeSource_Release(clock
->time_source
);
3748 if (clock
->time_source_sink
)
3749 IMFClockStateSink_Release(clock
->time_source_sink
);
3750 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &clock
->sinks
, struct clock_sink
, entry
)
3752 list_remove(&sink
->entry
);
3753 IMFClockStateSink_Release(sink
->state_sink
);
3756 LIST_FOR_EACH_ENTRY_SAFE(timer
, timer2
, &clock
->timers
, struct clock_timer
, entry
)
3758 list_remove(&timer
->entry
);
3759 IUnknown_Release(&timer
->IUnknown_iface
);
3761 DeleteCriticalSection(&clock
->cs
);
3768 static HRESULT WINAPI
present_clock_GetClockCharacteristics(IMFPresentationClock
*iface
, DWORD
*flags
)
3770 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3771 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3773 TRACE("%p, %p.\n", iface
, flags
);
3775 EnterCriticalSection(&clock
->cs
);
3776 if (clock
->time_source
)
3777 hr
= IMFPresentationTimeSource_GetClockCharacteristics(clock
->time_source
, flags
);
3778 LeaveCriticalSection(&clock
->cs
);
3783 static HRESULT WINAPI
present_clock_GetCorrelatedTime(IMFPresentationClock
*iface
, DWORD reserved
,
3784 LONGLONG
*clock_time
, MFTIME
*system_time
)
3786 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3787 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3789 TRACE("%p, %#x, %p, %p.\n", iface
, reserved
, clock_time
, system_time
);
3791 EnterCriticalSection(&clock
->cs
);
3792 if (clock
->time_source
)
3793 hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, reserved
, clock_time
, system_time
);
3794 LeaveCriticalSection(&clock
->cs
);
3799 static HRESULT WINAPI
present_clock_GetContinuityKey(IMFPresentationClock
*iface
, DWORD
*key
)
3801 TRACE("%p, %p.\n", iface
, key
);
3808 static HRESULT WINAPI
present_clock_GetState(IMFPresentationClock
*iface
, DWORD reserved
, MFCLOCK_STATE
*state
)
3810 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3812 TRACE("%p, %#x, %p.\n", iface
, reserved
, state
);
3814 EnterCriticalSection(&clock
->cs
);
3815 *state
= clock
->state
;
3816 LeaveCriticalSection(&clock
->cs
);
3821 static HRESULT WINAPI
present_clock_GetProperties(IMFPresentationClock
*iface
, MFCLOCK_PROPERTIES
*props
)
3823 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3824 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3826 TRACE("%p, %p.\n", iface
, props
);
3828 EnterCriticalSection(&clock
->cs
);
3829 if (clock
->time_source
)
3830 hr
= IMFPresentationTimeSource_GetProperties(clock
->time_source
, props
);
3831 LeaveCriticalSection(&clock
->cs
);
3836 static HRESULT WINAPI
present_clock_SetTimeSource(IMFPresentationClock
*iface
,
3837 IMFPresentationTimeSource
*time_source
)
3839 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3840 MFCLOCK_PROPERTIES props
;
3841 IMFClock
*source_clock
;
3844 TRACE("%p, %p.\n", iface
, time_source
);
3846 EnterCriticalSection(&clock
->cs
);
3848 if (clock
->time_source
)
3849 IMFPresentationTimeSource_Release(clock
->time_source
);
3850 if (clock
->time_source_sink
)
3851 IMFClockStateSink_Release(clock
->time_source_sink
);
3852 clock
->time_source
= NULL
;
3853 clock
->time_source_sink
= NULL
;
3855 hr
= IMFPresentationTimeSource_QueryInterface(time_source
, &IID_IMFClockStateSink
, (void **)&clock
->time_source_sink
);
3858 clock
->time_source
= time_source
;
3859 IMFPresentationTimeSource_AddRef(clock
->time_source
);
3862 if (SUCCEEDED(IMFPresentationTimeSource_GetUnderlyingClock(time_source
, &source_clock
)))
3864 if (SUCCEEDED(IMFClock_GetProperties(source_clock
, &props
)))
3865 clock
->frequency
= props
.qwClockFrequency
;
3866 IMFClock_Release(source_clock
);
3869 if (!clock
->frequency
)
3870 clock
->frequency
= MFCLOCK_FREQUENCY_HNS
;
3872 LeaveCriticalSection(&clock
->cs
);
3877 static HRESULT WINAPI
present_clock_GetTimeSource(IMFPresentationClock
*iface
,
3878 IMFPresentationTimeSource
**time_source
)
3880 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3883 TRACE("%p, %p.\n", iface
, time_source
);
3886 return E_INVALIDARG
;
3888 EnterCriticalSection(&clock
->cs
);
3889 if (clock
->time_source
)
3891 *time_source
= clock
->time_source
;
3892 IMFPresentationTimeSource_AddRef(*time_source
);
3895 hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3896 LeaveCriticalSection(&clock
->cs
);
3901 static HRESULT WINAPI
present_clock_GetTime(IMFPresentationClock
*iface
, MFTIME
*time
)
3903 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3904 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3907 TRACE("%p, %p.\n", iface
, time
);
3912 EnterCriticalSection(&clock
->cs
);
3913 if (clock
->time_source
)
3914 hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, 0, time
, &systime
);
3915 LeaveCriticalSection(&clock
->cs
);
3920 static HRESULT WINAPI
present_clock_AddClockStateSink(IMFPresentationClock
*iface
, IMFClockStateSink
*state_sink
)
3922 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3923 struct clock_sink
*sink
, *cur
;
3926 TRACE("%p, %p.\n", iface
, state_sink
);
3929 return E_INVALIDARG
;
3931 sink
= heap_alloc(sizeof(*sink
));
3933 return E_OUTOFMEMORY
;
3935 sink
->state_sink
= state_sink
;
3936 IMFClockStateSink_AddRef(sink
->state_sink
);
3938 EnterCriticalSection(&clock
->cs
);
3939 LIST_FOR_EACH_ENTRY(cur
, &clock
->sinks
, struct clock_sink
, entry
)
3941 if (cur
->state_sink
== state_sink
)
3949 static const enum clock_notification notifications
[MFCLOCK_STATE_PAUSED
+ 1] =
3951 /* MFCLOCK_STATE_INVALID */ 0, /* Does not apply */
3952 /* MFCLOCK_STATE_RUNNING */ CLOCK_NOTIFY_START
,
3953 /* MFCLOCK_STATE_STOPPED */ CLOCK_NOTIFY_STOP
,
3954 /* MFCLOCK_STATE_PAUSED */ CLOCK_NOTIFY_PAUSE
,
3956 struct clock_state_change_param param
;
3958 if (!clock
->is_shut_down
&& clock
->state
!= MFCLOCK_STATE_INVALID
)
3960 param
.u
.offset
= clock
->start_offset
;
3961 clock_notify_async_sink(clock
, MFGetSystemTime(), param
, notifications
[clock
->state
], sink
->state_sink
);
3964 list_add_tail(&clock
->sinks
, &sink
->entry
);
3966 LeaveCriticalSection(&clock
->cs
);
3970 IMFClockStateSink_Release(sink
->state_sink
);
3977 static HRESULT WINAPI
present_clock_RemoveClockStateSink(IMFPresentationClock
*iface
,
3978 IMFClockStateSink
*state_sink
)
3980 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3981 struct clock_sink
*sink
;
3983 TRACE("%p, %p.\n", iface
, state_sink
);
3986 return E_INVALIDARG
;
3988 EnterCriticalSection(&clock
->cs
);
3989 LIST_FOR_EACH_ENTRY(sink
, &clock
->sinks
, struct clock_sink
, entry
)
3991 if (sink
->state_sink
== state_sink
)
3993 IMFClockStateSink_Release(sink
->state_sink
);
3994 list_remove(&sink
->entry
);
3999 LeaveCriticalSection(&clock
->cs
);
4004 static HRESULT
clock_call_state_change(MFTIME system_time
, struct clock_state_change_param param
,
4005 enum clock_notification notification
, IMFClockStateSink
*sink
)
4009 switch (notification
)
4011 case CLOCK_NOTIFY_START
:
4012 hr
= IMFClockStateSink_OnClockStart(sink
, system_time
, param
.u
.offset
);
4014 case CLOCK_NOTIFY_STOP
:
4015 hr
= IMFClockStateSink_OnClockStop(sink
, system_time
);
4017 case CLOCK_NOTIFY_PAUSE
:
4018 hr
= IMFClockStateSink_OnClockPause(sink
, system_time
);
4020 case CLOCK_NOTIFY_RESTART
:
4021 hr
= IMFClockStateSink_OnClockRestart(sink
, system_time
);
4023 case CLOCK_NOTIFY_SET_RATE
:
4024 /* System time source does not allow 0.0 rate, presentation clock allows it without raising errors. */
4025 IMFClockStateSink_OnClockSetRate(sink
, system_time
, param
.u
.rate
);
4034 static HRESULT
clock_change_state(struct presentation_clock
*clock
, enum clock_command command
,
4035 struct clock_state_change_param param
)
4037 static const BYTE state_change_is_allowed
[MFCLOCK_STATE_PAUSED
+1][CLOCK_CMD_MAX
] =
4039 /* INVALID */ { 1, 1, 1, 1 },
4040 /* RUNNING */ { 1, 1, 1, 1 },
4041 /* STOPPED */ { 1, 1, 0, 1 },
4042 /* PAUSED */ { 1, 1, 0, 1 },
4044 static const MFCLOCK_STATE states
[CLOCK_CMD_MAX
] =
4046 /* CLOCK_CMD_START */ MFCLOCK_STATE_RUNNING
,
4047 /* CLOCK_CMD_STOP */ MFCLOCK_STATE_STOPPED
,
4048 /* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED
,
4049 /* CLOCK_CMD_SET_RATE */ 0, /* Unused */
4051 static const enum clock_notification notifications
[CLOCK_CMD_MAX
] =
4053 /* CLOCK_CMD_START */ CLOCK_NOTIFY_START
,
4054 /* CLOCK_CMD_STOP */ CLOCK_NOTIFY_STOP
,
4055 /* CLOCK_CMD_PAUSE */ CLOCK_NOTIFY_PAUSE
,
4056 /* CLOCK_CMD_SET_RATE */ CLOCK_NOTIFY_SET_RATE
,
4058 enum clock_notification notification
;
4059 struct clock_sink
*sink
;
4060 MFCLOCK_STATE old_state
;
4061 IMFAsyncResult
*result
;
4065 if (!clock
->time_source
)
4066 return MF_E_CLOCK_NO_TIME_SOURCE
;
4068 if (command
!= CLOCK_CMD_SET_RATE
&& clock
->state
== states
[command
] && clock
->state
!= MFCLOCK_STATE_RUNNING
)
4069 return MF_E_CLOCK_STATE_ALREADY_SET
;
4071 if (!state_change_is_allowed
[clock
->state
][command
])
4072 return MF_E_INVALIDREQUEST
;
4074 system_time
= MFGetSystemTime();
4076 if (command
== CLOCK_CMD_START
&& clock
->state
== MFCLOCK_STATE_PAUSED
&&
4077 param
.u
.offset
== PRESENTATION_CURRENT_POSITION
)
4079 notification
= CLOCK_NOTIFY_RESTART
;
4082 notification
= notifications
[command
];
4084 if (FAILED(hr
= clock_call_state_change(system_time
, param
, notification
, clock
->time_source_sink
)))
4087 old_state
= clock
->state
;
4088 if (command
!= CLOCK_CMD_SET_RATE
)
4089 clock
->state
= states
[command
];
4091 /* Dump all pending timer requests immediately on start; otherwise try to cancel scheduled items when
4092 transitioning from running state. */
4093 if ((clock
->state
== MFCLOCK_STATE_RUNNING
) ^ (old_state
== MFCLOCK_STATE_RUNNING
))
4095 struct clock_timer
*timer
, *timer2
;
4097 if (clock
->state
== MFCLOCK_STATE_RUNNING
)
4099 LIST_FOR_EACH_ENTRY_SAFE(timer
, timer2
, &clock
->timers
, struct clock_timer
, entry
)
4101 list_remove(&timer
->entry
);
4102 hr
= MFCreateAsyncResult(&timer
->IUnknown_iface
, &clock
->timer_callback
, NULL
, &result
);
4103 IUnknown_Release(&timer
->IUnknown_iface
);
4106 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_TIMER
, result
);
4107 IMFAsyncResult_Release(result
);
4113 LIST_FOR_EACH_ENTRY(timer
, &clock
->timers
, struct clock_timer
, entry
)
4117 MFCancelWorkItem(timer
->key
);
4124 LIST_FOR_EACH_ENTRY(sink
, &clock
->sinks
, struct clock_sink
, entry
)
4126 clock_notify_async_sink(clock
, system_time
, param
, notification
, sink
->state_sink
);
4132 static HRESULT WINAPI
present_clock_Start(IMFPresentationClock
*iface
, LONGLONG start_offset
)
4134 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4135 struct clock_state_change_param param
= {{0}};
4138 TRACE("%p, %s.\n", iface
, debugstr_time(start_offset
));
4140 EnterCriticalSection(&clock
->cs
);
4141 clock
->start_offset
= param
.u
.offset
= start_offset
;
4142 hr
= clock_change_state(clock
, CLOCK_CMD_START
, param
);
4143 LeaveCriticalSection(&clock
->cs
);
4148 static HRESULT WINAPI
present_clock_Stop(IMFPresentationClock
*iface
)
4150 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4151 struct clock_state_change_param param
= {{0}};
4154 TRACE("%p.\n", iface
);
4156 EnterCriticalSection(&clock
->cs
);
4157 hr
= clock_change_state(clock
, CLOCK_CMD_STOP
, param
);
4158 LeaveCriticalSection(&clock
->cs
);
4163 static HRESULT WINAPI
present_clock_Pause(IMFPresentationClock
*iface
)
4165 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4166 struct clock_state_change_param param
= {{0}};
4169 TRACE("%p.\n", iface
);
4171 EnterCriticalSection(&clock
->cs
);
4172 hr
= clock_change_state(clock
, CLOCK_CMD_PAUSE
, param
);
4173 LeaveCriticalSection(&clock
->cs
);
4178 static const IMFPresentationClockVtbl presentationclockvtbl
=
4180 present_clock_QueryInterface
,
4181 present_clock_AddRef
,
4182 present_clock_Release
,
4183 present_clock_GetClockCharacteristics
,
4184 present_clock_GetCorrelatedTime
,
4185 present_clock_GetContinuityKey
,
4186 present_clock_GetState
,
4187 present_clock_GetProperties
,
4188 present_clock_SetTimeSource
,
4189 present_clock_GetTimeSource
,
4190 present_clock_GetTime
,
4191 present_clock_AddClockStateSink
,
4192 present_clock_RemoveClockStateSink
,
4193 present_clock_Start
,
4195 present_clock_Pause
,
4198 static HRESULT WINAPI
present_clock_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **out
)
4200 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4201 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
4204 static ULONG WINAPI
present_clock_rate_control_AddRef(IMFRateControl
*iface
)
4206 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4207 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4210 static ULONG WINAPI
present_clock_rate_control_Release(IMFRateControl
*iface
)
4212 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4213 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4216 static HRESULT WINAPI
present_clock_rate_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
4218 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4219 struct clock_state_change_param param
;
4222 TRACE("%p, %d, %f.\n", iface
, thin
, rate
);
4225 return MF_E_THINNING_UNSUPPORTED
;
4227 EnterCriticalSection(&clock
->cs
);
4228 param
.u
.rate
= rate
;
4229 if (SUCCEEDED(hr
= clock_change_state(clock
, CLOCK_CMD_SET_RATE
, param
)))
4231 LeaveCriticalSection(&clock
->cs
);
4236 static HRESULT WINAPI
present_clock_rate_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
4238 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4240 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
4243 return E_INVALIDARG
;
4248 EnterCriticalSection(&clock
->cs
);
4249 *rate
= clock
->rate
;
4250 LeaveCriticalSection(&clock
->cs
);
4255 static const IMFRateControlVtbl presentclockratecontrolvtbl
=
4257 present_clock_rate_control_QueryInterface
,
4258 present_clock_rate_control_AddRef
,
4259 present_clock_rate_control_Release
,
4260 present_clock_rate_SetRate
,
4261 present_clock_rate_GetRate
,
4264 static HRESULT WINAPI
present_clock_timer_QueryInterface(IMFTimer
*iface
, REFIID riid
, void **out
)
4266 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4267 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
4270 static ULONG WINAPI
present_clock_timer_AddRef(IMFTimer
*iface
)
4272 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4273 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4276 static ULONG WINAPI
present_clock_timer_Release(IMFTimer
*iface
)
4278 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4279 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4282 static HRESULT
present_clock_schedule_timer(struct presentation_clock
*clock
, DWORD flags
, LONGLONG time
,
4283 struct clock_timer
*timer
)
4285 IMFAsyncResult
*result
;
4286 MFTIME systime
, clocktime
;
4290 if (!(flags
& MFTIMER_RELATIVE
))
4292 if (FAILED(hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, 0, &clocktime
, &systime
)))
4294 WARN("Failed to get clock time, hr %#x.\n", hr
);
4300 frequency
= clock
->frequency
/ 1000;
4303 /* Scheduled item is using clock instance callback, with timer instance as an object. Clock callback will
4304 call user callback and cleanup timer list. */
4306 if (FAILED(hr
= MFCreateAsyncResult(&timer
->IUnknown_iface
, &clock
->timer_callback
, NULL
, &result
)))
4309 hr
= MFScheduleWorkItemEx(result
, -time
, &timer
->key
);
4310 IMFAsyncResult_Release(result
);
4315 static HRESULT WINAPI
clock_timer_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
4317 if (IsEqualIID(riid
, &IID_IUnknown
))
4320 IUnknown_AddRef(iface
);
4325 return E_NOINTERFACE
;
4328 static ULONG WINAPI
clock_timer_AddRef(IUnknown
*iface
)
4330 struct clock_timer
*timer
= impl_clock_timer_from_IUnknown(iface
);
4331 return InterlockedIncrement(&timer
->refcount
);
4334 static ULONG WINAPI
clock_timer_Release(IUnknown
*iface
)
4336 struct clock_timer
*timer
= impl_clock_timer_from_IUnknown(iface
);
4337 ULONG refcount
= InterlockedDecrement(&timer
->refcount
);
4341 IMFAsyncResult_Release(timer
->result
);
4342 IMFAsyncCallback_Release(timer
->callback
);
4349 static const IUnknownVtbl clock_timer_vtbl
=
4351 clock_timer_QueryInterface
,
4353 clock_timer_Release
,
4356 static HRESULT WINAPI
present_clock_timer_SetTimer(IMFTimer
*iface
, DWORD flags
, LONGLONG time
,
4357 IMFAsyncCallback
*callback
, IUnknown
*state
, IUnknown
**cancel_key
)
4359 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4360 struct clock_timer
*clock_timer
;
4363 TRACE("%p, %#x, %s, %p, %p, %p.\n", iface
, flags
, debugstr_time(time
), callback
, state
, cancel_key
);
4365 if (!(clock_timer
= heap_alloc_zero(sizeof(*clock_timer
))))
4366 return E_OUTOFMEMORY
;
4368 if (FAILED(hr
= MFCreateAsyncResult(NULL
, NULL
, state
, &clock_timer
->result
)))
4370 heap_free(clock_timer
);
4374 clock_timer
->IUnknown_iface
.lpVtbl
= &clock_timer_vtbl
;
4375 clock_timer
->refcount
= 1;
4376 clock_timer
->callback
= callback
;
4377 IMFAsyncCallback_AddRef(clock_timer
->callback
);
4379 EnterCriticalSection(&clock
->cs
);
4381 if (clock
->state
== MFCLOCK_STATE_RUNNING
)
4382 hr
= present_clock_schedule_timer(clock
, flags
, time
, clock_timer
);
4383 else if (clock
->state
== MFCLOCK_STATE_STOPPED
)
4384 hr
= MF_S_CLOCK_STOPPED
;
4388 list_add_tail(&clock
->timers
, &clock_timer
->entry
);
4391 *cancel_key
= &clock_timer
->IUnknown_iface
;
4392 IUnknown_AddRef(*cancel_key
);
4396 LeaveCriticalSection(&clock
->cs
);
4399 IUnknown_Release(&clock_timer
->IUnknown_iface
);
4404 static HRESULT WINAPI
present_clock_timer_CancelTimer(IMFTimer
*iface
, IUnknown
*cancel_key
)
4406 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4407 struct clock_timer
*timer
;
4409 TRACE("%p, %p.\n", iface
, cancel_key
);
4411 EnterCriticalSection(&clock
->cs
);
4413 LIST_FOR_EACH_ENTRY(timer
, &clock
->timers
, struct clock_timer
, entry
)
4415 if (&timer
->IUnknown_iface
== cancel_key
)
4417 list_remove(&timer
->entry
);
4420 MFCancelWorkItem(timer
->key
);
4423 IUnknown_Release(&timer
->IUnknown_iface
);
4428 LeaveCriticalSection(&clock
->cs
);
4433 static const IMFTimerVtbl presentclocktimervtbl
=
4435 present_clock_timer_QueryInterface
,
4436 present_clock_timer_AddRef
,
4437 present_clock_timer_Release
,
4438 present_clock_timer_SetTimer
,
4439 present_clock_timer_CancelTimer
,
4442 static HRESULT WINAPI
present_clock_shutdown_QueryInterface(IMFShutdown
*iface
, REFIID riid
, void **out
)
4444 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4445 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
4448 static ULONG WINAPI
present_clock_shutdown_AddRef(IMFShutdown
*iface
)
4450 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4451 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4454 static ULONG WINAPI
present_clock_shutdown_Release(IMFShutdown
*iface
)
4456 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4457 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4460 static HRESULT WINAPI
present_clock_shutdown_Shutdown(IMFShutdown
*iface
)
4462 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4464 TRACE("%p.\n", iface
);
4466 EnterCriticalSection(&clock
->cs
);
4467 clock
->is_shut_down
= TRUE
;
4468 LeaveCriticalSection(&clock
->cs
);
4473 static HRESULT WINAPI
present_clock_shutdown_GetShutdownStatus(IMFShutdown
*iface
, MFSHUTDOWN_STATUS
*status
)
4475 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4478 TRACE("%p, %p.\n", iface
, status
);
4481 return E_INVALIDARG
;
4483 EnterCriticalSection(&clock
->cs
);
4484 if (clock
->is_shut_down
)
4485 *status
= MFSHUTDOWN_COMPLETED
;
4487 hr
= MF_E_INVALIDREQUEST
;
4488 LeaveCriticalSection(&clock
->cs
);
4493 static const IMFShutdownVtbl presentclockshutdownvtbl
=
4495 present_clock_shutdown_QueryInterface
,
4496 present_clock_shutdown_AddRef
,
4497 present_clock_shutdown_Release
,
4498 present_clock_shutdown_Shutdown
,
4499 present_clock_shutdown_GetShutdownStatus
,
4502 static HRESULT WINAPI
present_clock_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **out
)
4504 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
4505 IsEqualIID(riid
, &IID_IUnknown
))
4508 IMFAsyncCallback_AddRef(iface
);
4512 WARN("Unsupported %s.\n", wine_dbgstr_guid(riid
));
4514 return E_NOINTERFACE
;
4517 static ULONG WINAPI
present_clock_sink_callback_AddRef(IMFAsyncCallback
*iface
)
4519 struct presentation_clock
*clock
= impl_from_sink_callback_IMFAsyncCallback(iface
);
4520 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4523 static ULONG WINAPI
present_clock_sink_callback_Release(IMFAsyncCallback
*iface
)
4525 struct presentation_clock
*clock
= impl_from_sink_callback_IMFAsyncCallback(iface
);
4526 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4529 static HRESULT WINAPI
present_clock_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
4534 static HRESULT WINAPI
present_clock_sink_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
4536 struct sink_notification
*data
;
4540 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &object
)))
4543 data
= impl_sink_notification_from_IUnknown(object
);
4545 clock_call_state_change(data
->system_time
, data
->param
, data
->notification
, data
->sink
);
4547 IUnknown_Release(object
);
4552 static const IMFAsyncCallbackVtbl presentclocksinkcallbackvtbl
=
4554 present_clock_callback_QueryInterface
,
4555 present_clock_sink_callback_AddRef
,
4556 present_clock_sink_callback_Release
,
4557 present_clock_callback_GetParameters
,
4558 present_clock_sink_callback_Invoke
,
4561 static ULONG WINAPI
present_clock_timer_callback_AddRef(IMFAsyncCallback
*iface
)
4563 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
4564 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4567 static ULONG WINAPI
present_clock_timer_callback_Release(IMFAsyncCallback
*iface
)
4569 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
4570 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4573 static HRESULT WINAPI
present_clock_timer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
4575 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
4576 struct clock_timer
*timer
;
4580 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &object
)))
4583 timer
= impl_clock_timer_from_IUnknown(object
);
4585 EnterCriticalSection(&clock
->cs
);
4586 list_remove(&timer
->entry
);
4587 IUnknown_Release(&timer
->IUnknown_iface
);
4588 LeaveCriticalSection(&clock
->cs
);
4590 IMFAsyncCallback_Invoke(timer
->callback
, timer
->result
);
4592 IUnknown_Release(object
);
4597 static const IMFAsyncCallbackVtbl presentclocktimercallbackvtbl
=
4599 present_clock_callback_QueryInterface
,
4600 present_clock_timer_callback_AddRef
,
4601 present_clock_timer_callback_Release
,
4602 present_clock_callback_GetParameters
,
4603 present_clock_timer_callback_Invoke
,
4606 /***********************************************************************
4607 * MFCreatePresentationClock (mf.@)
4609 HRESULT WINAPI
MFCreatePresentationClock(IMFPresentationClock
**clock
)
4611 struct presentation_clock
*object
;
4613 TRACE("%p.\n", clock
);
4615 object
= heap_alloc_zero(sizeof(*object
));
4617 return E_OUTOFMEMORY
;
4619 object
->IMFPresentationClock_iface
.lpVtbl
= &presentationclockvtbl
;
4620 object
->IMFRateControl_iface
.lpVtbl
= &presentclockratecontrolvtbl
;
4621 object
->IMFTimer_iface
.lpVtbl
= &presentclocktimervtbl
;
4622 object
->IMFShutdown_iface
.lpVtbl
= &presentclockshutdownvtbl
;
4623 object
->sink_callback
.lpVtbl
= &presentclocksinkcallbackvtbl
;
4624 object
->timer_callback
.lpVtbl
= &presentclocktimercallbackvtbl
;
4625 object
->refcount
= 1;
4626 list_init(&object
->sinks
);
4627 list_init(&object
->timers
);
4628 object
->rate
= 1.0f
;
4629 InitializeCriticalSection(&object
->cs
);
4631 *clock
= &object
->IMFPresentationClock_iface
;
4636 static HRESULT WINAPI
standard_quality_manager_QueryInterface(IMFQualityManager
*iface
, REFIID riid
, void **out
)
4638 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
4640 if (IsEqualIID(riid
, &IID_IMFQualityManager
) ||
4641 IsEqualIID(riid
, &IID_IUnknown
))
4644 IMFQualityManager_AddRef(iface
);
4648 WARN("Unsupported %s.\n", debugstr_guid(riid
));
4650 return E_NOINTERFACE
;
4653 static ULONG WINAPI
standard_quality_manager_AddRef(IMFQualityManager
*iface
)
4655 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
4656 ULONG refcount
= InterlockedIncrement(&manager
->refcount
);
4658 TRACE("%p, refcount %u.\n", iface
, refcount
);
4663 static ULONG WINAPI
standard_quality_manager_Release(IMFQualityManager
*iface
)
4665 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
4666 ULONG refcount
= InterlockedDecrement(&manager
->refcount
);
4668 TRACE("%p, refcount %u.\n", iface
, refcount
);
4673 IMFPresentationClock_Release(manager
->clock
);
4674 DeleteCriticalSection(&manager
->cs
);
4681 static HRESULT WINAPI
standard_quality_manager_NotifyTopology(IMFQualityManager
*iface
, IMFTopology
*topology
)
4683 FIXME("%p, %p stub.\n", iface
, topology
);
4688 static HRESULT WINAPI
standard_quality_manager_NotifyPresentationClock(IMFQualityManager
*iface
,
4689 IMFPresentationClock
*clock
)
4691 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
4693 TRACE("%p, %p.\n", iface
, clock
);
4698 EnterCriticalSection(&manager
->cs
);
4700 IMFPresentationClock_Release(manager
->clock
);
4701 manager
->clock
= clock
;
4702 IMFPresentationClock_AddRef(manager
->clock
);
4703 LeaveCriticalSection(&manager
->cs
);
4708 static HRESULT WINAPI
standard_quality_manager_NotifyProcessInput(IMFQualityManager
*iface
, IMFTopologyNode
*node
,
4709 LONG input_index
, IMFSample
*sample
)
4711 TRACE("%p, %p, %d, %p stub.\n", iface
, node
, input_index
, sample
);
4716 static HRESULT WINAPI
standard_quality_manager_NotifyProcessOutput(IMFQualityManager
*iface
, IMFTopologyNode
*node
,
4717 LONG output_index
, IMFSample
*sample
)
4719 TRACE("%p, %p, %d, %p stub.\n", iface
, node
, output_index
, sample
);
4724 static HRESULT WINAPI
standard_quality_manager_NotifyQualityEvent(IMFQualityManager
*iface
, IUnknown
*object
,
4725 IMFMediaEvent
*event
)
4727 FIXME("%p, %p, %p stub.\n", iface
, object
, event
);
4732 static HRESULT WINAPI
standard_quality_manager_Shutdown(IMFQualityManager
*iface
)
4734 FIXME("%p stub.\n", iface
);
4739 static IMFQualityManagerVtbl standard_quality_manager_vtbl
=
4741 standard_quality_manager_QueryInterface
,
4742 standard_quality_manager_AddRef
,
4743 standard_quality_manager_Release
,
4744 standard_quality_manager_NotifyTopology
,
4745 standard_quality_manager_NotifyPresentationClock
,
4746 standard_quality_manager_NotifyProcessInput
,
4747 standard_quality_manager_NotifyProcessOutput
,
4748 standard_quality_manager_NotifyQualityEvent
,
4749 standard_quality_manager_Shutdown
,
4752 HRESULT WINAPI
MFCreateStandardQualityManager(IMFQualityManager
**manager
)
4754 struct quality_manager
*object
;
4756 TRACE("%p.\n", manager
);
4758 object
= heap_alloc_zero(sizeof(*object
));
4760 return E_OUTOFMEMORY
;
4762 object
->IMFQualityManager_iface
.lpVtbl
= &standard_quality_manager_vtbl
;
4763 object
->refcount
= 1;
4764 InitializeCriticalSection(&object
->cs
);
4766 *manager
= &object
->IMFQualityManager_iface
;