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
;
804 LIST_FOR_EACH_ENTRY_SAFE(source
, source2
, &session
->presentation
.sources
, struct media_source
, entry
)
806 list_remove(&source
->entry
);
808 IMFMediaSource_Release(source
->source
);
810 IMFPresentationDescriptor_Release(source
->pd
);
814 LIST_FOR_EACH_ENTRY_SAFE(node
, node2
, &session
->presentation
.nodes
, struct topo_node
, entry
)
816 list_remove(&node
->entry
);
817 release_topo_node(node
);
820 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &session
->presentation
.sinks
, struct media_sink
, entry
)
822 list_remove(&sink
->entry
);
825 IMFMediaSink_Release(sink
->sink
);
827 IMFMediaSinkPreroll_Release(sink
->preroll
);
828 if (sink
->event_generator
)
829 IMFMediaEventGenerator_Release(sink
->event_generator
);
834 static struct topo_node
*session_get_node_by_id(const struct media_session
*session
, TOPOID id
)
836 struct topo_node
*node
;
838 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
840 if (node
->node_id
== id
)
847 static void session_command_complete(struct media_session
*session
)
849 struct session_op
*op
;
852 session
->presentation
.flags
&= ~SESSION_FLAG_PENDING_COMMAND
;
854 /* Submit next command. */
855 if ((e
= list_head(&session
->commands
)))
857 op
= LIST_ENTRY(e
, struct session_op
, entry
);
858 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
862 static void session_command_complete_with_event(struct media_session
*session
, MediaEventType event
,
863 HRESULT status
, const PROPVARIANT
*param
)
865 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, event
, &GUID_NULL
, status
, param
);
866 session_command_complete(session
);
869 static HRESULT
session_subscribe_sources(struct media_session
*session
)
871 struct media_source
*source
;
874 if (session
->presentation
.flags
& SESSION_FLAG_SOURCES_SUBSCRIBED
)
877 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
879 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(source
->source
, &session
->events_callback
,
882 WARN("Failed to subscribe to source events, hr %#lx.\n", hr
);
887 session
->presentation
.flags
|= SESSION_FLAG_SOURCES_SUBSCRIBED
;
891 static void session_start(struct media_session
*session
, const GUID
*time_format
, const PROPVARIANT
*start_position
)
893 struct media_source
*source
;
896 switch (session
->state
)
898 case SESSION_STATE_STOPPED
:
900 /* Start request with no current topology. */
901 if (session
->presentation
.topo_status
== MF_TOPOSTATUS_INVALID
)
903 session_command_complete_with_event(session
, MESessionStarted
, MF_E_INVALIDREQUEST
, NULL
);
908 case SESSION_STATE_PAUSED
:
910 session
->presentation
.time_format
= *time_format
;
911 session
->presentation
.start_position
.vt
= VT_EMPTY
;
912 PropVariantCopy(&session
->presentation
.start_position
, start_position
);
914 if (FAILED(hr
= session_subscribe_sources(session
)))
916 session_command_complete_with_event(session
, MESessionStarted
, hr
, NULL
);
920 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
922 if (FAILED(hr
= IMFMediaSource_Start(source
->source
, source
->pd
, &GUID_NULL
, start_position
)))
923 WARN("Failed to start media source %p, hr %#lx.\n", source
->source
, hr
);
926 session
->state
= SESSION_STATE_STARTING_SOURCES
;
928 case SESSION_STATE_STARTED
:
929 FIXME("Seeking is not implemented.\n");
930 session_command_complete(session
);
933 session_command_complete_with_event(session
, MESessionStarted
, MF_E_INVALIDREQUEST
, NULL
);
938 static void session_set_started(struct media_session
*session
)
940 struct media_source
*source
;
941 IMFMediaEvent
*event
;
945 session
->state
= SESSION_STATE_STARTED
;
947 caps
= session
->caps
| MFSESSIONCAP_PAUSE
;
949 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
951 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &flags
)))
953 if (!(flags
& MFMEDIASOURCE_CAN_PAUSE
))
955 caps
&= ~MFSESSIONCAP_PAUSE
;
961 session_set_caps(session
, caps
);
963 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted
, &GUID_NULL
, S_OK
, NULL
, &event
)))
965 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
966 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
967 IMFMediaEvent_Release(event
);
969 session_command_complete(session
);
972 static void session_set_paused(struct media_session
*session
, unsigned int state
, HRESULT status
)
974 /* Failed event status could indicate a failure during normal transition to paused state,
975 or an attempt to pause from invalid initial state. To finalize failed transition in the former case,
976 state is still forced to PAUSED, otherwise previous state is retained. */
977 if (state
!= ~0u) session
->state
= state
;
978 if (SUCCEEDED(status
))
979 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
980 session_command_complete_with_event(session
, MESessionPaused
, status
, NULL
);
983 static void session_set_closed(struct media_session
*session
, HRESULT status
)
985 session
->state
= SESSION_STATE_CLOSED
;
986 if (SUCCEEDED(status
))
987 session_set_caps(session
, session
->caps
& ~(MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
));
988 session_command_complete_with_event(session
, MESessionClosed
, status
, NULL
);
991 static void session_pause(struct media_session
*session
)
993 unsigned int state
= ~0u;
996 switch (session
->state
)
998 case SESSION_STATE_STARTED
:
1000 /* Transition in two steps - pause the clock, wait for sinks, then pause sources. */
1001 if (SUCCEEDED(hr
= IMFPresentationClock_Pause(session
->clock
)))
1002 session
->state
= SESSION_STATE_PAUSING_SINKS
;
1003 state
= SESSION_STATE_PAUSED
;
1007 case SESSION_STATE_STOPPED
:
1008 hr
= MF_E_SESSION_PAUSEWHILESTOPPED
;
1011 hr
= MF_E_INVALIDREQUEST
;
1015 session_set_paused(session
, state
, hr
);
1018 static void session_clear_end_of_presentation(struct media_session
*session
)
1020 struct media_source
*source
;
1021 struct topo_node
*node
;
1023 session
->presentation
.flags
&= ~SESSION_FLAG_END_OF_PRESENTATION
;
1024 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1026 source
->flags
&= ~SOURCE_FLAG_END_OF_PRESENTATION
;
1028 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1030 node
->flags
&= ~TOPO_NODE_END_OF_STREAM
;
1032 session
->presentation
.topo_status
= MF_TOPOSTATUS_READY
;
1035 static void session_set_stopped(struct media_session
*session
, HRESULT status
)
1037 MediaEventType event_type
;
1038 IMFMediaEvent
*event
;
1040 session
->state
= SESSION_STATE_STOPPED
;
1041 event_type
= session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
? MESessionEnded
: MESessionStopped
;
1043 if (SUCCEEDED(MFCreateMediaEvent(event_type
, &GUID_NULL
, status
, NULL
, &event
)))
1045 IMFMediaEvent_SetUINT64(event
, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME
, session
->presentation
.clock_stop_time
);
1046 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
1047 IMFMediaEvent_Release(event
);
1049 session_clear_end_of_presentation(session
);
1050 session_command_complete(session
);
1053 static void session_stop(struct media_session
*session
)
1055 HRESULT hr
= MF_E_INVALIDREQUEST
;
1057 switch (session
->state
)
1059 case SESSION_STATE_STARTED
:
1060 case SESSION_STATE_PAUSED
:
1062 /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */
1063 IMFPresentationClock_GetTime(session
->clock
, &session
->presentation
.clock_stop_time
);
1064 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1065 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1067 session_set_stopped(session
, hr
);
1070 case SESSION_STATE_STOPPED
:
1074 session_command_complete_with_event(session
, MESessionStopped
, hr
, NULL
);
1079 static HRESULT
session_finalize_sinks(struct media_session
*session
)
1081 IMFFinalizableMediaSink
*fin_sink
;
1082 BOOL sinks_finalized
= TRUE
;
1083 struct media_sink
*sink
;
1086 session
->presentation
.flags
&= ~SESSION_FLAG_FINALIZE_SINKS
;
1087 session
->state
= SESSION_STATE_FINALIZING_SINKS
;
1089 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1091 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
1093 hr
= IMFFinalizableMediaSink_BeginFinalize(fin_sink
, &session
->sink_finalizer_callback
,
1094 (IUnknown
*)fin_sink
);
1095 IMFFinalizableMediaSink_Release(fin_sink
);
1098 sinks_finalized
= FALSE
;
1101 sink
->finalized
= TRUE
;
1104 if (sinks_finalized
)
1105 session_set_closed(session
, hr
);
1110 static void session_close(struct media_session
*session
)
1114 switch (session
->state
)
1116 case SESSION_STATE_STOPPED
:
1117 hr
= session_finalize_sinks(session
);
1119 case SESSION_STATE_STARTED
:
1120 case SESSION_STATE_PAUSED
:
1121 session
->presentation
.flags
|= SESSION_FLAG_FINALIZE_SINKS
;
1122 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1123 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1126 hr
= MF_E_INVALIDREQUEST
;
1130 session_clear_queued_topologies(session
);
1132 session_set_closed(session
, hr
);
1135 static void session_clear_topologies(struct media_session
*session
)
1139 if (session
->state
== SESSION_STATE_CLOSED
)
1140 hr
= MF_E_INVALIDREQUEST
;
1142 session_clear_queued_topologies(session
);
1143 session_command_complete_with_event(session
, MESessionTopologiesCleared
, hr
, NULL
);
1146 static HRESULT
session_is_presentation_rate_supported(struct media_session
*session
, BOOL thin
, float rate
,
1147 float *nearest_rate
)
1149 IMFRateSupport
*rate_support
;
1150 struct media_source
*source
;
1151 struct media_sink
*sink
;
1152 float value
= 0.0f
, tmp
;
1156 if (!nearest_rate
) nearest_rate
= &tmp
;
1160 *nearest_rate
= 1.0f
;
1164 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
1166 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1168 if (FAILED(hr
= MFGetService(source
->object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
,
1169 (void **)&rate_support
)))
1176 if (FAILED(hr
= IMFRateSupport_IsRateSupported(rate_support
, thin
, rate
, &value
)))
1177 WARN("Source does not support rate %f, hr %#lx.\n", rate
, hr
);
1178 IMFRateSupport_Release(rate_support
);
1180 /* Only "first" source is considered. */
1186 /* For sinks only check if rate is supported, ignoring nearest values. */
1187 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1190 if (FAILED(hr
= IMFMediaSink_GetCharacteristics(sink
->sink
, &flags
)))
1193 if (flags
& MEDIASINK_RATELESS
)
1196 if (FAILED(MFGetService(sink
->object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
,
1197 (void **)&rate_support
)))
1200 hr
= IMFRateSupport_IsRateSupported(rate_support
, thin
, rate
, NULL
);
1201 IMFRateSupport_Release(rate_support
);
1204 WARN("Sink %p does not support rate %f, hr %#lx.\n", sink
->sink
, rate
, hr
);
1211 *nearest_rate
= value
;
1216 static void session_set_consumed_clock(IUnknown
*object
, IMFPresentationClock
*clock
)
1218 IMFClockConsumer
*consumer
;
1220 if (SUCCEEDED(IUnknown_QueryInterface(object
, &IID_IMFClockConsumer
, (void **)&consumer
)))
1222 IMFClockConsumer_SetPresentationClock(consumer
, clock
);
1223 IMFClockConsumer_Release(consumer
);
1227 static void session_set_presentation_clock(struct media_session
*session
)
1229 IMFPresentationTimeSource
*time_source
= NULL
;
1230 struct media_source
*source
;
1231 struct media_sink
*sink
;
1232 struct topo_node
*node
;
1235 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1237 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
1238 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_NOTIFY_START_OF_STREAM
, 0);
1241 if (!(session
->presentation
.flags
& SESSION_FLAG_PRESENTATION_CLOCK_SET
))
1243 /* Attempt to get time source from the sinks. */
1244 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1246 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFPresentationTimeSource
,
1247 (void **)&time_source
)))
1253 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, time_source
);
1254 IMFPresentationTimeSource_Release(time_source
);
1257 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, session
->system_time_source
);
1260 WARN("Failed to set time source, hr %#lx.\n", hr
);
1262 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1264 if (node
->type
!= MF_TOPOLOGY_OUTPUT_NODE
)
1267 if (FAILED(hr
= IMFStreamSink_BeginGetEvent(node
->object
.sink_stream
, &session
->events_callback
,
1268 node
->object
.object
)))
1270 WARN("Failed to subscribe to stream sink events, hr %#lx.\n", hr
);
1274 /* Set clock for all topology nodes. */
1275 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1277 session_set_consumed_clock(source
->object
, session
->clock
);
1280 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1282 if (sink
->event_generator
&& FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(sink
->event_generator
,
1283 &session
->events_callback
, (IUnknown
*)sink
->event_generator
)))
1285 WARN("Failed to subscribe to sink events, hr %#lx.\n", hr
);
1288 if (FAILED(hr
= IMFMediaSink_SetPresentationClock(sink
->sink
, session
->clock
)))
1289 WARN("Failed to set presentation clock for the sink, hr %#lx.\n", hr
);
1292 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1294 if (node
->type
!= MF_TOPOLOGY_TRANSFORM_NODE
)
1297 session_set_consumed_clock(node
->object
.object
, session
->clock
);
1300 session
->presentation
.flags
|= SESSION_FLAG_PRESENTATION_CLOCK_SET
;
1304 static void session_set_rate(struct media_session
*session
, BOOL thin
, float rate
)
1306 IMFRateControl
*rate_control
;
1307 struct media_source
*source
;
1308 float clock_rate
= 0.0f
;
1312 hr
= session_is_presentation_rate_supported(session
, thin
, rate
, NULL
);
1315 hr
= IMFRateControl_GetRate(session
->clock_rate_control
, NULL
, &clock_rate
);
1317 if (SUCCEEDED(hr
) && (rate
!= clock_rate
) && SUCCEEDED(hr
= session_subscribe_sources(session
)))
1319 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1321 if (SUCCEEDED(hr
= MFGetService(source
->object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateControl
,
1322 (void **)&rate_control
)))
1324 hr
= IMFRateControl_SetRate(rate_control
, thin
, rate
);
1325 IMFRateControl_Release(rate_control
);
1328 session
->presentation
.flags
|= SESSION_FLAG_PENDING_RATE_CHANGE
;
1329 session
->presentation
.rate
= rate
;
1339 param
.fltVal
= rate
;
1340 session_command_complete_with_event(session
, MESessionRateChanged
, hr
, SUCCEEDED(hr
) ? ¶m
: NULL
);
1343 static void session_complete_rate_change(struct media_session
*session
)
1348 if (!(session
->presentation
.flags
& SESSION_FLAG_PENDING_RATE_CHANGE
))
1351 session
->presentation
.flags
&= ~SESSION_FLAG_PENDING_RATE_CHANGE
;
1352 session_set_presentation_clock(session
);
1354 hr
= IMFRateControl_SetRate(session
->clock_rate_control
, session
->presentation
.thin
,
1355 session
->presentation
.rate
);
1358 param
.fltVal
= session
->presentation
.rate
;
1360 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionRateChanged
, &GUID_NULL
, hr
,
1361 SUCCEEDED(hr
) ? ¶m
: NULL
);
1362 session_command_complete(session
);
1365 static struct media_source
*session_get_media_source(struct media_session
*session
, IMFMediaSource
*source
)
1367 struct media_source
*cur
;
1369 LIST_FOR_EACH_ENTRY(cur
, &session
->presentation
.sources
, struct media_source
, entry
)
1371 if (source
== cur
->source
)
1378 static void session_release_media_source(struct media_source
*source
)
1380 IMFMediaSource_Release(source
->source
);
1382 IMFPresentationDescriptor_Release(source
->pd
);
1386 static HRESULT
session_add_media_source(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSource
*source
)
1388 struct media_source
*media_source
;
1391 if (session_get_media_source(session
, source
))
1394 if (!(media_source
= calloc(1, sizeof(*media_source
))))
1395 return E_OUTOFMEMORY
;
1397 media_source
->source
= source
;
1398 IMFMediaSource_AddRef(media_source
->source
);
1400 hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
, &IID_IMFPresentationDescriptor
,
1401 (void **)&media_source
->pd
);
1404 list_add_tail(&session
->presentation
.sources
, &media_source
->entry
);
1406 session_release_media_source(media_source
);
1411 static void session_raise_topology_set(struct media_session
*session
, IMFTopology
*topology
, HRESULT status
)
1415 param
.vt
= topology
? VT_UNKNOWN
: VT_EMPTY
;
1416 param
.punkVal
= (IUnknown
*)topology
;
1418 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologySet
, &GUID_NULL
, status
, ¶m
);
1421 static DWORD
session_get_object_rate_caps(IUnknown
*object
)
1423 IMFRateSupport
*rate_support
;
1427 if (SUCCEEDED(MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
1430 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_FORWARD
, TRUE
, &rate
)) && rate
!= 0.0f
)
1431 caps
|= MFSESSIONCAP_RATE_FORWARD
;
1434 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_REVERSE
, TRUE
, &rate
)) && rate
!= 0.0f
)
1435 caps
|= MFSESSIONCAP_RATE_REVERSE
;
1437 IMFRateSupport_Release(rate_support
);
1443 static HRESULT
session_add_media_sink(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSink
*sink
)
1445 struct media_sink
*media_sink
;
1446 unsigned int disable_preroll
= 0;
1449 LIST_FOR_EACH_ENTRY(media_sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1451 if (sink
== media_sink
->sink
)
1455 if (!(media_sink
= calloc(1, sizeof(*media_sink
))))
1456 return E_OUTOFMEMORY
;
1458 media_sink
->sink
= sink
;
1459 IMFMediaSink_AddRef(media_sink
->sink
);
1461 IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaEventGenerator
, (void **)&media_sink
->event_generator
);
1463 IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_DISABLE_PREROLL
, &disable_preroll
);
1464 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
, &flags
)) && flags
& MEDIASINK_CAN_PREROLL
&& !disable_preroll
)
1466 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaSinkPreroll
, (void **)&media_sink
->preroll
)))
1467 session
->presentation
.flags
|= SESSION_FLAG_NEEDS_PREROLL
;
1470 list_add_tail(&session
->presentation
.sinks
, &media_sink
->entry
);
1475 static DWORD
transform_node_get_stream_id(struct topo_node
*node
, BOOL output
, unsigned int index
)
1477 DWORD
*map
= output
? node
->u
.transform
.output_map
: node
->u
.transform
.input_map
;
1478 return map
? map
[index
] : index
;
1481 static HRESULT
session_set_transform_stream_info(struct topo_node
*node
)
1483 DWORD
*input_map
= NULL
, *output_map
= NULL
;
1484 DWORD i
, input_count
, output_count
;
1485 struct transform_stream
*streams
;
1486 unsigned int block_alignment
;
1487 IMFMediaType
*media_type
;
1488 UINT32 bytes_per_second
;
1492 hr
= IMFTransform_GetStreamCount(node
->object
.transform
, &input_count
, &output_count
);
1493 if (SUCCEEDED(hr
) && (input_count
> 1 || output_count
> 1))
1495 input_map
= calloc(input_count
, sizeof(*input_map
));
1496 output_map
= calloc(output_count
, sizeof(*output_map
));
1497 if (FAILED(IMFTransform_GetStreamIDs(node
->object
.transform
, input_count
, input_map
,
1498 output_count
, output_map
)))
1500 /* Assume sequential identifiers. */
1503 input_map
= output_map
= NULL
;
1509 node
->u
.transform
.input_map
= input_map
;
1510 node
->u
.transform
.output_map
= output_map
;
1512 streams
= calloc(input_count
, sizeof(*streams
));
1513 for (i
= 0; i
< input_count
; ++i
)
1514 list_init(&streams
[i
].samples
);
1515 node
->u
.transform
.inputs
= streams
;
1516 node
->u
.transform
.input_count
= input_count
;
1518 streams
= calloc(output_count
, sizeof(*streams
));
1519 for (i
= 0; i
< output_count
; ++i
)
1521 list_init(&streams
[i
].samples
);
1523 if (SUCCEEDED(IMFTransform_GetOutputCurrentType(node
->object
.transform
,
1524 transform_node_get_stream_id(node
, TRUE
, i
), &media_type
)))
1526 if (SUCCEEDED(IMFMediaType_GetMajorType(media_type
, &major
)) && IsEqualGUID(&major
, &MFMediaType_Audio
)
1527 && SUCCEEDED(IMFMediaType_GetUINT32(media_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &block_alignment
)))
1529 streams
[i
].min_buffer_size
= block_alignment
;
1530 if (SUCCEEDED(IMFMediaType_GetUINT32(media_type
, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND
, &bytes_per_second
)))
1531 streams
[i
].min_buffer_size
= max(streams
[i
].min_buffer_size
, bytes_per_second
);
1533 IMFMediaType_Release(media_type
);
1536 node
->u
.transform
.outputs
= streams
;
1537 node
->u
.transform
.output_count
= output_count
;
1543 static HRESULT
session_get_stream_sink_type(IMFStreamSink
*sink
, IMFMediaType
**media_type
)
1545 IMFMediaTypeHandler
*handler
;
1548 if (SUCCEEDED(hr
= IMFStreamSink_GetMediaTypeHandler(sink
, &handler
)))
1550 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, media_type
);
1551 IMFMediaTypeHandler_Release(handler
);
1557 static HRESULT WINAPI
node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify
*iface
,
1558 REFIID riid
, void **obj
)
1560 if (IsEqualIID(riid
, &IID_IMFVideoSampleAllocatorNotify
) ||
1561 IsEqualIID(riid
, &IID_IUnknown
))
1564 IMFVideoSampleAllocatorNotify_AddRef(iface
);
1569 return E_NOINTERFACE
;
1572 static ULONG WINAPI
node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify
*iface
)
1577 static ULONG WINAPI
node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify
*iface
)
1582 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
);
1584 static HRESULT WINAPI
node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify
*iface
)
1586 struct topo_node
*topo_node
= impl_node_from_IMFVideoSampleAllocatorNotify(iface
);
1587 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &topo_node
->session
->sa_ready_callback
, (IUnknown
*)iface
);
1591 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl
=
1593 node_sample_allocator_cb_QueryInterface
,
1594 node_sample_allocator_cb_AddRef
,
1595 node_sample_allocator_cb_Release
,
1596 node_sample_allocator_cb_NotifyRelease
,
1599 static HRESULT
session_append_node(struct media_session
*session
, IMFTopologyNode
*node
)
1601 struct topo_node
*topo_node
;
1602 IMFMediaSink
*media_sink
;
1603 IMFMediaType
*media_type
;
1604 IMFStreamDescriptor
*sd
;
1607 if (!(topo_node
= calloc(1, sizeof(*topo_node
))))
1608 return E_OUTOFMEMORY
;
1610 IMFTopologyNode_GetNodeType(node
, &topo_node
->type
);
1611 IMFTopologyNode_GetTopoNodeID(node
, &topo_node
->node_id
);
1612 topo_node
->node
= node
;
1613 IMFTopologyNode_AddRef(topo_node
->node
);
1614 topo_node
->session
= session
;
1616 switch (topo_node
->type
)
1618 case MF_TOPOLOGY_OUTPUT_NODE
:
1619 topo_node
->u
.sink
.notify_cb
.lpVtbl
= &node_sample_allocator_cb_vtbl
;
1621 if (FAILED(hr
= topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&topo_node
->object
.object
)))
1623 WARN("Failed to get stream sink interface, hr %#lx.\n", hr
);
1627 if (FAILED(hr
= IMFStreamSink_GetMediaSink(topo_node
->object
.sink_stream
, &media_sink
)))
1630 if (SUCCEEDED(hr
= session_add_media_sink(session
, node
, media_sink
)))
1632 if (SUCCEEDED(session_get_stream_sink_type(topo_node
->object
.sink_stream
, &media_type
)))
1634 if (SUCCEEDED(MFGetService(topo_node
->object
.object
, &MR_VIDEO_ACCELERATION_SERVICE
,
1635 &IID_IMFVideoSampleAllocator
, (void **)&topo_node
->u
.sink
.allocator
)))
1637 if (FAILED(hr
= IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node
->u
.sink
.allocator
,
1640 WARN("Failed to initialize sample allocator for the stream, hr %#lx.\n", hr
);
1642 IMFVideoSampleAllocator_QueryInterface(topo_node
->u
.sink
.allocator
,
1643 &IID_IMFVideoSampleAllocatorCallback
, (void **)&topo_node
->u
.sink
.allocator_cb
);
1644 IMFVideoSampleAllocatorCallback_SetCallback(topo_node
->u
.sink
.allocator_cb
,
1645 &topo_node
->u
.sink
.notify_cb
);
1647 IMFMediaType_Release(media_type
);
1650 IMFMediaSink_Release(media_sink
);
1653 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
1654 if (FAILED(IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_SOURCE
, &IID_IMFMediaSource
,
1655 (void **)&topo_node
->u
.source
.source
)))
1657 WARN("Missing MF_TOPONODE_SOURCE, hr %#lx.\n", hr
);
1661 if (FAILED(hr
= session_add_media_source(session
, node
, topo_node
->u
.source
.source
)))
1664 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
1665 &IID_IMFStreamDescriptor
, (void **)&sd
)))
1667 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#lx.\n", hr
);
1671 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &topo_node
->u
.source
.stream_id
);
1672 IMFStreamDescriptor_Release(sd
);
1675 case MF_TOPOLOGY_TRANSFORM_NODE
:
1677 if (SUCCEEDED(hr
= topology_node_get_object(node
, &IID_IMFTransform
, (void **)&topo_node
->object
.transform
)))
1679 hr
= session_set_transform_stream_info(topo_node
);
1682 WARN("Failed to get IMFTransform for MFT node, hr %#lx.\n", hr
);
1685 case MF_TOPOLOGY_TEE_NODE
:
1686 FIXME("Unsupported node type %d.\n", topo_node
->type
);
1694 list_add_tail(&session
->presentation
.nodes
, &topo_node
->entry
);
1696 release_topo_node(topo_node
);
1701 static HRESULT
session_collect_nodes(struct media_session
*session
)
1703 IMFTopology
*topology
= session
->presentation
.current_topology
;
1704 IMFTopologyNode
*node
;
1708 if (!list_empty(&session
->presentation
.nodes
))
1711 if (FAILED(hr
= IMFTopology_GetNodeCount(topology
, &count
)))
1714 for (i
= 0; i
< count
; ++i
)
1716 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
1718 WARN("Failed to get node %u.\n", i
);
1722 hr
= session_append_node(session
, node
);
1723 IMFTopologyNode_Release(node
);
1726 WARN("Failed to add node %u.\n", i
);
1734 static HRESULT
session_set_current_topology(struct media_session
*session
, IMFTopology
*topology
)
1736 struct media_source
*source
;
1737 DWORD caps
, object_flags
;
1738 struct media_sink
*sink
;
1739 struct topo_node
*node
;
1740 IMFMediaEvent
*event
;
1743 if (FAILED(hr
= IMFTopology_CloneFrom(session
->presentation
.current_topology
, topology
)))
1745 WARN("Failed to clone topology, hr %#lx.\n", hr
);
1749 session_collect_nodes(session
);
1751 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1753 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
1755 if (FAILED(hr
= IMFTransform_ProcessMessage(node
->object
.transform
,
1756 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING
, 0)))
1761 /* FIXME: attributes are all zero for now */
1762 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime
, &GUID_NULL
, S_OK
, NULL
, &event
)))
1764 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME
, 0);
1765 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
1766 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT
, 0);
1768 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
1769 IMFMediaEvent_Release(event
);
1772 /* Update session caps. */
1773 caps
= MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
| MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
|
1774 MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1776 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1782 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &object_flags
)))
1784 if (!(object_flags
& MFMEDIASOURCE_DOES_NOT_USE_NETWORK
))
1785 caps
&= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1786 if (!(object_flags
& MFMEDIASOURCE_CAN_SEEK
))
1787 caps
&= ~MFSESSIONCAP_SEEK
;
1790 /* Mask unsupported rate caps. */
1792 caps
&= session_get_object_rate_caps(source
->object
)
1793 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1796 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1802 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
->sink
, &object_flags
)))
1804 if (!(object_flags
& MEDIASINK_RATELESS
))
1805 caps
&= session_get_object_rate_caps(sink
->object
)
1806 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1810 session_set_caps(session
, caps
);
1815 static void session_set_topology(struct media_session
*session
, DWORD flags
, IMFTopology
*topology
)
1817 IMFTopology
*resolved_topology
= NULL
;
1820 /* Resolve unless claimed to be full. */
1821 if (!(flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
) && topology
)
1823 if (!(flags
& MFSESSION_SETTOPOLOGY_NORESOLUTION
))
1825 hr
= session_bind_output_nodes(topology
);
1828 hr
= IMFTopoLoader_Load(session
->topo_loader
, topology
, &resolved_topology
, NULL
/* FIXME? */);
1830 hr
= session_init_media_types(resolved_topology
);
1834 topology
= resolved_topology
;
1839 if (flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
)
1841 if ((topology
&& topology
== session
->presentation
.current_topology
) || !topology
)
1843 /* FIXME: stop current topology, queue next one. */
1844 session_clear_presentation(session
);
1851 else if (topology
&& flags
& MFSESSION_SETTOPOLOGY_IMMEDIATE
)
1853 session_clear_queued_topologies(session
);
1854 session_clear_presentation(session
);
1857 session_raise_topology_set(session
, topology
, hr
);
1859 /* With no current topology set it right away, otherwise queue. */
1862 struct queued_topology
*queued_topology
;
1864 if ((queued_topology
= calloc(1, sizeof(*queued_topology
))))
1866 queued_topology
->topology
= topology
;
1867 IMFTopology_AddRef(queued_topology
->topology
);
1869 list_add_tail(&session
->topologies
, &queued_topology
->entry
);
1872 if (session
->presentation
.topo_status
== MF_TOPOSTATUS_INVALID
)
1874 hr
= session_set_current_topology(session
, topology
);
1875 session_set_topo_status(session
, hr
, MF_TOPOSTATUS_READY
);
1876 if (session
->quality_manager
)
1877 IMFQualityManager_NotifyTopology(session
->quality_manager
, topology
);
1881 if (resolved_topology
)
1882 IMFTopology_Release(resolved_topology
);
1885 static HRESULT WINAPI
mfsession_QueryInterface(IMFMediaSession
*iface
, REFIID riid
, void **out
)
1887 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1889 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1893 if (IsEqualIID(riid
, &IID_IMFMediaSession
) ||
1894 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1895 IsEqualIID(riid
, &IID_IUnknown
))
1897 *out
= &session
->IMFMediaSession_iface
;
1899 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1901 *out
= &session
->IMFGetService_iface
;
1903 else if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1905 *out
= &session
->IMFRateSupport_iface
;
1907 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
1909 *out
= &session
->IMFRateControl_iface
;
1914 IMFMediaSession_AddRef(iface
);
1918 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1919 return E_NOINTERFACE
;
1922 static ULONG WINAPI
mfsession_AddRef(IMFMediaSession
*iface
)
1924 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1925 ULONG refcount
= InterlockedIncrement(&session
->refcount
);
1927 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1932 static ULONG WINAPI
mfsession_Release(IMFMediaSession
*iface
)
1934 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1935 ULONG refcount
= InterlockedDecrement(&session
->refcount
);
1937 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1941 session_clear_queued_topologies(session
);
1942 session_clear_presentation(session
);
1943 session_clear_command_list(session
);
1944 if (session
->presentation
.current_topology
)
1945 IMFTopology_Release(session
->presentation
.current_topology
);
1946 if (session
->event_queue
)
1947 IMFMediaEventQueue_Release(session
->event_queue
);
1949 IMFPresentationClock_Release(session
->clock
);
1950 if (session
->system_time_source
)
1951 IMFPresentationTimeSource_Release(session
->system_time_source
);
1952 if (session
->clock_rate_control
)
1953 IMFRateControl_Release(session
->clock_rate_control
);
1954 if (session
->topo_loader
)
1955 IMFTopoLoader_Release(session
->topo_loader
);
1956 if (session
->quality_manager
)
1957 IMFQualityManager_Release(session
->quality_manager
);
1958 DeleteCriticalSection(&session
->cs
);
1965 static HRESULT WINAPI
mfsession_GetEvent(IMFMediaSession
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1967 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1969 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
1971 return IMFMediaEventQueue_GetEvent(session
->event_queue
, flags
, event
);
1974 static HRESULT WINAPI
mfsession_BeginGetEvent(IMFMediaSession
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1976 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1978 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1980 return IMFMediaEventQueue_BeginGetEvent(session
->event_queue
, callback
, state
);
1983 static HRESULT WINAPI
mfsession_EndGetEvent(IMFMediaSession
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
1985 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1987 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1989 return IMFMediaEventQueue_EndGetEvent(session
->event_queue
, result
, event
);
1992 static HRESULT WINAPI
mfsession_QueueEvent(IMFMediaSession
*iface
, MediaEventType event_type
, REFGUID ext_type
,
1993 HRESULT hr
, const PROPVARIANT
*value
)
1995 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1997 TRACE("%p, %ld, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1999 return IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, event_type
, ext_type
, hr
, value
);
2002 static HRESULT
session_check_stream_descriptor(IMFPresentationDescriptor
*pd
, IMFStreamDescriptor
*sd
)
2004 IMFStreamDescriptor
*selected_sd
;
2009 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(pd
, &count
)))
2011 WARN("Failed to get stream descriptor count, hr %#lx.\n", hr
);
2012 return MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED
;
2015 for (i
= 0; i
< count
; ++i
)
2017 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd
, i
,
2018 &selected
, &selected_sd
)))
2020 WARN("Failed to get stream descriptor %lu, hr %#lx.\n", i
, hr
);
2021 return MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED
;
2023 IMFStreamDescriptor_Release(selected_sd
);
2025 if (selected_sd
== sd
)
2030 WARN("Presentation descriptor %p stream %p is not selected.\n", pd
, sd
);
2031 return MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED
;
2035 WARN("Failed to find stream descriptor %lu, hr %#lx.\n", i
, hr
);
2036 return MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED
;
2039 static HRESULT
session_check_topology(IMFTopology
*topology
)
2041 MF_TOPOLOGY_TYPE node_type
;
2042 IMFTopologyNode
*node
;
2049 if (FAILED(IMFTopology_GetNodeCount(topology
, &node_count
))
2051 return E_INVALIDARG
;
2053 for (i
= 0; i
< node_count
; ++i
)
2055 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
2058 if (FAILED(hr
= IMFTopologyNode_GetNodeType(node
, &node_type
)))
2060 IMFTopologyNode_Release(node
);
2066 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
2068 IMFPresentationDescriptor
*pd
;
2069 IMFStreamDescriptor
*sd
;
2070 IMFMediaSource
*source
;
2072 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_SOURCE
, &IID_IMFMediaSource
,
2075 WARN("Missing MF_TOPONODE_SOURCE, hr %#lx.\n", hr
);
2076 IMFTopologyNode_Release(node
);
2077 return MF_E_TOPO_MISSING_SOURCE
;
2079 IMFMediaSource_Release(source
);
2081 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
,
2082 &IID_IMFPresentationDescriptor
, (void **)&pd
)))
2084 WARN("Missing MF_TOPONODE_PRESENTATION_DESCRIPTOR, hr %#lx.\n", hr
);
2085 IMFTopologyNode_Release(node
);
2086 return MF_E_TOPO_MISSING_PRESENTATION_DESCRIPTOR
;
2089 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
2090 &IID_IMFStreamDescriptor
, (void **)&sd
)))
2092 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#lx.\n", hr
);
2093 IMFPresentationDescriptor_Release(pd
);
2094 IMFTopologyNode_Release(node
);
2095 return MF_E_TOPO_MISSING_STREAM_DESCRIPTOR
;
2098 hr
= session_check_stream_descriptor(pd
, sd
);
2099 IMFPresentationDescriptor_Release(pd
);
2100 IMFStreamDescriptor_Release(sd
);
2103 IMFTopologyNode_Release(node
);
2114 IMFTopologyNode_Release(node
);
2120 static HRESULT WINAPI
mfsession_SetTopology(IMFMediaSession
*iface
, DWORD flags
, IMFTopology
*topology
)
2122 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2123 struct session_op
*op
;
2126 TRACE("%p, %#lx, %p.\n", iface
, flags
, topology
);
2128 if (FAILED(hr
= session_check_topology(topology
)))
2131 if (FAILED(hr
= create_session_op(SESSION_CMD_SET_TOPOLOGY
, &op
)))
2134 op
->set_topology
.flags
= flags
;
2135 op
->set_topology
.topology
= topology
;
2136 if (op
->set_topology
.topology
)
2137 IMFTopology_AddRef(op
->set_topology
.topology
);
2139 hr
= session_submit_command(session
, op
);
2140 IUnknown_Release(&op
->IUnknown_iface
);
2145 static HRESULT WINAPI
mfsession_ClearTopologies(IMFMediaSession
*iface
)
2147 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2149 TRACE("%p.\n", iface
);
2151 return session_submit_simple_command(session
, SESSION_CMD_CLEAR_TOPOLOGIES
);
2154 static HRESULT WINAPI
mfsession_Start(IMFMediaSession
*iface
, const GUID
*format
, const PROPVARIANT
*start_position
)
2156 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2157 struct session_op
*op
;
2160 TRACE("%p, %s, %s.\n", iface
, debugstr_guid(format
), debugstr_propvar(start_position
));
2162 if (!start_position
)
2165 if (FAILED(hr
= create_session_op(SESSION_CMD_START
, &op
)))
2168 op
->start
.time_format
= format
? *format
: GUID_NULL
;
2169 hr
= PropVariantCopy(&op
->start
.start_position
, start_position
);
2172 hr
= session_submit_command(session
, op
);
2174 IUnknown_Release(&op
->IUnknown_iface
);
2178 static HRESULT WINAPI
mfsession_Pause(IMFMediaSession
*iface
)
2180 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2182 TRACE("%p.\n", iface
);
2184 return session_submit_simple_command(session
, SESSION_CMD_PAUSE
);
2187 static HRESULT WINAPI
mfsession_Stop(IMFMediaSession
*iface
)
2189 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2191 TRACE("%p.\n", iface
);
2193 return session_submit_simple_command(session
, SESSION_CMD_STOP
);
2196 static HRESULT WINAPI
mfsession_Close(IMFMediaSession
*iface
)
2198 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2200 TRACE("%p.\n", iface
);
2202 return session_submit_simple_command(session
, SESSION_CMD_CLOSE
);
2205 static HRESULT WINAPI
mfsession_Shutdown(IMFMediaSession
*iface
)
2207 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2210 TRACE("%p.\n", iface
);
2212 EnterCriticalSection(&session
->cs
);
2213 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
2215 session
->state
= SESSION_STATE_SHUT_DOWN
;
2216 IMFMediaEventQueue_Shutdown(session
->event_queue
);
2217 if (session
->quality_manager
)
2218 IMFQualityManager_Shutdown(session
->quality_manager
);
2219 MFShutdownObject((IUnknown
*)session
->clock
);
2220 IMFPresentationClock_Release(session
->clock
);
2221 session
->clock
= NULL
;
2222 session_clear_presentation(session
);
2223 session_submit_simple_command(session
, SESSION_CMD_SHUTDOWN
);
2225 LeaveCriticalSection(&session
->cs
);
2230 static HRESULT WINAPI
mfsession_GetClock(IMFMediaSession
*iface
, IMFClock
**clock
)
2232 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2235 TRACE("%p, %p.\n", iface
, clock
);
2237 EnterCriticalSection(&session
->cs
);
2238 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
2240 *clock
= (IMFClock
*)session
->clock
;
2241 IMFClock_AddRef(*clock
);
2243 LeaveCriticalSection(&session
->cs
);
2248 static HRESULT WINAPI
mfsession_GetSessionCapabilities(IMFMediaSession
*iface
, DWORD
*caps
)
2250 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2253 TRACE("%p, %p.\n", iface
, caps
);
2258 EnterCriticalSection(&session
->cs
);
2259 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
2260 *caps
= session
->caps
;
2261 LeaveCriticalSection(&session
->cs
);
2266 static HRESULT WINAPI
mfsession_GetFullTopology(IMFMediaSession
*iface
, DWORD flags
, TOPOID id
, IMFTopology
**topology
)
2268 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
2269 struct queued_topology
*queued
;
2273 TRACE("%p, %#lx, %s, %p.\n", iface
, flags
, wine_dbgstr_longlong(id
), topology
);
2277 EnterCriticalSection(&session
->cs
);
2279 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
2281 if (flags
& MFSESSION_GETFULLTOPOLOGY_CURRENT
)
2283 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
2284 *topology
= session
->presentation
.current_topology
;
2286 hr
= MF_E_INVALIDREQUEST
;
2290 LIST_FOR_EACH_ENTRY(queued
, &session
->topologies
, struct queued_topology
, entry
)
2292 if (SUCCEEDED(IMFTopology_GetTopologyID(queued
->topology
, &topo_id
)) && topo_id
== id
)
2294 *topology
= queued
->topology
;
2301 IMFTopology_AddRef(*topology
);
2304 LeaveCriticalSection(&session
->cs
);
2309 static const IMFMediaSessionVtbl mfmediasessionvtbl
=
2311 mfsession_QueryInterface
,
2315 mfsession_BeginGetEvent
,
2316 mfsession_EndGetEvent
,
2317 mfsession_QueueEvent
,
2318 mfsession_SetTopology
,
2319 mfsession_ClearTopologies
,
2326 mfsession_GetSessionCapabilities
,
2327 mfsession_GetFullTopology
,
2330 static HRESULT WINAPI
session_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
2332 struct media_session
*session
= impl_from_IMFGetService(iface
);
2333 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
2336 static ULONG WINAPI
session_get_service_AddRef(IMFGetService
*iface
)
2338 struct media_session
*session
= impl_from_IMFGetService(iface
);
2339 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2342 static ULONG WINAPI
session_get_service_Release(IMFGetService
*iface
)
2344 struct media_session
*session
= impl_from_IMFGetService(iface
);
2345 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2348 typedef BOOL (*p_renderer_node_test_func
)(IMFMediaSink
*sink
);
2350 static BOOL
session_video_renderer_test_func(IMFMediaSink
*sink
)
2355 /* Use first sink to support IMFVideoRenderer. */
2356 hr
= IMFMediaSink_QueryInterface(sink
, &IID_IMFVideoRenderer
, (void **)&obj
);
2358 IUnknown_Release(obj
);
2363 static BOOL
session_audio_renderer_test_func(IMFMediaSink
*sink
)
2365 return mf_is_sar_sink(sink
);
2368 static HRESULT
session_get_renderer_node_service(struct media_session
*session
,
2369 p_renderer_node_test_func node_test_func
, REFGUID service
, REFIID riid
, void **obj
)
2371 HRESULT hr
= E_NOINTERFACE
;
2372 IMFStreamSink
*stream_sink
;
2373 IMFTopologyNode
*node
;
2374 IMFCollection
*nodes
;
2378 if (session
->presentation
.current_topology
)
2380 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session
->presentation
.current_topology
,
2383 while (IMFCollection_GetElement(nodes
, i
++, (IUnknown
**)&node
) == S_OK
)
2385 if (SUCCEEDED(topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
2387 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink
, &sink
)))
2389 if (node_test_func(sink
))
2391 if (FAILED(hr
= MFGetService((IUnknown
*)sink
, service
, riid
, obj
)))
2392 WARN("Failed to get service from renderer node, %#lx.\n", hr
);
2395 IMFStreamSink_Release(stream_sink
);
2398 IMFTopologyNode_Release(node
);
2404 IMFCollection_Release(nodes
);
2411 static HRESULT
session_get_audio_render_service(struct media_session
*session
, REFGUID service
,
2412 REFIID riid
, void **obj
)
2414 return session_get_renderer_node_service(session
, session_audio_renderer_test_func
,
2415 service
, riid
, obj
);
2418 static HRESULT
session_get_video_render_service(struct media_session
*session
, REFGUID service
,
2419 REFIID riid
, void **obj
)
2421 return session_get_renderer_node_service(session
, session_video_renderer_test_func
,
2422 service
, riid
, obj
);
2425 static HRESULT WINAPI
session_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
2427 struct media_session
*session
= impl_from_IMFGetService(iface
);
2430 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
2434 EnterCriticalSection(&session
->cs
);
2435 if (FAILED(hr
= session_is_shut_down(session
)))
2438 else if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
2440 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
2442 *obj
= &session
->IMFRateSupport_iface
;
2444 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
2446 *obj
= &session
->IMFRateControl_iface
;
2452 IUnknown_AddRef((IUnknown
*)*obj
);
2454 else if (IsEqualGUID(service
, &MF_LOCAL_MFT_REGISTRATION_SERVICE
))
2456 hr
= IMFLocalMFTRegistration_QueryInterface(&local_mft_registration
, riid
, obj
);
2458 else if (IsEqualGUID(service
, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE
))
2460 *obj
= &session
->IMFTopologyNodeAttributeEditor_iface
;
2461 IUnknown_AddRef((IUnknown
*)*obj
);
2463 else if (IsEqualGUID(service
, &MR_VIDEO_RENDER_SERVICE
))
2465 hr
= session_get_video_render_service(session
, service
, riid
, obj
);
2467 else if (IsEqualGUID(service
, &MR_POLICY_VOLUME_SERVICE
) ||
2468 IsEqualGUID(service
, &MR_STREAM_VOLUME_SERVICE
))
2470 hr
= session_get_audio_render_service(session
, service
, riid
, obj
);
2473 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
2475 LeaveCriticalSection(&session
->cs
);
2480 static const IMFGetServiceVtbl session_get_service_vtbl
=
2482 session_get_service_QueryInterface
,
2483 session_get_service_AddRef
,
2484 session_get_service_Release
,
2485 session_get_service_GetService
,
2488 static HRESULT WINAPI
session_commands_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2490 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2491 IsEqualIID(riid
, &IID_IUnknown
))
2494 IMFAsyncCallback_AddRef(iface
);
2498 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2500 return E_NOINTERFACE
;
2503 static ULONG WINAPI
session_commands_callback_AddRef(IMFAsyncCallback
*iface
)
2505 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2506 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2509 static ULONG WINAPI
session_commands_callback_Release(IMFAsyncCallback
*iface
)
2511 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2512 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2515 static HRESULT WINAPI
session_commands_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2520 static void session_deliver_pending_samples(struct media_session
*session
, IMFTopologyNode
*node
);
2522 static HRESULT WINAPI
session_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
2524 struct session_op
*op
= impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result
));
2525 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2527 TRACE("session %p, op %p, command %u.\n", session
, op
, op
->command
);
2529 EnterCriticalSection(&session
->cs
);
2531 if (session
->presentation
.flags
& SESSION_FLAG_PENDING_COMMAND
)
2533 WARN("session %p command is in progress, waiting for it to complete.\n", session
);
2534 LeaveCriticalSection(&session
->cs
);
2538 list_remove(&op
->entry
);
2539 session
->presentation
.flags
|= SESSION_FLAG_PENDING_COMMAND
;
2541 switch (op
->command
)
2543 case SESSION_CMD_CLEAR_TOPOLOGIES
:
2544 session_clear_topologies(session
);
2546 case SESSION_CMD_SET_TOPOLOGY
:
2547 session_set_topology(session
, op
->set_topology
.flags
, op
->set_topology
.topology
);
2548 session_command_complete(session
);
2550 case SESSION_CMD_START
:
2551 session_start(session
, &op
->start
.time_format
, &op
->start
.start_position
);
2553 case SESSION_CMD_PAUSE
:
2554 session_pause(session
);
2556 case SESSION_CMD_STOP
:
2557 session_stop(session
);
2559 case SESSION_CMD_CLOSE
:
2560 session_close(session
);
2562 case SESSION_CMD_SET_RATE
:
2563 session_set_rate(session
, op
->set_rate
.thin
, op
->set_rate
.rate
);
2565 case SESSION_CMD_SHUTDOWN
:
2566 session_clear_command_list(session
);
2567 session_command_complete(session
);
2573 LeaveCriticalSection(&session
->cs
);
2575 IUnknown_Release(&op
->IUnknown_iface
);
2580 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl
=
2582 session_commands_callback_QueryInterface
,
2583 session_commands_callback_AddRef
,
2584 session_commands_callback_Release
,
2585 session_commands_callback_GetParameters
,
2586 session_commands_callback_Invoke
,
2589 static HRESULT WINAPI
session_sa_ready_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2591 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
)
2592 || IsEqualIID(riid
, &IID_IUnknown
))
2595 IMFAsyncCallback_AddRef(iface
);
2599 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2601 return E_NOINTERFACE
;
2604 static ULONG WINAPI
session_sa_ready_callback_AddRef(IMFAsyncCallback
*iface
)
2606 struct media_session
*session
= impl_from_sa_ready_callback_IMFAsyncCallback(iface
);
2607 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2610 static ULONG WINAPI
session_sa_ready_callback_Release(IMFAsyncCallback
*iface
)
2612 struct media_session
*session
= impl_from_sa_ready_callback_IMFAsyncCallback(iface
);
2613 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2616 static HRESULT WINAPI
session_sa_ready_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2621 static HRESULT WINAPI
session_sa_ready_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
2623 IMFVideoSampleAllocatorNotify
*notify
= (IMFVideoSampleAllocatorNotify
*)IMFAsyncResult_GetStateNoAddRef(result
);
2624 struct topo_node
*topo_node
= impl_node_from_IMFVideoSampleAllocatorNotify(notify
);
2625 struct media_session
*session
= impl_from_sa_ready_callback_IMFAsyncCallback(iface
);
2626 IMFTopologyNode
*upstream_node
;
2627 DWORD upstream_output
;
2629 EnterCriticalSection(&session
->cs
);
2631 if (topo_node
->u
.sink
.requests
)
2633 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node
->node
, 0, &upstream_node
, &upstream_output
)))
2635 session_deliver_pending_samples(session
, upstream_node
);
2636 IMFTopologyNode_Release(upstream_node
);
2640 LeaveCriticalSection(&session
->cs
);
2645 static const IMFAsyncCallbackVtbl session_sa_ready_callback_vtbl
=
2647 session_sa_ready_callback_QueryInterface
,
2648 session_sa_ready_callback_AddRef
,
2649 session_sa_ready_callback_Release
,
2650 session_sa_ready_callback_GetParameters
,
2651 session_sa_ready_callback_Invoke
,
2654 static HRESULT WINAPI
session_events_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2656 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2657 IsEqualIID(riid
, &IID_IUnknown
))
2660 IMFAsyncCallback_AddRef(iface
);
2664 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2666 return E_NOINTERFACE
;
2669 static ULONG WINAPI
session_events_callback_AddRef(IMFAsyncCallback
*iface
)
2671 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2672 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2675 static ULONG WINAPI
session_events_callback_Release(IMFAsyncCallback
*iface
)
2677 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2678 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2681 static HRESULT WINAPI
session_events_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2686 static HRESULT
session_add_media_stream(struct media_session
*session
, IMFMediaSource
*source
, IMFMediaStream
*stream
)
2688 struct topo_node
*node
;
2689 IMFStreamDescriptor
*sd
;
2690 DWORD stream_id
= 0;
2693 if (FAILED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
2696 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &stream_id
);
2697 IMFStreamDescriptor_Release(sd
);
2701 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2703 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->u
.source
.source
== source
2704 && node
->u
.source
.stream_id
== stream_id
)
2706 if (node
->object
.source_stream
)
2708 WARN("Node already has stream set.\n");
2712 node
->object
.source_stream
= stream
;
2713 IMFMediaStream_AddRef(node
->object
.source_stream
);
2721 static BOOL
session_is_source_nodes_state(struct media_session
*session
, enum object_state state
)
2723 struct media_source
*source
;
2724 struct topo_node
*node
;
2726 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2728 if (source
->state
!= state
)
2732 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2734 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->state
!= state
)
2741 static BOOL
session_is_output_nodes_state(struct media_session
*session
, enum object_state state
)
2743 struct topo_node
*node
;
2745 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2747 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->state
!= state
)
2754 static enum object_state
session_get_object_state_for_event(MediaEventType event
)
2758 case MESourceSeeked
:
2759 case MEStreamSeeked
:
2760 case MESourceStarted
:
2761 case MEStreamStarted
:
2762 case MEStreamSinkStarted
:
2763 return OBJ_STATE_STARTED
;
2764 case MESourcePaused
:
2765 case MEStreamPaused
:
2766 case MEStreamSinkPaused
:
2767 return OBJ_STATE_PAUSED
;
2768 case MESourceStopped
:
2769 case MEStreamStopped
:
2770 case MEStreamSinkStopped
:
2771 return OBJ_STATE_STOPPED
;
2772 case MEStreamSinkPrerolled
:
2773 return OBJ_STATE_PREROLLED
;
2775 return OBJ_STATE_INVALID
;
2779 static HRESULT
session_start_clock(struct media_session
*session
)
2781 LONGLONG start_offset
= 0;
2784 if (IsEqualGUID(&session
->presentation
.time_format
, &GUID_NULL
))
2786 if (session
->presentation
.start_position
.vt
== VT_EMPTY
)
2787 start_offset
= PRESENTATION_CURRENT_POSITION
;
2788 else if (session
->presentation
.start_position
.vt
== VT_I8
)
2789 start_offset
= session
->presentation
.start_position
.hVal
.QuadPart
;
2791 FIXME("Unhandled position type %d.\n", session
->presentation
.start_position
.vt
);
2794 FIXME("Unhandled time format %s.\n", debugstr_guid(&session
->presentation
.time_format
));
2796 if (FAILED(hr
= IMFPresentationClock_Start(session
->clock
, start_offset
)))
2797 WARN("Failed to start session clock, hr %#lx.\n", hr
);
2802 static struct topo_node
*session_get_node_object(struct media_session
*session
, IUnknown
*object
,
2803 MF_TOPOLOGY_TYPE node_type
)
2805 struct topo_node
*node
= NULL
;
2807 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2809 if (node
->type
== node_type
&& object
== node
->object
.object
)
2816 static BOOL
session_set_node_object_state(struct media_session
*session
, IUnknown
*object
,
2817 MF_TOPOLOGY_TYPE node_type
, enum object_state state
)
2819 struct topo_node
*node
;
2820 BOOL changed
= FALSE
;
2822 if ((node
= session_get_node_object(session
, object
, node_type
)))
2824 changed
= node
->state
!= state
;
2825 node
->state
= state
;
2831 static void session_set_source_object_state(struct media_session
*session
, IUnknown
*object
,
2832 MediaEventType event_type
)
2834 IMFStreamSink
*stream_sink
;
2835 struct media_source
*src
;
2836 struct media_sink
*sink
;
2837 enum object_state state
;
2838 struct topo_node
*node
;
2839 BOOL changed
= FALSE
;
2843 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2848 case MESourceSeeked
:
2849 case MESourceStarted
:
2850 case MESourcePaused
:
2851 case MESourceStopped
:
2853 LIST_FOR_EACH_ENTRY(src
, &session
->presentation
.sources
, struct media_source
, entry
)
2855 if (object
== src
->object
)
2857 changed
= src
->state
!= state
;
2863 case MEStreamSeeked
:
2864 case MEStreamStarted
:
2865 case MEStreamPaused
:
2866 case MEStreamStopped
:
2868 changed
= session_set_node_object_state(session
, object
, MF_TOPOLOGY_SOURCESTREAM_NODE
, state
);
2876 switch (session
->state
)
2878 case SESSION_STATE_STARTING_SOURCES
:
2879 if (!session_is_source_nodes_state(session
, OBJ_STATE_STARTED
))
2882 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_STARTED_SOURCE
);
2884 session_set_presentation_clock(session
);
2886 if (session
->presentation
.flags
& SESSION_FLAG_NEEDS_PREROLL
)
2888 MFTIME preroll_time
= 0;
2890 if (session
->presentation
.start_position
.vt
== VT_I8
)
2891 preroll_time
= session
->presentation
.start_position
.hVal
.QuadPart
;
2893 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2894 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2898 /* FIXME: abort and enter error state on failure. */
2899 if (FAILED(hr
= IMFMediaSinkPreroll_NotifyPreroll(sink
->preroll
, preroll_time
)))
2900 WARN("Preroll notification failed, hr %#lx.\n", hr
);
2904 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink
->sink
, &count
)))
2906 for (i
= 0; i
< count
; ++i
)
2908 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink
->sink
, i
, &stream_sink
)))
2910 session_set_node_object_state(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
,
2911 OBJ_STATE_PREROLLED
);
2912 IMFStreamSink_Release(stream_sink
);
2918 session
->state
= SESSION_STATE_PREROLLING_SINKS
;
2920 else if (SUCCEEDED(session_start_clock(session
)))
2921 session
->state
= SESSION_STATE_STARTING_SINKS
;
2924 case SESSION_STATE_PAUSING_SOURCES
:
2925 if (!session_is_source_nodes_state(session
, OBJ_STATE_PAUSED
))
2928 session_set_paused(session
, SESSION_STATE_PAUSED
, S_OK
);
2930 case SESSION_STATE_STOPPING_SOURCES
:
2931 if (!session_is_source_nodes_state(session
, OBJ_STATE_STOPPED
))
2934 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2938 case MF_TOPOLOGY_OUTPUT_NODE
:
2939 IMFStreamSink_Flush(node
->object
.sink_stream
);
2941 case MF_TOPOLOGY_TRANSFORM_NODE
:
2942 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
2949 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
2951 if (session
->presentation
.flags
& SESSION_FLAG_FINALIZE_SINKS
)
2952 session_finalize_sinks(session
);
2954 session_set_stopped(session
, S_OK
);
2962 static void session_set_sink_stream_state(struct media_session
*session
, IMFStreamSink
*stream
,
2963 MediaEventType event_type
)
2965 struct media_source
*source
;
2966 enum object_state state
;
2970 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2973 if (!(changed
= session_set_node_object_state(session
, (IUnknown
*)stream
, MF_TOPOLOGY_OUTPUT_NODE
, state
)))
2976 switch (session
->state
)
2978 case SESSION_STATE_PREROLLING_SINKS
:
2979 if (!session_is_output_nodes_state(session
, OBJ_STATE_PREROLLED
))
2982 if (SUCCEEDED(session_start_clock(session
)))
2983 session
->state
= SESSION_STATE_STARTING_SINKS
;
2985 case SESSION_STATE_STARTING_SINKS
:
2986 if (!session_is_output_nodes_state(session
, OBJ_STATE_STARTED
))
2989 session_set_started(session
);
2991 case SESSION_STATE_PAUSING_SINKS
:
2992 if (!session_is_output_nodes_state(session
, OBJ_STATE_PAUSED
))
2995 session
->state
= SESSION_STATE_PAUSING_SOURCES
;
2997 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2999 if (FAILED(hr
= IMFMediaSource_Pause(source
->source
)))
3004 session_set_paused(session
, SESSION_STATE_PAUSED
, hr
);
3007 case SESSION_STATE_STOPPING_SINKS
:
3008 if (!session_is_output_nodes_state(session
, OBJ_STATE_STOPPED
))
3011 session
->state
= SESSION_STATE_STOPPING_SOURCES
;
3013 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3015 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
)
3016 IMFMediaSource_Stop(source
->source
);
3017 else if (FAILED(hr
= IMFMediaSource_Stop(source
->source
)))
3021 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
|| FAILED(hr
))
3022 session_set_stopped(session
, hr
);
3030 static struct sample
*transform_create_sample(IMFSample
*sample
)
3032 struct sample
*sample_entry
= calloc(1, sizeof(*sample_entry
));
3036 sample_entry
->sample
= sample
;
3037 if (sample_entry
->sample
)
3038 IMFSample_AddRef(sample_entry
->sample
);
3041 return sample_entry
;
3044 static HRESULT
transform_get_external_output_sample(const struct media_session
*session
, struct topo_node
*transform
,
3045 unsigned int output_index
, const MFT_OUTPUT_STREAM_INFO
*stream_info
, IMFSample
**sample
)
3047 IMFTopologyNode
*downstream_node
;
3048 IMFMediaBuffer
*buffer
= NULL
;
3049 struct topo_node
*topo_node
;
3050 unsigned int buffer_size
;
3051 DWORD downstream_input
;
3055 if (FAILED(IMFTopologyNode_GetOutput(transform
->node
, output_index
, &downstream_node
, &downstream_input
)))
3057 WARN("Failed to get connected node for output %u.\n", output_index
);
3058 return MF_E_UNEXPECTED
;
3061 IMFTopologyNode_GetTopoNodeID(downstream_node
, &node_id
);
3062 IMFTopologyNode_Release(downstream_node
);
3064 topo_node
= session_get_node_by_id(session
, node_id
);
3066 if (topo_node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& topo_node
->u
.sink
.allocator
)
3068 hr
= IMFVideoSampleAllocator_AllocateSample(topo_node
->u
.sink
.allocator
, sample
);
3072 buffer_size
= max(stream_info
->cbSize
, transform
->u
.transform
.outputs
[output_index
].min_buffer_size
);
3074 hr
= MFCreateAlignedMemoryBuffer(buffer_size
, stream_info
->cbAlignment
, &buffer
);
3076 hr
= MFCreateSample(sample
);
3079 hr
= IMFSample_AddBuffer(*sample
, buffer
);
3082 IMFMediaBuffer_Release(buffer
);
3088 static HRESULT
transform_node_pull_samples(const struct media_session
*session
, struct topo_node
*node
)
3090 MFT_OUTPUT_STREAM_INFO stream_info
;
3091 MFT_OUTPUT_DATA_BUFFER
*buffers
;
3092 struct sample
*queued_sample
;
3093 HRESULT hr
= E_UNEXPECTED
;
3097 if (!(buffers
= calloc(node
->u
.transform
.output_count
, sizeof(*buffers
))))
3098 return E_OUTOFMEMORY
;
3100 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
3102 buffers
[i
].dwStreamID
= transform_node_get_stream_id(node
, TRUE
, i
);
3103 buffers
[i
].pSample
= NULL
;
3104 buffers
[i
].dwStatus
= 0;
3105 buffers
[i
].pEvents
= NULL
;
3107 memset(&stream_info
, 0, sizeof(stream_info
));
3108 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(node
->object
.transform
, buffers
[i
].dwStreamID
, &stream_info
)))
3111 if (!(stream_info
.dwFlags
& (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
| MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
)))
3113 if (FAILED(hr
= transform_get_external_output_sample(session
, node
, i
, &stream_info
, &buffers
[i
].pSample
)))
3119 hr
= IMFTransform_ProcessOutput(node
->object
.transform
, 0, node
->u
.transform
.output_count
, buffers
, &status
);
3121 /* Collect returned samples for all streams. */
3122 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
3124 if (buffers
[i
].pEvents
)
3125 IMFCollection_Release(buffers
[i
].pEvents
);
3127 if (SUCCEEDED(hr
) && !(buffers
[i
].dwStatus
& MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE
))
3129 if (session
->quality_manager
)
3130 IMFQualityManager_NotifyProcessOutput(session
->quality_manager
, node
->node
, i
, buffers
[i
].pSample
);
3132 queued_sample
= transform_create_sample(buffers
[i
].pSample
);
3133 list_add_tail(&node
->u
.transform
.outputs
[i
].samples
, &queued_sample
->entry
);
3136 if (buffers
[i
].pSample
)
3137 IMFSample_Release(buffers
[i
].pSample
);
3145 static void session_deliver_sample_to_node(struct media_session
*session
, IMFTopologyNode
*node
, unsigned int input
,
3148 struct sample
*sample_entry
, *sample_entry2
;
3149 DWORD stream_id
, downstream_input
;
3150 IMFTopologyNode
*downstream_node
;
3151 struct topo_node
*topo_node
;
3152 MF_TOPOLOGY_TYPE node_type
;
3158 if (session
->quality_manager
)
3159 IMFQualityManager_NotifyProcessInput(session
->quality_manager
, node
, input
, sample
);
3161 IMFTopologyNode_GetNodeType(node
, &node_type
);
3162 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
3164 topo_node
= session_get_node_by_id(session
, node_id
);
3168 case MF_TOPOLOGY_OUTPUT_NODE
:
3169 if (topo_node
->u
.sink
.requests
)
3173 if (FAILED(hr
= IMFStreamSink_ProcessSample(topo_node
->object
.sink_stream
, sample
)))
3174 WARN("Stream sink failed to process sample, hr %#lx.\n", hr
);
3176 else if (FAILED(hr
= IMFStreamSink_PlaceMarker(topo_node
->object
.sink_stream
, MFSTREAMSINK_MARKER_ENDOFSEGMENT
,
3179 WARN("Failed to place sink marker, hr %#lx.\n", hr
);
3181 topo_node
->u
.sink
.requests
--;
3184 case MF_TOPOLOGY_TRANSFORM_NODE
:
3186 transform_node_pull_samples(session
, topo_node
);
3188 sample_entry
= transform_create_sample(sample
);
3189 list_add_tail(&topo_node
->u
.transform
.inputs
[input
].samples
, &sample_entry
->entry
);
3191 for (i
= 0; i
< topo_node
->u
.transform
.input_count
; ++i
)
3193 stream_id
= transform_node_get_stream_id(topo_node
, FALSE
, i
);
3194 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.inputs
[i
].samples
,
3195 struct sample
, entry
)
3197 if (sample_entry
->sample
)
3199 if ((hr
= IMFTransform_ProcessInput(topo_node
->object
.transform
, stream_id
,
3200 sample_entry
->sample
, 0)) == MF_E_NOTACCEPTING
)
3203 WARN("Failed to process input for stream %u/%lu, hr %#lx.\n", i
, stream_id
, hr
);
3204 transform_release_sample(sample_entry
);
3208 transform_stream_drop_samples(&topo_node
->u
.transform
.inputs
[i
]);
3216 if (FAILED(hr
= IMFTransform_ProcessMessage(topo_node
->object
.transform
, MFT_MESSAGE_COMMAND_DRAIN
, 0)))
3217 WARN("Drain command failed for transform, hr %#lx.\n", hr
);
3220 transform_node_pull_samples(session
, topo_node
);
3222 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
3225 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
3227 if ((sample_entry
= transform_create_sample(NULL
)))
3228 list_add_tail(&topo_node
->u
.transform
.outputs
[i
].samples
, &sample_entry
->entry
);
3232 /* Push down all available output. */
3233 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
3235 if (FAILED(IMFTopologyNode_GetOutput(node
, i
, &downstream_node
, &downstream_input
)))
3237 WARN("Failed to get connected node for output %u.\n", i
);
3241 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.outputs
[i
].samples
,
3242 struct sample
, entry
)
3244 if (!topo_node
->u
.transform
.outputs
[i
].requests
)
3247 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample_entry
->sample
);
3248 topo_node
->u
.transform
.outputs
[i
].requests
--;
3250 transform_release_sample(sample_entry
);
3253 IMFTopologyNode_Release(downstream_node
);
3257 case MF_TOPOLOGY_TEE_NODE
:
3258 FIXME("Unhandled downstream node type %d.\n", node_type
);
3265 static void session_deliver_pending_samples(struct media_session
*session
, IMFTopologyNode
*node
)
3267 struct sample
*sample_entry
, *sample_entry2
;
3268 IMFTopologyNode
*downstream_node
;
3269 struct topo_node
*topo_node
;
3270 MF_TOPOLOGY_TYPE node_type
;
3271 DWORD downstream_input
;
3275 IMFTopologyNode_GetNodeType(node
, &node_type
);
3276 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
3278 topo_node
= session_get_node_by_id(session
, node_id
);
3282 case MF_TOPOLOGY_TRANSFORM_NODE
:
3284 transform_node_pull_samples(session
, topo_node
);
3286 /* Push down all available output. */
3287 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
3289 if (FAILED(IMFTopologyNode_GetOutput(node
, i
, &downstream_node
, &downstream_input
)))
3291 WARN("Failed to get connected node for output %u.\n", i
);
3295 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.outputs
[i
].samples
,
3296 struct sample
, entry
)
3298 if (!topo_node
->u
.transform
.outputs
[i
].requests
)
3301 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample_entry
->sample
);
3302 topo_node
->u
.transform
.outputs
[i
].requests
--;
3304 transform_release_sample(sample_entry
);
3307 IMFTopologyNode_Release(downstream_node
);
3311 FIXME("Unexpected node type %u.\n", node_type
);
3316 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
)
3318 IMFTopologyNode
*downstream_node
, *upstream_node
;
3319 DWORD downstream_input
, upstream_output
;
3320 struct topo_node
*topo_node
;
3321 MF_TOPOLOGY_TYPE node_type
;
3322 struct sample
*sample
;
3326 IMFTopologyNode_GetNodeType(node
, &node_type
);
3327 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
3329 topo_node
= session_get_node_by_id(session
, node_id
);
3333 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
3334 if (FAILED(hr
= IMFMediaStream_RequestSample(topo_node
->object
.source_stream
, NULL
)))
3335 WARN("Sample request failed, hr %#lx.\n", hr
);
3337 case MF_TOPOLOGY_TRANSFORM_NODE
:
3339 if (list_empty(&topo_node
->u
.transform
.outputs
[output
].samples
))
3341 /* Forward request to upstream node. */
3342 if (SUCCEEDED(hr
= IMFTopologyNode_GetInput(node
, 0 /* FIXME */, &upstream_node
, &upstream_output
)))
3344 if (SUCCEEDED(hr
= session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
3345 topo_node
->u
.transform
.outputs
[output
].requests
++;
3346 IMFTopologyNode_Release(upstream_node
);
3351 if (SUCCEEDED(hr
= IMFTopologyNode_GetOutput(node
, output
, &downstream_node
, &downstream_input
)))
3353 sample
= LIST_ENTRY(list_head(&topo_node
->u
.transform
.outputs
[output
].samples
), struct sample
, entry
);
3354 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample
->sample
);
3355 transform_release_sample(sample
);
3356 IMFTopologyNode_Release(downstream_node
);
3361 case MF_TOPOLOGY_TEE_NODE
:
3362 FIXME("Unhandled upstream node type %d.\n", node_type
);
3370 static void session_request_sample(struct media_session
*session
, IMFStreamSink
*sink_stream
)
3372 struct topo_node
*sink_node
= NULL
, *node
;
3373 IMFTopologyNode
*upstream_node
;
3374 DWORD upstream_output
;
3377 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3379 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink_stream
)
3389 if (FAILED(hr
= IMFTopologyNode_GetInput(sink_node
->node
, 0, &upstream_node
, &upstream_output
)))
3391 WARN("Failed to get upstream node connection, hr %#lx.\n", hr
);
3395 sink_node
->u
.sink
.requests
++;
3396 if (FAILED(session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
3397 sink_node
->u
.sink
.requests
--;
3398 IMFTopologyNode_Release(upstream_node
);
3401 static void session_deliver_sample(struct media_session
*session
, IMFMediaStream
*stream
, const PROPVARIANT
*value
)
3403 struct topo_node
*source_node
= NULL
, *node
;
3404 IMFTopologyNode
*downstream_node
;
3405 DWORD downstream_input
;
3408 if (value
&& (value
->vt
!= VT_UNKNOWN
|| !value
->punkVal
))
3410 WARN("Unexpected value type %d.\n", value
->vt
);
3414 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3416 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->object
.source_stream
== stream
)
3427 source_node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3429 if (FAILED(hr
= IMFTopologyNode_GetOutput(source_node
->node
, 0, &downstream_node
, &downstream_input
)))
3431 WARN("Failed to get downstream node connection, hr %#lx.\n", hr
);
3435 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, value
? (IMFSample
*)value
->punkVal
: NULL
);
3436 IMFTopologyNode_Release(downstream_node
);
3439 static void session_sink_invalidated(struct media_session
*session
, IMFMediaEvent
*event
, IMFStreamSink
*sink
)
3441 struct topo_node
*node
, *sink_node
= NULL
;
3444 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3446 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink
)
3458 if (FAILED(hr
= MFCreateMediaEvent(MESinkInvalidated
, &GUID_NULL
, S_OK
, NULL
, &event
)))
3459 WARN("Failed to create event, hr %#lx.\n", hr
);
3465 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_OUTPUT_NODE
, sink_node
->node_id
);
3466 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3468 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3471 static BOOL
session_nodes_is_mask_set(struct media_session
*session
, MF_TOPOLOGY_TYPE node_type
, unsigned int flags
)
3473 struct media_source
*source
;
3474 struct topo_node
*node
;
3476 if (node_type
== MF_TOPOLOGY_MAX
)
3478 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3480 if ((source
->flags
& flags
) != flags
)
3486 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3488 if (node
->type
== node_type
&& (node
->flags
& flags
) != flags
)
3496 static void session_nodes_unset_mask(struct media_session
*session
, MF_TOPOLOGY_TYPE node_type
, unsigned int flags
)
3498 struct media_source
*source
;
3499 struct topo_node
*node
;
3501 if (node_type
== MF_TOPOLOGY_MAX
)
3503 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3505 source
->flags
&= ~flags
;
3510 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3512 if (node
->type
== node_type
)
3514 node
->flags
&= ~flags
;
3520 static void session_raise_end_of_presentation(struct media_session
*session
)
3522 if (!(session_nodes_is_mask_set(session
, MF_TOPOLOGY_SOURCESTREAM_NODE
, TOPO_NODE_END_OF_STREAM
)))
3525 if (!(session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
))
3527 if (session_nodes_is_mask_set(session
, MF_TOPOLOGY_MAX
, SOURCE_FLAG_END_OF_PRESENTATION
))
3529 session
->presentation
.flags
|= SESSION_FLAG_END_OF_PRESENTATION
| SESSION_FLAG_PENDING_COMMAND
;
3530 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MEEndOfPresentation
, &GUID_NULL
, S_OK
, NULL
);
3535 static void session_handle_end_of_stream(struct media_session
*session
, IMFMediaStream
*stream
)
3537 struct topo_node
*node
;
3539 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream
, MF_TOPOLOGY_SOURCESTREAM_NODE
))
3540 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3545 session_deliver_sample(session
, stream
, NULL
);
3547 session_raise_end_of_presentation(session
);
3550 static void session_handle_end_of_presentation(struct media_session
*session
, IMFMediaSource
*object
)
3552 struct media_source
*source
;
3554 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3556 if (source
->source
== object
)
3558 if (!(source
->flags
& SOURCE_FLAG_END_OF_PRESENTATION
))
3560 source
->flags
|= SOURCE_FLAG_END_OF_PRESENTATION
;
3561 session_raise_end_of_presentation(session
);
3569 static void session_sink_stream_marker(struct media_session
*session
, IMFStreamSink
*stream_sink
)
3571 struct topo_node
*node
;
3573 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
))
3574 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3579 node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3581 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
&&
3582 session_nodes_is_mask_set(session
, MF_TOPOLOGY_OUTPUT_NODE
, TOPO_NODE_END_OF_STREAM
))
3584 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3585 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
3586 session_stop(session
);
3590 static void session_sink_stream_scrub_complete(struct media_session
*session
, IMFStreamSink
*stream_sink
)
3592 struct topo_node
*node
;
3594 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
))
3595 || node
->flags
& TOPO_NODE_SCRUB_SAMPLE_COMPLETE
)
3600 node
->flags
|= TOPO_NODE_SCRUB_SAMPLE_COMPLETE
;
3602 /* Scrubbing event is not limited to the started state transition, or even the started state.
3603 Events are processed and forwarded at any point after transition from initial idle state. */
3604 if (session
->presentation
.flags
& SESSION_FLAG_SOURCES_SUBSCRIBED
&&
3605 session_nodes_is_mask_set(session
, MF_TOPOLOGY_OUTPUT_NODE
, TOPO_NODE_SCRUB_SAMPLE_COMPLETE
))
3607 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionScrubSampleComplete
, &GUID_NULL
, S_OK
, NULL
);
3608 session_nodes_unset_mask(session
, MF_TOPOLOGY_OUTPUT_NODE
, TOPO_NODE_SCRUB_SAMPLE_COMPLETE
);
3612 static HRESULT WINAPI
session_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3614 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
3615 IMFMediaEventGenerator
*event_source
;
3616 IMFMediaEvent
*event
= NULL
;
3617 MediaEventType event_type
;
3618 IUnknown
*object
= NULL
;
3619 IMFMediaSource
*source
;
3620 IMFMediaStream
*stream
;
3624 if (FAILED(hr
= IMFAsyncResult_GetState(result
, (IUnknown
**)&event_source
)))
3627 if (FAILED(hr
= IMFMediaEventGenerator_EndGetEvent(event_source
, result
, &event
)))
3629 WARN("Failed to get event from %p, hr %#lx.\n", event_source
, hr
);
3633 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
3635 WARN("Failed to get event type, hr %#lx.\n", hr
);
3639 value
.vt
= VT_EMPTY
;
3640 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
3642 WARN("Failed to get event value, hr %#lx.\n", hr
);
3648 case MESourceSeeked
:
3649 case MEStreamSeeked
:
3650 FIXME("Source/stream seeking, semi-stub!\n");
3652 case MESourceStarted
:
3653 case MESourcePaused
:
3654 case MESourceStopped
:
3655 case MEStreamStarted
:
3656 case MEStreamPaused
:
3657 case MEStreamStopped
:
3659 EnterCriticalSection(&session
->cs
);
3660 session_set_source_object_state(session
, (IUnknown
*)event_source
, event_type
);
3661 LeaveCriticalSection(&session
->cs
);
3665 case MESourceRateChanged
:
3667 EnterCriticalSection(&session
->cs
);
3668 session_complete_rate_change(session
);
3669 LeaveCriticalSection(&session
->cs
);
3673 case MEBufferingStarted
:
3674 case MEBufferingStopped
:
3676 EnterCriticalSection(&session
->cs
);
3677 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3679 if (event_type
== MEBufferingStarted
)
3680 IMFPresentationClock_Pause(session
->clock
);
3682 IMFPresentationClock_Start(session
->clock
, PRESENTATION_CURRENT_POSITION
);
3684 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3686 LeaveCriticalSection(&session
->cs
);
3689 case MEReconnectStart
:
3690 case MEReconnectEnd
:
3692 EnterCriticalSection(&session
->cs
);
3693 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3694 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3695 LeaveCriticalSection(&session
->cs
);
3698 case MEExtendedType
:
3699 case MERendererEvent
:
3700 case MEStreamSinkFormatChanged
:
3702 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3706 stream
= (IMFMediaStream
*)value
.punkVal
;
3708 if (value
.vt
!= VT_UNKNOWN
|| !stream
)
3710 WARN("Unexpected event value.\n");
3714 if (FAILED(hr
= IMFMediaStream_GetMediaSource(stream
, &source
)))
3717 EnterCriticalSection(&session
->cs
);
3718 if (SUCCEEDED(hr
= session_add_media_stream(session
, source
, stream
)))
3719 hr
= IMFMediaStream_BeginGetEvent(stream
, &session
->events_callback
, (IUnknown
*)stream
);
3720 LeaveCriticalSection(&session
->cs
);
3722 IMFMediaSource_Release(source
);
3725 case MEStreamSinkStarted
:
3726 case MEStreamSinkPaused
:
3727 case MEStreamSinkStopped
:
3728 case MEStreamSinkPrerolled
:
3730 EnterCriticalSection(&session
->cs
);
3731 session_set_sink_stream_state(session
, (IMFStreamSink
*)event_source
, event_type
);
3732 LeaveCriticalSection(&session
->cs
);
3735 case MEStreamSinkMarker
:
3737 EnterCriticalSection(&session
->cs
);
3738 session_sink_stream_marker(session
, (IMFStreamSink
*)event_source
);
3739 LeaveCriticalSection(&session
->cs
);
3742 case MEStreamSinkRequestSample
:
3744 EnterCriticalSection(&session
->cs
);
3745 session_request_sample(session
, (IMFStreamSink
*)event_source
);
3746 LeaveCriticalSection(&session
->cs
);
3749 case MEStreamSinkScrubSampleComplete
:
3751 EnterCriticalSection(&session
->cs
);
3752 session_sink_stream_scrub_complete(session
, (IMFStreamSink
*)event_source
);
3753 LeaveCriticalSection(&session
->cs
);
3757 EnterCriticalSection(&session
->cs
);
3758 session_deliver_sample(session
, (IMFMediaStream
*)event_source
, &value
);
3759 LeaveCriticalSection(&session
->cs
);
3764 EnterCriticalSection(&session
->cs
);
3765 session_handle_end_of_stream(session
, (IMFMediaStream
*)event_source
);
3766 LeaveCriticalSection(&session
->cs
);
3770 case MEEndOfPresentation
:
3772 EnterCriticalSection(&session
->cs
);
3773 session_handle_end_of_presentation(session
, (IMFMediaSource
*)event_source
);
3774 LeaveCriticalSection(&session
->cs
);
3777 case MEAudioSessionGroupingParamChanged
:
3778 case MEAudioSessionIconChanged
:
3779 case MEAudioSessionNameChanged
:
3780 case MEAudioSessionVolumeChanged
:
3782 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3785 case MEAudioSessionDeviceRemoved
:
3786 case MEAudioSessionDisconnected
:
3787 case MEAudioSessionExclusiveModeOverride
:
3788 case MEAudioSessionFormatChanged
:
3789 case MEAudioSessionServerShutdown
:
3791 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3793 case MESinkInvalidated
:
3795 EnterCriticalSection(&session
->cs
);
3796 session_sink_invalidated(session
, event_type
== MESinkInvalidated
? event
: NULL
,
3797 (IMFStreamSink
*)event_source
);
3798 LeaveCriticalSection(&session
->cs
);
3801 case MEQualityNotify
:
3803 if (session
->quality_manager
)
3805 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFStreamSink
, (void **)&object
)))
3806 IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFTransform
, (void **)&object
);
3810 IMFQualityManager_NotifyQualityEvent(session
->quality_manager
, object
, event
);
3811 IUnknown_Release(object
);
3820 PropVariantClear(&value
);
3824 IMFMediaEvent_Release(event
);
3826 if (FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(event_source
, iface
, (IUnknown
*)event_source
)))
3827 WARN("Failed to re-subscribe, hr %#lx.\n", hr
);
3829 IMFMediaEventGenerator_Release(event_source
);
3834 static const IMFAsyncCallbackVtbl session_events_callback_vtbl
=
3836 session_events_callback_QueryInterface
,
3837 session_events_callback_AddRef
,
3838 session_events_callback_Release
,
3839 session_events_callback_GetParameters
,
3840 session_events_callback_Invoke
,
3843 static HRESULT WINAPI
session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
3845 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
3846 IsEqualIID(riid
, &IID_IUnknown
))
3849 IMFAsyncCallback_AddRef(iface
);
3853 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3855 return E_NOINTERFACE
;
3858 static ULONG WINAPI
session_sink_finalizer_callback_AddRef(IMFAsyncCallback
*iface
)
3860 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3861 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3864 static ULONG WINAPI
session_sink_finalizer_callback_Release(IMFAsyncCallback
*iface
)
3866 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3867 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3870 static HRESULT WINAPI
session_sink_finalizer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
3875 static HRESULT WINAPI
session_sink_finalizer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3877 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3878 IMFFinalizableMediaSink
*fin_sink
= NULL
;
3879 BOOL sinks_finalized
= TRUE
;
3880 struct media_sink
*sink
;
3884 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
3887 EnterCriticalSection(&session
->cs
);
3889 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3891 if (state
== sink
->object
)
3893 if (FAILED(hr
= IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
3894 WARN("Unexpected, missing IMFFinalizableMediaSink, hr %#lx.\n", hr
);
3898 sinks_finalized
&= sink
->finalized
;
3899 if (!sinks_finalized
)
3904 IUnknown_Release(state
);
3908 /* Complete session transition, or close prematurely on error. */
3909 if (SUCCEEDED(hr
= IMFFinalizableMediaSink_EndFinalize(fin_sink
, result
)))
3911 sink
->finalized
= TRUE
;
3912 if (sinks_finalized
)
3913 session_set_closed(session
, hr
);
3915 IMFFinalizableMediaSink_Release(fin_sink
);
3918 LeaveCriticalSection(&session
->cs
);
3923 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl
=
3925 session_sink_finalizer_callback_QueryInterface
,
3926 session_sink_finalizer_callback_AddRef
,
3927 session_sink_finalizer_callback_Release
,
3928 session_sink_finalizer_callback_GetParameters
,
3929 session_sink_finalizer_callback_Invoke
,
3932 static HRESULT WINAPI
session_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
3934 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3935 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3938 static ULONG WINAPI
session_rate_support_AddRef(IMFRateSupport
*iface
)
3940 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3941 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3944 static ULONG WINAPI
session_rate_support_Release(IMFRateSupport
*iface
)
3946 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3947 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3950 static HRESULT
session_presentation_object_get_rate(IUnknown
*object
, MFRATE_DIRECTION direction
,
3951 BOOL thin
, BOOL fastest
, float *result
)
3953 IMFRateSupport
*rate_support
;
3957 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3959 if (FAILED(hr
= MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
3961 if (direction
== MFRATE_FORWARD
)
3967 return MF_E_REVERSE_UNSUPPORTED
;
3973 if (SUCCEEDED(hr
= IMFRateSupport_GetFastestRate(rate_support
, direction
, thin
, &rate
)))
3974 *result
= min(fabsf(rate
), *result
);
3978 if (SUCCEEDED(hr
= IMFRateSupport_GetSlowestRate(rate_support
, direction
, thin
, &rate
)))
3979 *result
= max(fabsf(rate
), *result
);
3982 IMFRateSupport_Release(rate_support
);
3987 static HRESULT
session_get_presentation_rate(struct media_session
*session
, MFRATE_DIRECTION direction
,
3988 BOOL thin
, BOOL fastest
, float *result
)
3990 struct media_source
*source
;
3991 struct media_sink
*sink
;
3992 HRESULT hr
= E_POINTER
;
3995 rate
= fastest
? FLT_MAX
: 0.0f
;
3997 EnterCriticalSection(&session
->cs
);
3999 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
4001 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
4003 if (FAILED(hr
= session_presentation_object_get_rate(source
->object
, direction
, thin
, fastest
, &rate
)))
4009 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
4011 if (FAILED(hr
= session_presentation_object_get_rate(sink
->object
, direction
, thin
, fastest
, &rate
)))
4017 LeaveCriticalSection(&session
->cs
);
4020 *result
= direction
== MFRATE_FORWARD
? rate
: -rate
;
4025 static HRESULT WINAPI
session_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
4026 BOOL thin
, float *rate
)
4028 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
4030 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
4032 return session_get_presentation_rate(session
, direction
, thin
, FALSE
, rate
);
4035 static HRESULT WINAPI
session_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
4036 BOOL thin
, float *rate
)
4038 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
4040 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
4042 return session_get_presentation_rate(session
, direction
, thin
, TRUE
, rate
);
4045 static HRESULT WINAPI
session_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
4046 float *nearest_supported_rate
)
4048 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
4051 TRACE("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_supported_rate
);
4053 EnterCriticalSection(&session
->cs
);
4054 hr
= session_is_presentation_rate_supported(session
, thin
, rate
, nearest_supported_rate
);
4055 LeaveCriticalSection(&session
->cs
);
4060 static const IMFRateSupportVtbl session_rate_support_vtbl
=
4062 session_rate_support_QueryInterface
,
4063 session_rate_support_AddRef
,
4064 session_rate_support_Release
,
4065 session_rate_support_GetSlowestRate
,
4066 session_rate_support_GetFastestRate
,
4067 session_rate_support_IsRateSupported
,
4070 static HRESULT WINAPI
session_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
4072 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
4073 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
4076 static ULONG WINAPI
session_rate_control_AddRef(IMFRateControl
*iface
)
4078 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
4079 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
4082 static ULONG WINAPI
session_rate_control_Release(IMFRateControl
*iface
)
4084 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
4085 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
4088 static HRESULT WINAPI
session_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
4090 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
4091 struct session_op
*op
;
4094 TRACE("%p, %d, %f.\n", iface
, thin
, rate
);
4096 if (FAILED(hr
= create_session_op(SESSION_CMD_SET_RATE
, &op
)))
4099 op
->set_rate
.thin
= thin
;
4100 op
->set_rate
.rate
= rate
;
4101 hr
= session_submit_command(session
, op
);
4102 IUnknown_Release(&op
->IUnknown_iface
);
4106 static HRESULT WINAPI
session_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
4108 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
4110 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
4112 return IMFRateControl_GetRate(session
->clock_rate_control
, thin
, rate
);
4115 static const IMFRateControlVtbl session_rate_control_vtbl
=
4117 session_rate_control_QueryInterface
,
4118 session_rate_control_AddRef
,
4119 session_rate_control_Release
,
4120 session_rate_control_SetRate
,
4121 session_rate_control_GetRate
,
4124 static HRESULT WINAPI
node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor
*iface
,
4125 REFIID riid
, void **obj
)
4127 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
4129 if (IsEqualIID(riid
, &IID_IMFTopologyNodeAttributeEditor
) ||
4130 IsEqualIID(riid
, &IID_IUnknown
))
4133 IMFTopologyNodeAttributeEditor_AddRef(iface
);
4137 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
4139 return E_NOINTERFACE
;
4142 static ULONG WINAPI
node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor
*iface
)
4144 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
4145 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
4148 static ULONG WINAPI
node_attribute_editor_Release(IMFTopologyNodeAttributeEditor
*iface
)
4150 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
4151 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
4154 static HRESULT WINAPI
node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor
*iface
,
4155 TOPOID id
, DWORD count
, MFTOPONODE_ATTRIBUTE_UPDATE
*updates
)
4157 FIXME("%p, %s, %lu, %p.\n", iface
, wine_dbgstr_longlong(id
), count
, updates
);
4162 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl
=
4164 node_attribute_editor_QueryInterface
,
4165 node_attribute_editor_AddRef
,
4166 node_attribute_editor_Release
,
4167 node_attribute_editor_UpdateNodeAttributes
,
4170 /***********************************************************************
4171 * MFCreateMediaSession (mf.@)
4173 HRESULT WINAPI
MFCreateMediaSession(IMFAttributes
*config
, IMFMediaSession
**session
)
4175 BOOL without_quality_manager
= FALSE
;
4176 struct media_session
*object
;
4179 TRACE("%p, %p.\n", config
, session
);
4181 if (!(object
= calloc(1, sizeof(*object
))))
4182 return E_OUTOFMEMORY
;
4184 object
->IMFMediaSession_iface
.lpVtbl
= &mfmediasessionvtbl
;
4185 object
->IMFGetService_iface
.lpVtbl
= &session_get_service_vtbl
;
4186 object
->IMFRateSupport_iface
.lpVtbl
= &session_rate_support_vtbl
;
4187 object
->IMFRateControl_iface
.lpVtbl
= &session_rate_control_vtbl
;
4188 object
->IMFTopologyNodeAttributeEditor_iface
.lpVtbl
= &node_attribute_editor_vtbl
;
4189 object
->commands_callback
.lpVtbl
= &session_commands_callback_vtbl
;
4190 object
->sa_ready_callback
.lpVtbl
= &session_sa_ready_callback_vtbl
;
4191 object
->events_callback
.lpVtbl
= &session_events_callback_vtbl
;
4192 object
->sink_finalizer_callback
.lpVtbl
= &session_sink_finalizer_callback_vtbl
;
4193 object
->refcount
= 1;
4194 list_init(&object
->topologies
);
4195 list_init(&object
->commands
);
4196 list_init(&object
->presentation
.sources
);
4197 list_init(&object
->presentation
.sinks
);
4198 list_init(&object
->presentation
.nodes
);
4199 InitializeCriticalSection(&object
->cs
);
4201 if (FAILED(hr
= MFCreateTopology(&object
->presentation
.current_topology
)))
4204 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
4207 if (FAILED(hr
= MFCreatePresentationClock(&object
->clock
)))
4210 if (FAILED(hr
= MFCreateSystemTimeSource(&object
->system_time_source
)))
4213 if (FAILED(hr
= IMFPresentationClock_QueryInterface(object
->clock
, &IID_IMFRateControl
,
4214 (void **)&object
->clock_rate_control
)))
4223 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_TOPOLOADER
, &clsid
)))
4225 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTopoLoader
,
4226 (void **)&object
->topo_loader
)))
4228 WARN("Failed to create custom topology loader, hr %#lx.\n", hr
);
4232 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_QUALITY_MANAGER
, &clsid
)))
4234 if (!(without_quality_manager
= IsEqualGUID(&clsid
, &GUID_NULL
)))
4236 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFQualityManager
,
4237 (void **)&object
->quality_manager
)))
4239 WARN("Failed to create custom quality manager, hr %#lx.\n", hr
);
4245 if (!object
->topo_loader
&& FAILED(hr
= MFCreateTopoLoader(&object
->topo_loader
)))
4248 if (!object
->quality_manager
&& !without_quality_manager
&&
4249 FAILED(hr
= MFCreateStandardQualityManager(&object
->quality_manager
)))
4254 if (object
->quality_manager
&& FAILED(hr
= IMFQualityManager_NotifyPresentationClock(object
->quality_manager
,
4260 *session
= &object
->IMFMediaSession_iface
;
4265 IMFMediaSession_Release(&object
->IMFMediaSession_iface
);