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
30 #include "wine/debug.h"
31 #include "wine/heap.h"
32 #include "wine/list.h"
34 #include "mf_private.h"
38 DEFINE_GUID(_MF_TOPONODE_IMFActivate
, 0x33706f4a, 0x309a, 0x49be, 0xa8, 0xdd, 0xe7, 0xc0, 0x87, 0x5e, 0xb6, 0x79);
40 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
44 SESSION_CMD_CLEAR_TOPOLOGIES
,
46 SESSION_CMD_SET_TOPOLOGY
,
50 /* Internally used commands. */
52 SESSION_CMD_QM_NOTIFY_TOPOLOGY
,
58 IUnknown IUnknown_iface
;
60 enum session_command command
;
66 IMFTopology
*topology
;
71 PROPVARIANT start_position
;
75 IMFTopology
*topology
;
85 struct queued_topology
88 IMFTopology
*topology
;
94 SESSION_STATE_STOPPED
= 0,
95 SESSION_STATE_STARTING_SOURCES
,
96 SESSION_STATE_PREROLLING_SINKS
,
97 SESSION_STATE_STARTING_SINKS
,
98 SESSION_STATE_STARTED
,
99 SESSION_STATE_PAUSING_SINKS
,
100 SESSION_STATE_PAUSING_SOURCES
,
101 SESSION_STATE_PAUSED
,
102 SESSION_STATE_STOPPING_SINKS
,
103 SESSION_STATE_STOPPING_SOURCES
,
104 SESSION_STATE_FINALIZING_SINKS
,
105 SESSION_STATE_CLOSED
,
106 SESSION_STATE_SHUT_DOWN
,
111 OBJ_STATE_STOPPED
= 0,
118 enum media_source_flags
120 SOURCE_FLAG_END_OF_PRESENTATION
= 0x1,
126 IMFMediaSource
*source
;
127 IMFPresentationDescriptor
*pd
;
128 enum object_state state
;
136 IMFMediaSinkPreroll
*preroll
;
137 IMFMediaEventGenerator
*event_generator
;
147 struct transform_stream
150 unsigned int requests
;
151 unsigned int min_buffer_size
;
156 TOPO_NODE_END_OF_STREAM
= 0x1,
162 struct media_session
*session
;
163 MF_TOPOLOGY_TYPE type
;
165 IMFTopologyNode
*node
;
166 enum object_state state
;
170 IMFMediaStream
*source_stream
;
171 IMFStreamSink
*sink_stream
;
172 IMFTransform
*transform
;
180 IMFMediaSource
*source
;
181 unsigned int stream_id
;
185 unsigned int requests
;
186 IMFVideoSampleAllocatorNotify notify_cb
;
187 IMFVideoSampleAllocator
*allocator
;
188 IMFVideoSampleAllocatorCallback
*allocator_cb
;
192 struct transform_stream
*inputs
;
193 unsigned int *input_map
;
194 unsigned int input_count
;
196 struct transform_stream
*outputs
;
197 unsigned int *output_map
;
198 unsigned int output_count
;
203 enum presentation_flags
205 SESSION_FLAG_SOURCES_SUBSCRIBED
= 0x1,
206 SESSION_FLAG_PRESENTATION_CLOCK_SET
= 0x2,
207 SESSION_FLAG_FINALIZE_SINKS
= 0x4,
208 SESSION_FLAG_NEEDS_PREROLL
= 0x8,
209 SESSION_FLAG_END_OF_PRESENTATION
= 0x10,
214 IMFMediaSession IMFMediaSession_iface
;
215 IMFGetService IMFGetService_iface
;
216 IMFRateSupport IMFRateSupport_iface
;
217 IMFRateControl IMFRateControl_iface
;
218 IMFTopologyNodeAttributeEditor IMFTopologyNodeAttributeEditor_iface
;
219 IMFAsyncCallback commands_callback
;
220 IMFAsyncCallback events_callback
;
221 IMFAsyncCallback sink_finalizer_callback
;
223 IMFMediaEventQueue
*event_queue
;
224 IMFPresentationClock
*clock
;
225 IMFPresentationTimeSource
*system_time_source
;
226 IMFRateControl
*clock_rate_control
;
227 IMFTopoLoader
*topo_loader
;
228 IMFQualityManager
*quality_manager
;
231 IMFTopology
*current_topology
;
232 MF_TOPOSTATUS topo_status
;
233 MFTIME clock_stop_time
;
239 /* Latest Start() arguments. */
241 PROPVARIANT start_position
;
243 struct list topologies
;
244 struct list commands
;
245 enum session_state state
;
253 IMFClockStateSink
*state_sink
;
265 enum clock_notification
270 CLOCK_NOTIFY_RESTART
,
271 CLOCK_NOTIFY_SET_RATE
,
274 struct clock_state_change_param
283 struct sink_notification
285 IUnknown IUnknown_iface
;
288 struct clock_state_change_param param
;
289 enum clock_notification notification
;
290 IMFClockStateSink
*sink
;
295 IUnknown IUnknown_iface
;
297 IMFAsyncResult
*result
;
298 IMFAsyncCallback
*callback
;
303 struct presentation_clock
305 IMFPresentationClock IMFPresentationClock_iface
;
306 IMFRateControl IMFRateControl_iface
;
307 IMFTimer IMFTimer_iface
;
308 IMFShutdown IMFShutdown_iface
;
309 IMFAsyncCallback sink_callback
;
310 IMFAsyncCallback timer_callback
;
312 IMFPresentationTimeSource
*time_source
;
313 IMFClockStateSink
*time_source_sink
;
315 LONGLONG start_offset
;
324 enum quality_manager_state
326 QUALITY_MANAGER_READY
= 0,
327 QUALITY_MANAGER_SHUT_DOWN
,
330 struct quality_manager
332 IMFQualityManager IMFQualityManager_iface
;
333 IMFClockStateSink IMFClockStateSink_iface
;
336 IMFTopology
*topology
;
337 IMFPresentationClock
*clock
;
342 static inline struct media_session
*impl_from_IMFMediaSession(IMFMediaSession
*iface
)
344 return CONTAINING_RECORD(iface
, struct media_session
, IMFMediaSession_iface
);
347 static struct media_session
*impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
349 return CONTAINING_RECORD(iface
, struct media_session
, commands_callback
);
352 static struct media_session
*impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
354 return CONTAINING_RECORD(iface
, struct media_session
, events_callback
);
357 static struct media_session
*impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
359 return CONTAINING_RECORD(iface
, struct media_session
, sink_finalizer_callback
);
362 static struct media_session
*impl_from_IMFGetService(IMFGetService
*iface
)
364 return CONTAINING_RECORD(iface
, struct media_session
, IMFGetService_iface
);
367 static struct media_session
*impl_session_from_IMFRateSupport(IMFRateSupport
*iface
)
369 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateSupport_iface
);
372 static struct media_session
*impl_session_from_IMFRateControl(IMFRateControl
*iface
)
374 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateControl_iface
);
377 static struct media_session
*impl_session_from_IMFTopologyNodeAttributeEditor(IMFTopologyNodeAttributeEditor
*iface
)
379 return CONTAINING_RECORD(iface
, struct media_session
, IMFTopologyNodeAttributeEditor_iface
);
382 static struct session_op
*impl_op_from_IUnknown(IUnknown
*iface
)
384 return CONTAINING_RECORD(iface
, struct session_op
, IUnknown_iface
);
387 static struct presentation_clock
*impl_from_IMFPresentationClock(IMFPresentationClock
*iface
)
389 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFPresentationClock_iface
);
392 static struct presentation_clock
*impl_from_IMFRateControl(IMFRateControl
*iface
)
394 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFRateControl_iface
);
397 static struct presentation_clock
*impl_from_IMFTimer(IMFTimer
*iface
)
399 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFTimer_iface
);
402 static struct presentation_clock
*impl_from_IMFShutdown(IMFShutdown
*iface
)
404 return CONTAINING_RECORD(iface
, struct presentation_clock
, IMFShutdown_iface
);
407 static struct presentation_clock
*impl_from_sink_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
409 return CONTAINING_RECORD(iface
, struct presentation_clock
, sink_callback
);
412 static struct presentation_clock
*impl_from_timer_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
414 return CONTAINING_RECORD(iface
, struct presentation_clock
, timer_callback
);
417 static struct clock_timer
*impl_clock_timer_from_IUnknown(IUnknown
*iface
)
419 return CONTAINING_RECORD(iface
, struct clock_timer
, IUnknown_iface
);
422 static struct sink_notification
*impl_sink_notification_from_IUnknown(IUnknown
*iface
)
424 return CONTAINING_RECORD(iface
, struct sink_notification
, IUnknown_iface
);
427 static struct quality_manager
*impl_from_IMFQualityManager(IMFQualityManager
*iface
)
429 return CONTAINING_RECORD(iface
, struct quality_manager
, IMFQualityManager_iface
);
432 static struct quality_manager
*impl_from_qm_IMFClockStateSink(IMFClockStateSink
*iface
)
434 return CONTAINING_RECORD(iface
, struct quality_manager
, IMFClockStateSink_iface
);
437 static struct topo_node
*impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify
*iface
)
439 return CONTAINING_RECORD(iface
, struct topo_node
, u
.sink
.notify_cb
);
442 /* IMFLocalMFTRegistration */
443 static HRESULT WINAPI
local_mft_registration_QueryInterface(IMFLocalMFTRegistration
*iface
, REFIID riid
, void **obj
)
445 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
447 if (IsEqualIID(riid
, &IID_IMFLocalMFTRegistration
) ||
448 IsEqualIID(riid
, &IID_IUnknown
))
451 IMFLocalMFTRegistration_AddRef(iface
);
455 WARN("Unexpected %s.\n", debugstr_guid(riid
));
457 return E_NOINTERFACE
;
460 static ULONG WINAPI
local_mft_registration_AddRef(IMFLocalMFTRegistration
*iface
)
465 static ULONG WINAPI
local_mft_registration_Release(IMFLocalMFTRegistration
*iface
)
470 static HRESULT WINAPI
local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration
*iface
, MFT_REGISTRATION_INFO
*info
,
476 TRACE("%p, %p, %u.\n", iface
, info
, count
);
478 for (i
= 0; i
< count
; ++i
)
480 if (FAILED(hr
= MFTRegisterLocalByCLSID(&info
[i
].clsid
, &info
[i
].guidCategory
, info
[i
].pszName
,
481 info
[i
].uiFlags
, info
[i
].cInTypes
, info
[i
].pInTypes
, info
[i
].cOutTypes
, info
[i
].pOutTypes
)))
490 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl
=
492 local_mft_registration_QueryInterface
,
493 local_mft_registration_AddRef
,
494 local_mft_registration_Release
,
495 local_mft_registration_RegisterMFTs
,
498 static IMFLocalMFTRegistration local_mft_registration
= { &local_mft_registration_vtbl
};
500 static HRESULT WINAPI
session_op_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
502 if (IsEqualIID(riid
, &IID_IUnknown
))
505 IUnknown_AddRef(iface
);
510 return E_NOINTERFACE
;
513 static ULONG WINAPI
session_op_AddRef(IUnknown
*iface
)
515 struct session_op
*op
= impl_op_from_IUnknown(iface
);
516 ULONG refcount
= InterlockedIncrement(&op
->refcount
);
518 TRACE("%p, refcount %u.\n", iface
, refcount
);
523 static ULONG WINAPI
session_op_Release(IUnknown
*iface
)
525 struct session_op
*op
= impl_op_from_IUnknown(iface
);
526 ULONG refcount
= InterlockedDecrement(&op
->refcount
);
528 TRACE("%p, refcount %u.\n", iface
, refcount
);
534 case SESSION_CMD_SET_TOPOLOGY
:
535 if (op
->u
.set_topology
.topology
)
536 IMFTopology_Release(op
->u
.set_topology
.topology
);
538 case SESSION_CMD_START
:
539 PropVariantClear(&op
->u
.start
.start_position
);
541 case SESSION_CMD_QM_NOTIFY_TOPOLOGY
:
542 if (op
->u
.notify_topology
.topology
)
543 IMFTopology_Release(op
->u
.notify_topology
.topology
);
554 static const IUnknownVtbl session_op_vtbl
=
556 session_op_QueryInterface
,
561 static HRESULT
create_session_op(enum session_command command
, struct session_op
**ret
)
563 struct session_op
*op
;
565 if (!(op
= heap_alloc_zero(sizeof(*op
))))
566 return E_OUTOFMEMORY
;
568 op
->IUnknown_iface
.lpVtbl
= &session_op_vtbl
;
570 op
->command
= command
;
577 static HRESULT
session_is_shut_down(struct media_session
*session
)
579 return session
->state
== SESSION_STATE_SHUT_DOWN
? MF_E_SHUTDOWN
: S_OK
;
582 static void session_push_back_command(struct media_session
*session
, enum session_command command
)
584 struct session_op
*op
;
586 if (SUCCEEDED(create_session_op(command
, &op
)))
587 list_add_head(&session
->commands
, &op
->entry
);
590 static HRESULT
session_submit_command(struct media_session
*session
, struct session_op
*op
)
594 EnterCriticalSection(&session
->cs
);
595 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
597 if (list_empty(&session
->commands
))
598 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
599 list_add_tail(&session
->commands
, &op
->entry
);
600 IUnknown_AddRef(&op
->IUnknown_iface
);
602 LeaveCriticalSection(&session
->cs
);
607 static HRESULT
session_submit_simple_command(struct media_session
*session
, enum session_command command
)
609 struct session_op
*op
;
612 if (FAILED(hr
= create_session_op(command
, &op
)))
615 hr
= session_submit_command(session
, op
);
616 IUnknown_Release(&op
->IUnknown_iface
);
620 static void session_clear_topologies(struct media_session
*session
)
622 struct queued_topology
*ptr
, *next
;
624 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &session
->topologies
, struct queued_topology
, entry
)
626 list_remove(&ptr
->entry
);
627 IMFTopology_Release(ptr
->topology
);
632 static void session_set_topo_status(struct media_session
*session
, HRESULT status
,
633 MF_TOPOSTATUS topo_status
)
635 IMFMediaEvent
*event
;
638 if (topo_status
== MF_TOPOSTATUS_INVALID
)
641 if (list_empty(&session
->topologies
))
643 FIXME("Unexpectedly empty topology queue.\n");
647 if (topo_status
> session
->presentation
.topo_status
)
649 struct queued_topology
*topology
= LIST_ENTRY(list_head(&session
->topologies
), struct queued_topology
, entry
);
651 param
.vt
= VT_UNKNOWN
;
652 param
.punkVal
= (IUnknown
*)topology
->topology
;
654 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus
, &GUID_NULL
, status
, ¶m
, &event
)))
657 session
->presentation
.topo_status
= topo_status
;
659 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_TOPOLOGY_STATUS
, topo_status
);
660 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
661 IMFMediaEvent_Release(event
);
665 static HRESULT
session_bind_output_nodes(IMFTopology
*topology
)
667 MF_TOPOLOGY_TYPE node_type
;
668 IMFStreamSink
*stream_sink
;
669 IMFMediaSink
*media_sink
;
670 WORD node_count
= 0, i
;
671 IMFTopologyNode
*node
;
672 IMFActivate
*activate
;
677 hr
= IMFTopology_GetNodeCount(topology
, &node_count
);
679 for (i
= 0; i
< node_count
; ++i
)
681 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
684 if (FAILED(hr
= IMFTopologyNode_GetNodeType(node
, &node_type
)) || node_type
!= MF_TOPOLOGY_OUTPUT_NODE
)
686 IMFTopologyNode_Release(node
);
690 if (SUCCEEDED(hr
= IMFTopologyNode_GetObject(node
, &object
)))
693 if (FAILED(IUnknown_QueryInterface(object
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
695 if (SUCCEEDED(hr
= IUnknown_QueryInterface(object
, &IID_IMFActivate
, (void **)&activate
)))
697 if (SUCCEEDED(hr
= IMFActivate_ActivateObject(activate
, &IID_IMFMediaSink
, (void **)&media_sink
)))
699 if (FAILED(IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_STREAMID
, &stream_id
)))
703 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink
, stream_id
, &stream_sink
)))
704 hr
= IMFMediaSink_AddStreamSink(media_sink
, stream_id
, NULL
, &stream_sink
);
707 hr
= IMFTopologyNode_SetObject(node
, (IUnknown
*)stream_sink
);
709 IMFMediaSink_Release(media_sink
);
713 IMFTopologyNode_SetUnknown(node
, &_MF_TOPONODE_IMFActivate
, (IUnknown
*)activate
);
715 IMFActivate_Release(activate
);
720 IMFStreamSink_Release(stream_sink
);
721 IUnknown_Release(object
);
724 IMFTopologyNode_Release(node
);
730 static void session_set_caps(struct media_session
*session
, DWORD caps
)
732 DWORD delta
= session
->caps
^ caps
;
733 IMFMediaEvent
*event
;
735 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
736 them to, since session always queries for current object rates. */
740 session
->caps
= caps
;
742 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged
, &GUID_NULL
, S_OK
, NULL
, &event
)))
745 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS
, caps
);
746 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS_DELTA
, delta
);
748 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
749 IMFMediaEvent_Release(event
);
752 static void transform_release_sample(struct sample
*sample
)
754 list_remove(&sample
->entry
);
756 IMFSample_Release(sample
->sample
);
760 static void transform_stream_drop_samples(struct transform_stream
*stream
)
762 struct sample
*sample
, *sample2
;
764 LIST_FOR_EACH_ENTRY_SAFE(sample
, sample2
, &stream
->samples
, struct sample
, entry
)
765 transform_release_sample(sample
);
768 static void release_topo_node(struct topo_node
*node
)
774 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
775 if (node
->u
.source
.source
)
776 IMFMediaSource_Release(node
->u
.source
.source
);
778 case MF_TOPOLOGY_TRANSFORM_NODE
:
779 for (i
= 0; i
< node
->u
.transform
.input_count
; ++i
)
780 transform_stream_drop_samples(&node
->u
.transform
.inputs
[i
]);
781 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
782 transform_stream_drop_samples(&node
->u
.transform
.outputs
[i
]);
783 heap_free(node
->u
.transform
.inputs
);
784 heap_free(node
->u
.transform
.outputs
);
785 heap_free(node
->u
.transform
.input_map
);
786 heap_free(node
->u
.transform
.output_map
);
788 case MF_TOPOLOGY_OUTPUT_NODE
:
789 if (node
->u
.sink
.allocator
)
790 IMFVideoSampleAllocator_Release(node
->u
.sink
.allocator
);
791 if (node
->u
.sink
.allocator_cb
)
793 IMFVideoSampleAllocatorCallback_SetCallback(node
->u
.sink
.allocator_cb
, NULL
);
794 IMFVideoSampleAllocatorCallback_Release(node
->u
.sink
.allocator_cb
);
801 if (node
->object
.object
)
802 IUnknown_Release(node
->object
.object
);
804 IMFTopologyNode_Release(node
->node
);
808 static void session_shutdown_current_topology(struct media_session
*session
)
810 unsigned int shutdown
, force_shutdown
;
811 MF_TOPOLOGY_TYPE node_type
;
812 IMFStreamSink
*stream_sink
;
813 IMFTopology
*topology
;
814 IMFTopologyNode
*node
;
815 IMFActivate
*activate
;
820 topology
= session
->presentation
.current_topology
;
821 force_shutdown
= session
->state
== SESSION_STATE_SHUT_DOWN
;
823 /* FIXME: should handle async MFTs, but these are not supported by the rest of the pipeline currently. */
825 while (SUCCEEDED(IMFTopology_GetNode(topology
, idx
++, &node
)))
827 if (SUCCEEDED(IMFTopologyNode_GetNodeType(node
, &node_type
)) &&
828 node_type
== MF_TOPOLOGY_OUTPUT_NODE
)
831 IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, &shutdown
);
833 if (force_shutdown
|| shutdown
)
835 if (SUCCEEDED(IMFTopologyNode_GetUnknown(node
, &_MF_TOPONODE_IMFActivate
, &IID_IMFActivate
,
836 (void **)&activate
)))
838 if (FAILED(hr
= IMFActivate_ShutdownObject(activate
)))
839 WARN("Failed to shut down activation object for the sink, hr %#x.\n", hr
);
840 IMFActivate_Release(activate
);
842 else if (SUCCEEDED(topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
844 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink
, &sink
)))
846 IMFMediaSink_Shutdown(sink
);
847 IMFMediaSink_Release(sink
);
850 IMFStreamSink_Release(stream_sink
);
855 IMFTopologyNode_Release(node
);
859 static void session_clear_command_list(struct media_session
*session
)
861 struct session_op
*op
, *op2
;
863 LIST_FOR_EACH_ENTRY_SAFE(op
, op2
, &session
->commands
, struct session_op
, entry
)
865 list_remove(&op
->entry
);
866 IUnknown_Release(&op
->IUnknown_iface
);
870 static void session_clear_presentation(struct media_session
*session
)
872 struct media_source
*source
, *source2
;
873 struct media_sink
*sink
, *sink2
;
874 struct topo_node
*node
, *node2
;
876 session_shutdown_current_topology(session
);
878 IMFTopology_Clear(session
->presentation
.current_topology
);
879 session
->presentation
.topo_status
= MF_TOPOSTATUS_INVALID
;
881 LIST_FOR_EACH_ENTRY_SAFE(source
, source2
, &session
->presentation
.sources
, struct media_source
, entry
)
883 list_remove(&source
->entry
);
885 IMFMediaSource_Release(source
->source
);
887 IMFPresentationDescriptor_Release(source
->pd
);
891 LIST_FOR_EACH_ENTRY_SAFE(node
, node2
, &session
->presentation
.nodes
, struct topo_node
, entry
)
893 list_remove(&node
->entry
);
894 release_topo_node(node
);
897 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &session
->presentation
.sinks
, struct media_sink
, entry
)
899 list_remove(&sink
->entry
);
902 IMFMediaSink_Release(sink
->sink
);
904 IMFMediaSinkPreroll_Release(sink
->preroll
);
905 if (sink
->event_generator
)
906 IMFMediaEventGenerator_Release(sink
->event_generator
);
911 static struct topo_node
*session_get_node_by_id(const struct media_session
*session
, TOPOID id
)
913 struct topo_node
*node
;
915 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
917 if (node
->node_id
== id
)
924 static void session_start(struct media_session
*session
, const GUID
*time_format
, const PROPVARIANT
*start_position
)
926 struct media_source
*source
;
929 switch (session
->state
)
931 case SESSION_STATE_STOPPED
:
932 case SESSION_STATE_PAUSED
:
934 session
->presentation
.time_format
= *time_format
;
935 session
->presentation
.start_position
.vt
= VT_EMPTY
;
936 PropVariantCopy(&session
->presentation
.start_position
, start_position
);
938 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
940 if (!(session
->presentation
.flags
& SESSION_FLAG_SOURCES_SUBSCRIBED
))
942 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(source
->source
, &session
->events_callback
,
943 (IUnknown
*)source
->source
)))
945 WARN("Failed to subscribe to source events, hr %#x.\n", hr
);
949 if (FAILED(hr
= IMFMediaSource_Start(source
->source
, source
->pd
, &GUID_NULL
, start_position
)))
950 WARN("Failed to start media source %p, hr %#x.\n", source
->source
, hr
);
953 session
->presentation
.flags
|= SESSION_FLAG_SOURCES_SUBSCRIBED
;
954 session
->state
= SESSION_STATE_STARTING_SOURCES
;
956 case SESSION_STATE_STARTED
:
957 FIXME("Seeking is not implemented.\n");
959 case SESSION_STATE_CLOSED
:
960 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionStarted
, &GUID_NULL
,
961 MF_E_INVALIDREQUEST
, NULL
);
968 static void session_command_complete(struct media_session
*session
)
970 struct session_op
*op
;
973 /* Pop current command, submit next. */
974 if ((e
= list_head(&session
->commands
)))
976 op
= LIST_ENTRY(e
, struct session_op
, entry
);
977 list_remove(&op
->entry
);
978 IUnknown_Release(&op
->IUnknown_iface
);
981 if ((e
= list_head(&session
->commands
)))
983 op
= LIST_ENTRY(e
, struct session_op
, entry
);
984 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
988 static void session_set_started(struct media_session
*session
)
990 struct media_source
*source
;
991 unsigned int caps
, flags
;
992 IMFMediaEvent
*event
;
994 session
->state
= SESSION_STATE_STARTED
;
996 caps
= session
->caps
| MFSESSIONCAP_PAUSE
;
998 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1000 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &flags
)))
1002 if (!(flags
& MFMEDIASOURCE_CAN_PAUSE
))
1004 caps
&= ~MFSESSIONCAP_PAUSE
;
1010 session_set_caps(session
, caps
);
1012 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted
, &GUID_NULL
, S_OK
, NULL
, &event
)))
1014 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
1015 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
1016 IMFMediaEvent_Release(event
);
1018 session_command_complete(session
);
1021 static void session_set_paused(struct media_session
*session
, HRESULT status
)
1023 session
->state
= SESSION_STATE_PAUSED
;
1024 if (SUCCEEDED(status
))
1025 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
1026 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionPaused
, &GUID_NULL
, status
, NULL
);
1027 session_command_complete(session
);
1030 static void session_set_closed(struct media_session
*session
, HRESULT status
)
1032 session
->state
= SESSION_STATE_CLOSED
;
1033 if (SUCCEEDED(status
))
1034 session_set_caps(session
, session
->caps
& ~(MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
));
1035 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionClosed
, &GUID_NULL
, status
, NULL
);
1036 session_command_complete(session
);
1039 static void session_pause(struct media_session
*session
)
1043 switch (session
->state
)
1045 case SESSION_STATE_STARTED
:
1047 /* Transition in two steps - pause the clock, wait for sinks, then pause sources. */
1048 if (SUCCEEDED(hr
= IMFPresentationClock_Pause(session
->clock
)))
1049 session
->state
= SESSION_STATE_PAUSING_SINKS
;
1053 hr
= MF_E_INVALIDREQUEST
;
1057 session_set_paused(session
, hr
);
1060 static void session_set_stopped(struct media_session
*session
, HRESULT status
)
1062 MediaEventType event_type
;
1063 IMFMediaEvent
*event
;
1065 session
->state
= SESSION_STATE_STOPPED
;
1066 event_type
= session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
? MESessionEnded
: MESessionStopped
;
1068 if (SUCCEEDED(MFCreateMediaEvent(event_type
, &GUID_NULL
, status
, NULL
, &event
)))
1070 IMFMediaEvent_SetUINT64(event
, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME
, session
->presentation
.clock_stop_time
);
1071 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
1072 IMFMediaEvent_Release(event
);
1074 session_command_complete(session
);
1077 static void session_stop(struct media_session
*session
)
1079 HRESULT hr
= MF_E_INVALIDREQUEST
;
1081 switch (session
->state
)
1083 case SESSION_STATE_STARTED
:
1084 case SESSION_STATE_PAUSED
:
1086 /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */
1087 IMFPresentationClock_GetTime(session
->clock
, &session
->presentation
.clock_stop_time
);
1088 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1089 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1091 session_set_stopped(session
, hr
);
1094 case SESSION_STATE_STOPPED
:
1098 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionStopped
, &GUID_NULL
, hr
, NULL
);
1099 session_command_complete(session
);
1104 static HRESULT
session_finalize_sinks(struct media_session
*session
)
1106 IMFFinalizableMediaSink
*fin_sink
;
1107 BOOL sinks_finalized
= TRUE
;
1108 struct media_sink
*sink
;
1111 session
->presentation
.flags
&= ~SESSION_FLAG_FINALIZE_SINKS
;
1112 session
->state
= SESSION_STATE_FINALIZING_SINKS
;
1114 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1116 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
1118 hr
= IMFFinalizableMediaSink_BeginFinalize(fin_sink
, &session
->sink_finalizer_callback
,
1119 (IUnknown
*)fin_sink
);
1120 IMFFinalizableMediaSink_Release(fin_sink
);
1123 sinks_finalized
= FALSE
;
1126 sink
->finalized
= TRUE
;
1129 if (sinks_finalized
)
1130 session_set_closed(session
, hr
);
1135 static void session_close(struct media_session
*session
)
1139 switch (session
->state
)
1141 case SESSION_STATE_STOPPED
:
1142 hr
= session_finalize_sinks(session
);
1144 case SESSION_STATE_STARTED
:
1145 case SESSION_STATE_PAUSED
:
1146 session
->presentation
.flags
|= SESSION_FLAG_FINALIZE_SINKS
;
1147 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1148 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1151 hr
= MF_E_INVALIDREQUEST
;
1156 session_set_closed(session
, hr
);
1159 static struct media_source
*session_get_media_source(struct media_session
*session
, IMFMediaSource
*source
)
1161 struct media_source
*cur
;
1163 LIST_FOR_EACH_ENTRY(cur
, &session
->presentation
.sources
, struct media_source
, entry
)
1165 if (source
== cur
->source
)
1172 static void session_release_media_source(struct media_source
*source
)
1174 IMFMediaSource_Release(source
->source
);
1176 IMFPresentationDescriptor_Release(source
->pd
);
1180 static HRESULT
session_add_media_source(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSource
*source
)
1182 struct media_source
*media_source
;
1185 if (session_get_media_source(session
, source
))
1188 if (!(media_source
= heap_alloc_zero(sizeof(*media_source
))))
1189 return E_OUTOFMEMORY
;
1191 media_source
->source
= source
;
1192 IMFMediaSource_AddRef(media_source
->source
);
1194 hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
, &IID_IMFPresentationDescriptor
,
1195 (void **)&media_source
->pd
);
1198 list_add_tail(&session
->presentation
.sources
, &media_source
->entry
);
1200 session_release_media_source(media_source
);
1205 static void session_raise_topology_set(struct media_session
*session
, IMFTopology
*topology
, HRESULT status
)
1209 param
.vt
= topology
? VT_UNKNOWN
: VT_EMPTY
;
1210 param
.punkVal
= (IUnknown
*)topology
;
1212 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologySet
, &GUID_NULL
, status
, ¶m
);
1215 static DWORD
session_get_object_rate_caps(IUnknown
*object
)
1217 IMFRateSupport
*rate_support
;
1221 if (SUCCEEDED(MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
1224 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_FORWARD
, TRUE
, &rate
)) && rate
!= 0.0f
)
1225 caps
|= MFSESSIONCAP_RATE_FORWARD
;
1228 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_REVERSE
, TRUE
, &rate
)) && rate
!= 0.0f
)
1229 caps
|= MFSESSIONCAP_RATE_REVERSE
;
1231 IMFRateSupport_Release(rate_support
);
1237 static HRESULT
session_add_media_sink(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSink
*sink
)
1239 struct media_sink
*media_sink
;
1240 unsigned int disable_preroll
= 0;
1243 LIST_FOR_EACH_ENTRY(media_sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1245 if (sink
== media_sink
->sink
)
1249 if (!(media_sink
= heap_alloc_zero(sizeof(*media_sink
))))
1250 return E_OUTOFMEMORY
;
1252 media_sink
->sink
= sink
;
1253 IMFMediaSink_AddRef(media_sink
->sink
);
1255 IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaEventGenerator
, (void **)&media_sink
->event_generator
);
1257 IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_DISABLE_PREROLL
, &disable_preroll
);
1258 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
, &flags
)) && flags
& MEDIASINK_CAN_PREROLL
&& !disable_preroll
)
1260 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaSinkPreroll
, (void **)&media_sink
->preroll
)))
1261 session
->presentation
.flags
|= SESSION_FLAG_NEEDS_PREROLL
;
1264 list_add_tail(&session
->presentation
.sinks
, &media_sink
->entry
);
1269 static unsigned int transform_node_get_stream_id(struct topo_node
*node
, BOOL output
, unsigned int index
)
1271 unsigned int *map
= output
? node
->u
.transform
.output_map
: node
->u
.transform
.input_map
;
1272 return map
? map
[index
] : index
;
1275 static HRESULT
session_set_transform_stream_info(struct topo_node
*node
)
1277 unsigned int *input_map
= NULL
, *output_map
= NULL
;
1278 unsigned int i
, input_count
, output_count
, block_alignment
;
1279 struct transform_stream
*streams
;
1280 IMFMediaType
*media_type
;
1284 hr
= IMFTransform_GetStreamCount(node
->object
.transform
, &input_count
, &output_count
);
1285 if (SUCCEEDED(hr
) && (input_count
> 1 || output_count
> 1))
1287 input_map
= heap_calloc(input_count
, sizeof(*input_map
));
1288 output_map
= heap_calloc(output_count
, sizeof(*output_map
));
1289 if (FAILED(IMFTransform_GetStreamIDs(node
->object
.transform
, input_count
, input_map
,
1290 output_count
, output_map
)))
1292 /* Assume sequential identifiers. */
1293 heap_free(input_map
);
1294 heap_free(output_map
);
1295 input_map
= output_map
= NULL
;
1301 node
->u
.transform
.input_map
= input_map
;
1302 node
->u
.transform
.output_map
= output_map
;
1304 streams
= heap_calloc(input_count
, sizeof(*streams
));
1305 for (i
= 0; i
< input_count
; ++i
)
1306 list_init(&streams
[i
].samples
);
1307 node
->u
.transform
.inputs
= streams
;
1308 node
->u
.transform
.input_count
= input_count
;
1310 streams
= heap_calloc(output_count
, sizeof(*streams
));
1311 for (i
= 0; i
< output_count
; ++i
)
1313 list_init(&streams
[i
].samples
);
1315 if (SUCCEEDED(IMFTransform_GetOutputCurrentType(node
->object
.transform
,
1316 transform_node_get_stream_id(node
, TRUE
, i
), &media_type
)))
1318 if (SUCCEEDED(IMFMediaType_GetMajorType(media_type
, &major
)) && IsEqualGUID(&major
, &MFMediaType_Audio
)
1319 && SUCCEEDED(IMFMediaType_GetUINT32(media_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &block_alignment
)))
1321 streams
[i
].min_buffer_size
= block_alignment
;
1323 IMFMediaType_Release(media_type
);
1326 node
->u
.transform
.outputs
= streams
;
1327 node
->u
.transform
.output_count
= output_count
;
1333 static HRESULT
session_get_stream_sink_type(IMFStreamSink
*sink
, IMFMediaType
**media_type
)
1335 IMFMediaTypeHandler
*handler
;
1338 if (SUCCEEDED(hr
= IMFStreamSink_GetMediaTypeHandler(sink
, &handler
)))
1340 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, media_type
);
1341 IMFMediaTypeHandler_Release(handler
);
1347 static HRESULT WINAPI
node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify
*iface
,
1348 REFIID riid
, void **obj
)
1350 if (IsEqualIID(riid
, &IID_IMFVideoSampleAllocatorNotify
) ||
1351 IsEqualIID(riid
, &IID_IUnknown
))
1354 IMFVideoSampleAllocatorNotify_AddRef(iface
);
1359 return E_NOINTERFACE
;
1362 static ULONG WINAPI
node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify
*iface
)
1367 static ULONG WINAPI
node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify
*iface
)
1372 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
);
1374 static HRESULT WINAPI
node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify
*iface
)
1376 struct topo_node
*topo_node
= impl_node_from_IMFVideoSampleAllocatorNotify(iface
);
1377 struct session_op
*op
;
1379 if (SUCCEEDED(create_session_op(SESSION_CMD_SA_READY
, &op
)))
1381 op
->u
.sa_ready
.node_id
= topo_node
->node_id
;
1382 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &topo_node
->session
->commands_callback
, &op
->IUnknown_iface
);
1383 IUnknown_Release(&op
->IUnknown_iface
);
1389 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl
=
1391 node_sample_allocator_cb_QueryInterface
,
1392 node_sample_allocator_cb_AddRef
,
1393 node_sample_allocator_cb_Release
,
1394 node_sample_allocator_cb_NotifyRelease
,
1397 static HRESULT
session_append_node(struct media_session
*session
, IMFTopologyNode
*node
)
1399 struct topo_node
*topo_node
;
1400 IMFMediaSink
*media_sink
;
1401 IMFMediaType
*media_type
;
1402 IMFStreamDescriptor
*sd
;
1405 if (!(topo_node
= heap_alloc_zero(sizeof(*topo_node
))))
1406 return E_OUTOFMEMORY
;
1408 IMFTopologyNode_GetNodeType(node
, &topo_node
->type
);
1409 IMFTopologyNode_GetTopoNodeID(node
, &topo_node
->node_id
);
1410 topo_node
->node
= node
;
1411 IMFTopologyNode_AddRef(topo_node
->node
);
1412 topo_node
->session
= session
;
1414 switch (topo_node
->type
)
1416 case MF_TOPOLOGY_OUTPUT_NODE
:
1417 topo_node
->u
.sink
.notify_cb
.lpVtbl
= &node_sample_allocator_cb_vtbl
;
1419 if (FAILED(hr
= topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&topo_node
->object
.object
)))
1421 WARN("Failed to get stream sink interface, hr %#x.\n", hr
);
1425 if (FAILED(hr
= IMFStreamSink_GetMediaSink(topo_node
->object
.sink_stream
, &media_sink
)))
1428 if (SUCCEEDED(hr
= session_add_media_sink(session
, node
, media_sink
)))
1430 if (SUCCEEDED(session_get_stream_sink_type(topo_node
->object
.sink_stream
, &media_type
)))
1432 if (SUCCEEDED(MFGetService(topo_node
->object
.object
, &MR_VIDEO_ACCELERATION_SERVICE
,
1433 &IID_IMFVideoSampleAllocator
, (void **)&topo_node
->u
.sink
.allocator
)))
1435 if (FAILED(hr
= IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node
->u
.sink
.allocator
,
1438 WARN("Failed to initialize sample allocator for the stream, hr %#x.\n", hr
);
1440 IMFVideoSampleAllocator_QueryInterface(topo_node
->u
.sink
.allocator
,
1441 &IID_IMFVideoSampleAllocatorCallback
, (void **)&topo_node
->u
.sink
.allocator_cb
);
1442 IMFVideoSampleAllocatorCallback_SetCallback(topo_node
->u
.sink
.allocator_cb
,
1443 &topo_node
->u
.sink
.notify_cb
);
1445 IMFMediaType_Release(media_type
);
1448 IMFMediaSink_Release(media_sink
);
1451 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
1452 if (FAILED(IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_SOURCE
, &IID_IMFMediaSource
,
1453 (void **)&topo_node
->u
.source
.source
)))
1455 WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr
);
1459 if (FAILED(hr
= session_add_media_source(session
, node
, topo_node
->u
.source
.source
)))
1462 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
1463 &IID_IMFStreamDescriptor
, (void **)&sd
)))
1465 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr
);
1469 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &topo_node
->u
.source
.stream_id
);
1470 IMFStreamDescriptor_Release(sd
);
1473 case MF_TOPOLOGY_TRANSFORM_NODE
:
1475 if (SUCCEEDED(hr
= topology_node_get_object(node
, &IID_IMFTransform
, (void **)&topo_node
->object
.transform
)))
1477 hr
= session_set_transform_stream_info(topo_node
);
1480 WARN("Failed to get IMFTransform for MFT node, hr %#x.\n", hr
);
1483 case MF_TOPOLOGY_TEE_NODE
:
1484 FIXME("Unsupported node type %d.\n", topo_node
->type
);
1492 list_add_tail(&session
->presentation
.nodes
, &topo_node
->entry
);
1494 release_topo_node(topo_node
);
1499 static HRESULT
session_collect_nodes(struct media_session
*session
)
1501 IMFTopology
*topology
= session
->presentation
.current_topology
;
1502 IMFTopologyNode
*node
;
1506 if (!list_empty(&session
->presentation
.nodes
))
1509 if (FAILED(hr
= IMFTopology_GetNodeCount(topology
, &count
)))
1512 for (i
= 0; i
< count
; ++i
)
1514 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
1516 WARN("Failed to get node %u.\n", i
);
1520 hr
= session_append_node(session
, node
);
1521 IMFTopologyNode_Release(node
);
1524 WARN("Failed to add node %u.\n", i
);
1532 static HRESULT
session_set_current_topology(struct media_session
*session
, IMFTopology
*topology
)
1534 struct media_source
*source
;
1535 DWORD caps
, object_flags
;
1536 struct media_sink
*sink
;
1537 struct topo_node
*node
;
1538 struct session_op
*op
;
1539 IMFMediaEvent
*event
;
1542 if (session
->quality_manager
)
1544 if (SUCCEEDED(create_session_op(SESSION_CMD_QM_NOTIFY_TOPOLOGY
, &op
)))
1546 op
->u
.notify_topology
.topology
= topology
;
1547 IMFTopology_AddRef(op
->u
.notify_topology
.topology
);
1548 session_submit_command(session
, op
);
1549 IUnknown_Release(&op
->IUnknown_iface
);
1553 if (FAILED(hr
= IMFTopology_CloneFrom(session
->presentation
.current_topology
, topology
)))
1555 WARN("Failed to clone topology, hr %#x.\n", hr
);
1559 session_collect_nodes(session
);
1561 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1563 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
1565 if (FAILED(hr
= IMFTransform_ProcessMessage(node
->object
.transform
,
1566 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING
, 0)))
1571 /* FIXME: attributes are all zero for now */
1572 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime
, &GUID_NULL
, S_OK
, NULL
, &event
)))
1574 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME
, 0);
1575 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
1576 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT
, 0);
1578 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
1579 IMFMediaEvent_Release(event
);
1582 /* Update session caps. */
1583 caps
= MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
| MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
|
1584 MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1586 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1592 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &object_flags
)))
1594 if (!(object_flags
& MFMEDIASOURCE_DOES_NOT_USE_NETWORK
))
1595 caps
&= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1596 if (!(object_flags
& MFMEDIASOURCE_CAN_SEEK
))
1597 caps
&= ~MFSESSIONCAP_SEEK
;
1600 /* Mask unsupported rate caps. */
1602 caps
&= session_get_object_rate_caps((IUnknown
*)source
->source
)
1603 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1606 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1612 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
->sink
, &object_flags
)))
1614 if (!(object_flags
& MEDIASINK_RATELESS
))
1615 caps
&= session_get_object_rate_caps((IUnknown
*)sink
->sink
)
1616 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1620 session_set_caps(session
, caps
);
1625 static void session_set_topology(struct media_session
*session
, DWORD flags
, IMFTopology
*topology
)
1627 IMFTopology
*resolved_topology
= NULL
;
1630 /* Resolve unless claimed to be full. */
1631 if (!(flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
) && topology
)
1633 if (!(flags
& MFSESSION_SETTOPOLOGY_NORESOLUTION
))
1635 hr
= session_bind_output_nodes(topology
);
1638 hr
= IMFTopoLoader_Load(session
->topo_loader
, topology
, &resolved_topology
, NULL
/* FIXME? */);
1642 topology
= resolved_topology
;
1647 if (flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
)
1649 if ((topology
&& topology
== session
->presentation
.current_topology
) || !topology
)
1651 /* FIXME: stop current topology, queue next one. */
1652 session_clear_presentation(session
);
1659 else if (topology
&& flags
& MFSESSION_SETTOPOLOGY_IMMEDIATE
)
1661 session_clear_topologies(session
);
1662 session_clear_presentation(session
);
1665 session_raise_topology_set(session
, topology
, hr
);
1667 /* With no current topology set it right away, otherwise queue. */
1670 struct queued_topology
*queued_topology
;
1672 if ((queued_topology
= heap_alloc_zero(sizeof(*queued_topology
))))
1674 queued_topology
->topology
= topology
;
1675 IMFTopology_AddRef(queued_topology
->topology
);
1677 list_add_tail(&session
->topologies
, &queued_topology
->entry
);
1680 if (session
->presentation
.topo_status
== MF_TOPOSTATUS_INVALID
)
1682 hr
= session_set_current_topology(session
, topology
);
1683 session_set_topo_status(session
, hr
, MF_TOPOSTATUS_READY
);
1687 if (resolved_topology
)
1688 IMFTopology_Release(resolved_topology
);
1691 static HRESULT WINAPI
mfsession_QueryInterface(IMFMediaSession
*iface
, REFIID riid
, void **out
)
1693 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1695 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1697 if (IsEqualIID(riid
, &IID_IMFMediaSession
) ||
1698 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1699 IsEqualIID(riid
, &IID_IUnknown
))
1701 *out
= &session
->IMFMediaSession_iface
;
1702 IMFMediaSession_AddRef(iface
);
1705 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1707 *out
= &session
->IMFGetService_iface
;
1708 IMFMediaSession_AddRef(iface
);
1712 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1714 return E_NOINTERFACE
;
1717 static ULONG WINAPI
mfsession_AddRef(IMFMediaSession
*iface
)
1719 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1720 ULONG refcount
= InterlockedIncrement(&session
->refcount
);
1722 TRACE("%p, refcount %u.\n", iface
, refcount
);
1727 static ULONG WINAPI
mfsession_Release(IMFMediaSession
*iface
)
1729 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1730 ULONG refcount
= InterlockedDecrement(&session
->refcount
);
1732 TRACE("%p, refcount %u.\n", iface
, refcount
);
1736 session_clear_topologies(session
);
1737 session_clear_presentation(session
);
1738 session_clear_command_list(session
);
1739 if (session
->presentation
.current_topology
)
1740 IMFTopology_Release(session
->presentation
.current_topology
);
1741 if (session
->event_queue
)
1742 IMFMediaEventQueue_Release(session
->event_queue
);
1744 IMFPresentationClock_Release(session
->clock
);
1745 if (session
->system_time_source
)
1746 IMFPresentationTimeSource_Release(session
->system_time_source
);
1747 if (session
->clock_rate_control
)
1748 IMFRateControl_Release(session
->clock_rate_control
);
1749 if (session
->topo_loader
)
1750 IMFTopoLoader_Release(session
->topo_loader
);
1751 if (session
->quality_manager
)
1752 IMFQualityManager_Release(session
->quality_manager
);
1753 DeleteCriticalSection(&session
->cs
);
1760 static HRESULT WINAPI
mfsession_GetEvent(IMFMediaSession
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1762 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1764 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
1766 return IMFMediaEventQueue_GetEvent(session
->event_queue
, flags
, event
);
1769 static HRESULT WINAPI
mfsession_BeginGetEvent(IMFMediaSession
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1771 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1773 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1775 return IMFMediaEventQueue_BeginGetEvent(session
->event_queue
, callback
, state
);
1778 static HRESULT WINAPI
mfsession_EndGetEvent(IMFMediaSession
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
1780 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1782 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1784 return IMFMediaEventQueue_EndGetEvent(session
->event_queue
, result
, event
);
1787 static HRESULT WINAPI
mfsession_QueueEvent(IMFMediaSession
*iface
, MediaEventType event_type
, REFGUID ext_type
,
1788 HRESULT hr
, const PROPVARIANT
*value
)
1790 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1792 TRACE("%p, %d, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1794 return IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, event_type
, ext_type
, hr
, value
);
1797 static HRESULT WINAPI
mfsession_SetTopology(IMFMediaSession
*iface
, DWORD flags
, IMFTopology
*topology
)
1799 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1800 struct session_op
*op
;
1801 WORD node_count
= 0;
1804 TRACE("%p, %#x, %p.\n", iface
, flags
, topology
);
1808 if (FAILED(IMFTopology_GetNodeCount(topology
, &node_count
)) || node_count
== 0)
1809 return E_INVALIDARG
;
1812 if (FAILED(hr
= create_session_op(SESSION_CMD_SET_TOPOLOGY
, &op
)))
1815 op
->u
.set_topology
.flags
= flags
;
1816 op
->u
.set_topology
.topology
= topology
;
1817 if (op
->u
.set_topology
.topology
)
1818 IMFTopology_AddRef(op
->u
.set_topology
.topology
);
1820 hr
= session_submit_command(session
, op
);
1821 IUnknown_Release(&op
->IUnknown_iface
);
1826 static HRESULT WINAPI
mfsession_ClearTopologies(IMFMediaSession
*iface
)
1828 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1830 TRACE("%p.\n", iface
);
1832 return session_submit_simple_command(session
, SESSION_CMD_CLEAR_TOPOLOGIES
);
1835 static HRESULT WINAPI
mfsession_Start(IMFMediaSession
*iface
, const GUID
*format
, const PROPVARIANT
*start_position
)
1837 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1838 struct session_op
*op
;
1841 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), start_position
);
1843 if (!start_position
)
1846 if (FAILED(hr
= create_session_op(SESSION_CMD_START
, &op
)))
1849 op
->u
.start
.time_format
= format
? *format
: GUID_NULL
;
1850 hr
= PropVariantCopy(&op
->u
.start
.start_position
, start_position
);
1853 hr
= session_submit_command(session
, op
);
1855 IUnknown_Release(&op
->IUnknown_iface
);
1859 static HRESULT WINAPI
mfsession_Pause(IMFMediaSession
*iface
)
1861 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1863 TRACE("%p.\n", iface
);
1865 return session_submit_simple_command(session
, SESSION_CMD_PAUSE
);
1868 static HRESULT WINAPI
mfsession_Stop(IMFMediaSession
*iface
)
1870 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1872 TRACE("%p.\n", iface
);
1874 return session_submit_simple_command(session
, SESSION_CMD_STOP
);
1877 static HRESULT WINAPI
mfsession_Close(IMFMediaSession
*iface
)
1879 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1881 TRACE("%p.\n", iface
);
1883 return session_submit_simple_command(session
, SESSION_CMD_CLOSE
);
1886 static HRESULT WINAPI
mfsession_Shutdown(IMFMediaSession
*iface
)
1888 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1891 TRACE("%p.\n", iface
);
1893 EnterCriticalSection(&session
->cs
);
1894 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1896 session
->state
= SESSION_STATE_SHUT_DOWN
;
1897 IMFMediaEventQueue_Shutdown(session
->event_queue
);
1898 if (session
->quality_manager
)
1899 IMFQualityManager_Shutdown(session
->quality_manager
);
1900 MFShutdownObject((IUnknown
*)session
->clock
);
1901 IMFPresentationClock_Release(session
->clock
);
1902 session
->clock
= NULL
;
1903 session_clear_presentation(session
);
1904 session_clear_command_list(session
);
1906 LeaveCriticalSection(&session
->cs
);
1911 static HRESULT WINAPI
mfsession_GetClock(IMFMediaSession
*iface
, IMFClock
**clock
)
1913 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1916 TRACE("%p, %p.\n", iface
, clock
);
1918 EnterCriticalSection(&session
->cs
);
1919 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1921 *clock
= (IMFClock
*)session
->clock
;
1922 IMFClock_AddRef(*clock
);
1924 LeaveCriticalSection(&session
->cs
);
1929 static HRESULT WINAPI
mfsession_GetSessionCapabilities(IMFMediaSession
*iface
, DWORD
*caps
)
1931 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1934 TRACE("%p, %p.\n", iface
, caps
);
1939 EnterCriticalSection(&session
->cs
);
1940 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1941 *caps
= session
->caps
;
1942 LeaveCriticalSection(&session
->cs
);
1947 static HRESULT WINAPI
mfsession_GetFullTopology(IMFMediaSession
*iface
, DWORD flags
, TOPOID id
, IMFTopology
**topology
)
1949 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1950 struct queued_topology
*queued
;
1954 TRACE("%p, %#x, %s, %p.\n", iface
, flags
, wine_dbgstr_longlong(id
), topology
);
1958 EnterCriticalSection(&session
->cs
);
1960 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1962 if (flags
& MFSESSION_GETFULLTOPOLOGY_CURRENT
)
1964 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
1965 *topology
= session
->presentation
.current_topology
;
1967 hr
= MF_E_INVALIDREQUEST
;
1971 LIST_FOR_EACH_ENTRY(queued
, &session
->topologies
, struct queued_topology
, entry
)
1973 if (SUCCEEDED(IMFTopology_GetTopologyID(queued
->topology
, &topo_id
)) && topo_id
== id
)
1975 *topology
= queued
->topology
;
1982 IMFTopology_AddRef(*topology
);
1985 LeaveCriticalSection(&session
->cs
);
1990 static const IMFMediaSessionVtbl mfmediasessionvtbl
=
1992 mfsession_QueryInterface
,
1996 mfsession_BeginGetEvent
,
1997 mfsession_EndGetEvent
,
1998 mfsession_QueueEvent
,
1999 mfsession_SetTopology
,
2000 mfsession_ClearTopologies
,
2007 mfsession_GetSessionCapabilities
,
2008 mfsession_GetFullTopology
,
2011 static HRESULT WINAPI
session_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
2013 struct media_session
*session
= impl_from_IMFGetService(iface
);
2014 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
2017 static ULONG WINAPI
session_get_service_AddRef(IMFGetService
*iface
)
2019 struct media_session
*session
= impl_from_IMFGetService(iface
);
2020 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2023 static ULONG WINAPI
session_get_service_Release(IMFGetService
*iface
)
2025 struct media_session
*session
= impl_from_IMFGetService(iface
);
2026 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2029 static HRESULT
session_get_video_render_service(struct media_session
*session
, REFGUID service
,
2030 REFIID riid
, void **obj
)
2032 IMFStreamSink
*stream_sink
;
2033 IMFTopologyNode
*node
;
2034 IMFCollection
*nodes
;
2038 HRESULT hr
= E_FAIL
;
2040 /* Use first sink to support IMFVideoRenderer. */
2041 if (session
->presentation
.current_topology
)
2043 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session
->presentation
.current_topology
,
2046 while (IMFCollection_GetElement(nodes
, i
++, (IUnknown
**)&node
) == S_OK
)
2048 if (SUCCEEDED(topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
2050 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink
, &sink
)))
2052 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
, &IID_IMFVideoRenderer
, (void **)&vr
)))
2054 if (FAILED(hr
= MFGetService(vr
, service
, riid
, obj
)))
2055 WARN("Failed to get service from video renderer %#x.\n", hr
);
2056 IUnknown_Release(vr
);
2059 IMFStreamSink_Release(stream_sink
);
2062 IMFTopologyNode_Release(node
);
2068 IMFCollection_Release(nodes
);
2075 static HRESULT WINAPI
session_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
2077 struct media_session
*session
= impl_from_IMFGetService(iface
);
2080 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
2084 EnterCriticalSection(&session
->cs
);
2085 if (FAILED(hr
= session_is_shut_down(session
)))
2088 else if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
2090 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
2092 *obj
= &session
->IMFRateSupport_iface
;
2094 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
2096 *obj
= &session
->IMFRateControl_iface
;
2102 IUnknown_AddRef((IUnknown
*)*obj
);
2104 else if (IsEqualGUID(service
, &MF_LOCAL_MFT_REGISTRATION_SERVICE
))
2106 hr
= IMFLocalMFTRegistration_QueryInterface(&local_mft_registration
, riid
, obj
);
2108 else if (IsEqualGUID(service
, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE
))
2110 *obj
= &session
->IMFTopologyNodeAttributeEditor_iface
;
2111 IUnknown_AddRef((IUnknown
*)*obj
);
2113 else if (IsEqualGUID(service
, &MR_VIDEO_RENDER_SERVICE
))
2115 hr
= session_get_video_render_service(session
, service
, riid
, obj
);
2118 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
2120 LeaveCriticalSection(&session
->cs
);
2125 static const IMFGetServiceVtbl session_get_service_vtbl
=
2127 session_get_service_QueryInterface
,
2128 session_get_service_AddRef
,
2129 session_get_service_Release
,
2130 session_get_service_GetService
,
2133 static HRESULT WINAPI
session_commands_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2135 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2136 IsEqualIID(riid
, &IID_IUnknown
))
2139 IMFAsyncCallback_AddRef(iface
);
2143 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2145 return E_NOINTERFACE
;
2148 static ULONG WINAPI
session_commands_callback_AddRef(IMFAsyncCallback
*iface
)
2150 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2151 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2154 static ULONG WINAPI
session_commands_callback_Release(IMFAsyncCallback
*iface
)
2156 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2157 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2160 static HRESULT WINAPI
session_commands_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2165 static HRESULT WINAPI
session_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
2167 struct session_op
*op
= impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result
));
2168 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2169 struct topo_node
*topo_node
;
2170 IMFTopologyNode
*upstream_node
;
2171 unsigned int upstream_output
;
2173 EnterCriticalSection(&session
->cs
);
2175 switch (op
->command
)
2177 case SESSION_CMD_CLEAR_TOPOLOGIES
:
2178 session_clear_topologies(session
);
2179 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologiesCleared
, &GUID_NULL
,
2181 session_command_complete(session
);
2183 case SESSION_CMD_SET_TOPOLOGY
:
2184 session_set_topology(session
, op
->u
.set_topology
.flags
, op
->u
.set_topology
.topology
);
2185 session_command_complete(session
);
2187 case SESSION_CMD_START
:
2188 session_start(session
, &op
->u
.start
.time_format
, &op
->u
.start
.start_position
);
2190 case SESSION_CMD_PAUSE
:
2191 session_pause(session
);
2193 case SESSION_CMD_STOP
:
2194 session_stop(session
);
2196 case SESSION_CMD_CLOSE
:
2197 session_close(session
);
2199 case SESSION_CMD_QM_NOTIFY_TOPOLOGY
:
2200 IMFQualityManager_NotifyTopology(session
->quality_manager
, op
->u
.notify_topology
.topology
);
2201 session_command_complete(session
);
2203 case SESSION_CMD_SA_READY
:
2204 topo_node
= session_get_node_by_id(session
, op
->u
.sa_ready
.node_id
);
2206 if (topo_node
->u
.sink
.requests
)
2208 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node
->node
, 0, &upstream_node
, &upstream_output
)))
2210 session_request_sample_from_node(session
, upstream_node
, upstream_output
);
2211 IMFTopologyNode_Release(upstream_node
);
2219 LeaveCriticalSection(&session
->cs
);
2224 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl
=
2226 session_commands_callback_QueryInterface
,
2227 session_commands_callback_AddRef
,
2228 session_commands_callback_Release
,
2229 session_commands_callback_GetParameters
,
2230 session_commands_callback_Invoke
,
2233 static HRESULT WINAPI
session_events_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2235 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2236 IsEqualIID(riid
, &IID_IUnknown
))
2239 IMFAsyncCallback_AddRef(iface
);
2243 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2245 return E_NOINTERFACE
;
2248 static ULONG WINAPI
session_events_callback_AddRef(IMFAsyncCallback
*iface
)
2250 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2251 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2254 static ULONG WINAPI
session_events_callback_Release(IMFAsyncCallback
*iface
)
2256 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2257 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2260 static HRESULT WINAPI
session_events_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2265 static HRESULT
session_add_media_stream(struct media_session
*session
, IMFMediaSource
*source
, IMFMediaStream
*stream
)
2267 struct topo_node
*node
;
2268 IMFStreamDescriptor
*sd
;
2269 DWORD stream_id
= 0;
2272 if (FAILED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
2275 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &stream_id
);
2276 IMFStreamDescriptor_Release(sd
);
2280 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2282 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->u
.source
.source
== source
2283 && node
->u
.source
.stream_id
== stream_id
)
2285 if (node
->object
.source_stream
)
2287 WARN("Node already has stream set.\n");
2291 node
->object
.source_stream
= stream
;
2292 IMFMediaStream_AddRef(node
->object
.source_stream
);
2300 static BOOL
session_is_source_nodes_state(struct media_session
*session
, enum object_state state
)
2302 struct media_source
*source
;
2303 struct topo_node
*node
;
2305 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2307 if (source
->state
!= state
)
2311 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2313 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->state
!= state
)
2320 static BOOL
session_is_output_nodes_state(struct media_session
*session
, enum object_state state
)
2322 struct topo_node
*node
;
2324 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2326 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->state
!= state
)
2333 static enum object_state
session_get_object_state_for_event(MediaEventType event
)
2337 case MESourceStarted
:
2338 case MEStreamStarted
:
2339 case MEStreamSinkStarted
:
2340 return OBJ_STATE_STARTED
;
2341 case MESourcePaused
:
2342 case MEStreamPaused
:
2343 case MEStreamSinkPaused
:
2344 return OBJ_STATE_PAUSED
;
2345 case MESourceStopped
:
2346 case MEStreamStopped
:
2347 case MEStreamSinkStopped
:
2348 return OBJ_STATE_STOPPED
;
2349 case MEStreamSinkPrerolled
:
2350 return OBJ_STATE_PREROLLED
;
2352 return OBJ_STATE_INVALID
;
2356 static void session_set_consumed_clock(IUnknown
*object
, IMFPresentationClock
*clock
)
2358 IMFClockConsumer
*consumer
;
2360 if (SUCCEEDED(IUnknown_QueryInterface(object
, &IID_IMFClockConsumer
, (void **)&consumer
)))
2362 IMFClockConsumer_SetPresentationClock(consumer
, clock
);
2363 IMFClockConsumer_Release(consumer
);
2367 static void session_set_presentation_clock(struct media_session
*session
)
2369 IMFPresentationTimeSource
*time_source
= NULL
;
2370 struct media_source
*source
;
2371 struct media_sink
*sink
;
2372 struct topo_node
*node
;
2375 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2377 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
2378 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_NOTIFY_START_OF_STREAM
, 0);
2381 if (!(session
->presentation
.flags
& SESSION_FLAG_PRESENTATION_CLOCK_SET
))
2383 /* Attempt to get time source from the sinks. */
2384 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2386 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFPresentationTimeSource
,
2387 (void **)&time_source
)))
2393 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, time_source
);
2394 IMFPresentationTimeSource_Release(time_source
);
2397 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, session
->system_time_source
);
2400 WARN("Failed to set time source, hr %#x.\n", hr
);
2402 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2404 if (node
->type
!= MF_TOPOLOGY_OUTPUT_NODE
)
2407 if (FAILED(hr
= IMFStreamSink_BeginGetEvent(node
->object
.sink_stream
, &session
->events_callback
,
2408 node
->object
.object
)))
2410 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr
);
2414 /* Set clock for all topology nodes. */
2415 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2417 session_set_consumed_clock((IUnknown
*)source
->source
, session
->clock
);
2420 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2422 if (sink
->event_generator
&& FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(sink
->event_generator
,
2423 &session
->events_callback
, (IUnknown
*)sink
->event_generator
)))
2425 WARN("Failed to subscribe to sink events, hr %#x.\n", hr
);
2428 if (FAILED(hr
= IMFMediaSink_SetPresentationClock(sink
->sink
, session
->clock
)))
2429 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr
);
2432 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2434 if (node
->type
!= MF_TOPOLOGY_TRANSFORM_NODE
)
2437 session_set_consumed_clock(node
->object
.object
, session
->clock
);
2440 session
->presentation
.flags
|= SESSION_FLAG_PRESENTATION_CLOCK_SET
;
2444 static HRESULT
session_start_clock(struct media_session
*session
)
2446 LONGLONG start_offset
= 0;
2449 if (IsEqualGUID(&session
->presentation
.time_format
, &GUID_NULL
))
2451 if (session
->presentation
.start_position
.vt
== VT_EMPTY
)
2452 start_offset
= PRESENTATION_CURRENT_POSITION
;
2453 else if (session
->presentation
.start_position
.vt
== VT_I8
)
2454 start_offset
= session
->presentation
.start_position
.hVal
.QuadPart
;
2456 FIXME("Unhandled position type %d.\n", session
->presentation
.start_position
.vt
);
2459 FIXME("Unhandled time format %s.\n", debugstr_guid(&session
->presentation
.time_format
));
2461 if (FAILED(hr
= IMFPresentationClock_Start(session
->clock
, start_offset
)))
2462 WARN("Failed to start session clock, hr %#x.\n", hr
);
2467 static struct topo_node
*session_get_node_object(struct media_session
*session
, IUnknown
*object
,
2468 MF_TOPOLOGY_TYPE node_type
)
2470 struct topo_node
*node
= NULL
;
2472 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2474 if (node
->type
== node_type
&& object
== node
->object
.object
)
2481 static BOOL
session_set_node_object_state(struct media_session
*session
, IUnknown
*object
,
2482 MF_TOPOLOGY_TYPE node_type
, enum object_state state
)
2484 struct topo_node
*node
;
2485 BOOL changed
= FALSE
;
2487 if ((node
= session_get_node_object(session
, object
, node_type
)))
2489 changed
= node
->state
!= state
;
2490 node
->state
= state
;
2496 static void session_set_source_object_state(struct media_session
*session
, IUnknown
*object
,
2497 MediaEventType event_type
)
2499 IMFStreamSink
*stream_sink
;
2500 struct media_source
*src
;
2501 struct media_sink
*sink
;
2502 enum object_state state
;
2503 struct topo_node
*node
;
2504 unsigned int i
, count
;
2505 BOOL changed
= FALSE
;
2508 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2513 case MESourceStarted
:
2514 case MESourcePaused
:
2515 case MESourceStopped
:
2517 LIST_FOR_EACH_ENTRY(src
, &session
->presentation
.sources
, struct media_source
, entry
)
2519 if (object
== (IUnknown
*)src
->source
)
2521 changed
= src
->state
!= state
;
2527 case MEStreamStarted
:
2528 case MEStreamPaused
:
2529 case MEStreamStopped
:
2531 changed
= session_set_node_object_state(session
, object
, MF_TOPOLOGY_SOURCESTREAM_NODE
, state
);
2539 switch (session
->state
)
2541 case SESSION_STATE_STARTING_SOURCES
:
2542 if (!session_is_source_nodes_state(session
, OBJ_STATE_STARTED
))
2545 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_STARTED_SOURCE
);
2547 session_set_presentation_clock(session
);
2549 if (session
->presentation
.flags
& SESSION_FLAG_NEEDS_PREROLL
)
2551 MFTIME preroll_time
= 0;
2553 if (session
->presentation
.start_position
.vt
== VT_I8
)
2554 preroll_time
= session
->presentation
.start_position
.hVal
.QuadPart
;
2556 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2557 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2561 /* FIXME: abort and enter error state on failure. */
2562 if (FAILED(hr
= IMFMediaSinkPreroll_NotifyPreroll(sink
->preroll
, preroll_time
)))
2563 WARN("Preroll notification failed, hr %#x.\n", hr
);
2567 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink
->sink
, &count
)))
2569 for (i
= 0; i
< count
; ++i
)
2571 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink
->sink
, i
, &stream_sink
)))
2573 session_set_node_object_state(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
,
2574 OBJ_STATE_PREROLLED
);
2575 IMFStreamSink_Release(stream_sink
);
2581 session
->state
= SESSION_STATE_PREROLLING_SINKS
;
2583 else if (SUCCEEDED(session_start_clock(session
)))
2584 session
->state
= SESSION_STATE_STARTING_SINKS
;
2587 case SESSION_STATE_PAUSING_SOURCES
:
2588 if (!session_is_source_nodes_state(session
, OBJ_STATE_PAUSED
))
2591 session_set_paused(session
, S_OK
);
2593 case SESSION_STATE_STOPPING_SOURCES
:
2594 if (!session_is_source_nodes_state(session
, OBJ_STATE_STOPPED
))
2597 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2601 case MF_TOPOLOGY_OUTPUT_NODE
:
2602 IMFStreamSink_Flush(node
->object
.sink_stream
);
2604 case MF_TOPOLOGY_TRANSFORM_NODE
:
2605 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
2612 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
2614 if (session
->presentation
.flags
& SESSION_FLAG_FINALIZE_SINKS
)
2615 session_finalize_sinks(session
);
2617 session_set_stopped(session
, S_OK
);
2625 static void session_set_sink_stream_state(struct media_session
*session
, IMFStreamSink
*stream
,
2626 MediaEventType event_type
)
2628 struct media_source
*source
;
2629 enum object_state state
;
2633 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2636 if (!(changed
= session_set_node_object_state(session
, (IUnknown
*)stream
, MF_TOPOLOGY_OUTPUT_NODE
, state
)))
2639 switch (session
->state
)
2641 case SESSION_STATE_PREROLLING_SINKS
:
2642 if (!session_is_output_nodes_state(session
, OBJ_STATE_PREROLLED
))
2645 if (SUCCEEDED(session_start_clock(session
)))
2646 session
->state
= SESSION_STATE_STARTING_SINKS
;
2648 case SESSION_STATE_STARTING_SINKS
:
2649 if (!session_is_output_nodes_state(session
, OBJ_STATE_STARTED
))
2652 session_set_started(session
);
2654 case SESSION_STATE_PAUSING_SINKS
:
2655 if (!session_is_output_nodes_state(session
, OBJ_STATE_PAUSED
))
2658 session
->state
= SESSION_STATE_PAUSING_SOURCES
;
2660 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2662 if (FAILED(hr
= IMFMediaSource_Pause(source
->source
)))
2667 session_set_paused(session
, hr
);
2670 case SESSION_STATE_STOPPING_SINKS
:
2671 if (!session_is_output_nodes_state(session
, OBJ_STATE_STOPPED
))
2674 session
->state
= SESSION_STATE_STOPPING_SOURCES
;
2676 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2678 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
)
2679 IMFMediaSource_Stop(source
->source
);
2680 else if (FAILED(hr
= IMFMediaSource_Stop(source
->source
)))
2684 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
|| FAILED(hr
))
2685 session_set_stopped(session
, hr
);
2693 static struct sample
*transform_create_sample(IMFSample
*sample
)
2695 struct sample
*sample_entry
= heap_alloc_zero(sizeof(*sample_entry
));
2699 sample_entry
->sample
= sample
;
2700 if (sample_entry
->sample
)
2701 IMFSample_AddRef(sample_entry
->sample
);
2704 return sample_entry
;
2707 static HRESULT
transform_get_external_output_sample(const struct media_session
*session
, struct topo_node
*transform
,
2708 unsigned int output_index
, const MFT_OUTPUT_STREAM_INFO
*stream_info
, IMFSample
**sample
)
2710 unsigned int buffer_size
, downstream_input
;
2711 IMFTopologyNode
*downstream_node
;
2712 IMFMediaBuffer
*buffer
= NULL
;
2713 struct topo_node
*topo_node
;
2717 if (FAILED(IMFTopologyNode_GetOutput(transform
->node
, output_index
, &downstream_node
, &downstream_input
)))
2719 WARN("Failed to get connected node for output %u.\n", output_index
);
2720 return MF_E_UNEXPECTED
;
2723 IMFTopologyNode_GetTopoNodeID(downstream_node
, &node_id
);
2724 IMFTopologyNode_Release(downstream_node
);
2726 topo_node
= session_get_node_by_id(session
, node_id
);
2728 if (topo_node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& topo_node
->u
.sink
.allocator
)
2730 hr
= IMFVideoSampleAllocator_AllocateSample(topo_node
->u
.sink
.allocator
, sample
);
2734 buffer_size
= max(stream_info
->cbSize
, transform
->u
.transform
.outputs
[output_index
].min_buffer_size
);
2736 hr
= MFCreateAlignedMemoryBuffer(buffer_size
, stream_info
->cbAlignment
, &buffer
);
2738 hr
= MFCreateSample(sample
);
2741 hr
= IMFSample_AddBuffer(*sample
, buffer
);
2744 IMFMediaBuffer_Release(buffer
);
2750 static HRESULT
transform_node_pull_samples(const struct media_session
*session
, struct topo_node
*node
)
2752 MFT_OUTPUT_STREAM_INFO stream_info
;
2753 MFT_OUTPUT_DATA_BUFFER
*buffers
;
2754 struct sample
*queued_sample
;
2757 HRESULT hr
= E_UNEXPECTED
;
2759 if (!(buffers
= heap_calloc(node
->u
.transform
.output_count
, sizeof(*buffers
))))
2760 return E_OUTOFMEMORY
;
2762 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2764 buffers
[i
].dwStreamID
= transform_node_get_stream_id(node
, TRUE
, i
);
2765 buffers
[i
].pSample
= NULL
;
2766 buffers
[i
].dwStatus
= 0;
2767 buffers
[i
].pEvents
= NULL
;
2769 memset(&stream_info
, 0, sizeof(stream_info
));
2770 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(node
->object
.transform
, buffers
[i
].dwStreamID
, &stream_info
)))
2773 if (!(stream_info
.dwFlags
& (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
| MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
)))
2775 if (FAILED(hr
= transform_get_external_output_sample(session
, node
, i
, &stream_info
, &buffers
[i
].pSample
)))
2781 hr
= IMFTransform_ProcessOutput(node
->object
.transform
, 0, node
->u
.transform
.output_count
, buffers
, &status
);
2783 /* Collect returned samples for all streams. */
2784 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2786 if (buffers
[i
].pEvents
)
2787 IMFCollection_Release(buffers
[i
].pEvents
);
2789 if (SUCCEEDED(hr
) && !(buffers
[i
].dwStatus
& MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE
))
2791 if (session
->quality_manager
)
2792 IMFQualityManager_NotifyProcessOutput(session
->quality_manager
, node
->node
, i
, buffers
[i
].pSample
);
2794 queued_sample
= transform_create_sample(buffers
[i
].pSample
);
2795 list_add_tail(&node
->u
.transform
.outputs
[i
].samples
, &queued_sample
->entry
);
2798 if (buffers
[i
].pSample
)
2799 IMFSample_Release(buffers
[i
].pSample
);
2807 static void session_deliver_sample_to_node(struct media_session
*session
, IMFTopologyNode
*node
, unsigned int input
,
2810 struct sample
*sample_entry
, *sample_entry2
;
2811 DWORD stream_id
, downstream_input
;
2812 IMFTopologyNode
*downstream_node
;
2813 struct topo_node
*topo_node
;
2814 MF_TOPOLOGY_TYPE node_type
;
2820 if (session
->quality_manager
)
2821 IMFQualityManager_NotifyProcessInput(session
->quality_manager
, node
, input
, sample
);
2823 IMFTopologyNode_GetNodeType(node
, &node_type
);
2824 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2826 topo_node
= session_get_node_by_id(session
, node_id
);
2830 case MF_TOPOLOGY_OUTPUT_NODE
:
2833 if (topo_node
->u
.sink
.requests
)
2835 if (FAILED(hr
= IMFStreamSink_ProcessSample(topo_node
->object
.sink_stream
, sample
)))
2836 WARN("Stream sink failed to process sample, hr %#x.\n", hr
);
2837 topo_node
->u
.sink
.requests
--;
2840 else if (FAILED(hr
= IMFStreamSink_PlaceMarker(topo_node
->object
.sink_stream
, MFSTREAMSINK_MARKER_ENDOFSEGMENT
,
2843 WARN("Failed to place sink marker, hr %#x.\n", hr
);
2846 case MF_TOPOLOGY_TRANSFORM_NODE
:
2848 transform_node_pull_samples(session
, topo_node
);
2850 sample_entry
= transform_create_sample(sample
);
2851 list_add_tail(&topo_node
->u
.transform
.inputs
[input
].samples
, &sample_entry
->entry
);
2853 for (i
= 0; i
< topo_node
->u
.transform
.input_count
; ++i
)
2855 stream_id
= transform_node_get_stream_id(topo_node
, FALSE
, i
);
2856 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.inputs
[i
].samples
,
2857 struct sample
, entry
)
2859 if (sample_entry
->sample
)
2861 if ((hr
= IMFTransform_ProcessInput(topo_node
->object
.transform
, stream_id
,
2862 sample_entry
->sample
, 0)) == MF_E_NOTACCEPTING
)
2865 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i
, stream_id
, hr
);
2866 transform_release_sample(sample_entry
);
2870 transform_stream_drop_samples(&topo_node
->u
.transform
.inputs
[i
]);
2878 if (FAILED(hr
= IMFTransform_ProcessMessage(topo_node
->object
.transform
, MFT_MESSAGE_COMMAND_DRAIN
, 0)))
2879 WARN("Drain command failed for transform, hr %#x.\n", hr
);
2882 transform_node_pull_samples(session
, topo_node
);
2884 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2887 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2889 if ((sample_entry
= transform_create_sample(NULL
)))
2890 list_add_tail(&topo_node
->u
.transform
.outputs
[i
].samples
, &sample_entry
->entry
);
2894 /* Push down all available output. */
2895 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2897 if (FAILED(IMFTopologyNode_GetOutput(node
, i
, &downstream_node
, &downstream_input
)))
2899 WARN("Failed to get connected node for output %u.\n", i
);
2903 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.outputs
[i
].samples
,
2904 struct sample
, entry
)
2906 if (!topo_node
->u
.transform
.outputs
[i
].requests
)
2909 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample_entry
->sample
);
2910 topo_node
->u
.transform
.outputs
[i
].requests
--;
2912 transform_release_sample(sample_entry
);
2915 IMFTopologyNode_Release(downstream_node
);
2919 case MF_TOPOLOGY_TEE_NODE
:
2920 FIXME("Unhandled downstream node type %d.\n", node_type
);
2927 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
)
2929 IMFTopologyNode
*downstream_node
, *upstream_node
;
2930 unsigned int downstream_input
, upstream_output
;
2931 struct topo_node
*topo_node
;
2932 MF_TOPOLOGY_TYPE node_type
;
2933 struct sample
*sample
;
2937 IMFTopologyNode_GetNodeType(node
, &node_type
);
2938 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2940 topo_node
= session_get_node_by_id(session
, node_id
);
2944 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
2945 if (FAILED(hr
= IMFMediaStream_RequestSample(topo_node
->object
.source_stream
, NULL
)))
2946 WARN("Sample request failed, hr %#x.\n", hr
);
2948 case MF_TOPOLOGY_TRANSFORM_NODE
:
2950 if (list_empty(&topo_node
->u
.transform
.outputs
[output
].samples
))
2952 /* Forward request to upstream node. */
2953 if (SUCCEEDED(hr
= IMFTopologyNode_GetInput(node
, 0 /* FIXME */, &upstream_node
, &upstream_output
)))
2955 if (SUCCEEDED(hr
= session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2956 topo_node
->u
.transform
.outputs
[output
].requests
++;
2957 IMFTopologyNode_Release(upstream_node
);
2962 if (SUCCEEDED(hr
= IMFTopologyNode_GetOutput(node
, output
, &downstream_node
, &downstream_input
)))
2964 sample
= LIST_ENTRY(list_head(&topo_node
->u
.transform
.outputs
[output
].samples
), struct sample
, entry
);
2965 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample
->sample
);
2966 transform_release_sample(sample
);
2967 IMFTopologyNode_Release(downstream_node
);
2972 case MF_TOPOLOGY_TEE_NODE
:
2973 FIXME("Unhandled upstream node type %d.\n", node_type
);
2981 static void session_request_sample(struct media_session
*session
, IMFStreamSink
*sink_stream
)
2983 struct topo_node
*sink_node
= NULL
, *node
;
2984 IMFTopologyNode
*upstream_node
;
2985 DWORD upstream_output
;
2988 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2990 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink_stream
)
3000 if (FAILED(hr
= IMFTopologyNode_GetInput(sink_node
->node
, 0, &upstream_node
, &upstream_output
)))
3002 WARN("Failed to get upstream node connection, hr %#x.\n", hr
);
3006 if (SUCCEEDED(session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
3007 sink_node
->u
.sink
.requests
++;
3008 IMFTopologyNode_Release(upstream_node
);
3011 static void session_deliver_sample(struct media_session
*session
, IMFMediaStream
*stream
, const PROPVARIANT
*value
)
3013 struct topo_node
*source_node
= NULL
, *node
;
3014 IMFTopologyNode
*downstream_node
;
3015 DWORD downstream_input
;
3018 if (value
&& (value
->vt
!= VT_UNKNOWN
|| !value
->punkVal
))
3020 WARN("Unexpected value type %d.\n", value
->vt
);
3024 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3026 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->object
.source_stream
== stream
)
3037 source_node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3039 if (FAILED(hr
= IMFTopologyNode_GetOutput(source_node
->node
, 0, &downstream_node
, &downstream_input
)))
3041 WARN("Failed to get downstream node connection, hr %#x.\n", hr
);
3045 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, value
? (IMFSample
*)value
->punkVal
: NULL
);
3046 IMFTopologyNode_Release(downstream_node
);
3049 static void session_sink_invalidated(struct media_session
*session
, IMFMediaEvent
*event
, IMFStreamSink
*sink
)
3051 struct topo_node
*node
, *sink_node
= NULL
;
3054 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3056 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink
)
3068 if (FAILED(hr
= MFCreateMediaEvent(MESinkInvalidated
, &GUID_NULL
, S_OK
, NULL
, &event
)))
3069 WARN("Failed to create event, hr %#x.\n", hr
);
3075 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_OUTPUT_NODE
, sink_node
->node_id
);
3076 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3078 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3081 static BOOL
session_nodes_is_mask_set(struct media_session
*session
, MF_TOPOLOGY_TYPE node_type
, unsigned int flags
)
3083 struct media_source
*source
;
3084 struct topo_node
*node
;
3086 if (node_type
== MF_TOPOLOGY_MAX
)
3088 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3090 if ((source
->flags
& flags
) != flags
)
3096 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3098 if (node
->type
== node_type
&& (node
->flags
& flags
) != flags
)
3106 static void session_raise_end_of_presentation(struct media_session
*session
)
3108 if (!(session_nodes_is_mask_set(session
, MF_TOPOLOGY_SOURCESTREAM_NODE
, TOPO_NODE_END_OF_STREAM
)))
3111 if (!(session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
))
3113 if (session_nodes_is_mask_set(session
, MF_TOPOLOGY_MAX
, SOURCE_FLAG_END_OF_PRESENTATION
))
3115 session
->presentation
.flags
|= SESSION_FLAG_END_OF_PRESENTATION
;
3116 session_push_back_command(session
, SESSION_CMD_END
);
3117 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MEEndOfPresentation
, &GUID_NULL
, S_OK
, NULL
);
3122 static void session_handle_end_of_stream(struct media_session
*session
, IMFMediaStream
*stream
)
3124 struct topo_node
*node
;
3126 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream
, MF_TOPOLOGY_SOURCESTREAM_NODE
))
3127 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3132 session_deliver_sample(session
, stream
, NULL
);
3134 session_raise_end_of_presentation(session
);
3137 static void session_handle_end_of_presentation(struct media_session
*session
, IMFMediaSource
*object
)
3139 struct media_source
*source
;
3141 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3143 if (source
->source
== object
)
3145 if (!(source
->flags
& SOURCE_FLAG_END_OF_PRESENTATION
))
3147 source
->flags
|= SOURCE_FLAG_END_OF_PRESENTATION
;
3148 session_raise_end_of_presentation(session
);
3156 static void session_sink_stream_marker(struct media_session
*session
, IMFStreamSink
*stream_sink
)
3158 struct topo_node
*node
;
3160 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
))
3161 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3166 node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3168 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
&&
3169 session_nodes_is_mask_set(session
, MF_TOPOLOGY_OUTPUT_NODE
, TOPO_NODE_END_OF_STREAM
))
3171 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3172 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
3173 session_stop(session
);
3177 static HRESULT WINAPI
session_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3179 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
3180 IMFMediaEventGenerator
*event_source
;
3181 IMFMediaEvent
*event
= NULL
;
3182 MediaEventType event_type
;
3183 IUnknown
*object
= NULL
;
3184 IMFMediaSource
*source
;
3185 IMFMediaStream
*stream
;
3189 if (FAILED(hr
= IMFAsyncResult_GetState(result
, (IUnknown
**)&event_source
)))
3192 if (FAILED(hr
= IMFMediaEventGenerator_EndGetEvent(event_source
, result
, &event
)))
3194 WARN("Failed to get event from %p, hr %#x.\n", event_source
, hr
);
3198 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
3200 WARN("Failed to get event type, hr %#x.\n", hr
);
3204 value
.vt
= VT_EMPTY
;
3205 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
3207 WARN("Failed to get event value, hr %#x.\n", hr
);
3213 case MESourceStarted
:
3214 case MESourcePaused
:
3215 case MESourceStopped
:
3216 case MEStreamStarted
:
3217 case MEStreamPaused
:
3218 case MEStreamStopped
:
3220 EnterCriticalSection(&session
->cs
);
3221 session_set_source_object_state(session
, (IUnknown
*)event_source
, event_type
);
3222 LeaveCriticalSection(&session
->cs
);
3226 case MEBufferingStarted
:
3227 case MEBufferingStopped
:
3229 EnterCriticalSection(&session
->cs
);
3230 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3232 if (event_type
== MEBufferingStarted
)
3233 IMFPresentationClock_Pause(session
->clock
);
3235 IMFPresentationClock_Start(session
->clock
, PRESENTATION_CURRENT_POSITION
);
3237 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3239 LeaveCriticalSection(&session
->cs
);
3242 case MEReconnectStart
:
3243 case MEReconnectEnd
:
3245 EnterCriticalSection(&session
->cs
);
3246 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3247 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3248 LeaveCriticalSection(&session
->cs
);
3251 case MEExtendedType
:
3252 case MERendererEvent
:
3253 case MEStreamSinkFormatChanged
:
3255 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3259 stream
= (IMFMediaStream
*)value
.punkVal
;
3261 if (value
.vt
!= VT_UNKNOWN
|| !stream
)
3263 WARN("Unexpected event value.\n");
3267 if (FAILED(hr
= IMFMediaStream_GetMediaSource(stream
, &source
)))
3270 EnterCriticalSection(&session
->cs
);
3271 if (SUCCEEDED(hr
= session_add_media_stream(session
, source
, stream
)))
3272 hr
= IMFMediaStream_BeginGetEvent(stream
, &session
->events_callback
, (IUnknown
*)stream
);
3273 LeaveCriticalSection(&session
->cs
);
3275 IMFMediaSource_Release(source
);
3278 case MEStreamSinkStarted
:
3279 case MEStreamSinkPaused
:
3280 case MEStreamSinkStopped
:
3281 case MEStreamSinkPrerolled
:
3283 EnterCriticalSection(&session
->cs
);
3284 session_set_sink_stream_state(session
, (IMFStreamSink
*)event_source
, event_type
);
3285 LeaveCriticalSection(&session
->cs
);
3288 case MEStreamSinkMarker
:
3290 EnterCriticalSection(&session
->cs
);
3291 session_sink_stream_marker(session
, (IMFStreamSink
*)event_source
);
3292 LeaveCriticalSection(&session
->cs
);
3295 case MEStreamSinkRequestSample
:
3297 EnterCriticalSection(&session
->cs
);
3298 session_request_sample(session
, (IMFStreamSink
*)event_source
);
3299 LeaveCriticalSection(&session
->cs
);
3304 EnterCriticalSection(&session
->cs
);
3305 session_deliver_sample(session
, (IMFMediaStream
*)event_source
, &value
);
3306 LeaveCriticalSection(&session
->cs
);
3311 EnterCriticalSection(&session
->cs
);
3312 session_handle_end_of_stream(session
, (IMFMediaStream
*)event_source
);
3313 LeaveCriticalSection(&session
->cs
);
3317 case MEEndOfPresentation
:
3319 EnterCriticalSection(&session
->cs
);
3320 session_handle_end_of_presentation(session
, (IMFMediaSource
*)event_source
);
3321 LeaveCriticalSection(&session
->cs
);
3324 case MEAudioSessionGroupingParamChanged
:
3325 case MEAudioSessionIconChanged
:
3326 case MEAudioSessionNameChanged
:
3327 case MEAudioSessionVolumeChanged
:
3329 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3332 case MEAudioSessionDeviceRemoved
:
3333 case MEAudioSessionDisconnected
:
3334 case MEAudioSessionExclusiveModeOverride
:
3335 case MEAudioSessionFormatChanged
:
3336 case MEAudioSessionServerShutdown
:
3338 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3340 case MESinkInvalidated
:
3342 EnterCriticalSection(&session
->cs
);
3343 session_sink_invalidated(session
, event_type
== MESinkInvalidated
? event
: NULL
,
3344 (IMFStreamSink
*)event_source
);
3345 LeaveCriticalSection(&session
->cs
);
3348 case MEQualityNotify
:
3350 if (session
->quality_manager
)
3352 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFStreamSink
, (void **)&object
)))
3353 IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFTransform
, (void **)&object
);
3357 IMFQualityManager_NotifyQualityEvent(session
->quality_manager
, object
, event
);
3358 IUnknown_Release(object
);
3367 PropVariantClear(&value
);
3371 IMFMediaEvent_Release(event
);
3373 if (FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(event_source
, iface
, (IUnknown
*)event_source
)))
3374 WARN("Failed to re-subscribe, hr %#x.\n", hr
);
3376 IMFMediaEventGenerator_Release(event_source
);
3381 static const IMFAsyncCallbackVtbl session_events_callback_vtbl
=
3383 session_events_callback_QueryInterface
,
3384 session_events_callback_AddRef
,
3385 session_events_callback_Release
,
3386 session_events_callback_GetParameters
,
3387 session_events_callback_Invoke
,
3390 static HRESULT WINAPI
session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
3392 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
3393 IsEqualIID(riid
, &IID_IUnknown
))
3396 IMFAsyncCallback_AddRef(iface
);
3400 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3402 return E_NOINTERFACE
;
3405 static ULONG WINAPI
session_sink_finalizer_callback_AddRef(IMFAsyncCallback
*iface
)
3407 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3408 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3411 static ULONG WINAPI
session_sink_finalizer_callback_Release(IMFAsyncCallback
*iface
)
3413 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3414 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3417 static HRESULT WINAPI
session_sink_finalizer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
3422 static HRESULT WINAPI
session_sink_finalizer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3424 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3425 IMFFinalizableMediaSink
*fin_sink
= NULL
;
3426 BOOL sinks_finalized
= TRUE
;
3427 struct media_sink
*sink
;
3431 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
3434 EnterCriticalSection(&session
->cs
);
3436 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3438 if (state
== (IUnknown
*)sink
->sink
)
3440 if (FAILED(hr
= IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
3441 WARN("Unexpected, missing IMFFinalizableSink, hr %#x.\n", hr
);
3445 sinks_finalized
&= sink
->finalized
;
3446 if (!sinks_finalized
)
3451 IUnknown_Release(state
);
3455 /* Complete session transition, or close prematurely on error. */
3456 if (SUCCEEDED(hr
= IMFFinalizableMediaSink_EndFinalize(fin_sink
, result
)))
3458 sink
->finalized
= TRUE
;
3459 if (sinks_finalized
)
3460 session_set_closed(session
, hr
);
3462 IMFFinalizableMediaSink_Release(fin_sink
);
3465 LeaveCriticalSection(&session
->cs
);
3470 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl
=
3472 session_sink_finalizer_callback_QueryInterface
,
3473 session_sink_finalizer_callback_AddRef
,
3474 session_sink_finalizer_callback_Release
,
3475 session_sink_finalizer_callback_GetParameters
,
3476 session_sink_finalizer_callback_Invoke
,
3479 static HRESULT WINAPI
session_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
3481 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3482 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3485 static ULONG WINAPI
session_rate_support_AddRef(IMFRateSupport
*iface
)
3487 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3488 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3491 static ULONG WINAPI
session_rate_support_Release(IMFRateSupport
*iface
)
3493 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3494 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3497 static HRESULT
session_presentation_object_get_rate(IUnknown
*object
, MFRATE_DIRECTION direction
,
3498 BOOL thin
, BOOL fastest
, float *result
)
3500 IMFRateSupport
*rate_support
;
3504 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3506 if (FAILED(hr
= MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
3508 if (direction
== MFRATE_FORWARD
)
3514 return MF_E_REVERSE_UNSUPPORTED
;
3520 if (SUCCEEDED(hr
= IMFRateSupport_GetFastestRate(rate_support
, direction
, thin
, &rate
)))
3521 *result
= min(fabsf(rate
), *result
);
3525 if (SUCCEEDED(hr
= IMFRateSupport_GetSlowestRate(rate_support
, direction
, thin
, &rate
)))
3526 *result
= max(fabsf(rate
), *result
);
3529 IMFRateSupport_Release(rate_support
);
3534 static HRESULT
session_get_presentation_rate(struct media_session
*session
, MFRATE_DIRECTION direction
,
3535 BOOL thin
, BOOL fastest
, float *result
)
3537 struct media_source
*source
;
3538 struct media_sink
*sink
;
3539 HRESULT hr
= E_POINTER
;
3542 rate
= fastest
? FLT_MAX
: 0.0f
;
3544 EnterCriticalSection(&session
->cs
);
3546 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
3548 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3550 if (FAILED(hr
= session_presentation_object_get_rate((IUnknown
*)source
->source
, direction
, thin
, fastest
, &rate
)))
3556 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3558 if (FAILED(hr
= session_presentation_object_get_rate((IUnknown
*)sink
->sink
, direction
, thin
, fastest
, &rate
)))
3564 LeaveCriticalSection(&session
->cs
);
3567 *result
= direction
== MFRATE_FORWARD
? rate
: -rate
;
3572 static HRESULT WINAPI
session_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3573 BOOL thin
, float *rate
)
3575 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3577 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3579 return session_get_presentation_rate(session
, direction
, thin
, FALSE
, rate
);
3582 static HRESULT WINAPI
session_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3583 BOOL thin
, float *rate
)
3585 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3587 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3589 return session_get_presentation_rate(session
, direction
, thin
, TRUE
, rate
);
3592 static HRESULT WINAPI
session_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
3593 float *nearest_supported_rate
)
3595 FIXME("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_supported_rate
);
3600 static const IMFRateSupportVtbl session_rate_support_vtbl
=
3602 session_rate_support_QueryInterface
,
3603 session_rate_support_AddRef
,
3604 session_rate_support_Release
,
3605 session_rate_support_GetSlowestRate
,
3606 session_rate_support_GetFastestRate
,
3607 session_rate_support_IsRateSupported
,
3610 static HRESULT WINAPI
session_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
3612 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3613 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3616 static ULONG WINAPI
session_rate_control_AddRef(IMFRateControl
*iface
)
3618 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3619 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3622 static ULONG WINAPI
session_rate_control_Release(IMFRateControl
*iface
)
3624 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3625 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3628 static HRESULT WINAPI
session_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
3630 FIXME("%p, %d, %f.\n", iface
, thin
, rate
);
3635 static HRESULT WINAPI
session_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
3637 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3639 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
3641 return IMFRateControl_GetRate(session
->clock_rate_control
, thin
, rate
);
3644 static const IMFRateControlVtbl session_rate_control_vtbl
=
3646 session_rate_control_QueryInterface
,
3647 session_rate_control_AddRef
,
3648 session_rate_control_Release
,
3649 session_rate_control_SetRate
,
3650 session_rate_control_GetRate
,
3653 static HRESULT WINAPI
node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor
*iface
,
3654 REFIID riid
, void **obj
)
3656 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
3658 if (IsEqualIID(riid
, &IID_IMFTopologyNodeAttributeEditor
) ||
3659 IsEqualIID(riid
, &IID_IUnknown
))
3662 IMFTopologyNodeAttributeEditor_AddRef(iface
);
3666 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
3668 return E_NOINTERFACE
;
3671 static ULONG WINAPI
node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor
*iface
)
3673 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
3674 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3677 static ULONG WINAPI
node_attribute_editor_Release(IMFTopologyNodeAttributeEditor
*iface
)
3679 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
3680 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3683 static HRESULT WINAPI
node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor
*iface
,
3684 TOPOID id
, DWORD count
, MFTOPONODE_ATTRIBUTE_UPDATE
*updates
)
3686 FIXME("%p, %s, %u, %p.\n", iface
, wine_dbgstr_longlong(id
), count
, updates
);
3691 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl
=
3693 node_attribute_editor_QueryInterface
,
3694 node_attribute_editor_AddRef
,
3695 node_attribute_editor_Release
,
3696 node_attribute_editor_UpdateNodeAttributes
,
3699 /***********************************************************************
3700 * MFCreateMediaSession (mf.@)
3702 HRESULT WINAPI
MFCreateMediaSession(IMFAttributes
*config
, IMFMediaSession
**session
)
3704 BOOL without_quality_manager
= FALSE
;
3705 struct media_session
*object
;
3708 TRACE("%p, %p.\n", config
, session
);
3710 object
= heap_alloc_zero(sizeof(*object
));
3712 return E_OUTOFMEMORY
;
3714 object
->IMFMediaSession_iface
.lpVtbl
= &mfmediasessionvtbl
;
3715 object
->IMFGetService_iface
.lpVtbl
= &session_get_service_vtbl
;
3716 object
->IMFRateSupport_iface
.lpVtbl
= &session_rate_support_vtbl
;
3717 object
->IMFRateControl_iface
.lpVtbl
= &session_rate_control_vtbl
;
3718 object
->IMFTopologyNodeAttributeEditor_iface
.lpVtbl
= &node_attribute_editor_vtbl
;
3719 object
->commands_callback
.lpVtbl
= &session_commands_callback_vtbl
;
3720 object
->events_callback
.lpVtbl
= &session_events_callback_vtbl
;
3721 object
->sink_finalizer_callback
.lpVtbl
= &session_sink_finalizer_callback_vtbl
;
3722 object
->refcount
= 1;
3723 list_init(&object
->topologies
);
3724 list_init(&object
->commands
);
3725 list_init(&object
->presentation
.sources
);
3726 list_init(&object
->presentation
.sinks
);
3727 list_init(&object
->presentation
.nodes
);
3728 InitializeCriticalSection(&object
->cs
);
3730 if (FAILED(hr
= MFCreateTopology(&object
->presentation
.current_topology
)))
3733 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
3736 if (FAILED(hr
= MFCreatePresentationClock(&object
->clock
)))
3739 if (FAILED(hr
= MFCreateSystemTimeSource(&object
->system_time_source
)))
3742 if (FAILED(hr
= IMFPresentationClock_QueryInterface(object
->clock
, &IID_IMFRateControl
,
3743 (void **)&object
->clock_rate_control
)))
3752 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_TOPOLOADER
, &clsid
)))
3754 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTopoLoader
,
3755 (void **)&object
->topo_loader
)))
3757 WARN("Failed to create custom topology loader, hr %#x.\n", hr
);
3761 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_QUALITY_MANAGER
, &clsid
)))
3763 if (!(without_quality_manager
= IsEqualGUID(&clsid
, &GUID_NULL
)))
3765 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFQualityManager
,
3766 (void **)&object
->quality_manager
)))
3768 WARN("Failed to create custom quality manager, hr %#x.\n", hr
);
3774 if (!object
->topo_loader
&& FAILED(hr
= MFCreateTopoLoader(&object
->topo_loader
)))
3777 if (!object
->quality_manager
&& !without_quality_manager
&&
3778 FAILED(hr
= MFCreateStandardQualityManager(&object
->quality_manager
)))
3783 if (object
->quality_manager
&& FAILED(hr
= IMFQualityManager_NotifyPresentationClock(object
->quality_manager
,
3789 *session
= &object
->IMFMediaSession_iface
;
3794 IMFMediaSession_Release(&object
->IMFMediaSession_iface
);
3798 static HRESULT WINAPI
sink_notification_QueryInterface(IUnknown
*iface
, REFIID riid
, void **out
)
3800 if (IsEqualIID(riid
, &IID_IUnknown
))
3803 IUnknown_AddRef(iface
);
3807 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3809 return E_NOINTERFACE
;
3812 static ULONG WINAPI
sink_notification_AddRef(IUnknown
*iface
)
3814 struct sink_notification
*notification
= impl_sink_notification_from_IUnknown(iface
);
3815 ULONG refcount
= InterlockedIncrement(¬ification
->refcount
);
3817 TRACE("%p, refcount %u.\n", iface
, refcount
);
3822 static ULONG WINAPI
sink_notification_Release(IUnknown
*iface
)
3824 struct sink_notification
*notification
= impl_sink_notification_from_IUnknown(iface
);
3825 ULONG refcount
= InterlockedDecrement(¬ification
->refcount
);
3827 TRACE("%p, refcount %u.\n", iface
, refcount
);
3831 IMFClockStateSink_Release(notification
->sink
);
3832 heap_free(notification
);
3838 static const IUnknownVtbl sinknotificationvtbl
=
3840 sink_notification_QueryInterface
,
3841 sink_notification_AddRef
,
3842 sink_notification_Release
,
3845 static void clock_notify_async_sink(struct presentation_clock
*clock
, MFTIME system_time
,
3846 struct clock_state_change_param param
, enum clock_notification notification
, IMFClockStateSink
*sink
)
3848 struct sink_notification
*object
;
3849 IMFAsyncResult
*result
;
3852 object
= heap_alloc(sizeof(*object
));
3856 object
->IUnknown_iface
.lpVtbl
= &sinknotificationvtbl
;
3857 object
->refcount
= 1;
3858 object
->system_time
= system_time
;
3859 object
->param
= param
;
3860 object
->notification
= notification
;
3861 object
->sink
= sink
;
3862 IMFClockStateSink_AddRef(object
->sink
);
3864 hr
= MFCreateAsyncResult(&object
->IUnknown_iface
, &clock
->sink_callback
, NULL
, &result
);
3865 IUnknown_Release(&object
->IUnknown_iface
);
3868 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD
, result
);
3869 IMFAsyncResult_Release(result
);
3873 static HRESULT WINAPI
present_clock_QueryInterface(IMFPresentationClock
*iface
, REFIID riid
, void **out
)
3875 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3877 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
3879 if (IsEqualIID(riid
, &IID_IMFPresentationClock
) ||
3880 IsEqualIID(riid
, &IID_IMFClock
) ||
3881 IsEqualIID(riid
, &IID_IUnknown
))
3883 *out
= &clock
->IMFPresentationClock_iface
;
3885 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
3887 *out
= &clock
->IMFRateControl_iface
;
3889 else if (IsEqualIID(riid
, &IID_IMFTimer
))
3891 *out
= &clock
->IMFTimer_iface
;
3893 else if (IsEqualIID(riid
, &IID_IMFShutdown
))
3895 *out
= &clock
->IMFShutdown_iface
;
3899 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3901 return E_NOINTERFACE
;
3904 IUnknown_AddRef((IUnknown
*)*out
);
3908 static ULONG WINAPI
present_clock_AddRef(IMFPresentationClock
*iface
)
3910 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3911 ULONG refcount
= InterlockedIncrement(&clock
->refcount
);
3913 TRACE("%p, refcount %u.\n", iface
, refcount
);
3918 static ULONG WINAPI
present_clock_Release(IMFPresentationClock
*iface
)
3920 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3921 ULONG refcount
= InterlockedDecrement(&clock
->refcount
);
3922 struct clock_timer
*timer
, *timer2
;
3923 struct clock_sink
*sink
, *sink2
;
3925 TRACE("%p, refcount %u.\n", iface
, refcount
);
3929 if (clock
->time_source
)
3930 IMFPresentationTimeSource_Release(clock
->time_source
);
3931 if (clock
->time_source_sink
)
3932 IMFClockStateSink_Release(clock
->time_source_sink
);
3933 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &clock
->sinks
, struct clock_sink
, entry
)
3935 list_remove(&sink
->entry
);
3936 IMFClockStateSink_Release(sink
->state_sink
);
3939 LIST_FOR_EACH_ENTRY_SAFE(timer
, timer2
, &clock
->timers
, struct clock_timer
, entry
)
3941 list_remove(&timer
->entry
);
3942 IUnknown_Release(&timer
->IUnknown_iface
);
3944 DeleteCriticalSection(&clock
->cs
);
3951 static HRESULT WINAPI
present_clock_GetClockCharacteristics(IMFPresentationClock
*iface
, DWORD
*flags
)
3953 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3954 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3956 TRACE("%p, %p.\n", iface
, flags
);
3958 EnterCriticalSection(&clock
->cs
);
3959 if (clock
->time_source
)
3960 hr
= IMFPresentationTimeSource_GetClockCharacteristics(clock
->time_source
, flags
);
3961 LeaveCriticalSection(&clock
->cs
);
3966 static HRESULT WINAPI
present_clock_GetCorrelatedTime(IMFPresentationClock
*iface
, DWORD reserved
,
3967 LONGLONG
*clock_time
, MFTIME
*system_time
)
3969 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3970 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
3972 TRACE("%p, %#x, %p, %p.\n", iface
, reserved
, clock_time
, system_time
);
3974 EnterCriticalSection(&clock
->cs
);
3975 if (clock
->time_source
)
3976 hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, reserved
, clock_time
, system_time
);
3977 LeaveCriticalSection(&clock
->cs
);
3982 static HRESULT WINAPI
present_clock_GetContinuityKey(IMFPresentationClock
*iface
, DWORD
*key
)
3984 TRACE("%p, %p.\n", iface
, key
);
3991 static HRESULT WINAPI
present_clock_GetState(IMFPresentationClock
*iface
, DWORD reserved
, MFCLOCK_STATE
*state
)
3993 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
3995 TRACE("%p, %#x, %p.\n", iface
, reserved
, state
);
3997 EnterCriticalSection(&clock
->cs
);
3998 *state
= clock
->state
;
3999 LeaveCriticalSection(&clock
->cs
);
4004 static HRESULT WINAPI
present_clock_GetProperties(IMFPresentationClock
*iface
, MFCLOCK_PROPERTIES
*props
)
4006 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4007 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
4009 TRACE("%p, %p.\n", iface
, props
);
4011 EnterCriticalSection(&clock
->cs
);
4012 if (clock
->time_source
)
4013 hr
= IMFPresentationTimeSource_GetProperties(clock
->time_source
, props
);
4014 LeaveCriticalSection(&clock
->cs
);
4019 static HRESULT WINAPI
present_clock_SetTimeSource(IMFPresentationClock
*iface
,
4020 IMFPresentationTimeSource
*time_source
)
4022 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4023 MFCLOCK_PROPERTIES props
;
4024 IMFClock
*source_clock
;
4027 TRACE("%p, %p.\n", iface
, time_source
);
4029 EnterCriticalSection(&clock
->cs
);
4031 if (clock
->time_source
)
4032 IMFPresentationTimeSource_Release(clock
->time_source
);
4033 if (clock
->time_source_sink
)
4034 IMFClockStateSink_Release(clock
->time_source_sink
);
4035 clock
->time_source
= NULL
;
4036 clock
->time_source_sink
= NULL
;
4038 hr
= IMFPresentationTimeSource_QueryInterface(time_source
, &IID_IMFClockStateSink
, (void **)&clock
->time_source_sink
);
4041 clock
->time_source
= time_source
;
4042 IMFPresentationTimeSource_AddRef(clock
->time_source
);
4045 if (SUCCEEDED(IMFPresentationTimeSource_GetUnderlyingClock(time_source
, &source_clock
)))
4047 if (SUCCEEDED(IMFClock_GetProperties(source_clock
, &props
)))
4048 clock
->frequency
= props
.qwClockFrequency
;
4049 IMFClock_Release(source_clock
);
4052 if (!clock
->frequency
)
4053 clock
->frequency
= MFCLOCK_FREQUENCY_HNS
;
4055 LeaveCriticalSection(&clock
->cs
);
4060 static HRESULT WINAPI
present_clock_GetTimeSource(IMFPresentationClock
*iface
,
4061 IMFPresentationTimeSource
**time_source
)
4063 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4066 TRACE("%p, %p.\n", iface
, time_source
);
4069 return E_INVALIDARG
;
4071 EnterCriticalSection(&clock
->cs
);
4072 if (clock
->time_source
)
4074 *time_source
= clock
->time_source
;
4075 IMFPresentationTimeSource_AddRef(*time_source
);
4078 hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
4079 LeaveCriticalSection(&clock
->cs
);
4084 static HRESULT WINAPI
present_clock_GetTime(IMFPresentationClock
*iface
, MFTIME
*time
)
4086 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4087 HRESULT hr
= MF_E_CLOCK_NO_TIME_SOURCE
;
4090 TRACE("%p, %p.\n", iface
, time
);
4095 EnterCriticalSection(&clock
->cs
);
4096 if (clock
->time_source
)
4097 hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, 0, time
, &systime
);
4098 LeaveCriticalSection(&clock
->cs
);
4103 static HRESULT WINAPI
present_clock_AddClockStateSink(IMFPresentationClock
*iface
, IMFClockStateSink
*state_sink
)
4105 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4106 struct clock_sink
*sink
, *cur
;
4109 TRACE("%p, %p.\n", iface
, state_sink
);
4112 return E_INVALIDARG
;
4114 sink
= heap_alloc(sizeof(*sink
));
4116 return E_OUTOFMEMORY
;
4118 sink
->state_sink
= state_sink
;
4119 IMFClockStateSink_AddRef(sink
->state_sink
);
4121 EnterCriticalSection(&clock
->cs
);
4122 LIST_FOR_EACH_ENTRY(cur
, &clock
->sinks
, struct clock_sink
, entry
)
4124 if (cur
->state_sink
== state_sink
)
4132 static const enum clock_notification notifications
[MFCLOCK_STATE_PAUSED
+ 1] =
4134 /* MFCLOCK_STATE_INVALID */ 0, /* Does not apply */
4135 /* MFCLOCK_STATE_RUNNING */ CLOCK_NOTIFY_START
,
4136 /* MFCLOCK_STATE_STOPPED */ CLOCK_NOTIFY_STOP
,
4137 /* MFCLOCK_STATE_PAUSED */ CLOCK_NOTIFY_PAUSE
,
4139 struct clock_state_change_param param
;
4141 if (!clock
->is_shut_down
&& clock
->state
!= MFCLOCK_STATE_INVALID
)
4143 param
.u
.offset
= clock
->start_offset
;
4144 clock_notify_async_sink(clock
, MFGetSystemTime(), param
, notifications
[clock
->state
], sink
->state_sink
);
4147 list_add_tail(&clock
->sinks
, &sink
->entry
);
4149 LeaveCriticalSection(&clock
->cs
);
4153 IMFClockStateSink_Release(sink
->state_sink
);
4160 static HRESULT WINAPI
present_clock_RemoveClockStateSink(IMFPresentationClock
*iface
,
4161 IMFClockStateSink
*state_sink
)
4163 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4164 struct clock_sink
*sink
;
4166 TRACE("%p, %p.\n", iface
, state_sink
);
4169 return E_INVALIDARG
;
4171 EnterCriticalSection(&clock
->cs
);
4172 LIST_FOR_EACH_ENTRY(sink
, &clock
->sinks
, struct clock_sink
, entry
)
4174 if (sink
->state_sink
== state_sink
)
4176 IMFClockStateSink_Release(sink
->state_sink
);
4177 list_remove(&sink
->entry
);
4182 LeaveCriticalSection(&clock
->cs
);
4187 static HRESULT
clock_call_state_change(MFTIME system_time
, struct clock_state_change_param param
,
4188 enum clock_notification notification
, IMFClockStateSink
*sink
)
4192 switch (notification
)
4194 case CLOCK_NOTIFY_START
:
4195 hr
= IMFClockStateSink_OnClockStart(sink
, system_time
, param
.u
.offset
);
4197 case CLOCK_NOTIFY_STOP
:
4198 hr
= IMFClockStateSink_OnClockStop(sink
, system_time
);
4200 case CLOCK_NOTIFY_PAUSE
:
4201 hr
= IMFClockStateSink_OnClockPause(sink
, system_time
);
4203 case CLOCK_NOTIFY_RESTART
:
4204 hr
= IMFClockStateSink_OnClockRestart(sink
, system_time
);
4206 case CLOCK_NOTIFY_SET_RATE
:
4207 /* System time source does not allow 0.0 rate, presentation clock allows it without raising errors. */
4208 IMFClockStateSink_OnClockSetRate(sink
, system_time
, param
.u
.rate
);
4217 static HRESULT
clock_change_state(struct presentation_clock
*clock
, enum clock_command command
,
4218 struct clock_state_change_param param
)
4220 static const BYTE state_change_is_allowed
[MFCLOCK_STATE_PAUSED
+1][CLOCK_CMD_MAX
] =
4222 /* INVALID */ { 1, 1, 1, 1 },
4223 /* RUNNING */ { 1, 1, 1, 1 },
4224 /* STOPPED */ { 1, 1, 0, 1 },
4225 /* PAUSED */ { 1, 1, 0, 1 },
4227 static const MFCLOCK_STATE states
[CLOCK_CMD_MAX
] =
4229 /* CLOCK_CMD_START */ MFCLOCK_STATE_RUNNING
,
4230 /* CLOCK_CMD_STOP */ MFCLOCK_STATE_STOPPED
,
4231 /* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED
,
4232 /* CLOCK_CMD_SET_RATE */ 0, /* Unused */
4234 static const enum clock_notification notifications
[CLOCK_CMD_MAX
] =
4236 /* CLOCK_CMD_START */ CLOCK_NOTIFY_START
,
4237 /* CLOCK_CMD_STOP */ CLOCK_NOTIFY_STOP
,
4238 /* CLOCK_CMD_PAUSE */ CLOCK_NOTIFY_PAUSE
,
4239 /* CLOCK_CMD_SET_RATE */ CLOCK_NOTIFY_SET_RATE
,
4241 enum clock_notification notification
;
4242 struct clock_sink
*sink
;
4243 MFCLOCK_STATE old_state
;
4244 IMFAsyncResult
*result
;
4248 if (!clock
->time_source
)
4249 return MF_E_CLOCK_NO_TIME_SOURCE
;
4251 if (command
!= CLOCK_CMD_SET_RATE
&& clock
->state
== states
[command
] && clock
->state
!= MFCLOCK_STATE_RUNNING
)
4252 return MF_E_CLOCK_STATE_ALREADY_SET
;
4254 if (!state_change_is_allowed
[clock
->state
][command
])
4255 return MF_E_INVALIDREQUEST
;
4257 system_time
= MFGetSystemTime();
4259 if (command
== CLOCK_CMD_START
&& clock
->state
== MFCLOCK_STATE_PAUSED
&&
4260 param
.u
.offset
== PRESENTATION_CURRENT_POSITION
)
4262 notification
= CLOCK_NOTIFY_RESTART
;
4265 notification
= notifications
[command
];
4267 if (FAILED(hr
= clock_call_state_change(system_time
, param
, notification
, clock
->time_source_sink
)))
4270 old_state
= clock
->state
;
4271 if (command
!= CLOCK_CMD_SET_RATE
)
4272 clock
->state
= states
[command
];
4274 /* Dump all pending timer requests immediately on start; otherwise try to cancel scheduled items when
4275 transitioning from running state. */
4276 if ((clock
->state
== MFCLOCK_STATE_RUNNING
) ^ (old_state
== MFCLOCK_STATE_RUNNING
))
4278 struct clock_timer
*timer
, *timer2
;
4280 if (clock
->state
== MFCLOCK_STATE_RUNNING
)
4282 LIST_FOR_EACH_ENTRY_SAFE(timer
, timer2
, &clock
->timers
, struct clock_timer
, entry
)
4284 list_remove(&timer
->entry
);
4285 hr
= MFCreateAsyncResult(&timer
->IUnknown_iface
, &clock
->timer_callback
, NULL
, &result
);
4286 IUnknown_Release(&timer
->IUnknown_iface
);
4289 MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_TIMER
, result
);
4290 IMFAsyncResult_Release(result
);
4296 LIST_FOR_EACH_ENTRY(timer
, &clock
->timers
, struct clock_timer
, entry
)
4300 MFCancelWorkItem(timer
->key
);
4307 LIST_FOR_EACH_ENTRY(sink
, &clock
->sinks
, struct clock_sink
, entry
)
4309 clock_notify_async_sink(clock
, system_time
, param
, notification
, sink
->state_sink
);
4315 static HRESULT WINAPI
present_clock_Start(IMFPresentationClock
*iface
, LONGLONG start_offset
)
4317 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4318 struct clock_state_change_param param
= {{0}};
4321 TRACE("%p, %s.\n", iface
, debugstr_time(start_offset
));
4323 EnterCriticalSection(&clock
->cs
);
4324 clock
->start_offset
= param
.u
.offset
= start_offset
;
4325 hr
= clock_change_state(clock
, CLOCK_CMD_START
, param
);
4326 LeaveCriticalSection(&clock
->cs
);
4331 static HRESULT WINAPI
present_clock_Stop(IMFPresentationClock
*iface
)
4333 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4334 struct clock_state_change_param param
= {{0}};
4337 TRACE("%p.\n", iface
);
4339 EnterCriticalSection(&clock
->cs
);
4340 hr
= clock_change_state(clock
, CLOCK_CMD_STOP
, param
);
4341 LeaveCriticalSection(&clock
->cs
);
4346 static HRESULT WINAPI
present_clock_Pause(IMFPresentationClock
*iface
)
4348 struct presentation_clock
*clock
= impl_from_IMFPresentationClock(iface
);
4349 struct clock_state_change_param param
= {{0}};
4352 TRACE("%p.\n", iface
);
4354 EnterCriticalSection(&clock
->cs
);
4355 hr
= clock_change_state(clock
, CLOCK_CMD_PAUSE
, param
);
4356 LeaveCriticalSection(&clock
->cs
);
4361 static const IMFPresentationClockVtbl presentationclockvtbl
=
4363 present_clock_QueryInterface
,
4364 present_clock_AddRef
,
4365 present_clock_Release
,
4366 present_clock_GetClockCharacteristics
,
4367 present_clock_GetCorrelatedTime
,
4368 present_clock_GetContinuityKey
,
4369 present_clock_GetState
,
4370 present_clock_GetProperties
,
4371 present_clock_SetTimeSource
,
4372 present_clock_GetTimeSource
,
4373 present_clock_GetTime
,
4374 present_clock_AddClockStateSink
,
4375 present_clock_RemoveClockStateSink
,
4376 present_clock_Start
,
4378 present_clock_Pause
,
4381 static HRESULT WINAPI
present_clock_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **out
)
4383 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4384 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
4387 static ULONG WINAPI
present_clock_rate_control_AddRef(IMFRateControl
*iface
)
4389 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4390 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4393 static ULONG WINAPI
present_clock_rate_control_Release(IMFRateControl
*iface
)
4395 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4396 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4399 static HRESULT WINAPI
present_clock_rate_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
4401 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4402 struct clock_state_change_param param
;
4405 TRACE("%p, %d, %f.\n", iface
, thin
, rate
);
4408 return MF_E_THINNING_UNSUPPORTED
;
4410 EnterCriticalSection(&clock
->cs
);
4411 param
.u
.rate
= rate
;
4412 if (SUCCEEDED(hr
= clock_change_state(clock
, CLOCK_CMD_SET_RATE
, param
)))
4414 LeaveCriticalSection(&clock
->cs
);
4419 static HRESULT WINAPI
present_clock_rate_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
4421 struct presentation_clock
*clock
= impl_from_IMFRateControl(iface
);
4423 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
4426 return E_INVALIDARG
;
4431 EnterCriticalSection(&clock
->cs
);
4432 *rate
= clock
->rate
;
4433 LeaveCriticalSection(&clock
->cs
);
4438 static const IMFRateControlVtbl presentclockratecontrolvtbl
=
4440 present_clock_rate_control_QueryInterface
,
4441 present_clock_rate_control_AddRef
,
4442 present_clock_rate_control_Release
,
4443 present_clock_rate_SetRate
,
4444 present_clock_rate_GetRate
,
4447 static HRESULT WINAPI
present_clock_timer_QueryInterface(IMFTimer
*iface
, REFIID riid
, void **out
)
4449 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4450 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
4453 static ULONG WINAPI
present_clock_timer_AddRef(IMFTimer
*iface
)
4455 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4456 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4459 static ULONG WINAPI
present_clock_timer_Release(IMFTimer
*iface
)
4461 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4462 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4465 static HRESULT
present_clock_schedule_timer(struct presentation_clock
*clock
, DWORD flags
, LONGLONG time
,
4466 struct clock_timer
*timer
)
4468 IMFAsyncResult
*result
;
4469 MFTIME systime
, clocktime
;
4473 if (!(flags
& MFTIMER_RELATIVE
))
4475 if (FAILED(hr
= IMFPresentationTimeSource_GetCorrelatedTime(clock
->time_source
, 0, &clocktime
, &systime
)))
4477 WARN("Failed to get clock time, hr %#x.\n", hr
);
4483 frequency
= clock
->frequency
/ 1000;
4486 /* Scheduled item is using clock instance callback, with timer instance as an object. Clock callback will
4487 call user callback and cleanup timer list. */
4489 if (FAILED(hr
= MFCreateAsyncResult(&timer
->IUnknown_iface
, &clock
->timer_callback
, NULL
, &result
)))
4492 hr
= MFScheduleWorkItemEx(result
, -time
, &timer
->key
);
4493 IMFAsyncResult_Release(result
);
4498 static HRESULT WINAPI
clock_timer_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
4500 if (IsEqualIID(riid
, &IID_IUnknown
))
4503 IUnknown_AddRef(iface
);
4508 return E_NOINTERFACE
;
4511 static ULONG WINAPI
clock_timer_AddRef(IUnknown
*iface
)
4513 struct clock_timer
*timer
= impl_clock_timer_from_IUnknown(iface
);
4514 return InterlockedIncrement(&timer
->refcount
);
4517 static ULONG WINAPI
clock_timer_Release(IUnknown
*iface
)
4519 struct clock_timer
*timer
= impl_clock_timer_from_IUnknown(iface
);
4520 ULONG refcount
= InterlockedDecrement(&timer
->refcount
);
4524 IMFAsyncResult_Release(timer
->result
);
4525 IMFAsyncCallback_Release(timer
->callback
);
4532 static const IUnknownVtbl clock_timer_vtbl
=
4534 clock_timer_QueryInterface
,
4536 clock_timer_Release
,
4539 static HRESULT WINAPI
present_clock_timer_SetTimer(IMFTimer
*iface
, DWORD flags
, LONGLONG time
,
4540 IMFAsyncCallback
*callback
, IUnknown
*state
, IUnknown
**cancel_key
)
4542 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4543 struct clock_timer
*clock_timer
;
4546 TRACE("%p, %#x, %s, %p, %p, %p.\n", iface
, flags
, debugstr_time(time
), callback
, state
, cancel_key
);
4548 if (!(clock_timer
= heap_alloc_zero(sizeof(*clock_timer
))))
4549 return E_OUTOFMEMORY
;
4551 if (FAILED(hr
= MFCreateAsyncResult(NULL
, NULL
, state
, &clock_timer
->result
)))
4553 heap_free(clock_timer
);
4557 clock_timer
->IUnknown_iface
.lpVtbl
= &clock_timer_vtbl
;
4558 clock_timer
->refcount
= 1;
4559 clock_timer
->callback
= callback
;
4560 IMFAsyncCallback_AddRef(clock_timer
->callback
);
4562 EnterCriticalSection(&clock
->cs
);
4564 if (clock
->state
== MFCLOCK_STATE_RUNNING
)
4565 hr
= present_clock_schedule_timer(clock
, flags
, time
, clock_timer
);
4566 else if (clock
->state
== MFCLOCK_STATE_STOPPED
)
4567 hr
= MF_S_CLOCK_STOPPED
;
4571 list_add_tail(&clock
->timers
, &clock_timer
->entry
);
4574 *cancel_key
= &clock_timer
->IUnknown_iface
;
4575 IUnknown_AddRef(*cancel_key
);
4579 LeaveCriticalSection(&clock
->cs
);
4582 IUnknown_Release(&clock_timer
->IUnknown_iface
);
4587 static HRESULT WINAPI
present_clock_timer_CancelTimer(IMFTimer
*iface
, IUnknown
*cancel_key
)
4589 struct presentation_clock
*clock
= impl_from_IMFTimer(iface
);
4590 struct clock_timer
*timer
;
4592 TRACE("%p, %p.\n", iface
, cancel_key
);
4594 EnterCriticalSection(&clock
->cs
);
4596 LIST_FOR_EACH_ENTRY(timer
, &clock
->timers
, struct clock_timer
, entry
)
4598 if (&timer
->IUnknown_iface
== cancel_key
)
4600 list_remove(&timer
->entry
);
4603 MFCancelWorkItem(timer
->key
);
4606 IUnknown_Release(&timer
->IUnknown_iface
);
4611 LeaveCriticalSection(&clock
->cs
);
4616 static const IMFTimerVtbl presentclocktimervtbl
=
4618 present_clock_timer_QueryInterface
,
4619 present_clock_timer_AddRef
,
4620 present_clock_timer_Release
,
4621 present_clock_timer_SetTimer
,
4622 present_clock_timer_CancelTimer
,
4625 static HRESULT WINAPI
present_clock_shutdown_QueryInterface(IMFShutdown
*iface
, REFIID riid
, void **out
)
4627 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4628 return IMFPresentationClock_QueryInterface(&clock
->IMFPresentationClock_iface
, riid
, out
);
4631 static ULONG WINAPI
present_clock_shutdown_AddRef(IMFShutdown
*iface
)
4633 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4634 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4637 static ULONG WINAPI
present_clock_shutdown_Release(IMFShutdown
*iface
)
4639 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4640 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4643 static HRESULT WINAPI
present_clock_shutdown_Shutdown(IMFShutdown
*iface
)
4645 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4647 TRACE("%p.\n", iface
);
4649 EnterCriticalSection(&clock
->cs
);
4650 clock
->is_shut_down
= TRUE
;
4651 LeaveCriticalSection(&clock
->cs
);
4656 static HRESULT WINAPI
present_clock_shutdown_GetShutdownStatus(IMFShutdown
*iface
, MFSHUTDOWN_STATUS
*status
)
4658 struct presentation_clock
*clock
= impl_from_IMFShutdown(iface
);
4661 TRACE("%p, %p.\n", iface
, status
);
4664 return E_INVALIDARG
;
4666 EnterCriticalSection(&clock
->cs
);
4667 if (clock
->is_shut_down
)
4668 *status
= MFSHUTDOWN_COMPLETED
;
4670 hr
= MF_E_INVALIDREQUEST
;
4671 LeaveCriticalSection(&clock
->cs
);
4676 static const IMFShutdownVtbl presentclockshutdownvtbl
=
4678 present_clock_shutdown_QueryInterface
,
4679 present_clock_shutdown_AddRef
,
4680 present_clock_shutdown_Release
,
4681 present_clock_shutdown_Shutdown
,
4682 present_clock_shutdown_GetShutdownStatus
,
4685 static HRESULT WINAPI
present_clock_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **out
)
4687 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
4688 IsEqualIID(riid
, &IID_IUnknown
))
4691 IMFAsyncCallback_AddRef(iface
);
4695 WARN("Unsupported %s.\n", wine_dbgstr_guid(riid
));
4697 return E_NOINTERFACE
;
4700 static ULONG WINAPI
present_clock_sink_callback_AddRef(IMFAsyncCallback
*iface
)
4702 struct presentation_clock
*clock
= impl_from_sink_callback_IMFAsyncCallback(iface
);
4703 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4706 static ULONG WINAPI
present_clock_sink_callback_Release(IMFAsyncCallback
*iface
)
4708 struct presentation_clock
*clock
= impl_from_sink_callback_IMFAsyncCallback(iface
);
4709 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4712 static HRESULT WINAPI
present_clock_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
4717 static HRESULT WINAPI
present_clock_sink_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
4719 struct sink_notification
*data
;
4723 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &object
)))
4726 data
= impl_sink_notification_from_IUnknown(object
);
4728 clock_call_state_change(data
->system_time
, data
->param
, data
->notification
, data
->sink
);
4730 IUnknown_Release(object
);
4735 static const IMFAsyncCallbackVtbl presentclocksinkcallbackvtbl
=
4737 present_clock_callback_QueryInterface
,
4738 present_clock_sink_callback_AddRef
,
4739 present_clock_sink_callback_Release
,
4740 present_clock_callback_GetParameters
,
4741 present_clock_sink_callback_Invoke
,
4744 static ULONG WINAPI
present_clock_timer_callback_AddRef(IMFAsyncCallback
*iface
)
4746 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
4747 return IMFPresentationClock_AddRef(&clock
->IMFPresentationClock_iface
);
4750 static ULONG WINAPI
present_clock_timer_callback_Release(IMFAsyncCallback
*iface
)
4752 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
4753 return IMFPresentationClock_Release(&clock
->IMFPresentationClock_iface
);
4756 static HRESULT WINAPI
present_clock_timer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
4758 struct presentation_clock
*clock
= impl_from_timer_callback_IMFAsyncCallback(iface
);
4759 struct clock_timer
*timer
;
4763 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &object
)))
4766 timer
= impl_clock_timer_from_IUnknown(object
);
4768 EnterCriticalSection(&clock
->cs
);
4769 list_remove(&timer
->entry
);
4770 IUnknown_Release(&timer
->IUnknown_iface
);
4771 LeaveCriticalSection(&clock
->cs
);
4773 IMFAsyncCallback_Invoke(timer
->callback
, timer
->result
);
4775 IUnknown_Release(object
);
4780 static const IMFAsyncCallbackVtbl presentclocktimercallbackvtbl
=
4782 present_clock_callback_QueryInterface
,
4783 present_clock_timer_callback_AddRef
,
4784 present_clock_timer_callback_Release
,
4785 present_clock_callback_GetParameters
,
4786 present_clock_timer_callback_Invoke
,
4789 /***********************************************************************
4790 * MFCreatePresentationClock (mf.@)
4792 HRESULT WINAPI
MFCreatePresentationClock(IMFPresentationClock
**clock
)
4794 struct presentation_clock
*object
;
4796 TRACE("%p.\n", clock
);
4798 object
= heap_alloc_zero(sizeof(*object
));
4800 return E_OUTOFMEMORY
;
4802 object
->IMFPresentationClock_iface
.lpVtbl
= &presentationclockvtbl
;
4803 object
->IMFRateControl_iface
.lpVtbl
= &presentclockratecontrolvtbl
;
4804 object
->IMFTimer_iface
.lpVtbl
= &presentclocktimervtbl
;
4805 object
->IMFShutdown_iface
.lpVtbl
= &presentclockshutdownvtbl
;
4806 object
->sink_callback
.lpVtbl
= &presentclocksinkcallbackvtbl
;
4807 object
->timer_callback
.lpVtbl
= &presentclocktimercallbackvtbl
;
4808 object
->refcount
= 1;
4809 list_init(&object
->sinks
);
4810 list_init(&object
->timers
);
4811 object
->rate
= 1.0f
;
4812 InitializeCriticalSection(&object
->cs
);
4814 *clock
= &object
->IMFPresentationClock_iface
;
4819 static HRESULT WINAPI
standard_quality_manager_QueryInterface(IMFQualityManager
*iface
, REFIID riid
, void **out
)
4821 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
4823 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
4825 if (IsEqualIID(riid
, &IID_IMFQualityManager
) ||
4826 IsEqualIID(riid
, &IID_IUnknown
))
4830 else if (IsEqualIID(riid
, &IID_IMFClockStateSink
))
4832 *out
= &manager
->IMFClockStateSink_iface
;
4836 WARN("Unsupported %s.\n", debugstr_guid(riid
));
4838 return E_NOINTERFACE
;
4841 IUnknown_AddRef((IUnknown
*)*out
);
4845 static ULONG WINAPI
standard_quality_manager_AddRef(IMFQualityManager
*iface
)
4847 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
4848 ULONG refcount
= InterlockedIncrement(&manager
->refcount
);
4850 TRACE("%p, refcount %u.\n", iface
, refcount
);
4855 static ULONG WINAPI
standard_quality_manager_Release(IMFQualityManager
*iface
)
4857 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
4858 ULONG refcount
= InterlockedDecrement(&manager
->refcount
);
4860 TRACE("%p, refcount %u.\n", iface
, refcount
);
4865 IMFPresentationClock_Release(manager
->clock
);
4866 if (manager
->topology
)
4867 IMFTopology_Release(manager
->topology
);
4868 DeleteCriticalSection(&manager
->cs
);
4875 static void standard_quality_manager_set_topology(struct quality_manager
*manager
, IMFTopology
*topology
)
4877 if (manager
->topology
)
4878 IMFTopology_Release(manager
->topology
);
4879 manager
->topology
= topology
;
4880 if (manager
->topology
)
4881 IMFTopology_AddRef(manager
->topology
);
4884 static HRESULT WINAPI
standard_quality_manager_NotifyTopology(IMFQualityManager
*iface
, IMFTopology
*topology
)
4886 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
4889 TRACE("%p, %p.\n", iface
, topology
);
4891 EnterCriticalSection(&manager
->cs
);
4892 if (manager
->state
== QUALITY_MANAGER_SHUT_DOWN
)
4896 standard_quality_manager_set_topology(manager
, topology
);
4898 LeaveCriticalSection(&manager
->cs
);
4903 static void standard_quality_manager_release_clock(struct quality_manager
*manager
)
4907 IMFPresentationClock_RemoveClockStateSink(manager
->clock
, &manager
->IMFClockStateSink_iface
);
4908 IMFPresentationClock_Release(manager
->clock
);
4910 manager
->clock
= NULL
;
4913 static HRESULT WINAPI
standard_quality_manager_NotifyPresentationClock(IMFQualityManager
*iface
,
4914 IMFPresentationClock
*clock
)
4916 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
4919 TRACE("%p, %p.\n", iface
, clock
);
4921 EnterCriticalSection(&manager
->cs
);
4922 if (manager
->state
== QUALITY_MANAGER_SHUT_DOWN
)
4928 standard_quality_manager_release_clock(manager
);
4929 manager
->clock
= clock
;
4930 IMFPresentationClock_AddRef(manager
->clock
);
4931 if (FAILED(IMFPresentationClock_AddClockStateSink(manager
->clock
, &manager
->IMFClockStateSink_iface
)))
4932 WARN("Failed to set state sink.\n");
4934 LeaveCriticalSection(&manager
->cs
);
4939 static HRESULT WINAPI
standard_quality_manager_NotifyProcessInput(IMFQualityManager
*iface
, IMFTopologyNode
*node
,
4940 LONG input_index
, IMFSample
*sample
)
4942 TRACE("%p, %p, %d, %p stub.\n", iface
, node
, input_index
, sample
);
4947 static HRESULT WINAPI
standard_quality_manager_NotifyProcessOutput(IMFQualityManager
*iface
, IMFTopologyNode
*node
,
4948 LONG output_index
, IMFSample
*sample
)
4950 TRACE("%p, %p, %d, %p stub.\n", iface
, node
, output_index
, sample
);
4955 static HRESULT WINAPI
standard_quality_manager_NotifyQualityEvent(IMFQualityManager
*iface
, IUnknown
*object
,
4956 IMFMediaEvent
*event
)
4958 FIXME("%p, %p, %p stub.\n", iface
, object
, event
);
4963 static HRESULT WINAPI
standard_quality_manager_Shutdown(IMFQualityManager
*iface
)
4965 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
4967 TRACE("%p.\n", iface
);
4969 EnterCriticalSection(&manager
->cs
);
4970 if (manager
->state
!= QUALITY_MANAGER_SHUT_DOWN
)
4972 standard_quality_manager_release_clock(manager
);
4973 standard_quality_manager_set_topology(manager
, NULL
);
4974 manager
->state
= QUALITY_MANAGER_SHUT_DOWN
;
4976 LeaveCriticalSection(&manager
->cs
);
4981 static const IMFQualityManagerVtbl standard_quality_manager_vtbl
=
4983 standard_quality_manager_QueryInterface
,
4984 standard_quality_manager_AddRef
,
4985 standard_quality_manager_Release
,
4986 standard_quality_manager_NotifyTopology
,
4987 standard_quality_manager_NotifyPresentationClock
,
4988 standard_quality_manager_NotifyProcessInput
,
4989 standard_quality_manager_NotifyProcessOutput
,
4990 standard_quality_manager_NotifyQualityEvent
,
4991 standard_quality_manager_Shutdown
,
4994 static HRESULT WINAPI
standard_quality_manager_sink_QueryInterface(IMFClockStateSink
*iface
,
4995 REFIID riid
, void **obj
)
4997 struct quality_manager
*manager
= impl_from_qm_IMFClockStateSink(iface
);
4998 return IMFQualityManager_QueryInterface(&manager
->IMFQualityManager_iface
, riid
, obj
);
5001 static ULONG WINAPI
standard_quality_manager_sink_AddRef(IMFClockStateSink
*iface
)
5003 struct quality_manager
*manager
= impl_from_qm_IMFClockStateSink(iface
);
5004 return IMFQualityManager_AddRef(&manager
->IMFQualityManager_iface
);
5007 static ULONG WINAPI
standard_quality_manager_sink_Release(IMFClockStateSink
*iface
)
5009 struct quality_manager
*manager
= impl_from_qm_IMFClockStateSink(iface
);
5010 return IMFQualityManager_Release(&manager
->IMFQualityManager_iface
);
5013 static HRESULT WINAPI
standard_quality_manager_sink_OnClockStart(IMFClockStateSink
*iface
,
5014 MFTIME systime
, LONGLONG offset
)
5019 static HRESULT WINAPI
standard_quality_manager_sink_OnClockStop(IMFClockStateSink
*iface
,
5025 static HRESULT WINAPI
standard_quality_manager_sink_OnClockPause(IMFClockStateSink
*iface
,
5031 static HRESULT WINAPI
standard_quality_manager_sink_OnClockRestart(IMFClockStateSink
*iface
,
5037 static HRESULT WINAPI
standard_quality_manager_sink_OnClockSetRate(IMFClockStateSink
*iface
,
5038 MFTIME systime
, float rate
)
5043 static const IMFClockStateSinkVtbl standard_quality_manager_sink_vtbl
=
5045 standard_quality_manager_sink_QueryInterface
,
5046 standard_quality_manager_sink_AddRef
,
5047 standard_quality_manager_sink_Release
,
5048 standard_quality_manager_sink_OnClockStart
,
5049 standard_quality_manager_sink_OnClockStop
,
5050 standard_quality_manager_sink_OnClockPause
,
5051 standard_quality_manager_sink_OnClockRestart
,
5052 standard_quality_manager_sink_OnClockSetRate
,
5055 HRESULT WINAPI
MFCreateStandardQualityManager(IMFQualityManager
**manager
)
5057 struct quality_manager
*object
;
5059 TRACE("%p.\n", manager
);
5061 object
= heap_alloc_zero(sizeof(*object
));
5063 return E_OUTOFMEMORY
;
5065 object
->IMFQualityManager_iface
.lpVtbl
= &standard_quality_manager_vtbl
;
5066 object
->IMFClockStateSink_iface
.lpVtbl
= &standard_quality_manager_sink_vtbl
;
5067 object
->refcount
= 1;
5068 InitializeCriticalSection(&object
->cs
);
5070 *manager
= &object
->IMFQualityManager_iface
;