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
,
49 /* Internally used commands. */
51 SESSION_CMD_QM_NOTIFY_TOPOLOGY
,
57 IUnknown IUnknown_iface
;
59 enum session_command command
;
65 IMFTopology
*topology
;
70 PROPVARIANT start_position
;
74 IMFTopology
*topology
;
84 struct queued_topology
87 IMFTopology
*topology
;
93 SESSION_STATE_STOPPED
= 0,
94 SESSION_STATE_STARTING_SOURCES
,
95 SESSION_STATE_PREROLLING_SINKS
,
96 SESSION_STATE_STARTING_SINKS
,
97 SESSION_STATE_STARTED
,
98 SESSION_STATE_PAUSING_SINKS
,
99 SESSION_STATE_PAUSING_SOURCES
,
100 SESSION_STATE_PAUSED
,
101 SESSION_STATE_STOPPING_SINKS
,
102 SESSION_STATE_STOPPING_SOURCES
,
103 SESSION_STATE_FINALIZING_SINKS
,
104 SESSION_STATE_CLOSED
,
105 SESSION_STATE_SHUT_DOWN
,
110 OBJ_STATE_STOPPED
= 0,
117 enum media_source_flags
119 SOURCE_FLAG_END_OF_PRESENTATION
= 0x1,
125 IMFMediaSource
*source
;
126 IMFPresentationDescriptor
*pd
;
127 enum object_state state
;
135 IMFMediaSinkPreroll
*preroll
;
136 IMFMediaEventGenerator
*event_generator
;
146 struct transform_stream
149 unsigned int requests
;
150 unsigned int min_buffer_size
;
155 TOPO_NODE_END_OF_STREAM
= 0x1,
161 struct media_session
*session
;
162 MF_TOPOLOGY_TYPE type
;
164 IMFTopologyNode
*node
;
165 enum object_state state
;
169 IMFMediaStream
*source_stream
;
170 IMFStreamSink
*sink_stream
;
171 IMFTransform
*transform
;
179 IMFMediaSource
*source
;
180 unsigned int stream_id
;
184 unsigned int requests
;
185 IMFVideoSampleAllocatorNotify notify_cb
;
186 IMFVideoSampleAllocator
*allocator
;
187 IMFVideoSampleAllocatorCallback
*allocator_cb
;
191 struct transform_stream
*inputs
;
192 unsigned int *input_map
;
193 unsigned int input_count
;
195 struct transform_stream
*outputs
;
196 unsigned int *output_map
;
197 unsigned int output_count
;
202 enum presentation_flags
204 SESSION_FLAG_SOURCES_SUBSCRIBED
= 0x1,
205 SESSION_FLAG_PRESENTATION_CLOCK_SET
= 0x2,
206 SESSION_FLAG_FINALIZE_SINKS
= 0x4,
207 SESSION_FLAG_NEEDS_PREROLL
= 0x8,
208 SESSION_FLAG_END_OF_PRESENTATION
= 0x10,
213 IMFMediaSession IMFMediaSession_iface
;
214 IMFGetService IMFGetService_iface
;
215 IMFRateSupport IMFRateSupport_iface
;
216 IMFRateControl IMFRateControl_iface
;
217 IMFTopologyNodeAttributeEditor IMFTopologyNodeAttributeEditor_iface
;
218 IMFAsyncCallback commands_callback
;
219 IMFAsyncCallback events_callback
;
220 IMFAsyncCallback sink_finalizer_callback
;
222 IMFMediaEventQueue
*event_queue
;
223 IMFPresentationClock
*clock
;
224 IMFPresentationTimeSource
*system_time_source
;
225 IMFRateControl
*clock_rate_control
;
226 IMFTopoLoader
*topo_loader
;
227 IMFQualityManager
*quality_manager
;
230 IMFTopology
*current_topology
;
231 MF_TOPOSTATUS topo_status
;
232 MFTIME clock_stop_time
;
238 /* Latest Start() arguments. */
240 PROPVARIANT start_position
;
242 struct list topologies
;
243 struct list commands
;
244 enum session_state state
;
249 enum quality_manager_state
251 QUALITY_MANAGER_READY
= 0,
252 QUALITY_MANAGER_SHUT_DOWN
,
255 struct quality_manager
257 IMFQualityManager IMFQualityManager_iface
;
258 IMFClockStateSink IMFClockStateSink_iface
;
261 IMFTopology
*topology
;
262 IMFPresentationClock
*clock
;
267 static inline struct media_session
*impl_from_IMFMediaSession(IMFMediaSession
*iface
)
269 return CONTAINING_RECORD(iface
, struct media_session
, IMFMediaSession_iface
);
272 static struct media_session
*impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
274 return CONTAINING_RECORD(iface
, struct media_session
, commands_callback
);
277 static struct media_session
*impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
279 return CONTAINING_RECORD(iface
, struct media_session
, events_callback
);
282 static struct media_session
*impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
284 return CONTAINING_RECORD(iface
, struct media_session
, sink_finalizer_callback
);
287 static struct media_session
*impl_from_IMFGetService(IMFGetService
*iface
)
289 return CONTAINING_RECORD(iface
, struct media_session
, IMFGetService_iface
);
292 static struct media_session
*impl_session_from_IMFRateSupport(IMFRateSupport
*iface
)
294 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateSupport_iface
);
297 static struct media_session
*impl_session_from_IMFRateControl(IMFRateControl
*iface
)
299 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateControl_iface
);
302 static struct media_session
*impl_session_from_IMFTopologyNodeAttributeEditor(IMFTopologyNodeAttributeEditor
*iface
)
304 return CONTAINING_RECORD(iface
, struct media_session
, IMFTopologyNodeAttributeEditor_iface
);
307 static struct session_op
*impl_op_from_IUnknown(IUnknown
*iface
)
309 return CONTAINING_RECORD(iface
, struct session_op
, IUnknown_iface
);
312 static struct quality_manager
*impl_from_IMFQualityManager(IMFQualityManager
*iface
)
314 return CONTAINING_RECORD(iface
, struct quality_manager
, IMFQualityManager_iface
);
317 static struct quality_manager
*impl_from_qm_IMFClockStateSink(IMFClockStateSink
*iface
)
319 return CONTAINING_RECORD(iface
, struct quality_manager
, IMFClockStateSink_iface
);
322 static struct topo_node
*impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify
*iface
)
324 return CONTAINING_RECORD(iface
, struct topo_node
, u
.sink
.notify_cb
);
327 /* IMFLocalMFTRegistration */
328 static HRESULT WINAPI
local_mft_registration_QueryInterface(IMFLocalMFTRegistration
*iface
, REFIID riid
, void **obj
)
330 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
332 if (IsEqualIID(riid
, &IID_IMFLocalMFTRegistration
) ||
333 IsEqualIID(riid
, &IID_IUnknown
))
336 IMFLocalMFTRegistration_AddRef(iface
);
340 WARN("Unexpected %s.\n", debugstr_guid(riid
));
342 return E_NOINTERFACE
;
345 static ULONG WINAPI
local_mft_registration_AddRef(IMFLocalMFTRegistration
*iface
)
350 static ULONG WINAPI
local_mft_registration_Release(IMFLocalMFTRegistration
*iface
)
355 static HRESULT WINAPI
local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration
*iface
, MFT_REGISTRATION_INFO
*info
,
361 TRACE("%p, %p, %u.\n", iface
, info
, count
);
363 for (i
= 0; i
< count
; ++i
)
365 if (FAILED(hr
= MFTRegisterLocalByCLSID(&info
[i
].clsid
, &info
[i
].guidCategory
, info
[i
].pszName
,
366 info
[i
].uiFlags
, info
[i
].cInTypes
, info
[i
].pInTypes
, info
[i
].cOutTypes
, info
[i
].pOutTypes
)))
375 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl
=
377 local_mft_registration_QueryInterface
,
378 local_mft_registration_AddRef
,
379 local_mft_registration_Release
,
380 local_mft_registration_RegisterMFTs
,
383 static IMFLocalMFTRegistration local_mft_registration
= { &local_mft_registration_vtbl
};
385 static HRESULT WINAPI
session_op_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
387 if (IsEqualIID(riid
, &IID_IUnknown
))
390 IUnknown_AddRef(iface
);
395 return E_NOINTERFACE
;
398 static ULONG WINAPI
session_op_AddRef(IUnknown
*iface
)
400 struct session_op
*op
= impl_op_from_IUnknown(iface
);
401 ULONG refcount
= InterlockedIncrement(&op
->refcount
);
403 TRACE("%p, refcount %u.\n", iface
, refcount
);
408 static ULONG WINAPI
session_op_Release(IUnknown
*iface
)
410 struct session_op
*op
= impl_op_from_IUnknown(iface
);
411 ULONG refcount
= InterlockedDecrement(&op
->refcount
);
413 TRACE("%p, refcount %u.\n", iface
, refcount
);
419 case SESSION_CMD_SET_TOPOLOGY
:
420 if (op
->u
.set_topology
.topology
)
421 IMFTopology_Release(op
->u
.set_topology
.topology
);
423 case SESSION_CMD_START
:
424 PropVariantClear(&op
->u
.start
.start_position
);
426 case SESSION_CMD_QM_NOTIFY_TOPOLOGY
:
427 if (op
->u
.notify_topology
.topology
)
428 IMFTopology_Release(op
->u
.notify_topology
.topology
);
439 static const IUnknownVtbl session_op_vtbl
=
441 session_op_QueryInterface
,
446 static HRESULT
create_session_op(enum session_command command
, struct session_op
**ret
)
448 struct session_op
*op
;
450 if (!(op
= calloc(1, sizeof(*op
))))
451 return E_OUTOFMEMORY
;
453 op
->IUnknown_iface
.lpVtbl
= &session_op_vtbl
;
455 op
->command
= command
;
462 static HRESULT
session_is_shut_down(struct media_session
*session
)
464 return session
->state
== SESSION_STATE_SHUT_DOWN
? MF_E_SHUTDOWN
: S_OK
;
467 static void session_push_back_command(struct media_session
*session
, enum session_command command
)
469 struct session_op
*op
;
471 if (SUCCEEDED(create_session_op(command
, &op
)))
472 list_add_head(&session
->commands
, &op
->entry
);
475 static HRESULT
session_submit_command(struct media_session
*session
, struct session_op
*op
)
479 EnterCriticalSection(&session
->cs
);
480 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
482 if (list_empty(&session
->commands
))
483 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
484 list_add_tail(&session
->commands
, &op
->entry
);
485 IUnknown_AddRef(&op
->IUnknown_iface
);
487 LeaveCriticalSection(&session
->cs
);
492 static HRESULT
session_submit_simple_command(struct media_session
*session
, enum session_command command
)
494 struct session_op
*op
;
497 if (FAILED(hr
= create_session_op(command
, &op
)))
500 hr
= session_submit_command(session
, op
);
501 IUnknown_Release(&op
->IUnknown_iface
);
505 static void session_clear_queued_topologies(struct media_session
*session
)
507 struct queued_topology
*ptr
, *next
;
509 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &session
->topologies
, struct queued_topology
, entry
)
511 list_remove(&ptr
->entry
);
512 IMFTopology_Release(ptr
->topology
);
517 static void session_set_topo_status(struct media_session
*session
, HRESULT status
,
518 MF_TOPOSTATUS topo_status
)
520 IMFMediaEvent
*event
;
523 if (topo_status
== MF_TOPOSTATUS_INVALID
)
526 if (list_empty(&session
->topologies
))
528 FIXME("Unexpectedly empty topology queue.\n");
532 if (topo_status
> session
->presentation
.topo_status
)
534 struct queued_topology
*topology
= LIST_ENTRY(list_head(&session
->topologies
), struct queued_topology
, entry
);
536 param
.vt
= VT_UNKNOWN
;
537 param
.punkVal
= (IUnknown
*)topology
->topology
;
539 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus
, &GUID_NULL
, status
, ¶m
, &event
)))
542 session
->presentation
.topo_status
= topo_status
;
544 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_TOPOLOGY_STATUS
, topo_status
);
545 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
546 IMFMediaEvent_Release(event
);
550 static HRESULT
session_bind_output_nodes(IMFTopology
*topology
)
552 MF_TOPOLOGY_TYPE node_type
;
553 IMFStreamSink
*stream_sink
;
554 IMFMediaSink
*media_sink
;
555 WORD node_count
= 0, i
;
556 IMFTopologyNode
*node
;
557 IMFActivate
*activate
;
562 hr
= IMFTopology_GetNodeCount(topology
, &node_count
);
564 for (i
= 0; i
< node_count
; ++i
)
566 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
569 if (FAILED(hr
= IMFTopologyNode_GetNodeType(node
, &node_type
)) || node_type
!= MF_TOPOLOGY_OUTPUT_NODE
)
571 IMFTopologyNode_Release(node
);
575 if (SUCCEEDED(hr
= IMFTopologyNode_GetObject(node
, &object
)))
578 if (FAILED(IUnknown_QueryInterface(object
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
580 if (SUCCEEDED(hr
= IUnknown_QueryInterface(object
, &IID_IMFActivate
, (void **)&activate
)))
582 if (SUCCEEDED(hr
= IMFActivate_ActivateObject(activate
, &IID_IMFMediaSink
, (void **)&media_sink
)))
584 if (FAILED(IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_STREAMID
, &stream_id
)))
588 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink
, stream_id
, &stream_sink
)))
589 hr
= IMFMediaSink_AddStreamSink(media_sink
, stream_id
, NULL
, &stream_sink
);
592 hr
= IMFTopologyNode_SetObject(node
, (IUnknown
*)stream_sink
);
594 IMFMediaSink_Release(media_sink
);
598 IMFTopologyNode_SetUnknown(node
, &_MF_TOPONODE_IMFActivate
, (IUnknown
*)activate
);
600 IMFActivate_Release(activate
);
605 IMFStreamSink_Release(stream_sink
);
606 IUnknown_Release(object
);
609 IMFTopologyNode_Release(node
);
615 static void session_set_caps(struct media_session
*session
, DWORD caps
)
617 DWORD delta
= session
->caps
^ caps
;
618 IMFMediaEvent
*event
;
620 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
621 them to, since session always queries for current object rates. */
625 session
->caps
= caps
;
627 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged
, &GUID_NULL
, S_OK
, NULL
, &event
)))
630 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS
, caps
);
631 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS_DELTA
, delta
);
633 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
634 IMFMediaEvent_Release(event
);
637 static void transform_release_sample(struct sample
*sample
)
639 list_remove(&sample
->entry
);
641 IMFSample_Release(sample
->sample
);
645 static void transform_stream_drop_samples(struct transform_stream
*stream
)
647 struct sample
*sample
, *sample2
;
649 LIST_FOR_EACH_ENTRY_SAFE(sample
, sample2
, &stream
->samples
, struct sample
, entry
)
650 transform_release_sample(sample
);
653 static void release_topo_node(struct topo_node
*node
)
659 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
660 if (node
->u
.source
.source
)
661 IMFMediaSource_Release(node
->u
.source
.source
);
663 case MF_TOPOLOGY_TRANSFORM_NODE
:
664 for (i
= 0; i
< node
->u
.transform
.input_count
; ++i
)
665 transform_stream_drop_samples(&node
->u
.transform
.inputs
[i
]);
666 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
667 transform_stream_drop_samples(&node
->u
.transform
.outputs
[i
]);
668 free(node
->u
.transform
.inputs
);
669 free(node
->u
.transform
.outputs
);
670 free(node
->u
.transform
.input_map
);
671 free(node
->u
.transform
.output_map
);
673 case MF_TOPOLOGY_OUTPUT_NODE
:
674 if (node
->u
.sink
.allocator
)
675 IMFVideoSampleAllocator_Release(node
->u
.sink
.allocator
);
676 if (node
->u
.sink
.allocator_cb
)
678 IMFVideoSampleAllocatorCallback_SetCallback(node
->u
.sink
.allocator_cb
, NULL
);
679 IMFVideoSampleAllocatorCallback_Release(node
->u
.sink
.allocator_cb
);
686 if (node
->object
.object
)
687 IUnknown_Release(node
->object
.object
);
689 IMFTopologyNode_Release(node
->node
);
693 static void session_shutdown_current_topology(struct media_session
*session
)
695 unsigned int shutdown
, force_shutdown
;
696 MF_TOPOLOGY_TYPE node_type
;
697 IMFStreamSink
*stream_sink
;
698 IMFTopology
*topology
;
699 IMFTopologyNode
*node
;
700 IMFActivate
*activate
;
705 topology
= session
->presentation
.current_topology
;
706 force_shutdown
= session
->state
== SESSION_STATE_SHUT_DOWN
;
708 /* FIXME: should handle async MFTs, but these are not supported by the rest of the pipeline currently. */
710 while (SUCCEEDED(IMFTopology_GetNode(topology
, idx
++, &node
)))
712 if (SUCCEEDED(IMFTopologyNode_GetNodeType(node
, &node_type
)) &&
713 node_type
== MF_TOPOLOGY_OUTPUT_NODE
)
716 IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, &shutdown
);
718 if (force_shutdown
|| shutdown
)
720 if (SUCCEEDED(IMFTopologyNode_GetUnknown(node
, &_MF_TOPONODE_IMFActivate
, &IID_IMFActivate
,
721 (void **)&activate
)))
723 if (FAILED(hr
= IMFActivate_ShutdownObject(activate
)))
724 WARN("Failed to shut down activation object for the sink, hr %#x.\n", hr
);
725 IMFActivate_Release(activate
);
727 else if (SUCCEEDED(topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
729 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink
, &sink
)))
731 IMFMediaSink_Shutdown(sink
);
732 IMFMediaSink_Release(sink
);
735 IMFStreamSink_Release(stream_sink
);
740 IMFTopologyNode_Release(node
);
744 static void session_clear_command_list(struct media_session
*session
)
746 struct session_op
*op
, *op2
;
748 LIST_FOR_EACH_ENTRY_SAFE(op
, op2
, &session
->commands
, struct session_op
, entry
)
750 list_remove(&op
->entry
);
751 IUnknown_Release(&op
->IUnknown_iface
);
755 static void session_clear_presentation(struct media_session
*session
)
757 struct media_source
*source
, *source2
;
758 struct media_sink
*sink
, *sink2
;
759 struct topo_node
*node
, *node2
;
761 session_shutdown_current_topology(session
);
763 IMFTopology_Clear(session
->presentation
.current_topology
);
764 session
->presentation
.topo_status
= MF_TOPOSTATUS_INVALID
;
766 LIST_FOR_EACH_ENTRY_SAFE(source
, source2
, &session
->presentation
.sources
, struct media_source
, entry
)
768 list_remove(&source
->entry
);
770 IMFMediaSource_Release(source
->source
);
772 IMFPresentationDescriptor_Release(source
->pd
);
776 LIST_FOR_EACH_ENTRY_SAFE(node
, node2
, &session
->presentation
.nodes
, struct topo_node
, entry
)
778 list_remove(&node
->entry
);
779 release_topo_node(node
);
782 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &session
->presentation
.sinks
, struct media_sink
, entry
)
784 list_remove(&sink
->entry
);
787 IMFMediaSink_Release(sink
->sink
);
789 IMFMediaSinkPreroll_Release(sink
->preroll
);
790 if (sink
->event_generator
)
791 IMFMediaEventGenerator_Release(sink
->event_generator
);
796 static struct topo_node
*session_get_node_by_id(const struct media_session
*session
, TOPOID id
)
798 struct topo_node
*node
;
800 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
802 if (node
->node_id
== id
)
809 static void session_command_complete(struct media_session
*session
)
811 struct session_op
*op
;
814 /* Pop current command, submit next. */
815 if ((e
= list_head(&session
->commands
)))
817 op
= LIST_ENTRY(e
, struct session_op
, entry
);
818 list_remove(&op
->entry
);
819 IUnknown_Release(&op
->IUnknown_iface
);
822 if ((e
= list_head(&session
->commands
)))
824 op
= LIST_ENTRY(e
, struct session_op
, entry
);
825 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
829 static void session_command_complete_with_event(struct media_session
*session
, MediaEventType event
,
830 HRESULT status
, const PROPVARIANT
*param
)
832 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, event
, &GUID_NULL
, status
, param
);
833 session_command_complete(session
);
836 static void session_start(struct media_session
*session
, const GUID
*time_format
, const PROPVARIANT
*start_position
)
838 struct media_source
*source
;
841 switch (session
->state
)
843 case SESSION_STATE_STOPPED
:
845 /* Start request with no current topology. */
846 if (session
->presentation
.topo_status
== MF_TOPOSTATUS_INVALID
)
848 session_command_complete_with_event(session
, MESessionStarted
, MF_E_INVALIDREQUEST
, NULL
);
853 case SESSION_STATE_PAUSED
:
855 session
->presentation
.time_format
= *time_format
;
856 session
->presentation
.start_position
.vt
= VT_EMPTY
;
857 PropVariantCopy(&session
->presentation
.start_position
, start_position
);
859 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
861 if (!(session
->presentation
.flags
& SESSION_FLAG_SOURCES_SUBSCRIBED
))
863 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(source
->source
, &session
->events_callback
,
864 (IUnknown
*)source
->source
)))
866 WARN("Failed to subscribe to source events, hr %#x.\n", hr
);
870 if (FAILED(hr
= IMFMediaSource_Start(source
->source
, source
->pd
, &GUID_NULL
, start_position
)))
871 WARN("Failed to start media source %p, hr %#x.\n", source
->source
, hr
);
874 session
->presentation
.flags
|= SESSION_FLAG_SOURCES_SUBSCRIBED
;
875 session
->state
= SESSION_STATE_STARTING_SOURCES
;
877 case SESSION_STATE_STARTED
:
878 FIXME("Seeking is not implemented.\n");
879 session_command_complete(session
);
882 session_command_complete_with_event(session
, MESessionStarted
, MF_E_INVALIDREQUEST
, NULL
);
887 static void session_set_started(struct media_session
*session
)
889 struct media_source
*source
;
890 unsigned int caps
, flags
;
891 IMFMediaEvent
*event
;
893 session
->state
= SESSION_STATE_STARTED
;
895 caps
= session
->caps
| MFSESSIONCAP_PAUSE
;
897 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
899 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &flags
)))
901 if (!(flags
& MFMEDIASOURCE_CAN_PAUSE
))
903 caps
&= ~MFSESSIONCAP_PAUSE
;
909 session_set_caps(session
, caps
);
911 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted
, &GUID_NULL
, S_OK
, NULL
, &event
)))
913 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
914 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
915 IMFMediaEvent_Release(event
);
917 session_command_complete(session
);
920 static void session_set_paused(struct media_session
*session
, unsigned int state
, HRESULT status
)
922 /* Failed event status could indicate a failure during normal transition to paused state,
923 or an attempt to pause from invalid initial state. To finalize failed transition in the former case,
924 state is still forced to PAUSED, otherwise previous state is retained. */
925 if (state
!= ~0u) session
->state
= state
;
926 if (SUCCEEDED(status
))
927 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
928 session_command_complete_with_event(session
, MESessionPaused
, status
, NULL
);
931 static void session_set_closed(struct media_session
*session
, HRESULT status
)
933 session
->state
= SESSION_STATE_CLOSED
;
934 if (SUCCEEDED(status
))
935 session_set_caps(session
, session
->caps
& ~(MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
));
936 session_command_complete_with_event(session
, MESessionClosed
, status
, NULL
);
939 static void session_pause(struct media_session
*session
)
941 unsigned int state
= ~0u;
944 switch (session
->state
)
946 case SESSION_STATE_STARTED
:
948 /* Transition in two steps - pause the clock, wait for sinks, then pause sources. */
949 if (SUCCEEDED(hr
= IMFPresentationClock_Pause(session
->clock
)))
950 session
->state
= SESSION_STATE_PAUSING_SINKS
;
951 state
= SESSION_STATE_PAUSED
;
955 case SESSION_STATE_STOPPED
:
956 hr
= MF_E_SESSION_PAUSEWHILESTOPPED
;
959 hr
= MF_E_INVALIDREQUEST
;
963 session_set_paused(session
, state
, hr
);
966 static void session_clear_end_of_presentation(struct media_session
*session
)
968 struct media_source
*source
;
969 struct topo_node
*node
;
971 session
->presentation
.flags
&= ~SESSION_FLAG_END_OF_PRESENTATION
;
972 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
974 source
->flags
&= ~SOURCE_FLAG_END_OF_PRESENTATION
;
976 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
978 node
->flags
&= ~TOPO_NODE_END_OF_STREAM
;
980 session
->presentation
.topo_status
= MF_TOPOSTATUS_READY
;
983 static void session_set_stopped(struct media_session
*session
, HRESULT status
)
985 MediaEventType event_type
;
986 IMFMediaEvent
*event
;
988 session
->state
= SESSION_STATE_STOPPED
;
989 event_type
= session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
? MESessionEnded
: MESessionStopped
;
991 if (SUCCEEDED(MFCreateMediaEvent(event_type
, &GUID_NULL
, status
, NULL
, &event
)))
993 IMFMediaEvent_SetUINT64(event
, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME
, session
->presentation
.clock_stop_time
);
994 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
995 IMFMediaEvent_Release(event
);
997 session_clear_end_of_presentation(session
);
998 session_command_complete(session
);
1001 static void session_stop(struct media_session
*session
)
1003 HRESULT hr
= MF_E_INVALIDREQUEST
;
1005 switch (session
->state
)
1007 case SESSION_STATE_STARTED
:
1008 case SESSION_STATE_PAUSED
:
1010 /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */
1011 IMFPresentationClock_GetTime(session
->clock
, &session
->presentation
.clock_stop_time
);
1012 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1013 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1015 session_set_stopped(session
, hr
);
1018 case SESSION_STATE_STOPPED
:
1022 session_command_complete_with_event(session
, MESessionStopped
, hr
, NULL
);
1027 static HRESULT
session_finalize_sinks(struct media_session
*session
)
1029 IMFFinalizableMediaSink
*fin_sink
;
1030 BOOL sinks_finalized
= TRUE
;
1031 struct media_sink
*sink
;
1034 session
->presentation
.flags
&= ~SESSION_FLAG_FINALIZE_SINKS
;
1035 session
->state
= SESSION_STATE_FINALIZING_SINKS
;
1037 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1039 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
1041 hr
= IMFFinalizableMediaSink_BeginFinalize(fin_sink
, &session
->sink_finalizer_callback
,
1042 (IUnknown
*)fin_sink
);
1043 IMFFinalizableMediaSink_Release(fin_sink
);
1046 sinks_finalized
= FALSE
;
1049 sink
->finalized
= TRUE
;
1052 if (sinks_finalized
)
1053 session_set_closed(session
, hr
);
1058 static void session_close(struct media_session
*session
)
1062 switch (session
->state
)
1064 case SESSION_STATE_STOPPED
:
1065 hr
= session_finalize_sinks(session
);
1067 case SESSION_STATE_STARTED
:
1068 case SESSION_STATE_PAUSED
:
1069 session
->presentation
.flags
|= SESSION_FLAG_FINALIZE_SINKS
;
1070 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1071 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1074 hr
= MF_E_INVALIDREQUEST
;
1078 session_clear_queued_topologies(session
);
1080 session_set_closed(session
, hr
);
1083 static void session_clear_topologies(struct media_session
*session
)
1087 if (session
->state
== SESSION_STATE_CLOSED
)
1088 hr
= MF_E_INVALIDREQUEST
;
1090 session_clear_queued_topologies(session
);
1091 session_command_complete_with_event(session
, MESessionTopologiesCleared
, hr
, NULL
);
1094 static struct media_source
*session_get_media_source(struct media_session
*session
, IMFMediaSource
*source
)
1096 struct media_source
*cur
;
1098 LIST_FOR_EACH_ENTRY(cur
, &session
->presentation
.sources
, struct media_source
, entry
)
1100 if (source
== cur
->source
)
1107 static void session_release_media_source(struct media_source
*source
)
1109 IMFMediaSource_Release(source
->source
);
1111 IMFPresentationDescriptor_Release(source
->pd
);
1115 static HRESULT
session_add_media_source(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSource
*source
)
1117 struct media_source
*media_source
;
1120 if (session_get_media_source(session
, source
))
1123 if (!(media_source
= calloc(1, sizeof(*media_source
))))
1124 return E_OUTOFMEMORY
;
1126 media_source
->source
= source
;
1127 IMFMediaSource_AddRef(media_source
->source
);
1129 hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
, &IID_IMFPresentationDescriptor
,
1130 (void **)&media_source
->pd
);
1133 list_add_tail(&session
->presentation
.sources
, &media_source
->entry
);
1135 session_release_media_source(media_source
);
1140 static void session_raise_topology_set(struct media_session
*session
, IMFTopology
*topology
, HRESULT status
)
1144 param
.vt
= topology
? VT_UNKNOWN
: VT_EMPTY
;
1145 param
.punkVal
= (IUnknown
*)topology
;
1147 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologySet
, &GUID_NULL
, status
, ¶m
);
1150 static DWORD
session_get_object_rate_caps(IUnknown
*object
)
1152 IMFRateSupport
*rate_support
;
1156 if (SUCCEEDED(MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
1159 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_FORWARD
, TRUE
, &rate
)) && rate
!= 0.0f
)
1160 caps
|= MFSESSIONCAP_RATE_FORWARD
;
1163 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_REVERSE
, TRUE
, &rate
)) && rate
!= 0.0f
)
1164 caps
|= MFSESSIONCAP_RATE_REVERSE
;
1166 IMFRateSupport_Release(rate_support
);
1172 static HRESULT
session_add_media_sink(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSink
*sink
)
1174 struct media_sink
*media_sink
;
1175 unsigned int disable_preroll
= 0;
1178 LIST_FOR_EACH_ENTRY(media_sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1180 if (sink
== media_sink
->sink
)
1184 if (!(media_sink
= calloc(1, sizeof(*media_sink
))))
1185 return E_OUTOFMEMORY
;
1187 media_sink
->sink
= sink
;
1188 IMFMediaSink_AddRef(media_sink
->sink
);
1190 IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaEventGenerator
, (void **)&media_sink
->event_generator
);
1192 IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_DISABLE_PREROLL
, &disable_preroll
);
1193 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
, &flags
)) && flags
& MEDIASINK_CAN_PREROLL
&& !disable_preroll
)
1195 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaSinkPreroll
, (void **)&media_sink
->preroll
)))
1196 session
->presentation
.flags
|= SESSION_FLAG_NEEDS_PREROLL
;
1199 list_add_tail(&session
->presentation
.sinks
, &media_sink
->entry
);
1204 static unsigned int transform_node_get_stream_id(struct topo_node
*node
, BOOL output
, unsigned int index
)
1206 unsigned int *map
= output
? node
->u
.transform
.output_map
: node
->u
.transform
.input_map
;
1207 return map
? map
[index
] : index
;
1210 static HRESULT
session_set_transform_stream_info(struct topo_node
*node
)
1212 unsigned int *input_map
= NULL
, *output_map
= NULL
;
1213 unsigned int i
, input_count
, output_count
, block_alignment
;
1214 struct transform_stream
*streams
;
1215 IMFMediaType
*media_type
;
1219 hr
= IMFTransform_GetStreamCount(node
->object
.transform
, &input_count
, &output_count
);
1220 if (SUCCEEDED(hr
) && (input_count
> 1 || output_count
> 1))
1222 input_map
= calloc(input_count
, sizeof(*input_map
));
1223 output_map
= calloc(output_count
, sizeof(*output_map
));
1224 if (FAILED(IMFTransform_GetStreamIDs(node
->object
.transform
, input_count
, input_map
,
1225 output_count
, output_map
)))
1227 /* Assume sequential identifiers. */
1230 input_map
= output_map
= NULL
;
1236 node
->u
.transform
.input_map
= input_map
;
1237 node
->u
.transform
.output_map
= output_map
;
1239 streams
= calloc(input_count
, sizeof(*streams
));
1240 for (i
= 0; i
< input_count
; ++i
)
1241 list_init(&streams
[i
].samples
);
1242 node
->u
.transform
.inputs
= streams
;
1243 node
->u
.transform
.input_count
= input_count
;
1245 streams
= calloc(output_count
, sizeof(*streams
));
1246 for (i
= 0; i
< output_count
; ++i
)
1248 list_init(&streams
[i
].samples
);
1250 if (SUCCEEDED(IMFTransform_GetOutputCurrentType(node
->object
.transform
,
1251 transform_node_get_stream_id(node
, TRUE
, i
), &media_type
)))
1253 if (SUCCEEDED(IMFMediaType_GetMajorType(media_type
, &major
)) && IsEqualGUID(&major
, &MFMediaType_Audio
)
1254 && SUCCEEDED(IMFMediaType_GetUINT32(media_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &block_alignment
)))
1256 streams
[i
].min_buffer_size
= block_alignment
;
1258 IMFMediaType_Release(media_type
);
1261 node
->u
.transform
.outputs
= streams
;
1262 node
->u
.transform
.output_count
= output_count
;
1268 static HRESULT
session_get_stream_sink_type(IMFStreamSink
*sink
, IMFMediaType
**media_type
)
1270 IMFMediaTypeHandler
*handler
;
1273 if (SUCCEEDED(hr
= IMFStreamSink_GetMediaTypeHandler(sink
, &handler
)))
1275 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, media_type
);
1276 IMFMediaTypeHandler_Release(handler
);
1282 static HRESULT WINAPI
node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify
*iface
,
1283 REFIID riid
, void **obj
)
1285 if (IsEqualIID(riid
, &IID_IMFVideoSampleAllocatorNotify
) ||
1286 IsEqualIID(riid
, &IID_IUnknown
))
1289 IMFVideoSampleAllocatorNotify_AddRef(iface
);
1294 return E_NOINTERFACE
;
1297 static ULONG WINAPI
node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify
*iface
)
1302 static ULONG WINAPI
node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify
*iface
)
1307 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
);
1309 static HRESULT WINAPI
node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify
*iface
)
1311 struct topo_node
*topo_node
= impl_node_from_IMFVideoSampleAllocatorNotify(iface
);
1312 struct session_op
*op
;
1314 if (SUCCEEDED(create_session_op(SESSION_CMD_SA_READY
, &op
)))
1316 op
->u
.sa_ready
.node_id
= topo_node
->node_id
;
1317 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &topo_node
->session
->commands_callback
, &op
->IUnknown_iface
);
1318 IUnknown_Release(&op
->IUnknown_iface
);
1324 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl
=
1326 node_sample_allocator_cb_QueryInterface
,
1327 node_sample_allocator_cb_AddRef
,
1328 node_sample_allocator_cb_Release
,
1329 node_sample_allocator_cb_NotifyRelease
,
1332 static HRESULT
session_append_node(struct media_session
*session
, IMFTopologyNode
*node
)
1334 struct topo_node
*topo_node
;
1335 IMFMediaSink
*media_sink
;
1336 IMFMediaType
*media_type
;
1337 IMFStreamDescriptor
*sd
;
1340 if (!(topo_node
= calloc(1, sizeof(*topo_node
))))
1341 return E_OUTOFMEMORY
;
1343 IMFTopologyNode_GetNodeType(node
, &topo_node
->type
);
1344 IMFTopologyNode_GetTopoNodeID(node
, &topo_node
->node_id
);
1345 topo_node
->node
= node
;
1346 IMFTopologyNode_AddRef(topo_node
->node
);
1347 topo_node
->session
= session
;
1349 switch (topo_node
->type
)
1351 case MF_TOPOLOGY_OUTPUT_NODE
:
1352 topo_node
->u
.sink
.notify_cb
.lpVtbl
= &node_sample_allocator_cb_vtbl
;
1354 if (FAILED(hr
= topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&topo_node
->object
.object
)))
1356 WARN("Failed to get stream sink interface, hr %#x.\n", hr
);
1360 if (FAILED(hr
= IMFStreamSink_GetMediaSink(topo_node
->object
.sink_stream
, &media_sink
)))
1363 if (SUCCEEDED(hr
= session_add_media_sink(session
, node
, media_sink
)))
1365 if (SUCCEEDED(session_get_stream_sink_type(topo_node
->object
.sink_stream
, &media_type
)))
1367 if (SUCCEEDED(MFGetService(topo_node
->object
.object
, &MR_VIDEO_ACCELERATION_SERVICE
,
1368 &IID_IMFVideoSampleAllocator
, (void **)&topo_node
->u
.sink
.allocator
)))
1370 if (FAILED(hr
= IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node
->u
.sink
.allocator
,
1373 WARN("Failed to initialize sample allocator for the stream, hr %#x.\n", hr
);
1375 IMFVideoSampleAllocator_QueryInterface(topo_node
->u
.sink
.allocator
,
1376 &IID_IMFVideoSampleAllocatorCallback
, (void **)&topo_node
->u
.sink
.allocator_cb
);
1377 IMFVideoSampleAllocatorCallback_SetCallback(topo_node
->u
.sink
.allocator_cb
,
1378 &topo_node
->u
.sink
.notify_cb
);
1380 IMFMediaType_Release(media_type
);
1383 IMFMediaSink_Release(media_sink
);
1386 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
1387 if (FAILED(IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_SOURCE
, &IID_IMFMediaSource
,
1388 (void **)&topo_node
->u
.source
.source
)))
1390 WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr
);
1394 if (FAILED(hr
= session_add_media_source(session
, node
, topo_node
->u
.source
.source
)))
1397 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
1398 &IID_IMFStreamDescriptor
, (void **)&sd
)))
1400 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr
);
1404 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &topo_node
->u
.source
.stream_id
);
1405 IMFStreamDescriptor_Release(sd
);
1408 case MF_TOPOLOGY_TRANSFORM_NODE
:
1410 if (SUCCEEDED(hr
= topology_node_get_object(node
, &IID_IMFTransform
, (void **)&topo_node
->object
.transform
)))
1412 hr
= session_set_transform_stream_info(topo_node
);
1415 WARN("Failed to get IMFTransform for MFT node, hr %#x.\n", hr
);
1418 case MF_TOPOLOGY_TEE_NODE
:
1419 FIXME("Unsupported node type %d.\n", topo_node
->type
);
1427 list_add_tail(&session
->presentation
.nodes
, &topo_node
->entry
);
1429 release_topo_node(topo_node
);
1434 static HRESULT
session_collect_nodes(struct media_session
*session
)
1436 IMFTopology
*topology
= session
->presentation
.current_topology
;
1437 IMFTopologyNode
*node
;
1441 if (!list_empty(&session
->presentation
.nodes
))
1444 if (FAILED(hr
= IMFTopology_GetNodeCount(topology
, &count
)))
1447 for (i
= 0; i
< count
; ++i
)
1449 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
1451 WARN("Failed to get node %u.\n", i
);
1455 hr
= session_append_node(session
, node
);
1456 IMFTopologyNode_Release(node
);
1459 WARN("Failed to add node %u.\n", i
);
1467 static HRESULT
session_set_current_topology(struct media_session
*session
, IMFTopology
*topology
)
1469 struct media_source
*source
;
1470 DWORD caps
, object_flags
;
1471 struct media_sink
*sink
;
1472 struct topo_node
*node
;
1473 struct session_op
*op
;
1474 IMFMediaEvent
*event
;
1477 if (session
->quality_manager
)
1479 if (SUCCEEDED(create_session_op(SESSION_CMD_QM_NOTIFY_TOPOLOGY
, &op
)))
1481 op
->u
.notify_topology
.topology
= topology
;
1482 IMFTopology_AddRef(op
->u
.notify_topology
.topology
);
1483 session_submit_command(session
, op
);
1484 IUnknown_Release(&op
->IUnknown_iface
);
1488 if (FAILED(hr
= IMFTopology_CloneFrom(session
->presentation
.current_topology
, topology
)))
1490 WARN("Failed to clone topology, hr %#x.\n", hr
);
1494 session_collect_nodes(session
);
1496 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1498 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
1500 if (FAILED(hr
= IMFTransform_ProcessMessage(node
->object
.transform
,
1501 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING
, 0)))
1506 /* FIXME: attributes are all zero for now */
1507 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime
, &GUID_NULL
, S_OK
, NULL
, &event
)))
1509 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME
, 0);
1510 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
1511 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT
, 0);
1513 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
1514 IMFMediaEvent_Release(event
);
1517 /* Update session caps. */
1518 caps
= MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
| MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
|
1519 MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1521 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1527 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &object_flags
)))
1529 if (!(object_flags
& MFMEDIASOURCE_DOES_NOT_USE_NETWORK
))
1530 caps
&= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1531 if (!(object_flags
& MFMEDIASOURCE_CAN_SEEK
))
1532 caps
&= ~MFSESSIONCAP_SEEK
;
1535 /* Mask unsupported rate caps. */
1537 caps
&= session_get_object_rate_caps((IUnknown
*)source
->source
)
1538 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1541 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1547 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
->sink
, &object_flags
)))
1549 if (!(object_flags
& MEDIASINK_RATELESS
))
1550 caps
&= session_get_object_rate_caps((IUnknown
*)sink
->sink
)
1551 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1555 session_set_caps(session
, caps
);
1560 static void session_set_topology(struct media_session
*session
, DWORD flags
, IMFTopology
*topology
)
1562 IMFTopology
*resolved_topology
= NULL
;
1565 /* Resolve unless claimed to be full. */
1566 if (!(flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
) && topology
)
1568 if (!(flags
& MFSESSION_SETTOPOLOGY_NORESOLUTION
))
1570 hr
= session_bind_output_nodes(topology
);
1573 hr
= IMFTopoLoader_Load(session
->topo_loader
, topology
, &resolved_topology
, NULL
/* FIXME? */);
1577 topology
= resolved_topology
;
1582 if (flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
)
1584 if ((topology
&& topology
== session
->presentation
.current_topology
) || !topology
)
1586 /* FIXME: stop current topology, queue next one. */
1587 session_clear_presentation(session
);
1594 else if (topology
&& flags
& MFSESSION_SETTOPOLOGY_IMMEDIATE
)
1596 session_clear_queued_topologies(session
);
1597 session_clear_presentation(session
);
1600 session_raise_topology_set(session
, topology
, hr
);
1602 /* With no current topology set it right away, otherwise queue. */
1605 struct queued_topology
*queued_topology
;
1607 if ((queued_topology
= calloc(1, sizeof(*queued_topology
))))
1609 queued_topology
->topology
= topology
;
1610 IMFTopology_AddRef(queued_topology
->topology
);
1612 list_add_tail(&session
->topologies
, &queued_topology
->entry
);
1615 if (session
->presentation
.topo_status
== MF_TOPOSTATUS_INVALID
)
1617 hr
= session_set_current_topology(session
, topology
);
1618 session_set_topo_status(session
, hr
, MF_TOPOSTATUS_READY
);
1622 if (resolved_topology
)
1623 IMFTopology_Release(resolved_topology
);
1626 static HRESULT WINAPI
mfsession_QueryInterface(IMFMediaSession
*iface
, REFIID riid
, void **out
)
1628 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1630 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1632 if (IsEqualIID(riid
, &IID_IMFMediaSession
) ||
1633 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1634 IsEqualIID(riid
, &IID_IUnknown
))
1636 *out
= &session
->IMFMediaSession_iface
;
1637 IMFMediaSession_AddRef(iface
);
1640 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1642 *out
= &session
->IMFGetService_iface
;
1643 IMFMediaSession_AddRef(iface
);
1647 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1649 return E_NOINTERFACE
;
1652 static ULONG WINAPI
mfsession_AddRef(IMFMediaSession
*iface
)
1654 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1655 ULONG refcount
= InterlockedIncrement(&session
->refcount
);
1657 TRACE("%p, refcount %u.\n", iface
, refcount
);
1662 static ULONG WINAPI
mfsession_Release(IMFMediaSession
*iface
)
1664 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1665 ULONG refcount
= InterlockedDecrement(&session
->refcount
);
1667 TRACE("%p, refcount %u.\n", iface
, refcount
);
1671 session_clear_queued_topologies(session
);
1672 session_clear_presentation(session
);
1673 session_clear_command_list(session
);
1674 if (session
->presentation
.current_topology
)
1675 IMFTopology_Release(session
->presentation
.current_topology
);
1676 if (session
->event_queue
)
1677 IMFMediaEventQueue_Release(session
->event_queue
);
1679 IMFPresentationClock_Release(session
->clock
);
1680 if (session
->system_time_source
)
1681 IMFPresentationTimeSource_Release(session
->system_time_source
);
1682 if (session
->clock_rate_control
)
1683 IMFRateControl_Release(session
->clock_rate_control
);
1684 if (session
->topo_loader
)
1685 IMFTopoLoader_Release(session
->topo_loader
);
1686 if (session
->quality_manager
)
1687 IMFQualityManager_Release(session
->quality_manager
);
1688 DeleteCriticalSection(&session
->cs
);
1695 static HRESULT WINAPI
mfsession_GetEvent(IMFMediaSession
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1697 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1699 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
1701 return IMFMediaEventQueue_GetEvent(session
->event_queue
, flags
, event
);
1704 static HRESULT WINAPI
mfsession_BeginGetEvent(IMFMediaSession
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1706 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1708 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1710 return IMFMediaEventQueue_BeginGetEvent(session
->event_queue
, callback
, state
);
1713 static HRESULT WINAPI
mfsession_EndGetEvent(IMFMediaSession
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
1715 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1717 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1719 return IMFMediaEventQueue_EndGetEvent(session
->event_queue
, result
, event
);
1722 static HRESULT WINAPI
mfsession_QueueEvent(IMFMediaSession
*iface
, MediaEventType event_type
, REFGUID ext_type
,
1723 HRESULT hr
, const PROPVARIANT
*value
)
1725 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1727 TRACE("%p, %d, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1729 return IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, event_type
, ext_type
, hr
, value
);
1732 static HRESULT WINAPI
mfsession_SetTopology(IMFMediaSession
*iface
, DWORD flags
, IMFTopology
*topology
)
1734 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1735 struct session_op
*op
;
1736 WORD node_count
= 0;
1739 TRACE("%p, %#x, %p.\n", iface
, flags
, topology
);
1743 if (FAILED(IMFTopology_GetNodeCount(topology
, &node_count
)) || node_count
== 0)
1744 return E_INVALIDARG
;
1747 if (FAILED(hr
= create_session_op(SESSION_CMD_SET_TOPOLOGY
, &op
)))
1750 op
->u
.set_topology
.flags
= flags
;
1751 op
->u
.set_topology
.topology
= topology
;
1752 if (op
->u
.set_topology
.topology
)
1753 IMFTopology_AddRef(op
->u
.set_topology
.topology
);
1755 hr
= session_submit_command(session
, op
);
1756 IUnknown_Release(&op
->IUnknown_iface
);
1761 static HRESULT WINAPI
mfsession_ClearTopologies(IMFMediaSession
*iface
)
1763 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1765 TRACE("%p.\n", iface
);
1767 return session_submit_simple_command(session
, SESSION_CMD_CLEAR_TOPOLOGIES
);
1770 static HRESULT WINAPI
mfsession_Start(IMFMediaSession
*iface
, const GUID
*format
, const PROPVARIANT
*start_position
)
1772 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1773 struct session_op
*op
;
1776 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), start_position
);
1778 if (!start_position
)
1781 if (FAILED(hr
= create_session_op(SESSION_CMD_START
, &op
)))
1784 op
->u
.start
.time_format
= format
? *format
: GUID_NULL
;
1785 hr
= PropVariantCopy(&op
->u
.start
.start_position
, start_position
);
1788 hr
= session_submit_command(session
, op
);
1790 IUnknown_Release(&op
->IUnknown_iface
);
1794 static HRESULT WINAPI
mfsession_Pause(IMFMediaSession
*iface
)
1796 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1798 TRACE("%p.\n", iface
);
1800 return session_submit_simple_command(session
, SESSION_CMD_PAUSE
);
1803 static HRESULT WINAPI
mfsession_Stop(IMFMediaSession
*iface
)
1805 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1807 TRACE("%p.\n", iface
);
1809 return session_submit_simple_command(session
, SESSION_CMD_STOP
);
1812 static HRESULT WINAPI
mfsession_Close(IMFMediaSession
*iface
)
1814 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1816 TRACE("%p.\n", iface
);
1818 return session_submit_simple_command(session
, SESSION_CMD_CLOSE
);
1821 static HRESULT WINAPI
mfsession_Shutdown(IMFMediaSession
*iface
)
1823 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1826 TRACE("%p.\n", iface
);
1828 EnterCriticalSection(&session
->cs
);
1829 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1831 session
->state
= SESSION_STATE_SHUT_DOWN
;
1832 IMFMediaEventQueue_Shutdown(session
->event_queue
);
1833 if (session
->quality_manager
)
1834 IMFQualityManager_Shutdown(session
->quality_manager
);
1835 MFShutdownObject((IUnknown
*)session
->clock
);
1836 IMFPresentationClock_Release(session
->clock
);
1837 session
->clock
= NULL
;
1838 session_clear_presentation(session
);
1839 session_clear_command_list(session
);
1841 LeaveCriticalSection(&session
->cs
);
1846 static HRESULT WINAPI
mfsession_GetClock(IMFMediaSession
*iface
, IMFClock
**clock
)
1848 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1851 TRACE("%p, %p.\n", iface
, clock
);
1853 EnterCriticalSection(&session
->cs
);
1854 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1856 *clock
= (IMFClock
*)session
->clock
;
1857 IMFClock_AddRef(*clock
);
1859 LeaveCriticalSection(&session
->cs
);
1864 static HRESULT WINAPI
mfsession_GetSessionCapabilities(IMFMediaSession
*iface
, DWORD
*caps
)
1866 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1869 TRACE("%p, %p.\n", iface
, caps
);
1874 EnterCriticalSection(&session
->cs
);
1875 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1876 *caps
= session
->caps
;
1877 LeaveCriticalSection(&session
->cs
);
1882 static HRESULT WINAPI
mfsession_GetFullTopology(IMFMediaSession
*iface
, DWORD flags
, TOPOID id
, IMFTopology
**topology
)
1884 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1885 struct queued_topology
*queued
;
1889 TRACE("%p, %#x, %s, %p.\n", iface
, flags
, wine_dbgstr_longlong(id
), topology
);
1893 EnterCriticalSection(&session
->cs
);
1895 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1897 if (flags
& MFSESSION_GETFULLTOPOLOGY_CURRENT
)
1899 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
1900 *topology
= session
->presentation
.current_topology
;
1902 hr
= MF_E_INVALIDREQUEST
;
1906 LIST_FOR_EACH_ENTRY(queued
, &session
->topologies
, struct queued_topology
, entry
)
1908 if (SUCCEEDED(IMFTopology_GetTopologyID(queued
->topology
, &topo_id
)) && topo_id
== id
)
1910 *topology
= queued
->topology
;
1917 IMFTopology_AddRef(*topology
);
1920 LeaveCriticalSection(&session
->cs
);
1925 static const IMFMediaSessionVtbl mfmediasessionvtbl
=
1927 mfsession_QueryInterface
,
1931 mfsession_BeginGetEvent
,
1932 mfsession_EndGetEvent
,
1933 mfsession_QueueEvent
,
1934 mfsession_SetTopology
,
1935 mfsession_ClearTopologies
,
1942 mfsession_GetSessionCapabilities
,
1943 mfsession_GetFullTopology
,
1946 static HRESULT WINAPI
session_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
1948 struct media_session
*session
= impl_from_IMFGetService(iface
);
1949 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
1952 static ULONG WINAPI
session_get_service_AddRef(IMFGetService
*iface
)
1954 struct media_session
*session
= impl_from_IMFGetService(iface
);
1955 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
1958 static ULONG WINAPI
session_get_service_Release(IMFGetService
*iface
)
1960 struct media_session
*session
= impl_from_IMFGetService(iface
);
1961 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
1964 typedef BOOL (*p_renderer_node_test_func
)(IMFMediaSink
*sink
);
1966 static BOOL
session_video_renderer_test_func(IMFMediaSink
*sink
)
1971 /* Use first sink to support IMFVideoRenderer. */
1972 hr
= IMFMediaSink_QueryInterface(sink
, &IID_IMFVideoRenderer
, (void **)&obj
);
1974 IUnknown_Release(obj
);
1979 static BOOL
session_audio_renderer_test_func(IMFMediaSink
*sink
)
1981 return mf_is_sar_sink(sink
);
1984 static HRESULT
session_get_renderer_node_service(struct media_session
*session
,
1985 p_renderer_node_test_func node_test_func
, REFGUID service
, REFIID riid
, void **obj
)
1987 HRESULT hr
= E_NOINTERFACE
;
1988 IMFStreamSink
*stream_sink
;
1989 IMFTopologyNode
*node
;
1990 IMFCollection
*nodes
;
1994 if (session
->presentation
.current_topology
)
1996 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session
->presentation
.current_topology
,
1999 while (IMFCollection_GetElement(nodes
, i
++, (IUnknown
**)&node
) == S_OK
)
2001 if (SUCCEEDED(topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
2003 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink
, &sink
)))
2005 if (node_test_func(sink
))
2007 if (FAILED(hr
= MFGetService((IUnknown
*)sink
, service
, riid
, obj
)))
2008 WARN("Failed to get service from renderer node, %#x.\n", hr
);
2011 IMFStreamSink_Release(stream_sink
);
2014 IMFTopologyNode_Release(node
);
2020 IMFCollection_Release(nodes
);
2027 static HRESULT
session_get_audio_render_service(struct media_session
*session
, REFGUID service
,
2028 REFIID riid
, void **obj
)
2030 return session_get_renderer_node_service(session
, session_audio_renderer_test_func
,
2031 service
, riid
, obj
);
2034 static HRESULT
session_get_video_render_service(struct media_session
*session
, REFGUID service
,
2035 REFIID riid
, void **obj
)
2037 return session_get_renderer_node_service(session
, session_video_renderer_test_func
,
2038 service
, riid
, obj
);
2041 static HRESULT WINAPI
session_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
2043 struct media_session
*session
= impl_from_IMFGetService(iface
);
2046 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
2050 EnterCriticalSection(&session
->cs
);
2051 if (FAILED(hr
= session_is_shut_down(session
)))
2054 else if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
2056 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
2058 *obj
= &session
->IMFRateSupport_iface
;
2060 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
2062 *obj
= &session
->IMFRateControl_iface
;
2068 IUnknown_AddRef((IUnknown
*)*obj
);
2070 else if (IsEqualGUID(service
, &MF_LOCAL_MFT_REGISTRATION_SERVICE
))
2072 hr
= IMFLocalMFTRegistration_QueryInterface(&local_mft_registration
, riid
, obj
);
2074 else if (IsEqualGUID(service
, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE
))
2076 *obj
= &session
->IMFTopologyNodeAttributeEditor_iface
;
2077 IUnknown_AddRef((IUnknown
*)*obj
);
2079 else if (IsEqualGUID(service
, &MR_VIDEO_RENDER_SERVICE
))
2081 hr
= session_get_video_render_service(session
, service
, riid
, obj
);
2083 else if (IsEqualGUID(service
, &MR_POLICY_VOLUME_SERVICE
))
2085 hr
= session_get_audio_render_service(session
, service
, riid
, obj
);
2088 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
2090 LeaveCriticalSection(&session
->cs
);
2095 static const IMFGetServiceVtbl session_get_service_vtbl
=
2097 session_get_service_QueryInterface
,
2098 session_get_service_AddRef
,
2099 session_get_service_Release
,
2100 session_get_service_GetService
,
2103 static HRESULT WINAPI
session_commands_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2105 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2106 IsEqualIID(riid
, &IID_IUnknown
))
2109 IMFAsyncCallback_AddRef(iface
);
2113 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2115 return E_NOINTERFACE
;
2118 static ULONG WINAPI
session_commands_callback_AddRef(IMFAsyncCallback
*iface
)
2120 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2121 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2124 static ULONG WINAPI
session_commands_callback_Release(IMFAsyncCallback
*iface
)
2126 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2127 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2130 static HRESULT WINAPI
session_commands_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2135 static HRESULT WINAPI
session_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
2137 struct session_op
*op
= impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result
));
2138 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2139 struct topo_node
*topo_node
;
2140 IMFTopologyNode
*upstream_node
;
2141 unsigned int upstream_output
;
2143 EnterCriticalSection(&session
->cs
);
2145 switch (op
->command
)
2147 case SESSION_CMD_CLEAR_TOPOLOGIES
:
2148 session_clear_topologies(session
);
2150 case SESSION_CMD_SET_TOPOLOGY
:
2151 session_set_topology(session
, op
->u
.set_topology
.flags
, op
->u
.set_topology
.topology
);
2152 session_command_complete(session
);
2154 case SESSION_CMD_START
:
2155 session_start(session
, &op
->u
.start
.time_format
, &op
->u
.start
.start_position
);
2157 case SESSION_CMD_PAUSE
:
2158 session_pause(session
);
2160 case SESSION_CMD_STOP
:
2161 session_stop(session
);
2163 case SESSION_CMD_CLOSE
:
2164 session_close(session
);
2166 case SESSION_CMD_QM_NOTIFY_TOPOLOGY
:
2167 IMFQualityManager_NotifyTopology(session
->quality_manager
, op
->u
.notify_topology
.topology
);
2168 session_command_complete(session
);
2170 case SESSION_CMD_SA_READY
:
2171 topo_node
= session_get_node_by_id(session
, op
->u
.sa_ready
.node_id
);
2173 if (topo_node
->u
.sink
.requests
)
2175 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node
->node
, 0, &upstream_node
, &upstream_output
)))
2177 session_request_sample_from_node(session
, upstream_node
, upstream_output
);
2178 IMFTopologyNode_Release(upstream_node
);
2186 LeaveCriticalSection(&session
->cs
);
2191 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl
=
2193 session_commands_callback_QueryInterface
,
2194 session_commands_callback_AddRef
,
2195 session_commands_callback_Release
,
2196 session_commands_callback_GetParameters
,
2197 session_commands_callback_Invoke
,
2200 static HRESULT WINAPI
session_events_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2202 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2203 IsEqualIID(riid
, &IID_IUnknown
))
2206 IMFAsyncCallback_AddRef(iface
);
2210 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2212 return E_NOINTERFACE
;
2215 static ULONG WINAPI
session_events_callback_AddRef(IMFAsyncCallback
*iface
)
2217 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2218 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2221 static ULONG WINAPI
session_events_callback_Release(IMFAsyncCallback
*iface
)
2223 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2224 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2227 static HRESULT WINAPI
session_events_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2232 static HRESULT
session_add_media_stream(struct media_session
*session
, IMFMediaSource
*source
, IMFMediaStream
*stream
)
2234 struct topo_node
*node
;
2235 IMFStreamDescriptor
*sd
;
2236 DWORD stream_id
= 0;
2239 if (FAILED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
2242 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &stream_id
);
2243 IMFStreamDescriptor_Release(sd
);
2247 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2249 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->u
.source
.source
== source
2250 && node
->u
.source
.stream_id
== stream_id
)
2252 if (node
->object
.source_stream
)
2254 WARN("Node already has stream set.\n");
2258 node
->object
.source_stream
= stream
;
2259 IMFMediaStream_AddRef(node
->object
.source_stream
);
2267 static BOOL
session_is_source_nodes_state(struct media_session
*session
, enum object_state state
)
2269 struct media_source
*source
;
2270 struct topo_node
*node
;
2272 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2274 if (source
->state
!= state
)
2278 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2280 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->state
!= state
)
2287 static BOOL
session_is_output_nodes_state(struct media_session
*session
, enum object_state state
)
2289 struct topo_node
*node
;
2291 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2293 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->state
!= state
)
2300 static enum object_state
session_get_object_state_for_event(MediaEventType event
)
2304 case MESourceStarted
:
2305 case MEStreamStarted
:
2306 case MEStreamSinkStarted
:
2307 return OBJ_STATE_STARTED
;
2308 case MESourcePaused
:
2309 case MEStreamPaused
:
2310 case MEStreamSinkPaused
:
2311 return OBJ_STATE_PAUSED
;
2312 case MESourceStopped
:
2313 case MEStreamStopped
:
2314 case MEStreamSinkStopped
:
2315 return OBJ_STATE_STOPPED
;
2316 case MEStreamSinkPrerolled
:
2317 return OBJ_STATE_PREROLLED
;
2319 return OBJ_STATE_INVALID
;
2323 static void session_set_consumed_clock(IUnknown
*object
, IMFPresentationClock
*clock
)
2325 IMFClockConsumer
*consumer
;
2327 if (SUCCEEDED(IUnknown_QueryInterface(object
, &IID_IMFClockConsumer
, (void **)&consumer
)))
2329 IMFClockConsumer_SetPresentationClock(consumer
, clock
);
2330 IMFClockConsumer_Release(consumer
);
2334 static void session_set_presentation_clock(struct media_session
*session
)
2336 IMFPresentationTimeSource
*time_source
= NULL
;
2337 struct media_source
*source
;
2338 struct media_sink
*sink
;
2339 struct topo_node
*node
;
2342 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2344 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
2345 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_NOTIFY_START_OF_STREAM
, 0);
2348 if (!(session
->presentation
.flags
& SESSION_FLAG_PRESENTATION_CLOCK_SET
))
2350 /* Attempt to get time source from the sinks. */
2351 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2353 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFPresentationTimeSource
,
2354 (void **)&time_source
)))
2360 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, time_source
);
2361 IMFPresentationTimeSource_Release(time_source
);
2364 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, session
->system_time_source
);
2367 WARN("Failed to set time source, hr %#x.\n", hr
);
2369 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2371 if (node
->type
!= MF_TOPOLOGY_OUTPUT_NODE
)
2374 if (FAILED(hr
= IMFStreamSink_BeginGetEvent(node
->object
.sink_stream
, &session
->events_callback
,
2375 node
->object
.object
)))
2377 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr
);
2381 /* Set clock for all topology nodes. */
2382 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2384 session_set_consumed_clock((IUnknown
*)source
->source
, session
->clock
);
2387 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2389 if (sink
->event_generator
&& FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(sink
->event_generator
,
2390 &session
->events_callback
, (IUnknown
*)sink
->event_generator
)))
2392 WARN("Failed to subscribe to sink events, hr %#x.\n", hr
);
2395 if (FAILED(hr
= IMFMediaSink_SetPresentationClock(sink
->sink
, session
->clock
)))
2396 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr
);
2399 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2401 if (node
->type
!= MF_TOPOLOGY_TRANSFORM_NODE
)
2404 session_set_consumed_clock(node
->object
.object
, session
->clock
);
2407 session
->presentation
.flags
|= SESSION_FLAG_PRESENTATION_CLOCK_SET
;
2411 static HRESULT
session_start_clock(struct media_session
*session
)
2413 LONGLONG start_offset
= 0;
2416 if (IsEqualGUID(&session
->presentation
.time_format
, &GUID_NULL
))
2418 if (session
->presentation
.start_position
.vt
== VT_EMPTY
)
2419 start_offset
= PRESENTATION_CURRENT_POSITION
;
2420 else if (session
->presentation
.start_position
.vt
== VT_I8
)
2421 start_offset
= session
->presentation
.start_position
.hVal
.QuadPart
;
2423 FIXME("Unhandled position type %d.\n", session
->presentation
.start_position
.vt
);
2426 FIXME("Unhandled time format %s.\n", debugstr_guid(&session
->presentation
.time_format
));
2428 if (FAILED(hr
= IMFPresentationClock_Start(session
->clock
, start_offset
)))
2429 WARN("Failed to start session clock, hr %#x.\n", hr
);
2434 static struct topo_node
*session_get_node_object(struct media_session
*session
, IUnknown
*object
,
2435 MF_TOPOLOGY_TYPE node_type
)
2437 struct topo_node
*node
= NULL
;
2439 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2441 if (node
->type
== node_type
&& object
== node
->object
.object
)
2448 static BOOL
session_set_node_object_state(struct media_session
*session
, IUnknown
*object
,
2449 MF_TOPOLOGY_TYPE node_type
, enum object_state state
)
2451 struct topo_node
*node
;
2452 BOOL changed
= FALSE
;
2454 if ((node
= session_get_node_object(session
, object
, node_type
)))
2456 changed
= node
->state
!= state
;
2457 node
->state
= state
;
2463 static void session_set_source_object_state(struct media_session
*session
, IUnknown
*object
,
2464 MediaEventType event_type
)
2466 IMFStreamSink
*stream_sink
;
2467 struct media_source
*src
;
2468 struct media_sink
*sink
;
2469 enum object_state state
;
2470 struct topo_node
*node
;
2471 unsigned int i
, count
;
2472 BOOL changed
= FALSE
;
2475 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2480 case MESourceStarted
:
2481 case MESourcePaused
:
2482 case MESourceStopped
:
2484 LIST_FOR_EACH_ENTRY(src
, &session
->presentation
.sources
, struct media_source
, entry
)
2486 if (object
== (IUnknown
*)src
->source
)
2488 changed
= src
->state
!= state
;
2494 case MEStreamStarted
:
2495 case MEStreamPaused
:
2496 case MEStreamStopped
:
2498 changed
= session_set_node_object_state(session
, object
, MF_TOPOLOGY_SOURCESTREAM_NODE
, state
);
2506 switch (session
->state
)
2508 case SESSION_STATE_STARTING_SOURCES
:
2509 if (!session_is_source_nodes_state(session
, OBJ_STATE_STARTED
))
2512 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_STARTED_SOURCE
);
2514 session_set_presentation_clock(session
);
2516 if (session
->presentation
.flags
& SESSION_FLAG_NEEDS_PREROLL
)
2518 MFTIME preroll_time
= 0;
2520 if (session
->presentation
.start_position
.vt
== VT_I8
)
2521 preroll_time
= session
->presentation
.start_position
.hVal
.QuadPart
;
2523 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2524 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2528 /* FIXME: abort and enter error state on failure. */
2529 if (FAILED(hr
= IMFMediaSinkPreroll_NotifyPreroll(sink
->preroll
, preroll_time
)))
2530 WARN("Preroll notification failed, hr %#x.\n", hr
);
2534 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink
->sink
, &count
)))
2536 for (i
= 0; i
< count
; ++i
)
2538 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink
->sink
, i
, &stream_sink
)))
2540 session_set_node_object_state(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
,
2541 OBJ_STATE_PREROLLED
);
2542 IMFStreamSink_Release(stream_sink
);
2548 session
->state
= SESSION_STATE_PREROLLING_SINKS
;
2550 else if (SUCCEEDED(session_start_clock(session
)))
2551 session
->state
= SESSION_STATE_STARTING_SINKS
;
2554 case SESSION_STATE_PAUSING_SOURCES
:
2555 if (!session_is_source_nodes_state(session
, OBJ_STATE_PAUSED
))
2558 session_set_paused(session
, SESSION_STATE_PAUSED
, S_OK
);
2560 case SESSION_STATE_STOPPING_SOURCES
:
2561 if (!session_is_source_nodes_state(session
, OBJ_STATE_STOPPED
))
2564 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2568 case MF_TOPOLOGY_OUTPUT_NODE
:
2569 IMFStreamSink_Flush(node
->object
.sink_stream
);
2571 case MF_TOPOLOGY_TRANSFORM_NODE
:
2572 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
2579 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
2581 if (session
->presentation
.flags
& SESSION_FLAG_FINALIZE_SINKS
)
2582 session_finalize_sinks(session
);
2584 session_set_stopped(session
, S_OK
);
2592 static void session_set_sink_stream_state(struct media_session
*session
, IMFStreamSink
*stream
,
2593 MediaEventType event_type
)
2595 struct media_source
*source
;
2596 enum object_state state
;
2600 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2603 if (!(changed
= session_set_node_object_state(session
, (IUnknown
*)stream
, MF_TOPOLOGY_OUTPUT_NODE
, state
)))
2606 switch (session
->state
)
2608 case SESSION_STATE_PREROLLING_SINKS
:
2609 if (!session_is_output_nodes_state(session
, OBJ_STATE_PREROLLED
))
2612 if (SUCCEEDED(session_start_clock(session
)))
2613 session
->state
= SESSION_STATE_STARTING_SINKS
;
2615 case SESSION_STATE_STARTING_SINKS
:
2616 if (!session_is_output_nodes_state(session
, OBJ_STATE_STARTED
))
2619 session_set_started(session
);
2621 case SESSION_STATE_PAUSING_SINKS
:
2622 if (!session_is_output_nodes_state(session
, OBJ_STATE_PAUSED
))
2625 session
->state
= SESSION_STATE_PAUSING_SOURCES
;
2627 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2629 if (FAILED(hr
= IMFMediaSource_Pause(source
->source
)))
2634 session_set_paused(session
, SESSION_STATE_PAUSED
, hr
);
2637 case SESSION_STATE_STOPPING_SINKS
:
2638 if (!session_is_output_nodes_state(session
, OBJ_STATE_STOPPED
))
2641 session
->state
= SESSION_STATE_STOPPING_SOURCES
;
2643 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2645 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
)
2646 IMFMediaSource_Stop(source
->source
);
2647 else if (FAILED(hr
= IMFMediaSource_Stop(source
->source
)))
2651 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
|| FAILED(hr
))
2652 session_set_stopped(session
, hr
);
2660 static struct sample
*transform_create_sample(IMFSample
*sample
)
2662 struct sample
*sample_entry
= calloc(1, sizeof(*sample_entry
));
2666 sample_entry
->sample
= sample
;
2667 if (sample_entry
->sample
)
2668 IMFSample_AddRef(sample_entry
->sample
);
2671 return sample_entry
;
2674 static HRESULT
transform_get_external_output_sample(const struct media_session
*session
, struct topo_node
*transform
,
2675 unsigned int output_index
, const MFT_OUTPUT_STREAM_INFO
*stream_info
, IMFSample
**sample
)
2677 unsigned int buffer_size
, downstream_input
;
2678 IMFTopologyNode
*downstream_node
;
2679 IMFMediaBuffer
*buffer
= NULL
;
2680 struct topo_node
*topo_node
;
2684 if (FAILED(IMFTopologyNode_GetOutput(transform
->node
, output_index
, &downstream_node
, &downstream_input
)))
2686 WARN("Failed to get connected node for output %u.\n", output_index
);
2687 return MF_E_UNEXPECTED
;
2690 IMFTopologyNode_GetTopoNodeID(downstream_node
, &node_id
);
2691 IMFTopologyNode_Release(downstream_node
);
2693 topo_node
= session_get_node_by_id(session
, node_id
);
2695 if (topo_node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& topo_node
->u
.sink
.allocator
)
2697 hr
= IMFVideoSampleAllocator_AllocateSample(topo_node
->u
.sink
.allocator
, sample
);
2701 buffer_size
= max(stream_info
->cbSize
, transform
->u
.transform
.outputs
[output_index
].min_buffer_size
);
2703 hr
= MFCreateAlignedMemoryBuffer(buffer_size
, stream_info
->cbAlignment
, &buffer
);
2705 hr
= MFCreateSample(sample
);
2708 hr
= IMFSample_AddBuffer(*sample
, buffer
);
2711 IMFMediaBuffer_Release(buffer
);
2717 static HRESULT
transform_node_pull_samples(const struct media_session
*session
, struct topo_node
*node
)
2719 MFT_OUTPUT_STREAM_INFO stream_info
;
2720 MFT_OUTPUT_DATA_BUFFER
*buffers
;
2721 struct sample
*queued_sample
;
2724 HRESULT hr
= E_UNEXPECTED
;
2726 if (!(buffers
= calloc(node
->u
.transform
.output_count
, sizeof(*buffers
))))
2727 return E_OUTOFMEMORY
;
2729 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2731 buffers
[i
].dwStreamID
= transform_node_get_stream_id(node
, TRUE
, i
);
2732 buffers
[i
].pSample
= NULL
;
2733 buffers
[i
].dwStatus
= 0;
2734 buffers
[i
].pEvents
= NULL
;
2736 memset(&stream_info
, 0, sizeof(stream_info
));
2737 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(node
->object
.transform
, buffers
[i
].dwStreamID
, &stream_info
)))
2740 if (!(stream_info
.dwFlags
& (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
| MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
)))
2742 if (FAILED(hr
= transform_get_external_output_sample(session
, node
, i
, &stream_info
, &buffers
[i
].pSample
)))
2748 hr
= IMFTransform_ProcessOutput(node
->object
.transform
, 0, node
->u
.transform
.output_count
, buffers
, &status
);
2750 /* Collect returned samples for all streams. */
2751 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2753 if (buffers
[i
].pEvents
)
2754 IMFCollection_Release(buffers
[i
].pEvents
);
2756 if (SUCCEEDED(hr
) && !(buffers
[i
].dwStatus
& MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE
))
2758 if (session
->quality_manager
)
2759 IMFQualityManager_NotifyProcessOutput(session
->quality_manager
, node
->node
, i
, buffers
[i
].pSample
);
2761 queued_sample
= transform_create_sample(buffers
[i
].pSample
);
2762 list_add_tail(&node
->u
.transform
.outputs
[i
].samples
, &queued_sample
->entry
);
2765 if (buffers
[i
].pSample
)
2766 IMFSample_Release(buffers
[i
].pSample
);
2774 static void session_deliver_sample_to_node(struct media_session
*session
, IMFTopologyNode
*node
, unsigned int input
,
2777 struct sample
*sample_entry
, *sample_entry2
;
2778 DWORD stream_id
, downstream_input
;
2779 IMFTopologyNode
*downstream_node
;
2780 struct topo_node
*topo_node
;
2781 MF_TOPOLOGY_TYPE node_type
;
2787 if (session
->quality_manager
)
2788 IMFQualityManager_NotifyProcessInput(session
->quality_manager
, node
, input
, sample
);
2790 IMFTopologyNode_GetNodeType(node
, &node_type
);
2791 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2793 topo_node
= session_get_node_by_id(session
, node_id
);
2797 case MF_TOPOLOGY_OUTPUT_NODE
:
2800 if (topo_node
->u
.sink
.requests
)
2802 if (FAILED(hr
= IMFStreamSink_ProcessSample(topo_node
->object
.sink_stream
, sample
)))
2803 WARN("Stream sink failed to process sample, hr %#x.\n", hr
);
2804 topo_node
->u
.sink
.requests
--;
2807 else if (FAILED(hr
= IMFStreamSink_PlaceMarker(topo_node
->object
.sink_stream
, MFSTREAMSINK_MARKER_ENDOFSEGMENT
,
2810 WARN("Failed to place sink marker, hr %#x.\n", hr
);
2813 case MF_TOPOLOGY_TRANSFORM_NODE
:
2815 transform_node_pull_samples(session
, topo_node
);
2817 sample_entry
= transform_create_sample(sample
);
2818 list_add_tail(&topo_node
->u
.transform
.inputs
[input
].samples
, &sample_entry
->entry
);
2820 for (i
= 0; i
< topo_node
->u
.transform
.input_count
; ++i
)
2822 stream_id
= transform_node_get_stream_id(topo_node
, FALSE
, i
);
2823 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.inputs
[i
].samples
,
2824 struct sample
, entry
)
2826 if (sample_entry
->sample
)
2828 if ((hr
= IMFTransform_ProcessInput(topo_node
->object
.transform
, stream_id
,
2829 sample_entry
->sample
, 0)) == MF_E_NOTACCEPTING
)
2832 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i
, stream_id
, hr
);
2833 transform_release_sample(sample_entry
);
2837 transform_stream_drop_samples(&topo_node
->u
.transform
.inputs
[i
]);
2845 if (FAILED(hr
= IMFTransform_ProcessMessage(topo_node
->object
.transform
, MFT_MESSAGE_COMMAND_DRAIN
, 0)))
2846 WARN("Drain command failed for transform, hr %#x.\n", hr
);
2849 transform_node_pull_samples(session
, topo_node
);
2851 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2854 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2856 if ((sample_entry
= transform_create_sample(NULL
)))
2857 list_add_tail(&topo_node
->u
.transform
.outputs
[i
].samples
, &sample_entry
->entry
);
2861 /* Push down all available output. */
2862 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2864 if (FAILED(IMFTopologyNode_GetOutput(node
, i
, &downstream_node
, &downstream_input
)))
2866 WARN("Failed to get connected node for output %u.\n", i
);
2870 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.outputs
[i
].samples
,
2871 struct sample
, entry
)
2873 if (!topo_node
->u
.transform
.outputs
[i
].requests
)
2876 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample_entry
->sample
);
2877 topo_node
->u
.transform
.outputs
[i
].requests
--;
2879 transform_release_sample(sample_entry
);
2882 IMFTopologyNode_Release(downstream_node
);
2886 case MF_TOPOLOGY_TEE_NODE
:
2887 FIXME("Unhandled downstream node type %d.\n", node_type
);
2894 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
)
2896 IMFTopologyNode
*downstream_node
, *upstream_node
;
2897 unsigned int downstream_input
, upstream_output
;
2898 struct topo_node
*topo_node
;
2899 MF_TOPOLOGY_TYPE node_type
;
2900 struct sample
*sample
;
2904 IMFTopologyNode_GetNodeType(node
, &node_type
);
2905 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2907 topo_node
= session_get_node_by_id(session
, node_id
);
2911 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
2912 if (FAILED(hr
= IMFMediaStream_RequestSample(topo_node
->object
.source_stream
, NULL
)))
2913 WARN("Sample request failed, hr %#x.\n", hr
);
2915 case MF_TOPOLOGY_TRANSFORM_NODE
:
2917 if (list_empty(&topo_node
->u
.transform
.outputs
[output
].samples
))
2919 /* Forward request to upstream node. */
2920 if (SUCCEEDED(hr
= IMFTopologyNode_GetInput(node
, 0 /* FIXME */, &upstream_node
, &upstream_output
)))
2922 if (SUCCEEDED(hr
= session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2923 topo_node
->u
.transform
.outputs
[output
].requests
++;
2924 IMFTopologyNode_Release(upstream_node
);
2929 if (SUCCEEDED(hr
= IMFTopologyNode_GetOutput(node
, output
, &downstream_node
, &downstream_input
)))
2931 sample
= LIST_ENTRY(list_head(&topo_node
->u
.transform
.outputs
[output
].samples
), struct sample
, entry
);
2932 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample
->sample
);
2933 transform_release_sample(sample
);
2934 IMFTopologyNode_Release(downstream_node
);
2939 case MF_TOPOLOGY_TEE_NODE
:
2940 FIXME("Unhandled upstream node type %d.\n", node_type
);
2948 static void session_request_sample(struct media_session
*session
, IMFStreamSink
*sink_stream
)
2950 struct topo_node
*sink_node
= NULL
, *node
;
2951 IMFTopologyNode
*upstream_node
;
2952 DWORD upstream_output
;
2955 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2957 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink_stream
)
2967 if (FAILED(hr
= IMFTopologyNode_GetInput(sink_node
->node
, 0, &upstream_node
, &upstream_output
)))
2969 WARN("Failed to get upstream node connection, hr %#x.\n", hr
);
2973 if (SUCCEEDED(session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2974 sink_node
->u
.sink
.requests
++;
2975 IMFTopologyNode_Release(upstream_node
);
2978 static void session_deliver_sample(struct media_session
*session
, IMFMediaStream
*stream
, const PROPVARIANT
*value
)
2980 struct topo_node
*source_node
= NULL
, *node
;
2981 IMFTopologyNode
*downstream_node
;
2982 DWORD downstream_input
;
2985 if (value
&& (value
->vt
!= VT_UNKNOWN
|| !value
->punkVal
))
2987 WARN("Unexpected value type %d.\n", value
->vt
);
2991 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2993 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->object
.source_stream
== stream
)
3004 source_node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3006 if (FAILED(hr
= IMFTopologyNode_GetOutput(source_node
->node
, 0, &downstream_node
, &downstream_input
)))
3008 WARN("Failed to get downstream node connection, hr %#x.\n", hr
);
3012 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, value
? (IMFSample
*)value
->punkVal
: NULL
);
3013 IMFTopologyNode_Release(downstream_node
);
3016 static void session_sink_invalidated(struct media_session
*session
, IMFMediaEvent
*event
, IMFStreamSink
*sink
)
3018 struct topo_node
*node
, *sink_node
= NULL
;
3021 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3023 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink
)
3035 if (FAILED(hr
= MFCreateMediaEvent(MESinkInvalidated
, &GUID_NULL
, S_OK
, NULL
, &event
)))
3036 WARN("Failed to create event, hr %#x.\n", hr
);
3042 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_OUTPUT_NODE
, sink_node
->node_id
);
3043 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3045 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3048 static BOOL
session_nodes_is_mask_set(struct media_session
*session
, MF_TOPOLOGY_TYPE node_type
, unsigned int flags
)
3050 struct media_source
*source
;
3051 struct topo_node
*node
;
3053 if (node_type
== MF_TOPOLOGY_MAX
)
3055 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3057 if ((source
->flags
& flags
) != flags
)
3063 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3065 if (node
->type
== node_type
&& (node
->flags
& flags
) != flags
)
3073 static void session_raise_end_of_presentation(struct media_session
*session
)
3075 if (!(session_nodes_is_mask_set(session
, MF_TOPOLOGY_SOURCESTREAM_NODE
, TOPO_NODE_END_OF_STREAM
)))
3078 if (!(session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
))
3080 if (session_nodes_is_mask_set(session
, MF_TOPOLOGY_MAX
, SOURCE_FLAG_END_OF_PRESENTATION
))
3082 session
->presentation
.flags
|= SESSION_FLAG_END_OF_PRESENTATION
;
3083 session_push_back_command(session
, SESSION_CMD_END
);
3084 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MEEndOfPresentation
, &GUID_NULL
, S_OK
, NULL
);
3089 static void session_handle_end_of_stream(struct media_session
*session
, IMFMediaStream
*stream
)
3091 struct topo_node
*node
;
3093 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream
, MF_TOPOLOGY_SOURCESTREAM_NODE
))
3094 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3099 session_deliver_sample(session
, stream
, NULL
);
3101 session_raise_end_of_presentation(session
);
3104 static void session_handle_end_of_presentation(struct media_session
*session
, IMFMediaSource
*object
)
3106 struct media_source
*source
;
3108 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3110 if (source
->source
== object
)
3112 if (!(source
->flags
& SOURCE_FLAG_END_OF_PRESENTATION
))
3114 source
->flags
|= SOURCE_FLAG_END_OF_PRESENTATION
;
3115 session_raise_end_of_presentation(session
);
3123 static void session_sink_stream_marker(struct media_session
*session
, IMFStreamSink
*stream_sink
)
3125 struct topo_node
*node
;
3127 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
))
3128 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3133 node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3135 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
&&
3136 session_nodes_is_mask_set(session
, MF_TOPOLOGY_OUTPUT_NODE
, TOPO_NODE_END_OF_STREAM
))
3138 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3139 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
3140 session_stop(session
);
3144 static HRESULT WINAPI
session_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3146 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
3147 IMFMediaEventGenerator
*event_source
;
3148 IMFMediaEvent
*event
= NULL
;
3149 MediaEventType event_type
;
3150 IUnknown
*object
= NULL
;
3151 IMFMediaSource
*source
;
3152 IMFMediaStream
*stream
;
3156 if (FAILED(hr
= IMFAsyncResult_GetState(result
, (IUnknown
**)&event_source
)))
3159 if (FAILED(hr
= IMFMediaEventGenerator_EndGetEvent(event_source
, result
, &event
)))
3161 WARN("Failed to get event from %p, hr %#x.\n", event_source
, hr
);
3165 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
3167 WARN("Failed to get event type, hr %#x.\n", hr
);
3171 value
.vt
= VT_EMPTY
;
3172 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
3174 WARN("Failed to get event value, hr %#x.\n", hr
);
3180 case MESourceStarted
:
3181 case MESourcePaused
:
3182 case MESourceStopped
:
3183 case MEStreamStarted
:
3184 case MEStreamPaused
:
3185 case MEStreamStopped
:
3187 EnterCriticalSection(&session
->cs
);
3188 session_set_source_object_state(session
, (IUnknown
*)event_source
, event_type
);
3189 LeaveCriticalSection(&session
->cs
);
3193 case MEBufferingStarted
:
3194 case MEBufferingStopped
:
3196 EnterCriticalSection(&session
->cs
);
3197 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3199 if (event_type
== MEBufferingStarted
)
3200 IMFPresentationClock_Pause(session
->clock
);
3202 IMFPresentationClock_Start(session
->clock
, PRESENTATION_CURRENT_POSITION
);
3204 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3206 LeaveCriticalSection(&session
->cs
);
3209 case MEReconnectStart
:
3210 case MEReconnectEnd
:
3212 EnterCriticalSection(&session
->cs
);
3213 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3214 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3215 LeaveCriticalSection(&session
->cs
);
3218 case MEExtendedType
:
3219 case MERendererEvent
:
3220 case MEStreamSinkFormatChanged
:
3222 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3226 stream
= (IMFMediaStream
*)value
.punkVal
;
3228 if (value
.vt
!= VT_UNKNOWN
|| !stream
)
3230 WARN("Unexpected event value.\n");
3234 if (FAILED(hr
= IMFMediaStream_GetMediaSource(stream
, &source
)))
3237 EnterCriticalSection(&session
->cs
);
3238 if (SUCCEEDED(hr
= session_add_media_stream(session
, source
, stream
)))
3239 hr
= IMFMediaStream_BeginGetEvent(stream
, &session
->events_callback
, (IUnknown
*)stream
);
3240 LeaveCriticalSection(&session
->cs
);
3242 IMFMediaSource_Release(source
);
3245 case MEStreamSinkStarted
:
3246 case MEStreamSinkPaused
:
3247 case MEStreamSinkStopped
:
3248 case MEStreamSinkPrerolled
:
3250 EnterCriticalSection(&session
->cs
);
3251 session_set_sink_stream_state(session
, (IMFStreamSink
*)event_source
, event_type
);
3252 LeaveCriticalSection(&session
->cs
);
3255 case MEStreamSinkMarker
:
3257 EnterCriticalSection(&session
->cs
);
3258 session_sink_stream_marker(session
, (IMFStreamSink
*)event_source
);
3259 LeaveCriticalSection(&session
->cs
);
3262 case MEStreamSinkRequestSample
:
3264 EnterCriticalSection(&session
->cs
);
3265 session_request_sample(session
, (IMFStreamSink
*)event_source
);
3266 LeaveCriticalSection(&session
->cs
);
3271 EnterCriticalSection(&session
->cs
);
3272 session_deliver_sample(session
, (IMFMediaStream
*)event_source
, &value
);
3273 LeaveCriticalSection(&session
->cs
);
3278 EnterCriticalSection(&session
->cs
);
3279 session_handle_end_of_stream(session
, (IMFMediaStream
*)event_source
);
3280 LeaveCriticalSection(&session
->cs
);
3284 case MEEndOfPresentation
:
3286 EnterCriticalSection(&session
->cs
);
3287 session_handle_end_of_presentation(session
, (IMFMediaSource
*)event_source
);
3288 LeaveCriticalSection(&session
->cs
);
3291 case MEAudioSessionGroupingParamChanged
:
3292 case MEAudioSessionIconChanged
:
3293 case MEAudioSessionNameChanged
:
3294 case MEAudioSessionVolumeChanged
:
3296 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3299 case MEAudioSessionDeviceRemoved
:
3300 case MEAudioSessionDisconnected
:
3301 case MEAudioSessionExclusiveModeOverride
:
3302 case MEAudioSessionFormatChanged
:
3303 case MEAudioSessionServerShutdown
:
3305 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3307 case MESinkInvalidated
:
3309 EnterCriticalSection(&session
->cs
);
3310 session_sink_invalidated(session
, event_type
== MESinkInvalidated
? event
: NULL
,
3311 (IMFStreamSink
*)event_source
);
3312 LeaveCriticalSection(&session
->cs
);
3315 case MEQualityNotify
:
3317 if (session
->quality_manager
)
3319 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFStreamSink
, (void **)&object
)))
3320 IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFTransform
, (void **)&object
);
3324 IMFQualityManager_NotifyQualityEvent(session
->quality_manager
, object
, event
);
3325 IUnknown_Release(object
);
3334 PropVariantClear(&value
);
3338 IMFMediaEvent_Release(event
);
3340 if (FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(event_source
, iface
, (IUnknown
*)event_source
)))
3341 WARN("Failed to re-subscribe, hr %#x.\n", hr
);
3343 IMFMediaEventGenerator_Release(event_source
);
3348 static const IMFAsyncCallbackVtbl session_events_callback_vtbl
=
3350 session_events_callback_QueryInterface
,
3351 session_events_callback_AddRef
,
3352 session_events_callback_Release
,
3353 session_events_callback_GetParameters
,
3354 session_events_callback_Invoke
,
3357 static HRESULT WINAPI
session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
3359 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
3360 IsEqualIID(riid
, &IID_IUnknown
))
3363 IMFAsyncCallback_AddRef(iface
);
3367 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3369 return E_NOINTERFACE
;
3372 static ULONG WINAPI
session_sink_finalizer_callback_AddRef(IMFAsyncCallback
*iface
)
3374 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3375 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3378 static ULONG WINAPI
session_sink_finalizer_callback_Release(IMFAsyncCallback
*iface
)
3380 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3381 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3384 static HRESULT WINAPI
session_sink_finalizer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
3389 static HRESULT WINAPI
session_sink_finalizer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3391 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3392 IMFFinalizableMediaSink
*fin_sink
= NULL
;
3393 BOOL sinks_finalized
= TRUE
;
3394 struct media_sink
*sink
;
3398 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
3401 EnterCriticalSection(&session
->cs
);
3403 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3405 if (state
== (IUnknown
*)sink
->sink
)
3407 if (FAILED(hr
= IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
3408 WARN("Unexpected, missing IMFFinalizableMediaSink, hr %#x.\n", hr
);
3412 sinks_finalized
&= sink
->finalized
;
3413 if (!sinks_finalized
)
3418 IUnknown_Release(state
);
3422 /* Complete session transition, or close prematurely on error. */
3423 if (SUCCEEDED(hr
= IMFFinalizableMediaSink_EndFinalize(fin_sink
, result
)))
3425 sink
->finalized
= TRUE
;
3426 if (sinks_finalized
)
3427 session_set_closed(session
, hr
);
3429 IMFFinalizableMediaSink_Release(fin_sink
);
3432 LeaveCriticalSection(&session
->cs
);
3437 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl
=
3439 session_sink_finalizer_callback_QueryInterface
,
3440 session_sink_finalizer_callback_AddRef
,
3441 session_sink_finalizer_callback_Release
,
3442 session_sink_finalizer_callback_GetParameters
,
3443 session_sink_finalizer_callback_Invoke
,
3446 static HRESULT WINAPI
session_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
3448 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3449 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3452 static ULONG WINAPI
session_rate_support_AddRef(IMFRateSupport
*iface
)
3454 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3455 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3458 static ULONG WINAPI
session_rate_support_Release(IMFRateSupport
*iface
)
3460 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3461 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3464 static HRESULT
session_presentation_object_get_rate(IUnknown
*object
, MFRATE_DIRECTION direction
,
3465 BOOL thin
, BOOL fastest
, float *result
)
3467 IMFRateSupport
*rate_support
;
3471 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3473 if (FAILED(hr
= MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
3475 if (direction
== MFRATE_FORWARD
)
3481 return MF_E_REVERSE_UNSUPPORTED
;
3487 if (SUCCEEDED(hr
= IMFRateSupport_GetFastestRate(rate_support
, direction
, thin
, &rate
)))
3488 *result
= min(fabsf(rate
), *result
);
3492 if (SUCCEEDED(hr
= IMFRateSupport_GetSlowestRate(rate_support
, direction
, thin
, &rate
)))
3493 *result
= max(fabsf(rate
), *result
);
3496 IMFRateSupport_Release(rate_support
);
3501 static HRESULT
session_get_presentation_rate(struct media_session
*session
, MFRATE_DIRECTION direction
,
3502 BOOL thin
, BOOL fastest
, float *result
)
3504 struct media_source
*source
;
3505 struct media_sink
*sink
;
3506 HRESULT hr
= E_POINTER
;
3509 rate
= fastest
? FLT_MAX
: 0.0f
;
3511 EnterCriticalSection(&session
->cs
);
3513 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
3515 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3517 if (FAILED(hr
= session_presentation_object_get_rate((IUnknown
*)source
->source
, direction
, thin
, fastest
, &rate
)))
3523 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3525 if (FAILED(hr
= session_presentation_object_get_rate((IUnknown
*)sink
->sink
, direction
, thin
, fastest
, &rate
)))
3531 LeaveCriticalSection(&session
->cs
);
3534 *result
= direction
== MFRATE_FORWARD
? rate
: -rate
;
3539 static HRESULT WINAPI
session_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3540 BOOL thin
, float *rate
)
3542 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3544 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3546 return session_get_presentation_rate(session
, direction
, thin
, FALSE
, rate
);
3549 static HRESULT WINAPI
session_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3550 BOOL thin
, float *rate
)
3552 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3554 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3556 return session_get_presentation_rate(session
, direction
, thin
, TRUE
, rate
);
3559 static HRESULT WINAPI
session_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
3560 float *nearest_supported_rate
)
3562 FIXME("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_supported_rate
);
3567 static const IMFRateSupportVtbl session_rate_support_vtbl
=
3569 session_rate_support_QueryInterface
,
3570 session_rate_support_AddRef
,
3571 session_rate_support_Release
,
3572 session_rate_support_GetSlowestRate
,
3573 session_rate_support_GetFastestRate
,
3574 session_rate_support_IsRateSupported
,
3577 static HRESULT WINAPI
session_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
3579 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3580 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3583 static ULONG WINAPI
session_rate_control_AddRef(IMFRateControl
*iface
)
3585 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3586 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3589 static ULONG WINAPI
session_rate_control_Release(IMFRateControl
*iface
)
3591 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3592 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3595 static HRESULT WINAPI
session_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
3597 FIXME("%p, %d, %f.\n", iface
, thin
, rate
);
3602 static HRESULT WINAPI
session_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
3604 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3606 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
3608 return IMFRateControl_GetRate(session
->clock_rate_control
, thin
, rate
);
3611 static const IMFRateControlVtbl session_rate_control_vtbl
=
3613 session_rate_control_QueryInterface
,
3614 session_rate_control_AddRef
,
3615 session_rate_control_Release
,
3616 session_rate_control_SetRate
,
3617 session_rate_control_GetRate
,
3620 static HRESULT WINAPI
node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor
*iface
,
3621 REFIID riid
, void **obj
)
3623 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
3625 if (IsEqualIID(riid
, &IID_IMFTopologyNodeAttributeEditor
) ||
3626 IsEqualIID(riid
, &IID_IUnknown
))
3629 IMFTopologyNodeAttributeEditor_AddRef(iface
);
3633 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
3635 return E_NOINTERFACE
;
3638 static ULONG WINAPI
node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor
*iface
)
3640 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
3641 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3644 static ULONG WINAPI
node_attribute_editor_Release(IMFTopologyNodeAttributeEditor
*iface
)
3646 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
3647 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3650 static HRESULT WINAPI
node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor
*iface
,
3651 TOPOID id
, DWORD count
, MFTOPONODE_ATTRIBUTE_UPDATE
*updates
)
3653 FIXME("%p, %s, %u, %p.\n", iface
, wine_dbgstr_longlong(id
), count
, updates
);
3658 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl
=
3660 node_attribute_editor_QueryInterface
,
3661 node_attribute_editor_AddRef
,
3662 node_attribute_editor_Release
,
3663 node_attribute_editor_UpdateNodeAttributes
,
3666 /***********************************************************************
3667 * MFCreateMediaSession (mf.@)
3669 HRESULT WINAPI
MFCreateMediaSession(IMFAttributes
*config
, IMFMediaSession
**session
)
3671 BOOL without_quality_manager
= FALSE
;
3672 struct media_session
*object
;
3675 TRACE("%p, %p.\n", config
, session
);
3677 if (!(object
= calloc(1, sizeof(*object
))))
3678 return E_OUTOFMEMORY
;
3680 object
->IMFMediaSession_iface
.lpVtbl
= &mfmediasessionvtbl
;
3681 object
->IMFGetService_iface
.lpVtbl
= &session_get_service_vtbl
;
3682 object
->IMFRateSupport_iface
.lpVtbl
= &session_rate_support_vtbl
;
3683 object
->IMFRateControl_iface
.lpVtbl
= &session_rate_control_vtbl
;
3684 object
->IMFTopologyNodeAttributeEditor_iface
.lpVtbl
= &node_attribute_editor_vtbl
;
3685 object
->commands_callback
.lpVtbl
= &session_commands_callback_vtbl
;
3686 object
->events_callback
.lpVtbl
= &session_events_callback_vtbl
;
3687 object
->sink_finalizer_callback
.lpVtbl
= &session_sink_finalizer_callback_vtbl
;
3688 object
->refcount
= 1;
3689 list_init(&object
->topologies
);
3690 list_init(&object
->commands
);
3691 list_init(&object
->presentation
.sources
);
3692 list_init(&object
->presentation
.sinks
);
3693 list_init(&object
->presentation
.nodes
);
3694 InitializeCriticalSection(&object
->cs
);
3696 if (FAILED(hr
= MFCreateTopology(&object
->presentation
.current_topology
)))
3699 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
3702 if (FAILED(hr
= MFCreatePresentationClock(&object
->clock
)))
3705 if (FAILED(hr
= MFCreateSystemTimeSource(&object
->system_time_source
)))
3708 if (FAILED(hr
= IMFPresentationClock_QueryInterface(object
->clock
, &IID_IMFRateControl
,
3709 (void **)&object
->clock_rate_control
)))
3718 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_TOPOLOADER
, &clsid
)))
3720 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTopoLoader
,
3721 (void **)&object
->topo_loader
)))
3723 WARN("Failed to create custom topology loader, hr %#x.\n", hr
);
3727 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_QUALITY_MANAGER
, &clsid
)))
3729 if (!(without_quality_manager
= IsEqualGUID(&clsid
, &GUID_NULL
)))
3731 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFQualityManager
,
3732 (void **)&object
->quality_manager
)))
3734 WARN("Failed to create custom quality manager, hr %#x.\n", hr
);
3740 if (!object
->topo_loader
&& FAILED(hr
= MFCreateTopoLoader(&object
->topo_loader
)))
3743 if (!object
->quality_manager
&& !without_quality_manager
&&
3744 FAILED(hr
= MFCreateStandardQualityManager(&object
->quality_manager
)))
3749 if (object
->quality_manager
&& FAILED(hr
= IMFQualityManager_NotifyPresentationClock(object
->quality_manager
,
3755 *session
= &object
->IMFMediaSession_iface
;
3760 IMFMediaSession_Release(&object
->IMFMediaSession_iface
);
3764 static HRESULT WINAPI
standard_quality_manager_QueryInterface(IMFQualityManager
*iface
, REFIID riid
, void **out
)
3766 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3768 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
3770 if (IsEqualIID(riid
, &IID_IMFQualityManager
) ||
3771 IsEqualIID(riid
, &IID_IUnknown
))
3775 else if (IsEqualIID(riid
, &IID_IMFClockStateSink
))
3777 *out
= &manager
->IMFClockStateSink_iface
;
3781 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3783 return E_NOINTERFACE
;
3786 IUnknown_AddRef((IUnknown
*)*out
);
3790 static ULONG WINAPI
standard_quality_manager_AddRef(IMFQualityManager
*iface
)
3792 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3793 ULONG refcount
= InterlockedIncrement(&manager
->refcount
);
3795 TRACE("%p, refcount %u.\n", iface
, refcount
);
3800 static ULONG WINAPI
standard_quality_manager_Release(IMFQualityManager
*iface
)
3802 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3803 ULONG refcount
= InterlockedDecrement(&manager
->refcount
);
3805 TRACE("%p, refcount %u.\n", iface
, refcount
);
3810 IMFPresentationClock_Release(manager
->clock
);
3811 if (manager
->topology
)
3812 IMFTopology_Release(manager
->topology
);
3813 DeleteCriticalSection(&manager
->cs
);
3820 static void standard_quality_manager_set_topology(struct quality_manager
*manager
, IMFTopology
*topology
)
3822 if (manager
->topology
)
3823 IMFTopology_Release(manager
->topology
);
3824 manager
->topology
= topology
;
3825 if (manager
->topology
)
3826 IMFTopology_AddRef(manager
->topology
);
3829 static HRESULT WINAPI
standard_quality_manager_NotifyTopology(IMFQualityManager
*iface
, IMFTopology
*topology
)
3831 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3834 TRACE("%p, %p.\n", iface
, topology
);
3836 EnterCriticalSection(&manager
->cs
);
3837 if (manager
->state
== QUALITY_MANAGER_SHUT_DOWN
)
3841 standard_quality_manager_set_topology(manager
, topology
);
3843 LeaveCriticalSection(&manager
->cs
);
3848 static void standard_quality_manager_release_clock(struct quality_manager
*manager
)
3852 IMFPresentationClock_RemoveClockStateSink(manager
->clock
, &manager
->IMFClockStateSink_iface
);
3853 IMFPresentationClock_Release(manager
->clock
);
3855 manager
->clock
= NULL
;
3858 static HRESULT WINAPI
standard_quality_manager_NotifyPresentationClock(IMFQualityManager
*iface
,
3859 IMFPresentationClock
*clock
)
3861 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3864 TRACE("%p, %p.\n", iface
, clock
);
3866 EnterCriticalSection(&manager
->cs
);
3867 if (manager
->state
== QUALITY_MANAGER_SHUT_DOWN
)
3873 standard_quality_manager_release_clock(manager
);
3874 manager
->clock
= clock
;
3875 IMFPresentationClock_AddRef(manager
->clock
);
3876 if (FAILED(IMFPresentationClock_AddClockStateSink(manager
->clock
, &manager
->IMFClockStateSink_iface
)))
3877 WARN("Failed to set state sink.\n");
3879 LeaveCriticalSection(&manager
->cs
);
3884 static HRESULT WINAPI
standard_quality_manager_NotifyProcessInput(IMFQualityManager
*iface
, IMFTopologyNode
*node
,
3885 LONG input_index
, IMFSample
*sample
)
3887 TRACE("%p, %p, %d, %p stub.\n", iface
, node
, input_index
, sample
);
3892 static HRESULT WINAPI
standard_quality_manager_NotifyProcessOutput(IMFQualityManager
*iface
, IMFTopologyNode
*node
,
3893 LONG output_index
, IMFSample
*sample
)
3895 TRACE("%p, %p, %d, %p stub.\n", iface
, node
, output_index
, sample
);
3900 static HRESULT WINAPI
standard_quality_manager_NotifyQualityEvent(IMFQualityManager
*iface
, IUnknown
*object
,
3901 IMFMediaEvent
*event
)
3903 FIXME("%p, %p, %p stub.\n", iface
, object
, event
);
3908 static HRESULT WINAPI
standard_quality_manager_Shutdown(IMFQualityManager
*iface
)
3910 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3912 TRACE("%p.\n", iface
);
3914 EnterCriticalSection(&manager
->cs
);
3915 if (manager
->state
!= QUALITY_MANAGER_SHUT_DOWN
)
3917 standard_quality_manager_release_clock(manager
);
3918 standard_quality_manager_set_topology(manager
, NULL
);
3919 manager
->state
= QUALITY_MANAGER_SHUT_DOWN
;
3921 LeaveCriticalSection(&manager
->cs
);
3926 static const IMFQualityManagerVtbl standard_quality_manager_vtbl
=
3928 standard_quality_manager_QueryInterface
,
3929 standard_quality_manager_AddRef
,
3930 standard_quality_manager_Release
,
3931 standard_quality_manager_NotifyTopology
,
3932 standard_quality_manager_NotifyPresentationClock
,
3933 standard_quality_manager_NotifyProcessInput
,
3934 standard_quality_manager_NotifyProcessOutput
,
3935 standard_quality_manager_NotifyQualityEvent
,
3936 standard_quality_manager_Shutdown
,
3939 static HRESULT WINAPI
standard_quality_manager_sink_QueryInterface(IMFClockStateSink
*iface
,
3940 REFIID riid
, void **obj
)
3942 struct quality_manager
*manager
= impl_from_qm_IMFClockStateSink(iface
);
3943 return IMFQualityManager_QueryInterface(&manager
->IMFQualityManager_iface
, riid
, obj
);
3946 static ULONG WINAPI
standard_quality_manager_sink_AddRef(IMFClockStateSink
*iface
)
3948 struct quality_manager
*manager
= impl_from_qm_IMFClockStateSink(iface
);
3949 return IMFQualityManager_AddRef(&manager
->IMFQualityManager_iface
);
3952 static ULONG WINAPI
standard_quality_manager_sink_Release(IMFClockStateSink
*iface
)
3954 struct quality_manager
*manager
= impl_from_qm_IMFClockStateSink(iface
);
3955 return IMFQualityManager_Release(&manager
->IMFQualityManager_iface
);
3958 static HRESULT WINAPI
standard_quality_manager_sink_OnClockStart(IMFClockStateSink
*iface
,
3959 MFTIME systime
, LONGLONG offset
)
3964 static HRESULT WINAPI
standard_quality_manager_sink_OnClockStop(IMFClockStateSink
*iface
,
3970 static HRESULT WINAPI
standard_quality_manager_sink_OnClockPause(IMFClockStateSink
*iface
,
3976 static HRESULT WINAPI
standard_quality_manager_sink_OnClockRestart(IMFClockStateSink
*iface
,
3982 static HRESULT WINAPI
standard_quality_manager_sink_OnClockSetRate(IMFClockStateSink
*iface
,
3983 MFTIME systime
, float rate
)
3988 static const IMFClockStateSinkVtbl standard_quality_manager_sink_vtbl
=
3990 standard_quality_manager_sink_QueryInterface
,
3991 standard_quality_manager_sink_AddRef
,
3992 standard_quality_manager_sink_Release
,
3993 standard_quality_manager_sink_OnClockStart
,
3994 standard_quality_manager_sink_OnClockStop
,
3995 standard_quality_manager_sink_OnClockPause
,
3996 standard_quality_manager_sink_OnClockRestart
,
3997 standard_quality_manager_sink_OnClockSetRate
,
4000 HRESULT WINAPI
MFCreateStandardQualityManager(IMFQualityManager
**manager
)
4002 struct quality_manager
*object
;
4004 TRACE("%p.\n", manager
);
4006 if (!(object
= calloc(1, sizeof(*object
))))
4007 return E_OUTOFMEMORY
;
4009 object
->IMFQualityManager_iface
.lpVtbl
= &standard_quality_manager_vtbl
;
4010 object
->IMFClockStateSink_iface
.lpVtbl
= &standard_quality_manager_sink_vtbl
;
4011 object
->refcount
= 1;
4012 InitializeCriticalSection(&object
->cs
);
4014 *manager
= &object
->IMFQualityManager_iface
;