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"
37 DEFINE_GUID(_MF_TOPONODE_IMFActivate
, 0x33706f4a, 0x309a, 0x49be, 0xa8, 0xdd, 0xe7, 0xc0, 0x87, 0x5e, 0xb6, 0x79);
39 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
43 SESSION_CMD_CLEAR_TOPOLOGIES
,
45 SESSION_CMD_SET_TOPOLOGY
,
49 /* Internally used commands. */
51 SESSION_CMD_QM_NOTIFY_TOPOLOGY
,
57 IUnknown IUnknown_iface
;
59 enum session_command command
;
65 IMFTopology
*topology
;
70 PROPVARIANT start_position
;
74 IMFTopology
*topology
;
84 struct queued_topology
87 IMFTopology
*topology
;
93 SESSION_STATE_STOPPED
= 0,
94 SESSION_STATE_STARTING_SOURCES
,
95 SESSION_STATE_PREROLLING_SINKS
,
96 SESSION_STATE_STARTING_SINKS
,
97 SESSION_STATE_STARTED
,
98 SESSION_STATE_PAUSING_SINKS
,
99 SESSION_STATE_PAUSING_SOURCES
,
100 SESSION_STATE_PAUSED
,
101 SESSION_STATE_STOPPING_SINKS
,
102 SESSION_STATE_STOPPING_SOURCES
,
103 SESSION_STATE_FINALIZING_SINKS
,
104 SESSION_STATE_CLOSED
,
105 SESSION_STATE_SHUT_DOWN
,
110 OBJ_STATE_STOPPED
= 0,
117 enum media_source_flags
119 SOURCE_FLAG_END_OF_PRESENTATION
= 0x1,
125 IMFMediaSource
*source
;
126 IMFPresentationDescriptor
*pd
;
127 enum object_state state
;
135 IMFMediaSinkPreroll
*preroll
;
136 IMFMediaEventGenerator
*event_generator
;
146 struct transform_stream
149 unsigned int requests
;
154 TOPO_NODE_END_OF_STREAM
= 0x1,
160 struct media_session
*session
;
161 MF_TOPOLOGY_TYPE type
;
163 IMFTopologyNode
*node
;
164 enum object_state state
;
168 IMFMediaStream
*source_stream
;
169 IMFStreamSink
*sink_stream
;
170 IMFTransform
*transform
;
178 IMFMediaSource
*source
;
179 unsigned int stream_id
;
183 unsigned int requests
;
184 IMFVideoSampleAllocatorNotify notify_cb
;
185 IMFVideoSampleAllocator
*allocator
;
186 IMFVideoSampleAllocatorCallback
*allocator_cb
;
190 struct transform_stream
*inputs
;
191 unsigned int *input_map
;
192 unsigned int input_count
;
194 struct transform_stream
*outputs
;
195 unsigned int *output_map
;
196 unsigned int output_count
;
201 enum presentation_flags
203 SESSION_FLAG_SOURCES_SUBSCRIBED
= 0x1,
204 SESSION_FLAG_PRESENTATION_CLOCK_SET
= 0x2,
205 SESSION_FLAG_FINALIZE_SINKS
= 0x4,
206 SESSION_FLAG_NEEDS_PREROLL
= 0x8,
207 SESSION_FLAG_END_OF_PRESENTATION
= 0x10,
212 IMFMediaSession IMFMediaSession_iface
;
213 IMFGetService IMFGetService_iface
;
214 IMFRateSupport IMFRateSupport_iface
;
215 IMFRateControl IMFRateControl_iface
;
216 IMFTopologyNodeAttributeEditor IMFTopologyNodeAttributeEditor_iface
;
217 IMFAsyncCallback commands_callback
;
218 IMFAsyncCallback events_callback
;
219 IMFAsyncCallback sink_finalizer_callback
;
221 IMFMediaEventQueue
*event_queue
;
222 IMFPresentationClock
*clock
;
223 IMFPresentationTimeSource
*system_time_source
;
224 IMFRateControl
*clock_rate_control
;
225 IMFTopoLoader
*topo_loader
;
226 IMFQualityManager
*quality_manager
;
229 IMFTopology
*current_topology
;
230 MF_TOPOSTATUS topo_status
;
231 MFTIME clock_stop_time
;
237 /* Latest Start() arguments. */
239 PROPVARIANT start_position
;
241 struct list topologies
;
242 struct list commands
;
243 enum session_state state
;
251 IMFClockStateSink
*state_sink
;
263 enum clock_notification
268 CLOCK_NOTIFY_RESTART
,
269 CLOCK_NOTIFY_SET_RATE
,
272 struct clock_state_change_param
281 struct sink_notification
283 IUnknown IUnknown_iface
;
286 struct clock_state_change_param param
;
287 enum clock_notification notification
;
288 IMFClockStateSink
*sink
;
293 IUnknown IUnknown_iface
;
295 IMFAsyncResult
*result
;
296 IMFAsyncCallback
*callback
;
301 struct presentation_clock
303 IMFPresentationClock IMFPresentationClock_iface
;
304 IMFRateControl IMFRateControl_iface
;
305 IMFTimer IMFTimer_iface
;
306 IMFShutdown IMFShutdown_iface
;
307 IMFAsyncCallback sink_callback
;
308 IMFAsyncCallback timer_callback
;
310 IMFPresentationTimeSource
*time_source
;
311 IMFClockStateSink
*time_source_sink
;
313 LONGLONG start_offset
;
322 struct quality_manager
324 IMFQualityManager IMFQualityManager_iface
;
327 IMFPresentationClock
*clock
;
331 static inline struct media_session
*impl_from_IMFMediaSession(IMFMediaSession
*iface
)
333 return CONTAINING_RECORD(iface
, struct media_session
, IMFMediaSession_iface
);
336 static struct media_session
*impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
338 return CONTAINING_RECORD(iface
, struct media_session
, commands_callback
);
341 static struct media_session
*impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
343 return CONTAINING_RECORD(iface
, struct media_session
, events_callback
);
346 static struct media_session
*impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
348 return CONTAINING_RECORD(iface
, struct media_session
, sink_finalizer_callback
);
351 static struct media_session
*impl_from_IMFGetService(IMFGetService
*iface
)
353 return CONTAINING_RECORD(iface
, struct media_session
, IMFGetService_iface
);
356 static struct media_session
*impl_session_from_IMFRateSupport(IMFRateSupport
*iface
)
358 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateSupport_iface
);
361 static struct media_session
*impl_session_from_IMFRateControl(IMFRateControl
*iface
)
363 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateControl_iface
);
366 static struct media_session
*impl_session_from_IMFTopologyNodeAttributeEditor(IMFTopologyNodeAttributeEditor
*iface
)
368 return CONTAINING_RECORD(iface
, struct media_session
, IMFTopologyNodeAttributeEditor_iface
);
371 static struct session_op
*impl_op_from_IUnknown(IUnknown
*iface
)
373 return CONTAINING_RECORD(iface
, struct session_op
, IUnknown_iface
);
376 static struct presentation_clock
*impl_from_IMFPresentationClock(IMFPresentationClock
*iface
)
378 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFPresentationClock_iface
);
381 static struct presentation_clock
*impl_from_IMFRateControl(IMFRateControl
*iface
)
383 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFRateControl_iface
);
386 static struct presentation_clock
*impl_from_IMFTimer(IMFTimer
*iface
)
388 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFTimer_iface
);
391 static struct presentation_clock
*impl_from_IMFShutdown(IMFShutdown
*iface
)
393 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFShutdown_iface
);
396 static struct presentation_clock
*impl_from_sink_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
398 return CONTAINING_RECORD(iface
, struct presentation_clock
, sink_callback
);
401 static struct presentation_clock
*impl_from_timer_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
403 return CONTAINING_RECORD(iface
, struct presentation_clock
, timer_callback
);
406 static struct clock_timer
*impl_clock_timer_from_IUnknown(IUnknown
*iface
)
408 return CONTAINING_RECORD(iface
, struct clock_timer
, IUnknown_iface
);
411 static struct sink_notification
*impl_sink_notification_from_IUnknown(IUnknown
*iface
)
413 return CONTAINING_RECORD(iface
, struct sink_notification
, IUnknown_iface
);
416 static struct quality_manager
*impl_from_IMFQualityManager(IMFQualityManager
*iface
)
418 return CONTAINING_RECORD(iface
, struct quality_manager
, IMFQualityManager_iface
);
421 static struct topo_node
*impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify
*iface
)
423 return CONTAINING_RECORD(iface
, struct topo_node
, u
.sink
.notify_cb
);
426 /* IMFLocalMFTRegistration */
427 static HRESULT WINAPI
local_mft_registration_QueryInterface(IMFLocalMFTRegistration
*iface
, REFIID riid
, void **obj
)
429 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
431 if (IsEqualIID(riid
, &IID_IMFLocalMFTRegistration
) ||
432 IsEqualIID(riid
, &IID_IUnknown
))
435 IMFLocalMFTRegistration_AddRef(iface
);
439 WARN("Unexpected %s.\n", debugstr_guid(riid
));
441 return E_NOINTERFACE
;
444 static ULONG WINAPI
local_mft_registration_AddRef(IMFLocalMFTRegistration
*iface
)
449 static ULONG WINAPI
local_mft_registration_Release(IMFLocalMFTRegistration
*iface
)
454 static HRESULT WINAPI
local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration
*iface
, MFT_REGISTRATION_INFO
*info
,
460 TRACE("%p, %p, %u.\n", iface
, info
, count
);
462 for (i
= 0; i
< count
; ++i
)
464 if (FAILED(hr
= MFTRegisterLocalByCLSID(&info
[i
].clsid
, &info
[i
].guidCategory
, info
[i
].pszName
,
465 info
[i
].uiFlags
, info
[i
].cInTypes
, info
[i
].pInTypes
, info
[i
].cOutTypes
, info
[i
].pOutTypes
)))
474 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl
=
476 local_mft_registration_QueryInterface
,
477 local_mft_registration_AddRef
,
478 local_mft_registration_Release
,
479 local_mft_registration_RegisterMFTs
,
482 static IMFLocalMFTRegistration local_mft_registration
= { &local_mft_registration_vtbl
};
484 static HRESULT WINAPI
session_op_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
486 if (IsEqualIID(riid
, &IID_IUnknown
))
489 IUnknown_AddRef(iface
);
494 return E_NOINTERFACE
;
497 static ULONG WINAPI
session_op_AddRef(IUnknown
*iface
)
499 struct session_op
*op
= impl_op_from_IUnknown(iface
);
500 ULONG refcount
= InterlockedIncrement(&op
->refcount
);
502 TRACE("%p, refcount %u.\n", iface
, refcount
);
507 static ULONG WINAPI
session_op_Release(IUnknown
*iface
)
509 struct session_op
*op
= impl_op_from_IUnknown(iface
);
510 ULONG refcount
= InterlockedDecrement(&op
->refcount
);
512 TRACE("%p, refcount %u.\n", iface
, refcount
);
518 case SESSION_CMD_SET_TOPOLOGY
:
519 if (op
->u
.set_topology
.topology
)
520 IMFTopology_Release(op
->u
.set_topology
.topology
);
522 case SESSION_CMD_START
:
523 PropVariantClear(&op
->u
.start
.start_position
);
525 case SESSION_CMD_QM_NOTIFY_TOPOLOGY
:
526 if (op
->u
.notify_topology
.topology
)
527 IMFTopology_Release(op
->u
.notify_topology
.topology
);
538 static IUnknownVtbl session_op_vtbl
=
540 session_op_QueryInterface
,
545 static HRESULT
create_session_op(enum session_command command
, struct session_op
**ret
)
547 struct session_op
*op
;
549 if (!(op
= heap_alloc_zero(sizeof(*op
))))
550 return E_OUTOFMEMORY
;
552 op
->IUnknown_iface
.lpVtbl
= &session_op_vtbl
;
554 op
->command
= command
;
561 static HRESULT
session_is_shut_down(struct media_session
*session
)
563 return session
->state
== SESSION_STATE_SHUT_DOWN
? MF_E_SHUTDOWN
: S_OK
;
566 static void session_push_back_command(struct media_session
*session
, enum session_command command
)
568 struct session_op
*op
;
570 if (SUCCEEDED(create_session_op(command
, &op
)))
571 list_add_head(&session
->commands
, &op
->entry
);
574 static HRESULT
session_submit_command(struct media_session
*session
, struct session_op
*op
)
578 EnterCriticalSection(&session
->cs
);
579 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
581 if (list_empty(&session
->commands
))
582 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
583 list_add_tail(&session
->commands
, &op
->entry
);
584 IUnknown_AddRef(&op
->IUnknown_iface
);
586 LeaveCriticalSection(&session
->cs
);
591 static HRESULT
session_submit_simple_command(struct media_session
*session
, enum session_command command
)
593 struct session_op
*op
;
596 if (FAILED(hr
= create_session_op(command
, &op
)))
599 hr
= session_submit_command(session
, op
);
600 IUnknown_Release(&op
->IUnknown_iface
);
604 static void session_clear_topologies(struct media_session
*session
)
606 struct queued_topology
*ptr
, *next
;
608 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &session
->topologies
, struct queued_topology
, entry
)
610 list_remove(&ptr
->entry
);
611 IMFTopology_Release(ptr
->topology
);
616 static void session_set_topo_status(struct media_session
*session
, HRESULT status
,
617 MF_TOPOSTATUS topo_status
)
619 IMFMediaEvent
*event
;
622 if (topo_status
== MF_TOPOSTATUS_INVALID
)
625 if (list_empty(&session
->topologies
))
627 FIXME("Unexpectedly empty topology queue.\n");
631 if (topo_status
> session
->presentation
.topo_status
)
633 struct queued_topology
*topology
= LIST_ENTRY(list_head(&session
->topologies
), struct queued_topology
, entry
);
635 param
.vt
= VT_UNKNOWN
;
636 param
.punkVal
= (IUnknown
*)topology
->topology
;
638 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus
, &GUID_NULL
, status
, ¶m
, &event
)))
641 session
->presentation
.topo_status
= topo_status
;
643 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_TOPOLOGY_STATUS
, topo_status
);
644 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
645 IMFMediaEvent_Release(event
);
649 static HRESULT
session_bind_output_nodes(IMFTopology
*topology
)
651 MF_TOPOLOGY_TYPE node_type
;
652 IMFStreamSink
*stream_sink
;
653 IMFMediaSink
*media_sink
;
654 WORD node_count
= 0, i
;
655 IMFTopologyNode
*node
;
656 IMFActivate
*activate
;
661 hr
= IMFTopology_GetNodeCount(topology
, &node_count
);
663 for (i
= 0; i
< node_count
; ++i
)
665 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
668 if (FAILED(hr
= IMFTopologyNode_GetNodeType(node
, &node_type
)) || node_type
!= MF_TOPOLOGY_OUTPUT_NODE
)
670 IMFTopologyNode_Release(node
);
674 if (SUCCEEDED(hr
= IMFTopologyNode_GetObject(node
, &object
)))
677 if (FAILED(IUnknown_QueryInterface(object
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
679 if (SUCCEEDED(hr
= IUnknown_QueryInterface(object
, &IID_IMFActivate
, (void **)&activate
)))
681 if (SUCCEEDED(hr
= IMFActivate_ActivateObject(activate
, &IID_IMFMediaSink
, (void **)&media_sink
)))
683 if (FAILED(IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_STREAMID
, &stream_id
)))
687 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink
, stream_id
, &stream_sink
)))
688 hr
= IMFMediaSink_AddStreamSink(media_sink
, stream_id
, NULL
, &stream_sink
);
691 hr
= IMFTopologyNode_SetObject(node
, (IUnknown
*)stream_sink
);
693 IMFMediaSink_Release(media_sink
);
697 IMFTopologyNode_SetUnknown(node
, &_MF_TOPONODE_IMFActivate
, (IUnknown
*)activate
);
699 IMFActivate_Release(activate
);
704 IMFStreamSink_Release(stream_sink
);
705 IUnknown_Release(object
);
708 IMFTopologyNode_Release(node
);
714 static void session_set_caps(struct media_session
*session
, DWORD caps
)
716 DWORD delta
= session
->caps
^ caps
;
717 IMFMediaEvent
*event
;
719 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
720 them to, since session always queries for current object rates. */
724 session
->caps
= caps
;
726 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged
, &GUID_NULL
, S_OK
, NULL
, &event
)))
729 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS
, caps
);
730 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS_DELTA
, delta
);
732 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
733 IMFMediaEvent_Release(event
);
736 static void transform_release_sample(struct sample
*sample
)
738 list_remove(&sample
->entry
);
740 IMFSample_Release(sample
->sample
);
744 static void transform_stream_drop_samples(struct transform_stream
*stream
)
746 struct sample
*sample
, *sample2
;
748 LIST_FOR_EACH_ENTRY_SAFE(sample
, sample2
, &stream
->samples
, struct sample
, entry
)
749 transform_release_sample(sample
);
752 static void release_topo_node(struct topo_node
*node
)
758 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
759 if (node
->u
.source
.source
)
760 IMFMediaSource_Release(node
->u
.source
.source
);
762 case MF_TOPOLOGY_TRANSFORM_NODE
:
763 for (i
= 0; i
< node
->u
.transform
.input_count
; ++i
)
764 transform_stream_drop_samples(&node
->u
.transform
.inputs
[i
]);
765 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
766 transform_stream_drop_samples(&node
->u
.transform
.outputs
[i
]);
767 heap_free(node
->u
.transform
.inputs
);
768 heap_free(node
->u
.transform
.outputs
);
769 heap_free(node
->u
.transform
.input_map
);
770 heap_free(node
->u
.transform
.output_map
);
772 case MF_TOPOLOGY_OUTPUT_NODE
:
773 if (node
->u
.sink
.allocator
)
774 IMFVideoSampleAllocator_Release(node
->u
.sink
.allocator
);
775 if (node
->u
.sink
.allocator_cb
)
777 IMFVideoSampleAllocatorCallback_SetCallback(node
->u
.sink
.allocator_cb
, NULL
);
778 IMFVideoSampleAllocatorCallback_Release(node
->u
.sink
.allocator_cb
);
785 if (node
->object
.object
)
786 IUnknown_Release(node
->object
.object
);
788 IMFTopologyNode_Release(node
->node
);
792 static void session_shutdown_current_topology(struct media_session
*session
)
794 unsigned int shutdown
, force_shutdown
;
795 MF_TOPOLOGY_TYPE node_type
;
796 IMFStreamSink
*stream_sink
;
797 IMFTopology
*topology
;
798 IMFTopologyNode
*node
;
799 IMFActivate
*activate
;
804 topology
= session
->presentation
.current_topology
;
805 force_shutdown
= session
->state
== SESSION_STATE_SHUT_DOWN
;
807 /* FIXME: should handle async MFTs, but these are not supported by the rest of the pipeline currently. */
809 while (SUCCEEDED(IMFTopology_GetNode(topology
, idx
++, &node
)))
811 if (SUCCEEDED(IMFTopologyNode_GetNodeType(node
, &node_type
)) &&
812 node_type
== MF_TOPOLOGY_OUTPUT_NODE
)
815 IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, &shutdown
);
817 if (force_shutdown
|| shutdown
)
819 if (SUCCEEDED(IMFTopologyNode_GetUnknown(node
, &_MF_TOPONODE_IMFActivate
, &IID_IMFActivate
,
820 (void **)&activate
)))
822 if (FAILED(hr
= IMFActivate_ShutdownObject(activate
)))
823 WARN("Failed to shut down activation object for the sink, hr %#x.\n", hr
);
824 IMFActivate_Release(activate
);
826 else if (SUCCEEDED(topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
828 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink
, &sink
)))
830 IMFMediaSink_Shutdown(sink
);
831 IMFMediaSink_Release(sink
);
834 IMFStreamSink_Release(stream_sink
);
839 IMFTopologyNode_Release(node
);
843 static void session_clear_presentation(struct media_session
*session
)
845 struct media_source
*source
, *source2
;
846 struct media_sink
*sink
, *sink2
;
847 struct topo_node
*node
, *node2
;
848 struct session_op
*op
, *op2
;
850 session_shutdown_current_topology(session
);
852 IMFTopology_Clear(session
->presentation
.current_topology
);
853 session
->presentation
.topo_status
= MF_TOPOSTATUS_INVALID
;
855 LIST_FOR_EACH_ENTRY_SAFE(source
, source2
, &session
->presentation
.sources
, struct media_source
, entry
)
857 list_remove(&source
->entry
);
859 IMFMediaSource_Release(source
->source
);
861 IMFPresentationDescriptor_Release(source
->pd
);
865 LIST_FOR_EACH_ENTRY_SAFE(node
, node2
, &session
->presentation
.nodes
, struct topo_node
, entry
)
867 list_remove(&node
->entry
);
868 release_topo_node(node
);
871 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &session
->presentation
.sinks
, struct media_sink
, entry
)
873 list_remove(&sink
->entry
);
876 IMFMediaSink_Release(sink
->sink
);
878 IMFMediaSinkPreroll_Release(sink
->preroll
);
879 if (sink
->event_generator
)
880 IMFMediaEventGenerator_Release(sink
->event_generator
);
884 LIST_FOR_EACH_ENTRY_SAFE(op
, op2
, &session
->commands
, struct session_op
, entry
)
886 list_remove(&op
->entry
);
887 IUnknown_Release(&op
->IUnknown_iface
);
891 static struct topo_node
*session_get_node_by_id(const struct media_session
*session
, TOPOID id
)
893 struct topo_node
*node
;
895 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
897 if (node
->node_id
== id
)
904 static void session_start(struct media_session
*session
, const GUID
*time_format
, const PROPVARIANT
*start_position
)
906 struct media_source
*source
;
909 switch (session
->state
)
911 case SESSION_STATE_STOPPED
:
912 case SESSION_STATE_PAUSED
:
914 session
->presentation
.time_format
= *time_format
;
915 session
->presentation
.start_position
.vt
= VT_EMPTY
;
916 PropVariantCopy(&session
->presentation
.start_position
, start_position
);
918 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
920 if (!(session
->presentation
.flags
& SESSION_FLAG_SOURCES_SUBSCRIBED
))
922 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(source
->source
, &session
->events_callback
,
923 (IUnknown
*)source
->source
)))
925 WARN("Failed to subscribe to source events, hr %#x.\n", hr
);
929 if (FAILED(hr
= IMFMediaSource_Start(source
->source
, source
->pd
, &GUID_NULL
, start_position
)))
930 WARN("Failed to start media source %p, hr %#x.\n", source
->source
, hr
);
933 session
->presentation
.flags
|= SESSION_FLAG_SOURCES_SUBSCRIBED
;
934 session
->state
= SESSION_STATE_STARTING_SOURCES
;
936 case SESSION_STATE_STARTED
:
937 FIXME("Seeking is not implemented.\n");
939 case SESSION_STATE_CLOSED
:
940 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionStarted
, &GUID_NULL
,
941 MF_E_INVALIDREQUEST
, NULL
);
948 static void session_command_complete(struct media_session
*session
)
950 struct session_op
*op
;
953 /* Pop current command, submit next. */
954 if ((e
= list_head(&session
->commands
)))
956 op
= LIST_ENTRY(e
, struct session_op
, entry
);
957 list_remove(&op
->entry
);
958 IUnknown_Release(&op
->IUnknown_iface
);
961 if ((e
= list_head(&session
->commands
)))
963 op
= LIST_ENTRY(e
, struct session_op
, entry
);
964 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
968 static void session_set_started(struct media_session
*session
)
970 struct media_source
*source
;
971 unsigned int caps
, flags
;
972 IMFMediaEvent
*event
;
974 session
->state
= SESSION_STATE_STARTED
;
976 caps
= session
->caps
| MFSESSIONCAP_PAUSE
;
978 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
980 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &flags
)))
982 if (!(flags
& MFMEDIASOURCE_CAN_PAUSE
))
984 caps
&= ~MFSESSIONCAP_PAUSE
;
990 session_set_caps(session
, caps
);
992 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted
, &GUID_NULL
, S_OK
, NULL
, &event
)))
994 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
995 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
996 IMFMediaEvent_Release(event
);
998 session_command_complete(session
);
1001 static void session_set_paused(struct media_session
*session
, HRESULT status
)
1003 session
->state
= SESSION_STATE_PAUSED
;
1004 if (SUCCEEDED(status
))
1005 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
1006 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionPaused
, &GUID_NULL
, status
, NULL
);
1007 session_command_complete(session
);
1010 static void session_set_closed(struct media_session
*session
, HRESULT status
)
1012 session
->state
= SESSION_STATE_CLOSED
;
1013 if (SUCCEEDED(status
))
1014 session_set_caps(session
, session
->caps
& ~(MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
));
1015 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionClosed
, &GUID_NULL
, status
, NULL
);
1016 session_command_complete(session
);
1019 static void session_pause(struct media_session
*session
)
1023 switch (session
->state
)
1025 case SESSION_STATE_STARTED
:
1027 /* Transition in two steps - pause the clock, wait for sinks, then pause sources. */
1028 if (SUCCEEDED(hr
= IMFPresentationClock_Pause(session
->clock
)))
1029 session
->state
= SESSION_STATE_PAUSING_SINKS
;
1033 hr
= MF_E_INVALIDREQUEST
;
1037 session_set_paused(session
, hr
);
1040 static void session_set_stopped(struct media_session
*session
, HRESULT status
)
1042 MediaEventType event_type
;
1043 IMFMediaEvent
*event
;
1045 session
->state
= SESSION_STATE_STOPPED
;
1046 event_type
= session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
? MESessionEnded
: MESessionStopped
;
1048 if (SUCCEEDED(MFCreateMediaEvent(event_type
, &GUID_NULL
, status
, NULL
, &event
)))
1050 IMFMediaEvent_SetUINT64(event
, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME
, session
->presentation
.clock_stop_time
);
1051 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
1052 IMFMediaEvent_Release(event
);
1054 session_command_complete(session
);
1057 static void session_stop(struct media_session
*session
)
1059 HRESULT hr
= MF_E_INVALIDREQUEST
;
1061 switch (session
->state
)
1063 case SESSION_STATE_STARTED
:
1064 case SESSION_STATE_PAUSED
:
1066 /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */
1067 IMFPresentationClock_GetTime(session
->clock
, &session
->presentation
.clock_stop_time
);
1068 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1069 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1071 session_set_stopped(session
, hr
);
1074 case SESSION_STATE_STOPPED
:
1078 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionStopped
, &GUID_NULL
, hr
, NULL
);
1079 session_command_complete(session
);
1084 static HRESULT
session_finalize_sinks(struct media_session
*session
)
1086 IMFFinalizableMediaSink
*fin_sink
;
1087 BOOL sinks_finalized
= TRUE
;
1088 struct media_sink
*sink
;
1091 session
->presentation
.flags
&= ~SESSION_FLAG_FINALIZE_SINKS
;
1092 session
->state
= SESSION_STATE_FINALIZING_SINKS
;
1094 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1096 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
1098 hr
= IMFFinalizableMediaSink_BeginFinalize(fin_sink
, &session
->sink_finalizer_callback
,
1099 (IUnknown
*)fin_sink
);
1100 IMFFinalizableMediaSink_Release(fin_sink
);
1103 sinks_finalized
= FALSE
;
1106 sink
->finalized
= TRUE
;
1109 if (sinks_finalized
)
1110 session_set_closed(session
, hr
);
1115 static void session_close(struct media_session
*session
)
1119 switch (session
->state
)
1121 case SESSION_STATE_STOPPED
:
1122 hr
= session_finalize_sinks(session
);
1124 case SESSION_STATE_STARTED
:
1125 case SESSION_STATE_PAUSED
:
1126 session
->presentation
.flags
|= SESSION_FLAG_FINALIZE_SINKS
;
1127 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1128 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1131 hr
= MF_E_INVALIDREQUEST
;
1136 session_set_closed(session
, hr
);
1139 static struct media_source
*session_get_media_source(struct media_session
*session
, IMFMediaSource
*source
)
1141 struct media_source
*cur
;
1143 LIST_FOR_EACH_ENTRY(cur
, &session
->presentation
.sources
, struct media_source
, entry
)
1145 if (source
== cur
->source
)
1152 static void session_release_media_source(struct media_source
*source
)
1154 IMFMediaSource_Release(source
->source
);
1156 IMFPresentationDescriptor_Release(source
->pd
);
1160 static HRESULT
session_add_media_source(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSource
*source
)
1162 struct media_source
*media_source
;
1165 if (session_get_media_source(session
, source
))
1168 if (!(media_source
= heap_alloc_zero(sizeof(*media_source
))))
1169 return E_OUTOFMEMORY
;
1171 media_source
->source
= source
;
1172 IMFMediaSource_AddRef(media_source
->source
);
1174 hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
, &IID_IMFPresentationDescriptor
,
1175 (void **)&media_source
->pd
);
1178 list_add_tail(&session
->presentation
.sources
, &media_source
->entry
);
1180 session_release_media_source(media_source
);
1185 static void session_raise_topology_set(struct media_session
*session
, IMFTopology
*topology
, HRESULT status
)
1189 param
.vt
= topology
? VT_UNKNOWN
: VT_EMPTY
;
1190 param
.punkVal
= (IUnknown
*)topology
;
1192 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologySet
, &GUID_NULL
, status
, ¶m
);
1195 static DWORD
session_get_object_rate_caps(IUnknown
*object
)
1197 IMFRateSupport
*rate_support
;
1201 if (SUCCEEDED(MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
1204 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_FORWARD
, TRUE
, &rate
)) && rate
!= 0.0f
)
1205 caps
|= MFSESSIONCAP_RATE_FORWARD
;
1208 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_REVERSE
, TRUE
, &rate
)) && rate
!= 0.0f
)
1209 caps
|= MFSESSIONCAP_RATE_REVERSE
;
1211 IMFRateSupport_Release(rate_support
);
1217 static HRESULT
session_add_media_sink(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSink
*sink
)
1219 struct media_sink
*media_sink
;
1222 LIST_FOR_EACH_ENTRY(media_sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1224 if (sink
== media_sink
->sink
)
1228 if (!(media_sink
= heap_alloc_zero(sizeof(*media_sink
))))
1229 return E_OUTOFMEMORY
;
1231 media_sink
->sink
= sink
;
1232 IMFMediaSink_AddRef(media_sink
->sink
);
1234 IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaEventGenerator
, (void **)&media_sink
->event_generator
);
1236 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
, &flags
)) && flags
& MEDIASINK_CAN_PREROLL
)
1238 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaSinkPreroll
, (void **)&media_sink
->preroll
)))
1239 session
->presentation
.flags
|= SESSION_FLAG_NEEDS_PREROLL
;
1242 list_add_tail(&session
->presentation
.sinks
, &media_sink
->entry
);
1247 static HRESULT
session_set_transform_stream_info(struct topo_node
*node
)
1249 unsigned int *input_map
= NULL
, *output_map
= NULL
;
1250 unsigned int i
, input_count
, output_count
;
1251 struct transform_stream
*streams
;
1254 hr
= IMFTransform_GetStreamCount(node
->object
.transform
, &input_count
, &output_count
);
1255 if (SUCCEEDED(hr
) && (input_count
> 1 || output_count
> 1))
1257 input_map
= heap_calloc(input_count
, sizeof(*input_map
));
1258 output_map
= heap_calloc(output_count
, sizeof(*output_map
));
1259 if (FAILED(IMFTransform_GetStreamIDs(node
->object
.transform
, input_count
, input_map
,
1260 output_count
, output_map
)))
1262 /* Assume sequential identifiers. */
1263 heap_free(input_map
);
1264 heap_free(output_map
);
1265 input_map
= output_map
= NULL
;
1271 streams
= heap_calloc(input_count
, sizeof(*streams
));
1272 for (i
= 0; i
< input_count
; ++i
)
1273 list_init(&streams
[i
].samples
);
1274 node
->u
.transform
.inputs
= streams
;
1276 streams
= heap_calloc(output_count
, sizeof(*streams
));
1277 for (i
= 0; i
< output_count
; ++i
)
1278 list_init(&streams
[i
].samples
);
1279 node
->u
.transform
.outputs
= streams
;
1281 node
->u
.transform
.input_count
= input_count
;
1282 node
->u
.transform
.output_count
= output_count
;
1283 node
->u
.transform
.input_map
= input_map
;
1284 node
->u
.transform
.output_map
= output_map
;
1290 static HRESULT
session_get_stream_sink_type(IMFStreamSink
*sink
, IMFMediaType
**media_type
)
1292 IMFMediaTypeHandler
*handler
;
1295 if (SUCCEEDED(hr
= IMFStreamSink_GetMediaTypeHandler(sink
, &handler
)))
1297 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, media_type
);
1298 IMFMediaTypeHandler_Release(handler
);
1304 static HRESULT WINAPI
node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify
*iface
,
1305 REFIID riid
, void **obj
)
1307 if (IsEqualIID(riid
, &IID_IMFVideoSampleAllocatorNotify
) ||
1308 IsEqualIID(riid
, &IID_IUnknown
))
1311 IMFVideoSampleAllocatorNotify_AddRef(iface
);
1316 return E_NOINTERFACE
;
1319 static ULONG WINAPI
node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify
*iface
)
1324 static ULONG WINAPI
node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify
*iface
)
1329 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
);
1331 static HRESULT WINAPI
node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify
*iface
)
1333 struct topo_node
*topo_node
= impl_node_from_IMFVideoSampleAllocatorNotify(iface
);
1334 struct session_op
*op
;
1336 if (SUCCEEDED(create_session_op(SESSION_CMD_SA_READY
, &op
)))
1338 op
->u
.sa_ready
.node_id
= topo_node
->node_id
;
1339 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &topo_node
->session
->commands_callback
, &op
->IUnknown_iface
);
1340 IUnknown_Release(&op
->IUnknown_iface
);
1346 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl
=
1348 node_sample_allocator_cb_QueryInterface
,
1349 node_sample_allocator_cb_AddRef
,
1350 node_sample_allocator_cb_Release
,
1351 node_sample_allocator_cb_NotifyRelease
,
1354 static HRESULT
session_append_node(struct media_session
*session
, IMFTopologyNode
*node
)
1356 struct topo_node
*topo_node
;
1357 IMFMediaSink
*media_sink
;
1358 IMFMediaType
*media_type
;
1359 IMFStreamDescriptor
*sd
;
1362 if (!(topo_node
= heap_alloc_zero(sizeof(*topo_node
))))
1363 return E_OUTOFMEMORY
;
1365 IMFTopologyNode_GetNodeType(node
, &topo_node
->type
);
1366 IMFTopologyNode_GetTopoNodeID(node
, &topo_node
->node_id
);
1367 topo_node
->node
= node
;
1368 IMFTopologyNode_AddRef(topo_node
->node
);
1369 topo_node
->session
= session
;
1371 switch (topo_node
->type
)
1373 case MF_TOPOLOGY_OUTPUT_NODE
:
1374 topo_node
->u
.sink
.notify_cb
.lpVtbl
= &node_sample_allocator_cb_vtbl
;
1376 if (FAILED(hr
= topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&topo_node
->object
.object
)))
1378 WARN("Failed to get stream sink interface, hr %#x.\n", hr
);
1382 if (FAILED(hr
= IMFStreamSink_GetMediaSink(topo_node
->object
.sink_stream
, &media_sink
)))
1385 if (SUCCEEDED(hr
= session_add_media_sink(session
, node
, media_sink
)))
1387 if (SUCCEEDED(session_get_stream_sink_type(topo_node
->object
.sink_stream
, &media_type
)))
1389 if (SUCCEEDED(MFGetService(topo_node
->object
.object
, &MR_VIDEO_ACCELERATION_SERVICE
,
1390 &IID_IMFVideoSampleAllocator
, (void **)&topo_node
->u
.sink
.allocator
)))
1392 if (FAILED(hr
= IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node
->u
.sink
.allocator
,
1395 WARN("Failed to initialize sample allocator for the stream, hr %#x.\n", hr
);
1397 IMFVideoSampleAllocator_QueryInterface(topo_node
->u
.sink
.allocator
,
1398 &IID_IMFVideoSampleAllocatorCallback
, (void **)&topo_node
->u
.sink
.allocator_cb
);
1399 IMFVideoSampleAllocatorCallback_SetCallback(topo_node
->u
.sink
.allocator_cb
,
1400 &topo_node
->u
.sink
.notify_cb
);
1402 IMFMediaType_Release(media_type
);
1405 IMFMediaSink_Release(media_sink
);
1408 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
1409 if (FAILED(IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_SOURCE
, &IID_IMFMediaSource
,
1410 (void **)&topo_node
->u
.source
.source
)))
1412 WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr
);
1416 if (FAILED(hr
= session_add_media_source(session
, node
, topo_node
->u
.source
.source
)))
1419 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
1420 &IID_IMFStreamDescriptor
, (void **)&sd
)))
1422 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr
);
1426 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &topo_node
->u
.source
.stream_id
);
1427 IMFStreamDescriptor_Release(sd
);
1430 case MF_TOPOLOGY_TRANSFORM_NODE
:
1432 if (SUCCEEDED(hr
= topology_node_get_object(node
, &IID_IMFTransform
, (void **)&topo_node
->object
.transform
)))
1434 hr
= session_set_transform_stream_info(topo_node
);
1437 WARN("Failed to get IMFTransform for MFT node, hr %#x.\n", hr
);
1440 case MF_TOPOLOGY_TEE_NODE
:
1441 FIXME("Unsupported node type %d.\n", topo_node
->type
);
1449 list_add_tail(&session
->presentation
.nodes
, &topo_node
->entry
);
1451 release_topo_node(topo_node
);
1456 static HRESULT
session_collect_nodes(struct media_session
*session
)
1458 IMFTopology
*topology
= session
->presentation
.current_topology
;
1459 IMFTopologyNode
*node
;
1463 if (!list_empty(&session
->presentation
.nodes
))
1466 if (FAILED(hr
= IMFTopology_GetNodeCount(topology
, &count
)))
1469 for (i
= 0; i
< count
; ++i
)
1471 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
1473 WARN("Failed to get node %u.\n", i
);
1477 hr
= session_append_node(session
, node
);
1478 IMFTopologyNode_Release(node
);
1481 WARN("Failed to add node %u.\n", i
);
1489 static HRESULT
session_set_current_topology(struct media_session
*session
, IMFTopology
*topology
)
1491 struct media_source
*source
;
1492 DWORD caps
, object_flags
;
1493 struct media_sink
*sink
;
1494 struct topo_node
*node
;
1495 struct session_op
*op
;
1496 IMFMediaEvent
*event
;
1499 if (session
->quality_manager
)
1501 if (SUCCEEDED(create_session_op(SESSION_CMD_QM_NOTIFY_TOPOLOGY
, &op
)))
1503 op
->u
.notify_topology
.topology
= topology
;
1504 IMFTopology_AddRef(op
->u
.notify_topology
.topology
);
1505 session_submit_command(session
, op
);
1506 IUnknown_Release(&op
->IUnknown_iface
);
1510 if (FAILED(hr
= IMFTopology_CloneFrom(session
->presentation
.current_topology
, topology
)))
1512 WARN("Failed to clone topology, hr %#x.\n", hr
);
1516 session_collect_nodes(session
);
1518 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1520 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
1522 if (FAILED(hr
= IMFTransform_ProcessMessage(node
->object
.transform
,
1523 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING
, 0)))
1528 /* FIXME: attributes are all zero for now */
1529 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime
, &GUID_NULL
, S_OK
, NULL
, &event
)))
1531 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME
, 0);
1532 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
1533 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT
, 0);
1535 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
1536 IMFMediaEvent_Release(event
);
1539 /* Update session caps. */
1540 caps
= MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
| MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
|
1541 MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1543 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1549 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &object_flags
)))
1551 if (!(object_flags
& MFMEDIASOURCE_DOES_NOT_USE_NETWORK
))
1552 caps
&= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1553 if (!(object_flags
& MFMEDIASOURCE_CAN_SEEK
))
1554 caps
&= ~MFSESSIONCAP_SEEK
;
1557 /* Mask unsupported rate caps. */
1559 caps
&= session_get_object_rate_caps((IUnknown
*)source
->source
)
1560 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1563 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1569 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
->sink
, &object_flags
)))
1571 if (!(object_flags
& MEDIASINK_RATELESS
))
1572 caps
&= session_get_object_rate_caps((IUnknown
*)sink
->sink
)
1573 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1577 session_set_caps(session
, caps
);
1582 static void session_set_topology(struct media_session
*session
, DWORD flags
, IMFTopology
*topology
)
1584 IMFTopology
*resolved_topology
= NULL
;
1587 /* Resolve unless claimed to be full. */
1588 if (!(flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
) && topology
)
1590 if (!(flags
& MFSESSION_SETTOPOLOGY_NORESOLUTION
))
1592 hr
= session_bind_output_nodes(topology
);
1595 hr
= IMFTopoLoader_Load(session
->topo_loader
, topology
, &resolved_topology
, NULL
/* FIXME? */);
1599 topology
= resolved_topology
;
1604 if (flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
)
1606 if ((topology
&& topology
== session
->presentation
.current_topology
) || !topology
)
1608 /* FIXME: stop current topology, queue next one. */
1609 session_clear_presentation(session
);
1616 else if (topology
&& flags
& MFSESSION_SETTOPOLOGY_IMMEDIATE
)
1618 session_clear_topologies(session
);
1619 session_clear_presentation(session
);
1622 session_raise_topology_set(session
, topology
, hr
);
1624 /* With no current topology set it right away, otherwise queue. */
1627 struct queued_topology
*queued_topology
;
1629 if ((queued_topology
= heap_alloc_zero(sizeof(*queued_topology
))))
1631 queued_topology
->topology
= topology
;
1632 IMFTopology_AddRef(queued_topology
->topology
);
1634 list_add_tail(&session
->topologies
, &queued_topology
->entry
);
1637 if (session
->presentation
.topo_status
== MF_TOPOSTATUS_INVALID
)
1639 hr
= session_set_current_topology(session
, topology
);
1640 session_set_topo_status(session
, hr
, MF_TOPOSTATUS_READY
);
1644 if (resolved_topology
)
1645 IMFTopology_Release(resolved_topology
);
1648 static HRESULT WINAPI
mfsession_QueryInterface(IMFMediaSession
*iface
, REFIID riid
, void **out
)
1650 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1652 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1654 if (IsEqualIID(riid
, &IID_IMFMediaSession
) ||
1655 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1656 IsEqualIID(riid
, &IID_IUnknown
))
1658 *out
= &session
->IMFMediaSession_iface
;
1659 IMFMediaSession_AddRef(iface
);
1662 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1664 *out
= &session
->IMFGetService_iface
;
1665 IMFMediaSession_AddRef(iface
);
1669 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1671 return E_NOINTERFACE
;
1674 static ULONG WINAPI
mfsession_AddRef(IMFMediaSession
*iface
)
1676 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1677 ULONG refcount
= InterlockedIncrement(&session
->refcount
);
1679 TRACE("%p, refcount %u.\n", iface
, refcount
);
1684 static ULONG WINAPI
mfsession_Release(IMFMediaSession
*iface
)
1686 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1687 ULONG refcount
= InterlockedDecrement(&session
->refcount
);
1689 TRACE("%p, refcount %u.\n", iface
, refcount
);
1693 session_clear_topologies(session
);
1694 session_clear_presentation(session
);
1695 if (session
->presentation
.current_topology
)
1696 IMFTopology_Release(session
->presentation
.current_topology
);
1697 if (session
->event_queue
)
1698 IMFMediaEventQueue_Release(session
->event_queue
);
1700 IMFPresentationClock_Release(session
->clock
);
1701 if (session
->system_time_source
)
1702 IMFPresentationTimeSource_Release(session
->system_time_source
);
1703 if (session
->clock_rate_control
)
1704 IMFRateControl_Release(session
->clock_rate_control
);
1705 if (session
->topo_loader
)
1706 IMFTopoLoader_Release(session
->topo_loader
);
1707 if (session
->quality_manager
)
1708 IMFQualityManager_Release(session
->quality_manager
);
1709 DeleteCriticalSection(&session
->cs
);
1716 static HRESULT WINAPI
mfsession_GetEvent(IMFMediaSession
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1718 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1720 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
1722 return IMFMediaEventQueue_GetEvent(session
->event_queue
, flags
, event
);
1725 static HRESULT WINAPI
mfsession_BeginGetEvent(IMFMediaSession
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1727 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1729 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1731 return IMFMediaEventQueue_BeginGetEvent(session
->event_queue
, callback
, state
);
1734 static HRESULT WINAPI
mfsession_EndGetEvent(IMFMediaSession
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
1736 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1738 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1740 return IMFMediaEventQueue_EndGetEvent(session
->event_queue
, result
, event
);
1743 static HRESULT WINAPI
mfsession_QueueEvent(IMFMediaSession
*iface
, MediaEventType event_type
, REFGUID ext_type
,
1744 HRESULT hr
, const PROPVARIANT
*value
)
1746 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1748 TRACE("%p, %d, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1750 return IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, event_type
, ext_type
, hr
, value
);
1753 static HRESULT WINAPI
mfsession_SetTopology(IMFMediaSession
*iface
, DWORD flags
, IMFTopology
*topology
)
1755 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1756 struct session_op
*op
;
1757 WORD node_count
= 0;
1760 TRACE("%p, %#x, %p.\n", iface
, flags
, topology
);
1764 if (FAILED(IMFTopology_GetNodeCount(topology
, &node_count
)) || node_count
== 0)
1765 return E_INVALIDARG
;
1768 if (FAILED(hr
= create_session_op(SESSION_CMD_SET_TOPOLOGY
, &op
)))
1771 op
->u
.set_topology
.flags
= flags
;
1772 op
->u
.set_topology
.topology
= topology
;
1773 if (op
->u
.set_topology
.topology
)
1774 IMFTopology_AddRef(op
->u
.set_topology
.topology
);
1776 hr
= session_submit_command(session
, op
);
1777 IUnknown_Release(&op
->IUnknown_iface
);
1782 static HRESULT WINAPI
mfsession_ClearTopologies(IMFMediaSession
*iface
)
1784 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1786 TRACE("%p.\n", iface
);
1788 return session_submit_simple_command(session
, SESSION_CMD_CLEAR_TOPOLOGIES
);
1791 static HRESULT WINAPI
mfsession_Start(IMFMediaSession
*iface
, const GUID
*format
, const PROPVARIANT
*start_position
)
1793 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1794 struct session_op
*op
;
1797 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), start_position
);
1799 if (!start_position
)
1802 if (FAILED(hr
= create_session_op(SESSION_CMD_START
, &op
)))
1805 op
->u
.start
.time_format
= format
? *format
: GUID_NULL
;
1806 hr
= PropVariantCopy(&op
->u
.start
.start_position
, start_position
);
1809 hr
= session_submit_command(session
, op
);
1811 IUnknown_Release(&op
->IUnknown_iface
);
1816 static HRESULT WINAPI
mfsession_Pause(IMFMediaSession
*iface
)
1818 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1820 TRACE("%p.\n", iface
);
1822 return session_submit_simple_command(session
, SESSION_CMD_PAUSE
);
1825 static HRESULT WINAPI
mfsession_Stop(IMFMediaSession
*iface
)
1827 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1829 TRACE("%p.\n", iface
);
1831 return session_submit_simple_command(session
, SESSION_CMD_STOP
);
1834 static HRESULT WINAPI
mfsession_Close(IMFMediaSession
*iface
)
1836 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1838 TRACE("%p.\n", iface
);
1840 return session_submit_simple_command(session
, SESSION_CMD_CLOSE
);
1843 static HRESULT WINAPI
mfsession_Shutdown(IMFMediaSession
*iface
)
1845 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1848 TRACE("%p.\n", iface
);
1850 EnterCriticalSection(&session
->cs
);
1851 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1853 session
->state
= SESSION_STATE_SHUT_DOWN
;
1854 IMFMediaEventQueue_Shutdown(session
->event_queue
);
1855 if (session
->quality_manager
)
1856 IMFQualityManager_Shutdown(session
->quality_manager
);
1857 MFShutdownObject((IUnknown
*)session
->clock
);
1858 IMFPresentationClock_Release(session
->clock
);
1859 session
->clock
= NULL
;
1860 session_clear_presentation(session
);
1862 LeaveCriticalSection(&session
->cs
);
1867 static HRESULT WINAPI
mfsession_GetClock(IMFMediaSession
*iface
, IMFClock
**clock
)
1869 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1872 TRACE("%p, %p.\n", iface
, clock
);
1874 EnterCriticalSection(&session
->cs
);
1875 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1877 *clock
= (IMFClock
*)session
->clock
;
1878 IMFClock_AddRef(*clock
);
1880 LeaveCriticalSection(&session
->cs
);
1885 static HRESULT WINAPI
mfsession_GetSessionCapabilities(IMFMediaSession
*iface
, DWORD
*caps
)
1887 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1890 TRACE("%p, %p.\n", iface
, caps
);
1895 EnterCriticalSection(&session
->cs
);
1896 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1897 *caps
= session
->caps
;
1898 LeaveCriticalSection(&session
->cs
);
1903 static HRESULT WINAPI
mfsession_GetFullTopology(IMFMediaSession
*iface
, DWORD flags
, TOPOID id
, IMFTopology
**topology
)
1905 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1906 struct queued_topology
*queued
;
1910 TRACE("%p, %#x, %s, %p.\n", iface
, flags
, wine_dbgstr_longlong(id
), topology
);
1914 EnterCriticalSection(&session
->cs
);
1916 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1918 if (flags
& MFSESSION_GETFULLTOPOLOGY_CURRENT
)
1920 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
1921 *topology
= session
->presentation
.current_topology
;
1923 hr
= MF_E_INVALIDREQUEST
;
1927 LIST_FOR_EACH_ENTRY(queued
, &session
->topologies
, struct queued_topology
, entry
)
1929 if (SUCCEEDED(IMFTopology_GetTopologyID(queued
->topology
, &topo_id
)) && topo_id
== id
)
1931 *topology
= queued
->topology
;
1938 IMFTopology_AddRef(*topology
);
1941 LeaveCriticalSection(&session
->cs
);
1946 static const IMFMediaSessionVtbl mfmediasessionvtbl
=
1948 mfsession_QueryInterface
,
1952 mfsession_BeginGetEvent
,
1953 mfsession_EndGetEvent
,
1954 mfsession_QueueEvent
,
1955 mfsession_SetTopology
,
1956 mfsession_ClearTopologies
,
1963 mfsession_GetSessionCapabilities
,
1964 mfsession_GetFullTopology
,
1967 static HRESULT WINAPI
session_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
1969 struct media_session
*session
= impl_from_IMFGetService(iface
);
1970 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
1973 static ULONG WINAPI
session_get_service_AddRef(IMFGetService
*iface
)
1975 struct media_session
*session
= impl_from_IMFGetService(iface
);
1976 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
1979 static ULONG WINAPI
session_get_service_Release(IMFGetService
*iface
)
1981 struct media_session
*session
= impl_from_IMFGetService(iface
);
1982 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
1985 static HRESULT WINAPI
session_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
1987 struct media_session
*session
= impl_from_IMFGetService(iface
);
1989 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
1993 if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
1995 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1997 *obj
= &session
->IMFRateSupport_iface
;
1999 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
2001 *obj
= &session
->IMFRateControl_iface
;
2004 else if (IsEqualGUID(service
, &MF_LOCAL_MFT_REGISTRATION_SERVICE
))
2006 return IMFLocalMFTRegistration_QueryInterface(&local_mft_registration
, riid
, obj
);
2008 else if (IsEqualGUID(service
, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE
))
2010 *obj
= &session
->IMFTopologyNodeAttributeEditor_iface
;
2012 else if (IsEqualGUID(service
, &MR_VIDEO_RENDER_SERVICE
))
2014 IMFStreamSink
*stream_sink
;
2015 IMFTopologyNode
*node
;
2016 IMFCollection
*nodes
;
2022 EnterCriticalSection(&session
->cs
);
2024 /* Use first sink to support IMFVideoRenderer. */
2025 if (session
->presentation
.current_topology
)
2027 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session
->presentation
.current_topology
,
2030 while (IMFCollection_GetElement(nodes
, i
++, (IUnknown
**)&node
) == S_OK
)
2032 if (SUCCEEDED(topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
2034 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink
, &sink
)))
2036 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
, &IID_IMFVideoRenderer
, (void **)&vr
)))
2038 if (FAILED(hr
= MFGetService(vr
, service
, riid
, obj
)))
2039 WARN("Failed to get service from video renderer %#x.\n", hr
);
2040 IUnknown_Release(vr
);
2043 IMFStreamSink_Release(stream_sink
);
2046 IMFTopologyNode_Release(node
);
2052 IMFCollection_Release(nodes
);
2056 LeaveCriticalSection(&session
->cs
);
2059 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
2062 IUnknown_AddRef((IUnknown
*)*obj
);
2064 return *obj
? S_OK
: E_NOINTERFACE
;
2067 static const IMFGetServiceVtbl session_get_service_vtbl
=
2069 session_get_service_QueryInterface
,
2070 session_get_service_AddRef
,
2071 session_get_service_Release
,
2072 session_get_service_GetService
,
2075 static HRESULT WINAPI
session_commands_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2077 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2078 IsEqualIID(riid
, &IID_IUnknown
))
2081 IMFAsyncCallback_AddRef(iface
);
2085 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2087 return E_NOINTERFACE
;
2090 static ULONG WINAPI
session_commands_callback_AddRef(IMFAsyncCallback
*iface
)
2092 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2093 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2096 static ULONG WINAPI
session_commands_callback_Release(IMFAsyncCallback
*iface
)
2098 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2099 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2102 static HRESULT WINAPI
session_commands_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2107 static HRESULT WINAPI
session_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
2109 struct session_op
*op
= impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result
));
2110 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2111 struct topo_node
*topo_node
;
2112 IMFTopologyNode
*upstream_node
;
2113 unsigned int upstream_output
;
2115 EnterCriticalSection(&session
->cs
);
2117 switch (op
->command
)
2119 case SESSION_CMD_CLEAR_TOPOLOGIES
:
2120 session_clear_topologies(session
);
2121 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologiesCleared
, &GUID_NULL
,
2123 session_command_complete(session
);
2125 case SESSION_CMD_SET_TOPOLOGY
:
2126 session_set_topology(session
, op
->u
.set_topology
.flags
, op
->u
.set_topology
.topology
);
2127 session_command_complete(session
);
2129 case SESSION_CMD_START
:
2130 session_start(session
, &op
->u
.start
.time_format
, &op
->u
.start
.start_position
);
2132 case SESSION_CMD_PAUSE
:
2133 session_pause(session
);
2135 case SESSION_CMD_STOP
:
2136 session_stop(session
);
2138 case SESSION_CMD_CLOSE
:
2139 session_close(session
);
2141 case SESSION_CMD_QM_NOTIFY_TOPOLOGY
:
2142 IMFQualityManager_NotifyTopology(session
->quality_manager
, op
->u
.notify_topology
.topology
);
2143 session_command_complete(session
);
2145 case SESSION_CMD_SA_READY
:
2146 topo_node
= session_get_node_by_id(session
, op
->u
.sa_ready
.node_id
);
2148 if (topo_node
->u
.sink
.requests
)
2150 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node
->node
, 0, &upstream_node
, &upstream_output
)))
2152 session_request_sample_from_node(session
, upstream_node
, upstream_output
);
2153 IMFTopologyNode_Release(upstream_node
);
2161 LeaveCriticalSection(&session
->cs
);
2166 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl
=
2168 session_commands_callback_QueryInterface
,
2169 session_commands_callback_AddRef
,
2170 session_commands_callback_Release
,
2171 session_commands_callback_GetParameters
,
2172 session_commands_callback_Invoke
,
2175 static HRESULT WINAPI
session_events_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2177 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2178 IsEqualIID(riid
, &IID_IUnknown
))
2181 IMFAsyncCallback_AddRef(iface
);
2185 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2187 return E_NOINTERFACE
;
2190 static ULONG WINAPI
session_events_callback_AddRef(IMFAsyncCallback
*iface
)
2192 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2193 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2196 static ULONG WINAPI
session_events_callback_Release(IMFAsyncCallback
*iface
)
2198 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2199 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2202 static HRESULT WINAPI
session_events_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2207 static HRESULT
session_add_media_stream(struct media_session
*session
, IMFMediaSource
*source
, IMFMediaStream
*stream
)
2209 struct topo_node
*node
;
2210 IMFStreamDescriptor
*sd
;
2211 DWORD stream_id
= 0;
2214 if (FAILED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
2217 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &stream_id
);
2218 IMFStreamDescriptor_Release(sd
);
2222 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2224 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->u
.source
.source
== source
2225 && node
->u
.source
.stream_id
== stream_id
)
2227 if (node
->object
.source_stream
)
2229 WARN("Node already has stream set.\n");
2233 node
->object
.source_stream
= stream
;
2234 IMFMediaStream_AddRef(node
->object
.source_stream
);
2242 static BOOL
session_is_source_nodes_state(struct media_session
*session
, enum object_state state
)
2244 struct media_source
*source
;
2245 struct topo_node
*node
;
2247 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2249 if (source
->state
!= state
)
2253 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2255 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->state
!= state
)
2262 static BOOL
session_is_output_nodes_state(struct media_session
*session
, enum object_state state
)
2264 struct topo_node
*node
;
2266 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2268 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->state
!= state
)
2275 static enum object_state
session_get_object_state_for_event(MediaEventType event
)
2279 case MESourceStarted
:
2280 case MEStreamStarted
:
2281 case MEStreamSinkStarted
:
2282 return OBJ_STATE_STARTED
;
2283 case MESourcePaused
:
2284 case MEStreamPaused
:
2285 case MEStreamSinkPaused
:
2286 return OBJ_STATE_PAUSED
;
2287 case MESourceStopped
:
2288 case MEStreamStopped
:
2289 case MEStreamSinkStopped
:
2290 return OBJ_STATE_STOPPED
;
2291 case MEStreamSinkPrerolled
:
2292 return OBJ_STATE_PREROLLED
;
2294 return OBJ_STATE_INVALID
;
2298 static void session_set_consumed_clock(IUnknown
*object
, IMFPresentationClock
*clock
)
2300 IMFClockConsumer
*consumer
;
2302 if (SUCCEEDED(IUnknown_QueryInterface(object
, &IID_IMFClockConsumer
, (void **)&consumer
)))
2304 IMFClockConsumer_SetPresentationClock(consumer
, clock
);
2305 IMFClockConsumer_Release(consumer
);
2309 static void session_set_presentation_clock(struct media_session
*session
)
2311 IMFPresentationTimeSource
*time_source
= NULL
;
2312 struct media_source
*source
;
2313 struct media_sink
*sink
;
2314 struct topo_node
*node
;
2317 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2319 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
2320 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_NOTIFY_START_OF_STREAM
, 0);
2323 if (!(session
->presentation
.flags
& SESSION_FLAG_PRESENTATION_CLOCK_SET
))
2325 /* Attempt to get time source from the sinks. */
2326 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2328 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFPresentationTimeSource
,
2329 (void **)&time_source
)))
2335 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, time_source
);
2336 IMFPresentationTimeSource_Release(time_source
);
2339 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, session
->system_time_source
);
2342 WARN("Failed to set time source, hr %#x.\n", hr
);
2344 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2346 if (node
->type
!= MF_TOPOLOGY_OUTPUT_NODE
)
2349 if (FAILED(hr
= IMFStreamSink_BeginGetEvent(node
->object
.sink_stream
, &session
->events_callback
,
2350 node
->object
.object
)))
2352 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr
);
2356 /* Set clock for all topology nodes. */
2357 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2359 session_set_consumed_clock((IUnknown
*)source
->source
, session
->clock
);
2362 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2364 if (sink
->event_generator
&& FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(sink
->event_generator
,
2365 &session
->events_callback
, (IUnknown
*)sink
->event_generator
)))
2367 WARN("Failed to subscribe to sink events, hr %#x.\n", hr
);
2370 if (FAILED(hr
= IMFMediaSink_SetPresentationClock(sink
->sink
, session
->clock
)))
2371 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr
);
2374 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2376 if (node
->type
!= MF_TOPOLOGY_TRANSFORM_NODE
)
2379 session_set_consumed_clock(node
->object
.object
, session
->clock
);
2382 session
->presentation
.flags
|= SESSION_FLAG_PRESENTATION_CLOCK_SET
;
2386 static HRESULT
session_start_clock(struct media_session
*session
)
2388 LONGLONG start_offset
= 0;
2391 if (IsEqualGUID(&session
->presentation
.time_format
, &GUID_NULL
))
2393 if (session
->presentation
.start_position
.vt
== VT_EMPTY
)
2394 start_offset
= PRESENTATION_CURRENT_POSITION
;
2395 else if (session
->presentation
.start_position
.vt
== VT_I8
)
2396 start_offset
= session
->presentation
.start_position
.hVal
.QuadPart
;
2398 FIXME("Unhandled position type %d.\n", session
->presentation
.start_position
.vt
);
2401 FIXME("Unhandled time format %s.\n", debugstr_guid(&session
->presentation
.time_format
));
2403 if (FAILED(hr
= IMFPresentationClock_Start(session
->clock
, start_offset
)))
2404 WARN("Failed to start session clock, hr %#x.\n", hr
);
2409 static struct topo_node
*session_get_node_object(struct media_session
*session
, IUnknown
*object
,
2410 MF_TOPOLOGY_TYPE node_type
)
2412 struct topo_node
*node
= NULL
;
2414 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2416 if (node
->type
== node_type
&& object
== node
->object
.object
)
2423 static BOOL
session_set_node_object_state(struct media_session
*session
, IUnknown
*object
,
2424 MF_TOPOLOGY_TYPE node_type
, enum object_state state
)
2426 struct topo_node
*node
;
2427 BOOL changed
= FALSE
;
2429 if ((node
= session_get_node_object(session
, object
, node_type
)))
2431 changed
= node
->state
!= state
;
2432 node
->state
= state
;
2438 static void session_set_source_object_state(struct media_session
*session
, IUnknown
*object
,
2439 MediaEventType event_type
)
2441 IMFStreamSink
*stream_sink
;
2442 struct media_source
*src
;
2443 struct media_sink
*sink
;
2444 enum object_state state
;
2445 struct topo_node
*node
;
2446 unsigned int i
, count
;
2447 BOOL changed
= FALSE
;
2450 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2455 case MESourceStarted
:
2456 case MESourcePaused
:
2457 case MESourceStopped
:
2459 LIST_FOR_EACH_ENTRY(src
, &session
->presentation
.sources
, struct media_source
, entry
)
2461 if (object
== (IUnknown
*)src
->source
)
2463 changed
= src
->state
!= state
;
2469 case MEStreamStarted
:
2470 case MEStreamPaused
:
2471 case MEStreamStopped
:
2473 changed
= session_set_node_object_state(session
, object
, MF_TOPOLOGY_SOURCESTREAM_NODE
, state
);
2481 switch (session
->state
)
2483 case SESSION_STATE_STARTING_SOURCES
:
2484 if (!session_is_source_nodes_state(session
, OBJ_STATE_STARTED
))
2487 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_STARTED_SOURCE
);
2489 session_set_presentation_clock(session
);
2491 if (session
->presentation
.flags
& SESSION_FLAG_NEEDS_PREROLL
)
2493 MFTIME preroll_time
= 0;
2495 if (session
->presentation
.start_position
.vt
== VT_I8
)
2496 preroll_time
= session
->presentation
.start_position
.hVal
.QuadPart
;
2498 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2499 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2503 /* FIXME: abort and enter error state on failure. */
2504 if (FAILED(hr
= IMFMediaSinkPreroll_NotifyPreroll(sink
->preroll
, preroll_time
)))
2505 WARN("Preroll notification failed, hr %#x.\n", hr
);
2509 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink
->sink
, &count
)))
2511 for (i
= 0; i
< count
; ++i
)
2513 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink
->sink
, i
, &stream_sink
)))
2515 session_set_node_object_state(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
,
2516 OBJ_STATE_PREROLLED
);
2517 IMFStreamSink_Release(stream_sink
);
2523 session
->state
= SESSION_STATE_PREROLLING_SINKS
;
2525 else if (SUCCEEDED(session_start_clock(session
)))
2526 session
->state
= SESSION_STATE_STARTING_SINKS
;
2529 case SESSION_STATE_PAUSING_SOURCES
:
2530 if (!session_is_source_nodes_state(session
, OBJ_STATE_PAUSED
))
2533 session_set_paused(session
, S_OK
);
2535 case SESSION_STATE_STOPPING_SOURCES
:
2536 if (!session_is_source_nodes_state(session
, OBJ_STATE_STOPPED
))
2539 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2543 case MF_TOPOLOGY_OUTPUT_NODE
:
2544 IMFStreamSink_Flush(node
->object
.sink_stream
);
2546 case MF_TOPOLOGY_TRANSFORM_NODE
:
2547 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
2554 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
2556 if (session
->presentation
.flags
& SESSION_FLAG_FINALIZE_SINKS
)
2557 session_finalize_sinks(session
);
2559 session_set_stopped(session
, S_OK
);
2567 static void session_set_sink_stream_state(struct media_session
*session
, IMFStreamSink
*stream
,
2568 MediaEventType event_type
)
2570 struct media_source
*source
;
2571 enum object_state state
;
2575 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2578 if (!(changed
= session_set_node_object_state(session
, (IUnknown
*)stream
, MF_TOPOLOGY_OUTPUT_NODE
, state
)))
2581 switch (session
->state
)
2583 case SESSION_STATE_PREROLLING_SINKS
:
2584 if (!session_is_output_nodes_state(session
, OBJ_STATE_PREROLLED
))
2587 if (SUCCEEDED(session_start_clock(session
)))
2588 session
->state
= SESSION_STATE_STARTING_SINKS
;
2590 case SESSION_STATE_STARTING_SINKS
:
2591 if (!session_is_output_nodes_state(session
, OBJ_STATE_STARTED
))
2594 session_set_started(session
);
2596 case SESSION_STATE_PAUSING_SINKS
:
2597 if (!session_is_output_nodes_state(session
, OBJ_STATE_PAUSED
))
2600 session
->state
= SESSION_STATE_PAUSING_SOURCES
;
2602 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2604 if (FAILED(hr
= IMFMediaSource_Pause(source
->source
)))
2609 session_set_paused(session
, hr
);
2612 case SESSION_STATE_STOPPING_SINKS
:
2613 if (!session_is_output_nodes_state(session
, OBJ_STATE_STOPPED
))
2616 session
->state
= SESSION_STATE_STOPPING_SOURCES
;
2618 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2620 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
)
2621 IMFMediaSource_Stop(source
->source
);
2622 else if (FAILED(hr
= IMFMediaSource_Stop(source
->source
)))
2626 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
|| FAILED(hr
))
2627 session_set_stopped(session
, hr
);
2635 static DWORD
transform_node_get_stream_id(struct topo_node
*node
, BOOL output
, DWORD index
)
2637 unsigned int *map
= output
? node
->u
.transform
.output_map
: node
->u
.transform
.input_map
;
2638 return map
? map
[index
] : index
;
2641 static struct sample
*transform_create_sample(IMFSample
*sample
)
2643 struct sample
*sample_entry
= heap_alloc_zero(sizeof(*sample_entry
));
2647 sample_entry
->sample
= sample
;
2648 if (sample_entry
->sample
)
2649 IMFSample_AddRef(sample_entry
->sample
);
2652 return sample_entry
;
2655 static HRESULT
transform_get_external_output_sample(const struct media_session
*session
, struct topo_node
*transform
,
2656 unsigned int output_index
, const MFT_OUTPUT_STREAM_INFO
*stream_info
, IMFSample
**sample
)
2658 IMFTopologyNode
*downstream_node
;
2659 unsigned int downstream_input
;
2660 IMFMediaBuffer
*buffer
= NULL
;
2661 struct topo_node
*topo_node
;
2665 if (FAILED(IMFTopologyNode_GetOutput(transform
->node
, output_index
, &downstream_node
, &downstream_input
)))
2667 WARN("Failed to get connected node for output %u.\n", output_index
);
2668 return MF_E_UNEXPECTED
;
2671 IMFTopologyNode_GetTopoNodeID(downstream_node
, &node_id
);
2672 IMFTopologyNode_Release(downstream_node
);
2674 topo_node
= session_get_node_by_id(session
, node_id
);
2676 if (topo_node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& topo_node
->u
.sink
.allocator
)
2678 hr
= IMFVideoSampleAllocator_AllocateSample(topo_node
->u
.sink
.allocator
, sample
);
2682 hr
= MFCreateAlignedMemoryBuffer(stream_info
->cbSize
, stream_info
->cbAlignment
, &buffer
);
2684 hr
= MFCreateSample(sample
);
2687 hr
= IMFSample_AddBuffer(*sample
, buffer
);
2690 IMFMediaBuffer_Release(buffer
);
2696 static HRESULT
transform_node_pull_samples(const struct media_session
*session
, struct topo_node
*node
)
2698 MFT_OUTPUT_STREAM_INFO stream_info
;
2699 MFT_OUTPUT_DATA_BUFFER
*buffers
;
2700 struct sample
*queued_sample
;
2703 HRESULT hr
= E_UNEXPECTED
;
2705 if (!(buffers
= heap_calloc(node
->u
.transform
.output_count
, sizeof(*buffers
))))
2706 return E_OUTOFMEMORY
;
2708 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2710 buffers
[i
].dwStreamID
= transform_node_get_stream_id(node
, TRUE
, i
);
2711 buffers
[i
].pSample
= NULL
;
2712 buffers
[i
].dwStatus
= 0;
2713 buffers
[i
].pEvents
= NULL
;
2715 memset(&stream_info
, 0, sizeof(stream_info
));
2716 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(node
->object
.transform
, buffers
[i
].dwStreamID
, &stream_info
)))
2719 if (!(stream_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
))
2721 if (FAILED(hr
= transform_get_external_output_sample(session
, node
, i
, &stream_info
, &buffers
[i
].pSample
)))
2727 hr
= IMFTransform_ProcessOutput(node
->object
.transform
, 0, node
->u
.transform
.output_count
, buffers
, &status
);
2729 /* Collect returned samples for all streams. */
2730 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2732 if (buffers
[i
].pEvents
)
2733 IMFCollection_Release(buffers
[i
].pEvents
);
2735 if (SUCCEEDED(hr
) && !(buffers
[i
].dwStatus
& MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE
))
2737 if (session
->quality_manager
)
2738 IMFQualityManager_NotifyProcessOutput(session
->quality_manager
, node
->node
, i
, buffers
[i
].pSample
);
2740 queued_sample
= transform_create_sample(buffers
[i
].pSample
);
2741 list_add_tail(&node
->u
.transform
.outputs
[i
].samples
, &queued_sample
->entry
);
2744 if (buffers
[i
].pSample
)
2745 IMFSample_Release(buffers
[i
].pSample
);
2753 static void session_deliver_sample_to_node(struct media_session
*session
, IMFTopologyNode
*node
, unsigned int input
,
2756 struct sample
*sample_entry
, *sample_entry2
;
2757 DWORD stream_id
, downstream_input
;
2758 IMFTopologyNode
*downstream_node
;
2759 struct topo_node
*topo_node
;
2760 MF_TOPOLOGY_TYPE node_type
;
2766 if (session
->quality_manager
)
2767 IMFQualityManager_NotifyProcessInput(session
->quality_manager
, node
, input
, sample
);
2769 IMFTopologyNode_GetNodeType(node
, &node_type
);
2770 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2772 topo_node
= session_get_node_by_id(session
, node_id
);
2776 case MF_TOPOLOGY_OUTPUT_NODE
:
2779 if (topo_node
->u
.sink
.requests
)
2781 if (FAILED(hr
= IMFStreamSink_ProcessSample(topo_node
->object
.sink_stream
, sample
)))
2782 WARN("Stream sink failed to process sample, hr %#x.\n", hr
);
2783 topo_node
->u
.sink
.requests
--;
2786 else if (FAILED(hr
= IMFStreamSink_PlaceMarker(topo_node
->object
.sink_stream
, MFSTREAMSINK_MARKER_ENDOFSEGMENT
,
2789 WARN("Failed to place sink marker, hr %#x.\n", hr
);
2792 case MF_TOPOLOGY_TRANSFORM_NODE
:
2794 transform_node_pull_samples(session
, topo_node
);
2796 sample_entry
= transform_create_sample(sample
);
2797 list_add_tail(&topo_node
->u
.transform
.inputs
[input
].samples
, &sample_entry
->entry
);
2799 for (i
= 0; i
< topo_node
->u
.transform
.input_count
; ++i
)
2801 stream_id
= transform_node_get_stream_id(topo_node
, FALSE
, i
);
2802 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.inputs
[i
].samples
,
2803 struct sample
, entry
)
2805 if (sample_entry
->sample
)
2807 if ((hr
= IMFTransform_ProcessInput(topo_node
->object
.transform
, stream_id
,
2808 sample_entry
->sample
, 0)) == MF_E_NOTACCEPTING
)
2811 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i
, stream_id
, hr
);
2812 transform_release_sample(sample_entry
);
2816 transform_stream_drop_samples(&topo_node
->u
.transform
.inputs
[i
]);
2824 if (FAILED(hr
= IMFTransform_ProcessMessage(topo_node
->object
.transform
, MFT_MESSAGE_COMMAND_DRAIN
, 0)))
2825 WARN("Drain command failed for transform, hr %#x.\n", hr
);
2828 transform_node_pull_samples(session
, topo_node
);
2830 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2833 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2835 if ((sample_entry
= transform_create_sample(NULL
)))
2836 list_add_tail(&topo_node
->u
.transform
.outputs
[i
].samples
, &sample_entry
->entry
);
2840 /* Push down all available output. */
2841 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2843 if (FAILED(IMFTopologyNode_GetOutput(node
, i
, &downstream_node
, &downstream_input
)))
2845 WARN("Failed to get connected node for output %u.\n", i
);
2849 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.outputs
[i
].samples
,
2850 struct sample
, entry
)
2852 if (!topo_node
->u
.transform
.outputs
[i
].requests
)
2855 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample_entry
->sample
);
2856 topo_node
->u
.transform
.outputs
[i
].requests
--;
2858 transform_release_sample(sample_entry
);
2861 IMFTopologyNode_Release(downstream_node
);
2865 case MF_TOPOLOGY_TEE_NODE
:
2866 FIXME("Unhandled downstream node type %d.\n", node_type
);
2873 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
)
2875 IMFTopologyNode
*downstream_node
, *upstream_node
;
2876 unsigned int downstream_input
, upstream_output
;
2877 struct topo_node
*topo_node
;
2878 MF_TOPOLOGY_TYPE node_type
;
2879 struct sample
*sample
;
2883 IMFTopologyNode_GetNodeType(node
, &node_type
);
2884 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2886 topo_node
= session_get_node_by_id(session
, node_id
);
2890 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
2891 if (FAILED(hr
= IMFMediaStream_RequestSample(topo_node
->object
.source_stream
, NULL
)))
2892 WARN("Sample request failed, hr %#x.\n", hr
);
2894 case MF_TOPOLOGY_TRANSFORM_NODE
:
2896 if (list_empty(&topo_node
->u
.transform
.outputs
[output
].samples
))
2898 /* Forward request to upstream node. */
2899 if (SUCCEEDED(hr
= IMFTopologyNode_GetInput(node
, 0 /* FIXME */, &upstream_node
, &upstream_output
)))
2901 if (SUCCEEDED(hr
= session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2902 topo_node
->u
.transform
.outputs
[output
].requests
++;
2903 IMFTopologyNode_Release(upstream_node
);
2908 if (SUCCEEDED(hr
= IMFTopologyNode_GetOutput(node
, output
, &downstream_node
, &downstream_input
)))
2910 sample
= LIST_ENTRY(list_head(&topo_node
->u
.transform
.outputs
[output
].samples
), struct sample
, entry
);
2911 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample
->sample
);
2912 transform_release_sample(sample
);
2913 IMFTopologyNode_Release(downstream_node
);
2918 case MF_TOPOLOGY_TEE_NODE
:
2919 FIXME("Unhandled upstream node type %d.\n", node_type
);
2927 static void session_request_sample(struct media_session
*session
, IMFStreamSink
*sink_stream
)
2929 struct topo_node
*sink_node
= NULL
, *node
;
2930 IMFTopologyNode
*upstream_node
;
2931 DWORD upstream_output
;
2934 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2936 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink_stream
)
2946 if (FAILED(hr
= IMFTopologyNode_GetInput(sink_node
->node
, 0, &upstream_node
, &upstream_output
)))
2948 WARN("Failed to get upstream node connection, hr %#x.\n", hr
);
2952 if (SUCCEEDED(session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2953 sink_node
->u
.sink
.requests
++;
2954 IMFTopologyNode_Release(upstream_node
);
2957 static void session_deliver_sample(struct media_session
*session
, IMFMediaStream
*stream
, const PROPVARIANT
*value
)
2959 struct topo_node
*source_node
= NULL
, *node
;
2960 IMFTopologyNode
*downstream_node
;
2961 DWORD downstream_input
;
2964 if (value
&& (value
->vt
!= VT_UNKNOWN
|| !value
->punkVal
))
2966 WARN("Unexpected value type %d.\n", value
->vt
);
2970 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2972 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->object
.source_stream
== stream
)
2983 source_node
->flags
|= TOPO_NODE_END_OF_STREAM
;
2985 if (FAILED(hr
= IMFTopologyNode_GetOutput(source_node
->node
, 0, &downstream_node
, &downstream_input
)))
2987 WARN("Failed to get downstream node connection, hr %#x.\n", hr
);
2991 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, value
? (IMFSample
*)value
->punkVal
: NULL
);
2992 IMFTopologyNode_Release(downstream_node
);
2995 static void session_sink_invalidated(struct media_session
*session
, IMFMediaEvent
*event
, IMFStreamSink
*sink
)
2997 struct topo_node
*node
, *sink_node
= NULL
;
3000 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3002 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink
)
3014 if (FAILED(hr
= MFCreateMediaEvent(MESinkInvalidated
, &GUID_NULL
, S_OK
, NULL
, &event
)))
3015 WARN("Failed to create event, hr %#x.\n", hr
);
3021 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_OUTPUT_NODE
, sink_node
->node_id
);
3022 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3024 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3027 static BOOL
session_nodes_is_mask_set(struct media_session
*session
, MF_TOPOLOGY_TYPE node_type
, unsigned int flags
)
3029 struct media_source
*source
;
3030 struct topo_node
*node
;
3032 if (node_type
== MF_TOPOLOGY_MAX
)
3034 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3036 if ((source
->flags
& flags
) != flags
)
3042 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3044 if (node
->type
== node_type
&& (node
->flags
& flags
) != flags
)
3052 static void session_raise_end_of_presentation(struct media_session
*session
)
3054 if (!(session_nodes_is_mask_set(session
, MF_TOPOLOGY_SOURCESTREAM_NODE
, TOPO_NODE_END_OF_STREAM
)))
3057 if (!(session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
))
3059 if (session_nodes_is_mask_set(session
, MF_TOPOLOGY_MAX
, SOURCE_FLAG_END_OF_PRESENTATION
))
3061 session
->presentation
.flags
|= SESSION_FLAG_END_OF_PRESENTATION
;
3062 session_push_back_command(session
, SESSION_CMD_END
);
3063 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MEEndOfPresentation
, &GUID_NULL
, S_OK
, NULL
);
3068 static void session_handle_end_of_stream(struct media_session
*session
, IMFMediaStream
*stream
)
3070 struct topo_node
*node
;
3072 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream
, MF_TOPOLOGY_SOURCESTREAM_NODE
))
3073 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3078 session_deliver_sample(session
, stream
, NULL
);
3080 session_raise_end_of_presentation(session
);
3083 static void session_handle_end_of_presentation(struct media_session
*session
, IMFMediaSource
*object
)
3085 struct media_source
*source
;
3087 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3089 if (source
->source
== object
)
3091 if (!(source
->flags
& SOURCE_FLAG_END_OF_PRESENTATION
))
3093 source
->flags
|= SOURCE_FLAG_END_OF_PRESENTATION
;
3094 session_raise_end_of_presentation(session
);
3102 static void session_sink_stream_marker(struct media_session
*session
, IMFStreamSink
*stream_sink
)
3104 struct topo_node
*node
;
3106 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
))
3107 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3112 node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3114 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
&&
3115 session_nodes_is_mask_set(session
, MF_TOPOLOGY_OUTPUT_NODE
, TOPO_NODE_END_OF_STREAM
))
3117 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3118 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
3119 session_stop(session
);
3123 static HRESULT WINAPI
session_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3125 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
3126 IMFMediaEventGenerator
*event_source
;
3127 IMFMediaEvent
*event
= NULL
;
3128 MediaEventType event_type
;
3129 IUnknown
*object
= NULL
;
3130 IMFMediaSource
*source
;
3131 IMFMediaStream
*stream
;
3135 if (FAILED(hr
= IMFAsyncResult_GetState(result
, (IUnknown
**)&event_source
)))
3138 if (FAILED(hr
= IMFMediaEventGenerator_EndGetEvent(event_source
, result
, &event
)))
3140 WARN("Failed to get event from %p, hr %#x.\n", event_source
, hr
);
3144 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
3146 WARN("Failed to get event type, hr %#x.\n", hr
);
3150 value
.vt
= VT_EMPTY
;
3151 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
3153 WARN("Failed to get event value, hr %#x.\n", hr
);
3159 case MESourceStarted
:
3160 case MESourcePaused
:
3161 case MESourceStopped
:
3162 case MEStreamStarted
:
3163 case MEStreamPaused
:
3164 case MEStreamStopped
:
3166 EnterCriticalSection(&session
->cs
);
3167 session_set_source_object_state(session
, (IUnknown
*)event_source
, event_type
);
3168 LeaveCriticalSection(&session
->cs
);
3172 case MEBufferingStarted
:
3173 case MEBufferingStopped
:
3175 EnterCriticalSection(&session
->cs
);
3176 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3178 if (event_type
== MEBufferingStarted
)
3179 IMFPresentationClock_Pause(session
->clock
);
3181 IMFPresentationClock_Start(session
->clock
, PRESENTATION_CURRENT_POSITION
);
3183 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3185 LeaveCriticalSection(&session
->cs
);
3189 stream
= (IMFMediaStream
*)value
.punkVal
;
3191 if (value
.vt
!= VT_UNKNOWN
|| !stream
)
3193 WARN("Unexpected event value.\n");
3197 if (FAILED(hr
= IMFMediaStream_GetMediaSource(stream
, &source
)))
3200 EnterCriticalSection(&session
->cs
);
3201 if (SUCCEEDED(hr
= session_add_media_stream(session
, source
, stream
)))
3202 hr
= IMFMediaStream_BeginGetEvent(stream
, &session
->events_callback
, (IUnknown
*)stream
);
3203 LeaveCriticalSection(&session
->cs
);
3205 IMFMediaSource_Release(source
);
3208 case MEStreamSinkStarted
:
3209 case MEStreamSinkPaused
:
3210 case MEStreamSinkStopped
:
3211 case MEStreamSinkPrerolled
:
3213 EnterCriticalSection(&session
->cs
);
3214 session_set_sink_stream_state(session
, (IMFStreamSink
*)event_source
, event_type
);
3215 LeaveCriticalSection(&session
->cs
);
3218 case MEStreamSinkMarker
:
3220 EnterCriticalSection(&session
->cs
);
3221 session_sink_stream_marker(session
, (IMFStreamSink
*)event_source
);
3222 LeaveCriticalSection(&session
->cs
);
3225 case MEStreamSinkRequestSample
:
3227 EnterCriticalSection(&session
->cs
);
3228 session_request_sample(session
, (IMFStreamSink
*)event_source
);
3229 LeaveCriticalSection(&session
->cs
);
3234 EnterCriticalSection(&session
->cs
);
3235 session_deliver_sample(session
, (IMFMediaStream
*)event_source
, &value
);
3236 LeaveCriticalSection(&session
->cs
);
3241 EnterCriticalSection(&session
->cs
);
3242 session_handle_end_of_stream(session
, (IMFMediaStream
*)event_source
);
3243 LeaveCriticalSection(&session
->cs
);
3247 case MEEndOfPresentation
:
3249 EnterCriticalSection(&session
->cs
);
3250 session_handle_end_of_presentation(session
, (IMFMediaSource
*)event_source
);
3251 LeaveCriticalSection(&session
->cs
);
3254 case MEAudioSessionGroupingParamChanged
:
3255 case MEAudioSessionIconChanged
:
3256 case MEAudioSessionNameChanged
:
3257 case MEAudioSessionVolumeChanged
:
3259 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3262 case MEAudioSessionDeviceRemoved
:
3263 case MEAudioSessionDisconnected
:
3264 case MEAudioSessionExclusiveModeOverride
:
3265 case MEAudioSessionFormatChanged
:
3266 case MEAudioSessionServerShutdown
:
3268 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3270 case MESinkInvalidated
:
3272 EnterCriticalSection(&session
->cs
);
3273 session_sink_invalidated(session
, event_type
== MESinkInvalidated
? event
: NULL
,
3274 (IMFStreamSink
*)event_source
);
3275 LeaveCriticalSection(&session
->cs
);
3278 case MEQualityNotify
:
3280 if (session
->quality_manager
)
3282 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFStreamSink
, (void **)&object
)))
3283 IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFTransform
, (void **)&object
);
3287 IMFQualityManager_NotifyQualityEvent(session
->quality_manager
, object
, event
);
3288 IUnknown_Release(object
);
3297 PropVariantClear(&value
);
3301 IMFMediaEvent_Release(event
);
3303 if (FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(event_source
, iface
, (IUnknown
*)event_source
)))
3304 WARN("Failed to re-subscribe, hr %#x.\n", hr
);
3306 IMFMediaEventGenerator_Release(event_source
);
3311 static const IMFAsyncCallbackVtbl session_events_callback_vtbl
=
3313 session_events_callback_QueryInterface
,
3314 session_events_callback_AddRef
,
3315 session_events_callback_Release
,
3316 session_events_callback_GetParameters
,
3317 session_events_callback_Invoke
,
3320 static HRESULT WINAPI
session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
3322 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
3323 IsEqualIID(riid
, &IID_IUnknown
))
3326 IMFAsyncCallback_AddRef(iface
);
3330 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3332 return E_NOINTERFACE
;
3335 static ULONG WINAPI
session_sink_finalizer_callback_AddRef(IMFAsyncCallback
*iface
)
3337 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3338 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3341 static ULONG WINAPI
session_sink_finalizer_callback_Release(IMFAsyncCallback
*iface
)
3343 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3344 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3347 static HRESULT WINAPI
session_sink_finalizer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
3352 static HRESULT WINAPI
session_sink_finalizer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3354 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3355 IMFFinalizableMediaSink
*fin_sink
= NULL
;
3356 BOOL sinks_finalized
= TRUE
;
3357 struct media_sink
*sink
;
3361 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
3364 EnterCriticalSection(&session
->cs
);
3366 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3368 if (state
== (IUnknown
*)sink
->sink
)
3370 if (FAILED(hr
= IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
3371 WARN("Unexpected, missing IMFFinalizableSink, hr %#x.\n", hr
);
3375 sinks_finalized
&= sink
->finalized
;
3376 if (!sinks_finalized
)
3381 IUnknown_Release(state
);
3385 /* Complete session transition, or close prematurely on error. */
3386 if (SUCCEEDED(hr
= IMFFinalizableMediaSink_EndFinalize(fin_sink
, result
)))
3388 sink
->finalized
= TRUE
;
3389 if (sinks_finalized
)
3390 session_set_closed(session
, hr
);
3392 IMFFinalizableMediaSink_Release(fin_sink
);
3395 LeaveCriticalSection(&session
->cs
);
3400 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl
=
3402 session_sink_finalizer_callback_QueryInterface
,
3403 session_sink_finalizer_callback_AddRef
,
3404 session_sink_finalizer_callback_Release
,
3405 session_sink_finalizer_callback_GetParameters
,
3406 session_sink_finalizer_callback_Invoke
,
3409 static HRESULT WINAPI
session_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
3411 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3412 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3415 static ULONG WINAPI
session_rate_support_AddRef(IMFRateSupport
*iface
)
3417 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3418 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3421 static ULONG WINAPI
session_rate_support_Release(IMFRateSupport
*iface
)
3423 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3424 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3427 static HRESULT
session_presentation_object_get_rate(IUnknown
*object
, MFRATE_DIRECTION direction
,
3428 BOOL thin
, BOOL fastest
, float *result
)
3430 IMFRateSupport
*rate_support
;
3434 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3436 if (FAILED(hr
= MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
3438 if (direction
== MFRATE_FORWARD
)
3444 return MF_E_REVERSE_UNSUPPORTED
;
3450 if (SUCCEEDED(hr
= IMFRateSupport_GetFastestRate(rate_support
, direction
, thin
, &rate
)))
3451 *result
= min(fabsf(rate
), *result
);
3455 if (SUCCEEDED(hr
= IMFRateSupport_GetSlowestRate(rate_support
, direction
, thin
, &rate
)))
3456 *result
= max(fabsf(rate
), *result
);
3459 IMFRateSupport_Release(rate_support
);
3464 static HRESULT
session_get_presentation_rate(struct media_session
*session
, MFRATE_DIRECTION direction
,
3465 BOOL thin
, BOOL fastest
, float *result
)
3467 struct media_source
*source
;
3468 struct media_sink
*sink
;
3469 HRESULT hr
= E_POINTER
;
3473 EnterCriticalSection(&session
->cs
);
3475 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
3477 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3479 if (FAILED(hr
= session_presentation_object_get_rate((IUnknown
*)source
->source
, direction
, thin
, fastest
, result
)))
3485 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3487 if (FAILED(hr
= session_presentation_object_get_rate((IUnknown
*)sink
->sink
, direction
, thin
, fastest
, result
)))
3493 LeaveCriticalSection(&session
->cs
);
3498 static HRESULT WINAPI
session_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3499 BOOL thin
, float *rate
)
3501 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3503 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3505 return session_get_presentation_rate(session
, direction
, thin
, FALSE
, rate
);
3508 static HRESULT WINAPI
session_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3509 BOOL thin
, float *rate
)
3511 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3513 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3515 return session_get_presentation_rate(session
, direction
, thin
, TRUE
, rate
);
3518 static HRESULT WINAPI
session_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
3519 float *nearest_supported_rate
)
3521 FIXME("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_supported_rate
);
3526 static const IMFRateSupportVtbl session_rate_support_vtbl
=
3528 session_rate_support_QueryInterface
,
3529 session_rate_support_AddRef
,
3530 session_rate_support_Release
,
3531 session_rate_support_GetSlowestRate
,
3532 session_rate_support_GetFastestRate
,
3533 session_rate_support_IsRateSupported
,
3536 static HRESULT WINAPI
session_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
3538 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3539 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3542 static ULONG WINAPI
session_rate_control_AddRef(IMFRateControl
*iface
)
3544 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3545 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3548 static ULONG WINAPI
session_rate_control_Release(IMFRateControl
*iface
)
3550 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3551 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3554 static HRESULT WINAPI
session_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
3556 FIXME("%p, %d, %f.\n", iface
, thin
, rate
);
3561 static HRESULT WINAPI
session_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
3563 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3565 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
3567 return IMFRateControl_GetRate(session
->clock_rate_control
, thin
, rate
);
3570 static const IMFRateControlVtbl session_rate_control_vtbl
=
3572 session_rate_control_QueryInterface
,
3573 session_rate_control_AddRef
,
3574 session_rate_control_Release
,
3575 session_rate_control_SetRate
,
3576 session_rate_control_GetRate
,
3579 static HRESULT WINAPI
node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor
*iface
,
3580 REFIID riid
, void **obj
)
3582 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
3584 if (IsEqualIID(riid
, &IID_IMFTopologyNodeAttributeEditor
) ||
3585 IsEqualIID(riid
, &IID_IUnknown
))
3588 IMFTopologyNodeAttributeEditor_AddRef(iface
);
3592 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
3594 return E_NOINTERFACE
;
3597 static ULONG WINAPI
node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor
*iface
)
3599 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
3600 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3603 static ULONG WINAPI
node_attribute_editor_Release(IMFTopologyNodeAttributeEditor
*iface
)
3605 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
3606 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3609 static HRESULT WINAPI
node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor
*iface
,
3610 TOPOID id
, DWORD count
, MFTOPONODE_ATTRIBUTE_UPDATE
*updates
)
3612 FIXME("%p, %s, %u, %p.\n", iface
, wine_dbgstr_longlong(id
), count
, updates
);
3617 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl
=
3619 node_attribute_editor_QueryInterface
,
3620 node_attribute_editor_AddRef
,
3621 node_attribute_editor_Release
,
3622 node_attribute_editor_UpdateNodeAttributes
,
3625 /***********************************************************************
3626 * MFCreateMediaSession (mf.@)
3628 HRESULT WINAPI
MFCreateMediaSession(IMFAttributes
*config
, IMFMediaSession
**session
)
3630 BOOL without_quality_manager
= FALSE
;
3631 struct media_session
*object
;
3634 TRACE("%p, %p.\n", config
, session
);
3636 object
= heap_alloc_zero(sizeof(*object
));
3638 return E_OUTOFMEMORY
;
3640 object
->IMFMediaSession_iface
.lpVtbl
= &mfmediasessionvtbl
;
3641 object
->IMFGetService_iface
.lpVtbl
= &session_get_service_vtbl
;
3642 object
->IMFRateSupport_iface
.lpVtbl
= &session_rate_support_vtbl
;
3643 object
->IMFRateControl_iface
.lpVtbl
= &session_rate_control_vtbl
;
3644 object
->IMFTopologyNodeAttributeEditor_iface
.lpVtbl
= &node_attribute_editor_vtbl
;
3645 object
->commands_callback
.lpVtbl
= &session_commands_callback_vtbl
;
3646 object
->events_callback
.lpVtbl
= &session_events_callback_vtbl
;
3647 object
->sink_finalizer_callback
.lpVtbl
= &session_sink_finalizer_callback_vtbl
;
3648 object
->refcount
= 1;
3649 list_init(&object
->topologies
);
3650 list_init(&object
->commands
);
3651 list_init(&object
->presentation
.sources
);
3652 list_init(&object
->presentation
.sinks
);
3653 list_init(&object
->presentation
.nodes
);
3654 InitializeCriticalSection(&object
->cs
);
3656 if (FAILED(hr
= MFCreateTopology(&object
->presentation
.current_topology
)))
3659 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
3662 if (FAILED(hr
= MFCreatePresentationClock(&object
->clock
)))
3665 if (FAILED(hr
= MFCreateSystemTimeSource(&object
->system_time_source
)))
3668 if (FAILED(hr
= IMFPresentationClock_QueryInterface(object
->clock
, &IID_IMFRateControl
,
3669 (void **)&object
->clock_rate_control
)))
3678 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_TOPOLOADER
, &clsid
)))
3680 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTopoLoader
,
3681 (void **)&object
->topo_loader
)))
3683 WARN("Failed to create custom topology loader, hr %#x.\n", hr
);
3687 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_QUALITY_MANAGER
, &clsid
)))
3689 if (!(without_quality_manager
= IsEqualGUID(&clsid
, &GUID_NULL
)))
3691 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFQualityManager
,
3692 (void **)&object
->quality_manager
)))
3694 WARN("Failed to create custom quality manager, hr %#x.\n", hr
);
3700 if (!object
->topo_loader
&& FAILED(hr
= MFCreateTopoLoader(&object
->topo_loader
)))
3703 if (!object
->quality_manager
&& !without_quality_manager
&&
3704 FAILED(hr
= MFCreateStandardQualityManager(&object
->quality_manager
)))
3709 if (object
->quality_manager
&& FAILED(hr
= IMFQualityManager_NotifyPresentationClock(object
->quality_manager
,
3715 *session
= &object
->IMFMediaSession_iface
;
3720 IMFMediaSession_Release(&object
->IMFMediaSession_iface
);
3724 static HRESULT WINAPI
sink_notification_QueryInterface(IUnknown
*iface
, REFIID riid
, void **out
)
3726 if (IsEqualIID(riid
, &IID_IUnknown
))
3729 IUnknown_AddRef(iface
);
3733 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3735 return E_NOINTERFACE
;
3738 static ULONG WINAPI
sink_notification_AddRef(IUnknown
*iface
)
3740 struct sink_notification
*notification
= impl_sink_notification_from_IUnknown(iface
);
3741 ULONG refcount
= InterlockedIncrement(¬ification
->refcount
);
3743 TRACE("%p, refcount %u.\n", iface
, refcount
);
3748 static ULONG WINAPI
sink_notification_Release(IUnknown
*iface
)
3750 struct sink_notification
*notification
= impl_sink_notification_from_IUnknown(iface
);
3751 ULONG refcount
= InterlockedDecrement(¬ification
->refcount
);
3753 TRACE("%p, refcount %u.\n", iface
, refcount
);
3757 IMFClockStateSink_Release(notification
->sink
);
3758 heap_free(notification
);
3764 static const IUnknownVtbl sinknotificationvtbl
=
3766 sink_notification_QueryInterface
,
3767 sink_notification_AddRef
,
3768 sink_notification_Release
,
3771 static void clock_notify_async_sink(struct presentation_clock
*clock
, MFTIME system_time
,
3772 struct clock_state_change_param param
, enum clock_notification notification
, IMFClockStateSink
*sink
)
3774 struct sink_notification
*object
;
3775 IMFAsyncResult
*result
;
3778 object
= heap_alloc(sizeof(*object
));
3782 object
->IUnknown_iface
.lpVtbl
= &sinknotificationvtbl
;
3783 object
->refcount
= 1;
3784 object
->system_time
= system_time
;
3785 object
->param
= param
;
3786 object
->notification
= notification
;
3787 object
->sink
= sink
;
3788 IMFClockStateSink_AddRef(object
->sink
);
3790 hr
= MFCreateAsyncResult(&object
->IUnknown_iface
, &clock
->sink_callback
, NULL
, &result
);
3791 IUnknown_Release(&object
->IUnknown_iface
);
3794 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD
, result
);
3795 IMFAsyncResult_Release(result
);
3799 static HRESULT WINAPI
present_clock_QueryInterface(IMFPresentationClock
*iface
, REFIID riid
, void **out
)
3801 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3803 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
3805 if (IsEqualIID(riid
, &IID_IMFPresentationClock
) ||
3806 IsEqualIID(riid
, &IID_IMFClock
) ||
3807 IsEqualIID(riid
, &IID_IUnknown
))
3809 *out
= &clock
->IMFPresentationClock_iface
;
3811 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
3813 *out
= &clock
->IMFRateControl_iface
;
3815 else if (IsEqualIID(riid
, &IID_IMFTimer
))
3817 *out
= &clock
->IMFTimer_iface
;
3819 else if (IsEqualIID(riid
, &IID_IMFShutdown
))
3821 *out
= &clock
->IMFShutdown_iface
;
3825 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3827 return E_NOINTERFACE
;
3830 IUnknown_AddRef((IUnknown
*)*out
);
3834 static ULONG WINAPI
present_clock_AddRef(IMFPresentationClock
*iface
)
3836 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3837 ULONG refcount
= InterlockedIncrement(&clock
->refcount
);
3839 TRACE("%p, refcount %u.\n", iface
, refcount
);
3844 static ULONG WINAPI
present_clock_Release(IMFPresentationClock
*iface
)
3846 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3847 ULONG refcount
= InterlockedDecrement(&clock
->refcount
);
3848 struct clock_timer
*timer
, *timer2
;
3849 struct clock_sink
*sink
, *sink2
;
3851 TRACE("%p, refcount %u.\n", iface
, refcount
);
3855 if (clock
->time_source
)
3856 IMFPresentationTimeSource_Release(clock
->time_source
);
3857 if (clock
->time_source_sink
)
3858 IMFClockStateSink_Release(clock
->time_source_sink
);
3859 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &clock
->sinks
, struct clock_sink
, entry
)
3861 list_remove(&sink
->entry
);
3862 IMFClockStateSink_Release(sink
->state_sink
);
3865 LIST_FOR_EACH_ENTRY_SAFE(timer
, timer2
, &clock
->timers
, struct clock_timer
, entry
)
3867 list_remove(&timer
->entry
);
3868 IUnknown_Release(&timer
->IUnknown_iface
);
3870 DeleteCriticalSection(&clock
->cs
);
3877 static HRESULT WINAPI
present_clock_GetClockCharacteristics(IMFPresentationClock
*iface
, DWORD
*flags
)
3879 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3880 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3882 TRACE("%p, %p.\n", iface
, flags
);
3884 EnterCriticalSection(&clock
->cs
);
3885 if (clock
->time_source
)
3886 hr
= IMFPresentationTimeSource_GetClockCharacteristics(clock
->time_source
, flags
);
3887 LeaveCriticalSection(&clock
->cs
);
3892 static HRESULT WINAPI
present_clock_GetCorrelatedTime(IMFPresentationClock
*iface
, DWORD reserved
,
3893 LONGLONG
*clock_time
, MFTIME
*system_time
)
3895 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3896 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3898 TRACE("%p, %#x, %p, %p.\n", iface
, reserved
, clock_time
, system_time
);
3900 EnterCriticalSection(&clock
->cs
);
3901 if (clock
->time_source
)
3902 hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, reserved
, clock_time
, system_time
);
3903 LeaveCriticalSection(&clock
->cs
);
3908 static HRESULT WINAPI
present_clock_GetContinuityKey(IMFPresentationClock
*iface
, DWORD
*key
)
3910 TRACE("%p, %p.\n", iface
, key
);
3917 static HRESULT WINAPI
present_clock_GetState(IMFPresentationClock
*iface
, DWORD reserved
, MFCLOCK_STATE
*state
)
3919 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3921 TRACE("%p, %#x, %p.\n", iface
, reserved
, state
);
3923 EnterCriticalSection(&clock
->cs
);
3924 *state
= clock
->state
;
3925 LeaveCriticalSection(&clock
->cs
);
3930 static HRESULT WINAPI
present_clock_GetProperties(IMFPresentationClock
*iface
, MFCLOCK_PROPERTIES
*props
)
3932 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3933 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3935 TRACE("%p, %p.\n", iface
, props
);
3937 EnterCriticalSection(&clock
->cs
);
3938 if (clock
->time_source
)
3939 hr
= IMFPresentationTimeSource_GetProperties(clock
->time_source
, props
);
3940 LeaveCriticalSection(&clock
->cs
);
3945 static HRESULT WINAPI
present_clock_SetTimeSource(IMFPresentationClock
*iface
,
3946 IMFPresentationTimeSource
*time_source
)
3948 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3949 MFCLOCK_PROPERTIES props
;
3950 IMFClock
*source_clock
;
3953 TRACE("%p, %p.\n", iface
, time_source
);
3955 EnterCriticalSection(&clock
->cs
);
3957 if (clock
->time_source
)
3958 IMFPresentationTimeSource_Release(clock
->time_source
);
3959 if (clock
->time_source_sink
)
3960 IMFClockStateSink_Release(clock
->time_source_sink
);
3961 clock
->time_source
= NULL
;
3962 clock
->time_source_sink
= NULL
;
3964 hr
= IMFPresentationTimeSource_QueryInterface(time_source
, &IID_IMFClockStateSink
, (void **)&clock
->time_source_sink
);
3967 clock
->time_source
= time_source
;
3968 IMFPresentationTimeSource_AddRef(clock
->time_source
);
3971 if (SUCCEEDED(IMFPresentationTimeSource_GetUnderlyingClock(time_source
, &source_clock
)))
3973 if (SUCCEEDED(IMFClock_GetProperties(source_clock
, &props
)))
3974 clock
->frequency
= props
.qwClockFrequency
;
3975 IMFClock_Release(source_clock
);
3978 if (!clock
->frequency
)
3979 clock
->frequency
= MFCLOCK_FREQUENCY_HNS
;
3981 LeaveCriticalSection(&clock
->cs
);
3986 static HRESULT WINAPI
present_clock_GetTimeSource(IMFPresentationClock
*iface
,
3987 IMFPresentationTimeSource
**time_source
)
3989 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3992 TRACE("%p, %p.\n", iface
, time_source
);
3995 return E_INVALIDARG
;
3997 EnterCriticalSection(&clock
->cs
);
3998 if (clock
->time_source
)
4000 *time_source
= clock
->time_source
;
4001 IMFPresentationTimeSource_AddRef(*time_source
);
4004 hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
4005 LeaveCriticalSection(&clock
->cs
);
4010 static HRESULT WINAPI
present_clock_GetTime(IMFPresentationClock
*iface
, MFTIME
*time
)
4012 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4013 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
4016 TRACE("%p, %p.\n", iface
, time
);
4021 EnterCriticalSection(&clock
->cs
);
4022 if (clock
->time_source
)
4023 hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, 0, time
, &systime
);
4024 LeaveCriticalSection(&clock
->cs
);
4029 static HRESULT WINAPI
present_clock_AddClockStateSink(IMFPresentationClock
*iface
, IMFClockStateSink
*state_sink
)
4031 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4032 struct clock_sink
*sink
, *cur
;
4035 TRACE("%p, %p.\n", iface
, state_sink
);
4038 return E_INVALIDARG
;
4040 sink
= heap_alloc(sizeof(*sink
));
4042 return E_OUTOFMEMORY
;
4044 sink
->state_sink
= state_sink
;
4045 IMFClockStateSink_AddRef(sink
->state_sink
);
4047 EnterCriticalSection(&clock
->cs
);
4048 LIST_FOR_EACH_ENTRY(cur
, &clock
->sinks
, struct clock_sink
, entry
)
4050 if (cur
->state_sink
== state_sink
)
4058 static const enum clock_notification notifications
[MFCLOCK_STATE_PAUSED
+ 1] =
4060 /* MFCLOCK_STATE_INVALID */ 0, /* Does not apply */
4061 /* MFCLOCK_STATE_RUNNING */ CLOCK_NOTIFY_START
,
4062 /* MFCLOCK_STATE_STOPPED */ CLOCK_NOTIFY_STOP
,
4063 /* MFCLOCK_STATE_PAUSED */ CLOCK_NOTIFY_PAUSE
,
4065 struct clock_state_change_param param
;
4067 if (!clock
->is_shut_down
&& clock
->state
!= MFCLOCK_STATE_INVALID
)
4069 param
.u
.offset
= clock
->start_offset
;
4070 clock_notify_async_sink(clock
, MFGetSystemTime(), param
, notifications
[clock
->state
], sink
->state_sink
);
4073 list_add_tail(&clock
->sinks
, &sink
->entry
);
4075 LeaveCriticalSection(&clock
->cs
);
4079 IMFClockStateSink_Release(sink
->state_sink
);
4086 static HRESULT WINAPI
present_clock_RemoveClockStateSink(IMFPresentationClock
*iface
,
4087 IMFClockStateSink
*state_sink
)
4089 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4090 struct clock_sink
*sink
;
4092 TRACE("%p, %p.\n", iface
, state_sink
);
4095 return E_INVALIDARG
;
4097 EnterCriticalSection(&clock
->cs
);
4098 LIST_FOR_EACH_ENTRY(sink
, &clock
->sinks
, struct clock_sink
, entry
)
4100 if (sink
->state_sink
== state_sink
)
4102 IMFClockStateSink_Release(sink
->state_sink
);
4103 list_remove(&sink
->entry
);
4108 LeaveCriticalSection(&clock
->cs
);
4113 static HRESULT
clock_call_state_change(MFTIME system_time
, struct clock_state_change_param param
,
4114 enum clock_notification notification
, IMFClockStateSink
*sink
)
4118 switch (notification
)
4120 case CLOCK_NOTIFY_START
:
4121 hr
= IMFClockStateSink_OnClockStart(sink
, system_time
, param
.u
.offset
);
4123 case CLOCK_NOTIFY_STOP
:
4124 hr
= IMFClockStateSink_OnClockStop(sink
, system_time
);
4126 case CLOCK_NOTIFY_PAUSE
:
4127 hr
= IMFClockStateSink_OnClockPause(sink
, system_time
);
4129 case CLOCK_NOTIFY_RESTART
:
4130 hr
= IMFClockStateSink_OnClockRestart(sink
, system_time
);
4132 case CLOCK_NOTIFY_SET_RATE
:
4133 /* System time source does not allow 0.0 rate, presentation clock allows it without raising errors. */
4134 IMFClockStateSink_OnClockSetRate(sink
, system_time
, param
.u
.rate
);
4143 static HRESULT
clock_change_state(struct presentation_clock
*clock
, enum clock_command command
,
4144 struct clock_state_change_param param
)
4146 static const BYTE state_change_is_allowed
[MFCLOCK_STATE_PAUSED
+1][CLOCK_CMD_MAX
] =
4148 /* INVALID */ { 1, 1, 1, 1 },
4149 /* RUNNING */ { 1, 1, 1, 1 },
4150 /* STOPPED */ { 1, 1, 0, 1 },
4151 /* PAUSED */ { 1, 1, 0, 1 },
4153 static const MFCLOCK_STATE states
[CLOCK_CMD_MAX
] =
4155 /* CLOCK_CMD_START */ MFCLOCK_STATE_RUNNING
,
4156 /* CLOCK_CMD_STOP */ MFCLOCK_STATE_STOPPED
,
4157 /* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED
,
4158 /* CLOCK_CMD_SET_RATE */ 0, /* Unused */
4160 static const enum clock_notification notifications
[CLOCK_CMD_MAX
] =
4162 /* CLOCK_CMD_START */ CLOCK_NOTIFY_START
,
4163 /* CLOCK_CMD_STOP */ CLOCK_NOTIFY_STOP
,
4164 /* CLOCK_CMD_PAUSE */ CLOCK_NOTIFY_PAUSE
,
4165 /* CLOCK_CMD_SET_RATE */ CLOCK_NOTIFY_SET_RATE
,
4167 enum clock_notification notification
;
4168 struct clock_sink
*sink
;
4169 MFCLOCK_STATE old_state
;
4170 IMFAsyncResult
*result
;
4174 if (!clock
->time_source
)
4175 return MF_E_CLOCK_NO_TIME_SOURCE
;
4177 if (command
!= CLOCK_CMD_SET_RATE
&& clock
->state
== states
[command
] && clock
->state
!= MFCLOCK_STATE_RUNNING
)
4178 return MF_E_CLOCK_STATE_ALREADY_SET
;
4180 if (!state_change_is_allowed
[clock
->state
][command
])
4181 return MF_E_INVALIDREQUEST
;
4183 system_time
= MFGetSystemTime();
4185 if (command
== CLOCK_CMD_START
&& clock
->state
== MFCLOCK_STATE_PAUSED
&&
4186 param
.u
.offset
== PRESENTATION_CURRENT_POSITION
)
4188 notification
= CLOCK_NOTIFY_RESTART
;
4191 notification
= notifications
[command
];
4193 if (FAILED(hr
= clock_call_state_change(system_time
, param
, notification
, clock
->time_source_sink
)))
4196 old_state
= clock
->state
;
4197 if (command
!= CLOCK_CMD_SET_RATE
)
4198 clock
->state
= states
[command
];
4200 /* Dump all pending timer requests immediately on start; otherwise try to cancel scheduled items when
4201 transitioning from running state. */
4202 if ((clock
->state
== MFCLOCK_STATE_RUNNING
) ^ (old_state
== MFCLOCK_STATE_RUNNING
))
4204 struct clock_timer
*timer
, *timer2
;
4206 if (clock
->state
== MFCLOCK_STATE_RUNNING
)
4208 LIST_FOR_EACH_ENTRY_SAFE(timer
, timer2
, &clock
->timers
, struct clock_timer
, entry
)
4210 list_remove(&timer
->entry
);
4211 hr
= MFCreateAsyncResult(&timer
->IUnknown_iface
, &clock
->timer_callback
, NULL
, &result
);
4212 IUnknown_Release(&timer
->IUnknown_iface
);
4215 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_TIMER
, result
);
4216 IMFAsyncResult_Release(result
);
4222 LIST_FOR_EACH_ENTRY(timer
, &clock
->timers
, struct clock_timer
, entry
)
4226 MFCancelWorkItem(timer
->key
);
4233 LIST_FOR_EACH_ENTRY(sink
, &clock
->sinks
, struct clock_sink
, entry
)
4235 clock_notify_async_sink(clock
, system_time
, param
, notification
, sink
->state_sink
);
4241 static HRESULT WINAPI
present_clock_Start(IMFPresentationClock
*iface
, LONGLONG start_offset
)
4243 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4244 struct clock_state_change_param param
= {{0}};
4247 TRACE("%p, %s.\n", iface
, debugstr_time(start_offset
));
4249 EnterCriticalSection(&clock
->cs
);
4250 clock
->start_offset
= param
.u
.offset
= start_offset
;
4251 hr
= clock_change_state(clock
, CLOCK_CMD_START
, param
);
4252 LeaveCriticalSection(&clock
->cs
);
4257 static HRESULT WINAPI
present_clock_Stop(IMFPresentationClock
*iface
)
4259 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4260 struct clock_state_change_param param
= {{0}};
4263 TRACE("%p.\n", iface
);
4265 EnterCriticalSection(&clock
->cs
);
4266 hr
= clock_change_state(clock
, CLOCK_CMD_STOP
, param
);
4267 LeaveCriticalSection(&clock
->cs
);
4272 static HRESULT WINAPI
present_clock_Pause(IMFPresentationClock
*iface
)
4274 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4275 struct clock_state_change_param param
= {{0}};
4278 TRACE("%p.\n", iface
);
4280 EnterCriticalSection(&clock
->cs
);
4281 hr
= clock_change_state(clock
, CLOCK_CMD_PAUSE
, param
);
4282 LeaveCriticalSection(&clock
->cs
);
4287 static const IMFPresentationClockVtbl presentationclockvtbl
=
4289 present_clock_QueryInterface
,
4290 present_clock_AddRef
,
4291 present_clock_Release
,
4292 present_clock_GetClockCharacteristics
,
4293 present_clock_GetCorrelatedTime
,
4294 present_clock_GetContinuityKey
,
4295 present_clock_GetState
,
4296 present_clock_GetProperties
,
4297 present_clock_SetTimeSource
,
4298 present_clock_GetTimeSource
,
4299 present_clock_GetTime
,
4300 present_clock_AddClockStateSink
,
4301 present_clock_RemoveClockStateSink
,
4302 present_clock_Start
,
4304 present_clock_Pause
,
4307 static HRESULT WINAPI
present_clock_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **out
)
4309 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4310 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
4313 static ULONG WINAPI
present_clock_rate_control_AddRef(IMFRateControl
*iface
)
4315 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4316 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4319 static ULONG WINAPI
present_clock_rate_control_Release(IMFRateControl
*iface
)
4321 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4322 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4325 static HRESULT WINAPI
present_clock_rate_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
4327 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4328 struct clock_state_change_param param
;
4331 TRACE("%p, %d, %f.\n", iface
, thin
, rate
);
4334 return MF_E_THINNING_UNSUPPORTED
;
4336 EnterCriticalSection(&clock
->cs
);
4337 param
.u
.rate
= rate
;
4338 if (SUCCEEDED(hr
= clock_change_state(clock
, CLOCK_CMD_SET_RATE
, param
)))
4340 LeaveCriticalSection(&clock
->cs
);
4345 static HRESULT WINAPI
present_clock_rate_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
4347 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4349 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
4352 return E_INVALIDARG
;
4357 EnterCriticalSection(&clock
->cs
);
4358 *rate
= clock
->rate
;
4359 LeaveCriticalSection(&clock
->cs
);
4364 static const IMFRateControlVtbl presentclockratecontrolvtbl
=
4366 present_clock_rate_control_QueryInterface
,
4367 present_clock_rate_control_AddRef
,
4368 present_clock_rate_control_Release
,
4369 present_clock_rate_SetRate
,
4370 present_clock_rate_GetRate
,
4373 static HRESULT WINAPI
present_clock_timer_QueryInterface(IMFTimer
*iface
, REFIID riid
, void **out
)
4375 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4376 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
4379 static ULONG WINAPI
present_clock_timer_AddRef(IMFTimer
*iface
)
4381 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4382 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4385 static ULONG WINAPI
present_clock_timer_Release(IMFTimer
*iface
)
4387 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4388 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4391 static HRESULT
present_clock_schedule_timer(struct presentation_clock
*clock
, DWORD flags
, LONGLONG time
,
4392 struct clock_timer
*timer
)
4394 IMFAsyncResult
*result
;
4395 MFTIME systime
, clocktime
;
4399 if (!(flags
& MFTIMER_RELATIVE
))
4401 if (FAILED(hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, 0, &clocktime
, &systime
)))
4403 WARN("Failed to get clock time, hr %#x.\n", hr
);
4409 frequency
= clock
->frequency
/ 1000;
4412 /* Scheduled item is using clock instance callback, with timer instance as an object. Clock callback will
4413 call user callback and cleanup timer list. */
4415 if (FAILED(hr
= MFCreateAsyncResult(&timer
->IUnknown_iface
, &clock
->timer_callback
, NULL
, &result
)))
4418 hr
= MFScheduleWorkItemEx(result
, -time
, &timer
->key
);
4419 IMFAsyncResult_Release(result
);
4424 static HRESULT WINAPI
clock_timer_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
4426 if (IsEqualIID(riid
, &IID_IUnknown
))
4429 IUnknown_AddRef(iface
);
4434 return E_NOINTERFACE
;
4437 static ULONG WINAPI
clock_timer_AddRef(IUnknown
*iface
)
4439 struct clock_timer
*timer
= impl_clock_timer_from_IUnknown(iface
);
4440 return InterlockedIncrement(&timer
->refcount
);
4443 static ULONG WINAPI
clock_timer_Release(IUnknown
*iface
)
4445 struct clock_timer
*timer
= impl_clock_timer_from_IUnknown(iface
);
4446 ULONG refcount
= InterlockedDecrement(&timer
->refcount
);
4450 IMFAsyncResult_Release(timer
->result
);
4451 IMFAsyncCallback_Release(timer
->callback
);
4458 static const IUnknownVtbl clock_timer_vtbl
=
4460 clock_timer_QueryInterface
,
4462 clock_timer_Release
,
4465 static HRESULT WINAPI
present_clock_timer_SetTimer(IMFTimer
*iface
, DWORD flags
, LONGLONG time
,
4466 IMFAsyncCallback
*callback
, IUnknown
*state
, IUnknown
**cancel_key
)
4468 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4469 struct clock_timer
*clock_timer
;
4472 TRACE("%p, %#x, %s, %p, %p, %p.\n", iface
, flags
, debugstr_time(time
), callback
, state
, cancel_key
);
4474 if (!(clock_timer
= heap_alloc_zero(sizeof(*clock_timer
))))
4475 return E_OUTOFMEMORY
;
4477 if (FAILED(hr
= MFCreateAsyncResult(NULL
, NULL
, state
, &clock_timer
->result
)))
4479 heap_free(clock_timer
);
4483 clock_timer
->IUnknown_iface
.lpVtbl
= &clock_timer_vtbl
;
4484 clock_timer
->refcount
= 1;
4485 clock_timer
->callback
= callback
;
4486 IMFAsyncCallback_AddRef(clock_timer
->callback
);
4488 EnterCriticalSection(&clock
->cs
);
4490 if (clock
->state
== MFCLOCK_STATE_RUNNING
)
4491 hr
= present_clock_schedule_timer(clock
, flags
, time
, clock_timer
);
4492 else if (clock
->state
== MFCLOCK_STATE_STOPPED
)
4493 hr
= MF_S_CLOCK_STOPPED
;
4497 list_add_tail(&clock
->timers
, &clock_timer
->entry
);
4500 *cancel_key
= &clock_timer
->IUnknown_iface
;
4501 IUnknown_AddRef(*cancel_key
);
4505 LeaveCriticalSection(&clock
->cs
);
4508 IUnknown_Release(&clock_timer
->IUnknown_iface
);
4513 static HRESULT WINAPI
present_clock_timer_CancelTimer(IMFTimer
*iface
, IUnknown
*cancel_key
)
4515 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4516 struct clock_timer
*timer
;
4518 TRACE("%p, %p.\n", iface
, cancel_key
);
4520 EnterCriticalSection(&clock
->cs
);
4522 LIST_FOR_EACH_ENTRY(timer
, &clock
->timers
, struct clock_timer
, entry
)
4524 if (&timer
->IUnknown_iface
== cancel_key
)
4526 list_remove(&timer
->entry
);
4529 MFCancelWorkItem(timer
->key
);
4532 IUnknown_Release(&timer
->IUnknown_iface
);
4537 LeaveCriticalSection(&clock
->cs
);
4542 static const IMFTimerVtbl presentclocktimervtbl
=
4544 present_clock_timer_QueryInterface
,
4545 present_clock_timer_AddRef
,
4546 present_clock_timer_Release
,
4547 present_clock_timer_SetTimer
,
4548 present_clock_timer_CancelTimer
,
4551 static HRESULT WINAPI
present_clock_shutdown_QueryInterface(IMFShutdown
*iface
, REFIID riid
, void **out
)
4553 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4554 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
4557 static ULONG WINAPI
present_clock_shutdown_AddRef(IMFShutdown
*iface
)
4559 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4560 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4563 static ULONG WINAPI
present_clock_shutdown_Release(IMFShutdown
*iface
)
4565 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4566 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4569 static HRESULT WINAPI
present_clock_shutdown_Shutdown(IMFShutdown
*iface
)
4571 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4573 TRACE("%p.\n", iface
);
4575 EnterCriticalSection(&clock
->cs
);
4576 clock
->is_shut_down
= TRUE
;
4577 LeaveCriticalSection(&clock
->cs
);
4582 static HRESULT WINAPI
present_clock_shutdown_GetShutdownStatus(IMFShutdown
*iface
, MFSHUTDOWN_STATUS
*status
)
4584 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4587 TRACE("%p, %p.\n", iface
, status
);
4590 return E_INVALIDARG
;
4592 EnterCriticalSection(&clock
->cs
);
4593 if (clock
->is_shut_down
)
4594 *status
= MFSHUTDOWN_COMPLETED
;
4596 hr
= MF_E_INVALIDREQUEST
;
4597 LeaveCriticalSection(&clock
->cs
);
4602 static const IMFShutdownVtbl presentclockshutdownvtbl
=
4604 present_clock_shutdown_QueryInterface
,
4605 present_clock_shutdown_AddRef
,
4606 present_clock_shutdown_Release
,
4607 present_clock_shutdown_Shutdown
,
4608 present_clock_shutdown_GetShutdownStatus
,
4611 static HRESULT WINAPI
present_clock_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **out
)
4613 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
4614 IsEqualIID(riid
, &IID_IUnknown
))
4617 IMFAsyncCallback_AddRef(iface
);
4621 WARN("Unsupported %s.\n", wine_dbgstr_guid(riid
));
4623 return E_NOINTERFACE
;
4626 static ULONG WINAPI
present_clock_sink_callback_AddRef(IMFAsyncCallback
*iface
)
4628 struct presentation_clock
*clock
= impl_from_sink_callback_IMFAsyncCallback(iface
);
4629 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4632 static ULONG WINAPI
present_clock_sink_callback_Release(IMFAsyncCallback
*iface
)
4634 struct presentation_clock
*clock
= impl_from_sink_callback_IMFAsyncCallback(iface
);
4635 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4638 static HRESULT WINAPI
present_clock_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
4643 static HRESULT WINAPI
present_clock_sink_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
4645 struct sink_notification
*data
;
4649 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &object
)))
4652 data
= impl_sink_notification_from_IUnknown(object
);
4654 clock_call_state_change(data
->system_time
, data
->param
, data
->notification
, data
->sink
);
4656 IUnknown_Release(object
);
4661 static const IMFAsyncCallbackVtbl presentclocksinkcallbackvtbl
=
4663 present_clock_callback_QueryInterface
,
4664 present_clock_sink_callback_AddRef
,
4665 present_clock_sink_callback_Release
,
4666 present_clock_callback_GetParameters
,
4667 present_clock_sink_callback_Invoke
,
4670 static ULONG WINAPI
present_clock_timer_callback_AddRef(IMFAsyncCallback
*iface
)
4672 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
4673 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4676 static ULONG WINAPI
present_clock_timer_callback_Release(IMFAsyncCallback
*iface
)
4678 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
4679 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4682 static HRESULT WINAPI
present_clock_timer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
4684 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
4685 struct clock_timer
*timer
;
4689 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &object
)))
4692 timer
= impl_clock_timer_from_IUnknown(object
);
4694 EnterCriticalSection(&clock
->cs
);
4695 list_remove(&timer
->entry
);
4696 IUnknown_Release(&timer
->IUnknown_iface
);
4697 LeaveCriticalSection(&clock
->cs
);
4699 IMFAsyncCallback_Invoke(timer
->callback
, timer
->result
);
4701 IUnknown_Release(object
);
4706 static const IMFAsyncCallbackVtbl presentclocktimercallbackvtbl
=
4708 present_clock_callback_QueryInterface
,
4709 present_clock_timer_callback_AddRef
,
4710 present_clock_timer_callback_Release
,
4711 present_clock_callback_GetParameters
,
4712 present_clock_timer_callback_Invoke
,
4715 /***********************************************************************
4716 * MFCreatePresentationClock (mf.@)
4718 HRESULT WINAPI
MFCreatePresentationClock(IMFPresentationClock
**clock
)
4720 struct presentation_clock
*object
;
4722 TRACE("%p.\n", clock
);
4724 object
= heap_alloc_zero(sizeof(*object
));
4726 return E_OUTOFMEMORY
;
4728 object
->IMFPresentationClock_iface
.lpVtbl
= &presentationclockvtbl
;
4729 object
->IMFRateControl_iface
.lpVtbl
= &presentclockratecontrolvtbl
;
4730 object
->IMFTimer_iface
.lpVtbl
= &presentclocktimervtbl
;
4731 object
->IMFShutdown_iface
.lpVtbl
= &presentclockshutdownvtbl
;
4732 object
->sink_callback
.lpVtbl
= &presentclocksinkcallbackvtbl
;
4733 object
->timer_callback
.lpVtbl
= &presentclocktimercallbackvtbl
;
4734 object
->refcount
= 1;
4735 list_init(&object
->sinks
);
4736 list_init(&object
->timers
);
4737 object
->rate
= 1.0f
;
4738 InitializeCriticalSection(&object
->cs
);
4740 *clock
= &object
->IMFPresentationClock_iface
;
4745 static HRESULT WINAPI
standard_quality_manager_QueryInterface(IMFQualityManager
*iface
, REFIID riid
, void **out
)
4747 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
4749 if (IsEqualIID(riid
, &IID_IMFQualityManager
) ||
4750 IsEqualIID(riid
, &IID_IUnknown
))
4753 IMFQualityManager_AddRef(iface
);
4757 WARN("Unsupported %s.\n", debugstr_guid(riid
));
4759 return E_NOINTERFACE
;
4762 static ULONG WINAPI
standard_quality_manager_AddRef(IMFQualityManager
*iface
)
4764 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
4765 ULONG refcount
= InterlockedIncrement(&manager
->refcount
);
4767 TRACE("%p, refcount %u.\n", iface
, refcount
);
4772 static ULONG WINAPI
standard_quality_manager_Release(IMFQualityManager
*iface
)
4774 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
4775 ULONG refcount
= InterlockedDecrement(&manager
->refcount
);
4777 TRACE("%p, refcount %u.\n", iface
, refcount
);
4782 IMFPresentationClock_Release(manager
->clock
);
4783 DeleteCriticalSection(&manager
->cs
);
4790 static HRESULT WINAPI
standard_quality_manager_NotifyTopology(IMFQualityManager
*iface
, IMFTopology
*topology
)
4792 FIXME("%p, %p stub.\n", iface
, topology
);
4797 static HRESULT WINAPI
standard_quality_manager_NotifyPresentationClock(IMFQualityManager
*iface
,
4798 IMFPresentationClock
*clock
)
4800 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
4802 TRACE("%p, %p.\n", iface
, clock
);
4807 EnterCriticalSection(&manager
->cs
);
4809 IMFPresentationClock_Release(manager
->clock
);
4810 manager
->clock
= clock
;
4811 IMFPresentationClock_AddRef(manager
->clock
);
4812 LeaveCriticalSection(&manager
->cs
);
4817 static HRESULT WINAPI
standard_quality_manager_NotifyProcessInput(IMFQualityManager
*iface
, IMFTopologyNode
*node
,
4818 LONG input_index
, IMFSample
*sample
)
4820 TRACE("%p, %p, %d, %p stub.\n", iface
, node
, input_index
, sample
);
4825 static HRESULT WINAPI
standard_quality_manager_NotifyProcessOutput(IMFQualityManager
*iface
, IMFTopologyNode
*node
,
4826 LONG output_index
, IMFSample
*sample
)
4828 TRACE("%p, %p, %d, %p stub.\n", iface
, node
, output_index
, sample
);
4833 static HRESULT WINAPI
standard_quality_manager_NotifyQualityEvent(IMFQualityManager
*iface
, IUnknown
*object
,
4834 IMFMediaEvent
*event
)
4836 FIXME("%p, %p, %p stub.\n", iface
, object
, event
);
4841 static HRESULT WINAPI
standard_quality_manager_Shutdown(IMFQualityManager
*iface
)
4843 FIXME("%p stub.\n", iface
);
4848 static IMFQualityManagerVtbl standard_quality_manager_vtbl
=
4850 standard_quality_manager_QueryInterface
,
4851 standard_quality_manager_AddRef
,
4852 standard_quality_manager_Release
,
4853 standard_quality_manager_NotifyTopology
,
4854 standard_quality_manager_NotifyPresentationClock
,
4855 standard_quality_manager_NotifyProcessInput
,
4856 standard_quality_manager_NotifyProcessOutput
,
4857 standard_quality_manager_NotifyQualityEvent
,
4858 standard_quality_manager_Shutdown
,
4861 HRESULT WINAPI
MFCreateStandardQualityManager(IMFQualityManager
**manager
)
4863 struct quality_manager
*object
;
4865 TRACE("%p.\n", manager
);
4867 object
= heap_alloc_zero(sizeof(*object
));
4869 return E_OUTOFMEMORY
;
4871 object
->IMFQualityManager_iface
.lpVtbl
= &standard_quality_manager_vtbl
;
4872 object
->refcount
= 1;
4873 InitializeCriticalSection(&object
->cs
);
4875 *manager
= &object
->IMFQualityManager_iface
;