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,
127 IMFMediaSource
*source
;
130 IMFPresentationDescriptor
*pd
;
131 enum object_state state
;
143 IMFMediaSinkPreroll
*preroll
;
144 IMFMediaEventGenerator
*event_generator
;
154 struct transform_stream
157 unsigned int requests
;
158 unsigned int min_buffer_size
;
163 TOPO_NODE_END_OF_STREAM
= 0x1,
169 struct media_session
*session
;
170 MF_TOPOLOGY_TYPE type
;
172 IMFTopologyNode
*node
;
173 enum object_state state
;
177 IMFMediaStream
*source_stream
;
178 IMFStreamSink
*sink_stream
;
179 IMFTransform
*transform
;
187 IMFMediaSource
*source
;
192 unsigned int requests
;
193 IMFVideoSampleAllocatorNotify notify_cb
;
194 IMFVideoSampleAllocator
*allocator
;
195 IMFVideoSampleAllocatorCallback
*allocator_cb
;
199 struct transform_stream
*inputs
;
201 unsigned int input_count
;
203 struct transform_stream
*outputs
;
205 unsigned int output_count
;
210 enum presentation_flags
212 SESSION_FLAG_SOURCES_SUBSCRIBED
= 0x1,
213 SESSION_FLAG_PRESENTATION_CLOCK_SET
= 0x2,
214 SESSION_FLAG_FINALIZE_SINKS
= 0x4,
215 SESSION_FLAG_NEEDS_PREROLL
= 0x8,
216 SESSION_FLAG_END_OF_PRESENTATION
= 0x10,
221 IMFMediaSession IMFMediaSession_iface
;
222 IMFGetService IMFGetService_iface
;
223 IMFRateSupport IMFRateSupport_iface
;
224 IMFRateControl IMFRateControl_iface
;
225 IMFTopologyNodeAttributeEditor IMFTopologyNodeAttributeEditor_iface
;
226 IMFAsyncCallback commands_callback
;
227 IMFAsyncCallback events_callback
;
228 IMFAsyncCallback sink_finalizer_callback
;
230 IMFMediaEventQueue
*event_queue
;
231 IMFPresentationClock
*clock
;
232 IMFPresentationTimeSource
*system_time_source
;
233 IMFRateControl
*clock_rate_control
;
234 IMFTopoLoader
*topo_loader
;
235 IMFQualityManager
*quality_manager
;
238 IMFTopology
*current_topology
;
239 MF_TOPOSTATUS topo_status
;
240 MFTIME clock_stop_time
;
246 /* Latest Start() arguments. */
248 PROPVARIANT start_position
;
250 struct list topologies
;
251 struct list commands
;
252 enum session_state state
;
257 static inline struct media_session
*impl_from_IMFMediaSession(IMFMediaSession
*iface
)
259 return CONTAINING_RECORD(iface
, struct media_session
, IMFMediaSession_iface
);
262 static struct media_session
*impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
264 return CONTAINING_RECORD(iface
, struct media_session
, commands_callback
);
267 static struct media_session
*impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
269 return CONTAINING_RECORD(iface
, struct media_session
, events_callback
);
272 static struct media_session
*impl_from_sink_finalizer_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
274 return CONTAINING_RECORD(iface
, struct media_session
, sink_finalizer_callback
);
277 static struct media_session
*impl_from_IMFGetService(IMFGetService
*iface
)
279 return CONTAINING_RECORD(iface
, struct media_session
, IMFGetService_iface
);
282 static struct media_session
*impl_session_from_IMFRateSupport(IMFRateSupport
*iface
)
284 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateSupport_iface
);
287 static struct media_session
*impl_session_from_IMFRateControl(IMFRateControl
*iface
)
289 return CONTAINING_RECORD(iface
, struct media_session
, IMFRateControl_iface
);
292 static struct media_session
*impl_session_from_IMFTopologyNodeAttributeEditor(IMFTopologyNodeAttributeEditor
*iface
)
294 return CONTAINING_RECORD(iface
, struct media_session
, IMFTopologyNodeAttributeEditor_iface
);
297 static struct session_op
*impl_op_from_IUnknown(IUnknown
*iface
)
299 return CONTAINING_RECORD(iface
, struct session_op
, IUnknown_iface
);
302 static struct topo_node
*impl_node_from_IMFVideoSampleAllocatorNotify(IMFVideoSampleAllocatorNotify
*iface
)
304 return CONTAINING_RECORD(iface
, struct topo_node
, u
.sink
.notify_cb
);
307 /* IMFLocalMFTRegistration */
308 static HRESULT WINAPI
local_mft_registration_QueryInterface(IMFLocalMFTRegistration
*iface
, REFIID riid
, void **obj
)
310 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
312 if (IsEqualIID(riid
, &IID_IMFLocalMFTRegistration
) ||
313 IsEqualIID(riid
, &IID_IUnknown
))
316 IMFLocalMFTRegistration_AddRef(iface
);
320 WARN("Unexpected %s.\n", debugstr_guid(riid
));
322 return E_NOINTERFACE
;
325 static ULONG WINAPI
local_mft_registration_AddRef(IMFLocalMFTRegistration
*iface
)
330 static ULONG WINAPI
local_mft_registration_Release(IMFLocalMFTRegistration
*iface
)
335 static HRESULT WINAPI
local_mft_registration_RegisterMFTs(IMFLocalMFTRegistration
*iface
, MFT_REGISTRATION_INFO
*info
,
341 TRACE("%p, %p, %u.\n", iface
, info
, count
);
343 for (i
= 0; i
< count
; ++i
)
345 if (FAILED(hr
= MFTRegisterLocalByCLSID(&info
[i
].clsid
, &info
[i
].guidCategory
, info
[i
].pszName
,
346 info
[i
].uiFlags
, info
[i
].cInTypes
, info
[i
].pInTypes
, info
[i
].cOutTypes
, info
[i
].pOutTypes
)))
355 static const IMFLocalMFTRegistrationVtbl local_mft_registration_vtbl
=
357 local_mft_registration_QueryInterface
,
358 local_mft_registration_AddRef
,
359 local_mft_registration_Release
,
360 local_mft_registration_RegisterMFTs
,
363 static IMFLocalMFTRegistration local_mft_registration
= { &local_mft_registration_vtbl
};
365 static HRESULT WINAPI
session_op_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
367 if (IsEqualIID(riid
, &IID_IUnknown
))
370 IUnknown_AddRef(iface
);
375 return E_NOINTERFACE
;
378 static ULONG WINAPI
session_op_AddRef(IUnknown
*iface
)
380 struct session_op
*op
= impl_op_from_IUnknown(iface
);
381 ULONG refcount
= InterlockedIncrement(&op
->refcount
);
383 TRACE("%p, refcount %u.\n", iface
, refcount
);
388 static ULONG WINAPI
session_op_Release(IUnknown
*iface
)
390 struct session_op
*op
= impl_op_from_IUnknown(iface
);
391 ULONG refcount
= InterlockedDecrement(&op
->refcount
);
393 TRACE("%p, refcount %u.\n", iface
, refcount
);
399 case SESSION_CMD_SET_TOPOLOGY
:
400 if (op
->u
.set_topology
.topology
)
401 IMFTopology_Release(op
->u
.set_topology
.topology
);
403 case SESSION_CMD_START
:
404 PropVariantClear(&op
->u
.start
.start_position
);
406 case SESSION_CMD_QM_NOTIFY_TOPOLOGY
:
407 if (op
->u
.notify_topology
.topology
)
408 IMFTopology_Release(op
->u
.notify_topology
.topology
);
419 static const IUnknownVtbl session_op_vtbl
=
421 session_op_QueryInterface
,
426 static HRESULT
create_session_op(enum session_command command
, struct session_op
**ret
)
428 struct session_op
*op
;
430 if (!(op
= calloc(1, sizeof(*op
))))
431 return E_OUTOFMEMORY
;
433 op
->IUnknown_iface
.lpVtbl
= &session_op_vtbl
;
435 op
->command
= command
;
442 static HRESULT
session_is_shut_down(struct media_session
*session
)
444 return session
->state
== SESSION_STATE_SHUT_DOWN
? MF_E_SHUTDOWN
: S_OK
;
447 static void session_push_back_command(struct media_session
*session
, enum session_command command
)
449 struct session_op
*op
;
451 if (SUCCEEDED(create_session_op(command
, &op
)))
452 list_add_head(&session
->commands
, &op
->entry
);
455 static HRESULT
session_submit_command(struct media_session
*session
, struct session_op
*op
)
459 EnterCriticalSection(&session
->cs
);
460 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
462 if (list_empty(&session
->commands
))
463 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
464 list_add_tail(&session
->commands
, &op
->entry
);
465 IUnknown_AddRef(&op
->IUnknown_iface
);
467 LeaveCriticalSection(&session
->cs
);
472 static HRESULT
session_submit_simple_command(struct media_session
*session
, enum session_command command
)
474 struct session_op
*op
;
477 if (FAILED(hr
= create_session_op(command
, &op
)))
480 hr
= session_submit_command(session
, op
);
481 IUnknown_Release(&op
->IUnknown_iface
);
485 static void session_clear_queued_topologies(struct media_session
*session
)
487 struct queued_topology
*ptr
, *next
;
489 LIST_FOR_EACH_ENTRY_SAFE(ptr
, next
, &session
->topologies
, struct queued_topology
, entry
)
491 list_remove(&ptr
->entry
);
492 IMFTopology_Release(ptr
->topology
);
497 static void session_set_topo_status(struct media_session
*session
, HRESULT status
,
498 MF_TOPOSTATUS topo_status
)
500 IMFMediaEvent
*event
;
503 if (topo_status
== MF_TOPOSTATUS_INVALID
)
506 if (list_empty(&session
->topologies
))
508 FIXME("Unexpectedly empty topology queue.\n");
512 if (topo_status
> session
->presentation
.topo_status
)
514 struct queued_topology
*topology
= LIST_ENTRY(list_head(&session
->topologies
), struct queued_topology
, entry
);
516 param
.vt
= VT_UNKNOWN
;
517 param
.punkVal
= (IUnknown
*)topology
->topology
;
519 if (FAILED(MFCreateMediaEvent(MESessionTopologyStatus
, &GUID_NULL
, status
, ¶m
, &event
)))
522 session
->presentation
.topo_status
= topo_status
;
524 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_TOPOLOGY_STATUS
, topo_status
);
525 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
526 IMFMediaEvent_Release(event
);
530 static HRESULT
session_bind_output_nodes(IMFTopology
*topology
)
532 MF_TOPOLOGY_TYPE node_type
;
533 IMFStreamSink
*stream_sink
;
534 IMFMediaSink
*media_sink
;
535 WORD node_count
= 0, i
;
536 IMFTopologyNode
*node
;
537 IMFActivate
*activate
;
542 hr
= IMFTopology_GetNodeCount(topology
, &node_count
);
544 for (i
= 0; i
< node_count
; ++i
)
546 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
549 if (FAILED(hr
= IMFTopologyNode_GetNodeType(node
, &node_type
)) || node_type
!= MF_TOPOLOGY_OUTPUT_NODE
)
551 IMFTopologyNode_Release(node
);
555 if (SUCCEEDED(hr
= IMFTopologyNode_GetObject(node
, &object
)))
558 if (FAILED(IUnknown_QueryInterface(object
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
560 if (SUCCEEDED(hr
= IUnknown_QueryInterface(object
, &IID_IMFActivate
, (void **)&activate
)))
562 if (SUCCEEDED(hr
= IMFActivate_ActivateObject(activate
, &IID_IMFMediaSink
, (void **)&media_sink
)))
564 if (FAILED(IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_STREAMID
, &stream_id
)))
568 if (FAILED(IMFMediaSink_GetStreamSinkById(media_sink
, stream_id
, &stream_sink
)))
569 hr
= IMFMediaSink_AddStreamSink(media_sink
, stream_id
, NULL
, &stream_sink
);
572 hr
= IMFTopologyNode_SetObject(node
, (IUnknown
*)stream_sink
);
574 IMFMediaSink_Release(media_sink
);
578 IMFTopologyNode_SetUnknown(node
, &_MF_TOPONODE_IMFActivate
, (IUnknown
*)activate
);
580 IMFActivate_Release(activate
);
585 IMFStreamSink_Release(stream_sink
);
586 IUnknown_Release(object
);
589 IMFTopologyNode_Release(node
);
595 static void session_set_caps(struct media_session
*session
, DWORD caps
)
597 DWORD delta
= session
->caps
^ caps
;
598 IMFMediaEvent
*event
;
600 /* Delta is documented to reflect rate value changes as well, but it's not clear what to compare
601 them to, since session always queries for current object rates. */
605 session
->caps
= caps
;
607 if (FAILED(MFCreateMediaEvent(MESessionCapabilitiesChanged
, &GUID_NULL
, S_OK
, NULL
, &event
)))
610 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS
, caps
);
611 IMFMediaEvent_SetUINT32(event
, &MF_EVENT_SESSIONCAPS_DELTA
, delta
);
613 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
614 IMFMediaEvent_Release(event
);
617 static void transform_release_sample(struct sample
*sample
)
619 list_remove(&sample
->entry
);
621 IMFSample_Release(sample
->sample
);
625 static void transform_stream_drop_samples(struct transform_stream
*stream
)
627 struct sample
*sample
, *sample2
;
629 LIST_FOR_EACH_ENTRY_SAFE(sample
, sample2
, &stream
->samples
, struct sample
, entry
)
630 transform_release_sample(sample
);
633 static void release_topo_node(struct topo_node
*node
)
639 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
640 if (node
->u
.source
.source
)
641 IMFMediaSource_Release(node
->u
.source
.source
);
643 case MF_TOPOLOGY_TRANSFORM_NODE
:
644 for (i
= 0; i
< node
->u
.transform
.input_count
; ++i
)
645 transform_stream_drop_samples(&node
->u
.transform
.inputs
[i
]);
646 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
647 transform_stream_drop_samples(&node
->u
.transform
.outputs
[i
]);
648 free(node
->u
.transform
.inputs
);
649 free(node
->u
.transform
.outputs
);
650 free(node
->u
.transform
.input_map
);
651 free(node
->u
.transform
.output_map
);
653 case MF_TOPOLOGY_OUTPUT_NODE
:
654 if (node
->u
.sink
.allocator
)
655 IMFVideoSampleAllocator_Release(node
->u
.sink
.allocator
);
656 if (node
->u
.sink
.allocator_cb
)
658 IMFVideoSampleAllocatorCallback_SetCallback(node
->u
.sink
.allocator_cb
, NULL
);
659 IMFVideoSampleAllocatorCallback_Release(node
->u
.sink
.allocator_cb
);
666 if (node
->object
.object
)
667 IUnknown_Release(node
->object
.object
);
669 IMFTopologyNode_Release(node
->node
);
673 static void session_shutdown_current_topology(struct media_session
*session
)
675 unsigned int shutdown
, force_shutdown
;
676 MF_TOPOLOGY_TYPE node_type
;
677 IMFStreamSink
*stream_sink
;
678 IMFTopology
*topology
;
679 IMFTopologyNode
*node
;
680 IMFActivate
*activate
;
685 topology
= session
->presentation
.current_topology
;
686 force_shutdown
= session
->state
== SESSION_STATE_SHUT_DOWN
;
688 /* FIXME: should handle async MFTs, but these are not supported by the rest of the pipeline currently. */
690 while (SUCCEEDED(IMFTopology_GetNode(topology
, idx
++, &node
)))
692 if (SUCCEEDED(IMFTopologyNode_GetNodeType(node
, &node_type
)) &&
693 node_type
== MF_TOPOLOGY_OUTPUT_NODE
)
696 IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE
, &shutdown
);
698 if (force_shutdown
|| shutdown
)
700 if (SUCCEEDED(IMFTopologyNode_GetUnknown(node
, &_MF_TOPONODE_IMFActivate
, &IID_IMFActivate
,
701 (void **)&activate
)))
703 if (FAILED(hr
= IMFActivate_ShutdownObject(activate
)))
704 WARN("Failed to shut down activation object for the sink, hr %#x.\n", hr
);
705 IMFActivate_Release(activate
);
707 else if (SUCCEEDED(topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
709 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink
, &sink
)))
711 IMFMediaSink_Shutdown(sink
);
712 IMFMediaSink_Release(sink
);
715 IMFStreamSink_Release(stream_sink
);
720 IMFTopologyNode_Release(node
);
724 static void session_clear_command_list(struct media_session
*session
)
726 struct session_op
*op
, *op2
;
728 LIST_FOR_EACH_ENTRY_SAFE(op
, op2
, &session
->commands
, struct session_op
, entry
)
730 list_remove(&op
->entry
);
731 IUnknown_Release(&op
->IUnknown_iface
);
735 static void session_clear_presentation(struct media_session
*session
)
737 struct media_source
*source
, *source2
;
738 struct media_sink
*sink
, *sink2
;
739 struct topo_node
*node
, *node2
;
741 session_shutdown_current_topology(session
);
743 IMFTopology_Clear(session
->presentation
.current_topology
);
744 session
->presentation
.topo_status
= MF_TOPOSTATUS_INVALID
;
746 LIST_FOR_EACH_ENTRY_SAFE(source
, source2
, &session
->presentation
.sources
, struct media_source
, entry
)
748 list_remove(&source
->entry
);
750 IMFMediaSource_Release(source
->source
);
752 IMFPresentationDescriptor_Release(source
->pd
);
756 LIST_FOR_EACH_ENTRY_SAFE(node
, node2
, &session
->presentation
.nodes
, struct topo_node
, entry
)
758 list_remove(&node
->entry
);
759 release_topo_node(node
);
762 LIST_FOR_EACH_ENTRY_SAFE(sink
, sink2
, &session
->presentation
.sinks
, struct media_sink
, entry
)
764 list_remove(&sink
->entry
);
767 IMFMediaSink_Release(sink
->sink
);
769 IMFMediaSinkPreroll_Release(sink
->preroll
);
770 if (sink
->event_generator
)
771 IMFMediaEventGenerator_Release(sink
->event_generator
);
776 static struct topo_node
*session_get_node_by_id(const struct media_session
*session
, TOPOID id
)
778 struct topo_node
*node
;
780 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
782 if (node
->node_id
== id
)
789 static void session_command_complete(struct media_session
*session
)
791 struct session_op
*op
;
794 /* Pop current command, submit next. */
795 if ((e
= list_head(&session
->commands
)))
797 op
= LIST_ENTRY(e
, struct session_op
, entry
);
798 list_remove(&op
->entry
);
799 IUnknown_Release(&op
->IUnknown_iface
);
802 if ((e
= list_head(&session
->commands
)))
804 op
= LIST_ENTRY(e
, struct session_op
, entry
);
805 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &session
->commands_callback
, &op
->IUnknown_iface
);
809 static void session_command_complete_with_event(struct media_session
*session
, MediaEventType event
,
810 HRESULT status
, const PROPVARIANT
*param
)
812 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, event
, &GUID_NULL
, status
, param
);
813 session_command_complete(session
);
816 static void session_start(struct media_session
*session
, const GUID
*time_format
, const PROPVARIANT
*start_position
)
818 struct media_source
*source
;
821 switch (session
->state
)
823 case SESSION_STATE_STOPPED
:
825 /* Start request with no current topology. */
826 if (session
->presentation
.topo_status
== MF_TOPOSTATUS_INVALID
)
828 session_command_complete_with_event(session
, MESessionStarted
, MF_E_INVALIDREQUEST
, NULL
);
833 case SESSION_STATE_PAUSED
:
835 session
->presentation
.time_format
= *time_format
;
836 session
->presentation
.start_position
.vt
= VT_EMPTY
;
837 PropVariantCopy(&session
->presentation
.start_position
, start_position
);
839 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
841 if (!(session
->presentation
.flags
& SESSION_FLAG_SOURCES_SUBSCRIBED
))
843 if (FAILED(hr
= IMFMediaSource_BeginGetEvent(source
->source
, &session
->events_callback
,
846 WARN("Failed to subscribe to source events, hr %#x.\n", hr
);
850 if (FAILED(hr
= IMFMediaSource_Start(source
->source
, source
->pd
, &GUID_NULL
, start_position
)))
851 WARN("Failed to start media source %p, hr %#x.\n", source
->source
, hr
);
854 session
->presentation
.flags
|= SESSION_FLAG_SOURCES_SUBSCRIBED
;
855 session
->state
= SESSION_STATE_STARTING_SOURCES
;
857 case SESSION_STATE_STARTED
:
858 FIXME("Seeking is not implemented.\n");
859 session_command_complete(session
);
862 session_command_complete_with_event(session
, MESessionStarted
, MF_E_INVALIDREQUEST
, NULL
);
867 static void session_set_started(struct media_session
*session
)
869 struct media_source
*source
;
870 IMFMediaEvent
*event
;
874 session
->state
= SESSION_STATE_STARTED
;
876 caps
= session
->caps
| MFSESSIONCAP_PAUSE
;
878 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
880 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &flags
)))
882 if (!(flags
& MFMEDIASOURCE_CAN_PAUSE
))
884 caps
&= ~MFSESSIONCAP_PAUSE
;
890 session_set_caps(session
, caps
);
892 if (SUCCEEDED(MFCreateMediaEvent(MESessionStarted
, &GUID_NULL
, S_OK
, NULL
, &event
)))
894 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
895 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
896 IMFMediaEvent_Release(event
);
898 session_command_complete(session
);
901 static void session_set_paused(struct media_session
*session
, unsigned int state
, HRESULT status
)
903 /* Failed event status could indicate a failure during normal transition to paused state,
904 or an attempt to pause from invalid initial state. To finalize failed transition in the former case,
905 state is still forced to PAUSED, otherwise previous state is retained. */
906 if (state
!= ~0u) session
->state
= state
;
907 if (SUCCEEDED(status
))
908 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
909 session_command_complete_with_event(session
, MESessionPaused
, status
, NULL
);
912 static void session_set_closed(struct media_session
*session
, HRESULT status
)
914 session
->state
= SESSION_STATE_CLOSED
;
915 if (SUCCEEDED(status
))
916 session_set_caps(session
, session
->caps
& ~(MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
));
917 session_command_complete_with_event(session
, MESessionClosed
, status
, NULL
);
920 static void session_pause(struct media_session
*session
)
922 unsigned int state
= ~0u;
925 switch (session
->state
)
927 case SESSION_STATE_STARTED
:
929 /* Transition in two steps - pause the clock, wait for sinks, then pause sources. */
930 if (SUCCEEDED(hr
= IMFPresentationClock_Pause(session
->clock
)))
931 session
->state
= SESSION_STATE_PAUSING_SINKS
;
932 state
= SESSION_STATE_PAUSED
;
936 case SESSION_STATE_STOPPED
:
937 hr
= MF_E_SESSION_PAUSEWHILESTOPPED
;
940 hr
= MF_E_INVALIDREQUEST
;
944 session_set_paused(session
, state
, hr
);
947 static void session_clear_end_of_presentation(struct media_session
*session
)
949 struct media_source
*source
;
950 struct topo_node
*node
;
952 session
->presentation
.flags
&= ~SESSION_FLAG_END_OF_PRESENTATION
;
953 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
955 source
->flags
&= ~SOURCE_FLAG_END_OF_PRESENTATION
;
957 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
959 node
->flags
&= ~TOPO_NODE_END_OF_STREAM
;
961 session
->presentation
.topo_status
= MF_TOPOSTATUS_READY
;
964 static void session_set_stopped(struct media_session
*session
, HRESULT status
)
966 MediaEventType event_type
;
967 IMFMediaEvent
*event
;
969 session
->state
= SESSION_STATE_STOPPED
;
970 event_type
= session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
? MESessionEnded
: MESessionStopped
;
972 if (SUCCEEDED(MFCreateMediaEvent(event_type
, &GUID_NULL
, status
, NULL
, &event
)))
974 IMFMediaEvent_SetUINT64(event
, &MF_SESSION_APPROX_EVENT_OCCURRENCE_TIME
, session
->presentation
.clock_stop_time
);
975 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
976 IMFMediaEvent_Release(event
);
978 session_clear_end_of_presentation(session
);
979 session_command_complete(session
);
982 static void session_stop(struct media_session
*session
)
984 HRESULT hr
= MF_E_INVALIDREQUEST
;
986 switch (session
->state
)
988 case SESSION_STATE_STARTED
:
989 case SESSION_STATE_PAUSED
:
991 /* Transition in two steps - stop the clock, wait for sinks, then stop sources. */
992 IMFPresentationClock_GetTime(session
->clock
, &session
->presentation
.clock_stop_time
);
993 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
994 session
->state
= SESSION_STATE_STOPPING_SINKS
;
996 session_set_stopped(session
, hr
);
999 case SESSION_STATE_STOPPED
:
1003 session_command_complete_with_event(session
, MESessionStopped
, hr
, NULL
);
1008 static HRESULT
session_finalize_sinks(struct media_session
*session
)
1010 IMFFinalizableMediaSink
*fin_sink
;
1011 BOOL sinks_finalized
= TRUE
;
1012 struct media_sink
*sink
;
1015 session
->presentation
.flags
&= ~SESSION_FLAG_FINALIZE_SINKS
;
1016 session
->state
= SESSION_STATE_FINALIZING_SINKS
;
1018 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1020 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
1022 hr
= IMFFinalizableMediaSink_BeginFinalize(fin_sink
, &session
->sink_finalizer_callback
,
1023 (IUnknown
*)fin_sink
);
1024 IMFFinalizableMediaSink_Release(fin_sink
);
1027 sinks_finalized
= FALSE
;
1030 sink
->finalized
= TRUE
;
1033 if (sinks_finalized
)
1034 session_set_closed(session
, hr
);
1039 static void session_close(struct media_session
*session
)
1043 switch (session
->state
)
1045 case SESSION_STATE_STOPPED
:
1046 hr
= session_finalize_sinks(session
);
1048 case SESSION_STATE_STARTED
:
1049 case SESSION_STATE_PAUSED
:
1050 session
->presentation
.flags
|= SESSION_FLAG_FINALIZE_SINKS
;
1051 if (SUCCEEDED(hr
= IMFPresentationClock_Stop(session
->clock
)))
1052 session
->state
= SESSION_STATE_STOPPING_SINKS
;
1055 hr
= MF_E_INVALIDREQUEST
;
1059 session_clear_queued_topologies(session
);
1061 session_set_closed(session
, hr
);
1064 static void session_clear_topologies(struct media_session
*session
)
1068 if (session
->state
== SESSION_STATE_CLOSED
)
1069 hr
= MF_E_INVALIDREQUEST
;
1071 session_clear_queued_topologies(session
);
1072 session_command_complete_with_event(session
, MESessionTopologiesCleared
, hr
, NULL
);
1075 static struct media_source
*session_get_media_source(struct media_session
*session
, IMFMediaSource
*source
)
1077 struct media_source
*cur
;
1079 LIST_FOR_EACH_ENTRY(cur
, &session
->presentation
.sources
, struct media_source
, entry
)
1081 if (source
== cur
->source
)
1088 static void session_release_media_source(struct media_source
*source
)
1090 IMFMediaSource_Release(source
->source
);
1092 IMFPresentationDescriptor_Release(source
->pd
);
1096 static HRESULT
session_add_media_source(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSource
*source
)
1098 struct media_source
*media_source
;
1101 if (session_get_media_source(session
, source
))
1104 if (!(media_source
= calloc(1, sizeof(*media_source
))))
1105 return E_OUTOFMEMORY
;
1107 media_source
->source
= source
;
1108 IMFMediaSource_AddRef(media_source
->source
);
1110 hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_PRESENTATION_DESCRIPTOR
, &IID_IMFPresentationDescriptor
,
1111 (void **)&media_source
->pd
);
1114 list_add_tail(&session
->presentation
.sources
, &media_source
->entry
);
1116 session_release_media_source(media_source
);
1121 static void session_raise_topology_set(struct media_session
*session
, IMFTopology
*topology
, HRESULT status
)
1125 param
.vt
= topology
? VT_UNKNOWN
: VT_EMPTY
;
1126 param
.punkVal
= (IUnknown
*)topology
;
1128 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MESessionTopologySet
, &GUID_NULL
, status
, ¶m
);
1131 static DWORD
session_get_object_rate_caps(IUnknown
*object
)
1133 IMFRateSupport
*rate_support
;
1137 if (SUCCEEDED(MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
1140 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_FORWARD
, TRUE
, &rate
)) && rate
!= 0.0f
)
1141 caps
|= MFSESSIONCAP_RATE_FORWARD
;
1144 if (SUCCEEDED(IMFRateSupport_GetFastestRate(rate_support
, MFRATE_REVERSE
, TRUE
, &rate
)) && rate
!= 0.0f
)
1145 caps
|= MFSESSIONCAP_RATE_REVERSE
;
1147 IMFRateSupport_Release(rate_support
);
1153 static HRESULT
session_add_media_sink(struct media_session
*session
, IMFTopologyNode
*node
, IMFMediaSink
*sink
)
1155 struct media_sink
*media_sink
;
1156 unsigned int disable_preroll
= 0;
1159 LIST_FOR_EACH_ENTRY(media_sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1161 if (sink
== media_sink
->sink
)
1165 if (!(media_sink
= calloc(1, sizeof(*media_sink
))))
1166 return E_OUTOFMEMORY
;
1168 media_sink
->sink
= sink
;
1169 IMFMediaSink_AddRef(media_sink
->sink
);
1171 IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaEventGenerator
, (void **)&media_sink
->event_generator
);
1173 IMFTopologyNode_GetUINT32(node
, &MF_TOPONODE_DISABLE_PREROLL
, &disable_preroll
);
1174 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
, &flags
)) && flags
& MEDIASINK_CAN_PREROLL
&& !disable_preroll
)
1176 if (SUCCEEDED(IMFMediaSink_QueryInterface(media_sink
->sink
, &IID_IMFMediaSinkPreroll
, (void **)&media_sink
->preroll
)))
1177 session
->presentation
.flags
|= SESSION_FLAG_NEEDS_PREROLL
;
1180 list_add_tail(&session
->presentation
.sinks
, &media_sink
->entry
);
1185 static DWORD
transform_node_get_stream_id(struct topo_node
*node
, BOOL output
, unsigned int index
)
1187 DWORD
*map
= output
? node
->u
.transform
.output_map
: node
->u
.transform
.input_map
;
1188 return map
? map
[index
] : index
;
1191 static HRESULT
session_set_transform_stream_info(struct topo_node
*node
)
1193 DWORD
*input_map
= NULL
, *output_map
= NULL
;
1194 DWORD i
, input_count
, output_count
;
1195 struct transform_stream
*streams
;
1196 unsigned int block_alignment
;
1197 IMFMediaType
*media_type
;
1201 hr
= IMFTransform_GetStreamCount(node
->object
.transform
, &input_count
, &output_count
);
1202 if (SUCCEEDED(hr
) && (input_count
> 1 || output_count
> 1))
1204 input_map
= calloc(input_count
, sizeof(*input_map
));
1205 output_map
= calloc(output_count
, sizeof(*output_map
));
1206 if (FAILED(IMFTransform_GetStreamIDs(node
->object
.transform
, input_count
, input_map
,
1207 output_count
, output_map
)))
1209 /* Assume sequential identifiers. */
1212 input_map
= output_map
= NULL
;
1218 node
->u
.transform
.input_map
= input_map
;
1219 node
->u
.transform
.output_map
= output_map
;
1221 streams
= calloc(input_count
, sizeof(*streams
));
1222 for (i
= 0; i
< input_count
; ++i
)
1223 list_init(&streams
[i
].samples
);
1224 node
->u
.transform
.inputs
= streams
;
1225 node
->u
.transform
.input_count
= input_count
;
1227 streams
= calloc(output_count
, sizeof(*streams
));
1228 for (i
= 0; i
< output_count
; ++i
)
1230 list_init(&streams
[i
].samples
);
1232 if (SUCCEEDED(IMFTransform_GetOutputCurrentType(node
->object
.transform
,
1233 transform_node_get_stream_id(node
, TRUE
, i
), &media_type
)))
1235 if (SUCCEEDED(IMFMediaType_GetMajorType(media_type
, &major
)) && IsEqualGUID(&major
, &MFMediaType_Audio
)
1236 && SUCCEEDED(IMFMediaType_GetUINT32(media_type
, &MF_MT_AUDIO_BLOCK_ALIGNMENT
, &block_alignment
)))
1238 streams
[i
].min_buffer_size
= block_alignment
;
1240 IMFMediaType_Release(media_type
);
1243 node
->u
.transform
.outputs
= streams
;
1244 node
->u
.transform
.output_count
= output_count
;
1250 static HRESULT
session_get_stream_sink_type(IMFStreamSink
*sink
, IMFMediaType
**media_type
)
1252 IMFMediaTypeHandler
*handler
;
1255 if (SUCCEEDED(hr
= IMFStreamSink_GetMediaTypeHandler(sink
, &handler
)))
1257 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, media_type
);
1258 IMFMediaTypeHandler_Release(handler
);
1264 static HRESULT WINAPI
node_sample_allocator_cb_QueryInterface(IMFVideoSampleAllocatorNotify
*iface
,
1265 REFIID riid
, void **obj
)
1267 if (IsEqualIID(riid
, &IID_IMFVideoSampleAllocatorNotify
) ||
1268 IsEqualIID(riid
, &IID_IUnknown
))
1271 IMFVideoSampleAllocatorNotify_AddRef(iface
);
1276 return E_NOINTERFACE
;
1279 static ULONG WINAPI
node_sample_allocator_cb_AddRef(IMFVideoSampleAllocatorNotify
*iface
)
1284 static ULONG WINAPI
node_sample_allocator_cb_Release(IMFVideoSampleAllocatorNotify
*iface
)
1289 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
);
1291 static HRESULT WINAPI
node_sample_allocator_cb_NotifyRelease(IMFVideoSampleAllocatorNotify
*iface
)
1293 struct topo_node
*topo_node
= impl_node_from_IMFVideoSampleAllocatorNotify(iface
);
1294 struct session_op
*op
;
1296 if (SUCCEEDED(create_session_op(SESSION_CMD_SA_READY
, &op
)))
1298 op
->u
.sa_ready
.node_id
= topo_node
->node_id
;
1299 MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &topo_node
->session
->commands_callback
, &op
->IUnknown_iface
);
1300 IUnknown_Release(&op
->IUnknown_iface
);
1306 static const IMFVideoSampleAllocatorNotifyVtbl node_sample_allocator_cb_vtbl
=
1308 node_sample_allocator_cb_QueryInterface
,
1309 node_sample_allocator_cb_AddRef
,
1310 node_sample_allocator_cb_Release
,
1311 node_sample_allocator_cb_NotifyRelease
,
1314 static HRESULT
session_append_node(struct media_session
*session
, IMFTopologyNode
*node
)
1316 struct topo_node
*topo_node
;
1317 IMFMediaSink
*media_sink
;
1318 IMFMediaType
*media_type
;
1319 IMFStreamDescriptor
*sd
;
1322 if (!(topo_node
= calloc(1, sizeof(*topo_node
))))
1323 return E_OUTOFMEMORY
;
1325 IMFTopologyNode_GetNodeType(node
, &topo_node
->type
);
1326 IMFTopologyNode_GetTopoNodeID(node
, &topo_node
->node_id
);
1327 topo_node
->node
= node
;
1328 IMFTopologyNode_AddRef(topo_node
->node
);
1329 topo_node
->session
= session
;
1331 switch (topo_node
->type
)
1333 case MF_TOPOLOGY_OUTPUT_NODE
:
1334 topo_node
->u
.sink
.notify_cb
.lpVtbl
= &node_sample_allocator_cb_vtbl
;
1336 if (FAILED(hr
= topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&topo_node
->object
.object
)))
1338 WARN("Failed to get stream sink interface, hr %#x.\n", hr
);
1342 if (FAILED(hr
= IMFStreamSink_GetMediaSink(topo_node
->object
.sink_stream
, &media_sink
)))
1345 if (SUCCEEDED(hr
= session_add_media_sink(session
, node
, media_sink
)))
1347 if (SUCCEEDED(session_get_stream_sink_type(topo_node
->object
.sink_stream
, &media_type
)))
1349 if (SUCCEEDED(MFGetService(topo_node
->object
.object
, &MR_VIDEO_ACCELERATION_SERVICE
,
1350 &IID_IMFVideoSampleAllocator
, (void **)&topo_node
->u
.sink
.allocator
)))
1352 if (FAILED(hr
= IMFVideoSampleAllocator_InitializeSampleAllocator(topo_node
->u
.sink
.allocator
,
1355 WARN("Failed to initialize sample allocator for the stream, hr %#x.\n", hr
);
1357 IMFVideoSampleAllocator_QueryInterface(topo_node
->u
.sink
.allocator
,
1358 &IID_IMFVideoSampleAllocatorCallback
, (void **)&topo_node
->u
.sink
.allocator_cb
);
1359 IMFVideoSampleAllocatorCallback_SetCallback(topo_node
->u
.sink
.allocator_cb
,
1360 &topo_node
->u
.sink
.notify_cb
);
1362 IMFMediaType_Release(media_type
);
1365 IMFMediaSink_Release(media_sink
);
1368 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
1369 if (FAILED(IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_SOURCE
, &IID_IMFMediaSource
,
1370 (void **)&topo_node
->u
.source
.source
)))
1372 WARN("Missing MF_TOPONODE_SOURCE, hr %#x.\n", hr
);
1376 if (FAILED(hr
= session_add_media_source(session
, node
, topo_node
->u
.source
.source
)))
1379 if (FAILED(hr
= IMFTopologyNode_GetUnknown(node
, &MF_TOPONODE_STREAM_DESCRIPTOR
,
1380 &IID_IMFStreamDescriptor
, (void **)&sd
)))
1382 WARN("Missing MF_TOPONODE_STREAM_DESCRIPTOR, hr %#x.\n", hr
);
1386 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &topo_node
->u
.source
.stream_id
);
1387 IMFStreamDescriptor_Release(sd
);
1390 case MF_TOPOLOGY_TRANSFORM_NODE
:
1392 if (SUCCEEDED(hr
= topology_node_get_object(node
, &IID_IMFTransform
, (void **)&topo_node
->object
.transform
)))
1394 hr
= session_set_transform_stream_info(topo_node
);
1397 WARN("Failed to get IMFTransform for MFT node, hr %#x.\n", hr
);
1400 case MF_TOPOLOGY_TEE_NODE
:
1401 FIXME("Unsupported node type %d.\n", topo_node
->type
);
1409 list_add_tail(&session
->presentation
.nodes
, &topo_node
->entry
);
1411 release_topo_node(topo_node
);
1416 static HRESULT
session_collect_nodes(struct media_session
*session
)
1418 IMFTopology
*topology
= session
->presentation
.current_topology
;
1419 IMFTopologyNode
*node
;
1423 if (!list_empty(&session
->presentation
.nodes
))
1426 if (FAILED(hr
= IMFTopology_GetNodeCount(topology
, &count
)))
1429 for (i
= 0; i
< count
; ++i
)
1431 if (FAILED(hr
= IMFTopology_GetNode(topology
, i
, &node
)))
1433 WARN("Failed to get node %u.\n", i
);
1437 hr
= session_append_node(session
, node
);
1438 IMFTopologyNode_Release(node
);
1441 WARN("Failed to add node %u.\n", i
);
1449 static HRESULT
session_set_current_topology(struct media_session
*session
, IMFTopology
*topology
)
1451 struct media_source
*source
;
1452 DWORD caps
, object_flags
;
1453 struct media_sink
*sink
;
1454 struct topo_node
*node
;
1455 struct session_op
*op
;
1456 IMFMediaEvent
*event
;
1459 if (session
->quality_manager
)
1461 if (SUCCEEDED(create_session_op(SESSION_CMD_QM_NOTIFY_TOPOLOGY
, &op
)))
1463 op
->u
.notify_topology
.topology
= topology
;
1464 IMFTopology_AddRef(op
->u
.notify_topology
.topology
);
1465 session_submit_command(session
, op
);
1466 IUnknown_Release(&op
->IUnknown_iface
);
1470 if (FAILED(hr
= IMFTopology_CloneFrom(session
->presentation
.current_topology
, topology
)))
1472 WARN("Failed to clone topology, hr %#x.\n", hr
);
1476 session_collect_nodes(session
);
1478 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
1480 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
1482 if (FAILED(hr
= IMFTransform_ProcessMessage(node
->object
.transform
,
1483 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING
, 0)))
1488 /* FIXME: attributes are all zero for now */
1489 if (SUCCEEDED(MFCreateMediaEvent(MESessionNotifyPresentationTime
, &GUID_NULL
, S_OK
, NULL
, &event
)))
1491 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME
, 0);
1492 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_PRESENTATION_TIME_OFFSET
, 0);
1493 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_START_PRESENTATION_TIME_AT_OUTPUT
, 0);
1495 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
1496 IMFMediaEvent_Release(event
);
1499 /* Update session caps. */
1500 caps
= MFSESSIONCAP_START
| MFSESSIONCAP_SEEK
| MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
|
1501 MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1503 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
1509 if (SUCCEEDED(IMFMediaSource_GetCharacteristics(source
->source
, &object_flags
)))
1511 if (!(object_flags
& MFMEDIASOURCE_DOES_NOT_USE_NETWORK
))
1512 caps
&= ~MFSESSIONCAP_DOES_NOT_USE_NETWORK
;
1513 if (!(object_flags
& MFMEDIASOURCE_CAN_SEEK
))
1514 caps
&= ~MFSESSIONCAP_SEEK
;
1517 /* Mask unsupported rate caps. */
1519 caps
&= session_get_object_rate_caps(source
->object
)
1520 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1523 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
1529 if (SUCCEEDED(IMFMediaSink_GetCharacteristics(sink
->sink
, &object_flags
)))
1531 if (!(object_flags
& MEDIASINK_RATELESS
))
1532 caps
&= session_get_object_rate_caps(sink
->object
)
1533 | ~(MFSESSIONCAP_RATE_FORWARD
| MFSESSIONCAP_RATE_REVERSE
);
1537 session_set_caps(session
, caps
);
1542 static void session_set_topology(struct media_session
*session
, DWORD flags
, IMFTopology
*topology
)
1544 IMFTopology
*resolved_topology
= NULL
;
1547 /* Resolve unless claimed to be full. */
1548 if (!(flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
) && topology
)
1550 if (!(flags
& MFSESSION_SETTOPOLOGY_NORESOLUTION
))
1552 hr
= session_bind_output_nodes(topology
);
1555 hr
= IMFTopoLoader_Load(session
->topo_loader
, topology
, &resolved_topology
, NULL
/* FIXME? */);
1559 topology
= resolved_topology
;
1564 if (flags
& MFSESSION_SETTOPOLOGY_CLEAR_CURRENT
)
1566 if ((topology
&& topology
== session
->presentation
.current_topology
) || !topology
)
1568 /* FIXME: stop current topology, queue next one. */
1569 session_clear_presentation(session
);
1576 else if (topology
&& flags
& MFSESSION_SETTOPOLOGY_IMMEDIATE
)
1578 session_clear_queued_topologies(session
);
1579 session_clear_presentation(session
);
1582 session_raise_topology_set(session
, topology
, hr
);
1584 /* With no current topology set it right away, otherwise queue. */
1587 struct queued_topology
*queued_topology
;
1589 if ((queued_topology
= calloc(1, sizeof(*queued_topology
))))
1591 queued_topology
->topology
= topology
;
1592 IMFTopology_AddRef(queued_topology
->topology
);
1594 list_add_tail(&session
->topologies
, &queued_topology
->entry
);
1597 if (session
->presentation
.topo_status
== MF_TOPOSTATUS_INVALID
)
1599 hr
= session_set_current_topology(session
, topology
);
1600 session_set_topo_status(session
, hr
, MF_TOPOSTATUS_READY
);
1604 if (resolved_topology
)
1605 IMFTopology_Release(resolved_topology
);
1608 static HRESULT WINAPI
mfsession_QueryInterface(IMFMediaSession
*iface
, REFIID riid
, void **out
)
1610 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1612 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1616 if (IsEqualIID(riid
, &IID_IMFMediaSession
) ||
1617 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1618 IsEqualIID(riid
, &IID_IUnknown
))
1620 *out
= &session
->IMFMediaSession_iface
;
1622 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1624 *out
= &session
->IMFGetService_iface
;
1626 else if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1628 *out
= &session
->IMFRateSupport_iface
;
1630 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
1632 *out
= &session
->IMFRateControl_iface
;
1637 IMFMediaSession_AddRef(iface
);
1641 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1642 return E_NOINTERFACE
;
1645 static ULONG WINAPI
mfsession_AddRef(IMFMediaSession
*iface
)
1647 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1648 ULONG refcount
= InterlockedIncrement(&session
->refcount
);
1650 TRACE("%p, refcount %u.\n", iface
, refcount
);
1655 static ULONG WINAPI
mfsession_Release(IMFMediaSession
*iface
)
1657 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1658 ULONG refcount
= InterlockedDecrement(&session
->refcount
);
1660 TRACE("%p, refcount %u.\n", iface
, refcount
);
1664 session_clear_queued_topologies(session
);
1665 session_clear_presentation(session
);
1666 session_clear_command_list(session
);
1667 if (session
->presentation
.current_topology
)
1668 IMFTopology_Release(session
->presentation
.current_topology
);
1669 if (session
->event_queue
)
1670 IMFMediaEventQueue_Release(session
->event_queue
);
1672 IMFPresentationClock_Release(session
->clock
);
1673 if (session
->system_time_source
)
1674 IMFPresentationTimeSource_Release(session
->system_time_source
);
1675 if (session
->clock_rate_control
)
1676 IMFRateControl_Release(session
->clock_rate_control
);
1677 if (session
->topo_loader
)
1678 IMFTopoLoader_Release(session
->topo_loader
);
1679 if (session
->quality_manager
)
1680 IMFQualityManager_Release(session
->quality_manager
);
1681 DeleteCriticalSection(&session
->cs
);
1688 static HRESULT WINAPI
mfsession_GetEvent(IMFMediaSession
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1690 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1692 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
1694 return IMFMediaEventQueue_GetEvent(session
->event_queue
, flags
, event
);
1697 static HRESULT WINAPI
mfsession_BeginGetEvent(IMFMediaSession
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1699 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1701 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1703 return IMFMediaEventQueue_BeginGetEvent(session
->event_queue
, callback
, state
);
1706 static HRESULT WINAPI
mfsession_EndGetEvent(IMFMediaSession
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
1708 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1710 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1712 return IMFMediaEventQueue_EndGetEvent(session
->event_queue
, result
, event
);
1715 static HRESULT WINAPI
mfsession_QueueEvent(IMFMediaSession
*iface
, MediaEventType event_type
, REFGUID ext_type
,
1716 HRESULT hr
, const PROPVARIANT
*value
)
1718 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1720 TRACE("%p, %d, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1722 return IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, event_type
, ext_type
, hr
, value
);
1725 static HRESULT WINAPI
mfsession_SetTopology(IMFMediaSession
*iface
, DWORD flags
, IMFTopology
*topology
)
1727 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1728 struct session_op
*op
;
1729 WORD node_count
= 0;
1732 TRACE("%p, %#x, %p.\n", iface
, flags
, topology
);
1736 if (FAILED(IMFTopology_GetNodeCount(topology
, &node_count
)) || node_count
== 0)
1737 return E_INVALIDARG
;
1740 if (FAILED(hr
= create_session_op(SESSION_CMD_SET_TOPOLOGY
, &op
)))
1743 op
->u
.set_topology
.flags
= flags
;
1744 op
->u
.set_topology
.topology
= topology
;
1745 if (op
->u
.set_topology
.topology
)
1746 IMFTopology_AddRef(op
->u
.set_topology
.topology
);
1748 hr
= session_submit_command(session
, op
);
1749 IUnknown_Release(&op
->IUnknown_iface
);
1754 static HRESULT WINAPI
mfsession_ClearTopologies(IMFMediaSession
*iface
)
1756 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1758 TRACE("%p.\n", iface
);
1760 return session_submit_simple_command(session
, SESSION_CMD_CLEAR_TOPOLOGIES
);
1763 static HRESULT WINAPI
mfsession_Start(IMFMediaSession
*iface
, const GUID
*format
, const PROPVARIANT
*start_position
)
1765 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1766 struct session_op
*op
;
1769 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(format
), start_position
);
1771 if (!start_position
)
1774 if (FAILED(hr
= create_session_op(SESSION_CMD_START
, &op
)))
1777 op
->u
.start
.time_format
= format
? *format
: GUID_NULL
;
1778 hr
= PropVariantCopy(&op
->u
.start
.start_position
, start_position
);
1781 hr
= session_submit_command(session
, op
);
1783 IUnknown_Release(&op
->IUnknown_iface
);
1787 static HRESULT WINAPI
mfsession_Pause(IMFMediaSession
*iface
)
1789 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1791 TRACE("%p.\n", iface
);
1793 return session_submit_simple_command(session
, SESSION_CMD_PAUSE
);
1796 static HRESULT WINAPI
mfsession_Stop(IMFMediaSession
*iface
)
1798 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1800 TRACE("%p.\n", iface
);
1802 return session_submit_simple_command(session
, SESSION_CMD_STOP
);
1805 static HRESULT WINAPI
mfsession_Close(IMFMediaSession
*iface
)
1807 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1809 TRACE("%p.\n", iface
);
1811 return session_submit_simple_command(session
, SESSION_CMD_CLOSE
);
1814 static HRESULT WINAPI
mfsession_Shutdown(IMFMediaSession
*iface
)
1816 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1819 TRACE("%p.\n", iface
);
1821 EnterCriticalSection(&session
->cs
);
1822 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1824 session
->state
= SESSION_STATE_SHUT_DOWN
;
1825 IMFMediaEventQueue_Shutdown(session
->event_queue
);
1826 if (session
->quality_manager
)
1827 IMFQualityManager_Shutdown(session
->quality_manager
);
1828 MFShutdownObject((IUnknown
*)session
->clock
);
1829 IMFPresentationClock_Release(session
->clock
);
1830 session
->clock
= NULL
;
1831 session_clear_presentation(session
);
1832 session_clear_command_list(session
);
1834 LeaveCriticalSection(&session
->cs
);
1839 static HRESULT WINAPI
mfsession_GetClock(IMFMediaSession
*iface
, IMFClock
**clock
)
1841 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1844 TRACE("%p, %p.\n", iface
, clock
);
1846 EnterCriticalSection(&session
->cs
);
1847 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1849 *clock
= (IMFClock
*)session
->clock
;
1850 IMFClock_AddRef(*clock
);
1852 LeaveCriticalSection(&session
->cs
);
1857 static HRESULT WINAPI
mfsession_GetSessionCapabilities(IMFMediaSession
*iface
, DWORD
*caps
)
1859 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1862 TRACE("%p, %p.\n", iface
, caps
);
1867 EnterCriticalSection(&session
->cs
);
1868 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1869 *caps
= session
->caps
;
1870 LeaveCriticalSection(&session
->cs
);
1875 static HRESULT WINAPI
mfsession_GetFullTopology(IMFMediaSession
*iface
, DWORD flags
, TOPOID id
, IMFTopology
**topology
)
1877 struct media_session
*session
= impl_from_IMFMediaSession(iface
);
1878 struct queued_topology
*queued
;
1882 TRACE("%p, %#x, %s, %p.\n", iface
, flags
, wine_dbgstr_longlong(id
), topology
);
1886 EnterCriticalSection(&session
->cs
);
1888 if (SUCCEEDED(hr
= session_is_shut_down(session
)))
1890 if (flags
& MFSESSION_GETFULLTOPOLOGY_CURRENT
)
1892 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
1893 *topology
= session
->presentation
.current_topology
;
1895 hr
= MF_E_INVALIDREQUEST
;
1899 LIST_FOR_EACH_ENTRY(queued
, &session
->topologies
, struct queued_topology
, entry
)
1901 if (SUCCEEDED(IMFTopology_GetTopologyID(queued
->topology
, &topo_id
)) && topo_id
== id
)
1903 *topology
= queued
->topology
;
1910 IMFTopology_AddRef(*topology
);
1913 LeaveCriticalSection(&session
->cs
);
1918 static const IMFMediaSessionVtbl mfmediasessionvtbl
=
1920 mfsession_QueryInterface
,
1924 mfsession_BeginGetEvent
,
1925 mfsession_EndGetEvent
,
1926 mfsession_QueueEvent
,
1927 mfsession_SetTopology
,
1928 mfsession_ClearTopologies
,
1935 mfsession_GetSessionCapabilities
,
1936 mfsession_GetFullTopology
,
1939 static HRESULT WINAPI
session_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
1941 struct media_session
*session
= impl_from_IMFGetService(iface
);
1942 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
1945 static ULONG WINAPI
session_get_service_AddRef(IMFGetService
*iface
)
1947 struct media_session
*session
= impl_from_IMFGetService(iface
);
1948 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
1951 static ULONG WINAPI
session_get_service_Release(IMFGetService
*iface
)
1953 struct media_session
*session
= impl_from_IMFGetService(iface
);
1954 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
1957 typedef BOOL (*p_renderer_node_test_func
)(IMFMediaSink
*sink
);
1959 static BOOL
session_video_renderer_test_func(IMFMediaSink
*sink
)
1964 /* Use first sink to support IMFVideoRenderer. */
1965 hr
= IMFMediaSink_QueryInterface(sink
, &IID_IMFVideoRenderer
, (void **)&obj
);
1967 IUnknown_Release(obj
);
1972 static BOOL
session_audio_renderer_test_func(IMFMediaSink
*sink
)
1974 return mf_is_sar_sink(sink
);
1977 static HRESULT
session_get_renderer_node_service(struct media_session
*session
,
1978 p_renderer_node_test_func node_test_func
, REFGUID service
, REFIID riid
, void **obj
)
1980 HRESULT hr
= E_NOINTERFACE
;
1981 IMFStreamSink
*stream_sink
;
1982 IMFTopologyNode
*node
;
1983 IMFCollection
*nodes
;
1987 if (session
->presentation
.current_topology
)
1989 if (SUCCEEDED(IMFTopology_GetOutputNodeCollection(session
->presentation
.current_topology
,
1992 while (IMFCollection_GetElement(nodes
, i
++, (IUnknown
**)&node
) == S_OK
)
1994 if (SUCCEEDED(topology_node_get_object(node
, &IID_IMFStreamSink
, (void **)&stream_sink
)))
1996 if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink
, &sink
)))
1998 if (node_test_func(sink
))
2000 if (FAILED(hr
= MFGetService((IUnknown
*)sink
, service
, riid
, obj
)))
2001 WARN("Failed to get service from renderer node, %#x.\n", hr
);
2004 IMFStreamSink_Release(stream_sink
);
2007 IMFTopologyNode_Release(node
);
2013 IMFCollection_Release(nodes
);
2020 static HRESULT
session_get_audio_render_service(struct media_session
*session
, REFGUID service
,
2021 REFIID riid
, void **obj
)
2023 return session_get_renderer_node_service(session
, session_audio_renderer_test_func
,
2024 service
, riid
, obj
);
2027 static HRESULT
session_get_video_render_service(struct media_session
*session
, REFGUID service
,
2028 REFIID riid
, void **obj
)
2030 return session_get_renderer_node_service(session
, session_video_renderer_test_func
,
2031 service
, riid
, obj
);
2034 static HRESULT WINAPI
session_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
2036 struct media_session
*session
= impl_from_IMFGetService(iface
);
2039 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
2043 EnterCriticalSection(&session
->cs
);
2044 if (FAILED(hr
= session_is_shut_down(session
)))
2047 else if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
2049 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
2051 *obj
= &session
->IMFRateSupport_iface
;
2053 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
2055 *obj
= &session
->IMFRateControl_iface
;
2061 IUnknown_AddRef((IUnknown
*)*obj
);
2063 else if (IsEqualGUID(service
, &MF_LOCAL_MFT_REGISTRATION_SERVICE
))
2065 hr
= IMFLocalMFTRegistration_QueryInterface(&local_mft_registration
, riid
, obj
);
2067 else if (IsEqualGUID(service
, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE
))
2069 *obj
= &session
->IMFTopologyNodeAttributeEditor_iface
;
2070 IUnknown_AddRef((IUnknown
*)*obj
);
2072 else if (IsEqualGUID(service
, &MR_VIDEO_RENDER_SERVICE
))
2074 hr
= session_get_video_render_service(session
, service
, riid
, obj
);
2076 else if (IsEqualGUID(service
, &MR_POLICY_VOLUME_SERVICE
) ||
2077 IsEqualGUID(service
, &MR_STREAM_VOLUME_SERVICE
))
2079 hr
= session_get_audio_render_service(session
, service
, riid
, obj
);
2082 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
2084 LeaveCriticalSection(&session
->cs
);
2089 static const IMFGetServiceVtbl session_get_service_vtbl
=
2091 session_get_service_QueryInterface
,
2092 session_get_service_AddRef
,
2093 session_get_service_Release
,
2094 session_get_service_GetService
,
2097 static HRESULT WINAPI
session_commands_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2099 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2100 IsEqualIID(riid
, &IID_IUnknown
))
2103 IMFAsyncCallback_AddRef(iface
);
2107 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2109 return E_NOINTERFACE
;
2112 static ULONG WINAPI
session_commands_callback_AddRef(IMFAsyncCallback
*iface
)
2114 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2115 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2118 static ULONG WINAPI
session_commands_callback_Release(IMFAsyncCallback
*iface
)
2120 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2121 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2124 static HRESULT WINAPI
session_commands_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2129 static HRESULT WINAPI
session_commands_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
2131 struct session_op
*op
= impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result
));
2132 struct media_session
*session
= impl_from_commands_callback_IMFAsyncCallback(iface
);
2133 struct topo_node
*topo_node
;
2134 IMFTopologyNode
*upstream_node
;
2135 DWORD upstream_output
;
2137 EnterCriticalSection(&session
->cs
);
2139 switch (op
->command
)
2141 case SESSION_CMD_CLEAR_TOPOLOGIES
:
2142 session_clear_topologies(session
);
2144 case SESSION_CMD_SET_TOPOLOGY
:
2145 session_set_topology(session
, op
->u
.set_topology
.flags
, op
->u
.set_topology
.topology
);
2146 session_command_complete(session
);
2148 case SESSION_CMD_START
:
2149 session_start(session
, &op
->u
.start
.time_format
, &op
->u
.start
.start_position
);
2151 case SESSION_CMD_PAUSE
:
2152 session_pause(session
);
2154 case SESSION_CMD_STOP
:
2155 session_stop(session
);
2157 case SESSION_CMD_CLOSE
:
2158 session_close(session
);
2160 case SESSION_CMD_QM_NOTIFY_TOPOLOGY
:
2161 IMFQualityManager_NotifyTopology(session
->quality_manager
, op
->u
.notify_topology
.topology
);
2162 session_command_complete(session
);
2164 case SESSION_CMD_SA_READY
:
2165 topo_node
= session_get_node_by_id(session
, op
->u
.sa_ready
.node_id
);
2167 if (topo_node
->u
.sink
.requests
)
2169 if (SUCCEEDED(IMFTopologyNode_GetInput(topo_node
->node
, 0, &upstream_node
, &upstream_output
)))
2171 session_request_sample_from_node(session
, upstream_node
, upstream_output
);
2172 IMFTopologyNode_Release(upstream_node
);
2180 LeaveCriticalSection(&session
->cs
);
2185 static const IMFAsyncCallbackVtbl session_commands_callback_vtbl
=
2187 session_commands_callback_QueryInterface
,
2188 session_commands_callback_AddRef
,
2189 session_commands_callback_Release
,
2190 session_commands_callback_GetParameters
,
2191 session_commands_callback_Invoke
,
2194 static HRESULT WINAPI
session_events_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
2196 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
2197 IsEqualIID(riid
, &IID_IUnknown
))
2200 IMFAsyncCallback_AddRef(iface
);
2204 WARN("Unsupported %s.\n", debugstr_guid(riid
));
2206 return E_NOINTERFACE
;
2209 static ULONG WINAPI
session_events_callback_AddRef(IMFAsyncCallback
*iface
)
2211 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2212 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
2215 static ULONG WINAPI
session_events_callback_Release(IMFAsyncCallback
*iface
)
2217 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
2218 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
2221 static HRESULT WINAPI
session_events_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
2226 static HRESULT
session_add_media_stream(struct media_session
*session
, IMFMediaSource
*source
, IMFMediaStream
*stream
)
2228 struct topo_node
*node
;
2229 IMFStreamDescriptor
*sd
;
2230 DWORD stream_id
= 0;
2233 if (FAILED(hr
= IMFMediaStream_GetStreamDescriptor(stream
, &sd
)))
2236 hr
= IMFStreamDescriptor_GetStreamIdentifier(sd
, &stream_id
);
2237 IMFStreamDescriptor_Release(sd
);
2241 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2243 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->u
.source
.source
== source
2244 && node
->u
.source
.stream_id
== stream_id
)
2246 if (node
->object
.source_stream
)
2248 WARN("Node already has stream set.\n");
2252 node
->object
.source_stream
= stream
;
2253 IMFMediaStream_AddRef(node
->object
.source_stream
);
2261 static BOOL
session_is_source_nodes_state(struct media_session
*session
, enum object_state state
)
2263 struct media_source
*source
;
2264 struct topo_node
*node
;
2266 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2268 if (source
->state
!= state
)
2272 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2274 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->state
!= state
)
2281 static BOOL
session_is_output_nodes_state(struct media_session
*session
, enum object_state state
)
2283 struct topo_node
*node
;
2285 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2287 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->state
!= state
)
2294 static enum object_state
session_get_object_state_for_event(MediaEventType event
)
2298 case MESourceStarted
:
2299 case MEStreamStarted
:
2300 case MEStreamSinkStarted
:
2301 return OBJ_STATE_STARTED
;
2302 case MESourcePaused
:
2303 case MEStreamPaused
:
2304 case MEStreamSinkPaused
:
2305 return OBJ_STATE_PAUSED
;
2306 case MESourceStopped
:
2307 case MEStreamStopped
:
2308 case MEStreamSinkStopped
:
2309 return OBJ_STATE_STOPPED
;
2310 case MEStreamSinkPrerolled
:
2311 return OBJ_STATE_PREROLLED
;
2313 return OBJ_STATE_INVALID
;
2317 static void session_set_consumed_clock(IUnknown
*object
, IMFPresentationClock
*clock
)
2319 IMFClockConsumer
*consumer
;
2321 if (SUCCEEDED(IUnknown_QueryInterface(object
, &IID_IMFClockConsumer
, (void **)&consumer
)))
2323 IMFClockConsumer_SetPresentationClock(consumer
, clock
);
2324 IMFClockConsumer_Release(consumer
);
2328 static void session_set_presentation_clock(struct media_session
*session
)
2330 IMFPresentationTimeSource
*time_source
= NULL
;
2331 struct media_source
*source
;
2332 struct media_sink
*sink
;
2333 struct topo_node
*node
;
2336 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2338 if (node
->type
== MF_TOPOLOGY_TRANSFORM_NODE
)
2339 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_NOTIFY_START_OF_STREAM
, 0);
2342 if (!(session
->presentation
.flags
& SESSION_FLAG_PRESENTATION_CLOCK_SET
))
2344 /* Attempt to get time source from the sinks. */
2345 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2347 if (SUCCEEDED(IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFPresentationTimeSource
,
2348 (void **)&time_source
)))
2354 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, time_source
);
2355 IMFPresentationTimeSource_Release(time_source
);
2358 hr
= IMFPresentationClock_SetTimeSource(session
->clock
, session
->system_time_source
);
2361 WARN("Failed to set time source, hr %#x.\n", hr
);
2363 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2365 if (node
->type
!= MF_TOPOLOGY_OUTPUT_NODE
)
2368 if (FAILED(hr
= IMFStreamSink_BeginGetEvent(node
->object
.sink_stream
, &session
->events_callback
,
2369 node
->object
.object
)))
2371 WARN("Failed to subscribe to stream sink events, hr %#x.\n", hr
);
2375 /* Set clock for all topology nodes. */
2376 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2378 session_set_consumed_clock(source
->object
, session
->clock
);
2381 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2383 if (sink
->event_generator
&& FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(sink
->event_generator
,
2384 &session
->events_callback
, (IUnknown
*)sink
->event_generator
)))
2386 WARN("Failed to subscribe to sink events, hr %#x.\n", hr
);
2389 if (FAILED(hr
= IMFMediaSink_SetPresentationClock(sink
->sink
, session
->clock
)))
2390 WARN("Failed to set presentation clock for the sink, hr %#x.\n", hr
);
2393 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2395 if (node
->type
!= MF_TOPOLOGY_TRANSFORM_NODE
)
2398 session_set_consumed_clock(node
->object
.object
, session
->clock
);
2401 session
->presentation
.flags
|= SESSION_FLAG_PRESENTATION_CLOCK_SET
;
2405 static HRESULT
session_start_clock(struct media_session
*session
)
2407 LONGLONG start_offset
= 0;
2410 if (IsEqualGUID(&session
->presentation
.time_format
, &GUID_NULL
))
2412 if (session
->presentation
.start_position
.vt
== VT_EMPTY
)
2413 start_offset
= PRESENTATION_CURRENT_POSITION
;
2414 else if (session
->presentation
.start_position
.vt
== VT_I8
)
2415 start_offset
= session
->presentation
.start_position
.hVal
.QuadPart
;
2417 FIXME("Unhandled position type %d.\n", session
->presentation
.start_position
.vt
);
2420 FIXME("Unhandled time format %s.\n", debugstr_guid(&session
->presentation
.time_format
));
2422 if (FAILED(hr
= IMFPresentationClock_Start(session
->clock
, start_offset
)))
2423 WARN("Failed to start session clock, hr %#x.\n", hr
);
2428 static struct topo_node
*session_get_node_object(struct media_session
*session
, IUnknown
*object
,
2429 MF_TOPOLOGY_TYPE node_type
)
2431 struct topo_node
*node
= NULL
;
2433 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2435 if (node
->type
== node_type
&& object
== node
->object
.object
)
2442 static BOOL
session_set_node_object_state(struct media_session
*session
, IUnknown
*object
,
2443 MF_TOPOLOGY_TYPE node_type
, enum object_state state
)
2445 struct topo_node
*node
;
2446 BOOL changed
= FALSE
;
2448 if ((node
= session_get_node_object(session
, object
, node_type
)))
2450 changed
= node
->state
!= state
;
2451 node
->state
= state
;
2457 static void session_set_source_object_state(struct media_session
*session
, IUnknown
*object
,
2458 MediaEventType event_type
)
2460 IMFStreamSink
*stream_sink
;
2461 struct media_source
*src
;
2462 struct media_sink
*sink
;
2463 enum object_state state
;
2464 struct topo_node
*node
;
2465 BOOL changed
= FALSE
;
2469 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2474 case MESourceStarted
:
2475 case MESourcePaused
:
2476 case MESourceStopped
:
2478 LIST_FOR_EACH_ENTRY(src
, &session
->presentation
.sources
, struct media_source
, entry
)
2480 if (object
== src
->object
)
2482 changed
= src
->state
!= state
;
2488 case MEStreamStarted
:
2489 case MEStreamPaused
:
2490 case MEStreamStopped
:
2492 changed
= session_set_node_object_state(session
, object
, MF_TOPOLOGY_SOURCESTREAM_NODE
, state
);
2500 switch (session
->state
)
2502 case SESSION_STATE_STARTING_SOURCES
:
2503 if (!session_is_source_nodes_state(session
, OBJ_STATE_STARTED
))
2506 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_STARTED_SOURCE
);
2508 session_set_presentation_clock(session
);
2510 if (session
->presentation
.flags
& SESSION_FLAG_NEEDS_PREROLL
)
2512 MFTIME preroll_time
= 0;
2514 if (session
->presentation
.start_position
.vt
== VT_I8
)
2515 preroll_time
= session
->presentation
.start_position
.hVal
.QuadPart
;
2517 /* Mark stream sinks without prerolling support as PREROLLED to keep state test logic generic. */
2518 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
2522 /* FIXME: abort and enter error state on failure. */
2523 if (FAILED(hr
= IMFMediaSinkPreroll_NotifyPreroll(sink
->preroll
, preroll_time
)))
2524 WARN("Preroll notification failed, hr %#x.\n", hr
);
2528 if (SUCCEEDED(IMFMediaSink_GetStreamSinkCount(sink
->sink
, &count
)))
2530 for (i
= 0; i
< count
; ++i
)
2532 if (SUCCEEDED(IMFMediaSink_GetStreamSinkByIndex(sink
->sink
, i
, &stream_sink
)))
2534 session_set_node_object_state(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
,
2535 OBJ_STATE_PREROLLED
);
2536 IMFStreamSink_Release(stream_sink
);
2542 session
->state
= SESSION_STATE_PREROLLING_SINKS
;
2544 else if (SUCCEEDED(session_start_clock(session
)))
2545 session
->state
= SESSION_STATE_STARTING_SINKS
;
2548 case SESSION_STATE_PAUSING_SOURCES
:
2549 if (!session_is_source_nodes_state(session
, OBJ_STATE_PAUSED
))
2552 session_set_paused(session
, SESSION_STATE_PAUSED
, S_OK
);
2554 case SESSION_STATE_STOPPING_SOURCES
:
2555 if (!session_is_source_nodes_state(session
, OBJ_STATE_STOPPED
))
2558 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2562 case MF_TOPOLOGY_OUTPUT_NODE
:
2563 IMFStreamSink_Flush(node
->object
.sink_stream
);
2565 case MF_TOPOLOGY_TRANSFORM_NODE
:
2566 IMFTransform_ProcessMessage(node
->object
.transform
, MFT_MESSAGE_COMMAND_FLUSH
, 0);
2573 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
2575 if (session
->presentation
.flags
& SESSION_FLAG_FINALIZE_SINKS
)
2576 session_finalize_sinks(session
);
2578 session_set_stopped(session
, S_OK
);
2586 static void session_set_sink_stream_state(struct media_session
*session
, IMFStreamSink
*stream
,
2587 MediaEventType event_type
)
2589 struct media_source
*source
;
2590 enum object_state state
;
2594 if ((state
= session_get_object_state_for_event(event_type
)) == OBJ_STATE_INVALID
)
2597 if (!(changed
= session_set_node_object_state(session
, (IUnknown
*)stream
, MF_TOPOLOGY_OUTPUT_NODE
, state
)))
2600 switch (session
->state
)
2602 case SESSION_STATE_PREROLLING_SINKS
:
2603 if (!session_is_output_nodes_state(session
, OBJ_STATE_PREROLLED
))
2606 if (SUCCEEDED(session_start_clock(session
)))
2607 session
->state
= SESSION_STATE_STARTING_SINKS
;
2609 case SESSION_STATE_STARTING_SINKS
:
2610 if (!session_is_output_nodes_state(session
, OBJ_STATE_STARTED
))
2613 session_set_started(session
);
2615 case SESSION_STATE_PAUSING_SINKS
:
2616 if (!session_is_output_nodes_state(session
, OBJ_STATE_PAUSED
))
2619 session
->state
= SESSION_STATE_PAUSING_SOURCES
;
2621 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2623 if (FAILED(hr
= IMFMediaSource_Pause(source
->source
)))
2628 session_set_paused(session
, SESSION_STATE_PAUSED
, hr
);
2631 case SESSION_STATE_STOPPING_SINKS
:
2632 if (!session_is_output_nodes_state(session
, OBJ_STATE_STOPPED
))
2635 session
->state
= SESSION_STATE_STOPPING_SOURCES
;
2637 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
2639 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
)
2640 IMFMediaSource_Stop(source
->source
);
2641 else if (FAILED(hr
= IMFMediaSource_Stop(source
->source
)))
2645 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
|| FAILED(hr
))
2646 session_set_stopped(session
, hr
);
2654 static struct sample
*transform_create_sample(IMFSample
*sample
)
2656 struct sample
*sample_entry
= calloc(1, sizeof(*sample_entry
));
2660 sample_entry
->sample
= sample
;
2661 if (sample_entry
->sample
)
2662 IMFSample_AddRef(sample_entry
->sample
);
2665 return sample_entry
;
2668 static HRESULT
transform_get_external_output_sample(const struct media_session
*session
, struct topo_node
*transform
,
2669 unsigned int output_index
, const MFT_OUTPUT_STREAM_INFO
*stream_info
, IMFSample
**sample
)
2671 IMFTopologyNode
*downstream_node
;
2672 IMFMediaBuffer
*buffer
= NULL
;
2673 struct topo_node
*topo_node
;
2674 unsigned int buffer_size
;
2675 DWORD downstream_input
;
2679 if (FAILED(IMFTopologyNode_GetOutput(transform
->node
, output_index
, &downstream_node
, &downstream_input
)))
2681 WARN("Failed to get connected node for output %u.\n", output_index
);
2682 return MF_E_UNEXPECTED
;
2685 IMFTopologyNode_GetTopoNodeID(downstream_node
, &node_id
);
2686 IMFTopologyNode_Release(downstream_node
);
2688 topo_node
= session_get_node_by_id(session
, node_id
);
2690 if (topo_node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& topo_node
->u
.sink
.allocator
)
2692 hr
= IMFVideoSampleAllocator_AllocateSample(topo_node
->u
.sink
.allocator
, sample
);
2696 buffer_size
= max(stream_info
->cbSize
, transform
->u
.transform
.outputs
[output_index
].min_buffer_size
);
2698 hr
= MFCreateAlignedMemoryBuffer(buffer_size
, stream_info
->cbAlignment
, &buffer
);
2700 hr
= MFCreateSample(sample
);
2703 hr
= IMFSample_AddBuffer(*sample
, buffer
);
2706 IMFMediaBuffer_Release(buffer
);
2712 static HRESULT
transform_node_pull_samples(const struct media_session
*session
, struct topo_node
*node
)
2714 MFT_OUTPUT_STREAM_INFO stream_info
;
2715 MFT_OUTPUT_DATA_BUFFER
*buffers
;
2716 struct sample
*queued_sample
;
2717 HRESULT hr
= E_UNEXPECTED
;
2721 if (!(buffers
= calloc(node
->u
.transform
.output_count
, sizeof(*buffers
))))
2722 return E_OUTOFMEMORY
;
2724 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2726 buffers
[i
].dwStreamID
= transform_node_get_stream_id(node
, TRUE
, i
);
2727 buffers
[i
].pSample
= NULL
;
2728 buffers
[i
].dwStatus
= 0;
2729 buffers
[i
].pEvents
= NULL
;
2731 memset(&stream_info
, 0, sizeof(stream_info
));
2732 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(node
->object
.transform
, buffers
[i
].dwStreamID
, &stream_info
)))
2735 if (!(stream_info
.dwFlags
& (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
| MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES
)))
2737 if (FAILED(hr
= transform_get_external_output_sample(session
, node
, i
, &stream_info
, &buffers
[i
].pSample
)))
2743 hr
= IMFTransform_ProcessOutput(node
->object
.transform
, 0, node
->u
.transform
.output_count
, buffers
, &status
);
2745 /* Collect returned samples for all streams. */
2746 for (i
= 0; i
< node
->u
.transform
.output_count
; ++i
)
2748 if (buffers
[i
].pEvents
)
2749 IMFCollection_Release(buffers
[i
].pEvents
);
2751 if (SUCCEEDED(hr
) && !(buffers
[i
].dwStatus
& MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE
))
2753 if (session
->quality_manager
)
2754 IMFQualityManager_NotifyProcessOutput(session
->quality_manager
, node
->node
, i
, buffers
[i
].pSample
);
2756 queued_sample
= transform_create_sample(buffers
[i
].pSample
);
2757 list_add_tail(&node
->u
.transform
.outputs
[i
].samples
, &queued_sample
->entry
);
2760 if (buffers
[i
].pSample
)
2761 IMFSample_Release(buffers
[i
].pSample
);
2769 static void session_deliver_sample_to_node(struct media_session
*session
, IMFTopologyNode
*node
, unsigned int input
,
2772 struct sample
*sample_entry
, *sample_entry2
;
2773 DWORD stream_id
, downstream_input
;
2774 IMFTopologyNode
*downstream_node
;
2775 struct topo_node
*topo_node
;
2776 MF_TOPOLOGY_TYPE node_type
;
2782 if (session
->quality_manager
)
2783 IMFQualityManager_NotifyProcessInput(session
->quality_manager
, node
, input
, sample
);
2785 IMFTopologyNode_GetNodeType(node
, &node_type
);
2786 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2788 topo_node
= session_get_node_by_id(session
, node_id
);
2792 case MF_TOPOLOGY_OUTPUT_NODE
:
2795 if (topo_node
->u
.sink
.requests
)
2797 if (FAILED(hr
= IMFStreamSink_ProcessSample(topo_node
->object
.sink_stream
, sample
)))
2798 WARN("Stream sink failed to process sample, hr %#x.\n", hr
);
2799 topo_node
->u
.sink
.requests
--;
2802 else if (FAILED(hr
= IMFStreamSink_PlaceMarker(topo_node
->object
.sink_stream
, MFSTREAMSINK_MARKER_ENDOFSEGMENT
,
2805 WARN("Failed to place sink marker, hr %#x.\n", hr
);
2808 case MF_TOPOLOGY_TRANSFORM_NODE
:
2810 transform_node_pull_samples(session
, topo_node
);
2812 sample_entry
= transform_create_sample(sample
);
2813 list_add_tail(&topo_node
->u
.transform
.inputs
[input
].samples
, &sample_entry
->entry
);
2815 for (i
= 0; i
< topo_node
->u
.transform
.input_count
; ++i
)
2817 stream_id
= transform_node_get_stream_id(topo_node
, FALSE
, i
);
2818 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.inputs
[i
].samples
,
2819 struct sample
, entry
)
2821 if (sample_entry
->sample
)
2823 if ((hr
= IMFTransform_ProcessInput(topo_node
->object
.transform
, stream_id
,
2824 sample_entry
->sample
, 0)) == MF_E_NOTACCEPTING
)
2827 WARN("Failed to process input for stream %u/%u, hr %#x.\n", i
, stream_id
, hr
);
2828 transform_release_sample(sample_entry
);
2832 transform_stream_drop_samples(&topo_node
->u
.transform
.inputs
[i
]);
2840 if (FAILED(hr
= IMFTransform_ProcessMessage(topo_node
->object
.transform
, MFT_MESSAGE_COMMAND_DRAIN
, 0)))
2841 WARN("Drain command failed for transform, hr %#x.\n", hr
);
2844 transform_node_pull_samples(session
, topo_node
);
2846 /* Remaining unprocessed input has been discarded, now queue markers for every output. */
2849 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2851 if ((sample_entry
= transform_create_sample(NULL
)))
2852 list_add_tail(&topo_node
->u
.transform
.outputs
[i
].samples
, &sample_entry
->entry
);
2856 /* Push down all available output. */
2857 for (i
= 0; i
< topo_node
->u
.transform
.output_count
; ++i
)
2859 if (FAILED(IMFTopologyNode_GetOutput(node
, i
, &downstream_node
, &downstream_input
)))
2861 WARN("Failed to get connected node for output %u.\n", i
);
2865 LIST_FOR_EACH_ENTRY_SAFE(sample_entry
, sample_entry2
, &topo_node
->u
.transform
.outputs
[i
].samples
,
2866 struct sample
, entry
)
2868 if (!topo_node
->u
.transform
.outputs
[i
].requests
)
2871 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample_entry
->sample
);
2872 topo_node
->u
.transform
.outputs
[i
].requests
--;
2874 transform_release_sample(sample_entry
);
2877 IMFTopologyNode_Release(downstream_node
);
2881 case MF_TOPOLOGY_TEE_NODE
:
2882 FIXME("Unhandled downstream node type %d.\n", node_type
);
2889 static HRESULT
session_request_sample_from_node(struct media_session
*session
, IMFTopologyNode
*node
, DWORD output
)
2891 IMFTopologyNode
*downstream_node
, *upstream_node
;
2892 DWORD downstream_input
, upstream_output
;
2893 struct topo_node
*topo_node
;
2894 MF_TOPOLOGY_TYPE node_type
;
2895 struct sample
*sample
;
2899 IMFTopologyNode_GetNodeType(node
, &node_type
);
2900 IMFTopologyNode_GetTopoNodeID(node
, &node_id
);
2902 topo_node
= session_get_node_by_id(session
, node_id
);
2906 case MF_TOPOLOGY_SOURCESTREAM_NODE
:
2907 if (FAILED(hr
= IMFMediaStream_RequestSample(topo_node
->object
.source_stream
, NULL
)))
2908 WARN("Sample request failed, hr %#x.\n", hr
);
2910 case MF_TOPOLOGY_TRANSFORM_NODE
:
2912 if (list_empty(&topo_node
->u
.transform
.outputs
[output
].samples
))
2914 /* Forward request to upstream node. */
2915 if (SUCCEEDED(hr
= IMFTopologyNode_GetInput(node
, 0 /* FIXME */, &upstream_node
, &upstream_output
)))
2917 if (SUCCEEDED(hr
= session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2918 topo_node
->u
.transform
.outputs
[output
].requests
++;
2919 IMFTopologyNode_Release(upstream_node
);
2924 if (SUCCEEDED(hr
= IMFTopologyNode_GetOutput(node
, output
, &downstream_node
, &downstream_input
)))
2926 sample
= LIST_ENTRY(list_head(&topo_node
->u
.transform
.outputs
[output
].samples
), struct sample
, entry
);
2927 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, sample
->sample
);
2928 transform_release_sample(sample
);
2929 IMFTopologyNode_Release(downstream_node
);
2934 case MF_TOPOLOGY_TEE_NODE
:
2935 FIXME("Unhandled upstream node type %d.\n", node_type
);
2943 static void session_request_sample(struct media_session
*session
, IMFStreamSink
*sink_stream
)
2945 struct topo_node
*sink_node
= NULL
, *node
;
2946 IMFTopologyNode
*upstream_node
;
2947 DWORD upstream_output
;
2950 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2952 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink_stream
)
2962 if (FAILED(hr
= IMFTopologyNode_GetInput(sink_node
->node
, 0, &upstream_node
, &upstream_output
)))
2964 WARN("Failed to get upstream node connection, hr %#x.\n", hr
);
2968 if (SUCCEEDED(session_request_sample_from_node(session
, upstream_node
, upstream_output
)))
2969 sink_node
->u
.sink
.requests
++;
2970 IMFTopologyNode_Release(upstream_node
);
2973 static void session_deliver_sample(struct media_session
*session
, IMFMediaStream
*stream
, const PROPVARIANT
*value
)
2975 struct topo_node
*source_node
= NULL
, *node
;
2976 IMFTopologyNode
*downstream_node
;
2977 DWORD downstream_input
;
2980 if (value
&& (value
->vt
!= VT_UNKNOWN
|| !value
->punkVal
))
2982 WARN("Unexpected value type %d.\n", value
->vt
);
2986 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
2988 if (node
->type
== MF_TOPOLOGY_SOURCESTREAM_NODE
&& node
->object
.source_stream
== stream
)
2999 source_node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3001 if (FAILED(hr
= IMFTopologyNode_GetOutput(source_node
->node
, 0, &downstream_node
, &downstream_input
)))
3003 WARN("Failed to get downstream node connection, hr %#x.\n", hr
);
3007 session_deliver_sample_to_node(session
, downstream_node
, downstream_input
, value
? (IMFSample
*)value
->punkVal
: NULL
);
3008 IMFTopologyNode_Release(downstream_node
);
3011 static void session_sink_invalidated(struct media_session
*session
, IMFMediaEvent
*event
, IMFStreamSink
*sink
)
3013 struct topo_node
*node
, *sink_node
= NULL
;
3016 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3018 if (node
->type
== MF_TOPOLOGY_OUTPUT_NODE
&& node
->object
.sink_stream
== sink
)
3030 if (FAILED(hr
= MFCreateMediaEvent(MESinkInvalidated
, &GUID_NULL
, S_OK
, NULL
, &event
)))
3031 WARN("Failed to create event, hr %#x.\n", hr
);
3037 IMFMediaEvent_SetUINT64(event
, &MF_EVENT_OUTPUT_NODE
, sink_node
->node_id
);
3038 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3040 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3043 static BOOL
session_nodes_is_mask_set(struct media_session
*session
, MF_TOPOLOGY_TYPE node_type
, unsigned int flags
)
3045 struct media_source
*source
;
3046 struct topo_node
*node
;
3048 if (node_type
== MF_TOPOLOGY_MAX
)
3050 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3052 if ((source
->flags
& flags
) != flags
)
3058 LIST_FOR_EACH_ENTRY(node
, &session
->presentation
.nodes
, struct topo_node
, entry
)
3060 if (node
->type
== node_type
&& (node
->flags
& flags
) != flags
)
3068 static void session_raise_end_of_presentation(struct media_session
*session
)
3070 if (!(session_nodes_is_mask_set(session
, MF_TOPOLOGY_SOURCESTREAM_NODE
, TOPO_NODE_END_OF_STREAM
)))
3073 if (!(session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
))
3075 if (session_nodes_is_mask_set(session
, MF_TOPOLOGY_MAX
, SOURCE_FLAG_END_OF_PRESENTATION
))
3077 session
->presentation
.flags
|= SESSION_FLAG_END_OF_PRESENTATION
;
3078 session_push_back_command(session
, SESSION_CMD_END
);
3079 IMFMediaEventQueue_QueueEventParamVar(session
->event_queue
, MEEndOfPresentation
, &GUID_NULL
, S_OK
, NULL
);
3084 static void session_handle_end_of_stream(struct media_session
*session
, IMFMediaStream
*stream
)
3086 struct topo_node
*node
;
3088 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream
, MF_TOPOLOGY_SOURCESTREAM_NODE
))
3089 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3094 session_deliver_sample(session
, stream
, NULL
);
3096 session_raise_end_of_presentation(session
);
3099 static void session_handle_end_of_presentation(struct media_session
*session
, IMFMediaSource
*object
)
3101 struct media_source
*source
;
3103 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3105 if (source
->source
== object
)
3107 if (!(source
->flags
& SOURCE_FLAG_END_OF_PRESENTATION
))
3109 source
->flags
|= SOURCE_FLAG_END_OF_PRESENTATION
;
3110 session_raise_end_of_presentation(session
);
3118 static void session_sink_stream_marker(struct media_session
*session
, IMFStreamSink
*stream_sink
)
3120 struct topo_node
*node
;
3122 if (!(node
= session_get_node_object(session
, (IUnknown
*)stream_sink
, MF_TOPOLOGY_OUTPUT_NODE
))
3123 || node
->flags
& TOPO_NODE_END_OF_STREAM
)
3128 node
->flags
|= TOPO_NODE_END_OF_STREAM
;
3130 if (session
->presentation
.flags
& SESSION_FLAG_END_OF_PRESENTATION
&&
3131 session_nodes_is_mask_set(session
, MF_TOPOLOGY_OUTPUT_NODE
, TOPO_NODE_END_OF_STREAM
))
3133 session_set_topo_status(session
, S_OK
, MF_TOPOSTATUS_ENDED
);
3134 session_set_caps(session
, session
->caps
& ~MFSESSIONCAP_PAUSE
);
3135 session_stop(session
);
3139 static HRESULT WINAPI
session_events_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3141 struct media_session
*session
= impl_from_events_callback_IMFAsyncCallback(iface
);
3142 IMFMediaEventGenerator
*event_source
;
3143 IMFMediaEvent
*event
= NULL
;
3144 MediaEventType event_type
;
3145 IUnknown
*object
= NULL
;
3146 IMFMediaSource
*source
;
3147 IMFMediaStream
*stream
;
3151 if (FAILED(hr
= IMFAsyncResult_GetState(result
, (IUnknown
**)&event_source
)))
3154 if (FAILED(hr
= IMFMediaEventGenerator_EndGetEvent(event_source
, result
, &event
)))
3156 WARN("Failed to get event from %p, hr %#x.\n", event_source
, hr
);
3160 if (FAILED(hr
= IMFMediaEvent_GetType(event
, &event_type
)))
3162 WARN("Failed to get event type, hr %#x.\n", hr
);
3166 value
.vt
= VT_EMPTY
;
3167 if (FAILED(hr
= IMFMediaEvent_GetValue(event
, &value
)))
3169 WARN("Failed to get event value, hr %#x.\n", hr
);
3175 case MESourceStarted
:
3176 case MESourcePaused
:
3177 case MESourceStopped
:
3178 case MEStreamStarted
:
3179 case MEStreamPaused
:
3180 case MEStreamStopped
:
3182 EnterCriticalSection(&session
->cs
);
3183 session_set_source_object_state(session
, (IUnknown
*)event_source
, event_type
);
3184 LeaveCriticalSection(&session
->cs
);
3188 case MEBufferingStarted
:
3189 case MEBufferingStopped
:
3191 EnterCriticalSection(&session
->cs
);
3192 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3194 if (event_type
== MEBufferingStarted
)
3195 IMFPresentationClock_Pause(session
->clock
);
3197 IMFPresentationClock_Start(session
->clock
, PRESENTATION_CURRENT_POSITION
);
3199 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3201 LeaveCriticalSection(&session
->cs
);
3204 case MEReconnectStart
:
3205 case MEReconnectEnd
:
3207 EnterCriticalSection(&session
->cs
);
3208 if (session_get_media_source(session
, (IMFMediaSource
*)event_source
))
3209 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3210 LeaveCriticalSection(&session
->cs
);
3213 case MEExtendedType
:
3214 case MERendererEvent
:
3215 case MEStreamSinkFormatChanged
:
3217 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3221 stream
= (IMFMediaStream
*)value
.punkVal
;
3223 if (value
.vt
!= VT_UNKNOWN
|| !stream
)
3225 WARN("Unexpected event value.\n");
3229 if (FAILED(hr
= IMFMediaStream_GetMediaSource(stream
, &source
)))
3232 EnterCriticalSection(&session
->cs
);
3233 if (SUCCEEDED(hr
= session_add_media_stream(session
, source
, stream
)))
3234 hr
= IMFMediaStream_BeginGetEvent(stream
, &session
->events_callback
, (IUnknown
*)stream
);
3235 LeaveCriticalSection(&session
->cs
);
3237 IMFMediaSource_Release(source
);
3240 case MEStreamSinkStarted
:
3241 case MEStreamSinkPaused
:
3242 case MEStreamSinkStopped
:
3243 case MEStreamSinkPrerolled
:
3245 EnterCriticalSection(&session
->cs
);
3246 session_set_sink_stream_state(session
, (IMFStreamSink
*)event_source
, event_type
);
3247 LeaveCriticalSection(&session
->cs
);
3250 case MEStreamSinkMarker
:
3252 EnterCriticalSection(&session
->cs
);
3253 session_sink_stream_marker(session
, (IMFStreamSink
*)event_source
);
3254 LeaveCriticalSection(&session
->cs
);
3257 case MEStreamSinkRequestSample
:
3259 EnterCriticalSection(&session
->cs
);
3260 session_request_sample(session
, (IMFStreamSink
*)event_source
);
3261 LeaveCriticalSection(&session
->cs
);
3266 EnterCriticalSection(&session
->cs
);
3267 session_deliver_sample(session
, (IMFMediaStream
*)event_source
, &value
);
3268 LeaveCriticalSection(&session
->cs
);
3273 EnterCriticalSection(&session
->cs
);
3274 session_handle_end_of_stream(session
, (IMFMediaStream
*)event_source
);
3275 LeaveCriticalSection(&session
->cs
);
3279 case MEEndOfPresentation
:
3281 EnterCriticalSection(&session
->cs
);
3282 session_handle_end_of_presentation(session
, (IMFMediaSource
*)event_source
);
3283 LeaveCriticalSection(&session
->cs
);
3286 case MEAudioSessionGroupingParamChanged
:
3287 case MEAudioSessionIconChanged
:
3288 case MEAudioSessionNameChanged
:
3289 case MEAudioSessionVolumeChanged
:
3291 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3294 case MEAudioSessionDeviceRemoved
:
3295 case MEAudioSessionDisconnected
:
3296 case MEAudioSessionExclusiveModeOverride
:
3297 case MEAudioSessionFormatChanged
:
3298 case MEAudioSessionServerShutdown
:
3300 IMFMediaEventQueue_QueueEvent(session
->event_queue
, event
);
3302 case MESinkInvalidated
:
3304 EnterCriticalSection(&session
->cs
);
3305 session_sink_invalidated(session
, event_type
== MESinkInvalidated
? event
: NULL
,
3306 (IMFStreamSink
*)event_source
);
3307 LeaveCriticalSection(&session
->cs
);
3310 case MEQualityNotify
:
3312 if (session
->quality_manager
)
3314 if (FAILED(IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFStreamSink
, (void **)&object
)))
3315 IMFMediaEventGenerator_QueryInterface(event_source
, &IID_IMFTransform
, (void **)&object
);
3319 IMFQualityManager_NotifyQualityEvent(session
->quality_manager
, object
, event
);
3320 IUnknown_Release(object
);
3329 PropVariantClear(&value
);
3333 IMFMediaEvent_Release(event
);
3335 if (FAILED(hr
= IMFMediaEventGenerator_BeginGetEvent(event_source
, iface
, (IUnknown
*)event_source
)))
3336 WARN("Failed to re-subscribe, hr %#x.\n", hr
);
3338 IMFMediaEventGenerator_Release(event_source
);
3343 static const IMFAsyncCallbackVtbl session_events_callback_vtbl
=
3345 session_events_callback_QueryInterface
,
3346 session_events_callback_AddRef
,
3347 session_events_callback_Release
,
3348 session_events_callback_GetParameters
,
3349 session_events_callback_Invoke
,
3352 static HRESULT WINAPI
session_sink_finalizer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
3354 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
3355 IsEqualIID(riid
, &IID_IUnknown
))
3358 IMFAsyncCallback_AddRef(iface
);
3362 WARN("Unsupported %s.\n", debugstr_guid(riid
));
3364 return E_NOINTERFACE
;
3367 static ULONG WINAPI
session_sink_finalizer_callback_AddRef(IMFAsyncCallback
*iface
)
3369 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3370 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3373 static ULONG WINAPI
session_sink_finalizer_callback_Release(IMFAsyncCallback
*iface
)
3375 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3376 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3379 static HRESULT WINAPI
session_sink_finalizer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
3384 static HRESULT WINAPI
session_sink_finalizer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
3386 struct media_session
*session
= impl_from_sink_finalizer_callback_IMFAsyncCallback(iface
);
3387 IMFFinalizableMediaSink
*fin_sink
= NULL
;
3388 BOOL sinks_finalized
= TRUE
;
3389 struct media_sink
*sink
;
3393 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
3396 EnterCriticalSection(&session
->cs
);
3398 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3400 if (state
== sink
->object
)
3402 if (FAILED(hr
= IMFMediaSink_QueryInterface(sink
->sink
, &IID_IMFFinalizableMediaSink
, (void **)&fin_sink
)))
3403 WARN("Unexpected, missing IMFFinalizableMediaSink, hr %#x.\n", hr
);
3407 sinks_finalized
&= sink
->finalized
;
3408 if (!sinks_finalized
)
3413 IUnknown_Release(state
);
3417 /* Complete session transition, or close prematurely on error. */
3418 if (SUCCEEDED(hr
= IMFFinalizableMediaSink_EndFinalize(fin_sink
, result
)))
3420 sink
->finalized
= TRUE
;
3421 if (sinks_finalized
)
3422 session_set_closed(session
, hr
);
3424 IMFFinalizableMediaSink_Release(fin_sink
);
3427 LeaveCriticalSection(&session
->cs
);
3432 static const IMFAsyncCallbackVtbl session_sink_finalizer_callback_vtbl
=
3434 session_sink_finalizer_callback_QueryInterface
,
3435 session_sink_finalizer_callback_AddRef
,
3436 session_sink_finalizer_callback_Release
,
3437 session_sink_finalizer_callback_GetParameters
,
3438 session_sink_finalizer_callback_Invoke
,
3441 static HRESULT WINAPI
session_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
3443 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3444 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3447 static ULONG WINAPI
session_rate_support_AddRef(IMFRateSupport
*iface
)
3449 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3450 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3453 static ULONG WINAPI
session_rate_support_Release(IMFRateSupport
*iface
)
3455 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3456 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3459 static HRESULT
session_presentation_object_get_rate(IUnknown
*object
, MFRATE_DIRECTION direction
,
3460 BOOL thin
, BOOL fastest
, float *result
)
3462 IMFRateSupport
*rate_support
;
3466 /* For objects that don't support rate control, it's assumed that only forward direction is allowed, at 1.0f. */
3468 if (FAILED(hr
= MFGetService(object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
, (void **)&rate_support
)))
3470 if (direction
== MFRATE_FORWARD
)
3476 return MF_E_REVERSE_UNSUPPORTED
;
3482 if (SUCCEEDED(hr
= IMFRateSupport_GetFastestRate(rate_support
, direction
, thin
, &rate
)))
3483 *result
= min(fabsf(rate
), *result
);
3487 if (SUCCEEDED(hr
= IMFRateSupport_GetSlowestRate(rate_support
, direction
, thin
, &rate
)))
3488 *result
= max(fabsf(rate
), *result
);
3491 IMFRateSupport_Release(rate_support
);
3496 static HRESULT
session_get_presentation_rate(struct media_session
*session
, MFRATE_DIRECTION direction
,
3497 BOOL thin
, BOOL fastest
, float *result
)
3499 struct media_source
*source
;
3500 struct media_sink
*sink
;
3501 HRESULT hr
= E_POINTER
;
3504 rate
= fastest
? FLT_MAX
: 0.0f
;
3506 EnterCriticalSection(&session
->cs
);
3508 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
3510 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3512 if (FAILED(hr
= session_presentation_object_get_rate(source
->object
, direction
, thin
, fastest
, &rate
)))
3518 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3520 if (FAILED(hr
= session_presentation_object_get_rate(sink
->object
, direction
, thin
, fastest
, &rate
)))
3526 LeaveCriticalSection(&session
->cs
);
3529 *result
= direction
== MFRATE_FORWARD
? rate
: -rate
;
3534 static HRESULT
session_is_presentation_rate_supported(struct media_session
*session
, BOOL thin
, float rate
,
3535 float *nearest_rate
)
3537 IMFRateSupport
*rate_support
;
3538 struct media_source
*source
;
3539 struct media_sink
*sink
;
3540 float value
= 0.0f
, tmp
;
3544 if (!nearest_rate
) nearest_rate
= &tmp
;
3548 *nearest_rate
= 1.0f
;
3552 EnterCriticalSection(&session
->cs
);
3554 if (session
->presentation
.topo_status
!= MF_TOPOSTATUS_INVALID
)
3556 LIST_FOR_EACH_ENTRY(source
, &session
->presentation
.sources
, struct media_source
, entry
)
3558 if (FAILED(hr
= MFGetService(source
->object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
,
3559 (void **)&rate_support
)))
3566 if (FAILED(hr
= IMFRateSupport_IsRateSupported(rate_support
, thin
, rate
, &value
)))
3567 WARN("Source does not support rate %f, hr %#x.\n", rate
, hr
);
3568 IMFRateSupport_Release(rate_support
);
3570 /* Only "first" source is considered. */
3576 /* For sinks only check if rate is supported, ignoring nearest values. */
3577 LIST_FOR_EACH_ENTRY(sink
, &session
->presentation
.sinks
, struct media_sink
, entry
)
3580 if (FAILED(hr
= IMFMediaSink_GetCharacteristics(sink
->sink
, &flags
)))
3583 if (flags
& MEDIASINK_RATELESS
)
3586 if (FAILED(MFGetService(sink
->object
, &MF_RATE_CONTROL_SERVICE
, &IID_IMFRateSupport
,
3587 (void **)&rate_support
)))
3590 hr
= IMFRateSupport_IsRateSupported(rate_support
, thin
, rate
, NULL
);
3591 IMFRateSupport_Release(rate_support
);
3594 WARN("Sink %p does not support rate %f, hr %#x.\n", sink
->sink
, rate
, hr
);
3601 LeaveCriticalSection(&session
->cs
);
3603 *nearest_rate
= value
;
3608 static HRESULT WINAPI
session_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3609 BOOL thin
, float *rate
)
3611 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3613 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3615 return session_get_presentation_rate(session
, direction
, thin
, FALSE
, rate
);
3618 static HRESULT WINAPI
session_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
3619 BOOL thin
, float *rate
)
3621 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3623 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
3625 return session_get_presentation_rate(session
, direction
, thin
, TRUE
, rate
);
3628 static HRESULT WINAPI
session_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
3629 float *nearest_supported_rate
)
3631 struct media_session
*session
= impl_session_from_IMFRateSupport(iface
);
3633 TRACE("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_supported_rate
);
3635 return session_is_presentation_rate_supported(session
, thin
, rate
, nearest_supported_rate
);
3638 static const IMFRateSupportVtbl session_rate_support_vtbl
=
3640 session_rate_support_QueryInterface
,
3641 session_rate_support_AddRef
,
3642 session_rate_support_Release
,
3643 session_rate_support_GetSlowestRate
,
3644 session_rate_support_GetFastestRate
,
3645 session_rate_support_IsRateSupported
,
3648 static HRESULT WINAPI
session_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
3650 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3651 return IMFMediaSession_QueryInterface(&session
->IMFMediaSession_iface
, riid
, obj
);
3654 static ULONG WINAPI
session_rate_control_AddRef(IMFRateControl
*iface
)
3656 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3657 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3660 static ULONG WINAPI
session_rate_control_Release(IMFRateControl
*iface
)
3662 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3663 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3666 static HRESULT WINAPI
session_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
3668 FIXME("%p, %d, %f.\n", iface
, thin
, rate
);
3673 static HRESULT WINAPI
session_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
3675 struct media_session
*session
= impl_session_from_IMFRateControl(iface
);
3677 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
3679 return IMFRateControl_GetRate(session
->clock_rate_control
, thin
, rate
);
3682 static const IMFRateControlVtbl session_rate_control_vtbl
=
3684 session_rate_control_QueryInterface
,
3685 session_rate_control_AddRef
,
3686 session_rate_control_Release
,
3687 session_rate_control_SetRate
,
3688 session_rate_control_GetRate
,
3691 static HRESULT WINAPI
node_attribute_editor_QueryInterface(IMFTopologyNodeAttributeEditor
*iface
,
3692 REFIID riid
, void **obj
)
3694 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
3696 if (IsEqualIID(riid
, &IID_IMFTopologyNodeAttributeEditor
) ||
3697 IsEqualIID(riid
, &IID_IUnknown
))
3700 IMFTopologyNodeAttributeEditor_AddRef(iface
);
3704 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
3706 return E_NOINTERFACE
;
3709 static ULONG WINAPI
node_attribute_editor_AddRef(IMFTopologyNodeAttributeEditor
*iface
)
3711 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
3712 return IMFMediaSession_AddRef(&session
->IMFMediaSession_iface
);
3715 static ULONG WINAPI
node_attribute_editor_Release(IMFTopologyNodeAttributeEditor
*iface
)
3717 struct media_session
*session
= impl_session_from_IMFTopologyNodeAttributeEditor(iface
);
3718 return IMFMediaSession_Release(&session
->IMFMediaSession_iface
);
3721 static HRESULT WINAPI
node_attribute_editor_UpdateNodeAttributes(IMFTopologyNodeAttributeEditor
*iface
,
3722 TOPOID id
, DWORD count
, MFTOPONODE_ATTRIBUTE_UPDATE
*updates
)
3724 FIXME("%p, %s, %u, %p.\n", iface
, wine_dbgstr_longlong(id
), count
, updates
);
3729 static const IMFTopologyNodeAttributeEditorVtbl node_attribute_editor_vtbl
=
3731 node_attribute_editor_QueryInterface
,
3732 node_attribute_editor_AddRef
,
3733 node_attribute_editor_Release
,
3734 node_attribute_editor_UpdateNodeAttributes
,
3737 /***********************************************************************
3738 * MFCreateMediaSession (mf.@)
3740 HRESULT WINAPI
MFCreateMediaSession(IMFAttributes
*config
, IMFMediaSession
**session
)
3742 BOOL without_quality_manager
= FALSE
;
3743 struct media_session
*object
;
3746 TRACE("%p, %p.\n", config
, session
);
3748 if (!(object
= calloc(1, sizeof(*object
))))
3749 return E_OUTOFMEMORY
;
3751 object
->IMFMediaSession_iface
.lpVtbl
= &mfmediasessionvtbl
;
3752 object
->IMFGetService_iface
.lpVtbl
= &session_get_service_vtbl
;
3753 object
->IMFRateSupport_iface
.lpVtbl
= &session_rate_support_vtbl
;
3754 object
->IMFRateControl_iface
.lpVtbl
= &session_rate_control_vtbl
;
3755 object
->IMFTopologyNodeAttributeEditor_iface
.lpVtbl
= &node_attribute_editor_vtbl
;
3756 object
->commands_callback
.lpVtbl
= &session_commands_callback_vtbl
;
3757 object
->events_callback
.lpVtbl
= &session_events_callback_vtbl
;
3758 object
->sink_finalizer_callback
.lpVtbl
= &session_sink_finalizer_callback_vtbl
;
3759 object
->refcount
= 1;
3760 list_init(&object
->topologies
);
3761 list_init(&object
->commands
);
3762 list_init(&object
->presentation
.sources
);
3763 list_init(&object
->presentation
.sinks
);
3764 list_init(&object
->presentation
.nodes
);
3765 InitializeCriticalSection(&object
->cs
);
3767 if (FAILED(hr
= MFCreateTopology(&object
->presentation
.current_topology
)))
3770 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
3773 if (FAILED(hr
= MFCreatePresentationClock(&object
->clock
)))
3776 if (FAILED(hr
= MFCreateSystemTimeSource(&object
->system_time_source
)))
3779 if (FAILED(hr
= IMFPresentationClock_QueryInterface(object
->clock
, &IID_IMFRateControl
,
3780 (void **)&object
->clock_rate_control
)))
3789 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_TOPOLOADER
, &clsid
)))
3791 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFTopoLoader
,
3792 (void **)&object
->topo_loader
)))
3794 WARN("Failed to create custom topology loader, hr %#x.\n", hr
);
3798 if (SUCCEEDED(IMFAttributes_GetGUID(config
, &MF_SESSION_QUALITY_MANAGER
, &clsid
)))
3800 if (!(without_quality_manager
= IsEqualGUID(&clsid
, &GUID_NULL
)))
3802 if (FAILED(hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IMFQualityManager
,
3803 (void **)&object
->quality_manager
)))
3805 WARN("Failed to create custom quality manager, hr %#x.\n", hr
);
3811 if (!object
->topo_loader
&& FAILED(hr
= MFCreateTopoLoader(&object
->topo_loader
)))
3814 if (!object
->quality_manager
&& !without_quality_manager
&&
3815 FAILED(hr
= MFCreateStandardQualityManager(&object
->quality_manager
)))
3820 if (object
->quality_manager
&& FAILED(hr
= IMFQualityManager_NotifyPresentationClock(object
->quality_manager
,
3826 *session
= &object
->IMFMediaSession_iface
;
3831 IMFMediaSession_Release(&object
->IMFMediaSession_iface
);