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
) ||
2084 IsEqualGUID(service
, &MR_STREAM_VOLUME_SERVICE
))
2086 hr
= session_get_audio_render_service(session
, service
, riid
, obj
);
2089 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
2091 LeaveCriticalSection(&session
->cs
);
2096 static const IMFGetServiceVtbl session_get_service_vtbl
=
2098 session_get_service_QueryInterface
,
2099 session_get_service_AddRef
,
2100 session_get_service_Release
,
2101 session_get_service_GetService
,
2104 static HRESULT WINAPI
session_commands_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2106 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2107 IsEqualIID(riid
, &IID_IUnknown
))
2110 IMFAsyncCallback_AddRef(iface
);
2114 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2116 return E_NOINTERFACE
;
2119 static ULONG WINAPI
session_commands_callback_AddRef(IMFAsyncCallback
*iface
)
2121 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2122 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2125 static ULONG WINAPI
session_commands_callback_Release(IMFAsyncCallback
*iface
)
2127 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2128 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2131 static HRESULT WINAPI
session_commands_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2136 static HRESULT WINAPI
session_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
2138 struct session_op
*op
= impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result
));
2139 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2140 struct topo_node
*topo_node
;
2141 IMFTopologyNode
*upstream_node
;
2142 unsigned int upstream_output
;
2144 EnterCriticalSection(&session
->cs
);
2146 switch (op
->command
)
2148 case SESSION_CMD_CLEAR_TOPOLOGIES
:
2149 session_clear_topologies(session
);
2151 case SESSION_CMD_SET_TOPOLOGY
:
2152 session_set_topology(session
, op
->u
.set_topology
.flags
, op
->u
.set_topology
.topology
);
2153 session_command_complete(session
);
2155 case SESSION_CMD_START
:
2156 session_start(session
, &op
->u
.start
.time_format
, &op
->u
.start
.start_position
);
2158 case SESSION_CMD_PAUSE
:
2159 session_pause(session
);
2161 case SESSION_CMD_STOP
:
2162 session_stop(session
);
2164 case SESSION_CMD_CLOSE
:
2165 session_close(session
);
2167 case SESSION_CMD_QM_NOTIFY_TOPOLOGY
:
2168 IMFQualityManager_NotifyTopology(session
->quality_manager
, op
->u
.notify_topology
.topology
);
2169 session_command_complete(session
);
2171 case SESSION_CMD_SA_READY
:
2172 topo_node
= session_get_node_by_id(session
, op
->u
.sa_ready
.node_id
);
2174 if (topo_node
->u
.sink
.requests
)
2176 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node
->node
, 0, &upstream_node
, &upstream_output
)))
2178 session_request_sample_from_node(session
, upstream_node
, upstream_output
);
2179 IMFTopologyNode_Release(upstream_node
);
2187 LeaveCriticalSection(&session
->cs
);
2192 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl
=
2194 session_commands_callback_QueryInterface
,
2195 session_commands_callback_AddRef
,
2196 session_commands_callback_Release
,
2197 session_commands_callback_GetParameters
,
2198 session_commands_callback_Invoke
,
2201 static HRESULT WINAPI
session_events_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2203 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2204 IsEqualIID(riid
, &IID_IUnknown
))
2207 IMFAsyncCallback_AddRef(iface
);
2211 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2213 return E_NOINTERFACE
;
2216 static ULONG WINAPI
session_events_callback_AddRef(IMFAsyncCallback
*iface
)
2218 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2219 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2222 static ULONG WINAPI
session_events_callback_Release(IMFAsyncCallback
*iface
)
2224 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2225 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2228 static HRESULT WINAPI
session_events_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2233 static HRESULT
session_add_media_stream(struct media_session
*session
, IMFMediaSource
*source
, IMFMediaStream
*stream
)
2235 struct topo_node
*node
;
2236 IMFStreamDescriptor
*sd
;
2237 DWORD stream_id
= 0;
2240 if (FAILED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
2243 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &stream_id
);
2244 IMFStreamDescriptor_Release(sd
);
2248 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2250 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->u
.source
.source
== source
2251 && node
->u
.source
.stream_id
== stream_id
)
2253 if (node
->object
.source_stream
)
2255 WARN("Node already has stream set.\n");
2259 node
->object
.source_stream
= stream
;
2260 IMFMediaStream_AddRef(node
->object
.source_stream
);
2268 static BOOL
session_is_source_nodes_state(struct media_session
*session
, enum object_state state
)
2270 struct media_source
*source
;
2271 struct topo_node
*node
;
2273 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2275 if (source
->state
!= state
)
2279 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2281 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->state
!= state
)
2288 static BOOL
session_is_output_nodes_state(struct media_session
*session
, enum object_state state
)
2290 struct topo_node
*node
;
2292 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2294 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->state
!= state
)
2301 static enum object_state
session_get_object_state_for_event(MediaEventType event
)
2305 case MESourceStarted
:
2306 case MEStreamStarted
:
2307 case MEStreamSinkStarted
:
2308 return OBJ_STATE_STARTED
;
2309 case MESourcePaused
:
2310 case MEStreamPaused
:
2311 case MEStreamSinkPaused
:
2312 return OBJ_STATE_PAUSED
;
2313 case MESourceStopped
:
2314 case MEStreamStopped
:
2315 case MEStreamSinkStopped
:
2316 return OBJ_STATE_STOPPED
;
2317 case MEStreamSinkPrerolled
:
2318 return OBJ_STATE_PREROLLED
;
2320 return OBJ_STATE_INVALID
;
2324 static void session_set_consumed_clock(IUnknown
*object
, IMFPresentationClock
*clock
)
2326 IMFClockConsumer
*consumer
;
2328 if (SUCCEEDED(IUnknown_QueryInterface(object
, &IID_IMFClockConsumer
, (void **)&consumer
)))
2330 IMFClockConsumer_SetPresentationClock(consumer
, clock
);
2331 IMFClockConsumer_Release(consumer
);
2335 static void session_set_presentation_clock(struct media_session
*session
)
2337 IMFPresentationTimeSource
*time_source
= NULL
;
2338 struct media_source
*source
;
2339 struct media_sink
*sink
;
2340 struct topo_node
*node
;
2343 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2345 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
2346 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_NOTIFY_START_OF_STREAM
, 0);
2349 if (!(session
->presentation
.flags
& SESSION_FLAG_PRESENTATION_CLOCK_SET
))
2351 /* Attempt to get time source from the sinks. */
2352 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2354 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFPresentationTimeSource
,
2355 (void **)&time_source
)))
2361 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, time_source
);
2362 IMFPresentationTimeSource_Release(time_source
);
2365 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, session
->system_time_source
);
2368 WARN("Failed to set time source, hr %#x.\n", hr
);
2370 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2372 if (node
->type
!= MF_TOPOLOGY_OUTPUT_NODE
)
2375 if (FAILED(hr
= IMFStreamSink_BeginGetEvent(node
->object
.sink_stream
, &session
->events_callback
,
2376 node
->object
.object
)))
2378 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr
);
2382 /* Set clock for all topology nodes. */
2383 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2385 session_set_consumed_clock((IUnknown
*)source
->source
, session
->clock
);
2388 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2390 if (sink
->event_generator
&& FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(sink
->event_generator
,
2391 &session
->events_callback
, (IUnknown
*)sink
->event_generator
)))
2393 WARN("Failed to subscribe to sink events, hr %#x.\n", hr
);
2396 if (FAILED(hr
= IMFMediaSink_SetPresentationClock(sink
->sink
, session
->clock
)))
2397 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr
);
2400 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2402 if (node
->type
!= MF_TOPOLOGY_TRANSFORM_NODE
)
2405 session_set_consumed_clock(node
->object
.object
, session
->clock
);
2408 session
->presentation
.flags
|= SESSION_FLAG_PRESENTATION_CLOCK_SET
;
2412 static HRESULT
session_start_clock(struct media_session
*session
)
2414 LONGLONG start_offset
= 0;
2417 if (IsEqualGUID(&session
->presentation
.time_format
, &GUID_NULL
))
2419 if (session
->presentation
.start_position
.vt
== VT_EMPTY
)
2420 start_offset
= PRESENTATION_CURRENT_POSITION
;
2421 else if (session
->presentation
.start_position
.vt
== VT_I8
)
2422 start_offset
= session
->presentation
.start_position
.hVal
.QuadPart
;
2424 FIXME("Unhandled position type %d.\n", session
->presentation
.start_position
.vt
);
2427 FIXME("Unhandled time format %s.\n", debugstr_guid(&session
->presentation
.time_format
));
2429 if (FAILED(hr
= IMFPresentationClock_Start(session
->clock
, start_offset
)))
2430 WARN("Failed to start session clock, hr %#x.\n", hr
);
2435 static struct topo_node
*session_get_node_object(struct media_session
*session
, IUnknown
*object
,
2436 MF_TOPOLOGY_TYPE node_type
)
2438 struct topo_node
*node
= NULL
;
2440 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2442 if (node
->type
== node_type
&& object
== node
->object
.object
)
2449 static BOOL
session_set_node_object_state(struct media_session
*session
, IUnknown
*object
,
2450 MF_TOPOLOGY_TYPE node_type
, enum object_state state
)
2452 struct topo_node
*node
;
2453 BOOL changed
= FALSE
;
2455 if ((node
= session_get_node_object(session
, object
, node_type
)))
2457 changed
= node
->state
!= state
;
2458 node
->state
= state
;
2464 static void session_set_source_object_state(struct media_session
*session
, IUnknown
*object
,
2465 MediaEventType event_type
)
2467 IMFStreamSink
*stream_sink
;
2468 struct media_source
*src
;
2469 struct media_sink
*sink
;
2470 enum object_state state
;
2471 struct topo_node
*node
;
2472 unsigned int i
, count
;
2473 BOOL changed
= FALSE
;
2476 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2481 case MESourceStarted
:
2482 case MESourcePaused
:
2483 case MESourceStopped
:
2485 LIST_FOR_EACH_ENTRY(src
, &session
->presentation
.sources
, struct media_source
, entry
)
2487 if (object
== (IUnknown
*)src
->source
)
2489 changed
= src
->state
!= state
;
2495 case MEStreamStarted
:
2496 case MEStreamPaused
:
2497 case MEStreamStopped
:
2499 changed
= session_set_node_object_state(session
, object
, MF_TOPOLOGY_SOURCESTREAM_NODE
, state
);
2507 switch (session
->state
)
2509 case SESSION_STATE_STARTING_SOURCES
:
2510 if (!session_is_source_nodes_state(session
, OBJ_STATE_STARTED
))
2513 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_STARTED_SOURCE
);
2515 session_set_presentation_clock(session
);
2517 if (session
->presentation
.flags
& SESSION_FLAG_NEEDS_PREROLL
)
2519 MFTIME preroll_time
= 0;
2521 if (session
->presentation
.start_position
.vt
== VT_I8
)
2522 preroll_time
= session
->presentation
.start_position
.hVal
.QuadPart
;
2524 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2525 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2529 /* FIXME: abort and enter error state on failure. */
2530 if (FAILED(hr
= IMFMediaSinkPreroll_NotifyPreroll(sink
->preroll
, preroll_time
)))
2531 WARN("Preroll notification failed, hr %#x.\n", hr
);
2535 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink
->sink
, &count
)))
2537 for (i
= 0; i
< count
; ++i
)
2539 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink
->sink
, i
, &stream_sink
)))
2541 session_set_node_object_state(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
,
2542 OBJ_STATE_PREROLLED
);
2543 IMFStreamSink_Release(stream_sink
);
2549 session
->state
= SESSION_STATE_PREROLLING_SINKS
;
2551 else if (SUCCEEDED(session_start_clock(session
)))
2552 session
->state
= SESSION_STATE_STARTING_SINKS
;
2555 case SESSION_STATE_PAUSING_SOURCES
:
2556 if (!session_is_source_nodes_state(session
, OBJ_STATE_PAUSED
))
2559 session_set_paused(session
, SESSION_STATE_PAUSED
, S_OK
);
2561 case SESSION_STATE_STOPPING_SOURCES
:
2562 if (!session_is_source_nodes_state(session
, OBJ_STATE_STOPPED
))
2565 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2569 case MF_TOPOLOGY_OUTPUT_NODE
:
2570 IMFStreamSink_Flush(node
->object
.sink_stream
);
2572 case MF_TOPOLOGY_TRANSFORM_NODE
:
2573 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
2580 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
2582 if (session
->presentation
.flags
& SESSION_FLAG_FINALIZE_SINKS
)
2583 session_finalize_sinks(session
);
2585 session_set_stopped(session
, S_OK
);
2593 static void session_set_sink_stream_state(struct media_session
*session
, IMFStreamSink
*stream
,
2594 MediaEventType event_type
)
2596 struct media_source
*source
;
2597 enum object_state state
;
2601 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2604 if (!(changed
= session_set_node_object_state(session
, (IUnknown
*)stream
, MF_TOPOLOGY_OUTPUT_NODE
, state
)))
2607 switch (session
->state
)
2609 case SESSION_STATE_PREROLLING_SINKS
:
2610 if (!session_is_output_nodes_state(session
, OBJ_STATE_PREROLLED
))
2613 if (SUCCEEDED(session_start_clock(session
)))
2614 session
->state
= SESSION_STATE_STARTING_SINKS
;
2616 case SESSION_STATE_STARTING_SINKS
:
2617 if (!session_is_output_nodes_state(session
, OBJ_STATE_STARTED
))
2620 session_set_started(session
);
2622 case SESSION_STATE_PAUSING_SINKS
:
2623 if (!session_is_output_nodes_state(session
, OBJ_STATE_PAUSED
))
2626 session
->state
= SESSION_STATE_PAUSING_SOURCES
;
2628 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2630 if (FAILED(hr
= IMFMediaSource_Pause(source
->source
)))
2635 session_set_paused(session
, SESSION_STATE_PAUSED
, hr
);
2638 case SESSION_STATE_STOPPING_SINKS
:
2639 if (!session_is_output_nodes_state(session
, OBJ_STATE_STOPPED
))
2642 session
->state
= SESSION_STATE_STOPPING_SOURCES
;
2644 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2646 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
)
2647 IMFMediaSource_Stop(source
->source
);
2648 else if (FAILED(hr
= IMFMediaSource_Stop(source
->source
)))
2652 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
|| FAILED(hr
))
2653 session_set_stopped(session
, hr
);
2661 static struct sample
*transform_create_sample(IMFSample
*sample
)
2663 struct sample
*sample_entry
= calloc(1, sizeof(*sample_entry
));
2667 sample_entry
->sample
= sample
;
2668 if (sample_entry
->sample
)
2669 IMFSample_AddRef(sample_entry
->sample
);
2672 return sample_entry
;
2675 static HRESULT
transform_get_external_output_sample(const struct media_session
*session
, struct topo_node
*transform
,
2676 unsigned int output_index
, const MFT_OUTPUT_STREAM_INFO
*stream_info
, IMFSample
**sample
)
2678 unsigned int buffer_size
, downstream_input
;
2679 IMFTopologyNode
*downstream_node
;
2680 IMFMediaBuffer
*buffer
= NULL
;
2681 struct topo_node
*topo_node
;
2685 if (FAILED(IMFTopologyNode_GetOutput(transform
->node
, output_index
, &downstream_node
, &downstream_input
)))
2687 WARN("Failed to get connected node for output %u.\n", output_index
);
2688 return MF_E_UNEXPECTED
;
2691 IMFTopologyNode_GetTopoNodeID(downstream_node
, &node_id
);
2692 IMFTopologyNode_Release(downstream_node
);
2694 topo_node
= session_get_node_by_id(session
, node_id
);
2696 if (topo_node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& topo_node
->u
.sink
.allocator
)
2698 hr
= IMFVideoSampleAllocator_AllocateSample(topo_node
->u
.sink
.allocator
, sample
);
2702 buffer_size
= max(stream_info
->cbSize
, transform
->u
.transform
.outputs
[output_index
].min_buffer_size
);
2704 hr
= MFCreateAlignedMemoryBuffer(buffer_size
, stream_info
->cbAlignment
, &buffer
);
2706 hr
= MFCreateSample(sample
);
2709 hr
= IMFSample_AddBuffer(*sample
, buffer
);
2712 IMFMediaBuffer_Release(buffer
);
2718 static HRESULT
transform_node_pull_samples(const struct media_session
*session
, struct topo_node
*node
)
2720 MFT_OUTPUT_STREAM_INFO stream_info
;
2721 MFT_OUTPUT_DATA_BUFFER
*buffers
;
2722 struct sample
*queued_sample
;
2725 HRESULT hr
= E_UNEXPECTED
;
2727 if (!(buffers
= calloc(node
->u
.transform
.output_count
, sizeof(*buffers
))))
2728 return E_OUTOFMEMORY
;
2730 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2732 buffers
[i
].dwStreamID
= transform_node_get_stream_id(node
, TRUE
, i
);
2733 buffers
[i
].pSample
= NULL
;
2734 buffers
[i
].dwStatus
= 0;
2735 buffers
[i
].pEvents
= NULL
;
2737 memset(&stream_info
, 0, sizeof(stream_info
));
2738 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(node
->object
.transform
, buffers
[i
].dwStreamID
, &stream_info
)))
2741 if (!(stream_info
.dwFlags
& (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
| MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
)))
2743 if (FAILED(hr
= transform_get_external_output_sample(session
, node
, i
, &stream_info
, &buffers
[i
].pSample
)))
2749 hr
= IMFTransform_ProcessOutput(node
->object
.transform
, 0, node
->u
.transform
.output_count
, buffers
, &status
);
2751 /* Collect returned samples for all streams. */
2752 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2754 if (buffers
[i
].pEvents
)
2755 IMFCollection_Release(buffers
[i
].pEvents
);
2757 if (SUCCEEDED(hr
) && !(buffers
[i
].dwStatus
& MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE
))
2759 if (session
->quality_manager
)
2760 IMFQualityManager_NotifyProcessOutput(session
->quality_manager
, node
->node
, i
, buffers
[i
].pSample
);
2762 queued_sample
= transform_create_sample(buffers
[i
].pSample
);
2763 list_add_tail(&node
->u
.transform
.outputs
[i
].samples
, &queued_sample
->entry
);
2766 if (buffers
[i
].pSample
)
2767 IMFSample_Release(buffers
[i
].pSample
);
2775 static void session_deliver_sample_to_node(struct media_session
*session
, IMFTopologyNode
*node
, unsigned int input
,
2778 struct sample
*sample_entry
, *sample_entry2
;
2779 DWORD stream_id
, downstream_input
;
2780 IMFTopologyNode
*downstream_node
;
2781 struct topo_node
*topo_node
;
2782 MF_TOPOLOGY_TYPE node_type
;
2788 if (session
->quality_manager
)
2789 IMFQualityManager_NotifyProcessInput(session
->quality_manager
, node
, input
, sample
);
2791 IMFTopologyNode_GetNodeType(node
, &node_type
);
2792 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2794 topo_node
= session_get_node_by_id(session
, node_id
);
2798 case MF_TOPOLOGY_OUTPUT_NODE
:
2801 if (topo_node
->u
.sink
.requests
)
2803 if (FAILED(hr
= IMFStreamSink_ProcessSample(topo_node
->object
.sink_stream
, sample
)))
2804 WARN("Stream sink failed to process sample, hr %#x.\n", hr
);
2805 topo_node
->u
.sink
.requests
--;
2808 else if (FAILED(hr
= IMFStreamSink_PlaceMarker(topo_node
->object
.sink_stream
, MFSTREAMSINK_MARKER_ENDOFSEGMENT
,
2811 WARN("Failed to place sink marker, hr %#x.\n", hr
);
2814 case MF_TOPOLOGY_TRANSFORM_NODE
:
2816 transform_node_pull_samples(session
, topo_node
);
2818 sample_entry
= transform_create_sample(sample
);
2819 list_add_tail(&topo_node
->u
.transform
.inputs
[input
].samples
, &sample_entry
->entry
);
2821 for (i
= 0; i
< topo_node
->u
.transform
.input_count
; ++i
)
2823 stream_id
= transform_node_get_stream_id(topo_node
, FALSE
, i
);
2824 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.inputs
[i
].samples
,
2825 struct sample
, entry
)
2827 if (sample_entry
->sample
)
2829 if ((hr
= IMFTransform_ProcessInput(topo_node
->object
.transform
, stream_id
,
2830 sample_entry
->sample
, 0)) == MF_E_NOTACCEPTING
)
2833 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i
, stream_id
, hr
);
2834 transform_release_sample(sample_entry
);
2838 transform_stream_drop_samples(&topo_node
->u
.transform
.inputs
[i
]);
2846 if (FAILED(hr
= IMFTransform_ProcessMessage(topo_node
->object
.transform
, MFT_MESSAGE_COMMAND_DRAIN
, 0)))
2847 WARN("Drain command failed for transform, hr %#x.\n", hr
);
2850 transform_node_pull_samples(session
, topo_node
);
2852 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2855 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2857 if ((sample_entry
= transform_create_sample(NULL
)))
2858 list_add_tail(&topo_node
->u
.transform
.outputs
[i
].samples
, &sample_entry
->entry
);
2862 /* Push down all available output. */
2863 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2865 if (FAILED(IMFTopologyNode_GetOutput(node
, i
, &downstream_node
, &downstream_input
)))
2867 WARN("Failed to get connected node for output %u.\n", i
);
2871 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.outputs
[i
].samples
,
2872 struct sample
, entry
)
2874 if (!topo_node
->u
.transform
.outputs
[i
].requests
)
2877 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample_entry
->sample
);
2878 topo_node
->u
.transform
.outputs
[i
].requests
--;
2880 transform_release_sample(sample_entry
);
2883 IMFTopologyNode_Release(downstream_node
);
2887 case MF_TOPOLOGY_TEE_NODE
:
2888 FIXME("Unhandled downstream node type %d.\n", node_type
);
2895 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
)
2897 IMFTopologyNode
*downstream_node
, *upstream_node
;
2898 unsigned int downstream_input
, upstream_output
;
2899 struct topo_node
*topo_node
;
2900 MF_TOPOLOGY_TYPE node_type
;
2901 struct sample
*sample
;
2905 IMFTopologyNode_GetNodeType(node
, &node_type
);
2906 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2908 topo_node
= session_get_node_by_id(session
, node_id
);
2912 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
2913 if (FAILED(hr
= IMFMediaStream_RequestSample(topo_node
->object
.source_stream
, NULL
)))
2914 WARN("Sample request failed, hr %#x.\n", hr
);
2916 case MF_TOPOLOGY_TRANSFORM_NODE
:
2918 if (list_empty(&topo_node
->u
.transform
.outputs
[output
].samples
))
2920 /* Forward request to upstream node. */
2921 if (SUCCEEDED(hr
= IMFTopologyNode_GetInput(node
, 0 /* FIXME */, &upstream_node
, &upstream_output
)))
2923 if (SUCCEEDED(hr
= session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2924 topo_node
->u
.transform
.outputs
[output
].requests
++;
2925 IMFTopologyNode_Release(upstream_node
);
2930 if (SUCCEEDED(hr
= IMFTopologyNode_GetOutput(node
, output
, &downstream_node
, &downstream_input
)))
2932 sample
= LIST_ENTRY(list_head(&topo_node
->u
.transform
.outputs
[output
].samples
), struct sample
, entry
);
2933 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample
->sample
);
2934 transform_release_sample(sample
);
2935 IMFTopologyNode_Release(downstream_node
);
2940 case MF_TOPOLOGY_TEE_NODE
:
2941 FIXME("Unhandled upstream node type %d.\n", node_type
);
2949 static void session_request_sample(struct media_session
*session
, IMFStreamSink
*sink_stream
)
2951 struct topo_node
*sink_node
= NULL
, *node
;
2952 IMFTopologyNode
*upstream_node
;
2953 DWORD upstream_output
;
2956 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2958 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink_stream
)
2968 if (FAILED(hr
= IMFTopologyNode_GetInput(sink_node
->node
, 0, &upstream_node
, &upstream_output
)))
2970 WARN("Failed to get upstream node connection, hr %#x.\n", hr
);
2974 if (SUCCEEDED(session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2975 sink_node
->u
.sink
.requests
++;
2976 IMFTopologyNode_Release(upstream_node
);
2979 static void session_deliver_sample(struct media_session
*session
, IMFMediaStream
*stream
, const PROPVARIANT
*value
)
2981 struct topo_node
*source_node
= NULL
, *node
;
2982 IMFTopologyNode
*downstream_node
;
2983 DWORD downstream_input
;
2986 if (value
&& (value
->vt
!= VT_UNKNOWN
|| !value
->punkVal
))
2988 WARN("Unexpected value type %d.\n", value
->vt
);
2992 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2994 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->object
.source_stream
== stream
)
3005 source_node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3007 if (FAILED(hr
= IMFTopologyNode_GetOutput(source_node
->node
, 0, &downstream_node
, &downstream_input
)))
3009 WARN("Failed to get downstream node connection, hr %#x.\n", hr
);
3013 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, value
? (IMFSample
*)value
->punkVal
: NULL
);
3014 IMFTopologyNode_Release(downstream_node
);
3017 static void session_sink_invalidated(struct media_session
*session
, IMFMediaEvent
*event
, IMFStreamSink
*sink
)
3019 struct topo_node
*node
, *sink_node
= NULL
;
3022 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3024 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink
)
3036 if (FAILED(hr
= MFCreateMediaEvent(MESinkInvalidated
, &GUID_NULL
, S_OK
, NULL
, &event
)))
3037 WARN("Failed to create event, hr %#x.\n", hr
);
3043 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_OUTPUT_NODE
, sink_node
->node_id
);
3044 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3046 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3049 static BOOL
session_nodes_is_mask_set(struct media_session
*session
, MF_TOPOLOGY_TYPE node_type
, unsigned int flags
)
3051 struct media_source
*source
;
3052 struct topo_node
*node
;
3054 if (node_type
== MF_TOPOLOGY_MAX
)
3056 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3058 if ((source
->flags
& flags
) != flags
)
3064 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3066 if (node
->type
== node_type
&& (node
->flags
& flags
) != flags
)
3074 static void session_raise_end_of_presentation(struct media_session
*session
)
3076 if (!(session_nodes_is_mask_set(session
, MF_TOPOLOGY_SOURCESTREAM_NODE
, TOPO_NODE_END_OF_STREAM
)))
3079 if (!(session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
))
3081 if (session_nodes_is_mask_set(session
, MF_TOPOLOGY_MAX
, SOURCE_FLAG_END_OF_PRESENTATION
))
3083 session
->presentation
.flags
|= SESSION_FLAG_END_OF_PRESENTATION
;
3084 session_push_back_command(session
, SESSION_CMD_END
);
3085 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MEEndOfPresentation
, &GUID_NULL
, S_OK
, NULL
);
3090 static void session_handle_end_of_stream(struct media_session
*session
, IMFMediaStream
*stream
)
3092 struct topo_node
*node
;
3094 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream
, MF_TOPOLOGY_SOURCESTREAM_NODE
))
3095 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3100 session_deliver_sample(session
, stream
, NULL
);
3102 session_raise_end_of_presentation(session
);
3105 static void session_handle_end_of_presentation(struct media_session
*session
, IMFMediaSource
*object
)
3107 struct media_source
*source
;
3109 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3111 if (source
->source
== object
)
3113 if (!(source
->flags
& SOURCE_FLAG_END_OF_PRESENTATION
))
3115 source
->flags
|= SOURCE_FLAG_END_OF_PRESENTATION
;
3116 session_raise_end_of_presentation(session
);
3124 static void session_sink_stream_marker(struct media_session
*session
, IMFStreamSink
*stream_sink
)
3126 struct topo_node
*node
;
3128 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
))
3129 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3134 node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3136 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
&&
3137 session_nodes_is_mask_set(session
, MF_TOPOLOGY_OUTPUT_NODE
, TOPO_NODE_END_OF_STREAM
))
3139 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3140 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
3141 session_stop(session
);
3145 static HRESULT WINAPI
session_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3147 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
3148 IMFMediaEventGenerator
*event_source
;
3149 IMFMediaEvent
*event
= NULL
;
3150 MediaEventType event_type
;
3151 IUnknown
*object
= NULL
;
3152 IMFMediaSource
*source
;
3153 IMFMediaStream
*stream
;
3157 if (FAILED(hr
= IMFAsyncResult_GetState(result
, (IUnknown
**)&event_source
)))
3160 if (FAILED(hr
= IMFMediaEventGenerator_EndGetEvent(event_source
, result
, &event
)))
3162 WARN("Failed to get event from %p, hr %#x.\n", event_source
, hr
);
3166 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
3168 WARN("Failed to get event type, hr %#x.\n", hr
);
3172 value
.vt
= VT_EMPTY
;
3173 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
3175 WARN("Failed to get event value, hr %#x.\n", hr
);
3181 case MESourceStarted
:
3182 case MESourcePaused
:
3183 case MESourceStopped
:
3184 case MEStreamStarted
:
3185 case MEStreamPaused
:
3186 case MEStreamStopped
:
3188 EnterCriticalSection(&session
->cs
);
3189 session_set_source_object_state(session
, (IUnknown
*)event_source
, event_type
);
3190 LeaveCriticalSection(&session
->cs
);
3194 case MEBufferingStarted
:
3195 case MEBufferingStopped
:
3197 EnterCriticalSection(&session
->cs
);
3198 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3200 if (event_type
== MEBufferingStarted
)
3201 IMFPresentationClock_Pause(session
->clock
);
3203 IMFPresentationClock_Start(session
->clock
, PRESENTATION_CURRENT_POSITION
);
3205 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3207 LeaveCriticalSection(&session
->cs
);
3210 case MEReconnectStart
:
3211 case MEReconnectEnd
:
3213 EnterCriticalSection(&session
->cs
);
3214 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3215 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3216 LeaveCriticalSection(&session
->cs
);
3219 case MEExtendedType
:
3220 case MERendererEvent
:
3221 case MEStreamSinkFormatChanged
:
3223 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3227 stream
= (IMFMediaStream
*)value
.punkVal
;
3229 if (value
.vt
!= VT_UNKNOWN
|| !stream
)
3231 WARN("Unexpected event value.\n");
3235 if (FAILED(hr
= IMFMediaStream_GetMediaSource(stream
, &source
)))
3238 EnterCriticalSection(&session
->cs
);
3239 if (SUCCEEDED(hr
= session_add_media_stream(session
, source
, stream
)))
3240 hr
= IMFMediaStream_BeginGetEvent(stream
, &session
->events_callback
, (IUnknown
*)stream
);
3241 LeaveCriticalSection(&session
->cs
);
3243 IMFMediaSource_Release(source
);
3246 case MEStreamSinkStarted
:
3247 case MEStreamSinkPaused
:
3248 case MEStreamSinkStopped
:
3249 case MEStreamSinkPrerolled
:
3251 EnterCriticalSection(&session
->cs
);
3252 session_set_sink_stream_state(session
, (IMFStreamSink
*)event_source
, event_type
);
3253 LeaveCriticalSection(&session
->cs
);
3256 case MEStreamSinkMarker
:
3258 EnterCriticalSection(&session
->cs
);
3259 session_sink_stream_marker(session
, (IMFStreamSink
*)event_source
);
3260 LeaveCriticalSection(&session
->cs
);
3263 case MEStreamSinkRequestSample
:
3265 EnterCriticalSection(&session
->cs
);
3266 session_request_sample(session
, (IMFStreamSink
*)event_source
);
3267 LeaveCriticalSection(&session
->cs
);
3272 EnterCriticalSection(&session
->cs
);
3273 session_deliver_sample(session
, (IMFMediaStream
*)event_source
, &value
);
3274 LeaveCriticalSection(&session
->cs
);
3279 EnterCriticalSection(&session
->cs
);
3280 session_handle_end_of_stream(session
, (IMFMediaStream
*)event_source
);
3281 LeaveCriticalSection(&session
->cs
);
3285 case MEEndOfPresentation
:
3287 EnterCriticalSection(&session
->cs
);
3288 session_handle_end_of_presentation(session
, (IMFMediaSource
*)event_source
);
3289 LeaveCriticalSection(&session
->cs
);
3292 case MEAudioSessionGroupingParamChanged
:
3293 case MEAudioSessionIconChanged
:
3294 case MEAudioSessionNameChanged
:
3295 case MEAudioSessionVolumeChanged
:
3297 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3300 case MEAudioSessionDeviceRemoved
:
3301 case MEAudioSessionDisconnected
:
3302 case MEAudioSessionExclusiveModeOverride
:
3303 case MEAudioSessionFormatChanged
:
3304 case MEAudioSessionServerShutdown
:
3306 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3308 case MESinkInvalidated
:
3310 EnterCriticalSection(&session
->cs
);
3311 session_sink_invalidated(session
, event_type
== MESinkInvalidated
? event
: NULL
,
3312 (IMFStreamSink
*)event_source
);
3313 LeaveCriticalSection(&session
->cs
);
3316 case MEQualityNotify
:
3318 if (session
->quality_manager
)
3320 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFStreamSink
, (void **)&object
)))
3321 IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFTransform
, (void **)&object
);
3325 IMFQualityManager_NotifyQualityEvent(session
->quality_manager
, object
, event
);
3326 IUnknown_Release(object
);
3335 PropVariantClear(&value
);
3339 IMFMediaEvent_Release(event
);
3341 if (FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(event_source
, iface
, (IUnknown
*)event_source
)))
3342 WARN("Failed to re-subscribe, hr %#x.\n", hr
);
3344 IMFMediaEventGenerator_Release(event_source
);
3349 static const IMFAsyncCallbackVtbl session_events_callback_vtbl
=
3351 session_events_callback_QueryInterface
,
3352 session_events_callback_AddRef
,
3353 session_events_callback_Release
,
3354 session_events_callback_GetParameters
,
3355 session_events_callback_Invoke
,
3358 static HRESULT WINAPI
session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
3360 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
3361 IsEqualIID(riid
, &IID_IUnknown
))
3364 IMFAsyncCallback_AddRef(iface
);
3368 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3370 return E_NOINTERFACE
;
3373 static ULONG WINAPI
session_sink_finalizer_callback_AddRef(IMFAsyncCallback
*iface
)
3375 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3376 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3379 static ULONG WINAPI
session_sink_finalizer_callback_Release(IMFAsyncCallback
*iface
)
3381 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3382 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3385 static HRESULT WINAPI
session_sink_finalizer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
3390 static HRESULT WINAPI
session_sink_finalizer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3392 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3393 IMFFinalizableMediaSink
*fin_sink
= NULL
;
3394 BOOL sinks_finalized
= TRUE
;
3395 struct media_sink
*sink
;
3399 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
3402 EnterCriticalSection(&session
->cs
);
3404 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3406 if (state
== (IUnknown
*)sink
->sink
)
3408 if (FAILED(hr
= IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
3409 WARN("Unexpected, missing IMFFinalizableMediaSink, hr %#x.\n", hr
);
3413 sinks_finalized
&= sink
->finalized
;
3414 if (!sinks_finalized
)
3419 IUnknown_Release(state
);
3423 /* Complete session transition, or close prematurely on error. */
3424 if (SUCCEEDED(hr
= IMFFinalizableMediaSink_EndFinalize(fin_sink
, result
)))
3426 sink
->finalized
= TRUE
;
3427 if (sinks_finalized
)
3428 session_set_closed(session
, hr
);
3430 IMFFinalizableMediaSink_Release(fin_sink
);
3433 LeaveCriticalSection(&session
->cs
);
3438 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl
=
3440 session_sink_finalizer_callback_QueryInterface
,
3441 session_sink_finalizer_callback_AddRef
,
3442 session_sink_finalizer_callback_Release
,
3443 session_sink_finalizer_callback_GetParameters
,
3444 session_sink_finalizer_callback_Invoke
,
3447 static HRESULT WINAPI
session_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
3449 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3450 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3453 static ULONG WINAPI
session_rate_support_AddRef(IMFRateSupport
*iface
)
3455 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3456 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3459 static ULONG WINAPI
session_rate_support_Release(IMFRateSupport
*iface
)
3461 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3462 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3465 static HRESULT
session_presentation_object_get_rate(IUnknown
*object
, MFRATE_DIRECTION direction
,
3466 BOOL thin
, BOOL fastest
, float *result
)
3468 IMFRateSupport
*rate_support
;
3472 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3474 if (FAILED(hr
= MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
3476 if (direction
== MFRATE_FORWARD
)
3482 return MF_E_REVERSE_UNSUPPORTED
;
3488 if (SUCCEEDED(hr
= IMFRateSupport_GetFastestRate(rate_support
, direction
, thin
, &rate
)))
3489 *result
= min(fabsf(rate
), *result
);
3493 if (SUCCEEDED(hr
= IMFRateSupport_GetSlowestRate(rate_support
, direction
, thin
, &rate
)))
3494 *result
= max(fabsf(rate
), *result
);
3497 IMFRateSupport_Release(rate_support
);
3502 static HRESULT
session_get_presentation_rate(struct media_session
*session
, MFRATE_DIRECTION direction
,
3503 BOOL thin
, BOOL fastest
, float *result
)
3505 struct media_source
*source
;
3506 struct media_sink
*sink
;
3507 HRESULT hr
= E_POINTER
;
3510 rate
= fastest
? FLT_MAX
: 0.0f
;
3512 EnterCriticalSection(&session
->cs
);
3514 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
3516 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3518 if (FAILED(hr
= session_presentation_object_get_rate((IUnknown
*)source
->source
, direction
, thin
, fastest
, &rate
)))
3524 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3526 if (FAILED(hr
= session_presentation_object_get_rate((IUnknown
*)sink
->sink
, direction
, thin
, fastest
, &rate
)))
3532 LeaveCriticalSection(&session
->cs
);
3535 *result
= direction
== MFRATE_FORWARD
? rate
: -rate
;
3540 static HRESULT WINAPI
session_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3541 BOOL thin
, float *rate
)
3543 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3545 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3547 return session_get_presentation_rate(session
, direction
, thin
, FALSE
, rate
);
3550 static HRESULT WINAPI
session_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3551 BOOL thin
, float *rate
)
3553 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3555 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3557 return session_get_presentation_rate(session
, direction
, thin
, TRUE
, rate
);
3560 static HRESULT WINAPI
session_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
3561 float *nearest_supported_rate
)
3563 FIXME("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_supported_rate
);
3568 static const IMFRateSupportVtbl session_rate_support_vtbl
=
3570 session_rate_support_QueryInterface
,
3571 session_rate_support_AddRef
,
3572 session_rate_support_Release
,
3573 session_rate_support_GetSlowestRate
,
3574 session_rate_support_GetFastestRate
,
3575 session_rate_support_IsRateSupported
,
3578 static HRESULT WINAPI
session_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
3580 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3581 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3584 static ULONG WINAPI
session_rate_control_AddRef(IMFRateControl
*iface
)
3586 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3587 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3590 static ULONG WINAPI
session_rate_control_Release(IMFRateControl
*iface
)
3592 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3593 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3596 static HRESULT WINAPI
session_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
3598 FIXME("%p, %d, %f.\n", iface
, thin
, rate
);
3603 static HRESULT WINAPI
session_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
3605 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3607 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
3609 return IMFRateControl_GetRate(session
->clock_rate_control
, thin
, rate
);
3612 static const IMFRateControlVtbl session_rate_control_vtbl
=
3614 session_rate_control_QueryInterface
,
3615 session_rate_control_AddRef
,
3616 session_rate_control_Release
,
3617 session_rate_control_SetRate
,
3618 session_rate_control_GetRate
,
3621 static HRESULT WINAPI
node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor
*iface
,
3622 REFIID riid
, void **obj
)
3624 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
3626 if (IsEqualIID(riid
, &IID_IMFTopologyNodeAttributeEditor
) ||
3627 IsEqualIID(riid
, &IID_IUnknown
))
3630 IMFTopologyNodeAttributeEditor_AddRef(iface
);
3634 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
3636 return E_NOINTERFACE
;
3639 static ULONG WINAPI
node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor
*iface
)
3641 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
3642 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3645 static ULONG WINAPI
node_attribute_editor_Release(IMFTopologyNodeAttributeEditor
*iface
)
3647 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
3648 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3651 static HRESULT WINAPI
node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor
*iface
,
3652 TOPOID id
, DWORD count
, MFTOPONODE_ATTRIBUTE_UPDATE
*updates
)
3654 FIXME("%p, %s, %u, %p.\n", iface
, wine_dbgstr_longlong(id
), count
, updates
);
3659 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl
=
3661 node_attribute_editor_QueryInterface
,
3662 node_attribute_editor_AddRef
,
3663 node_attribute_editor_Release
,
3664 node_attribute_editor_UpdateNodeAttributes
,
3667 /***********************************************************************
3668 * MFCreateMediaSession (mf.@)
3670 HRESULT WINAPI
MFCreateMediaSession(IMFAttributes
*config
, IMFMediaSession
**session
)
3672 BOOL without_quality_manager
= FALSE
;
3673 struct media_session
*object
;
3676 TRACE("%p, %p.\n", config
, session
);
3678 if (!(object
= calloc(1, sizeof(*object
))))
3679 return E_OUTOFMEMORY
;
3681 object
->IMFMediaSession_iface
.lpVtbl
= &mfmediasessionvtbl
;
3682 object
->IMFGetService_iface
.lpVtbl
= &session_get_service_vtbl
;
3683 object
->IMFRateSupport_iface
.lpVtbl
= &session_rate_support_vtbl
;
3684 object
->IMFRateControl_iface
.lpVtbl
= &session_rate_control_vtbl
;
3685 object
->IMFTopologyNodeAttributeEditor_iface
.lpVtbl
= &node_attribute_editor_vtbl
;
3686 object
->commands_callback
.lpVtbl
= &session_commands_callback_vtbl
;
3687 object
->events_callback
.lpVtbl
= &session_events_callback_vtbl
;
3688 object
->sink_finalizer_callback
.lpVtbl
= &session_sink_finalizer_callback_vtbl
;
3689 object
->refcount
= 1;
3690 list_init(&object
->topologies
);
3691 list_init(&object
->commands
);
3692 list_init(&object
->presentation
.sources
);
3693 list_init(&object
->presentation
.sinks
);
3694 list_init(&object
->presentation
.nodes
);
3695 InitializeCriticalSection(&object
->cs
);
3697 if (FAILED(hr
= MFCreateTopology(&object
->presentation
.current_topology
)))
3700 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
3703 if (FAILED(hr
= MFCreatePresentationClock(&object
->clock
)))
3706 if (FAILED(hr
= MFCreateSystemTimeSource(&object
->system_time_source
)))
3709 if (FAILED(hr
= IMFPresentationClock_QueryInterface(object
->clock
, &IID_IMFRateControl
,
3710 (void **)&object
->clock_rate_control
)))
3719 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_TOPOLOADER
, &clsid
)))
3721 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTopoLoader
,
3722 (void **)&object
->topo_loader
)))
3724 WARN("Failed to create custom topology loader, hr %#x.\n", hr
);
3728 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_QUALITY_MANAGER
, &clsid
)))
3730 if (!(without_quality_manager
= IsEqualGUID(&clsid
, &GUID_NULL
)))
3732 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFQualityManager
,
3733 (void **)&object
->quality_manager
)))
3735 WARN("Failed to create custom quality manager, hr %#x.\n", hr
);
3741 if (!object
->topo_loader
&& FAILED(hr
= MFCreateTopoLoader(&object
->topo_loader
)))
3744 if (!object
->quality_manager
&& !without_quality_manager
&&
3745 FAILED(hr
= MFCreateStandardQualityManager(&object
->quality_manager
)))
3750 if (object
->quality_manager
&& FAILED(hr
= IMFQualityManager_NotifyPresentationClock(object
->quality_manager
,
3756 *session
= &object
->IMFMediaSession_iface
;
3761 IMFMediaSession_Release(&object
->IMFMediaSession_iface
);
3765 static HRESULT WINAPI
standard_quality_manager_QueryInterface(IMFQualityManager
*iface
, REFIID riid
, void **out
)
3767 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3769 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
3771 if (IsEqualIID(riid
, &IID_IMFQualityManager
) ||
3772 IsEqualIID(riid
, &IID_IUnknown
))
3776 else if (IsEqualIID(riid
, &IID_IMFClockStateSink
))
3778 *out
= &manager
->IMFClockStateSink_iface
;
3782 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3784 return E_NOINTERFACE
;
3787 IUnknown_AddRef((IUnknown
*)*out
);
3791 static ULONG WINAPI
standard_quality_manager_AddRef(IMFQualityManager
*iface
)
3793 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3794 ULONG refcount
= InterlockedIncrement(&manager
->refcount
);
3796 TRACE("%p, refcount %u.\n", iface
, refcount
);
3801 static ULONG WINAPI
standard_quality_manager_Release(IMFQualityManager
*iface
)
3803 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3804 ULONG refcount
= InterlockedDecrement(&manager
->refcount
);
3806 TRACE("%p, refcount %u.\n", iface
, refcount
);
3811 IMFPresentationClock_Release(manager
->clock
);
3812 if (manager
->topology
)
3813 IMFTopology_Release(manager
->topology
);
3814 DeleteCriticalSection(&manager
->cs
);
3821 static void standard_quality_manager_set_topology(struct quality_manager
*manager
, IMFTopology
*topology
)
3823 if (manager
->topology
)
3824 IMFTopology_Release(manager
->topology
);
3825 manager
->topology
= topology
;
3826 if (manager
->topology
)
3827 IMFTopology_AddRef(manager
->topology
);
3830 static HRESULT WINAPI
standard_quality_manager_NotifyTopology(IMFQualityManager
*iface
, IMFTopology
*topology
)
3832 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3835 TRACE("%p, %p.\n", iface
, topology
);
3837 EnterCriticalSection(&manager
->cs
);
3838 if (manager
->state
== QUALITY_MANAGER_SHUT_DOWN
)
3842 standard_quality_manager_set_topology(manager
, topology
);
3844 LeaveCriticalSection(&manager
->cs
);
3849 static void standard_quality_manager_release_clock(struct quality_manager
*manager
)
3853 IMFPresentationClock_RemoveClockStateSink(manager
->clock
, &manager
->IMFClockStateSink_iface
);
3854 IMFPresentationClock_Release(manager
->clock
);
3856 manager
->clock
= NULL
;
3859 static HRESULT WINAPI
standard_quality_manager_NotifyPresentationClock(IMFQualityManager
*iface
,
3860 IMFPresentationClock
*clock
)
3862 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3865 TRACE("%p, %p.\n", iface
, clock
);
3867 EnterCriticalSection(&manager
->cs
);
3868 if (manager
->state
== QUALITY_MANAGER_SHUT_DOWN
)
3874 standard_quality_manager_release_clock(manager
);
3875 manager
->clock
= clock
;
3876 IMFPresentationClock_AddRef(manager
->clock
);
3877 if (FAILED(IMFPresentationClock_AddClockStateSink(manager
->clock
, &manager
->IMFClockStateSink_iface
)))
3878 WARN("Failed to set state sink.\n");
3880 LeaveCriticalSection(&manager
->cs
);
3885 static HRESULT WINAPI
standard_quality_manager_NotifyProcessInput(IMFQualityManager
*iface
, IMFTopologyNode
*node
,
3886 LONG input_index
, IMFSample
*sample
)
3888 TRACE("%p, %p, %d, %p stub.\n", iface
, node
, input_index
, sample
);
3893 static HRESULT WINAPI
standard_quality_manager_NotifyProcessOutput(IMFQualityManager
*iface
, IMFTopologyNode
*node
,
3894 LONG output_index
, IMFSample
*sample
)
3896 TRACE("%p, %p, %d, %p stub.\n", iface
, node
, output_index
, sample
);
3901 static HRESULT WINAPI
standard_quality_manager_NotifyQualityEvent(IMFQualityManager
*iface
, IUnknown
*object
,
3902 IMFMediaEvent
*event
)
3904 FIXME("%p, %p, %p stub.\n", iface
, object
, event
);
3909 static HRESULT WINAPI
standard_quality_manager_Shutdown(IMFQualityManager
*iface
)
3911 struct quality_manager
*manager
= impl_from_IMFQualityManager(iface
);
3913 TRACE("%p.\n", iface
);
3915 EnterCriticalSection(&manager
->cs
);
3916 if (manager
->state
!= QUALITY_MANAGER_SHUT_DOWN
)
3918 standard_quality_manager_release_clock(manager
);
3919 standard_quality_manager_set_topology(manager
, NULL
);
3920 manager
->state
= QUALITY_MANAGER_SHUT_DOWN
;
3922 LeaveCriticalSection(&manager
->cs
);
3927 static const IMFQualityManagerVtbl standard_quality_manager_vtbl
=
3929 standard_quality_manager_QueryInterface
,
3930 standard_quality_manager_AddRef
,
3931 standard_quality_manager_Release
,
3932 standard_quality_manager_NotifyTopology
,
3933 standard_quality_manager_NotifyPresentationClock
,
3934 standard_quality_manager_NotifyProcessInput
,
3935 standard_quality_manager_NotifyProcessOutput
,
3936 standard_quality_manager_NotifyQualityEvent
,
3937 standard_quality_manager_Shutdown
,
3940 static HRESULT WINAPI
standard_quality_manager_sink_QueryInterface(IMFClockStateSink
*iface
,
3941 REFIID riid
, void **obj
)
3943 struct quality_manager
*manager
= impl_from_qm_IMFClockStateSink(iface
);
3944 return IMFQualityManager_QueryInterface(&manager
->IMFQualityManager_iface
, riid
, obj
);
3947 static ULONG WINAPI
standard_quality_manager_sink_AddRef(IMFClockStateSink
*iface
)
3949 struct quality_manager
*manager
= impl_from_qm_IMFClockStateSink(iface
);
3950 return IMFQualityManager_AddRef(&manager
->IMFQualityManager_iface
);
3953 static ULONG WINAPI
standard_quality_manager_sink_Release(IMFClockStateSink
*iface
)
3955 struct quality_manager
*manager
= impl_from_qm_IMFClockStateSink(iface
);
3956 return IMFQualityManager_Release(&manager
->IMFQualityManager_iface
);
3959 static HRESULT WINAPI
standard_quality_manager_sink_OnClockStart(IMFClockStateSink
*iface
,
3960 MFTIME systime
, LONGLONG offset
)
3965 static HRESULT WINAPI
standard_quality_manager_sink_OnClockStop(IMFClockStateSink
*iface
,
3971 static HRESULT WINAPI
standard_quality_manager_sink_OnClockPause(IMFClockStateSink
*iface
,
3977 static HRESULT WINAPI
standard_quality_manager_sink_OnClockRestart(IMFClockStateSink
*iface
,
3983 static HRESULT WINAPI
standard_quality_manager_sink_OnClockSetRate(IMFClockStateSink
*iface
,
3984 MFTIME systime
, float rate
)
3989 static const IMFClockStateSinkVtbl standard_quality_manager_sink_vtbl
=
3991 standard_quality_manager_sink_QueryInterface
,
3992 standard_quality_manager_sink_AddRef
,
3993 standard_quality_manager_sink_Release
,
3994 standard_quality_manager_sink_OnClockStart
,
3995 standard_quality_manager_sink_OnClockStop
,
3996 standard_quality_manager_sink_OnClockPause
,
3997 standard_quality_manager_sink_OnClockRestart
,
3998 standard_quality_manager_sink_OnClockSetRate
,
4001 HRESULT WINAPI
MFCreateStandardQualityManager(IMFQualityManager
**manager
)
4003 struct quality_manager
*object
;
4005 TRACE("%p.\n", manager
);
4007 if (!(object
= calloc(1, sizeof(*object
))))
4008 return E_OUTOFMEMORY
;
4010 object
->IMFQualityManager_iface
.lpVtbl
= &standard_quality_manager_vtbl
;
4011 object
->IMFClockStateSink_iface
.lpVtbl
= &standard_quality_manager_sink_vtbl
;
4012 object
->refcount
= 1;
4013 InitializeCriticalSection(&object
->cs
);
4015 *manager
= &object
->IMFQualityManager_iface
;