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/list.h"
33 #include "mf_private.h"
37 DEFINE_GUID(_MF_TOPONODE_IMFActivate
, 0x33706f4a, 0x309a, 0x49be, 0xa8, 0xdd, 0xe7, 0xc0, 0x87, 0x5e, 0xb6, 0x79);
39 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
43 SESSION_CMD_CLEAR_TOPOLOGIES
,
45 SESSION_CMD_SET_TOPOLOGY
,
55 IUnknown IUnknown_iface
;
57 enum session_command command
;
63 IMFTopology
*topology
;
68 PROPVARIANT start_position
;
77 IMFTopology
*topology
;
83 struct queued_topology
86 IMFTopology
*topology
;
92 SESSION_STATE_STOPPED
= 0,
93 SESSION_STATE_STARTING_SOURCES
,
94 SESSION_STATE_PREROLLING_SINKS
,
95 SESSION_STATE_STARTING_SINKS
,
96 SESSION_STATE_STARTED
,
97 SESSION_STATE_PAUSING_SINKS
,
98 SESSION_STATE_PAUSING_SOURCES
,
100 SESSION_STATE_STOPPING_SINKS
,
101 SESSION_STATE_STOPPING_SOURCES
,
102 SESSION_STATE_FINALIZING_SINKS
,
103 SESSION_STATE_CLOSED
,
104 SESSION_STATE_SHUT_DOWN
,
109 OBJ_STATE_STOPPED
= 0,
116 enum media_source_flags
118 SOURCE_FLAG_END_OF_PRESENTATION
= 0x1,
126 IMFMediaSource
*source
;
129 IMFPresentationDescriptor
*pd
;
130 enum object_state state
;
142 IMFMediaSinkPreroll
*preroll
;
143 IMFMediaEventGenerator
*event_generator
;
153 struct transform_stream
156 unsigned int requests
;
157 unsigned int min_buffer_size
;
162 TOPO_NODE_END_OF_STREAM
= 0x1,
163 TOPO_NODE_SCRUB_SAMPLE_COMPLETE
= 0x2,
169 struct media_session
*session
;
170 MF_TOPOLOGY_TYPE type
;
172 IMFTopologyNode
*node
;
173 enum object_state state
;
177 IMFMediaStream
*source_stream
;
178 IMFStreamSink
*sink_stream
;
179 IMFTransform
*transform
;
187 IMFMediaSource
*source
;
192 unsigned int requests
;
193 IMFVideoSampleAllocatorNotify notify_cb
;
194 IMFVideoSampleAllocator
*allocator
;
195 IMFVideoSampleAllocatorCallback
*allocator_cb
;
199 struct transform_stream
*inputs
;
201 unsigned int input_count
;
203 struct transform_stream
*outputs
;
205 unsigned int output_count
;
210 enum presentation_flags
212 SESSION_FLAG_SOURCES_SUBSCRIBED
= 0x1,
213 SESSION_FLAG_PRESENTATION_CLOCK_SET
= 0x2,
214 SESSION_FLAG_FINALIZE_SINKS
= 0x4,
215 SESSION_FLAG_NEEDS_PREROLL
= 0x8,
216 SESSION_FLAG_END_OF_PRESENTATION
= 0x10,
217 SESSION_FLAG_PENDING_RATE_CHANGE
= 0x20,
218 SESSION_FLAG_PENDING_COMMAND
= 0x40,
223 IMFMediaSession IMFMediaSession_iface
;
224 IMFGetService IMFGetService_iface
;
225 IMFRateSupport IMFRateSupport_iface
;
226 IMFRateControl IMFRateControl_iface
;
227 IMFTopologyNodeAttributeEditor IMFTopologyNodeAttributeEditor_iface
;
228 IMFAsyncCallback commands_callback
;
229 IMFAsyncCallback sa_ready_callback
;
230 IMFAsyncCallback events_callback
;
231 IMFAsyncCallback sink_finalizer_callback
;
233 IMFMediaEventQueue
*event_queue
;
234 IMFPresentationClock
*clock
;
235 IMFPresentationTimeSource
*system_time_source
;
236 IMFRateControl
*clock_rate_control
;
237 IMFTopoLoader
*topo_loader
;
238 IMFQualityManager
*quality_manager
;
241 IMFTopology
*current_topology
;
242 MF_TOPOSTATUS topo_status
;
243 MFTIME clock_stop_time
;
249 /* Latest Start() arguments. */
251 PROPVARIANT start_position
;
252 /* Latest SetRate() arguments. */
256 struct list topologies
;
257 struct list commands
;
258 enum session_state state
;
263 static inline struct media_session
*impl_from_IMFMediaSession(IMFMediaSession
*iface
)
265 return CONTAINING_RECORD(iface
, struct media_session
, IMFMediaSession_iface
);
268 static struct media_session
*impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
270 return CONTAINING_RECORD(iface
, struct media_session
, commands_callback
);
273 static struct media_session
*impl_from_sa_ready_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
275 return CONTAINING_RECORD(iface
, struct media_session
, sa_ready_callback
);
278 static struct media_session
*impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
280 return CONTAINING_RECORD(iface
, struct media_session
, events_callback
);
283 static struct media_session
*impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
285 return CONTAINING_RECORD(iface
, struct media_session
, sink_finalizer_callback
);
288 static struct media_session
*impl_from_IMFGetService(IMFGetService
*iface
)
290 return CONTAINING_RECORD(iface
, struct media_session
, IMFGetService_iface
);
293 static struct media_session
*impl_session_from_IMFRateSupport(IMFRateSupport
*iface
)
295 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateSupport_iface
);
298 static struct media_session
*impl_session_from_IMFRateControl(IMFRateControl
*iface
)
300 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateControl_iface
);
303 static struct media_session
*impl_session_from_IMFTopologyNodeAttributeEditor(IMFTopologyNodeAttributeEditor
*iface
)
305 return CONTAINING_RECORD(iface
, struct media_session
, IMFTopologyNodeAttributeEditor_iface
);
308 static struct session_op
*impl_op_from_IUnknown(IUnknown
*iface
)
310 return CONTAINING_RECORD(iface
, struct session_op
, IUnknown_iface
);
313 static struct topo_node
*impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify
*iface
)
315 return CONTAINING_RECORD(iface
, struct topo_node
, u
.sink
.notify_cb
);
318 /* IMFLocalMFTRegistration */
319 static HRESULT WINAPI
local_mft_registration_QueryInterface(IMFLocalMFTRegistration
*iface
, REFIID riid
, void **obj
)
321 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
323 if (IsEqualIID(riid
, &IID_IMFLocalMFTRegistration
) ||
324 IsEqualIID(riid
, &IID_IUnknown
))
327 IMFLocalMFTRegistration_AddRef(iface
);
331 WARN("Unexpected %s.\n", debugstr_guid(riid
));
333 return E_NOINTERFACE
;
336 static ULONG WINAPI
local_mft_registration_AddRef(IMFLocalMFTRegistration
*iface
)
341 static ULONG WINAPI
local_mft_registration_Release(IMFLocalMFTRegistration
*iface
)
346 static HRESULT WINAPI
local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration
*iface
, MFT_REGISTRATION_INFO
*info
,
352 TRACE("%p, %p, %lu.\n", iface
, info
, count
);
354 for (i
= 0; i
< count
; ++i
)
356 if (FAILED(hr
= MFTRegisterLocalByCLSID(&info
[i
].clsid
, &info
[i
].guidCategory
, info
[i
].pszName
,
357 info
[i
].uiFlags
, info
[i
].cInTypes
, info
[i
].pInTypes
, info
[i
].cOutTypes
, info
[i
].pOutTypes
)))
366 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl
=
368 local_mft_registration_QueryInterface
,
369 local_mft_registration_AddRef
,
370 local_mft_registration_Release
,
371 local_mft_registration_RegisterMFTs
,
374 static IMFLocalMFTRegistration local_mft_registration
= { &local_mft_registration_vtbl
};
376 static HRESULT WINAPI
session_op_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
378 if (IsEqualIID(riid
, &IID_IUnknown
))
381 IUnknown_AddRef(iface
);
386 return E_NOINTERFACE
;
389 static ULONG WINAPI
session_op_AddRef(IUnknown
*iface
)
391 struct session_op
*op
= impl_op_from_IUnknown(iface
);
392 ULONG refcount
= InterlockedIncrement(&op
->refcount
);
394 TRACE("%p, refcount %lu.\n", iface
, refcount
);
399 static ULONG WINAPI
session_op_Release(IUnknown
*iface
)
401 struct session_op
*op
= impl_op_from_IUnknown(iface
);
402 ULONG refcount
= InterlockedDecrement(&op
->refcount
);
404 TRACE("%p, refcount %lu.\n", iface
, refcount
);
410 case SESSION_CMD_SET_TOPOLOGY
:
411 if (op
->set_topology
.topology
)
412 IMFTopology_Release(op
->set_topology
.topology
);
414 case SESSION_CMD_START
:
415 PropVariantClear(&op
->start
.start_position
);
426 static const IUnknownVtbl session_op_vtbl
=
428 session_op_QueryInterface
,
433 static HRESULT
create_session_op(enum session_command command
, struct session_op
**ret
)
435 struct session_op
*op
;
437 if (!(op
= calloc(1, sizeof(*op
))))
438 return E_OUTOFMEMORY
;
440 op
->IUnknown_iface
.lpVtbl
= &session_op_vtbl
;
442 op
->command
= command
;
449 static HRESULT
session_is_shut_down(struct media_session
*session
)
451 return session
->state
== SESSION_STATE_SHUT_DOWN
? MF_E_SHUTDOWN
: S_OK
;
454 static HRESULT
session_submit_command(struct media_session
*session
, struct session_op
*op
)
458 TRACE("session %p, op %p, command %u.\n", session
, op
, op
->command
);
460 EnterCriticalSection(&session
->cs
);
461 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
463 if (list_empty(&session
->commands
) && !(session
->presentation
.flags
& SESSION_FLAG_PENDING_COMMAND
))
464 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
465 if (op
->command
== SESSION_CMD_SHUTDOWN
)
466 list_add_head(&session
->commands
, &op
->entry
);
468 list_add_tail(&session
->commands
, &op
->entry
);
469 IUnknown_AddRef(&op
->IUnknown_iface
);
471 LeaveCriticalSection(&session
->cs
);
476 static HRESULT
session_submit_simple_command(struct media_session
*session
, enum session_command command
)
478 struct session_op
*op
;
481 if (FAILED(hr
= create_session_op(command
, &op
)))
484 hr
= session_submit_command(session
, op
);
485 IUnknown_Release(&op
->IUnknown_iface
);
489 static void session_clear_queued_topologies(struct media_session
*session
)
491 struct queued_topology
*ptr
, *next
;
493 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &session
->topologies
, struct queued_topology
, entry
)
495 list_remove(&ptr
->entry
);
496 IMFTopology_Release(ptr
->topology
);
501 static void session_set_topo_status(struct media_session
*session
, HRESULT status
,
502 MF_TOPOSTATUS topo_status
)
504 IMFMediaEvent
*event
;
507 if (topo_status
== MF_TOPOSTATUS_INVALID
)
510 if (list_empty(&session
->topologies
))
512 FIXME("Unexpectedly empty topology queue.\n");
516 if (topo_status
> session
->presentation
.topo_status
)
518 struct queued_topology
*topology
= LIST_ENTRY(list_head(&session
->topologies
), struct queued_topology
, entry
);
520 param
.vt
= VT_UNKNOWN
;
521 param
.punkVal
= (IUnknown
*)topology
->topology
;
523 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus
, &GUID_NULL
, status
, ¶m
, &event
)))
526 session
->presentation
.topo_status
= topo_status
;
528 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_TOPOLOGY_STATUS
, topo_status
);
529 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
530 IMFMediaEvent_Release(event
);
534 static HRESULT
session_bind_output_nodes(IMFTopology
*topology
)
536 MF_TOPOLOGY_TYPE node_type
;
537 IMFStreamSink
*stream_sink
;
538 IMFMediaSink
*media_sink
;
539 WORD node_count
= 0, i
;
540 IMFTopologyNode
*node
;
541 IMFActivate
*activate
;
546 hr
= IMFTopology_GetNodeCount(topology
, &node_count
);
548 for (i
= 0; i
< node_count
; ++i
)
550 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
553 if (FAILED(hr
= IMFTopologyNode_GetNodeType(node
, &node_type
)) || node_type
!= MF_TOPOLOGY_OUTPUT_NODE
)
555 IMFTopologyNode_Release(node
);
559 if (SUCCEEDED(hr
= IMFTopologyNode_GetObject(node
, &object
)))
562 if (FAILED(IUnknown_QueryInterface(object
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
564 if (SUCCEEDED(hr
= IUnknown_QueryInterface(object
, &IID_IMFActivate
, (void **)&activate
)))
566 if (SUCCEEDED(hr
= IMFActivate_ActivateObject(activate
, &IID_IMFMediaSink
, (void **)&media_sink
)))
568 if (FAILED(IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_STREAMID
, &stream_id
)))
572 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink
, stream_id
, &stream_sink
)))
573 hr
= IMFMediaSink_AddStreamSink(media_sink
, stream_id
, NULL
, &stream_sink
);
576 hr
= IMFTopologyNode_SetObject(node
, (IUnknown
*)stream_sink
);
578 IMFMediaSink_Release(media_sink
);
582 IMFTopologyNode_SetUnknown(node
, &_MF_TOPONODE_IMFActivate
, (IUnknown
*)activate
);
584 IMFActivate_Release(activate
);
589 IMFStreamSink_Release(stream_sink
);
590 IUnknown_Release(object
);
593 IMFTopologyNode_Release(node
);
599 static HRESULT
session_init_media_types(IMFTopology
*topology
)
601 MF_TOPOLOGY_TYPE node_type
;
602 WORD node_count
, i
, j
;
603 IMFTopologyNode
*node
;
608 if (FAILED(hr
= IMFTopology_GetNodeCount(topology
, &node_count
)))
611 for (i
= 0; i
< node_count
; ++i
)
613 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
616 if (FAILED(hr
= IMFTopologyNode_GetInputCount(node
, &input_count
))
617 || FAILED(hr
= IMFTopologyNode_GetNodeType(node
, &node_type
))
618 || node_type
!= MF_TOPOLOGY_OUTPUT_NODE
)
620 IMFTopologyNode_Release(node
);
624 for (j
= 0; j
< input_count
; ++j
)
626 IMFMediaTypeHandler
*handler
;
627 IMFTopologyNode
*up_node
;
630 if (SUCCEEDED(hr
= IMFTopologyNode_GetInput(node
, j
, &up_node
, &up_output
)))
632 hr
= topology_node_init_media_type(up_node
, up_output
, TRUE
, &type
);
633 IMFTopologyNode_Release(up_node
);
638 if (SUCCEEDED(hr
= topology_node_get_type_handler(node
, j
, FALSE
, &handler
)))
640 hr
= IMFMediaTypeHandler_SetCurrentMediaType(handler
, type
);
641 IMFMediaTypeHandler_Release(handler
);
644 IMFMediaType_Release(type
);
647 IMFTopologyNode_Release(node
);
653 static void session_set_caps(struct media_session
*session
, DWORD caps
)
655 DWORD delta
= session
->caps
^ caps
;
656 IMFMediaEvent
*event
;
658 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
659 them to, since session always queries for current object rates. */
663 session
->caps
= caps
;
665 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged
, &GUID_NULL
, S_OK
, NULL
, &event
)))
668 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS
, caps
);
669 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS_DELTA
, delta
);
671 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
672 IMFMediaEvent_Release(event
);
675 static void transform_release_sample(struct sample
*sample
)
677 list_remove(&sample
->entry
);
679 IMFSample_Release(sample
->sample
);
683 static void transform_stream_drop_samples(struct transform_stream
*stream
)
685 struct sample
*sample
, *sample2
;
687 LIST_FOR_EACH_ENTRY_SAFE(sample
, sample2
, &stream
->samples
, struct sample
, entry
)
688 transform_release_sample(sample
);
691 static void release_topo_node(struct topo_node
*node
)
697 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
698 if (node
->u
.source
.source
)
699 IMFMediaSource_Release(node
->u
.source
.source
);
701 case MF_TOPOLOGY_TRANSFORM_NODE
:
702 for (i
= 0; i
< node
->u
.transform
.input_count
; ++i
)
703 transform_stream_drop_samples(&node
->u
.transform
.inputs
[i
]);
704 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
705 transform_stream_drop_samples(&node
->u
.transform
.outputs
[i
]);
706 free(node
->u
.transform
.inputs
);
707 free(node
->u
.transform
.outputs
);
708 free(node
->u
.transform
.input_map
);
709 free(node
->u
.transform
.output_map
);
711 case MF_TOPOLOGY_OUTPUT_NODE
:
712 if (node
->u
.sink
.allocator
)
713 IMFVideoSampleAllocator_Release(node
->u
.sink
.allocator
);
714 if (node
->u
.sink
.allocator_cb
)
716 IMFVideoSampleAllocatorCallback_SetCallback(node
->u
.sink
.allocator_cb
, NULL
);
717 IMFVideoSampleAllocatorCallback_Release(node
->u
.sink
.allocator_cb
);
724 if (node
->object
.object
)
725 IUnknown_Release(node
->object
.object
);
727 IMFTopologyNode_Release(node
->node
);
731 static void session_shutdown_current_topology(struct media_session
*session
)
733 unsigned int shutdown
, force_shutdown
;
734 MF_TOPOLOGY_TYPE node_type
;
735 IMFStreamSink
*stream_sink
;
736 IMFTopology
*topology
;
737 IMFTopologyNode
*node
;
738 IMFActivate
*activate
;
743 topology
= session
->presentation
.current_topology
;
744 force_shutdown
= session
->state
== SESSION_STATE_SHUT_DOWN
;
746 /* FIXME: should handle async MFTs, but these are not supported by the rest of the pipeline currently. */
748 while (SUCCEEDED(IMFTopology_GetNode(topology
, idx
++, &node
)))
750 if (SUCCEEDED(IMFTopologyNode_GetNodeType(node
, &node_type
)) &&
751 node_type
== MF_TOPOLOGY_OUTPUT_NODE
)
754 IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, &shutdown
);
756 if (force_shutdown
|| shutdown
)
758 if (SUCCEEDED(IMFTopologyNode_GetUnknown(node
, &_MF_TOPONODE_IMFActivate
, &IID_IMFActivate
,
759 (void **)&activate
)))
761 if (FAILED(hr
= IMFActivate_ShutdownObject(activate
)))
762 WARN("Failed to shut down activation object for the sink, hr %#lx.\n", hr
);
763 IMFActivate_Release(activate
);
765 else if (SUCCEEDED(topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
767 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink
, &sink
)))
769 IMFMediaSink_Shutdown(sink
);
770 IMFMediaSink_Release(sink
);
773 IMFStreamSink_Release(stream_sink
);
778 IMFTopologyNode_Release(node
);
782 static void session_clear_command_list(struct media_session
*session
)
784 struct session_op
*op
, *op2
;
786 LIST_FOR_EACH_ENTRY_SAFE(op
, op2
, &session
->commands
, struct session_op
, entry
)
788 list_remove(&op
->entry
);
789 IUnknown_Release(&op
->IUnknown_iface
);
793 static void session_clear_presentation(struct media_session
*session
)
795 struct media_source
*source
, *source2
;
796 struct media_sink
*sink
, *sink2
;
797 struct topo_node
*node
, *node2
;
799 session_shutdown_current_topology(session
);
801 IMFTopology_Clear(session
->presentation
.current_topology
);
802 session
->presentation
.topo_status
= MF_TOPOSTATUS_INVALID
;
803 session
->presentation
.flags
= 0;
805 LIST_FOR_EACH_ENTRY_SAFE(source
, source2
, &session
->presentation
.sources
, struct media_source
, entry
)
807 list_remove(&source
->entry
);
809 IMFMediaSource_Release(source
->source
);
811 IMFPresentationDescriptor_Release(source
->pd
);
815 LIST_FOR_EACH_ENTRY_SAFE(node
, node2
, &session
->presentation
.nodes
, struct topo_node
, entry
)
817 list_remove(&node
->entry
);
818 release_topo_node(node
);
821 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &session
->presentation
.sinks
, struct media_sink
, entry
)
823 list_remove(&sink
->entry
);
826 IMFMediaSink_Release(sink
->sink
);
828 IMFMediaSinkPreroll_Release(sink
->preroll
);
829 if (sink
->event_generator
)
830 IMFMediaEventGenerator_Release(sink
->event_generator
);
835 static struct topo_node
*session_get_node_by_id(const struct media_session
*session
, TOPOID id
)
837 struct topo_node
*node
;
839 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
841 if (node
->node_id
== id
)
848 static void session_command_complete(struct media_session
*session
)
850 struct session_op
*op
;
853 session
->presentation
.flags
&= ~SESSION_FLAG_PENDING_COMMAND
;
855 /* Submit next command. */
856 if ((e
= list_head(&session
->commands
)))
858 op
= LIST_ENTRY(e
, struct session_op
, entry
);
859 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
863 static void session_command_complete_with_event(struct media_session
*session
, MediaEventType event
,
864 HRESULT status
, const PROPVARIANT
*param
)
866 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, event
, &GUID_NULL
, status
, param
);
867 session_command_complete(session
);
870 static HRESULT
session_subscribe_sources(struct media_session
*session
)
872 struct media_source
*source
;
875 if (session
->presentation
.flags
& SESSION_FLAG_SOURCES_SUBSCRIBED
)
878 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
880 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(source
->source
, &session
->events_callback
,
883 WARN("Failed to subscribe to source events, hr %#lx.\n", hr
);
888 session
->presentation
.flags
|= SESSION_FLAG_SOURCES_SUBSCRIBED
;
892 static void session_start(struct media_session
*session
, const GUID
*time_format
, const PROPVARIANT
*start_position
)
894 struct media_source
*source
;
897 switch (session
->state
)
899 case SESSION_STATE_STOPPED
:
901 /* Start request with no current topology. */
902 if (session
->presentation
.topo_status
== MF_TOPOSTATUS_INVALID
)
904 session_command_complete_with_event(session
, MESessionStarted
, MF_E_INVALIDREQUEST
, NULL
);
909 case SESSION_STATE_PAUSED
:
911 session
->presentation
.time_format
= *time_format
;
912 session
->presentation
.start_position
.vt
= VT_EMPTY
;
913 PropVariantCopy(&session
->presentation
.start_position
, start_position
);
915 if (FAILED(hr
= session_subscribe_sources(session
)))
917 session_command_complete_with_event(session
, MESessionStarted
, hr
, NULL
);
921 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
923 if (FAILED(hr
= IMFMediaSource_Start(source
->source
, source
->pd
, &GUID_NULL
, start_position
)))
925 WARN("Failed to start media source %p, hr %#lx.\n", source
->source
, hr
);
926 session_command_complete_with_event(session
, MESessionStarted
, hr
, NULL
);
931 session
->state
= SESSION_STATE_STARTING_SOURCES
;
933 case SESSION_STATE_STARTED
:
934 FIXME("Seeking is not implemented.\n");
935 session_command_complete(session
);
938 session_command_complete_with_event(session
, MESessionStarted
, MF_E_INVALIDREQUEST
, NULL
);
943 static void session_set_started(struct media_session
*session
)
945 struct media_source
*source
;
946 IMFMediaEvent
*event
;
950 session
->state
= SESSION_STATE_STARTED
;
952 caps
= session
->caps
| MFSESSIONCAP_PAUSE
;
954 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
956 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &flags
)))
958 if (!(flags
& MFMEDIASOURCE_CAN_PAUSE
))
960 caps
&= ~MFSESSIONCAP_PAUSE
;
966 session_set_caps(session
, caps
);
968 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted
, &GUID_NULL
, S_OK
, NULL
, &event
)))
970 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
971 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
972 IMFMediaEvent_Release(event
);
974 session_command_complete(session
);
977 static void session_set_paused(struct media_session
*session
, unsigned int state
, HRESULT status
)
979 /* Failed event status could indicate a failure during normal transition to paused state,
980 or an attempt to pause from invalid initial state. To finalize failed transition in the former case,
981 state is still forced to PAUSED, otherwise previous state is retained. */
982 if (state
!= ~0u) session
->state
= state
;
983 if (SUCCEEDED(status
))
984 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
985 session_command_complete_with_event(session
, MESessionPaused
, status
, NULL
);
988 static void session_set_closed(struct media_session
*session
, HRESULT status
)
990 session
->state
= SESSION_STATE_CLOSED
;
991 if (SUCCEEDED(status
))
992 session_set_caps(session
, session
->caps
& ~(MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
));
993 session_command_complete_with_event(session
, MESessionClosed
, status
, NULL
);
996 static void session_pause(struct media_session
*session
)
998 unsigned int state
= ~0u;
1001 switch (session
->state
)
1003 case SESSION_STATE_STARTED
:
1005 /* Transition in two steps - pause the clock, wait for sinks, then pause sources. */
1006 if (SUCCEEDED(hr
= IMFPresentationClock_Pause(session
->clock
)))
1007 session
->state
= SESSION_STATE_PAUSING_SINKS
;
1008 state
= SESSION_STATE_PAUSED
;
1012 case SESSION_STATE_STOPPED
:
1013 hr
= MF_E_SESSION_PAUSEWHILESTOPPED
;
1016 hr
= MF_E_INVALIDREQUEST
;
1020 session_set_paused(session
, state
, hr
);
1023 static void session_clear_end_of_presentation(struct media_session
*session
)
1025 struct media_source
*source
;
1026 struct topo_node
*node
;
1028 session
->presentation
.flags
&= ~SESSION_FLAG_END_OF_PRESENTATION
;
1029 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1031 source
->flags
&= ~SOURCE_FLAG_END_OF_PRESENTATION
;
1033 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1035 node
->flags
&= ~TOPO_NODE_END_OF_STREAM
;
1037 session
->presentation
.topo_status
= MF_TOPOSTATUS_READY
;
1040 static void session_set_stopped(struct media_session
*session
, HRESULT status
)
1042 MediaEventType event_type
;
1043 IMFMediaEvent
*event
;
1045 session
->state
= SESSION_STATE_STOPPED
;
1046 event_type
= session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
? MESessionEnded
: MESessionStopped
;
1048 if (SUCCEEDED(MFCreateMediaEvent(event_type
, &GUID_NULL
, status
, NULL
, &event
)))
1050 IMFMediaEvent_SetUINT64(event
, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME
, session
->presentation
.clock_stop_time
);
1051 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
1052 IMFMediaEvent_Release(event
);
1054 session_clear_end_of_presentation(session
);
1055 session_command_complete(session
);
1058 static void session_stop(struct media_session
*session
)
1060 HRESULT hr
= MF_E_INVALIDREQUEST
;
1062 switch (session
->state
)
1064 case SESSION_STATE_STARTED
:
1065 case SESSION_STATE_PAUSED
:
1067 /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */
1068 IMFPresentationClock_GetTime(session
->clock
, &session
->presentation
.clock_stop_time
);
1069 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1070 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1072 session_set_stopped(session
, hr
);
1075 case SESSION_STATE_STOPPED
:
1079 session_command_complete_with_event(session
, MESessionStopped
, hr
, NULL
);
1084 static HRESULT
session_finalize_sinks(struct media_session
*session
)
1086 IMFFinalizableMediaSink
*fin_sink
;
1087 BOOL sinks_finalized
= TRUE
;
1088 struct media_sink
*sink
;
1091 session
->presentation
.flags
&= ~SESSION_FLAG_FINALIZE_SINKS
;
1092 session
->state
= SESSION_STATE_FINALIZING_SINKS
;
1094 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1096 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
1098 hr
= IMFFinalizableMediaSink_BeginFinalize(fin_sink
, &session
->sink_finalizer_callback
,
1099 (IUnknown
*)fin_sink
);
1100 IMFFinalizableMediaSink_Release(fin_sink
);
1103 sinks_finalized
= FALSE
;
1106 sink
->finalized
= TRUE
;
1109 if (sinks_finalized
)
1110 session_set_closed(session
, hr
);
1115 static void session_close(struct media_session
*session
)
1119 switch (session
->state
)
1121 case SESSION_STATE_STOPPED
:
1122 hr
= session_finalize_sinks(session
);
1124 case SESSION_STATE_STARTED
:
1125 case SESSION_STATE_PAUSED
:
1126 session
->presentation
.flags
|= SESSION_FLAG_FINALIZE_SINKS
;
1127 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1128 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1131 hr
= MF_E_INVALIDREQUEST
;
1135 session_clear_queued_topologies(session
);
1137 session_set_closed(session
, hr
);
1140 static void session_clear_topologies(struct media_session
*session
)
1144 if (session
->state
== SESSION_STATE_CLOSED
)
1145 hr
= MF_E_INVALIDREQUEST
;
1147 session_clear_queued_topologies(session
);
1148 session_command_complete_with_event(session
, MESessionTopologiesCleared
, hr
, NULL
);
1151 static HRESULT
session_is_presentation_rate_supported(struct media_session
*session
, BOOL thin
, float rate
,
1152 float *nearest_rate
)
1154 IMFRateSupport
*rate_support
;
1155 struct media_source
*source
;
1156 struct media_sink
*sink
;
1157 float value
= 0.0f
, tmp
;
1161 if (!nearest_rate
) nearest_rate
= &tmp
;
1165 *nearest_rate
= 1.0f
;
1169 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
1171 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1173 if (FAILED(hr
= MFGetService(source
->object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
,
1174 (void **)&rate_support
)))
1181 if (FAILED(hr
= IMFRateSupport_IsRateSupported(rate_support
, thin
, rate
, &value
)))
1182 WARN("Source does not support rate %f, hr %#lx.\n", rate
, hr
);
1183 IMFRateSupport_Release(rate_support
);
1185 /* Only "first" source is considered. */
1191 /* For sinks only check if rate is supported, ignoring nearest values. */
1192 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1195 if (FAILED(hr
= IMFMediaSink_GetCharacteristics(sink
->sink
, &flags
)))
1198 if (flags
& MEDIASINK_RATELESS
)
1201 if (FAILED(MFGetService(sink
->object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
,
1202 (void **)&rate_support
)))
1205 hr
= IMFRateSupport_IsRateSupported(rate_support
, thin
, rate
, NULL
);
1206 IMFRateSupport_Release(rate_support
);
1209 WARN("Sink %p does not support rate %f, hr %#lx.\n", sink
->sink
, rate
, hr
);
1216 *nearest_rate
= value
;
1221 static void session_set_consumed_clock(IUnknown
*object
, IMFPresentationClock
*clock
)
1223 IMFClockConsumer
*consumer
;
1225 if (SUCCEEDED(IUnknown_QueryInterface(object
, &IID_IMFClockConsumer
, (void **)&consumer
)))
1227 IMFClockConsumer_SetPresentationClock(consumer
, clock
);
1228 IMFClockConsumer_Release(consumer
);
1232 static void session_set_presentation_clock(struct media_session
*session
)
1234 IMFPresentationTimeSource
*time_source
= NULL
;
1235 struct media_source
*source
;
1236 struct media_sink
*sink
;
1237 struct topo_node
*node
;
1240 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1242 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
1243 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_NOTIFY_START_OF_STREAM
, 0);
1246 if (!(session
->presentation
.flags
& SESSION_FLAG_PRESENTATION_CLOCK_SET
))
1248 /* Attempt to get time source from the sinks. */
1249 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1251 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFPresentationTimeSource
,
1252 (void **)&time_source
)))
1258 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, time_source
);
1259 IMFPresentationTimeSource_Release(time_source
);
1262 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, session
->system_time_source
);
1265 WARN("Failed to set time source, hr %#lx.\n", hr
);
1267 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1269 if (node
->type
!= MF_TOPOLOGY_OUTPUT_NODE
)
1272 if (FAILED(hr
= IMFStreamSink_BeginGetEvent(node
->object
.sink_stream
, &session
->events_callback
,
1273 node
->object
.object
)))
1275 WARN("Failed to subscribe to stream sink events, hr %#lx.\n", hr
);
1279 /* Set clock for all topology nodes. */
1280 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1282 session_set_consumed_clock(source
->object
, session
->clock
);
1285 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1287 if (sink
->event_generator
&& FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(sink
->event_generator
,
1288 &session
->events_callback
, (IUnknown
*)sink
->event_generator
)))
1290 WARN("Failed to subscribe to sink events, hr %#lx.\n", hr
);
1293 if (FAILED(hr
= IMFMediaSink_SetPresentationClock(sink
->sink
, session
->clock
)))
1294 WARN("Failed to set presentation clock for the sink, hr %#lx.\n", hr
);
1297 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1299 if (node
->type
!= MF_TOPOLOGY_TRANSFORM_NODE
)
1302 session_set_consumed_clock(node
->object
.object
, session
->clock
);
1305 session
->presentation
.flags
|= SESSION_FLAG_PRESENTATION_CLOCK_SET
;
1309 static void session_set_rate(struct media_session
*session
, BOOL thin
, float rate
)
1311 IMFRateControl
*rate_control
;
1312 struct media_source
*source
;
1313 float clock_rate
= 0.0f
;
1317 hr
= session_is_presentation_rate_supported(session
, thin
, rate
, NULL
);
1320 hr
= IMFRateControl_GetRate(session
->clock_rate_control
, NULL
, &clock_rate
);
1322 if (SUCCEEDED(hr
) && (rate
!= clock_rate
) && SUCCEEDED(hr
= session_subscribe_sources(session
)))
1324 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1326 if (SUCCEEDED(hr
= MFGetService(source
->object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateControl
,
1327 (void **)&rate_control
)))
1329 hr
= IMFRateControl_SetRate(rate_control
, thin
, rate
);
1330 IMFRateControl_Release(rate_control
);
1333 session
->presentation
.flags
|= SESSION_FLAG_PENDING_RATE_CHANGE
;
1334 session
->presentation
.rate
= rate
;
1344 param
.fltVal
= rate
;
1345 session_command_complete_with_event(session
, MESessionRateChanged
, hr
, SUCCEEDED(hr
) ? ¶m
: NULL
);
1348 static void session_complete_rate_change(struct media_session
*session
)
1353 if (!(session
->presentation
.flags
& SESSION_FLAG_PENDING_RATE_CHANGE
))
1356 session
->presentation
.flags
&= ~SESSION_FLAG_PENDING_RATE_CHANGE
;
1357 session_set_presentation_clock(session
);
1359 hr
= IMFRateControl_SetRate(session
->clock_rate_control
, session
->presentation
.thin
,
1360 session
->presentation
.rate
);
1363 param
.fltVal
= session
->presentation
.rate
;
1365 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionRateChanged
, &GUID_NULL
, hr
,
1366 SUCCEEDED(hr
) ? ¶m
: NULL
);
1367 session_command_complete(session
);
1370 static struct media_source
*session_get_media_source(struct media_session
*session
, IMFMediaSource
*source
)
1372 struct media_source
*cur
;
1374 LIST_FOR_EACH_ENTRY(cur
, &session
->presentation
.sources
, struct media_source
, entry
)
1376 if (source
== cur
->source
)
1383 static void session_release_media_source(struct media_source
*source
)
1385 IMFMediaSource_Release(source
->source
);
1387 IMFPresentationDescriptor_Release(source
->pd
);
1391 static HRESULT
session_add_media_source(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSource
*source
)
1393 struct media_source
*media_source
;
1396 if (session_get_media_source(session
, source
))
1399 if (!(media_source
= calloc(1, sizeof(*media_source
))))
1400 return E_OUTOFMEMORY
;
1402 media_source
->source
= source
;
1403 IMFMediaSource_AddRef(media_source
->source
);
1405 hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
, &IID_IMFPresentationDescriptor
,
1406 (void **)&media_source
->pd
);
1409 list_add_tail(&session
->presentation
.sources
, &media_source
->entry
);
1411 session_release_media_source(media_source
);
1416 static void session_raise_topology_set(struct media_session
*session
, IMFTopology
*topology
, HRESULT status
)
1420 param
.vt
= topology
? VT_UNKNOWN
: VT_EMPTY
;
1421 param
.punkVal
= (IUnknown
*)topology
;
1423 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologySet
, &GUID_NULL
, status
, ¶m
);
1426 static DWORD
session_get_object_rate_caps(IUnknown
*object
)
1428 IMFRateSupport
*rate_support
;
1432 if (SUCCEEDED(MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
1435 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_FORWARD
, TRUE
, &rate
)) && rate
!= 0.0f
)
1436 caps
|= MFSESSIONCAP_RATE_FORWARD
;
1439 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_REVERSE
, TRUE
, &rate
)) && rate
!= 0.0f
)
1440 caps
|= MFSESSIONCAP_RATE_REVERSE
;
1442 IMFRateSupport_Release(rate_support
);
1448 static HRESULT
session_add_media_sink(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSink
*sink
)
1450 struct media_sink
*media_sink
;
1451 unsigned int disable_preroll
= 0;
1454 LIST_FOR_EACH_ENTRY(media_sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1456 if (sink
== media_sink
->sink
)
1460 if (!(media_sink
= calloc(1, sizeof(*media_sink
))))
1461 return E_OUTOFMEMORY
;
1463 media_sink
->sink
= sink
;
1464 IMFMediaSink_AddRef(media_sink
->sink
);
1466 IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaEventGenerator
, (void **)&media_sink
->event_generator
);
1468 IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_DISABLE_PREROLL
, &disable_preroll
);
1469 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
, &flags
)) && flags
& MEDIASINK_CAN_PREROLL
&& !disable_preroll
)
1471 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaSinkPreroll
, (void **)&media_sink
->preroll
)))
1472 session
->presentation
.flags
|= SESSION_FLAG_NEEDS_PREROLL
;
1475 list_add_tail(&session
->presentation
.sinks
, &media_sink
->entry
);
1480 static DWORD
transform_node_get_stream_id(struct topo_node
*node
, BOOL output
, unsigned int index
)
1482 DWORD
*map
= output
? node
->u
.transform
.output_map
: node
->u
.transform
.input_map
;
1483 return map
? map
[index
] : index
;
1486 static HRESULT
session_set_transform_stream_info(struct topo_node
*node
)
1488 DWORD
*input_map
= NULL
, *output_map
= NULL
;
1489 DWORD i
, input_count
, output_count
;
1490 struct transform_stream
*streams
;
1491 unsigned int block_alignment
;
1492 IMFMediaType
*media_type
;
1493 UINT32 bytes_per_second
;
1497 hr
= IMFTransform_GetStreamCount(node
->object
.transform
, &input_count
, &output_count
);
1498 if (SUCCEEDED(hr
) && (input_count
> 1 || output_count
> 1))
1500 input_map
= calloc(input_count
, sizeof(*input_map
));
1501 output_map
= calloc(output_count
, sizeof(*output_map
));
1502 if (FAILED(IMFTransform_GetStreamIDs(node
->object
.transform
, input_count
, input_map
,
1503 output_count
, output_map
)))
1505 /* Assume sequential identifiers. */
1508 input_map
= output_map
= NULL
;
1514 node
->u
.transform
.input_map
= input_map
;
1515 node
->u
.transform
.output_map
= output_map
;
1517 streams
= calloc(input_count
, sizeof(*streams
));
1518 for (i
= 0; i
< input_count
; ++i
)
1519 list_init(&streams
[i
].samples
);
1520 node
->u
.transform
.inputs
= streams
;
1521 node
->u
.transform
.input_count
= input_count
;
1523 streams
= calloc(output_count
, sizeof(*streams
));
1524 for (i
= 0; i
< output_count
; ++i
)
1526 list_init(&streams
[i
].samples
);
1528 if (SUCCEEDED(IMFTransform_GetOutputCurrentType(node
->object
.transform
,
1529 transform_node_get_stream_id(node
, TRUE
, i
), &media_type
)))
1531 if (SUCCEEDED(IMFMediaType_GetMajorType(media_type
, &major
)) && IsEqualGUID(&major
, &MFMediaType_Audio
)
1532 && SUCCEEDED(IMFMediaType_GetUINT32(media_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &block_alignment
)))
1534 streams
[i
].min_buffer_size
= block_alignment
;
1535 if (SUCCEEDED(IMFMediaType_GetUINT32(media_type
, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND
, &bytes_per_second
)))
1536 streams
[i
].min_buffer_size
= max(streams
[i
].min_buffer_size
, bytes_per_second
);
1538 IMFMediaType_Release(media_type
);
1541 node
->u
.transform
.outputs
= streams
;
1542 node
->u
.transform
.output_count
= output_count
;
1548 static HRESULT
session_get_stream_sink_type(IMFStreamSink
*sink
, IMFMediaType
**media_type
)
1550 IMFMediaTypeHandler
*handler
;
1553 if (SUCCEEDED(hr
= IMFStreamSink_GetMediaTypeHandler(sink
, &handler
)))
1555 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, media_type
);
1556 IMFMediaTypeHandler_Release(handler
);
1562 static HRESULT WINAPI
node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify
*iface
,
1563 REFIID riid
, void **obj
)
1565 if (IsEqualIID(riid
, &IID_IMFVideoSampleAllocatorNotify
) ||
1566 IsEqualIID(riid
, &IID_IUnknown
))
1569 IMFVideoSampleAllocatorNotify_AddRef(iface
);
1574 return E_NOINTERFACE
;
1577 static ULONG WINAPI
node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify
*iface
)
1582 static ULONG WINAPI
node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify
*iface
)
1587 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
);
1589 static HRESULT WINAPI
node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify
*iface
)
1591 struct topo_node
*topo_node
= impl_node_from_IMFVideoSampleAllocatorNotify(iface
);
1592 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &topo_node
->session
->sa_ready_callback
, (IUnknown
*)iface
);
1596 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl
=
1598 node_sample_allocator_cb_QueryInterface
,
1599 node_sample_allocator_cb_AddRef
,
1600 node_sample_allocator_cb_Release
,
1601 node_sample_allocator_cb_NotifyRelease
,
1604 static HRESULT
session_append_node(struct media_session
*session
, IMFTopologyNode
*node
)
1606 struct topo_node
*topo_node
;
1607 IMFMediaSink
*media_sink
;
1608 IMFMediaType
*media_type
;
1609 IMFStreamDescriptor
*sd
;
1612 if (!(topo_node
= calloc(1, sizeof(*topo_node
))))
1613 return E_OUTOFMEMORY
;
1615 IMFTopologyNode_GetNodeType(node
, &topo_node
->type
);
1616 IMFTopologyNode_GetTopoNodeID(node
, &topo_node
->node_id
);
1617 topo_node
->node
= node
;
1618 IMFTopologyNode_AddRef(topo_node
->node
);
1619 topo_node
->session
= session
;
1621 switch (topo_node
->type
)
1623 case MF_TOPOLOGY_OUTPUT_NODE
:
1624 topo_node
->u
.sink
.notify_cb
.lpVtbl
= &node_sample_allocator_cb_vtbl
;
1626 if (FAILED(hr
= topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&topo_node
->object
.object
)))
1628 WARN("Failed to get stream sink interface, hr %#lx.\n", hr
);
1632 if (FAILED(hr
= IMFStreamSink_GetMediaSink(topo_node
->object
.sink_stream
, &media_sink
)))
1635 if (SUCCEEDED(hr
= session_add_media_sink(session
, node
, media_sink
)))
1637 if (SUCCEEDED(session_get_stream_sink_type(topo_node
->object
.sink_stream
, &media_type
)))
1639 if (SUCCEEDED(MFGetService(topo_node
->object
.object
, &MR_VIDEO_ACCELERATION_SERVICE
,
1640 &IID_IMFVideoSampleAllocator
, (void **)&topo_node
->u
.sink
.allocator
)))
1642 if (FAILED(hr
= IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node
->u
.sink
.allocator
,
1645 WARN("Failed to initialize sample allocator for the stream, hr %#lx.\n", hr
);
1647 IMFVideoSampleAllocator_QueryInterface(topo_node
->u
.sink
.allocator
,
1648 &IID_IMFVideoSampleAllocatorCallback
, (void **)&topo_node
->u
.sink
.allocator_cb
);
1649 IMFVideoSampleAllocatorCallback_SetCallback(topo_node
->u
.sink
.allocator_cb
,
1650 &topo_node
->u
.sink
.notify_cb
);
1652 IMFMediaType_Release(media_type
);
1655 IMFMediaSink_Release(media_sink
);
1658 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
1659 if (FAILED(IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_SOURCE
, &IID_IMFMediaSource
,
1660 (void **)&topo_node
->u
.source
.source
)))
1662 WARN("Missing MF_TOPONODE_SOURCE, hr %#lx.\n", hr
);
1666 if (FAILED(hr
= session_add_media_source(session
, node
, topo_node
->u
.source
.source
)))
1669 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
1670 &IID_IMFStreamDescriptor
, (void **)&sd
)))
1672 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#lx.\n", hr
);
1676 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &topo_node
->u
.source
.stream_id
);
1677 IMFStreamDescriptor_Release(sd
);
1680 case MF_TOPOLOGY_TRANSFORM_NODE
:
1682 if (SUCCEEDED(hr
= topology_node_get_object(node
, &IID_IMFTransform
, (void **)&topo_node
->object
.transform
)))
1684 hr
= session_set_transform_stream_info(topo_node
);
1687 WARN("Failed to get IMFTransform for MFT node, hr %#lx.\n", hr
);
1690 case MF_TOPOLOGY_TEE_NODE
:
1691 FIXME("Unsupported node type %d.\n", topo_node
->type
);
1699 list_add_tail(&session
->presentation
.nodes
, &topo_node
->entry
);
1701 release_topo_node(topo_node
);
1706 static HRESULT
session_collect_nodes(struct media_session
*session
)
1708 IMFTopology
*topology
= session
->presentation
.current_topology
;
1709 IMFTopologyNode
*node
;
1713 if (!list_empty(&session
->presentation
.nodes
))
1716 if (FAILED(hr
= IMFTopology_GetNodeCount(topology
, &count
)))
1719 for (i
= 0; i
< count
; ++i
)
1721 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
1723 WARN("Failed to get node %u.\n", i
);
1727 hr
= session_append_node(session
, node
);
1728 IMFTopologyNode_Release(node
);
1731 WARN("Failed to add node %u.\n", i
);
1739 static HRESULT
session_set_current_topology(struct media_session
*session
, IMFTopology
*topology
)
1741 struct media_source
*source
;
1742 DWORD caps
, object_flags
;
1743 struct media_sink
*sink
;
1744 struct topo_node
*node
;
1745 IMFMediaEvent
*event
;
1748 if (FAILED(hr
= IMFTopology_CloneFrom(session
->presentation
.current_topology
, topology
)))
1750 WARN("Failed to clone topology, hr %#lx.\n", hr
);
1754 session_collect_nodes(session
);
1756 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1758 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
1760 if (FAILED(hr
= IMFTransform_ProcessMessage(node
->object
.transform
,
1761 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING
, 0)))
1766 /* FIXME: attributes are all zero for now */
1767 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime
, &GUID_NULL
, S_OK
, NULL
, &event
)))
1769 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME
, 0);
1770 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
1771 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT
, 0);
1773 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
1774 IMFMediaEvent_Release(event
);
1777 /* Update session caps. */
1778 caps
= MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
| MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
|
1779 MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1781 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1787 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &object_flags
)))
1789 if (!(object_flags
& MFMEDIASOURCE_DOES_NOT_USE_NETWORK
))
1790 caps
&= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1791 if (!(object_flags
& MFMEDIASOURCE_CAN_SEEK
))
1792 caps
&= ~MFSESSIONCAP_SEEK
;
1795 /* Mask unsupported rate caps. */
1797 caps
&= session_get_object_rate_caps(source
->object
)
1798 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1801 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1807 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
->sink
, &object_flags
)))
1809 if (!(object_flags
& MEDIASINK_RATELESS
))
1810 caps
&= session_get_object_rate_caps(sink
->object
)
1811 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1815 session_set_caps(session
, caps
);
1820 static void session_set_topology(struct media_session
*session
, DWORD flags
, IMFTopology
*topology
)
1822 IMFTopology
*resolved_topology
= NULL
;
1825 /* Resolve unless claimed to be full. */
1826 if (!(flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
) && topology
)
1828 if (!(flags
& MFSESSION_SETTOPOLOGY_NORESOLUTION
))
1830 hr
= session_bind_output_nodes(topology
);
1833 hr
= IMFTopoLoader_Load(session
->topo_loader
, topology
, &resolved_topology
, NULL
/* FIXME? */);
1835 hr
= session_init_media_types(resolved_topology
);
1839 topology
= resolved_topology
;
1844 if (flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
)
1846 if ((topology
&& topology
== session
->presentation
.current_topology
) || !topology
)
1848 /* FIXME: stop current topology, queue next one. */
1849 session_clear_presentation(session
);
1856 else if (topology
&& flags
& MFSESSION_SETTOPOLOGY_IMMEDIATE
)
1858 session_clear_queued_topologies(session
);
1859 session_clear_presentation(session
);
1862 session_raise_topology_set(session
, topology
, hr
);
1864 /* With no current topology set it right away, otherwise queue. */
1867 struct queued_topology
*queued_topology
;
1869 if ((queued_topology
= calloc(1, sizeof(*queued_topology
))))
1871 queued_topology
->topology
= topology
;
1872 IMFTopology_AddRef(queued_topology
->topology
);
1874 list_add_tail(&session
->topologies
, &queued_topology
->entry
);
1877 if (session
->presentation
.topo_status
== MF_TOPOSTATUS_INVALID
)
1879 hr
= session_set_current_topology(session
, topology
);
1880 session_set_topo_status(session
, hr
, MF_TOPOSTATUS_READY
);
1881 if (session
->quality_manager
)
1882 IMFQualityManager_NotifyTopology(session
->quality_manager
, topology
);
1886 if (resolved_topology
)
1887 IMFTopology_Release(resolved_topology
);
1890 static HRESULT WINAPI
mfsession_QueryInterface(IMFMediaSession
*iface
, REFIID riid
, void **out
)
1892 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1894 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1898 if (IsEqualIID(riid
, &IID_IMFMediaSession
) ||
1899 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1900 IsEqualIID(riid
, &IID_IUnknown
))
1902 *out
= &session
->IMFMediaSession_iface
;
1904 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1906 *out
= &session
->IMFGetService_iface
;
1908 else if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1910 *out
= &session
->IMFRateSupport_iface
;
1912 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
1914 *out
= &session
->IMFRateControl_iface
;
1919 IMFMediaSession_AddRef(iface
);
1923 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1924 return E_NOINTERFACE
;
1927 static ULONG WINAPI
mfsession_AddRef(IMFMediaSession
*iface
)
1929 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1930 ULONG refcount
= InterlockedIncrement(&session
->refcount
);
1932 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1937 static ULONG WINAPI
mfsession_Release(IMFMediaSession
*iface
)
1939 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1940 ULONG refcount
= InterlockedDecrement(&session
->refcount
);
1942 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1946 session_clear_queued_topologies(session
);
1947 session_clear_presentation(session
);
1948 session_clear_command_list(session
);
1949 if (session
->presentation
.current_topology
)
1950 IMFTopology_Release(session
->presentation
.current_topology
);
1951 if (session
->event_queue
)
1952 IMFMediaEventQueue_Release(session
->event_queue
);
1954 IMFPresentationClock_Release(session
->clock
);
1955 if (session
->system_time_source
)
1956 IMFPresentationTimeSource_Release(session
->system_time_source
);
1957 if (session
->clock_rate_control
)
1958 IMFRateControl_Release(session
->clock_rate_control
);
1959 if (session
->topo_loader
)
1960 IMFTopoLoader_Release(session
->topo_loader
);
1961 if (session
->quality_manager
)
1962 IMFQualityManager_Release(session
->quality_manager
);
1963 DeleteCriticalSection(&session
->cs
);
1970 static HRESULT WINAPI
mfsession_GetEvent(IMFMediaSession
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1972 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1974 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
1976 return IMFMediaEventQueue_GetEvent(session
->event_queue
, flags
, event
);
1979 static HRESULT WINAPI
mfsession_BeginGetEvent(IMFMediaSession
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1981 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1983 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1985 return IMFMediaEventQueue_BeginGetEvent(session
->event_queue
, callback
, state
);
1988 static HRESULT WINAPI
mfsession_EndGetEvent(IMFMediaSession
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
1990 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1992 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1994 return IMFMediaEventQueue_EndGetEvent(session
->event_queue
, result
, event
);
1997 static HRESULT WINAPI
mfsession_QueueEvent(IMFMediaSession
*iface
, MediaEventType event_type
, REFGUID ext_type
,
1998 HRESULT hr
, const PROPVARIANT
*value
)
2000 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2002 TRACE("%p, %ld, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
2004 return IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, event_type
, ext_type
, hr
, value
);
2007 static HRESULT
session_check_stream_descriptor(IMFPresentationDescriptor
*pd
, IMFStreamDescriptor
*sd
)
2009 IMFStreamDescriptor
*selected_sd
;
2014 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(pd
, &count
)))
2016 WARN("Failed to get stream descriptor count, hr %#lx.\n", hr
);
2017 return MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED
;
2020 for (i
= 0; i
< count
; ++i
)
2022 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd
, i
,
2023 &selected
, &selected_sd
)))
2025 WARN("Failed to get stream descriptor %lu, hr %#lx.\n", i
, hr
);
2026 return MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED
;
2028 IMFStreamDescriptor_Release(selected_sd
);
2030 if (selected_sd
== sd
)
2035 WARN("Presentation descriptor %p stream %p is not selected.\n", pd
, sd
);
2036 return MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED
;
2040 WARN("Failed to find stream descriptor %lu, hr %#lx.\n", i
, hr
);
2041 return MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED
;
2044 static HRESULT
session_check_topology(IMFTopology
*topology
)
2046 MF_TOPOLOGY_TYPE node_type
;
2047 IMFTopologyNode
*node
;
2054 if (FAILED(IMFTopology_GetNodeCount(topology
, &node_count
))
2056 return E_INVALIDARG
;
2058 for (i
= 0; i
< node_count
; ++i
)
2060 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
2063 if (FAILED(hr
= IMFTopologyNode_GetNodeType(node
, &node_type
)))
2065 IMFTopologyNode_Release(node
);
2071 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
2073 IMFPresentationDescriptor
*pd
;
2074 IMFStreamDescriptor
*sd
;
2075 IMFMediaSource
*source
;
2077 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_SOURCE
, &IID_IMFMediaSource
,
2080 WARN("Missing MF_TOPONODE_SOURCE, hr %#lx.\n", hr
);
2081 IMFTopologyNode_Release(node
);
2082 return MF_E_TOPO_MISSING_SOURCE
;
2084 IMFMediaSource_Release(source
);
2086 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
,
2087 &IID_IMFPresentationDescriptor
, (void **)&pd
)))
2089 WARN("Missing MF_TOPONODE_PRESENTATION_DESCRIPTOR, hr %#lx.\n", hr
);
2090 IMFTopologyNode_Release(node
);
2091 return MF_E_TOPO_MISSING_PRESENTATION_DESCRIPTOR
;
2094 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
2095 &IID_IMFStreamDescriptor
, (void **)&sd
)))
2097 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#lx.\n", hr
);
2098 IMFPresentationDescriptor_Release(pd
);
2099 IMFTopologyNode_Release(node
);
2100 return MF_E_TOPO_MISSING_STREAM_DESCRIPTOR
;
2103 hr
= session_check_stream_descriptor(pd
, sd
);
2104 IMFPresentationDescriptor_Release(pd
);
2105 IMFStreamDescriptor_Release(sd
);
2108 IMFTopologyNode_Release(node
);
2119 IMFTopologyNode_Release(node
);
2125 static HRESULT WINAPI
mfsession_SetTopology(IMFMediaSession
*iface
, DWORD flags
, IMFTopology
*topology
)
2127 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2128 struct session_op
*op
;
2131 TRACE("%p, %#lx, %p.\n", iface
, flags
, topology
);
2133 if (FAILED(hr
= session_check_topology(topology
)))
2136 if (FAILED(hr
= create_session_op(SESSION_CMD_SET_TOPOLOGY
, &op
)))
2139 op
->set_topology
.flags
= flags
;
2140 op
->set_topology
.topology
= topology
;
2141 if (op
->set_topology
.topology
)
2142 IMFTopology_AddRef(op
->set_topology
.topology
);
2144 hr
= session_submit_command(session
, op
);
2145 IUnknown_Release(&op
->IUnknown_iface
);
2150 static HRESULT WINAPI
mfsession_ClearTopologies(IMFMediaSession
*iface
)
2152 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2154 TRACE("%p.\n", iface
);
2156 return session_submit_simple_command(session
, SESSION_CMD_CLEAR_TOPOLOGIES
);
2159 static HRESULT WINAPI
mfsession_Start(IMFMediaSession
*iface
, const GUID
*format
, const PROPVARIANT
*start_position
)
2161 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2162 struct session_op
*op
;
2165 TRACE("%p, %s, %s.\n", iface
, debugstr_guid(format
), debugstr_propvar(start_position
));
2167 if (!start_position
)
2170 if (FAILED(hr
= create_session_op(SESSION_CMD_START
, &op
)))
2173 op
->start
.time_format
= format
? *format
: GUID_NULL
;
2174 hr
= PropVariantCopy(&op
->start
.start_position
, start_position
);
2177 hr
= session_submit_command(session
, op
);
2179 IUnknown_Release(&op
->IUnknown_iface
);
2183 static HRESULT WINAPI
mfsession_Pause(IMFMediaSession
*iface
)
2185 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2187 TRACE("%p.\n", iface
);
2189 return session_submit_simple_command(session
, SESSION_CMD_PAUSE
);
2192 static HRESULT WINAPI
mfsession_Stop(IMFMediaSession
*iface
)
2194 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2196 TRACE("%p.\n", iface
);
2198 return session_submit_simple_command(session
, SESSION_CMD_STOP
);
2201 static HRESULT WINAPI
mfsession_Close(IMFMediaSession
*iface
)
2203 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2205 TRACE("%p.\n", iface
);
2207 return session_submit_simple_command(session
, SESSION_CMD_CLOSE
);
2210 static HRESULT WINAPI
mfsession_Shutdown(IMFMediaSession
*iface
)
2212 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2215 TRACE("%p.\n", iface
);
2217 EnterCriticalSection(&session
->cs
);
2218 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
2220 session
->state
= SESSION_STATE_SHUT_DOWN
;
2221 IMFMediaEventQueue_Shutdown(session
->event_queue
);
2222 if (session
->quality_manager
)
2223 IMFQualityManager_Shutdown(session
->quality_manager
);
2224 MFShutdownObject((IUnknown
*)session
->clock
);
2225 IMFPresentationClock_Release(session
->clock
);
2226 session
->clock
= NULL
;
2227 session_clear_presentation(session
);
2228 session_clear_queued_topologies(session
);
2229 session_submit_simple_command(session
, SESSION_CMD_SHUTDOWN
);
2231 LeaveCriticalSection(&session
->cs
);
2236 static HRESULT WINAPI
mfsession_GetClock(IMFMediaSession
*iface
, IMFClock
**clock
)
2238 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2241 TRACE("%p, %p.\n", iface
, clock
);
2243 EnterCriticalSection(&session
->cs
);
2244 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
2246 *clock
= (IMFClock
*)session
->clock
;
2247 IMFClock_AddRef(*clock
);
2249 LeaveCriticalSection(&session
->cs
);
2254 static HRESULT WINAPI
mfsession_GetSessionCapabilities(IMFMediaSession
*iface
, DWORD
*caps
)
2256 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2259 TRACE("%p, %p.\n", iface
, caps
);
2264 EnterCriticalSection(&session
->cs
);
2265 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
2266 *caps
= session
->caps
;
2267 LeaveCriticalSection(&session
->cs
);
2272 static HRESULT WINAPI
mfsession_GetFullTopology(IMFMediaSession
*iface
, DWORD flags
, TOPOID id
, IMFTopology
**topology
)
2274 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2275 struct queued_topology
*queued
;
2279 TRACE("%p, %#lx, %s, %p.\n", iface
, flags
, wine_dbgstr_longlong(id
), topology
);
2283 EnterCriticalSection(&session
->cs
);
2285 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
2287 if (flags
& MFSESSION_GETFULLTOPOLOGY_CURRENT
)
2289 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
2290 *topology
= session
->presentation
.current_topology
;
2292 hr
= MF_E_INVALIDREQUEST
;
2296 LIST_FOR_EACH_ENTRY(queued
, &session
->topologies
, struct queued_topology
, entry
)
2298 if (SUCCEEDED(IMFTopology_GetTopologyID(queued
->topology
, &topo_id
)) && topo_id
== id
)
2300 *topology
= queued
->topology
;
2307 IMFTopology_AddRef(*topology
);
2310 LeaveCriticalSection(&session
->cs
);
2315 static const IMFMediaSessionVtbl mfmediasessionvtbl
=
2317 mfsession_QueryInterface
,
2321 mfsession_BeginGetEvent
,
2322 mfsession_EndGetEvent
,
2323 mfsession_QueueEvent
,
2324 mfsession_SetTopology
,
2325 mfsession_ClearTopologies
,
2332 mfsession_GetSessionCapabilities
,
2333 mfsession_GetFullTopology
,
2336 static HRESULT WINAPI
session_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
2338 struct media_session
*session
= impl_from_IMFGetService(iface
);
2339 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
2342 static ULONG WINAPI
session_get_service_AddRef(IMFGetService
*iface
)
2344 struct media_session
*session
= impl_from_IMFGetService(iface
);
2345 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2348 static ULONG WINAPI
session_get_service_Release(IMFGetService
*iface
)
2350 struct media_session
*session
= impl_from_IMFGetService(iface
);
2351 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2354 typedef BOOL (*p_renderer_node_test_func
)(IMFMediaSink
*sink
);
2356 static BOOL
session_video_renderer_test_func(IMFMediaSink
*sink
)
2361 /* Use first sink to support IMFVideoRenderer. */
2362 hr
= IMFMediaSink_QueryInterface(sink
, &IID_IMFVideoRenderer
, (void **)&obj
);
2364 IUnknown_Release(obj
);
2369 static BOOL
session_audio_renderer_test_func(IMFMediaSink
*sink
)
2371 return mf_is_sar_sink(sink
);
2374 static HRESULT
session_get_renderer_node_service(struct media_session
*session
,
2375 p_renderer_node_test_func node_test_func
, REFGUID service
, REFIID riid
, void **obj
)
2377 HRESULT hr
= E_NOINTERFACE
;
2378 IMFStreamSink
*stream_sink
;
2379 IMFTopologyNode
*node
;
2380 IMFCollection
*nodes
;
2384 if (session
->presentation
.current_topology
)
2386 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session
->presentation
.current_topology
,
2389 while (IMFCollection_GetElement(nodes
, i
++, (IUnknown
**)&node
) == S_OK
)
2391 if (SUCCEEDED(topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
2393 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink
, &sink
)))
2395 if (node_test_func(sink
))
2397 if (FAILED(hr
= MFGetService((IUnknown
*)sink
, service
, riid
, obj
)))
2398 WARN("Failed to get service from renderer node, %#lx.\n", hr
);
2400 IMFMediaSink_Release(sink
);
2402 IMFStreamSink_Release(stream_sink
);
2405 IMFTopologyNode_Release(node
);
2411 IMFCollection_Release(nodes
);
2418 static HRESULT
session_get_audio_render_service(struct media_session
*session
, REFGUID service
,
2419 REFIID riid
, void **obj
)
2421 return session_get_renderer_node_service(session
, session_audio_renderer_test_func
,
2422 service
, riid
, obj
);
2425 static HRESULT
session_get_video_render_service(struct media_session
*session
, REFGUID service
,
2426 REFIID riid
, void **obj
)
2428 return session_get_renderer_node_service(session
, session_video_renderer_test_func
,
2429 service
, riid
, obj
);
2432 static HRESULT WINAPI
session_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
2434 struct media_session
*session
= impl_from_IMFGetService(iface
);
2437 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
2441 EnterCriticalSection(&session
->cs
);
2442 if (FAILED(hr
= session_is_shut_down(session
)))
2445 else if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
2447 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
2449 *obj
= &session
->IMFRateSupport_iface
;
2451 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
2453 *obj
= &session
->IMFRateControl_iface
;
2459 IUnknown_AddRef((IUnknown
*)*obj
);
2461 else if (IsEqualGUID(service
, &MF_LOCAL_MFT_REGISTRATION_SERVICE
))
2463 hr
= IMFLocalMFTRegistration_QueryInterface(&local_mft_registration
, riid
, obj
);
2465 else if (IsEqualGUID(service
, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE
))
2467 *obj
= &session
->IMFTopologyNodeAttributeEditor_iface
;
2468 IUnknown_AddRef((IUnknown
*)*obj
);
2470 else if (IsEqualGUID(service
, &MR_VIDEO_RENDER_SERVICE
))
2472 hr
= session_get_video_render_service(session
, service
, riid
, obj
);
2474 else if (IsEqualGUID(service
, &MR_POLICY_VOLUME_SERVICE
) ||
2475 IsEqualGUID(service
, &MR_STREAM_VOLUME_SERVICE
))
2477 hr
= session_get_audio_render_service(session
, service
, riid
, obj
);
2480 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
2482 LeaveCriticalSection(&session
->cs
);
2487 static const IMFGetServiceVtbl session_get_service_vtbl
=
2489 session_get_service_QueryInterface
,
2490 session_get_service_AddRef
,
2491 session_get_service_Release
,
2492 session_get_service_GetService
,
2495 static HRESULT WINAPI
session_commands_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2497 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2498 IsEqualIID(riid
, &IID_IUnknown
))
2501 IMFAsyncCallback_AddRef(iface
);
2505 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2507 return E_NOINTERFACE
;
2510 static ULONG WINAPI
session_commands_callback_AddRef(IMFAsyncCallback
*iface
)
2512 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2513 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2516 static ULONG WINAPI
session_commands_callback_Release(IMFAsyncCallback
*iface
)
2518 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2519 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2522 static HRESULT WINAPI
session_commands_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2527 static void session_deliver_pending_samples(struct media_session
*session
, IMFTopologyNode
*node
);
2529 static HRESULT WINAPI
session_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
2531 struct session_op
*op
= impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result
));
2532 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2534 TRACE("session %p, op %p, command %u.\n", session
, op
, op
->command
);
2536 EnterCriticalSection(&session
->cs
);
2538 if (session
->presentation
.flags
& SESSION_FLAG_PENDING_COMMAND
)
2540 WARN("session %p command is in progress, waiting for it to complete.\n", session
);
2541 LeaveCriticalSection(&session
->cs
);
2545 list_remove(&op
->entry
);
2546 session
->presentation
.flags
|= SESSION_FLAG_PENDING_COMMAND
;
2548 switch (op
->command
)
2550 case SESSION_CMD_CLEAR_TOPOLOGIES
:
2551 session_clear_topologies(session
);
2553 case SESSION_CMD_SET_TOPOLOGY
:
2554 session_set_topology(session
, op
->set_topology
.flags
, op
->set_topology
.topology
);
2555 session_command_complete(session
);
2557 case SESSION_CMD_START
:
2558 session_start(session
, &op
->start
.time_format
, &op
->start
.start_position
);
2560 case SESSION_CMD_PAUSE
:
2561 session_pause(session
);
2563 case SESSION_CMD_STOP
:
2564 session_stop(session
);
2566 case SESSION_CMD_CLOSE
:
2567 session_close(session
);
2569 case SESSION_CMD_SET_RATE
:
2570 session_set_rate(session
, op
->set_rate
.thin
, op
->set_rate
.rate
);
2572 case SESSION_CMD_SHUTDOWN
:
2573 session_clear_command_list(session
);
2574 session_command_complete(session
);
2580 LeaveCriticalSection(&session
->cs
);
2582 IUnknown_Release(&op
->IUnknown_iface
);
2587 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl
=
2589 session_commands_callback_QueryInterface
,
2590 session_commands_callback_AddRef
,
2591 session_commands_callback_Release
,
2592 session_commands_callback_GetParameters
,
2593 session_commands_callback_Invoke
,
2596 static HRESULT WINAPI
session_sa_ready_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2598 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
)
2599 || IsEqualIID(riid
, &IID_IUnknown
))
2602 IMFAsyncCallback_AddRef(iface
);
2606 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2608 return E_NOINTERFACE
;
2611 static ULONG WINAPI
session_sa_ready_callback_AddRef(IMFAsyncCallback
*iface
)
2613 struct media_session
*session
= impl_from_sa_ready_callback_IMFAsyncCallback(iface
);
2614 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2617 static ULONG WINAPI
session_sa_ready_callback_Release(IMFAsyncCallback
*iface
)
2619 struct media_session
*session
= impl_from_sa_ready_callback_IMFAsyncCallback(iface
);
2620 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2623 static HRESULT WINAPI
session_sa_ready_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2628 static HRESULT WINAPI
session_sa_ready_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
2630 IMFVideoSampleAllocatorNotify
*notify
= (IMFVideoSampleAllocatorNotify
*)IMFAsyncResult_GetStateNoAddRef(result
);
2631 struct topo_node
*topo_node
= impl_node_from_IMFVideoSampleAllocatorNotify(notify
);
2632 struct media_session
*session
= impl_from_sa_ready_callback_IMFAsyncCallback(iface
);
2633 IMFTopologyNode
*upstream_node
;
2634 DWORD upstream_output
;
2636 EnterCriticalSection(&session
->cs
);
2638 if (topo_node
->u
.sink
.requests
)
2640 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node
->node
, 0, &upstream_node
, &upstream_output
)))
2642 session_deliver_pending_samples(session
, upstream_node
);
2643 IMFTopologyNode_Release(upstream_node
);
2647 LeaveCriticalSection(&session
->cs
);
2652 static const IMFAsyncCallbackVtbl session_sa_ready_callback_vtbl
=
2654 session_sa_ready_callback_QueryInterface
,
2655 session_sa_ready_callback_AddRef
,
2656 session_sa_ready_callback_Release
,
2657 session_sa_ready_callback_GetParameters
,
2658 session_sa_ready_callback_Invoke
,
2661 static HRESULT WINAPI
session_events_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2663 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2664 IsEqualIID(riid
, &IID_IUnknown
))
2667 IMFAsyncCallback_AddRef(iface
);
2671 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2673 return E_NOINTERFACE
;
2676 static ULONG WINAPI
session_events_callback_AddRef(IMFAsyncCallback
*iface
)
2678 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2679 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2682 static ULONG WINAPI
session_events_callback_Release(IMFAsyncCallback
*iface
)
2684 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2685 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2688 static HRESULT WINAPI
session_events_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2693 static HRESULT
session_add_media_stream(struct media_session
*session
, IMFMediaSource
*source
, IMFMediaStream
*stream
)
2695 struct topo_node
*node
;
2696 IMFStreamDescriptor
*sd
;
2697 DWORD stream_id
= 0;
2700 if (FAILED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
2703 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &stream_id
);
2704 IMFStreamDescriptor_Release(sd
);
2708 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2710 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->u
.source
.source
== source
2711 && node
->u
.source
.stream_id
== stream_id
)
2713 if (node
->object
.source_stream
)
2715 WARN("Node already has stream set.\n");
2719 node
->object
.source_stream
= stream
;
2720 IMFMediaStream_AddRef(node
->object
.source_stream
);
2728 static BOOL
session_is_source_nodes_state(struct media_session
*session
, enum object_state state
)
2730 struct media_source
*source
;
2731 struct topo_node
*node
;
2733 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2735 if (source
->state
!= state
)
2739 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2741 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->state
!= state
)
2748 static BOOL
session_is_output_nodes_state(struct media_session
*session
, enum object_state state
)
2750 struct topo_node
*node
;
2752 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2754 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->state
!= state
)
2761 static enum object_state
session_get_object_state_for_event(MediaEventType event
)
2765 case MESourceSeeked
:
2766 case MEStreamSeeked
:
2767 case MESourceStarted
:
2768 case MEStreamStarted
:
2769 case MEStreamSinkStarted
:
2770 return OBJ_STATE_STARTED
;
2771 case MESourcePaused
:
2772 case MEStreamPaused
:
2773 case MEStreamSinkPaused
:
2774 return OBJ_STATE_PAUSED
;
2775 case MESourceStopped
:
2776 case MEStreamStopped
:
2777 case MEStreamSinkStopped
:
2778 return OBJ_STATE_STOPPED
;
2779 case MEStreamSinkPrerolled
:
2780 return OBJ_STATE_PREROLLED
;
2782 return OBJ_STATE_INVALID
;
2786 static HRESULT
session_start_clock(struct media_session
*session
)
2788 LONGLONG start_offset
= 0;
2791 if (IsEqualGUID(&session
->presentation
.time_format
, &GUID_NULL
))
2793 if (session
->presentation
.start_position
.vt
== VT_EMPTY
)
2794 start_offset
= PRESENTATION_CURRENT_POSITION
;
2795 else if (session
->presentation
.start_position
.vt
== VT_I8
)
2796 start_offset
= session
->presentation
.start_position
.hVal
.QuadPart
;
2798 FIXME("Unhandled position type %d.\n", session
->presentation
.start_position
.vt
);
2801 FIXME("Unhandled time format %s.\n", debugstr_guid(&session
->presentation
.time_format
));
2803 if (FAILED(hr
= IMFPresentationClock_Start(session
->clock
, start_offset
)))
2804 WARN("Failed to start session clock, hr %#lx.\n", hr
);
2809 static struct topo_node
*session_get_node_object(struct media_session
*session
, IUnknown
*object
,
2810 MF_TOPOLOGY_TYPE node_type
)
2812 struct topo_node
*node
= NULL
;
2814 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2816 if (node
->type
== node_type
&& object
== node
->object
.object
)
2823 static BOOL
session_set_node_object_state(struct media_session
*session
, IUnknown
*object
,
2824 MF_TOPOLOGY_TYPE node_type
, enum object_state state
)
2826 struct topo_node
*node
;
2827 BOOL changed
= FALSE
;
2829 if ((node
= session_get_node_object(session
, object
, node_type
)))
2831 changed
= node
->state
!= state
;
2832 node
->state
= state
;
2838 static void session_set_source_object_state(struct media_session
*session
, IUnknown
*object
,
2839 MediaEventType event_type
)
2841 IMFStreamSink
*stream_sink
;
2842 struct media_source
*src
;
2843 struct media_sink
*sink
;
2844 enum object_state state
;
2845 struct topo_node
*node
;
2846 BOOL changed
= FALSE
;
2850 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2855 case MESourceSeeked
:
2856 case MESourceStarted
:
2857 case MESourcePaused
:
2858 case MESourceStopped
:
2860 LIST_FOR_EACH_ENTRY(src
, &session
->presentation
.sources
, struct media_source
, entry
)
2862 if (object
== src
->object
)
2864 changed
= src
->state
!= state
;
2870 case MEStreamSeeked
:
2871 case MEStreamStarted
:
2872 case MEStreamPaused
:
2873 case MEStreamStopped
:
2875 changed
= session_set_node_object_state(session
, object
, MF_TOPOLOGY_SOURCESTREAM_NODE
, state
);
2883 switch (session
->state
)
2885 case SESSION_STATE_STARTING_SOURCES
:
2886 if (!session_is_source_nodes_state(session
, OBJ_STATE_STARTED
))
2889 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_STARTED_SOURCE
);
2891 session_set_presentation_clock(session
);
2893 if (session
->presentation
.flags
& SESSION_FLAG_NEEDS_PREROLL
)
2895 MFTIME preroll_time
= 0;
2897 if (session
->presentation
.start_position
.vt
== VT_I8
)
2898 preroll_time
= session
->presentation
.start_position
.hVal
.QuadPart
;
2900 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2901 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2905 /* FIXME: abort and enter error state on failure. */
2906 if (FAILED(hr
= IMFMediaSinkPreroll_NotifyPreroll(sink
->preroll
, preroll_time
)))
2907 WARN("Preroll notification failed, hr %#lx.\n", hr
);
2911 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink
->sink
, &count
)))
2913 for (i
= 0; i
< count
; ++i
)
2915 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink
->sink
, i
, &stream_sink
)))
2917 session_set_node_object_state(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
,
2918 OBJ_STATE_PREROLLED
);
2919 IMFStreamSink_Release(stream_sink
);
2925 session
->state
= SESSION_STATE_PREROLLING_SINKS
;
2927 else if (SUCCEEDED(session_start_clock(session
)))
2928 session
->state
= SESSION_STATE_STARTING_SINKS
;
2931 case SESSION_STATE_PAUSING_SOURCES
:
2932 if (!session_is_source_nodes_state(session
, OBJ_STATE_PAUSED
))
2935 session_set_paused(session
, SESSION_STATE_PAUSED
, S_OK
);
2937 case SESSION_STATE_STOPPING_SOURCES
:
2938 if (!session_is_source_nodes_state(session
, OBJ_STATE_STOPPED
))
2941 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2945 case MF_TOPOLOGY_OUTPUT_NODE
:
2946 IMFStreamSink_Flush(node
->object
.sink_stream
);
2948 case MF_TOPOLOGY_TRANSFORM_NODE
:
2949 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
2956 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
2958 if (session
->presentation
.flags
& SESSION_FLAG_FINALIZE_SINKS
)
2959 session_finalize_sinks(session
);
2961 session_set_stopped(session
, S_OK
);
2969 static void session_set_sink_stream_state(struct media_session
*session
, IMFStreamSink
*stream
,
2970 MediaEventType event_type
)
2972 struct media_source
*source
;
2973 enum object_state state
;
2977 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2980 if (!(changed
= session_set_node_object_state(session
, (IUnknown
*)stream
, MF_TOPOLOGY_OUTPUT_NODE
, state
)))
2983 switch (session
->state
)
2985 case SESSION_STATE_PREROLLING_SINKS
:
2986 if (!session_is_output_nodes_state(session
, OBJ_STATE_PREROLLED
))
2989 if (SUCCEEDED(session_start_clock(session
)))
2990 session
->state
= SESSION_STATE_STARTING_SINKS
;
2992 case SESSION_STATE_STARTING_SINKS
:
2993 if (!session_is_output_nodes_state(session
, OBJ_STATE_STARTED
))
2996 session_set_started(session
);
2998 case SESSION_STATE_PAUSING_SINKS
:
2999 if (!session_is_output_nodes_state(session
, OBJ_STATE_PAUSED
))
3002 session
->state
= SESSION_STATE_PAUSING_SOURCES
;
3004 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3006 if (FAILED(hr
= IMFMediaSource_Pause(source
->source
)))
3011 session_set_paused(session
, SESSION_STATE_PAUSED
, hr
);
3014 case SESSION_STATE_STOPPING_SINKS
:
3015 if (!session_is_output_nodes_state(session
, OBJ_STATE_STOPPED
))
3018 session
->state
= SESSION_STATE_STOPPING_SOURCES
;
3020 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3022 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
)
3023 IMFMediaSource_Stop(source
->source
);
3024 else if (FAILED(hr
= IMFMediaSource_Stop(source
->source
)))
3028 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
|| FAILED(hr
))
3029 session_set_stopped(session
, hr
);
3037 static struct sample
*transform_create_sample(IMFSample
*sample
)
3039 struct sample
*sample_entry
= calloc(1, sizeof(*sample_entry
));
3043 sample_entry
->sample
= sample
;
3044 if (sample_entry
->sample
)
3045 IMFSample_AddRef(sample_entry
->sample
);
3048 return sample_entry
;
3051 static HRESULT
transform_get_external_output_sample(const struct media_session
*session
, struct topo_node
*transform
,
3052 unsigned int output_index
, const MFT_OUTPUT_STREAM_INFO
*stream_info
, IMFSample
**sample
)
3054 IMFTopologyNode
*downstream_node
;
3055 IMFMediaBuffer
*buffer
= NULL
;
3056 struct topo_node
*topo_node
;
3057 unsigned int buffer_size
;
3058 DWORD downstream_input
;
3062 if (FAILED(IMFTopologyNode_GetOutput(transform
->node
, output_index
, &downstream_node
, &downstream_input
)))
3064 WARN("Failed to get connected node for output %u.\n", output_index
);
3065 return MF_E_UNEXPECTED
;
3068 IMFTopologyNode_GetTopoNodeID(downstream_node
, &node_id
);
3069 IMFTopologyNode_Release(downstream_node
);
3071 topo_node
= session_get_node_by_id(session
, node_id
);
3073 if (topo_node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& topo_node
->u
.sink
.allocator
)
3075 hr
= IMFVideoSampleAllocator_AllocateSample(topo_node
->u
.sink
.allocator
, sample
);
3079 buffer_size
= max(stream_info
->cbSize
, transform
->u
.transform
.outputs
[output_index
].min_buffer_size
);
3081 hr
= MFCreateAlignedMemoryBuffer(buffer_size
, stream_info
->cbAlignment
, &buffer
);
3083 hr
= MFCreateSample(sample
);
3086 hr
= IMFSample_AddBuffer(*sample
, buffer
);
3089 IMFMediaBuffer_Release(buffer
);
3095 static HRESULT
transform_node_pull_samples(const struct media_session
*session
, struct topo_node
*node
)
3097 MFT_OUTPUT_STREAM_INFO stream_info
;
3098 MFT_OUTPUT_DATA_BUFFER
*buffers
;
3099 struct sample
*queued_sample
;
3100 HRESULT hr
= E_UNEXPECTED
;
3104 if (!(buffers
= calloc(node
->u
.transform
.output_count
, sizeof(*buffers
))))
3105 return E_OUTOFMEMORY
;
3107 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
3109 buffers
[i
].dwStreamID
= transform_node_get_stream_id(node
, TRUE
, i
);
3110 buffers
[i
].pSample
= NULL
;
3111 buffers
[i
].dwStatus
= 0;
3112 buffers
[i
].pEvents
= NULL
;
3114 memset(&stream_info
, 0, sizeof(stream_info
));
3115 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(node
->object
.transform
, buffers
[i
].dwStreamID
, &stream_info
)))
3118 if (!(stream_info
.dwFlags
& (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
| MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
)))
3120 if (FAILED(hr
= transform_get_external_output_sample(session
, node
, i
, &stream_info
, &buffers
[i
].pSample
)))
3126 hr
= IMFTransform_ProcessOutput(node
->object
.transform
, 0, node
->u
.transform
.output_count
, buffers
, &status
);
3128 /* Collect returned samples for all streams. */
3129 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
3131 if (buffers
[i
].pEvents
)
3132 IMFCollection_Release(buffers
[i
].pEvents
);
3134 if (SUCCEEDED(hr
) && !(buffers
[i
].dwStatus
& MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE
))
3136 if (session
->quality_manager
)
3137 IMFQualityManager_NotifyProcessOutput(session
->quality_manager
, node
->node
, i
, buffers
[i
].pSample
);
3139 queued_sample
= transform_create_sample(buffers
[i
].pSample
);
3140 list_add_tail(&node
->u
.transform
.outputs
[i
].samples
, &queued_sample
->entry
);
3143 if (buffers
[i
].pSample
)
3144 IMFSample_Release(buffers
[i
].pSample
);
3152 static void session_deliver_sample_to_node(struct media_session
*session
, IMFTopologyNode
*node
, unsigned int input
,
3155 struct sample
*sample_entry
, *sample_entry2
;
3156 DWORD stream_id
, downstream_input
;
3157 IMFTopologyNode
*downstream_node
;
3158 struct topo_node
*topo_node
;
3159 MF_TOPOLOGY_TYPE node_type
;
3165 if (session
->quality_manager
)
3166 IMFQualityManager_NotifyProcessInput(session
->quality_manager
, node
, input
, sample
);
3168 IMFTopologyNode_GetNodeType(node
, &node_type
);
3169 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
3171 topo_node
= session_get_node_by_id(session
, node_id
);
3175 case MF_TOPOLOGY_OUTPUT_NODE
:
3176 if (topo_node
->u
.sink
.requests
)
3180 if (FAILED(hr
= IMFStreamSink_ProcessSample(topo_node
->object
.sink_stream
, sample
)))
3181 WARN("Stream sink failed to process sample, hr %#lx.\n", hr
);
3183 else if (FAILED(hr
= IMFStreamSink_PlaceMarker(topo_node
->object
.sink_stream
, MFSTREAMSINK_MARKER_ENDOFSEGMENT
,
3186 WARN("Failed to place sink marker, hr %#lx.\n", hr
);
3188 topo_node
->u
.sink
.requests
--;
3191 case MF_TOPOLOGY_TRANSFORM_NODE
:
3193 transform_node_pull_samples(session
, topo_node
);
3195 sample_entry
= transform_create_sample(sample
);
3196 list_add_tail(&topo_node
->u
.transform
.inputs
[input
].samples
, &sample_entry
->entry
);
3198 for (i
= 0; i
< topo_node
->u
.transform
.input_count
; ++i
)
3200 stream_id
= transform_node_get_stream_id(topo_node
, FALSE
, i
);
3201 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.inputs
[i
].samples
,
3202 struct sample
, entry
)
3204 if (sample_entry
->sample
)
3206 if ((hr
= IMFTransform_ProcessInput(topo_node
->object
.transform
, stream_id
,
3207 sample_entry
->sample
, 0)) == MF_E_NOTACCEPTING
)
3210 WARN("Failed to process input for stream %u/%lu, hr %#lx.\n", i
, stream_id
, hr
);
3211 transform_release_sample(sample_entry
);
3215 transform_stream_drop_samples(&topo_node
->u
.transform
.inputs
[i
]);
3223 if (FAILED(hr
= IMFTransform_ProcessMessage(topo_node
->object
.transform
, MFT_MESSAGE_COMMAND_DRAIN
, 0)))
3224 WARN("Drain command failed for transform, hr %#lx.\n", hr
);
3227 transform_node_pull_samples(session
, topo_node
);
3229 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
3232 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
3234 if ((sample_entry
= transform_create_sample(NULL
)))
3235 list_add_tail(&topo_node
->u
.transform
.outputs
[i
].samples
, &sample_entry
->entry
);
3239 /* Push down all available output. */
3240 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
3242 if (FAILED(IMFTopologyNode_GetOutput(node
, i
, &downstream_node
, &downstream_input
)))
3244 WARN("Failed to get connected node for output %u.\n", i
);
3248 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.outputs
[i
].samples
,
3249 struct sample
, entry
)
3251 if (!topo_node
->u
.transform
.outputs
[i
].requests
)
3254 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample_entry
->sample
);
3255 topo_node
->u
.transform
.outputs
[i
].requests
--;
3257 transform_release_sample(sample_entry
);
3260 IMFTopologyNode_Release(downstream_node
);
3264 case MF_TOPOLOGY_TEE_NODE
:
3265 FIXME("Unhandled downstream node type %d.\n", node_type
);
3272 static void session_deliver_pending_samples(struct media_session
*session
, IMFTopologyNode
*node
)
3274 struct sample
*sample_entry
, *sample_entry2
;
3275 IMFTopologyNode
*downstream_node
;
3276 struct topo_node
*topo_node
;
3277 MF_TOPOLOGY_TYPE node_type
;
3278 DWORD downstream_input
;
3282 IMFTopologyNode_GetNodeType(node
, &node_type
);
3283 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
3285 topo_node
= session_get_node_by_id(session
, node_id
);
3289 case MF_TOPOLOGY_TRANSFORM_NODE
:
3291 transform_node_pull_samples(session
, topo_node
);
3293 /* Push down all available output. */
3294 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
3296 if (FAILED(IMFTopologyNode_GetOutput(node
, i
, &downstream_node
, &downstream_input
)))
3298 WARN("Failed to get connected node for output %u.\n", i
);
3302 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.outputs
[i
].samples
,
3303 struct sample
, entry
)
3305 if (!topo_node
->u
.transform
.outputs
[i
].requests
)
3308 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample_entry
->sample
);
3309 topo_node
->u
.transform
.outputs
[i
].requests
--;
3311 transform_release_sample(sample_entry
);
3314 IMFTopologyNode_Release(downstream_node
);
3318 FIXME("Unexpected node type %u.\n", node_type
);
3323 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
)
3325 IMFTopologyNode
*downstream_node
, *upstream_node
;
3326 DWORD downstream_input
, upstream_output
;
3327 struct topo_node
*topo_node
;
3328 MF_TOPOLOGY_TYPE node_type
;
3329 struct sample
*sample
;
3333 IMFTopologyNode_GetNodeType(node
, &node_type
);
3334 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
3336 topo_node
= session_get_node_by_id(session
, node_id
);
3340 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
3341 if (FAILED(hr
= IMFMediaStream_RequestSample(topo_node
->object
.source_stream
, NULL
)))
3342 WARN("Sample request failed, hr %#lx.\n", hr
);
3344 case MF_TOPOLOGY_TRANSFORM_NODE
:
3346 if (list_empty(&topo_node
->u
.transform
.outputs
[output
].samples
))
3348 /* Forward request to upstream node. */
3349 if (SUCCEEDED(hr
= IMFTopologyNode_GetInput(node
, 0 /* FIXME */, &upstream_node
, &upstream_output
)))
3351 if (SUCCEEDED(hr
= session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
3352 topo_node
->u
.transform
.outputs
[output
].requests
++;
3353 IMFTopologyNode_Release(upstream_node
);
3358 if (SUCCEEDED(hr
= IMFTopologyNode_GetOutput(node
, output
, &downstream_node
, &downstream_input
)))
3360 sample
= LIST_ENTRY(list_head(&topo_node
->u
.transform
.outputs
[output
].samples
), struct sample
, entry
);
3361 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample
->sample
);
3362 transform_release_sample(sample
);
3363 IMFTopologyNode_Release(downstream_node
);
3368 case MF_TOPOLOGY_TEE_NODE
:
3369 FIXME("Unhandled upstream node type %d.\n", node_type
);
3377 static void session_request_sample(struct media_session
*session
, IMFStreamSink
*sink_stream
)
3379 struct topo_node
*sink_node
= NULL
, *node
;
3380 IMFTopologyNode
*upstream_node
;
3381 DWORD upstream_output
;
3384 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3386 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink_stream
)
3396 if (FAILED(hr
= IMFTopologyNode_GetInput(sink_node
->node
, 0, &upstream_node
, &upstream_output
)))
3398 WARN("Failed to get upstream node connection, hr %#lx.\n", hr
);
3402 sink_node
->u
.sink
.requests
++;
3403 if (FAILED(session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
3404 sink_node
->u
.sink
.requests
--;
3405 IMFTopologyNode_Release(upstream_node
);
3408 static void session_deliver_sample(struct media_session
*session
, IMFMediaStream
*stream
, const PROPVARIANT
*value
)
3410 struct topo_node
*source_node
= NULL
, *node
;
3411 IMFTopologyNode
*downstream_node
;
3412 DWORD downstream_input
;
3415 if (value
&& (value
->vt
!= VT_UNKNOWN
|| !value
->punkVal
))
3417 WARN("Unexpected value type %d.\n", value
->vt
);
3421 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3423 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->object
.source_stream
== stream
)
3434 source_node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3436 if (FAILED(hr
= IMFTopologyNode_GetOutput(source_node
->node
, 0, &downstream_node
, &downstream_input
)))
3438 WARN("Failed to get downstream node connection, hr %#lx.\n", hr
);
3442 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, value
? (IMFSample
*)value
->punkVal
: NULL
);
3443 IMFTopologyNode_Release(downstream_node
);
3446 static void session_sink_invalidated(struct media_session
*session
, IMFMediaEvent
*event
, IMFStreamSink
*sink
)
3448 struct topo_node
*node
, *sink_node
= NULL
;
3451 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3453 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink
)
3465 if (FAILED(hr
= MFCreateMediaEvent(MESinkInvalidated
, &GUID_NULL
, S_OK
, NULL
, &event
)))
3466 WARN("Failed to create event, hr %#lx.\n", hr
);
3472 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_OUTPUT_NODE
, sink_node
->node_id
);
3473 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3475 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3478 static BOOL
session_nodes_is_mask_set(struct media_session
*session
, MF_TOPOLOGY_TYPE node_type
, unsigned int flags
)
3480 struct media_source
*source
;
3481 struct topo_node
*node
;
3483 if (node_type
== MF_TOPOLOGY_MAX
)
3485 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3487 if ((source
->flags
& flags
) != flags
)
3493 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3495 if (node
->type
== node_type
&& (node
->flags
& flags
) != flags
)
3503 static void session_nodes_unset_mask(struct media_session
*session
, MF_TOPOLOGY_TYPE node_type
, unsigned int flags
)
3505 struct media_source
*source
;
3506 struct topo_node
*node
;
3508 if (node_type
== MF_TOPOLOGY_MAX
)
3510 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3512 source
->flags
&= ~flags
;
3517 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3519 if (node
->type
== node_type
)
3521 node
->flags
&= ~flags
;
3527 static void session_raise_end_of_presentation(struct media_session
*session
)
3529 if (!(session_nodes_is_mask_set(session
, MF_TOPOLOGY_SOURCESTREAM_NODE
, TOPO_NODE_END_OF_STREAM
)))
3532 if (!(session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
))
3534 if (session_nodes_is_mask_set(session
, MF_TOPOLOGY_MAX
, SOURCE_FLAG_END_OF_PRESENTATION
))
3536 session
->presentation
.flags
|= SESSION_FLAG_END_OF_PRESENTATION
| SESSION_FLAG_PENDING_COMMAND
;
3537 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MEEndOfPresentation
, &GUID_NULL
, S_OK
, NULL
);
3542 static void session_handle_end_of_stream(struct media_session
*session
, IMFMediaStream
*stream
)
3544 struct topo_node
*node
;
3546 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream
, MF_TOPOLOGY_SOURCESTREAM_NODE
))
3547 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3552 session_deliver_sample(session
, stream
, NULL
);
3554 session_raise_end_of_presentation(session
);
3557 static void session_handle_end_of_presentation(struct media_session
*session
, IMFMediaSource
*object
)
3559 struct media_source
*source
;
3561 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3563 if (source
->source
== object
)
3565 if (!(source
->flags
& SOURCE_FLAG_END_OF_PRESENTATION
))
3567 source
->flags
|= SOURCE_FLAG_END_OF_PRESENTATION
;
3568 session_raise_end_of_presentation(session
);
3576 static void session_sink_stream_marker(struct media_session
*session
, IMFStreamSink
*stream_sink
)
3578 struct topo_node
*node
;
3580 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
))
3581 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3586 node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3588 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
&&
3589 session_nodes_is_mask_set(session
, MF_TOPOLOGY_OUTPUT_NODE
, TOPO_NODE_END_OF_STREAM
))
3591 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3592 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
3593 session_stop(session
);
3597 static void session_sink_stream_scrub_complete(struct media_session
*session
, IMFStreamSink
*stream_sink
)
3599 struct topo_node
*node
;
3601 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
))
3602 || node
->flags
& TOPO_NODE_SCRUB_SAMPLE_COMPLETE
)
3607 node
->flags
|= TOPO_NODE_SCRUB_SAMPLE_COMPLETE
;
3609 /* Scrubbing event is not limited to the started state transition, or even the started state.
3610 Events are processed and forwarded at any point after transition from initial idle state. */
3611 if (session
->presentation
.flags
& SESSION_FLAG_SOURCES_SUBSCRIBED
&&
3612 session_nodes_is_mask_set(session
, MF_TOPOLOGY_OUTPUT_NODE
, TOPO_NODE_SCRUB_SAMPLE_COMPLETE
))
3614 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionScrubSampleComplete
, &GUID_NULL
, S_OK
, NULL
);
3615 session_nodes_unset_mask(session
, MF_TOPOLOGY_OUTPUT_NODE
, TOPO_NODE_SCRUB_SAMPLE_COMPLETE
);
3619 static HRESULT WINAPI
session_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3621 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
3622 IMFMediaEventGenerator
*event_source
;
3623 IMFMediaEvent
*event
= NULL
;
3624 MediaEventType event_type
;
3625 IUnknown
*object
= NULL
;
3626 IMFMediaSource
*source
;
3627 IMFMediaStream
*stream
;
3631 if (FAILED(hr
= IMFAsyncResult_GetState(result
, (IUnknown
**)&event_source
)))
3634 if (FAILED(hr
= IMFMediaEventGenerator_EndGetEvent(event_source
, result
, &event
)))
3636 WARN("Failed to get event from %p, hr %#lx.\n", event_source
, hr
);
3640 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
3642 WARN("Failed to get event type, hr %#lx.\n", hr
);
3646 value
.vt
= VT_EMPTY
;
3647 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
3649 WARN("Failed to get event value, hr %#lx.\n", hr
);
3655 case MESourceSeeked
:
3656 case MEStreamSeeked
:
3657 FIXME("Source/stream seeking, semi-stub!\n");
3659 case MESourceStarted
:
3660 case MESourcePaused
:
3661 case MESourceStopped
:
3662 case MEStreamStarted
:
3663 case MEStreamPaused
:
3664 case MEStreamStopped
:
3666 EnterCriticalSection(&session
->cs
);
3667 session_set_source_object_state(session
, (IUnknown
*)event_source
, event_type
);
3668 LeaveCriticalSection(&session
->cs
);
3672 case MESourceRateChanged
:
3674 EnterCriticalSection(&session
->cs
);
3675 session_complete_rate_change(session
);
3676 LeaveCriticalSection(&session
->cs
);
3680 case MEBufferingStarted
:
3681 case MEBufferingStopped
:
3683 EnterCriticalSection(&session
->cs
);
3684 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3686 if (event_type
== MEBufferingStarted
)
3687 IMFPresentationClock_Pause(session
->clock
);
3689 IMFPresentationClock_Start(session
->clock
, PRESENTATION_CURRENT_POSITION
);
3691 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3693 LeaveCriticalSection(&session
->cs
);
3696 case MEReconnectStart
:
3697 case MEReconnectEnd
:
3699 EnterCriticalSection(&session
->cs
);
3700 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3701 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3702 LeaveCriticalSection(&session
->cs
);
3705 case MEExtendedType
:
3706 case MERendererEvent
:
3707 case MEStreamSinkFormatChanged
:
3709 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3713 stream
= (IMFMediaStream
*)value
.punkVal
;
3715 if (value
.vt
!= VT_UNKNOWN
|| !stream
)
3717 WARN("Unexpected event value.\n");
3721 if (FAILED(hr
= IMFMediaStream_GetMediaSource(stream
, &source
)))
3724 EnterCriticalSection(&session
->cs
);
3725 if (SUCCEEDED(hr
= session_add_media_stream(session
, source
, stream
)))
3726 hr
= IMFMediaStream_BeginGetEvent(stream
, &session
->events_callback
, (IUnknown
*)stream
);
3727 LeaveCriticalSection(&session
->cs
);
3729 IMFMediaSource_Release(source
);
3732 case MEStreamSinkStarted
:
3733 case MEStreamSinkPaused
:
3734 case MEStreamSinkStopped
:
3735 case MEStreamSinkPrerolled
:
3737 EnterCriticalSection(&session
->cs
);
3738 session_set_sink_stream_state(session
, (IMFStreamSink
*)event_source
, event_type
);
3739 LeaveCriticalSection(&session
->cs
);
3742 case MEStreamSinkMarker
:
3744 EnterCriticalSection(&session
->cs
);
3745 session_sink_stream_marker(session
, (IMFStreamSink
*)event_source
);
3746 LeaveCriticalSection(&session
->cs
);
3749 case MEStreamSinkRequestSample
:
3751 EnterCriticalSection(&session
->cs
);
3752 session_request_sample(session
, (IMFStreamSink
*)event_source
);
3753 LeaveCriticalSection(&session
->cs
);
3756 case MEStreamSinkScrubSampleComplete
:
3758 EnterCriticalSection(&session
->cs
);
3759 session_sink_stream_scrub_complete(session
, (IMFStreamSink
*)event_source
);
3760 LeaveCriticalSection(&session
->cs
);
3764 EnterCriticalSection(&session
->cs
);
3765 session_deliver_sample(session
, (IMFMediaStream
*)event_source
, &value
);
3766 LeaveCriticalSection(&session
->cs
);
3771 EnterCriticalSection(&session
->cs
);
3772 session_handle_end_of_stream(session
, (IMFMediaStream
*)event_source
);
3773 LeaveCriticalSection(&session
->cs
);
3777 case MEEndOfPresentation
:
3779 EnterCriticalSection(&session
->cs
);
3780 session_handle_end_of_presentation(session
, (IMFMediaSource
*)event_source
);
3781 LeaveCriticalSection(&session
->cs
);
3784 case MEAudioSessionGroupingParamChanged
:
3785 case MEAudioSessionIconChanged
:
3786 case MEAudioSessionNameChanged
:
3787 case MEAudioSessionVolumeChanged
:
3789 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3792 case MEAudioSessionDeviceRemoved
:
3793 case MEAudioSessionDisconnected
:
3794 case MEAudioSessionExclusiveModeOverride
:
3795 case MEAudioSessionFormatChanged
:
3796 case MEAudioSessionServerShutdown
:
3798 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3800 case MESinkInvalidated
:
3802 EnterCriticalSection(&session
->cs
);
3803 session_sink_invalidated(session
, event_type
== MESinkInvalidated
? event
: NULL
,
3804 (IMFStreamSink
*)event_source
);
3805 LeaveCriticalSection(&session
->cs
);
3808 case MEQualityNotify
:
3810 if (session
->quality_manager
)
3812 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFStreamSink
, (void **)&object
)))
3813 IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFTransform
, (void **)&object
);
3817 IMFQualityManager_NotifyQualityEvent(session
->quality_manager
, object
, event
);
3818 IUnknown_Release(object
);
3827 PropVariantClear(&value
);
3831 IMFMediaEvent_Release(event
);
3833 if (FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(event_source
, iface
, (IUnknown
*)event_source
)))
3834 WARN("Failed to re-subscribe, hr %#lx.\n", hr
);
3836 IMFMediaEventGenerator_Release(event_source
);
3841 static const IMFAsyncCallbackVtbl session_events_callback_vtbl
=
3843 session_events_callback_QueryInterface
,
3844 session_events_callback_AddRef
,
3845 session_events_callback_Release
,
3846 session_events_callback_GetParameters
,
3847 session_events_callback_Invoke
,
3850 static HRESULT WINAPI
session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
3852 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
3853 IsEqualIID(riid
, &IID_IUnknown
))
3856 IMFAsyncCallback_AddRef(iface
);
3860 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3862 return E_NOINTERFACE
;
3865 static ULONG WINAPI
session_sink_finalizer_callback_AddRef(IMFAsyncCallback
*iface
)
3867 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3868 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3871 static ULONG WINAPI
session_sink_finalizer_callback_Release(IMFAsyncCallback
*iface
)
3873 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3874 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3877 static HRESULT WINAPI
session_sink_finalizer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
3882 static HRESULT WINAPI
session_sink_finalizer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3884 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3885 IMFFinalizableMediaSink
*fin_sink
= NULL
;
3886 BOOL sinks_finalized
= TRUE
;
3887 struct media_sink
*sink
;
3891 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
3894 EnterCriticalSection(&session
->cs
);
3896 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3898 if (state
== sink
->object
)
3900 if (FAILED(hr
= IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
3901 WARN("Unexpected, missing IMFFinalizableMediaSink, hr %#lx.\n", hr
);
3905 sinks_finalized
&= sink
->finalized
;
3906 if (!sinks_finalized
)
3911 IUnknown_Release(state
);
3915 /* Complete session transition, or close prematurely on error. */
3916 if (SUCCEEDED(hr
= IMFFinalizableMediaSink_EndFinalize(fin_sink
, result
)))
3918 sink
->finalized
= TRUE
;
3919 if (sinks_finalized
)
3920 session_set_closed(session
, hr
);
3922 IMFFinalizableMediaSink_Release(fin_sink
);
3925 LeaveCriticalSection(&session
->cs
);
3930 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl
=
3932 session_sink_finalizer_callback_QueryInterface
,
3933 session_sink_finalizer_callback_AddRef
,
3934 session_sink_finalizer_callback_Release
,
3935 session_sink_finalizer_callback_GetParameters
,
3936 session_sink_finalizer_callback_Invoke
,
3939 static HRESULT WINAPI
session_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
3941 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3942 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3945 static ULONG WINAPI
session_rate_support_AddRef(IMFRateSupport
*iface
)
3947 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3948 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3951 static ULONG WINAPI
session_rate_support_Release(IMFRateSupport
*iface
)
3953 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3954 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3957 static HRESULT
session_presentation_object_get_rate(IUnknown
*object
, MFRATE_DIRECTION direction
,
3958 BOOL thin
, BOOL fastest
, float *result
)
3960 IMFRateSupport
*rate_support
;
3964 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3966 if (FAILED(hr
= MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
3968 if (direction
== MFRATE_FORWARD
)
3974 return MF_E_REVERSE_UNSUPPORTED
;
3980 if (SUCCEEDED(hr
= IMFRateSupport_GetFastestRate(rate_support
, direction
, thin
, &rate
)))
3981 *result
= min(fabsf(rate
), *result
);
3985 if (SUCCEEDED(hr
= IMFRateSupport_GetSlowestRate(rate_support
, direction
, thin
, &rate
)))
3986 *result
= max(fabsf(rate
), *result
);
3989 IMFRateSupport_Release(rate_support
);
3994 static HRESULT
session_get_presentation_rate(struct media_session
*session
, MFRATE_DIRECTION direction
,
3995 BOOL thin
, BOOL fastest
, float *result
)
3997 struct media_source
*source
;
3998 struct media_sink
*sink
;
3999 HRESULT hr
= E_POINTER
;
4002 rate
= fastest
? FLT_MAX
: 0.0f
;
4004 EnterCriticalSection(&session
->cs
);
4006 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
4008 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
4010 if (FAILED(hr
= session_presentation_object_get_rate(source
->object
, direction
, thin
, fastest
, &rate
)))
4016 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
4018 if (FAILED(hr
= session_presentation_object_get_rate(sink
->object
, direction
, thin
, fastest
, &rate
)))
4024 LeaveCriticalSection(&session
->cs
);
4027 *result
= direction
== MFRATE_FORWARD
? rate
: -rate
;
4032 static HRESULT WINAPI
session_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
4033 BOOL thin
, float *rate
)
4035 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
4037 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
4039 return session_get_presentation_rate(session
, direction
, thin
, FALSE
, rate
);
4042 static HRESULT WINAPI
session_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
4043 BOOL thin
, float *rate
)
4045 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
4047 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
4049 return session_get_presentation_rate(session
, direction
, thin
, TRUE
, rate
);
4052 static HRESULT WINAPI
session_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
4053 float *nearest_supported_rate
)
4055 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
4058 TRACE("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_supported_rate
);
4060 EnterCriticalSection(&session
->cs
);
4061 hr
= session_is_presentation_rate_supported(session
, thin
, rate
, nearest_supported_rate
);
4062 LeaveCriticalSection(&session
->cs
);
4067 static const IMFRateSupportVtbl session_rate_support_vtbl
=
4069 session_rate_support_QueryInterface
,
4070 session_rate_support_AddRef
,
4071 session_rate_support_Release
,
4072 session_rate_support_GetSlowestRate
,
4073 session_rate_support_GetFastestRate
,
4074 session_rate_support_IsRateSupported
,
4077 static HRESULT WINAPI
session_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
4079 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
4080 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
4083 static ULONG WINAPI
session_rate_control_AddRef(IMFRateControl
*iface
)
4085 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
4086 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
4089 static ULONG WINAPI
session_rate_control_Release(IMFRateControl
*iface
)
4091 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
4092 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
4095 static HRESULT WINAPI
session_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
4097 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
4098 struct session_op
*op
;
4101 TRACE("%p, %d, %f.\n", iface
, thin
, rate
);
4103 if (FAILED(hr
= create_session_op(SESSION_CMD_SET_RATE
, &op
)))
4106 op
->set_rate
.thin
= thin
;
4107 op
->set_rate
.rate
= rate
;
4108 hr
= session_submit_command(session
, op
);
4109 IUnknown_Release(&op
->IUnknown_iface
);
4113 static HRESULT WINAPI
session_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
4115 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
4117 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
4119 return IMFRateControl_GetRate(session
->clock_rate_control
, thin
, rate
);
4122 static const IMFRateControlVtbl session_rate_control_vtbl
=
4124 session_rate_control_QueryInterface
,
4125 session_rate_control_AddRef
,
4126 session_rate_control_Release
,
4127 session_rate_control_SetRate
,
4128 session_rate_control_GetRate
,
4131 static HRESULT WINAPI
node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor
*iface
,
4132 REFIID riid
, void **obj
)
4134 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
4136 if (IsEqualIID(riid
, &IID_IMFTopologyNodeAttributeEditor
) ||
4137 IsEqualIID(riid
, &IID_IUnknown
))
4140 IMFTopologyNodeAttributeEditor_AddRef(iface
);
4144 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
4146 return E_NOINTERFACE
;
4149 static ULONG WINAPI
node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor
*iface
)
4151 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
4152 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
4155 static ULONG WINAPI
node_attribute_editor_Release(IMFTopologyNodeAttributeEditor
*iface
)
4157 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
4158 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
4161 static HRESULT WINAPI
node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor
*iface
,
4162 TOPOID id
, DWORD count
, MFTOPONODE_ATTRIBUTE_UPDATE
*updates
)
4164 FIXME("%p, %s, %lu, %p.\n", iface
, wine_dbgstr_longlong(id
), count
, updates
);
4169 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl
=
4171 node_attribute_editor_QueryInterface
,
4172 node_attribute_editor_AddRef
,
4173 node_attribute_editor_Release
,
4174 node_attribute_editor_UpdateNodeAttributes
,
4177 /***********************************************************************
4178 * MFCreateMediaSession (mf.@)
4180 HRESULT WINAPI
MFCreateMediaSession(IMFAttributes
*config
, IMFMediaSession
**session
)
4182 BOOL without_quality_manager
= FALSE
;
4183 struct media_session
*object
;
4186 TRACE("%p, %p.\n", config
, session
);
4188 if (!(object
= calloc(1, sizeof(*object
))))
4189 return E_OUTOFMEMORY
;
4191 object
->IMFMediaSession_iface
.lpVtbl
= &mfmediasessionvtbl
;
4192 object
->IMFGetService_iface
.lpVtbl
= &session_get_service_vtbl
;
4193 object
->IMFRateSupport_iface
.lpVtbl
= &session_rate_support_vtbl
;
4194 object
->IMFRateControl_iface
.lpVtbl
= &session_rate_control_vtbl
;
4195 object
->IMFTopologyNodeAttributeEditor_iface
.lpVtbl
= &node_attribute_editor_vtbl
;
4196 object
->commands_callback
.lpVtbl
= &session_commands_callback_vtbl
;
4197 object
->sa_ready_callback
.lpVtbl
= &session_sa_ready_callback_vtbl
;
4198 object
->events_callback
.lpVtbl
= &session_events_callback_vtbl
;
4199 object
->sink_finalizer_callback
.lpVtbl
= &session_sink_finalizer_callback_vtbl
;
4200 object
->refcount
= 1;
4201 list_init(&object
->topologies
);
4202 list_init(&object
->commands
);
4203 list_init(&object
->presentation
.sources
);
4204 list_init(&object
->presentation
.sinks
);
4205 list_init(&object
->presentation
.nodes
);
4206 InitializeCriticalSection(&object
->cs
);
4208 if (FAILED(hr
= MFCreateTopology(&object
->presentation
.current_topology
)))
4211 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
4214 if (FAILED(hr
= MFCreatePresentationClock(&object
->clock
)))
4217 if (FAILED(hr
= MFCreateSystemTimeSource(&object
->system_time_source
)))
4220 if (FAILED(hr
= IMFPresentationClock_QueryInterface(object
->clock
, &IID_IMFRateControl
,
4221 (void **)&object
->clock_rate_control
)))
4230 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_TOPOLOADER
, &clsid
)))
4232 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTopoLoader
,
4233 (void **)&object
->topo_loader
)))
4235 WARN("Failed to create custom topology loader, hr %#lx.\n", hr
);
4239 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_QUALITY_MANAGER
, &clsid
)))
4241 if (!(without_quality_manager
= IsEqualGUID(&clsid
, &GUID_NULL
)))
4243 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFQualityManager
,
4244 (void **)&object
->quality_manager
)))
4246 WARN("Failed to create custom quality manager, hr %#lx.\n", hr
);
4252 if (!object
->topo_loader
&& FAILED(hr
= MFCreateTopoLoader(&object
->topo_loader
)))
4255 if (!object
->quality_manager
&& !without_quality_manager
&&
4256 FAILED(hr
= MFCreateStandardQualityManager(&object
->quality_manager
)))
4261 if (object
->quality_manager
&& FAILED(hr
= IMFQualityManager_NotifyPresentationClock(object
->quality_manager
,
4267 *session
= &object
->IMFMediaSession_iface
;
4272 IMFMediaSession_Release(&object
->IMFMediaSession_iface
);